diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..3a08426 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,23 @@ +version: "{build}" + +clone_depth: 1 + +clone_folder: c:\gopath\src\github.com\gen2brain\raylib-go + +environment: + GOPATH: c:\gopath + MSYS_PATH: c:\msys64 + CGO_ENABLED: 1 + CGO_CFLAGS: -g -O2 -Ic:\msys64\mingw32\include + GOARCH: 386 + CC: i686-w64-mingw32-gcc + +install: + - echo %GOPATH% + - echo %MSYS_PATH% + - set PATH=%GOPATH%\bin;c:\go\bin;%MSYS_PATH%\usr\bin;%MSYS_PATH%\mingw32\bin;%PATH% + - go version + - go env + +build_script: + - bash -lc "cd /c/gopath/src/github.com/gen2brain/raylib-go && go get -t ./... && make" diff --git a/.gitignore b/.gitignore index c6074b2..824d669 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ .idea .vsc .vs + +# Ignore go.sum when go.mod is added. +go.sum diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..27ece65 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +language: go + +os: + - linux + #- osx + +go: + - 1.9.x + +before_install: + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then + sudo apt-get update -y; + sudo apt-get install libxi-dev libxinerama-dev libxcursor-dev libxrandr-dev libgl1-mesa-dev -y; + fi + +install: + - go get -t ./... diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0e4a951 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +PACKAGES= raylib raygui easings physics rres + +GO?= go + +all: packages + +packages: + @for pkg in ${PACKAGES}; do \ + echo "Building package github.com/gen2brain/raylib-go/$$pkg..."; \ + ${GO} build github.com/gen2brain/raylib-go/$$pkg || exit 1; \ + done diff --git a/README.md b/README.md index 034576d..fd74823 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,78 @@ -![logo](https://git.terah.dev/UnrealXR/raylib-go/raw/branch/master/assets/raylib-go_256x256.png) +![logo](https://goo.gl/XlIcXz) ## raylib-go -[![Build Status](https://git.terah.dev/UnrealXR/raylib-go/actions/workflows/build.yml/badge.svg)](https://git.terah.dev/UnrealXR/raylib-go/actions) -[![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/raylib?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/raylib) -[![Go Report Card](https://goreportcard.com/badge/git.terah.dev/UnrealXR/raylib-go/raylib)](https://goreportcard.com/report/git.terah.dev/UnrealXR/raylib-go/raylib) -[![Examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://git.terah.dev/UnrealXR/raylib-go/src/branch/master/examples) +[![TravisCI Build Status](https://travis-ci.org/gen2brain/raylib-go.svg?branch=master)](https://travis-ci.org/gen2brain/raylib-go) +[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/qv2iggrqtgl7xhr0?svg=true)](https://ci.appveyor.com/project/gen2brain/raylib-go) +[![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/raylib?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/raylib) +[![Go Report Card](https://goreportcard.com/badge/github.com/gen2brain/raylib-go)](https://goreportcard.com/report/github.com/gen2brain/raylib-go) +[![Examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://github.com/gen2brain/raylib-go/tree/master/examples) Golang bindings for [raylib](http://www.raylib.com/), a simple and easy-to-use library to enjoy videogames programming. -This is a fork of [gen2brain's `raylib-go` bindings](https://github.com/gen2brain/raylib-go) to add [DRM leasing](https://wayland.app/protocols/drm-lease-v1) support. - -raylib C source code is included and compiled together with bindings. Note that the first build can take a few minutes. - -It is also possible to use raylib-go without cgo (Windows only; see requirements below). - ### Requirements ##### Ubuntu - apt-get install libgl1-mesa-dev libxi-dev libxcursor-dev libxrandr-dev libxinerama-dev libwayland-dev libxkbcommon-dev +###### X11 + + apt-get install libgl1-mesa-dev libxi-dev libxcursor-dev libxrandr-dev libxinerama-dev + +###### Wayland + + apt-get install libgl1-mesa-dev libwayland-dev libxkbcommon-dev ##### Fedora - dnf install mesa-libGL-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel wayland-devel libxkbcommon-devel +###### X11 + + dnf install mesa-libGL-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel + +###### Wayland + + dnf install mesa-libGL-devel wayland-devel libxkbcommon-devel ##### macOS -On macOS, you need Xcode or Command Line Tools for Xcode (if you have `brew` installed, you already have this). +On macOS you need Xcode or Command Line Tools for Xcode. ##### Windows -###### cgo - On Windows you need C compiler, like [Mingw-w64](https://mingw-w64.org) or [TDM-GCC](http://tdm-gcc.tdragon.net/). You can also build binary in [MSYS2](https://msys2.github.io/) shell. -To remove console window, build with `-ldflags "-H=windowsgui"`. - -###### purego (without cgo, i.e. CGO_ENABLED=0) - -Download the raylib.dll from the assets on the [releases page](https://github.com/raysan5/raylib/releases). It is contained in the `raylib-*_win64_msvc*.zip`. -Put the raylib.dll into the root folder of your project or copy it into `C:\Windows\System32` for a system-wide installation. - -It is also possible to build the DLL yourself. You can find more info at [raylib's wiki](https://github.com/raysan5/raylib/wiki/Working-on-Windows). - ##### Android -[Android example](https://git.terah.dev/UnrealXR/raylib-go/tree/master/examples/others/android/example). +[Android example](https://github.com/gen2brain/raylib-go/tree/master/examples/others/android/example). -##### Wasm - -For web bindings, refer to [Raylib-Go-Wasm](https://github.com/BrownNPC/Raylib-Go-Wasm); it should be largely compatible with this repository. +##### Raspberry Pi +[RPi example](https://github.com/gen2brain/raylib-go/tree/master/examples/others/rpi/basic_window). ### Installation - go get -v -u git.terah.dev/UnrealXR/raylib-go/raylib + go get -v -u github.com/gen2brain/raylib-go/raylib ### Build tags -* `drm` - build for Linux native [DRM](https://en.wikipedia.org/wiki/Direct_Rendering_Manager) mode, including Raspberry Pi 4 and other devices (PLATFORM_DRM) -* `drm_disable_input` - disables keyboard input capabilities for the DRM backend. Requires the `drm` build tag as a prerequisite -* `drm_leasing` - enables Wayland DRM leasing capabilties. Requires the `drm` build tag as a prerequisite -* `sdl` - build for [SDL](https://github.com/libsdl-org/SDL) backend (PLATFORM_DESKTOP_SDL) -* `sdl3` - build for [SDL3](https://github.com/libsdl-org/SDL) backend (PLATFORM_DESKTOP_SDL3) -* `rgfw` - build for [RGFW](https://github.com/ColleagueRiley/RGFW) backend (PLATFORM_DESKTOP_RGFW) +* `drm` - build for Linux native mode, including Raspberry Pi 4 and other devices (PLATFORM_DRM) +* `rpi` - build for Raspberry Pi platform (PLATFORM_RPI) +* `wayland` - build against Wayland libraries * `noaudio` - disables audio functions -* `opengl43` - uses OpenGL 4.3 backend * `opengl21` - uses OpenGL 2.1 backend (default is 3.3 on desktop) * `opengl11` - uses OpenGL 1.1 backend (pseudo OpenGL 1.1 style) -* `es2` - uses OpenGL ES 2.0 backend (can be used to link against [Google's ANGLE](https://github.com/google/angle)) -* `es3` - experimental support for OpenGL ES 3.0 -* `x11` - force X11 compatibility mode on Wayland (PLATFORM_DESKTOP/GLFW) -* `wayland` - force Wayland only mode (PLATFORM_DESKTOP/GLFW) ### Documentation -Documentation on [GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/raylib). Also check raylib [cheatsheet](http://www.raylib.com/cheatsheet/cheatsheet.html). If you have problems or need assistance there is an active community in the #raylib-go channel of the [Raylib Discord Server](https://discord.gg/raylib) that can help. +Documentation on [GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/raylib). Also check raylib [cheatsheet](http://www.raylib.com/cheatsheet/cheatsheet.html). ### Example ```go package main -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" +import "github.com/gen2brain/raylib-go/raylib" func main() { rl.InitWindow(800, 450, "raylib [core] example - basic window") - defer rl.CloseWindow() rl.SetTargetFPS(60) @@ -94,41 +80,19 @@ func main() { rl.BeginDrawing() rl.ClearBackground(rl.RayWhite) + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LightGray) rl.EndDrawing() } + + rl.CloseWindow() } ``` -Check more [examples](https://git.terah.dev/UnrealXR/raylib-go/tree/master/examples) organized by raylib modules. +Check more [examples](https://github.com/gen2brain/raylib-go/tree/master/examples) organized by raylib modules. -### Cross-compile (Linux) - -To cross-compile for Windows install [MinGW](https://www.mingw-w64.org/) toolchain. - -``` -$ CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -$ file basic_window.exe -basic_window.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows, 11 sections - -$ CGO_ENABLED=1 CC=i686-w64-mingw32-gcc GOOS=windows GOARCH=386 go build -ldflags "-s -w" -$ file basic_window.exe -basic_window.exe: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows, 9 sections -``` - -To cross-compile for macOS install [OSXCross](https://github.com/tpoechtrager/osxcross) toolchain. - -``` -$ CGO_ENABLED=1 CC=x86_64-apple-darwin21.1-clang GOOS=darwin GOARCH=amd64 go build -ldflags "-linkmode external -s -w '-extldflags=-mmacosx-version-min=10.15'" -$ file basic_window -basic_window: Mach-O 64-bit x86_64 executable, flags: - -$ CGO_ENABLED=1 CC=aarch64-apple-darwin21.1-clang GOOS=darwin GOARCH=arm64 go build -ldflags "-linkmode external -s -w '-extldflags=-mmacosx-version-min=12.0.0'" -$ file basic_window -basic_window: Mach-O 64-bit arm64 executable, flags: -``` ### License -raylib-go is licensed under an unmodified zlib/libpng license. View [LICENSE](https://git.terah.dev/UnrealXR/raylib-go/blob/master/LICENSE). +raylib-go is licensed under an unmodified zlib/libpng license. View [LICENSE](https://github.com/gen2brain/raylib-go/blob/master/LICENSE). diff --git a/assets/raylib-go_256x256.png b/assets/raylib-go_256x256.png deleted file mode 100644 index 380e8c8..0000000 Binary files a/assets/raylib-go_256x256.png and /dev/null differ diff --git a/easings/README.md b/easings/README.md index 54c3761..fbc1273 100644 --- a/easings/README.md +++ b/easings/README.md @@ -1,7 +1,7 @@ -## easings [![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/easings?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/easings) +## easings [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/easings?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/easings) Useful easing functions for values animation. A port of Robert Penner's [easing equations](http://robertpenner.com/easing/). -![Demo](../examples/easings/easings/easings.gif) +![screenshot](https://goo.gl/crzRrH) diff --git a/easings/go.mod b/easings/go.mod deleted file mode 100644 index 54815db..0000000 --- a/easings/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module git.terah.dev/UnrealXR/raylib-go/easings - -go 1.21 diff --git a/examples/audio/audio_multichannel_sound/audio_multichannel_sound.go b/examples/audio/audio_multichannel_sound/audio_multichannel_sound.go new file mode 100644 index 0000000..345afcc --- /dev/null +++ b/examples/audio/audio_multichannel_sound/audio_multichannel_sound.go @@ -0,0 +1,66 @@ +package main + +import ( + "fmt" + + "github.com/gen2brain/raylib-go/raylib" +) + +func main() { + // Initialization + //-------------------------------------------------------------------------------------- + screenWidth := int32(800) + screenHeight := int32(450) + + rl.InitWindow(screenWidth, screenHeight, "raylib [audio] example - Multichannel sound playing") + + rl.InitAudioDevice() // Initialize audio device + + fxWav := rl.LoadSound("sound.wav") // Load WAV audio file + fxOgg := rl.LoadSound("target.ogg") // Load OGG audio file + + rl.SetSoundVolume(fxWav, 0.2) + + rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + for !rl.WindowShouldClose() { // Detect window close button or ESC key + // Update + //---------------------------------------------------------------------------------- + if rl.IsKeyPressed(rl.KeyEnter) { + rl.PlaySoundMulti(fxWav) + } // Play a new wav sound instance + if rl.IsKeyPressed(rl.KeySpace) { + rl.PlaySoundMulti(fxOgg) + } // Play a new ogg sound instance + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawText("MULTICHANNEL SOUND PLAYING", 20, 20, 20, rl.Gray) + rl.DrawText("Press SPACE to play new ogg instance!", 200, 120, 20, rl.LightGray) + rl.DrawText("Press ENTER to play new wav instance!", 200, 180, 20, rl.LightGray) + + rl.DrawText(fmt.Sprintf("CONCURRENT SOUNDS PLAYING: %02d", rl.GetSoundsPlaying()), 220, 280, 20, rl.Red) + + rl.EndDrawing() + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + rl.StopSoundMulti() // We must stop the buffer pool before unloading + + rl.UnloadSound(fxWav) // Unload sound data + rl.UnloadSound(fxOgg) // Unload sound data + + rl.CloseAudioDevice() // Close audio device + + rl.CloseWindow() // Close window and OpenGL context + //-------------------------------------------------------------------------------------- +} diff --git a/examples/audio/sound_multi/sound.wav b/examples/audio/audio_multichannel_sound/sound.wav similarity index 100% rename from examples/audio/sound_multi/sound.wav rename to examples/audio/audio_multichannel_sound/sound.wav diff --git a/examples/audio/audio_multichannel_sound/target.ogg b/examples/audio/audio_multichannel_sound/target.ogg new file mode 100644 index 0000000..2b73e1c Binary files /dev/null and b/examples/audio/audio_multichannel_sound/target.ogg differ diff --git a/examples/audio/mixed_processor/coin.wav b/examples/audio/mixed_processor/coin.wav deleted file mode 100644 index ad95bfb..0000000 Binary files a/examples/audio/mixed_processor/coin.wav and /dev/null differ diff --git a/examples/audio/mixed_processor/country.mp3 b/examples/audio/mixed_processor/country.mp3 deleted file mode 100644 index 91066cc..0000000 Binary files a/examples/audio/mixed_processor/country.mp3 and /dev/null differ diff --git a/examples/audio/mixed_processor/main.go b/examples/audio/mixed_processor/main.go deleted file mode 100644 index de3789d..0000000 --- a/examples/audio/mixed_processor/main.go +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************************* -* -* raylib [audio] example - Mixed audio processing -* -* Example originally created with raylib 4.2, last time updated with raylib 4.2 -* -* Example contributed by hkc (@hatkidchan) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2023 hkc (@hatkidchan) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -var exponent float32 = 1.0 // Audio exponentiation value -var averageVolume [400]float32 // Average volume history - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [audio] example - processing mixed output") - - rl.InitAudioDevice() // Initialize audio device - rl.AttachAudioMixedProcessor(ProcessAudio) - - music := rl.LoadMusicStream("country.mp3") - sound := rl.LoadSound("coin.wav") - - rl.PlayMusicStream(music) - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - rl.UpdateMusicStream(music) // Update music buffer with new stream data - - // Modify processing variables - if rl.IsKeyPressed(rl.KeyLeft) { - exponent -= 0.05 - } - if rl.IsKeyPressed(rl.KeyRight) { - exponent += 0.05 - } - if rl.IsKeyPressed(rl.KeyDown) { - exponent -= 0.25 - } - if rl.IsKeyPressed(rl.KeyUp) { - exponent += 0.25 - } - - // Make sure that exponent stays between 0.5 and 3 - exponent = clamp(exponent, 0.5, 3) - - if rl.IsKeyPressed(rl.KeySpace) { - rl.PlaySound(sound) - } - - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, rl.LightGray) - - rl.DrawText(fmt.Sprintf("EXPONENT = %.2f", exponent), 215, 180, 20, rl.LightGray) - - rl.DrawRectangle(199, 199, 402, 34, rl.LightGray) - for i := int32(0); i < 400; i++ { - rl.DrawLine(201+i, 232-int32(averageVolume[i]*32), 201+i, 232, rl.Maroon) - } - rl.DrawRectangleLines(199, 199, 402, 34, rl.Gray) - - rl.DrawText("PRESS SPACE TO PLAY OTHER SOUND", 200, 250, 20, rl.LightGray) - rl.DrawText("USE LEFT AND RIGHT ARROWS TO ALTER DISTORTION", 140, 280, 20, rl.LightGray) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadMusicStream(music) // Unload music stream buffers from RAM - rl.DetachAudioMixedProcessor(ProcessAudio) // Disconnect audio processor - rl.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) - - rl.CloseWindow() // Close window and OpenGL context -} - -// ProcessAudio is the audio processing function -func ProcessAudio(buffer []float32, frames int) { - var average float32 // Temporary average volume - maxFrame := frames / 2 - - // Each frame has 2 samples (left and right), - // so we should loop `frames / 2` times - for frame := 0; frame < maxFrame; frame++ { - left := &buffer[frame*2+0] // Left channel - right := &buffer[frame*2+1] // Right channel - - // Modify left and right channel samples with exponent - *left = pow(abs(*left), exponent) * sgn(*left) - *right = pow(abs(*right), exponent) * sgn(*right) - - // Accumulating average volume - average += abs(*left) / float32(maxFrame) - average += abs(*right) / float32(maxFrame) - } - - // Shift average volume history buffer to the left - for i := 0; i < 399; i++ { - averageVolume[i] = averageVolume[i+1] - } - - // Add the new average value - averageVolume[399] = average -} - -// Helper functions to make the code shorter -// (using less type conversions) -// (Golang: Please make the `math` package generic! This is ridiculous :-) -func abs(value float32) float32 { - return float32(math.Abs(float64(value))) -} - -func pow(value, exponent float32) float32 { - return float32(math.Pow(float64(value), float64(exponent))) -} - -func sgn(value float32) float32 { - if value < 0 { - return -1 - } else if value > 0 { - return 1 - } - return 0 -} -func clamp(value, min, max float32) float32 { - if value < min { - return min - } - if value > max { - return max - } - return value -} diff --git a/examples/audio/module_playing/main.go b/examples/audio/module_playing/main.go index 18b81e5..bf03840 100644 --- a/examples/audio/module_playing/main.go +++ b/examples/audio/module_playing/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const maxCircles = 64 diff --git a/examples/audio/music_stream/main.go b/examples/audio/music_stream/main.go index 0a9f7a5..5b5f27e 100644 --- a/examples/audio/music_stream/main.go +++ b/examples/audio/music_stream/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { rl.InitWindow(800, 450, "raylib [audio] example - music playing (streaming)") rl.InitAudioDevice() diff --git a/examples/audio/raw_stream/main.go b/examples/audio/raw_stream/main.go index 9a1f335..d8a9ddf 100644 --- a/examples/audio/raw_stream/main.go +++ b/examples/audio/raw_stream/main.go @@ -1,69 +1,71 @@ package main import ( - "fmt" "math" - "time" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( - nSamples = 44000 * 10 - sampleRate = 6000 - bufferSize = nSamples - frequency = 440 - targetFPS = 240 + maxSamples = 22050 + maxSamplesPerUpdate = 4096 ) func main() { rl.InitWindow(800, 450, "raylib [audio] example - raw audio streaming") - position := rl.NewVector2(0, 0) - - rl.SetAudioStreamBufferSizeDefault(bufferSize) rl.InitAudioDevice() - // Init raw audio stream (sample rate: , sample size: 32bit-float, channels: 1-mono) - stream := rl.LoadAudioStream(nSamples, 32, 1) + // Init raw audio stream (sample rate: 22050, sample size: 32bit-float, channels: 1-mono) + stream := rl.InitAudioStream(22050, 32, 1) - //// Create sine wave to play - data := make([]float32, nSamples) + //// Fill audio stream with some samples (sine wave) + data := make([]float32, maxSamples) - for i := 0; i < nSamples; i++ { - t := float32(i) / float32(nSamples) - data[i] = float32(math.Sin(float64((2 * rl.Pi * frequency * t)))) + for i := 0; i < maxSamples; i++ { + data[i] = float32(math.Sin(float64((2*rl.Pi*float32(i))/2) * rl.Deg2rad)) } - // NOTE: The buffer can only be updated when it has been processed. Time between buffer processing and next load and causes clipping + // NOTE: The generated MAX_SAMPLES do not fit to close a perfect loop + // for that reason, there is a clip everytime audio stream is looped rl.PlayAudioStream(stream) - startTime := time.Now() - rl.SetTargetFPS(targetFPS) + totalSamples := int32(maxSamples) + samplesLeft := int32(totalSamples) + + position := rl.NewVector2(0, 0) + + rl.SetTargetFPS(30) for !rl.WindowShouldClose() { - // Refill audio stream if buffer is processed + // Refill audio stream if required if rl.IsAudioStreamProcessed(stream) { - elapsedTime := time.Since(startTime).Seconds() - currentSampleIndex := int(math.Mod(elapsedTime*float64(sampleRate), float64(nSamples))) - nextSampleIndex := currentSampleIndex + bufferSize - - if nextSampleIndex > nSamples { - nextSampleIndex = bufferSize - (nSamples - currentSampleIndex) - rl.UpdateAudioStream(stream, append(data[currentSampleIndex:], data[:nextSampleIndex]...)) + numSamples := int32(0) + if samplesLeft >= maxSamplesPerUpdate { + numSamples = maxSamplesPerUpdate } else { - rl.UpdateAudioStream(stream, data[currentSampleIndex:nextSampleIndex]) + numSamples = samplesLeft + } + + rl.UpdateAudioStream(stream, data[totalSamples-samplesLeft:], numSamples) + + samplesLeft -= numSamples + + // Reset samples feeding (loop audio) + if samplesLeft <= 0 { + samplesLeft = totalSamples } } rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - rl.DrawText(fmt.Sprintf("%d Hz SINE WAVE SHOULD BE PLAYING!", frequency), 200, 140, 20, rl.LightGray) + rl.DrawText("SINE WAVE SHOULD BE PLAYING!", 240, 140, 20, rl.LightGray) // NOTE: Draw a part of the sine wave (only screen width) for i := 0; i < int(rl.GetScreenWidth()); i++ { position.X = float32(i) - position.Y = 250 + 10*data[i*nSamples/int(20*rl.GetScreenWidth())] + position.Y = 250 + 50*data[i] rl.DrawPixelV(position, rl.Red) } @@ -71,7 +73,7 @@ func main() { rl.EndDrawing() } - rl.UnloadAudioStream(stream) // Close raw audio stream and delete buffers from RAM + rl.CloseAudioStream(stream) // Close raw audio stream and delete buffers from RAM rl.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) diff --git a/examples/audio/sound_loading/main.go b/examples/audio/sound_loading/main.go index 8239c03..c9a8713 100644 --- a/examples/audio/sound_loading/main.go +++ b/examples/audio/sound_loading/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/audio/sound_multi/main.go b/examples/audio/sound_multi/main.go deleted file mode 100644 index 067440b..0000000 --- a/examples/audio/sound_multi/main.go +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************************* -* -* raylib [audio] example - Playing sound multiple times -* -* Example originally created with raylib 4.6 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2023 Jeffery Myers (@JeffM2501) -* -********************************************************************************************/ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 - maxSounds = 10 -) - -var soundArray [maxSounds]rl.Sound -var currentSound int32 - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [audio] example - playing sound multiple times") - - // Initialize audio device - rl.InitAudioDevice() - - // Load WAV audio file into the first slot as the 'source' sound - // this sound owns the sample data - soundArray[0] = rl.LoadSound("sound.wav") - - for i := 1; i < maxSounds; i++ { - // Load an alias of the sound into slots 1-9. - // These do not own the sound data, but can be played - soundArray[i] = rl.LoadSoundAlias(soundArray[0]) - } - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !rl.WindowShouldClose() { // Detect window close button or ESC key - if rl.IsKeyPressed(rl.KeySpace) { - rl.PlaySound(soundArray[currentSound]) // play the next open sound slot - currentSound++ // increment the sound slot - if currentSound >= maxSounds { // if the sound slot is out of bounds, go back to 0 - currentSound = 0 - } - - // Note: a better way would be to look at the list for the first sound that is not playing and use that slot - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.DrawText("Press SPACE to PLAY a WAV sound!", 200, 180, 20, rl.LightGray) - rl.EndDrawing() - } - - rl.UnloadSound(soundArray[0]) // Unload source sound data - rl.CloseAudioDevice() // Close audio device - - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/core/2d_camera/main.go b/examples/core/2d_camera/main.go index 6c77b20..cce6fe5 100644 --- a/examples/core/2d_camera/main.go +++ b/examples/core/2d_camera/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) var ( diff --git a/examples/core/2d_camera_mouse_zoom/main.go b/examples/core/2d_camera_mouse_zoom/main.go deleted file mode 100644 index a99522e..0000000 --- a/examples/core/2d_camera_mouse_zoom/main.go +++ /dev/null @@ -1,101 +0,0 @@ -package main - -/******************************************************************************************* -* -* raylib [core] example - 2d camera mouse zoom -* -* Example originally created with raylib 4.2, last time updated with raylib 4.2 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2022 Jeffery Myers (@JeffM2501) -* -********************************************************************************************/ - -// ------------------------------------------------------------------------------------ -// Program main entry point -// ------------------------------------------------------------------------------------ -func main() { - // Initialization - //-------------------------------------------------------------------------------------- - const ( - screenWidth = 800 - screenHeight = 450 - ) - - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera mouse zoom") - - var camera rl.Camera2D - camera.Zoom = 1.0 - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - // Translate based on mouse right click - if rl.IsMouseButtonDown(rl.MouseRightButton) { - delta := rl.GetMouseDelta() - delta = rl.Vector2Scale(delta, -1.0/camera.Zoom) - - camera.Target = rl.Vector2Add(camera.Target, delta) - } - - // Zoom based on mouse wheel - wheel := rl.GetMouseWheelMove() - if wheel != 0 { - // Get the world point that is under the mouse - mouseWorldPos := rl.GetScreenToWorld2D(rl.GetMousePosition(), camera) - - // Set the offset to where the mouse is - camera.Offset = rl.GetMousePosition() - - // Set the target to match, so that the camera maps the world space point - // under the cursor to the screen space point under the cursor at any zoom - camera.Target = mouseWorldPos - - // Zoom increment - const zoomIncrement float32 = 0.125 - - camera.Zoom += (wheel * zoomIncrement) - if camera.Zoom < zoomIncrement { - camera.Zoom = zoomIncrement - } - } - - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - rl.ClearBackground(rl.Black) - - rl.BeginMode2D(camera) - - // Draw the 3d grid, rotated 90 degrees and centered around 0,0 - // just so we have something in the XY plane - rl.PushMatrix() - rl.Translatef(0, 25*50, 0) - rl.Rotatef(90, 1, 0, 0) - rl.DrawGrid(100, 50) - rl.PopMatrix() - - // Draw a reference circle - rl.DrawCircle(100, 100, 50, rl.Yellow) - - rl.EndMode2D() - - rl.DrawText("Mouse right button drag to move, mouse wheel to zoom", 10, 10, 20, rl.White) - - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} diff --git a/examples/core/2d_camera_platformer/main.go b/examples/core/2d_camera_platformer/main.go deleted file mode 100644 index 7ce4f17..0000000 --- a/examples/core/2d_camera_platformer/main.go +++ /dev/null @@ -1,261 +0,0 @@ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 - gravity = 400 - playerJumpSpeed = 350.0 - playerHORSpeed = 200.0 -) - -type Player struct { - position rl.Vector2 - speed float32 - canJump bool -} - -type EnvironmentItem struct { - rect rl.Rectangle - blocking bool - color rl.Color -} - -type cameraUpdater func(*rl.Camera2D, *Player, []EnvironmentItem, float32) - -// These 3 variables are used only for camera 4, -// but they need to be declared on module level -// for camera 4 to work (static in C) -var eveningOut = false -var evenOutSpeed float32 = 700 -var evenOutTarget float32 = 0 - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera platformer") - - player := Player{ - position: rl.NewVector2(400, 280), - speed: 0, - canJump: false, - } - - envItems := []EnvironmentItem{ - {rect: rl.Rectangle{Width: 1000, Height: 400}, blocking: false, color: rl.LightGray}, - {rect: rl.Rectangle{Y: 400, Width: 1000, Height: 200}, blocking: true, color: rl.Gray}, - {rect: rl.Rectangle{X: 300, Y: 200, Width: 400, Height: 10}, blocking: true, color: rl.Gray}, - {rect: rl.Rectangle{X: 250, Y: 300, Width: 100, Height: 10}, blocking: true, color: rl.Gray}, - {rect: rl.Rectangle{X: 650, Y: 300, Width: 100, Height: 10}, blocking: true, color: rl.Gray}, - } - - camera := rl.Camera2D{ - Offset: rl.Vector2{X: screenWidth / 2, Y: screenHeight / 2}, - Target: player.position, - Rotation: 0, - Zoom: 1, - } - - cameraUpdaters := []cameraUpdater{ - updateCameraCenter, - updateCameraCenterInsideMap, - updateCameraCenterSmoothFollow, - updateCameraEvenOutOnLanding, - updateCameraPlayerBoundsPush, - } - cameraDescriptions := []string{ - "1. Follow player center", - "2. Follow player center, but clamp to map edges", - "3. Follow player center; smoothed", - "4. Follow player center horizontally; update player center vertically after landing", - "5. Player push camera on getting too close to screen edge", - } - - cameraOption := 0 - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - deltaTime := rl.GetFrameTime() - - updatePlayer(&player, envItems, deltaTime) - - camera.Zoom += rl.GetMouseWheelMove() * 0.05 - - camera.Zoom = clamp(camera.Zoom, 0.25, 3) - - if rl.IsKeyPressed(rl.KeyC) { - cameraOption = (cameraOption + 1) % len(cameraUpdaters) - } - // Call update camera function by its pointer - cameraUpdaters[cameraOption](&camera, &player, envItems, deltaTime) - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginMode2D(camera) - - for _, item := range envItems { - rl.DrawRectangleRec(item.rect, item.color) - } - - playerRect := rl.Rectangle{ - X: player.position.X - 20, - Y: player.position.Y - 40, - Width: 40, - Height: 40, - } - rl.DrawRectangleRec(playerRect, rl.Red) - rl.DrawCircleV(player.position, 5, rl.Gold) - - rl.EndMode2D() - - rl.DrawText("Controls:", 20, 20, 10, rl.Black) - rl.DrawText(" - Right/Left to move", 40, 40, 10, rl.DarkGray) - rl.DrawText(" - Space to jump", 40, 60, 10, rl.DarkGray) - rl.DrawText(" - Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, rl.DarkGray) - rl.DrawText(" - C to change camera mode", 20, 100, 10, rl.Black) - rl.DrawText("Current Camera Mode:", 20, 120, 10, rl.DarkGray) - rl.DrawText(cameraDescriptions[cameraOption], 40, 140, 10, rl.DarkGray) - - rl.EndDrawing() - } - rl.CloseWindow() -} - -func updatePlayer(player *Player, envItems []EnvironmentItem, delta float32) { - if rl.IsKeyDown(rl.KeyLeft) { - player.position.X -= playerHORSpeed * delta - } - if rl.IsKeyDown(rl.KeyRight) { - player.position.X += playerHORSpeed * delta - } - if rl.IsKeyDown(rl.KeySpace) && player.canJump { - player.speed = -playerJumpSpeed - player.canJump = false - } - - hitObstacle := false - for _, item := range envItems { - if item.blocking && - item.rect.X <= player.position.X && item.rect.X+item.rect.Width >= player.position.X && - item.rect.Y >= player.position.Y && item.rect.Y <= player.position.Y+player.speed*delta { - hitObstacle = true - player.speed = 0 - player.position.Y = item.rect.Y - break - } - } - - if !hitObstacle { - player.position.Y += player.speed * delta - player.speed += gravity * delta - player.canJump = false - } else { - player.canJump = true - } -} - -func updateCameraCenter(camera *rl.Camera2D, player *Player, _ []EnvironmentItem, _ float32) { - camera.Offset = rl.Vector2{X: screenWidth / 2, Y: screenHeight / 2} - camera.Target = player.position -} - -func updateCameraCenterInsideMap(camera *rl.Camera2D, player *Player, envItems []EnvironmentItem, _ float32) { - camera.Offset = rl.Vector2{X: screenWidth / 2, Y: screenHeight / 2} - camera.Target = player.position - - var minX, minY, maxX, maxY float32 = 1000, 1000, -1000, -10000 - - for _, item := range envItems { - minX = min(item.rect.X, minX) - maxX = max(item.rect.X+item.rect.Width, maxX) - minY = min(item.rect.Y, minY) - maxY = max(item.rect.Y+item.rect.Height, maxY) - } - - maxV := rl.GetWorldToScreen2D(rl.Vector2{X: maxX, Y: maxY}, *camera) - minV := rl.GetWorldToScreen2D(rl.Vector2{X: minX, Y: minY}, *camera) - - if maxV.X < screenWidth { - camera.Offset.X = screenWidth - (maxV.X - screenWidth/2) - } - if maxV.Y < screenHeight { - camera.Offset.Y = screenHeight - (maxV.Y - screenHeight/2) - } - if minV.X > 0 { - camera.Offset.X = screenWidth/2 - minV.X - } - if minV.Y > 0 { - camera.Offset.Y = screenHeight/2 - minV.Y - } -} - -func updateCameraCenterSmoothFollow(camera *rl.Camera2D, player *Player, _ []EnvironmentItem, delta float32) { - var minSpeed, minEffectLength, fractionSpeed float32 = 30.0, 10.0, 0.8 - - camera.Offset = rl.Vector2{X: screenWidth / 2, Y: screenHeight / 2} - diff := rl.Vector2Subtract(player.position, camera.Target) - length := rl.Vector2Length(diff) - - if length > minEffectLength { - speed := max(fractionSpeed*length, minSpeed) - camera.Target = rl.Vector2Add(camera.Target, rl.Vector2Scale(diff, speed*delta/length)) - } -} - -func updateCameraEvenOutOnLanding(camera *rl.Camera2D, player *Player, _ []EnvironmentItem, delta float32) { - camera.Offset = rl.Vector2{X: screenWidth / 2, Y: screenHeight / 2} - camera.Target.X = player.position.X - - if eveningOut { - if evenOutTarget > camera.Target.Y { - camera.Target.Y += evenOutSpeed * delta - if camera.Target.Y > evenOutTarget { - camera.Target.Y = evenOutTarget - eveningOut = false - } - } else { - camera.Target.Y -= evenOutSpeed * delta - if camera.Target.Y < evenOutTarget { - camera.Target.Y = evenOutTarget - eveningOut = false - } - } - } else { - if player.canJump && player.speed == 0 && player.position.Y != camera.Target.Y { - eveningOut = true - evenOutTarget = player.position.Y - } - } -} - -func updateCameraPlayerBoundsPush(camera *rl.Camera2D, player *Player, _ []EnvironmentItem, _ float32) { - bbox := rl.Vector2{X: 0.2, Y: 0.2} - - bboxWorldMin := rl.GetScreenToWorld2D(rl.Vector2{X: (1 - bbox.X) * 0.5 * screenWidth, Y: (1 - bbox.Y) * 0.5 * screenHeight}, *camera) - bboxWorldMax := rl.GetScreenToWorld2D(rl.Vector2{X: (1 + bbox.X) * 0.5 * screenWidth, Y: (1 + bbox.Y) * 0.5 * screenHeight}, *camera) - camera.Offset = rl.Vector2{X: (1 - bbox.X) * 0.5 * screenWidth, Y: (1 - bbox.Y) * 0.5 * screenHeight} - - if player.position.X < bboxWorldMin.X { - camera.Target.X = player.position.X - } - if player.position.Y < bboxWorldMin.Y { - camera.Target.Y = player.position.Y - } - if player.position.X > bboxWorldMax.X { - camera.Target.X = bboxWorldMin.X + (player.position.X - bboxWorldMax.X) - } - if player.position.Y > bboxWorldMax.Y { - camera.Target.Y = bboxWorldMin.Y + (player.position.Y - bboxWorldMax.Y) - } -} - -func clamp(zoom float32, min float32, max float32) float32 { - if zoom < min { - return min - } - if zoom > max { - return max - } - return zoom -} diff --git a/examples/core/2d_camera_splitscreen/main.go b/examples/core/2d_camera_splitscreen/main.go deleted file mode 100644 index 141b376..0000000 --- a/examples/core/2d_camera_splitscreen/main.go +++ /dev/null @@ -1,128 +0,0 @@ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenW = int32(800) - screenH = int32(440) - playerSize = float32(40) - cam1, cam2 rl.Camera2D -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [core] example - 2d camera split screen") - - player1 := rl.NewRectangle(200, 200, playerSize, playerSize) - player2 := rl.NewRectangle(250, 200, playerSize, playerSize) - - cam1.Target = rl.NewVector2(player1.X, player1.Y) - cam1.Offset = rl.NewVector2(200, 200) - cam1.Rotation = 0 - cam1.Zoom = 1 - - cam2 = cam1 - cam2.Target = rl.NewVector2(player2.X, player2.Y) - - screenCam1 := rl.LoadRenderTexture(screenW/2, screenH) - screenCam2 := rl.LoadRenderTexture(screenW/2, screenH) - - splitScreenRec := rl.NewRectangle(0, 0, float32(screenCam1.Texture.Width), -float32(screenCam1.Texture.Height)) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - if rl.IsKeyDown(rl.KeyS) { - player1.Y += 3 - } else if rl.IsKeyDown(rl.KeyW) { - player1.Y -= 3 - } - if rl.IsKeyDown(rl.KeyD) { - player1.X += 3 - } else if rl.IsKeyDown(rl.KeyA) { - player1.X -= 3 - } - - if rl.IsKeyDown(rl.KeyUp) { - player2.Y -= 3 - } else if rl.IsKeyDown(rl.KeyDown) { - player2.Y += 3 - } - if rl.IsKeyDown(rl.KeyRight) { - player2.X += 3 - } else if rl.IsKeyDown(rl.KeyLeft) { - player2.X -= 3 - } - - cam1.Target = rl.NewVector2(player1.X, player1.Y) - cam2.Target = rl.NewVector2(player2.X, player2.Y) - - rl.BeginTextureMode(screenCam1) - rl.ClearBackground(rl.RayWhite) - rl.BeginMode2D(cam1) - - for i := 0; i < int(screenW/int32(playerSize))+1; i++ { - rl.DrawLineV(rl.NewVector2(playerSize*float32(i), 0), rl.NewVector2(playerSize*float32(i), float32(screenH)), rl.LightGray) - } - for i := 0; i < int(screenH/int32(playerSize))+1; i++ { - rl.DrawLineV(rl.NewVector2(0, playerSize*float32(i)), rl.NewVector2(float32(screenW), playerSize*float32(i)), rl.LightGray) - } - for i := 0; i < int(screenW/int32(playerSize)); i++ { - for j := 0; j < int(screenH/int32(playerSize)); j++ { - rl.DrawText("["+fmt.Sprint(i)+","+fmt.Sprint(j)+"]", 10+int32(playerSize*float32(i)), 15+int32(playerSize*float32(j)), 10, rl.LightGray) - } - } - - rl.DrawRectangleRec(player1, rl.Red) - rl.DrawRectangleRec(player2, rl.Blue) - rl.EndMode2D() - - rl.DrawRectangle(0, 0, screenW/2, 30, rl.Fade(rl.RayWhite, 0.6)) - rl.DrawText("PLAYER 1 WASD KEYS", 10, 10, 10, rl.Maroon) - rl.EndTextureMode() - - rl.BeginTextureMode(screenCam2) - rl.ClearBackground(rl.RayWhite) - rl.BeginMode2D(cam2) - - for i := 0; i < int(screenW/int32(playerSize))+1; i++ { - rl.DrawLineV(rl.NewVector2(playerSize*float32(i), 0), rl.NewVector2(playerSize*float32(i), float32(screenH)), rl.LightGray) - } - for i := 0; i < int(screenH/int32(playerSize))+1; i++ { - rl.DrawLineV(rl.NewVector2(0, playerSize*float32(i)), rl.NewVector2(float32(screenW), playerSize*float32(i)), rl.LightGray) - } - for i := 0; i < int(screenW/int32(playerSize)); i++ { - for j := 0; j < int(screenH/int32(playerSize)); j++ { - rl.DrawText("["+fmt.Sprint(i)+","+fmt.Sprint(j)+"]", 10+int32(playerSize*float32(i)), 15+int32(playerSize*float32(j)), 10, rl.LightGray) - } - } - - rl.DrawRectangleRec(player1, rl.Red) - rl.DrawRectangleRec(player2, rl.Blue) - rl.EndMode2D() - - rl.DrawRectangle(0, 0, screenW/2, 30, rl.Fade(rl.RayWhite, 0.6)) - rl.DrawText("PLAYER 2 ARROW KEYS", 10, 10, 10, rl.Maroon) - rl.EndTextureMode() - - rl.BeginDrawing() - rl.ClearBackground(rl.Black) - - rl.DrawTextureRec(screenCam1.Texture, splitScreenRec, rl.NewVector2(0, 0), rl.White) - rl.DrawTextureRec(screenCam2.Texture, splitScreenRec, rl.NewVector2(float32(screenW/2), 0), rl.White) - rl.DrawRectangle((screenW/2)-2, 0, 4, screenH, rl.LightGray) - - rl.EndDrawing() - - } - - rl.UnloadRenderTexture(screenCam1) - rl.UnloadRenderTexture(screenCam2) - - rl.CloseWindow() -} diff --git a/examples/core/2d_paint/main.go b/examples/core/2d_paint/main.go index 5c83e85..a00ac7d 100644 --- a/examples/core/2d_paint/main.go +++ b/examples/core/2d_paint/main.go @@ -3,7 +3,7 @@ package main import ( "os" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + rl "github.com/gen2brain/raylib-go/raylib" ) const colorCount = 23 @@ -139,7 +139,7 @@ func main() { } if btnSaveMouseHover && rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsKeyPressed(rl.KeyS) { - image := rl.LoadImageFromTexture(target.Texture) + image := rl.GetTextureData(target.Texture) rl.ImageFlipVertical(*&image) rl.ExportImage(*image, "export.png") rl.UnloadImage(image) @@ -214,3 +214,4 @@ func main() { os.Exit(0) } + diff --git a/examples/core/3d_camera_first_person/main.go b/examples/core/3d_camera_first_person/main.go index 95ecee5..5b6d5b3 100644 --- a/examples/core/3d_camera_first_person/main.go +++ b/examples/core/3d_camera_first_person/main.go @@ -1,43 +1,22 @@ package main import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( - maxColumns = 20 - screenWidth = 800 - screenHeight = 450 - False = 0 - True = 1 + maxColumns = 20 ) -var camModes = map[rl.CameraMode]string{ - rl.CameraFree: "FREE", - rl.CameraOrbital: "ORBITAL", - rl.CameraFirstPerson: "FIRST PERSON", - rl.CameraThirdPerson: "THIRD PERSON", -} - -var camProjections = map[rl.CameraProjection]string{ - rl.CameraPerspective: "PERSPECTIVE", - rl.CameraOrthographic: "ORTHOGRAPHIC", -} - func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person") + rl.InitWindow(800, 450, "raylib [core] example - 3d camera first person") - // Define the camera to look into our 3d world (position, target, up vector) camera := rl.Camera3D{} - camera.Position = rl.NewVector3(0.0, 2.0, 4.0) // Camera position - camera.Target = rl.NewVector3(0.0, 2.0, 0.0) // Camera looking at point - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) // Camera up vector (rotation towards target) - camera.Fovy = 60.0 // Camera field-of-view Y - camera.Projection = rl.CameraPerspective // Camera projection type - - cameraMode := rl.CameraFirstPerson + camera.Position = rl.NewVector3(4.0, 2.0, 4.0) + camera.Target = rl.NewVector3(0.0, 1.8, 0.0) + camera.Up = rl.NewVector3(0.0, 1.0, 0.0) + camera.Fovy = 60.0 + camera.Projection = rl.CameraPerspective // Generates some random columns heights := make([]float32, maxColumns) @@ -45,81 +24,17 @@ func main() { colors := make([]rl.Color, maxColumns) for i := 0; i < maxColumns; i++ { - heights[i] = rndF(1, 12) - positions[i] = rl.NewVector3(rndF(-15, 15), heights[i]/2, rndF(-15, 15)) - colors[i] = rl.NewColor(rndU(20, 255), rndU(10, 55), 30, 255) + heights[i] = float32(rl.GetRandomValue(1, 12)) + positions[i] = rl.NewVector3(float32(rl.GetRandomValue(-15, 15)), heights[i]/2, float32(rl.GetRandomValue(-15, 15))) + colors[i] = rl.NewColor(uint8(rl.GetRandomValue(20, 255)), uint8(rl.GetRandomValue(10, 55)), 30, 255) } - rl.DisableCursor() // Limit cursor to relative movement inside the window - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second + rl.SetCameraMode(camera, rl.CameraFirstPerson) // Set a first person camera mode - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Switch camera mode - if rl.IsKeyPressed(rl.KeyOne) { - cameraMode = rl.CameraFree - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) // Reset roll - } - if rl.IsKeyPressed(rl.KeyTwo) { - cameraMode = rl.CameraFirstPerson - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) // Reset roll - } - if rl.IsKeyPressed(rl.KeyThree) { - cameraMode = rl.CameraThirdPerson - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) // Reset roll - } - if rl.IsKeyPressed(rl.KeyFour) { - cameraMode = rl.CameraOrbital - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) // Reset roll - } + rl.SetTargetFPS(60) - // Switch camera projection - if rl.IsKeyPressed(rl.KeyP) { - cameraMode = rl.CameraThirdPerson - if camera.Projection == rl.CameraPerspective { - // Create isometric view - // Note: The target distance is related to the render distance in the orthographic projection - camera.Position = rl.NewVector3(0.0, 2.0, -100.0) - camera.Target = rl.NewVector3(0.0, 2.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Projection = rl.CameraOrthographic - camera.Fovy = 20.0 // near plane width in CAMERA_ORTHOGRAPHIC - rl.CameraYaw(&camera, -135*rl.Deg2rad, True) - rl.CameraPitch(&camera, -45*rl.Deg2rad, True, True, False) - } else if camera.Projection == rl.CameraOrthographic { - // Reset to default view - camera.Position = rl.NewVector3(0.0, 2.0, 10.0) - camera.Target = rl.NewVector3(0.0, 2.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Projection = rl.CameraPerspective - camera.Fovy = 60.0 - } - } - - // Update camera computes movement internally depending on the camera mode. - // Some default standard keyboard/mouse inputs are hardcoded to simplify use. - // For advance camera controls, it's recommended to compute camera movement manually. - rl.UpdateCamera(&camera, cameraMode) // Update camera - - /* - // Camera PRO usage example (EXPERIMENTAL) - // This new camera function allows custom movement/rotation values to be directly provided - // as input parameters, with this approach, rcamera module is internally independent of raylib inputs - UpdateCameraPro(&camera, - (Vector3){ - (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward - (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, - (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left - (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, - 0.0f // Move up-down - }, - (Vector3){ - GetMouseDelta().x*0.05f, // Rotation: yaw - GetMouseDelta().y*0.05f, // Rotation: pitch - 0.0f // Rotation: roll - }, - GetMouseWheelMove()*2.0f); // Move to target (zoom) - */ + for !rl.WindowShouldClose() { + rl.UpdateCamera(&camera) // Update camera rl.BeginDrawing() @@ -138,57 +53,17 @@ func main() { rl.DrawCubeWires(positions[i], 2.0, heights[i], 2.0, rl.Maroon) } - // Draw player cube - if cameraMode == rl.CameraThirdPerson { - rl.DrawCube(camera.Target, 0.5, 0.5, 0.5, rl.Purple) - rl.DrawCubeWires(camera.Target, 0.5, 0.5, 0.5, rl.DarkPurple) - } - rl.EndMode3D() - // Draw info boxes - rl.DrawRectangle(5, 5, 330, 100, rl.Fade(rl.SkyBlue, 0.5)) - rl.DrawRectangleLines(5, 5, 330, 100, rl.Blue) + rl.DrawRectangle(10, 10, 220, 70, rl.Fade(rl.SkyBlue, 0.5)) + rl.DrawRectangleLines(10, 10, 220, 70, rl.Blue) - rl.DrawText("Camera controls:", 15, 15, 10, rl.Black) - rl.DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, rl.Black) - rl.DrawText("- Look around: arrow keys or mouse", 15, 45, 10, rl.Black) - rl.DrawText("- Camera mode keys: 1,2,3,4", 15, 60, 10, rl.Black) - rl.DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, rl.Black) - rl.DrawText("- Camera projection key: P", 15, 90, 10, rl.Black) - - rl.DrawRectangle(600, 5, 195, 100, rl.Fade(rl.SkyBlue, 0.5)) - rl.DrawRectangleLines(600, 5, 195, 100, rl.Blue) - - rl.DrawText("Camera status:", 610, 15, 10, rl.Black) - rl.DrawText(s2T("Mode:", camModes[cameraMode]), 610, 30, 10, rl.Black) - rl.DrawText(s2T("Projection:", camProjections[camera.Projection]), 610, 45, 10, rl.Black) - rl.DrawText(s2T("Position:", v2T(camera.Position)), 610, 60, 10, rl.Black) - rl.DrawText(s2T("Target:", v2T(camera.Target)), 610, 75, 10, rl.Black) - rl.DrawText(s2T("Up:", v2T(camera.Up)), 610, 90, 10, rl.Black) + rl.DrawText("First person camera default controls:", 20, 20, 10, rl.Black) + rl.DrawText("- Move with keys: W, A, S, D", 40, 40, 10, rl.DarkGray) + rl.DrawText("- Mouse move to look around", 40, 60, 10, rl.DarkGray) rl.EndDrawing() } rl.CloseWindow() } - -// rndU generates a random uint8 value between min and max -func rndU(min, max int32) uint8 { - return uint8(rl.GetRandomValue(min, max)) -} - -// rndF generates a random float32 value between min and max -func rndF(min, max int32) float32 { - return float32(rl.GetRandomValue(min, max)) -} - -// s2t generates a Status item string from a name and value -func s2T(name, value string) string { - return fmt.Sprintf(" - %s %s", name, value) -} - -// v2T generates a string from a rl.Vector3 -func v2T(v rl.Vector3) string { - return fmt.Sprintf("%6.3f, %6.3f, %6.3f", v.X, v.Y, v.Z) -} diff --git a/examples/core/3d_camera_free/main.go b/examples/core/3d_camera_free/main.go index c4b4751..6dd86d7 100644 --- a/examples/core/3d_camera_free/main.go +++ b/examples/core/3d_camera_free/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -16,10 +16,12 @@ func main() { cubePosition := rl.NewVector3(0.0, 0.0, 0.0) + rl.SetCameraMode(camera, rl.CameraFree) // Set a free camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode + rl.UpdateCamera(&camera) // Update camera if rl.IsKeyDown(rl.KeyZ) { camera.Target = rl.NewVector3(0.0, 0.0, 0.0) @@ -44,6 +46,8 @@ func main() { rl.DrawText("Free camera default controls:", 20, 20, 10, rl.Black) rl.DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, rl.DarkGray) rl.DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, rl.DarkGray) + rl.DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, rl.DarkGray) + rl.DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, rl.DarkGray) rl.DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, rl.DarkGray) rl.EndDrawing() diff --git a/examples/core/3d_camera_splitscreen/main.go b/examples/core/3d_camera_splitscreen/main.go deleted file mode 100644 index 8a8dc5a..0000000 --- a/examples/core/3d_camera_splitscreen/main.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenW = int32(800) - screenH = int32(450) - cam1, cam2 rl.Camera3D -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [core] example - 3d camera split screen") - - // Setup player 1 camera and screen - cam1.Fovy = 45 - cam1.Up.Y = 1 - cam1.Target.Y = 1 - cam1.Position.Z = -3 - cam1.Position.Y = 1 - - // Setup player two camera and screen - cam2.Fovy = 45 - cam2.Up.Y = 1 - cam2.Target.Y = 3 - cam2.Position.X = -3 - cam2.Position.Y = 3 - - screenCam1 := rl.LoadRenderTexture(screenW/2, screenH) - screenCam2 := rl.LoadRenderTexture(screenW/2, screenH) - - splitScreenRec := rl.NewRectangle(0, 0, float32(screenCam1.Texture.Width), -float32(screenCam1.Texture.Height)) - - count := float32(5) - spacing := float32(4) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - // If anyone moves this frame, how far will they move based on the time - // since the last frame this moves things at 10 world units per second, - // regardless of the actual FPS - frameOffset := 10 * rl.GetFrameTime() - - // Move Player1 forward and backwards (no turning) - if rl.IsKeyDown(rl.KeyW) { - cam1.Position.Z += frameOffset - cam1.Target.Z += frameOffset - } else if rl.IsKeyDown(rl.KeyS) { - cam1.Position.Z -= frameOffset - cam1.Target.Z -= frameOffset - } - - // Move Player2 forward and backwards (no turning) - if rl.IsKeyDown(rl.KeyUp) { - cam2.Position.X += frameOffset - cam2.Target.X += frameOffset - } else if rl.IsKeyDown(rl.KeyDown) { - cam2.Position.X -= frameOffset - cam2.Target.X -= frameOffset - } - - // Draw Player1 view to the render texture - rl.BeginTextureMode(screenCam1) - rl.ClearBackground(rl.SkyBlue) - rl.BeginMode3D(cam1) - - rl.DrawPlane(rl.Vector3Zero(), rl.NewVector2(50, 50), rl.Beige) - - for x := -count * spacing; x <= count*spacing; x += spacing { - for z := -count * spacing; z <= count*spacing; z += spacing { - rl.DrawCube(rl.NewVector3(x-0.5, 1.5, z), 1, 1, 1, rl.Lime) - rl.DrawCube(rl.NewVector3(x-0.5, 0.5, z), 0.25, 1, 0.25, rl.Brown) - } - } - - rl.DrawCube(cam1.Position, 1, 1, 1, rl.Red) - rl.DrawCube(cam2.Position, 1, 1, 1, rl.Blue) - - rl.EndMode3D() - - rl.DrawRectangle(0, 0, screenW/2, 40, rl.Fade(rl.RayWhite, 0.8)) - rl.DrawText("PLAYER1: W/S to move", 10, 10, 20, rl.Maroon) - rl.EndTextureMode() - - // Draw Player2 view to the render texture - rl.BeginTextureMode(screenCam2) - rl.ClearBackground(rl.SkyBlue) - rl.BeginMode3D(cam2) - - rl.DrawPlane(rl.Vector3Zero(), rl.NewVector2(50, 50), rl.Beige) - - for x := -count * spacing; x <= count*spacing; x += spacing { - for z := -count * spacing; z <= count*spacing; z += spacing { - rl.DrawCube(rl.NewVector3(x, 1.5, z), 1, 1, 1, rl.Lime) - rl.DrawCube(rl.NewVector3(x, 0.5, z), 0.25, 1, 0.25, rl.Brown) - } - } - - rl.DrawCube(cam1.Position, 1, 1, 1, rl.Red) - rl.DrawCube(cam2.Position, 1, 1, 1, rl.Blue) - - rl.EndMode3D() - - rl.DrawRectangle(0, 0, screenW/2, 40, rl.Fade(rl.RayWhite, 0.8)) - rl.DrawText("PLAYER2: UP/DOWN to move", 10, 10, 20, rl.Maroon) - rl.EndTextureMode() - - // Draw both views render textures to the screen side by side - rl.BeginDrawing() - rl.ClearBackground(rl.Black) - - rl.DrawTextureRec(screenCam1.Texture, splitScreenRec, rl.NewVector2(0, 0), rl.White) - rl.DrawTextureRec(screenCam2.Texture, splitScreenRec, rl.NewVector2(float32(screenW/2), 0), rl.White) - rl.DrawRectangle((screenW/2)-2, 0, 4, screenH, rl.LightGray) - - rl.EndDrawing() - - } - - rl.UnloadRenderTexture(screenCam1) - rl.UnloadRenderTexture(screenCam2) - - rl.CloseWindow() -} diff --git a/examples/core/3d_mode/main.go b/examples/core/3d_mode/main.go index 6cf6a63..2d8e882 100644 --- a/examples/core/3d_mode/main.go +++ b/examples/core/3d_mode/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/core/3d_picking/main.go b/examples/core/3d_picking/main.go index 1bba7ae..04832d9 100644 --- a/examples/core/3d_picking/main.go +++ b/examples/core/3d_picking/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -21,24 +21,23 @@ func main() { cubeSize := rl.NewVector3(2.0, 2.0, 2.0) var ray rl.Ray - var collision rl.RayCollision + + collision := false + + rl.SetCameraMode(camera, rl.CameraFree) // Set a free camera mode rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode + rl.UpdateCamera(&camera) // Update camera if rl.IsMouseButtonPressed(rl.MouseLeftButton) { - if !collision.Hit { - ray = rl.GetMouseRay(rl.GetMousePosition(), camera) + ray = rl.GetMouseRay(rl.GetMousePosition(), camera) - // Check collision between ray and box - min := rl.NewVector3(cubePosition.X-cubeSize.X/2, cubePosition.Y-cubeSize.Y/2, cubePosition.Z-cubeSize.Z/2) - max := rl.NewVector3(cubePosition.X+cubeSize.X/2, cubePosition.Y+cubeSize.Y/2, cubePosition.Z+cubeSize.Z/2) - collision = rl.GetRayCollisionBox(ray, rl.NewBoundingBox(min, max)) - } else { - collision.Hit = false - } + // Check collision between ray and box + min := rl.NewVector3(cubePosition.X-cubeSize.X/2, cubePosition.Y-cubeSize.Y/2, cubePosition.Z-cubeSize.Z/2) + max := rl.NewVector3(cubePosition.X+cubeSize.X/2, cubePosition.Y+cubeSize.Y/2, cubePosition.Z+cubeSize.Z/2) + collision = rl.CheckCollisionRayBox(ray, rl.NewBoundingBox(min, max)) } rl.BeginDrawing() @@ -47,7 +46,7 @@ func main() { rl.BeginMode3D(camera) - if collision.Hit { + if collision { rl.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, rl.Red) rl.DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, rl.Maroon) @@ -65,7 +64,7 @@ func main() { rl.DrawText("Try selecting the box with mouse!", 240, 10, 20, rl.DarkGray) - if collision.Hit { + if collision { rl.DrawText("BOX SELECTED", (screenWidth-rl.MeasureText("BOX SELECTED", 30))/2, int32(float32(screenHeight)*0.1), 30, rl.Green) } diff --git a/examples/core/basic_window/main.go b/examples/core/basic_window/main.go index ced965d..d28f846 100644 --- a/examples/core/basic_window/main.go +++ b/examples/core/basic_window/main.go @@ -1,6 +1,6 @@ package main -import "git.terah.dev/UnrealXR/raylib-go/raylib" +import "github.com/gen2brain/raylib-go/raylib" func main() { rl.SetConfigFlags(rl.FlagVsyncHint) diff --git a/examples/core/basic_window_manager/main.go b/examples/core/basic_window_manager/main.go deleted file mode 100644 index 98ac1a6..0000000 --- a/examples/core/basic_window_manager/main.go +++ /dev/null @@ -1,106 +0,0 @@ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const screenW = int32(1280) -const screenH = int32(720) - -type gameScreen int - -const ( - LOGO = iota - TITLE - GAMEPLAY - ENDING -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [core] example - basic screen manager") - - var currentScreen gameScreen - currentScreen = LOGO - frames := 0 - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - switch currentScreen { - case LOGO: - frames++ - if frames > 240 { - currentScreen = TITLE - } - case TITLE: - if rl.IsKeyPressed(rl.KeyEnter) { - currentScreen = GAMEPLAY - } - case GAMEPLAY: - if rl.IsKeyPressed(rl.KeyEnter) { - currentScreen = ENDING - } - case ENDING: - if rl.IsKeyPressed(rl.KeyEnter) { - currentScreen = LOGO - frames = 0 - } - } - - rl.BeginDrawing() - - rl.ClearBackground(rl.Black) - rec := rl.NewRectangle(0, 0, float32(screenW), float32(screenH)) - switch currentScreen { - case LOGO: - txt := "YOUR LOGO GOES HERE" - txtlen := rl.MeasureText(txt, 50) - rl.DrawText(txt, screenW/2-txtlen/2-3, screenH/2-50+3, 50, rl.Magenta) - rl.DrawText(txt, screenW/2-txtlen/2-1, screenH/2-50+1, 50, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2-50, 50, rl.White) - txt = "this message disappears in " + fmt.Sprint(240-frames) + " frames" - txtlen = rl.MeasureText(txt, 30) - rl.DrawText(txt, screenW/2-txtlen/2-3, screenH/2+3, 30, rl.Magenta) - rl.DrawText(txt, screenW/2-txtlen/2-1, screenH/2+1, 30, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2, 30, rl.White) - case TITLE: - rl.DrawRectangleRec(rec, rl.DarkGreen) - txt := "AN AMAZING TITLE GOES HERE" - txtlen := rl.MeasureText(txt, 50) - rl.DrawText(txt, screenW/2-txtlen/2-2, screenH/2-50+2, 50, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2-50, 50, rl.White) - txt = "press enter to move to next screen" - txtlen = rl.MeasureText(txt, 30) - rl.DrawText(txt, screenW/2-txtlen/2-2, screenH/2+2, 30, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2, 30, rl.White) - case GAMEPLAY: - rl.DrawRectangleRec(rec, rl.DarkPurple) - txt := "FUN GAMEPLAY GOES HERE" - txtlen := rl.MeasureText(txt, 50) - rl.DrawText(txt, screenW/2-txtlen/2-2, screenH/2-50+2, 50, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2-50, 50, rl.White) - txt = "press enter to move to next screen" - txtlen = rl.MeasureText(txt, 30) - rl.DrawText(txt, screenW/2-txtlen/2-2, screenH/2+2, 30, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2, 30, rl.White) - case ENDING: - rl.DrawRectangleRec(rec, rl.DarkBlue) - txt := "A DRAMATIC ENDING GOES HERE" - txtlen := rl.MeasureText(txt, 50) - rl.DrawText(txt, screenW/2-txtlen/2-2, screenH/2-50+2, 50, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2-50, 50, rl.White) - txt = "press enter to move to next screen" - txtlen = rl.MeasureText(txt, 30) - rl.DrawText(txt, screenW/2-txtlen/2-2, screenH/2+2, 30, rl.Black) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2, 30, rl.White) - } - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/core/color_select/main.go b/examples/core/color_select/main.go index 2bb9bd3..dd107d6 100644 --- a/examples/core/color_select/main.go +++ b/examples/core/color_select/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { rl.InitWindow(800, 450, "raylib [core] example - color selection (collision detection)") diff --git a/examples/core/core_split_screen/main.go b/examples/core/core_split_screen/main.go deleted file mode 100644 index dd70554..0000000 --- a/examples/core/core_split_screen/main.go +++ /dev/null @@ -1,144 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -/******************************************************************************************* -* -* raylib [core] example - split screen -* -* Example originally created with raylib 3.7, last time updated with raylib 4.0 -* -* Example contributed by Jeffery Myers (@JeffM2501) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2021-2022 Jeffery Myers (@JeffM2501) -* -********************************************************************************************/ - -var cameraPlayer1 rl.Camera -var cameraPlayer2 rl.Camera - -// Scene drawing -func DrawScene() { - count := float32(5.0) - spacing := float32(4.0) - - // Grid of cube trees on a plane to make a "world" - rl.DrawPlane(rl.Vector3{0, 0, 0}, rl.Vector2{50, 50}, rl.Beige) // Simple world plane - - for x := -float32(count * spacing); x <= count*spacing; x += spacing { - for z := -float32(count * spacing); z <= count*spacing; z += spacing { - rl.DrawCube(rl.Vector3{x, 1.5, z}, 1, 1, 1, rl.Lime) - rl.DrawCube(rl.Vector3{x, 0.5, z}, 0.25, 1, 0.25, rl.Brown) - } - } - - // Draw a cube at each player's position - rl.DrawCube(cameraPlayer1.Position, 1, 1, 1, rl.Red) - rl.DrawCube(cameraPlayer2.Position, 1, 1, 1, rl.Blue) -} - -// ------------------------------------------------------------------------------------ -// Program main entry point -// ------------------------------------------------------------------------------------ -func main() { - // Initialization - //-------------------------------------------------------------------------------------- - const ( - screenWidth = 800 - screenHeight = 450 - ) - - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - split screen") - - // Setup player 1 camera and screen - cameraPlayer1.Fovy = 45.0 - cameraPlayer1.Up.Y = 1.0 - cameraPlayer1.Target.Y = 1.0 - cameraPlayer1.Position.Z = -3.0 - cameraPlayer1.Position.Y = 1.0 - - screenPlayer1 := rl.LoadRenderTexture(screenWidth/2, screenHeight) - - // Setup player two camera and screen - cameraPlayer2.Fovy = 45.0 - cameraPlayer2.Up.Y = 1.0 - cameraPlayer2.Target.Y = 3.0 - cameraPlayer2.Position.X = -3.0 - cameraPlayer2.Position.Y = 3.0 - - screenPlayer2 := rl.LoadRenderTexture(screenWidth/2, screenHeight) - - // Build a flipped rectangle the size of the split view to use for drawing later - splitScreenRect := rl.Rectangle{0.0, 0.0, float32(screenPlayer1.Texture.Width), float32(-screenPlayer1.Texture.Height)} - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - // If anyone moves this frame, how far will they move based on the time since the last frame - // this moves thigns at 10 world units per second, regardless of the actual FPS - offsetThisFrame := 10.0 * rl.GetFrameTime() - - // Move Player1 forward and backwards (no turning) - if rl.IsKeyDown(rl.KeyW) { - cameraPlayer1.Position.Z += offsetThisFrame - cameraPlayer1.Target.Z += offsetThisFrame - } else if rl.IsKeyDown(rl.KeyS) { - cameraPlayer1.Position.Z -= offsetThisFrame - cameraPlayer1.Target.Z -= offsetThisFrame - } - - // Move Player2 forward and backwards (no turning) - if rl.IsKeyDown(rl.KeyUp) { - cameraPlayer2.Position.X += offsetThisFrame - cameraPlayer2.Target.X += offsetThisFrame - } else if rl.IsKeyDown(rl.KeyDown) { - cameraPlayer2.Position.X -= offsetThisFrame - cameraPlayer2.Target.X -= offsetThisFrame - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - // Draw Player1 view to the render texture - rl.BeginTextureMode(screenPlayer1) - rl.ClearBackground(rl.SkyBlue) - rl.BeginMode3D(cameraPlayer1) - DrawScene() - rl.EndMode3D() - rl.DrawText("PLAYER1 W/S to move", 10, 10, 20, rl.Red) - rl.EndTextureMode() - - // Draw Player2 view to the render texture - rl.BeginTextureMode(screenPlayer2) - rl.ClearBackground(rl.SkyBlue) - rl.BeginMode3D(cameraPlayer2) - DrawScene() - rl.EndMode3D() - rl.DrawText("PLAYER2 UP/DOWN to move", 10, 10, 20, rl.Blue) - rl.EndTextureMode() - - // Draw both views render textures to the screen side by side - rl.BeginDrawing() - rl.ClearBackground(rl.Black) - rl.DrawTextureRec(screenPlayer1.Texture, splitScreenRect, rl.Vector2{0, 0}, rl.White) - rl.DrawTextureRec(screenPlayer2.Texture, splitScreenRect, rl.Vector2{screenWidth / 2.0, 0}, rl.White) - rl.EndDrawing() - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.UnloadRenderTexture(screenPlayer1) // Unload render texture - rl.UnloadRenderTexture(screenPlayer2) // Unload render texture - - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} diff --git a/examples/core/custom_frame_control/main.go b/examples/core/custom_frame_control/main.go deleted file mode 100644 index 4498b48..0000000 --- a/examples/core/custom_frame_control/main.go +++ /dev/null @@ -1,131 +0,0 @@ -package main - -/******************************************************************************************* -* -* raylib [core] example - custom frame control -* -* NOTE: WARNING: This is an example for advanced users willing to have full control over -* the frame processes. By default, EndDrawing() calls the following processes: -* 1. Draw remaining batch data: rlDrawRenderBatchActive() -* 2. SwapScreenBuffer() -* 3. Frame time control: WaitTime() -* 4. PollInputEvents() -* -* To avoid steps 2, 3 and 4, flag SUPPORT_CUSTOM_FRAME_CONTROL can be enabled in -* config.h (it requires recompiling raylib). This way those steps are up to the user. -* -* Note that enabling this flag invalidates some functions: -* - GetFrameTime() -* - SetTargetFPS() -* - GetFPS() -* -* Example originally created with raylib 4.0, last time updated with raylib 4.0 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2021-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - Custom Frame Control") - - previousTime := rl.GetTime() - currentTime := 0.0 - updateDrawTime := 0.0 - waitTime := 0.0 - deltaTime := 0.0 - - timeCounter := 0.0 - position := 0.0 - pause := false - - targetFPS := 60 - - for !rl.WindowShouldClose() { - rl.PollInputEvents() // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL) - - if rl.IsKeyPressed(rl.KeySpace) { - pause = !pause - } - if rl.IsKeyPressed(rl.KeyUp) { - targetFPS += 20 - } else if rl.IsKeyPressed(rl.KeyDown) { - targetFPS -= 20 - } - - if targetFPS < 0 { - targetFPS = 0 - } - - if !pause { - position += 200 * deltaTime // We move at 200 pixels per second - if position >= float64(rl.GetScreenWidth()) { - position = 0 - } - timeCounter += deltaTime // We count time (seconds) - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - for i := 0; i < rl.GetScreenWidth()/200; i++ { - rl.DrawRectangle(200*int32(i), 0, 1, int32(rl.GetScreenHeight()), rl.SkyBlue) - } - - rl.DrawCircle(int32(position), int32(rl.GetScreenHeight()/2-25), 50, rl.Red) - - msg := fmt.Sprintf("%03.0f ms", timeCounter*1000) - rl.DrawText(msg, int32(position-40), int32(rl.GetScreenHeight()/2-100), 20, rl.Maroon) - msg = fmt.Sprintf("PosX: %03.0f", position) - rl.DrawText(msg, int32(position-50), int32(rl.GetScreenHeight()/2+40), 20, rl.Black) - - msg = "Circle is moving at a constant 200 pixels/sec,\nindependently of the frame rate." - rl.DrawText(msg, 10, 10, 20, rl.DarkGray) - msg = "PRESS SPACE to PAUSE MOVEMENT" - rl.DrawText(msg, 10, int32(rl.GetScreenHeight()-60), 20, rl.Gray) - msg = "PRESS UP | DOWN to CHANGE TARGET FPS" - rl.DrawText(msg, 10, int32(rl.GetScreenHeight()-30), 20, rl.Gray) - msg = fmt.Sprintf("TARGET FPS: %d", targetFPS) - rl.DrawText(msg, int32(rl.GetScreenWidth()-220), 10, 20, rl.Lime) - msg = fmt.Sprintf("CURRENT FPS: %d", int(1/deltaTime)) - rl.DrawText(msg, int32(rl.GetScreenWidth()-220), 40, 20, rl.Lime) - - rl.EndDrawing() - - // NOTE: In case raylib is configured to SUPPORT_CUSTOM_FRAME_CONTROL, - // Events polling, screen buffer swap and frame time control must be managed by the user - - rl.SwapScreenBuffer() // We want a fixed frame rate - - currentTime = rl.GetTime() - updateDrawTime = currentTime - previousTime - - if targetFPS > 0 { // We want a fixed frame rate - waitTime = (1 / float64(targetFPS)) - updateDrawTime - if waitTime > 0 { - rl.WaitTime(waitTime) - currentTime = rl.GetTime() - deltaTime = currentTime - previousTime - } - } else { - deltaTime = updateDrawTime - } - - previousTime = currentTime - } - - rl.CloseWindow() -} diff --git a/examples/core/custom_logging/main.go b/examples/core/custom_logging/main.go deleted file mode 100644 index 76934b7..0000000 --- a/examples/core/custom_logging/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "fmt" - "time" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - // Set custom logger - rl.SetTraceLogCallback(customLog) - - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - Custom Logging") - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.DrawText("Check the console output to see the custom logger in action!", 60, 200, 20, rl.LightGray) - rl.EndDrawing() - } - - rl.CloseWindow() -} - -// Custom logging function -func customLog(msgType int, text string) { - now := time.Now() - - switch rl.TraceLogLevel(msgType) { - case rl.LogInfo: - fmt.Println("[INFO] : ", now, text) - case rl.LogError: - fmt.Println("[ERROR] : ", now, text) - case rl.LogWarning: - fmt.Println("[WARNING] : ", now, text) - case rl.LogDebug: - fmt.Println("[DEBUG] : ", now, text) - default: - fmt.Println("[UNKNOWN] : ", now, text) - } -} diff --git a/examples/core/drop_files/main.go b/examples/core/drop_files/main.go index cd05821..91a98d8 100644 --- a/examples/core/drop_files/main.go +++ b/examples/core/drop_files/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) @@ -8,13 +12,12 @@ func main() { rl.SetTargetFPS(60) - var count int + count := int32(0) var droppedFiles []string for !rl.WindowShouldClose() { if rl.IsFileDropped() { - droppedFiles = rl.LoadDroppedFiles() - count = len(droppedFiles) + droppedFiles = rl.GetDroppedFiles(&count) } rl.BeginDrawing() @@ -25,7 +28,7 @@ func main() { } else { rl.DrawText("Dropped files:", 100, 40, 20, rl.DarkGray) - for i := 0; i < count; i++ { + for i := int32(0); i < count; i++ { if i%2 == 0 { rl.DrawRectangle(0, int32(85+40*i), screenWidth, 40, rl.Fade(rl.LightGray, 0.5)) } else { @@ -41,7 +44,7 @@ func main() { rl.EndDrawing() } - rl.UnloadDroppedFiles() + rl.ClearDroppedFiles() rl.CloseWindow() } diff --git a/examples/core/gestures_detection/main.go b/examples/core/gestures_detection/main.go index 78fd200..9dc7371 100644 --- a/examples/core/gestures_detection/main.go +++ b/examples/core/gestures_detection/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + var ( maxGestureStrings int = 20 ) diff --git a/examples/core/input_gamepad/main.go b/examples/core/input_gamepad/main.go index 3a42f93..d4da677 100644 --- a/examples/core/input_gamepad/main.go +++ b/examples/core/input_gamepad/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( @@ -21,165 +21,163 @@ func main() { rl.SetTargetFPS(60) - var gamepad int32 = 0 // which gamepad to display - for !rl.WindowShouldClose() { rl.BeginDrawing() rl.ClearBackground(rl.RayWhite) - if rl.IsGamepadAvailable(gamepad) { - rl.DrawText(fmt.Sprintf("GP1: %s", rl.GetGamepadName(gamepad)), 10, 10, 10, rl.Black) + if rl.IsGamepadAvailable(rl.GamepadPlayer1) { + rl.DrawText(fmt.Sprintf("GP1: %s", rl.GetGamepadName(rl.GamepadPlayer1)), 10, 10, 10, rl.Black) - if rl.GetGamepadName(gamepad) == xbox360NameID { + if rl.IsGamepadName(rl.GamepadPlayer1, xbox360NameID) { rl.DrawTexture(texXboxPad, 0, 0, rl.DarkGray) // Draw buttons: xbox home - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddle) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonHome) { rl.DrawCircle(394, 89, 19, rl.Red) } // Draw buttons: basic - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleRight) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonStart) { rl.DrawCircle(436, 150, 9, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleLeft) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonSelect) { rl.DrawCircle(352, 150, 9, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceLeft) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonX) { rl.DrawCircle(501, 151, 15, rl.Blue) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceDown) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonA) { rl.DrawCircle(536, 187, 15, rl.Lime) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceRight) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonB) { rl.DrawCircle(572, 151, 15, rl.Maroon) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceUp) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonY) { rl.DrawCircle(536, 115, 15, rl.Gold) } // Draw buttons: d-pad rl.DrawRectangle(317, 202, 19, 71, rl.Black) rl.DrawRectangle(293, 228, 69, 19, rl.Black) - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceUp) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonUp) { rl.DrawRectangle(317, 202, 19, 26, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceDown) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonDown) { rl.DrawRectangle(317, 202+45, 19, 26, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceLeft) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonLeft) { rl.DrawRectangle(292, 228, 25, 19, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceRight) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonRight) { rl.DrawRectangle(292+44, 228, 26, 19, rl.Red) } // Draw buttons: left-right back - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftTrigger1) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonLb) { rl.DrawCircle(259, 61, 20, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightTrigger1) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadXboxButtonRb) { rl.DrawCircle(536, 61, 20, rl.Red) } // Draw axis: left joystick rl.DrawCircle(259, 152, 39, rl.Black) rl.DrawCircle(259, 152, 34, rl.LightGray) - rl.DrawCircle(int32(259+(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisLeftX)*20)), - int32(152-(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisLeftY)*20)), 25, rl.Black) + rl.DrawCircle(int32(259+(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadXboxAxisLeftX)*20)), + int32(152-(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadXboxAxisLeftY)*20)), 25, rl.Black) // Draw axis: right joystick rl.DrawCircle(461, 237, 38, rl.Black) rl.DrawCircle(461, 237, 33, rl.LightGray) - rl.DrawCircle(int32(461+(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisRightX)*20)), - int32(237-(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisRightY)*20)), 25, rl.Black) + rl.DrawCircle(int32(461+(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadXboxAxisRightX)*20)), + int32(237-(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadXboxAxisRightY)*20)), 25, rl.Black) // Draw axis: left-right triggers rl.DrawRectangle(170, 30, 15, 70, rl.Gray) rl.DrawRectangle(604, 30, 15, 70, rl.Gray) - rl.DrawRectangle(170, 30, 15, int32(((1.0+rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisLeftTrigger))/2.0)*70), rl.Red) - rl.DrawRectangle(604, 30, 15, int32(((1.0+rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisRightTrigger))/2.0)*70), rl.Red) + rl.DrawRectangle(170, 30, 15, int32(((1.0+rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadXboxAxisLt))/2.0)*70), rl.Red) + rl.DrawRectangle(604, 30, 15, int32(((1.0+rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadXboxAxisRt))/2.0)*70), rl.Red) - } else if rl.GetGamepadName(gamepad) == ps3NameID { + } else if rl.IsGamepadName(rl.GamepadPlayer1, ps3NameID) { rl.DrawTexture(texPs3Pad, 0, 0, rl.DarkGray) // Draw buttons: ps - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddle) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonPs) { rl.DrawCircle(396, 222, 13, rl.Red) } // Draw buttons: basic - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleLeft) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonSelect) { rl.DrawRectangle(328, 170, 32, 13, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleRight) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonStart) { rl.DrawTriangle(rl.NewVector2(436, 168), rl.NewVector2(436, 185), rl.NewVector2(464, 177), rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceUp) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonTriangle) { rl.DrawCircle(557, 144, 13, rl.Lime) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceRight) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonCircle) { rl.DrawCircle(586, 173, 13, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceDown) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonCross) { rl.DrawCircle(557, 203, 13, rl.Violet) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceLeft) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonSquare) { rl.DrawCircle(527, 173, 13, rl.Pink) } // Draw buttons: d-pad rl.DrawRectangle(225, 132, 24, 84, rl.Black) rl.DrawRectangle(195, 161, 84, 25, rl.Black) - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceUp) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonUp) { rl.DrawRectangle(225, 132, 24, 29, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceDown) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonDown) { rl.DrawRectangle(225, 132+54, 24, 30, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceLeft) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonLeft) { rl.DrawRectangle(195, 161, 30, 25, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceRight) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonRight) { rl.DrawRectangle(195+54, 161, 30, 25, rl.Red) } // Draw buttons: left-right back buttons - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftTrigger1) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonL1) { rl.DrawCircle(239, 82, 20, rl.Red) } - if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightTrigger1) { + if rl.IsGamepadButtonDown(rl.GamepadPlayer1, rl.GamepadPs3ButtonR1) { rl.DrawCircle(557, 82, 20, rl.Red) } // Draw axis: left joystick rl.DrawCircle(319, 255, 35, rl.Black) rl.DrawCircle(319, 255, 31, rl.LightGray) - rl.DrawCircle(int32(319+(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisLeftX)*20)), - int32(255+(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisLeftY)*20)), 25, rl.Black) + rl.DrawCircle(int32(319+(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadPs3AxisLeftX)*20)), + int32(255+(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadPs3AxisLeftY)*20)), 25, rl.Black) // Draw axis: right joystick rl.DrawCircle(475, 255, 35, rl.Black) rl.DrawCircle(475, 255, 31, rl.LightGray) - rl.DrawCircle(int32(475+(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisRightX)*20)), - int32(255+(rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisRightY)*20)), 25, rl.Black) + rl.DrawCircle(int32(475+(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadPs3AxisRightX)*20)), + int32(255+(rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadPs3AxisRightY)*20)), 25, rl.Black) // Draw axis: left-right triggers rl.DrawRectangle(169, 48, 15, 70, rl.Gray) rl.DrawRectangle(611, 48, 15, 70, rl.Gray) - rl.DrawRectangle(169, 48, 15, int32(((1.0-rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisLeftTrigger))/2.0)*70), rl.Red) - rl.DrawRectangle(611, 48, 15, int32(((1.0-rl.GetGamepadAxisMovement(gamepad, rl.GamepadAxisRightTrigger))/2.0)*70), rl.Red) + rl.DrawRectangle(169, 48, 15, int32(((1.0-rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadPs3AxisL2))/2.0)*70), rl.Red) + rl.DrawRectangle(611, 48, 15, int32(((1.0-rl.GetGamepadAxisMovement(rl.GamepadPlayer1, rl.GamepadPs3AxisR2))/2.0)*70), rl.Red) } else { rl.DrawText("- GENERIC GAMEPAD -", 280, 180, 20, rl.Gray) // TODO: Draw generic gamepad } - rl.DrawText(fmt.Sprintf("DETECTED AXIS [%d]:", rl.GetGamepadAxisCount(gamepad)), 10, 50, 10, rl.Maroon) + rl.DrawText(fmt.Sprintf("DETECTED AXIS [%d]:", rl.GetGamepadAxisCount(rl.GamepadPlayer1)), 10, 50, 10, rl.Maroon) - for i := int32(0); i < rl.GetGamepadAxisCount(gamepad); i++ { - rl.DrawText(fmt.Sprintf("AXIS %d: %.02f", i, rl.GetGamepadAxisMovement(gamepad, i)), 20, 70+20*i, 10, rl.DarkGray) + for i := int32(0); i < rl.GetGamepadAxisCount(rl.GamepadPlayer1); i++ { + rl.DrawText(fmt.Sprintf("AXIS %d: %.02f", i, rl.GetGamepadAxisMovement(rl.GamepadPlayer1, i)), 20, 70+20*i, 10, rl.DarkGray) } if rl.GetGamepadButtonPressed() != -1 { diff --git a/examples/core/input_keys/main.go b/examples/core/input_keys/main.go index 90d2be8..1b6bb65 100644 --- a/examples/core/input_keys/main.go +++ b/examples/core/input_keys/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/core/input_mouse/main.go b/examples/core/input_mouse/main.go index 72d2af6..94f3a06 100644 --- a/examples/core/input_mouse/main.go +++ b/examples/core/input_mouse/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/core/mouse_wheel/main.go b/examples/core/mouse_wheel/main.go index bfa2819..288dfff 100644 --- a/examples/core/mouse_wheel/main.go +++ b/examples/core/mouse_wheel/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -18,7 +18,7 @@ func main() { rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - boxPositionY -= int32(rl.GetMouseWheelMove()) * scrollSpeed + boxPositionY -= rl.GetMouseWheelMove() * scrollSpeed rl.BeginDrawing() diff --git a/examples/core/random_values/main.go b/examples/core/random_values/main.go index c0a88a8..bb6f188 100644 --- a/examples/core/random_values/main.go +++ b/examples/core/random_values/main.go @@ -3,13 +3,13 @@ package main import ( "fmt" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { rl.InitWindow(800, 450, "raylib [core] example - generate random values") - framesCounter := 0 // Variable used to count frames + framesCounter := 0 // Variable used to count frames randValue := rl.GetRandomValue(-8, 5) // Get a random integer number between -8 and 5 (both included) rl.SetTargetFPS(60) diff --git a/examples/core/scissor_test/main.go b/examples/core/scissor_test/main.go deleted file mode 100644 index 2be5593..0000000 --- a/examples/core/scissor_test/main.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenW = int32(800) - screenH = int32(450) -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [core] example - scissor test") - - scissorArea := rl.NewRectangle(0, 0, 300, 300) - scissorMode := true - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - if rl.IsKeyPressed(rl.KeyS) { - scissorMode = !scissorMode - } - - scissorArea.X = float32(rl.GetMouseX()) - scissorArea.Y = float32(rl.GetMouseY()) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - if scissorMode { - rl.BeginScissorMode(scissorArea.ToInt32().X, scissorArea.ToInt32().Y, scissorArea.ToInt32().Width, scissorArea.ToInt32().Height) - } - - rl.DrawRectangle(0, 0, screenW, screenH, rl.Red) - rl.DrawText("MOVE MOUSE TO REVEAL TEXT", 190, 200, 20, rl.Black) - - if scissorMode { - rl.EndScissorMode() - } - - rl.DrawRectangleLinesEx(scissorArea, 1, rl.Black) - rl.DrawText("S KEY TO TOGGLE MODE", 10, 10, 20, rl.Black) - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/core/smooth_pixelperfect/main.go b/examples/core/smooth_pixelperfect/main.go deleted file mode 100644 index b137f67..0000000 --- a/examples/core/smooth_pixelperfect/main.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "fmt" - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const screenW = int32(1280) -const screenH = int32(720) -const virtualScreenW = screenW / 5 -const virtualScreenH = screenH / 5 -const virtualRatio = float32(screenW) / float32(virtualScreenW) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [core] example - smooth pixel-perfect camera") - - worldSpaceCam := rl.Camera2D{} - worldSpaceCam.Zoom = 1 - - screenSpaceCam := rl.Camera2D{} - screenSpaceCam.Zoom = 1 - - target := rl.LoadRenderTexture(virtualScreenW, virtualScreenH) - - rec1 := rl.NewRectangle(120, 60, 80, 40) - rec2 := rl.NewRectangle(130, 70, 90, 30) - rec3 := rl.NewRectangle(140, 80, 65, 45) - - sourceRec := rl.NewRectangle(0, 0, float32(target.Texture.Width), -float32(target.Texture.Height)) - destRec := rl.NewRectangle(-virtualRatio, -virtualRatio, float32(screenW)+(virtualRatio*2), float32(screenH)+(virtualRatio*2)) - - origin := rl.NewVector2(0, 0) - - rotation, camX, camY := float32(0), float32(0), float32(0) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rotation += 60 * rl.GetFrameTime() - - camX = float32(math.Sin(rl.GetTime()) * 50) - camY = float32(math.Cos(rl.GetTime()) * 30) - - screenSpaceCam.Target = rl.NewVector2(camX, camY) - - worldSpaceCam.Target.X = screenSpaceCam.Target.X - screenSpaceCam.Target.X -= worldSpaceCam.Target.X - screenSpaceCam.Target.X *= virtualRatio - - worldSpaceCam.Target.Y = screenSpaceCam.Target.Y - screenSpaceCam.Target.Y -= worldSpaceCam.Target.Y - screenSpaceCam.Target.Y *= virtualRatio - - rl.BeginTextureMode(target) - rl.ClearBackground(rl.RayWhite) - rl.BeginMode2D(worldSpaceCam) - - rl.DrawRectanglePro(rec1, origin, rotation, rl.Black) - rl.DrawRectanglePro(rec2, origin, -rotation, rl.Red) - rl.DrawRectanglePro(rec3, origin, rotation+45, rl.Blue) - - rl.EndMode2D() - rl.EndTextureMode() - - rl.BeginDrawing() - rl.ClearBackground(rl.Red) - rl.BeginMode2D(screenSpaceCam) - rl.DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0, rl.White) - rl.EndMode2D() - - rl.DrawText("screen res "+fmt.Sprint(screenW)+"x"+fmt.Sprint(screenH), 10, 10, 20, rl.Black) - rl.DrawText("world res "+fmt.Sprint(virtualScreenW)+"x"+fmt.Sprint(virtualScreenH), 10, 30, 20, rl.Black) - rl.DrawFPS(screenW-100, 10) - - rl.EndDrawing() - } - - rl.UnloadRenderTexture(target) - - rl.CloseWindow() -} diff --git a/examples/core/storage_values/main.go b/examples/core/storage_values/main.go index c2f136e..4b5f19d 100644 --- a/examples/core/storage_values/main.go +++ b/examples/core/storage_values/main.go @@ -1,64 +1,45 @@ -/******************************************************************************************* -* -* raylib [core] example - Storage save/load values -* -* Example originally created with raylib 1.4, last time updated with raylib 4.2 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ package main import ( - "encoding/binary" "fmt" - "os" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( - screenWidth = 800 - screenHeight = 450 - storageDataFile = "storage.data" - // NOTE: Storage positions must start with 0, directly related to file memory layout - storagePositionScore = 0 - storagePositionHiscore = 1 + storageScore = 0 + storageHiscore = 1 ) func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - storage save/load values") + rl.InitWindow(800, 450, "raylib [core] example - storage save/load values") - var score int32 - var hiscore int32 - var framesCounter int32 + score := int32(0) + hiscore := int32(0) - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second + framesCounter := 0 - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { if rl.IsKeyPressed(rl.KeyR) { score = rl.GetRandomValue(1000, 2000) hiscore = rl.GetRandomValue(2000, 4000) } if rl.IsKeyPressed(rl.KeyEnter) { - _ = SaveStorageValue(storagePositionScore, score) - _ = SaveStorageValue(storagePositionHiscore, hiscore) + rl.SaveStorageValue(storageScore, score) + rl.SaveStorageValue(storageHiscore, hiscore) } else if rl.IsKeyPressed(rl.KeySpace) { // NOTE: If requested position could not be found, value 0 is returned - score, _ = LoadStorageValue(storagePositionScore) - hiscore, _ = LoadStorageValue(storagePositionHiscore) + score = rl.LoadStorageValue(storageScore) + hiscore = rl.LoadStorageValue(storageHiscore) } framesCounter++ - // Draw rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) rl.DrawText(fmt.Sprintf("SCORE: %d", score), 280, 130, 40, rl.Maroon) @@ -73,55 +54,5 @@ func main() { rl.EndDrawing() } - // De-Initialization - rl.CloseWindow() // Close window and OpenGL context -} - -// SaveStorageValue saves an integer value to storage file (to defined position) -// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer) -func SaveStorageValue(position uint32, value int32) error { - // Load the file data - fileData, err := os.ReadFile(storageDataFile) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to load file: %v", err) - } - - dataSize := len(fileData) - requiredSize := int((position + 1) * 4) // Each int32 is 4 bytes - newFileData := make([]byte, requiredSize) - - // Copy existing file data to newFileData - if dataSize > 0 { - copy(newFileData, fileData) - } - - // Update the value at the specified position - binary.LittleEndian.PutUint32(newFileData[position*4:], uint32(value)) - - // Save the updated data back to the file - err = os.WriteFile(storageDataFile, newFileData, 0644) - if err != nil { - return fmt.Errorf("failed to save file: %v", err) - } - - return nil -} - -// LoadStorageValue loads an integer value from storage file (from defined position) -// NOTE: If requested position could not be found, value 0 is returned -func LoadStorageValue(position uint32) (int32, error) { - // Load the file data - fileData, err := os.ReadFile(storageDataFile) - if err != nil { - return 0, fmt.Errorf("failed to load file: %v", err) - } - - dataSize := len(fileData) - if dataSize < int((position+1)*4) { - return 0, fmt.Errorf("position out of bounds") - } - - // Read the value at the specified position - value := int32(binary.LittleEndian.Uint32(fileData[position*4:])) - return value, nil + rl.CloseWindow() } diff --git a/examples/core/vr_simulator/distortion100.fs b/examples/core/vr_simulator/distortion100.fs deleted file mode 100644 index f72c689..0000000 --- a/examples/core/vr_simulator/distortion100.fs +++ /dev/null @@ -1,52 +0,0 @@ -#version 100 - -precision mediump float; - -// Input vertex attributes (from vertex shader) -varying vec2 fragTexCoord; -varying vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// NOTE: Add here your custom variables -uniform vec2 leftLensCenter; -uniform vec2 rightLensCenter; -uniform vec2 leftScreenCenter; -uniform vec2 rightScreenCenter; -uniform vec2 scale; -uniform vec2 scaleIn; -uniform vec4 deviceWarpParam; -uniform vec4 chromaAbParam; - -void main() -{ - // Compute lens distortion - vec2 lensCenter = fragTexCoord.x < 0.5? leftLensCenter : rightLensCenter; - vec2 screenCenter = fragTexCoord.x < 0.5? leftScreenCenter : rightScreenCenter; - vec2 theta = (fragTexCoord - lensCenter)*scaleIn; - float rSq = theta.x*theta.x + theta.y*theta.y; - vec2 theta1 = theta*(deviceWarpParam.x + deviceWarpParam.y*rSq + deviceWarpParam.z*rSq*rSq + deviceWarpParam.w*rSq*rSq*rSq); - vec2 thetaBlue = theta1*(chromaAbParam.z + chromaAbParam.w*rSq); - vec2 tcBlue = lensCenter + scale*thetaBlue; - - if (any(bvec2(clamp(tcBlue, screenCenter - vec2(0.25, 0.5), screenCenter + vec2(0.25, 0.5)) - tcBlue))) - { - // Set black fragment for everything outside the lens border - gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); - } - else - { - // Compute color chroma aberration - float blue = texture2D(texture0, tcBlue).b; - vec2 tcGreen = lensCenter + scale*theta1; - float green = texture2D(texture0, tcGreen).g; - - vec2 thetaRed = theta1*(chromaAbParam.x + chromaAbParam.y*rSq); - vec2 tcRed = lensCenter + scale*thetaRed; - - float red = texture2D(texture0, tcRed).r; - gl_FragColor = vec4(red, green, blue, 1.0); - } -} diff --git a/examples/core/vr_simulator/distortion330.fs b/examples/core/vr_simulator/distortion330.fs deleted file mode 100644 index 97044c4..0000000 --- a/examples/core/vr_simulator/distortion330.fs +++ /dev/null @@ -1,53 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -// NOTE: Add here your custom variables -uniform vec2 leftLensCenter = vec2(0.288, 0.5); -uniform vec2 rightLensCenter = vec2(0.712, 0.5); -uniform vec2 leftScreenCenter = vec2(0.25, 0.5); -uniform vec2 rightScreenCenter = vec2(0.75, 0.5); -uniform vec2 scale = vec2(0.25, 0.45); -uniform vec2 scaleIn = vec2(4, 2.2222); -uniform vec4 deviceWarpParam = vec4(1, 0.22, 0.24, 0); -uniform vec4 chromaAbParam = vec4(0.996, -0.004, 1.014, 0.0); - -void main() -{ - // Compute lens distortion - vec2 lensCenter = fragTexCoord.x < 0.5? leftLensCenter : rightLensCenter; - vec2 screenCenter = fragTexCoord.x < 0.5? leftScreenCenter : rightScreenCenter; - vec2 theta = (fragTexCoord - lensCenter)*scaleIn; - float rSq = theta.x*theta.x + theta.y*theta.y; - vec2 theta1 = theta*(deviceWarpParam.x + deviceWarpParam.y*rSq + deviceWarpParam.z*rSq*rSq + deviceWarpParam.w*rSq*rSq*rSq); - vec2 thetaBlue = theta1*(chromaAbParam.z + chromaAbParam.w*rSq); - vec2 tcBlue = lensCenter + scale*thetaBlue; - - if (any(bvec2(clamp(tcBlue, screenCenter - vec2(0.25, 0.5), screenCenter + vec2(0.25, 0.5)) - tcBlue))) - { - // Set black fragment for everything outside the lens border - finalColor = vec4(0.0, 0.0, 0.0, 1.0); - } - else - { - // Compute color chroma aberration - float blue = texture(texture0, tcBlue).b; - vec2 tcGreen = lensCenter + scale*theta1; - float green = texture(texture0, tcGreen).g; - - vec2 thetaRed = theta1*(chromaAbParam.x + chromaAbParam.y*rSq); - vec2 tcRed = lensCenter + scale*thetaRed; - - float red = texture(texture0, tcRed).r; - finalColor = vec4(red, green, blue, 1.0); - } -} diff --git a/examples/core/vr_simulator/main.go b/examples/core/vr_simulator/main.go deleted file mode 100644 index 3e1e7e1..0000000 --- a/examples/core/vr_simulator/main.go +++ /dev/null @@ -1,137 +0,0 @@ -/******************************************************************************************* -* -* raylib [core] example - VR Simulator (Oculus Rift CV1 parameters) -* -* Example originally created with raylib 2.5, last time updated with raylib 4.0 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2017-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 - glslVersion = 330 // Desktop - // glslVersion = 100 // Android, web -) - -func main() { - // NOTE: screenWidth/screenHeight should match VR device aspect ratio - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator") - - // VR device parameters definition - device := rl.VrDeviceInfo{ - // Oculus Rift CV1 parameters for simulator - HResolution: 2160, // Horizontal resolution in pixels - VResolution: 1200, // Vertical resolution in pixels - HScreenSize: 0.133793, // Horizontal size in meters - VScreenSize: 0.0669, // Vertical size in meters - EyeToScreenDistance: 0.041, // Distance between eye and display in meters - LensSeparationDistance: 0.07, // Lens separation distance in meters - InterpupillaryDistance: 0.07, // IPD (distance between pupils) in meters - - // NOTE: CV1 uses fresnel-hybrid-asymmetric lenses with specific compute shaders - // Following parameters are just an approximation to CV1 distortion stereo rendering - - // Lens distortion constant parameters - LensDistortionValues: [4]float32{1.0, 0.22, 0.24, 0.0}, - // Chromatic aberration correction parameters - ChromaAbCorrection: [4]float32{0.996, -0.004, 1.014, 0.0}, - } - - // Load VR stereo config for VR device parameters (Oculus Rift CV1 parameters) - config := rl.LoadVrStereoConfig(device) - - // Distortion shader (uses device lens distortion and chroma) - fileName := fmt.Sprintf("distortion%d.fs", glslVersion) - distortion := rl.LoadShader("", fileName) - - // Update distortion shader with lens and distortion-scale parameters - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "leftLensCenter"), - config.LeftLensCenter[:], rl.ShaderUniformVec2) - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "rightLensCenter"), - config.RightLensCenter[:], rl.ShaderUniformVec2) - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "leftScreenCenter"), - config.LeftScreenCenter[:], rl.ShaderUniformVec2) - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "rightScreenCenter"), - config.RightScreenCenter[:], rl.ShaderUniformVec2) - - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "scale"), - config.Scale[:], rl.ShaderUniformVec2) - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "scaleIn"), - config.ScaleIn[:], rl.ShaderUniformVec2) - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "deviceWarpParam"), - device.LensDistortionValues[:], rl.ShaderUniformVec4) - rl.SetShaderValue(distortion, rl.GetShaderLocation(distortion, "chromaAbParam"), - device.ChromaAbCorrection[:], rl.ShaderUniformVec4) - - // Initialize frame buffer for stereo rendering - // NOTE: Screen size should match HMD aspect ratio - target := rl.LoadRenderTexture(device.HResolution, device.VResolution) - - // The target's height is flipped (in the source Rectangle), due to OpenGL reasons - sourceRec := rl.Rectangle{Width: float32(target.Texture.Width), Height: float32(-target.Texture.Height)} - destRec := rl.Rectangle{Width: float32(rl.GetScreenWidth()), Height: float32(rl.GetScreenHeight())} - - // Define the camera to look into our 3d world - - camera := rl.Camera{ - Position: rl.Vector3{X: 5, Y: 2, Z: 5}, - Target: rl.Vector3{Y: 2}, - Up: rl.Vector3{Y: 1}, - Fovy: 60.0, - Projection: rl.CameraPerspective, - } - - cubePosition := rl.Vector3{} - - rl.DisableCursor() // Limit cursor to relative movement inside the window - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - rl.UpdateCamera(&camera, rl.CameraFirstPerson) - - // Draw texture - rl.BeginTextureMode(target) - rl.ClearBackground(rl.RayWhite) - rl.BeginVrStereoMode(config) - rl.BeginMode3D(camera) - - rl.DrawCube(cubePosition, 2.0, 2.0, 2.0, rl.Red) - rl.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, rl.Maroon) - rl.DrawGrid(40, 1.0) - - rl.EndMode3D() - rl.EndVrStereoMode() - rl.EndTextureMode() - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginShaderMode(distortion) - rl.DrawTexturePro(target.Texture, sourceRec, destRec, rl.Vector2{}, 0.0, rl.White) - rl.EndShaderMode() - rl.DrawFPS(10, 10) - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadVrStereoConfig(config) // Unload stereo config - - rl.UnloadRenderTexture(target) // Unload stereo render fbo - rl.UnloadShader(distortion) // Unload distortion shader - - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/core/window_flags/main.go b/examples/core/window_flags/main.go deleted file mode 100644 index 5fa82fa..0000000 --- a/examples/core/window_flags/main.go +++ /dev/null @@ -1,260 +0,0 @@ -/******************************************************************************************* -* -* raylib [core] example - window flags -* -* Example originally created with raylib 3.5, last time updated with raylib 3.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2020-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -// Possible window flags -/* - FLAG_VSYNC_HINT - FLAG_FULLSCREEN_MODE -> not working properly -> wrong scaling! - FLAG_WINDOW_RESIZABLE - FLAG_WINDOW_UNDECORATED - FLAG_WINDOW_TRANSPARENT - FLAG_WINDOW_HIDDEN - FLAG_WINDOW_MINIMIZED -> Not supported on window creation - FLAG_WINDOW_MAXIMIZED -> Not supported on window creation - FLAG_WINDOW_UNFOCUSED - FLAG_WINDOW_TOPMOST - FLAG_WINDOW_HIGHDPI -> errors after minimize-resize, fb size is recalculated - FLAG_WINDOW_ALWAYS_RUN - FLAG_MSAA_4X_HINT -*/ - -func main() { - // Set configuration flags for window creation - //SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI); - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - Window Flags") - - ballPosition := rl.Vector2{X: float32(rl.GetScreenWidth()) / 2.0, Y: float32(rl.GetScreenHeight()) / 2.0} - ballSpeed := rl.Vector2{X: 5.0, Y: 4.0} - ballRadius := float32(20.0) - framesCounter := 0 - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !rl.WindowShouldClose() { // Detect window close button or ESC key - if rl.IsKeyPressed(rl.KeyF) { - rl.ToggleFullscreen() // modifies window size when scaling! - } - - if rl.IsKeyPressed(rl.KeyR) { - if rl.IsWindowState(rl.FlagWindowResizable) { - rl.ClearWindowState(rl.FlagWindowResizable) - } else { - rl.SetWindowState(rl.FlagWindowResizable) - } - } - - if rl.IsKeyPressed(rl.KeyD) { - if rl.IsWindowState(rl.FlagWindowUndecorated) { - rl.ClearWindowState(rl.FlagWindowUndecorated) - } else { - rl.SetWindowState(rl.FlagWindowUndecorated) - } - } - - if rl.IsKeyPressed(rl.KeyH) { - if !rl.IsWindowState(rl.FlagWindowHidden) { - rl.SetWindowState(rl.FlagWindowHidden) - } - - framesCounter = 0 - } - - if rl.IsWindowState(rl.FlagWindowHidden) { - framesCounter++ - if framesCounter >= 240 { - rl.ClearWindowState(rl.FlagWindowHidden) // Show window after 3 seconds - } - } - - if rl.IsKeyPressed(rl.KeyN) { - if !rl.IsWindowState(rl.FlagWindowMinimized) { - rl.MinimizeWindow() - } - - framesCounter = 0 - } - - if rl.IsWindowState(rl.FlagWindowMinimized) { - framesCounter++ - if framesCounter >= 240 { - rl.RestoreWindow() // Restore window after 3 seconds - } - } - - if rl.IsKeyPressed(rl.KeyM) { - // NOTE: Requires FLAG_WINDOW_RESIZABLE enabled! - if rl.IsWindowState(rl.FlagWindowMaximized) { - rl.RestoreWindow() - } else { - rl.MaximizeWindow() - } - } - - if rl.IsKeyPressed(rl.KeyU) { - if rl.IsWindowState(rl.FlagWindowUnfocused) { - rl.ClearWindowState(rl.FlagWindowUnfocused) - } else { - rl.SetWindowState(rl.FlagWindowUnfocused) - } - } - - if rl.IsKeyPressed(rl.KeyT) { - if rl.IsWindowState(rl.FlagWindowTopmost) { - rl.ClearWindowState(rl.FlagWindowTopmost) - } else { - rl.SetWindowState(rl.FlagWindowTopmost) - } - } - - if rl.IsKeyPressed(rl.KeyA) { - if rl.IsWindowState(rl.FlagWindowAlwaysRun) { - rl.ClearWindowState(rl.FlagWindowAlwaysRun) - } else { - rl.SetWindowState(rl.FlagWindowAlwaysRun) - } - } - - if rl.IsKeyPressed(rl.KeyV) { - if rl.IsWindowState(rl.FlagVsyncHint) { - rl.ClearWindowState(rl.FlagVsyncHint) - } else { - rl.SetWindowState(rl.FlagVsyncHint) - } - } - - // Bouncing ball logic - ballPosition.X += ballSpeed.X - ballPosition.Y += ballSpeed.Y - if (ballPosition.X >= (float32(rl.GetScreenWidth()) - ballRadius)) || (ballPosition.X <= ballRadius) { - ballSpeed.X *= -1.0 - } - if (ballPosition.Y >= (float32(rl.GetScreenHeight()) - ballRadius)) || (ballPosition.Y <= ballRadius) { - ballSpeed.Y *= -1.0 - } - - rl.BeginDrawing() - if rl.IsWindowState(rl.FlagWindowTransparent) { - rl.ClearBackground(rl.Blank) - } else { - rl.ClearBackground(rl.White) - } - - rl.DrawCircleV(ballPosition, ballRadius, rl.Maroon) - rl.DrawRectangleLinesEx( - rl.Rectangle{ - Width: float32(rl.GetScreenWidth()), - Height: float32(rl.GetScreenHeight()), - }, - 4, rl.White, - ) - - rl.DrawCircleV(rl.GetMousePosition(), 10, rl.DarkBlue) - - rl.DrawFPS(10, 10) - - rl.DrawText( - fmt.Sprintf("Screen Size: [%d, %d]", rl.GetScreenWidth(), rl.GetScreenHeight()), - 10, - 40, - 10, - rl.Green, - ) - - // Draw window state info - rl.DrawText("Following flags can be set after window creation:", 10, 60, 10, rl.Gray) - if rl.IsWindowState(rl.FlagFullscreenMode) { - rl.DrawText("[F] FLAG_FULLSCREEN_MODE: on", 10, 80, 10, rl.Lime) - } else { - rl.DrawText("[F] FLAG_FULLSCREEN_MODE: off", 10, 80, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowResizable) { - rl.DrawText("[R] FLAG_WINDOW_RESIZABLE: on", 10, 100, 10, rl.Lime) - } else { - rl.DrawText("[R] FLAG_WINDOW_RESIZABLE: off", 10, 100, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowUndecorated) { - rl.DrawText("[D] FLAG_WINDOW_UNDECORATED: on", 10, 120, 10, rl.Lime) - } else { - rl.DrawText("[D] FLAG_WINDOW_UNDECORATED: off", 10, 120, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowHidden) { - rl.DrawText("[H] FLAG_WINDOW_HIDDEN: on", 10, 140, 10, rl.Lime) - } else { - rl.DrawText("[H] FLAG_WINDOW_HIDDEN: off", 10, 140, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowMinimized) { - rl.DrawText("[N] FLAG_WINDOW_MINIMIZED: on", 10, 160, 10, rl.Lime) - } else { - rl.DrawText("[N] FLAG_WINDOW_MINIMIZED: off", 10, 160, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowMaximized) { - rl.DrawText("[M] FLAG_WINDOW_MAXIMIZED: on", 10, 180, 10, rl.Lime) - } else { - rl.DrawText("[M] FLAG_WINDOW_MAXIMIZED: off", 10, 180, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowUnfocused) { - rl.DrawText("[G] FLAG_WINDOW_UNFOCUSED: on", 10, 200, 10, rl.Lime) - } else { - rl.DrawText("[U] FLAG_WINDOW_UNFOCUSED: off", 10, 200, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowTopmost) { - rl.DrawText("[T] FLAG_WINDOW_TOPMOST: on", 10, 220, 10, rl.Lime) - } else { - rl.DrawText("[T] FLAG_WINDOW_TOPMOST: off", 10, 220, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowAlwaysRun) { - rl.DrawText("[A] FLAG_WINDOW_ALWAYS_RUN: on", 10, 240, 10, rl.Lime) - } else { - rl.DrawText("[A] FLAG_WINDOW_ALWAYS_RUN: off", 10, 240, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagVsyncHint) { - rl.DrawText("[V] FLAG_VSYNC_HINT: on", 10, 260, 10, - rl.Lime) - } else { - rl.DrawText("[V] FLAG_VSYNC_HINT: off", 10, 260, 10, rl.Maroon) - } - - rl.DrawText("Following flags can only be set before window creation:", 10, 300, 10, rl.Gray) - if rl.IsWindowState(rl.FlagWindowHighdpi) { - rl.DrawText("FLAG_WINDOW_HIGHDPI: on", 10, 320, 10, rl.Lime) - } else { - rl.DrawText("FLAG_WINDOW_HIGHDPI: off", 10, 320, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagWindowTransparent) { - rl.DrawText("FLAG_WINDOW_TRANSPARENT: on", 10, 340, 10, rl.Lime) - } else { - rl.DrawText("FLAG_WINDOW_TRANSPARENT: off", 10, 340, 10, rl.Maroon) - } - if rl.IsWindowState(rl.FlagMsaa4xHint) { - rl.DrawText("FLAG_MSAA_4X_HINT: on", 10, 360, 10, rl.Lime) - } else { - rl.DrawText("FLAG_MSAA_4X_HINT: off", 10, 360, 10, rl.Maroon) - } - - rl.EndDrawing() - } - rl.CloseWindow() -} diff --git a/examples/core/window_letterbox/main.go b/examples/core/window_letterbox/main.go deleted file mode 100644 index b004d34..0000000 --- a/examples/core/window_letterbox/main.go +++ /dev/null @@ -1,115 +0,0 @@ -package main - -import ( - "fmt" - "image/color" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - // Enable config flags for resizable window and vertical synchro - rl.SetConfigFlags(rl.FlagWindowResizable | rl.FlagVsyncHint) - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - Window Scale Letterbox") - rl.SetWindowMinSize(320, 240) - - gameScreenWidth, gameScreenHeight := int32(640), int32(480) - - // Render texture initialization, used to hold the rendering result so we can easily resize it - target := rl.LoadRenderTexture(gameScreenWidth, gameScreenHeight) - rl.SetTextureFilter(target.Texture, rl.FilterBilinear) // Texture scale filter to use - - colors := getRandomColors() - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Compute required frame buffer scaling - scale := min(float32(rl.GetScreenWidth())/float32(gameScreenWidth), - float32(rl.GetScreenHeight())/float32(gameScreenHeight)) - - if rl.IsKeyPressed(rl.KeySpace) { - // Recalculate random colors for the bars - colors = getRandomColors() - } - - // Update virtual mouse (clamped mouse value behind game screen) - mouse := rl.GetMousePosition() - virtualMouse := rl.Vector2{ - X: (mouse.X - (float32(rl.GetScreenWidth())-(float32(gameScreenWidth)*scale))*0.5) / scale, - Y: (mouse.Y - (float32(rl.GetScreenHeight())-(float32(gameScreenHeight)*scale))*0.5) / scale, - } - virtualMouse = rl.Vector2Clamp( - virtualMouse, - rl.Vector2{}, - rl.Vector2{X: float32(gameScreenWidth), Y: float32(gameScreenHeight)}, - ) - - // Apply the same transformation as the virtual mouse to the real mouse (i.e. to work with raygui) - //rl.SetMouseOffset( - // int(-(float32(rl.GetScreenWidth())-(float32(gameScreenWidth)*scale))*0.5), - // int(-(float32(rl.GetScreenHeight())-(float32(gameScreenHeight)*scale))*0.5), - //) - //rl.SetMouseScale(1/scale, 1/scale) - - // Draw everything in the render texture, note this will not be rendered on screen, yet - rl.BeginTextureMode(target) - - rl.ClearBackground(rl.White) - for i := int32(0); i < 10; i++ { - rl.DrawRectangle(0, (gameScreenHeight/10)*i, gameScreenWidth, gameScreenHeight/10, colors[i]) - } - - text := "If executed inside a window,\nyou can resize the window,\nand see the screen scaling!" - rl.DrawText(text, 10, 25, 20, rl.White) - text = fmt.Sprintf("Default Mouse: [%.0f , %.0f]", mouse.X, mouse.Y) - rl.DrawText(text, 350, 25, 20, rl.Green) - text = fmt.Sprintf("Virtual Mouse: [%.0f , %.0f]", virtualMouse.X, virtualMouse.Y) - rl.DrawText(text, 350, 55, 20, rl.Yellow) - - rl.EndTextureMode() - - rl.BeginDrawing() - rl.ClearBackground(rl.Black) - // Draw render texture to screen, properly scaled - rl.DrawTexturePro( - target.Texture, - rl.Rectangle{Width: float32(target.Texture.Width), Height: float32(-target.Texture.Height)}, - rl.Rectangle{ - X: (float32(rl.GetScreenWidth()) - float32(gameScreenWidth)*scale) * 0.5, - Y: (float32(rl.GetScreenHeight()) - float32(gameScreenHeight)*scale) * 0.5, - Width: float32(gameScreenWidth) * scale, - Height: float32(gameScreenHeight) * scale, - }, - rl.Vector2{X: 0, Y: 0}, 0, rl.White, - ) - rl.EndDrawing() - } - rl.UnloadRenderTexture(target) - rl.CloseWindow() // Close window and OpenGL context -} - -func getRandomColors() []color.RGBA { - var colors []color.RGBA - - for i := 0; i < 10; i++ { - randomColor := color.RGBA{ - R: rndUint8(100, 250), - G: rndUint8(50, 150), - B: rndUint8(10, 100), - A: 255, - } - colors = append(colors, randomColor) - } - - return colors -} - -func rndUint8(min, max int32) uint8 { - return uint8(rl.GetRandomValue(min, max)) -} diff --git a/examples/core/window_should_close/main.go b/examples/core/window_should_close/main.go deleted file mode 100644 index 4858ed5..0000000 --- a/examples/core/window_should_close/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 850 - screenHeight = 480 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - window should close") - - rl.SetExitKey(rl.KeyNull) // Disable KEY_ESCAPE to close window, X-button still works - - exitWindowRequested := false // Flag to request window to exit - exitWindow := false // Flag to set window to exit - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !exitWindow { - if rl.WindowShouldClose() || rl.IsMouseButtonPressed(rl.KeyEscape) { - exitWindowRequested = true - } - - if exitWindowRequested { - if rl.IsKeyPressed(rl.KeyY) { - exitWindow = true - } else if rl.IsKeyPressed(rl.KeyN) { - exitWindowRequested = false - } - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - if exitWindowRequested { - rl.DrawRectangle(0, 100, screenWidth, 200, rl.Black) - rl.DrawText("Are you sure you want to exit the program? [Y/N]", 40, 180, 30, rl.White) - } else { - rl.DrawText("Try to close the window to get confirmation message!", 120, 200, 20, rl.LightGray) - } - - rl.EndDrawing() - } - - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/core/world_screen/main.go b/examples/core/world_screen/main.go index 53b4ba7..2b900d1 100644 --- a/examples/core/world_screen/main.go +++ b/examples/core/world_screen/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -14,15 +14,17 @@ func main() { camera.Position = rl.NewVector3(10.0, 10.0, 10.0) // Camera position camera.Target = rl.NewVector3(0.0, 0.0, 0.0) // Camera looking at point camera.Up = rl.NewVector3(0.0, 1.0, 0.0) // Camera up vector (rotation towards target) - camera.Fovy = 45.0 // Camera field-of-view Y + camera.Fovy = 45.0 // Camera field-of-view Y cubePosition := rl.NewVector3(0.0, 0.0, 0.0) cubeScreenPosition := rl.Vector2{} + rl.SetCameraMode(camera, rl.CameraFree) // Set a free camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode + rl.UpdateCamera(&camera) // Update camera // Calculate cube screen space position (with a little offset to be in top) cubeScreenPosition = rl.GetWorldToScreen(rl.NewVector3(cubePosition.X, cubePosition.Y+2.5, cubePosition.Z), camera) diff --git a/examples/easings/easings/easings.gif b/examples/easings/easings/easings.gif deleted file mode 100644 index 633bcf1..0000000 Binary files a/examples/easings/easings/easings.gif and /dev/null differ diff --git a/examples/easings/easings/main.go b/examples/easings/easings/main.go index c2371fb..d4ae033 100644 --- a/examples/easings/easings/main.go +++ b/examples/easings/easings/main.go @@ -1,11 +1,9 @@ package main import ( - "strings" - - "git.terah.dev/UnrealXR/raylib-go/easings" - "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/easings" + "github.com/gen2brain/raylib-go/raygui" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -23,8 +21,8 @@ func main() { ballPosition := rl.NewVector2(startPositionX, float32(screenHeight)/2) - comboActive := int32(0) - comboLastActive := int32(0) + comboActive := 0 + comboLastActive := 0 easingTypes := []string{"SineIn", "SineOut", "SineInOut", "BounceIn", "BounceOut", "BounceInOut", "BackIn", "BackOut", "BackInOut"} ease := easingTypes[comboActive] @@ -77,7 +75,7 @@ func main() { rl.ClearBackground(rl.RayWhite) raygui.Label(rl.NewRectangle(20, 20, 200, 20), "Easing Type:") - comboActive = raygui.ComboBox(rl.NewRectangle(20, 40, 200, 20), strings.Join(easingTypes, ";"), comboActive) + comboActive = raygui.ComboBox(rl.NewRectangle(20, 40, 200, 20), easingTypes, comboActive) raygui.Label(rl.NewRectangle(20, 80, 200, 20), "Press R to reset") diff --git a/examples/games/arkanoid/main.go b/examples/games/arkanoid/main.go index 0339aaa..14d5735 100644 --- a/examples/games/arkanoid/main.go +++ b/examples/games/arkanoid/main.go @@ -1,277 +1,277 @@ -package main - -/******************************************************************************************* -* -* raylib - sample game: arkanoid -* -* Sample game Marc Palau and Ramon Santamaria -* -* This game has been created using raylib v1.3 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* Copyright (c) 2015 Ramon Santamaria (@raysan5) -* -* Ported to raylib-go by Nehpe (@nehpe), July 2019 -* -********************************************************************************************/ - -import ( - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - PLAYER_MAX_LIFE = 5 - LINES_OF_BRICKS = 5 - BRICKS_PER_LINE = 20 -) - -type Player struct { - position rl.Vector2 - size rl.Vector2 - life int -} - -type Ball struct { - position rl.Vector2 - speed rl.Vector2 - radius float32 - active bool -} - -type Brick struct { - position rl.Vector2 - active bool -} - -const ( - screenWidth = 800 - screenHeight = 450 -) - -type Game struct { - gameOver bool - pause bool - player Player - ball Ball - brick [LINES_OF_BRICKS][BRICKS_PER_LINE]Brick - brickSize rl.Vector2 -} - -func main() { - rl.InitWindow(screenWidth, screenHeight, "sample game: arkanoid") - - // Init game - game := NewGame() - game.gameOver = true - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - game.Update() - - game.Draw() - - } - - rl.CloseWindow() - -} - -// For android -func init() { - rl.SetCallbackFunc(main) -} - -// NewGame - Create a new game instance -func NewGame() (g Game) { - g.Init() - return -} - -// Init - initialize game -func (g *Game) Init() { - g.brickSize = rl.Vector2{float32(rl.GetScreenWidth() / BRICKS_PER_LINE), 40} - - // Initialize player - g.player.position = rl.Vector2{float32(screenWidth / 2), float32(screenHeight * 7 / 8)} - g.player.size = rl.Vector2{float32(screenWidth / 10), 20} - g.player.life = PLAYER_MAX_LIFE - - // Initialize ball - g.ball.position = rl.Vector2{float32(screenWidth / 2), float32(screenHeight*7/8 - 30)} - g.ball.speed = rl.Vector2{0, 0} - g.ball.radius = 7 - g.ball.active = false - - initialDownPosition := int(50) - - for i := 0; i < LINES_OF_BRICKS; i++ { - for j := 0; j < BRICKS_PER_LINE; j++ { - g.brick[i][j].position = rl.Vector2{float32(j)*g.brickSize.X + g.brickSize.X/2, float32(i)*g.brickSize.Y + float32(initialDownPosition)} - g.brick[i][j].active = true - } - } -} - -// Update - update game state -func (g *Game) Update() { - if !g.gameOver { - - if rl.IsKeyPressed(rl.KeyP) { - g.pause = !g.pause - } - - if !g.pause { - - if rl.IsKeyDown(rl.KeyLeft) || rl.IsKeyDown(rl.KeyA) { - g.player.position.X -= 5 - } - if (g.player.position.X - g.player.size.X/2) <= 0 { - g.player.position.X = g.player.size.X / 2 - } - if rl.IsKeyDown(rl.KeyRight) || rl.IsKeyDown(rl.KeyD) { - g.player.position.X += 5 - } - if (g.player.position.X + g.player.size.X/2) >= screenWidth { - g.player.position.X = screenWidth - g.player.size.X/2 - } - - if !g.ball.active { - if rl.IsKeyPressed(rl.KeySpace) { - g.ball.active = true - g.ball.speed = rl.Vector2{0, -5} - } - } - - if g.ball.active { - g.ball.position.X += g.ball.speed.X - g.ball.position.Y += g.ball.speed.Y - } else { - g.ball.position = rl.Vector2{g.player.position.X, screenHeight*7/8 - 30} - } - - // Collision logic: ball vs walls - if ((g.ball.position.X + g.ball.radius) >= screenWidth) || ((g.ball.position.X - g.ball.radius) <= 0) { - g.ball.speed.X *= -1 - } - if (g.ball.position.Y - g.ball.radius) <= 0 { - g.ball.speed.Y *= -1 - } - if (g.ball.position.Y + g.ball.radius) >= screenHeight { - g.ball.speed = rl.Vector2{0, 0} - g.ball.active = false - - g.player.life-- - } - if (rl.CheckCollisionCircleRec(g.ball.position, g.ball.radius, - rl.Rectangle{g.player.position.X - g.player.size.X/2, g.player.position.Y - g.player.size.Y/2, g.player.size.X, g.player.size.Y})) { - if g.ball.speed.Y > 0 { - g.ball.speed.Y *= -1 - g.ball.speed.X = (g.ball.position.X - g.player.position.X) / (g.player.size.X / 2) * 5 - } - } - // Collision logic: ball vs bricks - for i := 0; i < LINES_OF_BRICKS; i++ { - for j := 0; j < BRICKS_PER_LINE; j++ { - if g.brick[i][j].active { - if ((g.ball.position.Y - g.ball.radius) <= (g.brick[i][j].position.Y + g.brickSize.Y/2)) && - ((g.ball.position.Y - g.ball.radius) > (g.brick[i][j].position.Y + g.brickSize.Y/2 + g.ball.speed.Y)) && - ((float32(math.Abs(float64(g.ball.position.X - g.brick[i][j].position.X)))) < (g.brickSize.X/2 + g.ball.radius*2/3)) && - (g.ball.speed.Y < 0) { - // Hit below - g.brick[i][j].active = false - g.ball.speed.Y *= -1 - } else if ((g.ball.position.Y + g.ball.radius) >= (g.brick[i][j].position.Y - g.brickSize.Y/2)) && - ((g.ball.position.Y + g.ball.radius) < (g.brick[i][j].position.Y - g.brickSize.Y/2 + g.ball.speed.Y)) && - ((float32(math.Abs(float64(g.ball.position.X - g.brick[i][j].position.X)))) < (g.brickSize.X/2 + g.ball.radius*2/3)) && - (g.ball.speed.Y > 0) { - // Hit above - g.brick[i][j].active = false - g.ball.speed.Y *= -1 - } else if ((g.ball.position.X + g.ball.radius) >= (g.brick[i][j].position.X - g.brickSize.X/2)) && - ((g.ball.position.X + g.ball.radius) < (g.brick[i][j].position.X - g.brickSize.X/2 + g.ball.speed.X)) && - ((float32(math.Abs(float64(g.ball.position.Y - g.brick[i][j].position.Y)))) < (g.brickSize.Y/2 + g.ball.radius*2/3)) && - (g.ball.speed.X > 0) { - // Hit left - g.brick[i][j].active = false - g.ball.speed.X *= -1 - } else if ((g.ball.position.X - g.ball.radius) <= (g.brick[i][j].position.X + g.brickSize.X/2)) && - ((g.ball.position.X - g.ball.radius) > (g.brick[i][j].position.X + g.brickSize.X/2 + g.ball.speed.X)) && - ((float32(math.Abs(float64(g.ball.position.Y - g.brick[i][j].position.Y)))) < (g.brickSize.Y/2 + g.ball.radius*2/3)) && - (g.ball.speed.X < 0) { - // Hit right - g.brick[i][j].active = false - g.ball.speed.X *= -1 - } - } - } - } - } - - // Game over logic - if g.player.life <= 0 { - g.gameOver = true - } else { - g.gameOver = true - - for i := 0; i < LINES_OF_BRICKS; i++ { - for j := 0; j < BRICKS_PER_LINE; j++ { - if g.brick[i][j].active { - g.gameOver = false - } - } - } - } - - } else { - if rl.IsKeyPressed(rl.KeyEnter) { - g.Init() - g.gameOver = false - } - } -} - -// Draw - draw game -func (g *Game) Draw() { - rl.BeginDrawing() - rl.ClearBackground(rl.White) - - if !g.gameOver { - // Draw player bar - rl.DrawRectangle(int32(g.player.position.X-g.player.size.X/2), int32(g.player.position.Y-g.player.size.Y/2), int32(g.player.size.X), int32(g.player.size.Y), rl.Black) - - // Draw player lives - for i := 0; i < g.player.life; i++ { - rl.DrawRectangle(int32(20+40*i), screenHeight-30, 35, 10, rl.LightGray) - } - - // Draw Ball - rl.DrawCircleV(g.ball.position, g.ball.radius, rl.Maroon) - - for i := 0; i < LINES_OF_BRICKS; i++ { - for j := 0; j < BRICKS_PER_LINE; j++ { - if g.brick[i][j].active { - if (i+j)%2 == 0 { - rl.DrawRectangle(int32(g.brick[i][j].position.X-g.brickSize.X/2), int32(g.brick[i][j].position.Y-g.brickSize.Y/2), int32(g.brickSize.X), int32(g.brickSize.Y), rl.Gray) - } else { - rl.DrawRectangle(int32(g.brick[i][j].position.X-g.brickSize.X/2), int32(g.brick[i][j].position.Y-g.brickSize.Y/2), int32(g.brickSize.X), int32(g.brickSize.Y), rl.DarkGray) - } - } - } - } - - if g.pause { - rl.DrawText("GAME PAUSED", screenWidth/2-rl.MeasureText("GAME PAUSED", 40)/2, screenHeight/2+screenHeight/4-40, 40, rl.Gray) - } - - } else { - str := "PRESS [ENTER] TO PLAY AGAIN" - x := int(rl.GetScreenWidth()/2) - int(rl.MeasureText(str, 20)/2) - y := rl.GetScreenHeight()/2 - 50 - rl.DrawText(str, int32(x), int32(y), 20, rl.Gray) - } - - rl.EndDrawing() -} +package main + +/******************************************************************************************* +* +* raylib - sample game: arkanoid +* +* Sample game Marc Palau and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +* Ported to raylib-go by Nehpe (@nehpe), July 2019 +* +********************************************************************************************/ + +import ( + "math" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +const ( + PLAYER_MAX_LIFE = 5 + LINES_OF_BRICKS = 5 + BRICKS_PER_LINE = 20 +) + +type Player struct { + position rl.Vector2 + size rl.Vector2 + life int +} + +type Ball struct { + position rl.Vector2 + speed rl.Vector2 + radius float32 + active bool +} + +type Brick struct { + position rl.Vector2 + active bool +} + +const ( + screenWidth = 800 + screenHeight = 450 +) + +type Game struct { + gameOver bool + pause bool + player Player + ball Ball + brick [LINES_OF_BRICKS][BRICKS_PER_LINE]Brick + brickSize rl.Vector2 +} + +func main() { + rl.InitWindow(screenWidth, screenHeight, "sample game: arkanoid") + + // Init game + game := NewGame() + game.gameOver = true + + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + game.Update() + + game.Draw() + + } + + rl.CloseWindow() + +} + +// For android +func init() { + rl.SetCallbackFunc(main) +} + +// NewGame - Create a new game instance +func NewGame() (g Game) { + g.Init() + return +} + +// Init - initialize game +func (g *Game) Init() { + g.brickSize = rl.Vector2{float32(rl.GetScreenWidth() / BRICKS_PER_LINE), 40} + + // Initialize player + g.player.position = rl.Vector2{float32(screenWidth / 2), float32(screenHeight * 7 / 8)} + g.player.size = rl.Vector2{float32(screenWidth / 10), 20} + g.player.life = PLAYER_MAX_LIFE + + // Initialize ball + g.ball.position = rl.Vector2{float32(screenWidth / 2), float32(screenHeight*7/8 - 30)} + g.ball.speed = rl.Vector2{0, 0} + g.ball.radius = 7 + g.ball.active = false + + initialDownPosition := int(50) + + for i := 0; i < LINES_OF_BRICKS; i++ { + for j := 0; j < BRICKS_PER_LINE; j++ { + g.brick[i][j].position = rl.Vector2{float32(j)*g.brickSize.X + g.brickSize.X/2, float32(i)*g.brickSize.Y + float32(initialDownPosition)} + g.brick[i][j].active = true + } + } +} + +// Update - update game state +func (g *Game) Update() { + if !g.gameOver { + + if rl.IsKeyPressed(rl.KeyP) { + g.pause = !g.pause + } + + if !g.pause { + + if rl.IsKeyDown(rl.KeyLeft) || rl.IsKeyDown(rl.KeyA) { + g.player.position.X -= 5 + } + if (g.player.position.X - g.player.size.X/2) <= 0 { + g.player.position.X = g.player.size.X / 2 + } + if rl.IsKeyDown(rl.KeyRight) || rl.IsKeyDown(rl.KeyD) { + g.player.position.X += 5 + } + if (g.player.position.X + g.player.size.X/2) >= screenWidth { + g.player.position.X = screenWidth - g.player.size.X/2 + } + + if !g.ball.active { + if rl.IsKeyPressed(rl.KeySpace) { + g.ball.active = true + g.ball.speed = rl.Vector2{0, -5} + } + } + + if g.ball.active { + g.ball.position.X += g.ball.speed.X + g.ball.position.Y += g.ball.speed.Y + } else { + g.ball.position = rl.Vector2{g.player.position.X, screenHeight*7/8 - 30} + } + + // Collision logic: ball vs walls + if ((g.ball.position.X + g.ball.radius) >= screenWidth) || ((g.ball.position.X - g.ball.radius) <= 0) { + g.ball.speed.X *= -1 + } + if (g.ball.position.Y - g.ball.radius) <= 0 { + g.ball.speed.Y *= -1 + } + if (g.ball.position.Y + g.ball.radius) >= screenHeight { + g.ball.speed = rl.Vector2{0, 0} + g.ball.active = false + + g.player.life-- + } + if (rl.CheckCollisionCircleRec(g.ball.position, g.ball.radius, + rl.Rectangle{g.player.position.X - g.player.size.X/2, g.player.position.Y - g.player.size.Y/2, g.player.size.X, g.player.size.Y})) { + if g.ball.speed.Y > 0 { + g.ball.speed.Y *= -1 + g.ball.speed.X = (g.ball.position.X - g.player.position.X) / (g.player.size.X / 2) * 5 + } + } + // Collision logic: ball vs bricks + for i := 0; i < LINES_OF_BRICKS; i++ { + for j := 0; j < BRICKS_PER_LINE; j++ { + if g.brick[i][j].active { + if ((g.ball.position.Y - g.ball.radius) <= (g.brick[i][j].position.Y + g.brickSize.Y/2)) && + ((g.ball.position.Y - g.ball.radius) > (g.brick[i][j].position.Y + g.brickSize.Y/2 + g.ball.speed.Y)) && + ((float32(math.Abs(float64(g.ball.position.X - g.brick[i][j].position.X)))) < (g.brickSize.X/2 + g.ball.radius*2/3)) && + (g.ball.speed.Y < 0) { + // Hit below + g.brick[i][j].active = false + g.ball.speed.Y *= -1 + } else if ((g.ball.position.Y + g.ball.radius) >= (g.brick[i][j].position.Y - g.brickSize.Y/2)) && + ((g.ball.position.Y + g.ball.radius) < (g.brick[i][j].position.Y - g.brickSize.Y/2 + g.ball.speed.Y)) && + ((float32(math.Abs(float64(g.ball.position.X - g.brick[i][j].position.X)))) < (g.brickSize.X/2 + g.ball.radius*2/3)) && + (g.ball.speed.Y > 0) { + // Hit above + g.brick[i][j].active = false + g.ball.speed.Y *= -1 + } else if ((g.ball.position.X + g.ball.radius) >= (g.brick[i][j].position.X - g.brickSize.X/2)) && + ((g.ball.position.X + g.ball.radius) < (g.brick[i][j].position.X - g.brickSize.X/2 + g.ball.speed.X)) && + ((float32(math.Abs(float64(g.ball.position.Y - g.brick[i][j].position.Y)))) < (g.brickSize.Y/2 + g.ball.radius*2/3)) && + (g.ball.speed.X > 0) { + // Hit left + g.brick[i][j].active = false + g.ball.speed.X *= -1 + } else if ((g.ball.position.X - g.ball.radius) <= (g.brick[i][j].position.X + g.brickSize.X/2)) && + ((g.ball.position.X - g.ball.radius) > (g.brick[i][j].position.X + g.brickSize.X/2 + g.ball.speed.X)) && + ((float32(math.Abs(float64(g.ball.position.Y - g.brick[i][j].position.Y)))) < (g.brickSize.Y/2 + g.ball.radius*2/3)) && + (g.ball.speed.X < 0) { + // Hit right + g.brick[i][j].active = false + g.ball.speed.X *= -1 + } + } + } + } + } + + // Game over logic + if g.player.life <= 0 { + g.gameOver = true + } else { + g.gameOver = true + + for i := 0; i < LINES_OF_BRICKS; i++ { + for j := 0; j < BRICKS_PER_LINE; j++ { + if g.brick[i][j].active { + g.gameOver = false + } + } + } + } + + } else { + if rl.IsKeyPressed(rl.KeyEnter) { + g.Init() + g.gameOver = false + } + } +} + +// Draw - draw game +func (g *Game) Draw() { + rl.BeginDrawing() + rl.ClearBackground(rl.White) + + if !g.gameOver { + // Draw player bar + rl.DrawRectangle(int32(g.player.position.X-g.player.size.X/2), int32(g.player.position.Y-g.player.size.Y/2), int32(g.player.size.X), int32(g.player.size.Y), rl.Black) + + // Draw player lives + for i := 0; i < g.player.life; i++ { + rl.DrawRectangle(int32(20+40*i), screenHeight-30, 35, 10, rl.LightGray) + } + + // Draw Ball + rl.DrawCircleV(g.ball.position, g.ball.radius, rl.Maroon) + + for i := 0; i < LINES_OF_BRICKS; i++ { + for j := 0; j < BRICKS_PER_LINE; j++ { + if g.brick[i][j].active { + if (i+j)%2 == 0 { + rl.DrawRectangle(int32(g.brick[i][j].position.X-g.brickSize.X/2), int32(g.brick[i][j].position.Y-g.brickSize.Y/2), int32(g.brickSize.X), int32(g.brickSize.Y), rl.Gray) + } else { + rl.DrawRectangle(int32(g.brick[i][j].position.X-g.brickSize.X/2), int32(g.brick[i][j].position.Y-g.brickSize.Y/2), int32(g.brickSize.X), int32(g.brickSize.Y), rl.DarkGray) + } + } + } + } + + if g.pause { + rl.DrawText("GAME PAUSED", screenWidth/2-rl.MeasureText("GAME PAUSED", 40)/2, screenHeight/2+screenHeight/4-40, 40, rl.Gray) + } + + } else { + str := "PRESS [ENTER] TO PLAY AGAIN" + x := int(rl.GetScreenWidth()/2) - int(rl.MeasureText(str, 20)/2) + y := rl.GetScreenHeight()/2 - 50 + rl.DrawText(str, int32(x), int32(y), 20, rl.Gray) + } + + rl.EndDrawing() +} diff --git a/examples/games/floppy/main.go b/examples/games/floppy/main.go index 35c61b1..6da73a4 100644 --- a/examples/games/floppy/main.go +++ b/examples/games/floppy/main.go @@ -4,6 +4,8 @@ import ( "fmt" "os" "runtime" + + "github.com/gen2brain/raylib-go/raylib" ) const ( diff --git a/examples/games/life/main.go b/examples/games/life/main.go index e4ed546..74cb410 100644 --- a/examples/games/life/main.go +++ b/examples/games/life/main.go @@ -4,7 +4,7 @@ import ( "math/rand" "time" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( @@ -32,7 +32,7 @@ type Game struct { } func main() { - rand.New(rand.NewSource(time.Now().UnixNano())) + rand.Seed(time.Now().UnixNano()) game := Game{} game.Init(false) diff --git a/examples/games/pong/main.go b/examples/games/pong/main.go deleted file mode 100644 index 0f1dd4f..0000000 --- a/examples/games/pong/main.go +++ /dev/null @@ -1,174 +0,0 @@ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -// Game settings -const ( - screenWidth = 800 - screenHeight = 600 -) - -// Paddle struct -type Paddle struct { - Pos rl.Vector2 - Width float32 - Height float32 - Speed float32 -} - -// Ball struct -type Ball struct { - Pos rl.Vector2 - Speed rl.Vector2 - Radius float32 -} - -// Game struct -type Game struct { - paddle1 Paddle - paddle2 Paddle - ball Ball - player1Score int - player2Score int -} - -// Check for collision between ball and paddle, and determine side -func CheckCollisionSide(ball Ball, paddle Paddle) string { - closestX := rl.Clamp(ball.Pos.X, paddle.Pos.X, paddle.Pos.X+paddle.Width) - closestY := rl.Clamp(ball.Pos.Y, paddle.Pos.Y, paddle.Pos.Y+paddle.Height) - - dx := ball.Pos.X - closestX - dy := ball.Pos.Y - closestY - - distanceSq := dx*dx + dy*dy - radiusSq := ball.Radius * ball.Radius - - if distanceSq <= radiusSq { - // Determine where it hit - if closestX == paddle.Pos.X || closestX == paddle.Pos.X+paddle.Width { - return "side" - } - if closestY == paddle.Pos.Y || closestY == paddle.Pos.Y+paddle.Height { - return "topbottom" - } - return "side" // fallback - } - - return "none" -} - -// Initialize the game state -func (g *Game) Init() { - g.paddle1 = Paddle{ - Pos: rl.NewVector2(30, float32(screenHeight/2-50)), - Width: 10, - Height: 100, - Speed: 5, - } - - g.paddle2 = Paddle{ - Pos: rl.NewVector2(float32(screenWidth-40), float32(screenHeight/2-50)), - Width: 10, - Height: 100, - Speed: 5, - } - - g.ball = Ball{ - Pos: rl.NewVector2(float32(screenWidth/2), float32(screenHeight/2)), - Speed: rl.NewVector2(5, 4), - Radius: 10, - } - - g.player1Score = 0 - g.player2Score = 0 -} - -// Game update logic -func (g *Game) Update() { - // Player 1 - W/S - if rl.IsKeyDown(rl.KeyW) && g.paddle1.Pos.Y > 0 { - g.paddle1.Pos.Y -= g.paddle1.Speed - } - if rl.IsKeyDown(rl.KeyS) && g.paddle1.Pos.Y < screenHeight-g.paddle1.Height { - g.paddle1.Pos.Y += g.paddle1.Speed - } - - // Player 2 - Up/Down - if rl.IsKeyDown(rl.KeyUp) && g.paddle2.Pos.Y > 0 { - g.paddle2.Pos.Y -= g.paddle2.Speed - } - if rl.IsKeyDown(rl.KeyDown) && g.paddle2.Pos.Y < screenHeight-g.paddle2.Height { - g.paddle2.Pos.Y += g.paddle2.Speed - } - - // Ball movement - g.ball.Pos.X += g.ball.Speed.X - g.ball.Pos.Y += g.ball.Speed.Y - - // Ball bounce off top/bottom walls - if g.ball.Pos.Y <= g.ball.Radius || g.ball.Pos.Y >= float32(screenHeight)-g.ball.Radius { - g.ball.Speed.Y *= -1 - } - - // Ball collisions with paddle sides only - if CheckCollisionSide(g.ball, g.paddle1) == "side" { - g.ball.Speed.X *= -1 - // Reposition ball outside paddle1 - g.ball.Pos.X = g.paddle1.Pos.X + g.paddle1.Width + g.ball.Radius - } - - if CheckCollisionSide(g.ball, g.paddle2) == "side" { - g.ball.Speed.X *= -1 - // Reposition ball outside paddle2 - g.ball.Pos.X = g.paddle2.Pos.X - g.ball.Radius - } - - // Scoring - if g.ball.Pos.X < 0 { - g.player2Score++ - g.ball.Pos = rl.NewVector2(float32(screenWidth/2), float32(screenHeight/2)) - g.ball.Speed.X *= -1 - } - if g.ball.Pos.X > float32(screenWidth) { - g.player1Score++ - g.ball.Pos = rl.NewVector2(float32(screenWidth/2), float32(screenHeight/2)) - g.ball.Speed.X *= -1 - } -} - -// Draw game elements -func (g *Game) Draw() { - // Draw paddles - rl.DrawRectangleV(g.paddle1.Pos, rl.NewVector2(g.paddle1.Width, g.paddle1.Height), rl.Black) - rl.DrawRectangleV(g.paddle2.Pos, rl.NewVector2(g.paddle2.Width, g.paddle2.Height), rl.Black) - - // Draw ball - rl.DrawCircleV(g.ball.Pos, g.ball.Radius, rl.Black) - - // Draw scores - rl.DrawText(fmt.Sprintf("Player 1 : %d", g.player1Score), 20, 20, 20, rl.DarkGray) - rl.DrawText(fmt.Sprintf("Player 2 : %d", g.player2Score), screenWidth-140, 20, 20, rl.DarkGray) -} - -func main() { - rl.InitWindow(screenWidth, screenHeight, "Pong in Go!") - rl.SetTargetFPS(60) - - var game Game - game.Init() - - for !rl.WindowShouldClose() { - game.Update() - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - game.Draw() - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/games/snake/main.go b/examples/games/snake/main.go index 86eaaae..9353ca9 100644 --- a/examples/games/snake/main.go +++ b/examples/games/snake/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + const ( snakeLength = 256 squareSize = 31 @@ -156,15 +160,15 @@ func (g *Game) Update() { if !g.Fruit.Active { g.Fruit.Active = true g.Fruit.Position = rl.NewVector2( - float32(rl.GetRandomValue(0, (g.ScreenWidth/squareSize)-1)*squareSize)+(g.Offset.X)/2, - float32(rl.GetRandomValue(0, (g.ScreenHeight/squareSize)-1)*squareSize)+(g.Offset.Y)/2, + float32(rl.GetRandomValue(0, (g.ScreenWidth/squareSize)-1)*squareSize+int32(g.Offset.X)/2), + float32(rl.GetRandomValue(0, (g.ScreenHeight/squareSize)-1)*squareSize+int32(g.Offset.Y)/2), ) for i := 0; i < g.CounterTail; i++ { for (g.Fruit.Position.X == g.Snake[i].Position.X) && (g.Fruit.Position.Y == g.Snake[i].Position.Y) { g.Fruit.Position = rl.NewVector2( - float32(rl.GetRandomValue(0, (g.ScreenWidth/squareSize)-1)*squareSize)+g.Offset.X/2, - float32(rl.GetRandomValue(0, (g.ScreenHeight/squareSize)-1)*squareSize)+g.Offset.Y/2, + float32(rl.GetRandomValue(0, (g.ScreenWidth/squareSize)-1)*squareSize), + float32(rl.GetRandomValue(0, (g.ScreenHeight/squareSize)-1)*squareSize), ) i = 0 } diff --git a/examples/go.mod b/examples/go.mod deleted file mode 100644 index 70eaebf..0000000 --- a/examples/go.mod +++ /dev/null @@ -1,26 +0,0 @@ -module examples - -go 1.21 - -replace git.terah.dev/UnrealXR/raylib-go/raylib => ../raylib - -replace git.terah.dev/UnrealXR/raylib-go/raygui => ../raygui - -replace git.terah.dev/UnrealXR/raylib-go/easings => ../easings - -replace git.terah.dev/UnrealXR/raylib-go/physics => ../physics - -require ( - git.terah.dev/UnrealXR/raylib-go/easings v0.0.0-00010101000000-000000000000 - git.terah.dev/UnrealXR/raylib-go/physics v0.0.0-00010101000000-000000000000 - git.terah.dev/UnrealXR/raylib-go/raygui v0.0.0-00010101000000-000000000000 - git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b - github.com/jakecoffman/cp v1.2.1 - github.com/neguse/go-box2d-lite v0.0.0-20170921151050-5d8ed9b7272b -) - -require ( - github.com/ebitengine/purego v0.8.1 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/sys v0.27.0 // indirect -) diff --git a/examples/go.sum b/examples/go.sum deleted file mode 100644 index 928bf43..0000000 --- a/examples/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= -github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/jakecoffman/cp v1.2.1 h1:zkhc2Gpo9l4NLUZfeG3j33+3bQD7MkqPa+n5PdX+5mI= -github.com/jakecoffman/cp v1.2.1/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg= -github.com/neguse/go-box2d-lite v0.0.0-20170921151050-5d8ed9b7272b h1:+67TGbwfgeB5o03Rx+ZBW44zAQ+wUujcwdRA0p9CbJI= -github.com/neguse/go-box2d-lite v0.0.0-20170921151050-5d8ed9b7272b/go.mod h1:kvKwD9codtns5mvpA53V3vLnqFb/Ahcu8zgkGM0SIbI= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/examples/gui/basic_controls/main.go b/examples/gui/basic_controls/main.go new file mode 100644 index 0000000..107e2e7 --- /dev/null +++ b/examples/gui/basic_controls/main.go @@ -0,0 +1,92 @@ +package main + +import ( + "fmt" + + "github.com/gen2brain/raylib-go/raygui" + "github.com/gen2brain/raylib-go/raylib" +) + +func main() { + screenWidth := int32(800) + screenHeight := int32(450) + + rl.SetConfigFlags(rl.FlagVsyncHint) + + rl.InitWindow(screenWidth, screenHeight, "raylib [gui] example - basic controls") + + buttonToggle := true + buttonClicked := false + checkboxChecked := false + + spinnerValue := 5 + sliderValue := float32(10) + sliderBarValue := float32(70) + progressValue := float32(0.5) + + comboActive := 0 + comboLastActive := 0 + toggleActive := 0 + + toggleText := []string{"Item 1", "Item 2", "Item 3"} + comboText := []string{"default_light", "default_dark", "hello_kitty", "monokai", "obsidian", "solarized_light", "solarized", "zahnrad"} + + var inputText string + + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + if buttonClicked { + progressValue += 0.1 + if progressValue >= 1.1 { + progressValue = 0.0 + } + } + + rl.BeginDrawing() + + rl.ClearBackground(rl.Beige) + + raygui.Label(rl.NewRectangle(50, 50, 80, 20), "Label") + + buttonClicked = raygui.Button(rl.NewRectangle(50, 70, 80, 40), "Button") + + raygui.Label(rl.NewRectangle(70, 140, 20, 20), "Checkbox") + checkboxChecked = raygui.CheckBox(rl.NewRectangle(50, 140, 20, 20), checkboxChecked) + + raygui.Label(rl.NewRectangle(50, 190, 200, 20), "ProgressBar") + raygui.ProgressBar(rl.NewRectangle(50, 210, 200, 20), progressValue) + raygui.Label(rl.NewRectangle(200+50+5, 210, 20, 20), fmt.Sprintf("%.1f", progressValue)) + + raygui.Label(rl.NewRectangle(50, 260, 200, 20), "Slider") + sliderValue = raygui.Slider(rl.NewRectangle(50, 280, 200, 20), sliderValue, 0, 100) + raygui.Label(rl.NewRectangle(200+50+5, 280, 20, 20), fmt.Sprintf("%.0f", sliderValue)) + + buttonToggle = raygui.ToggleButton(rl.NewRectangle(50, 350, 100, 40), "ToggleButton", buttonToggle) + + raygui.Label(rl.NewRectangle(500, 50, 200, 20), "ToggleGroup") + toggleActive = raygui.ToggleGroup(rl.NewRectangle(500, 70, 60, 30), toggleText, toggleActive) + + raygui.Label(rl.NewRectangle(500, 120, 200, 20), "SliderBar") + sliderBarValue = raygui.SliderBar(rl.NewRectangle(500, 140, 200, 20), sliderBarValue, 0, 100) + raygui.Label(rl.NewRectangle(500+200+5, 140, 20, 20), fmt.Sprintf("%.0f", sliderBarValue)) + + raygui.Label(rl.NewRectangle(500, 190, 200, 20), "Spinner") + spinnerValue = raygui.Spinner(rl.NewRectangle(500, 210, 200, 20), spinnerValue, 0, 100) + + raygui.Label(rl.NewRectangle(500, 260, 200, 20), "ComboBox") + comboActive = raygui.ComboBox(rl.NewRectangle(500, 280, 200, 20), comboText, comboActive) + + if comboLastActive != comboActive { + raygui.LoadGuiStyle(fmt.Sprintf("styles/%s.style", comboText[comboActive])) + comboLastActive = comboActive + } + + raygui.Label(rl.NewRectangle(500, 330, 200, 20), "TextBox") + inputText = raygui.TextBox(rl.NewRectangle(500, 350, 200, 20), inputText) + + rl.EndDrawing() + } + + rl.CloseWindow() +} diff --git a/examples/gui/basic_controls/styles/default_dark.style b/examples/gui/basic_controls/styles/default_dark.style new file mode 100644 index 0000000..4b903c8 --- /dev/null +++ b/examples/gui/basic_controls/styles/default_dark.style @@ -0,0 +1,99 @@ +GLOBAL_BASE_COLOR 0xf5f5f5ff +GLOBAL_BORDER_COLOR 0xf5f5f5ff +GLOBAL_TEXT_COLOR 0xf5f5f5ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0x293235ff +LINES_COLOR 0x90abb5ff +LABEL_BORDER_WIDTH 0x0 +LABEL_TEXT_COLOR 0x90acb4ff +LABEL_TEXT_PADDING 0x0 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x0 +BUTTON_DEFAULT_BORDER_COLOR 0x3e4a4fff +BUTTON_DEFAULT_INSIDE_COLOR 0x344041ff +BUTTON_DEFAULT_TEXT_COLOR 0x90acb4ff +BUTTON_HOVER_BORDER_COLOR 0x47595fff +BUTTON_HOVER_INSIDE_COLOR 0x334f59ff +BUTTON_HOVER_TEXT_COLOR 0x90acb4ff +BUTTON_PRESSED_BORDER_COLOR 0x5f9aa4ff +BUTTON_PRESSED_INSIDE_COLOR 0x334f59ff +BUTTON_PRESSED_TEXT_COLOR 0x5f9aa8ff +TOGGLE_TEXT_PADDING 0x20 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x3e4b4dff +TOGGLE_DEFAULT_INSIDE_COLOR 0x344041ff +TOGGLE_DEFAULT_TEXT_COLOR 0x828282ff +TOGGLE_HOVER_BORDER_COLOR 0x47595fff +TOGGLE_HOVER_INSIDE_COLOR 0x334f59ff +TOGGLE_HOVER_TEXT_COLOR 0x828282ff +TOGGLE_PRESSED_BORDER_COLOR 0x5f9aa8ff +TOGGLE_PRESSED_INSIDE_COLOR 0x334f59ff +TOGGLE_PRESSED_TEXT_COLOR 0x5f9aa8ff +TOGGLE_ACTIVE_BORDER_COLOR 0x92c763ff +TOGGLE_ACTIVE_INSIDE_COLOR 0x334f59ff +TOGGLE_ACTIVE_TEXT_COLOR 0x92c763ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x0 +SLIDER_BORDER_COLOR 0x828282ff +SLIDER_INSIDE_COLOR 0x3e4b4dff +SLIDER_DEFAULT_COLOR 0x92c763ff +SLIDER_HOVER_COLOR 0xc3e0a9ff +SLIDER_ACTIVE_COLOR 0xffffffff +SLIDERBAR_BORDER_COLOR 0x828282ff +SLIDERBAR_INSIDE_COLOR 0x344041ff +SLIDERBAR_DEFAULT_COLOR 0x92c763ff +SLIDERBAR_HOVER_COLOR 0xc3e0a9ff +SLIDERBAR_ACTIVE_COLOR 0xffffffff +SLIDERBAR_ZERO_LINE_COLOR 0x828282ff +PROGRESSBAR_BORDER_COLOR 0x828282ff +PROGRESSBAR_INSIDE_COLOR 0x3e4b4dff +PROGRESSBAR_PROGRESS_COLOR 0x92c763ff +PROGRESSBAR_BORDER_WIDTH 0x1 +SPINNER_LABEL_BORDER_COLOR 0x3e4b4dff +SPINNER_LABEL_INSIDE_COLOR 0x344041ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x3e4b4dff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0x344041ff +SPINNER_DEFAULT_SYMBOL_COLOR 0x5f9aa8ff +SPINNER_DEFAULT_TEXT_COLOR 0x5f9aa8ff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0x47595fff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0x334f59ff +SPINNER_HOVER_SYMBOL_COLOR 0x5f9aa8ff +SPINNER_HOVER_TEXT_COLOR 0x5f9aa8ff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x92c763ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0x334f59ff +SPINNER_PRESSED_SYMBOL_COLOR 0x92c763ff +SPINNER_PRESSED_TEXT_COLOR 0x92c763ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x30 +COMBOBOX_BUTTON_HEIGHT 0x20 +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x3e4b4dff +COMBOBOX_DEFAULT_INSIDE_COLOR 0x344041ff +COMBOBOX_DEFAULT_TEXT_COLOR 0x5f9aa8ff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0x5f9aa8ff +COMBOBOX_HOVER_BORDER_COLOR 0x47595fff +COMBOBOX_HOVER_INSIDE_COLOR 0x334f59ff +COMBOBOX_HOVER_TEXT_COLOR 0x5f9aa8ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0x5f9aa8ff +COMBOBOX_PRESSED_BORDER_COLOR 0x5f9aa8ff +COMBOBOX_PRESSED_INSIDE_COLOR 0x334f59ff +COMBOBOX_PRESSED_TEXT_COLOR 0x5f9aa8ff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x92c763ff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0x334f59ff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0x92c763ff +CHECKBOX_DEFAULT_BORDER_COLOR 0x47595fff +CHECKBOX_DEFAULT_INSIDE_COLOR 0x344041ff +CHECKBOX_HOVER_BORDER_COLOR 0x47595fff +CHECKBOX_HOVER_INSIDE_COLOR 0x334f59ff +CHECKBOX_CLICK_BORDER_COLOR 0x5f9aa8ff +CHECKBOX_CLICK_INSIDE_COLOR 0x334f59ff +CHECKBOX_STATUS_ACTIVE_COLOR 0x92c763ff +CHECKBOX_INSIDE_WIDTH 0x2 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x47595fff +TEXTBOX_INSIDE_COLOR 0x828282ff +TEXTBOX_TEXT_COLOR 0xff +TEXTBOX_LINE_COLOR 0xff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/default_light.style b/examples/gui/basic_controls/styles/default_light.style new file mode 100644 index 0000000..3a4786c --- /dev/null +++ b/examples/gui/basic_controls/styles/default_light.style @@ -0,0 +1,99 @@ +GLOBAL_BASE_COLOR 0xf5f5f5ff +GLOBAL_BORDER_COLOR 0xf5f5f5ff +GLOBAL_TEXT_COLOR 0xf5f5f5ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0xf5f5f5ff +LINES_COLOR 0x90abb5ff +LABEL_BORDER_WIDTH 0x1 +LABEL_TEXT_COLOR 0x4d4d4dff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x828282ff +BUTTON_DEFAULT_INSIDE_COLOR 0xc8c8c8ff +BUTTON_DEFAULT_TEXT_COLOR 0x4d4d4dff +BUTTON_HOVER_BORDER_COLOR 0xc8c8c8ff +BUTTON_HOVER_INSIDE_COLOR 0xffffffff +BUTTON_HOVER_TEXT_COLOR 0x868686ff +BUTTON_PRESSED_BORDER_COLOR 0x7bb0d6ff +BUTTON_PRESSED_INSIDE_COLOR 0xbcecffff +BUTTON_PRESSED_TEXT_COLOR 0x5f9aa7ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x828282ff +TOGGLE_DEFAULT_INSIDE_COLOR 0xc8c8c8ff +TOGGLE_DEFAULT_TEXT_COLOR 0x828282ff +TOGGLE_HOVER_BORDER_COLOR 0xc8c8c8ff +TOGGLE_HOVER_INSIDE_COLOR 0xffffffff +TOGGLE_HOVER_TEXT_COLOR 0x828282ff +TOGGLE_PRESSED_BORDER_COLOR 0xbdd7eaff +TOGGLE_PRESSED_INSIDE_COLOR 0xddf5ffff +TOGGLE_PRESSED_TEXT_COLOR 0xafccd3ff +TOGGLE_ACTIVE_BORDER_COLOR 0x7bb0d6ff +TOGGLE_ACTIVE_INSIDE_COLOR 0xbcecffff +TOGGLE_ACTIVE_TEXT_COLOR 0x5f9aa7ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x1 +SLIDER_BORDER_COLOR 0x828282ff +SLIDER_INSIDE_COLOR 0xc8c8c8ff +SLIDER_DEFAULT_COLOR 0xbcecffff +SLIDER_HOVER_COLOR 0xffffffff +SLIDER_ACTIVE_COLOR 0xddf5ffff +SLIDERBAR_BORDER_COLOR 0x828282ff +SLIDERBAR_INSIDE_COLOR 0xc8c8c8ff +SLIDERBAR_DEFAULT_COLOR 0xbcecffff +SLIDERBAR_HOVER_COLOR 0xffffffff +SLIDERBAR_ACTIVE_COLOR 0xddf5ffff +SLIDERBAR_ZERO_LINE_COLOR 0x828282ff +PROGRESSBAR_BORDER_COLOR 0x828282ff +PROGRESSBAR_INSIDE_COLOR 0xc8c8c8ff +PROGRESSBAR_PROGRESS_COLOR 0xbcecffff +PROGRESSBAR_BORDER_WIDTH 0x2 +SPINNER_LABEL_BORDER_COLOR 0x828282ff +SPINNER_LABEL_INSIDE_COLOR 0xc8c8c8ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x828282ff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0xc8c8c8ff +SPINNER_DEFAULT_SYMBOL_COLOR 0xff +SPINNER_DEFAULT_TEXT_COLOR 0xff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0xc8c8c8ff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0xffffffff +SPINNER_HOVER_SYMBOL_COLOR 0xff +SPINNER_HOVER_TEXT_COLOR 0xff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x7bb0d6ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0xbcecffff +SPINNER_PRESSED_SYMBOL_COLOR 0x5f9aa7ff +SPINNER_PRESSED_TEXT_COLOR 0xff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x14 +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x828282ff +COMBOBOX_DEFAULT_INSIDE_COLOR 0xc8c8c8ff +COMBOBOX_DEFAULT_TEXT_COLOR 0x828282ff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0x828282ff +COMBOBOX_HOVER_BORDER_COLOR 0xc8c8c8ff +COMBOBOX_HOVER_INSIDE_COLOR 0xffffffff +COMBOBOX_HOVER_TEXT_COLOR 0x828282ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0x828282ff +COMBOBOX_PRESSED_BORDER_COLOR 0x7bb0d6ff +COMBOBOX_PRESSED_INSIDE_COLOR 0xbcecffff +COMBOBOX_PRESSED_TEXT_COLOR 0x5f9aa7ff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x78acff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0x66e7ffff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0x78acff +CHECKBOX_DEFAULT_BORDER_COLOR 0x828282ff +CHECKBOX_DEFAULT_INSIDE_COLOR 0xffffffff +CHECKBOX_HOVER_BORDER_COLOR 0xc8c8c8ff +CHECKBOX_HOVER_INSIDE_COLOR 0xffffffff +CHECKBOX_CLICK_BORDER_COLOR 0x66e7ffff +CHECKBOX_CLICK_INSIDE_COLOR 0xddf5ffff +CHECKBOX_STATUS_ACTIVE_COLOR 0xbcecffff +CHECKBOX_INSIDE_WIDTH 0x1 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x828282ff +TEXTBOX_INSIDE_COLOR 0xf5f5f5ff +TEXTBOX_TEXT_COLOR 0xff +TEXTBOX_LINE_COLOR 0xff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/hello_kitty.style b/examples/gui/basic_controls/styles/hello_kitty.style new file mode 100644 index 0000000..bba8e32 --- /dev/null +++ b/examples/gui/basic_controls/styles/hello_kitty.style @@ -0,0 +1,98 @@ +GLOBAL_BASE_COLOR 0xff80c1ff +GLOBAL_BORDER_COLOR 0xf5f5f5ff +GLOBAL_TEXT_COLOR 0x650065ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0xffd4eaff +LABEL_BORDER_WIDTH 0x1 +LABEL_TEXT_COLOR 0x650065ff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x828282ff +BUTTON_DEFAULT_INSIDE_COLOR 0xffc6e3ff +BUTTON_DEFAULT_TEXT_COLOR 0x650065ff +BUTTON_HOVER_BORDER_COLOR 0xc8c8c8ff +BUTTON_HOVER_INSIDE_COLOR 0xffc6e3ff +BUTTON_HOVER_TEXT_COLOR 0x761c76ff +BUTTON_PRESSED_BORDER_COLOR 0x7bb0d6ff +BUTTON_PRESSED_INSIDE_COLOR 0xffb8dcff +BUTTON_PRESSED_TEXT_COLOR 0xa971a9ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x828282ff +TOGGLE_DEFAULT_INSIDE_COLOR 0xffc6e3ff +TOGGLE_DEFAULT_TEXT_COLOR 0x650065ff +TOGGLE_HOVER_BORDER_COLOR 0xc8c8c8ff +TOGGLE_HOVER_INSIDE_COLOR 0xffc6e3ff +TOGGLE_HOVER_TEXT_COLOR 0x761c76ff +TOGGLE_PRESSED_BORDER_COLOR 0xbdd7eaff +TOGGLE_PRESSED_INSIDE_COLOR 0xffb8dcff +TOGGLE_PRESSED_TEXT_COLOR 0xa971a9ff +TOGGLE_ACTIVE_BORDER_COLOR 0x7bb0d6ff +TOGGLE_ACTIVE_INSIDE_COLOR 0xff8ec7ff +TOGGLE_ACTIVE_TEXT_COLOR 0xa971a9ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x1 +SLIDER_BORDER_COLOR 0x828282ff +SLIDER_INSIDE_COLOR 0xffc6e3ff +SLIDER_DEFAULT_COLOR 0xffaad5ff +SLIDER_HOVER_COLOR 0xff9cceff +SLIDER_ACTIVE_COLOR 0xff80c1ff +SLIDERBAR_BORDER_COLOR 0x828282ff +SLIDERBAR_INSIDE_COLOR 0xffc6e3ff +SLIDERBAR_DEFAULT_COLOR 0xffaad5ff +SLIDERBAR_HOVER_COLOR 0xff9cceff +SLIDERBAR_ACTIVE_COLOR 0xff80c1ff +SLIDERBAR_ZERO_LINE_COLOR 0xff8ec7ff +PROGRESSBAR_BORDER_COLOR 0x828282ff +PROGRESSBAR_INSIDE_COLOR 0xffc6e3ff +PROGRESSBAR_PROGRESS_COLOR 0xffaad5ff +PROGRESSBAR_BORDER_WIDTH 0x2 +SPINNER_LABEL_BORDER_COLOR 0x828282ff +SPINNER_LABEL_INSIDE_COLOR 0xffc6e3ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x828282ff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0xffc6e3ff +SPINNER_DEFAULT_SYMBOL_COLOR 0x650065ff +SPINNER_DEFAULT_TEXT_COLOR 0x650065ff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0xc8c8c8ff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0xffc6e3ff +SPINNER_HOVER_SYMBOL_COLOR 0x761c76ff +SPINNER_HOVER_TEXT_COLOR 0x761c76ff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x7bb0d6ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0xffb8dcff +SPINNER_PRESSED_SYMBOL_COLOR 0xa971a9ff +SPINNER_PRESSED_TEXT_COLOR 0xa971a9ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x1e +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x828282ff +COMBOBOX_DEFAULT_INSIDE_COLOR 0xffc6e3ff +COMBOBOX_DEFAULT_TEXT_COLOR 0x650065ff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0x650065ff +COMBOBOX_HOVER_BORDER_COLOR 0xc8c8c8ff +COMBOBOX_HOVER_INSIDE_COLOR 0xffc6e3ff +COMBOBOX_HOVER_TEXT_COLOR 0x761c76ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0x761c76ff +COMBOBOX_PRESSED_BORDER_COLOR 0x7bb0d6ff +COMBOBOX_PRESSED_INSIDE_COLOR 0xff8ec7ff +COMBOBOX_PRESSED_TEXT_COLOR 0xba8dbaff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x78acff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0xff8ec7ff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0xba8dbaff +CHECKBOX_DEFAULT_BORDER_COLOR 0x828282ff +CHECKBOX_DEFAULT_INSIDE_COLOR 0xffc6e3ff +CHECKBOX_HOVER_BORDER_COLOR 0xc8c8c8ff +CHECKBOX_HOVER_INSIDE_COLOR 0xffffffff +CHECKBOX_CLICK_BORDER_COLOR 0x66e7ffff +CHECKBOX_CLICK_INSIDE_COLOR 0xffaad5ff +CHECKBOX_STATUS_ACTIVE_COLOR 0xff8ec7ff +CHECKBOX_INSIDE_WIDTH 0x4 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x828282ff +TEXTBOX_INSIDE_COLOR 0xffc6e3ff +TEXTBOX_TEXT_COLOR 0x650065ff +TEXTBOX_LINE_COLOR 0x985598ff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/monokai.style b/examples/gui/basic_controls/styles/monokai.style new file mode 100644 index 0000000..0248d6e --- /dev/null +++ b/examples/gui/basic_controls/styles/monokai.style @@ -0,0 +1,98 @@ +GLOBAL_BASE_COLOR 0x262921ff +GLOBAL_BORDER_COLOR 0x102ff +GLOBAL_TEXT_COLOR 0xf8f8f1ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0xb6b7b5ff +LABEL_BORDER_WIDTH 0x1 +LABEL_TEXT_COLOR 0xf8f8f1ff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x38393aff +BUTTON_DEFAULT_INSIDE_COLOR 0x9e9f9cff +BUTTON_DEFAULT_TEXT_COLOR 0xf8f8f1ff +BUTTON_HOVER_BORDER_COLOR 0x1c1d1eff +BUTTON_HOVER_INSIDE_COLOR 0x9e9f9cff +BUTTON_HOVER_TEXT_COLOR 0xf8f8f2ff +BUTTON_PRESSED_BORDER_COLOR 0x102ff +BUTTON_PRESSED_INSIDE_COLOR 0x868883ff +BUTTON_PRESSED_TEXT_COLOR 0xfbfbf7ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x38393aff +TOGGLE_DEFAULT_INSIDE_COLOR 0x9e9f9cff +TOGGLE_DEFAULT_TEXT_COLOR 0xf8f8f1ff +TOGGLE_HOVER_BORDER_COLOR 0x1c1d1eff +TOGGLE_HOVER_INSIDE_COLOR 0x9e9f9cff +TOGGLE_HOVER_TEXT_COLOR 0xf8f8f2ff +TOGGLE_PRESSED_BORDER_COLOR 0x102ff +TOGGLE_PRESSED_INSIDE_COLOR 0x868883ff +TOGGLE_PRESSED_TEXT_COLOR 0xfbfbf7ff +TOGGLE_ACTIVE_BORDER_COLOR 0x102ff +TOGGLE_ACTIVE_INSIDE_COLOR 0x3e4039ff +TOGGLE_ACTIVE_TEXT_COLOR 0xfbfbf7ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x1 +SLIDER_BORDER_COLOR 0x38393aff +SLIDER_INSIDE_COLOR 0x9e9f9cff +SLIDER_DEFAULT_COLOR 0x6e706bff +SLIDER_HOVER_COLOR 0x565852ff +SLIDER_ACTIVE_COLOR 0x262921ff +SLIDERBAR_BORDER_COLOR 0x38393aff +SLIDERBAR_INSIDE_COLOR 0x9e9f9cff +SLIDERBAR_DEFAULT_COLOR 0x6e706bff +SLIDERBAR_HOVER_COLOR 0x565852ff +SLIDERBAR_ACTIVE_COLOR 0x262921ff +SLIDERBAR_ZERO_LINE_COLOR 0x3e4039ff +PROGRESSBAR_BORDER_COLOR 0x38393aff +PROGRESSBAR_INSIDE_COLOR 0x9e9f9cff +PROGRESSBAR_PROGRESS_COLOR 0x6e706bff +PROGRESSBAR_BORDER_WIDTH 0x2 +SPINNER_LABEL_BORDER_COLOR 0x38393aff +SPINNER_LABEL_INSIDE_COLOR 0x9e9f9cff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x38393aff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0x9e9f9cff +SPINNER_DEFAULT_SYMBOL_COLOR 0xf8f8f1ff +SPINNER_DEFAULT_TEXT_COLOR 0xf8f8f1ff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0x1c1d1eff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0x9e9f9cff +SPINNER_HOVER_SYMBOL_COLOR 0xf8f8f2ff +SPINNER_HOVER_TEXT_COLOR 0xf8f8f2ff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x102ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0x868883ff +SPINNER_PRESSED_SYMBOL_COLOR 0xfbfbf7ff +SPINNER_PRESSED_TEXT_COLOR 0xfbfbf7ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x1e +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x38393aff +COMBOBOX_DEFAULT_INSIDE_COLOR 0x9e9f9cff +COMBOBOX_DEFAULT_TEXT_COLOR 0xf8f8f1ff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0xf8f8f1ff +COMBOBOX_HOVER_BORDER_COLOR 0x1c1d1eff +COMBOBOX_HOVER_INSIDE_COLOR 0x9e9f9cff +COMBOBOX_HOVER_TEXT_COLOR 0xf8f8f2ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0xf8f8f2ff +COMBOBOX_PRESSED_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_INSIDE_COLOR 0x3e4039ff +COMBOBOX_PRESSED_TEXT_COLOR 0xfbfbf8ff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0x3e4039ff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0xfbfbf8ff +CHECKBOX_DEFAULT_BORDER_COLOR 0x38393aff +CHECKBOX_DEFAULT_INSIDE_COLOR 0x9e9f9cff +CHECKBOX_HOVER_BORDER_COLOR 0x1c1d1eff +CHECKBOX_HOVER_INSIDE_COLOR 0xffffffff +CHECKBOX_CLICK_BORDER_COLOR 0x102ff +CHECKBOX_CLICK_INSIDE_COLOR 0x6e706bff +CHECKBOX_STATUS_ACTIVE_COLOR 0x3e4039ff +CHECKBOX_INSIDE_WIDTH 0x4 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x38393aff +TEXTBOX_INSIDE_COLOR 0x9e9f9cff +TEXTBOX_TEXT_COLOR 0xf8f8f1ff +TEXTBOX_LINE_COLOR 0xfafaf5ff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/obsidian.style b/examples/gui/basic_controls/styles/obsidian.style new file mode 100644 index 0000000..79d4053 --- /dev/null +++ b/examples/gui/basic_controls/styles/obsidian.style @@ -0,0 +1,98 @@ +GLOBAL_BASE_COLOR 0x293034ff +GLOBAL_BORDER_COLOR 0x102ff +GLOBAL_TEXT_COLOR 0xa8e2aeff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0xb7babbff +LABEL_BORDER_WIDTH 0x1 +LABEL_TEXT_COLOR 0xa8e2aeff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x38393aff +BUTTON_DEFAULT_INSIDE_COLOR 0x9fa3a4ff +BUTTON_DEFAULT_TEXT_COLOR 0xa8e2aeff +BUTTON_HOVER_BORDER_COLOR 0x1c1d1eff +BUTTON_HOVER_INSIDE_COLOR 0x9fa3a4ff +BUTTON_HOVER_TEXT_COLOR 0xb1e5b7ff +BUTTON_PRESSED_BORDER_COLOR 0x102ff +BUTTON_PRESSED_INSIDE_COLOR 0x888c8eff +BUTTON_PRESSED_TEXT_COLOR 0xceeed2ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x38393aff +TOGGLE_DEFAULT_INSIDE_COLOR 0x9fa3a4ff +TOGGLE_DEFAULT_TEXT_COLOR 0xa8e2aeff +TOGGLE_HOVER_BORDER_COLOR 0x1c1d1eff +TOGGLE_HOVER_INSIDE_COLOR 0x9fa3a4ff +TOGGLE_HOVER_TEXT_COLOR 0xb1e5b7ff +TOGGLE_PRESSED_BORDER_COLOR 0x102ff +TOGGLE_PRESSED_INSIDE_COLOR 0x888c8eff +TOGGLE_PRESSED_TEXT_COLOR 0xceeed2ff +TOGGLE_ACTIVE_BORDER_COLOR 0x102ff +TOGGLE_ACTIVE_INSIDE_COLOR 0x40474aff +TOGGLE_ACTIVE_TEXT_COLOR 0xceeed2ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x1 +SLIDER_BORDER_COLOR 0x38393aff +SLIDER_INSIDE_COLOR 0x9fa3a4ff +SLIDER_DEFAULT_COLOR 0x707577ff +SLIDER_HOVER_COLOR 0x585e61ff +SLIDER_ACTIVE_COLOR 0x293034ff +SLIDERBAR_BORDER_COLOR 0x38393aff +SLIDERBAR_INSIDE_COLOR 0x9fa3a4ff +SLIDERBAR_DEFAULT_COLOR 0x707577ff +SLIDERBAR_HOVER_COLOR 0x585e61ff +SLIDERBAR_ACTIVE_COLOR 0x293034ff +SLIDERBAR_ZERO_LINE_COLOR 0x40474aff +PROGRESSBAR_BORDER_COLOR 0x38393aff +PROGRESSBAR_INSIDE_COLOR 0x9fa3a4ff +PROGRESSBAR_PROGRESS_COLOR 0x707577ff +PROGRESSBAR_BORDER_WIDTH 0x2 +SPINNER_LABEL_BORDER_COLOR 0x38393aff +SPINNER_LABEL_INSIDE_COLOR 0x9fa3a4ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x38393aff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0x9fa3a4ff +SPINNER_DEFAULT_SYMBOL_COLOR 0xa8e2aeff +SPINNER_DEFAULT_TEXT_COLOR 0xa8e2aeff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0x1c1d1eff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0x9fa3a4ff +SPINNER_HOVER_SYMBOL_COLOR 0xb1e5b7ff +SPINNER_HOVER_TEXT_COLOR 0xb1e5b7ff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x102ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0x888c8eff +SPINNER_PRESSED_SYMBOL_COLOR 0xceeed2ff +SPINNER_PRESSED_TEXT_COLOR 0xceeed2ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x1e +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x38393aff +COMBOBOX_DEFAULT_INSIDE_COLOR 0x9fa3a4ff +COMBOBOX_DEFAULT_TEXT_COLOR 0xa8e2aeff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0xa8e2aeff +COMBOBOX_HOVER_BORDER_COLOR 0x1c1d1eff +COMBOBOX_HOVER_INSIDE_COLOR 0x9fa3a4ff +COMBOBOX_HOVER_TEXT_COLOR 0xb1e5b7ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0xb1e5b7ff +COMBOBOX_PRESSED_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_INSIDE_COLOR 0x40474aff +COMBOBOX_PRESSED_TEXT_COLOR 0xd8f2dbff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0x40474aff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0xd8f2dbff +CHECKBOX_DEFAULT_BORDER_COLOR 0x38393aff +CHECKBOX_DEFAULT_INSIDE_COLOR 0x9fa3a4ff +CHECKBOX_HOVER_BORDER_COLOR 0x1c1d1eff +CHECKBOX_HOVER_INSIDE_COLOR 0xffffffff +CHECKBOX_CLICK_BORDER_COLOR 0x102ff +CHECKBOX_CLICK_INSIDE_COLOR 0x707577ff +CHECKBOX_STATUS_ACTIVE_COLOR 0x40474aff +CHECKBOX_INSIDE_WIDTH 0x4 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x38393aff +TEXTBOX_INSIDE_COLOR 0x9fa3a4ff +TEXTBOX_TEXT_COLOR 0xa8e2aeff +TEXTBOX_LINE_COLOR 0xc5ebc9ff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/solarized.style b/examples/gui/basic_controls/styles/solarized.style new file mode 100644 index 0000000..24605c1 --- /dev/null +++ b/examples/gui/basic_controls/styles/solarized.style @@ -0,0 +1,98 @@ +GLOBAL_BASE_COLOR 0x2b36ff +GLOBAL_BORDER_COLOR 0x102ff +GLOBAL_TEXT_COLOR 0xf8f8f1ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0xaab8bcff +LABEL_BORDER_WIDTH 0x1 +LABEL_TEXT_COLOR 0xf8f8f1ff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x38393aff +BUTTON_DEFAULT_INSIDE_COLOR 0x8da0a5ff +BUTTON_DEFAULT_TEXT_COLOR 0xf8f8f1ff +BUTTON_HOVER_BORDER_COLOR 0x1c1d1eff +BUTTON_HOVER_INSIDE_COLOR 0x8da0a5ff +BUTTON_HOVER_TEXT_COLOR 0xf8f8f2ff +BUTTON_PRESSED_BORDER_COLOR 0x102ff +BUTTON_PRESSED_INSIDE_COLOR 0x71898fff +BUTTON_PRESSED_TEXT_COLOR 0xfbfbf7ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x38393aff +TOGGLE_DEFAULT_INSIDE_COLOR 0x8da0a5ff +TOGGLE_DEFAULT_TEXT_COLOR 0xf8f8f1ff +TOGGLE_HOVER_BORDER_COLOR 0x1c1d1eff +TOGGLE_HOVER_INSIDE_COLOR 0x8da0a5ff +TOGGLE_HOVER_TEXT_COLOR 0xf8f8f2ff +TOGGLE_PRESSED_BORDER_COLOR 0x102ff +TOGGLE_PRESSED_INSIDE_COLOR 0x71898fff +TOGGLE_PRESSED_TEXT_COLOR 0xfbfbf7ff +TOGGLE_ACTIVE_BORDER_COLOR 0x102ff +TOGGLE_ACTIVE_INSIDE_COLOR 0x1c424cff +TOGGLE_ACTIVE_TEXT_COLOR 0xfbfbf7ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x1 +SLIDER_BORDER_COLOR 0x38393aff +SLIDER_INSIDE_COLOR 0x8da0a5ff +SLIDER_DEFAULT_COLOR 0x557179ff +SLIDER_HOVER_COLOR 0x385a62ff +SLIDER_ACTIVE_COLOR 0x2b36ff +SLIDERBAR_BORDER_COLOR 0x38393aff +SLIDERBAR_INSIDE_COLOR 0x8da0a5ff +SLIDERBAR_DEFAULT_COLOR 0x557179ff +SLIDERBAR_HOVER_COLOR 0x385a62ff +SLIDERBAR_ACTIVE_COLOR 0x2b36ff +SLIDERBAR_ZERO_LINE_COLOR 0x1c424cff +PROGRESSBAR_BORDER_COLOR 0x38393aff +PROGRESSBAR_INSIDE_COLOR 0x8da0a5ff +PROGRESSBAR_PROGRESS_COLOR 0x557179ff +PROGRESSBAR_BORDER_WIDTH 0x2 +SPINNER_LABEL_BORDER_COLOR 0x38393aff +SPINNER_LABEL_INSIDE_COLOR 0x8da0a5ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x38393aff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0x8da0a5ff +SPINNER_DEFAULT_SYMBOL_COLOR 0xf8f8f1ff +SPINNER_DEFAULT_TEXT_COLOR 0xf8f8f1ff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0x1c1d1eff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0x8da0a5ff +SPINNER_HOVER_SYMBOL_COLOR 0xf8f8f2ff +SPINNER_HOVER_TEXT_COLOR 0xf8f8f2ff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x102ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0x71898fff +SPINNER_PRESSED_SYMBOL_COLOR 0xfbfbf7ff +SPINNER_PRESSED_TEXT_COLOR 0xfbfbf7ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x1e +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x38393aff +COMBOBOX_DEFAULT_INSIDE_COLOR 0x8da0a5ff +COMBOBOX_DEFAULT_TEXT_COLOR 0xf8f8f1ff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0xf8f8f1ff +COMBOBOX_HOVER_BORDER_COLOR 0x1c1d1eff +COMBOBOX_HOVER_INSIDE_COLOR 0x8da0a5ff +COMBOBOX_HOVER_TEXT_COLOR 0xf8f8f2ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0xf8f8f2ff +COMBOBOX_PRESSED_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_INSIDE_COLOR 0x1c424cff +COMBOBOX_PRESSED_TEXT_COLOR 0xfbfbf8ff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0x1c424cff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0xfbfbf8ff +CHECKBOX_DEFAULT_BORDER_COLOR 0x38393aff +CHECKBOX_DEFAULT_INSIDE_COLOR 0x8da0a5ff +CHECKBOX_HOVER_BORDER_COLOR 0x1c1d1eff +CHECKBOX_HOVER_INSIDE_COLOR 0xffffffff +CHECKBOX_CLICK_BORDER_COLOR 0x102ff +CHECKBOX_CLICK_INSIDE_COLOR 0x557179ff +CHECKBOX_STATUS_ACTIVE_COLOR 0x1c424cff +CHECKBOX_INSIDE_WIDTH 0x4 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x38393aff +TEXTBOX_INSIDE_COLOR 0x8da0a5ff +TEXTBOX_TEXT_COLOR 0xf8f8f1ff +TEXTBOX_LINE_COLOR 0xfafaf5ff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/solarized_light.style b/examples/gui/basic_controls/styles/solarized_light.style new file mode 100644 index 0000000..8d413c9 --- /dev/null +++ b/examples/gui/basic_controls/styles/solarized_light.style @@ -0,0 +1,98 @@ +GLOBAL_BASE_COLOR 0xfcf6e3ff +GLOBAL_BORDER_COLOR 0x102ff +GLOBAL_TEXT_COLOR 0x657b82ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0xfefcf5ff +LABEL_BORDER_WIDTH 0x1 +LABEL_TEXT_COLOR 0x657b82ff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x2 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x38393aff +BUTTON_DEFAULT_INSIDE_COLOR 0xfdfbf2ff +BUTTON_DEFAULT_TEXT_COLOR 0x657b82ff +BUTTON_HOVER_BORDER_COLOR 0x1c1d1eff +BUTTON_HOVER_INSIDE_COLOR 0xfdfbf2ff +BUTTON_HOVER_TEXT_COLOR 0x76898fff +BUTTON_PRESSED_BORDER_COLOR 0x102ff +BUTTON_PRESSED_INSIDE_COLOR 0xfdfaefff +BUTTON_PRESSED_TEXT_COLOR 0xa9b5b9ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x38393aff +TOGGLE_DEFAULT_INSIDE_COLOR 0xfdfbf2ff +TOGGLE_DEFAULT_TEXT_COLOR 0x657b82ff +TOGGLE_HOVER_BORDER_COLOR 0x1c1d1eff +TOGGLE_HOVER_INSIDE_COLOR 0xfdfbf2ff +TOGGLE_HOVER_TEXT_COLOR 0x76898fff +TOGGLE_PRESSED_BORDER_COLOR 0x102ff +TOGGLE_PRESSED_INSIDE_COLOR 0xfdfaefff +TOGGLE_PRESSED_TEXT_COLOR 0xa9b5b9ff +TOGGLE_ACTIVE_BORDER_COLOR 0x102ff +TOGGLE_ACTIVE_INSIDE_COLOR 0xfcf7e6ff +TOGGLE_ACTIVE_TEXT_COLOR 0xa9b5b9ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x1 +SLIDER_BUTTON_BORDER_WIDTH 0x1 +SLIDER_BORDER_COLOR 0x38393aff +SLIDER_INSIDE_COLOR 0xfdfbf2ff +SLIDER_DEFAULT_COLOR 0xfdf9ecff +SLIDER_HOVER_COLOR 0xfcf8e9ff +SLIDER_ACTIVE_COLOR 0xfcf6e3ff +SLIDERBAR_BORDER_COLOR 0x38393aff +SLIDERBAR_INSIDE_COLOR 0xfdfbf2ff +SLIDERBAR_DEFAULT_COLOR 0xfdf9ecff +SLIDERBAR_HOVER_COLOR 0xfcf8e9ff +SLIDERBAR_ACTIVE_COLOR 0xfcf6e3ff +SLIDERBAR_ZERO_LINE_COLOR 0xfcf7e6ff +PROGRESSBAR_BORDER_COLOR 0x38393aff +PROGRESSBAR_INSIDE_COLOR 0xfdfbf2ff +PROGRESSBAR_PROGRESS_COLOR 0xfdf9ecff +PROGRESSBAR_BORDER_WIDTH 0x2 +SPINNER_LABEL_BORDER_COLOR 0x38393aff +SPINNER_LABEL_INSIDE_COLOR 0xfdfbf2ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x38393aff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0xfdfbf2ff +SPINNER_DEFAULT_SYMBOL_COLOR 0x657b82ff +SPINNER_DEFAULT_TEXT_COLOR 0x657b82ff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0x1c1d1eff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0xfdfbf2ff +SPINNER_HOVER_SYMBOL_COLOR 0x76898fff +SPINNER_HOVER_TEXT_COLOR 0x76898fff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x102ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0xfdfaefff +SPINNER_PRESSED_SYMBOL_COLOR 0xa9b5b9ff +SPINNER_PRESSED_TEXT_COLOR 0xa9b5b9ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x1e +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x38393aff +COMBOBOX_DEFAULT_INSIDE_COLOR 0xfdfbf2ff +COMBOBOX_DEFAULT_TEXT_COLOR 0x657b82ff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0x657b82ff +COMBOBOX_HOVER_BORDER_COLOR 0x1c1d1eff +COMBOBOX_HOVER_INSIDE_COLOR 0xfdfbf2ff +COMBOBOX_HOVER_TEXT_COLOR 0x76898fff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0x76898fff +COMBOBOX_PRESSED_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_INSIDE_COLOR 0xfcf7e6ff +COMBOBOX_PRESSED_TEXT_COLOR 0xbac4c7ff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x102ff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0xfcf7e6ff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0xbac4c7ff +CHECKBOX_DEFAULT_BORDER_COLOR 0x38393aff +CHECKBOX_DEFAULT_INSIDE_COLOR 0xfdfbf2ff +CHECKBOX_HOVER_BORDER_COLOR 0x1c1d1eff +CHECKBOX_HOVER_INSIDE_COLOR 0xffffffff +CHECKBOX_CLICK_BORDER_COLOR 0x102ff +CHECKBOX_CLICK_INSIDE_COLOR 0xfdf9ecff +CHECKBOX_STATUS_ACTIVE_COLOR 0xfcf7e6ff +CHECKBOX_INSIDE_WIDTH 0x4 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x38393aff +TEXTBOX_INSIDE_COLOR 0xfdfbf2ff +TEXTBOX_TEXT_COLOR 0x657b82ff +TEXTBOX_LINE_COLOR 0x98a7abff +TEXTBOX_TEXT_FONTSIZE 0xa diff --git a/examples/gui/basic_controls/styles/zahnrad.style b/examples/gui/basic_controls/styles/zahnrad.style new file mode 100644 index 0000000..54ca5f6 --- /dev/null +++ b/examples/gui/basic_controls/styles/zahnrad.style @@ -0,0 +1,98 @@ +GLOBAL_BASE_COLOR 0xf5f5f5ff +GLOBAL_BORDER_COLOR 0xf5f5f5ff +GLOBAL_TEXT_COLOR 0xf5f5f5ff +GLOBAL_TEXT_FONTSIZE 0xa +GLOBAL_BORDER_WIDTH 0x1 +BACKGROUND_COLOR 0x2d2d2dff +LABEL_BORDER_WIDTH 0x2 +LABEL_TEXT_COLOR 0xafafafff +LABEL_TEXT_PADDING 0x14 +BUTTON_BORDER_WIDTH 0x1 +BUTTON_TEXT_PADDING 0x14 +BUTTON_DEFAULT_BORDER_COLOR 0x414141ff +BUTTON_DEFAULT_INSIDE_COLOR 0x323232ff +BUTTON_DEFAULT_TEXT_COLOR 0xafafafff +BUTTON_HOVER_BORDER_COLOR 0x3e3e3eff +BUTTON_HOVER_INSIDE_COLOR 0x2d2d2dff +BUTTON_HOVER_TEXT_COLOR 0x767472ff +BUTTON_PRESSED_BORDER_COLOR 0x414141ff +BUTTON_PRESSED_INSIDE_COLOR 0x323232ff +BUTTON_PRESSED_TEXT_COLOR 0x616161ff +TOGGLE_TEXT_PADDING 0x14 +TOGGLE_BORDER_WIDTH 0x1 +TOGGLE_DEFAULT_BORDER_COLOR 0x414141ff +TOGGLE_DEFAULT_INSIDE_COLOR 0x323232ff +TOGGLE_DEFAULT_TEXT_COLOR 0xafafafff +TOGGLE_HOVER_BORDER_COLOR 0x3e3e3eff +TOGGLE_HOVER_INSIDE_COLOR 0x2d2d2dff +TOGGLE_HOVER_TEXT_COLOR 0x767472ff +TOGGLE_PRESSED_BORDER_COLOR 0x414141ff +TOGGLE_PRESSED_INSIDE_COLOR 0x323232ff +TOGGLE_PRESSED_TEXT_COLOR 0x616161ff +TOGGLE_ACTIVE_BORDER_COLOR 0xafafafff +TOGGLE_ACTIVE_INSIDE_COLOR 0x414141ff +TOGGLE_ACTIVE_TEXT_COLOR 0xa3a3a3ff +TOGGLEGROUP_PADDING 0x3 +SLIDER_BORDER_WIDTH 0x0 +SLIDER_BUTTON_BORDER_WIDTH 0x0 +SLIDER_BORDER_COLOR 0x414141ff +SLIDER_INSIDE_COLOR 0x232525ff +SLIDER_DEFAULT_COLOR 0x646464ff +SLIDER_HOVER_COLOR 0x767472ff +SLIDER_ACTIVE_COLOR 0x929291ff +SLIDERBAR_BORDER_COLOR 0x828282ff +SLIDERBAR_INSIDE_COLOR 0x262626ff +SLIDERBAR_DEFAULT_COLOR 0x616161ff +SLIDERBAR_HOVER_COLOR 0x646464ff +SLIDERBAR_ACTIVE_COLOR 0x929292ff +SLIDERBAR_ZERO_LINE_COLOR 0xafafafff +PROGRESSBAR_BORDER_COLOR 0x828282ff +PROGRESSBAR_INSIDE_COLOR 0x262626ff +PROGRESSBAR_PROGRESS_COLOR 0x646464ff +PROGRESSBAR_BORDER_WIDTH 0x0 +SPINNER_LABEL_BORDER_COLOR 0x414141ff +SPINNER_LABEL_INSIDE_COLOR 0x323232ff +SPINNER_DEFAULT_BUTTON_BORDER_COLOR 0x414141ff +SPINNER_DEFAULT_BUTTON_INSIDE_COLOR 0x323232ff +SPINNER_DEFAULT_SYMBOL_COLOR 0xafafafff +SPINNER_DEFAULT_TEXT_COLOR 0xafafafff +SPINNER_HOVER_BUTTON_BORDER_COLOR 0x3e3e3eff +SPINNER_HOVER_BUTTON_INSIDE_COLOR 0x2d2d2dff +SPINNER_HOVER_SYMBOL_COLOR 0x767472ff +SPINNER_HOVER_TEXT_COLOR 0x767472ff +SPINNER_PRESSED_BUTTON_BORDER_COLOR 0x414141ff +SPINNER_PRESSED_BUTTON_INSIDE_COLOR 0x323232ff +SPINNER_PRESSED_SYMBOL_COLOR 0x646464ff +SPINNER_PRESSED_TEXT_COLOR 0x646464ff +COMBOBOX_PADDING 0x1 +COMBOBOX_BUTTON_WIDTH 0x1e +COMBOBOX_BUTTON_HEIGHT 0x1e +COMBOBOX_BORDER_WIDTH 0x1 +COMBOBOX_DEFAULT_BORDER_COLOR 0x414141ff +COMBOBOX_DEFAULT_INSIDE_COLOR 0x323232ff +COMBOBOX_DEFAULT_TEXT_COLOR 0xafafafff +COMBOBOX_DEFAULT_LIST_TEXT_COLOR 0xafafafff +COMBOBOX_HOVER_BORDER_COLOR 0x3e3e3eff +COMBOBOX_HOVER_INSIDE_COLOR 0x2d2d2dff +COMBOBOX_HOVER_TEXT_COLOR 0x767472ff +COMBOBOX_HOVER_LIST_TEXT_COLOR 0x767472ff +COMBOBOX_PRESSED_BORDER_COLOR 0x414141ff +COMBOBOX_PRESSED_INSIDE_COLOR 0x323232ff +COMBOBOX_PRESSED_TEXT_COLOR 0x646464ff +COMBOBOX_PRESSED_LIST_BORDER_COLOR 0x414141ff +COMBOBOX_PRESSED_LIST_INSIDE_COLOR 0x323232ff +COMBOBOX_PRESSED_LIST_TEXT_COLOR 0x646464ff +CHECKBOX_DEFAULT_BORDER_COLOR 0x414141ff +CHECKBOX_DEFAULT_INSIDE_COLOR 0x323232ff +CHECKBOX_HOVER_BORDER_COLOR 0x3e3e3eff +CHECKBOX_HOVER_INSIDE_COLOR 0x2d2d2dff +CHECKBOX_CLICK_BORDER_COLOR 0x414141ff +CHECKBOX_CLICK_INSIDE_COLOR 0x323232ff +CHECKBOX_STATUS_ACTIVE_COLOR 0x414141ff +CHECKBOX_INSIDE_WIDTH 0x2 +TEXTBOX_BORDER_WIDTH 0x1 +TEXTBOX_BORDER_COLOR 0x414141ff +TEXTBOX_INSIDE_COLOR 0x323232ff +TEXTBOX_TEXT_COLOR 0xafafafff +TEXTBOX_LINE_COLOR 0xafafafff +TEXTBOX_TEXT_FONTSIZE 0x9 diff --git a/examples/gui/button/main.go b/examples/gui/button/main.go deleted file mode 100644 index ef2d6fa..0000000 --- a/examples/gui/button/main.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "fmt" - - gui "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - rl.InitWindow(800, 450, "raygui - button") - - rl.SetTargetFPS(60) - - var button bool - - for !rl.WindowShouldClose() { - rl.BeginDrawing() - - rl.ClearBackground(rl.Black) - - button = gui.Button(rl.NewRectangle(50, 150, 100, 40), "Click") - if button { - fmt.Println("Clicked on button") - } - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/gui/controls_test_suite/controls_test_suite.go b/examples/gui/controls_test_suite/controls_test_suite.go deleted file mode 100644 index a635890..0000000 --- a/examples/gui/controls_test_suite/controls_test_suite.go +++ /dev/null @@ -1,281 +0,0 @@ -package main - -import ( - "fmt" - - gui "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -/******************************************************************************************* -* -* raygui - controls test suite -* -* TEST CONTROLS: -* - gui.DropdownBox() -* - gui.CheckBox() -* - gui.Spinner() -* - gui.ValueBox() -* - gui.TextBox() -* - gui.Button() -* - gui.ComboBox() -* - gui.ListView() -* - gui.ToggleGroup() -* - gui.ColorPicker() -* - gui.Slider() -* - gui.SliderBar() -* - gui.ProgressBar() -* - gui.ColorBarAlpha() -* - gui.ScrollPanel() -* -* -* DEPENDENCIES: -* raylib 4.0 - Windowing/input management and drawing. -* raygui 3.2 - Immediate-mode GUI controls. -* -* COMPILATION (Windows - MinGW): -* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99 -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2022 Ramon Santamaria (@raysan5) -* -**********************************************************************************************/ - -//#define RAYGUI_CUSTOM_ICONS // It requires providing gui_icons.h in the same directory -//#include "gui_icons.h" // External icons data provided, it can be generated with rGuiIcons tool - -// ------------------------------------------------------------------------------------ -// Program main entry point -// ------------------------------------------------------------------------------------ -func main() { - // Initialization - //--------------------------------------------------------------------------------------- - const ( - screenWidth = 690 - screenHeight = 560 - ) - - rl.InitWindow(screenWidth, screenHeight, "raygui - controls test suite") - rl.SetExitKey(0) - - // GUI controls initialization - //---------------------------------------------------------------------------------- - var ( - dropdownBox000Active int32 = 0 - dropDown000EditMode bool = false - - dropdownBox001Active int32 = 0 - dropDown001EditMode bool = false - - spinner001Value int32 = 0 - spinnerEditMode bool = false - - valueBox002Value int32 = 0 - valueBoxEditMode bool = false - - textBoxText = "Text box" - textBoxEditMode bool = false - - listViewScrollIndex int32 = 0 - listViewActive int32 = -1 - - listViewExScrollIndex int32 = 0 - listViewExActive int32 = 2 - listViewExFocus int32 = -1 - listViewExList = []string{"This", "is", "a", "list view", "with", "disable", "elements", "amazing!"} - - colorPickerValue = rl.Red - - sliderValue float32 = 50 - sliderBarValue float32 = 60 - progressValue float32 = 0.4 - - forceSquaredChecked bool = false - - alphaValue float32 = 0.5 - - comboBoxActive int32 = 1 - - toggleGroupActive int32 = 0 - - viewScroll = rl.Vector2{0, 0} - - //---------------------------------------------------------------------------------- - - // Custom GUI font loading - //Font font = LoadFontEx("fonts/rainyhearts16.ttf", 12, 0, 0); - //GuiSetFont(font); - - exitWindow bool = false - showMessageBox bool = false - - textInput string - showTextInputBox bool = false - - // TODO textInputFileName string - ) - - rl.SetTargetFPS(60) - //-------------------------------------------------------------------------------------- - - // Main game loop - for !exitWindow { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - exitWindow = rl.WindowShouldClose() - - if rl.IsKeyPressed(rl.KeyEscape) { - showMessageBox = !showMessageBox - } - - if rl.IsKeyDown(rl.KeyLeftControl) && rl.IsKeyPressed(rl.KeyS) { - showTextInputBox = true - } - - // TODO if rl.IsFileDropped() { - // TODO var droppedFiles gui.FilePathList = rl.LoadDroppedFiles() - // TODO if (droppedFiles.count > 0) && rl.IsFileExtension(droppedFiles.paths[0], ".rgs") { - // TODO gui.LoadStyle(droppedFiles.paths[0]) - // TODO } - // TODO rl.UnloadDroppedFiles(droppedFiles) // Clear internal buffers - // TODO } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - - rl.ClearBackground(rl.GetColor(uint(gui.GetStyle(gui.DEFAULT, gui.BACKGROUND_COLOR)))) - - // raygui: controls drawing - //---------------------------------------------------------------------------------- - if dropDown000EditMode || dropDown001EditMode { - gui.Lock() - } else if !dropDown000EditMode && !dropDown001EditMode { - gui.Unlock() - } - //GuiDisable(); - - // First GUI column - //GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - forceSquaredChecked = gui.CheckBox(rl.Rectangle{25, 108, 15, 15}, "FORCE CHECK!", forceSquaredChecked) - - gui.SetStyle(gui.TEXTBOX, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_CENTER) - //GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - gui.Spinner(rl.Rectangle{25, 135, 125, 30}, "", &spinner001Value, 0, 100, spinnerEditMode) - - if gui.ValueBox(rl.Rectangle{25, 175, 125, 30}, "", &valueBox002Value, 0, 100, valueBoxEditMode) { - valueBoxEditMode = !valueBoxEditMode - } - gui.SetStyle(gui.TEXTBOX, gui.TEXT_ALIGNMENT, int64(gui.TEXT_ALIGN_LEFT)) - if gui.TextBox(rl.Rectangle{25, 215, 125, 30}, &textBoxText, 64, textBoxEditMode) { - textBoxEditMode = !textBoxEditMode - } - - gui.SetStyle(gui.BUTTON, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_CENTER) - - if gui.Button(rl.Rectangle{25, 255, 125, 30}, gui.IconText(gui.ICON_FILE_SAVE, "Save File")) { - showTextInputBox = true - } - - gui.GroupBox(rl.Rectangle{25, 310, 125, 150}, "STATES") - //GuiLock(); - gui.SetState(gui.STATE_NORMAL) - if gui.Button(rl.Rectangle{30, 320, 115, 30}, "NORMAL") { - } - gui.SetState(gui.STATE_FOCUSED) - if gui.Button(rl.Rectangle{30, 355, 115, 30}, "FOCUSED") { - } - gui.SetState(gui.STATE_PRESSED) - if gui.Button(rl.Rectangle{30, 390, 115, 30}, "#15#PRESSED") { - } - gui.SetState(gui.STATE_DISABLED) - if gui.Button(rl.Rectangle{30, 425, 115, 30}, "DISABLED") { - } - gui.SetState(gui.STATE_NORMAL) - //GuiUnlock(); - - comboBoxActive = gui.ComboBox(rl.Rectangle{25, 470, 125, 30}, "ONE;TWO;THREE;FOUR", comboBoxActive) - - // NOTE: gui.DropdownBox must draw after any other control that can be covered on unfolding - gui.SetStyle(gui.DROPDOWNBOX, gui.TEXT_ALIGNMENT, int64(gui.TEXT_ALIGN_LEFT)) - if gui.DropdownBox(rl.Rectangle{25, 65, 125, 30}, "#01#ONE;#02#TWO;#03#THREE;#04#FOUR", &dropdownBox001Active, dropDown001EditMode) { - dropDown001EditMode = !dropDown001EditMode - } - - gui.SetStyle(gui.DROPDOWNBOX, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_CENTER) - if gui.DropdownBox(rl.Rectangle{25, 25, 125, 30}, "ONE;TWO;THREE", &dropdownBox000Active, dropDown000EditMode) { - dropDown000EditMode = !dropDown000EditMode - } - - // Second GUI column - listViewActive = gui.ListView(rl.Rectangle{165, 25, 140, 140}, "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey", &listViewScrollIndex, listViewActive) - listViewExActive = gui.ListViewEx(rl.Rectangle{165, 180, 140, 200}, listViewExList, &listViewExFocus, &listViewExScrollIndex, listViewExActive) - - toggleGroupActive = gui.ToggleGroup(rl.Rectangle{165, 400, 140, 25}, "#1#ONE\n#3#TWO\n#8#THREE\n#23#", toggleGroupActive) - - // Third GUI column - gui.Panel(rl.NewRectangle(320, 25, 225, 140), "Panel Info") - colorPickerValue = gui.ColorPicker(rl.Rectangle{320, 185, 196, 192}, "", colorPickerValue) - - sliderValue = gui.Slider(rl.Rectangle{355, 400, 165, 20}, "TEST", - fmt.Sprintf("%2.2f", sliderValue), sliderValue, -50, 100) - sliderBarValue = gui.SliderBar(rl.Rectangle{320, 430, 200, 20}, "", - fmt.Sprintf("%2.2f", sliderBarValue), sliderBarValue, 0, 100) - progressValue = gui.ProgressBar(rl.Rectangle{320, 460, 200, 20}, "", "", progressValue, 0, 1) - - // NOTE: View rectangle could be used to perform some scissor test - var view rl.Rectangle - gui.ScrollPanel(rl.Rectangle{560, 25, 102, 354}, "", rl.Rectangle{560, 25, 300, 1200}, &viewScroll, &view) - - var mouseCell rl.Vector2 - gui.Grid(rl.Rectangle{560, 25 + 180 + 195, 100, 120}, "", 20, 3, &mouseCell) - - alphaValue = gui.ColorBarAlpha(rl.Rectangle{320, 490, 200, 30}, "", alphaValue) - - gui.StatusBar(rl.Rectangle{0, float32(rl.GetScreenHeight()) - 20, float32(rl.GetScreenWidth()), 20}, "This is a status bar") - - if showMessageBox { - rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), int32(rl.GetScreenHeight()), rl.Fade(rl.RayWhite, 0.8)) - var result int32 = gui.MessageBox(rl.Rectangle{float32(rl.GetScreenWidth())/2 - 125, float32(rl.GetScreenHeight())/2 - 50, 250, 100}, gui.IconText(gui.ICON_EXIT, "Close Window"), "Do you really want to exit?", "Yes;No") - - if (result == 0) || (result == 2) { - showMessageBox = false - } else if result == 1 { - exitWindow = true - } - } - - if showTextInputBox { - rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), int32(rl.GetScreenHeight()), rl.Fade(rl.RayWhite, 0.8)) - var secretViewActive bool - var result int32 = gui.TextInputBox( - rl.Rectangle{float32(rl.GetScreenWidth())/2 - 120, float32(rl.GetScreenHeight())/2 - 60, 240, 140}, - "Save", - gui.IconText(gui.ICON_FILE_SAVE, "Save file as..."), - "Ok;Cancel", - &textInput, 255, &secretViewActive) - - if result == 1 { - // TODO: Validate textInput value and save - // strcpy(textInputFileName, textInput) - // TODO textInputFileName = textInput - } - if (result == 0) || (result == 1) || (result == 2) { - showTextInputBox = false - //strcpy(textInput, "\0"); - textInput = "" - } - } - //---------------------------------------------------------------------------------- - - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} diff --git a/examples/gui/controls_test_suite/controls_test_suite.png b/examples/gui/controls_test_suite/controls_test_suite.png deleted file mode 100644 index 8db0e25..0000000 Binary files a/examples/gui/controls_test_suite/controls_test_suite.png and /dev/null differ diff --git a/examples/gui/icons/README.md b/examples/gui/icons/README.md deleted file mode 100644 index 8c114f4..0000000 --- a/examples/gui/icons/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This example loads a custom .rgi-file and draws the 255th icon. You can use the [rGuiIcons](https://raylibtech.itch.io/rguiicons) tool to view or create icon files. - -![Screenshot](./screenshot.png) diff --git a/examples/gui/icons/default_icons_with_255.rgi b/examples/gui/icons/default_icons_with_255.rgi deleted file mode 100644 index 8271617..0000000 Binary files a/examples/gui/icons/default_icons_with_255.rgi and /dev/null differ diff --git a/examples/gui/icons/main.go b/examples/gui/icons/main.go deleted file mode 100644 index a86e84f..0000000 --- a/examples/gui/icons/main.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - rl.InitWindow(800, 600, "raylib-go - icons example") - defer rl.CloseWindow() - - raygui.LoadIcons("default_icons_with_255.rgi", false) - - for !rl.WindowShouldClose() { - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - raygui.DrawIcon(raygui.ICON_255, 100, 100, 8, rl.Gray) - rl.EndDrawing() - } -} diff --git a/examples/gui/icons/screenshot.png b/examples/gui/icons/screenshot.png deleted file mode 100644 index 3e05961..0000000 Binary files a/examples/gui/icons/screenshot.png and /dev/null differ diff --git a/examples/gui/portable_window/portable_window.go b/examples/gui/portable_window/portable_window.go deleted file mode 100644 index 9f8463c..0000000 --- a/examples/gui/portable_window/portable_window.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "fmt" - - gui "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -/******************************************************************************************* -* -* raygui - portable window -* -* DEPENDENCIES: -* raylib 4.0 - Windowing/input management and drawing. -* raygui 3.0 - Immediate-mode GUI controls. -* -* COMPILATION (Windows - MinGW): -* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99 -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2022 Ramon Santamaria (@raysan5) -* -**********************************************************************************************/ - -// ------------------------------------------------------------------------------------ -// Program main entry point -// ------------------------------------------------------------------------------------ -func main() { - // Initialization - //--------------------------------------------------------------------------------------- - const ( - screenWidth = 800 - screenHeight = 600 - ) - - rl.SetConfigFlags(rl.FlagWindowUndecorated) - rl.InitWindow(screenWidth, screenHeight, "raygui - portable window") - - // General variables - var ( - mousePosition = rl.Vector2{0, 0} - windowPosition = rl.Vector2{500, 200} - panOffset = mousePosition - dragWindow = false - ) - - rl.SetWindowPosition(int(windowPosition.X), int(windowPosition.Y)) - - exitWindow := false - - rl.SetTargetFPS(60) - //-------------------------------------------------------------------------------------- - - // Main game loop - for !exitWindow && !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - mousePosition = rl.GetMousePosition() - - if rl.IsMouseButtonPressed(rl.MouseLeftButton) { - if (rl.CheckCollisionPointRec(mousePosition, rl.Rectangle{0, 0, screenWidth, 20})) { - dragWindow = true - panOffset = mousePosition - } - } - - if dragWindow { - windowPosition.X += (mousePosition.X - panOffset.X) - windowPosition.Y += (mousePosition.Y - panOffset.Y) - - if rl.IsMouseButtonReleased(rl.MouseLeftButton) { - dragWindow = false - } - - rl.SetWindowPosition(int(windowPosition.X), int(windowPosition.Y)) - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - exitWindow = gui.WindowBox(rl.Rectangle{0, 0, screenWidth, screenHeight}, "#198# PORTABLE WINDOW") - - rl.DrawText(fmt.Sprintf("Mouse Position: [ %.0f, %.0f ]", mousePosition.X, mousePosition.Y), 10, 40, 10, rl.DarkGray) - - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} diff --git a/examples/gui/scroll_panel/scroll_panel.go b/examples/gui/scroll_panel/scroll_panel.go deleted file mode 100644 index eed0a62..0000000 --- a/examples/gui/scroll_panel/scroll_panel.go +++ /dev/null @@ -1,193 +0,0 @@ -package main - -import ( - "fmt" - - gui "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -/******************************************************************************************* -* -* raygui - Controls test -* -* TEST CONTROLS: -* - gui.ScrollPanel() -* -* DEPENDENCIES: -* raylib 4.0 - Windowing/input management and drawing. -* raygui 3.0 - Immediate-mode GUI controls. -* -* COMPILATION (Windows - MinGW): -* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99 -* -* COMPILATION (Linux - gcc): -* gcc -o $(NAME_PART) $(FILE_NAME) -I../../src -lraylib -lGL -lm -lpthread -ldl -lrt -lX11 -std=c99 -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2019-2022 Vlad Adrian (@Demizdor) and Ramon Santamaria (@raysan5) -* -**********************************************************************************************/ - -// ------------------------------------------------------------------------------------ -// Program main entry point -// ------------------------------------------------------------------------------------ -func main() { - - // Initialization - //--------------------------------------------------------------------------------------- - const ( - screenWidth = 800 - screenHeight = 450 - ) - - rl.InitWindow(screenWidth, screenHeight, "raygui - gui.ScrollPanel()") - - var ( - panelRec = rl.Rectangle{20, 40, 200, 150} - panelContentRec = rl.Rectangle{0, 0, 340, 340} - panelView = rl.Rectangle{0, 0, 0, 0} - panelScroll = rl.Vector2{99, -20} - mouseCell = rl.Vector2{0, 0} - - showContentArea = true - ) - - rl.SetTargetFPS(60) - //--------------------------------------------------------------------------------------- - - // Main game loop - for !rl.WindowShouldClose() { - // Detect window close button or ESC key - - // Update - //---------------------------------------------------------------------------------- - // TODO: Implement required update logic - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.DrawText(fmt.Sprintf("[%.1f, %.1f]", panelScroll.X, panelScroll.Y), 4, 4, 20, rl.Red) - - gui.ScrollPanel(panelRec, "", panelContentRec, &panelScroll, &panelView) - - rl.BeginScissorMode(int32(panelView.X), int32(panelView.Y), int32(panelView.Width), int32(panelView.Height)) - gui.Grid(rl.Rectangle{ - float32(panelRec.X + panelScroll.X), - float32(panelRec.Y + panelScroll.Y), - float32(panelContentRec.Width), - float32(panelContentRec.Height), - }, "", 16, 3, &mouseCell) - rl.EndScissorMode() - - if showContentArea { - rl.DrawRectangle( - int32(panelRec.X+panelScroll.X), - int32(panelRec.Y+panelScroll.Y), - int32(panelContentRec.Width), - int32(panelContentRec.Height), - rl.Fade(rl.Red, 0.1), - ) - } - - DrawStyleEditControls() - - showContentArea = gui.CheckBox(rl.Rectangle{565, 80, 20, 20}, "SHOW CONTENT AREA", showContentArea) - - panelContentRec.Width = gui.SliderBar(rl.Rectangle{590, 385, 145, 15}, - "WIDTH", - fmt.Sprintf("%.1f", panelContentRec.Width), - panelContentRec.Width, - 1, 600) - panelContentRec.Height = gui.SliderBar(rl.Rectangle{590, 410, 145, 15}, - "HEIGHT", - fmt.Sprintf("%.1f", panelContentRec.Height), - panelContentRec.Height, 1, 400) - - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} - -// Draw and process scroll bar style edition controls -func DrawStyleEditControls() { - // ScrollPanel style controls - //---------------------------------------------------------- - gui.GroupBox(rl.Rectangle{550, 170, 220, 205}, "SCROLLBAR STYLE") - - var style int32 - - style = int32(gui.GetStyle(gui.SCROLLBAR, gui.BORDER_WIDTH)) - gui.Label(rl.Rectangle{555, 195, 110, 10}, "BORDER_WIDTH") - gui.Spinner(rl.Rectangle{670, 190, 90, 20}, "", &style, 0, 6, false) - gui.SetStyle(gui.SCROLLBAR, gui.BORDER_WIDTH, int64(style)) - - style = int32(gui.GetStyle(gui.SCROLLBAR, gui.ARROWS_SIZE)) - gui.Label(rl.Rectangle{555, 220, 110, 10}, "ARROWS_SIZE") - gui.Spinner(rl.Rectangle{670, 215, 90, 20}, "", &style, 4, 14, false) - gui.SetStyle(gui.SCROLLBAR, gui.ARROWS_SIZE, int64(style)) - - style = int32(gui.GetStyle(gui.SCROLLBAR, gui.SLIDER_PADDING)) - gui.Label(rl.Rectangle{555, 245, 110, 10}, "SLIDER_PADDING") - gui.Spinner(rl.Rectangle{670, 240, 90, 20}, "", &style, 0, 14, false) - gui.SetStyle(gui.SCROLLBAR, gui.SLIDER_PADDING, int64(style)) - - style = boolToint32(gui.CheckBox(rl.Rectangle{565, 280, 20, 20}, "ARROWS_VISIBLE", int32Tobool(int32(gui.GetStyle(gui.SCROLLBAR, gui.ARROWS_VISIBLE))))) - gui.SetStyle(gui.SCROLLBAR, gui.ARROWS_VISIBLE, int64(style)) - - style = int32(gui.GetStyle(gui.SCROLLBAR, gui.SLIDER_PADDING)) - gui.Label(rl.Rectangle{555, 325, 110, 10}, "SLIDER_PADDING") - gui.Spinner(rl.Rectangle{670, 320, 90, 20}, "", &style, 0, 14, false) - gui.SetStyle(gui.SCROLLBAR, gui.SLIDER_PADDING, int64(style)) - - style = int32(gui.GetStyle(gui.SCROLLBAR, gui.SLIDER_WIDTH)) - gui.Label(rl.Rectangle{555, 350, 110, 10}, "SLIDER_WIDTH") - gui.Spinner(rl.Rectangle{670, 345, 90, 20}, "", &style, 2, 100, false) - gui.SetStyle(gui.SCROLLBAR, gui.SLIDER_WIDTH, int64(style)) - - var text string - if gui.GetStyle(gui.LISTVIEW, gui.SCROLLBAR_SIDE) == gui.SCROLLBAR_LEFT_SIDE { - text = "SCROLLBAR: LEFT" - } else { - text = "SCROLLBAR: RIGHT" - } - style = boolToint32(gui.Toggle(rl.Rectangle{560, 110, 200, 35}, text, int32Tobool(int32(gui.GetStyle(gui.LISTVIEW, gui.SCROLLBAR_SIDE))))) - gui.SetStyle(gui.LISTVIEW, gui.SCROLLBAR_SIDE, int64(style)) - //---------------------------------------------------------- - - // ScrollBar style controls - //---------------------------------------------------------- - gui.GroupBox(rl.Rectangle{550, 20, 220, 135}, "SCROLLPANEL STYLE") - - style = int32(gui.GetStyle(gui.LISTVIEW, gui.SCROLLBAR_WIDTH)) - gui.Label(rl.Rectangle{555, 35, 110, 10}, "SCROLLBAR_WIDTH") - gui.Spinner(rl.Rectangle{670, 30, 90, 20}, "", &style, 6, 30, false) - gui.SetStyle(gui.LISTVIEW, gui.SCROLLBAR_WIDTH, int64(style)) - - style = int32(gui.GetStyle(gui.DEFAULT, gui.BORDER_WIDTH)) - gui.Label(rl.Rectangle{555, 60, 110, 10}, "BORDER_WIDTH") - gui.Spinner(rl.Rectangle{670, 55, 90, 20}, "", &style, 0, 20, false) - gui.SetStyle(gui.DEFAULT, gui.BORDER_WIDTH, int64(style)) - //---------------------------------------------------------- -} - -func boolToint32(b bool) int32 { - if b { - return 1 - } - return 0 -} - -func int32Tobool(v int32) bool { - return 0 < v -} diff --git a/examples/gui/scroll_panel/scroll_panel.png b/examples/gui/scroll_panel/scroll_panel.png deleted file mode 100644 index fe2e095..0000000 Binary files a/examples/gui/scroll_panel/scroll_panel.png and /dev/null differ diff --git a/examples/models/animation/guy.iqm b/examples/models/animation/guy.iqm deleted file mode 100644 index 36bed5e..0000000 Binary files a/examples/models/animation/guy.iqm and /dev/null differ diff --git a/examples/models/animation/guyanim.iqm b/examples/models/animation/guyanim.iqm deleted file mode 100644 index 824a68a..0000000 Binary files a/examples/models/animation/guyanim.iqm and /dev/null differ diff --git a/examples/models/animation/guytex.png b/examples/models/animation/guytex.png deleted file mode 100644 index 05a58ee..0000000 Binary files a/examples/models/animation/guytex.png and /dev/null differ diff --git a/examples/models/animation/main.go b/examples/models/animation/main.go deleted file mode 100644 index c5e06b7..0000000 --- a/examples/models/animation/main.go +++ /dev/null @@ -1,95 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Load 3d model with animations and play them -* -* Example originally created with raylib 2.5, last time updated with raylib 3.5 -* -* Example contributed by Culacant (@culacant) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2019-2024 Culacant (@culacant) and Ramon Santamaria (@raysan5) -* -******************************************************************************************** -* -* NOTE: To export a model from blender, make sure it is not posed, the vertices need to be -* in the same position as they would be in edit mode and the scale of your models is -* set to 0. Scaling can be done from the export menu. -* -********************************************************************************************/ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(10.0, 10.0, 10.0) - camera.Target = rl.NewVector3(0.0, 0.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 45.0 - camera.Projection = rl.CameraPerspective - - model := rl.LoadModel("guy.iqm") - texture := rl.LoadTexture("guytex.png") - rl.SetMaterialTexture(model.Materials, rl.MapDiffuse, texture) - - position := rl.NewVector3(0, 0, 0) - - anims := rl.LoadModelAnimations("guyanim.iqm") - animFrameCount := 0 - - rl.DisableCursor() - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.UpdateCamera(&camera, rl.CameraFirstPerson) - - if rl.IsKeyDown(rl.KeySpace) { - animFrameCount++ - animCurrent := anims[0] - animFrameNum := animCurrent.FrameCount - - rl.UpdateModelAnimation(model, anims[0], int32(animFrameCount)) - if animFrameCount >= int(animFrameNum) { - animFrameCount = 0 - } - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginMode3D(camera) - - rl.DrawModelEx(model, position, rl.NewVector3(1, 0, 0), -90, rl.NewVector3(1, 1, 1), rl.White) - // Draw translation cubes - for i := int32(0); i < model.BoneCount; i++ { - pose := anims[0].GetFramePose(animFrameCount, int(i)) - rl.DrawCube(pose.Translation, 0.2, 0.2, 0.2, rl.Red) - } - rl.DrawGrid(10, 1) - - rl.EndMode3D() - - rl.DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, rl.Black) - rl.DrawText("(c) Guy IQM 3D model by @culacant", 10, 30, 10, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadModel(model) - rl.UnloadModelAnimations(anims) - rl.UnloadTexture(texture) - - rl.CloseWindow() -} diff --git a/examples/models/billboard/main.go b/examples/models/billboard/main.go index 7f0320f..c177938 100644 --- a/examples/models/billboard/main.go +++ b/examples/models/billboard/main.go @@ -1,26 +1,13 @@ -/******************************************************************************************* -* -* raylib [models] example - Drawing billboards -* -* Example originally created with raylib 1.3, last time updated with raylib 3.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/package main +package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 + "github.com/gen2brain/raylib-go/raylib" ) func main() { + screenWidth := int32(800) + screenHeight := int32(450) + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards") camera := rl.Camera{} @@ -30,61 +17,28 @@ func main() { camera.Fovy = 45.0 camera.Projection = rl.CameraPerspective - bill := rl.LoadTexture("billboard.png") // Our texture billboard - billPositionStatic := rl.NewVector3(0.0, 2.0, 0.0) // Position of static billboard - billPositionRotating := rl.NewVector3(1.0, 2.0, 1.0) // Position of rotating billboard + bill := rl.LoadTexture("billboard.png") // Our texture billboard + billPosition := rl.NewVector3(0.0, 2.0, 0.0) // Position where draw billboard - // Entire billboard texture, source is used to take a segment from a larger texture. - source := rl.Rectangle{ - Width: float32(bill.Width), - Height: float32(bill.Height), - } - - // NOTE: Billboard locked on axis-Y - billUp := rl.Vector3{Y: 1.0} - - // Set the height of the rotating billboard to 1.0 with the aspect ratio fixed - size := rl.Vector2{ - X: source.Width / source.Height, - Y: 1.0, - } - - // Rotate around origin - // Here we choose to rotate around the image center - origin := rl.Vector2Scale(size, 0.5) - - // Distance is needed for the correct billboard draw order - // Larger distance (further away from the camera) should be drawn prior to smaller distance. - var distanceStatic, distanceRotating, rotation float32 + rl.SetCameraMode(camera, rl.CameraOrbital) // Set an orbital camera mode rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - // Update - rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode + rl.UpdateCamera(&camera) // Update camera - rotation += 0.4 - distanceStatic = rl.Vector3Distance(camera.Position, billPositionStatic) - distanceRotating = rl.Vector3Distance(camera.Position, billPositionRotating) - - // Draw rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) + rl.BeginMode3D(camera) rl.DrawGrid(10, 1.0) // Draw a grid - // Draw order matters! - if distanceStatic > distanceRotating { - rl.DrawBillboard(camera, bill, billPositionStatic, 2.0, rl.White) - rl.DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, rl.White) - } else { - rl.DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, rl.White) - rl.DrawBillboard(camera, bill, billPositionStatic, 2.0, rl.White) - } + rl.DrawBillboard(camera, bill, billPosition, 2.0, rl.White) rl.EndMode3D() - rl.DrawFPS(10, 10) + rl.EndDrawing() } diff --git a/examples/models/box_collisions/main.go b/examples/models/box_collisions/main.go index 82c2c4c..596a5d7 100644 --- a/examples/models/box_collisions/main.go +++ b/examples/models/box_collisions/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/models/cubicmap/main.go b/examples/models/cubicmap/main.go index f5790fe..bad513f 100644 --- a/examples/models/cubicmap/main.go +++ b/examples/models/cubicmap/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -30,12 +30,14 @@ func main() { rl.UnloadImage(image) // Unload cubicmap image from RAM, already uploaded to VRAM + rl.SetCameraMode(camera, rl.CameraOrbital) // Set an orbital camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { // Update - rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode + rl.UpdateCamera(&camera) // Update camera // Draw diff --git a/examples/models/draw_cube_texture/cubicmap_atlas.png b/examples/models/draw_cube_texture/cubicmap_atlas.png deleted file mode 100644 index 9fc404a..0000000 Binary files a/examples/models/draw_cube_texture/cubicmap_atlas.png and /dev/null differ diff --git a/examples/models/draw_cube_texture/main.go b/examples/models/draw_cube_texture/main.go deleted file mode 100644 index 9ae0ef5..0000000 --- a/examples/models/draw_cube_texture/main.go +++ /dev/null @@ -1,256 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Draw textured cube -* -* Example originally created with raylib 4.5, last time updated with raylib 4.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2022-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - draw cube texture") - - // Define the camera to look into our 3d world - camera := rl.Camera{ - Position: rl.Vector3{ - Y: 10.0, - Z: 10.0, - }, - Target: rl.Vector3{}, - Up: rl.Vector3{Y: 1.0}, - Fovy: 45.0, - Projection: rl.CameraPerspective, - } - - // Load texture to be applied to the cubes sides - texture := rl.LoadTexture("cubicmap_atlas.png") - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - // TODO: Update your variables here - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginMode3D(camera) - - // Draw cube with an applied texture - vec := rl.Vector3{ - X: -2.0, - Y: 2.0, - } - DrawCubeTexture(texture, vec, 2.0, 4.0, 2.0, rl.White) - - // Draw cube with an applied texture, but only a defined rectangle piece of the texture - rec := rl.Rectangle{ - Y: float32(texture.Height) / 2.0, - Width: float32(texture.Width) / 2.0, - Height: float32(texture.Height) / 2.0, - } - vec = rl.Vector3{ - X: 2.0, - Y: 1.0, - } - DrawCubeTextureRec(texture, rec, vec, 2.0, 2.0, 2.0, rl.White) - - rl.DrawGrid(10, 1.0) // Draw a grid - rl.EndMode3D() - rl.DrawFPS(10, 10) - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadTexture(texture) // Unload texture - rl.CloseWindow() // Close window and OpenGL context -} - -// DrawCubeTexture draws a textured cube -// NOTE: Cube position is the center position -func DrawCubeTexture(texture rl.Texture2D, position rl.Vector3, width, height, length float32, color rl.Color) { - x := position.X - y := position.Y - z := position.Z - - // Set desired texture to be enabled while drawing following vertex data - rl.SetTexture(texture.ID) - - // Vertex data transformation can be defined with the commented lines, - // but in this example we calculate the transformed vertex data directly when calling rlVertex3f() - // rl.PushMatrix() - // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) - //rl.Translatef(2.0, 0.0, 0.0) - //rl.Rotatef(45, 0, 1, ) - //rl.Scalef(2.0, 2.0, 2.0) - - rl.Begin(rl.Quads) - rl.Color4ub(color.R, color.G, color.B, color.A) - // Front Face - rl.Normal3f(0.0, 0.0, 1.0) // Normal Pointing Towards Viewer - rl.TexCoord2f(0.0, 0.0) - rl.Vertex3f(x-width/2, y-height/2, z+length/2) // Bottom Left Of The Texture and Quad - rl.TexCoord2f(1.0, 0.0) - rl.Vertex3f(x+width/2, y-height/2, z+length/2) // Bottom Right Of The Texture and Quad - rl.TexCoord2f(1.0, 1.0) - rl.Vertex3f(x+width/2, y+height/2, z+length/2) // Top Right Of The Texture and Quad - rl.TexCoord2f(0.0, 1.0) - rl.Vertex3f(x-width/2, y+height/2, z+length/2) // Top Left Of The Texture and Quad - // Back Face - rl.Normal3f(0.0, 0.0, -1.0) // Normal Pointing Away From Viewer - rl.TexCoord2f(1.0, 0.0) - rl.Vertex3f(x-width/2, y-height/2, z-length/2) // Bottom Right Of The Texture and Quad - rl.TexCoord2f(1.0, 1.0) - rl.Vertex3f(x-width/2, y+height/2, z-length/2) // Top Right Of The Texture and Quad - rl.TexCoord2f(0.0, 1.0) - rl.Vertex3f(x+width/2, y+height/2, z-length/2) // Top Left Of The Texture and Quad - rl.TexCoord2f(0.0, 0.0) - rl.Vertex3f(x+width/2, y-height/2, z-length/2) // Bottom Left Of The Texture and Quad - // Top Face - rl.Normal3f(0.0, 1.0, 0.0) // Normal Pointing Up - rl.TexCoord2f(0.0, 1.0) - rl.Vertex3f(x-width/2, y+height/2, z-length/2) // Top Left Of The Texture and Quad. - rl.TexCoord2f(0.0, 0.0) - rl.Vertex3f(x-width/2, y+height/2, z+length/2) // Bottom Left Of The Texture and Quad - rl.TexCoord2f(1.0, 0.0) - rl.Vertex3f(x+width/2, y+height/2, z+length/2) // Bottom Right Of The Texture and Quad - rl.TexCoord2f(1.0, 1.0) - rl.Vertex3f(x+width/2, y+height/2, z-length/2) // Top Right Of The Texture and Quad Bottom Face - rl.Normal3f(0.0, -1.0, 0.0) // Normal Pointing Down - rl.TexCoord2f(1.0, 1.0) - rl.Vertex3f(x-width/2, y-height/2, z-length/2) // Top Right Of The Texture and Quad - rl.TexCoord2f(0.0, 1.0) - rl.Vertex3f(x+width/2, y-height/2, z-length/2) // Top Left Of The Texture and Quad - rl.TexCoord2f(0.0, 0.0) - rl.Vertex3f(x+width/2, y-height/2, z+length/2) // Bottom Left Of The Texture and Quad - rl.TexCoord2f(1.0, 0.0) - rl.Vertex3f(x-width/2, y-height/2, z+length/2) // Bottom Right Of The Texture and Quad - // Right face - rl.Normal3f(1.0, 0.0, 0.0) // Normal Pointing Right - rl.TexCoord2f(1.0, 0.0) - rl.Vertex3f(x+width/2, y-height/2, z-length/2) // Bottom Right Of The Texture and Quad - rl.TexCoord2f(1.0, 1.0) - rl.Vertex3f(x+width/2, y+height/2, z-length/2) // Top Right Of The Texture and Quad - rl.TexCoord2f(0.0, 1.0) - rl.Vertex3f(x+width/2, y+height/2, z+length/2) // Top Left Of The Texture and Quad - rl.TexCoord2f(0.0, 0.0) - rl.Vertex3f(x+width/2, y-height/2, z+length/2) // Bottom Left Of The Texture and Quad - // Left Face - rl.Normal3f(-1.0, 0.0, 0.0) // Normal Pointing Left - rl.TexCoord2f(0.0, 0.0) - rl.Vertex3f(x-width/2, y-height/2, z-length/2) // Bottom Left Of The Texture and Quad - rl.TexCoord2f(1.0, 0.0) - rl.Vertex3f(x-width/2, y-height/2, z+length/2) // Bottom Right Of The Texture and Quad - rl.TexCoord2f(1.0, 1.0) - rl.Vertex3f(x-width/2, y+height/2, z+length/2) // Top Right Of The Texture and Quad - rl.TexCoord2f(0.0, 1.0) - rl.Vertex3f(x-width/2, y+height/2, z-length/2) // Top Left Of The Texture and Quad - - rl.End() - //rl.PopMatrix() - - rl.SetTexture(0) -} - -// DrawCubeTextureRec draws a cube with texture piece applied to all faces -func DrawCubeTextureRec(texture rl.Texture2D, source rl.Rectangle, position rl.Vector3, width, height, - length float32, color rl.Color) { - - x := position.X - y := position.Y - z := position.Z - - texWidth := float32(texture.Width) - texHeight := float32(texture.Height) - - // Set desired texture to be enabled while drawing following vertex data - rl.SetTexture(texture.ID) - - // We calculate the normalized texture coordinates for the desired texture-source-rectangle - // It means converting from (tex.width, tex.height) coordinates to [0.0f, 1.0f] equivalent - rl.Begin(rl.Quads) - rl.Color4ub(color.R, color.G, color.B, color.A) - - // Front face - rl.Normal3f(0.0, 0.0, 1.0) - rl.TexCoord2f(source.X/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x-width/2, y-height/2, z+length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x+width/2, y-height/2, z+length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, source.Y/texHeight) - rl.Vertex3f(x+width/2, y+height/2, z+length/2) - rl.TexCoord2f(source.X/texWidth, source.Y/texHeight) - rl.Vertex3f(x-width/2, y+height/2, z+length/2) - - // Back face - rl.Normal3f(0.0, 0.0, -1.0) - rl.TexCoord2f((source.X+source.Width)/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x-width/2, y-height/2, z-length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, source.Y/texHeight) - rl.Vertex3f(x-width/2, y+height/2, z-length/2) - rl.TexCoord2f(source.X/texWidth, source.Y/texHeight) - rl.Vertex3f(x+width/2, y+height/2, z-length/2) - rl.TexCoord2f(source.X/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x+width/2, y-height/2, z-length/2) - - // Top face - rl.Normal3f(0.0, 1.0, 0.0) - rl.TexCoord2f(source.X/texWidth, source.Y/texHeight) - rl.Vertex3f(x-width/2, y+height/2, z-length/2) - rl.TexCoord2f(source.X/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x-width/2, y+height/2, z+length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x+width/2, y+height/2, z+length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, source.Y/texHeight) - rl.Vertex3f(x+width/2, y+height/2, z-length/2) - - // Bottom face - rl.Normal3f(0.0, -1.0, 0.0) - rl.TexCoord2f((source.X+source.Width)/texWidth, source.Y/texHeight) - rl.Vertex3f(x-width/2, y-height/2, z-length/2) - rl.TexCoord2f(source.X/texWidth, source.Y/texHeight) - rl.Vertex3f(x+width/2, y-height/2, z-length/2) - rl.TexCoord2f(source.X/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x+width/2, y-height/2, z+length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x-width/2, y-height/2, z+length/2) - - // Right face - rl.Normal3f(1.0, 0.0, 0.0) - rl.TexCoord2f((source.X+source.Width)/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x+width/2, y-height/2, z-length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, source.Y/texHeight) - rl.Vertex3f(x+width/2, y+height/2, z-length/2) - rl.TexCoord2f(source.X/texWidth, source.Y/texHeight) - rl.Vertex3f(x+width/2, y+height/2, z+length/2) - rl.TexCoord2f(source.X/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x+width/2, y-height/2, z+length/2) - - // Left face - rl.Normal3f(-1.0, 0.0, 0.0) - rl.TexCoord2f(source.X/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x-width/2, y-height/2, z-length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, (source.Y+source.Height)/texHeight) - rl.Vertex3f(x-width/2, y-height/2, z+length/2) - rl.TexCoord2f((source.X+source.Width)/texWidth, source.Y/texHeight) - rl.Vertex3f(x-width/2, y+height/2, z+length/2) - rl.TexCoord2f(source.X/texWidth, source.Y/texHeight) - rl.Vertex3f(x-width/2, y+height/2, z-length/2) - - rl.End() - - rl.SetTexture(0) -} diff --git a/examples/models/first_person_maze/cubicmap.png b/examples/models/first_person_maze/cubicmap.png deleted file mode 100644 index 392dbf2..0000000 Binary files a/examples/models/first_person_maze/cubicmap.png and /dev/null differ diff --git a/examples/models/first_person_maze/cubicmap_atlas.png b/examples/models/first_person_maze/cubicmap_atlas.png deleted file mode 100644 index 9fc404a..0000000 Binary files a/examples/models/first_person_maze/cubicmap_atlas.png and /dev/null differ diff --git a/examples/models/first_person_maze/main.go b/examples/models/first_person_maze/main.go deleted file mode 100644 index 310e31d..0000000 --- a/examples/models/first_person_maze/main.go +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - first person maze -* -* This example has been created using raylib-go v0.0.0-20220104071325-2f072dc2d259 (https://git.terah.dev/UnrealXR/raylib-go) -* raylib-go is licensed under an unmodified zlib/libpng license (https://git.terah.dev/UnrealXR/raylib-go/blob/master/LICENSE) -* -* Original C version for Raylib 2.5 Copyright (c) 2019 Ramon Santamaria (@raysan5) -* Converted to Go by Michael Redman January 4, 2022 -* -********************************************************************************************/ - -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - // Initialization - //-------------------------------------------------------------------------------------- - var screenWidth int32 = 800 - var screenHeight int32 = 450 - - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze") - - // Define the camera to look into our 3d world - camera := rl.Camera{} - camera.Position = rl.NewVector3(0.2, 0.4, 0.2) - camera.Target = rl.NewVector3(0.0, 0.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 45.0 - camera.Projection = rl.CameraPerspective - - imMap := rl.LoadImage("cubicmap.png") // Load cubicmap image (RAM) - cubicmap := rl.LoadTextureFromImage(imMap) // Convert image to texture to display (VRAM) - mesh := rl.GenMeshCubicmap(*imMap, rl.NewVector3(1.0, 1.0, 1.0)) - model := rl.LoadModelFromMesh(mesh) - - // NOTE: By default each cube is mapped to one part of texture atlas - texture := rl.LoadTexture("cubicmap_atlas.png") // load map texture - model.Materials.GetMap(rl.MapDiffuse).Texture = texture // Set map diffuse texture - // Get map image data to be used for collision detectio - mapPixels := rl.LoadImageColors(imMap) - rl.UnloadImage(imMap) // Unload image from RAM - - mapPosition := rl.NewVector3(-16.0, 0.0, -8.0) // Set model position - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - oldCamPos := camera.Position // Store old camera position - - rl.UpdateCamera(&camera, rl.CameraFirstPerson) // Update camera with first person mode - - // Check player collision (we simplify to 2D collision detection) - playerPos := rl.NewVector2(camera.Position.X, camera.Position.Z) - playerRadius := 0.1 // Collision radius (player is modelled as a cylinder for collision) - - playerCellX := (int)(playerPos.X - mapPosition.X + 0.5) - playerCellY := (int)(playerPos.Y - mapPosition.Z + 0.5) - - // Out-of-limits security check - if playerCellX < 0 { - playerCellX = 0 - } else if playerCellX >= int(cubicmap.Width) { - playerCellX = int(cubicmap.Width) - 1 - } - - if playerCellY < 0 { - playerCellY = 0 - } else if playerCellY >= int(cubicmap.Height) { - playerCellY = int(cubicmap.Height) - 1 - } - - // Check map collisions using image data and player position - // TODO: Improvement: Just check player surrounding cells for collision - for y := 0; y < int(cubicmap.Height); y++ { - for x := 0; x < int(cubicmap.Width); x++ { - // Collision: white pixel, only check R channel - if mapPixels[y*int(cubicmap.Width)+x].R == 255 && (rl.CheckCollisionCircleRec(playerPos, float32(playerRadius), rl.NewRectangle(float32(mapPosition.X-0.5+float32(x)), float32(mapPosition.Z-0.5+float32(y)), 1.0, 1.0))) { - // Collision detected, reset camera position - camera.Position = oldCamPos - } - } - } - //---------------------------------------------------------------------------------- - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginMode3D(camera) - rl.DrawModel(model, mapPosition, 1.0, rl.White) // Draw maze map - rl.EndMode3D() - rl.DrawTextureEx(cubicmap, rl.NewVector2(float32(rl.GetScreenWidth())-float32(cubicmap.Width)*4.0-20, 20.0), 0.0, 4.0, rl.White) - rl.DrawRectangleLines(int32(rl.GetScreenWidth())-cubicmap.Width*4-20, 20, cubicmap.Width*4, cubicmap.Height*4, rl.Green) - // Draw player position radar - rl.DrawRectangle(int32(rl.GetScreenWidth()-int(cubicmap.Width*4)-20+(playerCellX*4)), int32(20+playerCellY*4), 4, 4, rl.Red) - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.UnloadTexture(cubicmap) // Unload cubicmap texture - rl.UnloadTexture(texture) // Unload map texture - rl.UnloadModel(model) // Unload map model - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} diff --git a/examples/models/geometric_shapes/main.go b/examples/models/geometric_shapes/main.go index bf78869..31a6397 100644 --- a/examples/models/geometric_shapes/main.go +++ b/examples/models/geometric_shapes/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/models/gltf_loading/main.go b/examples/models/gltf_loading/main.go deleted file mode 100644 index 79505ab..0000000 --- a/examples/models/gltf_loading/main.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - gltf loading") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(5.0, 5.0, 5.0) - camera.Target = rl.NewVector3(0.0, 2.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 45.0 - camera.Projection = rl.CameraPerspective - - model := rl.LoadModel("robot.glb") - - animIndex := 0 - animCurrentFrame := 0 - - modelAnims := rl.LoadModelAnimations("robot.glb") - - position := rl.NewVector3(0, 0, 0) - rl.DisableCursor() - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.UpdateCamera(&camera, rl.CameraOrbital) - - if rl.IsKeyPressed(rl.KeyUp) { - animIndex++ - if animIndex >= len(modelAnims) { - animIndex = 0 - } - } - if rl.IsKeyPressed(rl.KeyDown) { - animIndex-- - if animIndex < 0 { - animIndex = len(modelAnims) - 1 - } - } - - animPlaying := modelAnims[animIndex] - animCurrentFrame = (animCurrentFrame + 1) % int(animPlaying.FrameCount) - rl.UpdateModelAnimation(model, animPlaying, int32(animCurrentFrame)) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.DrawModel(model, position, 0.8, rl.White) - - rl.EndMode3D() - - rl.DrawText(fmt.Sprintf("current animation: %s [%d]", animPlaying.GetName(), animIndex), 10, 10, 10, rl.Black) - rl.DrawText("UP/DOWN ARROW KEYS CHANGE ANIMATION", 10, 30, 10, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadModel(model) - - rl.CloseWindow() -} diff --git a/examples/models/gltf_loading/robot.glb b/examples/models/gltf_loading/robot.glb deleted file mode 100644 index 549011e..0000000 Binary files a/examples/models/gltf_loading/robot.glb and /dev/null differ diff --git a/examples/models/heightmap/main.go b/examples/models/heightmap/main.go index 896ffd8..3e7f9b9 100644 --- a/examples/models/heightmap/main.go +++ b/examples/models/heightmap/main.go @@ -3,7 +3,7 @@ package main import ( //"fmt" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -30,12 +30,14 @@ func main() { rl.UnloadImage(image) // Unload heightmap image from RAM, already uploaded to VRAM + rl.SetCameraMode(camera, rl.CameraOrbital) // Set an orbital camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { // Update - rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode + rl.UpdateCamera(&camera) // Update camera // Draw diff --git a/examples/models/m3d_loading/cesium_man.m3d b/examples/models/m3d_loading/cesium_man.m3d deleted file mode 100644 index ddf9f50..0000000 Binary files a/examples/models/m3d_loading/cesium_man.m3d and /dev/null differ diff --git a/examples/models/m3d_loading/main.go b/examples/models/m3d_loading/main.go deleted file mode 100644 index d979a2c..0000000 --- a/examples/models/m3d_loading/main.go +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Load models M3D -* -* Example originally created with raylib 4.5, last time updated with raylib 4.5 -* -* Example contributed by bzt (@bztsrc) and reviewed by Ramon Santamaria (@raysan5) -* -* NOTES: -* - Model3D (M3D) fileformat specs: https://gitlab.com/bztsrc/model3d -* - Bender M3D exported: https://gitlab.com/bztsrc/model3d/-/tree/master/blender -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2022-2024 bzt (@bztsrc) -* -********************************************************************************************/ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - // Initialization - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - M3D model loading") - - // Define the camera to look into our 3d world - camera := rl.Camera{ - Position: rl.NewVector3(1.5, 1.5, 1.5), - Target: rl.NewVector3(0.0, 0.4, 0.0), - Up: rl.NewVector3(0.0, 1.0, 0.0), - Fovy: 45.0, - Projection: rl.CameraPerspective, - } - - position := rl.NewVector3(0.0, 0.0, 0.0) - - modelFileName := "cesium_man.m3d" - drawMesh := true - drawSkeleton := true - animPlaying := false // Store anim state, what to draw - - // Load model - model := rl.LoadModel(modelFileName) - - // Load animations - - animFrameCounter := 0 - animID := 0 - anims := rl.LoadModelAnimations(modelFileName) - animsCount := int32(len(anims)) - - rl.DisableCursor() - rl.SetTargetFPS(60) - - // Main game loop - for !rl.WindowShouldClose() { - // Update - rl.UpdateCamera(&camera, rl.CameraFirstPerson) - - if animsCount > 0 { - // Play animation when space bar is held down (or step one frame with N) - if rl.IsKeyDown(rl.KeySpace) || rl.IsKeyPressed(rl.KeyN) { - animFrameCounter++ - if animFrameCounter >= int(anims[animID].FrameCount) { - animFrameCounter = 0 - } - rl.UpdateModelAnimation(model, anims[animID], int32(animFrameCounter)) - animPlaying = true - } - - // Select animation by pressing C - if rl.IsKeyPressed(rl.KeyC) { - animFrameCounter = 0 - animID++ - if animID >= int(animsCount) { - animID = 0 - } - rl.UpdateModelAnimation(model, anims[animID], 0) - animPlaying = true - } - } - - // Toggle skeleton drawing - if rl.IsKeyPressed(rl.KeyB) { - drawSkeleton = !drawSkeleton - } - - // Toggle mesh drawing - if rl.IsKeyPressed(rl.KeyM) { - drawMesh = !drawMesh - } - - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - // Draw 3d model with texture - if drawMesh { - rl.DrawModel(model, position, 1.0, rl.White) - } - - // Draw the animated skeleton - if drawSkeleton { - modelBones := model.GetBones() - modelPoses := model.GetBindPose() - anim := anims[animID] - animBones := anim.GetBones() - for bone := 0; bone < int(model.BoneCount)-1; bone++ { - if !animPlaying || animsCount == 0 { - // Display the bind-pose skeleton - rl.DrawCube(modelPoses[bone].Translation, 0.04, 0.04, 0.04, rl.Red) - if modelBones[bone].Parent >= 0 { - rl.DrawLine3D(modelPoses[bone].Translation, modelPoses[modelBones[bone].Parent].Translation, rl.Red) - } - } else { - // // Display the frame-pose skeleton - pos := anim.GetFramePose(animFrameCounter, bone).Translation - rl.DrawCube(pos, 0.05, 0.05, 0.05, rl.Red) - if animBones[bone].Parent >= 0 { - endPos := anim.GetFramePose(animFrameCounter, int(animBones[bone].Parent)).Translation - rl.DrawLine3D(pos, endPos, rl.Red) - } - } - } - } - - rl.DrawGrid(10, 1.0) - - rl.EndMode3D() - - rl.DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, screenHeight-80, 10, rl.Maroon) - rl.DrawText("PRESS N to STEP ONE ANIMATION FRAME", 10, screenHeight-60, 10, rl.DarkGray) - rl.DrawText("PRESS C to CYCLE THROUGH ANIMATIONS", 10, screenHeight-40, 10, rl.DarkGray) - rl.DrawText("PRESS M to toggle MESH, B to toggle SKELETON DRAWING", 10, screenHeight-20, 10, rl.DarkGray) - rl.DrawText("(c) CesiumMan model by KhronosGroup", screenWidth-210, screenHeight-20, 10, rl.Gray) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadModelAnimations(anims) - rl.UnloadModel(model) - rl.CloseWindow() -} diff --git a/examples/models/mesh_generation/main.go b/examples/models/mesh_generation/main.go deleted file mode 100644 index 9f1d0ec..0000000 --- a/examples/models/mesh_generation/main.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - numModels := 9 - - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(10.0, 5.0, 10.0) - camera.Target = rl.NewVector3(0.0, 0.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 45.0 - camera.Projection = rl.CameraPerspective - - checked := rl.GenImageChecked(2, 2, 1, 1, rl.Black, rl.Red) - texture := rl.LoadTextureFromImage(checked) - rl.UnloadImage(checked) - - models := make([]rl.Model, numModels) - - models[0] = rl.LoadModelFromMesh(rl.GenMeshPlane(2, 2, 4, 3)) - models[1] = rl.LoadModelFromMesh(rl.GenMeshCube(2, 1, 2)) - models[2] = rl.LoadModelFromMesh(rl.GenMeshSphere(2, 32, 32)) - models[3] = rl.LoadModelFromMesh(rl.GenMeshHemiSphere(2, 16, 16)) - models[4] = rl.LoadModelFromMesh(rl.GenMeshCylinder(1, 2, 16)) - models[5] = rl.LoadModelFromMesh(rl.GenMeshTorus(0.25, 4, 16, 32)) - models[6] = rl.LoadModelFromMesh(rl.GenMeshKnot(1, 2, 16, 128)) - models[7] = rl.LoadModelFromMesh(rl.GenMeshPoly(5, 2)) - models[8] = rl.LoadModelFromMesh(GenMeshCustom()) - - for i := 0; i < numModels; i++ { - rl.SetMaterialTexture(models[i].Materials, rl.MapDiffuse, texture) - } - - position := rl.Vector3Zero() - - currentModel := 0 - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.UpdateCamera(&camera, rl.CameraOrbital) - - if rl.IsKeyPressed(rl.KeyUp) { - currentModel = (currentModel + 1) % numModels // Cycle between the textures - } - if rl.IsKeyPressed(rl.KeyDown) { - // Adding numModels here is necessary to avoid a crash - // where the golang % (modulus) operator, doesn't work as - // one might expect for negative numbers. - currentModel = (currentModel + numModels - 1) % numModels // Cycle between the textures - } - if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { - currentModel = (currentModel + 1) % numModels // Cycle between the textures - } - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.DrawModel(models[currentModel], position, 1, rl.White) - rl.DrawGrid(10, 1) - - rl.EndMode3D() - - rl.DrawRectangle(10, 10, 310, 50, rl.Fade(rl.SkyBlue, 0.5)) - rl.DrawRectangleLines(10, 10, 310, 50, rl.Fade(rl.DarkBlue, 0.5)) - rl.DrawText("UP/DOWN ARROW KEY OR LEFT MOUSE", 20, 20, 10, rl.Blue) - rl.DrawText("BUTTON TO CHANGE MODELS", 20, 40, 10, rl.Blue) - - txt := "PLANE" - switch currentModel { - case 1: - txt = "CUBE" - case 2: - txt = "SPHERE" - case 3: - txt = "HEMISPHERE" - case 4: - txt = "CYLINDER" - case 5: - txt = "TORUS" - case 6: - txt = "KNOT" - case 7: - txt = "POLY" - case 8: - txt = "Custom (triangle)" - } - txtlen := rl.MeasureText(txt, 20) - rl.DrawText(txt, screenWidth/2-txtlen/2, 10, 20, rl.DarkBlue) - - rl.EndDrawing() - } - - rl.UnloadTexture(texture) - // Custom models meshes needs to be - // cleared manually - clearCustomMesh(models[8]) - for i := 0; i < numModels; i++ { - rl.UnloadModel(models[i]) - } - - rl.CloseWindow() -} - -func clearCustomMesh(model rl.Model) { - // Vertices, Normals and Texcoords of your CUSTOM mesh are Go slices. - // UnloadModel calls UnloadMesh for every mesh and UnloadMesh tries - // to free your Go slices. This will panic because it cannot free - // Go slices. Free() is a C function and it expects to free C memory - // and not a Go slice. So clear the slices manually like this. - model.Meshes.Vertices = nil - model.Meshes.Normals = nil - model.Meshes.Texcoords = nil -} - -// GenMeshCustom generates a simple triangle mesh from code -func GenMeshCustom() rl.Mesh { - mesh := rl.Mesh{ - TriangleCount: 1, - VertexCount: 3, - } - - var vertices, normals, texcoords []float32 - - // 3 vertices - vertices = addCoord(vertices, 0, 0, 0) - vertices = addCoord(vertices, 1, 0, 2) - vertices = addCoord(vertices, 2, 0, 0) - mesh.Vertices = unsafe.SliceData(vertices) - - // 3 normals - normals = addCoord(normals, 0, 1, 0) - normals = addCoord(normals, 0, 1, 0) - normals = addCoord(normals, 0, 1, 0) - mesh.Normals = unsafe.SliceData(normals) - - // 3 texcoords - texcoords = addCoord(texcoords, 0, 0) - texcoords = addCoord(texcoords, 0.5, 1) - texcoords = addCoord(texcoords, 1, 0) - mesh.Texcoords = unsafe.SliceData(texcoords) - - // Upload mesh data from CPU (RAM) to GPU (VRAM) memory - rl.UploadMesh(&mesh, false) - - return mesh -} - -func addCoord(slice []float32, values ...float32) []float32 { - for _, value := range values { - slice = append(slice, value) - } - return slice -} diff --git a/examples/models/mesh_picking/main.go b/examples/models/mesh_picking/main.go deleted file mode 100644 index fba3e4e..0000000 --- a/examples/models/mesh_picking/main.go +++ /dev/null @@ -1,261 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Mesh picking in 3d mode, ground plane, triangle, mesh -* -* Example originally created with raylib 1.7, last time updated with raylib 4.0 -* -* Example contributed by Joel Davis (@joeld42) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2017-2024 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "math" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -// Program main entry point -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking") - - // Define the camera to look into our 3d world - camera := rl.Camera{ - Position: rl.Vector3{ - X: 20.0, - Y: 20.0, - Z: 20.0, - }, // Camera position - Target: rl.Vector3{Y: 8.0}, // Camera looking at point - Up: rl.Vector3{Y: 1.6}, // Camera up vector (rotation towards target) - Fovy: 45.0, // Camera field-of-view Y - Projection: rl.CameraPerspective, // Camera projection type - } - var ray rl.Ray // Picking ray - - tower := rl.LoadModel("turret.obj") // Load OBJ model - texture := rl.LoadTexture("turret_diffuse.png") // Load model texture - materials := unsafe.Slice(tower.Materials, tower.MaterialCount) - materials[0].GetMap(rl.MapDiffuse).Texture = texture // Set model diffuse texture - - towerPos := rl.Vector3{} // Set model position - meshes := unsafe.Slice(tower.Meshes, tower.MeshCount) - towerBBox := rl.GetMeshBoundingBox(meshes[0]) // Get mesh bounding box - - // Ground quad - g0 := rl.Vector3{ - X: -50.0, - Z: -50.0, - } - g1 := rl.Vector3{ - X: -50.0, - Z: 50.0, - } - g2 := rl.Vector3{ - X: 50.0, - Z: 50.0, - } - g3 := rl.Vector3{ - X: 50.0, - Z: -50.0, - } - - // Test triangle - ta := rl.Vector3{ - X: -25.0, - Y: 0.5, - } - tb := rl.Vector3{ - X: -4.0, - Y: 2.5, - Z: 1.0, - } - tc := rl.Vector3{ - X: -8.0, - Y: 6.5, - } - - bary := rl.Vector3{} - - // Test sphere - sp := rl.Vector3{ - X: -30.0, - Y: 5.0, - Z: 5.0, - } - sr := float32(4.0) - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - if rl.IsCursorHidden() { - rl.UpdateCamera(&camera, rl.CameraFirstPerson) // Update camera - } - // Toggle camera controls - if rl.IsMouseButtonPressed(rl.MouseButtonRight) { - if rl.IsCursorHidden() { - rl.EnableCursor() - } else { - rl.DisableCursor() - } - } - - // Display information about the closest hit - collision := rl.RayCollision{ - Distance: math.MaxFloat32, - Hit: false, - } - hitObjectName := "None" - cursorColor := rl.White - - // Get ray and test against objects - // See issue : https://git.terah.dev/UnrealXR/raylib-go/issues/457 - //ray = rl.GetScreenToWorldRay(rl.GetMousePosition(), camera) - ray = rl.GetMouseRay(rl.GetMousePosition(), camera) - - // Check ray collision against ground quad - groundHitInfo := rl.GetRayCollisionQuad(ray, g0, g1, g2, g3) - - if (groundHitInfo.Hit) && (groundHitInfo.Distance < collision.Distance) { - collision = groundHitInfo - cursorColor = rl.Green - hitObjectName = "Ground" - } - - // Check ray collision against test triangle - triHitInfo := rl.GetRayCollisionTriangle(ray, ta, tb, tc) - - if (triHitInfo.Hit) && (triHitInfo.Distance < collision.Distance) { - collision = triHitInfo - cursorColor = rl.Purple - hitObjectName = "Triangle" - - bary = rl.Vector3Barycenter(collision.Point, ta, tb, tc) - } - - // Check ray collision against test sphere - sphereHitInfo := rl.GetRayCollisionSphere(ray, sp, sr) - - if (sphereHitInfo.Hit) && (sphereHitInfo.Distance < collision.Distance) { - collision = sphereHitInfo - cursorColor = rl.Orange - hitObjectName = "Sphere" - } - - // Check ray collision against bounding box first, before trying the full ray-mesh test - boxHitInfo := rl.GetRayCollisionBox(ray, towerBBox) - - if (boxHitInfo.Hit) && (boxHitInfo.Distance < collision.Distance) { - collision = boxHitInfo - cursorColor = rl.Orange - hitObjectName = "Box" - - // Check ray collision against model meshes - meshHitInfo := rl.RayCollision{} - for m := int32(0); m < tower.MeshCount; m++ { - // NOTE: We consider the model.transform for the collision check, but - // it can be checked against any transform Matrix, used when checking against same - // model drawn multiple times with multiple transforms - meshHitInfo = rl.GetRayCollisionMesh(ray, meshes[m], tower.Transform) - if meshHitInfo.Hit { - // Save the closest hit mesh - if (!collision.Hit) || (collision.Distance > meshHitInfo.Distance) { - collision = meshHitInfo - } - - break // Stop once one mesh collision is detected, the colliding mesh is m - } - } - - if meshHitInfo.Hit { - collision = meshHitInfo - cursorColor = rl.Orange - hitObjectName = "Mesh" - } - } - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginMode3D(camera) - - // Draw the tower - // WARNING: If scale is different from 1.0f, - // not considered by GetRayCollisionModel() - rl.DrawModel(tower, towerPos, 1.0, rl.White) - - // Draw the test triangle - rl.DrawLine3D(ta, tb, rl.Purple) - rl.DrawLine3D(tb, tc, rl.Purple) - rl.DrawLine3D(tc, ta, rl.Purple) - - // Draw the test sphere - rl.DrawSphereWires(sp, sr, 8, 8, rl.Purple) - - // Draw the mesh bbox if we hit it - if boxHitInfo.Hit { - rl.DrawBoundingBox(towerBBox, rl.Lime) - } - - // If we hit something, draw the cursor at the hit point - if collision.Hit { - rl.DrawCube(collision.Point, 0.3, 0.3, 0.3, cursorColor) - rl.DrawCubeWires(collision.Point, 0.3, 0.3, 0.3, rl.Red) - - normalEnd := rl.Vector3{} - normalEnd.X = collision.Point.X + collision.Normal.X - normalEnd.Y = collision.Point.Y + collision.Normal.Y - normalEnd.Z = collision.Point.Z + collision.Normal.Z - - rl.DrawLine3D(collision.Point, normalEnd, rl.Red) - } - - rl.DrawRay(ray, rl.Maroon) - rl.DrawGrid(10, 10.0) - - rl.EndMode3D() - - // Draw some debug GUI text - rl.DrawText(fmt.Sprintf("Hit Object: %s", hitObjectName), 10, 50, 10, rl.Black) - - if collision.Hit { - ypos := int32(70) - rl.DrawText(fmt.Sprintf("Distance: %3.2f", collision.Distance), 10, ypos, 10, rl.Black) - rl.DrawText(Vec2Str("Hit Pos : %3.2f %3.2f %3.2f", collision.Point), 10, ypos+15, 10, rl.Black) - rl.DrawText(Vec2Str("Hit Norm: %3.2f %3.2f %3.2f", collision.Normal), 10, ypos+30, 10, rl.Black) - if triHitInfo.Hit && hitObjectName == "Triangle" { - rl.DrawText(Vec2Str("Barycenter: %3.2f %3.2f %3.2f", bary), 10, ypos+45, 10, rl.Black) - } - } - - rl.DrawText("Right click mouse to toggle camera controls", 10, 430, 10, rl.Gray) - rl.DrawText("(c) Turret 3D model by Alberto Cano", screenWidth-200, screenHeight-20, 10, rl.Gray) - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadModel(tower) // Unload model - rl.UnloadTexture(texture) // Unload texture - - rl.CloseWindow() // Close window and OpenGL context -} - -func Vec2Str(format string, vec rl.Vector3) string { - return fmt.Sprintf(format, vec.X, vec.Y, vec.Z) -} diff --git a/examples/models/mesh_picking/turret.obj b/examples/models/mesh_picking/turret.obj deleted file mode 100644 index bf7caac..0000000 --- a/examples/models/mesh_picking/turret.obj +++ /dev/null @@ -1,1888 +0,0 @@ -# (c) 2018 Medieval Assets Pack by Alberto Cano -# Licensed as Creative Commons Attribution-NonCommercial 4.0 - -# -# object turret -# - -v 0.0000 13.3010 3.5973 -v 0.0000 12.1596 2.3386 -v 2.5639 12.1596 2.3386 -v 3.4913 13.3010 3.5973 -v 3.5203 14.0462 3.0738 -v 3.9444 14.0450 3.1421 -v 3.9444 14.0369 -0.0000 -v 3.4351 14.0369 -0.0000 -v 3.4352 14.0462 2.9719 -v 3.3643 13.3303 2.9127 -v 0.0000 13.3303 2.9127 -v 0.0000 13.3010 2.9740 -v 3.4352 13.3010 2.9740 -v 0.0000 14.0462 2.9719 -v 3.9444 13.2918 -0.0000 -v 3.9444 13.2998 3.1441 -v 3.4913 14.0462 3.5952 -v 3.3643 13.3303 -0.0000 -v 0.0000 13.3303 -0.0000 -v 0.0000 14.0462 3.5952 -v 2.5639 12.1504 -0.0000 -v 3.4352 13.2918 -0.0000 -v 3.5237 14.9316 3.0740 -v 3.9478 14.9305 3.1422 -v 3.4947 14.9316 3.5953 -v 3.5271 16.4764 1.4274 -v 3.9512 16.4752 1.4274 -v 3.9512 15.9080 2.0774 -v 3.5271 15.9092 2.0092 -v 1.8327 16.4815 3.5953 -v 1.8617 16.4815 3.0742 -v 2.5117 15.9086 3.0742 -v 2.4725 15.9086 3.5953 -v 3.9512 16.4757 3.1424 -v 3.4981 16.4769 3.5955 -v 3.5271 16.4769 3.0742 -v 2.5639 12.1596 -2.3386 -v 0.0000 12.1596 -2.3386 -v 0.0000 13.3010 -3.5973 -v 3.4913 13.3010 -3.5973 -v 3.5203 14.0462 -3.0738 -v 3.4351 14.0462 -2.9720 -v 3.9444 14.0450 -3.1421 -v 0.0000 13.3010 -2.9740 -v 0.0000 13.3303 -2.9127 -v 3.3643 13.3303 -2.9127 -v 3.4352 13.3010 -2.9740 -v 0.0000 14.0462 -2.9719 -v 3.9444 13.2998 -3.1441 -v 3.4913 14.0462 -3.5952 -v 0.0000 14.0462 -3.5952 -v 3.9478 14.9305 -3.1422 -v 3.5237 14.9316 -3.0740 -v 3.4947 14.9316 -3.5953 -v 3.9512 15.9080 -2.0774 -v 3.9512 16.4752 -1.4274 -v 3.5271 16.4764 -1.4274 -v 3.5271 15.9092 -2.0092 -v 2.5117 15.9086 -3.0742 -v 1.8617 16.4815 -3.0742 -v 1.8327 16.4815 -3.5954 -v 2.4725 15.9086 -3.5953 -v 3.4981 16.4769 -3.5955 -v 3.9512 16.4757 -3.1424 -v 3.5271 16.4769 -3.0742 -v -2.5639 12.1596 2.3386 -v -3.4913 13.3010 3.5973 -v -3.5203 14.0462 3.0738 -v -3.4351 14.0462 2.9720 -v -3.4351 14.0369 0.0000 -v -3.9444 14.0369 0.0000 -v -3.9444 14.0450 3.1421 -v -3.3643 13.3303 2.9127 -v -3.4351 13.3010 2.9740 -v -3.9444 13.2918 0.0000 -v -3.9444 13.2998 3.1441 -v -3.4913 14.0462 3.5952 -v -3.3643 13.3303 0.0000 -v -2.5639 12.1504 0.0000 -v -3.4351 13.2918 0.0000 -v -3.9478 14.9305 3.1422 -v -3.5237 14.9316 3.0740 -v -3.4947 14.9316 3.5954 -v -3.9512 15.9080 2.0774 -v -3.9512 16.4752 1.4274 -v -3.5271 16.4764 1.4274 -v -3.5271 15.9092 2.0092 -v -2.5117 15.9086 3.0742 -v -1.8617 16.4815 3.0742 -v -1.8327 16.4815 3.5954 -v -2.4725 15.9086 3.5953 -v -3.4981 16.4769 3.5955 -v -3.9512 16.4757 3.1424 -v -3.5271 16.4769 3.0742 -v -2.5639 12.1596 -2.3386 -v -3.4913 13.3010 -3.5972 -v -3.5203 14.0462 -3.0738 -v -3.9444 14.0450 -3.1421 -v -3.4351 14.0462 -2.9719 -v -3.3643 13.3303 -2.9127 -v -3.4351 13.3010 -2.9740 -v -3.9444 13.2998 -3.1441 -v -3.4913 14.0462 -3.5952 -v -3.5237 14.9316 -3.0740 -v -3.9478 14.9305 -3.1422 -v -3.4947 14.9316 -3.5953 -v -3.5271 16.4764 -1.4274 -v -3.9512 16.4752 -1.4274 -v -3.9512 15.9080 -2.0774 -v -3.5271 15.9092 -2.0092 -v -1.8327 16.4815 -3.5953 -v -1.8617 16.4815 -3.0742 -v -2.5117 15.9086 -3.0742 -v -2.4725 15.9086 -3.5953 -v -3.9512 16.4757 -3.1424 -v -3.4981 16.4769 -3.5955 -v -3.5271 16.4769 -3.0742 -v 0.1550 14.0277 -3.1544 -v 0.1550 14.0277 -3.5335 -v 0.1550 16.9018 -3.5335 -v 0.1550 16.9018 -3.1544 -v -0.5341 14.0277 -3.5335 -v -0.5341 16.9018 -3.5335 -v -0.5341 14.0277 -3.1544 -v -0.5341 16.9018 -3.1544 -v -3.5170 14.0277 -0.3456 -v -3.8961 14.0277 -0.3456 -v -3.8961 16.9018 -0.3456 -v -3.5170 16.9018 -0.3456 -v -3.8961 14.0277 0.3435 -v -3.8961 16.9018 0.3435 -v -3.5170 14.0277 0.3435 -v -3.5170 16.9018 0.3435 -v -0.3446 14.0277 3.1662 -v -0.3446 14.0277 3.5453 -v -0.3446 16.9018 3.5453 -v -0.3446 16.9018 3.1662 -v 0.3445 14.0277 3.5453 -v 0.3445 16.9018 3.5453 -v 0.3445 14.0277 3.1662 -v 0.3445 16.9018 3.1662 -v 3.5160 14.0277 0.3435 -v 3.8951 14.0277 0.3435 -v 3.8951 16.9018 0.3435 -v 3.5160 16.9018 0.3435 -v 3.8951 14.0277 -0.3456 -v 3.8951 16.9018 -0.3456 -v 3.5160 14.0277 -0.3456 -v 3.5160 16.9018 -0.3456 -v 0.0000 8.6187 2.3766 -v 0.4715 8.6467 2.3766 -v 0.4598 9.7167 2.3896 -v -0.0117 10.0591 2.3896 -v 0.8403 8.5183 2.4160 -v 0.8403 8.5183 2.3077 -v 0.8403 8.6724 2.3077 -v 0.8403 8.6724 2.4160 -v 0.7068 9.8138 2.4290 -v 0.7068 9.8138 2.3207 -v -0.0117 10.3117 2.3207 -v -0.0117 10.3117 2.4290 -v -0.8403 8.6724 2.4160 -v -0.8403 8.6724 2.3077 -v -0.8403 8.5183 2.3077 -v -0.8403 8.5183 2.4160 -v -0.7186 8.5183 2.4160 -v -0.7186 8.5183 2.3077 -v -0.0000 8.4646 2.3077 -v -0.0000 8.4646 2.4160 -v 0.7185 8.5183 2.5347 -v 0.7185 8.6724 2.5347 -v 0.4715 8.6467 2.5347 -v 0.4598 9.7167 2.4290 -v -0.0117 10.0591 2.4290 -v -0.7186 8.6724 2.5347 -v -0.7186 8.5183 2.5347 -v -0.4715 8.6567 2.5347 -v -0.0000 8.4646 2.5347 -v -0.0000 8.6187 2.5347 -v -0.4833 9.7167 2.3896 -v -0.4715 8.6567 2.3766 -v -0.7303 9.8138 2.3207 -v -0.7302 9.8138 2.4290 -v 0.7185 8.5183 2.3077 -v 0.7185 8.5183 2.4160 -v -0.4832 9.7167 2.4290 -v 0.4715 8.6467 2.4160 -v -0.4716 8.6567 2.4160 -v -0.0000 8.6187 2.4160 -v -0.7186 8.6724 2.4160 -v -0.7186 8.6724 2.3077 -v 0.7185 8.6724 2.4160 -v 0.7185 8.6724 2.3077 -v 0.8403 8.5183 2.5347 -v 0.8403 8.6724 2.5347 -v -0.8403 8.6724 2.5347 -v -0.8403 8.5183 2.5347 -v 2.6080 8.6187 -0.0010 -v 2.6080 8.6467 -0.4725 -v 2.6210 9.7167 -0.4608 -v 2.6210 10.0591 0.0107 -v 2.6474 8.5183 -0.8413 -v 2.5392 8.5183 -0.8413 -v 2.5392 8.6724 -0.8413 -v 2.6474 8.6724 -0.8413 -v 2.6604 9.8138 -0.7079 -v 2.5522 9.8138 -0.7078 -v 2.5522 10.3117 0.0107 -v 2.6604 10.3117 0.0107 -v 2.6474 8.6724 0.8393 -v 2.5392 8.6724 0.8393 -v 2.5392 8.5183 0.8393 -v 2.6474 8.5183 0.8393 -v 2.6474 8.5183 0.7175 -v 2.5392 8.5183 0.7175 -v 2.5392 8.4646 -0.0010 -v 2.6474 8.4646 -0.0010 -v 2.7661 8.5183 -0.7195 -v 2.7661 8.6724 -0.7195 -v 2.7661 8.6467 -0.4725 -v 2.6604 9.7167 -0.4609 -v 2.6604 10.0591 0.0107 -v 2.7661 8.6724 0.7175 -v 2.7661 8.5183 0.7175 -v 2.7661 8.6567 0.4705 -v 2.7661 8.4646 -0.0010 -v 2.7661 8.6187 -0.0010 -v 2.6210 9.7167 0.4822 -v 2.6080 8.6567 0.4705 -v 2.5522 9.8138 0.7292 -v 2.6604 9.8138 0.7292 -v 2.5392 8.5183 -0.7196 -v 2.6474 8.5183 -0.7195 -v 2.6604 9.7167 0.4822 -v 2.6474 8.6467 -0.4725 -v 2.6474 8.6567 0.4705 -v 2.6474 8.6187 -0.0010 -v 2.6474 8.6724 0.7175 -v 2.5392 8.6724 0.7175 -v 2.6474 8.6724 -0.7195 -v 2.5392 8.6724 -0.7196 -v 2.7661 8.5183 -0.8413 -v 2.7661 8.6724 -0.8413 -v 2.7661 8.6724 0.8393 -v 2.7661 8.5183 0.8393 -v -2.6159 8.6187 -0.0010 -v -2.6159 8.6467 0.4705 -v -2.6289 9.7167 0.4588 -v -2.6289 10.0591 -0.0127 -v -2.6553 8.5183 0.8393 -v -2.5470 8.5183 0.8393 -v -2.5470 8.6724 0.8393 -v -2.6553 8.6724 0.8393 -v -2.6683 9.8138 0.7058 -v -2.5600 9.8138 0.7058 -v -2.5600 10.3117 -0.0127 -v -2.6683 10.3117 -0.0127 -v -2.6553 8.6724 -0.8413 -v -2.5470 8.6724 -0.8413 -v -2.5470 8.5183 -0.8413 -v -2.6553 8.5183 -0.8413 -v -2.6553 8.5183 -0.7195 -v -2.5470 8.5183 -0.7195 -v -2.5470 8.4646 -0.0010 -v -2.6553 8.4646 -0.0010 -v -2.7740 8.5183 0.7175 -v -2.7740 8.6724 0.7175 -v -2.7740 8.6467 0.4705 -v -2.6683 9.7167 0.4589 -v -2.6683 10.0591 -0.0127 -v -2.7740 8.6724 -0.7195 -v -2.7740 8.5183 -0.7195 -v -2.7740 8.6567 -0.4725 -v -2.7740 8.4646 -0.0010 -v -2.7740 8.6187 -0.0010 -v -2.6289 9.7167 -0.4843 -v -2.6159 8.6567 -0.4725 -v -2.5600 9.8138 -0.7312 -v -2.6683 9.8138 -0.7312 -v -2.5470 8.5183 0.7175 -v -2.6553 8.5183 0.7175 -v -2.6683 9.7167 -0.4842 -v -2.6553 8.6467 0.4705 -v -2.6553 8.6567 -0.4725 -v -2.6553 8.6187 -0.0010 -v -2.6553 8.6724 -0.7195 -v -2.5470 8.6724 -0.7195 -v -2.6553 8.6724 0.7175 -v -2.5470 8.6724 0.7175 -v -2.7740 8.5183 0.8393 -v -2.7740 8.6724 0.8393 -v -2.7740 8.6724 -0.8413 -v -2.7740 8.5183 -0.8413 -v -2.5639 0.0000 -2.3386 -v -2.5639 0.0000 2.3365 -v -2.5639 12.1411 2.3365 -v 2.5639 -0.0000 2.3365 -v 2.5639 12.1411 2.3365 -v 2.5639 -0.0000 -2.3386 -v -3.3222 12.8680 -0.0010 -v -3.3222 12.8680 -2.9994 -v -3.3222 11.9932 -2.9994 -v -3.3222 11.8321 -0.0010 -v -0.0000 12.8680 2.9974 -v -3.3222 12.8680 2.9974 -v -3.3222 11.9932 2.9974 -v -0.0000 11.8320 2.9974 -v 3.3221 12.8680 -0.0010 -v 3.3221 12.8680 2.9974 -v 3.3221 11.9932 2.9974 -v 3.3221 11.8320 -0.0010 -v -0.0000 12.8680 -2.9994 -v 3.3221 12.8680 -2.9994 -v 3.3221 11.9932 -2.9994 -v -0.0000 11.8320 -2.9994 -v -2.5639 11.9932 -2.3386 -v -0.0000 11.8320 -2.3386 -v 2.5639 11.9932 -2.3386 -v 2.5639 11.8321 -0.0010 -v 2.5639 11.9932 2.3365 -v -0.0000 11.8321 2.3365 -v -2.5639 11.9932 2.3365 -v -2.5639 11.8321 -0.0010 -v -2.5639 12.8680 -2.3386 -v -2.5639 12.8680 -0.0010 -v -2.5639 12.8680 2.3365 -v -0.0000 12.8680 2.3365 -v 2.5639 12.8680 2.3365 -v 2.5639 12.8680 -0.0010 -v 2.5639 12.8680 -2.3386 -v -0.0000 12.8680 -2.3386 -v -3.3222 6.6605 -0.0010 -v -3.3222 6.6605 -2.9994 -v -3.3222 5.7858 -2.9994 -v -3.3222 5.6246 -0.0010 -v -0.0000 6.6605 2.9974 -v -3.3222 6.6605 2.9974 -v -3.3222 5.7858 2.9974 -v -0.0000 5.6246 2.9974 -v 3.3221 6.6605 -0.0010 -v 3.3221 6.6605 2.9974 -v 3.3221 5.7858 2.9974 -v 3.3221 5.6246 -0.0010 -v -0.0000 6.6605 -2.9994 -v 3.3221 6.6605 -2.9994 -v 3.3221 5.7858 -2.9994 -v -0.0000 5.6246 -2.9994 -v -2.5639 5.7858 -2.3386 -v -0.0000 5.6246 -2.3386 -v 2.5639 5.7858 -2.3386 -v 2.5639 5.6246 -0.0010 -v 2.5639 5.7858 2.3365 -v -0.0000 5.6246 2.3365 -v -2.5639 5.7858 2.3365 -v -2.5639 5.6246 -0.0010 -v -2.5639 6.6605 -2.3386 -v -2.5639 6.6605 -0.0010 -v -2.5639 6.6605 2.3365 -v -0.0000 6.6605 2.3365 -v 2.5639 6.6605 2.3365 -v 2.5639 6.6605 -0.0010 -v 2.5639 6.6605 -2.3386 -v -0.0000 6.6605 -2.3386 -v -2.6103 9.3882 2.4561 -v -2.6767 9.3882 1.9558 -v -2.9138 6.4859 1.8341 -v -2.9138 6.4859 2.7406 -v -2.9138 12.2904 1.8341 -v -2.9138 12.2904 2.7406 -v -1.9967 6.4859 2.7406 -v -2.0923 9.3882 2.4561 -v -1.9967 11.6821 2.7406 -v -1.9967 6.4859 1.8341 -v -2.1587 9.3882 1.9558 -v -1.9967 11.6821 1.8341 -v -2.6103 9.4353 -2.4582 -v -2.9138 6.5331 -2.7426 -v -2.9138 6.5331 -1.8362 -v -2.6767 9.4353 -1.9578 -v -2.9138 12.3375 -1.8362 -v -2.9138 12.3375 -2.7426 -v -2.0923 9.4353 -2.4581 -v -1.9967 6.5331 -2.7426 -v -1.9967 11.7293 -2.7426 -v -2.1587 9.4353 -1.9578 -v -1.9967 6.5331 -1.8362 -v -1.9967 11.7293 -1.8362 -v -2.6103 2.9022 -2.4582 -v -2.9138 0.0000 -2.7426 -v -2.9138 0.0000 -1.8362 -v -2.6767 2.9022 -1.9578 -v -2.9138 5.8044 -1.8362 -v -2.9138 5.8044 -2.7426 -v -2.0923 2.9022 -2.4581 -v -1.9967 0.0000 -2.7426 -v -1.9967 6.4231 -2.7426 -v -2.1587 2.9022 -1.9578 -v -1.9967 0.0000 -1.8362 -v -1.9967 6.4231 -1.8362 -v 2.6103 9.4517 2.4561 -v 2.9138 6.5495 2.7406 -v 2.9138 6.5495 1.8341 -v 2.6767 9.4517 1.9558 -v 2.9138 12.3539 1.8341 -v 2.9138 12.3539 2.7406 -v 2.0923 9.4517 2.4561 -v 1.9967 6.5495 2.7406 -v 1.9967 11.7456 2.7406 -v 2.1587 9.4517 1.9558 -v 1.9967 6.5495 1.8341 -v 1.9967 11.7456 1.8341 -v 2.6103 2.9022 -2.4581 -v 2.6767 2.9022 -1.9578 -v 2.9138 -0.0000 -1.8362 -v 2.9138 -0.0000 -2.7426 -v 2.9138 5.8044 -1.8362 -v 2.9138 5.8044 -2.7426 -v 1.9967 -0.0000 -2.7426 -v 2.0923 2.9022 -2.4581 -v 1.9967 6.4231 -2.7426 -v 1.9967 -0.0000 -1.8362 -v 2.1587 2.9022 -1.9578 -v 1.9967 6.4231 -1.8362 -v 2.6103 9.4353 -2.4582 -v 2.6767 9.4353 -1.9578 -v 2.9138 6.5331 -1.8362 -v 2.9138 6.5331 -2.7427 -v 2.9138 12.3375 -1.8362 -v 2.9138 12.3375 -2.7427 -v 1.9967 6.5331 -2.7427 -v 2.0923 9.4353 -2.4581 -v 1.9967 11.7293 -2.7427 -v 1.9967 6.5331 -1.8362 -v 2.1587 9.4353 -1.9578 -v 1.9967 11.7293 -1.8362 -v 2.6103 2.9022 2.4561 -v 2.9138 -0.0000 2.7406 -v 2.9138 -0.0000 1.8341 -v 2.6767 2.9022 1.9558 -v 2.9138 5.8044 1.8341 -v 2.9138 5.8044 2.7406 -v 2.0923 2.9022 2.4561 -v 1.9967 -0.0000 2.7406 -v 1.9967 6.4231 2.7406 -v 2.1587 2.9022 1.9558 -v 1.9967 -0.0000 1.8341 -v 1.9967 6.4231 1.8341 -v -2.6103 2.9022 2.4561 -v -2.6767 2.9022 1.9558 -v -2.9138 0.0000 1.8341 -v -2.9138 0.0000 2.7406 -v -2.9138 5.8044 1.8341 -v -2.9138 5.8044 2.7406 -v -1.9967 0.0000 2.7406 -v -2.0923 2.9022 2.4561 -v -1.9967 6.4231 2.7406 -v -1.9967 0.0000 1.8341 -v -2.1587 2.9022 1.9558 -v -1.9967 6.4231 1.8341 -v -1.5453 5.6703 -3.5469 -v -1.5453 7.5835 -3.4309 -v -0.7727 7.5835 -3.4309 -v -0.7727 4.7854 -3.5469 -v -1.5453 9.4968 -3.2987 -v -0.7727 9.4968 -3.2987 -v -1.5453 11.4101 -3.3804 -v -0.7727 11.4101 -3.3804 -v -1.5453 13.3234 -3.5469 -v -0.7727 13.3234 -3.5469 -v -0.0000 7.5835 -3.4309 -v -0.0000 4.2830 -3.5469 -v -0.0000 9.4968 -3.2987 -v -0.0000 11.4101 -3.3804 -v -0.0000 13.3234 -3.5469 -v 0.7726 7.5835 -3.4309 -v 0.7726 4.7854 -3.5469 -v 0.7726 9.4968 -3.2987 -v 0.7726 11.4101 -3.3804 -v 0.7726 13.3234 -3.5469 -v 1.5453 7.5835 -3.4309 -v 1.5453 5.6702 -3.5469 -v 1.5453 9.4968 -3.2987 -v 1.5453 11.4101 -3.3804 -v 1.5453 13.3234 -3.5469 -v 0.0000 23.5750 -0.0000 -v -4.1897 16.4768 -3.9339 -v -4.1897 16.4768 3.9339 -v 4.1897 16.4768 3.9339 -v 4.1897 16.4768 -3.9339 -v -1.2971 3.7738 -2.1572 -v -1.2971 3.7738 -2.6666 -v -1.7173 3.6544 -2.6666 -v -1.7173 3.6544 -2.1572 -v -1.2971 -0.0000 -2.6666 -v -1.2971 3.3171 -2.6666 -v -1.2971 3.3171 -2.4156 -v -1.2971 -0.0000 -2.4156 -v -1.7173 -0.0000 -2.6666 -v -1.7173 3.3171 -2.6666 -v -1.7173 -0.0000 -2.1572 -v -1.7173 3.3171 -2.1572 -v 1.2970 3.7738 -2.6666 -v 1.2970 3.7738 -2.1572 -v 1.7173 3.6544 -2.1572 -v 1.7173 3.6544 -2.6666 -v 1.2970 -0.0000 -2.4156 -v 1.2970 3.3171 -2.4156 -v 1.2970 3.3171 -2.6666 -v 1.2970 -0.0000 -2.6666 -v 1.7173 -0.0000 -2.6666 -v 1.7173 3.3171 -2.6666 -v 1.7173 3.3171 -2.1572 -v 1.7173 -0.0000 -2.1572 -v -0.0000 4.3176 -2.6666 -v -0.0000 4.3176 -2.1572 -v -0.0000 3.7437 -2.6666 -v -0.0000 3.7437 -2.4156 -v -0.0000 -0.0000 -2.4156 -# 518 vertices - -vn 0.0000 -0.7408 0.6718 -vn 0.0016 1.0000 -0.0028 -vn -0.0000 0.9024 0.4309 -vn 0.0000 -0.0028 -1.0000 -vn 1.0000 0.0000 -0.0000 -vn 0.4189 -0.8046 0.4210 -vn 0.7071 0.0020 0.7071 -vn -0.0000 1.0000 -0.0000 -vn 0.0000 0.0028 1.0000 -vn 0.6366 -0.7712 0.0024 -vn 0.4322 0.9018 -0.0014 -vn -1.0000 -0.0000 0.0000 -vn 0.1589 -0.0004 -0.9873 -vn -0.9985 0.0039 -0.0555 -vn 0.7071 -0.0029 0.7071 -vn 0.0524 -0.7346 -0.6765 -vn -0.6635 -0.7469 -0.0434 -vn 0.7071 -0.0016 0.7071 -vn -1.0000 0.0014 -0.0007 -vn 1.0000 -0.0014 0.0007 -vn 0.1062 -0.7327 -0.6723 -vn -0.0001 -0.0001 1.0000 -vn -0.0000 0.0001 -1.0000 -vn -0.6920 -0.7204 -0.0452 -vn 0.0000 -0.7408 -0.6718 -vn 0.0016 1.0000 0.0028 -vn -0.0000 0.9024 -0.4309 -vn 0.0000 -0.0028 1.0000 -vn 0.4189 -0.8046 -0.4210 -vn 0.7071 0.0020 -0.7071 -vn -0.0000 1.0000 0.0000 -vn -0.0000 0.0028 -1.0000 -vn 0.6366 -0.7712 -0.0024 -vn 0.4322 0.9018 0.0014 -vn 0.1589 -0.0004 0.9873 -vn -0.9985 0.0039 0.0555 -vn 0.7071 -0.0029 -0.7071 -vn 0.0524 -0.7346 0.6765 -vn -0.6635 -0.7469 0.0434 -vn 0.7071 -0.0016 -0.7071 -vn -1.0000 0.0014 0.0007 -vn 1.0000 -0.0014 -0.0007 -vn 0.1062 -0.7327 0.6723 -vn -0.0001 -0.0001 -1.0000 -vn -0.0000 0.0001 1.0000 -vn -0.6920 -0.7204 0.0452 -vn -0.0000 -0.7408 0.6718 -vn -0.0016 1.0000 -0.0028 -vn 0.0000 0.9024 0.4309 -vn -0.0000 -0.0028 -1.0000 -vn -1.0000 0.0000 0.0000 -vn -0.4189 -0.8046 0.4210 -vn -0.7071 0.0020 0.7071 -vn 0.0000 1.0000 -0.0000 -vn -0.6366 -0.7712 0.0024 -vn -0.4322 0.9018 -0.0014 -vn -0.4321 0.9018 -0.0014 -vn 1.0000 -0.0000 -0.0000 -vn -0.1589 -0.0004 -0.9873 -vn 0.9985 0.0039 -0.0555 -vn -0.7071 -0.0029 0.7071 -vn -0.0524 -0.7346 -0.6765 -vn 0.6635 -0.7469 -0.0434 -vn -0.7071 -0.0016 0.7071 -vn 1.0000 0.0014 -0.0007 -vn -1.0000 -0.0014 0.0007 -vn -0.1062 -0.7327 -0.6723 -vn 0.0001 -0.0001 1.0000 -vn 0.0000 0.0001 -1.0000 -vn 0.6920 -0.7204 -0.0452 -vn -0.0000 -0.7408 -0.6718 -vn -0.0016 1.0000 0.0028 -vn 0.0000 0.9024 -0.4309 -vn -0.0000 -0.0028 1.0000 -vn -0.4189 -0.8046 -0.4210 -vn -0.7071 0.0020 -0.7071 -vn 0.0000 1.0000 0.0000 -vn -0.6366 -0.7712 -0.0024 -vn -0.4321 0.9018 0.0014 -vn -0.4322 0.9018 0.0014 -vn -0.1589 -0.0004 0.9873 -vn 0.9985 0.0039 0.0555 -vn -0.7071 -0.0029 -0.7071 -vn -0.0524 -0.7346 0.6765 -vn 0.6635 -0.7469 0.0434 -vn -0.7071 -0.0016 -0.7071 -vn 1.0000 0.0014 0.0007 -vn -1.0000 -0.0014 -0.0007 -vn -0.1062 -0.7327 0.6723 -vn 0.0001 -0.0001 -1.0000 -vn 0.0000 0.0001 1.0000 -vn 0.6920 -0.7204 0.0452 -vn -0.0000 0.0000 -1.0000 -vn 0.0000 0.0000 1.0000 -vn -0.0035 -0.0104 0.9999 -vn 1.0000 -0.0000 -0.0002 -vn 0.5696 0.8219 -0.0001 -vn -0.0745 -0.9972 0.0000 -vn -0.0000 -0.0000 1.0000 -vn -0.0000 0.0000 1.0000 -vn 0.0033 -0.0104 0.9999 -vn -0.5696 0.8219 0.0001 -vn 0.0745 -0.9972 0.0000 -vn 0.0000 -0.0000 1.0000 -vn -0.9999 -0.0109 0.0008 -vn -0.5875 -0.8092 0.0009 -vn 0.5875 -0.8092 -0.0008 -vn 0.9999 0.0111 -0.0004 -vn 0.0803 0.9968 0.0001 -vn -0.0593 0.9982 -0.0000 -vn -0.0027 -0.0118 0.9999 -vn -0.9999 -0.0102 0.0001 -vn 0.9999 0.0103 -0.0002 -vn 0.0029 -0.0117 0.9999 -vn 1.0000 -0.0000 0.0001 -vn -0.1034 0.9946 0.0000 -vn -0.0593 0.9982 0.0000 -vn 0.0803 0.9968 -0.0000 -vn 0.0634 0.9980 -0.0000 -vn -1.0000 0.0000 0.0001 -vn -0.0000 -1.0000 0.0000 -vn 0.0000 -1.0000 0.0000 -vn 0.0000 -1.0000 -0.0000 -vn -0.0001 0.0000 1.0000 -vn 0.9999 -0.0104 0.0035 -vn -0.0001 0.0000 -1.0000 -vn -0.0001 0.8219 -0.5696 -vn -0.0000 -0.9972 0.0745 -vn 1.0000 -0.0000 0.0000 -vn 0.9999 -0.0104 -0.0034 -vn 0.0001 0.8219 0.5696 -vn 0.0000 -0.9972 -0.0745 -vn 0.0008 -0.0109 0.9999 -vn 0.0008 -0.8092 0.5875 -vn -0.0008 -0.8092 -0.5875 -vn -0.0004 0.0111 -0.9999 -vn 0.0000 0.9968 -0.0803 -vn -0.0000 0.9982 0.0593 -vn 0.9999 -0.0118 0.0027 -vn 0.0001 -0.0102 0.9999 -vn -0.0002 0.0103 -0.9999 -vn 0.9999 -0.0117 -0.0029 -vn 0.0001 -0.0000 -1.0000 -vn 0.0000 0.9946 0.1034 -vn 0.0000 0.9982 0.0593 -vn 0.0000 0.9968 -0.0804 -vn 0.0000 0.9980 -0.0634 -vn 0.0001 -0.0000 1.0000 -vn -0.0000 -0.9972 -0.0745 -vn -0.0000 -1.0000 -0.0000 -vn -0.9999 -0.0104 -0.0035 -vn 0.0002 -0.0000 1.0000 -vn -1.0000 0.0000 -0.0000 -vn -0.9999 -0.0104 0.0033 -vn -0.0008 -0.0109 -0.9999 -vn -0.0009 -0.8092 -0.5875 -vn 0.0007 -0.8092 0.5875 -vn 0.0004 0.0111 0.9999 -vn -0.0001 0.9968 0.0803 -vn 0.0000 0.9982 -0.0593 -vn -0.9999 -0.0118 -0.0027 -vn -0.0001 -0.0102 -0.9999 -vn 0.0002 0.0103 0.9999 -vn -0.9999 -0.0117 0.0029 -vn -0.0001 -0.0000 1.0000 -vn 0.0000 0.9946 -0.1034 -vn 0.0000 0.9968 0.0803 -vn 0.0000 0.9980 0.0634 -vn -1.0000 0.0000 -0.0001 -vn 0.0000 -0.0000 -1.0000 -vn -0.0547 -0.9980 0.0314 -vn -0.0263 -0.9978 -0.0603 -vn 0.0547 -0.9980 -0.0314 -vn 0.0263 -0.9978 0.0603 -vn 0.0547 -0.9980 0.0314 -vn -0.0263 -0.9978 0.0603 -vn -0.0547 -0.9980 -0.0314 -vn 0.0263 -0.9978 -0.0603 -vn -0.9945 0.0939 0.0469 -vn -0.9945 -0.0939 0.0469 -vn 0.0000 0.0976 0.9952 -vn -0.0469 -0.1106 0.9928 -vn 0.9980 0.0430 -0.0471 -vn 0.9974 -0.0543 -0.0471 -vn -0.0000 0.0419 -0.9991 -vn -0.0199 -0.0471 -0.9987 -vn -0.9945 0.0939 -0.0469 -vn -0.9945 -0.0939 -0.0469 -vn 0.0000 0.0976 -0.9952 -vn -0.0469 -0.1106 -0.9928 -vn 0.9980 0.0430 0.0471 -vn 0.9974 -0.0543 0.0471 -vn 0.0000 0.0419 0.9991 -vn -0.0199 -0.0471 0.9987 -vn 0.0375 -0.0870 -0.9955 -vn 0.9983 -0.0354 0.0471 -vn 0.0162 -0.0377 0.9992 -vn 0.9945 0.0939 0.0469 -vn 0.9945 -0.0939 0.0469 -vn -0.0000 0.0976 0.9952 -vn 0.0469 -0.1106 0.9928 -vn -0.9980 0.0430 -0.0471 -vn -0.9974 -0.0543 -0.0471 -vn 0.0199 -0.0471 -0.9987 -vn 0.9945 0.0939 -0.0469 -vn 0.9945 -0.0939 -0.0469 -vn -0.0000 0.0976 -0.9952 -vn -0.0375 -0.0870 -0.9955 -vn -0.9980 0.0430 0.0471 -vn -0.9983 -0.0354 0.0471 -vn -0.0162 -0.0377 0.9992 -vn 0.0469 -0.1106 -0.9928 -vn -0.9974 -0.0543 0.0471 -vn 0.0199 -0.0471 0.9987 -vn -0.0375 -0.0870 0.9955 -vn -0.9983 -0.0354 -0.0471 -vn -0.0162 -0.0377 -0.9992 -vn 0.0375 -0.0870 0.9955 -vn 0.9983 -0.0354 -0.0471 -vn 0.0162 -0.0377 -0.9992 -vn 0.0281 0.0492 -0.9984 -vn 0.0141 0.0591 -0.9982 -vn 0.0101 0.0563 -0.9984 -vn 0.0163 0.0408 -0.9990 -vn -0.0000 0.0132 -0.9999 -vn -0.0000 -0.0647 -0.9979 -vn -0.0000 -0.0867 -0.9962 -vn -0.0000 0.0535 -0.9986 -vn -0.0000 0.0380 -0.9993 -vn -0.0101 0.0563 -0.9984 -vn -0.0163 0.0408 -0.9990 -vn -0.0141 0.0591 -0.9982 -vn -0.0281 0.0492 -0.9984 -vn -0.8612 0.5083 0.0000 -vn 0.0000 0.4847 0.8747 -vn 0.8612 0.5083 -0.0000 -vn -0.0000 0.4847 -0.8747 -vn -0.2731 0.9620 0.0000 -vn 0.2731 0.9620 0.0000 -vn 0.3867 0.9222 0.0000 -vn -0.0000 -0.0000 -1.0000 -vn 0.3124 -0.9499 -0.0000 -vn -0.3867 0.9222 0.0000 -vn -0.3124 -0.9499 0.0000 -# 244 vertex normals - -vt 0.4672 0.7287 0.0000 -vt 0.4672 0.6812 0.0000 -vt 0.5381 0.6812 0.0000 -vt 0.5637 0.7287 0.0000 -vt 0.4511 0.6743 0.0000 -vt 0.4498 0.6669 0.0000 -vt 0.5101 0.6669 0.0000 -vt 0.5101 0.6758 0.0000 -vt 0.4531 0.6758 0.0000 -vt 0.6996 0.8663 0.0000 -vt 0.6083 0.8663 0.0000 -vt 0.6083 0.8881 0.0000 -vt 0.6996 0.8881 0.0000 -vt 0.6083 0.9203 0.0000 -vt 0.6996 0.9203 0.0000 -vt 0.6348 0.6259 0.0000 -vt 0.6348 0.6557 0.0000 -vt 0.5033 0.6557 0.0000 -vt 0.5033 0.6259 0.0000 -vt 0.4860 0.7374 0.0000 -vt 0.4587 0.8045 0.0000 -vt 0.4433 0.8046 0.0000 -vt 0.7663 0.6259 0.0000 -vt 0.7905 0.6258 0.0000 -vt 0.7905 0.6557 0.0000 -vt 0.7664 0.6557 0.0000 -vt 0.5578 0.5104 0.0000 -vt 0.6319 0.5104 0.0000 -vt 0.6319 0.6024 0.0000 -vt 0.5578 0.6024 0.0000 -vt 0.4411 0.6748 0.0000 -vt 0.4531 0.7357 0.0000 -vt 0.4411 0.7357 0.0000 -vt 0.5654 0.8042 0.0000 -vt 0.5654 0.7371 0.0000 -vt 0.5169 0.8663 0.0000 -vt 0.5169 0.8881 0.0000 -vt 0.5169 0.9203 0.0000 -vt 0.7344 0.2540 0.0000 -vt 0.7344 0.2807 0.0000 -vt 0.7215 0.2807 0.0000 -vt 0.7215 0.2540 0.0000 -vt 0.7532 0.2524 0.0000 -vt 0.7532 0.2800 0.0000 -vt 0.7370 0.2800 0.0000 -vt 0.7370 0.2524 0.0000 -vt 0.8440 0.5063 0.0000 -vt 0.8440 0.5248 0.0000 -vt 0.8307 0.5248 0.0000 -vt 0.8307 0.5063 0.0000 -vt 0.7344 0.3486 0.0000 -vt 0.7215 0.3486 0.0000 -vt 0.7215 0.3237 0.0000 -vt 0.7344 0.3237 0.0000 -vt 0.7532 0.3506 0.0000 -vt 0.7370 0.3506 0.0000 -vt 0.7370 0.3238 0.0000 -vt 0.7532 0.3238 0.0000 -vt 0.8440 0.5570 0.0000 -vt 0.8307 0.5570 0.0000 -vt 0.8364 0.5997 0.0000 -vt 0.7950 0.5997 0.0000 -vt 0.8096 0.5854 0.0000 -vt 0.8364 0.5608 0.0000 -vt 0.8663 0.5452 0.0000 -vt 0.8798 0.5570 0.0000 -vt 0.8093 0.5451 0.0000 -vt 0.7959 0.5570 0.0000 -vt 0.8620 0.5854 0.0000 -vt 0.8784 0.5997 0.0000 -vt 0.6756 0.2660 0.0000 -vt 0.6505 0.2660 0.0000 -vt 0.6505 0.4622 0.0000 -vt 0.6756 0.4622 0.0000 -vt 0.6058 0.3002 0.0000 -vt 0.6440 0.3002 0.0000 -vt 0.6440 0.4741 0.0000 -vt 0.6058 0.4741 0.0000 -vt 0.6280 0.0055 0.0000 -vt 0.6545 0.0069 0.0000 -vt 0.6548 0.0671 0.0000 -vt 0.6284 0.0865 0.0000 -vt 0.6000 0.2239 0.0000 -vt 0.6163 0.2239 0.0000 -vt 0.6163 0.2472 0.0000 -vt 0.6000 0.2472 0.0000 -vt 0.6822 0.1033 0.0000 -vt 0.6903 0.1033 0.0000 -vt 0.6903 0.1767 0.0000 -vt 0.6822 0.1767 0.0000 -vt 0.5852 0.2472 0.0000 -vt 0.5852 0.2239 0.0000 -vt 0.6098 0.1405 0.0000 -vt 0.6145 0.1405 0.0000 -vt 0.6140 0.1724 0.0000 -vt 0.6093 0.1724 0.0000 -vt 0.6552 0.1246 0.0000 -vt 0.6681 0.1246 0.0000 -vt 0.6659 0.1454 0.0000 -vt 0.6571 0.0825 0.0000 -vt 0.6723 0.0885 0.0000 -vt 0.6279 0.1193 0.0000 -vt 0.6279 0.1037 0.0000 -vt 0.6681 0.2453 0.0000 -vt 0.6552 0.2453 0.0000 -vt 0.6668 0.2246 0.0000 -vt 0.6507 0.1850 0.0000 -vt 0.6636 0.1850 0.0000 -vt 0.6018 0.0674 0.0000 -vt 0.6015 0.0077 0.0000 -vt 0.6903 0.2501 0.0000 -vt 0.6822 0.2501 0.0000 -vt 0.6135 0.2044 0.0000 -vt 0.6089 0.2043 0.0000 -vt 0.5834 0.0885 0.0000 -vt 0.5987 0.0825 0.0000 -vt 0.6955 0.1208 0.0000 -vt 0.6955 0.0105 0.0000 -vt 0.7028 0.0105 0.0000 -vt 0.7028 0.1208 0.0000 -vt 0.7028 0.1808 0.0000 -vt 0.6955 0.1808 0.0000 -vt 0.7028 0.2409 0.0000 -vt 0.6955 0.2409 0.0000 -vt 0.7028 0.3501 0.0000 -vt 0.6955 0.3501 0.0000 -vt 0.6375 0.2580 0.0000 -vt 0.6331 0.2581 0.0000 -vt 0.6322 0.2120 0.0000 -vt 0.6366 0.2119 0.0000 -vt 0.6312 0.1659 0.0000 -vt 0.6356 0.1658 0.0000 -vt 0.5834 0.0179 0.0000 -vt 0.5987 0.0169 0.0000 -vt 0.6903 0.3459 0.0000 -vt 0.6822 0.3459 0.0000 -vt 0.6822 0.0075 0.0000 -vt 0.6903 0.0075 0.0000 -vt 0.6571 0.0163 0.0000 -vt 0.6723 0.0179 0.0000 -vt 0.6242 0.1418 0.0000 -vt 0.6307 0.1417 0.0000 -vt 0.6247 0.1661 0.0000 -vt 0.6256 0.2121 0.0000 -vt 0.6265 0.2583 0.0000 -vt 0.6335 0.2823 0.0000 -vt 0.6270 0.2824 0.0000 -vt 0.6047 0.1405 0.0000 -vt 0.6042 0.1724 0.0000 -vt 0.6038 0.2043 0.0000 -vt 0.6365 0.1297 0.0000 -vt 0.6367 0.1416 0.0000 -vt 0.6305 0.1298 0.0000 -vt 0.6240 0.1300 0.0000 -vt 0.6681 0.1144 0.0000 -vt 0.6552 0.1144 0.0000 -vt 0.6037 0.2097 0.0000 -vt 0.6088 0.2097 0.0000 -vt 0.6135 0.2098 0.0000 -vt 0.6145 0.1351 0.0000 -vt 0.6099 0.1351 0.0000 -vt 0.6048 0.1351 0.0000 -vt 0.6552 0.2555 0.0000 -vt 0.6681 0.2555 0.0000 -vt 0.6272 0.2943 0.0000 -vt 0.6337 0.2942 0.0000 -vt 0.6395 0.2822 0.0000 -vt 0.6397 0.2940 0.0000 -vt 0.1601 0.2593 0.0000 -vt 0.1601 0.0045 0.0000 -vt 0.2454 0.0045 0.0000 -vt 0.2454 0.2590 0.0000 -vt 0.2838 0.5470 0.0000 -vt 0.2838 0.2690 0.0000 -vt 0.1765 0.2690 0.0000 -vt 0.1765 0.5470 0.0000 -vt 0.1150 0.3564 0.0000 -vt 0.1150 0.0538 0.0000 -vt 0.0116 0.0538 0.0000 -vt 0.0116 0.3569 0.0000 -vt 0.0100 0.6667 0.0000 -vt 0.0100 0.3673 0.0000 -vt 0.1291 0.3673 0.0000 -vt 0.1291 0.6667 0.0000 -vt 0.9942 0.1083 0.0000 -vt 0.9942 0.2099 0.0000 -vt 0.9659 0.2099 0.0000 -vt 0.9607 0.1083 0.0000 -vt 0.9942 0.0068 0.0000 -vt 0.9659 0.0068 0.0000 -vt 0.3004 0.5798 0.0000 -vt 0.2911 0.5701 0.0000 -vt 0.2911 0.6124 0.0000 -vt 0.3004 0.6124 0.0000 -vt 0.3004 0.6450 0.0000 -vt 0.2911 0.6547 0.0000 -vt 0.3334 0.6547 0.0000 -vt 0.3334 0.6450 0.0000 -vt 0.3663 0.6450 0.0000 -vt 0.3757 0.6547 0.0000 -vt 0.3757 0.6124 0.0000 -vt 0.3663 0.6124 0.0000 -vt 0.3663 0.5798 0.0000 -vt 0.3757 0.5701 0.0000 -vt 0.3334 0.5701 0.0000 -vt 0.3334 0.5798 0.0000 -vt 0.2876 0.5671 0.0000 -vt 0.2747 0.5537 0.0000 -vt 0.3334 0.5537 0.0000 -vt 0.3334 0.5671 0.0000 -vt 0.3793 0.5671 0.0000 -vt 0.3922 0.5537 0.0000 -vt 0.3922 0.6125 0.0000 -vt 0.3793 0.6125 0.0000 -vt 0.3793 0.6578 0.0000 -vt 0.3922 0.6712 0.0000 -vt 0.3334 0.6712 0.0000 -vt 0.3334 0.6578 0.0000 -vt 0.2876 0.6578 0.0000 -vt 0.2747 0.6712 0.0000 -vt 0.2747 0.6125 0.0000 -vt 0.2876 0.6125 0.0000 -vt 0.9513 0.1060 0.0000 -vt 0.9513 0.0044 0.0000 -vt 0.9230 0.0044 0.0000 -vt 0.9178 0.1060 0.0000 -vt 0.9097 0.1060 0.0000 -vt 0.9097 0.0044 0.0000 -vt 0.8814 0.0044 0.0000 -vt 0.8762 0.1060 0.0000 -vt 0.8814 0.2076 0.0000 -vt 0.9097 0.2076 0.0000 -vt 0.9230 0.2075 0.0000 -vt 0.9513 0.2075 0.0000 -vt 0.8658 0.1132 0.0000 -vt 0.8487 0.1132 0.0000 -vt 0.8445 0.0044 0.0000 -vt 0.8755 0.0044 0.0000 -vt 0.8445 0.2221 0.0000 -vt 0.8755 0.2221 0.0000 -vt 0.7801 0.1104 0.0000 -vt 0.7912 0.0058 0.0000 -vt 0.7576 0.0058 0.0000 -vt 0.7611 0.1104 0.0000 -vt 0.7912 0.2151 0.0000 -vt 0.7576 0.2374 0.0000 -vt 0.7362 0.1124 0.0000 -vt 0.7464 0.0064 0.0000 -vt 0.7139 0.0064 0.0000 -vt 0.7182 0.1124 0.0000 -vt 0.7139 0.2409 0.0000 -vt 0.7464 0.2409 0.0000 -vt 0.8231 0.1080 0.0000 -vt 0.8044 0.1080 0.0000 -vt 0.7986 0.0056 0.0000 -vt 0.8316 0.0056 0.0000 -vt 0.8316 0.2103 0.0000 -vt 0.7986 0.2321 0.0000 -vt 0.3996 0.1076 0.0000 -vt 0.3999 0.1680 0.0000 -vt 0.3755 0.1681 0.0000 -vt 0.3751 0.0799 0.0000 -vt 0.4002 0.2285 0.0000 -vt 0.3758 0.2286 0.0000 -vt 0.4005 0.2888 0.0000 -vt 0.3761 0.2890 0.0000 -vt 0.4008 0.3494 0.0000 -vt 0.3764 0.3495 0.0000 -vt 0.3512 0.1683 0.0000 -vt 0.3507 0.0641 0.0000 -vt 0.3515 0.2287 0.0000 -vt 0.3518 0.2891 0.0000 -vt 0.3521 0.3496 0.0000 -vt 0.3268 0.1684 0.0000 -vt 0.3264 0.0801 0.0000 -vt 0.3271 0.2288 0.0000 -vt 0.3274 0.2892 0.0000 -vt 0.3277 0.3497 0.0000 -vt 0.3025 0.1685 0.0000 -vt 0.3022 0.1081 0.0000 -vt 0.3028 0.2289 0.0000 -vt 0.3031 0.2893 0.0000 -vt 0.3033 0.3498 0.0000 -vt 0.1505 0.9738 0.0000 -vt 0.0042 0.6813 0.0000 -vt 0.2968 0.6813 0.0000 -vt 0.9446 0.3902 0.0000 -vt 0.9268 0.3902 0.0000 -vt 0.9268 0.3744 0.0000 -vt 0.9446 0.3744 0.0000 -vt 0.8974 0.3747 0.0000 -vt 0.8974 0.4922 0.0000 -vt 0.9065 0.4922 0.0000 -vt 0.9065 0.3747 0.0000 -vt 0.9924 0.3882 0.0000 -vt 0.9924 0.5080 0.0000 -vt 0.9766 0.5080 0.0000 -vt 0.9766 0.3882 0.0000 -vt 0.9160 0.3747 0.0000 -vt 0.9160 0.4922 0.0000 -vt 0.9924 0.5202 0.0000 -vt 0.9766 0.5245 0.0000 -vt 0.9160 0.5041 0.0000 -vt 0.8974 0.5041 0.0000 -vt 0.9268 0.4879 0.0000 -vt 0.9446 0.4879 0.0000 -vt 0.9446 0.5038 0.0000 -vt 0.9268 0.5038 0.0000 -vt 0.8789 0.3882 0.0000 -vt 0.8789 0.5080 0.0000 -vt 0.8630 0.5080 0.0000 -vt 0.8630 0.3882 0.0000 -vt 0.8789 0.5245 0.0000 -vt 0.8630 0.5202 0.0000 -vt 0.9268 0.4391 0.0000 -vt 0.9446 0.4391 0.0000 -vt 0.9277 0.5235 0.0000 -vt 0.9277 0.5442 0.0000 -vt 0.9356 0.4391 0.0000 -vt 0.9356 0.3902 0.0000 -vt 0.9356 0.4879 0.0000 -vt 0.4150 0.4926 0.0000 -vt 0.3619 0.5102 0.0000 -vt 0.3617 0.3568 0.0000 -vt 0.4148 0.3567 0.0000 -vt 0.3087 0.4928 0.0000 -vt 0.3085 0.3569 0.0000 -# 327 texture coords - -o turret -g turret -f 1/1/1 2/2/1 3/3/1 -f 3/3/1 4/4/1 1/1/1 -f 5/5/2 6/6/2 7/7/2 -f 5/5/2 7/7/2 8/8/2 -f 5/5/2 8/8/2 9/9/2 -f 10/10/3 11/11/3 12/12/3 -f 12/12/3 13/13/3 10/10/3 -f 12/12/4 14/14/4 9/15/4 -f 9/15/4 13/13/4 12/12/4 -f 15/16/5 7/17/5 6/18/5 -f 6/18/5 16/19/5 15/16/5 -f 3/20/6 16/21/6 4/22/6 -f 4/23/7 16/24/7 6/25/7 -f 6/25/7 17/26/7 4/23/7 -f 10/27/8 18/28/8 19/29/8 -f 19/29/8 11/30/8 10/27/8 -f 17/31/8 5/5/8 9/9/8 -f 17/31/8 9/9/8 14/32/8 -f 17/31/8 14/32/8 20/33/8 -f 4/23/9 17/26/9 20/17/9 -f 20/17/9 1/16/9 4/23/9 -f 15/34/10 16/21/10 3/20/10 -f 3/20/10 21/35/10 15/34/10 -f 10/36/11 13/37/11 22/12/11 -f 22/12/11 18/11/11 10/36/11 -f 13/37/12 9/38/12 8/14/12 -f 8/14/12 22/12/12 13/37/12 -f 5/39/13 23/40/13 24/41/13 -f 24/41/13 6/42/13 5/39/13 -f 17/43/14 25/44/14 23/45/14 -f 23/45/14 5/46/14 17/43/14 -f 6/47/15 24/48/15 25/49/15 -f 25/49/15 17/50/15 6/47/15 -f 26/51/16 27/52/16 28/53/16 -f 28/53/16 29/54/16 26/51/16 -f 30/55/17 31/56/17 32/57/17 -f 32/57/17 33/58/17 30/55/17 -f 34/59/18 35/60/18 25/49/18 -f 25/49/18 24/48/18 34/59/18 -f 36/61/19 26/62/19 29/63/19 -f 29/63/19 23/64/19 36/61/19 -f 28/65/20 27/66/20 34/59/20 -f 34/59/20 24/48/20 28/65/20 -f 24/41/21 23/40/21 29/54/21 -f 29/54/21 28/53/21 24/41/21 -f 33/67/22 25/49/22 35/60/22 -f 35/60/22 30/68/22 33/67/22 -f 32/69/23 31/70/23 36/61/23 -f 36/61/23 23/64/23 32/69/23 -f 23/45/24 25/44/24 33/58/24 -f 33/58/24 32/57/24 23/45/24 -f 37/3/25 38/2/25 39/1/25 -f 39/1/25 40/4/25 37/3/25 -f 41/5/26 42/9/26 8/8/26 -f 41/5/26 8/8/26 7/7/26 -f 41/5/26 7/7/26 43/6/26 -f 44/12/27 45/11/27 46/10/27 -f 46/10/27 47/13/27 44/12/27 -f 42/15/28 48/14/28 44/12/28 -f 44/12/28 47/13/28 42/15/28 -f 43/18/5 7/17/5 15/16/5 -f 15/16/5 49/19/5 43/18/5 -f 37/20/29 40/22/29 49/21/29 -f 40/23/30 50/26/30 43/25/30 -f 43/25/30 49/24/30 40/23/30 -f 19/29/31 18/28/31 46/27/31 -f 46/27/31 45/30/31 19/29/31 -f 50/31/31 51/33/31 48/32/31 -f 50/31/31 48/32/31 42/9/31 -f 50/31/31 42/9/31 41/5/31 -f 51/17/32 50/26/32 40/23/32 -f 40/23/32 39/16/32 51/17/32 -f 15/34/33 21/35/33 37/20/33 -f 37/20/33 49/21/33 15/34/33 -f 22/12/34 47/37/34 46/36/34 -f 46/36/34 18/11/34 22/12/34 -f 8/14/12 42/38/12 47/37/12 -f 47/37/12 22/12/12 8/14/12 -f 52/41/35 53/40/35 41/39/35 -f 41/39/35 43/42/35 52/41/35 -f 53/45/36 54/44/36 50/43/36 -f 50/43/36 41/46/36 53/45/36 -f 54/49/37 52/48/37 43/47/37 -f 43/47/37 50/50/37 54/49/37 -f 55/53/38 56/52/38 57/51/38 -f 57/51/38 58/54/38 55/53/38 -f 59/57/39 60/56/39 61/55/39 -f 61/55/39 62/58/39 59/57/39 -f 54/49/40 63/60/40 64/59/40 -f 64/59/40 52/48/40 54/49/40 -f 58/63/41 57/62/41 65/61/41 -f 65/61/41 53/64/41 58/63/41 -f 55/65/42 52/48/42 64/59/42 -f 64/59/42 56/66/42 55/65/42 -f 52/41/43 55/53/43 58/54/43 -f 58/54/43 53/40/43 52/41/43 -f 63/60/44 54/49/44 62/67/44 -f 62/67/44 61/68/44 63/60/44 -f 59/69/45 53/64/45 65/61/45 -f 65/61/45 60/70/45 59/69/45 -f 53/45/46 59/57/46 62/58/46 -f 62/58/46 54/44/46 53/45/46 -f 66/3/47 2/2/47 1/1/47 -f 1/1/47 67/4/47 66/3/47 -f 68/5/48 69/9/48 70/8/48 -f 68/5/48 70/8/48 71/7/48 -f 68/5/48 71/7/48 72/6/48 -f 12/12/49 11/11/49 73/10/49 -f 73/10/49 74/13/49 12/12/49 -f 69/15/50 14/14/50 12/12/50 -f 12/12/50 74/13/50 69/15/50 -f 72/18/51 71/17/51 75/16/51 -f 75/16/51 76/19/51 72/18/51 -f 66/20/52 67/22/52 76/21/52 -f 67/23/53 77/26/53 72/25/53 -f 72/25/53 76/24/53 67/23/53 -f 19/29/54 78/28/54 73/27/54 -f 73/27/54 11/30/54 19/29/54 -f 77/31/54 20/33/54 14/32/54 -f 77/31/54 14/32/54 69/9/54 -f 77/31/54 69/9/54 68/5/54 -f 20/17/9 77/26/9 67/23/9 -f 67/23/9 1/16/9 20/17/9 -f 75/34/55 79/35/55 66/20/55 -f 66/20/55 76/21/55 75/34/55 -f 80/12/56 74/37/57 73/36/57 -f 73/36/57 78/11/56 80/12/56 -f 70/14/58 69/38/58 74/37/58 -f 74/37/58 80/12/58 70/14/58 -f 81/41/59 82/40/59 68/39/59 -f 68/39/59 72/42/59 81/41/59 -f 82/45/60 83/44/60 77/43/60 -f 77/43/60 68/46/60 82/45/60 -f 83/49/61 81/48/61 72/47/61 -f 72/47/61 77/50/61 83/49/61 -f 84/53/62 85/52/62 86/51/62 -f 86/51/62 87/54/62 84/53/62 -f 88/57/63 89/56/63 90/55/63 -f 90/55/63 91/58/63 88/57/63 -f 83/49/64 92/60/64 93/59/64 -f 93/59/64 81/48/64 83/49/64 -f 87/63/65 86/62/65 94/61/65 -f 94/61/65 82/64/65 87/63/65 -f 84/65/66 81/48/66 93/59/66 -f 93/59/66 85/66/66 84/65/66 -f 81/41/67 84/53/67 87/54/67 -f 87/54/67 82/40/67 81/41/67 -f 92/60/68 83/49/68 91/67/68 -f 91/67/68 90/68/68 92/60/68 -f 88/69/69 82/64/69 94/61/69 -f 94/61/69 89/70/69 88/69/69 -f 82/45/70 88/57/70 91/58/70 -f 91/58/70 83/44/70 82/45/70 -f 39/1/71 38/2/71 95/3/71 -f 95/3/71 96/4/71 39/1/71 -f 97/5/72 98/6/72 71/7/72 -f 97/5/72 71/7/72 70/8/72 -f 97/5/72 70/8/72 99/9/72 -f 100/10/73 45/11/73 44/12/73 -f 44/12/73 101/13/73 100/10/73 -f 44/12/74 48/14/74 99/15/74 -f 99/15/74 101/13/74 44/12/74 -f 75/16/51 71/17/51 98/18/51 -f 98/18/51 102/19/51 75/16/51 -f 95/20/75 102/21/75 96/22/75 -f 96/23/76 102/24/76 98/25/76 -f 98/25/76 103/26/76 96/23/76 -f 100/27/77 78/28/77 19/29/77 -f 19/29/77 45/30/77 100/27/77 -f 103/31/77 97/5/77 99/9/77 -f 103/31/77 99/9/77 48/32/77 -f 103/31/77 48/32/77 51/33/77 -f 96/23/32 103/26/32 51/17/32 -f 51/17/32 39/16/32 96/23/32 -f 75/34/78 102/21/78 95/20/78 -f 95/20/78 79/35/78 75/34/78 -f 100/36/79 101/37/79 80/12/80 -f 80/12/80 78/11/80 100/36/79 -f 101/37/58 99/38/58 70/14/58 -f 70/14/58 80/12/58 101/37/58 -f 97/39/81 104/40/81 105/41/81 -f 105/41/81 98/42/81 97/39/81 -f 103/43/82 106/44/82 104/45/82 -f 104/45/82 97/46/82 103/43/82 -f 98/47/83 105/48/83 106/49/83 -f 106/49/83 103/50/83 98/47/83 -f 107/51/84 108/52/84 109/53/84 -f 109/53/84 110/54/84 107/51/84 -f 111/55/85 112/56/85 113/57/85 -f 113/57/85 114/58/85 111/55/85 -f 115/59/86 116/60/86 106/49/86 -f 106/49/86 105/48/86 115/59/86 -f 117/61/87 107/62/87 110/63/87 -f 110/63/87 104/64/87 117/61/87 -f 109/65/88 108/66/88 115/59/88 -f 115/59/88 105/48/88 109/65/88 -f 105/41/89 104/40/89 110/54/89 -f 110/54/89 109/53/89 105/41/89 -f 114/67/90 106/49/90 116/60/90 -f 116/60/90 111/68/90 114/67/90 -f 113/69/91 112/70/91 117/61/91 -f 117/61/91 104/64/91 113/69/91 -f 104/45/92 106/44/92 114/58/92 -f 114/58/92 113/57/92 104/45/92 -f 118/71/58 119/72/58 120/73/58 -f 120/73/58 121/74/58 118/71/58 -f 119/75/93 122/76/93 123/77/93 -f 123/77/93 120/78/93 119/75/93 -f 122/72/51 124/71/51 125/74/51 -f 125/74/51 123/73/51 122/72/51 -f 126/71/93 127/72/93 128/73/93 -f 128/73/93 129/74/93 126/71/93 -f 127/75/51 130/76/51 131/77/51 -f 131/77/51 128/78/51 127/75/51 -f 130/72/94 132/71/94 133/74/94 -f 133/74/94 131/73/94 130/72/94 -f 134/71/51 135/72/51 136/73/51 -f 136/73/51 137/74/51 134/71/51 -f 135/75/94 138/76/94 139/77/94 -f 139/77/94 136/78/94 135/75/94 -f 138/72/58 140/71/58 141/74/58 -f 141/74/58 139/73/58 138/72/58 -f 142/71/94 143/72/94 144/73/94 -f 144/73/94 145/74/94 142/71/94 -f 143/75/58 146/76/58 147/77/58 -f 147/77/58 144/78/58 143/75/58 -f 146/72/93 148/71/93 149/74/93 -f 149/74/93 147/73/93 146/72/93 -f 150/79/95 151/80/95 152/81/95 -f 152/81/95 153/82/95 150/79/95 -f 154/83/96 155/84/96 156/85/96 -f 156/85/96 157/86/96 154/83/96 -f 158/87/97 159/88/97 160/89/97 -f 160/89/97 161/90/97 158/87/97 -f 162/86/51 163/91/51 164/92/51 -f 164/92/51 165/83/51 162/86/51 -f 166/93/98 167/94/98 168/95/98 -f 168/95/98 169/96/98 166/93/98 -f 170/97/99 171/98/99 172/99/99 -f 173/100/99 158/101/99 161/102/99 -f 161/102/99 174/103/99 173/100/99 -f 175/104/100 176/105/100 177/106/100 -f 177/106/99 176/105/99 178/107/99 -f 178/107/99 179/108/99 177/106/99 -f 150/79/101 153/82/101 180/109/101 -f 180/109/101 181/110/101 150/79/101 -f 161/90/102 160/89/102 182/111/102 -f 182/111/102 183/112/102 161/90/102 -f 169/96/103 168/95/103 184/113/103 -f 184/113/103 185/114/103 169/96/103 -f 174/103/100 161/102/100 183/115/100 -f 183/115/100 186/116/100 174/103/100 -f 172/99/104 179/108/104 178/107/104 -f 178/107/104 170/97/104 172/99/104 -f 152/117/105 151/118/105 187/119/105 -f 187/119/105 173/120/105 152/117/105 -f 152/117/106 173/120/106 174/121/106 -f 174/121/106 153/122/106 152/117/106 -f 153/122/107 174/121/107 186/123/107 -f 186/123/107 180/124/107 153/122/107 -f 180/124/108 186/123/108 188/125/108 -f 188/125/108 181/126/108 180/124/108 -f 181/127/109 188/128/109 189/129/109 -f 189/129/109 150/130/109 181/127/109 -f 150/130/110 189/129/110 187/131/110 -f 187/131/110 151/132/110 150/130/110 -f 190/133/111 188/134/111 186/116/111 -f 186/116/111 183/115/111 190/133/111 -f 182/111/112 191/135/112 190/136/112 -f 190/136/112 183/112/112 182/111/112 -f 192/137/113 193/138/113 159/88/113 -f 159/88/113 158/87/113 192/137/113 -f 173/100/114 187/139/114 192/140/114 -f 192/140/114 158/101/114 173/100/114 -f 194/92/115 154/83/115 157/86/115 -f 157/86/115 195/91/115 194/92/115 -f 171/141/116 192/142/116 187/131/116 -f 187/131/116 172/143/116 171/141/116 -f 172/143/117 187/131/117 189/129/117 -f 189/129/117 179/144/117 172/143/117 -f 179/144/118 189/129/118 188/128/118 -f 188/128/118 177/145/118 179/144/118 -f 177/145/119 188/128/119 190/146/119 -f 190/146/119 175/147/119 177/145/119 -f 196/85/120 162/86/120 165/83/120 -f 165/83/120 197/84/120 196/85/120 -f 176/148/98 166/93/98 169/96/98 -f 169/96/98 178/149/98 176/148/98 -f 178/149/103 169/96/103 185/114/103 -f 185/114/103 170/150/103 178/149/103 -f 156/151/54 193/152/54 192/142/54 -f 192/142/54 157/153/54 156/151/54 -f 157/153/8 192/142/8 171/141/8 -f 171/141/8 195/154/8 157/153/8 -f 195/155/104 171/98/104 170/97/104 -f 170/97/104 194/156/104 195/155/104 -f 194/157/121 170/150/121 185/114/121 -f 185/114/121 154/158/121 194/157/121 -f 154/158/121 185/114/121 184/113/121 -f 184/113/121 155/159/121 154/158/121 -f 164/160/122 167/94/122 166/93/122 -f 166/93/122 165/161/122 164/160/122 -f 165/161/123 166/93/123 176/148/123 -f 176/148/123 197/162/123 165/161/123 -f 197/163/124 176/105/124 175/104/124 -f 175/104/124 196/164/124 197/163/124 -f 196/165/54 175/147/54 190/146/54 -f 190/146/54 162/166/54 196/165/54 -f 162/166/54 190/146/54 191/167/54 -f 191/167/54 163/168/54 162/166/54 -f 198/79/125 199/80/125 200/81/125 -f 200/81/125 201/82/125 198/79/125 -f 202/83/126 203/84/126 204/85/126 -f 204/85/126 205/86/126 202/83/126 -f 206/87/127 207/88/127 208/89/127 -f 208/89/127 209/90/127 206/87/127 -f 210/86/104 211/91/104 212/92/104 -f 212/92/104 213/83/104 210/86/104 -f 214/93/128 215/94/128 216/95/128 -f 216/95/128 217/96/128 214/93/128 -f 218/97/58 219/98/58 220/99/58 -f 221/100/129 206/101/129 209/102/129 -f 209/102/129 222/103/129 221/100/129 -f 223/104/129 224/105/129 225/106/129 -f 225/106/58 224/105/58 226/107/58 -f 226/107/58 227/108/58 225/106/58 -f 198/79/130 201/82/130 228/109/130 -f 228/109/130 229/110/130 198/79/130 -f 209/90/131 208/89/131 230/111/131 -f 230/111/131 231/112/131 209/90/131 -f 217/96/132 216/95/132 232/113/132 -f 232/113/132 233/114/132 217/96/132 -f 222/103/58 209/102/58 231/115/58 -f 231/115/58 234/116/58 222/103/58 -f 220/99/5 227/108/5 226/107/5 -f 226/107/5 218/97/5 220/99/5 -f 200/117/133 199/118/133 235/119/133 -f 235/119/133 221/120/133 200/117/133 -f 200/117/134 221/120/134 222/121/134 -f 222/121/134 201/122/134 200/117/134 -f 201/122/135 222/121/135 234/123/135 -f 234/123/135 228/124/135 201/122/135 -f 228/124/136 234/123/136 236/125/136 -f 236/125/136 229/126/136 228/124/136 -f 229/127/137 236/128/137 237/129/137 -f 237/129/137 198/130/137 229/127/137 -f 198/130/138 237/129/138 235/131/138 -f 235/131/138 199/132/138 198/130/138 -f 238/133/139 236/134/139 234/116/139 -f 234/116/139 231/115/139 238/133/139 -f 230/111/140 239/135/140 238/136/140 -f 238/136/140 231/112/140 230/111/140 -f 240/137/141 241/138/141 207/88/141 -f 207/88/141 206/87/141 240/137/141 -f 221/100/142 235/139/142 240/140/142 -f 240/140/142 206/101/142 221/100/142 -f 242/92/143 202/83/143 205/86/143 -f 205/86/143 243/91/143 242/92/143 -f 219/141/144 240/142/144 235/131/144 -f 235/131/144 220/143/144 219/141/144 -f 220/143/145 235/131/145 237/129/145 -f 237/129/145 227/144/145 220/143/145 -f 227/144/146 237/129/146 236/128/146 -f 236/128/146 225/145/146 227/144/146 -f 225/145/147 236/128/147 238/146/147 -f 238/146/147 223/147/147 225/145/147 -f 244/85/148 210/86/148 213/83/148 -f 213/83/148 245/84/148 244/85/148 -f 224/148/128 214/93/128 217/96/128 -f 217/96/128 226/149/128 224/148/128 -f 226/149/149 217/96/149 233/114/149 -f 233/114/149 218/150/149 226/149/149 -f 204/151/8 241/152/8 240/142/8 -f 240/142/8 205/153/8 204/151/8 -f 205/153/8 240/142/8 219/141/8 -f 219/141/8 243/154/8 205/153/8 -f 243/155/58 219/98/58 218/97/58 -f 218/97/58 242/156/58 243/155/58 -f 242/157/121 218/150/121 233/114/121 -f 233/114/121 202/158/121 242/157/121 -f 202/158/122 233/114/122 232/113/122 -f 232/113/122 203/159/122 202/158/122 -f 212/160/121 215/94/121 214/93/121 -f 214/93/121 213/161/121 212/160/121 -f 213/161/150 214/93/150 224/148/150 -f 224/148/150 245/162/150 213/161/150 -f 245/163/115 224/105/115 223/104/115 -f 223/104/115 244/164/115 245/163/115 -f 244/165/54 223/147/54 238/146/54 -f 238/146/54 210/166/54 244/165/54 -f 210/166/54 238/146/54 239/167/54 -f 239/167/54 211/168/54 210/166/54 -f 246/79/151 247/80/151 248/81/151 -f 248/81/151 249/82/151 246/79/151 -f 250/83/152 251/84/152 252/85/152 -f 252/85/152 253/86/152 250/83/152 -f 254/87/131 255/88/131 256/89/131 -f 256/89/131 257/90/131 254/87/131 -f 258/86/93 259/91/93 260/92/93 -f 260/92/93 261/83/93 258/86/93 -f 262/93/149 263/94/149 264/95/149 -f 264/95/149 265/96/149 262/93/149 -f 266/97/51 267/98/51 268/99/51 -f 269/100/12 254/101/12 257/102/12 -f 257/102/12 270/103/12 269/100/12 -f 271/104/153 272/105/153 273/106/153 -f 273/106/12 272/105/12 274/107/12 -f 274/107/12 275/108/12 273/106/12 -f 246/79/154 249/82/154 276/109/154 -f 276/109/154 277/110/154 246/79/154 -f 257/90/127 256/89/127 278/111/127 -f 278/111/127 279/112/127 257/90/127 -f 265/96/128 264/95/128 280/113/128 -f 280/113/128 281/114/128 265/96/128 -f 270/103/12 257/102/12 279/115/12 -f 279/115/12 282/116/12 270/103/12 -f 268/99/51 275/108/51 274/107/51 -f 274/107/51 266/97/51 268/99/51 -f 248/117/155 247/118/155 283/119/155 -f 283/119/155 269/120/155 248/117/155 -f 248/117/156 269/120/156 270/121/156 -f 270/121/156 249/122/156 248/117/156 -f 249/122/157 270/121/157 282/123/157 -f 282/123/157 276/124/157 249/122/157 -f 276/124/158 282/123/158 284/125/158 -f 284/125/158 277/126/158 276/124/158 -f 277/127/159 284/128/159 285/129/159 -f 285/129/159 246/130/159 277/127/159 -f 246/130/160 285/129/160 283/131/160 -f 283/131/160 247/132/160 246/130/160 -f 286/133/161 284/134/161 282/116/161 -f 282/116/161 279/115/161 286/133/161 -f 278/111/162 287/135/162 286/136/162 -f 286/136/162 279/112/162 278/111/162 -f 288/137/163 289/138/163 255/88/163 -f 255/88/163 254/87/163 288/137/163 -f 269/100/164 283/139/164 288/140/164 -f 288/140/164 254/101/164 269/100/164 -f 290/92/165 250/83/165 253/86/165 -f 253/86/165 291/91/165 290/92/165 -f 267/141/166 288/142/166 283/131/166 -f 283/131/166 268/143/166 267/141/166 -f 268/143/160 283/131/160 285/129/160 -f 285/129/160 275/144/160 268/143/160 -f 275/144/167 285/129/167 284/128/167 -f 284/128/167 273/145/167 275/144/167 -f 273/145/168 284/128/168 286/146/168 -f 286/146/168 271/147/168 273/145/168 -f 292/85/126 258/86/126 261/83/126 -f 261/83/126 293/84/126 292/85/126 -f 272/148/149 262/93/149 265/96/149 -f 265/96/149 274/149/149 272/148/149 -f 274/149/128 265/96/128 281/114/128 -f 281/114/128 266/150/128 274/149/128 -f 252/151/54 289/152/54 288/142/54 -f 288/142/54 253/153/54 252/151/54 -f 253/153/54 288/142/54 267/141/54 -f 267/141/54 291/154/54 253/153/54 -f 291/155/51 267/98/51 266/97/51 -f 266/97/51 290/156/51 291/155/51 -f 290/157/123 266/150/123 281/114/123 -f 281/114/123 250/158/123 290/157/123 -f 250/158/121 281/114/121 280/113/121 -f 280/113/121 251/159/121 250/158/121 -f 260/160/121 263/94/121 262/93/121 -f 262/93/121 261/161/121 260/160/121 -f 261/161/121 262/93/121 272/148/121 -f 272/148/121 293/162/121 261/161/121 -f 293/163/169 272/105/169 271/104/169 -f 271/104/169 292/164/169 293/163/169 -f 292/165/54 271/147/54 286/146/54 -f 286/146/54 258/166/54 292/165/54 -f 258/166/54 286/146/54 287/167/54 -f 287/167/54 259/168/54 258/166/54 -f 95/169/51 294/170/51 295/171/51 -f 295/171/51 296/172/51 95/169/51 -f 296/173/94 295/174/94 297/175/94 -f 297/175/94 298/176/94 296/173/94 -f 298/177/58 297/178/58 299/179/58 -f 299/179/58 37/180/58 298/177/58 -f 37/181/170 299/182/170 294/183/170 -f 294/183/170 95/184/170 37/181/170 -f 300/185/51 301/186/51 302/187/51 -f 302/187/51 303/188/51 300/185/51 -f 304/185/100 305/189/100 306/190/100 -f 306/190/100 307/188/100 304/185/100 -f 308/185/58 309/189/58 310/190/58 -f 310/190/58 311/188/58 308/185/58 -f 312/185/93 313/186/93 314/187/93 -f 314/187/93 315/188/93 312/185/93 -f 316/191/171 302/192/171 315/193/171 -f 315/193/171 317/194/171 316/191/171 -f 318/195/172 314/196/172 311/197/172 -f 311/197/172 319/198/172 318/195/172 -f 320/199/173 310/200/173 307/201/173 -f 307/201/173 321/202/173 320/199/173 -f 322/203/174 306/204/174 303/205/174 -f 303/205/174 323/206/174 322/203/174 -f 324/207/54 301/208/54 300/209/54 -f 300/209/54 325/210/54 324/207/54 -f 326/211/8 305/212/8 304/213/8 -f 304/213/8 327/214/8 326/211/8 -f 328/215/77 309/216/77 308/217/77 -f 308/217/77 329/218/77 328/215/77 -f 330/219/77 313/220/77 312/221/77 -f 312/221/77 331/222/77 330/219/77 -f 308/185/58 311/188/58 314/187/58 -f 314/187/58 313/186/58 308/185/58 -f 312/185/93 315/188/93 302/190/93 -f 302/190/93 301/189/93 312/185/93 -f 318/195/175 317/194/175 315/193/175 -f 315/193/175 314/196/175 318/195/175 -f 320/199/176 319/198/176 311/197/176 -f 311/197/176 310/200/176 320/199/176 -f 322/203/177 321/202/177 307/201/177 -f 307/201/177 306/204/177 322/203/177 -f 330/219/54 329/218/54 308/217/54 -f 308/217/54 313/220/54 330/219/54 -f 324/207/31 331/222/31 312/221/31 -f 312/221/31 301/208/31 324/207/31 -f 300/185/51 303/188/51 306/190/51 -f 306/190/51 305/189/51 300/185/51 -f 304/185/94 307/188/94 310/187/94 -f 310/187/94 309/186/94 304/185/94 -f 316/191/178 323/206/178 303/205/178 -f 303/205/178 302/192/178 316/191/178 -f 326/211/77 325/210/77 300/209/77 -f 300/209/77 305/212/77 326/211/77 -f 328/215/77 327/214/77 304/213/77 -f 304/213/77 309/216/77 328/215/77 -f 332/185/51 333/186/51 334/187/51 -f 334/187/51 335/188/51 332/185/51 -f 336/223/94 337/224/94 338/225/94 -f 338/225/94 339/226/94 336/223/94 -f 340/227/58 341/228/58 342/229/58 -f 342/229/58 343/230/58 340/227/58 -f 344/185/93 345/186/93 346/187/93 -f 346/187/93 347/188/93 344/185/93 -f 348/191/171 334/192/171 347/193/171 -f 347/193/171 349/194/171 348/191/171 -f 350/195/172 346/196/172 343/197/172 -f 343/197/172 351/198/172 350/195/172 -f 352/199/173 342/200/173 339/201/173 -f 339/201/173 353/202/173 352/199/173 -f 354/203/174 338/204/174 335/205/174 -f 335/205/174 355/206/174 354/203/174 -f 356/207/54 333/208/54 332/209/54 -f 332/209/54 357/210/54 356/207/54 -f 358/211/8 337/212/8 336/213/8 -f 336/213/8 359/214/8 358/211/8 -f 360/215/54 341/216/54 340/217/54 -f 340/217/54 361/218/54 360/215/54 -f 362/219/77 345/220/77 344/221/77 -f 344/221/77 363/222/77 362/219/77 -f 340/227/58 343/230/58 346/231/58 -f 346/231/58 345/232/58 340/227/58 -f 344/185/93 347/188/93 334/190/93 -f 334/190/93 333/189/93 344/185/93 -f 350/195/175 349/194/175 347/193/175 -f 347/193/175 346/196/175 350/195/175 -f 352/199/176 351/198/176 343/197/176 -f 343/197/176 342/200/176 352/199/176 -f 354/203/177 353/202/177 339/201/177 -f 339/201/177 338/204/177 354/203/177 -f 362/219/54 361/218/54 340/217/54 -f 340/217/54 345/220/54 362/219/54 -f 356/207/31 363/222/31 344/221/31 -f 344/221/31 333/208/31 356/207/31 -f 332/185/51 335/188/51 338/190/51 -f 338/190/51 337/189/51 332/185/51 -f 336/223/94 339/226/94 342/233/94 -f 342/233/94 341/234/94 336/223/94 -f 348/191/178 355/206/178 335/205/178 -f 335/205/178 334/192/178 348/191/178 -f 358/211/77 357/210/77 332/209/77 -f 332/209/77 337/212/77 358/211/77 -f 360/215/54 359/214/54 336/213/54 -f 336/213/54 341/216/54 360/215/54 -f 364/235/179 365/236/179 366/237/179 -f 366/237/179 367/238/179 364/235/179 -f 368/239/180 365/236/180 364/235/180 -f 364/235/180 369/240/180 368/239/180 -f 364/241/181 367/242/181 370/243/181 -f 370/243/181 371/244/181 364/241/181 -f 369/245/182 364/241/182 371/244/182 -f 371/244/182 372/246/182 369/245/182 -f 371/247/183 370/248/183 373/249/183 -f 373/249/183 374/250/183 371/247/183 -f 375/251/184 372/252/184 371/247/184 -f 371/247/184 374/250/184 375/251/184 -f 365/253/185 374/254/185 373/255/185 -f 373/255/185 366/256/185 365/253/185 -f 368/257/186 375/258/186 374/254/186 -f 374/254/186 365/253/186 368/257/186 -f 376/235/187 377/238/187 378/237/187 -f 378/237/187 379/236/187 376/235/187 -f 380/239/188 381/240/188 376/235/188 -f 376/235/188 379/236/188 380/239/188 -f 376/241/189 382/244/189 383/243/189 -f 383/243/189 377/242/189 376/241/189 -f 381/245/190 384/246/190 382/244/190 -f 382/244/190 376/241/190 381/245/190 -f 382/247/191 385/250/191 386/249/191 -f 386/249/191 383/248/191 382/247/191 -f 387/251/192 385/250/192 382/247/192 -f 382/247/192 384/252/192 387/251/192 -f 379/253/193 378/256/193 386/255/193 -f 386/255/193 385/254/193 379/253/193 -f 380/257/194 379/253/194 385/254/194 -f 385/254/194 387/258/194 380/257/194 -f 388/235/187 389/238/187 390/237/187 -f 390/237/187 391/236/187 388/235/187 -f 392/239/188 393/240/188 388/235/188 -f 388/235/188 391/236/188 392/239/188 -f 388/241/189 394/244/189 395/243/189 -f 395/243/189 389/242/189 388/241/189 -f 393/245/195 396/246/195 394/244/195 -f 394/244/195 388/241/195 393/245/195 -f 394/247/191 397/250/191 398/249/191 -f 398/249/191 395/248/191 394/247/191 -f 399/251/196 397/250/196 394/247/196 -f 394/247/196 396/252/196 399/251/196 -f 391/253/193 390/256/193 398/255/193 -f 398/255/193 397/254/193 391/253/193 -f 392/257/197 391/253/197 397/254/197 -f 397/254/197 399/258/197 392/257/197 -f 400/235/198 401/238/198 402/237/198 -f 402/237/198 403/236/198 400/235/198 -f 404/239/199 405/240/199 400/235/199 -f 400/235/199 403/236/199 404/239/199 -f 400/241/200 406/244/200 407/243/200 -f 407/243/200 401/242/200 400/241/200 -f 405/245/201 408/246/201 406/244/201 -f 406/244/201 400/241/201 405/245/201 -f 406/247/202 409/250/202 410/249/202 -f 410/249/202 407/248/202 406/247/202 -f 411/251/203 409/250/203 406/247/203 -f 406/247/203 408/252/203 411/251/203 -f 403/253/185 402/256/185 410/255/185 -f 410/255/185 409/254/185 403/253/185 -f 404/257/204 403/253/204 409/254/204 -f 409/254/204 411/258/204 404/257/204 -f 412/235/205 413/236/205 414/237/205 -f 414/237/205 415/238/205 412/235/205 -f 416/239/206 413/236/206 412/235/206 -f 412/235/206 417/240/206 416/239/206 -f 412/241/207 415/242/207 418/243/207 -f 418/243/207 419/244/207 412/241/207 -f 417/245/208 412/241/208 419/244/208 -f 419/244/208 420/246/208 417/245/208 -f 419/247/209 418/248/209 421/249/209 -f 421/249/209 422/250/209 419/247/209 -f 423/251/210 420/252/210 419/247/210 -f 419/247/210 422/250/210 423/251/210 -f 413/253/193 422/254/193 421/255/193 -f 421/255/193 414/256/193 413/253/193 -f 416/257/211 423/258/211 422/254/211 -f 422/254/211 413/253/211 416/257/211 -f 424/235/205 425/236/205 426/237/205 -f 426/237/205 427/238/205 424/235/205 -f 428/239/206 425/236/206 424/235/206 -f 424/235/206 429/240/206 428/239/206 -f 424/241/207 427/242/207 430/243/207 -f 430/243/207 431/244/207 424/241/207 -f 429/245/212 424/241/212 431/244/212 -f 431/244/212 432/246/212 429/245/212 -f 431/247/209 430/248/209 433/249/209 -f 433/249/209 434/250/209 431/247/209 -f 435/251/213 432/252/213 431/247/213 -f 431/247/213 434/250/213 435/251/213 -f 425/253/193 434/254/193 433/255/193 -f 433/255/193 426/256/193 425/253/193 -f 428/257/214 435/258/214 434/254/214 -f 434/254/214 425/253/214 428/257/214 -f 436/235/198 437/238/198 438/237/198 -f 438/237/198 439/236/198 436/235/198 -f 440/239/199 441/240/199 436/235/199 -f 436/235/199 439/236/199 440/239/199 -f 436/241/200 442/244/200 443/243/200 -f 443/243/200 437/242/200 436/241/200 -f 441/245/215 444/246/215 442/244/215 -f 442/244/215 436/241/215 441/245/215 -f 442/247/202 445/250/202 446/249/202 -f 446/249/202 443/248/202 442/247/202 -f 447/251/216 445/250/216 442/247/216 -f 442/247/216 444/252/216 447/251/216 -f 439/253/185 438/256/185 446/255/185 -f 446/255/185 445/254/185 439/253/185 -f 440/257/217 439/253/217 445/254/217 -f 445/254/217 447/258/217 440/257/217 -f 448/235/179 449/236/179 450/237/179 -f 450/237/179 451/238/179 448/235/179 -f 452/239/180 449/236/180 448/235/180 -f 448/235/180 453/240/180 452/239/180 -f 448/241/181 451/242/181 454/243/181 -f 454/243/181 455/244/181 448/241/181 -f 453/245/218 448/241/218 455/244/218 -f 455/244/218 456/246/218 453/245/218 -f 455/247/183 454/248/183 457/249/183 -f 457/249/183 458/250/183 455/247/183 -f 459/251/219 456/252/219 455/247/219 -f 455/247/219 458/250/219 459/251/219 -f 449/253/185 458/254/185 457/255/185 -f 457/255/185 450/256/185 449/253/185 -f 452/257/220 459/258/220 458/254/220 -f 458/254/220 449/253/220 452/257/220 -f 460/259/221 461/260/222 462/261/223 -f 462/261/223 463/262/224 460/259/221 -f 461/260/222 464/263/225 465/264/225 -f 465/264/225 462/261/223 461/260/222 -f 464/263/225 466/265/226 467/266/226 -f 467/266/226 465/264/225 464/263/225 -f 466/265/226 468/267/227 469/268/227 -f 469/268/227 467/266/226 466/265/226 -f 463/262/224 462/261/223 470/269/228 -f 470/269/228 471/270/229 463/262/224 -f 462/261/223 465/264/225 472/271/225 -f 472/271/225 470/269/228 462/261/223 -f 465/264/225 467/266/226 473/272/226 -f 473/272/226 472/271/225 465/264/225 -f 467/266/226 469/268/227 474/273/227 -f 474/273/227 473/272/226 467/266/226 -f 471/270/229 470/269/228 475/274/230 -f 475/274/230 476/275/231 471/270/229 -f 470/269/228 472/271/225 477/276/225 -f 477/276/225 475/274/230 470/269/228 -f 472/271/225 473/272/226 478/277/226 -f 478/277/226 477/276/225 472/271/225 -f 473/272/226 474/273/227 479/278/227 -f 479/278/227 478/277/226 473/272/226 -f 476/275/231 475/274/230 480/279/232 -f 480/279/232 481/280/233 476/275/231 -f 475/274/230 477/276/225 482/281/225 -f 482/281/225 480/279/232 475/274/230 -f 477/276/225 478/277/226 483/282/226 -f 483/282/226 482/281/225 477/276/225 -f 478/277/226 479/278/227 484/283/227 -f 484/283/227 483/282/226 478/277/226 -f 485/284/234 486/285/234 487/286/234 -f 485/284/235 487/285/235 488/286/235 -f 485/284/236 488/285/236 489/286/236 -f 485/284/237 489/285/237 486/286/237 -f 490/287/238 491/288/238 492/289/238 -f 492/289/238 493/290/238 490/287/238 -f 494/291/58 495/292/58 496/293/58 -f 496/293/58 497/294/58 494/291/58 -f 498/295/93 499/296/93 495/297/93 -f 495/297/93 494/298/93 498/295/93 -f 500/299/153 501/300/153 499/292/153 -f 499/292/153 498/291/153 500/299/153 -f 492/301/93 491/302/93 495/297/93 -f 495/297/93 499/296/93 492/301/93 -f 493/303/153 492/304/153 499/292/153 -f 499/292/153 501/300/153 493/303/153 -f 502/305/239 503/306/239 504/307/239 -f 504/307/239 505/308/239 502/305/239 -f 506/294/153 507/293/153 508/292/153 -f 508/292/153 509/291/153 506/294/153 -f 510/291/129 511/292/129 512/300/129 -f 512/300/129 513/299/129 510/291/129 -f 509/309/93 508/310/93 511/311/93 -f 511/311/93 510/312/93 509/309/93 -f 505/304/129 504/303/129 512/300/129 -f 512/300/129 511/292/129 505/304/129 -f 502/313/93 505/314/93 511/311/93 -f 511/311/93 508/310/93 502/313/93 -f 502/305/240 514/315/77 515/316/77 -f 515/316/77 503/306/240 502/305/240 -f 508/310/93 516/317/241 514/318/241 -f 514/318/241 502/313/93 508/310/93 -f 516/315/242 517/319/242 496/320/242 -f 496/320/242 495/288/242 516/315/242 -f 491/288/243 490/287/243 515/316/77 -f 515/316/77 514/315/77 491/288/243 -f 495/297/170 491/302/170 514/318/241 -f 514/318/241 516/317/241 495/297/170 -f 508/305/244 507/321/244 517/319/244 -f 517/319/244 516/315/244 508/305/244 -f 496/322/170 517/323/170 518/324/170 -f 518/324/170 497/325/170 496/322/170 -f 517/323/93 507/326/93 506/327/93 -f 506/327/93 518/324/93 517/323/93 -# 782 faces - diff --git a/examples/models/mesh_picking/turret_diffuse.png b/examples/models/mesh_picking/turret_diffuse.png deleted file mode 100644 index 33628e3..0000000 Binary files a/examples/models/mesh_picking/turret_diffuse.png and /dev/null differ diff --git a/examples/models/obj_loading/main.go b/examples/models/obj_loading/main.go index 806c726..84ee9fc 100644 --- a/examples/models/obj_loading/main.go +++ b/examples/models/obj_loading/main.go @@ -1,22 +1,9 @@ package main import ( - "path/filepath" - "slices" - "unsafe" - - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) -var supportedFileTypes = []string{ - ".obj", - ".gltf", - ".glb", - ".vox", - ".iqm", - ".m3d", -} - func main() { screenWidth := int32(800) screenHeight := int32(450) @@ -37,75 +24,26 @@ func main() { position := rl.NewVector3(0.0, 0.0, 0.0) // Set model position - meshes := unsafe.Slice(obj.Meshes, obj.MeshCount) - bounds := rl.GetMeshBoundingBox(meshes[0]) // Set model bounds - - selected := false - - rl.DisableCursor() rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - // Update - rl.UpdateCamera(&camera, rl.CameraFirstPerson) - - // Load new models/textures on drag&drop - if rl.IsFileDropped() { - droppedFiles := rl.LoadDroppedFiles() - - if len(droppedFiles) == 1 { // Only support one file dropped - if slices.Contains(supportedFileTypes, filepath.Ext(droppedFiles[0])) { // Model file formats supported - rl.UnloadModel(obj) // Unload previous model - obj = rl.LoadModel(droppedFiles[0]) // Load new model - rl.SetMaterialTexture(obj.Materials, rl.MapDiffuse, texture) // Set current map diffuse texture - - meshes = unsafe.Slice(obj.Meshes, obj.MeshCount) - bounds = rl.GetMeshBoundingBox(meshes[0]) - - // TODO: Move camera position from target enough distance to visualize model properly - } else if filepath.Ext(droppedFiles[0]) == ".png" { // Texture file formats supported - // Unload current model texture and load new one - rl.UnloadTexture(texture) - texture = rl.LoadTexture(droppedFiles[0]) - rl.SetMaterialTexture(obj.Materials, rl.MapDiffuse, texture) // Set current map diffuse texture - } - } - - rl.UnloadDroppedFiles() // Unload file paths from memory - } - - // Select model on mouse click - if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { - // Check collision between ray and box - if rl.GetRayCollisionBox(rl.GetMouseRay(rl.GetMousePosition(), camera), bounds).Hit { - selected = !selected - } else { - selected = false - } - } - rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) + rl.BeginMode3D(camera) rl.DrawModel(obj, position, 1.0, rl.White) // Draw 3d model with texture - rl.DrawGrid(20, 10.0) // Draw a grid - if selected { - rl.DrawBoundingBox(bounds, rl.Green) // Draw selection box - } + rl.DrawGrid(20, 10.0) // Draw a grid rl.EndMode3D() - rl.DrawText("Drag & drop model to load mesh/texture", 10, screenHeight-20, 10, rl.Gray) - if selected { - rl.DrawText("Model selected!", screenWidth-110, 10, 10, rl.Green) - } rl.DrawText("(c) Castle 3D model by Alberto Cano", screenWidth-200, screenHeight-20, 10, rl.Gray) - rl.DrawFPS(10, 10) rl.EndDrawing() } + rl.UnloadTexture(texture) // Unload texture rl.UnloadModel(obj) // Unload model diff --git a/examples/models/orthographic/main.go b/examples/models/orthographic/main.go deleted file mode 100644 index 977b180..0000000 --- a/examples/models/orthographic/main.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - - fovyPerspective := float32(45) - widthOrthographic := float32(10) - - screenWidth := int32(1280) - screenHeight := int32(800) - - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - orthographic") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(0.0, 10.0, 10.0) - camera.Target = rl.NewVector3(0.0, 0.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = fovyPerspective - camera.Projection = rl.CameraPerspective - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.UpdateCamera(&camera, rl.CameraOrbital) - - if rl.IsKeyPressed(rl.KeySpace) { - - if camera.Projection == rl.CameraPerspective { - camera.Fovy = widthOrthographic - camera.Projection = rl.CameraOrthographic - } else { - camera.Fovy = fovyPerspective - camera.Projection = rl.CameraPerspective - } - - } - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.DrawCube(rl.NewVector3(-4, 0, 2), 2, 5, 2, rl.Red) - rl.DrawCubeWires(rl.NewVector3(-4, 0, 2), 2, 5, 2, rl.Gold) - rl.DrawCubeWires(rl.NewVector3(-4, 0, -2), 3, 6, 2, rl.Maroon) - - rl.DrawSphere(rl.NewVector3(-1, 0, -2), 1, rl.Green) - rl.DrawSphereWires(rl.NewVector3(1, 0, 2), 2, 16, 16, rl.Lime) - - rl.DrawCylinder(rl.NewVector3(4, 0, -2), 1, 2, 3, 4, rl.SkyBlue) - rl.DrawCylinderWires(rl.NewVector3(4, 0, -2), 1, 2, 3, 4, rl.DarkBlue) - rl.DrawCylinderWires(rl.NewVector3(4.5, -1, 2), 1, 1, 2, 6, rl.Brown) - - rl.DrawCylinder(rl.NewVector3(1, 0, -4), 0, 1.5, 3, 8, rl.Gold) - rl.DrawCylinderWires(rl.NewVector3(1, 0, -4), 0, 1.5, 3, 8, rl.Pink) - - rl.DrawGrid(10, 1) - - rl.EndMode3D() - - rl.DrawText("PRESS SPACE TO CHANGE CAMERA PROJECTION", 10, 10, 20, rl.Black) - - if camera.Projection == rl.CameraPerspective { - rl.DrawText("CURRENT CAMERA PROJECTION IS PERSPECTIVE", 10, 30, 20, rl.Black) - } else { - rl.DrawText("CURRENT CAMERA PROJECTION IS ORTHOGRAPHIC", 10, 30, 20, rl.Black) - } - - rl.DrawFPS(screenWidth-100, 10) - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/models/rlgl_solar_system/main.go b/examples/models/rlgl_solar_system/main.go deleted file mode 100644 index e784465..0000000 --- a/examples/models/rlgl_solar_system/main.go +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - rlgl module usage with push/pop matrix transformations -* -* NOTE: This example uses [rlgl] module functionality (pseudo-OpenGL 1.1 style coding) -* -* Example originally created with raylib 2.5, last time updated with raylib 4.0 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2018-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 - - sunRadius = 4.0 - earthRadius = 0.6 - moonRadius = 0.16 - - earthOrbitRadius = 8.0 - moonOrbitRadius = 1.5 - - rings, slices = 16, 16 -) - -func main() { - // Initialization - title := "raylib [models] example - rlgl module usage with push/pop matrix transformations" - rl.InitWindow(screenWidth, screenHeight, title) - - // Define the camera to look into our 3d world - camera := rl.Camera{ - Position: rl.Vector3{ - X: 16.0, - Y: 16.0, - Z: 16.0, - }, // Camera position - Target: rl.Vector3{}, // Camera looking at point - Up: rl.Vector3{Y: 1.0}, // Camera up vector (rotation towards target) - Fovy: 45.0, // Camera field-of-view Y - Projection: rl.CameraPerspective, // Camera projection type - } - - var rotationSpeed float32 = 0.2 // General system rotation speed - var earthRotation float32 // Rotation of earth around itself (days) in degrees - var earthOrbitRotation float32 // Rotation of earth around the Sun (years) in degrees - var moonRotation float32 // Rotation of moon around itself - var moonOrbitRotation float32 // Rotation of moon around earth in degrees - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - rl.UpdateCamera(&camera, rl.CameraOrbital) - - earthRotation += 5.0 * rotationSpeed - earthOrbitRotation += 365 / 360.0 * (5.0 * rotationSpeed) * rotationSpeed - moonRotation += 2.0 * rotationSpeed - moonOrbitRotation += 8.0 * rotationSpeed - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - rl.BeginMode3D(camera) - - rl.PushMatrix() - rl.Scalef(sunRadius, sunRadius, sunRadius) // Scale Sun - DrawSphereBasic(rl.Gold) // Draw the Sun - rl.PopMatrix() - - rl.PushMatrix() - rl.Rotatef(earthOrbitRotation, 0.0, 1.0, 0.0) // Rotation for Earth orbit around Sun - rl.Translatef(earthOrbitRadius, 0.0, 0.0) // Translation for Earth orbit - - rl.PushMatrix() - rl.Rotatef(earthRotation, 0.25, 1.0, 0.0) // Rotation for Earth itself - rl.Scalef(earthRadius, earthRadius, earthRadius) // Scale Earth - - DrawSphereBasic(rl.Blue) // Draw the Earth - rl.PopMatrix() - - rl.Rotatef(moonOrbitRotation, 0.0, 1.0, 0.0) // Rotation for Moon orbit around Earth - rl.Translatef(moonOrbitRadius, 0.0, 0.0) // Translation for Moon orbit - rl.Rotatef(moonRotation, 0.0, 1.0, 0.0) // Rotation for Moon itself - rl.Scalef(moonRadius, moonRadius, moonRadius) // Scale Moon - - DrawSphereBasic(rl.LightGray) // Draw the Moon - rl.PopMatrix() - - // Some reference elements (not affected by previous matrix transformations) - rl.DrawCircle3D(rl.Vector3{}, earthOrbitRadius, rl.NewVector3(1, 0, 0), 90.0, rl.Fade(rl.Red, 0.5)) - rl.DrawGrid(20, 1.0) - - rl.EndMode3D() - - rl.DrawText("EARTH ORBITING AROUND THE SUN!", 400, 10, 20, rl.Maroon) - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - // De-Initialization - rl.CloseWindow() // Close window and OpenGL context -} - -// DrawSphereBasic draws a sphere without any matrix transformation -// NOTE: Sphere is drawn in world position ( 0, 0, 0 ) with radius 1.0f -func DrawSphereBasic(color rl.Color) { - // Make sure there is enough space in the internal render batch - // buffer to store all required vertex, batch is reset if required - rl.CheckRenderBatchLimit((rings + 2) * slices * 6) - - rl.Begin(rl.Triangles) - rl.Color4ub(color.R, color.G, color.B, color.A) - - for ring := int32(0); ring < (rings + 2); ring++ { - for slice := int32(0); slice < slices; slice++ { - rl.Vertex3f(getCoords(ring, slice)) - rl.Vertex3f(getCoords(ring+1, slice+1)) - rl.Vertex3f(getCoords(ring+1, slice)) - rl.Vertex3f(getCoords(ring, slice)) - rl.Vertex3f(getCoords(ring, slice+1)) - rl.Vertex3f(getCoords(ring+1, slice+1)) - } - } - rl.End() -} - -func getCoords(ring, slice int32) (x, y, z float32) { - ringF := float64(ring) - sliceF := float64(slice) - - // Calculate angels - alpha := rl.Deg2rad * (270 + (180/(float64(rings)+1))*ringF) - beta := rl.Deg2rad * (sliceF * 360 / float64(slices)) - - // Calculate coords - x = float32(math.Cos(alpha) * math.Sin(beta)) - y = float32(math.Sin(alpha)) - z = float32(math.Cos(alpha) * math.Cos(beta)) - - return x, y, z -} diff --git a/examples/models/skybox/main.go b/examples/models/skybox/main.go deleted file mode 100644 index 9307f53..0000000 --- a/examples/models/skybox/main.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - "fmt" - "path/filepath" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - skyboxFilename := "skybox.png" - - rl.InitWindow(800, 450, "raylib [models] example - skybox loading and drawing") - - camera := rl.NewCamera3D( - rl.NewVector3(1.0, 1.0, 1.0), - rl.NewVector3(4.0, 1.0, 4.0), - rl.NewVector3(0.0, 1.0, 0.0), - 45.0, - rl.CameraPerspective, - ) - - // load skybox shader and set required locations - skyboxShader := rl.LoadShader("skybox.vs", "skybox.fs") - - setShaderIntValue(skyboxShader, "environmentMap", rl.MapCubemap) - - // load skybox model - cube := rl.GenMeshCube(1.0, 1.0, 1.0) - skybox := rl.LoadModelFromMesh(cube) - - skybox.Materials.Shader = skyboxShader - - // load cubemap texture - skyboxImg := rl.LoadImage(skyboxFilename) - - skyboxTexture := rl.LoadTextureCubemap(skyboxImg, rl.CubemapLayoutAutoDetect) - - rl.UnloadImage(skyboxImg) - - rl.SetMaterialTexture(skybox.Materials, rl.MapCubemap, skyboxTexture) - - // limit cursor to relative movement inside the window - rl.DisableCursor() - - // set our game to run at 60 frames-per-second - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraFirstPerson) - - // load new cubemap texture on drag&drop - if rl.IsFileDropped() { - droppedFiles := rl.LoadDroppedFiles() - - // only support one file dropped - if len(droppedFiles) == 1 { - switch filepath.Ext(droppedFiles[0]) { - case ".png", ".jpg", ".bmp", ".tga": - skyboxFilename = droppedFiles[0] - - rl.UnloadTexture(skyboxTexture) - - img := rl.LoadImage(skyboxFilename) - - skyboxTexture = rl.LoadTextureCubemap(img, rl.CubemapLayoutAutoDetect) - - rl.UnloadImage(img) - - rl.SetMaterialTexture(skybox.Materials, rl.MapCubemap, skyboxTexture) - } - } - - rl.UnloadDroppedFiles() - } - - rl.BeginDrawing() - - rl.ClearBackground(rl.White) - - rl.BeginMode3D(camera) - - // we are inside the cube, we need to disable backface culling - rl.DisableBackfaceCulling() - rl.DisableDepthMask() - - rl.DrawModel(skybox, rl.NewVector3(0, 0, 0), 1.0, rl.White) - - // restore depth and backface culling - rl.EnableBackfaceCulling() - rl.EnableDepthMask() - - rl.DrawGrid(10, 1.0) - - rl.EndMode3D() - - rl.DrawText( - fmt.Sprintf("File: %s", skyboxFilename), - 10, - int32(rl.GetScreenHeight()-20), - 10, - rl.Black, - ) - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - rl.UnloadModel(skybox) - rl.UnloadTexture(skyboxTexture) - rl.UnloadShader(skyboxShader) - - rl.CloseWindow() -} - -func setShaderIntValue(shader rl.Shader, name string, value int32) { - rl.SetShaderValue( - shader, - rl.GetShaderLocation(shader, name), - unsafe.Slice((*float32)(unsafe.Pointer(&value)), 4), - rl.ShaderUniformInt, - ) -} diff --git a/examples/models/skybox/skybox.fs b/examples/models/skybox/skybox.fs deleted file mode 100644 index 25ae075..0000000 --- a/examples/models/skybox/skybox.fs +++ /dev/null @@ -1,19 +0,0 @@ -#version 330 - -// input vertex attributes (from vertex shader) -in vec3 fragPosition; - -// input uniform values -uniform samplerCube environmentMap; - -// output fragment color -out vec4 finalColor; - -void main() -{ - // fetch color from texture map - vec3 color = texture(environmentMap, fragPosition).rgb; - - // calculate final fragment color - finalColor = vec4(color, 1.0); -} \ No newline at end of file diff --git a/examples/models/skybox/skybox.png b/examples/models/skybox/skybox.png deleted file mode 100644 index 36a79b2..0000000 Binary files a/examples/models/skybox/skybox.png and /dev/null differ diff --git a/examples/models/skybox/skybox.vs b/examples/models/skybox/skybox.vs deleted file mode 100644 index e43c329..0000000 --- a/examples/models/skybox/skybox.vs +++ /dev/null @@ -1,24 +0,0 @@ -#version 330 - -// input vertex attributes -in vec3 vertexPosition; - -// input uniform values -uniform mat4 matProjection; -uniform mat4 matView; - -// output vertex attributes (to fragment shader) -out vec3 fragPosition; - -void main() -{ - // calculate fragment position based on model transformations - fragPosition = vertexPosition; - - // remove translation from the view matrix - mat4 rotView = mat4(mat3(matView)); - vec4 clipPos = matProjection*rotView*vec4(vertexPosition, 1.0); - - // calculate final vertex position - gl_Position = clipPos; -} \ No newline at end of file diff --git a/examples/models/vox_loading/knight.vox b/examples/models/vox_loading/knight.vox deleted file mode 100644 index c921bf5..0000000 Binary files a/examples/models/vox_loading/knight.vox and /dev/null differ diff --git a/examples/models/vox_loading/main.go b/examples/models/vox_loading/main.go deleted file mode 100644 index 5311042..0000000 --- a/examples/models/vox_loading/main.go +++ /dev/null @@ -1,82 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - voxel loading") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(10.0, 10.0, 10.0) - camera.Target = rl.NewVector3(0.0, 0.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 45.0 - camera.Projection = rl.CameraPerspective - - voxFiles := []string{"knight.vox", "sword.vox", "monument.vox"} - - var models []rl.Model - - for i := 0; i < len(voxFiles); i++ { - models = append(models, rl.LoadModel(voxFiles[i])) - bb := rl.GetModelBoundingBox(models[i]) - center := rl.Vector3Zero() - center.X = bb.Min.X + ((bb.Max.X - bb.Min.X) / 2) - center.Z = bb.Min.Z + ((bb.Max.Z - bb.Min.Z) / 2) - - matTranslate := rl.MatrixTranslate(-center.X, 0, -center.Z) - models[i].Transform = matTranslate - } - - currentModel := 0 - - rl.DisableCursor() - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.UpdateCamera(&camera, rl.CameraOrbital) - - if rl.IsKeyPressed(rl.KeyUp) { - currentModel++ - if currentModel >= len(models) { - currentModel = 0 - } - - } - if rl.IsKeyPressed(rl.KeyDown) { - currentModel-- - if currentModel < 0 { - currentModel = len(models) - 1 - } - - } - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.DrawModel(models[currentModel], rl.Vector3Zero(), 1, rl.White) - - rl.EndMode3D() - - rl.DrawText("current voxel file: "+voxFiles[currentModel], 10, 10, 10, rl.Black) - rl.DrawText("UP/DOWN ARROW KEYS CHANGE FILE", 10, 30, 10, rl.Black) - rl.DrawText("MOUSE SCROLL OR KEYPAD + / - TO CHANGE ZOOM", 10, 50, 10, rl.Black) - - rl.EndDrawing() - } - - for i := 0; i < len(models); i++ { - rl.UnloadModel(models[i]) - } - - rl.CloseWindow() -} diff --git a/examples/models/vox_loading/monument.vox b/examples/models/vox_loading/monument.vox deleted file mode 100644 index fd77111..0000000 Binary files a/examples/models/vox_loading/monument.vox and /dev/null differ diff --git a/examples/models/vox_loading/sword.vox b/examples/models/vox_loading/sword.vox deleted file mode 100644 index 05fc482..0000000 Binary files a/examples/models/vox_loading/sword.vox and /dev/null differ diff --git a/examples/models/waving_cubes/main.go b/examples/models/waving_cubes/main.go deleted file mode 100644 index 5fb874f..0000000 --- a/examples/models/waving_cubes/main.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - waving cubes") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(30.0, 20.0, 30.0) - camera.Target = rl.NewVector3(0.0, 0.0, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 70.0 - camera.Projection = rl.CameraPerspective - - numBloks := 15 - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - time := rl.GetTime() - - scale := (2 + float32(math.Sin(time))) * 0.7 - - camTime := time * 0.3 - - camera.Position.X = float32(math.Cos(camTime)) * 40 - camera.Position.Z = float32(math.Sin(camTime)) * 40 - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.DrawGrid(10, 5) - - for x := 0; x < numBloks; x++ { - - for y := 0; y < numBloks; y++ { - - for z := 0; z < numBloks; z++ { - - blockScale := float32((x + y + z)) / 30 - - scatter := math.Sin(float64(blockScale*20) + (time * 4)) - - cubePos := rl.NewVector3(float32((x-numBloks/2))*(scale*3)+float32(scatter), float32((y-numBloks/2))*(scale*2)+float32(scatter), float32((z-numBloks/2))*(scale*3)+float32(scatter)) - - cubeColor := rl.ColorFromHSV(float32(((x+y+z)*18)%360), 0.75, 0.9) - - cubeSize := (2.4 - scale) * blockScale - - rl.DrawCube(cubePos, cubeSize, cubeSize, cubeSize, cubeColor) - - } - } - } - - rl.EndMode3D() - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/models/yaw_pitch_roll/main.go b/examples/models/yaw_pitch_roll/main.go deleted file mode 100644 index 4fea2f3..0000000 --- a/examples/models/yaw_pitch_roll/main.go +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Plane rotations (yaw, pitch, roll) -* -* Example originally created with raylib 1.8, last time updated with raylib 4.0 -* -* Example contributed by Berni (@Berni8k) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2017-2024 Berni (@Berni8k) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - //SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI) - title := "raylib [models] example - plane rotations (yaw, pitch, roll)" - rl.InitWindow(screenWidth, screenHeight, title) - - camera := rl.Camera{ - Position: rl.Vector3{ - Y: 50.0, - Z: -120.0, - }, // Camera position perspective - Target: rl.Vector3{}, // Camera looking at point - Up: rl.Vector3{Y: 1.0}, // Camera up vector (rotation towards target) - Fovy: 30.0, // Camera field-of-view Y - Projection: rl.CameraPerspective, // Camera type - } - model := rl.LoadModel("plane.obj") // Load model - texture := rl.LoadTexture("plane_diffuse.png") // Load model texture - rl.SetMaterialTexture(model.Materials, rl.MapDiffuse, texture) // Set map diffuse texture - - var pitch, roll, yaw float32 - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - - // Plane pitch (x-axis) controls - pitch = controlPlane(pitch, 0.6, rl.KeyDown, rl.KeyUp) - // Plane yaw (y-axis) controls - roll = controlPlane(roll, 1.0, rl.KeyLeft, rl.KeyRight) - // Plane roll (z-axis) controls - yaw = controlPlane(yaw, 1.0, rl.KeyA, rl.KeyS) - - // Transformation matrix for rotations - rotationV := rl.Vector3{ - X: rl.Deg2rad * pitch, - Y: rl.Deg2rad * yaw, - Z: rl.Deg2rad * roll, - } - model.Transform = rl.MatrixRotateXYZ(rotationV) - - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - // Draw 3D model (recommended to draw 3D always before 2D) - rl.BeginMode3D(camera) - - // Draw 3d model with texture - rl.DrawModel(model, rl.Vector3{Y: -8.0}, 1.0, rl.White) - rl.DrawGrid(10, 10.0) - - rl.EndMode3D() - - // Draw controls info - rl.DrawRectangle(30, 370, 260, 70, rl.Fade(rl.Green, 0.5)) - rl.DrawRectangleLines(30, 370, 260, 70, rl.Fade(rl.DarkGreen, 0.5)) - rl.DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 380, 10, rl.DarkGray) - rl.DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 400, 10, rl.DarkGray) - rl.DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 420, 10, rl.DarkGray) - - rl.DrawText("(c) WWI Plane Model created by GiaHanLam", screenWidth-240, screenHeight-20, 10, rl.DarkGray) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadModel(model) // Unload model data - rl.UnloadTexture(texture) // Unload texture data - - rl.CloseWindow() // Close window and OpenGL context -} - -func controlPlane(ctrl, value float32, key1, key2 int32) float32 { - if rl.IsKeyDown(key1) { - ctrl -= value - } else if rl.IsKeyDown(key2) { - ctrl += value - } else { - if ctrl > 0.0 { - ctrl -= value / 2 - } else if ctrl < 0.0 { - ctrl += value / 2 - } - } - return ctrl -} diff --git a/examples/models/yaw_pitch_roll/plane.obj b/examples/models/yaw_pitch_roll/plane.obj deleted file mode 100644 index 29b5944..0000000 --- a/examples/models/yaw_pitch_roll/plane.obj +++ /dev/null @@ -1,10858 +0,0 @@ -# Blender v2.90.0 OBJ File: '' -# www.blender.org -o BODY_Material_#24_0 -v 2.545141 5.783802 -25.976692 -v 3.235504 6.677957 -13.125248 -v 1.687940 5.646317 -12.937294 -v -0.137555 3.728988 -25.602322 -v 0.973665 3.982364 -25.648491 -v -0.137555 5.284053 -12.871292 -v 0.973664 10.132854 -26.769033 -v 3.235504 13.408313 -14.351426 -v 4.269554 11.864355 -14.070142 -v 2.545140 8.331417 -26.440832 -v 4.632663 10.043135 -13.738335 -v 4.269555 8.221914 -13.406528 -v -0.137555 10.386230 -26.815191 -v -0.137555 14.802216 -14.605382 -v 1.687940 14.439952 -14.539380 -v -0.137555 10.386230 -26.815191 -v 0.973664 10.132854 -26.769033 -v -0.137555 10.132854 -26.769033 -v -0.137555 3.982364 -25.648491 -v 0.973665 3.982364 -25.648491 -v -0.137555 3.728988 -25.602322 -v 0.663374 15.705781 23.193211 -v 0.663374 14.114862 23.483055 -v 0.998288 14.910323 23.338135 -v 0.376462 18.602148 -30.355957 -v 0.330657 18.078314 -27.583200 -v 0.330657 17.075186 -24.744356 -v 0.376461 3.909487 -27.628571 -v 0.330618 3.524783 -30.914526 -v 0.285052 3.476720 -33.171906 -v 0.330657 11.401349 -24.776545 -v 0.376461 3.909487 -27.628571 -v 0.200132 4.545812 -36.862782 -v 0.200132 4.545812 -36.862782 -v 0.170088 5.657253 -38.139938 -v 0.170088 6.808916 -39.080044 -v 0.170088 12.034781 -40.236835 -v 0.170088 13.888091 -40.062054 -v 0.200132 15.707024 -39.244591 -v 0.200132 15.707024 -39.244591 -v 0.219588 17.377857 -38.011116 -v 0.285053 18.414829 -35.894424 -v 1.161025 13.829943 21.691204 -v 1.361917 14.567539 21.556824 -v 1.161026 15.305133 21.422447 -v 4.441549 12.221634 18.442724 -v 4.818830 14.087643 18.102762 -v 4.441548 15.953656 17.762800 -v 1.264851 22.121515 18.453445 -v 1.328365 22.272367 18.425961 -v 1.264851 22.423220 18.398476 -v 0.958179 22.423220 18.398476 -v 0.894666 22.272367 18.425961 -v 0.958179 22.121515 18.453445 -v 1.607252 21.900675 17.518620 -v 1.764696 22.274622 17.450493 -v 1.607252 22.648573 17.382362 -v 0.847047 22.648573 17.382362 -v 0.689604 22.274622 17.450493 -v 0.847048 21.900675 17.518620 -v 2.480337 19.942028 3.044717 -v 2.591266 20.552032 5.535551 -v 4.904634 19.031322 5.812605 -v 2.225156 18.538774 -2.685168 -v 3.460114 18.497147 0.467442 -v 4.473044 17.821404 0.554293 -v 2.406395 17.006306 3.793933 -v 3.460114 16.467627 0.837195 -v 2.406395 15.928947 -2.119541 -v -2.820251 5.783802 -25.976692 -v -1.963050 5.646317 -12.937294 -v -3.510613 6.677957 -13.125248 -v -0.137555 3.728988 -25.602322 -v -0.137555 5.284053 -12.871292 -v -1.248775 3.982364 -25.648491 -v -1.248774 10.132854 -26.769033 -v -4.544662 11.864355 -14.070142 -v -3.510613 13.408313 -14.351426 -v -2.820250 8.331417 -26.440832 -v -4.544664 8.221914 -13.406528 -v -4.907773 10.043135 -13.738335 -v -1.963049 14.439952 -14.539380 -v -0.137555 10.386230 -26.815191 -v -0.137555 10.132854 -26.769033 -v -1.248774 10.132854 -26.769033 -v -0.137555 3.982364 -25.648491 -v -0.137555 3.728988 -25.602322 -v -1.248775 3.982364 -25.648491 -v -0.938484 15.705781 23.193211 -v -1.273397 14.910323 23.338135 -v -0.938484 14.114862 23.483055 -v -0.651571 18.602148 -30.355957 -v -0.605767 17.075186 -24.744356 -v -0.605767 18.078314 -27.583200 -v -0.651571 3.909487 -27.628571 -v -0.560162 3.476720 -33.171906 -v -0.605727 3.524783 -30.914526 -v -0.605767 11.401349 -24.776545 -v -0.475242 4.545812 -36.862782 -v -0.651571 3.909487 -27.628571 -v -0.475242 4.545812 -36.862782 -v -0.445197 6.808916 -39.080044 -v -0.445197 5.657253 -38.139938 -v -0.445198 12.034781 -40.236835 -v -0.475242 15.707024 -39.244591 -v -0.445197 13.888091 -40.062054 -v -0.475242 15.707024 -39.244591 -v -0.560163 18.414829 -35.894424 -v -0.494698 17.377857 -38.011116 -v -1.436135 13.829943 21.691204 -v -1.436136 15.305133 21.422447 -v -1.637027 14.567539 21.556824 -v -4.716660 12.221634 18.442724 -v -4.716659 15.953656 17.762800 -v -5.093940 14.087643 18.102762 -v -1.539961 22.121515 18.453445 -v -1.539961 22.423220 18.398476 -v -1.603475 22.272367 18.425961 -v -1.233289 22.423220 18.398476 -v -1.233289 22.121515 18.453445 -v -1.169775 22.272367 18.425961 -v -1.882362 21.900675 17.518620 -v -1.882362 22.648573 17.382362 -v -2.039805 22.274622 17.450493 -v -1.122157 22.648573 17.382362 -v -1.122157 21.900675 17.518620 -v -0.964713 22.274622 17.450493 -v -2.755446 19.942028 3.044717 -v -5.179746 19.031322 5.812605 -v -2.866376 20.552032 5.535551 -v -2.500265 18.538774 -2.685168 -v -4.748155 17.821404 0.554293 -v -3.735223 18.497147 0.467442 -v -2.681505 17.006306 3.793933 -v -2.681505 15.928947 -2.119541 -v -3.735224 16.467627 0.837195 -v 5.886480 9.962349 1.986112 -v 4.473047 7.797970 2.380435 -v 6.382811 12.515405 1.520978 -v 2.357693 6.351778 2.643912 -v -0.137555 5.843942 2.736434 -v -0.137555 18.750629 -3.898979 -v 5.886480 15.068464 1.055844 -v -0.137555 21.086037 5.438262 -v -0.137555 20.817574 4.364942 -v -0.137555 15.705820 -3.344262 -v -0.137555 17.229437 5.018654 -v 2.406395 17.006306 3.793933 -v 2.480337 19.942028 3.044717 -v 3.460114 18.497147 0.467442 -v 3.460114 16.467627 0.837195 -v -0.137555 17.229437 5.018654 -v -0.137555 20.817574 4.364942 -v 2.480337 19.942028 3.044717 -v 2.406395 17.006306 3.793933 -v 2.406395 15.928947 -2.119541 -v 2.225156 18.538774 -2.685168 -v -0.137555 18.750629 -3.898979 -v -0.137555 15.705820 -3.344262 -v 3.460114 16.467627 0.837195 -v 3.460114 18.497147 0.467442 -v 6.450380 10.797626 7.312677 -v 4.904636 8.521720 7.727320 -v 6.993171 13.482239 6.823577 -v 2.591268 7.001008 8.004374 -v -0.137555 6.467003 8.101662 -v 6.450378 16.166853 6.334475 -v 0.973664 10.132854 -26.769033 -v 2.545140 8.331417 -26.440832 -v -0.137555 8.331417 -26.440832 -v -0.137555 10.132854 -26.769033 -v 2.545140 8.331417 -26.440832 -v 2.545141 5.783802 -25.976692 -v -0.137555 5.783802 -25.976692 -v -0.137555 8.331417 -26.440832 -v -0.137555 5.783802 -25.976692 -v 2.545141 5.783802 -25.976692 -v 0.973665 3.982364 -25.648491 -v -0.137555 3.982364 -25.648491 -v -0.137555 27.150551 8.418542 -v 10.657262 27.150551 8.418542 -v 10.657262 27.734844 13.241050 -v -0.137555 27.734844 13.241050 -v 10.657262 27.734844 13.241050 -v 10.657262 28.271790 13.143222 -v -0.137555 28.271790 13.143222 -v -0.137555 27.734844 13.241050 -v -0.137555 26.248919 3.469610 -v 10.657262 26.245462 3.654478 -v 21.452074 26.836880 8.475688 -v 21.452074 27.421173 13.298194 -v 21.452074 27.421173 13.298194 -v 21.452074 27.958118 13.200370 -v 10.657262 28.271790 13.143222 -v 10.657262 27.936581 8.275336 -v -0.137555 27.936581 8.275336 -v -0.137555 28.271790 13.143222 -v 2.342535 26.107084 2.691110 -v 10.657262 26.074389 2.673605 -v 21.452074 25.931791 3.711624 -v 32.246895 26.201221 8.591496 -v 32.246895 26.785511 13.414004 -v 32.246895 26.785511 13.414004 -v 32.246895 27.322460 13.316178 -v 21.452074 27.958118 13.200370 -v 21.452074 27.622913 8.332482 -v 10.657262 27.103384 3.498175 -v -0.137555 27.034948 3.326405 -v 6.234208 24.407400 -5.868575 -v 10.657262 24.407400 -5.868575 -v 10.657262 25.029203 -2.931825 -v 5.849846 25.098688 -2.843851 -v 21.452074 25.760714 2.730751 -v 32.246895 25.296129 3.827433 -v 41.450764 25.660938 8.689931 -v 38.136772 26.311825 13.500302 -v 38.136772 26.311825 13.500302 -v 38.136772 26.848774 13.402480 -v 32.246895 27.322460 13.316178 -v 32.246895 26.987251 8.448291 -v 21.452074 26.789709 3.555321 -v 10.657262 26.917547 2.519993 -v 2.342535 26.893122 2.547905 -v 10.657262 24.911684 -5.960440 -v 10.657262 24.407400 -5.868575 -v 6.234208 24.407400 -5.868575 -v 6.234208 24.911684 -5.960440 -v 21.452074 24.715536 -2.874681 -v 21.452074 25.098589 -1.065534 -v 10.657262 25.412260 -1.122682 -v 32.246895 25.125055 2.846561 -v 43.041698 24.755846 3.925868 -v 41.450764 25.660938 8.689931 -v 41.450764 26.446968 8.546725 -v 38.136772 26.848774 13.402480 -v 38.136772 26.311825 13.500302 -v 38.136772 26.848774 13.402480 -v 41.450764 26.446968 8.546725 -v 32.246895 26.154055 3.671129 -v 21.452074 26.603876 2.577139 -v 10.657262 26.198298 -1.265890 -v 10.657262 25.707838 -3.055464 -v 5.849846 25.884718 -2.987059 -v 5.429670 26.198298 -1.265890 -v 21.452074 24.598013 -5.903296 -v 21.452074 24.093729 -5.811423 -v 32.246895 24.079874 -2.758871 -v 32.246895 24.462931 -0.949727 -v 43.041698 24.584768 2.944992 -v 43.041698 24.755846 3.925868 -v 43.041698 25.613764 3.769564 -v 41.450764 25.660938 8.689931 -v 43.041698 25.613764 3.769564 -v 32.246883 25.968218 2.692949 -v 21.452074 25.884623 -1.208742 -v 21.452074 25.394167 -2.998319 -v 32.246895 23.962353 -5.787486 -v 32.246895 23.458073 -5.695620 -v 41.915051 23.539589 -2.660438 -v 43.041698 23.922642 -0.851296 -v 43.041698 24.584768 2.944992 -v 43.041698 25.427927 2.791382 -v 43.041698 25.427927 2.791382 -v 32.246895 25.248964 -1.092931 -v 32.246895 24.758509 -2.882509 -v 40.086185 23.422073 -5.689055 -v 40.086185 22.917782 -5.597183 -v 43.041698 23.922642 -0.851296 -v 41.915051 23.539589 -2.660438 -v 41.915051 24.218218 -2.784075 -v 43.041698 24.708681 -0.994498 -v 43.041698 24.708681 -0.994498 -v 41.915051 24.218218 -2.784075 -v -0.137555 26.248919 3.469610 -v -0.137555 27.034948 3.326405 -v 2.342535 26.893122 2.547905 -v 2.342535 26.107084 2.691110 -v 5.429670 26.198298 -1.265890 -v 5.429670 25.412260 -1.122682 -v 6.234208 24.911684 -5.960440 -v 6.234208 24.407400 -5.868575 -v 5.849846 25.098688 -2.843851 -v 5.849846 25.884718 -2.987059 -v 21.452074 24.093729 -5.811423 -v 32.246895 23.458073 -5.695620 -v 21.452074 24.598013 -5.903296 -v 10.657262 24.911684 -5.960440 -v 40.086185 22.917782 -5.597183 -v 32.246895 23.962353 -5.787486 -v 40.086185 22.917782 -5.597183 -v 40.086185 23.422073 -5.689055 -v 40.086185 23.422073 -5.689055 -v 5.429670 25.412260 -1.122682 -v 6.234208 24.911684 -5.960440 -v 0.301038 3.263966 -5.783109 -v 0.197856 3.753135 -5.871772 -v 31.931070 10.162366 -7.040006 -v 32.026306 9.709085 -6.957421 -v 39.669945 11.589635 -7.300035 -v 39.736111 11.274701 -7.242656 -v 0.387923 6.649406 14.232206 -v 32.075500 13.113069 13.054610 -v 31.962679 13.650052 12.956777 -v 0.266163 7.228906 14.126631 -v 37.826111 14.319102 12.834886 -v 37.726982 14.790937 12.748921 -v 32.026306 9.709085 -6.957421 -v 32.085331 10.333307 -1.938074 -v 0.387387 3.865942 -0.760052 -v 0.301038 3.263966 -5.783109 -v 39.736111 11.274701 -7.242656 -v 42.631611 12.549485 -2.430761 -v 42.539577 12.987517 -2.510567 -v 42.558872 13.816903 2.562746 -v 42.650913 13.378873 2.642551 -v 42.631611 12.549485 -2.430761 -v 31.952864 10.963766 -2.052936 -v 31.980639 11.746195 2.991455 -v 42.558872 13.816903 2.562746 -v 42.539577 12.987517 -2.510567 -v 31.931070 10.162366 -7.040006 -v 0.197856 3.753135 -5.871772 -v 0.243875 4.546322 -0.883360 -v 39.669945 11.589635 -7.300035 -v 42.539577 12.987517 -2.510567 -v 42.631611 12.549485 -2.430761 -v 39.736111 11.274701 -7.242656 -v 32.075500 13.113069 13.054610 -v 0.387923 6.649406 14.232206 -v 0.498981 5.383774 9.351863 -v 32.146481 11.874181 8.170041 -v 0.322121 6.222238 9.199900 -v 0.266163 7.228906 14.126631 -v 31.962679 13.650052 12.956777 -v 31.983232 12.651127 8.028491 -v 37.726982 14.790937 12.748921 -v 37.826111 14.319102 12.834886 -v 41.148281 13.882128 7.790358 -v 41.034866 14.421938 7.692010 -v 37.826111 14.319102 12.834886 -v 41.148281 13.882128 7.790358 -v 37.726982 14.790937 12.748921 -v 41.034866 14.421938 7.692010 -v 32.113106 11.115736 3.106316 -v 0.440122 4.637904 4.286060 -v 0.296608 5.318285 4.162748 -v 42.650913 13.378873 2.642551 -v 39.669945 11.589635 -7.300035 -v 4.091239 8.149817 -35.663517 -v 5.559022 7.933621 -36.487488 -v 10.651894 10.839343 -20.973984 -v 2.289506 10.581471 -20.926994 -v 2.316500 11.808965 -21.150627 -v 4.136919 9.079532 -35.830589 -v -0.137555 10.420605 -28.919138 -v -0.137555 11.835061 -21.155396 -v -0.137555 10.607282 -20.931702 -v 2.289506 10.581471 -20.926994 -v 2.316500 11.808965 -21.150627 -v -0.137555 11.835061 -21.155396 -v 10.651894 10.839343 -20.973984 -v 10.753733 11.399936 -21.076115 -v 12.581096 10.727206 -20.953552 -v 12.692742 11.199199 -21.039536 -v 15.755084 9.283175 -24.701189 -v 15.931952 9.756166 -24.787363 -v 15.310983 10.176061 -23.504894 -v 15.140950 9.703977 -23.418880 -v 17.404955 7.330409 -32.602814 -v 17.600180 7.780162 -32.684757 -v 13.768648 7.331349 -36.377769 -v 5.559022 7.933621 -36.487488 -v 5.622406 8.862197 -36.656662 -v 13.907855 7.973525 -36.291916 -v -0.137555 10.420605 -28.919138 -v 4.136919 9.079532 -35.830589 -v 4.091239 8.149817 -35.663517 -v -0.137555 9.192825 -28.695456 -v 12.692742 11.199199 -21.039536 -v 12.581096 10.727206 -20.953552 -v 16.102695 7.227387 -35.385410 -v 16.283424 7.700906 -35.471687 -v 16.283424 7.700906 -35.471687 -v 16.102695 7.227387 -35.385410 -v 15.310983 10.176061 -23.504894 -v 16.283424 7.700906 -35.471687 -v 13.907855 7.973525 -36.291916 -v 12.692742 11.199199 -21.039536 -v 10.753733 11.399936 -21.076115 -v 5.622406 8.862197 -36.656662 -v 17.404955 7.330409 -32.602814 -v 15.755084 9.283175 -24.701189 -v 15.140950 9.703977 -23.418880 -v 16.102695 7.227387 -35.385410 -v 13.768648 7.331349 -36.377769 -v 12.581096 10.727206 -20.953552 -v 15.931952 9.756166 -24.787363 -v 17.600180 7.780162 -32.684757 -v 30.305048 12.463110 10.208496 -v 30.963701 12.438213 10.208937 -v 30.813036 26.748894 11.243511 -v 30.154379 26.773792 11.243069 -v 30.963701 12.438213 10.208937 -v 30.960356 12.540001 8.359914 -v 30.809679 26.850677 9.394487 -v 30.813036 26.748894 11.243511 -v 30.960356 12.540001 8.359914 -v 30.301702 12.564899 8.359473 -v 30.151026 26.875576 9.394049 -v 30.809679 26.850677 9.394487 -v 30.301702 12.564899 8.359473 -v 30.305048 12.463110 10.208496 -v 30.154379 26.773792 11.243069 -v 30.151026 26.875576 9.394049 -v 0.634450 18.576508 2.205827 -v 0.634450 20.241886 1.902417 -v 1.850016 20.241886 1.902417 -v 1.850016 18.576508 2.205827 -v 0.634450 18.658239 2.654441 -v 1.850016 18.658239 2.654441 -v 1.850016 20.323616 2.351031 -v 0.634450 20.323616 2.351031 -v 0.634450 18.576508 2.205827 -v 1.850016 18.576508 2.205827 -v 1.850016 18.658239 2.654441 -v 0.634450 18.658239 2.654441 -v 1.850016 18.576508 2.205827 -v 1.850016 20.241886 1.902417 -v 1.850016 20.323616 2.351031 -v 1.850016 18.658239 2.654441 -v 1.850016 20.241886 1.902417 -v 0.634450 20.241886 1.902417 -v 0.634450 20.323616 2.351031 -v 1.850016 20.323616 2.351031 -v 0.634450 20.241886 1.902417 -v 0.634450 18.576508 2.205827 -v 0.634450 18.658239 2.654441 -v 0.634450 20.323616 2.351031 -v 6.450358 16.871246 6.704314 -v 6.450358 17.393959 9.573412 -v 6.993151 13.322628 10.315155 -v 6.993151 12.799915 7.446060 -v 4.904616 19.147156 6.289673 -v 4.904616 19.669867 9.158772 -v 2.591246 20.667866 6.012619 -v 2.591246 21.190580 8.881716 -v -0.137555 21.201870 5.915332 -v -0.137555 21.724585 8.784430 -v 2.591248 6.318684 8.626856 -v 2.591248 6.841393 11.495952 -v -0.137555 6.307393 11.593240 -v -0.137555 5.784679 8.724144 -v 4.904616 7.839396 8.349802 -v 4.904616 8.362108 11.218898 -v 6.450361 10.115304 7.935161 -v 6.450361 10.638018 10.804259 -v 6.450361 16.632854 11.177889 -v 6.993151 13.581101 11.733877 -v 6.993151 13.322628 10.315155 -v 6.450358 17.393959 9.573412 -v 4.904616 18.908764 10.763247 -v 4.904616 19.669867 9.158772 -v 2.591246 20.429476 10.486194 -v 2.591246 21.190580 8.881716 -v -0.137555 20.963480 10.388906 -v -0.137555 21.724585 8.784430 -v 2.591248 7.099868 12.914675 -v -0.137555 6.565864 13.011965 -v -0.137555 6.307393 11.593240 -v 2.591248 6.841393 11.495952 -v 4.904616 8.620581 12.637621 -v 4.904616 8.362108 11.218898 -v 6.450361 10.896488 12.222981 -v 6.450361 10.638018 10.804259 -v 6.450361 16.489346 12.240279 -v 6.993151 13.763827 12.736833 -v 6.993151 13.581101 11.733877 -v 6.450361 16.632854 11.177889 -v 4.904616 18.765253 11.825639 -v 4.904616 18.908764 10.763247 -v 2.591246 20.285967 11.548583 -v 2.591246 20.429476 10.486194 -v -0.137555 20.819971 11.451295 -v -0.137555 20.963480 10.388906 -v 2.591248 7.282592 13.917631 -v -0.137555 6.748590 14.014921 -v -0.137555 6.565864 13.011965 -v 2.591248 7.099868 12.914675 -v 4.904616 8.803307 13.640577 -v 4.904616 8.620581 12.637621 -v 6.450361 11.079216 13.225934 -v 6.450361 10.896488 12.222981 -v 6.450358 16.850937 14.456967 -v 6.993151 14.166320 14.946074 -v 6.993151 13.763827 12.736833 -v 6.450361 16.489346 12.240279 -v 4.904615 19.126841 14.042328 -v 4.904616 18.765253 11.825639 -v 2.591246 20.647554 13.765274 -v 2.591246 20.285967 11.548583 -v -0.137555 21.181559 13.667984 -v -0.137555 20.819971 11.451295 -v 2.591248 7.685090 16.126867 -v -0.137555 7.151085 16.224155 -v -0.137555 6.748590 14.014921 -v 2.591248 7.282592 13.917631 -v 4.904616 9.205801 15.849814 -v 4.904616 8.803307 13.640577 -v 6.450361 11.481709 15.435171 -v 6.450361 11.079216 13.225934 -v 6.450358 16.871246 6.704314 -v 6.993151 12.799915 7.446060 -v 5.267464 12.946739 7.419309 -v 4.856030 16.032776 6.857073 -v 4.904616 19.147156 6.289673 -v 3.684370 17.757896 6.542778 -v 2.591246 20.667866 6.012619 -v 1.930855 18.910583 6.332776 -v -0.137555 21.201870 5.915332 -v -0.137555 19.315353 6.259032 -v 2.591248 6.318684 8.626856 -v -0.137555 5.784679 8.724144 -v -0.137555 7.629245 8.388088 -v 1.930856 8.034017 8.314344 -v 4.904616 7.839396 8.349802 -v 3.684371 9.186704 8.104342 -v 6.450361 10.115304 7.935161 -v 4.856033 10.911824 7.790046 -v 6.358034 16.913443 14.535474 -v 6.358034 17.286711 16.584303 -v 6.893217 14.639720 17.066553 -v 6.893217 14.266452 15.017725 -v 4.833952 19.157454 14.126644 -v 4.833952 19.530722 16.175474 -v 2.553005 20.656855 13.853474 -v 2.553004 21.030119 15.902303 -v -0.137555 21.183367 13.757549 -v -0.137555 21.556639 15.806378 -v 2.553006 7.876051 16.181973 -v 2.553005 8.280234 18.225168 -v -0.137555 7.753714 18.321089 -v -0.137555 7.349532 16.277897 -v 4.833952 9.375453 15.908801 -v 4.833954 9.748725 17.957628 -v 2.553005 8.280234 18.225168 -v 2.553006 7.876051 16.181973 -v 6.358034 11.619465 15.499971 -v 6.358034 11.992731 17.548800 -v 4.833954 9.748725 17.957628 -v 4.833952 9.375453 15.908801 -v 3.367140 17.535583 17.474588 -v 3.367140 10.639707 18.730930 -v 7.131627 17.223406 19.063496 -v 5.827884 16.925011 20.438580 -v 6.319389 14.494061 20.881462 -v 7.730550 14.261175 19.603176 -v 5.426033 19.734667 18.605974 -v 4.428194 18.985874 20.063118 -v 2.873438 21.412638 18.300266 -v 2.333411 20.362902 19.812241 -v -0.137555 22.001863 18.192917 -v -0.137555 20.846445 19.724144 -v 2.873440 7.109707 20.906082 -v 2.333412 8.625226 21.950691 -v -0.137555 8.141681 22.038780 -v -0.137555 6.520483 21.013433 -v 5.426036 8.787681 20.600376 -v 4.428196 10.002252 21.699814 -v 7.131627 11.298944 20.142857 -v 5.827887 12.063114 21.324352 -v 6.319389 14.494061 20.881462 -v 5.827884 16.925011 20.438580 -v 4.652434 16.446011 20.525845 -v 5.047093 14.494061 20.881462 -v 4.428194 18.985874 20.063118 -v 3.528546 18.100796 20.224361 -v 2.333411 20.362902 19.812241 -v 1.846524 19.206488 20.022923 -v -0.137555 20.846445 19.724144 -v -0.137555 19.594753 19.952187 -v -0.137555 8.141681 22.038780 -v 2.333412 8.625226 21.950691 -v 1.846525 9.781638 21.740005 -v -0.137555 9.393373 21.810745 -v 4.428196 10.002252 21.699814 -v 3.528547 10.887330 21.538559 -v 5.827887 12.063114 21.324352 -v 4.652437 12.542114 21.237080 -v 4.652434 16.446011 20.525845 -v 4.441548 15.953656 17.762800 -v 4.818830 14.087643 18.102762 -v 5.047093 14.494061 20.881462 -v 3.528546 18.100796 20.224361 -v 3.367140 17.535583 17.474588 -v 1.846524 19.206488 20.022923 -v 1.759172 18.592596 17.282019 -v -0.137555 19.594753 19.952187 -v -0.137555 18.963770 17.214392 -v 1.846525 9.781638 21.740005 -v 1.759172 9.582694 18.923504 -v -0.137555 9.211522 18.991127 -v -0.137555 9.393373 21.810745 -v 3.528547 10.887330 21.538559 -v 3.367140 10.639707 18.730930 -v 4.652437 12.542114 21.237080 -v 4.441549 12.221634 18.442724 -v 7.061548 17.029957 17.660933 -v 7.654699 14.096279 18.195410 -v 6.893217 14.639720 17.066553 -v 6.358034 17.286711 16.584303 -v 5.372399 19.517012 17.207823 -v 4.833952 19.530722 16.175474 -v 2.844412 21.178797 16.905069 -v 2.553004 21.030119 15.902303 -v -0.137555 21.762342 16.798756 -v -0.137555 21.556639 15.806378 -v 2.844412 7.013754 19.485758 -v -0.137555 6.430205 19.592070 -v -0.137555 7.753714 18.321089 -v 5.372402 8.675551 19.182995 -v 7.061551 11.162606 18.729893 -v 6.358034 11.992731 17.548800 -v 7.131627 17.223406 19.063496 -v 7.730550 14.261175 19.603176 -v 7.654699 14.096279 18.195410 -v 7.061548 17.029957 17.660933 -v 5.426033 19.734667 18.605974 -v 5.372399 19.517012 17.207823 -v 2.873438 21.412638 18.300266 -v 2.844412 21.178797 16.905069 -v -0.137555 22.001863 18.192917 -v -0.137555 21.762342 16.798756 -v 2.873440 7.109707 20.906082 -v -0.137555 6.520483 21.013433 -v -0.137555 6.430205 19.592070 -v 2.844412 7.013754 19.485758 -v 5.426036 8.787681 20.600376 -v 5.372402 8.675551 19.182995 -v 7.131627 11.298944 20.142857 -v 7.061551 11.162606 18.729893 -v 10.347656 -5.313800 13.892914 -v 10.189377 -4.324817 14.341125 -v 10.173791 -4.065199 8.973198 -v 10.189374 -5.093708 9.342202 -v 9.902440 -2.803895 8.298583 -v 10.613137 -2.555629 8.260398 -v 10.749097 -4.127771 8.234436 -v 10.021957 -4.190809 8.244131 -v 9.801115 -1.547646 8.867919 -v 10.497879 -1.142371 8.805583 -v 9.733415 -0.613330 9.865463 -v 10.420865 -0.103137 9.786989 -v 9.709641 -0.143181 11.139349 -v 10.393823 0.403852 11.055208 -v 9.733415 -0.208778 12.495639 -v 10.420865 0.301416 12.417167 -v 9.722919 -0.800133 13.727847 -v 10.497879 -0.394859 13.665511 -v 9.824161 -1.827220 14.648387 -v 10.613143 -1.578959 14.610202 -v 9.943579 -3.133664 15.117107 -v 10.749100 -3.070621 15.107410 -v 10.062968 -4.520590 15.062659 -v 10.885056 -4.642758 15.081449 -v 10.144868 -5.776834 14.493324 -v 11.004154 -6.056028 14.536266 -v 10.221666 -6.653613 13.486927 -v 11.091516 -6.927130 13.528999 -v 11.004154 -6.056028 14.536266 -v 10.144868 -5.776834 14.493324 -v 10.248635 -7.046638 12.201180 -v 11.122193 -7.346391 12.247284 -v 10.221666 -7.058166 10.856751 -v 11.091516 -7.331683 10.898822 -v 10.144865 -6.524346 9.633391 -v 11.004151 -6.803540 9.676335 -v 10.062968 -5.497261 8.712852 -v 10.885054 -5.619434 8.731646 -v 11.410480 -5.221654 13.878742 -v 11.529890 -5.957200 13.093418 -v 11.410480 -5.810138 10.052730 -v 11.364158 -5.001564 9.328028 -v 9.902440 -2.803895 8.298583 -v 10.021957 -4.190809 8.244131 -v 10.021960 -4.078360 8.975224 -v 9.927868 -2.986496 9.018088 -v 10.062968 -5.497261 8.712852 -v 10.037540 -5.106868 9.344226 -v 10.144865 -6.524346 9.633391 -v 10.195823 -5.915451 10.068927 -v 10.221666 -7.058166 10.856751 -v 10.152031 -6.380999 11.038991 -v 10.248635 -7.046638 12.201180 -v 10.173262 -6.432639 12.106741 -v 10.221666 -6.653613 13.486927 -v 10.152031 -6.062517 13.109615 -v 10.144868 -5.776834 14.493324 -v 10.195823 -5.326966 13.894939 -v 10.144868 -5.776834 14.493324 -v 10.062968 -4.520590 15.062659 -v 10.037540 -4.337977 14.343151 -v 10.195823 -5.326966 13.894939 -v 9.943579 -3.133664 15.117107 -v 10.021963 -3.246119 14.386018 -v 9.824161 -1.827220 14.648387 -v 9.927871 -2.217605 14.017013 -v 9.722919 -0.800133 13.727847 -v 9.848101 -1.409030 13.292312 -v 9.733415 -0.208778 12.495639 -v 9.794803 -0.943481 12.322249 -v 9.709641 -0.143181 11.139349 -v 9.776086 -0.891838 11.254501 -v 9.733415 -0.613330 9.865463 -v 9.794800 -1.261969 10.251627 -v 9.801115 -1.547646 8.867919 -v 9.848098 -1.997514 9.466303 -v 11.388451 -4.072338 8.225910 -v 11.268930 -2.685418 8.280360 -v 11.294358 -2.868025 8.999867 -v 11.388016 -3.954838 8.957199 -v 11.167605 -1.429169 8.849696 -v 11.214588 -1.879037 9.448082 -v 11.099905 -0.494853 9.847242 -v 11.161290 -1.143492 10.233404 -v 11.076132 -0.024707 11.121126 -v 11.142576 -0.773364 11.236277 -v 11.099905 -0.090303 12.477416 -v 11.161293 -0.825004 12.304027 -v 11.167608 -0.681659 13.709624 -v 11.214591 -1.290552 13.274091 -v 11.268933 -1.708743 14.630164 -v 11.294361 -2.099133 13.998790 -v 11.388453 -3.015193 15.098885 -v 11.388453 -3.127642 14.367793 -v 11.541418 -4.402113 15.044438 -v 11.515990 -4.219506 14.324928 -v 11.694958 -5.658357 14.475101 -v 11.562313 -5.208493 13.876717 -v 11.694958 -5.658357 14.475101 -v 11.771752 -6.569247 13.473953 -v 11.702118 -5.944039 13.091393 -v 11.562313 -5.208493 13.876717 -v 11.798721 -6.962277 12.188204 -v 11.723349 -6.314167 12.088518 -v 11.771752 -6.973800 10.843776 -v 11.702118 -6.262527 11.020768 -v 11.694952 -6.405869 9.615170 -v 11.562313 -5.796978 10.050706 -v 11.541418 -5.378782 8.694632 -v 11.515990 -4.988397 9.326004 -v 9.927868 -2.986496 9.018088 -v 10.021960 -4.078360 8.975224 -v 10.173791 -4.065199 8.973198 -v 10.079700 -2.973335 9.016065 -v 10.037540 -5.106868 9.344226 -v 10.189374 -5.093708 9.342202 -v 10.195823 -5.915451 10.068927 -v 10.347653 -5.902290 10.066901 -v 10.152031 -6.380999 11.038991 -v 10.324265 -6.367838 11.036967 -v 10.173262 -6.432639 12.106741 -v 10.345494 -6.419479 12.104715 -v 10.152031 -6.062517 13.109615 -v 10.324265 -6.049350 13.107590 -v 10.195823 -5.326966 13.894939 -v 10.347656 -5.313800 13.892914 -v 10.195823 -5.326966 13.894939 -v 10.037540 -4.337977 14.343151 -v 10.189377 -4.324817 14.341125 -v 10.347656 -5.313800 13.892914 -v 10.021963 -3.246119 14.386018 -v 10.173796 -3.232952 14.383994 -v 9.927871 -2.217605 14.017013 -v 10.079700 -2.204439 14.014987 -v 9.848101 -1.409030 13.292312 -v 9.999933 -1.395863 13.290288 -v 9.794803 -0.943481 12.322249 -v 9.946635 -0.930319 12.320226 -v 9.776086 -0.891838 11.254501 -v 9.927916 -0.878675 11.252476 -v 9.794800 -1.261969 10.251627 -v 9.946632 -1.248802 10.249601 -v 9.848098 -1.997514 9.466303 -v 9.999930 -1.984348 9.464279 -v 11.388016 -3.954838 8.957199 -v 11.294358 -2.868025 8.999867 -v 11.142525 -2.881190 9.001891 -v 11.236621 -3.973048 8.959024 -v 11.214588 -1.879037 9.448082 -v 11.062758 -1.892203 9.450106 -v 11.161290 -1.143492 10.233404 -v 11.009460 -1.156657 10.235428 -v 11.142576 -0.773364 11.236277 -v 10.990744 -0.786530 11.238302 -v 11.161293 -0.825004 12.304027 -v 11.009460 -0.838170 12.306050 -v 11.214591 -1.290552 13.274091 -v 11.062758 -1.303718 13.276114 -v 11.294361 -2.099133 13.998790 -v 11.142528 -2.112300 14.000815 -v 11.388453 -3.127642 14.367793 -v 11.236621 -3.140807 14.369819 -v 11.515990 -4.219506 14.324928 -v 11.364158 -4.232666 14.326954 -v 11.562313 -5.208493 13.876717 -v 11.410480 -5.221654 13.878742 -v 11.562313 -5.208493 13.876717 -v 11.702118 -5.944039 13.091393 -v 11.529890 -5.957200 13.093418 -v 11.410480 -5.221654 13.878742 -v 11.723349 -6.314167 12.088518 -v 11.551121 -6.327328 12.090542 -v 11.702118 -6.262527 11.020768 -v 11.529890 -6.275688 11.022794 -v 11.562313 -5.796978 10.050706 -v 11.410480 -5.810138 10.052730 -v 11.515990 -4.988397 9.326004 -v 11.364158 -5.001564 9.328028 -v 11.268930 -2.685418 8.280360 -v 11.388451 -4.072338 8.225910 -v 10.749097 -4.127771 8.234436 -v 10.613137 -2.555629 8.260398 -v 11.167605 -1.429169 8.849696 -v 10.497879 -1.142371 8.805583 -v 11.099905 -0.494853 9.847242 -v 10.420865 -0.103137 9.786989 -v 11.076132 -0.024707 11.121126 -v 10.393823 0.403852 11.055208 -v 11.099905 -0.090303 12.477416 -v 10.420865 0.301416 12.417167 -v 11.167608 -0.681659 13.709624 -v 10.497879 -0.394859 13.665511 -v 11.268933 -1.708743 14.630164 -v 10.613143 -1.578959 14.610202 -v 11.388453 -3.015193 15.098885 -v 10.749100 -3.070621 15.107410 -v 11.541418 -4.402113 15.044438 -v 10.885056 -4.642758 15.081449 -v 11.694958 -5.658357 14.475101 -v 11.004154 -6.056028 14.536266 -v 11.771752 -6.569247 13.473953 -v 11.694958 -5.658357 14.475101 -v 11.004154 -6.056028 14.536266 -v 11.091516 -6.927130 13.528999 -v 11.798721 -6.962277 12.188204 -v 11.122193 -7.346391 12.247284 -v 11.771752 -6.973800 10.843776 -v 11.091516 -7.331683 10.898822 -v 11.694952 -6.405869 9.615170 -v 11.004151 -6.803540 9.676335 -v 11.541418 -5.378782 8.694632 -v 10.885054 -5.619434 8.731646 -v 2.834212 15.910932 19.358097 -v 2.834203 15.949227 19.568314 -v 3.293931 14.261284 19.875835 -v 3.293931 14.222986 19.665619 -v 1.578188 17.146614 19.132973 -v 1.578188 17.184916 19.343189 -v -0.137555 17.598896 19.050575 -v -0.137555 17.637207 19.260788 -v 1.578186 11.299354 20.198269 -v 1.578186 11.337653 20.408482 -v -0.137555 10.885364 20.490883 -v -0.137555 10.847074 20.280666 -v 2.834198 12.535027 19.973148 -v 2.834198 12.573324 20.183361 -v 3.293931 14.222986 19.665619 -v 3.293931 14.261284 19.875835 -v 2.834198 12.573324 20.183361 -v 2.834198 12.535027 19.973148 -v 0.612181 15.845090 21.324074 -v 0.612181 13.289986 21.789577 -v 2.322617 15.861096 20.732384 -v 1.674100 15.581246 21.285297 -v 1.954364 14.552227 21.472775 -v 2.703207 14.463718 20.986965 -v 1.282826 16.884050 20.546009 -v 0.908404 16.334541 21.148060 -v -0.137555 17.258476 20.477798 -v -0.137555 16.610268 21.097824 -v 1.282824 12.043385 21.427917 -v 0.908404 12.769909 21.797489 -v -0.137555 12.494183 21.847721 -v -0.137555 11.668958 21.496132 -v 2.322616 13.066336 21.241550 -v 1.674100 13.523205 21.660248 -v 1.954364 14.552227 21.472775 -v 1.674100 15.581246 21.285297 -v 1.298521 15.367919 21.324165 -v 1.520683 14.552227 21.472775 -v 1.674100 15.581246 21.285297 -v 0.908404 16.334541 21.148060 -v 0.691564 15.965047 21.215378 -v 1.298521 15.367919 21.324165 -v 0.908404 16.334541 21.148060 -v -0.137555 16.610268 21.097824 -v -0.137555 16.183609 21.175556 -v 0.691564 15.965047 21.215378 -v -0.137555 12.494183 21.847721 -v 0.908404 12.769909 21.797489 -v 0.691563 13.139404 21.730171 -v -0.137555 12.920841 21.769989 -v 0.908404 12.769909 21.797489 -v 1.674100 13.523205 21.660248 -v 1.298520 13.736532 21.621380 -v 0.691563 13.139404 21.730171 -v 1.674100 13.523205 21.660248 -v 1.954364 14.552227 21.472775 -v 1.520683 14.552227 21.472775 -v 1.298520 13.736532 21.621380 -v 1.520683 14.507906 21.229500 -v 1.298521 15.323596 21.080891 -v 1.161026 15.245500 21.095123 -v 1.361917 14.507906 21.229500 -v 1.298521 15.323596 21.080891 -v 0.691564 15.920726 20.972099 -v 0.612181 15.785457 20.996750 -v 1.161026 15.245500 21.095123 -v 0.691564 15.920726 20.972099 -v -0.137555 16.139288 20.932285 -v -0.137555 15.983094 20.960735 -v 0.612181 15.785457 20.996750 -v -0.137555 12.876520 21.526718 -v 0.691563 13.095083 21.486900 -v 0.612181 13.230352 21.462250 -v -0.137555 13.032715 21.498264 -v 0.691563 13.095083 21.486900 -v 1.298520 13.692211 21.378109 -v 1.161025 13.770308 21.363880 -v 0.612181 13.230352 21.462250 -v 1.298520 13.692211 21.378109 -v 1.520683 14.507906 21.229500 -v 1.361917 14.507906 21.229500 -v 1.161025 13.770308 21.363880 -v 1.520683 14.552227 21.472775 -v 1.298521 15.367919 21.324165 -v 1.298521 15.323596 21.080891 -v 1.520683 14.507906 21.229500 -v 1.298521 15.367919 21.324165 -v 0.691564 15.965047 21.215378 -v 0.691564 15.920726 20.972099 -v 1.298521 15.323596 21.080891 -v 0.691564 15.965047 21.215378 -v -0.137555 16.183609 21.175556 -v -0.137555 16.139288 20.932285 -v 0.691564 15.920726 20.972099 -v -0.137555 12.920841 21.769989 -v 0.691563 13.139404 21.730171 -v 0.691563 13.095083 21.486900 -v -0.137555 12.876520 21.526718 -v 0.691563 13.139404 21.730171 -v 1.298520 13.736532 21.621380 -v 1.298520 13.692211 21.378109 -v 0.691563 13.095083 21.486900 -v 1.298520 13.736532 21.621380 -v 1.520683 14.552227 21.472775 -v 1.520683 14.507906 21.229500 -v 1.298520 13.692211 21.378109 -v 1.161026 15.305133 21.422447 -v 1.361917 14.567539 21.556824 -v 1.361917 14.507906 21.229500 -v 1.161026 15.245500 21.095123 -v 1.361917 14.567539 21.556824 -v 1.161025 13.829943 21.691204 -v 1.161025 13.770308 21.363880 -v 1.361917 14.507906 21.229500 -v 1.161025 13.829943 21.691204 -v 0.612181 13.289986 21.789577 -v 0.612181 13.230352 21.462250 -v 1.161025 13.770308 21.363880 -v 0.612181 13.289986 21.789577 -v -0.137555 13.092350 21.825588 -v -0.137555 13.032715 21.498264 -v 0.612181 13.230352 21.462250 -v -0.137555 16.042728 21.288063 -v 0.612181 15.845090 21.324074 -v 0.612181 15.785457 20.996750 -v -0.137555 15.983094 20.960735 -v 0.612181 15.845090 21.324074 -v 1.161026 15.305133 21.422447 -v 1.161026 15.245500 21.095123 -v 0.612181 15.785457 20.996750 -v 2.322617 15.861096 20.732384 -v 2.703207 14.463718 20.986965 -v 2.703207 14.261284 19.875835 -v 2.322617 15.658666 19.621250 -v 1.282826 16.884050 20.546009 -v 1.282826 16.681616 19.434883 -v -0.137555 17.258476 20.477798 -v -0.137555 17.056042 19.366665 -v 1.282824 12.043385 21.427917 -v -0.137555 11.668958 21.496132 -v -0.137555 11.466525 20.385002 -v 1.282824 11.840951 20.316792 -v 2.322616 13.066336 21.241550 -v 2.322616 12.863903 20.130421 -v 2.703207 14.463718 20.986965 -v 2.322616 13.066336 21.241550 -v 2.322616 12.863903 20.130421 -v 2.703207 14.261284 19.875835 -v 2.322617 15.658666 19.621250 -v 2.703207 14.261284 19.875835 -v 3.293931 14.261284 19.875835 -v 2.834203 15.949227 19.568314 -v 2.703207 14.261284 19.875835 -v 2.322616 12.863903 20.130421 -v 2.834198 12.573324 20.183361 -v 3.293931 14.261284 19.875835 -v 2.322616 12.863903 20.130421 -v 1.282824 11.840951 20.316792 -v 1.578186 11.337653 20.408482 -v 2.834198 12.573324 20.183361 -v 1.282824 11.840951 20.316792 -v -0.137555 11.466525 20.385002 -v -0.137555 10.885364 20.490883 -v 1.578186 11.337653 20.408482 -v -0.137555 17.056042 19.366665 -v 1.282826 16.681616 19.434883 -v 1.578188 17.184916 19.343189 -v -0.137555 17.637207 19.260788 -v 1.282826 16.681616 19.434883 -v 2.322617 15.658666 19.621250 -v 2.834203 15.949227 19.568314 -v 1.578188 17.184916 19.343189 -v 0.663374 14.114862 23.483055 -v 0.715733 14.051090 23.425133 -v 1.072334 14.898061 23.270828 -v 0.998288 14.910323 23.338135 -v 0.715733 15.745030 23.116516 -v -0.137555 16.092754 23.053173 -v -0.137555 16.032167 23.133743 -v 0.663374 15.705781 23.193211 -v 0.998288 14.910323 23.338135 -v 1.072334 14.898061 23.270828 -v 0.715733 15.745030 23.116516 -v 0.663374 15.705781 23.193211 -v 0.715733 13.707285 21.538033 -v 1.072334 14.554255 21.383720 -v 1.072334 14.898061 23.270828 -v 0.715733 14.051090 23.425133 -v -0.137555 15.748948 21.166065 -v -0.137555 16.092754 23.053173 -v 0.715733 15.745030 23.116516 -v 0.715733 15.401227 21.229416 -v 1.072334 14.554255 21.383720 -v 0.715733 15.401227 21.229416 -v 0.715733 15.745030 23.116516 -v 1.072334 14.898061 23.270828 -v 6.777748 -3.374685 12.138167 -v 2.092322 7.513035 15.175448 -v 2.646245 7.840734 14.815410 -v 7.332256 -2.982224 11.851208 -v 2.704278 7.707127 15.538341 -v 7.388817 -3.256060 12.533605 -v 7.388817 -3.256060 12.533605 -v 2.704278 7.707127 15.538341 -v 2.092322 7.513035 15.175448 -v 6.777748 -3.374685 12.138167 -v 6.154264 -3.665658 11.352397 -v 1.461396 4.755218 2.757458 -v 2.013677 4.917661 2.296532 -v 6.703182 -3.810490 10.881698 -v 6.703182 -3.810490 10.881698 -v 2.013677 4.917661 2.296532 -v 2.074895 5.073448 3.014745 -v 6.769146 -3.258756 11.366552 -v 6.769146 -3.258756 11.366552 -v 2.074895 5.073448 3.014745 -v 1.461396 4.755218 2.757458 -v 6.154264 -3.665658 11.352397 -v -0.137555 -3.498145 12.355363 -v -0.137555 -4.092004 12.209984 -v 8.748431 -4.092004 12.209988 -v 8.748431 -3.498145 12.355365 -v -0.137555 -4.409125 11.687263 -v 8.748431 -4.409125 11.687264 -v -0.137555 -4.263747 11.093404 -v 8.748431 -4.263747 11.093406 -v -0.137555 -3.741025 10.776280 -v 8.748431 -3.741025 10.776284 -v -0.137555 -3.147167 10.921659 -v 8.748431 -3.147167 10.921661 -v -0.137555 -3.147167 10.921659 -v -0.137555 -2.830044 11.444382 -v 8.748431 -2.830044 11.444382 -v 8.748431 -3.147167 10.921661 -v -0.137555 -2.975422 12.038241 -v 8.748431 -2.975422 12.038241 -v 8.748431 -3.498145 12.355365 -v 8.748431 -4.092004 12.209988 -v 8.748431 -3.953632 12.021311 -v 8.748431 -3.533713 12.124108 -v 8.748431 -4.409125 11.687264 -v 8.748431 -4.177870 11.651694 -v 8.748431 -4.263747 11.093406 -v 8.748431 -4.075072 11.231778 -v 8.748431 -3.741025 10.776284 -v 8.748431 -3.705457 11.007539 -v 8.748431 -3.147167 10.921661 -v 8.748431 -3.285537 11.110336 -v 8.748431 -3.147167 10.921661 -v 8.748431 -2.830044 11.444382 -v 8.748431 -3.061300 11.479952 -v 8.748431 -3.285537 11.110336 -v 8.748431 -2.975422 12.038241 -v 8.748431 -3.164097 11.899868 -v 8.748431 -3.953632 12.021311 -v 9.643316 -3.959666 12.022240 -v 9.605914 -3.541481 12.125302 -v 8.748431 -3.533713 12.124108 -v 8.748431 -4.177870 11.651694 -v 9.658809 -4.183187 11.652513 -v 9.643316 -3.959666 12.022240 -v 8.748431 -3.953632 12.021311 -v 8.748431 -4.075072 11.231778 -v 9.643316 -4.081106 11.232705 -v 9.658809 -4.183187 11.652513 -v 8.748431 -4.177870 11.651694 -v 8.748431 -3.705457 11.007539 -v 9.605911 -3.713226 11.008735 -v 9.643316 -4.081106 11.232705 -v 8.748431 -4.075072 11.231778 -v 8.748431 -3.285537 11.110336 -v 9.568512 -3.295041 11.111799 -v 9.605911 -3.713226 11.008735 -v 8.748431 -3.705457 11.007539 -v 8.748431 -3.061300 11.479952 -v 9.553020 -3.071526 11.481525 -v 9.568512 -3.295041 11.111799 -v 8.748431 -3.285537 11.110336 -v 8.748431 -3.164097 11.899868 -v 9.568512 -3.173601 11.901333 -v 9.553020 -3.071526 11.481525 -v 8.748431 -3.061300 11.479952 -v 8.748431 -3.533713 12.124108 -v 9.605914 -3.541481 12.125302 -v 9.568512 -3.173601 11.901333 -v 8.748431 -3.164097 11.899868 -v 10.058415 -4.646990 13.001652 -v 9.940152 -3.324768 13.327479 -v 9.605914 -3.355837 13.332259 -v 9.724178 -4.678094 13.006378 -v 10.107403 -5.353782 11.832620 -v 10.058415 -4.646990 13.001652 -v 9.724178 -4.678094 13.006378 -v 9.773163 -5.384840 11.837338 -v 10.058415 -5.031002 10.505172 -v 10.107403 -5.353782 11.832620 -v 9.773163 -5.384840 11.837338 -v 9.724178 -5.062070 10.509952 -v 9.940152 -3.867794 9.797000 -v 10.058415 -5.031002 10.505172 -v 9.724178 -5.062070 10.509952 -v 9.605911 -3.898864 9.801778 -v 9.821888 -2.545539 10.122879 -v 9.940152 -3.867794 9.797000 -v 9.605911 -3.898864 9.801778 -v 9.487651 -2.576614 10.127659 -v 9.772903 -1.838800 11.291918 -v 9.821888 -2.545539 10.122879 -v 9.487651 -2.576614 10.127659 -v 9.438663 -1.869869 11.296698 -v 9.821891 -2.161563 12.619308 -v 9.772903 -1.838800 11.291918 -v 9.438663 -1.869869 11.296698 -v 9.487651 -2.192633 12.624087 -v 9.940152 -3.324768 13.327479 -v 9.821891 -2.161563 12.619308 -v 9.487651 -2.192633 12.624087 -v 9.605914 -3.355837 13.332259 -v 9.605914 -3.541481 12.125302 -v 9.643316 -3.959666 12.022240 -v 9.724178 -4.678094 13.006378 -v 9.605914 -3.355837 13.332259 -v 9.643316 -3.959666 12.022240 -v 9.658809 -4.183187 11.652513 -v 9.773163 -5.384840 11.837338 -v 9.724178 -4.678094 13.006378 -v 9.658809 -4.183187 11.652513 -v 9.643316 -4.081106 11.232705 -v 9.724178 -5.062070 10.509952 -v 9.773163 -5.384840 11.837338 -v 9.643316 -4.081106 11.232705 -v 9.605911 -3.713226 11.008735 -v 9.605911 -3.898864 9.801778 -v 9.724178 -5.062070 10.509952 -v 9.605911 -3.713226 11.008735 -v 9.568512 -3.295041 11.111799 -v 9.487651 -2.576614 10.127659 -v 9.605911 -3.898864 9.801778 -v 9.568512 -3.295041 11.111799 -v 9.553020 -3.071526 11.481525 -v 9.438663 -1.869869 11.296698 -v 9.487651 -2.576614 10.127659 -v 9.553020 -3.071526 11.481525 -v 9.568512 -3.173601 11.901333 -v 9.487651 -2.192633 12.624087 -v 9.438663 -1.869869 11.296698 -v 9.568512 -3.173601 11.901333 -v 9.605914 -3.541481 12.125302 -v 9.605914 -3.355837 13.332259 -v 9.487651 -2.192633 12.624087 -v 34.341240 10.973569 -4.305973 -v 34.243908 10.975993 -4.362118 -v 34.243908 24.352579 -3.784413 -v 34.341240 24.350153 -3.728268 -v 34.243908 10.971145 -4.249835 -v 34.243908 24.347727 -3.672129 -v 34.243908 10.971145 -4.249835 -v 34.243908 24.347727 -3.672129 -v 30.426413 12.832979 10.128780 -v 30.118052 12.800472 9.998507 -v 12.762002 27.443340 10.522055 -v 13.057944 27.553009 10.638275 -v 30.118052 12.800472 9.998507 -v 30.158758 12.818146 10.331888 -v 12.812175 27.472626 10.853327 -v 12.762002 27.443340 10.522055 -v 5.737073 7.860677 11.055306 -v 5.473027 7.993579 10.894900 -v 29.891050 26.787380 10.721846 -v 30.191610 26.743053 10.866119 -v 5.473027 7.993579 10.894900 -v 5.484356 7.996225 11.231019 -v 29.919748 26.796295 11.056828 -v 29.891050 26.787380 10.721846 -v 31.197435 10.997549 0.614511 -v 30.819914 11.104485 0.424588 -v 30.819914 27.064472 9.410694 -v 31.197435 26.957542 9.600615 -v 30.819914 10.890615 0.804433 -v 30.819914 26.850609 9.790541 -v 30.819914 10.890615 0.804433 -v 30.819914 26.850609 9.790541 -v 6.536887 16.464014 12.762231 -v 6.446542 16.478489 12.489015 -v 13.910448 26.973335 10.576986 -v 14.000791 26.958862 10.850204 -v 6.228430 16.608864 12.353185 -v 13.692336 27.103703 10.441158 -v 6.010320 16.778763 12.434308 -v 13.474224 27.273605 10.522282 -v 6.010320 16.778763 12.434308 -v 5.919975 16.888662 12.684867 -v 13.383882 27.383507 10.772839 -v 13.474224 27.273605 10.522282 -v 6.010320 16.874187 12.958085 -v 13.474224 27.369030 11.046057 -v 6.228430 16.743813 13.093915 -v 13.692336 27.238659 11.181887 -v 6.446542 16.573915 13.012792 -v 13.910448 27.068760 11.100763 -v 3.460064 17.646593 0.622345 -v 2.406346 17.756693 -2.452592 -v 2.406346 18.909416 -2.662604 -v 3.460064 18.907696 0.392586 -v -0.137555 17.892881 -3.742776 -v -0.137555 19.238968 -3.988016 -v -0.137555 19.903610 4.531394 -v 2.406346 19.189877 3.396056 -v 2.406346 20.489861 3.159215 -v -0.137555 21.291946 4.278457 -v 3.460064 18.907696 0.392586 -v 2.406346 18.909416 -2.662604 -v 1.988101 18.997980 -2.176482 -v 2.868576 18.907696 0.392586 -v 2.406346 18.909416 -2.662604 -v -0.137555 19.238968 -3.988016 -v -0.137555 19.364216 -3.300538 -v 1.988101 18.997980 -2.176482 -v -0.137555 21.291946 4.278457 -v 2.406346 20.489861 3.159215 -v 1.988101 20.286793 2.693955 -v -0.137555 20.931133 3.633897 -v 2.406346 20.489861 3.159215 -v 3.460064 18.907696 0.392586 -v 2.868576 18.907696 0.392586 -v 1.988101 20.286793 2.693955 -v 2.868576 18.907696 0.392586 -v 1.988101 18.997980 -2.176482 -v 1.988101 17.957739 -1.986966 -v 2.868576 17.970634 0.563307 -v 1.988101 18.997980 -2.176482 -v -0.137555 19.364216 -3.300538 -v -0.137555 18.330683 -3.112241 -v 1.988101 17.957739 -1.986966 -v -0.137555 20.931133 3.633897 -v 1.988101 20.286793 2.693955 -v 1.988101 19.330694 2.868146 -v -0.137555 20.041740 3.795932 -v 1.988101 20.286793 2.693955 -v 2.868576 18.907696 0.392586 -v 2.868576 17.970634 0.563307 -v 1.988101 19.330694 2.868146 -v 1.764696 19.540924 2.445557 -v 1.607252 19.914867 2.377429 -v 1.607252 22.648573 17.382362 -v 1.764696 22.274622 17.450493 -v 1.227150 20.069763 2.349210 -v 1.227150 22.803465 17.354145 -v 0.847047 19.914867 2.377429 -v 0.847047 22.648573 17.382362 -v 0.689604 19.540924 2.445557 -v 0.689604 22.274622 17.450493 -v 0.847048 19.166975 2.513686 -v 0.847048 21.900675 17.518620 -v 0.847048 19.166975 2.513686 -v 1.227150 19.012081 2.541905 -v 1.227150 21.745783 17.546841 -v 0.847048 21.900675 17.518620 -v 1.607252 19.166975 2.513686 -v 1.607252 21.900675 17.518620 -v 1.227150 22.803465 17.354145 -v 1.227150 21.745783 17.546841 -v 1.328365 22.063547 17.279758 -v 1.264851 22.214399 17.252277 -v 1.264851 22.423220 18.398476 -v 1.328365 22.272367 18.425961 -v 1.111515 22.276884 17.240891 -v 1.111515 22.485704 18.387093 -v 0.958179 22.214399 17.252277 -v 0.958179 22.423220 18.398476 -v 0.894666 22.063547 17.279758 -v 0.894666 22.272367 18.425961 -v 0.958179 21.912691 17.307243 -v 0.958179 22.121515 18.453445 -v 1.111515 21.850206 17.318626 -v 1.111515 22.059031 18.464828 -v 1.264851 21.912691 17.307243 -v 1.264851 22.121515 18.453445 -v 1.264851 21.912691 17.307243 -v 1.264851 22.121515 18.453445 -v 1.111515 22.485704 18.387093 -v 1.111515 22.059031 18.464828 -v 0.133934 16.457468 22.082756 -v 0.267938 16.083843 22.120594 -v 2.302677 19.353851 21.730213 -v 1.762202 19.625370 21.680744 -v 0.376600 15.523850 22.167568 -v 2.625365 19.191742 21.759747 -v 0.628120 15.397494 22.190586 -v 2.876886 19.065380 21.782768 -v 1.073912 15.597871 22.200733 -v 3.029603 18.988661 21.796749 -v 3.662046 22.581758 20.906145 -v 3.067275 22.880556 20.851706 -v 4.308591 22.256952 20.965319 -v 4.570708 22.125269 20.989309 -v 4.812643 22.003733 21.011454 -v 3.548905 24.540596 20.280066 -v 4.345898 24.140202 20.353010 -v 4.939451 25.479950 19.791376 -v 3.965612 25.969181 19.702246 -v 5.111174 23.755747 20.423056 -v 5.808561 25.043331 19.870920 -v 5.474634 23.573153 20.456320 -v 6.406145 24.743126 19.925615 -v 5.860458 23.379328 20.491632 -v 6.917789 24.486084 19.972445 -v 5.114145 27.688271 18.802736 -v 4.300347 26.658504 19.377474 -v 5.623532 26.764912 19.158976 -v 6.998875 29.319054 17.636089 -v 6.739822 26.703918 19.030687 -v 8.696851 30.098463 16.817387 -v 7.574537 26.468971 19.019972 -v 10.099993 29.987379 16.565411 -v 7.997971 25.885288 19.232836 -v 10.327551 28.673668 17.340019 -v 1.523451 15.759408 22.209934 -v 3.151719 18.927311 21.807922 -v 5.006096 21.906542 21.029158 -v 6.168966 23.224344 20.519869 -v 7.326908 24.280552 20.009890 -v 8.236472 25.164478 19.527105 -v 9.891048 26.912106 18.423786 -v 0.133934 16.457468 22.082756 -v 1.762202 19.625370 21.680744 -v 1.761461 19.573685 21.405102 -v 0.143137 16.425117 21.804653 -v 0.267938 16.083843 22.120594 -v 0.133934 16.457468 22.082756 -v 0.143137 16.425117 21.804653 -v 0.277901 16.052988 21.842400 -v 0.376600 15.523850 22.167568 -v 0.267938 16.083843 22.120594 -v 0.277901 16.052988 21.842400 -v 0.387803 15.495456 21.889267 -v 0.628120 15.397494 22.190586 -v 0.376600 15.523850 22.167568 -v 0.387803 15.495456 21.889267 -v 0.639325 15.369096 21.912289 -v 3.151719 18.927311 21.807922 -v 1.523451 15.759408 22.209934 -v 1.532655 15.727063 21.931828 -v 3.150980 18.875626 21.532272 -v 1.073912 15.597871 22.200733 -v 0.628120 15.397494 22.190586 -v 0.639325 15.369096 21.912289 -v 1.084074 15.567410 21.922523 -v 1.762202 19.625370 21.680744 -v 3.067275 22.880556 20.851706 -v 3.056602 22.809984 20.580938 -v 1.761461 19.573685 21.405102 -v 5.006096 21.906542 21.029158 -v 3.151719 18.927311 21.807922 -v 3.150980 18.875626 21.532272 -v 4.995420 21.835970 20.758394 -v 3.548905 24.540596 20.280066 -v 3.965612 25.969181 19.702246 -v 3.945781 25.881596 19.438158 -v 3.533330 24.460865 20.012613 -v 6.168966 23.224344 20.519869 -v 5.006096 21.906542 21.029158 -v 4.995420 21.835970 20.758394 -v 6.153392 23.144617 20.252417 -v 4.300347 26.658504 19.377474 -v 5.114145 27.688271 18.802736 -v 5.088283 27.589695 18.544235 -v 4.278272 26.566811 19.115355 -v 5.114145 27.688271 18.802736 -v 6.998875 29.319054 17.636089 -v 6.966145 29.208187 17.385136 -v 5.088283 27.589695 18.544235 -v 6.998875 29.319054 17.636089 -v 8.696851 30.098463 16.817387 -v 8.659721 29.979841 16.571980 -v 6.966145 29.208187 17.385136 -v 8.696851 30.098463 16.817387 -v 10.099993 29.987379 16.565411 -v 10.061254 29.865934 16.322176 -v 8.659721 29.979841 16.571980 -v 10.327551 28.673668 17.340019 -v 9.891048 26.912106 18.423786 -v 9.860877 26.805782 18.169872 -v 10.292060 28.557926 17.092480 -v 8.236472 25.164478 19.527105 -v 7.326908 24.280552 20.009890 -v 7.307082 24.192966 19.745806 -v 8.213132 25.070473 19.266150 -v 10.099993 29.987379 16.565411 -v 10.327551 28.673668 17.340019 -v 10.292060 28.557926 17.092480 -v 10.061254 29.865934 16.322176 -v 1.523451 15.759408 22.209934 -v 1.073912 15.597871 22.200733 -v 1.084074 15.567410 21.922523 -v 1.532655 15.727063 21.931828 -v 9.891048 26.912106 18.423786 -v 8.236472 25.164478 19.527105 -v 8.213132 25.070473 19.266150 -v 9.860877 26.805782 18.169872 -v 3.965612 25.969181 19.702246 -v 4.300347 26.658504 19.377474 -v 4.278272 26.566811 19.115355 -v 3.945781 25.881596 19.438158 -v 3.067275 22.880556 20.851706 -v 3.548905 24.540596 20.280066 -v 3.533330 24.460865 20.012613 -v 3.056602 22.809984 20.580938 -v 7.326908 24.280552 20.009890 -v 6.168966 23.224344 20.519869 -v 6.153392 23.144617 20.252417 -v 7.307082 24.192966 19.745806 -v 1.761461 19.573685 21.405102 -v 3.056602 22.809984 20.580938 -v 4.995420 21.835970 20.758394 -v 3.150980 18.875626 21.532272 -v 1.084074 15.567410 21.922523 -v 0.277901 16.052988 21.842400 -v 0.143137 16.425117 21.804653 -v 1.532655 15.727063 21.931828 -v 1.084074 15.567410 21.922523 -v 0.639325 15.369096 21.912289 -v 0.387803 15.495456 21.889267 -v 0.277901 16.052988 21.842400 -v 1.532655 15.727063 21.931828 -v 0.143137 16.425117 21.804653 -v 1.761461 19.573685 21.405102 -v 3.150980 18.875626 21.532272 -v 3.533330 24.460865 20.012613 -v 6.153392 23.144617 20.252417 -v 4.995420 21.835970 20.758394 -v 3.056602 22.809984 20.580938 -v 4.278272 26.566811 19.115355 -v 8.213132 25.070473 19.266150 -v 7.307082 24.192966 19.745806 -v 3.945781 25.881596 19.438158 -v 6.153392 23.144617 20.252417 -v 3.533330 24.460865 20.012613 -v 3.945781 25.881596 19.438158 -v 7.307082 24.192966 19.745806 -v 6.966145 29.208187 17.385136 -v 8.659721 29.979841 16.571980 -v 10.061254 29.865934 16.322176 -v 10.292060 28.557926 17.092480 -v 8.213132 25.070473 19.266150 -v 4.278272 26.566811 19.115355 -v 5.088283 27.589695 18.544235 -v 9.860877 26.805782 18.169872 -v 9.860877 26.805782 18.169872 -v 5.088283 27.589695 18.544235 -v 6.966145 29.208187 17.385136 -v 10.292060 28.557926 17.092480 -v 0.376462 18.602148 -30.355957 -v 0.330657 17.075186 -24.744356 -v 0.285053 18.414829 -35.894424 -v 0.330618 18.670710 -33.683582 -v 0.330657 17.075186 -24.744356 -v 0.330657 15.336257 -22.014980 -v 0.330657 12.973974 -22.107353 -v 0.330657 11.401349 -24.776545 -v 0.330657 11.401349 -24.776545 -v 0.330657 7.251087 -23.778145 -v 0.330657 4.289977 -24.225880 -v 0.376461 3.909487 -27.628571 -v 0.330657 11.401349 -24.776545 -v 0.200132 4.545812 -36.862782 -v 0.285053 18.414829 -35.894424 -v 0.330657 17.075186 -24.744356 -v 0.285052 3.476720 -33.171906 -v 0.219588 3.910732 -35.557438 -v 0.200132 4.545812 -36.862782 -v 0.376461 3.909487 -27.628571 -v 0.170088 12.034781 -40.236835 -v 0.200132 15.707024 -39.244591 -v 0.285053 18.414829 -35.894424 -v 0.200132 4.545812 -36.862782 -v 0.170088 6.808916 -39.080044 -v 0.170088 9.315046 -39.888615 -v 0.170088 12.034781 -40.236835 -v 0.200132 4.545812 -36.862782 -v 11.142525 -2.881190 9.001891 -v 11.236621 -3.140807 14.369819 -v 11.364158 -4.232666 14.326954 -v 11.236621 -3.973048 8.959024 -v 11.062758 -1.892203 9.450106 -v 11.142528 -2.112300 14.000815 -v 11.551121 -6.327328 12.090542 -v 11.529890 -6.275688 11.022794 -v 11.009460 -1.156657 10.235428 -v 11.062758 -1.303718 13.276114 -v 10.990744 -0.786530 11.238302 -v 11.009460 -0.838170 12.306050 -v 9.946635 -0.930319 12.320226 -v 9.927916 -0.878675 11.252476 -v 9.946632 -1.248802 10.249601 -v 9.999933 -1.395863 13.290288 -v 10.079700 -2.204439 14.014987 -v 9.999930 -1.984348 9.464279 -v 10.079700 -2.973335 9.016065 -v 10.173796 -3.232952 14.383994 -v 10.347653 -5.902290 10.066901 -v 10.324265 -6.049350 13.107590 -v 10.324265 -6.367838 11.036967 -v 10.345494 -6.419479 12.104715 -v -0.137555 16.032167 23.133743 -v -0.137555 13.788481 23.542515 -v -0.137555 16.042728 21.288063 -v -0.137555 13.092350 21.825588 -v 1.759172 18.592596 17.282019 -v 1.759172 9.582694 18.923504 -v -0.137555 18.963770 17.214392 -v -0.137555 9.211522 18.991127 -v -0.137555 10.607282 -20.931702 -v -0.137555 9.192825 -28.695456 -v 5.849846 25.098688 -2.843851 -v 5.429670 25.412260 -1.122682 -v 6.450380 10.797626 7.312677 -v 6.993171 13.482239 6.823577 -v 5.595087 13.518061 6.817050 -v 5.158012 11.356320 7.210891 -v 4.904636 8.521720 7.727320 -v 6.450380 10.797626 7.312677 -v 5.158012 11.356320 7.210891 -v 3.913326 9.523684 7.544775 -v 6.993171 13.482239 6.823577 -v 6.450378 16.166853 6.334475 -v 5.158011 15.679805 6.423209 -v 5.595087 13.518061 6.817050 -v 2.591268 7.001008 8.004374 -v 4.904636 8.521720 7.727320 -v 3.913326 9.523684 7.544775 -v 2.050524 8.299153 7.767869 -v 4.904634 19.031322 5.812605 -v 2.591266 20.552032 5.535551 -v 2.050523 19.210899 5.779888 -v 3.913326 17.986372 6.002982 -v 6.450378 16.166853 6.334475 -v 4.904634 19.031322 5.812605 -v 3.913326 17.986372 6.002982 -v 5.158011 15.679805 6.423209 -v 2.591266 20.552032 5.535551 -v -0.137555 21.086037 5.438262 -v -0.137555 19.639086 5.701879 -v 2.050523 19.210899 5.779888 -v 0.715733 14.051090 23.425133 -v 0.663374 14.114862 23.483055 -v -0.137555 13.788481 23.542515 -v -0.137555 13.703371 23.488483 -v 0.715733 13.707285 21.538033 -v 0.715733 14.051090 23.425133 -v -0.137555 13.703371 23.488483 -v -0.137555 13.359564 21.601383 -v -0.137555 6.467003 8.101662 -v 2.591268 7.001008 8.004374 -v 2.050524 8.299153 7.767869 -v -0.137555 7.870969 7.845878 -v -4.748156 7.797970 2.380435 -v -6.161592 9.962349 1.986112 -v -6.657920 12.515405 1.520978 -v -2.632802 6.351778 2.643912 -v -0.137555 5.843942 2.736434 -v -6.161589 15.068464 1.055844 -v -0.137555 17.229437 5.018654 -v -0.137555 15.705820 -3.344262 -v -2.681505 17.006306 3.793933 -v -3.735224 16.467627 0.837195 -v -3.735223 18.497147 0.467442 -v -2.755446 19.942028 3.044717 -v -0.137555 17.229437 5.018654 -v -2.681505 17.006306 3.793933 -v -2.755446 19.942028 3.044717 -v -0.137555 20.817574 4.364942 -v -2.681505 15.928947 -2.119541 -v -0.137555 15.705820 -3.344262 -v -0.137555 18.750629 -3.898979 -v -2.500265 18.538774 -2.685168 -v -3.735224 16.467627 0.837195 -v -3.735223 18.497147 0.467442 -v -5.179747 8.521720 7.727320 -v -6.725490 10.797626 7.312677 -v -7.268282 13.482239 6.823577 -v -2.866378 7.001008 8.004374 -v -0.137555 6.467003 8.101662 -v -6.725487 16.166853 6.334475 -v -0.137555 8.331417 -26.440832 -v -2.820250 8.331417 -26.440832 -v -1.248774 10.132854 -26.769033 -v -0.137555 10.132854 -26.769033 -v -0.137555 5.783802 -25.976692 -v -2.820251 5.783802 -25.976692 -v -2.820250 8.331417 -26.440832 -v -0.137555 8.331417 -26.440832 -v -0.137555 5.783802 -25.976692 -v -0.137555 3.982364 -25.648491 -v -1.248775 3.982364 -25.648491 -v -2.820251 5.783802 -25.976692 -v -10.932370 27.734844 13.241050 -v -10.932370 27.150551 8.418542 -v -0.137555 27.150551 8.418542 -v -0.137555 27.734844 13.241050 -v -0.137555 28.271790 13.143222 -v -10.932370 28.271790 13.143222 -v -10.932370 27.734844 13.241050 -v -0.137555 27.734844 13.241050 -v -10.932370 26.245462 3.654478 -v -0.137555 26.248919 3.469610 -v -21.727186 27.421173 13.298194 -v -21.727186 26.836880 8.475688 -v -21.727186 27.958118 13.200370 -v -21.727186 27.421173 13.298194 -v -0.137555 27.936581 8.275336 -v -10.932370 27.936581 8.275336 -v -10.932370 28.271790 13.143222 -v -0.137555 28.271790 13.143222 -v -10.932370 26.074389 2.673605 -v -2.617644 26.107084 2.691110 -v -21.727186 25.931791 3.711624 -v -32.521996 26.785511 13.414004 -v -32.521996 26.201221 8.591496 -v -32.521996 27.322460 13.316178 -v -32.521996 26.785511 13.414004 -v -21.727186 27.622913 8.332482 -v -21.727186 27.958118 13.200370 -v -0.137555 27.034948 3.326405 -v -10.932370 27.103384 3.498175 -v -6.509318 24.407400 -5.868575 -v -6.124956 25.098688 -2.843851 -v -10.932370 25.029203 -2.931825 -v -10.932370 24.407400 -5.868575 -v -21.727186 25.760714 2.730751 -v -32.521996 25.296129 3.827433 -v -38.411888 26.311825 13.500302 -v -41.725868 25.660938 8.689931 -v -38.411888 26.848774 13.402480 -v -38.411888 26.311825 13.500302 -v -32.521996 26.987251 8.448291 -v -32.521996 27.322460 13.316178 -v -21.727186 26.789709 3.555321 -v -2.617644 26.893122 2.547905 -v -10.932370 26.917547 2.519993 -v -6.509318 24.407400 -5.868575 -v -10.932370 24.407400 -5.868575 -v -10.932370 24.911684 -5.960440 -v -6.509318 24.911684 -5.960440 -v -21.727186 25.098589 -1.065534 -v -21.727186 24.715536 -2.874681 -v -10.932370 25.412260 -1.122682 -v -32.521996 25.125055 2.846561 -v -43.316811 24.755846 3.925868 -v -38.411888 26.848774 13.402480 -v -41.725868 26.446968 8.546725 -v -41.725868 25.660938 8.689931 -v -38.411888 26.311825 13.500302 -v -41.725868 26.446968 8.546725 -v -38.411888 26.848774 13.402480 -v -32.521996 26.154055 3.671129 -v -21.727186 26.603876 2.577139 -v -6.124956 25.884718 -2.987059 -v -10.932370 25.707838 -3.055464 -v -10.932370 26.198298 -1.265890 -v -5.704780 26.198298 -1.265890 -v -21.727186 24.598013 -5.903296 -v -21.727186 24.093729 -5.811423 -v -32.521996 24.462931 -0.949727 -v -32.521996 24.079874 -2.758871 -v -43.316811 24.584768 2.944992 -v -43.316811 25.613764 3.769564 -v -43.316811 24.755846 3.925868 -v -41.725868 25.660938 8.689931 -v -43.316811 25.613764 3.769564 -v -32.521996 25.968218 2.692949 -v -21.727186 25.394167 -2.998319 -v -21.727186 25.884623 -1.208742 -v -32.521996 23.962353 -5.787486 -v -32.521996 23.458073 -5.695620 -v -43.316811 23.922642 -0.851296 -v -42.190163 23.539589 -2.660438 -v -43.316811 25.427927 2.791382 -v -43.316811 24.584768 2.944992 -v -43.316811 25.427927 2.791382 -v -32.521996 24.758509 -2.882509 -v -32.521996 25.248964 -1.092931 -v -40.361286 23.422073 -5.689055 -v -40.361286 22.917782 -5.597183 -v -43.316811 23.922642 -0.851296 -v -43.316811 24.708681 -0.994498 -v -42.190163 24.218218 -2.784075 -v -42.190163 23.539589 -2.660438 -v -42.190163 24.218218 -2.784075 -v -43.316811 24.708681 -0.994498 -v -2.617644 26.893122 2.547905 -v -0.137555 27.034948 3.326405 -v -0.137555 26.248919 3.469610 -v -2.617644 26.107084 2.691110 -v -5.704780 25.412260 -1.122682 -v -5.704780 26.198298 -1.265890 -v -6.124956 25.098688 -2.843851 -v -6.509318 24.407400 -5.868575 -v -6.509318 24.911684 -5.960440 -v -6.124956 25.884718 -2.987059 -v -21.727186 24.093729 -5.811423 -v -32.521996 23.458073 -5.695620 -v -10.932370 24.911684 -5.960440 -v -21.727186 24.598013 -5.903296 -v -40.361286 22.917782 -5.597183 -v -32.521996 23.962353 -5.787486 -v -40.361286 23.422073 -5.689055 -v -40.361286 22.917782 -5.597183 -v -40.361286 23.422073 -5.689055 -v -5.704780 25.412260 -1.122682 -v -6.509318 24.911684 -5.960440 -v -0.576148 3.263966 -5.783109 -v -32.301418 9.709085 -6.957421 -v -32.206169 10.162366 -7.040006 -v -0.472966 3.753135 -5.871772 -v -40.011227 11.274701 -7.242656 -v -39.945049 11.589635 -7.300035 -v -0.663033 6.649406 14.232206 -v -0.541272 7.228906 14.126631 -v -32.237789 13.650052 12.956777 -v -32.350616 13.113069 13.054610 -v -38.002087 14.790937 12.748921 -v -38.101227 14.319102 12.834886 -v -0.662496 3.865942 -0.760052 -v -32.360443 10.333307 -1.938074 -v -32.301418 9.709085 -6.957421 -v -0.576148 3.263966 -5.783109 -v -42.906727 12.549485 -2.430761 -v -40.011227 11.274701 -7.242656 -v -42.926029 13.378873 2.642551 -v -42.833996 13.816903 2.562746 -v -42.814693 12.987517 -2.510567 -v -42.906727 12.549485 -2.430761 -v -42.833996 13.816903 2.562746 -v -32.255753 11.746195 2.991455 -v -32.227974 10.963766 -2.052936 -v -42.814693 12.987517 -2.510567 -v -32.206169 10.162366 -7.040006 -v -0.518984 4.546322 -0.883360 -v -0.472966 3.753135 -5.871772 -v -39.945049 11.589635 -7.300035 -v -40.011227 11.274701 -7.242656 -v -42.906727 12.549485 -2.430761 -v -42.814693 12.987517 -2.510567 -v -0.774090 5.383774 9.351863 -v -32.421593 11.874181 8.170041 -v -0.597230 6.222238 9.199900 -v -32.258347 12.651127 8.028491 -v -41.423397 13.882128 7.790358 -v -38.101227 14.319102 12.834886 -v -38.002087 14.790937 12.748921 -v -41.309978 14.421938 7.692010 -v -32.421593 11.874181 8.170041 -v -32.350616 13.113069 13.054610 -v -38.101227 14.319102 12.834886 -v -41.423397 13.882128 7.790358 -v -41.309978 14.421938 7.692010 -v -38.002087 14.790937 12.748921 -v -32.237789 13.650052 12.956777 -v -32.258347 12.651127 8.028491 -v -0.715231 4.637904 4.286060 -v -32.388218 11.115736 3.106316 -v -0.571717 5.318285 4.162748 -v -42.926029 13.378873 2.642551 -v -39.945049 11.589635 -7.300035 -v -0.774090 5.383774 9.351863 -v -0.597230 6.222238 9.199900 -v -10.927002 10.839343 -20.973984 -v -5.834132 7.933621 -36.487488 -v -4.366348 8.149817 -35.663517 -v -2.564616 10.581471 -20.926994 -v -2.591609 11.808965 -21.150627 -v -0.137555 11.835061 -21.155396 -v -0.137555 10.420605 -28.919138 -v -4.412028 9.079532 -35.830589 -v -0.137555 10.607282 -20.931702 -v -0.137555 11.835061 -21.155396 -v -2.591609 11.808965 -21.150627 -v -2.564616 10.581471 -20.926994 -v -11.028844 11.399936 -21.076115 -v -10.927002 10.839343 -20.973984 -v -12.967854 11.199199 -21.039536 -v -12.856207 10.727206 -20.953552 -v -15.586095 10.176061 -23.504894 -v -16.207060 9.756166 -24.787363 -v -16.030195 9.283175 -24.701189 -v -15.416062 9.703977 -23.418880 -v -17.875292 7.780162 -32.684757 -v -17.680067 7.330409 -32.602814 -v -14.043754 7.331349 -36.377769 -v -14.182967 7.973525 -36.291916 -v -5.897515 8.862197 -36.656662 -v -5.834132 7.933621 -36.487488 -v -4.366348 8.149817 -35.663517 -v -4.412028 9.079532 -35.830589 -v -0.137555 10.420605 -28.919138 -v -0.137555 9.192825 -28.695456 -v -12.967854 11.199199 -21.039536 -v -12.856207 10.727206 -20.953552 -v -16.558538 7.700906 -35.471687 -v -16.377802 7.227387 -35.385410 -v -16.377802 7.227387 -35.385410 -v -16.558538 7.700906 -35.471687 -v -15.586095 10.176061 -23.504894 -v -12.967854 11.199199 -21.039536 -v -14.182967 7.973525 -36.291916 -v -16.558538 7.700906 -35.471687 -v -11.028844 11.399936 -21.076115 -v -5.897515 8.862197 -36.656662 -v -15.416062 9.703977 -23.418880 -v -16.030195 9.283175 -24.701189 -v -17.680067 7.330409 -32.602814 -v -16.377802 7.227387 -35.385410 -v -14.043754 7.331349 -36.377769 -v -12.856207 10.727206 -20.953552 -v -17.875292 7.780162 -32.684757 -v -16.207060 9.756166 -24.787363 -v -30.580156 12.463110 10.208496 -v -30.429491 26.773792 11.243069 -v -31.088133 26.748894 11.243511 -v -31.238810 12.438213 10.208937 -v -31.238810 12.438213 10.208937 -v -31.088133 26.748894 11.243511 -v -31.084776 26.850677 9.394487 -v -31.235453 12.540001 8.359914 -v -31.235453 12.540001 8.359914 -v -31.084776 26.850677 9.394487 -v -30.426134 26.875576 9.394049 -v -30.576811 12.564899 8.359473 -v -30.576811 12.564899 8.359473 -v -30.426134 26.875576 9.394049 -v -30.429491 26.773792 11.243069 -v -30.580156 12.463110 10.208496 -v -0.909560 18.576508 2.205827 -v -2.125126 18.576508 2.205827 -v -2.125126 20.241886 1.902417 -v -0.909560 20.241886 1.902417 -v -0.909560 18.658239 2.654441 -v -0.909560 20.323616 2.351031 -v -2.125126 20.323616 2.351031 -v -2.125126 18.658239 2.654441 -v -0.909560 18.576508 2.205827 -v -0.909560 18.658239 2.654441 -v -2.125126 18.658239 2.654441 -v -2.125126 18.576508 2.205827 -v -2.125126 18.576508 2.205827 -v -2.125126 18.658239 2.654441 -v -2.125126 20.323616 2.351031 -v -2.125126 20.241886 1.902417 -v -2.125126 20.241886 1.902417 -v -2.125126 20.323616 2.351031 -v -0.909560 20.323616 2.351031 -v -0.909560 20.241886 1.902417 -v -0.909560 20.241886 1.902417 -v -0.909560 20.323616 2.351031 -v -0.909560 18.658239 2.654441 -v -0.909560 18.576508 2.205827 -v -7.268263 13.322628 10.315155 -v -6.725470 17.393959 9.573412 -v -6.725470 16.871246 6.704314 -v -7.268263 12.799915 7.446060 -v -5.179726 19.669867 9.158772 -v -5.179726 19.147156 6.289673 -v -2.866356 21.190580 8.881716 -v -2.866356 20.667866 6.012619 -v -0.137555 21.724585 8.784430 -v -0.137555 21.201870 5.915332 -v -0.137555 6.307393 11.593240 -v -2.866358 6.841393 11.495952 -v -2.866358 6.318684 8.626856 -v -0.137555 5.784679 8.724144 -v -5.179727 8.362108 11.218898 -v -5.179727 7.839396 8.349802 -v -5.179727 8.362108 11.218898 -v -6.725470 10.638018 10.804259 -v -6.725470 10.115304 7.935161 -v -5.179727 7.839396 8.349802 -v -6.725470 10.638018 10.804259 -v -6.725470 10.115304 7.935161 -v -7.268263 13.322628 10.315155 -v -7.268263 13.581101 11.733877 -v -6.725470 16.632854 11.177889 -v -6.725470 17.393959 9.573412 -v -5.179726 18.908764 10.763247 -v -5.179726 19.669867 9.158772 -v -2.866356 20.429476 10.486194 -v -2.866356 21.190580 8.881716 -v -0.137555 20.963480 10.388906 -v -0.137555 21.724585 8.784430 -v -0.137555 6.307393 11.593240 -v -0.137555 6.565864 13.011965 -v -2.866358 7.099868 12.914675 -v -2.866358 6.841393 11.495952 -v -5.179727 8.620581 12.637621 -v -6.725470 10.896488 12.222981 -v -7.268263 13.581101 11.733877 -v -7.268263 13.763827 12.736833 -v -6.725470 16.489346 12.240279 -v -6.725470 16.632854 11.177889 -v -5.179726 18.765253 11.825639 -v -5.179726 18.908764 10.763247 -v -2.866356 20.285967 11.548583 -v -2.866356 20.429476 10.486194 -v -0.137555 20.819971 11.451295 -v -0.137555 20.963480 10.388906 -v -0.137555 6.565864 13.011965 -v -0.137555 6.748590 14.014921 -v -2.866358 7.282592 13.917631 -v -2.866358 7.099868 12.914675 -v -5.179727 8.803307 13.640577 -v -5.179727 8.620581 12.637621 -v -6.725470 11.079216 13.225934 -v -6.725470 10.896488 12.222981 -v -7.268263 13.763827 12.736833 -v -7.268263 14.166320 14.946074 -v -6.725467 16.850937 14.456967 -v -6.725470 16.489346 12.240279 -v -5.179726 19.126841 14.042328 -v -5.179726 18.765253 11.825639 -v -2.866356 20.647554 13.765274 -v -2.866356 20.285967 11.548583 -v -0.137555 21.181559 13.667984 -v -0.137555 20.819971 11.451295 -v -0.137555 6.748590 14.014921 -v -0.137555 7.151085 16.224155 -v -2.866358 7.685090 16.126867 -v -2.866358 7.282592 13.917631 -v -5.179727 9.205801 15.849814 -v -5.179727 8.803307 13.640577 -v -6.725470 11.481709 15.435171 -v -6.725470 11.079216 13.225934 -v -6.725470 16.871246 6.704314 -v -5.131141 16.032776 6.857073 -v -5.542573 12.946739 7.419309 -v -7.268263 12.799915 7.446060 -v -5.179726 19.147156 6.289673 -v -3.959480 17.757896 6.542778 -v -2.866356 20.667866 6.012619 -v -2.205964 18.910583 6.332776 -v -0.137555 21.201870 5.915332 -v -0.137555 19.315353 6.259032 -v -2.866358 6.318684 8.626856 -v -2.205966 8.034017 8.314344 -v -0.137555 7.629245 8.388088 -v -0.137555 5.784679 8.724144 -v -3.959480 9.186704 8.104342 -v -5.131142 10.911824 7.790046 -v -7.168325 14.639720 17.066553 -v -6.633142 17.286711 16.584303 -v -6.633142 16.913443 14.535474 -v -7.168325 14.266452 15.017725 -v -5.109061 19.530722 16.175474 -v -5.109061 19.157454 14.126644 -v -2.828113 21.030119 15.902303 -v -2.828115 20.656855 13.853474 -v -0.137555 21.556639 15.806378 -v -0.137555 21.183367 13.757549 -v -0.137555 7.753714 18.321089 -v -2.828115 8.280234 18.225168 -v -2.828116 7.876051 16.181973 -v -0.137555 7.349532 16.277897 -v -5.109064 9.748725 17.957628 -v -5.109062 9.375453 15.908801 -v -6.633142 11.992731 17.548800 -v -6.633142 11.619465 15.499971 -v -3.642250 10.639707 18.730930 -v -3.642249 17.535583 17.474588 -v -4.716659 15.953656 17.762800 -v -4.716660 12.221634 18.442724 -v -7.406736 17.223406 19.063496 -v -8.005659 14.261175 19.603176 -v -6.594498 14.494061 20.881462 -v -6.102993 16.925011 20.438580 -v -5.701145 19.734667 18.605974 -v -4.703304 18.985874 20.063118 -v -3.148548 21.412638 18.300266 -v -2.608520 20.362902 19.812241 -v -0.137555 22.001863 18.192917 -v -0.137555 20.846445 19.724144 -v -3.148549 7.109707 20.906082 -v -0.137555 6.520483 21.013433 -v -0.137555 8.141681 22.038780 -v -2.608521 8.625226 21.950691 -v -5.701147 8.787681 20.600376 -v -4.703304 10.002252 21.699814 -v -7.406736 11.298944 20.142857 -v -6.102996 12.063114 21.324352 -v -6.594498 14.494061 20.881462 -v -5.322203 14.494061 20.881462 -v -4.927547 16.446011 20.525845 -v -6.102993 16.925011 20.438580 -v -3.803655 18.100796 20.224361 -v -4.703304 18.985874 20.063118 -v -2.121634 19.206488 20.022923 -v -2.608520 20.362902 19.812241 -v -0.137555 19.594753 19.952187 -v -0.137555 20.846445 19.724144 -v -0.137555 8.141681 22.038780 -v -0.137555 9.393373 21.810745 -v -2.121634 9.781638 21.740005 -v -2.608521 8.625226 21.950691 -v -3.803658 10.887330 21.538559 -v -4.703304 10.002252 21.699814 -v -4.927547 12.542114 21.237080 -v -6.102996 12.063114 21.324352 -v -5.093940 14.087643 18.102762 -v -4.716659 15.953656 17.762800 -v -4.927547 16.446011 20.525845 -v -5.322203 14.494061 20.881462 -v -3.642249 17.535583 17.474588 -v -3.803655 18.100796 20.224361 -v -2.034281 18.592596 17.282019 -v -2.121634 19.206488 20.022923 -v -0.137555 18.963770 17.214392 -v -0.137555 19.594753 19.952187 -v -0.137555 9.211522 18.991127 -v -2.034282 9.582694 18.923504 -v -2.121634 9.781638 21.740005 -v -0.137555 9.393373 21.810745 -v -3.642250 10.639707 18.730930 -v -3.803658 10.887330 21.538559 -v -4.716660 12.221634 18.442724 -v -4.927547 12.542114 21.237080 -v -7.168325 14.639720 17.066553 -v -7.929808 14.096279 18.195410 -v -7.336660 17.029957 17.660933 -v -6.633142 17.286711 16.584303 -v -5.647511 19.517012 17.207823 -v -5.109061 19.530722 16.175474 -v -3.119521 21.178797 16.905069 -v -2.828113 21.030119 15.902303 -v -0.137555 21.762342 16.798756 -v -0.137555 21.556639 15.806378 -v -0.137555 7.753714 18.321089 -v -0.137555 6.430205 19.592070 -v -3.119522 7.013754 19.485758 -v -2.828115 8.280234 18.225168 -v -5.647511 8.675551 19.182995 -v -5.109064 9.748725 17.957628 -v -7.336660 11.162606 18.729893 -v -6.633142 11.992731 17.548800 -v -7.929808 14.096279 18.195410 -v -8.005659 14.261175 19.603176 -v -7.406736 17.223406 19.063496 -v -7.336660 17.029957 17.660933 -v -5.701145 19.734667 18.605974 -v -5.647511 19.517012 17.207823 -v -3.148548 21.412638 18.300266 -v -3.119521 21.178797 16.905069 -v -0.137555 22.001863 18.192917 -v -0.137555 21.762342 16.798756 -v -0.137555 6.430205 19.592070 -v -0.137555 6.520483 21.013433 -v -3.148549 7.109707 20.906082 -v -3.119522 7.013754 19.485758 -v -5.701147 8.787681 20.600376 -v -5.647511 8.675551 19.182995 -v -7.406736 11.298944 20.142857 -v -7.336660 11.162606 18.729893 -v -10.448902 -4.065199 8.973198 -v -10.464485 -4.324817 14.341125 -v -10.622765 -5.313800 13.892914 -v -10.464482 -5.093708 9.342202 -v -11.024202 -4.127771 8.234436 -v -10.888246 -2.555629 8.260398 -v -10.177548 -2.803895 8.298583 -v -10.297066 -4.190809 8.244131 -v -10.772985 -1.142371 8.805583 -v -10.076224 -1.547646 8.867919 -v -10.695973 -0.103137 9.786989 -v -10.008523 -0.613330 9.865463 -v -10.668931 0.403852 11.055208 -v -9.984747 -0.143181 11.139349 -v -10.695973 0.301416 12.417167 -v -10.008523 -0.208778 12.495639 -v -10.772990 -0.394859 13.665511 -v -9.998027 -0.800133 13.727847 -v -10.888248 -1.578959 14.610202 -v -10.099266 -1.827220 14.648387 -v -11.024208 -3.070621 15.107410 -v -10.218687 -3.133664 15.117107 -v -11.160166 -4.642758 15.081449 -v -10.338077 -4.520590 15.062659 -v -11.279265 -6.056028 14.536266 -v -10.419976 -5.776834 14.493324 -v -11.279265 -6.056028 14.536266 -v -11.366625 -6.927130 13.528999 -v -10.496778 -6.653613 13.486927 -v -10.419976 -5.776834 14.493324 -v -11.397299 -7.346391 12.247284 -v -10.523744 -7.046638 12.201180 -v -11.366625 -7.331683 10.898822 -v -10.496775 -7.058166 10.856751 -v -11.279260 -6.803540 9.676335 -v -10.419973 -6.524346 9.633391 -v -11.160163 -5.619434 8.731646 -v -10.338074 -5.497261 8.712852 -v -11.685589 -5.810138 10.052730 -v -11.804996 -5.957200 13.093418 -v -11.685592 -5.221654 13.878742 -v -11.639263 -5.001564 9.328028 -v -10.177548 -2.803895 8.298583 -v -10.202976 -2.986496 9.018088 -v -10.297069 -4.078360 8.975224 -v -10.297066 -4.190809 8.244131 -v -10.297066 -4.190809 8.244131 -v -10.297069 -4.078360 8.975224 -v -10.312647 -5.106868 9.344226 -v -10.338074 -5.497261 8.712852 -v -10.338074 -5.497261 8.712852 -v -10.312647 -5.106868 9.344226 -v -10.470928 -5.915451 10.068927 -v -10.419973 -6.524346 9.633391 -v -10.419973 -6.524346 9.633391 -v -10.470928 -5.915451 10.068927 -v -10.427139 -6.380999 11.038991 -v -10.496775 -7.058166 10.856751 -v -10.496775 -7.058166 10.856751 -v -10.427139 -6.380999 11.038991 -v -10.448370 -6.432639 12.106741 -v -10.523744 -7.046638 12.201180 -v -10.523744 -7.046638 12.201180 -v -10.448370 -6.432639 12.106741 -v -10.427139 -6.062517 13.109615 -v -10.496778 -6.653613 13.486927 -v -10.496778 -6.653613 13.486927 -v -10.427139 -6.062517 13.109615 -v -10.470931 -5.326966 13.894939 -v -10.419976 -5.776834 14.493324 -v -10.419976 -5.776834 14.493324 -v -10.470931 -5.326966 13.894939 -v -10.312652 -4.337977 14.343151 -v -10.338077 -4.520590 15.062659 -v -10.338077 -4.520590 15.062659 -v -10.312652 -4.337977 14.343151 -v -10.297069 -3.246119 14.386018 -v -10.218687 -3.133664 15.117107 -v -10.218687 -3.133664 15.117107 -v -10.297069 -3.246119 14.386018 -v -10.202979 -2.217605 14.017013 -v -10.099266 -1.827220 14.648387 -v -10.099266 -1.827220 14.648387 -v -10.202979 -2.217605 14.017013 -v -10.123209 -1.409030 13.292312 -v -9.998027 -0.800133 13.727847 -v -9.998027 -0.800133 13.727847 -v -10.123209 -1.409030 13.292312 -v -10.069911 -0.943481 12.322249 -v -10.008523 -0.208778 12.495639 -v -10.008523 -0.208778 12.495639 -v -10.069911 -0.943481 12.322249 -v -10.051191 -0.891838 11.254501 -v -9.984747 -0.143181 11.139349 -v -9.984747 -0.143181 11.139349 -v -10.051191 -0.891838 11.254501 -v -10.069908 -1.261969 10.251627 -v -10.008523 -0.613330 9.865463 -v -10.008523 -0.613330 9.865463 -v -10.069908 -1.261969 10.251627 -v -10.123206 -1.997514 9.466303 -v -10.076224 -1.547646 8.867919 -v -10.076224 -1.547646 8.867919 -v -10.123206 -1.997514 9.466303 -v -10.202976 -2.986496 9.018088 -v -10.177548 -2.803895 8.298583 -v -11.663559 -4.072338 8.225910 -v -11.663124 -3.954838 8.957199 -v -11.569467 -2.868025 8.999867 -v -11.544039 -2.685418 8.280360 -v -11.544039 -2.685418 8.280360 -v -11.569467 -2.868025 8.999867 -v -11.489699 -1.879037 9.448082 -v -11.442715 -1.429169 8.849696 -v -11.442715 -1.429169 8.849696 -v -11.489699 -1.879037 9.448082 -v -11.436399 -1.143492 10.233404 -v -11.375010 -0.494853 9.847242 -v -11.375010 -0.494853 9.847242 -v -11.436399 -1.143492 10.233404 -v -11.417682 -0.773364 11.236277 -v -11.351240 -0.024707 11.121126 -v -11.351240 -0.024707 11.121126 -v -11.417682 -0.773364 11.236277 -v -11.436399 -0.825004 12.304027 -v -11.375016 -0.090303 12.477416 -v -11.375016 -0.090303 12.477416 -v -11.436399 -0.825004 12.304027 -v -11.489699 -1.290552 13.274091 -v -11.442718 -0.681659 13.709624 -v -11.442718 -0.681659 13.709624 -v -11.489699 -1.290552 13.274091 -v -11.569469 -2.099133 13.998790 -v -11.544042 -1.708743 14.630164 -v -11.544042 -1.708743 14.630164 -v -11.569469 -2.099133 13.998790 -v -11.663559 -3.127642 14.367793 -v -11.663562 -3.015193 15.098885 -v -11.663562 -3.015193 15.098885 -v -11.663559 -3.127642 14.367793 -v -11.791100 -4.219506 14.324928 -v -11.816527 -4.402113 15.044438 -v -11.816527 -4.402113 15.044438 -v -11.791100 -4.219506 14.324928 -v -11.837422 -5.208493 13.876717 -v -11.970063 -5.658357 14.475101 -v -11.970063 -5.658357 14.475101 -v -11.837422 -5.208493 13.876717 -v -11.977229 -5.944039 13.091393 -v -12.046864 -6.569247 13.473953 -v -12.046864 -6.569247 13.473953 -v -11.977229 -5.944039 13.091393 -v -11.998460 -6.314167 12.088518 -v -12.073831 -6.962277 12.188204 -v -12.073831 -6.962277 12.188204 -v -11.998460 -6.314167 12.088518 -v -11.977229 -6.262527 11.020768 -v -12.046861 -6.973800 10.843776 -v -12.046861 -6.973800 10.843776 -v -11.977229 -6.262527 11.020768 -v -11.837420 -5.796978 10.050706 -v -11.970063 -6.405869 9.615170 -v -11.970063 -6.405869 9.615170 -v -11.837420 -5.796978 10.050706 -v -11.791097 -4.988397 9.326004 -v -11.816525 -5.378782 8.694632 -v -11.816525 -5.378782 8.694632 -v -11.791097 -4.988397 9.326004 -v -11.663124 -3.954838 8.957199 -v -11.663559 -4.072338 8.225910 -v -10.202976 -2.986496 9.018088 -v -10.354806 -2.973335 9.016065 -v -10.448902 -4.065199 8.973198 -v -10.297069 -4.078360 8.975224 -v -10.297069 -4.078360 8.975224 -v -10.448902 -4.065199 8.973198 -v -10.464482 -5.093708 9.342202 -v -10.312647 -5.106868 9.344226 -v -10.312647 -5.106868 9.344226 -v -10.464482 -5.093708 9.342202 -v -10.622762 -5.902290 10.066901 -v -10.470928 -5.915451 10.068927 -v -10.470928 -5.915451 10.068927 -v -10.622762 -5.902290 10.066901 -v -10.599370 -6.367838 11.036967 -v -10.427139 -6.380999 11.038991 -v -10.427139 -6.380999 11.038991 -v -10.599370 -6.367838 11.036967 -v -10.620604 -6.419479 12.104715 -v -10.448370 -6.432639 12.106741 -v -10.448370 -6.432639 12.106741 -v -10.620604 -6.419479 12.104715 -v -10.599373 -6.049350 13.107590 -v -10.427139 -6.062517 13.109615 -v -10.427139 -6.062517 13.109615 -v -10.599373 -6.049350 13.107590 -v -10.622765 -5.313800 13.892914 -v -10.470931 -5.326966 13.894939 -v -10.470931 -5.326966 13.894939 -v -10.622765 -5.313800 13.892914 -v -10.464485 -4.324817 14.341125 -v -10.312652 -4.337977 14.343151 -v -10.312652 -4.337977 14.343151 -v -10.464485 -4.324817 14.341125 -v -10.448902 -3.232952 14.383994 -v -10.297069 -3.246119 14.386018 -v -10.297069 -3.246119 14.386018 -v -10.448902 -3.232952 14.383994 -v -10.354809 -2.204439 14.014987 -v -10.202979 -2.217605 14.017013 -v -10.202979 -2.217605 14.017013 -v -10.354809 -2.204439 14.014987 -v -10.275043 -1.395863 13.290288 -v -10.123209 -1.409030 13.292312 -v -10.123209 -1.409030 13.292312 -v -10.275043 -1.395863 13.290288 -v -10.221741 -0.930319 12.320226 -v -10.069911 -0.943481 12.322249 -v -10.069911 -0.943481 12.322249 -v -10.221741 -0.930319 12.320226 -v -10.203024 -0.878675 11.252476 -v -10.051191 -0.891838 11.254501 -v -10.051191 -0.891838 11.254501 -v -10.203024 -0.878675 11.252476 -v -10.221741 -1.248802 10.249601 -v -10.069908 -1.261969 10.251627 -v -10.069908 -1.261969 10.251627 -v -10.221741 -1.248802 10.249601 -v -10.275040 -1.984348 9.464279 -v -10.123206 -1.997514 9.466303 -v -10.123206 -1.997514 9.466303 -v -10.275040 -1.984348 9.464279 -v -10.354806 -2.973335 9.016065 -v -10.202976 -2.986496 9.018088 -v -11.663124 -3.954838 8.957199 -v -11.511726 -3.973048 8.959024 -v -11.417636 -2.881190 9.001891 -v -11.569467 -2.868025 8.999867 -v -11.569467 -2.868025 8.999867 -v -11.417636 -2.881190 9.001891 -v -11.337867 -1.892203 9.450106 -v -11.489699 -1.879037 9.448082 -v -11.489699 -1.879037 9.448082 -v -11.337867 -1.892203 9.450106 -v -11.284566 -1.156657 10.235428 -v -11.436399 -1.143492 10.233404 -v -11.436399 -1.143492 10.233404 -v -11.284566 -1.156657 10.235428 -v -11.265852 -0.786530 11.238302 -v -11.417682 -0.773364 11.236277 -v -11.417682 -0.773364 11.236277 -v -11.265852 -0.786530 11.238302 -v -11.284569 -0.838170 12.306050 -v -11.436399 -0.825004 12.304027 -v -11.436399 -0.825004 12.304027 -v -11.284569 -0.838170 12.306050 -v -11.337867 -1.303718 13.276114 -v -11.489699 -1.290552 13.274091 -v -11.489699 -1.290552 13.274091 -v -11.337867 -1.303718 13.276114 -v -11.417636 -2.112300 14.000815 -v -11.569469 -2.099133 13.998790 -v -11.569469 -2.099133 13.998790 -v -11.417636 -2.112300 14.000815 -v -11.511729 -3.140807 14.369819 -v -11.663559 -3.127642 14.367793 -v -11.663559 -3.127642 14.367793 -v -11.511729 -3.140807 14.369819 -v -11.639269 -4.232666 14.326954 -v -11.791100 -4.219506 14.324928 -v -11.791100 -4.219506 14.324928 -v -11.639269 -4.232666 14.326954 -v -11.685592 -5.221654 13.878742 -v -11.837422 -5.208493 13.876717 -v -11.837422 -5.208493 13.876717 -v -11.685592 -5.221654 13.878742 -v -11.804996 -5.957200 13.093418 -v -11.977229 -5.944039 13.091393 -v -11.977229 -5.944039 13.091393 -v -11.804996 -5.957200 13.093418 -v -11.826226 -6.327328 12.090542 -v -11.998460 -6.314167 12.088518 -v -11.998460 -6.314167 12.088518 -v -11.826226 -6.327328 12.090542 -v -11.804996 -6.275688 11.022794 -v -11.977229 -6.262527 11.020768 -v -11.977229 -6.262527 11.020768 -v -11.804996 -6.275688 11.022794 -v -11.685589 -5.810138 10.052730 -v -11.837420 -5.796978 10.050706 -v -11.837420 -5.796978 10.050706 -v -11.685589 -5.810138 10.052730 -v -11.639263 -5.001564 9.328028 -v -11.791097 -4.988397 9.326004 -v -11.791097 -4.988397 9.326004 -v -11.639263 -5.001564 9.328028 -v -11.511726 -3.973048 8.959024 -v -11.663124 -3.954838 8.957199 -v -11.663559 -4.072338 8.225910 -v -11.544039 -2.685418 8.280360 -v -11.442715 -1.429169 8.849696 -v -11.375010 -0.494853 9.847242 -v -11.351240 -0.024707 11.121126 -v -11.375016 -0.090303 12.477416 -v -11.442718 -0.681659 13.709624 -v -11.544042 -1.708743 14.630164 -v -11.663562 -3.015193 15.098885 -v -11.816527 -4.402113 15.044438 -v -11.970063 -5.658357 14.475101 -v -11.970063 -5.658357 14.475101 -v -12.046864 -6.569247 13.473953 -v -12.073831 -6.962277 12.188204 -v -12.046861 -6.973800 10.843776 -v -11.970063 -6.405869 9.615170 -v -11.816525 -5.378782 8.694632 -v -3.569041 14.261284 19.875835 -v -3.109313 15.949227 19.568314 -v -3.109322 15.910932 19.358097 -v -3.569041 14.222986 19.665619 -v -1.853298 17.184916 19.343189 -v -1.853298 17.146614 19.132973 -v -0.137555 17.637207 19.260788 -v -0.137555 17.598896 19.050575 -v -0.137555 10.885364 20.490883 -v -1.853296 11.337653 20.408482 -v -1.853296 11.299354 20.198269 -v -0.137555 10.847074 20.280666 -v -3.109308 12.573324 20.183361 -v -3.109308 12.535027 19.973148 -v -3.109308 12.573324 20.183361 -v -3.569041 14.261284 19.875835 -v -3.569041 14.222986 19.665619 -v -3.109308 12.535027 19.973148 -v -0.887290 13.289986 21.789577 -v -0.887291 15.845090 21.324074 -v -2.597726 15.861096 20.732384 -v -2.978316 14.463718 20.986965 -v -2.229474 14.552227 21.472775 -v -1.949210 15.581246 21.285297 -v -1.557935 16.884050 20.546009 -v -1.183514 16.334541 21.148060 -v -0.137555 17.258476 20.477798 -v -0.137555 16.610268 21.097824 -v -1.557934 12.043385 21.427917 -v -0.137555 11.668958 21.496132 -v -0.137555 12.494183 21.847721 -v -1.183513 12.769909 21.797489 -v -2.597726 13.066336 21.241550 -v -1.949209 13.523205 21.660248 -v -2.229474 14.552227 21.472775 -v -1.795793 14.552227 21.472775 -v -1.573631 15.367919 21.324165 -v -1.949210 15.581246 21.285297 -v -1.949210 15.581246 21.285297 -v -1.573631 15.367919 21.324165 -v -0.966673 15.965047 21.215378 -v -1.183514 16.334541 21.148060 -v -1.183514 16.334541 21.148060 -v -0.966673 15.965047 21.215378 -v -0.137555 16.183609 21.175556 -v -0.137555 16.610268 21.097824 -v -0.137555 12.494183 21.847721 -v -0.137555 12.920841 21.769989 -v -0.966673 13.139404 21.730171 -v -1.183513 12.769909 21.797489 -v -1.183513 12.769909 21.797489 -v -0.966673 13.139404 21.730171 -v -1.573630 13.736532 21.621380 -v -1.949209 13.523205 21.660248 -v -1.949209 13.523205 21.660248 -v -1.573630 13.736532 21.621380 -v -1.795793 14.552227 21.472775 -v -2.229474 14.552227 21.472775 -v -1.795793 14.507906 21.229500 -v -1.637027 14.507906 21.229500 -v -1.436136 15.245500 21.095123 -v -1.573631 15.323596 21.080891 -v -1.573631 15.323596 21.080891 -v -1.436136 15.245500 21.095123 -v -0.887291 15.785457 20.996750 -v -0.966673 15.920726 20.972099 -v -0.966673 15.920726 20.972099 -v -0.887291 15.785457 20.996750 -v -0.137555 15.983094 20.960735 -v -0.137555 16.139288 20.932285 -v -0.137555 12.876520 21.526718 -v -0.137555 13.032715 21.498264 -v -0.887290 13.230352 21.462250 -v -0.966673 13.095083 21.486900 -v -0.966673 13.095083 21.486900 -v -0.887290 13.230352 21.462250 -v -1.436135 13.770308 21.363880 -v -1.573630 13.692211 21.378109 -v -1.573630 13.692211 21.378109 -v -1.436135 13.770308 21.363880 -v -1.637027 14.507906 21.229500 -v -1.795793 14.507906 21.229500 -v -1.795793 14.552227 21.472775 -v -1.795793 14.507906 21.229500 -v -1.573631 15.323596 21.080891 -v -1.573631 15.367919 21.324165 -v -1.573631 15.367919 21.324165 -v -1.573631 15.323596 21.080891 -v -0.966673 15.920726 20.972099 -v -0.966673 15.965047 21.215378 -v -0.966673 15.965047 21.215378 -v -0.966673 15.920726 20.972099 -v -0.137555 16.139288 20.932285 -v -0.137555 16.183609 21.175556 -v -0.137555 12.920841 21.769989 -v -0.137555 12.876520 21.526718 -v -0.966673 13.095083 21.486900 -v -0.966673 13.139404 21.730171 -v -0.966673 13.139404 21.730171 -v -0.966673 13.095083 21.486900 -v -1.573630 13.692211 21.378109 -v -1.573630 13.736532 21.621380 -v -1.573630 13.736532 21.621380 -v -1.573630 13.692211 21.378109 -v -1.795793 14.507906 21.229500 -v -1.795793 14.552227 21.472775 -v -1.436136 15.305133 21.422447 -v -1.436136 15.245500 21.095123 -v -1.637027 14.507906 21.229500 -v -1.637027 14.567539 21.556824 -v -1.637027 14.567539 21.556824 -v -1.637027 14.507906 21.229500 -v -1.436135 13.770308 21.363880 -v -1.436135 13.829943 21.691204 -v -1.436135 13.829943 21.691204 -v -1.436135 13.770308 21.363880 -v -0.887290 13.230352 21.462250 -v -0.887290 13.289986 21.789577 -v -0.887290 13.289986 21.789577 -v -0.887290 13.230352 21.462250 -v -0.137555 13.032715 21.498264 -v -0.137555 13.092350 21.825588 -v -0.137555 16.042728 21.288063 -v -0.137555 15.983094 20.960735 -v -0.887291 15.785457 20.996750 -v -0.887291 15.845090 21.324074 -v -0.887291 15.845090 21.324074 -v -0.887291 15.785457 20.996750 -v -1.436136 15.245500 21.095123 -v -1.436136 15.305133 21.422447 -v -2.978316 14.261284 19.875835 -v -2.978316 14.463718 20.986965 -v -2.597726 15.861096 20.732384 -v -2.597726 15.658666 19.621250 -v -1.557935 16.884050 20.546009 -v -1.557935 16.681616 19.434883 -v -0.137555 17.258476 20.477798 -v -0.137555 17.056042 19.366665 -v -0.137555 11.466525 20.385002 -v -0.137555 11.668958 21.496132 -v -1.557934 12.043385 21.427917 -v -1.557934 11.840951 20.316792 -v -2.597726 13.066336 21.241550 -v -2.597726 12.863903 20.130421 -v -2.597726 12.863903 20.130421 -v -2.597726 13.066336 21.241550 -v -2.978316 14.463718 20.986965 -v -2.978316 14.261284 19.875835 -v -2.597726 15.658666 19.621250 -v -3.109313 15.949227 19.568314 -v -3.569041 14.261284 19.875835 -v -2.978316 14.261284 19.875835 -v -2.978316 14.261284 19.875835 -v -3.569041 14.261284 19.875835 -v -3.109308 12.573324 20.183361 -v -2.597726 12.863903 20.130421 -v -2.597726 12.863903 20.130421 -v -3.109308 12.573324 20.183361 -v -1.853296 11.337653 20.408482 -v -1.557934 11.840951 20.316792 -v -1.557934 11.840951 20.316792 -v -1.853296 11.337653 20.408482 -v -0.137555 10.885364 20.490883 -v -0.137555 11.466525 20.385002 -v -0.137555 17.056042 19.366665 -v -0.137555 17.637207 19.260788 -v -1.853298 17.184916 19.343189 -v -1.557935 16.681616 19.434883 -v -1.557935 16.681616 19.434883 -v -1.853298 17.184916 19.343189 -v -3.109313 15.949227 19.568314 -v -2.597726 15.658666 19.621250 -v -0.938484 14.114862 23.483055 -v -1.273397 14.910323 23.338135 -v -1.347445 14.898061 23.270828 -v -0.990843 14.051090 23.425133 -v -0.137555 16.032167 23.133743 -v -0.137555 16.092754 23.053173 -v -0.990843 15.745030 23.116516 -v -0.938484 15.705781 23.193211 -v -1.273397 14.910323 23.338135 -v -0.938484 15.705781 23.193211 -v -0.990843 15.745030 23.116516 -v -1.347445 14.898061 23.270828 -v -0.990843 13.707285 21.538033 -v -0.990843 14.051090 23.425133 -v -1.347445 14.898061 23.270828 -v -1.347445 14.554255 21.383720 -v -0.990843 15.745030 23.116516 -v -0.137555 16.092754 23.053173 -v -0.137555 15.748948 21.166065 -v -0.990843 15.401227 21.229416 -v -1.347445 14.554255 21.383720 -v -1.347445 14.898061 23.270828 -v -0.990843 15.745030 23.116516 -v -0.990843 15.401227 21.229416 -v -7.052857 -3.374685 12.138167 -v -7.607366 -2.982224 11.851208 -v -2.921354 7.840734 14.815410 -v -2.367431 7.513035 15.175448 -v -7.663925 -3.256060 12.533605 -v -2.979387 7.707127 15.538341 -v -7.052857 -3.374685 12.138167 -v -2.367431 7.513035 15.175448 -v -6.429377 -3.665658 11.352397 -v -6.978294 -3.810490 10.881698 -v -2.288786 4.917661 2.296532 -v -1.736506 4.755218 2.757458 -v -7.044255 -3.258756 11.366552 -v -2.350004 5.073448 3.014745 -v -6.429377 -3.665658 11.352397 -v -1.736506 4.755218 2.757458 -v -0.137555 -3.498145 12.355363 -v -9.023540 -3.498145 12.355365 -v -9.023540 -4.092004 12.209988 -v -0.137555 -4.092004 12.209984 -v -9.023540 -4.409125 11.687264 -v -0.137555 -4.409125 11.687263 -v -9.023540 -4.263747 11.093406 -v -0.137555 -4.263747 11.093404 -v -9.023540 -3.741025 10.776284 -v -0.137555 -3.741025 10.776280 -v -9.023540 -3.147167 10.921661 -v -0.137555 -3.147167 10.921659 -v -0.137555 -3.147167 10.921659 -v -9.023540 -3.147167 10.921661 -v -9.023540 -2.830044 11.444382 -v -0.137555 -2.830044 11.444382 -v -9.023540 -2.975422 12.038241 -v -0.137555 -2.975422 12.038241 -v -9.023540 -3.498145 12.355365 -v -9.023540 -3.533713 12.124108 -v -9.023540 -3.953632 12.021311 -v -9.023540 -4.092004 12.209988 -v -9.023540 -4.177870 11.651694 -v -9.023540 -4.409125 11.687264 -v -9.023540 -4.075072 11.231778 -v -9.023540 -4.263747 11.093406 -v -9.023540 -3.705457 11.007539 -v -9.023540 -3.741025 10.776284 -v -9.023540 -3.285537 11.110336 -v -9.023540 -3.147167 10.921661 -v -9.023540 -3.147167 10.921661 -v -9.023540 -3.285537 11.110336 -v -9.023540 -3.061300 11.479952 -v -9.023540 -2.830044 11.444382 -v -9.023540 -3.164097 11.899868 -v -9.023540 -2.975422 12.038241 -v -9.881022 -3.541481 12.125302 -v -9.918426 -3.959666 12.022240 -v -9.023540 -3.953632 12.021311 -v -9.023540 -3.533713 12.124108 -v -9.918426 -3.959666 12.022240 -v -9.933917 -4.183187 11.652513 -v -9.023540 -4.177870 11.651694 -v -9.023540 -3.953632 12.021311 -v -9.933917 -4.183187 11.652513 -v -9.918426 -4.081106 11.232705 -v -9.023540 -4.075072 11.231778 -v -9.023540 -4.177870 11.651694 -v -9.918426 -4.081106 11.232705 -v -9.881022 -3.713226 11.008735 -v -9.023540 -3.705457 11.007539 -v -9.023540 -4.075072 11.231778 -v -9.881022 -3.713226 11.008735 -v -9.843617 -3.295041 11.111799 -v -9.023540 -3.285537 11.110336 -v -9.023540 -3.705457 11.007539 -v -9.843617 -3.295041 11.111799 -v -9.828129 -3.071526 11.481525 -v -9.023540 -3.061300 11.479952 -v -9.023540 -3.285537 11.110336 -v -9.828129 -3.071526 11.481525 -v -9.843620 -3.173601 11.901333 -v -9.023540 -3.164097 11.899868 -v -9.023540 -3.061300 11.479952 -v -9.843620 -3.173601 11.901333 -v -9.881022 -3.541481 12.125302 -v -9.023540 -3.533713 12.124108 -v -9.023540 -3.164097 11.899868 -v -9.881022 -3.355837 13.332259 -v -10.215263 -3.324768 13.327479 -v -10.333525 -4.646990 13.001652 -v -9.999287 -4.678094 13.006378 -v -9.999287 -4.678094 13.006378 -v -10.333525 -4.646990 13.001652 -v -10.382511 -5.353782 11.832620 -v -10.048271 -5.384840 11.837338 -v -10.048271 -5.384840 11.837338 -v -10.382511 -5.353782 11.832620 -v -10.333525 -5.031002 10.505172 -v -9.999284 -5.062070 10.509952 -v -9.999284 -5.062070 10.509952 -v -10.333525 -5.031002 10.505172 -v -10.215261 -3.867794 9.797000 -v -9.881022 -3.898864 9.801778 -v -9.881022 -3.898864 9.801778 -v -10.215261 -3.867794 9.797000 -v -10.096996 -2.545539 10.122879 -v -9.762759 -2.576614 10.127659 -v -9.762759 -2.576614 10.127659 -v -10.096996 -2.545539 10.122879 -v -10.048013 -1.838800 11.291918 -v -9.713772 -1.869869 11.296698 -v -9.713772 -1.869869 11.296698 -v -10.048013 -1.838800 11.291918 -v -10.096999 -2.161563 12.619308 -v -9.762759 -2.192633 12.624087 -v -9.762759 -2.192633 12.624087 -v -10.096999 -2.161563 12.619308 -v -10.215263 -3.324768 13.327479 -v -9.881022 -3.355837 13.332259 -v -9.881022 -3.541481 12.125302 -v -9.881022 -3.355837 13.332259 -v -9.999287 -4.678094 13.006378 -v -9.918426 -3.959666 12.022240 -v -9.918426 -3.959666 12.022240 -v -9.999287 -4.678094 13.006378 -v -10.048271 -5.384840 11.837338 -v -9.933917 -4.183187 11.652513 -v -9.933917 -4.183187 11.652513 -v -10.048271 -5.384840 11.837338 -v -9.999284 -5.062070 10.509952 -v -9.918426 -4.081106 11.232705 -v -9.918426 -4.081106 11.232705 -v -9.999284 -5.062070 10.509952 -v -9.881022 -3.898864 9.801778 -v -9.881022 -3.713226 11.008735 -v -9.881022 -3.713226 11.008735 -v -9.881022 -3.898864 9.801778 -v -9.762759 -2.576614 10.127659 -v -9.843617 -3.295041 11.111799 -v -9.843617 -3.295041 11.111799 -v -9.762759 -2.576614 10.127659 -v -9.713772 -1.869869 11.296698 -v -9.828129 -3.071526 11.481525 -v -9.828129 -3.071526 11.481525 -v -9.713772 -1.869869 11.296698 -v -9.762759 -2.192633 12.624087 -v -9.843620 -3.173601 11.901333 -v -9.843620 -3.173601 11.901333 -v -9.762759 -2.192633 12.624087 -v -9.881022 -3.355837 13.332259 -v -9.881022 -3.541481 12.125302 -v -34.616352 10.973569 -4.305973 -v -34.616352 24.350153 -3.728268 -v -34.519024 24.352579 -3.784413 -v -34.519024 10.975993 -4.362118 -v -34.519024 24.347727 -3.672129 -v -34.519024 10.971145 -4.249835 -v -34.519024 10.971145 -4.249835 -v -34.519024 24.347727 -3.672129 -v -30.701521 12.832979 10.128780 -v -13.333050 27.553009 10.638275 -v -13.037113 27.443340 10.522055 -v -30.393160 12.800472 9.998507 -v -30.393160 12.800472 9.998507 -v -13.037113 27.443340 10.522055 -v -13.087281 27.472626 10.853327 -v -30.433870 12.818146 10.331888 -v -6.012183 7.860677 11.055306 -v -30.466719 26.743053 10.866119 -v -30.166159 26.787380 10.721846 -v -5.748137 7.993579 10.894900 -v -5.748137 7.993579 10.894900 -v -30.166159 26.787380 10.721846 -v -30.194857 26.796295 11.056828 -v -5.759465 7.996225 11.231019 -v -31.472544 10.997549 0.614511 -v -31.472544 26.957542 9.600615 -v -31.095026 27.064472 9.410694 -v -31.095026 11.104485 0.424588 -v -31.095026 26.850609 9.790541 -v -31.095026 10.890615 0.804433 -v -31.095026 10.890615 0.804433 -v -31.095026 26.850609 9.790541 -v -6.811996 16.464014 12.762231 -v -14.275897 26.958862 10.850204 -v -14.185555 26.973335 10.576986 -v -6.721651 16.478489 12.489015 -v -13.967443 27.103703 10.441158 -v -6.503540 16.608864 12.353185 -v -13.749335 27.273605 10.522282 -v -6.285429 16.778763 12.434308 -v -6.285429 16.778763 12.434308 -v -13.749335 27.273605 10.522282 -v -13.658987 27.383507 10.772839 -v -6.195086 16.888662 12.684867 -v -13.749335 27.369030 11.046057 -v -6.285429 16.874187 12.958085 -v -13.967443 27.238659 11.181887 -v -6.503540 16.743813 13.093915 -v -14.185555 27.068760 11.100763 -v -6.721651 16.573915 13.012792 -v -3.735173 17.646593 0.622345 -v -3.735174 18.907696 0.392586 -v -2.681455 18.909416 -2.662604 -v -2.681455 17.756693 -2.452592 -v -0.137555 19.238968 -3.988016 -v -0.137555 17.892881 -3.742776 -v -0.137555 19.903610 4.531394 -v -0.137555 21.291946 4.278457 -v -2.681456 20.489861 3.159215 -v -2.681455 19.189877 3.396056 -v -3.735174 18.907696 0.392586 -v -3.143685 18.907696 0.392586 -v -2.263211 18.997980 -2.176482 -v -2.681455 18.909416 -2.662604 -v -2.681455 18.909416 -2.662604 -v -2.263211 18.997980 -2.176482 -v -0.137555 19.364216 -3.300538 -v -0.137555 19.238968 -3.988016 -v -0.137555 21.291946 4.278457 -v -0.137555 20.931133 3.633897 -v -2.263211 20.286793 2.693955 -v -2.681456 20.489861 3.159215 -v -2.681456 20.489861 3.159215 -v -2.263211 20.286793 2.693955 -v -3.143685 18.907696 0.392586 -v -3.735174 18.907696 0.392586 -v -3.143685 18.907696 0.392586 -v -3.143685 17.970634 0.563307 -v -2.263211 17.957739 -1.986966 -v -2.263211 18.997980 -2.176482 -v -2.263211 18.997980 -2.176482 -v -2.263211 17.957739 -1.986966 -v -0.137555 18.330683 -3.112241 -v -0.137555 19.364216 -3.300538 -v -0.137555 20.931133 3.633897 -v -0.137555 20.041740 3.795932 -v -2.263211 19.330694 2.868146 -v -2.263211 20.286793 2.693955 -v -2.263211 20.286793 2.693955 -v -2.263211 19.330694 2.868146 -v -3.143685 17.970634 0.563307 -v -3.143685 18.907696 0.392586 -v -2.039805 19.540924 2.445557 -v -2.039805 22.274622 17.450493 -v -1.882362 22.648573 17.382362 -v -1.882362 19.914867 2.377429 -v -1.502259 22.803465 17.354145 -v -1.502259 20.069763 2.349210 -v -1.122157 22.648573 17.382362 -v -1.122157 19.914867 2.377429 -v -0.964713 22.274622 17.450493 -v -0.964713 19.540924 2.445557 -v -1.122157 21.900675 17.518620 -v -1.122157 19.166975 2.513686 -v -1.122157 19.166975 2.513686 -v -1.122157 21.900675 17.518620 -v -1.502259 21.745783 17.546841 -v -1.502259 19.012081 2.541905 -v -1.882362 21.900675 17.518620 -v -1.882362 19.166975 2.513686 -v -1.502259 21.745783 17.546841 -v -1.502259 22.803465 17.354145 -v -1.603475 22.063547 17.279758 -v -1.603475 22.272367 18.425961 -v -1.539961 22.423220 18.398476 -v -1.539961 22.214399 17.252277 -v -1.386625 22.485704 18.387093 -v -1.386625 22.276884 17.240891 -v -1.233289 22.423220 18.398476 -v -1.233289 22.214399 17.252277 -v -1.169775 22.272367 18.425961 -v -1.169775 22.063547 17.279758 -v -1.233289 22.121515 18.453445 -v -1.233289 21.912691 17.307243 -v -1.386625 22.059031 18.464828 -v -1.386625 21.850206 17.318626 -v -1.539961 22.121515 18.453445 -v -1.539961 21.912691 17.307243 -v -1.539961 21.912691 17.307243 -v -1.539961 22.121515 18.453445 -v -1.386625 22.059031 18.464828 -v -1.386625 22.485704 18.387093 -v -3.417006 10.968184 22.387386 -v -1.213201 14.126719 22.777767 -v -1.609402 14.102673 22.739937 -v -3.879512 11.357963 22.337925 -v -3.140869 10.735471 22.416927 -v -0.655696 14.247482 22.824745 -v -2.925635 10.554080 22.439945 -v -0.440460 14.066093 22.847767 -v -2.794947 10.443944 22.453922 -v -0.448988 13.577412 22.857906 -v -5.848219 8.446975 21.563320 -v -6.357187 8.875909 21.508881 -v -5.294947 7.980704 21.622498 -v -5.070643 7.791671 21.646484 -v -4.863611 7.617192 21.668633 -v -8.008676 6.131011 20.448557 -v -7.011161 7.204411 21.010193 -v -7.693181 7.779181 20.937244 -v -8.842028 6.833315 20.359426 -v -7.264944 5.504225 20.528097 -v -6.356288 6.652514 21.080233 -v -6.753573 5.073263 20.582792 -v -6.045258 6.390395 21.113504 -v -6.315737 4.704283 20.629625 -v -5.715096 6.112151 21.148817 -v -9.969534 5.100362 19.459917 -v -10.725815 2.725559 18.293270 -v -8.920165 4.995983 19.816156 -v -9.343699 6.254065 20.034655 -v -10.773172 0.857841 17.474567 -v -8.424287 3.994022 19.687868 -v -10.118230 -0.388031 17.222591 -v -7.879467 3.319399 19.677153 -v -8.821138 -0.079582 17.997200 -v -7.176163 3.160187 19.890013 -v -2.690449 10.355878 22.465099 -v -0.420340 13.100590 22.867107 -v -4.698066 7.477681 21.686337 -v -5.451099 5.889658 21.177050 -v -6.419691 3.224981 20.184286 -v -5.965638 4.409235 20.667070 -v -7.374048 1.015672 19.080969 -v -1.609402 14.102673 22.739937 -v -1.576042 14.106964 22.461826 -v -3.832299 11.379006 22.062275 -v -3.879512 11.357963 22.337925 -v -1.213201 14.126719 22.777767 -v -1.180917 14.129717 22.499580 -v -1.576042 14.106964 22.461826 -v -1.609402 14.102673 22.739937 -v -0.655696 14.247482 22.824745 -v -0.625182 14.248373 22.546444 -v -1.180917 14.129717 22.499580 -v -1.213201 14.126719 22.777767 -v -0.440460 14.066093 22.847767 -v -0.409945 14.066982 22.569466 -v -0.625182 14.248373 22.546444 -v -0.655696 14.247482 22.824745 -v -2.690449 10.355878 22.465099 -v -2.643234 10.376924 22.189453 -v -0.386982 13.104876 22.589008 -v -0.420340 13.100590 22.867107 -v -0.448988 13.577412 22.857906 -v -0.416986 13.580074 22.579697 -v -0.409945 14.066982 22.569466 -v -0.440460 14.066093 22.847767 -v -3.879512 11.357963 22.337925 -v -3.832299 11.379006 22.062275 -v -6.296528 8.913524 21.238117 -v -6.357187 8.875909 21.508881 -v -4.698066 7.477681 21.686337 -v -4.637406 7.515300 21.415569 -v -2.643234 10.376924 22.189453 -v -2.690449 10.355878 22.465099 -v -7.693181 7.779181 20.937244 -v -7.626042 7.824908 20.669788 -v -8.769339 6.886054 20.095335 -v -8.842028 6.833315 20.359426 -v -5.451099 5.889658 21.177050 -v -5.383957 5.935385 20.909594 -v -4.637406 7.515300 21.415569 -v -4.698066 7.477681 21.686337 -v -9.343699 6.254065 20.034655 -v -9.268124 6.310481 19.772535 -v -9.889118 5.162975 19.201414 -v -9.969534 5.100362 19.459917 -v -9.969534 5.100362 19.459917 -v -9.889118 5.162975 19.201414 -v -10.636815 2.799323 18.042316 -v -10.725815 2.725559 18.293270 -v -10.725815 2.725559 18.293270 -v -10.636815 2.799323 18.042316 -v -10.678776 0.938709 17.229160 -v -10.773172 0.857841 17.474567 -v -10.773172 0.857841 17.474567 -v -10.678776 0.938709 17.229160 -v -10.021882 -0.304576 16.979359 -v -10.118230 -0.388031 17.222591 -v -8.821138 -0.079582 17.997200 -v -8.728744 -0.001357 17.749660 -v -7.288219 1.085293 18.827051 -v -7.374048 1.015672 19.080969 -v -6.419691 3.224981 20.184286 -v -6.342486 3.283472 19.923330 -v -5.892945 4.461967 20.402983 -v -5.965638 4.409235 20.667070 -v -10.118230 -0.388031 17.222591 -v -10.021882 -0.304576 16.979359 -v -8.728744 -0.001357 17.749660 -v -8.821138 -0.079582 17.997200 -v -0.420340 13.100590 22.867107 -v -0.386982 13.104876 22.589008 -v -0.416986 13.580074 22.579697 -v -0.448988 13.577412 22.857906 -v -7.374048 1.015672 19.080969 -v -7.288219 1.085293 18.827051 -v -6.342486 3.283472 19.923330 -v -6.419691 3.224981 20.184286 -v -8.842028 6.833315 20.359426 -v -8.769339 6.886054 20.095335 -v -9.268124 6.310481 19.772535 -v -9.343699 6.254065 20.034655 -v -6.357187 8.875909 21.508881 -v -6.296528 8.913524 21.238117 -v -7.626042 7.824908 20.669788 -v -7.693181 7.779181 20.937244 -v -5.965638 4.409235 20.667070 -v -5.892945 4.461967 20.402983 -v -5.383957 5.935385 20.909594 -v -5.451099 5.889658 21.177050 -v -3.832299 11.379006 22.062275 -v -2.643234 10.376924 22.189453 -v -4.637406 7.515300 21.415569 -v -6.296528 8.913524 21.238117 -v -1.576042 14.106964 22.461826 -v -1.180917 14.129717 22.499580 -v -0.416986 13.580074 22.579697 -v -0.386982 13.104876 22.589008 -v -0.416986 13.580074 22.579697 -v -1.180917 14.129717 22.499580 -v -0.625182 14.248373 22.546444 -v -0.409945 14.066982 22.569466 -v -3.832299 11.379006 22.062275 -v -1.576042 14.106964 22.461826 -v -0.386982 13.104876 22.589008 -v -2.643234 10.376924 22.189453 -v -4.637406 7.515300 21.415569 -v -5.383957 5.935385 20.909594 -v -7.626042 7.824908 20.669788 -v -6.296528 8.913524 21.238117 -v -5.892945 4.461967 20.402983 -v -6.342486 3.283472 19.923330 -v -9.268124 6.310481 19.772535 -v -8.769339 6.886054 20.095335 -v -8.769339 6.886054 20.095335 -v -7.626042 7.824908 20.669788 -v -5.383957 5.935385 20.909594 -v -5.892945 4.461967 20.402983 -v -10.636815 2.799323 18.042316 -v -8.728744 -0.001357 17.749660 -v -10.021882 -0.304576 16.979359 -v -10.678776 0.938709 17.229160 -v -9.889118 5.162975 19.201414 -v -9.268124 6.310481 19.772535 -v -6.342486 3.283472 19.923330 -v -7.288219 1.085293 18.827051 -v -10.636815 2.799323 18.042316 -v -9.889118 5.162975 19.201414 -v -7.288219 1.085293 18.827051 -v -8.728744 -0.001357 17.749660 -v 0.330618 18.670710 -33.683582 -v 0.285053 18.414829 -35.894424 -v -0.560163 18.414829 -35.894424 -v -0.605727 18.670710 -33.683582 -v -0.651571 18.602148 -30.355957 -v -0.605727 18.670710 -33.683582 -v -0.560163 18.414829 -35.894424 -v -0.605767 17.075186 -24.744356 -v -0.605767 17.075186 -24.744356 -v -0.605767 11.401349 -24.776545 -v -0.605767 12.973974 -22.107353 -v -0.605767 15.336257 -22.014980 -v -0.605767 11.401349 -24.776545 -v -0.651571 3.909487 -27.628571 -v -0.605766 4.289977 -24.225880 -v -0.605767 7.251087 -23.778145 -v -0.560163 18.414829 -35.894424 -v -0.475242 4.545812 -36.862782 -v -0.605767 11.401349 -24.776545 -v -0.605767 17.075186 -24.744356 -v -0.475242 4.545812 -36.862782 -v -0.494697 3.910732 -35.557438 -v -0.560162 3.476720 -33.171906 -v -0.651571 3.909487 -27.628571 -v -0.560163 18.414829 -35.894424 -v -0.475242 15.707024 -39.244591 -v -0.445198 12.034781 -40.236835 -v -0.475242 4.545812 -36.862782 -v -0.445198 12.034781 -40.236835 -v -0.445197 9.315046 -39.888615 -v -0.445197 6.808916 -39.080044 -v -0.475242 4.545812 -36.862782 -v 0.330657 15.336257 -22.014980 -v 0.330657 17.075186 -24.744356 -v -0.605767 17.075186 -24.744356 -v -0.605767 15.336257 -22.014980 -v 0.330657 17.075186 -24.744356 -v 0.330657 18.078314 -27.583200 -v -0.605767 18.078314 -27.583200 -v -0.605767 17.075186 -24.744356 -v 0.170088 12.034781 -40.236835 -v -0.445198 12.034781 -40.236835 -v -0.445197 13.888091 -40.062054 -v 0.170088 13.888091 -40.062054 -v 0.330618 3.524783 -30.914526 -v 0.376461 3.909487 -27.628571 -v -0.651571 3.909487 -27.628571 -v -0.605727 3.524783 -30.914526 -v 0.376461 3.909487 -27.628571 -v 0.330657 4.289977 -24.225880 -v -0.605766 4.289977 -24.225880 -v -0.651571 3.909487 -27.628571 -v 0.200132 15.707024 -39.244591 -v -0.475242 15.707024 -39.244591 -v -0.494698 17.377857 -38.011116 -v 0.219588 17.377857 -38.011116 -v 0.219588 3.910732 -35.557438 -v -0.494697 3.910732 -35.557438 -v -0.475242 4.545812 -36.862782 -v 0.200132 4.545812 -36.862782 -v 0.170088 13.888091 -40.062054 -v -0.445197 13.888091 -40.062054 -v -0.475242 15.707024 -39.244591 -v 0.200132 15.707024 -39.244591 -v 0.285052 3.476720 -33.171906 -v -0.560162 3.476720 -33.171906 -v -0.494697 3.910732 -35.557438 -v 0.219588 3.910732 -35.557438 -v 0.170088 6.808916 -39.080044 -v -0.445197 6.808916 -39.080044 -v -0.445197 9.315046 -39.888615 -v 0.170088 9.315046 -39.888615 -v 0.219588 17.377857 -38.011116 -v -0.494698 17.377857 -38.011116 -v -0.560163 18.414829 -35.894424 -v 0.285053 18.414829 -35.894424 -v 0.200132 4.545812 -36.862782 -v -0.475242 4.545812 -36.862782 -v -0.445197 5.657253 -38.139938 -v 0.170088 5.657253 -38.139938 -v 0.330618 18.670710 -33.683582 -v -0.605727 18.670710 -33.683582 -v -0.651571 18.602148 -30.355957 -v 0.376462 18.602148 -30.355957 -v 0.330657 18.078314 -27.583200 -v 0.376462 18.602148 -30.355957 -v -0.651571 18.602148 -30.355957 -v -0.605767 18.078314 -27.583200 -v 0.170088 9.315046 -39.888615 -v -0.445197 9.315046 -39.888615 -v -0.445198 12.034781 -40.236835 -v 0.170088 12.034781 -40.236835 -v 0.330657 11.401349 -24.776545 -v 0.330657 12.973974 -22.107353 -v -0.605767 12.973974 -22.107353 -v -0.605767 11.401349 -24.776545 -v 0.330657 4.289977 -24.225880 -v 0.330657 7.251087 -23.778145 -v -0.605767 7.251087 -23.778145 -v -0.605766 4.289977 -24.225880 -v 0.285052 3.476720 -33.171906 -v 0.330618 3.524783 -30.914526 -v -0.605727 3.524783 -30.914526 -v -0.560162 3.476720 -33.171906 -v 0.170088 5.657253 -38.139938 -v -0.445197 5.657253 -38.139938 -v -0.445197 6.808916 -39.080044 -v 0.170088 6.808916 -39.080044 -v 0.330657 7.251087 -23.778145 -v 0.330657 11.401349 -24.776545 -v -0.605767 11.401349 -24.776545 -v -0.605767 7.251087 -23.778145 -v 0.330657 12.973974 -22.107353 -v 0.330657 15.336257 -22.014980 -v -0.605767 15.336257 -22.014980 -v -0.605767 12.973974 -22.107353 -v -11.639269 -4.232666 14.326954 -v -11.511729 -3.140807 14.369819 -v -11.417636 -2.881190 9.001891 -v -11.511726 -3.973048 8.959024 -v -11.417636 -2.112300 14.000815 -v -11.337867 -1.892203 9.450106 -v -11.804996 -6.275688 11.022794 -v -11.826226 -6.327328 12.090542 -v -11.337867 -1.303718 13.276114 -v -11.284566 -1.156657 10.235428 -v -11.284569 -0.838170 12.306050 -v -11.265852 -0.786530 11.238302 -v -10.221741 -1.248802 10.249601 -v -10.203024 -0.878675 11.252476 -v -10.221741 -0.930319 12.320226 -v -10.275043 -1.395863 13.290288 -v -10.354806 -2.973335 9.016065 -v -10.275040 -1.984348 9.464279 -v -10.354809 -2.204439 14.014987 -v -10.448902 -3.232952 14.383994 -v -10.599373 -6.049350 13.107590 -v -10.622762 -5.902290 10.066901 -v -10.620604 -6.419479 12.104715 -v -10.599370 -6.367838 11.036967 -v -0.137555 13.788481 23.542515 -v -0.137555 16.032167 23.133743 -v -0.137555 13.092350 21.825588 -v -0.137555 16.042728 21.288063 -v -2.034282 9.582694 18.923504 -v -2.034281 18.592596 17.282019 -v -0.137555 9.211522 18.991127 -v -0.137555 18.963770 17.214392 -v -0.137555 9.192825 -28.695456 -v -0.137555 10.607282 -20.931702 -v -5.704780 25.412260 -1.122682 -v -6.124956 25.098688 -2.843851 -v -6.725490 10.797626 7.312677 -v -5.433122 11.356320 7.210891 -v -5.870196 13.518061 6.817050 -v -7.268282 13.482239 6.823577 -v -5.179747 8.521720 7.727320 -v -4.188437 9.523684 7.544775 -v -5.433122 11.356320 7.210891 -v -6.725490 10.797626 7.312677 -v -7.268282 13.482239 6.823577 -v -5.870196 13.518061 6.817050 -v -5.433122 15.679805 6.423209 -v -6.725487 16.166853 6.334475 -v -2.866378 7.001008 8.004374 -v -2.325634 8.299153 7.767869 -v -4.188437 9.523684 7.544775 -v -5.179747 8.521720 7.727320 -v -5.179746 19.031322 5.812605 -v -4.188436 17.986372 6.002982 -v -2.325632 19.210899 5.779888 -v -2.866376 20.552032 5.535551 -v -6.725487 16.166853 6.334475 -v -5.433122 15.679805 6.423209 -v -4.188436 17.986372 6.002982 -v -5.179746 19.031322 5.812605 -v -2.866376 20.552032 5.535551 -v -2.325632 19.210899 5.779888 -v -0.137555 19.639086 5.701879 -v -0.137555 21.086037 5.438262 -v -0.137555 13.788481 23.542515 -v -0.938484 14.114862 23.483055 -v -0.990843 14.051090 23.425133 -v -0.137555 13.703371 23.488483 -v -0.137555 13.703371 23.488483 -v -0.990843 14.051090 23.425133 -v -0.990843 13.707285 21.538033 -v -0.137555 13.359564 21.601383 -v -0.137555 6.467003 8.101662 -v -0.137555 7.870969 7.845878 -v -2.325634 8.299153 7.767869 -v -2.866378 7.001008 8.004374 -v 1.870543 20.548264 5.038902 -v 1.870543 22.464592 4.689771 -v 0.505632 23.065418 4.580308 -v 0.505632 20.832825 4.987058 -v -0.859279 23.065418 4.580308 -v -0.859279 20.832825 4.987056 -v -2.224189 22.464592 4.689771 -v -2.224189 20.548264 5.038902 -v 1.870543 20.472183 4.621320 -v 0.505632 20.756752 4.569478 -v 0.505632 22.989342 4.162726 -v 1.870543 22.388515 4.272189 -v -0.859278 20.756752 4.569476 -v -0.859278 22.989342 4.162726 -v -2.224189 20.472183 4.621320 -v -2.224189 22.388515 4.272189 -v -2.224189 20.548264 5.038902 -v -2.224189 22.464592 4.689771 -v -2.224189 22.388515 4.272189 -v -2.224189 20.472183 4.621320 -v -2.224189 22.464592 4.689771 -v -0.859279 23.065418 4.580308 -v -0.859278 22.989342 4.162726 -v -2.224189 22.388515 4.272189 -v 0.505632 23.065418 4.580308 -v 0.505632 22.989342 4.162726 -v 1.870543 22.464592 4.689771 -v 1.870543 22.388515 4.272189 -v 1.870543 22.464592 4.689771 -v 1.870543 20.548264 5.038902 -v 1.870543 20.472183 4.621320 -v 1.870543 22.388515 4.272189 -v -1.806203 23.529200 16.307932 -v -1.365730 23.349699 16.340633 -v -1.183280 22.916361 16.419582 -v -1.806203 22.916361 16.419582 -v -1.183280 22.916361 16.419582 -v -1.365730 23.349699 16.340633 -v -1.365730 23.360544 16.400158 -v -1.183280 22.927206 16.479107 -v -1.806203 23.529200 16.307932 -v -1.806203 23.540041 16.367455 -v -2.246677 23.349699 16.340633 -v -2.246677 23.360544 16.400158 -v -2.429127 22.916361 16.419582 -v -2.429127 22.927206 16.479107 -v -2.246677 22.483023 16.498531 -v -2.246677 22.493864 16.558056 -v -1.806203 22.303526 16.531235 -v -1.806203 22.314371 16.590755 -v -1.365730 22.483023 16.498531 -v -1.365730 22.493864 16.558056 -v -1.183280 22.927206 16.479107 -v -1.365730 23.360544 16.400158 -v -1.806203 23.540041 16.367455 -v -1.806203 22.927206 16.479107 -v -2.246677 23.349699 16.340633 -v -2.429127 22.916361 16.419582 -v -2.246677 23.360544 16.400158 -v -2.429127 22.927206 16.479107 -v -2.246677 22.493864 16.558056 -v -1.806203 22.314371 16.590755 -v -1.365730 22.493864 16.558056 -v -1.365730 22.483023 16.498531 -v -1.806203 22.303526 16.531235 -v -2.246677 22.483023 16.498531 -v 29.751905 10.424383 -0.328292 -v 29.443541 10.391874 -0.458566 -v 12.087492 25.034750 0.064983 -v 12.383435 25.144411 0.181201 -v 29.443541 10.391874 -0.458566 -v 29.484251 10.409550 -0.125184 -v 12.137660 25.064028 0.396255 -v 12.087492 25.034750 0.064983 -v 5.062560 5.452081 0.598234 -v 4.798513 5.584981 0.437826 -v 29.216539 24.378778 0.264774 -v 29.517099 24.334452 0.409047 -v 4.798513 5.584981 0.437826 -v 4.809842 5.587626 0.773945 -v 29.245237 24.387697 0.599754 -v 29.216539 24.378778 0.264774 -v 5.862374 14.055417 2.305160 -v 5.772030 14.069890 2.031945 -v 13.235933 24.564737 0.119916 -v 13.326281 24.550264 0.393134 -v 5.553920 14.200265 1.896114 -v 13.017826 24.695112 -0.015912 -v 5.335808 14.370164 1.977235 -v 12.799714 24.865015 0.065210 -v 5.335808 14.370164 1.977235 -v 5.245464 14.480065 2.227794 -v 12.709373 24.974913 0.315768 -v 12.799714 24.865015 0.065210 -v 5.335808 14.465589 2.501012 -v 12.799714 24.960436 0.588987 -v 5.553920 14.335216 2.636842 -v 13.017826 24.830057 0.724817 -v 5.772030 14.165317 2.555719 -v 13.235933 24.660166 0.643693 -v 30.305048 10.643557 0.578635 -v 30.963701 10.618658 0.579076 -v 30.813036 24.929342 1.613645 -v 30.154379 24.954233 1.613205 -v 30.963701 10.618658 0.579076 -v 30.960356 10.720448 -1.269946 -v 30.809679 25.031126 -0.235375 -v 30.813036 24.929342 1.613645 -v 30.960356 10.720448 -1.269946 -v 30.301702 10.745346 -1.270385 -v 30.151026 25.056025 -0.235818 -v 30.809679 25.031126 -0.235375 -v 30.301702 10.745346 -1.270385 -v 30.305048 10.643557 0.578635 -v 30.154379 24.954233 1.613205 -v 30.151026 25.056025 -0.235818 -v 30.168859 12.297785 8.400374 -v 29.800108 12.215061 8.225577 -v 30.481874 25.568533 0.910831 -v 30.850637 25.651247 1.085624 -v 29.783651 12.389593 8.543138 -v 30.465429 25.743063 1.228393 -v 29.783651 12.389593 8.543138 -v 30.465429 25.743063 1.228393 -v -30.407583 10.874838 0.548656 -v -30.256914 25.185518 1.583229 -v -30.915556 25.160620 1.583671 -v -31.066236 10.849939 0.549096 -v -31.066236 10.849939 0.549096 -v -30.915556 25.160620 1.583671 -v -30.912214 25.262411 -0.265351 -v -31.062880 10.951727 -1.299926 -v -31.062880 10.951727 -1.299926 -v -30.912214 25.262411 -0.265351 -v -30.253561 25.287302 -0.265792 -v -30.404238 10.976625 -1.300365 -v -30.404238 10.976625 -1.300365 -v -30.253561 25.287302 -0.265792 -v -30.256914 25.185518 1.583229 -v -30.407583 10.874838 0.548656 -v -30.528948 11.244707 0.468940 -v -13.160481 25.964739 0.978435 -v -12.864539 25.855074 0.862214 -v -30.220583 11.212198 0.338664 -v -30.220583 11.212198 0.338664 -v -12.864539 25.855074 0.862214 -v -12.914712 25.884352 1.193487 -v -30.261293 11.229874 0.672046 -v -5.839613 6.272407 1.395468 -v -30.294146 25.154779 1.206283 -v -29.993582 25.199106 1.062009 -v -5.575566 6.405307 1.235060 -v -5.575566 6.405307 1.235060 -v -29.993582 25.199106 1.062009 -v -30.022280 25.208025 1.396987 -v -5.586895 6.407953 1.571177 -v -6.639424 14.875742 3.102392 -v -14.103328 25.370588 1.190364 -v -14.012986 25.385061 0.917148 -v -6.549077 14.890219 2.829175 -v -13.794873 25.515436 0.781316 -v -6.330967 15.020592 2.693344 -v -13.576761 25.685339 0.862441 -v -6.112858 15.190493 2.774467 -v -6.112858 15.190493 2.774467 -v -13.576761 25.685339 0.862441 -v -13.486419 25.795240 1.112998 -v -6.022512 15.300392 3.025024 -v -13.576761 25.780760 1.386217 -v -6.112858 15.285915 3.298242 -v -13.794873 25.650393 1.522045 -v -6.330967 15.155542 3.434072 -v -14.012986 25.480490 1.440923 -v -6.549077 14.985643 3.352951 -v -30.282450 25.731180 1.116691 -v -30.282450 12.223915 9.098432 -v -29.904940 12.318897 9.259166 -v -29.904940 25.826159 1.277427 -v -29.904940 12.128931 8.937694 -v -29.904940 25.636194 0.955959 -v -29.904940 25.636194 0.955959 -v -29.904940 12.128931 8.937694 -vt 1.879478 0.530174 -vt 1.897414 0.524735 -vt 1.879566 0.526113 -vt 1.881690 0.427537 -vt 1.899500 0.427921 -vt 1.881778 0.423476 -vt 1.948867 0.692212 -vt 1.948604 0.707056 -vt 1.953637 0.699684 -vt 0.565573 0.782724 -vt 0.597737 0.776562 -vt 0.631173 0.764652 -vt 0.596866 0.612516 -vt 0.558627 0.607968 -vt 0.532640 0.607381 -vt 0.630058 0.699236 -vt 0.596866 0.612516 -vt 0.489568 0.620042 -vt 0.489568 0.620042 -vt 0.475518 0.632309 -vt 0.464575 0.645515 -vt 0.450798 0.706790 -vt 0.452967 0.728116 -vt 0.462399 0.748874 -vt 0.462399 0.748874 -vt 0.476409 0.768140 -vt 0.500841 0.780471 -vt 1.802491 0.725181 -vt 1.806539 0.710319 -vt 1.802491 0.695456 -vt 1.052336 0.836845 -vt 1.057214 0.817874 -vt 1.052250 0.798920 -vt 0.848890 0.817343 -vt 0.848723 0.828857 -vt 0.856840 0.837024 -vt 0.876845 0.828942 -vt 0.877015 0.817427 -vt 0.868894 0.809261 -vt 1.880832 0.983071 -vt 1.880933 0.976152 -vt 1.876054 0.971245 -vt 1.864033 0.976101 -vt 1.863932 0.983021 -vt 1.868811 0.987928 -vt 0.879478 0.530174 -vt 0.879566 0.526113 -vt 0.897414 0.524735 -vt 0.881690 0.427537 -vt 0.881778 0.423476 -vt 0.899500 0.427921 -vt 0.948867 0.692212 -vt 0.953637 0.699684 -vt 0.948604 0.707056 -vt 0.565573 0.782724 -vt 0.631173 0.764652 -vt 0.597737 0.776562 -vt 0.596866 0.612516 -vt 0.532640 0.607381 -vt 0.558627 0.607968 -vt 0.630058 0.699236 -vt 0.489568 0.620042 -vt 0.596866 0.612516 -vt 0.489568 0.620042 -vt 0.464575 0.645515 -vt 0.475518 0.632309 -vt 0.450798 0.706790 -vt 0.462399 0.748874 -vt 0.452967 0.728116 -vt 0.462399 0.748874 -vt 0.500841 0.780471 -vt 0.476409 0.768140 -vt 0.802491 0.725181 -vt 0.802491 0.695456 -vt 0.806539 0.710319 -vt 0.052336 0.836845 -vt 0.052250 0.798920 -vt 0.057214 0.817874 -vt 1.848890 0.817343 -vt 1.856840 0.837024 -vt 1.848723 0.828857 -vt 1.876845 0.828942 -vt 1.868894 0.809261 -vt 1.877015 0.817427 -vt 0.880832 0.983071 -vt 0.876054 0.971245 -vt 0.880933 0.976152 -vt 0.864033 0.976101 -vt 0.868811 0.987928 -vt 0.863932 0.983021 -vt 0.764773 0.724732 -vt 0.734627 0.710218 -vt 0.734627 0.809321 -vt 1.897414 0.524735 -vt 1.923223 0.496405 -vt 1.880188 0.497240 -vt 1.879566 0.526113 -vt 1.923223 0.496405 -vt 1.924064 0.457336 -vt 1.881068 0.456409 -vt 1.880188 0.497240 -vt 1.881068 0.456409 -vt 1.924064 0.457336 -vt 1.899500 0.427921 -vt 1.881690 0.427537 -vt 0.122549 0.656233 -vt 0.122578 0.652637 -vt 0.010500 0.652637 -vt 0.010633 0.652337 -vt 0.234486 0.661460 -vt 0.234656 0.654561 -vt 0.346443 0.668053 -vt 0.346734 0.658459 -vt 0.407538 0.672188 -vt 0.408643 0.660136 -vt 0.122122 0.451058 -vt 0.123852 0.442823 -vt 0.078205 0.439206 -vt 0.076831 0.448786 -vt 0.234965 0.454150 -vt 0.235514 0.448414 -vt 0.347024 0.455886 -vt 0.347440 0.450682 -vt 0.428376 0.456721 -vt 0.428786 0.451517 -vt 0.454072 0.482134 -vt 0.433218 0.452772 -vt 0.428376 0.456721 -vt 1.008858 0.429252 -vt 1.359604 0.433571 -vt 1.361111 0.429252 -vt 1.415687 0.433571 -vt 1.415695 0.429252 -vt 1.007350 0.223041 -vt 1.359604 0.226016 -vt 1.360039 0.219522 -vt 1.007350 0.219056 -vt 1.408423 0.225906 -vt 1.411958 0.221276 -vt 1.417122 0.012457 -vt 1.444812 0.062060 -vt 1.449332 0.062060 -vt 1.421961 0.012442 -vt 1.676401 0.986658 -vt 1.700313 0.990996 -vt 1.701728 0.978157 -vt 1.677748 0.976969 -vt 1.786661 0.989188 -vt 1.787706 0.983066 -vt 1.808887 0.988109 -vt 1.806581 0.983761 -vt 2.956937 0.990430 -vt 2.964659 0.990613 -vt 2.960512 0.822945 -vt 2.952790 0.822763 -vt 2.964659 0.990613 -vt 2.986306 0.990450 -vt 2.982158 0.822781 -vt 2.960512 0.822945 -vt 2.986306 0.990450 -vt 2.994010 0.989886 -vt 2.989862 0.822218 -vt 2.982158 0.822781 -vt 2.935309 0.991339 -vt 2.956937 0.990430 -vt 2.952790 0.822763 -vt 2.931161 0.823668 -vt 0.880274 0.541093 -vt 0.880271 0.560769 -vt 0.894615 0.560769 -vt 0.894613 0.541093 -vt 0.880271 0.585741 -vt 0.894615 0.585741 -vt 0.894611 0.566056 -vt 0.880276 0.566056 -vt 0.880274 0.541093 -vt 0.894613 0.541093 -vt 0.894601 0.535809 -vt 0.880285 0.535809 -vt 0.899927 0.585758 -vt 0.899927 0.566039 -vt 0.894611 0.566056 -vt 0.894615 0.585741 -vt 0.894615 0.560769 -vt 0.880271 0.560769 -vt 0.880276 0.566056 -vt 0.894611 0.566056 -vt 0.874960 0.566039 -vt 0.874960 0.585758 -vt 0.880271 0.585741 -vt 0.880276 0.566056 -vt 0.151943 0.966273 -vt 0.118276 0.966204 -vt 0.118294 0.984845 -vt 0.151961 0.984813 -vt 0.178138 0.965761 -vt 0.178157 0.984787 -vt 0.204440 0.965590 -vt 0.204459 0.984762 -vt 0.232801 0.965563 -vt 0.232820 0.984734 -vt 0.038622 0.965136 -vt 0.012148 0.965162 -vt 0.014053 0.984946 -vt 0.038641 0.984922 -vt 0.065148 0.965369 -vt 0.065167 0.984896 -vt 0.091706 0.965741 -vt 0.091724 0.984871 -vt 1.041294 0.782869 -vt 1.041455 0.852946 -vt 1.347561 0.949223 -vt 1.320488 0.949446 -vt 1.320590 0.961766 -vt 1.347663 0.961543 -vt 1.293415 0.949670 -vt 1.293517 0.961990 -vt 1.266341 0.949894 -vt 1.266443 0.962214 -vt 1.239268 0.950118 -vt 1.239370 0.962438 -vt 1.455855 0.948328 -vt 1.428781 0.948551 -vt 1.428883 0.960871 -vt 1.455957 0.960648 -vt 1.401708 0.948775 -vt 1.401810 0.961095 -vt 1.374635 0.948999 -vt 1.374737 0.961319 -vt 0.570606 0.567542 -vt 0.583420 0.567306 -vt 0.583267 0.559022 -vt 0.570454 0.559258 -vt 0.597978 0.567038 -vt 0.597825 0.558754 -vt 0.613012 0.566762 -vt 0.612860 0.558477 -vt 0.613380 0.586739 -vt 0.598345 0.587015 -vt 0.598505 0.595698 -vt 0.613540 0.595421 -vt 0.583787 0.587283 -vt 0.583947 0.595966 -vt 0.570974 0.587519 -vt 0.571134 0.596202 -vt 0.557296 0.587771 -vt 0.557455 0.596453 -vt 0.543262 0.588029 -vt 0.543422 0.596712 -vt 0.528359 0.588303 -vt 0.528518 0.596986 -vt 1.932941 0.593358 -vt 1.936440 0.593358 -vt 1.936440 0.572867 -vt 1.932941 0.572867 -vt 1.791431 0.684576 -vt 1.791431 0.736062 -vt 1.978612 0.593111 -vt 1.978612 0.614013 -vt 1.985470 0.613849 -vt 1.985470 0.593358 -vt 1.978612 0.614013 -vt 1.978612 0.634422 -vt 1.985470 0.634339 -vt 1.985470 0.613849 -vt 1.978612 0.634422 -vt 1.978612 0.654830 -vt 1.985470 0.654830 -vt 1.985470 0.634339 -vt 1.978612 0.531886 -vt 1.978612 0.552294 -vt 1.985470 0.552377 -vt 1.985470 0.531886 -vt 1.978612 0.552294 -vt 1.978612 0.572703 -vt 1.985470 0.572867 -vt 1.985470 0.552377 -vt 1.978612 0.572703 -vt 1.978612 0.593111 -vt 1.985470 0.593358 -vt 1.985470 0.572867 -vt 1.989519 0.593358 -vt 1.989519 0.613849 -vt 1.992030 0.613849 -vt 1.992030 0.593358 -vt 1.989519 0.613849 -vt 1.989519 0.634339 -vt 1.992030 0.634339 -vt 1.992030 0.613849 -vt 1.989519 0.634339 -vt 1.989519 0.654830 -vt 1.992030 0.654830 -vt 1.992030 0.634339 -vt 1.989519 0.531886 -vt 1.989519 0.552377 -vt 1.992030 0.552377 -vt 1.992030 0.531886 -vt 1.989519 0.552377 -vt 1.989519 0.572867 -vt 1.992030 0.572867 -vt 1.992030 0.552377 -vt 1.989519 0.572867 -vt 1.989519 0.593358 -vt 1.992030 0.593358 -vt 1.992030 0.572867 -vt 1.985470 0.593358 -vt 1.985470 0.613849 -vt 1.989519 0.613849 -vt 1.989519 0.593358 -vt 1.985470 0.613849 -vt 1.985470 0.634339 -vt 1.989519 0.634339 -vt 1.989519 0.613849 -vt 1.985470 0.634339 -vt 1.985470 0.654830 -vt 1.989519 0.654830 -vt 1.989519 0.634339 -vt 1.985470 0.531886 -vt 1.985470 0.552377 -vt 1.989519 0.552377 -vt 1.989519 0.531886 -vt 1.985470 0.552377 -vt 1.985470 0.572867 -vt 1.989519 0.572867 -vt 1.989519 0.552377 -vt 1.985470 0.572867 -vt 1.985470 0.593358 -vt 1.989519 0.593358 -vt 1.989519 0.572867 -vt 1.997477 0.613849 -vt 1.997477 0.593358 -vt 1.992030 0.593358 -vt 1.992030 0.613849 -vt 1.997477 0.593358 -vt 1.997477 0.572867 -vt 1.992030 0.572867 -vt 1.992030 0.593358 -vt 1.997477 0.572867 -vt 1.997477 0.552377 -vt 1.992030 0.552377 -vt 1.992030 0.572867 -vt 1.997477 0.552377 -vt 1.997477 0.531886 -vt 1.992030 0.531886 -vt 1.992030 0.552377 -vt 1.997477 0.654830 -vt 1.997477 0.634339 -vt 1.992030 0.634339 -vt 1.992030 0.654830 -vt 1.997477 0.634339 -vt 1.997477 0.613849 -vt 1.992030 0.613849 -vt 1.992030 0.634339 -vt 1.964272 0.593111 -vt 1.964272 0.572703 -vt 1.945781 0.572867 -vt 1.945781 0.593358 -vt 1.945781 0.613849 -vt 1.945781 0.593358 -vt 1.936440 0.593358 -vt 1.936440 0.613848 -vt 1.945781 0.593358 -vt 1.945781 0.572867 -vt 1.936440 0.572867 -vt 1.936440 0.593358 -vt 1.945781 0.572867 -vt 1.945781 0.552377 -vt 1.936440 0.552377 -vt 1.936440 0.572867 -vt 1.945781 0.552377 -vt 1.945781 0.531886 -vt 1.936440 0.531886 -vt 1.936440 0.552377 -vt 1.945781 0.654830 -vt 1.945781 0.634339 -vt 1.936440 0.634339 -vt 1.936440 0.654830 -vt 1.945781 0.634339 -vt 1.945781 0.613849 -vt 1.936440 0.613848 -vt 1.936440 0.634339 -vt 1.979362 0.691436 -vt 1.979348 0.689810 -vt 1.963987 0.689810 -vt 1.964001 0.691436 -vt 1.964001 0.691436 -vt 1.963987 0.689810 -vt 1.948957 0.689810 -vt 1.948867 0.692212 -vt 1.979067 0.658221 -vt 1.963706 0.658221 -vt 1.963987 0.689810 -vt 1.979348 0.689810 -vt 1.963706 0.658221 -vt 1.948957 0.658221 -vt 1.948957 0.689810 -vt 1.963987 0.689810 -vt 0.787461 0.635838 -vt 0.787461 0.644547 -vt 0.790486 0.644521 -vt 0.790486 0.635883 -vt 0.787461 0.652662 -vt 0.790486 0.652704 -vt 0.787461 0.661373 -vt 0.790486 0.661424 -vt 0.787461 0.669213 -vt 0.790486 0.669213 -vt 0.787461 0.677249 -vt 0.790486 0.677249 -vt 0.787461 0.611351 -vt 0.787461 0.618762 -vt 0.790486 0.618762 -vt 0.790486 0.611351 -vt 0.787461 0.627702 -vt 0.790486 0.627702 -vt 2.838023 0.574485 -vt 2.819068 0.574477 -vt 2.820639 0.577859 -vt 2.836431 0.577819 -vt 2.850694 0.586961 -vt 2.838023 0.574485 -vt 2.836431 0.577819 -vt 2.847119 0.588558 -vt 2.850748 0.605962 -vt 2.850694 0.586961 -vt 2.847119 0.588558 -vt 2.847216 0.604497 -vt 2.838228 0.618611 -vt 2.850748 0.605962 -vt 2.847216 0.604497 -vt 2.836657 0.615142 -vt 2.819383 0.618676 -vt 2.838228 0.618611 -vt 2.836657 0.615142 -vt 2.820841 0.615024 -vt 2.806807 0.606156 -vt 2.819383 0.618676 -vt 2.820841 0.615024 -vt 2.810164 0.604546 -vt 2.806580 0.587149 -vt 2.806807 0.606156 -vt 2.810164 0.604546 -vt 2.810070 0.588715 -vt 2.819068 0.574477 -vt 2.806580 0.587149 -vt 2.810070 0.588715 -vt 2.820639 0.577859 -vt 2.826168 0.590676 -vt 2.831048 0.590663 -vt 2.836431 0.577819 -vt 2.820639 0.577859 -vt 2.831048 0.590663 -vt 2.834519 0.594115 -vt 2.847119 0.588558 -vt 2.836431 0.577819 -vt 2.834519 0.594115 -vt 2.834548 0.599011 -vt 2.847216 0.604497 -vt 2.847119 0.588558 -vt 2.834548 0.599011 -vt 2.831117 0.602483 -vt 2.836657 0.615142 -vt 2.847216 0.604497 -vt 2.831117 0.602483 -vt 2.826236 0.602496 -vt 2.820841 0.615024 -vt 2.836657 0.615142 -vt 2.826236 0.602496 -vt 2.822765 0.599043 -vt 2.810164 0.604546 -vt 2.820841 0.615024 -vt 2.822765 0.599043 -vt 2.822736 0.594147 -vt 2.810070 0.588715 -vt 2.810164 0.604546 -vt 2.822736 0.594147 -vt 2.826168 0.590676 -vt 2.820639 0.577859 -vt 2.810070 0.588715 -vt 1.712529 0.749275 -vt 1.712529 0.796196 -vt 1.722815 0.796196 -vt 1.722815 0.749275 -vt 1.712529 0.796196 -vt 1.712529 0.821096 -vt 1.722815 0.821096 -vt 1.722815 0.796196 -vt 1.712529 0.687755 -vt 1.712529 0.713461 -vt 1.722815 0.713461 -vt 1.722815 0.687755 -vt 1.712529 0.713461 -vt 1.712529 0.749275 -vt 1.722815 0.749275 -vt 1.722815 0.713461 -vt 1.869054 0.971224 -vt 1.875811 0.987949 -vt 0.868492 0.837058 -vt 0.857248 0.809226 -vt 1.963142 0.507307 -vt 1.956692 0.465842 -vt 1.953100 0.466601 -vt 1.959462 0.507483 -vt 1.975459 0.514343 -vt 1.971978 0.514904 -vt 1.971030 0.518012 -vt 1.975659 0.517915 -vt 1.974988 0.462717 -vt 1.981663 0.505121 -vt 1.985318 0.504333 -vt 1.978737 0.462523 -vt 1.932504 0.389173 -vt 1.926916 0.381387 -vt 1.928188 0.391026 -vt 1.953100 0.466601 -vt 1.941483 0.425665 -vt 1.918600 0.436844 -vt 1.935331 0.471062 -vt 1.945891 0.513500 -vt 1.959462 0.507483 -vt 1.941512 0.510082 -vt 1.945891 0.513500 -vt 1.953322 0.516859 -vt 1.956592 0.511103 -vt 1.941512 0.510082 -vt 1.959462 0.507483 -vt 1.953100 0.466601 -vt 1.935331 0.471062 -vt 1.935117 0.407189 -vt 1.905937 0.424989 -vt 1.918600 0.436844 -vt 1.941483 0.425665 -vt 1.905937 0.424989 -vt 1.935117 0.407189 -vt 1.928188 0.391026 -vt 1.886744 0.406160 -vt 0.631173 0.764652 -vt 0.661496 0.745082 -vt 0.660792 0.717479 -vt 0.630058 0.699236 -vt 2.858635 0.680042 -vt 2.871958 0.679834 -vt 2.882754 0.675465 -vt 2.847085 0.674987 -vt 2.891651 0.666530 -vt 2.838888 0.666443 -vt 1.939803 0.691444 -vt 1.939801 0.709338 -vt 1.776324 0.680594 -vt 1.776324 0.740044 -vt 1.026016 0.772165 -vt 1.026226 0.863725 -vt 1.006733 0.768437 -vt 1.006960 0.867541 -vt 0.480897 0.445316 -vt 0.478945 0.407182 -vt 0.467033 0.405254 -vt 0.468978 0.443492 -vt 0.483699 0.484442 -vt 0.480897 0.445316 -vt 0.468978 0.443492 -vt 0.473741 0.481656 -vt 0.478945 0.407182 -vt 0.473654 0.367990 -vt 0.464299 0.367976 -vt 0.467033 0.405254 -vt 0.484683 0.508705 -vt 0.483699 0.484442 -vt 0.473741 0.481656 -vt 0.475839 0.508026 -vt 0.471613 0.341395 -vt 0.470613 0.322225 -vt 0.465906 0.323652 -vt 0.465805 0.340155 -vt 0.473654 0.367990 -vt 0.471613 0.341395 -vt 0.465805 0.340155 -vt 0.464299 0.367976 -vt 0.470613 0.322225 -vt 0.470069 0.279726 -vt 0.464726 0.279813 -vt 0.465906 0.323652 -vt 0.485336 0.540193 -vt 0.484683 0.508705 -vt 0.475839 0.508026 -vt 0.474510 0.533329 -vt 1.734627 0.809321 -vt 1.734627 0.710218 -vt 1.764773 0.724732 -vt 0.880188 0.497240 -vt 0.923223 0.496405 -vt 0.897414 0.524735 -vt 0.879566 0.526113 -vt 0.881068 0.456409 -vt 0.924064 0.457336 -vt 0.923223 0.496405 -vt 0.880188 0.497240 -vt 0.881068 0.456409 -vt 0.881690 0.427537 -vt 0.899500 0.427921 -vt 0.924064 0.457336 -vt 1.010500 0.652637 -vt 1.122578 0.652637 -vt 1.122549 0.656233 -vt 1.010633 0.652337 -vt 1.234656 0.654561 -vt 1.234486 0.661460 -vt 1.346734 0.658459 -vt 1.346443 0.668053 -vt 1.408643 0.660136 -vt 1.407538 0.672188 -vt 1.078205 0.439206 -vt 1.123852 0.442823 -vt 1.122122 0.451058 -vt 1.076831 0.448786 -vt 1.234965 0.454150 -vt 1.235514 0.448414 -vt 1.347024 0.455886 -vt 1.347440 0.450682 -vt 1.428376 0.456721 -vt 1.428786 0.451517 -vt 1.454072 0.482134 -vt 1.447451 0.487014 -vt 1.428376 0.456721 -vt 1.433218 0.452772 -vt 0.008858 0.429252 -vt 0.361111 0.429252 -vt 0.359604 0.433571 -vt 0.415695 0.429252 -vt 0.415687 0.433571 -vt 0.417122 0.012457 -vt 0.421961 0.012442 -vt 0.449332 0.062060 -vt 0.444812 0.062060 -vt 0.676401 0.986658 -vt 0.677748 0.976969 -vt 0.701728 0.978157 -vt 0.700313 0.990996 -vt 0.787706 0.983066 -vt 0.786661 0.989188 -vt 0.806581 0.983761 -vt 0.808887 0.988109 -vt 3.956937 0.990430 -vt 3.952790 0.822763 -vt 3.960512 0.822945 -vt 3.964659 0.990613 -vt 3.964659 0.990613 -vt 3.960512 0.822945 -vt 3.982158 0.822781 -vt 3.986306 0.990450 -vt 3.986306 0.990450 -vt 3.982158 0.822781 -vt 3.989862 0.822218 -vt 3.994010 0.989886 -vt 3.935309 0.991339 -vt 3.931161 0.823668 -vt 3.952790 0.822763 -vt 3.956937 0.990430 -vt 1.880274 0.541093 -vt 1.894613 0.541093 -vt 1.894615 0.560769 -vt 1.880271 0.560769 -vt 1.880271 0.585741 -vt 1.880276 0.566056 -vt 1.894611 0.566056 -vt 1.894615 0.585741 -vt 1.880274 0.541093 -vt 1.880285 0.535809 -vt 1.894601 0.535809 -vt 1.894613 0.541093 -vt 1.899927 0.585758 -vt 1.894615 0.585741 -vt 1.894611 0.566056 -vt 1.899927 0.566039 -vt 1.894615 0.560769 -vt 1.894611 0.566056 -vt 1.880276 0.566056 -vt 1.880271 0.560769 -vt 1.874960 0.566039 -vt 1.880276 0.566056 -vt 1.880271 0.585741 -vt 1.874960 0.585758 -vt 1.151943 0.966273 -vt 1.151961 0.984813 -vt 1.118294 0.984845 -vt 1.118276 0.966204 -vt 1.178138 0.965761 -vt 1.178157 0.984787 -vt 1.204440 0.965590 -vt 1.204459 0.984762 -vt 1.232801 0.965563 -vt 1.232820 0.984734 -vt 1.038622 0.965136 -vt 1.038641 0.984922 -vt 1.014053 0.984946 -vt 1.012148 0.965162 -vt 1.091724 0.984871 -vt 0.041455 0.852946 -vt 0.041294 0.782869 -vt 0.052250 0.798920 -vt 0.052336 0.836845 -vt 0.347561 0.949223 -vt 0.347663 0.961543 -vt 0.320590 0.961766 -vt 0.320488 0.949446 -vt 0.293517 0.961990 -vt 0.293415 0.949670 -vt 0.266443 0.962214 -vt 0.266341 0.949894 -vt 0.239370 0.962438 -vt 0.239268 0.950118 -vt 0.455855 0.948328 -vt 0.455957 0.960648 -vt 0.428883 0.960871 -vt 0.428781 0.948551 -vt 0.401810 0.961095 -vt 0.401708 0.948775 -vt 0.374737 0.961319 -vt 0.374635 0.948999 -vt 1.613012 0.566762 -vt 1.612860 0.558477 -vt 1.627604 0.558206 -vt 1.627756 0.566490 -vt 1.513593 0.568591 -vt 1.513441 0.560307 -vt 1.527838 0.560042 -vt 1.527991 0.568326 -vt 1.527991 0.568326 -vt 1.527838 0.560042 -vt 1.542742 0.559767 -vt 1.542895 0.568052 -vt 1.556928 0.567794 -vt 1.556776 0.559509 -vt 1.570454 0.559258 -vt 1.570606 0.567542 -vt 1.570606 0.567542 -vt 1.570454 0.559258 -vt 1.583267 0.559022 -vt 1.583420 0.567306 -vt 1.583420 0.567306 -vt 1.583267 0.559022 -vt 1.597825 0.558754 -vt 1.597978 0.567038 -vt 1.597978 0.567038 -vt 1.597825 0.558754 -vt 1.612860 0.558477 -vt 1.613012 0.566762 -vt 1.628124 0.586467 -vt 1.628284 0.595150 -vt 1.613540 0.595421 -vt 1.613380 0.586739 -vt 1.613380 0.586739 -vt 1.613540 0.595421 -vt 1.598505 0.595698 -vt 1.598345 0.587015 -vt 1.598345 0.587015 -vt 1.598505 0.595698 -vt 1.583947 0.595966 -vt 1.583787 0.587283 -vt 1.583787 0.587283 -vt 1.583947 0.595966 -vt 1.571134 0.596202 -vt 1.570974 0.587519 -vt 1.570974 0.587519 -vt 1.571134 0.596202 -vt 1.557456 0.596453 -vt 1.557296 0.587771 -vt 1.557296 0.587771 -vt 1.557456 0.596453 -vt 1.543422 0.596712 -vt 1.543262 0.588029 -vt 1.543262 0.588029 -vt 1.543422 0.596712 -vt 1.528518 0.596986 -vt 1.528358 0.588303 -vt 1.528358 0.588303 -vt 1.528518 0.596986 -vt 1.514121 0.597251 -vt 1.513961 0.588568 -vt 1.612860 0.558477 -vt 1.612825 0.556578 -vt 1.627569 0.556307 -vt 1.627604 0.558206 -vt 1.627604 0.558206 -vt 1.627569 0.556307 -vt 1.642140 0.556039 -vt 1.642175 0.557938 -vt 1.642175 0.557938 -vt 1.642140 0.556039 -vt 1.656962 0.555766 -vt 1.656997 0.557665 -vt 1.670449 0.557417 -vt 1.670414 0.555518 -vt 1.684206 0.555265 -vt 1.684240 0.557164 -vt 1.684240 0.557164 -vt 1.684206 0.555265 -vt 1.698385 0.555004 -vt 1.698421 0.556903 -vt 1.482951 0.560868 -vt 1.497922 0.558693 -vt 1.497957 0.560592 -vt 1.497957 0.560592 -vt 1.497922 0.558693 -vt 1.513406 0.558408 -vt 1.513441 0.560307 -vt 1.513441 0.560307 -vt 1.513406 0.558408 -vt 1.527803 0.558143 -vt 1.527838 0.560042 -vt 1.527838 0.560042 -vt 1.527803 0.558143 -vt 1.542707 0.557869 -vt 1.542742 0.559767 -vt 1.542742 0.559767 -vt 1.542707 0.557869 -vt 1.556741 0.557610 -vt 1.556776 0.559509 -vt 1.556776 0.559509 -vt 1.556741 0.557610 -vt 1.570419 0.557359 -vt 1.570454 0.559258 -vt 1.570454 0.559258 -vt 1.570419 0.557359 -vt 1.583232 0.557123 -vt 1.583267 0.559022 -vt 1.583267 0.559022 -vt 1.583232 0.557123 -vt 1.597790 0.556855 -vt 1.597825 0.558754 -vt 1.597825 0.558754 -vt 1.597790 0.556855 -vt 1.612825 0.556578 -vt 1.628284 0.595150 -vt 1.628316 0.596895 -vt 1.613572 0.597166 -vt 1.613540 0.595421 -vt 1.613540 0.595421 -vt 1.613572 0.597166 -vt 1.598537 0.597443 -vt 1.598505 0.595698 -vt 1.598505 0.595698 -vt 1.598537 0.597443 -vt 1.583979 0.597710 -vt 1.583947 0.595966 -vt 1.583947 0.595966 -vt 1.583979 0.597710 -vt 1.571166 0.597946 -vt 1.571134 0.596202 -vt 1.571134 0.596202 -vt 1.571166 0.597946 -vt 1.557488 0.598198 -vt 1.557456 0.596453 -vt 1.557456 0.596453 -vt 1.557488 0.598198 -vt 1.543454 0.598456 -vt 1.543422 0.596712 -vt 1.543422 0.596712 -vt 1.543454 0.598456 -vt 1.528550 0.598731 -vt 1.528518 0.596986 -vt 1.528518 0.596986 -vt 1.528550 0.598731 -vt 1.514153 0.598995 -vt 1.514121 0.597251 -vt 1.514121 0.597251 -vt 1.514153 0.598995 -vt 1.498669 0.599280 -vt 1.498637 0.597536 -vt 1.498637 0.597536 -vt 1.498669 0.599280 -vt 1.483663 0.599557 -vt 1.483631 0.597812 -vt 1.699100 0.593847 -vt 1.699132 0.595591 -vt 1.684952 0.595852 -vt 1.684920 0.594108 -vt 1.684920 0.594108 -vt 1.684952 0.595852 -vt 1.671161 0.596106 -vt 1.671129 0.594361 -vt 1.657677 0.594609 -vt 1.657709 0.596354 -vt 1.642887 0.596626 -vt 1.642854 0.594882 -vt 0.936439 0.572867 -vt 0.936439 0.593358 -vt 0.932941 0.593358 -vt 0.932941 0.572867 -vt 0.791431 0.736062 -vt 0.791431 0.684576 -vt 0.978612 0.593111 -vt 0.985470 0.593358 -vt 0.985470 0.613849 -vt 0.978612 0.614013 -vt 0.978612 0.614013 -vt 0.985470 0.613849 -vt 0.985470 0.634339 -vt 0.978612 0.634422 -vt 0.978612 0.634422 -vt 0.985470 0.634339 -vt 0.985470 0.654830 -vt 0.978612 0.654830 -vt 0.978612 0.531886 -vt 0.985470 0.531886 -vt 0.985470 0.552377 -vt 0.978612 0.552294 -vt 0.978612 0.552294 -vt 0.985470 0.552377 -vt 0.985470 0.572867 -vt 0.978612 0.572703 -vt 0.978612 0.572703 -vt 0.985470 0.572867 -vt 0.985470 0.593358 -vt 0.978612 0.593111 -vt 0.989519 0.593358 -vt 0.992030 0.593358 -vt 0.992030 0.613849 -vt 0.989519 0.613849 -vt 0.989519 0.613849 -vt 0.992030 0.613849 -vt 0.992030 0.634339 -vt 0.989519 0.634339 -vt 0.989519 0.634339 -vt 0.992030 0.634339 -vt 0.992030 0.654830 -vt 0.989519 0.654830 -vt 0.989519 0.531886 -vt 0.992030 0.531886 -vt 0.992030 0.552377 -vt 0.989519 0.552377 -vt 0.989519 0.552377 -vt 0.992030 0.552377 -vt 0.992030 0.572867 -vt 0.989519 0.572867 -vt 0.989519 0.572867 -vt 0.992030 0.572867 -vt 0.992030 0.593358 -vt 0.989519 0.593358 -vt 0.985470 0.593358 -vt 0.989519 0.593358 -vt 0.989519 0.613849 -vt 0.985470 0.613849 -vt 0.985470 0.613849 -vt 0.989519 0.613849 -vt 0.989519 0.634339 -vt 0.985470 0.634339 -vt 0.985470 0.634339 -vt 0.989519 0.634339 -vt 0.989519 0.654830 -vt 0.985470 0.654830 -vt 0.985470 0.531886 -vt 0.989519 0.531886 -vt 0.989519 0.552377 -vt 0.985470 0.552377 -vt 0.985470 0.552377 -vt 0.989519 0.552377 -vt 0.989519 0.572867 -vt 0.985470 0.572867 -vt 0.985470 0.572867 -vt 0.989519 0.572867 -vt 0.989519 0.593358 -vt 0.985470 0.593358 -vt 0.997477 0.613849 -vt 0.992030 0.613849 -vt 0.992030 0.593358 -vt 0.997477 0.593358 -vt 0.997477 0.593358 -vt 0.992030 0.593358 -vt 0.992030 0.572867 -vt 0.997477 0.572867 -vt 0.997477 0.572867 -vt 0.992030 0.572867 -vt 0.992030 0.552377 -vt 0.997477 0.552377 -vt 0.997477 0.552377 -vt 0.992030 0.552377 -vt 0.992030 0.531886 -vt 0.997477 0.531886 -vt 0.997477 0.654830 -vt 0.992030 0.654830 -vt 0.992030 0.634339 -vt 0.997477 0.634339 -vt 0.997477 0.634339 -vt 0.992030 0.634339 -vt 0.992030 0.613849 -vt 0.945781 0.572867 -vt 0.964273 0.572703 -vt 0.964273 0.593111 -vt 0.945781 0.593358 -vt 0.945781 0.613849 -vt 0.936439 0.613848 -vt 0.936439 0.593358 -vt 0.945781 0.593358 -vt 0.945781 0.593358 -vt 0.936439 0.593358 -vt 0.936439 0.572867 -vt 0.945781 0.572867 -vt 0.945781 0.572867 -vt 0.936439 0.572867 -vt 0.936439 0.552377 -vt 0.945781 0.552377 -vt 0.945781 0.552377 -vt 0.936439 0.552377 -vt 0.936439 0.531886 -vt 0.945781 0.531886 -vt 0.945781 0.654830 -vt 0.936439 0.654830 -vt 0.936439 0.634339 -vt 0.945781 0.634339 -vt 0.945781 0.634339 -vt 0.936439 0.634339 -vt 0.936439 0.613848 -vt 0.945781 0.613849 -vt 0.979362 0.691436 -vt 0.964001 0.691436 -vt 0.963987 0.689810 -vt 0.979348 0.689810 -vt 0.964001 0.691436 -vt 0.948867 0.692212 -vt 0.948957 0.689810 -vt 0.963987 0.689810 -vt 0.979067 0.658221 -vt 0.979348 0.689810 -vt 0.963987 0.689810 -vt 0.963706 0.658221 -vt 0.963706 0.658221 -vt 0.963987 0.689810 -vt 0.948957 0.689810 -vt 0.948957 0.658221 -vt 1.787461 0.635838 -vt 1.790486 0.635883 -vt 1.790486 0.644521 -vt 1.787461 0.644547 -vt 1.790486 0.652704 -vt 1.787461 0.652662 -vt 1.790486 0.661424 -vt 1.787461 0.661373 -vt 1.790486 0.669213 -vt 1.787461 0.669213 -vt 1.790486 0.677249 -vt 1.787461 0.677249 -vt 1.787461 0.611351 -vt 1.790486 0.611351 -vt 1.790486 0.618762 -vt 1.787461 0.618762 -vt 1.790486 0.627702 -vt 1.787461 0.627702 -vt 0.820639 0.577859 -vt 0.819068 0.574477 -vt 0.838023 0.574485 -vt 0.836431 0.577819 -vt 0.836431 0.577819 -vt 0.838023 0.574485 -vt 0.850694 0.586961 -vt 0.847119 0.588558 -vt 0.847119 0.588558 -vt 0.850694 0.586961 -vt 0.850748 0.605962 -vt 0.847216 0.604497 -vt 0.847216 0.604497 -vt 0.850748 0.605962 -vt 0.838228 0.618611 -vt 0.836657 0.615142 -vt 0.836657 0.615142 -vt 0.838228 0.618611 -vt 0.819383 0.618676 -vt 0.820841 0.615024 -vt 0.820841 0.615024 -vt 0.819383 0.618676 -vt 0.806807 0.606156 -vt 0.810164 0.604546 -vt 0.810164 0.604546 -vt 0.806807 0.606156 -vt 0.806580 0.587149 -vt 0.810070 0.588715 -vt 0.810070 0.588715 -vt 0.806580 0.587149 -vt 0.819068 0.574477 -vt 0.820639 0.577859 -vt 0.826167 0.590676 -vt 0.820639 0.577859 -vt 0.836431 0.577819 -vt 0.831048 0.590663 -vt 0.831048 0.590663 -vt 0.836431 0.577819 -vt 0.847119 0.588558 -vt 0.834520 0.594115 -vt 0.834520 0.594115 -vt 0.847119 0.588558 -vt 0.847216 0.604497 -vt 0.834548 0.599011 -vt 0.834548 0.599011 -vt 0.847216 0.604497 -vt 0.836657 0.615142 -vt 0.831117 0.602483 -vt 0.831117 0.602483 -vt 0.836657 0.615142 -vt 0.820841 0.615024 -vt 0.826236 0.602496 -vt 0.826236 0.602496 -vt 0.820841 0.615024 -vt 0.810164 0.604546 -vt 0.822765 0.599043 -vt 0.822765 0.599043 -vt 0.810164 0.604546 -vt 0.810070 0.588715 -vt 0.822736 0.594147 -vt 0.822736 0.594147 -vt 0.810070 0.588715 -vt 0.820639 0.577859 -vt 0.826167 0.590676 -vt 0.712529 0.749275 -vt 0.722815 0.749275 -vt 0.722815 0.796196 -vt 0.712529 0.796196 -vt 0.712529 0.796196 -vt 0.722815 0.796196 -vt 0.722815 0.821096 -vt 0.712529 0.687755 -vt 0.722815 0.687755 -vt 0.722815 0.713461 -vt 0.712529 0.713461 -vt 0.712529 0.713461 -vt 0.722815 0.713461 -vt 0.722815 0.749275 -vt 0.712529 0.749275 -vt 0.875811 0.987949 -vt 0.869054 0.971224 -vt 1.857248 0.809226 -vt 1.868492 0.837058 -vt 0.963142 0.507307 -vt 0.959462 0.507483 -vt 0.953100 0.466601 -vt 0.956692 0.465842 -vt 0.975459 0.514343 -vt 0.975659 0.517915 -vt 0.971030 0.518012 -vt 0.974988 0.462717 -vt 0.978737 0.462523 -vt 0.985318 0.504333 -vt 0.981663 0.505121 -vt 0.953100 0.466601 -vt 0.935331 0.471062 -vt 0.918600 0.436844 -vt 0.941483 0.425665 -vt 0.945891 0.513500 -vt 0.956592 0.511103 -vt 0.953322 0.516859 -vt 0.953100 0.466601 -vt 0.959462 0.507483 -vt 0.941512 0.510082 -vt 0.935331 0.471062 -vt 0.918600 0.436844 -vt 0.905937 0.424989 -vt 0.935117 0.407189 -vt 0.941483 0.425665 -vt 0.928188 0.391026 -vt 0.935117 0.407189 -vt 0.905937 0.424989 -vt 0.886744 0.406160 -vt 0.526626 0.783518 -vt 0.500841 0.780471 -vt 0.500841 0.780471 -vt 0.526626 0.783518 -vt 0.631173 0.764652 -vt 0.630058 0.699236 -vt 0.660792 0.717479 -vt 0.661496 0.745082 -vt 0.661496 0.745082 -vt 0.631173 0.764652 -vt 0.631173 0.764652 -vt 0.661496 0.745082 -vt 0.631173 0.764652 -vt 0.597737 0.776562 -vt 0.597737 0.776562 -vt 0.631173 0.764652 -vt 0.450798 0.706790 -vt 0.450798 0.706790 -vt 0.452967 0.728116 -vt 0.452967 0.728116 -vt 0.558627 0.607968 -vt 0.596866 0.612516 -vt 0.596866 0.612516 -vt 0.558627 0.607968 -vt 0.596866 0.612516 -vt 0.637337 0.616972 -vt 0.637337 0.616972 -vt 0.596866 0.612516 -vt 0.462399 0.748874 -vt 0.462399 0.748874 -vt 0.476409 0.768140 -vt 0.476409 0.768140 -vt 0.504547 0.612629 -vt 0.504547 0.612629 -vt 0.489568 0.620042 -vt 0.489568 0.620042 -vt 0.452967 0.728116 -vt 0.452967 0.728116 -vt 0.462399 0.748874 -vt 0.462399 0.748874 -vt 0.532640 0.607381 -vt 0.532640 0.607381 -vt 0.504547 0.612629 -vt 0.504547 0.612629 -vt 0.464575 0.645515 -vt 0.464575 0.645515 -vt 0.454897 0.674918 -vt 0.454897 0.674918 -vt 0.476409 0.768140 -vt 0.476409 0.768140 -vt 0.500841 0.780471 -vt 0.500841 0.780471 -vt 0.489568 0.620042 -vt 0.489568 0.620042 -vt 0.475518 0.632309 -vt 0.475518 0.632309 -vt 0.526626 0.783518 -vt 0.526626 0.783518 -vt 0.565573 0.782724 -vt 0.565573 0.782724 -vt 0.597737 0.776562 -vt 0.565573 0.782724 -vt 0.565573 0.782724 -vt 0.597737 0.776562 -vt 0.454897 0.674918 -vt 0.454897 0.674918 -vt 0.450798 0.706790 -vt 0.450798 0.706790 -vt 0.630058 0.699236 -vt 0.660792 0.717479 -vt 0.660792 0.717479 -vt 0.630058 0.699236 -vt 0.637337 0.616972 -vt 0.641785 0.651360 -vt 0.641785 0.651360 -vt 0.637337 0.616972 -vt 0.532640 0.607381 -vt 0.558627 0.607968 -vt 0.558627 0.607968 -vt 0.532640 0.607381 -vt 0.475518 0.632309 -vt 0.475518 0.632309 -vt 0.464575 0.645515 -vt 0.464575 0.645515 -vt 0.641785 0.651360 -vt 0.630058 0.699236 -vt 0.630058 0.699236 -vt 0.641785 0.651360 -vt 0.660792 0.717479 -vt 0.661496 0.745082 -vt 0.661496 0.745082 -vt 0.660792 0.717479 -vt 3.838417 0.629355 -vt 3.847316 0.620416 -vt 3.883001 0.620895 -vt 3.891823 0.630072 -vt 3.858914 0.615670 -vt 3.871445 0.615838 -vt 0.882754 0.675465 -vt 0.871958 0.679834 -vt 0.858635 0.680042 -vt 0.847085 0.674987 -vt 0.891651 0.666530 -vt 0.838888 0.666443 -vt 0.939801 0.709338 -vt 0.939803 0.691444 -vt 0.776324 0.740044 -vt 0.776324 0.680594 -vt 0.026226 0.863725 -vt 0.026016 0.772165 -vt 0.006960 0.867541 -vt 0.006733 0.768437 -vt 0.475514 0.113873 -vt 0.463662 0.116085 -vt 0.462963 0.154364 -vt 0.474805 0.152050 -vt 0.477040 0.074678 -vt 0.467179 0.077787 -vt 0.463662 0.116085 -vt 0.475514 0.113873 -vt 0.474805 0.152050 -vt 0.462963 0.154364 -vt 0.461444 0.191712 -vt 0.470793 0.191393 -vt 0.477234 0.050396 -vt 0.468417 0.051363 -vt 0.467179 0.077787 -vt 0.477040 0.074678 -vt 0.469620 0.218039 -vt 0.463855 0.219468 -vt 0.464494 0.235959 -vt 0.469244 0.237231 -vt 0.470793 0.191393 -vt 0.461444 0.191712 -vt 0.463855 0.219468 -vt 0.469620 0.218039 -vt 0.469244 0.237231 -vt 0.464494 0.235959 -vt 0.464726 0.279813 -vt 0.470069 0.279726 -vt 0.476861 0.018904 -vt 0.466265 0.026117 -vt 0.468417 0.051363 -vt 0.477234 0.050396 -vt 1.981228 0.796580 -vt 1.981343 0.741059 -vt 1.942279 0.723767 -vt 1.941700 0.788339 -vt 1.901950 0.723781 -vt 1.902173 0.788339 -vt 1.862950 0.741047 -vt 1.862839 0.796665 -vt 0.862839 0.796665 -vt 0.902173 0.788339 -vt 0.901950 0.723781 -vt 0.862950 0.741047 -vt 0.941700 0.788339 -vt 0.942279 0.723767 -vt 0.981228 0.796580 -vt 0.981343 0.741059 -vt 1.862839 0.796665 -vt 1.862950 0.741047 -vt 1.855536 0.734860 -vt 1.855120 0.796308 -vt 1.981343 0.741059 -vt 1.981228 0.796580 -vt 1.989729 0.796687 -vt 1.989631 0.734959 -vt 0.844269 0.970059 -vt 0.840070 0.973577 -vt 0.839588 0.978994 -vt 0.846439 0.976789 -vt 1.853430 0.974539 -vt 1.849805 0.970333 -vt 1.844269 0.970059 -vt 1.846439 0.976789 -vt 0.849805 0.970333 -vt 0.853430 0.974539 -vt 1.840070 0.973577 -vt 1.839588 0.978994 -vt 1.843067 0.983246 -vt 1.848652 0.983663 -vt 1.852944 0.980064 -vt 0.843067 0.983246 -vt 0.848652 0.983663 -vt 0.852944 0.980064 -vt 1.956937 0.990430 -vt 1.964659 0.990613 -vt 1.960512 0.822945 -vt 1.952790 0.822763 -vt 1.964659 0.990613 -vt 1.986306 0.990450 -vt 1.982158 0.822781 -vt 1.960512 0.822945 -vt 1.986306 0.990450 -vt 1.994010 0.989886 -vt 1.989862 0.822218 -vt 1.982158 0.822781 -vt 1.935309 0.991339 -vt 1.956937 0.990430 -vt 1.952790 0.822763 -vt 1.931161 0.823668 -vt 0.956937 0.990430 -vt 0.952790 0.822763 -vt 0.960512 0.822945 -vt 0.964659 0.990613 -vt 0.964659 0.990613 -vt 0.960512 0.822945 -vt 0.982158 0.822781 -vt 0.986306 0.990450 -vt 0.986306 0.990450 -vt 0.982158 0.822781 -vt 0.989862 0.822218 -vt 0.994010 0.989886 -vt 0.935309 0.991339 -vt 0.931161 0.823668 -vt 0.952790 0.822763 -vt 0.956937 0.990430 -vt 0.869549 0.494493 -vt 0.685876 0.470732 -vt 0.686956 0.503877 -vt 0.845515 0.545239 -vt 0.858857 0.533495 -vt 0.699936 0.535074 -vt 0.865099 0.357931 -vt 0.681322 0.330970 -vt 0.682548 0.368587 -vt 0.867157 0.421069 -vt 0.683656 0.402609 -vt 0.684743 0.435968 -vt 0.863161 0.273323 -vt 0.678978 0.276933 -vt 0.680251 0.298094 -vt 0.489619 0.321696 -vt 0.470613 0.322225 -vt 0.471613 0.341395 -vt 0.535821 0.320678 -vt 0.518922 0.329838 -vt 0.525635 0.340736 -vt 0.764773 0.794808 -vt 0.777260 0.759770 -vt 0.862351 0.052066 -vt 0.679553 0.048633 -vt 0.679553 0.081796 -vt 0.836677 0.002131 -vt 0.691510 0.017031 -vt 0.850394 0.013434 -vt 0.862351 0.188698 -vt 0.679553 0.183992 -vt 0.679553 0.221628 -vt 0.862351 0.125527 -vt 0.679552 0.116577 -vt 0.679553 0.149953 -vt 0.679553 0.254521 -vt 0.488258 0.237141 -vt 0.469620 0.218039 -vt 0.469244 0.237231 -vt 0.534467 0.236654 -vt 0.523633 0.216939 -vt 0.517279 0.228049 -vt 1.764773 0.794808 -vt 1.777260 0.759770 -vt 0.526575 0.441997 -vt 0.527814 0.480018 -vt 0.525447 0.407375 -vt 0.528647 0.505581 -vt 0.529865 0.542964 -vt 0.549395 0.279043 -vt 0.524206 0.369307 -vt 0.470069 0.279726 -vt 0.481435 0.279541 -vt 1.773548 0.788447 -vt 1.794554 0.804641 -vt 1.810287 0.776335 -vt 1.792986 0.760963 -vt 1.767225 0.804455 -vt 1.785301 0.819129 -vt 1.794554 0.804641 -vt 1.773548 0.788447 -vt 1.811318 0.732380 -vt 1.842490 0.758277 -vt 1.857822 0.684972 -vt 1.807952 0.688354 -vt 1.792986 0.760963 -vt 1.810287 0.776335 -vt 0.480897 0.445316 -vt 0.483699 0.484442 -vt 0.478945 0.407182 -vt 0.484683 0.508705 -vt 0.485336 0.540193 -vt 0.473654 0.367990 -vt 0.007228 0.696445 -vt 0.119097 0.704237 -vt 0.122549 0.656233 -vt 0.010633 0.652337 -vt 0.003656 0.747731 -vt 0.115658 0.753608 -vt 0.231007 0.711437 -vt 0.234486 0.661460 -vt 0.122578 0.652637 -vt 0.122635 0.602044 -vt 0.010442 0.602044 -vt 0.010500 0.652637 -vt 0.028796 0.757590 -vt 0.114950 0.763773 -vt 0.227568 0.760808 -vt 0.342960 0.718029 -vt 0.346443 0.668053 -vt 0.234656 0.654561 -vt 0.234828 0.602638 -vt 0.122635 0.552394 -vt 0.010560 0.550570 -vt 0.062947 0.849104 -vt 0.108784 0.852297 -vt 0.110904 0.821863 -vt 0.061147 0.817481 -vt 0.226860 0.770973 -vt 0.339521 0.767400 -vt 0.438412 0.723653 -vt 0.407538 0.672188 -vt 0.346734 0.658459 -vt 0.347022 0.603842 -vt 0.234828 0.552988 -vt 0.122635 0.542227 -vt 0.036628 0.541905 -vt 0.222813 0.829063 -vt 0.224120 0.810314 -vt 0.112209 0.803114 -vt 0.338813 0.777565 -vt 0.451460 0.774172 -vt 0.449077 0.613331 -vt 0.441013 0.606700 -vt 0.408643 0.660136 -vt 0.414803 0.663012 -vt 0.408643 0.660136 -vt 0.441013 0.606700 -vt 0.347022 0.554192 -vt 0.234828 0.542822 -vt 0.122635 0.502880 -vt 0.122635 0.484280 -vt 0.072599 0.485738 -vt 0.067729 0.503711 -vt 0.334766 0.835655 -vt 0.336072 0.816907 -vt 0.450752 0.784337 -vt 0.468300 0.556341 -vt 0.458729 0.555094 -vt 0.449465 0.611753 -vt 0.458729 0.555094 -vt 0.347022 0.544025 -vt 0.234828 0.503474 -vt 0.234828 0.484874 -vt 0.435030 0.841614 -vt 0.448012 0.823679 -vt 0.467840 0.545989 -vt 0.458499 0.545633 -vt 0.458499 0.545633 -vt 0.347022 0.504678 -vt 0.347022 0.486078 -vt 0.466944 0.501505 -vt 0.447451 0.487014 -vt 0.458683 0.504904 -vt 0.458683 0.504904 -vt 0.447451 0.487014 -vt 0.008432 0.542215 -vt 0.010560 0.550570 -vt 0.036628 0.541905 -vt 0.031953 0.534333 -vt 0.067729 0.503711 -vt 0.059617 0.498005 -vt 0.076831 0.448786 -vt 0.071413 0.450752 -vt 0.063922 0.484353 -vt 0.072599 0.485738 -vt 0.220694 0.859497 -vt 0.332646 0.866089 -vt 0.234965 0.454150 -vt 0.122122 0.451058 -vt 0.413957 0.870728 -vt 0.347024 0.455886 -vt 0.428376 0.456721 -vt 0.058035 0.799341 -vt 0.076831 0.448786 -vt 1.007350 0.433571 -vt 1.361111 0.429252 -vt 1.359604 0.377913 -vt 1.007350 0.377143 -vt 1.008858 0.429252 -vt 1.415695 0.429252 -vt 1.443716 0.379205 -vt 1.444812 0.062060 -vt 1.442509 0.117159 -vt 1.447494 0.117159 -vt 1.449332 0.062060 -vt 1.359604 0.064109 -vt 1.359604 0.113625 -vt 1.442509 0.117159 -vt 1.444812 0.062060 -vt 1.359604 0.012457 -vt 1.007350 0.012457 -vt 1.007350 0.062893 -vt 1.359604 0.226016 -vt 1.007350 0.223041 -vt 1.007350 0.273165 -vt 1.359604 0.273993 -vt 1.007350 0.164184 -vt 1.007350 0.219056 -vt 1.360039 0.219522 -vt 1.359604 0.165360 -vt 1.411958 0.221276 -vt 1.417218 0.224158 -vt 1.444355 0.160955 -vt 1.440307 0.160955 -vt 1.408423 0.225906 -vt 1.424813 0.274675 -vt 1.411958 0.221276 -vt 1.440307 0.160955 -vt 1.359604 0.326053 -vt 1.007350 0.325257 -vt 1.007350 0.112438 -vt 1.442099 0.327051 -vt 1.417122 0.012457 -vt 1.619799 0.822990 -vt 1.602982 0.814799 -vt 1.556521 0.990202 -vt 1.649324 0.985311 -vt 1.701728 0.978157 -vt 1.727590 0.833933 -vt 1.682262 0.899936 -vt 1.677748 0.976969 -vt 1.843743 0.951051 -vt 1.839120 0.949321 -vt 1.832190 0.961777 -vt 1.836182 0.964853 -vt 1.864233 0.869956 -vt 1.859622 0.870344 -vt 1.826082 0.827429 -vt 1.741088 0.816903 -vt 1.742659 0.826246 -vt 1.825098 0.833812 -vt 1.682262 0.899936 -vt 1.727590 0.833933 -vt 1.721259 0.826124 -vt 1.671031 0.894589 -vt 1.806581 0.983761 -vt 1.808887 0.988109 -vt 1.850605 0.840104 -vt 1.847832 0.843279 -vt 1.847832 0.843279 -vt 1.850605 0.840104 -vt 1.832190 0.961777 -vt 1.847832 0.843279 -vt 1.825098 0.833812 -vt 1.806581 0.983761 -vt 1.787706 0.983066 -vt 1.742659 0.826246 -vt 1.474077 0.865561 -vt 1.497494 0.952154 -vt 1.505137 0.965983 -vt 1.486724 0.833848 -vt 1.511976 0.821328 -vt 1.535132 0.991677 -vt 1.839120 0.949321 -vt 1.859622 0.870344 -vt 0.151943 0.966273 -vt 0.151914 0.936365 -vt 0.118246 0.934817 -vt 0.118276 0.966204 -vt 0.178138 0.965761 -vt 0.178109 0.936030 -vt 0.204440 0.965590 -vt 0.204412 0.935862 -vt 0.232801 0.965563 -vt 0.232773 0.935835 -vt 0.038622 0.965136 -vt 0.038592 0.934188 -vt 0.010231 0.934215 -vt 0.012148 0.965162 -vt 0.065148 0.965369 -vt 0.065118 0.934322 -vt 0.091706 0.965741 -vt 0.091676 0.934542 -vt 0.151897 0.918153 -vt 0.118231 0.919298 -vt 0.118246 0.934817 -vt 0.151914 0.936365 -vt 0.178092 0.917926 -vt 0.178109 0.936030 -vt 0.204394 0.917878 -vt 0.204412 0.935862 -vt 0.232755 0.917851 -vt 0.232773 0.935835 -vt 0.038578 0.918885 -vt 0.010216 0.918912 -vt 0.010231 0.934215 -vt 0.038592 0.934188 -vt 0.065103 0.918970 -vt 0.065118 0.934322 -vt 0.091661 0.919114 -vt 0.091676 0.934542 -vt 0.151886 0.907159 -vt 0.118220 0.908326 -vt 0.118231 0.919298 -vt 0.151897 0.918153 -vt 0.178081 0.906997 -vt 0.178092 0.917926 -vt 0.204384 0.906970 -vt 0.204394 0.917878 -vt 0.232745 0.906943 -vt 0.232755 0.917851 -vt 0.038567 0.908066 -vt 0.010206 0.908094 -vt 0.010216 0.918912 -vt 0.038578 0.918885 -vt 0.065093 0.908117 -vt 0.065103 0.918970 -vt 0.091650 0.908208 -vt 0.091661 0.919114 -vt 0.151864 0.884126 -vt 0.118197 0.884159 -vt 0.118220 0.908326 -vt 0.151886 0.907159 -vt 0.178059 0.884101 -vt 0.178081 0.906997 -vt 0.204361 0.884075 -vt 0.204384 0.906970 -vt 0.232723 0.884048 -vt 0.232745 0.906943 -vt 0.038544 0.884236 -vt 0.010183 0.884263 -vt 0.010206 0.908094 -vt 0.038567 0.908066 -vt 0.065070 0.884210 -vt 0.065093 0.908117 -vt 0.091627 0.884184 -vt 0.091650 0.908208 -vt 1.319964 0.882191 -vt 1.320134 0.902752 -vt 1.347219 0.902528 -vt 1.347049 0.881967 -vt 1.292880 0.882414 -vt 1.293050 0.902975 -vt 1.265796 0.882638 -vt 1.265966 0.903199 -vt 1.238712 0.882862 -vt 1.238882 0.903423 -vt 1.428215 0.881296 -vt 1.428385 0.901857 -vt 1.455469 0.901633 -vt 1.455299 0.881072 -vt 1.401217 0.881519 -vt 1.401387 0.902080 -vt 1.428385 0.901857 -vt 1.428215 0.881296 -vt 1.374133 0.881743 -vt 1.374303 0.902304 -vt 1.401387 0.902080 -vt 1.401217 0.881519 -vt 1.320333 0.930704 -vt 1.320488 0.949446 -vt 1.347561 0.949223 -vt 1.347406 0.930480 -vt 1.293260 0.930928 -vt 1.293415 0.949670 -vt 1.266186 0.931151 -vt 1.266341 0.949894 -vt 1.239113 0.931375 -vt 1.239268 0.950118 -vt 1.428626 0.929809 -vt 1.428781 0.948551 -vt 1.455855 0.948328 -vt 1.455700 0.929585 -vt 1.401553 0.930033 -vt 1.401708 0.948775 -vt 1.374480 0.930256 -vt 1.374635 0.948999 -vt 1.320590 0.961766 -vt 1.320820 0.989579 -vt 1.347893 0.989356 -vt 1.347663 0.961543 -vt 1.293517 0.961990 -vt 1.293746 0.989803 -vt 1.266443 0.962214 -vt 1.266673 0.990027 -vt 1.239370 0.962438 -vt 1.239600 0.990251 -vt 1.428883 0.960871 -vt 1.429113 0.988684 -vt 1.456187 0.988461 -vt 1.455957 0.960648 -vt 1.401810 0.961095 -vt 1.402040 0.988908 -vt 1.374737 0.961319 -vt 1.374966 0.989132 -vt 1.320218 0.916692 -vt 1.347291 0.916468 -vt 1.347219 0.902528 -vt 1.320134 0.902752 -vt 1.293144 0.916916 -vt 1.293050 0.902975 -vt 1.266071 0.917140 -vt 1.265966 0.903199 -vt 1.238997 0.917363 -vt 1.238882 0.903423 -vt 1.428510 0.915797 -vt 1.455584 0.915573 -vt 1.455469 0.901633 -vt 1.401438 0.916021 -vt 1.374364 0.916245 -vt 1.374303 0.902304 -vt 1.320333 0.930704 -vt 1.347406 0.930480 -vt 1.347291 0.916468 -vt 1.320218 0.916692 -vt 1.293260 0.930928 -vt 1.293144 0.916916 -vt 1.266186 0.931151 -vt 1.266071 0.917140 -vt 1.239113 0.931375 -vt 1.238997 0.917363 -vt 1.428626 0.929809 -vt 1.455700 0.929585 -vt 1.455584 0.915573 -vt 1.428510 0.915797 -vt 1.401553 0.930033 -vt 1.401438 0.916021 -vt 1.374480 0.930256 -vt 1.374364 0.916245 -vt 2.838425 0.629350 -vt 2.833580 0.641115 -vt 2.896551 0.641960 -vt 2.891809 0.630066 -vt 0.613012 0.566762 -vt 0.613203 0.577108 -vt 0.627946 0.576837 -vt 0.627756 0.566490 -vt 0.597978 0.567038 -vt 0.598168 0.577385 -vt 0.583420 0.567306 -vt 0.583610 0.577653 -vt 0.570606 0.567542 -vt 0.570797 0.577889 -vt 0.556928 0.567794 -vt 0.557118 0.578140 -vt 0.542895 0.568052 -vt 0.543085 0.578399 -vt 0.527991 0.568326 -vt 0.528181 0.578673 -vt 0.513593 0.568591 -vt 0.513784 0.578938 -vt 0.498110 0.568876 -vt 0.498300 0.579223 -vt 0.483103 0.569152 -vt 0.483294 0.579499 -vt 0.698573 0.565187 -vt 0.698763 0.575534 -vt 0.712688 0.575278 -vt 0.712498 0.564931 -vt 0.684393 0.565448 -vt 0.684583 0.575795 -vt 0.670601 0.565702 -vt 0.670792 0.576048 -vt 0.657149 0.565949 -vt 0.657340 0.576296 -vt 0.642327 0.566222 -vt 0.642517 0.576569 -vt 4.838881 0.666464 -vt 4.847080 0.675011 -vt 4.882653 0.675536 -vt 4.891664 0.666551 -vt 0.627756 0.566490 -vt 0.627604 0.558206 -vt 0.642327 0.566222 -vt 0.642175 0.557938 -vt 0.657149 0.565949 -vt 0.656997 0.557665 -vt 0.670601 0.565702 -vt 0.670449 0.557417 -vt 0.684393 0.565448 -vt 0.684240 0.557164 -vt 0.698573 0.565187 -vt 0.698421 0.556903 -vt 0.712498 0.564931 -vt 0.712345 0.556646 -vt 0.483103 0.569152 -vt 0.498110 0.568876 -vt 0.497957 0.560592 -vt 0.482951 0.560868 -vt 0.513593 0.568591 -vt 0.513441 0.560307 -vt 0.527991 0.568326 -vt 0.527838 0.560042 -vt 0.542895 0.568052 -vt 0.542742 0.559767 -vt 0.556928 0.567794 -vt 0.556776 0.559509 -vt 0.628124 0.586467 -vt 0.628283 0.595150 -vt 0.513961 0.588568 -vt 0.514121 0.597251 -vt 0.498477 0.588853 -vt 0.498637 0.597536 -vt 0.483471 0.589129 -vt 0.483631 0.597812 -vt 0.712866 0.584908 -vt 0.698941 0.585164 -vt 0.699100 0.593847 -vt 0.713025 0.593590 -vt 0.684761 0.585425 -vt 0.684920 0.594108 -vt 0.670969 0.585679 -vt 0.671129 0.594361 -vt 0.657517 0.585926 -vt 0.657677 0.594609 -vt 0.642695 0.586199 -vt 0.642854 0.594882 -vt 0.612860 0.558477 -vt 0.627604 0.558206 -vt 0.627569 0.556307 -vt 0.612825 0.556578 -vt 0.642175 0.557938 -vt 0.642140 0.556039 -vt 0.656997 0.557665 -vt 0.656962 0.555766 -vt 0.670449 0.557417 -vt 0.670414 0.555518 -vt 0.684240 0.557164 -vt 0.684206 0.555265 -vt 0.698421 0.556903 -vt 0.698386 0.555004 -vt 0.712345 0.556646 -vt 0.712310 0.554747 -vt 0.482951 0.560868 -vt 0.497957 0.560592 -vt 0.497922 0.558693 -vt 0.482916 0.558969 -vt 0.513441 0.560307 -vt 0.513406 0.558408 -vt 0.527838 0.560042 -vt 0.527803 0.558143 -vt 0.542742 0.559767 -vt 0.542707 0.557869 -vt 0.556776 0.559509 -vt 0.556741 0.557610 -vt 0.570454 0.559258 -vt 0.570419 0.557359 -vt 0.583267 0.559022 -vt 0.583232 0.557123 -vt 0.597825 0.558754 -vt 0.597790 0.556855 -vt 0.628283 0.595150 -vt 0.613540 0.595421 -vt 0.613572 0.597166 -vt 0.628316 0.596895 -vt 0.598505 0.595698 -vt 0.598537 0.597443 -vt 0.583947 0.595966 -vt 0.583979 0.597710 -vt 0.571134 0.596202 -vt 0.571166 0.597946 -vt 0.557455 0.596453 -vt 0.557488 0.598198 -vt 0.543422 0.596712 -vt 0.543454 0.598456 -vt 0.528518 0.596986 -vt 0.528550 0.598731 -vt 0.514121 0.597251 -vt 0.514153 0.598995 -vt 0.498637 0.597536 -vt 0.498669 0.599280 -vt 0.483631 0.597812 -vt 0.483663 0.599557 -vt 0.713025 0.593590 -vt 0.699100 0.593847 -vt 0.699132 0.595591 -vt 0.713057 0.595335 -vt 0.684920 0.594108 -vt 0.684952 0.595852 -vt 0.671129 0.594361 -vt 0.671161 0.596106 -vt 0.657677 0.594609 -vt 0.657709 0.596354 -vt 0.642854 0.594882 -vt 0.642887 0.596626 -vt 0.613380 0.586739 -vt 0.628124 0.586467 -vt 0.627946 0.576837 -vt 0.613203 0.577108 -vt 0.598345 0.587015 -vt 0.598168 0.577385 -vt 0.583787 0.587283 -vt 0.583610 0.577653 -vt 0.570974 0.587519 -vt 0.570797 0.577889 -vt 0.557296 0.587771 -vt 0.557118 0.578140 -vt 0.543262 0.588029 -vt 0.543085 0.578399 -vt 0.528359 0.588303 -vt 0.528181 0.578673 -vt 0.513961 0.588568 -vt 0.513784 0.578938 -vt 0.498477 0.588853 -vt 0.498300 0.579223 -vt 0.483471 0.589129 -vt 0.483294 0.579499 -vt 0.698941 0.585164 -vt 0.712866 0.584908 -vt 0.712688 0.575278 -vt 0.698763 0.575534 -vt 0.684761 0.585425 -vt 0.684583 0.575795 -vt 0.670969 0.585679 -vt 0.670792 0.576048 -vt 0.657517 0.585926 -vt 0.657340 0.576296 -vt 0.642695 0.586199 -vt 0.642517 0.576569 -vt 1.932941 0.613848 -vt 1.936440 0.613848 -vt 1.936440 0.593358 -vt 1.932941 0.593358 -vt 1.932941 0.634339 -vt 1.936440 0.634339 -vt 1.932941 0.654830 -vt 1.936440 0.654830 -vt 1.932941 0.552377 -vt 1.936440 0.552377 -vt 1.936440 0.531886 -vt 1.932941 0.531886 -vt 1.932941 0.572867 -vt 1.936440 0.572867 -vt 1.964272 0.614013 -vt 1.978612 0.614013 -vt 1.978612 0.593111 -vt 1.964272 0.593111 -vt 1.964272 0.634422 -vt 1.978612 0.634422 -vt 1.964272 0.654830 -vt 1.978612 0.654830 -vt 1.964272 0.552294 -vt 1.978612 0.552294 -vt 1.978612 0.531886 -vt 1.964272 0.531886 -vt 1.964272 0.572703 -vt 1.978612 0.572703 -vt 1.964272 0.614013 -vt 1.964272 0.593111 -vt 1.945781 0.593358 -vt 1.945781 0.613849 -vt 1.964272 0.634422 -vt 1.945781 0.634339 -vt 1.964272 0.654830 -vt 1.945781 0.654830 -vt 1.964272 0.552294 -vt 1.964272 0.531886 -vt 1.945781 0.531886 -vt 1.945781 0.552377 -vt 1.964272 0.572703 -vt 1.945781 0.572867 -vt 1.948957 0.689810 -vt 1.939799 0.689810 -vt 1.939803 0.691444 -vt 1.948867 0.692212 -vt 1.939799 0.658221 -vt 1.939799 0.689810 -vt 1.948957 0.689810 -vt 1.948957 0.658221 -vt 1.901649 0.531322 -vt 1.901649 0.681789 -vt 1.911924 0.681789 -vt 1.911924 0.531322 -vt 1.919678 0.681789 -vt 1.919678 0.531322 -vt 1.919678 0.531322 -vt 1.919678 0.681789 -vt 1.929541 0.681789 -vt 1.927963 0.531322 -vt 2.929541 0.681789 -vt 2.927963 0.531322 -vt 2.919678 0.531322 -vt 2.919678 0.681789 -vt 2.919678 0.681789 -vt 2.919678 0.531322 -vt 2.911924 0.531322 -vt 2.911924 0.681789 -vt 2.911924 0.681789 -vt 2.911924 0.531322 -vt 2.901649 0.531322 -vt 2.901649 0.681789 -vt 0.653557 0.635717 -vt 0.653557 0.644666 -vt 0.787461 0.644547 -vt 0.787461 0.635838 -vt 0.653557 0.652542 -vt 0.787461 0.652662 -vt 0.653557 0.661492 -vt 0.787461 0.661373 -vt 0.653557 0.669213 -vt 0.787461 0.669213 -vt 0.653557 0.677249 -vt 0.787461 0.677249 -vt 0.653557 0.611351 -vt 0.653557 0.618762 -vt 0.787461 0.618762 -vt 0.787461 0.611351 -vt 0.653557 0.627702 -vt 0.787461 0.627702 -vt 0.790486 0.644521 -vt 0.804256 0.644590 -vt 0.804256 0.635967 -vt 0.790486 0.635883 -vt 0.790486 0.652704 -vt 0.804256 0.652654 -vt 0.804256 0.644590 -vt 0.790486 0.644521 -vt 0.790486 0.661424 -vt 0.804256 0.661401 -vt 0.804256 0.652654 -vt 0.790486 0.652704 -vt 0.790486 0.669213 -vt 0.804256 0.669213 -vt 0.804256 0.661401 -vt 0.790486 0.661424 -vt 0.790486 0.677249 -vt 0.804256 0.677249 -vt 0.804256 0.669213 -vt 0.790486 0.669213 -vt 0.790486 0.618762 -vt 0.804256 0.618762 -vt 0.804256 0.611351 -vt 0.790486 0.611351 -vt 0.790486 0.627702 -vt 0.804256 0.627702 -vt 0.804256 0.618762 -vt 0.790486 0.618762 -vt 0.790486 0.635883 -vt 0.804256 0.635967 -vt 0.804256 0.627702 -vt 0.790486 0.627702 -vt 1.907472 0.257985 -vt 1.908977 0.257975 -vt 1.912623 0.051317 -vt 1.911119 0.051328 -vt 1.910712 0.257976 -vt 1.914357 0.051377 -vt 1.905738 0.257926 -vt 1.909384 0.051326 -vt 1.945508 0.023291 -vt 1.942880 0.023291 -vt 1.942142 0.289169 -vt 1.945365 0.289169 -vt 1.953900 0.023291 -vt 1.948675 0.023291 -vt 1.948937 0.289169 -vt 1.953900 0.289169 -vt 1.884426 0.003712 -vt 1.882265 0.003712 -vt 1.882265 0.306753 -vt 1.884426 0.306753 -vt 1.891725 0.003712 -vt 1.887573 0.003712 -vt 1.887573 0.306753 -vt 1.891725 0.306753 -vt 0.672500 0.806611 -vt 0.671067 0.801549 -vt 0.457033 0.801549 -vt 0.458466 0.806611 -vt 0.671087 0.796454 -vt 0.457013 0.796454 -vt 0.672521 0.811706 -vt 0.458446 0.811706 -vt 0.973814 0.134518 -vt 0.970027 0.134518 -vt 0.970027 0.286613 -vt 0.973814 0.286613 -vt 0.967029 0.134518 -vt 0.967029 0.286613 -vt 0.963765 0.134518 -vt 0.963765 0.286613 -vt 0.991477 0.134518 -vt 0.987690 0.134518 -vt 0.987690 0.286613 -vt 0.991477 0.286613 -vt 0.983886 0.134518 -vt 0.983886 0.286613 -vt 0.980889 0.134518 -vt 0.980889 0.286613 -vt 0.977618 0.134518 -vt 0.977618 0.286613 -vt 1.688848 0.749275 -vt 1.688848 0.796196 -vt 1.707262 0.796196 -vt 1.707262 0.749275 -vt 1.688848 0.821096 -vt 1.707262 0.821096 -vt 1.688848 0.687755 -vt 1.688848 0.713461 -vt 1.707262 0.713461 -vt 1.707262 0.687755 -vt 1.707262 0.749275 -vt 1.707262 0.796196 -vt 1.712529 0.796196 -vt 1.712529 0.749275 -vt 1.707262 0.796196 -vt 1.707262 0.821096 -vt 1.712529 0.821096 -vt 1.712529 0.796196 -vt 1.707262 0.687755 -vt 1.707262 0.713461 -vt 1.712529 0.713461 -vt 1.712529 0.687755 -vt 1.707262 0.713461 -vt 1.707262 0.749275 -vt 1.712529 0.749275 -vt 1.712529 0.713461 -vt 0.901273 0.987954 -vt 0.905721 0.987777 -vt 0.898839 0.809308 -vt 0.894390 0.809475 -vt 0.910255 0.987933 -vt 0.903373 0.809475 -vt 0.914763 0.987434 -vt 0.907880 0.808954 -vt 0.919212 0.987273 -vt 0.912328 0.808772 -vt 0.923660 0.987101 -vt 0.916777 0.808601 -vt 0.887785 0.988453 -vt 0.892292 0.987943 -vt 0.885410 0.809505 -vt 0.880903 0.810015 -vt 0.896825 0.988115 -vt 0.889943 0.809656 -vt 1.835327 0.793387 -vt 1.831746 0.793387 -vt 1.831746 0.820585 -vt 1.835327 0.820585 -vt 1.828119 0.793387 -vt 1.828119 0.820585 -vt 1.824470 0.793387 -vt 1.824470 0.820585 -vt 1.820887 0.793387 -vt 1.820887 0.820585 -vt 1.817304 0.793387 -vt 1.817304 0.820585 -vt 1.813656 0.793387 -vt 1.813656 0.820585 -vt 1.810030 0.793387 -vt 1.810030 0.820585 -vt 1.838908 0.793387 -vt 1.838908 0.820585 -vt 1.963142 0.507307 -vt 1.966829 0.510170 -vt 1.963771 0.464386 -vt 1.956692 0.465842 -vt 1.971978 0.514904 -vt 1.968024 0.463687 -vt 1.975459 0.514343 -vt 1.971339 0.463143 -vt 1.978725 0.509767 -vt 1.973352 0.462812 -vt 1.954252 0.423683 -vt 1.945634 0.424628 -vt 1.962774 0.422283 -vt 1.966228 0.421716 -vt 1.969417 0.421193 -vt 1.938767 0.405843 -vt 1.949923 0.403838 -vt 1.946255 0.386738 -vt 1.932504 0.389173 -vt 1.960009 0.402182 -vt 1.957710 0.384857 -vt 1.964799 0.401395 -vt 1.965586 0.383564 -vt 1.969884 0.400560 -vt 1.972329 0.382456 -vt 1.930994 0.364212 -vt 1.931040 0.379851 -vt 1.943846 0.369533 -vt 1.936570 0.333645 -vt 1.955052 0.362291 -vt 1.950086 0.315819 -vt 1.964760 0.358704 -vt 1.963966 0.306471 -vt 1.972943 0.361369 -vt 1.976111 0.317948 -vt 1.981663 0.505121 -vt 1.974988 0.462717 -vt 1.972942 0.421304 -vt 1.974470 0.399545 -vt 1.977774 0.381266 -vt 1.980256 0.366925 -vt 1.985764 0.339373 -vt 1.966829 0.510170 -vt 1.963142 0.507307 -vt 1.960727 0.510219 -vt 1.964615 0.512998 -vt 1.971978 0.514904 -vt 1.966829 0.510170 -vt 1.964615 0.512998 -vt 1.971030 0.518012 -vt 1.978725 0.509767 -vt 1.975459 0.514343 -vt 1.975659 0.517915 -vt 1.979438 0.515266 -vt 1.956692 0.465842 -vt 1.945634 0.424628 -vt 1.941483 0.425665 -vt 1.953100 0.466601 -vt 1.972942 0.421304 -vt 1.974988 0.462717 -vt 1.978737 0.462523 -vt 1.977648 0.421732 -vt 1.938767 0.405843 -vt 1.932504 0.389173 -vt 1.928188 0.391026 -vt 1.935117 0.407189 -vt 1.974470 0.399545 -vt 1.972942 0.421304 -vt 1.977648 0.421732 -vt 1.978161 0.399738 -vt 1.931040 0.379851 -vt 1.930994 0.364212 -vt 1.926746 0.365415 -vt 1.926916 0.381387 -vt 1.930994 0.364212 -vt 1.936570 0.333645 -vt 1.933515 0.332831 -vt 1.926746 0.365415 -vt 1.936570 0.333645 -vt 1.950086 0.315819 -vt 1.948466 0.313374 -vt 1.933515 0.332831 -vt 1.950086 0.315819 -vt 1.963966 0.306471 -vt 1.962437 0.303992 -vt 1.948466 0.313374 -vt 1.976111 0.317948 -vt 1.985764 0.339373 -vt 1.990410 0.338499 -vt 1.978359 0.315358 -vt 1.980256 0.366925 -vt 1.977774 0.381266 -vt 1.981269 0.381445 -vt 1.984066 0.367261 -vt 1.963966 0.306471 -vt 1.976111 0.317948 -vt 1.978359 0.315358 -vt 1.965424 0.303475 -vt 1.981663 0.505121 -vt 1.978725 0.509767 -vt 1.979438 0.515266 -vt 1.982307 0.509582 -vt 1.985764 0.339373 -vt 1.980256 0.366925 -vt 1.984066 0.367261 -vt 1.990410 0.338499 -vt 1.931040 0.379851 -vt 1.945634 0.424628 -vt 1.938767 0.405843 -vt 1.935117 0.407189 -vt 1.941483 0.425665 -vt 1.977774 0.381266 -vt 1.974470 0.399545 -vt 1.978161 0.399738 -vt 1.981269 0.381445 -vt 1.956592 0.511103 -vt 1.950077 0.517329 -vt 1.926916 0.381387 -vt 1.876822 0.376070 -vt 1.886744 0.406160 -vt 1.928188 0.391026 -vt 1.933515 0.332831 -vt 1.931160 0.313322 -vt 1.921929 0.299465 -vt 1.906951 0.304459 -vt 1.876822 0.376070 -vt 1.926916 0.381387 -vt 1.926746 0.365415 -vt 1.882738 0.329557 -vt 1.882738 0.329557 -vt 1.926746 0.365415 -vt 1.933515 0.332831 -vt 1.906951 0.304459 -vt 0.565573 0.782724 -vt 0.631173 0.764652 -vt 0.500841 0.780471 -vt 0.526626 0.783518 -vt 0.630058 0.699236 -vt 0.641785 0.651360 -vt 0.637337 0.616972 -vt 0.596866 0.612516 -vt 0.630058 0.699236 -vt 0.489568 0.620042 -vt 0.500841 0.780471 -vt 0.631173 0.764652 -vt 0.532640 0.607381 -vt 0.504547 0.612629 -vt 0.489568 0.620042 -vt 0.596866 0.612516 -vt 0.450798 0.706790 -vt 0.462399 0.748874 -vt 0.500841 0.780471 -vt 0.489568 0.620042 -vt 0.464575 0.645515 -vt 0.454897 0.674918 -vt 0.450798 0.706790 -vt 0.489568 0.620042 -vt 4.896566 0.641971 -vt 4.833570 0.641126 -vt 4.833514 0.653935 -vt 4.896511 0.654781 -vt 4.891823 0.630072 -vt 4.838417 0.629355 -vt 4.858635 0.680069 -vt 4.871963 0.679861 -vt 4.883001 0.620895 -vt 4.847316 0.620416 -vt 4.871445 0.615838 -vt 4.858914 0.615670 -vt 2.896495 0.654765 -vt 2.833525 0.653920 -vt 2.882991 0.620893 -vt 2.847321 0.620414 -vt 2.871440 0.615838 -vt 2.858914 0.615670 -vt 1.676401 0.986658 -vt 1.671031 0.894589 -vt 0.063613 0.482216 -vt 0.058323 0.502256 -vt 1.979348 0.689810 -vt 1.979362 0.691436 -vt 1.993903 0.691436 -vt 1.993911 0.689810 -vt 1.979067 0.658221 -vt 1.979348 0.689810 -vt 1.993911 0.689810 -vt 1.993909 0.658221 -vt 0.521275 0.077663 -vt 0.521275 0.115703 -vt 0.521275 0.150343 -vt 0.521275 0.052086 -vt 0.521275 0.014684 -vt 0.521275 0.188430 -vt 0.773548 0.788447 -vt 0.792986 0.760963 -vt 0.810287 0.776335 -vt 0.794554 0.804641 -vt 0.767225 0.804455 -vt 0.773548 0.788447 -vt 0.794554 0.804641 -vt 0.785301 0.819129 -vt 0.811318 0.732380 -vt 0.807952 0.688354 -vt 0.857822 0.684972 -vt 0.842490 0.758277 -vt 0.792986 0.760963 -vt 0.810287 0.776335 -vt 0.477040 0.074678 -vt 0.475514 0.113873 -vt 0.474805 0.152050 -vt 0.477234 0.050396 -vt 0.476861 0.018904 -vt 0.470793 0.191393 -vt 1.122549 0.656233 -vt 1.119097 0.704237 -vt 1.007228 0.696445 -vt 1.010633 0.652337 -vt 1.115658 0.753608 -vt 1.003656 0.747731 -vt 1.234486 0.661460 -vt 1.231007 0.711437 -vt 1.010442 0.602044 -vt 1.122635 0.602044 -vt 1.122578 0.652637 -vt 1.010500 0.652637 -vt 1.114950 0.763773 -vt 1.028796 0.757590 -vt 1.227568 0.760808 -vt 1.346443 0.668053 -vt 1.342960 0.718029 -vt 1.234828 0.602638 -vt 1.234656 0.654561 -vt 1.010560 0.550570 -vt 1.122635 0.552394 -vt 1.062947 0.849104 -vt 1.061147 0.817481 -vt 1.110904 0.821863 -vt 1.108784 0.852297 -vt 1.226860 0.770973 -vt 1.339521 0.767400 -vt 1.407538 0.672188 -vt 1.438412 0.723653 -vt 1.347022 0.603842 -vt 1.346734 0.658459 -vt 1.234828 0.552988 -vt 1.036628 0.541905 -vt 1.122635 0.542227 -vt 1.224120 0.810314 -vt 1.222813 0.829063 -vt 1.112209 0.803114 -vt 1.338813 0.777565 -vt 1.451460 0.774172 -vt 1.408643 0.660136 -vt 1.441013 0.606700 -vt 1.449077 0.613331 -vt 1.414803 0.663012 -vt 1.441013 0.606700 -vt 1.408643 0.660136 -vt 1.347022 0.554192 -vt 1.234828 0.542822 -vt 1.072599 0.485738 -vt 1.122635 0.484280 -vt 1.122635 0.502880 -vt 1.067729 0.503711 -vt 1.336072 0.816907 -vt 1.334766 0.835655 -vt 1.450752 0.784337 -vt 1.458729 0.555094 -vt 1.468300 0.556341 -vt 1.449466 0.611753 -vt 1.458729 0.555094 -vt 1.347022 0.544025 -vt 1.234828 0.484874 -vt 1.234828 0.503474 -vt 1.448012 0.823679 -vt 1.435030 0.841614 -vt 1.458499 0.545633 -vt 1.467840 0.545989 -vt 1.458499 0.545633 -vt 1.347022 0.486078 -vt 1.347022 0.504678 -vt 1.466944 0.501505 -vt 1.458683 0.504904 -vt 1.447451 0.487014 -vt 1.458683 0.504904 -vt 1.036628 0.541905 -vt 1.010560 0.550570 -vt 1.008432 0.542215 -vt 1.031953 0.534333 -vt 1.059617 0.498005 -vt 1.067729 0.503711 -vt 1.063922 0.484353 -vt 1.071413 0.450752 -vt 1.076831 0.448786 -vt 1.072599 0.485738 -vt 1.220694 0.859497 -vt 1.332646 0.866089 -vt 1.122122 0.451058 -vt 1.234965 0.454150 -vt 1.413957 0.870728 -vt 1.347024 0.455886 -vt 1.428376 0.456721 -vt 1.058035 0.799341 -vt 1.076831 0.448786 -vt 0.007350 0.433571 -vt 0.007350 0.223041 -vt 0.007350 0.219056 -vt 0.360029 0.219502 -vt 0.359781 0.223060 -vt 0.412410 0.221355 -vt 0.408486 0.225878 -vt 0.007350 0.377143 -vt 0.359604 0.377913 -vt 0.361111 0.429252 -vt 0.008858 0.429252 -vt 0.443716 0.379205 -vt 0.415695 0.429252 -vt 0.447494 0.117159 -vt 0.442509 0.117159 -vt 0.444812 0.062060 -vt 0.449332 0.062060 -vt 0.442509 0.117159 -vt 0.359604 0.113625 -vt 0.359604 0.064109 -vt 0.444812 0.062060 -vt 0.359604 0.012457 -vt 0.007350 0.062893 -vt 0.007350 0.012457 -vt 0.007350 0.273165 -vt 0.359604 0.273993 -vt 0.007350 0.164184 -vt 0.359856 0.165360 -vt 0.444599 0.160996 -vt 0.417279 0.223981 -vt 0.411881 0.221286 -vt 0.439950 0.160996 -vt 0.359604 0.273993 -vt 0.359781 0.223060 -vt 0.408486 0.225878 -vt 0.424813 0.274675 -vt 0.439950 0.160996 -vt 0.411881 0.221286 -vt 0.360029 0.219502 -vt 0.359856 0.165360 -vt 0.007350 0.325257 -vt 0.359604 0.326053 -vt 0.007350 0.112438 -vt 0.442099 0.327051 -vt 0.417122 0.012457 -vt 0.007350 0.273165 -vt 0.007350 0.164184 -vt 0.556521 0.990202 -vt 0.602982 0.814799 -vt 0.619799 0.822990 -vt 0.649324 0.985311 -vt 0.701728 0.978157 -vt 0.677748 0.976969 -vt 0.682262 0.899936 -vt 0.727590 0.833933 -vt 0.832190 0.961777 -vt 0.839120 0.949321 -vt 0.843743 0.951051 -vt 0.836182 0.964853 -vt 0.859622 0.870344 -vt 0.864233 0.869956 -vt 0.826082 0.827429 -vt 0.825098 0.833812 -vt 0.742659 0.826246 -vt 0.741088 0.816903 -vt 0.721259 0.826124 -vt 0.727590 0.833933 -vt 0.682262 0.899936 -vt 0.671031 0.894589 -vt 0.806581 0.983761 -vt 0.808887 0.988109 -vt 0.847832 0.843279 -vt 0.850605 0.840104 -vt 0.850605 0.840104 -vt 0.847832 0.843279 -vt 0.832190 0.961777 -vt 0.806581 0.983761 -vt 0.825098 0.833812 -vt 0.847832 0.843279 -vt 0.787706 0.983066 -vt 0.742659 0.826246 -vt 0.505137 0.965983 -vt 0.497494 0.952154 -vt 0.474077 0.865561 -vt 0.486724 0.833848 -vt 0.511976 0.821328 -vt 0.535132 0.991677 -vt 0.859622 0.870344 -vt 0.839120 0.949321 -vt 1.118246 0.934817 -vt 1.151914 0.936365 -vt 1.151943 0.966273 -vt 1.118276 0.966204 -vt 1.178110 0.936030 -vt 1.178138 0.965761 -vt 1.204412 0.935862 -vt 1.204440 0.965590 -vt 1.232773 0.935835 -vt 1.232801 0.965563 -vt 1.010231 0.934215 -vt 1.038592 0.934188 -vt 1.038622 0.965136 -vt 1.012148 0.965162 -vt 1.065118 0.934322 -vt 1.065148 0.965369 -vt 1.065118 0.934322 -vt 1.091676 0.934542 -vt 1.091706 0.965741 -vt 1.065148 0.965369 -vt 1.091676 0.934542 -vt 1.091706 0.965741 -vt 1.118246 0.934817 -vt 1.118231 0.919298 -vt 1.151897 0.918153 -vt 1.151914 0.936365 -vt 1.178092 0.917926 -vt 1.178110 0.936030 -vt 1.204394 0.917878 -vt 1.204412 0.935862 -vt 1.232755 0.917851 -vt 1.232773 0.935835 -vt 1.010231 0.934215 -vt 1.010216 0.918912 -vt 1.038578 0.918885 -vt 1.038592 0.934188 -vt 1.065103 0.918970 -vt 1.091661 0.919114 -vt 1.118231 0.919298 -vt 1.118220 0.908326 -vt 1.151886 0.907159 -vt 1.151897 0.918153 -vt 1.178082 0.906997 -vt 1.178092 0.917926 -vt 1.204384 0.906970 -vt 1.204394 0.917878 -vt 1.232745 0.906943 -vt 1.232755 0.917851 -vt 1.010216 0.918912 -vt 1.010206 0.908094 -vt 1.038567 0.908066 -vt 1.038578 0.918885 -vt 1.065093 0.908117 -vt 1.065103 0.918970 -vt 1.091650 0.908208 -vt 1.091661 0.919114 -vt 1.118220 0.908326 -vt 1.118197 0.884159 -vt 1.151864 0.884126 -vt 1.151886 0.907159 -vt 1.178059 0.884101 -vt 1.178082 0.906997 -vt 1.204361 0.884075 -vt 1.204384 0.906970 -vt 1.232723 0.884048 -vt 1.232745 0.906943 -vt 1.010206 0.908094 -vt 1.010183 0.884263 -vt 1.038544 0.884236 -vt 1.038567 0.908066 -vt 1.065070 0.884210 -vt 1.065093 0.908117 -vt 1.091627 0.884184 -vt 1.091650 0.908208 -vt 1.065167 0.984896 -vt 0.347219 0.902528 -vt 0.320134 0.902752 -vt 0.319964 0.882191 -vt 0.347049 0.881967 -vt 0.293050 0.902975 -vt 0.292880 0.882414 -vt 0.265966 0.903199 -vt 0.265796 0.882638 -vt 0.238882 0.903423 -vt 0.238712 0.882862 -vt 0.455469 0.901633 -vt 0.428385 0.901857 -vt 0.428215 0.881296 -vt 0.455299 0.881072 -vt 0.401387 0.902080 -vt 0.401217 0.881519 -vt 0.374303 0.902304 -vt 0.374133 0.881743 -vt 0.320333 0.930704 -vt 0.347406 0.930480 -vt 0.347561 0.949223 -vt 0.320488 0.949446 -vt 0.293260 0.930928 -vt 0.293415 0.949670 -vt 0.266186 0.931151 -vt 0.266341 0.949894 -vt 0.239113 0.931375 -vt 0.239268 0.950118 -vt 0.428626 0.929809 -vt 0.455700 0.929585 -vt 0.455855 0.948328 -vt 0.428781 0.948551 -vt 0.401553 0.930033 -vt 0.401708 0.948775 -vt 0.374480 0.930256 -vt 0.374635 0.948999 -vt 0.347893 0.989356 -vt 0.320820 0.989579 -vt 0.320590 0.961766 -vt 0.347663 0.961543 -vt 0.293746 0.989803 -vt 0.293517 0.961990 -vt 0.266673 0.990027 -vt 0.266443 0.962214 -vt 0.239600 0.990251 -vt 0.239370 0.962438 -vt 0.456187 0.988461 -vt 0.429113 0.988684 -vt 0.428883 0.960871 -vt 0.455957 0.960648 -vt 0.402040 0.988908 -vt 0.401810 0.961095 -vt 0.374966 0.989132 -vt 0.374737 0.961319 -vt 0.347219 0.902528 -vt 0.347291 0.916468 -vt 0.320218 0.916692 -vt 0.320134 0.902752 -vt 0.293144 0.916916 -vt 0.293050 0.902975 -vt 0.266071 0.917140 -vt 0.265966 0.903199 -vt 0.238998 0.917363 -vt 0.238882 0.903423 -vt 0.455469 0.901633 -vt 0.455584 0.915573 -vt 0.428510 0.915797 -vt 0.428385 0.901857 -vt 0.401437 0.916021 -vt 0.401387 0.902080 -vt 0.374364 0.916245 -vt 0.374303 0.902304 -vt 0.347291 0.916468 -vt 0.347406 0.930480 -vt 0.320333 0.930704 -vt 0.320218 0.916692 -vt 0.293260 0.930928 -vt 0.293144 0.916916 -vt 0.266186 0.931151 -vt 0.266071 0.917140 -vt 0.239113 0.931375 -vt 0.238998 0.917363 -vt 0.455584 0.915573 -vt 0.455700 0.929585 -vt 0.428626 0.929809 -vt 0.428510 0.915797 -vt 0.401553 0.930033 -vt 0.401437 0.916021 -vt 0.374480 0.930256 -vt 0.374364 0.916245 -vt 0.896551 0.641960 -vt 0.833580 0.641115 -vt 0.838425 0.629350 -vt 0.891809 0.630066 -vt 1.627946 0.576837 -vt 1.613203 0.577108 -vt 1.613012 0.566762 -vt 1.627756 0.566490 -vt 1.598168 0.577385 -vt 1.597978 0.567038 -vt 1.583610 0.577653 -vt 1.583420 0.567306 -vt 1.570796 0.577889 -vt 1.570606 0.567542 -vt 1.557118 0.578140 -vt 1.556928 0.567794 -vt 1.543085 0.578399 -vt 1.542895 0.568052 -vt 1.528181 0.578673 -vt 1.527991 0.568326 -vt 1.513784 0.578938 -vt 1.513593 0.568591 -vt 1.498300 0.579223 -vt 1.498110 0.568876 -vt 1.483294 0.579499 -vt 1.483104 0.569152 -vt 1.712688 0.575278 -vt 1.698763 0.575534 -vt 1.698573 0.565187 -vt 1.712498 0.564931 -vt 1.684583 0.575795 -vt 1.684393 0.565448 -vt 1.670792 0.576048 -vt 1.670601 0.565702 -vt 1.657340 0.576296 -vt 1.657149 0.565949 -vt 1.642517 0.576569 -vt 1.642327 0.566222 -vt 3.882653 0.675536 -vt 3.847080 0.675011 -vt 3.838880 0.666464 -vt 3.891664 0.666551 -vt 1.627756 0.566490 -vt 1.627604 0.558206 -vt 1.642175 0.557938 -vt 1.642327 0.566222 -vt 1.642327 0.566222 -vt 1.642175 0.557938 -vt 1.656997 0.557665 -vt 1.657149 0.565949 -vt 1.657149 0.565949 -vt 1.656997 0.557665 -vt 1.670449 0.557417 -vt 1.670601 0.565702 -vt 1.670601 0.565702 -vt 1.670449 0.557417 -vt 1.684240 0.557164 -vt 1.684393 0.565448 -vt 1.684393 0.565448 -vt 1.684240 0.557164 -vt 1.698421 0.556903 -vt 1.698573 0.565187 -vt 1.698573 0.565187 -vt 1.698421 0.556903 -vt 1.712345 0.556646 -vt 1.712498 0.564931 -vt 1.483104 0.569152 -vt 1.482951 0.560868 -vt 1.497957 0.560592 -vt 1.498110 0.568876 -vt 1.498110 0.568876 -vt 1.497957 0.560592 -vt 1.513441 0.560307 -vt 1.513593 0.568591 -vt 1.542895 0.568052 -vt 1.542742 0.559767 -vt 1.556776 0.559509 -vt 1.556928 0.567794 -vt 1.513961 0.588568 -vt 1.514121 0.597251 -vt 1.498637 0.597536 -vt 1.498477 0.588853 -vt 1.498477 0.588853 -vt 1.498637 0.597536 -vt 1.483631 0.597812 -vt 1.483471 0.589129 -vt 1.712866 0.584908 -vt 1.713025 0.593590 -vt 1.699100 0.593847 -vt 1.698941 0.585164 -vt 1.698941 0.585164 -vt 1.699100 0.593847 -vt 1.684920 0.594108 -vt 1.684761 0.585425 -vt 1.684761 0.585425 -vt 1.684920 0.594108 -vt 1.671129 0.594361 -vt 1.670969 0.585679 -vt 1.670969 0.585679 -vt 1.671129 0.594361 -vt 1.657677 0.594609 -vt 1.657517 0.585926 -vt 1.657517 0.585926 -vt 1.657677 0.594609 -vt 1.642854 0.594882 -vt 1.642695 0.586199 -vt 1.642695 0.586199 -vt 1.642854 0.594882 -vt 1.628284 0.595150 -vt 1.628124 0.586467 -vt 1.656997 0.557665 -vt 1.656962 0.555766 -vt 1.670414 0.555518 -vt 1.670449 0.557417 -vt 1.698421 0.556903 -vt 1.698385 0.555004 -vt 1.712311 0.554747 -vt 1.712345 0.556646 -vt 1.482916 0.558969 -vt 1.612860 0.558477 -vt 1.713025 0.593590 -vt 1.713057 0.595335 -vt 1.699132 0.595591 -vt 1.699100 0.593847 -vt 1.671129 0.594361 -vt 1.671161 0.596106 -vt 1.657709 0.596354 -vt 1.657677 0.594609 -vt 1.642854 0.594882 -vt 1.642887 0.596626 -vt 1.628316 0.596895 -vt 1.628284 0.595150 -vt 1.628124 0.586467 -vt 1.613380 0.586739 -vt 1.598345 0.587015 -vt 1.583787 0.587283 -vt 1.570974 0.587519 -vt 1.557296 0.587771 -vt 1.543262 0.588029 -vt 1.528358 0.588303 -vt 1.513961 0.588568 -vt 1.498477 0.588853 -vt 1.483471 0.589129 -vt 1.712866 0.584908 -vt 1.698941 0.585164 -vt 1.684761 0.585425 -vt 1.670969 0.585679 -vt 1.657517 0.585926 -vt 1.642695 0.586199 -vt 0.936439 0.593358 -vt 0.936439 0.613848 -vt 0.932941 0.613848 -vt 0.932941 0.593358 -vt 0.936439 0.634339 -vt 0.932941 0.634339 -vt 0.936439 0.654830 -vt 0.932941 0.654830 -vt 0.936439 0.531886 -vt 0.936439 0.552377 -vt 0.932941 0.552377 -vt 0.932941 0.531886 -vt 0.936439 0.572867 -vt 0.932941 0.572867 -vt 0.964273 0.614013 -vt 0.964273 0.593111 -vt 0.978612 0.593111 -vt 0.978612 0.614013 -vt 0.964273 0.634422 -vt 0.978612 0.634422 -vt 0.964273 0.654830 -vt 0.978612 0.654830 -vt 0.964273 0.552294 -vt 0.964273 0.531886 -vt 0.978612 0.531886 -vt 0.978612 0.552294 -vt 0.964273 0.572703 -vt 0.978612 0.572703 -vt 0.997477 0.613849 -vt 0.945781 0.593358 -vt 0.964273 0.593111 -vt 0.964273 0.614013 -vt 0.945781 0.613849 -vt 0.964273 0.634422 -vt 0.945781 0.634339 -vt 0.964273 0.654830 -vt 0.945781 0.654830 -vt 0.945781 0.531886 -vt 0.964273 0.531886 -vt 0.964273 0.552294 -vt 0.945781 0.552377 -vt 0.964273 0.572703 -vt 0.945781 0.572867 -vt 0.939803 0.691444 -vt 0.939799 0.689810 -vt 0.948957 0.689810 -vt 0.948867 0.692212 -vt 0.948957 0.689810 -vt 0.939799 0.689810 -vt 0.939799 0.658221 -vt 0.948957 0.658221 -vt 2.901649 0.531322 -vt 2.911924 0.531322 -vt 2.911924 0.681789 -vt 2.901649 0.681789 -vt 2.919678 0.531322 -vt 2.919678 0.681789 -vt 2.927963 0.531322 -vt 2.929541 0.681789 -vt 0.929541 0.681789 -vt 0.919678 0.681789 -vt 0.919678 0.531322 -vt 0.927963 0.531322 -vt 0.911924 0.681789 -vt 0.911924 0.531322 -vt 0.901649 0.681789 -vt 0.901649 0.531322 -vt 1.653557 0.635717 -vt 1.787461 0.635838 -vt 1.787461 0.644547 -vt 1.653557 0.644666 -vt 1.787461 0.652662 -vt 1.653557 0.652542 -vt 1.787461 0.661373 -vt 1.653557 0.661492 -vt 1.787461 0.669213 -vt 1.653557 0.669213 -vt 1.787461 0.677249 -vt 1.653557 0.677249 -vt 1.653557 0.611351 -vt 1.787461 0.611351 -vt 1.787461 0.618762 -vt 1.653557 0.618762 -vt 1.787461 0.627702 -vt 1.653557 0.627702 -vt 1.804256 0.635967 -vt 1.804256 0.644590 -vt 1.790486 0.644521 -vt 1.790486 0.635883 -vt 1.804256 0.644590 -vt 1.804256 0.652654 -vt 1.790486 0.652704 -vt 1.790486 0.644521 -vt 1.804256 0.652654 -vt 1.804256 0.661401 -vt 1.790486 0.661424 -vt 1.790486 0.652704 -vt 1.804256 0.661401 -vt 1.804256 0.669213 -vt 1.790486 0.669213 -vt 1.790486 0.661424 -vt 1.804256 0.669213 -vt 1.804256 0.677249 -vt 1.790486 0.677249 -vt 1.790486 0.669213 -vt 1.804256 0.611351 -vt 1.804256 0.618762 -vt 1.790486 0.618762 -vt 1.790486 0.611351 -vt 1.804256 0.618762 -vt 1.804256 0.627702 -vt 1.790486 0.627702 -vt 1.790486 0.618762 -vt 1.804256 0.627702 -vt 1.804256 0.635967 -vt 1.790486 0.635883 -vt 1.790486 0.627702 -vt 0.907472 0.257985 -vt 0.911119 0.051328 -vt 0.912623 0.051317 -vt 0.908977 0.257975 -vt 0.914357 0.051377 -vt 0.910712 0.257976 -vt 0.905738 0.257926 -vt 0.909384 0.051326 -vt 2.945508 0.023291 -vt 2.945365 0.289169 -vt 2.942142 0.289169 -vt 2.942880 0.023291 -vt 2.953900 0.023291 -vt 2.953900 0.289169 -vt 2.948937 0.289169 -vt 2.948675 0.023291 -vt 2.884426 0.003712 -vt 2.884426 0.306753 -vt 2.882265 0.306753 -vt 2.882265 0.003712 -vt 2.891725 0.003712 -vt 2.891725 0.306753 -vt 2.887573 0.306753 -vt 2.887573 0.003712 -vt 3.672500 0.806611 -vt 3.458466 0.806611 -vt 3.457033 0.801549 -vt 3.671067 0.801549 -vt 3.457013 0.796454 -vt 3.671087 0.796454 -vt 3.672521 0.811706 -vt 3.458446 0.811706 -vt 3.973814 0.134518 -vt 3.973814 0.286613 -vt 3.970027 0.286613 -vt 3.970027 0.134518 -vt 3.967030 0.286613 -vt 3.967030 0.134518 -vt 3.963765 0.286613 -vt 3.963765 0.134518 -vt 3.991477 0.134518 -vt 3.991477 0.286613 -vt 3.987690 0.286613 -vt 3.987690 0.134518 -vt 3.983886 0.286613 -vt 3.983886 0.134518 -vt 3.980889 0.286613 -vt 3.980889 0.134518 -vt 3.977618 0.286613 -vt 3.977618 0.134518 -vt 0.688848 0.749275 -vt 0.707262 0.749275 -vt 0.707262 0.796196 -vt 0.688848 0.796196 -vt 0.707262 0.821096 -vt 0.688848 0.821096 -vt 0.688848 0.687755 -vt 0.707262 0.687755 -vt 0.707262 0.713461 -vt 0.688848 0.713461 -vt 0.707262 0.749275 -vt 0.712529 0.749275 -vt 0.712529 0.796196 -vt 0.707262 0.796196 -vt 0.707262 0.796196 -vt 0.712529 0.796196 -vt 0.712529 0.821096 -vt 0.707262 0.821096 -vt 0.707262 0.687755 -vt 0.712529 0.687755 -vt 0.712529 0.713461 -vt 0.707262 0.713461 -vt 0.707262 0.713461 -vt 0.712529 0.713461 -vt 0.712529 0.749275 -vt 0.707262 0.749275 -vt 0.712529 0.821096 -vt 1.901273 0.987954 -vt 1.894390 0.809475 -vt 1.898839 0.809308 -vt 1.905721 0.987777 -vt 1.903373 0.809475 -vt 1.910255 0.987933 -vt 1.907880 0.808954 -vt 1.914763 0.987434 -vt 1.912328 0.808772 -vt 1.919212 0.987273 -vt 1.916777 0.808601 -vt 1.923660 0.987101 -vt 1.887785 0.988453 -vt 1.880903 0.810015 -vt 1.885410 0.809505 -vt 1.892292 0.987943 -vt 1.889943 0.809656 -vt 1.896825 0.988115 -vt 0.835327 0.793387 -vt 0.835327 0.820585 -vt 0.831746 0.820585 -vt 0.831746 0.793387 -vt 0.828119 0.820585 -vt 0.828119 0.793387 -vt 0.824470 0.820585 -vt 0.824470 0.793387 -vt 0.820887 0.820585 -vt 0.820887 0.793387 -vt 0.817304 0.820585 -vt 0.817304 0.793387 -vt 0.813656 0.820585 -vt 0.813656 0.793387 -vt 0.810030 0.820585 -vt 0.810030 0.793387 -vt 0.838908 0.793387 -vt 0.838908 0.820585 -vt 0.963771 0.464386 -vt 0.966829 0.510170 -vt 0.963142 0.507307 -vt 0.956692 0.465842 -vt 0.968024 0.463687 -vt 0.971978 0.514904 -vt 0.971339 0.463143 -vt 0.975459 0.514343 -vt 0.973352 0.462812 -vt 0.978725 0.509767 -vt 0.954252 0.423683 -vt 0.945634 0.424628 -vt 0.962774 0.422283 -vt 0.966228 0.421716 -vt 0.969417 0.421193 -vt 0.946255 0.386738 -vt 0.949923 0.403838 -vt 0.938767 0.405843 -vt 0.932504 0.389173 -vt 0.957710 0.384857 -vt 0.960009 0.402182 -vt 0.965586 0.383564 -vt 0.964799 0.401395 -vt 0.972329 0.382456 -vt 0.969884 0.400560 -vt 0.930994 0.364212 -vt 0.936570 0.333645 -vt 0.943846 0.369533 -vt 0.931040 0.379851 -vt 0.950086 0.315819 -vt 0.955052 0.362291 -vt 0.963966 0.306471 -vt 0.964760 0.358704 -vt 0.976111 0.317948 -vt 0.972943 0.361369 -vt 0.974988 0.462717 -vt 0.981663 0.505121 -vt 0.972942 0.421304 -vt 0.974470 0.399545 -vt 0.980256 0.366925 -vt 0.977774 0.381266 -vt 0.985764 0.339373 -vt 0.966829 0.510170 -vt 0.964615 0.512998 -vt 0.960727 0.510219 -vt 0.963142 0.507307 -vt 0.971978 0.514904 -vt 0.971030 0.518012 -vt 0.964615 0.512998 -vt 0.966829 0.510170 -vt 0.971978 0.514904 -vt 0.978725 0.509767 -vt 0.979438 0.515266 -vt 0.975659 0.517915 -vt 0.975459 0.514343 -vt 0.956692 0.465842 -vt 0.953100 0.466601 -vt 0.941483 0.425665 -vt 0.945634 0.424628 -vt 0.972942 0.421304 -vt 0.977648 0.421732 -vt 0.978737 0.462523 -vt 0.974988 0.462717 -vt 0.938767 0.405843 -vt 0.935117 0.407189 -vt 0.928188 0.391026 -vt 0.932504 0.389173 -vt 0.974470 0.399545 -vt 0.978161 0.399738 -vt 0.977648 0.421732 -vt 0.972942 0.421304 -vt 0.931040 0.379851 -vt 0.926916 0.381387 -vt 0.926746 0.365415 -vt 0.930994 0.364212 -vt 0.930994 0.364212 -vt 0.926746 0.365415 -vt 0.933515 0.332831 -vt 0.936570 0.333645 -vt 0.936570 0.333645 -vt 0.933515 0.332831 -vt 0.948466 0.313374 -vt 0.950086 0.315819 -vt 0.950086 0.315819 -vt 0.948466 0.313374 -vt 0.962437 0.303992 -vt 0.963966 0.306471 -vt 0.976111 0.317948 -vt 0.978359 0.315358 -vt 0.990410 0.338499 -vt 0.985764 0.339373 -vt 0.980256 0.366925 -vt 0.984066 0.367261 -vt 0.981269 0.381445 -vt 0.977774 0.381266 -vt 0.963966 0.306471 -vt 0.965424 0.303475 -vt 0.978359 0.315358 -vt 0.976111 0.317948 -vt 0.981663 0.505121 -vt 0.982307 0.509582 -vt 0.979438 0.515266 -vt 0.978725 0.509767 -vt 0.985764 0.339373 -vt 0.990410 0.338499 -vt 0.984066 0.367261 -vt 0.980256 0.366925 -vt 0.932504 0.389173 -vt 0.928188 0.391026 -vt 0.926916 0.381387 -vt 0.931040 0.379851 -vt 0.945634 0.424628 -vt 0.941483 0.425665 -vt 0.935117 0.407189 -vt 0.938767 0.405843 -vt 0.977774 0.381266 -vt 0.981269 0.381445 -vt 0.978161 0.399738 -vt 0.974470 0.399545 -vt 0.959462 0.507483 -vt 0.956592 0.511103 -vt 0.945891 0.513500 -vt 0.941512 0.510082 -vt 0.950077 0.517329 -vt 0.886744 0.406160 -vt 0.876822 0.376070 -vt 0.926916 0.381387 -vt 0.928188 0.391026 -vt 0.933515 0.332831 -vt 0.906951 0.304459 -vt 0.921929 0.299465 -vt 0.931160 0.313322 -vt 0.926746 0.365415 -vt 0.926916 0.381387 -vt 0.876822 0.376070 -vt 0.882738 0.329557 -vt 0.933515 0.332831 -vt 0.926746 0.365415 -vt 0.882738 0.329557 -vt 0.906951 0.304459 -vt 0.565573 0.782724 -vt 0.526626 0.783518 -vt 0.500841 0.780471 -vt 0.631173 0.764652 -vt 0.630058 0.699236 -vt 0.596866 0.612516 -vt 0.637337 0.616972 -vt 0.641785 0.651360 -vt 0.500841 0.780471 -vt 0.489568 0.620042 -vt 0.630058 0.699236 -vt 0.631173 0.764652 -vt 0.489568 0.620042 -vt 0.504547 0.612629 -vt 0.532640 0.607381 -vt 0.596866 0.612516 -vt 0.500841 0.780471 -vt 0.462399 0.748874 -vt 0.450798 0.706790 -vt 0.489568 0.620042 -vt 0.450798 0.706790 -vt 0.454897 0.674918 -vt 0.464575 0.645515 -vt 0.489568 0.620042 -vt 3.833514 0.653935 -vt 3.833570 0.641126 -vt 3.896566 0.641971 -vt 3.896511 0.654781 -vt 3.871963 0.679861 -vt 3.858635 0.680069 -vt 0.896495 0.654765 -vt 0.833525 0.653920 -vt 0.847321 0.620414 -vt 0.882991 0.620893 -vt 0.858914 0.615670 -vt 0.871440 0.615838 -vt 0.671031 0.894589 -vt 0.676401 0.986658 -vt 1.058323 0.502256 -vt 1.063613 0.482216 -vt 0.993903 0.691436 -vt 0.979362 0.691436 -vt 0.979348 0.689810 -vt 0.993911 0.689810 -vt 0.993911 0.689810 -vt 0.979348 0.689810 -vt 0.979067 0.658221 -vt 0.993909 0.658221 -vt 1.862950 0.741047 -vt 1.901950 0.723781 -vt 1.899748 0.711405 -vt 1.855536 0.734860 -vt 1.942279 0.723767 -vt 1.944343 0.711333 -vt 1.981343 0.741059 -vt 1.989631 0.734959 -vt 1.853947 0.974376 -vt 1.850019 0.969849 -vt 1.849805 0.970333 -vt 1.853430 0.974539 -vt 1.844046 0.969394 -vt 1.844269 0.970059 -vt 1.839486 0.973242 -vt 1.840070 0.973577 -vt 1.838931 0.979200 -vt 1.839588 0.978994 -vt 1.842796 0.983726 -vt 1.843067 0.983246 -vt 1.848811 0.984156 -vt 1.848652 0.983663 -vt 1.853443 0.980298 -vt 1.852944 0.980064 -vt 0.945508 0.023291 -vt 0.942880 0.023291 -vt 0.942142 0.289169 -vt 0.945365 0.289169 -vt 0.953900 0.023291 -vt 0.948675 0.023291 -vt 0.948937 0.289169 -vt 0.953900 0.289169 -vt 3.884426 0.003712 -vt 3.882265 0.003712 -vt 3.882265 0.306753 -vt 3.884426 0.306753 -vt 3.891725 0.003712 -vt 3.887573 0.003712 -vt 3.887573 0.306753 -vt 3.891725 0.306753 -vt 1.973814 0.134518 -vt 1.970027 0.134518 -vt 1.970027 0.286613 -vt 1.973814 0.286613 -vt 1.967029 0.134518 -vt 1.967029 0.286613 -vt 1.963765 0.134518 -vt 1.963765 0.286613 -vt 1.991477 0.134518 -vt 1.987690 0.134518 -vt 1.987690 0.286613 -vt 1.991477 0.286613 -vt 1.983886 0.134518 -vt 1.983886 0.286613 -vt 1.980889 0.134518 -vt 1.980889 0.286613 -vt 1.977618 0.134518 -vt 1.977618 0.286613 -vt 2.672500 0.806611 -vt 2.671067 0.801549 -vt 2.457033 0.801549 -vt 2.458466 0.806611 -vt 2.671087 0.796454 -vt 2.457013 0.796454 -vt 2.672521 0.811706 -vt 2.458446 0.811706 -vt 3.945508 0.023291 -vt 3.945365 0.289169 -vt 3.942142 0.289169 -vt 3.942880 0.023291 -vt 3.953900 0.023291 -vt 3.953900 0.289169 -vt 3.948937 0.289169 -vt 3.948675 0.023291 -vt 0.884426 0.003712 -vt 0.884426 0.306753 -vt 0.882265 0.306753 -vt 0.882265 0.003712 -vt 0.891725 0.003712 -vt 0.891725 0.306753 -vt 0.887573 0.306753 -vt 0.887573 0.003712 -vt 2.973814 0.134518 -vt 2.973814 0.286613 -vt 2.970027 0.286613 -vt 2.970027 0.134518 -vt 2.967030 0.286613 -vt 2.967030 0.134518 -vt 2.963765 0.286613 -vt 2.963765 0.134518 -vt 2.991477 0.134518 -vt 2.991477 0.286613 -vt 2.987690 0.286613 -vt 2.987690 0.134518 -vt 2.983886 0.286613 -vt 2.983886 0.134518 -vt 2.980889 0.286613 -vt 2.980889 0.134518 -vt 2.977618 0.286613 -vt 2.977618 0.134518 -vt 1.672500 0.806611 -vt 1.458466 0.806611 -vt 1.457033 0.801549 -vt 1.671067 0.801549 -vt 1.457013 0.796454 -vt 1.671087 0.796454 -vt 1.672521 0.811706 -vt 1.458446 0.811706 -vn 0.0000 -0.1792 -0.9838 -vn 0.0000 -0.1793 -0.9838 -vn -0.0000 0.1792 0.9838 -vn 0.9944 0.0999 0.0353 -vn 0.9977 0.0649 -0.0215 -vn 0.9997 0.0130 -0.0182 -vn 0.9945 -0.0659 -0.0808 -vn 0.9989 0.0044 -0.0465 -vn 0.9991 0.0175 -0.0395 -vn -0.9944 0.0999 0.0353 -vn -0.9977 0.0649 -0.0215 -vn -0.9997 0.0130 -0.0182 -vn -0.9945 -0.0659 -0.0808 -vn -0.9989 0.0044 -0.0465 -vn -0.9991 0.0175 -0.0395 -vn 0.0000 0.9838 -0.1792 -vn 0.8539 -0.0933 -0.5120 -vn -0.0001 -0.1789 -0.9839 -vn 0.8444 0.0810 -0.5296 -vn 0.8444 0.0809 -0.5296 -vn -0.0034 -0.0721 0.9974 -vn 0.9999 0.0106 -0.0012 -vn 0.0034 0.0721 -0.9974 -vn -0.9999 -0.0106 0.0012 -vn 0.0000 -0.9838 0.1792 -vn 1.0000 0.0000 0.0000 -vn -1.0000 0.0000 0.0000 -vn -0.9962 -0.0864 0.0133 -vn 0.9962 0.0864 -0.0133 -vn 0.9659 -0.2546 0.0464 -vn 0.0000 0.1793 0.9838 -vn -0.9659 -0.2546 0.0464 -vn -0.7071 -0.6957 0.1267 -vn -0.2588 -0.9503 0.1731 -vn -0.2588 0.9503 -0.1731 -vn -0.7071 0.6957 -0.1267 -vn -0.9659 0.2546 -0.0464 -vn 0.9659 0.2546 -0.0464 -vn 0.7071 -0.6957 0.1267 -vn 0.2588 -0.9503 0.1731 -vn 0.2588 0.9503 -0.1731 -vn 0.7071 0.6957 -0.1267 -vn 0.6533 -0.1395 0.7441 -vn 0.6533 0.3930 0.6471 -vn 0.9239 -0.3765 0.0686 -vn 0.9239 0.3765 -0.0686 -vn 0.0358 -0.2361 0.9711 -vn 0.0357 -0.2361 0.9711 -vn 0.0865 -0.8509 0.5181 -vn 0.0864 -0.8510 0.5181 -vn 0.0865 -0.9673 -0.2384 -vn 0.0358 -0.5170 -0.8552 -vn -0.0358 0.2361 -0.9711 -vn -0.0865 0.8510 -0.5181 -vn -0.0865 0.9673 0.2384 -vn -0.0358 0.5170 0.8552 -vn -0.9956 -0.0926 0.0142 -vn -0.9956 -0.0925 0.0142 -vn -0.9437 0.0593 0.3255 -vn -0.4395 0.1610 0.8837 -vn -0.4396 0.1610 0.8837 -vn -0.4396 -0.1610 -0.8837 -vn -0.9437 -0.0593 -0.3255 -vn -0.8906 0.4474 -0.0815 -vn -0.4530 -0.8886 0.0724 -vn 0.8906 -0.4474 0.0815 -vn -0.9097 0.4098 -0.0673 -vn -0.0294 -0.2356 -0.9714 -vn -0.0295 -0.2356 -0.9714 -vn 0.0496 -0.0823 -0.9954 -vn 0.0499 -0.0821 -0.9954 -vn 0.0551 -0.0729 -0.9958 -vn 0.0219 -0.1369 -0.9903 -vn -0.0675 -0.3073 -0.9492 -vn -0.0908 -0.3505 -0.9321 -vn -0.8539 -0.0933 -0.5120 -vn 0.0001 -0.1789 -0.9839 -vn -0.8444 0.0810 -0.5296 -vn -0.8444 0.0809 -0.5296 -vn 0.0034 -0.0721 0.9974 -vn -0.9999 0.0106 -0.0012 -vn -0.0034 0.0721 -0.9974 -vn 0.9999 -0.0106 0.0012 -vn 0.9962 -0.0864 0.0133 -vn 0.9887 -0.1218 -0.0873 -vn 0.9887 -0.1217 -0.0872 -vn 0.9856 -0.1559 -0.0655 -vn 0.9856 -0.1558 -0.0655 -vn -0.9962 0.0864 -0.0133 -vn -0.0166 -0.0378 0.9991 -vn 0.0167 0.3374 0.9412 -vn 0.0474 0.6615 0.7484 -vn 0.0755 0.9959 0.0497 -vn 0.0755 0.9349 -0.3467 -vn 0.0474 0.4060 -0.9126 -vn 0.0167 0.0390 -0.9991 -vn -0.0166 -0.3363 -0.9416 -vn -0.0476 -0.6641 -0.7462 -vn -0.0720 -0.8977 -0.4348 -vn -0.0856 -0.9951 -0.0496 -vn -0.0856 -0.9342 0.3464 -vn -0.0720 -0.7255 0.6844 -vn -0.0476 -0.4091 0.9112 -vn 0.0166 0.0373 -0.9992 -vn 0.0477 0.4105 -0.9106 -vn 0.0477 0.6652 0.7452 -vn 0.0477 0.6651 0.7452 -vn -0.6533 -0.1395 0.7441 -vn -0.6533 0.3930 0.6471 -vn -0.9239 -0.3765 0.0686 -vn -0.9239 0.3765 -0.0686 -vn -0.0358 -0.2361 0.9711 -vn -0.0357 -0.2361 0.9711 -vn -0.0865 -0.8509 0.5181 -vn -0.0864 -0.8510 0.5181 -vn -0.0865 -0.9673 -0.2384 -vn -0.0358 -0.5170 -0.8552 -vn 0.0358 0.2361 -0.9711 -vn 0.0865 0.8510 -0.5181 -vn 0.0865 0.9673 0.2384 -vn 0.0358 0.5170 0.8552 -vn 0.9956 -0.0926 0.0142 -vn 0.9437 0.0593 0.3255 -vn 0.4396 0.1610 0.8837 -vn 0.4396 -0.1610 -0.8837 -vn 0.9437 -0.0593 -0.3255 -vn -0.7621 0.6423 -0.0815 -vn 0.6382 0.7665 0.0724 -vn 0.7621 -0.6423 0.0815 -vn 0.2049 0.1199 -0.9714 -vn 0.0887 -0.0219 -0.9958 -vn 0.1345 0.0338 -0.9903 -vn 0.1345 0.0339 -0.9903 -vn 0.2558 0.1831 -0.9492 -vn 0.2864 0.2216 -0.9321 -vn 0.0000 0.9934 -0.1150 -vn 0.0000 0.8434 0.5373 -vn 0.0000 0.9429 0.3332 -vn 0.0000 0.0939 -0.9956 -vn 0.0000 -0.9932 0.1163 -vn 0.0000 -0.9938 0.1111 -vn 0.0000 0.5939 -0.8045 -vn 0.0000 -0.8992 -0.4375 -vn 0.0000 0.4099 -0.9121 -vn 0.0000 -0.9838 -0.1790 -vn 0.0000 -0.3071 -0.9517 -vn 0.0000 0.8980 -0.4399 -vn 0.0000 -0.7544 -0.6565 -vn 0.0000 0.9998 0.0206 -vn 0.0000 0.9826 0.1856 -vn 0.0000 -0.1270 -0.9919 -vn 0.0000 -0.8616 0.5076 -vn 0.0000 -0.1495 0.9888 -vn 0.0000 -0.9998 0.0213 -vn 0.0000 -0.6324 -0.7747 -vn 0.0000 0.2339 0.9723 -vn 0.0000 -0.0391 0.9992 -vn 0.8197 -0.5727 -0.0082 -vn 0.7597 -0.6501 -0.0164 -vn 0.4703 -0.8816 0.0405 -vn -0.0000 -0.9926 0.1213 -vn 0.4006 -0.9109 0.0987 -vn 0.0000 -0.9980 0.0635 -vn 0.6690 0.6800 -0.3002 -vn 0.7067 0.6511 -0.2768 -vn 0.8960 0.3880 -0.2160 -vn 0.9775 0.1101 -0.1802 -vn 0.9876 0.0385 -0.1522 -vn 0.9463 -0.3136 -0.0788 -vn 0.0000 0.9347 -0.3555 -vn 0.0000 0.9403 -0.3405 -vn 0.3748 0.8697 -0.3211 -vn 0.1348 0.9134 -0.3841 -vn 0.3839 0.8929 -0.2354 -vn 0.7451 0.6335 -0.2084 -vn 0.4943 0.8181 -0.2940 -vn 0.1307 0.8932 -0.4302 -vn 0.7392 0.6373 -0.2177 -vn -0.5050 0.7994 -0.3256 -vn -0.5068 0.7980 -0.3260 -vn -0.8197 -0.5727 -0.0082 -vn -0.4704 -0.8815 0.0416 -vn -0.7597 -0.6501 -0.0164 -vn -0.4006 -0.9109 0.0987 -vn -0.6690 0.6800 -0.3002 -vn -0.8960 0.3880 -0.2160 -vn -0.7067 0.6511 -0.2768 -vn -0.9775 0.1101 -0.1802 -vn -0.9463 -0.3136 -0.0788 -vn -0.9876 0.0385 -0.1522 -vn -0.3748 0.8697 -0.3211 -vn -0.1348 0.9134 -0.3841 -vn -0.7451 0.6335 -0.2084 -vn -0.3840 0.8928 -0.2352 -vn -0.4943 0.8181 -0.2940 -vn -0.7392 0.6373 -0.2177 -vn -0.1307 0.8932 -0.4302 -vn 0.5050 0.7994 -0.3256 -vn 0.5068 0.7980 -0.3260 -vn 0.9200 -0.3895 -0.0438 -vn 0.7085 -0.7055 0.0167 -vn 0.9937 -0.0210 -0.1099 -vn 0.3860 -0.9206 0.0597 -vn 0.0000 -0.9972 0.0754 -vn -0.0000 0.9401 -0.3409 -vn 0.9362 0.3098 -0.1661 -vn 0.0000 0.9695 -0.2450 -vn -0.0000 0.9695 -0.2451 -vn -0.5050 0.7993 -0.3256 -vn 0.1308 0.8933 -0.4301 -vn -0.0000 -0.2046 -0.9789 -vn -0.0000 -0.2045 -0.9789 -vn -0.4656 -0.1810 -0.8663 -vn -0.7520 0.1019 0.6512 -vn -0.6996 0.1149 0.7053 -vn -0.9368 0.0336 0.3482 -vn 0.9219 -0.3858 -0.0358 -vn 0.7125 -0.7007 0.0373 -vn 0.9938 -0.0197 -0.1090 -vn 0.3893 -0.9164 0.0926 -vn -0.0000 -0.9935 0.1135 -vn 0.9394 0.3025 -0.1612 -vn -0.0000 -0.9884 0.1517 -vn -0.0154 -0.9881 0.1530 -vn -0.0147 -0.9926 0.1203 -vn 0.0000 -0.9927 0.1203 -vn -0.0000 -0.9835 0.1807 -vn -0.0161 -0.9839 0.1780 -vn -0.0446 -0.9872 0.1534 -vn -0.0446 -0.9918 0.1202 -vn 0.0147 0.9975 -0.0687 -vn 0.0142 0.9925 -0.1213 -vn 0.0000 0.9925 -0.1224 -vn 0.0000 0.9976 -0.0687 -vn -0.0031 -0.9852 0.1715 -vn -0.0159 -0.9849 0.1722 -vn -0.0446 -0.9828 0.1791 -vn -0.0606 -0.9873 0.1471 -vn -0.0638 -0.9917 0.1120 -vn 0.0444 0.9967 -0.0686 -vn 0.0445 0.9917 -0.1203 -vn 0.0135 0.9835 -0.1804 -vn -0.0000 0.9841 -0.1778 -vn -0.0053 -0.9766 0.2148 -vn -0.0174 -0.9773 0.2109 -vn -0.0174 -0.9785 0.2055 -vn -0.0052 -0.9793 0.2025 -vn -0.0446 -0.9841 0.1716 -vn -0.0563 -0.9827 0.1767 -vn -0.0593 -0.9865 0.1525 -vn -0.0679 -0.9923 0.1038 -vn 0.0635 0.9961 -0.0605 -vn 0.0605 0.9916 -0.1140 -vn 0.0446 0.9828 -0.1791 -vn 0.0136 0.9824 -0.1862 -vn -0.0031 0.9824 -0.1869 -vn -0.0446 -0.9773 0.2069 -vn -0.0446 -0.9809 0.1893 -vn -0.0166 -0.9823 0.1868 -vn -0.0553 -0.9836 0.1716 -vn -0.0526 -0.9833 0.1742 -vn 0.8962 0.0795 0.4364 -vn 0.8986 0.0786 0.4316 -vn 0.8256 0.1011 0.5551 -vn 0.0676 0.9963 -0.0525 -vn 0.0593 0.9904 -0.1252 -vn 0.0563 0.9826 -0.1767 -vn 0.0446 0.9814 -0.1865 -vn 0.0181 0.9766 -0.2141 -vn 0.0227 0.9655 -0.2596 -vn 0.0159 0.9680 -0.2503 -vn 0.0045 0.9802 -0.1978 -vn -0.0589 -0.9748 0.2154 -vn -0.0560 -0.9796 0.1932 -vn -0.0508 -0.9839 0.1716 -vn 0.9875 0.0283 0.1553 -vn 0.0526 0.9830 -0.1759 -vn 0.0553 0.9809 -0.1864 -vn 0.0446 0.9732 -0.2254 -vn 0.0445 0.9635 -0.2641 -vn -0.0565 -0.9730 0.2236 -vn -0.0519 -0.9800 0.1919 -vn 0.0508 0.9812 -0.1864 -vn 0.0559 0.9718 -0.2292 -vn 0.0587 0.9604 -0.2723 -vn 0.9624 -0.0487 -0.2673 -vn 0.9648 -0.0471 -0.2588 -vn 0.0519 0.9733 -0.2236 -vn 0.0562 0.9582 -0.2804 -vn -0.5676 -0.1476 -0.8100 -vn -0.8987 -0.0786 -0.4316 -vn -0.9924 -0.0221 -0.1211 -vn -0.9841 -0.0319 -0.1749 -vn -0.9835 -0.0324 -0.1781 -vn -0.0611 -0.9745 0.2161 -vn 0.0228 0.9610 -0.2757 -vn -0.0625 -0.9723 0.2253 -vn 0.0609 0.9601 -0.2730 -vn 0.0623 0.9574 -0.2820 -vn -0.0032 -0.9834 0.1815 -vn 0.0162 0.9577 -0.2872 -vn -0.0001 -0.1787 -0.9839 -vn -0.0000 -0.1790 -0.9838 -vn 0.2043 -0.9714 0.1206 -vn 0.2062 -0.9691 0.1355 -vn 0.2028 -0.9703 0.1316 -vn 0.2023 -0.9725 0.1157 -vn 0.2064 -0.9704 0.1254 -vn 0.2098 -0.9674 0.1418 -vn 0.9793 0.1992 -0.0363 -vn 0.9689 0.2231 0.1071 -vn 0.9685 0.2235 0.1098 -vn -0.1963 0.9684 -0.1536 -vn -0.1984 0.9667 -0.1615 -vn -0.1946 0.9674 -0.1621 -vn -0.1918 0.9688 -0.1569 -vn -0.1950 0.9680 -0.1577 -vn -0.2012 0.9675 -0.1532 -vn -0.2015 0.9679 -0.1504 -vn 0.2095 -0.9478 0.2403 -vn 0.2030 -0.9475 0.2469 -vn 0.2036 -0.9594 0.1952 -vn 0.2103 -0.9583 0.1935 -vn -0.2020 0.9618 -0.1846 -vn -0.2019 0.9594 -0.1968 -vn -0.1990 0.9601 -0.1966 -vn -0.1989 0.9625 -0.1847 -vn 0.8157 0.2651 0.5142 -vn 0.8863 0.2565 0.3856 -vn 0.8856 0.2566 0.3871 -vn 0.2161 -0.9480 0.2338 -vn 0.2170 -0.9595 0.1794 -vn -0.1960 0.9606 -0.1969 -vn -0.1958 0.9638 -0.1811 -vn 0.2091 -0.9666 0.1482 -vn 0.2034 -0.9683 0.1448 -vn -0.2018 0.9663 -0.1599 -vn 0.2144 -0.9649 0.1518 -vn -0.1887 0.9686 -0.1620 -vn 0.0194 -0.9850 0.1714 -vn -0.0243 -0.9816 0.1893 -vn -0.0351 -0.9805 0.1935 -vn 0.0195 -0.9851 0.1708 -vn 0.0303 0.9835 -0.1786 -vn 0.0432 0.9832 -0.1771 -vn 0.0000 0.9836 -0.1804 -vn 0.8843 -0.2718 0.3796 -vn 0.8851 -0.2730 0.3770 -vn 0.7757 -0.1504 0.6130 -vn 0.7694 -0.1448 0.6222 -vn 0.9213 -0.3842 -0.0598 -vn 0.9219 -0.3835 -0.0547 -vn 0.1710 -0.0770 -0.9823 -vn -0.2475 -0.0947 -0.9642 -vn -0.2487 -0.0949 -0.9639 -vn 0.2026 -0.0813 -0.9759 -vn -0.0000 -0.1442 -0.9895 -vn -0.6983 -0.1037 -0.7083 -vn -0.7022 -0.1031 -0.7044 -vn -0.0000 -0.1442 -0.9896 -vn 0.6740 -0.0671 0.7357 -vn 0.8315 -0.4074 -0.3777 -vn 0.3503 -0.1008 -0.9312 -vn 0.2032 0.9615 -0.1848 -vn 0.2145 0.9594 -0.1833 -vn 0.1479 0.9702 -0.1919 -vn 0.1350 0.9718 -0.1935 -vn 0.0864 0.9783 -0.1884 -vn 0.0784 0.9794 -0.1859 -vn -0.2904 -0.9414 0.1717 -vn -0.2905 -0.9414 0.1717 -vn -0.1809 -0.9647 0.1917 -vn -0.1928 -0.9627 0.1896 -vn -0.1140 -0.9728 0.2019 -vn -0.0992 -0.9740 0.2039 -vn 0.2978 0.9392 -0.1709 -vn 0.9360 0.3463 -0.0631 -vn 0.9995 -0.0324 0.0059 -vn 0.3827 0.9089 -0.1656 -vn 0.3827 -0.9089 0.1656 -vn 0.9469 0.3020 0.1101 -vn 0.9993 -0.0186 0.0309 -vn 0.9994 -0.0186 0.0308 -vn 0.8668 0.4564 0.2010 -vn 0.6734 0.6679 0.3168 -vn 0.5930 0.7275 0.3451 -vn 0.3440 0.8484 0.4024 -vn 0.2982 0.8624 0.4091 -vn -0.0000 0.9035 0.4286 -vn 0.9361 0.3503 0.0302 -vn 0.9999 -0.0040 0.0160 -vn 0.9056 0.4218 0.0451 -vn 0.7095 0.6984 0.0943 -vn 0.6699 0.7358 0.0994 -vn 0.3804 0.9165 0.1238 -vn 0.3539 0.9269 0.1252 -vn -0.0000 0.9910 0.1339 -vn 0.9250 0.3749 -0.0620 -vn 1.0000 -0.0005 0.0010 -vn 1.0000 -0.0005 0.0009 -vn 0.9233 0.3789 -0.0627 -vn 0.7082 0.6968 -0.1137 -vn 0.7059 0.6991 -0.1140 -vn 0.3834 0.9115 -0.1487 -vn 0.3818 0.9122 -0.1488 -vn 0.0000 0.9870 -0.1610 -vn 0.1951 -0.9621 0.1903 -vn 0.0000 -0.9810 0.1941 -vn 0.0000 -0.9810 0.1940 -vn 0.5516 -0.8195 0.1557 -vn 0.5376 -0.7017 -0.4676 -vn 0.3682 -0.7906 -0.4893 -vn 0.8315 -0.5466 0.0996 -vn 0.6258 0.3869 0.6773 -vn 0.6774 0.1319 0.7237 -vn 0.4790 0.6031 0.6379 -vn 0.2592 0.7475 0.6116 -vn -0.0000 0.7982 0.6023 -vn 0.2592 -0.4838 0.8359 -vn -0.0000 -0.5345 0.8452 -vn 0.4790 -0.3393 0.8096 -vn 0.6258 -0.1232 0.7702 -vn -0.9232 -0.3599 0.1346 -vn -0.9202 -0.3672 0.1357 -vn -0.9967 0.0102 0.0804 -vn -0.9967 0.0187 0.0791 -vn -0.7081 -0.6823 0.1818 -vn -0.7038 -0.6866 0.1824 -vn -0.3837 -0.8984 0.2135 -vn -0.3807 -0.8997 0.2136 -vn 0.0000 -0.9745 0.2246 -vn 0.0000 -0.9748 0.2229 -vn -0.3787 0.9240 -0.0535 -vn -0.3818 0.9227 -0.0533 -vn -0.0000 0.9979 -0.0644 -vn -0.7010 0.7128 -0.0226 -vn -0.7054 0.7085 -0.0219 -vn -0.9182 0.3953 0.0240 -vn -0.9213 0.3880 0.0250 -vn 0.8413 0.2013 -0.5017 -vn 0.7821 -0.1569 -0.6031 -vn 0.8184 -0.0436 -0.5730 -vn 0.8229 0.3371 -0.4573 -vn 0.7202 0.5883 -0.3678 -vn 0.6498 0.6848 -0.3298 -vn 0.4114 0.8766 -0.2495 -vn 0.3501 0.9064 -0.2361 -vn -0.0000 0.9792 -0.2030 -vn 0.2071 -0.6673 -0.7154 -vn -0.0000 -0.6926 -0.7213 -vn 0.4172 -0.5825 -0.6976 -vn 0.6203 -0.4184 -0.6635 -vn 0.6735 -0.3531 -0.6494 -vn 0.9262 0.3644 -0.0965 -vn 0.9985 -0.0174 -0.0518 -vn 0.9986 -0.0017 -0.0536 -vn 0.9207 0.3778 -0.0981 -vn 0.7110 0.6902 -0.1347 -vn 0.7031 0.6980 -0.1356 -vn 0.3855 0.9087 -0.1603 -vn 0.3799 0.9110 -0.1606 -vn -0.0000 0.9856 -0.1693 -vn 0.3776 -0.9244 0.0547 -vn -0.0000 -0.9980 0.0634 -vn 0.3831 -0.9221 0.0545 -vn 0.6998 -0.7137 0.0300 -vn 0.7077 -0.7059 0.0291 -vn 0.9183 -0.3958 -0.0073 -vn 0.9239 -0.3825 -0.0089 -vn -0.9961 -0.0867 0.0133 -vn -0.9978 -0.0661 0.0102 -vn -0.9978 -0.0658 0.0101 -vn -0.1233 0.1705 -0.9776 -vn -0.1523 0.2208 -0.9634 -vn -0.0231 -0.1539 -0.9878 -vn -0.0228 -0.1570 -0.9873 -vn -0.3348 0.4709 -0.8162 -vn -0.3835 0.5223 -0.7616 -vn -0.5382 0.6789 -0.4994 -vn -0.5575 0.6972 -0.4507 -vn -0.6150 0.7794 -0.1199 -vn -0.5281 0.8051 0.2699 -vn -0.5505 0.8062 0.2168 -vn -0.3156 0.7038 0.6364 -vn -0.3631 0.7368 0.5704 -vn -0.1133 0.4609 0.8802 -vn -0.1363 0.4997 0.8554 -vn -0.0211 0.1511 0.9883 -vn -0.0209 0.1492 0.9886 -vn -0.0599 -0.1890 0.9802 -vn -0.0766 -0.2392 0.9680 -vn -0.1901 -0.5504 0.8130 -vn -0.2160 -0.6149 0.7584 -vn -0.2929 -0.8311 0.4728 -vn -0.2972 -0.8469 0.4409 -vn -0.3157 -0.9378 0.1442 -vn -0.3157 -0.9378 0.1443 -vn -0.2929 -0.9347 -0.2012 -vn -0.2972 -0.9402 -0.1661 -vn -0.1901 -0.7693 -0.6100 -vn -0.2160 -0.8144 -0.5385 -vn -0.0611 -0.4773 -0.8766 -vn -0.0767 -0.5190 -0.8513 -vn 0.6292 0.4847 -0.6077 -vn 0.5871 0.7004 -0.4059 -vn 0.6222 0.6555 0.4281 -vn 0.6295 0.4441 0.6375 -vn -0.9984 -0.0568 0.0024 -vn -0.9984 -0.0569 0.0024 -vn -0.9984 -0.0435 0.0359 -vn -0.9985 -0.0431 0.0349 -vn -0.9983 -0.0385 0.0431 -vn -0.9983 -0.0388 0.0435 -vn -0.9979 -0.0634 0.0122 -vn -0.9978 -0.0658 0.0125 -vn -0.9935 -0.1129 0.0174 -vn -0.9979 -0.0641 0.0074 -vn -0.9978 -0.0665 0.0079 -vn -0.9983 -0.0497 -0.0295 -vn -0.9983 -0.0500 -0.0298 -vn -0.9966 -0.0667 -0.0485 -vn -0.9966 -0.0664 -0.0483 -vn -0.9941 -0.0876 -0.0633 -vn -0.9942 -0.0872 -0.0631 -vn -0.9873 -0.1391 -0.0761 -vn -0.9874 -0.1386 -0.0765 -vn -0.9891 -0.1378 -0.0517 -vn -0.9890 -0.1385 -0.0522 -vn -0.9946 -0.1032 -0.0123 -vn -0.9945 -0.1035 -0.0129 -vn 0.9949 0.0988 -0.0179 -vn 0.9950 0.0987 -0.0179 -vn 0.9949 0.0996 -0.0126 -vn 0.9927 0.1148 -0.0378 -vn 0.9927 0.1148 -0.0372 -vn 0.9893 0.1390 -0.0451 -vn 0.9894 0.1380 -0.0458 -vn 0.9893 0.1389 -0.0451 -vn 0.9907 0.1344 -0.0216 -vn 0.9907 0.1341 -0.0215 -vn 0.9941 0.1073 -0.0165 -vn 0.9907 0.1347 -0.0198 -vn 0.9907 0.1343 -0.0198 -vn 0.9893 0.1461 0.0012 -vn 0.9894 0.1454 0.0022 -vn 0.9927 0.1209 0.0015 -vn 0.9927 0.1206 0.0009 -vn 0.0327 -0.2277 0.9732 -vn -0.0004 0.1569 0.9876 -vn 0.0003 0.1482 0.9890 -vn -0.0326 0.5087 0.8603 -vn -0.0326 0.5086 0.8604 -vn -0.0588 0.7976 0.6003 -vn -0.0588 0.7970 0.6012 -vn -0.0732 0.9682 0.2394 -vn -0.0729 0.9660 0.2481 -vn -0.0771 0.9854 -0.1516 -vn -0.0732 0.8515 -0.5193 -vn -0.0730 0.8468 -0.5270 -vn -0.0588 0.5804 -0.8122 -vn -0.0588 0.5795 -0.8129 -vn -0.0326 0.2266 -0.9734 -vn -0.0004 -0.1472 -0.9891 -vn 0.0004 -0.1559 -0.9878 -vn 0.0327 -0.5096 -0.8598 -vn 0.0610 -0.7961 -0.6020 -vn 0.0804 -0.9656 -0.2471 -vn 0.0874 -0.9846 0.1514 -vn 0.0804 -0.8467 0.5259 -vn 0.0610 -0.5784 0.8134 -vn -0.0029 0.1489 0.9888 -vn 0.6889 -0.1066 0.7170 -vn 0.6661 0.1776 0.7244 -vn 0.7087 -0.3739 0.5983 -vn 0.7225 -0.5749 0.3840 -vn 0.7274 -0.6782 0.1043 -vn 0.7225 -0.6637 -0.1934 -vn 0.7087 -0.5367 -0.4579 -vn 0.6883 -0.3224 -0.6498 -vn -0.0001 -0.1505 -0.9886 -vn 0.6674 -0.0506 -0.7430 -vn -0.0328 0.2281 -0.9731 -vn 0.6304 0.2338 -0.7403 -vn -0.0587 0.5797 -0.8127 -vn 0.6292 0.4846 -0.6077 -vn -0.0730 0.8492 -0.5230 -vn 0.5871 0.7004 -0.4058 -vn 0.5708 0.8115 -0.1249 -vn -0.0730 0.9671 0.2436 -vn 0.5695 0.8047 0.1678 -vn -0.0588 0.7971 0.6010 -vn 0.6222 0.6555 0.4280 -vn -0.0358 0.5093 0.8599 -vn 0.0774 0.1839 -0.9799 -vn 0.0260 -0.1509 -0.9882 -vn 0.0258 -0.1495 -0.9884 -vn 0.1040 0.2455 -0.9638 -vn 0.2593 0.5127 -0.8185 -vn 0.3094 0.5759 -0.7567 -vn 0.4486 0.7407 -0.5002 -vn 0.4683 0.7617 -0.4477 -vn 0.5205 0.8439 -0.1298 -vn 0.4486 0.8567 0.2545 -vn 0.4683 0.8611 0.1981 -vn 0.2593 0.7350 0.6265 -vn 0.3093 0.7767 0.5486 -vn 0.0774 0.4699 0.8793 -vn 0.1040 0.5238 0.8455 -vn 0.0259 0.1531 0.9879 -vn 0.0259 0.1544 0.9877 -vn 0.1267 -0.1699 0.9773 -vn 0.1554 -0.2192 0.9632 -vn 0.3181 -0.4943 0.8090 -vn 0.3529 -0.5528 0.7549 -vn 0.4547 -0.7559 0.4710 -vn 0.4598 -0.7700 0.4423 -vn 0.4841 -0.8648 0.1330 -vn 0.4842 -0.8648 0.1330 -vn 0.4548 -0.8625 -0.2221 -vn 0.4598 -0.8674 -0.1905 -vn 0.3180 -0.7146 -0.6230 -vn 0.3529 -0.7541 -0.5539 -vn 0.1267 -0.4557 -0.8811 -vn 0.1555 -0.4985 -0.8529 -vn 0.8660 0.4919 -0.0896 -vn 0.5000 0.8520 -0.1552 -vn 0.0000 0.9838 -0.1793 -vn 0.5000 -0.8520 0.1552 -vn 0.4768 0.4204 0.7720 -vn 0.4767 0.4204 0.7720 -vn 0.5505 0.1496 0.8213 -vn 0.2753 0.6187 0.7359 -vn 0.0000 0.6912 0.7226 -vn 0.2753 -0.3194 0.9068 -vn -0.0000 -0.3920 0.9200 -vn 0.4768 -0.1212 0.8706 -vn 0.0000 0.9838 -0.1791 -vn 0.2706 0.7695 0.5785 -vn -0.0000 0.7993 0.6010 -vn -0.5120 0.0164 -0.8588 -vn 0.4238 0.4055 -0.8099 -vn 0.4278 0.4065 -0.8073 -vn 0.9216 0.3863 0.0369 -vn 0.9216 0.3863 0.0368 -vn -0.4064 -0.4012 0.8209 -vn -0.4064 -0.4013 0.8209 -vn -0.9326 -0.2755 0.2330 -vn -0.8821 -0.4710 0.0106 -vn -0.4229 -0.7463 -0.5140 -vn 0.9315 0.2618 -0.2524 -vn -0.4553 0.4941 0.7406 -vn -0.4553 0.4941 0.7407 -vn -0.0000 0.1520 0.9884 -vn -0.0000 -0.5914 0.8064 -vn 0.0000 -0.9884 0.1520 -vn 0.0000 -0.8064 -0.5914 -vn 0.0000 -0.1520 -0.9884 -vn 0.0000 0.5914 -0.8064 -vn 0.0000 0.9884 -0.1520 -vn -0.0000 0.8064 0.5914 -vn -0.0030 -0.2387 0.9711 -vn -0.0029 -0.2390 0.9710 -vn -0.0031 -0.2386 0.9711 -vn -0.0059 -0.8554 0.5179 -vn -0.0059 -0.8554 0.5180 -vn -0.0057 -0.9714 -0.2373 -vn -0.0059 -0.9715 -0.2369 -vn -0.0059 -0.9715 -0.2368 -vn -0.0059 -0.9715 -0.2370 -vn -0.0031 -0.5195 -0.8545 -vn -0.0030 -0.5194 -0.8545 -vn 0.0040 0.2388 -0.9711 -vn 0.0040 0.2387 -0.9711 -vn 0.0114 0.8554 -0.5178 -vn 0.0114 0.8555 -0.5177 -vn 0.0113 0.8554 -0.5178 -vn 0.0116 0.9714 0.2372 -vn 0.0114 0.9715 0.2368 -vn 0.0114 0.9715 0.2369 -vn 0.0040 0.5195 0.8544 -vn 0.0039 0.5196 0.8544 -vn 0.0038 0.5198 0.8543 -vn 0.0040 0.5194 0.8545 -vn -0.5000 0.0374 -0.8652 -vn -0.5000 -0.0373 0.8652 -vn -0.5000 -0.0374 0.8652 -vn 0.6385 0.7592 -0.1260 -vn -0.2118 -0.2181 -0.9527 -vn -0.5267 -0.6034 -0.5988 -vn 0.6331 0.7545 -0.1727 -vn 0.0371 0.0072 0.9993 -vn -0.3758 -0.4743 0.7961 -vn -0.5267 -0.6033 -0.5988 -vn 0.6092 -0.7909 -0.0581 -vn -0.4221 0.5423 -0.7264 -vn -0.1468 0.1824 -0.9722 -vn 0.6104 -0.7917 0.0240 -vn -0.4222 0.5423 -0.7264 -vn -0.3940 0.5200 0.7579 -vn -0.0558 0.0831 0.9950 -vn -0.1469 0.1824 -0.9722 -vn -0.5000 0.4249 -0.7546 -vn -0.5000 -0.4249 0.7547 -vn -0.5000 -0.4249 0.7546 -vn -0.5000 -0.4248 0.7546 -vn 0.8194 -0.5640 0.1027 -vn 0.5794 -0.5255 -0.6230 -vn 0.5794 -0.5256 -0.6230 -vn 0.8194 -0.5640 0.1028 -vn -0.5794 0.2721 -0.7683 -vn -0.8194 0.5640 -0.1028 -vn -0.5794 0.5255 0.6230 -vn -0.5794 0.5256 0.6230 -vn 0.5794 -0.2721 0.7683 -vn 0.9999 -0.0025 -0.0139 -vn 0.7750 -0.1133 -0.6217 -vn 0.7152 -0.1253 -0.6876 -vn 0.9999 0.0026 0.0143 -vn 0.7864 0.1107 0.6078 -vn 0.6983 0.1283 0.7042 -vn 0.0817 0.9966 -0.0118 -vn 0.2007 0.9739 -0.1059 -vn 0.0646 0.8796 -0.4713 -vn 0.0647 0.8796 -0.4713 -vn 0.0504 0.8706 -0.4894 -vn 0.0505 0.8706 -0.4894 -vn -0.7071 -0.6957 0.1268 -vn -0.7071 -0.6956 0.1269 -vn 0.7071 -0.6956 0.1268 -vn 0.7071 -0.6956 0.1269 -vn 0.7071 -0.6957 0.1268 -vn -0.0075 0.1264 0.9920 -vn 0.0034 0.1143 0.9934 -vn 0.0149 0.1770 0.9841 -vn 0.0115 0.1830 0.9830 -vn -0.0157 0.1212 0.9925 -vn 0.0094 0.1775 0.9841 -vn -0.0392 0.1348 0.9901 -vn -0.0106 0.1893 0.9819 -vn -0.0698 0.1559 0.9853 -vn -0.0188 0.1960 0.9804 -vn 0.0485 0.2717 0.9612 -vn 0.0503 0.2750 0.9601 -vn 0.0806 0.3318 0.9399 -vn 0.0792 0.3290 0.9410 -vn 0.1044 0.3691 0.9235 -vn 0.1042 0.3689 0.9236 -vn 0.1053 0.3718 0.9223 -vn 0.1026 0.3743 0.9216 -vn 0.0983 0.3753 0.9217 -vn 0.1528 0.4280 0.8908 -vn 0.1261 0.3967 0.9092 -vn 0.1415 0.4131 0.8996 -vn 0.1769 0.4466 0.8771 -vn 0.1512 0.4285 0.8908 -vn 0.1755 0.4662 0.8671 -vn 0.1376 0.4504 0.8822 -vn 0.1567 0.4798 0.8633 -vn 0.1143 0.4452 0.8881 -vn 0.1284 0.4901 0.8622 -vn -0.0624 0.1552 0.9859 -vn -0.0154 0.1967 0.9804 -vn 0.0502 0.2749 0.9602 -vn 0.0811 0.3326 0.9396 -vn 0.0980 0.3792 0.9201 -vn 0.1069 0.4232 0.8997 -vn 0.1151 0.4751 0.8724 -vn -0.9408 -0.3389 0.0056 -vn -0.9409 -0.3385 0.0060 -vn -0.9410 -0.3384 0.0061 -vn -0.9810 -0.1933 -0.0167 -vn -0.9810 -0.1933 -0.0168 -vn 0.4039 -0.9080 0.1116 -vn 0.4040 -0.9080 0.1115 -vn 0.4039 -0.9080 0.1115 -vn -0.9318 0.3578 -0.0606 -vn 0.8560 -0.5080 0.0959 -vn 0.8560 -0.5080 0.0958 -vn -0.9622 0.2714 -0.0213 -vn -0.9622 0.2714 -0.0214 -vn 0.7680 -0.6256 0.1373 -vn 0.7680 -0.6256 0.1372 -vn -0.8121 0.5683 -0.1328 -vn -0.8121 0.5682 -0.1329 -vn -0.7078 0.6783 -0.1974 -vn -0.5123 0.8047 -0.2999 -vn -0.5123 0.8047 -0.3000 -vn -0.0067 0.8979 -0.4401 -vn 0.9683 -0.2492 -0.0164 -vn 0.7309 -0.6613 0.1686 -vn 0.9815 0.0655 -0.1801 -vn 0.3323 -0.9359 0.1172 -vn 0.3323 -0.9359 0.1171 -vn 0.3323 -0.9359 0.1173 -vn 0.7653 -0.6228 0.1628 -vn 0.7653 -0.6228 0.1627 -vn -0.9096 0.4100 -0.0671 -vn -0.9096 0.4102 -0.0669 -vn -0.9627 0.2690 -0.0282 -vn -0.9627 0.2690 -0.0281 -vn 0.7033 -0.6902 0.1704 -vn 0.0495 -0.0825 -0.9954 -vn 0.0551 -0.0726 -0.9958 -vn 0.0551 -0.0727 -0.9958 -vn -0.1099 -0.3837 -0.9169 -vn -0.1793 -0.5131 -0.8394 -vn -0.1793 -0.5130 -0.8394 -vn -0.1337 -0.4227 -0.8963 -vn -0.1549 -0.4704 -0.8688 -vn -0.1548 -0.4704 -0.8688 -vn 0.9969 -0.0775 -0.0138 -vn 0.9999 0.0009 0.0110 -vn 0.9999 0.0009 0.0111 -vn 0.9999 0.0009 0.0114 -vn 1.0000 -0.0040 -0.0066 -vn 0.9997 0.0111 -0.0198 -vn 0.9998 -0.0043 -0.0201 -vn 0.9998 -0.0043 -0.0202 -vn 0.9998 -0.0044 -0.0200 -vn 0.9999 -0.0034 -0.0152 -vn 0.9999 -0.0034 -0.0153 -vn 0.6304 0.2338 -0.7402 -vn 0.7087 -0.3741 0.5982 -vn 0.6883 -0.3224 -0.6499 -vn 0.5708 0.8115 -0.1248 -vn 0.5695 0.8046 0.1678 -vn 0.7225 -0.5750 0.3840 -vn 0.7087 -0.5366 -0.4580 -vn 0.7225 -0.6638 -0.1934 -vn -0.9972 -0.0744 0.0115 -vn -0.9972 -0.0743 0.0114 -vn -1.0000 0.0026 -0.0004 -vn -0.0000 -0.9854 0.1700 -vn -0.9835 -0.0325 -0.1781 -vn 0.2706 -0.5160 0.8127 -vn -0.0000 -0.5360 0.8442 -vn -0.0000 -0.9838 0.1793 -vn -0.7085 -0.7055 0.0167 -vn -0.9200 -0.3896 -0.0438 -vn -0.9937 -0.0210 -0.1099 -vn -0.3860 -0.9206 0.0597 -vn -0.9362 0.3098 -0.1661 -vn 0.5050 0.7993 -0.3256 -vn -0.1308 0.8933 -0.4301 -vn 0.0000 -0.2023 -0.9793 -vn 0.4656 -0.1810 -0.8663 -vn 0.7520 0.1019 0.6512 -vn 0.6996 0.1148 0.7052 -vn 0.9368 0.0336 0.3482 -vn -0.7125 -0.7007 0.0373 -vn -0.9219 -0.3858 -0.0358 -vn -0.9938 -0.0197 -0.1090 -vn -0.3892 -0.9165 0.0926 -vn -0.9394 0.3025 -0.1612 -vn 0.0147 -0.9926 0.1203 -vn 0.0152 -0.9882 0.1526 -vn 0.0161 -0.9839 0.1780 -vn 0.0446 -0.9918 0.1202 -vn 0.0446 -0.9872 0.1534 -vn -0.0142 0.9925 -0.1213 -vn -0.0147 0.9975 -0.0687 -vn 0.0159 -0.9849 0.1722 -vn 0.0030 -0.9852 0.1716 -vn 0.0446 -0.9828 0.1791 -vn 0.0638 -0.9917 0.1120 -vn 0.0606 -0.9873 0.1471 -vn -0.0445 0.9917 -0.1203 -vn -0.0444 0.9967 -0.0686 -vn -0.0135 0.9835 -0.1804 -vn 0.0053 -0.9766 0.2148 -vn 0.0052 -0.9793 0.2025 -vn 0.0174 -0.9785 0.2055 -vn 0.0174 -0.9773 0.2109 -vn 0.0446 -0.9841 0.1716 -vn 0.0563 -0.9827 0.1767 -vn 0.0679 -0.9923 0.1038 -vn 0.0593 -0.9865 0.1525 -vn -0.0604 0.9916 -0.1140 -vn -0.0635 0.9961 -0.0605 -vn -0.0446 0.9828 -0.1791 -vn 0.0031 0.9824 -0.1869 -vn -0.0136 0.9824 -0.1862 -vn 0.0446 -0.9809 0.1893 -vn 0.0446 -0.9773 0.2069 -vn 0.0166 -0.9823 0.1868 -vn 0.0553 -0.9836 0.1716 -vn 0.0526 -0.9833 0.1742 -vn -0.8256 0.1011 0.5551 -vn -0.8986 0.0786 0.4316 -vn -0.8962 0.0795 0.4364 -vn -0.0593 0.9904 -0.1252 -vn -0.0676 0.9963 -0.0525 -vn -0.0563 0.9826 -0.1768 -vn -0.0446 0.9814 -0.1865 -vn -0.0159 0.9680 -0.2504 -vn -0.0227 0.9655 -0.2596 -vn -0.0181 0.9766 -0.2141 -vn -0.0045 0.9802 -0.1978 -vn 0.0560 -0.9796 0.1932 -vn 0.0589 -0.9747 0.2154 -vn 0.0508 -0.9839 0.1716 -vn -0.9875 0.0283 0.1553 -vn -0.0526 0.9830 -0.1759 -vn -0.0553 0.9809 -0.1864 -vn -0.0445 0.9635 -0.2641 -vn -0.0446 0.9732 -0.2254 -vn 0.0519 -0.9800 0.1919 -vn 0.0565 -0.9730 0.2236 -vn -0.0508 0.9812 -0.1864 -vn -0.0587 0.9604 -0.2723 -vn -0.0559 0.9718 -0.2292 -vn -0.9624 -0.0487 -0.2673 -vn -0.9648 -0.0471 -0.2588 -vn -0.0562 0.9582 -0.2804 -vn -0.0519 0.9733 -0.2236 -vn 0.5676 -0.1476 -0.8100 -vn 0.8987 -0.0786 -0.4316 -vn 0.9841 -0.0319 -0.1749 -vn 0.9924 -0.0221 -0.1211 -vn 0.9835 -0.0324 -0.1781 -vn 0.0611 -0.9745 0.2161 -vn -0.0228 0.9610 -0.2757 -vn 0.0625 -0.9723 0.2254 -vn -0.0609 0.9601 -0.2730 -vn -0.0623 0.9574 -0.2820 -vn 0.0032 -0.9834 0.1815 -vn -0.0162 0.9577 -0.2872 -vn 0.0001 -0.1787 -0.9839 -vn -0.1383 -0.5229 0.8411 -vn 0.1440 0.8129 0.5642 -vn 0.0912 0.5948 0.7987 -vn -0.0884 -0.2567 0.9624 -vn -0.2028 -0.9703 0.1316 -vn -0.2062 -0.9691 0.1355 -vn -0.2043 -0.9714 0.1206 -vn -0.2023 -0.9725 0.1158 -vn -0.2098 -0.9674 0.1418 -vn -0.2064 -0.9704 0.1254 -vn -0.9685 0.2235 0.1098 -vn -0.9689 0.2231 0.1071 -vn -0.9793 0.1992 -0.0363 -vn 0.1946 0.9674 -0.1621 -vn 0.1983 0.9667 -0.1616 -vn 0.1963 0.9684 -0.1536 -vn 0.1918 0.9688 -0.1569 -vn 0.1950 0.9681 -0.1577 -vn 0.2014 0.9679 -0.1504 -vn 0.2012 0.9675 -0.1532 -vn -0.2030 -0.9476 0.2468 -vn 0.2019 0.9594 -0.1968 -vn -0.8863 0.2565 0.3856 -vn -0.8157 0.2651 0.5142 -vn -0.8856 0.2566 0.3871 -vn -0.2126 -0.9613 0.1755 -vn -0.2160 -0.9480 0.2338 -vn -0.2161 -0.9480 0.2338 -vn -0.2170 -0.9595 0.1794 -vn 0.1958 0.9638 -0.1811 -vn 0.1960 0.9606 -0.1969 -vn 0.1959 0.9607 -0.1967 -vn 0.1977 0.9635 -0.1805 -vn -0.2034 -0.9683 0.1448 -vn -0.2090 -0.9666 0.1482 -vn 0.2018 0.9663 -0.1599 -vn -0.2144 -0.9649 0.1518 -vn 0.1887 0.9686 -0.1620 -vn -0.2037 -0.9687 0.1420 -vn 0.2020 0.9641 -0.1724 -vn 0.0350 -0.9805 0.1935 -vn 0.0243 -0.9816 0.1893 -vn -0.0194 -0.9850 0.1714 -vn -0.0195 -0.9851 0.1708 -vn -0.0303 0.9835 -0.1786 -vn -0.0432 0.9832 -0.1771 -vn -0.7757 -0.1504 0.6130 -vn -0.8851 -0.2730 0.3770 -vn -0.8843 -0.2718 0.3796 -vn -0.7694 -0.1448 0.6222 -vn -0.9219 -0.3835 -0.0547 -vn -0.9213 -0.3842 -0.0598 -vn -0.1710 -0.0770 -0.9823 -vn -0.2026 -0.0813 -0.9759 -vn 0.2487 -0.0949 -0.9639 -vn 0.2475 -0.0947 -0.9642 -vn 0.7022 -0.1031 -0.7044 -vn 0.6983 -0.1037 -0.7083 -vn -0.6740 -0.0671 0.7357 -vn -0.8315 -0.4074 -0.3777 -vn -0.3503 -0.1008 -0.9312 -vn -0.2032 0.9615 -0.1848 -vn -0.1350 0.9718 -0.1935 -vn -0.1479 0.9702 -0.1919 -vn -0.2145 0.9594 -0.1833 -vn -0.0864 0.9783 -0.1884 -vn -0.0784 0.9794 -0.1859 -vn 0.1809 -0.9647 0.1917 -vn 0.2905 -0.9413 0.1717 -vn 0.1928 -0.9627 0.1896 -vn 0.1140 -0.9728 0.2019 -vn 0.0991 -0.9740 0.2038 -vn -0.2978 0.9392 -0.1709 -vn -0.9995 -0.0324 0.0059 -vn -0.9360 0.3463 -0.0631 -vn -0.3827 0.9089 -0.1656 -vn -0.3827 -0.9089 0.1656 -vn -0.5556 -0.8180 0.1490 -vn -0.7523 -0.6481 0.1181 -vn -0.8965 -0.4358 0.0794 -vn -0.4125 -0.4268 -0.8048 -vn -0.9808 -0.1919 0.0350 -vn -0.9994 -0.0186 0.0308 -vn -0.9993 -0.0186 0.0309 -vn -0.9469 0.3020 0.1101 -vn -0.8668 0.4564 0.2010 -vn -0.6734 0.6679 0.3168 -vn -0.5930 0.7275 0.3451 -vn -0.3440 0.8484 0.4024 -vn -0.2982 0.8624 0.4091 -vn -0.9999 -0.0040 0.0160 -vn -0.9999 -0.0040 0.0161 -vn -0.9361 0.3503 0.0302 -vn -0.9056 0.4218 0.0451 -vn -0.7095 0.6984 0.0943 -vn -0.6699 0.7358 0.0994 -vn -0.3804 0.9165 0.1238 -vn -0.3539 0.9269 0.1252 -vn -1.0000 -0.0005 0.0009 -vn -1.0000 -0.0005 0.0010 -vn -0.9249 0.3751 -0.0623 -vn -0.9233 0.3788 -0.0626 -vn -0.7082 0.6968 -0.1137 -vn -0.7059 0.6991 -0.1140 -vn -0.3834 0.9115 -0.1487 -vn -0.3818 0.9122 -0.1488 -vn -0.3813 -0.9075 0.1765 -vn -0.3798 -0.9081 0.1764 -vn -0.7054 -0.6967 0.1302 -vn -0.7053 -0.6969 0.1300 -vn -0.6258 0.3869 0.6773 -vn -0.6774 0.1319 0.7237 -vn -0.4790 0.6031 0.6379 -vn -0.2592 0.7475 0.6116 -vn -0.2592 -0.4838 0.8359 -vn -0.4790 -0.3393 0.8096 -vn -0.6258 -0.1232 0.7702 -vn 0.9967 0.0102 0.0804 -vn 0.9202 -0.3672 0.1357 -vn 0.9233 -0.3599 0.1346 -vn 0.9967 0.0187 0.0791 -vn 0.7038 -0.6866 0.1824 -vn 0.7081 -0.6823 0.1818 -vn 0.3807 -0.8997 0.2136 -vn 0.3837 -0.8984 0.2135 -vn 0.3818 0.9227 -0.0533 -vn 0.3787 0.9240 -0.0535 -vn 0.7054 0.7085 -0.0219 -vn 0.7010 0.7128 -0.0226 -vn 0.9213 0.3880 0.0250 -vn 0.9182 0.3953 0.0240 -vn -0.8184 -0.0436 -0.5730 -vn -0.7821 -0.1569 -0.6031 -vn -0.8413 0.2013 -0.5017 -vn -0.8229 0.3371 -0.4573 -vn -0.7202 0.5883 -0.3678 -vn -0.6498 0.6848 -0.3298 -vn -0.4114 0.8766 -0.2495 -vn -0.3501 0.9064 -0.2361 -vn -0.2071 -0.6673 -0.7154 -vn -0.2297 -0.6614 -0.7140 -vn -0.4172 -0.5825 -0.6976 -vn -0.4608 -0.5558 -0.6920 -vn -0.6203 -0.4184 -0.6635 -vn -0.6735 -0.3531 -0.6494 -vn -0.9986 -0.0017 -0.0536 -vn -0.9985 -0.0174 -0.0518 -vn -0.9262 0.3644 -0.0965 -vn -0.9207 0.3778 -0.0981 -vn -0.7110 0.6902 -0.1347 -vn -0.7031 0.6980 -0.1356 -vn -0.3855 0.9087 -0.1603 -vn -0.3799 0.9110 -0.1606 -vn -0.3776 -0.9244 0.0547 -vn -0.3831 -0.9221 0.0545 -vn -0.6998 -0.7137 0.0300 -vn -0.7077 -0.7059 0.0291 -vn -0.9183 -0.3958 -0.0073 -vn -0.9239 -0.3825 -0.0089 -vn 0.9978 -0.0658 0.0101 -vn 0.9978 -0.0661 0.0102 -vn 0.9961 -0.0867 0.0133 -vn -0.0014 -0.1517 -0.9884 -vn 0.0245 0.2351 -0.9717 -vn 0.1233 0.1705 -0.9776 -vn 0.0228 -0.1570 -0.9873 -vn 0.0406 0.5855 -0.8097 -vn 0.3348 0.4709 -0.8162 -vn 0.0539 0.8503 -0.5236 -vn 0.5382 0.6789 -0.4994 -vn 0.0597 0.9866 -0.1518 -vn 0.6150 0.7794 -0.1199 -vn 0.0499 0.9692 0.2412 -vn 0.5281 0.8051 0.2699 -vn 0.0299 0.8037 0.5943 -vn 0.3156 0.7038 0.6364 -vn 0.0165 0.5155 0.8567 -vn 0.1133 0.4609 0.8802 -vn -0.0025 0.1519 0.9884 -vn 0.0211 0.1511 0.9883 -vn -0.0395 -0.2307 0.9722 -vn 0.0599 -0.1890 0.9802 -vn -0.0697 -0.6095 0.7897 -vn 0.1901 -0.5504 0.8130 -vn -0.0697 -0.6096 0.7897 -vn -0.0889 -0.8741 0.4775 -vn 0.2929 -0.8311 0.4728 -vn -0.0938 -0.9840 0.1514 -vn 0.3157 -0.9378 0.1442 -vn -0.0889 -0.9772 -0.1928 -vn 0.2930 -0.9347 -0.2012 -vn -0.0697 -0.8187 -0.5700 -vn 0.1901 -0.7693 -0.6100 -vn -0.0395 -0.5122 -0.8579 -vn 0.0611 -0.4773 -0.8766 -vn -0.9931 0.1161 -0.0179 -vn -0.9931 0.1162 -0.0179 -vn -0.9956 0.0925 -0.0143 -vn -0.9956 0.0924 -0.0142 -vn 0.9996 -0.0273 -0.0086 -vn 0.9951 -0.0592 0.0792 -vn 0.9998 -0.0178 0.0069 -vn 0.9998 -0.0179 0.0069 -vn 0.9935 -0.1128 0.0180 -vn 0.9934 -0.1129 0.0180 -vn 0.9935 -0.1130 0.0168 -vn 0.9935 -0.1130 0.0167 -vn 0.9998 -0.0191 -0.0012 -vn 0.9998 -0.0191 -0.0013 -vn 0.9951 -0.0803 -0.0578 -vn 0.9978 -0.0528 -0.0390 -vn 0.9920 -0.1203 -0.0385 -vn -0.9935 0.1129 -0.0120 -vn -0.9935 0.1129 -0.0119 -vn -0.9912 0.1167 -0.0629 -vn -0.9867 0.1601 -0.0280 -vn -0.9867 0.1602 -0.0280 -vn -0.9941 0.1075 -0.0149 -vn -0.9941 0.1076 -0.0149 -vn -0.9941 0.1071 -0.0181 -vn -0.9941 0.1070 -0.0181 -vn -0.9867 0.1611 -0.0215 -vn -0.9912 0.1302 0.0249 -vn -0.9935 0.1112 -0.0227 -vn -0.9935 0.1112 -0.0226 -vn 0.0677 0.9004 0.4298 -vn 0.0678 0.9004 0.4298 -vn 0.0678 0.7296 -0.6805 -vn 0.0673 0.7226 -0.6879 -vn 0.0673 0.8960 0.4390 -vn 0.0226 0.3343 0.9422 -vn -0.0260 -0.1509 -0.9882 -vn -0.0774 0.1839 -0.9799 -vn -0.2593 0.5128 -0.8185 -vn -0.4487 0.7406 -0.5001 -vn -0.5205 0.8439 -0.1298 -vn -0.4486 0.8567 0.2545 -vn -0.2593 0.7350 0.6265 -vn -0.0774 0.4699 0.8793 -vn -0.0259 0.1531 0.9879 -vn -0.1267 -0.1699 0.9773 -vn -0.3181 -0.4943 0.8090 -vn -0.4547 -0.7559 0.4710 -vn -0.4841 -0.8648 0.1330 -vn -0.4548 -0.8625 -0.2221 -vn -0.3180 -0.7146 -0.6230 -vn -0.1267 -0.4557 -0.8811 -vn -0.8660 0.4919 -0.0896 -vn -0.5000 0.8520 -0.1552 -vn -0.5000 -0.8520 0.1552 -vn -0.4768 0.4204 0.7720 -vn -0.5505 0.1496 0.8213 -vn -0.4767 0.4204 0.7720 -vn -0.2753 0.6187 0.7359 -vn -0.2753 -0.3194 0.9068 -vn -0.4768 -0.1212 0.8706 -vn -0.2706 0.7695 0.5785 -vn 0.9147 -0.4028 0.0328 -vn -0.4278 0.4065 -0.8073 -vn -0.4238 0.4055 -0.8099 -vn 0.9195 -0.3930 -0.0104 -vn -0.4724 -0.0396 0.8805 -vn -0.5109 -0.0173 0.8595 -vn 0.9147 -0.4027 0.0328 -vn 0.9195 -0.3929 -0.0104 -vn 0.9326 -0.2755 0.2330 -vn -0.4655 -0.4834 -0.7414 -vn -0.3343 -0.5671 -0.7528 -vn 0.8821 -0.4710 0.0106 -vn -0.4610 0.7435 0.4843 -vn -0.5679 0.7188 0.4010 -vn 0.0030 -0.2387 0.9711 -vn 0.0030 -0.2388 0.9711 -vn 0.0031 -0.2386 0.9711 -vn 0.0058 -0.8554 0.5179 -vn 0.0058 -0.8555 0.5179 -vn 0.0059 -0.8554 0.5179 -vn 0.0059 -0.9715 -0.2368 -vn 0.0057 -0.9714 -0.2373 -vn 0.0059 -0.9715 -0.2370 -vn 0.0030 -0.5194 -0.8545 -vn 0.0031 -0.5195 -0.8544 -vn 0.0031 -0.5195 -0.8545 -vn 0.0030 -0.5194 -0.8546 -vn -0.0040 0.2387 -0.9711 -vn -0.0040 0.2386 -0.9711 -vn -0.0040 0.2388 -0.9711 -vn -0.0116 0.8556 -0.5175 -vn -0.0114 0.8554 -0.5178 -vn -0.0112 0.8552 -0.5181 -vn -0.0113 0.8554 -0.5179 -vn -0.0114 0.9715 0.2369 -vn -0.0114 0.9715 0.2368 -vn -0.0116 0.9714 0.2372 -vn -0.0113 0.9715 0.2368 -vn -0.0040 0.5196 0.8544 -vn -0.0040 0.5195 0.8545 -vn -0.0040 0.5195 0.8544 -vn -0.0040 0.5194 0.8545 -vn 0.5000 0.0374 -0.8652 -vn 0.5000 -0.0374 0.8652 -vn 0.5000 -0.0373 0.8652 -vn -0.6385 0.7592 -0.1260 -vn -0.6331 0.7545 -0.1727 -vn 0.5267 -0.6034 -0.5988 -vn 0.2118 -0.2181 -0.9527 -vn 0.5267 -0.6033 -0.5988 -vn 0.3758 -0.4743 0.7962 -vn -0.0371 0.0072 0.9993 -vn -0.6092 -0.7909 -0.0581 -vn -0.6104 -0.7917 0.0240 -vn 0.1468 0.1824 -0.9722 -vn 0.4221 0.5423 -0.7264 -vn 0.4222 0.5423 -0.7264 -vn 0.1469 0.1824 -0.9722 -vn 0.0558 0.0831 0.9950 -vn 0.3940 0.5200 0.7579 -vn 0.5000 0.4249 -0.7546 -vn 0.5000 -0.4249 0.7546 -vn 0.5000 -0.4249 0.7547 -vn 0.5000 -0.4248 0.7546 -vn -0.8194 -0.5640 0.1027 -vn -0.8194 -0.5640 0.1028 -vn -0.5794 -0.5256 -0.6230 -vn -0.5794 -0.5255 -0.6230 -vn 0.5794 0.2721 -0.7683 -vn 0.5794 0.2720 -0.7683 -vn 0.8194 0.5640 -0.1028 -vn 0.5794 0.5255 0.6230 -vn 0.5794 0.5256 0.6230 -vn -0.5794 -0.2721 0.7683 -vn -0.9999 -0.0025 -0.0139 -vn -0.9999 0.0026 0.0143 -vn -0.7152 -0.1253 -0.6876 -vn -0.7750 -0.1133 -0.6217 -vn -0.6983 0.1283 0.7042 -vn -0.7864 0.1107 0.6078 -vn -0.0817 0.9966 -0.0118 -vn -0.2007 0.9739 -0.1059 -vn -0.0646 0.8796 -0.4713 -vn -0.0647 0.8796 -0.4713 -vn -0.0504 0.8706 -0.4894 -vn -0.0505 0.8706 -0.4894 -vn -0.7071 -0.6956 0.1268 -vn -0.1568 -0.0834 0.9841 -vn -0.1037 -0.0481 0.9934 -vn -0.1191 -0.0429 0.9920 -vn -0.1636 -0.0827 0.9830 -vn -0.1595 -0.0786 0.9841 -vn -0.1176 -0.0334 0.9925 -vn -0.1781 -0.0649 0.9819 -vn -0.1393 -0.0171 0.9901 -vn -0.1876 -0.0600 0.9804 -vn -0.1708 0.0027 0.9853 -vn -0.2306 -0.1516 0.9612 -vn -0.2329 -0.1546 0.9601 -vn -0.2981 -0.2413 0.9235 -vn -0.2712 -0.2024 0.9410 -vn -0.2732 -0.2048 0.9399 -vn -0.2980 -0.2412 0.9236 -vn -0.3003 -0.2433 0.9223 -vn -0.3037 -0.2418 0.9216 -vn -0.3063 -0.2382 0.9217 -vn -0.3331 -0.3091 0.8908 -vn -0.3408 -0.3385 0.8771 -vn -0.3240 -0.2929 0.8996 -vn -0.3149 -0.2722 0.9092 -vn -0.3593 -0.3450 0.8671 -vn -0.3343 -0.3078 0.8908 -vn -0.3792 -0.3331 0.8633 -vn -0.3598 -0.3039 0.8822 -vn -0.3999 -0.3111 0.8622 -vn -0.3641 -0.2805 0.8881 -vn -0.1868 -0.0633 0.9804 -vn -0.1673 -0.0038 0.9859 -vn -0.2328 -0.1545 0.9602 -vn -0.2738 -0.2056 0.9396 -vn -0.3468 -0.2650 0.8997 -vn -0.3099 -0.2395 0.9201 -vn -0.3913 -0.2930 0.8724 -vn -0.0595 0.9982 0.0060 -vn -0.0596 0.9982 0.0060 -vn -0.0598 0.9982 0.0062 -vn -0.0596 0.9982 0.0061 -vn -0.2089 0.9778 -0.0168 -vn -0.2089 0.9778 -0.0167 -vn 0.9937 -0.0135 0.1116 -vn 0.9937 -0.0135 0.1115 -vn 0.9937 -0.0136 0.1114 -vn -0.6960 0.7155 -0.0606 -vn 0.8042 -0.5866 0.0958 -vn 0.8042 -0.5866 0.0957 -vn -0.6286 0.7775 -0.0213 -vn 0.8776 -0.4594 0.1373 -vn 0.8776 -0.4594 0.1372 -vn -0.8422 0.5225 -0.1329 -vn -0.9023 0.3833 -0.1974 -vn -0.9415 0.1538 -0.2999 -vn -0.8279 -0.3476 -0.4400 -vn -0.8279 -0.3476 -0.4401 -vn 0.6106 -0.7918 -0.0165 -vn 0.6106 -0.7918 -0.0164 -vn 0.8958 -0.4113 0.1686 -vn 0.3265 -0.9279 -0.1801 -vn 0.9911 0.0634 0.1173 -vn 0.9911 0.0633 0.1172 -vn 0.8739 -0.4580 0.1628 -vn 0.8740 -0.4579 0.1628 -vn -0.7350 0.6747 -0.0674 -vn -0.7352 0.6745 -0.0671 -vn -0.7353 0.6745 -0.0670 -vn -0.6265 0.7789 -0.0282 -vn -0.6265 0.7789 -0.0281 -vn -0.6266 0.7789 -0.0281 -vn 0.9114 -0.3745 0.1704 -vn 0.9115 -0.3745 0.1704 -vn 0.0953 -0.0130 -0.9954 -vn 0.0953 -0.0131 -0.9954 -vn 0.0951 -0.0135 -0.9954 -vn 0.0884 -0.0220 -0.9958 -vn 0.0885 -0.0220 -0.9958 -vn 0.3094 0.2522 -0.9169 -vn 0.4009 0.3669 -0.8394 -vn 0.4010 0.3669 -0.8394 -vn 0.3358 0.2894 -0.8963 -vn 0.3358 0.2895 -0.8963 -vn 0.3713 0.3277 -0.8688 -vn 0.3713 0.3276 -0.8688 -vn -0.9969 -0.0775 -0.0138 -vn -0.9999 0.0009 0.0110 -vn -0.9999 0.0009 0.0111 -vn -0.9999 0.0009 0.0114 -vn -1.0000 -0.0040 -0.0066 -vn -1.0000 -0.0040 -0.0067 -vn -0.9997 0.0111 -0.0198 -vn -0.9998 -0.0043 -0.0202 -vn -0.9998 -0.0043 -0.0201 -vn -0.9999 -0.0034 -0.0152 -vn -0.9999 -0.0034 -0.0153 -vn -0.9954 0.0949 -0.0146 -vn -0.9954 0.0951 -0.0146 -vn -0.9954 0.0950 -0.0146 -vn -0.9856 0.1669 -0.0257 -vn 0.9972 -0.0743 0.0114 -vn 0.9972 -0.0744 0.0115 -vn 1.0000 0.0026 -0.0004 -vn 0.9835 -0.0325 -0.1781 -vn -0.2706 -0.5160 0.8127 -vn -0.4084 0.8980 -0.1636 -vn -0.2088 0.9621 -0.1753 -vn 0.2088 0.9621 -0.1753 -vn 0.4084 0.8980 -0.1636 -vn 0.7071 0.6957 -0.1268 -vn -0.7071 0.6957 -0.1268 -vn -0.8194 0.5640 -0.1027 -vn 0.9984 -0.0227 0.0516 -vn -0.5034 -0.3952 -0.7684 -vn -0.4923 -0.3987 -0.7737 -vn 0.9984 -0.0230 0.0511 -vn -0.5701 0.4169 0.7080 -vn -0.5599 0.4199 0.7143 -vn -0.5701 0.4169 0.7079 -vn -0.5600 0.4199 0.7142 -vn 0.3758 -0.4743 0.7961 -vn 0.5793 0.2721 -0.7683 -vn 0.8194 0.5640 -0.1027 -vn 0.5276 0.4322 0.7314 -vn 0.5276 -0.4321 -0.7314 -vn 0.5276 -0.4322 -0.7313 -s off -f 16/1/1 17/2/1 18/3/1 -f 19/4/2 20/5/2 21/6/2 -f 22/7/3 23/8/3 24/9/3 -f 25/10/4 26/11/4 27/12/4 -f 28/13/5 29/14/5 30/15/5 -f 31/16/6 32/17/6 33/18/6 -f 34/19/7 35/20/7 36/21/7 -f 37/22/8 38/23/8 39/24/8 -f 40/25/9 41/26/9 42/27/9 -f 43/28/3 44/29/3 45/30/3 -f 46/31/3 47/32/3 48/33/3 -f 49/34/3 50/35/3 51/36/3 -f 52/37/3 53/38/3 54/39/3 -f 55/40/3 56/41/3 57/42/3 -f 58/43/3 59/44/3 60/45/3 -f 83/46/1 84/47/1 85/48/1 -f 86/49/2 87/50/2 88/51/2 -f 89/52/3 90/53/3 91/54/3 -f 92/55/10 93/56/10 94/57/10 -f 95/58/11 96/59/11 97/60/11 -f 98/61/12 99/62/12 100/63/12 -f 101/64/13 102/65/13 103/66/13 -f 104/67/14 105/68/14 106/69/14 -f 107/70/15 108/71/15 109/72/15 -f 110/73/3 111/74/3 112/75/3 -f 113/76/3 114/77/3 115/78/3 -f 116/79/3 117/80/3 118/81/3 -f 119/82/3 120/83/3 121/84/3 -f 122/85/3 123/86/3 124/87/3 -f 125/88/3 126/89/3 127/90/3 -f 69/91/16 146/92/16 147/93/16 -f 168/94/1 169/95/1 170/96/1 -f 168/94/1 170/96/1 171/97/1 -f 172/98/1 173/99/1 174/100/1 -f 172/98/1 174/100/1 175/101/1 -f 176/102/1 177/103/1 178/104/1 -f 176/102/1 178/104/1 179/105/1 -f 184/106/3 185/107/3 186/108/3 -f 184/106/3 186/108/3 187/109/3 -f 192/110/3 193/111/3 185/107/3 -f 192/110/3 185/107/3 184/106/3 -f 203/112/3 204/113/3 193/111/3 -f 203/112/3 193/111/3 192/110/3 -f 217/114/3 218/115/3 204/113/3 -f 217/114/3 204/113/3 203/112/3 -f 224/116/1 225/117/1 226/118/1 -f 224/116/1 226/118/1 227/119/1 -f 225/117/1 224/116/1 245/120/1 -f 225/117/1 245/120/1 246/121/1 -f 246/121/1 245/120/1 257/122/1 -f 246/121/1 257/122/1 258/123/1 -f 258/123/1 257/122/1 266/124/1 -f 258/123/1 266/124/1 267/125/1 -f 269/126/17 290/127/17 291/128/17 -f 295/129/18 297/130/1 298/131/1 -f 298/131/1 297/130/1 299/132/1 -f 298/131/1 299/132/1 300/133/1 -f 301/134/3 302/135/3 303/136/3 -f 301/134/3 303/136/3 304/137/3 -f 302/135/3 305/138/3 306/139/3 -f 302/135/3 306/139/3 303/136/3 -f 324/140/19 325/141/19 326/142/19 -f 324/140/20 326/142/20 327/143/20 -f 357/144/3 358/145/3 359/146/3 -f 357/144/3 359/146/3 360/147/3 -f 358/145/3 361/148/3 362/149/3 -f 358/145/3 362/149/3 359/146/3 -f 363/150/3 364/151/3 362/149/3 -f 363/150/3 362/149/3 361/148/3 -f 399/152/21 400/153/21 401/154/21 -f 399/152/21 401/154/21 402/155/21 -f 403/156/22 404/157/22 405/158/22 -f 403/156/22 405/158/22 406/159/22 -f 407/160/23 408/161/23 409/162/23 -f 407/160/23 409/162/23 410/163/23 -f 411/164/24 412/165/24 413/166/24 -f 411/164/24 413/166/24 414/167/24 -f 415/168/1 416/169/1 417/170/1 -f 415/168/1 417/170/1 418/171/1 -f 419/172/3 420/173/3 421/174/3 -f 419/172/3 421/174/3 422/175/3 -f 423/176/25 424/177/25 425/178/25 -f 423/176/25 425/178/25 426/179/25 -f 427/180/26 428/181/26 429/182/26 -f 427/180/26 429/182/26 430/183/26 -f 431/184/16 432/185/16 433/186/16 -f 431/184/16 433/186/16 434/187/16 -f 435/188/27 436/189/27 437/190/27 -f 435/188/27 437/190/27 438/191/27 -f 511/192/1 512/193/1 513/194/1 -f 511/192/1 513/194/1 514/195/1 -f 515/196/1 511/192/1 514/195/1 -f 515/196/1 514/195/1 516/197/1 -f 517/198/1 515/196/1 516/197/1 -f 517/198/1 516/197/1 518/199/1 -f 519/200/1 517/198/1 518/199/1 -f 519/200/1 518/199/1 520/201/1 -f 521/202/1 522/203/1 523/204/1 -f 521/202/1 523/204/1 524/205/1 -f 525/206/1 521/202/1 524/205/1 -f 525/206/1 524/205/1 526/207/1 -f 527/208/1 525/206/1 526/207/1 -f 527/208/1 526/207/1 528/209/1 -f 512/193/1 527/208/1 528/209/1 -f 512/193/1 528/209/1 513/194/1 -f 48/33/3 551/210/3 552/211/3 -f 48/33/3 552/211/3 46/31/3 -f 571/212/3 572/213/3 573/214/3 -f 571/212/3 573/214/3 574/215/3 -f 572/213/3 575/216/3 576/217/3 -f 572/213/3 576/217/3 573/214/3 -f 575/216/3 577/218/3 578/219/3 -f 575/216/3 578/219/3 576/217/3 -f 577/218/3 579/220/3 580/221/3 -f 577/218/3 580/221/3 578/219/3 -f 581/222/3 582/223/3 583/224/3 -f 581/222/3 583/224/3 584/225/3 -f 582/223/3 585/226/3 586/227/3 -f 582/223/3 586/227/3 583/224/3 -f 585/226/3 587/228/3 588/229/3 -f 585/226/3 588/229/3 586/227/3 -f 587/228/3 571/212/3 574/215/3 -f 587/228/3 574/215/3 588/229/3 -f 711/230/28 713/231/28 714/232/28 -f 711/230/28 714/232/28 712/233/28 -f 713/231/28 715/234/28 716/235/28 -f 713/231/28 716/235/28 714/232/28 -f 715/234/28 683/236/28 686/237/28 -f 715/234/28 686/237/28 716/235/28 -f 718/238/29 721/239/29 722/240/29 -f 718/238/29 722/240/29 719/241/29 -f 721/239/29 723/242/29 724/243/29 -f 721/239/29 724/243/29 722/240/29 -f 723/242/29 725/244/29 726/245/29 -f 723/242/29 726/245/29 724/243/29 -f 725/244/29 727/246/29 728/247/29 -f 725/244/29 728/247/29 726/245/29 -f 727/246/29 729/248/29 730/249/29 -f 727/246/29 730/249/29 728/247/29 -f 729/248/29 731/250/29 732/251/29 -f 729/248/29 732/251/29 730/249/29 -f 867/252/30 868/253/30 869/254/30 -f 867/252/30 869/254/30 870/255/30 -f 45/30/3 871/256/3 872/257/3 -f 45/30/3 872/257/3 43/28/3 -f 887/258/3 888/259/3 889/260/3 -f 887/258/3 889/260/3 890/261/3 -f 891/262/3 892/263/3 893/264/3 -f 891/262/3 893/264/3 894/265/3 -f 895/266/3 896/267/3 897/268/3 -f 895/266/3 897/268/3 898/269/3 -f 899/270/3 900/271/3 901/272/3 -f 899/270/3 901/272/3 902/273/3 -f 903/274/3 904/275/3 905/276/3 -f 903/274/3 905/276/3 906/277/3 -f 907/278/3 908/279/3 909/280/3 -f 907/278/3 909/280/3 910/281/3 -f 911/282/3 912/283/3 913/284/3 -f 911/282/3 913/284/3 914/285/3 -f 915/286/31 916/287/31 917/288/31 -f 915/286/31 917/288/31 918/289/31 -f 919/290/3 920/291/3 921/292/3 -f 919/290/31 921/292/31 922/293/31 -f 923/294/31 924/295/31 925/296/31 -f 923/294/3 925/296/3 926/297/3 -f 927/298/3 928/299/3 929/300/3 -f 927/298/31 929/300/31 930/301/31 -f 931/302/3 932/303/3 933/304/3 -f 931/302/3 933/304/3 934/305/3 -f 935/306/32 936/307/32 937/308/32 -f 935/306/32 937/308/32 938/309/32 -f 939/310/33 940/311/33 941/312/33 -f 939/310/33 941/312/33 942/313/33 -f 943/314/34 944/315/34 945/316/34 -f 943/314/34 945/316/34 946/317/34 -f 947/318/35 948/319/35 949/320/35 -f 947/318/35 949/320/35 950/321/35 -f 951/322/36 952/323/36 953/324/36 -f 951/322/36 953/324/36 954/325/36 -f 955/326/37 956/327/37 957/328/37 -f 955/326/37 957/328/37 958/329/37 -f 959/330/38 960/331/38 961/332/38 -f 959/330/38 961/332/38 962/333/38 -f 963/334/30 964/335/30 965/336/30 -f 963/334/30 965/336/30 966/337/30 -f 967/338/39 968/339/39 969/340/39 -f 967/338/39 969/340/39 970/341/39 -f 971/342/40 972/343/40 973/344/40 -f 971/342/40 973/344/40 974/345/40 -f 975/346/41 976/347/41 977/348/41 -f 975/346/41 977/348/41 978/349/41 -f 979/350/42 980/351/42 981/352/42 -f 979/350/42 981/352/42 982/353/42 -f 997/354/30 998/355/30 999/356/30 -f 997/354/30 999/356/30 1000/357/30 -f 1001/358/3 1002/359/3 1003/360/3 -f 1001/358/3 1003/360/3 1004/361/3 -f 1005/362/3 1006/363/3 1007/364/3 -f 1005/362/3 1007/364/3 1008/365/3 -f 1009/366/3 1010/367/3 1011/368/3 -f 1009/366/3 1011/368/3 1012/369/3 -f 1013/370/3 1014/371/3 1015/372/3 -f 1013/370/3 1015/372/3 1016/373/3 -f 1017/374/3 1018/375/3 1019/376/3 -f 1017/374/3 1019/376/3 1020/377/3 -f 1021/378/3 1022/379/3 1023/380/3 -f 1021/378/3 1023/380/3 1024/381/3 -f 1025/382/43 1026/383/43 1027/384/43 -f 1025/382/43 1027/384/43 1028/385/43 -f 1033/386/44 1034/387/44 1035/388/44 -f 1033/386/44 1035/388/44 1036/389/44 -f 1037/390/45 1038/391/45 1039/392/45 -f 1037/390/45 1039/392/45 1040/393/45 -f 1045/394/46 1046/395/46 1047/396/46 -f 1045/394/46 1047/396/46 1048/397/46 -f 1089/398/26 1090/399/26 1091/400/26 -f 1089/398/26 1091/400/26 1092/401/26 -f 1090/399/26 1093/402/26 1094/403/26 -f 1090/399/26 1094/403/26 1091/400/26 -f 1093/402/26 1095/404/26 1096/405/26 -f 1093/402/26 1096/405/26 1094/403/26 -f 1095/404/26 1097/406/26 1098/407/26 -f 1095/404/26 1098/407/26 1096/405/26 -f 1097/406/26 1099/408/26 1100/409/26 -f 1097/406/26 1100/409/26 1098/407/26 -f 1101/410/26 1102/411/26 1103/412/26 -f 1101/410/26 1103/412/26 1104/413/26 -f 1102/411/26 1105/414/26 1106/415/26 -f 1102/411/26 1106/415/26 1103/412/26 -f 1105/414/26 1089/398/26 1092/401/26 -f 1105/414/26 1092/401/26 1106/415/26 -f 1139/416/47 1140/417/47 1141/418/47 -f 1139/416/48 1141/418/48 1142/419/48 -f 1143/420/49 1144/421/49 1145/422/49 -f 1143/420/50 1145/422/50 1146/423/50 -f 1147/424/51 1148/425/51 1149/426/51 -f 1147/424/51 1149/426/51 1150/427/51 -f 1151/428/52 1152/429/52 1153/430/52 -f 1151/428/52 1153/430/52 1154/431/52 -f 1155/432/53 1156/433/53 1157/434/53 -f 1155/432/53 1157/434/53 1158/435/53 -f 1159/436/54 1160/437/54 1161/438/54 -f 1159/436/54 1161/438/54 1162/439/54 -f 1163/440/55 1164/441/55 1165/442/55 -f 1163/440/55 1165/442/55 1166/443/55 -f 1167/444/56 1168/445/56 1169/446/56 -f 1167/444/56 1169/446/56 1170/447/56 -f 1171/448/57 1172/449/57 1173/450/57 -f 1171/448/57 1173/450/57 1174/451/57 -f 1175/452/57 1176/453/57 1177/454/57 -f 1175/452/57 1177/454/57 1178/455/57 -f 1179/456/57 1180/457/57 1181/458/57 -f 1179/456/57 1181/458/57 1182/459/57 -f 1183/460/57 1184/461/57 1185/462/57 -f 1183/460/57 1185/462/57 1186/463/57 -f 1187/464/57 1188/465/57 1189/466/57 -f 1187/464/57 1189/466/57 1190/467/57 -f 1191/468/57 1192/469/57 1193/470/57 -f 1191/468/57 1193/470/57 1194/471/57 -f 1195/472/57 1196/473/57 1197/474/57 -f 1195/472/57 1197/474/57 1198/475/57 -f 1199/476/58 1200/477/58 1201/478/58 -f 1199/476/57 1201/478/57 1202/479/57 -f 1279/480/59 1280/481/59 1281/482/59 -f 1279/480/59 1281/482/59 1282/483/59 -f 1283/484/60 1284/485/60 1285/486/60 -f 1283/484/61 1285/486/61 1286/487/61 -f 1287/488/62 1288/489/62 1289/490/62 -f 1287/488/62 1289/490/62 1290/491/62 -f 1291/492/63 1292/493/63 1293/494/63 -f 1291/492/63 1293/494/63 1294/495/63 -f 57/42/3 1313/496/3 1314/497/3 -f 57/42/3 1314/497/3 55/40/3 -f 51/36/3 1333/498/3 1334/499/3 -f 51/36/3 1334/499/3 49/34/3 -f 1377/500/64 1378/501/64 1379/502/64 -f 1377/500/64 1379/502/64 1380/503/64 -f 1389/504/65 1390/505/65 1391/506/65 -f 1389/504/65 1391/506/65 1392/507/65 -f 1393/508/66 1394/509/66 1395/510/66 -f 1393/508/66 1395/510/66 1396/511/66 -f 1453/512/67 1455/513/67 1456/514/67 -f 1465/515/68 1466/516/68 1467/517/68 -f 1465/515/69 1467/517/69 1468/518/69 -f 1469/519/70 1471/520/70 1472/521/71 -f 1473/522/72 1475/523/72 1476/524/72 -f 1477/525/73 1478/526/73 1479/527/73 -f 1477/525/73 1479/527/73 1480/528/73 -f 1481/529/74 1482/530/74 1483/531/74 -f 1481/529/74 1483/531/74 1484/532/74 -f 1489/533/75 1490/534/75 1491/535/75 -f 1489/533/75 1491/535/75 1492/536/75 -f 1509/537/26 1510/538/26 1511/539/26 -f 1509/537/26 1511/539/26 1512/540/26 -f 1545/541/28 1546/542/28 1547/543/28 -f 1545/541/28 1547/543/28 1548/544/28 -f 1548/544/28 1547/543/28 1550/545/28 -f 1548/544/28 1550/545/28 1549/546/28 -f 1557/547/3 1558/548/3 23/8/3 -f 1557/547/3 23/8/3 22/7/3 -f 1559/549/3 1560/550/3 872/257/3 -f 1559/549/3 872/257/3 871/256/3 -f 1561/551/3 1562/552/3 552/211/3 -f 1561/551/3 552/211/3 551/210/3 -f 1563/553/3 1564/554/3 1562/552/3 -f 1563/553/3 1562/552/3 1561/551/3 -f 52/37/3 54/39/3 1334/499/3 -f 52/37/3 1334/499/3 1333/498/3 -f 58/43/3 60/45/3 1314/497/3 -f 58/43/3 1314/497/3 1313/496/3 -f 1569/555/3 1570/556/3 1571/557/3 -f 1569/555/3 1571/557/3 1572/558/3 -f 1573/559/3 1574/560/3 1575/561/3 -f 1573/559/3 1575/561/3 1576/562/3 -f 1577/563/3 1578/564/3 1579/565/3 -f 1577/563/3 1579/565/3 1580/566/3 -f 1581/567/3 1582/568/3 1583/569/3 -f 1581/567/3 1583/569/3 1584/570/3 -f 1585/571/3 1586/572/3 1587/573/3 -f 1585/571/3 1587/573/3 1588/574/3 -f 1589/575/3 1590/576/3 1591/577/3 -f 1589/575/3 1591/577/3 1592/578/3 -f 1593/579/3 1594/580/3 1595/581/3 -f 1593/579/3 1595/581/3 1596/582/3 -f 1605/583/3 1606/584/3 1607/585/3 -f 1605/583/3 1607/585/3 1608/586/3 -f 1615/587/16 1616/588/16 135/589/16 -f 1637/590/1 1638/591/1 1639/592/1 -f 1637/590/1 1639/592/1 1640/593/1 -f 1641/594/1 1642/595/1 1643/596/1 -f 1641/594/1 1643/596/1 1644/597/1 -f 1645/598/1 1646/599/1 1647/600/1 -f 1645/598/1 1647/600/1 1648/601/1 -f 1653/602/3 1654/603/3 1655/604/3 -f 1653/602/3 1655/604/3 1656/605/3 -f 1654/603/3 1661/606/3 1662/607/3 -f 1654/603/3 1662/607/3 1655/604/3 -f 1661/606/3 1672/608/3 1673/609/3 -f 1661/606/3 1673/609/3 1662/607/3 -f 1672/608/3 1686/610/3 1687/611/3 -f 1672/608/3 1687/611/3 1673/609/3 -f 1693/612/1 1694/613/1 1695/614/1 -f 1693/612/1 1695/614/1 1696/615/1 -f 1714/616/1 1695/614/1 1694/613/1 -f 1714/616/1 1694/613/1 1715/617/1 -f 1726/618/1 1714/616/1 1715/617/1 -f 1726/618/1 1715/617/1 1727/619/1 -f 1735/620/1 1726/618/1 1727/619/1 -f 1735/620/1 1727/619/1 1736/621/1 -f 1740/622/76 1739/623/76 1759/624/76 -f 1740/622/76 1759/624/76 1760/625/76 -f 1764/626/77 1765/627/1 1766/628/1 -f 1765/627/1 1768/629/1 1769/630/1 -f 1765/627/1 1769/630/1 1766/628/1 -f 1793/631/78 1794/632/78 1795/633/78 -f 1793/631/79 1795/633/79 1796/634/79 -f 1828/635/3 1829/636/3 1830/637/3 -f 1828/635/3 1830/637/3 1831/638/3 -f 1831/638/3 1830/637/3 1832/639/3 -f 1831/638/3 1832/639/3 1833/640/3 -f 1832/639/3 1834/641/3 1835/642/3 -f 1832/639/3 1835/642/3 1833/640/3 -f 1870/643/80 1871/644/80 1872/645/80 -f 1870/643/80 1872/645/80 1873/646/80 -f 1874/647/81 1875/648/81 1876/649/81 -f 1874/647/81 1876/649/81 1877/650/81 -f 1878/651/82 1879/652/82 1880/653/82 -f 1878/651/82 1880/653/82 1881/654/82 -f 1882/655/83 1883/656/83 1884/657/83 -f 1882/655/83 1884/657/83 1885/658/83 -f 1886/659/1 1887/660/1 1888/661/1 -f 1886/659/1 1888/661/1 1889/662/1 -f 1890/663/3 1891/664/3 1892/665/3 -f 1890/663/3 1892/665/3 1893/666/3 -f 1894/667/25 1895/668/25 1896/669/25 -f 1894/667/25 1896/669/25 1897/670/25 -f 1898/671/27 1899/672/27 1900/673/27 -f 1898/671/27 1900/673/27 1901/674/27 -f 1902/675/16 1903/676/16 1904/677/16 -f 1902/675/16 1904/677/16 1905/678/16 -f 1906/679/26 1907/680/26 1908/681/26 -f 1906/679/26 1908/681/26 1909/682/26 -f 1984/683/1 1985/684/1 1986/685/1 -f 1984/683/1 1986/685/1 1987/686/1 -f 1988/687/1 1989/688/1 1985/684/1 -f 1988/687/1 1985/684/1 1984/683/1 -f 1990/689/1 1991/690/1 1989/688/1 -f 1990/689/1 1989/688/1 1988/687/1 -f 1992/691/1 1993/692/1 1991/690/1 -f 1992/691/1 1991/690/1 1990/689/1 -f 1994/693/1 1995/694/1 1996/695/1 -f 1994/693/1 1996/695/1 1997/696/1 -f 1987/686/1 1986/685/1 1999/697/1 -f 2018/698/3 2019/699/3 2020/700/3 -f 2018/698/3 2020/700/3 2021/701/3 -f 2040/702/3 2041/703/3 2042/704/3 -f 2040/702/3 2042/704/3 2043/705/3 -f 2043/705/3 2042/704/3 2044/706/3 -f 2043/705/3 2044/706/3 2045/707/3 -f 2045/707/3 2044/706/3 2046/708/3 -f 2045/707/3 2046/708/3 2047/709/3 -f 2047/709/3 2046/708/3 2048/710/3 -f 2047/709/3 2048/710/3 2049/711/3 -f 2050/712/3 2051/713/3 2052/714/3 -f 2050/712/3 2052/714/3 2053/715/3 -f 2053/715/3 2052/714/3 2054/716/3 -f 2053/715/3 2054/716/3 2055/717/3 -f 2055/717/3 2054/716/3 2056/718/3 -f 2055/717/3 2056/718/3 2057/719/3 -f 2057/719/3 2056/718/3 2041/703/3 -f 2057/719/3 2041/703/3 2040/702/3 -f 2154/720/84 2155/721/84 2156/722/84 -f 2154/720/84 2156/722/84 2157/723/84 -f 2190/724/85 2191/725/85 2192/726/85 -f 2190/724/86 2192/726/86 2193/727/86 -f 2194/728/87 2195/729/87 2196/730/87 -f 2194/728/88 2196/730/88 2197/731/88 -f 2202/732/84 2203/733/84 2204/734/84 -f 2202/732/84 2204/734/84 2205/735/84 -f 2206/736/84 2207/737/84 2208/738/84 -f 2206/736/84 2208/738/84 2209/739/84 -f 2210/740/84 2211/741/84 2212/742/84 -f 2210/740/84 2212/742/84 2213/743/84 -f 2214/744/84 2215/745/84 2216/746/84 -f 2214/744/84 2216/746/84 2217/747/84 -f 2218/748/89 2219/749/89 2220/750/89 -f 2218/748/89 2220/750/89 2221/751/89 -f 2222/752/89 2223/753/89 2224/754/89 -f 2222/752/89 2224/754/89 2225/755/89 -f 2226/756/89 2227/757/89 2228/758/89 -f 2226/756/89 2228/758/89 2229/759/89 -f 2230/760/89 2231/761/89 2232/762/89 -f 2230/760/89 2232/762/89 2233/763/89 -f 2234/764/89 2235/765/89 2236/766/89 -f 2234/764/89 2236/766/89 2237/767/89 -f 2238/768/89 2239/769/89 2240/770/89 -f 2238/768/89 2240/770/89 2241/771/89 -f 2242/772/89 2243/773/89 2244/774/89 -f 2242/772/89 2244/774/89 2245/775/89 -f 2246/776/89 2247/777/89 2248/778/89 -f 2246/776/89 2248/778/89 2249/779/89 -f 2282/780/90 2283/781/90 2284/782/90 -f 2282/780/90 2284/782/90 2285/783/90 -f 2286/784/91 2287/785/91 2288/786/91 -f 2286/784/91 2288/786/91 2289/787/91 -f 2290/788/92 2291/789/92 2292/790/92 -f 2290/788/92 2292/790/92 2293/791/92 -f 2298/792/93 2299/793/93 2300/794/93 -f 2298/792/93 2300/794/93 2301/795/93 -f 2302/796/94 2303/797/94 2304/798/94 -f 2302/796/94 2304/798/94 2305/799/94 -f 2310/800/95 2312/801/95 2313/802/95 -f 2314/803/96 2315/804/96 2316/805/96 -f 2314/803/96 2316/805/96 2317/806/96 -f 2318/807/97 2319/808/97 2320/809/97 -f 2318/807/97 2320/809/97 2321/810/97 -f 2322/811/98 2323/812/98 2324/813/98 -f 2322/811/98 2324/813/98 2325/814/98 -f 2326/815/99 2327/816/99 2328/817/99 -f 2326/815/99 2328/817/99 2329/818/99 -f 2330/819/100 2331/820/100 2332/821/100 -f 2330/819/100 2332/821/100 2333/822/100 -f 2334/823/101 2335/824/101 2336/825/101 -f 2334/823/101 2336/825/101 2337/826/101 -f 2338/827/102 2339/828/102 2340/829/102 -f 2338/827/102 2340/829/102 2341/830/102 -f 2342/831/103 2343/832/103 2344/833/103 -f 2346/834/90 2347/835/90 2348/836/90 -f 2346/834/90 2348/836/90 2349/837/90 -f 2350/838/103 2351/839/103 2352/840/103 -f 2350/838/103 2352/840/103 2353/841/103 -f 2354/842/102 2355/843/102 2356/844/102 -f 2354/842/102 2356/844/102 2357/845/102 -f 2358/846/101 2359/847/101 2360/848/101 -f 2358/846/101 2360/848/101 2361/849/101 -f 2362/850/100 2363/851/100 2364/852/100 -f 2362/850/100 2364/852/100 2365/853/100 -f 2366/854/99 2367/855/99 2368/856/99 -f 2366/854/99 2368/856/99 2369/857/99 -f 2370/858/98 2371/859/98 2372/860/98 -f 2370/858/98 2372/860/98 2373/861/98 -f 2374/862/97 2375/863/97 2376/864/97 -f 2374/862/97 2376/864/97 2377/865/97 -f 2378/866/104 2379/867/104 2380/868/104 -f 2378/866/104 2380/868/104 2381/869/104 -f 2382/870/105 2383/871/105 2384/872/105 -f 2382/870/105 2384/872/105 2385/873/105 -f 2390/874/94 2391/875/94 2392/876/94 -f 2390/874/94 2392/876/94 2393/877/94 -f 2394/878/93 2395/879/93 2396/880/93 -f 2394/878/93 2396/880/93 2397/881/93 -f 2402/882/106 2403/883/106 2404/884/106 -f 2402/882/107 2404/884/107 2405/885/107 -f 2441/886/32 2442/887/32 2443/888/32 -f 2441/886/32 2443/888/32 2444/889/32 -f 2445/890/3 2446/891/3 111/74/3 -f 2445/890/3 111/74/3 110/73/3 -f 2461/892/3 2462/893/3 2463/894/3 -f 2461/892/3 2463/894/3 2464/895/3 -f 2465/896/3 2466/897/3 2467/898/3 -f 2465/896/3 2467/898/3 2468/899/3 -f 2469/900/3 2470/901/3 2471/902/3 -f 2469/900/3 2471/902/3 2472/903/3 -f 2473/904/3 2474/905/3 2475/906/3 -f 2473/904/3 2475/906/3 2476/907/3 -f 2477/908/3 2478/909/3 2479/910/3 -f 2477/908/3 2479/910/3 2480/911/3 -f 2481/912/3 2482/913/3 2483/914/3 -f 2481/912/3 2483/914/3 2484/915/3 -f 2485/916/3 2486/917/3 2487/918/3 -f 2485/916/3 2487/918/3 2488/919/3 -f 2489/920/31 2490/921/31 2491/922/31 -f 2489/920/31 2491/922/31 2492/923/31 -f 2493/924/31 2494/925/31 2495/926/31 -f 2493/924/3 2495/926/3 2496/927/3 -f 2497/928/3 2498/929/3 2499/930/3 -f 2497/928/31 2499/930/31 2500/931/31 -f 2501/932/31 2502/933/31 2503/934/31 -f 2501/932/3 2503/934/3 2504/935/3 -f 2505/936/3 2506/937/3 2507/938/3 -f 2505/936/3 2507/938/3 2508/939/3 -f 2509/940/30 2510/941/30 2511/942/30 -f 2509/940/30 2511/942/30 2512/943/30 -f 2513/944/39 2514/945/39 2515/946/39 -f 2513/944/39 2515/946/39 2516/947/39 -f 2517/948/40 2518/949/40 2519/950/40 -f 2517/948/40 2519/950/40 2520/951/40 -f 2521/952/41 2522/953/41 2523/954/41 -f 2521/952/41 2523/954/41 2524/955/41 -f 2525/956/42 2526/957/42 2527/958/42 -f 2525/956/42 2527/958/42 2528/959/42 -f 2529/960/38 2530/961/38 2531/962/38 -f 2529/960/38 2531/962/38 2532/963/38 -f 2533/964/37 2534/965/37 2535/966/37 -f 2533/964/37 2535/966/37 2536/967/37 -f 2537/968/32 2538/969/32 2539/970/32 -f 2537/968/32 2539/970/32 2540/971/32 -f 2541/972/33 2542/973/33 2543/974/33 -f 2541/972/33 2543/974/33 2544/975/33 -f 2545/976/34 2546/977/34 2547/978/34 -f 2545/976/34 2547/978/34 2548/979/34 -f 2549/980/35 2550/981/35 2551/982/35 -f 2549/980/35 2551/982/35 2552/983/35 -f 2553/984/36 2554/985/36 2555/986/36 -f 2571/987/32 2572/988/32 2573/989/32 -f 2571/987/32 2573/989/32 2574/990/32 -f 2575/991/3 2576/992/3 2577/993/3 -f 2575/991/3 2577/993/3 2578/994/3 -f 2579/995/3 2580/996/3 2581/997/3 -f 2579/995/3 2581/997/3 2582/998/3 -f 2583/999/3 2584/1000/3 2585/1001/3 -f 2583/999/3 2585/1001/3 2586/1002/3 -f 2587/1003/3 2588/1004/3 2589/1005/3 -f 2587/1003/3 2589/1005/3 2590/1006/3 -f 2591/1007/3 2592/1008/3 2593/1009/3 -f 2591/1007/3 2593/1009/3 2594/1010/3 -f 2595/1011/3 2596/1012/3 2597/1013/3 -f 2595/1011/3 2597/1013/3 2598/1014/3 -f 2599/1015/108 2600/1016/108 2601/1017/108 -f 2599/1015/108 2601/1017/108 2602/1018/108 -f 2607/1019/109 2608/1020/109 2609/1021/109 -f 2607/1019/109 2609/1021/109 2610/1022/109 -f 2611/1023/110 2612/1024/110 2613/1025/110 -f 2611/1023/110 2613/1025/110 2614/1026/110 -f 2619/1027/111 2620/1028/111 2621/1029/111 -f 2619/1027/111 2621/1029/111 2622/1030/111 -f 2657/1031/27 2658/1032/27 2659/1033/27 -f 2657/1031/27 2659/1033/27 2660/1034/27 -f 2660/1034/27 2659/1033/27 2661/1035/27 -f 2660/1034/27 2661/1035/27 2662/1036/27 -f 2662/1036/27 2661/1035/27 2663/1037/27 -f 2662/1036/27 2663/1037/27 2664/1038/27 -f 2664/1038/27 2663/1037/27 2665/1039/27 -f 2664/1038/27 2665/1039/27 2666/1040/27 -f 2666/1040/27 2665/1039/27 2667/1041/27 -f 2666/1040/27 2667/1041/27 2668/1042/27 -f 2669/1043/27 2670/1044/27 2671/1045/27 -f 2669/1043/27 2671/1045/27 2672/1046/27 -f 2672/1046/27 2671/1045/27 2673/1047/27 -f 2672/1046/27 2673/1047/27 2674/1048/27 -f 2674/1048/27 2673/1047/27 2658/1032/27 -f 2674/1048/27 2658/1032/27 2657/1031/27 -f 2707/1049/112 2708/1050/112 2709/1051/112 -f 2707/1049/113 2709/1051/113 2710/1052/113 -f 2711/1053/114 2712/1054/114 2713/1055/114 -f 2711/1053/115 2713/1055/115 2714/1056/115 -f 2715/1057/116 2716/1058/116 2717/1059/116 -f 2715/1057/116 2717/1059/116 2718/1060/116 -f 2719/1061/117 2720/1062/117 2721/1063/117 -f 2719/1061/117 2721/1063/117 2722/1064/117 -f 2723/1065/118 2724/1066/118 2725/1067/118 -f 2723/1065/118 2725/1067/118 2726/1068/118 -f 2727/1069/119 2728/1070/119 2729/1071/119 -f 2727/1069/119 2729/1071/119 2730/1072/119 -f 2731/1073/120 2732/1074/120 2733/1075/120 -f 2731/1073/120 2733/1075/120 2734/1076/120 -f 2735/1077/121 2736/1078/121 2737/1079/121 -f 2735/1077/121 2737/1079/121 2738/1080/121 -f 2739/1081/122 2740/1082/122 2741/1083/122 -f 2739/1081/122 2741/1083/122 2742/1084/122 -f 2743/1085/122 2744/1086/122 2745/1087/122 -f 2743/1085/122 2745/1087/122 2746/1088/122 -f 2747/1089/122 2748/1090/122 2749/1091/122 -f 2747/1089/122 2749/1091/122 2750/1092/122 -f 2751/1093/122 2752/1094/122 2753/1095/122 -f 2751/1093/122 2753/1095/122 2754/1096/122 -f 2755/1097/122 2756/1098/122 2757/1099/122 -f 2755/1097/122 2757/1099/122 2758/1100/122 -f 2759/1101/122 2760/1102/122 2761/1103/122 -f 2759/1101/122 2761/1103/122 2762/1104/122 -f 2763/1105/122 2764/1106/122 2765/1107/122 -f 2763/1105/122 2765/1107/122 2766/1108/122 -f 2767/1109/122 2768/1110/122 2769/1111/122 -f 2767/1109/122 2769/1111/122 2770/1112/122 -f 2847/1113/123 2848/1114/123 2849/1115/123 -f 2847/1113/123 2849/1115/123 2850/1116/123 -f 2851/1117/124 2852/1118/124 2853/1119/124 -f 2855/1120/125 2856/1121/125 2857/1122/125 -f 2855/1120/125 2857/1122/125 2858/1123/125 -f 2859/1124/126 2860/1125/126 2861/1126/126 -f 2859/1124/126 2861/1126/126 2862/1127/126 -f 2881/1128/3 2882/1129/3 123/86/3 -f 2881/1128/3 123/86/3 122/85/3 -f 2901/1130/3 2902/1131/3 117/80/3 -f 2901/1130/3 117/80/3 116/79/3 -f 2945/1132/127 2946/1133/127 2947/1134/127 -f 2945/1132/127 2947/1134/127 2948/1135/127 -f 2957/1136/128 2958/1137/128 2959/1138/128 -f 2961/1139/129 2962/1140/129 2963/1141/129 -f 2961/1139/129 2963/1141/129 2964/1142/129 -f 3033/1143/130 3034/1144/130 3035/1145/130 -f 3033/1143/130 3035/1145/130 3036/1146/130 -f 3041/1147/131 3042/1148/131 3043/1149/131 -f 3045/1150/132 3046/1151/132 3047/1152/132 -f 3045/1150/133 3047/1152/133 3048/1153/133 -f 3049/1154/134 3050/1155/134 3051/1156/134 -f 3049/1154/134 3051/1156/134 3052/1157/134 -f 3057/1158/135 3058/1159/135 3059/1160/135 -f 3057/1158/135 3059/1160/135 3060/1161/135 -f 3073/1162/136 3074/1163/136 3075/1164/136 -f 3073/1162/136 3075/1164/136 3076/1165/136 -f 3081/1166/27 3082/1167/27 3083/1168/27 -f 3081/1166/27 3083/1168/27 3084/1169/27 -f 3105/1170/137 3106/1171/137 3107/1172/137 -f 3105/1170/137 3107/1172/137 3108/1173/137 -f 3109/1174/138 3110/1175/138 3111/1176/138 -f 3109/1174/138 3111/1176/138 3112/1177/138 -f 3113/1178/139 3114/1179/139 3115/1180/139 -f 3113/1178/139 3115/1180/139 3116/1181/139 -f 3117/1182/140 3118/1183/140 3119/1184/140 -f 3117/1182/140 3119/1184/140 3120/1185/140 -f 3121/1186/141 3122/1187/141 3123/1188/141 -f 3121/1186/141 3123/1188/141 3124/1189/141 -f 3125/1190/142 3126/1191/142 3127/1192/142 -f 3125/1190/142 3127/1192/142 3128/1193/142 -f 3129/1194/143 3130/1195/143 3131/1196/143 -f 3129/1194/143 3131/1196/143 3132/1197/143 -f 3133/1198/144 3134/1199/144 3135/1200/144 -f 3133/1198/144 3135/1200/144 3136/1201/144 -f 3137/1202/145 3138/1203/145 3139/1204/145 -f 3137/1202/145 3139/1204/145 3140/1205/145 -f 3141/1206/146 3142/1207/146 3143/1208/146 -f 3141/1206/146 3143/1208/146 3144/1209/146 -f 3145/1210/147 3146/1211/147 3147/1212/147 -f 3145/1210/147 3147/1212/147 3148/1213/147 -f 3149/1214/148 3150/1215/148 3151/1216/148 -f 3149/1214/148 3151/1216/148 3152/1217/148 -f 3153/1218/149 3154/1219/149 3155/1220/149 -f 3153/1218/149 3155/1220/149 3156/1221/149 -f 3157/1222/150 3158/1223/150 3159/1224/150 -f 3157/1222/150 3159/1224/150 3160/1225/150 -f 3161/1226/151 3162/1227/151 3163/1228/151 -f 3161/1226/151 3163/1228/151 3164/1229/151 -f 3165/1230/152 3166/1231/152 3167/1232/152 -f 3165/1230/152 3167/1232/152 3168/1233/152 -f 3169/1234/153 3170/1235/153 3171/1236/153 -f 3169/1234/153 3171/1236/153 3172/1237/153 -f 3173/1238/154 3174/1239/154 3175/1240/154 -f 3173/1238/154 3175/1240/154 3176/1241/154 -f 3177/1242/155 3178/1243/155 3179/1244/155 -f 3177/1242/155 3179/1244/155 3180/1245/155 -f 3181/1246/156 3182/1247/156 3183/1248/156 -f 3181/1246/156 3183/1248/156 3184/1249/156 -f 3185/1250/157 3186/1251/157 3187/1252/157 -f 3185/1250/157 3187/1252/157 3188/1253/157 -f 3193/1254/89 3197/1255/89 3198/1256/89 -f 3193/1254/89 3198/1256/89 3194/1257/89 -f 3197/1255/89 3199/1258/89 3200/1259/89 -f 3197/1255/89 3200/1259/89 3198/1256/89 -f 3201/1260/84 3202/1261/84 3203/1262/84 -f 3201/1260/84 3203/1262/84 3204/1263/84 -f 3206/1264/84 3201/1260/84 3204/1263/84 -f 3206/1264/84 3204/1263/84 3207/1265/84 -f 91/54/3 3213/1266/3 3214/1267/3 -f 91/54/3 3214/1267/3 89/52/3 -f 2445/890/3 3215/1268/3 3216/1269/3 -f 2445/890/3 3216/1269/3 2446/891/3 -f 2018/698/3 3217/1270/3 3218/1271/3 -f 2018/698/3 3218/1271/3 2019/699/3 -f 3217/1270/3 3219/1272/3 3220/1273/3 -f 3217/1270/3 3220/1273/3 3218/1271/3 -f 2901/1130/3 120/83/3 119/82/3 -f 2901/1130/3 119/82/3 2902/1131/3 -f 2881/1128/3 126/89/3 125/88/3 -f 2881/1128/3 125/88/3 2882/1129/3 -f 3225/1274/3 3226/1275/3 3227/1276/3 -f 3225/1274/3 3227/1276/3 3228/1277/3 -f 3229/1278/3 3230/1279/3 3231/1280/3 -f 3229/1278/3 3231/1280/3 3232/1281/3 -f 3233/1282/3 3234/1283/3 3235/1284/3 -f 3233/1282/3 3235/1284/3 3236/1285/3 -f 3237/1286/3 3238/1287/3 3239/1288/3 -f 3237/1286/3 3239/1288/3 3240/1289/3 -f 3241/1290/3 3242/1291/3 3243/1292/3 -f 3241/1290/3 3243/1292/3 3244/1293/3 -f 3245/1294/3 3246/1295/3 3247/1296/3 -f 3245/1294/3 3247/1296/3 3248/1297/3 -f 3249/1298/3 3250/1299/3 3251/1300/3 -f 3249/1298/3 3251/1300/3 3252/1301/3 -f 3261/1302/3 3262/1303/3 3263/1304/3 -f 3261/1302/3 3263/1304/3 3264/1305/3 -f 3265/1306/3 3266/1307/3 3267/1308/3 -f 3265/1306/3 3267/1308/3 3268/1309/3 -f 3268/1309/3 3267/1308/3 3269/1310/3 -f 3268/1309/3 3269/1310/3 3270/1311/3 -f 3270/1311/3 3269/1310/3 3271/1312/3 -f 3270/1311/3 3271/1312/3 3272/1313/3 -f 3273/1314/1 3274/1315/1 3275/1316/1 -f 3273/1314/1 3275/1316/1 3276/1317/1 -f 3274/1315/1 3277/1318/1 3278/1319/1 -f 3274/1315/1 3278/1319/1 3275/1316/1 -f 3277/1318/1 3279/1320/1 3280/1321/1 -f 3277/1318/1 3280/1321/1 3278/1319/1 -f 3281/1322/27 3282/1323/27 3283/1324/27 -f 3281/1322/27 3283/1324/27 3284/1325/27 -f 3293/1326/26 3294/1327/26 3295/1328/26 -f 3293/1326/26 3295/1328/26 3296/1329/26 -f 3297/1330/1 3298/1331/1 3299/1332/1 -f 3297/1330/1 3299/1332/1 3300/1333/1 -f 3317/1334/3 3318/1335/3 3319/1336/3 -f 3317/1334/3 3319/1336/3 3320/1337/3 -f 3321/1338/1 3297/1330/1 3300/1333/1 -f 3321/1338/1 3300/1333/1 3322/1339/1 -f 3319/1336/3 3323/1340/3 3324/1341/3 -f 3319/1336/3 3324/1341/3 3320/1337/3 -f 3324/1341/3 3325/1342/3 3326/1343/3 -f 3324/1341/3 3326/1343/3 3320/1337/3 -f 3326/1343/3 3327/1344/3 3317/1334/3 -f 3326/1343/3 3317/1334/3 3320/1337/3 -f 3299/1332/1 3328/1345/1 3329/1346/1 -f 3299/1332/1 3329/1346/1 3300/1333/1 -f 3300/1333/1 3329/1346/1 3330/1347/1 -f 3300/1333/1 3330/1347/1 3322/1339/1 -f 3365/1348/21 3366/1349/21 3367/1350/21 -f 3365/1348/21 3367/1350/21 3368/1351/21 -f 3369/1352/22 3370/1353/22 3371/1354/22 -f 3369/1352/22 3371/1354/22 3372/1355/22 -f 3373/1356/23 3374/1357/23 3375/1358/23 -f 3373/1356/23 3375/1358/23 3376/1359/23 -f 3377/1360/24 3378/1361/24 3379/1362/24 -f 3377/1360/24 3379/1362/24 3380/1363/24 -f 3389/1364/80 3390/1365/80 3391/1366/80 -f 3389/1364/80 3391/1366/80 3392/1367/80 -f 3393/1368/81 3394/1369/81 3395/1370/81 -f 3393/1368/81 3395/1370/81 3396/1371/81 -f 3397/1372/82 3398/1373/82 3399/1374/82 -f 3397/1372/82 3399/1374/82 3400/1375/82 -f 3401/1376/83 3402/1377/83 3403/1378/83 -f 3401/1376/83 3403/1378/83 3404/1379/83 -s 1 -f 1/1380/158 2/1381/159 3/1382/160 -f 4/1383/161 5/1384/162 6/1385/163 -f 7/1386/164 8/1387/165 9/1388/166 -f 10/1389/167 11/1390/168 12/1391/169 -f 13/1392/170 14/1393/171 15/1394/172 -f 61/1395/173 62/1396/174 63/1397/175 -f 64/1398/176 65/1399/177 66/1400/178 -f 67/1401/179 68/1402/180 69/91/16 -f 70/1403/181 71/1404/182 72/1405/183 -f 73/1406/161 74/1407/163 75/1408/184 -f 76/1409/185 77/1410/186 78/1411/187 -f 79/1412/188 80/1413/189 81/1414/190 -f 13/1392/170 82/1415/191 14/1393/171 -f 128/1416/192 129/1417/193 130/1418/194 -f 131/1419/195 132/1420/196 133/1421/197 -f 134/1422/198 135/589/16 136/1423/199 -f 1/1380/158 10/1389/167 12/1391/169 -f 1/1380/158 12/1391/169 2/1381/159 -f 5/1384/162 1/1380/158 3/1382/160 -f 5/1384/162 3/1382/160 6/1385/163 -f 7/1386/164 13/1392/170 15/1394/172 -f 7/1386/164 15/1394/172 8/1387/165 -f 10/1389/167 7/1386/164 9/1388/166 -f 10/1389/167 9/1388/166 11/1390/168 -f 137/1424/200 138/1425/201 2/1381/159 -f 137/1424/200 2/1381/159 12/1391/169 -f 139/1426/202 137/1424/200 12/1391/169 -f 139/1426/202 12/1391/169 11/1390/168 -f 138/1425/201 140/1427/203 3/1382/160 -f 138/1425/201 3/1382/160 2/1381/159 -f 140/1427/203 141/1428/204 6/1385/163 -f 140/1427/203 6/1385/163 3/1382/160 -f 14/1393/171 142/1429/205 64/1398/176 -f 14/1393/171 64/1398/176 15/1394/172 -f 64/1398/176 66/1400/178 8/1387/165 -f 64/1398/176 8/1387/165 15/1394/172 -f 66/1400/178 143/1430/206 9/1388/166 -f 66/1400/178 9/1388/166 8/1387/165 -f 143/1430/206 139/1426/202 11/1390/168 -f 143/1430/206 11/1390/168 9/1388/166 -f 144/1431/207 62/1396/174 61/1395/173 -f 144/1431/207 61/1395/173 145/1432/208 -f 69/91/16 147/93/16 67/1401/179 -f 148/1433/209 149/1434/173 150/1435/210 -f 148/1433/209 150/1435/210 151/1436/180 -f 152/1437/211 153/1438/212 154/1439/213 -f 152/1437/211 154/1439/213 155/1440/213 -f 156/1441/214 157/1442/215 158/1443/31 -f 156/1441/214 158/1443/31 159/1444/3 -f 160/1445/216 161/1446/216 157/1442/215 -f 160/1445/216 157/1442/215 156/1441/214 -f 137/1424/200 162/1447/217 163/1448/218 -f 137/1424/200 163/1448/218 138/1425/201 -f 164/1449/219 162/1447/217 137/1424/200 -f 164/1449/219 137/1424/200 139/1426/202 -f 138/1425/201 163/1448/218 165/1450/220 -f 138/1425/201 165/1450/220 140/1427/203 -f 165/1450/220 166/1451/221 141/1428/204 -f 165/1450/220 141/1428/204 140/1427/203 -f 63/1397/175 167/1452/222 143/1430/206 -f 63/1397/175 143/1430/206 66/1400/178 -f 167/1452/222 164/1449/219 139/1426/202 -f 167/1452/222 139/1426/202 143/1430/206 -f 61/1395/173 63/1397/175 66/1400/178 -f 61/1395/173 66/1400/178 65/1399/177 -f 180/1453/223 181/1454/224 182/1455/225 -f 180/1453/223 182/1455/225 183/1456/226 -f 188/1457/227 189/1458/228 181/1454/224 -f 188/1457/227 181/1454/224 180/1453/223 -f 181/1454/224 190/1459/229 191/1460/230 -f 181/1454/224 191/1460/230 182/1455/225 -f 194/1461/231 195/1462/232 196/1463/233 -f 194/1461/231 196/1463/233 197/1464/234 -f 188/1457/227 198/1465/235 199/1466/236 -f 188/1457/227 199/1466/236 189/1458/228 -f 189/1458/228 200/1467/237 190/1459/229 -f 189/1458/228 190/1459/229 181/1454/224 -f 190/1459/229 201/1468/238 202/1469/239 -f 190/1459/229 202/1469/239 191/1460/230 -f 205/1470/240 206/1471/241 195/1462/232 -f 205/1470/240 195/1462/232 194/1461/231 -f 195/1462/232 207/1472/242 208/1473/243 -f 195/1462/232 208/1473/243 196/1463/233 -f 209/1474/244 210/1475/245 211/1476/246 -f 209/1474/244 211/1476/246 212/1477/247 -f 199/1466/236 213/1478/248 200/1467/237 -f 199/1466/236 200/1467/237 189/1458/228 -f 200/1467/237 214/1479/249 201/1468/238 -f 200/1467/237 201/1468/238 190/1459/229 -f 201/1468/238 215/1480/250 216/1481/251 -f 201/1468/238 216/1481/251 202/1469/239 -f 219/1482/252 220/1483/253 206/1471/241 -f 219/1482/252 206/1471/241 205/1470/240 -f 206/1471/241 221/1484/254 207/1472/242 -f 206/1471/241 207/1472/242 195/1462/232 -f 222/1485/255 223/1486/256 208/1473/243 -f 222/1485/255 208/1473/243 207/1472/242 -f 211/1476/246 228/1487/257 229/1488/258 -f 211/1476/246 229/1488/258 230/1489/259 -f 213/1478/248 231/1490/260 214/1479/249 -f 213/1478/248 214/1479/249 200/1467/237 -f 214/1479/249 232/1491/261 215/1480/250 -f 214/1479/249 215/1480/250 201/1468/238 -f 233/1492/262 234/1493/263 235/1494/264 -f 233/1492/262 235/1494/264 236/1495/264 -f 237/1496/265 238/1497/266 220/1483/253 -f 237/1496/265 220/1483/253 219/1482/252 -f 220/1483/253 239/1498/267 221/1484/254 -f 220/1483/253 221/1484/254 206/1471/241 -f 221/1484/254 240/1499/268 222/1485/255 -f 221/1484/254 222/1485/255 207/1472/242 -f 241/1500/269 242/1501/270 243/1502/271 -f 241/1500/269 243/1502/271 244/1503/272 -f 228/1487/257 247/1504/273 248/1505/274 -f 228/1487/257 248/1505/274 229/1488/258 -f 231/1490/260 249/1506/275 232/1491/261 -f 231/1490/260 232/1491/261 214/1479/249 -f 250/1507/276 251/1508/276 234/1493/263 -f 250/1507/276 234/1493/263 252/1509/262 -f 238/1497/266 253/1510/277 239/1498/267 -f 238/1497/266 239/1498/267 220/1483/253 -f 239/1498/267 254/1511/278 240/1499/268 -f 239/1498/267 240/1499/268 221/1484/254 -f 255/1512/279 256/1513/280 242/1501/270 -f 255/1512/279 242/1501/270 241/1500/269 -f 248/1505/274 247/1504/273 259/1514/281 -f 248/1505/274 259/1514/281 260/1515/282 -f 261/1516/26 262/1517/26 251/1508/276 -f 261/1516/26 251/1508/276 250/1507/276 -f 253/1510/277 263/1518/283 254/1511/278 -f 253/1510/277 254/1511/278 239/1498/267 -f 264/1519/284 265/1520/285 256/1513/280 -f 264/1519/284 256/1513/280 255/1512/279 -f 268/1521/286 269/126/17 270/1522/17 -f 268/1521/286 270/1522/17 271/1523/287 -f 264/1519/284 272/1524/288 273/1525/289 -f 264/1519/284 273/1525/289 265/1520/285 -f 274/1526/1 275/1527/1 276/1528/290 -f 274/1526/1 276/1528/290 277/1529/290 -f 277/1529/290 276/1528/290 278/1530/291 -f 277/1529/290 278/1530/291 279/1531/291 -f 280/1532/292 281/1533/292 282/1534/293 -f 280/1532/292 282/1534/293 283/1535/294 -f 210/1475/245 284/1536/257 228/1487/257 -f 210/1475/245 228/1487/257 211/1476/246 -f 284/1536/257 285/1537/295 247/1504/273 -f 284/1536/257 247/1504/273 228/1487/257 -f 286/1538/280 287/1539/296 242/1501/270 -f 286/1538/280 242/1501/270 256/1513/280 -f 247/1504/273 285/1537/295 288/1540/297 -f 247/1504/273 288/1540/297 259/1514/281 -f 289/1541/298 286/1538/280 256/1513/280 -f 289/1541/298 256/1513/280 265/1520/285 -f 269/126/17 291/128/17 270/1522/17 -f 292/1542/299 289/1541/298 265/1520/285 -f 292/1542/299 265/1520/285 273/1525/289 -f 230/1489/259 229/1488/258 213/1478/248 -f 230/1489/259 213/1478/248 199/1466/236 -f 229/1488/258 248/1505/274 231/1490/260 -f 229/1488/258 231/1490/260 213/1478/248 -f 255/1512/279 241/1500/269 222/1485/255 -f 255/1512/279 222/1485/255 240/1499/268 -f 248/1505/274 260/1515/282 249/1506/275 -f 248/1505/274 249/1506/275 231/1490/260 -f 264/1519/284 255/1512/279 240/1499/268 -f 264/1519/284 240/1499/268 254/1511/278 -f 268/1521/286 271/1523/287 262/1517/26 -f 268/1521/286 262/1517/26 261/1516/26 -f 272/1524/288 264/1519/284 254/1511/278 -f 272/1524/288 254/1511/278 263/1518/283 -f 230/1489/259 293/1543/300 212/1477/247 -f 230/1489/259 212/1477/247 211/1476/246 -f 242/1501/270 287/1539/296 294/1544/301 -f 242/1501/270 294/1544/301 243/1502/271 -f 293/1543/300 230/1489/259 199/1466/236 -f 293/1543/300 199/1466/236 198/1465/235 -f 222/1485/255 241/1500/269 244/1503/272 -f 222/1485/255 244/1503/272 223/1486/256 -f 295/129/302 296/1545/302 297/130/303 -f 307/1546/304 308/1547/305 309/1548/306 -f 307/1546/304 309/1548/306 310/1549/307 -f 311/1550/308 312/1551/309 308/1547/305 -f 311/1550/308 308/1547/305 307/1546/304 -f 313/1552/310 314/1553/311 315/1554/312 -f 313/1552/310 315/1554/312 316/1555/310 -f 317/1556/313 318/1557/314 319/1558/315 -f 317/1556/313 319/1558/315 320/1559/316 -f 321/1560/317 322/1561/318 323/1562/319 -f 321/1560/317 323/1562/319 317/1556/313 -f 328/1563/320 329/1564/321 330/1565/322 -f 328/1563/320 330/1565/322 331/1566/323 -f 332/1567/324 333/1568/325 334/1569/326 -f 332/1567/324 334/1569/326 335/1570/327 -f 336/1571/328 337/1572/328 338/1573/329 -f 336/1571/328 338/1573/329 339/1574/330 -f 340/1575/331 328/1563/320 331/1566/323 -f 340/1575/331 331/1566/323 341/1576/332 -f 334/1569/326 342/1577/333 343/1578/334 -f 334/1569/326 343/1578/334 335/1570/327 -f 344/1579/335 345/1580/336 309/1548/306 -f 344/1579/335 309/1548/306 308/1547/305 -f 346/1581/337 318/1557/314 317/1556/313 -f 346/1581/337 317/1556/313 323/1562/319 -f 347/1582/338 344/1579/335 308/1547/305 -f 347/1582/338 308/1547/305 312/1551/309 -f 348/1583/339 321/1560/317 317/1556/313 -f 348/1583/339 317/1556/313 320/1559/316 -f 339/1574/330 338/1573/329 315/1554/312 -f 339/1574/330 315/1554/312 314/1553/311 -f 335/1570/327 343/1578/334 319/1558/315 -f 335/1570/327 319/1558/315 318/1557/314 -f 331/1566/323 330/1565/322 345/1580/336 -f 331/1566/323 345/1580/336 344/1579/335 -f 332/1567/324 335/1570/327 318/1557/314 -f 332/1567/324 318/1557/314 346/1581/337 -f 341/1576/332 331/1566/323 344/1579/335 -f 341/1576/332 344/1579/335 347/1582/338 -f 349/1584/340 350/1585/341 351/1586/342 -f 349/1584/340 351/1586/342 352/1587/343 -f 353/1588/344 354/1589/345 355/1590/346 -f 353/1588/344 355/1590/346 356/1591/346 -f 365/1592/347 366/1593/348 367/1594/349 -f 365/1592/347 367/1594/349 368/1595/350 -f 369/1596/351 370/1597/352 366/1593/348 -f 369/1596/351 366/1593/348 365/1592/347 -f 371/1598/353 372/1599/354 373/1600/355 -f 371/1598/353 373/1600/355 374/1601/356 -f 375/1602/357 376/1603/358 377/1604/359 -f 375/1602/357 377/1604/359 378/1605/360 -f 379/1606/361 380/1607/361 368/1595/350 -f 379/1606/361 368/1595/350 367/1594/349 -f 370/1597/352 369/1596/351 381/1608/362 -f 370/1597/352 381/1608/362 382/1609/362 -f 371/1598/353 374/1601/356 383/1610/363 -f 371/1598/353 383/1610/363 384/1611/363 -f 372/1599/354 377/1604/359 376/1603/358 -f 372/1599/354 376/1603/358 373/1600/355 -f 385/1612/364 386/1613/365 387/1614/366 -f 385/1612/364 387/1614/366 388/1615/367 -f 354/1589/345 353/1588/344 389/1616/368 -f 354/1589/345 389/1616/368 390/1617/369 -f 390/1617/369 389/1616/368 388/1615/367 -f 390/1617/369 388/1615/367 387/1614/366 -f 391/1618/370 392/1619/371 393/1620/372 -f 391/1618/370 393/1620/372 394/1621/373 -f 351/1586/342 350/1585/341 395/1622/374 -f 351/1586/342 395/1622/374 396/1623/375 -f 396/1623/375 395/1622/374 394/1621/373 -f 396/1623/375 394/1621/373 393/1620/372 -f 385/1612/364 397/1624/376 398/1625/376 -f 385/1612/364 398/1625/376 386/1613/365 -f 439/1626/377 440/1627/377 441/1628/378 -f 439/1626/377 441/1628/378 442/1629/378 -f 443/1630/42 444/1631/42 440/1627/377 -f 443/1630/42 440/1627/377 439/1626/377 -f 445/1632/379 446/1633/379 444/1631/42 -f 445/1632/379 444/1631/42 443/1630/42 -f 447/1634/16 448/1635/16 446/1633/379 -f 447/1634/16 446/1633/379 445/1632/379 -f 449/1636/380 450/1637/380 451/1638/25 -f 449/1636/380 451/1638/25 452/1639/25 -f 453/1640/39 454/1641/39 450/1637/380 -f 453/1640/39 450/1637/380 449/1636/380 -f 455/1642/45 456/1643/45 454/1641/39 -f 455/1642/45 454/1641/39 453/1640/39 -f 442/1629/378 441/1628/378 456/1643/45 -f 442/1629/378 456/1643/45 455/1642/45 -f 457/1644/381 458/1645/382 459/1646/383 -f 457/1644/381 459/1646/383 460/1647/384 -f 461/1648/385 457/1644/381 460/1647/384 -f 461/1648/385 460/1647/384 462/1649/386 -f 463/1650/387 461/1648/385 462/1649/386 -f 463/1650/387 462/1649/386 464/1651/388 -f 465/1652/389 463/1650/387 464/1651/388 -f 465/1652/389 464/1651/388 466/1653/389 -f 467/1654/380 468/1655/25 469/1656/25 -f 467/1654/380 469/1656/25 470/1657/380 -f 471/1658/39 467/1654/380 470/1657/380 -f 471/1658/39 470/1657/380 472/1659/39 -f 473/1660/45 471/1658/39 472/1659/39 -f 473/1660/45 472/1659/39 474/1661/45 -f 458/1645/382 473/1660/45 474/1661/45 -f 458/1645/382 474/1661/45 459/1646/383 -f 475/1662/390 476/1663/391 477/1664/391 -f 475/1662/390 477/1664/391 478/1665/392 -f 479/1666/393 475/1662/390 478/1665/392 -f 479/1666/393 478/1665/392 480/1667/394 -f 481/1668/395 479/1666/393 480/1667/394 -f 481/1668/395 480/1667/394 482/1669/396 -f 483/1670/397 481/1668/395 482/1669/396 -f 483/1670/397 482/1669/396 484/1671/397 -f 485/1672/380 486/1673/25 487/1674/25 -f 485/1672/380 487/1674/25 488/1675/380 -f 489/1676/39 485/1672/380 488/1675/380 -f 489/1676/39 488/1675/380 490/1677/39 -f 491/1678/45 489/1676/39 490/1677/39 -f 491/1678/45 490/1677/39 492/1679/45 -f 476/1663/391 491/1678/45 492/1679/45 -f 476/1663/391 492/1679/45 477/1664/391 -f 493/1680/398 494/1681/399 495/1682/400 -f 493/1680/398 495/1682/400 496/1683/401 -f 497/1684/402 493/1680/398 496/1683/401 -f 497/1684/402 496/1683/401 498/1685/403 -f 499/1686/404 497/1684/402 498/1685/403 -f 499/1686/404 498/1685/403 500/1687/405 -f 501/1688/406 499/1686/404 500/1687/405 -f 501/1688/406 500/1687/405 502/1689/406 -f 503/1690/380 504/1691/25 505/1692/25 -f 503/1690/380 505/1692/25 506/1693/380 -f 507/1694/39 503/1690/380 506/1693/380 -f 507/1694/39 506/1693/380 508/1695/39 -f 509/1696/45 507/1694/39 508/1695/39 -f 509/1696/45 508/1695/39 510/1697/45 -f 494/1681/399 509/1696/45 510/1697/45 -f 494/1681/399 510/1697/45 495/1682/400 -f 529/1698/46 530/1699/46 531/1700/26 -f 529/1698/46 531/1700/26 532/1701/26 -f 533/1702/42 534/1703/42 530/1699/46 -f 533/1702/42 530/1699/46 529/1698/46 -f 535/1704/379 536/1705/379 534/1703/42 -f 535/1704/379 534/1703/42 533/1702/42 -f 537/1706/16 538/1707/16 536/1705/379 -f 537/1706/16 536/1705/379 535/1704/379 -f 539/1708/407 540/1709/407 541/1710/408 -f 539/1708/407 541/1710/408 542/1711/409 -f 543/1712/410 544/1713/411 545/1714/412 -f 543/1712/410 545/1714/412 546/1715/410 -f 547/1716/45 548/1717/45 549/1718/413 -f 547/1716/45 549/1718/413 550/1719/413 -f 532/1701/26 531/1700/26 548/1717/45 -f 532/1701/26 548/1717/45 547/1716/45 -f 553/1720/414 554/1721/414 555/1722/415 -f 553/1720/414 555/1722/415 556/1723/415 -f 557/1724/416 558/1725/416 554/1721/414 -f 557/1724/416 554/1721/414 553/1720/414 -f 559/1726/417 560/1727/417 558/1725/416 -f 559/1726/417 558/1725/416 557/1724/416 -f 561/1728/418 562/1729/418 560/1727/417 -f 561/1728/418 560/1727/417 559/1726/417 -f 563/1730/419 564/1731/419 565/1732/420 -f 563/1730/419 565/1732/420 566/1733/420 -f 567/1734/421 568/1735/421 564/1731/419 -f 567/1734/421 564/1731/419 563/1730/419 -f 569/1736/422 570/1737/422 568/1735/421 -f 569/1736/422 568/1735/421 567/1734/421 -f 556/1723/415 555/1722/415 570/1737/422 -f 556/1723/415 570/1737/422 569/1736/422 -f 589/1738/423 590/1739/424 591/1740/425 -f 589/1738/423 591/1740/425 592/1741/426 -f 593/1742/427 594/1743/428 590/1739/424 -f 593/1742/427 590/1739/424 589/1738/423 -f 595/1744/429 596/1745/430 594/1743/428 -f 595/1744/429 594/1743/428 593/1742/427 -f 597/1746/431 598/1747/432 596/1745/430 -f 597/1746/431 596/1745/430 595/1744/429 -f 599/1748/433 600/1749/434 601/1750/435 -f 599/1748/433 601/1750/435 602/1751/435 -f 603/1752/436 604/1753/437 600/1749/434 -f 603/1752/436 600/1749/434 599/1748/433 -f 605/1754/438 606/1755/439 604/1753/437 -f 605/1754/438 604/1753/437 603/1752/436 -f 592/1741/426 591/1740/425 606/1755/439 -f 592/1741/426 606/1755/439 605/1754/438 -f 607/1756/440 608/1757/441 609/1758/442 -f 607/1756/440 609/1758/442 610/1759/443 -f 611/1760/444 607/1756/440 610/1759/443 -f 611/1760/444 610/1759/443 612/1761/445 -f 613/1762/446 611/1760/444 612/1761/445 -f 613/1762/446 612/1761/445 614/1763/447 -f 615/1764/448 613/1762/446 614/1763/447 -f 615/1764/448 614/1763/447 616/1765/448 -f 617/1766/449 618/1767/450 619/1768/450 -f 617/1766/449 619/1768/450 545/1714/412 -f 620/1769/451 617/1766/449 545/1714/412 -f 620/1769/451 545/1714/412 544/1713/411 -f 621/1770/452 620/1769/451 544/1713/411 -f 621/1770/452 544/1713/411 622/1771/453 -f 608/1757/441 621/1770/452 622/1771/453 -f 608/1757/441 622/1771/453 609/1758/442 -f 623/1772/454 624/1773/455 625/1774/456 -f 623/1772/454 625/1774/456 626/1775/457 -f 627/1776/458 623/1772/454 626/1775/457 -f 627/1776/458 626/1775/457 628/1777/459 -f 629/1778/460 627/1776/458 628/1777/459 -f 629/1778/460 628/1777/459 630/1779/461 -f 631/1780/462 629/1778/460 630/1779/461 -f 631/1780/462 630/1779/461 632/1781/462 -f 633/1782/463 634/1783/464 635/1784/464 -f 633/1782/463 635/1784/464 636/1785/465 -f 637/1786/466 633/1782/463 636/1785/465 -f 637/1786/466 636/1785/465 638/1787/467 -f 639/1788/468 637/1786/466 638/1787/467 -f 639/1788/468 638/1787/467 640/1789/469 -f 624/1773/455 639/1788/468 640/1789/469 -f 624/1773/455 640/1789/469 625/1774/456 -f 641/1790/470 642/1791/471 643/1792/472 -f 641/1790/470 643/1792/472 644/1793/470 -f 645/1794/473 646/1795/474 647/1796/475 -f 645/1794/473 647/1796/475 648/1797/476 -f 649/1798/477 650/1799/478 646/1795/474 -f 649/1798/477 646/1795/474 645/1794/473 -f 651/1800/479 652/1801/480 650/1799/478 -f 651/1800/479 650/1799/478 649/1798/477 -f 653/1802/481 654/1803/481 652/1801/480 -f 653/1802/481 652/1801/480 651/1800/479 -f 655/1804/482 656/1805/483 654/1803/481 -f 655/1804/482 654/1803/481 653/1802/481 -f 657/1806/484 658/1807/485 656/1805/483 -f 657/1806/484 656/1805/483 655/1804/482 -f 659/1808/486 660/1809/487 658/1807/485 -f 659/1808/486 658/1807/485 657/1806/484 -f 661/1810/488 662/1811/489 660/1809/487 -f 661/1810/488 660/1809/487 659/1808/486 -f 663/1812/490 664/1813/491 662/1811/489 -f 663/1812/490 662/1811/489 661/1810/488 -f 665/1814/492 666/1815/493 664/1813/491 -f 665/1814/492 664/1813/491 663/1812/490 -f 667/1816/494 668/1817/495 669/1818/493 -f 667/1816/494 669/1818/493 670/1819/492 -f 671/1820/496 672/1821/497 668/1817/495 -f 671/1820/496 668/1817/495 667/1816/494 -f 673/1822/498 674/1823/499 672/1821/497 -f 673/1822/498 672/1821/497 671/1820/496 -f 675/1824/500 676/1825/501 674/1823/499 -f 675/1824/500 674/1823/499 673/1822/498 -f 677/1826/502 678/1827/503 676/1825/501 -f 677/1826/502 676/1825/501 675/1824/500 -f 648/1797/476 647/1796/475 678/1827/503 -f 648/1797/476 678/1827/503 677/1826/502 -f 679/1828/504 680/1829/505 681/1830/506 -f 679/1828/504 681/1830/506 682/1831/507 -f 683/236/28 684/1832/508 685/1833/509 -f 683/236/28 685/1833/509 686/237/28 -f 684/1832/508 687/1834/510 688/1835/511 -f 684/1832/508 688/1835/511 685/1833/509 -f 687/1834/510 689/1836/512 690/1837/513 -f 687/1834/510 690/1837/513 688/1835/511 -f 689/1836/512 691/1838/514 692/1839/515 -f 689/1836/512 692/1839/515 690/1837/513 -f 691/1838/514 693/1840/516 694/1841/516 -f 691/1838/514 694/1841/516 692/1839/515 -f 693/1840/516 695/1842/517 696/1843/518 -f 693/1840/516 696/1843/518 694/1841/516 -f 695/1842/517 697/1844/519 698/1845/520 -f 695/1842/517 698/1845/520 696/1843/518 -f 699/1846/519 700/1847/521 701/1848/522 -f 699/1846/519 701/1848/522 702/1849/520 -f 700/1847/521 703/1850/523 704/1851/524 -f 700/1847/521 704/1851/524 701/1848/522 -f 703/1850/523 705/1852/525 706/1853/526 -f 703/1850/523 706/1853/526 704/1851/524 -f 705/1852/525 707/1854/527 708/1855/528 -f 705/1852/525 708/1855/528 706/1853/526 -f 707/1854/527 709/1856/529 710/1857/530 -f 707/1854/527 710/1857/530 708/1855/528 -f 709/1856/529 711/230/28 712/233/28 -f 709/1856/529 712/233/28 710/1857/530 -f 717/1858/531 718/238/29 719/241/29 -f 717/1858/531 719/241/29 720/1859/532 -f 731/250/29 733/1860/533 734/1861/533 -f 731/250/29 734/1861/533 732/251/29 -f 733/1860/533 735/1862/534 736/1863/535 -f 733/1860/533 736/1863/535 734/1861/533 -f 735/1862/534 737/1864/536 738/1865/537 -f 735/1862/534 738/1865/537 736/1863/535 -f 739/1866/538 740/1867/539 741/1868/540 -f 739/1866/538 741/1868/540 742/1869/537 -f 740/1867/539 743/1870/541 744/1871/541 -f 740/1867/539 744/1871/541 741/1868/540 -f 743/1870/541 745/1872/542 746/1873/543 -f 743/1870/541 746/1873/543 744/1871/541 -f 745/1872/542 747/1874/544 748/1875/545 -f 745/1872/542 748/1875/545 746/1873/543 -f 747/1874/544 749/1876/546 750/1877/547 -f 747/1874/544 750/1877/547 748/1875/545 -f 749/1876/546 717/1858/531 720/1859/532 -f 749/1876/546 720/1859/532 750/1877/547 -f 751/1878/548 752/1879/549 753/1880/550 -f 751/1878/548 753/1880/550 754/1881/548 -f 752/1879/549 755/1882/551 756/1883/552 -f 752/1879/549 756/1883/552 753/1880/550 -f 755/1882/551 757/1884/553 758/1885/554 -f 755/1882/551 758/1885/554 756/1883/552 -f 757/1884/553 759/1886/555 760/1887/556 -f 757/1884/553 760/1887/556 758/1885/554 -f 759/1886/555 761/1888/557 762/1889/557 -f 759/1886/555 762/1889/557 760/1887/556 -f 761/1888/557 763/1890/558 764/1891/559 -f 761/1888/557 764/1891/559 762/1889/557 -f 763/1890/558 765/1892/560 766/1893/561 -f 763/1890/558 766/1893/561 764/1891/559 -f 767/1894/560 768/1895/562 769/1896/562 -f 767/1894/560 769/1896/562 770/1897/561 -f 768/1895/562 771/1898/563 772/1899/564 -f 768/1895/562 772/1899/564 769/1896/562 -f 771/1898/563 773/1900/565 774/1901/565 -f 771/1898/563 774/1901/565 772/1899/564 -f 773/1900/565 775/1902/566 776/1903/566 -f 773/1900/565 776/1903/566 774/1901/565 -f 775/1902/566 777/1904/567 778/1905/567 -f 775/1902/566 778/1905/567 776/1903/566 -f 777/1904/567 779/1906/568 780/1907/568 -f 777/1904/567 780/1907/568 778/1905/567 -f 779/1906/568 781/1908/569 782/1909/569 -f 779/1906/568 782/1909/569 780/1907/568 -f 781/1908/569 783/1910/570 784/1911/570 -f 781/1908/569 784/1911/570 782/1909/569 -f 783/1910/570 751/1878/548 754/1881/548 -f 783/1910/570 754/1881/548 784/1911/570 -f 785/1912/571 786/1913/548 787/1914/572 -f 785/1912/571 787/1914/572 788/1915/573 -f 786/1913/548 789/1916/570 790/1917/574 -f 786/1913/548 790/1917/574 787/1914/572 -f 789/1916/570 791/1918/569 792/1919/575 -f 789/1916/570 792/1919/575 790/1917/574 -f 791/1918/569 793/1920/568 794/1921/576 -f 791/1918/569 794/1921/576 792/1919/575 -f 793/1920/568 795/1922/567 796/1923/577 -f 793/1920/568 796/1923/577 794/1921/576 -f 795/1922/567 797/1924/566 798/1925/578 -f 795/1922/567 798/1925/578 796/1923/577 -f 797/1924/566 799/1926/565 800/1927/579 -f 797/1924/566 800/1927/579 798/1925/578 -f 799/1926/565 801/1928/580 802/1929/581 -f 799/1926/565 802/1929/581 800/1927/579 -f 801/1928/580 803/1930/582 804/1931/583 -f 801/1928/580 804/1931/583 802/1929/581 -f 803/1930/582 805/1932/584 806/1933/585 -f 803/1930/582 806/1933/585 804/1931/583 -f 807/1934/584 808/1935/586 809/1936/587 -f 807/1934/584 809/1936/587 810/1937/585 -f 808/1935/586 811/1938/557 812/1939/588 -f 808/1935/586 812/1939/588 809/1936/587 -f 811/1938/557 813/1940/589 814/1941/590 -f 811/1938/557 814/1941/590 812/1939/588 -f 813/1940/589 815/1942/591 816/1943/592 -f 813/1940/589 816/1943/592 814/1941/590 -f 815/1942/591 817/1944/593 818/1945/507 -f 815/1942/591 818/1945/507 816/1943/592 -f 817/1944/593 785/1912/571 788/1915/573 -f 817/1944/593 788/1915/573 818/1945/507 -f 819/1946/594 820/1947/595 821/1948/596 -f 819/1946/594 821/1948/596 822/1949/597 -f 823/1950/598 819/1946/594 822/1949/597 -f 823/1950/598 822/1949/597 824/1951/599 -f 825/1952/600 823/1950/598 824/1951/599 -f 825/1952/600 824/1951/599 826/1953/601 -f 827/1954/602 825/1952/600 826/1953/601 -f 827/1954/602 826/1953/601 828/1955/602 -f 829/1956/603 827/1954/602 828/1955/602 -f 829/1956/603 828/1955/602 830/1957/604 -f 831/1958/605 829/1956/603 830/1957/604 -f 831/1958/605 830/1957/604 832/1959/606 -f 833/1960/607 831/1958/605 832/1959/606 -f 833/1960/607 832/1959/606 834/1961/608 -f 835/1962/609 833/1960/607 834/1961/608 -f 835/1962/609 834/1961/608 836/1963/610 -f 837/1964/611 835/1962/609 836/1963/610 -f 837/1964/611 836/1963/610 838/1965/612 -f 839/1966/613 837/1964/611 838/1965/612 -f 839/1966/613 838/1965/612 840/1967/614 -f 841/1968/615 842/1969/613 843/1970/614 -f 841/1968/615 843/1970/614 844/1971/616 -f 845/1972/617 841/1968/615 844/1971/616 -f 845/1972/617 844/1971/616 846/1973/618 -f 847/1974/619 845/1972/617 846/1973/618 -f 847/1974/619 846/1973/618 848/1975/620 -f 849/1976/621 847/1974/619 848/1975/620 -f 849/1976/621 848/1975/620 850/1977/622 -f 851/1978/623 849/1976/621 850/1977/622 -f 851/1978/623 850/1977/622 852/1979/624 -f 820/1947/595 851/1978/623 852/1979/624 -f 820/1947/595 852/1979/624 821/1948/596 -f 853/1980/625 854/1981/625 855/1982/38 -f 853/1980/625 855/1982/38 856/1983/38 -f 857/1984/626 858/1985/626 854/1981/625 -f 857/1984/626 854/1981/625 853/1980/625 -f 859/1986/627 860/1987/627 858/1985/626 -f 859/1986/627 858/1985/626 857/1984/626 -f 861/1988/628 862/1989/628 863/1990/25 -f 861/1988/628 863/1990/25 864/1991/25 -f 865/1992/39 866/1993/39 862/1989/628 -f 865/1992/39 862/1989/628 861/1988/628 -f 873/1994/629 874/1995/630 875/1996/631 -f 873/1994/629 875/1996/631 876/1997/631 -f 877/1998/632 878/1999/632 874/1995/630 -f 877/1998/632 874/1995/630 873/1994/629 -f 879/2000/633 880/2001/633 878/1999/632 -f 879/2000/633 878/1999/632 877/1998/632 -f 881/2002/634 882/2003/634 883/2004/635 -f 881/2002/634 883/2004/635 884/2005/635 -f 885/2006/636 886/2007/636 882/2003/634 -f 885/2006/636 882/2003/634 881/2002/634 -f 876/1997/631 875/1996/631 886/2007/636 -f 876/1997/631 886/2007/636 885/2006/636 -f 983/2008/625 984/2009/38 985/2010/38 -f 983/2008/625 985/2010/38 986/2011/625 -f 987/2012/626 983/2008/625 986/2011/625 -f 987/2012/626 986/2011/625 988/2013/626 -f 989/2014/637 987/2012/626 988/2013/626 -f 989/2014/637 988/2013/626 990/2015/16 -f 991/2016/628 992/2017/25 993/2018/25 -f 991/2016/628 993/2018/25 994/2019/628 -f 995/2020/39 991/2016/628 994/2019/628 -f 995/2020/39 994/2019/628 996/2021/39 -f 1029/2022/638 1030/2023/639 1031/2024/639 -f 1029/2022/638 1031/2024/639 1032/2025/638 -f 1041/2026/16 1042/2027/627 1043/2028/379 -f 1041/2026/16 1043/2028/379 1044/2029/379 -f 1049/2030/640 1050/2031/640 1051/2032/641 -f 1049/2030/640 1051/2032/641 1052/2033/642 -f 1052/2033/642 1051/2032/641 1053/2034/643 -f 1052/2033/642 1053/2034/643 1054/2035/644 -f 1055/2036/645 1056/2037/646 1057/2038/646 -f 1055/2036/645 1057/2038/646 1058/2039/645 -f 1059/2040/647 1060/2041/648 1061/2042/649 -f 1059/2040/647 1061/2042/649 1062/2043/649 -f 1063/2044/650 1064/2045/650 1065/2046/650 -f 1063/2044/650 1065/2046/650 1066/2047/650 -f 1067/2048/651 1068/2049/652 1069/2050/648 -f 1067/2048/651 1069/2050/648 1070/2051/647 -f 1071/2052/653 1072/2053/654 1073/2054/654 -f 1071/2052/653 1073/2054/654 1074/2055/653 -f 1072/2053/654 1075/2056/655 1076/2057/655 -f 1072/2053/654 1076/2057/655 1073/2054/654 -f 1075/2056/655 1077/2058/656 1078/2059/656 -f 1075/2056/655 1078/2059/656 1076/2057/655 -f 1077/2058/656 1079/2060/657 1080/2061/657 -f 1077/2058/656 1080/2061/657 1078/2059/656 -f 1079/2060/657 1081/2062/658 1082/2063/658 -f 1079/2060/657 1082/2063/658 1080/2061/657 -f 1083/2064/658 1084/2065/659 1085/2066/659 -f 1083/2064/658 1085/2066/659 1086/2067/658 -f 1084/2065/659 1087/2068/660 1088/2069/660 -f 1084/2065/659 1088/2069/660 1085/2066/659 -f 1087/2068/660 1071/2052/653 1074/2055/653 -f 1087/2068/660 1074/2055/653 1088/2069/660 -f 1107/2070/661 1108/2071/661 1109/2072/662 -f 1107/2070/661 1109/2072/662 1110/2073/663 -f 1111/2074/664 1112/2075/664 1113/2076/665 -f 1111/2074/664 1113/2076/665 1114/2077/665 -f 1115/2078/666 1116/2079/667 1117/2080/668 -f 1115/2078/666 1117/2080/668 1118/2081/669 -f 1119/2082/670 1120/2083/670 1121/2084/671 -f 1119/2082/670 1121/2084/671 1122/2085/671 -f 1123/2086/672 1124/2087/673 1125/2088/672 -f 1123/2086/672 1125/2088/672 1126/2089/673 -f 1127/2090/674 1128/2091/674 1129/2092/675 -f 1127/2090/674 1129/2092/675 1130/2093/676 -f 1131/2094/677 1132/2095/678 1133/2096/679 -f 1131/2094/677 1133/2096/679 1134/2097/678 -f 1135/2098/680 1136/2099/681 1137/2100/682 -f 1135/2098/680 1137/2100/682 1138/2101/683 -f 1203/2102/26 1204/2103/684 1205/2104/684 -f 1203/2102/26 1205/2104/684 1206/2105/26 -f 1204/2103/684 1207/2106/685 1208/2107/686 -f 1204/2103/684 1208/2107/686 1205/2104/684 -f 1209/2108/685 1203/2102/26 1206/2105/26 -f 1209/2108/685 1206/2105/26 1210/2109/686 -f 1211/2110/687 1212/2111/688 1213/2112/689 -f 1211/2110/687 1213/2112/689 1214/2113/690 -f 1215/2114/688 1216/2115/691 1217/2116/692 -f 1215/2114/688 1217/2116/692 1218/2117/693 -f 1216/2115/691 1211/2110/687 1214/2113/690 -f 1216/2115/691 1214/2113/690 1217/2116/692 -f 1219/2118/694 1220/2119/695 1221/2120/696 -f 1219/2118/694 1221/2120/696 1222/2121/697 -f 1223/2122/698 1224/2123/699 1225/2124/700 -f 1223/2122/698 1225/2124/700 1226/2125/701 -f 1224/2123/699 1219/2118/694 1222/2121/697 -f 1224/2123/699 1222/2121/697 1225/2124/700 -f 1227/2126/26 1228/2127/702 1229/2128/702 -f 1227/2126/26 1229/2128/702 1230/2129/26 -f 1228/2127/702 1231/2130/703 1232/2131/704 -f 1228/2127/702 1232/2131/704 1229/2128/702 -f 1233/2132/705 1227/2126/26 1230/2129/26 -f 1233/2132/705 1230/2129/26 1234/2133/704 -f 1235/2134/706 1236/2135/707 1237/2136/708 -f 1235/2134/706 1237/2136/708 1238/2137/709 -f 1236/2135/707 1239/2138/1 1240/2139/1 -f 1236/2135/707 1240/2139/1 1237/2136/708 -f 1239/2138/1 1241/2140/710 1242/2141/710 -f 1239/2138/1 1242/2141/710 1240/2139/1 -f 1243/2142/710 1244/2143/711 1245/2144/711 -f 1243/2142/710 1245/2144/711 1246/2145/710 -f 1244/2143/711 1247/2146/712 1248/2147/713 -f 1244/2143/711 1248/2147/713 1245/2144/711 -f 1247/2146/712 1249/2148/3 1250/2149/3 -f 1247/2146/712 1250/2149/3 1248/2147/713 -f 1249/2148/3 1251/2150/714 1252/2151/714 -f 1249/2148/3 1252/2151/714 1250/2149/3 -f 1251/2150/714 1235/2134/706 1238/2137/709 -f 1251/2150/714 1238/2137/709 1252/2151/714 -f 1253/2152/715 1254/2153/716 1255/2154/717 -f 1253/2152/715 1255/2154/717 1256/2155/718 -f 1254/2153/716 1257/2156/1 1258/2157/1 -f 1254/2153/716 1258/2157/1 1255/2154/717 -f 1259/2158/3 1260/2159/719 1261/2160/720 -f 1259/2158/3 1261/2160/720 1262/2161/3 -f 1260/2159/719 1253/2152/715 1256/2155/718 -f 1260/2159/719 1256/2155/718 1261/2160/720 -f 1263/2162/721 1264/2163/721 1265/2164/721 -f 1263/2162/721 1265/2164/721 1266/2165/721 -f 1267/2166/722 1268/2167/722 1269/2168/722 -f 1267/2166/722 1269/2168/722 1270/2169/722 -f 1271/2170/723 1272/2171/723 1273/2172/724 -f 1271/2170/723 1273/2172/724 1274/2173/723 -f 1275/2174/725 1276/2175/726 1277/2176/725 -f 1275/2174/725 1277/2176/725 1278/2177/726 -f 1295/2178/26 1296/2179/42 1297/2180/42 -f 1295/2178/26 1297/2180/42 1298/2181/26 -f 1296/2179/42 1299/2182/16 1300/2183/16 -f 1296/2179/42 1300/2183/16 1297/2180/42 -f 1299/2182/16 1301/2184/36 1302/2185/36 -f 1299/2182/16 1302/2185/36 1300/2183/16 -f 1301/2184/36 1303/2186/27 1304/2187/27 -f 1301/2184/36 1304/2187/27 1302/2185/36 -f 1303/2186/27 1305/2188/727 1306/2189/33 -f 1303/2186/27 1306/2189/33 1304/2187/27 -f 1307/2190/728 1308/2191/25 1309/2192/25 -f 1307/2190/728 1309/2192/25 1310/2193/33 -f 1308/2191/25 1311/2194/39 1312/2195/39 -f 1308/2191/25 1312/2195/39 1309/2192/25 -f 1311/2194/39 1295/2178/26 1298/2181/26 -f 1311/2194/39 1298/2181/26 1312/2195/39 -f 1315/2196/26 1316/2197/42 1317/2198/42 -f 1315/2196/26 1317/2198/42 1318/2199/26 -f 1316/2197/42 1319/2200/16 1320/2201/16 -f 1316/2197/42 1320/2201/16 1317/2198/42 -f 1319/2200/16 1321/2202/36 1322/2203/36 -f 1319/2200/16 1322/2203/36 1320/2201/16 -f 1321/2202/36 1323/2204/27 1324/2205/27 -f 1321/2202/36 1324/2205/27 1322/2203/36 -f 1323/2204/27 1325/2206/33 1326/2207/33 -f 1323/2204/27 1326/2207/33 1324/2205/27 -f 1325/2206/33 1327/2208/25 1328/2209/25 -f 1325/2206/33 1328/2209/25 1326/2207/33 -f 1327/2208/25 1329/2210/729 1330/2211/730 -f 1327/2208/25 1330/2211/730 1328/2209/25 -f 1331/2212/731 1315/2196/26 1318/2199/26 -f 1331/2212/731 1318/2199/26 1332/2213/39 -f 1335/2214/732 1336/2215/733 1337/2216/734 -f 1335/2214/732 1337/2216/734 1338/2217/735 -f 1336/2215/733 1339/2218/736 1340/2219/737 -f 1336/2215/733 1340/2219/737 1337/2216/734 -f 1339/2218/736 1341/2220/738 1342/2221/739 -f 1339/2218/736 1342/2221/739 1340/2219/737 -f 1341/2220/738 1343/2222/740 1344/2223/741 -f 1341/2220/738 1344/2223/741 1342/2221/739 -f 1338/2217/735 1337/2216/734 1345/2224/742 -f 1338/2217/735 1345/2224/742 1346/2225/743 -f 1337/2216/734 1340/2219/737 1347/2226/742 -f 1337/2216/734 1347/2226/742 1345/2224/742 -f 1340/2219/737 1342/2221/739 1348/2227/742 -f 1340/2219/737 1348/2227/742 1347/2226/742 -f 1348/2227/742 1342/2221/739 1344/2223/741 -f 1348/2227/742 1344/2223/741 1349/2228/742 -f 1350/2229/744 1351/2230/745 1352/2231/746 -f 1350/2229/744 1352/2231/746 1353/2232/747 -f 1351/2230/745 1354/2233/745 1355/2234/748 -f 1351/2230/745 1355/2234/748 1352/2231/746 -f 1355/2234/748 1354/2233/745 1356/2235/745 -f 1355/2234/748 1356/2235/745 1357/2236/749 -f 1357/2236/749 1356/2235/745 1358/2237/745 -f 1357/2236/749 1358/2237/745 1359/2238/750 -f 1360/2239/751 1361/2240/752 1362/2241/753 -f 1360/2239/751 1362/2241/753 1363/2242/754 -f 1363/2242/754 1362/2241/753 1364/2243/755 -f 1363/2242/754 1364/2243/755 1365/2244/756 -f 1365/2244/756 1364/2243/755 1366/2245/757 -f 1365/2244/756 1366/2245/757 1367/2246/758 -f 1366/2245/757 1368/2247/759 1369/2248/760 -f 1366/2245/757 1369/2248/760 1367/2246/758 -f 1370/2249/761 1371/2250/762 1344/2223/741 -f 1370/2249/761 1344/2223/741 1343/2222/740 -f 1371/2250/762 1372/2251/763 1349/2228/742 -f 1371/2250/762 1349/2228/742 1344/2223/741 -f 1372/2251/763 1373/2252/764 1358/2237/745 -f 1372/2251/763 1358/2237/745 1349/2228/742 -f 1359/2238/750 1374/2253/765 1375/2254/766 -f 1359/2238/750 1375/2254/766 1368/2247/759 -f 1361/2240/752 1353/2232/747 1352/2231/746 -f 1361/2240/752 1352/2231/746 1362/2241/753 -f 1362/2241/753 1352/2231/746 1355/2234/748 -f 1362/2241/753 1355/2234/748 1364/2243/755 -f 1364/2243/755 1355/2234/748 1357/2236/749 -f 1364/2243/755 1357/2236/749 1366/2245/757 -f 1357/2236/749 1359/2238/750 1368/2247/759 -f 1357/2236/749 1368/2247/759 1366/2245/757 -f 1376/2255/767 1369/2248/760 1368/2247/759 -f 1376/2255/767 1368/2247/759 1375/2254/766 -f 1346/2225/743 1345/2224/742 1351/2230/745 -f 1346/2225/743 1351/2230/745 1350/2229/744 -f 1345/2224/742 1347/2226/742 1354/2233/745 -f 1345/2224/742 1354/2233/745 1351/2230/745 -f 1354/2233/745 1347/2226/742 1348/2227/742 -f 1354/2233/745 1348/2227/742 1356/2235/745 -f 1356/2235/745 1348/2227/742 1349/2228/742 -f 1356/2235/745 1349/2228/742 1358/2237/745 -f 1373/2252/764 1374/2253/765 1359/2238/750 -f 1373/2252/764 1359/2238/750 1358/2237/745 -f 1381/2256/768 1382/2257/769 1383/2258/770 -f 1381/2256/768 1383/2258/770 1384/2259/769 -f 1385/2260/771 1386/2261/771 1387/2262/772 -f 1385/2260/771 1387/2262/772 1388/2263/771 -f 1397/2264/773 1398/2265/773 1399/2266/774 -f 1397/2264/773 1399/2266/774 1400/2267/775 -f 1401/2268/776 1402/2269/776 1403/2270/776 -f 1401/2268/776 1403/2270/776 1404/2271/776 -f 1405/2272/777 1406/2273/778 1407/2274/778 -f 1405/2272/777 1407/2274/778 1408/2275/778 -f 1409/2276/779 1410/2277/779 1411/2278/779 -f 1409/2276/779 1411/2278/779 1412/2279/780 -f 1413/2280/781 1414/2281/781 1415/2282/782 -f 1413/2280/781 1415/2282/782 1416/2283/782 -f 1417/2284/783 1418/2285/784 1419/2286/784 -f 1417/2284/783 1419/2286/784 1420/2287/784 -f 1421/2288/785 1422/2289/785 1423/2290/785 -f 1421/2288/785 1423/2290/785 1424/2291/785 -f 1425/2292/786 1426/2293/787 1427/2294/787 -f 1425/2292/786 1427/2294/787 1428/2295/787 -f 1429/2296/788 1430/2297/788 1431/2298/788 -f 1429/2296/788 1431/2298/788 1432/2299/788 -f 1433/2300/789 1434/2301/789 1435/2302/789 -f 1433/2300/789 1435/2302/789 1436/2303/789 -f 1437/2304/790 1438/2305/790 1439/2306/790 -f 1437/2304/790 1439/2306/790 1440/2307/790 -f 1441/2308/791 1442/2309/791 1443/2310/791 -f 1441/2308/791 1443/2310/791 1444/2311/791 -f 1445/2312/792 1446/2313/792 1447/2314/793 -f 1445/2312/792 1447/2314/793 1448/2315/794 -f 1449/2316/795 1450/2317/795 1451/2318/796 -f 1449/2316/795 1451/2318/796 1452/2319/795 -f 1453/512/797 1454/2320/798 1455/513/798 -f 1457/2321/799 1458/2322/800 1459/2323/799 -f 1457/2321/799 1459/2323/799 1460/2324/799 -f 1461/2325/801 1462/2326/801 1463/2327/801 -f 1461/2325/801 1463/2327/801 1464/2328/801 -f 1469/519/802 1470/2329/802 1471/520/802 -f 1473/522/803 1474/2330/804 1475/523/803 -f 1485/2331/805 1486/2332/805 1487/2333/805 -f 1485/2331/805 1487/2333/805 1488/2334/805 -f 1493/2335/806 1494/2336/807 1495/2337/806 -f 1493/2335/806 1495/2337/806 1496/2338/806 -f 1497/2339/808 1498/2340/808 1499/2341/808 -f 1497/2339/808 1499/2341/808 1500/2342/808 -f 1501/2343/809 1502/2344/810 1503/2345/809 -f 1501/2343/809 1503/2345/809 1504/2346/809 -f 1505/2347/811 1506/2348/811 1507/2349/811 -f 1505/2347/811 1507/2349/811 1508/2350/811 -f 1513/2351/812 1514/2352/813 1515/2353/814 -f 1513/2351/812 1515/2353/814 1516/2354/813 -f 1517/2355/815 1518/2356/815 1519/2357/815 -f 1517/2355/815 1519/2357/815 1520/2358/815 -f 1521/2359/816 1522/2360/816 1523/2361/816 -f 1521/2359/816 1523/2361/816 1524/2362/816 -f 1525/2363/817 1526/2364/818 1527/2365/818 -f 1525/2363/817 1527/2365/818 1528/2366/819 -f 1529/2367/820 1530/2368/821 1531/2369/820 -f 1529/2367/820 1531/2369/820 1532/2370/821 -f 1533/2371/572 1534/2372/581 1535/2373/822 -f 1533/2371/572 1535/2373/822 1536/2374/573 -f 1536/2374/573 1535/2373/822 679/1828/504 -f 1536/2374/573 679/1828/504 682/1831/507 -f 1537/2375/823 1538/2376/824 1534/2372/581 -f 1537/2375/823 1534/2372/581 1533/2371/572 -f 680/1829/505 1539/2377/825 1540/2378/826 -f 680/1829/505 1540/2378/826 681/1830/506 -f 1541/2379/827 1542/2380/828 1538/2376/824 -f 1541/2379/827 1538/2376/824 1537/2375/823 -f 1543/2381/576 1544/2382/829 1542/2380/828 -f 1543/2381/576 1542/2380/828 1541/2379/827 -f 1549/546/28 1550/545/28 1551/2383/471 -f 1549/546/28 1551/2383/471 1552/2384/472 -f 1552/2384/472 1551/2383/471 643/1792/472 -f 1552/2384/472 643/1792/472 642/1791/471 -f 1553/2385/830 1554/2386/831 641/1790/470 -f 1553/2385/830 641/1790/470 644/1793/470 -f 1555/2387/832 1556/2388/832 1554/2386/831 -f 1555/2387/832 1554/2386/831 1553/2385/830 -f 352/1587/343 1565/2389/833 1566/2390/833 -f 352/1587/343 1566/2390/833 349/1584/340 -f 278/1530/291 283/1535/834 1567/2391/293 -f 278/1530/291 1567/2391/293 1568/2392/291 -f 1597/2393/835 1598/2394/835 1599/2395/836 -f 1597/2393/835 1599/2395/836 1600/2396/836 -f 1601/2397/380 1602/2398/380 1603/2399/25 -f 1601/2397/380 1603/2399/25 1604/2400/837 -f 70/1403/181 72/1405/183 80/1413/189 -f 70/1403/181 80/1413/189 79/1412/188 -f 75/1408/184 74/1407/163 71/1404/182 -f 75/1408/184 71/1404/182 70/1403/181 -f 76/1409/185 78/1411/187 82/1415/191 -f 76/1409/185 82/1415/191 13/1392/170 -f 79/1412/188 81/1414/190 77/1410/186 -f 79/1412/188 77/1410/186 76/1409/185 -f 72/1405/183 1609/2401/838 1610/2402/839 -f 72/1405/183 1610/2402/839 80/1413/189 -f 80/1413/189 1610/2402/839 1611/2403/840 -f 80/1413/189 1611/2403/840 81/1414/190 -f 71/1404/182 1612/2404/841 1609/2401/838 -f 71/1404/182 1609/2401/838 72/1405/183 -f 74/1407/163 1613/2405/204 1612/2404/841 -f 74/1407/163 1612/2404/841 71/1404/182 -f 14/1393/171 82/1415/191 131/1419/195 -f 14/1393/171 131/1419/195 142/1429/205 -f 78/1411/187 132/1420/196 131/1419/195 -f 78/1411/187 131/1419/195 82/1415/191 -f 77/1410/186 1614/2406/842 132/1420/196 -f 77/1410/186 132/1420/196 78/1411/187 -f 81/1414/190 1611/2403/840 1614/2406/842 -f 81/1414/190 1614/2406/842 77/1410/186 -f 144/1431/207 145/1432/208 128/1416/192 -f 144/1431/207 128/1416/192 130/1418/194 -f 1615/587/16 135/589/16 134/1422/198 -f 1617/2407/843 1618/2408/199 1619/2409/844 -f 1617/2407/843 1619/2409/844 1620/2410/192 -f 1621/2411/845 1622/2412/846 1623/2413/846 -f 1621/2411/845 1623/2413/846 1624/2414/212 -f 1625/2415/847 1626/2416/3 1627/2417/31 -f 1625/2415/847 1627/2417/31 1628/2418/848 -f 1629/2419/849 1625/2415/847 1628/2418/848 -f 1629/2419/849 1628/2418/848 1630/2420/849 -f 1610/2402/839 1609/2401/838 1631/2421/850 -f 1610/2402/839 1631/2421/850 1632/2422/851 -f 1610/2402/839 1632/2422/851 1633/2423/852 -f 1610/2402/839 1633/2423/852 1611/2403/840 -f 1609/2401/838 1612/2404/841 1634/2424/853 -f 1609/2401/838 1634/2424/853 1631/2421/850 -f 1613/2405/204 1635/2425/221 1634/2424/853 -f 1613/2405/204 1634/2424/853 1612/2404/841 -f 1614/2406/842 1636/2426/854 129/1417/193 -f 1614/2406/842 129/1417/193 132/1420/196 -f 1611/2403/840 1633/2423/852 1636/2426/854 -f 1611/2403/840 1636/2426/854 1614/2406/842 -f 132/1420/196 129/1417/193 128/1416/192 -f 132/1420/196 128/1416/192 133/1421/197 -f 1649/2427/855 1650/2428/856 1651/2429/223 -f 1649/2427/855 1651/2429/223 1652/2430/226 -f 1650/2428/856 1657/2431/857 1658/2432/227 -f 1650/2428/856 1658/2432/227 1651/2429/223 -f 1659/2433/858 1660/2434/859 1650/2428/856 -f 1659/2433/858 1650/2428/856 1649/2427/855 -f 1663/2435/233 1664/2436/860 1665/2437/861 -f 1663/2435/233 1665/2437/861 1666/2438/234 -f 1658/2432/227 1657/2431/857 1667/2439/862 -f 1658/2432/227 1667/2439/862 1668/2440/863 -f 1660/2434/859 1669/2441/864 1657/2431/857 -f 1660/2434/859 1657/2431/857 1650/2428/856 -f 1670/2442/865 1671/2443/866 1660/2434/859 -f 1670/2442/865 1660/2434/859 1659/2433/858 -f 1664/2436/860 1674/2444/867 1675/2445/868 -f 1664/2436/860 1675/2445/868 1665/2437/861 -f 1676/2446/243 1677/2447/869 1664/2436/860 -f 1676/2446/243 1664/2436/860 1663/2435/233 -f 1678/2448/870 1679/2449/871 1680/2450/872 -f 1678/2448/870 1680/2450/872 1681/2451/873 -f 1669/2441/864 1682/2452/874 1667/2439/862 -f 1669/2441/864 1667/2439/862 1657/2431/857 -f 1671/2443/866 1683/2453/875 1669/2441/864 -f 1671/2443/866 1669/2441/864 1660/2434/859 -f 1684/2454/876 1685/2455/877 1671/2443/866 -f 1684/2454/876 1671/2443/866 1670/2442/865 -f 1674/2444/867 1688/2456/878 1689/2457/879 -f 1674/2444/867 1689/2457/879 1675/2445/868 -f 1677/2447/869 1690/2458/880 1674/2444/867 -f 1677/2447/869 1674/2444/867 1664/2436/860 -f 1676/2446/243 1691/2459/881 1692/2460/882 -f 1676/2446/243 1692/2460/882 1677/2447/869 -f 1697/2461/883 1698/2462/884 1680/2450/872 -f 1697/2461/883 1680/2450/872 1699/2463/885 -f 1683/2453/875 1700/2464/886 1682/2452/874 -f 1683/2453/875 1682/2452/874 1669/2441/864 -f 1685/2455/877 1701/2465/887 1683/2453/875 -f 1685/2455/877 1683/2453/875 1671/2443/866 -f 1702/2466/888 1703/2467/889 1704/2468/890 -f 1702/2466/888 1704/2468/890 1705/2469/888 -f 1688/2456/878 1706/2470/891 1707/2471/892 -f 1688/2456/878 1707/2471/892 1689/2457/879 -f 1690/2458/880 1708/2472/893 1688/2456/878 -f 1690/2458/880 1688/2456/878 1674/2444/867 -f 1692/2460/882 1709/2473/894 1690/2458/880 -f 1692/2460/882 1690/2458/880 1677/2447/869 -f 1710/2474/895 1711/2475/896 1712/2476/897 -f 1710/2474/895 1712/2476/897 1713/2477/898 -f 1716/2478/899 1717/2479/900 1698/2462/884 -f 1716/2478/899 1698/2462/884 1697/2461/883 -f 1701/2465/887 1718/2480/901 1700/2464/886 -f 1701/2465/887 1700/2464/886 1683/2453/875 -f 1703/2467/889 1719/2481/902 1720/2482/902 -f 1703/2467/889 1720/2482/902 1721/2483/890 -f 1708/2472/893 1722/2484/903 1706/2470/891 -f 1708/2472/893 1706/2470/891 1688/2456/878 -f 1709/2473/894 1723/2485/904 1708/2472/893 -f 1709/2473/894 1708/2472/893 1690/2458/880 -f 1711/2475/896 1724/2486/905 1725/2487/906 -f 1711/2475/896 1725/2487/906 1712/2476/897 -f 1716/2478/899 1728/2488/907 1729/2489/908 -f 1716/2478/899 1729/2489/908 1717/2479/900 -f 1719/2481/902 1730/2490/27 1731/2491/27 -f 1719/2481/902 1731/2491/27 1720/2482/902 -f 1723/2485/904 1732/2492/909 1722/2484/903 -f 1723/2485/904 1722/2484/903 1708/2472/893 -f 1724/2486/905 1733/2493/910 1734/2494/911 -f 1724/2486/905 1734/2494/911 1725/2487/906 -f 1737/2495/912 1738/2496/913 1739/623/76 -f 1737/2495/912 1739/623/76 1740/622/76 -f 1734/2494/911 1733/2493/910 1741/2497/914 -f 1734/2494/911 1741/2497/914 1742/2498/915 -f 1743/2499/916 1744/2500/1 1745/2501/1 -f 1743/2499/916 1745/2501/1 1746/2502/916 -f 1746/2502/916 1747/2503/917 1748/2504/917 -f 1746/2502/916 1748/2504/917 1743/2499/916 -f 1749/2505/918 1750/2506/919 1751/2507/919 -f 1749/2505/918 1751/2507/919 1752/2508/920 -f 1698/2462/884 1753/2509/884 1681/2451/873 -f 1698/2462/884 1681/2451/873 1680/2450/872 -f 1717/2479/900 1754/2510/921 1753/2509/884 -f 1717/2479/900 1753/2509/884 1698/2462/884 -f 1711/2475/896 1755/2511/922 1756/2512/905 -f 1711/2475/896 1756/2512/905 1724/2486/905 -f 1717/2479/900 1729/2489/908 1757/2513/923 -f 1717/2479/900 1757/2513/923 1754/2510/921 -f 1724/2486/905 1756/2512/905 1758/2514/924 -f 1724/2486/905 1758/2514/924 1733/2493/910 -f 1733/2493/910 1758/2514/924 1761/2515/925 -f 1733/2493/910 1761/2515/925 1741/2497/914 -f 1682/2452/874 1697/2461/883 1699/2463/885 -f 1682/2452/874 1699/2463/885 1667/2439/862 -f 1700/2464/886 1716/2478/899 1697/2461/883 -f 1700/2464/886 1697/2461/883 1682/2452/874 -f 1692/2460/882 1712/2476/897 1725/2487/906 -f 1692/2460/882 1725/2487/906 1709/2473/894 -f 1718/2480/901 1728/2488/907 1716/2478/899 -f 1718/2480/901 1716/2478/899 1700/2464/886 -f 1709/2473/894 1725/2487/906 1734/2494/911 -f 1709/2473/894 1734/2494/911 1723/2485/904 -f 1730/2490/27 1738/2496/913 1737/2495/912 -f 1730/2490/27 1737/2495/912 1731/2491/27 -f 1723/2485/904 1734/2494/911 1742/2498/915 -f 1723/2485/904 1742/2498/915 1732/2492/909 -f 1679/2449/871 1762/2516/926 1699/2463/885 -f 1679/2449/871 1699/2463/885 1680/2450/872 -f 1711/2475/896 1710/2474/895 1763/2517/927 -f 1711/2475/896 1763/2517/927 1755/2511/922 -f 1667/2439/862 1699/2463/885 1762/2516/926 -f 1667/2439/862 1762/2516/926 1668/2440/863 -f 1692/2460/882 1691/2459/881 1713/2477/898 -f 1692/2460/882 1713/2477/898 1712/2476/897 -f 1764/626/928 1766/628/303 1767/2518/928 -f 1770/2519/929 1771/2520/930 1772/2521/931 -f 1770/2519/929 1772/2521/931 1773/2522/932 -f 1773/2522/932 1772/2521/931 1774/2523/3 -f 1773/2522/932 1774/2523/3 1775/2524/3 -f 1776/2525/933 1777/2526/934 1778/2527/935 -f 1776/2525/933 1778/2527/935 1779/2528/936 -f 1777/2526/934 1780/2529/937 1781/2530/938 -f 1777/2526/934 1781/2530/938 1778/2527/935 -f 1782/2531/939 1783/2532/940 1784/2533/941 -f 1782/2531/939 1784/2533/941 1785/2534/941 -f 1786/2535/942 1787/2536/943 1788/2537/944 -f 1786/2535/942 1788/2537/944 1789/2538/945 -f 1790/2539/946 1788/2537/944 1791/2540/947 -f 1790/2539/946 1791/2540/947 1792/2541/948 -f 1797/2542/949 1770/2519/929 1773/2522/932 -f 1797/2542/949 1773/2522/932 1798/2543/949 -f 1799/2544/950 1800/2545/950 1772/2521/931 -f 1799/2544/950 1772/2521/931 1771/2520/930 -f 1801/2546/951 1802/2547/952 1803/2548/952 -f 1801/2546/951 1803/2548/952 1804/2549/953 -f 1805/2550/954 1806/2551/955 1807/2552/956 -f 1805/2550/954 1807/2552/956 1808/2553/957 -f 1809/2554/958 1810/2555/959 1811/2556/960 -f 1809/2554/958 1811/2556/960 1812/2557/961 -f 1776/2525/933 1813/2558/962 1814/2559/963 -f 1776/2525/933 1814/2559/963 1777/2526/934 -f 1788/2537/944 1787/2536/943 1815/2560/964 -f 1788/2537/944 1815/2560/964 1791/2540/947 -f 1777/2526/934 1814/2559/963 1816/2561/965 -f 1777/2526/934 1816/2561/965 1780/2529/937 -f 1788/2537/944 1790/2539/946 1817/2562/966 -f 1788/2537/944 1817/2562/966 1789/2538/945 -f 1782/2531/939 1801/2546/951 1804/2549/953 -f 1782/2531/939 1804/2549/953 1783/2532/940 -f 1786/2535/942 1809/2554/958 1812/2557/961 -f 1786/2535/942 1812/2557/961 1787/2536/943 -f 1813/2558/962 1818/2563/967 1805/2550/954 -f 1813/2558/962 1805/2550/954 1814/2559/963 -f 1787/2536/943 1812/2557/961 1819/2564/968 -f 1787/2536/943 1819/2564/968 1815/2560/964 -f 1814/2559/963 1805/2550/954 1808/2553/957 -f 1814/2559/963 1808/2553/957 1816/2561/965 -f 1820/2565/969 1821/2566/970 1822/2567/971 -f 1820/2565/969 1822/2567/971 1823/2568/972 -f 1824/2569/973 1825/2570/346 1826/2571/346 -f 1824/2569/973 1826/2571/346 1827/2572/974 -f 1836/2573/975 1837/2574/976 1838/2575/977 -f 1836/2573/975 1838/2575/977 1839/2576/978 -f 1837/2574/976 1840/2577/979 1841/2578/980 -f 1837/2574/976 1841/2578/980 1838/2575/977 -f 1842/2579/981 1843/2580/982 1844/2581/983 -f 1842/2579/981 1844/2581/983 1845/2582/984 -f 1846/2583/985 1847/2584/986 1848/2585/357 -f 1846/2583/985 1848/2585/357 1849/2586/360 -f 1850/2587/987 1836/2573/975 1839/2576/978 -f 1850/2587/987 1839/2576/978 1851/2588/987 -f 1840/2577/979 1852/2589/988 1853/2590/988 -f 1840/2577/979 1853/2590/988 1841/2578/980 -f 1842/2579/981 1854/2591/989 1855/2592/989 -f 1842/2579/981 1855/2592/989 1843/2580/982 -f 1845/2582/984 1844/2581/983 1847/2584/986 -f 1845/2582/984 1847/2584/986 1846/2583/985 -f 1856/2593/990 1857/2594/991 1858/2595/992 -f 1856/2593/990 1858/2595/992 1859/2596/993 -f 1860/2597/994 1824/2569/973 1827/2572/974 -f 1860/2597/994 1827/2572/974 1861/2598/995 -f 1857/2594/991 1860/2597/994 1861/2598/995 -f 1857/2594/991 1861/2598/995 1858/2595/992 -f 1862/2599/996 1863/2600/997 1864/2601/997 -f 1862/2599/996 1864/2601/997 1865/2602/998 -f 1866/2603/999 1821/2566/970 1820/2565/969 -f 1866/2603/999 1820/2565/969 1867/2604/1000 -f 1865/2602/998 1866/2603/999 1867/2604/1000 -f 1865/2602/998 1867/2604/1000 1862/2599/996 -f 1856/2593/990 1859/2596/993 1868/2605/1001 -f 1856/2593/990 1868/2605/1001 1869/2606/1001 -f 1910/2607/1002 1911/2608/1003 1912/2609/1003 -f 1910/2607/1002 1912/2609/1003 1913/2610/1002 -f 1911/2608/1003 1914/2611/36 1915/2612/36 -f 1911/2608/1003 1915/2612/36 1912/2609/1003 -f 1914/2611/36 1916/2613/1004 1917/2614/1004 -f 1914/2611/36 1917/2614/1004 1915/2612/36 -f 1916/2613/1004 1918/2615/16 1919/2616/16 -f 1916/2613/1004 1919/2616/16 1917/2614/1004 -f 1920/2617/25 1921/2618/1005 1922/2619/1005 -f 1920/2617/25 1922/2619/1005 1923/2620/25 -f 1921/2618/1005 1924/2621/1006 1925/2622/1006 -f 1921/2618/1005 1925/2622/1006 1922/2619/1005 -f 1926/2623/1007 1927/2624/1008 1928/2625/1009 -f 1926/2623/1007 1928/2625/1009 1929/2626/1009 -f 1930/2627/1010 1910/2607/1002 1913/2610/1002 -f 1930/2627/1010 1913/2610/1002 1931/2628/1010 -f 1932/2629/1011 1933/2630/1012 1934/2631/1013 -f 1932/2629/1011 1934/2631/1013 1935/2632/1014 -f 1935/2632/1014 1934/2631/1013 1936/2633/1015 -f 1935/2632/1014 1936/2633/1015 1937/2634/1016 -f 1937/2634/1016 1936/2633/1015 1938/2635/1017 -f 1937/2634/1016 1938/2635/1017 1939/2636/1018 -f 1939/2636/1018 1938/2635/1017 1940/2637/389 -f 1939/2636/1018 1940/2637/389 1941/2638/389 -f 1942/2639/25 1943/2640/25 1944/2641/1005 -f 1942/2639/25 1944/2641/1005 1945/2642/1005 -f 1945/2642/1005 1944/2641/1005 1946/2643/33 -f 1945/2642/1005 1946/2643/33 1926/2623/1007 -f 1926/2623/1007 1946/2643/33 1947/2644/110 -f 1926/2623/1007 1947/2644/110 1927/2624/1008 -f 1927/2624/1008 1947/2644/110 1933/2630/1012 -f 1927/2624/1008 1933/2630/1012 1932/2629/1011 -f 1948/2645/1019 1949/2646/1020 1950/2647/1021 -f 1948/2645/1019 1950/2647/1021 1951/2648/1022 -f 1951/2648/1022 1950/2647/1021 1952/2649/1023 -f 1951/2648/1022 1952/2649/1023 1953/2650/1024 -f 1953/2650/1024 1952/2649/1023 1954/2651/1025 -f 1953/2650/1024 1954/2651/1025 1955/2652/1026 -f 1955/2652/1026 1954/2651/1025 1956/2653/397 -f 1955/2652/1026 1956/2653/397 1957/2654/397 -f 1958/2655/25 1959/2656/25 1960/2657/1005 -f 1958/2655/25 1960/2657/1005 1961/2658/1005 -f 1961/2658/1005 1960/2657/1005 1962/2659/33 -f 1961/2658/1005 1962/2659/33 1963/2660/33 -f 1963/2660/33 1962/2659/33 1964/2661/110 -f 1963/2660/33 1964/2661/110 1965/2662/110 -f 1965/2662/110 1964/2661/110 1949/2646/1020 -f 1965/2662/110 1949/2646/1020 1948/2645/1019 -f 1966/2663/1027 1967/2664/1028 1968/2665/1029 -f 1966/2663/1027 1968/2665/1029 1969/2666/1030 -f 1969/2666/1030 1968/2665/1029 1970/2667/1031 -f 1969/2666/1030 1970/2667/1031 1971/2668/1032 -f 1971/2668/1032 1970/2667/1031 1972/2669/1033 -f 1971/2668/1032 1972/2669/1033 1973/2670/1034 -f 1973/2670/1034 1972/2669/1033 1974/2671/406 -f 1973/2670/1034 1974/2671/406 1975/2672/406 -f 1976/2673/25 1977/2674/25 1978/2675/1005 -f 1976/2673/25 1978/2675/1005 1979/2676/1005 -f 1979/2676/1005 1978/2675/1005 1980/2677/33 -f 1979/2676/1005 1980/2677/33 1981/2678/33 -f 1981/2678/33 1980/2677/33 1982/2679/110 -f 1981/2678/33 1982/2679/110 1983/2680/110 -f 1983/2680/110 1982/2679/110 1967/2664/1028 -f 1983/2680/110 1967/2664/1028 1966/2663/1027 -f 1929/2626/1009 1998/2681/1 1995/694/1 -f 1929/2626/1009 1995/694/1 1994/693/1 -f 1928/2625/1009 1999/697/1 1998/2681/1 -f 1928/2625/1009 1998/2681/1 1929/2626/1009 -f 1987/686/1 1999/697/1 1928/2625/1009 -f 2000/2682/27 2001/2683/111 2002/2684/111 -f 2000/2682/27 2002/2684/111 2003/2685/27 -f 2001/2683/111 2004/2686/36 2005/2687/36 -f 2001/2683/111 2005/2687/36 2002/2684/111 -f 2004/2686/36 2006/2688/1004 2007/2689/1004 -f 2004/2686/36 2007/2689/1004 2005/2687/36 -f 2006/2688/1004 2008/2690/16 2009/2691/16 -f 2006/2688/1004 2009/2691/16 2007/2689/1004 -f 2010/2692/408 2011/2693/1035 2012/2694/1036 -f 2010/2692/408 2012/2694/1036 2013/2695/409 -f 2011/2693/1035 2014/2696/1037 2015/2697/1038 -f 2011/2693/1035 2015/2697/1038 2012/2694/1036 -f 2014/2696/1037 2016/2698/110 2017/2699/110 -f 2014/2696/1037 2017/2699/110 2015/2697/1038 -f 2016/2698/110 2000/2682/27 2003/2685/27 -f 2016/2698/110 2003/2685/27 2017/2699/110 -f 2022/2700/1039 2023/2701/1040 2024/2702/1040 -f 2022/2700/1039 2024/2702/1040 2025/2703/1039 -f 2026/2704/1041 2022/2700/1039 2025/2703/1039 -f 2026/2704/1041 2025/2703/1039 2027/2705/1041 -f 2028/2706/1042 2026/2704/1041 2027/2705/1041 -f 2028/2706/1042 2027/2705/1041 2029/2707/1042 -f 2030/2708/418 2028/2706/1042 2029/2707/1042 -f 2030/2708/418 2029/2707/1042 2031/2709/418 -f 2032/2710/1043 2033/2711/420 2034/2712/420 -f 2032/2710/1043 2034/2712/420 2035/2713/1043 -f 2036/2714/1044 2032/2710/1043 2035/2713/1043 -f 2036/2714/1044 2035/2713/1043 2037/2715/1044 -f 2038/2716/1045 2036/2714/1044 2037/2715/1044 -f 2038/2716/1045 2037/2715/1044 2039/2717/1045 -f 2023/2701/1040 2038/2716/1045 2039/2717/1045 -f 2023/2701/1040 2039/2717/1045 2024/2702/1040 -f 2058/2718/1046 2059/2719/1047 2060/2720/1048 -f 2058/2718/1046 2060/2720/1048 2061/2721/1049 -f 2059/2719/1047 2062/2722/1050 2063/2723/1051 -f 2059/2719/1047 2063/2723/1051 2060/2720/1048 -f 2062/2722/1050 2064/2724/1052 2065/2725/1053 -f 2062/2722/1050 2065/2725/1053 2063/2723/1051 -f 2064/2724/1052 2066/2726/431 2067/2727/432 -f 2064/2724/1052 2067/2727/432 2065/2725/1053 -f 2068/2728/435 2069/2729/1054 2070/2730/1055 -f 2068/2728/435 2070/2730/1055 2071/2731/435 -f 2069/2729/1054 2072/2732/1056 2073/2733/1057 -f 2069/2729/1054 2073/2733/1057 2070/2730/1055 -f 2072/2732/1056 2074/2734/1058 2075/2735/1059 -f 2072/2732/1056 2075/2735/1059 2073/2733/1057 -f 2074/2734/1058 2058/2718/1046 2061/2721/1049 -f 2074/2734/1058 2061/2721/1049 2075/2735/1059 -f 2076/2736/1060 2077/2737/1061 2078/2738/1062 -f 2076/2736/1060 2078/2738/1062 2079/2739/1063 -f 2079/2739/1063 2078/2738/1062 2080/2740/1064 -f 2079/2739/1063 2080/2740/1064 2081/2741/1065 -f 2081/2741/1065 2080/2740/1064 2082/2742/1066 -f 2081/2741/1065 2082/2742/1066 2083/2743/1067 -f 2083/2743/1067 2082/2742/1066 2084/2744/448 -f 2083/2743/1067 2084/2744/448 2085/2745/448 -f 2086/2746/450 2087/2747/450 2088/2748/1068 -f 2086/2746/450 2088/2748/1068 2089/2749/1069 -f 2089/2749/1069 2088/2748/1068 2090/2750/1070 -f 2089/2749/1069 2090/2750/1070 2091/2751/1071 -f 2091/2751/1071 2090/2750/1070 2092/2752/1072 -f 2091/2751/1071 2092/2752/1072 2093/2753/1073 -f 2093/2753/1073 2092/2752/1072 2077/2737/1061 -f 2093/2753/1073 2077/2737/1061 2076/2736/1060 -f 2094/2754/1074 2095/2755/1075 2096/2756/1076 -f 2094/2754/1074 2096/2756/1076 2097/2757/1077 -f 2097/2757/1077 2096/2756/1076 2098/2758/1078 -f 2097/2757/1077 2098/2758/1078 2099/2759/1079 -f 2099/2759/1079 2098/2758/1078 2100/2760/1080 -f 2099/2759/1079 2100/2760/1080 2101/2761/1081 -f 2101/2761/1081 2100/2760/1080 2102/2762/462 -f 2101/2761/1081 2102/2762/462 2103/2763/462 -f 2104/2764/464 2105/2765/464 2106/2766/1082 -f 2104/2764/464 2106/2766/1082 2107/2767/1083 -f 2107/2767/1083 2106/2766/1082 2108/2768/1084 -f 2107/2767/1083 2108/2768/1084 2109/2769/1085 -f 2109/2769/1085 2108/2768/1084 2110/2770/1086 -f 2109/2769/1085 2110/2770/1086 2111/2771/1087 -f 2111/2771/1087 2110/2770/1086 2095/2755/1075 -f 2111/2771/1087 2095/2755/1075 2094/2754/1074 -f 2112/2772/1088 2113/2773/1089 2114/2774/1090 -f 2112/2772/1088 2114/2774/1090 2115/2775/1090 -f 2116/2776/1091 2117/2777/1092 2118/2778/1093 -f 2116/2776/1091 2118/2778/1093 2119/2779/1094 -f 2117/2777/1092 2120/2780/1095 2121/2781/1096 -f 2117/2777/1092 2121/2781/1096 2118/2778/1093 -f 2120/2780/1095 2122/2782/1097 2123/2783/1098 -f 2120/2780/1095 2123/2783/1098 2121/2781/1096 -f 2122/2782/1097 2124/2784/1099 2125/2785/1100 -f 2122/2782/1097 2125/2785/1100 2123/2783/1098 -f 2124/2784/1099 2126/2786/1101 2127/2787/1102 -f 2124/2784/1099 2127/2787/1102 2125/2785/1100 -f 2126/2786/1101 2128/2788/1103 2129/2789/1104 -f 2126/2786/1101 2129/2789/1104 2127/2787/1102 -f 2128/2788/1103 2130/2790/1105 2131/2791/1106 -f 2128/2788/1103 2131/2791/1106 2129/2789/1104 -f 2130/2790/1105 2132/2792/1107 2133/2793/1108 -f 2130/2790/1105 2133/2793/1108 2131/2791/1106 -f 2132/2792/1107 2134/2794/1109 2135/2795/1110 -f 2132/2792/1107 2135/2795/1110 2133/2793/1108 -f 2134/2794/1109 2136/2796/1111 2137/2797/1112 -f 2134/2794/1109 2137/2797/1112 2135/2795/1110 -f 2138/2798/1113 2139/2799/1114 2140/2800/1115 -f 2138/2798/1113 2140/2800/1115 2141/2801/1112 -f 2139/2799/1114 2142/2802/1116 2143/2803/1117 -f 2139/2799/1114 2143/2803/1117 2140/2800/1115 -f 2142/2802/1116 2144/2804/1118 2145/2805/1119 -f 2142/2802/1116 2145/2805/1119 2143/2803/1117 -f 2144/2804/1118 2146/2806/1120 2147/2807/1121 -f 2144/2804/1118 2147/2807/1121 2145/2805/1119 -f 2146/2806/1120 2148/2808/1122 2149/2809/1123 -f 2146/2806/1120 2149/2809/1123 2147/2807/1121 -f 2148/2808/1122 2116/2776/1091 2119/2779/1094 -f 2148/2808/1122 2119/2779/1094 2149/2809/1123 -f 2150/2810/1124 2151/2811/1125 2152/2812/1126 -f 2150/2810/1124 2152/2812/1126 2153/2813/1127 -f 2158/2814/1128 2159/2815/1128 2160/2816/1128 -f 2158/2814/1128 2160/2816/1128 2161/2817/1128 -f 2162/2818/1129 2163/2819/1129 2164/2820/1129 -f 2162/2818/1129 2164/2820/1129 2165/2821/1129 -f 2166/2822/1130 2167/2823/1130 2168/2824/1131 -f 2166/2822/1130 2168/2824/1131 2169/2825/1130 -f 2170/2826/1132 2171/2827/1132 2172/2828/1133 -f 2170/2826/1132 2172/2828/1133 2173/2829/1132 -f 2174/2830/1134 2175/2831/1134 2176/2832/1135 -f 2174/2830/1134 2176/2832/1135 2177/2833/1135 -f 2178/2834/1136 2179/2835/1136 2180/2836/1136 -f 2178/2834/1136 2180/2836/1136 2181/2837/1137 -f 2182/2838/1138 2183/2839/1138 2184/2840/1138 -f 2182/2838/1138 2184/2840/1138 2185/2841/1138 -f 2186/2842/1139 2187/2843/1139 2188/2844/1139 -f 2186/2842/1139 2188/2844/1139 2189/2845/1139 -f 2198/2846/1140 2199/2847/1140 2200/2848/1140 -f 2198/2846/1140 2200/2848/1140 2201/2849/1140 -f 2250/2850/1141 2251/2851/1141 2252/2852/1142 -f 2250/2850/1141 2252/2852/1142 2253/2853/1141 -f 2254/2854/1143 2255/2855/1143 2256/2856/1143 -f 2254/2854/1143 2256/2856/1143 2257/2857/1143 -f 2258/2858/1144 2259/2859/1144 2260/2860/1145 -f 2258/2858/1144 2260/2860/1145 2261/2861/1145 -f 2262/2862/1146 2263/2863/1147 2264/2864/1147 -f 2262/2862/1146 2264/2864/1147 2265/2865/1147 -f 2266/2866/1148 2267/2867/1148 2268/2868/1148 -f 2266/2866/1148 2268/2868/1148 2269/2869/1149 -f 2270/2870/1150 2271/2871/1150 2272/2872/1150 -f 2270/2870/1150 2272/2872/1150 2273/2873/1150 -f 2274/2874/1151 2275/2875/1151 2276/2876/1151 -f 2274/2874/1151 2276/2876/1151 2277/2877/1151 -f 2278/2878/1152 2279/2879/1153 2280/2880/1153 -f 2278/2878/1152 2280/2880/1153 2281/2881/1153 -f 2294/2882/1154 2295/2883/1155 2296/2884/1155 -f 2294/2882/1154 2296/2884/1155 2297/2885/1154 -f 2306/2886/1156 2307/2887/1156 2308/2888/1156 -f 2306/2886/1156 2308/2888/1156 2309/2889/1156 -f 2310/800/95 2311/2890/95 2312/801/95 -f 2342/831/103 2344/833/103 2345/2891/103 -f 2386/2892/1157 2387/2893/1157 2388/2894/1157 -f 2386/2892/1157 2388/2894/1157 2389/2895/1157 -f 2398/2896/1158 2399/2897/1158 2400/2898/1158 -f 2398/2896/1158 2400/2898/1158 2401/2899/1158 -f 2406/2900/1159 2407/2901/1159 2408/2902/1159 -f 2406/2900/1159 2408/2902/1159 2409/2903/1159 -f 2116/2776/1091 2410/2904/1160 2411/2905/1161 -f 2116/2776/1091 2411/2905/1161 2117/2777/1092 -f 2117/2777/1092 2411/2905/1161 2412/2906/1162 -f 2117/2777/1092 2412/2906/1162 2120/2780/1095 -f 2120/2780/1095 2412/2906/1162 2413/2907/1163 -f 2120/2780/1095 2413/2907/1163 2122/2782/1097 -f 2122/2782/1097 2413/2907/1163 2414/2908/1164 -f 2122/2782/1097 2414/2908/1164 2124/2784/1099 -f 2124/2784/1099 2414/2908/1164 2415/2909/1165 -f 2124/2784/1099 2415/2909/1165 2126/2786/1101 -f 2126/2786/1101 2415/2909/1165 2416/2910/1166 -f 2126/2786/1101 2416/2910/1166 2128/2788/1103 -f 2128/2788/1103 2416/2910/1166 2417/2911/1167 -f 2128/2788/1103 2417/2911/1167 2130/2790/1105 -f 2130/2790/1105 2417/2911/1167 2418/2912/1168 -f 2130/2790/1105 2418/2912/1168 2132/2792/1107 -f 2132/2792/1107 2418/2912/1168 2419/2913/1169 -f 2132/2792/1107 2419/2913/1169 2134/2794/1109 -f 2134/2794/1109 2419/2913/1169 2420/2914/1170 -f 2134/2794/1109 2420/2914/1170 2136/2796/1111 -f 2138/2798/1113 2421/2915/1170 2422/2916/1171 -f 2138/2798/1113 2422/2916/1171 2139/2799/1114 -f 2139/2799/1114 2422/2916/1171 2423/2917/1172 -f 2139/2799/1114 2423/2917/1172 2142/2802/1116 -f 2142/2802/1116 2423/2917/1172 2424/2918/1173 -f 2142/2802/1116 2424/2918/1173 2144/2804/1118 -f 2144/2804/1118 2424/2918/1173 2425/2919/1174 -f 2144/2804/1118 2425/2919/1174 2146/2806/1120 -f 2146/2806/1120 2425/2919/1174 2426/2920/1175 -f 2146/2806/1120 2426/2920/1175 2148/2808/1122 -f 2148/2808/1122 2426/2920/1175 2410/2904/1160 -f 2148/2808/1122 2410/2904/1160 2116/2776/1091 -f 2427/2921/37 2428/2922/1176 2429/2923/1176 -f 2427/2921/37 2429/2923/1176 2430/2924/37 -f 2428/2922/1176 2431/2925/1177 2432/2926/1177 -f 2428/2922/1176 2432/2926/1177 2429/2923/1176 -f 2431/2925/1177 2433/2927/16 2434/2928/627 -f 2431/2925/1177 2434/2928/627 2432/2926/1177 -f 2435/2929/25 2436/2930/1178 2437/2931/1178 -f 2435/2929/25 2437/2931/1178 2438/2932/25 -f 2436/2930/1178 2439/2933/33 2440/2934/33 -f 2436/2930/1178 2440/2934/33 2437/2931/1178 -f 2447/2935/1179 2448/2936/1180 2449/2937/1180 -f 2447/2935/1179 2449/2937/1180 2450/2938/1181 -f 2451/2939/1182 2447/2935/1179 2450/2938/1181 -f 2451/2939/1182 2450/2938/1181 2452/2940/1182 -f 2453/2941/633 2451/2939/1182 2452/2940/1182 -f 2453/2941/633 2452/2940/1182 2454/2942/633 -f 2455/2943/1183 2456/2944/635 2457/2945/635 -f 2455/2943/1183 2457/2945/635 2458/2946/1183 -f 2459/2947/1184 2455/2943/1183 2458/2946/1183 -f 2459/2947/1184 2458/2946/1183 2460/2948/1184 -f 2448/2936/1180 2459/2947/1184 2460/2948/1184 -f 2448/2936/1180 2460/2948/1184 2449/2937/1180 -f 2553/984/36 2555/986/36 2556/2949/36 -f 2557/2950/37 2558/2951/37 2559/2952/1176 -f 2557/2950/37 2559/2952/1176 2560/2953/1176 -f 2560/2953/1176 2559/2952/1176 2561/2954/1177 -f 2560/2953/1176 2561/2954/1177 2562/2955/1177 -f 2562/2955/1177 2561/2954/1177 2563/2956/627 -f 2562/2955/1177 2563/2956/627 2564/2957/16 -f 2565/2958/25 2566/2959/25 2567/2960/1178 -f 2565/2958/25 2567/2960/1178 2568/2961/1178 -f 2568/2961/1178 2567/2960/1178 2569/2962/33 -f 2568/2961/1178 2569/2962/33 2570/2963/33 -f 2603/2964/639 2604/2965/639 2605/2966/1185 -f 2603/2964/639 2605/2966/1185 2606/2967/1185 -f 2615/2968/1004 2616/2969/627 2617/2970/16 -f 2615/2968/1004 2617/2970/16 2618/2971/1004 -f 2623/2972/1186 2624/2973/1187 2625/2974/1188 -f 2623/2972/1186 2625/2974/1188 2626/2975/1189 -f 2624/2973/1187 2627/2976/1190 2628/2977/1191 -f 2624/2973/1187 2628/2977/1191 2625/2974/1188 -f 2627/2976/1190 2629/2978/1192 2630/2979/1193 -f 2627/2976/1190 2630/2979/1193 2628/2977/1191 -f 2631/2980/1194 2632/2981/1195 2633/2982/1196 -f 2631/2980/1194 2633/2982/1196 2634/2983/1197 -f 2632/2981/1195 2635/2984/1198 2636/2985/1199 -f 2632/2981/1195 2636/2985/1199 2633/2982/1196 -f 2635/2984/1198 2637/2986/1194 2638/2987/1197 -f 2635/2984/1198 2638/2987/1197 2636/2985/1199 -f 2639/2988/653 2640/2989/653 2641/2990/654 -f 2639/2988/653 2641/2990/654 2642/2991/654 -f 2642/2991/654 2641/2990/654 2643/2992/655 -f 2642/2991/654 2643/2992/655 2644/2993/655 -f 2644/2993/655 2643/2992/655 2645/2994/656 -f 2644/2993/655 2645/2994/656 2646/2995/656 -f 2646/2995/656 2645/2994/656 2647/2996/657 -f 2646/2995/656 2647/2996/657 2648/2997/657 -f 2648/2997/657 2647/2996/657 2649/2998/658 -f 2648/2997/657 2649/2998/658 2650/2999/658 -f 2651/3000/658 2652/3001/658 2653/3002/659 -f 2651/3000/658 2653/3002/659 2654/3003/659 -f 2654/3003/659 2653/3002/659 2655/3004/660 -f 2654/3003/659 2655/3004/660 2656/3005/660 -f 2656/3005/660 2655/3004/660 2640/2989/653 -f 2656/3005/660 2640/2989/653 2639/2988/653 -f 2675/3006/1200 2676/3007/1201 2677/3008/1200 -f 2675/3006/1200 2677/3008/1200 2678/3009/1202 -f 2679/3010/1203 2680/3011/1204 2681/3012/1205 -f 2679/3010/1203 2681/3012/1205 2682/3013/1205 -f 2683/3014/1206 2684/3015/1206 2685/3016/1207 -f 2683/3014/1206 2685/3016/1207 2686/3017/1208 -f 2687/3018/1209 2688/3019/1210 2689/3020/1211 -f 2687/3018/1209 2689/3020/1211 2690/3021/1212 -f 2691/3022/1213 2692/3023/1214 2693/3024/1215 -f 2691/3022/1213 2693/3024/1215 2694/3025/1213 -f 2695/3026/1216 2696/3027/1217 2697/3028/1218 -f 2695/3026/1216 2697/3028/1218 2698/3029/1219 -f 2699/3030/1220 2700/3031/1221 2701/3032/1222 -f 2699/3030/1220 2701/3032/1222 2702/3033/1223 -f 2703/3034/1224 2704/3035/1225 2705/3036/1226 -f 2703/3034/1224 2705/3036/1226 2706/3037/1227 -f 2771/3038/27 2772/3039/27 2773/3040/1228 -f 2771/3038/27 2773/3040/1228 2774/3041/1228 -f 2774/3041/1228 2773/3040/1228 2775/3042/1229 -f 2774/3041/1228 2775/3042/1229 2776/3043/1230 -f 2777/3044/1230 2778/3045/1229 2772/3039/27 -f 2777/3044/1230 2772/3039/27 2771/3038/27 -f 2779/3046/1231 2780/3047/1232 2781/3048/1233 -f 2779/3046/1231 2781/3048/1233 2782/3049/1234 -f 2783/3050/1234 2784/3051/1235 2785/3052/1236 -f 2783/3050/1234 2785/3052/1236 2786/3053/1237 -f 2786/3053/1237 2785/3052/1236 2780/3047/1232 -f 2786/3053/1237 2780/3047/1232 2779/3046/1231 -f 2787/3054/1238 2788/3055/1239 2789/3056/1240 -f 2787/3054/1238 2789/3056/1240 2790/3057/1241 -f 2791/3058/1242 2792/3059/1243 2793/3060/1244 -f 2791/3058/1242 2793/3060/1244 2794/3061/1245 -f 2794/3061/1245 2793/3060/1244 2788/3055/1239 -f 2794/3061/1245 2788/3055/1239 2787/3054/1238 -f 2795/3062/27 2796/3063/27 2797/3064/1246 -f 2795/3062/27 2797/3064/1246 2798/3065/1246 -f 2798/3065/1246 2797/3064/1246 2799/3066/1247 -f 2798/3065/1246 2799/3066/1247 2800/3067/1248 -f 2801/3068/1249 2802/3069/1247 2796/3063/27 -f 2801/3068/1249 2796/3063/27 2795/3062/27 -f 2803/3070/1250 2804/3071/1251 2805/3072/1252 -f 2803/3070/1250 2805/3072/1252 2806/3073/1253 -f 2806/3073/1253 2805/3072/1252 2807/3074/1 -f 2806/3073/1253 2807/3074/1 2808/3075/1 -f 2808/3075/1 2807/3074/1 2809/3076/1254 -f 2808/3075/1 2809/3076/1254 2810/3077/1254 -f 2811/3078/1254 2812/3079/1255 2813/3080/1256 -f 2811/3078/1254 2813/3080/1256 2814/3081/1256 -f 2814/3081/1256 2813/3080/1256 2815/3082/1257 -f 2814/3081/1256 2815/3082/1257 2816/3083/1258 -f 2816/3083/1258 2815/3082/1257 2817/3084/3 -f 2816/3083/1258 2817/3084/3 2818/3085/3 -f 2818/3085/3 2817/3084/3 2819/3086/1259 -f 2818/3085/3 2819/3086/1259 2820/3087/1259 -f 2820/3087/1259 2819/3086/1259 2804/3071/1251 -f 2820/3087/1259 2804/3071/1251 2803/3070/1250 -f 2821/3088/1260 2822/3089/1261 2823/3090/1262 -f 2821/3088/1260 2823/3090/1262 2824/3091/1263 -f 2824/3091/1263 2823/3090/1262 2825/3092/1 -f 2824/3091/1263 2825/3092/1 2826/3093/1 -f 2827/3094/3 2828/3095/3 2829/3096/1264 -f 2827/3094/3 2829/3096/1264 2830/3097/1265 -f 2830/3097/1265 2829/3096/1264 2822/3089/1261 -f 2830/3097/1265 2822/3089/1261 2821/3088/1260 -f 2831/3098/1266 2832/3099/1266 2833/3100/1266 -f 2831/3098/1266 2833/3100/1266 2834/3101/1266 -f 2835/3102/1267 2836/3103/1267 2837/3104/1267 -f 2835/3102/1267 2837/3104/1267 2838/3105/1267 -f 2839/3106/1268 2840/3107/1268 2841/3108/1269 -f 2839/3106/1268 2841/3108/1269 2842/3109/1268 -f 2843/3110/1270 2844/3111/1271 2845/3112/1270 -f 2843/3110/1270 2845/3112/1270 2846/3113/1271 -f 2851/1117/124 2853/1119/124 2854/3114/124 -f 2863/3115/27 2864/3116/27 2865/3117/36 -f 2863/3115/27 2865/3117/36 2866/3118/36 -f 2866/3118/36 2865/3117/36 2867/3119/16 -f 2866/3118/36 2867/3119/16 2868/3120/16 -f 2868/3120/16 2867/3119/16 2869/3121/42 -f 2868/3120/16 2869/3121/42 2870/3122/42 -f 2870/3122/42 2869/3121/42 2871/3123/26 -f 2870/3122/42 2871/3123/26 2872/3124/26 -f 2872/3124/26 2871/3123/26 2873/3125/39 -f 2872/3124/26 2873/3125/39 2874/3126/731 -f 2875/3127/729 2876/3128/39 2877/3129/25 -f 2875/3127/729 2877/3129/25 2878/3130/25 -f 2878/3130/25 2877/3129/25 2879/3131/33 -f 2878/3130/25 2879/3131/33 2880/3132/33 -f 2880/3132/33 2879/3131/33 2864/3116/27 -f 2880/3132/33 2864/3116/27 2863/3115/27 -f 2883/3133/27 2884/3134/27 2885/3135/36 -f 2883/3133/27 2885/3135/36 2886/3136/36 -f 2886/3136/36 2885/3135/36 2887/3137/16 -f 2886/3136/36 2887/3137/16 2888/3138/16 -f 2888/3138/16 2887/3137/16 2889/3139/42 -f 2888/3138/16 2889/3139/42 2890/3140/42 -f 2890/3140/42 2889/3139/42 2891/3141/26 -f 2890/3140/42 2891/3141/26 2892/3142/26 -f 2892/3142/26 2891/3141/26 2893/3143/39 -f 2892/3142/26 2893/3143/39 2894/3144/39 -f 2894/3144/39 2893/3143/39 2895/3145/25 -f 2894/3144/39 2895/3145/25 2896/3146/25 -f 2896/3146/25 2895/3145/25 2897/3147/33 -f 2896/3146/25 2897/3147/33 2898/3148/1272 -f 2899/3149/727 2900/3150/33 2884/3134/27 -f 2899/3149/727 2884/3134/27 2883/3133/27 -f 2903/3151/1273 2904/3152/1274 2905/3153/1275 -f 2903/3151/1273 2905/3153/1275 2906/3154/1276 -f 2907/3155/1277 2908/3156/1278 2904/3152/1274 -f 2907/3155/1277 2904/3152/1274 2903/3151/1273 -f 2909/3157/1279 2910/3158/1280 2908/3156/1278 -f 2909/3157/1279 2908/3156/1278 2907/3155/1277 -f 2911/3159/1281 2912/3160/1282 2910/3158/1280 -f 2911/3159/1281 2910/3158/1280 2909/3157/1279 -f 2913/3161/1283 2903/3151/1273 2906/3154/1276 -f 2913/3161/1283 2906/3154/1276 2914/3162/1284 -f 2915/3163/1283 2907/3155/1277 2903/3151/1273 -f 2915/3163/1283 2903/3151/1273 2913/3161/1283 -f 2916/3164/1283 2909/3157/1279 2907/3155/1277 -f 2916/3164/1283 2907/3155/1277 2915/3163/1283 -f 2916/3164/1283 2917/3165/1283 2911/3159/1281 -f 2916/3164/1283 2911/3159/1281 2909/3157/1279 -f 2918/3166/1285 2919/3167/1286 2920/3168/1287 -f 2918/3166/1285 2920/3168/1287 2921/3169/1288 -f 2922/3170/1289 2923/3171/1286 2919/3167/1286 -f 2922/3170/1289 2919/3167/1286 2918/3166/1285 -f 2922/3170/1289 2924/3172/1290 2925/3173/1286 -f 2922/3170/1289 2925/3173/1286 2923/3171/1286 -f 2924/3172/1290 2926/3174/1291 2927/3175/1286 -f 2924/3172/1290 2927/3175/1286 2925/3173/1286 -f 2928/3176/1292 2929/3177/1293 2930/3178/1294 -f 2928/3176/1292 2930/3178/1294 2931/3179/1295 -f 2929/3177/1293 2932/3180/1296 2933/3181/1297 -f 2929/3177/1293 2933/3181/1297 2930/3178/1294 -f 2932/3180/1296 2934/3182/1298 2935/3183/1299 -f 2932/3180/1296 2935/3183/1299 2933/3181/1297 -f 2936/3184/1300 2937/3185/1301 2935/3183/1299 -f 2936/3184/1300 2935/3183/1299 2934/3182/1298 -f 2911/3159/1281 2938/3186/1302 2939/3187/1303 -f 2911/3159/1281 2939/3187/1303 2912/3160/1282 -f 2917/3165/1283 2940/3188/1304 2938/3186/1302 -f 2917/3165/1283 2938/3186/1302 2911/3159/1281 -f 2927/3175/1286 2941/3189/1305 2940/3188/1304 -f 2927/3175/1286 2940/3188/1304 2917/3165/1283 -f 2926/3174/1291 2937/3185/1301 2942/3190/1306 -f 2926/3174/1291 2942/3190/1306 2943/3191/1307 -f 2931/3179/1295 2930/3178/1294 2918/3166/1285 -f 2931/3179/1295 2918/3166/1285 2921/3169/1288 -f 2930/3178/1294 2933/3181/1297 2922/3170/1289 -f 2930/3178/1294 2922/3170/1289 2918/3166/1285 -f 2933/3181/1297 2935/3183/1299 2924/3172/1290 -f 2933/3181/1297 2924/3172/1290 2922/3170/1289 -f 2937/3185/1301 2926/3174/1291 2924/3172/1290 -f 2937/3185/1301 2924/3172/1290 2935/3183/1299 -f 2937/3185/1301 2936/3184/1300 2944/3192/1308 -f 2937/3185/1301 2944/3192/1308 2942/3190/1306 -f 2919/3167/1286 2913/3161/1283 2914/3162/1284 -f 2919/3167/1286 2914/3162/1284 2920/3168/1287 -f 2923/3171/1286 2915/3163/1283 2913/3161/1283 -f 2923/3171/1286 2913/3161/1283 2919/3167/1286 -f 2923/3171/1286 2925/3173/1286 2916/3164/1283 -f 2923/3171/1286 2916/3164/1283 2915/3163/1283 -f 2925/3173/1286 2927/3175/1286 2917/3165/1283 -f 2925/3173/1286 2917/3165/1283 2916/3164/1283 -f 2941/3189/1305 2927/3175/1286 2926/3174/1291 -f 2941/3189/1305 2926/3174/1291 2943/3191/1307 -f 2949/3193/1309 2950/3194/1310 2951/3195/1311 -f 2949/3193/1309 2951/3195/1311 2952/3196/1312 -f 2953/3197/1313 2954/3198/1314 2955/3199/1314 -f 2953/3197/1313 2955/3199/1314 2956/3200/1314 -f 2957/1136/128 2959/1138/128 2960/3201/128 -f 2965/3202/1315 2966/3203/1316 2967/3204/1317 -f 2965/3202/1315 2967/3204/1317 2968/3205/1316 -f 2969/3206/1318 2970/3207/1318 2971/3208/1318 -f 2969/3206/1318 2971/3208/1318 2972/3209/1318 -f 2973/3210/1319 2974/3211/1319 2975/3212/1320 -f 2973/3210/1319 2975/3212/1320 2976/3213/1319 -f 2977/3214/1321 2978/3215/1321 2979/3216/1321 -f 2977/3214/1321 2979/3216/1321 2980/3217/1321 -f 2981/3218/1322 2982/3219/1323 2983/3220/1323 -f 2981/3218/1322 2983/3220/1323 2984/3221/1322 -f 2985/3222/1324 2986/3223/1324 2987/3224/1324 -f 2985/3222/1324 2987/3224/1324 2988/3225/1324 -f 2989/3226/1325 2990/3227/1325 2991/3228/1325 -f 2989/3226/1325 2991/3228/1325 2992/3229/1325 -f 2993/3230/1326 2994/3231/1326 2995/3232/1326 -f 2993/3230/1326 2995/3232/1326 2996/3233/1326 -f 2997/3234/1327 2998/3235/1328 2999/3236/1328 -f 2997/3234/1327 2999/3236/1328 3000/3237/1328 -f 3001/3238/1329 3002/3239/1330 3003/3240/1330 -f 3001/3238/1329 3003/3240/1330 3004/3241/1330 -f 3005/3242/1331 3006/3243/1331 3007/3244/1331 -f 3005/3242/1331 3007/3244/1331 3008/3245/1331 -f 3009/3246/1332 3010/3247/1332 3011/3248/1332 -f 3009/3246/1332 3011/3248/1332 3012/3249/1332 -f 3013/3250/1333 3014/3251/1333 3015/3252/1334 -f 3013/3250/1333 3015/3252/1334 3016/3253/1334 -f 3017/3254/1335 3018/3255/1335 3019/3256/1336 -f 3017/3254/1335 3019/3256/1336 3020/3257/1335 -f 3021/3258/1337 3022/3259/1338 3023/3260/1339 -f 3021/3258/1337 3023/3260/1339 3024/3261/1338 -f 3025/3262/1340 3026/3263/1340 3027/3264/1341 -f 3025/3262/1340 3027/3264/1341 3028/3265/1342 -f 3029/3266/1343 3030/3267/1344 3031/3268/1343 -f 3029/3266/1343 3031/3268/1343 3032/3269/1343 -f 3037/3270/1345 3038/3271/1345 3039/3272/1346 -f 3037/3270/1345 3039/3272/1346 3040/3273/1347 -f 3041/1147/1348 3043/1149/1349 3044/3274/1349 -f 3053/3275/1350 3054/3276/1350 3055/3277/1350 -f 3053/3275/1350 3055/3277/1350 3056/3278/1350 -f 3061/3279/1351 3062/3280/1352 3063/3281/1351 -f 3061/3279/1351 3063/3281/1351 3064/3282/1351 -f 3065/3283/1353 3066/3284/1354 3067/3285/1354 -f 3065/3283/1353 3067/3285/1354 3068/3286/1353 -f 3069/3287/1355 3070/3288/1356 3071/3289/1355 -f 3069/3287/1355 3071/3289/1355 3072/3290/1355 -f 3077/3291/1357 3078/3292/1357 3079/3293/1357 -f 3077/3291/1357 3079/3293/1357 3080/3294/1357 -f 3085/3295/1358 3086/3296/1359 3087/3297/1360 -f 3085/3295/1358 3087/3297/1360 3088/3298/1359 -f 3089/3299/1361 3090/3300/1362 3091/3301/1361 -f 3089/3299/1361 3091/3301/1361 3092/3302/1361 -f 3093/3303/1363 3094/3304/1363 3095/3305/1363 -f 3093/3303/1363 3095/3305/1363 3096/3306/1363 -f 3097/3307/1364 3098/3308/1364 3099/3309/1365 -f 3097/3307/1364 3099/3309/1365 3100/3310/1364 -f 3101/3311/1366 3102/3312/1367 3103/3313/1366 -f 3101/3311/1366 3103/3313/1366 3104/3314/1367 -f 3189/3315/1368 3190/3316/1369 3191/3317/1370 -f 3189/3315/1368 3191/3317/1370 3192/3318/1369 -f 2152/2812/1126 3189/3315/1368 3192/3318/1369 -f 2152/2812/1126 3192/3318/1369 2153/2813/1127 -f 3190/3316/1369 3193/1254/89 3194/1257/89 -f 3190/3316/1369 3194/1257/89 3191/3317/1370 -f 2151/2811/1125 2150/2810/1124 3195/3319/1371 -f 2151/2811/1125 3195/3319/1371 3196/3320/1371 -f 3205/3321/1089 3206/1264/84 3207/1265/84 -f 3205/3321/1089 3207/1265/84 3208/3322/1088 -f 2112/2772/1088 3205/3321/1089 3208/3322/1088 -f 2112/2772/1088 3208/3322/1088 2113/2773/1089 -f 2114/2774/1090 3209/3323/1372 3210/3324/1373 -f 2114/2774/1090 3210/3324/1373 2115/2775/1090 -f 3209/3323/1372 3211/3325/1374 3212/3326/1374 -f 3209/3323/1372 3212/3326/1374 3210/3324/1373 -f 3221/3327/833 3222/3328/833 1823/2568/972 -f 3221/3327/833 1823/2568/972 1822/2567/971 -f 1748/2504/917 3223/3329/917 3224/3330/918 -f 1748/2504/917 3224/3330/918 1752/2508/1375 -f 3253/3331/836 3254/3332/1376 3255/3333/1376 -f 3253/3331/836 3255/3333/1376 3256/3334/836 -f 3257/3335/25 3258/3336/1005 3259/3337/1005 -f 3257/3335/25 3259/3337/1005 3260/3338/837 -f 3285/3339/1377 3286/3340/1378 3287/3341/1378 -f 3285/3339/1377 3287/3341/1378 3288/3342/1377 -f 3286/3340/1378 3289/3343/1379 3290/3344/1379 -f 3286/3340/1378 3290/3344/1379 3287/3341/1378 -f 3289/3343/1379 3291/3345/1380 3292/3346/1380 -f 3289/3343/1379 3292/3346/1380 3290/3344/1379 -f 3301/3347/26 3302/3348/1381 3303/3349/1381 -f 3301/3347/26 3303/3349/1381 3304/3350/26 -f 3302/3348/1381 3305/3351/16 3306/3352/16 -f 3302/3348/1381 3306/3352/16 3303/3349/1381 -f 3305/3351/16 3307/3353/1382 3308/3354/1382 -f 3305/3351/16 3308/3354/1382 3306/3352/16 -f 3307/3353/1382 3309/3355/27 3310/3356/27 -f 3307/3353/1382 3310/3356/27 3308/3354/1382 -f 3309/3355/27 3311/3357/33 3312/3358/33 -f 3309/3355/27 3312/3358/33 3310/3356/27 -f 3311/3357/33 3313/3359/837 3314/3360/837 -f 3311/3357/33 3314/3360/837 3312/3358/33 -f 3313/3359/837 3315/3361/39 3316/3362/39 -f 3313/3359/837 3316/3362/39 3314/3360/837 -f 3315/3361/39 3301/3347/26 3304/3350/26 -f 3315/3361/39 3304/3350/26 3316/3362/39 -f 3331/3363/687 3332/3364/688 3333/3365/689 -f 3331/3363/687 3333/3365/689 3334/3366/690 -f 3335/3367/688 3336/3368/691 3337/3369/692 -f 3335/3367/688 3337/3369/692 3338/3370/693 -f 3336/3368/691 3331/3363/687 3334/3366/690 -f 3336/3368/691 3334/3366/690 3337/3369/692 -f 3339/3371/694 3340/3372/695 3341/3373/696 -f 3339/3371/694 3341/3373/696 3342/3374/697 -f 3343/3375/698 3344/3376/699 3345/3377/700 -f 3343/3375/698 3345/3377/700 3346/3378/701 -f 3344/3376/699 3339/3371/694 3342/3374/697 -f 3344/3376/699 3342/3374/697 3345/3377/700 -f 3347/3379/706 3348/3380/707 3349/3381/707 -f 3347/3379/706 3349/3381/707 3350/3382/709 -f 3348/3380/707 3351/3383/1 3352/3384/1 -f 3348/3380/707 3352/3384/1 3349/3381/707 -f 3351/3383/1 3353/3385/710 3354/3386/710 -f 3351/3383/1 3354/3386/710 3352/3384/1 -f 3355/3387/710 3356/3388/711 3357/3389/1383 -f 3355/3387/710 3357/3389/1383 3358/3390/710 -f 3356/3388/711 3359/3391/713 3360/3392/712 -f 3356/3388/711 3360/3392/712 3357/3389/1383 -f 3359/3391/713 3361/3393/3 3362/3394/3 -f 3359/3391/713 3362/3394/3 3360/3392/712 -f 3361/3393/3 3363/3395/714 3364/3396/714 -f 3361/3393/3 3364/3396/714 3362/3394/3 -f 3363/3395/714 3347/3379/706 3350/3382/709 -f 3363/3395/714 3350/3382/709 3364/3396/714 -f 3381/3397/1384 3382/3398/1385 3383/3399/1386 -f 3381/3397/1384 3383/3399/1386 3384/3400/1387 -f 3382/3398/1385 3385/3401/1388 3386/3402/1389 -f 3382/3398/1385 3386/3402/1389 3383/3399/1386 -f 3387/3403/1390 3381/3397/1384 3384/3400/1387 -f 3387/3403/1390 3384/3400/1387 3388/3404/1391 -f 3405/3405/1231 3406/3406/1232 3407/3407/1233 -f 3405/3405/1231 3407/3407/1233 3408/3408/1234 -f 3409/3409/1234 3410/3410/1235 3411/3411/1392 -f 3409/3409/1234 3411/3411/1392 3412/3412/1237 -f 3412/3412/1237 3411/3411/1392 3406/3406/1232 -f 3412/3412/1237 3406/3406/1232 3405/3405/1231 -f 3413/3413/1238 3414/3414/1239 3415/3415/1240 -f 3413/3413/1238 3415/3415/1240 3416/3416/1241 -f 3417/3417/1242 3418/3418/1243 3419/3419/1244 -f 3417/3417/1242 3419/3419/1244 3420/3420/1245 -f 3420/3420/1245 3419/3419/1244 3414/3414/1239 -f 3420/3420/1245 3414/3414/1239 3413/3413/1238 -f 3421/3421/1251 3422/3422/1251 3423/3423/1252 -f 3421/3421/1251 3423/3423/1252 3424/3424/1253 -f 3424/3424/1253 3423/3423/1252 3425/3425/1 -f 3424/3424/1253 3425/3425/1 3426/3426/1 -f 3426/3426/1 3425/3425/1 3427/3427/1254 -f 3426/3426/1 3427/3427/1254 3428/3428/1254 -f 3429/3429/1393 3430/3430/1254 3431/3431/1394 -f 3429/3429/1393 3431/3431/1394 3432/3432/1256 -f 3432/3432/1256 3431/3431/1394 3433/3433/1257 -f 3432/3432/1256 3433/3433/1257 3434/3434/1257 -f 3434/3434/1257 3433/3433/1257 3435/3435/3 -f 3434/3434/1257 3435/3435/3 3436/3436/3 -f 3436/3436/3 3435/3435/3 3437/3437/1259 -f 3436/3436/3 3437/3437/1259 3438/3438/1259 -f 3438/3438/1259 3437/3437/1259 3422/3422/1251 -f 3438/3438/1259 3422/3422/1251 3421/3421/1251 -f 3439/3439/27 3440/3440/27 3441/3441/1395 -f 3439/3439/27 3441/3441/1395 3442/3442/1395 -f 3442/3442/1395 3441/3441/1395 3443/3443/1396 -f 3442/3442/1395 3443/3443/1396 3444/3444/1397 -f 3445/3445/1397 3446/3446/1396 3440/3440/27 -f 3445/3445/1397 3440/3440/27 3439/3439/27 diff --git a/examples/models/yaw_pitch_roll/plane_diffuse.png b/examples/models/yaw_pitch_roll/plane_diffuse.png deleted file mode 100644 index 07371c0..0000000 Binary files a/examples/models/yaw_pitch_roll/plane_diffuse.png and /dev/null differ diff --git a/examples/others/android/example/README.md b/examples/others/android/example/README.md index 8ab1a50..9a15651 100644 --- a/examples/others/android/example/README.md +++ b/examples/others/android/example/README.md @@ -3,28 +3,25 @@ To compile example to shared library you will need [Android NDK](https://developer.android.com/ndk/downloads/index.html). To build Android apk you will need [Android SDK](http://developer.android.com/sdk/index.html#Other). -Export path to Android NDK, point to location where you have unpacked archive (WARNING: NDK 27 is not supported . See https://github.com/raysan5/raylib/issues/4166): +Export path to Android NDK, point to location where you have unpacked archive: export ANDROID_NDK_HOME=/opt/android-ndk Add toolchain bin directory to PATH: - export PATH=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH} + export PATH=${ANDROID_NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:${PATH} Export sysroot and libdirs: - export ANDROID_SYSROOT=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot + export ANDROID_SYSROOT=${ANDROID_NDK_HOME}/sysroot + export ANDROID_PLATFORM=${ANDROID_NDK_HOME}/platforms/android-16/arch-arm export ANDROID_TOOLCHAIN=${ANDROID_NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -Export API version: - - export ANDROID_API=16 - And compile shared library: - CC="armv7a-linux-androideabi${ANDROID_API}-clang" \ - CGO_CFLAGS="-I${ANDROID_SYSROOT}/usr/include -I${ANDROID_SYSROOT}/usr/include/arm-linux-androideabi --sysroot=${ANDROID_SYSROOT} -D__ANDROID_API__=${ANDROID_API}" \ - CGO_LDFLAGS="-L${ANDROID_SYSROOT}/usr/lib/arm-linux-androideabi/${ANDROID_API} -L${ANDROID_TOOLCHAIN}/arm-linux-androideabi/lib --sysroot=${ANDROID_SYSROOT}" \ + CC="arm-linux-androideabi-gcc" \ + CGO_CFLAGS="-I${ANDROID_SYSROOT}/usr/include -I${ANDROID_SYSROOT}/usr/include/arm-linux-androideabi --sysroot=${ANDROID_SYSROOT} -D__ANDROID_API__=16" \ + CGO_LDFLAGS="-L${ANDROID_SYSROOT}/usr/lib/arm-linux-androideabi -L${ANDROID_PLATFORM}/usr/lib -L${ANDROID_TOOLCHAIN}/arm-linux-androideabi/lib -L${ANDROID_TOOLCHAIN}/lib/gcc/arm-linux-androideabi/4.9.x --sysroot=${ANDROID_PLATFORM}" \ CGO_ENABLED=1 GOOS=android GOARCH=arm \ go build -buildmode=c-shared -ldflags="-s -w -extldflags=-Wl,-soname,libexample.so" \ -o=android/libs/armeabi-v7a/libexample.so @@ -33,17 +30,13 @@ To build apk export path to Android SDK, point to location where you unpacked ar export ANDROID_HOME=/opt/android-sdk -And build apk: +And build apk with ant: + + cd android + ant clean debug + +Or with gradle: ./gradlew assembleDebug -If everything is successfully built apk can be found in the android/build/outputs. - - -For aarch64/arm64 replace `arm-linux-androideabi` with `aarch64-linux-android`, set GOARCH to arm64 and use minimum `ANDROID_API=21`. - -### Windows - -To build shared libraries on Windows you can inspect the file `androidcompile.bat` by opening it on a text editor, it can then be configured to generate the libraries when running the .bat file - -See also [instructions](https://developer.android.com/build/building-cmdline#build_bundle) to build a android app bundle for appstore distribution \ No newline at end of file +If everything is successfully built apk can be found in bin/ directory or in the android/build/outputs in case `gradle` is used. diff --git a/examples/others/android/example/android/AndroidManifest.xml b/examples/others/android/example/android/AndroidManifest.xml index 19b1694..20cc5cf 100644 --- a/examples/others/android/example/android/AndroidManifest.xml +++ b/examples/others/android/example/android/AndroidManifest.xml @@ -1,9 +1,10 @@ - + @@ -14,7 +15,6 @@ diff --git a/examples/others/android/example/android/build.gradle b/examples/others/android/example/android/build.gradle index b819fb4..3bb73a0 100644 --- a/examples/others/android/example/android/build.gradle +++ b/examples/others/android/example/android/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.application' android { - namespace = "com.example.android" - compileSdkVersion 34 - buildToolsVersion '34.0.0' + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "com.example.android" minSdkVersion 16 - targetSdkVersion 34 + targetSdkVersion 27 versionCode 1 versionName '1.0' } diff --git a/examples/others/android/example/android/build.xml b/examples/others/android/example/android/build.xml new file mode 100644 index 0000000..3e7a699 --- /dev/null +++ b/examples/others/android/example/android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/others/android/example/android/project.properties b/examples/others/android/example/android/project.properties new file mode 100644 index 0000000..36b004b --- /dev/null +++ b/examples/others/android/example/android/project.properties @@ -0,0 +1,2 @@ +# Project target. +target=android-27 diff --git a/examples/others/android/example/androidcompile.bat b/examples/others/android/example/androidcompile.bat deleted file mode 100644 index e45f342..0000000 --- a/examples/others/android/example/androidcompile.bat +++ /dev/null @@ -1,68 +0,0 @@ -@REM Set your desired api. Max is 31 -@set ANDROID_API=31 -@REM Your library name. If you change it here you should also change it in your android manifest... -@set LIBRARY_NAME=example -@REM Set your android sdk folder here -@set ANDROID_HOME=F:/AndroidSDK -@REM Set your android NDK folder here. WARNING: NDK 27 is not supported yet. See https://github.com/raysan5/raylib/issues/4166 -@set ANDROID_NDK_HOME=F:/AndroidSDK/ndk/23.2.8568313 -@REM The target architecture for android. See https://developer.android.com/ndk/guides/abis. -@REM Valid options are: armeabi-v7a,arm64-v8a,x86,x86_64 or "all" if you want to build for all architectures. -@set TARGET_ARCH="all" -@REM Automatic setup. Should work by default. Do not change anything below here -@set PATH=%ANDROID_NDK_HOME%/toolchains/llvm/prebuilt/windows-x86_64/bin;%PATH% -@set ANDROID_SYSROOT=%ANDROID_NDK_HOME%/toolchains/llvm/prebuilt/windows-x86_64/sysroot -@set ANDROID_TOOLCHAIN=%ANDROID_NDK_HOME%/toolchains/llvm/prebuilt/windows-x86_64 -@IF %TARGET_ARCH% == "all" ( - @GOTO:BUILDALL -) else ( - @GOTO:MAIN -) - -:COMPILE - @echo compiling for platform %FL% and architecture %GOARCH% - @set CGO_CFLAGS="-I%ANDROID_SYSROOT%/usr/include -I%ANDROID_SYSROOT%/usr/include/%TRIPLE% --sysroot=%ANDROID_SYSROOT% -D__ANDROID_API__=%ANDROID_API%" - @set CGO_LDFLAGS="-L%ANDROID_SYSROOT%/usr/lib/%TRIPLE%/%ANDROID_API% -L%ANDROID_TOOLCHAIN%/%TRIPLE%/lib --sysroot=%ANDROID_SYSROOT%" - @set CGO_ENABLED=1 - @set GOOS=android - @set GOARCH=%GOARCH% - @go build -buildmode=c-shared -ldflags="-s -w -extldflags=-Wl,-soname,lib%LIBRARY_NAME%.so" -o=android/libs/%FL%/lib%LIBRARY_NAME%.so -@EXIT /B - -:BUILDALL - @set TARGET_ARCH="armeabi-v7a" - @CALL:MAIN - @set TARGET_ARCH="arm64-v8a" - @CALL:MAIN - @set TARGET_ARCH="x86" - @CALL:MAIN - @set TARGET_ARCH="x86_64" - @CALL:MAIN -@EXIT /B - -:MAIN - @IF %TARGET_ARCH% == "armeabi-v7a" ( - @set CC="armv7a-linux-androideabi%ANDROID_API%-clang" - @set TRIPLE=arm-linux-androideabi - @set FL=armeabi-v7a - @set GOARCH=arm - @CALL:COMPILE ) - @IF %TARGET_ARCH% == "arm64-v8a" ( - @set CC="aarch64-linux-android%ANDROID_API%-clang" - @set TRIPLE=aarch64-linux-android - @set FL=arm64-v8a - @set GOARCH=arm64 - @CALL:COMPILE ) - @IF %TARGET_ARCH% == "x86" ( - @set CC="i686-linux-android%ANDROID_API%-clang" - @set TRIPLE=i686-linux-android - @set FL=x86 - @set GOARCH=386 - @CALL:COMPILE ) - @IF %TARGET_ARCH% == "x86_64" ( - @set CC="x86_64-linux-android%ANDROID_API%-clang" - @set TRIPLE=x86_64-linux-android - @set FL=x86_64 - @set GOARCH=amd64 - @CALL:COMPILE ) -@EXIT /B diff --git a/examples/others/android/example/build.gradle b/examples/others/android/example/build.gradle index 301e2dd..e9f7a57 100644 --- a/examples/others/android/example/build.gradle +++ b/examples/others/android/example/build.gradle @@ -4,7 +4,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.2.2' + classpath 'com.android.tools.build:gradle:3.0.1' } } diff --git a/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties b/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties index b05c5cc..9f7ad18 100644 --- a/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties +++ b/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/examples/others/android/example/main.go b/examples/others/android/example/main.go index bfcfaa2..dc2d7a6 100644 --- a/examples/others/android/example/main.go +++ b/examples/others/android/example/main.go @@ -4,7 +4,7 @@ import ( "os" "runtime" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) // Game states diff --git a/examples/others/bunnymark/main.go b/examples/others/bunnymark/main.go index cb86aa2..d7f1b43 100644 --- a/examples/others/bunnymark/main.go +++ b/examples/others/bunnymark/main.go @@ -3,13 +3,9 @@ package main import ( "fmt" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) -// This is the maximum amount of elements (quads) per batch -// NOTE: This value is defined in [rlgl] module and can be changed there -const maxBatchElements = 8192 - // Bunny type type Bunny struct { Position rl.Vector2 @@ -18,14 +14,15 @@ type Bunny struct { } func main() { - screenWidth := int32(800) - screenHeight := int32(450) + screenWidth := int32(1280) + screenHeight := int32(960) - rl.InitWindow(screenWidth, screenHeight, "raylib [others] example - bunnymark") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - Bunnymark") texture := rl.LoadTexture("wabbit_alpha.png") bunnies := make([]*Bunny, 0) + bunniesCount := 0 rl.SetTargetFPS(60) @@ -36,11 +33,11 @@ func main() { for i := 0; i < 100; i++ { b := &Bunny{} b.Position = rl.GetMousePosition() - b.Speed.X = float32(rl.GetRandomValue(-250, 250)) / 60.0 - b.Speed.Y = float32(rl.GetRandomValue(-250, 250)) / 60.0 - b.Color = rl.NewColor(uint8(rl.GetRandomValue(50, 240)), uint8(rl.GetRandomValue(80, 240)), uint8(rl.GetRandomValue(100, 240)), 255) + b.Speed.X = float32(rl.GetRandomValue(250, 500)) / 60.0 + b.Speed.Y = float32(rl.GetRandomValue(250, 500)-500) / 60.0 bunnies = append(bunnies, b) + bunniesCount++ } } @@ -49,11 +46,11 @@ func main() { b.Position.X += b.Speed.X b.Position.Y += b.Speed.Y - if ((b.Position.X + float32(texture.Width/2)) > float32(screenWidth)) || ((b.Position.X + float32(texture.Width/2)) < 0) { + if (b.Position.X > float32(screenWidth)) || (b.Position.X < 0) { b.Speed.X *= -1 } - if ((b.Position.Y + float32(texture.Height/2)) > float32(screenHeight)) || ((b.Position.Y + float32(texture.Height/2-40)) < 0) { + if (b.Position.Y > float32(screenHeight)) || (b.Position.Y < 0) { b.Speed.Y *= -1 } } @@ -63,20 +60,18 @@ func main() { rl.ClearBackground(rl.RayWhite) for _, b := range bunnies { - // NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS), - // a draw call is launched and buffer starts being filled again; - // before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU... - // Process of sending data is costly and it could happen that GPU data has not been completely - // processed for drawing while new data is tried to be sent (updating current in-use buffers) - // it could generates a stall and consequently a frame drop, limiting the number of drawn bunnies - rl.DrawTexture(texture, int32(b.Position.X), int32(b.Position.Y), b.Color) + // NOTE: When internal QUADS batch limit is reached, a draw call is launched and + // batching buffer starts being filled again; before launching the draw call, + // updated vertex data from internal buffer is send to GPU... it seems it generates + // a stall and consequently a frame drop, limiting number of bunnies drawn at 60 fps + rl.DrawTexture(texture, int32(b.Position.X), int32(b.Position.Y), rl.RayWhite) } - rl.DrawRectangle(0, 0, screenWidth, 40, rl.Black) - rl.DrawText(fmt.Sprintf("bunnies: %d", len(bunnies)), 120, 10, 20, rl.Green) - rl.DrawText(fmt.Sprintf("batched draw calls: %d", 1+len(bunnies)/maxBatchElements), 320, 10, 20, rl.Maroon) + rl.DrawRectangle(0, 0, screenWidth, 40, rl.LightGray) + rl.DrawText("raylib bunnymark", 10, 10, 20, rl.DarkGray) + rl.DrawText(fmt.Sprintf("bunnies: %d", bunniesCount), 400, 10, 20, rl.Red) - rl.DrawFPS(10, 10) + rl.DrawFPS(260, 10) rl.EndDrawing() } diff --git a/examples/others/rpi/basic_window/README.md b/examples/others/rpi/basic_window/README.md new file mode 100644 index 0000000..f548f3a --- /dev/null +++ b/examples/others/rpi/basic_window/README.md @@ -0,0 +1,18 @@ +### Raspberry Pi example + +To cross compile example for Raspberry Pi you will need [RPi toolchain](https://github.com/raspberrypi/tools/tree/master/arm-bcm2708) and [userspace libraries](https://github.com/raspberrypi/firmware) (opt/vc). + +Export path to RPi toolchain: + + export RPI_HOME=/opt/tools/arm-bcm2708/arm-linux-gnueabihf + +Add toolchain bin directory to PATH: + + export PATH=${RPI_HOME}/bin:${PATH} + +And compile example: + + CC=arm-linux-gnueabihf-gcc \ + CGO_CFLAGS="-I/opt/vc/include -I/opt/vc/include/interface/vcos -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads --sysroot=${RPI_HOME}/arm-linux-gnueabihf/sysroot" \ + CGO_LDFLAGS="-L/opt/vc/lib -L/opt/vc/lib64 --sysroot=${RPI_HOME}/arm-linux-gnueabihf/sysroot" \ + CGO_ENABLED=1 GOOS=linux GOARCH=arm go build diff --git a/examples/others/rpi/basic_window/main.go b/examples/others/rpi/basic_window/main.go new file mode 100644 index 0000000..38749a8 --- /dev/null +++ b/examples/others/rpi/basic_window/main.go @@ -0,0 +1,21 @@ +package main + +import "github.com/gen2brain/raylib-go/raylib" + +func main() { + rl.InitWindow(800, 450, "raylib [rpi] example - basic window") + + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LightGray) + + rl.EndDrawing() + } + + rl.CloseWindow() +} diff --git a/examples/others/utils/utils.go b/examples/others/utils/utils.go index 97881fd..1dd5581 100644 --- a/examples/others/utils/utils.go +++ b/examples/others/utils/utils.go @@ -1,15 +1,14 @@ package main import ( + "github.com/gen2brain/raylib-go/raylib" "log" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { rl.SetTraceLogCallback(func(logType int, str string) { level := "" - switch rl.TraceLogLevel(logType) { + switch logType { case rl.LogDebug: level = "Debug" case rl.LogError: @@ -23,7 +22,7 @@ func main() { case rl.LogFatal: level = "Fatal" } - if rl.TraceLogLevel(logType) != rl.LogFatal { + if logType != rl.LogFatal { log.Printf("%s - %s", level, str) } else { log.Fatalf("%s - %s", level, str) diff --git a/examples/physics/box2d/main.go b/examples/physics/box2d/main.go index d2da34e..d0e61b6 100644 --- a/examples/physics/box2d/main.go +++ b/examples/physics/box2d/main.go @@ -4,6 +4,8 @@ import ( "math" "math/rand" + "github.com/gen2brain/raylib-go/raylib" + box2d "github.com/neguse/go-box2d-lite/box2dlite" ) diff --git a/examples/physics/chipmunk/main.go b/examples/physics/chipmunk/main.go index e304182..08e59d3 100644 --- a/examples/physics/chipmunk/main.go +++ b/examples/physics/chipmunk/main.go @@ -5,7 +5,7 @@ import ( "math" "math/rand" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" "github.com/jakecoffman/cp" ) @@ -85,7 +85,7 @@ func main() { for !rl.WindowShouldClose() { // calculate dt now := rl.GetTime() - dt = float32(now - lastTime) + dt = now - lastTime lastTime = now // update the mouse position diff --git a/examples/physics/physac/demo/main.go b/examples/physics/physac/demo/main.go index 8c64634..8fb3777 100644 --- a/examples/physics/physac/demo/main.go +++ b/examples/physics/physac/demo/main.go @@ -1,8 +1,8 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/physics" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/physics" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -52,10 +52,9 @@ func main() { } // Destroy falling physics bodies - for i := 0; i < physics.GetBodiesCount(); i++ { - body := physics.GetBody(i) + for _, body := range physics.GetBodies() { if body.Position.Y > float32(screenHeight)*2 { - body.Destroy() + physics.DestroyBody(body) } } @@ -66,9 +65,7 @@ func main() { rl.DrawFPS(screenWidth-90, screenHeight-30) // Draw created physics bodies - for i := 0; i < physics.GetBodiesCount(); i++ { - body := physics.GetBody(i) - + for i, body := range physics.GetBodies() { vertexCount := physics.GetShapeVerticesCount(i) for j := 0; j < vertexCount; j++ { // Get physics bodies shape vertices to draw lines diff --git a/examples/physics/physac/friction/main.go b/examples/physics/physac/friction/main.go index b384162..6eed272 100644 --- a/examples/physics/physac/friction/main.go +++ b/examples/physics/physac/friction/main.go @@ -1,8 +1,8 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/physics" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/physics" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/physics/physac/movement/main.go b/examples/physics/physac/movement/main.go index 0962a67..164b62f 100644 --- a/examples/physics/physac/movement/main.go +++ b/examples/physics/physac/movement/main.go @@ -1,7 +1,8 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/physics" + "github.com/gen2brain/raylib-go/physics" + "github.com/gen2brain/raylib-go/raylib" ) const ( diff --git a/examples/physics/physac/restitution/main.go b/examples/physics/physac/restitution/main.go index 4658e40..0c069b1 100644 --- a/examples/physics/physac/restitution/main.go +++ b/examples/physics/physac/restitution/main.go @@ -1,8 +1,8 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/physics" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/physics" + "github.com/gen2brain/raylib-go/raylib" ) const ( diff --git a/examples/physics/physac/shatter/main.go b/examples/physics/physac/shatter/main.go index 264a1a5..56ad42f 100644 --- a/examples/physics/physac/shatter/main.go +++ b/examples/physics/physac/shatter/main.go @@ -1,8 +1,8 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/physics" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/physics" + "github.com/gen2brain/raylib-go/raylib" ) const ( @@ -41,14 +41,8 @@ func main() { } if rl.IsMouseButtonPressed(rl.MouseLeftButton) { - //for _, b := range physics.GetBodies() { - for i := 0; i < physics.GetBodiesCount(); i++ { - body := physics.GetBody(i) - if body == nil { - continue - } - - physics.Shatter(body, rl.GetMousePosition(), 10/body.InverseMass) + for _, b := range physics.GetBodies() { + b.Shatter(rl.GetMousePosition(), 10/b.InverseMass) } } diff --git a/examples/shaders/basic_lighting/light.go b/examples/shaders/basic_lighting/light.go deleted file mode 100644 index c398de0..0000000 --- a/examples/shaders/basic_lighting/light.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "fmt" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -type LightType int32 - -const ( - LightTypeDirectional LightType = iota - LightTypePoint -) - -type Light struct { - shader rl.Shader - lightType LightType - position rl.Vector3 - target rl.Vector3 - color rl.Color - enabled int32 - // shader locations - enabledLoc int32 - typeLoc int32 - posLoc int32 - targetLoc int32 - colorLoc int32 -} - -const maxLightsCount = 4 - -var lightCount = 0 - -func NewLight( - lightType LightType, - position, target rl.Vector3, - color rl.Color, - shader rl.Shader) Light { - light := Light{ - shader: shader, - } - if lightCount < maxLightsCount { - light.enabled = 1 - light.lightType = lightType - light.position = position - light.target = target - light.color = color - light.enabledLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].enabled", lightCount)) - light.typeLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].type", lightCount)) - light.posLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].position", lightCount)) - light.targetLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].target", lightCount)) - light.colorLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].color", lightCount)) - light.UpdateValues() - lightCount++ - } - return light -} - -func (lt *Light) UpdateValues() { - // Send to shader light enabled state and type - rl.SetShaderValue(lt.shader, lt.enabledLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.enabled)), 4), rl.ShaderUniformInt) - rl.SetShaderValue(lt.shader, lt.typeLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.lightType)), 4), rl.ShaderUniformInt) - - // Send to shader light position values - rl.SetShaderValue(lt.shader, lt.posLoc, []float32{lt.position.X, lt.position.Y, lt.position.Z}, rl.ShaderUniformVec3) - - // Send to shader light target target values - rl.SetShaderValue(lt.shader, lt.targetLoc, []float32{lt.target.X, lt.target.Y, lt.target.Z}, rl.ShaderUniformVec3) - - // Send to shader light color values - rl.SetShaderValue(lt.shader, lt.colorLoc, - []float32{float32(lt.color.R) / 255, float32(lt.color.G) / 255, float32(lt.color.B) / 255, float32(lt.color.A) / 255}, - rl.ShaderUniformVec4) -} diff --git a/examples/shaders/basic_lighting/lighting.fs b/examples/shaders/basic_lighting/lighting.fs deleted file mode 100644 index 58845c8..0000000 --- a/examples/shaders/basic_lighting/lighting.fs +++ /dev/null @@ -1,82 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec3 fragPosition; -in vec2 fragTexCoord; -//in vec4 fragColor; -in vec3 fragNormal; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -// NOTE: Add here your custom variables - -#define MAX_LIGHTS 4 -#define LIGHT_DIRECTIONAL 0 -#define LIGHT_POINT 1 - -struct MaterialProperty { - vec3 color; - int useSampler; - sampler2D sampler; -}; - -struct Light { - int enabled; - int type; - vec3 position; - vec3 target; - vec4 color; -}; - -// Input lighting values -uniform Light lights[MAX_LIGHTS]; -uniform vec4 ambient; -uniform vec3 viewPos; - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord); - vec3 lightDot = vec3(0.0); - vec3 normal = normalize(fragNormal); - vec3 viewD = normalize(viewPos - fragPosition); - vec3 specular = vec3(0.0); - - // NOTE: Implement here your fragment shader code - - for (int i = 0; i < MAX_LIGHTS; i++) - { - if (lights[i].enabled == 1) - { - vec3 light = vec3(0.0); - - if (lights[i].type == LIGHT_DIRECTIONAL) - { - light = -normalize(lights[i].target - lights[i].position); - } - - if (lights[i].type == LIGHT_POINT) - { - light = normalize(lights[i].position - fragPosition); - } - - float NdotL = max(dot(normal, light), 0.0); - lightDot += lights[i].color.rgb*NdotL; - - float specCo = 0.0; - if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine - specular += specCo; - } - } - - finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); - finalColor += texelColor*(ambient/10.0)*colDiffuse; - - // Gamma correction - finalColor = pow(finalColor, vec4(1.0/2.2)); -} diff --git a/examples/shaders/basic_lighting/lighting.vs b/examples/shaders/basic_lighting/lighting.vs deleted file mode 100644 index f8ec45f..0000000 --- a/examples/shaders/basic_lighting/lighting.vs +++ /dev/null @@ -1,32 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; -in vec4 vertexColor; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matModel; -uniform mat4 matNormal; - -// Output vertex attributes (to fragment shader) -out vec3 fragPosition; -out vec2 fragTexCoord; -out vec4 fragColor; -out vec3 fragNormal; - -// NOTE: Add here your custom variables - -void main() -{ - // Send vertex attributes to fragment shader - fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); - fragTexCoord = vertexTexCoord; - fragColor = vertexColor; - fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); - - // Calculate final vertex position - gl_Position = mvp*vec4(vertexPosition, 1.0); -} diff --git a/examples/shaders/basic_lighting/main.go b/examples/shaders/basic_lighting/main.go deleted file mode 100644 index 29c7d13..0000000 --- a/examples/shaders/basic_lighting/main.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) //ENABLE 4X MSAA IF AVAILABLE - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(2.0, 4.0, 6.0) - camera.Target = rl.NewVector3(0.0, 0.5, 0.0) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 45.0 - camera.Projection = rl.CameraPerspective - - ground := rl.LoadModelFromMesh(rl.GenMeshPlane(10, 10, 3, 3)) - cube := rl.LoadModelFromMesh(rl.GenMeshCube(2, 4, 2)) - - shader := rl.LoadShader("lighting.vs", "lighting.fs") - - *shader.Locs = rl.GetShaderLocation(shader, "viewPos") - - ambientLoc := rl.GetShaderLocation(shader, "ambient") - shaderValue := []float32{0.1, 0.1, 0.1, 1.0} - rl.SetShaderValue(shader, ambientLoc, shaderValue, rl.ShaderUniformVec4) - - ground.Materials.Shader = shader - cube.Materials.Shader = shader - - lights := make([]Light, 4) - lights[0] = NewLight(LightTypePoint, rl.NewVector3(-2, 1, -2), rl.NewVector3(0, 0, 0), rl.Yellow, shader) - - lights[1] = NewLight(LightTypePoint, rl.NewVector3(2, 1, 2), rl.NewVector3(0, 0, 0), rl.Red, shader) - - lights[2] = NewLight(LightTypePoint, rl.NewVector3(-2, 1, 2), rl.NewVector3(0, 0, 0), rl.Green, shader) - - lights[3] = NewLight(LightTypePoint, rl.NewVector3(2, 1, -2), rl.NewVector3(0, 0, 0), rl.Blue, shader) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraOrbital) - - cameraPos := []float32{camera.Position.X, camera.Position.Y, camera.Position.Z} - rl.SetShaderValue(shader, *shader.Locs, cameraPos, rl.ShaderUniformVec3) - - if rl.IsKeyPressed(rl.KeyY) { - lights[0].enabled *= -1 - } - if rl.IsKeyPressed(rl.KeyR) { - lights[1].enabled *= -1 - } - if rl.IsKeyPressed(rl.KeyG) { - lights[2].enabled *= -1 - } - if rl.IsKeyPressed(rl.KeyB) { - lights[3].enabled *= -1 - } - - for i := 0; i < len(lights); i++ { - lights[i].UpdateValues() - } - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.DrawModel(ground, rl.NewVector3(0, 0, 0), 1, rl.White) - rl.DrawModel(cube, rl.NewVector3(0, 0, 0), 1, rl.White) - - for i := 0; i < len(lights); i++ { - if lights[i].enabled == 1 { - rl.DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color) - } else { - rl.DrawSphereWires(lights[i].position, 0.2, 8, 8, rl.Fade(lights[i].color, 0.3)) - } - } - - rl.DrawGrid(10, 1.0) // Draw a grid - - rl.EndMode3D() - - rl.DrawFPS(10, 10) - - rl.DrawText("KEYS [Y] [R] [G] [B] TURN LIGHTS ON/OFF", 10, 40, 20, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadShader(shader) // Unload shader - rl.UnloadModel(cube) // Unload model - rl.UnloadModel(ground) // Unload model - - rl.CloseWindow() -} diff --git a/examples/shaders/custom_uniform/glsl330/swirl.fs b/examples/shaders/custom_uniform/glsl330/swirl.fs index b2a53ca..4741e59 100644 --- a/examples/shaders/custom_uniform/glsl330/swirl.fs +++ b/examples/shaders/custom_uniform/glsl330/swirl.fs @@ -11,6 +11,8 @@ uniform vec4 colDiffuse; // Output fragment color out vec4 finalColor; +// NOTE: Add here your custom variables + // NOTE: Render size values should be passed from code const float renderWidth = 800; const float renderHeight = 450; @@ -18,7 +20,6 @@ const float renderHeight = 450; float radius = 250.0; float angle = 0.8; -// NOTE: center is connected to the golang code uniform vec2 center = vec2(200.0, 200.0); void main() @@ -40,7 +41,7 @@ void main() } tc += center; - vec4 color = texture(texture0, tc/texSize)*colDiffuse*fragColor;; + vec4 color = texture2D(texture0, tc/texSize)*colDiffuse*fragColor;; finalColor = vec4(color.rgb, 1.0);; } \ No newline at end of file diff --git a/examples/shaders/custom_uniform/main.go b/examples/shaders/custom_uniform/main.go index 82c10f5..78da4a5 100644 --- a/examples/shaders/custom_uniform/main.go +++ b/examples/shaders/custom_uniform/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -31,9 +31,6 @@ func main() { // Get variable (uniform) location on the shader to connect with the program // NOTE: If uniform variable could not be found in the shader, function returns -1 swirlCenterLoc := rl.GetShaderLocation(shader, "center") - if swirlCenterLoc == -1 { - println("Warning: [SHDR] Swirl Center uniform not found on shader") - } swirlCenter := make([]float32, 2) swirlCenter[0] = float32(screenWidth) / 2 @@ -42,6 +39,9 @@ func main() { // Create a RenderTexture2D to be used for render to texture target := rl.LoadRenderTexture(screenWidth, screenHeight) + // Setup orbital camera + rl.SetCameraMode(camera, rl.CameraOrbital) // Set an orbital camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { @@ -55,7 +55,7 @@ func main() { // Send new value to the shader to be used on drawing rl.SetShaderValue(shader, swirlCenterLoc, swirlCenter, rl.ShaderUniformVec2) - rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode + rl.UpdateCamera(&camera) // Update camera rl.BeginDrawing() diff --git a/examples/shaders/eratosthenes/eratosthenes.fs b/examples/shaders/eratosthenes/eratosthenes.fs deleted file mode 100644 index 644e38d..0000000 --- a/examples/shaders/eratosthenes/eratosthenes.fs +++ /dev/null @@ -1,59 +0,0 @@ -#version 330 - -/************************************************************************************* - - The Sieve of Eratosthenes -- a simple shader by ProfJski - An early prime number sieve: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes - - The screen is divided into a square grid of boxes, each representing an integer value. - Each integer is tested to see if it is a prime number. Primes are colored white. - Non-primes are colored with a color that indicates the smallest factor which evenly divdes our integer. - - You can change the scale variable to make a larger or smaller grid. - Total number of integers displayed = scale squared, so scale = 100 tests the first 10,000 integers. - - WARNING: If you make scale too large, your GPU may bog down! - -***************************************************************************************/ - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Output fragment color -out vec4 finalColor; - -// Make a nice spectrum of colors based on counter and maxSize -vec4 Colorizer(float counter, float maxSize) -{ - float red = 0.0, green = 0.0, blue = 0.0; - float normsize = counter/maxSize; - - red = smoothstep(0.3, 0.7, normsize); - green = sin(3.14159*normsize); - blue = 1.0 - smoothstep(0.0, 0.4, normsize); - - return vec4(0.8*red, 0.8*green, 0.8*blue, 1.0); -} - -void main() -{ - vec4 color = vec4(1.0); - float scale = 1000.0; // Makes 100x100 square grid. Change this variable to make a smaller or larger grid. - int value = int(scale*floor(fragTexCoord.y*scale)+floor(fragTexCoord.x*scale)); // Group pixels into boxes representing integer values - - if ((value == 0) || (value == 1) || (value == 2)) finalColor = vec4(1.0); - else - { - for (int i = 2; (i < max(2, sqrt(value) + 1)); i++) - { - if ((value - i*floor(float(value)/float(i))) == 0) - { - color = Colorizer(float(i), scale); - //break; // Uncomment to color by the largest factor instead - } - } - - finalColor = color; - } -} diff --git a/examples/shaders/eratosthenes/main.go b/examples/shaders/eratosthenes/main.go deleted file mode 100644 index 62b070f..0000000 --- a/examples/shaders/eratosthenes/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - Eratosthenes") - - shader := rl.LoadShader("", "eratosthenes.fs") - target := rl.LoadRenderTexture(screenWidth, screenHeight) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.BeginTextureMode(target) - rl.ClearBackground(rl.Black) - rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), int32(rl.GetScreenHeight()), rl.Black) - rl.EndTextureMode() - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginShaderMode(shader) - - rl.DrawTextureRec(target.Texture, rl.NewRectangle(0, 0, float32(target.Texture.Width), float32(target.Texture.Height)), rl.Vector2Zero(), rl.White) - - rl.EndShaderMode() - - rl.EndDrawing() - } - - rl.UnloadShader(shader) - rl.UnloadRenderTexture(target) - - rl.CloseWindow() -} diff --git a/examples/shaders/mesh_instancing/glsl330/base_lighting_instanced.vs b/examples/shaders/mesh_instancing/glsl330/base_lighting_instanced.vs deleted file mode 100644 index d198efe..0000000 --- a/examples/shaders/mesh_instancing/glsl330/base_lighting_instanced.vs +++ /dev/null @@ -1,36 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; -in vec4 vertexColor; - -in mat4 instanceTransform; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matNormal; - -// Output vertex attributes (to fragment shader) -out vec3 fragPosition; -out vec2 fragTexCoord; -out vec4 fragColor; -out vec3 fragNormal; - -// NOTE: Add here your custom variables - -void main() -{ - // Compute MVP for current instance - mat4 mvpi = mvp*instanceTransform; - - // Send vertex attributes to fragment shader - fragPosition = vec3(mvpi*vec4(vertexPosition, 1.0)); - fragTexCoord = vertexTexCoord; - fragColor = vertexColor; - fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); - - // Calculate final vertex position - gl_Position = mvpi*vec4(vertexPosition, 1.0); -} diff --git a/examples/shaders/mesh_instancing/glsl330/lighting.fs b/examples/shaders/mesh_instancing/glsl330/lighting.fs deleted file mode 100644 index 6877c1c..0000000 --- a/examples/shaders/mesh_instancing/glsl330/lighting.fs +++ /dev/null @@ -1,82 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec3 fragPosition; -in vec2 fragTexCoord; -in vec4 fragColor; -in vec3 fragNormal; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -// NOTE: Add here your custom variables - -#define MAX_LIGHTS 4 -#define LIGHT_DIRECTIONAL 0 -#define LIGHT_POINT 1 - -struct MaterialProperty { - vec3 color; - int useSampler; - sampler2D sampler; -}; - -struct Light { - int enabled; - int type; - vec3 position; - vec3 target; - vec4 color; -}; - -// Input lighting values -uniform Light lights[MAX_LIGHTS]; -uniform vec4 ambient; -uniform vec3 viewPos; - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord); - vec3 lightDot = vec3(0.0); - vec3 normal = normalize(fragNormal); - vec3 viewD = normalize(viewPos - fragPosition); - vec3 specular = vec3(0.0); - - // NOTE: Implement here your fragment shader code - - for (int i = 0; i < MAX_LIGHTS; i++) - { - if (lights[i].enabled == 1) - { - vec3 light = vec3(0.0); - - if (lights[i].type == LIGHT_DIRECTIONAL) - { - light = -normalize(lights[i].target - lights[i].position); - } - - if (lights[i].type == LIGHT_POINT) - { - light = normalize(lights[i].position - fragPosition); - } - - float NdotL = max(dot(normal, light), 0.0); - lightDot += lights[i].color.rgb*NdotL; - - float specCo = 0.0; - if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine - specular += specCo; - } - } - - finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); - finalColor += texelColor*(ambient/10.0)*colDiffuse; - - // Gamma correction - finalColor = pow(finalColor, vec4(1.0/2.2)); -} diff --git a/examples/shaders/mesh_instancing/light.go b/examples/shaders/mesh_instancing/light.go deleted file mode 100644 index c398de0..0000000 --- a/examples/shaders/mesh_instancing/light.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "fmt" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -type LightType int32 - -const ( - LightTypeDirectional LightType = iota - LightTypePoint -) - -type Light struct { - shader rl.Shader - lightType LightType - position rl.Vector3 - target rl.Vector3 - color rl.Color - enabled int32 - // shader locations - enabledLoc int32 - typeLoc int32 - posLoc int32 - targetLoc int32 - colorLoc int32 -} - -const maxLightsCount = 4 - -var lightCount = 0 - -func NewLight( - lightType LightType, - position, target rl.Vector3, - color rl.Color, - shader rl.Shader) Light { - light := Light{ - shader: shader, - } - if lightCount < maxLightsCount { - light.enabled = 1 - light.lightType = lightType - light.position = position - light.target = target - light.color = color - light.enabledLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].enabled", lightCount)) - light.typeLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].type", lightCount)) - light.posLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].position", lightCount)) - light.targetLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].target", lightCount)) - light.colorLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].color", lightCount)) - light.UpdateValues() - lightCount++ - } - return light -} - -func (lt *Light) UpdateValues() { - // Send to shader light enabled state and type - rl.SetShaderValue(lt.shader, lt.enabledLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.enabled)), 4), rl.ShaderUniformInt) - rl.SetShaderValue(lt.shader, lt.typeLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.lightType)), 4), rl.ShaderUniformInt) - - // Send to shader light position values - rl.SetShaderValue(lt.shader, lt.posLoc, []float32{lt.position.X, lt.position.Y, lt.position.Z}, rl.ShaderUniformVec3) - - // Send to shader light target target values - rl.SetShaderValue(lt.shader, lt.targetLoc, []float32{lt.target.X, lt.target.Y, lt.target.Z}, rl.ShaderUniformVec3) - - // Send to shader light color values - rl.SetShaderValue(lt.shader, lt.colorLoc, - []float32{float32(lt.color.R) / 255, float32(lt.color.G) / 255, float32(lt.color.B) / 255, float32(lt.color.A) / 255}, - rl.ShaderUniformVec4) -} diff --git a/examples/shaders/mesh_instancing/main.go b/examples/shaders/mesh_instancing/main.go deleted file mode 100644 index ce5862c..0000000 --- a/examples/shaders/mesh_instancing/main.go +++ /dev/null @@ -1,251 +0,0 @@ -package main - -import ( - "fmt" - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const MAX_INSTANCES = 100000 - -func main() { - var ( - screenWidth = int32(800) // Framebuffer width - screenHeight = int32(450) // Framebuffer height - fps = 60 // Frames per second - speed = 30 // Speed of jump animation - groups = 2 // Count of separate groups jumping around - amp = float32(10) // Maximum amplitude of jump - variance = float32(0.8) // Global variance in jump height - loop = float32(0.0) // Individual cube's computed loop timer - textPositionY int32 = 300 - framesCounter = 0 - ) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mesh instancing") - - // Define the camera to look into our 3d world - camera := rl.Camera{ - Position: rl.NewVector3(-125.0, 125.0, -125.0), - Target: rl.NewVector3(0.0, 0.0, 0.0), - Up: rl.NewVector3(0.0, 1.0, 0.0), - Fovy: 45.0, - Projection: rl.CameraPerspective, - } - - cube := rl.GenMeshCube(1.0, 1.0, 1.0) - - rotations := make([]rl.Matrix, MAX_INSTANCES) // Rotation state of instances - rotationsInc := make([]rl.Matrix, MAX_INSTANCES) // Per-frame rotation animation of instances - translations := make([]rl.Matrix, MAX_INSTANCES) // Locations of instances - - // Scatter random cubes around - for i := 0; i < MAX_INSTANCES; i++ { - x := float32(rl.GetRandomValue(-50, 50)) - y := float32(rl.GetRandomValue(-50, 50)) - z := float32(rl.GetRandomValue(-50, 50)) - translations[i] = rl.MatrixTranslate(x, y, z) - - x = float32(rl.GetRandomValue(0, 360)) - y = float32(rl.GetRandomValue(0, 360)) - z = float32(rl.GetRandomValue(0, 360)) - axis := rl.Vector3Normalize(rl.NewVector3(x, y, z)) - angle := float32(rl.GetRandomValue(0, 10)) * rl.Deg2rad - - rotationsInc[i] = rl.MatrixRotate(axis, angle) - rotations[i] = rl.MatrixIdentity() - } - - transforms := make([]rl.Matrix, MAX_INSTANCES) - - shader := rl.LoadShader("glsl330/base_lighting_instanced.vs", "glsl330/lighting.fs") - shader.UpdateLocation(rl.ShaderLocMatrixMvp, rl.GetShaderLocation(shader, "mvp")) - shader.UpdateLocation(rl.ShaderLocVectorView, rl.GetShaderLocation(shader, "viewPos")) - shader.UpdateLocation(rl.ShaderLocMatrixModel, rl.GetShaderLocationAttrib(shader, "instanceTransform")) - - // ambient light level - ambientLoc := rl.GetShaderLocation(shader, "ambient") - rl.SetShaderValue(shader, ambientLoc, []float32{0.2, 0.2, 0.2, 1.0}, rl.ShaderUniformVec4) - NewLight(LightTypeDirectional, rl.NewVector3(50.0, 50.0, 0.0), rl.Vector3Zero(), rl.White, shader) - - material := rl.LoadMaterialDefault() - material.Shader = shader - mmap := material.GetMap(rl.MapDiffuse) - mmap.Color = rl.Red - - rl.SetTargetFPS(int32(fps)) - for !rl.WindowShouldClose() { - // Update - //---------------------------------------------------------------------------------- - - textPositionY = 300 - framesCounter++ - - if rl.IsKeyDown(rl.KeyUp) { - amp += 0.5 - } - if rl.IsKeyDown(rl.KeyDown) { - if amp <= 1 { - amp = 1 - } else { - amp -= 1 - } - } - if rl.IsKeyDown(rl.KeyLeft) { - if variance < 0 { - variance = 0 - } else { - variance -= 0.01 - } - } - if rl.IsKeyDown(rl.KeyRight) { - if variance > 1 { - variance = 1 - } else { - variance += 0.01 - } - } - if rl.IsKeyDown(rl.KeyOne) { - groups = 1 - } - if rl.IsKeyDown(rl.KeyTwo) { - groups = 2 - } - if rl.IsKeyDown(rl.KeyThree) { - groups = 3 - } - if rl.IsKeyDown(rl.KeyFour) { - groups = 4 - } - if rl.IsKeyDown(rl.KeyFive) { - groups = 5 - } - if rl.IsKeyDown(rl.KeySix) { - groups = 6 - } - if rl.IsKeyDown(rl.KeySeven) { - groups = 7 - } - if rl.IsKeyDown(rl.KeyEight) { - groups = 8 - } - if rl.IsKeyDown(rl.KeyNine) { - groups = 9 - } - if rl.IsKeyDown(rl.KeyW) { - groups = 7 - amp = 25 - speed = 18 - variance = float32(0.70) - } - if rl.IsKeyDown(rl.KeyEqual) { - if float32(speed) <= float32(fps)*0.25 { - speed = int(float32(fps) * 0.25) - } else { - speed = int(float32(speed) * 0.95) - } - } - if rl.IsKeyDown(rl.KeyKpAdd) { - if float32(speed) <= float32(fps)*0.25 { - speed = int(float32(fps) * 0.25) - } else { - speed = int(float32(speed) * 0.95) - } - } - if rl.IsKeyDown(rl.KeyMinus) { - speed = int(math.Max(float64(speed)*1.02, float64(speed)+1)) - } - if rl.IsKeyDown(rl.KeyKpSubtract) { - speed = int(math.Max(float64(speed)*1.02, float64(speed)+1)) - } - - // Update the light shader with the camera view position - rl.SetShaderValue(shader, shader.GetLocation(rl.ShaderLocVectorView), - []float32{camera.Position.X, camera.Position.Y, camera.Position.Z}, rl.ShaderUniformVec3) - - // Apply per-instance transformations - for i := 0; i < MAX_INSTANCES; i++ { - rotations[i] = rl.MatrixMultiply(rotations[i], rotationsInc[i]) - transforms[i] = rl.MatrixMultiply(rotations[i], translations[i]) - - // Get the animation cycle's framesCounter for this instance - loop = float32((framesCounter+int(float32(i%groups)/float32(groups)*float32(speed)))%speed) / float32(speed) - - // Calculate the y according to loop cycle - y := float32(math.Sin(float64(loop)*rl.Pi*2)) * amp * - ((1 - variance) + (float32(variance) * float32(i%(groups*10)) / float32(groups*10))) - - // Clamp to floor - if y < 0 { - y = 0 - } - - transforms[i] = rl.MatrixMultiply(transforms[i], rl.MatrixTranslate(0.0, y, 0.0)) - } - - rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - { - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - //rl.DrawMesh(cube, material, rl.MatrixIdentity()) - rl.DrawMeshInstanced(cube, material, transforms, MAX_INSTANCES) - rl.EndMode3D() - - rl.DrawText("A CUBE OF DANCING CUBES!", 490, 10, 20, rl.Maroon) - rl.DrawText("PRESS KEYS:", 10, textPositionY, 20, rl.Black) - - textPositionY += 25 - rl.DrawText("1 - 9", 10, textPositionY, 10, rl.Black) - rl.DrawText(": Number of groups", 50, textPositionY, 10, rl.Black) - rl.DrawText(fmt.Sprintf(": %d", groups), 160, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("UP", 10, textPositionY, 10, rl.Black) - rl.DrawText(": increase amplitude", 50, textPositionY, 10, rl.Black) - rl.DrawText(fmt.Sprintf(": %.2f", amp), 160, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("DOWN", 10, textPositionY, 10, rl.Black) - rl.DrawText(": decrease amplitude", 50, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("LEFT", 10, textPositionY, 10, rl.Black) - rl.DrawText(": decrease variance", 50, textPositionY, 10, rl.Black) - rl.DrawText(fmt.Sprintf(": %.2f", variance), 160, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("RIGHT", 10, textPositionY, 10, rl.Black) - rl.DrawText(": increase variance", 50, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("+/=", 10, textPositionY, 10, rl.Black) - rl.DrawText(": increase speed", 50, textPositionY, 10, rl.Black) - rl.DrawText(fmt.Sprintf(": %d = %f loops/sec", speed, float32(fps)/float32(speed)), 160, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("-", 10, textPositionY, 10, rl.Black) - rl.DrawText(": decrease speed", 50, textPositionY, 10, rl.Black) - - textPositionY += 15 - rl.DrawText("W", 10, textPositionY, 10, rl.Black) - rl.DrawText(": Wild setup!", 50, textPositionY, 10, rl.Black) - - rl.DrawFPS(10, 10) - } - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - rl.CloseWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} diff --git a/examples/shaders/model_shader/main.go b/examples/shaders/model_shader/main.go index 8c13f79..ad8a80e 100644 --- a/examples/shaders/model_shader/main.go +++ b/examples/shaders/model_shader/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -29,10 +29,12 @@ func main() { position := rl.NewVector3(0.0, 0.0, 0.0) // Set model position + rl.SetCameraMode(camera, rl.CameraFree) // Set free camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode + rl.UpdateCamera(&camera) // Update camera rl.BeginDrawing() diff --git a/examples/shaders/multi_sample2d/color_mix.fs b/examples/shaders/multi_sample2d/color_mix.fs deleted file mode 100644 index e794d32..0000000 --- a/examples/shaders/multi_sample2d/color_mix.fs +++ /dev/null @@ -1,27 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec3 vertexPos; -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform sampler2D texture1; -uniform vec4 colDiffuse; - -uniform float divider = 0.5; - -out vec4 finalColor; - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor0 = texture(texture0, fragTexCoord); - vec4 texelColor1 = texture(texture1, fragTexCoord); - - float x = fract(fragTexCoord.s); - float final = smoothstep(divider - 0.1, divider + 0.1, x); - - finalColor = mix(texelColor0, texelColor1, final); -} \ No newline at end of file diff --git a/examples/shaders/multi_sample2d/main.go b/examples/shaders/multi_sample2d/main.go deleted file mode 100644 index b85f5ff..0000000 --- a/examples/shaders/multi_sample2d/main.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - multiple sample2D") - - imRed := rl.GenImageColor(int(screenWidth), int(screenHeight), rl.NewColor(uint8(255), uint8(0), uint8(0), uint8(255))) - texRed := rl.LoadTextureFromImage(imRed) - rl.UnloadImage(imRed) - - imBlue := rl.GenImageColor(int(screenWidth), int(screenHeight), rl.NewColor(uint8(0), uint8(0), uint8(255), uint8(255))) - texBlue := rl.LoadTextureFromImage(imBlue) - rl.UnloadImage(imBlue) - - shader := rl.LoadShader("", "color_mix.fs") - - texBlueLoc := rl.GetShaderLocation(shader, "texture1") - dividerLoc := rl.GetShaderLocation(shader, "divider") - dividerValue := []float32{0.5} - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - if rl.IsKeyDown(rl.KeyRight) { - dividerValue[0] += 0.01 - } else if rl.IsKeyDown(rl.KeyLeft) { - dividerValue[0] -= 0.01 - } - - if dividerValue[0] < 0 { - dividerValue[0] = 0 - } else if dividerValue[0] > 1 { - dividerValue[0] = 1 - } - - rl.SetShaderValue(shader, dividerLoc, dividerValue, rl.ShaderUniformFloat) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginShaderMode(shader) - - rl.SetShaderValueTexture(shader, texBlueLoc, texBlue) - rl.DrawTexture(texRed, 0, 0, rl.White) - - rl.EndShaderMode() - - rl.DrawText("USE LEFT/RIGHT ARROW KEYS TO MIX COLORS", 15, 17, 20, rl.Black) - rl.DrawText("USE LEFT/RIGHT ARROW KEYS TO MIX COLORS", 16, 16, 20, rl.White) - - rl.EndDrawing() - } - - rl.UnloadShader(shader) // Unload shader - rl.UnloadTexture(texRed) // Unload texture - rl.UnloadTexture(texBlue) // Unload texture - - rl.CloseWindow() -} diff --git a/examples/shaders/pbr/glsl330/pbr.fs b/examples/shaders/pbr/glsl330/pbr.fs deleted file mode 100644 index 0448073..0000000 --- a/examples/shaders/pbr/glsl330/pbr.fs +++ /dev/null @@ -1,296 +0,0 @@ -#version 330 - -#define MAX_LIGHTS 4 -#define LIGHT_DIRECTIONAL 0 -#define LIGHT_POINT 1 -#define LIGHT_SPOT 2 -#define PI 3.14159265358979323846 - -struct Light{ - int enabled; - int type; - float enargy; - float cutOff ; - float outerCutOff; - float constant; - float linear ; - float quadratic ; - float shiny ; - float specularStr; - vec3 position; - vec3 direction; - vec3 lightColor; -}; - -// Input vertex attributes (from vertex shader) -in vec3 fragPosition; -in vec2 fragTexCoord; -in vec4 fragColor; -in vec3 fragNormal; -in vec4 shadowPos; -in mat3 TBN; - -// Output fragment color -out vec4 finalColor; -// mask -uniform sampler2D mask; -uniform int frame; -// Input uniform values -uniform int numOfLights = 4; -uniform sampler2D albedoMap; -uniform sampler2D mraMap; -uniform sampler2D normalMap; -uniform sampler2D emissiveMap; // r: Hight g:emissive -// Input uniform values -uniform sampler2D texture0; -uniform sampler2D texture1; -uniform sampler2D flashlight; - -uniform vec4 colDiffuse; - -uniform vec2 tiling = vec2(0.5); -uniform vec2 offset ; -uniform vec2 tilingFlashlight = vec2(0.5); -uniform vec2 offsetFlashlight ; - -uniform int useTexAlbedo =1; -uniform int useTexNormal = 0; -uniform int useTexMRA =1; -uniform int useTexEmissive =1; - -uniform vec4 albedoColor ; -uniform vec4 emissiveColor ; -uniform float normalValue =0.5; -uniform float metallicValue =0.4; -uniform float roughnessValue =0; -uniform float aoValue =0.8; -uniform float emissivePower ; - -// Input lighting values -uniform Light lights[MAX_LIGHTS]; -uniform vec3 viewPos; - -uniform vec3 ambientColor = vec3(1,1,1); -uniform float ambientStrength = 0.2; -uniform float ambient = 0.03; -uniform float fogDensity; - -vec3 CalcDirLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic); -vec3 CalcPointLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic); -vec3 CalcSpotLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic); - -// Reflectivity in range 0.0 to 1.0 -// NOTE: Reflectivity is increased when surface view at larger angle -vec3 SchlickFresnel(float hDotV,vec3 refl) -{ - return refl + (1.0 - refl)*pow(1.0 - hDotV, 5.0); -} - -float GgxDistribution(float nDotH,float roughness) -{ - float a = roughness * roughness * roughness * roughness; - float d = nDotH * nDotH * (a - 1.0) + 1.0; - d = PI * d * d; - return a / max(d,0.0000001); -} - -float GeomSmith(float nDotV,float nDotL,float roughness) -{ - float r = roughness + 1.0; - float k = r*r / 8.0; - float ik = 1.0 - k; - float ggx1 = nDotV/(nDotV*ik + k); - float ggx2 = nDotL/(nDotL*ik + k); - return ggx1*ggx2; -} - -vec3 ComputePBR() -{ - vec3 albedo = texture(albedoMap,vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; - albedo = vec3(albedoColor.x*albedo.x, albedoColor.y*albedo.y, albedoColor.z*albedo.z); - - float metallic = clamp(metallicValue, 0.0, 1.0); - float roughness = clamp(roughnessValue, 0.0, 1.0); - float ao = clamp(aoValue, 0.0, 1.0); - - if (useTexMRA == 1) - { - vec4 mra = texture(mraMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y))*useTexMRA; - metallic = clamp(mra.r + metallicValue, 0.04, 1.0); - roughness = clamp(mra.g + roughnessValue, 0.04, 1.0); - ao = (mra.b + aoValue)*0.5; - } - - vec3 N = normalize(fragNormal); - if (useTexNormal == 1) - { - N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb; - N = normalize(N*2.0 - 1.0); - N = normalize(N*TBN); - } - - vec3 V = normalize(viewPos - fragPosition); - - vec3 emissive = vec3(0); - emissive = (texture(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * useTexEmissive; - - // return N;//vec3(metallic,metallic,metallic); - // if dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity - vec3 baseRefl = mix(vec3(0.04), albedo.rgb, metallic); - vec3 lightAccum = vec3(0.0); // Acumulate lighting lum - - vec3 norm=N; - vec3 viewDir=V; - vec3 result = vec3(0.0); - - for (int i = 0; i < MAX_LIGHTS; i++){ - - if(lights[i].enabled == 1){ - - if(lights[i].type == LIGHT_DIRECTIONAL){ - result += CalcDirLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic); - } - - if(lights[i].type == LIGHT_POINT){ - result += CalcPointLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic); - } - - if(lights[i].type == LIGHT_SPOT){ - result += CalcSpotLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic); - } - - } - - } - - vec3 ambientFinal = (ambientColor + albedo)*ambient*0.5; - - return ambientFinal+result*ao + emissive; - -} - - -void main() -{ - vec3 color = ComputePBR(); - - // HDR tonemapping - color = pow(color, color + vec3(1.0)); - - // // Gamma correction - // color = pow(color, vec3(1.0/2.5)); - - // Fog calculation - float dist = length(viewPos - fragPosition); - - // these could be parameters... - const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0); - - - // Exponential fog - float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity)); - - - fogFactor = clamp(fogFactor, 0.0, 1.0); - - finalColor = mix(fogColor,vec4(color,1.0), fogFactor); -} - - - -vec3 CalcDirLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic) -{ - - vec3 L = normalize(-light.direction); - float diff=max(dot(normal,L),0.0); - vec3 diffuse=light.lightColor*diff*vec3(texture(texture0,fragTexCoord)); - vec3 H = normalize(diffuse + L); - - // Cook-Torrance BRDF distribution function - float nDotV = max(dot(normal,viewDir), 0.0000001); - float nDotL = max(dot(normal,L), 0.0000001); - float hDotV = max(dot(H,viewDir), 0.0); - float nDotH = max(dot(normal,H), 0.0); - float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H - float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow - vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance - - vec3 spec = (D*G*F)/(4.0*nDotV*nDotL); - - // Difuse and spec light can't be above 1.0 - // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent - vec3 kD = vec3(1.0) - F; - // Mult kD by the inverse of metallnes, only non-metals should have diffuse light - kD *= 1.0 - metallic; - // Angle of light has impact on result - return ((kD*albedo.rgb/PI + spec)*nDotL)*light.enabled; - -} - -vec3 CalcPointLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic) -{ - - vec3 L = normalize(light.position - fragPosition); - vec3 H = normalize(viewDir + L); - float distance=length(light.position-fragPosition); - float attenuation=light.enargy/(light.constant+light.linear*distance+light.quadratic*(distance*distance)); - vec3 radiance = light.lightColor.rgb*light.enargy*attenuation; - - // Cook-Torrance BRDF distribution function - float nDotV = max(dot(normal,viewDir), 0.0000001); - float nDotL = max(dot(normal,L), 0.0000001); - float hDotV = max(dot(H,viewDir), 0.0); - float nDotH = max(dot(normal,H), 0.0); - float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H - float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow - vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance - - vec3 spec = (D*G*F)/(4.0*nDotV*nDotL); - - // Difuse and spec light can't be above 1.0 - // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent - vec3 kD = vec3(1.0) - F; - // Mult kD by the inverse of metallnes, only non-metals should have diffuse light - kD *= 1.0 - metallic; - // Angle of light has impact on result - return ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*light.enabled ; -} - -vec3 CalcSpotLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic){ - - vec3 L = normalize(light.position - fragPosition); - - float theta=dot(L,normalize(-light.direction)); - float epsilon=cos(radians(light.cutOff))-cos(radians(light.outerCutOff)); - float intensity=smoothstep(0.0,1.0,(theta-cos(radians(light.outerCutOff)))/epsilon);//clamp((theta-cos(radians(light.outerCutOff)))/epsilon,0.0,1.0); - intensity*= length(vec3(texture(flashlight,vec2(fragTexCoord.x*tilingFlashlight.x + offsetFlashlight.y, fragTexCoord.y*tilingFlashlight.y + offsetFlashlight.y)).rgb)); - - float diff=max(dot(normal,L),0.0); - vec3 H = light.lightColor*diff*vec3(texture(texture0,fragTexCoord)); - float distance=length(light.position-fragPosition); - float attenuation=light.enargy/(light.constant+light.linear*distance+light.quadratic*(distance*distance)); - vec3 radiance = light.lightColor.rgb*light.enargy*attenuation; - H*=intensity; - - // Cook-Torrance BRDF distribution function - float nDotV = max(dot(normal,viewDir), 0.0000001); - float nDotL = max(dot(normal,L), 0.0000001); - float hDotV = max(dot(H,viewDir), 0.0); - float nDotH = max(dot(normal,H), 0.0); - float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H - float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow - vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance - - vec3 spec = (D*G*F)/(4.0*nDotV*nDotL); - spec*=intensity; - - - // Difuse and spec light can't be above 1.0 - // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent - vec3 kD = vec3(1.0) - F; - // Mult kD by the inverse of metallnes, only non-metals should have diffuse light - kD *= 1.0 - metallic; - // Angle of light has impact on result - return ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*light.enabled; -} - diff --git a/examples/shaders/pbr/glsl330/pbr.vs b/examples/shaders/pbr/glsl330/pbr.vs deleted file mode 100644 index 53b0d0f..0000000 --- a/examples/shaders/pbr/glsl330/pbr.vs +++ /dev/null @@ -1,50 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; -in vec3 vertexTangent; -in vec4 vertexColor; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matModel; -uniform mat4 matNormal; -uniform vec3 lightPos; -uniform vec4 difColor; - -// Output vertex attributes (to fragment shader) -out vec3 fragPosition; -out vec2 fragTexCoord; -out vec2 fragTexCoord2; -out vec4 fragColor; -out vec3 fragNormal; -out mat3 TBN; - -const float normalOffset = 0.1; - -void main() -{ - // Compute binormal from vertex normal and tangent - vec3 vertexBinormal = cross(vertexNormal, vertexTangent); - - // Compute fragment normal based on normal transformations - mat3 normalMatrix = transpose(inverse(mat3(matModel))); - - // Compute fragment position based on model transformations - fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); - - fragTexCoord = vertexTexCoord; - fragNormal = normalize(normalMatrix*vertexNormal); - vec3 fragTangent = normalize(normalMatrix*vertexTangent); - fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal); - vec3 fragBinormal = normalize(normalMatrix*vertexBinormal); - fragBinormal = cross(fragNormal, fragTangent); - - TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal)); - - // Calculate final vertex position - gl_Position = mvp*vec4(vertexPosition, 1.0); -} - diff --git a/examples/shaders/pbr/light.go b/examples/shaders/pbr/light.go deleted file mode 100644 index d99c9e0..0000000 --- a/examples/shaders/pbr/light.go +++ /dev/null @@ -1,213 +0,0 @@ -package main - -import ( - "fmt" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -type LightType int32 - -const ( - LightTypeDirectional LightType = iota - LightTypePoint - LightTypeSpot -) - -type Light struct { - Shader rl.Shader - combineStatus bool - lightType LightType - position rl.Vector3 - direction rl.Vector3 - lightColor rl.Color - enabled int32 - enargy float32 - cutOff float32 - outerCutOff float32 - constant float32 - linear float32 - quadratic float32 - shiny float32 - specularStr float32 - // shader locations - enabledLoc int32 - typeLoc int32 - posLoc int32 - dirLoc int32 - colorLoc int32 - viewPosLoc int32 - enargyLoc int32 - cutOffLoc int32 - outerCutOffLoc int32 - constantLoc int32 - linearLoc int32 - quadraticLoc int32 - shinyLoc int32 - specularStrLoc int32 -} - -var MaxLights = 5 -var lightCount = 0 - -func (lt *Light) NewLight( - lightType LightType, - position, direction rl.Vector3, - color rl.Color, - enargy float32, shader *rl.Shader) Light { - - light := Light{ - Shader: *shader, - } - - if lightCount < MaxLights { - light.enabled = 1 - light.lightType = lightType - light.position = position - light.direction = direction - light.lightColor = color - light.enargy = enargy - light.cutOff = 12.5 - light.outerCutOff = 17.5 - light.constant = 1.0 - light.linear = 0.09 - light.quadratic = 0.032 - light.shiny = 32.0 - light.specularStr = 0.9 - light.enabledLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].enabled", lightCount)) - light.typeLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].type", lightCount)) - light.posLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].position", lightCount)) - light.dirLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].direction", lightCount)) - light.colorLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].lightColor", lightCount)) - light.enargyLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].enargy", lightCount)) - light.cutOffLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].cutOff", lightCount)) - light.outerCutOffLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].outerCutOff", lightCount)) - light.constantLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].constant", lightCount)) - light.linearLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].linear", lightCount)) - light.quadraticLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].quadratic", lightCount)) - light.shinyLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].shiny", lightCount)) - light.specularStrLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].specularStr", lightCount)) - - light.UpdateValues() - lightCount++ - } - return light -} - -func (lt *Light) UpdateValues() { - // Send to shader light enabled state and type - rl.SetShaderValue(lt.Shader, lt.enabledLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.enabled)), 4), rl.ShaderUniformInt) - rl.SetShaderValue(lt.Shader, lt.typeLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.lightType)), 4), rl.ShaderUniformInt) - - // Send to shader light position values - rl.SetShaderValue(lt.Shader, lt.posLoc, []float32{lt.position.X, lt.position.Y, lt.position.Z}, rl.ShaderUniformVec3) - - // Send to shader light direction values - rl.SetShaderValue(lt.Shader, lt.dirLoc, []float32{lt.direction.X, lt.direction.Y, lt.direction.Z}, rl.ShaderUniformVec3) - - // Send to shader light color values - rl.SetShaderValue(lt.Shader, lt.colorLoc, - []float32{float32(lt.lightColor.R) / 255, float32(lt.lightColor.G) / 255, float32(lt.lightColor.B) / 255}, - rl.ShaderUniformVec3) - - // Send to shader light enargy values - rl.SetShaderValue(lt.Shader, lt.enargyLoc, []float32{lt.enargy}, rl.ShaderUniformFloat) - - // Send to shader light spot values - rl.SetShaderValue(lt.Shader, lt.cutOffLoc, []float32{lt.cutOff}, rl.ShaderUniformFloat) - rl.SetShaderValue(lt.Shader, lt.outerCutOffLoc, []float32{lt.outerCutOff}, rl.ShaderUniformFloat) - - // Send to shader light pointLight values - rl.SetShaderValue(lt.Shader, lt.constantLoc, []float32{lt.constant}, rl.ShaderUniformFloat) - rl.SetShaderValue(lt.Shader, lt.linearLoc, []float32{lt.linear}, rl.ShaderUniformFloat) - rl.SetShaderValue(lt.Shader, lt.quadraticLoc, []float32{lt.quadratic}, rl.ShaderUniformFloat) - - // Send to shader light shiness values - rl.SetShaderValue(lt.Shader, lt.shinyLoc, []float32{lt.shiny}, rl.ShaderUniformFloat) - rl.SetShaderValue(lt.Shader, lt.specularStrLoc, []float32{lt.specularStr}, rl.ShaderUniformFloat) - -} - -// if you want more 5 light in the light.fs change #define MAX_LIGHTS "your number" -func (lt *Light) SetMaxLight(max int) { - MaxLights = max -} - -func (lt *Light) SetConfigSpotLight(light *Light, cutOff, outerCutOff float32) { - light.cutOff = cutOff - light.outerCutOff = outerCutOff - light.UpdateValues() -} - -func (lt *Light) SetConfigPointLight(light *Light, constant, linear, quadratic float32) { - light.constant = constant - light.linear = linear - light.quadratic = quadratic - light.UpdateValues() -} - -func (lt *Light) SetConfigShiness(light *Light, shiny, specularStr float32) { - light.shiny = shiny - light.specularStr = specularStr - light.UpdateValues() -} - -func (lt *Light) SetMaterialTexture(materials []*rl.Material, texture []*rl.Texture2D) { - for index, material := range materials { - rl.SetMaterialTexture(material, rl.MapDiffuse, *texture[index]) - } -} - -func (lt *Light) SetFlashlightTexture(materials []*rl.Material, texure *rl.Texture2D) { - - lt.Shader.UpdateLocation(rl.ShaderLocMapOcclusion, rl.GetShaderLocation(lt.Shader, "flashlight")) - for _, material := range materials { - rl.SetMaterialTexture(material, rl.MapOcclusion, *texure) - } -} - -func (lt *Light) Init(ambientStrength float32, ambientColor rl.Vector3) { - if !lt.combineStatus { - lt.configShader() - } - lt.viewPosLoc = rl.GetShaderLocation(lt.Shader, "viewPos") - rl.SetShaderValue(lt.Shader, rl.GetShaderLocation(lt.Shader, "ambientColor"), []float32{ambientColor.X, ambientColor.Y, ambientColor.Z}, rl.ShaderUniformVec3) - rl.SetShaderValue(lt.Shader, rl.GetShaderLocation(lt.Shader, "ambientStrength"), []float32{ambientStrength}, rl.ShaderUniformFloat) -} - -func (lt *Light) DisableLight(light *Light) { - light.enabled *= -1 - light.UpdateValues() -} - -func (lt *Light) EnableLight(light *Light) { - light.enabled = 1 - light.UpdateValues() -} - -func (lt *Light) DrawSpherelight(light *Light) { - if light.enabled == 1 { - rl.DrawSphereEx(light.position, 0.2, 8, 8, light.lightColor) - } else { - rl.DrawSphereWires(light.position, 0.2, 8, 8, rl.Fade(light.lightColor, 0.3)) - } -} - -func (lt *Light) UpdateReflect(cameraPos rl.Vector3) { - rl.SetShaderValue(lt.Shader, lt.viewPosLoc, []float32{cameraPos.X, cameraPos.Y, cameraPos.Z}, rl.ShaderUniformVec3) -} - -func (lt *Light) configShader() { - lt.Shader = rl.LoadShader("pbr.vs", "./pbr.fs") -} - -// exce before init or set manually -func (lt *Light) SetCombineShader(CombineShader *rl.Shader) { - lt.combineStatus = true - lt.Shader = *CombineShader -} - -func (lt *Light) Unload() { - rl.UnloadShader(lt.Shader) -} diff --git a/examples/shaders/pbr/main.go b/examples/shaders/pbr/main.go deleted file mode 100644 index 28dba9f..0000000 --- a/examples/shaders/pbr/main.go +++ /dev/null @@ -1,83 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - - screenWidth := int32(900) - screenHeight := int32(500) - rl.SetConfigFlags(rl.FlagMsaa4xHint) //ENABLE 4X MSAA IF AVAILABLE - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr") - - car := rl.LoadModel("./models/old_car_new.glb") - plane := rl.LoadModel("./models/plane.glb") - - cam := rl.Camera3D{} - cam.Fovy = 45 - cam.Position = rl.Vector3{2, 2, 8} - cam.Projection = rl.CameraPerspective - cam.Up = rl.Vector3{0, 1, 0} - - shader := rl.LoadShader("./glsl330/pbr.vs", "./glsl330/pbr.fs") - - l := Light{} - l.SetCombineShader(&shader) - l.Init(0.0, rl.Vector3{1, 1, 1}) - l1 := l.NewLight(LightTypePoint, rl.Vector3{-1, 1, -2}, rl.Vector3{}, rl.Yellow, 4, &l.Shader) - l2 := l.NewLight(LightTypePoint, rl.Vector3{2, 1, 1}, rl.Vector3{}, rl.Green, 3.3, &l.Shader) - l3 := l.NewLight(LightTypePoint, rl.Vector3{-2, 1, 1}, rl.Vector3{}, rl.Red, 8.3, &l.Shader) - l4 := l.NewLight(LightTypePoint, rl.Vector3{1, 1, -2}, rl.Vector3{}, rl.Blue, 2, &l.Shader) - - p := PhysicRender{} - p.SetCombineShader(&shader) - p.Init() - - p.UseTexAlbedo() - p.UseTexMRA() - p.UseTexNormal() - p.UseTexEmissive() - - car.GetMaterials()[0].Shader = shader - - p.AlbedoColorModel(&car, rl.White) - p.MetallicValue(0.0) - p.RoughnessValue(0) - p.EmissivePower(0.0) - p.AoValue(0.0) - p.NormalValue(0.2) - - p.EmissiveColor(rl.NewColor(255, 162, 0, 255)) - p.TextureMapAlbedo(&car.GetMaterials()[0], rl.LoadTexture("models/old_car_d.png")) - p.TextureMapMetalness(&car.GetMaterials()[0], rl.LoadTexture("models/old_car_mra.png")) - p.TextureMapNormal(&car.GetMaterials()[0], rl.LoadTexture("models/old_car_n.png")) - rl.SetMaterialTexture(&car.GetMaterials()[0], rl.MapEmission, rl.LoadTexture("models/old_car_e.png")) - - p.SetTiling(rl.NewVector2(1, 1)) - - plane.GetMaterials()[0].Shader = shader - p.TextureMapAlbedo(&plane.GetMaterials()[0], rl.LoadTexture("./models/road_a.png")) - p.TextureMapNormal(&plane.GetMaterials()[0], rl.LoadTexture("./models/road_n.png")) - p.TextureMapMetalness(&plane.GetMaterials()[0], rl.LoadTexture("./models/road_mra.png")) - - rl.SetTargetFPS(60) - for !rl.WindowShouldClose() { - rl.UpdateCamera(&cam, rl.CameraOrbital) - p.UpadteByCamera(cam.Position) - rl.BeginDrawing() - rl.DrawFPS(10, 20) - rl.ClearBackground(rl.Gray) - rl.BeginMode3D(cam) - rl.DrawModel(car, rl.Vector3{0, 0.01, 0}, 0.25, rl.RayWhite) - rl.DrawModel(plane, rl.Vector3{0, 0, 0}, 5, rl.RayWhite) - l.DrawSpherelight(&l1) - l.DrawSpherelight(&l2) - l.DrawSpherelight(&l3) - l.DrawSpherelight(&l4) - rl.EndMode3D() - rl.EndDrawing() - } - rl.CloseWindow() -} diff --git a/examples/shaders/pbr/models/old_car_d.png b/examples/shaders/pbr/models/old_car_d.png deleted file mode 100644 index d8b3c83..0000000 Binary files a/examples/shaders/pbr/models/old_car_d.png and /dev/null differ diff --git a/examples/shaders/pbr/models/old_car_e.png b/examples/shaders/pbr/models/old_car_e.png deleted file mode 100644 index 23f01c0..0000000 Binary files a/examples/shaders/pbr/models/old_car_e.png and /dev/null differ diff --git a/examples/shaders/pbr/models/old_car_mra.png b/examples/shaders/pbr/models/old_car_mra.png deleted file mode 100644 index 0fb46b3..0000000 Binary files a/examples/shaders/pbr/models/old_car_mra.png and /dev/null differ diff --git a/examples/shaders/pbr/models/old_car_n.png b/examples/shaders/pbr/models/old_car_n.png deleted file mode 100644 index 11f689f..0000000 Binary files a/examples/shaders/pbr/models/old_car_n.png and /dev/null differ diff --git a/examples/shaders/pbr/models/old_car_new.glb b/examples/shaders/pbr/models/old_car_new.glb deleted file mode 100644 index 119995c..0000000 Binary files a/examples/shaders/pbr/models/old_car_new.glb and /dev/null differ diff --git a/examples/shaders/pbr/models/plane.glb b/examples/shaders/pbr/models/plane.glb deleted file mode 100644 index 452e1c5..0000000 Binary files a/examples/shaders/pbr/models/plane.glb and /dev/null differ diff --git a/examples/shaders/pbr/models/road_a.png b/examples/shaders/pbr/models/road_a.png deleted file mode 100644 index 1037773..0000000 Binary files a/examples/shaders/pbr/models/road_a.png and /dev/null differ diff --git a/examples/shaders/pbr/models/road_mra.png b/examples/shaders/pbr/models/road_mra.png deleted file mode 100644 index 988c839..0000000 Binary files a/examples/shaders/pbr/models/road_mra.png and /dev/null differ diff --git a/examples/shaders/pbr/models/road_n.png b/examples/shaders/pbr/models/road_n.png deleted file mode 100644 index a5f3548..0000000 Binary files a/examples/shaders/pbr/models/road_n.png and /dev/null differ diff --git a/examples/shaders/pbr/pbr.go b/examples/shaders/pbr/pbr.go deleted file mode 100644 index b43ed5a..0000000 --- a/examples/shaders/pbr/pbr.go +++ /dev/null @@ -1,218 +0,0 @@ -package main - -import ( - "fmt" - "reflect" - "unsafe" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - LIGHT_DIRECTIONAL int32 = iota - LIGHT_POINT - LIGHT_SPOT -) - -type light struct { - Enabled int32 - Type int32 - Target rl.Vector3 - Position rl.Vector3 - Color [4]float32 - Intensity float32 - // Shader light parameters locations - enabledLoc int32 - typeLoc int32 - targetLoc int32 - positionLoc int32 - colorLoc int32 - intensityLoc int32 -} - -type PhysicRender struct { - Shader *rl.Shader - combineStatus bool -} - -// make light and pbr Shader -func (ph *PhysicRender) Init() { - - if !ph.combineStatus { - ph.configShader() - } - - ph.Shader.UpdateLocation(rl.ShaderLocMapAlbedo, rl.GetShaderLocation(*ph.Shader, "albedoMap")) - ph.Shader.UpdateLocation(rl.ShaderLocMapMetalness, rl.GetShaderLocation(*ph.Shader, "mraMap")) - ph.Shader.UpdateLocation(rl.ShaderLocMapNormal, rl.GetShaderLocation(*ph.Shader, "normalMap")) - ph.Shader.UpdateLocation(rl.ShaderLocMapEmission, rl.GetShaderLocation(*ph.Shader, "emissiveMap")) - ph.Shader.UpdateLocation(12, rl.GetShaderLocation(*ph.Shader, "albedoColor")) - ph.Shader.UpdateLocation(rl.ShaderLocVectorView, rl.GetShaderLocation(*ph.Shader, "viewPos")) - - ambientColor := rl.Color{R: 122, G: 36, B: 26, A: 100} - ambientColorNormalized := rl.NewVector3(float32(ambientColor.R)/255.0, float32(ambientColor.G)/255.0, float32(ambientColor.B)/255.0) - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambientColor"), []float32{ambientColorNormalized.X, ambientColorNormalized.Y, ambientColorNormalized.Z}, rl.ShaderUniformVec3) - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambient"), []float32{float32(0.03)}, rl.ShaderUniformFloat) - - lightCountLoc := rl.GetShaderLocation(*ph.Shader, "numOfLights") - rl.SetShaderValue(*ph.Shader, lightCountLoc, generiteIntForGlsl(int32(MaxLights)), rl.ShaderUniformInt) - -} - -func (ph *PhysicRender) UpadteByCamera(pos rl.Vector3) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "viewPos"), []float32{pos.X, pos.Y, pos.Z}, rl.ShaderUniformVec3) -} - -func (ph *PhysicRender) CreateLight(typeLight int32, position rl.Vector3, target rl.Vector3, color rl.Color, intensity float32) light { - light := light{} - if lightCount < MaxLights { - light.Enabled = 1 - light.Position = position - light.Type = typeLight - light.Target = target - light.Color[0] = float32(float32(color.R) / 255.0) - light.Color[1] = float32(float32(color.G) / 255.0) - light.Color[2] = float32(float32(color.B) / 255.0) - light.Color[3] = float32(float32(color.A) / 255.0) - light.Intensity = intensity - // NOTE: Shader parameters names for lights must match the requested ones - light.enabledLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].enabled", lightCount)) - light.positionLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].position", lightCount)) - light.colorLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].color", lightCount)) - light.intensityLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].intensity", lightCount)) - light.typeLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].type", lightCount)) - //light.targetLoc = rl.GetShaderLocation(ph.Shader, fmt.Sprintf("lights[%d].target", lightCount)) - - ph.UpdateLight(*ph.Shader, light) - - lightCount++ - - } - - return light -} - -func (ph *PhysicRender) UpdateLight(Shader rl.Shader, light light) { - rl.SetShaderValue(Shader, light.enabledLoc, generiteIntForGlsl(light.Enabled), rl.ShaderUniformInt) - rl.SetShaderValue(Shader, light.positionLoc, []float32{light.Position.X, light.Position.Y, light.Position.Z}, rl.ShaderUniformVec3) - rl.SetShaderValue(Shader, light.colorLoc, []float32{light.Color[0], light.Color[1], light.Color[2], light.Color[3]}, rl.ShaderUniformVec4) - rl.SetShaderValue(Shader, light.intensityLoc, []float32{light.Intensity}, rl.ShaderUniformFloat) - rl.SetShaderValue(Shader, light.typeLoc, generiteIntForGlsl(light.Type), rl.ShaderUniformInt) - //rl.SetShaderValue(Shader, light.targetLoc,[]float32{light.Target.X, light.Target.Y, light.Target.Z}, rl.ShaderUniformVec3) -} - -func (ph *PhysicRender) MaxLights(value int) { - MaxLights = value -} - -func (ph *PhysicRender) TextureMapAlbedo(modelMaterials *rl.Material, texture rl.Texture2D) { - rl.SetMaterialTexture(modelMaterials, rl.MapAlbedo, texture) -} - -func (ph *PhysicRender) TextureMapMetalness(modelMaterials *rl.Material, texture rl.Texture2D) { - rl.SetMaterialTexture(modelMaterials, rl.MapMetalness, texture) -} - -func (ph *PhysicRender) TextureMapRoughness(modelMaterials *rl.Material, texture rl.Texture2D) { - rl.SetMaterialTexture(modelMaterials, rl.MapRoughness, texture) -} - -func (ph *PhysicRender) TextureMapNormal(modelMaterials *rl.Material, texture rl.Texture2D) { - rl.SetMaterialTexture(modelMaterials, rl.MapNormal, texture) -} - -func (ph *PhysicRender) TextureMapOcclusion(modelMaterials *rl.Material, texture rl.Texture2D) { - rl.SetMaterialTexture(modelMaterials, rl.MapOcclusion, texture) -} - -func (ph *PhysicRender) DrawSphereLoctionLight(li light, color rl.Color) { - rl.DrawSphereEx(li.Position, 0.2, 8, 8, color) -} - -func (ph *PhysicRender) AlbedoColorModel(model *rl.Model, color rl.Color) { - model.GetMaterials()[0].GetMap(rl.MapAlbedo).Color = color -} - -func (ph *PhysicRender) EmissiveColor(color rl.Color) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "emissiveColor"), []float32{float32(color.R), float32(color.G), float32(color.B), float32(color.A)}, rl.ShaderUniformVec4) -} - -func (ph *PhysicRender) NormalValue(value float32) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "emissiveColor"), []float32{value}, rl.ShaderUniformFloat) -} - -func (ph *PhysicRender) MetallicValue(value float32) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "metallicValue"), []float32{value}, rl.ShaderUniformFloat) -} - -func (ph *PhysicRender) RoughnessValue(value float32) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "roughnessValue"), []float32{value}, rl.ShaderUniformFloat) -} - -func (ph *PhysicRender) AoValue(value float32) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "aoValue"), []float32{value}, rl.ShaderUniformFloat) -} - -func (ph *PhysicRender) EmissivePower(value float32) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "emissivePower"), []float32{value}, rl.ShaderUniformFloat) -} - -func (ph *PhysicRender) AmbientColor(colorAmbient rl.Vector3, ambientValue float32) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambientColor"), []float32{colorAmbient.X, colorAmbient.Y, colorAmbient.Z}, rl.ShaderUniformVec3) - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambient"), []float32{ambientValue}, rl.ShaderUniformFloat) -} - -func (ph *PhysicRender) SetTiling(value rl.Vector2) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "tiling"), []float32{value.X, value.Y}, rl.ShaderUniformVec2) -} - -func (ph *PhysicRender) SetOffset(value rl.Vector2) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "offset"), []float32{value.X, value.Y}, rl.ShaderUniformVec2) -} - -func (ph *PhysicRender) SetTilingFlashlight(value rl.Vector2) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "tilingFlashlight"), []float32{value.X, value.Y}, rl.ShaderUniformVec2) -} - -func (ph *PhysicRender) SetOffsetFlashlight(value rl.Vector2) { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "offsetFlashlight"), []float32{value.X, value.Y}, rl.ShaderUniformVec2) -} - -func (ph *PhysicRender) UseTexAlbedo() { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexAlbedo"), generiteIntForGlsl(1), rl.ShaderUniformInt) -} - -func (ph *PhysicRender) UseTexNormal() { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexNormal"), generiteIntForGlsl(1), rl.ShaderUniformInt) -} - -func (ph *PhysicRender) UseTexMRA() { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexMRA"), generiteIntForGlsl(1), rl.ShaderUniformInt) -} - -func (ph *PhysicRender) UseTexEmissive() { - rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexEmissive"), generiteIntForGlsl(1), rl.ShaderUniformInt) -} - -func (ph *PhysicRender) configShader() { - sh := rl.LoadShader("./pbr.vs", "./pbr.fs") - ph.Shader = &sh -} - -// exce before init or set manually -func (ph *PhysicRender) SetCombineShader(CombineShader *rl.Shader) { - ph.combineStatus = true - ph.Shader = CombineShader -} - -func (ph *PhysicRender) Unload() { - rl.UnloadShader(*ph.Shader) -} - -func generiteIntForGlsl(value int32) []float32 { - data := &reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(&value)), - Len: 4, - Cap: 4, - } - return *(*[]float32)(unsafe.Pointer(data)) -} diff --git a/examples/shaders/postprocessing/glsl330/sobel.fs b/examples/shaders/postprocessing/glsl330/sobel.fs index cb335c0..f317ae3 100644 --- a/examples/shaders/postprocessing/glsl330/sobel.fs +++ b/examples/shaders/postprocessing/glsl330/sobel.fs @@ -20,22 +20,22 @@ void main() float y = 1.0/resolution.y; vec4 horizEdge = vec4(0.0); - horizEdge -= texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y))*1.0; - horizEdge -= texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y ))*2.0; - horizEdge -= texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y))*1.0; - horizEdge += texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y))*1.0; - horizEdge += texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y ))*2.0; - horizEdge += texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y))*1.0; + horizEdge -= texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y))*1.0; + horizEdge -= texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y ))*2.0; + horizEdge -= texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y))*1.0; + horizEdge += texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y))*1.0; + horizEdge += texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y ))*2.0; + horizEdge += texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y))*1.0; vec4 vertEdge = vec4(0.0); - vertEdge -= texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y))*1.0; - vertEdge -= texture(texture0, vec2(fragTexCoord.x , fragTexCoord.y - y))*2.0; - vertEdge -= texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y))*1.0; - vertEdge += texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y))*1.0; - vertEdge += texture(texture0, vec2(fragTexCoord.x , fragTexCoord.y + y))*2.0; - vertEdge += texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y))*1.0; + vertEdge -= texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y))*1.0; + vertEdge -= texture2D(texture0, vec2(fragTexCoord.x , fragTexCoord.y - y))*2.0; + vertEdge -= texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y))*1.0; + vertEdge += texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y))*1.0; + vertEdge += texture2D(texture0, vec2(fragTexCoord.x , fragTexCoord.y + y))*2.0; + vertEdge += texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y))*1.0; vec3 edge = sqrt((horizEdge.rgb*horizEdge.rgb) + (vertEdge.rgb*vertEdge.rgb)); - finalColor = vec4(edge, texture(texture0, fragTexCoord).a); + finalColor = vec4(edge, texture2D(texture0, fragTexCoord).a); } \ No newline at end of file diff --git a/examples/shaders/postprocessing/main.go b/examples/shaders/postprocessing/main.go index 6377e36..0f379ae 100644 --- a/examples/shaders/postprocessing/main.go +++ b/examples/shaders/postprocessing/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const MaxPostproShaders = 12 @@ -77,10 +77,12 @@ func main() { // Create a RenderTexture2D to be used for render to texture target := rl.LoadRenderTexture(screenWidth, screenHeight) + rl.SetCameraMode(camera, rl.CameraOrbital) // Set free camera mode + rl.SetTargetFPS(60) for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode + rl.UpdateCamera(&camera) // Update camera if rl.IsKeyPressed(rl.KeyRight) { currentShader++ diff --git a/examples/shaders/raymarching/main.go b/examples/shaders/raymarching/main.go deleted file mode 100644 index 23684f0..0000000 --- a/examples/shaders/raymarching/main.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) // ENABLE 4X MSAA IF AVAILABLE - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - raymarching") - - camera := rl.Camera{} - camera.Position = rl.NewVector3(2.5, 2.5, 3.0) - camera.Target = rl.NewVector3(0.0, 0.0, 0.7) - camera.Up = rl.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 65.0 - - shader := rl.LoadShader("", "raymarching.fs") - - viewEyeLoc := rl.GetShaderLocation(shader, "viewEye") - viewCenterLoc := rl.GetShaderLocation(shader, "viewCenter") - runtTimeLoc := rl.GetShaderLocation(shader, "runTime") - resolutionLoc := rl.GetShaderLocation(shader, "resolution") - - resolution := []float32{float32(screenWidth), float32(screenHeight)} - rl.SetShaderValue(shader, resolutionLoc, resolution, rl.ShaderUniformVec2) - - runTimer := float32(0) - - rl.DisableCursor() - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - rl.UpdateCamera(&camera, rl.CameraThirdPerson) // Update camera with free camera mode - - camPos := []float32{camera.Position.X, camera.Position.Y, camera.Position.Z} - camTarget := []float32{camera.Target.X, camera.Target.Y, camera.Target.Z} - - deltaTime := rl.GetFrameTime() - runTimer += deltaTime - runTime := []float32{runTimer} - - rl.SetShaderValue(shader, viewEyeLoc, camPos, rl.ShaderUniformVec3) - rl.SetShaderValue(shader, viewCenterLoc, camTarget, rl.ShaderUniformVec3) - rl.SetShaderValue(shader, runtTimeLoc, runTime, rl.ShaderUniformFloat) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginShaderMode(shader) - - rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), int32(rl.GetScreenHeight()), rl.White) - rl.EndShaderMode() - - rl.DrawText("(c) Raymarching shader by Iñigo Quilez. MIT License.", screenWidth-280, screenHeight-20, 10, rl.Black) - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - rl.UnloadShader(shader) // Unload shader - - rl.CloseWindow() -} diff --git a/examples/shaders/raymarching/raymarching.fs b/examples/shaders/raymarching/raymarching.fs deleted file mode 100644 index 6a9eb45..0000000 --- a/examples/shaders/raymarching/raymarching.fs +++ /dev/null @@ -1,430 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Output fragment color -out vec4 finalColor; - -uniform vec3 viewEye; -uniform vec3 viewCenter; -uniform float runTime; -uniform vec2 resolution; - -// The MIT License -// Copyright © 2013 Inigo Quilez -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -// A list of useful distance function to simple primitives, and an example on how to -// do some interesting boolean operations, repetition and displacement. -// -// More info here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm - -#define AA 1 // make this 1 is your machine is too slow - -//------------------------------------------------------------------ - -float sdPlane( vec3 p ) -{ - return p.y; -} - -float sdSphere( vec3 p, float s ) -{ - return length(p)-s; -} - -float sdBox( vec3 p, vec3 b ) -{ - vec3 d = abs(p) - b; - return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)); -} - -float sdEllipsoid( in vec3 p, in vec3 r ) -{ - return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z); -} - -float udRoundBox( vec3 p, vec3 b, float r ) -{ - return length(max(abs(p)-b,0.0))-r; -} - -float sdTorus( vec3 p, vec2 t ) -{ - return length( vec2(length(p.xz)-t.x,p.y) )-t.y; -} - -float sdHexPrism( vec3 p, vec2 h ) -{ - vec3 q = abs(p); -#if 0 - return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x); -#else - float d1 = q.z-h.y; - float d2 = max((q.x*0.866025+q.y*0.5),q.y)-h.x; - return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); -#endif -} - -float sdCapsule( vec3 p, vec3 a, vec3 b, float r ) -{ - vec3 pa = p-a, ba = b-a; - float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); - return length( pa - ba*h ) - r; -} - -float sdEquilateralTriangle( in vec2 p ) -{ - const float k = sqrt(3.0); - p.x = abs(p.x) - 1.0; - p.y = p.y + 1.0/k; - if( p.x + k*p.y > 0.0 ) p = vec2( p.x - k*p.y, -k*p.x - p.y )/2.0; - p.x += 2.0 - 2.0*clamp( (p.x+2.0)/2.0, 0.0, 1.0 ); - return -length(p)*sign(p.y); -} - -float sdTriPrism( vec3 p, vec2 h ) -{ - vec3 q = abs(p); - float d1 = q.z-h.y; -#if 1 - // distance bound - float d2 = max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5; -#else - // correct distance - h.x *= 0.866025; - float d2 = sdEquilateralTriangle(p.xy/h.x)*h.x; -#endif - return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); -} - -float sdCylinder( vec3 p, vec2 h ) -{ - vec2 d = abs(vec2(length(p.xz),p.y)) - h; - return min(max(d.x,d.y),0.0) + length(max(d,0.0)); -} - -float sdCone( in vec3 p, in vec3 c ) -{ - vec2 q = vec2( length(p.xz), p.y ); - float d1 = -q.y-c.z; - float d2 = max( dot(q,c.xy), q.y); - return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); -} - -float sdConeSection( in vec3 p, in float h, in float r1, in float r2 ) -{ - float d1 = -p.y - h; - float q = p.y - h; - float si = 0.5*(r1-r2)/h; - float d2 = max( sqrt( dot(p.xz,p.xz)*(1.0-si*si)) + q*si - r2, q ); - return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); -} - -float sdPryamid4(vec3 p, vec3 h ) // h = { cos a, sin a, height } -{ - // Tetrahedron = Octahedron - Cube - float box = sdBox( p - vec3(0,-2.0*h.z,0), vec3(2.0*h.z) ); - - float d = 0.0; - d = max( d, abs( dot(p, vec3( -h.x, h.y, 0 )) )); - d = max( d, abs( dot(p, vec3( h.x, h.y, 0 )) )); - d = max( d, abs( dot(p, vec3( 0, h.y, h.x )) )); - d = max( d, abs( dot(p, vec3( 0, h.y,-h.x )) )); - float octa = d - h.z; - return max(-box,octa); // Subtraction - } - -float length2( vec2 p ) -{ - return sqrt( p.x*p.x + p.y*p.y ); -} - -float length6( vec2 p ) -{ - p = p*p*p; p = p*p; - return pow( p.x + p.y, 1.0/6.0 ); -} - -float length8( vec2 p ) -{ - p = p*p; p = p*p; p = p*p; - return pow( p.x + p.y, 1.0/8.0 ); -} - -float sdTorus82( vec3 p, vec2 t ) -{ - vec2 q = vec2(length2(p.xz)-t.x,p.y); - return length8(q)-t.y; -} - -float sdTorus88( vec3 p, vec2 t ) -{ - vec2 q = vec2(length8(p.xz)-t.x,p.y); - return length8(q)-t.y; -} - -float sdCylinder6( vec3 p, vec2 h ) -{ - return max( length6(p.xz)-h.x, abs(p.y)-h.y ); -} - -//------------------------------------------------------------------ - -float opS( float d1, float d2 ) -{ - return max(-d2,d1); -} - -vec2 opU( vec2 d1, vec2 d2 ) -{ - return (d1.x0.0 ) tmax = min( tmax, tp1 ); - float tp2 = (1.6-ro.y)/rd.y; if( tp2>0.0 ) { if( ro.y>1.6 ) tmin = max( tmin, tp2 ); - else tmax = min( tmax, tp2 ); } -#endif - - float t = tmin; - float m = -1.0; - for( int i=0; i<64; i++ ) - { - float precis = 0.0005*t; - vec2 res = map( ro+rd*t ); - if( res.xtmax ) break; - t += res.x; - m = res.y; - } - - if( t>tmax ) m=-1.0; - return vec2( t, m ); -} - - -float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ) -{ - float res = 1.0; - float t = mint; - for( int i=0; i<16; i++ ) - { - float h = map( ro + rd*t ).x; - res = min( res, 8.0*h/t ); - t += clamp( h, 0.02, 0.10 ); - if( h<0.001 || t>tmax ) break; - } - return clamp( res, 0.0, 1.0 ); -} - -vec3 calcNormal( in vec3 pos ) -{ - vec2 e = vec2(1.0,-1.0)*0.5773*0.0005; - return normalize( e.xyy*map( pos + e.xyy ).x + - e.yyx*map( pos + e.yyx ).x + - e.yxy*map( pos + e.yxy ).x + - e.xxx*map( pos + e.xxx ).x ); - /* - vec3 eps = vec3( 0.0005, 0.0, 0.0 ); - vec3 nor = vec3( - map(pos+eps.xyy).x - map(pos-eps.xyy).x, - map(pos+eps.yxy).x - map(pos-eps.yxy).x, - map(pos+eps.yyx).x - map(pos-eps.yyx).x ); - return normalize(nor); - */ -} - -float calcAO( in vec3 pos, in vec3 nor ) -{ - float occ = 0.0; - float sca = 1.0; - for( int i=0; i<5; i++ ) - { - float hr = 0.01 + 0.12*float(i)/4.0; - vec3 aopos = nor * hr + pos; - float dd = map( aopos ).x; - occ += -(dd-hr)*sca; - sca *= 0.95; - } - return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ); -} - -// http://iquilezles.org/www/articles/checkerfiltering/checkerfiltering.htm -float checkersGradBox( in vec2 p ) -{ - // filter kernel - vec2 w = fwidth(p) + 0.001; - // analytical integral (box filter) - vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w; - // xor pattern - return 0.5 - 0.5*i.x*i.y; -} - -vec3 render( in vec3 ro, in vec3 rd ) -{ - vec3 col = vec3(0.7, 0.9, 1.0) +rd.y*0.8; - vec2 res = castRay(ro,rd); - float t = res.x; - float m = res.y; - if( m>-0.5 ) - { - vec3 pos = ro + t*rd; - vec3 nor = calcNormal( pos ); - vec3 ref = reflect( rd, nor ); - - // material - col = 0.45 + 0.35*sin( vec3(0.05,0.08,0.10)*(m-1.0) ); - if( m<1.5 ) - { - - float f = checkersGradBox( 5.0*pos.xz ); - col = 0.3 + f*vec3(0.1); - } - - // lighting - float occ = calcAO( pos, nor ); - vec3 lig = normalize( vec3(cos(-0.4 * runTime), sin(0.7 * runTime), -0.6) ); - vec3 hal = normalize( lig-rd ); - float amb = clamp( 0.5+0.5*nor.y, 0.0, 1.0 ); - float dif = clamp( dot( nor, lig ), 0.0, 1.0 ); - float bac = clamp( dot( nor, normalize(vec3(-lig.x,0.0,-lig.z))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0); - float dom = smoothstep( -0.1, 0.1, ref.y ); - float fre = pow( clamp(1.0+dot(nor,rd),0.0,1.0), 2.0 ); - - dif *= calcSoftshadow( pos, lig, 0.02, 2.5 ); - dom *= calcSoftshadow( pos, ref, 0.02, 2.5 ); - - float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0)* - dif * - (0.04 + 0.96*pow( clamp(1.0+dot(hal,rd),0.0,1.0), 5.0 )); - - vec3 lin = vec3(0.0); - lin += 1.30*dif*vec3(1.00,0.80,0.55); - lin += 0.40*amb*vec3(0.40,0.60,1.00)*occ; - lin += 0.50*dom*vec3(0.40,0.60,1.00)*occ; - lin += 0.50*bac*vec3(0.25,0.25,0.25)*occ; - lin += 0.25*fre*vec3(1.00,1.00,1.00)*occ; - col = col*lin; - col += 10.00*spe*vec3(1.00,0.90,0.70); - - col = mix( col, vec3(0.8,0.9,1.0), 1.0-exp( -0.0002*t*t*t ) ); - } - - return vec3( clamp(col,0.0,1.0) ); -} - -mat3 setCamera( in vec3 ro, in vec3 ta, float cr ) -{ - vec3 cw = normalize(ta-ro); - vec3 cp = vec3(sin(cr), cos(cr),0.0); - vec3 cu = normalize( cross(cw,cp) ); - vec3 cv = normalize( cross(cu,cw) ); - return mat3( cu, cv, cw ); -} - -void main() -{ - vec3 tot = vec3(0.0); -#if AA>1 - for( int m=0; m1 - } - tot /= float(AA*AA); -#endif - - finalColor = vec4( tot, 1.0 ); -} diff --git a/examples/shaders/shapes_textures/main.go b/examples/shaders/shapes_textures/main.go index e374af2..9bd6443 100644 --- a/examples/shaders/shapes_textures/main.go +++ b/examples/shaders/shapes_textures/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/shaders/texture_drawing/cubes_panning.fs b/examples/shaders/texture_drawing/cubes_panning.fs deleted file mode 100644 index 1d75e4e..0000000 --- a/examples/shaders/texture_drawing/cubes_panning.fs +++ /dev/null @@ -1,61 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Output fragment color -out vec4 finalColor; - -// Custom variables -#define PI 3.14159265358979323846 -uniform float uTime = 0.0; - -float divisions = 5.0; -float angle = 0.0; - -vec2 VectorRotateTime(vec2 v, float speed) -{ - float time = uTime*speed; - float localTime = fract(time); // The time domain this works on is 1 sec. - - if ((localTime >= 0.0) && (localTime < 0.25)) angle = 0.0; - else if ((localTime >= 0.25) && (localTime < 0.50)) angle = PI/4*sin(2*PI*localTime - PI/2); - else if ((localTime >= 0.50) && (localTime < 0.75)) angle = PI*0.25; - else if ((localTime >= 0.75) && (localTime < 1.00)) angle = PI/4*sin(2*PI*localTime); - - // Rotate vector by angle - v -= 0.5; - v = mat2(cos(angle), -sin(angle), sin(angle), cos(angle))*v; - v += 0.5; - - return v; -} - -float Rectangle(in vec2 st, in float size, in float fill) -{ - float roundSize = 0.5 - size/2.0; - float left = step(roundSize, st.x); - float top = step(roundSize, st.y); - float bottom = step(roundSize, 1.0 - st.y); - float right = step(roundSize, 1.0 - st.x); - - return (left*bottom*right*top)*fill; -} - -void main() -{ - vec2 fragPos = fragTexCoord; - fragPos.xy += uTime/9.0; - - fragPos *= divisions; - vec2 ipos = floor(fragPos); // Get the integer coords - vec2 fpos = fract(fragPos); // Get the fractional coords - - fpos = VectorRotateTime(fpos, 0.2); - - float alpha = Rectangle(fpos, 0.216, 1.0); - vec3 color = vec3(0.3, 0.3, 0.3); - - finalColor = vec4(color, alpha); -} \ No newline at end of file diff --git a/examples/shaders/texture_drawing/main.go b/examples/shaders/texture_drawing/main.go deleted file mode 100644 index 3f7136b..0000000 --- a/examples/shaders/texture_drawing/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture drawing") - - imBlank := rl.GenImageColor(1024, 1024, rl.Blank) - texture := rl.LoadTextureFromImage(imBlank) - rl.UnloadImage(imBlank) - - shader := rl.LoadShader("", "cubes_panning.fs") - - time := []float32{0} - - timeLoc := rl.GetShaderLocation(shader, "uTime") - - rl.SetShaderValue(shader, timeLoc, time, rl.ShaderUniformFloat) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - time = nil - time = []float32{float32(rl.GetTime())} - rl.SetShaderValue(shader, timeLoc, time, rl.ShaderUniformFloat) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginShaderMode(shader) - rl.DrawTexture(texture, 0, 0, rl.White) - rl.EndShaderMode() - - rl.DrawText("BACKGROUND is PAINTED and ANIMATED on SHADER!", 10, 10, 20, rl.Maroon) - - rl.EndDrawing() - } - - rl.UnloadShader(shader) // Unload shader - - rl.CloseWindow() -} diff --git a/examples/shaders/texture_outline/gopher.png b/examples/shaders/texture_outline/gopher.png deleted file mode 100644 index 8347cee..0000000 Binary files a/examples/shaders/texture_outline/gopher.png and /dev/null differ diff --git a/examples/shaders/texture_outline/main.go b/examples/shaders/texture_outline/main.go deleted file mode 100644 index 50b2257..0000000 --- a/examples/shaders/texture_outline/main.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture outline") - - texture := rl.LoadTexture("gopher.png") - - shader := rl.LoadShader("", "outline.fs") - - cnt := rl.NewVector2(float32(screenWidth/2), float32(screenHeight/2)) - - outlineSize := []float32{2} - outlineColor := []float32{1, 0, 0, 1} - textureSize := []float32{float32(texture.Width), float32(texture.Height)} - - outlineSizeLoc := rl.GetShaderLocation(shader, "outlineSize") - outlineColorLoc := rl.GetShaderLocation(shader, "outlineColor") - textureSizeLoc := rl.GetShaderLocation(shader, "textureSize") - - rl.SetShaderValue(shader, outlineSizeLoc, outlineSize, rl.ShaderUniformFloat) - rl.SetShaderValue(shader, outlineColorLoc, outlineColor, rl.ShaderUniformVec4) - rl.SetShaderValue(shader, textureSizeLoc, textureSize, rl.ShaderUniformVec2) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - if rl.IsKeyPressed(rl.KeyUp) { - outlineSize[0]++ - } else if rl.IsKeyPressed(rl.KeyDown) { - outlineSize[0]-- - if outlineSize[0] < 1 { - outlineSize[0] = 1 - } - } - - rl.SetShaderValue(shader, outlineSizeLoc, outlineSize, rl.ShaderUniformFloat) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginShaderMode(shader) - - rl.DrawTexture(texture, int32(cnt.X)-texture.Width/2, int32(cnt.Y)-texture.Height/2, rl.White) - - rl.EndShaderMode() - - rl.DrawText("UP/DOWN ARROW KEYS INCREASE OUTLINE THICKNESS", 10, 10, 10, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadShader(shader) - rl.UnloadTexture(texture) - - rl.CloseWindow() -} diff --git a/examples/shaders/texture_outline/outline.fs b/examples/shaders/texture_outline/outline.fs deleted file mode 100644 index 2584a21..0000000 --- a/examples/shaders/texture_outline/outline.fs +++ /dev/null @@ -1,35 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -uniform vec2 textureSize; -uniform float outlineSize; -uniform vec4 outlineColor; - -// Output fragment color -out vec4 finalColor; - -void main() -{ - vec4 texel = texture(texture0, fragTexCoord); // Get texel color - vec2 texelScale = vec2(0.0); - texelScale.x = outlineSize/textureSize.x; - texelScale.y = outlineSize/textureSize.y; - - // We sample four corner texels, but only for the alpha channel (this is for the outline) - vec4 corners = vec4(0.0); - corners.x = texture(texture0, fragTexCoord + vec2(texelScale.x, texelScale.y)).a; - corners.y = texture(texture0, fragTexCoord + vec2(texelScale.x, -texelScale.y)).a; - corners.z = texture(texture0, fragTexCoord + vec2(-texelScale.x, texelScale.y)).a; - corners.w = texture(texture0, fragTexCoord + vec2(-texelScale.x, -texelScale.y)).a; - - float outline = min(dot(corners, vec4(1.0)), 1.0); - vec4 color = mix(vec4(0.0), outlineColor, outline); - finalColor = mix(color, texel, texel.a); -} \ No newline at end of file diff --git a/examples/shaders/texture_tiling/cubicmap_atlas.png b/examples/shaders/texture_tiling/cubicmap_atlas.png deleted file mode 100644 index 9fc404a..0000000 Binary files a/examples/shaders/texture_tiling/cubicmap_atlas.png and /dev/null differ diff --git a/examples/shaders/texture_tiling/main.go b/examples/shaders/texture_tiling/main.go deleted file mode 100644 index 2af0f8a..0000000 --- a/examples/shaders/texture_tiling/main.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture tiling") - - cam := rl.Camera3D{} - cam.Position = rl.NewVector3(4, 4, 4) - cam.Target = rl.NewVector3(0, 0.5, 0) - cam.Up = rl.NewVector3(0, 1, 0) - cam.Fovy = 45 - cam.Projection = rl.CameraPerspective - - cube := rl.GenMeshCube(1, 1, 1) - model := rl.LoadModelFromMesh(cube) - - texture := rl.LoadTexture("cubicmap_atlas.png") - rl.SetMaterialTexture(model.Materials, rl.MapDiffuse, texture) - - tiling := []float32{3, 3} - shader := rl.LoadShader("", "tiling.fs") - rl.SetShaderValue(shader, rl.GetShaderLocation(shader, "tiling"), tiling, rl.ShaderUniformVec2) - model.Materials.Shader = shader - - rl.DisableCursor() - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - rl.UpdateCamera(&cam, rl.CameraOrbital) - - if rl.IsKeyPressed(rl.KeyZ) { - cam.Target = rl.NewVector3(0, 0.5, 0) - } - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(cam) - - rl.BeginShaderMode(shader) - rl.DrawModel(model, rl.Vector3Zero(), 2, rl.White) - rl.EndShaderMode() - - rl.DrawGrid(10, 1) - - rl.EndMode3D() - - rl.EndDrawing() - } - - rl.UnloadShader(shader) - rl.UnloadModel(model) - rl.UnloadTexture(texture) - - rl.CloseWindow() -} diff --git a/examples/shaders/texture_tiling/tiling.fs b/examples/shaders/texture_tiling/tiling.fs deleted file mode 100644 index 6e7f524..0000000 --- a/examples/shaders/texture_tiling/tiling.fs +++ /dev/null @@ -1,14 +0,0 @@ -#version 330 core - -uniform sampler2D diffuseMap; -uniform vec2 tiling; - -in vec2 fragTexCoord; - -out vec4 fragColor; - -void main() -{ - vec2 texCoord = fragTexCoord * tiling; - fragColor = texture(diffuseMap, texCoord); -} diff --git a/examples/shaders/texture_waves/main.go b/examples/shaders/texture_waves/main.go deleted file mode 100644 index ce32710..0000000 --- a/examples/shaders/texture_waves/main.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture waves") - - texture := rl.LoadTexture("space.png") - - shader := rl.LoadShader("", "wave.fs") - - secondsLoc := rl.GetShaderLocation(shader, "seconds") - freqXLoc := rl.GetShaderLocation(shader, "freqX") - freqYLoc := rl.GetShaderLocation(shader, "freqY") - ampXLoc := rl.GetShaderLocation(shader, "ampX") - ampYLoc := rl.GetShaderLocation(shader, "ampY") - speedXLoc := rl.GetShaderLocation(shader, "speedX") - speedYLoc := rl.GetShaderLocation(shader, "speedY") - - freqX := []float32{25} - freqY := []float32{25} - ampX := []float32{5} - ampY := []float32{5} - speedX := []float32{8} - speedY := []float32{8} - - screensize := []float32{float32(rl.GetScreenWidth()), float32(rl.GetScreenHeight())} - - rl.SetShaderValue(shader, rl.GetShaderLocation(shader, "size"), screensize, rl.ShaderUniformVec2) - rl.SetShaderValue(shader, freqXLoc, freqX, rl.ShaderUniformFloat) - rl.SetShaderValue(shader, freqYLoc, freqY, rl.ShaderUniformFloat) - rl.SetShaderValue(shader, ampXLoc, ampX, rl.ShaderUniformFloat) - rl.SetShaderValue(shader, ampYLoc, ampY, rl.ShaderUniformFloat) - rl.SetShaderValue(shader, speedXLoc, speedX, rl.ShaderUniformFloat) - rl.SetShaderValue(shader, speedYLoc, speedY, rl.ShaderUniformFloat) - - seconds := []float32{0} - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - seconds[0] += rl.GetFrameTime() - rl.SetShaderValue(shader, secondsLoc, seconds, rl.ShaderUniformFloat) - - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginShaderMode(shader) - rl.DrawTexture(texture, 0, 0, rl.White) - rl.DrawTexture(texture, texture.Width, 0, rl.White) - rl.EndShaderMode() - - rl.EndDrawing() - } - - rl.UnloadShader(shader) - rl.UnloadTexture(texture) - - rl.CloseWindow() -} diff --git a/examples/shaders/texture_waves/space.png b/examples/shaders/texture_waves/space.png deleted file mode 100644 index 5d016e4..0000000 Binary files a/examples/shaders/texture_waves/space.png and /dev/null differ diff --git a/examples/shaders/texture_waves/wave.fs b/examples/shaders/texture_waves/wave.fs deleted file mode 100644 index 1f22bee..0000000 --- a/examples/shaders/texture_waves/wave.fs +++ /dev/null @@ -1,37 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -uniform float seconds; - -uniform vec2 size; - -uniform float freqX; -uniform float freqY; -uniform float ampX; -uniform float ampY; -uniform float speedX; -uniform float speedY; - -void main() { - float pixelWidth = 1.0 / size.x; - float pixelHeight = 1.0 / size.y; - float aspect = pixelHeight / pixelWidth; - float boxLeft = 0.0; - float boxTop = 0.0; - - vec2 p = fragTexCoord; - p.x += cos((fragTexCoord.y - boxTop) * freqX / ( pixelWidth * 750.0) + (seconds * speedX)) * ampX * pixelWidth; - p.y += sin((fragTexCoord.x - boxLeft) * freqY * aspect / ( pixelHeight * 750.0) + (seconds * speedY)) * ampY * pixelHeight; - - finalColor = texture(texture0, p)*colDiffuse*fragColor; -} diff --git a/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs deleted file mode 100644 index 0a99e18..0000000 --- a/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs +++ /dev/null @@ -1,18 +0,0 @@ -#version 100 - -precision mediump float; - -// Input vertex attributes (from fragment shader) -varying vec2 fragTexCoord; -varying float height; - - -void main() -{ - vec4 darkblue = vec4(0.0, 0.13, 0.18, 1.0); - vec4 lightblue = vec4(1.0, 1.0, 1.0, 1.0); - // Interpolate between two colors based on height - vec4 finalColor = mix(darkblue, lightblue, height); - - gl_FragColor = finalColor; -} diff --git a/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs deleted file mode 100644 index ef79097..0000000 --- a/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs +++ /dev/null @@ -1,48 +0,0 @@ -#version 100 - -precision mediump float; - -// Input vertex attributes -attribute vec3 vertexPosition; -attribute vec2 vertexTexCoord; -attribute vec3 vertexNormal; -attribute vec4 vertexColor; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matModel; -uniform mat4 matNormal; - -uniform float time; - -uniform sampler2D perlinNoiseMap; - -// Output vertex attributes (to fragment shader) -varying vec3 fragPosition; -varying vec2 fragTexCoord; -varying vec3 fragNormal; -varying float height; - -void main() -{ - // Calculate animated texture coordinates based on time and vertex position - vec2 animatedTexCoord = sin(vertexTexCoord + vec2(sin(time + vertexPosition.x * 0.1), cos(time + vertexPosition.z * 0.1)) * 0.3); - - // Normalize animated texture coordinates to range [0, 1] - animatedTexCoord = animatedTexCoord * 0.5 + 0.5; - - // Fetch displacement from the perlin noise map - float displacement = texture2D(perlinNoiseMap, animatedTexCoord).r * 7.0; // Amplified displacement - - // Displace vertex position - vec3 displacedPosition = vertexPosition + vec3(0.0, displacement, 0.0); - - // Send vertex attributes to fragment shader - fragPosition = vec3(matModel * vec4(displacedPosition, 1.0)); - fragTexCoord = vertexTexCoord; - fragNormal = normalize(vec3(matNormal * vec4(vertexNormal, 1.0))); - height = displacedPosition.y * 0.2; // Send height to fragment shader for coloring - - // Calculate final vertex position - gl_Position = mvp * vec4(displacedPosition, 1.0); -} diff --git a/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs deleted file mode 100644 index b80b76e..0000000 --- a/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs +++ /dev/null @@ -1,16 +0,0 @@ -#version 330 - -// Input fragment attributes (from fragment shader) -in vec2 fragTexCoord; -in float height; - -// Output fragment color -out vec4 finalColor; - -void main() -{ - vec4 darkblue = vec4(0.0, 0.13, 0.18, 1.0); - vec4 lightblue = vec4(1.0, 1.0, 1.0, 1.0); - // Interpolate between two colors based on height - finalColor = mix(darkblue, lightblue, height); -} diff --git a/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs deleted file mode 100644 index c6526db..0000000 --- a/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs +++ /dev/null @@ -1,46 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; -in vec4 vertexColor; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matModel; -uniform mat4 matNormal; - -uniform float time; - -uniform sampler2D perlinNoiseMap; - -// Output vertex attributes (to fragment shader) -out vec3 fragPosition; -out vec2 fragTexCoord; -out vec3 fragNormal; -out float height; - -void main() -{ - // Calculate animated texture coordinates based on time and vertex position - vec2 animatedTexCoord = sin(vertexTexCoord + vec2(sin(time + vertexPosition.x * 0.1), cos(time + vertexPosition.z * 0.1)) * 0.3); - - // Normalize animated texture coordinates to range [0, 1] - animatedTexCoord = animatedTexCoord * 0.5 + 0.5; - - // Fetch displacement from the perlin noise map - float displacement = texture(perlinNoiseMap, animatedTexCoord).r * 7.0; // Amplified displacement - - // Displace vertex position - vec3 displacedPosition = vertexPosition + vec3(0.0, displacement, 0.0); - - // Send vertex attributes to fragment shader - fragPosition = vec3(matModel * vec4(displacedPosition, 1.0)); - fragTexCoord = vertexTexCoord; - fragNormal = normalize(vec3(matNormal * vec4(vertexNormal, 1.0))); - height = displacedPosition.y * 0.2; // Send height to fragment shader for coloring - - // Calculate final vertex position - gl_Position = mvp * vec4(displacedPosition, 1.0); -} diff --git a/examples/shaders/vertex_displacement/main.go b/examples/shaders/vertex_displacement/main.go deleted file mode 100644 index d7c0677..0000000 --- a/examples/shaders/vertex_displacement/main.go +++ /dev/null @@ -1,143 +0,0 @@ -/******************************************************************************************* -* -* raylib [shaders] example - Vertex displacement -* -* Example complexity rating: [★★★☆] 3/4 -* -* Example originally created with raylib 5.0, last time updated with raylib 5.5 -* -* Example originally contributed by Alex ZH (@ZzzhHe) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2023-2025 Alex ZH (@ZzzhHe) -* -********************************************************************************************/ - -package main - -import ( - "fmt" - "os" - "path/filepath" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -// NOTE: Usage: `PLATFORM_DESKTOP=1 go run .` -var glslVersion int - -func init() { - if v, ok := os.LookupEnv("PLATFORM_DESKTOP"); ok && v == "1" { - glslVersion = 330 - } else { // PLATFORM_ANDROID, PLATFORM_WEB - glslVersion = 100 - } -} - -// ------------------------------------------------------------------------------------ -// Program main entry point -// ------------------------------------------------------------------------------------ -func main() { - // Initialization - //-------------------------------------------------------------------------------------- - const screenWidth int32 = 800 - const screenHeight int32 = 450 - - rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement") - defer rl.CloseWindow() // Close window and OpenGL context - - // Set up camera - camera := rl.Camera{ - Position: rl.NewVector3(20.0, 5.0, -20.0), - Target: rl.Vector3Zero(), - Up: rl.NewVector3(0.0, 1.0, 0.0), - Fovy: 60.0, - Projection: rl.CameraPerspective, - } - - // Load vertex and fragment shaders - shaderDir := fmt.Sprintf("glsl%d", glslVersion) - - shader := rl.LoadShader( - filepath.Join(shaderDir, "vertex_displacement.vs"), - filepath.Join(shaderDir, "vertex_displacement.fs"), - ) - defer rl.UnloadShader(shader) - - timeLoc := rl.GetShaderLocation(shader, "time") - - // Load perlin noise texture - perlinNoiseImage := rl.GenImagePerlinNoise(512, 512, 0, 0, 1.0) - perlinNoiseMap := rl.LoadTextureFromImage(perlinNoiseImage) - defer rl.UnloadTexture(perlinNoiseMap) - rl.UnloadImage(perlinNoiseImage) - - // Set shader uniform location - perlinNoiseMapLoc := rl.GetShaderLocation(shader, "perlinNoiseMap") - rl.EnableShader(shader.ID) - rl.ActiveTextureSlot(1) - rl.EnableTexture(perlinNoiseMap.ID) - rl.SetUniformSampler(perlinNoiseMapLoc, 1) - - // Create a plane mesh and model - planeMesh := rl.GenMeshPlane(50, 50, 50, 50) - planeModel := rl.LoadModelFromMesh(planeMesh) - defer rl.UnloadModel(planeModel) - - // Set plane model material - planeModel.Materials.Shader = shader - - timer := float32(0) - - rl.DisableCursor() - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode - - deltaTime := rl.GetFrameTime() - timer += deltaTime - timeValue := []float32{timer} - - rl.SetShaderValue(shader, timeLoc, timeValue, rl.ShaderUniformFloat) // Send time value to shader - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - - rl.BeginShaderMode(shader) - - // Draw plane model - rl.DrawModel(planeModel, rl.Vector3Zero(), 1.0, rl.White) - - rl.EndShaderMode() - - rl.EndMode3D() - - rl.DrawText("Vertex displacement", 10, 10, 20, rl.DarkGray) - - rl.DrawFPS(10, 40) - - rl.EndDrawing() - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - // NOTE: Unload all loaded resources at this point (that are not `defer`-ed) - //-------------------------------------------------------------------------------------- -} diff --git a/examples/shapes/basic_shapes/main.go b/examples/shapes/basic_shapes/main.go index 560ce56..62fbdb9 100644 --- a/examples/shapes/basic_shapes/main.go +++ b/examples/shapes/basic_shapes/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/shapes/bouncing_ball/main.go b/examples/shapes/bouncing_ball/main.go deleted file mode 100644 index f5a47d3..0000000 --- a/examples/shapes/bouncing_ball/main.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - bouncing ball") - - ballPos := rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2) - ballSpeed := rl.NewVector2(5, 4) - ballRadius := 20 - - pause := false - frames := 0 - - rl.SetTargetFPS(60) - - rl.SetMousePosition(0, 0) - - for !rl.WindowShouldClose() { - - if rl.IsKeyPressed(rl.KeySpace) { - pause = !pause - } - - if !pause { - ballPos.X += ballSpeed.X - ballPos.Y += ballSpeed.Y - if ballPos.X >= float32(screenWidth)-float32(ballRadius) || ballPos.X <= float32(ballRadius) { - ballSpeed.X *= -1 - } - if ballPos.Y >= float32(screenHeight)-float32(ballRadius) || ballPos.Y <= float32(ballRadius) { - ballSpeed.Y *= -1 - } - } else { - frames++ - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("SPACE key to pause", 10, 10, 20, rl.Black) - - rl.DrawCircleV(ballPos, float32(ballRadius), rl.Red) - - if pause && (frames/30)%2 == 0 { - rl.DrawText("PAUSED", 10, screenHeight-40, 30, rl.Black) - } - - rl.DrawFPS(screenWidth-100, 10) - - rl.EndDrawing() - - } - - rl.CloseWindow() -} diff --git a/examples/shapes/collision_area/main.go b/examples/shapes/collision_area/main.go deleted file mode 100644 index 225ec09..0000000 --- a/examples/shapes/collision_area/main.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenWidth = int32(1280) - screenHeight = int32(720) - - pause = false - collision = false - - boxCollision = rl.Rectangle{} - screenUpperLimit = float32(40) - boxAspeedX = float32(4) -) - -func main() { - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - collision area") - - rl.SetTargetFPS(60) - - boxA := rl.NewRectangle(10, float32(rl.GetScreenHeight()/2)-50, 200, 100) - boxB := rl.NewRectangle(float32(rl.GetScreenWidth()/2)-30, float32(rl.GetScreenHeight()/2)-30, 60, 60) - - for !rl.WindowShouldClose() { - - mousePos := rl.GetMousePosition() - - if !pause { - boxA.X += boxAspeedX - } - if boxA.X+boxA.Width >= float32(rl.GetScreenWidth()) || boxA.X <= 0 { - boxAspeedX *= -1 - } - - boxB.X = mousePos.X - boxB.Width/2 - boxB.Y = mousePos.Y - boxB.Height/2 - - if boxB.X+boxB.Width >= float32(rl.GetScreenWidth()) { - boxB.X = float32(rl.GetScreenWidth()) - boxB.Width - } else if boxB.X <= 0 { - boxB.X = 0 - } - - if boxB.Y+boxB.Height >= float32(rl.GetScreenHeight()) { - boxB.Y = float32(rl.GetScreenHeight()) - boxB.Height - } else if boxB.X <= screenUpperLimit { - boxB.Y = screenUpperLimit - } - - collision := rl.CheckCollisionRecs(boxA, boxB) - - if collision { - boxCollision = rl.GetCollisionRec(boxA, boxB) - } - - if rl.IsKeyPressed(rl.KeySpace) { - pause = !pause - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - if collision { - rl.DrawRectangle(0, 0, screenWidth, int32(screenUpperLimit), rl.Red) - rl.DrawRectangleRec(boxCollision, rl.Lime) - rl.DrawText("COLLISION", int32(rl.GetScreenWidth()/2)-(rl.MeasureText("COLLISION", 20)/2), int32(screenUpperLimit/2)-10, 20, rl.Black) - rl.DrawText("Collision Area: "+fmt.Sprint(boxCollision.Width*boxCollision.Height), int32(rl.GetScreenWidth()/2)-100, int32(screenUpperLimit+10), 20, rl.Black) - } else { - rl.DrawRectangle(0, 0, screenWidth, int32(screenUpperLimit), rl.Black) - } - - rl.DrawRectangleRec(boxA, rl.Orange) - rl.DrawRectangleRec(boxB, rl.Blue) - - rl.DrawText("Press SPACE to PAUSE/RESUME", 20, int32(rl.GetScreenHeight())-35, 20, rl.Black) - - rl.EndDrawing() - - } - - rl.CloseWindow() -} diff --git a/examples/shapes/colors_pallete/main.go b/examples/shapes/colors_pallete/main.go index f4189ae..c732bbb 100644 --- a/examples/shapes/colors_pallete/main.go +++ b/examples/shapes/colors_pallete/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/shapes/draw_circle_sector/main.go b/examples/shapes/draw_circle_sector/main.go deleted file mode 100644 index e754294..0000000 --- a/examples/shapes/draw_circle_sector/main.go +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************************* - * - * raylib [shapes] example - draw circle sector (with gui options) - * - * Example originally created with raylib 2.5, last time updated with raylib 2.5 - * - * Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) - * - * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, - * BSD-like license that allows static linking with closed source software - * - * Copyright (c) 2018-2024 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) - * - ********************************************************************************************/ -package main - -import ( - "fmt" - "math" - - gui "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw circle sector") - - center := rl.Vector2{X: (float32(screenWidth) - 300) / 2.0, Y: float32(screenHeight / 2.0)} - var outerRadius, startAngle, endAngle, segments, minSegments float32 = 180.0, 0.0, 180.0, 10.0, 4 - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.DrawLine(500, 0, 500, screenWidth, rl.Fade(rl.LightGray, 0.6)) - rl.DrawRectangle(500, 0, screenWidth-500, screenHeight, rl.Fade(rl.LightGray, 0.3)) - - rl.DrawCircleSector(center, outerRadius, startAngle, endAngle, int32(segments), rl.Fade(rl.Maroon, 0.3)) - rl.DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, int32(segments), rl.Fade(rl.Maroon, 0.6)) - - // Draw GUI controls - r := rl.Rectangle{X: 600, Y: 40, Width: 120, Height: 20} - msg := fmt.Sprintf("%.2f", startAngle) - startAngle = gui.Slider(r, "StartAngle", msg, startAngle, 0, 720) - - r = rl.Rectangle{X: 600, Y: 70, Width: 120, Height: 20} - msg = fmt.Sprintf("%.2f", endAngle) - endAngle = gui.Slider(r, "EndAngle", msg, endAngle, 0, 720) - - r = rl.Rectangle{X: 600, Y: 140, Width: 120, Height: 20} - msg = fmt.Sprintf("%.2f", outerRadius) - outerRadius = gui.Slider(r, "Radius", msg, outerRadius, 0, 200) - - r = rl.Rectangle{X: 600, Y: 170, Width: 120, Height: 20} - msg = fmt.Sprintf("%.2f", segments) - segments = gui.Slider(r, "Segments", msg, segments, 0, 100) - - minSegments = calculateMinSegments(startAngle, endAngle) - text := "MODE: AUTO" - color := rl.DarkGray - if segments >= minSegments { - text = "MODE: MANUAL" - color = rl.Maroon - } - rl.DrawText(text, 600, 200, 10, color) - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - // De-Initialization - rl.CloseWindow() // Close window and OpenGL context -} - -func calculateMinSegments(startAngle, endAngle float32) float32 { - return float32(math.Trunc(math.Ceil((float64(endAngle - startAngle)) / 90))) -} diff --git a/examples/shapes/draw_ring/main.go b/examples/shapes/draw_ring/main.go deleted file mode 100644 index ace9aee..0000000 --- a/examples/shapes/draw_ring/main.go +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************************* -* -* raylib [shapes] example - draw ring (with gui options) -* -* Example originally created with raylib 2.5, last time updated with raylib 2.5 -* -* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2018-2024 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "math" - - gui "git.terah.dev/UnrealXR/raylib-go/raygui" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw ring") - - center := rl.Vector2{X: (float32(rl.GetScreenWidth()) - 300) / 2.0, Y: float32(rl.GetScreenHeight()) / 2.0} - - var innerRadius, outerRadius float32 = 80.0, 190.0 - var startAngle, endAngle float32 = 0.0, 360 - var segments float32 = 0.0 - - drawRing, drawRingLines, drawSectorLines := true, false, false - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - // NOTE: All variables update happens inside GUI control functions - - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.DrawLine(500, 0, 500, int32(rl.GetScreenHeight()), rl.Fade(rl.LightGray, 0.6)) - rl.DrawRectangle(500, 0, int32(rl.GetScreenWidth())-500, int32(rl.GetScreenHeight()), - rl.Fade(rl.LightGray, 0.3)) - - if drawRing { - rl.DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, int32( - segments), rl.Fade(rl.Maroon, 0.3)) - } - if drawRingLines { - rl.DrawRingLines(center, innerRadius, outerRadius, startAngle, endAngle, int32( - segments), rl.Fade(rl.Black, 0.4)) - } - if drawSectorLines { - rl.DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, int32( - segments), rl.Fade(rl.Black, 0.4)) - } - - // Draw GUI controls - //------------------------------------------------------------------------------ - startAngle = gui.Slider(rl.Rectangle{ - X: 600, Y: 40, Width: 120, Height: 20, - }, "StartAngle", fmt.Sprintf("%.2f", startAngle), startAngle, -450, 450) - endAngle = gui.Slider(rl.Rectangle{ - X: 600, Y: 70, Width: 120, Height: 20, - }, "EndAngle", fmt.Sprintf("%.2f", endAngle), endAngle, -450, 450) - - innerRadius = gui.Slider(rl.Rectangle{ - X: 600, Y: 140, Width: 120, Height: 20, - }, "InnerRadius", fmt.Sprintf("%.2f", innerRadius), innerRadius, 0, 100) - outerRadius = gui.Slider(rl.Rectangle{ - X: 600, Y: 170, Width: 120, Height: 20, - }, "OuterRadius", fmt.Sprintf("%.2f", outerRadius), outerRadius, 0, 200) - - segments = gui.Slider(rl.Rectangle{ - X: 600, Y: 240, Width: 120, Height: 20, - }, "Segments", fmt.Sprintf("%.2f", segments), segments, 0, 100) - - drawRing = gui.CheckBox(rl.Rectangle{ - X: 600, Y: 320, Width: 20, Height: 20, - }, "Draw Ring", drawRing) - drawRingLines = gui.CheckBox(rl.Rectangle{ - X: 600, Y: 350, Width: 20, Height: 20, - }, "Draw Ring Lines", drawRingLines) - drawSectorLines = gui.CheckBox(rl.Rectangle{ - X: 600, Y: 380, Width: 20, Height: 20, - }, "Draw Sector Lines", drawSectorLines) - - minSegments := ceil((endAngle - startAngle) / 90) - var color = rl.DarkGray - if segments >= minSegments { - color = rl.Maroon - } - var mode = "AUTO" - if segments >= minSegments { - mode = "MANUAL" - } - rl.DrawText(fmt.Sprintf("MODE: %s", mode), 600, 270, 10, color) - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - // De-Initialization - rl.CloseWindow() // Close window and OpenGL context -} - -func ceil(value float32) float32 { - return float32(math.Ceil(float64(value))) -} diff --git a/examples/shapes/easings_ball_anim/main.go b/examples/shapes/easings_ball_anim/main.go deleted file mode 100644 index 7927b8e..0000000 --- a/examples/shapes/easings_ball_anim/main.go +++ /dev/null @@ -1,86 +0,0 @@ -package main - -import ( - ez "git.terah.dev/UnrealXR/raylib-go/easings" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings ball anim") - - ballPosX := -100 - ballRadius := 20 - ballAlpha := float32(0) - - state := 0 - frames := 0 - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - if state == 0 { - - frames++ - ballPosX = int(ez.ElasticOut(float32(frames), -100, float32(screenWidth/2)+100, 100)) - - if frames >= 100 { - frames = 0 - state = 1 - } - - } else if state == 1 { - frames++ - ballRadius = int(ez.ElasticIn(float32(frames), 20, 500, 150)) - - if frames >= 150 { - frames = 0 - state = 2 - } - } else if state == 2 { - frames++ - ballAlpha = ez.CubicOut(float32(frames), 0, 1, 150) - - if frames >= 150 { - frames = 0 - state = 3 - } - } else if state == 3 { - if rl.IsKeyPressed(rl.KeyEnter) { - ballPosX = -100 - ballRadius = 20 - ballAlpha = 0 - state = 0 - } - - } - - if rl.IsKeyPressed(rl.KeyR) { - frames = 0 - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - if state >= 2 { - rl.DrawRectangle(0, 0, screenWidth, screenHeight, rl.Green) - } - - rl.DrawCircle(int32(ballPosX), 200, float32(ballRadius), rl.Fade(rl.Red, 1-ballAlpha)) - - if state == 3 { - textlen := rl.MeasureText("press ENTER to replay", 20) - rl.DrawText("press ENTER to replay", (screenWidth/2)-textlen/2, 200, 20, rl.Black) - } - - rl.EndDrawing() - - } - - rl.CloseWindow() -} diff --git a/examples/shapes/easings_box_anim/main.go b/examples/shapes/easings_box_anim/main.go deleted file mode 100644 index 9a65db5..0000000 --- a/examples/shapes/easings_box_anim/main.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - ez "git.terah.dev/UnrealXR/raylib-go/easings" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - fps = int32(60) -) - -const ( - screenWidth = int32(800) - screenHeight = int32(450) -) - -func main() { - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings box anim") - - rec := rl.NewRectangle(float32(screenWidth/2), -100, 100, 100) - rotation := float32(0) - alpha := float32(1) - - state := 0 - frames := 0 - - rl.SetTargetFPS(fps) - - for !rl.WindowShouldClose() { - - switch state { - case 0: - frames++ - - rec.Y = ez.ElasticOut(float32(frames), -100, float32(screenHeight/2)+100, 120) - - if frames >= 120 { - frames = 0 - state = 1 - } - - case 1: - frames++ - rec.Height = ez.BounceOut(float32(frames), 100, -90, 120) - rec.Width = ez.BounceOut(float32(frames), 100, float32(screenWidth), 120) - - if frames >= 120 { - frames++ - state = 2 - } - case 2: - frames++ - rotation = ez.QuadOut(float32(frames), 0, 270, 240) - if frames >= 240 { - frames = 0 - state = 3 - } - case 3: - frames++ - rec.Height = ez.CircOut(float32(frames), 10, float32(screenWidth), 120) - if frames >= 120 { - frames = 0 - state = 4 - } - - case 4: - frames++ - alpha = ez.SineOut(float32(frames), 1, -1, 160) - if frames >= 160 { - frames = 0 - state = 5 - } - default: - break - } - - if rl.IsKeyPressed(rl.KeySpace) { - rec = rl.NewRectangle(float32(screenWidth/2), -100, 100, 100) - rotation = 0 - alpha = 1 - state = 0 - frames = 0 - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawRectanglePro(rec, rl.NewVector2(rec.Width/2, rec.Height/2), rotation, rl.Fade(rl.Black, alpha)) - - if state == 5 { - txtlen := rl.MeasureText("SPACE to replay", 20) - rl.DrawText("SPACE to replay", (screenWidth/2)-txtlen/2, 200, 20, rl.Black) - } - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/shapes/easings_rectangle_array/main.go b/examples/shapes/easings_rectangle_array/main.go deleted file mode 100644 index 287cf75..0000000 --- a/examples/shapes/easings_rectangle_array/main.go +++ /dev/null @@ -1,92 +0,0 @@ -package main - -import ( - ez "git.terah.dev/UnrealXR/raylib-go/easings" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - playTime = float32(240) - fps = int32(60) -) - -const ( - recsW, recsH = 50, 50 - screenWidth = int32(800) - screenHeight = int32(450) - maxRecsX = int(screenWidth) / recsW - maxRecsY = int(screenHeight) / recsH -) - -func main() { - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings rectangle array") - - var recs [maxRecsX * maxRecsY]rl.Rectangle - - for y := 0; y < maxRecsY; y++ { - - for x := 0; x < maxRecsX; x++ { - recs[y*maxRecsX+x].X = float32(recsW/2 + recsW*float32(x)) - recs[y*maxRecsX+x].Y = float32(recsH/2 + recsH*float32(y)) - recs[y*maxRecsX+x].Width = float32(recsW) - recs[y*maxRecsX+x].Height = float32(recsH) - } - - } - - rotation := float32(0) - frameCount := float32(0) - state := 0 - - rl.SetTargetFPS(fps) - - for !rl.WindowShouldClose() { - - if state == 0 { - frameCount++ - - for i := 0; i < maxRecsX*maxRecsY; i++ { - recs[i].Height = float32(ez.LinearIn(frameCount, recsH, -recsH, playTime)) - recs[i].Width = float32(ez.LinearIn(frameCount, recsW, -recsW, playTime)) - - if recs[i].Height < 0 { - recs[i].Height = 0 - } - - if recs[i].Width < 0 { - recs[i].Width = 0 - } - - if recs[i].Height == 0 && recs[i].Width == 0 { - state = 1 - } - rotation = float32(ez.LinearIn(frameCount, 0, 360, playTime)) - } - } else if state == 1 && rl.IsKeyPressed(rl.KeySpace) { - frameCount = 0 - for i := 0; i < maxRecsX*maxRecsY; i++ { - recs[i].Height = float32(recsH) - recs[i].Width = float32(recsW) - } - - state = 0 - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - if state == 0 { - for i := 0; i < maxRecsX*maxRecsY; i++ { - rl.DrawRectanglePro(recs[i], rl.NewVector2(recs[i].Width/2, recs[i].Height/2), rotation, rl.Red) - } - } else if state == 1 { - txtlen := rl.MeasureText("SPACE to replay", 20) - rl.DrawText("SPACE to replay", (screenWidth/2)-txtlen/2, 200, 20, rl.Black) - } - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/shapes/following_eyes/main.go b/examples/shapes/following_eyes/main.go deleted file mode 100644 index a52a318..0000000 --- a/examples/shapes/following_eyes/main.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - following eyes") - - scleraLpos := rl.NewVector2(float32(screenWidth/2)-100, float32(screenHeight/2)) - scleraRpos := rl.NewVector2(float32(screenWidth/2)+100, float32(screenHeight/2)) - scleraRad := 80 - - irisLpos := rl.NewVector2(float32(screenWidth/2)-100, float32(screenHeight/2)) - irisRpos := rl.NewVector2(float32(screenWidth/2)+100, float32(screenHeight/2)) - irisRad := 24 - - angle := float32(0) - dx, dy, dxx, dyy := float32(0), float32(0), float32(0), float32(0) - - rl.SetTargetFPS(60) - - rl.SetMousePosition(0, 0) - - for !rl.WindowShouldClose() { - - irisLpos = rl.GetMousePosition() - irisRpos = rl.GetMousePosition() - - if !rl.CheckCollisionPointCircle(irisLpos, scleraLpos, float32(scleraRad-20)) { - - dx = irisLpos.X - scleraLpos.X - dy = irisLpos.Y - scleraLpos.Y - - angle = float32(math.Atan2(float64(dy), float64(dx))) - - dxx = (float32(scleraRad-irisRad) * float32(math.Cos(float64(angle)))) - dyy = (float32(scleraRad-irisRad) * float32(math.Sin(float64(angle)))) - - irisLpos.X = scleraLpos.X + dxx - irisLpos.Y = scleraLpos.Y + dyy - - } - - if !rl.CheckCollisionPointCircle(irisRpos, scleraRpos, float32(scleraRad)-20) { - dx = irisRpos.X - scleraRpos.X - dy = irisRpos.Y - scleraRpos.Y - - angle = float32(math.Atan2(float64(dy), float64(dx))) - - dxx = (float32(scleraRad-irisRad) * float32(math.Cos(float64(angle)))) - dyy = (float32(scleraRad-irisRad) * float32(math.Sin(float64(angle)))) - - irisRpos.X = scleraRpos.X + dxx - irisRpos.Y = scleraRpos.Y + dyy - - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawCircleV(scleraLpos, float32(scleraRad), rl.LightGray) - rl.DrawCircleV(irisLpos, float32(irisRad), rl.Red) - rl.DrawCircleV(irisLpos, 10, rl.Black) - - rl.DrawCircleV(scleraRpos, float32(scleraRad), rl.LightGray) - rl.DrawCircleV(irisRpos, float32(irisRad), rl.Orange) - rl.DrawCircleV(irisRpos, 10, rl.Black) - - rl.DrawFPS(screenWidth-100, 10) - - rl.EndDrawing() - - } - - rl.CloseWindow() -} diff --git a/examples/shapes/lines_bezier/main.go b/examples/shapes/lines_bezier/main.go index f1eeb10..dd2e0bb 100644 --- a/examples/shapes/lines_bezier/main.go +++ b/examples/shapes/lines_bezier/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/shapes/logo_raylib/main.go b/examples/shapes/logo_raylib/main.go index 4e300ef..79b2062 100644 --- a/examples/shapes/logo_raylib/main.go +++ b/examples/shapes/logo_raylib/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/shapes/logo_raylib_anim/main.go b/examples/shapes/logo_raylib_anim/main.go index 1e4e2c6..931084e 100644 --- a/examples/shapes/logo_raylib_anim/main.go +++ b/examples/shapes/logo_raylib_anim/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/shapes/rectangle_scaling/main.go b/examples/shapes/rectangle_scaling/main.go deleted file mode 100644 index 029fef5..0000000 --- a/examples/shapes/rectangle_scaling/main.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - mouseScaleMarkSize = float32(12) - rec = rl.NewRectangle(100, 100, 200, 80) - mouseScaleReady, MouseScaleMode = false, false -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rectangle scaling mouse") - - rl.SetTargetFPS(60) - - rl.SetMousePosition(0, 0) - - for !rl.WindowShouldClose() { - - mousePos := rl.GetMousePosition() - - if rl.CheckCollisionPointRec(mousePos, rl.NewRectangle(rec.X+rec.Width-mouseScaleMarkSize, rec.Y+rec.Height-mouseScaleMarkSize, mouseScaleMarkSize, mouseScaleMarkSize)) { - mouseScaleReady = true - if rl.IsMouseButtonPressed(rl.MouseLeftButton) { - MouseScaleMode = true - } - } else { - mouseScaleReady = false - } - - if MouseScaleMode { - - mouseScaleReady = true - rec.Width = mousePos.X - rec.X - rec.Height = mousePos.Y - rec.Y - - // CHECK MIN MAX REC SIZES - if rec.Width < mouseScaleMarkSize { - rec.Width = rec.Width - } - if rec.Height < mouseScaleMarkSize { - rec.Height = rec.Width - } - if rec.Width > (float32(rl.GetScreenWidth()) - rec.X) { - rec.Width = float32(rl.GetScreenWidth()) - rec.X - } - if rec.Height > (float32(rl.GetScreenHeight()) - rec.Y) { - rec.Height = float32(rl.GetScreenHeight()) - rec.Y - } - if rl.IsMouseButtonReleased(rl.MouseLeftButton) { - MouseScaleMode = false - } - - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("Scale rectangle dragging from bottom-right corner!", 10, 10, 20, rl.Black) - - rl.DrawRectangleRec(rec, rl.Fade(rl.Green, 0.5)) - - if mouseScaleReady { - rl.DrawRectangleLinesEx(rec, 1, rl.Red) - rl.DrawTriangle(rl.NewVector2(rec.X+rec.Width-mouseScaleMarkSize, rec.Y+rec.Height), rl.NewVector2(rec.X+rec.Width, rec.Y+rec.Height), rl.NewVector2(rec.X+rec.Width, rec.Y+rec.Height-mouseScaleMarkSize), rl.Red) - } - - rl.EndDrawing() - - } - - rl.CloseWindow() -} diff --git a/examples/text/bmfont_ttf/main.go b/examples/text/bmfont_ttf/main.go index a1724dd..1378eae 100644 --- a/examples/text/bmfont_ttf/main.go +++ b/examples/text/bmfont_ttf/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/text/bmfont_unordered/main.go b/examples/text/bmfont_unordered/main.go index f67f0b4..54df292 100644 --- a/examples/text/bmfont_unordered/main.go +++ b/examples/text/bmfont_unordered/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/text/codepoints_loading/DotGothic16-Regular.ttf b/examples/text/codepoints_loading/DotGothic16-Regular.ttf deleted file mode 100644 index 18b0c1e..0000000 Binary files a/examples/text/codepoints_loading/DotGothic16-Regular.ttf and /dev/null differ diff --git a/examples/text/codepoints_loading/main.go b/examples/text/codepoints_loading/main.go deleted file mode 100644 index d8793a1..0000000 --- a/examples/text/codepoints_loading/main.go +++ /dev/null @@ -1,95 +0,0 @@ -/******************************************************************************************* -* -* raylib [text] example - Codepoints loading -* -* Example originally created with raylib 4.2, last time updated with raylib 2.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2022-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "slices" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - codepoints loading") - - // Text to be displayed, must be UTF-8 (save this code file as UTF-8) - // NOTE: It can contain all the required text for the game, - // this text will be scanned to get all the required codepoints - text := "いろはにほへと ちりぬるを\nわかよたれそ つねならむ\nうゐのおくやま けふこえて\nあさきゆめみし ゑひもせす" - - // Get codepoints from text - allCodepoints := []rune(text) - - // Removed duplicate codepoints to generate smaller font atlas - slices.Sort(allCodepoints) - codepoints := slices.Compact(allCodepoints) - codepointsCount := len(codepoints) - - // Load font containing all the provided codepoint glyphs - // A texture font atlas is automatically generated - font := rl.LoadFontEx("DotGothic16-Regular.ttf", 36, codepoints, int32(codepointsCount)) - - // Set bi-linear scale filter for better font scaling - rl.SetTextureFilter(font.Texture, rl.FilterBilinear) - // Set line spacing for multiline text (when line breaks are included '\n') - rl.SetTextLineSpacing(20) - - showFontAtlas := false - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - if rl.IsKeyPressed(rl.KeySpace) { - showFontAtlas = !showFontAtlas - } - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawRectangle(0, 0, screenWidth, 70, rl.Black) - msg := fmt.Sprintf("Total codepoints contained in provided text: %d", len(allCodepoints)) - rl.DrawText(msg, 10, 10, 20, rl.Green) - msg = fmt.Sprintf("Total codepoints required for font atlas (duplicates excluded): %d", codepointsCount) - rl.DrawText(msg, 10, 40, 20, rl.Green) - - if showFontAtlas { - // Draw generated font texture atlas containing provided codepoints - rl.DrawTexture(font.Texture, 150, 100, rl.Black) - rl.DrawRectangleLines(150, 100, font.Texture.Width, font.Texture.Height, rl.Black) - } else { - // Draw provided text with loaded font, containing all required codepoint glyphs - pos := rl.Vector2{ - X: 160, - Y: 110, - } - rl.DrawTextEx(font, text, pos, 48, 5, rl.Black) - } - - msg = "Press SPACE to toggle font atlas view!" - rl.DrawText(msg, 10, screenHeight-30, 20, rl.Gray) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadFont(font) // Unload font - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/text/draw_3d/alpha_discard.fs b/examples/text/draw_3d/alpha_discard.fs deleted file mode 100644 index d2134a6..0000000 --- a/examples/text/draw_3d/alpha_discard.fs +++ /dev/null @@ -1,19 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -void main() -{ - vec4 texelColor = texture(texture0, fragTexCoord); - if (texelColor.a == 0.0) discard; - finalColor = texelColor * fragColor * colDiffuse; -} diff --git a/examples/text/draw_3d/main.go b/examples/text/draw_3d/main.go deleted file mode 100644 index e534924..0000000 --- a/examples/text/draw_3d/main.go +++ /dev/null @@ -1,822 +0,0 @@ -/******************************************************************************************* -* -* raylib [text] example - Draw 3d -* -* NOTE: Draw a 2D text in 3D space, each letter is drawn in a quad (or 2 quads if back face is set) -* where the texture coordinates of each quad map to the texture coordinates of the glyphs -* inside the font texture. -* -* A more efficient approach, i believe, would be to render the text in a render texture and -* map that texture to a plane and render that, or maybe a shader but my method allows more -* flexibility...for example to change position of each letter individually to make some think -* like a wavy text effect. -* -* Special thanks to: -* @Nighten for the DrawTextStyle() code https://github.com/NightenDushi/Raylib_DrawTextStyle -* Chris Camacho (codifies - http://bedroomcoders.co.uk/) for the alpha discard shader -* -* Example originally created with raylib 3.5, last time updated with raylib 4.0 -* -* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2021-2024 Vlad Adrian (@demizdor) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "math" - "path/filepath" - "unicode/utf8" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -// Globals -const ( - letterBoundarySize = 0.25 - textMaxLayers = 32 - maxTextLength = 64 - screenWidth = 800 - screenHeight = 450 -) - -var letterBoundaryColor = rl.Violet -var showLetterBoundary, showTextBoundary = false, false - -// Data Types definition - -// WaveTextConfig is a configuration structure for waving the text -type WaveTextConfig struct { - waveRange, waveSpeed, waveOffset rl.Vector3 -} - -// Program main entry point -func main() { - // Initialization - rl.SetConfigFlags(rl.FlagMsaa4xHint | rl.FlagVsyncHint) - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - draw 2D text in 3D") - - spin := true // Spin the camera? - multicolor := false // Multicolor mode - - // Define the camera to look into our 3d world - camera := rl.Camera3D{ - Position: rl.Vector3{ - X: -10.0, - Y: 15.0, - Z: -10.0, - }, // Camera position - Target: rl.Vector3{}, // Camera looking at point - Up: rl.Vector3{Y: 1.0}, // Camera up vector (rotation towards target) - Fovy: 45.0, // Camera field-of-view Y - Projection: rl.CameraPerspective, // Camera projection type - } - - cameraMode := rl.CameraOrbital - - cubePosition := rl.Vector3{Y: 1.0} - cubeSize := rl.Vector3{ - X: 2.0, - Y: 2.0, - Z: 2.0, - } - - // Use the default font - font := rl.GetFontDefault() - var fontSize, fontSpacing, lineSpacing float32 = 8.0, 0.5, -1 - - // Set the text (using markdown!) - text := "Hello ~~World~~ in 3D!" - tbox := rl.Vector3{} - var layers, quads int32 = 1, 0 - var layerDistance float32 = 0.01 - - wcfg := WaveTextConfig{ - waveSpeed: rl.Vector3{ - X: 3, - Y: 3, - Z: 0.5, - }, - waveOffset: rl.Vector3{ - X: 0.35, - Y: 0.35, - Z: 0.35, - }, - waveRange: rl.Vector3{ - X: 0.45, - Y: 0.45, - Z: 0.45, - }, - } - - var time float32 - - // Set up a light and dark color - light, dark := rl.Maroon, rl.Red - - // Load the alpha discard shader - alphaDiscard := rl.LoadShader("", "alpha_discard.fs") - - // Array filled with multiple random colors (when multicolor mode is set) - var multi [textMaxLayers]rl.Color - - rl.DisableCursor() // Limit cursor to relative movement inside the window - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - rl.UpdateCamera(&camera, cameraMode) - - // Handle font files dropped - if rl.IsFileDropped() { - droppedFiles := rl.LoadDroppedFiles() - - // NOTE: We only support first ttf file dropped - rl.UnloadFont(font) - if filepath.Ext(droppedFiles[0]) == ".ttf" { - font = rl.LoadFontEx(droppedFiles[0], int32(fontSize), nil, 0) - } else if filepath.Ext(droppedFiles[0]) == ".fnt" { - font = rl.LoadFont(droppedFiles[0]) - fontSize = float32(font.BaseSize) - } - - rl.UnloadDroppedFiles() // Unload file paths from memory - } - - // Handle Events - if rl.IsKeyPressed(rl.KeyF1) { - showLetterBoundary = !showLetterBoundary - } - if rl.IsKeyPressed(rl.KeyF2) { - showTextBoundary = !showTextBoundary - } - if rl.IsKeyPressed(rl.KeyF3) { - // Handle camera change - spin = !spin - // we need to reset the camera when changing modes - camera = rl.Camera3D{ - Target: rl.Vector3{}, // Camera looking at point - Up: rl.Vector3{Y: 1.0}, // Camera up vector (rotation towards target) - Fovy: 45.0, // Camera field-of-view Y - Projection: rl.CameraPerspective, // Camera projection type - } - - if spin { - camera.Position = rl.Vector3{ - X: -10.0, - Y: 15.0, - Z: -10.0, - } // Camera position - cameraMode = rl.CameraOrbital - } else { - camera.Position = rl.Vector3{ - X: 10.0, - Y: 10.0, - Z: -10.0, - } // Camera position - cameraMode = rl.CameraFree - } - } - - // Handle clicking the cube - if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { - // TODO : Missing function, see issue https://git.terah.dev/UnrealXR/raylib-go/issues/457 - //ray := rl.GetScreenToWorldRay(rl.GetMousePosition(), camera) - ray := rl.GetMouseRay(rl.GetMousePosition(), camera) - - // Check collision between ray and box - v1 := rl.Vector3{ - X: cubePosition.X - cubeSize.X/2, - Y: cubePosition.Y - cubeSize.Y/2, - Z: cubePosition.Z - cubeSize.Z/2, - } - v2 := rl.Vector3{ - X: cubePosition.X + cubeSize.X/2, - Y: cubePosition.Y + cubeSize.Y/2, - Z: cubePosition.Z + cubeSize.Z/2, - } - collision := rl.GetRayCollisionBox(ray, rl.BoundingBox{ - Min: v1, - Max: v2, - }) - - if collision.Hit { - // Generate new random colors - light = generateRandomColor(0.5, 0.78) - dark = generateRandomColor(0.4, 0.58) - } - } - - // Handle text layers changes - if rl.IsKeyPressed(rl.KeyHome) && layers > 1 { - layers-- - } else if rl.IsKeyPressed(rl.KeyEnd) && layers < textMaxLayers { - layers++ - } - - // Handle text changes - if rl.IsKeyPressed(rl.KeyLeft) { - fontSize -= 0.5 - } else if rl.IsKeyPressed(rl.KeyRight) { - fontSize += 0.5 - } else if rl.IsKeyPressed(rl.KeyUp) { - fontSpacing -= 0.1 - } else if rl.IsKeyPressed(rl.KeyDown) { - fontSpacing += 0.1 - } else if rl.IsKeyPressed(rl.KeyPageUp) { - lineSpacing -= 0.5 - } else if rl.IsKeyPressed(rl.KeyPageDown) { - lineSpacing += 0.5 - } else if rl.IsKeyDown(rl.KeyInsert) { - layerDistance -= 0.001 - } else if rl.IsKeyDown(rl.KeyDelete) { - layerDistance += 0.001 - } else if rl.IsKeyPressed(rl.KeyTab) { - multicolor = !multicolor // Enable /disable multicolor mode - - if multicolor { - // Fill color array with random colors - for i := 0; i < textMaxLayers; i++ { - multi[i] = generateRandomColor(0.5, 0.8) - multi[i].A = uint8(rl.GetRandomValue(0, 255)) - } - } - } - - // Handle text input - ch := rl.GetCharPressed() - if rl.IsKeyPressed(rl.KeyBackspace) { - // Remove last char - text = text[:len(text)-1] - } else if rl.IsKeyPressed(rl.KeyEnter) { - // handle newline - text += "\n" - } else if ch != 0 && len(text) < maxTextLength { - // append only printable chars - text += string(ch) - } - - // Measure 3D text so we can center it - tbox = measureTextWave3D(font, text, fontSize, fontSpacing, lineSpacing) - - quads = 0 // Reset quad counter - time += rl.GetFrameTime() // Update timer needed by `drawTextWave3D()` - - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.BeginMode3D(camera) - rl.DrawCubeV(cubePosition, cubeSize, dark) - rl.DrawCubeWires(cubePosition, 2.1, 2.1, 2.1, light) - - rl.DrawGrid(10, 2.0) - - // Use a shader to handle the depth buffer issue with transparent textures - // NOTE: more info at https://bedroomcoders.co.uk/raylib-billboards-advanced-use/ - rl.BeginShaderMode(alphaDiscard) - - // Draw the 3D text above the red cube - rl.PushMatrix() - rl.Rotatef(90.0, 1.0, 0.0, 0.0) - rl.Rotatef(90.0, 0.0, 0.0, -1.0) - - for i := int32(0); i < layers; i++ { - clr := light - if multicolor { - clr = multi[i] - } - - vec := rl.Vector3{ - X: -tbox.X / 2.0, - Y: layerDistance * float32(i), - Z: -4.5, - } - drawTextWave3D(font, text, vec, fontSize, fontSpacing, lineSpacing, true, &wcfg, time, clr) - } - - // Draw the text boundary if set - if showTextBoundary { - rl.DrawCubeWiresV(rl.Vector3{Z: -4.5 + tbox.Z/2}, tbox, dark) - } - rl.PopMatrix() - - // Don't draw the letter boundaries for the 3D text below - slb := showLetterBoundary - showLetterBoundary = false - - // Draw 3D options (use default font) - rl.PushMatrix() - rl.Rotatef(180.0, 0.0, 1.0, 0.0) - opt := fmt.Sprintf("< SIZE: %2.1f >", fontSize) - quads += int32(len(opt)) - m := measureText3D(rl.GetFontDefault(), opt, 8.0, 1.0, 0.0) - pos := rl.Vector3{ - X: -m.X / 2.0, - Y: 0.01, - Z: 2.0, - } - drawText3D(rl.GetFontDefault(), opt, pos, 8.0, 1.0, 0.0, false, rl.Blue) - pos.Z += 0.5 + m.Z - - opt = fmt.Sprintf("< SPACING: %2.1f >", fontSpacing) - quads += int32(len(opt)) - m = measureText3D(rl.GetFontDefault(), opt, 8.0, 1.0, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 8.0, 1.0, 0.0, false, rl.Blue) - pos.Z += 0.5 + m.Z - - opt = fmt.Sprintf("< LINE: %2.1f >", lineSpacing) - quads += int32(len(opt)) - m = measureText3D(rl.GetFontDefault(), opt, 8.0, 1.0, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 8.0, 1.0, 0.0, false, rl.Blue) - pos.Z += 1.0 + m.Z - - lbox := "OFF" - if slb { - lbox = "ON" - } - opt = fmt.Sprintf("< LBOX: %3s >", lbox) - quads += int32(len(opt)) - m = measureText3D(rl.GetFontDefault(), opt, 8.0, 1.0, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 8.0, 1.0, 0.0, false, rl.Red) - pos.Z += 0.5 + m.Z - - tb := "OFF" - if showTextBoundary { - tb = "ON" - } - opt = fmt.Sprintf("< TBOX: %3s >", tb) - quads += int32(len(opt)) - m = measureText3D(rl.GetFontDefault(), opt, 8.0, 1.0, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 8.0, 1.0, 0.0, false, rl.Red) - pos.Z += 0.5 + m.Z - - opt = fmt.Sprintf("< LAYER DISTANCE: %.3f >", layerDistance) - quads += int32(len(opt)) - m = measureText3D(rl.GetFontDefault(), opt, 8.0, 1.0, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 8.0, 1.0, 0.0, false, rl.DarkPurple) - rl.PopMatrix() - - // Draw 3D info text (use default font) - opt = "All the text displayed here is in 3D" - quads += 36 - m = measureText3D(rl.GetFontDefault(), opt, 10.0, 0.5, 0.0) - pos = rl.Vector3{ - X: -m.X / 2.0, - Y: 0.01, - Z: 2.0, - } - drawText3D(rl.GetFontDefault(), opt, pos, 10.0, 0.5, 0.0, false, rl.DarkBlue) - pos.Z += 1.5 + m.Z - - opt = "press [Left]/[Right] to change the font size" - quads += 44 - m = measureText3D(rl.GetFontDefault(), opt, 6.0, 0.5, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 6.0, 0.5, 0.0, false, rl.DarkBlue) - pos.Z += 0.5 + m.Z - - opt = "press [Up]/[Down] to change the font spacing" - quads += 44 - m = measureText3D(rl.GetFontDefault(), opt, 6.0, 0.5, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 6.0, 0.5, 0.0, false, rl.DarkBlue) - pos.Z += 0.5 + m.Z - - opt = "press [PgUp]/[PgDown] to change the line spacing" - quads += 48 - m = measureText3D(rl.GetFontDefault(), opt, 6.0, 0.5, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 6.0, 0.5, 0.0, false, rl.DarkBlue) - pos.Z += 0.5 + m.Z - - opt = "press [F1] to toggle the letter boundary" - quads += 39 - m = measureText3D(rl.GetFontDefault(), opt, 6.0, 0.5, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 6.0, 0.5, 0.0, false, rl.DarkBlue) - pos.Z += 0.5 + m.Z - - opt = "press [F2] to toggle the text boundary" - quads += 37 - m = measureText3D(rl.GetFontDefault(), opt, 6.0, 0.5, 0.0) - pos.X = -m.X / 2.0 - drawText3D(rl.GetFontDefault(), opt, pos, 6.0, 0.5, 0.0, false, rl.DarkBlue) - - showLetterBoundary = slb - rl.EndShaderMode() - - rl.EndMode3D() - - // Draw 2D info text & stats - msg := `Drag & drop a font file to change the font! -Type something, see what happens! - -Press [F3] to toggle the camera` - rl.DrawText(msg, 10, 35, 10, rl.Black) - - cam := "FREE" - if spin { - cam = "ORBITAL" - } - quads += int32(len(text)) * 2 * layers - tmp := fmt.Sprintf("%2d layer(s) | %s camera | %4d quads (%4d verts)", layers, cam, quads, quads*4) - width := rl.MeasureText(tmp, 10) - rl.DrawText(tmp, screenWidth-20-width, 10, 10, rl.DarkGreen) - - tmp = "[Home]/[End] to add/remove 3D text layers" - width = rl.MeasureText(tmp, 10) - rl.DrawText(tmp, screenWidth-20-width, 25, 10, rl.DarkGray) - - tmp = "[Insert]/[Delete] to increase/decrease distance between layers" - width = rl.MeasureText(tmp, 10) - rl.DrawText(tmp, screenWidth-20-width, 40, 10, rl.DarkGray) - - tmp = "click the [CUBE] for a random color" - width = rl.MeasureText(tmp, 10) - rl.DrawText(tmp, screenWidth-20-width, 55, 10, rl.DarkGray) - - tmp = "[Tab] to toggle multicolor mode" - width = rl.MeasureText(tmp, 10) - rl.DrawText(tmp, screenWidth-20-width, 70, 10, rl.DarkGray) - - rl.DrawFPS(10, 10) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadFont(font) - rl.CloseWindow() // Close window and OpenGL context - -} - -// Module Functions Definitions - -// drawTextCodepoint3D draws codepoint at specified position in 3D space -func drawTextCodepoint3D(font rl.Font, codepoint rune, position rl.Vector3, fontSize float32, backface bool, - tint rl.Color) { - // Character index position in sprite font - // NOTE: In case a codepoint is not available in the font, index returned points to '?' - index := rl.GetGlyphIndex(font, codepoint) - scale := fontSize / float32(font.BaseSize) - - // Character destination rectangle on screen - // NOTE: We consider charsPadding on drawing - glyphs := unsafe.Slice(font.Chars, font.CharsCount) - position.X += float32(glyphs[index].OffsetX-font.CharsPadding) / float32(font.BaseSize) * scale - position.Z += float32(glyphs[index].OffsetY-font.CharsPadding) / float32(font.BaseSize) * scale - - // Character source rectangle from font texture atlas - // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects - recs := unsafe.Slice(font.Recs, font.CharsCount) - srcRec := rl.Rectangle{ - X: recs[index].X - float32(font.CharsPadding), - Y: recs[index].Y - float32(font.CharsPadding), - Width: recs[index].Width + 2.0*float32(font.CharsPadding), - Height: recs[index].Height + 2.0*float32(font.CharsPadding), - } - - width := (recs[index].Width + 2.0*float32(font.CharsPadding)) / float32(font.BaseSize) * scale - height := (recs[index].Height + 2.0*float32(font.CharsPadding)) / float32(font.BaseSize) * scale - - if font.Texture.ID > 0 { - var x, y, z float32 - - // normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f) - tx := srcRec.X / float32(font.Texture.Width) - ty := srcRec.Y / float32(font.Texture.Height) - tw := (srcRec.X + srcRec.Width) / float32(font.Texture.Width) - th := (srcRec.Y + srcRec.Height) / float32(font.Texture.Height) - - if showLetterBoundary { - pos := rl.Vector3{ - X: position.X + width/2, - Y: position.Y, - Z: position.Z + height/2, - } - size := rl.Vector3{ - X: width, - Y: letterBoundarySize, - Z: height, - } - rl.DrawCubeWiresV(pos, size, letterBoundaryColor) - } - - var limit int32 = 4 - if backface { - limit = 8 - } - rl.CheckRenderBatchLimit(limit) - rl.SetTexture(font.Texture.ID) - - rl.PushMatrix() - rl.Translatef(position.X, position.Y, position.Z) - - rl.Begin(rl.Quads) - rl.Color4ub(tint.R, tint.G, tint.B, tint.A) - - // Front Face - rl.Normal3f(0.0, 1.0, 0.0) // Normal Pointing Up - rl.TexCoord2f(tx, ty) - rl.Vertex3f(x, y, z) // Top Left Of The Texture and Quad - rl.TexCoord2f(tx, th) - rl.Vertex3f(x, y, z+height) // Bottom Left Of The Texture and Quad - rl.TexCoord2f(tw, th) - rl.Vertex3f(x+width, y, z+height) // Bottom Right Of The Texture and Quad - rl.TexCoord2f(tw, ty) - rl.Vertex3f(x+width, y, z) // Top Right Of The Texture and Quad - - if backface { - // Back Face - rl.Normal3f(0.0, -1.0, 0.0) // Normal Pointing Down - rl.TexCoord2f(tx, ty) - rl.Vertex3f(x, y, z) // Top Right Of The Texture and Quad - rl.TexCoord2f(tw, ty) - rl.Vertex3f(x+width, y, z) // Top Left Of The Texture and Quad - rl.TexCoord2f(tw, th) - rl.Vertex3f(x+width, y, z+height) // Bottom Left Of The Texture and Quad - rl.TexCoord2f(tx, th) - rl.Vertex3f(x, y, z+height) // Bottom Right Of The Texture and Quad - } - rl.End() - rl.PopMatrix() - rl.SetTexture(0) - } -} - -// drawText3D draws a 2D text in 3D space -func drawText3D(font rl.Font, text string, position rl.Vector3, fontSize, fontSpacing, - lineSpacing float32, backface bool, tint rl.Color) { - length := int32(len(text)) // Total length in bytes of the text, - // scanned by codepoints in loop - - // TextOffsetY : Offset between lines (on line break '\n') - // TextOffsetX : Offset X to next character to draw - var textOffsetY, textOffsetX float32 - - scale := fontSize / float32(font.BaseSize) - for i := int32(0); i < length; { - - // Get next codepoint from byte string and glyph index in font - codepoint, codepointByteCount := getCodepoint(text, i) - index := rl.GetGlyphIndex(font, codepoint) - - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all the bad bytes using the '?' symbol moving one byte - if codepoint == 0x3f { - codepointByteCount = 1 - } - - if codepoint == 0 || codepoint == '\n' { - // NOTE: Fixed line spacing of 1.5 line-height - // TODO: Support custom line spacing defined by user - textOffsetY += scale + lineSpacing/float32(font.BaseSize)*scale - textOffsetX = 0.0 - } else { - if (codepoint != ' ') && (codepoint != '\t') { - vec := rl.Vector3{ - X: position.X + textOffsetX, - Y: position.Y, - Z: position.Z + textOffsetY, - } - drawTextCodepoint3D(font, codepoint, vec, fontSize, backface, tint) - } - - textOffsetX += getTextWidth(font, index, fontSpacing, scale) - } - - i += codepointByteCount // Move text bytes counter to next codepoint - } -} - -// measureText3D measures a text in 3D. For some reason `MeasureTextEx()` -// just doesn't seem to work, so I had to use this instead. -func measureText3D(font rl.Font, text string, fontSize, fontSpacing, lineSpacing float32) rl.Vector3 { - length := int32(len(text)) - var tempLen, lenCounter int32 // Used to count longer text line num chars - - var ( - tempTextWidth float32 // Used to count longer text line width - scale = fontSize / float32(font.BaseSize) - textHeight = scale - textWidth float32 - ) - - var ( - letter rune // Current character - index int32 // Index position in sprite font - ) - - for i := int32(0); i < length; i++ { - lenCounter++ - - var next int32 - letter, next = getCodepoint(text, i) - index = rl.GetGlyphIndex(font, letter) - - // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all the bad bytes using the '?' symbol so to not skip any we set next = 1 - if letter == 0x3f { - next = 1 - } - i += next - 1 - - if letter != 0 && letter != '\n' { - textWidth += getTextWidth(font, index, fontSpacing, scale) - } else { - if tempTextWidth < textWidth { - tempTextWidth = textWidth - } - lenCounter = 0 - textWidth = 0.0 - textHeight += scale + lineSpacing/float32(font.BaseSize)*scale - } - - if tempLen < lenCounter { - tempLen = lenCounter - } - } - - if tempTextWidth < textWidth { - tempTextWidth = textWidth - } - - // Adds chars spacing to measure - vec := rl.Vector3{ - X: tempTextWidth + float32(tempLen-1)*fontSpacing/float32(font.BaseSize)*scale, - Y: 0.25, - Z: textHeight, - } - return vec -} - -// drawTextWave3D draws a 2D text in 3D space and wave the parts that start with `~~` and end with `~~`. -// This is a modified version of the original code by @Nighten found here https://github.com/NightenDushi/Raylib_DrawTextStyle -func drawTextWave3D(font rl.Font, text string, position rl.Vector3, fontSize, fontSpacing, - lineSpacing float32, backface bool, config *WaveTextConfig, time float32, tint rl.Color) { - length := int32(len(text)) // Total length in bytes of the text, scanned by codepoints in loop - - // TextOffsetY : Offset between lines (on line break '\n') - // TextOffsetX : Offset X to next character to draw - var textOffsetY, textOffsetX float32 - var wave bool - - scale := fontSize / float32(font.BaseSize) - - for i, k := int32(0), int32(0); i < length; k++ { - // Get next codepoint from byte string and glyph index in font - codepoint, codepointByteCount := getCodepoint(text, i) - index := rl.GetGlyphIndex(font, codepoint) - - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all the bad bytes using the '?' symbol moving one byte - if codepoint == 0x3f { - codepointByteCount = 1 - } - - if codepoint == 0 || codepoint == '\n' { - // NOTE: Fixed line spacing of 1.5 line-height - // TODO: Support custom line spacing defined by user - textOffsetY += scale + lineSpacing/float32(font.BaseSize)*scale - textOffsetX = 0.0 - k = 0 - } else if codepoint == '~' { - var r rune - r, codepointByteCount = getCodepoint(text, i+1) - if r == '~' { - codepointByteCount += 1 - wave = !wave - } - } else { - if (codepoint != ' ') && (codepoint != '\t') { - pos := position - if wave { // Apply the wave effect - kk := float32(k) - pos.X += sin(time*config.waveSpeed.X-kk*config.waveOffset.X) * config.waveRange.X - pos.Y += sin(time*config.waveSpeed.Y-kk*config.waveOffset.Y) * config.waveRange.Y - pos.Z += sin(time*config.waveSpeed.Z-kk*config.waveOffset.Z) * config.waveRange.Z - } - - vec := rl.Vector3{ - X: pos.X + textOffsetX, - Y: pos.Y, - Z: pos.Z + textOffsetY, - } - drawTextCodepoint3D(font, codepoint, vec, fontSize, backface, tint) - } - - textOffsetX += getTextWidth(font, index, fontSpacing, scale) - } - - i += codepointByteCount // Move text bytes counter to next codepoint - } -} - -// measureTextWave3D measures a text in 3D ignoring the `~~` chars. -func measureTextWave3D(font rl.Font, text string, fontSize, fontSpacing, lineSpacing float32) rl.Vector3 { - length := int32(len(text)) - var tempLen, lenCounter int32 // Used to count longer text line num chars - - var ( - tempTextWidth float32 = 0.0 // Used to count longer text line width - scale = fontSize / float32(font.BaseSize) - textHeight = scale - textWidth float32 = 0.0 - ) - - var letter, index int32 // Current character and Index position in sprite font - - for i := int32(0); i < length; i++ { - lenCounter++ - var next int32 - - letter, next = getCodepoint(text, i) - index = rl.GetGlyphIndex(font, letter) - - // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all the bad bytes using the '?' symbol so to not skip any we set next = 1 - if letter == 0x3f { - next = 1 - } - i += next - 1 - - if letter != 0 && letter != '\n' { - r, _ := getCodepoint(text, i+1) - if letter == '~' && r == '~' { - i++ - } else { - textWidth += getTextWidth(font, index, fontSpacing, scale) - } - } else { - if tempTextWidth < textWidth { - tempTextWidth = textWidth - } - lenCounter = 0 - textWidth = 0.0 - textHeight += scale + lineSpacing/float32(font.BaseSize)*scale - } - - if tempLen < lenCounter { - tempLen = lenCounter - } - } - - if tempTextWidth < textWidth { - tempTextWidth = textWidth - } - - vec := rl.Vector3{ - X: tempTextWidth + float32(tempLen-1)*fontSpacing/float32(font.BaseSize)*scale, // Adds chars spacing to measure - Y: 0.25, - Z: textHeight, - } - - return vec -} - -// generateRandomColor generates a nice color with a random hue -func generateRandomColor(s, v float32) rl.Color { - const Phi = float64(0.618033988749895) // Golden ratio conjugate - h := float64(rl.GetRandomValue(0, 360)) - h = math.Mod(h+h*Phi, 360.0) - return rl.ColorFromHSV(float32(h), s, v) -} - -// getCodepoint returns the rune starting at index, plus the length of that rune in bytes -func getCodepoint(s string, index int32) (rune, int32) { - if index == int32(len(s)) { - return 0, 0 - } - r := []rune(s[index:]) - return r[0], int32(utf8.RuneLen(r[0])) -} - -// sin is just a convenience function to avoid a bunch of type conversions -func sin(value float32) float32 { - return float32(math.Sin(float64(value))) -} - -func getTextWidth(font rl.Font, index int32, spacing, scale float32) float32 { - glyphs := unsafe.Slice(font.Chars, font.CharsCount) - if glyphs[index].AdvanceX == 0 { - recs := unsafe.Slice(font.Recs, font.CharsCount) - return (recs[index].Width + spacing) / float32(font.BaseSize) * scale - } else { - return (float32(glyphs[index].AdvanceX) + spacing) / float32(font.BaseSize) * scale - } -} diff --git a/examples/text/font_filters/KAISG.ttf b/examples/text/font_filters/KAISG.ttf deleted file mode 100644 index 04478b2..0000000 Binary files a/examples/text/font_filters/KAISG.ttf and /dev/null differ diff --git a/examples/text/font_filters/main.go b/examples/text/font_filters/main.go deleted file mode 100644 index 7c181de..0000000 --- a/examples/text/font_filters/main.go +++ /dev/null @@ -1,125 +0,0 @@ -/******************************************************************************************* -* -* raylib [text] example - Font filters -* -* NOTE: After font loading, font texture atlas filter could be configured for a softer -* display of the font when scaling it to different sizes, that way, it's not required -* to generate multiple fonts at multiple sizes (as long as the scaling is not very different) -* -* Example originally created with raylib 1.3, last time updated with raylib 4.2 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "path/filepath" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - font filters") - msg := "Loaded Font" - - // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) - - // TTF Font loading with custom generation parameters - font := rl.LoadFontEx("KAISG.ttf", 96, nil, 0) - - // Generate mipmap levels to use trilinear filtering - // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR - rl.GenTextureMipmaps(&font.Texture) - - fontSize := float32(font.BaseSize) - fontPosition := rl.Vector2{X: 40.0, Y: screenHeight/2.0 - 80.0} - textSize := rl.Vector2{} - - // Setup texture scaling filter - rl.SetTextureFilter(font.Texture, rl.FilterPoint) - currentFontFilter := 0 // TEXTURE_FILTER_POINT - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - for !rl.WindowShouldClose() { // Detect window close button or ESC key - fontSize += rl.GetMouseWheelMove() * 4.0 - - // Choose font texture filter method - if rl.IsKeyPressed(rl.KeyOne) { - rl.SetTextureFilter(font.Texture, rl.FilterPoint) - currentFontFilter = 0 - } else if rl.IsKeyPressed(rl.KeyTwo) { - rl.SetTextureFilter(font.Texture, rl.FilterBilinear) - currentFontFilter = 1 - } else if rl.IsKeyPressed(rl.KeyThree) { - // NOTE: Trilinear filter won't be noticed on 2D drawing - rl.SetTextureFilter(font.Texture, rl.FilterTrilinear) - currentFontFilter = 2 - } - - textSize = rl.MeasureTextEx(font, msg, fontSize, 0) - - if rl.IsKeyDown(rl.KeyLeft) { - fontPosition.X -= 10 - } else if rl.IsKeyDown(rl.KeyRight) { - fontPosition.X += 10 - } - - // Load a dropped TTF file dynamically (at current fontSize) - if rl.IsFileDropped() { - droppedFiles := rl.LoadDroppedFiles() - - // NOTE: We only support first ttf file dropped - if filepath.Ext(droppedFiles[0]) == ".ttf" { - rl.UnloadFont(font) - font = rl.LoadFontEx(droppedFiles[0], int32(fontSize), nil, 0) - } - - rl.UnloadDroppedFiles() // Unload file paths from memory - } - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("Use mouse wheel to change font size", 20, 20, 10, rl.Gray) - rl.DrawText("Use KEY_RIGHT and KEY_LEFT to move text", 20, 40, 10, rl.Gray) - rl.DrawText("Use 1, 2, 3 to change texture filter", 20, 60, 10, rl.Gray) - rl.DrawText("Drop a new TTF font for dynamic loading", 20, 80, 10, rl.DarkGray) - rl.DrawTextEx(font, msg, fontPosition, fontSize, 0, rl.Black) - - // TODO: It seems texSize measurement is not accurate due to chars offsets... - //rl.DrawRectangleLines(fontPosition.X, fontPosition.Y, textSize.X, textSize.Y, rl.Red); - - rl.DrawRectangle(0, screenHeight-80, screenWidth, 80, rl.LightGray) - text := fmt.Sprintf("Font size: %02.02f", fontSize) - rl.DrawText(text, 20, screenHeight-50, 10, rl.DarkGray) - text = fmt.Sprintf("Text size: [%02.02f, %02.02f]", textSize.X, textSize.Y) - rl.DrawText(text, 20, screenHeight-30, 10, rl.DarkGray) - rl.DrawText("CURRENT TEXTURE FILTER:", 250, 400, 20, rl.Gray) - - switch currentFontFilter { - case 0: - rl.DrawText("POINT", 570, 400, 20, rl.Black) - case 1: - rl.DrawText("BILINEAR", 570, 400, 20, rl.Black) - case 2: - rl.DrawText("TRILINEAR", 570, 400, 20, rl.Black) - } - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadFont(font) // Font unloading - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/text/font_loading/main.go b/examples/text/font_loading/main.go deleted file mode 100644 index db1b49d..0000000 --- a/examples/text/font_loading/main.go +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************************* -* -* raylib [text] example - Font loading -* -* NOTE: raylib can load fonts from multiple input file formats: -* -* - TTF/OTF > Sprite font atlas is generated on loading, user can configure -* some of the generation parameters (size, characters to include) -* - BMFonts > Angel code font fileformat, sprite font image must be provided -* together with the .fnt file, font generation cna not be configured -* - XNA Spritefont > Sprite font image, following XNA Spritefont conventions, -* Characters in image must follow some spacing and order rules -* -* Example originally created with raylib 1.4, last time updated with raylib 3.0 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2016-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - font loading") - - // Define characters to draw - // NOTE: raylib supports UTF-8 encoding, following list is actually codified as UTF8 internally - msg := "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI\nJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmn\nopqrstuvwxyz" + - "{|}~¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓ\nÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷\nøùúûüýþÿ" - - // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) - - // BMFont (AngelCode) : Font data and image atlas have been generated using external program - fontBm := rl.LoadFont("pixantiqua.fnt") - - // TTF font : Font data and atlas are generated directly from TTF - // NOTE: We define a font base size of 32 pixels tall and up-to 250 characters - fontTtf := rl.LoadFontEx("pixantiqua.ttf", 32, nil, 250) - - rl.SetTextLineSpacing(16) // Set line spacing for multiline text (when line breaks are included '\n') - - useTtf := false - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - useTtf = rl.IsKeyDown(rl.KeySpace) - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("Hold SPACE to use TTF generated font", 20, 20, 20, rl.LightGray) - - if !useTtf { - rl.DrawTextEx(fontBm, msg, rl.Vector2{X: 20.0, Y: 100.0}, float32(fontBm.BaseSize), 2, rl.Maroon) - rl.DrawText("Using BMFont (Angelcode) imported", 20, int32(rl.GetScreenHeight())-30, 20, rl.Gray) - } else { - rl.DrawTextEx(fontTtf, msg, rl.Vector2{X: 20.0, Y: 100.0}, float32(fontTtf.BaseSize), 2, rl.Lime) - rl.DrawText("Using TTF font generated", 20, int32(rl.GetScreenHeight())-30, 20, rl.Gray) - } - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadFont(fontBm) // AngelCode Font unloading - rl.UnloadFont(fontTtf) // TTF Font unloading - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/text/font_loading/pixantiqua.fnt b/examples/text/font_loading/pixantiqua.fnt deleted file mode 100644 index fd9f9db..0000000 --- a/examples/text/font_loading/pixantiqua.fnt +++ /dev/null @@ -1,188 +0,0 @@ -info face="PixAntiqua" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=2,2,2,2 spacing=2,2 outline=0 -common lineHeight=32 base=27 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 -page id=0 file="pixantiqua.png" -chars count=184 -char id=32 x=9 y=304 width=7 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=33 x=391 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=34 x=240 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=35 x=468 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=36 x=152 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=37 x=176 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=38 x=303 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=39 x=495 y=266 width=8 height=36 xoffset=-3 yoffset=-2 xadvance=5 page=0 chnl=15 -char id=40 x=256 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=199 x=432 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=200 x=126 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=201 x=147 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=202 x=288 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=203 x=189 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=204 x=468 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=205 x=486 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=206 x=0 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=207 x=72 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=208 x=329 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=209 x=277 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=210 x=182 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=211 x=26 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=41 x=272 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=42 x=288 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=43 x=414 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=44 x=378 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=45 x=414 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=46 x=443 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=47 x=392 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=48 x=485 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=49 x=450 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=50 x=21 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=51 x=42 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=59 x=456 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=60 x=168 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=61 x=309 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=62 x=336 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=63 x=315 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=64 x=364 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=65 x=390 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=66 x=120 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=67 x=144 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=68 x=168 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=69 x=294 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=52 x=488 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=53 x=63 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=54 x=24 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=55 x=48 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=56 x=72 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=57 x=96 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=58 x=404 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=70 x=252 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=71 x=192 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=72 x=78 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=78 x=78 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=79 x=355 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=80 x=264 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=81 x=381 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=82 x=288 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=83 x=312 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=91 x=144 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=92 x=108 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=93 x=304 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=94 x=34 y=0 width=32 height=36 xoffset=-3 yoffset=-2 xadvance=29 page=0 chnl=15 -char id=95 x=231 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=96 x=442 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=97 x=408 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=98 x=432 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=99 x=210 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=84 x=336 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=85 x=360 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=86 x=0 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=87 x=68 y=0 width=30 height=36 xoffset=-3 yoffset=-2 xadvance=27 page=0 chnl=15 -char id=88 x=26 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=89 x=384 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=90 x=84 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=100 x=456 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=101 x=480 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=102 x=54 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=103 x=0 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=104 x=24 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=105 x=469 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=106 x=18 y=266 width=16 height=36 xoffset=-8 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=107 x=48 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=108 x=417 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=109 x=161 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15 -char id=110 x=72 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=111 x=96 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=117 x=192 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=118 x=216 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=119 x=248 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15 -char id=120 x=240 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=121 x=264 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=122 x=288 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=123 x=432 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=124 x=365 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=125 x=378 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=126 x=393 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=127 x=132 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15 -char id=160 x=0 y=304 width=7 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=161 x=352 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=162 x=351 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=163 x=336 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=165 x=360 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=167 x=384 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=169 x=433 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=170 x=224 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=171 x=105 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=172 x=0 y=0 width=32 height=36 xoffset=-3 yoffset=-2 xadvance=29 page=0 chnl=15 -char id=173 x=494 y=38 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=174 x=52 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=175 x=52 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=176 x=126 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=177 x=435 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=178 x=320 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=179 x=336 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=181 x=459 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=112 x=120 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=113 x=144 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=114 x=396 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=115 x=168 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=116 x=36 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=182 x=408 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=183 x=498 y=190 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=185 x=192 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=186 x=208 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=187 x=477 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=191 x=456 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=192 x=407 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=193 x=234 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=194 x=416 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=195 x=156 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=196 x=130 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=197 x=104 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=198 x=190 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15 -char id=212 x=0 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=213 x=338 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=214 x=312 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=215 x=357 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=216 x=286 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=217 x=456 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=218 x=480 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=219 x=0 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=220 x=24 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=221 x=48 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=222 x=260 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=223 x=72 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=224 x=96 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=225 x=120 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=226 x=144 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=227 x=168 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=228 x=192 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=229 x=216 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=230 x=219 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15 -char id=231 x=372 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=73 x=90 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=74 x=216 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=75 x=240 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=76 x=273 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=77 x=100 y=0 width=30 height=36 xoffset=-3 yoffset=-2 xadvance=27 page=0 chnl=15 -char id=232 x=312 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=233 x=240 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=234 x=264 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=235 x=104 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=236 x=430 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=237 x=482 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=238 x=160 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=239 x=176 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=240 x=128 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=241 x=200 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=242 x=224 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=243 x=248 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=244 x=272 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=245 x=296 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=246 x=320 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=247 x=330 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=248 x=208 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15 -char id=249 x=344 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=250 x=368 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=251 x=416 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=252 x=440 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=253 x=464 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 -char id=254 x=0 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15 -char id=255 x=0 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15 diff --git a/examples/text/font_loading/pixantiqua.png b/examples/text/font_loading/pixantiqua.png deleted file mode 100644 index 2aa2870..0000000 Binary files a/examples/text/font_loading/pixantiqua.png and /dev/null differ diff --git a/examples/text/font_loading/pixantiqua.ttf b/examples/text/font_loading/pixantiqua.ttf deleted file mode 100644 index e012875..0000000 Binary files a/examples/text/font_loading/pixantiqua.ttf and /dev/null differ diff --git a/examples/text/font_sdf/AnonymousPro-Bold.ttf b/examples/text/font_sdf/AnonymousPro-Bold.ttf deleted file mode 100644 index f14c18c..0000000 Binary files a/examples/text/font_sdf/AnonymousPro-Bold.ttf and /dev/null differ diff --git a/examples/text/font_sdf/OFL.txt b/examples/text/font_sdf/OFL.txt deleted file mode 100644 index 45b11f5..0000000 --- a/examples/text/font_sdf/OFL.txt +++ /dev/null @@ -1,94 +0,0 @@ -Copyright (c) 2009, Mark Simonson (http://www.ms-studio.com, mark@marksimonson.com), -with Reserved Font Name Anonymous Pro. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -https://openfontlicense.org - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/examples/text/font_sdf/main.go b/examples/text/font_sdf/main.go deleted file mode 100644 index 915048d..0000000 --- a/examples/text/font_sdf/main.go +++ /dev/null @@ -1,106 +0,0 @@ -package main - -import ( - _ "embed" - "fmt" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -//go:embed AnonymousPro-Bold.ttf -var fileData []byte - -func main() { - // Initialization - const screenWidth, screenHeight = 800, 450 - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - SDF fonts") - defer rl.CloseWindow() // Close window and OpenGL context - - // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) - - const msg = "Signed Distance Fields" - - // Default font generation from TTF font - fontDefault := rl.Font{BaseSize: 16, CharsCount: 95} - defer rl.UnloadFont(fontDefault) // Default font unloading - - // Loading font data from memory data - // Parameters > font size: 16, no glyphs array provided (nil), glyphs count: 95 (autogenerate chars array) - glyphs := rl.LoadFontData(fileData, 16, nil, 95, rl.FontDefault) - fontDefault.Chars = &glyphs[0] - - // Parameters > font size: 16, glyphs padding in image: 4 px, pack method: 0 (default) - atlas := rl.GenImageFontAtlas(unsafe.Slice(fontDefault.Chars, fontDefault.CharsCount), unsafe.Slice(&fontDefault.Recs, fontDefault.CharsCount), 16, 4, 0) - fontDefault.Texture = rl.LoadTextureFromImage(&atlas) - rl.UnloadImage(&atlas) - - // SDF font generation from TTF font - fontSDF := rl.Font{BaseSize: 16, CharsCount: 95} - defer rl.UnloadFont(fontSDF) // SDF font unloading - - // Parameters > font size: 16, no glyphs array provided (nil), glyphs count: 0 (defaults to 95) - glyphsSDF := rl.LoadFontData(fileData, 16, nil, 0, rl.FontSdf) - fontSDF.Chars = &glyphsSDF[0] - // Parameters > font size: 16, glyphs padding in image: 0 px, pack method: 1 (Skyline algorithm) - atlas = rl.GenImageFontAtlas(unsafe.Slice(fontSDF.Chars, fontSDF.CharsCount), unsafe.Slice(&fontSDF.Recs, fontSDF.CharsCount), 16, 0, 1) - fontSDF.Texture = rl.LoadTextureFromImage(&atlas) - rl.UnloadImage(&atlas) - - // Load SDF required shader (we use default vertex shader) - shader := rl.LoadShader("", "sdf.fs") - defer rl.UnloadShader(shader) // Unload SDF shader - rl.SetTextureFilter(fontSDF.Texture, rl.FilterBilinear) // Required for SDF font - - fontPosition := rl.NewVector2(40, screenHeight/2.0-50) - textSize := rl.Vector2Zero() - fontSize := float32(16) - currentFont := 0 // 0 - fontDefault, 1 - fontSDF - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - fontSize += rl.GetMouseWheelMove() * 8.0 - - if fontSize < 6 { - fontSize = 6 - } - - if rl.IsKeyDown(rl.KeySpace) { - currentFont = 1 - textSize = rl.MeasureTextEx(fontSDF, msg, fontSize, 0) - } else { - currentFont = 0 - textSize = rl.MeasureTextEx(fontDefault, msg, fontSize, 0) - } - - fontPosition.X = float32(rl.GetScreenWidth()/2) - textSize.X/2 - fontPosition.Y = float32(rl.GetScreenHeight()/2) - textSize.Y/2 + 80 - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - if currentFont == 1 { - // NOTE: SDF fonts require a custom SDf shader to compute fragment color - rl.BeginShaderMode(shader) // Activate SDF font shader - rl.DrawTextEx(fontSDF, msg, fontPosition, fontSize, 0, rl.Black) - rl.EndShaderMode() // Activate our default shader for next drawings - rl.DrawTexture(fontSDF.Texture, 10, 10, rl.Black) - rl.DrawText("SDF!", 320, 20, 80, rl.Red) - } else { - rl.DrawTextEx(fontDefault, msg, fontPosition, fontSize, 0, rl.Black) - rl.DrawTexture(fontDefault.Texture, 10, 10, rl.Black) - rl.DrawText("default font", 315, 40, 30, rl.Gray) - } - - rl.DrawText("FONT SIZE: 16.0", int32(rl.GetScreenWidth()-240), 20, 20, rl.DarkGray) - rl.DrawText(fmt.Sprintf("RENDER SIZE: %02.02f", fontSize), int32(rl.GetScreenWidth()-240), 50, 20, rl.DarkGray) - rl.DrawText("Use MOUSE WHEEL to SCALE TEXT!", int32(rl.GetScreenWidth()-240), 90, 10, rl.DarkGray) - - rl.DrawText("HOLD SPACE to USE SDF FONT VERSION!", 340, int32(rl.GetScreenHeight()-30), 20, rl.Maroon) - - rl.EndDrawing() - - } -} diff --git a/examples/text/font_sdf/sdf.fs b/examples/text/font_sdf/sdf.fs deleted file mode 100644 index 545f450..0000000 --- a/examples/text/font_sdf/sdf.fs +++ /dev/null @@ -1,26 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -// NOTE: Add here your custom variables - -void main() -{ - // Texel color fetching from texture sampler - // NOTE: Calculate alpha using signed distance field (SDF) - float distanceFromOutline = texture(texture0, fragTexCoord).a - 0.5; - float distanceChangePerFragment = length(vec2(dFdx(distanceFromOutline), dFdy(distanceFromOutline))); - float alpha = smoothstep(-distanceChangePerFragment, distanceChangePerFragment, distanceFromOutline); - - // Calculate final fragment color - finalColor = vec4(fragColor.rgb, fragColor.a*alpha); -} diff --git a/examples/text/format_text/main.go b/examples/text/format_text/main.go index 4320b5c..d5962c0 100644 --- a/examples/text/format_text/main.go +++ b/examples/text/format_text/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/text/input_box/main.go b/examples/text/input_box/main.go deleted file mode 100644 index b1e3e18..0000000 --- a/examples/text/input_box/main.go +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************************* - * - * raylib [text] example - Input Box - * - * Example originally created with raylib 1.7, last time updated with raylib 3.5 - * - * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, - * BSD-like license that allows static linking with closed source software - * - * Copyright (c) 2017-2024 Ramon Santamaria (@raysan5) - * - ********************************************************************************************/ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 - maxInputChars = 9 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - input box") - - var name [maxInputChars]rune - var letterCount, framesCounter int32 - var mouseOnText bool - - textBox := rl.Rectangle{X: screenWidth/2.0 - 100, Y: 180, Width: 225, Height: 50} - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - mouseOnText = rl.CheckCollisionPointRec(rl.GetMousePosition(), textBox) - - if mouseOnText { - // Set the window's cursor to the I-Beam - rl.SetMouseCursor(rl.MouseCursorIBeam) - - // Get char pressed (unicode character) on the queue - key := rl.GetCharPressed() - - // Check if more characters have been pressed on the same frame - for key > 0 { - // NOTE: Only allow keys in range [32..125] - if (key >= 32) && (key <= 125) && (letterCount < maxInputChars) { - name[letterCount] = key - letterCount++ - } - - key = rl.GetCharPressed() // Check next character in the queue - } - - if rl.IsKeyPressed(rl.KeyBackspace) { - letterCount-- - if letterCount < 0 { - letterCount = 0 - } - name[letterCount] = 0 - } - } else { - rl.SetMouseCursor(rl.MouseCursorDefault) - } - - if mouseOnText { - framesCounter++ - } else { - framesCounter = 0 - } - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("PLACE MOUSE OVER INPUT BOX!", 240, 140, 20, rl.Gray) - - rl.DrawRectangleRec(textBox, rl.LightGray) - col := rl.DarkGray - if mouseOnText { - col = rl.Red - } - rl.DrawRectangleLines(int32(textBox.X), int32(textBox.Y), int32(textBox.Width), int32(textBox.Height), col) - - rl.DrawText(getString(name), int32(textBox.X)+5, int32(textBox.Y)+8, 40, rl.Maroon) - text := fmt.Sprintf("INPUT CHARS: %d/%d", letterCount, maxInputChars) - rl.DrawText(text, 315, 250, 20, rl.DarkGray) - - if mouseOnText { - if letterCount < maxInputChars { - // Draw blinking underscore char - if ((framesCounter / 20) % 2) == 0 { - x := int32(textBox.X) + 8 + rl.MeasureText(getString(name), 40) - rl.DrawText("_", x, int32(textBox.Y)+12, 40, rl.Maroon) - } - } else { - rl.DrawText("Press BACKSPACE to delete chars...", 230, 300, 20, rl.Gray) - } - } - - rl.EndDrawing() - } - - // De-Initialization - rl.CloseWindow() // Close window and OpenGL context -} - -func getString(r [maxInputChars]rune) string { - var s string - for _, char := range r { - if char == 0 { - return s - } - s += string(char) - } - return s -} diff --git a/examples/text/raylib_fonts/main.go b/examples/text/raylib_fonts/main.go index c5257ef..fcecdac 100644 --- a/examples/text/raylib_fonts/main.go +++ b/examples/text/raylib_fonts/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const maxFonts = 8 diff --git a/examples/text/rectangle_bounds/main.go b/examples/text/rectangle_bounds/main.go deleted file mode 100644 index b0d4172..0000000 --- a/examples/text/rectangle_bounds/main.go +++ /dev/null @@ -1,308 +0,0 @@ -/******************************************************************************************* -* -* raylib [text] example - Rectangle bounds -* -* Example originally created with raylib 2.5, last time updated with raylib 4.0 -* -* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2018-2024 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "unicode/utf8" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 - MeasureState = 0 - DrawState = 1 -) - -func main() { - - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - draw text inside a rectangle") - - text := `Text cannot escape this container ...word wrap also works when active so here's a long text for testing. - -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nec ullamcorper sit amet risus nullam eget felis eget.` - - resizing, wordWrap := false, true - - container := rl.Rectangle{ - X: 25.0, - Y: 25.0, - Width: screenWidth - 50.0, - Height: screenHeight - 250.0, - } - resizer := rl.Rectangle{ - X: container.X + container.Width - 17, - Y: container.Y + container.Height - 17, - Width: 14, - Height: 14, - } - - // Minimum width and height for the container rectangle - minWidth := float32(60.0) - minHeight := float32(60.0) - maxWidth := screenWidth - float32(50.0) - maxHeight := screenHeight - float32(160.0) - - lastMouse := rl.Vector2{} // Stores last mouse coordinates - borderColor := rl.Maroon // Container border color - font := rl.GetFontDefault() // Get default system font - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - if rl.IsKeyPressed(rl.KeySpace) { - wordWrap = !wordWrap - } - - mouse := rl.GetMousePosition() - - // Check if the mouse is inside the container and toggle border color - if rl.CheckCollisionPointRec(mouse, container) { - borderColor = rl.Fade(rl.Maroon, 0.4) - } else if !resizing { - borderColor = rl.Maroon - } - - // Container resizing logic - if resizing { - if rl.IsMouseButtonReleased(rl.MouseButtonLeft) { - resizing = false - } - - width := container.Width + (mouse.X - lastMouse.X) - height := container.Height + (mouse.Y - lastMouse.Y) - - container.Width = rl.Clamp(width, minWidth, maxWidth) - container.Height = rl.Clamp(height, minHeight, maxHeight) - } else { - // Check if we're resizing - if rl.IsMouseButtonDown(rl.MouseButtonLeft) && rl.CheckCollisionPointRec(mouse, resizer) { - resizing = true - } - } - - // Move resizer rectangle properly - resizer.X = container.X + container.Width - 17 - resizer.Y = container.Y + container.Height - 17 - - lastMouse = mouse // Update mouse - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawRectangleLinesEx(container, 3, borderColor) // Draw container border - - // Draw text in container (add some padding) - DrawTextBoxed(font, text, rl.Rectangle{ - X: container.X + 4, - Y: container.Y + 4, - Width: container.Width - 4, - Height: container.Height - 4, - }, 20.0, 2.0, wordWrap, rl.Gray) - - rl.DrawRectangleRec(resizer, borderColor) // Draw the resize box - - // Draw bottom info - rl.DrawRectangle(0, screenHeight-54, screenWidth, 54, rl.Gray) - rl.DrawRectangleRec(rl.Rectangle{ - X: 382.0, - Y: screenHeight - 34.0, - Width: 12.0, - Height: 12.0, - }, rl.Maroon) - - rl.DrawText("Word Wrap: ", 313, screenHeight-115, 20, rl.Black) - if wordWrap { - rl.DrawText("ON", 447, screenHeight-115, 20, rl.Red) - } else { - rl.DrawText("OFF", 447, screenHeight-115, 20, rl.Black) - } - - rl.DrawText("Press [SPACE] to toggle word wrap", 218, screenHeight-86, 20, rl.Gray) - rl.DrawText("Click hold & drag the to resize the container", 155, screenHeight-38, 20, rl.RayWhite) - - rl.EndDrawing() - } - - // De-Initialization - rl.CloseWindow() // Close window and OpenGL context -} - -//-------------------------------------------------------------------------------------- -// Module functions definition -//-------------------------------------------------------------------------------------- - -// DrawTextBoxed draws text using font inside rectangle limits -func DrawTextBoxed(font rl.Font, text string, rec rl.Rectangle, fontSize, spacing float32, wordWrap bool, tint rl.Color) { - DrawTextBoxedSelectable(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, rl.White, rl.White) -} - -// DrawTextBoxedSelectable draws text using font inside rectangle limits with support for text selection -func DrawTextBoxedSelectable(font rl.Font, text string, rec rl.Rectangle, fontSize, spacing float32, - wordWrap bool, tint rl.Color, selectStart, selectLength int32, selectTint, selectBackTint rl.Color) { - - length := int32(len(text)) // Total length in bytes of the text, scanned by codepoints in loop - - // TextOffsetY : Offset between lines (on line break '\n') - // TextOffsetX : Offset X to next character to draw - var textOffsetY, textOffsetX float32 - - scaleFactor := fontSize / float32(font.BaseSize) // Character rectangle scaling factor - - // Word/character wrapping mechanism variables - state := DrawState - if wordWrap { - state = MeasureState - } - - // StartLine : Index where to begin drawing (where a line begins) - // EndLine : Index where to stop drawing (where a line ends) - // LastK : Holds last value of the character position - var startLine, endLine, lastk int32 = -1, -1, -1 - - for i, k := int32(0), int32(0); i < length; i, k = i+1, k+1 { - // Get next codepoint from byte string and glyph index in font - codepoint, width := utf8.DecodeRuneInString(text[i:]) - codepointByteCount := int32(width) - index := rl.GetGlyphIndex(font, codepoint) - - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all the bad bytes using the '?' symbol moving one byte - if codepoint == 0x3f { - codepointByteCount = 1 - } - i += codepointByteCount - 1 - - var glyphWidth float32 - if codepoint != '\n' { - chars := unsafe.Slice(font.Chars, font.CharsCount) - if chars[index].AdvanceX == 0 { - glyphWidth = unsafe.Slice(font.Recs, font.CharsCount)[index].Width * scaleFactor - } else { - glyphWidth = float32(chars[index].AdvanceX) * scaleFactor - } - - if i+1 < length { - glyphWidth = glyphWidth + spacing - } - } - - // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside the rec container - // We store this info in startLine and endLine, then we change states, draw the text between those two variables - // and change states again and again recursively until the end of the text (or until we get outside the container). - // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately - // and begin drawing on the next line before we can get outside the container. - if state == MeasureState { - // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more - // Ref: http://jkorpela.fi/chars/spaces.html - if (codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n') { - endLine = i - } - - if (textOffsetX + glyphWidth) > rec.Width { - if endLine < 1 { - endLine = i - } - - if i == endLine { - endLine -= codepointByteCount - } - if (startLine + codepointByteCount) == endLine { - endLine = i - codepointByteCount - } - - state = 1 - state // Toggle state between MeasureState and DrawState - } else if (i + 1) == length { - endLine = i - state = 1 - state // Toggle state between MeasureState and DrawState - } else if codepoint == '\n' { - state = 1 - state // Toggle state between MeasureState and DrawState - } - - if state == DrawState { - textOffsetX = 0 - i = startLine - glyphWidth = 0 - - // Save character position when we switch states - tmp := lastk - lastk = k - 1 - k = tmp - } - } else { - if codepoint == '\n' { - if !wordWrap { - textOffsetY += float32(font.BaseSize+font.BaseSize/2) * scaleFactor - textOffsetX = 0 - } - } else { - if !wordWrap && ((textOffsetX + glyphWidth) > rec.Width) { - textOffsetY += float32(font.BaseSize+font.BaseSize/2) * scaleFactor - textOffsetX = 0 - } - - // When text overflows rectangle height limit, just stop drawing - if (textOffsetY + float32(font.BaseSize)*scaleFactor) > rec.Height { - break - } - - // Draw selection background - isGlyphSelected := false - if (selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)) { - rl.DrawRectangleRec(rl.Rectangle{ - X: rec.X + textOffsetX - 1, - Y: rec.Y + textOffsetY, - Width: glyphWidth, - Height: float32(font.BaseSize) * scaleFactor, - }, selectBackTint) - isGlyphSelected = true - } - - // Draw current character glyph - if (codepoint != ' ') && (codepoint != '\t') { - col := tint - if isGlyphSelected { - col = selectTint - } - pos := rl.Vector2{ - X: rec.X + textOffsetX, - Y: rec.Y + textOffsetY, - } - rl.DrawTextEx(font, string(codepoint), pos, fontSize, 0, col) - } - } - - if wordWrap && (i == endLine) { - textOffsetY += float32(font.BaseSize+font.BaseSize/2) * scaleFactor - textOffsetX = 0 - startLine = endLine - endLine = -1 - glyphWidth = 0 - selectStart += lastk - k - k = lastk - - state = 1 - state // Toggle state between MeasureState and DrawState - } - } - - if (textOffsetX != 0) || (codepoint != ' ') { // avoid leading spaces - textOffsetX += glyphWidth - } - } -} diff --git a/examples/text/sprite_fonts/main.go b/examples/text/sprite_fonts/main.go index d388b62..0958818 100644 --- a/examples/text/sprite_fonts/main.go +++ b/examples/text/sprite_fonts/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/text/ttf_loading/main.go b/examples/text/ttf_loading/main.go index d3dae4a..57e7eaa 100644 --- a/examples/text/ttf_loading/main.go +++ b/examples/text/ttf_loading/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -17,7 +17,7 @@ func main() { // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) // TTF Font loading with custom generation parameters - font := rl.LoadFontEx("fonts/KAISG.ttf", 96, nil) + font := rl.LoadFontEx("fonts/KAISG.ttf", 96, nil, 0) // Generate mipmap levels to use trilinear filtering // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR @@ -30,7 +30,7 @@ func main() { rl.SetTextureFilter(font.Texture, rl.FilterPoint) currentFontFilter := 0 // FilterPoint - count := 0 + count := int32(0) droppedFiles := make([]string, 0) rl.SetTargetFPS(60) @@ -38,7 +38,7 @@ func main() { for !rl.WindowShouldClose() { // Update //---------------------------------------------------------------------------------- - fontSize += int32(rl.GetMouseWheelMove() * 4.0) + fontSize += rl.GetMouseWheelMove() * 4.0 // Choose font texture filter method if rl.IsKeyPressed(rl.KeyOne) { @@ -63,13 +63,12 @@ func main() { // Load a dropped TTF file dynamically (at current fontSize) if rl.IsFileDropped() { - droppedFiles = rl.LoadDroppedFiles() - count = len(droppedFiles) + droppedFiles = rl.GetDroppedFiles(&count) if count == 1 { // Only support one ttf file dropped rl.UnloadFont(font) - font = rl.LoadFontEx(droppedFiles[0], fontSize, nil) - rl.UnloadDroppedFiles() + font = rl.LoadFontEx(droppedFiles[0], fontSize, nil, 0) + rl.ClearDroppedFiles() } } @@ -105,7 +104,7 @@ func main() { rl.UnloadFont(font) // Font unloading - rl.UnloadDroppedFiles() // Clear internal buffers + rl.ClearDroppedFiles() // Clear internal buffers rl.CloseWindow() } diff --git a/examples/text/unicode/main.go b/examples/text/unicode/main.go deleted file mode 100644 index 42f1897..0000000 --- a/examples/text/unicode/main.go +++ /dev/null @@ -1,396 +0,0 @@ -/******************************************************************************************* -* -* raylib [text] example - Unicode -* -* Example originally created with raylib 2.5, last time updated with raylib 4.0 -* -* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2019-2024 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import ( - "fmt" - "unicode/utf8" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 - emojiPerWidth = 8 - emojiPerHeight = 4 - MeasureState = 0 - DrawState = 1 -) - -type Messages struct { - text string - language string -} - -type Emoji struct { - index int32 // Index inside `emojiCodepoints` - message int32 // Message index - color rl.Color // Emoji color -} - -// Arrays that holds the random emojis -var emoji [emojiPerWidth * emojiPerHeight]Emoji -var hovered, selected int32 = -1, -1 - -func main() { - rl.SetConfigFlags(rl.FlagMsaa4xHint | rl.FlagVsyncHint) - rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - unicode") - - // Load the font resources - // NOTE: fontAsian is for asian languages, - // fontEmoji is the emojis and fontDefault is used for everything else - fontDefault := rl.LoadFont("resources/dejavu.fnt") - fontAsian := rl.LoadFont("resources/noto_cjk.fnt") - fontEmoji := rl.LoadFont("resources/symbola.fnt") - - hoveredPos := rl.Vector2{} - selectedPos := rl.Vector2{} - - RandomizeEmoji() - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - - // Add a new set of emojis when SPACE is pressed - if rl.IsKeyPressed(rl.KeySpace) { - RandomizeEmoji() - } - - // Set the selected emoji - if rl.IsMouseButtonPressed(rl.MouseButtonLeft) && (hovered != -1) && (hovered != selected) { - selected = hovered - selectedPos = hoveredPos - } - - mouse := rl.GetMousePosition() - position := rl.Vector2{ - X: 28.8, - Y: 10.0, - } - hovered = -1 - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - // Draw random emojis in the background - for i := int32(0); i < emojiPerWidth*emojiPerHeight; i++ { - txt := emojiCodepoints[emoji[i].index : emoji[i].index+4] - emojiRect := rl.Rectangle{ - X: position.X, - Y: position.Y, - Width: float32(fontEmoji.BaseSize), - Height: float32(fontEmoji.BaseSize), - } - - if !rl.CheckCollisionPointRec(mouse, emojiRect) { - col := rl.Fade(rl.LightGray, 0.4) - if selected == i { - col = emoji[i].color - } - rl.DrawTextEx(fontEmoji, txt, position, float32(fontEmoji.BaseSize), 1.0, col) - } else { - rl.DrawTextEx(fontEmoji, txt, position, float32(fontEmoji.BaseSize), 1.0, emoji[i].color) - hovered = i - hoveredPos = position - } - - if (i != 0) && (i%emojiPerWidth == 0) { - position.Y += float32(fontEmoji.BaseSize) + 24.25 - position.X = 28.8 - } else { - position.X += float32(fontEmoji.BaseSize) + 28.8 - } - } - - // Draw the message when an emoji is selected - if selected != -1 { - message := emoji[selected].message - horizontalPadding := 20 - verticalPadding := 30 - font := fontDefault - - // Set correct font for asian languages - if messages[message].language == "Chinese" || - messages[message].language == "Korean" || - messages[message].language == "Japanese" { - font = fontAsian - } - - // Calculate size for the message box (approximate the height and width) - sz := rl.MeasureTextEx(font, messages[message].text, float32(font.BaseSize), 1.0) - if sz.X > 300 { - sz.Y *= sz.X / 300 - sz.X = 300 - } else if sz.X < 160 { - sz.X = 160 - } - - msgRect := rl.Rectangle{ - X: selectedPos.X - 38.8, - Y: selectedPos.Y, - Width: float32(2*horizontalPadding) + sz.X, - Height: float32(2*verticalPadding) + sz.Y, - } - msgRect.Y -= msgRect.Height - - // Coordinates for the chat bubble triangle - a := rl.Vector2{ - X: selectedPos.X, - Y: msgRect.Y + msgRect.Height, - } - b := rl.Vector2{ - X: a.X + 8, - Y: a.Y + 10, - } - c := rl.Vector2{ - X: a.X + 10, - Y: a.Y, - } - - // Don't go outside the screen - if msgRect.X < 10 { - msgRect.X += 28 - } - if msgRect.Y < 10 { - msgRect.Y = selectedPos.Y + 84 - a.Y = msgRect.Y - c.Y = a.Y - b.Y = a.Y - 10 - - // Swap values so we can actually render the triangle :( - a, b = b, a - } - - if msgRect.X+msgRect.Width > screenWidth { - msgRect.X -= (msgRect.X + msgRect.Width) - screenWidth + 10 - } - - // Draw chat bubble - rl.DrawRectangleRec(msgRect, emoji[selected].color) - rl.DrawTriangle(a, b, c, emoji[selected].color) - - // Draw the main text message - textRect := rl.Rectangle{ - X: msgRect.X + float32(horizontalPadding)/2, - Y: msgRect.Y + float32(verticalPadding)/2, - Width: msgRect.Width - float32(horizontalPadding), - Height: msgRect.Height, - } - DrawTextBoxed(font, messages[message].text, textRect, float32(font.BaseSize), 1.0, true, rl.White) - - // Draw the info text below the main message - size := len(messages[message].text) - length := utf8.RuneCountInString(messages[message].text) - info := fmt.Sprintf("%s %d characters %d bytes", messages[message].language, length, size) - sz = rl.MeasureTextEx(rl.GetFontDefault(), info, 10, 1.0) - - rl.DrawText(info, int32(textRect.X+textRect.Width-sz.X), int32(msgRect.Y+msgRect.Height-sz.Y-2), 10, - rl.RayWhite) - - } - - // Draw the info text - rl.DrawText("These emojis have something to tell you, click each to find out!", (screenWidth-650)/2, - screenHeight-40, 20, rl.Gray) - rl.DrawText("Each emoji is a unicode character from a font, not a texture... Press [SPACEBAR] to refresh", - (screenWidth-484)/2, screenHeight-16, 10, rl.Gray) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadFont(fontDefault) // Unload font resource - rl.UnloadFont(fontAsian) // Unload font resource - rl.UnloadFont(fontEmoji) // Unload font resource - - rl.CloseWindow() // Close window and OpenGL context -} - -// RandomizeEmoji fills the emoji array with random emoji (only those emojis present in fontEmoji) -func RandomizeEmoji() { - hovered, selected = -1, -1 - start := rl.GetRandomValue(45, 360) - - for i := int32(0); i < emojiPerWidth*emojiPerHeight; i++ { - // 0-179 emoji codepoints (from emoji char array) each 4bytes + null char - emoji[i].index = rl.GetRandomValue(0, 179) * 5 - - // Generate a random color for this emoji - emoji[i].color = rl.Fade(rl.ColorFromHSV(float32((start*(i+1))%360), 0.6, 0.85), 0.8) - - // Set a random message for this emoji - emoji[i].message = rl.GetRandomValue(0, int32(len(messages)-1)) - } -} - -// DrawTextBoxed draws text using font inside rectangle limits -func DrawTextBoxed(font rl.Font, text string, rec rl.Rectangle, fontSize, spacing float32, wordWrap bool, tint rl.Color) { - DrawTextBoxedSelectable(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, rl.White, rl.White) -} - -// DrawTextBoxedSelectable draws text using font inside rectangle limits with support for text selection -func DrawTextBoxedSelectable(font rl.Font, text string, rec rl.Rectangle, fontSize, spacing float32, - wordWrap bool, tint rl.Color, selectStart, selectLength int32, selectTint, selectBackTint rl.Color) { - - length := int32(len(text)) // Total length in bytes of the text, scanned by codepoints in loop - - // TextOffsetY : Offset between lines (on line break '\n') - // TextOffsetX : Offset X to next character to draw - var textOffsetY, textOffsetX float32 - - scaleFactor := fontSize / float32(font.BaseSize) // Character rectangle scaling factor - - // Word/character wrapping mechanism variables - state := DrawState - if wordWrap { - state = MeasureState - } - - // StartLine : Index where to begin drawing (where a line begins) - // EndLine : Index where to stop drawing (where a line ends) - // LastK : Holds last value of the character position - var startLine, endLine, lastk int32 = -1, -1, -1 - for i, k := int32(0), int32(0); i < length; i, k = i+1, k+1 { - // Get next codepoint from byte string and glyph index in font - codepoint, width := utf8.DecodeRuneInString(text[i:]) - codepointByteCount := int32(width) - index := rl.GetGlyphIndex(font, codepoint) - - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all the bad bytes using the '?' symbol moving one byte - if codepoint == 0x3f { - codepointByteCount = 1 - } - i += codepointByteCount - 1 - - var glyphWidth float32 - if codepoint != '\n' { - chars := unsafe.Slice(font.Chars, font.CharsCount) - if chars[index].AdvanceX == 0 { - glyphWidth = unsafe.Slice(font.Recs, font.CharsCount)[index].Width * scaleFactor - } else { - glyphWidth = float32(chars[index].AdvanceX) * scaleFactor - } - - if i+1 < length { - glyphWidth = glyphWidth + spacing - } - } - - // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside the rec container - // We store this info in startLine and endLine, then we change states, draw the text between those two variables - // and change states again and again recursively until the end of the text (or until we get outside the container). - // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately - // and begin drawing on the next line before we can get outside the container. - if state == MeasureState { - // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more - // Ref: http://jkorpela.fi/chars/spaces.html - if (codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n') { - endLine = i - } - - if (textOffsetX + glyphWidth) > rec.Width { - if endLine < 1 { - endLine = i - } - - if i == endLine { - endLine -= codepointByteCount - } - if (startLine + codepointByteCount) == endLine { - endLine = i - codepointByteCount - } - - state = 1 - state // Toggle state between MeasureState and DrawState - } else if (i + 1) == length { - endLine = i - state = 1 - state // Toggle state between MeasureState and DrawState - } else if codepoint == '\n' { - state = 1 - state // Toggle state between MeasureState and DrawState - } - - if state == DrawState { - textOffsetX = 0 - i = startLine - glyphWidth = 0 - - // Save character position when we switch states - lastk, k = k-1, lastk - } - } else { - if codepoint == '\n' { - if !wordWrap { - textOffsetY += float32(font.BaseSize+font.BaseSize/2) * scaleFactor - textOffsetX = 0 - } - } else { - if !wordWrap && ((textOffsetX + glyphWidth) > rec.Width) { - textOffsetY += float32(font.BaseSize+font.BaseSize/2) * scaleFactor - textOffsetX = 0 - } - - // When text overflows rectangle height limit, just stop drawing - if (textOffsetY + float32(font.BaseSize)*scaleFactor) > rec.Height { - break - } - - // Draw selection background - isGlyphSelected := false - if (selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)) { - rl.DrawRectangleRec(rl.Rectangle{ - X: rec.X + textOffsetX - 1, - Y: rec.Y + textOffsetY, - Width: glyphWidth, - Height: float32(font.BaseSize) * scaleFactor, - }, selectBackTint) - isGlyphSelected = true - } - - // Draw current character glyph - if (codepoint != ' ') && (codepoint != '\t') { - col := tint - if isGlyphSelected { - col = selectTint - } - pos := rl.Vector2{ - X: rec.X + textOffsetX, - Y: rec.Y + textOffsetY, - } - rl.DrawTextEx(font, string(codepoint), pos, fontSize, 0, col) - } - } - - if wordWrap && (i == endLine) { - textOffsetY += float32(font.BaseSize+font.BaseSize/2) * scaleFactor - textOffsetX = 0 - startLine = endLine - endLine = -1 - glyphWidth = 0 - selectStart += lastk - k - k = lastk - - state = 1 - state // Toggle state between MeasureState and DrawState - } - } - - textOffsetX += glyphWidth - } -} diff --git a/examples/text/unicode/resources/dejavu.fnt b/examples/text/unicode/resources/dejavu.fnt deleted file mode 100644 index 6503b35..0000000 --- a/examples/text/unicode/resources/dejavu.fnt +++ /dev/null @@ -1,1115 +0,0 @@ -info face="DejaVu Sans" size=-16 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2 outline=1 -common lineHeight=19 base=15 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 -page id=0 file="dejavu.png" -chars count=1111 -char id=32 x=259 y=464 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=33 x=464 y=382 width=4 height=14 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=34 x=112 y=461 width=7 height=7 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15 -char id=35 x=33 y=407 width=14 height=13 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=15 -char id=36 x=381 y=153 width=10 height=16 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=37 x=493 y=222 width=17 height=14 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=38 x=275 y=257 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=39 x=506 y=395 width=4 height=7 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15 -char id=40 x=18 y=178 width=6 height=16 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=41 x=10 y=178 width=6 height=16 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=42 x=192 y=444 width=10 height=11 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=43 x=369 y=415 width=13 height=11 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=44 x=474 y=450 width=5 height=6 xoffset=0 yoffset=12 xadvance=5 page=0 chnl=15 -char id=45 x=191 y=468 width=7 height=4 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=15 -char id=46 x=207 y=465 width=5 height=4 xoffset=0 yoffset=12 xadvance=5 page=0 chnl=15 -char id=47 x=331 y=224 width=8 height=15 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=15 -char id=48 x=396 y=304 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=49 x=290 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=50 x=386 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=51 x=374 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=52 x=466 y=302 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=53 x=338 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=54 x=273 y=353 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=55 x=326 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=56 x=286 y=353 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=57 x=42 y=327 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=58 x=428 y=441 width=5 height=10 xoffset=0 yoffset=6 xadvance=5 page=0 chnl=15 -char id=59 x=472 y=398 width=5 height=12 xoffset=0 yoffset=6 xadvance=5 page=0 chnl=15 -char id=60 x=339 y=415 width=13 height=11 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=61 x=42 y=461 width=13 height=7 xoffset=0 yoffset=7 xadvance=13 page=0 chnl=15 -char id=62 x=324 y=415 width=13 height=11 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=63 x=501 y=238 width=9 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=64 x=368 y=135 width=17 height=16 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=65 x=60 y=295 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=66 x=299 y=353 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=67 x=90 y=295 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=68 x=105 y=294 width=13 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=69 x=325 y=353 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=70 x=194 y=371 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=71 x=208 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=72 x=420 y=320 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=73 x=423 y=384 width=5 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=74 x=237 y=136 width=7 height=17 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=15 -char id=75 x=60 y=311 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=76 x=72 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=77 x=288 y=273 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=78 x=74 y=311 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=79 x=320 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=80 x=351 y=353 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=81 x=467 y=135 width=14 height=16 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=82 x=102 y=311 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=83 x=116 y=310 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=84 x=130 y=310 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=85 x=144 y=307 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=86 x=496 y=270 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=87 x=164 y=242 width=18 height=14 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=88 x=150 y=291 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=89 x=158 y=307 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=90 x=210 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=91 x=34 y=178 width=6 height=16 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=92 x=321 y=224 width=8 height=15 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=15 -char id=93 x=26 y=178 width=6 height=16 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=94 x=27 y=461 width=13 height=7 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=95 x=107 y=470 width=12 height=4 xoffset=-2 yoffset=16 xadvance=8 page=0 chnl=15 -char id=96 x=398 y=453 width=7 height=6 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=15 -char id=97 x=312 y=428 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=98 x=455 y=350 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=99 x=36 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=100 x=468 y=350 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=101 x=286 y=428 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=102 x=311 y=385 width=8 height=14 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=103 x=65 y=375 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=104 x=410 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=105 x=476 y=382 width=4 height=14 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15 -char id=106 x=289 y=136 width=6 height=17 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=107 x=130 y=374 width=11 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=108 x=482 y=382 width=4 height=14 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15 -char id=109 x=93 y=422 width=16 height=11 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=110 x=495 y=424 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=111 x=260 y=430 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=112 x=143 y=374 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=113 x=156 y=371 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=114 x=292 y=441 width=8 height=11 xoffset=0 yoffset=5 xadvance=7 page=0 chnl=15 -char id=115 x=435 y=428 width=10 height=11 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=116 x=229 y=402 width=8 height=13 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15 -char id=117 x=411 y=428 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=118 x=143 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=119 x=213 y=418 width=15 height=11 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=120 x=130 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=121 x=476 y=318 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=122 x=363 y=428 width=10 height=11 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=123 x=60 y=141 width=10 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=124 x=469 y=20 width=5 height=18 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=125 x=48 y=141 width=10 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=126 x=266 y=456 width=13 height=6 xoffset=0 yoffset=7 xadvance=13 page=0 chnl=15 -char id=160 x=284 y=463 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=161 x=506 y=153 width=4 height=14 xoffset=1 yoffset=5 xadvance=6 page=0 chnl=15 -char id=162 x=492 y=205 width=10 height=15 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=15 -char id=163 x=0 y=343 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=164 x=440 y=414 width=12 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=165 x=0 y=327 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=166 x=42 y=178 width=5 height=16 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=15 -char id=167 x=345 y=154 width=10 height=16 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=168 x=502 y=447 width=8 height=5 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=169 x=352 y=273 width=14 height=14 xoffset=1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=170 x=237 y=443 width=9 height=11 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=171 x=337 y=441 width=10 height=10 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=15 -char id=172 x=462 y=440 width=13 height=8 xoffset=0 yoffset=7 xadvance=13 page=0 chnl=15 -char id=173 x=155 y=470 width=7 height=4 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=15 -char id=174 x=400 y=272 width=14 height=14 xoffset=1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=175 x=145 y=470 width=8 height=4 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=176 x=0 y=461 width=8 height=8 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=177 x=337 y=401 width=13 height=12 xoffset=0 yoffset=4 xadvance=13 page=0 chnl=15 -char id=178 x=392 y=441 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=179 x=382 y=441 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=180 x=380 y=453 width=7 height=6 xoffset=1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=181 x=169 y=371 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=182 x=393 y=153 width=10 height=16 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=183 x=14 y=471 width=5 height=5 xoffset=0 yoffset=7 xadvance=5 page=0 chnl=15 -char id=184 x=423 y=453 width=6 height=6 xoffset=1 yoffset=13 xadvance=8 page=0 chnl=15 -char id=185 x=411 y=441 width=7 height=10 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=186 x=259 y=443 width=9 height=11 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=187 x=349 y=441 width=10 height=10 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=15 -char id=188 x=411 y=238 width=16 height=14 xoffset=0 yoffset=2 xadvance=16 page=0 chnl=15 -char id=189 x=447 y=238 width=16 height=14 xoffset=0 yoffset=2 xadvance=16 page=0 chnl=15 -char id=190 x=356 y=240 width=17 height=14 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=191 x=228 y=386 width=9 height=14 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=192 x=135 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=193 x=150 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=194 x=165 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=195 x=180 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=196 x=195 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=197 x=210 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=198 x=299 y=241 width=17 height=14 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=199 x=225 y=79 width=13 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=200 x=119 y=118 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=201 x=106 y=119 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=202 x=80 y=119 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=203 x=353 y=116 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=204 x=504 y=97 width=6 height=17 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=205 x=321 y=136 width=6 height=17 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=206 x=187 y=136 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=207 x=147 y=136 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=208 x=448 y=270 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=209 x=420 y=97 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=210 x=112 y=61 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=211 x=32 y=65 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=212 x=128 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=213 x=457 y=40 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=214 x=473 y=40 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=215 x=380 y=401 width=12 height=12 xoffset=1 yoffset=4 xadvance=13 page=0 chnl=15 -char id=216 x=451 y=135 width=14 height=16 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=217 x=329 y=79 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=218 x=476 y=97 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=219 x=308 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=220 x=70 y=100 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=221 x=56 y=103 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=222 x=26 y=375 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=223 x=0 y=375 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=224 x=52 y=213 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=225 x=39 y=213 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=226 x=26 y=213 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=227 x=494 y=350 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=228 x=481 y=350 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=229 x=293 y=155 width=11 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=230 x=0 y=422 width=17 height=11 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=231 x=192 y=387 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=232 x=478 y=188 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=233 x=452 y=188 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=234 x=426 y=188 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=235 x=429 y=352 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=236 x=380 y=223 width=7 height=15 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=237 x=371 y=223 width=7 height=15 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=15 -char id=238 x=351 y=223 width=8 height=15 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=239 x=321 y=385 width=8 height=14 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=240 x=403 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=241 x=422 y=368 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=242 x=286 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=243 x=260 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=244 x=234 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=245 x=364 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=246 x=338 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=247 x=310 y=441 width=13 height=10 xoffset=0 yoffset=6 xadvance=13 page=0 chnl=15 -char id=248 x=64 y=407 width=12 height=13 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=249 x=96 y=229 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=250 x=84 y=229 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=251 x=24 y=230 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=252 x=60 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=253 x=315 y=20 width=11 height=18 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=254 x=158 y=117 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=255 x=171 y=117 width=11 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=256 x=45 y=160 width=13 height=16 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=15 -char id=257 x=312 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=258 x=0 y=26 width=13 height=18 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=259 x=195 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=260 x=80 y=62 width=14 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=261 x=322 y=321 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=262 x=255 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=263 x=312 y=207 width=10 height=15 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=264 x=270 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=265 x=384 y=206 width=10 height=15 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=266 x=285 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=267 x=24 y=391 width=10 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=268 x=300 y=79 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=269 x=456 y=205 width=10 height=15 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=270 x=288 y=60 width=13 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=271 x=432 y=270 width=14 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=272 x=368 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=273 x=266 y=321 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=274 x=254 y=155 width=11 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=15 -char id=275 x=234 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=276 x=197 y=117 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=277 x=169 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=278 x=210 y=117 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=279 x=247 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=280 x=223 y=117 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=281 x=260 y=353 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=282 x=236 y=117 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=283 x=156 y=208 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=284 x=425 y=40 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=285 x=172 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=286 x=377 y=40 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=287 x=328 y=20 width=11 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=288 x=48 y=62 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=289 x=444 y=116 width=11 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=290 x=394 y=0 width=14 height=18 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=291 x=185 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=292 x=42 y=103 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=293 x=322 y=98 width=12 height=17 xoffset=-2 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=294 x=108 y=262 width=15 height=14 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=295 x=298 y=305 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=296 x=157 y=136 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=297 x=281 y=385 width=8 height=14 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=298 x=486 y=153 width=8 height=16 xoffset=-2 yoffset=0 xadvance=5 page=0 chnl=15 -char id=299 x=271 y=385 width=8 height=14 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=300 x=107 y=138 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=301 x=311 y=224 width=8 height=15 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=302 x=305 y=136 width=6 height=17 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=303 x=313 y=136 width=6 height=17 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15 -char id=304 x=505 y=116 width=5 height=17 xoffset=0 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=305 x=506 y=382 width=4 height=11 xoffset=0 yoffset=5 xadvance=4 page=0 chnl=15 -char id=306 x=84 y=138 width=10 height=17 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=307 x=137 y=137 width=8 height=17 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=308 x=101 y=0 width=8 height=20 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=309 x=443 y=20 width=8 height=18 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=310 x=88 y=22 width=12 height=18 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=311 x=302 y=21 width=11 height=18 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=312 x=0 y=435 width=11 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=313 x=493 y=116 width=10 height=17 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=15 -char id=314 x=297 y=136 width=6 height=17 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=15 -char id=315 x=401 y=20 width=10 height=18 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=316 x=461 y=20 width=6 height=18 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15 -char id=317 x=48 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=318 x=406 y=385 width=7 height=14 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=319 x=302 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=320 x=379 y=385 width=7 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=321 x=340 y=305 width=12 height=14 xoffset=-2 yoffset=2 xadvance=9 page=0 chnl=15 -char id=322 x=397 y=385 width=7 height=14 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=15 -char id=323 x=238 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=324 x=108 y=229 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=325 x=60 y=23 width=12 height=18 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=326 x=144 y=226 width=10 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=327 x=210 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=328 x=336 y=207 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=329 x=315 y=289 width=13 height=14 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=330 x=168 y=98 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=331 x=216 y=387 width=10 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=332 x=483 y=135 width=14 height=16 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=15 -char id=333 x=13 y=343 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=334 x=64 y=62 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=335 x=374 y=189 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=336 x=176 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=337 x=400 y=188 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=338 x=63 y=247 width=19 height=14 xoffset=-1 yoffset=2 xadvance=17 page=0 chnl=15 -char id=339 x=486 y=398 width=18 height=11 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=340 x=14 y=103 width=12 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=341 x=236 y=224 width=9 height=15 xoffset=0 yoffset=1 xadvance=7 page=0 chnl=15 -char id=342 x=116 y=21 width=12 height=18 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=343 x=192 y=224 width=9 height=15 xoffset=-1 yoffset=5 xadvance=7 page=0 chnl=15 -char id=344 x=455 y=78 width=12 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=345 x=291 y=224 width=8 height=15 xoffset=0 yoffset=1 xadvance=7 page=0 chnl=15 -char id=346 x=182 y=98 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=347 x=360 y=206 width=10 height=15 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=348 x=462 y=97 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=349 x=396 y=205 width=10 height=15 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=350 x=497 y=78 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=351 x=180 y=387 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=352 x=84 y=100 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=353 x=444 y=205 width=10 height=15 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=354 x=98 y=100 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=355 x=0 y=178 width=8 height=16 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15 -char id=356 x=126 y=99 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=357 x=361 y=223 width=8 height=15 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15 -char id=358 x=294 y=321 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=359 x=239 y=402 width=8 height=13 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15 -char id=360 x=196 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=361 x=84 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=362 x=173 y=155 width=12 height=16 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=15 -char id=363 x=230 y=370 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=364 x=280 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=365 x=132 y=226 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=366 x=294 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=367 x=453 y=153 width=10 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=15 -char id=368 x=350 y=97 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=369 x=12 y=230 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=370 x=364 y=97 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=371 x=104 y=343 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=372 x=126 y=41 width=18 height=17 xoffset=-1 yoffset=-1 xadvance=16 page=0 chnl=15 -char id=373 x=343 y=172 width=15 height=15 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=374 x=434 y=97 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=375 x=289 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=376 x=14 y=122 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=377 x=105 y=80 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=378 x=348 y=206 width=10 height=15 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=379 x=90 y=81 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=380 x=156 y=387 width=10 height=14 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=381 x=60 y=81 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=382 x=156 y=225 width=10 height=15 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=383 x=331 y=385 width=8 height=14 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=384 x=434 y=320 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=385 x=243 y=257 width=14 height=14 xoffset=-2 yoffset=2 xadvance=12 page=0 chnl=15 -char id=386 x=78 y=375 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=387 x=416 y=352 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=388 x=364 y=321 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=389 x=480 y=302 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=390 x=225 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=391 x=310 y=41 width=15 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=392 x=270 y=305 width=12 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=393 x=259 y=257 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=394 x=483 y=238 width=16 height=14 xoffset=-2 yoffset=2 xadvance=13 page=0 chnl=15 -char id=395 x=130 y=358 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=396 x=377 y=337 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=397 x=52 y=359 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=398 x=325 y=337 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=399 x=419 y=254 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=400 x=12 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=401 x=336 y=98 width=12 height=17 xoffset=-2 yoffset=2 xadvance=9 page=0 chnl=15 -char id=402 x=96 y=138 width=9 height=17 xoffset=-2 yoffset=2 xadvance=6 page=0 chnl=15 -char id=403 x=239 y=41 width=16 height=17 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=404 x=363 y=59 width=13 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=405 x=36 y=263 width=16 height=14 xoffset=0 yoffset=2 xadvance=16 page=0 chnl=15 -char id=406 x=361 y=385 width=7 height=14 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=407 x=388 y=385 width=7 height=14 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=15 -char id=408 x=165 y=291 width=13 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=409 x=442 y=336 width=11 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=410 x=370 y=385 width=7 height=14 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15 -char id=411 x=468 y=334 width=11 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=412 x=429 y=238 width=16 height=14 xoffset=0 yoffset=2 xadvance=16 page=0 chnl=15 -char id=413 x=409 y=40 width=14 height=17 xoffset=-2 yoffset=2 xadvance=12 page=0 chnl=15 -char id=414 x=218 y=370 width=10 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=415 x=96 y=278 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=416 x=112 y=278 width=14 height=14 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=417 x=352 y=401 width=12 height=12 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=418 x=18 y=263 width=16 height=14 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=419 x=450 y=286 width=13 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=420 x=405 y=288 width=13 height=14 xoffset=-2 yoffset=2 xadvance=10 page=0 chnl=15 -char id=421 x=288 y=117 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=422 x=159 y=155 width=12 height=16 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=423 x=14 y=327 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=424 x=132 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=425 x=143 y=358 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=426 x=327 y=117 width=11 height=17 xoffset=-4 yoffset=2 xadvance=5 page=0 chnl=15 -char id=427 x=476 y=153 width=8 height=16 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15 -char id=428 x=326 y=305 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=429 x=341 y=385 width=8 height=14 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=430 x=112 y=99 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=431 x=192 y=274 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=432 x=366 y=401 width=12 height=12 xoffset=0 yoffset=4 xadvance=10 page=0 chnl=15 -char id=433 x=240 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=434 x=70 y=327 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=435 x=128 y=275 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=436 x=176 y=274 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=437 x=330 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=438 x=423 y=428 width=10 height=11 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=439 x=489 y=318 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=440 x=242 y=305 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=441 x=104 y=375 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=442 x=0 y=230 width=10 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=443 x=350 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=444 x=126 y=326 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=445 x=208 y=354 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=446 x=372 y=206 width=10 height=15 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=447 x=195 y=355 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=448 x=505 y=39 width=5 height=17 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=449 x=117 y=138 width=8 height=17 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=450 x=36 y=141 width=10 height=17 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=15 -char id=451 x=458 y=382 width=4 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=452 x=476 y=20 width=23 height=17 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 -char id=453 x=80 y=178 width=21 height=15 xoffset=0 yoffset=1 xadvance=21 page=0 chnl=15 -char id=454 x=103 y=175 width=19 height=15 xoffset=-1 yoffset=1 xadvance=18 page=0 chnl=15 -char id=455 x=441 y=40 width=14 height=17 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=456 x=393 y=59 width=13 height=17 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=457 x=264 y=136 width=7 height=17 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15 -char id=458 x=257 y=41 width=16 height=17 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=459 x=160 y=60 width=14 height=17 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=460 x=0 y=84 width=13 height=17 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=461 x=408 y=59 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=462 x=221 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=463 x=217 y=136 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=464 x=301 y=224 width=8 height=15 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=465 x=272 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=466 x=247 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=467 x=483 y=78 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=468 x=432 y=205 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=469 x=158 y=21 width=12 height=18 xoffset=0 yoffset=-2 xadvance=12 page=0 chnl=15 -char id=470 x=369 y=153 width=10 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=15 -char id=471 x=242 y=0 width=12 height=19 xoffset=0 yoffset=-3 xadvance=12 page=0 chnl=15 -char id=472 x=72 y=141 width=10 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=473 x=256 y=0 width=12 height=19 xoffset=0 yoffset=-3 xadvance=12 page=0 chnl=15 -char id=474 x=457 y=116 width=10 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=475 x=270 y=0 width=12 height=19 xoffset=0 yoffset=-3 xadvance=12 page=0 chnl=15 -char id=476 x=0 y=141 width=10 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=477 x=91 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=478 x=488 y=0 width=13 height=18 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=479 x=332 y=154 width=11 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=480 x=458 y=0 width=13 height=18 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=481 x=306 y=155 width=11 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=482 x=349 y=136 width=17 height=16 xoffset=-1 yoffset=0 xadvance=16 page=0 chnl=15 -char id=483 x=318 y=241 width=17 height=14 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=484 x=144 y=275 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=485 x=238 y=321 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=486 x=16 y=65 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=487 x=224 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=488 x=490 y=97 width=12 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=489 x=423 y=59 width=13 height=17 xoffset=-2 yoffset=-1 xadvance=9 page=0 chnl=15 -char id=490 x=96 y=61 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=491 x=78 y=359 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=492 x=182 y=0 width=14 height=19 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=15 -char id=493 x=262 y=117 width=11 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=494 x=54 y=122 width=11 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=495 x=211 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=496 x=433 y=20 width=8 height=18 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=497 x=398 y=222 width=23 height=14 xoffset=0 yoffset=2 xadvance=23 page=0 chnl=15 -char id=498 x=448 y=222 width=21 height=14 xoffset=0 yoffset=2 xadvance=21 page=0 chnl=15 -char id=499 x=0 y=247 width=19 height=14 xoffset=-1 yoffset=2 xadvance=18 page=0 chnl=15 -char id=500 x=208 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=501 x=263 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=502 x=124 y=243 width=18 height=14 xoffset=0 yoffset=2 xadvance=18 page=0 chnl=15 -char id=503 x=67 y=122 width=11 height=17 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=504 x=224 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=505 x=48 y=230 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=506 x=438 y=59 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=507 x=154 y=98 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=508 x=146 y=41 width=17 height=17 xoffset=-1 yoffset=-1 xadvance=16 page=0 chnl=15 -char id=509 x=181 y=173 width=17 height=15 xoffset=-1 yoffset=1 xadvance=16 page=0 chnl=15 -char id=510 x=410 y=0 width=14 height=18 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=511 x=145 y=156 width=12 height=16 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=512 x=453 y=59 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=513 x=273 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=514 x=60 y=160 width=13 height=16 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=15 -char id=515 x=338 y=337 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=516 x=132 y=118 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=517 x=143 y=209 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=518 x=267 y=155 width=11 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=15 -char id=519 x=273 y=337 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=520 x=501 y=20 width=9 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=521 x=203 y=224 width=9 height=15 xoffset=-2 yoffset=1 xadvance=4 page=0 chnl=15 -char id=522 x=496 y=153 width=8 height=16 xoffset=-2 yoffset=0 xadvance=5 page=0 chnl=15 -char id=523 x=502 y=318 width=8 height=14 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=524 x=144 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=525 x=104 y=212 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=526 x=387 y=135 width=14 height=16 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=15 -char id=527 x=208 y=338 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=528 x=385 y=78 width=12 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=529 x=214 y=224 width=9 height=15 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=15 -char id=530 x=201 y=155 width=12 height=16 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=15 -char id=531 x=261 y=385 width=8 height=14 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15 -char id=532 x=427 y=78 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=533 x=36 y=230 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=534 x=75 y=160 width=12 height=16 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=15 -char id=535 x=446 y=368 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=536 x=144 y=21 width=12 height=18 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=537 x=60 y=230 width=10 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=538 x=102 y=22 width=12 height=18 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=539 x=177 y=136 width=8 height=17 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15 -char id=540 x=341 y=20 width=10 height=18 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=541 x=120 y=226 width=10 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=542 x=378 y=97 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=543 x=392 y=97 width=12 height=17 xoffset=-2 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=544 x=406 y=97 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=545 x=327 y=40 width=15 height=17 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=546 x=375 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=547 x=422 y=401 width=11 height=12 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=548 x=240 y=79 width=13 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=549 x=458 y=366 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=550 x=483 y=59 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=551 x=221 y=354 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=552 x=41 y=122 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=553 x=182 y=355 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=554 x=362 y=0 width=14 height=18 xoffset=-1 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=555 x=215 y=155 width=11 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=556 x=378 y=0 width=14 height=18 xoffset=-1 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=557 x=78 y=212 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=558 x=489 y=39 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=559 x=169 y=355 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=560 x=426 y=0 width=14 height=18 xoffset=-1 yoffset=-2 xadvance=13 page=0 chnl=15 -char id=561 x=319 y=155 width=11 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=562 x=89 y=157 width=12 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=563 x=431 y=116 width=11 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=564 x=227 y=136 width=8 height=17 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=15 -char id=565 x=17 y=407 width=14 height=13 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=566 x=465 y=153 width=9 height=16 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=567 x=415 y=385 width=6 height=14 xoffset=-2 yoffset=5 xadvance=4 page=0 chnl=15 -char id=568 x=104 y=246 width=18 height=14 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=569 x=144 y=243 width=18 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=570 x=15 y=160 width=13 height=16 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=571 x=419 y=135 width=14 height=16 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=572 x=146 y=406 width=11 height=13 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15 -char id=573 x=39 y=375 width=11 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=574 x=435 y=135 width=14 height=16 xoffset=-2 yoffset=1 xadvance=10 page=0 chnl=15 -char id=575 x=13 y=213 width=11 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=576 x=0 y=213 width=11 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=577 x=200 y=306 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=578 x=399 y=428 width=10 height=11 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=579 x=336 y=321 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=580 x=355 y=257 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=581 x=390 y=288 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=582 x=250 y=21 width=11 height=18 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=15 -char id=583 x=387 y=188 width=11 height=15 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=584 x=207 y=136 width=8 height=17 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=15 -char id=585 x=197 y=136 width=8 height=17 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=586 x=203 y=41 width=16 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=587 x=270 y=289 width=13 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=588 x=255 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=589 x=215 y=444 width=9 height=11 xoffset=-1 yoffset=5 xadvance=7 page=0 chnl=15 -char id=590 x=480 y=286 width=13 height=14 xoffset=-2 yoffset=2 xadvance=10 page=0 chnl=15 -char id=591 x=234 y=190 width=12 height=15 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=880 x=108 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=881 x=226 y=444 width=9 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=882 x=291 y=257 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=883 x=266 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=884 x=121 y=461 width=5 height=7 xoffset=0 yoffset=1 xadvance=4 page=0 chnl=15 -char id=885 x=439 y=452 width=5 height=6 xoffset=0 yoffset=13 xadvance=4 page=0 chnl=15 -char id=886 x=350 y=321 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=887 x=471 y=425 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=890 x=446 y=452 width=5 height=6 xoffset=2 yoffset=14 xadvance=8 page=0 chnl=15 -char id=891 x=351 y=428 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=892 x=12 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=893 x=48 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=894 x=479 y=398 width=5 height=12 xoffset=0 yoffset=6 xadvance=5 page=0 chnl=15 -char id=895 x=255 y=136 width=7 height=17 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=15 -char id=900 x=389 y=453 width=7 height=6 xoffset=1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=901 x=435 y=441 width=8 height=9 xoffset=0 yoffset=-2 xadvance=8 page=0 chnl=15 -char id=902 x=90 y=195 width=13 height=15 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=903 x=0 y=471 width=5 height=5 xoffset=0 yoffset=7 xadvance=5 page=0 chnl=15 -char id=904 x=428 y=171 width=15 height=15 xoffset=-2 yoffset=1 xadvance=12 page=0 chnl=15 -char id=905 x=308 y=173 width=16 height=15 xoffset=-2 yoffset=1 xadvance=14 page=0 chnl=15 -char id=906 x=225 y=224 width=9 height=15 xoffset=-2 yoffset=1 xadvance=7 page=0 chnl=15 -char id=908 x=411 y=171 width=15 height=15 xoffset=-2 yoffset=1 xadvance=13 page=0 chnl=15 -char id=910 x=236 y=173 width=16 height=15 xoffset=-2 yoffset=1 xadvance=13 page=0 chnl=15 -char id=911 x=326 y=173 width=15 height=15 xoffset=-2 yoffset=1 xadvance=13 page=0 chnl=15 -char id=912 x=423 y=20 width=8 height=18 xoffset=-2 yoffset=-2 xadvance=5 page=0 chnl=15 -char id=913 x=30 y=295 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=914 x=91 y=343 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=915 x=434 y=368 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=916 x=30 y=311 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=917 x=117 y=359 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=918 x=15 y=311 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=919 x=378 y=321 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=920 x=480 y=270 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=921 x=437 y=384 width=5 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=922 x=112 y=327 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=923 x=465 y=286 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=924 x=307 y=257 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=925 x=140 y=326 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=926 x=482 y=366 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=927 x=403 y=256 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=928 x=168 y=323 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=929 x=65 y=343 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=931 x=78 y=343 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=932 x=210 y=322 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=933 x=224 y=321 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=934 x=16 y=279 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=935 x=495 y=286 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=936 x=48 y=279 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=937 x=64 y=279 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=938 x=167 y=136 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=939 x=399 y=78 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=940 x=192 y=190 width=12 height=15 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=941 x=180 y=224 width=10 height=15 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=942 x=377 y=20 width=10 height=18 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=943 x=389 y=223 width=7 height=15 xoffset=0 yoffset=1 xadvance=5 page=0 chnl=15 -char id=944 x=365 y=20 width=10 height=18 xoffset=0 yoffset=-2 xadvance=9 page=0 chnl=15 -char id=945 x=426 y=415 width=12 height=11 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=946 x=237 y=21 width=11 height=18 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=947 x=130 y=342 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=948 x=143 y=342 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=949 x=60 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=950 x=24 y=141 width=10 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=951 x=362 y=369 width=10 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=952 x=364 y=337 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=953 x=302 y=441 width=6 height=11 xoffset=0 yoffset=5 xadvance=5 page=0 chnl=15 -char id=954 x=24 y=448 width=10 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=955 x=169 y=339 width=11 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=956 x=182 y=339 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=957 x=221 y=431 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=958 x=12 y=141 width=10 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=959 x=195 y=431 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=960 x=384 y=415 width=12 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=961 x=91 y=375 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=962 x=314 y=369 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=963 x=398 y=415 width=12 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=964 x=169 y=431 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=965 x=0 y=448 width=10 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=966 x=406 y=320 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=967 x=52 y=375 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=968 x=392 y=321 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=969 x=128 y=422 width=15 height=11 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=970 x=301 y=385 width=8 height=14 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=15 -char id=971 x=168 y=387 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=972 x=299 y=207 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=973 x=480 y=205 width=10 height=15 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 -char id=974 x=394 y=171 width=15 height=15 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=975 x=130 y=21 width=12 height=18 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=976 x=278 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=977 x=390 y=353 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=978 x=195 y=290 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=979 x=143 y=174 width=17 height=15 xoffset=-2 yoffset=1 xadvance=13 page=0 chnl=15 -char id=980 x=75 y=81 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=981 x=357 y=78 width=12 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=982 x=145 y=421 width=15 height=11 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=983 x=346 y=189 width=12 height=15 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=984 x=192 y=60 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=985 x=26 y=343 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=986 x=301 y=117 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=987 x=104 y=359 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=988 x=494 y=366 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=989 x=340 y=117 width=11 height=17 xoffset=-3 yoffset=2 xadvance=7 page=0 chnl=15 -char id=990 x=39 y=359 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=991 x=26 y=359 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=992 x=328 y=0 width=15 height=18 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=993 x=494 y=302 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=994 x=221 y=41 width=16 height=17 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=995 x=159 y=259 width=15 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=996 x=45 y=84 width=13 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=997 x=410 y=304 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=998 x=30 y=84 width=13 height=17 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=999 x=106 y=407 width=12 height=13 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=1000 x=15 y=26 width=13 height=18 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1001 x=439 y=188 width=11 height=15 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1002 x=387 y=256 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1003 x=454 y=414 width=12 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1004 x=30 y=160 width=13 height=16 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=1005 x=499 y=135 width=11 height=16 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1006 x=0 y=103 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1007 x=379 y=116 width=11 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1008 x=394 y=401 width=12 height=12 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1009 x=299 y=337 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1010 x=387 y=428 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1011 x=273 y=136 width=6 height=17 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=1012 x=416 y=272 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1013 x=448 y=400 width=10 height=12 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1014 x=460 y=398 width=10 height=12 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1015 x=286 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1016 x=405 y=116 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1017 x=15 y=295 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1018 x=451 y=254 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1019 x=252 y=321 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1020 x=332 y=190 width=12 height=15 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1021 x=345 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1022 x=0 y=295 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1023 x=135 y=291 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1024 x=418 y=116 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1025 x=28 y=122 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1026 x=0 y=65 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1027 x=481 y=116 width=10 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1028 x=120 y=294 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1029 x=438 y=302 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1030 x=430 y=384 width=5 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=1031 x=127 y=137 width=8 height=17 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=1032 x=246 y=136 width=7 height=17 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=15 -char id=1033 x=42 y=247 width=19 height=14 xoffset=-1 yoffset=2 xadvance=18 page=0 chnl=15 -char id=1034 x=261 y=241 width=17 height=14 xoffset=0 yoffset=2 xadvance=17 page=0 chnl=15 -char id=1035 x=467 y=254 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1036 x=448 y=97 width=12 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=1037 x=441 y=78 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=1038 x=413 y=78 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1039 x=371 y=78 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1040 x=435 y=286 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1041 x=221 y=338 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1042 x=234 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1043 x=36 y=391 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1044 x=361 y=40 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1045 x=247 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1046 x=21 y=247 width=19 height=14 xoffset=-1 yoffset=2 xadvance=17 page=0 chnl=15 -char id=1047 x=260 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1048 x=214 y=305 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1049 x=315 y=79 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=1050 x=354 y=305 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1051 x=360 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1052 x=0 y=279 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1053 x=182 y=323 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1054 x=32 y=279 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1055 x=88 y=311 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1056 x=312 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1057 x=285 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1058 x=56 y=327 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1059 x=196 y=322 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1060 x=125 y=259 width=15 height=14 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1061 x=75 y=295 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1062 x=468 y=59 width=13 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1063 x=351 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1064 x=204 y=241 width=17 height=14 xoffset=0 yoffset=2 xadvance=17 page=0 chnl=15 -char id=1065 x=86 y=42 width=18 height=17 xoffset=0 yoffset=2 xadvance=18 page=0 chnl=15 -char id=1066 x=142 y=259 width=15 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1067 x=80 y=279 width=14 height=14 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1068 x=390 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1069 x=420 y=288 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1070 x=184 y=241 width=18 height=14 xoffset=0 yoffset=2 xadvance=17 page=0 chnl=15 -char id=1071 x=403 y=337 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1072 x=13 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1073 x=117 y=209 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1074 x=375 y=428 width=10 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1075 x=204 y=444 width=9 height=11 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=15 -char id=1076 x=49 y=407 width=13 height=13 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1077 x=52 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1078 x=57 y=422 width=16 height=11 xoffset=-1 yoffset=5 xadvance=14 page=0 chnl=15 -char id=1079 x=84 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1080 x=96 y=448 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1081 x=468 y=205 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1082 x=495 y=411 width=11 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1083 x=338 y=428 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1084 x=412 y=415 width=12 height=11 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1085 x=459 y=427 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1086 x=325 y=428 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1087 x=144 y=448 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1088 x=494 y=334 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1089 x=180 y=444 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1090 x=299 y=428 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1091 x=0 y=359 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1092 x=344 y=40 width=15 height=17 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1093 x=273 y=429 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1094 x=92 y=407 width=12 height=13 xoffset=0 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1095 x=270 y=443 width=9 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1096 x=111 y=422 width=15 height=11 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15 -char id=1097 x=488 y=382 width=16 height=13 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15 -char id=1098 x=309 y=415 width=13 height=11 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1099 x=468 y=412 width=12 height=11 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1100 x=447 y=427 width=10 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1101 x=120 y=448 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1102 x=247 y=417 width=14 height=11 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1103 x=117 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1104 x=65 y=212 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1105 x=91 y=359 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1106 x=0 y=122 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1107 x=247 y=224 width=9 height=15 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=15 -char id=1108 x=168 y=447 width=10 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1109 x=483 y=425 width=10 height=11 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=1110 x=506 y=366 width=4 height=14 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15 -char id=1111 x=291 y=385 width=8 height=14 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=1112 x=281 y=136 width=6 height=17 xoffset=-2 yoffset=2 xadvance=4 page=0 chnl=15 -char id=1113 x=75 y=422 width=16 height=11 xoffset=-1 yoffset=5 xadvance=14 page=0 chnl=15 -char id=1114 x=196 y=418 width=15 height=11 xoffset=0 yoffset=5 xadvance=14 page=0 chnl=15 -char id=1115 x=368 y=305 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1116 x=491 y=188 width=11 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1117 x=72 y=229 width=10 height=15 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1118 x=276 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=1119 x=184 y=403 width=10 height=13 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1120 x=375 y=240 width=16 height=14 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1121 x=162 y=418 width=15 height=11 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1122 x=160 y=275 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1123 x=228 y=305 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1124 x=290 y=173 width=16 height=15 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1125 x=408 y=401 width=12 height=12 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1126 x=54 y=263 width=16 height=14 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1127 x=179 y=418 width=15 height=11 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1128 x=471 y=222 width=20 height=14 xoffset=0 yoffset=2 xadvance=19 page=0 chnl=15 -char id=1129 x=19 y=422 width=17 height=11 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=1130 x=224 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1131 x=78 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1132 x=337 y=241 width=17 height=14 xoffset=0 yoffset=2 xadvance=16 page=0 chnl=15 -char id=1133 x=263 y=416 width=14 height=11 xoffset=0 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1134 x=60 y=0 width=11 height=21 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1135 x=353 y=20 width=10 height=18 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1136 x=90 y=262 width=16 height=14 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1137 x=129 y=0 width=16 height=19 xoffset=-1 yoffset=1 xadvance=14 page=0 chnl=15 -char id=1138 x=256 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1139 x=65 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1140 x=210 y=257 width=15 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1141 x=294 y=415 width=13 height=11 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1142 x=293 y=41 width=15 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=1143 x=135 y=192 width=13 height=15 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=1144 x=308 y=0 width=18 height=18 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=1145 x=218 y=173 width=16 height=15 xoffset=-1 yoffset=5 xadvance=14 page=0 chnl=15 -char id=1146 x=124 y=175 width=17 height=15 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1147 x=306 y=401 width=14 height=12 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1148 x=22 y=46 width=20 height=17 xoffset=-1 yoffset=-1 xadvance=19 page=0 chnl=15 -char id=1149 x=162 y=173 width=17 height=15 xoffset=0 yoffset=1 xadvance=16 page=0 chnl=15 -char id=1150 x=275 y=41 width=16 height=17 xoffset=-1 yoffset=-1 xadvance=15 page=0 chnl=15 -char id=1151 x=193 y=257 width=15 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1152 x=378 y=59 width=13 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1153 x=242 y=369 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1154 x=72 y=448 width=10 height=11 xoffset=-1 yoffset=6 xadvance=8 page=0 chnl=15 -char id=1155 x=319 y=453 width=10 height=6 xoffset=-10 yoffset=1 xadvance=0 page=0 chnl=15 -char id=1156 x=481 y=448 width=9 height=5 xoffset=-7 yoffset=1 xadvance=0 page=0 chnl=15 -char id=1157 x=453 y=452 width=5 height=6 xoffset=-6 yoffset=1 xadvance=0 page=0 chnl=15 -char id=1158 x=467 y=450 width=5 height=6 xoffset=-6 yoffset=1 xadvance=0 page=0 chnl=15 -char id=1159 x=233 y=457 width=16 height=6 xoffset=-14 yoffset=1 xadvance=0 page=0 chnl=15 -char id=1160 x=73 y=0 width=26 height=20 xoffset=-18 yoffset=-1 xadvance=7 page=0 chnl=15 -char id=1161 x=0 y=0 width=24 height=24 xoffset=-17 yoffset=-3 xadvance=7 page=0 chnl=15 -char id=1162 x=45 y=0 width=13 height=21 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=1163 x=228 y=0 width=12 height=19 xoffset=0 yoffset=1 xadvance=11 page=0 chnl=15 -char id=1164 x=172 y=307 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1165 x=133 y=406 width=11 height=13 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=1166 x=156 y=355 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1167 x=182 y=207 width=11 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1168 x=357 y=154 width=10 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=15 -char id=1169 x=207 y=403 width=9 height=13 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=15 -char id=1170 x=424 y=304 width=12 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1171 x=104 y=435 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1172 x=314 y=117 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1173 x=204 y=387 width=10 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=15 -char id=1174 x=0 y=46 width=20 height=17 xoffset=-1 yoffset=2 xadvance=17 page=0 chnl=15 -char id=1175 x=72 y=263 width=16 height=14 xoffset=-1 yoffset=5 xadvance=14 page=0 chnl=15 -char id=1176 x=275 y=117 width=11 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1177 x=96 y=391 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1178 x=348 y=59 width=13 height=17 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1179 x=65 y=359 width=11 height=14 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1180 x=98 y=327 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1181 x=156 y=434 width=11 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1182 x=240 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1183 x=276 y=190 width=12 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1184 x=0 y=263 width=16 height=14 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1185 x=279 y=415 width=13 height=11 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1186 x=333 y=59 width=13 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1187 x=78 y=407 width=12 height=13 xoffset=0 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1188 x=84 y=246 width=18 height=14 xoffset=0 yoffset=2 xadvance=16 page=0 chnl=15 -char id=1189 x=230 y=417 width=15 height=11 xoffset=0 yoffset=5 xadvance=14 page=0 chnl=15 -char id=1190 x=106 y=42 width=18 height=17 xoffset=0 yoffset=2 xadvance=17 page=0 chnl=15 -char id=1191 x=465 y=238 width=16 height=14 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15 -char id=1192 x=272 y=173 width=16 height=15 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1193 x=322 y=401 width=13 height=12 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1194 x=303 y=60 width=13 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1195 x=398 y=369 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1196 x=498 y=58 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1197 x=159 y=403 width=11 height=13 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1198 x=28 y=327 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1199 x=481 y=334 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1200 x=308 y=321 width=12 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1201 x=130 y=209 width=11 height=15 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1202 x=318 y=60 width=13 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1203 x=455 y=334 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1204 x=184 y=41 width=17 height=17 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1205 x=0 y=407 width=15 height=13 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=1206 x=343 y=78 width=12 height=17 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1207 x=120 y=407 width=11 height=13 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1208 x=429 y=336 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1209 x=248 y=443 width=9 height=11 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1210 x=416 y=336 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1211 x=206 y=371 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1212 x=242 y=241 width=17 height=14 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1213 x=354 y=415 width=13 height=11 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1214 x=165 y=41 width=17 height=17 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1215 x=180 y=290 width=13 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1216 x=444 y=384 width=5 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=1217 x=44 y=43 width=19 height=17 xoffset=-1 yoffset=-1 xadvance=17 page=0 chnl=15 -char id=1218 x=200 y=173 width=16 height=15 xoffset=-1 yoffset=1 xadvance=14 page=0 chnl=15 -char id=1219 x=74 y=22 width=12 height=18 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1220 x=91 y=212 width=11 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1221 x=442 y=0 width=14 height=18 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1222 x=60 y=195 width=13 height=15 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1223 x=469 y=78 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1224 x=13 y=359 width=11 height=14 xoffset=0 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1225 x=473 y=0 width=13 height=18 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1226 x=150 y=191 width=12 height=15 xoffset=0 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1227 x=392 y=116 width=11 height=17 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1228 x=196 y=403 width=9 height=13 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1229 x=345 y=0 width=15 height=18 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1230 x=45 y=196 width=13 height=15 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1231 x=470 y=382 width=4 height=14 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15 -char id=1232 x=30 y=23 width=13 height=18 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=15 -char id=1233 x=465 y=188 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1234 x=15 y=84 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=1235 x=442 y=352 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1236 x=280 y=241 width=17 height=14 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=1237 x=38 y=422 width=17 height=11 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=1238 x=366 y=116 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1239 x=413 y=188 width=11 height=15 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1240 x=227 y=257 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1241 x=182 y=431 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1242 x=256 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=1243 x=195 y=339 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1244 x=65 y=43 width=19 height=17 xoffset=-1 yoffset=-1 xadvance=17 page=0 chnl=15 -char id=1245 x=393 y=240 width=16 height=14 xoffset=-1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1246 x=249 y=117 width=11 height=17 xoffset=0 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1247 x=120 y=391 width=10 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1248 x=156 y=339 width=11 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1249 x=117 y=343 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1250 x=187 y=155 width=12 height=16 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=15 -char id=1251 x=132 y=390 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1252 x=266 y=98 width=12 height=17 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=15 -char id=1253 x=254 y=369 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1254 x=224 y=60 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=1255 x=52 y=343 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1256 x=464 y=270 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1257 x=482 y=412 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1258 x=393 y=40 width=14 height=17 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=1259 x=39 y=343 width=11 height=14 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1260 x=120 y=80 width=13 height=17 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=1261 x=0 y=391 width=10 height=14 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1262 x=131 y=156 width=12 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=15 -char id=1263 x=184 y=117 width=11 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1264 x=140 y=98 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1265 x=93 y=119 width=11 height=17 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1266 x=28 y=103 width=12 height=17 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=1267 x=198 y=21 width=11 height=18 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 -char id=1268 x=145 y=117 width=11 height=17 xoffset=0 yoffset=-1 xadvance=11 page=0 chnl=15 -char id=1269 x=239 y=386 width=9 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1270 x=469 y=116 width=10 height=17 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1271 x=218 y=403 width=9 height=13 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=15 -char id=1272 x=240 y=60 width=14 height=17 xoffset=0 yoffset=-1 xadvance=14 page=0 chnl=15 -char id=1273 x=382 y=305 width=12 height=14 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1274 x=252 y=98 width=12 height=17 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1275 x=499 y=254 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1276 x=45 y=23 width=13 height=18 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1277 x=208 y=207 width=11 height=15 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1278 x=300 y=289 width=13 height=14 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1279 x=247 y=430 width=11 height=11 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1329 x=248 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1330 x=256 y=305 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1331 x=483 y=254 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1332 x=371 y=256 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1333 x=206 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1334 x=45 y=295 width=13 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1335 x=377 y=353 width=11 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1336 x=186 y=306 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1337 x=377 y=171 width=15 height=15 xoffset=0 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1338 x=477 y=171 width=14 height=15 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1339 x=154 y=323 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1340 x=182 y=371 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1341 x=360 y=172 width=15 height=15 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=1342 x=493 y=171 width=13 height=15 xoffset=1 yoffset=2 xadvance=14 page=0 chnl=15 -char id=1343 x=84 y=327 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1344 x=120 y=192 width=13 height=15 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1345 x=290 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1346 x=339 y=257 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1347 x=323 y=257 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1348 x=461 y=171 width=14 height=15 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1349 x=262 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1350 x=75 y=195 width=13 height=15 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1351 x=304 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1352 x=284 y=305 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1353 x=0 y=196 width=13 height=15 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1354 x=272 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1355 x=452 y=302 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1356 x=304 y=273 width=14 height=14 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1357 x=312 y=305 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1358 x=336 y=273 width=14 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1359 x=318 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1360 x=280 y=321 width=12 height=14 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15 -char id=1361 x=220 y=190 width=12 height=15 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1362 x=470 y=366 width=10 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=1363 x=435 y=254 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1364 x=0 y=311 width=13 height=14 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=1365 x=384 y=272 width=14 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1366 x=445 y=171 width=14 height=15 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=1369 x=19 y=461 width=6 height=8 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=15 -char id=1370 x=135 y=461 width=5 height=7 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=1371 x=415 y=453 width=6 height=6 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=15 -char id=1372 x=487 y=438 width=8 height=8 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=15 -char id=1373 x=371 y=453 width=7 height=6 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=15 -char id=1374 x=71 y=461 width=9 height=7 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=15 -char id=1375 x=307 y=454 width=10 height=6 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 -char id=1377 x=288 y=401 width=16 height=12 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=1378 x=420 y=205 width=10 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1379 x=15 y=196 width=13 height=15 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1380 x=178 y=190 width=12 height=15 xoffset=0 yoffset=5 xadvance=11 page=0 chnl=15 -char id=1381 x=429 y=153 width=10 height=16 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1382 x=30 y=196 width=13 height=15 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1383 x=258 y=224 width=9 height=15 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=15 -char id=1384 x=168 y=225 width=10 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1385 x=105 y=192 width=13 height=15 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 -char id=1386 x=0 y=160 width=13 height=16 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=1387 x=296 y=0 width=10 height=19 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1388 x=504 y=188 width=6 height=15 xoffset=0 yoffset=5 xadvance=4 page=0 chnl=15 -char id=1389 x=111 y=0 width=16 height=19 xoffset=0 yoffset=1 xadvance=16 page=0 chnl=15 -char id=1390 x=241 y=155 width=11 height=16 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1391 x=284 y=0 width=10 height=19 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1392 x=144 y=390 width=10 height=14 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=1393 x=228 y=155 width=11 height=16 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1394 x=360 y=189 width=12 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1395 x=441 y=153 width=10 height=16 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1396 x=117 y=157 width=12 height=16 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1397 x=504 y=205 width=6 height=15 xoffset=-2 yoffset=5 xadvance=4 page=0 chnl=15 -char id=1398 x=103 y=157 width=12 height=16 xoffset=-2 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1399 x=269 y=224 width=9 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=1400 x=108 y=448 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1401 x=341 y=224 width=8 height=15 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15 -char id=1402 x=254 y=173 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=1403 x=324 y=207 width=10 height=15 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=1404 x=208 y=431 width=11 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1405 x=156 y=447 width=10 height=11 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1406 x=214 y=0 width=12 height=19 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 -char id=1407 x=270 y=401 width=16 height=12 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=1408 x=408 y=205 width=10 height=15 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1409 x=13 y=375 width=11 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1410 x=281 y=442 width=9 height=11 xoffset=0 yoffset=5 xadvance=7 page=0 chnl=15 -char id=1411 x=147 y=0 width=16 height=19 xoffset=0 yoffset=1 xadvance=16 page=0 chnl=15 -char id=1412 x=164 y=190 width=12 height=15 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1413 x=234 y=430 width=11 height=11 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=1414 x=165 y=0 width=15 height=19 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=1415 x=403 y=135 width=14 height=16 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 -char id=1417 x=455 y=440 width=5 height=9 xoffset=0 yoffset=7 xadvance=5 page=0 chnl=15 -char id=1418 x=164 y=468 width=7 height=4 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=15 -char id=8192 x=289 y=463 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=15 -char id=8193 x=507 y=349 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=16 page=0 chnl=15 -char id=8194 x=507 y=334 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=15 -char id=8195 x=507 y=339 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=16 page=0 chnl=15 -char id=8196 x=249 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=8197 x=244 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=15 -char id=8198 x=214 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=15 -char id=8199 x=507 y=439 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=15 -char id=8200 x=507 y=424 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=15 -char id=8201 x=219 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=15 -char id=8202 x=224 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=2 page=0 chnl=15 -char id=8203 x=234 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8204 x=239 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8205 x=264 y=464 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8206 x=269 y=464 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8207 x=274 y=464 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8208 x=182 y=468 width=7 height=4 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=15 -char id=8209 x=173 y=468 width=7 height=4 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=15 -char id=8210 x=79 y=470 width=12 height=4 xoffset=-1 yoffset=9 xadvance=10 page=0 chnl=15 -char id=8211 x=121 y=470 width=10 height=4 xoffset=-1 yoffset=9 xadvance=8 page=0 chnl=15 -char id=8212 x=21 y=471 width=18 height=4 xoffset=-1 yoffset=9 xadvance=16 page=0 chnl=15 -char id=8213 x=41 y=470 width=18 height=4 xoffset=-1 yoffset=9 xadvance=16 page=0 chnl=15 -char id=8214 x=413 y=20 width=8 height=18 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8215 x=57 y=461 width=12 height=7 xoffset=-2 yoffset=13 xadvance=8 page=0 chnl=15 -char id=8216 x=142 y=461 width=5 height=7 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=8217 x=128 y=461 width=5 height=7 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=8218 x=460 y=451 width=5 height=6 xoffset=0 yoffset=12 xadvance=5 page=0 chnl=15 -char id=8219 x=149 y=461 width=5 height=7 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=8220 x=82 y=461 width=8 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8221 x=92 y=461 width=8 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8222 x=361 y=453 width=8 height=6 xoffset=0 yoffset=12 xadvance=8 page=0 chnl=15 -char id=8223 x=102 y=461 width=8 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8224 x=417 y=153 width=10 height=16 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8225 x=405 y=153 width=10 height=16 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8226 x=10 y=461 width=7 height=8 xoffset=1 yoffset=6 xadvance=9 page=0 chnl=15 -char id=8227 x=445 y=441 width=8 height=9 xoffset=1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=8228 x=200 y=465 width=5 height=4 xoffset=0 yoffset=12 xadvance=5 page=0 chnl=15 -char id=8229 x=133 y=470 width=10 height=4 xoffset=0 yoffset=12 xadvance=11 page=0 chnl=15 -char id=8230 x=61 y=470 width=16 height=4 xoffset=0 yoffset=12 xadvance=16 page=0 chnl=15 -char id=8231 x=7 y=471 width=5 height=5 xoffset=0 yoffset=7 xadvance=5 page=0 chnl=15 -char id=8232 x=507 y=359 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8233 x=229 y=465 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8234 x=254 y=464 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8235 x=507 y=434 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8236 x=507 y=429 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8237 x=279 y=464 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8238 x=507 y=354 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8239 x=507 y=344 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=15 -char id=8240 x=423 y=222 width=23 height=14 xoffset=-1 yoffset=2 xadvance=21 page=0 chnl=15 -char id=8241 x=49 y=178 width=29 height=15 xoffset=-1 yoffset=2 xadvance=28 page=0 chnl=15 -char id=8242 x=407 y=453 width=6 height=6 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15 -char id=8243 x=331 y=453 width=8 height=6 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=8244 x=294 y=454 width=11 height=6 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8245 x=431 y=453 width=6 height=6 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15 -char id=8246 x=351 y=453 width=8 height=6 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=8247 x=281 y=455 width=11 height=6 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8248 x=341 y=453 width=8 height=6 xoffset=-1 yoffset=14 xadvance=5 page=0 chnl=15 -char id=8249 x=420 y=441 width=6 height=10 xoffset=0 yoffset=6 xadvance=6 page=0 chnl=15 -char id=8250 x=402 y=441 width=7 height=10 xoffset=0 yoffset=6 xadvance=6 page=0 chnl=15 -char id=8251 x=45 y=311 width=13 height=14 xoffset=0 yoffset=2 xadvance=13 page=0 chnl=15 -char id=8252 x=351 y=385 width=8 height=14 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8253 x=250 y=385 width=9 height=14 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 -char id=8254 x=93 y=470 width=12 height=4 xoffset=-2 yoffset=2 xadvance=8 page=0 chnl=15 -char id=8255 x=214 y=457 width=17 height=6 xoffset=-2 yoffset=14 xadvance=13 page=0 chnl=15 -char id=8256 x=176 y=460 width=17 height=6 xoffset=-2 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=8257 x=372 y=441 width=8 height=10 xoffset=-2 yoffset=10 xadvance=4 page=0 chnl=15 -char id=8258 x=329 y=136 width=18 height=16 xoffset=-1 yoffset=1 xadvance=16 page=0 chnl=15 -char id=8259 x=492 y=448 width=8 height=5 xoffset=0 yoffset=7 xadvance=8 page=0 chnl=15 -char id=8260 x=117 y=375 width=11 height=14 xoffset=-4 yoffset=2 xadvance=3 page=0 chnl=15 -char id=8261 x=503 y=0 width=6 height=18 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 -char id=8262 x=453 y=20 width=6 height=18 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 -char id=8263 x=223 y=241 width=17 height=14 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=8264 x=448 y=318 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=8265 x=462 y=318 width=12 height=14 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=15 -char id=8266 x=172 y=403 width=10 height=13 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=15 -char id=8267 x=280 y=155 width=11 height=16 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15 -char id=8268 x=497 y=437 width=8 height=8 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=15 -char id=8269 x=477 y=438 width=8 height=8 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=15 -char id=8270 x=325 y=441 width=10 height=10 xoffset=-1 yoffset=7 xadvance=8 page=0 chnl=15 -char id=8271 x=263 y=401 width=5 height=13 xoffset=1 yoffset=5 xadvance=5 page=0 chnl=15 -char id=8272 x=26 y=0 width=17 height=21 xoffset=-2 yoffset=-1 xadvance=13 page=0 chnl=15 -char id=8273 x=389 y=20 width=10 height=18 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=15 -char id=8274 x=280 y=224 width=9 height=15 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=15 -char id=8275 x=156 y=460 width=18 height=6 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=8276 x=195 y=457 width=17 height=6 xoffset=-2 yoffset=14 xadvance=13 page=0 chnl=15 -char id=8277 x=435 y=400 width=11 height=12 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=15 -char id=8278 x=361 y=441 width=9 height=10 xoffset=0 yoffset=4 xadvance=9 page=0 chnl=15 -char id=8279 x=251 y=456 width=13 height=6 xoffset=-1 yoffset=2 xadvance=11 page=0 chnl=15 -char id=8280 x=26 y=435 width=11 height=11 xoffset=1 yoffset=4 xadvance=13 page=0 chnl=15 -char id=8281 x=39 y=435 width=11 height=11 xoffset=1 yoffset=4 xadvance=13 page=0 chnl=15 -char id=8282 x=451 y=384 width=5 height=14 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15 -char id=8283 x=198 y=0 width=14 height=19 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=15 -char id=8284 x=176 y=258 width=15 height=14 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=8285 x=256 y=401 width=5 height=13 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=15 -char id=8286 x=249 y=402 width=5 height=13 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=15 -char id=8287 x=294 y=462 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=15 -char id=8288 x=299 y=462 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8289 x=304 y=462 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8290 x=309 y=462 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8291 x=314 y=462 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8292 x=319 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8298 x=324 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8299 x=329 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8300 x=334 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8301 x=339 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8302 x=344 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 -char id=8303 x=349 y=461 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=0 page=0 chnl=15 diff --git a/examples/text/unicode/resources/dejavu.png b/examples/text/unicode/resources/dejavu.png deleted file mode 100644 index 77fe4b3..0000000 Binary files a/examples/text/unicode/resources/dejavu.png and /dev/null differ diff --git a/examples/text/unicode/resources/noto_cjk.fnt b/examples/text/unicode/resources/noto_cjk.fnt deleted file mode 100644 index f112ef8..0000000 --- a/examples/text/unicode/resources/noto_cjk.fnt +++ /dev/null @@ -1,580 +0,0 @@ -info face="Noto Serif CJK JP" size=-16 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2 outline=1 -common lineHeight=23 base=18 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 -page id=0 file="noto_cjk.png" -chars count=576 -char id=32 x=507 y=185 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=15 -char id=33 x=449 y=285 width=5 height=14 xoffset=0 yoffset=5 xadvance=5 page=0 chnl=15 -char id=34 x=393 y=315 width=8 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=35 x=285 y=287 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=36 x=500 y=61 width=10 height=18 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=37 x=52 y=257 width=15 height=15 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15 -char id=38 x=495 y=268 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=39 x=413 y=315 width=5 height=8 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=15 -char id=40 x=339 y=21 width=7 height=19 xoffset=0 yoffset=4 xadvance=6 page=0 chnl=15 -char id=41 x=330 y=21 width=7 height=19 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=42 x=321 y=317 width=10 height=9 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=15 -char id=43 x=26 y=322 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15 -char id=44 x=353 y=316 width=6 height=9 xoffset=-1 yoffset=15 xadvance=5 page=0 chnl=15 -char id=45 x=136 y=334 width=7 height=4 xoffset=-1 yoffset=12 xadvance=5 page=0 chnl=15 -char id=46 x=109 y=334 width=5 height=5 xoffset=0 yoffset=14 xadvance=5 page=0 chnl=15 -char id=47 x=500 y=81 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=48 x=406 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=49 x=418 y=286 width=9 height=14 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15 -char id=50 x=394 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=51 x=382 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=52 x=272 y=287 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=53 x=370 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=54 x=358 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=55 x=346 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=56 x=334 y=287 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=57 x=322 y=287 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=58 x=502 y=300 width=5 height=11 xoffset=0 yoffset=8 xadvance=5 page=0 chnl=15 -char id=59 x=190 y=238 width=6 height=16 xoffset=-1 yoffset=8 xadvance=5 page=0 chnl=15 -char id=60 x=39 y=322 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15 -char id=61 x=440 y=315 width=11 height=7 xoffset=-1 yoffset=9 xadvance=9 page=0 chnl=15 -char id=62 x=78 y=321 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15 -char id=63 x=460 y=252 width=7 height=15 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15 -char id=64 x=72 y=221 width=16 height=16 xoffset=-1 yoffset=6 xadvance=14 page=0 chnl=15 -char id=65 x=447 y=269 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=66 x=175 y=289 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=67 x=75 y=290 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=68 x=415 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=69 x=119 y=290 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=70 x=105 y=290 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=71 x=431 y=269 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=72 x=302 y=271 width=15 height=14 xoffset=-1 yoffset=5 xadvance=14 page=0 chnl=15 -char id=73 x=439 y=285 width=8 height=14 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15 -char id=74 x=268 y=200 width=9 height=17 xoffset=-2 yoffset=5 xadvance=6 page=0 chnl=15 -char id=75 x=367 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=76 x=203 y=289 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=77 x=158 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=78 x=285 y=271 width=15 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=79 x=479 y=269 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=80 x=189 y=289 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=81 x=209 y=142 width=14 height=18 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=82 x=30 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=83 x=259 y=287 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=84 x=45 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=85 x=335 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=86 x=399 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=87 x=485 y=252 width=19 height=14 xoffset=-1 yoffset=5 xadvance=17 page=0 chnl=15 -char id=88 x=0 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=89 x=15 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=90 x=217 y=287 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15 -char id=91 x=8 y=164 width=6 height=18 xoffset=0 yoffset=4 xadvance=5 page=0 chnl=15 -char id=92 x=497 y=141 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=93 x=0 y=164 width=6 height=18 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15 -char id=94 x=465 y=313 width=9 height=7 xoffset=0 yoffset=8 xadvance=9 page=0 chnl=15 -char id=95 x=145 y=334 width=11 height=3 xoffset=-1 yoffset=17 xadvance=9 page=0 chnl=15 -char id=96 x=74 y=335 width=6 height=6 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15 -char id=97 x=13 y=322 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15 -char id=98 x=398 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=99 x=129 y=321 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15 -char id=100 x=426 y=217 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=101 x=117 y=321 width=10 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15 -char id=102 x=140 y=238 width=10 height=16 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15 -char id=103 x=52 y=239 width=11 height=16 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15 -char id=104 x=440 y=217 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=105 x=469 y=252 width=7 height=15 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15 -char id=106 x=95 y=0 width=8 height=20 xoffset=-3 yoffset=4 xadvance=5 page=0 chnl=15 -char id=107 x=412 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=108 x=451 y=252 width=7 height=15 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15 -char id=109 x=386 y=302 width=18 height=11 xoffset=-1 yoffset=8 xadvance=16 page=0 chnl=15 -char id=110 x=488 y=300 width=12 height=11 xoffset=-1 yoffset=8 xadvance=11 page=0 chnl=15 -char id=111 x=91 y=321 width=11 height=11 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15 -char id=112 x=300 y=218 width=12 height=16 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15 -char id=113 x=286 y=219 width=12 height=16 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15 -char id=114 x=141 y=321 width=10 height=11 xoffset=-1 yoffset=8 xadvance=7 page=0 chnl=15 -char id=115 x=165 y=320 width=9 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15 -char id=116 x=429 y=286 width=8 height=14 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15 -char id=117 x=474 y=300 width=12 height=11 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15 -char id=118 x=0 y=322 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15 -char id=119 x=424 y=302 width=16 height=11 xoffset=-1 yoffset=8 xadvance=13 page=0 chnl=15 -char id=120 x=104 y=321 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15 -char id=121 x=342 y=218 width=12 height=16 xoffset=-2 yoffset=8 xadvance=9 page=0 chnl=15 -char id=122 x=153 y=320 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15 -char id=123 x=467 y=141 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=124 x=111 y=0 width=4 height=20 xoffset=0 yoffset=4 xadvance=4 page=0 chnl=15 -char id=125 x=457 y=141 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=126 x=27 y=335 width=11 height=6 xoffset=-1 yoffset=9 xadvance=9 page=0 chnl=15 -char id=160 x=507 y=180 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=15 -char id=161 x=478 y=252 width=5 height=15 xoffset=0 yoffset=8 xadvance=5 page=0 chnl=15 -char id=162 x=430 y=252 width=10 height=15 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=163 x=310 y=287 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15 -char id=164 x=52 y=322 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15 -char id=165 x=201 y=305 width=12 height=13 xoffset=-2 yoffset=6 xadvance=9 page=0 chnl=15 -char id=166 x=105 y=0 width=4 height=20 xoffset=0 yoffset=4 xadvance=4 page=0 chnl=15 -char id=167 x=244 y=200 width=10 height=17 xoffset=3 yoffset=4 xadvance=16 page=0 chnl=15 -char id=168 x=116 y=334 width=9 height=4 xoffset=-1 yoffset=5 xadvance=7 page=0 chnl=15 -char id=169 x=251 y=271 width=15 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15 -char id=170 x=383 y=316 width=8 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=171 x=248 y=317 width=10 height=10 xoffset=-1 yoffset=9 xadvance=8 page=0 chnl=15 -char id=172 x=427 y=315 width=11 height=7 xoffset=-1 yoffset=10 xadvance=9 page=0 chnl=15 -char id=173 x=127 y=334 width=7 height=4 xoffset=-1 yoffset=12 xadvance=5 page=0 chnl=15 -char id=174 x=236 y=317 width=10 height=10 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=15 -char id=175 x=158 y=333 width=7 height=3 xoffset=0 yoffset=6 xadvance=7 page=0 chnl=15 -char id=176 x=486 y=313 width=7 height=7 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15 -char id=177 x=154 y=256 width=15 height=15 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=178 x=270 y=317 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=179 x=260 y=317 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=180 x=58 y=335 width=6 height=6 xoffset=1 yoffset=4 xadvance=7 page=0 chnl=15 -char id=181 x=26 y=240 width=11 height=16 xoffset=0 yoffset=7 xadvance=10 page=0 chnl=15 -char id=182 x=216 y=200 width=12 height=17 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15 -char id=183 x=102 y=334 width=5 height=5 xoffset=0 yoffset=10 xadvance=5 page=0 chnl=15 -char id=184 x=504 y=313 width=6 height=7 xoffset=0 yoffset=16 xadvance=7 page=0 chnl=15 -char id=185 x=280 y=317 width=7 height=10 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15 -char id=186 x=403 y=315 width=8 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15 -char id=187 x=224 y=320 width=10 height=10 xoffset=-1 yoffset=9 xadvance=8 page=0 chnl=15 -char id=188 x=137 y=256 width=15 height=15 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15 -char id=189 x=375 y=236 width=16 height=15 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15 -char id=190 x=120 y=256 width=15 height=15 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15 -char id=191 x=442 y=252 width=7 height=15 xoffset=0 yoffset=8 xadvance=7 page=0 chnl=15 -char id=192 x=273 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 -char id=193 x=353 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 -char id=194 x=48 y=202 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=195 x=337 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 -char id=196 x=0 y=203 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=197 x=225 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 -char id=198 x=20 y=275 width=18 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=199 x=400 y=141 width=13 height=18 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=200 x=443 y=141 width=12 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=201 x=498 y=101 width=12 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=202 x=429 y=141 width=12 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15 -char id=203 x=202 y=200 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15 -char id=204 x=502 y=121 width=8 height=18 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15 -char id=205 x=477 y=141 width=8 height=18 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15 -char id=206 x=487 y=141 width=8 height=18 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15 -char id=207 x=279 y=200 width=8 height=17 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15 -char id=208 x=319 y=271 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15 -char id=209 x=142 y=143 width=15 height=18 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=210 x=305 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 -char id=211 x=369 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 -char id=212 x=491 y=180 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=213 x=475 y=180 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=214 x=96 y=201 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15 -char id=215 x=173 y=305 width=12 height=13 xoffset=2 yoffset=6 xadvance=16 page=0 chnl=15 -char id=216 x=209 y=219 width=14 height=16 xoffset=-1 yoffset=4 xadvance=12 page=0 chnl=15 -char id=217 x=241 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=218 x=257 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15 -char id=219 x=64 y=202 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=220 x=16 y=203 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15 -char id=221 x=385 y=141 width=13 height=18 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15 -char id=222 x=231 y=287 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15 -char id=223 x=299 y=254 width=12 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=224 x=13 y=240 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=225 x=0 y=240 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=226 x=493 y=217 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=227 x=367 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15 -char id=228 x=341 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15 -char id=229 x=480 y=217 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=230 x=442 y=301 width=15 height=11 xoffset=-1 yoffset=8 xadvance=14 page=0 chnl=15 -char id=231 x=406 y=253 width=10 height=15 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15 -char id=232 x=116 y=238 width=10 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=233 x=128 y=238 width=10 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=234 x=104 y=239 width=10 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=235 x=418 y=253 width=10 height=15 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15 -char id=236 x=172 y=238 width=7 height=16 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15 -char id=237 x=181 y=238 width=7 height=16 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15 -char id=238 x=163 y=238 width=7 height=16 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15 -char id=239 x=501 y=235 width=9 height=15 xoffset=-2 yoffset=4 xadvance=5 page=0 chnl=15 -char id=240 x=454 y=217 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15 -char id=241 x=327 y=253 width=12 height=15 xoffset=-1 yoffset=4 xadvance=11 page=0 chnl=15 -char id=242 x=91 y=239 width=11 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=243 x=78 y=239 width=11 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=244 x=65 y=239 width=11 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=245 x=393 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=246 x=380 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=247 x=233 y=271 width=16 height=14 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=248 x=215 y=305 width=11 height=13 xoffset=-1 yoffset=7 xadvance=10 page=0 chnl=15 -char id=249 x=384 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=250 x=356 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=251 x=314 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=252 x=313 y=254 width=12 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15 -char id=253 x=0 y=0 width=12 height=21 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=15 -char id=254 x=14 y=0 width=11 height=21 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15 -char id=255 x=81 y=0 width=12 height=20 xoffset=-2 yoffset=4 xadvance=9 page=0 chnl=15 -char id=8220 x=361 y=316 width=9 height=8 xoffset=-1 yoffset=4 xadvance=7 page=0 chnl=15 -char id=8222 x=372 y=316 width=9 height=8 xoffset=-1 yoffset=14 xadvance=7 page=0 chnl=15 -char id=9829 x=18 y=222 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12288 x=507 y=141 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=16 page=0 chnl=15 -char id=12290 x=476 y=313 width=8 height=7 xoffset=-1 yoffset=14 xadvance=16 page=0 chnl=15 -char id=12353 x=147 y=289 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12354 x=73 y=183 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12355 x=459 y=300 width=13 height=11 xoffset=1 yoffset=9 xadvance=16 page=0 chnl=15 -char id=12356 x=483 y=235 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12357 x=298 y=287 width=10 height=14 xoffset=3 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12358 x=415 y=141 width=12 height=18 xoffset=2 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12359 x=187 y=305 width=12 height=13 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12360 x=409 y=180 width=15 height=17 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12361 x=53 y=307 width=14 height=13 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12362 x=108 y=220 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12363 x=271 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12364 x=0 y=184 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12365 x=32 y=202 width=14 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12366 x=72 y=143 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12367 x=152 y=238 width=9 height=16 xoffset=3 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12368 x=256 y=219 width=13 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12369 x=375 y=181 width=15 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12370 x=340 y=122 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12371 x=284 y=254 width=13 height=15 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12372 x=426 y=180 width=15 height=17 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12373 x=142 y=201 width=13 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12374 x=57 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12375 x=443 y=180 width=14 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12376 x=112 y=201 width=13 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12377 x=235 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12378 x=209 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12379 x=309 y=200 width=18 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12380 x=137 y=163 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12381 x=358 y=181 width=15 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12382 x=396 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12383 x=217 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12384 x=277 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12385 x=324 y=181 width=15 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12386 x=430 y=121 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12387 x=195 y=320 width=13 height=10 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=15 -char id=12388 x=267 y=303 width=17 height=12 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12389 x=218 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12390 x=411 y=236 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12391 x=338 y=236 width=17 height=15 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12392 x=370 y=218 width=12 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12393 x=392 y=181 width=15 height=17 xoffset=2 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12394 x=477 y=199 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12395 x=160 y=220 width=15 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12396 x=447 y=235 width=16 height=15 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12397 x=491 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12398 x=465 y=235 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12399 x=36 y=221 width=16 height=16 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12400 x=479 y=101 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12401 x=247 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12402 x=495 y=199 width=15 height=16 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12403 x=36 y=144 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12404 x=253 y=181 width=16 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12405 x=348 y=200 width=17 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12406 x=289 y=200 width=18 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12407 x=386 y=200 width=17 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12408 x=228 y=303 width=18 height=12 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12409 x=139 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12410 x=456 y=285 width=17 height=13 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12411 x=55 y=183 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12412 x=171 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12413 x=95 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12414 x=193 y=219 width=14 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12415 x=405 y=200 width=16 height=16 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12416 x=367 y=200 width=17 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12417 x=90 y=221 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12418 x=328 y=218 width=12 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12419 x=383 y=270 width=14 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12420 x=472 y=161 width=17 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12421 x=159 y=305 width=12 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12422 x=109 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12423 x=348 y=302 width=11 height=12 xoffset=3 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12424 x=241 y=219 width=13 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12425 x=127 y=201 width=13 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12426 x=500 y=41 width=10 height=18 xoffset=3 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12427 x=188 y=256 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12428 x=177 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12429 x=177 y=220 width=14 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12430 x=351 y=270 width=14 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12431 x=163 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12432 x=393 y=236 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12433 x=181 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12434 x=143 y=220 width=15 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12435 x=54 y=221 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12436 x=289 y=142 width=14 height=18 xoffset=2 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12437 x=463 y=269 width=14 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12438 x=101 y=306 width=13 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12441 x=40 y=335 width=7 height=6 xoffset=-6 yoffset=3 xadvance=0 page=0 chnl=15 -char id=12442 x=49 y=335 width=7 height=6 xoffset=-5 yoffset=3 xadvance=0 page=0 chnl=15 -char id=12443 x=495 y=313 width=7 height=7 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12444 x=0 y=335 width=7 height=7 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12445 x=333 y=317 width=8 height=9 xoffset=4 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12446 x=65 y=322 width=11 height=11 xoffset=4 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12447 x=193 y=142 width=14 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12448 x=453 y=314 width=10 height=7 xoffset=3 yoffset=9 xadvance=16 page=0 chnl=15 -char id=12449 x=334 y=303 width=12 height=12 xoffset=2 yoffset=9 xadvance=16 page=0 chnl=15 -char id=12450 x=126 y=220 width=15 height=16 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12451 x=374 y=302 width=10 height=12 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12452 x=157 y=201 width=13 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12453 x=161 y=289 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12454 x=459 y=180 width=14 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12455 x=289 y=317 width=14 height=9 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=15 -char id=12456 x=494 y=285 width=16 height=13 xoffset=0 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12457 x=116 y=306 width=13 height=13 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12458 x=459 y=199 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12459 x=307 y=181 width=15 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12460 x=453 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12461 x=289 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12462 x=285 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12463 x=80 y=202 width=14 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12464 x=448 y=121 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12465 x=0 y=222 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12466 x=19 y=124 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12467 x=304 y=303 width=14 height=12 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12468 x=429 y=235 width=16 height=15 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12469 x=199 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12470 x=160 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12471 x=103 y=257 width=15 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12472 x=341 y=181 width=15 height=17 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12473 x=69 y=257 width=15 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12474 x=145 y=182 width=16 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12475 x=86 y=257 width=15 height=15 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12476 x=278 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12477 x=204 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12478 x=322 y=122 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12479 x=321 y=142 width=14 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12480 x=38 y=124 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12481 x=127 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12482 x=434 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12483 x=320 y=303 width=12 height=12 xoffset=2 yoffset=9 xadvance=16 page=0 chnl=15 -char id=12484 x=252 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12485 x=266 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12486 x=441 y=199 width=16 height=16 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12487 x=228 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12488 x=256 y=200 width=10 height=17 xoffset=4 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12489 x=230 y=200 width=12 height=17 xoffset=3 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12490 x=91 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12491 x=406 y=302 width=16 height=11 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12492 x=35 y=258 width=15 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12493 x=484 y=121 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12494 x=90 y=290 width=13 height=14 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12495 x=176 y=320 width=17 height=10 xoffset=-1 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12496 x=196 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12497 x=177 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12498 x=60 y=290 width=13 height=14 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12499 x=171 y=256 width=15 height=15 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12500 x=0 y=258 width=16 height=15 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12501 x=236 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12502 x=18 y=144 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12503 x=90 y=143 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12504 x=248 y=303 width=17 height=12 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12505 x=120 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12506 x=475 y=285 width=17 height=13 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12507 x=357 y=236 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12508 x=415 y=161 width=17 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12509 x=37 y=183 width=16 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12510 x=286 y=303 width=16 height=12 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12511 x=354 y=253 width=11 height=15 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12512 x=18 y=258 width=15 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12513 x=268 y=254 width=14 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12514 x=215 y=271 width=16 height=14 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12515 x=131 y=306 width=12 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12516 x=423 y=199 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12517 x=305 y=317 width=14 height=9 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=15 -char id=12518 x=0 y=307 width=16 height=13 xoffset=0 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12519 x=210 y=320 width=12 height=10 xoffset=2 yoffset=9 xadvance=16 page=0 chnl=15 -char id=12520 x=85 y=306 width=14 height=13 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12521 x=225 y=219 width=14 height=16 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12522 x=39 y=239 width=11 height=16 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12523 x=0 y=275 width=18 height=14 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12524 x=36 y=307 width=15 height=13 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12525 x=69 y=306 width=14 height=13 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12526 x=145 y=305 width=12 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12527 x=220 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12528 x=19 y=183 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15 -char id=12529 x=18 y=307 width=16 height=13 xoffset=0 yoffset=6 xadvance=16 page=0 chnl=15 -char id=12530 x=271 y=219 width=13 height=16 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12531 x=268 y=271 width=15 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12532 x=304 y=122 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12533 x=133 y=289 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12534 x=245 y=287 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15 -char id=12535 x=190 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12536 x=140 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12537 x=329 y=200 width=17 height=16 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12538 x=54 y=144 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=12539 x=66 y=335 width=6 height=6 xoffset=5 yoffset=10 xadvance=16 page=0 chnl=15 -char id=12540 x=9 y=335 width=16 height=6 xoffset=0 yoffset=10 xadvance=16 page=0 chnl=15 -char id=12541 x=343 y=317 width=8 height=9 xoffset=4 yoffset=8 xadvance=16 page=0 chnl=15 -char id=12542 x=361 y=302 width=11 height=12 xoffset=4 yoffset=5 xadvance=16 page=0 chnl=15 -char id=12543 x=172 y=201 width=13 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=19968 x=82 y=334 width=18 height=5 xoffset=-1 yoffset=8 xadvance=16 page=0 chnl=15 -char id=19975 x=217 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15 -char id=19979 x=120 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=19981 x=100 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20037 x=80 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20096 x=60 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20102 x=394 y=121 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20107 x=40 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20108 x=60 y=274 width=18 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15 -char id=20154 x=20 y=104 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20260 x=0 y=104 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20307 x=480 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20316 x=320 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20320 x=340 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20663 x=320 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20814 x=120 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20837 x=80 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20853 x=60 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20891 x=40 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20986 x=0 y=144 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=20999 x=480 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21040 x=460 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21147 x=133 y=123 width=17 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21151 x=440 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21315 x=420 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21507 x=377 y=162 width=17 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21527 x=152 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21534 x=400 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=21705 x=380 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=22622 x=360 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=22825 x=340 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=22833 x=260 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=22836 x=220 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=22909 x=160 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=23376 x=140 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=23398 x=120 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=23544 x=80 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=23558 x=60 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24120 x=40 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24180 x=117 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15 -char id=24320 x=20 y=44 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24433 x=0 y=44 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24471 x=469 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24515 x=16 y=164 width=19 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24605 x=197 y=162 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=24651 x=357 y=162 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=25105 x=449 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26080 x=409 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26082 x=369 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26085 x=187 y=200 width=13 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 -char id=26131 x=457 y=0 width=17 height=19 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26178 x=0 y=124 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26368 x=440 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26377 x=420 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26408 x=400 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=26543 x=380 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=27493 x=360 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=27515 x=340 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=27714 x=320 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=27835 x=300 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=27963 x=280 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=28937 x=260 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=29483 x=240 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=29503 x=220 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=29627 x=200 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=29702 x=157 y=163 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=29827 x=180 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=30002 x=159 y=142 width=15 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=30045 x=460 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=30693 x=440 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=31119 x=420 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=31169 x=348 y=21 width=19 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=31348 x=400 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32299 x=380 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32368 x=360 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32705 x=340 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32769 x=257 y=162 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32773 x=300 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32780 x=280 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32988 x=260 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=32993 x=240 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=33021 x=220 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=33853 x=200 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=34382 x=180 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=34678 x=160 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=34892 x=140 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=35265 x=120 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=35328 x=100 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36208 x=80 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36335 x=60 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36523 x=40 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36817 x=20 y=84 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36820 x=0 y=84 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36861 x=480 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36941 x=460 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=36965 x=440 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=37326 x=420 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=38590 x=400 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=38750 x=380 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=39034 x=360 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=39118 x=300 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=39135 x=280 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=39340 x=260 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=39532 x=240 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=39543 x=220 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=40575 x=200 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=40614 x=180 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15 -char id=44040 x=160 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44049 x=357 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44057 x=140 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44060 x=19 y=23 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44163 x=145 y=21 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44221 x=412 y=121 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44256 x=238 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=44397 x=237 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44536 x=80 y=274 width=18 height=14 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15 -char id=44544 x=100 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=44592 x=282 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45033 x=466 y=121 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45149 x=237 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=45208 x=437 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45209 x=0 y=23 width=17 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45212 x=20 y=64 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45216 x=0 y=64 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45320 x=198 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45328 x=176 y=142 width=15 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45397 x=495 y=0 width=15 height=19 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=45576 x=297 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=45716 x=317 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=45720 x=337 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=45768 x=266 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=45796 x=27 y=0 width=18 height=20 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=46020 x=40 y=275 width=18 height=14 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15 -char id=46024 x=117 y=163 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=46160 x=320 y=42 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=46301 x=300 y=42 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=46384 x=257 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=46972 x=197 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=46976 x=280 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47000 x=163 y=21 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47196 x=258 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=47336 x=240 y=42 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=47476 x=298 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=47484 x=97 y=163 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=47532 x=65 y=0 width=14 height=20 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 -char id=47560 x=277 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47564 x=200 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47568 x=180 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47588 x=127 y=21 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47673 x=181 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=47784 x=318 y=236 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=48148 x=297 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=48152 x=317 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=48373 x=217 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49373 x=376 y=121 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49436 x=73 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49464 x=55 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49688 x=377 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49845 x=397 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49884 x=125 y=143 width=15 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=49892 x=358 y=122 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50420 x=100 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50500 x=417 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50504 x=114 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50506 x=460 y=101 width=17 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50508 x=76 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50612 x=215 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50631 x=249 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50640 x=47 y=0 width=16 height=20 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=50728 x=77 y=163 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=50836 x=198 y=237 width=18 height=15 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15 -char id=50857 x=57 y=164 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=50948 x=37 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=50976 x=489 y=21 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=51012 x=37 y=164 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 -char id=51060 x=298 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=51080 x=91 y=22 width=16 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=51088 x=337 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=51228 x=109 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=51460 x=429 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=51648 x=232 y=21 width=15 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=51652 x=108 y=143 width=15 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=52380 x=476 y=0 width=17 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=52840 x=314 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15 -char id=54032 x=389 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=54532 x=100 y=274 width=18 height=14 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15 -char id=54616 x=177 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15 -char id=54620 x=157 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=54988 x=137 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15 -char id=65292 x=420 y=315 width=5 height=8 xoffset=0 yoffset=15 xadvance=16 page=0 chnl=15 -char id=65311 x=467 y=217 width=11 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15 diff --git a/examples/text/unicode/resources/noto_cjk.png b/examples/text/unicode/resources/noto_cjk.png deleted file mode 100644 index d3f7b6f..0000000 Binary files a/examples/text/unicode/resources/noto_cjk.png and /dev/null differ diff --git a/examples/text/unicode/resources/symbola.fnt b/examples/text/unicode/resources/symbola.fnt deleted file mode 100644 index 5a39fcd..0000000 --- a/examples/text/unicode/resources/symbola.fnt +++ /dev/null @@ -1,191 +0,0 @@ -info face="Symbola" size=-64 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2 outline=2 -common lineHeight=81 base=59 scaleW=1024 scaleH=1024 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 -page id=0 file="symbola.png" -chars count=187 -char id=9749 x=135 y=333 width=63 height=61 xoffset=1 yoffset=9 xadvance=65 page=0 chnl=15 -char id=9752 x=366 y=396 width=57 height=59 xoffset=0 yoffset=10 xadvance=58 page=0 chnl=15 -char id=9760 x=257 y=0 width=46 height=68 xoffset=0 yoffset=7 xadvance=47 page=0 chnl=15 -char id=9785 x=61 y=579 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=9786 x=183 y=578 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=10083 x=984 y=200 width=35 height=50 xoffset=1 yoffset=12 xadvance=37 page=0 chnl=15 -char id=10084 x=266 y=697 width=58 height=44 xoffset=1 yoffset=15 xadvance=60 page=0 chnl=15 -char id=127744 x=736 y=266 width=40 height=63 xoffset=4 yoffset=10 xadvance=48 page=0 chnl=15 -char id=127789 x=401 y=637 width=64 height=56 xoffset=0 yoffset=14 xadvance=64 page=0 chnl=15 -char id=127790 x=697 y=331 width=62 height=60 xoffset=1 yoffset=10 xadvance=64 page=0 chnl=15 -char id=127791 x=0 y=699 width=64 height=51 xoffset=0 yoffset=17 xadvance=64 page=0 chnl=15 -char id=127792 x=456 y=202 width=64 height=63 xoffset=0 yoffset=9 xadvance=64 page=0 chnl=15 -char id=127798 x=523 y=695 width=58 height=35 xoffset=3 yoffset=27 xadvance=64 page=0 chnl=15 -char id=127805 x=825 y=330 width=60 height=60 xoffset=0 yoffset=11 xadvance=60 page=0 chnl=15 -char id=127806 x=259 y=268 width=60 height=63 xoffset=0 yoffset=10 xadvance=60 page=0 chnl=15 -char id=127807 x=322 y=333 width=59 height=61 xoffset=0 yoffset=10 xadvance=60 page=0 chnl=15 -char id=127808 x=0 y=269 width=63 height=63 xoffset=0 yoffset=9 xadvance=63 page=0 chnl=15 -char id=127811 x=305 y=396 width=59 height=59 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=127812 x=696 y=0 width=64 height=66 xoffset=2 yoffset=8 xadvance=68 page=0 chnl=15 -char id=127813 x=61 y=397 width=58 height=60 xoffset=0 yoffset=11 xadvance=58 page=0 chnl=15 -char id=127814 x=946 y=265 width=61 height=62 xoffset=0 yoffset=9 xadvance=61 page=0 chnl=15 -char id=127815 x=584 y=635 width=56 height=56 xoffset=0 yoffset=12 xadvance=56 page=0 chnl=15 -char id=127827 x=121 y=397 width=58 height=60 xoffset=0 yoffset=10 xadvance=58 page=0 chnl=15 -char id=127828 x=0 y=334 width=68 height=61 xoffset=0 yoffset=10 xadvance=68 page=0 chnl=15 -char id=127829 x=68 y=70 width=65 height=65 xoffset=0 yoffset=8 xadvance=65 page=0 chnl=15 -char id=127830 x=737 y=135 width=59 height=64 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=127831 x=560 y=0 width=66 height=66 xoffset=0 yoffset=8 xadvance=66 page=0 chnl=15 -char id=127832 x=135 y=70 width=65 height=65 xoffset=0 yoffset=8 xadvance=65 page=0 chnl=15 -char id=127837 x=630 y=331 width=65 height=60 xoffset=0 yoffset=13 xadvance=65 page=0 chnl=15 -char id=127838 x=628 y=0 width=66 height=66 xoffset=0 yoffset=8 xadvance=66 page=0 chnl=15 -char id=127839 x=566 y=267 width=59 height=63 xoffset=0 yoffset=9 xadvance=59 page=0 chnl=15 -char id=127840 x=562 y=332 width=66 height=60 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15 -char id=127841 x=798 y=135 width=57 height=64 xoffset=0 yoffset=9 xadvance=57 page=0 chnl=15 -char id=127842 x=467 y=637 width=57 height=56 xoffset=0 yoffset=13 xadvance=57 page=0 chnl=15 -char id=127845 x=213 y=137 width=65 height=64 xoffset=0 yoffset=9 xadvance=65 page=0 chnl=15 -char id=127846 x=950 y=67 width=34 height=65 xoffset=0 yoffset=8 xadvance=34 page=0 chnl=15 -char id=127850 x=522 y=202 width=64 height=63 xoffset=0 yoffset=9 xadvance=64 page=0 chnl=15 -char id=127851 x=544 y=135 width=64 height=64 xoffset=0 yoffset=9 xadvance=65 page=0 chnl=15 -char id=127855 x=440 y=333 width=49 height=61 xoffset=0 yoffset=10 xadvance=49 page=0 chnl=15 -char id=127856 x=207 y=638 width=64 height=57 xoffset=0 yoffset=11 xadvance=64 page=0 chnl=15 -char id=127857 x=710 y=633 width=65 height=55 xoffset=0 yoffset=13 xadvance=66 page=0 chnl=15 -char id=127858 x=237 y=396 width=66 height=59 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15 -char id=127859 x=195 y=268 width=62 height=63 xoffset=1 yoffset=9 xadvance=64 page=0 chnl=15 -char id=127861 x=77 y=0 width=65 height=68 xoffset=0 yoffset=6 xadvance=65 page=0 chnl=15 -char id=127862 x=857 y=135 width=57 height=64 xoffset=0 yoffset=9 xadvance=58 page=0 chnl=15 -char id=127863 x=47 y=203 width=41 height=64 xoffset=0 yoffset=9 xadvance=41 page=0 chnl=15 -char id=127867 x=833 y=633 width=66 height=54 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15 -char id=127868 x=986 y=67 width=25 height=53 xoffset=0 yoffset=12 xadvance=25 page=0 chnl=15 -char id=127870 x=383 y=333 width=55 height=61 xoffset=1 yoffset=10 xadvance=57 page=0 chnl=15 -char id=127871 x=530 y=394 width=42 height=59 xoffset=0 yoffset=12 xadvance=42 page=0 chnl=15 -char id=127874 x=0 y=70 width=66 height=65 xoffset=0 yoffset=8 xadvance=66 page=0 chnl=15 -char id=128065 x=384 y=696 width=68 height=39 xoffset=-2 yoffset=19 xadvance=64 page=0 chnl=15 -char id=128068 x=132 y=698 width=57 height=47 xoffset=0 yoffset=15 xadvance=57 page=0 chnl=15 -char id=128069 x=777 y=633 width=54 height=55 xoffset=0 yoffset=14 xadvance=54 page=0 chnl=15 -char id=128121 x=478 y=136 width=64 height=64 xoffset=0 yoffset=8 xadvance=64 page=0 chnl=15 -char id=128122 x=65 y=269 width=63 height=63 xoffset=0 yoffset=9 xadvance=63 page=0 chnl=15 -char id=128123 x=339 y=637 width=60 height=57 xoffset=2 yoffset=14 xadvance=64 page=0 chnl=15 -char id=128125 x=505 y=267 width=59 height=63 xoffset=0 yoffset=9 xadvance=60 page=0 chnl=15 -char id=128126 x=321 y=268 width=60 height=63 xoffset=2 yoffset=7 xadvance=64 page=0 chnl=15 -char id=128127 x=889 y=67 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128128 x=627 y=266 width=55 height=63 xoffset=0 yoffset=9 xadvance=55 page=0 chnl=15 -char id=128139 x=574 y=394 width=68 height=58 xoffset=0 yoffset=12 xadvance=68 page=0 chnl=15 -char id=128140 x=202 y=70 width=65 height=65 xoffset=0 yoffset=8 xadvance=65 page=0 chnl=15 -char id=128147 x=642 y=634 width=66 height=55 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15 -char id=128151 x=588 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 -char id=128152 x=280 y=137 width=64 height=64 xoffset=0 yoffset=9 xadvance=64 page=0 chnl=15 -char id=128153 x=654 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 -char id=128155 x=720 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 -char id=128156 x=786 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 -char id=128157 x=77 y=137 width=67 height=64 xoffset=0 yoffset=9 xadvance=68 page=0 chnl=15 -char id=128159 x=335 y=69 width=64 height=65 xoffset=0 yoffset=8 xadvance=64 page=0 chnl=15 -char id=128162 x=130 y=268 width=63 height=63 xoffset=0 yoffset=9 xadvance=63 page=0 chnl=15 -char id=128163 x=146 y=137 width=65 height=64 xoffset=0 yoffset=9 xadvance=65 page=0 chnl=15 -char id=128164 x=454 y=695 width=67 height=38 xoffset=0 yoffset=23 xadvance=67 page=0 chnl=15 -char id=128169 x=916 y=134 width=57 height=64 xoffset=0 yoffset=9 xadvance=58 page=0 chnl=15 -char id=128420 x=852 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 -char id=128512 x=732 y=513 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128514 x=644 y=393 width=63 height=58 xoffset=0 yoffset=12 xadvance=63 page=0 chnl=15 -char id=128515 x=610 y=514 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128518 x=488 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128519 x=144 y=0 width=59 height=68 xoffset=0 yoffset=7 xadvance=59 page=0 chnl=15 -char id=128520 x=584 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128521 x=427 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128523 x=61 y=519 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128524 x=0 y=519 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128525 x=915 y=452 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128526 x=854 y=452 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128527 x=793 y=453 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128528 x=732 y=453 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128529 x=671 y=453 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128530 x=488 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128533 x=122 y=459 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128534 x=854 y=572 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128535 x=305 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128536 x=122 y=579 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128537 x=366 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128538 x=244 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128539 x=305 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128541 x=366 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128542 x=427 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128543 x=488 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128544 x=549 y=575 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128545 x=671 y=573 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128546 x=732 y=573 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128547 x=793 y=573 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128548 x=427 y=0 width=59 height=67 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128549 x=915 y=572 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128550 x=0 y=639 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128553 x=898 y=392 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128554 x=959 y=391 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128555 x=0 y=459 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128556 x=61 y=459 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128557 x=305 y=0 width=59 height=67 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128558 x=183 y=458 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128559 x=244 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128560 x=709 y=393 width=61 height=58 xoffset=0 yoffset=12 xadvance=62 page=0 chnl=15 -char id=128561 x=835 y=392 width=61 height=58 xoffset=0 yoffset=12 xadvance=61 page=0 chnl=15 -char id=128562 x=366 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128563 x=427 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128564 x=90 y=203 width=88 height=63 xoffset=0 yoffset=7 xadvance=59 page=0 chnl=15 -char id=128565 x=549 y=455 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128566 x=610 y=574 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128567 x=610 y=454 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128568 x=401 y=69 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128569 x=878 y=0 width=67 height=65 xoffset=0 yoffset=8 xadvance=67 page=0 chnl=15 -char id=128570 x=523 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128571 x=828 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128573 x=767 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128575 x=706 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128576 x=645 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=128577 x=122 y=519 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128578 x=183 y=518 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128579 x=244 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=128580 x=305 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129296 x=200 y=333 width=59 height=61 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129297 x=366 y=0 width=59 height=67 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=129298 x=383 y=268 width=59 height=63 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129299 x=549 y=515 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129300 x=0 y=0 width=75 height=68 xoffset=0 yoffset=7 xadvance=72 page=0 chnl=15 -char id=129301 x=671 y=513 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129302 x=181 y=396 width=54 height=60 xoffset=2 yoffset=7 xadvance=59 page=0 chnl=15 -char id=129303 x=778 y=266 width=98 height=62 xoffset=-1 yoffset=12 xadvance=96 page=0 chnl=15 -char id=129312 x=0 y=137 width=75 height=64 xoffset=-1 yoffset=9 xadvance=74 page=0 chnl=15 -char id=129314 x=793 y=513 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129315 x=346 y=136 width=64 height=64 xoffset=-1 yoffset=9 xadvance=64 page=0 chnl=15 -char id=129316 x=444 y=267 width=59 height=63 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129319 x=488 y=0 width=70 height=66 xoffset=0 yoffset=8 xadvance=70 page=0 chnl=15 -char id=129320 x=854 y=512 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129321 x=915 y=512 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129322 x=0 y=579 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129323 x=762 y=0 width=59 height=66 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=129324 x=772 y=393 width=61 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129325 x=949 y=329 width=59 height=60 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129326 x=261 y=333 width=59 height=61 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129327 x=462 y=69 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15 -char id=129346 x=975 y=134 width=46 height=64 xoffset=-1 yoffset=8 xadvance=44 page=0 chnl=15 -char id=129347 x=675 y=135 width=60 height=64 xoffset=-1 yoffset=9 xadvance=58 page=0 chnl=15 -char id=129360 x=70 y=334 width=63 height=61 xoffset=-1 yoffset=10 xadvance=61 page=0 chnl=15 -char id=129361 x=191 y=698 width=73 height=45 xoffset=-1 yoffset=18 xadvance=72 page=0 chnl=15 -char id=129362 x=253 y=203 width=66 height=63 xoffset=-1 yoffset=9 xadvance=64 page=0 chnl=15 -char id=129363 x=122 y=639 width=83 height=57 xoffset=-1 yoffset=14 xadvance=82 page=0 chnl=15 -char id=129364 x=491 y=332 width=69 height=60 xoffset=-1 yoffset=11 xadvance=68 page=0 chnl=15 -char id=129365 x=412 y=136 width=64 height=64 xoffset=-1 yoffset=8 xadvance=63 page=0 chnl=15 -char id=129366 x=947 y=0 width=66 height=65 xoffset=-1 yoffset=8 xadvance=65 page=0 chnl=15 -char id=129367 x=180 y=203 width=71 height=63 xoffset=-1 yoffset=8 xadvance=70 page=0 chnl=15 -char id=129368 x=878 y=266 width=66 height=62 xoffset=-1 yoffset=9 xadvance=65 page=0 chnl=15 -char id=129369 x=269 y=70 width=64 height=65 xoffset=-1 yoffset=8 xadvance=63 page=0 chnl=15 -char id=129370 x=823 y=0 width=53 height=66 xoffset=1 yoffset=8 xadvance=55 page=0 chnl=15 -char id=129371 x=205 y=0 width=50 height=68 xoffset=1 yoffset=7 xadvance=52 page=0 chnl=15 -char id=129372 x=389 y=202 width=65 height=63 xoffset=1 yoffset=9 xadvance=67 page=0 chnl=15 -char id=129373 x=887 y=330 width=60 height=60 xoffset=1 yoffset=10 xadvance=62 page=0 chnl=15 -char id=129374 x=961 y=632 width=61 height=51 xoffset=1 yoffset=15 xadvance=64 page=0 chnl=15 -char id=129375 x=526 y=637 width=56 height=56 xoffset=1 yoffset=12 xadvance=58 page=0 chnl=15 -char id=129377 x=425 y=396 width=53 height=59 xoffset=1 yoffset=10 xadvance=56 page=0 chnl=15 -char id=129378 x=321 y=203 width=66 height=63 xoffset=-1 yoffset=9 xadvance=64 page=0 chnl=15 -char id=129379 x=761 y=331 width=62 height=60 xoffset=1 yoffset=12 xadvance=64 page=0 chnl=15 -char id=129380 x=480 y=396 width=48 height=59 xoffset=4 yoffset=13 xadvance=56 page=0 chnl=15 -char id=129381 x=0 y=397 width=59 height=60 xoffset=0 yoffset=10 xadvance=59 page=0 chnl=15 -char id=129382 x=684 y=266 width=50 height=63 xoffset=1 yoffset=10 xadvance=53 page=0 chnl=15 -char id=129383 x=610 y=135 width=63 height=64 xoffset=1 yoffset=8 xadvance=65 page=0 chnl=15 -char id=129384 x=901 y=632 width=58 height=53 xoffset=2 yoffset=16 xadvance=63 page=0 chnl=15 -char id=129385 x=326 y=696 width=56 height=41 xoffset=2 yoffset=19 xadvance=60 page=0 chnl=15 -char id=129386 x=273 y=637 width=64 height=57 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 -char id=129387 x=0 y=203 width=45 height=64 xoffset=4 yoffset=9 xadvance=53 page=0 chnl=15 -char id=129472 x=66 y=699 width=64 height=49 xoffset=0 yoffset=14 xadvance=64 page=0 chnl=15 -char id=129488 x=61 y=639 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15 -char id=129505 x=918 y=200 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15 diff --git a/examples/text/unicode/resources/symbola.png b/examples/text/unicode/resources/symbola.png deleted file mode 100644 index e942606..0000000 Binary files a/examples/text/unicode/resources/symbola.png and /dev/null differ diff --git a/examples/text/unicode/unicode.go b/examples/text/unicode/unicode.go deleted file mode 100644 index a6d51e9..0000000 --- a/examples/text/unicode/unicode.go +++ /dev/null @@ -1,298 +0,0 @@ -package main - -// String containing 180 emoji codepoints separated by a '\0' char -var emojiCodepoints = "\xF0\x9F\x8C\x80\x00\xF0\x9F\x98\x80\x00\xF0\x9F\x98\x82\x00\xF0\x9F\xA4\xA3\x00\xF0" + - "\x9F\x98" + - "\x83\x00\xF0\x9F\x98\x86\x00\xF0\x9F\x98\x89\x00" + - "\xF0\x9F\x98\x8B\x00\xF0\x9F\x98\x8E\x00\xF0\x9F\x98\x8D\x00\xF0\x9F\x98\x98\x00\xF0\x9F\x98\x97\x00\xF0\x9F\x98" + - "\x99\x00\xF0\x9F\x98\x9A\x00\xF0\x9F\x99\x82\x00" + - "\xF0\x9F\xA4\x97\x00\xF0\x9F\xA4\xA9\x00\xF0\x9F\xA4\x94\x00\xF0\x9F\xA4\xA8\x00\xF0\x9F\x98\x90\x00\xF0\x9F\x98" + - "\x91\x00\xF0\x9F\x98\xB6\x00\xF0\x9F\x99\x84\x00" + - "\xF0\x9F\x98\x8F\x00\xF0\x9F\x98\xA3\x00\xF0\x9F\x98\xA5\x00\xF0\x9F\x98\xAE\x00\xF0\x9F\xA4\x90\x00\xF0\x9F\x98" + - "\xAF\x00\xF0\x9F\x98\xAA\x00\xF0\x9F\x98\xAB\x00" + - "\xF0\x9F\x98\xB4\x00\xF0\x9F\x98\x8C\x00\xF0\x9F\x98\x9B\x00\xF0\x9F\x98\x9D\x00\xF0\x9F\xA4\xA4\x00\xF0\x9F\x98" + - "\x92\x00\xF0\x9F\x98\x95\x00\xF0\x9F\x99\x83\x00" + - "\xF0\x9F\xA4\x91\x00\xF0\x9F\x98\xB2\x00\xF0\x9F\x99\x81\x00\xF0\x9F\x98\x96\x00\xF0\x9F\x98\x9E\x00\xF0\x9F\x98" + - "\x9F\x00\xF0\x9F\x98\xA4\x00\xF0\x9F\x98\xA2\x00" + - "\xF0\x9F\x98\xAD\x00\xF0\x9F\x98\xA6\x00\xF0\x9F\x98\xA9\x00\xF0\x9F\xA4\xAF\x00\xF0\x9F\x98\xAC\x00\xF0\x9F\x98" + - "\xB0\x00\xF0\x9F\x98\xB1\x00\xF0\x9F\x98\xB3\x00" + - "\xF0\x9F\xA4\xAA\x00\xF0\x9F\x98\xB5\x00\xF0\x9F\x98\xA1\x00\xF0\x9F\x98\xA0\x00\xF0\x9F\xA4\xAC\x00\xF0\x9F\x98" + - "\xB7\x00\xF0\x9F\xA4\x92\x00\xF0\x9F\xA4\x95\x00" + - "\xF0\x9F\xA4\xA2\x00\xF0\x9F\xA4\xAE\x00\xF0\x9F\xA4\xA7\x00\xF0\x9F\x98\x87\x00\xF0\x9F\xA4\xA0\x00\xF0\x9F\xA4" + - "\xAB\x00\xF0\x9F\xA4\xAD\x00\xF0\x9F\xA7\x90\x00" + - "\xF0\x9F\xA4\x93\x00\xF0\x9F\x98\x88\x00\xF0\x9F\x91\xBF\x00\xF0\x9F\x91\xB9\x00\xF0\x9F\x91\xBA\x00\xF0\x9F\x92" + - "\x80\x00\xF0\x9F\x91\xBB\x00\xF0\x9F\x91\xBD\x00" + - "\xF0\x9F\x91\xBE\x00\xF0\x9F\xA4\x96\x00\xF0\x9F\x92\xA9\x00\xF0\x9F\x98\xBA\x00\xF0\x9F\x98\xB8\x00\xF0\x9F\x98" + - "\xB9\x00\xF0\x9F\x98\xBB\x00\xF0\x9F\x98\xBD\x00" + - "\xF0\x9F\x99\x80\x00\xF0\x9F\x98\xBF\x00\xF0\x9F\x8C\xBE\x00\xF0\x9F\x8C\xBF\x00\xF0\x9F\x8D\x80\x00\xF0\x9F\x8D" + - "\x83\x00\xF0\x9F\x8D\x87\x00\xF0\x9F\x8D\x93\x00" + - "\xF0\x9F\xA5\x9D\x00\xF0\x9F\x8D\x85\x00\xF0\x9F\xA5\xA5\x00\xF0\x9F\xA5\x91\x00\xF0\x9F\x8D\x86\x00\xF0\x9F\xA5" + - "\x94\x00\xF0\x9F\xA5\x95\x00\xF0\x9F\x8C\xBD\x00" + - "\xF0\x9F\x8C\xB6\x00\xF0\x9F\xA5\x92\x00\xF0\x9F\xA5\xA6\x00\xF0\x9F\x8D\x84\x00\xF0\x9F\xA5\x9C\x00\xF0\x9F\x8C" + - "\xB0\x00\xF0\x9F\x8D\x9E\x00\xF0\x9F\xA5\x90\x00" + - "\xF0\x9F\xA5\x96\x00\xF0\x9F\xA5\xA8\x00\xF0\x9F\xA5\x9E\x00\xF0\x9F\xA7\x80\x00\xF0\x9F\x8D\x96\x00\xF0\x9F\x8D" + - "\x97\x00\xF0\x9F\xA5\xA9\x00\xF0\x9F\xA5\x93\x00" + - "\xF0\x9F\x8D\x94\x00\xF0\x9F\x8D\x9F\x00\xF0\x9F\x8D\x95\x00\xF0\x9F\x8C\xAD\x00\xF0\x9F\xA5\xAA\x00\xF0\x9F\x8C" + - "\xAE\x00\xF0\x9F\x8C\xAF\x00\xF0\x9F\xA5\x99\x00" + - "\xF0\x9F\xA5\x9A\x00\xF0\x9F\x8D\xB3\x00\xF0\x9F\xA5\x98\x00\xF0\x9F\x8D\xB2\x00\xF0\x9F\xA5\xA3\x00\xF0\x9F\xA5" + - "\x97\x00\xF0\x9F\x8D\xBF\x00\xF0\x9F\xA5\xAB\x00" + - "\xF0\x9F\x8D\xB1\x00\xF0\x9F\x8D\x98\x00\xF0\x9F\x8D\x9D\x00\xF0\x9F\x8D\xA0\x00\xF0\x9F\x8D\xA2\x00\xF0\x9F\x8D" + - "\xA5\x00\xF0\x9F\x8D\xA1\x00\xF0\x9F\xA5\x9F\x00" + - "\xF0\x9F\xA5\xA1\x00\xF0\x9F\x8D\xA6\x00\xF0\x9F\x8D\xAA\x00\xF0\x9F\x8E\x82\x00\xF0\x9F\x8D\xB0\x00\xF0\x9F\xA5" + - "\xA7\x00\xF0\x9F\x8D\xAB\x00\xF0\x9F\x8D\xAF\x00" + - "\xF0\x9F\x8D\xBC\x00\xF0\x9F\xA5\x9B\x00\xF0\x9F\x8D\xB5\x00\xF0\x9F\x8D\xB6\x00\xF0\x9F\x8D\xBE\x00\xF0\x9F\x8D" + - "\xB7\x00\xF0\x9F\x8D\xBB\x00\xF0\x9F\xA5\x82\x00" + - "\xF0\x9F\xA5\x83\x00\xF0\x9F\xA5\xA4\x00\xF0\x9F\xA5\xA2\x00\xF0\x9F\x91\x81\x00\xF0\x9F\x91\x85\x00\xF0\x9F\x91" + - "\x84\x00\xF0\x9F\x92\x8B\x00\xF0\x9F\x92\x98\x00" + - "\xF0\x9F\x92\x93\x00\xF0\x9F\x92\x97\x00\xF0\x9F\x92\x99\x00\xF0\x9F\x92\x9B\x00\xF0\x9F\xA7\xA1\x00\xF0\x9F\x92" + - "\x9C\x00\xF0\x9F\x96\xA4\x00\xF0\x9F\x92\x9D\x00" + - "\xF0\x9F\x92\x9F\x00\xF0\x9F\x92\x8C\x00\xF0\x9F\x92\xA4\x00\xF0\x9F\x92\xA2\x00\xF0\x9F\x92\xA3\x00" - -var messages = []Messages{ - // Array containing all the emojis messages - { - "\x46\x61\x6C\x73\x63\x68\x65\x73\x20\xC3\x9C\x62\x65\x6E\x20\x76\x6F\x6E\x20\x58\x79\x6C\x6F\x70\x68\x6F\x6E" + - "\x6D\x75\x73\x69\x6B\x20\x71\x75\xC3\xA4\x6C" + - "\x74\x20\x6A\x65\x64\x65\x6E\x20\x67\x72\xC3\xB6\xC3\x9F\x65\x72\x65\x6E\x20\x5A\x77\x65\x72\x67", - "German", - }, - { - "\x42\x65\x69\xC3\x9F\x20\x6E\x69\x63\x68\x74\x20\x69\x6E\x20\x64\x69\x65\x20\x48\x61\x6E\x64\x2C\x20\x64\x69" + - "\x65\x20\x64\x69\x63\x68\x20\x66\xC3\xBC\x74" + - "\x74\x65\x72\x74\x2E", - "German", - }, - { - "\x41\x75\xC3\x9F\x65\x72\x6F\x72\x64\x65\x6E\x74\x6C\x69\x63\x68\x65\x20\xC3\x9C\x62\x65\x6C\x20\x65\x72\x66" + - "\x6F\x72\x64\x65\x72\x6E\x20\x61\x75\xC3\x9F" + - "\x65\x72\x6F\x72\x64\x65\x6E\x74\x6C\x69\x63\x68\x65\x20\x4D\x69\x74\x74\x65\x6C\x2E", - "German", - }, - { - "\xD4\xBF\xD6\x80\xD5\xB6\xD5\xA1\xD5\xB4\x20\xD5\xA1\xD5\xBA\xD5\xA1\xD5\xAF\xD5\xAB\x20\xD5\xB8\xD6\x82\xD5" + - "\xBF\xD5\xA5\xD5\xAC\x20\xD6\x87\x20\xD5\xAB" + - "\xD5\xB6\xD5\xAE\xD5\xAB\x20\xD5\xA1\xD5\xB6\xD5\xB0\xD5\xA1\xD5\xB6\xD5\xA3\xD5\xAB\xD5\xBD\xD5\xBF\x20\xD5\xB9\xD5\xA8\xD5\xB6\xD5\xA5\xD6\x80", - "Armenian", - }, - { - "\xD4\xB5\xD6\x80\xD5\xA2\x20\xD5\xB8\xD6\x80\x20\xD5\xAF\xD5\xA1\xD6\x81\xD5\xAB\xD5\xB6\xD5\xA8\x20\xD5\xA5" + - "\xD5\xAF\xD5\xA1\xD6\x82\x20\xD5\xA1\xD5\xB6\xD5" + - "\xBF\xD5\xA1\xD5\xBC\x2C\x20\xD5\xAE\xD5\xA1\xD5\xBC\xD5\xA5\xD6\x80\xD5\xA8\x20\xD5\xA1\xD5\xBD\xD5\xA1\xD6\x81" + - "\xD5\xAB\xD5\xB6\x2E\x2E\x2E\x20\xC2\xAB\xD4\xBF" + - "\xD5\xB8\xD5\xBF\xD5\xA8\x20\xD5\xB4\xD5\xA5\xD6\x80\xD5\xB8\xD5\xB6\xD6\x81\xD5\xAB\xD6\x81\x20\xD5\xA7\x3A\xC2\xBB", - "Armenian", - }, - { - "\xD4\xB3\xD5\xA1\xD5\xBC\xD5\xA8\xD5\x9D\x20\xD5\xA3\xD5\xA1\xD6\x80\xD5\xB6\xD5\xA1\xD5\xB6\x2C\x20\xD5\xB1" + - "\xD5\xAB\xD6\x82\xD5\xB6\xD5\xA8\xD5\x9D\x20\xD5" + - "\xB1\xD5\xB4\xD5\xBC\xD5\xA1\xD5\xB6", - "Armenian", - }, - { - "\x4A\x65\xC5\xBC\x75\x20\x6B\x6C\xC4\x85\x74\x77\x2C\x20\x73\x70\xC5\x82\xC3\xB3\x64\xC5\xBA\x20\x46\x69\x6E" + - "\x6F\x6D\x20\x63\x7A\xC4\x99\xC5\x9B\xC4\x87" + - "\x20\x67\x72\x79\x20\x68\x61\xC5\x84\x62\x21", - "Polish", - }, - { - "\x44\x6F\x62\x72\x79\x6D\x69\x20\x63\x68\xC4\x99\x63\x69\x61\x6D\x69\x20\x6A\x65\x73\x74\x20\x70\x69\x65\x6B" + - "\xC5\x82\x6F\x20\x77\x79\x62\x72\x75\x6B\x6F" + - "\x77\x61\x6E\x65\x2E", - "Polish", - }, - { - "\xC3\x8E\xC8\x9B\x69\x20\x6D\x75\x6C\xC8\x9B\x75\x6D\x65\x73\x63\x20\x63\xC4\x83\x20\x61\x69\x20\x61\x6C\x65" + - "\x73\x20\x72\x61\x79\x6C\x69\x62\x2E\x0A\xC8\x98" + - "\x69\x20\x73\x70\x65\x72\x20\x73\xC4\x83\x20\x61\x69\x20\x6F\x20\x7A\x69\x20\x62\x75\x6E\xC4\x83\x21", - "Romanian", - }, - { - "\xD0\xAD\xD1\x85\x2C\x20\xD1\x87\xD1\x83\xD0\xB6\xD0\xB0\xD0\xBA\x2C\x20\xD0\xBE\xD0\xB1\xD1\x89\xD0\xB8\xD0" + - "\xB9\x20\xD1\x81\xD1\x8A\xD1\x91\xD0\xBC\x20" + - "\xD1\x86\xD0\xB5\xD0\xBD\x20\xD1\x88\xD0\xBB\xD1\x8F\xD0\xBF\x20\x28\xD1\x8E\xD1\x84\xD1\x82\xD1\x8C\x29\x20\xD0\xB2\xD0\xB4\xD1\x80\xD1\x8B\xD0\xB7\xD0\xB3\x21", - "Russian", - }, - { - "\xD0\xAF\x20\xD0\xBB\xD1\x8E\xD0\xB1\xD0\xBB\xD1\x8E\x20\x72\x61\x79\x6C\x69\x62\x21", - "Russian", - }, - { - "\xD0\x9C\xD0\xBE\xD0\xBB\xD1\x87\xD0\xB8\x2C\x20\xD1\x81\xD0\xBA\xD1\x80\xD1\x8B\xD0\xB2\xD0\xB0\xD0\xB9\xD1" + - "\x81\xD1\x8F\x20\xD0\xB8\x20\xD1\x82\xD0\xB0\xD0\xB8" + - "\x0A\xD0\x98\x20\xD1\x87\xD1\x83\xD0\xB2\xD1\x81\xD1\x82\xD0\xB2\xD0\xB0\x20\xD0\xB8\x20\xD0\xBC\xD0\xB5\xD1\x87" + - "\xD1\x82\xD1\x8B\x20\xD1\x81\xD0\xB2\xD0\xBE\xD0\xB8\x20" + - "\xE2\x80\x93\x0A\xD0\x9F\xD1\x83\xD1\x81\xD0\xBA\xD0\xB0\xD0\xB9\x20\xD0\xB2\x20\xD0\xB4\xD1\x83\xD1\x88\xD0\xB5" + - "\xD0\xB2\xD0\xBD\xD0\xBE\xD0\xB9\x20\xD0\xB3\xD0\xBB\xD1" + - "\x83\xD0\xB1\xD0\xB8\xD0\xBD\xD0\xB5\x0A\xD0\x98\x20\xD0\xB2\xD1\x81\xD1\x85\xD0\xBE\xD0\xB4\xD1\x8F\xD1\x82\x20" + - "\xD0\xB8\x20\xD0\xB7\xD0\xB0\xD0\xB9\xD0\xB4\xD1\x83\xD1" + - "\x82\x20\xD0\xBE\xD0\xBD\xD0\xB5\x0A\xD0\x9A\xD0\xB0\xD0\xBA\x20\xD0\xB7\xD0\xB2\xD0\xB5\xD0\xB7\xD0\xB4\xD1\x8B" + - "\x20\xD1\x8F\xD1\x81\xD0\xBD\xD1\x8B\xD0\xB5\x20\xD0\xB2" + - "\x20\xD0\xBD\xD0\xBE\xD1\x87\xD0\xB8\x2D\x0A\xD0\x9B\xD1\x8E\xD0\xB1\xD1\x83\xD0\xB9\xD1\x81\xD1\x8F\x20\xD0\xB8" + - "\xD0\xBC\xD0\xB8\x20\xE2\x80\x93\x20\xD0\xB8\x20\xD0\xBC" + - "\xD0\xBE\xD0\xBB\xD1\x87\xD0\xB8\x2E", - "Russian", - }, - { - "\x56\x6F\x69\x78\x20\x61\x6D\x62\x69\x67\x75\xC3\xAB\x20\x64\xE2\x80\x99\x75\x6E\x20\x63\xC5\x93\x75\x72\x20" + - "\x71\x75\x69\x20\x61\x75\x20\x7A\xC3\xA9\x70" + - "\x68\x79\x72\x20\x70\x72\xC3\xA9\x66\xC3\xA8\x72\x65\x20\x6C\x65\x73\x20\x6A\x61\x74\x74\x65\x73\x20\x64\x65\x20\x6B\x69\x77\x69", - "French", - }, - { - "\x42\x65\x6E\x6A\x61\x6D\xC3\xAD\x6E\x20\x70\x69\x64\x69\xC3\xB3\x20\x75\x6E\x61\x20\x62\x65\x62\x69\x64\x61" + - "\x20\x64\x65\x20\x6B\x69\x77\x69\x20\x79\x20" + - "\x66\x72\x65\x73\x61\x3B\x20\x4E\x6F\xC3\xA9\x2C\x20\x73\x69\x6E\x20\x76\x65\x72\x67\xC3\xBC\x65\x6E\x7A\x61\x2C" + - "\x20\x6C\x61\x20\x6D\xC3\xA1\x73\x20\x65\x78" + - "\x71\x75\x69\x73\x69\x74\x61\x20\x63\x68\x61\x6D\x70\x61\xC3\xB1\x61\x20\x64\x65\x6C\x20\x6D\x65\x6E\xC3\xBA\x2E", - "Spanish", - }, - { - "\xCE\xA4\xCE\xB1\xCF\x87\xCE\xAF\xCF\x83\xCF\x84\xCE\xB7\x20\xCE\xB1\xCE\xBB\xCF\x8E\xCF\x80\xCE\xB7\xCE\xBE" + - "\x20\xCE\xB2\xCE\xB1\xCF\x86\xCE\xAE\xCF\x82\x20" + - "\xCF\x88\xCE\xB7\xCE\xBC\xCE\xAD\xCE\xBD\xCE\xB7\x20\xCE\xB3\xCE\xB7\x2C\x20\xCE\xB4\xCF\x81\xCE\xB1\xCF\x83\xCE" + - "\xBA\xCE\xB5\xCE\xBB\xCE\xAF\xCE\xB6\xCE\xB5\xCE" + - "\xB9\x20\xCF\x85\xCF\x80\xCE\xAD\xCF\x81\x20\xCE\xBD\xCF\x89\xCE\xB8\xCF\x81\xCE\xBF\xCF\x8D\x20\xCE\xBA\xCF\x85\xCE\xBD\xCF\x8C\xCF\x82", - "Greek", - }, - { - "\xCE\x97\x20\xCE\xBA\xCE\xB1\xCE\xBB\xCF\x8D\xCF\x84\xCE\xB5\xCF\x81\xCE\xB7\x20\xCE\xAC\xCE\xBC\xCF\x85\xCE" + - "\xBD\xCE\xB1\x20\xCE\xB5\xCE\xAF\xCE\xBD" + - "\xCE\xB1\xCE\xB9\x20\xCE\xB7\x20\xCE\xB5\xCF\x80\xCE\xAF\xCE\xB8\xCE\xB5\xCF\x83\xCE\xB7\x2E", - "Greek", - }, - { - "\xCE\xA7\xCF\x81\xCF\x8C\xCE\xBD\xCE\xB9\xCE\xB1\x20\xCE\xBA\xCE\xB1\xCE\xB9\x20\xCE\xB6\xCE\xB1\xCE\xBC\xCE\xAC\xCE\xBD\xCE\xB9\xCE\xB1\x21", - "Greek", - }, - { - "\xCE\xA0\xCF\x8E\xCF\x82\x20\xCF\x84\xCE\xB1\x20\xCF\x80\xCE\xB1\xCF\x82\x20\xCF\x83\xCE\xAE\xCE\xBC\xCE\xB5\xCF\x81\xCE\xB1\x3B", - "Greek", - }, - - { - "\xE6\x88\x91\xE8\x83\xBD\xE5\x90\x9E\xE4\xB8\x8B\xE7\x8E\xBB\xE7\x92\x83\xE8\x80\x8C\xE4\xB8\x8D\xE4\xBC\xA4\xE8\xBA\xAB\xE4\xBD\x93\xE3\x80\x82", - "Chinese", - }, - { - "\xE4\xBD\xA0\xE5\x90\x83\xE4\xBA\x86\xE5\x90\x97\xEF\xBC\x9F", - "Chinese", - }, - { - "\xE4\xB8\x8D\xE4\xBD\x9C\xE4\xB8\x8D\xE6\xAD\xBB\xE3\x80\x82", - "Chinese", - }, - { - "\xE6\x9C\x80\xE8\xBF\x91\xE5\xA5\xBD\xE5\x90\x97\xEF\xBC\x9F", - "Chinese", - }, - { - "\xE5\xA1\x9E\xE7\xBF\x81\xE5\xA4\xB1\xE9\xA9\xAC\xEF\xBC\x8C\xE7\x84\x89\xE7\x9F\xA5\xE9\x9D\x9E\xE7\xA6\x8F\xE3\x80\x82", - "Chinese", - }, - { - "\xE5\x8D\x83\xE5\x86\x9B\xE6\x98\x93\xE5\xBE\x97\x2C\x20\xE4\xB8\x80\xE5\xB0\x86\xE9\x9A\xBE\xE6\xB1\x82", - "Chinese", - }, - { - "\xE4\xB8\x87\xE4\xBA\x8B\xE5\xBC\x80\xE5\xA4\xB4\xE9\x9A\xBE\xE3\x80\x82", - "Chinese", - }, - { - "\xE9\xA3\x8E\xE6\x97\xA0\xE5\xB8\xB8\xE9\xA1\xBA\xEF\xBC\x8C\xE5\x85\xB5\xE6\x97\xA0\xE5\xB8\xB8\xE8\x83\x9C\xE3\x80\x82", - "Chinese", - }, - { - "\xE6\xB4\xBB\xE5\x88\xB0\xE8\x80\x81\xEF\xBC\x8C\xE5\xAD\xA6\xE5\x88\xB0\xE8\x80\x81\xE3\x80\x82", - "Chinese", - }, - { - "\xE4\xB8\x80\xE8\xA8\x80\xE6\x97\xA2\xE5\x87\xBA\xEF\xBC\x8C\xE9\xA9\xB7\xE9\xA9\xAC\xE9\x9A\xBE\xE8\xBF\xBD\xE3\x80\x82", - "Chinese", - }, - { - "\xE8\xB7\xAF\xE9\x81\xA5\xE7\x9F\xA5\xE9\xA9\xAC\xE5\x8A\x9B\xEF\xBC\x8C\xE6\x97\xA5\xE4\xB9\x85\xE8\xA7\x81\xE4\xBA\xBA\xE5\xBF\x83", - "Chinese", - }, - { - "\xE6\x9C\x89\xE7\x90\x86\xE8\xB5\xB0\xE9\x81\x8D\xE5\xA4\xA9\xE4\xB8\x8B\xEF\xBC\x8C\xE6\x97\xA0\xE7\x90\x86\xE5\xAF\xB8\xE6\xAD\xA5\xE9\x9A\xBE\xE8\xA1\x8C\xE3\x80\x82", - "Chinese", - }, - - { - "\xE7\x8C\xBF\xE3\x82\x82\xE6\x9C\xA8\xE3\x81\x8B\xE3\x82\x89\xE8\x90\xBD\xE3\x81\xA1\xE3\x82\x8B", - "Japanese", - }, - { - "\xE4\xBA\x80\xE3\x81\xAE\xE7\x94\xB2\xE3\x82\x88\xE3\x82\x8A\xE5\xB9\xB4\xE3\x81\xAE\xE5\x8A\x9F", - "Japanese", - }, - { - "\xE3\x81\x86\xE3\x82\x89\xE3\x82\x84\xE3\x81\xBE\xE3\x81\x97\x20\x20\xE6\x80\x9D\xE3\x81\xB2\xE5\x88\x87\xE3\x82\x8B\xE6\x99\x82\x20\x20\xE7\x8C\xAB\xE3\x81\xAE\xE6\x81\x8B", - "Japanese", - }, - { - "\xE8\x99\x8E\xE7\xA9\xB4\xE3\x81\xAB\xE5\x85\xA5\xE3\x82\x89\xE3\x81\x9A\xE3\x82\x93\xE3\x81\xB0\xE8\x99\x8E\xE5\xAD\x90\xE3\x82\x92\xE5\xBE\x97\xE3\x81\x9A\xE3\x80\x82", - "Japanese", - }, - { - "\xE4\xBA\x8C\xE5\x85\x8E\xE3\x82\x92\xE8\xBF\xBD\xE3\x81\x86\xE8\x80\x85\xE3\x81\xAF\xE4\xB8\x80\xE5\x85\x8E\xE3\x82\x92\xE3\x82\x82\xE5\xBE\x97\xE3\x81\x9A\xE3\x80\x82", - "Japanese", - }, - { - "\xE9\xA6\xAC\xE9\xB9\xBF\xE3\x81\xAF\xE6\xAD\xBB\xE3\x81\xAA\xE3\x81\xAA\xE3\x81\x8D\xE3\x82\x83\xE6\xB2\xBB\xE3\x82\x89\xE3\x81\xAA\xE3\x81\x84\xE3\x80\x82", - "Japanese", - }, - { - "\xE6\x9E\xAF\xE9\x87\x8E\xE8\xB7\xAF\xE3\x81\xAB\xE3\x80\x80\xE5\xBD\xB1\xE3\x81\x8B\xE3\x81\x95\xE3\x81\xAA\xE3\x82\x8A\xE3\x81\xA6\xE3\x80\x80\xE3\x82\x8F\xE3\x81\x8B\xE3\x82\x8C\xE3\x81\x91\xE3\x82\x8A", - "Japanese", - }, - { - "\xE7\xB9\xB0\xE3\x82\x8A\xE8\xBF\x94\xE3\x81\x97\xE9\xBA\xA6\xE3\x81\xAE\xE7\x95\x9D\xE7\xB8\xAB\xE3\x81\xB5\xE8\x83\xA1\xE8\x9D\xB6\xE5\x93\x89", - "Japanese", - }, - - { - "\xEC\x95\x84\xEB\x93\x9D\xED\x95\x9C\x20\xEB\xB0\x94\xEB\x8B\xA4\x20\xEC\x9C\x84\xEC\x97\x90\x20\xEA\xB0\x88" + - "\xEB\xA7\xA4\xEA\xB8\xB0\x20\xEB\x91\x90\xEC\x97\x87\x20" + - "\xEB\x82\xA0\xEC\x95\x84\x20\xEB\x8F\x88\xEB\x8B\xA4\x2E\x0A\xEB\x84\x88\xED\x9B\x8C\xEB\x84\x88\xED\x9B\x8C\x20" + - "\xEC\x8B\x9C\xEB\xA5\xBC\x20\xEC\x93\xB4\xEB\x8B\xA4\x2E" + - "\x20\xEB\xAA\xA8\xEB\xA5\xB4\xEB\x8A\x94\x20\xEB\x82\x98\xEB\x9D\xBC\x20\xEA\xB8\x80\xEC\x9E\x90\xEB\x8B\xA4\x2E" + - "\x0A\xEB\x84\x90\xEB\x94\xB0\xEB\x9E\x80\x20\xED\x95\x98" + - "\xEB\x8A\x98\x20\xEB\xB3\xB5\xED\x8C\x90\xEC\x97\x90\x20\xEB\x82\x98\xEB\x8F\x84\x20\xEA\xB0\x99\xEC\x9D\xB4\x20\xEC\x8B\x9C\xEB\xA5\xBC\x20\xEC\x93\xB4\xEB\x8B\xA4\x2E", - "Korean", - }, - { - "\xEC\xA0\x9C\x20\xEB\x88\x88\xEC\x97\x90\x20\xEC\x95\x88\xEA\xB2\xBD\xEC\x9D\xB4\xEB\x8B\xA4", - "Korean", - }, - { - "\xEA\xBF\xA9\x20\xEB\xA8\xB9\xEA\xB3\xA0\x20\xEC\x95\x8C\x20\xEB\xA8\xB9\xEB\x8A\x94\xEB\x8B\xA4", - "Korean", - }, - { - "\xEB\xA1\x9C\xEB\xA7\x88\xEB\x8A\x94\x20\xED\x95\x98\xEB\xA3\xA8\xEC\x95\x84\xEC\xB9\xA8\xEC\x97\x90\x20\xEC" + - "\x9D\xB4\xEB\xA3\xA8\xEC\x96\xB4\xEC\xA7\x84\x20\xEA\xB2\x83\xEC\x9D\xB4" + - "\x20\xEC\x95\x84\xEB\x8B\x88\xEB\x8B\xA4", - "Korean", - }, - { - "\xEA\xB3\xA0\xEC\x83\x9D\x20\xEB\x81\x9D\xEC\x97\x90\x20\xEB\x82\x99\xEC\x9D\xB4\x20\xEC\x98\xA8\xEB\x8B\xA4", - "Korean", - }, - { - "\xEA\xB0\x9C\xEC\xB2\x9C\xEC\x97\x90\xEC\x84\x9C\x20\xEC\x9A\xA9\x20\xEB\x82\x9C\xEB\x8B\xA4", - "Korean", - }, - { - "\xEC\x95\x88\xEB\x85\x95\xED\x95\x98\xEC\x84\xB8\xEC\x9A\x94\x3F", - "Korean", - }, - { - "\xEB\xA7\x8C\xEB\x82\x98\xEC\x84\x9C\x20\xEB\xB0\x98\xEA\xB0\x91\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4", - "Korean", - }, - { - "\xED\x95\x9C\xEA\xB5\xAD\xEB\xA7\x90\x20\xED\x95\x98\xEC\x8B\xA4\x20\xEC\xA4\x84\x20\xEC\x95\x84\xEC\x84\xB8\xEC\x9A\x94\x3F", - "Korean", - }, -} diff --git a/examples/text/writing_anim/main.go b/examples/text/writing_anim/main.go index a6671a0..daabe5b 100644 --- a/examples/text/writing_anim/main.go +++ b/examples/text/writing_anim/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/textures/background_scrolling/cyberpunk_street_background.png b/examples/textures/background_scrolling/cyberpunk_street_background.png deleted file mode 100644 index 838d08a..0000000 Binary files a/examples/textures/background_scrolling/cyberpunk_street_background.png and /dev/null differ diff --git a/examples/textures/background_scrolling/cyberpunk_street_foreground.png b/examples/textures/background_scrolling/cyberpunk_street_foreground.png deleted file mode 100644 index 528b4ae..0000000 Binary files a/examples/textures/background_scrolling/cyberpunk_street_foreground.png and /dev/null differ diff --git a/examples/textures/background_scrolling/cyberpunk_street_midground.png b/examples/textures/background_scrolling/cyberpunk_street_midground.png deleted file mode 100644 index 73f24fe..0000000 Binary files a/examples/textures/background_scrolling/cyberpunk_street_midground.png and /dev/null differ diff --git a/examples/textures/background_scrolling/main.go b/examples/textures/background_scrolling/main.go deleted file mode 100644 index ef36116..0000000 --- a/examples/textures/background_scrolling/main.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenW = int32(1280) - screenH = int32(500) -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [textures] example - background scrolling") - - background := rl.LoadTexture("cyberpunk_street_background.png") - midground := rl.LoadTexture("cyberpunk_street_midground.png") - foreground := rl.LoadTexture("cyberpunk_street_foreground.png") - - scrollBack := float32(0) - scrollMid := float32(0) - scrollFore := float32(0) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - scrollBack -= 0.1 - scrollMid -= 0.5 - scrollFore -= 1 - - if scrollBack <= -float32(background.Width)*2 { - scrollBack = 0 - } - - if scrollMid <= -float32(midground.Width)*2 { - scrollMid = 0 - } - - if scrollFore <= -float32(foreground.Width)*2 { - scrollFore = 0 - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawTextureEx(background, rl.NewVector2(scrollBack, 20), 0, 2, rl.White) - rl.DrawTextureEx(background, rl.NewVector2(float32(background.Width*2)+scrollBack, 20), 0, 2, rl.White) - - rl.DrawTextureEx(midground, rl.NewVector2(scrollMid, 20), 0, 2, rl.White) - rl.DrawTextureEx(midground, rl.NewVector2(float32(midground.Width*2)+scrollMid, 20), 0, 2, rl.White) - - rl.DrawTextureEx(foreground, rl.NewVector2(scrollFore, 20), 0, 2, rl.White) - rl.DrawTextureEx(foreground, rl.NewVector2(float32(foreground.Width*2)+scrollFore, 20), 0, 2, rl.White) - - txt := "BACKGROUND SCROLLING & PARALLAX" - txtlen := rl.MeasureText(txt, 20) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-50, 20, rl.Black) - txt = "(c) Cyberpunk Street Environment by Luis Zuno (@ansimuz)" - txtlen = rl.MeasureText(txt, 10) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-25, 10, rl.Black) - - rl.EndDrawing() - } - - rl.CloseWindow() -} diff --git a/examples/textures/blend_modes/cyberpunk_street_background.png b/examples/textures/blend_modes/cyberpunk_street_background.png deleted file mode 100644 index 838d08a..0000000 Binary files a/examples/textures/blend_modes/cyberpunk_street_background.png and /dev/null differ diff --git a/examples/textures/blend_modes/cyberpunk_street_foreground.png b/examples/textures/blend_modes/cyberpunk_street_foreground.png deleted file mode 100644 index 528b4ae..0000000 Binary files a/examples/textures/blend_modes/cyberpunk_street_foreground.png and /dev/null differ diff --git a/examples/textures/blend_modes/main.go b/examples/textures/blend_modes/main.go deleted file mode 100644 index 0c857c6..0000000 --- a/examples/textures/blend_modes/main.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenW = int32(1280) - screenH = int32(720) - blendCountMax = 4 - blendMode = 0 -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [textures] example - blend modes") - - bgImg := rl.LoadImage("cyberpunk_street_background.png") - bgTex := rl.LoadTextureFromImage(bgImg) - - fgImg := rl.LoadImage("cyberpunk_street_foreground.png") - fgTex := rl.LoadTextureFromImage(fgImg) - - rl.UnloadImage(bgImg) - rl.UnloadImage(fgImg) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - if rl.IsKeyPressed(rl.KeySpace) { - if blendMode >= blendCountMax-1 { - blendMode = 0 - } else { - blendMode++ - } - - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawTexture(bgTex, screenW/2-bgTex.Width/2, screenH/2-bgTex.Height/2, rl.White) - rl.BeginBlendMode(rl.BlendMode(blendMode)) - rl.DrawTexture(fgTex, screenW/2-fgTex.Width/2, screenH/2-fgTex.Height/2, rl.White) - rl.EndBlendMode() - - txt := "Press SPACE to change blend modes" - txtlen := rl.MeasureText(txt, 20) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-70, 20, rl.Black) - switch rl.BlendMode(blendMode) { - case rl.BlendAlpha: - txt = "Current rl.BlendAlpha" - txtlen = rl.MeasureText(txt, 20) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-50, 20, rl.Black) - case rl.BlendAdditive: - txt = "Current rl.BlendAdditive" - txtlen = rl.MeasureText(txt, 20) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-50, 20, rl.Black) - case rl.BlendMultiplied: - txt = "Current rl.BlendMultiplied" - txtlen = rl.MeasureText(txt, 20) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-50, 20, rl.Black) - case rl.BlendAddColors: - txt = "Current rl.BlendAddColors" - txtlen = rl.MeasureText(txt, 20) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-50, 20, rl.Black) - } - - txt = "(c) Cyberpunk Street Environment by Luis Zuno (@ansimuz)" - txtlen = rl.MeasureText(txt, 10) - rl.DrawText(txt, (screenW/2)-txtlen/2, screenH-25, 10, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadTexture(fgTex) - rl.UnloadTexture(bgTex) - - rl.CloseWindow() -} diff --git a/examples/textures/draw_tiled/main.go b/examples/textures/draw_tiled/main.go deleted file mode 100644 index 2a4ca93..0000000 --- a/examples/textures/draw_tiled/main.go +++ /dev/null @@ -1,302 +0,0 @@ -/******************************************************************************************* - * - * raylib [textures] example - Draw part of the texture tiled - * - * Example originally created with raylib 3.0, last time updated with raylib 4.2 - * - * Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) - * - * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, - * BSD-like license that allows static linking with closed source software - * - * Copyright (c) 2020-2024 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) - * - ********************************************************************************************/ -package main - -import ( - "fmt" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -const ( - screenWidth = 800 - screenHeight = 450 - optWidth = 220 // Max width for the options container - marginSize = 8 // Size for the margins - colorSize = 16 // Size of the color select buttons -) - -func main() { - rl.SetConfigFlags(rl.FlagWindowResizable) // Make the window resizable - rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - Draw part of a texture tiled") - - // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - texPattern := rl.LoadTexture("patterns.png") - rl.SetTextureFilter(texPattern, rl.FilterTrilinear) // Makes the texture smoother when upscaled - - // Coordinates for all patterns inside the texture - recPattern := []rl.Rectangle{ - {3, 3, 66, 66}, - {75, 3, 100, 100}, - {3, 75, 66, 66}, - {7, 156, 50, 50}, - {85, 106, 90, 45}, - {75, 154, 100, 60}, - } - - // Setup colors - colors := []rl.Color{rl.Black, rl.Maroon, rl.Orange, rl.Blue, rl.Purple, - rl.Beige, rl.Lime, rl.Red, rl.DarkGray, rl.SkyBlue} - var maxColors = len(colors) - colorRec := make([]rl.Rectangle, maxColors) - - // Calculate rectangle for each color - var x, y float32 - for i := 0; i < maxColors; i++ { - colorRec[i].X = 2.0 + marginSize + x - colorRec[i].Y = 22.0 + 256.0 + marginSize + y - colorRec[i].Width = colorSize * 2.0 - colorRec[i].Height = colorSize - - if i == (maxColors/2 - 1) { - x = 0 - y += colorSize + marginSize - } else { - x += colorSize*2 + marginSize - } - } - - activePattern := 0 - activeCol := 0 - scale := float32(1.0) - rotation := float32(0.0) - - rl.SetTargetFPS(60) - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Handle mouse - if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { - mouse := rl.GetMousePosition() - - // Check which pattern was clicked and set it as the active pattern - for i := 0; i < len(recPattern); i++ { - r := rl.Rectangle{ - X: 2 + marginSize + recPattern[i].X, - Y: 40 + marginSize + recPattern[i].Y, - Width: recPattern[i].Width, - Height: recPattern[i].Height, - } - if rl.CheckCollisionPointRec(mouse, r) { - activePattern = i - break - } - } - - // Check to see which color was clicked and set it as the active color - for i := 0; i < maxColors; i++ { - if rl.CheckCollisionPointRec(mouse, colorRec[i]) { - activeCol = i - break - } - } - } - - // Handle keys - - // Change scale - if rl.IsKeyPressed(rl.KeyUp) { - scale += 0.25 - } - if rl.IsKeyPressed(rl.KeyDown) { - scale -= 0.25 - } - scale = clamp(scale, 0.25, 10) - - // Change rotation - if rl.IsKeyPressed(rl.KeyLeft) { - rotation -= 25.0 - } - if rl.IsKeyPressed(rl.KeyRight) { - rotation += 25.0 - } - - // Reset - if rl.IsKeyPressed(rl.KeySpace) { - rotation = 0.0 - scale = 1.0 - } - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - // Draw the tiled area - src := rl.Rectangle{ - X: optWidth + marginSize, - Y: marginSize, - Width: float32(rl.GetScreenWidth()) - optWidth - 2.0*marginSize, - Height: float32(rl.GetScreenHeight()) - 2.0*marginSize, - } - DrawTextureTiled(texPattern, recPattern[activePattern], src, rl.Vector2{}, rotation, scale, colors[activeCol]) - - // Draw options - rl.DrawRectangle(marginSize, marginSize, optWidth-marginSize, int32(rl.GetScreenHeight())-2*marginSize, - rl.ColorAlpha(rl.LightGray, 0.5)) - - rl.DrawText("Select Pattern", 2+marginSize, 30+marginSize, 10, rl.Black) - rl.DrawTexture(texPattern, 2+marginSize, 40+marginSize, rl.Black) - rl.DrawRectangle(int32(2+marginSize+recPattern[activePattern].X), - int32(40+marginSize+recPattern[activePattern].Y), - int32(recPattern[activePattern].Width), - int32(recPattern[activePattern].Height), rl.ColorAlpha(rl.DarkBlue, 0.3)) - - rl.DrawText("Select Color", 2+marginSize, 10+256+marginSize, 10, rl.Black) - for i := 0; i < maxColors; i++ { - rl.DrawRectangleRec(colorRec[i], colors[i]) - if activeCol == i { - rl.DrawRectangleLinesEx(colorRec[i], 3, rl.ColorAlpha(rl.White, 0.5)) - } - } - - rl.DrawText("Scale (UP/DOWN to change)", 2+marginSize, 80+256+marginSize, 10, rl.Black) - rl.DrawText(fmt.Sprintf("%.2fx", scale), 2+marginSize, 92+256+marginSize, 20, rl.Black) - - rl.DrawText("Rotation (LEFT/RIGHT to change)", 2+marginSize, 122+256+marginSize, 10, rl.Black) - rl.DrawText(fmt.Sprintf("%.0f degrees", rotation), 2+marginSize, 134+256+marginSize, 20, rl.Black) - - rl.DrawText("Press [SPACE] to reset", 2+marginSize, 164+256+marginSize, 10, rl.DarkBlue) - - // Draw FPS - rl.DrawText(fmt.Sprintf("%d FPS", rl.GetFPS()), 2+marginSize, 2+marginSize, 20, rl.Black) - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadTexture(texPattern) // Unload texture - - rl.CloseWindow() // Close window and OpenGL context -} - -// DrawTextureTiled draws a part of a texture (defined by a rectangle) with rotation and scale tiled into dest. -func DrawTextureTiled(texture rl.Texture2D, source, dest rl.Rectangle, origin rl.Vector2, rotation, scale float32, - tint rl.Color) { - - if (texture.ID <= 0) || (scale <= 0.0) { // Want see an infinite loop?!...just delete this line! - return - } - if (source.Width == 0) || (source.Height == 0) { - return - } - - tileWidth := source.Width * scale - tileHeight := source.Height * scale - if (dest.Width < tileWidth) && (dest.Height < tileHeight) { - // Can fit only one tile - src := rl.Rectangle{ - X: source.X, - Y: source.Y, - Width: dest.Width / tileWidth * source.Width, - Height: dest.Height / tileHeight * source.Height, - } - dst := rl.Rectangle{X: dest.X, Y: dest.Y, Width: dest.Width, Height: dest.Height} - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } else if dest.Width <= tileWidth { - // Tiled vertically (one column) - var dy float32 - for ; dy+tileHeight < dest.Height; dy += tileHeight { - src := rl.Rectangle{ - X: source.X, - Y: source.Y, - Width: dest.Width / tileWidth * source.Width, - Height: source.Height, - } - dst := rl.Rectangle{X: dest.X, Y: dest.Y + dy, Width: dest.Width, Height: tileHeight} - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } - - // Fit last tile - if dy < dest.Height { - src := rl.Rectangle{X: source.X, Y: source.Y, - Width: (dest.Width / tileWidth) * source.Width, - Height: ((dest.Height - dy) / tileHeight) * source.Height, - } - dst := rl.Rectangle{X: dest.X, Y: dest.Y + dy, Width: dest.Width, Height: dest.Height - dy} - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } - } else if dest.Height <= tileHeight { - // Tiled horizontally (one row) - var dx float32 - for ; dx+tileWidth < dest.Width; dx += tileWidth { - src := rl.Rectangle{ - X: source.X, Y: source.Y, Width: source.Width, - Height: (dest.Height / tileHeight) * source.Height, - } - dst := rl.Rectangle{X: dest.X + dx, Y: dest.Y, Width: tileWidth, Height: dest.Height} - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } - - // Fit last tile - if dx < dest.Width { - src := rl.Rectangle{ - X: source.X, Y: source.Y, Width: ((dest.Width - dx) / tileWidth) * source.Width, - Height: (dest.Height / tileHeight) * source.Height, - } - dst := rl.Rectangle{X: dest.X + dx, Y: dest.Y, Width: dest.Width - dx, Height: dest.Height} - rl.DrawTexturePro(texture, src, - dst, origin, rotation, tint) - } - } else { - // Tiled both horizontally and vertically (rows and columns) - var dx float32 - for ; dx+tileWidth < dest.Width; dx += tileWidth { - var dy float32 - for ; dy+tileHeight < dest.Height; dy += tileHeight { - dst := rl.Rectangle{X: dest.X + dx, Y: dest.Y + dy, Width: tileWidth, Height: tileHeight} - rl.DrawTexturePro(texture, source, dst, origin, rotation, tint) - } - - if dy < dest.Height { - src := rl.Rectangle{ - X: source.X, Y: source.Y, - Width: source.Width, Height: ((dest.Height - dy) / tileHeight) * source.Height, - } - dst := rl.Rectangle{ - X: dest.X + dx, Y: dest.Y + dy, - Width: tileWidth, Height: dest.Height - dy, - } - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } - } - - // Fit last column of tiles - if dx < dest.Width { - var dy float32 - for ; dy+tileHeight < dest.Height; dy += tileHeight { - src := rl.Rectangle{ - X: source.X, Y: source.Y, - Width: ((dest.Width - dx) / tileWidth) * source.Width, Height: source.Height, - } - dst := rl.Rectangle{X: dest.X + dx, Y: dest.Y + dy, Width: dest.Width - dx, Height: tileHeight} - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } - - // Draw final tile in the bottom right corner - if dy < dest.Height { - src := rl.Rectangle{ - X: source.X, Y: source.Y, - Width: ((dest.Width - dx) / tileWidth) * source.Width, - Height: ((dest.Height - dy) / tileHeight) * source.Height, - } - dst := rl.Rectangle{X: dest.X + dx, Y: dest.Y + dy, Width: dest.Width - dx, Height: dest.Height - dy} - rl.DrawTexturePro(texture, src, dst, origin, rotation, tint) - } - } - } -} - -func clamp(value, minValue, maxValue float32) float32 { - return min(maxValue, max(value, minValue)) -} diff --git a/examples/textures/draw_tiled/patterns.png b/examples/textures/draw_tiled/patterns.png deleted file mode 100644 index 58b3c37..0000000 Binary files a/examples/textures/draw_tiled/patterns.png and /dev/null differ diff --git a/examples/textures/image_drawing/main.go b/examples/textures/image_drawing/main.go index c4f76e1..365c579 100644 --- a/examples/textures/image_drawing/main.go +++ b/examples/textures/image_drawing/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/textures/image_generation/main.go b/examples/textures/image_generation/main.go index 16f78fd..cab5e9a 100644 --- a/examples/textures/image_generation/main.go +++ b/examples/textures/image_generation/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const numTextures = 7 @@ -12,11 +12,12 @@ func main() { rl.InitWindow(int32(screenWidth), int32(screenHeight), "raylib [textures] example - procedural images generation") - verticalGradient := rl.GenImageGradientLinear(screenWidth, screenHeight, 0, rl.Red, rl.Blue) - horizontalGradient := rl.GenImageGradientLinear(screenWidth, screenHeight, 90, rl.Red, rl.Blue) + verticalGradient := rl.GenImageGradientV(screenWidth, screenHeight, rl.Red, rl.Blue) + horizontalGradient := rl.GenImageGradientH(screenWidth, screenHeight, rl.Red, rl.Blue) radialGradient := rl.GenImageGradientRadial(screenWidth, screenHeight, 0, rl.White, rl.Black) checked := rl.GenImageChecked(screenWidth, screenHeight, 32, 32, rl.Red, rl.Blue) whiteNoise := rl.GenImageWhiteNoise(screenWidth, screenHeight, 0.5) + perlinNoise := rl.GenImagePerlinNoise(screenWidth, screenHeight, 50, 50, 4.0) cellular := rl.GenImageCellular(screenWidth, screenHeight, 32) textures := make([]rl.Texture2D, numTextures) @@ -25,7 +26,8 @@ func main() { textures[2] = rl.LoadTextureFromImage(radialGradient) textures[3] = rl.LoadTextureFromImage(checked) textures[4] = rl.LoadTextureFromImage(whiteNoise) - textures[5] = rl.LoadTextureFromImage(cellular) + textures[5] = rl.LoadTextureFromImage(perlinNoise) + textures[6] = rl.LoadTextureFromImage(cellular) // Unload image data (CPU RAM) rl.UnloadImage(verticalGradient) @@ -33,6 +35,7 @@ func main() { rl.UnloadImage(radialGradient) rl.UnloadImage(checked) rl.UnloadImage(whiteNoise) + rl.UnloadImage(perlinNoise) rl.UnloadImage(cellular) currentTexture := 0 @@ -71,6 +74,9 @@ func main() { rl.DrawText("WHITE NOISE", 640, 10, 20, rl.Red) break case 5: + rl.DrawText("PERLIN NOISE", 630, 10, 20, rl.RayWhite) + break + case 6: rl.DrawText("CELLULAR", 670, 10, 20, rl.RayWhite) break default: diff --git a/examples/textures/image_image/main.go b/examples/textures/image_image/main.go index 8de80bb..24472eb 100644 --- a/examples/textures/image_image/main.go +++ b/examples/textures/image_image/main.go @@ -4,7 +4,7 @@ import ( "image/png" "os" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -35,7 +35,7 @@ func main() { for !rl.WindowShouldClose() { if rl.IsKeyPressed(rl.KeyS) { - rimg := rl.LoadImageFromTexture(texture) + rimg := rl.GetTextureData(texture) f, err := os.Create("image_saved.png") if err != nil { diff --git a/examples/textures/image_loading/main.go b/examples/textures/image_loading/main.go index e97eb9b..9aeb41e 100644 --- a/examples/textures/image_loading/main.go +++ b/examples/textures/image_loading/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/textures/image_processing/main.go b/examples/textures/image_processing/main.go index 5dfdc87..5c449a4 100644 --- a/examples/textures/image_processing/main.go +++ b/examples/textures/image_processing/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const numProcesses = 8 @@ -35,9 +35,9 @@ func main() { rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image processing") - image := rl.LoadImage("parrots.png") // Loaded in CPU memory (RAM) + image := rl.LoadImage("parrots.png") // Loaded in CPU memory (RAM) rl.ImageFormat(image, rl.UncompressedR8g8b8a8) // Format image to RGBA 32bit (required for texture update) - texture := rl.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM) + texture := rl.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM) currentProcess := None textureReload := false @@ -98,8 +98,8 @@ func main() { break } - pixels := rl.LoadImageColors(image) // Get pixel data from image (RGBA 32bit) - rl.UpdateTexture(texture, pixels) // Update texture with new image data + pixels := rl.GetImageData(image) // Get pixel data from image (RGBA 32bit) + rl.UpdateTexture(texture, pixels) // Update texture with new image data textureReload = false } diff --git a/examples/textures/image_text/main.go b/examples/textures/image_text/main.go index 2b93857..b416442 100644 --- a/examples/textures/image_text/main.go +++ b/examples/textures/image_text/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -11,7 +11,8 @@ func main() { rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image text drawing") // TTF Font loading with custom generation parameters - font := rl.LoadFontEx("fonts/KAISG.ttf", 64, nil) + var fontChars int32 + font := rl.LoadFontEx("fonts/KAISG.ttf", 64, &fontChars, 0) parrots := rl.LoadImage("parrots.png") // Load image in CPU memory (RAM) diff --git a/examples/textures/logo_raylib/main.go b/examples/textures/logo_raylib/main.go index 86d8d55..8777074 100644 --- a/examples/textures/logo_raylib/main.go +++ b/examples/textures/logo_raylib/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/textures/mouse_painting/main.go b/examples/textures/mouse_painting/main.go deleted file mode 100644 index 6b61854..0000000 --- a/examples/textures/mouse_painting/main.go +++ /dev/null @@ -1,188 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - screenW = int32(800) - screenH = int32(450) - - colors = []rl.Color{rl.RayWhite, rl.Yellow, rl.Gold, rl.Pink, rl.Red, rl.Maroon, rl.Green, rl.Lime, rl.DarkGreen, rl.SkyBlue, rl.Blue, rl.DarkBlue, rl.Purple, rl.Violet, rl.DarkPurple, rl.Beige, rl.Brown, rl.DarkBrown, rl.LightGray, rl.Gray, rl.DarkGray, rl.Black} - - colorRecs []rl.Rectangle -) - -func main() { - - rl.InitWindow(screenW, screenH, "raylib [textures] example - mouse painting") - - for i := 0; i < len(colors); i++ { - colorRecs = append(colorRecs, rl.NewRectangle(10+(30*float32(i))+(2*float32(i)), 10, 30, 30)) - } - colorSelected, colorMouseHover := 1, 0 - colorPrev := colorSelected - brushSize := float32(20) - mousePressed := false - - btnSaveRec := rl.NewRectangle(750, 10, 40, 30) - btnSaveMouseHover, showSaveMsg := false, false - saveMsgCount := 0 - - target := rl.LoadRenderTexture(screenW, screenH) - - rl.BeginTextureMode(target) - rl.ClearBackground(colors[0]) - rl.EndTextureMode() - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - mousePos := rl.GetMousePosition() - - if rl.IsKeyPressed(rl.KeyRight) { - colorSelected++ - } else if rl.IsKeyPressed(rl.KeyLeft) { - colorSelected-- - } - - if colorSelected >= len(colors) { - colorSelected = len(colors) - 1 - } else if colorSelected < 0 { - colorSelected = 0 - } - - for i := 0; i < len(colorRecs); i++ { - if rl.CheckCollisionPointRec(mousePos, colorRecs[i]) { - colorMouseHover = i - } else { - colorMouseHover = -1 - } - - if colorMouseHover >= 0 && rl.IsMouseButtonPressed(rl.MouseButtonLeft) { - colorSelected = colorMouseHover - colorPrev = colorSelected - } - } - - if rl.IsKeyPressed(rl.KeyUp) { - brushSize += 5 - } else if rl.IsKeyPressed(rl.KeyDown) { - brushSize -= 5 - } - brushSize += rl.GetMouseWheelMove() * 5 - if brushSize < 2 { - brushSize = 2 - } - if brushSize > 50 { - brushSize = 50 - } - - if rl.IsKeyPressed(rl.KeyC) { - rl.BeginTextureMode(target) - rl.ClearBackground(colors[0]) - rl.EndTextureMode() - } - - if rl.IsMouseButtonDown(rl.MouseButtonLeft) { - rl.BeginTextureMode(target) - if mousePos.Y > 50 { - rl.DrawCircle(int32(mousePos.X), int32(mousePos.Y), brushSize, colors[colorSelected]) - } - rl.EndTextureMode() - } - - if rl.IsMouseButtonDown(rl.MouseButtonRight) { - if !mousePressed { - colorPrev = colorSelected - colorSelected = 0 - } - - mousePressed = true - - rl.BeginTextureMode(target) - if mousePos.Y > 50 { - rl.DrawCircle(int32(mousePos.X), int32(mousePos.Y), brushSize, colors[0]) - } - rl.EndTextureMode() - } else if rl.IsMouseButtonReleased(rl.MouseButtonRight) && mousePressed { - colorSelected = colorPrev - mousePressed = false - } - - if rl.CheckCollisionPointRec(mousePos, btnSaveRec) { - btnSaveMouseHover = true - } else { - btnSaveMouseHover = false - } - - if btnSaveMouseHover && rl.IsMouseButtonReleased(rl.MouseButtonLeft) || rl.IsKeyPressed(rl.KeyS) { - image := rl.LoadImageFromTexture(target.Texture) - rl.ImageFlipVertical(image) - rl.ExportImage(*image, "raylib_mouse_painting.png") - rl.UnloadImage(image) - showSaveMsg = true - } - - if showSaveMsg { - saveMsgCount++ - if saveMsgCount > 240 { - showSaveMsg = false - saveMsgCount = 0 - } - } - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawTextureRec(target.Texture, rl.NewRectangle(0, 0, float32(target.Texture.Width), -float32(target.Texture.Height)), rl.Vector2Zero(), rl.White) - - if mousePos.Y > 50 { - if rl.IsMouseButtonDown(rl.MouseButtonRight) { - rl.DrawCircleLines(int32(mousePos.X), int32(mousePos.Y), brushSize, rl.Gray) - } else { - rl.DrawCircle(rl.GetMouseX(), rl.GetMouseY(), brushSize, colors[colorSelected]) - } - } - - rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), 50, rl.RayWhite) - rl.DrawLine(0, 50, int32(rl.GetScreenWidth()), 50, rl.LightGray) - - for i := 0; i < len(colors); i++ { - rl.DrawRectangleRec(colorRecs[i], colors[i]) - } - - rl.DrawRectangleLines(10, 10, 30, 30, rl.LightGray) - - if colorMouseHover >= 0 { - rl.DrawRectangleRec(colorRecs[colorMouseHover], rl.Fade(rl.White, 0.6)) - } - - rl.DrawRectangleLinesEx(rl.NewRectangle(colorRecs[colorSelected].X-2, colorRecs[colorSelected].Y-2, colorRecs[colorSelected].Width+4, colorRecs[colorSelected].Height+4), 2, rl.Black) - - if btnSaveMouseHover { - rl.DrawRectangleLinesEx(btnSaveRec, 2, rl.Red) - rl.DrawText("SAVE!", 755, 20, 10, rl.Red) - } else { - rl.DrawRectangleLinesEx(btnSaveRec, 2, rl.Black) - rl.DrawText("SAVE!", 755, 20, 10, rl.Black) - } - - if showSaveMsg { - rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), int32(rl.GetScreenHeight()), rl.Fade(rl.RayWhite, 0.8)) - rl.DrawRectangle(0, screenH/2-40, int32(rl.GetScreenWidth()), 80, rl.Black) - txt := "IMG SAVED" - txtlen := rl.MeasureText(txt, 20) - rl.DrawText(txt, screenW/2-txtlen/2, screenH/2-10, 20, rl.RayWhite) - } - - rl.DrawText("hold left mouse to draw right mouse to erase | mouse wheel up/down arrows change brush size | right/left arrows change color | c key to clear", 10, screenH-15, 10, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadRenderTexture(target) - - rl.CloseWindow() -} diff --git a/examples/textures/npatch_drawing/main.go b/examples/textures/npatch_drawing/main.go deleted file mode 100644 index 43bfe6b..0000000 --- a/examples/textures/npatch_drawing/main.go +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************************* -* -* raylib [textures] example - N-patch drawing -* -* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM) -* -* Example originally created with raylib 2.0, last time updated with raylib 2.5 -* -* Example contributed by Jorge A. Gomes (@overdev) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2018-2024 Jorge A. Gomes (@overdev) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - N-patch drawing") - - // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - nPatchTexture := rl.LoadTexture("ninepatch_button.png") - - var mousePosition rl.Vector2 - var origin rl.Vector2 - - // Position and size of the n-patches - dstRec1 := rl.Rectangle{X: 480.0, Y: 160.0, Width: 32.0, Height: 32.0} - dstRec2 := rl.Rectangle{X: 160.0, Y: 160.0, Width: 32.0, Height: 32.0} - dstRecH := rl.Rectangle{X: 160.0, Y: 93.0, Width: 32.0, Height: 32.0} - dstRecV := rl.Rectangle{X: 92.0, Y: 160.0, Width: 32.0, Height: 32.0} - - // A 9-patch (NPatchNinePatch) changes its sizes in both axis - ninePatchInfo1 := rl.NPatchInfo{ - Source: rl.Rectangle{Width: 64.0, Height: 64.0}, - Left: 12, - Top: 40, - Right: 12, - Bottom: 12, - Layout: rl.NPatchNinePatch, - } - ninePatchInfo2 := rl.NPatchInfo{ - Source: rl.Rectangle{Y: 128.0, Width: 64.0, Height: 64.0}, - Left: 16, - Top: 16, - Right: 16, - Bottom: 16, - Layout: rl.NPatchNinePatch, - } - - // A horizontal 3-patch (NPatchThreePatchHorizontal) changes its sizes along the x-axis only - h3PatchInfo := rl.NPatchInfo{ - Source: rl.Rectangle{Y: 64.0, Width: 64.0, Height: 64.0}, - Left: 8, - Top: 8, - Right: 8, - Bottom: 8, - Layout: rl.NPatchThreePatchHorizontal, - } - - // A vertical 3-patch (NPatchThreePatchVertical) changes its sizes along the y-axis only - v3PatchInfo := rl.NPatchInfo{ - Source: rl.Rectangle{Y: 192.0, Width: 64.0, Height: 64.0}, - Left: 6, - Top: 6, - Right: 6, - Bottom: 6, - Layout: rl.NPatchThreePatchVertical, - } - - rl.SetTargetFPS(60) - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - mousePosition = rl.GetMousePosition() - - // Resize the n-patches based on mouse position - dstRec1.Width = mousePosition.X - dstRec1.X - dstRec1.Height = mousePosition.Y - dstRec1.Y - dstRec2.Width = mousePosition.X - dstRec2.X - dstRec2.Height = mousePosition.Y - dstRec2.Y - dstRecH.Width = mousePosition.X - dstRecH.X - dstRecV.Height = mousePosition.Y - dstRecV.Y - - // Set a minimum Width and/or Height - dstRec1.Width = clamp(dstRec1.Width, 1, 300) - dstRec1.Height = clamp(dstRec1.Height, 1, screenHeight) - dstRec2.Width = clamp(dstRec2.Width, 1, 300) - dstRec2.Height = clamp(dstRec2.Height, 1, screenHeight) - dstRecH.Width = clamp(dstRecH.Width, 1, screenWidth) - dstRecV.Height = clamp(dstRecV.Height, 1, screenHeight) - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - // Draw the n-patches - rl.DrawTextureNPatch(nPatchTexture, ninePatchInfo2, dstRec2, origin, 0.0, rl.White) - rl.DrawTextureNPatch(nPatchTexture, ninePatchInfo1, dstRec1, origin, 0.0, rl.White) - rl.DrawTextureNPatch(nPatchTexture, h3PatchInfo, dstRecH, origin, 0.0, rl.White) - rl.DrawTextureNPatch(nPatchTexture, v3PatchInfo, dstRecV, origin, 0.0, rl.White) - - // Draw the source texture - rl.DrawRectangleLines(5, 88, 74, 266, rl.Blue) - rl.DrawTexture(nPatchTexture, 10, 93, rl.White) - rl.DrawText("TEXTURE", 15, 360, 10, rl.DarkGray) - - rl.DrawText("Move the mouse to stretch or shrink the n-patches", 10, 20, 20, rl.DarkGray) - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadTexture(nPatchTexture) // Texture unloading - rl.CloseWindow() // Close window and OpenGL context -} - -func clamp(value, min, max float32) float32 { - if value < min { - return min - } - if value > max { - return max - } - return value -} diff --git a/examples/textures/npatch_drawing/ninepatch_button.png b/examples/textures/npatch_drawing/ninepatch_button.png deleted file mode 100644 index f10037a..0000000 Binary files a/examples/textures/npatch_drawing/ninepatch_button.png and /dev/null differ diff --git a/examples/textures/particles_blending/main.go b/examples/textures/particles_blending/main.go index 8b4b7ca..414d700 100644 --- a/examples/textures/particles_blending/main.go +++ b/examples/textures/particles_blending/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( diff --git a/examples/textures/raw_data/main.go b/examples/textures/raw_data/main.go index c950d51..714d1f0 100644 --- a/examples/textures/raw_data/main.go +++ b/examples/textures/raw_data/main.go @@ -1,7 +1,7 @@ package main import ( - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { diff --git a/examples/textures/textures_sprite_anim/main.go b/examples/textures/rectangle/main.go similarity index 98% rename from examples/textures/textures_sprite_anim/main.go rename to examples/textures/rectangle/main.go index dfa715d..795989b 100644 --- a/examples/textures/textures_sprite_anim/main.go +++ b/examples/textures/rectangle/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) const ( diff --git a/examples/textures/textures_sprite_anim/scarfy.png b/examples/textures/rectangle/scarfy.png similarity index 100% rename from examples/textures/textures_sprite_anim/scarfy.png rename to examples/textures/rectangle/scarfy.png diff --git a/examples/textures/sprite_button/button.png b/examples/textures/sprite_button/button.png deleted file mode 100644 index 99a383b..0000000 Binary files a/examples/textures/sprite_button/button.png and /dev/null differ diff --git a/examples/textures/sprite_button/buttonfx.wav b/examples/textures/sprite_button/buttonfx.wav deleted file mode 100644 index b93b0ca..0000000 Binary files a/examples/textures/sprite_button/buttonfx.wav and /dev/null differ diff --git a/examples/textures/sprite_button/main.go b/examples/textures/sprite_button/main.go deleted file mode 100644 index dc685e8..0000000 --- a/examples/textures/sprite_button/main.go +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************************* -* -* raylib [textures] example - sprite button -* -* Example originally created with raylib 2.5, last time updated with raylib 2.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2019-2024 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ -package main - -import rl "git.terah.dev/UnrealXR/raylib-go/raylib" - -const ( - screenWidth = 800 - screenHeight = 450 - numFrames = 3 // Number of frames (rectangles) for the button sprite texture -) - -func main() { - rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - sprite button") - - rl.InitAudioDevice() // Initialize audio device - - fxButton := rl.LoadSound("buttonfx.wav") // Load button sound - button := rl.LoadTexture("button.png") // Load button texture - - // Define frame rectangle for drawing - frameHeight := float32(button.Height) / numFrames - sourceRec := rl.Rectangle{Width: float32(button.Width), Height: frameHeight} - - // Define button bounds on screen - btnBounds := rl.Rectangle{ - X: float32(screenWidth/2.0 - button.Width/2.0), - Y: float32(screenHeight/2.0 - button.Height/numFrames/2.0), - Width: float32(button.Width), - Height: frameHeight, - } - - btnState := 0 // Button state: 0-NORMAL, 1-MOUSE_HOVER, 2-PRESSED - btnAction := false // Button action should be activated - - rl.SetTargetFPS(60) - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - mousePoint := rl.GetMousePosition() - btnAction = false - - // Check button state - if rl.CheckCollisionPointRec(mousePoint, btnBounds) { - if rl.IsMouseButtonDown(rl.MouseButtonLeft) { - btnState = 2 - } else { - btnState = 1 - } - - if rl.IsMouseButtonReleased(rl.MouseButtonLeft) { - btnAction = true - } - } else { - - btnState = 0 - } - - if btnAction { - rl.PlaySound(fxButton) - - // TODO: Any desired action - } - - // Calculate button frame rectangle to draw depending on button state - sourceRec.Y = float32(btnState) * frameHeight - - // Draw - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawTextureRec(button, sourceRec, rl.Vector2{X: btnBounds.X, Y: btnBounds.Y}, rl.White) // Draw button frame - - rl.EndDrawing() - } - - // De-Initialization - rl.UnloadTexture(button) // Unload button texture - rl.UnloadSound(fxButton) // Unload sound - - rl.CloseAudioDevice() // Close audio device - - rl.CloseWindow() // Close window and OpenGL context -} diff --git a/examples/textures/sprite_explosion/boom.wav b/examples/textures/sprite_explosion/boom.wav deleted file mode 100644 index fd18137..0000000 Binary files a/examples/textures/sprite_explosion/boom.wav and /dev/null differ diff --git a/examples/textures/sprite_explosion/explosion.png b/examples/textures/sprite_explosion/explosion.png deleted file mode 100644 index 6df1cf3..0000000 Binary files a/examples/textures/sprite_explosion/explosion.png and /dev/null differ diff --git a/examples/textures/sprite_explosion/main.go b/examples/textures/sprite_explosion/main.go deleted file mode 100644 index 8cd487f..0000000 --- a/examples/textures/sprite_explosion/main.go +++ /dev/null @@ -1,82 +0,0 @@ -package main - -import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - numFramesPerLine, numLines = 5, 5 -) - -func main() { - screenWidth := int32(1280) - screenHeight := int32(720) - - rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - sprite explosion") - - rl.InitAudioDevice() - fxBoom := rl.LoadSound("boom.wav") - explosion := rl.LoadTexture("explosion.png") - - frameW := float32(explosion.Width / int32(numFramesPerLine)) - frameH := float32(explosion.Height / int32(numLines)) - - currentFrame, currentLine := 0, 0 - - frameRec := rl.NewRectangle(0, 0, frameW, frameH) - position := rl.NewVector2(0, 0) - - active := false - framesCount := 0 - - rl.SetTargetFPS(120) - - for !rl.WindowShouldClose() { - - if rl.IsMouseButtonPressed(rl.MouseLeftButton) && !active { - position = rl.GetMousePosition() - active = true - position.X -= frameW / 2 - position.Y -= frameH / 2 - rl.PlaySound(fxBoom) - } - - if active { - framesCount++ - if framesCount > 2 { - currentFrame++ - if currentFrame >= numFramesPerLine { - currentFrame = 0 - currentLine++ - if currentLine >= numLines { - currentLine = 0 - active = false - } - } - - framesCount = 0 - } - } - - frameRec.X = frameW * float32(currentFrame) - frameRec.Y = frameH * float32(currentLine) - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - rl.DrawText("click left mouse on screen to explode", 19, 21, 20, rl.Red) - rl.DrawText("click left mouse on screen to explode", 20, 20, 20, rl.Black) - - if active { - rl.DrawTextureRec(explosion, frameRec, position, rl.White) - } - - rl.EndDrawing() - } - - rl.UnloadTexture(explosion) - rl.UnloadSound(fxBoom) - rl.CloseAudioDevice() - - rl.CloseWindow() -} diff --git a/examples/textures/srcrec_dstrec/main.go b/examples/textures/srcrec_dstrec/main.go index c51181a..80768a2 100644 --- a/examples/textures/srcrec_dstrec/main.go +++ b/examples/textures/srcrec_dstrec/main.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/gen2brain/raylib-go/raylib" +) + func main() { screenWidth := int32(800) screenHeight := int32(450) diff --git a/examples/textures/textured_curve/main.go b/examples/textures/textured_curve/main.go deleted file mode 100644 index 67f0914..0000000 --- a/examples/textures/textured_curve/main.go +++ /dev/null @@ -1,201 +0,0 @@ -package main - -import ( - "fmt" - "math" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -var ( - texRoad rl.Texture2D - showCurve = true - curveW = float32(50) - curveSegments = 24 - - curveStartPos, curveStartPosTangent, curveEndPos, curveEndPosTangent rl.Vector2 - - curveSelectedPoint *rl.Vector2 - - screenW = int32(800) - screenH = int32(450) -) - -func main() { - - rl.SetConfigFlags(rl.FlagVsyncHint | rl.FlagMsaa4xHint) - - rl.InitWindow(screenW, screenH, "raylib [textures] example - textured curve") - - texRoad = rl.LoadTexture("road.png") - rl.SetTextureFilter(texRoad, rl.TextureFilterMode(rl.FilterBilinear)) - - curveStartPos = rl.NewVector2(80, 100) - curveStartPosTangent = rl.NewVector2(100, 300) - - curveEndPos = rl.NewVector2(700, 350) - curveEndPosTangent = rl.NewVector2(600, 100) - - rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - - upCurve() - upOptions() - - rl.BeginDrawing() - rl.ClearBackground(rl.RayWhite) - - drawTexturedCurve() - drawCurve() - - rl.DrawText("Drag points to move curve, press SPACE to show/hide base curve", 10, 10, 10, rl.Black) - rl.DrawText("Curve width: "+fmt.Sprintf("%.0f", curveW)+" use UP/DOWN arrows to adjust", 10, 30, 10, rl.Black) - rl.DrawText("Curve segments: "+fmt.Sprint(curveSegments)+" use RIGHT/LEFT arrows to adjust", 10, 50, 10, rl.Black) - - rl.EndDrawing() - } - - rl.UnloadTexture(texRoad) - - rl.CloseWindow() -} - -func upCurve() { - - if !rl.IsMouseButtonDown(rl.MouseLeftButton) { - curveSelectedPoint = &rl.Vector2{} - } - - *curveSelectedPoint = rl.Vector2Add(*curveSelectedPoint, rl.GetMouseDelta()) - - mouse := rl.GetMousePosition() - - if rl.CheckCollisionPointCircle(mouse, curveStartPos, 6) { - curveSelectedPoint = &curveStartPos - } else if rl.CheckCollisionPointCircle(mouse, curveStartPosTangent, 6) { - curveSelectedPoint = &curveStartPosTangent - } else if rl.CheckCollisionPointCircle(mouse, curveEndPos, 6) { - curveSelectedPoint = &curveEndPos - } else if rl.CheckCollisionPointCircle(mouse, curveEndPosTangent, 6) { - curveSelectedPoint = &curveEndPosTangent - } - -} -func upOptions() { - - if rl.IsKeyPressed(rl.KeySpace) { - showCurve = !showCurve - } - if rl.IsKeyPressed(rl.KeyUp) { - curveW += 2 - } - if rl.IsKeyPressed(rl.KeyDown) { - curveW -= 2 - } - if curveW < 2 { - curveW = 2 - } - if rl.IsKeyPressed(rl.KeyLeft) { - curveSegments -= 2 - } - if rl.IsKeyPressed(rl.KeyRight) { - curveSegments += 2 - } - if curveSegments < 2 { - curveSegments = 2 - } - -} -func drawTexturedCurve() { - - step := float32(1) / float32(curveSegments) - previous := curveStartPos - previousTangent := rl.Vector2Zero() - previousV := float32(0) - tangentSet := false - current := rl.Vector2Zero() - t := float32(0) - - for i := 0; i < curveSegments; i++ { - t = step * float32(i) - a := float32(math.Pow(1-float64(t), 3)) - b := 3 * float32(math.Pow(1-float64(t), 2)) * t - c := 3 * (1 - t) * float32(math.Pow(float64(t), 2)) - d := float32(math.Pow(float64(t), 3)) - - current.Y = a*curveStartPos.Y + b*curveStartPosTangent.Y + c*curveEndPosTangent.Y + d*curveEndPos.Y - current.X = a*curveStartPos.X + b*curveStartPosTangent.X + c*curveEndPosTangent.X + d*curveEndPos.X - - delta := rl.NewVector2(current.X-previous.X, current.Y-previous.Y) - normal := rl.Vector2Normalize(rl.NewVector2(-delta.Y, delta.X)) - v := previousV + rl.Vector2Length(delta) - - if !tangentSet { - previousTangent = normal - tangentSet = true - } - - prevPosNormal := rl.Vector2Add(previous, rl.Vector2Scale(previousTangent, curveW)) - prevNegNormal := rl.Vector2Add(previous, rl.Vector2Scale(previousTangent, -curveW)) - - currentPosNormal := rl.Vector2Add(current, rl.Vector2Scale(normal, curveW)) - currentNegNormal := rl.Vector2Add(current, rl.Vector2Scale(normal, -curveW)) - - rl.SetTexture(texRoad.ID) - rl.Begin(rl.Quads) - - rl.Color4ub(255, 255, 255, 255) - rl.Normal3f(0, 0, 1) - - rl.TexCoord2f(0, previousV) - rl.Vertex2f(prevNegNormal.X, prevNegNormal.Y) - - rl.TexCoord2f(1, previousV) - rl.Vertex2f(prevPosNormal.X, prevPosNormal.Y) - - rl.TexCoord2f(1, v) - rl.Vertex2f(currentPosNormal.X, currentPosNormal.Y) - - rl.TexCoord2f(0, v) - rl.Vertex2f(currentNegNormal.X, currentNegNormal.Y) - - rl.End() - - previous = current - previousTangent = normal - previousV = v - - } - -} -func drawCurve() { - - if showCurve { - rl.DrawSplineSegmentBezierCubic(curveStartPos, curveEndPos, curveStartPosTangent, curveEndPosTangent, 2, rl.Blue) - } - rl.DrawLineV(curveStartPos, curveStartPosTangent, rl.SkyBlue) - rl.DrawLineV(curveEndPos, curveEndPosTangent, rl.Purple) - mouse := rl.GetMousePosition() - - if rl.CheckCollisionPointCircle(mouse, curveStartPos, 6) { - rl.DrawCircleV(curveStartPos, 7, rl.Yellow) - } - rl.DrawCircleV(curveStartPos, 5, rl.Red) - - if rl.CheckCollisionPointCircle(mouse, curveStartPosTangent, 6) { - rl.DrawCircleV(curveStartPosTangent, 7, rl.Yellow) - } - rl.DrawCircleV(curveStartPosTangent, 5, rl.Maroon) - - if rl.CheckCollisionPointCircle(mouse, curveEndPos, 6) { - rl.DrawCircleV(curveEndPos, 7, rl.Yellow) - } - rl.DrawCircleV(curveEndPosTangent, 5, rl.Green) - - if rl.CheckCollisionPointCircle(mouse, curveEndPosTangent, 6) { - rl.DrawCircleV(curveEndPosTangent, 7, rl.Yellow) - } - rl.DrawCircleV(curveEndPosTangent, 5, rl.DarkGreen) - -} diff --git a/examples/textures/textured_curve/road.png b/examples/textures/textured_curve/road.png deleted file mode 100644 index 082f4cd..0000000 Binary files a/examples/textures/textured_curve/road.png and /dev/null differ diff --git a/examples/textures/textures_gif_player/main.go b/examples/textures/textures_gif_player/main.go deleted file mode 100644 index 51d1275..0000000 --- a/examples/textures/textures_gif_player/main.go +++ /dev/null @@ -1,113 +0,0 @@ -package main - -import ( - "fmt" - "image/color" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" -) - -func main() { - - const MAX_FRAME_DELAY int32 = 20 - const MIN_FRAME_DELAY int32 = 1 - - // Initialization - const screenWidth int32 = 800 - const screenHeight int32 = 450 - - rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - gif playing") - - var animFrames int32 = 0 - - // Load all GIF animation frames into a single Image - // NOTE: GIF data is always loaded as RGBA (32bit) by default - // NOTE: Frames are just appended one after another in image.data memory - var imScarfyAnim *rl.Image = rl.LoadImageAnim("scarfy_run.gif", &animFrames) - - // Load texture from image - // NOTE: We will update this texture when required with next frame data - // WARNING: It's not recommended to use this technique for sprites animation, - // use spritesheets instead, like illustrated in textures_sprite_anim example - var texScarfyAnim rl.Texture2D = rl.LoadTextureFromImage(imScarfyAnim) - var texScarfyAnimSize int32 = imScarfyAnim.Width * imScarfyAnim.Height - - var nextFrameDataOffset uint32 = 0 // Current byte offset to next frame in image.data - var currentAnimFrame int32 = 0 // Current animation frame to load and draw - var frameDelay int32 = 8 // Frame delay to switch between animation frames - var frameCounter int32 = 0 // General frames counter - - rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - - // Main game loop - for !rl.WindowShouldClose() { // Detect window close button or ESC key - // Update - frameCounter++ - - if frameCounter >= frameDelay { - // Move to next frame - // NOTE: If final frame is reached we return to first frame - currentAnimFrame++ - if currentAnimFrame >= animFrames { - currentAnimFrame = 0 - } - - // Get memory offset position for next frame data in image.data - nextFrameDataOffset = uint32(imScarfyAnim.Width * imScarfyAnim.Height * int32(4) * currentAnimFrame) - // Update GPU texture data with next frame image data - // WARNING: Data size (frame size) and pixel format must match already created texture - // here we needed to make the Data as public - rl.UpdateTexture(texScarfyAnim, - unsafe.Slice((*color.RGBA)(unsafe.Pointer(uintptr(imScarfyAnim.Data)+uintptr(nextFrameDataOffset))), texScarfyAnimSize)) - - frameCounter = 0 - } - - // Control frames delay - if rl.IsKeyPressed(rl.KeyRight) { - frameDelay++ - } else if rl.IsKeyPressed(rl.KeyLeft) { - frameDelay-- - } - - if frameDelay > MAX_FRAME_DELAY { - frameDelay = MAX_FRAME_DELAY - } else if frameDelay < MIN_FRAME_DELAY { - frameDelay = MIN_FRAME_DELAY - } - - // Draw - rl.BeginDrawing() - - rl.ClearBackground(rl.RayWhite) - - rl.DrawText(fmt.Sprintf("TOTAL GIF FRAMES: %02d", animFrames), 50, 30, 20, rl.LightGray) - rl.DrawText(fmt.Sprintf("CURRENT FRAME: %02d", currentAnimFrame), 50, 60, 20, rl.Gray) - rl.DrawText(fmt.Sprintf("CURRENT FRAME IMAGE.DATA OFFSET: %02d", nextFrameDataOffset), 50, 90, 20, rl.Gray) - - rl.DrawText("FRAMES DELAY: ", 100, 305, 10, rl.DarkGray) - rl.DrawText(fmt.Sprintf("%02d frames", frameDelay), 620, 305, 10, rl.DarkGray) - rl.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 350, 10, rl.DarkGray) - - for i := int32(0); i < MAX_FRAME_DELAY; i++ { - if i < frameDelay { - rl.DrawRectangle(190+21*i, 300, 20, 20, rl.Red) - } - rl.DrawRectangleLines(190+21*i, 300, 20, 20, rl.Maroon) - } - - rl.DrawTexture(texScarfyAnim, int32(rl.GetScreenWidth()/2)-texScarfyAnim.Width/2, 140, rl.White) - - rl.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, rl.Gray) - - rl.EndDrawing() - } - - // De-Initialization - defer rl.UnloadTexture(texScarfyAnim) // Unload texture - defer rl.UnloadImage(imScarfyAnim) // Unload image (contains all frames) - - defer rl.CloseWindow() // Close window and OpenGL context - -} diff --git a/examples/textures/textures_gif_player/scarfy_run.gif b/examples/textures/textures_gif_player/scarfy_run.gif deleted file mode 100644 index f0f712c..0000000 Binary files a/examples/textures/textures_gif_player/scarfy_run.gif and /dev/null differ diff --git a/examples/textures/to_image/main.go b/examples/textures/to_image/main.go index a65d4d1..8a88453 100644 --- a/examples/textures/to_image/main.go +++ b/examples/textures/to_image/main.go @@ -1,7 +1,7 @@ package main import ( - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) func main() { @@ -14,8 +14,8 @@ func main() { texture := rl.LoadTextureFromImage(image) // Image converted to texture, GPU memory (RAM -> VRAM) rl.UnloadImage(image) // Unload image data from CPU memory (RAM) - image = rl.LoadImageFromTexture(texture) // Retrieve image data from GPU memory (VRAM -> RAM) - rl.UnloadTexture(texture) // Unload texture from GPU memory (VRAM) + image = rl.GetTextureData(texture) // Retrieve image data from GPU memory (VRAM -> RAM) + rl.UnloadTexture(texture) // Unload texture from GPU memory (VRAM) texture = rl.LoadTextureFromImage(image) // Recreate texture from retrieved image data (RAM -> VRAM) rl.UnloadImage(image) // Unload retrieved image data from CPU memory (RAM) diff --git a/physics/README.md b/physics/README.md index 851f199..b86c883 100644 --- a/physics/README.md +++ b/physics/README.md @@ -1,5 +1,5 @@ -## physics [![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/physics?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/physics) +## physics [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/physics?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/physics) 2D Physics library for videogames. -A port of Victor Fisac's [physac engine](https://github.com/raysan5/physac/blob/master/src/physac.h). +A port of Victor Fisac's [physac engine](https://github.com/raysan5/raylib/blob/master/src/physac.h). diff --git a/physics/go.mod b/physics/go.mod deleted file mode 100644 index 67b71a1..0000000 --- a/physics/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module git.terah.dev/UnrealXR/raylib-go/physics - -go 1.21 - -require git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b - -require ( - github.com/ebitengine/purego v0.8.1 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/sys v0.27.0 // indirect -) diff --git a/physics/go.sum b/physics/go.sum deleted file mode 100644 index 62eb5f5..0000000 --- a/physics/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= -github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b h1:wK8D9x3f+BX1xFGgjj399dYx2eskikDZHxlRaSSA19Q= -git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/physics/physics.go b/physics/physics.go index 0e57c95..fc61a7f 100644 --- a/physics/physics.go +++ b/physics/physics.go @@ -5,10 +5,8 @@ package physics import ( "math" - "math/rand" - "time" - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/gen2brain/raylib-go/raylib" ) // ShapeType type @@ -27,9 +25,11 @@ type Polygon struct { // Current used vertex and normals count VertexCount int // Polygon vertex positions vectors - Positions [maxVertices]rl.Vector2 + Vertices [maxVertices]rl.Vector2 // Polygon vertex normals vectors Normals [maxVertices]rl.Vector2 + // Vertices transform matrix 2x2 + Transform rl.Mat2 } // Shape type @@ -40,16 +40,12 @@ type Shape struct { Body *Body // Circle shape radius (used for circle shapes) Radius float32 - // Vertices transform matrix 2x2 - Transform rl.Mat2 // Polygon shape vertices position and normals data (just used for polygon shapes) VertexData Polygon } // Body type type Body struct { - // Reference unique identifier - ID int // Enabled dynamics state (collisions are calculated anyway) Enabled bool // Physics body shape pivot @@ -88,10 +84,8 @@ type Body struct { Shape Shape } -// Manifold type -type Manifold struct { - // Reference unique identifier - ID int +// manifold type +type manifold struct { // Manifold first physics body reference BodyA *Body // Manifold second physics body reference @@ -114,8 +108,9 @@ type Manifold struct { // Constants const ( - maxBodies = 64 - maxManifolds = 4096 + maxBodies = 64 + maxManifolds = 4096 + maxVertices = 24 circleVertices = 24 @@ -123,51 +118,37 @@ const ( penetrationAllowance = 0.05 penetrationCorrection = 0.4 - degToRad = math.Pi / 180 - epsilon = 0.000001 - physacK = 1.0 / 3.0 + fltMax = 3.402823466 + 38 + epsilon = 0.000001 ) // Globals var ( - // Offset time for MONOTONIC clock - baseTime = time.Now() + // Physics bodies pointers + bodies []*Body - // Start time in milliseconds - startTime float32 - - // Delta time used for physics steps, in milliseconds - deltaTime float32 = 1.0 / 60.0 / 10.0 * 1000 - - // Current time in milliseconds - currentTime float32 - - // Hi-res clock frequency - frequency uint64 = 0 - - // Physics time step delta time accumulator - accumulator float32 + // Physics manifolds pointers + manifolds []*manifold // Physics world gravity force - gravityForce = rl.NewVector2(0, 9.81) + gravityForce rl.Vector2 - // Physics bodies pointers array - bodies [64]*Body - - // Physics world current bodies counter - bodiesCount int - - // Physics bodies pointers array - manifolds [4096]*Manifold - - // Physics world current manifolds counter - manifoldsCount int + // Delta time used for physics steps, in milliseconds + deltaTime float32 ) -// Init - Initializes physics values, pointers and creates physics loop thread +// Init - initializes physics values func Init() { - initTimer() - accumulator = 0 + deltaTime = 1.0 / 60.0 / 10.0 * 1000 + gravityForce = rl.NewVector2(0, 9.81) + + bodies = make([]*Body, 0, maxBodies) + manifolds = make([]*manifold, 0, maxManifolds) +} + +// Sets physics fixed time step in milliseconds. 1.666666 by default +func SetPhysicsTimeStep(delta float32) { + deltaTime = delta } // SetGravity - Sets physics global gravity force @@ -178,89 +159,41 @@ func SetGravity(x, y float32) { // NewBodyCircle - Creates a new circle physics body with generic parameters func NewBodyCircle(pos rl.Vector2, radius, density float32) *Body { - newID := findAvailableBodyIndex() - if newID < 0 { - return nil - } - - // Initialize new body with generic values - newBody := &Body{ - ID: newID, - Enabled: true, - Position: pos, - Velocity: rl.Vector2{}, - Force: rl.Vector2{}, - AngularVelocity: 0.0, - Torque: 0.0, - Orient: 0.0, - Shape: Shape{ - Type: CircleShape, - Radius: radius, - Transform: rl.Mat2Radians(0.0), - VertexData: Polygon{}, - }, - StaticFriction: 0.4, - DynamicFriction: 0.2, - Restitution: 0.0, - UseGravity: true, - IsGrounded: false, - FreezeOrient: false, - } - - newBody.Shape.Body = newBody - - newBody.Mass = math.Pi * radius * radius * density - newBody.InverseMass = safeDiv(1.0, newBody.Mass) - newBody.Inertia = newBody.Mass * radius * radius - newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) - - // Add new body to bodies pointers array and update bodies count - bodies[bodiesCount] = newBody - bodiesCount++ - return newBody + return NewBodyPolygon(pos, radius, circleVertices, density) } // NewBodyRectangle - Creates a new rectangle physics body with generic parameters func NewBodyRectangle(pos rl.Vector2, width, height, density float32) *Body { - newID := findAvailableBodyIndex() - if newID < 0 { - return nil - } + newBody := &Body{} // Initialize new body with generic values - newBody := &Body{ - ID: newID, - Enabled: true, - Position: pos, - Velocity: rl.Vector2{}, - Force: rl.Vector2{}, - AngularVelocity: 0.0, - Torque: 0.0, - Orient: 0.0, - Shape: Shape{ - Type: PolygonShape, - Transform: rl.Mat2Radians(0.0), - VertexData: createRectanglePolygon(pos, rl.NewVector2(width, height)), - }, - StaticFriction: 0.4, - DynamicFriction: 0.2, - Restitution: 0.0, - UseGravity: true, - IsGrounded: false, - FreezeOrient: false, - } + newBody.Enabled = true + newBody.Position = pos + newBody.Velocity = rl.Vector2{} + newBody.Force = rl.Vector2{} + newBody.AngularVelocity = 0 + newBody.Torque = 0 + newBody.Orient = 0 + + newBody.Shape = Shape{} + newBody.Shape.Type = PolygonShape + newBody.Shape.Body = newBody + newBody.Shape.VertexData = newRectanglePolygon(pos, rl.NewVector2(width, height)) // Calculate centroid and moment of inertia - newBody.Shape.Body = newBody - var center rl.Vector2 + center := rl.Vector2{} area := float32(0.0) inertia := float32(0.0) + k := float32(1.0) / 3.0 for i := 0; i < newBody.Shape.VertexData.VertexCount; i++ { // Triangle vertices, third vertex implied as (0, 0) - nextIndex := getNextIndex(i, newBody.Shape.VertexData.VertexCount) - p1 := newBody.Shape.VertexData.Positions[i] - p2 := newBody.Shape.VertexData.Positions[nextIndex] + p1 := newBody.Shape.VertexData.Vertices[i] + nextIndex := 0 + if i+1 < newBody.Shape.VertexData.VertexCount { + nextIndex = i + 1 + } + p2 := newBody.Shape.VertexData.Vertices[nextIndex] D := rl.Vector2CrossProduct(p1, p2) triangleArea := D / 2 @@ -268,77 +201,79 @@ func NewBodyRectangle(pos rl.Vector2, width, height, density float32) *Body { area += triangleArea // Use area to weight the centroid average, not just vertex position - center.X += triangleArea * physacK * (p1.X + p2.X) - center.Y += triangleArea * physacK * (p1.Y + p2.Y) + center.X += triangleArea * k * (p1.X + p2.X) + center.Y += triangleArea * k * (p1.Y + p2.Y) - var intx2 float32 = p1.X*p1.X + p2.X*p1.X + p2.X*p2.X - var inty2 float32 = p1.Y*p1.Y + p2.Y*p1.Y + p2.Y*p2.Y - inertia += (0.25 * physacK * D) * (intx2 + inty2) + intx2 := p1.X*p1.X + p2.X*p1.X + p2.X*p2.X + inty2 := p1.Y*p1.Y + p2.Y*p1.Y + p2.Y*p2.Y + inertia += (0.25 * k * D) * (intx2 + inty2) } center.X *= 1.0 / area center.Y *= 1.0 / area // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary + // NOTE: this is not really necessary for i := 0; i < newBody.Shape.VertexData.VertexCount; i++ { - newBody.Shape.VertexData.Positions[i].X -= center.X - newBody.Shape.VertexData.Positions[i].Y -= center.Y + newBody.Shape.VertexData.Vertices[i].X -= center.X + newBody.Shape.VertexData.Vertices[i].Y -= center.Y } newBody.Mass = density * area - newBody.InverseMass = safeDiv(1.0, newBody.Mass) newBody.Inertia = density * inertia - newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) + newBody.StaticFriction = 0.4 + newBody.DynamicFriction = 0.2 + newBody.Restitution = 0 + newBody.UseGravity = true + newBody.IsGrounded = false + newBody.FreezeOrient = false + + if newBody.Mass != 0 { + newBody.InverseMass = 1.0 / newBody.Mass + } + + if newBody.Inertia != 0 { + newBody.InverseInertia = 1.0 / newBody.Inertia + } + + // Add new body to bodies pointers + bodies = append(bodies, newBody) - // Add new body to bodies pointers array and update bodies count - bodies[bodiesCount] = newBody - bodiesCount++ return newBody } // NewBodyPolygon - Creates a new polygon physics body with generic parameters func NewBodyPolygon(pos rl.Vector2, radius float32, sides int, density float32) *Body { - newID := findAvailableBodyIndex() - if newID < 0 { - return nil - } + newBody := &Body{} // Initialize new body with generic values - newBody := &Body{ - ID: newID, - Enabled: true, - Position: pos, - Velocity: rl.Vector2{}, - Force: rl.Vector2{}, - AngularVelocity: 0.0, - Torque: 0.0, - Orient: 0.0, - Shape: Shape{ - Type: PolygonShape, - Transform: rl.Mat2Radians(0), - VertexData: createRandomPolygon(radius, sides), - }, - StaticFriction: 0.4, - DynamicFriction: 0.2, - Restitution: 0.0, - UseGravity: true, - IsGrounded: false, - FreezeOrient: false, - } + newBody.Enabled = true + newBody.Position = pos + newBody.Velocity = rl.Vector2{} + newBody.Force = rl.Vector2{} + newBody.AngularVelocity = 0 + newBody.Torque = 0 + newBody.Orient = 0 + newBody.Shape = Shape{} + newBody.Shape.Type = PolygonShape newBody.Shape.Body = newBody + newBody.Shape.VertexData = newRandomPolygon(radius, sides) // Calculate centroid and moment of inertia - var center rl.Vector2 + center := rl.Vector2{} area := float32(0.0) inertia := float32(0.0) + alpha := float32(1.0) / 3.0 for i := 0; i < newBody.Shape.VertexData.VertexCount; i++ { // Triangle vertices, third vertex implied as (0, 0) - nextIndex := getNextIndex(i, newBody.Shape.VertexData.VertexCount) - position1 := newBody.Shape.VertexData.Positions[i] - position2 := newBody.Shape.VertexData.Positions[nextIndex] + position1 := newBody.Shape.VertexData.Vertices[i] + nextIndex := 0 + if i+1 < newBody.Shape.VertexData.VertexCount { + nextIndex = i + 1 + } + position2 := newBody.Shape.VertexData.Vertices[nextIndex] cross := rl.Vector2CrossProduct(position1, position2) triangleArea := cross / 2 @@ -346,12 +281,12 @@ func NewBodyPolygon(pos rl.Vector2, radius float32, sides int, density float32) area += triangleArea // Use area to weight the centroid average, not just vertex position - center.X += triangleArea * physacK * (position1.X + position2.X) - center.Y += triangleArea * physacK * (position1.Y + position2.Y) + center.X += triangleArea * alpha * (position1.X + position2.X) + center.Y += triangleArea * alpha * (position1.Y + position2.Y) intx2 := position1.X*position1.X + position2.X*position1.X + position2.X*position2.X inty2 := position1.Y*position1.Y + position2.Y*position1.Y + position2.Y*position2.Y - inertia += (0.25 * physacK * cross) * (intx2 + inty2) + inertia += (0.25 * alpha * cross) * (intx2 + inty2) } center.X *= 1.0 / area @@ -360,62 +295,247 @@ func NewBodyPolygon(pos rl.Vector2, radius float32, sides int, density float32) // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) // Note: this is not really necessary for i := 0; i < newBody.Shape.VertexData.VertexCount; i++ { - newBody.Shape.VertexData.Positions[i].X -= center.X - newBody.Shape.VertexData.Positions[i].Y -= center.Y + newBody.Shape.VertexData.Vertices[i].X -= center.X + newBody.Shape.VertexData.Vertices[i].Y -= center.Y } newBody.Mass = density * area - newBody.InverseMass = safeDiv(1.0, newBody.Mass) newBody.Inertia = density * inertia - newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) + newBody.StaticFriction = 0.4 + newBody.DynamicFriction = 0.2 + newBody.Restitution = 0 + newBody.UseGravity = true + newBody.IsGrounded = false + newBody.FreezeOrient = false + + if newBody.Mass != 0 { + newBody.InverseMass = 1.0 / newBody.Mass + } + + if newBody.Inertia != 0 { + newBody.InverseInertia = 1.0 / newBody.Inertia + } + + // Add new body to bodies pointers + bodies = append(bodies, newBody) - // Add new body to bodies pointers array and update bodies count - bodies[bodiesCount] = newBody - bodiesCount++ return newBody } +// GetBodies - Returns the slice of created physics bodies +func GetBodies() []*Body { + return bodies +} + +// GetBodiesCount - Returns the current amount of created physics bodies +func GetBodiesCount() int { + return len(bodies) +} + +// GetBody - Returns a physics body of the bodies pool at a specific index +func GetBody(index int) *Body { + var body *Body + + if index < len(bodies) { + body = bodies[index] + } else { + rl.TraceLog(rl.LogDebug, "[PHYSAC] physics body index is out of bounds") + } + + return body +} + +// GetShapeType - Returns the physics body shape type (Circle or Polygon) +func GetShapeType(index int) ShapeType { + var result ShapeType + + if index < len(bodies) { + result = bodies[index].Shape.Type + } else { + rl.TraceLog(rl.LogDebug, "[PHYSAC] physics body index is out of bounds") + } + + return result +} + +// GetShapeVerticesCount - Returns the amount of vertices of a physics body shape +func GetShapeVerticesCount(index int) int { + result := 0 + + if index < len(bodies) { + switch bodies[index].Shape.Type { + case CircleShape: + result = circleVertices + break + case PolygonShape: + result = bodies[index].Shape.VertexData.VertexCount + break + } + } else { + rl.TraceLog(rl.LogDebug, "[PHYSAC] physics body index is out of bounds") + } + + return result +} + +// DestroyBody - Unitializes and destroys a physics body +func DestroyBody(body *Body) bool { + for index, b := range bodies { + if b == body { + // Free body allocated memory + bodies = append(bodies[:index], bodies[index+1:]...) + return true + } + } + + return false +} + +// Update - Physics steps calculations (dynamics, collisions and position corrections) +func Update() { + deltaTime = rl.GetFrameTime() * 1000 + + // Clear previous generated collisions information + for _, m := range manifolds { + destroyManifold(m) + } + + // Reset physics bodies grounded state + for _, b := range bodies { + b.IsGrounded = false + } + + // Generate new collision information + bodiesCount := len(bodies) + for i := 0; i < bodiesCount; i++ { + + bodyA := bodies[i] + + for j := i + 1; j < bodiesCount; j++ { + + bodyB := bodies[j] + + if (bodyA.InverseMass == 0) && (bodyB.InverseMass == 0) { + continue + } + + var m *manifold + if bodyA.Shape.Type == PolygonShape && bodyB.Shape.Type == CircleShape { + m = newManifold(bodyB, bodyA) + } else { + m = newManifold(bodyA, bodyB) + } + + m.solveManifold() + + if m.ContactsCount > 0 { + // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot + newManifold := newManifold(bodyA, bodyB) + newManifold.Penetration = m.Penetration + newManifold.Normal = m.Normal + newManifold.Contacts[0] = m.Contacts[0] + newManifold.Contacts[1] = m.Contacts[1] + newManifold.ContactsCount = m.ContactsCount + newManifold.Restitution = m.Restitution + newManifold.DynamicFriction = m.DynamicFriction + newManifold.StaticFriction = m.StaticFriction + } + } + } + + // Integrate forces to physics bodies + for _, b := range bodies { + b.integrateForces() + } + + // Initialize physics manifolds to solve collisions + for _, m := range manifolds { + m.initializeManifolds() + } + + // Integrate physics collisions impulses to solve collisions + manifoldsCount := len(manifolds) + for i := 0; i < collisionIterations; i++ { + for j := 0; j < manifoldsCount; j++ { + if i < manifoldsCount { + manifolds[i].integrateImpulses() + } + } + } + + // Integrate velocity to physics bodies + for _, b := range bodies { + b.integrateVelocity() + } + + // Correct physics bodies positions based on manifolds collision information + for _, m := range manifolds { + m.correctPositions() + } + + // Clear physics bodies forces + for _, b := range bodies { + b.Force = rl.Vector2{} + b.Torque = 0 + } +} + // Reset - Destroys created physics bodies and manifolds func Reset() { - Close() + bodies = make([]*Body, 0, maxBodies) + manifolds = make([]*manifold, 0, maxManifolds) +} + +// Close - Unitializes physics pointers +func Close() { + // Unitialize physics manifolds dynamic memory allocations + for _, m := range manifolds { + destroyManifold(m) + } + + // Unitialize physics bodies dynamic memory allocations + for _, b := range bodies { + DestroyBody(b) + } } // AddForce - Adds a force to a physics body -func AddForce(body *Body, force rl.Vector2) { - if body != nil { - body.Force = rl.Vector2Add(body.Force, force) - } +func (b *Body) AddForce(force rl.Vector2) { + b.Force = rl.Vector2Add(b.Force, force) } // AddTorque - Adds an angular force to a physics body -func AddTorque(body *Body, amount float32) { - if body != nil { - body.Torque += amount - } +func (b *Body) AddTorque(amount float32) { + b.Torque += amount } // Shatter - Shatters a polygon shape physics body to little physics bodies with explosion force -func Shatter(body *Body, position rl.Vector2, force float32) { - if body == nil || body.Shape.Type != PolygonShape { +func (b *Body) Shatter(position rl.Vector2, force float32) { + if b.Shape.Type != PolygonShape { return } - vertexData := body.Shape.VertexData + vertexData := b.Shape.VertexData collision := false for i := 0; i < vertexData.VertexCount; i++ { - nextIndex := getNextIndex(i, vertexData.VertexCount) - pA := body.Position - pB := rl.Mat2MultiplyVector2(body.Shape.Transform, - rl.Vector2Add(body.Position, vertexData.Positions[i])) - pC := rl.Mat2MultiplyVector2(body.Shape.Transform, - rl.Vector2Add(body.Position, vertexData.Positions[nextIndex])) + positionA := b.Position + positionB := rl.Mat2MultiplyVector2(vertexData.Transform, rl.Vector2Add(b.Position, vertexData.Vertices[i])) + + nextIndex := 0 + if i+1 < vertexData.VertexCount { + nextIndex = i + 1 + } + + positionC := rl.Mat2MultiplyVector2(vertexData.Transform, rl.Vector2Add(b.Position, vertexData.Vertices[nextIndex])) // Check collision between each triangle - alpha := ((pB.Y-pC.Y)*(position.X-pC.X) + (pC.X-pB.X)*(position.Y-pC.Y)) / - ((pB.Y-pC.Y)*(pA.X-pC.X) + (pC.X-pB.X)*(pA.Y-pC.Y)) - beta := ((pC.Y-pA.Y)*(position.X-pC.X) + (pA.X-pC.X)*(position.Y-pC.Y)) / - ((pB.Y-pC.Y)*(pA.X-pC.X) + (pC.X-pB.X)*(pA.Y-pC.Y)) + alpha := ((positionB.Y-positionC.Y)*(position.X-positionC.X) + (positionC.X-positionB.X)*(position.Y-positionC.Y)) / + ((positionB.Y-positionC.Y)*(positionA.X-positionC.X) + (positionC.X-positionB.X)*(positionA.Y-positionC.Y)) + + beta := ((positionC.Y-positionA.Y)*(position.X-positionC.X) + (positionA.X-positionC.X)*(position.Y-positionC.Y)) / + ((positionB.Y-positionC.Y)*(positionA.X-positionC.X) + (positionC.X-positionB.X)*(positionA.Y-positionC.Y)) + gamma := 1.0 - alpha - beta if alpha > 0 && beta > 0 && gamma > 0 { @@ -424,251 +544,207 @@ func Shatter(body *Body, position rl.Vector2, force float32) { } } - if !collision { - return - } + if collision { + count := vertexData.VertexCount + bodyPos := b.Position - count := vertexData.VertexCount - bodyPos := body.Position - trans := body.Shape.Transform - - vertices := make([]rl.Vector2, count) - for i := 0; i < count; i++ { - vertices[i] = vertexData.Positions[i] - } - - // Destroy shattered physics body - body.Destroy() - for i := 0; i < count; i++ { - nextIndex := getNextIndex(i, count) - center := triangleBarycenter(vertices[i], vertices[nextIndex], rl.Vector2{}) - center = rl.Vector2Add(bodyPos, center) - offset := rl.Vector2Subtract(center, bodyPos) - - var newBody *Body = NewBodyPolygon(center, 10, 3, 10) - var newData Polygon = Polygon{} - newData.VertexCount = 3 - newData.Positions[0] = rl.Vector2Subtract(vertices[i], offset) - newData.Positions[1] = rl.Vector2Subtract(vertices[nextIndex], offset) - newData.Positions[2] = rl.Vector2Subtract(position, center) - - // Separate vertices to avoid unnecessary physics collisions - newData.Positions[0].X *= 0.95 - newData.Positions[0].Y *= 0.95 - newData.Positions[1].X *= 0.95 - newData.Positions[1].Y *= 0.95 - newData.Positions[2].X *= 0.95 - newData.Positions[2].Y *= 0.95 - - // Calculate polygon faces normals - for j := 0; j < newData.VertexCount; j++ { - nextVertex := getNextIndex(j, newData.VertexCount) - face := rl.Vector2Subtract(newData.Positions[nextVertex], newData.Positions[j]) - - newData.Normals[j] = rl.NewVector2(face.Y, -face.X) - normalize(&newData.Normals[j]) + vertices := make([]rl.Vector2, count) + trans := vertexData.Transform + for i := 0; i < count; i++ { + vertices[i] = vertexData.Vertices[i] } - // Apply computed vertex data to new physics body shape - newBody.Shape.VertexData = newData - newBody.Shape.Transform = trans + // Destroy shattered physics body + DestroyBody(b) - // Calculate centroid and moment of inertia - center = rl.Vector2{} - area := float32(0.0) - inertia := float32(0.0) - - for j := 0; j < newBody.Shape.VertexData.VertexCount; j++ { - // Triangle vertices, third vertex implied as (0, 0) - nextVertex := getNextIndex(j, newBody.Shape.VertexData.VertexCount) - p1 := newBody.Shape.VertexData.Positions[j] - p2 := newBody.Shape.VertexData.Positions[nextVertex] - - D := rl.Vector2CrossProduct(p1, p2) - triangleArea := D / 2 - - area += triangleArea - - // Use area to weight the centroid average, not just vertex position - center.X += triangleArea * physacK * (p1.X + p2.X) - center.Y += triangleArea * physacK * (p1.Y + p2.Y) - - intx2 := p1.X*p1.X + p2.X*p1.X + p2.X*p2.X - inty2 := p1.Y*p1.Y + p2.Y*p1.Y + p2.Y*p2.Y - inertia += (0.25*physacK*D)*intx2 + inty2 - } - - center.X *= 1.0 / area - center.Y *= 1.0 / area - - newBody.Mass = area - newBody.InverseMass = safeDiv(1.0, newBody.Mass) - newBody.Inertia = inertia - newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) - - // Calculate explosion force direction - pointA := newBody.Position - pointB := rl.Vector2Subtract(newData.Positions[1], newData.Positions[0]) - pointB.X /= 2.0 - pointB.Y /= 2.0 - forceDirection := rl.Vector2Subtract( - rl.Vector2Add(pointA, rl.Vector2Add(newData.Positions[0], pointB)), - newBody.Position, - ) - normalize(&forceDirection) - forceDirection.X *= force - forceDirection.Y *= force - - // Apply force to new physics body - AddForce(newBody, forceDirection) - } -} - -// GetBodies - Returns the slice of created physics bodies -func GetBodies() []*Body { - return bodies[:bodiesCount] -} - -// GetBodiesCount - Returns the current amount of created physics bodies -func GetBodiesCount() int { - return bodiesCount -} - -// GetBody - Returns a physics body of the bodies pool at a specific index -func GetBody(index int) *Body { - return bodies[index] -} - -// GetShapeType - Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -func GetShapeType(index int) ShapeType { - result := ShapeType(-1) - if index < bodiesCount { - if bodies[index] != nil { - result = bodies[index].Shape.Type - } - } - return result -} - -// GetShapeVerticesCount - Returns the amount of vertices of a physics body shape -func GetShapeVerticesCount(index int) int { - var result int = 0 - if index < bodiesCount { - if bodies[index] != nil { - switch bodies[index].Shape.Type { - case CircleShape: - result = circleVertices - case PolygonShape: - result = bodies[index].Shape.VertexData.VertexCount - default: + for i := 0; i < count; i++ { + nextIndex := 0 + if i+1 < count { + nextIndex = i + 1 } + + center := triangleBarycenter(vertices[i], vertices[nextIndex], rl.NewVector2(0, 0)) + center = rl.Vector2Add(bodyPos, center) + offset := rl.Vector2Subtract(center, bodyPos) + + newBody := NewBodyPolygon(center, 10, 3, 10) // Create polygon physics body with relevant values + + newData := Polygon{} + newData.VertexCount = 3 + newData.Transform = trans + + newData.Vertices[0] = rl.Vector2Subtract(vertices[i], offset) + newData.Vertices[1] = rl.Vector2Subtract(vertices[nextIndex], offset) + newData.Vertices[2] = rl.Vector2Subtract(position, center) + + // Separate vertices to avoid unnecessary physics collisions + newData.Vertices[0].X *= 0.95 + newData.Vertices[0].Y *= 0.95 + newData.Vertices[1].X *= 0.95 + newData.Vertices[1].Y *= 0.95 + newData.Vertices[2].X *= 0.95 + newData.Vertices[2].Y *= 0.95 + + // Calculate polygon faces normals + for j := 0; j < newData.VertexCount; j++ { + nextVertex := 0 + if j+1 < newData.VertexCount { + nextVertex = j + 1 + } + + face := rl.Vector2Subtract(newData.Vertices[nextVertex], newData.Vertices[j]) + + newData.Normals[j] = rl.NewVector2(face.Y, -face.X) + normalize(&newData.Normals[j]) + } + + // Apply computed vertex data to new physics body shape + newBody.Shape.VertexData = newData + + // Calculate centroid and moment of inertia + center = rl.NewVector2(0, 0) + area := float32(0.0) + inertia := float32(0.0) + k := float32(1.0) / 3.0 + + for j := 0; j < newBody.Shape.VertexData.VertexCount; j++ { + // Triangle vertices, third vertex implied as (0, 0) + p1 := newBody.Shape.VertexData.Vertices[j] + nextVertex := 0 + if j+1 < newBody.Shape.VertexData.VertexCount { + nextVertex = j + 1 + } + p2 := newBody.Shape.VertexData.Vertices[nextVertex] + + D := rl.Vector2CrossProduct(p1, p2) + triangleArea := D / 2 + + area += triangleArea + + // Use area to weight the centroid average, not just vertex position + center.X += triangleArea * k * (p1.X + p2.X) + center.Y += triangleArea * k * (p1.Y + p2.Y) + + intx2 := p1.X*p1.X + p2.X*p1.X + p2.X*p2.X + inty2 := p1.Y*p1.Y + p2.Y*p1.Y + p2.Y*p2.Y + inertia += (0.25 * k * D) * (intx2 + inty2) + } + + center.X *= 1.0 / area + center.Y *= 1.0 / area + + newBody.Mass = area + newBody.Inertia = inertia + + if newBody.Mass != 0 { + newBody.InverseMass = 1.0 / newBody.Mass + } + + if newBody.Inertia != 0 { + newBody.InverseInertia = 1.0 / newBody.Inertia + } + + // Calculate explosion force direction + pointA := newBody.Position + pointB := rl.Vector2Subtract(newData.Vertices[1], newData.Vertices[0]) + pointB.X /= 2 + pointB.Y /= 2 + forceDirection := rl.Vector2Subtract(rl.Vector2Add(pointA, rl.Vector2Add(newData.Vertices[0], pointB)), newBody.Position) + normalize(&forceDirection) + forceDirection.X *= force + forceDirection.Y *= force + + // Apply force to new physics body + newBody.AddForce(forceDirection) } } - return result } // GetShapeVertex - Returns transformed position of a body shape (body position + vertex transformed position) func (b *Body) GetShapeVertex(vertex int) rl.Vector2 { - var position rl.Vector2 + position := rl.Vector2{} switch b.Shape.Type { case CircleShape: - angle := 360.0 / circleVertices * float64(vertex) * (degToRad) - position.X = b.Position.X + float32(math.Cos(angle))*b.Shape.Radius - position.Y = b.Position.Y + float32(math.Sin(angle))*b.Shape.Radius + position.X = b.Position.X + float32(math.Cos(360/float64(circleVertices)*float64(vertex)*rl.Deg2rad))*b.Shape.Radius + position.Y = b.Position.Y + float32(math.Sin(360/float64(circleVertices)*float64(vertex)*rl.Deg2rad))*b.Shape.Radius + break case PolygonShape: - position = rl.Vector2Add( - b.Position, - rl.Mat2MultiplyVector2(b.Shape.Transform, b.Shape.VertexData.Positions[vertex]), - ) + position = rl.Vector2Add(b.Position, rl.Mat2MultiplyVector2(b.Shape.VertexData.Transform, b.Shape.VertexData.Vertices[vertex])) + break } + return position } -// SetBodyRotation - Sets physics body shape transform based on radians parameter +// SetRotation - Sets physics body shape transform based on radians parameter func (b *Body) SetRotation(radians float32) { b.Orient = radians + if b.Shape.Type == PolygonShape { - b.Shape.Transform = rl.Mat2Radians(radians) + b.Shape.VertexData.Transform = rl.Mat2Radians(radians) } } -// Destroy - Unitializes and destroy a physics body -func (b *Body) Destroy() { - id := b.ID - index := -1 - for i := 0; i < bodiesCount; i++ { - if bodies[i].ID == id { - index = i - break - } - } - if index == -1 { +// integrateVelocity - Integrates physics velocity into position and forces +func (b *Body) integrateVelocity() { + if !b.Enabled { return } - bodies[index] = nil + b.Position.X += b.Velocity.X * deltaTime + b.Position.Y += b.Velocity.Y * deltaTime - // Reorder physics bodies pointers array and its catched index - for i := index; i+1 < bodiesCount; i++ { - bodies[i] = bodies[i+1] + if !b.FreezeOrient { + b.Orient += b.AngularVelocity * deltaTime } - // Update physics bodies count - bodiesCount-- + rl.Mat2Set(&b.Shape.VertexData.Transform, b.Orient) + + b.integrateForces() } -// Close - Unitializes physics pointers -func Close() { - // Unitialize physics manifolds dynamic memory allocations - for i := manifoldsCount - 1; i >= 0; i-- { - destroyManifold(manifolds[i]) +// integrateForces - Integrates physics forces into velocity +func (b *Body) integrateForces() { + if b.InverseMass == 0 || !b.Enabled { + return } - // Unitialize physics bodies dynamic memory allocations - for i := bodiesCount - 1; i >= 0; i-- { - bodies[i].Destroy() + b.Velocity.X += (b.Force.X * b.InverseMass) * (deltaTime / 2) + b.Velocity.Y += (b.Force.Y * b.InverseMass) * (deltaTime / 2) + + if b.UseGravity { + b.Velocity.X += gravityForce.X * (deltaTime / 1000 / 2) + b.Velocity.Y += gravityForce.Y * (deltaTime / 1000 / 2) + } + + if !b.FreezeOrient { + b.AngularVelocity += b.Torque * b.InverseInertia * (deltaTime / 2) } } -// findAvailableBodyIndex - Finds a valid index for a new physics body initialization -func findAvailableBodyIndex() int { - index := -1 - for i := 0; i < maxBodies; i++ { - currentID := i - - // Check if current id already exist in other physics body - for k := 0; k < bodiesCount; k++ { - if bodies[k].ID == currentID { - currentID++ - break - } - } - - // If it is not used, use it as new physics body id - if currentID == i { - index = i - break - } - } - return index -} - -// createRandomPolygon - Creates a random polygon shape with max vertex distance from polygon pivot -func createRandomPolygon(radius float32, sides int) Polygon { - var data Polygon = Polygon{} +// newRandomPolygon - Creates a random polygon shape with max vertex distance from polygon pivot +func newRandomPolygon(radius float32, sides int) Polygon { + data := Polygon{} data.VertexCount = sides + orient := rl.GetRandomValue(0, 360) + data.Transform = rl.Mat2Radians(float32(orient) * rl.Deg2rad) + // Calculate polygon vertices positions for i := 0; i < data.VertexCount; i++ { - data.Positions[i].X = float32(math.Cos(360.0/float64(sides)*float64(i)*degToRad)) * radius - data.Positions[i].Y = float32(math.Sin(360.0/float64(sides)*float64(i)*degToRad)) * radius + data.Vertices[i].X = float32(math.Cos(360/float64(sides)*float64(i)*rl.Deg2rad)) * radius + data.Vertices[i].Y = float32(math.Sin(360/float64(sides)*float64(i)*rl.Deg2rad)) * radius } // Calculate polygon faces normals for i := 0; i < data.VertexCount; i++ { - nextIndex := getNextIndex(i, sides) - face := rl.Vector2Subtract(data.Positions[nextIndex], data.Positions[i]) + nextIndex := 0 + if i+1 < sides { + nextIndex = i + 1 + } + + face := rl.Vector2Subtract(data.Vertices[nextIndex], data.Vertices[i]) data.Normals[i] = rl.NewVector2(face.Y, -face.X) normalize(&data.Normals[i]) @@ -677,21 +753,26 @@ func createRandomPolygon(radius float32, sides int) Polygon { return data } -// createRectanglePolygon - Creates a rectangle polygon shape based on a min and max positions -func createRectanglePolygon(pos rl.Vector2, size rl.Vector2) Polygon { - var data Polygon = Polygon{} +// newRectanglePolygon - Creates a rectangle polygon shape based on a min and max positions +func newRectanglePolygon(pos, size rl.Vector2) Polygon { + data := Polygon{} + data.VertexCount = 4 + data.Transform = rl.Mat2Radians(0) // Calculate polygon vertices positions - data.Positions[0] = rl.NewVector2(pos.X+size.X/2, pos.Y-size.Y/2) - data.Positions[1] = rl.NewVector2(pos.X+size.X/2, pos.Y+size.Y/2) - data.Positions[2] = rl.NewVector2(pos.X-size.X/2, pos.Y+size.Y/2) - data.Positions[3] = rl.NewVector2(pos.X-size.X/2, pos.Y-size.Y/2) + data.Vertices[0] = rl.NewVector2(pos.X+size.X/2, pos.Y-size.Y/2) + data.Vertices[1] = rl.NewVector2(pos.X+size.X/2, pos.Y+size.Y/2) + data.Vertices[2] = rl.NewVector2(pos.X-size.X/2, pos.Y+size.Y/2) + data.Vertices[3] = rl.NewVector2(pos.X-size.X/2, pos.Y-size.Y/2) // Calculate polygon faces normals for i := 0; i < data.VertexCount; i++ { - nextIndex := getNextIndex(i, data.VertexCount) - face := rl.Vector2Subtract(data.Positions[nextIndex], data.Positions[i]) + nextIndex := 0 + if i+1 < data.VertexCount { + nextIndex = i + 1 + } + face := rl.Vector2Subtract(data.Vertices[nextIndex], data.Vertices[i]) data.Normals[i] = rl.NewVector2(face.Y, -face.X) normalize(&data.Normals[i]) @@ -700,318 +781,124 @@ func createRectanglePolygon(pos rl.Vector2, size rl.Vector2) Polygon { return data } -// step - Does physics steps calculations (dynamics, collisions and position corrections) -func step() { - // Clear previous generated collisions information - for i := manifoldsCount - 1; i >= 0; i-- { - if manifold := manifolds[i]; manifold != nil { - destroyManifold(manifold) - } - } - - // Reset physics bodies grounded state - for i := 0; i < bodiesCount; i++ { - bodies[i].IsGrounded = false - } - - // Generate new collision information - for i := 0; i < bodiesCount; i++ { - bodyA := bodies[i] - if bodyA == nil { - continue - } - - for j := i + 1; j < bodiesCount; j++ { - var bodyB *Body = bodies[j] - if bodyB == nil || bodyA.InverseMass == 0 && bodyB.InverseMass == 0 { - continue - } - - manifold := createManifold(bodyA, bodyB) - solveManifold(manifold) - - if manifold.ContactsCount > 0 { - // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot - newManifold := createManifold(bodyA, bodyB) - newManifold.Penetration = manifold.Penetration - newManifold.Normal = manifold.Normal - newManifold.Contacts[0] = manifold.Contacts[0] - newManifold.Contacts[1] = manifold.Contacts[1] - newManifold.ContactsCount = manifold.ContactsCount - newManifold.Restitution = manifold.Restitution - newManifold.DynamicFriction = manifold.DynamicFriction - newManifold.StaticFriction = manifold.StaticFriction - } - } - } - - // Integrate forces to physics bodies - for i := 0; i < bodiesCount; i++ { - if body := bodies[i]; body != nil { - integrateForces(body) - } - } - - // Initialize physics manifolds to solve collisions - for i := 0; i < manifoldsCount; i++ { - if manifold := manifolds[i]; manifold != nil { - initializeManifolds(manifold) - } - } - - // Integrate physics collisions impulses to solve collisions - for i := 0; i < collisionIterations; i++ { - for j := 0; j < manifoldsCount; j++ { - if manifold := manifolds[i]; manifold != nil { - integrateImpulses(manifold) - } - } - } - - // Integrate velocity to physics bodies - for i := 0; i < bodiesCount; i++ { - if body := bodies[i]; body != nil { - integrateVelocity(body) - } - } - - // Correct physics bodies positions based on manifolds collision information - for i := 0; i < manifoldsCount; i++ { - if manifold := manifolds[i]; manifold != nil { - correctPositions(manifold) - } - } - - // Clear physics bodies forces - for i := 0; i < bodiesCount; i++ { - if body := bodies[i]; body != nil { - body.Force = rl.Vector2{} - body.Torque = 0 - } - } -} - -// Update - Runs physics step -func Update() { - // Calculate current time - currentTime = getCurrentTime() - - // Calculate current delta time - var delta float32 = currentTime - startTime - - // Store the time elapsed since the last frame began - accumulator += delta - - // Fixed time stepping loop - for accumulator >= deltaTime { - step() - accumulator -= deltaTime - } - - // Record the starting of this frame - startTime = currentTime -} - -// SetTimeStep - Sets physics fixed time step in milliseconds. 1.666666 by default -func SetTimeStep(delta float32) { - deltaTime = delta -} - -// findAvailableManifoldIndex - Finds a valid index for a new manifold initialization -func findAvailableManifoldIndex() int { - index := -1 - for i := 0; i < maxManifolds; i++ { - var currentId int = i - - // Check if current id already exist in other physics body - for k := 0; k < manifoldsCount; k++ { - if manifolds[k].ID == currentId { - currentId++ - break - } - } - - // If it is not used, use it as new physics body id - if currentId == i { - index = i - break - } - } - return index -} - -// createManifold - Creates a new physics manifold to solve collision -func createManifold(a *Body, b *Body) *Manifold { - newID := findAvailableManifoldIndex() - if newID < 0 { - return nil - } +// newManifold - Creates a new physics manifold to solve collision +func newManifold(a, b *Body) *manifold { + newManifold := &manifold{} // Initialize new manifold with generic values - newManifold := &Manifold{ - ID: newID, - BodyA: a, - BodyB: b, - Penetration: 0, - Normal: rl.Vector2{}, - Contacts: [2]rl.Vector2{}, - ContactsCount: 0, - Restitution: 0.0, - DynamicFriction: 0.0, - StaticFriction: 0.0, - } + newManifold.BodyA = a + newManifold.BodyB = b + newManifold.Penetration = 0 + newManifold.Normal = rl.Vector2{} + newManifold.Contacts[0] = rl.Vector2{} + newManifold.Contacts[1] = rl.Vector2{} + newManifold.ContactsCount = 0 + newManifold.Restitution = 0 + newManifold.DynamicFriction = 0 + newManifold.StaticFriction = 0 - // Add new contact to conctas pointers array and update contacts count - manifolds[manifoldsCount] = newManifold - manifoldsCount++ + // Add new manifold to manifolds pointers + manifolds = append(manifolds, newManifold) return newManifold } // destroyManifold - Unitializes and destroys a physics manifold -func destroyManifold(manifold *Manifold) { - if manifold == nil { - return - } - - id := manifold.ID - index := -1 - for i := 0; i < manifoldsCount; i++ { - if manifolds[i].ID == id { - index = i - break - } - } - if index < 0 { - return - } - - manifolds[index] = nil - - // Reorder physics manifolds pointers array and its catched index - for i := index; i < manifoldsCount; i++ { - if (i + 1) < manifoldsCount { - manifolds[i] = manifolds[i+1] +func destroyManifold(manifold *manifold) bool { + for index, m := range manifolds { + if m == manifold { + // Free manifold allocated memory + manifolds = append(manifolds[:index], manifolds[index+1:]...) + return true } } - // Update physics manifolds count - manifoldsCount-- + return false } // solveManifold - Solves a created physics manifold between two physics bodies -func solveManifold(manifold *Manifold) { - switch manifold.BodyA.Shape.Type { +func (m *manifold) solveManifold() { + switch m.BodyA.Shape.Type { case CircleShape: - switch manifold.BodyB.Shape.Type { + switch m.BodyB.Shape.Type { case CircleShape: - solveCircleToCircle(manifold) + m.solveCircleToCircle() + break case PolygonShape: - solveCircleToPolygon(manifold) + m.solveCircleToPolygon() + break } case PolygonShape: - switch manifold.BodyB.Shape.Type { + switch m.BodyB.Shape.Type { case CircleShape: - solvePolygonToCircle(manifold) + m.solvePolygonToCircle() + break case PolygonShape: - solvePolygonToPolygon(manifold) + m.solvePolygonToPolygon() + break } } - // Update physics body grounded state if normal direction is down and grounded state - // is not set yet in previous manifolds - if !manifold.BodyB.IsGrounded { - manifold.BodyB.IsGrounded = manifold.Normal.Y < 0 + // Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds + if !m.BodyB.IsGrounded { + m.BodyB.IsGrounded = (m.Normal.Y < 0) } } // solveCircleToCircle - Solves collision between two circle shape physics bodies -func solveCircleToCircle(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB - if bodyA == nil || bodyB == nil { - return - } +func (m *manifold) solveCircleToCircle() { + bodyA := m.BodyA + bodyB := m.BodyB // Calculate translational vector, which is normal - var normal rl.Vector2 = rl.Vector2Subtract(bodyB.Position, bodyA.Position) + normal := rl.Vector2Subtract(bodyB.Position, bodyA.Position) distSqr := rl.Vector2LenSqr(normal) radius := bodyA.Shape.Radius + bodyB.Shape.Radius // Check if circles are not in contact if distSqr >= radius*radius { - manifold.ContactsCount = 0 + m.ContactsCount = 0 return } distance := float32(math.Sqrt(float64(distSqr))) - manifold.ContactsCount = 1 + m.ContactsCount = 1 + if distance == 0 { - manifold.Penetration = bodyA.Shape.Radius - manifold.Normal = rl.NewVector2(1, 0) - manifold.Contacts[0] = bodyA.Position + m.Penetration = bodyA.Shape.Radius + m.Normal = rl.NewVector2(1, 0) + m.Contacts[0] = bodyA.Position } else { - manifold.Penetration = radius - distance - // Faster than using normalize() due to sqrt is already performed - manifold.Normal = rl.NewVector2( - normal.X/distance, - normal.Y/distance, - ) - manifold.Contacts[0] = rl.NewVector2( - manifold.Normal.X*bodyA.Shape.Radius+bodyA.Position.X, - manifold.Normal.Y*bodyA.Shape.Radius+bodyA.Position.Y, - ) + m.Penetration = radius - distance + m.Normal = rl.NewVector2(normal.X/distance, normal.Y/distance) // Faster than using normalize() due to sqrt is already performed + m.Contacts[0] = rl.NewVector2(m.Normal.X*bodyA.Shape.Radius+bodyA.Position.X, m.Normal.Y*bodyA.Shape.Radius+bodyA.Position.Y) } // Update physics body grounded state if normal direction is down if !bodyA.IsGrounded { - bodyA.IsGrounded = manifold.Normal.Y < 0 + bodyA.IsGrounded = (m.Normal.Y < 0) } } // solveCircleToPolygon - Solves collision between a circle to a polygon shape physics bodies -func solveCircleToPolygon(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB - if bodyA == nil || bodyB == nil { - return - } - solveDifferentShapes(manifold, bodyA, bodyB) -} - -// solvePolygonToCircle - Solves collision between a polygon to a circle shape physics bodies -func solvePolygonToCircle(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB - if bodyA == nil || bodyB == nil { - return - } - solveDifferentShapes(manifold, bodyB, bodyA) - manifold.Normal.X *= -1.0 - manifold.Normal.Y *= -1.0 -} - -// solveDifferentShapes - Solves collision between two different types of shapes -func solveDifferentShapes(manifold *Manifold, bodyA *Body, bodyB *Body) { - manifold.ContactsCount = 0 +func (m *manifold) solveCircleToPolygon() { + m.ContactsCount = 0 // Transform circle center to polygon transform space - center := rl.Mat2MultiplyVector2( - rl.Mat2Transpose(bodyB.Shape.Transform), - rl.Vector2Subtract(bodyA.Position, bodyB.Position), - ) + center := m.BodyA.Position + center = rl.Mat2MultiplyVector2(rl.Mat2Transpose(m.BodyB.Shape.VertexData.Transform), rl.Vector2Subtract(center, m.BodyB.Position)) // Find edge with minimum penetration - // It is the same concept as using support points in SolvePolygonToPolygon - separation := float32(-math.MaxFloat32) + // It is the same concept as using support points in solvePolygonToPolygon + separation := float32(-fltMax) faceNormal := 0 - vertexData := bodyB.Shape.VertexData + vertexData := m.BodyB.Shape.VertexData for i := 0; i < vertexData.VertexCount; i++ { - currentSeparation := rl.Vector2DotProduct( - vertexData.Normals[i], - rl.Vector2Subtract(center, vertexData.Positions[i]), - ) + currentSeparation := rl.Vector2DotProduct(vertexData.Normals[i], rl.Vector2Subtract(center, vertexData.Vertices[i])) - if currentSeparation > bodyA.Shape.Radius { + if currentSeparation > m.BodyA.Shape.Radius { return } @@ -1022,92 +909,96 @@ func solveDifferentShapes(manifold *Manifold, bodyA *Body, bodyB *Body) { } // Grab face's vertices - nextIndex := getNextIndex(faceNormal, vertexData.VertexCount) - v1 := vertexData.Positions[faceNormal] - v2 := vertexData.Positions[nextIndex] + v1 := vertexData.Vertices[faceNormal] + nextIndex := 0 + if faceNormal+1 < vertexData.VertexCount { + nextIndex = faceNormal + 1 + } + v2 := vertexData.Vertices[nextIndex] // Check to see if center is within polygon if separation < epsilon { - manifold.ContactsCount = 1 - var normal rl.Vector2 = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, vertexData.Normals[faceNormal]) - manifold.Normal = rl.NewVector2(-normal.X, -normal.Y) - manifold.Contacts[0] = rl.NewVector2( - manifold.Normal.X*bodyA.Shape.Radius+bodyA.Position.X, - manifold.Normal.Y*bodyA.Shape.Radius+bodyA.Position.Y, - ) - manifold.Penetration = bodyA.Shape.Radius + m.ContactsCount = 1 + normal := rl.Mat2MultiplyVector2(vertexData.Transform, vertexData.Normals[faceNormal]) + m.Normal = rl.NewVector2(-normal.X, -normal.Y) + m.Contacts[0] = rl.NewVector2(m.Normal.X*m.BodyA.Shape.Radius+m.BodyA.Position.X, m.Normal.Y*m.BodyA.Shape.Radius+m.BodyA.Position.Y) + m.Penetration = m.BodyA.Shape.Radius return } // Determine which voronoi region of the edge center of circle lies within dot1 := rl.Vector2DotProduct(rl.Vector2Subtract(center, v1), rl.Vector2Subtract(v2, v1)) dot2 := rl.Vector2DotProduct(rl.Vector2Subtract(center, v2), rl.Vector2Subtract(v1, v2)) - manifold.Penetration = bodyA.Shape.Radius - separation + m.Penetration = m.BodyA.Shape.Radius - separation - switch { - case dot1 <= 0: // Closest to v1 - if rl.Vector2Distance(center, v1) > bodyA.Shape.Radius*bodyA.Shape.Radius { + if dot1 <= 0 { // Closest to v1 + if rl.Vector2Distance(center, v1) > m.BodyA.Shape.Radius*m.BodyA.Shape.Radius { return } - manifold.ContactsCount = 1 - var normal rl.Vector2 = rl.Vector2Subtract(v1, center) - normal = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, normal) + m.ContactsCount = 1 + normal := rl.Vector2Subtract(v1, center) + normal = rl.Mat2MultiplyVector2(vertexData.Transform, normal) normalize(&normal) - manifold.Normal = normal - v1 = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, v1) - v1 = rl.Vector2Add(v1, bodyB.Position) - manifold.Contacts[0] = v1 - - case dot2 <= 0: // Closest to v2 - if rl.Vector2Distance(center, v2) > bodyA.Shape.Radius*bodyA.Shape.Radius { + m.Normal = normal + v1 = rl.Mat2MultiplyVector2(vertexData.Transform, v1) + v1 = rl.Vector2Add(v1, m.BodyB.Position) + m.Contacts[0] = v1 + } else if dot2 <= 0 { // Closest to v2 + if rl.Vector2Distance(center, v2) > m.BodyA.Shape.Radius*m.BodyA.Shape.Radius { return } - manifold.ContactsCount = 1 - var normal rl.Vector2 = rl.Vector2Subtract(v2, center) - v2 = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, v2) - v2 = rl.Vector2Add(v2, bodyB.Position) - manifold.Contacts[0] = v2 - normal = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, normal) + m.ContactsCount = 1 + normal := rl.Vector2Subtract(v2, center) + v2 = rl.Mat2MultiplyVector2(vertexData.Transform, v2) + v2 = rl.Vector2Add(v2, m.BodyB.Position) + m.Contacts[0] = v2 + normal = rl.Mat2MultiplyVector2(vertexData.Transform, normal) normalize(&normal) - manifold.Normal = normal + m.Normal = normal + } else { // Closest to face + normal := vertexData.Normals[faceNormal] - default: // Closest to face - var normal rl.Vector2 = vertexData.Normals[faceNormal] - - if rl.Vector2DotProduct(rl.Vector2Subtract(center, v1), normal) > bodyA.Shape.Radius { + if rl.Vector2DotProduct(rl.Vector2Subtract(center, v1), normal) > m.BodyA.Shape.Radius { return } - normal = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, normal) - manifold.Normal = rl.NewVector2(-normal.X, -normal.Y) - manifold.Contacts[0] = rl.NewVector2( - manifold.Normal.X*bodyA.Shape.Radius+bodyA.Position.X, - manifold.Normal.Y*bodyA.Shape.Radius+bodyA.Position.Y, - ) - manifold.ContactsCount = 1 + normal = rl.Mat2MultiplyVector2(vertexData.Transform, normal) + m.Normal = rl.NewVector2(-normal.X, -normal.Y) + m.Contacts[0] = rl.NewVector2(m.Normal.X*m.BodyA.Shape.Radius+m.BodyA.Position.X, m.Normal.Y*m.BodyA.Shape.Radius+m.BodyA.Position.Y) + m.ContactsCount = 1 } } -// solvePolygonToPolygon - Solves collision between two polygons shape physics bodies -func solvePolygonToPolygon(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB - if bodyA == nil || bodyB == nil { - return - } +// solvePolygonToCircle - Solves collision between a polygon to a circle shape physics bodies +func (m *manifold) solvePolygonToCircle() { + bodyA := m.BodyA + bodyB := m.BodyB - shapeA, shapeB := bodyA.Shape, bodyB.Shape - manifold.ContactsCount = 0 + m.BodyA = bodyB + m.BodyB = bodyA + + m.solveCircleToPolygon() + + m.Normal.X *= -1 + m.Normal.Y *= -1 +} + +// solvePolygonToPolygon - Solves collision between two polygons shape physics bodies +func (m *manifold) solvePolygonToPolygon() { + bodyA := m.BodyA.Shape + bodyB := m.BodyB.Shape + m.ContactsCount = 0 // Check for separating axis with A shape's face planes - faceA, penetrationA := findAxisLeastPenetration(shapeA, shapeB) + faceA, penetrationA := findAxisLeastPenetration(bodyA, bodyB) if penetrationA >= 0 { return } // Check for separating axis with B shape's face planes - faceB, penetrationB := findAxisLeastPenetration(shapeB, shapeA) + faceB, penetrationB := findAxisLeastPenetration(bodyB, bodyA) if penetrationB >= 0 { return } @@ -1115,35 +1006,40 @@ func solvePolygonToPolygon(manifold *Manifold) { referenceIndex := 0 flip := false // Always point from A shape to B shape - var refPoly Shape // Reference - var incPoly Shape // Incident + refPoly := Shape{} // Reference + incPoly := Shape{} // Incident // Determine which shape contains reference face if biasGreaterThan(penetrationA, penetrationB) { - refPoly = shapeA - incPoly = shapeB + refPoly = bodyA + incPoly = bodyB referenceIndex = faceA } else { - refPoly = shapeB - incPoly = shapeA + refPoly = bodyB + incPoly = bodyA referenceIndex = faceB flip = true } // World space incident face - var incidentFace [2]rl.Vector2 - findIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex) + incidentFace0 := rl.Vector2{} + incidentFace1 := rl.Vector2{} + findIncidentFace(&incidentFace0, &incidentFace1, refPoly, incPoly, referenceIndex) // Setup reference face vertices refData := refPoly.VertexData - v1 := refData.Positions[referenceIndex] - referenceIndex = getNextIndex(referenceIndex, refData.VertexCount) - v2 := refData.Positions[referenceIndex] + v1 := refData.Vertices[referenceIndex] + if referenceIndex+1 < refData.VertexCount { + referenceIndex = referenceIndex + 1 + } else { + referenceIndex = 0 + } + v2 := refData.Vertices[referenceIndex] // Transform vertices to world space - v1 = rl.Mat2MultiplyVector2(refPoly.Transform, v1) + v1 = rl.Mat2MultiplyVector2(refData.Transform, v1) v1 = rl.Vector2Add(v1, refPoly.Body.Position) - v2 = rl.Mat2MultiplyVector2(refPoly.Transform, v2) + v2 = rl.Mat2MultiplyVector2(refData.Transform, v2) v2 = rl.Vector2Add(v2, refPoly.Body.Position) // Calculate reference face side normal in world space @@ -1153,112 +1049,83 @@ func solvePolygonToPolygon(manifold *Manifold) { // Orthogonalize refFaceNormal := rl.NewVector2(sidePlaneNormal.Y, -sidePlaneNormal.X) refC := rl.Vector2DotProduct(refFaceNormal, v1) - negSide := rl.Vector2DotProduct(sidePlaneNormal, v1) * float32(-1) + negSide := rl.Vector2DotProduct(sidePlaneNormal, v1) * -1 posSide := rl.Vector2DotProduct(sidePlaneNormal, v2) - // Clip incident face to reference face side planes (due to floating point error, possible to not have required points - if clip(rl.NewVector2(-sidePlaneNormal.X, -sidePlaneNormal.Y), negSide, &incidentFace[0], &incidentFace[1]) < 2 { + // clip incident face to reference face side planes (due to floating point error, possible to not have required points + if clip(rl.NewVector2(-sidePlaneNormal.X, -sidePlaneNormal.Y), negSide, &incidentFace0, &incidentFace1) < 2 { return } - - if clip(sidePlaneNormal, posSide, &incidentFace[0], &incidentFace[1]) < 2 { + if clip(sidePlaneNormal, posSide, &incidentFace0, &incidentFace1) < 2 { return } // Flip normal if required if flip { - manifold.Normal = rl.NewVector2(-refFaceNormal.X, -refFaceNormal.Y) + m.Normal = rl.NewVector2(-refFaceNormal.X, -refFaceNormal.Y) } else { - manifold.Normal = refFaceNormal + m.Normal = refFaceNormal } // Keep points behind reference face - currentPoint := 0 // Clipped points behind reference face - separation := rl.Vector2DotProduct(refFaceNormal, incidentFace[0]) - refC - + currentPoint := 0 // clipped points behind reference face + separation := rl.Vector2DotProduct(refFaceNormal, incidentFace0) - refC if separation <= 0 { - manifold.Contacts[currentPoint] = incidentFace[0] - manifold.Penetration = -separation + m.Contacts[currentPoint] = incidentFace0 + m.Penetration = -separation currentPoint++ } else { - manifold.Penetration = 0 + m.Penetration = 0 } - separation = rl.Vector2DotProduct(refFaceNormal, incidentFace[1]) - refC + separation = rl.Vector2DotProduct(refFaceNormal, incidentFace1) - refC if separation <= 0 { - manifold.Contacts[currentPoint] = incidentFace[1] - manifold.Penetration += -separation + m.Contacts[currentPoint] = incidentFace1 + m.Penetration += -separation currentPoint++ // Calculate total penetration average - manifold.Penetration /= float32(currentPoint) + m.Penetration /= float32(currentPoint) } - manifold.ContactsCount = currentPoint -} - -// integrateForces - Integrates physics forces into velocity -func integrateForces(body *Body) { - if body == nil || body.InverseMass == 0 || !body.Enabled { - return - } - - body.Velocity.X += body.Force.X * body.InverseMass * (deltaTime / 2.0) - body.Velocity.Y += body.Force.Y * body.InverseMass * (deltaTime / 2.0) - - if body.UseGravity { - body.Velocity.X += gravityForce.X * (deltaTime / 1000 / 2.0) - body.Velocity.Y += gravityForce.Y * (deltaTime / 1000 / 2.0) - } - - if !body.FreezeOrient { - body.AngularVelocity += body.Torque * body.InverseInertia * (deltaTime / 2.0) - } + m.ContactsCount = currentPoint } // initializeManifolds - Initializes physics manifolds to solve collisions -func initializeManifolds(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB +func (m *manifold) initializeManifolds() { + bodyA := m.BodyA + bodyB := m.BodyB - if bodyA == nil || bodyB == nil { - return - } + // Calculate average restitution, static and dynamic friction + m.Restitution = float32(math.Sqrt(float64(bodyA.Restitution * bodyB.Restitution))) + m.StaticFriction = float32(math.Sqrt(float64(bodyA.StaticFriction * bodyB.StaticFriction))) + m.DynamicFriction = float32(math.Sqrt(float64(bodyA.DynamicFriction * bodyB.DynamicFriction))) - // // Calculate average restitution, static and dynamic friction - manifold.Restitution = float32(math.Sqrt(float64(bodyA.Restitution * bodyB.Restitution))) - manifold.StaticFriction = float32(math.Sqrt(float64(bodyA.StaticFriction * bodyB.StaticFriction))) - manifold.DynamicFriction = float32(math.Sqrt(float64(bodyA.DynamicFriction * bodyB.DynamicFriction))) - - for i := 0; i < manifold.ContactsCount; i++ { + for i := 0; i < 2; i++ { // Caculate radius from center of mass to contact - radiusA := rl.Vector2Subtract(manifold.Contacts[i], bodyA.Position) - radiusB := rl.Vector2Subtract(manifold.Contacts[i], bodyB.Position) + radiusA := rl.Vector2Subtract(m.Contacts[i], bodyA.Position) + radiusB := rl.Vector2Subtract(m.Contacts[i], bodyB.Position) crossA := rl.Vector2Cross(bodyA.AngularVelocity, radiusA) crossB := rl.Vector2Cross(bodyB.AngularVelocity, radiusB) - radiusV := rl.NewVector2( - bodyB.Velocity.X+crossB.X-bodyA.Velocity.X-crossA.X, - bodyB.Velocity.Y+crossB.Y-bodyA.Velocity.Y-crossA.Y, - ) + + radiusV := rl.Vector2{} + radiusV.X = bodyB.Velocity.X + crossB.X - bodyA.Velocity.X - crossA.X + radiusV.Y = bodyB.Velocity.Y + crossB.Y - bodyA.Velocity.Y - crossA.Y // Determine if we should perform a resting collision or not; - // The idea is if the only thing moving this object is gravity, then the collision should be - // performed without any restitution - rad := rl.NewVector2(gravityForce.X*deltaTime/1000, gravityForce.Y*deltaTime/1000) - if rl.Vector2LenSqr(radiusV) < (rl.Vector2LenSqr(rad) + epsilon) { - manifold.Restitution = 0 + // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution + if rl.Vector2LenSqr(radiusV) < (rl.Vector2LenSqr(rl.NewVector2(gravityForce.X*deltaTime/1000, gravityForce.Y*deltaTime/1000)) + epsilon) { + m.Restitution = 0 } } } // integrateImpulses - Integrates physics collisions impulses to solve collisions -func integrateImpulses(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB - - if bodyA == nil || bodyB == nil { - return - } +func (m *manifold) integrateImpulses() { + bodyA := m.BodyA + bodyB := m.BodyB // Early out and positional correct if both objects have infinite mass if math.Abs(float64(bodyA.InverseMass+bodyB.InverseMass)) <= epsilon { @@ -1267,78 +1134,64 @@ func integrateImpulses(manifold *Manifold) { return } - for i := 0; i < manifold.ContactsCount; i++ { + for i := 0; i < m.ContactsCount; i++ { // Calculate radius from center of mass to contact - radiusA := rl.Vector2Subtract(manifold.Contacts[i], bodyA.Position) - radiusB := rl.Vector2Subtract(manifold.Contacts[i], bodyB.Position) + radiusA := rl.Vector2Subtract(m.Contacts[i], bodyA.Position) + radiusB := rl.Vector2Subtract(m.Contacts[i], bodyB.Position) // Calculate relative velocity - radiusV := rl.NewVector2( - bodyB.Velocity.X+rl.Vector2Cross(bodyB.AngularVelocity, radiusB).X- - bodyA.Velocity.X-rl.Vector2Cross(bodyA.AngularVelocity, radiusA).X, - bodyB.Velocity.Y+rl.Vector2Cross(bodyB.AngularVelocity, radiusB).Y- - bodyA.Velocity.Y-rl.Vector2Cross(bodyA.AngularVelocity, radiusA).Y, - ) + radiusV := rl.Vector2{} + radiusV.X = bodyB.Velocity.X + rl.Vector2Cross(bodyB.AngularVelocity, radiusB).X - bodyA.Velocity.X - rl.Vector2Cross(bodyA.AngularVelocity, radiusA).X + radiusV.Y = bodyB.Velocity.Y + rl.Vector2Cross(bodyB.AngularVelocity, radiusB).Y - bodyA.Velocity.Y - rl.Vector2Cross(bodyA.AngularVelocity, radiusA).Y // Relative velocity along the normal - contactVelocity := rl.Vector2DotProduct(radiusV, manifold.Normal) + contactVelocity := rl.Vector2DotProduct(radiusV, m.Normal) // Do not resolve if velocities are separating if contactVelocity > 0 { return } - raCrossN := rl.Vector2CrossProduct(radiusA, manifold.Normal) - rbCrossN := rl.Vector2CrossProduct(radiusB, manifold.Normal) + raCrossN := rl.Vector2CrossProduct(radiusA, m.Normal) + rbCrossN := rl.Vector2CrossProduct(radiusB, m.Normal) - inverseMassSum := bodyA.InverseMass + bodyB.InverseMass + - (raCrossN*raCrossN)*bodyA.InverseInertia + (rbCrossN*rbCrossN)*bodyB.InverseInertia + inverseMassSum := bodyA.InverseMass + bodyB.InverseMass + (raCrossN*raCrossN)*bodyA.InverseInertia + (rbCrossN*rbCrossN)*bodyB.InverseInertia // Calculate impulse scalar value - impulse := -(manifold.Restitution + 1.0) * contactVelocity + impulse := -(1.0 + m.Restitution) * contactVelocity impulse /= inverseMassSum - impulse /= float32(manifold.ContactsCount) + impulse /= float32(m.ContactsCount) // Apply impulse to each physics body - impulseV := rl.NewVector2(manifold.Normal.X*impulse, manifold.Normal.Y*impulse) + impulseV := rl.NewVector2(m.Normal.X*impulse, m.Normal.Y*impulse) if bodyA.Enabled { bodyA.Velocity.X += bodyA.InverseMass * (-impulseV.X) bodyA.Velocity.Y += bodyA.InverseMass * (-impulseV.Y) - if !bodyA.FreezeOrient { - bodyA.AngularVelocity += bodyA.InverseInertia * - rl.Vector2CrossProduct(radiusA, rl.NewVector2(-impulseV.X, -impulseV.Y)) + bodyA.AngularVelocity += bodyA.InverseInertia * rl.Vector2CrossProduct(radiusA, rl.NewVector2(-impulseV.X, -impulseV.Y)) } } if bodyB.Enabled { - bodyB.Velocity.X += bodyB.InverseMass * impulseV.X - bodyB.Velocity.Y += bodyB.InverseMass * impulseV.Y - + bodyB.Velocity.X += bodyB.InverseMass * (impulseV.X) + bodyB.Velocity.Y += bodyB.InverseMass * (impulseV.Y) if !bodyB.FreezeOrient { bodyB.AngularVelocity += bodyB.InverseInertia * rl.Vector2CrossProduct(radiusB, impulseV) } } // Apply friction impulse to each physics body - radiusV.X = 0 + - bodyB.Velocity.X + rl.Vector2Cross(bodyB.AngularVelocity, radiusB).X - - bodyA.Velocity.X - rl.Vector2Cross(bodyA.AngularVelocity, radiusA).X - radiusV.Y = 0 + - bodyB.Velocity.Y + rl.Vector2Cross(bodyB.AngularVelocity, radiusB).Y - - bodyA.Velocity.Y - rl.Vector2Cross(bodyA.AngularVelocity, radiusA).Y + radiusV.X = bodyB.Velocity.X + rl.Vector2Cross(bodyB.AngularVelocity, radiusB).X - bodyA.Velocity.X - rl.Vector2Cross(bodyA.AngularVelocity, radiusA).X + radiusV.Y = bodyB.Velocity.Y + rl.Vector2Cross(bodyB.AngularVelocity, radiusB).Y - bodyA.Velocity.Y - rl.Vector2Cross(bodyA.AngularVelocity, radiusA).Y - tangent := rl.NewVector2( - radiusV.X-manifold.Normal.X*rl.Vector2DotProduct(radiusV, manifold.Normal), - radiusV.Y-manifold.Normal.Y*rl.Vector2DotProduct(radiusV, manifold.Normal), - ) + tangent := rl.NewVector2(radiusV.X-(m.Normal.X*rl.Vector2DotProduct(radiusV, m.Normal)), radiusV.Y-(m.Normal.Y*rl.Vector2DotProduct(radiusV, m.Normal))) normalize(&tangent) // Calculate impulse tangent magnitude - impulseTangent := -rl.Vector2DotProduct(radiusV, tangent) + impulseTangent := -(rl.Vector2DotProduct(radiusV, tangent)) impulseTangent /= inverseMassSum - impulseTangent /= float32(manifold.ContactsCount) + impulseTangent /= float32(m.ContactsCount) absImpulseTangent := float32(math.Abs(float64(impulseTangent))) @@ -1348,14 +1201,11 @@ func integrateImpulses(manifold *Manifold) { } // Apply coulumb's law - var tangentImpulse rl.Vector2 - if absImpulseTangent < impulse*manifold.StaticFriction { + tangentImpulse := rl.Vector2{} + if absImpulseTangent < impulse*m.StaticFriction { tangentImpulse = rl.NewVector2(tangent.X*impulseTangent, tangent.Y*impulseTangent) } else { - tangentImpulse = rl.NewVector2( - tangent.X*(-impulse)*manifold.DynamicFriction, - tangent.Y*(-impulse)*manifold.DynamicFriction, - ) + tangentImpulse = rl.NewVector2(tangent.X*-impulse*m.DynamicFriction, tangent.Y*-impulse*m.DynamicFriction) } // Apply friction impulse @@ -1364,14 +1214,13 @@ func integrateImpulses(manifold *Manifold) { bodyA.Velocity.Y += bodyA.InverseMass * (-tangentImpulse.Y) if !bodyA.FreezeOrient { - bodyA.AngularVelocity += bodyA.InverseInertia * - rl.Vector2CrossProduct(radiusA, rl.NewVector2(-tangentImpulse.X, -tangentImpulse.Y)) + bodyA.AngularVelocity += bodyA.InverseInertia * rl.Vector2CrossProduct(radiusA, rl.NewVector2(-tangentImpulse.X, -tangentImpulse.Y)) } } if bodyB.Enabled { - bodyB.Velocity.X += bodyB.InverseMass * tangentImpulse.X - bodyB.Velocity.Y += bodyB.InverseMass * tangentImpulse.Y + bodyB.Velocity.X += bodyB.InverseMass * (tangentImpulse.X) + bodyB.Velocity.Y += bodyB.InverseMass * (tangentImpulse.Y) if !bodyB.FreezeOrient { bodyB.AngularVelocity += bodyB.InverseInertia * rl.Vector2CrossProduct(radiusB, tangentImpulse) @@ -1380,34 +1229,14 @@ func integrateImpulses(manifold *Manifold) { } } -// integrateVelocity - Integrates physics velocity into position and forces -func integrateVelocity(body *Body) { - if body == nil || !body.Enabled { - return - } - - body.Position.X += body.Velocity.X * deltaTime - body.Position.Y += body.Velocity.Y * deltaTime - - if !body.FreezeOrient { - body.Orient += body.AngularVelocity * deltaTime - } - - rl.Mat2Set(&body.Shape.Transform, body.Orient) - - integrateForces(body) -} - // correctPositions - Corrects physics bodies positions based on manifolds collision information -func correctPositions(manifold *Manifold) { - bodyA, bodyB := manifold.BodyA, manifold.BodyB - if bodyA == nil || bodyB == nil { - return - } +func (m *manifold) correctPositions() { + bodyA := m.BodyA + bodyB := m.BodyB - corrCoeff := float32(math.Max(float64(manifold.Penetration-penetrationAllowance), 0)) / - (bodyA.InverseMass + bodyB.InverseMass) * penetrationCorrection - correction := rl.NewVector2(corrCoeff*manifold.Normal.X, corrCoeff*manifold.Normal.Y) + correction := rl.Vector2{} + correction.X = float32(math.Max(float64(m.Penetration-penetrationAllowance), 0)) / (bodyA.InverseMass + bodyB.InverseMass) * m.Normal.X * penetrationCorrection + correction.Y = float32(math.Max(float64(m.Penetration-penetrationAllowance), 0)) / (bodyA.InverseMass + bodyB.InverseMass) * m.Normal.Y * penetrationCorrection if bodyA.Enabled { bodyA.Position.X -= correction.X * bodyA.InverseMass @@ -1422,11 +1251,11 @@ func correctPositions(manifold *Manifold) { // getSupport - Returns the extreme point along a direction within a polygon func getSupport(shape Shape, dir rl.Vector2) rl.Vector2 { - bestProjection := float32(-math.MaxFloat32) + bestProjection := float32(-fltMax) bestVertex := rl.Vector2{} for i := 0; i < shape.VertexData.VertexCount; i++ { - vertex := shape.VertexData.Positions[i] + vertex := shape.VertexData.Vertices[i] projection := rl.Vector2DotProduct(vertex, dir) if projection > bestProjection { @@ -1439,27 +1268,28 @@ func getSupport(shape Shape, dir rl.Vector2) rl.Vector2 { } // findAxisLeastPenetration - Finds polygon shapes axis least penetration -func findAxisLeastPenetration(shapeA Shape, shapeB Shape) (int, float32) { +func findAxisLeastPenetration(shapeA, shapeB Shape) (int, float32) { bestIndex := 0 - bestDistance := float32(-math.MaxFloat32) + bestDistance := float32(-fltMax) dataA := shapeA.VertexData + dataB := shapeB.VertexData for i := 0; i < dataA.VertexCount; i++ { // Retrieve a face normal from A shape normal := dataA.Normals[i] - transNormal := rl.Mat2MultiplyVector2(shapeA.Transform, normal) + transNormal := rl.Mat2MultiplyVector2(dataA.Transform, normal) // Transform face normal into B shape's model space - buT := rl.Mat2Transpose(shapeB.Transform) + buT := rl.Mat2Transpose(dataB.Transform) normal = rl.Mat2MultiplyVector2(buT, transNormal) - // Retrieve vertex on face from A shape, transform into B shape's model space + // Retrieve support point from B shape along -n support := getSupport(shapeB, rl.NewVector2(-normal.X, -normal.Y)) // Retrieve vertex on face from A shape, transform into B shape's model space - vertex := dataA.Positions[i] - vertex = rl.Mat2MultiplyVector2(shapeA.Transform, vertex) + vertex := dataA.Vertices[i] + vertex = rl.Mat2MultiplyVector2(dataA.Transform, vertex) vertex = rl.Vector2Add(vertex, shapeA.Body.Position) vertex = rl.Vector2Subtract(vertex, shapeB.Body.Position) vertex = rl.Mat2MultiplyVector2(buT, vertex) @@ -1474,25 +1304,27 @@ func findAxisLeastPenetration(shapeA Shape, shapeB Shape) (int, float32) { } } - return bestIndex, float32(bestDistance) + return bestIndex, bestDistance } // findIncidentFace - Finds two polygon shapes incident face -func findIncidentFace(v0 *rl.Vector2, v1 *rl.Vector2, ref Shape, inc Shape, index int) { +func findIncidentFace(v0, v1 *rl.Vector2, ref, inc Shape, index int) { refData := ref.VertexData incData := inc.VertexData - refNormal := refData.Normals[index] + referenceNormal := refData.Normals[index] // Calculate normal in incident's frame of reference - refNormal = rl.Mat2MultiplyVector2(ref.Transform, refNormal) // To world space - refNormal = rl.Mat2MultiplyVector2(rl.Mat2Transpose(inc.Transform), refNormal) // To incident's model space + referenceNormal = rl.Mat2MultiplyVector2(refData.Transform, referenceNormal) // To world space + referenceNormal = rl.Mat2MultiplyVector2(rl.Mat2Transpose(incData.Transform), referenceNormal) // To incident's model space // Find most anti-normal face on polygon incidentFace := 0 - minDot := float32(math.MaxFloat32) + minDot := float32(fltMax) + for i := 0; i < incData.VertexCount; i++ { - dot := rl.Vector2DotProduct(refNormal, incData.Normals[i]) + dot := rl.Vector2DotProduct(referenceNormal, incData.Normals[i]) + if dot < minDot { minDot = dot incidentFace = i @@ -1500,17 +1332,26 @@ func findIncidentFace(v0 *rl.Vector2, v1 *rl.Vector2, ref Shape, inc Shape, inde } // Assign face vertices for incident face - *v0 = rl.Mat2MultiplyVector2(inc.Transform, incData.Positions[incidentFace]) + *v0 = rl.Mat2MultiplyVector2(incData.Transform, incData.Vertices[incidentFace]) *v0 = rl.Vector2Add(*v0, inc.Body.Position) - incidentFace = getNextIndex(incidentFace, incData.VertexCount) - *v1 = rl.Mat2MultiplyVector2(inc.Transform, incData.Positions[incidentFace]) + + if incidentFace+1 < incData.VertexCount { + incidentFace = incidentFace + 1 + } else { + incidentFace = 0 + } + + *v1 = rl.Mat2MultiplyVector2(incData.Transform, incData.Vertices[incidentFace]) *v1 = rl.Vector2Add(*v1, inc.Body.Position) } // clip - Calculates clipping based on a normal and two faces -func clip(normal rl.Vector2, clip float32, faceA *rl.Vector2, faceB *rl.Vector2) int { +func clip(normal rl.Vector2, clip float32, faceA, faceB *rl.Vector2) int { sp := 0 - out := [2]rl.Vector2{*faceA, *faceB} + + out := make([]rl.Vector2, 2) + out[0] = *faceA + out[1] = *faceB // Retrieve distances from each endpoint to the line distanceA := rl.Vector2DotProduct(normal, *faceA) - clip @@ -1519,12 +1360,11 @@ func clip(normal rl.Vector2, clip float32, faceA *rl.Vector2, faceB *rl.Vector2) // If negative (behind plane) if distanceA <= 0 { out[sp] = *faceA - sp++ + sp += 1 } - if distanceB <= 0 { out[sp] = *faceB - sp++ + sp += 1 } // If the points are on different sides of the plane @@ -1542,61 +1382,38 @@ func clip(normal rl.Vector2, clip float32, faceA *rl.Vector2, faceB *rl.Vector2) // Assign the new converted values *faceA = out[0] *faceB = out[1] + return sp } -// biasGreaterThan - Checks if values are between bias range -func biasGreaterThan(valueA float32, valueB float32) bool { +// biasGreaterThan - Check if values are between bias range +func biasGreaterThan(valueA, valueB float32) bool { return valueA >= (valueB*0.95 + valueA*0.01) } // triangleBarycenter - Returns the barycenter of a triangle given by 3 points -func triangleBarycenter(v1 rl.Vector2, v2 rl.Vector2, v3 rl.Vector2) rl.Vector2 { - return rl.NewVector2( - (v1.X+v2.X+v3.X)/3, - (v1.Y+v2.Y+v3.Y)/3, - ) +func triangleBarycenter(v1, v2, v3 rl.Vector2) rl.Vector2 { + result := rl.Vector2{} + + result.X = (v1.X + v2.X + v3.X) / 3 + result.Y = (v1.Y + v2.Y + v3.Y) / 3 + + return result } -// initTimer - Initializes hi-resolution MONOTONIC timer -func initTimer() { - rand.Seed(getTimeCount()) - frequency = 1000000000 - startTime = getCurrentTime() // Get current time -} +// normalize - Normalize provided vector +func normalize(v *rl.Vector2) { + var length, ilength float32 -// getTimeCount - Gets hi-res MONOTONIC time measure in nanoseconds -func getTimeCount() int64 { - return time.Since(baseTime).Nanoseconds() -} + aux := *v + length = float32(math.Sqrt(float64(aux.X*aux.X + aux.Y*aux.Y))) -// getCurrentTime - Gets current time measure in milliseconds -func getCurrentTime() float32 { - return float32(getTimeCount()) / float32(frequency) * 1000 -} - -// normalize - Returns the normalized values of a vector -func normalize(vector *rl.Vector2) { - aux := *vector - length := float32(math.Sqrt(float64(aux.X*aux.X + aux.Y*aux.Y))) if length == 0 { length = 1.0 } - ilength := 1.0 / length - vector.X *= ilength - vector.Y *= ilength -} -func getNextIndex(i, count int) int { - if i+1 < count { - return i + 1 - } - return 0 -} + ilength = 1.0 / length -func safeDiv(a, b float32) float32 { - if b == 0 { - return 0 - } - return a / b + v.X *= ilength + v.Y *= ilength } diff --git a/raygui/README.md b/raygui/README.md index 85ffb99..bcbaaff 100644 --- a/raygui/README.md +++ b/raygui/README.md @@ -1,13 +1,5 @@ -## raygui [![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/raygui?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/raygui) +## raygui [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/raygui?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/raygui) raygui is simple and easy-to-use IMGUI (immediate mode GUI API) library. - -### controls_test_suite - -![Demo](../examples/gui/controls_test_suite/controls_test_suite.png) - - -### scroll_panel - -![Demo](../examples/gui/scroll_panel/scroll_panel.png) +![screenshot](https://goo.gl/ieeaLj) diff --git a/raygui/button.go b/raygui/button.go new file mode 100644 index 0000000..741e3e9 --- /dev/null +++ b/raygui/button.go @@ -0,0 +1,38 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// buttonColoring describes the per-state properties for a Button control. +type buttonColoring struct { + Border, Inside, Text Property +} + +// buttonColors lists the styling for each supported state. +var buttonColors = map[ControlState]buttonColoring{ + Normal: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, + Clicked: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, + Focused: {ButtonHoverBorderColor, ButtonHoverInsideColor, ButtonHoverTextColor}, + Pressed: {ButtonPressedBorderColor, ButtonPressedInsideColor, ButtonPressedTextColor}, +} + +// Button - Button element, returns true when clicked +func Button(bounds rl.Rectangle, text string) bool { + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(text, textHeight) + + ConstrainRectangle(&bounds, textWidth, textWidth+GetStyle32(ButtonTextPadding), textHeight, textHeight+GetStyle32(ButtonTextPadding)/2) + + // Determine what state we're in and whether its valid. + state := GetInteractionState(bounds) + colors, exist := buttonColors[state] + if !exist { + return false + } + + // Draw control + b := bounds.ToInt32() + DrawBorderedRectangle(b, GetStyle32(ButtonBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.Text)) + + return state == Clicked +} diff --git a/raygui/cgo.go b/raygui/cgo.go deleted file mode 100644 index 4198945..0000000 --- a/raygui/cgo.go +++ /dev/null @@ -1,6 +0,0 @@ -package raygui - -/* -#cgo CFLAGS: -std=gnu99 -Wno-unused-result -*/ -import "C" diff --git a/raygui/checkbox.go b/raygui/checkbox.go new file mode 100644 index 0000000..99a8c6a --- /dev/null +++ b/raygui/checkbox.go @@ -0,0 +1,40 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// checkboxColoring describes the per-state properties for a CheckBox control. +type checkboxColoring struct { + Border, Inside Property +} + +// checkboxColors lists the styling for each supported state. +var checkboxColors = map[ControlState]checkboxColoring{ + Normal: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, + Clicked: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, + Pressed: {CheckboxClickBorderColor, CheckboxClickInsideColor}, + Focused: {CheckboxHoverBorderColor, CheckboxHoverInsideColor}, +} + +// CheckBox - Check Box element, returns true when active +func CheckBox(bounds rl.Rectangle, checked bool) bool { + state := GetInteractionState(bounds) + colors, exists := checkboxColors[state] + if !exists { + return checked + } + + // Update control + if state == Clicked { + checked = !checked + } + + // Render control + box := bounds.ToInt32() + DrawBorderedRectangle(box, GetStyle32(ToggleBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + if checked { + // Show the inner button. + DrawInsetRectangle(box, GetStyle32(CheckboxInsideWidth), GetStyleColor(CheckboxDefaultActiveColor)) + } + + return checked +} diff --git a/raygui/combobox.go b/raygui/combobox.go new file mode 100644 index 0000000..3de56e6 --- /dev/null +++ b/raygui/combobox.go @@ -0,0 +1,74 @@ +package raygui + +import ( + "fmt" + "github.com/gen2brain/raylib-go/raylib" +) + +// comboboxColoring describes the per-state colors for a Combobox control. +type comboboxColoring struct { + Border Property + Inside Property + List Property + Text Property +} + +// comboboxColors lists the styling for each supported state. +var comboboxColors = map[ControlState]comboboxColoring{ + Normal: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, + Clicked: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, + Focused: {ComboboxHoverBorderColor, ComboboxHoverInsideColor, ComboboxHoverListTextColor, ComboboxHoverTextColor}, + Pressed: {ComboboxPressedBorderColor, ComboboxPressedInsideColor, ComboboxPressedListTextColor, ComboboxPressedTextColor}, +} + +// ComboBox draws a simplified version of a ComboBox allowing the user to select a string +// from a list accompanied by an N/M counter. The widget does not provide a drop-down/completion +// or any input support. +func ComboBox(bounds rl.Rectangle, comboText []string, active int) int { + // Reject invalid selections and disable rendering. + comboCount := len(comboText) + if active < 0 || active >= comboCount { + rl.TraceLog(rl.LogWarning, "ComboBox active expects 0 <= active <= %d", comboCount) + return -1 + } + + // Calculate text dimensions. + textHeight := GetStyle32(GlobalTextFontsize) + activeText := comboText[active] + textWidth := rl.MeasureText(activeText, textHeight) + + // Ensure box is large enough. + ConstrainRectangle(&bounds, textWidth, textWidth + GetStyle32(ToggleTextPadding), textHeight, textHeight + GetStyle32(ToggleTextPadding)) + b := bounds.ToInt32() + + // Generate the worst-case sizing of the counter so we can avoid resizing it as the numbers go up/down. + clickWidth := rl.MeasureText(fmt.Sprintf("%d/%d", comboCount, comboCount), b.Height) + + // Counter shows the index of the selection and the maximum number, e.g. "1/3". + counter := rl.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(clickWidth), float32(b.Height)) + c := counter.ToInt32() + + // Determine if the user is interacting with the control, and if so, which state it is in. + state := GetInteractionState(bounds, counter) + colors, exists := comboboxColors[state] + if !exists { + return active + } + + // Update the control when the user releases the mouse over it. + if state == Clicked { + // increment but wrap to 0 on reaching end-of-list. + active = (active + 1) % comboCount + } + + // Render the box itself + DrawBorderedRectangle(b, GetStyle32(ComboboxBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + rl.DrawText(activeText, b.X+((b.Width/2)-(rl.MeasureText(activeText, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.Text)) + + // Render the accompanying "clicks" box showing the element counter. + DrawBorderedRectangle(c, GetStyle32(ComboboxBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + counterText := fmt.Sprintf("%d/%d", active+1, comboCount) + rl.DrawText(counterText, c.X+((c.Width/2)-(rl.MeasureText(counterText, textHeight)/2)), c.Y+((c.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.List)) + + return active +} diff --git a/raygui/cstring.go b/raygui/cstring.go deleted file mode 100644 index 023bfd4..0000000 --- a/raygui/cstring.go +++ /dev/null @@ -1,102 +0,0 @@ -package raygui - -/* -#include -// Code from https://blog.pytool.com/language/golang/cgo/go-cgo-string/ - -static char** make_str_array(int size) { - return calloc(sizeof(char*), size); -} - -static int len_str_array(char **arr) { - int i = 0; - while (arr[i] != NULL) i++; - return i+1; // NULL does count -} - -static void set_str_array(char **arr, int idx, char *s) { - arr[idx] = s; -} - -static void free_str_array(char **arr, int size) { - int i; - for (i = 0; i < size; i++) { - free(arr[i]); - } - free(arr); -} -*/ -import "C" - -import ( - "unsafe" -) - -// CStringArray represents an array of pointers to NULL terminated C strings, -// the array itself is terminated with a NULL -type CStringArray struct { - Pointer unsafe.Pointer - Length int -} - -// NewCStringArray returns an instance of CStringArray -func NewCStringArray() *CStringArray { - return &CStringArray{} -} - -// NewCStringArrayFromSlice makes an instance of CStringArray then copy the -// input slice to it. -func NewCStringArrayFromSlice(ss []string) *CStringArray { - var arr CStringArray - arr.Copy(ss) - return &arr -} - -func NewCStringArrayFromPointer(p unsafe.Pointer) *CStringArray { - return &CStringArray{ - Length: int(C.len_str_array((**C.char)(p))), - Pointer: p, - } -} - -// ToSlice converts CStringArray to Go slice of strings -func (arr *CStringArray) ToSlice() []string { - if arr.Length == 0 || arr.Pointer == nil { - return []string{} - } - - var ss []string - var cs **C.char - defer C.free(unsafe.Pointer(cs)) - p := uintptr(arr.Pointer) - for { - cs = *(***C.char)(unsafe.Pointer(&p)) - if *cs == nil { // skip NULL - the last element - break - } - ss = append(ss, C.GoString(*cs)) - p += unsafe.Sizeof(p) - } - - return ss -} - -// Copy converts Go slice of strings to C underlying struct of CStringArray -func (arr *CStringArray) Copy(ss []string) { - arr.Length = len(ss) + 1 // one more element for NULL at the end - arr.Pointer = unsafe.Pointer(C.make_str_array(C.int(arr.Length))) - - for i, s := range ss { - cs := C.CString(s) // will be free by Free() method - C.set_str_array((**C.char)(arr.Pointer), C.int(i), cs) - } -} - -// Free frees C underlying struct of CStringArray -// MUST call this method after using CStringArray -// Exception: If you use NewCStringArrayFromPointer() to create CStringArray object -// and you use other way to free C underlying structure pointed by the pointer, -// then don't need to call Free() -func (arr *CStringArray) Free() { - C.free_str_array((**C.char)(arr.Pointer), C.int(arr.Length)) -} diff --git a/raygui/go.mod b/raygui/go.mod deleted file mode 100644 index e9096e0..0000000 --- a/raygui/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module git.terah.dev/UnrealXR/raylib-go/raygui - -go 1.21 - -require git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b - -require ( - github.com/ebitengine/purego v0.8.1 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/sys v0.27.0 // indirect -) diff --git a/raygui/go.sum b/raygui/go.sum deleted file mode 100644 index 62eb5f5..0000000 --- a/raygui/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= -github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b h1:wK8D9x3f+BX1xFGgjj399dYx2eskikDZHxlRaSSA19Q= -git.terah.dev/UnrealXR/raylib-go/raylib v0.0.0-20241202103652-5d50abe7c65b/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/raygui/label.go b/raygui/label.go new file mode 100644 index 0000000..e253a93 --- /dev/null +++ b/raygui/label.go @@ -0,0 +1,21 @@ +package raygui + +import rl "github.com/gen2brain/raylib-go/raylib" + +// Label - Label element, show text +func Label(bounds rl.Rectangle, text string) { + LabelEx(bounds, text, rl.GetColor(int32(style[LabelTextColor])), rl.NewColor(0, 0, 0, 0), rl.NewColor(0, 0, 0, 0)) +} + +// LabelEx - Label element extended, configurable colors +func LabelEx(bounds rl.Rectangle, text string, textColor, border, inner rl.Color) { + textHeight := GetStyle32(GlobalTextFontsize) + textWidth := rl.MeasureText(text, textHeight) + + ConstrainRectangle(&bounds, textWidth, textWidth + GetStyle32(LabelTextPadding), textHeight, textHeight + GetStyle32(LabelTextPadding) / 2) + + // Draw control + b := bounds.ToInt32() + DrawBorderedRectangle(b, GetStyle32(LabelBorderWidth), border, inner) + rl.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) +} diff --git a/raygui/progressbar.go b/raygui/progressbar.go new file mode 100644 index 0000000..a9410b8 --- /dev/null +++ b/raygui/progressbar.go @@ -0,0 +1,23 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// ProgressBar - Progress Bar element, shows current progress value +func ProgressBar(bounds rl.Rectangle, value float32) { + b := bounds.ToInt32() + if value > 1.0 { + value = 1.0 + } else if value < 0.0 { + value = 0.0 + } + + borderWidth := GetStyle32(ProgressbarBorderWidth) + progressBar := InsetRectangle(b, borderWidth) // backing rectangle + progressWidth := int32(value * float32(progressBar.Width)) // how much should be replaced with progress + progressValue := rl.RectangleInt32{progressBar.X, progressBar.Y, progressWidth, progressBar.Height} + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, GetStyleColor(ProgressbarBorderColor)) + rl.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, GetStyleColor(ProgressbarInsideColor)) + rl.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, GetStyleColor(ProgressbarProgressColor)) +} diff --git a/raygui/raygui.go b/raygui/raygui.go index e41a749..6224a8a 100644 --- a/raygui/raygui.go +++ b/raygui/raygui.go @@ -1,1395 +1,79 @@ +// Package raygui - Simple and easy-to-use IMGUI (immediate mode GUI API) library + package raygui -/* -#define RAYGUI_IMPLEMENTATION -#include "raygui.h" -#include -*/ -import "C" - import ( - "image/color" - "strings" - "unsafe" - - rl "git.terah.dev/UnrealXR/raylib-go/raylib" + rl "github.com/gen2brain/raylib-go/raylib" ) +// GUI controls states +type ControlState int + const ( - SCROLLBAR_LEFT_SIDE = 0 - SCROLLBAR_RIGHT_SIDE = 1 + Disabled ControlState = iota + // Normal is the default state for rendering GUI elements. + Normal + // Focused indicates the mouse is hovering over the GUI element. + Focused + // Pressed indicates the mouse is hovering over the GUI element and LMB is pressed down. + Pressed + // Clicked indicates the mouse is hovering over the GUI element and LMB has just been released. + Clicked ) -// GuiStyleProp - Style property -type GuiStyleProp struct { - controlId uint16 - propertyId uint16 - propertyValue uint32 -} - -// Gui control state -const ( - STATE_NORMAL int32 = 0 - STATE_FOCUSED = 1 - STATE_PRESSED = 2 - STATE_DISABLED = 3 -) - -// GuiState . -type GuiState = int32 - -// Gui control text alignment -const ( - TEXT_ALIGN_LEFT int32 = 0 - TEXT_ALIGN_CENTER = 1 - TEXT_ALIGN_RIGHT = 2 -) - -// GuiTextAlignment . -type GuiTextAlignment = int32 - -// Gui control text alignment vertical -const ( - TEXT_ALIGN_TOP int32 = 0 - TEXT_ALIGN_MIDDLE = 1 - TEXT_ALIGN_BOTTOM = 2 -) - -// GuiTextWrapMode . -type GuiTextWrapMode = int32 - -// Gui control text wrap mode -// NOTE: Useful for multiline text -const ( - TEXT_WRAP_NONE int32 = 0 - TEXT_WRAP_CHAR = 1 - TEXT_WRAP_WORD = 2 -) - -// GuiTextAlignmentVertical . -type GuiTextAlignmentVertical = int32 - -// DEFAULT - Gui controls -const ( - DEFAULT int32 = 0 - LABEL = 1 - BUTTON = 2 - TOGGLE = 3 - SLIDER = 4 - PROGRESSBAR = 5 - CHECKBOX = 6 - COMBOBOX = 7 - DROPDOWNBOX = 8 - TEXTBOX = 9 - VALUEBOX = 10 - SPINNER = 11 - LISTVIEW = 12 - COLORPICKER = 13 - SCROLLBAR = 14 - STATUSBAR = 15 -) - -// GuiControl . -type GuiControl = int32 - -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) -const ( - BORDER_COLOR_NORMAL int32 = 0 - BASE_COLOR_NORMAL = 1 - TEXT_COLOR_NORMAL = 2 - BORDER_COLOR_FOCUSED = 3 - BASE_COLOR_FOCUSED = 4 - TEXT_COLOR_FOCUSED = 5 - BORDER_COLOR_PRESSED = 6 - BASE_COLOR_PRESSED = 7 - TEXT_COLOR_PRESSED = 8 - BORDER_COLOR_DISABLED = 9 - BASE_COLOR_DISABLED = 10 - TEXT_COLOR_DISABLED = 11 - BORDER_WIDTH = 12 - TEXT_PADDING = 13 - TEXT_ALIGNMENT = 14 -) - -// GuiControlProperty . -type GuiControlProperty = int32 - -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -const ( - TEXT_SIZE int32 = 16 - TEXT_SPACING = 17 - LINE_COLOR = 18 - BACKGROUND_COLOR = 19 - TEXT_LINE_SPACING = 20 - TEXT_ALIGNMENT_VERTICAL = 21 - TEXT_WRAP_MODE = 22 -) - -// GuiDefaultProperty . -type GuiDefaultProperty = int32 - -// GROUP_PADDING . -const ( - GROUP_PADDING int32 = 16 -) - -// GuiToggleProperty . -type GuiToggleProperty = int32 - -const ( - // Slider size of internal bar - SLIDER_WIDTH int32 = 16 - // Slider/SliderBar internal bar padding - SLIDER_PADDING = 17 -) - -// GuiSliderProperty . -type GuiSliderProperty = int32 - -const ( - // ProgressBar internal padding - PROGRESS_PADDING int32 = 16 -) - -// GuiProgressBarProperty . -type GuiProgressBarProperty = int32 - -const ( - ARROWS_SIZE int32 = 16 - ARROWS_VISIBLE = 17 - SCROLL_SLIDER_PADDING = 18 - SCROLL_SLIDER_SIZE = 19 - SCROLL_PADDING = 20 - SCROLL_SPEED = 21 -) - -// GuiScrollBarProperty . -type GuiScrollBarProperty = int32 - -const ( - CHECK_PADDING int32 = 16 -) - -// GuiCheckBoxProperty . -type GuiCheckBoxProperty = int32 - -const ( - // ComboBox right button width - COMBO_BUTTON_WIDTH int32 = 16 - // ComboBox button separation - COMBO_BUTTON_SPACING = 17 -) - -// GuiComboBoxProperty . -type GuiComboBoxProperty = int32 - -const ( - // DropdownBox arrow separation from border and items - ARROW_PADDING int32 = 16 - // DropdownBox items separation - DROPDOWN_ITEMS_SPACING = 17 -) - -// GuiDropdownBoxProperty . -type GuiDropdownBoxProperty = int32 - -const ( - // TextBox/TextBoxMulti/ValueBox/Spinner inner text padding - TEXT_INNER_PADDING int32 = 16 - // TextBoxMulti lines separation - TEXT_LINES_SPACING = 17 -) - -// GuiTextBoxProperty . -type GuiTextBoxProperty = int32 - -const ( - // Spinner left/right buttons width - SPIN_BUTTON_WIDTH int32 = 16 - // Spinner buttons separation - SPIN_BUTTON_SPACING = 17 -) - -// GuiSpinnerProperty . -type GuiSpinnerProperty = int32 - -const ( - // ListView items height - LIST_ITEMS_HEIGHT int32 = 16 - // ListView items separation - LIST_ITEMS_SPACING = 17 - // ListView scrollbar size (usually width) - SCROLLBAR_WIDTH = 18 - // ListView scrollbar side (0-left, 1-right) - SCROLLBAR_SIDE = 19 -) - -// GuiListViewProperty . -type GuiListViewProperty = int32 - -const ( - COLOR_SELECTOR_SIZE int32 = 16 - // rl.ColorPicker right hue bar width - HUEBAR_WIDTH = 17 - // rl.ColorPicker right hue bar separation from panel - HUEBAR_PADDING = 18 - // rl.ColorPicker right hue bar selector height - HUEBAR_SELECTOR_HEIGHT = 19 - // rl.ColorPicker right hue bar selector overflow - HUEBAR_SELECTOR_OVERFLOW = 20 -) - -// GuiColorPickerProperty . -type GuiColorPickerProperty = int32 - -// GuiEnable - Enable gui controls (global state) -func Enable() { - C.GuiEnable() -} - -// GuiDisable - Disable gui controls (global state) -func Disable() { - C.GuiDisable() -} - -// GuiLock - Lock gui controls (global state) -func Lock() { - C.GuiLock() -} - -// GuiUnlock - Unlock gui controls (global state) -func Unlock() { - C.GuiUnlock() -} - -// GuiIsLocked - Check if gui is locked (global state) -func IsLocked() bool { - return bool(C.GuiIsLocked()) -} - -// GuiFade - Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f -func Fade(color rl.Color, alpha float32) { - ccolor := (*C.Color)(unsafe.Pointer(&color)) - calpha := C.float(alpha) - C.GuiFade(*ccolor, calpha) -} - -// GuiSetState - Set gui state (global state) -func SetState(state int32) { - cstate := C.int(state) - C.GuiSetState(cstate) -} - -// GuiGetState - Get gui state (global state) -func GetState() int32 { - return int32(C.GuiGetState()) -} - -// GuiSetStyle . -func SetStyle(control int32, property int32, value int64) { - ccontrol := C.int(control) - cproperty := C.int(property) - cvalue := C.int(value) - C.GuiSetStyle(ccontrol, cproperty, cvalue) -} - -// GuiGetStyle - Get one style property -func GetStyle(control int32, property int32) int64 { - ccontrol := C.int(control) - cproperty := C.int(property) - return int64(C.GuiGetStyle(ccontrol, cproperty)) -} - -// GuiWindowBox - Window Box control, shows a window that can be closed -func WindowBox(bounds rl.Rectangle, title string) bool { - var cbounds C.struct_Rectangle - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - var ctitle *C.char - if len(title) > 0 { - ctitle = C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) +// IsColliding will return true if 'point' is within any of the given rectangles. +func IsInAny(point rl.Vector2, rectangles ...rl.Rectangle) bool { + for _, rect := range rectangles { + if rl.CheckCollisionPointRec(point, rect) { + return true + } } - return C.GuiWindowBox(cbounds, ctitle) != 0 + return false } -// GuiGroupBox - Group Box control with text name -func GroupBox(bounds rl.Rectangle, text string) { - var cbounds C.struct_Rectangle - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) +// GetInteractionState determines the current state of a control based on mouse position and +// button states. +func GetInteractionState(rectangles ...rl.Rectangle) ControlState { + switch { + case !IsInAny(rl.GetMousePosition(), rectangles...): + return Normal + case rl.IsMouseButtonDown(rl.MouseLeftButton): + return Pressed + case rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton): + return Clicked + default: + return Focused } - C.GuiGroupBox(cbounds, ctext) } -// GuiLine - Line separator control, could contain text -func Line(bounds rl.Rectangle, text string) { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) +// Constrain rectangle will ensure that if width/height are below given minimums, they will +// be set to an ideal minimum. +func ConstrainRectangle(bounds *rl.Rectangle, minWidth, idealWidth, minHeight, idealHeight int32) { + if int32(bounds.Width) < minWidth { + bounds.Width = float32(idealWidth) + } + if int32(bounds.Height) < minHeight { + bounds.Height = float32(idealHeight) } - C.GuiLine(cbounds, ctext) } -// Panel - Panel control, useful to group controls -func Panel(bounds rl.Rectangle, text string) { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) +// InsetRectangle returns the dimensions of a rectangle inset by a margin within an outer rectangle. +func InsetRectangle(outer rl.RectangleInt32, inset int32) rl.RectangleInt32 { + return rl.RectangleInt32{ + X: outer.X + inset, Y: outer.Y + inset, + Width: outer.Width - 2*inset, Height: outer.Height - 2*inset, } - C.GuiPanel(cbounds, ctext) } -// ScrollPanel control - Scroll Panel control -func ScrollPanel(bounds rl.Rectangle, text string, content rl.Rectangle, scroll *rl.Vector2, view *rl.Rectangle) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - var ccontent C.struct_Rectangle - ccontent.x = C.float(content.X) - ccontent.y = C.float(content.Y) - ccontent.width = C.float(content.Width) - ccontent.height = C.float(content.Height) - var cscroll C.struct_Vector2 - cscroll.x = C.float(scroll.X) - cscroll.y = C.float(scroll.Y) - defer func() { - scroll.X = float32(cscroll.x) - scroll.Y = float32(cscroll.y) - }() - var cview C.struct_Rectangle - cview.x = C.float(view.X) - cview.y = C.float(view.Y) - cview.width = C.float(view.Width) - cview.height = C.float(view.Height) - defer func() { - view.X = float32(cview.x) - view.Y = float32(cview.y) - view.Width = float32(cview.width) - view.Height = float32(cview.height) - }() - - res := C.GuiScrollPanel(cbounds, ctext, ccontent, &cscroll, &cview) - - return int32(res) +// DrawInsetRectangle is a helper to draw a box inset by a margin of an outer container. +func DrawInsetRectangle(outer rl.RectangleInt32, inset int32, color rl.Color) { + inside := InsetRectangle(outer, inset) + rl.DrawRectangle(inside.X, inside.Y, inside.Width, inside.Height, color) } -// ScrollBar control (used by GuiScrollPanel()) -func ScrollBar(bounds rl.Rectangle, value, minValue, maxValue int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - - cvalue := C.int(value) - cminValue := C.int(minValue) - cmaxValue := C.int(maxValue) - - return int32(C.GuiScrollBar(cbounds, cvalue, cminValue, cmaxValue)) -} - -// Label control, shows text -func Label(bounds rl.Rectangle, text string) { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - C.GuiLabel(cbounds, ctext) -} - -// Button control, returns true when clicked -func Button(bounds rl.Rectangle, text string) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - return C.GuiButton(cbounds, ctext) != 0 -} - -// LabelButton control, show true when clicked -func LabelButton(bounds rl.Rectangle, text string) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - return C.GuiLabelButton(cbounds, ctext) != 0 -} - -// Toggle control, returns true when active -func Toggle(bounds rl.Rectangle, text string, active bool) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cactive := C.bool(active) - C.GuiToggle(cbounds, ctext, &cactive) - return bool(cactive) -} - -// ToggleGroup control, returns active toggle index -func ToggleGroup(bounds rl.Rectangle, text string, active int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cactive := C.int(active) - C.GuiToggleGroup(cbounds, ctext, &cactive) - return int32(cactive) -} - -// ToggleSlider control, returns true when clicked -func ToggleSlider(bounds rl.Rectangle, text string, active int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cactive := C.int(active) - C.GuiToggleSlider(cbounds, ctext, &cactive) - return int32(cactive) -} - -// CheckBox control, returns true when active -func CheckBox(bounds rl.Rectangle, text string, checked bool) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cchecked := C.bool(checked) - C.GuiCheckBox(cbounds, ctext, &cchecked) - return bool(cchecked) -} - -// ComboBox control, returns selected item index -func ComboBox(bounds rl.Rectangle, text string, active int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cactive := C.int(active) - C.GuiComboBox(cbounds, ctext, &cactive) - return int32(cactive) -} - -// Spinner control, sets value to the selected number and returns true when clicked. -func Spinner(bounds rl.Rectangle, text string, value *int32, minValue, maxValue int, editMode bool) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - - if value == nil { - value = new(int32) - } - cvalue := C.int(*value) - defer func() { - *value = int32(cvalue) - }() - - cminValue := C.int(minValue) - cmaxValue := C.int(maxValue) - ceditMode := C.bool(editMode) - - return C.GuiSpinner(cbounds, ctext, &cvalue, cminValue, cmaxValue, ceditMode) != 0 -} - -// Slider control -func Slider(bounds rl.Rectangle, textLeft string, textRight string, value float32, minValue float32, maxValue float32) float32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - - var ctextLeft *C.char - if len(textLeft) > 0 { - ctextLeft = C.CString(textLeft) - defer C.free(unsafe.Pointer(ctextLeft)) - } - - var ctextRight *C.char - if len(textRight) > 0 { - ctextRight = C.CString(textRight) - defer C.free(unsafe.Pointer(ctextRight)) - } - - cvalue := C.float(value) - cminValue := C.float(minValue) - cmaxValue := C.float(maxValue) - C.GuiSlider(cbounds, ctextLeft, ctextRight, &cvalue, cminValue, cmaxValue) - return float32(cvalue) -} - -// SliderBar control, returns selected value -func SliderBar(bounds rl.Rectangle, textLeft string, textRight string, value float32, minValue float32, maxValue float32) float32 { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - - var ctextLeft *C.char - if len(textLeft) > 0 { - ctextLeft = C.CString(textLeft) - defer C.free(unsafe.Pointer(ctextLeft)) - } - - var ctextRight *C.char - if len(textRight) > 0 { - ctextRight = C.CString(textRight) - defer C.free(unsafe.Pointer(ctextRight)) - } - - cvalue := C.float(value) - cminValue := C.float(minValue) - cmaxValue := C.float(maxValue) - C.GuiSliderBar(cbounds, ctextLeft, ctextRight, &cvalue, cminValue, cmaxValue) - return float32(cvalue) -} - -// ProgressBar control, shows current progress value -func ProgressBar(bounds rl.Rectangle, textLeft string, textRight string, value float32, minValue float32, maxValue float32) float32 { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - - var ctextLeft *C.char - if len(textLeft) > 0 { - ctextLeft = C.CString(textLeft) - defer C.free(unsafe.Pointer(ctextLeft)) - } - - var ctextRight *C.char - if len(textRight) > 0 { - ctextRight = C.CString(textRight) - defer C.free(unsafe.Pointer(ctextRight)) - } - - cvalue := C.float(value) - cminValue := C.float(minValue) - cmaxValue := C.float(maxValue) - C.GuiProgressBar(cbounds, ctextLeft, ctextRight, &cvalue, cminValue, cmaxValue) - return float32(cvalue) -} - -// StatusBar control, shows info text -func StatusBar(bounds rl.Rectangle, text string) { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - C.GuiStatusBar(cbounds, ctext) -} - -// DummyRec control for placeholders -func DummyRec(bounds rl.Rectangle, text string) { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - C.GuiDummyRec(cbounds, ctext) -} - -// Grid control, returns mouse cell position -func Grid(bounds rl.Rectangle, text string, spacing float32, subdivs int32, mouseCell *rl.Vector2) int32 { - var cbounds C.struct_Rectangle - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cspacing := C.float(spacing) - csubdivs := C.int(subdivs) - var cmouseCell C.struct_Vector2 - cmouseCell.x = C.float(mouseCell.X) - cmouseCell.y = C.float(mouseCell.Y) - res := C.GuiGrid(cbounds, ctext, cspacing, csubdivs, &cmouseCell) - mouseCell.X = float32(cmouseCell.x) - mouseCell.Y = float32(cmouseCell.y) - return int32(res) -} - -// ListView control, returns selected list item index -func ListView(bounds rl.Rectangle, text string, scrollIndex *int32, active int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - - if scrollIndex == nil { - scrollIndex = new(int32) - } - cscrollIndex := C.int(*scrollIndex) - defer func() { - *scrollIndex = int32(cscrollIndex) - }() - - cactive := C.int(active) - - C.GuiListView(cbounds, ctext, &cscrollIndex, &cactive) - return int32(cactive) -} - -// MessageBox control, displays a message -func MessageBox(bounds rl.Rectangle, title string, message string, buttons string) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctitle *C.char - if len(title) > 0 { - ctitle = C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) - } - var cmessage *C.char - if len(message) > 0 { - cmessage = C.CString(message) - defer C.free(unsafe.Pointer(cmessage)) - } - cbuttons := C.CString(buttons) - defer C.free(unsafe.Pointer(cbuttons)) - return int32(C.GuiMessageBox(cbounds, ctitle, cmessage, cbuttons)) -} - -// ColorPicker control (multiple color controls) -func ColorPicker(bounds rl.Rectangle, text string, color rl.Color) rl.Color { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - var ccolor C.struct_Color - ccolor.r = C.uchar(color.R) - ccolor.g = C.uchar(color.G) - ccolor.b = C.uchar(color.B) - ccolor.a = C.uchar(color.A) - C.GuiColorPicker(cbounds, ctext, &ccolor) - var goRes rl.Color - goRes.A = byte(ccolor.a) - goRes.R = byte(ccolor.r) - goRes.G = byte(ccolor.g) - goRes.B = byte(ccolor.b) - return goRes -} - -// ColorPanel control -func ColorPanel(bounds rl.Rectangle, text string, color rl.Color) rl.Color { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - var ccolor C.struct_Color - ccolor.b = C.uchar(color.B) - ccolor.a = C.uchar(color.A) - ccolor.r = C.uchar(color.R) - ccolor.g = C.uchar(color.G) - C.GuiColorPanel(cbounds, ctext, &ccolor) - var goRes rl.Color - goRes.A = byte(ccolor.a) - goRes.R = byte(ccolor.r) - goRes.G = byte(ccolor.g) - goRes.B = byte(ccolor.b) - return goRes -} - -// ColorBarAlpha control -func ColorBarAlpha(bounds rl.Rectangle, text string, alpha float32) float32 { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - calpha := C.float(alpha) - C.GuiColorBarAlpha(cbounds, ctext, &calpha) - return float32(calpha) -} - -// ColorBarHue control -func ColorBarHue(bounds rl.Rectangle, text string, value float32) float32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - cvalue := C.float(value) - C.GuiColorBarHue(cbounds, ctext, &cvalue) - return float32(cvalue) -} - -// ColorPickerHSV - Color Picker control that avoids conversion to RGB on each call (multiple color controls) -func ColorPickerHSV(bounds rl.Rectangle, text string, colorHSV *rl.Vector3) int32 { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - - var ccolorHSV C.struct_Vector3 - ccolorHSV.x = C.float(colorHSV.X) - ccolorHSV.y = C.float(colorHSV.Y) - ccolorHSV.z = C.float(colorHSV.Z) - defer func() { - colorHSV.X = float32(ccolorHSV.x) - colorHSV.Y = float32(ccolorHSV.y) - colorHSV.Z = float32(ccolorHSV.z) - }() - - return int32(C.GuiColorPickerHSV(cbounds, ctext, &ccolorHSV)) -} - -// ColorPanelHSV - Color Panel control that returns HSV color value, used by GuiColorPickerHSV() -func ColorPanelHSV(bounds rl.Rectangle, text string, colorHSV *rl.Vector3) int32 { - var cbounds C.struct_Rectangle - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - - var ccolorHSV C.struct_Vector3 - ccolorHSV.x = C.float(colorHSV.X) - ccolorHSV.y = C.float(colorHSV.Y) - ccolorHSV.z = C.float(colorHSV.Z) - defer func() { - colorHSV.X = float32(ccolorHSV.x) - colorHSV.Y = float32(ccolorHSV.y) - colorHSV.Z = float32(ccolorHSV.z) - }() - - return int32(C.GuiColorPanelHSV(cbounds, ctext, &ccolorHSV)) -} - -// DropdownBox control -func DropdownBox(bounds rl.Rectangle, text string, active *int32, editMode bool) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - - if active == nil { - active = new(int32) - } - cactive := C.int(*active) - defer func() { - *active = int32(cactive) - }() - - ceditMode := C.bool(editMode) - - return C.GuiDropdownBox(cbounds, ctext, &cactive, ceditMode) != 0 -} - -// ValueBox control, updates input text with numbers -func ValueBox(bounds rl.Rectangle, text string, value *int32, minValue, maxValue int, editMode bool) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - var ctext *C.char - if len(text) > 0 { - ctext = C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - } - - if value == nil { - value = new(int32) - } - cvalue := C.int(*value) - defer func() { - *value = int32(cvalue) - }() - - cminValue := C.int(minValue) - cmaxValue := C.int(maxValue) - ceditMode := C.bool(editMode) - - return C.GuiValueBox(cbounds, ctext, &cvalue, cminValue, cmaxValue, ceditMode) != 0 -} - -// TextBox control, updates input text -func TextBox(bounds rl.Rectangle, text *string, textSize int, editMode bool) bool { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - - bs := []byte(*text) - if len(bs) == 0 { - bs = []byte{byte(0)} - } - if 0 < len(bs) && bs[len(bs)-1] != byte(0) { // minimalize allocation - bs = append(bs, byte(0)) // for next input symbols - } - ctext := (*C.char)(unsafe.Pointer(&bs[0])) - defer func() { - *text = strings.Trim(string(bs), "\x00") - // no need : C.free(unsafe.Pointer(ctext)) - }() - - ctextSize := C.int(textSize) - ceditMode := C.bool(editMode) - - return C.GuiTextBox(cbounds, ctext, ctextSize, ceditMode) != 0 -} - -// LoadStyle file over global style variable (.rgs) -func LoadStyle(fileName string) { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - C.GuiLoadStyle(cfileName) -} - -// LoadStyleDefault over global style -func LoadStyleDefault() { - C.GuiLoadStyleDefault() -} - -// LoadStyleFromMemory - Load style from memory (binary only) -func LoadStyleFromMemory(data []byte) { - C.GuiLoadStyleFromMemory((*C.uchar)(unsafe.Pointer(&data[0])), C.int(len(data))) -} - -// IconText gets text with icon id prepended (if supported) -func IconText(iconId int32, text string) string { - ciconId := C.int(iconId) - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - return C.GoString(C.GuiIconText(ciconId, ctext)) -} - -// Icons enumeration -const ( - ICON_NONE int32 = iota - ICON_FOLDER_FILE_OPEN - ICON_FILE_SAVE_CLASSIC - ICON_FOLDER_OPEN - ICON_FOLDER_SAVE - ICON_FILE_OPEN - ICON_FILE_SAVE - ICON_FILE_EXPORT - ICON_FILE_ADD - ICON_FILE_DELETE - ICON_FILETYPE_TEXT - ICON_FILETYPE_AUDIO - ICON_FILETYPE_IMAGE - ICON_FILETYPE_PLAY - ICON_FILETYPE_VIDEO - ICON_FILETYPE_INFO - ICON_FILE_COPY - ICON_FILE_CUT - ICON_FILE_PASTE - ICON_CURSOR_HAND - ICON_CURSOR_POINTER - ICON_CURSOR_CLASSIC - ICON_PENCIL - ICON_PENCIL_BIG - ICON_BRUSH_CLASSIC - ICON_BRUSH_PAINTER - ICON_WATER_DROP - ICON_COLOR_PICKER - ICON_RUBBER - ICON_COLOR_BUCKET - ICON_TEXT_T - ICON_TEXT_A - ICON_SCALE - ICON_RESIZE - ICON_FILTER_POINT - ICON_FILTER_BILINEAR - ICON_CROP - ICON_CROP_ALPHA - ICON_SQUARE_TOGGLE - ICON_SYMMETRY - ICON_SYMMETRY_HORIZONTAL - ICON_SYMMETRY_VERTICAL - ICON_LENS - ICON_LENS_BIG - ICON_EYE_ON - ICON_EYE_OFF - ICON_FILTER_TOP - ICON_FILTER - ICON_TARGET_POINT - ICON_TARGET_SMALL - ICON_TARGET_BIG - ICON_TARGET_MOVE - ICON_CURSOR_MOVE - ICON_CURSOR_SCALE - ICON_CURSOR_SCALE_RIGHT - ICON_CURSOR_SCALE_LEFT - ICON_UNDO - ICON_REDO - ICON_REREDO - ICON_MUTATE - ICON_ROTATE - ICON_REPEAT - ICON_SHUFFLE - ICON_EMPTYBOX - ICON_TARGET - ICON_TARGET_SMALL_FILL - ICON_TARGET_BIG_FILL - ICON_TARGET_MOVE_FILL - ICON_CURSOR_MOVE_FILL - ICON_CURSOR_SCALE_FILL - ICON_CURSOR_SCALE_RIGHT_FILL - ICON_CURSOR_SCALE_LEFT_FILL - ICON_UNDO_FILL - ICON_REDO_FILL - ICON_REREDO_FILL - ICON_MUTATE_FILL - ICON_ROTATE_FILL - ICON_REPEAT_FILL - ICON_SHUFFLE_FILL - ICON_EMPTYBOX_SMALL - ICON_BOX - ICON_BOX_TOP - ICON_BOX_TOP_RIGHT - ICON_BOX_RIGHT - ICON_BOX_BOTTOM_RIGHT - ICON_BOX_BOTTOM - ICON_BOX_BOTTOM_LEFT - ICON_BOX_LEFT - ICON_BOX_TOP_LEFT - ICON_BOX_CENTER - ICON_BOX_CIRCLE_MASK - ICON_POT - ICON_ALPHA_MULTIPLY - ICON_ALPHA_CLEAR - ICON_DITHERING - ICON_MIPMAPS - ICON_BOX_GRID - ICON_GRID - ICON_BOX_CORNERS_SMALL - ICON_BOX_CORNERS_BIG - ICON_FOUR_BOXES - ICON_GRID_FILL - ICON_BOX_MULTISIZE - ICON_ZOOM_SMALL - ICON_ZOOM_MEDIUM - ICON_ZOOM_BIG - ICON_ZOOM_ALL - ICON_ZOOM_CENTER - ICON_BOX_DOTS_SMALL - ICON_BOX_DOTS_BIG - ICON_BOX_CONCENTRIC - ICON_BOX_GRID_BIG - ICON_OK_TICK - ICON_CROSS - ICON_ARROW_LEFT - ICON_ARROW_RIGHT - ICON_ARROW_DOWN - ICON_ARROW_UP - ICON_ARROW_LEFT_FILL - ICON_ARROW_RIGHT_FILL - ICON_ARROW_DOWN_FILL - ICON_ARROW_UP_FILL - ICON_AUDIO - ICON_FX - ICON_WAVE - ICON_WAVE_SINUS - ICON_WAVE_SQUARE - ICON_WAVE_TRIANGULAR - ICON_CROSS_SMALL - ICON_PLAYER_PREVIOUS - ICON_PLAYER_PLAY_BACK - ICON_PLAYER_PLAY - ICON_PLAYER_PAUSE - ICON_PLAYER_STOP - ICON_PLAYER_NEXT - ICON_PLAYER_RECORD - ICON_MAGNET - ICON_LOCK_CLOSE - ICON_LOCK_OPEN - ICON_CLOCK - ICON_TOOLS - ICON_GEAR - ICON_GEAR_BIG - ICON_BIN - ICON_HAND_POINTER - ICON_LASER - ICON_COIN - ICON_EXPLOSION - ICON_1UP - ICON_PLAYER - ICON_PLAYER_JUMP - ICON_KEY - ICON_DEMON - ICON_TEXT_POPUP - ICON_GEAR_EX - ICON_CRACK - ICON_CRACK_POINTS - ICON_STAR - ICON_DOOR - ICON_EXIT - ICON_MODE_2D - ICON_MODE_3D - ICON_CUBE - ICON_CUBE_FACE_TOP - ICON_CUBE_FACE_LEFT - ICON_CUBE_FACE_FRONT - ICON_CUBE_FACE_BOTTOM - ICON_CUBE_FACE_RIGHT - ICON_CUBE_FACE_BACK - ICON_CAMERA - ICON_SPECIAL - ICON_LINK_NET - ICON_LINK_BOXES - ICON_LINK_MULTI - ICON_LINK - ICON_LINK_BROKE - ICON_TEXT_NOTES - ICON_NOTEBOOK - ICON_SUITCASE - ICON_SUITCASE_ZIP - ICON_MAILBOX - ICON_MONITOR - ICON_PRINTER - ICON_PHOTO_CAMERA - ICON_PHOTO_CAMERA_FLASH - ICON_HOUSE - ICON_HEART - ICON_CORNER - ICON_VERTICAL_BARS - ICON_VERTICAL_BARS_FILL - ICON_LIFE_BARS - ICON_INFO - ICON_CROSSLINE - ICON_HELP - ICON_FILETYPE_ALPHA - ICON_FILETYPE_HOME - ICON_LAYERS_VISIBLE - ICON_LAYERS - ICON_WINDOW - ICON_HIDPI - ICON_FILETYPE_BINARY - ICON_HEX - ICON_SHIELD - ICON_FILE_NEW - ICON_FOLDER_ADD - ICON_ALARM - ICON_CPU - ICON_ROM - ICON_STEP_OVER - ICON_STEP_INTO - ICON_STEP_OUT - ICON_RESTART - ICON_BREAKPOINT_ON - ICON_BREAKPOINT_OFF - ICON_BURGER_MENU - ICON_CASE_SENSITIVE - ICON_REG_EXP - ICON_FOLDER - ICON_FILE - ICON_SAND_TIMER - ICON_220 - ICON_221 - ICON_222 - ICON_223 - ICON_224 - ICON_225 - ICON_226 - ICON_227 - ICON_228 - ICON_229 - ICON_230 - ICON_231 - ICON_232 - ICON_233 - ICON_234 - ICON_235 - ICON_236 - ICON_237 - ICON_238 - ICON_239 - ICON_240 - ICON_241 - ICON_242 - ICON_243 - ICON_244 - ICON_245 - ICON_246 - ICON_247 - ICON_248 - ICON_249 - ICON_250 - ICON_251 - ICON_252 - ICON_253 - ICON_254 - ICON_255 -) - -// TextInputBox control, ask for text -func TextInputBox(bounds rl.Rectangle, title, message, buttons string, text *string, textMaxSize int32, secretViewActive *bool) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - - var ctitle *C.char - if len(title) > 0 { - ctitle = C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) - } - - var cmessage *C.char - if len(message) > 0 { - cmessage = C.CString(message) - defer C.free(unsafe.Pointer(cmessage)) - } - - cbuttons := C.CString(buttons) - defer C.free(unsafe.Pointer(cbuttons)) - - bs := []byte(*text) - if len(bs) == 0 { - bs = []byte{byte(0)} - } - if 0 < len(bs) && bs[len(bs)-1] != byte(0) { // minimalize allocation - bs = append(bs, byte(0)) // for next input symbols - } - ctext := (*C.char)(unsafe.Pointer(&bs[0])) - defer func() { - *text = strings.TrimSpace(strings.Trim(string(bs), "\x00")) - // no need : C.free(unsafe.Pointer(ctext)) - }() - - ctextMaxSize := C.int(textMaxSize) - - csecretViewActive := C.bool(*secretViewActive) - defer func() { - *secretViewActive = bool(csecretViewActive) - }() - - return int32(C.GuiTextInputBox(cbounds, ctitle, cmessage, cbuttons, ctext, ctextMaxSize, &csecretViewActive)) -} - -// ListViewEx control with extended parameters -func ListViewEx(bounds rl.Rectangle, text []string, focus, scrollIndex *int32, active int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - - ctext := NewCStringArrayFromSlice(text) - defer ctext.Free() - - count := C.int(len(text)) - - if focus == nil { - focus = new(int32) - } - cfocus := C.int(*focus) - defer func() { - *focus = int32(cfocus) - }() - - if scrollIndex == nil { - scrollIndex = new(int32) - } - cscrollIndex := C.int(*scrollIndex) - defer func() { - *scrollIndex = int32(cscrollIndex) - }() - - cactive := C.int(active) - - C.GuiListViewEx(cbounds, (**C.char)(ctext.Pointer), count, &cfocus, &cscrollIndex, &cactive) - return int32(cactive) -} - -// TabBar control -func TabBar(bounds rl.Rectangle, text []string, active *int32) int32 { - var cbounds C.struct_Rectangle - cbounds.x = C.float(bounds.X) - cbounds.y = C.float(bounds.Y) - cbounds.width = C.float(bounds.Width) - cbounds.height = C.float(bounds.Height) - - ctext := NewCStringArrayFromSlice(text) - defer ctext.Free() - - count := C.int(len(text)) - - if active == nil { - active = new(int32) - } - cactive := C.int(*active) - defer func() { - *active = int32(cactive) - }() - return int32(C.GuiTabBar(cbounds, (**C.char)(ctext.Pointer), count, &cactive)) -} - -// SetFont - set custom font (global state) -func SetFont(font rl.Font) { - cfont := (*C.Font)(unsafe.Pointer(&font)) - C.GuiSetFont(*cfont) -} - -// GetFont - get custom font (global state) -func GetFont() rl.Font { - ret := C.GuiGetFont() - ptr := unsafe.Pointer(&ret) - return *(*rl.Font)(ptr) -} - -// LoadIcons - load raygui icons file (.rgi) into internal icons data -func LoadIcons(fileName string, loadIconsName bool) { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - C.GuiLoadIcons(cfileName, C.bool(loadIconsName)) -} - -// DrawIcon - draw icon using pixel size at specified position -func DrawIcon(iconId, posX, posY, pixelSize int32, col color.RGBA) { - C.GuiDrawIcon(C.int(iconId), C.int(posX), C.int(posY), C.int(pixelSize), *(*C.Color)(unsafe.Pointer(&col))) +// DrawBorderedRectangle is a helper to draw a box with a border around it. +func DrawBorderedRectangle(bounds rl.RectangleInt32, borderWidth int32, borderColor, insideColor rl.Color) { + inside := InsetRectangle(bounds, borderWidth) + rl.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, borderColor) + rl.DrawRectangle(inside.X, inside.Y, inside.Width, inside.Height, insideColor) } diff --git a/raygui/raygui.h b/raygui/raygui.h deleted file mode 100644 index 9127710..0000000 --- a/raygui/raygui.h +++ /dev/null @@ -1,5523 +0,0 @@ -/******************************************************************************************* -* -* raygui v4.0 - A simple and easy-to-use immediate-mode gui library -* -* DESCRIPTION: -* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also -* available as a standalone library, as long as input and drawing functions are provided. -* -* FEATURES: -* - Immediate-mode gui, minimal retained data -* - +25 controls provided (basic and advanced) -* - Styling system for colors, font and metrics -* - Icons supported, embedded as a 1-bit icons pack -* - Standalone mode option (custom input/graphics backend) -* - Multiple support tools provided for raygui development -* -* POSSIBLE IMPROVEMENTS: -* - Better standalone mode API for easy plug of custom backends -* - Externalize required inputs, allow user easier customization -* -* LIMITATIONS: -* - No editable multi-line word-wraped text box supported -* - No auto-layout mechanism, up to the user to define controls position and size -* - Standalone mode requires library modification and some user work to plug another backend -* -* NOTES: -* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for -* font atlas recs and glyphs, freeing that memory is (usually) up to the user, -* no unload function is explicitly provided... but note that GuiLoadStyleDefaulf() unloads -* by default any previously loaded font (texture, recs, glyphs). -* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions -* -* CONTROLS PROVIDED: -* # Container/separators Controls -* - WindowBox --> StatusBar, Panel -* - GroupBox --> Line -* - Line -* - Panel --> StatusBar -* - ScrollPanel --> StatusBar -* - TabBar --> Button -* -* # Basic Controls -* - Label -* - LabelButton --> Label -* - Button -* - Toggle -* - ToggleGroup --> Toggle -* - ToggleSlider -* - CheckBox -* - ComboBox -* - DropdownBox -* - TextBox -* - ValueBox --> TextBox -* - Spinner --> Button, ValueBox -* - Slider -* - SliderBar --> Slider -* - ProgressBar -* - StatusBar -* - DummyRec -* - Grid -* -* # Advance Controls -* - ListView -* - ColorPicker --> ColorPanel, ColorBarHue -* - MessageBox --> Window, Label, Button -* - TextInputBox --> Window, Label, TextBox, Button -* -* It also provides a set of functions for styling the controls based on its properties (size, color). -* -* -* RAYGUI STYLE (guiStyle): -* raygui uses a global data array for all gui style properties (allocated on data segment by default), -* when a new style is loaded, it is loaded over the global style... but a default gui style could always be -* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one -* -* The global style array size is fixed and depends on the number of controls and properties: -* -* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; -* -* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB -* -* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style -* used for all controls, when any of those base values is set, it is automatically populated to all -* controls, so, specific control values overwriting generic style should be set after base values. -* -* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those -* properties are actually common to all controls and can not be overwritten individually (like BASE ones) -* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR -* -* Custom control properties can be defined using the EXTENDED properties for each independent control. -* -* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler -* -* -* RAYGUI ICONS (guiIcons): -* raygui could use a global array containing icons data (allocated on data segment by default), -* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set -* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded -* -* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon -* requires 8 integers (16*16/32) to be stored in memory. -* -* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set. -* -* The global icons array size is fixed and depends on the number of icons and size: -* -* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS]; -* -* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB -* -* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons -* -* RAYGUI LAYOUT: -* raygui currently does not provide an auto-layout mechanism like other libraries, -* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it. -* -* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout -* -* CONFIGURATION: -* #define RAYGUI_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* #define RAYGUI_STANDALONE -* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined -* internally in the library and input management and drawing functions must be provided by -* the user (check library implementation for further details). -* -* #define RAYGUI_NO_ICONS -* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB) -* -* #define RAYGUI_CUSTOM_ICONS -* Includes custom ricons.h header defining a set of custom icons, -* this file can be generated using rGuiIcons tool -* -* #define RAYGUI_DEBUG_RECS_BOUNDS -* Draw control bounds rectangles for debug -* -* #define RAYGUI_DEBUG_TEXT_BOUNDS -* Draw text bounds rectangles for debug -* -* VERSIONS HISTORY: -* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() -* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() -* ADDED: Multiple new icons, mostly compiler related -* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE -* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode -* ADDED: Support loading styles with custom font charset from external file -* REDESIGNED: GuiTextBox(), support mouse cursor positioning -* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only) -* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color -* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText() -* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value -* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value -* REDESIGNED: GuiComboBox(), get parameters by reference and return result value -* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value -* REDESIGNED: GuiSlider(), get parameters by reference and return result value -* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value -* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value -* REDESIGNED: GuiListView(), get parameters by reference and return result value -* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value -* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value -* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value -* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value -* REDESIGNED: GuiGrid(), get parameters by reference and return result value -* REDESIGNED: GuiGrid(), added extra parameter -* REDESIGNED: GuiListViewEx(), change parameters order -* REDESIGNED: All controls return result as int value -* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars -* REVIEWED: All examples and specially controls_test_suite -* RENAMED: gui_file_dialog module to gui_window_file_dialog -* UPDATED: All styles to include ISO-8859-15 charset (as much as possible) -* -* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER -* ADDED: GuiLoadStyleFromMemory() (binary only) -* REVIEWED: GuiScrollBar() horizontal movement key -* REVIEWED: GuiTextBox() crash on cursor movement -* REVIEWED: GuiTextBox(), additional inputs support -* REVIEWED: GuiLabelButton(), avoid text cut -* REVIEWED: GuiTextInputBox(), password input -* REVIEWED: Local GetCodepointNext(), aligned with raylib -* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds -* -* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle() -* ADDED: Helper functions to split text in separate lines -* ADDED: Multiple new icons, useful for code editing tools -* REMOVED: Unneeded icon editing functions -* REMOVED: GuiTextBoxMulti(), very limited and broken -* REMOVED: MeasureTextEx() dependency, logic directly implemented -* REMOVED: DrawTextEx() dependency, logic directly implemented -* REVIEWED: GuiScrollBar(), improve mouse-click behaviour -* REVIEWED: Library header info, more info, better organized -* REDESIGNED: GuiTextBox() to support cursor movement -* REDESIGNED: GuiDrawText() to divide drawing by lines -* -* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes -* REMOVED: GuiScrollBar(), only internal -* REDESIGNED: GuiPanel() to support text parameter -* REDESIGNED: GuiScrollPanel() to support text parameter -* REDESIGNED: GuiColorPicker() to support text parameter -* REDESIGNED: GuiColorPanel() to support text parameter -* REDESIGNED: GuiColorBarAlpha() to support text parameter -* REDESIGNED: GuiColorBarHue() to support text parameter -* REDESIGNED: GuiTextInputBox() to support password -* -* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool) -* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures -* REVIEWED: External icons usage logic -* REVIEWED: GuiLine() for centered alignment when including text -* RENAMED: Multiple controls properties definitions to prepend RAYGUI_ -* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency -* Projects updated and multiple tweaks -* -* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file -* REDESIGNED: GuiTextBoxMulti() -* REMOVED: GuiImageButton*() -* Multiple minor tweaks and bugs corrected -* -* 2.9 (17-Mar-2021) REMOVED: Tooltip API -* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() -* 2.7 (20-Feb-2020) ADDED: Possible tooltips API -* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() -* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() -* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() -* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties -* ADDED: 8 new custom styles ready to use -* Multiple minor tweaks and bugs corrected -* -* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() -* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed -* Refactor all controls drawing mechanism to use control state -* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls -* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string -* REDESIGNED: Style system (breaking change) -* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts -* REVIEWED: GuiComboBox(), GuiListView()... -* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... -* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout -* 1.5 (21-Jun-2017) Working in an improved styles system -* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) -* 1.3 (12-Jun-2017) Complete redesign of style system -* 1.1 (01-Jun-2017) Complete review of the library -* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria. -* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria. -* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria. -* -* DEPENDENCIES: -* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing -* -* STANDALONE MODE: -* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled -* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs. -* -* The following functions should be redefined for a custom backend: -* -* - Vector2 GetMousePosition(void); -* - float GetMouseWheelMove(void); -* - bool IsMouseButtonDown(int button); -* - bool IsMouseButtonPressed(int button); -* - bool IsMouseButtonReleased(int button); -* - bool IsKeyDown(int key); -* - bool IsKeyPressed(int key); -* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() -* -* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() -* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() -* -* - Font GetFontDefault(void); // -- GuiLoadStyleDefault() -* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle() -* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image -* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) -* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data -* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data -* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs -* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list -* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list -* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() -* -* CONTRIBUTORS: -* Ramon Santamaria: Supervision, review, redesign, update and maintenance -* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) -* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) -* Adria Arranz: Testing and implementation of additional controls (2018) -* Jordi Jorba: Testing and implementation of additional controls (2018) -* Albert Martos: Review and testing of the library (2015) -* Ian Eito: Review and testing of the library (2015) -* Kevin Gato: Initial implementation of basic components (2014) -* Daniel Nicolas: Initial implementation of basic components (2014) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#ifndef RAYGUI_H -#define RAYGUI_H - -#define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 0 -#define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "4.0" - -#if !defined(RAYGUI_STANDALONE) - #include "raylib.h" -#endif - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) - #if defined(BUILD_LIBTYPE_SHARED) - #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) - #elif defined(USE_LIBTYPE_SHARED) - #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) - #endif -#endif - -// Function specifiers definition -#ifndef RAYGUIAPI - #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// Allow custom memory allocators -#ifndef RAYGUI_MALLOC - #define RAYGUI_MALLOC(sz) malloc(sz) -#endif -#ifndef RAYGUI_CALLOC - #define RAYGUI_CALLOC(n,sz) calloc(n,sz) -#endif -#ifndef RAYGUI_FREE - #define RAYGUI_FREE(p) free(p) -#endif - -// Simple log system to avoid printf() calls if required -// NOTE: Avoiding those calls, also avoids const strings memory usage -#define RAYGUI_SUPPORT_LOG_INFO -#if defined(RAYGUI_SUPPORT_LOG_INFO) - #define RAYGUI_LOG(...) printf(__VA_ARGS__) -#else - #define RAYGUI_LOG(...) -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Some types are required for RAYGUI_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(RAYGUI_STANDALONE) - #ifndef __cplusplus - // Boolean type - #ifndef true - typedef enum { false, true } bool; - #endif - #endif - - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; - - // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV() - typedef struct Vector3 { - float x; - float y; - float z; - } Vector3; - - // Color type, RGBA (32bit) - typedef struct Color { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; - } Color; - - // Rectangle type - typedef struct Rectangle { - float x; - float y; - float width; - float height; - } Rectangle; - - // TODO: Texture2D type is very coupled to raylib, required by Font type - // It should be redesigned to be provided by user - typedef struct Texture2D { - unsigned int id; // OpenGL texture id - int width; // Texture base width - int height; // Texture base height - int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (PixelFormat type) - } Texture2D; - - // Image, pixel data stored in CPU memory (RAM) - typedef struct Image { - void *data; // Image raw data - int width; // Image base width - int height; // Image base height - int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (PixelFormat type) - } Image; - - // GlyphInfo, font characters glyphs info - typedef struct GlyphInfo { - int value; // Character value (Unicode) - int offsetX; // Character offset X when drawing - int offsetY; // Character offset Y when drawing - int advanceX; // Character advance position X - Image image; // Character image data - } GlyphInfo; - - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() - // It should be redesigned to be provided by user - typedef struct Font { - int baseSize; // Base size (default chars height) - int glyphCount; // Number of glyph characters - int glyphPadding; // Padding around the glyph characters - Texture2D texture; // Texture atlas containing the glyphs - Rectangle *recs; // Rectangles in texture for the glyphs - GlyphInfo *glyphs; // Glyphs info data - } Font; -#endif - - -// Style property -// NOTE: Used when exporting style as code for convenience -typedef struct GuiStyleProp { - unsigned short controlId; // Control identifier - unsigned short propertyId; // Property identifier - int propertyValue; // Property value -} GuiStyleProp; - -/* -// Controls text style -NOT USED- -// NOTE: Text style is defined by control -typedef struct GuiTextStyle { - unsigned int size; - int charSpacing; - int lineSpacing; - int alignmentH; - int alignmentV; - int padding; -} GuiTextStyle; -*/ - -// Gui control state -typedef enum { - STATE_NORMAL = 0, - STATE_FOCUSED, - STATE_PRESSED, - STATE_DISABLED -} GuiState; - -// Gui control text alignment -typedef enum { - TEXT_ALIGN_LEFT = 0, - TEXT_ALIGN_CENTER, - TEXT_ALIGN_RIGHT -} GuiTextAlignment; - -// Gui control text alignment vertical -// NOTE: Text vertical position inside the text bounds -typedef enum { - TEXT_ALIGN_TOP = 0, - TEXT_ALIGN_MIDDLE, - TEXT_ALIGN_BOTTOM -} GuiTextAlignmentVertical; - -// Gui control text wrap mode -// NOTE: Useful for multiline text -typedef enum { - TEXT_WRAP_NONE = 0, - TEXT_WRAP_CHAR, - TEXT_WRAP_WORD -} GuiTextWrapMode; - -// Gui controls -typedef enum { - // Default -> populates to all controls when set - DEFAULT = 0, - - // Basic controls - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - SPINNER, // Uses: BUTTON, VALUEBOX - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR -} GuiControl; - -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) -typedef enum { - BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL - BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL - TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL - BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED - BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED - TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED - BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED - BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED - TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED - BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED - BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED - TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH, // Control border size, 0 for no border - //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls - //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING, // Control text padding, not considering border - TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding) - //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls -} GuiControlProperty; - -// TODO: Which text styling properties should be global or per-control? -// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while -// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and -// should be configured by user as needed while defining the UI layout - - -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) -//---------------------------------------------------------------------------------- -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT? -typedef enum { - TEXT_SIZE = 16, // Text size (glyphs max height) - TEXT_SPACING, // Text spacing between glyphs - LINE_COLOR, // Line control color - BACKGROUND_COLOR, // Background color - TEXT_LINE_SPACING, // Text spacing between lines - TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) - TEXT_WRAP_MODE // Text wrap-mode inside text bounds - //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thikness -} GuiDefaultProperty; - -// Other possible text properties: -// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... - -// Label -//typedef enum { } GuiLabelProperty; - -// Button/Spinner -//typedef enum { } GuiButtonProperty; - -// Toggle/ToggleGroup -typedef enum { - GROUP_PADDING = 16, // ToggleGroup separation between toggles -} GuiToggleProperty; - -// Slider/SliderBar -typedef enum { - SLIDER_WIDTH = 16, // Slider size of internal bar - SLIDER_PADDING // Slider/SliderBar internal bar padding -} GuiSliderProperty; - -// ProgressBar -typedef enum { - PROGRESS_PADDING = 16, // ProgressBar internal padding -} GuiProgressBarProperty; - -// ScrollBar -typedef enum { - ARROWS_SIZE = 16, // ScrollBar arrows size - ARROWS_VISIBLE, // ScrollBar arrows visible - SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding - SCROLL_SLIDER_SIZE, // ScrollBar slider size - SCROLL_PADDING, // ScrollBar scroll padding from arrows - SCROLL_SPEED, // ScrollBar scrolling speed -} GuiScrollBarProperty; - -// CheckBox -typedef enum { - CHECK_PADDING = 16 // CheckBox internal check padding -} GuiCheckBoxProperty; - -// ComboBox -typedef enum { - COMBO_BUTTON_WIDTH = 16, // ComboBox right button width - COMBO_BUTTON_SPACING // ComboBox button separation -} GuiComboBoxProperty; - -// DropdownBox -typedef enum { - ARROW_PADDING = 16, // DropdownBox arrow separation from border and items - DROPDOWN_ITEMS_SPACING // DropdownBox items separation -} GuiDropdownBoxProperty; - -// TextBox/TextBoxMulti/ValueBox/Spinner -typedef enum { - TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable -} GuiTextBoxProperty; - -// Spinner -typedef enum { - SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width - SPIN_BUTTON_SPACING, // Spinner buttons separation -} GuiSpinnerProperty; - -// ListView -typedef enum { - LIST_ITEMS_HEIGHT = 16, // ListView items height - LIST_ITEMS_SPACING, // ListView items separation - SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) - SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) -} GuiListViewProperty; - -// ColorPicker -typedef enum { - COLOR_SELECTOR_SIZE = 16, - HUEBAR_WIDTH, // ColorPicker right hue bar width - HUEBAR_PADDING, // ColorPicker right hue bar separation from panel - HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height - HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow -} GuiColorPickerProperty; - -#define SCROLLBAR_LEFT_SIDE 0 -#define SCROLLBAR_RIGHT_SIDE 1 - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -// Global gui state control functions -RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state) -RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state) -RAYGUIAPI void GuiLock(void); // Lock gui controls (global state) -RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state) -RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state) -RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f -RAYGUIAPI void GuiSetState(int state); // Set gui state (global state) -RAYGUIAPI int GuiGetState(void); // Get gui state (global state) - -// Font set/get functions -RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state) -RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state) - -// Style set/get functions -RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property -RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property - -// Styles loading functions -RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) -RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style - -// Tooltips management functions -RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state) -RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state) -RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string - -// Icons functionality -RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) -#if !defined(RAYGUI_NO_ICONS) -RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size -RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer -RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data -RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position -#endif - - -// Controls -//---------------------------------------------------------------------------------------------------------- -// Container/separator controls, useful for controls organization -RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed -RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name -RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text -RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 -RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control - -// Basic controls set -RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control, shows text -RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked -RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked -RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control, returns true when active -RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control, returns active toggle index -RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control, returns true when clicked -RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active -RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control, returns selected item index - -RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item -RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value -RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers -RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text - -RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control, returns selected value -RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control, returns selected value -RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control, shows current progress value -RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text -RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders -RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control, returns mouse cell position - -// Advance controls set -RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control, returns selected list item index -RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret -RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) -RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control -RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control -RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control -RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that returns HSV color value, used by GuiColorPickerHSV() -//---------------------------------------------------------------------------------------------------------- - - -#if !defined(RAYGUI_NO_ICONS) - -#if !defined(RAYGUI_CUSTOM_ICONS) -//---------------------------------------------------------------------------------- -// Icons enumeration -//---------------------------------------------------------------------------------- -typedef enum { - ICON_NONE = 0, - ICON_FOLDER_FILE_OPEN = 1, - ICON_FILE_SAVE_CLASSIC = 2, - ICON_FOLDER_OPEN = 3, - ICON_FOLDER_SAVE = 4, - ICON_FILE_OPEN = 5, - ICON_FILE_SAVE = 6, - ICON_FILE_EXPORT = 7, - ICON_FILE_ADD = 8, - ICON_FILE_DELETE = 9, - ICON_FILETYPE_TEXT = 10, - ICON_FILETYPE_AUDIO = 11, - ICON_FILETYPE_IMAGE = 12, - ICON_FILETYPE_PLAY = 13, - ICON_FILETYPE_VIDEO = 14, - ICON_FILETYPE_INFO = 15, - ICON_FILE_COPY = 16, - ICON_FILE_CUT = 17, - ICON_FILE_PASTE = 18, - ICON_CURSOR_HAND = 19, - ICON_CURSOR_POINTER = 20, - ICON_CURSOR_CLASSIC = 21, - ICON_PENCIL = 22, - ICON_PENCIL_BIG = 23, - ICON_BRUSH_CLASSIC = 24, - ICON_BRUSH_PAINTER = 25, - ICON_WATER_DROP = 26, - ICON_COLOR_PICKER = 27, - ICON_RUBBER = 28, - ICON_COLOR_BUCKET = 29, - ICON_TEXT_T = 30, - ICON_TEXT_A = 31, - ICON_SCALE = 32, - ICON_RESIZE = 33, - ICON_FILTER_POINT = 34, - ICON_FILTER_BILINEAR = 35, - ICON_CROP = 36, - ICON_CROP_ALPHA = 37, - ICON_SQUARE_TOGGLE = 38, - ICON_SYMMETRY = 39, - ICON_SYMMETRY_HORIZONTAL = 40, - ICON_SYMMETRY_VERTICAL = 41, - ICON_LENS = 42, - ICON_LENS_BIG = 43, - ICON_EYE_ON = 44, - ICON_EYE_OFF = 45, - ICON_FILTER_TOP = 46, - ICON_FILTER = 47, - ICON_TARGET_POINT = 48, - ICON_TARGET_SMALL = 49, - ICON_TARGET_BIG = 50, - ICON_TARGET_MOVE = 51, - ICON_CURSOR_MOVE = 52, - ICON_CURSOR_SCALE = 53, - ICON_CURSOR_SCALE_RIGHT = 54, - ICON_CURSOR_SCALE_LEFT = 55, - ICON_UNDO = 56, - ICON_REDO = 57, - ICON_REREDO = 58, - ICON_MUTATE = 59, - ICON_ROTATE = 60, - ICON_REPEAT = 61, - ICON_SHUFFLE = 62, - ICON_EMPTYBOX = 63, - ICON_TARGET = 64, - ICON_TARGET_SMALL_FILL = 65, - ICON_TARGET_BIG_FILL = 66, - ICON_TARGET_MOVE_FILL = 67, - ICON_CURSOR_MOVE_FILL = 68, - ICON_CURSOR_SCALE_FILL = 69, - ICON_CURSOR_SCALE_RIGHT_FILL = 70, - ICON_CURSOR_SCALE_LEFT_FILL = 71, - ICON_UNDO_FILL = 72, - ICON_REDO_FILL = 73, - ICON_REREDO_FILL = 74, - ICON_MUTATE_FILL = 75, - ICON_ROTATE_FILL = 76, - ICON_REPEAT_FILL = 77, - ICON_SHUFFLE_FILL = 78, - ICON_EMPTYBOX_SMALL = 79, - ICON_BOX = 80, - ICON_BOX_TOP = 81, - ICON_BOX_TOP_RIGHT = 82, - ICON_BOX_RIGHT = 83, - ICON_BOX_BOTTOM_RIGHT = 84, - ICON_BOX_BOTTOM = 85, - ICON_BOX_BOTTOM_LEFT = 86, - ICON_BOX_LEFT = 87, - ICON_BOX_TOP_LEFT = 88, - ICON_BOX_CENTER = 89, - ICON_BOX_CIRCLE_MASK = 90, - ICON_POT = 91, - ICON_ALPHA_MULTIPLY = 92, - ICON_ALPHA_CLEAR = 93, - ICON_DITHERING = 94, - ICON_MIPMAPS = 95, - ICON_BOX_GRID = 96, - ICON_GRID = 97, - ICON_BOX_CORNERS_SMALL = 98, - ICON_BOX_CORNERS_BIG = 99, - ICON_FOUR_BOXES = 100, - ICON_GRID_FILL = 101, - ICON_BOX_MULTISIZE = 102, - ICON_ZOOM_SMALL = 103, - ICON_ZOOM_MEDIUM = 104, - ICON_ZOOM_BIG = 105, - ICON_ZOOM_ALL = 106, - ICON_ZOOM_CENTER = 107, - ICON_BOX_DOTS_SMALL = 108, - ICON_BOX_DOTS_BIG = 109, - ICON_BOX_CONCENTRIC = 110, - ICON_BOX_GRID_BIG = 111, - ICON_OK_TICK = 112, - ICON_CROSS = 113, - ICON_ARROW_LEFT = 114, - ICON_ARROW_RIGHT = 115, - ICON_ARROW_DOWN = 116, - ICON_ARROW_UP = 117, - ICON_ARROW_LEFT_FILL = 118, - ICON_ARROW_RIGHT_FILL = 119, - ICON_ARROW_DOWN_FILL = 120, - ICON_ARROW_UP_FILL = 121, - ICON_AUDIO = 122, - ICON_FX = 123, - ICON_WAVE = 124, - ICON_WAVE_SINUS = 125, - ICON_WAVE_SQUARE = 126, - ICON_WAVE_TRIANGULAR = 127, - ICON_CROSS_SMALL = 128, - ICON_PLAYER_PREVIOUS = 129, - ICON_PLAYER_PLAY_BACK = 130, - ICON_PLAYER_PLAY = 131, - ICON_PLAYER_PAUSE = 132, - ICON_PLAYER_STOP = 133, - ICON_PLAYER_NEXT = 134, - ICON_PLAYER_RECORD = 135, - ICON_MAGNET = 136, - ICON_LOCK_CLOSE = 137, - ICON_LOCK_OPEN = 138, - ICON_CLOCK = 139, - ICON_TOOLS = 140, - ICON_GEAR = 141, - ICON_GEAR_BIG = 142, - ICON_BIN = 143, - ICON_HAND_POINTER = 144, - ICON_LASER = 145, - ICON_COIN = 146, - ICON_EXPLOSION = 147, - ICON_1UP = 148, - ICON_PLAYER = 149, - ICON_PLAYER_JUMP = 150, - ICON_KEY = 151, - ICON_DEMON = 152, - ICON_TEXT_POPUP = 153, - ICON_GEAR_EX = 154, - ICON_CRACK = 155, - ICON_CRACK_POINTS = 156, - ICON_STAR = 157, - ICON_DOOR = 158, - ICON_EXIT = 159, - ICON_MODE_2D = 160, - ICON_MODE_3D = 161, - ICON_CUBE = 162, - ICON_CUBE_FACE_TOP = 163, - ICON_CUBE_FACE_LEFT = 164, - ICON_CUBE_FACE_FRONT = 165, - ICON_CUBE_FACE_BOTTOM = 166, - ICON_CUBE_FACE_RIGHT = 167, - ICON_CUBE_FACE_BACK = 168, - ICON_CAMERA = 169, - ICON_SPECIAL = 170, - ICON_LINK_NET = 171, - ICON_LINK_BOXES = 172, - ICON_LINK_MULTI = 173, - ICON_LINK = 174, - ICON_LINK_BROKE = 175, - ICON_TEXT_NOTES = 176, - ICON_NOTEBOOK = 177, - ICON_SUITCASE = 178, - ICON_SUITCASE_ZIP = 179, - ICON_MAILBOX = 180, - ICON_MONITOR = 181, - ICON_PRINTER = 182, - ICON_PHOTO_CAMERA = 183, - ICON_PHOTO_CAMERA_FLASH = 184, - ICON_HOUSE = 185, - ICON_HEART = 186, - ICON_CORNER = 187, - ICON_VERTICAL_BARS = 188, - ICON_VERTICAL_BARS_FILL = 189, - ICON_LIFE_BARS = 190, - ICON_INFO = 191, - ICON_CROSSLINE = 192, - ICON_HELP = 193, - ICON_FILETYPE_ALPHA = 194, - ICON_FILETYPE_HOME = 195, - ICON_LAYERS_VISIBLE = 196, - ICON_LAYERS = 197, - ICON_WINDOW = 198, - ICON_HIDPI = 199, - ICON_FILETYPE_BINARY = 200, - ICON_HEX = 201, - ICON_SHIELD = 202, - ICON_FILE_NEW = 203, - ICON_FOLDER_ADD = 204, - ICON_ALARM = 205, - ICON_CPU = 206, - ICON_ROM = 207, - ICON_STEP_OVER = 208, - ICON_STEP_INTO = 209, - ICON_STEP_OUT = 210, - ICON_RESTART = 211, - ICON_BREAKPOINT_ON = 212, - ICON_BREAKPOINT_OFF = 213, - ICON_BURGER_MENU = 214, - ICON_CASE_SENSITIVE = 215, - ICON_REG_EXP = 216, - ICON_FOLDER = 217, - ICON_FILE = 218, - ICON_SAND_TIMER = 219, - ICON_220 = 220, - ICON_221 = 221, - ICON_222 = 222, - ICON_223 = 223, - ICON_224 = 224, - ICON_225 = 225, - ICON_226 = 226, - ICON_227 = 227, - ICON_228 = 228, - ICON_229 = 229, - ICON_230 = 230, - ICON_231 = 231, - ICON_232 = 232, - ICON_233 = 233, - ICON_234 = 234, - ICON_235 = 235, - ICON_236 = 236, - ICON_237 = 237, - ICON_238 = 238, - ICON_239 = 239, - ICON_240 = 240, - ICON_241 = 241, - ICON_242 = 242, - ICON_243 = 243, - ICON_244 = 244, - ICON_245 = 245, - ICON_246 = 246, - ICON_247 = 247, - ICON_248 = 248, - ICON_249 = 249, - ICON_250 = 250, - ICON_251 = 251, - ICON_252 = 252, - ICON_253 = 253, - ICON_254 = 254, - ICON_255 = 255, -} GuiIconName; -#endif - -#endif - -#if defined(__cplusplus) -} // Prevents name mangling of functions -#endif - -#endif // RAYGUI_H - -/*********************************************************************************** -* -* RAYGUI IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RAYGUI_IMPLEMENTATION) - -#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] -#include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] -#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() -#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] -#include // Required for: roundf() [GuiColorPicker()] - -#ifdef __cplusplus - #define RAYGUI_CLITERAL(name) name -#else - #define RAYGUI_CLITERAL(name) (name) -#endif - -// Check if two rectangles are equal, used to validate a slider bounds as an id -#ifndef CHECK_BOUNDS_ID - #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height)) -#endif - -#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) - -// Embedded icons, no external file provided -#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) -#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons -#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id - -// Icons data is defined by bit array (every bit represents one pixel) -// Those arrays are stored as unsigned int data arrays, so, -// every array element defines 32 pixels (bits) of information -// One icon is defined by 8 int, (8 int * 32 bit = 256 bit = 16*16 pixels) -// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels) -#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32) - -//---------------------------------------------------------------------------------- -// Icons data for all gui possible icons (allocated on data segment by default) -// -// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so, -// every 16x16 icon requires 8 integers (16*16/32) to be stored -// -// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), -// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS -// -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB -//---------------------------------------------------------------------------------- -static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE - 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN - 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC - 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN - 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE - 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN - 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE - 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT - 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO - 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE - 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY - 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO - 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO - 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY - 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT - 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE - 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND - 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER - 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC - 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL - 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG - 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC - 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER - 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP - 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER - 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER - 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET - 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T - 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A - 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE - 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE - 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT - 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR - 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP - 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA - 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE - 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY - 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL - 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL - 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS - 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG - 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON - 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF - 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP - 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER - 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT - 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL - 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG - 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE - 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE - 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE - 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT - 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT - 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO - 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO - 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO - 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE - 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE - 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT - 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE - 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX - 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET - 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL - 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL - 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL - 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL - 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL - 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL - 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL - 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL - 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL - 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL - 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL - 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL - 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL - 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL - 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX - 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP - 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT - 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT - 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT - 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT - 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER - 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK - 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT - 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY - 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR - 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING - 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS - 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID - 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID - 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL - 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG - 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES - 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL - 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE - 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL - 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM - 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG - 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL - 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER - 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL - 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG - 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC - 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG - 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK - 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS - 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT - 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT - 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN - 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP - 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL - 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL - 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL - 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL - 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO - 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX - 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE - 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS - 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE - 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR - 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL - 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS - 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK - 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY - 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE - 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP - 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT - 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD - 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET - 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE - 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN - 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK - 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS - 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR - 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG - 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN - 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER - 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER - 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN - 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION - 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP - 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER - 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP - 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY - 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON - 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP - 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX - 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK - 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS - 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR - 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR - 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT - 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D - 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D - 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE - 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP - 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT - 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT - 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM - 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT - 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK - 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA - 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL - 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET - 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES - 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI - 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK - 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE - 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES - 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK - 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE - 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP - 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX - 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR - 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER - 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA - 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH - 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE - 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER - 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS - 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL - 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS - 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO - 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE - 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP - 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA - 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME - 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE - 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS - 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW - 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI - 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY - 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX - 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD - 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW - 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD - 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM - 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU - 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM - 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER - 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO - 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT - 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART - 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON - 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF - 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU - 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE - 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP - 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE - 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_220 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_221 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_222 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_223 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_224 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_225 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_226 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_227 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_228 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_232 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_233 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 -}; - -// NOTE: We keep a pointer to the icons array, useful to point to other sets if required -static unsigned int *guiIconsPtr = guiIcons; - -#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS - -#ifndef RAYGUI_ICON_SIZE - #define RAYGUI_ICON_SIZE 0 -#endif - -// WARNING: Those values define the total size of the style data array, -// if changed, previous saved styles could become incompatible -#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls -#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties -#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// Gui control property style color element -typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state - -static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) -static bool guiLocked = false; // Gui lock state (no inputs processed) -static float guiAlpha = 1.0f; // Gui controls transparency - -static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) - -static bool guiTooltip = false; // Tooltip enabled/disabled -static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) - -static bool guiSliderDragging = false; // Gui slider drag state (no inputs processed except dragged slider) -static Rectangle guiSliderActive = { 0 }; // Gui slider active bounds rectangle, used as an unique identifier - -static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() -//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking -static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down -static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement - -//---------------------------------------------------------------------------------- -// Style data array for all gui style properties (allocated on data segment by default) -// -// NOTE 1: First set of BASE properties are generic to all controls but could be individually -// overwritten per control, first set of EXTENDED properties are generic to all controls and -// can not be overwritten individually but custom EXTENDED properties can be used by control -// -// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(), -// but default gui style could always be recovered with GuiLoadStyleDefault() -// -// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB -//---------------------------------------------------------------------------------- -static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 }; - -static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization - -//---------------------------------------------------------------------------------- -// Standalone Mode Functions Declaration -// -// NOTE: raygui depend on some raylib input and drawing functions -// To use raygui as standalone library, below functions must be defined by the user -//---------------------------------------------------------------------------------- -#if defined(RAYGUI_STANDALONE) - -#define KEY_RIGHT 262 -#define KEY_LEFT 263 -#define KEY_DOWN 264 -#define KEY_UP 265 -#define KEY_BACKSPACE 259 -#define KEY_ENTER 257 - -#define MOUSE_LEFT_BUTTON 0 - -// Input required functions -//------------------------------------------------------------------------------- -static Vector2 GetMousePosition(void); -static float GetMouseWheelMove(void); -static bool IsMouseButtonDown(int button); -static bool IsMouseButtonPressed(int button); -static bool IsMouseButtonReleased(int button); - -static bool IsKeyDown(int key); -static bool IsKeyPressed(int key); -static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() -//------------------------------------------------------------------------------- - -// Drawing required functions -//------------------------------------------------------------------------------- -static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() -static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() -//------------------------------------------------------------------------------- - -// Text required functions -//------------------------------------------------------------------------------- -static Font GetFontDefault(void); // -- GuiLoadStyleDefault() -static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font - -static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image -static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) - -static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data -static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data - -static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs - -static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list -static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list - -static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() -//------------------------------------------------------------------------------- - -// raylib functions already implemented in raygui -//------------------------------------------------------------------------------- -static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value -static int ColorToInt(Color color); // Returns hexadecimal value for a Color -static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle -static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings -static int TextToInteger(const char *text); // Get integer value from text - -static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text -static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient -//------------------------------------------------------------------------------- - -#endif // RAYGUI_STANDALONE - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) - -static int GetTextWidth(const char *text); // Gui get text width using gui font and style -static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds -static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor - -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style - -static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings -static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB -static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV - -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() -static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position - -static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor - -//---------------------------------------------------------------------------------- -// Gui Setup Functions Definition -//---------------------------------------------------------------------------------- -// Enable gui global state -// NOTE: We check for STATE_DISABLED to avoid messing custom global state setups -void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; } - -// Disable gui global state -// NOTE: We check for STATE_NORMAL to avoid messing custom global state setups -void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; } - -// Lock gui global state -void GuiLock(void) { guiLocked = true; } - -// Unlock gui global state -void GuiUnlock(void) { guiLocked = false; } - -// Check if gui is locked (global state) -bool GuiIsLocked(void) { return guiLocked; } - -// Set gui controls alpha global state -void GuiSetAlpha(float alpha) -{ - if (alpha < 0.0f) alpha = 0.0f; - else if (alpha > 1.0f) alpha = 1.0f; - - guiAlpha = alpha; -} - -// Set gui state (global state) -void GuiSetState(int state) { guiState = (GuiState)state; } - -// Get gui state (global state) -int GuiGetState(void) { return guiState; } - -// Set custom gui font -// NOTE: Font loading/unloading is external to raygui -void GuiSetFont(Font font) -{ - if (font.texture.id > 0) - { - // NOTE: If we try to setup a font but default style has not been - // lazily loaded before, it will be overwritten, so we need to force - // default style loading first - if (!guiStyleLoaded) GuiLoadStyleDefault(); - - guiFont = font; - } -} - -// Get custom gui font -Font GuiGetFont(void) -{ - return guiFont; -} - -// Set control style property value -void GuiSetStyle(int control, int property, int value) -{ - if (!guiStyleLoaded) GuiLoadStyleDefault(); - guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; - - // Default properties are propagated to all controls - if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE)) - { - for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; - } -} - -// Get control style property value -int GuiGetStyle(int control, int property) -{ - if (!guiStyleLoaded) GuiLoadStyleDefault(); - return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property]; -} - -//---------------------------------------------------------------------------------- -// Gui Controls Functions Definition -//---------------------------------------------------------------------------------- - -// Window Box control -int GuiWindowBox(Rectangle bounds, const char *title) -{ - // Window title bar height (including borders) - // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() - #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT) - #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 - #endif - - int result = 0; - //GuiState state = guiState; - - int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; - - Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; - if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; - - Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 }; - Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20, - statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 }; - - // Update control - //-------------------------------------------------------------------- - // NOTE: Logic is directly managed by button - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiStatusBar(statusBar, title); // Draw window header as status bar - GuiPanel(windowPanel, NULL); // Draw window base - - // Draw window close button - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - result = GuiButton(closeButtonRec, "x"); -#else - result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL)); -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - //-------------------------------------------------------------------- - - return result; // Window close button clicked: result = 1 -} - -// Group Box control with text name -int GuiGroupBox(Rectangle bounds, const char *text) -{ - #if !defined(RAYGUI_GROUPBOX_LINE_THICK) - #define RAYGUI_GROUPBOX_LINE_THICK 1 - #endif - - int result = 0; - GuiState state = guiState; - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR))); - - GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); - //-------------------------------------------------------------------- - - return result; -} - -// Line control -int GuiLine(Rectangle bounds, const char *text) -{ - #if !defined(RAYGUI_LINE_ORIGIN_SIZE) - #define RAYGUI_LINE_MARGIN_TEXT 12 - #endif - #if !defined(RAYGUI_LINE_TEXT_PADDING) - #define RAYGUI_LINE_TEXT_PADDING 4 - #endif - - int result = 0; - GuiState state = guiState; - - Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)); - - // Draw control - //-------------------------------------------------------------------- - if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); - else - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(text) + 2; - textBounds.height = bounds.height; - textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT; - textBounds.y = bounds.y; - - // Draw line with embedded text label: "--- text --------------" - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); - GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); - } - //-------------------------------------------------------------------- - - return result; -} - -// Panel control -int GuiPanel(Rectangle bounds, const char *text) -{ - #if !defined(RAYGUI_PANEL_BORDER_WIDTH) - #define RAYGUI_PANEL_BORDER_WIDTH 1 - #endif - - int result = 0; - GuiState state = guiState; - - // Text will be drawn as a header bar (if provided) - Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; - if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; - - if (text != NULL) - { - // Move panel bounds after the header bar - bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; - bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; - } - - // Draw control - //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar - - GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), - GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR))); - //-------------------------------------------------------------------- - - return result; -} - -// Tab Bar control -// NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) -{ - #define RAYGUI_TABBAR_ITEM_WIDTH 160 - - int result = -1; - //GuiState state = guiState; - - Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; - - if (*active < 0) *active = 0; - else if (*active > count - 1) *active = count - 1; - - int offsetX = 0; // Required in case tabs go out of screen - offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); - if (offsetX < 0) offsetX = 0; - - bool toggle = false; // Required for individual toggles - - // Draw control - //-------------------------------------------------------------------- - for (int i = 0; i < count; i++) - { - tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; - - if (tabBounds.x < GetScreenWidth()) - { - // Draw tabs as toggle controls - int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); - int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(TOGGLE, TEXT_PADDING, 8); - - if (i == (*active)) - { - toggle = true; - GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); - } - else - { - toggle = false; - GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); - if (toggle) *active = i; - } - - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); - - // Draw tab close button - // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; -#else - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - } - } - - // Draw tab-bar bottom line - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); - //-------------------------------------------------------------------- - - return result; // Return as result the current TAB closing requested -} - -// Scroll Panel control -int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) -{ - #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 - #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 - - int result = 0; - GuiState state = guiState; - float mouseWheelSpeed = 20.0f; // Default movement speed with mouse wheel - - Rectangle temp = { 0 }; - if (view == NULL) view = &temp; - - Vector2 scrollPos = { 0.0f, 0.0f }; - if (scroll != NULL) scrollPos = *scroll; - - // Text will be drawn as a header bar (if provided) - Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; - if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; - - if (text != NULL) - { - // Move panel bounds after the header bar - bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; - bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1; - } - - bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; - bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; - - // Recheck to account for the other scrollbar being visible - if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; - if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; - - int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; - int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; - Rectangle horizontalScrollBar = { - (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)horizontalScrollBarWidth - }; - Rectangle verticalScrollBar = { - (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), - (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)verticalScrollBarWidth, - (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - }; - - // Make sure scroll bars have a minimum width/height - // NOTE: If content >>> bounds, size could be very small or even 0 - if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) - { - horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; - mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.height vs bounds.height - } - if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) - { - verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; - mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.width vs bounds.width - } - - // Calculate view area (area without the scrollbars) - *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? - RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : - RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; - - // Clip view area to the actual content size - if (view->width > content.width) view->width = content.width; - if (view->height > content.height) view->height = content.height; - - float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); - float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; - float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - -#if defined(SUPPORT_SCROLLBAR_KEY_INPUT) - if (hasHorizontalScrollBar) - { - if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - } - - if (hasVerticalScrollBar) - { - if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - } -#endif - float wheelMove = GetMouseWheelMove(); - - // Horizontal and vertical scrolling with mouse wheel - if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed; - else scrollPos.y += wheelMove*mouseWheelSpeed; // Vertical scroll - } - } - - // Normalize scroll values - if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; - if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; - if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; - if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar - - GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background - - // Save size of the scrollbar slider - const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - - // Draw horizontal scrollbar if visible - if (hasHorizontalScrollBar) - { - // Change scrollbar slider size to show the diff in size between the content width and the widget width - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth))); - scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax); - } - else scrollPos.x = 0.0f; - - // Draw vertical scrollbar if visible - if (hasVerticalScrollBar) - { - // Change scrollbar slider size to show the diff in size between the content height and the widget height - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth))); - scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax); - } - else scrollPos.y = 0.0f; - - // Draw detail corner rectangle if both scroll bars are visible - if (hasHorizontalScrollBar && hasVerticalScrollBar) - { - Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 }; - GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3)))); - } - - // Draw scrollbar lines depending on current state - GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); - - // Set scrollbar slider size back to the way it was before - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); - //-------------------------------------------------------------------- - - if (scroll != NULL) *scroll = scrollPos; - - return result; -} - -// Label control -int GuiLabel(Rectangle bounds, const char *text) -{ - int result = 0; - GuiState state = guiState; - - // Update control - //-------------------------------------------------------------------- - //... - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - return result; -} - -// Button control, returns true when clicked -int GuiButton(Rectangle bounds, const char *text) -{ - int result = 0; - GuiState state = guiState; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - // Check button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3)))); - GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3)))); - - if (state == STATE_FOCUSED) GuiTooltip(bounds); - //------------------------------------------------------------------ - - return result; // Button pressed: result = 1 -} - -// Label button control -int GuiLabelButton(Rectangle bounds, const char *text) -{ - GuiState state = guiState; - bool pressed = false; - - // NOTE: We force bounds.width to be all text - float textWidth = (float)GetTextWidth(text); - if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - // Check checkbox state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - return pressed; -} - -// Toggle Button control, returns true when active -int GuiToggle(Rectangle bounds, const char *text, bool *active) -{ - int result = 0; - GuiState state = guiState; - - bool temp = false; - if (active == NULL) active = &temp; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - // Check toggle button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - state = STATE_NORMAL; - *active = !(*active); - } - else state = STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == STATE_NORMAL) - { - GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3))))); - GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3))))); - } - else - { - GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3))); - GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3))); - } - - if (state == STATE_FOCUSED) GuiTooltip(bounds); - //-------------------------------------------------------------------- - - return result; -} - -// Toggle Group control, returns toggled button codepointIndex -int GuiToggleGroup(Rectangle bounds, const char *text, int *active) -{ - #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) - #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 - #endif - - int result = 0; - float initBoundsX = bounds.x; - - int temp = 0; - if (active == NULL) active = &temp; - - bool toggle = false; // Required for individual toggles - - // Get substrings items from text (items pointers) - int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; - int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, rows); - - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) - { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } - - if (i == (*active)) - { - toggle = true; - GuiToggle(bounds, items[i], &toggle); - } - else - { - toggle = false; - GuiToggle(bounds, items[i], &toggle); - if (toggle) *active = i; - } - - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); - } - - return result; -} - -// Toggle Slider control extended, returns true when clicked -int GuiToggleSlider(Rectangle bounds, const char *text, int *active) -{ - int result = 0; - GuiState state = guiState; - - int temp = 0; - if (active == NULL) active = &temp; - - //bool toggle = false; // Required for individual toggles - - // Get substrings items from text (items pointers) - int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, NULL); - - Rectangle slider = { - 0, // Calculated later depending on the active toggle - bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), - (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount, - bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - (*active)++; - result = 1; - } - else state = STATE_FOCUSED; - } - - if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED; - } - - if (*active >= itemCount) *active = 0; - slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))), - GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL))); - - // Draw internal slider - if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); - else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED))); - else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); - - // Draw text in slider - if (text != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(text); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = slider.x + slider.width/2 - textBounds.width/2; - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha)); - } - //-------------------------------------------------------------------- - - return result; -} - -// Check Box control, returns 1 when state changed -int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) -{ - int result = 0; - GuiState state = guiState; - - bool temp = false; - if (checked == NULL) checked = &temp; - - Rectangle textBounds = { 0 }; - - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text) + 2; - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - Rectangle totalBounds = { - (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, - bounds.y, - bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), - bounds.height, - }; - - // Check checkbox state - if (CheckCollisionPointRec(mousePoint, totalBounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - *checked = !(*checked); - result = 1; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK); - - if (*checked) - { - Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), - bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), - bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), - bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; - GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3))); - } - - GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - return result; -} - -// Combo Box control, returns selected item codepointIndex -int GuiComboBox(Rectangle bounds, const char *text, int *active) -{ - int result = 0; - GuiState state = guiState; - - int temp = 0; - if (active == NULL) active = &temp; - - bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); - - Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING), - (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; - - // Get substrings items from text (items pointers, lengths and count) - int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, NULL); - - if (*active < 0) *active = 0; - else if (*active > (itemCount - 1)) *active = itemCount - 1; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds) || - CheckCollisionPointRec(mousePoint, selector)) - { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - *active += 1; - if (*active >= itemCount) *active = 0; // Cyclic combobox - } - - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - // Draw combo box main - GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3)))); - GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3)))); - - // Draw selector using a custom button - // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - - GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount)); - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - //-------------------------------------------------------------------- - - return result; -} - -// Dropdown Box control -// NOTE: Returns mouse click -int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) -{ - int result = 0; - GuiState state = guiState; - - int itemSelected = *active; - int itemFocused = -1; - - // Get substrings items from text (items pointers, lengths and count) - int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, NULL); - - Rectangle boundsOpen = bounds; - boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); - - Rectangle itemBounds = bounds; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - if (editMode) - { - state = STATE_PRESSED; - - // Check if mouse has been pressed or released outside limits - if (!CheckCollisionPointRec(mousePoint, boundsOpen)) - { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1; - } - - // Check if already selected item has been pressed again - if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; - - // Check focused and selected item - for (int i = 0; i < itemCount; i++) - { - // Update item rectangle y position for next item - itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); - - if (CheckCollisionPointRec(mousePoint, itemBounds)) - { - itemFocused = i; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - itemSelected = i; - result = 1; // Item selected - } - break; - } - } - - itemBounds = bounds; - } - else - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - result = 1; - state = STATE_PRESSED; - } - else state = STATE_FOCUSED; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (editMode) GuiPanel(boundsOpen, NULL); - - GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3))); - GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3))); - - if (editMode) - { - // Draw visible items - for (int i = 0; i < itemCount; i++) - { - // Update item rectangle y position for next item - itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); - - if (i == itemSelected) - { - GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED))); - GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED))); - } - else if (i == itemFocused) - { - GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED))); - GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED))); - } - else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL))); - } - } - - // Draw arrows (using icon if available) -#if defined(RAYGUI_NO_ICONS) - GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText("#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL -#endif - //-------------------------------------------------------------------- - - *active = itemSelected; - - // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... - return result; // Mouse click: result = 1 -} - -// Text Box control -// NOTE: Returns true on ENTER pressed (useful for data validation) -int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) -{ - #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) - #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement - #endif - #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) - #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement - #endif - - int result = 0; - GuiState state = guiState; - - bool multiline = false; // TODO: Consider multiline text input - int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); - - Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); - int textWidth = GetTextWidth(text) - GetTextWidth(text + textBoxCursorIndex); - int textIndexOffset = 0; // Text index offset to start drawing in the box - - // Cursor rectangle - // NOTE: Position X value should be updated - Rectangle cursor = { - textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING), - textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), - 2, - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 - }; - - if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; - if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH); - - // Mouse cursor rectangle - // NOTE: Initialized outside of screen - Rectangle mouseCursor = cursor; - mouseCursor.x = -1; - mouseCursor.width = 1; - - // Auto-cursor movement logic - // NOTE: Cursor moves automatically when key down after some time - if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++; - else - { - autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter - autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter - } - - // Blink-cursor frame counter - //if (!autoCursorMode) blinkCursorFrameCounter++; - //else blinkCursorFrameCounter = 0; - - // Update control - //-------------------------------------------------------------------- - // WARNING: Text editing is only supported under certain conditions: - if ((state != STATE_DISABLED) && // Control not disabled - !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode - !guiLocked && // Gui not locked - !guiSliderDragging && // No gui slider on dragging - (wrapMode == TEXT_WRAP_NONE)) // No wrap mode - { - Vector2 mousePosition = GetMousePosition(); - - if (editMode) - { - state = STATE_PRESSED; - - // If text does not fit in the textbox and current cursor position is out of bounds, - // we add an index offset to text for drawing only what requires depending on cursor - while (textWidth >= textBounds.width) - { - int nextCodepointSize = 0; - GetCodepointNext(text + textIndexOffset, &nextCodepointSize); - - textIndexOffset += nextCodepointSize; - - textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex); - } - - int textLength = (int)strlen(text); // Get current text length - int codepoint = GetCharPressed(); // Get Unicode codepoint - if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n'; - - if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; - - // Encode codepoint as UTF-8 - int codepointSize = 0; - const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); - - // Add codepoint to text, at current cursor position - // NOTE: Make sure we do not overflow buffer size - if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < bufferSize)) - { - // Move forward data from cursor position - for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; - - // Add new codepoint in current cursor position - for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i]; - - textBoxCursorIndex += codepointSize; - textLength += codepointSize; - - // Make sure text last character is EOL - text[textLength] = '\0'; - } - - // Move cursor to start - if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0; - - // Move cursor to end - if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength; - - // Delete codepoint from text, after current cursor position - if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) - { - autoCursorDelayCounter++; - - if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames - { - int nextCodepointSize = 0; - GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); - - // Move backward text from cursor position - for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize]; - - textLength -= codepointSize; - - // Make sure text last character is EOL - text[textLength] = '\0'; - } - } - - // Delete codepoint from text, before current cursor position - if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) - { - autoCursorDelayCounter++; - - if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames - { - int prevCodepointSize = 0; - GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); - - // Move backward text from cursor position - for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize]; - - // Prevent cursor index from decrementing past 0 - if (textBoxCursorIndex > 0) - { - textBoxCursorIndex -= codepointSize; - textLength -= codepointSize; - } - - // Make sure text last character is EOL - text[textLength] = '\0'; - } - } - - // Move cursor position with keys - if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) - { - autoCursorDelayCounter++; - - if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames - { - int prevCodepointSize = 0; - GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); - - if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize; - } - } - else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) - { - autoCursorDelayCounter++; - - if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames - { - int nextCodepointSize = 0; - GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); - - if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize; - } - } - - // Move cursor position with mouse - if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text - { - float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; - int codepointIndex = 0; - float glyphWidth = 0.0f; - float widthToMouseX = 0; - int mouseCursorIndex = 0; - - for (int i = textIndexOffset; i < textLength; i++) - { - codepoint = GetCodepointNext(&text[i], &codepointSize); - codepointIndex = GetGlyphIndex(guiFont, codepoint); - - if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); - else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); - - if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2))) - { - mouseCursor.x = textBounds.x + widthToMouseX; - mouseCursorIndex = i; - break; - } - - widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - } - - // Check if mouse cursor is at the last position - int textEndWidth = GetTextWidth(text + textIndexOffset); - if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2)) - { - mouseCursor.x = textBounds.x + textEndWidth; - mouseCursorIndex = (int)strlen(text); - } - - // Place cursor at required index on mouse click - if ((mouseCursor.x >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - cursor.x = mouseCursor.x; - textBoxCursorIndex = mouseCursorIndex; - } - } - else mouseCursor.x = -1; - - // Recalculate cursor position.y depending on textBoxCursorIndex - cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING); - //if (multiline) cursor.y = GetTextLines() - - // Finish text editing on ENTER or mouse click outside bounds - if ((!multiline && IsKeyPressed(KEY_ENTER)) || - (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) - { - textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index - result = 1; - } - } - else - { - if (CheckCollisionPointRec(mousePosition, bounds)) - { - state = STATE_FOCUSED; - - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - textBoxCursorIndex = (int)strlen(text); // GLOBAL: Place cursor index to the end of current text - result = 1; - } - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == STATE_PRESSED) - { - GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); - } - else if (state == STATE_DISABLED) - { - GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED))); - } - else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK); - - // Draw text considering index offset if required - // NOTE: Text index offset depends on cursor position - GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3)))); - - // Draw cursor - if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY)) - { - //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0)) - GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); - - // Draw mouse position cursor (if required) - if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); - } - else if (state == STATE_FOCUSED) GuiTooltip(bounds); - //-------------------------------------------------------------------- - - return result; // Mouse button pressed: result = 1 -} - -/* -// Text Box control with multiple lines and word-wrap -// NOTE: This text-box is readonly, no editing supported by default -bool GuiTextBoxMulti(Rectangle bounds, char *text, int bufferSize, bool editMode) -{ - bool pressed = false; - - GuiSetStyle(TEXTBOX, TEXT_READONLY, 1); - GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported - GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); - - // TODO: Implement methods to calculate cursor position properly - pressed = GuiTextBox(bounds, text, bufferSize, editMode); - - GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); - GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); - GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); - - return pressed; -} -*/ - -// Spinner control, returns selected value -int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) -{ - int result = 1; - GuiState state = guiState; - - int tempValue = *value; - - Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y, - bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height }; - Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; - Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; - - Rectangle textBounds = { 0 }; - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text) + 2; - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - // Check spinner state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - } - } - -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(leftButtonBound, "<")) tempValue--; - if (GuiButton(rightButtonBound, ">")) tempValue++; -#else - if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--; - if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++; -#endif - - if (!editMode) - { - if (tempValue < minValue) tempValue = minValue; - if (tempValue > maxValue) tempValue = maxValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode); - - // Draw value selector custom buttons - // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH)); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - - // Draw text label if provided - GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - *value = tempValue; - return result; -} - -// Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter -int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) -{ - #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) - #define RAYGUI_VALUEBOX_MAX_CHARS 32 - #endif - - int result = 0; - GuiState state = guiState; - - char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - sprintf(textValue, "%i", *value); - - Rectangle textBounds = { 0 }; - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text) + 2; - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - bool valueHasChanged = false; - - if (editMode) - { - state = STATE_PRESSED; - - int keyCount = (int)strlen(textValue); - - // Only allow keys in range [48..57] - if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) - { - if (GetTextWidth(textValue) < bounds.width) - { - int key = GetCharPressed(); - if ((key >= 48) && (key <= 57)) - { - textValue[keyCount] = (char)key; - keyCount++; - valueHasChanged = true; - } - } - } - - // Delete text - if (keyCount > 0) - { - if (IsKeyPressed(KEY_BACKSPACE)) - { - keyCount--; - textValue[keyCount] = '\0'; - valueHasChanged = true; - } - } - - if (valueHasChanged) *value = TextToInteger(textValue); - - // NOTE: We are not clamp values until user input finishes - //if (*value > maxValue) *value = maxValue; - //else if (*value < minValue) *value = minValue; - - if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; - } - else - { - if (*value > maxValue) *value = maxValue; - else if (*value < minValue) *value = minValue; - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - Color baseColor = BLANK; - if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); - else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); - - GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); - GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); - - // Draw cursor - if (editMode) - { - // NOTE: ValueBox internal text is always centered - Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) }; - GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); - } - - // Draw text label if provided - GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - return result; -} - -// Slider control with pro parameters -// NOTE: Other GuiSlider*() controls use this one -int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth) -{ - int result = 0; - float oldValue = *value; - GuiState state = guiState; - - float temp = (maxValue - minValue)/2.0f; - if (value == NULL) value = &temp; - - int sliderValue = (int)(((*value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); - - Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), - 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; - - if (sliderWidth > 0) // Slider - { - slider.x += (sliderValue - sliderWidth/2); - slider.width = (float)sliderWidth; - } - else if (sliderWidth == 0) // SliderBar - { - slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); - slider.width = (float)sliderValue; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (guiSliderDragging) // Keep dragging outside of bounds - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) - { - state = STATE_PRESSED; - - // Get equivalent value and slider position from mousePosition.x - *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; - } - } - else - { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts - - if (!CheckCollisionPointRec(mousePoint, slider)) - { - // Get equivalent value and slider position from mousePosition.x - *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; - - if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider - else if (sliderWidth == 0) slider.width = (float)sliderValue; // SliderBar - } - } - else state = STATE_FOCUSED; - } - - if (*value > maxValue) *value = maxValue; - else if (*value < minValue) *value = minValue; - } - - // Control value change check - if(oldValue == *value) result = 0; - else result = 1; - - // Bar limits check - if (sliderWidth > 0) // Slider - { - if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); - else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); - } - else if (sliderWidth == 0) // SliderBar - { - if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); - - // Draw slider internal bar (depends on state) - if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); - else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED))); - else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED))); - - // Draw left/right text if provided - if (textLeft != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textLeft); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3)))); - } - - if (textRight != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textRight); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3)))); - } - //-------------------------------------------------------------------- - - return result; -} - -// Slider control extended, returns selected value and has text -int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) -{ - return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH)); -} - -// Slider Bar control extended, returns selected value -int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) -{ - return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0); -} - -// Progress Bar control extended, shows current progress value -int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) -{ - int result = 0; - GuiState state = guiState; - - float temp = (maxValue - minValue)/2.0f; - if (value == NULL) value = &temp; - - // Progress bar - Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), - bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, - bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) }; - - // Update control - //-------------------------------------------------------------------- - if (*value > maxValue) *value = maxValue; - - // WARNING: Working with floats could lead to rounding issues - if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue)? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f); - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == STATE_DISABLED) - { - GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK); - } - else - { - if (*value > minValue) - { - // Draw progress bar with colored border, more visual - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); - } - else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - - if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); - else - { - // Draw borders not yet reached by value - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - } - - // Draw slider internal progress bar (depends on state) - GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); - } - - // Draw left/right text if provided - if (textLeft != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textLeft); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3)))); - } - - if (textRight != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textRight); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3)))); - } - //-------------------------------------------------------------------- - - return result; -} - -// Status Bar control -int GuiStatusBar(Rectangle bounds, const char *text) -{ - int result = 0; - GuiState state = guiState; - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); - GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - return result; -} - -// Dummy rectangle control, intended for placeholding -int GuiDummyRec(Rectangle bounds, const char *text) -{ - int result = 0; - GuiState state = guiState; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - // Check button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else state = STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); - GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED))); - //------------------------------------------------------------------ - - return result; -} - -// List View control -int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) -{ - int result = 0; - int itemCount = 0; - const char **items = NULL; - - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); - - result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); - - return result; -} - -// List View control with extended parameters -int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus) -{ - int result = 0; - GuiState state = guiState; - - int itemFocused = (focus == NULL)? -1 : *focus; - int itemSelected = (active == NULL)? -1 : *active; - - // Check if we need a scroll bar - bool useScrollBar = false; - if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true; - - // Define base item rectangle [0] - Rectangle itemBounds = { 0 }; - itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING); - itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); - itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); - itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); - if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); - - // Get items on the list - int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); - if (visibleItems > count) visibleItems = count; - - int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; - if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; - int endIndex = startIndex + visibleItems; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - // Check mouse inside list view - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Check focused and selected item - for (int i = 0; i < visibleItems; i++) - { - if (CheckCollisionPointRec(mousePoint, itemBounds)) - { - itemFocused = startIndex + i; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - if (itemSelected == (startIndex + i)) itemSelected = -1; - else itemSelected = startIndex + i; - } - break; - } - - // Update item rectangle y position for next item - itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); - } - - if (useScrollBar) - { - int wheelMove = (int)GetMouseWheelMove(); - startIndex -= wheelMove; - - if (startIndex < 0) startIndex = 0; - else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; - - endIndex = startIndex + visibleItems; - if (endIndex > count) endIndex = count; - } - } - else itemFocused = -1; - - // Reset item rectangle y to [0] - itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background - - // Draw visible items - for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) - { - if (state == STATE_DISABLED) - { - if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); - - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); - } - else - { - if (((startIndex + i) == itemSelected) && (active != NULL)) - { - // Draw item selected - GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED))); - } - else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned! - { - // Draw item focused - GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED))); - } - else - { - // Draw item normal - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); - } - } - - // Update item rectangle y position for next item - itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); - } - - if (useScrollBar) - { - Rectangle scrollBarBounds = { - bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), - bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), - bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - }; - - // Calculate percentage of visible items and apply same percentage to scrollbar - float percentVisible = (float)(endIndex - startIndex)/count; - float sliderSize = bounds.height*percentVisible; - - int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size - int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size - GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed - - startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); - - GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default - } - //-------------------------------------------------------------------- - - if (active != NULL) *active = itemSelected; - if (focus != NULL) *focus = itemFocused; - if (scrollIndex != NULL) *scrollIndex = startIndex; - - return result; -} - -// Color Panel control -int GuiColorPanel(Rectangle bounds, const char *text, Color *color) -{ - int result = 0; - GuiState state = guiState; - Vector2 pickerSelector = { 0 }; - - const Color colWhite = { 255, 255, 255, 255 }; - const Color colBlack = { 0, 0, 0, 255 }; - - Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; - Vector3 hsv = ConvertRGBtoHSV(vcolor); - - pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation - pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value - - Vector3 maxHue = { hsv.x, 1.0f, 1.0f }; - Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - pickerSelector = mousePoint; - - // Calculate color from picker - Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y - - hsv.y = colorPick.x; - hsv.z = 1.0f - colorPick.y; - - Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - (unsigned char)(255.0f*(float)color->a/255.0f) }; - - } - else state = STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state != STATE_DISABLED) - { - DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); - DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); - - // Draw color picker: selector - Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; - GuiDrawRectangle(selector, 0, BLANK, colWhite); - } - else - { - DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); - } - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); - //-------------------------------------------------------------------- - - return result; -} - -// Color Bar Alpha control -// NOTE: Returns alpha value normalized [0..1] -int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) -{ - #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE) - #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 - #endif - - int result = 0; - GuiState state = guiState; - Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (guiSliderDragging) // Keep dragging outside of bounds - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) - { - state = STATE_PRESSED; - - *alpha = (mousePoint.x - bounds.x)/bounds.width; - if (*alpha <= 0.0f) *alpha = 0.0f; - if (*alpha >= 1.0f) *alpha = 1.0f; - } - } - else - { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts - - *alpha = (mousePoint.x - bounds.x)/bounds.width; - if (*alpha <= 0.0f) *alpha = 0.0f; - if (*alpha >= 1.0f) *alpha = 1.0f; - //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; - } - else state = STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - - // Draw alpha bar: checked background - if (state != STATE_DISABLED) - { - int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE; - int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE; - - for (int x = 0; x < checksX; x++) - { - for (int y = 0; y < checksY; y++) - { - Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE }; - GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f)); - } - } - - DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); - } - else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); - - // Draw alpha bar: selector - GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); - //-------------------------------------------------------------------- - - return result; -} - -// Color Bar Hue control -// Returns hue value normalized [0..1] -// NOTE: Other similar bars (for reference): -// Color GuiColorBarSat() [WHITE->color] -// Color GuiColorBarValue() [BLACK->color], HSV/HSL -// float GuiColorBarLuminance() [BLACK->WHITE] -int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) -{ - int result = 0; - GuiState state = guiState; - Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (guiSliderDragging) // Keep dragging outside of bounds - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) - { - state = STATE_PRESSED; - - *hue = (mousePoint.y - bounds.y)*360/bounds.height; - if (*hue <= 0.0f) *hue = 0.0f; - if (*hue >= 359.0f) *hue = 359.0f; - } - } - else - { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts - - *hue = (mousePoint.y - bounds.y)*360/bounds.height; - if (*hue <= 0.0f) *hue = 0.0f; - if (*hue >= 359.0f) *hue = 359.0f; - - } - else state = STATE_FOCUSED; - - /*if (IsKeyDown(KEY_UP)) - { - hue -= 2.0f; - if (hue <= 0.0f) hue = 0.0f; - } - else if (IsKeyDown(KEY_DOWN)) - { - hue += 2.0f; - if (hue >= 360.0f) hue = 360.0f; - }*/ - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state != STATE_DISABLED) - { - // Draw hue bar:color bars - // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); - } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); - - // Draw hue bar: selector - GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); - //-------------------------------------------------------------------- - - return result; -} - -// Color Picker control -// NOTE: It's divided in multiple controls: -// Color GuiColorPanel(Rectangle bounds, Color color) -// float GuiColorBarAlpha(Rectangle bounds, float alpha) -// float GuiColorBarHue(Rectangle bounds, float value) -// NOTE: bounds define GuiColorPanel() size -int GuiColorPicker(Rectangle bounds, const char *text, Color *color) -{ - int result = 0; - - Color temp = { 200, 0, 0, 255 }; - if (color == NULL) color = &temp; - - GuiColorPanel(bounds, NULL, color); - - Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; - - Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); - - GuiColorBarHue(boundsHue, NULL, &hsv.x); - - //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); - Vector3 rgb = ConvertHSVtoRGB(hsv); - - *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a }; - - return result; -} - -// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering. -// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB. -// NOTE: It's divided in multiple controls: -// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) -// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) -// float GuiColorBarHue(Rectangle bounds, float value) -// NOTE: bounds define GuiColorPanelHSV() size -int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) -{ - int result = 0; - - Vector3 tempHsv = { 0 }; - - if (colorHsv == NULL) - { - const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f }; - tempHsv = ConvertRGBtoHSV(tempColor); - colorHsv = &tempHsv; - } - - GuiColorPanelHSV(bounds, NULL, colorHsv); - - const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - - GuiColorBarHue(boundsHue, NULL, &colorHsv->x); - - return result; -} - -// Color Panel control, returns HSV color value in *colorHsv. -// Used by GuiColorPickerHSV() -int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) -{ - int result = 0; - GuiState state = guiState; - Vector2 pickerSelector = { 0 }; - - const Color colWhite = { 255, 255, 255, 255 }; - const Color colBlack = { 0, 0, 0, 255 }; - - pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation - pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value - - Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; - Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - pickerSelector = mousePoint; - - // Calculate color from picker - Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y - - colorHsv->y = colorPick.x; - colorHsv->z = 1.0f - colorPick.y; - } - else state = STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state != STATE_DISABLED) - { - DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); - DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); - - // Draw color picker: selector - Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; - GuiDrawRectangle(selector, 0, BLANK, colWhite); - } - else - { - DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); - } - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); - //-------------------------------------------------------------------- - - return result; -} - -// Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) -{ - #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) - #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 - #endif - #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING) - #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 - #endif - - int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button - - int buttonCount = 0; - const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); - Rectangle buttonBounds = { 0 }; - buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; - buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; - buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; - buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; - - int textWidth = GetTextWidth(message) + 2; - - Rectangle textBounds = { 0 }; - textBounds.x = bounds.x + bounds.width/2 - textWidth/2; - textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; - textBounds.width = (float)textWidth; - textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; - - // Draw control - //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; - - int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - GuiLabel(textBounds, message); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); - - prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - - for (int i = 0; i < buttonCount; i++) - { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; - buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); - } - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); - //-------------------------------------------------------------------- - - return result; -} - -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) -{ - #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) - #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 - #endif - #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING) - #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12 - #endif - #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT) - #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 - #endif - - // Used to enable text edit mode - // WARNING: No more than one GuiTextInputBox() should be open at the same time - static bool textEditMode = false; - - int result = -1; - - int buttonCount = 0; - const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); - Rectangle buttonBounds = { 0 }; - buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; - buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; - buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; - buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT; - - int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; - - Rectangle textBounds = { 0 }; - if (message != NULL) - { - int textSize = GetTextWidth(message) + 2; - - textBounds.x = bounds.x + bounds.width/2 - textSize/2; - textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - textBounds.width = (float)textSize; - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - } - - Rectangle textBoxBounds = { 0 }; - textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; - textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2; - if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; - else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); - textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2; - textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT; - - // Draw control - //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; - - // Draw message if available - if (message != NULL) - { - int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - GuiLabel(textBounds, message); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); - } - - if (secretViewActive != NULL) - { - static char stars[] = "****************"; - if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, - ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; - - GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); - } - else - { - if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; - } - - int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - - for (int i = 0; i < buttonCount; i++) - { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; - buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); - } - - if (result >= 0) textEditMode = false; - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); - //-------------------------------------------------------------------- - - return result; // Result is the pressed button index -} - -// Grid control -// NOTE: Returns grid mouse-hover selected cell -// About drawing lines at subpixel spacing, simple put, not easy solution: -// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster -int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell) -{ - // Grid lines alpha amount - #if !defined(RAYGUI_GRID_ALPHA) - #define RAYGUI_GRID_ALPHA 0.15f - #endif - - int result = 0; - GuiState state = guiState; - - Vector2 mousePoint = GetMousePosition(); - Vector2 currentMouseCell = { -1, -1 }; - - float spaceWidth = spacing/(float)subdivs; - int linesV = (int)(bounds.width/spaceWidth) + 1; - int linesH = (int)(bounds.height/spaceWidth) + 1; - - int color = GuiGetStyle(DEFAULT, LINE_COLOR); - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - // NOTE: Cell values must be the upper left of the cell the mouse is in - currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); - currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED); - - if (subdivs > 0) - { - // Draw vertical grid lines - for (int i = 0; i < linesV; i++) - { - Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height }; - GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); - } - - // Draw horizontal grid lines - for (int i = 0; i < linesH; i++) - { - Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width, 1 }; - GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); - } - } - - if (mouseCell != NULL) *mouseCell = currentMouseCell; - return result; -} - -//---------------------------------------------------------------------------------- -// Tooltip management functions -// NOTE: Tooltips requires some global variables: tooltipPtr -//---------------------------------------------------------------------------------- -// Enable gui tooltips (global state) -void GuiEnableTooltip(void) { guiTooltip = true; } - -// Disable gui tooltips (global state) -void GuiDisableTooltip(void) { guiTooltip = false; } - -// Set tooltip string -void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } - - -//---------------------------------------------------------------------------------- -// Styles loading functions -//---------------------------------------------------------------------------------- - -// Load raygui style file (.rgs) -// NOTE: By default a binary file is expected, that file could contain a custom font, -// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE) -void GuiLoadStyle(const char *fileName) -{ - #define MAX_LINE_BUFFER_SIZE 256 - - bool tryBinary = false; - - // Try reading the files as text file first - FILE *rgsFile = fopen(fileName, "rt"); - - if (rgsFile != NULL) - { - char buffer[MAX_LINE_BUFFER_SIZE] = { 0 }; - fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); - - if (buffer[0] == '#') - { - int controlId = 0; - int propertyId = 0; - unsigned int propertyValue = 0; - - while (!feof(rgsFile)) - { - switch (buffer[0]) - { - case 'p': - { - // Style property: p - - sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); - GuiSetStyle(controlId, propertyId, (int)propertyValue); - - } break; - case 'f': - { - // Style font: f - - int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); - - Font font = { 0 }; - int *codepoints = NULL; - int codepointCount = 0; - - if (charmapFileName[0] != '0') - { - // Load text data from file - // NOTE: Expected an UTF-8 array of codepoints, no separation - char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName)); - codepoints = LoadCodepoints(textData, &codepointCount); - UnloadFileText(textData); - } - - if (fontFileName[0] != '\0') - { - // In case a font is already loaded and it is not default internal font, unload it - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - - if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount); - else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints - } - - // If font texture not properly loaded, revert to default font and size/spacing - if (font.texture.id == 0) - { - font = GetFontDefault(); - GuiSetStyle(DEFAULT, TEXT_SIZE, 10); - GuiSetStyle(DEFAULT, TEXT_SPACING, 1); - } - - UnloadCodepoints(codepoints); - - if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font); - - } break; - default: break; - } - - fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); - } - } - else tryBinary = true; - - fclose(rgsFile); - } - - if (tryBinary) - { - rgsFile = fopen(fileName, "rb"); - - if (rgsFile != NULL) - { - fseek(rgsFile, 0, SEEK_END); - int fileDataSize = ftell(rgsFile); - fseek(rgsFile, 0, SEEK_SET); - - if (fileDataSize > 0) - { - unsigned char *fileData = (unsigned char *)RAYGUI_MALLOC(fileDataSize*sizeof(unsigned char)); - fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); - - GuiLoadStyleFromMemory(fileData, fileDataSize); - - RAYGUI_FREE(fileData); - } - - fclose(rgsFile); - } - } -} - -// Load style default over global style -void GuiLoadStyleDefault(void) -{ - // We set this variable first to avoid cyclic function calls - // when calling GuiSetStyle() and GuiGetStyle() - guiStyleLoaded = true; - - // Initialize default LIGHT style property values - // WARNING: Default value are applied to all controls on set but - // they can be overwritten later on for every custom control - GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); - GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); - GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); - GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); - GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); - GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); - GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); - GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); - GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); - GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); - GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); - GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); - GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); - GuiSetStyle(DEFAULT, TEXT_PADDING, 0); - GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - - // Initialize default extended property values - // NOTE: By default, extended property values are initialized to 0 - GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls - GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls - GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 15); // DEFAULT, 15 pixels between lines - GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds - - // Initialize control-specific property values - // NOTE: Those properties are in default list but require specific values by control type - GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 2); - GuiSetStyle(SLIDER, TEXT_PADDING, 4); - GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4); - GuiSetStyle(CHECKBOX, TEXT_PADDING, 4); - GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT); - GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0); - GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - GuiSetStyle(TEXTBOX, TEXT_PADDING, 4); - GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(VALUEBOX, TEXT_PADDING, 0); - GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(SPINNER, TEXT_PADDING, 0); - GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); - GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - - // Initialize extended property values - // NOTE: By default, extended property values are initialized to 0 - GuiSetStyle(TOGGLE, GROUP_PADDING, 2); - GuiSetStyle(SLIDER, SLIDER_WIDTH, 16); - GuiSetStyle(SLIDER, SLIDER_PADDING, 1); - GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); - GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); - GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32); - GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2); - GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); - GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2); - GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24); - GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2); - GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); - GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); - GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); - GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); - GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12); - GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28); - GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2); - GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12); - GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); - GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8); - GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16); - GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8); - GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8); - GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); - - if (guiFont.texture.id != GetFontDefault().texture.id) - { - // Unload previous font texture - UnloadTexture(guiFont.texture); - RL_FREE(guiFont.recs); - RL_FREE(guiFont.glyphs); - guiFont.recs = NULL; - guiFont.glyphs = NULL; - - // Setup default raylib font - guiFont = GetFontDefault(); - - // NOTE: Default raylib font character 95 is a white square - Rectangle whiteChar = guiFont.recs[95]; - - // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering - SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); - } -} - -// Get text with icon id prepended -// NOTE: Useful to add icons by name id (enum) instead of -// a number that can change between ricon versions -const char *GuiIconText(int iconId, const char *text) -{ -#if defined(RAYGUI_NO_ICONS) - return NULL; -#else - static char buffer[1024] = { 0 }; - static char iconBuffer[16] = { 0 }; - - if (text != NULL) - { - memset(buffer, 0, 1024); - sprintf(buffer, "#%03i#", iconId); - - for (int i = 5; i < 1024; i++) - { - buffer[i] = text[i - 5]; - if (text[i - 5] == '\0') break; - } - - return buffer; - } - else - { - sprintf(iconBuffer, "#%03i#", iconId); - - return iconBuffer; - } -#endif -} - -#if !defined(RAYGUI_NO_ICONS) -// Get full icons data pointer -unsigned int *GuiGetIcons(void) { return guiIconsPtr; } - -// Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], -// WARNING: guiIconsName[]][] memory should be manually freed! -char **GuiLoadIcons(const char *fileName, bool loadIconsName) -{ - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - - FILE *rgiFile = fopen(fileName, "rb"); - - char **guiIconsName = NULL; - - if (rgiFile != NULL) - { - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; - - fread(signature, 1, 4, rgiFile); - fread(&version, sizeof(short), 1, rgiFile); - fread(&reserved, sizeof(short), 1, rgiFile); - fread(&iconCount, sizeof(short), 1, rgiFile); - fread(&iconSize, sizeof(short), 1, rgiFile); - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) - { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH); - fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); - } - } - else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); - - // Read icons data directly over internal icons array - fread(guiIconsPtr, sizeof(unsigned int), iconCount*(iconSize*iconSize/32), rgiFile); - } - - fclose(rgiFile); - } - - return guiIconsName; -} - -// Draw selected icon using rectangles pixel-by-pixel -void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) -{ - #define BIT_CHECK(a,b) ((a) & (1u<<(b))) - - for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) - { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); - #endif - } - - if ((k == 15) || (k == 31)) y++; - } - } -} - -// Set icon drawing size -void GuiSetIconScale(int scale) -{ - if (scale >= 1) guiIconScale = scale; -} - -#endif // !RAYGUI_NO_ICONS - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -// Load style from memory -// WARNING: Binary files only -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - unsigned int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - memcpy(&controlId, fileDataPtr, sizeof(short)); - memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); - memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); - fileDataPtr += 8; - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image - -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - memcpy(&fontDataSize, fileDataPtr, sizeof(int)); - fileDataPtr += 4; - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - - memcpy(&font.baseSize, fileDataPtr, sizeof(int)); - memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); - memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - // Load font white rectangle - Rectangle fontWhiteRec = { 0 }; - memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); - fileDataPtr += 16; - - // Load font image parameters - int fontImageUncompSize = 0; - int fontImageCompSize = 0; - memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); - memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); - fileDataPtr += 8; - - Image imFont = { 0 }; - imFont.mipmaps = 1; - memcpy(&imFont.width, fileDataPtr, sizeof(int)); - memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); - memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) - { - // Compressed font atlas image data (DEFLATE), it requires DecompressData() - int dataUncompSize = 0; - unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize); - memcpy(compData, fileDataPtr, fontImageCompSize); - fileDataPtr += fontImageCompSize; - - imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); - - // Security check, dataUncompSize must match the provided fontImageUncompSize - if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); - - RAYGUI_FREE(compData); - } - else - { - // Font atlas image data is not compressed - imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageUncompSize); - memcpy(imFont.data, fileDataPtr, fontImageUncompSize); - fileDataPtr += fontImageUncompSize; - } - - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - - // Validate font atlas texture was loaded correctly - if (font.texture.id != 0) - { - // Load font recs data - int recsDataSize = font.glyphCount*sizeof(Rectangle); - int recsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed recs data - memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) - { - // Recs data is compressed, uncompress it - unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_MALLOC(recsDataCompressedSize); - - memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); - fileDataPtr += recsDataCompressedSize; - - int recsDataUncompSize = 0; - font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); - - RAYGUI_FREE(recsDataCompressed); - } - else - { - // Recs data is uncompressed - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); - fileDataPtr += sizeof(Rectangle); - } - } - - // Load font glyphs info data - int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph - int glyphsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed glyphs data - memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - // Allocate required glyphs space to fill with data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - - if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) - { - // Glyphs data is compressed, uncompress it - unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_MALLOC(glyphsDataCompressedSize); - - memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); - fileDataPtr += glyphsDataCompressedSize; - - int glyphsDataUncompSize = 0; - unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); - - unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; - - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); - glyphsDataUncompPtr += 16; - } - - RAYGUI_FREE(glypsDataCompressed); - RAYGUI_FREE(glyphsDataUncomp); - } - else - { - // Glyphs data is uncompressed - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); - fileDataPtr += 16; - } - } - } - else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call - if ((fontWhiteRec.x > 0) && - (fontWhiteRec.y > 0) && - (fontWhiteRec.width > 0) && - (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); - } -#endif - } -} - -// Gui get text width considering icon -static int GetTextWidth(const char *text) -{ - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif - - Vector2 textSize = { 0 }; - int textIconOffset = 0; - - if ((text != NULL) && (text[0] != '\0')) - { - if (text[0] == '#') - { - for (int i = 1; (i < 5) && (text[i] != '\0'); i++) - { - if (text[i] == '#') - { - textIconOffset = i; - break; - } - } - } - - text += textIconOffset; - - // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly - float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - - // Custom MeasureText() implementation - if ((guiFont.texture.id > 0) && (text != NULL)) - { - // Get size in bytes of text, considering end of line and line break - int size = 0; - for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) - { - if ((text[i] != '\0') && (text[i] != '\n')) size++; - else break; - } - - float scaleFactor = fontSize/(float)guiFont.baseSize; - textSize.y = (float)guiFont.baseSize*scaleFactor; - float glyphWidth = 0.0f; - - for (int i = 0, codepointSize = 0; i < size; i += codepointSize) - { - int codepoint = GetCodepointNext(&text[i], &codepointSize); - int codepointIndex = GetGlyphIndex(guiFont, codepoint); - - if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); - else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); - - textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - } - } - - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE - ICON_TEXT_PADDING); - } - - return (int)textSize.x; -} - -// Get text bounds considering control bounds -static Rectangle GetTextBounds(int control, Rectangle bounds) -{ - Rectangle textBounds = bounds; - - textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); - textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING); - textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); - textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line! - - // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds - switch (control) - { - case COMBOBOX: - case DROPDOWNBOX: - case LISTVIEW: - // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW - case SLIDER: - case CHECKBOX: - case VALUEBOX: - case SPINNER: - // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER - default: - { - // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() - if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); - else textBounds.x += GuiGetStyle(control, TEXT_PADDING); - } - break; - } - - return textBounds; -} - -// Get text icon if provided and move text cursor -// NOTE: We support up to 999 values for iconId -static const char *GetTextIcon(const char *text, int *iconId) -{ -#if !defined(RAYGUI_NO_ICONS) - *iconId = -1; - if (text[0] == '#') // Maybe we have an icon! - { - char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' - - int pos = 1; - while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) - { - iconValue[pos - 1] = text[pos]; - pos++; - } - - if (text[pos] == '#') - { - *iconId = TextToInteger(iconValue); - - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); - } - } -#endif - - return text; -} - -// Get text divided into lines (by line-breaks '\n') -const char **GetTextLines(const char *text, int *count) -{ - #define RAYGUI_MAX_TEXT_LINES 128 - - static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 }; - for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings - - int textSize = (int)strlen(text); - - lines[0] = text; - int len = 0; - *count = 1; - //int lineSize = 0; // Stores current line size, not returned - - for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++) - { - if (text[i] == '\n') - { - //lineSize = len; - k++; - lines[k] = &text[i + 1]; // WARNING: next value is valid? - len = 0; - *count += 1; - } - else len++; - } - - //lines[*count - 1].size = len; - - return lines; -} - -// Get text width to next space for provided string -static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex) -{ - float width = 0; - int codepointByteCount = 0; - int codepoint = 0; - int index = 0; - float glyphWidth = 0; - float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; - - for (int i = 0; text[i] != '\0'; i++) - { - if (text[i] != ' ') - { - codepoint = GetCodepoint(&text[i], &codepointByteCount); - index = GetGlyphIndex(guiFont, codepoint); - glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor; - width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - } - else - { - *nextSpaceIndex = i; - break; - } - } - - return width; -} - -// Gui draw text using default font -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint) -{ - #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif - - if ((text == NULL) || (text[0] == '\0')) return; // Security check - - // PROCEDURE: - // - Text is processed line per line - // - For every line, horizontal alignment is defined - // - For all text, vertical alignment is defined (multiline text only) - // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only) - - // Get text lines (using '\n' as delimiter) to be processed individually - // WARNING: We can't use GuiTextSplit() function because it can be already used - // before the GuiDrawText() call and its buffer is static, it would be overriden :( - int lineCount = 0; - const char **lines = GetTextLines(text, &lineCount); - - // Text style variables - //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT); - int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL); - int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing - - // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap - float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2); - float posOffsetY = 0.0f; - - for (int i = 0; i < lineCount; i++) - { - int iconId = 0; - lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor - - // Get text position depending on alignment and iconId - //--------------------------------------------------------------------------------- - Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; - - // NOTE: We get text size after icon has been processed - // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed? - int textSizeX = GetTextWidth(lines[i]); - - // If text requires an icon, add size to measure - if (iconId >= 0) - { - textSizeX += RAYGUI_ICON_SIZE*guiIconScale; - - // WARNING: If only icon provided, text could be pointing to EOF character: '\0' -#if !defined(RAYGUI_NO_ICONS) - if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; -#endif - } - - // Check guiTextAlign global variables - switch (alignment) - { - case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break; - case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break; - case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break; - default: break; - } - - switch (alignmentVertical) - { - // Only valid in case of wordWrap = 0; - case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break; - case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; - case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; - default: break; - } - - // NOTE: Make sure we get pixel-perfect coordinates, - // In case of decimals we got weird text positioning - textBoundsPosition.x = (float)((int)textBoundsPosition.x); - textBoundsPosition.y = (float)((int)textBoundsPosition.y); - //--------------------------------------------------------------------------------- - - // Draw text (with icon if available) - //--------------------------------------------------------------------------------- -#if !defined(RAYGUI_NO_ICONS) - if (iconId >= 0) - { - // NOTE: We consider icon height, probably different than text size - GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - } -#endif - // Get size in bytes of text, - // considering end of line and line break - int lineSize = 0; - for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } - float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; - - int textOffsetY = 0; - float textOffsetX = 0.0f; - float glyphWidth = 0; - for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) - { - int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); - int index = GetGlyphIndex(guiFont, codepoint); - - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all of the bad bytes using the '?' symbol moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size - - // Wrap mode text measuring to space to validate if it can be drawn or - // a new line is required - if (wrapMode == TEXT_WRAP_CHAR) - { - // Get glyph width to check if it goes out of bounds - if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); - else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; - - // Jump to next line if current character reach end of the box limits - if ((textOffsetX + glyphWidth) > textBounds.width) - { - textOffsetX = 0.0f; - textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); - } - } - else if (wrapMode == TEXT_WRAP_WORD) - { - // Get width to next space in line - int nextSpaceIndex = 0; - float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); - - if ((textOffsetX + nextSpaceWidth) > textBounds.width) - { - textOffsetX = 0.0f; - textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); - } - - // TODO: Consider case: (nextSpaceWidth >= textBounds.width) - } - - if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint - else - { - // TODO: There are multiple types of spaces in Unicode, - // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html - if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph - { - if (wrapMode == TEXT_WRAP_NONE) - { - // Draw only required text glyphs fitting the textBounds.width - if (textOffsetX <= (textBounds.width - glyphWidth)) - { - DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); - } - } - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) - { - // Draw only glyphs inside the bounds - if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) - { - DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); - } - } - } - - if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - } - } - - if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - //--------------------------------------------------------------------------------- - } - -#if defined(RAYGUI_DEBUG_TEXT_BOUNDS) - GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f)); -#endif -} - -// Gui draw rectangle using default raygui plain style with borders -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) -{ - if (color.a > 0) - { - // Draw rectangle filled with color - DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha)); - } - - if (borderWidth > 0) - { - // Draw rectangle border lines with color - DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); - DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); - DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); - DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); - } - -#if defined(RAYGUI_DEBUG_RECS_BOUNDS) - DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f)); -#endif -} - -// Draw tooltip using control bounds -static void GuiTooltip(Rectangle controlRec) -{ - if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiSliderDragging) - { - Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - - if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); - - GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, NULL); - - int textPadding = GuiGetStyle(LABEL, TEXT_PADDING); - int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); - GuiSetStyle(LABEL, TEXT_PADDING, 0); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, guiTooltipPtr); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment); - GuiSetStyle(LABEL, TEXT_PADDING, textPadding); - } -} - -// Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - // NOTE: Those definitions could be externally provided if required - - // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user - // textRow is an externally provided array of integers that stores row number for every splitted string - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; - - // Count how many substrings we have on text and point to every one - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) - { - result[counter] = buffer + i + 1; - - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - - *count = counter; - - return result; -} - -// Convert color data from RGB to HSV -// NOTE: Color data should be passed normalized -static Vector3 ConvertRGBtoHSV(Vector3 rgb) -{ - Vector3 hsv = { 0 }; - float min = 0.0f; - float max = 0.0f; - float delta = 0.0f; - - min = (rgb.x < rgb.y)? rgb.x : rgb.y; - min = (min < rgb.z)? min : rgb.z; - - max = (rgb.x > rgb.y)? rgb.x : rgb.y; - max = (max > rgb.z)? max : rgb.z; - - hsv.z = max; // Value - delta = max - min; - - if (delta < 0.00001f) - { - hsv.y = 0.0f; - hsv.x = 0.0f; // Undefined, maybe NAN? - return hsv; - } - - if (max > 0.0f) - { - // NOTE: If max is 0, this divide would cause a crash - hsv.y = (delta/max); // Saturation - } - else - { - // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined - hsv.y = 0.0f; - hsv.x = 0.0f; // Undefined, maybe NAN? - return hsv; - } - - // NOTE: Comparing float values could not work properly - if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta - else - { - if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow - else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan - } - - hsv.x *= 60.0f; // Convert to degrees - - if (hsv.x < 0.0f) hsv.x += 360.0f; - - return hsv; -} - -// Convert color data from HSV to RGB -// NOTE: Color data should be passed normalized -static Vector3 ConvertHSVtoRGB(Vector3 hsv) -{ - Vector3 rgb = { 0 }; - float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; - long i = 0; - - // NOTE: Comparing float values could not work properly - if (hsv.y <= 0.0f) - { - rgb.x = hsv.z; - rgb.y = hsv.z; - rgb.z = hsv.z; - return rgb; - } - - hh = hsv.x; - if (hh >= 360.0f) hh = 0.0f; - hh /= 60.0f; - - i = (long)hh; - ff = hh - i; - p = hsv.z*(1.0f - hsv.y); - q = hsv.z*(1.0f - (hsv.y*ff)); - t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); - - switch (i) - { - case 0: - { - rgb.x = hsv.z; - rgb.y = t; - rgb.z = p; - } break; - case 1: - { - rgb.x = q; - rgb.y = hsv.z; - rgb.z = p; - } break; - case 2: - { - rgb.x = p; - rgb.y = hsv.z; - rgb.z = t; - } break; - case 3: - { - rgb.x = p; - rgb.y = q; - rgb.z = hsv.z; - } break; - case 4: - { - rgb.x = t; - rgb.y = p; - rgb.z = hsv.z; - } break; - case 5: - default: - { - rgb.x = hsv.z; - rgb.y = p; - rgb.z = q; - } break; - } - - return rgb; -} - -// Scroll bar control (used by GuiScrollPanel()) -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? - (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : - (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - const int valueRange = maxValue - minValue; - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ - (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), - bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), - (float)sliderSize }; - } - else // horizontal - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), - bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - (float)sliderSize, - bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (guiSliderDragging) // Keep dragging outside of bounds - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && - !CheckCollisionPointRec(mousePoint, arrowUpLeft) && - !CheckCollisionPointRec(mousePoint, arrowDownRight)) - { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) - { - state = STATE_PRESSED; - - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - } - else - { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Handle mouse wheel - int wheel = (int)GetMouseWheelMove(); - if (wheel != 0) value += wheel; - - // Handle mouse button down - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts - - // Check arrows click - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (!CheckCollisionPointRec(mousePoint, slider)) - { - // If click on scrollbar position but not on slider, place slider directly on that position - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - - state = STATE_PRESSED; - } - - // Keyboard control on mouse hover scrollbar - /* - if (isVertical) - { - if (IsKeyDown(KEY_DOWN)) value += 5; - else if (IsKeyDown(KEY_UP)) value -= 5; - } - else - { - if (IsKeyDown(KEY_RIGHT)) value += 5; - else if (IsKeyDown(KEY_LEFT)) value -= 5; - } - */ - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_ICONS) - GuiDrawText(isVertical? "^" : "<", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); - GuiDrawText(isVertical? "v" : ">", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText(isVertical? "#121#" : "#118#", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - -// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -// WARNING: It multiplies current alpha by alpha scale factor -static Color GuiFade(Color color, float alpha) -{ - if (alpha < 0.0f) alpha = 0.0f; - else if (alpha > 1.0f) alpha = 1.0f; - - Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) }; - - return result; -} - -#if defined(RAYGUI_STANDALONE) -// Returns a Color struct from hexadecimal value -static Color GetColor(int hexValue) -{ - Color color; - - color.r = (unsigned char)(hexValue >> 24) & 0xFF; - color.g = (unsigned char)(hexValue >> 16) & 0xFF; - color.b = (unsigned char)(hexValue >> 8) & 0xFF; - color.a = (unsigned char)hexValue & 0xFF; - - return color; -} - -// Returns hexadecimal value for a Color -static int ColorToInt(Color color) -{ - return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); -} - -// Check if point is inside rectangle -static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) -{ - bool collision = false; - - if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && - (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; - - return collision; -} - -// Formatting of text with variables to 'embed' -static const char *TextFormat(const char *text, ...) -{ - #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE) - #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 - #endif - - static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; - - va_list args; - va_start(args, text); - vsprintf(buffer, text, args); - va_end(args); - - return buffer; -} - -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -// Split string into multiple strings -const char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings we have on text and point to every one - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - } - - *count = counter; - return result; -} - -// Get integer value from text -// NOTE: This function replaces atoi() [stdlib.h] -static int TextToInteger(const char *text) -{ - int value = 0; - int sign = 1; - - if ((text[0] == '+') || (text[0] == '-')) - { - if (text[0] == '-') sign = -1; - text++; - } - - for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0'); - - return value*sign; -} - -// Encode codepoint into UTF-8 text (char array size returned as parameter) -static const char *CodepointToUTF8(int codepoint, int *byteSize) -{ - static char utf8[6] = { 0 }; - int size = 0; - - if (codepoint <= 0x7f) - { - utf8[0] = (char)codepoint; - size = 1; - } - else if (codepoint <= 0x7ff) - { - utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); - utf8[1] = (char)((codepoint & 0x3f) | 0x80); - size = 2; - } - else if (codepoint <= 0xffff) - { - utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); - utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); - utf8[2] = (char)((codepoint & 0x3f) | 0x80); - size = 3; - } - else if (codepoint <= 0x10ffff) - { - utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); - utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); - utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); - utf8[3] = (char)((codepoint & 0x3f) | 0x80); - size = 4; - } - - *byteSize = size; - - return utf8; -} - -// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found -// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned -// Total number of bytes processed are returned as a parameter -// NOTE: the standard says U+FFFD should be returned in case of errors -// but that character is not supported by the default font in raylib -static int GetCodepointNext(const char *text, int *codepointSize) -{ - const char *ptr = text; - int codepoint = 0x3f; // Codepoint (defaults to '?') - *codepointSize = 1; - - // Get current codepoint and bytes processed - if (0xf0 == (0xf8 & ptr[0])) - { - // 4 byte UTF-8 codepoint - if(((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks - codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); - *codepointSize = 4; - } - else if (0xe0 == (0xf0 & ptr[0])) - { - // 3 byte UTF-8 codepoint */ - if(((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks - codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); - *codepointSize = 3; - } - else if (0xc0 == (0xe0 & ptr[0])) - { - // 2 byte UTF-8 codepoint - if((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks - codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); - *codepointSize = 2; - } - else if (0x00 == (0x80 & ptr[0])) - { - // 1 byte UTF-8 codepoint - codepoint = ptr[0]; - *codepointSize = 1; - } - - - return codepoint; -} -#endif // RAYGUI_STANDALONE - -#endif // RAYGUI_IMPLEMENTATION diff --git a/raygui/raylib.h b/raygui/raylib.h deleted file mode 100644 index 1c4c4a0..0000000 --- a/raygui/raylib.h +++ /dev/null @@ -1,1662 +0,0 @@ -/********************************************************************************************** -* -* raylib v5.0 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) -* -* FEATURES: -* - NO external dependencies, all required libraries included with raylib -* - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly, -* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5. -* - Written in plain C code (C99) in PascalCase/camelCase notation -* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3 or ES2 - choose at compile) -* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] -* - Multiple Fonts formats supported (TTF, XNA fonts, AngelCode fonts) -* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) -* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! -* - Flexible Materials system, supporting classic maps and PBR maps -* - Animated 3D models supported (skeletal bones animation) (IQM) -* - Shaders support, including Model shaders and Postprocessing shaders -* - Powerful math module for Vector, Matrix and Quaternion operations: [raymath] -* - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, XM, MOD) -* - VR stereo rendering with configurable HMD device parameters -* - Bindings to multiple programming languages available! -* -* NOTES: -* - One default Font is loaded on InitWindow()->LoadFontDefault() [core, text] -* - One default Texture2D is loaded on rlglInit(), 1x1 white pixel R8G8B8A8 [rlgl] (OpenGL 3.3 or ES2) -* - One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2) -* - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2) -* -* DEPENDENCIES (included): -* [rcore] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input (PLATFORM_DESKTOP) -* [rlgl] glad (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading (PLATFORM_DESKTOP) -* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management -* -* OPTIONAL DEPENDENCIES (included): -* [rcore] msf_gif (Miles Fogle) for GIF recording -* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm -* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm -* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) -* [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG) -* [rtextures] stb_image_resize (Sean Barret) for image resizing algorithms -* [rtext] stb_truetype (Sean Barret) for ttf fonts loading -* [rtext] stb_rect_pack (Sean Barret) for rectangles packing -* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation -* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL) -* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF) -* [rmodels] Model3D (bzt) for models loading (M3D, https://bztsrc.gitlab.io/model3d) -* [raudio] dr_wav (David Reid) for WAV audio file loading -* [raudio] dr_flac (David Reid) for FLAC audio file loading -* [raudio] dr_mp3 (David Reid) for MP3 audio file loading -* [raudio] stb_vorbis (Sean Barret) for OGG audio loading -* [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading -* [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading -* -* -* LICENSE: zlib/libpng -* -* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software: -* -* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#ifndef RAYLIB_H -#define RAYLIB_H - -#include // Required for: va_list - Only used by TraceLogCallback - -#define RAYLIB_VERSION_MAJOR 5 -#define RAYLIB_VERSION_MINOR 0 -#define RAYLIB_VERSION_PATCH 0 -#define RAYLIB_VERSION "5.0" - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) - #if defined(BUILD_LIBTYPE_SHARED) - #if defined(__TINYC__) - #define __declspec(x) __attribute__((x)) - #endif - #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) - #elif defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) - #endif -#endif - -#ifndef RLAPI - #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -//---------------------------------------------------------------------------------- -// Some basic Defines -//---------------------------------------------------------------------------------- -#ifndef PI - #define PI 3.14159265358979323846f -#endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif - -// Allow custom memory allocators -// NOTE: Require recompiling raylib sources -#ifndef RL_MALLOC - #define RL_MALLOC(sz) malloc(sz) -#endif -#ifndef RL_CALLOC - #define RL_CALLOC(n,sz) calloc(n,sz) -#endif -#ifndef RL_REALLOC - #define RL_REALLOC(ptr,sz) realloc(ptr,sz) -#endif -#ifndef RL_FREE - #define RL_FREE(ptr) free(ptr) -#endif - -// NOTE: MSVC C++ compiler does not support compound literals (C99 feature) -// Plain structures in C++ (without constructors) can be initialized with { } -// This is called aggregate initialization (C++11 feature) -#if defined(__cplusplus) - #define CLITERAL(type) type -#else - #define CLITERAL(type) (type) -#endif - -// Some compilers (mostly macos clang) default to C++98, -// where aggregate initialization can't be used -// So, give a more clear error stating how to fix this -#if !defined(_MSC_VER) && (defined(__cplusplus) && __cplusplus < 201103L) - #error "C++11 or later is required. Add -std=c++11" -#endif - -// NOTE: We set some defines with some data types declared by raylib -// Other modules (raymath, rlgl) also require some of those types, so, -// to be able to use those other modules as standalone (not depending on raylib) -// this defines are very useful for internal check and avoid type (re)definitions -#define RL_COLOR_TYPE -#define RL_RECTANGLE_TYPE -#define RL_VECTOR2_TYPE -#define RL_VECTOR3_TYPE -#define RL_VECTOR4_TYPE -#define RL_QUATERNION_TYPE -#define RL_MATRIX_TYPE - -// Some Basic Colors -// NOTE: Custom raylib color palette for amazing visuals on WHITE background -#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray -#define GRAY CLITERAL(Color){ 130, 130, 130, 255 } // Gray -#define DARKGRAY CLITERAL(Color){ 80, 80, 80, 255 } // Dark Gray -#define YELLOW CLITERAL(Color){ 253, 249, 0, 255 } // Yellow -#define GOLD CLITERAL(Color){ 255, 203, 0, 255 } // Gold -#define ORANGE CLITERAL(Color){ 255, 161, 0, 255 } // Orange -#define PINK CLITERAL(Color){ 255, 109, 194, 255 } // Pink -#define RED CLITERAL(Color){ 230, 41, 55, 255 } // Red -#define MAROON CLITERAL(Color){ 190, 33, 55, 255 } // Maroon -#define GREEN CLITERAL(Color){ 0, 228, 48, 255 } // Green -#define LIME CLITERAL(Color){ 0, 158, 47, 255 } // Lime -#define DARKGREEN CLITERAL(Color){ 0, 117, 44, 255 } // Dark Green -#define SKYBLUE CLITERAL(Color){ 102, 191, 255, 255 } // Sky Blue -#define BLUE CLITERAL(Color){ 0, 121, 241, 255 } // Blue -#define DARKBLUE CLITERAL(Color){ 0, 82, 172, 255 } // Dark Blue -#define PURPLE CLITERAL(Color){ 200, 122, 255, 255 } // Purple -#define VIOLET CLITERAL(Color){ 135, 60, 190, 255 } // Violet -#define DARKPURPLE CLITERAL(Color){ 112, 31, 126, 255 } // Dark Purple -#define BEIGE CLITERAL(Color){ 211, 176, 131, 255 } // Beige -#define BROWN CLITERAL(Color){ 127, 106, 79, 255 } // Brown -#define DARKBROWN CLITERAL(Color){ 76, 63, 47, 255 } // Dark Brown - -#define WHITE CLITERAL(Color){ 255, 255, 255, 255 } // White -#define BLACK CLITERAL(Color){ 0, 0, 0, 255 } // Black -#define BLANK CLITERAL(Color){ 0, 0, 0, 0 } // Blank (Transparent) -#define MAGENTA CLITERAL(Color){ 255, 0, 255, 255 } // Magenta -#define RAYWHITE CLITERAL(Color){ 245, 245, 245, 255 } // My own White (raylib logo) - -//---------------------------------------------------------------------------------- -// Structures Definition -//---------------------------------------------------------------------------------- -// Boolean type -#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) - #include -#elif !defined(__cplusplus) && !defined(bool) - typedef enum bool { false = 0, true = !false } bool; - #define RL_BOOL_TYPE -#endif - -// Vector2, 2 components -typedef struct Vector2 { - float x; // Vector x component - float y; // Vector y component -} Vector2; - -// Vector3, 3 components -typedef struct Vector3 { - float x; // Vector x component - float y; // Vector y component - float z; // Vector z component -} Vector3; - -// Vector4, 4 components -typedef struct Vector4 { - float x; // Vector x component - float y; // Vector y component - float z; // Vector z component - float w; // Vector w component -} Vector4; - -// Quaternion, 4 components (Vector4 alias) -typedef Vector4 Quaternion; - -// Matrix, 4x4 components, column major, OpenGL style, right-handed -typedef struct Matrix { - float m0, m4, m8, m12; // Matrix first row (4 components) - float m1, m5, m9, m13; // Matrix second row (4 components) - float m2, m6, m10, m14; // Matrix third row (4 components) - float m3, m7, m11, m15; // Matrix fourth row (4 components) -} Matrix; - -// Color, 4 components, R8G8B8A8 (32bit) -typedef struct Color { - unsigned char r; // Color red value - unsigned char g; // Color green value - unsigned char b; // Color blue value - unsigned char a; // Color alpha value -} Color; - -// Rectangle, 4 components -typedef struct Rectangle { - float x; // Rectangle top-left corner position x - float y; // Rectangle top-left corner position y - float width; // Rectangle width - float height; // Rectangle height -} Rectangle; - -// Image, pixel data stored in CPU memory (RAM) -typedef struct Image { - void *data; // Image raw data - int width; // Image base width - int height; // Image base height - int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (PixelFormat type) -} Image; - -// Texture, tex data stored in GPU memory (VRAM) -typedef struct Texture { - unsigned int id; // OpenGL texture id - int width; // Texture base width - int height; // Texture base height - int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (PixelFormat type) -} Texture; - -// Texture2D, same as Texture -typedef Texture Texture2D; - -// TextureCubemap, same as Texture -typedef Texture TextureCubemap; - -// RenderTexture, fbo for texture rendering -typedef struct RenderTexture { - unsigned int id; // OpenGL framebuffer object id - Texture texture; // Color buffer attachment texture - Texture depth; // Depth buffer attachment texture -} RenderTexture; - -// RenderTexture2D, same as RenderTexture -typedef RenderTexture RenderTexture2D; - -// NPatchInfo, n-patch layout info -typedef struct NPatchInfo { - Rectangle source; // Texture source rectangle - int left; // Left border offset - int top; // Top border offset - int right; // Right border offset - int bottom; // Bottom border offset - int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 -} NPatchInfo; - -// GlyphInfo, font characters glyphs info -typedef struct GlyphInfo { - int value; // Character value (Unicode) - int offsetX; // Character offset X when drawing - int offsetY; // Character offset Y when drawing - int advanceX; // Character advance position X - Image image; // Character image data -} GlyphInfo; - -// Font, font texture and GlyphInfo array data -typedef struct Font { - int baseSize; // Base size (default chars height) - int glyphCount; // Number of glyph characters - int glyphPadding; // Padding around the glyph characters - Texture2D texture; // Texture atlas containing the glyphs - Rectangle *recs; // Rectangles in texture for the glyphs - GlyphInfo *glyphs; // Glyphs info data -} Font; - -// Camera, defines position/orientation in 3d space -typedef struct Camera3D { - Vector3 position; // Camera position - Vector3 target; // Camera target it looks-at - Vector3 up; // Camera up vector (rotation over its axis) - float fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic - int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC -} Camera3D; - -typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D - -// Camera2D, defines position/orientation in 2d space -typedef struct Camera2D { - Vector2 offset; // Camera offset (displacement from target) - Vector2 target; // Camera target (rotation and zoom origin) - float rotation; // Camera rotation in degrees - float zoom; // Camera zoom (scaling), should be 1.0f by default -} Camera2D; - -// Mesh, vertex data and vao/vbo -typedef struct Mesh { - int vertexCount; // Number of vertices stored in arrays - int triangleCount; // Number of triangles stored (indexed or not) - - // Vertex attributes data - float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) - float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - float *texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) - float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) - float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) - unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - unsigned short *indices; // Vertex indices (in case vertex data comes indexed) - - // Animation vertex data - float *animVertices; // Animated vertex positions (after bones transformations) - float *animNormals; // Animated normals (after bones transformations) - unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) - float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) - - // OpenGL identifiers - unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data) -} Mesh; - -// Shader -typedef struct Shader { - unsigned int id; // Shader program id - int *locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) -} Shader; - -// MaterialMap -typedef struct MaterialMap { - Texture2D texture; // Material map texture - Color color; // Material map color - float value; // Material map value -} MaterialMap; - -// Material, includes shader and maps -typedef struct Material { - Shader shader; // Material shader - MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS) - float params[4]; // Material generic parameters (if required) -} Material; - -// Transform, vertex transformation data -typedef struct Transform { - Vector3 translation; // Translation - Quaternion rotation; // Rotation - Vector3 scale; // Scale -} Transform; - -// Bone, skeletal animation bone -typedef struct BoneInfo { - char name[32]; // Bone name - int parent; // Bone parent -} BoneInfo; - -// Model, meshes, materials and animation data -typedef struct Model { - Matrix transform; // Local transform matrix - - int meshCount; // Number of meshes - int materialCount; // Number of materials - Mesh *meshes; // Meshes array - Material *materials; // Materials array - int *meshMaterial; // Mesh material number - - // Animation data - int boneCount; // Number of bones - BoneInfo *bones; // Bones information (skeleton) - Transform *bindPose; // Bones base transformation (pose) -} Model; - -// ModelAnimation -typedef struct ModelAnimation { - int boneCount; // Number of bones - int frameCount; // Number of animation frames - BoneInfo *bones; // Bones information (skeleton) - Transform **framePoses; // Poses array by frame - char name[32]; // Animation name -} ModelAnimation; - -// Ray, ray for raycasting -typedef struct Ray { - Vector3 position; // Ray position (origin) - Vector3 direction; // Ray direction -} Ray; - -// RayCollision, ray hit information -typedef struct RayCollision { - bool hit; // Did the ray hit something? - float distance; // Distance to the nearest hit - Vector3 point; // Point of the nearest hit - Vector3 normal; // Surface normal of hit -} RayCollision; - -// BoundingBox -typedef struct BoundingBox { - Vector3 min; // Minimum vertex box-corner - Vector3 max; // Maximum vertex box-corner -} BoundingBox; - -// Wave, audio wave data -typedef struct Wave { - unsigned int frameCount; // Total number of frames (considering channels) - unsigned int sampleRate; // Frequency (samples per second) - unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) - unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) - void *data; // Buffer data pointer -} Wave; - -// Opaque structs declaration -// NOTE: Actual structs are defined internally in raudio module -typedef struct rAudioBuffer rAudioBuffer; -typedef struct rAudioProcessor rAudioProcessor; - -// AudioStream, custom audio stream -typedef struct AudioStream { - rAudioBuffer *buffer; // Pointer to internal data used by the audio system - rAudioProcessor *processor; // Pointer to internal data processor, useful for audio effects - - unsigned int sampleRate; // Frequency (samples per second) - unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) - unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) -} AudioStream; - -// Sound -typedef struct Sound { - AudioStream stream; // Audio stream - unsigned int frameCount; // Total number of frames (considering channels) -} Sound; - -// Music, audio stream, anything longer than ~10 seconds should be streamed -typedef struct Music { - AudioStream stream; // Audio stream - unsigned int frameCount; // Total number of frames (considering channels) - bool looping; // Music looping enable - - int ctxType; // Type of music context (audio filetype) - void *ctxData; // Audio context data, depends on type -} Music; - -// VrDeviceInfo, Head-Mounted-Display device parameters -typedef struct VrDeviceInfo { - int hResolution; // Horizontal resolution in pixels - int vResolution; // Vertical resolution in pixels - float hScreenSize; // Horizontal size in meters - float vScreenSize; // Vertical size in meters - float vScreenCenter; // Screen center in meters - float eyeToScreenDistance; // Distance between eye and display in meters - float lensSeparationDistance; // Lens separation distance in meters - float interpupillaryDistance; // IPD (distance between pupils) in meters - float lensDistortionValues[4]; // Lens distortion constant parameters - float chromaAbCorrection[4]; // Chromatic aberration correction parameters -} VrDeviceInfo; - -// VrStereoConfig, VR stereo rendering configuration for simulator -typedef struct VrStereoConfig { - Matrix projection[2]; // VR projection matrices (per eye) - Matrix viewOffset[2]; // VR view offset matrices (per eye) - float leftLensCenter[2]; // VR left lens center - float rightLensCenter[2]; // VR right lens center - float leftScreenCenter[2]; // VR left screen center - float rightScreenCenter[2]; // VR right screen center - float scale[2]; // VR distortion scale - float scaleIn[2]; // VR distortion scale in -} VrStereoConfig; - -// File path list -typedef struct FilePathList { - unsigned int capacity; // Filepaths max entries - unsigned int count; // Filepaths entries count - char **paths; // Filepaths entries -} FilePathList; - -// Automation event -typedef struct AutomationEvent { - unsigned int frame; // Event frame - unsigned int type; // Event type (AutomationEventType) - int params[4]; // Event parameters (if required) -} AutomationEvent; - -// Automation event list -typedef struct AutomationEventList { - unsigned int capacity; // Events max entries (MAX_AUTOMATION_EVENTS) - unsigned int count; // Events entries count - AutomationEvent *events; // Events entries -} AutomationEventList; - -//---------------------------------------------------------------------------------- -// Enumerators Definition -//---------------------------------------------------------------------------------- -// System/Window config flags -// NOTE: Every bit registers one state (use it with bit masks) -// By default all flags are set to 0 -typedef enum { - FLAG_VSYNC_HINT = 0x00000040, // Set to try enabling V-Sync on GPU - FLAG_FULLSCREEN_MODE = 0x00000002, // Set to run program in fullscreen - FLAG_WINDOW_RESIZABLE = 0x00000004, // Set to allow resizable window - FLAG_WINDOW_UNDECORATED = 0x00000008, // Set to disable window decoration (frame and buttons) - FLAG_WINDOW_HIDDEN = 0x00000080, // Set to hide window - FLAG_WINDOW_MINIMIZED = 0x00000200, // Set to minimize window (iconify) - FLAG_WINDOW_MAXIMIZED = 0x00000400, // Set to maximize window (expanded to monitor) - FLAG_WINDOW_UNFOCUSED = 0x00000800, // Set to window non focused - FLAG_WINDOW_TOPMOST = 0x00001000, // Set to window always on top - FLAG_WINDOW_ALWAYS_RUN = 0x00000100, // Set to allow windows running while minimized - FLAG_WINDOW_TRANSPARENT = 0x00000010, // Set to allow transparent framebuffer - FLAG_WINDOW_HIGHDPI = 0x00002000, // Set to support HighDPI - FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED - FLAG_BORDERLESS_WINDOWED_MODE = 0x00008000, // Set to run program in borderless windowed mode - FLAG_MSAA_4X_HINT = 0x00000020, // Set to try enabling MSAA 4X - FLAG_INTERLACED_HINT = 0x00010000 // Set to try enabling interlaced video format (for V3D) -} ConfigFlags; - -// Trace log level -// NOTE: Organized by priority level -typedef enum { - LOG_ALL = 0, // Display all logs - LOG_TRACE, // Trace logging, intended for internal use only - LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds - LOG_INFO, // Info logging, used for program execution info - LOG_WARNING, // Warning logging, used on recoverable failures - LOG_ERROR, // Error logging, used on unrecoverable failures - LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) - LOG_NONE // Disable logging -} TraceLogLevel; - -// Keyboard keys (US keyboard layout) -// NOTE: Use GetKeyPressed() to allow redefining -// required keys for alternative layouts -typedef enum { - KEY_NULL = 0, // Key: NULL, used for no key pressed - // Alphanumeric keys - KEY_APOSTROPHE = 39, // Key: ' - KEY_COMMA = 44, // Key: , - KEY_MINUS = 45, // Key: - - KEY_PERIOD = 46, // Key: . - KEY_SLASH = 47, // Key: / - KEY_ZERO = 48, // Key: 0 - KEY_ONE = 49, // Key: 1 - KEY_TWO = 50, // Key: 2 - KEY_THREE = 51, // Key: 3 - KEY_FOUR = 52, // Key: 4 - KEY_FIVE = 53, // Key: 5 - KEY_SIX = 54, // Key: 6 - KEY_SEVEN = 55, // Key: 7 - KEY_EIGHT = 56, // Key: 8 - KEY_NINE = 57, // Key: 9 - KEY_SEMICOLON = 59, // Key: ; - KEY_EQUAL = 61, // Key: = - KEY_A = 65, // Key: A | a - KEY_B = 66, // Key: B | b - KEY_C = 67, // Key: C | c - KEY_D = 68, // Key: D | d - KEY_E = 69, // Key: E | e - KEY_F = 70, // Key: F | f - KEY_G = 71, // Key: G | g - KEY_H = 72, // Key: H | h - KEY_I = 73, // Key: I | i - KEY_J = 74, // Key: J | j - KEY_K = 75, // Key: K | k - KEY_L = 76, // Key: L | l - KEY_M = 77, // Key: M | m - KEY_N = 78, // Key: N | n - KEY_O = 79, // Key: O | o - KEY_P = 80, // Key: P | p - KEY_Q = 81, // Key: Q | q - KEY_R = 82, // Key: R | r - KEY_S = 83, // Key: S | s - KEY_T = 84, // Key: T | t - KEY_U = 85, // Key: U | u - KEY_V = 86, // Key: V | v - KEY_W = 87, // Key: W | w - KEY_X = 88, // Key: X | x - KEY_Y = 89, // Key: Y | y - KEY_Z = 90, // Key: Z | z - KEY_LEFT_BRACKET = 91, // Key: [ - KEY_BACKSLASH = 92, // Key: '\' - KEY_RIGHT_BRACKET = 93, // Key: ] - KEY_GRAVE = 96, // Key: ` - // Function keys - KEY_SPACE = 32, // Key: Space - KEY_ESCAPE = 256, // Key: Esc - KEY_ENTER = 257, // Key: Enter - KEY_TAB = 258, // Key: Tab - KEY_BACKSPACE = 259, // Key: Backspace - KEY_INSERT = 260, // Key: Ins - KEY_DELETE = 261, // Key: Del - KEY_RIGHT = 262, // Key: Cursor right - KEY_LEFT = 263, // Key: Cursor left - KEY_DOWN = 264, // Key: Cursor down - KEY_UP = 265, // Key: Cursor up - KEY_PAGE_UP = 266, // Key: Page up - KEY_PAGE_DOWN = 267, // Key: Page down - KEY_HOME = 268, // Key: Home - KEY_END = 269, // Key: End - KEY_CAPS_LOCK = 280, // Key: Caps lock - KEY_SCROLL_LOCK = 281, // Key: Scroll down - KEY_NUM_LOCK = 282, // Key: Num lock - KEY_PRINT_SCREEN = 283, // Key: Print screen - KEY_PAUSE = 284, // Key: Pause - KEY_F1 = 290, // Key: F1 - KEY_F2 = 291, // Key: F2 - KEY_F3 = 292, // Key: F3 - KEY_F4 = 293, // Key: F4 - KEY_F5 = 294, // Key: F5 - KEY_F6 = 295, // Key: F6 - KEY_F7 = 296, // Key: F7 - KEY_F8 = 297, // Key: F8 - KEY_F9 = 298, // Key: F9 - KEY_F10 = 299, // Key: F10 - KEY_F11 = 300, // Key: F11 - KEY_F12 = 301, // Key: F12 - KEY_LEFT_SHIFT = 340, // Key: Shift left - KEY_LEFT_CONTROL = 341, // Key: Control left - KEY_LEFT_ALT = 342, // Key: Alt left - KEY_LEFT_SUPER = 343, // Key: Super left - KEY_RIGHT_SHIFT = 344, // Key: Shift right - KEY_RIGHT_CONTROL = 345, // Key: Control right - KEY_RIGHT_ALT = 346, // Key: Alt right - KEY_RIGHT_SUPER = 347, // Key: Super right - KEY_KB_MENU = 348, // Key: KB menu - // Keypad keys - KEY_KP_0 = 320, // Key: Keypad 0 - KEY_KP_1 = 321, // Key: Keypad 1 - KEY_KP_2 = 322, // Key: Keypad 2 - KEY_KP_3 = 323, // Key: Keypad 3 - KEY_KP_4 = 324, // Key: Keypad 4 - KEY_KP_5 = 325, // Key: Keypad 5 - KEY_KP_6 = 326, // Key: Keypad 6 - KEY_KP_7 = 327, // Key: Keypad 7 - KEY_KP_8 = 328, // Key: Keypad 8 - KEY_KP_9 = 329, // Key: Keypad 9 - KEY_KP_DECIMAL = 330, // Key: Keypad . - KEY_KP_DIVIDE = 331, // Key: Keypad / - KEY_KP_MULTIPLY = 332, // Key: Keypad * - KEY_KP_SUBTRACT = 333, // Key: Keypad - - KEY_KP_ADD = 334, // Key: Keypad + - KEY_KP_ENTER = 335, // Key: Keypad Enter - KEY_KP_EQUAL = 336, // Key: Keypad = - // Android key buttons - KEY_BACK = 4, // Key: Android back button - KEY_MENU = 82, // Key: Android menu button - KEY_VOLUME_UP = 24, // Key: Android volume up button - KEY_VOLUME_DOWN = 25 // Key: Android volume down button -} KeyboardKey; - -// Add backwards compatibility support for deprecated names -#define MOUSE_LEFT_BUTTON MOUSE_BUTTON_LEFT -#define MOUSE_RIGHT_BUTTON MOUSE_BUTTON_RIGHT -#define MOUSE_MIDDLE_BUTTON MOUSE_BUTTON_MIDDLE - -// Mouse buttons -typedef enum { - MOUSE_BUTTON_LEFT = 0, // Mouse button left - MOUSE_BUTTON_RIGHT = 1, // Mouse button right - MOUSE_BUTTON_MIDDLE = 2, // Mouse button middle (pressed wheel) - MOUSE_BUTTON_SIDE = 3, // Mouse button side (advanced mouse device) - MOUSE_BUTTON_EXTRA = 4, // Mouse button extra (advanced mouse device) - MOUSE_BUTTON_FORWARD = 5, // Mouse button forward (advanced mouse device) - MOUSE_BUTTON_BACK = 6, // Mouse button back (advanced mouse device) -} MouseButton; - -// Mouse cursor -typedef enum { - MOUSE_CURSOR_DEFAULT = 0, // Default pointer shape - MOUSE_CURSOR_ARROW = 1, // Arrow shape - MOUSE_CURSOR_IBEAM = 2, // Text writing cursor shape - MOUSE_CURSOR_CROSSHAIR = 3, // Cross shape - MOUSE_CURSOR_POINTING_HAND = 4, // Pointing hand cursor - MOUSE_CURSOR_RESIZE_EW = 5, // Horizontal resize/move arrow shape - MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape - MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape - MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape - MOUSE_CURSOR_RESIZE_ALL = 9, // The omnidirectional resize/move cursor shape - MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape -} MouseCursor; - -// Gamepad buttons -typedef enum { - GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, just for error checking - GAMEPAD_BUTTON_LEFT_FACE_UP, // Gamepad left DPAD up button - GAMEPAD_BUTTON_LEFT_FACE_RIGHT, // Gamepad left DPAD right button - GAMEPAD_BUTTON_LEFT_FACE_DOWN, // Gamepad left DPAD down button - GAMEPAD_BUTTON_LEFT_FACE_LEFT, // Gamepad left DPAD left button - GAMEPAD_BUTTON_RIGHT_FACE_UP, // Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) - GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, // Gamepad right button right (i.e. PS3: Square, Xbox: X) - GAMEPAD_BUTTON_RIGHT_FACE_DOWN, // Gamepad right button down (i.e. PS3: Cross, Xbox: A) - GAMEPAD_BUTTON_RIGHT_FACE_LEFT, // Gamepad right button left (i.e. PS3: Circle, Xbox: B) - GAMEPAD_BUTTON_LEFT_TRIGGER_1, // Gamepad top/back trigger left (first), it could be a trailing button - GAMEPAD_BUTTON_LEFT_TRIGGER_2, // Gamepad top/back trigger left (second), it could be a trailing button - GAMEPAD_BUTTON_RIGHT_TRIGGER_1, // Gamepad top/back trigger right (one), it could be a trailing button - GAMEPAD_BUTTON_RIGHT_TRIGGER_2, // Gamepad top/back trigger right (second), it could be a trailing button - GAMEPAD_BUTTON_MIDDLE_LEFT, // Gamepad center buttons, left one (i.e. PS3: Select) - GAMEPAD_BUTTON_MIDDLE, // Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) - GAMEPAD_BUTTON_MIDDLE_RIGHT, // Gamepad center buttons, right one (i.e. PS3: Start) - GAMEPAD_BUTTON_LEFT_THUMB, // Gamepad joystick pressed button left - GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right -} GamepadButton; - -// Gamepad axis -typedef enum { - GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis - GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis - GAMEPAD_AXIS_RIGHT_X = 2, // Gamepad right stick X axis - GAMEPAD_AXIS_RIGHT_Y = 3, // Gamepad right stick Y axis - GAMEPAD_AXIS_LEFT_TRIGGER = 4, // Gamepad back trigger left, pressure level: [1..-1] - GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // Gamepad back trigger right, pressure level: [1..-1] -} GamepadAxis; - -// Material map index -typedef enum { - MATERIAL_MAP_ALBEDO = 0, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) - MATERIAL_MAP_METALNESS, // Metalness material (same as: MATERIAL_MAP_SPECULAR) - MATERIAL_MAP_NORMAL, // Normal material - MATERIAL_MAP_ROUGHNESS, // Roughness material - MATERIAL_MAP_OCCLUSION, // Ambient occlusion material - MATERIAL_MAP_EMISSION, // Emission material - MATERIAL_MAP_HEIGHT, // Heightmap material - MATERIAL_MAP_CUBEMAP, // Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - MATERIAL_MAP_IRRADIANCE, // Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - MATERIAL_MAP_PREFILTER, // Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - MATERIAL_MAP_BRDF // Brdf material -} MaterialMapIndex; - -#define MATERIAL_MAP_DIFFUSE MATERIAL_MAP_ALBEDO -#define MATERIAL_MAP_SPECULAR MATERIAL_MAP_METALNESS - -// Shader location index -typedef enum { - SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position - SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 - SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 - SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal - SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent - SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color - SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection - SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) - SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection - SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) - SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal - SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view - SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color - SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color - SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color - SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE) - SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR) - SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal - SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness - SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion - SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission - SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height - SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap - SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance - SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter - SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf -} ShaderLocationIndex; - -#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO -#define SHADER_LOC_MAP_SPECULAR SHADER_LOC_MAP_METALNESS - -// Shader uniform data type -typedef enum { - SHADER_UNIFORM_FLOAT = 0, // Shader uniform type: float - SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) - SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) - SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) - SHADER_UNIFORM_INT, // Shader uniform type: int - SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) - SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) - SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) - SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d -} ShaderUniformDataType; - -// Shader attribute data types -typedef enum { - SHADER_ATTRIB_FLOAT = 0, // Shader attribute type: float - SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) - SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) - SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) -} ShaderAttributeDataType; - -// Pixel formats -// NOTE: Support depends on OpenGL version and platform -typedef enum { - PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp - PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp - PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp - PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) - PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) - PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) - PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp - PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp -} PixelFormat; - -// Texture parameters: filter mode -// NOTE 1: Filtering considers mipmaps if available in the texture -// NOTE 2: Filter is accordingly set for minification and magnification -typedef enum { - TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation - TEXTURE_FILTER_BILINEAR, // Linear filtering - TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) - TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x - TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x - TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x -} TextureFilter; - -// Texture parameters: wrap mode -typedef enum { - TEXTURE_WRAP_REPEAT = 0, // Repeats texture in tiled mode - TEXTURE_WRAP_CLAMP, // Clamps texture to edge pixel in tiled mode - TEXTURE_WRAP_MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode - TEXTURE_WRAP_MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode -} TextureWrap; - -// Cubemap layouts -typedef enum { - CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type - CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces - CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces - CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces - CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces - CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirrectangular map) -} CubemapLayout; - -// Font type, defines generation method -typedef enum { - FONT_DEFAULT = 0, // Default font generation, anti-aliased - FONT_BITMAP, // Bitmap font generation, no anti-aliasing - FONT_SDF // SDF font generation, requires external shader -} FontType; - -// Color blending modes (pre-defined) -typedef enum { - BLEND_ALPHA = 0, // Blend textures considering alpha (default) - BLEND_ADDITIVE, // Blend textures adding colors - BLEND_MULTIPLIED, // Blend textures multiplying colors - BLEND_ADD_COLORS, // Blend textures adding colors (alternative) - BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) - BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha - BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) - BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate()) -} BlendMode; - -// Gesture -// NOTE: Provided as bit-wise flags to enable only desired gestures -typedef enum { - GESTURE_NONE = 0, // No gesture - GESTURE_TAP = 1, // Tap gesture - GESTURE_DOUBLETAP = 2, // Double tap gesture - GESTURE_HOLD = 4, // Hold gesture - GESTURE_DRAG = 8, // Drag gesture - GESTURE_SWIPE_RIGHT = 16, // Swipe right gesture - GESTURE_SWIPE_LEFT = 32, // Swipe left gesture - GESTURE_SWIPE_UP = 64, // Swipe up gesture - GESTURE_SWIPE_DOWN = 128, // Swipe down gesture - GESTURE_PINCH_IN = 256, // Pinch in gesture - GESTURE_PINCH_OUT = 512 // Pinch out gesture -} Gesture; - -// Camera system modes -typedef enum { - CAMERA_CUSTOM = 0, // Custom camera - CAMERA_FREE, // Free camera - CAMERA_ORBITAL, // Orbital camera - CAMERA_FIRST_PERSON, // First person camera - CAMERA_THIRD_PERSON // Third person camera -} CameraMode; - -// Camera projection -typedef enum { - CAMERA_PERSPECTIVE = 0, // Perspective projection - CAMERA_ORTHOGRAPHIC // Orthographic projection -} CameraProjection; - -// N-patch layout -typedef enum { - NPATCH_NINE_PATCH = 0, // Npatch layout: 3x3 tiles - NPATCH_THREE_PATCH_VERTICAL, // Npatch layout: 1x3 tiles - NPATCH_THREE_PATCH_HORIZONTAL // Npatch layout: 3x1 tiles -} NPatchLayout; - -// Callbacks to hook some internal functions -// WARNING: These callbacks are intended for advance users -typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages -typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data -typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data -typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data -typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data - -//------------------------------------------------------------------------------------ -// Global Variables Definition -//------------------------------------------------------------------------------------ -// It's lonely here... - -//------------------------------------------------------------------------------------ -// Window and Graphics Device Functions (Module: core) -//------------------------------------------------------------------------------------ - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -// Window-related functions -RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context -RLAPI void CloseWindow(void); // Close window and unload OpenGL context -RLAPI bool WindowShouldClose(void); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) -RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully -RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen -RLAPI bool IsWindowHidden(void); // Check if window is currently hidden (only PLATFORM_DESKTOP) -RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized (only PLATFORM_DESKTOP) -RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized (only PLATFORM_DESKTOP) -RLAPI bool IsWindowFocused(void); // Check if window is currently focused (only PLATFORM_DESKTOP) -RLAPI bool IsWindowResized(void); // Check if window has been resized last frame -RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled -RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags (only PLATFORM_DESKTOP) -RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags -RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) -RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed (only PLATFORM_DESKTOP) -RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) -RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) -RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) -RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) -RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) -RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP and PLATFORM_WEB) -RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) -RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window -RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) -RLAPI void SetWindowMaxSize(int width, int height); // Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) -RLAPI void SetWindowSize(int width, int height); // Set window dimensions -RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) -RLAPI void SetWindowFocused(void); // Set window focused (only PLATFORM_DESKTOP) -RLAPI void *GetWindowHandle(void); // Get native window handle -RLAPI int GetScreenWidth(void); // Get current screen width -RLAPI int GetScreenHeight(void); // Get current screen height -RLAPI int GetRenderWidth(void); // Get current render width (it considers HiDPI) -RLAPI int GetRenderHeight(void); // Get current render height (it considers HiDPI) -RLAPI int GetMonitorCount(void); // Get number of connected monitors -RLAPI int GetCurrentMonitor(void); // Get current connected monitor -RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position -RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (current video mode used by monitor) -RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (current video mode used by monitor) -RLAPI int GetMonitorPhysicalWidth(int monitor); // Get specified monitor physical width in millimetres -RLAPI int GetMonitorPhysicalHeight(int monitor); // Get specified monitor physical height in millimetres -RLAPI int GetMonitorRefreshRate(int monitor); // Get specified monitor refresh rate -RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor -RLAPI Vector2 GetWindowScaleDPI(void); // Get window scale DPI factor -RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the specified monitor -RLAPI void SetClipboardText(const char *text); // Set clipboard text content -RLAPI const char *GetClipboardText(void); // Get clipboard text content -RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling -RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling - -// Cursor-related functions -RLAPI void ShowCursor(void); // Shows cursor -RLAPI void HideCursor(void); // Hides cursor -RLAPI bool IsCursorHidden(void); // Check if cursor is not visible -RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) -RLAPI void DisableCursor(void); // Disables cursor (lock cursor) -RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the screen - -// Drawing-related functions -RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color) -RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing -RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering) -RLAPI void BeginMode2D(Camera2D camera); // Begin 2D mode with custom camera (2D) -RLAPI void EndMode2D(void); // Ends 2D mode with custom camera -RLAPI void BeginMode3D(Camera3D camera); // Begin 3D mode with custom camera (3D) -RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode -RLAPI void BeginTextureMode(RenderTexture2D target); // Begin drawing to render texture -RLAPI void EndTextureMode(void); // Ends drawing to render texture -RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing -RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) -RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied, subtract, custom) -RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) -RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) -RLAPI void EndScissorMode(void); // End scissor mode -RLAPI void BeginVrStereoMode(VrStereoConfig config); // Begin stereo rendering (requires VR simulator) -RLAPI void EndVrStereoMode(void); // End stereo rendering (requires VR simulator) - -// VR stereo config functions for VR simulator -RLAPI VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device); // Load VR stereo config for VR simulator device parameters -RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR stereo config - -// Shader management functions -// NOTE: Shader functionality is not available on OpenGL 1.1 -RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations -RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations -RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready -RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location -RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value -RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector -RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) -RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value for texture (sampler2d) -RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) - -// Screen-space-related functions -RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Get a ray trace from mouse position -RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix) -RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix -RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get the screen space position for a 3d world space position -RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get the world space position for a 2d camera screen space position -RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position -RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the screen space position for a 2d camera world space position - -// Timing-related functions -RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) -RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time) -RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow() -RLAPI int GetFPS(void); // Get current FPS - -// Custom frame control functions -// NOTE: Those functions are intended for advance users that want full control over the frame processing -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() -// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL -RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) -RLAPI void PollInputEvents(void); // Register all input events -RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution) - -// Random values generation functions -RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator -RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) -RLAPI int *LoadRandomSequence(unsigned int count, int min, int max); // Load random values sequence, no values repeated -RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence - -// Misc. functions -RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format) -RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS) -RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) - -// NOTE: Following functions implemented in module [utils] -//------------------------------------------------------------------ -RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) -RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level -RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator -RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator -RLAPI void MemFree(void *ptr); // Internal memory free - -// Set custom callbacks -// WARNING: Callbacks setup is intended for advance users -RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log -RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader -RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver -RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader -RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver - -// Files management functions -RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) -RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() -RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success -RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success -RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string -RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() -RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success -//------------------------------------------------------------------ - -// File system functions -RLAPI bool FileExists(const char *fileName); // Check if file exists -RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists -RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (including point: .png, .wav) -RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) -RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') -RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string -RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) -RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) -RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) -RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) -RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) -RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success -RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory -RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths -RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan -RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths -RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window -RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths -RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths -RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) - -// Compression/Encoding functionality -RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() -RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() -RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree() -RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree() - -// Automation events functionality -RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS -RLAPI void UnloadAutomationEventList(AutomationEventList *list); // Unload automation events list from file -RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName); // Export automation events list as text file -RLAPI void SetAutomationEventList(AutomationEventList *list); // Set automation event list to record to -RLAPI void SetAutomationEventBaseFrame(int frame); // Set automation event internal base frame to start recording -RLAPI void StartAutomationEventRecording(void); // Start recording automation events (AutomationEventList must be set) -RLAPI void StopAutomationEventRecording(void); // Stop recording automation events -RLAPI void PlayAutomationEvent(AutomationEvent event); // Play a recorded automation event - -//------------------------------------------------------------------------------------ -// Input Handling Functions (Module: core) -//------------------------------------------------------------------------------------ - -// Input-related functions: keyboard -RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once -RLAPI bool IsKeyPressedRepeat(int key); // Check if a key has been pressed again (Only PLATFORM_DESKTOP) -RLAPI bool IsKeyDown(int key); // Check if a key is being pressed -RLAPI bool IsKeyReleased(int key); // Check if a key has been released once -RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed -RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty -RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty -RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) - -// Input-related functions: gamepads -RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available -RLAPI const char *GetGamepadName(int gamepad); // Get gamepad internal name id -RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if a gamepad button has been pressed once -RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a gamepad button is being pressed -RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once -RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed -RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed -RLAPI int GetGamepadAxisCount(int gamepad); // Get gamepad axis count for a gamepad -RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis -RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB) - -// Input-related functions: mouse -RLAPI bool IsMouseButtonPressed(int button); // Check if a mouse button has been pressed once -RLAPI bool IsMouseButtonDown(int button); // Check if a mouse button is being pressed -RLAPI bool IsMouseButtonReleased(int button); // Check if a mouse button has been released once -RLAPI bool IsMouseButtonUp(int button); // Check if a mouse button is NOT being pressed -RLAPI int GetMouseX(void); // Get mouse position X -RLAPI int GetMouseY(void); // Get mouse position Y -RLAPI Vector2 GetMousePosition(void); // Get mouse position XY -RLAPI Vector2 GetMouseDelta(void); // Get mouse delta between frames -RLAPI void SetMousePosition(int x, int y); // Set mouse position XY -RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset -RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling -RLAPI float GetMouseWheelMove(void); // Get mouse wheel movement for X or Y, whichever is larger -RLAPI Vector2 GetMouseWheelMoveV(void); // Get mouse wheel movement for both X and Y -RLAPI void SetMouseCursor(int cursor); // Set mouse cursor - -// Input-related functions: touch -RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size) -RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size) -RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size) -RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index -RLAPI int GetTouchPointCount(void); // Get number of touch points - -//------------------------------------------------------------------------------------ -// Gestures and Touch Handling Functions (Module: rgestures) -//------------------------------------------------------------------------------------ -RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags -RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected -RLAPI int GetGestureDetected(void); // Get latest detected gesture -RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds -RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector -RLAPI float GetGestureDragAngle(void); // Get gesture drag angle -RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta -RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle - -//------------------------------------------------------------------------------------ -// Camera System Functions (Module: rcamera) -//------------------------------------------------------------------------------------ -RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode -RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation - -//------------------------------------------------------------------------------------ -// Basic Shapes Drawing Functions (Module: shapes) -//------------------------------------------------------------------------------------ -// Set texture and rectangle to be used on shapes drawing -// NOTE: It can be useful when using basic shapes and one single font, -// defining a font char white rectangle would allow drawing everything in a single draw call -RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing - -// Basic shapes drawing functions -RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel -RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) -RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line -RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) -RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) -RLAPI void DrawLineStrip(Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines) -RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation -RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle -RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle -RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline -RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle -RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) -RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline -RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version) -RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse -RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline -RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring -RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline -RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle -RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) -RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle -RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters -RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle -RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle -RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors -RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline -RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters -RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges -RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline -RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) -RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!) -RLAPI void DrawTriangleFan(Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points (first vertex is the center) -RLAPI void DrawTriangleStrip(Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points -RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) -RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides -RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters - -// Splines drawing functions -RLAPI void DrawSplineLinear(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Linear, minimum 2 points -RLAPI void DrawSplineBasis(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: B-Spline, minimum 4 points -RLAPI void DrawSplineCatmullRom(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Catmull-Rom, minimum 4 points -RLAPI void DrawSplineBezierQuadratic(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] -RLAPI void DrawSplineBezierCubic(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] -RLAPI void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color); // Draw spline segment: Linear, 2 points -RLAPI void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: B-Spline, 4 points -RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: Catmull-Rom, 4 points -RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point -RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points - -// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] -RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear -RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline -RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom -RLAPI Vector2 GetSplinePointBezierQuad(Vector2 p1, Vector2 c2, Vector2 p3, float t); // Get (evaluate) spline point: Quadratic Bezier -RLAPI Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t); // Get (evaluate) spline point: Cubic Bezier - -// Basic shapes collision detection functions -RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles -RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles -RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle -RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle -RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle -RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle -RLAPI bool CheckCollisionPointPoly(Vector2 point, Vector2 *points, int pointCount); // Check if point is within a polygon described by array of vertices -RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference -RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] -RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision - -//------------------------------------------------------------------------------------ -// Texture Loading and Drawing Functions (Module: textures) -//------------------------------------------------------------------------------------ - -// Image loading functions -// NOTE: These functions do not require GPU access -RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) -RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data -RLAPI Image LoadImageSvg(const char *fileNameOrString, int width, int height); // Load image from SVG file data or string with specified size -RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) -RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' -RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data -RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot) -RLAPI bool IsImageReady(Image image); // Check if an image is ready -RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) -RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success -RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer -RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success - -// Image generation functions -RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color -RLAPI Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end); // Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient -RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient -RLAPI Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer); // Generate image: square gradient -RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked -RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise -RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise -RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells -RLAPI Image GenImageText(int width, int height, const char *text); // Generate image: grayscale image from text data - -// Image manipulation functions -RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) -RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece -RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) -RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font) -RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format -RLAPI void ImageToPOT(Image *image, Color fill); // Convert image to POT (power-of-two) -RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle -RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value -RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color -RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image -RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel -RLAPI void ImageBlurGaussian(Image *image, int blurSize); // Apply Gaussian blur using a box blur approximation -RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm) -RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) -RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color -RLAPI void ImageMipmaps(Image *image); // Compute all mipmap levels for a provided image -RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -RLAPI void ImageFlipVertical(Image *image); // Flip image vertically -RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally -RLAPI void ImageRotate(Image *image, int degrees); // Rotate image by input angle in degrees (-359 to 359) -RLAPI void ImageRotateCW(Image *image); // Rotate image clockwise 90deg -RLAPI void ImageRotateCCW(Image *image); // Rotate image counter-clockwise 90deg -RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint -RLAPI void ImageColorInvert(Image *image); // Modify image color: invert -RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale -RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) -RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) -RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color -RLAPI Color *LoadImageColors(Image image); // Load color data from image as a Color array (RGBA - 32bit) -RLAPI Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount); // Load colors palette from image as a Color array (RGBA - 32bit) -RLAPI void UnloadImageColors(Color *colors); // Unload color data loaded with LoadImageColors() -RLAPI void UnloadImagePalette(Color *colors); // Unload colors palette loaded with LoadImagePalette() -RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle -RLAPI Color GetImageColor(Image image, int x, int y); // Get image pixel color at (x, y) position - -// Image drawing functions -// NOTE: Image software-rendering functions (CPU) -RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with given color -RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); // Draw pixel within an image -RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version) -RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image -RLAPI void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color); // Draw line within an image (Vector version) -RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image -RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version) -RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image -RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color); // Draw circle outline within an image (Vector version) -RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image -RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version) -RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image -RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image -RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source) -RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination) -RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination) - -// Texture loading functions -// NOTE: These functions require GPU access -RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM) -RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data -RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported -RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) -RLAPI bool IsTextureReady(Texture2D texture); // Check if a texture is ready -RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) -RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready -RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) -RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data -RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data - -// Texture configuration functions -RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture -RLAPI void SetTextureFilter(Texture2D texture, int filter); // Set texture scaling filter mode -RLAPI void SetTextureWrap(Texture2D texture, int wrap); // Set texture wrapping mode - -// Texture drawing functions -RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D -RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 -RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters -RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters -RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely - -// Color/pixel related functions -RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f -RLAPI int ColorToInt(Color color); // Get hexadecimal value for a Color -RLAPI Vector4 ColorNormalize(Color color); // Get Color normalized as float [0..1] -RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1] -RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] -RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] -RLAPI Color ColorTint(Color color, Color tint); // Get color multiplied with another color -RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f -RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f -RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f -RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint -RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value -RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format -RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer -RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format - -//------------------------------------------------------------------------------------ -// Font Loading and Text Drawing Functions (Module: text) -//------------------------------------------------------------------------------------ - -// Font loading/unloading functions -RLAPI Font GetFontDefault(void); // Get the default Font -RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set -RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) -RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' -RLAPI bool IsFontReady(Font font); // Check if a font is ready -RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use -RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info -RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) -RLAPI void UnloadFont(Font font); // Unload font from GPU memory (VRAM) -RLAPI bool ExportFontAsCode(Font font, const char *fileName); // Export font as code file, returns true on success - -// Text drawing functions -RLAPI void DrawFPS(int posX, int posY); // Draw current FPS -RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters -RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) -RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) -RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint) - -// Text font info functions -RLAPI void SetTextLineSpacing(int spacing); // Set vertical line spacing when drawing with line-breaks -RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found -RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found -RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found - -// Text codepoints management functions (unicode characters) -RLAPI char *LoadUTF8(const int *codepoints, int length); // Load UTF-8 text encoded from codepoints array -RLAPI void UnloadUTF8(char *text); // Unload UTF-8 text encoded from codepoints array -RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter -RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory -RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string -RLAPI int GetCodepoint(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) - -// Text strings management functions (no UTF-8 strings, only byte chars) -// NOTE: Some strings allocate memory internally for returned strings, just be careful! -RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied -RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal -RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending -RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style) -RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string -RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) -RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) -RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter -RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings -RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! -RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string -RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string -RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string -RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string -RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported) - -//------------------------------------------------------------------------------------ -// Basic 3d Shapes Drawing Functions (Module: models) -//------------------------------------------------------------------------------------ - -// Basic geometric 3D shapes drawing functions -RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space -RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line -RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space -RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) -RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color); // Draw a triangle strip defined by points -RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube -RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) -RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires -RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version) -RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere -RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters -RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires -RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone -RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos -RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires -RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos -RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos -RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos -RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ -RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line -RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) - -//------------------------------------------------------------------------------------ -// Model 3d Loading and Drawing Functions (Module: models) -//------------------------------------------------------------------------------------ - -// Model management functions -RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials) -RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) -RLAPI bool IsModelReady(Model model); // Check if a model is ready -RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) -RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) - -// Model drawing functions -RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters -RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) -RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) -RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source -RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation - -// Mesh management functions -RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids -RLAPI void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset); // Update mesh vertex data in GPU for a specific buffer index -RLAPI void UnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU -RLAPI void DrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform -RLAPI void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms -RLAPI bool ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file, returns true on success -RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits -RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents - -// Mesh generation functions -RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh -RLAPI Mesh GenMeshPlane(float width, float length, int resX, int resZ); // Generate plane mesh (with subdivisions) -RLAPI Mesh GenMeshCube(float width, float height, float length); // Generate cuboid mesh -RLAPI Mesh GenMeshSphere(float radius, int rings, int slices); // Generate sphere mesh (standard sphere) -RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices); // Generate half-sphere mesh (no bottom cap) -RLAPI Mesh GenMeshCylinder(float radius, float height, int slices); // Generate cylinder mesh -RLAPI Mesh GenMeshCone(float radius, float height, int slices); // Generate cone/pyramid mesh -RLAPI Mesh GenMeshTorus(float radius, float size, int radSeg, int sides); // Generate torus mesh -RLAPI Mesh GenMeshKnot(float radius, float size, int radSeg, int sides); // Generate trefoil knot mesh -RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); // Generate heightmap mesh from image data -RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data - -// Material loading/unloading functions -RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file -RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -RLAPI bool IsMaterialReady(Material material); // Check if a material is ready -RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) -RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) -RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh - -// Model animations loading/unloading functions -RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file -RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose -RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data -RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data -RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match - -// Collision detection functions -RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres -RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Check collision between two bounding boxes -RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere -RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere -RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box -RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh -RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle -RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad - -//------------------------------------------------------------------------------------ -// Audio Loading and Playing Functions (Module: audio) -//------------------------------------------------------------------------------------ -typedef void (*AudioCallback)(void *bufferData, unsigned int frames); - -// Audio device management functions -RLAPI void InitAudioDevice(void); // Initialize audio device and context -RLAPI void CloseAudioDevice(void); // Close the audio device and context -RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully -RLAPI void SetMasterVolume(float volume); // Set master volume (listener) -RLAPI float GetMasterVolume(void); // Get master volume (listener) - -// Wave/Sound loading/unloading functions -RLAPI Wave LoadWave(const char *fileName); // Load wave data from file -RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' -RLAPI bool IsWaveReady(Wave wave); // Checks if wave data is ready -RLAPI Sound LoadSound(const char *fileName); // Load sound from file -RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data -RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data -RLAPI bool IsSoundReady(Sound sound); // Checks if a sound is ready -RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data -RLAPI void UnloadWave(Wave wave); // Unload wave data -RLAPI void UnloadSound(Sound sound); // Unload sound -RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data) -RLAPI bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success -RLAPI bool ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h), returns true on success - -// Wave/Sound management functions -RLAPI void PlaySound(Sound sound); // Play a sound -RLAPI void StopSound(Sound sound); // Stop playing a sound -RLAPI void PauseSound(Sound sound); // Pause a sound -RLAPI void ResumeSound(Sound sound); // Resume a paused sound -RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing -RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) -RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) -RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center) -RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave -RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range -RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format -RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a 32bit float data array -RLAPI void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples() - -// Music management functions -RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file -RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data -RLAPI bool IsMusicReady(Music music); // Checks if a music stream is ready -RLAPI void UnloadMusicStream(Music music); // Unload music stream -RLAPI void PlayMusicStream(Music music); // Start music playing -RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing -RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming -RLAPI void StopMusicStream(Music music); // Stop music playing -RLAPI void PauseMusicStream(Music music); // Pause music playing -RLAPI void ResumeMusicStream(Music music); // Resume playing paused music -RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) -RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) -RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center) -RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) -RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) - -// AudioStream management functions -RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) -RLAPI bool IsAudioStreamReady(AudioStream stream); // Checks if an audio stream is ready -RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory -RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data -RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill -RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream -RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream -RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream -RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing -RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream -RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) -RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) -RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 is centered) -RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams -RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data - -RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives the samples as s -RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream - -RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives the samples as s -RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline - -#if defined(__cplusplus) -} -#endif - -#endif // RAYLIB_H diff --git a/raygui/slider.go b/raygui/slider.go new file mode 100644 index 0000000..153b867 --- /dev/null +++ b/raygui/slider.go @@ -0,0 +1,76 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// Slider - Slider element, returns selected value +func Slider(bounds rl.Rectangle, value, minValue, maxValue float32) float32 { + b := bounds.ToInt32() + sliderPos := float32(0) + state := Normal + + buttonTravelDistance := float32(0) + mousePoint := rl.GetMousePosition() + + // Update control + if value < minValue { + value = minValue + } else if value >= maxValue { + value = maxValue + } + + sliderPos = (value - minValue) / (maxValue - minValue) + + sliderButton := rl.RectangleInt32{} + sliderButton.Width = (b.Width-(2*int32(style[SliderButtonBorderWidth])))/10 - 8 + sliderButton.Height = b.Height - (2 * int32(style[SliderBorderWidth]+2*style[SliderButtonBorderWidth])) + + sliderButtonMinPos := b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButtonMaxPos := b.X + b.Width - (int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButton.Width) + + buttonTravelDistance = float32(sliderButtonMaxPos - sliderButtonMinPos) + + sliderButton.X = b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + int32(sliderPos*buttonTravelDistance) + sliderButton.Y = b.Y + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + + if rl.CheckCollisionPointRec(mousePoint, bounds) { + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + } + + if state == Pressed && rl.IsMouseButtonDown(rl.MouseLeftButton) { + sliderButton.X = int32(mousePoint.X) - sliderButton.Width/2 + + if sliderButton.X <= sliderButtonMinPos { + sliderButton.X = sliderButtonMinPos + } else if sliderButton.X >= sliderButtonMaxPos { + sliderButton.X = sliderButtonMaxPos + } + + sliderPos = float32(sliderButton.X-sliderButtonMinPos) / buttonTravelDistance + } + } else { + state = Normal + } + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[SliderBorderColor]))) + rl.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), rl.GetColor(int32(style[SliderInsideColor]))) + + switch state { + case Normal: + rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderDefaultColor]))) + break + case Focused: + rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderHoverColor]))) + break + case Pressed: + rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderActiveColor]))) + break + default: + break + } + + return minValue + (maxValue-minValue)*sliderPos +} diff --git a/raygui/sliderbar.go b/raygui/sliderbar.go new file mode 100644 index 0000000..dbce8fc --- /dev/null +++ b/raygui/sliderbar.go @@ -0,0 +1,76 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// SliderBar - Slider Bar element, returns selected value +func SliderBar(bounds rl.Rectangle, value, minValue, maxValue float32) float32 { + b := bounds.ToInt32() + state := Normal + + mousePoint := rl.GetMousePosition() + + fixedValue := float32(0) + fixedMinValue := float32(0) + + fixedValue = value - minValue + maxValue = maxValue - minValue + fixedMinValue = 0 + + // Update control + if fixedValue <= fixedMinValue { + fixedValue = fixedMinValue + } else if fixedValue >= maxValue { + fixedValue = maxValue + } + + sliderBar := rl.RectangleInt32{} + + sliderBar.X = b.X + int32(style[SliderBorderWidth]) + sliderBar.Y = b.Y + int32(style[SliderBorderWidth]) + sliderBar.Width = int32((fixedValue * (float32(b.Width) - 2*float32(style[SliderBorderWidth]))) / (maxValue - fixedMinValue)) + sliderBar.Height = b.Height - 2*int32(style[SliderBorderWidth]) + + if rl.CheckCollisionPointRec(mousePoint, bounds) { + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + + sliderBar.Width = (int32(mousePoint.X) - b.X - int32(style[SliderBorderWidth])) + + if int32(mousePoint.X) <= (b.X + int32(style[SliderBorderWidth])) { + sliderBar.Width = 0 + } else if int32(mousePoint.X) >= (b.X + b.Width - int32(style[SliderBorderWidth])) { + sliderBar.Width = b.Width - 2*int32(style[SliderBorderWidth]) + } + } + } else { + state = Normal + } + + fixedValue = (float32(sliderBar.Width) * (maxValue - fixedMinValue)) / (float32(b.Width) - 2*float32(style[SliderBorderWidth])) + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[SliderbarBorderColor]))) + rl.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), rl.GetColor(int32(style[SliderbarInsideColor]))) + + switch state { + case Normal: + rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarDefaultColor]))) + break + case Focused: + rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarHoverColor]))) + break + case Pressed: + rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarActiveColor]))) + break + default: + break + } + + if minValue < 0 && maxValue > 0 { + rl.DrawRectangle((b.X+int32(style[SliderBorderWidth]))-int32(minValue*(float32(b.Width-(int32(style[SliderBorderWidth])*2))/maxValue)), sliderBar.Y, 1, sliderBar.Height, rl.GetColor(int32(style[SliderbarZeroLineColor]))) + } + + return fixedValue + minValue +} diff --git a/raygui/spinner.go b/raygui/spinner.go new file mode 100644 index 0000000..eb9a8f3 --- /dev/null +++ b/raygui/spinner.go @@ -0,0 +1,176 @@ +package raygui + +import ( + "fmt" + "github.com/gen2brain/raylib-go/raylib" +) + +// For spinner +var ( + framesCounter int + framesCounter2 int + valueSpeed bool +) + +// Spinner - Spinner element, returns selected value +func Spinner(bounds rl.Rectangle, value, minValue, maxValue int) int { + b := bounds.ToInt32() + state := Normal + + mousePoint := rl.GetMousePosition() + labelBoxBound := rl.RectangleInt32{b.X + b.Width/4 + 1, b.Y, b.Width / 2, b.Height} + leftButtonBound := rl.RectangleInt32{b.X, b.Y, b.Width / 4, b.Height} + rightButtonBound := rl.RectangleInt32{b.X + b.Width - b.Width/4 + 1, b.Y, b.Width / 4, b.Height} + + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(fmt.Sprintf("%d", value), textHeight) + + buttonSide := 0 + + // Update control + if rl.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) || rl.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) || rl.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { + if rl.IsKeyDown(rl.KeyLeft) { + state = Pressed + buttonSide = 1 + + if value > minValue { + value-- + } + } else if rl.IsKeyDown(rl.KeyRight) { + state = Pressed + buttonSide = 2 + + if value < maxValue { + value++ + } + } + } + + if rl.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) { + buttonSide = 1 + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + if !valueSpeed { + if value > minValue { + value-- + } + valueSpeed = true + } else { + framesCounter++ + } + + state = Pressed + + if value > minValue { + if framesCounter >= 30 { + value-- + } + } + } + } else if rl.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) { + buttonSide = 2 + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + if !valueSpeed { + if value < maxValue { + value++ + } + valueSpeed = true + } else { + framesCounter++ + } + + state = Pressed + + if value < maxValue { + if framesCounter >= 30 { + value++ + } + } + } + } else if !rl.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { + buttonSide = 0 + } + + if rl.IsMouseButtonUp(rl.MouseLeftButton) { + valueSpeed = false + framesCounter = 0 + } + + // Draw control + switch state { + case Normal: + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + + rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) + rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) + + rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultTextColor]))) + break + case Focused: + if buttonSide == 1 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + } else if buttonSide == 2 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverSymbolColor]))) + } + + rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) + rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) + + rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverTextColor]))) + break + case Pressed: + if buttonSide == 1 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + } else if buttonSide == 2 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedSymbolColor]))) + } + + rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) + rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) + + rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedTextColor]))) + break + default: + break + } + + return value +} diff --git a/raygui/style.go b/raygui/style.go new file mode 100644 index 0000000..33a0da6 --- /dev/null +++ b/raygui/style.go @@ -0,0 +1,418 @@ +// GUI element appearance can be dynamically configured through Property values, the set of which +// forms a theme called the Style. +package raygui + +import ( + "bufio" + "fmt" + rl "github.com/gen2brain/raylib-go/raylib" + "io/ioutil" + "strconv" + "strings" +) + +// Property - GUI property +type Property int32 + +// GUI properties enumeration +const ( + GlobalBaseColor Property = iota + GlobalBorderColor + GlobalTextColor + GlobalTextFontsize + GlobalBorderWidth + GlobalBackgroundColor + GlobalLinesColor + LabelBorderWidth + LabelTextColor + LabelTextPadding + ButtonBorderWidth + ButtonTextPadding + ButtonDefaultBorderColor + ButtonDefaultInsideColor + ButtonDefaultTextColor + ButtonHoverBorderColor + ButtonHoverInsideColor + ButtonHoverTextColor + ButtonPressedBorderColor + ButtonPressedInsideColor + ButtonPressedTextColor + ToggleTextPadding + ToggleBorderWidth + ToggleDefaultBorderColor + ToggleDefaultInsideColor + ToggleDefaultTextColor + ToggleHoverBorderColor + ToggleHoverInsideColor + ToggleHoverTextColor + TogglePressedBorderColor + TogglePressedInsideColor + TogglePressedTextColor + ToggleActiveBorderColor + ToggleActiveInsideColor + ToggleActiveTextColor + TogglegroupPadding + SliderBorderWidth + SliderButtonBorderWidth + SliderBorderColor + SliderInsideColor + SliderDefaultColor + SliderHoverColor + SliderActiveColor + SliderbarBorderColor + SliderbarInsideColor + SliderbarDefaultColor + SliderbarHoverColor + SliderbarActiveColor + SliderbarZeroLineColor + ProgressbarBorderColor + ProgressbarInsideColor + ProgressbarProgressColor + ProgressbarBorderWidth + SpinnerLabelBorderColor + SpinnerLabelInsideColor + SpinnerDefaultButtonBorderColor + SpinnerDefaultButtonInsideColor + SpinnerDefaultSymbolColor + SpinnerDefaultTextColor + SpinnerHoverButtonBorderColor + SpinnerHoverButtonInsideColor + SpinnerHoverSymbolColor + SpinnerHoverTextColor + SpinnerPressedButtonBorderColor + SpinnerPressedButtonInsideColor + SpinnerPressedSymbolColor + SpinnerPressedTextColor + ComboboxPadding + boundsWidth + boundsHeight + ComboboxBorderWidth + ComboboxDefaultBorderColor + ComboboxDefaultInsideColor + ComboboxDefaultTextColor + ComboboxDefaultListTextColor + ComboboxHoverBorderColor + ComboboxHoverInsideColor + ComboboxHoverTextColor + ComboboxHoverListTextColor + ComboboxPressedBorderColor + ComboboxPressedInsideColor + ComboboxPressedTextColor + ComboboxPressedListBorderColor + ComboboxPressedListInsideColor + ComboboxPressedListTextColor + CheckboxDefaultBorderColor + CheckboxDefaultInsideColor + CheckboxHoverBorderColor + CheckboxHoverInsideColor + CheckboxClickBorderColor + CheckboxClickInsideColor + CheckboxDefaultActiveColor + CheckboxInsideWidth + TextboxBorderWidth + TextboxBorderColor + TextboxInsideColor + TextboxTextColor + TextboxLineColor + TextboxTextFontsize + + // Add new properties above. + NumProperties +) + +// GUI property names (to read/write style text files) +var propertyName = [NumProperties]string{ + "GLOBAL_BASE_COLOR", + "GLOBAL_BORDER_COLOR", + "GLOBAL_TEXT_COLOR", + "GLOBAL_TEXT_FONTSIZE", + "GLOBAL_BORDER_WIDTH", + "BACKGROUND_COLOR", + "LINES_COLOR", + "LABEL_BORDER_WIDTH", + "LABEL_TEXT_COLOR", + "LABEL_TEXT_PADDING", + "BUTTON_BORDER_WIDTH", + "BUTTON_TEXT_PADDING", + "BUTTON_DEFAULT_BORDER_COLOR", + "BUTTON_DEFAULT_INSIDE_COLOR", + "BUTTON_DEFAULT_TEXT_COLOR", + "BUTTON_HOVER_BORDER_COLOR", + "BUTTON_HOVER_INSIDE_COLOR", + "BUTTON_HOVER_TEXT_COLOR", + "BUTTON_PRESSED_BORDER_COLOR", + "BUTTON_PRESSED_INSIDE_COLOR", + "BUTTON_PRESSED_TEXT_COLOR", + "TOGGLE_TEXT_PADDING", + "TOGGLE_BORDER_WIDTH", + "TOGGLE_DEFAULT_BORDER_COLOR", + "TOGGLE_DEFAULT_INSIDE_COLOR", + "TOGGLE_DEFAULT_TEXT_COLOR", + "TOGGLE_HOVER_BORDER_COLOR", + "TOGGLE_HOVER_INSIDE_COLOR", + "TOGGLE_HOVER_TEXT_COLOR", + "TOGGLE_PRESSED_BORDER_COLOR", + "TOGGLE_PRESSED_INSIDE_COLOR", + "TOGGLE_PRESSED_TEXT_COLOR", + "TOGGLE_ACTIVE_BORDER_COLOR", + "TOGGLE_ACTIVE_INSIDE_COLOR", + "TOGGLE_ACTIVE_TEXT_COLOR", + "TOGGLEGROUP_PADDING", + "SLIDER_BORDER_WIDTH", + "SLIDER_BUTTON_BORDER_WIDTH", + "SLIDER_BORDER_COLOR", + "SLIDER_INSIDE_COLOR", + "SLIDER_DEFAULT_COLOR", + "SLIDER_HOVER_COLOR", + "SLIDER_ACTIVE_COLOR", + "SLIDERBAR_BORDER_COLOR", + "SLIDERBAR_INSIDE_COLOR", + "SLIDERBAR_DEFAULT_COLOR", + "SLIDERBAR_HOVER_COLOR", + "SLIDERBAR_ACTIVE_COLOR", + "SLIDERBAR_ZERO_LINE_COLOR", + "PROGRESSBAR_BORDER_COLOR", + "PROGRESSBAR_INSIDE_COLOR", + "PROGRESSBAR_PROGRESS_COLOR", + "PROGRESSBAR_BORDER_WIDTH", + "SPINNER_LABEL_BORDER_COLOR", + "SPINNER_LABEL_INSIDE_COLOR", + "SPINNER_DEFAULT_BUTTON_BORDER_COLOR", + "SPINNER_DEFAULT_BUTTON_INSIDE_COLOR", + "SPINNER_DEFAULT_SYMBOL_COLOR", + "SPINNER_DEFAULT_TEXT_COLOR", + "SPINNER_HOVER_BUTTON_BORDER_COLOR", + "SPINNER_HOVER_BUTTON_INSIDE_COLOR", + "SPINNER_HOVER_SYMBOL_COLOR", + "SPINNER_HOVER_TEXT_COLOR", + "SPINNER_PRESSED_BUTTON_BORDER_COLOR", + "SPINNER_PRESSED_BUTTON_INSIDE_COLOR", + "SPINNER_PRESSED_SYMBOL_COLOR", + "SPINNER_PRESSED_TEXT_COLOR", + "COMBOBOX_PADDING", + "COMBOBOX_BUTTON_WIDTH", + "COMBOBOX_BUTTON_HEIGHT", + "COMBOBOX_BORDER_WIDTH", + "COMBOBOX_DEFAULT_BORDER_COLOR", + "COMBOBOX_DEFAULT_INSIDE_COLOR", + "COMBOBOX_DEFAULT_TEXT_COLOR", + "COMBOBOX_DEFAULT_LIST_TEXT_COLOR", + "COMBOBOX_HOVER_BORDER_COLOR", + "COMBOBOX_HOVER_INSIDE_COLOR", + "COMBOBOX_HOVER_TEXT_COLOR", + "COMBOBOX_HOVER_LIST_TEXT_COLOR", + "COMBOBOX_PRESSED_BORDER_COLOR", + "COMBOBOX_PRESSED_INSIDE_COLOR", + "COMBOBOX_PRESSED_TEXT_COLOR", + "COMBOBOX_PRESSED_LIST_BORDER_COLOR", + "COMBOBOX_PRESSED_LIST_INSIDE_COLOR", + "COMBOBOX_PRESSED_LIST_TEXT_COLOR", + "CHECKBOX_DEFAULT_BORDER_COLOR", + "CHECKBOX_DEFAULT_INSIDE_COLOR", + "CHECKBOX_HOVER_BORDER_COLOR", + "CHECKBOX_HOVER_INSIDE_COLOR", + "CHECKBOX_CLICK_BORDER_COLOR", + "CHECKBOX_CLICK_INSIDE_COLOR", + "CHECKBOX_STATUS_ACTIVE_COLOR", + "CHECKBOX_INSIDE_WIDTH", + "TEXTBOX_BORDER_WIDTH", + "TEXTBOX_BORDER_COLOR", + "TEXTBOX_INSIDE_COLOR", + "TEXTBOX_TEXT_COLOR", + "TEXTBOX_LINE_COLOR", + "TEXTBOX_TEXT_FONTSIZE", +} + +// Current GUI style (default light). +var style = [NumProperties]int64{ + 0xf5f5f5ff, // GLOBAL_BASE_COLOR + 0xf5f5f5ff, // GLOBAL_BORDER_COLOR + 0xf5f5f5ff, // GLOBAL_TEXT_COLOR + 10, // GLOBAL_TEXT_FONTSIZE + 1, // GLOBAL_BORDER_WIDTH + 0xf5f5f5ff, // BACKGROUND_COLOR + 0x90abb5ff, // LINES_COLOR + 1, // LABEL_BORDER_WIDTH + 0x4d4d4dff, // LABEL_TEXT_COLOR + 20, // LABEL_TEXT_PADDING + 2, // BUTTON_BORDER_WIDTH + 20, // BUTTON_TEXT_PADDING + 0x828282ff, // BUTTON_DEFAULT_BORDER_COLOR + 0xc8c8c8ff, // BUTTON_DEFAULT_INSIDE_COLOR + 0x4d4d4dff, // BUTTON_DEFAULT_TEXT_COLOR + 0xc8c8c8ff, // BUTTON_HOVER_BORDER_COLOR + 0xffffffff, // BUTTON_HOVER_INSIDE_COLOR + 0x868686ff, // BUTTON_HOVER_TEXT_COLOR + 0x7bb0d6ff, // BUTTON_PRESSED_BORDER_COLOR + 0xbcecffff, // BUTTON_PRESSED_INSIDE_COLOR + 0x5f9aa7ff, // BUTTON_PRESSED_TEXT_COLOR + 20, // TOGGLE_TEXT_PADDING + 1, // TOGGLE_BORDER_WIDTH + 0x828282ff, // TOGGLE_DEFAULT_BORDER_COLOR + 0xc8c8c8ff, // TOGGLE_DEFAULT_INSIDE_COLOR + 0x828282ff, // TOGGLE_DEFAULT_TEXT_COLOR + 0xc8c8c8ff, // TOGGLE_HOVER_BORDER_COLOR + 0xffffffff, // TOGGLE_HOVER_INSIDE_COLOR + 0x828282ff, // TOGGLE_HOVER_TEXT_COLOR + 0xbdd7eaff, // TOGGLE_PRESSED_BORDER_COLOR + 0xddf5ffff, // TOGGLE_PRESSED_INSIDE_COLOR + 0xafccd3ff, // TOGGLE_PRESSED_TEXT_COLOR + 0x7bb0d6ff, // TOGGLE_ACTIVE_BORDER_COLOR + 0xbcecffff, // TOGGLE_ACTIVE_INSIDE_COLOR + 0x5f9aa7ff, // TOGGLE_ACTIVE_TEXT_COLOR + 3, // TOGGLEGROUP_PADDING + 1, // SLIDER_BORDER_WIDTH + 1, // SLIDER_BUTTON_BORDER_WIDTH + 0x828282ff, // SLIDER_BORDER_COLOR + 0xc8c8c8ff, // SLIDER_INSIDE_COLOR + 0xbcecffff, // SLIDER_DEFAULT_COLOR + 0xffffffff, // SLIDER_HOVER_COLOR + 0xddf5ffff, // SLIDER_ACTIVE_COLOR + 0x828282ff, // SLIDERBAR_BORDER_COLOR + 0xc8c8c8ff, // SLIDERBAR_INSIDE_COLOR + 0xbcecffff, // SLIDERBAR_DEFAULT_COLOR + 0xffffffff, // SLIDERBAR_HOVER_COLOR + 0xddf5ffff, // SLIDERBAR_ACTIVE_COLOR + 0x828282ff, // SLIDERBAR_ZERO_LINE_COLOR + 0x828282ff, // PROGRESSBAR_BORDER_COLOR + 0xc8c8c8ff, // PROGRESSBAR_INSIDE_COLOR + 0xbcecffff, // PROGRESSBAR_PROGRESS_COLOR + 2, // PROGRESSBAR_BORDER_WIDTH + 0x828282ff, // SPINNER_LABEL_BORDER_COLOR + 0xc8c8c8ff, // SPINNER_LABEL_INSIDE_COLOR + 0x828282ff, // SPINNER_DEFAULT_BUTTON_BORDER_COLOR + 0xc8c8c8ff, // SPINNER_DEFAULT_BUTTON_INSIDE_COLOR + 0x000000ff, // SPINNER_DEFAULT_SYMBOL_COLOR + 0x000000ff, // SPINNER_DEFAULT_TEXT_COLOR + 0xc8c8c8ff, // SPINNER_HOVER_BUTTON_BORDER_COLOR + 0xffffffff, // SPINNER_HOVER_BUTTON_INSIDE_COLOR + 0x000000ff, // SPINNER_HOVER_SYMBOL_COLOR + 0x000000ff, // SPINNER_HOVER_TEXT_COLOR + 0x7bb0d6ff, // SPINNER_PRESSED_BUTTON_BORDER_COLOR + 0xbcecffff, // SPINNER_PRESSED_BUTTON_INSIDE_COLOR + 0x5f9aa7ff, // SPINNER_PRESSED_SYMBOL_COLOR + 0x000000ff, // SPINNER_PRESSED_TEXT_COLOR + 1, // COMBOBOX_PADDING + 30, // COMBOBOX_BUTTON_WIDTH + 20, // COMBOBOX_BUTTON_HEIGHT + 1, // COMBOBOX_BORDER_WIDTH + 0x828282ff, // COMBOBOX_DEFAULT_BORDER_COLOR + 0xc8c8c8ff, // COMBOBOX_DEFAULT_INSIDE_COLOR + 0x828282ff, // COMBOBOX_DEFAULT_TEXT_COLOR + 0x828282ff, // COMBOBOX_DEFAULT_LIST_TEXT_COLOR + 0xc8c8c8ff, // COMBOBOX_HOVER_BORDER_COLOR + 0xffffffff, // COMBOBOX_HOVER_INSIDE_COLOR + 0x828282ff, // COMBOBOX_HOVER_TEXT_COLOR + 0x828282ff, // COMBOBOX_HOVER_LIST_TEXT_COLOR + 0x7bb0d6ff, // COMBOBOX_PRESSED_BORDER_COLOR + 0xbcecffff, // COMBOBOX_PRESSED_INSIDE_COLOR + 0x5f9aa7ff, // COMBOBOX_PRESSED_TEXT_COLOR + 0x0078acff, // COMBOBOX_PRESSED_LIST_BORDER_COLOR + 0x66e7ffff, // COMBOBOX_PRESSED_LIST_INSIDE_COLOR + 0x0078acff, // COMBOBOX_PRESSED_LIST_TEXT_COLOR + 0x828282ff, // CHECKBOX_DEFAULT_BORDER_COLOR + 0xffffffff, // CHECKBOX_DEFAULT_INSIDE_COLOR + 0xc8c8c8ff, // CHECKBOX_HOVER_BORDER_COLOR + 0xffffffff, // CHECKBOX_HOVER_INSIDE_COLOR + 0x66e7ffff, // CHECKBOX_CLICK_BORDER_COLOR + 0xddf5ffff, // CHECKBOX_CLICK_INSIDE_COLOR + 0xbcecffff, // CHECKBOX_STATUS_ACTIVE_COLOR + 1, // CHECKBOX_INSIDE_WIDTH + 1, // TEXTBOX_BORDER_WIDTH + 0x828282ff, // TEXTBOX_BORDER_COLOR + 0xf5f5f5ff, // TEXTBOX_INSIDE_COLOR + 0x000000ff, // TEXTBOX_TEXT_COLOR + 0x000000ff, // TEXTBOX_LINE_COLOR + 10, // TEXTBOX_TEXT_FONTSIZE +} + +// LoadGuiStyle will load a GUI style from a file. See SaveGuiStyle. +func LoadGuiStyle(fileName string) { + file, err := rl.OpenAsset(fileName) + if err != nil { + rl.TraceLog(rl.LogWarning, "[%s] GUI style file could not be opened: %w", fileName, err) + return + } + defer file.Close() + + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) != 2 { + continue + } + + id := fields[0] + value := fields[1] + + for i := 0; i < len(propertyName); i++ { + if id == propertyName[i] { + if strings.HasPrefix(value, "0x") { + value = value[2:] + } + + v, err := strconv.ParseInt(value, 16, 64) + if err == nil { + style[i] = int64(v) + } + } + } + } +} + +// SaveGuiStyle will write the current GUI style to a file in a format suitable for loading via LoadGuiStyle. +func SaveGuiStyle(fileName string) { + var styleFile string + for i := 0; i < len(propertyName); i++ { + styleFile += fmt.Sprintf("%-40s0x%x\n", propertyName[i], GetStyleProperty(Property(i))) + } + + if err := ioutil.WriteFile(fileName, []byte(styleFile), 0644); err != nil { + rl.TraceLog(rl.LogWarning, "[%s] GUI style file could not be written: %w", fileName, err) + } +} + +// SetStyleProperty - Set one style property +func SetStyleProperty(guiProperty Property, value int64) { + style[guiProperty] = value +} + +// SetStyleColor - Set one style property to a color value +func SetStyleColor(guiProperty Property, value rl.Color) { + style[guiProperty] = int64(rl.ColorToInt(value)) +} + +// GetStyleProperty - Get one style property +func GetStyleProperty(guiProperty Property) int64 { + return style[int(guiProperty)] +} + +// BackgroundColor will return the current background color +func BackgroundColor() rl.Color { + return rl.GetColor(int32(style[GlobalBackgroundColor])) +} + +// LinesColor will return the current color for lines +func LinesColor() rl.Color { + return rl.GetColor(int32(style[GlobalLinesColor])) +} + +// TextColor will return the current color for normal state +func TextColor() rl.Color { + return rl.GetColor(int32(style[GlobalTextColor])) +} + +// GetStyle32 will return the int32 for a given property of the current style +func GetStyle32(property Property) int32 { + return int32(style[property]) +} + +// GetPropColor will return the Color value for a given property of the current style +func GetStyleColor(property Property) rl.Color { + return rl.GetColor(int32(style[property])) +} diff --git a/raygui/textbox.go b/raygui/textbox.go new file mode 100644 index 0000000..61258e2 --- /dev/null +++ b/raygui/textbox.go @@ -0,0 +1,62 @@ +package raygui + +import ( + "fmt" + "github.com/gen2brain/raylib-go/raylib" + "time" +) + +var backspaceHeld = false +var nextBackspace = time.Now() + +// BackspaceRepeatDelay controls the time backspace must be held down before it will repeat. +var BackspaceRepeatDelay = 300 * time.Millisecond +// BackspaceRepeatInterval controls how frequently backspace registers after the initial delay. +var BackspaceRepeatInterval = 60 * time.Millisecond + +// TextBox - Text Box element, updates input text +func TextBox(bounds rl.Rectangle, text string) string { + b := bounds.ToInt32() + + letter := int32(-1) + + // Update control + state := GetInteractionState(bounds) + borderColor := TextboxBorderColor + if state == Pressed || state == Focused { + borderColor = ToggleActiveBorderColor + + framesCounter2++ + letter = rl.GetKeyPressed() + if letter != -1 { + if letter >= 32 && letter < 127 { + text = fmt.Sprintf("%s%c", text, letter) + } + } + + backspacing := rl.IsKeyPressed(rl.KeyBackspace) + if backspacing { + nextBackspace = time.Now().Add(BackspaceRepeatDelay) + } else if rl.IsKeyDown(rl.KeyBackspace) { + backspacing = time.Since(nextBackspace) >= 0 + if backspacing { + nextBackspace = time.Now().Add(BackspaceRepeatInterval) + } + } + if backspacing && len(text) > 0 { + text = text[:len(text)-1] + } + } + + DrawBorderedRectangle(b, GetStyle32(TextboxBorderWidth), GetStyleColor(borderColor), GetStyleColor(TextboxInsideColor)) + rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), GetStyleColor(TextboxTextColor)) + + if state == Focused || state == Pressed { + // Draw a cursor, when focused. + if (framesCounter2/20)%2 == 0 { + rl.DrawRectangle(b.X+4+rl.MeasureText(text, int32(style[GlobalTextFontsize])), b.Y+2, 1, b.Height-4, rl.GetColor(int32(style[TextboxLineColor]))) + } + } + + return text +} diff --git a/raygui/togglebutton.go b/raygui/togglebutton.go new file mode 100644 index 0000000..3848b62 --- /dev/null +++ b/raygui/togglebutton.go @@ -0,0 +1,48 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// togglebuttonColoring describes the per-state colors for a ToggleBox control. +type togglebuttonColoring struct { + Border, Inside, Text Property +} + +// togglebuttonColors lists the styling for each supported state. +var togglebuttonColors = map[ControlState]togglebuttonColoring{ + Normal: {ToggleDefaultBorderColor, ToggleDefaultInsideColor, ToggleDefaultTextColor}, + // Hijacking 'Clicked' for the 'active' state. + Clicked: {ToggleActiveBorderColor, ToggleActiveInsideColor, ToggleDefaultTextColor}, + Pressed: {TogglePressedBorderColor, TogglePressedInsideColor, TogglePressedTextColor}, + Focused: {ToggleHoverBorderColor, ToggleHoverInsideColor, ToggleHoverTextColor}, +} + +// ToggleButton - Toggle Button element, returns true when active +func ToggleButton(bounds rl.Rectangle, text string, active bool) bool { + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(text, textHeight) + + ConstrainRectangle(&bounds, textWidth, textWidth+GetStyle32(ToggleTextPadding), textHeight, textHeight+GetStyle32(ToggleTextPadding)) + + state := GetInteractionState(bounds) + if state == Clicked { + active = !active + state = Normal + } + + // Hijack 'Clicked' as the 'active' state + if state == Normal && active { + state = Clicked + } + + colors, exists := togglebuttonColors[state] + if !exists { + return active + } + + // Draw control + b := bounds.ToInt32() + DrawBorderedRectangle(b, GetStyle32(ToggleBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.Text)) + + return active +} diff --git a/raygui/togglegroup.go b/raygui/togglegroup.go new file mode 100644 index 0000000..33ccaa1 --- /dev/null +++ b/raygui/togglegroup.go @@ -0,0 +1,17 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// ToggleGroup - Toggle Group element, returns toggled button index +func ToggleGroup(bounds rl.Rectangle, toggleText []string, active int) int { + padding := float32(style[TogglegroupPadding]) + for i := 0; i < len(toggleText); i++ { + if i == active { + ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+padding), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) + } else if ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+padding), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { + active = i + } + } + + return active +} diff --git a/raylib/camera.go b/raylib/camera.go new file mode 100644 index 0000000..2429b44 --- /dev/null +++ b/raylib/camera.go @@ -0,0 +1,50 @@ +// +build !android + +package rl + +/* +#include "raylib.h" +*/ +import "C" + +// SetCameraMode - Set camera mode (multiple camera modes available) +func SetCameraMode(camera Camera, mode CameraMode) { + ccamera := camera.cptr() + cmode := (C.int)(mode) + C.SetCameraMode(*ccamera, cmode) +} + +// UpdateCamera - Update camera position for selected mode +func UpdateCamera(camera *Camera) { + ccamera := camera.cptr() + C.UpdateCamera(ccamera) +} + +// SetCameraPanControl - Set camera pan key to combine with mouse movement (free camera) +func SetCameraPanControl(panKey int32) { + cpanKey := (C.int)(panKey) + C.SetCameraPanControl(cpanKey) +} + +// SetCameraAltControl - Set camera alt key to combine with mouse movement (free camera) +func SetCameraAltControl(altKey int32) { + caltKey := (C.int)(altKey) + C.SetCameraAltControl(caltKey) +} + +// SetCameraSmoothZoomControl - Set camera smooth zoom key to combine with mouse (free camera) +func SetCameraSmoothZoomControl(szKey int32) { + cszKey := (C.int)(szKey) + C.SetCameraSmoothZoomControl(cszKey) +} + +// SetCameraMoveControls - Set camera move controls (1st person and 3rd person cameras) +func SetCameraMoveControls(frontKey int32, backKey int32, rightKey int32, leftKey int32, upKey int32, downKey int32) { + cfrontKey := (C.int)(frontKey) + cbackKey := (C.int)(backKey) + crightKey := (C.int)(rightKey) + cleftKey := (C.int)(leftKey) + cupKey := (C.int)(upKey) + cdownKey := (C.int)(downKey) + C.SetCameraMoveControls(cfrontKey, cbackKey, crightKey, cleftKey, cupKey, cdownKey) +} diff --git a/raylib/camera.h b/raylib/camera.h new file mode 100644 index 0000000..35eda83 --- /dev/null +++ b/raylib/camera.h @@ -0,0 +1,522 @@ +/******************************************************************************************* +* +* raylib.camera - Camera system with multiple modes support +* +* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) +* +* CONFIGURATION: +* +* #define CAMERA_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define CAMERA_STANDALONE +* If defined, the library can be used as standalone as a camera system but some +* functions must be redefined to manage inputs accordingly. +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, update and maintenance +* Marc Palau: Initial implementation (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2015-2021 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef CAMERA_H +#define CAMERA_H + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Below types are required for CAMERA_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(CAMERA_STANDALONE) + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Camera type, defines a camera position/orientation in 3d space + typedef struct Camera3D { + Vector3 position; // Camera position + Vector3 target; // Camera target it looks-at + Vector3 up; // Camera up vector (rotation over its axis) + float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic + int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + } Camera3D; + + typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D + + // Camera system modes + typedef enum { + CAMERA_CUSTOM = 0, + CAMERA_FREE, + CAMERA_ORBITAL, + CAMERA_FIRST_PERSON, + CAMERA_THIRD_PERSON + } CameraMode; + + // Camera projection modes + typedef enum { + CAMERA_PERSPECTIVE = 0, + CAMERA_ORTHOGRAPHIC + } CameraProjection; +#endif + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +#if defined(CAMERA_STANDALONE) +void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) +void UpdateCamera(Camera *camera); // Update camera position for selected mode + +void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) +void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) +void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera) +void SetCameraMoveControls(int keyFront, int keyBack, + int keyRight, int keyLeft, + int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) +#endif + +#ifdef __cplusplus +} +#endif + +#endif // CAMERA_H + + +/*********************************************************************************** +* +* CAMERA IMPLEMENTATION +* +************************************************************************************/ + +#if defined(CAMERA_IMPLEMENTATION) + +#include // Required for: sinf(), cosf(), sqrtf() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef PI + #define PI 3.14159265358979323846 +#endif +#ifndef DEG2RAD + #define DEG2RAD (PI/180.0f) +#endif +#ifndef RAD2DEG + #define RAD2DEG (180.0f/PI) +#endif + +// Camera mouse movement sensitivity +#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f +#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f + +// FREE_CAMERA +#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f +#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f +#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f +#define CAMERA_FREE_MIN_CLAMP 85.0f +#define CAMERA_FREE_MAX_CLAMP -85.0f +#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f +#define CAMERA_FREE_PANNING_DIVIDER 5.1f + +// ORBITAL_CAMERA +#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame + +// FIRST_PERSON +//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f +#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f +#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f +#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f + +#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f +#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f +#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f + +// THIRD_PERSON +//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f +#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f +#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f +#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f +#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } + +// PLAYER (used by camera) +#define PLAYER_MOVEMENT_SENSITIVITY 20.0f + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Camera move modes (first person and third person cameras) +typedef enum { + MOVE_FRONT = 0, + MOVE_BACK, + MOVE_RIGHT, + MOVE_LEFT, + MOVE_UP, + MOVE_DOWN +} CameraMove; + +// Camera global state context data [56 bytes] +typedef struct { + unsigned int mode; // Current camera mode + float targetDistance; // Camera distance from position to target + float playerEyesPosition; // Player eyes position from ground (in meters) + Vector2 angle; // Camera angle in plane XZ + + // Camera movement control keys + int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) + int smoothZoomControl; // Smooth zoom control key + int altControl; // Alternative control key + int panControl; // Pan view control key +} CameraData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static CameraData CAMERA = { // Global CAMERA state context + .mode = 0, + .targetDistance = 0, + .playerEyesPosition = 1.85f, + .angle = { 0 }, + .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, + .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL + .altControl = 342, // raylib: KEY_LEFT_ALT + .panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE +}; + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +#if defined(CAMERA_STANDALONE) +// NOTE: Camera controls depend on some raylib input functions +static void EnableCursor() {} // Unlock cursor +static void DisableCursor() {} // Lock cursor + +static int IsKeyDown(int key) { return 0; } + +static int IsMouseButtonDown(int button) { return 0;} +static float GetMouseWheelMove() { return 0.0f; } +static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Select camera mode (multiple camera modes available) +void SetCameraMode(Camera camera, int mode) +{ + Vector3 v1 = camera.position; + Vector3 v2 = camera.target; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + float dz = v2.z - v1.z; + + CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target + + // Camera angle calculation + CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) + CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) + + CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position + + // Lock cursor for first person and third person cameras + if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); + else EnableCursor(); + + CAMERA.mode = mode; +} + +// Update camera depending on selected mode +// NOTE: Camera controls depend on some raylib functions: +// System: EnableCursor(), DisableCursor() +// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove() +// Keys: IsKeyDown() +// TODO: Port to quaternion-based camera (?) +void UpdateCamera(Camera *camera) +{ + static int swingCounter = 0; // Used for 1st person swinging movement + static Vector2 previousMousePosition = { 0.0f, 0.0f }; + + // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) + + // Mouse movement detection + Vector2 mousePositionDelta = { 0.0f, 0.0f }; + Vector2 mousePosition = GetMousePosition(); + float mouseWheelMove = GetMouseWheelMove(); + + // Keys input detection + // TODO: Input detection is raylib-dependant, it could be moved outside the module + bool keyPan = IsMouseButtonDown(CAMERA.panControl); + bool keyAlt = IsKeyDown(CAMERA.altControl); + bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); + bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]), + IsKeyDown(CAMERA.moveControl[MOVE_BACK]), + IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]), + IsKeyDown(CAMERA.moveControl[MOVE_LEFT]), + IsKeyDown(CAMERA.moveControl[MOVE_UP]), + IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; + + if (CAMERA.mode != CAMERA_CUSTOM) + { + mousePositionDelta.x = mousePosition.x - previousMousePosition.x; + mousePositionDelta.y = mousePosition.y - previousMousePosition.y; + + previousMousePosition = mousePosition; + } + + // Support for multiple automatic camera modes + // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually + switch (CAMERA.mode) + { + case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme + { + // Camera zoom + if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) + { + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; + } + + // Camera looking down + else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + } + else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + + // if (camera->target.y < 0) camera->target.y = -0.001; + } + else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) + { + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; + } + // Camera looking up + else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + } + else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + + // if (camera->target.y > 0) camera->target.y = 0.001; + } + else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) + { + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; + } + + // Input keys checks + if (keyPan) + { + if (keyAlt) // Alternative key behaviour + { + if (szoomKey) + { + // Camera smooth zoom + CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); + } + else + { + // Camera rotation + CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; + CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; + + // Angle clamp + if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; + else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; + } + } + else + { + // Camera panning + camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); + } + } + + // Update camera position with changes + camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; + camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y; + camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + + } break; + case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed + { + CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom + + // Camera distance clamp + if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; + + // Update camera position with changes + camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; + camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; + camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + + } break; + case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable + { + camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - + sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - + cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + + cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - + sinf(CAMERA.angle.y)*direction[MOVE_BACK] + + 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - + cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + + sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - + sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + // Camera orientation calculation + CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); + CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); + + // Angle clamp + if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; + else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; + + // Recalculate camera target considering translation and rotation + Matrix translation = MatrixTranslate(0, 0, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER)); + Matrix rotation = MatrixRotateXYZ((Vector3){ PI*2 - CAMERA.angle.y, PI*2 - CAMERA.angle.x, 0 }); + Matrix transform = MatrixMultiply(translation, rotation); + + camera->target.x = camera->position.x - transform.m12; + camera->target.y = camera->position.y - transform.m13; + camera->target.z = camera->position.z - transform.m14; + + // If movement detected (some key pressed), increase swinging + for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; } + + // Camera position update + // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' + camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; + + camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; + camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; + + } break; + case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable + { + camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - + sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - + cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + + cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - + sinf(CAMERA.angle.y)*direction[MOVE_BACK] + + 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - + cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + + sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - + sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + // Camera orientation calculation + CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); + CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); + + // Angle clamp + if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; + else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; + + // Camera zoom + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + + // Camera distance clamp + if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; + + // TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target... + camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; + + if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; + else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; + + camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + + } break; + case CAMERA_CUSTOM: break; + default: break; + } +} + +// Set camera pan key to combine with mouse movement (free camera) +void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; } + +// Set camera alt key to combine with mouse movement (free camera) +void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; } + +// Set camera smooth zoom key to combine with mouse (free camera) +void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; } + +// Set camera move controls (1st person and 3rd person cameras) +void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown) +{ + CAMERA.moveControl[MOVE_FRONT] = keyFront; + CAMERA.moveControl[MOVE_BACK] = keyBack; + CAMERA.moveControl[MOVE_RIGHT] = keyRight; + CAMERA.moveControl[MOVE_LEFT] = keyLeft; + CAMERA.moveControl[MOVE_UP] = keyUp; + CAMERA.moveControl[MOVE_DOWN] = keyDown; +} + +#endif // CAMERA_IMPLEMENTATION diff --git a/raylib/cgo.go b/raylib/cgo.go index 88562e0..918b996 100644 --- a/raylib/cgo.go +++ b/raylib/cgo.go @@ -1,6 +1,6 @@ package rl /* -#cgo CFLAGS: -std=gnu99 -Wno-missing-braces -Wno-unused-result -Wno-implicit-function-declaration -Wno-int-to-pointer-cast +#cgo CFLAGS: -std=gnu99 -Wno-missing-braces -Wno-unused-result */ import "C" diff --git a/raylib/cgo_android.go b/raylib/cgo_android.go index 11714e9..f6c6a75 100644 --- a/raylib/cgo_android.go +++ b/raylib/cgo_android.go @@ -1,4 +1,3 @@ -//go:build android // +build android package rl @@ -7,8 +6,6 @@ package rl #include "external/android/native_app_glue/android_native_app_glue.c" #cgo android LDFLAGS: -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lm -#cgo android CFLAGS: -DPLATFORM_ANDROID -DGRAPHICS_API_OPENGL_ES2 -Iexternal/android/native_app_glue -Wno-implicit-const-int-float-conversion - -#cgo android,arm CFLAGS: -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 +#cgo android CFLAGS: -DPLATFORM_ANDROID -DGRAPHICS_API_OPENGL_ES2 -Iexternal/android/native_app_glue */ import "C" diff --git a/raylib/cgo_darwin.go b/raylib/cgo_darwin.go index 575fb88..77668f4 100644 --- a/raylib/cgo_darwin.go +++ b/raylib/cgo_darwin.go @@ -1,5 +1,4 @@ -//go:build darwin && !rgfw && !sdl && !sdl3 -// +build darwin,!rgfw,!sdl,!sdl3 +// +build darwin package rl @@ -8,7 +7,6 @@ package rl #include "external/glfw/src/init.c" #include "external/glfw/src/input.c" #include "external/glfw/src/monitor.c" -#include "external/glfw/src/platform.c" #include "external/glfw/src/vulkan.c" #include "external/glfw/src/window.c" @@ -17,26 +15,16 @@ package rl #include "external/glfw/src/cocoa_monitor.m" #include "external/glfw/src/cocoa_time.c" #include "external/glfw/src/cocoa_window.m" -#include "external/glfw/src/posix_module.c" #include "external/glfw/src/posix_thread.c" #include "external/glfw/src/nsgl_context.m" #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { - return GLFW_TRUE; -} +#cgo darwin LDFLAGS: -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework CoreFoundation +#cgo darwin CFLAGS: -x objective-c -Iexternal/glfw/include -D_GLFW_COCOA -D_GLFW_USE_CHDIR -D_GLFW_USE_MENUBAR -D_GLFW_USE_RETINA -Wno-deprecated-declarations -DPLATFORM_DESKTOP -#cgo darwin LDFLAGS: -framework Cocoa -framework IOKit -framework CoreVideo -framework CoreFoundation -#cgo darwin CFLAGS: -x objective-c -Iexternal/glfw/include -D_GLFW_COCOA -D_GLFW_USE_CHDIR -D_GLFW_USE_MENUBAR -D_GLFW_USE_RETINA -Wno-deprecated-declarations -Wno-implicit-const-int-float-conversion -DPLATFORM_DESKTOP - -#cgo darwin,!es2,!es3 LDFLAGS: -framework OpenGL - -#cgo darwin,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo darwin,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo darwin,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo darwin,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo darwin,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo darwin,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 +#cgo darwin,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11 +#cgo darwin,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21 +#cgo darwin,!opengl11,!opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_33 */ import "C" diff --git a/raylib/cgo_darwin_rgfw.go b/raylib/cgo_darwin_rgfw.go deleted file mode 100644 index 3006c24..0000000 --- a/raylib/cgo_darwin_rgfw.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build darwin && rgfw && !sdl && !sdl3 -// +build darwin,rgfw,!sdl,!sdl3 - -package rl - -/* -#cgo darwin LDFLAGS: -framework Foundation -framework AppKit -framework CoreVideo -#cgo darwin CFLAGS: -DPLATFORM_DESKTOP_RGFW -Wno-deprecated-declarations -Wno-implicit-const-int-float-conversion -Wno-typedef-redefinition -Wno-extern-initializer -Wno-unused-value -#cgo darwin CFLAGS: -Wno-incompatible-pointer-types -Wno-incompatible-function-pointer-types -Wno-incompatible-pointer-types-discards-qualifiers -Wno-macro-redefined - -#cgo darwin,!es2,!es3 LDFLAGS: -framework OpenGL - -#cgo darwin,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo darwin,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo darwin,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo darwin,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo darwin,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo darwin,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_darwin_sdl.go b/raylib/cgo_darwin_sdl.go deleted file mode 100644 index a5d3a08..0000000 --- a/raylib/cgo_darwin_sdl.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build darwin && (sdl || sdl3) && !rgfw -// +build darwin -// +build sdl sdl3 -// +build !rgfw - -package rl - -/* -#cgo darwin LDFLAGS: -framework Cocoa -framework IOKit -framework CoreVideo -framework CoreFoundation -#cgo darwin CFLAGS: -Wno-deprecated-declarations -Wno-implicit-const-int-float-conversion -#cgo darwin,sdl CFLAGS: -DPLATFORM_DESKTOP_SDL -#cgo darwin,sdl3 CFLAGS: -DPLATFORM_DESKTOP_SDL -DPLATFORM_DESKTOP_SDL3 -#cgo darwin,sdl pkg-config: sdl2 -#cgo darwin,sdl3 pkg-config: sdl3 - -#cgo darwin,!es2,!es3 LDFLAGS: -framework OpenGL - -#cgo darwin,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo darwin,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo darwin,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo darwin,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo darwin,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo darwin,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_freebsd.go b/raylib/cgo_freebsd.go deleted file mode 100644 index c29c731..0000000 --- a/raylib/cgo_freebsd.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build freebsd && !linux && !rgfw && !drm && !sdl && !sdl3 && !android -// +build freebsd,!linux,!rgfw,!drm,!sdl,!sdl3,!android - -package rl - -/* -#include "external/glfw/src/context.c" -#include "external/glfw/src/init.c" -#include "external/glfw/src/input.c" -#include "external/glfw/src/monitor.c" -#include "external/glfw/src/platform.c" -#include "external/glfw/src/vulkan.c" -#include "external/glfw/src/window.c" - -#include "external/glfw/src/x11_init.c" -#include "external/glfw/src/x11_monitor.c" -#include "external/glfw/src/x11_window.c" -#include "external/glfw/src/glx_context.c" - -#include "external/glfw/src/null_joystick.c" -#include "external/glfw/src/posix_module.c" -#include "external/glfw/src/posix_poll.c" -#include "external/glfw/src/posix_thread.c" -#include "external/glfw/src/posix_time.c" -#include "external/glfw/src/xkb_unicode.c" -#include "external/glfw/src/egl_context.c" -#include "external/glfw/src/osmesa_context.c" - -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { - return GLFW_TRUE; -} - -#cgo freebsd CFLAGS: -I. -I/usr/local/include -Iexternal/glfw/include -DPLATFORM_DESKTOP -D_GLFW_X11 -#cgo freebsd LDFLAGS: -L/usr/local/lib -lm -pthread -ldl -lrt -lX11 - -#cgo freebsd,!es2,!es3 LDFLAGS: -lGL - -#cgo freebsd,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo freebsd,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo freebsd,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo freebsd,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo freebsd,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo freebsd,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_freebsd_rgfw.go b/raylib/cgo_freebsd_rgfw.go deleted file mode 100644 index 6df34b8..0000000 --- a/raylib/cgo_freebsd_rgfw.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build freebsd && rgfw && !linux && !drm && !sdl && !sdl3 && !android -// +build freebsd,rgfw,!linux,!drm,!sdl,!sdl3,!android - -package rl - -/* -#cgo freebsd CFLAGS: -I. -I/usr/local/include -DPLATFORM_DESKTOP_RGFW -#cgo freebsd LDFLAGS: -L/usr/local/lib -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor -lm -lpthread -ldl -lrt - -#cgo freebsd,!es2,!es3 LDFLAGS: -lGL - -#cgo freebsd,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo freebsd,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo freebsd,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo freebsd,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo freebsd,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo freebsd,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_freebsd_sdl.go b/raylib/cgo_freebsd_sdl.go deleted file mode 100644 index cc56b7e..0000000 --- a/raylib/cgo_freebsd_sdl.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build freebsd && !linux && (sdl || sdl3) && !rgfw && !drm && !android -// +build freebsd -// +build !linux -// +build sdl sdl3 -// +build !rgfw -// +build !drm -// +build !android - -package rl - -/* -#cgo freebsd CFLAGS: -I. -I/usr/local/include -#cgo freebsd,sdl CFLAGS: -DPLATFORM_DESKTOP_SDL -#cgo freebsd,sdl3 CFLAGS: -DPLATFORM_DESKTOP_SDL -DPLATFORM_DESKTOP_SDL3 -#cgo freebsd LDFLAGS: -L/usr/local/lib - -#cgo freebsd,sdl pkg-config: sdl2 -#cgo freebsd,sdl3 pkg-config: sdl3 - -#cgo freebsd,!es2,!es3 LDFLAGS: -lGL - -#cgo freebsd,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo freebsd,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo freebsd,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo freebsd,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo freebsd,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo freebsd,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_linux.go b/raylib/cgo_linux.go index 453d563..77a6bb5 100644 --- a/raylib/cgo_linux.go +++ b/raylib/cgo_linux.go @@ -1,5 +1,4 @@ -//go:build linux && !rgfw && !drm && !sdl && !sdl3 && !android -// +build linux,!rgfw,!drm,!sdl,!sdl3,!android +// +build linux,!drm,!rpi,!android package rl @@ -8,17 +7,21 @@ package rl #include "external/glfw/src/init.c" #include "external/glfw/src/input.c" #include "external/glfw/src/monitor.c" -#include "external/glfw/src/platform.c" #include "external/glfw/src/vulkan.c" #include "external/glfw/src/window.c" -#if defined _GLFW_WAYLAND +#ifdef _GLFW_WAYLAND #include "external/glfw/src/wl_init.c" #include "external/glfw/src/wl_monitor.c" #include "external/glfw/src/wl_window.c" +#include "external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c" +#include "external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c" +#include "external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c" +#include "external/glfw/src/wayland-xdg-shell-client-protocol.c" +#include "external/glfw/src/wayland-xdg-decoration-client-protocol.c" +#include "external/glfw/src/wayland-viewporter-client-protocol.c" #endif - -#if defined _GLFW_X11 +#ifdef _GLFW_X11 #include "external/glfw/src/x11_init.c" #include "external/glfw/src/x11_monitor.c" #include "external/glfw/src/x11_window.c" @@ -26,33 +29,22 @@ package rl #endif #include "external/glfw/src/linux_joystick.c" -#include "external/glfw/src/posix_module.c" -#include "external/glfw/src/posix_poll.c" #include "external/glfw/src/posix_thread.c" #include "external/glfw/src/posix_time.c" #include "external/glfw/src/xkb_unicode.c" #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { - return GLFW_TRUE; -} - #cgo linux CFLAGS: -Iexternal/glfw/include -DPLATFORM_DESKTOP -Wno-stringop-overflow -#cgo linux LDFLAGS: -lm -pthread -ldl -lrt -lxkbcommon -#cgo linux,!x11 LDFLAGS: -lwayland-client -lwayland-cursor -lwayland-egl -#cgo linux,x11 CFLAGS: -D_GLFW_X11 +#cgo linux,!wayland LDFLAGS: -lGL -lm -pthread -ldl -lrt -lX11 +#cgo linux,wayland LDFLAGS: -lGL -lm -pthread -ldl -lrt -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + +#cgo linux,!wayland CFLAGS: -D_GLFW_X11 #cgo linux,wayland CFLAGS: -D_GLFW_WAYLAND -#cgo linux,!x11,!wayland CFLAGS: -D_GLFW_X11 -D_GLFW_WAYLAND -#cgo linux,!es2,!es3,!wayland LDFLAGS: -lGL - -#cgo linux,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo linux,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo linux,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo linux,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo linux,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo linux,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 +#cgo linux,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11 +#cgo linux,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21 +#cgo linux,!opengl11,!opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_33 */ import "C" diff --git a/raylib/cgo_linux_drm.go b/raylib/cgo_linux_drm.go index 66d07e4..7c9a9f1 100644 --- a/raylib/cgo_linux_drm.go +++ b/raylib/cgo_linux_drm.go @@ -1,11 +1,9 @@ -//go:build linux && drm && !drm_leasing && !drm_disable_input && !rgfw && !sdl && !sdl3 && !android -// +build linux,drm,!drm_leasing,!drm_disable_input,!rgfw,!sdl,!sdl3,!android +// +build linux,drm,!rpi,!android package rl /* -#cgo pkg-config: libdrm gbm -#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl -#cgo linux,drm CFLAGS: -DSUPPORT_SSH_KEYBOARD_RPI -DPLATFORM_DRM -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 +#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl +#cgo linux,drm CFLAGS: -DPLATFORM_DRM -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 -I/usr/include/libdrm */ import "C" diff --git a/raylib/cgo_linux_drm_leasing.go b/raylib/cgo_linux_drm_leasing.go deleted file mode 100644 index b56afc0..0000000 --- a/raylib/cgo_linux_drm_leasing.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build linux && drm && drm_leasing && !drm_disable_input && !rgfw && !sdl && !sdl3 && !android -// +build linux,drm,drm_leasing,!drm_disable_input,!rgfw,!sdl,!sdl3,!android - -package rl - -/* -#cgo pkg-config: libdrm gbm wayland-client -#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl -#cgo linux,drm CFLAGS: -DSUPPORT_SSH_KEYBOARD_RPI -DPLATFORM_DRM -DENABLE_WAYLAND_DRM_LEASING -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 -*/ -import "C" diff --git a/raylib/cgo_linux_drm_leasing_no_keyboard.go b/raylib/cgo_linux_drm_leasing_no_keyboard.go deleted file mode 100644 index bd04a7f..0000000 --- a/raylib/cgo_linux_drm_leasing_no_keyboard.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build linux && drm && drm_leasing && drm_disable_input && !rgfw && !sdl && !sdl3 && !android -// +build linux,drm,drm_leasing,drm_disable_input,!rgfw,!sdl,!sdl3,!android - -package rl - -/* -#cgo pkg-config: libdrm gbm wayland-client -#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl -#cgo linux,drm CFLAGS: -DDISABLE_EVDEV_INPUT -DPLATFORM_DRM -DENABLE_WAYLAND_DRM_LEASING -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 -*/ -import "C" diff --git a/raylib/cgo_linux_drm_no_keyboard.go b/raylib/cgo_linux_drm_no_keyboard.go deleted file mode 100644 index 12c329d..0000000 --- a/raylib/cgo_linux_drm_no_keyboard.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build linux && drm && drm_disable_input && !drm_leasing && !rgfw && !sdl && !sdl3 && !android -// +build linux,drm,drm_disable_input,!drm_leasing,!rgfw,!sdl,!sdl3,!android - -package rl - -/* -#cgo pkg-config: libdrm gbm -#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl -#cgo linux,drm CFLAGS: -DDISABLE_EVDEV_INPUT -DPLATFORM_DRM -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 -*/ -import "C" diff --git a/raylib/cgo_linux_rgfw.go b/raylib/cgo_linux_rgfw.go deleted file mode 100644 index 7585836..0000000 --- a/raylib/cgo_linux_rgfw.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build linux && rgfw && !drm && !sdl && !sdl3 && !android -// +build linux,rgfw,!drm,!sdl,!sdl3,!android - -package rl - -/* -#cgo linux,!es2 LDFLAGS: -lm -#cgo linux CFLAGS: -DPLATFORM_DESKTOP_RGFW -Wno-builtin-declaration-mismatch -Wno-discarded-qualifiers -Wno-int-conversion -#cgo linux LDFLAGS: -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor -lm -lpthread -ldl -lrt - -#cgo linux,!es2,!es3 LDFLAGS: -lGL - -#cgo linux,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo linux,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo linux,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo linux,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo linux,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo linux,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_linux_rpi.go b/raylib/cgo_linux_rpi.go new file mode 100644 index 0000000..063f05a --- /dev/null +++ b/raylib/cgo_linux_rpi.go @@ -0,0 +1,9 @@ +// +build linux,rpi,!drm,!android + +package rl + +/* +#cgo linux,rpi LDFLAGS: -L/opt/vc/lib -L/opt/vc/lib64 -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -lvcos -lvchiq_arm -ldl +#cgo linux,rpi CFLAGS: -DPLATFORM_RPI -DGRAPHICS_API_OPENGL_ES2 -I/opt/vc/include -I/opt/vc/include/interface/vcos -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads +*/ +import "C" diff --git a/raylib/cgo_linux_sdl.go b/raylib/cgo_linux_sdl.go deleted file mode 100644 index cde87da..0000000 --- a/raylib/cgo_linux_sdl.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build linux && (sdl || sdl3) && !rgfw && !drm && !android -// +build linux -// +build sdl sdl3 -// +build !rgfw -// +build !drm -// +build !android - -package rl - -/* -#cgo linux,!es2 LDFLAGS: -lm -#cgo linux CFLAGS: -Wno-stringop-overflow -#cgo linux,sdl CFLAGS: -DPLATFORM_DESKTOP_SDL -#cgo linux,sdl3 CFLAGS: -DPLATFORM_DESKTOP_SDL -DPLATFORM_DESKTOP_SDL3 -#cgo linux,sdl pkg-config: sdl2 -#cgo linux,sdl3 pkg-config: sdl3 - -#cgo linux,!es2,!es3 LDFLAGS: -lGL - -#cgo linux,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo linux,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo linux,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo linux,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo linux,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo linux,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_openbsd.go b/raylib/cgo_openbsd.go deleted file mode 100644 index a40ee1c..0000000 --- a/raylib/cgo_openbsd.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build openbsd && !linux && !rgfw && !drm && !sdl && !sdl3 && !android -// +build openbsd,!linux,!rgfw,!drm,!sdl,!sdl3,!android - -package rl - -/* -#include "external/glfw/src/context.c" -#include "external/glfw/src/init.c" -#include "external/glfw/src/input.c" -#include "external/glfw/src/monitor.c" -#include "external/glfw/src/platform.c" -#include "external/glfw/src/vulkan.c" -#include "external/glfw/src/window.c" - -#include "external/glfw/src/x11_init.c" -#include "external/glfw/src/x11_monitor.c" -#include "external/glfw/src/x11_window.c" -#include "external/glfw/src/glx_context.c" - -#include "external/glfw/src/null_joystick.c" -#include "external/glfw/src/posix_module.c" -#include "external/glfw/src/posix_poll.c" -#include "external/glfw/src/posix_thread.c" -#include "external/glfw/src/posix_time.c" -#include "external/glfw/src/xkb_unicode.c" -#include "external/glfw/src/egl_context.c" -#include "external/glfw/src/osmesa_context.c" - -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { - return GLFW_TRUE; -} - -#cgo openbsd CFLAGS: -I. -I/usr/X11R6/include -Iexternal/glfw/include -DPLATFORM_DESKTOP -D_GLFW_X11 -#cgo openbsd LDFLAGS: -L/usr/X11R6/lib -lm -pthread -lX11 - -#cgo openbsd,!es2,!es3 LDFLAGS: -lGL - -#cgo openbsd,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo openbsd,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo openbsd,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo openbsd,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo openbsd,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo openbsd,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_openbsd_rgfw.go b/raylib/cgo_openbsd_rgfw.go deleted file mode 100644 index 11441dc..0000000 --- a/raylib/cgo_openbsd_rgfw.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build openbsd && rgfw && !linux && !sdl && !sdl3 && !drm && !android -// +build openbsd,rgfw,!linux,!sdl,!sdl3,!drm,!android - -package rl - -/* -#cgo openbsd CFLAGS: -I. -I/usr/X11R6/include -DPLATFORM_DESKTOP_RGFW -#cgo openbsd LDFLAGS: -L/usr/X11R6/lib -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor -lm -lpthread -ldl -lrt - -#cgo openbsd,!es2,!es3 LDFLAGS: -lGL - -#cgo openbsd,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo openbsd,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo openbsd,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo openbsd,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo openbsd,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo openbsd,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_openbsd_sdl.go b/raylib/cgo_openbsd_sdl.go deleted file mode 100644 index 4fe5e5a..0000000 --- a/raylib/cgo_openbsd_sdl.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build openbsd && !linux && (sdl || sdl3) && !rgfw && !drm && !android -// +build openbsd -// +build !linux -// +build sdl sdl3 -// +build !rgfw -// +build !drm -// +build !android - -package rl - -/* -#cgo openbsd CFLAGS: -I. -I/usr/X11R6/include -#cgo openbsd,sdl CFLAGS: -DPLATFORM_DESKTOP_SDL -#cgo openbsd,sdl3 CFLAGS: -DPLATFORM_DESKTOP_SDL -DPLATFORM_DESKTOP_SDL3 -#cgo openbsd LDFLAGS: -L/usr/X11R6/lib - -#cgo openbsd,sdl pkg-config: sdl2 -#cgo openbsd,sdl3 pkg-config: sdl3 - -#cgo openbsd,!es2,!es3 LDFLAGS: -lGL - -#cgo openbsd,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo openbsd,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo openbsd,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo openbsd,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo openbsd,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo openbsd,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_vendor.go b/raylib/cgo_vendor.go deleted file mode 100644 index 87308cb..0000000 --- a/raylib/cgo_vendor.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build required -// +build required - -package rl - -import ( - _ "git.terah.dev/UnrealXR/raylib-go/raylib/external" - _ "git.terah.dev/UnrealXR/raylib-go/raylib/external/android/native_app_glue" - _ "git.terah.dev/UnrealXR/raylib-go/raylib/external/glfw/include/GLFW" - _ "git.terah.dev/UnrealXR/raylib-go/raylib/external/glfw/src" - _ "git.terah.dev/UnrealXR/raylib-go/raylib/platforms" -) diff --git a/raylib/cgo_windows.go b/raylib/cgo_windows.go index c2cd044..08442d4 100644 --- a/raylib/cgo_windows.go +++ b/raylib/cgo_windows.go @@ -1,5 +1,4 @@ -//go:build windows && !rgfw && !sdl && !sdl3 -// +build windows,!rgfw,!sdl,!sdl3 +// +build windows package rl @@ -8,13 +7,11 @@ package rl #include "external/glfw/src/init.c" #include "external/glfw/src/input.c" #include "external/glfw/src/monitor.c" -#include "external/glfw/src/platform.c" #include "external/glfw/src/vulkan.c" #include "external/glfw/src/window.c" #include "external/glfw/src/win32_init.c" #include "external/glfw/src/win32_joystick.c" -#include "external/glfw/src/win32_module.c" #include "external/glfw/src/win32_monitor.c" #include "external/glfw/src/win32_thread.c" #include "external/glfw/src/win32_time.c" @@ -23,20 +20,11 @@ package rl #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { - return GLFW_TRUE; -} +#cgo windows LDFLAGS: -lopengl32 -lgdi32 -lwinmm -lole32 +#cgo windows CFLAGS: -D_GLFW_WIN32 -Iexternal -Iexternal/glfw/include -Iexternal/glfw/deps/mingw -DPLATFORM_DESKTOP -#cgo windows LDFLAGS: -lgdi32 -lwinmm -lole32 -#cgo windows CFLAGS: -Iexternal -Iexternal/glfw/include -DPLATFORM_DESKTOP -D_GLFW_WIN32 -Wno-stringop-overflow - -#cgo windows,!es2,!es3 LDFLAGS: -lopengl32 - -#cgo windows,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo windows,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo windows,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo windows,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo windows,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo windows,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 +#cgo windows,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11 +#cgo windows,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21 +#cgo windows,!opengl11,!opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_33 */ import "C" diff --git a/raylib/cgo_windows_rgfw.go b/raylib/cgo_windows_rgfw.go deleted file mode 100644 index eea463d..0000000 --- a/raylib/cgo_windows_rgfw.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build windows && rgfw && !sdl && !sdl3 -// +build windows,rgfw,!sdl,!sdl3 - -package rl - -/* -#cgo windows LDFLAGS: -lgdi32 -lwinmm -#cgo windows CFLAGS: -Iexternal -DPLATFORM_DESKTOP_RGFW -Wno-stringop-overflow -Wno-discarded-qualifiers - -#cgo windows,!es2,!es3 LDFLAGS: -lopengl32 - -#cgo windows,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo windows,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo windows,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo windows,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo windows,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo windows,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/cgo_windows_sdl.go b/raylib/cgo_windows_sdl.go deleted file mode 100644 index 58d53a4..0000000 --- a/raylib/cgo_windows_sdl.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build windows && (sdl || sdl3) && !rgfw -// +build windows -// +build sdl sdl3 -// +build !rgfw - -package rl - -/* -#cgo windows LDFLAGS: -lgdi32 -lwinmm -lole32 -#cgo windows,sdl LDFLAGS: -lSDL2 -#cgo windows,sdl3 LDFLAGS: -lSDL3 -#cgo windows CFLAGS: -Iexternal -Wno-stringop-overflow -#cgo windows,sdl CFLAGS: -DPLATFORM_DESKTOP_SDL -#cgo windows,sdl3 CFLAGS: -DPLATFORM_DESKTOP_SDL -DPLATFORM_DESKTOP_SDL3 - -#cgo windows,!es2,!es3 LDFLAGS: -lopengl32 - -#cgo windows,opengl11,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_11 -#cgo windows,opengl21,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_21 -#cgo windows,opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_43 -#cgo windows,!opengl11,!opengl21,!opengl43,!es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_33 -#cgo windows,es2,!es3 CFLAGS: -DGRAPHICS_API_OPENGL_ES2 -#cgo windows,es3,!es2 CFLAGS: -DGRAPHICS_API_OPENGL_ES3 -*/ -import "C" diff --git a/raylib/compat.go b/raylib/compat.go deleted file mode 100644 index 3cd0337..0000000 --- a/raylib/compat.go +++ /dev/null @@ -1,98 +0,0 @@ -//go:build go1.21 -// +build go1.21 - -package rl - -/* -#include "raylib.h" -#include -*/ -import "C" - -import ( - "runtime" - "slices" -) - -// List of VaoIDs of meshes created by calling UploadMesh() -// Used by UnloadMesh() to determine if mesh is go-managed or C-allocated -var goManagedMeshIDs = make([]uint32, 0) - -// UploadMesh - Upload vertex data into a VAO (if supported) and VBO -func UploadMesh(mesh *Mesh, dynamic bool) { - // check if mesh has already been uploaded to prevent duplication - if mesh.VaoID != 0 { - TraceLog(LogWarning, "VAO: [ID %d] Trying to re-load an already loaded mesh", mesh.VaoID) - return - } - - pinner := runtime.Pinner{} - // Mesh pointer fields must be pinned to allow a Mesh pointer to be passed to C.UploadMesh() below - // nil checks are required because Pin() will panic if passed nil - if mesh.Vertices != nil { - pinner.Pin(mesh.Vertices) - } - if mesh.Texcoords != nil { - pinner.Pin(mesh.Texcoords) - } - if mesh.Texcoords2 != nil { - pinner.Pin(mesh.Texcoords2) - } - if mesh.Normals != nil { - pinner.Pin(mesh.Normals) - } - if mesh.Tangents != nil { - pinner.Pin(mesh.Tangents) - } - if mesh.Colors != nil { - pinner.Pin(mesh.Colors) - } - if mesh.Indices != nil { - pinner.Pin(mesh.Indices) - } - if mesh.AnimVertices != nil { - pinner.Pin(mesh.AnimVertices) - } - if mesh.AnimNormals != nil { - pinner.Pin(mesh.AnimNormals) - } - if mesh.BoneIds != nil { - pinner.Pin(mesh.BoneIds) - } - if mesh.BoneWeights != nil { - pinner.Pin(mesh.BoneWeights) - } - // VboID of a new mesh should always be nil before uploading, but including this in case a mesh happens to have it set. - if mesh.VboID != nil { - pinner.Pin(mesh.VboID) - } - - cMesh := mesh.cptr() - C.UploadMesh(cMesh, C.bool(dynamic)) - - // Add new mesh VaoID to list - goManagedMeshIDs = append(goManagedMeshIDs, mesh.VaoID) - - pinner.Unpin() -} - -// UnloadMesh - Unload mesh from memory (RAM and/or VRAM) -func UnloadMesh(mesh *Mesh) { - // Check list of go-managed mesh IDs - if slices.Contains(goManagedMeshIDs, mesh.VaoID) { - // C.UnloadMesh() only needs to read the VaoID & VboID - // passing a temporary struct with all other fields nil makes it safe for the C code to call free() - tempMesh := Mesh{ - VaoID: mesh.VaoID, - VboID: mesh.VboID, - } - cmesh := tempMesh.cptr() - C.UnloadMesh(*cmesh) - - // remove mesh VaoID from list - goManagedMeshIDs = slices.DeleteFunc(goManagedMeshIDs, func(id uint32) bool { return id == mesh.VaoID }) - } else { - cmesh := mesh.cptr() - C.UnloadMesh(*cmesh) - } -} diff --git a/raylib/compat_compat.go b/raylib/compat_compat.go deleted file mode 100644 index 1c362fb..0000000 --- a/raylib/compat_compat.go +++ /dev/null @@ -1,69 +0,0 @@ -//go:build !go1.21 -// +build !go1.21 - -package rl - -/* -#include "raylib.h" -#include -*/ -import "C" - -import ( - "runtime" - - "golang.org/x/exp/slices" -) - -// List of VaoIDs of meshes created by calling UploadMesh() -// Used by UnloadMesh() to determine if mesh is go-managed or C-allocated -var goManagedMeshIDs = make([]uint32, 0) - -// UploadMesh - Upload vertex data into a VAO (if supported) and VBO -func UploadMesh(mesh *Mesh, dynamic bool) { - // check if mesh has already been uploaded to prevent duplication - if mesh.VaoID != 0 { - TraceLog(LogWarning, "VAO: [ID %d] Trying to re-load an already loaded mesh", mesh.VaoID) - return - } - - defer runtime.KeepAlive(mesh.Vertices) - defer runtime.KeepAlive(mesh.Texcoords) - defer runtime.KeepAlive(mesh.Texcoords2) - defer runtime.KeepAlive(mesh.Normals) - defer runtime.KeepAlive(mesh.Tangents) - defer runtime.KeepAlive(mesh.Colors) - defer runtime.KeepAlive(mesh.Indices) - defer runtime.KeepAlive(mesh.AnimVertices) - defer runtime.KeepAlive(mesh.AnimNormals) - defer runtime.KeepAlive(mesh.BoneIds) - defer runtime.KeepAlive(mesh.BoneWeights) - defer runtime.KeepAlive(mesh.VboID) - - cMesh := mesh.cptr() - C.UploadMesh(cMesh, C.bool(dynamic)) - - // Add new mesh VaoID to list - goManagedMeshIDs = append(goManagedMeshIDs, mesh.VaoID) -} - -// UnloadMesh - Unload mesh from memory (RAM and/or VRAM) -func UnloadMesh(mesh *Mesh) { - // Check list of go-managed mesh IDs - if slices.Contains(goManagedMeshIDs, mesh.VaoID) { - // C.UnloadMesh() only needs to read the VaoID & VboID - // passing a temporary struct with all other fields nil makes it safe for the C code to call free() - tempMesh := Mesh{ - VaoID: mesh.VaoID, - VboID: mesh.VboID, - } - cmesh := tempMesh.cptr() - C.UnloadMesh(*cmesh) - - // remove mesh VaoID from list - goManagedMeshIDs = slices.DeleteFunc(goManagedMeshIDs, func(id uint32) bool { return id == mesh.VaoID }) - } else { - cmesh := mesh.cptr() - C.UnloadMesh(*cmesh) - } -} diff --git a/raylib/config.h b/raylib/config.h index c0d50cd..6cec344 100644 --- a/raylib/config.h +++ b/raylib/config.h @@ -6,7 +6,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2018-2025 Ahmad Fatoum & Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2021 Ahmad Fatoum & Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -25,259 +25,169 @@ * **********************************************************************************************/ -#ifndef CONFIG_H -#define CONFIG_H - //------------------------------------------------------------------------------------ -// Module selection - Some modules could be avoided -// Mandatory modules: rcore, rlgl, utils +// Module: core - Configuration Flags //------------------------------------------------------------------------------------ -#define SUPPORT_MODULE_RSHAPES 1 -#define SUPPORT_MODULE_RTEXTURES 1 -#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures -#define SUPPORT_MODULE_RMODELS 1 -#define SUPPORT_MODULE_RAUDIO 1 - -//------------------------------------------------------------------------------------ -// Module: rcore - Configuration Flags -//------------------------------------------------------------------------------------ -// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital -#define SUPPORT_CAMERA_SYSTEM 1 -// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag -#define SUPPORT_GESTURES_SYSTEM 1 -// Include pseudo-random numbers generator (rprand.h), based on Xoshiro128** and SplitMix64 -#define SUPPORT_RPRAND_GENERATOR 1 +// Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital +#define SUPPORT_CAMERA_SYSTEM 1 +// Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag +#define SUPPORT_GESTURES_SYSTEM 1 // Mouse gestures are directly mapped like touches and processed by gestures system -#define SUPPORT_MOUSE_GESTURES 1 +#define SUPPORT_MOUSE_GESTURES 1 // Reconfigure standard input to receive key inputs, works with SSH connection. -//#define SUPPORT_SSH_KEYBOARD_RPI 1 +#define SUPPORT_SSH_KEYBOARD_RPI 1 +// Draw a mouse pointer on screen +#define SUPPORT_MOUSE_CURSOR_NATIVE 1 // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. -#define SUPPORT_WINMM_HIGHRES_TIMER 1 -// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used -//#define SUPPORT_BUSY_WAIT_LOOP 1 +#define SUPPORT_WINMM_HIGHRES_TIMER 1 +// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used +//#define SUPPORT_BUSY_WAIT_LOOP 1 // Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy -#define SUPPORT_PARTIALBUSY_WAIT_LOOP 1 +#define SUPPORT_PARTIALBUSY_WAIT_LOOP +// Wait for events passively (sleeping while no events) instead of polling them actively every frame +//#define SUPPORT_EVENTS_WAITING 1 // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() -#define SUPPORT_SCREEN_CAPTURE 1 +#define SUPPORT_SCREEN_CAPTURE 1 // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() -#define SUPPORT_GIF_RECORDING 1 +#define SUPPORT_GIF_RECORDING 1 // Support CompressData() and DecompressData() functions -#define SUPPORT_COMPRESSION_API 1 -// Support automatic generated events, loading and recording of those events when required -#define SUPPORT_AUTOMATION_EVENTS 1 -// Support custom frame control, only for advanced users -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() -// Enabling this flag allows manual control of the frame processes, use at your own risk -//#define SUPPORT_CUSTOM_FRAME_CONTROL 1 +#define SUPPORT_COMPRESSION_API 1 +// Support saving binary data automatically to a generated storage.data file. This file is managed internally. +#define SUPPORT_DATA_STORAGE 1 -// Support for clipboard image loading -// NOTE: Only working on SDL3, GLFW (Windows) and RGFW (Windows) -#define SUPPORT_CLIPBOARD_IMAGE 1 - -// NOTE: Clipboard image loading requires support for some image file formats -// TODO: Those defines should probably be removed from here, I prefer to let the user manage them -#if defined(SUPPORT_CLIPBOARD_IMAGE) - #ifndef SUPPORT_MODULE_RTEXTURES - #define SUPPORT_MODULE_RTEXTURES 1 - #endif - #ifndef STBI_REQUIRED - #define STBI_REQUIRED - #endif - #ifndef SUPPORT_FILEFORMAT_BMP // For clipboard image on Windows - #define SUPPORT_FILEFORMAT_BMP 1 - #endif - #ifndef SUPPORT_FILEFORMAT_PNG // Wayland uses png for prints, at least it was on 22 LTS ubuntu - #define SUPPORT_FILEFORMAT_PNG 1 - #endif - #ifndef SUPPORT_FILEFORMAT_JPG - #define SUPPORT_FILEFORMAT_JPG 1 - #endif +// core: Configuration values +//------------------------------------------------------------------------------------ +#if defined(__linux__) + #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) +#else + #define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths #endif +#define MAX_GAMEPADS 4 // Max number of gamepads supported +#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) +#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) +#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported +#define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue -// rcore: Configuration values -//------------------------------------------------------------------------------------ -#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity -#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) +#define STORAGE_DATA_FILE "storage.data" // Automatic storage filename -#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported -#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported -#define MAX_GAMEPADS 4 // Maximum number of gamepads supported -#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad) -#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) -#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds -#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported -#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue -#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue +#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB -#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB - -#define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record //------------------------------------------------------------------------------------ // Module: rlgl - Configuration values //------------------------------------------------------------------------------------ - -// Enable OpenGL Debug Context (only available on OpenGL 4.3) -//#define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT 1 - // Show OpenGL extensions and capabilities detailed logs on init -//#define RLGL_SHOW_GL_DETAILS_INFO 1 +//#define SUPPORT_GL_DETAILS_INFO 1 -#define RL_SUPPORT_MESH_GPU_SKINNING 1 // GPU skinning, comment if your GPU does not support more than 8 VBOs - -//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // Default internal render batch elements limits -#define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) -#define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) -#define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture()) - -#define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack - -#define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported - -#define RL_CULL_DISTANCE_NEAR 0.001 // Default projection matrix near cull distance -#define RL_CULL_DISTANCE_FAR 10000.0 // Default projection matrix far cull distance - -// Default shader vertex attribute locations -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 -#if defined(RL_SUPPORT_MESH_GPU_SKINNING) - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + #define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch limits +#elif defined(GRAPHICS_API_OPENGL_ES2) + #define DEFAULT_BATCH_BUFFER_ELEMENTS 2048 // Default internal render batch limits #endif -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9 +#define DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) +#define DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) + +#define MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack +#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh +#define MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported +#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported + +#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance +#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance // Default shader vertex attribute names to set location points -// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience -#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD -#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL -#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 - -#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix -#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix -#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix -#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix -#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)) -#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) -#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) -#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) -#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) +#define DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 +#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 +#define DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 +#define DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 +#define DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 +#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 //------------------------------------------------------------------------------------ -// Module: rshapes - Configuration Flags +// Module: shapes - Configuration Flags //------------------------------------------------------------------------------------ // Use QUADS instead of TRIANGLES for drawing when possible // Some lines-based shapes could still use lines -#define SUPPORT_QUADS_DRAW_MODE 1 - -// rshapes: Configuration values -//------------------------------------------------------------------------------------ -#define SPLINE_SEGMENT_DIVISIONS 24 // Spline segments subdivisions +#define SUPPORT_QUADS_DRAW_MODE 1 //------------------------------------------------------------------------------------ -// Module: rtextures - Configuration Flags +// Module: textures - Configuration Flags //------------------------------------------------------------------------------------ // Selecte desired fileformats to be supported for image data loading #define SUPPORT_FILEFORMAT_PNG 1 -#define SUPPORT_FILEFORMAT_BMP 1 +//#define SUPPORT_FILEFORMAT_BMP 1 //#define SUPPORT_FILEFORMAT_TGA 1 -#define SUPPORT_FILEFORMAT_JPG 1 +//#define SUPPORT_FILEFORMAT_JPG 1 #define SUPPORT_FILEFORMAT_GIF 1 -#define SUPPORT_FILEFORMAT_QOI 1 //#define SUPPORT_FILEFORMAT_PSD 1 #define SUPPORT_FILEFORMAT_DDS 1 -//#define SUPPORT_FILEFORMAT_HDR 1 -//#define SUPPORT_FILEFORMAT_PIC 1 +#define SUPPORT_FILEFORMAT_HDR 1 //#define SUPPORT_FILEFORMAT_KTX 1 //#define SUPPORT_FILEFORMAT_ASTC 1 //#define SUPPORT_FILEFORMAT_PKM 1 //#define SUPPORT_FILEFORMAT_PVR 1 -// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) -#define SUPPORT_IMAGE_EXPORT 1 +// Support image export functionality (.png, .bmp, .tga, .jpg) +#define SUPPORT_IMAGE_EXPORT 1 // Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) -#define SUPPORT_IMAGE_GENERATION 1 +#define SUPPORT_IMAGE_GENERATION 1 // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... // If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT() -#define SUPPORT_IMAGE_MANIPULATION 1 +#define SUPPORT_IMAGE_MANIPULATION 1 //------------------------------------------------------------------------------------ -// Module: rtext - Configuration Flags +// Module: text - Configuration Flags //------------------------------------------------------------------------------------ // Default font is loaded on window initialization to be available for the user to render simple text // NOTE: If enabled, uses external module functions to load default raylib font -#define SUPPORT_DEFAULT_FONT 1 +#define SUPPORT_DEFAULT_FONT 1 // Selected desired font fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_TTF 1 -#define SUPPORT_FILEFORMAT_FNT 1 -#define SUPPORT_FILEFORMAT_BDF 1 +#define SUPPORT_FILEFORMAT_FNT 1 +#define SUPPORT_FILEFORMAT_TTF 1 // Support text management functions // If not defined, still some functions are supported: TextLength(), TextFormat() -#define SUPPORT_TEXT_MANIPULATION 1 +#define SUPPORT_TEXT_MANIPULATION 1 -// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle -// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow -// drawing text and shapes with a single draw call [SetShapesTexture()]. -#define SUPPORT_FONT_ATLAS_WHITE_REC 1 - -// rtext: Configuration values +// text: Configuration values //------------------------------------------------------------------------------------ -#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: +#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() -#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() +#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints() +#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() //------------------------------------------------------------------------------------ -// Module: rmodels - Configuration Flags +// Module: models - Configuration Flags //------------------------------------------------------------------------------------ // Selected desired model fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_OBJ 1 -#define SUPPORT_FILEFORMAT_MTL 1 -#define SUPPORT_FILEFORMAT_IQM 1 -#define SUPPORT_FILEFORMAT_GLTF 1 -#define SUPPORT_FILEFORMAT_VOX 1 -#define SUPPORT_FILEFORMAT_M3D 1 +#define SUPPORT_FILEFORMAT_OBJ 1 +#define SUPPORT_FILEFORMAT_MTL 1 +#define SUPPORT_FILEFORMAT_IQM 1 +#define SUPPORT_FILEFORMAT_GLTF 1 // Support procedural mesh generation functions, uses external par_shapes.h library // NOTE: Some generated meshes DO NOT include generated texture coordinates -#define SUPPORT_MESH_GENERATION 1 +#define SUPPORT_MESH_GENERATION 1 -// rmodels: Configuration values -//------------------------------------------------------------------------------------ -#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING -#define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh -#else -#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh -#endif //------------------------------------------------------------------------------------ -// Module: raudio - Configuration Flags +// Module: audio - Configuration Flags //------------------------------------------------------------------------------------ // Desired audio fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_WAV 1 -#define SUPPORT_FILEFORMAT_OGG 1 -#define SUPPORT_FILEFORMAT_MP3 1 -#define SUPPORT_FILEFORMAT_QOA 1 -//#define SUPPORT_FILEFORMAT_FLAC 1 -#define SUPPORT_FILEFORMAT_XM 1 -#define SUPPORT_FILEFORMAT_MOD 1 +#define SUPPORT_FILEFORMAT_WAV 1 +#define SUPPORT_FILEFORMAT_OGG 1 +#define SUPPORT_FILEFORMAT_XM 1 +#define SUPPORT_FILEFORMAT_MOD 1 +#define SUPPORT_FILEFORMAT_MP3 1 +//#define SUPPORT_FILEFORMAT_FLAC 1 -// raudio: Configuration values +// audio: Configuration values //------------------------------------------------------------------------------------ #define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit) #define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo @@ -289,14 +199,13 @@ // Module: utils - Configuration Flags //------------------------------------------------------------------------------------ // Standard file io library (stdio.h) included -#define SUPPORT_STANDARD_FILEIO 1 +#define SUPPORT_STANDARD_FILEIO // Show TRACELOG() output messages // NOTE: By default LOG_DEBUG traces not shown -#define SUPPORT_TRACELOG 1 -//#define SUPPORT_TRACELOG_DEBUG 1 +#define SUPPORT_TRACELOG 1 +//#define SUPPORT_TRACELOG_DEBUG 1 // utils: Configuration values //------------------------------------------------------------------------------------ -#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message - -#endif // CONFIG_H +#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message +#define MAX_UWP_MESSAGES 512 // Max UWP messages to process diff --git a/raylib/core.c b/raylib/core.c new file mode 100644 index 0000000..4021cdd --- /dev/null +++ b/raylib/core.c @@ -0,0 +1,6622 @@ +/********************************************************************************************** +* +* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms +* +* PLATFORMS SUPPORTED: +* - PLATFORM_DESKTOP: Windows (Win32, Win64) +* - PLATFORM_DESKTOP: Linux (X11 desktop mode) +* - PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop) +* - PLATFORM_DESKTOP: OSX/macOS +* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64) +* - PLATFORM_RPI: Raspberry Pi 0,1,2,3,4 (Raspbian) +* - PLATFORM_DRM: Linux native mode, including Raspberry Pi 4 with V3D fkms driver +* - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox) +* - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One +* +* CONFIGURATION: +* +* #define PLATFORM_DESKTOP +* Windowing and input system configured for desktop platforms: Windows, Linux, OSX, FreeBSD, OpenBSD, NetBSD, DragonFly +* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for mirror rendering - View [rlgl] module to enable it +* +* #define PLATFORM_ANDROID +* Windowing and input system configured for Android device, app activity managed internally in this module. +* NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL +* +* #define PLATFORM_RPI +* Windowing and input system configured for Raspberry Pi i native mode (no X.org required, tested on Raspbian), +* graphic device is managed by EGL and inputs are processed is raw mode, reading from /dev/input/ +* +* #define PLATFORM_WEB +* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js +* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code. +* +* #define PLATFORM_UWP +* Universal Windows Platform support, using OpenGL ES 2.0 through ANGLE on multiple Windows platforms, +* including Windows 10 App, Windows Phone and Xbox One platforms. +* +* #define SUPPORT_DEFAULT_FONT (default) +* Default font is loaded on window initialization to be available for the user to render simple text. +* NOTE: If enabled, uses external module functions to load default raylib font (module: text) +* +* #define SUPPORT_CAMERA_SYSTEM +* Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital +* +* #define SUPPORT_GESTURES_SYSTEM +* Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag +* +* #define SUPPORT_MOUSE_GESTURES +* Mouse gestures are directly mapped like touches and processed by gestures system. +* +* #define SUPPORT_TOUCH_AS_MOUSE +* Touch input and mouse input are shared. Mouse functions also return touch information. +* +* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only) +* Reconfigure standard input to receive key inputs, works with SSH connection. +* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or +* blocking the device is not restored properly. Use with care. +* +* #define SUPPORT_MOUSE_CURSOR_NATIVE (Raspberry Pi and DRM only) +* Draw a mouse pointer on screen +* +* #define SUPPORT_BUSY_WAIT_LOOP +* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used +* +* #define SUPPORT_PARTIALBUSY_WAIT_LOOP +* Use a partial-busy wait loop, in this case frame sleeps for most of the time and runs a busy-wait-loop at the end +* +* #define SUPPORT_EVENTS_WAITING +* Wait for events passively (sleeping while no events) instead of polling them actively every frame +* +* #define SUPPORT_SCREEN_CAPTURE +* Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() +* +* #define SUPPORT_GIF_RECORDING +* Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() +* +* #define SUPPORT_COMPRESSION_API +* Support CompressData() and DecompressData() functions, those functions use zlib implementation +* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module +* for linkage +* +* #define SUPPORT_DATA_STORAGE +* Support saving binary data automatically to a generated storage.data file. This file is managed internally +* +* +* DEPENDENCIES: +* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly) +* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion) +* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) +* gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" // Declares module functions + +// Check if config flags have been externally provided on compilation line +#if !defined(EXTERNAL_CONFIG_FLAGS) + #include "config.h" // Defines module configuration flags +#endif + +#include "utils.h" // Required for: TRACELOG macros + +#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. +#endif + +#define RAYMATH_IMPLEMENTATION // Define external out-of-line implementation of raymath here +#include "raymath.h" // Required for: Vector3 and Matrix functions + +#define RLGL_IMPLEMENTATION +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 + +#if defined(SUPPORT_GESTURES_SYSTEM) + #define GESTURES_IMPLEMENTATION + #include "gestures.h" // Gestures detection functionality +#endif + +#if defined(SUPPORT_CAMERA_SYSTEM) + #define CAMERA_IMPLEMENTATION + #include "camera.h" // Camera system functionality +#endif + +#if defined(SUPPORT_GIF_RECORDING) + //#define MSF_GIF_MALLOC RL_MALLOC + //#define MSF_GIF_FREE RL_FREE + + #define MSF_GIF_IMPL + #include "external/msf_gif.h" // Support GIF recording +#endif + +#if defined(SUPPORT_COMPRESSION_API) + #define SINFL_IMPLEMENTATION + #include "external/sinfl.h" + + #define SDEFL_IMPLEMENTATION + #include "external/sdefl.h" +#endif + +#include // Required for: srand(), rand(), atexit() +#include // Required for: sprintf() [Used in OpenURL()] +#include // Required for: strrchr(), strcmp(), strlen() +#include // Required for: time() [Used in InitTimer()] +#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] + +#include // Required for: stat() [Used in GetFileModTime()] + +#if (defined(PLATFORM_DESKTOP) || defined(PLATFORM_UWP)) && defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) + #define DIRENT_MALLOC RL_MALLOC + #define DIRENT_FREE RL_FREE + + #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] +#else + #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] +#endif + +#if defined(_WIN32) + #include // Required for: _getch(), _chdir() + #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() + #define CHDIR _chdir + #include // Required for _access() [Used in FileExists()] +#else + #include // Required for: getch(), chdir() (POSIX), access() + #define GETCWD getcwd + #define CHDIR chdir +#endif + +#if defined(PLATFORM_DESKTOP) + #define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 + // NOTE: Already provided by rlgl implementation (on glad.h) + #include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management + // NOTE: GLFW3 already includes gl.h (OpenGL) headers + + // Support retrieving native window handlers + #if defined(_WIN32) + #define GLFW_EXPOSE_NATIVE_WIN32 + #include "GLFW/glfw3native.h" // WARNING: It requires customization to avoid windows.h inclusion! + + #if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) + // NOTE: Those functions require linking with winmm library + unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); + unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); + #endif + #endif + #if defined(__linux__) || defined(__FreeBSD__) + #include // Required for: timespec, nanosleep(), select() - POSIX + + //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type + //#define GLFW_EXPOSE_NATIVE_WAYLAND + //#define GLFW_EXPOSE_NATIVE_MIR + #include "GLFW/glfw3native.h" // Required for: glfwGetX11Window() + #endif + #if defined(__APPLE__) + #include // Required for: usleep() + + //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition + #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow() + #endif +#endif + +#if defined(PLATFORM_ANDROID) + //#include // Android sensors functions (accelerometer, gyroscope, light...) + #include // Defines AWINDOW_FLAG_FULLSCREEN and others + #include // Defines basic app state struct and manages activity + + #include // Native platform windowing system interface + //#include // OpenGL ES 2.0 library (not required in this module) +#endif + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + #include // POSIX file control definitions - open(), creat(), fcntl() + #include // POSIX standard function definitions - read(), close(), STDIN_FILENO + #include // POSIX terminal control definitions - tcgetattr(), tcsetattr() + #include // POSIX threads management (inputs reading) + #include // POSIX directory browsing + + #include // UNIX System call for device-specific input/output operations - ioctl() + #include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition + #include // Linux: Keycodes constants definition (KEY_A, ...) + #include // Linux: Joystick support library + +#if defined(PLATFORM_RPI) + #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions +#endif + +#if defined(PLATFORM_DRM) + #include // Generic Buffer Management + #include // Direct Rendering Manager user-level library interface + #include // Direct Rendering Manager modesetting interface +#endif + + #include "EGL/egl.h" // Native platform windowing system interface + #include "EGL/eglext.h" // EGL extensions + //#include "GLES2/gl2.h" // OpenGL ES 2.0 library (not required in this module) +#endif + +#if defined(PLATFORM_UWP) + #include "EGL/egl.h" // Native platform windowing system interface + #include "EGL/eglext.h" // EGL extensions + //#include "GLES2/gl2.h" // OpenGL ES 2.0 library (not required in this module) + #include "uwp_events.h" // UWP bootstrapping functions +#endif + +#if defined(PLATFORM_WEB) + #define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL) + #include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management + #include // Required for: timespec, nanosleep(), select() - POSIX + + #include // Emscripten library - LLVM to JavaScript compiler + #include // Emscripten HTML5 library +#endif + +#if defined(SUPPORT_COMPRESSION_API) + // NOTE: Those declarations require stb_image and stb_image_write definitions, included in textures module + unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality); + char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen); +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + #define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event number + + #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) + #define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events +#endif + +#ifndef MAX_FILEPATH_LENGTH + #if defined(__linux__) + #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) + #else + #define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths + #endif +#endif + +#ifndef MAX_GAMEPADS + #define MAX_GAMEPADS 4 // Max number of gamepads supported +#endif +#ifndef MAX_GAMEPAD_AXIS + #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) +#endif +#ifndef MAX_GAMEPAD_BUTTONS + #define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) +#endif +#ifndef MAX_TOUCH_POINTS + #define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported +#endif +#ifndef MAX_KEY_PRESSED_QUEUE + #define MAX_KEY_PRESSED_QUEUE 16 // Max number of keys in the key input queue +#endif +#ifndef MAX_CHAR_PRESSED_QUEUE + #define MAX_CHAR_PRESSED_QUEUE 16 // Max number of characters in the char input queue +#endif + +#if defined(SUPPORT_DATA_STORAGE) + #ifndef STORAGE_DATA_FILE + #define STORAGE_DATA_FILE "storage.data" // Automatic storage filename + #endif +#endif + +#ifndef MAX_DECOMPRESSION_SIZE + #define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB +#endif + +// Flags operation macros +#define FLAG_SET(n, f) ((n) |= (f)) +#define FLAG_CLEAR(n, f) ((n) &= ~(f)) +#define FLAG_TOGGLE(n, f) ((n) ^= (f)) +#define FLAG_CHECK(n, f) ((n) & (f)) + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) +typedef struct { + pthread_t threadId; // Event reading thread id + int fd; // File descriptor to the device it is assigned to + int eventNum; // Number of 'event' device + Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) + int touchSlot; // Hold the touch slot number of the currently being sent multitouch block + bool isMouse; // True if device supports relative X Y movements + bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH + bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH + bool isKeyboard; // True if device has letter keycodes + bool isGamepad; // True if device has gamepad buttons +} InputEventWorker; +#endif + +typedef struct { int x; int y; } Point; +typedef struct { unsigned int width; unsigned int height; } Size; + +// Core global state context data +typedef struct CoreData { + struct { +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + GLFWwindow *handle; // Native window handle (graphic device) +#endif +#if defined(PLATFORM_RPI) + EGL_DISPMANX_WINDOW_T handle; // Native window handle (graphic device) +#endif +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) +#if defined(PLATFORM_DRM) + int fd; // /dev/dri/... file descriptor + drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector + int modeIndex; // index of the used mode of connector->modes + drmModeCrtc *crtc; // crt controller + struct gbm_device *gbmDevice; // device of Generic Buffer Management (GBM, native platform for EGL on DRM) + struct gbm_surface *gbmSurface; // surface of GBM + struct gbm_bo *prevBO; // previous used GBM buffer object (during frame swapping) + uint32_t prevFB; // previous used GBM framebufer (during frame swapping) +#endif + EGLDisplay device; // Native display device (physical screen connection) + EGLSurface surface; // Surface to draw on, framebuffers (connected to context) + EGLContext context; // Graphic context, mode in which drawing can be done + EGLConfig config; // Graphic config +#endif + const char *title; // Window text title const pointer + unsigned int flags; // Configuration flags (bit based), keeps window state + bool ready; // Check if window has been initialized successfully + bool fullscreen; // Check if fullscreen mode is enabled + bool shouldClose; // Check if window set for closing + bool resizedLastFrame; // Check if window has been resized last frame + + Point position; // Window position on screen (required on fullscreen toggle) + Size display; // Display width and height (monitor, device-screen, LCD, ...) + Size screen; // Screen width and height (used render area) + Size currentFbo; // Current render width and height, it could change on BeginTextureMode() + Size render; // Framebuffer width and height (render area, including black bars if required) + Point renderOffset; // Offset from render area (must be divided by 2) + Matrix screenScale; // Matrix to scale screen (framebuffer rendering) + + char **dropFilesPath; // Store dropped files paths as strings + int dropFilesCount; // Count dropped files strings + + } Window; +#if defined(PLATFORM_ANDROID) + struct { + bool appEnabled; // Flag to detect if app is active ** = true + struct android_app *app; // Android activity + struct android_poll_source *source; // Android events polling source + const char *internalDataPath; // Android internal data path to write data (/data/data//files) + bool contextRebindRequired; // Used to know context rebind required + } Android; +#endif +#if defined(PLATFORM_UWP) + struct { + const char *internalDataPath; // UWP App data path + } UWP; +#endif + struct { +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event" +#endif + struct { + int exitKey; // Default exit key + char currentKeyState[512]; // Registers current frame key state + char previousKeyState[512]; // Registers previous frame key state + + int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue + int keyPressedQueueCount; // Input keys queue count + + int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue + int charPressedQueueCount; // Input characters queue count + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + int defaultMode; // Default keyboard mode + struct termios defaultSettings; // Default keyboard settings + int fd; // File descriptor for the evdev keyboard +#endif + } Keyboard; + struct { + Vector2 position; // Mouse position on screen + Vector2 offset; // Mouse offset + Vector2 scale; // Mouse scaling + + int cursor; // Tracks current mouse cursor + bool cursorHidden; // Track if cursor is hidden + bool cursorOnScreen; // Tracks if cursor is inside client area + + char currentButtonState[MOUSE_BUTTON_MAX]; // Registers current mouse button state + char previousButtonState[MOUSE_BUTTON_MAX]; // Registers previous mouse button state + float currentWheelMove; // Registers current mouse wheel variation + float previousWheelMove; // Registers previous mouse wheel variation +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + char currentButtonStateEvdev[MOUSE_BUTTON_MAX]; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update) +#endif + } Mouse; + struct { + Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen + char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state + char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state + } Touch; + struct { + int lastButtonPressed; // Register last gamepad button pressed + int axisCount; // Register number of available gamepad axis + bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready + float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state + char currentState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state + char previousState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + pthread_t threadId; // Gamepad reading thread id + int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor + char name[64]; // Gamepad name holder +#endif + } Gamepad; + } Input; + struct { + double current; // Current time measure + double previous; // Previous time measure + double update; // Time measure for frame update + double draw; // Time measure for frame draw + double frame; // Time measure for one frame + double target; // Desired time for one frame, if 0 not applied +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) + unsigned long long base; // Base time measure for hi-res timer +#endif + } Time; +} CoreData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static CoreData CORE = { 0 }; // Global CORE state context + +static char **dirFilesPath = NULL; // Store directory files paths as strings +static int dirFilesCount = 0; // Count directory files strings + +#if defined(SUPPORT_SCREEN_CAPTURE) +static int screenshotCounter = 0; // Screenshots counter +#endif + +#if defined(SUPPORT_GIF_RECORDING) +static int gifFramesCounter = 0; // GIF frames counter +static bool gifRecording = false; // GIF recording state +static MsfGifState gifState = { 0 }; // MSGIF context state +#endif +//----------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------- +// Other Modules Functions Declaration (required by core) +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_DEFAULT_FONT) +extern void LoadFontDefault(void); // [Module: text] Loads default font on InitWindow() +extern void UnloadFontDefault(void); // [Module: text] Unloads default font from GPU memory +#endif + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +static bool InitGraphicsDevice(int width, int height); // Initialize graphics device +static void SetupFramebuffer(int width, int height); // Setup main framebuffer +static void SetupViewport(int width, int height); // Set viewport for a provided width and height +static void SwapBuffers(void); // Copy back buffer to front buffer + +static void InitTimer(void); // Initialize timer +static void Wait(float ms); // Wait for some milliseconds (stop program execution) + +static void PollInputEvents(void); // Register user events + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) +static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error +// Window callbacks events +static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized +#if !defined(PLATFORM_WEB) +static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized +#endif +static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored +static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window +// Input callbacks events +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed +static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value) +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move +static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel +static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area +#endif + +#if defined(PLATFORM_ANDROID) +static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands +static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs +#endif + +#if defined(PLATFORM_WEB) +static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); +static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData); +#endif + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) +#if defined(SUPPORT_SSH_KEYBOARD_RPI) +static void InitKeyboard(void); // Init raw keyboard system (standard input reading) +static void ProcessKeyboard(void); // Process keyboard events +static void RestoreKeyboard(void); // Restore keyboard system +#else +static void InitTerminal(void); // Init terminal (block echo and signal short cuts) +static void RestoreTerminal(void); // Restore terminal +#endif + +static void InitEvdevInput(void); // Evdev inputs initialization +static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate +static void PollKeyboardEvents(void); // Process evdev keyboard events. +static void *EventThread(void *arg); // Input device events reading thread + +static void InitGamepad(void); // Init raw gamepad input +static void *GamepadThread(void *arg); // Mouse reading thread + +#if defined(PLATFORM_DRM) +typedef unsigned int uint; +static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list +static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list +static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list +#endif + +#endif // PLATFORM_RPI || PLATFORM_DRM + +#if defined(_WIN32) + // NOTE: We include Sleep() function signature here to avoid windows.h inclusion (kernel32 lib) + void __stdcall Sleep(unsigned long msTimeout); // Required for Wait() +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Window and OpenGL Context Functions +//---------------------------------------------------------------------------------- + +#if defined(PLATFORM_ANDROID) +// To allow easier porting to android, we allow the user to define a +// main function which we call from android_main, defined by ourselves +//extern int main(int argc, char *argv[]); +extern void android_run(); + +void android_main(struct android_app *app) +{ + char arg0[] = "raylib"; // NOTE: argv[] are mutable + CORE.Android.app = app; + + (void)android_run(); + // TODO: Should we maybe report != 0 return codes somewhere? + //(void)main(1, (char *[]) { arg0, NULL }); +} + +// TODO: Add this to header (if apps really need it) +struct android_app *GetAndroidApp(void) +{ + return CORE.Android.app; +} +#endif +#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && !defined(SUPPORT_SSH_KEYBOARD_RPI) +// Init terminal (block echo and signal short cuts) +static void InitTerminal(void) +{ + TRACELOG(LOG_INFO, "RPI: Reconfiguring terminal..."); + + // Save terminal keyboard settings and reconfigure terminal with new settings + struct termios keyboardNewSettings; + tcgetattr(STDIN_FILENO, &CORE.Input.Keyboard.defaultSettings); // Get current keyboard settings + keyboardNewSettings = CORE.Input.Keyboard.defaultSettings; + + // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo + // NOTE: ISIG controls if ^C and ^Z generate break signals or not + keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG); + keyboardNewSettings.c_cc[VMIN] = 1; + keyboardNewSettings.c_cc[VTIME] = 0; + + // Set new keyboard settings (change occurs immediately) + tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings); + + // Save old keyboard mode to restore it at the end + if (ioctl(STDIN_FILENO, KDGKBMODE, &CORE.Input.Keyboard.defaultMode) < 0) + { + // NOTE: It could mean we are using a remote keyboard through ssh or from the desktop + TRACELOG(LOG_WARNING, "RPI: Failed to change keyboard mode (not a local terminal)"); + } + else ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE); + + // Register terminal restore when program finishes + atexit(RestoreTerminal); +} +// Restore terminal +static void RestoreTerminal(void) +{ + TRACELOG(LOG_INFO, "RPI: Restoring terminal..."); + + // Reset to default keyboard settings + tcsetattr(STDIN_FILENO, TCSANOW, &CORE.Input.Keyboard.defaultSettings); + + // Reconfigure keyboard to default mode + ioctl(STDIN_FILENO, KDSKBMODE, CORE.Input.Keyboard.defaultMode); +} +#endif +// Initialize window and OpenGL context +// NOTE: data parameter could be used to pass any kind of required data to the initialization +void InitWindow(int width, int height, const char *title) +{ +#if defined(PLATFORM_UWP) + if (!UWPIsConfigured()) + { + TRACELOG(LOG_ERROR, "UWP Functions have not been set yet, please set these before initializing raylib!"); + return; + } +#endif + + TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION); + + if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title; + + // Initialize required global values different than 0 + CORE.Input.Keyboard.exitKey = KEY_ESCAPE; + CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; + CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW; + CORE.Input.Gamepad.lastButtonPressed = -1; + +#if defined(PLATFORM_UWP) + // The axis count is 6 (2 thumbsticks and left and right trigger) + CORE.Input.Gamepad.axisCount = 6; +#endif + +#if defined(PLATFORM_ANDROID) + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + + // Input data is android app pointer + CORE.Android.internalDataPath = CORE.Android.app->activity->internalDataPath; + + // Set desired windows flags before initializing anything + ANativeActivity_setWindowFlags(CORE.Android.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER + + int orientation = AConfiguration_getOrientation(CORE.Android.app->config); + + if (orientation == ACONFIGURATION_ORIENTATION_PORT) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as portrait"); + else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as landscape"); + + // TODO: Automatic orientation doesn't seem to work + if (width <= height) + { + AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_PORT); + TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait"); + } + else + { + AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_LAND); + TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape"); + } + + //AConfiguration_getDensity(CORE.Android.app->config); + //AConfiguration_getKeyboard(CORE.Android.app->config); + //AConfiguration_getScreenSize(CORE.Android.app->config); + //AConfiguration_getScreenLong(CORE.Android.app->config); + + CORE.Android.app->onAppCmd = AndroidCommandCallback; + CORE.Android.app->onInputEvent = AndroidInputCallback; + + InitAssetManager(CORE.Android.app->activity->assetManager, CORE.Android.app->activity->internalDataPath); + + TRACELOG(LOG_INFO, "ANDROID: App initialized successfully"); + + // Android ALooper_pollAll() variables + int pollResult = 0; + int pollEvents = 0; + + // Wait for window to be initialized (display and context) + while (!CORE.Window.ready) + { + // Process events loop + while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&CORE.Android.source)) >= 0) + { + // Process this event + if (CORE.Android.source != NULL) CORE.Android.source->process(CORE.Android.app, CORE.Android.source); + + // NOTE: Never close window, native activity is controlled by the system! + //if (CORE.Android.app->destroyRequested != 0) CORE.Window.shouldClose = true; + } + } +#endif +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) || defined(PLATFORM_DRM) + // Init graphics device (display device and OpenGL context) + // NOTE: returns true if window and graphic device has been initialized successfully + CORE.Window.ready = InitGraphicsDevice(width, height); + + if (!CORE.Window.ready) return; + + // Init hi-res timer + InitTimer(); + +#if defined(SUPPORT_DEFAULT_FONT) + // Load default font + // NOTE: External functions (defined in module: text) + LoadFontDefault(); + Rectangle rec = GetFontDefault().recs[95]; + // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); +#else + // Set default internal texture (1px white) and rectangle to be used for shapes drawing + SetShapesTexture(rlGetTextureDefault(), (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); +#endif +#if defined(PLATFORM_DESKTOP) + if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) + { + // Set default font texture filter for HighDPI (blurry) + SetTextureFilter(GetFontDefault().texture, TEXTURE_FILTER_BILINEAR); + } +#endif + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + // Init raw input system + InitEvdevInput(); // Evdev inputs initialization + InitGamepad(); // Gamepad init +#if defined(SUPPORT_SSH_KEYBOARD_RPI) + InitKeyboard(); // Keyboard init +#else + InitTerminal(); // Terminal init +#endif +#endif + +#if defined(PLATFORM_WEB) + // Detect fullscreen change events + //emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback); + //emscripten_set_resize_callback("#canvas", NULL, 1, EmscriptenResizeCallback); + + // Support keyboard events + //emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); + //emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); + + // Support touch events + emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenTouchCallback); + emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenTouchCallback); + emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenTouchCallback); + emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenTouchCallback); + + // Support gamepad events (not provided by GLFW3 on emscripten) + emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback); + emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); +#endif + + CORE.Input.Mouse.position.x = (float)CORE.Window.screen.width/2.0f; + CORE.Input.Mouse.position.y = (float)CORE.Window.screen.height/2.0f; +#endif // PLATFORM_ANDROID +} + +// Close window and unload OpenGL context +void CloseWindow(void) +{ +#if defined(SUPPORT_GIF_RECORDING) + if (gifRecording) + { + MsfGifResult result = msf_gif_end(&gifState); + msf_gif_free(result); + gifRecording = false; + } +#endif + +#if defined(SUPPORT_DEFAULT_FONT) + UnloadFontDefault(); +#endif + + rlglClose(); // De-init rlgl + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + glfwDestroyWindow(CORE.Window.handle); + glfwTerminate(); +#endif + +#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_UWP) + timeEndPeriod(1); // Restore time period +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) +#if defined(PLATFORM_DRM) + if (CORE.Window.prevFB) + { + drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB); + CORE.Window.prevFB = 0; + } + + if (CORE.Window.prevBO) + { + gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO); + CORE.Window.prevBO = NULL; + } + + if (CORE.Window.gbmSurface) + { + gbm_surface_destroy(CORE.Window.gbmSurface); + CORE.Window.gbmSurface = NULL; + } + + if (CORE.Window.gbmDevice) + { + gbm_device_destroy(CORE.Window.gbmDevice); + CORE.Window.gbmDevice = NULL; + } + + if (CORE.Window.crtc) + { + if (CORE.Window.connector) + { + drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, CORE.Window.crtc->buffer_id, + CORE.Window.crtc->x, CORE.Window.crtc->y, &CORE.Window.connector->connector_id, 1, &CORE.Window.crtc->mode); + drmModeFreeConnector(CORE.Window.connector); + CORE.Window.connector = NULL; + } + + drmModeFreeCrtc(CORE.Window.crtc); + CORE.Window.crtc = NULL; + } + + if (CORE.Window.fd != -1) + { + close(CORE.Window.fd); + CORE.Window.fd = -1; + } +#endif + + // Close surface, context and display + if (CORE.Window.device != EGL_NO_DISPLAY) + { +#if !defined(PLATFORM_DRM) + eglMakeCurrent(CORE.Window.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +#endif + if (CORE.Window.surface != EGL_NO_SURFACE) + { + eglDestroySurface(CORE.Window.device, CORE.Window.surface); + CORE.Window.surface = EGL_NO_SURFACE; + } + + if (CORE.Window.context != EGL_NO_CONTEXT) + { + eglDestroyContext(CORE.Window.device, CORE.Window.context); + CORE.Window.context = EGL_NO_CONTEXT; + } + + eglTerminate(CORE.Window.device); + CORE.Window.device = EGL_NO_DISPLAY; + } +#endif + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + // Wait for mouse and gamepad threads to finish before closing + // NOTE: Those threads should already have finished at this point + // because they are controlled by CORE.Window.shouldClose variable + + CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called + + // Close the evdev keyboard + if (CORE.Input.Keyboard.fd != -1) + { + close(CORE.Input.Keyboard.fd); + CORE.Input.Keyboard.fd = -1; + } + + for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + { + if (CORE.Input.eventWorker[i].threadId) + { + pthread_join(CORE.Input.eventWorker[i].threadId, NULL); + } + } + + + if (CORE.Input.Gamepad.threadId) pthread_join(CORE.Input.Gamepad.threadId, NULL); +#endif + + CORE.Window.ready = false; + TRACELOG(LOG_INFO, "Window closed successfully"); +} + +// Check if KEY_ESCAPE pressed or Close icon pressed +bool WindowShouldClose(void) +{ +#if defined(PLATFORM_WEB) + // Emterpreter-Async required to run sync code + // https://github.com/emscripten-core/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code + // By default, this function is never called on a web-ready raylib example because we encapsulate + // frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously + // but now emscripten allows sync code to be executed in an interpreted way, using emterpreter! + emscripten_sleep(16); + return false; +#endif + +#if defined(PLATFORM_DESKTOP) + if (CORE.Window.ready) + { + // While window minimized, stop loop execution + while (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)) glfwWaitEvents(); + + CORE.Window.shouldClose = glfwWindowShouldClose(CORE.Window.handle); + + // Reset close status for next frame + glfwSetWindowShouldClose(CORE.Window.handle, GLFW_FALSE); + + return CORE.Window.shouldClose; + } + else return true; +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) + if (CORE.Window.ready) return CORE.Window.shouldClose; + else return true; +#endif +} + +// Check if window has been initialized successfully +bool IsWindowReady(void) +{ + return CORE.Window.ready; +} + +// Check if window is currently fullscreen +bool IsWindowFullscreen(void) +{ + return CORE.Window.fullscreen; +} + +// Check if window is currently hidden +bool IsWindowHidden(void) +{ +#if defined(PLATFORM_DESKTOP) + return ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0); +#endif + return false; +} + +// Check if window has been minimized +bool IsWindowMinimized(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) + return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0); +#else + return false; +#endif +} + +// Check if window has been maximized (only PLATFORM_DESKTOP) +bool IsWindowMaximized(void) +{ +#if defined(PLATFORM_DESKTOP) + return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0); +#else + return false; +#endif +} + +// Check if window has the focus +bool IsWindowFocused(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) + return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0); // TODO! +#else + return true; +#endif +} + +// Check if window has been resizedLastFrame +bool IsWindowResized(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) + return CORE.Window.resizedLastFrame; +#else + return false; +#endif +} + +// Check if one specific window flag is enabled +bool IsWindowState(unsigned int flag) +{ + return ((CORE.Window.flags & flag) > 0); +} + +// Toggle fullscreen mode (only PLATFORM_DESKTOP) +void ToggleFullscreen(void) +{ +#if defined(PLATFORM_DESKTOP) + // NOTE: glfwSetWindowMonitor() doesn't work properly (bugs) + if (!CORE.Window.fullscreen) + { + // Store previous window position (in case we exit fullscreen) + glfwGetWindowPos(CORE.Window.handle, &CORE.Window.position.x, &CORE.Window.position.y); + + int monitorCount = 0; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + int monitorIndex = GetCurrentMonitor(); + + // Use current monitor, so we correctly get the display the window is on + GLFWmonitor* monitor = monitorIndex < monitorCount ? monitors[monitorIndex] : NULL; + + if (!monitor) + { + TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor"); + + CORE.Window.fullscreen = false; // Toggle fullscreen flag + CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; + + glfwSetWindowMonitor(CORE.Window.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + return; + } + + CORE.Window.fullscreen = true; // Toggle fullscreen flag + CORE.Window.flags |= FLAG_FULLSCREEN_MODE; + + glfwSetWindowMonitor(CORE.Window.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + } + else + { + CORE.Window.fullscreen = false; // Toggle fullscreen flag + CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; + + glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + } + + // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) + // NOTE: V-Sync can be enabled by graphic driver configuration + if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1); +#endif +#if defined(PLATFORM_WEB) + EM_ASM + ( + // This strategy works well while using raylib minimal web shell for emscripten, + // it re-scales the canvas to fullscreen using monitor resolution, for tools this + // is a good strategy but maybe games prefer to keep current canvas resolution and + // display it in fullscreen, adjusting monitor resolution if possible + if (document.fullscreenElement) document.exitFullscreen(); + else Module.requestFullscreen(false, true); + ); + +/* + if (!CORE.Window.fullscreen) + { + // Option 1: Request fullscreen for the canvas element + // This option does not seem to work at all + //emscripten_request_fullscreen("#canvas", false); + + // Option 2: Request fullscreen for the canvas element with strategy + // This option does not seem to work at all + // Ref: https://github.com/emscripten-core/emscripten/issues/5124 + // EmscriptenFullscreenStrategy strategy = { + // .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT, + // .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF, + // .filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT, + // .canvasResizedCallback = EmscriptenWindowResizedCallback, + // .canvasResizedCallbackUserData = NULL + // }; + //emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy); + + // Option 3: Request fullscreen for the canvas element with strategy + // It works as expected but only inside the browser (client area) + EmscriptenFullscreenStrategy strategy = { + .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT, + .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF, + .filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT, + .canvasResizedCallback = EmscriptenWindowResizedCallback, + .canvasResizedCallbackUserData = NULL + }; + emscripten_enter_soft_fullscreen("#canvas", &strategy); + + int width, height; + emscripten_get_canvas_element_size("#canvas", &width, &height); + TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height); + } + else + { + //emscripten_exit_fullscreen(); + emscripten_exit_soft_fullscreen(); + + int width, height; + emscripten_get_canvas_element_size("#canvas", &width, &height); + TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height); + } +*/ + + CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag + CORE.Window.flags ^= FLAG_FULLSCREEN_MODE; +#endif +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + TRACELOG(LOG_WARNING, "SYSTEM: Failed to toggle to windowed mode"); +#endif +} + +// Set window state: maximized, if resizable (only PLATFORM_DESKTOP) +void MaximizeWindow(void) +{ +#if defined(PLATFORM_DESKTOP) + if (glfwGetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE) == GLFW_TRUE) + { + glfwMaximizeWindow(CORE.Window.handle); + CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; + } +#endif +} + +// Set window state: minimized (only PLATFORM_DESKTOP) +void MinimizeWindow(void) +{ +#if defined(PLATFORM_DESKTOP) + // NOTE: Following function launches callback that sets appropiate flag! + glfwIconifyWindow(CORE.Window.handle); +#endif +} + +// Set window state: not minimized/maximized (only PLATFORM_DESKTOP) +void RestoreWindow(void) +{ +#if defined(PLATFORM_DESKTOP) + if (glfwGetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE) == GLFW_TRUE) + { + // Restores the specified window if it was previously iconified (minimized) or maximized + glfwRestoreWindow(CORE.Window.handle); + CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; + CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; + } +#endif +} + +// Set window configuration state using flags +void SetWindowState(unsigned int flags) +{ +#if defined(PLATFORM_DESKTOP) + // Check previous state and requested state to apply required changes + // NOTE: In most cases the functions already change the flags internally + + // State change: FLAG_VSYNC_HINT + if (((CORE.Window.flags & FLAG_VSYNC_HINT) != (flags & FLAG_VSYNC_HINT)) && ((flags & FLAG_VSYNC_HINT) > 0)) + { + glfwSwapInterval(1); + CORE.Window.flags |= FLAG_VSYNC_HINT; + } + + // State change: FLAG_FULLSCREEN_MODE + if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE)) + { + ToggleFullscreen(); // NOTE: Window state flag updated inside function + } + + // State change: FLAG_WINDOW_RESIZABLE + if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE, GLFW_TRUE); + CORE.Window.flags |= FLAG_WINDOW_RESIZABLE; + } + + // State change: FLAG_WINDOW_UNDECORATED + if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) != (flags & FLAG_WINDOW_UNDECORATED)) && (flags & FLAG_WINDOW_UNDECORATED)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_FALSE); + CORE.Window.flags |= FLAG_WINDOW_UNDECORATED; + } + + // State change: FLAG_WINDOW_HIDDEN + if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) != (flags & FLAG_WINDOW_HIDDEN)) && ((flags & FLAG_WINDOW_HIDDEN) > 0)) + { + glfwHideWindow(CORE.Window.handle); + CORE.Window.flags |= FLAG_WINDOW_HIDDEN; + } + + // State change: FLAG_WINDOW_MINIMIZED + if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) != (flags & FLAG_WINDOW_MINIMIZED)) && ((flags & FLAG_WINDOW_MINIMIZED) > 0)) + { + //GLFW_ICONIFIED + MinimizeWindow(); // NOTE: Window state flag updated inside function + } + + // State change: FLAG_WINDOW_MAXIMIZED + if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0)) + { + //GLFW_MAXIMIZED + MaximizeWindow(); // NOTE: Window state flag updated inside function + } + + // State change: FLAG_WINDOW_UNFOCUSED + if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) != (flags & FLAG_WINDOW_UNFOCUSED)) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_FOCUS_ON_SHOW, GLFW_FALSE); + CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; + } + + // State change: FLAG_WINDOW_TOPMOST + if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) != (flags & FLAG_WINDOW_TOPMOST)) && ((flags & FLAG_WINDOW_TOPMOST) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_TRUE); + CORE.Window.flags |= FLAG_WINDOW_TOPMOST; + } + + // State change: FLAG_WINDOW_ALWAYS_RUN + if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) != (flags & FLAG_WINDOW_ALWAYS_RUN)) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)) + { + CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN; + } + + // The following states can not be changed after window creation + + // State change: FLAG_WINDOW_TRANSPARENT + if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) + { + TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization"); + } + + // State change: FLAG_WINDOW_HIGHDPI + if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) + { + TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization"); + } + + // State change: FLAG_MSAA_4X_HINT + if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0)) + { + TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization"); + } + + // State change: FLAG_INTERLACED_HINT + if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0)) + { + TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization"); + } +#endif +} + +// Clear window configuration state flags +void ClearWindowState(unsigned int flags) +{ +#if defined(PLATFORM_DESKTOP) + // Check previous state and requested state to apply required changes + // NOTE: In most cases the functions already change the flags internally + + // State change: FLAG_VSYNC_HINT + if (((CORE.Window.flags & FLAG_VSYNC_HINT) > 0) && ((flags & FLAG_VSYNC_HINT) > 0)) + { + glfwSwapInterval(0); + CORE.Window.flags &= ~FLAG_VSYNC_HINT; + } + + // State change: FLAG_FULLSCREEN_MODE + if (((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) && ((flags & FLAG_FULLSCREEN_MODE) > 0)) + { + ToggleFullscreen(); // NOTE: Window state flag updated inside function + } + + // State change: FLAG_WINDOW_RESIZABLE + if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE, GLFW_FALSE); + CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE; + } + + // State change: FLAG_WINDOW_UNDECORATED + if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) && ((flags & FLAG_WINDOW_UNDECORATED) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_TRUE); + CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED; + } + + // State change: FLAG_WINDOW_HIDDEN + if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) && ((flags & FLAG_WINDOW_HIDDEN) > 0)) + { + glfwShowWindow(CORE.Window.handle); + CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; + } + + // State change: FLAG_WINDOW_MINIMIZED + if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((flags & FLAG_WINDOW_MINIMIZED) > 0)) + { + RestoreWindow(); // NOTE: Window state flag updated inside function + } + + // State change: FLAG_WINDOW_MAXIMIZED + if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0)) + { + RestoreWindow(); // NOTE: Window state flag updated inside function + } + + // State change: FLAG_WINDOW_UNFOCUSED + if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_FOCUS_ON_SHOW, GLFW_TRUE); + CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; + } + + // State change: FLAG_WINDOW_TOPMOST + if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) && ((flags & FLAG_WINDOW_TOPMOST) > 0)) + { + glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_FALSE); + CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST; + } + + // State change: FLAG_WINDOW_ALWAYS_RUN + if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) > 0) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)) + { + CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN; + } + + // The following states can not be changed after window creation + + // State change: FLAG_WINDOW_TRANSPARENT + if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) + { + TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization"); + } + + // State change: FLAG_WINDOW_HIGHDPI + if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) + { + TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization"); + } + + // State change: FLAG_MSAA_4X_HINT + if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0)) + { + TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization"); + } + + // State change: FLAG_INTERLACED_HINT + if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0)) + { + TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization"); + } +#endif +} + +// Set icon for window (only PLATFORM_DESKTOP) +// NOTE: Image must be in RGBA format, 8bit per channel +void SetWindowIcon(Image image) +{ +#if defined(PLATFORM_DESKTOP) + if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + { + GLFWimage icon[1] = { 0 }; + + icon[0].width = image.width; + icon[0].height = image.height; + icon[0].pixels = (unsigned char *)image.data; + + // NOTE 1: We only support one image icon + // NOTE 2: The specified image data is copied before this function returns + glfwSetWindowIcon(CORE.Window.handle, 1, icon); + } + else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); +#endif +} + +// Set title for window (only PLATFORM_DESKTOP) +void SetWindowTitle(const char *title) +{ + CORE.Window.title = title; +#if defined(PLATFORM_DESKTOP) + glfwSetWindowTitle(CORE.Window.handle, title); +#endif +} + +// Set window position on screen (windowed mode) +void SetWindowPosition(int x, int y) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetWindowPos(CORE.Window.handle, x, y); +#endif +} + +// Set monitor for the current window (fullscreen mode) +void SetWindowMonitor(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount = 0; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + TRACELOG(LOG_INFO, "GLFW: Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); + + const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); + glfwSetWindowMonitor(CORE.Window.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate); + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif +} + +// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) +void SetWindowMinSize(int width, int height) +{ +#if defined(PLATFORM_DESKTOP) + const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + glfwSetWindowSizeLimits(CORE.Window.handle, width, height, mode->width, mode->height); +#endif +} + +// Set window dimensions +// TODO: Issues on HighDPI scaling +void SetWindowSize(int width, int height) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetWindowSize(CORE.Window.handle, width, height); +#endif +#if defined(PLATFORM_WEB) + //emscripten_set_canvas_size(width, height); // DEPRECATED! + + // TODO: Below functions should be used to replace previous one but + // they do not seem to work properly + //emscripten_set_canvas_element_size("canvas", width, height); + //emscripten_set_element_css_size("canvas", width, height); +#endif +} + +// Get current screen width +int GetScreenWidth(void) +{ + return CORE.Window.currentFbo.width; +} + +// Get current screen height +int GetScreenHeight(void) +{ + return CORE.Window.currentFbo.height; +} + +// Get native window handle +void *GetWindowHandle(void) +{ +#if defined(PLATFORM_DESKTOP) && defined(_WIN32) + // NOTE: Returned handle is: void *HWND (windows.h) + return glfwGetWin32Window(CORE.Window.handle); +#endif +#if defined(__linux__) + // NOTE: Returned handle is: unsigned long Window (X.h) + // typedef unsigned long XID; + // typedef XID Window; + //unsigned long id = (unsigned long)glfwGetX11Window(window); + return NULL; // TODO: Find a way to return value... cast to void *? +#endif +#if defined(__APPLE__) + // NOTE: Returned handle is: (objc_object *) + return NULL; // TODO: return (void *)glfwGetCocoaWindow(window); +#endif + + return NULL; +} + +// Get number of monitors +int GetMonitorCount(void) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + glfwGetMonitors(&monitorCount); + return monitorCount; +#else + return 1; +#endif +} + +// Get number of monitors +int GetCurrentMonitor(void) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor* monitor = NULL; + + if (monitorCount == 1) // easy out + return 0; + + if (IsWindowFullscreen()) + { + monitor = glfwGetWindowMonitor(CORE.Window.handle); + for (int i = 0; i < monitorCount; i++) + { + if (monitors[i] == monitor) + return i; + } + return 0; + } + else + { + int x = 0; + int y = 0; + + glfwGetWindowPos(CORE.Window.handle, &x, &y); + + for (int i = 0; i < monitorCount; i++) + { + int mx = 0; + int my = 0; + + int width = 0; + int height = 0; + + monitor = monitors[i]; + glfwGetMonitorWorkarea(monitor, &mx, &my, &width, &height); + if (x >= mx && x <= (mx + width) && y >= my && y <= (my + height)) + return i; + } + } + return 0; +#else + return 0; +#endif +} + +// Get selected monitor width +Vector2 GetMonitorPosition(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int x, y; + glfwGetMonitorPos(monitors[monitor], &x, &y); + + return (Vector2){ (float)x, (float)y }; + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif + return (Vector2){ 0, 0 }; +} + +// Get selected monitor width (max available by monitor) +int GetMonitorWidth(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int count = 0; + const GLFWvidmode *modes = glfwGetVideoModes(monitors[monitor], &count); + + // We return the maximum resolution available, the last one in the modes array + if (count > 0) return modes[count - 1].width; + else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif + return 0; +} + +// Get selected monitor width (max available by monitor) +int GetMonitorHeight(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int count = 0; + const GLFWvidmode *modes = glfwGetVideoModes(monitors[monitor], &count); + + // We return the maximum resolution available, the last one in the modes array + if (count > 0) return modes[count - 1].height; + else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif + return 0; +} + +// Get selected monitor physical width in millimetres +int GetMonitorPhysicalWidth(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int physicalWidth; + glfwGetMonitorPhysicalSize(monitors[monitor], &physicalWidth, NULL); + return physicalWidth; + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif + return 0; +} + +// Get primary monitor physical height in millimetres +int GetMonitorPhysicalHeight(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int physicalHeight; + glfwGetMonitorPhysicalSize(monitors[monitor], NULL, &physicalHeight); + return physicalHeight; + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif + return 0; +} + +int GetMonitorRefreshRate(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + const GLFWvidmode *vidmode = glfwGetVideoMode(monitors[monitor]); + return vidmode->refreshRate; + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif +#if defined(PLATFORM_DRM) + if ((CORE.Window.connector) && (CORE.Window.modeIndex >= 0)) + { + return CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh; + } +#endif + return 0; +} + +// Get window position XY on monitor +Vector2 GetWindowPosition(void) +{ + int x = 0; + int y = 0; +#if defined(PLATFORM_DESKTOP) + glfwGetWindowPos(CORE.Window.handle, &x, &y); +#endif + return (Vector2){ (float)x, (float)y }; +} + +// Get window scale DPI factor +Vector2 GetWindowScaleDPI(void) +{ + Vector2 scale = { 1.0f, 1.0f }; + +#if defined(PLATFORM_DESKTOP) + float xdpi = 1.0; + float ydpi = 1.0; + Vector2 windowPos = GetWindowPosition(); + + int monitorCount = 0; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + // Check window monitor + for (int i = 0; i < monitorCount; i++) + { + glfwGetMonitorContentScale(monitors[i], &xdpi, &ydpi); + + int xpos, ypos, width, height; + glfwGetMonitorWorkarea(monitors[i], &xpos, &ypos, &width, &height); + + if ((windowPos.x >= xpos) && (windowPos.x < xpos + width) && + (windowPos.y >= ypos) && (windowPos.y < ypos + height)) + { + scale.x = xdpi; + scale.y = ydpi; + break; + } + } +#endif + + return scale; +} + +// Get the human-readable, UTF-8 encoded name of the primary monitor +const char *GetMonitorName(int monitor) +{ +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + return glfwGetMonitorName(monitors[monitor]); + } + else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif + return ""; +} + +// Get clipboard text content +// NOTE: returned string is allocated and freed by GLFW +const char *GetClipboardText(void) +{ +#if defined(PLATFORM_DESKTOP) + return glfwGetClipboardString(CORE.Window.handle); +#else + return NULL; +#endif +} + +// Set clipboard text content +void SetClipboardText(const char *text) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetClipboardString(CORE.Window.handle, text); +#endif +} + +// Show mouse cursor +void ShowCursor(void) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif +#if defined(PLATFORM_UWP) + UWPGetMouseShowFunc()(); +#endif + CORE.Input.Mouse.cursorHidden = false; +} + +// Hides mouse cursor +void HideCursor(void) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); +#endif +#if defined(PLATFORM_UWP) + UWPGetMouseHideFunc()(); +#endif + CORE.Input.Mouse.cursorHidden = true; +} + +// Check if cursor is not visible +bool IsCursorHidden(void) +{ + return CORE.Input.Mouse.cursorHidden; +} + +// Enables cursor (unlock cursor) +void EnableCursor(void) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif +#if defined(PLATFORM_WEB) + emscripten_exit_pointerlock(); +#endif +#if defined(PLATFORM_UWP) + UWPGetMouseUnlockFunc()(); +#endif + CORE.Input.Mouse.cursorHidden = false; +} + +// Disables cursor (lock cursor) +void DisableCursor(void) +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif +#if defined(PLATFORM_WEB) + emscripten_request_pointerlock("#canvas", 1); +#endif +#if defined(PLATFORM_UWP) + UWPGetMouseLockFunc()(); +#endif + CORE.Input.Mouse.cursorHidden = true; +} + +// Check if cursor is on the current screen. +bool IsCursorOnScreen(void) +{ + return CORE.Input.Mouse.cursorOnScreen; +} + +// Set background color (framebuffer clear color) +void ClearBackground(Color color) +{ + rlClearColor(color.r, color.g, color.b, color.a); // Set clear color + rlClearScreenBuffers(); // Clear current framebuffers +} + +// Setup canvas (framebuffer) to start drawing +void BeginDrawing(void) +{ + CORE.Time.current = GetTime(); // Number of elapsed seconds since InitTimer() + CORE.Time.update = CORE.Time.current - CORE.Time.previous; + CORE.Time.previous = CORE.Time.current; + + rlLoadIdentity(); // Reset current matrix (modelview) + rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling + + //rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1 + // NOTE: Not required with OpenGL 3.3+ +} + +// End canvas drawing and swap buffers (double buffering) +void EndDrawing(void) +{ +#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_MOUSE_CURSOR_NATIVE) + // On native mode we have no system mouse cursor, so, + // we draw a small rectangle for user reference + if (!CORE.Input.Mouse.cursorHidden) + { + DrawRectangle(CORE.Input.Mouse.position.x, CORE.Input.Mouse.position.y, 3, 3, MAROON); + } +#endif + + rlDrawRenderBatchActive(); // Update and draw internal render batch + +#if defined(SUPPORT_GIF_RECORDING) + #define GIF_RECORD_FRAMERATE 10 + + if (gifRecording) + { + gifFramesCounter++; + + // NOTE: We record one gif frame every 10 game frames + if ((gifFramesCounter%GIF_RECORD_FRAMERATE) == 0) + { + // Get image data for the current frame (from backbuffer) + // NOTE: This process is quite slow... :( + unsigned char *screenData = rlReadScreenPixels(CORE.Window.screen.width, CORE.Window.screen.height); + msf_gif_frame(&gifState, screenData, 10, 16, CORE.Window.screen.width*4); + + RL_FREE(screenData); // Free image data + } + + if (((gifFramesCounter/15)%2) == 1) + { + DrawCircle(30, CORE.Window.screen.height - 20, 10, RED); + DrawText("RECORDING", 50, CORE.Window.screen.height - 25, 10, MAROON); + } + + rlDrawRenderBatchActive(); // Update and draw internal render batch + } +#endif + + SwapBuffers(); // Copy back buffer to front buffer + + // Frame time control system + CORE.Time.current = GetTime(); + CORE.Time.draw = CORE.Time.current - CORE.Time.previous; + CORE.Time.previous = CORE.Time.current; + + CORE.Time.frame = CORE.Time.update + CORE.Time.draw; + + // Wait for some milliseconds... + if (CORE.Time.frame < CORE.Time.target) + { + Wait((float)(CORE.Time.target - CORE.Time.frame)*1000.0f); + + CORE.Time.current = GetTime(); + double waitTime = CORE.Time.current - CORE.Time.previous; + CORE.Time.previous = CORE.Time.current; + + CORE.Time.frame += waitTime; // Total frame time: update + draw + wait + } + + PollInputEvents(); // Poll user events +} + +// Initialize 2D mode with custom camera (2D) +void BeginMode2D(Camera2D camera) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlLoadIdentity(); // Reset current matrix (modelview) + + // Apply 2d camera transformation to modelview + rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera))); + + // Apply screen scaling if required + rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); +} + +// Ends 2D mode with custom camera +void EndMode2D(void) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlLoadIdentity(); // Reset current matrix (modelview) + rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required +} + +// Initializes 3D mode with custom camera (3D) +void BeginMode3D(Camera3D camera) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlMatrixMode(RL_PROJECTION); // Switch to projection matrix + rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection + rlLoadIdentity(); // Reset current matrix (projection) + + float aspect = (float)CORE.Window.currentFbo.width/(float)CORE.Window.currentFbo.height; + + // NOTE: zNear and zFar values are important when computing depth buffer values + if (camera.projection == CAMERA_PERSPECTIVE) + { + // Setup perspective projection + double top = RL_CULL_DISTANCE_NEAR*tan(camera.fovy*0.5*DEG2RAD); + double right = top*aspect; + + rlFrustum(-right, right, -top, top, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + } + else if (camera.projection == CAMERA_ORTHOGRAPHIC) + { + // Setup orthographic projection + double top = camera.fovy/2.0; + double right = top*aspect; + + rlOrtho(-right, right, -top,top, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + } + + rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix + rlLoadIdentity(); // Reset current matrix (modelview) + + // Setup Camera view + Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + rlMultMatrixf(MatrixToFloat(matView)); // Multiply modelview matrix by view matrix (camera) + + rlEnableDepthTest(); // Enable DEPTH_TEST for 3D +} + +// Ends 3D mode and returns to default 2D orthographic mode +void EndMode3D(void) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlMatrixMode(RL_PROJECTION); // Switch to projection matrix + rlPopMatrix(); // Restore previous matrix (projection) from matrix stack + + rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix + rlLoadIdentity(); // Reset current matrix (modelview) + + rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required + + rlDisableDepthTest(); // Disable DEPTH_TEST for 2D +} + +// Initializes render texture for drawing +void BeginTextureMode(RenderTexture2D target) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlEnableFramebuffer(target.id); // Enable render target + + // Set viewport to framebuffer size + rlViewport(0, 0, target.texture.width, target.texture.height); + + rlMatrixMode(RL_PROJECTION); // Switch to projection matrix + rlLoadIdentity(); // Reset current matrix (projection) + + // Set orthographic projection to current framebuffer size + // NOTE: Configured top-left corner as (0, 0) + rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f); + + rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix + rlLoadIdentity(); // Reset current matrix (modelview) + + //rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?) + + // Setup current width/height for proper aspect ratio + // calculation when using BeginMode3D() + CORE.Window.currentFbo.width = target.texture.width; + CORE.Window.currentFbo.height = target.texture.height; +} + +// Ends drawing to render texture +void EndTextureMode(void) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlDisableFramebuffer(); // Disable render target (fbo) + + // Set viewport to default framebuffer size + SetupViewport(CORE.Window.render.width, CORE.Window.render.height); + + // Reset current fbo to screen size + CORE.Window.currentFbo.width = CORE.Window.screen.width; + CORE.Window.currentFbo.height = CORE.Window.screen.height; +} + +// Begin custom shader mode +void BeginShaderMode(Shader shader) +{ + rlSetShader(shader); +} + +// End custom shader mode (returns to default shader) +void EndShaderMode(void) +{ + rlSetShader(rlGetShaderDefault()); +} + +// Begin blending mode (alpha, additive, multiplied) +// NOTE: Only 3 blending modes supported, default blend mode is alpha +void BeginBlendMode(int mode) +{ + rlSetBlendMode(mode); +} + +// End blending mode (reset to default: alpha blending) +void EndBlendMode(void) +{ + rlSetBlendMode(BLEND_ALPHA); +} + +// Begin scissor mode (define screen area for following drawing) +// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left +void BeginScissorMode(int x, int y, int width, int height) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlEnableScissorTest(); + rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height); +} + +// End scissor mode +void EndScissorMode(void) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + rlDisableScissorTest(); +} + +// Begin VR drawing configuration +void BeginVrStereoMode(VrStereoConfig config) +{ + rlEnableStereoRender(); + + // Set stereo render matrices + rlSetMatrixProjectionStereo(config.projection[0], config.projection[1]); + rlSetMatrixViewOffsetStereo(config.viewOffset[0], config.viewOffset[1]); +} + +// End VR drawing process (and desktop mirror) +void EndVrStereoMode(void) +{ + rlDisableStereoRender(); +} + +// Load VR stereo config for VR simulator device parameters +VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device) +{ + VrStereoConfig config = { 0 }; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Compute aspect ratio + float aspect = ((float)device.hResolution*0.5f)/(float)device.vResolution; + + // Compute lens parameters + float lensShift = (device.hScreenSize*0.25f - device.lensSeparationDistance*0.5f)/device.hScreenSize; + config.leftLensCenter[0] = 0.25f + lensShift; + config.leftLensCenter[1] = 0.5f; + config.rightLensCenter[0] = 0.75f - lensShift; + config.rightLensCenter[1] = 0.5f; + config.leftScreenCenter[0] = 0.25f; + config.leftScreenCenter[1] = 0.5f; + config.rightScreenCenter[0] = 0.75f; + config.rightScreenCenter[1] = 0.5f; + + // Compute distortion scale parameters + // NOTE: To get lens max radius, lensShift must be normalized to [-1..1] + float lensRadius = fabsf(-1.0f - 4.0f*lensShift); + float lensRadiusSq = lensRadius*lensRadius; + float distortionScale = device.lensDistortionValues[0] + + device.lensDistortionValues[1]*lensRadiusSq + + device.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq + + device.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq; + + float normScreenWidth = 0.5f; + float normScreenHeight = 1.0f; + config.scaleIn[0] = 2.0f/normScreenWidth; + config.scaleIn[1] = 2.0f/normScreenHeight/aspect; + config.scale[0] = normScreenWidth*0.5f/distortionScale; + config.scale[1] = normScreenHeight*0.5f*aspect/distortionScale; + + // Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance) + // ...but with lens distortion it is increased (see Oculus SDK Documentation) + //float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance); // Really need distortionScale? + float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance); + + // Compute camera projection matrices + float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] + Matrix proj = MatrixPerspective(fovy, aspect, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + + config.projection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)); + config.projection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f)); + + // Compute camera transformation matrices + // NOTE: Camera movement might seem more natural if we model the head. + // Our axis of rotation is the base of our head, so we might want to add + // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions. + config.viewOffset[0] = MatrixTranslate(-device.interpupillaryDistance*0.5f, 0.075f, 0.045f); + config.viewOffset[1] = MatrixTranslate(device.interpupillaryDistance*0.5f, 0.075f, 0.045f); + + // Compute eyes Viewports + /* + config.eyeViewportRight[0] = 0; + config.eyeViewportRight[1] = 0; + config.eyeViewportRight[2] = device.hResolution/2; + config.eyeViewportRight[3] = device.vResolution; + + config.eyeViewportLeft[0] = device.hResolution/2; + config.eyeViewportLeft[1] = 0; + config.eyeViewportLeft[2] = device.hResolution/2; + config.eyeViewportLeft[3] = device.vResolution; + */ +#else + TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1"); +#endif + + return config; +} + +// Unload VR stereo config properties +void UnloadVrStereoConfig(VrStereoConfig config) +{ + //... +} + +// Load shader from files and bind default locations +// NOTE: If shader string is NULL, using default vertex/fragment shaders +Shader LoadShader(const char *vsFileName, const char *fsFileName) +{ + Shader shader = { 0 }; + shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int)); + + // NOTE: All locations must be reseted to -1 (no location) + for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; + + char *vShaderStr = NULL; + char *fShaderStr = NULL; + + if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName); + if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName); + + shader.id = rlLoadShaderCode(vShaderStr, fShaderStr); + + if (vShaderStr != NULL) UnloadFileText(vShaderStr); + if (fShaderStr != NULL) UnloadFileText(fShaderStr); + + // After shader loading, we TRY to set default location names + if (shader.id > 0) + { + // Default shader attrib locations have been fixed before linking: + // vertex position location = 0 + // vertex texcoord location = 1 + // vertex normal location = 2 + // vertex color location = 3 + // vertex tangent location = 4 + // vertex texcoord2 location = 5 + + // NOTE: If any location is not found, loc point becomes -1 + + // Get handles to GLSL input attibute locations + shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_POSITION); + shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_NORMAL); + shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_TANGENT); + shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_COLOR); + + // Get handles to GLSL uniform locations (vertex shader) + shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, "mvp"); + shader.locs[SHADER_LOC_MATRIX_VIEW] = rlGetLocationUniform(shader.id, "view"); + shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, "projection"); + shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, "matNormal"); + + // Get handles to GLSL uniform locations (fragment shader) + shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, "colDiffuse"); + shader.locs[SHADER_LOC_MAP_DIFFUSE] = rlGetLocationUniform(shader.id, "texture0"); + shader.locs[SHADER_LOC_MAP_SPECULAR] = rlGetLocationUniform(shader.id, "texture1"); + shader.locs[SHADER_LOC_MAP_NORMAL] = rlGetLocationUniform(shader.id, "texture2"); + } + + return shader; +} + +// Load shader from code strings and bind default locations +RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) +{ + Shader shader = { 0 }; + shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int)); + + shader.id = rlLoadShaderCode(vsCode, fsCode); + + // After shader loading, we TRY to set default location names + if (shader.id > 0) + { + // Default shader attrib locations have been fixed before linking: + // vertex position location = 0 + // vertex texcoord location = 1 + // vertex normal location = 2 + // vertex color location = 3 + // vertex tangent location = 4 + // vertex texcoord2 location = 5 + + // NOTE: If any location is not found, loc point becomes -1 + + // Get handles to GLSL input attibute locations + shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_POSITION); + shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_NORMAL); + shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_TANGENT); + shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, DEFAULT_SHADER_ATTRIB_NAME_COLOR); + + // Get handles to GLSL uniform locations (vertex shader) + shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, "mvp"); + shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, "projection"); + shader.locs[SHADER_LOC_MATRIX_VIEW] = rlGetLocationUniform(shader.id, "view"); + + // Get handles to GLSL uniform locations (fragment shader) + shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, "colDiffuse"); + shader.locs[SHADER_LOC_MAP_DIFFUSE] = rlGetLocationUniform(shader.id, "texture0"); + shader.locs[SHADER_LOC_MAP_SPECULAR] = rlGetLocationUniform(shader.id, "texture1"); + shader.locs[SHADER_LOC_MAP_NORMAL] = rlGetLocationUniform(shader.id, "texture2"); + } + + return shader; +} + +// Unload shader from GPU memory (VRAM) +void UnloadShader(Shader shader) +{ + if (shader.id != rlGetShaderDefault().id) + { + rlUnloadShaderProgram(shader.id); + RL_FREE(shader.locs); + } +} + +// Get shader uniform location +int GetShaderLocation(Shader shader, const char *uniformName) +{ + return rlGetLocationUniform(shader.id, uniformName); +} + +// Get shader attribute location +int GetShaderLocationAttrib(Shader shader, const char *attribName) +{ + return rlGetLocationAttrib(shader.id, attribName); +} + +// Set shader uniform value +void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType) +{ + SetShaderValueV(shader, locIndex, value, uniformType, 1); +} + +// Set shader uniform value vector +void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count) +{ + rlEnableShader(shader.id); + rlSetUniform(locIndex, value, uniformType, count); + //rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set +} + +// Set shader uniform value (matrix 4x4) +void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat) +{ + rlEnableShader(shader.id); + rlSetUniformMatrix(locIndex, mat); + //rlDisableShader(); +} + +// Set shader uniform value for texture +void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture) +{ + rlEnableShader(shader.id); + rlSetUniformSampler(locIndex, texture.id); + //rlDisableShader(); +} + +// Returns a ray trace from mouse position +Ray GetMouseRay(Vector2 mouse, Camera camera) +{ + Ray ray = { 0 }; + + // Calculate normalized device coordinates + // NOTE: y value is negative + float x = (2.0f*mouse.x)/(float)GetScreenWidth() - 1.0f; + float y = 1.0f - (2.0f*mouse.y)/(float)GetScreenHeight(); + float z = 1.0f; + + // Store values in a vector + Vector3 deviceCoords = { x, y, z }; + + // Calculate view matrix from camera look at + Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + + Matrix matProj = MatrixIdentity(); + + if (camera.projection == CAMERA_PERSPECTIVE) + { + // Calculate projection matrix from perspective + matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + } + else if (camera.projection == CAMERA_ORTHOGRAPHIC) + { + float aspect = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height; + double top = camera.fovy/2.0; + double right = top*aspect; + + // Calculate projection matrix from orthographic + matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0); + } + + // Unproject far/near points + Vector3 nearPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); + Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); + + // Unproject the mouse cursor in the near plane. + // We need this as the source position because orthographic projects, compared to perspect doesn't have a + // convergence point, meaning that the "eye" of the camera is more like a plane than a point. + Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); + + // Calculate normalized direction vector + Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint)); + + if (camera.projection == CAMERA_PERSPECTIVE) ray.position = camera.position; + else if (camera.projection == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos; + + // Apply calculated vectors to ray + ray.direction = direction; + + return ray; +} + +// Get transform matrix for camera +Matrix GetCameraMatrix(Camera camera) +{ + return MatrixLookAt(camera.position, camera.target, camera.up); +} + +// Returns camera 2d transform matrix +Matrix GetCameraMatrix2D(Camera2D camera) +{ + Matrix matTransform = { 0 }; + // The camera in world-space is set by + // 1. Move it to target + // 2. Rotate by -rotation and scale by (1/zoom) + // When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller), + // not for the camera getting bigger, hence the invert. Same deal with rotation. + // 3. Move it by (-offset); + // Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera) + // we need to do it into opposite direction (inverse transform) + + // Having camera transform in world-space, inverse of it gives the modelview transform. + // Since (A*B*C)' = C'*B'*A', the modelview is + // 1. Move to offset + // 2. Rotate and Scale + // 3. Move by -target + Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); + Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); + Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); + Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f); + + matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); + + return matTransform; +} + +// Returns the screen space position from a 3d world space position +Vector2 GetWorldToScreen(Vector3 position, Camera camera) +{ + Vector2 screenPosition = GetWorldToScreenEx(position, camera, GetScreenWidth(), GetScreenHeight()); + + return screenPosition; +} + +// Returns size position for a 3d world space position (useful for texture drawing) +Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height) +{ + // Calculate projection matrix (from perspective instead of frustum + Matrix matProj = MatrixIdentity(); + + if (camera.projection == CAMERA_PERSPECTIVE) + { + // Calculate projection matrix from perspective + matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + } + else if (camera.projection == CAMERA_ORTHOGRAPHIC) + { + float aspect = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height; + double top = camera.fovy/2.0; + double right = top*aspect; + + // Calculate projection matrix from orthographic + matProj = MatrixOrtho(-right, right, -top, top, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + } + + // Calculate view matrix from camera look at (and transpose it) + Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + + // Convert world position vector to quaternion + Quaternion worldPos = { position.x, position.y, position.z, 1.0f }; + + // Transform world position to view + worldPos = QuaternionTransform(worldPos, matView); + + // Transform result to projection (clip space position) + worldPos = QuaternionTransform(worldPos, matProj); + + // Calculate normalized device coordinates (inverted y) + Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w }; + + // Calculate 2d screen position vector + Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)width, (ndcPos.y + 1.0f)/2.0f*(float)height }; + + return screenPosition; +} + +// Returns the screen space position for a 2d camera world space position +Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera) +{ + Matrix matCamera = GetCameraMatrix2D(camera); + Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera); + + return (Vector2){ transform.x, transform.y }; +} + +// Returns the world space position for a 2d camera screen space position +Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera) +{ + Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera)); + Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera); + + return (Vector2){ transform.x, transform.y }; +} + +// Set target FPS (maximum) +void SetTargetFPS(int fps) +{ + if (fps < 1) CORE.Time.target = 0.0; + else CORE.Time.target = 1.0/(double)fps; + + TRACELOG(LOG_INFO, "TIMER: Target time per frame: %02.03f milliseconds", (float)CORE.Time.target*1000); +} + +// Returns current FPS +// NOTE: We calculate an average framerate +int GetFPS(void) +{ + #define FPS_CAPTURE_FRAMES_COUNT 30 // 30 captures + #define FPS_AVERAGE_TIME_SECONDS 0.5f // 500 millisecondes + #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT) + + static int index = 0; + static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 }; + static float average = 0, last = 0; + float fpsFrame = GetFrameTime(); + + if (fpsFrame == 0) return 0; + + if ((GetTime() - last) > FPS_STEP) + { + last = (float)GetTime(); + index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT; + average -= history[index]; + history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT; + average += history[index]; + } + + return (int)roundf(1.0f/average); +} + +// Returns time in seconds for last frame drawn (delta time) +float GetFrameTime(void) +{ + return (float)CORE.Time.frame; +} + +// Get elapsed time measure in seconds since InitTimer() +// NOTE: On PLATFORM_DESKTOP InitTimer() is called on InitWindow() +// NOTE: On PLATFORM_DESKTOP, timer is initialized on glfwInit() +double GetTime(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + return glfwGetTime(); // Elapsed time since glfwInit() +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + unsigned long long int time = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; + + return (double)(time - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() +#endif + +#if defined(PLATFORM_UWP) + return UWPGetQueryTimeFunc()(); +#endif +} + +// Setup window configuration flags (view FLAGS) +// NOTE: This function is expected to be called before window creation, +// because it setups some flags for the window creation process. +// To configure window states after creation, just use SetWindowState() +void SetConfigFlags(unsigned int flags) +{ + // Selected flags are set but not evaluated at this point, + // flag evaluation happens at InitWindow() or SetWindowState() + CORE.Window.flags |= flags; +} + +// NOTE TRACELOG() function is located in [utils.h] + +// Takes a screenshot of current screen (saved a .png) +// NOTE: This function could work in any platform but some platforms: PLATFORM_ANDROID and PLATFORM_WEB +// have their own internal file-systems, to dowload image to user file-system some additional mechanism is required +void TakeScreenshot(const char *fileName) +{ + unsigned char *imgData = rlReadScreenPixels(CORE.Window.render.width, CORE.Window.render.height); + Image image = { imgData, CORE.Window.render.width, CORE.Window.render.height, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; + + char path[512] = { 0 }; +#if defined(PLATFORM_ANDROID) + strcpy(path, CORE.Android.internalDataPath); + strcat(path, "/"); + strcat(path, fileName); +#elif defined(PLATFORM_UWP) + strcpy(path, CORE.UWP.internalDataPath); + strcat(path, "/"); + strcat(path, fileName); +#else + strcpy(path, fileName); +#endif + + ExportImage(image, path); + RL_FREE(imgData); + +#if defined(PLATFORM_WEB) + // Download file from MEMFS (emscripten memory filesystem) + // saveFileFromMEMFSToDisk() function is defined in raylib/src/shell.html + emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", GetFileName(path), GetFileName(path))); +#endif + + // TODO: Verification required for log + TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path); +} + +// Returns a random value between min and max (both included) +int GetRandomValue(int min, int max) +{ + if (min > max) + { + int tmp = max; + max = min; + min = tmp; + } + + return (rand()%(abs(max - min) + 1) + min); +} + +// Check if the file exists +bool FileExists(const char *fileName) +{ + bool result = false; + +#if defined(_WIN32) + if (_access(fileName, 0) != -1) result = true; +#else + if (access(fileName, F_OK) != -1) result = true; +#endif + + return result; +} + +// Check file extension +// NOTE: Extensions checking is not case-sensitive +bool IsFileExtension(const char *fileName, const char *ext) +{ + bool result = false; + const char *fileExt = GetFileExtension(fileName); + + if (fileExt != NULL) + { +#if defined(SUPPORT_TEXT_MANIPULATION) + int extCount = 0; + const char **checkExts = TextSplit(ext, ';', &extCount); + + char fileExtLower[16] = { 0 }; + strcpy(fileExtLower, TextToLower(fileExt)); + + for (int i = 0; i < extCount; i++) + { + if (TextIsEqual(fileExtLower, TextToLower(checkExts[i]))) + { + result = true; + break; + } + } +#else + if (strcmp(fileExt, ext) == 0) result = true; +#endif + } + + return result; +} + +// Check if a directory path exists +bool DirectoryExists(const char *dirPath) +{ + bool result = false; + DIR *dir = opendir(dirPath); + + if (dir != NULL) + { + result = true; + closedir(dir); + } + + return result; +} + +// Get pointer to extension for a filename string (includes the dot: .png) +const char *GetFileExtension(const char *fileName) +{ + const char *dot = strrchr(fileName, '.'); + + if (!dot || dot == fileName) return NULL; + + return dot; +} + +// String pointer reverse break: returns right-most occurrence of charset in s +static const char *strprbrk(const char *s, const char *charset) +{ + const char *latestMatch = NULL; + for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { } + return latestMatch; +} + +// Get pointer to filename for a path string +const char *GetFileName(const char *filePath) +{ + const char *fileName = NULL; + if (filePath != NULL) fileName = strprbrk(filePath, "\\/"); + + if (!fileName) return filePath; + + return fileName + 1; +} + +// Get filename string without extension (uses static string) +const char *GetFileNameWithoutExt(const char *filePath) +{ + #define MAX_FILENAMEWITHOUTEXT_LENGTH 128 + + static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH]; + memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH); + + if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension + + int len = (int)strlen(fileName); + + for (int i = 0; (i < len) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++) + { + if (fileName[i] == '.') + { + // NOTE: We break on first '.' found + fileName[i] = '\0'; + break; + } + } + + return fileName; +} + +// Get directory for a given filePath +const char *GetDirectoryPath(const char *filePath) +{ +/* + // NOTE: Directory separator is different in Windows and other platforms, + // fortunately, Windows also support the '/' separator, that's the one should be used + #if defined(_WIN32) + char separator = '\\'; + #else + char separator = '/'; + #endif +*/ + const char *lastSlash = NULL; + static char dirPath[MAX_FILEPATH_LENGTH]; + memset(dirPath, 0, MAX_FILEPATH_LENGTH); + + // In case provided path does not contain a root drive letter (C:\, D:\) nor leading path separator (\, /), + // we add the current directory path to dirPath + if (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/') + { + // For security, we set starting path to current directory, + // obtained path will be concated to this + dirPath[0] = '.'; + dirPath[1] = '/'; + } + + lastSlash = strprbrk(filePath, "\\/"); + if (lastSlash) + { + if (lastSlash == filePath) + { + // The last and only slash is the leading one: path is in a root directory + dirPath[0] = filePath[0]; + dirPath[1] = '\0'; + } + else + { + // NOTE: Be careful, strncpy() is not safe, it does not care about '\0' + memcpy(dirPath + (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/' ? 2 : 0), filePath, strlen(filePath) - (strlen(lastSlash) - 1)); + dirPath[strlen(filePath) - strlen(lastSlash) + (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/' ? 2 : 0)] = '\0'; // Add '\0' manually + } + } + + return dirPath; +} + +// Get previous directory path for a given path +const char *GetPrevDirectoryPath(const char *dirPath) +{ + static char prevDirPath[MAX_FILEPATH_LENGTH]; + memset(prevDirPath, 0, MAX_FILEPATH_LENGTH); + int pathLen = (int)strlen(dirPath); + + if (pathLen <= 3) strcpy(prevDirPath, dirPath); + + for (int i = (pathLen - 1); (i >= 0) && (pathLen > 3); i--) + { + if ((dirPath[i] == '\\') || (dirPath[i] == '/')) + { + // Check for root: "C:\" or "/" + if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++; + + strncpy(prevDirPath, dirPath, i); + break; + } + } + + return prevDirPath; +} + +// Get current working directory +const char *GetWorkingDirectory(void) +{ + static char currentDir[MAX_FILEPATH_LENGTH]; + memset(currentDir, 0, MAX_FILEPATH_LENGTH); + + char *ptr = GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1); + + return ptr; +} + +// Get filenames in a directory path (max 512 files) +// NOTE: Files count is returned by parameters pointer +char **GetDirectoryFiles(const char *dirPath, int *fileCount) +{ + #define MAX_DIRECTORY_FILES 512 + + ClearDirectoryFiles(); + + // Memory allocation for MAX_DIRECTORY_FILES + dirFilesPath = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *)); + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char)); + + int counter = 0; + struct dirent *entity; + DIR *dir = opendir(dirPath); + + if (dir != NULL) // It's a directory + { + // TODO: Reading could be done in two passes, + // first one to count files and second one to read names + // That way we can allocate required memory, instead of a limited pool + + while ((entity = readdir(dir)) != NULL) + { + strcpy(dirFilesPath[counter], entity->d_name); + counter++; + } + + closedir(dir); + } + else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file... + + dirFilesCount = counter; + *fileCount = dirFilesCount; + + return dirFilesPath; +} + +// Clear directory files paths buffers +void ClearDirectoryFiles(void) +{ + if (dirFilesCount > 0) + { + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesPath[i]); + + RL_FREE(dirFilesPath); + } + + dirFilesCount = 0; +} + +// Change working directory, returns true on success +bool ChangeDirectory(const char *dir) +{ + bool result = CHDIR(dir); + + if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir); + + return (result == 0); +} + +// Check if a file has been dropped into window +bool IsFileDropped(void) +{ + if (CORE.Window.dropFilesCount > 0) return true; + else return false; +} + +// Get dropped files names +char **GetDroppedFiles(int *count) +{ + *count = CORE.Window.dropFilesCount; + return CORE.Window.dropFilesPath; +} + +// Clear dropped files paths buffer +void ClearDroppedFiles(void) +{ + if (CORE.Window.dropFilesCount > 0) + { + for (int i = 0; i < CORE.Window.dropFilesCount; i++) RL_FREE(CORE.Window.dropFilesPath[i]); + + RL_FREE(CORE.Window.dropFilesPath); + + CORE.Window.dropFilesCount = 0; + } +} + +// Get file modification time (last write time) +long GetFileModTime(const char *fileName) +{ + struct stat result = { 0 }; + + if (stat(fileName, &result) == 0) + { + time_t mod = result.st_mtime; + + return (long)mod; + } + + return 0; +} + +// Compress data (DEFLATE algorythm) +unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength) +{ + #define COMPRESSION_QUALITY_DEFLATE 8 + + unsigned char *compData = NULL; + +#if defined(SUPPORT_COMPRESSION_API) + // Compress data and generate a valid DEFLATE stream + struct sdefl sdefl = { 0 }; + int bounds = sdefl_bound(dataLength); + compData = (unsigned char *)RL_CALLOC(bounds, 1); + *compDataLength = sdeflate(&sdefl, compData, data, dataLength, COMPRESSION_QUALITY_DEFLATE); // Compression level 8, same as stbwi + + TraceLog(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataLength, compDataLength); +#endif + + return compData; +} + +// Decompress data (DEFLATE algorythm) +unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength) +{ + unsigned char *data = NULL; + +#if defined(SUPPORT_COMPRESSION_API) + // Decompress data from a valid DEFLATE stream + data = RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1); + int length = sinflate(data, compData, compDataLength); + unsigned char *temp = RL_REALLOC(data, length); + + if (temp != NULL) data = temp; + else TRACELOG(LOG_WARNING, "SYSTEM: Failed to re-allocate required decompression memory"); + + *dataLength = length; + + TraceLog(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataLength, dataLength); +#endif + + return data; +} + +// Save integer value to storage file (to defined position) +// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer) +bool SaveStorageValue(unsigned int position, int value) +{ + bool success = false; + +#if defined(SUPPORT_DATA_STORAGE) + char path[512] = { 0 }; +#if defined(PLATFORM_ANDROID) + strcpy(path, CORE.Android.internalDataPath); + strcat(path, "/"); + strcat(path, STORAGE_DATA_FILE); +#elif defined(PLATFORM_UWP) + strcpy(path, CORE.UWP.internalDataPath); + strcat(path, "/"); + strcat(path, STORAGE_DATA_FILE); +#else + strcpy(path, STORAGE_DATA_FILE); +#endif + + unsigned int dataSize = 0; + unsigned int newDataSize = 0; + unsigned char *fileData = LoadFileData(path, &dataSize); + unsigned char *newFileData = NULL; + + if (fileData != NULL) + { + if (dataSize <= (position*sizeof(int))) + { + // Increase data size up to position and store value + newDataSize = (position + 1)*sizeof(int); + newFileData = (unsigned char *)RL_REALLOC(fileData, newDataSize); + + if (newFileData != NULL) + { + // RL_REALLOC succeded + int *dataPtr = (int *)newFileData; + dataPtr[position] = value; + } + else + { + // RL_REALLOC failed + TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to realloc data (%u), position in bytes (%u) bigger than actual file size", path, dataSize, position*sizeof(int)); + + // We store the old size of the file + newFileData = fileData; + newDataSize = dataSize; + } + } + else + { + // Store the old size of the file + newFileData = fileData; + newDataSize = dataSize; + + // Replace value on selected position + int *dataPtr = (int *)newFileData; + dataPtr[position] = value; + } + + success = SaveFileData(path, newFileData, newDataSize); + RL_FREE(newFileData); + } + else + { + TRACELOG(LOG_INFO, "FILEIO: [%s] File not found, creating it", path); + + dataSize = (position + 1)*sizeof(int); + fileData = (unsigned char *)RL_MALLOC(dataSize); + int *dataPtr = (int *)fileData; + dataPtr[position] = value; + + success = SaveFileData(path, fileData, dataSize); + UnloadFileData(fileData); + } +#endif + + return success; +} + +// Load integer value from storage file (from defined position) +// NOTE: If requested position could not be found, value 0 is returned +int LoadStorageValue(unsigned int position) +{ + int value = 0; + +#if defined(SUPPORT_DATA_STORAGE) + char path[512] = { 0 }; +#if defined(PLATFORM_ANDROID) + strcpy(path, CORE.Android.internalDataPath); + strcat(path, "/"); + strcat(path, STORAGE_DATA_FILE); +#elif defined(PLATFORM_UWP) + strcpy(path, CORE.UWP.internalDataPath); + strcat(path, "/"); + strcat(path, STORAGE_DATA_FILE); +#else + strcpy(path, STORAGE_DATA_FILE); +#endif + + unsigned int dataSize = 0; + unsigned char *fileData = LoadFileData(path, &dataSize); + + if (fileData != NULL) + { + if (dataSize < (position*4)) TRACELOG(LOG_WARNING, "SYSTEM: Failed to find storage position"); + else + { + int *dataPtr = (int *)fileData; + value = dataPtr[position]; + } + + UnloadFileData(fileData); + } +#endif + return value; +} + +// Open URL with default system browser (if available) +// NOTE: This function is only safe to use if you control the URL given. +// A user could craft a malicious string performing another action. +// Only call this function yourself not with user input or make sure to check the string yourself. +// Ref: https://github.com/raysan5/raylib/issues/686 +void OpenURL(const char *url) +{ + // Small security check trying to avoid (partially) malicious code... + // sorry for the inconvenience when you hit this point... + if (strchr(url, '\'') != NULL) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL is not valid"); + } + else + { +#if defined(PLATFORM_DESKTOP) + char *cmd = (char *)RL_CALLOC(strlen(url) + 10, sizeof(char)); + #if defined(_WIN32) + sprintf(cmd, "explorer %s", url); + #endif + #if defined(__linux__) || defined(__FreeBSD__) + sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser + #endif + #if defined(__APPLE__) + sprintf(cmd, "open '%s'", url); + #endif + system(cmd); + RL_FREE(cmd); +#endif +#if defined(PLATFORM_WEB) + emscripten_run_script(TextFormat("window.open('%s', '_blank')", url)); +#endif + } +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions +//---------------------------------------------------------------------------------- +// Detect if a key has been pressed once +bool IsKeyPressed(int key) +{ + bool pressed = false; + + if ((CORE.Input.Keyboard.previousKeyState[key] == 0) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true; + else pressed = false; + + return pressed; +} + +// Detect if a key is being pressed (key held down) +bool IsKeyDown(int key) +{ + if (CORE.Input.Keyboard.currentKeyState[key] == 1) return true; + else return false; +} + +// Detect if a key has been released once +bool IsKeyReleased(int key) +{ + bool released = false; + + if ((CORE.Input.Keyboard.previousKeyState[key] == 1) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true; + else released = false; + + return released; +} + +// Detect if a key is NOT being pressed (key not held down) +bool IsKeyUp(int key) +{ + if (CORE.Input.Keyboard.currentKeyState[key] == 0) return true; + else return false; +} + +// Get the last key pressed +int GetKeyPressed(void) +{ + int value = 0; + + if (CORE.Input.Keyboard.keyPressedQueueCount > 0) + { + // Get character from the queue head + value = CORE.Input.Keyboard.keyPressedQueue[0]; + + // Shift elements 1 step toward the head. + for (int i = 0; i < (CORE.Input.Keyboard.keyPressedQueueCount - 1); i++) + CORE.Input.Keyboard.keyPressedQueue[i] = CORE.Input.Keyboard.keyPressedQueue[i + 1]; + + // Reset last character in the queue + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 0; + CORE.Input.Keyboard.keyPressedQueueCount--; + } + + return value; +} + +// Get the last char pressed +int GetCharPressed(void) +{ + int value = 0; + + if (CORE.Input.Keyboard.charPressedQueueCount > 0) + { + // Get character from the queue head + value = CORE.Input.Keyboard.charPressedQueue[0]; + + // Shift elements 1 step toward the head. + for (int i = 0; i < (CORE.Input.Keyboard.charPressedQueueCount - 1); i++) + CORE.Input.Keyboard.charPressedQueue[i] = CORE.Input.Keyboard.charPressedQueue[i + 1]; + + // Reset last character in the queue + CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = 0; + CORE.Input.Keyboard.charPressedQueueCount--; + } + + return value; +} + +// Set a custom key to exit program +// NOTE: default exitKey is ESCAPE +void SetExitKey(int key) +{ +#if !defined(PLATFORM_ANDROID) + CORE.Input.Keyboard.exitKey = key; +#endif +} + +// NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) + +// Detect if a gamepad is available +bool IsGamepadAvailable(int gamepad) +{ + bool result = false; + + if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true; + + return result; +} + +// Check gamepad name (if available) +bool IsGamepadName(int gamepad, const char *name) +{ + bool result = false; + const char *currentName = NULL; + + if (CORE.Input.Gamepad.ready[gamepad]) currentName = GetGamepadName(gamepad); + if ((name != NULL) && (currentName != NULL)) result = (strcmp(name, currentName) == 0); + + return result; +} + +// Return gamepad internal name id +const char *GetGamepadName(int gamepad) +{ +#if defined(PLATFORM_DESKTOP) + if (CORE.Input.Gamepad.ready[gamepad]) return glfwGetJoystickName(gamepad); + else return NULL; +#endif +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name); + return CORE.Input.Gamepad.name; +#endif + return NULL; +} + +// Return gamepad axis count +int GetGamepadAxisCount(int gamepad) +{ +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + int axisCount = 0; + if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGAXES, &axisCount); + CORE.Input.Gamepad.axisCount = axisCount; +#endif + + return CORE.Input.Gamepad.axisCount; +} + +// Return axis movement vector for a gamepad +float GetGamepadAxisMovement(int gamepad, int axis) +{ + float value = 0; + + if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS) && + (fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]) > 0.1f)) value = CORE.Input.Gamepad.axisState[gamepad][axis]; // 0.1f = GAMEPAD_AXIS_MINIMUM_DRIFT/DELTA + + return value; +} + +// Detect if a gamepad button has been pressed once +bool IsGamepadButtonPressed(int gamepad, int button) +{ + bool pressed = false; + + if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + (CORE.Input.Gamepad.previousState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentState[gamepad][button] == 1)) pressed = true; + else pressed = false; + + return pressed; +} + +// Detect if a gamepad button is being pressed +bool IsGamepadButtonDown(int gamepad, int button) +{ + bool result = false; + + if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + (CORE.Input.Gamepad.currentState[gamepad][button] == 1)) result = true; + + return result; +} + +// Detect if a gamepad button has NOT been pressed once +bool IsGamepadButtonReleased(int gamepad, int button) +{ + bool released = false; + + if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + (CORE.Input.Gamepad.previousState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentState[gamepad][button] == 0)) released = true; + else released = false; + + return released; +} + +// Detect if a gamepad button is NOT being pressed +bool IsGamepadButtonUp(int gamepad, int button) +{ + bool result = false; + + if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + (CORE.Input.Gamepad.currentState[gamepad][button] == 0)) result = true; + + return result; +} + +// Get the last gamepad button pressed +int GetGamepadButtonPressed(void) +{ + return CORE.Input.Gamepad.lastButtonPressed; +} + +// Set internal gamepad mappings +int SetGamepadMappings(const char *mappings) +{ + int result = 0; + +#if defined(PLATFORM_DESKTOP) + result = glfwUpdateGamepadMappings(mappings); +#endif + + return result; +} + +// Detect if a mouse button has been pressed once +bool IsMouseButtonPressed(int button) +{ + bool pressed = false; + + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true; + + // Map touches to mouse buttons checking + if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true; + + return pressed; +} + +// Detect if a mouse button is being pressed +bool IsMouseButtonDown(int button) +{ + bool down = false; + + if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true; + + // Map touches to mouse buttons checking + if (CORE.Input.Touch.currentTouchState[button] == 1) down = true; + + return down; +} + +// Detect if a mouse button has been released once +bool IsMouseButtonReleased(int button) +{ + bool released = false; + + if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true; + + // Map touches to mouse buttons checking + if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true; + + return released; +} + +// Detect if a mouse button is NOT being pressed +bool IsMouseButtonUp(int button) +{ + return !IsMouseButtonDown(button); +} + +// Returns mouse position X +int GetMouseX(void) +{ +#if defined(PLATFORM_ANDROID) + return (int)CORE.Input.Touch.position[0].x; +#else + return (int)((CORE.Input.Mouse.position.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x); +#endif +} + +// Returns mouse position Y +int GetMouseY(void) +{ +#if defined(PLATFORM_ANDROID) + return (int)CORE.Input.Touch.position[0].y; +#else + return (int)((CORE.Input.Mouse.position.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y); +#endif +} + +// Returns mouse position XY +Vector2 GetMousePosition(void) +{ + Vector2 position = { 0 }; + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) + position = GetTouchPosition(0); +#else + position.x = (CORE.Input.Mouse.position.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x; + position.y = (CORE.Input.Mouse.position.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y; +#endif + + return position; +} + +// Set mouse position XY +void SetMousePosition(int x, int y) +{ + CORE.Input.Mouse.position = (Vector2){ (float)x, (float)y }; +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + // NOTE: emscripten not implemented + glfwSetCursorPos(CORE.Window.handle, CORE.Input.Mouse.position.x, CORE.Input.Mouse.position.y); +#endif +#if defined(PLATFORM_UWP) + UWPGetMouseSetPosFunc()(x, y); +#endif +} + +// Set mouse offset +// NOTE: Useful when rendering to different size targets +void SetMouseOffset(int offsetX, int offsetY) +{ + CORE.Input.Mouse.offset = (Vector2){ (float)offsetX, (float)offsetY }; +} + +// Set mouse scaling +// NOTE: Useful when rendering to different size targets +void SetMouseScale(float scaleX, float scaleY) +{ + CORE.Input.Mouse.scale = (Vector2){ scaleX, scaleY }; +} + +// Returns mouse wheel movement Y +float GetMouseWheelMove(void) +{ +#if defined(PLATFORM_ANDROID) + return 0.0f; +#endif +#if defined(PLATFORM_WEB) + return CORE.Input.Mouse.previousWheelMove/100.0f; +#endif + + return CORE.Input.Mouse.previousWheelMove; +} + +// Set mouse cursor +// NOTE: This is a no-op on platforms other than PLATFORM_DESKTOP +void SetMouseCursor(int cursor) +{ +#if defined(PLATFORM_DESKTOP) + CORE.Input.Mouse.cursor = cursor; + if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(CORE.Window.handle, NULL); + else + { + // NOTE: We are relating internal GLFW enum values to our MouseCursor enum values + glfwSetCursor(CORE.Window.handle, glfwCreateStandardCursor(0x00036000 + cursor)); + } +#endif +} + +// Returns touch position X for touch point 0 (relative to screen size) +int GetTouchX(void) +{ +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) + return (int)CORE.Input.Touch.position[0].x; +#else // PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM + return GetMouseX(); +#endif +} + +// Returns touch position Y for touch point 0 (relative to screen size) +int GetTouchY(void) +{ +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) + return (int)CORE.Input.Touch.position[0].y; +#else // PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM + return GetMouseY(); +#endif +} + +// Returns touch position XY for a touch point index (relative to screen size) +// TODO: Touch position should be scaled depending on display size and render size +Vector2 GetTouchPosition(int index) +{ + Vector2 position = { -1.0f, -1.0f }; + +#if defined(PLATFORM_DESKTOP) + // TODO: GLFW does not support multi-touch input just yet + // https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch + // https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages + if (index == 0) position = GetMousePosition(); +#endif +#if defined(PLATFORM_ANDROID) + if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index]; + else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); + + if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height)) + { + position.x = position.x*((float)CORE.Window.screen.width/(float)(CORE.Window.display.width - CORE.Window.renderOffset.x)) - CORE.Window.renderOffset.x/2; + position.y = position.y*((float)CORE.Window.screen.height/(float)(CORE.Window.display.height - CORE.Window.renderOffset.y)) - CORE.Window.renderOffset.y/2; + } + else + { + position.x = position.x*((float)CORE.Window.render.width/(float)CORE.Window.display.width) - CORE.Window.renderOffset.x/2; + position.y = position.y*((float)CORE.Window.render.height/(float)CORE.Window.display.height) - CORE.Window.renderOffset.y/2; + } +#endif +#if defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) + if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index]; + else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); + + // TODO: Touch position scaling required? +#endif + + return position; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +// Initialize display device and framebuffer +// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size +// If width or height are 0, default display size will be used for framebuffer size +// NOTE: returns false in case graphic device could not be created +static bool InitGraphicsDevice(int width, int height) +{ + CORE.Window.screen.width = width; // User desired width + CORE.Window.screen.height = height; // User desired height + CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default + + // NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars... + // ...in top-down or left-right to match display aspect ratio (no weird scalings) + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + glfwSetErrorCallback(ErrorCallback); + +#if defined(__APPLE__) + glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE); +#endif + + if (!glfwInit()) + { + TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW"); + return false; + } + + // NOTE: Getting video modes is not implemented in emscripten GLFW3 version +#if defined(PLATFORM_DESKTOP) + // Find monitor resolution + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + if (!monitor) + { + TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor"); + return false; + } + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + + CORE.Window.display.width = mode->width; + CORE.Window.display.height = mode->height; + + // Screen size security check + if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; + if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; +#endif // PLATFORM_DESKTOP + +#if defined(PLATFORM_WEB) + CORE.Window.display.width = CORE.Window.screen.width; + CORE.Window.display.height = CORE.Window.screen.height; +#endif // PLATFORM_WEB + + glfwDefaultWindowHints(); // Set default windows hints + //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits + //glfwWindowHint(GLFW_GREEN_BITS, 8); // Framebuffer green color component bits + //glfwWindowHint(GLFW_BLUE_BITS, 8); // Framebuffer blue color component bits + //glfwWindowHint(GLFW_ALPHA_BITS, 8); // Framebuffer alpha color component bits + //glfwWindowHint(GLFW_DEPTH_BITS, 24); // Depthbuffer bits + //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window + //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API + //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers + + // Check window creation flags + if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; + + if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window + else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden + + if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window + else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window + + if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window + else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable + + // Disable FLAG_WINDOW_MINIMIZED, not supported on initialization + if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; + + // Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization + if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; + + if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE); + else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); + + if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); + else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); + + // NOTE: Some GLFW flags are not supported on HTML5 +#if defined(PLATFORM_DESKTOP) + if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer + else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer + + if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) + { + // Resize window content area based on the monitor content scale. + // NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11. + // On platforms like macOS the resolution of the framebuffer is changed independently of the window size. + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on + #if defined(__APPLE__) + glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); + #endif + } + else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); +#endif + + if (CORE.Window.flags & FLAG_MSAA_4X_HINT) + { + // NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs + TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); + glfwWindowHint(GLFW_SAMPLES, 4); // Tries to enable multisampling x4 (MSAA), default is 0 + } + + // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version + // with forward compatibility to older OpenGL versions. + // For example, if using OpenGL 1.1, driver can provide a 4.3 context forward compatible. + + // Check selection OpenGL version + if (rlGetVersion() == OPENGL_21) + { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // Choose OpenGL major version (just hint) + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // Choose OpenGL minor version (just hint) + } + else if (rlGetVersion() == OPENGL_33) + { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint) + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above! + // Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE +#if defined(__APPLE__) + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // OSX Requires fordward compatibility +#else + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Fordward Compatibility Hint: Only 3.3 and above! +#endif + //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context + } + else if (rlGetVersion() == OPENGL_ES_20) // Request OpenGL ES 2.0 context + { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); +#if defined(PLATFORM_DESKTOP) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); +#else + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); +#endif + } + +#if defined(PLATFORM_DESKTOP) + // NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions. + // Forcing this initialization here avoids doing it on `PollInputEvents` called by `EndDrawing` after first frame has been just drawn. + // The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience. + // REF: https://github.com/raysan5/raylib/issues/1554 + if (MAX_GAMEPADS > 0) glfwSetJoystickCallback(NULL); +#endif + + if (CORE.Window.fullscreen) + { + // remember center for switchinging from fullscreen to window + CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2; + CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2; + + if (CORE.Window.position.x < 0) CORE.Window.position.x = 0; + if (CORE.Window.position.y < 0) CORE.Window.position.y = 0; + + // Obtain recommended CORE.Window.display.width/CORE.Window.display.height from a valid videomode for the monitor + int count = 0; + const GLFWvidmode *modes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count); + + // Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height + for (int i = 0; i < count; i++) + { + if ((unsigned int)modes[i].width >= CORE.Window.screen.width) + { + if ((unsigned int)modes[i].height >= CORE.Window.screen.height) + { + CORE.Window.display.width = modes[i].width; + CORE.Window.display.height = modes[i].height; + break; + } + } + } + +#if defined(PLATFORM_DESKTOP) + // If we are windowed fullscreen, ensures that window does not minimize when focus is lost + if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) + { + glfwWindowHint(GLFW_AUTO_ICONIFY, 0); + } +#endif + TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); + + // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, + // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3), + // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched + // by the sides to fit all monitor space... + + // Try to setup the most appropiate fullscreen framebuffer for the requested screenWidth/screenHeight + // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset) + // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale + // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed... + // HighDPI monitors are properly considered in a following similar function: SetupViewport() + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); + + CORE.Window.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL); + + // NOTE: Full-screen change, not working properly... + //glfwSetWindowMonitor(CORE.Window.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + } + else + { + // No-fullscreen window creation + CORE.Window.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); + + if (CORE.Window.handle) + { +#if defined(PLATFORM_DESKTOP) + // Center window on screen + int windowPosX = CORE.Window.display.width/2 - CORE.Window.screen.width/2; + int windowPosY = CORE.Window.display.height/2 - CORE.Window.screen.height/2; + + if (windowPosX < 0) windowPosX = 0; + if (windowPosY < 0) windowPosY = 0; + + glfwSetWindowPos(CORE.Window.handle, windowPosX, windowPosY); +#endif + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + } + } + + if (!CORE.Window.handle) + { + glfwTerminate(); + TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); + return false; + } + else + { + TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); +#if defined(PLATFORM_DESKTOP) + TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); +#endif + TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); + TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); + TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); + } + + // Set window callback events + glfwSetWindowSizeCallback(CORE.Window.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! +#if !defined(PLATFORM_WEB) + glfwSetWindowMaximizeCallback(CORE.Window.handle, WindowMaximizeCallback); +#endif + glfwSetWindowIconifyCallback(CORE.Window.handle, WindowIconifyCallback); + glfwSetWindowFocusCallback(CORE.Window.handle, WindowFocusCallback); + glfwSetDropCallback(CORE.Window.handle, WindowDropCallback); + // Set input callback events + glfwSetKeyCallback(CORE.Window.handle, KeyCallback); + glfwSetCharCallback(CORE.Window.handle, CharCallback); + glfwSetMouseButtonCallback(CORE.Window.handle, MouseButtonCallback); + glfwSetCursorPosCallback(CORE.Window.handle, MouseCursorPosCallback); // Track mouse position changes + glfwSetScrollCallback(CORE.Window.handle, MouseScrollCallback); + glfwSetCursorEnterCallback(CORE.Window.handle, CursorEnterCallback); + + glfwMakeContextCurrent(CORE.Window.handle); + +#if !defined(PLATFORM_WEB) + glfwSwapInterval(0); // No V-Sync by default +#endif + + // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) + // NOTE: V-Sync can be enabled by graphic driver configuration + if (CORE.Window.flags & FLAG_VSYNC_HINT) + { + // WARNING: It seems to hits a critical render path in Intel HD Graphics + glfwSwapInterval(1); + TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC"); + } +#endif // PLATFORM_DESKTOP || PLATFORM_WEB + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) + CORE.Window.fullscreen = true; + CORE.Window.flags |= FLAG_FULLSCREEN_MODE; + +#if defined(PLATFORM_RPI) + bcm_host_init(); + + DISPMANX_ELEMENT_HANDLE_T dispmanElement; + DISPMANX_DISPLAY_HANDLE_T dispmanDisplay; + DISPMANX_UPDATE_HANDLE_T dispmanUpdate; + + VC_RECT_T dstRect; + VC_RECT_T srcRect; +#endif + +#if defined(PLATFORM_DRM) + CORE.Window.fd = -1; + CORE.Window.connector = NULL; + CORE.Window.modeIndex = -1; + CORE.Window.crtc = NULL; + CORE.Window.gbmDevice = NULL; + CORE.Window.gbmSurface = NULL; + CORE.Window.prevBO = NULL; + CORE.Window.prevFB = 0; + +#if defined(DEFAULT_GRAPHIC_DEVICE_DRM) + CORE.Window.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); +#else + TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying card1"); + CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // VideoCore VI (Raspberry Pi 4) + if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL)) + { + TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0"); + CORE.Window.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) + } +#endif + if (-1 == CORE.Window.fd) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card"); + return false; + } + + drmModeRes *res = drmModeGetResources(CORE.Window.fd); + if (!res) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources"); + return false; + } + + TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors); + for (size_t i = 0; i < res->count_connectors; i++) + { + TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i); + drmModeConnector *con = drmModeGetConnector(CORE.Window.fd, res->connectors[i]); + TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); + if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id)) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); + CORE.Window.connector = con; + break; + } + else + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); + drmModeFreeConnector(con); + } + } + if (!CORE.Window.connector) + { + TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found"); + drmModeFreeResources(res); + return false; + } + + drmModeEncoder *enc = drmModeGetEncoder(CORE.Window.fd, CORE.Window.connector->encoder_id); + if (!enc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); + drmModeFreeResources(res); + return false; + } + + CORE.Window.crtc = drmModeGetCrtc(CORE.Window.fd, enc->crtc_id); + if (!CORE.Window.crtc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); + drmModeFreeEncoder(enc); + drmModeFreeResources(res); + return false; + } + + // If InitWindow should use the current mode find it in the connector's mode list + if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0)) + { + TRACELOG(LOG_TRACE, "DISPLAY: Selecting DRM connector mode for current used mode..."); + + CORE.Window.modeIndex = FindMatchingConnectorMode(CORE.Window.connector, &CORE.Window.crtc->mode); + + if (CORE.Window.modeIndex < 0) + { + TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found"); + drmModeFreeEncoder(enc); + drmModeFreeResources(res); + return false; + } + + CORE.Window.screen.width = CORE.Window.display.width; + CORE.Window.screen.height = CORE.Window.display.height; + } + + const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT; + const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60; + // try to find an exact matching mode + CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); + // if nothing found, try to find a nearly matching mode + if (CORE.Window.modeIndex < 0) + CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); + // if nothing found, try to find an exactly matching mode including interlaced + if (CORE.Window.modeIndex < 0) + CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); + // if nothing found, try to find a nearly matching mode including interlaced + if (CORE.Window.modeIndex < 0) + CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); + // if nothing found, there is no suitable mode + if (CORE.Window.modeIndex < 0) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode"); + drmModeFreeEncoder(enc); + drmModeFreeResources(res); + return false; + } + + CORE.Window.display.width = CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay; + CORE.Window.display.height = CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay; + + TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", CORE.Window.connector->modes[CORE.Window.modeIndex].name, + CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, + (CORE.Window.connector->modes[CORE.Window.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p', + CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh); + + // Use the width and height of the surface for render + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + + drmModeFreeEncoder(enc); + enc = NULL; + + drmModeFreeResources(res); + res = NULL; + + CORE.Window.gbmDevice = gbm_create_device(CORE.Window.fd); + if (!CORE.Window.gbmDevice) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM device"); + return false; + } + + CORE.Window.gbmSurface = gbm_surface_create(CORE.Window.gbmDevice, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, + CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!CORE.Window.gbmSurface) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM surface"); + return false; + } +#endif + + EGLint samples = 0; + EGLint sampleBuffer = 0; + if (CORE.Window.flags & FLAG_MSAA_4X_HINT) + { + samples = 4; + sampleBuffer = 1; + TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); + } + + const EGLint framebufferAttribs[] = + { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI? +#if defined(PLATFORM_DRM) + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! +#endif + EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) + EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) + EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) +#if defined(PLATFORM_DRM) + EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer) +#endif + //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) + EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) + //EGL_STENCIL_SIZE, 8, // Stencil buffer size + EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA + EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) + EGL_NONE + }; + + const EGLint contextAttribs[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + +#if defined(PLATFORM_UWP) + const EGLint surfaceAttributes[] = + { + // EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is part of the same optimization as EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (see above). + // If you have compilation issues with it then please update your Visual Studio templates. + EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_NONE + }; + + const EGLint defaultDisplayAttributes[] = + { + // These are the default display attributes, used to request ANGLE's D3D11 renderer. + // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + + // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices. + // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it. + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + + // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call + // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. + // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + const EGLint fl9_3DisplayAttributes[] = + { + // These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3. + // These attributes are used if the call to eglInitialize fails with the default display attributes. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + const EGLint warpDisplayAttributes[] = + { + // These attributes can be used to request D3D11 WARP. + // They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + // eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11. + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)(eglGetProcAddress("eglGetPlatformDisplayEXT")); + if (!eglGetPlatformDisplayEXT) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get function pointer: eglGetPlatformDisplayEXT()"); + return false; + } + + // + // To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying + // parameters passed to eglGetPlatformDisplayEXT: + // 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+. + // 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again + // using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3. + // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again + // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer. + // + + // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. + CORE.Window.device = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); + if (CORE.Window.device == EGL_NO_DISPLAY) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + return false; + } + + if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE) + { + // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices). + CORE.Window.device = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + if (CORE.Window.device == EGL_NO_DISPLAY) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + return false; + } + + if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE) + { + // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. + CORE.Window.device = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); + if (CORE.Window.device == EGL_NO_DISPLAY) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + return false; + } + + if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE) + { + // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. + TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + return false; + } + } + } + + EGLint numConfigs = 0; + if ((eglChooseConfig(CORE.Window.device, framebufferAttribs, &CORE.Window.config, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0)) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose first EGL configuration"); + return false; + } + + // Create a PropertySet and initialize with the EGLNativeWindowType. + //PropertySet^ surfaceCreationProperties = ref new PropertySet(); + //surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), window); // CoreWindow^ window + + // You can configure the surface to render at a lower resolution and be scaled up to + // the full window size. The scaling is often free on mobile hardware. + // + // One way to configure the SwapChainPanel is to specify precisely which resolution it should render at. + // Size customRenderSurfaceSize = Size(800, 600); + // surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(customRenderSurfaceSize)); + // + // Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size. + // e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640 + // float customResolutionScale = 0.5f; + // surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(customResolutionScale)); + + + // eglCreateWindowSurface() requires a EGLNativeWindowType parameter, + // In Windows platform: typedef HWND EGLNativeWindowType; + + + // Property: EGLNativeWindowTypeProperty + // Type: IInspectable + // Description: Set this property to specify the window type to use for creating a surface. + // If this property is missing, surface creation will fail. + // + //const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty"; + + //https://stackoverflow.com/questions/46550182/how-to-create-eglsurface-using-c-winrt-and-angle + + //CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, reinterpret_cast(surfaceCreationProperties), surfaceAttributes); + CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, (EGLNativeWindowType) UWPGetCoreWindowPtr(), surfaceAttributes); + if (CORE.Window.surface == EGL_NO_SURFACE) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL fullscreen surface"); + return false; + } + + CORE.Window.context = eglCreateContext(CORE.Window.device, CORE.Window.config, EGL_NO_CONTEXT, contextAttribs); + if (CORE.Window.context == EGL_NO_CONTEXT) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); + return false; + } + + // Get EGL device window size + eglQuerySurface(CORE.Window.device, CORE.Window.surface, EGL_WIDTH, &CORE.Window.screen.width); + eglQuerySurface(CORE.Window.device, CORE.Window.surface, EGL_HEIGHT, &CORE.Window.screen.height); + + // Get display size + UWPGetDisplaySizeFunc()(&CORE.Window.display.width, &CORE.Window.display.height); + + // Use the width and height of the surface for render + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + +#endif // PLATFORM_UWP + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + EGLint numConfigs = 0; + + // Get an EGL device connection +#if defined(PLATFORM_DRM) + CORE.Window.device = eglGetDisplay((EGLNativeDisplayType)CORE.Window.gbmDevice); +#else + CORE.Window.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); +#endif + if (CORE.Window.device == EGL_NO_DISPLAY) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + return false; + } + + // Initialize the EGL device connection + if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE) + { + // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. + TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + return false; + } + +#if defined(PLATFORM_DRM) + if (!eglChooseConfig(CORE.Window.device, NULL, NULL, 0, &numConfigs)) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError()); + return false; + } + + TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs); + + EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs)); + if (!configs) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs"); + return false; + } + + EGLint matchingNumConfigs = 0; + if (!eglChooseConfig(CORE.Window.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs)) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError()); + free(configs); + return false; + } + + TRACELOG(LOG_TRACE, "DISPLAY: EGL matching configs available: %d", matchingNumConfigs); + + // find the EGL config that matches the previously setup GBM format + int found = 0; + for (EGLint i = 0; i < matchingNumConfigs; ++i) + { + EGLint id = 0; + if (!eglGetConfigAttrib(CORE.Window.device, configs[i], EGL_NATIVE_VISUAL_ID, &id)) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config attribute: 0x%x", eglGetError()); + continue; + } + + if (GBM_FORMAT_ARGB8888 == id) + { + TRACELOG(LOG_TRACE, "DISPLAY: Using EGL config: %d", i); + CORE.Window.config = configs[i]; + found = 1; + break; + } + } + + RL_FREE(configs); + + if (!found) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable EGL config"); + return false; + } +#else + // Get an appropriate EGL framebuffer configuration + eglChooseConfig(CORE.Window.device, framebufferAttribs, &CORE.Window.config, 1, &numConfigs); +#endif + + // Set rendering API + eglBindAPI(EGL_OPENGL_ES_API); + + // Create an EGL rendering context + CORE.Window.context = eglCreateContext(CORE.Window.device, CORE.Window.config, EGL_NO_CONTEXT, contextAttribs); + if (CORE.Window.context == EGL_NO_CONTEXT) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); + return false; + } +#endif + + // Create an EGL window surface + //--------------------------------------------------------------------------------- +#if defined(PLATFORM_ANDROID) + EGLint displayFormat = 0; + + // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry() + // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID + eglGetConfigAttrib(CORE.Window.device, CORE.Window.config, EGL_NATIVE_VISUAL_ID, &displayFormat); + + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); + + ANativeWindow_setBuffersGeometry(CORE.Android.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); + //ANativeWindow_setBuffersGeometry(CORE.Android.app->window, 0, 0, displayFormat); // Force use of native display size + + CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, CORE.Android.app->window, NULL); +#endif // PLATFORM_ANDROID + +#if defined(PLATFORM_RPI) + graphics_get_display_size(0, &CORE.Window.display.width, &CORE.Window.display.height); + + // Screen size security check + if (CORE.Window.screen.width <= 0) CORE.Window.screen.width = CORE.Window.display.width; + if (CORE.Window.screen.height <= 0) CORE.Window.screen.height = CORE.Window.display.height; + + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); + + dstRect.x = 0; + dstRect.y = 0; + dstRect.width = CORE.Window.display.width; + dstRect.height = CORE.Window.display.height; + + srcRect.x = 0; + srcRect.y = 0; + srcRect.width = CORE.Window.render.width << 16; + srcRect.height = CORE.Window.render.height << 16; + + // NOTE: RPI dispmanx windowing system takes care of source rectangle scaling to destination rectangle by hardware (no cost) + // Take care that renderWidth/renderHeight fit on displayWidth/displayHeight aspect ratio + + VC_DISPMANX_ALPHA_T alpha; + alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; + //alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE; // TODO: Allow transparent framebuffer! -> FLAG_WINDOW_TRANSPARENT + alpha.opacity = 255; // Set transparency level for framebuffer, requires EGLAttrib: EGL_TRANSPARENT_TYPE + alpha.mask = 0; + + dispmanDisplay = vc_dispmanx_display_open(0); // LCD + dispmanUpdate = vc_dispmanx_update_start(0); + + dispmanElement = vc_dispmanx_element_add(dispmanUpdate, dispmanDisplay, 0/*layer*/, &dstRect, 0/*src*/, + &srcRect, DISPMANX_PROTECTION_NONE, &alpha, 0/*clamp*/, DISPMANX_NO_ROTATE); + + CORE.Window.handle.element = dispmanElement; + CORE.Window.handle.width = CORE.Window.render.width; + CORE.Window.handle.height = CORE.Window.render.height; + vc_dispmanx_update_submit_sync(dispmanUpdate); + + CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, &CORE.Window.handle, NULL); + + const unsigned char *const renderer = glGetString(GL_RENDERER); + if (renderer) TRACELOG(LOG_INFO, "DISPLAY: Renderer name is: %s", renderer); + else TRACELOG(LOG_WARNING, "DISPLAY: Failed to get renderer name"); + //--------------------------------------------------------------------------------- +#endif // PLATFORM_RPI + +#if defined(PLATFORM_DRM) + CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, (EGLNativeWindowType)CORE.Window.gbmSurface, NULL); + if (EGL_NO_SURFACE == CORE.Window.surface) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError()); + return false; + } + + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); +#endif // PLATFORM_DRM + + // There must be at least one frame displayed before the buffers are swapped + //eglSwapInterval(CORE.Window.device, 1); + + if (eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context) == EGL_FALSE) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface"); + return false; + } + else + { + TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); + TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); + TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); + TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); + TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); + } +#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP + + // Load OpenGL extensions + // NOTE: GL procedures address loader is required to load extensions +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + rlLoadExtensions(glfwGetProcAddress); +#else + rlLoadExtensions(eglGetProcAddress); +#endif + + // Initialize OpenGL context (states and resources) + // NOTE: CORE.Window.screen.width and CORE.Window.screen.height not used, just stored as globals in rlgl + rlglInit(CORE.Window.screen.width, CORE.Window.screen.height); + + int fbWidth = CORE.Window.render.width; + int fbHeight = CORE.Window.render.height; + +#if defined(PLATFORM_DESKTOP) + if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) + { + // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling + // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); + #if !defined(__APPLE__) + glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight); + + // Screen scaling matrix is required in case desired screen area is different than display area + CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); + + // Mouse input scaling for the new screen size + SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight); + #endif + } +#endif + + // Setup default viewport + SetupViewport(fbWidth, fbHeight); + + CORE.Window.currentFbo.width = CORE.Window.screen.width; + CORE.Window.currentFbo.height = CORE.Window.screen.height; + + ClearBackground(RAYWHITE); // Default background color for raylib games :P + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_UWP) + CORE.Window.ready = true; +#endif + + if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow(); + + return true; +} + +// Set viewport for a provided width and height +static void SetupViewport(int width, int height) +{ + CORE.Window.render.width = width; + CORE.Window.render.height = height; + + // Set viewport width and height + // NOTE: We consider render size (scaled) and offset in case black bars are required and + // render area does not match full display area (this situation is only applicable on fullscreen mode) +#if defined(__APPLE__) + float xScale = 1.0f, yScale = 1.0f; + glfwGetWindowContentScale(CORE.Window.handle, &xScale, &yScale); + rlViewport(CORE.Window.renderOffset.x/2*xScale, CORE.Window.renderOffset.y/2*yScale, (CORE.Window.render.width - CORE.Window.renderOffset.x)*xScale, (CORE.Window.render.height - CORE.Window.renderOffset.y)*yScale); +#else + rlViewport(CORE.Window.renderOffset.x/2, CORE.Window.renderOffset.y/2, CORE.Window.render.width - CORE.Window.renderOffset.x, CORE.Window.render.height - CORE.Window.renderOffset.y); +#endif + + rlMatrixMode(RL_PROJECTION); // Switch to projection matrix + rlLoadIdentity(); // Reset current matrix (projection) + + // Set orthographic projection to current framebuffer size + // NOTE: Configured top-left corner as (0, 0) + rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, 0.0f, 1.0f); + + rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix + rlLoadIdentity(); // Reset current matrix (modelview) +} + +// Compute framebuffer size relative to screen size and display size +// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified +static void SetupFramebuffer(int width, int height) +{ + // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var) + if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height)) + { + TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height); + + // Downscaling to fit display with border-bars + float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width; + float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height; + + if (widthRatio <= heightRatio) + { + CORE.Window.render.width = CORE.Window.display.width; + CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio); + CORE.Window.renderOffset.x = 0; + CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height); + } + else + { + CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio); + CORE.Window.render.height = CORE.Window.display.height; + CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width); + CORE.Window.renderOffset.y = 0; + } + + // Screen scaling required + float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width; + CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f); + + // NOTE: We render to full display resolution! + // We just need to calculate above parameters for downscale matrix and offsets + CORE.Window.render.width = CORE.Window.display.width; + CORE.Window.render.height = CORE.Window.display.height; + + TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height); + } + else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height)) + { + // Required screen size is smaller than display size + TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height); + + if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0)) + { + CORE.Window.screen.width = CORE.Window.display.width; + CORE.Window.screen.height = CORE.Window.display.height; + } + + // Upscaling to fit display with border-bars + float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height; + float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height; + + if (displayRatio <= screenRatio) + { + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio); + CORE.Window.renderOffset.x = 0; + CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height); + } + else + { + CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio); + CORE.Window.render.height = CORE.Window.screen.height; + CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width); + CORE.Window.renderOffset.y = 0; + } + } + else + { + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + CORE.Window.renderOffset.x = 0; + CORE.Window.renderOffset.y = 0; + } +} + +// Initialize hi-resolution timer +static void InitTimer(void) +{ + srand((unsigned int)time(NULL)); // Initialize random seed + +// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. +// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. +// High resolutions can also prevent the CPU power management system from entering power-saving modes. +// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter. +#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_UWP) + timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms) +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + struct timespec now = { 0 }; + + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success + { + CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; + } + else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available"); +#endif + + CORE.Time.previous = GetTime(); // Get time as double +} + +// Wait for some milliseconds (stop program execution) +// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could +// take longer than expected... for that reason we use the busy wait loop +// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected +// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32! +static void Wait(float ms) +{ +#if defined(PLATFORM_UWP) + UWPGetSleepFunc()(ms/1000); + return; +#endif + +#if defined(SUPPORT_BUSY_WAIT_LOOP) + double prevTime = GetTime(); + double nextTime = 0.0; + + // Busy wait loop + while ((nextTime - prevTime) < ms/1000.0f) nextTime = GetTime(); +#else + #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) + #define DEFAULT_PARTIALBUSY_WAIT_TIME 4 + #define PARTIALBUSY_WAIT_FACTOR 0.95 + + double halfWait = DEFAULT_PARTIALBUSY_WAIT_TIME; + if (CORE.Time.target > 0) halfWait = CORE.Time.target*PARTIALBUSY_WAIT_FACTOR; + + double destTime = GetTime() + ms/1000; + if (ms > halfWait) ms -= (float)halfWait; + #endif + + #if defined(_WIN32) + Sleep((unsigned int)ms); + #endif + #if defined(__linux__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) + struct timespec req = { 0 }; + time_t sec = (int)(ms/1000.0f); + ms -= (sec*1000); + req.tv_sec = sec; + req.tv_nsec = ms*1000000L; + + // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated. + while (nanosleep(&req, &req) == -1) continue; + #endif + #if defined(__APPLE__) + usleep(ms*1000.0f); + #endif + + #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) + while (GetTime() < destTime) { } + #endif +#endif +} + +// Poll (store) all input events +static void PollInputEvents(void) +{ +#if defined(SUPPORT_GESTURES_SYSTEM) + // NOTE: Gestures update must be called every frame to reset gestures correctly + // because ProcessGestureEvent() is just called on an event, not every frame + UpdateGestures(); +#endif + + // Reset keys/chars pressed registered + CORE.Input.Keyboard.keyPressedQueueCount = 0; + CORE.Input.Keyboard.charPressedQueueCount = 0; + +#if !(defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) + // Reset last gamepad button/axis registered state + CORE.Input.Gamepad.lastButtonPressed = -1; + CORE.Input.Gamepad.axisCount = 0; +#endif + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + // Register previous keys states + for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + + PollKeyboardEvents(); + + // Register previous mouse states + CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; + CORE.Input.Mouse.currentWheelMove = 0.0f; + for (int i = 0; i < 3; i++) + { + CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; + CORE.Input.Mouse.currentButtonState[i] = CORE.Input.Mouse.currentButtonStateEvdev[i]; + } + + // Register gamepads buttons events + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (CORE.Input.Gamepad.ready[i]) // Check if gamepad is available + { + // Register previous gamepad states + for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousState[i][k] = CORE.Input.Gamepad.currentState[i][k]; + } + } +#endif + +#if defined(PLATFORM_UWP) + // Register previous keys states + for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (CORE.Input.Gamepad.ready[i]) + { + for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousState[i][k] = CORE.Input.Gamepad.currentState[i][k]; + } + } + + // Register previous mouse states + CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; + CORE.Input.Mouse.currentWheelMove = 0.0f; + + for (int i = 0; i < 3; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; +#endif // PLATFORM_UWP + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback) + + // Register previous keys states + for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + + // Register previous mouse states + for (int i = 0; i < 3; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; + + // Register previous mouse wheel state + CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; + CORE.Input.Mouse.currentWheelMove = 0.0f; +#endif + + // Register previous touch states + for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; + +#if defined(PLATFORM_DESKTOP) + // Check if gamepads are ready + // NOTE: We do it here in case of disconnection + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (glfwJoystickPresent(i)) CORE.Input.Gamepad.ready[i] = true; + else CORE.Input.Gamepad.ready[i] = false; + } + + // Register gamepads buttons events + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (CORE.Input.Gamepad.ready[i]) // Check if gamepad is available + { + // Register previous gamepad states + for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousState[i][k] = CORE.Input.Gamepad.currentState[i][k]; + + // Get current gamepad state + // NOTE: There is no callback available, so we get it manually + // Get remapped buttons + GLFWgamepadstate state = { 0 }; + glfwGetGamepadState(i, &state); // This remapps all gamepads so they have their buttons mapped like an xbox controller + + const unsigned char *buttons = state.buttons; + + for (int k = 0; (buttons != NULL) && (k < GLFW_GAMEPAD_BUTTON_DPAD_LEFT + 1) && (k < MAX_GAMEPAD_BUTTONS); k++) + { + GamepadButton button = -1; + + switch (k) + { + case GLFW_GAMEPAD_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; + case GLFW_GAMEPAD_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; + case GLFW_GAMEPAD_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break; + case GLFW_GAMEPAD_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break; + + case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break; + case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break; + + case GLFW_GAMEPAD_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break; + case GLFW_GAMEPAD_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break; + case GLFW_GAMEPAD_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break; + + case GLFW_GAMEPAD_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break; + case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break; + case GLFW_GAMEPAD_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break; + case GLFW_GAMEPAD_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break; + + case GLFW_GAMEPAD_BUTTON_LEFT_THUMB: button = GAMEPAD_BUTTON_LEFT_THUMB; break; + case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB: button = GAMEPAD_BUTTON_RIGHT_THUMB; break; + default: break; + } + + if (button != -1) // Check for valid button + { + if (buttons[k] == GLFW_PRESS) + { + CORE.Input.Gamepad.currentState[i][button] = 1; + CORE.Input.Gamepad.lastButtonPressed = button; + } + else CORE.Input.Gamepad.currentState[i][button] = 0; + } + } + + // Get current axis state + const float *axes = state.axes; + + for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1) && (k < MAX_GAMEPAD_AXIS); k++) + { + CORE.Input.Gamepad.axisState[i][k] = axes[k]; + } + + // Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis) + CORE.Input.Gamepad.currentState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1); + CORE.Input.Gamepad.currentState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1); + + CORE.Input.Gamepad.axisCount = GLFW_GAMEPAD_AXIS_LAST + 1; + } + } + + CORE.Window.resizedLastFrame = false; + +#if defined(SUPPORT_EVENTS_WAITING) + glfwWaitEvents(); +#else + glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! +#endif +#endif // PLATFORM_DESKTOP + +// Gamepad support using emscripten API +// NOTE: GLFW3 joystick functionality not available in web +#if defined(PLATFORM_WEB) + // Get number of gamepads connected + int numGamepads = 0; + if (emscripten_sample_gamepad_data() == EMSCRIPTEN_RESULT_SUCCESS) numGamepads = emscripten_get_num_gamepads(); + + for (int i = 0; (i < numGamepads) && (i < MAX_GAMEPADS); i++) + { + // Register previous gamepad button states + for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousState[i][k] = CORE.Input.Gamepad.currentState[i][k]; + + EmscriptenGamepadEvent gamepadState; + + int result = emscripten_get_gamepad_status(i, &gamepadState); + + if (result == EMSCRIPTEN_RESULT_SUCCESS) + { + // Register buttons data for every connected gamepad + for (int j = 0; (j < gamepadState.numButtons) && (j < MAX_GAMEPAD_BUTTONS); j++) + { + GamepadButton button = -1; + + // Gamepad Buttons reference: https://www.w3.org/TR/gamepad/#gamepad-interface + switch (j) + { + case 0: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break; + case 1: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; + case 2: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break; + case 3: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; + case 4: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break; + case 5: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break; + case 6: button = GAMEPAD_BUTTON_LEFT_TRIGGER_2; break; + case 7: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_2; break; + case 8: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break; + case 9: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break; + case 10: button = GAMEPAD_BUTTON_LEFT_THUMB; break; + case 11: button = GAMEPAD_BUTTON_RIGHT_THUMB; break; + case 12: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break; + case 13: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break; + case 14: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break; + case 15: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break; + default: break; + } + + if (button != -1) // Check for valid button + { + if (gamepadState.digitalButton[j] == 1) + { + CORE.Input.Gamepad.currentState[i][button] = 1; + CORE.Input.Gamepad.lastButtonPressed = button; + } + else CORE.Input.Gamepad.currentState[i][button] = 0; + } + + //TRACELOGD("INPUT: Gamepad %d, button %d: Digital: %d, Analog: %g", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]); + } + + // Register axis data for every connected gamepad + for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++) + { + CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j]; + } + + CORE.Input.Gamepad.axisCount = gamepadState.numAxes; + } + } +#endif + +#if defined(PLATFORM_ANDROID) + // Register previous keys states + // NOTE: Android supports up to 260 keys + for (int i = 0; i < 260; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + + // Android ALooper_pollAll() variables + int pollResult = 0; + int pollEvents = 0; + + // Poll Events (registered events) + // NOTE: Activity is paused if not enabled (CORE.Android.appEnabled) + while ((pollResult = ALooper_pollAll(CORE.Android.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&CORE.Android.source)) >= 0) + { + // Process this event + if (CORE.Android.source != NULL) CORE.Android.source->process(CORE.Android.app, CORE.Android.source); + + // NOTE: Never close window, native activity is controlled by the system! + if (CORE.Android.app->destroyRequested != 0) + { + //CORE.Window.shouldClose = true; + //ANativeActivity_finish(CORE.Android.app->activity); + } + } +#endif + +#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_SSH_KEYBOARD_RPI) + // NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin, + // we now use both methods inside here. 2nd method is still used for legacy purposes (Allows for input trough SSH console) + ProcessKeyboard(); + + // NOTE: Mouse input events polling is done asynchronously in another pthread - EventThread() + // NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread() +#endif +} + +// Copy back buffer to front buffers +static void SwapBuffers(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + glfwSwapBuffers(CORE.Window.handle); +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) + eglSwapBuffers(CORE.Window.device, CORE.Window.surface); + +#if defined(PLATFORM_DRM) + if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc) + { + TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); + abort(); + } + + struct gbm_bo *bo = gbm_surface_lock_front_buffer(CORE.Window.gbmSurface); + if (!bo) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer"); + abort(); + } + + uint32_t fb = 0; + int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, + CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb); + if (0 != result) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result); + abort(); + } + + result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0, + &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]); + if (0 != result) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result); + abort(); + } + + if (CORE.Window.prevFB) + { + result = drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB); + if (0 != result) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result); + abort(); + } + } + CORE.Window.prevFB = fb; + + if (CORE.Window.prevBO) + { + gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO); + } + CORE.Window.prevBO = bo; +#endif // PLATFORM_DRM +#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP +} + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) +// GLFW3 Error Callback, runs on GLFW3 error +static void ErrorCallback(int error, const char *description) +{ + TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description); +} + + +// GLFW3 WindowSize Callback, runs when window is resizedLastFrame +// NOTE: Window resizing not allowed by default +static void WindowSizeCallback(GLFWwindow *window, int width, int height) +{ + SetupViewport(width, height); // Reset viewport and projection matrix for new size + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + CORE.Window.resizedLastFrame = true; + + if (IsWindowFullscreen()) return; + + // Set current screen size + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + // NOTE: Postprocessing texture is not scaled to new size + +} + +// GLFW3 WindowIconify Callback, runs when window is minimized/restored +static void WindowIconifyCallback(GLFWwindow *window, int iconified) +{ + if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified + else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored +} + +#if !defined(PLATFORM_WEB) +// GLFW3 WindowMaximize Callback, runs when window is maximized/restored +static void WindowMaximizeCallback(GLFWwindow *window, int maximized) +{ + if (maximized) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized + else CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored +} +#endif + +// GLFW3 WindowFocus Callback, runs when window get/lose focus +static void WindowFocusCallback(GLFWwindow *window, int focused) +{ + if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused + else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus +} + +// GLFW3 Keyboard Callback, runs on key pressed +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + //TRACELOG(LOG_DEBUG, "Key Callback: KEY:%i(%c) - SCANCODE:%i (STATE:%i)", key, key, scancode, action); + + if (key == CORE.Input.Keyboard.exitKey && action == GLFW_PRESS) + { + glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); + + // NOTE: Before closing window, while loop must be left! + } +#if defined(SUPPORT_SCREEN_CAPTURE) + else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) + { +#if defined(SUPPORT_GIF_RECORDING) + if (mods == GLFW_MOD_CONTROL) + { + if (gifRecording) + { + gifRecording = false; + + MsfGifResult result = msf_gif_end(&gifState); + + char path[512] = { 0 }; + #if defined(PLATFORM_ANDROID) + strcpy(path, CORE.Android.internalDataPath); + strcat(path, TextFormat("./screenrec%03i.gif", screenshotCounter)); + #else + strcpy(path, TextFormat("./screenrec%03i.gif", screenshotCounter)); + #endif + + SaveFileData(path, result.data, (unsigned int)result.dataSize); + msf_gif_free(result); + + #if defined(PLATFORM_WEB) + // Download file from MEMFS (emscripten memory filesystem) + // saveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html + emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", TextFormat("screenrec%03i.gif", screenshotCounter - 1), TextFormat("screenrec%03i.gif", screenshotCounter - 1))); + #endif + + TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); + } + else + { + gifRecording = true; + gifFramesCounter = 0; + + msf_gif_begin(&gifState, CORE.Window.screen.width, CORE.Window.screen.height); + screenshotCounter++; + + TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); + } + } + else +#endif // SUPPORT_GIF_RECORDING + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } + } +#endif // SUPPORT_SCREEN_CAPTURE + else + { + // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 + // to work properly with our implementation (IsKeyDown/IsKeyUp checks) + if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; + else CORE.Input.Keyboard.currentKeyState[key] = 1; + + // Check if there is space available in the key queue + if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) + { + // Add character to the queue + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; + CORE.Input.Keyboard.keyPressedQueueCount++; + } + } +} + +// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value) +static void CharCallback(GLFWwindow *window, unsigned int key) +{ + //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); + + // NOTE: Registers any key down considering OS keyboard layout but + // do not detects action events, those should be managed by user... + // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 + // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char + + // Check if there is space available in the queue + if (CORE.Input.Keyboard.charPressedQueueCount < MAX_KEY_PRESSED_QUEUE) + { + // Add character to the queue + CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = key; + CORE.Input.Keyboard.charPressedQueueCount++; + } +} + +// GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) +{ + // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, + // but future releases may add more actions (i.e. GLFW_REPEAT) + CORE.Input.Mouse.currentButtonState[button] = action; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + // Register touch actions + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_DOWN; + else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_UP; + + // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() + + // Assign a pointer ID + gestureEvent.pointerId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = GetMousePosition(); + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +// GLFW3 Cursor Position Callback, runs on mouse move +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) +{ + CORE.Input.Mouse.position.x = (float)x; + CORE.Input.Mouse.position.y = (float)y; + CORE.Input.Touch.position[0] = CORE.Input.Mouse.position; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + gestureEvent.touchAction = TOUCH_MOVE; + + // Assign a pointer ID + gestureEvent.pointerId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = CORE.Input.Touch.position[0]; + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +// GLFW3 Srolling Callback, runs on mouse wheel +static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) +{ + CORE.Input.Mouse.currentWheelMove = (float)yoffset; +} + +// GLFW3 CursorEnter Callback, when cursor enters the window +static void CursorEnterCallback(GLFWwindow *window, int enter) +{ + if (enter == true) CORE.Input.Mouse.cursorOnScreen = true; + else CORE.Input.Mouse.cursorOnScreen = false; +} + +// GLFW3 Window Drop Callback, runs when drop files into window +// NOTE: Paths are stored in dynamic memory for further retrieval +// Everytime new files are dropped, old ones are discarded +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) +{ + ClearDroppedFiles(); + + CORE.Window.dropFilesPath = (char **)RL_MALLOC(count*sizeof(char *)); + + for (int i = 0; i < count; i++) + { + CORE.Window.dropFilesPath[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char)); + strcpy(CORE.Window.dropFilesPath[i], paths[i]); + } + + CORE.Window.dropFilesCount = count; +} +#endif + +#if defined(PLATFORM_ANDROID) +// ANDROID: Process activity lifecycle commands +static void AndroidCommandCallback(struct android_app *app, int32_t cmd) +{ + switch (cmd) + { + case APP_CMD_START: + { + //rendering = true; + } break; + case APP_CMD_RESUME: break; + case APP_CMD_INIT_WINDOW: + { + if (app->window != NULL) + { + if (CORE.Android.contextRebindRequired) + { + // Reset screen scaling to full display size + EGLint displayFormat; + eglGetConfigAttrib(CORE.Window.device, CORE.Window.config, EGL_NATIVE_VISUAL_ID, &displayFormat); + ANativeWindow_setBuffersGeometry(app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); + + // Recreate display surface and re-attach OpenGL context + CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, app->window, NULL); + eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context); + + CORE.Android.contextRebindRequired = false; + } + else + { + CORE.Window.display.width = ANativeWindow_getWidth(CORE.Android.app->window); + CORE.Window.display.height = ANativeWindow_getHeight(CORE.Android.app->window); + + // Init graphics device (display device and OpenGL context) + InitGraphicsDevice(CORE.Window.screen.width, CORE.Window.screen.height); + + // Init hi-res timer + InitTimer(); + + #if defined(SUPPORT_DEFAULT_FONT) + // Load default font + // NOTE: External function (defined in module: text) + LoadFontDefault(); + Rectangle rec = GetFontDefault().recs[95]; + // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); + #endif + + // TODO: GPU assets reload in case of lost focus (lost context) + // NOTE: This problem has been solved just unbinding and rebinding context from display + /* + if (assetsReloadRequired) + { + for (int i = 0; i < assetsCount; i++) + { + // TODO: Unload old asset if required + + // Load texture again to pointed texture + (*textureAsset + i) = LoadTexture(assetPath[i]); + } + } + */ + } + } + } break; + case APP_CMD_GAINED_FOCUS: + { + CORE.Android.appEnabled = true; + //ResumeMusicStream(); + } break; + case APP_CMD_PAUSE: break; + case APP_CMD_LOST_FOCUS: + { + CORE.Android.appEnabled = false; + //PauseMusicStream(); + } break; + case APP_CMD_TERM_WINDOW: + { + // Dettach OpenGL context and destroy display surface + // NOTE 1: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...) + // NOTE 2: In some cases (too many context loaded), OS could unload context automatically... :( + eglMakeCurrent(CORE.Window.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(CORE.Window.device, CORE.Window.surface); + + CORE.Android.contextRebindRequired = true; + } break; + case APP_CMD_SAVE_STATE: break; + case APP_CMD_STOP: break; + case APP_CMD_DESTROY: + { + // TODO: Finish activity? + //ANativeActivity_finish(CORE.Android.app->activity); + } break; + case APP_CMD_CONFIG_CHANGED: + { + //AConfiguration_fromAssetManager(CORE.Android.app->config, CORE.Android.app->activity->assetManager); + //print_cur_config(CORE.Android.app); + + // Check screen orientation here! + } break; + default: break; + } +} + +// ANDROID: Get input events +static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) +{ + // If additional inputs are required check: + // https://developer.android.com/ndk/reference/group/input + // https://developer.android.com/training/game-controllers/controller-input + + int type = AInputEvent_getType(event); + int source = AInputEvent_getSource(event); + + if (type == AINPUT_EVENT_TYPE_MOTION) + { + if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) || + ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD)) + { + // Get first touch position + CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0); + CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0); + + // Get second touch position + CORE.Input.Touch.position[1].x = AMotionEvent_getX(event, 1); + CORE.Input.Touch.position[1].y = AMotionEvent_getY(event, 1); + + int32_t keycode = AKeyEvent_getKeyCode(event); + if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) + { + CORE.Input.Keyboard.currentKeyState[keycode] = 1; // Key down + + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; + CORE.Input.Keyboard.keyPressedQueueCount++; + } + else CORE.Input.Keyboard.currentKeyState[keycode] = 0; // Key up + + // Stop processing gamepad buttons + return 1; + } + } + else if (type == AINPUT_EVENT_TYPE_KEY) + { + int32_t keycode = AKeyEvent_getKeyCode(event); + //int32_t AKeyEvent_getMetaState(event); + + // Save current button and its state + // NOTE: Android key action is 0 for down and 1 for up + if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) + { + CORE.Input.Keyboard.currentKeyState[keycode] = 1; // Key down + + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; + CORE.Input.Keyboard.keyPressedQueueCount++; + } + else CORE.Input.Keyboard.currentKeyState[keycode] = 0; // Key up + + if (keycode == AKEYCODE_POWER) + { + // Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS + // Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS + // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected. + // NOTE: AndroidManifest.xml must have + // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour + return 0; + } + else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU)) + { + // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS! + return 1; + } + else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN)) + { + // Set default OS behaviour + return 0; + } + + return 0; + } + + CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0); + CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0); + + int32_t action = AMotionEvent_getAction(event); + unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; + + if (flags == AMOTION_EVENT_ACTION_DOWN || flags == AMOTION_EVENT_ACTION_MOVE) + { + CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1; + } + else if (flags == AMOTION_EVENT_ACTION_UP) + { + CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0; + } + +#if defined(SUPPORT_GESTURES_SYSTEM) + + GestureEvent gestureEvent; + + // Register touch actions + if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN; + else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP; + else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + // NOTE: Documentation says pointerCount is Always >= 1, + // but in practice it can be 0 or over a million + gestureEvent.pointCount = AMotionEvent_getPointerCount(event); + + // Only enable gestures for 1-3 touch points + if ((gestureEvent.pointCount > 0) && (gestureEvent.pointCount < 4)) + { + // Register touch points id + // NOTE: Only two points registered + gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0); + gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1); + + // Register touch points position + gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) }; + gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) }; + + // Normalize gestureEvent.position[x] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); + gestureEvent.position[1].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); + } +#endif + + return 0; +} +#endif + +#if defined(PLATFORM_WEB) +// Register touch input events +static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) +{ + for (int i = 0; i < touchEvent->numTouches; i++) + { + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0; + } + +#if defined(SUPPORT_GESTURES_SYSTEM) + GestureEvent gestureEvent = { 0 }; + + // Register touch actions + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_DOWN; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_UP; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + gestureEvent.pointCount = touchEvent->numTouches; + + // Register touch points id + gestureEvent.pointerId[0] = touchEvent->touches[0].identifier; + gestureEvent.pointerId[1] = touchEvent->touches[1].identifier; + + // Register touch points position + // NOTE: Only two points registered + gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; + gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; + + double canvasWidth, canvasHeight; + // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but + // we are looking for actual CSS size: canvas.style.width and canvas.style.height + //EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); + emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight); + + // Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x *= ((float)GetScreenWidth()/(float)canvasWidth); + gestureEvent.position[0].y *= ((float)GetScreenHeight()/(float)canvasHeight); + gestureEvent.position[1].x *= ((float)GetScreenWidth()/(float)canvasWidth); + gestureEvent.position[1].y *= ((float)GetScreenHeight()/(float)canvasHeight); + + CORE.Input.Touch.position[0] = gestureEvent.position[0]; + CORE.Input.Touch.position[1] = gestureEvent.position[1]; + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#else + // Support only simple touch position + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) + { + // Get first touch position + CORE.Input.Touch.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; + + double canvasWidth, canvasHeight; + //EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); + emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight); + + // Normalize gestureEvent.position[x] for screenWidth and screenHeight + CORE.Input.Touch.position[0].x *= ((float)GetScreenWidth()/(float)canvasWidth); + CORE.Input.Touch.position[0].y *= ((float)GetScreenHeight()/(float)canvasHeight); + } +#endif + + return 1; +} + +// Register connected/disconnected gamepads events +static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) +{ + /* + TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"", + eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state", + gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); + + for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]); + for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); + */ + + if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) CORE.Input.Gamepad.ready[gamepadEvent->index] = true; + else CORE.Input.Gamepad.ready[gamepadEvent->index] = false; + + // TODO: Test gamepadEvent->index + + return 0; +} +#endif + +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) + +#if defined(SUPPORT_SSH_KEYBOARD_RPI) +// Initialize Keyboard system (using standard input) +static void InitKeyboard(void) +{ + // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor + + // Make stdin non-blocking (not enough, need to configure to non-canonical mode) + int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified + + // Save terminal keyboard settings and reconfigure terminal with new settings + struct termios keyboardNewSettings; + tcgetattr(STDIN_FILENO, &CORE.Input.Keyboard.defaultSettings); // Get current keyboard settings + keyboardNewSettings = CORE.Input.Keyboard.defaultSettings; + + // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing + // NOTE: ISIG controls if ^C and ^Z generate break signals or not + keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG); + //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF); + keyboardNewSettings.c_cc[VMIN] = 1; + keyboardNewSettings.c_cc[VTIME] = 0; + + // Set new keyboard settings (change occurs immediately) + tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings); + + // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE + + // Save old keyboard mode to restore it at the end + if (ioctl(STDIN_FILENO, KDGKBMODE, &CORE.Input.Keyboard.defaultMode) < 0) + { + // NOTE: It could mean we are using a remote keyboard through ssh! + TRACELOG(LOG_WARNING, "RPI: Failed to change keyboard mode (SSH keyboard?)"); + } + else + { + // We reconfigure keyboard mode to get: + // - scancodes (K_RAW) + // - keycodes (K_MEDIUMRAW) + // - ASCII chars (K_XLATE) + // - UNICODE chars (K_UNICODE) + ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE); + } + + // Register keyboard restore when program finishes + atexit(RestoreKeyboard); +} + +// Process keyboard inputs +// TODO: Most probably input reading and processing should be in a separate thread +static void ProcessKeyboard(void) +{ + #define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read + + // Keyboard input polling (fill keys[256] array with status) + int bufferByteCount = 0; // Bytes available on the buffer + char keysBuffer[MAX_KEYBUFFER_SIZE]; // Max keys to be read at a time + + // Read availables keycodes from stdin + bufferByteCount = read(STDIN_FILENO, keysBuffer, MAX_KEYBUFFER_SIZE); // POSIX system call + + // Reset pressed keys array (it will be filled below) + if (bufferByteCount > 0) for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0; + + // Check keys from event input workers (This is the new keyboard reading method) + //for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = CORE.Input.Keyboard.currentKeyStateEvdev[i]; + + // Fill all read bytes (looking for keys) + for (int i = 0; i < bufferByteCount; i++) + { + // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code! + // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42 + if (keysBuffer[i] == 0x1b) + { + // Detect ESC to stop program + if (bufferByteCount == 1) CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] = 1; + else + { + if (keysBuffer[i + 1] == 0x5b) // Special function key + { + if ((keysBuffer[i + 2] == 0x5b) || (keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) + { + // Process special function keys (F1 - F12) + switch (keysBuffer[i + 3]) + { + case 0x41: CORE.Input.Keyboard.currentKeyState[290] = 1; break; // raylib KEY_F1 + case 0x42: CORE.Input.Keyboard.currentKeyState[291] = 1; break; // raylib KEY_F2 + case 0x43: CORE.Input.Keyboard.currentKeyState[292] = 1; break; // raylib KEY_F3 + case 0x44: CORE.Input.Keyboard.currentKeyState[293] = 1; break; // raylib KEY_F4 + case 0x45: CORE.Input.Keyboard.currentKeyState[294] = 1; break; // raylib KEY_F5 + case 0x37: CORE.Input.Keyboard.currentKeyState[295] = 1; break; // raylib KEY_F6 + case 0x38: CORE.Input.Keyboard.currentKeyState[296] = 1; break; // raylib KEY_F7 + case 0x39: CORE.Input.Keyboard.currentKeyState[297] = 1; break; // raylib KEY_F8 + case 0x30: CORE.Input.Keyboard.currentKeyState[298] = 1; break; // raylib KEY_F9 + case 0x31: CORE.Input.Keyboard.currentKeyState[299] = 1; break; // raylib KEY_F10 + case 0x33: CORE.Input.Keyboard.currentKeyState[300] = 1; break; // raylib KEY_F11 + case 0x34: CORE.Input.Keyboard.currentKeyState[301] = 1; break; // raylib KEY_F12 + default: break; + } + + if (keysBuffer[i + 2] == 0x5b) i += 4; + else if ((keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) i += 5; + } + else + { + switch (keysBuffer[i + 2]) + { + case 0x41: CORE.Input.Keyboard.currentKeyState[265] = 1; break; // raylib KEY_UP + case 0x42: CORE.Input.Keyboard.currentKeyState[264] = 1; break; // raylib KEY_DOWN + case 0x43: CORE.Input.Keyboard.currentKeyState[262] = 1; break; // raylib KEY_RIGHT + case 0x44: CORE.Input.Keyboard.currentKeyState[263] = 1; break; // raylib KEY_LEFT + default: break; + } + + i += 3; // Jump to next key + } + + // NOTE: Some keys are not directly keymapped (CTRL, ALT, SHIFT) + } + } + } + else if (keysBuffer[i] == 0x0a) // raylib KEY_ENTER (don't mix with KEY_*) + { + CORE.Input.Keyboard.currentKeyState[257] = 1; + + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 257; // Add keys pressed into queue + CORE.Input.Keyboard.keyPressedQueueCount++; + } + else if (keysBuffer[i] == 0x7f) // raylib KEY_BACKSPACE + { + CORE.Input.Keyboard.currentKeyState[259] = 1; + + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 257; // Add keys pressed into queue + CORE.Input.Keyboard.keyPressedQueueCount++; + } + else + { + // Translate lowercase a-z letters to A-Z + if ((keysBuffer[i] >= 97) && (keysBuffer[i] <= 122)) + { + CORE.Input.Keyboard.currentKeyState[(int)keysBuffer[i] - 32] = 1; + } + else CORE.Input.Keyboard.currentKeyState[(int)keysBuffer[i]] = 1; + + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keysBuffer[i]; // Add keys pressed into queue + CORE.Input.Keyboard.keyPressedQueueCount++; + } + } + + // Check exit key (same functionality as GLFW3 KeyCallback()) + if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true; + +#if defined(SUPPORT_SCREEN_CAPTURE) + // Check screen capture key (raylib key: KEY_F12) + if (CORE.Input.Keyboard.currentKeyState[301] == 1) + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } +#endif +} + +// Restore default keyboard input +static void RestoreKeyboard(void) +{ + // Reset to default keyboard settings + tcsetattr(STDIN_FILENO, TCSANOW, &CORE.Input.Keyboard.defaultSettings); + + // Reconfigure keyboard to default mode + ioctl(STDIN_FILENO, KDSKBMODE, CORE.Input.Keyboard.defaultMode); +} +#endif // SUPPORT_SSH_KEYBOARD_RPI + +// Initialise user input from evdev(/dev/input/event) this means mouse, keyboard or gamepad devices +static void InitEvdevInput(void) +{ + char path[MAX_FILEPATH_LENGTH]; + DIR *directory; + struct dirent *entity; + + // Initialise keyboard file descriptor + CORE.Input.Keyboard.fd = -1; + + // Reset variables + for (int i = 0; i < MAX_TOUCH_POINTS; ++i) + { + CORE.Input.Touch.position[i].x = -1; + CORE.Input.Touch.position[i].y = -1; + } + + // Reset keyboard key state + for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0; + + // Open the linux directory of "/dev/input" + directory = opendir(DEFAULT_EVDEV_PATH); + + if (directory) + { + while ((entity = readdir(directory)) != NULL) + { + if (strncmp("event", entity->d_name, strlen("event")) == 0) // Search for devices named "event*" + { + sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name); + ConfigureEvdevDevice(path); // Configure the device if appropriate + } + } + + closedir(directory); + } + else TRACELOG(LOG_WARNING, "RPI: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH); +} + +// Identifies a input device and configures it for use if appropriate +static void ConfigureEvdevDevice(char *device) +{ + #define BITS_PER_LONG (8*sizeof(long)) + #define NBITS(x) ((((x) - 1)/BITS_PER_LONG) + 1) + #define OFF(x) ((x)%BITS_PER_LONG) + #define BIT(x) (1UL<> OFF(bit)) & 1) + + struct input_absinfo absinfo; + unsigned long evBits[NBITS(EV_MAX)]; + unsigned long absBits[NBITS(ABS_MAX)]; + unsigned long relBits[NBITS(REL_MAX)]; + unsigned long keyBits[NBITS(KEY_MAX)]; + bool hasAbs = false; + bool hasRel = false; + bool hasAbsMulti = false; + int freeWorkerId = -1; + int fd = -1; + + InputEventWorker *worker; + + // Open the device and allocate worker + //------------------------------------------------------------------------------------------------------- + // Find a free spot in the workers array + for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + { + if (CORE.Input.eventWorker[i].threadId == 0) + { + freeWorkerId = i; + break; + } + } + + // Select the free worker from array + if (freeWorkerId >= 0) + { + worker = &(CORE.Input.eventWorker[freeWorkerId]); // Grab a pointer to the worker + memset(worker, 0, sizeof(InputEventWorker)); // Clear the worker + } + else + { + TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread for %s, out of worker slots", device); + return; + } + + // Open the device + fd = open(device, O_RDONLY | O_NONBLOCK); + if (fd < 0) + { + TRACELOG(LOG_WARNING, "RPI: Failed to open input device %s", device); + return; + } + worker->fd = fd; + + // Grab number on the end of the devices name "event" + int devNum = 0; + char *ptrDevName = strrchr(device, 't'); + worker->eventNum = -1; + + if (ptrDevName != NULL) + { + if (sscanf(ptrDevName, "t%d", &devNum) == 1) + worker->eventNum = devNum; + } + + // At this point we have a connection to the device, but we don't yet know what the device is. + // It could be many things, even as simple as a power button... + //------------------------------------------------------------------------------------------------------- + + // Identify the device + //------------------------------------------------------------------------------------------------------- + ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the available device properties + + // Check for absolute input devices + if (TEST_BIT(evBits, EV_ABS)) + { + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits); + + // Check for absolute movement support (usualy touchscreens, but also joysticks) + if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y)) + { + hasAbs = true; + + // Get the scaling values + ioctl(fd, EVIOCGABS(ABS_X), &absinfo); + worker->absRange.x = absinfo.minimum; + worker->absRange.width = absinfo.maximum - absinfo.minimum; + ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); + worker->absRange.y = absinfo.minimum; + worker->absRange.height = absinfo.maximum - absinfo.minimum; + } + + // Check for multiple absolute movement support (usualy multitouch touchscreens) + if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y)) + { + hasAbsMulti = true; + + // Get the scaling values + ioctl(fd, EVIOCGABS(ABS_X), &absinfo); + worker->absRange.x = absinfo.minimum; + worker->absRange.width = absinfo.maximum - absinfo.minimum; + ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); + worker->absRange.y = absinfo.minimum; + worker->absRange.height = absinfo.maximum - absinfo.minimum; + } + } + + // Check for relative movement support (usualy mouse) + if (TEST_BIT(evBits, EV_REL)) + { + ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits); + + if (TEST_BIT(relBits, REL_X) && TEST_BIT(relBits, REL_Y)) hasRel = true; + } + + // Check for button support to determine the device type(usualy on all input devices) + if (TEST_BIT(evBits, EV_KEY)) + { + ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits); + + if (hasAbs || hasAbsMulti) + { + if (TEST_BIT(keyBits, BTN_TOUCH)) worker->isTouch = true; // This is a touchscreen + if (TEST_BIT(keyBits, BTN_TOOL_FINGER)) worker->isTouch = true; // This is a drawing tablet + if (TEST_BIT(keyBits, BTN_TOOL_PEN)) worker->isTouch = true; // This is a drawing tablet + if (TEST_BIT(keyBits, BTN_STYLUS)) worker->isTouch = true; // This is a drawing tablet + if (worker->isTouch || hasAbsMulti) worker->isMultitouch = true; // This is a multitouch capable device + } + + if (hasRel) + { + if (TEST_BIT(keyBits, BTN_LEFT)) worker->isMouse = true; // This is a mouse + if (TEST_BIT(keyBits, BTN_RIGHT)) worker->isMouse = true; // This is a mouse + } + + if (TEST_BIT(keyBits, BTN_A)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_TRIGGER)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_START)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_TL)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_TL)) worker->isGamepad = true; // This is a gamepad + + if (TEST_BIT(keyBits, KEY_SPACE)) worker->isKeyboard = true; // This is a keyboard + } + //------------------------------------------------------------------------------------------------------- + + // Decide what to do with the device + //------------------------------------------------------------------------------------------------------- + if (worker->isKeyboard && CORE.Input.Keyboard.fd == -1) + { + // Use the first keyboard encountered. This assumes that a device that says it's a keyboard is just a + // keyboard. The keyboard is polled synchronously, whereas other input devices are polled in separate + // threads so that they don't drop events when the frame rate is slow. + TRACELOG(LOG_INFO, "RPI: Opening keyboard device: %s", device); + CORE.Input.Keyboard.fd = worker->fd; + } + else if (worker->isTouch || worker->isMouse) + { + // Looks like an interesting device + TRACELOG(LOG_INFO, "RPI: Opening input device: %s (%s%s%s%s)", device, + worker->isMouse? "mouse " : "", + worker->isMultitouch? "multitouch " : "", + worker->isTouch? "touchscreen " : "", + worker->isGamepad? "gamepad " : ""); + + // Create a thread for this device + int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); + if (error != 0) + { + TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread: %s (error: %d)", device, error); + worker->threadId = 0; + close(fd); + } + +#if defined(USE_LAST_TOUCH_DEVICE) + // Find touchscreen with the highest index + int maxTouchNumber = -1; + + for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + { + if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = CORE.Input.eventWorker[i].eventNum; + } + + // Find touchscreens with lower indexes + for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + { + if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum < maxTouchNumber)) + { + if (CORE.Input.eventWorker[i].threadId != 0) + { + TRACELOG(LOG_WARNING, "RPI: Found duplicate touchscreen, killing touchscreen on event: %d", i); + pthread_cancel(CORE.Input.eventWorker[i].threadId); + close(CORE.Input.eventWorker[i].fd); + } + } + } +#endif + } + else close(fd); // We are not interested in this device + //------------------------------------------------------------------------------------------------------- +} + +static void PollKeyboardEvents(void) +{ + // Scancode to keycode mapping for US keyboards + // TODO: Probably replace this with a keymap from the X11 to get the correct regional map for the keyboard: + // Currently non US keyboards will have the wrong mapping for some keys + static const int keymap_US[] = + { 0,256,49,50,51,52,53,54,55,56,57,48,45,61,259,258,81,87,69,82,84, + 89,85,73,79,80,91,93,257,341,65,83,68,70,71,72,74,75,76,59,39,96, + 340,92,90,88,67,86,66,78,77,44,46,47,344,332,342,32,280,290,291, + 292,293,294,295,296,297,298,299,282,281,327,328,329,333,324,325, + 326,334,321,322,323,320,330,0,85,86,300,301,89,90,91,92,93,94,95, + 335,345,331,283,346,101,268,265,266,263,262,269,264,267,260,261, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,347,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,0,0,0,0,0,200,201,202,203,204,205,206,207,208,209,210, + 211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226, + 227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242, + 243,244,245,246,247,248,0,0,0,0,0,0,0, }; + + int fd = CORE.Input.Keyboard.fd; + if (fd == -1) return; + + struct input_event event; + int keycode; + + // Try to read data from the keyboard and only continue if successful + while (read(fd, &event, sizeof(event)) == (int)sizeof(event)) + { + // Button parsing + if (event.type == EV_KEY) + { + // Keyboard button parsing + if ((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255 + { + keycode = keymap_US[event.code & 0xFF]; // The code we get is a scancode so we look up the apropriate keycode + + // Make sure we got a valid keycode + if ((keycode > 0) && (keycode < sizeof(CORE.Input.Keyboard.currentKeyState))) + { + // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt + // Event interface: 'value' is the value the event carries. Either a relative change for EV_REL, + // absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat + CORE.Input.Keyboard.currentKeyState[keycode] = (event.value >= 1)? 1 : 0; + if (event.value >= 1) + { + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; // Register last key pressed + CORE.Input.Keyboard.keyPressedQueueCount++; + } + + #if defined(SUPPORT_SCREEN_CAPTURE) + // Check screen capture key (raylib key: KEY_F12) + if (CORE.Input.Keyboard.currentKeyState[301] == 1) + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } + #endif + + if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true; + + TRACELOGD("RPI: KEY_%s ScanCode: %4i KeyCode: %4i", event.value == 0 ? "UP":"DOWN", event.code, keycode); + } + } + } + } +} + +// Input device events reading thread +static void *EventThread(void *arg) +{ + struct input_event event; + InputEventWorker *worker = (InputEventWorker *)arg; + + int touchAction = -1; + bool gestureUpdate = false; + + while (!CORE.Window.shouldClose) + { + // Try to read data from the device and only continue if successful + while (read(worker->fd, &event, sizeof(event)) == (int)sizeof(event)) + { + // Relative movement parsing + if (event.type == EV_REL) + { + if (event.code == REL_X) + { + CORE.Input.Mouse.position.x += event.value; + CORE.Input.Touch.position[0].x = CORE.Input.Mouse.position.x; + + #if defined(SUPPORT_GESTURES_SYSTEM) + touchAction = TOUCH_MOVE; + gestureUpdate = true; + #endif + } + + if (event.code == REL_Y) + { + CORE.Input.Mouse.position.y += event.value; + CORE.Input.Touch.position[0].y = CORE.Input.Mouse.position.y; + + #if defined(SUPPORT_GESTURES_SYSTEM) + touchAction = TOUCH_MOVE; + gestureUpdate = true; + #endif + } + + if (event.code == REL_WHEEL) CORE.Input.Mouse.currentWheelMove += event.value; + } + + // Absolute movement parsing + if (event.type == EV_ABS) + { + // Basic movement + if (event.code == ABS_X) + { + CORE.Input.Mouse.position.x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange + CORE.Input.Touch.position[0].x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange + + #if defined(SUPPORT_GESTURES_SYSTEM) + touchAction = TOUCH_MOVE; + gestureUpdate = true; + #endif + } + + if (event.code == ABS_Y) + { + CORE.Input.Mouse.position.y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange + CORE.Input.Touch.position[0].y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange + + #if defined(SUPPORT_GESTURES_SYSTEM) + touchAction = TOUCH_MOVE; + gestureUpdate = true; + #endif + } + + // Multitouch movement + if (event.code == ABS_MT_SLOT) worker->touchSlot = event.value; // Remember the slot number for the folowing events + + if (event.code == ABS_MT_POSITION_X) + { + if (worker->touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[worker->touchSlot].x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange + } + + if (event.code == ABS_MT_POSITION_Y) + { + if (worker->touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[worker->touchSlot].y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange + } + + if (event.code == ABS_MT_TRACKING_ID) + { + if ((event.value < 0) && (worker->touchSlot < MAX_TOUCH_POINTS)) + { + // Touch has ended for this point + CORE.Input.Touch.position[worker->touchSlot].x = -1; + CORE.Input.Touch.position[worker->touchSlot].y = -1; + } + } + + // Touchscreen tap + if (event.code == ABS_PRESSURE) + { + int previousMouseLeftButtonState = CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT]; + + if (!event.value && previousMouseLeftButtonState) + { + CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0; + + #if defined(SUPPORT_GESTURES_SYSTEM) + touchAction = TOUCH_UP; + gestureUpdate = true; + #endif + } + + if (event.value && !previousMouseLeftButtonState) + { + CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1; + + #if defined(SUPPORT_GESTURES_SYSTEM) + touchAction = TOUCH_DOWN; + gestureUpdate = true; + #endif + } + } + + } + + // Button parsing + if (event.type == EV_KEY) + { + // Mouse button parsing + if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT)) + { + CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value; + + #if defined(SUPPORT_GESTURES_SYSTEM) + if (event.value > 0) touchAction = TOUCH_DOWN; + else touchAction = TOUCH_UP; + gestureUpdate = true; + #endif + } + + if (event.code == BTN_RIGHT) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value; + if (event.code == BTN_MIDDLE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value; + if (event.code == BTN_SIDE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value; + if (event.code == BTN_EXTRA) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value; + if (event.code == BTN_FORWARD) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value; + if (event.code == BTN_BACK) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value; + } + + // Screen confinement + if (!CORE.Input.Mouse.cursorHidden) + { + if (CORE.Input.Mouse.position.x < 0) CORE.Input.Mouse.position.x = 0; + if (CORE.Input.Mouse.position.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.position.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x; + + if (CORE.Input.Mouse.position.y < 0) CORE.Input.Mouse.position.y = 0; + if (CORE.Input.Mouse.position.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.position.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y; + } + + // Gesture update + if (gestureUpdate) + { + #if defined(SUPPORT_GESTURES_SYSTEM) + GestureEvent gestureEvent = { 0 }; + + gestureEvent.pointCount = 0; + gestureEvent.touchAction = touchAction; + + if (CORE.Input.Touch.position[0].x >= 0) gestureEvent.pointCount++; + if (CORE.Input.Touch.position[1].x >= 0) gestureEvent.pointCount++; + if (CORE.Input.Touch.position[2].x >= 0) gestureEvent.pointCount++; + if (CORE.Input.Touch.position[3].x >= 0) gestureEvent.pointCount++; + + gestureEvent.pointerId[0] = 0; + gestureEvent.pointerId[1] = 1; + gestureEvent.pointerId[2] = 2; + gestureEvent.pointerId[3] = 3; + + gestureEvent.position[0] = CORE.Input.Touch.position[0]; + gestureEvent.position[1] = CORE.Input.Touch.position[1]; + gestureEvent.position[2] = CORE.Input.Touch.position[2]; + gestureEvent.position[3] = CORE.Input.Touch.position[3]; + + ProcessGestureEvent(gestureEvent); + #endif + } + } + Wait(5); // Sleep for 5ms to avoid hogging CPU time + } + + close(worker->fd); + + return NULL; +} + +// Init gamepad system +static void InitGamepad(void) +{ + char gamepadDev[128] = ""; + + for (int i = 0; i < MAX_GAMEPADS; i++) + { + sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i); + + if ((CORE.Input.Gamepad.streamId[i] = open(gamepadDev, O_RDONLY|O_NONBLOCK)) < 0) + { + // NOTE: Only show message for first gamepad + if (i == 0) TRACELOG(LOG_WARNING, "RPI: Failed to open Gamepad device, no gamepad available"); + } + else + { + CORE.Input.Gamepad.ready[i] = true; + + // NOTE: Only create one thread + if (i == 0) + { + int error = pthread_create(&CORE.Input.Gamepad.threadId, NULL, &GamepadThread, NULL); + + if (error != 0) TRACELOG(LOG_WARNING, "RPI: Failed to create gamepad input event thread"); + else TRACELOG(LOG_INFO, "RPI: Gamepad device initialized successfully"); + } + } + } +} + +// Process Gamepad (/dev/input/js0) +static void *GamepadThread(void *arg) +{ + #define JS_EVENT_BUTTON 0x01 // Button pressed/released + #define JS_EVENT_AXIS 0x02 // Joystick axis moved + #define JS_EVENT_INIT 0x80 // Initial state of device + + struct js_event { + unsigned int time; // event timestamp in milliseconds + short value; // event value + unsigned char type; // event type + unsigned char number; // event axis/button number + }; + + // Read gamepad event + struct js_event gamepadEvent; + + while (!CORE.Window.shouldClose) + { + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (read(CORE.Input.Gamepad.streamId[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) + { + gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events + + // Process gamepad events by type + if (gamepadEvent.type == JS_EVENT_BUTTON) + { + //TRACELOG(LOG_WARNING, "RPI: Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + + if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) + { + // 1 - button pressed, 0 - button released + CORE.Input.Gamepad.currentState[i][gamepadEvent.number] = (int)gamepadEvent.value; + + if ((int)gamepadEvent.value == 1) CORE.Input.Gamepad.lastButtonPressed = gamepadEvent.number; + else CORE.Input.Gamepad.lastButtonPressed = -1; + } + } + else if (gamepadEvent.type == JS_EVENT_AXIS) + { + //TRACELOG(LOG_WARNING, "RPI: Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + + if (gamepadEvent.number < MAX_GAMEPAD_AXIS) + { + // NOTE: Scaling of gamepadEvent.value to get values between -1..1 + CORE.Input.Gamepad.axisState[i][gamepadEvent.number] = (float)gamepadEvent.value/32768; + } + } + } + else Wait(1); // Sleep for 1 ms to avoid hogging CPU time + } + } + + return NULL; +} +#endif // PLATFORM_RPI || PLATFORM_DRM + +#if defined(PLATFORM_UWP) +// UWP function pointers +// NOTE: Those pointers are set by UWP App +static UWPQueryTimeFunc uwpQueryTimeFunc = NULL; +static UWPSleepFunc uwpSleepFunc = NULL; +static UWPDisplaySizeFunc uwpDisplaySizeFunc = NULL; +static UWPMouseFunc uwpMouseLockFunc = NULL; +static UWPMouseFunc uwpMouseUnlockFunc = NULL; +static UWPMouseFunc uwpMouseShowFunc = NULL; +static UWPMouseFunc uwpMouseHideFunc = NULL; +static UWPMouseSetPosFunc uwpMouseSetPosFunc = NULL; +static void *uwpCoreWindow = NULL; + +// Check all required UWP function pointers have been set +bool UWPIsConfigured() +{ + bool pass = true; + + if (uwpQueryTimeFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetQueryTimeFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpSleepFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetSleepFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpDisplaySizeFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetDisplaySizeFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpMouseLockFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseLockFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpMouseUnlockFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseUnlockFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpMouseShowFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseShowFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpMouseHideFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseHideFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpMouseSetPosFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseSetPosFunc() must be called with a valid function before InitWindow()"); pass = false; } + if (uwpCoreWindow == NULL) { TRACELOG(LOG_ERROR, "UWP: A pointer to the UWP core window must be set before InitWindow()"); pass = false; } + + return pass; +} + +// UWP function handlers get/set +void UWPSetDataPath(const char* path) { CORE.UWP.internalDataPath = path; } +UWPQueryTimeFunc UWPGetQueryTimeFunc(void) { return uwpQueryTimeFunc; } +void UWPSetQueryTimeFunc(UWPQueryTimeFunc func) { uwpQueryTimeFunc = func; } +UWPSleepFunc UWPGetSleepFunc(void) { return uwpSleepFunc; } +void UWPSetSleepFunc(UWPSleepFunc func) { uwpSleepFunc = func; } +UWPDisplaySizeFunc UWPGetDisplaySizeFunc(void) { return uwpDisplaySizeFunc; } +void UWPSetDisplaySizeFunc(UWPDisplaySizeFunc func) { uwpDisplaySizeFunc = func; } +UWPMouseFunc UWPGetMouseLockFunc() { return uwpMouseLockFunc; } +void UWPSetMouseLockFunc(UWPMouseFunc func) { uwpMouseLockFunc = func; } +UWPMouseFunc UWPGetMouseUnlockFunc() { return uwpMouseUnlockFunc; } +void UWPSetMouseUnlockFunc(UWPMouseFunc func) { uwpMouseUnlockFunc = func; } +UWPMouseFunc UWPGetMouseShowFunc() { return uwpMouseShowFunc; } +void UWPSetMouseShowFunc(UWPMouseFunc func) { uwpMouseShowFunc = func; } +UWPMouseFunc UWPGetMouseHideFunc() { return uwpMouseHideFunc; } +void UWPSetMouseHideFunc(UWPMouseFunc func) { uwpMouseHideFunc = func; } +UWPMouseSetPosFunc UWPGetMouseSetPosFunc() { return uwpMouseSetPosFunc; } +void UWPSetMouseSetPosFunc(UWPMouseSetPosFunc func) { uwpMouseSetPosFunc = func; } + +void *UWPGetCoreWindowPtr() { return uwpCoreWindow; } +void UWPSetCoreWindowPtr(void* ptr) { uwpCoreWindow = ptr; } +void UWPMouseWheelEvent(int deltaY) { CORE.Input.Mouse.currentWheelMove = (float)deltaY; } + +void UWPKeyDownEvent(int key, bool down, bool controlKey) +{ + if (key == CORE.Input.Keyboard.exitKey && down) + { + // Time to close the window. + CORE.Window.shouldClose = true; + } +#if defined(SUPPORT_SCREEN_CAPTURE) + else if (key == KEY_F12 && down) + { +#if defined(SUPPORT_GIF_RECORDING) + if (controlKey) + { + if (gifRecording) + { + gifRecording = false; + + MsfGifResult result = msf_gif_end(&gifState); + + SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.UWP.internalDataPath, screenshotCounter), result.data, result.dataSize); + msf_gif_free(result); + +#if defined(PLATFORM_WEB) + // Download file from MEMFS (emscripten memory filesystem) + // saveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html + emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", TextFormat("screenrec%03i.gif", screenshotCounter - 1), TextFormat("screenrec%03i.gif", screenshotCounter - 1))); +#endif + TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); + } + else + { + gifRecording = true; + gifFramesCounter = 0; + + msf_gif_begin(&gifState, CORE.Window.screen.width, CORE.Window.screen.height); + screenshotCounter++; + + TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); + } + } + else +#endif // SUPPORT_GIF_RECORDING + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } + } +#endif // SUPPORT_SCREEN_CAPTURE + else + { + CORE.Input.Keyboard.currentKeyState[key] = down; + } +} + +void UWPKeyCharEvent(int key) +{ + if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) + { + // Add character to the queue + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; + CORE.Input.Keyboard.keyPressedQueueCount++; + } +} + +void UWPMouseButtonEvent(int button, bool down) +{ + CORE.Input.Mouse.currentButtonState[button] = down; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + // Register touch actions + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_DOWN; + else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_UP; + + // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() + + // Assign a pointer ID + gestureEvent.pointerId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = GetMousePosition(); + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +void UWPMousePosEvent(double x, double y) +{ + CORE.Input.Mouse.position.x = (float)x; + CORE.Input.Mouse.position.y = (float)y; + CORE.Input.Touch.position[0] = CORE.Input.Mouse.position; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + gestureEvent.touchAction = TOUCH_MOVE; + + // Assign a pointer ID + gestureEvent.pointerId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = CORE.Input.Mouse.position; + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +void UWPResizeEvent(int width, int height) +{ + SetupViewport(width, height); // Reset viewport and projection matrix for new size + + // Set current screen size + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + + // NOTE: Postprocessing texture is not scaled to new size + + CORE.Window.resizedLastFrame = true; +} + +void UWPActivateGamepadEvent(int gamepad, bool active) +{ + if (gamepad < MAX_GAMEPADS) CORE.Input.Gamepad.ready[gamepad] = active; +} + +void UWPRegisterGamepadButton(int gamepad, int button, bool down) +{ + if (gamepad < MAX_GAMEPADS) + { + if (button < MAX_GAMEPAD_BUTTONS) + { + CORE.Input.Gamepad.currentState[gamepad][button] = down; + CORE.Input.Gamepad.lastButtonPressed = button; + } + } +} + +void UWPRegisterGamepadAxis(int gamepad, int axis, float value) +{ + if (gamepad < MAX_GAMEPADS) + { + if (axis < MAX_GAMEPAD_AXIS) CORE.Input.Gamepad.axisState[gamepad][axis] = value; + } +} + +void UWPGestureMove(int pointer, float x, float y) +{ +#if defined(SUPPORT_GESTURES_SYSTEM) + GestureEvent gestureEvent = { 0 }; + + // Assign the pointer ID and touch action + gestureEvent.pointerId[0] = pointer; + gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0].x = x; + gestureEvent.position[0].y = y; + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +void UWPGestureTouch(int pointer, float x, float y, bool touch) +{ +#if defined(SUPPORT_GESTURES_SYSTEM) + GestureEvent gestureEvent = { 0 }; + + // Assign the pointer ID and touch action + gestureEvent.pointerId[0] = pointer; + gestureEvent.touchAction = touch ? TOUCH_DOWN : TOUCH_UP; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0].x = x; + gestureEvent.position[0].y = y; + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +#endif // PLATFORM_UWP + +#if defined(PLATFORM_DRM) +// Search matching DRM mode in connector's mode list +static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode) +{ + if (NULL == connector) return -1; + if (NULL == mode) return -1; + + // safe bitwise comparison of two modes + #define BINCMP(a, b) memcmp((a), (b), (sizeof(a) < sizeof(b)) ? sizeof(a) : sizeof(b)) + + for (size_t i = 0; i < connector->count_modes; i++) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay, + connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive"); + + if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i])) return i; + } + + return -1; + + #undef BINCMP +} + +// Search exactly matching DRM connector mode in connector's list +static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced) +{ + TRACELOG(LOG_TRACE, "DISPLAY: Searching exact connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s", width, height, fps, allowInterlaced ? "yes" : "no"); + + if (NULL == connector) return -1; + + for (int i = 0; i < CORE.Window.connector->count_modes; i++) + { + const drmModeModeInfo *const mode = &CORE.Window.connector->modes[i]; + + TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive"); + + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && (!allowInterlaced)) continue; + + if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i; + } + + TRACELOG(LOG_TRACE, "DISPLAY: No DRM exact matching mode found"); + return -1; +} + +// Search the nearest matching DRM connector mode in connector's list +static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced) +{ + TRACELOG(LOG_TRACE, "DISPLAY: Searching nearest connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s", width, height, fps, allowInterlaced ? "yes" : "no"); + + if (NULL == connector) return -1; + + int nearestIndex = -1; + for (int i = 0; i < CORE.Window.connector->count_modes; i++) + { + const drmModeModeInfo *const mode = &CORE.Window.connector->modes[i]; + + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, + (mode->flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive"); + + if ((mode->hdisplay < width) || (mode->vdisplay < height) | (mode->vrefresh < fps)) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode is too small"); + continue; + } + + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && (!allowInterlaced)) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode"); + continue; + } + + if ((mode->hdisplay >= width) && (mode->vdisplay >= height) && (mode->vrefresh >= fps)) + { + const int widthDiff = mode->hdisplay - width; + const int heightDiff = mode->vdisplay - height; + const int fpsDiff = mode->vrefresh - fps; + + if (nearestIndex < 0) + { + nearestIndex = i; + continue; + } + + const int nearestWidthDiff = CORE.Window.connector->modes[nearestIndex].hdisplay - width; + const int nearestHeightDiff = CORE.Window.connector->modes[nearestIndex].vdisplay - height; + const int nearestFpsDiff = CORE.Window.connector->modes[nearestIndex].vrefresh - fps; + + if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) nearestIndex = i; + } + } + + return nearestIndex; +} +#endif diff --git a/raylib/rcore.go b/raylib/core.go similarity index 52% rename from raylib/rcore.go rename to raylib/core.go index 213a656..449ab9f 100644 --- a/raylib/rcore.go +++ b/raylib/core.go @@ -7,63 +7,32 @@ package rl import "C" import ( - "image/color" "unsafe" ) -// newVector2FromPointer - Returns new Vector2 from pointer -func newVector2FromPointer(ptr unsafe.Pointer) Vector2 { - return *(*Vector2)(ptr) -} - // cptr returns C pointer func (v *Vector2) cptr() *C.Vector2 { return (*C.Vector2)(unsafe.Pointer(v)) } -// newVector3FromPointer - Returns new Vector3 from pointer -func newVector3FromPointer(ptr unsafe.Pointer) Vector3 { - return *(*Vector3)(ptr) -} - // cptr returns C pointer func (v *Vector3) cptr() *C.Vector3 { return (*C.Vector3)(unsafe.Pointer(v)) } -// newVector4FromPointer - Returns new Vector4 from pointer -func newVector4FromPointer(ptr unsafe.Pointer) Vector4 { - return *(*Vector4)(ptr) -} - // cptr returns C pointer func (v *Vector4) cptr() *C.Vector4 { return (*C.Vector4)(unsafe.Pointer(v)) } -// newMatrixFromPointer - Returns new Matrix from pointer -func newMatrixFromPointer(ptr unsafe.Pointer) Matrix { - return *(*Matrix)(ptr) -} - // cptr returns C pointer func (m *Matrix) cptr() *C.Matrix { return (*C.Matrix)(unsafe.Pointer(m)) } -// newColorFromPointer - Returns new Color from pointer -func newColorFromPointer(ptr unsafe.Pointer) color.RGBA { - return *(*color.RGBA)(ptr) -} - -// colorCptr returns color C pointer -func colorCptr(col color.RGBA) *C.Color { - return (*C.Color)(unsafe.Pointer(&col)) -} - -// newRectangleFromPointer - Returns new Rectangle from pointer -func newRectangleFromPointer(ptr unsafe.Pointer) Rectangle { - return *(*Rectangle)(ptr) +// cptr returns C pointer +func (color *Color) cptr() *C.Color { + return (*C.Color)(unsafe.Pointer(color)) } // cptr returns C pointer @@ -71,67 +40,22 @@ func (r *Rectangle) cptr() *C.Rectangle { return (*C.Rectangle)(unsafe.Pointer(r)) } -// newCamera3DFromPointer - Returns new Camera3D from pointer -func newCamera3DFromPointer(ptr unsafe.Pointer) Camera3D { - return *(*Camera3D)(ptr) -} - // cptr returns C pointer func (c *Camera) cptr() *C.Camera { return (*C.Camera)(unsafe.Pointer(c)) } -// newCamera2DFromPointer - Returns new Camera2D from pointer -func newCamera2DFromPointer(ptr unsafe.Pointer) Camera2D { - return *(*Camera2D)(ptr) -} - // cptr returns C pointer func (c *Camera2D) cptr() *C.Camera2D { return (*C.Camera2D)(unsafe.Pointer(c)) } -// newBoundingBoxFromPointer - Returns new BoundingBox from pointer -func newBoundingBoxFromPointer(ptr unsafe.Pointer) BoundingBox { - return *(*BoundingBox)(ptr) -} - // cptr returns C pointer func (b *BoundingBox) cptr() *C.BoundingBox { return (*C.BoundingBox)(unsafe.Pointer(b)) } -// newShaderFromPointer - Returns new Shader from pointer -func newShaderFromPointer(ptr unsafe.Pointer) Shader { - return *(*Shader)(ptr) -} - -// cptr returns C pointer -func (s *Shader) cptr() *C.Shader { - return (*C.Shader)(unsafe.Pointer(s)) -} - -// newAutomationEventFromPointer - Returns new AutomationEvent from pointer -func newAutomationEventFromPointer(ptr unsafe.Pointer) AutomationEvent { - return *(*AutomationEvent)(ptr) -} - -// cptr returns C pointer -func (a *AutomationEvent) cptr() *C.AutomationEvent { - return (*C.AutomationEvent)(unsafe.Pointer(a)) -} - -// newAutomationEventListFromPointer - Returns new AutomationEventList from pointer -func newAutomationEventListFromPointer(ptr unsafe.Pointer) AutomationEventList { - return *(*AutomationEventList)(ptr) -} - -// cptr returns C pointer -func (a *AutomationEventList) cptr() *C.AutomationEventList { - return (*C.AutomationEventList)(unsafe.Pointer(a)) -} - -// WindowShouldClose - Check if KeyEscape pressed or Close icon pressed +// WindowShouldClose - Check if KEY_ESCAPE pressed or Close icon pressed func WindowShouldClose() bool { ret := C.WindowShouldClose() v := bool(ret) @@ -193,7 +117,7 @@ func IsWindowResized() bool { } // IsWindowState - Check if one specific window flag is enabled -func IsWindowState(flag uint32) bool { +func IsWindowState(flag byte) bool { cflag := (C.uint)(flag) ret := C.IsWindowState(cflag) v := bool(ret) @@ -201,13 +125,13 @@ func IsWindowState(flag uint32) bool { } // SetWindowState - Set window configuration state using flags -func SetWindowState(flags uint32) { +func SetWindowState(flags byte) { cflags := (C.uint)(flags) C.SetWindowState(cflags) } // ClearWindowState - Clear window configuration state flags -func ClearWindowState(flags uint32) { +func ClearWindowState(flags byte) { cflags := (C.uint)(flags) C.ClearWindowState(cflags) } @@ -217,11 +141,6 @@ func ToggleFullscreen() { C.ToggleFullscreen() } -// ToggleBorderlessWindowed - Borderless fullscreen toggle (only PLATFORM_DESKTOP) -func ToggleBorderlessWindowed() { - C.ToggleBorderlessWindowed() -} - // MaximizeWindow - Set window state: maximized, if resizable func MaximizeWindow() { C.MaximizeWindow() @@ -237,19 +156,12 @@ func RestoreWindow() { C.RestoreWindow() } -// SetWindowIcon - Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) +// SetWindowIcon - Set icon for window (only PLATFORM_DESKTOP) func SetWindowIcon(image Image) { cimage := image.cptr() C.SetWindowIcon(*cimage) } -// SetWindowIcons - Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) -func SetWindowIcons(images []Image, count int32) { - cimages := (&images[0]).cptr() - cimagesCount := C.int(count) - C.SetWindowIcons(cimages, cimagesCount) -} - // SetWindowTitle - Set title for window (only PLATFORM_DESKTOP) func SetWindowTitle(title string) { ctitle := C.CString(title) @@ -277,13 +189,6 @@ func SetWindowMinSize(w, h int) { C.SetWindowMinSize(cw, ch) } -// SetWindowMaxSize - Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) -func SetWindowMaxSize(w, h int) { - cw := (C.int)(w) - ch := (C.int)(h) - C.SetWindowMaxSize(cw, ch) -} - // SetWindowSize - Set window dimensions func SetWindowSize(w, h int) { cw := (C.int)(w) @@ -291,18 +196,6 @@ func SetWindowSize(w, h int) { C.SetWindowSize(cw, ch) } -// SetWindowOpacity - Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) -func SetWindowOpacity(opacity float32) { - copacity := (C.float)(opacity) - C.SetWindowOpacity(copacity) -} - -// GetWindowHandle - Get native window handle -func GetWindowHandle() unsafe.Pointer { - v := C.GetWindowHandle() - return v -} - // GetScreenWidth - Get current screen width func GetScreenWidth() int { ret := C.GetScreenWidth() @@ -317,20 +210,6 @@ func GetScreenHeight() int { return v } -// GetRenderWidth - Get current render width (it considers HiDPI) -func GetRenderWidth() int { - ret := C.GetRenderWidth() - v := (int)(ret) - return v -} - -// GetRenderHeight - Get current render height (it considers HiDPI) -func GetRenderHeight() int { - ret := C.GetRenderHeight() - v := (int)(ret) - return v -} - // GetMonitorCount - Get number of connected monitors func GetMonitorCount() int { ret := C.GetMonitorCount() @@ -338,7 +217,7 @@ func GetMonitorCount() int { return v } -// GetCurrentMonitor - Get current monitor where window is placed +// GetCurrentMonitor - Get current connected monitor func GetCurrentMonitor() int { ret := C.GetCurrentMonitor() v := (int)(ret) @@ -429,28 +308,9 @@ func GetClipboardText() string { return v } -// GetClipboardImage - Get clipboard image content -// -// Only works with SDL3 backend or Windows with GLFW/RGFW -func GetClipboardImage() Image { - ret := C.GetClipboardImage() - v := newImageFromPointer(unsafe.Pointer(&ret)) - return *v -} - -// EnableEventWaiting - Enable waiting for events on EndDrawing(), no automatic event polling -func EnableEventWaiting() { - C.EnableEventWaiting() -} - -// DisableEventWaiting - Disable waiting for events on EndDrawing(), automatic events polling -func DisableEventWaiting() { - C.DisableEventWaiting() -} - // ClearBackground - Sets Background Color -func ClearBackground(col color.RGBA) { - ccolor := colorCptr(col) +func ClearBackground(color Color) { + ccolor := color.cptr() C.ClearBackground(*ccolor) } @@ -511,144 +371,11 @@ func EndScissorMode() { C.EndScissorMode() } -// LoadShader - Load a custom shader and bind default locations -func LoadShader(vsFileName string, fsFileName string) Shader { - cvsFileName := C.CString(vsFileName) - defer C.free(unsafe.Pointer(cvsFileName)) - - cfsFileName := C.CString(fsFileName) - defer C.free(unsafe.Pointer(cfsFileName)) - - if vsFileName == "" { - cvsFileName = nil - } - - if fsFileName == "" { - cfsFileName = nil - } - - ret := C.LoadShader(cvsFileName, cfsFileName) - v := newShaderFromPointer(unsafe.Pointer(&ret)) - - return v -} - -// LoadShaderFromMemory - Load shader from code strings and bind default locations -func LoadShaderFromMemory(vsCode string, fsCode string) Shader { - cvsCode := C.CString(vsCode) - defer C.free(unsafe.Pointer(cvsCode)) - - cfsCode := C.CString(fsCode) - defer C.free(unsafe.Pointer(cfsCode)) - - if vsCode == "" { - cvsCode = nil - } - - if fsCode == "" { - cfsCode = nil - } - - ret := C.LoadShaderFromMemory(cvsCode, cfsCode) - v := newShaderFromPointer(unsafe.Pointer(&ret)) - - return v -} - -// IsShaderValid - Check if a shader is valid (loaded on GPU) -func IsShaderValid(shader Shader) bool { - cshader := shader.cptr() - ret := C.IsShaderValid(*cshader) - v := bool(ret) - return v -} - -// GetShaderLocation - Get shader uniform location -func GetShaderLocation(shader Shader, uniformName string) int32 { - cshader := shader.cptr() - cuniformName := C.CString(uniformName) - defer C.free(unsafe.Pointer(cuniformName)) - - ret := C.GetShaderLocation(*cshader, cuniformName) - v := (int32)(ret) - return v -} - -// GetShaderLocationAttrib - Get shader attribute location -func GetShaderLocationAttrib(shader Shader, attribName string) int32 { - cshader := shader.cptr() - cuniformName := C.CString(attribName) - defer C.free(unsafe.Pointer(cuniformName)) - - ret := C.GetShaderLocationAttrib(*cshader, cuniformName) - v := (int32)(ret) - return v -} - -// SetShaderValue - Set shader uniform value (float) -func SetShaderValue(shader Shader, locIndex int32, value []float32, uniformType ShaderUniformDataType) { - cshader := shader.cptr() - clocIndex := (C.int)(locIndex) - cvalue := (*C.float)(unsafe.Pointer(&value[0])) - cuniformType := (C.int)(uniformType) - C.SetShaderValue(*cshader, clocIndex, unsafe.Pointer(cvalue), cuniformType) -} - -// SetShaderValueV - Set shader uniform value (float) -func SetShaderValueV(shader Shader, locIndex int32, value []float32, uniformType ShaderUniformDataType, count int32) { - cshader := shader.cptr() - clocIndex := (C.int)(locIndex) - cvalue := (*C.float)(unsafe.Pointer(&value[0])) - cuniformType := (C.int)(uniformType) - ccount := (C.int)(count) - C.SetShaderValueV(*cshader, clocIndex, unsafe.Pointer(cvalue), cuniformType, ccount) -} - -// SetShaderValueMatrix - Set shader uniform value (matrix 4x4) -func SetShaderValueMatrix(shader Shader, locIndex int32, mat Matrix) { - cshader := shader.cptr() - clocIndex := (C.int)(locIndex) - cmat := mat.cptr() - C.SetShaderValueMatrix(*cshader, clocIndex, *cmat) -} - -// SetShaderValueTexture - Set shader uniform value for texture (sampler2d) -func SetShaderValueTexture(shader Shader, locIndex int32, texture Texture2D) { - cshader := shader.cptr() - clocIndex := (C.int)(locIndex) - ctexture := texture.cptr() - C.SetShaderValueTexture(*cshader, clocIndex, *ctexture) -} - -// UnloadShader - Unload a custom shader from memory -func UnloadShader(shader Shader) { - cshader := shader.cptr() - C.UnloadShader(*cshader) -} - -// GetMouseRay - Get a ray trace from mouse position -// -// Deprecated: Use [GetScreenToWorldRay] instead. +// GetMouseRay - Returns a ray trace from mouse position func GetMouseRay(mousePosition Vector2, camera Camera) Ray { - return GetScreenToWorldRay(mousePosition, camera) -} - -// GetScreenToWorldRay - Get a ray trace from screen position (i.e mouse) -func GetScreenToWorldRay(position Vector2, camera Camera) Ray { - cposition := position.cptr() + cmousePosition := mousePosition.cptr() ccamera := camera.cptr() - ret := C.GetScreenToWorldRay(*cposition, *ccamera) - v := newRayFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetScreenToWorldRayEx - Get a ray trace from screen position (i.e mouse) in a viewport -func GetScreenToWorldRayEx(position Vector2, camera Camera, width, height int32) Ray { - cposition := position.cptr() - ccamera := camera.cptr() - cwidth := (C.int)(width) - cheight := (C.int)(height) - ret := C.GetScreenToWorldRayEx(*cposition, *ccamera, cwidth, cheight) + ret := C.GetMouseRay(*cmousePosition, *ccamera) v := newRayFromPointer(unsafe.Pointer(&ret)) return v } @@ -678,26 +405,6 @@ func GetWorldToScreen(position Vector3, camera Camera) Vector2 { return v } -// GetScreenToWorld2D - Returns the world space position for a 2d camera screen space position -func GetScreenToWorld2D(position Vector2, camera Camera2D) Vector2 { - cposition := position.cptr() - ccamera := camera.cptr() - ret := C.GetScreenToWorld2D(*cposition, *ccamera) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetWorldToScreenEx - Get size position for a 3d world space position -func GetWorldToScreenEx(position Vector3, camera Camera, width int32, height int32) Vector2 { - cposition := position.cptr() - ccamera := camera.cptr() - cwidth := (C.int)(width) - cheight := (C.int)(height) - ret := C.GetWorldToScreenEx(*cposition, *ccamera, cwidth, cheight) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - // GetWorldToScreen2D - Returns the screen space position for a 2d camera world space position func GetWorldToScreen2D(position Vector2, camera Camera2D) Vector2 { cposition := position.cptr() @@ -707,6 +414,15 @@ func GetWorldToScreen2D(position Vector2, camera Camera2D) Vector2 { return v } +// GetScreenToWorld2D - Returns the world space position for a 2d camera screen space position +func GetScreenToWorld2D(position Vector2, camera Camera2D) Vector2 { + cposition := position.cptr() + ccamera := camera.cptr() + ret := C.GetScreenToWorld2D(*cposition, *ccamera) + v := newVector2FromPointer(unsafe.Pointer(&ret)) + return v +} + // SetTargetFPS - Set target FPS (maximum) func SetTargetFPS(fps int32) { cfps := (C.int)(fps) @@ -714,9 +430,9 @@ func SetTargetFPS(fps int32) { } // GetFPS - Returns current FPS -func GetFPS() int32 { +func GetFPS() float32 { ret := C.GetFPS() - v := (int32)(ret) + v := (float32)(ret) return v } @@ -728,65 +444,42 @@ func GetFrameTime() float32 { } // GetTime - Return time in seconds -func GetTime() float64 { +func GetTime() float32 { ret := C.GetTime() - v := (float64)(ret) + v := (float32)(ret) return v } -// Custom frame control functions -// NOTE: SwapScreenBuffer and PollInputEvents are intended for advanced users that want full control over the frame processing -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() -// To avoid that behaviour and control frame processes manually you can either enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL -// or add CGO_CFLAGS="-DSUPPORT_CUSTOM_FRAME_CONTROL=1" to your build - -// SwapScreenBuffer - Swap back buffer to front buffer -func SwapScreenBuffer() { - C.SwapScreenBuffer() -} - -// Register all input events -func PollInputEvents() { - C.PollInputEvents() -} - -// WaitTime - Wait for some time (halt program execution) -func WaitTime(seconds float64) { - cseconds := (C.double)(seconds) - C.WaitTime(cseconds) -} - // Fade - Returns color with alpha applied, alpha goes from 0.0f to 1.0f -func Fade(col color.RGBA, alpha float32) color.RGBA { - ccolor := colorCptr(col) +func Fade(color Color, alpha float32) Color { + ccolor := color.cptr() calpha := (C.float)(alpha) ret := C.Fade(*ccolor, calpha) v := newColorFromPointer(unsafe.Pointer(&ret)) return v } -// ColorToInt - Get hexadecimal value for a Color (0xRRGGBBAA) -func ColorToInt(col color.RGBA) int32 { - ccolor := colorCptr(col) +// ColorToInt - Returns hexadecimal value for a Color +func ColorToInt(color Color) int32 { + ccolor := color.cptr() ret := C.ColorToInt(*ccolor) v := (int32)(ret) return v } // ColorNormalize - Returns color normalized as float [0..1] -func ColorNormalize(col color.RGBA) Vector4 { +func ColorNormalize(color Color) Vector4 { result := Vector4{} - r, g, b, a := col.R, col.G, col.B, col.A - result.X = float32(r) / 255 - result.Y = float32(g) / 255 - result.Z = float32(b) / 255 - result.W = float32(a) / 255 + result.X = float32(color.R) / 255 + result.Y = float32(color.G) / 255 + result.Z = float32(color.B) / 255 + result.W = float32(color.A) / 255 return result } // ColorFromNormalized - Returns Color from normalized values [0..1] -func ColorFromNormalized(normalized Vector4) color.RGBA { +func ColorFromNormalized(normalized Vector4) Color { cnormalized := normalized.cptr() ret := C.ColorFromNormalized(*cnormalized) v := newColorFromPointer(unsafe.Pointer(&ret)) @@ -794,15 +487,15 @@ func ColorFromNormalized(normalized Vector4) color.RGBA { } // ColorToHSV - Returns HSV values for a Color, hue [0..360], saturation/value [0..1] -func ColorToHSV(col color.RGBA) Vector3 { - ccolor := colorCptr(col) +func ColorToHSV(color Color) Vector3 { + ccolor := color.cptr() ret := C.ColorToHSV(*ccolor) v := newVector3FromPointer(unsafe.Pointer(&ret)) return v } // ColorFromHSV - Returns a Color from HSV values, hue [0..360], saturation/value [0..1] -func ColorFromHSV(hue, saturation, value float32) color.RGBA { +func ColorFromHSV(hue, saturation, value float32) Color { chue := (C.float)(hue) csaturation := (C.float)(saturation) cvalue := (C.float)(value) @@ -811,60 +504,24 @@ func ColorFromHSV(hue, saturation, value float32) color.RGBA { return v } -// ColorTint - Get color multiplied with another color -func ColorTint(col color.RGBA, tint color.RGBA) color.RGBA { - ccolor := colorCptr(col) - ctint := colorCptr(tint) - ret := C.ColorTint(*ccolor, *ctint) - v := newColorFromPointer(unsafe.Pointer(&ret)) - return v -} - -// ColorBrightness - Get color with brightness correction, brightness factor goes from -1.0f to 1.0f -func ColorBrightness(col color.RGBA, factor float32) color.RGBA { - ccolor := colorCptr(col) - cfactor := C.float(factor) - ret := C.ColorBrightness(*ccolor, cfactor) - v := newColorFromPointer(unsafe.Pointer(&ret)) - return v -} - -// ColorContrast - Get color with contrast correction, contrast values between -1.0f and 1.0f -func ColorContrast(col color.RGBA, contrast float32) color.RGBA { - ccolor := colorCptr(col) - ccontrast := C.float(contrast) - ret := C.ColorContrast(*ccolor, ccontrast) - v := newColorFromPointer(unsafe.Pointer(&ret)) - return v -} - // ColorAlpha - Returns color with alpha applied, alpha goes from 0.0f to 1.0f -func ColorAlpha(col color.RGBA, alpha float32) color.RGBA { - return Fade(col, alpha) +func ColorAlpha(color Color, alpha float32) Color { + return Fade(color, alpha) } // ColorAlphaBlend - Returns src alpha-blended into dst color with tint -func ColorAlphaBlend(src, dst, tint color.RGBA) color.RGBA { - csrc := colorCptr(src) - cdst := colorCptr(dst) - ctint := colorCptr(tint) +func ColorAlphaBlend(src, dst, tint Color) Color { + csrc := src.cptr() + cdst := dst.cptr() + ctint := tint.cptr() ret := C.ColorAlphaBlend(*csrc, *cdst, *ctint) v := newColorFromPointer(unsafe.Pointer(&ret)) return v } -// ColorLerp - Get color lerp interpolation between two colors, factor [0.0f..1.0f] -func ColorLerp(col1, col2 color.RGBA, factor float32) color.RGBA { - ccol1 := colorCptr(col1) - ccol2 := colorCptr(col2) - ret := C.ColorLerp(*ccol1, *ccol2, C.float(factor)) - v := newColorFromPointer(unsafe.Pointer(&ret)) - return v -} - // GetColor - Returns a Color struct from hexadecimal value -func GetColor(hexValue uint) color.RGBA { - chexValue := (C.uint)(hexValue) +func GetColor(hexValue int32) Color { + chexValue := (C.int)(hexValue) ret := C.GetColor(chexValue) v := newColorFromPointer(unsafe.Pointer(&ret)) return v @@ -890,6 +547,30 @@ func Vector3ToFloat(vec Vector3) []float32 { return data } +// MatrixToFloat - Converts Matrix to float32 slice +func MatrixToFloat(mat Matrix) []float32 { + data := make([]float32, 0) + + data[0] = mat.M0 + data[1] = mat.M4 + data[2] = mat.M8 + data[3] = mat.M12 + data[4] = mat.M1 + data[5] = mat.M5 + data[6] = mat.M9 + data[7] = mat.M13 + data[8] = mat.M2 + data[9] = mat.M6 + data[10] = mat.M10 + data[11] = mat.M14 + data[12] = mat.M3 + data[13] = mat.M7 + data[14] = mat.M11 + data[15] = mat.M15 + + return data +} + // GetRandomValue - Returns a random value between min and max (both included) func GetRandomValue(min, max int32) int32 { cmin := (C.int)(min) @@ -899,15 +580,8 @@ func GetRandomValue(min, max int32) int32 { return v } -// OpenURL - Open URL with default system browser (if available) -func OpenURL(url string) { - curl := C.CString(url) - defer C.free(unsafe.Pointer(curl)) - C.OpenURL(curl) -} - // SetConfigFlags - Setup some window configuration flags -func SetConfigFlags(flags uint32) { +func SetConfigFlags(flags byte) { cflags := (C.uint)(flags) C.SetConfigFlags(cflags) } @@ -919,59 +593,21 @@ func TakeScreenshot(name string) { C.TakeScreenshot(cname) } -// LoadAutomationEventList - Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS -func LoadAutomationEventList(fileName string) AutomationEventList { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - - ret := C.LoadAutomationEventList(cfileName) - v := newAutomationEventListFromPointer(unsafe.Pointer(&ret)) +// SaveStorageValue - Storage save integer value (to defined position) +func SaveStorageValue(position, value int32) { + cposition := (C.uint)(position) + cvalue := (C.int)(value) + C.SaveStorageValue(cposition, cvalue) +} +// LoadStorageValue - Storage load integer value (from defined position) +func LoadStorageValue(position int32) int32 { + cposition := (C.uint)(position) + ret := C.LoadStorageValue(cposition) + v := (int32)(ret) return v } -// UnloadAutomationEventList - Unload automation events list from file -func UnloadAutomationEventList(list *AutomationEventList) { - C.UnloadAutomationEventList(*list.cptr()) -} - -// ExportAutomationEventList - Export automation events list as text file -func ExportAutomationEventList(list AutomationEventList, fileName string) bool { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - - ret := C.ExportAutomationEventList(*list.cptr(), cfileName) - v := bool(ret) - - return v -} - -// SetAutomationEventList - Set automation event list to record to -func SetAutomationEventList(list *AutomationEventList) { - C.SetAutomationEventList(list.cptr()) -} - -// SetAutomationEventBaseFrame - Set automation event internal base frame to start recording -func SetAutomationEventBaseFrame(frame int) { - cframe := (C.int)(frame) - C.SetAutomationEventBaseFrame(cframe) -} - -// StartAutomationEventRecording - Start recording automation events (AutomationEventList must be set) -func StartAutomationEventRecording() { - C.StartAutomationEventRecording() -} - -// StopAutomationEventRecording - Stop recording automation events -func StopAutomationEventRecording() { - C.StopAutomationEventRecording() -} - -// PlayAutomationEvent - Play a recorded automation event -func PlayAutomationEvent(event AutomationEvent) { - C.PlayAutomationEvent(*event.cptr()) -} - // IsKeyPressed - Detect if a key has been pressed once func IsKeyPressed(key int32) bool { ckey := (C.int)(key) @@ -980,14 +616,6 @@ func IsKeyPressed(key int32) bool { return v } -// IsKeyPressedRepeat - Detect if a key has been pressed again (Only PLATFORM_DESKTOP) -func IsKeyPressedRepeat(key int32) bool { - ckey := (C.int)(key) - ret := C.IsKeyPressedRepeat(ckey) - v := bool(ret) - return v -} - // IsKeyDown - Detect if a key is being pressed func IsKeyDown(key int32) bool { ckey := (C.int)(key) @@ -1019,13 +647,6 @@ func GetKeyPressed() int32 { return v } -// GetCharPressed - Get the last char pressed -func GetCharPressed() int32 { - ret := C.GetCharPressed() - v := (int32)(ret) - return v -} - // SetExitKey - Set a custom key to exit program (default is ESC) func SetExitKey(key int32) { ckey := (C.int)(key) @@ -1040,6 +661,16 @@ func IsGamepadAvailable(gamepad int32) bool { return v } +// IsGamepadName - Check gamepad name (if available) +func IsGamepadName(gamepad int32, name string) bool { + cgamepad := (C.int)(gamepad) + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + ret := C.IsGamepadName(cgamepad, cname) + v := bool(ret) + return v +} + // GetGamepadName - Return gamepad internal name id func GetGamepadName(gamepad int32) string { cgamepad := (C.int)(gamepad) @@ -1109,7 +740,7 @@ func GetGamepadAxisMovement(gamepad, axis int32) float32 { } // SetGamepadMappings - Set internal gamepad mappings (SDL_GameControllerDB) -func SetGamepadMappings(mappings string) int32 { +func SetGamepadMapping(mappings string) int32 { cmappings := C.CString(mappings) defer C.free(unsafe.Pointer(cmappings)) ret := C.SetGamepadMappings(cmappings) @@ -1117,13 +748,8 @@ func SetGamepadMappings(mappings string) int32 { return v } -// SetGamepadVibration - Set gamepad vibration for both motors (duration in seconds) -func SetGamepadVibration(gamepad int32, leftMotor, rightMotor, duration float32) { - C.SetGamepadVibration(C.int(gamepad), C.float(leftMotor), C.float(rightMotor), C.float(duration)) -} - // IsMouseButtonPressed - Detect if a mouse button has been pressed once -func IsMouseButtonPressed(button MouseButton) bool { +func IsMouseButtonPressed(button int32) bool { cbutton := (C.int)(button) ret := C.IsMouseButtonPressed(cbutton) v := bool(ret) @@ -1131,7 +757,7 @@ func IsMouseButtonPressed(button MouseButton) bool { } // IsMouseButtonDown - Detect if a mouse button is being pressed -func IsMouseButtonDown(button MouseButton) bool { +func IsMouseButtonDown(button int32) bool { cbutton := (C.int)(button) ret := C.IsMouseButtonDown(cbutton) v := bool(ret) @@ -1139,7 +765,7 @@ func IsMouseButtonDown(button MouseButton) bool { } // IsMouseButtonReleased - Detect if a mouse button has been released once -func IsMouseButtonReleased(button MouseButton) bool { +func IsMouseButtonReleased(button int32) bool { cbutton := (C.int)(button) ret := C.IsMouseButtonReleased(cbutton) v := bool(ret) @@ -1147,7 +773,7 @@ func IsMouseButtonReleased(button MouseButton) bool { } // IsMouseButtonUp - Detect if a mouse button is NOT being pressed -func IsMouseButtonUp(button MouseButton) bool { +func IsMouseButtonUp(button int32) bool { cbutton := (C.int)(button) ret := C.IsMouseButtonUp(cbutton) v := bool(ret) @@ -1175,13 +801,6 @@ func GetMousePosition() Vector2 { return v } -// GetMouseDelta - Get mouse delta between frames -func GetMouseDelta() Vector2 { - ret := C.GetMouseDelta() - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - // SetMousePosition - Set mouse position XY func SetMousePosition(x, y int) { cx := (C.int)(x) @@ -1203,26 +822,13 @@ func SetMouseScale(scaleX, scaleY float32) { C.SetMouseScale(cscaleX, cscaleY) } -// GetMouseWheelMove - Get mouse wheel movement for X or Y, whichever is larger -func GetMouseWheelMove() float32 { +// GetMouseWheelMove - Returns mouse wheel movement Y +func GetMouseWheelMove() int32 { ret := C.GetMouseWheelMove() - v := (float32)(ret) + v := (int32)(ret) return v } -// GetMouseWheelMoveV - Get mouse wheel movement for both X and Y -func GetMouseWheelMoveV() Vector2 { - ret := C.GetMouseWheelMoveV() - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// SetMouseCursor - Set mouse cursor -func SetMouseCursor(cursor int32) { - ccursor := (C.int)(cursor) - C.SetMouseCursor(ccursor) -} - // GetTouchX - Returns touch position X for touch point 0 (relative to screen size) func GetTouchX() int32 { ret := C.GetTouchX() @@ -1244,39 +850,3 @@ func GetTouchPosition(index int32) Vector2 { v := newVector2FromPointer(unsafe.Pointer(&ret)) return v } - -// GetTouchPointId - Get touch point identifier for given index -func GetTouchPointId(index int32) int32 { - cindex := (C.int)(index) - ret := C.GetTouchPointId(cindex) - v := (int32)(ret) - return v -} - -// GetTouchPointCount - Get number of touch points -func GetTouchPointCount() int32 { - ret := C.GetTouchPointCount() - v := (int32)(ret) - return v -} - -// BeginVrStereoMode - Begin stereo rendering (requires VR simulator) -func BeginVrStereoMode(config VrStereoConfig) { - C.BeginVrStereoMode(*(*C.VrStereoConfig)(unsafe.Pointer(&config))) -} - -// EndVrStereoMode - End stereo rendering (requires VR simulator) -func EndVrStereoMode() { - C.EndVrStereoMode() -} - -// LoadVrStereoConfig - Load VR stereo config for VR simulator device parameters -func LoadVrStereoConfig(device VrDeviceInfo) VrStereoConfig { - ret := C.LoadVrStereoConfig(*(*C.VrDeviceInfo)(unsafe.Pointer(&device))) - return *(*VrStereoConfig)(unsafe.Pointer(&ret)) -} - -// UnloadVrStereoConfig - Unload VR stereo config -func UnloadVrStereoConfig(config VrStereoConfig) { - C.UnloadVrStereoConfig(*(*C.VrStereoConfig)(unsafe.Pointer(&config))) -} diff --git a/raylib/external/RGFW.h b/raylib/external/RGFW.h deleted file mode 100644 index 1582fbf..0000000 --- a/raylib/external/RGFW.h +++ /dev/null @@ -1,10837 +0,0 @@ -/* -* -* RGFW 1.7.5-dev - -* Copyright (C) 2022-25 ColleagueRiley -* -* libpng license -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. - -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -* -* -*/ - -/* - (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION) - #define RGFW_IMPLEMENTATION - makes it so source code is included with header -*/ - -/* - #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included - #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found - #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl) - #define RGFW_BUFFER - (optional) draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format) - #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api) - #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api) - This version doesn't work for desktops (I'm pretty sure) - #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2) - #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3) - #define RGFW_DIRECTX - (optional) include integration directX functions (windows only) - #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros - #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY) - #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX) - - #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress) - #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS - #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11) - #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland - #define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime - #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor - #define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) use XCursor, but don't link it in code, (you'll have to link it with -lXcursor) - #define RGFW_NO_X11_EXT_PRELOAD (optional) (unix only) use Xext, but don't link it in code, (you'll have to link it with -lXext) - #define RGFW_NO_LOAD_WINMM (optional) (windows only) use winmm (timeBeginPeriod), but don't link it in code, (you'll have to link it with -lwinmm) - #define RGFW_NO_WINMM (optional) (windows only) don't use winmm - #define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit - #define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions - #define RGFW_NO_DWM (windows only) - do not use or link dwmapi - #define RGFW_USE_XDL (optional) (X11) if XDL (XLib Dynamic Loader) should be used to load X11 dynamically during runtime (must include XDL.h along with RGFW) - #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU) - #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name - #define RGFW_NO_DPI - do not calculate DPI (no XRM nor libShcore included) - #define RGFW_BUFFER_BGR - use the BGR format for bufffers instead of RGB, saves processing time - #define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue) - - #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc) - #define RGFW_FREE x - choose the default deallocation function (defaults to standard free) - #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default) - - #define RGFW_EXPORT - use when building RGFW - #define RGFW_IMPORT - use when linking with RGFW (not as a single-header) - - #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc)) - #define RGFW_bool x - choose what type to use for bool, by default u32 is used -*/ - -/* -Example to get you started : - -linux : gcc main.c -lX11 -lXrandr -lGL -windows : gcc main.c -lopengl32 -lgdi32 -macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit - -#define RGFW_IMPLEMENTATION -#include "RGFW.h" - -u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF}; - -int main() { - RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0); - - RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4); - - while (RGFW_window_shouldClose(win) == RGFW_FALSE) { - while (RGFW_window_checkEvent(win)) { - if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape)) - break; - } - - RGFW_window_swapBuffers(win); - - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); - } - - RGFW_window_close(win); -} - - compiling : - - if you wish to compile the library all you have to do is create a new file with this in it - - rgfw.c - #define RGFW_IMPLEMENTATION - #include "RGFW.h" - - You may also want to add - `#define RGFW_EXPORT` when compiling and - `#define RGFW_IMPORT`when linking RGFW on it's own: - this reduces inline functions and prevents bloat in the object file - - then you can use gcc (or whatever compile you wish to use) to compile the library into object file - - ex. gcc -c RGFW.c -fPIC - - after you compile the library into an object file, you can also turn the object file into an static or shared library - - (commands ar and gcc can be replaced with whatever equivalent your system uses) - - static : ar rcs RGFW.a RGFW.o - shared : - windows: - gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll - linux: - gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so - macos: - gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit -*/ - - - -/* - Credits : - EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing - - stb - This project is heavily inspired by the stb single header files - - GLFW: - certain parts of winapi and X11 are very poorly documented, - GLFW's source code was referenced and used throughout the project. - - contributors : (feel free to put yourself here if you contribute) - krisvers -> code review - EimaMei (SaCode) -> code review - Code-Nycticebus -> bug fixes - Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs - AICDG (@THISISAGOODNAME) -> vulkan support (example) - @Easymode -> support, testing/debugging, bug fixes and reviews - Joshua Rowe (omnisci3nce) - bug fix, review (macOS) - @lesleyrs -> bug fix, review (OpenGL) - Nick Porcino (meshula) - testing, organization, review (MacOS, examples) - @DarekParodia -> code review (X11) (C++) -*/ - -#if _MSC_VER - #pragma comment(lib, "gdi32") - #pragma comment(lib, "shell32") - #pragma comment(lib, "User32") - #pragma warning( push ) - #pragma warning( disable : 4996 4191 4127) - #if _MSC_VER < 600 - #define RGFW_C89 - #endif -#else - #if defined(__STDC__) && !defined(__STDC_VERSION__) - #define RGFW_C89 - #endif -#endif - -#ifndef RGFW_USERPTR - #define RGFW_USERPTR NULL -#endif - -#ifndef RGFW_UNUSED - #define RGFW_UNUSED(x) (void)(x) -#endif - -#ifndef RGFW_ROUND - #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f) -#endif - -#ifndef RGFW_ALLOC - #include - #define RGFW_ALLOC malloc - #define RGFW_FREE free -#endif - -#ifndef RGFW_ASSERT - #include - #define RGFW_ASSERT assert -#endif - -#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET) - #include -#endif - -#ifndef RGFW_MEMSET - #define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num) -#endif - -#ifndef RGFW_MEMCPY - #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len) -#endif - -#ifndef RGFW_STRNCMP - #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max) -#endif - -#ifndef RGFW_STRNCPY - #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len) -#endif - -#ifndef RGFW_STRSTR - #define RGFW_STRSTR(str, substr) strstr(str, substr) -#endif - -#ifndef RGFW_STRTOL - /* required for X11 XDnD and X11 Monitor DPI */ - #include - #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base) - #define RGFW_ATOF(num) atof(num) -#endif - -#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */ - #define RGFW_NO_MONITOR - #define RGFW_NO_PASSTHROUGH -#endif - -#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT) - #if defined(_WIN32) - #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT)) - #define __declspec(x) __attribute__((x)) - #endif - - #if defined(RGFW_EXPORT) - #define RGFWDEF __declspec(dllexport) - #else - #define RGFWDEF __declspec(dllimport) - #endif - #else - #if defined(RGFW_EXPORT) - #define RGFWDEF __attribute__((visibility("default"))) - #endif - #endif - #ifndef RGFWDEF - #define RGFWDEF - #endif -#endif - -#ifndef RGFWDEF - #ifdef RGFW_C89 - #define RGFWDEF __inline - #else - #define RGFWDEF inline - #endif -#endif - -#ifndef RGFW_ENUM - #define RGFW_ENUM(type, name) type name; enum -#endif - - -#if defined(__cplusplus) && !defined(__EMSCRIPTEN__) - extern "C" { -#endif - - /* makes sure the header file part is only defined once by default */ -#ifndef RGFW_HEADER - -#define RGFW_HEADER - -#include -#ifndef RGFW_INT_DEFINED - #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */ - typedef unsigned char u8; - typedef signed char i8; - typedef unsigned short u16; - typedef signed short i16; - typedef unsigned long int u32; - typedef signed long int i32; - typedef unsigned long long u64; - typedef signed long long i64; - #else /* use stdint standard types instead of c "standard" types */ - #include - - typedef uint8_t u8; - typedef int8_t i8; - typedef uint16_t u16; - typedef int16_t i16; - typedef uint32_t u32; - typedef int32_t i32; - typedef uint64_t u64; - typedef int64_t i64; - #endif - #define RGFW_INT_DEFINED -#endif - -#ifndef RGFW_BOOL_DEFINED - #define RGFW_BOOL_DEFINED - typedef u8 RGFW_bool; -#endif - -#define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */ -#define RGFW_TRUE (RGFW_bool)1 -#define RGFW_FALSE (RGFW_bool)0 - -/* these OS macros look better & are standardized */ -/* plus it helps with cross-compiling */ - -#ifdef __EMSCRIPTEN__ - #define RGFW_WASM - - #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU) - #define RGFW_OPENGL - #endif - - #ifdef RGFW_EGL - #undef RGFW_EGL - #endif - - #include - #include - - #ifdef RGFW_WEBGPU - #include - #endif -#endif - -#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS_X11 - #define RGFW_UNIX - #undef __APPLE__ -#endif - -#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ - #define RGFW_WINDOWS - /* make sure the correct architecture is defined */ - #if defined(_WIN64) - #define _AMD64_ - #undef _X86_ - #else - #undef _AMD64_ - #ifndef _X86_ - #define _X86_ - #endif - #endif - - #ifndef RGFW_NO_XINPUT - #ifdef __MINGW32__ /* try to find the right header */ - #include - #else - #include - #endif - #endif -#endif -#if defined(RGFW_WAYLAND) - #define RGFW_DEBUG /* wayland will be in debug mode by default for now */ - #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) - #define RGFW_EGL - #define RGFW_OPENGL - #define RGFW_UNIX - #include - #endif - - #include -#endif -#if !defined(RGFW_NO_X11) && !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS_X11 - #define RGFW_X11 - #define RGFW_UNIX - #include - #include -#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS - #if !defined(RGFW_BUFFER_BGR) - #define RGFW_BUFFER_BGR - #else - #undef RGFW_BUFFER_BGR - #endif -#endif - -#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL) - #define RGFW_EGL -#endif - -#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API) - #define RGFW_OPENGL -#endif - -#ifdef RGFW_EGL - #include -#elif defined(RGFW_OSMESA) - #ifdef RGFW_WINDOWS - #define OEMRESOURCE - #include - #ifndef GLAPIENTRY - #define GLAPIENTRY APIENTRY - #endif - #ifndef GLAPI - #define GLAPI WINGDIAPI - #endif - #endif - - #ifndef __APPLE__ - #include - #else - #include - #endif -#endif - -#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER) - #pragma comment(lib, "opengl32") -#endif - -#if defined(RGFW_OPENGL) && defined(RGFW_X11) - #ifndef GLX_MESA_swap_control - #define GLX_MESA_swap_control - #endif - #include /* GLX defs, xlib.h, gl.h */ -#endif - -#define RGFW_COCOA_FRAME_NAME NULL - -/*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions) - this is mostly used to allow you to force the use of XWayland -*/ -RGFWDEF void RGFW_useWayland(RGFW_bool wayland); -RGFWDEF RGFW_bool RGFW_usingWayland(void); -/* - regular RGFW stuff -*/ - -#define RGFW_key u8 - -typedef RGFW_ENUM(u8, RGFW_eventType) { - /*! event codes */ - RGFW_eventNone = 0, /*!< no event has been sent */ - RGFW_keyPressed, /* a key has been pressed */ - RGFW_keyReleased, /*!< a key has been released */ - /*! key event note - the code of the key pressed is stored in - RGFW_event.key - !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! - - while a string version is stored in - RGFW_event.KeyString - - RGFW_event.keyMod holds the current keyMod - this means if CapsLock, NumLock are active or not - */ - RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */ - RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */ - RGFW_mousePosChanged, /*!< the position of the mouse has been changed */ - /*! mouse event note - the x and y of the mouse can be found in the vector, RGFW_event.point - - RGFW_event.button holds which mouse button was pressed - */ - RGFW_gamepadConnected, /*!< a gamepad was connected */ - RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */ - RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */ - RGFW_gamepadButtonReleased, /*!< a gamepad button was released */ - RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */ - /*! gamepad event note - RGFW_event.gamepad holds which gamepad was altered, if any - RGFW_event.button holds which gamepad button was pressed - - RGFW_event.axis holds the data of all the axises - RGFW_event.axisesCount says how many axises there are - */ - RGFW_windowMoved, /*!< the window was moved (by the user) */ - RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */ - RGFW_focusIn, /*!< window is in focus now */ - RGFW_focusOut, /*!< window is out of focus now */ - RGFW_mouseEnter, /* mouse entered the window */ - RGFW_mouseLeave, /* mouse left the window */ - RGFW_windowRefresh, /* The window content needs to be refreshed */ - - /* attribs change event note - The event data is sent straight to the window structure - with win->r.x, win->r.y, win->r.w and win->r.h - */ - RGFW_quit, /*!< the user clicked the quit button */ - RGFW_DND, /*!< a file has been dropped into the window */ - RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */ - /* dnd data note - The x and y coords of the drop are stored in the vector RGFW_event.point - - RGFW_event.droppedFilesCount holds how many files were dropped - - This is also the size of the array which stores all the dropped file string, - RGFW_event.droppedFiles - */ - RGFW_windowMaximized, /*!< the window was maximized */ - RGFW_windowMinimized, /*!< the window was minimized */ - RGFW_windowRestored, /*!< the window was restored */ - RGFW_scaleUpdated /*!< content scale factor changed */ -}; - -/*! mouse button codes (RGFW_event.button) */ -typedef RGFW_ENUM(u8, RGFW_mouseButton) { - RGFW_mouseLeft = 0, /*!< left mouse button is pressed */ - RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */ - RGFW_mouseRight, /*!< right mouse button is pressed */ - RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */ - RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */ - RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, - RGFW_mouseFinal -}; - -#ifndef RGFW_MAX_PATH -#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */ -#endif -#ifndef RGFW_MAX_DROPS -#define RGFW_MAX_DROPS 260 /* max items you can drop at once */ -#endif - -#define RGFW_BIT(x) (1 << x) - -/* for RGFW_event.lockstate */ -typedef RGFW_ENUM(u8, RGFW_keymod) { - RGFW_modCapsLock = RGFW_BIT(0), - RGFW_modNumLock = RGFW_BIT(1), - RGFW_modControl = RGFW_BIT(2), - RGFW_modAlt = RGFW_BIT(3), - RGFW_modShift = RGFW_BIT(4), - RGFW_modSuper = RGFW_BIT(5), - RGFW_modScrollLock = RGFW_BIT(6) -}; - -/*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */ -typedef RGFW_ENUM(u8, RGFW_gamepadCodes) { - RGFW_gamepadNone = 0, /*!< or PS X button */ - RGFW_gamepadA, /*!< or PS X button */ - RGFW_gamepadB, /*!< or PS circle button */ - RGFW_gamepadY, /*!< or PS triangle button */ - RGFW_gamepadX, /*!< or PS square button */ - RGFW_gamepadStart, /*!< start button */ - RGFW_gamepadSelect, /*!< select button */ - RGFW_gamepadHome, /*!< home button */ - RGFW_gamepadUp, /*!< dpad up */ - RGFW_gamepadDown, /*!< dpad down */ - RGFW_gamepadLeft, /*!< dpad left */ - RGFW_gamepadRight, /*!< dpad right */ - RGFW_gamepadL1, /*!< left bump */ - RGFW_gamepadL2, /*!< left trigger */ - RGFW_gamepadR1, /*!< right bumper */ - RGFW_gamepadR2, /*!< right trigger */ - RGFW_gamepadL3, /* left thumb stick */ - RGFW_gamepadR3, /*!< right thumb stick */ - RGFW_gamepadFinal -}; - -/*! basic vector type, if there's not already a point/vector type of choice */ -#ifndef RGFW_point - typedef struct RGFW_point { i32 x, y; } RGFW_point; -#endif - -/*! basic rect type, if there's not already a rect type of choice */ -#ifndef RGFW_rect - typedef struct RGFW_rect { i32 x, y, w, h; } RGFW_rect; -#endif - -/*! basic area type, if there's not already a area type of choice */ -#ifndef RGFW_area - typedef struct RGFW_area { u32 w, h; } RGFW_area; -#endif - -#if defined(__cplusplus) && !defined(__APPLE__) -#define RGFW_POINT(x, y) {(i32)x, (i32)y} -#define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h} -#define RGFW_AREA(w, h) {(u32)w, (u32)h} -#else -#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)} -#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)} -#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)} -#endif - -#ifndef RGFW_NO_MONITOR - /* monitor mode data | can be changed by the user (with functions)*/ - typedef struct RGFW_monitorMode { - RGFW_area area; /*!< monitor workarea size */ - u32 refreshRate; /*!< monitor refresh rate */ - u8 red, blue, green; - } RGFW_monitorMode; - - /*! structure for monitor data */ - typedef struct RGFW_monitor { - i32 x, y; /*!< x - y of the monitor workarea */ - char name[128]; /*!< monitor name */ - float scaleX, scaleY; /*!< monitor content scale */ - float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */ - float physW, physH; /*!< monitor physical size in inches */ - - RGFW_monitorMode mode; - } RGFW_monitor; - - /*! get an array of all the monitors (max 6) */ - RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len); - /*! get the primary monitor */ - RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); - - typedef RGFW_ENUM(u8, RGFW_modeRequest) { - RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */ - RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */ - RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */ - RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB - }; - - /*! request a specific mode */ - RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); - /*! check if 2 monitor modes are the same */ - RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); -#endif - -/* RGFW mouse loading */ -typedef void RGFW_mouse; - -/*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */ -RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels); -/*!< frees RGFW_mouse data */ -RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse); - -/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */ -/*! Event structure for checking/getting events */ -typedef struct RGFW_event { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_point point; /*!< mouse x, y of event (or drop point) */ - RGFW_point vector; /*!< raw mouse movement */ - float scaleX, scaleY; /*!< DPI scaling */ - - RGFW_key key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */ - u8 keyChar; /*!< mapped key char of the event */ - - RGFW_bool repeat; /*!< key press event repeated (the key is being held) */ - RGFW_keymod keyMod; - - u8 button; /* !< which mouse (or gamepad) button was pressed */ - double scroll; /*!< the raw mouse scroll value */ - - u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */ - u8 axisesCount; /*!< number of axises */ - - u8 whichAxis; /* which axis was effected */ - RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */ - - /*! drag and drop data */ - /* 260 max paths with a max length of 260 */ - char** droppedFiles; /*!< dropped files */ - size_t droppedFilesCount; /*!< house many files were dropped */ - - void* _win; /*!< the window this event applies too (for event queue events) */ -} RGFW_event; - -/*! source data for the window (used by the APIs) */ -#ifdef RGFW_WINDOWS -typedef struct RGFW_window_src { - HWND window; /*!< source window */ - HDC hdc; /*!< source HDC */ - u32 hOffset; /*!< height offset for window */ - HICON hIconSmall, hIconBig; /*!< source window icons */ - #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) - HGLRC ctx; /*!< source graphics context */ - #elif defined(RGFW_OSMESA) - OSMesaContext ctx; - #elif defined(RGFW_EGL) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; - #endif - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - HDC hdcMem; - HBITMAP bitmap; - u8* bitmapBits; - #endif - RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */ -} RGFW_window_src; -#elif defined(RGFW_UNIX) -typedef struct RGFW_window_src { -#if defined(RGFW_X11) - Display* display; /*!< source display */ - Window window; /*!< source window */ - #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) - GLXContext ctx; /*!< source graphics context */ - GLXFBConfig bestFbc; - #elif defined(RGFW_OSMESA) - OSMesaContext ctx; - #elif defined(RGFW_EGL) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; - #endif - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - XImage* bitmap; - #endif - GC gc; - XVisualInfo visual; - #ifdef RGFW_ADVANCED_SMOOTH_RESIZE - i64 counter_value; - XID counter; - #endif - RGFW_rect r; -#endif /* RGFW_X11 */ -#if defined(RGFW_WAYLAND) - struct wl_display* wl_display; - struct wl_surface* surface; - struct wl_buffer* wl_buffer; - struct wl_keyboard* keyboard; - - struct wl_compositor* compositor; - struct xdg_surface* xdg_surface; - struct xdg_toplevel* xdg_toplevel; - struct zxdg_toplevel_decoration_v1* decoration; - struct xdg_wm_base* xdg_wm_base; - struct wl_shm* shm; - struct wl_seat *seat; - u8* buffer; - #if defined(RGFW_EGL) - struct wl_egl_window* eglWindow; - #endif - #if defined(RGFW_EGL) && !defined(RGFW_X11) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; - #elif defined(RGFW_OSMESA) && !defined(RGFW_X11) - OSMesaContext ctx; - #endif -#endif /* RGFW_WAYLAND */ -} RGFW_window_src; -#endif /* RGFW_UNIX */ -#if defined(RGFW_MACOS) -typedef struct RGFW_window_src { - void* window; -#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) - void* ctx; /*!< source graphics context */ -#elif defined(RGFW_OSMESA) - OSMesaContext ctx; -#elif defined(RGFW_EGL) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; -#endif - - void* view; /* apple viewpoint thingy */ - void* mouse; -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -#endif -} RGFW_window_src; -#elif defined(RGFW_WASM) -typedef struct RGFW_window_src { - #if defined(RGFW_WEBGPU) - WGPUInstance ctx; - WGPUDevice device; - WGPUQueue queue; - #elif defined(RGFW_OSMESA) - OSMesaContext ctx; - #else - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; - #endif -} RGFW_window_src; -#endif - -/*! Optional arguments for making a windows */ -typedef RGFW_ENUM(u32, RGFW_windowFlags) { - RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */ - RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */ - RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */ - RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */ - RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */ - RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */ - RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */ - RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */ - RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */ - RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */ - RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */ - RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */ - RGFW_windowMaximize = RGFW_BIT(12), - RGFW_windowCenterCursor = RGFW_BIT(13), - RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */ - RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */ - RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */ - RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */ - RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */ - RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize -}; - -typedef struct RGFW_window { - RGFW_window_src src; /*!< src window data */ - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */ - /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ - RGFW_area bufferSize; -#endif - void* userPtr; /* ptr for usr data */ - - RGFW_event event; /*!< current event */ - - RGFW_rect r; /*!< the x, y, w and h of the struct */ - - /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */ - RGFW_key exitKey; - RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */ - - u32 _flags; /*!< windows flags (for RGFW to check) */ - RGFW_rect _oldRect; /*!< rect before fullscreen */ -} RGFW_window; /*!< window structure for managing the window */ - -#if defined(RGFW_X11) || defined(RGFW_MACOS) - typedef u64 RGFW_thread; /*!< thread type unix */ -#else - typedef void* RGFW_thread; /*!< thread type for windows */ -#endif - -/*! scale monitor to window size */ -RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win); - -/** * @defgroup Window_management -* @{ */ - - -/*! - * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM - * by default the class name will == the root window's name -*/ -RGFWDEF void RGFW_setClassName(const char* name); -RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */ - -/*! (cocoa only) change directory to resource folder */ -RGFWDEF void RGFW_moveToMacOSResourceDir(void); - -/* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */ - -RGFWDEF RGFW_window* RGFW_createWindow( - const char* name, /* name of the window */ - RGFW_rect rect, /* rect of window */ - RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/ -); /*!< function to create a window and struct */ - -RGFWDEF RGFW_window* RGFW_createWindowPtr( - const char* name, /* name of the window */ - RGFW_rect rect, /* rect of window */ - RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */ - RGFW_window* win /* ptr to the window struct you want to use */ -); /*!< function to create a window (without allocating a window struct) */ - -RGFWDEF void RGFW_window_initBuffer(RGFW_window* win); -RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area); -RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area); - -/*! set the window flags (will undo flags if they don't match the old ones) */ -RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags); - -/*! get the size of the screen to an area struct */ -RGFWDEF RGFW_area RGFW_getScreenSize(void); - - -/*! - this function checks an *individual* event (and updates window structure attributes) - this means, using this function without a while loop may cause event lag - - ex. - - while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one] - - this function is optional if you choose to use event callbacks, - although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents` -*/ - -RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ - -/*! - for RGFW_window_eventWait and RGFW_window_checkEvents - waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL` - if waitMS == 0, the loop will not wait for events - if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns - if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event -*/ -typedef RGFW_ENUM(i32, RGFW_eventWait) { - RGFW_eventNoWait = 0, - RGFW_eventWaitNext = -1 -}; - -/*! sleep until RGFW gets an event or the timer ends (defined by OS) */ -RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS); - -/*! - check all the events until there are none left. - This should only be used if you're using callbacks only -*/ -RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS); - -/*! - tell RGFW_window_eventWait to stop waiting (to be ran from another thread) -*/ -RGFWDEF void RGFW_stopCheckEvents(void); - -/*! window managment functions */ -RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */ - -/*! move a window to a given point */ -RGFWDEF void RGFW_window_move(RGFW_window* win, - RGFW_point v /*!< new pos */ -); - -#ifndef RGFW_NO_MONITOR - /*! move window to a specific monitor */ - RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */); -#endif - -/*! resize window to a current size/area */ -RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */ - RGFW_area a /*!< new size */ -); - -/*! set window aspect ratio */ -RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a); -/*! set the minimum dimensions of a window */ -RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); -/*! set the maximum dimensions of a window */ -RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); - -RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */ -RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */ -RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */ -RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */ -RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */ -RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */ -RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/ -RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/ -RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */ -RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */ - -/*! if the window should have a border or not (borderless) based on bool value of `border` */ -RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border); -RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win); - -/*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/ -RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow); -/*! check if DND is allowed */ -RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win); - - -#ifndef RGFW_NO_PASSTHROUGH - /*! turn on / off mouse passthrough */ - RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough); -#endif - -/*! rename window to a given string */ -RGFWDEF void RGFW_window_setName(RGFW_window* win, - const char* name -); - -RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */ - u8* icon /*!< icon bitmap */, - RGFW_area a /*!< width and height of the bitmap */, - i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ -); /*!< image MAY be resized by default, set both the taskbar and window icon */ - -typedef RGFW_ENUM(u8, RGFW_icon) { - RGFW_iconTaskbar = RGFW_BIT(0), - RGFW_iconWindow = RGFW_BIT(1), - RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow -}; -RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type); - -/*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */ -RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse); - -/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */ -RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); - -RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ -/* - Locks cursor at the center of the window - win->event.point becomes raw mouse movement data - - this is useful for a 3D camera -*/ -RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area); -/*! if the mouse is held by RGFW */ -RGFWDEF RGFW_bool RGFW_window_mouseHeld(RGFW_window* win); -/*! stop holding the mouse and let it move freely */ -RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win); - -/*! hide the window */ -RGFWDEF void RGFW_window_hide(RGFW_window* win); -/*! show the window */ -RGFWDEF void RGFW_window_show(RGFW_window* win); - -/* - makes it so `RGFW_window_shouldClose` returns true or overrides a window close - by modifying window flags -*/ -RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose); - -/*! where the mouse is on the screen */ -RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void); - -/*! where the mouse is on the window */ -RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win); - -/*! show the mouse or hide the mouse */ -RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show); -/*! if the mouse is hidden */ -RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win); -/*! move the mouse to a given point */ -RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v); - -/*! if the window should close (RGFW_close was sent or escape was pressed) */ -RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); -/*! if the window is fullscreen */ -RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win); -/*! if the window is hidden */ -RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win); -/*! if the window is minimized */ -RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win); -/*! if the window is maximized */ -RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win); -/*! if the window is floating */ -RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win); -/** @} */ - -/** * @defgroup Monitor -* @{ */ - -#ifndef RGFW_NO_MONITOR -/* - scale the window to the monitor. - This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation -*/ -RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); -/*! get the struct of the window's monitor */ -RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); -#endif - -/** @} */ - -/** * @defgroup Input -* @{ */ - -/*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus. */ -RGFWDEF RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/ - -RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */ - -RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */ -RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */ - -/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */ -RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */); - -/*! if a mouse button is pressed */ -RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/*! if a mouse button is held */ -RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/*! if a mouse button was released */ -RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/*! if a mouse button was pressed (checks previous state only) */ -RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/** @} */ - -/** * @defgroup Clipboard -* @{ */ -typedef ptrdiff_t RGFW_ssize_t; - -RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */ -/*! read clipboard data or send a NULL str to just get the length of the clipboard data */ -RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity); -RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */ -/** @} */ - - - -/** * @defgroup error handling -* @{ */ -typedef RGFW_ENUM(u8, RGFW_debugType) { - RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo -}; - -typedef RGFW_ENUM(u8, RGFW_errorCode) { - RGFW_noError = 0, /*!< no error */ - RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */ - RGFW_errWayland, - RGFW_errDirectXContext, - RGFW_errIOKit, - RGFW_errClipboard, - RGFW_errFailedFuncLoad, - RGFW_errBuffer, - RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, - RGFW_warningWayland, RGFW_warningOpenGL -}; - -typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor* monitor; u32 srcError; } RGFW_debugContext; - -#if defined(__cplusplus) && !defined(__APPLE__) -#define RGFW_DEBUG_CTX(win, err) {win, NULL, err} -#define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, &monitor, 0} -#else -#define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, NULL, err} -#define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, &monitor, 0} -#endif - -typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg); -RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func); -RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg); -/** @} */ - -/** - - - event callbacks. - These are completely optional, so you can use the normal - RGFW_checkEvent() method if you prefer that - -* @defgroup Callbacks -* @{ -*/ - -/*! RGFW_windowMoved, the window and its new rect value */ -typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowResized, the window and its new rect value */ -typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowRestored, the window and its new rect value */ -typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowMaximized, the window and its new rect value */ -typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowMinimized, the window and its new rect value */ -typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_quit, the window that was closed */ -typedef void (* RGFW_windowQuitfunc)(RGFW_window* win); -/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */ -typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus); -/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ -typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status); -/*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */ -typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector); -/*! RGFW_DNDInit, the window, the point of the drop on the windows */ -typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point); -/*! RGFW_windowRefresh, the window that needs to be refreshed */ -typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win); -/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */ -typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed); -/*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ -typedef void (* RGFW_mouseButtonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed); -/*! RGFW_gamepadButtonPressed, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ -typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed); -/*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */ -typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis); -/*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */ -typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected); -/*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */ -typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount); -/*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */ -typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY); - -/*! set callback for a window move event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func); -/*! set callback for a window resize event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func); -/*! set callback for a window quit event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func); -/*! set callback for a mouse move event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func); -/*! set callback for a window refresh event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func); -/*! set callback for a window focus change event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); -/*! set callback for a mouse notify event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func); -/*! set callback for a drop event event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func); -/*! set callback for a start of a drop event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func); -/*! set callback for a key (press / release) event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); -/*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func); -/*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func); -/*! set callback for a gamepad axis move event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func); -/*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func); -/*! set call back for when window is maximized. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func); -/*! set call back for when window is minimized. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func); -/*! set call back for when window is restored. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func); -/*! set callback for when the DPI changes. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func); -/** @} */ - -/** * @defgroup Threads -* @{ */ - -#ifndef RGFW_NO_THREADS -/*! threading functions */ - -/*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */ -/* - I'd suggest you use sili's threading functions instead - if you're going to use sili - which is a good idea generally -*/ - -#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND) - typedef void* (* RGFW_threadFunc_ptr)(void*); -#else - typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); -#endif - -RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */ -RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */ -RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */ -RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */ -#endif - -/** @} */ - -/** * @defgroup gamepad -* @{ */ - -typedef RGFW_ENUM(u8, RGFW_gamepadType) { - RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown -}; - -/*! gamepad count starts at 0*/ -RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis); -RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller); -RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win); -RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller); - -/** @} */ - -/** * @defgroup graphics_API -* @{ */ - -/*!< make the window the current opengl drawing context - - NOTE: - if you want to switch the graphics context's thread, - you have to run RGFW_window_makeCurrent(NULL); on the old thread - then RGFW_window_makeCurrent(valid_window) on the new thread -*/ -RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win); - -/*! get current RGFW window graphics context */ -RGFWDEF RGFW_window* RGFW_getCurrent(void); - -/* supports openGL, directX, OSMesa, EGL and software rendering */ -RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */ -RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); -/*!< render the software rendering buffer (this is called by RGFW_window_swapInterval) */ -RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win); - -typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */ - -/*! native API functions */ -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) -/*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */ -RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software); -/*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */ -RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win); - -/*! OpenGL init hints */ -typedef RGFW_ENUM(u8, RGFW_glHints) { - RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */ - RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */ - RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */ - RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */ - RGFW_glDoubleBuffer, /*!< request double buffering */ - RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */ - RGFW_glDepth, - RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */ - RGFW_glSRGB, /*!< request sRGA */ - RGFW_glRobustness, /*!< request a robust context */ - RGFW_glDebug, /*!< request opengl debugging */ - RGFW_glNoError, /*!< request no opengl errors */ - RGFW_glReleaseBehavior, - RGFW_glProfile, - RGFW_glMajor, RGFW_glMinor, - RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */ - RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */ - RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */ -}; -RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value); -RGFWDEF RGFW_bool RGFW_extensionSupported(const char* extension, size_t len); /*!< check if whether the specified API extension is supported by the current OpenGL or OpenGL ES context */ -RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */ -RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */ -RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval */ -void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/ - -RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len); /*!< check if whether the specified platform-specific API extension is supported by the current OpenGL or OpenGL ES context */ -#endif -#ifdef RGFW_VULKAN - #if defined(RGFW_WAYLAND) && defined(RGFW_X11) - #define VK_USE_PLATFORM_WAYLAND_KHR - #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface")) - #elif defined(RGFW_WAYLAND) - #define VK_USE_PLATFORM_WAYLAND_KHR - #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" - #elif defined(RGFW_X11) - #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE "VK_KHR_xlib_surface" - #elif defined(RGFW_WINDOWS) - #define VK_USE_PLATFORM_WIN32_KHR - #define OEMRESOURCE - #define RGFW_VK_SURFACE "VK_KHR_win32_surface" - #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) - #define VK_USE_PLATFORM_MACOS_MVK - #define RGFW_VK_SURFACE "VK_MVK_macos_surface" - #else - #define RGFW_VK_SURFACE NULL - #endif - -/* if you don't want to use the above macros */ -RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */ - -#include - -RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface); -RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); -#endif -#ifdef RGFW_DIRECTX -#ifndef RGFW_WINDOWS - #undef RGFW_DIRECTX -#else - #define OEMRESOURCE - #include - - #ifndef __cplusplus - #define __uuidof(T) IID_##T - #endif -RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain); -#endif -#endif - -/** @} */ - -/** * @defgroup Supporting -* @{ */ - -/*! optional init/deinit function */ -RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */ -RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */ - -RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open */ -RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */ -RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ -RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */ -RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */ -RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */ - -/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */ -RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap); - -/*!< change which window is the root window */ -RGFWDEF void RGFW_setRootWindow(RGFW_window* win); -RGFWDEF RGFW_window* RGFW_getRootWindow(void); - -/*! standard event queue, used for injecting events and returning source API callback events like any other queue check */ -/* these are all used internally by RGFW */ -void RGFW_eventQueuePush(RGFW_event event); -RGFW_event* RGFW_eventQueuePop(RGFW_window* win); - -/* for C++ / C89 */ -#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(e); } - -/*! - key codes and mouse icon enums -*/ -#undef RGFW_key -typedef RGFW_ENUM(u8, RGFW_key) { - RGFW_keyNULL = 0, - RGFW_escape = '\033', - RGFW_backtick = '`', - RGFW_0 = '0', - RGFW_1 = '1', - RGFW_2 = '2', - RGFW_3 = '3', - RGFW_4 = '4', - RGFW_5 = '5', - RGFW_6 = '6', - RGFW_7 = '7', - RGFW_8 = '8', - RGFW_9 = '9', - - RGFW_minus = '-', - RGFW_equals = '=', - RGFW_backSpace = '\b', - RGFW_tab = '\t', - RGFW_space = ' ', - - RGFW_a = 'a', - RGFW_b = 'b', - RGFW_c = 'c', - RGFW_d = 'd', - RGFW_e = 'e', - RGFW_f = 'f', - RGFW_g = 'g', - RGFW_h = 'h', - RGFW_i = 'i', - RGFW_j = 'j', - RGFW_k = 'k', - RGFW_l = 'l', - RGFW_m = 'm', - RGFW_n = 'n', - RGFW_o = 'o', - RGFW_p = 'p', - RGFW_q = 'q', - RGFW_r = 'r', - RGFW_s = 's', - RGFW_t = 't', - RGFW_u = 'u', - RGFW_v = 'v', - RGFW_w = 'w', - RGFW_x = 'x', - RGFW_y = 'y', - RGFW_z = 'z', - - RGFW_period = '.', - RGFW_comma = ',', - RGFW_slash = '/', - RGFW_bracket = '{', - RGFW_closeBracket = '}', - RGFW_semicolon = ';', - RGFW_apostrophe = '\'', - RGFW_backSlash = '\\', - RGFW_return = '\n', - - RGFW_delete = '\177', /* 127 */ - - RGFW_F1, - RGFW_F2, - RGFW_F3, - RGFW_F4, - RGFW_F5, - RGFW_F6, - RGFW_F7, - RGFW_F8, - RGFW_F9, - RGFW_F10, - RGFW_F11, - RGFW_F12, - - RGFW_capsLock, - RGFW_shiftL, - RGFW_controlL, - RGFW_altL, - RGFW_superL, - RGFW_shiftR, - RGFW_controlR, - RGFW_altR, - RGFW_superR, - RGFW_up, - RGFW_down, - RGFW_left, - RGFW_right, - RGFW_insert, - RGFW_end, - RGFW_home, - RGFW_pageUp, - RGFW_pageDown, - - RGFW_numLock, - RGFW_KP_Slash, - RGFW_multiply, - RGFW_KP_Minus, - RGFW_KP_1, - RGFW_KP_2, - RGFW_KP_3, - RGFW_KP_4, - RGFW_KP_5, - RGFW_KP_6, - RGFW_KP_7, - RGFW_KP_8, - RGFW_KP_9, - RGFW_KP_0, - RGFW_KP_Period, - RGFW_KP_Return, - RGFW_scrollLock, - RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */ - }; - -RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); - -typedef RGFW_ENUM(u8, RGFW_mouseIcons) { - RGFW_mouseNormal = 0, - RGFW_mouseArrow, - RGFW_mouseIbeam, - RGFW_mouseCrosshair, - RGFW_mousePointingHand, - RGFW_mouseResizeEW, - RGFW_mouseResizeNS, - RGFW_mouseResizeNWSE, - RGFW_mouseResizeNESW, - RGFW_mouseResizeAll, - RGFW_mouseNotAllowed, - RGFW_mouseIconFinal = 16 /* padding for alignment */ -}; -/** @} */ - -#endif /* RGFW_HEADER */ -#if defined(RGFW_X11) || defined(RGFW_WAYLAND) - #define RGFW_OS_BASED_VALUE(l, w, m, h) l -#elif defined(RGFW_WINDOWS) - #define RGFW_OS_BASED_VALUE(l, w, m, h) w -#elif defined(RGFW_MACOS) - #define RGFW_OS_BASED_VALUE(l, w, m, h) m -#elif defined(RGFW_WASM) - #define RGFW_OS_BASED_VALUE(l, w, m, h) h -#endif - - -#ifdef RGFW_IMPLEMENTATION -RGFW_bool RGFW_useWaylandBool = 1; -void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; } -RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; } - -#if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND) -#define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland -#else -#define RGFW_GOTO_WAYLAND(fallback) -#endif - -char* RGFW_clipboard_data; -void RGFW_clipboard_switch(char* newstr); -void RGFW_clipboard_switch(char* newstr) { - if (RGFW_clipboard_data != NULL) - RGFW_FREE(RGFW_clipboard_data); - RGFW_clipboard_data = newstr; -} - -#define RGFW_CHECK_CLIPBOARD() \ - if (size <= 0 && RGFW_clipboard_data != NULL) \ - return (const char*)RGFW_clipboard_data; \ - else if (size <= 0) \ - return "\0"; - -const char* RGFW_readClipboard(size_t* len) { - RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0); - RGFW_CHECK_CLIPBOARD(); - char* str = (char*)RGFW_ALLOC((size_t)size); - RGFW_ASSERT(str != NULL); - str[0] = '\0'; - - size = RGFW_readClipboardPtr(str, (size_t)size); - - RGFW_CHECK_CLIPBOARD(); - - if (len != NULL) *len = (size_t)size; - - RGFW_clipboard_switch(str); - return (const char*)str; -} - -RGFW_debugfunc RGFW_debugCallback = NULL; -RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) { - RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback; - RGFW_debugCallback = func; - return RGFW_debugCallbackPrev; -} - -#ifdef RGFW_DEBUG -#include -#endif - -void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) { - if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg); - #ifdef RGFW_DEBUG - switch (type) { - case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break; - case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break; - case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break; - default: break; - } - - switch (err) { - #ifdef RGFW_BUFFER - case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break; - #endif - case RGFW_infoMonitor: printf(": scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", ctx.monitor->name, ctx.monitor->x, ctx.monitor->y, ctx.monitor->mode.area.w, ctx.monitor->mode.area.h, ctx.monitor->physW, ctx.monitor->physH, ctx.monitor->scaleX, ctx.monitor->scaleY, ctx.monitor->pixelRatio, ctx.monitor->mode.refreshRate, ctx.monitor->mode.red + ctx.monitor->mode.green + ctx.monitor->mode.blue); break; - case RGFW_infoWindow: printf(" with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break; - case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break; - default: printf("\n"); - } - #endif -} - -u64 RGFW_timerOffset = 0; -void RGFW_setTime(double time) { - RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq()); -} - -double RGFW_getTime(void) { - return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq()); -} - -u64 RGFW_getTimeNS(void) { - return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq()); -} - -/* -RGFW_IMPLEMENTATION starts with generic RGFW defines - -This is the start of keycode data - - Why not use macros instead of the numbers itself? - Windows -> Not all scancodes keys are macros - Linux -> Only symcodes are values, (XK_0 - XK_1, XK_a - XK_z) are larger than 0xFF00, I can't find any way to work with them without making the array an unreasonable size - MacOS -> windows and linux already don't have keycodes as macros, so there's no point -*/ - - - -/* - the c++ compiler doesn't support setting up an array like, - we'll have to do it during runtime using a function & this messy setup -*/ - -#ifndef RGFW_CUSTOM_BACKEND - -#if !defined(__cplusplus) && !defined(RGFW_C89) -#define RGFW_NEXT , -#define RGFW_MAP -#else -#define RGFW_NEXT ; -#define RGFW_MAP RGFW_keycodes -#endif - -u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = { -#if defined(__cplusplus) || defined(RGFW_C89) - 0 -}; -void RGFW_init_keys(void); -void RGFW_init_keys(void) { -#endif - RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick RGFW_NEXT - - RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9, - RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space, - RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z, - RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash, - RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return, - RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL, - #if !defined(RGFW_MACOS) && !defined(RGFW_WASM) - RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(134, 0x15C, 55, 0)] = RGFW_superR, - RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR, - #endif - RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 112, DOM_VK_F12)] = RGFW_F12 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT -#if defined(__cplusplus) || defined(RGFW_C89) -} -#else -}; -#endif - -#undef RGFW_NEXT -#undef RGFW_MAP - -u32 RGFW_apiKeyToRGFW(u32 keycode) { - #if defined(__cplusplus) || defined(RGFW_C89) - if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) { - RGFW_init_keys(); - } - #endif - - /* make sure the key isn't out of bounds */ - if (keycode > sizeof(RGFW_keycodes) / sizeof(u8)) - return 0; - - return RGFW_keycodes[keycode]; -} -#endif /* RGFW_CUSTOM_BACKEND */ - -typedef struct { - RGFW_bool current : 1; - RGFW_bool prev : 1; -} RGFW_keyState; - -RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} }; - -RGFWDEF void RGFW_resetKeyPrev(void); -void RGFW_resetKeyPrev(void) { - size_t i; /*!< reset each previous state */ - for (i = 0; i < RGFW_keyLast; i++) RGFW_keyboard[i].prev = 0; -} -RGFWDEF void RGFW_resetKey(void); -void RGFW_resetKey(void) { RGFW_MEMSET(RGFW_keyboard, 0, sizeof(RGFW_keyboard)); } -/* - this is the end of keycode data -*/ - -/* gamepad data */ -RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */ -RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */ - -RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */ -i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */ -char RGFW_gamepads_name[4][128]; /*!< gamepad names */ -u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */ - -/* - event callback defines start here -*/ - - -/* - These exist to avoid the - if (func == NULL) check - for (allegedly) better performance - - RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning -*/ -static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); } -static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} -static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} -static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);} -static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} -static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } -static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);} -static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} -static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } -static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); } -static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);} -static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} -static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); } - -#define RGFW_CALLBACK_DEFINE(x, x2) \ -RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \ -RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \ - RGFW_##x##func prev = RGFW_##x##Callback; \ - RGFW_##x##Callback = func; \ - return prev; \ -} -RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized) -RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized) -RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored) -RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved) -RGFW_CALLBACK_DEFINE(windowResized, WindowResized) -RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit) -RGFW_CALLBACK_DEFINE(mousePos, MousePos) -RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh) -RGFW_CALLBACK_DEFINE(focus, Focus) -RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify) -RGFW_CALLBACK_DEFINE(dnd, Dnd) -RGFW_CALLBACK_DEFINE(dndInit, DndInit) -RGFW_CALLBACK_DEFINE(key, Key) -RGFW_CALLBACK_DEFINE(mouseButton, MouseButton) -RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton) -RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis) -RGFW_CALLBACK_DEFINE(gamepad, Gamepad) -RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated) -#undef RGFW_CALLBACK_DEFINE - -void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) { - RGFW_window_eventWait(win, waitMS); - - while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { - if (win->event.type == RGFW_quit) return; - } - - #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */ - RGFW_sleep(0); - #endif -} - -void RGFW_window_checkMode(RGFW_window* win); -void RGFW_window_checkMode(RGFW_window* win) { - if (RGFW_window_isMinimized(win)) { - win->_flags |= RGFW_windowMinimize; - RGFW_windowMinimizedCallback(win, win->r); - } else if (RGFW_window_isMaximized(win)) { - win->_flags |= RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win); - RGFW_windowMaximizedCallback(win, win->r); - } else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) || - (win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) { - win->_flags &= ~(u32)RGFW_windowMinimize; - if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); - RGFW_windowRestoredCallback(win, win->r); - } -} - -/* -no more event call back defines -*/ - -#define SET_ATTRIB(a, v) { \ - RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ - attribs[index++] = a; \ - attribs[index++] = v; \ -} - -#define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed */ -#define RGFW_EVENT_QUIT RGFW_BIT(25) /* the window close button was pressed */ -#define RGFW_HOLD_MOUSE RGFW_BIT(26) /*!< hold the moues still */ -#define RGFW_MOUSE_LEFT RGFW_BIT(27) /* if mouse left the window */ -#define RGFW_WINDOW_ALLOC RGFW_BIT(28) /* if window was allocated by RGFW */ -#define RGFW_BUFFER_ALLOC RGFW_BIT(29) /* if window.buffer was allocated by RGFW */ -#define RGFW_WINDOW_INIT RGFW_BIT(30) /* if window.buffer was allocated by RGFW */ -#define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE | RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus) - -RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) { - RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window)); - RGFW_ASSERT(win != NULL); - win->_flags = RGFW_WINDOW_ALLOC; - return RGFW_createWindowPtr(name, rect, flags, win); -} - -#if defined(RGFW_USE_XDL) && defined(RGFW_X11) - #define XDL_IMPLEMENTATION - #include "XDL.h" -#endif - -#define RGFW_MAX_EVENTS 32 -typedef struct RGFW_globalStruct { - RGFW_window* root; - RGFW_window* current; - i32 windowCount; - i32 eventLen; - i32 eventIndex; - - #ifdef RGFW_X11 - Display* display; - Window helperWindow; - char* clipboard; /* for writing to the clipboard selection */ - size_t clipboard_len; - #endif - #ifdef RGFW_WAYLAND - struct wl_display* wl_display; - #endif - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_mouse* hiddenMouse; - #endif - RGFW_event events[RGFW_MAX_EVENTS]; - -} RGFW_globalStruct; -#if !defined(RGFW_C89) && !defined(__cplusplus) -RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0}; -#define _RGFW_init RGFW_TRUE -#else -RGFW_bool _RGFW_init = RGFW_FALSE; -RGFW_globalStruct _RGFW; -#endif - -void RGFW_eventQueuePush(RGFW_event event) { - if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return; - _RGFW.events[_RGFW.eventLen] = event; - _RGFW.eventLen++; -} - -RGFW_event* RGFW_eventQueuePop(RGFW_window* win) { - RGFW_event* ev; - if (_RGFW.eventLen == 0) return NULL; - - ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex]; - - _RGFW.eventLen--; - if (_RGFW.eventLen && _RGFW.eventIndex < (_RGFW.eventLen - 1)) - _RGFW.eventIndex++; - else if (_RGFW.eventLen == 0) - _RGFW.eventIndex = 0; - - if (ev->_win != win && ev->_win != NULL) { - RGFW_eventQueuePush(*ev); - return NULL; - } - - ev->droppedFilesCount = win->event.droppedFilesCount; - ev->droppedFiles = win->event.droppedFiles; - return ev; -} - -RGFW_event* RGFW_window_checkEventCore(RGFW_window* win); -RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) { - RGFW_event* ev; - RGFW_ASSERT(win != NULL); - if (win->event.type == 0 && _RGFW.eventLen == 0) - RGFW_resetKeyPrev(); - - if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) { - static RGFW_event event; - event = win->event; - RGFW_window_close(win); - return &event; - } - - if (win->event.type != RGFW_DNDInit) win->event.type = 0; - - /* check queued events */ - ev = RGFW_eventQueuePop(win); - if (ev != NULL) { - if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE); - win->event = *ev; - } - else return NULL; - - return &win->event; -} - - -RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags); -void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; } -RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; } - -/* do a basic initialization for RGFW_window, this is to standard it for each OS */ -void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) { - RGFW_UNUSED(flags); - if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init(); - _RGFW.windowCount++; - - /* rect based the requested flags */ - if (_RGFW.root == NULL) { - RGFW_setRootWindow(win); - RGFW_setTime(0); - } - - if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0; - - /* set and init the new window's data */ - win->r = rect; - win->exitKey = RGFW_escape; - win->event.droppedFilesCount = 0; - - win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC); - win->_flags |= flags; - win->event.keyMod = 0; - win->_lastMousePoint.x = 0; - win->_lastMousePoint.y = 0; - - win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS); - RGFW_ASSERT(win->event.droppedFiles != NULL); - - { - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH)); - } -} - -void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { - RGFW_windowFlags cmpFlags = win->_flags; - if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0; - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); - #endif - - if (flags & RGFW_windowCenter) RGFW_window_center(win); - if (flags & RGFW_windowCenterCursor) - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); - if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0); - else RGFW_window_setBorder(win, 1); - if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE); - else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0); - if (flags & RGFW_windowMaximize) RGFW_window_maximize(win); - else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win); - if (flags & RGFW_windowMinimize) RGFW_window_minimize(win); - else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win); - if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0); - else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1); - if (flags & RGFW_windowHide) RGFW_window_hide(win); - else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win); - if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir(); - if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1); - else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0); - if (flags & RGFW_windowFocus) RGFW_window_focus(win); - - if (flags & RGFW_windowNoResize) { - RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h)); - RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h)); - } else if (cmpFlags & RGFW_windowNoResize) { - RGFW_window_setMaxSize(win, RGFW_AREA(0, 0)); - RGFW_window_setMinSize(win, RGFW_AREA(0, 0)); - } - - win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS); -} - -RGFW_bool RGFW_window_isInFocus(RGFW_window* win) { -#ifdef RGFW_WASM - return RGFW_TRUE; -#else - return RGFW_BOOL(win->_flags & RGFW_windowFocus); -#endif -} - -void RGFW_window_initBuffer(RGFW_window* win) { - RGFW_area area = RGFW_getScreenSize(); - if ((win->_flags & RGFW_windowNoResize)) - area = RGFW_AREA(win->r.w, win->r.h); - - RGFW_window_initBufferSize(win, area); -} - -void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) { -#if defined(RGFW_BUFFER) || defined(RGFW_OSMESA) - win->_flags |= RGFW_BUFFER_ALLOC; - #ifndef RGFW_WINDOWS - u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4); - RGFW_ASSERT(buffer != NULL); - - RGFW_window_initBufferPtr(win, buffer, area); - #else /* windows's bitmap allocs memory for us */ - RGFW_window_initBufferPtr(win, (u8*)NULL, area); - #endif -#else - RGFW_UNUSED(win); RGFW_UNUSED(area); -#endif -} - -#ifdef RGFW_MACOS -RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer); -RGFWDEF void* RGFW_cocoaGetLayer(void); -#endif - -const char* RGFW_className = NULL; -void RGFW_setClassName(const char* name) { RGFW_className = name; } - -#ifndef RGFW_X11 -void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); } -#endif - -RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - -RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { - return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win)); -} -RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) { - return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win)); -} -RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) { - return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); -} -RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { - return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); -} - -RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - return win->_lastMousePoint; -} - -RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) { - return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win)); -} - -RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) { - return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win)); -} - -RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) { - return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); -} - -RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) { - return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key)); -} - -RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) { - return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); -} - -void RGFW_window_makeCurrent(RGFW_window* win) { - _RGFW.current = win; -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) - RGFW_window_makeCurrent_OpenGL(win); -#endif -} - -RGFW_window* RGFW_getCurrent(void) { - return _RGFW.current; -} - -void RGFW_window_swapBuffers(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_window_swapBuffers_software(win); -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) - RGFW_window_swapBuffers_OpenGL(win); -#endif -} - -RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value); -void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) { - if (value) - *data |= bit; - else if (!value && (*(data) & bit)) - *data ^= bit; -} - -void RGFW_window_center(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_area screenR = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2)); -} - -RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) { - RGFW_monitorMode mode; - RGFW_ASSERT(win != NULL); - - mode.area.w = (u32)win->r.w; - mode.area.h = (u32)win->r.h; - return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale); -} - -void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode); -void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) { - if (bpp == 32) bpp = 24; - mode->red = mode->green = mode->blue = (u8)(bpp / 3); - - u32 delta = bpp - (mode->red * 3); /* handle leftovers */ - if (delta >= 1) mode->green = mode->green + 1; - if (delta == 2) mode->red = mode->red + 1; -} - -RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) { - return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) && - ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) && - ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB))); -} - -RGFW_bool RGFW_window_shouldClose(RGFW_window* win) { - return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| (win->exitKey && RGFW_isPressed(win, win->exitKey))); -} - -void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) { - if (shouldClose) { - win->_flags |= RGFW_EVENT_QUIT; - RGFW_windowQuitCallback(win); - } else { - win->_flags &= ~(u32)RGFW_EVENT_QUIT; - } -} - -#ifndef RGFW_NO_MONITOR -void RGFW_window_scaleToMonitor(RGFW_window* win) { - RGFW_monitor monitor = RGFW_window_getMonitor(win); - if (monitor.scaleX == 0 && monitor.scaleY == 0) - return; - - RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h))); -} - -void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { - RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y)); -} -#endif - -RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { - return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth); -} - -RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect); -RGFWDEF void RGFW_releaseCursor(RGFW_window* win); - - -RGFW_bool RGFW_window_mouseHeld(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_HOLD_MOUSE); } - -void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { - if (!area.w && !area.h) - area = RGFW_AREA(win->r.w / 2, win->r.h / 2); - - win->_flags |= RGFW_HOLD_MOUSE; - RGFW_captureCursor(win, win->r); - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); -} - -void RGFW_window_mouseUnhold(RGFW_window* win) { - win->_flags &= ~(u32)RGFW_HOLD_MOUSE; - RGFW_releaseCursor(win); -} - -u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) { - double deltaTime = RGFW_getTime() - startTime; - if (deltaTime == 0) return 0; - - double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */ - if (fpsCap && fps > fpsCap) { - double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */ - double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */ - - if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000)); - } - - return (u32) fps; -} - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) { - #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA) - u32 x, y; - for (y = 0; y < (u32)win->r.h; y++) { - for (x = 0; x < (u32)win->r.w; x++) { - u32 index = (y * 4 * win->bufferSize.w) + x * 4; - - u8 red = data[index]; - data[index] = win->buffer[index + 2]; - data[index + 2] = red; - } - } - #elif defined(RGFW_OSMESA) - u32 y; - for(y = 0; y < (u32)win->r.h; y++){ - u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w; - u32 index_to = y * 4 * win->bufferSize.w; - memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w); - } - #else - RGFW_UNUSED(win); RGFW_UNUSED(data); - #endif -} -#endif - -u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return RGFW_gamepadPressed[c][button].current; -} -u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return RGFW_gamepadPressed[c][button].prev; -} -u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button); -} -u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button); -} - -RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) { - RGFW_UNUSED(win); - return RGFW_gamepadAxes[controller][whichAxis]; -} -const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) { - RGFW_UNUSED(win); - return (const char*)RGFW_gamepads_name[controller]; -} - -size_t RGFW_getGamepadCount(RGFW_window* win) { - RGFW_UNUSED(win); - return RGFW_gamepadCount; -} - -RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) { - RGFW_UNUSED(win); - return RGFW_gamepads_type[controller]; -} - -RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); -void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) { - if (value) win->event.keyMod |= mod; - else win->event.keyMod &= ~mod; -} - -RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); -void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { - RGFW_updateKeyMod(win, RGFW_modCapsLock, capital); - RGFW_updateKeyMod(win, RGFW_modNumLock, numlock); - RGFW_updateKeyMod(win, RGFW_modControl, control); - RGFW_updateKeyMod(win, RGFW_modAlt, alt); - RGFW_updateKeyMod(win, RGFW_modShift, shift); - RGFW_updateKeyMod(win, RGFW_modSuper, super); - RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll); -} - -RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); -void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) { - RGFW_updateKeyModsPro(win, capital, numlock, - RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR), - RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR), - RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR), - RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR), - scroll); -} - -RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show); -void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) { - if (show && (win->_flags & RGFW_windowHideMouse)) - win->_flags ^= RGFW_windowHideMouse; - else if (!show && !(win->_flags & RGFW_windowHideMouse)) - win->_flags |= RGFW_windowHideMouse; -} - -RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) { - return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse); -} - -RGFW_bool RGFW_window_borderless(RGFW_window* win) { - return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder); -} - -RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); } -RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); } - -#ifndef RGFW_WINDOWS -void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { - RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); -} -#endif - -#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) -#ifndef __USE_POSIX199309 - #define __USE_POSIX199309 -#endif -#include -struct timespec; -#endif - -#if defined(RGFW_X11) || defined(RGFW_WINDOWS) -void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { - RGFW_window_showMouseFlags(win, show); - if (show == 0) - RGFW_window_setMouse(win, _RGFW.hiddenMouse); - else - RGFW_window_setMouseDefault(win); -} -#endif - -#ifndef RGFW_MACOS -void RGFW_moveToMacOSResourceDir(void) { } -#endif - -/* - graphics API specific code (end of generic code) - starts here -*/ - - -/* - OpenGL defines start here (Normal, EGL, OSMesa) -*/ - -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) - -#ifdef RGFW_WINDOWS - #define WIN32_LEAN_AND_MEAN - #define OEMRESOURCE - #include -#endif - -#if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER) - #include -#elif defined(__APPLE__) - #ifndef GL_SILENCE_DEPRECATION - #define GL_SILENCE_DEPRECATION - #endif - #include - #include -#endif - -/* EGL, normal OpenGL only */ -#ifndef RGFW_EGL -i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8, -#else -i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0, -#endif - 0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0}; - -void RGFW_setGLHint(RGFW_glHints hint, i32 value) { - if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value; -} - -RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) { - const char *start = extensions; - const char *where; - const char* terminator; - - if (extensions == NULL || ext == NULL) - return RGFW_FALSE; - - where = strstr(extensions, ext); - while (where) { - terminator = where + len; - if ((where == start || *(where - 1) == ' ') && - (*terminator == ' ' || *terminator == '\0')) { - return RGFW_TRUE; - } - where = RGFW_STRSTR(terminator, ext); - } - - return RGFW_FALSE; -} - -RGFW_bool RGFW_extensionSupported(const char* extension, size_t len) { - #ifdef GL_NUM_EXTENSIONS - if (RGFW_GL_HINTS[RGFW_glMajor] >= 3) { - i32 i; - GLint count = 0; - - RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress("glGetStringi"); - RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress("RGFW_glGetIntegerv"); - if (RGFW_glGetIntegerv) - ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count); - - for (i = 0; RGFW_glGetStringi && i < count; i++) { - const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i); - if (en && RGFW_STRNCMP(en, extension, len) == 0) - return RGFW_TRUE; - } - } else -#endif - { - RGFW_proc RGFW_glGetString = RGFW_getProcAddress("glGetString"); - - if (RGFW_glGetString) { - const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(GL_EXTENSIONS); - if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) - return RGFW_TRUE; - } - } - - return RGFW_extensionSupportedPlatform(extension, len); -} - -/* OPENGL normal only (no EGL / OSMesa) */ -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM) - -#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0) - #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0) - #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0) - #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0) - #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0) - #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0) - #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0) - #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0) - -#if defined(RGFW_X11) || defined(RGFW_WINDOWS) - #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0) - #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0) - #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0) - #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0) - #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0) - #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0) - #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0) - #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0) - #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0) - #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0) - #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0) - #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0) - #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0) - #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) - #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0) - #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0) - #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0) - #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) - #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) - #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0) -#endif - -#ifdef RGFW_WINDOWS - #define WGL_SUPPORT_OPENGL_ARB 0x2010 - #define WGL_COLOR_BITS_ARB 0x2014 - #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 - #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 - #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 - #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 - #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 - #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 - #define WGL_SAMPLE_BUFFERS_ARB 0x2041 - #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 - #define WGL_PIXEL_TYPE_ARB 0x2013 - #define WGL_TYPE_RGBA_ARB 0x202B - - #define WGL_TRANSPARENT_ARB 0x200A -#endif - -/* The window'ing api needs to know how to render the data we (or opengl) give it - MacOS and Windows do this using a structure called a "pixel format" - X11 calls it a "Visual" - This function returns the attributes for the format we want */ -i32* RGFW_initFormatAttribs(u32 useSoftware); -i32* RGFW_initFormatAttribs(u32 useSoftware) { - RGFW_UNUSED(useSoftware); - static i32 attribs[] = { - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_RENDER_TYPE, - RGFW_GL_FULL_FORMAT, - RGFW_GL_DRAW, 1, - RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA, - #endif - - #ifdef RGFW_X11 - GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, - #endif - - #ifdef RGFW_MACOS - 72, - 8, 24, - #endif - - #ifdef RGFW_WINDOWS - WGL_SUPPORT_OPENGL_ARB, 1, - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, - WGL_COLOR_BITS_ARB, 32, - #endif - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27; - - #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ - if (attVal) { \ - attribs[index] = attrib;\ - attribs[index + 1] = attVal;\ - index += 2;\ - } - - #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING) - RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching); - #endif - - RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1); - - RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]); - - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); - #endif - - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]); - - if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { - RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE); - } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) { - RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE); - } - - i32 flags = 0; - if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT; - if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT; - RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags); - #else - i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4; - RGFW_GL_ADD_ATTRIB(14, accumSize); - #endif - - #ifndef RGFW_X11 - RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); - #endif - - #ifdef RGFW_MACOS - if (useSoftware) { - RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID); - } else { - attribs[index] = RGFW_GL_RENDER_TYPE; - index += 1; - } - #endif - - #ifdef RGFW_MACOS - /* macOS has the surface attribs and the opengl attribs connected for some reason - maybe this is to give macOS more control to limit openGL/the opengl version? */ - - attribs[index] = 99; - attribs[index + 1] = 0x1000; - - - if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) { - attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200); - } - #endif - - RGFW_GL_ADD_ATTRIB(0, 0); - - return attribs; -} - -/* EGL only (no OSMesa nor normal OPENGL) */ -#elif defined(RGFW_EGL) - -#include - -#if defined(RGFW_LINK_EGL) - typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*); - - PFNEGLINITIALIZEPROC eglInitializeSource; - PFNEGLGETCONFIGSPROC eglGetConfigsSource; - PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource; - PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource; - PFNEGLCREATECONTEXTPROC eglCreateContextSource; - PFNEGLMAKECURRENTPROC eglMakeCurrentSource; - PFNEGLGETDISPLAYPROC eglGetDisplaySource; - PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource; - PFNEGLSWAPINTERVALPROC eglSwapIntervalSource; - PFNEGLBINDAPIPROC eglBindAPISource; - PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource; - PFNEGLTERMINATEPROC eglTerminateSource; - PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource; - - #define eglInitialize eglInitializeSource - #define eglGetConfigs eglGetConfigsSource - #define eglChooseConfig eglChooseConfigSource - #define eglCreateWindowSurface eglCreateWindowSurfaceSource - #define eglCreateContext eglCreateContextSource - #define eglMakeCurrent eglMakeCurrentSource - #define eglGetDisplay eglGetDisplaySource - #define eglSwapBuffers eglSwapBuffersSource - #define eglSwapInterval eglSwapIntervalSource - #define eglBindAPI eglBindAPISource - #define eglDestroyContext eglDestroyContextSource - #define eglTerminate eglTerminateSource - #define eglDestroySurface eglDestroySurfaceSource; -#endif - - -#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098 -#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb - -#ifndef RGFW_GL_ADD_ATTRIB -#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ - if (attVal) { \ - attribs[index] = attrib;\ - attribs[index + 1] = attVal;\ - index += 2;\ - } -#endif - - -void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) { - RGFW_UNUSED(software); -#if defined(RGFW_LINK_EGL) - eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize"); - eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs"); - eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig"); - eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface"); - eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext"); - eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent"); - eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay"); - eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers"); - eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval"); - eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI"); - eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext"); - eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate"); - eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface"); - - RGFW_ASSERT(eglInitializeSource != NULL && - eglGetConfigsSource != NULL && - eglChooseConfigSource != NULL && - eglCreateWindowSurfaceSource != NULL && - eglCreateContextSource != NULL && - eglMakeCurrentSource != NULL && - eglGetDisplaySource != NULL && - eglSwapBuffersSource != NULL && - eglSwapIntervalsSource != NULL && - eglBindAPISource != NULL && - eglDestroyContextSource != NULL && - eglTerminateSource != NULL && - eglDestroySurfaceSource != NULL); -#endif /* RGFW_LINK_EGL */ - -#ifdef RGFW_WAYLAND - if (RGFW_useWaylandBool) - win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h); -#endif - - #ifdef RGFW_WINDOWS - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc); - #elif defined(RGFW_MACOS) - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0); - #elif defined(RGFW_WAYLAND) - if (RGFW_useWaylandBool) - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display); - else - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); - #else - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); - #endif - - EGLint major, minor; - - eglInitialize(win->src.EGL_display, &major, &minor); - - #ifndef EGL_OPENGL_ES1_BIT - #define EGL_OPENGL_ES1_BIT 0x1 - #endif - - EGLint egl_config[24] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - #ifdef RGFW_OPENGL_ES1 - EGL_OPENGL_ES1_BIT, - #elif defined(RGFW_OPENGL_ES3) - EGL_OPENGL_ES3_BIT, - #elif defined(RGFW_OPENGL_ES2) - EGL_OPENGL_ES2_BIT, - #else - EGL_OPENGL_BIT, - #endif - EGL_NONE, EGL_NONE - }; - - { - size_t index = 7; - EGLint* attribs = egl_config; - - RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); - RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); - RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); - RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); - RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); - - if (RGFW_GL_HINTS[RGFW_glSRGB]) - RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]); - - RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); - } - - EGLConfig config; - EGLint numConfigs; - eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs); - - #if defined(RGFW_MACOS) - void* layer = RGFW_cocoaGetLayer(); - - RGFW_window_cocoaSetLayer(win, layer); - - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL); - #elif defined(RGFW_WINDOWS) - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); - #elif defined(RGFW_WAYLAND) - if (RGFW_useWaylandBool) - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL); - else - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); - #else - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); - #endif - - EGLint attribs[12]; - size_t index = 0; - -#ifdef RGFW_OPENGL_ES1 - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1); -#elif defined(RGFW_OPENGL_ES2) - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2); -#elif defined(RGFW_OPENGL_ES3) - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3); -#endif - - RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); - RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); - - if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) - RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); - - if (RGFW_GL_HINTS[RGFW_glMajor]) { - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]); - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]); - - if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) { - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); - } - else { - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); - } - } - - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]); - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]); - if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { - RGFW_GL_ADD_ATTRIB(0x2097, 0x2098); - } else { - RGFW_GL_ADD_ATTRIB(0x2096, 0x0000); - } - - RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); - - #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3) - eglBindAPI(EGL_OPENGL_ES_API); - #else - eglBindAPI(EGL_OPENGL_API); - #endif - - win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs); - - if (win->src.EGL_context == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context"); - return; - } - - eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); - eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized"); -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { - if (win->src.EGL_display == NULL) return; - - eglDestroySurface(win->src.EGL_display, win->src.EGL_surface); - eglDestroyContext(win->src.EGL_display, win->src.EGL_context); - eglTerminate(win->src.EGL_display); - win->src.EGL_display = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed"); -} - -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - if (win == NULL) - eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - else { - eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); - } -} - -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); } - -void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); } - -#ifdef RGFW_APPLE -void* RGFWnsglFramework = NULL; -#elif defined(RGFW_WINDOWS) -HMODULE RGFW_wgl_dll = NULL; -#endif - -RGFW_proc RGFW_getProcAddress(const char* procname) { - #if defined(RGFW_WINDOWS) - RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); - - if (proc) - return proc; - #endif - - return (RGFW_proc) eglGetProcAddress(procname); -} - -RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) { - const char* extensions = eglQueryString(_RGFW.root->src.EGL_display, EGL_EXTENSIONS); - return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); -} - -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL); - - eglSwapInterval(win->src.EGL_display, swapInterval); - -} - -#endif /* RGFW_EGL */ - -/* - end of RGFW_EGL defines -*/ -#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/ - -/* - RGFW_VULKAN defines -*/ -#ifdef RGFW_VULKAN -#ifdef RGFW_MACOS -#include -#endif - -const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) { - static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME}; - arr[1] = RGFW_VK_SURFACE; - if (count != NULL) *count = 2; - - return (const char**)arr; -} - -VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) { - RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance); - RGFW_ASSERT(surface != NULL); - - *surface = VK_NULL_HANDLE; - -#ifdef RGFW_X11 - RGFW_GOTO_WAYLAND(0); - VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window }; - return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface); -#endif -#if defined(RGFW_WAYLAND) -wayland: - VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface }; - return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface); -#elif defined(RGFW_WINDOWS) - VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window }; - - return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface); -#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) - void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); - VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView }; - - return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface); -#endif -} - - -RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { - RGFW_ASSERT(instance); - if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init(); -#ifdef RGFW_X11 - RGFW_GOTO_WAYLAND(0); - Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)); - if (_RGFW.root) - visual = _RGFW.root->src.visual.visual; - - RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual)); - return out; -#endif -#if defined(RGFW_WAYLAND) -wayland: - RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display); - return wlout; -#elif defined(RGFW_WINDOWS) -#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) - return RGFW_FALSE; /* TODO */ -#endif -} -#endif /* end of RGFW_vulkan */ - -/* -This is where OS specific stuff starts -*/ - - -#if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX) - int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */ - - #if defined(__linux__) - #include - #include - #include - #include - - u32 RGFW_linux_updateGamepad(RGFW_window* win); - u32 RGFW_linux_updateGamepad(RGFW_window* win) { - /* check for new gamepads */ - static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"}; - static u8 RGFW_rawGamepads[6]; - { - u16 i; - for (i = 0; i < 6; i++) { - u16 index = RGFW_gamepadCount; - if (RGFW_rawGamepads[i]) { - struct input_id device_info; - if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) { - if (errno == ENODEV) { - RGFW_rawGamepads[i] = 0; - } - } - continue; - } - - i32 js = open(str[i], O_RDONLY); - - if (js <= 0) - break; - - if (RGFW_gamepadCount >= 4) { - close(js); - break; - } - - RGFW_rawGamepads[i] = 1; - - int axes, buttons; - if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) { - close(js); - continue; - } - - if (buttons <= 5 || buttons >= 30) { - close(js); - continue; - } - - RGFW_gamepadCount++; - - RGFW_gamepads[index] = js; - - ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]); - RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0; - - u8 j; - for (j = 0; j < 16; j++) { - RGFW_gamepadPressed[index][j].prev = 0; - RGFW_gamepadPressed[index][j].current = 0; - } - - win->event.type = RGFW_gamepadConnected; - - RGFW_gamepads_type[index] = RGFW_gamepadUnknown; - if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box")) - RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft; - else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5")) - RGFW_gamepads_type[index] = RGFW_gamepadSony; - else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo")) - RGFW_gamepads_type[index] = RGFW_gamepadNintendo; - else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech")) - RGFW_gamepads_type[index] = RGFW_gamepadLogitech; - - win->event.gamepad = index; - RGFW_gamepadCallback(win, index, 1); - return 1; - } - } - /* check gamepad events */ - u8 i; - - for (i = 0; i < RGFW_gamepadCount; i++) { - struct js_event e; - if (RGFW_gamepads[i] == 0) - continue; - - i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0); - fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK); - - ssize_t bytes; - while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) { - switch (e.type) { - case JS_EVENT_BUTTON: { - size_t typeIndex = 0; - if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1; - else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2; - - win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased; - u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */ - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, - RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, - },{ /* xbox */ - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart, - RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight - },{ /* Logitech */ - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, - RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight - } - }; - - win->event.button = RGFW_linux2RGFW[typeIndex][e.number]; - win->event.gamepad = i; - if (win->event.button == 255) break; - - RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current; - RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value); - RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value)); - - return 1; - } - case JS_EVENT_AXIS: { - size_t axis = e.number / 2; - if (axis == 2) axis = 1; - - ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount); - win->event.axisesCount = 2; - - if (axis < 3) { - if (e.number == 0 || e.number == 3) - RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100); - else if (e.number == 1 || e.number == 4) { - RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100); - } - } - - win->event.axis[axis] = RGFW_gamepadAxes[i][axis]; - win->event.type = RGFW_gamepadAxisMove; - win->event.gamepad = i; - win->event.whichAxis = (u8)axis; - RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis); - return 1; - } - default: break; - } - } - if (bytes == -1 && errno == ENODEV) { - RGFW_gamepadCount--; - close(RGFW_gamepads[i]); - RGFW_gamepads[i] = 0; - - win->event.type = RGFW_gamepadDisconnected; - win->event.gamepad = i; - RGFW_gamepadCallback(win, i, 0); - return 1; - } - } - return 0; - } - - #endif -#endif - - - -/* - - Start of Wayland defines - - -*/ - -#ifdef RGFW_WAYLAND -/* -Wayland TODO: (out of date) -- fix RGFW_keyPressed lock state - - RGFW_windowMoved, the window was moved (by the user) - RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized] - RGFW_windowRefresh The window content needs to be refreshed - - RGFW_DND a file has been dropped into the window - RGFW_DNDInit - -- window args: - #define RGFW_windowNoResize the window cannot be resized by the user - #define RGFW_windowAllowDND the window supports drag and drop - #define RGFW_scaleToMonitor scale the window to the screen - -- other missing functions functions ("TODO wayland") (~30 functions) -- fix buffer rendering weird behavior -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -RGFW_window* RGFW_key_win = NULL; - -/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ -#include "xdg-shell.h" -#include "xdg-decoration-unstable-v1.h" - -struct xkb_context *xkb_context; -struct xkb_keymap *keymap = NULL; -struct xkb_state *xkb_state = NULL; -enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode; -struct zxdg_decoration_manager_v1 *decoration_manager = NULL; - -struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL; -struct wl_surface* RGFW_cursor_surface = NULL; -struct wl_cursor_image* RGFW_cursor_image = NULL; - -void xdg_wm_base_ping_handler(void *data, - struct xdg_wm_base *wm_base, uint32_t serial) -{ - RGFW_UNUSED(data); - xdg_wm_base_pong(wm_base, serial); -} - -const struct xdg_wm_base_listener xdg_wm_base_listener = { - .ping = xdg_wm_base_ping_handler, -}; - -RGFW_bool RGFW_wl_configured = 0; - -void xdg_surface_configure_handler(void *data, - struct xdg_surface *xdg_surface, uint32_t serial) -{ - RGFW_UNUSED(data); - xdg_surface_ack_configure(xdg_surface, serial); - RGFW_wl_configured = 1; -} - -const struct xdg_surface_listener xdg_surface_listener = { - .configure = xdg_surface_configure_handler, -}; - -void xdg_toplevel_configure_handler(void *data, - struct xdg_toplevel *toplevel, int32_t width, int32_t height, - struct wl_array *states) -{ - RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states); - RGFW_UNUSED(width); RGFW_UNUSED(height); -} - -void xdg_toplevel_close_handler(void *data, - struct xdg_toplevel *toplevel) -{ - RGFW_UNUSED(data); - RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel); - if (win == NULL) - win = RGFW_key_win; - - RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); - RGFW_windowQuitCallback(win); -} - -void shm_format_handler(void *data, - struct wl_shm *shm, uint32_t format) -{ - RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format); -} - -const struct wl_shm_listener shm_listener = { - .format = shm_format_handler, -}; - -const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = xdg_toplevel_configure_handler, - .close = xdg_toplevel_close_handler, -}; - -RGFW_window* RGFW_mouse_win = NULL; - -void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y); - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - RGFW_mouse_win = win; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter; - e.point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); - e._win = win); - - RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE); -} -void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface); - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - if (RGFW_mouse_win == win) - RGFW_mouse_win = NULL; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave; - e.point = win->event.point; - e._win = win); - - RGFW_mouseNotifyCallback(win, win->event.point, RGFW_FALSE); -} -void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y); - - RGFW_ASSERT(RGFW_mouse_win != NULL); - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)); - e._win = RGFW_mouse_win); - - RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector); -} -void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); - RGFW_ASSERT(RGFW_mouse_win != NULL); - - u32 b = (button - 0x110) + 1; - - /* flip right and middle button codes */ - if (b == 2) b = 3; - else if (b == 3) b = 2; - - RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current; - RGFW_mouseButtons[b].current = RGFW_BOOL(state); - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed + RGFW_BOOL(state); - e.button = (u8)b; - e._win = RGFW_mouse_win); - RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state)); -} -void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); - RGFW_ASSERT(RGFW_mouse_win != NULL); - - double scroll = wl_fixed_to_double(value); - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.button = RGFW_mouseScrollUp + (scroll < 0); - e.scroll = scroll; - e._win = RGFW_mouse_win); - - RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1); -} - -void RGFW_doNothing(void) { } - -void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format); - - char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); - xkb_keymap_unref (keymap); - keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - munmap (keymap_string, size); - close (fd); - xkb_state_unref (xkb_state); - xkb_state = xkb_state_new (keymap); -} -void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys); - - RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface); - - RGFW_key_win->_flags |= RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = RGFW_focusIn, e._win = RGFW_key_win); - RGFW_focusCallback(RGFW_key_win, RGFW_TRUE); - - RGFW_resetKey(); - if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); -} -void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); - - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - if (RGFW_key_win == win) - RGFW_key_win = NULL; - - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win); - win->_flags &= ~(u32)RGFW_windowFocus; - RGFW_focusCallback(win, RGFW_FALSE); -} -void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); - - if (RGFW_key_win == NULL) return; - - xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8); - - u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8); - RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current; - RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state); - - RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state); - e.key = (u8)RGFWkey; - e.keyChar = (u8)keysym; - e.repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey); - e._win = RGFW_key_win); - - RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock"))); - RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state)); -} -void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); - xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); -} -struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *, -int, int))&RGFW_doNothing}; - -void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) { - RGFW_UNUSED(data); - struct wl_pointer_listener pointer_listener = (struct wl_pointer_listener){&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing}; - - if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer *pointer = wl_seat_get_pointer (seat); - wl_pointer_add_listener (pointer, &pointer_listener, NULL); - } - if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat); - wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL); - } -} -struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing}; - -void wl_global_registry_handler(void *data, - struct wl_registry *registry, uint32_t id, const char *interface, - uint32_t version) -{ - RGFW_window* win = (RGFW_window*)data; - RGFW_UNUSED(version); - if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) { - win->src.compositor = wl_registry_bind(registry, - id, &wl_compositor_interface, 4); - } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) { - win->src.xdg_wm_base = wl_registry_bind(registry, - id, &xdg_wm_base_interface, 1); - } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) { - decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); - } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) { - win->src.shm = wl_registry_bind(registry, - id, &wl_shm_interface, 1); - wl_shm_add_listener(win->src.shm, &shm_listener, NULL); - } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) { - win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); - wl_seat_add_listener(win->src.seat, &seat_listener, NULL); - } -} - -void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); } -const struct wl_registry_listener registry_listener = { - .global = wl_global_registry_handler, - .global_remove = wl_global_registry_remove, -}; - -void decoration_handle_configure(void *data, - struct zxdg_toplevel_decoration_v1 *decoration, - enum zxdg_toplevel_decoration_v1_mode mode) { - RGFW_UNUSED(data); RGFW_UNUSED(decoration); - RGFW_current_mode = mode; -} - -const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { - .configure = decoration_handle_configure, -}; - -void randname(char *buf) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - - int i; - for (i = 0; i < 6; ++i) { - buf[i] = (char)('A'+(r&15)+(r&16)*2); - r >>= 5; - } -} - -size_t wl_stringlen(char* name) { - size_t i = 0; - while (name[i]) { i++; } - return i; -} - -int anonymous_shm_open(void) { - char name[] = "/RGFW-wayland-XXXXXX"; - int retries = 100; - - do { - randname(name + wl_stringlen(name) - 6); - - --retries; - /* shm_open guarantees that O_CLOEXEC is set */ - int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - } while (retries > 0 && errno == EEXIST); - - return -1; -} - -int create_shm_file(off_t size) { - int fd = anonymous_shm_open(); - if (fd < 0) { - return fd; - } - - if (ftruncate(fd, size) < 0) { - close(fd); - return -1; - } - - return fd; -} - -void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - RGFW_UNUSED(data); RGFW_UNUSED(cb); RGFW_UNUSED(time); - - #ifdef RGFW_BUFFER - RGFW_window* win = (RGFW_window*)data; - wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); - wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h); - wl_surface_commit(win->src.surface); - #endif -} - -const struct wl_callback_listener wl_surface_frame_listener = { - .done = wl_surface_frame_done, -}; -#endif /* RGFW_WAYLAND */ -/* - End of Wayland defines -*/ - -/* - - -Start of Linux / Unix defines - - -*/ - -#ifdef RGFW_UNIX -#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) -#include -#endif - -#include - -#ifndef RGFW_NO_DPI -#include -#include -#endif - -#include -#include -#include -#include - -#include /* for converting keycode to string */ -#include /* for hiding */ -#include -#include -#include - -#include /* for data limits (mainly used in drag and drop functions) */ -#include - -/* atoms needed for drag and drop */ -Atom XdndAware, XtextPlain, XtextUriList; -Atom RGFW_XUTF8_STRING = 0; - -Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0; - -#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int); - typedef void (*PFN_XcursorImageDestroy)(XcursorImage*); - typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*); -#endif -#ifdef RGFW_OPENGL - typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); -#endif - -#if !defined(RGFW_NO_X11_XI_PRELOAD) - typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); - PFN_XISelectEvents XISelectEventsSRC = NULL; - #define XISelectEvents XISelectEventsSRC - - void* X11Xihandle = NULL; -#endif - -#if !defined(RGFW_NO_X11_EXT_PRELOAD) - typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int); - PFN_XSyncIntToValue XSyncIntToValueSRC = NULL; - #define XSyncIntToValue XSyncIntToValueSRC - - typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue); - PFN_XSyncSetCounter XSyncSetCounterSRC = NULL; - #define XSyncSetCounter XSyncSetCounterSRC - - typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue); - PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL; - #define XSyncCreateCounter XSyncCreateCounterSRC - - typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); - PFN_XShapeCombineMask XShapeCombineMaskSRC; - #define XShapeCombineMask XShapeCombineMaskSRC - - typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); - PFN_XShapeCombineRegion XShapeCombineRegionSRC; - #define XShapeCombineRegion XShapeCombineRegionSRC - void* X11XEXThandle = NULL; -#endif - -#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL; - PFN_XcursorImageCreate XcursorImageCreateSRC = NULL; - PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL; - - #define XcursorImageLoadCursor XcursorImageLoadCursorSRC - #define XcursorImageCreate XcursorImageCreateSRC - #define XcursorImageDestroy XcursorImageDestroySRC - - void* X11Cursorhandle = NULL; -#endif - -const char* RGFW_instName = NULL; -void RGFW_setXInstName(const char* name) { - RGFW_instName = name; -} - -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) -RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { - const char* extensions = glXQueryExtensionsString(_RGFW.display, XDefaultScreen(_RGFW.display)); - return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); -} -RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); } -#endif - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { - RGFW_GOTO_WAYLAND(0); - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = (u8*)buffer; - win->bufferSize = area; - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer"); - #ifdef RGFW_X11 - #ifdef RGFW_OSMESA - win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - - win->src.bitmap = XCreateImage( - win->src.display, win->src.visual.visual, (u32)win->src.visual.depth, - ZPixmap, 0, NULL, area.w, area.h, 32, 0 - ); - #endif - #ifdef RGFW_WAYLAND - wayland: {} - u32 size = (u32)(win->r.w * win->r.h * 4); - int fd = create_shm_file(size); - if (fd < 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer."); - exit(1); - } - - win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (win->src.buffer == MAP_FAILED) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!"); - close(fd); - exit(1); - } - - win->_flags |= RGFW_BUFFER_ALLOC; - - struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size); - win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4, - WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - - close(fd); - - wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); - wl_surface_commit(win->src.surface); - - u8 color[] = {0x00, 0x00, 0x00, 0xFF}; - - size_t i; - for (i = 0; i < area.w * area.h * 4; i += 4) { - RGFW_MEMCPY(&win->buffer[i], color, 4); - } - - RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4)); - - #if defined(RGFW_OSMESA) - win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #endif -#else - #ifdef RGFW_WAYLAND - wayland:{} - #endif - - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); -#endif -} - -#define RGFW_LOAD_ATOM(name) \ - static Atom name = 0; \ - if (name == 0) name = XInternAtom(_RGFW.display, #name, False); - -void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); - - RGFW_GOTO_WAYLAND(0); - #ifdef RGFW_X11 - RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); - - struct __x11WindowHints { - unsigned long flags, functions, decorations, status; - long input_mode; - } hints; - hints.flags = 2; - hints.decorations = border; - - XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, - PropModeReplace, (u8*)&hints, 5 - ); - - if (RGFW_window_isHidden(win) == 0) { - RGFW_window_hide(win); - RGFW_window_show(win); - } - - #endif - #ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(win); RGFW_UNUSED(border); - #endif -} - -void RGFW_releaseCursor(RGFW_window* win) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XUngrabPointer(win->src.display, CurrentTime); - - /* disable raw input */ - unsigned char mask[] = { 0 }; - XIEventMask em; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(win); -#endif -} - -void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - /* enable raw input */ - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; - XISetMask(mask, XI_RawMotion); - - XIEventMask em; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); - - XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2))); -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(win); RGFW_UNUSED(r); -#endif -} - -#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL) -#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ - void* ptr = dlsym(proc, #name); \ - if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \ -} - - - -void RGFW_window_getVisual(RGFW_window* win, RGFW_bool software) { -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) - i32* visual_attribs = RGFW_initFormatAttribs(software); - i32 fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount); - - i32 best_fbc = -1; - i32 best_depth = 0; - i32 best_samples = 0; - - if (fbcount == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs"); - return; - } - - i32 i; - for (i = 0; i < fbcount; i++) { - XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]); - if (vi == NULL) - continue; - - i32 samp_buf, samples; - glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples); - - if (best_fbc == -1) best_fbc = i; - if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && best_depth == 0) { - best_fbc = i; - best_depth = vi->depth; - } - if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) { - best_fbc = i; - best_depth = vi->depth; - best_samples = samples; - } - XFree(vi); - } - - if (best_fbc == -1) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual"); - return; - } - - win->src.bestFbc = fbc[best_fbc]; - XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc); - if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent)) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth"); - - if (best_samples < RGFW_GL_HINTS[RGFW_glSamples]) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling"); - - XFree(fbc); - win->src.visual = *vi; - XFree(vi); -#else - RGFW_UNUSED(software); - win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display)); - win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display)); - if (win->_flags & RGFW_windowTransparent) { - XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */ - if (win->src.visual.depth != 32) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth"); - } -#endif -} - -#ifndef RGFW_EGL -void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) { - RGFW_UNUSED(software); -#ifdef RGFW_OPENGL - i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 }; - context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB; - if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) - context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - else - context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - - if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { - context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB; - context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor]; - context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB; - context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor]; - } - - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) - glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB"); - - GLXContext ctx = NULL; - if (_RGFW.root != NULL && _RGFW.root != win) { - ctx = _RGFW.root->src.ctx; - RGFW_window_makeCurrent_OpenGL(_RGFW.root); - } - - if (glXCreateContextAttribsARB == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context"); - win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True); - } - else { - win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs); - XSync(win->src.display, False); - if (win->src.ctx == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context"); - win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True); - } - } - - glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); -#else - RGFW_UNUSED(win); RGFW_UNUSED(software); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - if (win->src.ctx == NULL) return; - glXDestroyContext(win->src.display, win->src.ctx); - win->src.ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#else -RGFW_UNUSED(win); -#endif -} -#endif - - -i32 RGFW_init(void) { - RGFW_GOTO_WAYLAND(1); -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - -#ifdef RGFW_X11 - if (_RGFW.windowCount != -1) return 0; - #ifdef RGFW_USE_XDL - XDL_init(); - #endif - - #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so"); - #else - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1"); - #endif - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate); - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy); - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor); - #endif - - #if !defined(RGFW_NO_X11_XI_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so"); - #else - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6"); - #endif - RGFW_PROC_DEF(X11Xihandle, XISelectEvents); - #endif - - #if !defined(RGFW_NO_X11_EXT_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so"); - #else - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6"); - #endif - RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter); - RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue); - RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter); - RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion); - RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); - #endif - - XInitThreads(); /*!< init X11 threading */ - _RGFW.display = XOpenDisplay(0); - XSetWindowAttributes wa; - RGFW_MEMSET(&wa, 0, sizeof(wa)); - wa.event_mask = PropertyChangeMask; - _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0, - InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa); - - _RGFW.windowCount = 0; - u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4); - _RGFW.clipboard = NULL; - - XkbComponentNamesRec rec; - XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd); - XkbDescPtr evdesc; - u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])]; - - XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc); - - RGFW_MEMSET(&rec, 0, sizeof(rec)); - rec.keycodes = (char*)"evdev"; - evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False); - /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */ - if(evdesc != NULL && desc != NULL){ - for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){ - old[i] = RGFW_keycodes[i]; - RGFW_keycodes[i] = 0; - } - for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){ - for(int j = desc->min_key_code; j <= desc->max_key_code; j++){ - if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){ - RGFW_keycodes[j] = old[i]; - break; - } - } - } - XkbFreeKeyboard(desc, 0, True); - XkbFreeKeyboard(evdesc, 0, True); - } -#endif -#ifdef RGFW_WAYLAND -wayland: - _RGFW.wl_display = wl_display_connect(NULL); -#endif - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 0; -} - - -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - RGFW_window_basic_init(win, rect, flags); - -#ifdef RGFW_WAYLAND - win->src.compositor = NULL; -#endif - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */ - - win->src.display = XOpenDisplay(NULL); - RGFW_window_getVisual(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware)); - - /* make X window attrubutes */ - XSetWindowAttributes swa; - RGFW_MEMSET(&swa, 0, sizeof(swa)); - - Colormap cmap; - swa.colormap = cmap = XCreateColormap(win->src.display, - DefaultRootWindow(win->src.display), - win->src.visual.visual, AllocNone); - swa.event_mask = event_mask; - - /* create the window */ - win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h, - 0, win->src.visual.depth, InputOutput, win->src.visual.visual, - CWColormap | CWBorderPixel | CWEventMask, &swa); - - XFreeColors(win->src.display, cmap, NULL, 0, 0); - - win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL); - - /* In your .desktop app, if you set the property - StartupWMClass=RGFW that will assoicate the launcher icon - with your application - robrohan */ - if (RGFW_className == NULL) - RGFW_className = (char*)name; - - XClassHint hint; - hint.res_class = (char*)RGFW_className; - if (RGFW_instName == NULL) hint.res_name = (char*)name; - else hint.res_name = (char*)RGFW_instName; - XSetClassHint(win->src.display, win->src.window, &hint); - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */ - - /* make it so the user can't close the window until the program does */ - if (wm_delete_window == 0) { - wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False); - RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False); - RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False); - } - - XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1); - /* set the background */ - RGFW_window_setName(win, name); - - XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */ - - if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */ - win->_flags |= RGFW_windowAllowDND; - - /* actions */ - XtextUriList = XInternAtom(win->src.display, "text/uri-list", False); - XtextPlain = XInternAtom(win->src.display, "text/plain", False); - XdndAware = XInternAtom(win->src.display, "XdndAware", False); - const u8 version = 5; - - XChangeProperty(win->src.display, win->src.window, - XdndAware, 4, 32, - PropModeReplace, &version, 1); /*!< turns on drag and drop */ - } - -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER) - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST) - Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window}; - XSetWMProtocols(win->src.display, win->src.window, protcols, 2); - - XSyncValue initial_value; - XSyncIntToValue(&initial_value, 0); - win->src.counter = XSyncCreateCounter(win->src.display, initial_value); - - XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1); -#endif - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware)); - RGFW_window_initBuffer(win); - } - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - RGFW_window_setMouseDefault(win); - RGFW_window_setFlags(win, flags); - - win->src.r = win->r; - - RGFW_window_show(win); - return win; /*return newly created window */ -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental"); - - win->src.wl_display = _RGFW.wl_display; - if (win->src.wl_display == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display"); - #ifdef RGFW_X11 - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11"); - RGFW_useWayland(0); - return RGFW_createWindowPtr(name, rect, flags, win); - #endif - return NULL; - } - - - #ifdef RGFW_X11 - win->src.window = _RGFW.helperWindow; - XMapWindow(win->src.display, win->src.window); - XFlush(win->src.display); - if (wm_delete_window == 0) { - wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False); - RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False); - RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False); - } - #endif - - struct wl_registry *registry = wl_display_get_registry(win->src.wl_display); - wl_registry_add_listener(registry, ®istry_listener, win); - - wl_display_roundtrip(win->src.wl_display); - wl_display_dispatch(win->src.wl_display); - - if (win->src.compositor == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor."); - return NULL; - } - - if (RGFW_wl_cursor_theme == NULL) { - RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm); - RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor); - - struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr"); - RGFW_cursor_image = cursor->images[0]; - struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); - - wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); - wl_surface_commit(RGFW_cursor_surface); - } - - xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL); - - xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - win->src.surface = wl_compositor_create_surface(win->src.compositor); - wl_surface_set_user_data(win->src.surface, win); - - win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface); - xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL); - - xdg_wm_base_set_user_data(win->src.xdg_wm_base, win); - - win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); - xdg_toplevel_set_user_data(win->src.xdg_toplevel, win); - xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL); - - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); - - if (!(flags & RGFW_windowNoBorder)) { - win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - decoration_manager, win->src.xdg_toplevel); - } - - wl_display_roundtrip(win->src.wl_display); - - wl_surface_commit(win->src.surface); - RGFW_window_show(win); - - /* wait for the surface to be configured */ - while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { } - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware)); - RGFW_window_initBuffer(win); - } - struct wl_callback* callback = wl_surface_frame(win->src.surface); - wl_callback_add_listener(callback, &wl_surface_frame_listener, win); - wl_surface_commit(win->src.surface); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - - RGFW_window_setMouseDefault(win); - RGFW_window_setFlags(win, flags); - return win; /* return newly created window */ -#endif -} - -RGFW_area RGFW_getScreenSize(void) { - RGFW_GOTO_WAYLAND(1); - RGFW_init(); - - #ifdef RGFW_X11 - Screen* scrn = DefaultScreenOfDisplay(_RGFW.display); - return RGFW_AREA(scrn->width, scrn->height); - #endif - #ifdef RGFW_WAYLAND - wayland: return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */ - #endif -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_init(); - RGFW_point RGFWMouse; - - i32 x, y; - u32 z; - Window window1, window2; - XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z); - - return RGFWMouse; -} - -RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event); -void RGFW_XHandleClipboardSelection(XEvent* event) { - RGFW_LOAD_ATOM(ATOM_PAIR); - RGFW_LOAD_ATOM(MULTIPLE); - RGFW_LOAD_ATOM(TARGETS); - RGFW_LOAD_ATOM(SAVE_TARGETS); - - const XSelectionRequestEvent* request = &event->xselectionrequest; - const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING }; - const int formatCount = sizeof(formats) / sizeof(formats[0]); - - if (request->target == TARGETS) { - const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING }; - - XChangeProperty(_RGFW.display, request->requestor, request->property, - XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); - } else if (request->target == MULTIPLE) { - Atom* targets = NULL; - - Atom actualType = 0; - int actualFormat = 0; - unsigned long count = 0, bytesAfter = 0; - - XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX, - False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); - - unsigned long i; - for (i = 0; i < (u32)count; i += 2) { - if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING) - XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i], - 8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len); - else - targets[i + 1] = None; - } - - XChangeProperty(_RGFW.display, - request->requestor, request->property, ATOM_PAIR, 32, - PropModeReplace, (u8*) targets, (i32)count); - - XFlush(_RGFW.display); - XFree(targets); - } else if (request->target == SAVE_TARGETS) - XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); - else { - int i; - for (i = 0; i < formatCount; i++) { - if (request->target != formats[i]) - continue; - XChangeProperty(_RGFW.display, request->requestor, request->property, request->target, - 8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len); - } - } - - XEvent reply = { SelectionNotify }; - reply.xselection.property = request->property; - reply.xselection.display = request->display; - reply.xselection.requestor = request->requestor; - reply.xselection.selection = request->selection; - reply.xselection.target = request->target; - reply.xselection.time = request->time; - - XSendEvent(_RGFW.display, request->requestor, False, 0, &reply); -} - -char* RGFW_strtok(char* str, const char* delimStr); -char* RGFW_strtok(char* str, const char* delimStr) { - static char* static_str = NULL; - - if (str != NULL) - static_str = str; - - if (static_str == NULL) { - return NULL; - } - - while (*static_str != '\0') { - RGFW_bool delim = 0; - const char* d; - for (d = delimStr; *d != '\0'; d++) { - if (*static_str == *d) { - delim = 1; - break; - } - } - if (!delim) - break; - static_str++; - } - - if (*static_str == '\0') - return NULL; - - char* token_start = static_str; - while (*static_str != '\0') { - int delim = 0; - const char* d; - for (d = delimStr; *d != '\0'; d++) { - if (*static_str == *d) { - delim = 1; - break; - } - } - - if (delim) { - *static_str = '\0'; - static_str++; - break; - } - static_str++; - } - - return token_start; -} - -i32 RGFW_XHandleClipboardSelectionHelper(void); - -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - RGFW_XHandleClipboardSelectionHelper(); - - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) return ev; - - #if defined(__linux__) && !defined(RGFW_NO_LINUX) - if (RGFW_linux_updateGamepad(win)) return &win->event; - #endif - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - RGFW_LOAD_ATOM(XdndTypeList); - RGFW_LOAD_ATOM(XdndSelection); - RGFW_LOAD_ATOM(XdndEnter); - RGFW_LOAD_ATOM(XdndPosition); - RGFW_LOAD_ATOM(XdndStatus); - RGFW_LOAD_ATOM(XdndLeave); - RGFW_LOAD_ATOM(XdndDrop); - RGFW_LOAD_ATOM(XdndFinished); - RGFW_LOAD_ATOM(XdndActionCopy); - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST); - RGFW_LOAD_ATOM(WM_PROTOCOLS); - XPending(win->src.display); - - XEvent E; /*!< raw X11 event */ - - /* if there is no unread qued events, get a new one */ - if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading)) - && win->event.type != RGFW_quit - ) - XNextEvent(win->src.display, &E); - else { - return NULL; - } - - win->event.type = 0; - - /* xdnd data */ - static Window source = 0; - static long version = 0; - static i32 format = 0; - - XEvent reply = { ClientMessage }; - - switch (E.type) { - case KeyPress: - case KeyRelease: { - win->event.repeat = RGFW_FALSE; - /* check if it's a real key release */ - if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */ - XEvent NE; - XPeekEvent(win->src.display, &NE); - - if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */ - win->event.repeat = RGFW_TRUE; - } - - /* set event key data */ - win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); - KeySym sym = (KeySym)XkbKeycodeToKeysym(win->src.display, (KeyCode)E.xkey.keycode, 0, (KeyCode)E.xkey.state & ShiftMask ? 1 : 0); - - if ((E.xkey.state & LockMask) && sym >= XK_a && sym <= XK_z) - sym = (E.xkey.state & ShiftMask) ? sym + 32 : sym - 32; - if ((u8)sym != (u32)sym) - sym = 0; - - win->event.keyChar = (u8)sym; - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - /* get keystate data */ - win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased; - - XKeyboardState keystate; - XGetKeyboardControl(win->src.display, &keystate); - - RGFW_keyboard[win->event.key].current = (E.type == KeyPress); - - XkbStateRec state; - XkbGetState(win->src.display, XkbUseCoreKbd, &state); - RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress)); - break; - } - case ButtonPress: - case ButtonRelease: - if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */ - XFlush(win->src.display); - return RGFW_window_checkEvent(win); - } - - win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */ - win->event.button = (u8)(E.xbutton.button - 1); - switch(win->event.button) { - case RGFW_mouseScrollUp: - win->event.scroll = 1; - break; - case RGFW_mouseScrollDown: - win->event.scroll = -1; - break; - default: break; - } - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - - if (win->event.repeat == RGFW_FALSE) - win->event.repeat = RGFW_isPressed(win, win->event.key); - - RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress); - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress)); - break; - - case MotionNotify: - win->event.point.x = E.xmotion.x; - win->event.point.y = E.xmotion.y; - - win->event.vector.x = win->event.point.x - win->_lastMousePoint.x; - win->event.vector.y = win->event.point.y - win->_lastMousePoint.y; - win->_lastMousePoint = win->event.point; - - win->event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - break; - - case GenericEvent: { - /* MotionNotify is used for mouse events if the mouse isn't held */ - if (!(win->_flags & RGFW_HOLD_MOUSE)) { - XFreeEventData(win->src.display, &E.xcookie); - break; - } - - XGetEventData(win->src.display, &E.xcookie); - if (E.xcookie.evtype == XI_RawMotion) { - XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; - if (raw->valuators.mask_len == 0) { - XFreeEventData(win->src.display, &E.xcookie); - break; - } - - double deltaX = 0.0f; - double deltaY = 0.0f; - - /* check if relative motion data exists where we think it does */ - if (XIMaskIsSet(raw->valuators.mask, 0) != 0) - deltaX += raw->raw_values[0]; - if (XIMaskIsSet(raw->valuators.mask, 1) != 0) - deltaY += raw->raw_values[1]; - - win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY); - win->event.point.x = win->_lastMousePoint.x + win->event.vector.x; - win->event.point.y = win->_lastMousePoint.y + win->event.vector.y; - win->_lastMousePoint = win->event.point; - - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); - - win->event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - } - - XFreeEventData(win->src.display, &E.xcookie); - break; - } - - case Expose: { - win->event.type = RGFW_windowRefresh; - RGFW_windowRefreshCallback(win); - -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - XSyncValue value; - XSyncIntToValue(&value, (i32)win->src.counter_value); - XSyncSetCounter(win->src.display, win->src.counter, value); -#endif - break; - } - case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break; - case ClientMessage: { - /* if the client closed the window */ - if (E.xclient.data.l[0] == (long)wm_delete_window) { - win->event.type = RGFW_quit; - RGFW_window_setShouldClose(win, RGFW_TRUE); - RGFW_windowQuitCallback(win); - break; - } -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { - RGFW_windowRefreshCallback(win); - win->src.counter_value = 0; - win->src.counter_value |= E.xclient.data.l[2]; - win->src.counter_value |= (E.xclient.data.l[3] << 32); - - XSyncValue value; - XSyncIntToValue(&value, (i32)win->src.counter_value); - XSyncSetCounter(win->src.display, win->src.counter, value); - break; - } -#endif - if ((win->_flags & RGFW_windowAllowDND) == 0) - break; - - reply.xclient.window = source; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)win->src.window; - reply.xclient.data.l[1] = 0; - reply.xclient.data.l[2] = None; - - if (E.xclient.message_type == XdndEnter) { - if (version > 5) - break; - - unsigned long count; - Atom* formats; - Atom real_formats[6]; - Bool list = E.xclient.data.l[1] & 1; - - source = (unsigned long int)E.xclient.data.l[0]; - version = E.xclient.data.l[1] >> 24; - format = None; - if (list) { - Atom actualType; - i32 actualFormat; - unsigned long bytesAfter; - - XGetWindowProperty( - win->src.display, source, XdndTypeList, - 0, LONG_MAX, False, 4, - &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats - ); - } else { - count = 0; - - size_t i; - for (i = 2; i < 5; i++) { - if (E.xclient.data.l[i] != None) { - real_formats[count] = (unsigned long int)E.xclient.data.l[i]; - count += 1; - } - } - - formats = real_formats; - } - - size_t i; - for (i = 0; i < count; i++) { - if (formats[i] == XtextUriList || formats[i] == XtextPlain) { - format = (int)formats[i]; - break; - } - } - - if (list) { - XFree(formats); - } - - break; - } - - if (E.xclient.message_type == XdndPosition) { - const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; - const i32 yabs = (E.xclient.data.l[2]) & 0xffff; - Window dummy; - i32 xpos, ypos; - - if (version > 5) - break; - - XTranslateCoordinates( - win->src.display, XDefaultRootWindow(win->src.display), win->src.window, - xabs, yabs, &xpos, &ypos, &dummy - ); - - win->event.point.x = xpos; - win->event.point.y = ypos; - - reply.xclient.window = source; - reply.xclient.message_type = XdndStatus; - - if (format) { - reply.xclient.data.l[1] = 1; - if (version >= 2) - reply.xclient.data.l[4] = (long)XdndActionCopy; - } - - XSendEvent(win->src.display, source, False, NoEventMask, &reply); - XFlush(win->src.display); - break; - } - if (E.xclient.message_type != XdndDrop) - break; - - if (version > 5) - break; - - size_t i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - - win->event.droppedFilesCount = 0; - - - win->event.type = RGFW_DNDInit; - - if (format) { - Time time = (version >= 1) - ? (Time)E.xclient.data.l[2] - : CurrentTime; - - XConvertSelection( - win->src.display, XdndSelection, (Atom)format, - XdndSelection, win->src.window, time - ); - } else if (version >= 2) { - XEvent new_reply = { ClientMessage }; - - XSendEvent(win->src.display, source, False, NoEventMask, &new_reply); - XFlush(win->src.display); - } - - RGFW_dndInitCallback(win, win->event.point); - } break; - case SelectionRequest: - RGFW_XHandleClipboardSelection(&E); - XFlush(win->src.display); - return RGFW_window_checkEvent(win); - case SelectionNotify: { - /* this is only for checking for xdnd drops */ - if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND)) - break; - char* data; - unsigned long result; - - Atom actualType; - i32 actualFormat; - unsigned long bytesAfter; - - XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); - - if (result == 0) - break; - - const char* prefix = (const char*)"file://"; - - char* line; - - win->event.droppedFilesCount = 0; - win->event.type = RGFW_DND; - - while ((line = (char*)RGFW_strtok(data, "\r\n"))) { - char path[RGFW_MAX_PATH]; - - data = NULL; - - if (line[0] == '#') - continue; - - char* l; - for (l = line; 1; l++) { - if ((l - line) > 7) - break; - else if (*l != prefix[(l - line)]) - break; - else if (*l == '\0' && prefix[(l - line)] == '\0') { - line += 7; - while (*line != '/') - line++; - break; - } else if (*l == '\0') - break; - } - - win->event.droppedFilesCount++; - - size_t index = 0; - while (*line) { - if (line[0] == '%' && line[1] && line[2]) { - const char digits[3] = { line[1], line[2], '\0' }; - path[index] = (char) RGFW_STRTOL(digits, NULL, 16); - line += 2; - } else - path[index] = *line; - - index++; - line++; - } - path[index] = '\0'; - RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1); - } - - RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); - if (data) - XFree(data); - - if (version >= 2) { - XEvent new_reply = { ClientMessage }; - new_reply.xclient.format = 32; - new_reply.xclient.message_type = XdndFinished; - new_reply.xclient.data.l[1] = (long int)result; - new_reply.xclient.data.l[2] = (long int)XdndActionCopy; - XSendEvent(win->src.display, source, False, NoEventMask, &new_reply); - XFlush(win->src.display); - } - break; - } - case FocusIn: - if ((win->_flags & RGFW_windowFullscreen)) - XMapRaised(win->src.display, win->src.window); - - win->_flags |= RGFW_windowFocus; - win->event.type = RGFW_focusIn; - RGFW_focusCallback(win, 1); - - - RGFW_resetKey(); - if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); - break; - case FocusOut: - if ((win->_flags & RGFW_windowFullscreen)) - RGFW_window_minimize(win); - - win->_flags &= ~(u32)RGFW_windowFocus; - win->event.type = RGFW_focusOut; - RGFW_focusCallback(win, 0); - break; - case PropertyNotify: RGFW_window_checkMode(win); break; - case EnterNotify: { - win->event.type = RGFW_mouseEnter; - win->event.point.x = E.xcrossing.x; - win->event.point.y = E.xcrossing.y; - RGFW_mouseNotifyCallback(win, win->event.point, 1); - break; - } - - case LeaveNotify: { - win->event.type = RGFW_mouseLeave; - RGFW_mouseNotifyCallback(win, win->event.point, 0); - break; - } - - case ConfigureNotify: { - /* detect resize */ - RGFW_window_checkMode(win); - if (E.xconfigure.width != win->src.r.w || E.xconfigure.height != win->src.r.h) { - win->event.type = RGFW_windowResized; - win->src.r = win->r = RGFW_RECT(win->src.r.x, win->src.r.y, E.xconfigure.width, E.xconfigure.height); - RGFW_windowResizedCallback(win, win->r); - break; - } - - /* detect move */ - if (E.xconfigure.x != win->src.r.x || E.xconfigure.y != win->src.r.y) { - win->event.type = RGFW_windowMoved; - win->src.r = win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->src.r.w, win->src.r.h); - RGFW_windowMovedCallback(win, win->r); - break; - } - - break; - } - default: - XFlush(win->src.display); - return RGFW_window_checkEvent(win); - } - XFlush(win->src.display); - if (win->event.type) return &win->event; - else return NULL; -#endif -#ifdef RGFW_WAYLAND - wayland: - if ((win->_flags & RGFW_windowHide) == 0) - wl_display_roundtrip(win->src.wl_display); - return NULL; -#endif -} - -void RGFW_window_move(RGFW_window* win, RGFW_point v) { - RGFW_ASSERT(win != NULL); - win->r.x = v.x; - win->r.y = v.y; - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XMoveWindow(win->src.display, win->src.window, v.x, v.y); -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_ASSERT(win != NULL); - - if (win->src.compositor) { - struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat); - if (!pointer) { - return; - } - - wl_display_flush(win->src.wl_display); - } -#endif -} - - -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - win->r.w = (i32)a.w; - win->r.h = (i32)a.h; - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XResizeWindow(win->src.display, win->src.window, a.w, a.h); - - if ((win->_flags & RGFW_windowNoResize)) { - XSizeHints sh; - sh.flags = (1L << 4) | (1L << 5); - sh.min_width = sh.max_width = (i32)a.w; - sh.min_height = sh.max_height = (i32)a.h; - - XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS); - } -#endif -#ifdef RGFW_WAYLAND - wayland: - if (win->src.compositor) { - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); - #ifdef RGFW_OPENGL - wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0); - #endif - } -#endif -} - -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - - if (a.w == 0 && a.h == 0) - return; - - XSizeHints hints; - long flags; - - XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); - - hints.flags |= PAspect; - - hints.min_aspect.x = hints.max_aspect.x = (i32)a.w; - hints.min_aspect.y = hints.max_aspect.y = (i32)a.h; - - XSetWMNormalHints(win->src.display, win->src.window, &hints); -} - -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - - long flags; - XSizeHints hints; - RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); - - XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); - - hints.flags |= PMinSize; - - hints.min_width = (i32)a.w; - hints.min_height = (i32)a.h; - - XSetWMNormalHints(win->src.display, win->src.window, &hints); -} - -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - - long flags; - XSizeHints hints; - RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); - - XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); - - hints.flags |= PMaxSize; - - hints.max_width = (i32)a.w; - hints.max_height = (i32)a.h; - - XSetWMNormalHints(win->src.display, win->src.window, &hints); -} - -void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized); -void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) { - RGFW_ASSERT(win != NULL); - RGFW_LOAD_ATOM(_NET_WM_STATE); - RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); - RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); - - XEvent xev = {0}; - xev.type = ClientMessage; - xev.xclient.window = win->src.window; - xev.xclient.message_type = _NET_WM_STATE; - xev.xclient.format = 32; - xev.xclient.data.l[0] = maximized; - xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ; - xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = 0; - - XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); -} - -void RGFW_window_maximize(RGFW_window* win) { - win->_oldRect = win->r; - RGFW_toggleXMaximized(win, 1); -} - -void RGFW_window_focus(RGFW_window* win) { - RGFW_ASSERT(win); - - XWindowAttributes attr; - XGetWindowAttributes(win->src.display, win->src.window, &attr); - if (attr.map_state != IsViewable) return; - - XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime); - XFlush(win->src.display); -} - -void RGFW_window_raise(RGFW_window* win) { - RGFW_ASSERT(win); - XRaiseWindow(win->src.display, win->src.window); - XMapRaised(win->src.display, win->src.window); -} - -void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen); -void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - RGFW_LOAD_ATOM(_NET_WM_STATE); - - XEvent xev = {0}; - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.message_type = _NET_WM_STATE; - xev.xclient.window = win->src.window; - xev.xclient.format = 32; - xev.xclient.data.l[0] = fullscreen; - xev.xclient.data.l[1] = (long int)netAtom; - xev.xclient.data.l[2] = 0; - - XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); -} - -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - if (fullscreen) { - win->_flags |= RGFW_windowFullscreen; - win->_oldRect = win->r; - } - else win->_flags &= ~(u32)RGFW_windowFullscreen; - - RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); - - RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen); - - XRaiseWindow(win->src.display, win->src.window); - XMapRaised(win->src.display, win->src.window); -} - -void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { - RGFW_ASSERT(win != NULL); - - RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); - RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating); -} - -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - RGFW_ASSERT(win != NULL); - const u32 value = (u32) (0xffffffffu * (double) opacity); - RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY); - XChangeProperty(win->src.display, win->src.window, - NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); -} - -void RGFW_window_minimize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - if (RGFW_window_isMaximized(win)) return; - - win->_oldRect = win->r; - XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display)); - XFlush(win->src.display); -} - -void RGFW_window_restore(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_toggleXMaximized(win, 0); - - win->r = win->_oldRect; - RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); - - RGFW_window_show(win); - XFlush(win->src.display); -} - -RGFW_bool RGFW_window_isFloating(RGFW_window* win) { - RGFW_LOAD_ATOM(_NET_WM_STATE); - RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); - - Atom actual_type; - int actual_format; - unsigned long nitems, bytes_after; - Atom* prop_return = NULL; - - int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, - &actual_type, &actual_format, &nitems, &bytes_after, - (unsigned char **)&prop_return); - - if (status != Success || actual_type != XA_ATOM) - return RGFW_FALSE; - - unsigned long i; - for (i = 0; i < nitems; i++) - if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE; - - if (prop_return) - XFree(prop_return); - - return RGFW_FALSE; -} - -void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); - #ifdef RGFW_X11 - XStoreName(win->src.display, win->src.window, name); - - RGFW_LOAD_ATOM(_NET_WM_NAME); - - char buf[256]; - RGFW_MEMSET(buf, 0, sizeof(buf)); - RGFW_STRNCPY(buf, name, sizeof(buf) - 1); - - XChangeProperty( - win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING, - 8, PropModeReplace, (u8*)buf, sizeof(buf) - ); - #endif - #ifdef RGFW_WAYLAND - wayland: - if (win->src.compositor) - xdg_toplevel_set_title(win->src.xdg_toplevel, name); - #endif -} - -#ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { - RGFW_ASSERT(win != NULL); - if (passthrough) { - Region region = XCreateRegion(); - XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); - XDestroyRegion(region); - - return; - } - - XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); -} -#endif /* RGFW_NO_PASSTHROUGH */ - -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { - RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - RGFW_LOAD_ATOM(_NET_WM_ICON); - if (icon == NULL || (channels != 3 && channels != 4)) { - RGFW_bool res = (RGFW_bool)XChangeProperty( - win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, - PropModeReplace, (u8*)NULL, 0 - ); - return res; - } - - i32 count = (i32)(2 + (a.w * a.h)); - - unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long)); - RGFW_ASSERT(data != NULL); - - data[0] = (unsigned long)a.w; - data[1] = (unsigned long)a.h; - - unsigned long* target = &data[2]; - u32 x, y; - - for (x = 0; x < a.w; x++) { - for (y = 0; y < a.h; y++) { - size_t i = y * a.w + x; - u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF; - - target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) | - (unsigned long)((icon[i * 4 + 1]) << 8) | - (unsigned long)((icon[i * 4 + 2]) << 0) | - (unsigned long)(alpha << 24); - } - } - - RGFW_bool res = RGFW_TRUE; - if (type & RGFW_iconTaskbar) { - res = (RGFW_bool)XChangeProperty( - win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, - PropModeReplace, (u8*)data, count - ); - } - - if (type & RGFW_iconWindow) { - XWMHints wm_hints; - wm_hints.flags = IconPixmapHint; - - i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display)); - XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)), - (u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0); - - wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth); - XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h); - image->data = NULL; - XDestroyImage(image); - - XSetWMHints(win->src.display, win->src.window, &wm_hints); - } - - RGFW_FREE(data); - XFlush(win->src.display); - return RGFW_BOOL(res); -#endif -#ifdef RGFW_WAYLAND - wayland: - return RGFW_FALSE; -#endif -} - -RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { - RGFW_ASSERT(icon); - RGFW_ASSERT(channels == 3 || channels == 4); - RGFW_GOTO_WAYLAND(0); - -#ifdef RGFW_X11 -#ifndef RGFW_NO_X11_CURSOR - RGFW_init(); - XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h); - native->xhot = 0; - native->yhot = 0; - - XcursorPixel* target = native->pixels; - size_t x, y; - for (x = 0; x < a.w; x++) { - for (y = 0; y < a.h; y++) { - size_t i = y * a.w + x; - u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF; - - target[i] = (u32)((icon[i * 4 + 0]) << 16) - | (u32)((icon[i * 4 + 1]) << 8) - | (u32)((icon[i * 4 + 2]) << 0) - | (u32)(alpha << 24); - } - } - - Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native); - XcursorImageDestroy(native); - - return (void*)cursor; -#else - RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels); - return NULL; -#endif -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); - return NULL; /* TODO */ -#endif -} - -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - RGFW_ASSERT(win && mouse); - XDefineCursor(win->src.display, win->src.window, (Cursor)mouse); -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(win); RGFW_UNUSED(mouse); -#endif -} - -void RGFW_freeMouse(RGFW_mouse* mouse) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - RGFW_ASSERT(mouse); - XFreeCursor(_RGFW.display, (Cursor)mouse); -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(mouse); -#endif -} - -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { -RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 - RGFW_ASSERT(win != NULL); - - XEvent event; - XQueryPointer(win->src.display, DefaultRootWindow(win->src.display), - &event.xbutton.root, &event.xbutton.window, - &event.xbutton.x_root, &event.xbutton.y_root, - &event.xbutton.x, &event.xbutton.y, - &event.xbutton.state); - - win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); - if (event.xbutton.x == p.x && event.xbutton.y == p.y) - return; - - XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y); -#endif -#ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(win); RGFW_UNUSED(p); -#endif -} - -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); -} - -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { - RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; - - if (mouse > (sizeof(mouseIconSrc) / sizeof(u8))) - return RGFW_FALSE; - - mouse = mouseIconSrc[mouse]; - - Cursor cursor = XCreateFontCursor(win->src.display, mouse); - XDefineCursor(win->src.display, win->src.window, (Cursor) cursor); - - XFreeCursor(win->src.display, (Cursor) cursor); - return RGFW_TRUE; -#endif -#ifdef RGFW_WAYLAND - wayland: { } - static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" }; - - struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); - RGFW_cursor_image = wlcursor->images[0]; - struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); - - wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); - wl_surface_commit(RGFW_cursor_surface); - return RGFW_TRUE; - -#endif -} - -void RGFW_window_hide(RGFW_window* win) { - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XUnmapWindow(win->src.display, win->src.window); -#endif -#ifdef RGFW_WAYLAND - wayland: - wl_surface_attach(win->src.surface, NULL, 0, 0); - wl_surface_commit(win->src.surface); - win->_flags |= RGFW_windowHide; -#endif -} - -void RGFW_window_show(RGFW_window* win) { - win->_flags &= ~(u32)RGFW_windowHide; - if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XMapWindow(win->src.display, win->src.window); -#endif -#ifdef RGFW_WAYLAND - wayland: - /* wl_surface_attach(win->src.surface, win->rc., 0, 0); */ - wl_surface_commit(win->src.surface); -#endif -} - -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 - RGFW_init(); - if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) { - if (str != NULL) - RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len - 1); - _RGFW.clipboard[_RGFW.clipboard_len - 1] = '\0'; - return (RGFW_ssize_t)_RGFW.clipboard_len - 1; - } - - XEvent event; - int format; - unsigned long N, sizeN; - char* data; - Atom target; - - RGFW_LOAD_ATOM(XSEL_DATA); - - XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime); - XSync(_RGFW.display, 0); - while (1) { - XNextEvent(_RGFW.display, &event); - if (event.type != SelectionNotify) continue; - - if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0) - return -1; - break; - } - - XGetWindowProperty(event.xselection.display, event.xselection.requestor, - event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target, - &format, &sizeN, &N, (u8**) &data); - - RGFW_ssize_t size; - if (sizeN > strCapacity && str != NULL) - size = -1; - - if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) { - RGFW_MEMCPY(str, data, sizeN); - str[sizeN] = '\0'; - XFree(data); - } else if (str != NULL) size = -1; - - XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property); - size = (RGFW_ssize_t)sizeN; - - return size; -#endif -#if defined(RGFW_WAYLAND) -wayland: return 0; -#endif -} - -i32 RGFW_XHandleClipboardSelectionHelper(void) { -#ifdef RGFW_X11 - RGFW_LOAD_ATOM(SAVE_TARGETS); - - XEvent event; - XPending(_RGFW.display); - - if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading)) - XNextEvent(_RGFW.display, &event); - else - return 0; - - switch (event.type) { - case SelectionRequest: - RGFW_XHandleClipboardSelection(&event); - return 0; - case SelectionNotify: - if (event.xselection.target == SAVE_TARGETS) - return 0; - break; - default: break; - } - - return 0; -#else - return 1; -#endif -} - -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 - RGFW_LOAD_ATOM(SAVE_TARGETS); - RGFW_init(); - - /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */ - XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime); - if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection"); - return; - } - - if (_RGFW.clipboard) - RGFW_FREE(_RGFW.clipboard); - - _RGFW.clipboard = (char*)RGFW_ALLOC(textLen); - RGFW_ASSERT(_RGFW.clipboard != NULL); - - RGFW_STRNCPY(_RGFW.clipboard, text, textLen - 1); - _RGFW.clipboard[textLen - 1] = '\0'; - _RGFW.clipboard_len = textLen; - #endif - #ifdef RGFW_WAYLAND - wayland: - RGFW_UNUSED(text); RGFW_UNUSED(textLen); - #endif -} - -RGFW_bool RGFW_window_isHidden(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - XWindowAttributes windowAttributes; - XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); - - return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win)); -} - -RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_LOAD_ATOM(WM_STATE); - - Atom actual_type; - i32 actual_format; - unsigned long nitems, bytes_after; - unsigned char* prop_data; - - i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False, - AnyPropertyType, &actual_type, &actual_format, - &nitems, &bytes_after, &prop_data); - - if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) { - XFree(prop_data); - return RGFW_TRUE; - } - - if (prop_data != NULL) - XFree(prop_data); - - XWindowAttributes windowAttributes; - XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); - return windowAttributes.map_state != IsViewable; -} - -RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_LOAD_ATOM(_NET_WM_STATE); - RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); - RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); - - Atom actual_type; - i32 actual_format; - unsigned long nitems, bytes_after; - unsigned char* prop_data; - - i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False, - XA_ATOM, &actual_type, &actual_format, - &nitems, &bytes_after, &prop_data); - - if (status != Success) { - if (prop_data != NULL) - XFree(prop_data); - - return RGFW_FALSE; - } - - u64 i; - for (i = 0; i < nitems; ++i) { - if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT || - prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) { - XFree(prop_data); - return RGFW_TRUE; - } - } - - if (prop_data != NULL) - XFree(prop_data); - - return RGFW_FALSE; -} - -#ifndef RGFW_NO_DPI -u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi); -u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) { - if (mi.hTotal == 0 || mi.vTotal == 0) return 0; - return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal)); -} -#endif - - -static float XGetSystemContentDPI(Display* display, i32 screen) { - float dpi = 96.0f; - - #ifndef RGFW_NO_DPI - RGFW_UNUSED(screen); - char* rms = XResourceManagerString(display); - XrmDatabase db = NULL; - if (rms) db = XrmGetStringDatabase(rms); - - if (rms && db) { - XrmValue value; - char* type = NULL; - - if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0) - dpi = (float)RGFW_ATOF(value.addr); - XrmDestroyDatabase(db); - } - #else - dpi = RGFW_ROUND(DisplayWidth(display, screen) / (DisplayWidthMM(display, screen) / 25.4)); - #endif - - return dpi; -} - -RGFW_monitor RGFW_XCreateMonitor(i32 screen); -RGFW_monitor RGFW_XCreateMonitor(i32 screen) { - RGFW_monitor monitor; - RGFW_init(); - Display* display = _RGFW.display; - - if (screen == -1) screen = DefaultScreen(display); - - Screen* scrn = DefaultScreenOfDisplay(display); - RGFW_area size = RGFW_AREA(scrn->width, scrn->height); - - monitor.x = 0; - monitor.y = 0; - monitor.mode.area = RGFW_AREA(size.w, size.h); - monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f; - monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f; - - RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode); - - char* name = XDisplayName((const char*)display); - RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1); - monitor.name[sizeof(monitor.name) - 1] = '\0'; - - float dpi = XGetSystemContentDPI(display, screen); - monitor.pixelRatio = dpi >= 192.0f ? 2 : 1; - monitor.scaleX = (float) (dpi) / 96.0f; - monitor.scaleY = (float) (dpi) / 96.0f; - - #ifndef RGFW_NO_DPI - XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); - monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]); - - XRRCrtcInfo* ci = NULL; - int crtc = screen; - - if (sr->ncrtc > crtc) { - ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]); - } - #endif - - #ifndef RGFW_NO_DPI - XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]); - - if (info == NULL || ci == NULL) { - XRRFreeScreenResources(sr); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); - return monitor; - } - - - float physW = (float)info->mm_width / 25.4f; - float physH = (float)info->mm_height / 25.4f; - - RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1); - monitor.name[sizeof(monitor.name) - 1] = '\0'; - - if ((u8)physW && (u8)physH) { - monitor.physW = physW; - monitor.physH = physH; - } - - monitor.x = ci->x; - monitor.y = ci->y; - - if (ci->width && ci->height) { - monitor.mode.area.w = (u32)ci->width; - monitor.mode.area.h = (u32)ci->height; - } - #endif - - #ifndef RGFW_NO_DPI - XRRFreeCrtcInfo(ci); - XRRFreeScreenResources(sr); - #endif - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); - return monitor; -} - -RGFW_monitor* RGFW_getMonitors(size_t* len) { - static RGFW_monitor monitors[7]; - - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 - RGFW_init(); - - Display* display = _RGFW.display; - i32 max = ScreenCount(display); - - i32 i; - for (i = 0; i < max && i < 6; i++) - monitors[i] = RGFW_XCreateMonitor(i); - - if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6)); - - return monitors; - #endif - #ifdef RGFW_WAYLAND - wayland: return monitors; /* TODO WAYLAND */ - #endif -} - -RGFW_monitor RGFW_getPrimaryMonitor(void) { - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 - return RGFW_XCreateMonitor(-1); - #endif - #ifdef RGFW_WAYLAND - wayland: return (RGFW_monitor){ 0 }; /* TODO WAYLAND */ - #endif -} - -RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 - #ifndef RGFW_NO_DPI - RGFW_init(); - XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display)); - if (screenRes == NULL) return RGFW_FALSE; - - int i; - for (i = 0; i < screenRes->ncrtc; i++) { - XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]); - if (!crtcInfo) continue; - - if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) { - RRMode rmode = None; - int index; - for (index = 0; index < screenRes->nmode; index++) { - RGFW_monitorMode foundMode; - foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height); - foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]); - RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode); - - if (RGFW_monitorModeCompare(mode, foundMode, request)) { - rmode = screenRes->modes[index].id; - - RROutput output = screenRes->outputs[i]; - XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output); - if (info) { - XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i], - CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1); - XRRFreeOutputInfo(info); - XRRFreeCrtcInfo(crtcInfo); - XRRFreeScreenResources(screenRes); - return RGFW_TRUE; - } - } - } - - XRRFreeCrtcInfo(crtcInfo); - XRRFreeScreenResources(screenRes); - return RGFW_FALSE; - } - - XRRFreeCrtcInfo(crtcInfo); - } - - XRRFreeScreenResources(screenRes); - return RGFW_FALSE; - #endif -#endif -#ifdef RGFW_WAYLAND -wayland: -#endif - return RGFW_FALSE; -} - -RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { - RGFW_monitor mon; - RGFW_MEMSET(&mon, 0, sizeof(mon)); - - RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 - XWindowAttributes attrs; - if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) { - return mon; - } - - i32 i; - for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) { - Screen* screen = ScreenOfDisplay(win->src.display, i); - if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) && - attrs.y >= 0 && attrs.y < XHeightOfScreen(screen)) - return RGFW_XCreateMonitor(i); - } -#endif -#ifdef RGFW_WAYLAND -wayland: -#endif - return mon; - -} - -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - if (win == NULL) - glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL); - else - glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); -} -void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); } -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); } -#endif - -void RGFW_window_swapBuffers_software(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - #ifdef RGFW_X11 - win->src.bitmap->data = (char*) win->buffer; - RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data); - XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h); - win->src.bitmap->data = NULL; - return; - #endif - #ifdef RGFW_WAYLAND - wayland: - #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA) - RGFW_RGB_to_BGR(win, win->src.buffer); - #else - size_t y; - for (y = 0; y < win->r.h; y++) { - u32 index = (y * 4 * win->r.w); - u32 index2 = (y * 4 * win->bufferSize.w); - RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4); - } - #endif - - wl_surface_frame_done(win, NULL, 0); - wl_surface_commit(win->src.surface); - #endif -#else -#ifdef RGFW_WAYLAND - wayland: -#endif - RGFW_UNUSED(win); -#endif -} - -#if !defined(RGFW_EGL) - -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL); - - #if defined(RGFW_OPENGL) - // cached pfn to avoid calling glXGetProcAddress more than once - static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123; - static int (*pfn2)(int) = NULL; - - if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) { - pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT")); - if (pfn == NULL) { - const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"}; - u32 i; - for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) - pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i])); - - if (pfn2 != NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function"); - } else { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function"); - } - } - } - if (pfn != NULL) - pfn(win->src.display, win->src.window, swapInterval); - else if (pfn2 != NULL) { - pfn2(swapInterval); - } - #else - RGFW_UNUSED(swapInterval); - #endif -} -#endif - -void RGFW_deinit(void) { - if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) return; - #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL; -#ifdef RGFW_X11 - /* to save the clipboard on the x server after the window is closed */ - RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); - RGFW_LOAD_ATOM(SAVE_TARGETS); - if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) { - XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime); - while (RGFW_XHandleClipboardSelectionHelper()); - } - if (_RGFW.clipboard) { - RGFW_FREE(_RGFW.clipboard); - _RGFW.clipboard = NULL; - } - - RGFW_freeMouse(_RGFW.hiddenMouse); - XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */ - - #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) - RGFW_FREE_LIBRARY(X11Cursorhandle); - #endif - #if !defined(RGFW_NO_X11_XI_PRELOAD) - RGFW_FREE_LIBRARY(X11Xihandle); - #endif - - #ifdef RGFW_USE_XDL - XDL_close(); - #endif - - #if !defined(RGFW_NO_X11_EXT_PRELOAD) - RGFW_FREE_LIBRARY(X11XEXThandle); - #endif -#endif -#ifdef RGFW_WAYLAND - wl_display_disconnect(_RGFW.wl_display); -#endif - #ifndef RGFW_NO_LINUX - if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){ - close(RGFW_eventWait_forceStop[0]); - close(RGFW_eventWait_forceStop[1]); - } - - u8 i; - for (i = 0; i < RGFW_gamepadCount; i++) { - if(RGFW_gamepads[i]) - close(RGFW_gamepads[i]); - } - #endif - - _RGFW.root = NULL; - _RGFW.windowCount = -1; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); -} - -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); - - #ifdef RGFW_X11 - RGFW_GOTO_WAYLAND(0); - - /* ungrab pointer if it was grabbed */ - if (win->_flags & RGFW_HOLD_MOUSE) - XUngrabPointer(win->src.display, CurrentTime); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (win->buffer != NULL) { - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - XDestroyImage((XImage*) win->src.bitmap); - } - #endif - - XFreeGC(win->src.display, win->src.gc); - XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */ - win->src.window = 0; - XCloseDisplay(win->src.display); - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } - return; - #endif - - #ifdef RGFW_WAYLAND - wayland: - - #ifdef RGFW_X11 - XDestroyWindow(win->src.display, (Drawable) win->src.window); - #endif - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - xdg_toplevel_destroy(win->src.xdg_toplevel); - xdg_surface_destroy(win->src.xdg_surface); - wl_surface_destroy(win->src.surface); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - wl_buffer_destroy(win->src.wl_buffer); - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - - munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4)); - #endif - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } - #endif -} - - -/* - End of X11 linux / wayland / unix defines -*/ - -#include -#include -#include - -void RGFW_stopCheckEvents(void) { - - RGFW_eventWait_forceStop[2] = 1; - while (1) { - const char byte = 0; - const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1); - if (result == 1 || result == -1) - break; - } -} - -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - if (waitMS == 0) return; - - u8 i; - if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) { - if (pipe(RGFW_eventWait_forceStop) != -1) { - fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0); - fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0); - fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0); - fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0); - } - } - - struct pollfd fds[] = { - #ifdef RGFW_WAYLAND - { wl_display_get_fd(win->src.wl_display), POLLIN, 0 }, - #else - { ConnectionNumber(win->src.display), POLLIN, 0 }, - #endif - #ifdef RGFW_X11 - { ConnectionNumber(_RGFW.display), POLLIN, 0 }, - #endif - { RGFW_eventWait_forceStop[0], POLLIN, 0 }, - #if defined(__linux__) - { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0} - #endif - }; - - u8 index = 2; -#ifdef RGFW_X11 - index++; -#endif - - #if defined(__linux__) || defined(__NetBSD__) - for (i = 0; i < RGFW_gamepadCount; i++) { - if (RGFW_gamepads[i] == 0) - continue; - - fds[index].fd = RGFW_gamepads[i]; - index++; - } - #endif - - - u64 start = RGFW_getTimeNS(); - - - #ifdef RGFW_WAYLAND - while (wl_display_dispatch(win->src.wl_display) <= 0 - #else - while (XPending(win->src.display) == 0 - #endif - #ifdef RGFW_X11 - && XPending(_RGFW.display) == 0 - #endif - ) { - if (poll(fds, index, waitMS) <= 0) - break; - - if (waitMS != RGFW_eventWaitNext) - waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6; - } - - /* drain any data in the stop request */ - if (RGFW_eventWait_forceStop[2]) { - char data[64]; - (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data)); - - RGFW_eventWait_forceStop[2] = 0; - } -} - -i32 RGFW_getClock(void); -i32 RGFW_getClock(void) { - static i32 clock = -1; - if (clock != -1) return clock; - - #if defined(_POSIX_MONOTONIC_CLOCK) - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - clock = CLOCK_MONOTONIC; - #else - clock = CLOCK_REALTIME; - #endif - - return clock; -} - -u64 RGFW_getTimerFreq(void) { return 1000000000LLU; } -u64 RGFW_getTimerValue(void) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec; -} -#endif /* end of wayland or X11 defines */ - - - -/* - - Start of Windows defines - - -*/ - -#ifdef RGFW_WINDOWS -#define WIN32_LEAN_AND_MEAN -#define OEMRESOURCE -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifndef WM_DPICHANGED -#define WM_DPICHANGED 0x02E0 -#endif - -#ifndef RGFW_NO_XINPUT - typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); - PFN_XInputGetState XInputGetStateSRC = NULL; - #define XInputGetState XInputGetStateSRC - - typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); - PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL; - #define XInputGetKeystroke XInputGetKeystrokeSRC - - HMODULE RGFW_XInput_dll = NULL; -#endif - -char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source); - -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 - -typedef int (*PFN_wglGetSwapIntervalEXT)(void); -PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL; -#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc - - -void* RGFWgamepadApi = NULL; - -/* these two wgl functions need to be preloaded */ -typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList); -PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; - -#ifndef RGFW_EGL - HMODULE RGFW_wgl_dll = NULL; -#endif - -#ifndef RGFW_NO_LOAD_WGL - typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC); - typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC); - typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR); - typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC); - typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void); - typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void); - typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC); - - PFN_wglCreateContext wglCreateContextSRC; - PFN_wglDeleteContext wglDeleteContextSRC; - PFN_wglGetProcAddress wglGetProcAddressSRC; - PFN_wglMakeCurrent wglMakeCurrentSRC; - PFN_wglGetCurrentDC wglGetCurrentDCSRC; - PFN_wglGetCurrentContext wglGetCurrentContextSRC; - PFN_wglShareLists wglShareListsSRC; - - #define wglCreateContext wglCreateContextSRC - #define wglDeleteContext wglDeleteContextSRC - #define wglGetProcAddress wglGetProcAddressSRC - #define wglMakeCurrent wglMakeCurrentSRC - #define wglGetCurrentDC wglGetCurrentDCSRC - #define wglGetCurrentContext wglGetCurrentContextSRC - #define wglShareLists wglShareListsSRC -#endif - -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) -RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { - const char* extensions = NULL; - - RGFW_proc proc = RGFW_getProcAddress("wglGetExtensionsStringARB"); - RGFW_proc proc2 = RGFW_getProcAddress("wglGetExtensionsStringEXT"); - - if (proc) - extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC()); - else if (proc2) - extensions = ((const char*(*)(void))proc2)(); - - return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); -} - -RGFW_proc RGFW_getProcAddress(const char* procname) { - RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname); - if (proc) - return proc; - - return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); -} - -typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); -PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; - -typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval); -PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; -#endif - -#ifndef RGFW_NO_DWM -HMODULE RGFW_dwm_dll = NULL; -typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND; -typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*); -PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL; -#endif -void RGFW_win32_makeWindowTransparent(RGFW_window* win); -void RGFW_win32_makeWindowTransparent(RGFW_window* win) { - if (!(win->_flags & RGFW_windowTransparent)) return; - - #ifndef RGFW_NO_DWM - if (DwmEnableBlurBehindWindowSRC != NULL) { - DWM_BLURBEHIND bb = {0, 0, 0, 0}; - bb.dwFlags = 0x1; - bb.fEnable = TRUE; - bb.hRgnBlur = NULL; - DwmEnableBlurBehindWindowSRC(win->src.window, &bb); - - } else - #endif - { - SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); - SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA); - } -} - -LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW"); - if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam); - - RECT windowRect; - GetWindowRect(hWnd, &windowRect); - - switch (message) { - case WM_CLOSE: - case WM_QUIT: - RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); - RGFW_windowQuitCallback(win); - return 0; - case WM_ACTIVATE: { - RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE); - if (inFocus) win->_flags |= RGFW_windowFocus; - else win->_flags &= ~ (u32)RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e._win = win); - - RGFW_focusCallback(win, inFocus); - - if ((win->_flags & RGFW_windowFullscreen) == 0) - return DefWindowProcW(hWnd, message, wParam, lParam); - - win->_flags &= ~(u32)RGFW_EVENT_PASSED; - if (inFocus == RGFW_FALSE) RGFW_window_minimize(win); - else RGFW_window_setFullscreen(win, 1); - return DefWindowProcW(hWnd, message, wParam, lParam); - } - case WM_MOVE: - win->r.x = windowRect.left; - win->r.y = windowRect.top; - RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win); - RGFW_windowMovedCallback(win, win->r); - return DefWindowProcW(hWnd, message, wParam, lParam); - case WM_SIZE: { - if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) { - double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h; - - int width = windowRect.right - windowRect.left; - int height = windowRect.bottom - windowRect.top; - int newHeight = (int)(width / aspectRatio); - int newWidth = (int)(height * aspectRatio); - - if (win->r.w > windowRect.right - windowRect.left || - win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset)) - { - if (newHeight > height) windowRect.right = windowRect.left + newWidth; - else windowRect.bottom = windowRect.top + newHeight; - } else { - if (newHeight < height) windowRect.right = windowRect.left + newWidth; - else windowRect.bottom = windowRect.top + newHeight; - } - - RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left), - (u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset)); - } - - win->r.w = windowRect.right - windowRect.left; - win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win); - RGFW_windowResizedCallback(win, win->r); - RGFW_window_checkMode(win); - return DefWindowProcW(hWnd, message, wParam, lParam); - } - #ifndef RGFW_NO_MONITOR - case WM_DPICHANGED: { - if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); - - const float scaleX = HIWORD(wParam) / (float) 96; - const float scaleY = LOWORD(wParam) / (float) 96; - RGFW_scaleUpdatedCallback(win, scaleX, scaleY); - RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = scaleX; e.scaleY = scaleY; e._win = win); - return DefWindowProcW(hWnd, message, wParam, lParam); - } - #endif - case WM_GETMINMAXINFO: { - MINMAXINFO* mmi = (MINMAXINFO*) lParam; - mmi->ptMinTrackSize.x = (LONG)win->src.minSize.w; - mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset); - if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) - return DefWindowProcW(hWnd, message, wParam, lParam); - - mmi->ptMaxTrackSize.x = (LONG)win->src.maxSize.w; - mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset); - return DefWindowProcW(hWnd, message, wParam, lParam); - } - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win); - RGFW_windowRefreshCallback(win); - EndPaint(hWnd, &ps); - - return DefWindowProcW(hWnd, message, wParam, lParam); - } - #if(_WIN32_WINNT >= 0x0600) - case WM_DWMCOMPOSITIONCHANGED: - case WM_DWMCOLORIZATIONCOLORCHANGED: - RGFW_win32_makeWindowTransparent(win); - break; - #endif -/* based on sokol_app.h */ -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break; - case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break; - case WM_TIMER: RGFW_windowRefreshCallback(win); break; -#endif - case WM_NCLBUTTONDOWN: { - /* workaround for half-second pause when starting to move window - see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/ - */ - POINT point = { 0, 0 }; - if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE) - break; - - ScreenToClient(win->src.window, &point); - PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16)); - break; - } - default: break; - } - return DefWindowProcW(hWnd, message, wParam, lParam); -} - -#ifndef RGFW_NO_DPI - HMODULE RGFW_Shcore_dll = NULL; - typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); - PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL; - #define GetDpiForMonitor GetDpiForMonitorSRC -#endif - -#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM) - HMODULE RGFW_winmm_dll = NULL; - typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32); - typedef PFN_timeBeginPeriod PFN_timeEndPeriod; - PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC; - #define timeBeginPeriod timeBeginPeriodSRC - #define timeEndPeriod timeEndPeriodSRC -#elif !defined(RGFW_NO_WINMM) - __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod); - __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod); -#endif -#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ - name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \ - RGFW_ASSERT(name##SRC != NULL); \ - } - -#ifndef RGFW_NO_XINPUT -void RGFW_loadXInput(void); -void RGFW_loadXInput(void) { - u32 i; - static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"}; - - for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL); i++) { - RGFW_XInput_dll = LoadLibraryA(names[i]); - RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState); - RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke); - } - - if (XInputGetStateSRC == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetState"); - if (XInputGetKeystrokeSRC == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetKeystroke"); -} -#endif - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = buffer; - win->bufferSize = area; - - BITMAPV5HEADER bi; - ZeroMemory(&bi, sizeof(bi)); - bi.bV5Size = sizeof(bi); - bi.bV5Width = (i32)area.w; - bi.bV5Height = -((LONG) area.h); - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_RGB; - - win->src.bitmap = CreateDIBSection(win->src.hdc, - (BITMAPINFO*) &bi, DIB_RGB_COLORS, - (void**) &win->src.bitmapBits, - NULL, (DWORD) 0); - - if (win->buffer == NULL) - win->buffer = win->src.bitmapBits; - - win->src.hdcMem = CreateCompatibleDC(win->src.hdc); - SelectObject(win->src.hdcMem, win->src.bitmap); - - #if defined(RGFW_OSMESA) - win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #else - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ - #endif -} - -void RGFW_releaseCursor(RGFW_window* win) { - RGFW_UNUSED(win); - ClipCursor(NULL); - const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL }; - RegisterRawInputDevices(&id, 1, sizeof(id)); -} - -void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { - RGFW_UNUSED(win); RGFW_UNUSED(rect); - - RECT clipRect; - GetClientRect(win->src.window, &clipRect); - ClientToScreen(win->src.window, (POINT*) &clipRect.left); - ClientToScreen(win->src.window, (POINT*) &clipRect.right); - ClipCursor(&clipRect); - - const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window }; - RegisterRawInputDevices(&id, 1, sizeof(id)); -} - -#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); } - -#ifdef RGFW_DIRECTX -int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { - RGFW_ASSERT(win && pFactory && pDevice && swapchain); - - static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; - swapChainDesc.BufferCount = 2; - swapChainDesc.BufferDesc.Width = win->r.w; - swapChainDesc.BufferDesc.Height = win->r.h; - swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.OutputWindow = (HWND)win->src.window; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.Windowed = TRUE; - swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - - HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain); - if (FAILED(hr)) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(win, hr), "Failed to create DirectX swap chain!"); - return -2; - } - - return 0; -} -#endif - -void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); -void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) { -#ifdef RGFW_OPENGL - if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL) - return; - - HDC dummy_dc = GetDC(dummyWin); - u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - - PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; - - int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd); - SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd); - - HGLRC dummy_context = wglCreateContext(dummy_dc); - wglMakeCurrent(dummy_dc, dummy_context); - - wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB"); - wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB"); - - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapIntervalEXT == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function"); - } - - wglMakeCurrent(dummy_dc, 0); - wglDeleteContext(dummy_context); - ReleaseDC(dummyWin, dummy_dc); -#else - RGFW_UNUSED(dummyWin); -#endif -} - -#ifndef RGFW_EGL -void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) { -#ifdef RGFW_OPENGL - PIXELFORMATDESCRIPTOR pfd; - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.iLayerType = PFD_MAIN_PLANE; - pfd.cColorBits = 32; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil]; - pfd.cAuxBuffers = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers]; - if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO; - - /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */ - if (software) - pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; - - /* get pixel format, default to a basic pixel format */ - int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); - if (wglChoosePixelFormatARB != NULL) { - i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(software); - - int new_pixel_format; - UINT num_formats; - wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); - if (!num_formats) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL"); - else pixel_format = new_pixel_format; - } - - PIXELFORMATDESCRIPTOR suggested; - if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || - !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format"); - - if (wglCreateContextAttribsARB != NULL) { - /* create opengl/WGL context for the specified version */ - u32 index = 0; - i32 attribs[40]; - - if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) { - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB); - } - else { - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); - } - - if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { - SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]); - SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]); - } - - SET_ATTRIB(0, 0); - - win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); - } else { /* fall back to a default context (probably opengl 2 or something) */ - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context"); - win->src.ctx = wglCreateContext(win->src.hdc); - } - - ReleaseDC(win->src.window, win->src.hdc); - win->src.hdc = GetDC(win->src.window); - wglMakeCurrent(win->src.hdc, win->src.ctx); - - if (_RGFW.root != win) - wglShareLists(_RGFW.root->src.ctx, win->src.ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); -#else - RGFW_UNUSED(win); RGFW_UNUSED(software); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - if (win->src.ctx == NULL) return; - wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */ - win->src.ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#else - RGFW_UNUSED(win); -#endif -} -#endif - - -i32 RGFW_init(void) { -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - - #ifndef RGFW_NO_XINPUT - if (RGFW_XInput_dll == NULL) - RGFW_loadXInput(); - #endif - -#ifndef RGFW_NO_DPI - #if (_WIN32_WINNT >= 0x0600) - SetProcessDPIAware(); - #endif -#endif - - #ifndef RGFW_NO_WINMM - #ifndef RGFW_NO_LOAD_WINMM - RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll"); - RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod); - RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod); - #endif - timeBeginPeriod(1); - #endif - - #ifndef RGFW_NO_DWM - RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll"); - RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow); - #endif - - RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll"); - #ifndef RGFW_NO_LOAD_WGL - RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext); - RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext); - RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress); - RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent); - RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC); - RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext); - RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists); - #endif - - u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4); - - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 1; -} - -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - if (name[0] == 0) name = (char*) " "; - - RGFW_window_basic_init(win, rect, flags); - - win->src.hIconSmall = win->src.hIconBig = NULL; - win->src.maxSize = RGFW_AREA(0, 0); - win->src.minSize = RGFW_AREA(0, 0); - win->src.aspectRatio = RGFW_AREA(0, 0); - - HINSTANCE inh = GetModuleHandleA(NULL); - - #ifndef __cplusplus - WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */ - #else - WNDCLASSW Class = { }; - #endif - - if (RGFW_className == NULL) - RGFW_className = (char*)name; - - wchar_t wide_class[256]; - MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255); - - Class.lpszClassName = wide_class; - Class.hInstance = inh; - Class.hCursor = LoadCursor(NULL, IDC_ARROW); - Class.lpfnWndProc = WndProcW; - Class.cbClsExtra = sizeof(RGFW_window*); - - Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); - if (Class.hIcon == NULL) - Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); - - RegisterClassW(&Class); - - DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - - RECT windowRect, clientRect; - - if (!(flags & RGFW_windowNoBorder)) { - window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME; - - if (!(flags & RGFW_windowNoResize)) - window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX; - } else - window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU; - - wchar_t wide_name[256]; - MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255); - HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0); - - GetWindowRect(dummyWin, &windowRect); - GetClientRect(dummyWin, &clientRect); - - RGFW_win32_loadOpenGLFuncs(dummyWin); - DestroyWindow(dummyWin); - - win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top); - win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0); - SetPropW(win->src.window, L"RGFW", win); - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */ - - if (flags & RGFW_windowAllowDND) { - win->_flags |= RGFW_windowAllowDND; - RGFW_window_setDND(win, 1); - } - win->src.hdc = GetDC(win->src.window); - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware)); - RGFW_window_initBuffer(win); - } - - RGFW_window_setFlags(win, flags); - RGFW_win32_makeWindowTransparent(win); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - RGFW_window_show(win); - - return win; -} - -void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); - LONG style = GetWindowLong(win->src.window, GWL_STYLE); - - - if (border == 0) { - SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); - SetWindowPos( - win->src.window, HWND_TOP, 0, 0, 0, 0, - SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE - ); - } - else { - style |= WS_OVERLAPPEDWINDOW; - if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX; - SetWindowPos( - win->src.window, HWND_TOP, 0, 0, 0, 0, - SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE - ); - } -} - -void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { - RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); - DragAcceptFiles(win->src.window, allow); -} - -RGFW_area RGFW_getScreenSize(void) { - HDC dc = GetDC(NULL); - RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES)); - ReleaseDC(NULL, dc); - return area; -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - POINT p; - GetCursorPos(&p); - - return RGFW_POINT(p.x, p.y); -} - -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - win->src.aspectRatio = a; -} - -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - win->src.minSize = a; -} - -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - win->src.maxSize = a; -} - -void RGFW_window_focus(RGFW_window* win) { - RGFW_ASSERT(win); - SetForegroundWindow(win->src.window); - SetFocus(win->src.window); -} - -void RGFW_window_raise(RGFW_window* win) { - RGFW_ASSERT(win); - BringWindowToTop(win->src.window); - SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); -} - -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - - if (fullscreen == RGFW_FALSE) { - RGFW_window_setBorder(win, 1); - SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + (i32)win->src.hOffset, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - win->_flags &= ~(u32)RGFW_windowFullscreen; - win->r = win->_oldRect; - return; - } - - win->_oldRect = win->r; - win->_flags |= RGFW_windowFullscreen; - - RGFW_monitor mon = RGFW_window_getMonitor(win); - RGFW_window_setBorder(win, 0); - - SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW); - RGFW_monitor_scaleToWindow(mon, win); - - win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h); -} - -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_window_hide(win); - ShowWindow(win->src.window, SW_MAXIMIZE); -} - -void RGFW_window_minimize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - ShowWindow(win->src.window, SW_MINIMIZE); -} - -void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { - RGFW_ASSERT(win != NULL); - if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); -} - -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED); - SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA); -} - -void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); } - -RGFW_bool RGFW_window_isFloating(RGFW_window* win) { - return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; -} - -u8 RGFW_xinput2RGFW[] = { - RGFW_gamepadA, /* or PS X button */ - RGFW_gamepadB, /* or PS circle button */ - RGFW_gamepadX, /* or PS square button */ - RGFW_gamepadY, /* or PS triangle button */ - RGFW_gamepadR1, /* right bumper */ - RGFW_gamepadL1, /* left bump */ - RGFW_gamepadL2, /* left trigger */ - RGFW_gamepadR2, /* right trigger */ - 0, 0, 0, 0, 0, 0, 0, 0, - RGFW_gamepadUp, /* dpad up */ - RGFW_gamepadDown, /* dpad down */ - RGFW_gamepadLeft, /* dpad left */ - RGFW_gamepadRight, /* dpad right */ - RGFW_gamepadStart, /* start button */ - RGFW_gamepadSelect,/* select button */ - RGFW_gamepadL3, - RGFW_gamepadR3, -}; -i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e); -i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) { - #ifndef RGFW_NO_XINPUT - - RGFW_UNUSED(win); - u16 i; - for (i = 0; i < 4; i++) { - XINPUT_KEYSTROKE keystroke; - - if (XInputGetKeystroke == NULL) - return 0; - - DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke); - - if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) { - if (result != ERROR_SUCCESS) - return 0; - - if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS) - continue; - - /* gamepad + 1 = RGFW_gamepadButtonReleased */ - e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); - e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800]; - RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current; - RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); - - RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed); - return 1; - } - - XINPUT_STATE state; - if (XInputGetState == NULL || - XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED - ) { - if (RGFW_gamepads[i] == 0) - continue; - - RGFW_gamepads[i] = 0; - RGFW_gamepadCount--; - - win->event.type = RGFW_gamepadDisconnected; - win->event.gamepad = (u16)i; - RGFW_gamepadCallback(win, i, 0); - return 1; - } - - if (RGFW_gamepads[i] == 0) { - RGFW_gamepads[i] = 1; - RGFW_gamepadCount++; - - char str[] = "Microsoft X-Box (XInput device)"; - RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str)); - RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0'; - win->event.type = RGFW_gamepadConnected; - win->event.gamepad = i; - RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; - - RGFW_gamepadCallback(win, i, 1); - return 1; - } - -#define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) /* Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. */ - - if ((state.Gamepad.sThumbLX < INPUT_DEADZONE && - state.Gamepad.sThumbLX > -INPUT_DEADZONE) && - (state.Gamepad.sThumbLY < INPUT_DEADZONE && - state.Gamepad.sThumbLY > -INPUT_DEADZONE)) - { - state.Gamepad.sThumbLX = 0; - state.Gamepad.sThumbLY = 0; - } - - if ((state.Gamepad.sThumbRX < INPUT_DEADZONE && - state.Gamepad.sThumbRX > -INPUT_DEADZONE) && - (state.Gamepad.sThumbRY < INPUT_DEADZONE && - state.Gamepad.sThumbRY > -INPUT_DEADZONE)) - { - state.Gamepad.sThumbRX = 0; - state.Gamepad.sThumbRY = 0; - } - - e->axisesCount = 2; - RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100); - RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100); - - if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){ - win->event.whichAxis = 0; - - e->type = RGFW_gamepadAxisMove; - e->axis[0] = axis1; - RGFW_gamepadAxes[i][0] = e->axis[0]; - - RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis); - return 1; - } - - if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) { - win->event.whichAxis = 1; - e->type = RGFW_gamepadAxisMove; - e->axis[1] = axis2; - RGFW_gamepadAxes[i][1] = e->axis[1]; - - RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis); - return 1; - } - } - - #endif - - return 0; -} - -void RGFW_stopCheckEvents(void) { - PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0); -} - -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); - MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT); -} - -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) return ev; - - static HDROP drop; - if (win->event.type == RGFW_DNDInit) { - if (win->event.droppedFilesCount) { - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - } - - win->event.droppedFilesCount = 0; - win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0); - - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) { - UINT length = DragQueryFileW(drop, i, NULL, 0); - if (length == 0) - continue; - - WCHAR buffer[RGFW_MAX_PATH * 2]; - if (length > (RGFW_MAX_PATH * 2) - 1) - length = RGFW_MAX_PATH * 2; - - DragQueryFileW(drop, i, buffer, length + 1); - - char* str = RGFW_createUTF8FromWideStringWin32(buffer); - if (str != NULL) - RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1); - - win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; - } - - DragFinish(drop); - RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); - - win->event.type = RGFW_DND; - return &win->event; - } - - if (RGFW_checkXInput(win, &win->event)) - return &win->event; - - static BYTE keyboardState[256]; - GetKeyboardState(keyboardState); - - MSG msg; - if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { - if (msg.hwnd != win->src.window && msg.hwnd != NULL) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - return RGFW_window_checkEvent(win); - } - } else { - return NULL; - } - - switch (msg.message) { - case WM_MOUSELEAVE: - win->event.type = RGFW_mouseLeave; - win->_flags |= RGFW_MOUSE_LEFT; - RGFW_mouseNotifyCallback(win, win->event.point, 0); - break; - case WM_SYSKEYUP: case WM_KEYUP: { - i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); - if (scancode == 0) - scancode = (i32)MapVirtualKeyW((UINT)msg.wParam, MAPVK_VK_TO_VSC); - - switch (scancode) { - case 0x54: scancode = 0x137; break; /* Alt+PrtS */ - case 0x146: scancode = 0x45; break; /* Ctrl+Pause */ - case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */ - default: break; - } - - win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode); - - if (msg.wParam == VK_CONTROL) { - if (HIWORD(msg.lParam) & KF_EXTENDED) - win->event.key = RGFW_controlR; - else win->event.key = RGFW_controlL; - } - - wchar_t charBuffer; - ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL); - - win->event.keyChar = (u8)charBuffer; - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - win->event.type = RGFW_keyReleased; - RGFW_keyboard[win->event.key].current = 0; - - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); - break; - } - case WM_SYSKEYDOWN: case WM_KEYDOWN: { - i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); - if (scancode == 0) - scancode = (i32)MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC); - - switch (scancode) { - case 0x54: scancode = 0x137; break; /* Alt+PrtS */ - case 0x146: scancode = 0x45; break; /* Ctrl+Pause */ - case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */ - default: break; - } - - win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode); - if (msg.wParam == VK_CONTROL) { - if (HIWORD(msg.lParam) & KF_EXTENDED) - win->event.key = RGFW_controlR; - else win->event.key = RGFW_controlL; - } - - wchar_t charBuffer; - ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL); - win->event.keyChar = (u8)charBuffer; - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - win->event.type = RGFW_keyPressed; - win->event.repeat = RGFW_isPressed(win, win->event.key); - RGFW_keyboard[win->event.key].current = 1; - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); - break; - } - case WM_MOUSEMOVE: { - if ((win->_flags & RGFW_HOLD_MOUSE)) - break; - - win->event.type = RGFW_mousePosChanged; - - i32 x = GET_X_LPARAM(msg.lParam); - i32 y = GET_Y_LPARAM(msg.lParam); - - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - - if (win->_flags & RGFW_MOUSE_LEFT) { - win->_flags &= ~(u32)RGFW_MOUSE_LEFT; - win->event.type = RGFW_mouseEnter; - RGFW_mouseNotifyCallback(win, win->event.point, 1); - } - - win->event.point.x = x; - win->event.point.y = y; - win->_lastMousePoint = RGFW_POINT(x, y); - - break; - } - case WM_INPUT: { - if (!(win->_flags & RGFW_HOLD_MOUSE)) - break; - - unsigned size = sizeof(RAWINPUT); - static RAWINPUT raw; - - GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER)); - - if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) ) - break; - - if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { - POINT pos = {0, 0}; - int width, height; - - if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) { - pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN); - pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN); - width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - } - else { - width = GetSystemMetrics(SM_CXSCREEN); - height = GetSystemMetrics(SM_CYSCREEN); - } - - pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width); - pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height); - ScreenToClient(win->src.window, &pos); - - win->event.vector.x = pos.x - win->_lastMousePoint.x; - win->event.vector.y = pos.y - win->_lastMousePoint.y; - } else { - win->event.vector.x = raw.data.mouse.lLastX; - win->event.vector.y = raw.data.mouse.lLastY; - } - - win->event.type = RGFW_mousePosChanged; - win->_lastMousePoint.x += win->event.vector.x; - win->_lastMousePoint.y += win->event.vector.y; - win->event.point = win->_lastMousePoint; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - break; - } - case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: - if (msg.message == WM_XBUTTONDOWN) - win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); - else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft : - (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle; - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: - if (msg.message == WM_XBUTTONUP) - win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); - else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft : - (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; - case WM_MOUSEWHEEL: - if (msg.wParam > 0) - win->event.button = RGFW_mouseScrollUp; - else - win->event.button = RGFW_mouseScrollDown; - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - - win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA; - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - case WM_DROPFILES: { - win->event.type = RGFW_DNDInit; - - drop = (HDROP) msg.wParam; - POINT pt; - - /* Move the mouse to the position of the drop */ - DragQueryPoint(drop, &pt); - - win->event.point.x = pt.x; - win->event.point.y = pt.y; - - RGFW_dndInitCallback(win, win->event.point); - } - break; - default: - TranslateMessage(&msg); - DispatchMessageA(&msg); - return RGFW_window_checkEvent(win); - } - - TranslateMessage(&msg); - DispatchMessageA(&msg); - - return &win->event; -} - -RGFW_bool RGFW_window_isHidden(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win); -} - -RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - #ifndef __cplusplus - WINDOWPLACEMENT placement = { 0 }; - #else - WINDOWPLACEMENT placement = { }; - #endif - GetWindowPlacement(win->src.window, &placement); - return placement.showCmd == SW_SHOWMINIMIZED; -} - -RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - #ifndef __cplusplus - WINDOWPLACEMENT placement = { 0 }; - #else - WINDOWPLACEMENT placement = { }; - #endif - GetWindowPlacement(win->src.window, &placement); - return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window); -} - -typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo; -#ifndef RGFW_NO_MONITOR -RGFW_monitor win32CreateMonitor(HMONITOR src); -RGFW_monitor win32CreateMonitor(HMONITOR src) { - RGFW_monitor monitor; - MONITORINFOEX monitorInfo; - - monitorInfo.cbSize = sizeof(MONITORINFOEX); - GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo); - - /* get the monitor's index */ - DISPLAY_DEVICEA dd; - dd.cb = sizeof(dd); - - DWORD deviceNum; - for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { - if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) - continue; - - DEVMODEA dm; - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); - - if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { - monitor.mode.refreshRate = dm.dmDisplayFrequency; - RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode); - } - - DISPLAY_DEVICEA mdd; - mdd.cb = sizeof(mdd); - - if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) { - RGFW_STRNCPY(monitor.name, mdd.DeviceString, sizeof(monitor.name) - 1); - monitor.name[sizeof(monitor.name) - 1] = '\0'; - break; - } - } - - - - - monitor.x = monitorInfo.rcWork.left; - monitor.y = monitorInfo.rcWork.top; - monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); - monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); - - HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL); - /* get pixels per inch */ - float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX); - float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX); - - monitor.scaleX = dpiX / 96.0f; - monitor.scaleY = dpiY / 96.0f; - monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f; - - monitor.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f; - monitor.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f; - DeleteDC(hdc); - - #ifndef RGFW_NO_DPI - RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll"); - RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor); - - if (GetDpiForMonitor != NULL) { - u32 x, y; - GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y); - monitor.scaleX = (float) (x) / (float) 96.0f; - monitor.scaleY = (float) (y) / (float) 96.0f; - monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f; - } - #endif - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); - return monitor; -} -#endif /* RGFW_NO_MONITOR */ - -#ifndef RGFW_NO_MONITOR -BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); -BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { - RGFW_UNUSED(hdcMonitor); - RGFW_UNUSED(lprcMonitor); - - RGFW_mInfo* info = (RGFW_mInfo*) dwData; - - - if (info->iIndex >= 6) - return FALSE; - - info->monitors[info->iIndex] = win32CreateMonitor(hMonitor); - info->iIndex++; - - return TRUE; -} - -RGFW_monitor RGFW_getPrimaryMonitor(void) { - #ifdef __cplusplus - return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); - #else - return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); - #endif -} - -RGFW_monitor* RGFW_getMonitors(size_t* len) { - static RGFW_monitor monitors[6]; - RGFW_mInfo info; - info.iIndex = 0; - info.monitors = monitors; - - EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info); - - if (len != NULL) *len = (size_t)info.iIndex; - return monitors; -} - -RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { - HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); - return win32CreateMonitor(src); -} - -RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - POINT p = { mon.x, mon.y }; - HMONITOR src = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY); - - MONITORINFOEX monitorInfo; - monitorInfo.cbSize = sizeof(MONITORINFOEX); - GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo); - - DISPLAY_DEVICEA dd; - dd.cb = sizeof(dd); - - /* Enumerate display devices */ - DWORD deviceNum; - for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { - if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) - continue; - - if (strcmp(dd.DeviceName, (const char*)monitorInfo.szDevice) != 0) - continue; - - DEVMODEA dm; - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); - - if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { - if (request & RGFW_monitorScale) { - dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; - dm.dmPelsWidth = mode.area.w; - dm.dmPelsHeight = mode.area.h; - } - - if (request & RGFW_monitorRefresh) { - dm.dmFields |= DM_DISPLAYFREQUENCY; - dm.dmDisplayFrequency = mode.refreshRate; - } - - if (request & RGFW_monitorRGB) { - dm.dmFields |= DM_BITSPERPEL; - dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue); - } - - if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { - if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) - return RGFW_TRUE; - return RGFW_FALSE; - } else return RGFW_FALSE; - } - } - - return RGFW_FALSE; -} - -#endif -HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon); -HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) { - size_t channels = (size_t)c; - - BITMAPV5HEADER bi; - ZeroMemory(&bi, sizeof(bi)); - bi.bV5Size = sizeof(bi); - bi.bV5Width = (i32)a.w; - bi.bV5Height = -((LONG) a.h); - bi.bV5Planes = 1; - bi.bV5BitCount = (WORD)(channels * 8); - bi.bV5Compression = BI_RGB; - HDC dc = GetDC(NULL); - u8* target = NULL; - - HBITMAP color = CreateDIBSection(dc, - (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target, - NULL, (DWORD) 0); - - size_t x, y; - for (y = 0; y < a.h; y++) { - for (x = 0; x < a.w; x++) { - size_t index = (y * 4 * (size_t)a.w) + x * channels; - target[index] = src[index + 2]; - target[index + 1] = src[index + 1]; - target[index + 2] = src[index]; - target[index + 3] = src[index + 3]; - } - } - - ReleaseDC(NULL, dc); - - HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL); - - ICONINFO ii; - ZeroMemory(&ii, sizeof(ii)); - ii.fIcon = icon; - ii.xHotspot = a.w / 2; - ii.yHotspot = a.h / 2; - ii.hbmMask = mask; - ii.hbmColor = color; - - HICON handle = CreateIconIndirect(&ii); - - DeleteObject(color); - DeleteObject(mask); - - return handle; -} - -void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { - HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE); - return cursor; -} - -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { - RGFW_ASSERT(win && mouse); - SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse); - SetCursor((HCURSOR)mouse); -} - -void RGFW_freeMouse(RGFW_mouse* mouse) { - RGFW_ASSERT(mouse); - DestroyCursor((HCURSOR)mouse); -} - -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); -} - -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { - RGFW_ASSERT(win != NULL); - - static const u32 mouseIconSrc[16] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO}; - if (mouse > (sizeof(mouseIconSrc) / sizeof(u32))) - return RGFW_FALSE; - - char* icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]); - - SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon)); - SetCursor(LoadCursorA(NULL, icon)); - return RGFW_TRUE; -} - -void RGFW_window_hide(RGFW_window* win) { - ShowWindow(win->src.window, SW_HIDE); -} - -void RGFW_window_show(RGFW_window* win) { - if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); - ShowWindow(win->src.window, SW_RESTORE); -} - -#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL; -void RGFW_deinit(void) { - #ifndef RGFW_NO_XINPUT - RGFW_FREE_LIBRARY(RGFW_XInput_dll); - #endif - - #ifndef RGFW_NO_DPI - RGFW_FREE_LIBRARY(RGFW_Shcore_dll); - #endif - - #ifndef RGFW_NO_WINMM - timeEndPeriod(1); - #ifndef RGFW_NO_LOAD_WINMM - RGFW_FREE_LIBRARY(RGFW_winmm_dll); - #endif - #endif - - RGFW_FREE_LIBRARY(RGFW_wgl_dll); - _RGFW.root = NULL; - - RGFW_freeMouse(_RGFW.hiddenMouse); - _RGFW.windowCount = -1; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); -} - - -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - #ifdef RGFW_BUFFER - DeleteDC(win->src.hdcMem); - DeleteObject(win->src.bitmap); - #endif - - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); - RemovePropW(win->src.window, L"RGFW"); - ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */ - DestroyWindow(win->src.window); /*!< delete window */ - - if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall); - if (win->src.hIconBig) DestroyIcon(win->src.hIconBig); - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } -} - -void RGFW_window_move(RGFW_window* win, RGFW_point v) { - RGFW_ASSERT(win != NULL); - - win->r.x = v.x; - win->r.y = v.y; - SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE); -} - -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - - win->r.w = (i32)a.w; - win->r.h = (i32)a.h; - SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE); -} - - -void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_ASSERT(win != NULL); - - wchar_t wide_name[256]; - MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256); - SetWindowTextW(win->src.window, wide_name); -} - -#ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { - RGFW_ASSERT(win != NULL); - COLORREF key = 0; - BYTE alpha = 0; - DWORD flags = 0; - i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE); - - if (exStyle & WS_EX_LAYERED) - GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags); - - if (passthrough) - exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); - else { - exStyle &= ~WS_EX_TRANSPARENT; - if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA)) - exStyle &= ~WS_EX_LAYERED; - } - - SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle); - - if (passthrough) - SetLayeredWindowAttributes(win->src.window, key, alpha, flags); -} -#endif - -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) { - RGFW_ASSERT(win != NULL); - #ifndef RGFW_WIN95 - RGFW_UNUSED(channels); - - if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall); - if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig); - - if (src == NULL) { - HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION); - if (type & RGFW_iconWindow) - SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon); - if (type & RGFW_iconTaskbar) - SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon); - return RGFW_TRUE; - } - - if (type & RGFW_iconWindow) { - win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE); - SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall); - } - if (type & RGFW_iconTaskbar) { - win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE); - SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig); - } - return RGFW_TRUE; - #else - RGFW_UNUSED(src); - RGFW_UNUSED(a); - RGFW_UNUSED(channels); - return RGFW_FALSE; - #endif -} - -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - /* Open the clipboard */ - if (OpenClipboard(NULL) == 0) - return -1; - - /* Get the clipboard data as a Unicode string */ - HANDLE hData = GetClipboardData(CF_UNICODETEXT); - if (hData == NULL) { - CloseClipboard(); - return -1; - } - - wchar_t* wstr = (wchar_t*) GlobalLock(hData); - - RGFW_ssize_t textLen = 0; - - { - setlocale(LC_ALL, "en_US.UTF-8"); - - textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1; - if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1) - textLen = 0; - - if (str != NULL && textLen) { - if (textLen > 1) - wcstombs(str, wstr, (size_t)(textLen)); - - str[textLen] = '\0'; - } - } - - /* Release the clipboard data */ - GlobalUnlock(hData); - CloseClipboard(); - - return textLen; -} - -void RGFW_writeClipboard(const char* text, u32 textLen) { - HANDLE object; - WCHAR* buffer; - - object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR)); - if (!object) - return; - - buffer = (WCHAR*) GlobalLock(object); - if (!buffer) { - GlobalFree(object); - return; - } - - MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen); - GlobalUnlock(object); - - if (!OpenClipboard(_RGFW.root->src.window)) { - GlobalFree(object); - return; - } - - EmptyClipboard(); - SetClipboardData(CF_UNICODETEXT, object); - CloseClipboard(); -} - -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { - RGFW_ASSERT(win != NULL); - win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); - SetCursorPos(p.x, p.y); -} - -#ifdef RGFW_OPENGL -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - if (win == NULL) - wglMakeCurrent(NULL, NULL); - else - wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx); -} -void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); } -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); } -#endif - -#ifndef RGFW_EGL -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL); -#if defined(RGFW_OPENGL) - if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval"); -#else - RGFW_UNUSED(swapInterval); -#endif -} -#endif - -void RGFW_window_swapBuffers_software(RGFW_window* win) { -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (win->buffer != win->src.bitmapBits) - memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4); - - RGFW_RGB_to_BGR(win, win->src.bitmapBits); - BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); -#else - RGFW_UNUSED(win); -#endif -} - -char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) { - if (source == NULL) { - return NULL; - } - i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); - if (!size) { - return NULL; - } - - static char target[RGFW_MAX_PATH * 2]; - if (size > RGFW_MAX_PATH * 2) - size = RGFW_MAX_PATH * 2; - - target[size] = 0; - - if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { - return NULL; - } - - return target; -} - -u64 RGFW_getTimerFreq(void) { - static u64 frequency = 0; - if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); - - return frequency; -} - -u64 RGFW_getTimerValue(void) { - u64 value; - QueryPerformanceCounter((LARGE_INTEGER*)&value); - return value; -} - -void RGFW_sleep(u64 ms) { - Sleep((u32)ms); -} - -#ifndef RGFW_NO_THREADS - -RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); } -void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); } -void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); } -void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); } - -#endif -#endif /* RGFW_WINDOWS */ - -/* - End of Windows defines -*/ - - - -/* - - Start of MacOS defines - - -*/ - -#if defined(RGFW_MACOS) -/* - based on silicon.h - start of cocoa wrapper -*/ - -#include -#include -#include -#include -#include -#include - -typedef CGRect NSRect; -typedef CGPoint NSPoint; -typedef CGSize NSSize; - -typedef const char* NSPasteboardType; -typedef unsigned long NSUInteger; -typedef long NSInteger; -typedef NSInteger NSModalResponse; - -#ifdef __arm64__ - /* ARM just uses objc_msgSend */ -#define abi_objc_msgSend_stret objc_msgSend -#define abi_objc_msgSend_fpret objc_msgSend -#else /* __i386__ */ - /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ -#define abi_objc_msgSend_stret objc_msgSend_stret -#define abi_objc_msgSend_fpret objc_msgSend_fpret -#endif - -#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) -#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z) -#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z) -#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z) -#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) -#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) -#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) -#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) -#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z) -#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y) -#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z) - -id NSApp = NULL; - -#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release")) -id NSString_stringWithUTF8String(const char* str); -id NSString_stringWithUTF8String(const char* str) { - return ((id(*)(id, SEL, const char*))objc_msgSend) - ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); -} - -const char* NSString_to_char(id str); -const char* NSString_to_char(id str) { - return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String")); -} - -void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function); -void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) { - Class selected_class; - - if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) { - selected_class = objc_getClass("ViewClass"); - } else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) { - selected_class = objc_getClass("WindowClass"); - } else { - selected_class = objc_getClass(class_name); - } - - class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0); -} - -/* Header for the array. */ -typedef struct siArrayHeader { - size_t count; - /* TODO(EimaMei): Add a `type_width` later on. */ -} siArrayHeader; - -/* Gets the header of the siArray. */ -#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1) -#define si_array_len(array) (SI_ARRAY_HEADER(array)->count) -#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function) -/* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/ -#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function) - -unsigned char* NSBitmapImageRep_bitmapData(id imageRep); -unsigned char* NSBitmapImageRep_bitmapData(id imageRep) { - return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData")); -} - -typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) { - NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */ - NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */ - NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */ - - NSBitmapFormatSixteenBitLittleEndian = (1 << 8), - NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9), - NSBitmapFormatSixteenBitBigEndian = (1 << 10), - NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11) -}; - -id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits); -id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { - SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); - - return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) - (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); -} - -id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); -id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { - void* nsclass = objc_getClass("NSColor"); - SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); - return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) - ((id)nsclass, func, red, green, blue, alpha); -} - -typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) { - NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ - NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */ - NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */ - NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */ - NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */ - NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */ - NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */ - NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */ - NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */ - NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */ - - NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */ - NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */ - NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */ - NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */ - NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ -}; - -typedef RGFW_ENUM(NSInteger, NSWindowButton) { - NSWindowCloseButton = 0, - NSWindowMiniaturizeButton = 1, - NSWindowZoomButton = 2, - NSWindowToolbarButton = 3, - NSWindowDocumentIconButton = 4, - NSWindowDocumentVersionsButton = 6, - NSWindowFullScreenButton = 7, -}; -void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param); -void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) { - ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) - (context, sel_registerName("setValues:forParameter:"), vals, param); -} -void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs); -void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) { - return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend) - (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs); -} - -id NSPasteboard_generalPasteboard(void); -id NSPasteboard_generalPasteboard(void) { - return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); -} - -id* cstrToNSStringArray(char** strs, size_t len); -id* cstrToNSStringArray(char** strs, size_t len) { - static id nstrs[6]; - size_t i; - for (i = 0; i < len; i++) - nstrs[i] = NSString_stringWithUTF8String(strs[i]); - - return nstrs; -} - -const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len); -const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) { - SEL func = sel_registerName("stringForType:"); - id nsstr = NSString_stringWithUTF8String(dataType); - id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr); - const char* str = NSString_to_char(nsString); - if (len != NULL) - *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4); - return str; -} - -id c_array_to_NSArray(void* array, size_t len); -id c_array_to_NSArray(void* array, size_t len) { - SEL func = sel_registerName("initWithObjects:count:"); - void* nsclass = objc_getClass("NSArray"); - return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) - (NSAlloc(nsclass), func, array, len); -} - - -void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len); -void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) { - id* ntypes = cstrToNSStringArray((char**)newTypes, len); - - id array = c_array_to_NSArray(ntypes, len); - objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); - NSRelease(array); -} - -NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner); -NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) { - id* ntypes = cstrToNSStringArray((char**)newTypes, len); - - SEL func = sel_registerName("declareTypes:owner:"); - - id array = c_array_to_NSArray(ntypes, len); - - NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend) - (pasteboard, func, array, owner); - NSRelease(array); - - return output; -} - -#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain")) - -typedef enum NSApplicationActivationPolicy { - NSApplicationActivationPolicyRegular, - NSApplicationActivationPolicyAccessory, - NSApplicationActivationPolicyProhibited -} NSApplicationActivationPolicy; - -typedef RGFW_ENUM(u32, NSBackingStoreType) { - NSBackingStoreRetained = 0, - NSBackingStoreNonretained = 1, - NSBackingStoreBuffered = 2 -}; - -typedef RGFW_ENUM(u32, NSWindowStyleMask) { - NSWindowStyleMaskBorderless = 0, - NSWindowStyleMaskTitled = 1 << 0, - NSWindowStyleMaskClosable = 1 << 1, - NSWindowStyleMaskMiniaturizable = 1 << 2, - NSWindowStyleMaskResizable = 1 << 3, - NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ - NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, - NSWindowStyleMaskFullScreen = 1 << 14, - NSWindowStyleMaskFullSizeContentView = 1 << 15, - NSWindowStyleMaskUtilityWindow = 1 << 4, - NSWindowStyleMaskDocModalWindow = 1 << 6, - NSWindowStyleMaskNonactivatingpanel = 1 << 7, - NSWindowStyleMaskHUDWindow = 1 << 13 -}; - -NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */ - - -typedef RGFW_ENUM(i32, NSDragOperation) { - NSDragOperationNone = 0, - NSDragOperationCopy = 1, - NSDragOperationLink = 2, - NSDragOperationGeneric = 4, - NSDragOperationPrivate = 8, - NSDragOperationMove = 16, - NSDragOperationDelete = 32, - NSDragOperationEvery = (int)ULONG_MAX -}; - -void* NSArray_objectAtIndex(id array, NSUInteger index) { - SEL func = sel_registerName("objectAtIndex:"); - return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index); -} - -id NSWindow_contentView(id window) { - SEL func = sel_registerName("contentView"); - return objc_msgSend_id(window, func); -} - -/* - End of cocoa wrapper -*/ - -#ifdef RGFW_OPENGL -/* MacOS opengl API spares us yet again (there are no extensions) */ -RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; } -CFBundleRef RGFWnsglFramework = NULL; - -RGFW_proc RGFW_getProcAddress(const char* procname) { - if (RGFWnsglFramework == NULL) - RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - - CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); - - RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); - - CFRelease(symbolName); - - return symbol; -} -#endif - -id NSWindow_delegate(RGFW_window* win) { - return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate")); -} - -u32 RGFW_OnClose(id self) { - RGFW_window* win = NULL; - object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win); - if (win == NULL) - return true; - - RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); - RGFW_windowQuitCallback(win); - - return false; -} - -/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */ -bool acceptsFirstResponder(void) { return true; } -bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } - -NSDragOperation draggingEntered(id self, SEL sel, id sender) { - RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); - - return NSDragOperationCopy; -} -NSDragOperation draggingUpdated(id self, SEL sel, id sender) { - RGFW_UNUSED(sel); - - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || (!(win->_flags & RGFW_windowAllowDND))) - return 0; - - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); - RGFW_eventQueuePushEx(e.type = RGFW_DNDInit; - e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - e._win = win); - - RGFW_dndInitCallback(win, win->event.point); - return NSDragOperationCopy; -} -bool prepareForDragOperation(id self) { - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) - return true; - - if (!(win->_flags & RGFW_windowAllowDND)) { - return false; - } - - return true; -} - -void RGFW__osxDraggingEnded(id self, SEL sel, id sender); -void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; } - -/* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */ -bool performDragOperation(id self, SEL sel, id sender) { - RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); - - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - - if (win == NULL) - return false; - - /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */ - - id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); - - /* Get the types of data available on the pasteboard */ - id types = objc_msgSend_id(pasteBoard, sel_registerName("types")); - - /* Get the string type for file URLs */ - id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType"); - - /* Check if the pasteboard contains file URLs */ - if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard."); - return 0; - } - - id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType); - int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count")); - - if (count == 0) - return 0; - - int i; - for (i = 0; i < count; i++) { - id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); - const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); - RGFW_STRNCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH - 1); - win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; - } - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); - - win->event.droppedFilesCount = (size_t)count; - RGFW_eventQueuePushEx(e.type = RGFW_DND; - e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - e.droppedFilesCount = (size_t)count; - e._win = win); - - RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); - - return false; -} - -#ifndef RGFW_NO_IOKIT -#include -#include - -u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { - u32 refreshRate = 0; - io_iterator_t it; - io_service_t service; - CFNumberRef indexRef, clockRef, countRef; - uint32_t clock, count; - -#ifdef kIOMainPortDefault - if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) -#elif defined(kIOMasterPortDefault) - if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) -#endif - return RGFW_FALSE; - - while ((service = IOIteratorNext(it)) != 0) { - uint32_t index; - indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions); - if (indexRef == 0) continue; - - if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) { - CFRelease(indexRef); - break; - } - - CFRelease(indexRef); - } - - if (service) { - clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions); - if (clockRef) { - if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) { - countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions); - if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) { - refreshRate = (u32)RGFW_ROUND(clock / (double) count); - CFRelease(countRef); - } - } - CFRelease(clockRef); - } - } - - IOObjectRelease(it); - return refreshRate; -} - -IOHIDDeviceRef RGFW_osxControllers[4] = {NULL}; - -size_t findControllerIndex(IOHIDDeviceRef device) { - size_t i; - for (i = 0; i < 4; i++) - if (RGFW_osxControllers[i] == device) - return i; - return (size_t)-1; -} - -void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) { - RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); - IOHIDElementRef element = IOHIDValueGetElement(value); - - IOHIDDeviceRef device = IOHIDElementGetDevice(element); - size_t index = findControllerIndex(device); - if (index == (size_t)-1) return; - - uint32_t usagePage = IOHIDElementGetUsagePage(element); - uint32_t usage = IOHIDElementGetUsage(element); - - CFIndex intValue = IOHIDValueGetIntegerValue(value); - - u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{ - 0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart, - RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft, - RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1, - RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome}, - {0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX, - RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1, - RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart, - RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome} - }; - - u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0]; - if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft) - RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1]; - - switch (usagePage) { - case kHIDPage_Button: { - u8 button = 0; - if (usage < sizeof(RGFW_osx2RGFW)) - button = RGFW_osx2RGFW[usage]; - - RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue); - RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current; - RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue); - RGFW_eventQueuePushEx(e.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased; - e.button = button; - e.gamepad = (u16)index; - e._win = _RGFW.root); - break; - } - case kHIDPage_GenericDesktop: { - CFIndex logicalMin = IOHIDElementGetLogicalMin(element); - CFIndex logicalMax = IOHIDElementGetLogicalMax(element); - - if (logicalMax <= logicalMin) return; - if (intValue < logicalMin) intValue = logicalMin; - if (intValue > logicalMax) intValue = logicalMax; - - i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin)); - - u8 whichAxis = 0; - switch (usage) { - case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break; - case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break; - case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break; - case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break; - default: return; - } - - RGFW_event e; - e.type = RGFW_gamepadAxisMove; - e.gamepad = (u16)index; - e.whichAxis = whichAxis; - e._win = _RGFW.root; - for (size_t i = 0; i < 4; i++) - e.axis[i] = RGFW_gamepadAxes[index][i]; - - RGFW_eventQueuePush(e); - - RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis); - } - } -} - -void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) { - RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); - CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); - int usage = 0; - if (usageRef) - CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage); - - if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) { - return; - } - - size_t i; - for (i = 0; i < 4; i++) { - if (RGFW_osxControllers[i] != NULL) - continue; - - RGFW_osxControllers[i] = device; - - IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL); - - CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - if (deviceName) - CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8); - - RGFW_gamepads_type[i] = RGFW_gamepadUnknown; - if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox")) - RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5")) - RGFW_gamepads_type[i] = RGFW_gamepadSony; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo")) - RGFW_gamepads_type[i] = RGFW_gamepadNintendo; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech")) - RGFW_gamepads_type[i] = RGFW_gamepadLogitech; - - RGFW_gamepads[i] = (u16)i; - RGFW_gamepadCount++; - - RGFW_eventQueuePushEx(e.type = RGFW_gamepadConnected; - e.gamepad = (u16)i; - e._win = _RGFW.root); - - RGFW_gamepadCallback(_RGFW.root, (u16)i, 1); - break; - } -} - -void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) { - RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device); - CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); - int usage = 0; - if (usageRef) - CFNumberGetValue(usageRef, kCFNumberIntType, &usage); - - if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) { - return; - } - - size_t index = findControllerIndex(device); - if (index != (size_t)-1) - RGFW_osxControllers[index] = NULL; - - RGFW_eventQueuePushEx(e.type = RGFW_gamepadDisconnected; - e.gamepad = (u16)index; - e._win = _RGFW.root); - RGFW_gamepadCallback(_RGFW.root, (u16)index, 0); - - RGFW_gamepadCount--; -} - -RGFWDEF void RGFW_osxInitIOKit(void); -void RGFW_osxInitIOKit(void) { - IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); - if (!hidManager) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager."); - return; - } - - CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable( - kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks - ); - if (!matchingDictionary) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit."); - CFRelease(hidManager); - return; - } - - CFDictionarySetValue( - matchingDictionary, - CFSTR(kIOHIDDeviceUsagePageKey), - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop}) - ); - - IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary); - - IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL); - IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL); - - IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - - IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); - - /* Execute the run loop once in order to register any initially-attached joysticks */ - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); -} -#endif - -void RGFW_moveToMacOSResourceDir(void) { - char resourcesPath[256]; - - CFBundleRef bundle = CFBundleGetMainBundle(); - if (!bundle) - return; - - CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); - CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); - - if ( - CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo || - CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0 - ) { - CFRelease(last); - CFRelease(resourcesURL); - return; - } - - CFRelease(last); - CFRelease(resourcesURL); - - chdir(resourcesPath); -} - - -void RGFW__osxWindowDeminiaturize(id self, SEL sel) { - RGFW_UNUSED(sel); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - win->_flags |= RGFW_windowMinimize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); - RGFW_windowRestoredCallback(win, win->r); - -} -void RGFW__osxWindowMiniaturize(id self, SEL sel) { - RGFW_UNUSED(sel); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - win->_flags &= ~(u32)RGFW_windowMinimize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e._win = win); - RGFW_windowMinimizedCallback(win, win->r); - -} - -void RGFW__osxWindowBecameKey(id self, SEL sel) { - RGFW_UNUSED(sel); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - win->_flags |= RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = win); - - RGFW_focusCallback(win, RGFW_TRUE); - - RGFW_resetKey(); - if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); -} - -void RGFW__osxWindowResignKey(id self, SEL sel) { - RGFW_UNUSED(sel); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - win->_flags &= ~(u32)RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win); - RGFW_focusCallback(win, RGFW_FALSE); -} - -NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) { - RGFW_UNUSED(sel); - - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return frameSize; - - win->r.w = (i32)frameSize.width; - win->r.h = (i32)frameSize.height; - - RGFW_monitor mon = RGFW_window_getMonitor(win); - if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) { - win->_flags |= RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win); - RGFW_windowMaximizedCallback(win, win->r); - } else if (win->_flags & RGFW_windowMaximize) { - win->_flags &= ~(u32)RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); - RGFW_windowRestoredCallback(win, win->r); - - } - - - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win); - RGFW_windowResizedCallback(win, win->r); - return frameSize; -} - -void RGFW__osxWindowMove(id self, SEL sel) { - RGFW_UNUSED(sel); - - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); - win->r.x = (i32) frame.origin.x; - win->r.y = (i32) frame.origin.y; - - RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win); - RGFW_windowMovedCallback(win, win->r); -} - -void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - RGFW_monitor mon = RGFW_window_getMonitor(win); - RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY); - RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = mon.scaleX; e.scaleY = mon.scaleY ; e._win = win); -} - -void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { - RGFW_UNUSED(rect); RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win); - RGFW_windowRefreshCallback(win); -} - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = buffer; - win->bufferSize = area; - win->_flags |= RGFW_BUFFER_ALLOC; - #ifdef RGFW_OSMESA - win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #else - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ - #endif -} - -void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) { - objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer); -} - -void* RGFW_cocoaGetLayer(void) { - return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer")); -} - -NSPasteboardType const NSPasteboardTypeURL = "public.url"; -NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url"; - -id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) { - Class customViewClass; - customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0); - - class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L"); - class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}"); - class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, ""); - - id customView = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init")); - object_setInstanceVariable(customView, "RGFW_window", win); - - return customView; -} - -#ifndef RGFW_EGL -void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) { -#ifdef RGFW_OPENGL - void* attrs = RGFW_initFormatAttribs(software); - void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs); - - if (format == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL"); - void* subAttrs = RGFW_initFormatAttribs(1); - format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs); - - if (format == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed"); - else - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering"); - } - - /* the pixel format can be passed directly to opengl context creation to create a context - this is because the format also includes information about the opengl version (which may be a bad thing) */ - - win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win), - sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format); - - objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL")); - win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext")); - - if (win->_flags & RGFW_windowTransparent) { - i32 opacity = 0; - #define NSOpenGLCPSurfaceOpacity 236 - NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity); - } - - objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); -#else - RGFW_UNUSED(win); RGFW_UNUSED(software); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - if (win->src.ctx == NULL) return; - objc_msgSend_void(win->src.ctx, sel_registerName("release")); - win->src.ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#else - RGFW_UNUSED(win); -#endif -} -#endif - - -i32 RGFW_init(void) { -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - - /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea??? - Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance). - */ - si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose); - - /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */ - si_func_to_SEL("NSWindow", acceptsFirstResponder); - si_func_to_SEL("NSWindow", performKeyEquivalent); - - if (NSApp == NULL) { - NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - - ((void (*)(id, SEL, NSUInteger))objc_msgSend) - (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); - - #ifndef RGFW_NO_IOKIT - RGFW_osxInitIOKit(); - #endif - } - - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 0; -} - -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - static u8 RGFW_loaded = 0; - RGFW_window_basic_init(win, rect, flags); - - /* RR Create an autorelease pool */ - id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - pool = objc_msgSend_id(pool, sel_registerName("init")); - - RGFW_window_setMouseDefault(win); - - NSRect windowRect; - windowRect.origin.x = win->r.x; - windowRect.origin.y = win->r.y; - windowRect.size.width = win->r.w; - windowRect.size.height = win->r.h; - - NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled; - - if (!(flags & RGFW_windowNoResize)) - macArgs |= NSWindowStyleMaskResizable; - if (!(flags & RGFW_windowNoBorder)) - macArgs |= NSWindowStyleMaskTitled; - { - void* nsclass = objc_getClass("NSWindow"); - SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); - - win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) - (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false); - } - - id str = NSString_stringWithUTF8String(name); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str); - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware)); - RGFW_window_initBuffer(win); - } - - #ifdef RGFW_OPENGL - else - #endif - { - NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}}; - win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect); - } - - void* contentView = NSWindow_contentView((id)win->src.window); - objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true); - objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); - - if (flags & RGFW_windowTransparent) { - objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); - - objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), - NSColor_colorWithSRGB(0, 0, 0, 0)); - } - - Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); - - class_addIvar( - delegateClass, "RGFW_window", - sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), - "L" - ); - - class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}"); - class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, ""); - class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); - class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, ""); - class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, ""); - class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, ""); - class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, ""); - class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@"); - class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@"); - class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); - class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); - class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@"); - class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@"); - - id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); - - if (RGFW_COCOA_FRAME_NAME) - objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); - - object_setInstanceVariable(delegate, "RGFW_window", win); - - objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate); - - if (flags & RGFW_windowAllowDND) { - win->_flags |= RGFW_windowAllowDND; - - NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; - NSregisterForDraggedTypes((id)win->src.window, types, 3); - } - - RGFW_window_setFlags(win, flags); - - /* Show the window */ - objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); - ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); - RGFW_window_show(win); - - if (!RGFW_loaded) { - objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow")); - - RGFW_loaded = 1; - } - - objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); - - objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); - NSRetain(win->src.window); - NSRetain(NSApp); - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - return win; -} - -void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { - NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); - NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); - float offset = 0; - - RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); - NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView; - if (border) - storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; - if (!(win->_flags & RGFW_windowNoResize)) { - storeType |= NSWindowStyleMaskResizable; - } - - ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType); - - if (!border) { - id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton); - id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview")); - objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true); - - offset = (float)(frame.size.height - content.size.height); - } - - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset)); - win->r.h -= (i32)offset; -} - -RGFW_area RGFW_getScreenSize(void) { - static CGDirectDisplayID display = 0; - - if (display == 0) - display = CGMainDisplayID(); - - return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_ASSERT(_RGFW.root != NULL); - - CGEventRef e = CGEventCreate(NULL); - CGPoint point = CGEventGetLocation(e); - CFRelease(e); - - return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ -} - -typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ - NSEventTypeLeftMouseDown = 1, - NSEventTypeLeftMouseUp = 2, - NSEventTypeRightMouseDown = 3, - NSEventTypeRightMouseUp = 4, - NSEventTypeMouseMoved = 5, - NSEventTypeLeftMouseDragged = 6, - NSEventTypeRightMouseDragged = 7, - NSEventTypeMouseEntered = 8, - NSEventTypeMouseExited = 9, - NSEventTypeKeyDown = 10, - NSEventTypeKeyUp = 11, - NSEventTypeFlagsChanged = 12, - NSEventTypeAppKitDefined = 13, - NSEventTypeSystemDefined = 14, - NSEventTypeApplicationDefined = 15, - NSEventTypePeriodic = 16, - NSEventTypeCursorUpdate = 17, - NSEventTypeScrollWheel = 22, - NSEventTypeTabletPoint = 23, - NSEventTypeTabletProximity = 24, - NSEventTypeOtherMouseDown = 25, - NSEventTypeOtherMouseUp = 26, - NSEventTypeOtherMouseDragged = 27, - /* The following event types are available on some hardware on 10.5.2 and later */ - NSEventTypeGesture = 29, - NSEventTypeMagnify = 30, - NSEventTypeSwipe = 31, - NSEventTypeRotate = 18, - NSEventTypeBeginGesture = 19, - NSEventTypeEndGesture = 20, - - NSEventTypeSmartMagnify = 32, - NSEventTypeQuickLook = 33, - - NSEventTypePressure = 34, - NSEventTypeDirectTouch = 37, - - NSEventTypeChangeMode = 38, -}; - -typedef unsigned long long NSEventMask; - -typedef enum NSEventModifierFlags { - NSEventModifierFlagCapsLock = 1 << 16, - NSEventModifierFlagShift = 1 << 17, - NSEventModifierFlagControl = 1 << 18, - NSEventModifierFlagOption = 1 << 19, - NSEventModifierFlagCommand = 1 << 20, - NSEventModifierFlagNumericPad = 1 << 21 -} NSEventModifierFlags; - -void RGFW_stopCheckEvents(void) { - id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); - - id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend) - (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"), - NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0); - - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 1); - - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); -} - -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); - - id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); - - void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend) - (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS); - - SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - (NSApp, eventFunc, - ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); - - - if (e) { - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 1); - } - - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); -} - -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - - objc_msgSend_void((id)win->src.mouse, sel_registerName("set")); - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) { - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return ev; - } - - id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); - - SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - - void* date = NULL; - - id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); - - if (e == NULL) { - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return NULL; - } - - if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 0); - - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return NULL; - } - - if (win->event.droppedFilesCount) { - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - } - - win->event.droppedFilesCount = 0; - win->event.type = 0; - - u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type")); - switch (type) { - case NSEventTypeMouseEntered: { - win->event.type = RGFW_mouseEnter; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); - - win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y)); - RGFW_mouseNotifyCallback(win, win->event.point, 1); - break; - } - - case NSEventTypeMouseExited: - win->event.type = RGFW_mouseLeave; - RGFW_mouseNotifyCallback(win, win->event.point, 0); - break; - - case NSEventTypeKeyDown: { - u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - - u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); - if (((u8)mappedKey) == 239) - mappedKey = 0; - - win->event.keyChar = (u8)mappedKey; - - win->event.key = (u8)RGFW_apiKeyToRGFW(key); - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - win->event.type = RGFW_keyPressed; - win->event.repeat = RGFW_isPressed(win, win->event.key); - RGFW_keyboard[win->event.key].current = 1; - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); - break; - } - - case NSEventTypeKeyUp: { - u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - - - u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); - if (((u8)mappedKey) == 239) - mappedKey = 0; - - win->event.keyChar = (u8)mappedKey; - - win->event.key = (u8)RGFW_apiKeyToRGFW(key); - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - win->event.type = RGFW_keyReleased; - - RGFW_keyboard[win->event.key].current = 0; - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); - break; - } - - case NSEventTypeFlagsChanged: { - u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags")); - RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255), - ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255), - ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0); - u8 i; - for (i = 0; i < 9; i++) - RGFW_keyboard[i + RGFW_capsLock].prev = 0; - - for (i = 0; i < 5; i++) { - u32 shift = (1 << (i + 16)); - u32 key = i + RGFW_capsLock; - - if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) { - RGFW_keyboard[key].current = 1; - - if (key != RGFW_capsLock) - RGFW_keyboard[key+ 4].current = 1; - - win->event.type = RGFW_keyPressed; - win->event.key = (u8)key; - break; - } - - if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) { - RGFW_keyboard[key].current = 0; - - if (key != RGFW_capsLock) - RGFW_keyboard[key + 4].current = 0; - - win->event.type = RGFW_keyReleased; - win->event.key = (u8)key; - break; - } - } - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed); - - break; - } - case NSEventTypeLeftMouseDragged: - case NSEventTypeOtherMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeMouseMoved: { - win->event.type = RGFW_mousePosChanged; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); - win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - - p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX")); - p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y); - - win->_lastMousePoint = win->event.point; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - break; - } - case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: { - u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber")); - switch (buttonNumber) { - case 0: win->event.button = RGFW_mouseLeft; break; - case 1: win->event.button = RGFW_mouseRight; break; - case 2: win->event.button = RGFW_mouseMiddle; break; - default: win->event.button = (u8)buttonNumber; - } - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - } - case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: { - u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber")); - switch (buttonNumber) { - case 0: win->event.button = RGFW_mouseLeft; break; - case 1: win->event.button = RGFW_mouseRight; break; - case 2: win->event.button = RGFW_mouseMiddle; break; - default: win->event.button = (u8)buttonNumber; - } - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; - } - case NSEventTypeScrollWheel: { - double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - - if (deltaY > 0) { - win->event.button = RGFW_mouseScrollUp; - } - else if (deltaY < 0) { - win->event.button = RGFW_mouseScrollDown; - } - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - - win->event.scroll = deltaY; - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - } - - default: - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return RGFW_window_checkEvent(win); - } - - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - return &win->event; -} - - -void RGFW_window_move(RGFW_window* win, RGFW_point v) { - RGFW_ASSERT(win != NULL); - - win->r.x = v.x; - win->r.y = v.y; - ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); -} - -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { - RGFW_ASSERT(win != NULL); - - NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); - NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); - float offset = (float)(frame.size.height - content.size.height); - - win->r.w = (i32)a.w; - win->r.h = (i32)a.h; - - ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true); -} - -void RGFW_window_focus(RGFW_window* win) { - RGFW_ASSERT(win); - objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); - ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow")); -} - -void RGFW_window_raise(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL); - objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey); -} - -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return; - if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return; - - if (fullscreen) { - win->_oldRect = win->r; - RGFW_monitor mon = RGFW_window_getMonitor(win); - win->r = RGFW_RECT(0, 0, mon.x, mon.y); - win->_flags |= RGFW_windowFullscreen; - RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h)); - RGFW_window_move(win, RGFW_POINT(0, 0)); - } - objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); - - if (!fullscreen) { - win->r = win->_oldRect; - win->_flags &= ~(u32)RGFW_windowFullscreen; - - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); - RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); - } -} - -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - if (RGFW_window_isMaximized(win)) return; - - win->_flags |= RGFW_windowMaximize; - objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); -} - -void RGFW_window_minimize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL); -} - -void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { - RGFW_ASSERT(win != NULL); - if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey); - else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey); -} - -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity); - objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255)); - - if (opacity) - objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity)); - -} - -void RGFW_window_restore(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - if (RGFW_window_isMaximized(win)) - objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); - - objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL); - RGFW_window_show(win); -} - -RGFW_bool RGFW_window_isFloating(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level")); - return level > kCGNormalWindowLevelKey; -} - -void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_ASSERT(win != NULL); - - id str = NSString_stringWithUTF8String(name); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str); -} - -#ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { - objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough); -} -#endif - -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { - if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1); - - ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h}); -} - -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { - ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h}); -} - -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { - if (a.w == 0 && a.h == 0) { - a = RGFW_getScreenSize(); - } - - ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h}); -} - -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) { - RGFW_ASSERT(win != NULL); - RGFW_UNUSED(type); - - if (data == NULL) { - objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL); - return RGFW_TRUE; - } - - /* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */ - id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels); - RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels); - - /* Add ze representation. */ - id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h})); - - objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation); - - /* Finally, set the dock image to it. */ - objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image); - /* Free the garbage. */ - NSRelease(dock_image); - NSRelease(representation); - - return RGFW_TRUE; -} - -id NSCursor_arrowStr(const char* str) { - void* nclass = objc_getClass("NSCursor"); - SEL func = sel_registerName(str); - return (id) objc_msgSend_id(nclass, func); -} - -RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { - if (icon == NULL) { - objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set")); - return NULL; - } - - /* NOTE(EimaMei): Code by yours truly. */ - /* Make a bitmap representation, then copy the loaded image into it. */ - id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels); - RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels); - - /* Add ze representation. */ - id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h})); - - objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation); - - /* Finally, set the cursor image. */ - id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend) - (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0}); - - /* Free the garbage. */ - NSRelease(cursor_image); - NSRelease(representation); - - return (void*)cursor; -} - -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { - RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse); - CGDisplayShowCursor(kCGDirectMainDisplay); - objc_msgSend_void((id)mouse, sel_registerName("set")); - win->src.mouse = mouse; -} - -void RGFW_freeMouse(RGFW_mouse* mouse) { - RGFW_ASSERT(mouse); - NSRelease((id)mouse); -} - -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); -} - -void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { - RGFW_window_showMouseFlags(win, show); - if (show) CGDisplayShowCursor(kCGDirectMainDisplay); - else CGDisplayHideCursor(kCGDirectMainDisplay); -} - -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) { - static const char* mouseIconSrc[16] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"}; - if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char*)))) - return RGFW_FALSE; - - const char* mouseStr = mouseIconSrc[stdMouses]; - id mouse = NSCursor_arrowStr(mouseStr); - - if (mouse == NULL) - return RGFW_FALSE; - - RGFW_UNUSED(win); - CGDisplayShowCursor(kCGDirectMainDisplay); - objc_msgSend_void(mouse, sel_registerName("set")); - win->src.mouse = mouse; - - return RGFW_TRUE; -} - -void RGFW_releaseCursor(RGFW_window* win) { - RGFW_UNUSED(win); - CGAssociateMouseAndMouseCursorPosition(1); -} - -void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { - RGFW_UNUSED(win); - - CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)}); - CGAssociateMouseAndMouseCursorPosition(0); -} - -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { - RGFW_UNUSED(win); - - win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y); - CGWarpMouseCursorPosition((CGPoint){v.x, v.y}); -} - - -void RGFW_window_hide(RGFW_window* win) { - objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false); -} - -void RGFW_window_show(RGFW_window* win) { - if (win->_flags & RGFW_windowFocusOnShow) - ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); - - ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL); - objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true); -} - -RGFW_bool RGFW_window_isHidden(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible")); - return visible == NO && !RGFW_window_isMinimized(win); -} - -RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES; -} - -RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed")); - return b; -} - -id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { - Class NSScreenClass = objc_getClass("NSScreen"); - - id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens")); - - NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count")); - NSUInteger i; - for (i = 0; i < count; i++) { - id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i); - id description = objc_msgSend_id(screen, sel_registerName("deviceDescription")); - id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber"); - id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey); - - if ((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")) == display) { - return screen; - } - } - - return NULL; -} - -u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID); - -u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { - if (mode) { - u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode); - if (refreshRate != 0) return refreshRate; - } - -#ifndef RGFW_NO_IOKIT - u32 res = RGFW_osx_getFallbackRefreshRate(display); - if (res != 0) return res; -#else - RGFW_UNUSED(display); -#endif - return 60; -} - -RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { - RGFW_monitor monitor; - - const char name[] = "MacOS\0"; - RGFW_MEMCPY(monitor.name, name, 6); - - CGRect bounds = CGDisplayBounds(display); - monitor.x = (i32)bounds.origin.x; - monitor.y = (i32)bounds.origin.y; - monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height); - - monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8; - - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); - monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode); - CFRelease(mode); - - CGSize screenSizeMM = CGDisplayScreenSize(display); - monitor.physW = (float)screenSizeMM.width / 25.4f; - monitor.physH = (float)screenSizeMM.height / 25.4f; - - float ppi_width = (monitor.mode.area.w/monitor.physW); - float ppi_height = (monitor.mode.area.h/monitor.physH); - - monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor")); - float dpi = 96.0f * monitor.pixelRatio; - - monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f; - monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f; - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); - return monitor; -} - - -RGFW_monitor* RGFW_getMonitors(size_t* len) { - static CGDirectDisplayID displays[7]; - u32 count; - - if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess) - return NULL; - - if (count > 6) count = 6; - - static RGFW_monitor monitors[7]; - - u32 i; - for (i = 0; i < count; i++) - monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i])); - - if (len != NULL) *len = count; - return monitors; -} - -RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - CGPoint point = { mon.x, mon.y }; - - CGDirectDisplayID display; - uint32_t displayCount = 0; - CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount); - if (err != kCGErrorSuccess || displayCount != 1) - return RGFW_FALSE; - - CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); - - if (allModes == NULL) - return RGFW_FALSE; - - CFIndex i; - for (i = 0; i < CFArrayGetCount(allModes); i++) { - CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); - - RGFW_monitorMode foundMode; - foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode)); - foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); - foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; - - if (RGFW_monitorModeCompare(mode, foundMode, request)) { - if (CGDisplaySetDisplayMode(display, cmode, NULL) == kCGErrorSuccess) { - CFRelease(allModes); - return RGFW_TRUE; - } - break; - } - } - - CFRelease(allModes); - - return RGFW_FALSE; -} - -RGFW_monitor RGFW_getPrimaryMonitor(void) { - CGDirectDisplayID primary = CGMainDisplayID(); - return RGFW_NSCreateMonitor(primary, RGFW_getNSScreenForDisplayID(primary)); -} - -RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { - id screen = objc_msgSend_id(win->src.window, sel_registerName("screen")); - id description = objc_msgSend_id(screen, sel_registerName("deviceDescription")); - id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber"); - id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey); - - CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")); - - return RGFW_NSCreateMonitor(display, screen); -} - -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - size_t clip_len; - char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len); - if (clip == NULL) return -1; - - if (str != NULL) { - if (strCapacity < clip_len) - return 0; - - RGFW_MEMCPY(str, clip, clip_len); - - str[clip_len] = '\0'; - } - - return (RGFW_ssize_t)clip_len; -} - -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_UNUSED(textLen); - - NSPasteboardType array[] = { NSPasteboardTypeString, NULL }; - NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL); - - SEL func = sel_registerName("setString:forType:"); - ((bool (*)(id, SEL, id, id))objc_msgSend) - (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString)); -} - - #ifdef RGFW_OPENGL - void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - if (win != NULL) - objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); - else - objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext")); - } - void* RGFW_getCurrent_OpenGL(void) { - return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); - } - - void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { - objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer")); - } - #endif - - #if !defined(RGFW_EGL) - - void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL); - #if defined(RGFW_OPENGL) - - NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222); - #else - RGFW_UNUSED(swapInterval); - #endif - } - - #endif - -void RGFW_window_swapBuffers_software(RGFW_window* win) { -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - RGFW_RGB_to_BGR(win, win->buffer); - i32 channels = 4; - id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc")); - NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h}; - image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size); - - id rep = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false, - "NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w * (u32)channels, 8 * (u32)channels); - ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep); - - id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); - ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES); - id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer")); - - ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image); - ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES); - - NSRelease(rep); - NSRelease(image); -#else - RGFW_UNUSED(win); -#endif -} - -void RGFW_deinit(void) { - _RGFW.windowCount = -1; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); -} - -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - NSRelease(win->src.view); - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - #endif - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } -} - -u64 RGFW_getTimerFreq(void) { - static u64 freq = 0; - if (freq == 0) { - mach_timebase_info_data_t info; - mach_timebase_info(&info); - freq = (u64)((info.denom * 1e9) / info.numer); - } - - return freq; -} - -u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); } - -#endif /* RGFW_MACOS */ - -/* - End of MaOS defines -*/ - -/* - WASM defines -*/ - -#ifdef RGFW_WASM -EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root); - RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, E->windowInnerWidth, E->windowInnerHeight)); - return EM_TRUE; -} - -EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - static u8 fullscreen = RGFW_FALSE; - static RGFW_rect ogRect; - - if (fullscreen == RGFW_FALSE) { - ogRect = _RGFW.root->r; - } - - fullscreen = !fullscreen; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root); - _RGFW.root->r = RGFW_RECT(0, 0, E->screenWidth, E->screenHeight); - - EM_ASM("Module.canvas.focus();"); - - if (fullscreen == RGFW_FALSE) { - _RGFW.root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h); - /* emscripten_request_fullscreen("#canvas", 0); */ - } else { - #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0 - EmscriptenFullscreenStrategy FSStrat = {0}; - FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */ - FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; - FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; - emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat); - #else - emscripten_request_fullscreen("#canvas", 1); - #endif - } - - emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h); - - RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r); - return EM_TRUE; -} - - - -EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); - - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = _RGFW.root); - _RGFW.root->_flags |= RGFW_windowFocus; - RGFW_focusCallback(_RGFW.root, 1); - - RGFW_resetKey(); - if ((_RGFW.root->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(_RGFW.root, RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h)); - return EM_TRUE; -} - -EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); - - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = _RGFW.root); - _RGFW.root->_flags &= ~(u32)RGFW_windowFocus; - RGFW_focusCallback(_RGFW.root, 0); - return EM_TRUE; -} - -EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.point = RGFW_POINT(E->targetX, E->targetY); - e.vector = RGFW_POINT(E->movementX, E->movementY); - e._win = _RGFW.root); - - _RGFW.root->_lastMousePoint = RGFW_POINT(E->targetX, E->targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->targetX, E->targetY), RGFW_POINT(E->movementX, E->movementY)); - return EM_TRUE; -} - -EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - int button = E->button; - if (button > 2) - button += 2; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.point = RGFW_POINT(E->targetX, E->targetY); - e.vector = RGFW_POINT(E->movementX, E->movementY); - e.button = (u8)button; - e.scroll = 0; - e._win = _RGFW.root); - RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; - RGFW_mouseButtons[button].current = 1; - - RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1); - return EM_TRUE; -} - -EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - int button = E->button; - if (button > 2) - button += 2; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; - e.point = RGFW_POINT(E->targetX, E->targetY); - e.vector = RGFW_POINT(E->movementX, E->movementY); - e.button = (u8)button; - e.scroll = 0; - e._win = _RGFW.root); - RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; - RGFW_mouseButtons[button].current = 0; - - RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0); - return EM_TRUE; -} - -EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - int button = RGFW_mouseScrollUp + (E->deltaY < 0); - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.button = (u8)button; - e.scroll = (double)(E->deltaY < 0 ? 1 : -1); - e._win = _RGFW.root); - RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; - RGFW_mouseButtons[button].current = 1; - RGFW_mouseButtonCallback(_RGFW.root, button, E->deltaY < 0 ? 1 : -1, 1); - - return EM_TRUE; -} - -EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - size_t i; - for (i = 0; i < (size_t)E->numTouches; i++) { - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - e.button = RGFW_mouseLeft; - e._win = _RGFW.root); - - RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current; - RGFW_mouseButtons[RGFW_mouseLeft].current = 1; - - _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); - RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1); - } - - return EM_TRUE; -} -EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - size_t i; - for (i = 0; i < (size_t)E->numTouches; i++) { - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - e.button = RGFW_mouseLeft; - e._win = _RGFW.root); - - _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); - } - return EM_TRUE; -} - -EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - size_t i; - for (i = 0; i < (size_t)E->numTouches; i++) { - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; - e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - e.button = RGFW_mouseLeft; - e._win = _RGFW.root); - - RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current; - RGFW_mouseButtons[RGFW_mouseLeft].current = 0; - - _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); - RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0); - } - return EM_TRUE; -} - -EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; } - -EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - if (gamepadEvent->index >= 4) - return 0; - - size_t i = gamepadEvent->index; - if (gamepadEvent->connected) { - RGFW_STRNCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1); - RGFW_gamepads_name[gamepadEvent->index][sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1] = '\0'; - RGFW_gamepads_type[i] = RGFW_gamepadUnknown; - if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box")) - RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5")) - RGFW_gamepads_type[i] = RGFW_gamepadSony; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo")) - RGFW_gamepads_type[i] = RGFW_gamepadNintendo; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech")) - RGFW_gamepads_type[i] = RGFW_gamepadLogitech; - RGFW_gamepadCount++; - } else { - RGFW_gamepadCount--; - } - - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected); - e.gamepad = (u16)gamepadEvent->index; - e._win = _RGFW.root); - - RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected); - RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected; - - return 1; /* The event was consumed by the callback handler */ -} - -u32 RGFW_wASMPhysicalToRGFW(u32 hash) { - switch(hash) { /* 0x0000 */ - case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */ - case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */ - case 0x67251059U /* Digit1 */: return RGFW_1; /* 0x0003 */ - case 0x6725105AU /* Digit2 */: return RGFW_2; /* 0x0004 */ - case 0x6725105BU /* Digit3 */: return RGFW_3; /* 0x0005 */ - case 0x6725105CU /* Digit4 */: return RGFW_4; /* 0x0006 */ - case 0x6725105DU /* Digit5 */: return RGFW_5; /* 0x0007 */ - case 0x6725105EU /* Digit6 */: return RGFW_6; /* 0x0008 */ - case 0x6725105FU /* Digit7 */: return RGFW_7; /* 0x0009 */ - case 0x67251050U /* Digit8 */: return RGFW_8; /* 0x000A */ - case 0x67251051U /* Digit9 */: return RGFW_9; /* 0x000B */ - case 0x92E14DD3U /* Minus */: return RGFW_minus; /* 0x000C */ - case 0x92E1FBACU /* Equal */: return RGFW_equals; /* 0x000D */ - case 0x36BF1CB5U /* Backspace */: return RGFW_backSpace; /* 0x000E */ - case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */ - case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */ - case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */ - case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */ - case 0x2C595B52U /* KeyR */: return RGFW_r; /* 0x0013 */ - case 0x2C595B54U /* KeyT */: return RGFW_t; /* 0x0014 */ - case 0x2C595B59U /* KeyY */: return RGFW_y; /* 0x0015 */ - case 0x2C595B55U /* KeyU */: return RGFW_u; /* 0x0016 */ - case 0x2C595B4FU /* KeyO */: return RGFW_o; /* 0x0018 */ - case 0x2C595B50U /* KeyP */: return RGFW_p; /* 0x0019 */ - case 0x45D8158CU /* BracketLeft */: return RGFW_closeBracket; /* 0x001A */ - case 0xDEEABF7CU /* BracketRight */: return RGFW_bracket; /* 0x001B */ - case 0x92E1C5D2U /* Enter */: return RGFW_return; /* 0x001C */ - case 0xE058958CU /* ControlLeft */: return RGFW_controlL; /* 0x001D */ - case 0x2C595B41U /* KeyA */: return RGFW_a; /* 0x001E */ - case 0x2C595B53U /* KeyS */: return RGFW_s; /* 0x001F */ - case 0x2C595B44U /* KeyD */: return RGFW_d; /* 0x0020 */ - case 0x2C595B46U /* KeyF */: return RGFW_f; /* 0x0021 */ - case 0x2C595B47U /* KeyG */: return RGFW_g; /* 0x0022 */ - case 0x2C595B48U /* KeyH */: return RGFW_h; /* 0x0023 */ - case 0x2C595B4AU /* KeyJ */: return RGFW_j; /* 0x0024 */ - case 0x2C595B4BU /* KeyK */: return RGFW_k; /* 0x0025 */ - case 0x2C595B4CU /* KeyL */: return RGFW_l; /* 0x0026 */ - case 0x2707219EU /* Semicolon */: return RGFW_semicolon; /* 0x0027 */ - case 0x92E0B58DU /* Quote */: return RGFW_apostrophe; /* 0x0028 */ - case 0x36BF358DU /* Backquote */: return RGFW_backtick; /* 0x0029 */ - case 0x26B1958CU /* ShiftLeft */: return RGFW_shiftL; /* 0x002A */ - case 0x36BF2438U /* Backslash */: return RGFW_backSlash; /* 0x002B */ - case 0x2C595B5AU /* KeyZ */: return RGFW_z; /* 0x002C */ - case 0x2C595B58U /* KeyX */: return RGFW_x; /* 0x002D */ - case 0x2C595B43U /* KeyC */: return RGFW_c; /* 0x002E */ - case 0x2C595B56U /* KeyV */: return RGFW_v; /* 0x002F */ - case 0x2C595B42U /* KeyB */: return RGFW_b; /* 0x0030 */ - case 0x2C595B4EU /* KeyN */: return RGFW_n; /* 0x0031 */ - case 0x2C595B4DU /* KeyM */: return RGFW_m; /* 0x0032 */ - case 0x92E1A1C1U /* Comma */: return RGFW_comma; /* 0x0033 */ - case 0x672FFAD4U /* Period */: return RGFW_period; /* 0x0034 */ - case 0x92E0A438U /* Slash */: return RGFW_slash; /* 0x0035 */ - case 0xC5A6BF7CU /* ShiftRight */: return RGFW_shiftR; - case 0x5D64DA91U /* NumpadMultiply */: return RGFW_multiply; - case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */ - case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */ - case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */ - case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */ - case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */ - case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */ - case 0x7174B78CU /* F4 */: return RGFW_F4; /* 0x003E */ - case 0x7174B78DU /* F5 */: return RGFW_F5; /* 0x003F */ - case 0x7174B78EU /* F6 */: return RGFW_F6; /* 0x0040 */ - case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */ - case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */ - case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */ - case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */ - case 0xC925FCDFU /* Numpad7 */: return RGFW_multiply; /* 0x0047 */ - case 0xC925FCD0U /* Numpad8 */: return RGFW_KP_8; /* 0x0048 */ - case 0xC925FCD1U /* Numpad9 */: return RGFW_KP_9; /* 0x0049 */ - case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_minus; /* 0x004A */ - case 0xC925FCDCU /* Numpad4 */: return RGFW_KP_4; /* 0x004B */ - case 0xC925FCDDU /* Numpad5 */: return RGFW_KP_5; /* 0x004C */ - case 0xC925FCDEU /* Numpad6 */: return RGFW_KP_6; /* 0x004D */ - case 0xC925FCD9U /* Numpad1 */: return RGFW_KP_1; /* 0x004F */ - case 0xC925FCDAU /* Numpad2 */: return RGFW_KP_2; /* 0x0050 */ - case 0xC925FCDBU /* Numpad3 */: return RGFW_KP_3; /* 0x0051 */ - case 0xC925FCD8U /* Numpad0 */: return RGFW_KP_0; /* 0x0052 */ - case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */ - case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */ - case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */ - case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return; - case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */ - case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */ - case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */ - case 0xC91BB690U /* ArrowUp */: return RGFW_up; /* 0xE048 */ - case 0x672F9210U /* PageUp */: return RGFW_pageUp; /* 0xE049 */ - case 0x3799258CU /* ArrowLeft */: return RGFW_left; /* 0xE04B */ - case 0x4CE33F7CU /* ArrowRight */: return RGFW_right; /* 0xE04D */ - case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */ - case 0x3799379EU /* ArrowDown */: return RGFW_down; /* 0xE050 */ - case 0xBA90179EU /* PageDown */: return RGFW_pageDown; /* 0xE051 */ - case 0x6723CB2CU /* Insert */: return RGFW_insert; /* 0xE052 */ - case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */ - case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */ - case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */ - } - - return 0; -} - -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) { - const char* iCode = code; - - u32 hash = 0; - while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; - - u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash); - - u8 mappedKey = (u8)(*((u32*)key)); - - if (*((u16*)key) != mappedKey) { - mappedKey = 0; - if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab; - } - - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased); - e.key = (u8)physicalKey; - e.keyChar = (u8)mappedKey; - e.keyMod = _RGFW.root->event.keyMod; - e._win = _RGFW.root); - - RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current; - RGFW_keyboard[physicalKey].current = press; - - RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press); -} - -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { - RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll); -} - -void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { - if (!(_RGFW.root->_flags & RGFW_windowAllowDND)) - return; - - _RGFW.root->event.droppedFilesCount = count; - RGFW_eventQueuePushEx(e.type = RGFW_DND; - e.droppedFilesCount = count; - e._win = _RGFW.root); - RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count); -} - -RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE; -void RGFW_stopCheckEvents(void) { - RGFW_stopCheckEvents_bool = RGFW_TRUE; -} - -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); - if (waitMS == 0) return; - - u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6); - - while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS) - emscripten_sleep(0); - - RGFW_stopCheckEvents_bool = RGFW_FALSE; -} - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = buffer; - win->bufferSize = area; - #ifdef RGFW_OSMESA - win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #else - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ - #endif -} - -void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { - /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ - /* TODO: find a better way to do this - */ - RGFW_STRNCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH - 1); - _RGFW.root->event.droppedFiles[index][RGFW_MAX_PATH - 1] = '\0'; -} - -#include -#include -#include -#include - -void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } - -void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { - FILE* file = fopen(path, "w+"); - if (file == NULL) - return; - - fwrite(data, sizeof(char), len, file); - fclose(file); -} - -void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) { -#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER) - EmscriptenWebGLContextAttributes attrs; - attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth]; - attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha]; - attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil]; - attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples]; - attrs.premultipliedAlpha = EM_TRUE; - attrs.preserveDrawingBuffer = EM_FALSE; - - if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) - attrs.renderViaOffscreenBackBuffer = 0; - else - attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers]; - - attrs.failIfMajorPerformanceCaveat = EM_FALSE; - attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor]; - attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor]; - - attrs.enableExtensionsByDefault = EM_TRUE; - attrs.explicitSwapControl = EM_TRUE; - - emscripten_webgl_init_context_attributes(&attrs); - win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs); - emscripten_webgl_make_context_current(win->src.ctx); - - #ifdef LEGACY_GL_EMULATION - EM_ASM("Module.useWebGL = true; GLImmediate.init();"); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); - #endif - glViewport(0, 0, win->r.w, win->r.h); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA) - if (win->src.ctx == 0) return; - emscripten_webgl_destroy_context(win->src.ctx); - win->src.ctx = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA) - if(win->src.ctx == 0) return; - OSMesaDestroyContext(win->src.ctx); - win->src.ctx = 0; -#else - RGFW_UNUSED(win); -#endif -} - -i32 RGFW_init(void) { -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -2; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 0; -} - -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - RGFW_window_basic_init(win, rect, flags); - RGFW_window_initOpenGL(win, 0); - - #if defined(RGFW_WEBGPU) - win->src.ctx = wgpuCreateInstance(NULL); - win->src.device = emscripten_webgpu_get_device(); - win->src.queue = wgpuDeviceGetQueue(win->src.device); - #endif - - emscripten_set_canvas_element_size("#canvas", rect.w, rect.h); - emscripten_set_window_title(name); - - /* load callbacks */ - emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize); - emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange); - emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove); - emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); - emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); - emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); - emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); - emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); - emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); - emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); - emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); - emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); - emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad); - emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad); - - if (flags & RGFW_windowAllowDND) { - win->_flags |= RGFW_windowAllowDND; - } - - EM_ASM({ - window.addEventListener("keydown", - (event) => { - var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); - Module._RGFW_handleKeyEvent(key, code, 1); - _free(key); _free(code); - }, - true); - window.addEventListener("keyup", - (event) => { - var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); - Module._RGFW_handleKeyEvent(key, code, 0); - _free(key); _free(code); - }, - true); - }); - - EM_ASM({ - var canvas = document.getElementById('canvas'); - canvas.addEventListener('drop', function(e) { - e.preventDefault(); - if (e.dataTransfer.file < 0) - return; - - var filenamesArray = []; - var count = e.dataTransfer.files.length; - - /* Read and save the files to emscripten's files */ - var drop_dir = '.rgfw_dropped_files'; - Module._RGFW_mkdir(drop_dir); - - for (var i = 0; i < count; i++) { - var file = e.dataTransfer.files[i]; - - var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); - var reader = new FileReader(); - - reader.onloadend = (e) => { - if (reader.readyState != 2) { - out('failed to read dropped file: '+file.name+': '+reader.error); - } - else { - var data = e.target.result; - - _RGFW_writeFile(path, new Uint8Array(data), file.size); - } - }; - - reader.readAsArrayBuffer(file); - /* This works weird on modern opengl */ - var filename = stringToNewUTF8(path); - - filenamesArray.push(filename); - - Module._RGFW_makeSetValue(i, filename); - } - - Module._Emscripten_onDrop(count); - - for (var i = 0; i < count; ++i) { - _free(filenamesArray[i]); - } - }, true); - - canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); - }); - - RGFW_window_setFlags(win, flags); - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initBuffer(win); - } - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - return win; -} - -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) return ev; - - emscripten_sample_gamepad_data(); - /* check gamepads */ - int i; - for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) { - if (RGFW_gamepads[i] == 0) - continue; - EmscriptenGamepadEvent gamepadState; - - if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS) - break; - - /* Register buttons data for every connected gamepad */ - int j; - for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) { - u32 map[] = { - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, - RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, - RGFW_gamepadSelect, RGFW_gamepadStart, - RGFW_gamepadL3, RGFW_gamepadR3, - RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome - }; - - - u32 button = map[j]; - if (button == 404) - continue; - - if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) { - if (gamepadState.digitalButton[j]) - win->event.type = RGFW_gamepadButtonPressed; - else - win->event.type = RGFW_gamepadButtonReleased; - - win->event.gamepad = i; - win->event.button = map[j]; - - RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current; - RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j]; - - RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]); - return &win->event; - } - } - - for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) { - win->event.axisesCount = gamepadState.numAxes / 2; - if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) || - RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f) - ) { - - RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f); - RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f); - win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)]; - - win->event.type = RGFW_gamepadAxisMove; - win->event.gamepad = i; - win->event.whichAxis = j / 2; - - RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis); - return &win->event; - } - } - } - - return NULL; -} - -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { - RGFW_UNUSED(win); - emscripten_set_canvas_element_size("#canvas", a.w, a.h); -} - -/* NOTE: I don't know if this is possible */ -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } -/* this one might be possible but it looks iffy */ -RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; } - -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } -void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); } - -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { - static const char cursors[16][16] = { - "default", "default", "text", "crosshair", - "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", - "move", "not-allowed" - }; - - RGFW_UNUSED(win); - EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]); - return RGFW_TRUE; -} - -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); -} - -void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { - RGFW_window_showMouseFlags(win, show); - if (show) - RGFW_window_setMouseDefault(win); - else - EM_ASM(document.getElementById('canvas').style.cursor = 'none';); -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_point point; - point.x = EM_ASM_INT({ - return window.mouseX || 0; - }); - point.y = EM_ASM_INT({ - return window.mouseY || 0; - }); - return point; -} - -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { - RGFW_UNUSED(win); - - EM_ASM_({ - var canvas = document.getElementById('canvas'); - if ($0) { - canvas.style.pointerEvents = 'none'; - } else { - canvas.style.pointerEvents = 'auto'; - } - }, passthrough); -} - -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_UNUSED(textLen); - EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); -} - - -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); - /* - placeholder code for later - I'm not sure if this is possible do the the async stuff - */ - return 0; -} - -void RGFW_window_swapBuffers_software(RGFW_window* win) { -#if defined(RGFW_OSMESA) - EM_ASM_({ - var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); - let context = document.getElementById("canvas").getContext("2d"); - let image = context.getImageData(0, 0, $1, $2); - image.data.set(data); - context.putImageData(image, 0, $4 - $2); - }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h); -#elif defined(RGFW_BUFFER) - EM_ASM_({ - var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); - let context = document.getElementById("canvas").getContext("2d"); - let image = context.getImageData(0, 0, $1, $2); - image.data.set(data); - context.putImageData(image, 0, 0); - }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h); - emscripten_sleep(0); -#else - RGFW_UNUSED(win); -#endif -} - -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { -#if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER)) - if (win == NULL) - emscripten_webgl_make_context_current(0); - else - emscripten_webgl_make_context_current(win->src.ctx); -#endif -} - - -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { -#ifndef RGFW_WEBGPU - emscripten_webgl_commit_frame(); - -#endif - emscripten_sleep(0); -} - -#ifndef RGFW_WEBGPU -void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } -#endif - -#ifndef RGFW_EGL -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } -#endif - -void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); } - -void RGFW_window_close(RGFW_window* win) { - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - #endif - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } -} - -int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } -int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } - -RGFW_area RGFW_getScreenSize(void) { - return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight()); -} - -RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) { -#ifdef RGFW_OPENGL - return EM_ASM_INT({ - var ext = UTF8ToString($0, $1); - var canvas = document.querySelector('canvas'); - var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - if (!gl) return 0; - - var supported = gl.getSupportedExtensions(); - return supported && supported.includes(ext) ? 1 : 0; - }, extension, len); -#else - return RGFW_FALSE; -#endif -} - -RGFW_proc RGFW_getProcAddress(const char* procname) { -#ifdef RGFW_OPENGL - return (RGFW_proc)emscripten_webgl_get_proc_address(procname); -#else - return NULL -#endif -} - -void RGFW_sleep(u64 milisecond) { - emscripten_sleep(milisecond); -} - -u64 RGFW_getTimerFreq(void) { return (u64)1000; } -u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; } - -void RGFW_releaseCursor(RGFW_window* win) { - RGFW_UNUSED(win); - emscripten_exit_pointerlock(); -} - -void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { - RGFW_UNUSED(win); RGFW_UNUSED(r); - - emscripten_request_pointerlock("#canvas", 1); -} - - -void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_UNUSED(win); - emscripten_set_window_title(name); -} - -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - RGFW_area screen = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT(0, 0)); - RGFW_window_resize(win, screen); -} - -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - if (fullscreen) { - win->_flags |= RGFW_windowFullscreen; - EM_ASM( Module.requestFullscreen(false, true); ); - return; - } - win->_flags &= ~(u32)RGFW_windowFullscreen; - EM_ASM( Module.exitFullscreen(false, true); ); -} - -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - RGFW_UNUSED(win); - EM_ASM({ - var element = document.getElementById("canvas"); - if (element) - element.style.opacity = $1; - }, "elementId", opacity); -} - -/* unsupported functions */ -void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); } -void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); } -RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; } -RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; } -RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; } -void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } -void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); } -void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); } -void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); } -void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); } -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE; } -void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); } -void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); } -RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } -RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } -RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } -RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } -RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; } -#endif - -/* end of web asm defines */ - -/* unix (macOS, linux, web asm) only stuff */ -#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) -#ifndef RGFW_NO_THREADS -#include - -RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { - RGFW_thread t; - pthread_create((pthread_t*) &t, NULL, *ptr, args); - return t; -} -void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); } -void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); } - -#if defined(__linux__) -void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); } -#else -void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(thread); RGFW_UNUSED(priority); } -#endif -#endif - -#ifndef RGFW_WASM -void RGFW_sleep(u64 ms) { - struct timespec time; - time.tv_sec = 0; - time.tv_nsec = (long int)((double)ms * 1e+6); - - #ifndef RGFW_NO_UNIX_CLOCK - nanosleep(&time, NULL); - #endif -} -#endif - -#endif /* end of unix / mac stuff */ -#endif /* RGFW_IMPLEMENTATION */ - -#if defined(__cplusplus) && !defined(__EMSCRIPTEN__) -} -#endif - -#if _MSC_VER - #pragma warning( pop ) -#endif diff --git a/raylib/external/android/native_app_glue/vendor.go b/raylib/external/android/native_app_glue/vendor.go deleted file mode 100644 index 0fb2a0f..0000000 --- a/raylib/external/android/native_app_glue/vendor.go +++ /dev/null @@ -1,4 +0,0 @@ -//go:build required -// +build required - -package vendor diff --git a/raylib/external/cgltf.h b/raylib/external/cgltf.h index 36fd644..4cc2d7e 100644 --- a/raylib/external/cgltf.h +++ b/raylib/external/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.14 + * Version: 1.10 * * Website: https://github.com/jkuhlmann/cgltf * @@ -63,15 +63,9 @@ * By passing null for the output pointer, users can find out how many floats are required in the * output buffer. * - * `cgltf_accessor_unpack_indices` reads in the index data from an accessor. Assumes that - * `cgltf_load_buffers` has already been called. By passing null for the output pointer, users can - * find out how many indices are required in the output buffer. Returns 0 if the accessor is - * sparse or if the output component size is less than the accessor's component size. - * - * `cgltf_num_components` is a tiny utility that tells you the dimensionality of + * `cgltf_accessor_num_components` is a tiny utility that tells you the dimensionality of * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate - * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for - * similar purposes. + * the necessary amount of memory. * * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element @@ -80,29 +74,31 @@ * * `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading * vector types and does not support matrix types. The passed-in element size is the number of uints - * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in + * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in * element_size is too small, or if the accessor is sparse. * * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t * and only works with single-component data types. * - * `cgltf_copy_extras_json` allows users to retrieve the "extras" data that can be attached to many - * glTF objects (which can be arbitrary JSON data). This is a legacy function, consider using - * cgltf_extras::data directly instead. You can parse this data using your own JSON parser + * `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*, + * char* dest, cgltf_size* dest_size)` allows users to retrieve the "extras" data that + * can be attached to many glTF objects (which can be arbitrary JSON data). The + * `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data + * as it appears in the complete glTF JSON data. This function copies the extras data + * into the provided buffer. If `dest` is NULL, the length of the data is written into + * `dest_size`. You can then parse this data using your own JSON parser * or, if you've included the cgltf implementation using the integrated JSMN JSON parser. */ #ifndef CGLTF_H_INCLUDED__ #define CGLTF_H_INCLUDED__ #include -#include /* For uint8_t, uint32_t */ #ifdef __cplusplus extern "C" { #endif typedef size_t cgltf_size; -typedef long long int cgltf_ssize; typedef float cgltf_float; typedef int cgltf_int; typedef unsigned int cgltf_uint; @@ -113,7 +109,6 @@ typedef enum cgltf_file_type cgltf_file_type_invalid, cgltf_file_type_gltf, cgltf_file_type_glb, - cgltf_file_type_max_enum } cgltf_file_type; typedef enum cgltf_result @@ -128,13 +123,12 @@ typedef enum cgltf_result cgltf_result_io_error, cgltf_result_out_of_memory, cgltf_result_legacy_gltf, - cgltf_result_max_enum } cgltf_result; typedef struct cgltf_memory_options { - void* (*alloc_func)(void* user, cgltf_size size); - void (*free_func) (void* user, void* ptr); + void* (*alloc)(void* user, cgltf_size size); + void (*free) (void* user, void* ptr); void* user_data; } cgltf_memory_options; @@ -158,7 +152,6 @@ typedef enum cgltf_buffer_view_type cgltf_buffer_view_type_invalid, cgltf_buffer_view_type_indices, cgltf_buffer_view_type_vertices, - cgltf_buffer_view_type_max_enum } cgltf_buffer_view_type; typedef enum cgltf_attribute_type @@ -171,8 +164,6 @@ typedef enum cgltf_attribute_type cgltf_attribute_type_color, cgltf_attribute_type_joints, cgltf_attribute_type_weights, - cgltf_attribute_type_custom, - cgltf_attribute_type_max_enum } cgltf_attribute_type; typedef enum cgltf_component_type @@ -184,7 +175,6 @@ typedef enum cgltf_component_type cgltf_component_type_r_16u, /* UNSIGNED_SHORT */ cgltf_component_type_r_32u, /* UNSIGNED_INT */ cgltf_component_type_r_32f, /* FLOAT */ - cgltf_component_type_max_enum } cgltf_component_type; typedef enum cgltf_type @@ -197,12 +187,10 @@ typedef enum cgltf_type cgltf_type_mat2, cgltf_type_mat3, cgltf_type_mat4, - cgltf_type_max_enum } cgltf_type; typedef enum cgltf_primitive_type { - cgltf_primitive_type_invalid, cgltf_primitive_type_points, cgltf_primitive_type_lines, cgltf_primitive_type_line_loop, @@ -210,7 +198,6 @@ typedef enum cgltf_primitive_type cgltf_primitive_type_triangles, cgltf_primitive_type_triangle_strip, cgltf_primitive_type_triangle_fan, - cgltf_primitive_type_max_enum } cgltf_primitive_type; typedef enum cgltf_alpha_mode @@ -218,7 +205,6 @@ typedef enum cgltf_alpha_mode cgltf_alpha_mode_opaque, cgltf_alpha_mode_mask, cgltf_alpha_mode_blend, - cgltf_alpha_mode_max_enum } cgltf_alpha_mode; typedef enum cgltf_animation_path_type { @@ -227,21 +213,18 @@ typedef enum cgltf_animation_path_type { cgltf_animation_path_type_rotation, cgltf_animation_path_type_scale, cgltf_animation_path_type_weights, - cgltf_animation_path_type_max_enum } cgltf_animation_path_type; typedef enum cgltf_interpolation_type { cgltf_interpolation_type_linear, cgltf_interpolation_type_step, cgltf_interpolation_type_cubic_spline, - cgltf_interpolation_type_max_enum } cgltf_interpolation_type; typedef enum cgltf_camera_type { cgltf_camera_type_invalid, cgltf_camera_type_perspective, cgltf_camera_type_orthographic, - cgltf_camera_type_max_enum } cgltf_camera_type; typedef enum cgltf_light_type { @@ -249,21 +232,11 @@ typedef enum cgltf_light_type { cgltf_light_type_directional, cgltf_light_type_point, cgltf_light_type_spot, - cgltf_light_type_max_enum } cgltf_light_type; -typedef enum cgltf_data_free_method { - cgltf_data_free_method_none, - cgltf_data_free_method_file_release, - cgltf_data_free_method_memory_free, - cgltf_data_free_method_max_enum -} cgltf_data_free_method; - typedef struct cgltf_extras { - cgltf_size start_offset; /* this field is deprecated and will be removed in the future; use data instead */ - cgltf_size end_offset; /* this field is deprecated and will be removed in the future; use data instead */ - - char* data; + cgltf_size start_offset; + cgltf_size end_offset; } cgltf_extras; typedef struct cgltf_extension { @@ -277,7 +250,6 @@ typedef struct cgltf_buffer cgltf_size size; char* uri; void* data; /* loaded by cgltf_load_buffers */ - cgltf_data_free_method data_free_method; cgltf_extras extras; cgltf_size extensions_count; cgltf_extension* extensions; @@ -288,7 +260,6 @@ typedef enum cgltf_meshopt_compression_mode { cgltf_meshopt_compression_mode_attributes, cgltf_meshopt_compression_mode_triangles, cgltf_meshopt_compression_mode_indices, - cgltf_meshopt_compression_mode_max_enum } cgltf_meshopt_compression_mode; typedef enum cgltf_meshopt_compression_filter { @@ -296,7 +267,6 @@ typedef enum cgltf_meshopt_compression_filter { cgltf_meshopt_compression_filter_octahedral, cgltf_meshopt_compression_filter_quaternion, cgltf_meshopt_compression_filter_exponential, - cgltf_meshopt_compression_filter_max_enum } cgltf_meshopt_compression_filter; typedef struct cgltf_meshopt_compression @@ -334,6 +304,15 @@ typedef struct cgltf_accessor_sparse cgltf_component_type indices_component_type; cgltf_buffer_view* values_buffer_view; cgltf_size values_byte_offset; + cgltf_extras extras; + cgltf_extras indices_extras; + cgltf_extras values_extras; + cgltf_size extensions_count; + cgltf_extension* extensions; + cgltf_size indices_extensions_count; + cgltf_extension* indices_extensions; + cgltf_size values_extensions_count; + cgltf_extension* values_extensions; } cgltf_accessor_sparse; typedef struct cgltf_accessor @@ -393,10 +372,6 @@ typedef struct cgltf_texture char* name; cgltf_image* image; cgltf_sampler* sampler; - cgltf_bool has_basisu; - cgltf_image* basisu_image; - cgltf_bool has_webp; - cgltf_image* webp_image; cgltf_extras extras; cgltf_size extensions_count; cgltf_extension* extensions; @@ -407,7 +382,6 @@ typedef struct cgltf_texture_transform cgltf_float offset[2]; cgltf_float rotation; cgltf_float scale[2]; - cgltf_bool has_texcoord; cgltf_int texcoord; } cgltf_texture_transform; @@ -418,6 +392,9 @@ typedef struct cgltf_texture_view cgltf_float scale; /* equivalent to strength for occlusion_texture */ cgltf_bool has_transform; cgltf_texture_transform transform; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; } cgltf_texture_view; typedef struct cgltf_pbr_metallic_roughness @@ -428,6 +405,8 @@ typedef struct cgltf_pbr_metallic_roughness cgltf_float base_color_factor[4]; cgltf_float metallic_factor; cgltf_float roughness_factor; + + cgltf_extras extras; } cgltf_pbr_metallic_roughness; typedef struct cgltf_pbr_specular_glossiness @@ -485,33 +464,6 @@ typedef struct cgltf_sheen cgltf_float sheen_roughness_factor; } cgltf_sheen; -typedef struct cgltf_emissive_strength -{ - cgltf_float emissive_strength; -} cgltf_emissive_strength; - -typedef struct cgltf_iridescence -{ - cgltf_float iridescence_factor; - cgltf_texture_view iridescence_texture; - cgltf_float iridescence_ior; - cgltf_float iridescence_thickness_min; - cgltf_float iridescence_thickness_max; - cgltf_texture_view iridescence_thickness_texture; -} cgltf_iridescence; - -typedef struct cgltf_anisotropy -{ - cgltf_float anisotropy_strength; - cgltf_float anisotropy_rotation; - cgltf_texture_view anisotropy_texture; -} cgltf_anisotropy; - -typedef struct cgltf_dispersion -{ - cgltf_float dispersion; -} cgltf_dispersion; - typedef struct cgltf_material { char* name; @@ -523,10 +475,6 @@ typedef struct cgltf_material cgltf_bool has_ior; cgltf_bool has_specular; cgltf_bool has_sheen; - cgltf_bool has_emissive_strength; - cgltf_bool has_iridescence; - cgltf_bool has_anisotropy; - cgltf_bool has_dispersion; cgltf_pbr_metallic_roughness pbr_metallic_roughness; cgltf_pbr_specular_glossiness pbr_specular_glossiness; cgltf_clearcoat clearcoat; @@ -535,10 +483,6 @@ typedef struct cgltf_material cgltf_sheen sheen; cgltf_transmission transmission; cgltf_volume volume; - cgltf_emissive_strength emissive_strength; - cgltf_iridescence iridescence; - cgltf_anisotropy anisotropy; - cgltf_dispersion dispersion; cgltf_texture_view normal_texture; cgltf_texture_view occlusion_texture; cgltf_texture_view emissive_texture; @@ -570,11 +514,6 @@ typedef struct cgltf_draco_mesh_compression { cgltf_size attributes_count; } cgltf_draco_mesh_compression; -typedef struct cgltf_mesh_gpu_instancing { - cgltf_attribute* attributes; - cgltf_size attributes_count; -} cgltf_mesh_gpu_instancing; - typedef struct cgltf_primitive { cgltf_primitive_type type; cgltf_accessor* indices; @@ -656,7 +595,6 @@ typedef struct cgltf_light { cgltf_float range; cgltf_float spot_inner_cone_angle; cgltf_float spot_outer_cone_angle; - cgltf_extras extras; } cgltf_light; struct cgltf_node { @@ -679,8 +617,6 @@ struct cgltf_node { cgltf_float scale[3]; cgltf_float matrix[16]; cgltf_extras extras; - cgltf_bool has_mesh_gpu_instancing; - cgltf_mesh_gpu_instancing mesh_gpu_instancing; cgltf_size extensions_count; cgltf_extension* extensions; }; @@ -832,8 +768,7 @@ cgltf_result cgltf_load_buffers( cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data); -cgltf_size cgltf_decode_string(char* string); -cgltf_size cgltf_decode_uri(char* uri); +void cgltf_decode_uri(char* uri); cgltf_result cgltf_validate(cgltf_data* data); @@ -842,39 +777,16 @@ void cgltf_free(cgltf_data* data); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); -const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view); - cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size); cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size); cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); cgltf_size cgltf_num_components(cgltf_type type); -cgltf_size cgltf_component_size(cgltf_component_type component_type); -cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count); -cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count); -/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); -cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object); -cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object); -cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object); -cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object); -cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object); -cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object); -cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object); -cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object); -cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object); -cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object); -cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object); -cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object); -cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object); -cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object); -cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object); -cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object); - #ifdef __cplusplus } #endif @@ -895,13 +807,13 @@ cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const #ifdef CGLTF_IMPLEMENTATION -#include /* For assert */ +#include /* For uint8_t, uint32_t */ #include /* For strncpy */ #include /* For fopen */ #include /* For UINT_MAX etc */ #include /* For FLT_MAX */ -#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF) || !defined(CGLTF_ATOLL) +#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF) #include /* For malloc, free, atoi, atof */ #endif @@ -933,15 +845,15 @@ enum jsmnerr { }; typedef struct { jsmntype_t type; - ptrdiff_t start; - ptrdiff_t end; + int start; + int end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; typedef struct { - size_t pos; /* offset in the JSON string */ + unsigned int pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; @@ -952,15 +864,12 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t */ -#ifndef CGLTF_CONSTS -#define GlbHeaderSize 12 -#define GlbChunkHeaderSize 8 +static const cgltf_size GlbHeaderSize = 12; +static const cgltf_size GlbChunkHeaderSize = 8; static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; static const uint32_t GlbMagicBinChunk = 0x004E4942; -#define CGLTF_CONSTS -#endif #ifndef CGLTF_MALLOC #define CGLTF_MALLOC(size) malloc(size) @@ -974,9 +883,6 @@ static const uint32_t GlbMagicBinChunk = 0x004E4942; #ifndef CGLTF_ATOF #define CGLTF_ATOF(str) atof(str) #endif -#ifndef CGLTF_ATOLL -#define CGLTF_ATOLL(str) atoll(str) -#endif #ifndef CGLTF_VALIDATE_ENABLE_ASSERTS #define CGLTF_VALIDATE_ENABLE_ASSERTS 0 #endif @@ -999,7 +905,7 @@ static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_siz { return NULL; } - void* result = options->memory.alloc_func(options->memory.user_data, element_size * count); + void* result = options->memory.alloc(options->memory.user_data, element_size * count); if (!result) { return NULL; @@ -1011,8 +917,8 @@ static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_siz static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data) { (void)file_options; - void* (*memory_alloc)(void*, cgltf_size) = memory_options->alloc_func ? memory_options->alloc_func : &cgltf_default_alloc; - void (*memory_free)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free; + void* (*memory_alloc)(void*, cgltf_size) = memory_options->alloc ? memory_options->alloc : &cgltf_default_alloc; + void (*memory_free)(void*, void*) = memory_options->free ? memory_options->free : &cgltf_default_free; FILE* file = fopen(path, "rb"); if (!file) @@ -1026,12 +932,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m { fseek(file, 0, SEEK_END); -#ifdef _MSC_VER - __int64 length = _ftelli64(file); -#else long length = ftell(file); -#endif - if (length < 0) { fclose(file); @@ -1048,7 +949,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m fclose(file); return cgltf_result_out_of_memory; } - + cgltf_size read_size = fread(file_data, 1, file_size, file); fclose(file); @@ -1074,7 +975,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data) { (void)file_options; - void (*memfree)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free; + void (*memfree)(void*, void*) = memory_options->free ? memory_options->free : &cgltf_default_free; memfree(memory_options->user_data, data); } @@ -1093,13 +994,13 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s } cgltf_options fixed_options = *options; - if (fixed_options.memory.alloc_func == NULL) + if (fixed_options.memory.alloc == NULL) { - fixed_options.memory.alloc_func = &cgltf_default_alloc; + fixed_options.memory.alloc = &cgltf_default_alloc; } - if (fixed_options.memory.free_func == NULL) + if (fixed_options.memory.free == NULL) { - fixed_options.memory.free_func = &cgltf_default_free; + fixed_options.memory.free = &cgltf_default_free; } uint32_t tmp; @@ -1156,7 +1057,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s // JSON chunk: length uint32_t json_length; memcpy(&json_length, json_chunk, 4); - if (json_length > size - GlbHeaderSize - GlbChunkHeaderSize) + if (GlbHeaderSize + GlbChunkHeaderSize + json_length > size) { return cgltf_result_data_too_short; } @@ -1170,10 +1071,10 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s json_chunk += GlbChunkHeaderSize; - const void* bin = NULL; + const void* bin = 0; cgltf_size bin_size = 0; - if (GlbChunkHeaderSize <= size - GlbHeaderSize - GlbChunkHeaderSize - json_length) + if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize <= size) { // We can read another chunk const uint8_t* bin_chunk = json_chunk + json_length; @@ -1181,7 +1082,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s // Bin chunk: length uint32_t bin_length; memcpy(&bin_length, bin_chunk, 4); - if (bin_length > size - GlbHeaderSize - GlbChunkHeaderSize - json_length - GlbChunkHeaderSize) + if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize + bin_length > size) { return cgltf_result_data_too_short; } @@ -1219,8 +1120,8 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg return cgltf_result_invalid_options; } + void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free; cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read; - void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release; void* file_data = NULL; cgltf_size file_size = 0; @@ -1234,7 +1135,7 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg if (result != cgltf_result_success) { - file_release(&options->memory, &options->file, file_data); + memory_free(options->memory.user_data, file_data); return result; } @@ -1264,8 +1165,8 @@ static void cgltf_combine_paths(char* path, const char* base, const char* uri) static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data) { - void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc_func ? options->memory.alloc_func : &cgltf_default_alloc; - void (*memory_free)(void*, void*) = options->memory.free_func ? options->memory.free_func : &cgltf_default_free; + void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc ? options->memory.alloc : &cgltf_default_alloc; + void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free; cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read; char* path = (char*)memory_alloc(options->memory.user_data, strlen(uri) + strlen(gltf_path) + 1); @@ -1291,8 +1192,8 @@ static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_s cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data) { - void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc_func ? options->memory.alloc_func : &cgltf_default_alloc; - void (*memory_free)(void*, void*) = options->memory.free_func ? options->memory.free_func : &cgltf_default_free; + void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc ? options->memory.alloc : &cgltf_default_alloc; + void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free; unsigned char* data = (unsigned char*)memory_alloc(options->memory.user_data, size); if (!data) @@ -1345,78 +1246,7 @@ static int cgltf_unhex(char ch) -1; } -cgltf_size cgltf_decode_string(char* string) -{ - char* read = string + strcspn(string, "\\"); - if (*read == 0) - { - return read - string; - } - char* write = string; - char* last = string; - - for (;;) - { - // Copy characters since last escaped sequence - cgltf_size written = read - last; - memmove(write, last, written); - write += written; - - if (*read++ == 0) - { - break; - } - - // jsmn already checked that all escape sequences are valid - switch (*read++) - { - case '\"': *write++ = '\"'; break; - case '/': *write++ = '/'; break; - case '\\': *write++ = '\\'; break; - case 'b': *write++ = '\b'; break; - case 'f': *write++ = '\f'; break; - case 'r': *write++ = '\r'; break; - case 'n': *write++ = '\n'; break; - case 't': *write++ = '\t'; break; - case 'u': - { - // UCS-2 codepoint \uXXXX to UTF-8 - int character = 0; - for (cgltf_size i = 0; i < 4; ++i) - { - character = (character << 4) + cgltf_unhex(*read++); - } - - if (character <= 0x7F) - { - *write++ = character & 0xFF; - } - else if (character <= 0x7FF) - { - *write++ = 0xC0 | ((character >> 6) & 0xFF); - *write++ = 0x80 | (character & 0x3F); - } - else - { - *write++ = 0xE0 | ((character >> 12) & 0xFF); - *write++ = 0x80 | ((character >> 6) & 0x3F); - *write++ = 0x80 | (character & 0x3F); - } - break; - } - default: - break; - } - - last = read; - read += strcspn(read, "\\"); - } - - *write = 0; - return write - string; -} - -cgltf_size cgltf_decode_uri(char* uri) +void cgltf_decode_uri(char* uri) { char* write = uri; char* i = uri; @@ -1444,7 +1274,6 @@ cgltf_size cgltf_decode_uri(char* uri) } *write = 0; - return write - uri; } cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path) @@ -1462,7 +1291,6 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, } data->buffers[0].data = (void*)data->bin; - data->buffers[0].data_free_method = cgltf_data_free_method_none; } for (cgltf_size i = 0; i < data->buffers_count; ++i) @@ -1486,7 +1314,6 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0) { cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data); - data->buffers[i].data_free_method = cgltf_data_free_method_memory_free; if (res != cgltf_result_success) { @@ -1501,7 +1328,6 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, else if (strstr(uri, "://") == NULL && gltf_path) { cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data); - data->buffers[i].data_free_method = cgltf_data_free_method_file_release; if (res != cgltf_result_success) { @@ -1517,6 +1343,8 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, return cgltf_result_success; } +static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); + static cgltf_size cgltf_calc_index_bound(cgltf_buffer_view* buffer_view, cgltf_size offset, cgltf_component_type component_type, cgltf_size count) { char* data = (char*)buffer_view->buffer->data + offset + buffer_view->offset; @@ -1567,9 +1395,6 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_accessor* accessor = &data->accessors[i]; - CGLTF_ASSERT_IF(data->accessors[i].component_type == cgltf_component_type_invalid, cgltf_result_invalid_gltf); - CGLTF_ASSERT_IF(data->accessors[i].type == cgltf_type_invalid, cgltf_result_invalid_gltf); - cgltf_size element_size = cgltf_calc_size(accessor->type, accessor->component_type); if (accessor->buffer_view) @@ -1583,7 +1408,7 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_accessor_sparse* sparse = &accessor->sparse; - cgltf_size indices_component_size = cgltf_component_size(sparse->indices_component_type); + cgltf_size indices_component_size = cgltf_calc_size(cgltf_type_scalar, sparse->indices_component_type); cgltf_size indices_req_size = sparse->indices_byte_offset + indices_component_size * sparse->count; cgltf_size values_req_size = sparse->values_byte_offset + element_size * sparse->count; @@ -1649,48 +1474,43 @@ cgltf_result cgltf_validate(cgltf_data* data) for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j) { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].type == cgltf_primitive_type_invalid, cgltf_result_invalid_gltf); CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets_count != data->meshes[i].primitives[0].targets_count, cgltf_result_invalid_gltf); - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes_count == 0, cgltf_result_invalid_gltf); - - cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data; - - CGLTF_ASSERT_IF(first->count == 0, cgltf_result_invalid_gltf); - - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) + if (data->meshes[i].primitives[j].attributes_count) { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); - } + cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data; - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) - { - for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); } - } - cgltf_accessor* indices = data->meshes[i].primitives[j].indices; + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) + { + for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf); + } + } - CGLTF_ASSERT_IF(indices && - indices->component_type != cgltf_component_type_r_8u && - indices->component_type != cgltf_component_type_r_16u && - indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); + cgltf_accessor* indices = data->meshes[i].primitives[j].indices; - CGLTF_ASSERT_IF(indices && indices->type != cgltf_type_scalar, cgltf_result_invalid_gltf); - CGLTF_ASSERT_IF(indices && indices->stride != cgltf_component_size(indices->component_type), cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(indices && + indices->component_type != cgltf_component_type_r_8u && + indices->component_type != cgltf_component_type_r_16u && + indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); - if (indices && indices->buffer_view && indices->buffer_view->buffer->data) - { - cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count); + if (indices && indices->buffer_view && indices->buffer_view->buffer->data) + { + cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count); - CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short); - } + CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short); + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) - { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf); + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf); + } } } } @@ -1699,20 +1519,7 @@ cgltf_result cgltf_validate(cgltf_data* data) { if (data->nodes[i].weights && data->nodes[i].mesh) { - CGLTF_ASSERT_IF(data->nodes[i].mesh->primitives_count && data->nodes[i].mesh->primitives[0].targets_count != data->nodes[i].weights_count, cgltf_result_invalid_gltf); - } - - if (data->nodes[i].has_mesh_gpu_instancing) - { - CGLTF_ASSERT_IF(data->nodes[i].mesh == NULL, cgltf_result_invalid_gltf); - CGLTF_ASSERT_IF(data->nodes[i].mesh_gpu_instancing.attributes_count == 0, cgltf_result_invalid_gltf); - - cgltf_accessor* first = data->nodes[i].mesh_gpu_instancing.attributes[0].data; - - for (cgltf_size k = 0; k < data->nodes[i].mesh_gpu_instancing.attributes_count; ++k) - { - CGLTF_ASSERT_IF(data->nodes[i].mesh_gpu_instancing.attributes[k].data->count != first->count, cgltf_result_invalid_gltf); - } + CGLTF_ASSERT_IF (data->nodes[i].mesh->primitives_count && data->nodes[i].mesh->primitives[0].targets_count != data->nodes[i].weights_count, cgltf_result_invalid_gltf); } } @@ -1760,15 +1567,10 @@ cgltf_result cgltf_validate(cgltf_data* data) cgltf_size values = channel->sampler->interpolation == cgltf_interpolation_type_cubic_spline ? 3 : 1; - CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_data_too_short); } } - for (cgltf_size i = 0; i < data->variants_count; ++i) - { - CGLTF_ASSERT_IF(!data->variants[i].name, cgltf_result_invalid_gltf); - } - return cgltf_result_success; } @@ -1800,19 +1602,14 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* return cgltf_result_success; } -static void cgltf_free_extras(cgltf_data* data, cgltf_extras* extras) -{ - data->memory.free_func(data->memory.user_data, extras->data); -} - -static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count) +void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count) { for (cgltf_size i = 0; i < extensions_count; ++i) { - data->memory.free_func(data->memory.user_data, extensions[i].name); - data->memory.free_func(data->memory.user_data, extensions[i].data); + data->memory.free(data->memory.user_data, extensions[i].name); + data->memory.free(data->memory.user_data, extensions[i].data); } - data->memory.free_func(data->memory.user_data, extensions); + data->memory.free(data->memory.user_data, extensions); } void cgltf_free(cgltf_data* data) @@ -1824,281 +1621,272 @@ void cgltf_free(cgltf_data* data) void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = data->file.release ? data->file.release : cgltf_default_file_release; - data->memory.free_func(data->memory.user_data, data->asset.copyright); - data->memory.free_func(data->memory.user_data, data->asset.generator); - data->memory.free_func(data->memory.user_data, data->asset.version); - data->memory.free_func(data->memory.user_data, data->asset.min_version); + data->memory.free(data->memory.user_data, data->asset.copyright); + data->memory.free(data->memory.user_data, data->asset.generator); + data->memory.free(data->memory.user_data, data->asset.version); + data->memory.free(data->memory.user_data, data->asset.min_version); cgltf_free_extensions(data, data->asset.extensions, data->asset.extensions_count); - cgltf_free_extras(data, &data->asset.extras); for (cgltf_size i = 0; i < data->accessors_count; ++i) { - data->memory.free_func(data->memory.user_data, data->accessors[i].name); + data->memory.free(data->memory.user_data, data->accessors[i].name); + if(data->accessors[i].is_sparse) + { + cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count); + cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count); + cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count); + } cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count); - cgltf_free_extras(data, &data->accessors[i].extras); } - data->memory.free_func(data->memory.user_data, data->accessors); + data->memory.free(data->memory.user_data, data->accessors); for (cgltf_size i = 0; i < data->buffer_views_count; ++i) { - data->memory.free_func(data->memory.user_data, data->buffer_views[i].name); - data->memory.free_func(data->memory.user_data, data->buffer_views[i].data); + data->memory.free(data->memory.user_data, data->buffer_views[i].name); + data->memory.free(data->memory.user_data, data->buffer_views[i].data); cgltf_free_extensions(data, data->buffer_views[i].extensions, data->buffer_views[i].extensions_count); - cgltf_free_extras(data, &data->buffer_views[i].extras); } - data->memory.free_func(data->memory.user_data, data->buffer_views); + data->memory.free(data->memory.user_data, data->buffer_views); for (cgltf_size i = 0; i < data->buffers_count; ++i) { - data->memory.free_func(data->memory.user_data, data->buffers[i].name); + data->memory.free(data->memory.user_data, data->buffers[i].name); - if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release) + if (data->buffers[i].data != data->bin) { file_release(&data->memory, &data->file, data->buffers[i].data); } - else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free) - { - data->memory.free_func(data->memory.user_data, data->buffers[i].data); - } - - data->memory.free_func(data->memory.user_data, data->buffers[i].uri); + data->memory.free(data->memory.user_data, data->buffers[i].uri); cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count); - cgltf_free_extras(data, &data->buffers[i].extras); } - data->memory.free_func(data->memory.user_data, data->buffers); + + data->memory.free(data->memory.user_data, data->buffers); for (cgltf_size i = 0; i < data->meshes_count; ++i) { - data->memory.free_func(data->memory.user_data, data->meshes[i].name); + data->memory.free(data->memory.user_data, data->meshes[i].name); for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j) { for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) { - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].attributes[k].name); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].attributes[k].name); } - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].attributes); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].attributes); for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) { for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) { - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes[m].name); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes[m].name); } - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes); } - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].targets); if (data->meshes[i].primitives[j].has_draco_mesh_compression) { for (cgltf_size k = 0; k < data->meshes[i].primitives[j].draco_mesh_compression.attributes_count; ++k) { - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes[k].name); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes[k].name); } - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes); } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) - { - cgltf_free_extras(data, &data->meshes[i].primitives[j].mappings[k].extras); - } - - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].mappings); + data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].mappings); cgltf_free_extensions(data, data->meshes[i].primitives[j].extensions, data->meshes[i].primitives[j].extensions_count); - cgltf_free_extras(data, &data->meshes[i].primitives[j].extras); } - data->memory.free_func(data->memory.user_data, data->meshes[i].primitives); - data->memory.free_func(data->memory.user_data, data->meshes[i].weights); + data->memory.free(data->memory.user_data, data->meshes[i].primitives); + data->memory.free(data->memory.user_data, data->meshes[i].weights); for (cgltf_size j = 0; j < data->meshes[i].target_names_count; ++j) { - data->memory.free_func(data->memory.user_data, data->meshes[i].target_names[j]); + data->memory.free(data->memory.user_data, data->meshes[i].target_names[j]); } cgltf_free_extensions(data, data->meshes[i].extensions, data->meshes[i].extensions_count); - cgltf_free_extras(data, &data->meshes[i].extras); - data->memory.free_func(data->memory.user_data, data->meshes[i].target_names); + data->memory.free(data->memory.user_data, data->meshes[i].target_names); } - data->memory.free_func(data->memory.user_data, data->meshes); + data->memory.free(data->memory.user_data, data->meshes); for (cgltf_size i = 0; i < data->materials_count; ++i) { - data->memory.free_func(data->memory.user_data, data->materials[i].name); + data->memory.free(data->memory.user_data, data->materials[i].name); + + if(data->materials[i].has_pbr_metallic_roughness) + { + cgltf_free_extensions(data, data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.extensions, data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].pbr_metallic_roughness.base_color_texture.extensions, data->materials[i].pbr_metallic_roughness.base_color_texture.extensions_count); + } + if(data->materials[i].has_pbr_specular_glossiness) + { + cgltf_free_extensions(data, data->materials[i].pbr_specular_glossiness.diffuse_texture.extensions, data->materials[i].pbr_specular_glossiness.diffuse_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.extensions, data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.extensions_count); + } + if(data->materials[i].has_clearcoat) + { + cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_texture.extensions, data->materials[i].clearcoat.clearcoat_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_roughness_texture.extensions, data->materials[i].clearcoat.clearcoat_roughness_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_normal_texture.extensions, data->materials[i].clearcoat.clearcoat_normal_texture.extensions_count); + } + if(data->materials[i].has_specular) + { + cgltf_free_extensions(data, data->materials[i].specular.specular_texture.extensions, data->materials[i].specular.specular_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].specular.specular_color_texture.extensions, data->materials[i].specular.specular_color_texture.extensions_count); + } + if(data->materials[i].has_transmission) + { + cgltf_free_extensions(data, data->materials[i].transmission.transmission_texture.extensions, data->materials[i].transmission.transmission_texture.extensions_count); + } + if (data->materials[i].has_volume) + { + cgltf_free_extensions(data, data->materials[i].volume.thickness_texture.extensions, data->materials[i].volume.thickness_texture.extensions_count); + } + if(data->materials[i].has_sheen) + { + cgltf_free_extensions(data, data->materials[i].sheen.sheen_color_texture.extensions, data->materials[i].sheen.sheen_color_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].sheen.sheen_roughness_texture.extensions, data->materials[i].sheen.sheen_roughness_texture.extensions_count); + } + + cgltf_free_extensions(data, data->materials[i].normal_texture.extensions, data->materials[i].normal_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].occlusion_texture.extensions, data->materials[i].occlusion_texture.extensions_count); + cgltf_free_extensions(data, data->materials[i].emissive_texture.extensions, data->materials[i].emissive_texture.extensions_count); cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count); - cgltf_free_extras(data, &data->materials[i].extras); } - data->memory.free_func(data->memory.user_data, data->materials); + data->memory.free(data->memory.user_data, data->materials); - for (cgltf_size i = 0; i < data->images_count; ++i) + for (cgltf_size i = 0; i < data->images_count; ++i) { - data->memory.free_func(data->memory.user_data, data->images[i].name); - data->memory.free_func(data->memory.user_data, data->images[i].uri); - data->memory.free_func(data->memory.user_data, data->images[i].mime_type); + data->memory.free(data->memory.user_data, data->images[i].name); + data->memory.free(data->memory.user_data, data->images[i].uri); + data->memory.free(data->memory.user_data, data->images[i].mime_type); cgltf_free_extensions(data, data->images[i].extensions, data->images[i].extensions_count); - cgltf_free_extras(data, &data->images[i].extras); } - data->memory.free_func(data->memory.user_data, data->images); + data->memory.free(data->memory.user_data, data->images); for (cgltf_size i = 0; i < data->textures_count; ++i) { - data->memory.free_func(data->memory.user_data, data->textures[i].name); - + data->memory.free(data->memory.user_data, data->textures[i].name); cgltf_free_extensions(data, data->textures[i].extensions, data->textures[i].extensions_count); - cgltf_free_extras(data, &data->textures[i].extras); } - data->memory.free_func(data->memory.user_data, data->textures); + data->memory.free(data->memory.user_data, data->textures); for (cgltf_size i = 0; i < data->samplers_count; ++i) { - data->memory.free_func(data->memory.user_data, data->samplers[i].name); - + data->memory.free(data->memory.user_data, data->samplers[i].name); cgltf_free_extensions(data, data->samplers[i].extensions, data->samplers[i].extensions_count); - cgltf_free_extras(data, &data->samplers[i].extras); } - data->memory.free_func(data->memory.user_data, data->samplers); + data->memory.free(data->memory.user_data, data->samplers); for (cgltf_size i = 0; i < data->skins_count; ++i) { - data->memory.free_func(data->memory.user_data, data->skins[i].name); - data->memory.free_func(data->memory.user_data, data->skins[i].joints); + data->memory.free(data->memory.user_data, data->skins[i].name); + data->memory.free(data->memory.user_data, data->skins[i].joints); cgltf_free_extensions(data, data->skins[i].extensions, data->skins[i].extensions_count); - cgltf_free_extras(data, &data->skins[i].extras); } - data->memory.free_func(data->memory.user_data, data->skins); + data->memory.free(data->memory.user_data, data->skins); for (cgltf_size i = 0; i < data->cameras_count; ++i) { - data->memory.free_func(data->memory.user_data, data->cameras[i].name); - - if (data->cameras[i].type == cgltf_camera_type_perspective) - { - cgltf_free_extras(data, &data->cameras[i].data.perspective.extras); - } - else if (data->cameras[i].type == cgltf_camera_type_orthographic) - { - cgltf_free_extras(data, &data->cameras[i].data.orthographic.extras); - } - + data->memory.free(data->memory.user_data, data->cameras[i].name); cgltf_free_extensions(data, data->cameras[i].extensions, data->cameras[i].extensions_count); - cgltf_free_extras(data, &data->cameras[i].extras); } - data->memory.free_func(data->memory.user_data, data->cameras); + data->memory.free(data->memory.user_data, data->cameras); for (cgltf_size i = 0; i < data->lights_count; ++i) { - data->memory.free_func(data->memory.user_data, data->lights[i].name); - - cgltf_free_extras(data, &data->lights[i].extras); + data->memory.free(data->memory.user_data, data->lights[i].name); } - data->memory.free_func(data->memory.user_data, data->lights); + data->memory.free(data->memory.user_data, data->lights); for (cgltf_size i = 0; i < data->nodes_count; ++i) { - data->memory.free_func(data->memory.user_data, data->nodes[i].name); - data->memory.free_func(data->memory.user_data, data->nodes[i].children); - data->memory.free_func(data->memory.user_data, data->nodes[i].weights); - - if (data->nodes[i].has_mesh_gpu_instancing) - { - for (cgltf_size j = 0; j < data->nodes[i].mesh_gpu_instancing.attributes_count; ++j) - { - data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes[j].name); - } - - data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes); - } - + data->memory.free(data->memory.user_data, data->nodes[i].name); + data->memory.free(data->memory.user_data, data->nodes[i].children); + data->memory.free(data->memory.user_data, data->nodes[i].weights); cgltf_free_extensions(data, data->nodes[i].extensions, data->nodes[i].extensions_count); - cgltf_free_extras(data, &data->nodes[i].extras); } - data->memory.free_func(data->memory.user_data, data->nodes); + data->memory.free(data->memory.user_data, data->nodes); for (cgltf_size i = 0; i < data->scenes_count; ++i) { - data->memory.free_func(data->memory.user_data, data->scenes[i].name); - data->memory.free_func(data->memory.user_data, data->scenes[i].nodes); + data->memory.free(data->memory.user_data, data->scenes[i].name); + data->memory.free(data->memory.user_data, data->scenes[i].nodes); cgltf_free_extensions(data, data->scenes[i].extensions, data->scenes[i].extensions_count); - cgltf_free_extras(data, &data->scenes[i].extras); } - data->memory.free_func(data->memory.user_data, data->scenes); + data->memory.free(data->memory.user_data, data->scenes); for (cgltf_size i = 0; i < data->animations_count; ++i) { - data->memory.free_func(data->memory.user_data, data->animations[i].name); + data->memory.free(data->memory.user_data, data->animations[i].name); for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j) { cgltf_free_extensions(data, data->animations[i].samplers[j].extensions, data->animations[i].samplers[j].extensions_count); - cgltf_free_extras(data, &data->animations[i].samplers[j].extras); } - data->memory.free_func(data->memory.user_data, data->animations[i].samplers); + data->memory.free(data->memory.user_data, data->animations[i].samplers); for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j) { cgltf_free_extensions(data, data->animations[i].channels[j].extensions, data->animations[i].channels[j].extensions_count); - cgltf_free_extras(data, &data->animations[i].channels[j].extras); } - data->memory.free_func(data->memory.user_data, data->animations[i].channels); + data->memory.free(data->memory.user_data, data->animations[i].channels); cgltf_free_extensions(data, data->animations[i].extensions, data->animations[i].extensions_count); - cgltf_free_extras(data, &data->animations[i].extras); } - data->memory.free_func(data->memory.user_data, data->animations); + data->memory.free(data->memory.user_data, data->animations); for (cgltf_size i = 0; i < data->variants_count; ++i) { - data->memory.free_func(data->memory.user_data, data->variants[i].name); - - cgltf_free_extras(data, &data->variants[i].extras); + data->memory.free(data->memory.user_data, data->variants[i].name); } - data->memory.free_func(data->memory.user_data, data->variants); + data->memory.free(data->memory.user_data, data->variants); cgltf_free_extensions(data, data->data_extensions, data->data_extensions_count); - cgltf_free_extras(data, &data->extras); for (cgltf_size i = 0; i < data->extensions_used_count; ++i) { - data->memory.free_func(data->memory.user_data, data->extensions_used[i]); + data->memory.free(data->memory.user_data, data->extensions_used[i]); } - data->memory.free_func(data->memory.user_data, data->extensions_used); + data->memory.free(data->memory.user_data, data->extensions_used); for (cgltf_size i = 0; i < data->extensions_required_count; ++i) { - data->memory.free_func(data->memory.user_data, data->extensions_required[i]); + data->memory.free(data->memory.user_data, data->extensions_required[i]); } - data->memory.free_func(data->memory.user_data, data->extensions_required); + data->memory.free(data->memory.user_data, data->extensions_required); file_release(&data->memory, &data->file, data->file_data); - data->memory.free_func(data->memory.user_data, data); + data->memory.free(data->memory.user_data, data); } void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix) @@ -2181,7 +1969,7 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix) } } -static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_type component_type) +static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_type component_type) { switch (component_type) { @@ -2191,6 +1979,8 @@ static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_ return *((const uint16_t*) in); case cgltf_component_type_r_32u: return *((const uint32_t*) in); + case cgltf_component_type_r_32f: + return (cgltf_size)*((const float*) in); case cgltf_component_type_r_8: return *((const int8_t*) in); case cgltf_component_type_r_8u: @@ -2200,21 +1990,6 @@ static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_ } } -static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_type component_type) -{ - switch (component_type) - { - case cgltf_component_type_r_16u: - return *((const uint16_t*) in); - case cgltf_component_type_r_32u: - return *((const uint32_t*) in); - case cgltf_component_type_r_8u: - return *((const uint8_t*) in); - default: - return 0; - } -} - static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_type component_type, cgltf_bool normalized) { if (component_type == cgltf_component_type_r_32f) @@ -2240,9 +2015,11 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty } } - return (cgltf_float)cgltf_component_read_integer(in, component_type); + return (cgltf_float)cgltf_component_read_index(in, component_type); } +static cgltf_size cgltf_component_size(cgltf_component_type component_type); + static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size) { cgltf_size num_components = cgltf_num_components(type); @@ -2345,41 +2122,21 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl cgltf_size element_count = float_count / floats_per_element; // First pass: convert each element in the base accessor. - if (accessor->buffer_view == NULL) + cgltf_float* dest = out; + cgltf_accessor dense = *accessor; + dense.is_sparse = 0; + for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element) { - memset(out, 0, element_count * floats_per_element * sizeof(cgltf_float)); - } - else - { - const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); - if (element == NULL) + if (!cgltf_accessor_read_float(&dense, index, dest, floats_per_element)) { return 0; } - element += accessor->offset; - - if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float)) - { - memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float)); - } - else - { - cgltf_float* dest = out; - - for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element, element += accessor->stride) - { - if (!cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, dest, floats_per_element)) - { - return 0; - } - } - } } // Second pass: write out each element in the sparse accessor. if (accessor->is_sparse) { - const cgltf_accessor_sparse* sparse = &accessor->sparse; + const cgltf_accessor_sparse* sparse = &dense.sparse; const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view); const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view); @@ -2393,15 +2150,17 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl reader_head += sparse->values_byte_offset; cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type); - for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride) + for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride) { size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type); float* writer_head = out + writer_index * floats_per_element; - if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element)) + if (!cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element)) { return 0; } + + reader_head += dense.stride; } } @@ -2495,165 +2254,11 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size return cgltf_component_read_index(element, accessor->component_type); } -cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object) -{ - assert(object && (cgltf_size)(object - data->meshes) < data->meshes_count); - return (cgltf_size)(object - data->meshes); -} - -cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object) -{ - assert(object && (cgltf_size)(object - data->materials) < data->materials_count); - return (cgltf_size)(object - data->materials); -} - -cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object) -{ - assert(object && (cgltf_size)(object - data->accessors) < data->accessors_count); - return (cgltf_size)(object - data->accessors); -} - -cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object) -{ - assert(object && (cgltf_size)(object - data->buffer_views) < data->buffer_views_count); - return (cgltf_size)(object - data->buffer_views); -} - -cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object) -{ - assert(object && (cgltf_size)(object - data->buffers) < data->buffers_count); - return (cgltf_size)(object - data->buffers); -} - -cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object) -{ - assert(object && (cgltf_size)(object - data->images) < data->images_count); - return (cgltf_size)(object - data->images); -} - -cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object) -{ - assert(object && (cgltf_size)(object - data->textures) < data->textures_count); - return (cgltf_size)(object - data->textures); -} - -cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object) -{ - assert(object && (cgltf_size)(object - data->samplers) < data->samplers_count); - return (cgltf_size)(object - data->samplers); -} - -cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object) -{ - assert(object && (cgltf_size)(object - data->skins) < data->skins_count); - return (cgltf_size)(object - data->skins); -} - -cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object) -{ - assert(object && (cgltf_size)(object - data->cameras) < data->cameras_count); - return (cgltf_size)(object - data->cameras); -} - -cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object) -{ - assert(object && (cgltf_size)(object - data->lights) < data->lights_count); - return (cgltf_size)(object - data->lights); -} - -cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object) -{ - assert(object && (cgltf_size)(object - data->nodes) < data->nodes_count); - return (cgltf_size)(object - data->nodes); -} - -cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object) -{ - assert(object && (cgltf_size)(object - data->scenes) < data->scenes_count); - return (cgltf_size)(object - data->scenes); -} - -cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object) -{ - assert(object && (cgltf_size)(object - data->animations) < data->animations_count); - return (cgltf_size)(object - data->animations); -} - -cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object) -{ - assert(object && (cgltf_size)(object - animation->samplers) < animation->samplers_count); - return (cgltf_size)(object - animation->samplers); -} - -cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object) -{ - assert(object && (cgltf_size)(object - animation->channels) < animation->channels_count); - return (cgltf_size)(object - animation->channels); -} - -cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count) -{ - if (out == NULL) - { - return accessor->count; - } - - index_count = accessor->count < index_count ? accessor->count : index_count; - cgltf_size index_component_size = cgltf_component_size(accessor->component_type); - - if (accessor->is_sparse) - { - return 0; - } - if (accessor->buffer_view == NULL) - { - return 0; - } - if (index_component_size > out_component_size) - { - return 0; - } - const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); - if (element == NULL) - { - return 0; - } - element += accessor->offset; - - if (index_component_size == out_component_size && accessor->stride == out_component_size) - { - memcpy(out, element, index_count * index_component_size); - return index_count; - } - - // The component size of the output array is larger than the component size of the index data, so index data will be padded. - switch (out_component_size) - { - case 2: - for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride) - { - ((uint16_t*)out)[index] = (uint16_t)cgltf_component_read_index(element, accessor->component_type); - } - break; - case 4: - for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride) - { - ((uint32_t*)out)[index] = (uint32_t)cgltf_component_read_index(element, accessor->component_type); - } - break; - default: - break; - } - - return index_count; -} - #define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_NOMEM -2 #define CGLTF_ERROR_LEGACY -3 #define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; } -#define CGLTF_CHECK_TOKTYPE_RET(tok_, type_, ret_) if ((tok_).type != (type_)) { return ret_; } #define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */ #define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1) @@ -2664,7 +2269,7 @@ static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, co { CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING); size_t const str_len = strlen(str); - size_t const name_length = (size_t)(tok->end - tok->start); + size_t const name_length = tok->end - tok->start; return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128; } @@ -2672,28 +2277,17 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return CGLTF_ATOI(tmp); } -static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk) -{ - CGLTF_CHECK_TOKTYPE_RET(*tok, JSMN_PRIMITIVE, 0); - char tmp[128]; - int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); - strncpy(tmp, (const char*)json_chunk + tok->start, size); - tmp[size] = 0; - long long res = CGLTF_ATOLL(tmp); - return res < 0 ? 0 : (cgltf_size)res; -} - static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_float)CGLTF_ATOF(tmp); @@ -2701,7 +2295,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk) { - int size = (int)(tok->end - tok->start); + int size = tok->end - tok->start; return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0; } @@ -2767,8 +2361,8 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke { return CGLTF_ERROR_JSON; } - int size = (int)(tokens[i].end - tokens[i].start); - char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); + int size = tokens[i].end - tokens[i].start; + char* result = (char*)options->memory.alloc(options->memory.user_data, size + 1); if (!result) { return CGLTF_ERROR_NOMEM; @@ -2823,12 +2417,6 @@ static int cgltf_parse_json_string_array(cgltf_options* options, jsmntok_t const static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* out_type, int* out_index) { - if (*name == '_') - { - *out_type = cgltf_attribute_type_custom; - return; - } - const char* us = strchr(name, '_'); size_t len = us ? (size_t)(us - name) : strlen(name); @@ -2868,11 +2456,6 @@ static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* o if (us && *out_type != cgltf_attribute_type_invalid) { *out_index = CGLTF_ATOI(us + 1); - if (*out_index < 0) - { - *out_type = cgltf_attribute_type_invalid; - *out_index = 0; - } } } @@ -2913,27 +2496,11 @@ static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t con return i; } -static int cgltf_parse_json_extras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras) +static int cgltf_parse_json_extras(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras) { - if (out_extras->data) - { - return CGLTF_ERROR_JSON; - } - - /* fill deprecated fields for now, this will be removed in the future */ + (void)json_chunk; out_extras->start_offset = tokens[i].start; out_extras->end_offset = tokens[i].end; - - size_t start = tokens[i].start; - size_t size = tokens[i].end - start; - out_extras->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); - if (!out_extras->data) - { - return CGLTF_ERROR_NOMEM; - } - strncpy(out_extras->data, (const char*)json_chunk + start, size); - out_extras->data[size] = '\0'; - i = cgltf_skip_json(tokens, i); return i; } @@ -2948,7 +2515,7 @@ static int cgltf_parse_json_unprocessed_extension(cgltf_options* options, jsmnto } cgltf_size name_length = tokens[i].end - tokens[i].start; - out_extension->name = (char*)options->memory.alloc_func(options->memory.user_data, name_length + 1); + out_extension->name = (char*)options->memory.alloc(options->memory.user_data, name_length + 1); if (!out_extension->name) { return CGLTF_ERROR_NOMEM; @@ -2959,7 +2526,7 @@ static int cgltf_parse_json_unprocessed_extension(cgltf_options* options, jsmnto size_t start = tokens[i].start; size_t size = tokens[i].end - start; - out_extension->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); + out_extension->data = (char*)options->memory.alloc(options->memory.user_data, size + 1); if (!out_extension->data) { return CGLTF_ERROR_NOMEM; @@ -3030,39 +2597,6 @@ static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmnt out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } - else - { - i = cgltf_skip_json(tokens, i+1); - } - - if (i < 0) - { - return i; - } - } - - return i; -} - -static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh_gpu_instancing* out_mesh_gpu_instancing) -{ - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - - int size = tokens[i].size; - ++i; - - for (int j = 0; j < size; ++j) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "attributes") == 0) - { - i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count); - } - else - { - i = cgltf_skip_json(tokens, i+1); - } if (i < 0) { @@ -3090,7 +2624,7 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto int material = -1; int variants_tok = -1; - int extras_tok = -1; + cgltf_extras extras = {0, 0}; for (int k = 0; k < obj_size; ++k) { @@ -3111,8 +2645,7 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - extras_tok = i + 1; - i = cgltf_skip_json(tokens, extras_tok); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &extras); } else { @@ -3140,13 +2673,7 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto out_mappings[*offset].material = CGLTF_PTRINDEX(cgltf_material, material); out_mappings[*offset].variant = variant; - - if (extras_tok >= 0) - { - int e = cgltf_parse_json_extras(options, tokens, extras_tok, json_chunk, &out_mappings[*offset].extras); - if (e < 0) - return e; - } + out_mappings[*offset].extras = extras; (*offset)++; } @@ -3205,31 +2732,6 @@ static int cgltf_parse_json_material_mappings(cgltf_options* options, jsmntok_t return i; } -static cgltf_primitive_type cgltf_json_to_primitive_type(jsmntok_t const* tok, const uint8_t* json_chunk) -{ - int type = cgltf_json_to_int(tok, json_chunk); - - switch (type) - { - case 0: - return cgltf_primitive_type_points; - case 1: - return cgltf_primitive_type_lines; - case 2: - return cgltf_primitive_type_line_loop; - case 3: - return cgltf_primitive_type_line_strip; - case 4: - return cgltf_primitive_type_triangles; - case 5: - return cgltf_primitive_type_triangle_strip; - case 6: - return cgltf_primitive_type_triangle_fan; - default: - return cgltf_primitive_type_invalid; - } -} - static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3246,7 +2748,9 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) { ++i; - out_prim->type = cgltf_json_to_primitive_type(tokens+i, json_chunk); + out_prim->type + = (cgltf_primitive_type) + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) @@ -3284,7 +2788,7 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_prim->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_prim->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3482,7 +2986,7 @@ static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, c } } -static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) +static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3496,7 +3000,7 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_sparse->count = cgltf_json_to_size(tokens + i, json_chunk); + out_sparse->count = cgltf_json_to_int(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) @@ -3520,7 +3024,7 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0) { ++i; - out_sparse->indices_byte_offset = cgltf_json_to_size(tokens + i, json_chunk); + out_sparse->indices_byte_offset = cgltf_json_to_int(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0) @@ -3529,6 +3033,14 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->indices_extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->indices_extensions_count, &out_sparse->indices_extensions); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3561,9 +3073,17 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0) { ++i; - out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk); + out_sparse->values_byte_offset = cgltf_json_to_int(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->values_extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->values_extensions_count, &out_sparse->values_extensions); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3575,6 +3095,14 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons } } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->extensions_count, &out_sparse->extensions); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3614,7 +3142,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to { ++i; out_accessor->offset = - cgltf_json_to_size(tokens+i, json_chunk); + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0) @@ -3632,7 +3160,8 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_accessor->count = cgltf_json_to_size(tokens+i, json_chunk); + out_accessor->count = + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) @@ -3687,11 +3216,11 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0) { out_accessor->is_sparse = 1; - i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse); + i = cgltf_parse_json_accessor_sparse(options, tokens, i + 1, json_chunk, &out_accessor->sparse); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_accessor->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_accessor->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3739,7 +3268,6 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0) { ++i; - out_texture_transform->has_texcoord = 1; out_texture_transform->texcoord = cgltf_json_to_int(tokens + i, json_chunk); ++i; } @@ -3759,8 +3287,6 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view) { - (void)options; - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); out_texture_view->scale = 1.0f; @@ -3785,7 +3311,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) { ++i; out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); @@ -3797,12 +3323,28 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture_view->extras); + } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_texture_view->extensions) + { + return CGLTF_ERROR_JSON; + } + int extensions_size = tokens[i].size; + out_texture_view->extensions_count = 0; + out_texture_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + if (!out_texture_view->extensions) + { + return CGLTF_ERROR_NOMEM; + } ++i; @@ -3817,7 +3359,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const } else { - i = cgltf_skip_json(tokens, i + 1); + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture_view->extensions[out_texture_view->extensions_count++])); } if (i < 0) @@ -3854,11 +3396,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0) { ++i; - out_pbr->metallic_factor = + out_pbr->metallic_factor = cgltf_json_to_float(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) + else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) { ++i; out_pbr->roughness_factor = @@ -3871,11 +3413,17 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt } else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0) { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->base_color_texture); + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, + &out_pbr->base_color_texture); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0) { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture); + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, + &out_pbr->metallic_roughness_texture); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_pbr->extras); } else { @@ -4184,172 +3732,6 @@ static int cgltf_parse_json_sheen(cgltf_options* options, jsmntok_t const* token return i; } -static int cgltf_parse_json_emissive_strength(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_emissive_strength* out_emissive_strength) -{ - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int size = tokens[i].size; - ++i; - - // Default - out_emissive_strength->emissive_strength = 1.f; - - for (int j = 0; j < size; ++j) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveStrength") == 0) - { - ++i; - out_emissive_strength->emissive_strength = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - - if (i < 0) - { - return i; - } - } - - return i; -} - -static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_iridescence* out_iridescence) -{ - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int size = tokens[i].size; - ++i; - - // Default - out_iridescence->iridescence_ior = 1.3f; - out_iridescence->iridescence_thickness_min = 100.f; - out_iridescence->iridescence_thickness_max = 400.f; - - for (int j = 0; j < size; ++j) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceFactor") == 0) - { - ++i; - out_iridescence->iridescence_factor = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceTexture") == 0) - { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_iridescence->iridescence_texture); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceIor") == 0) - { - ++i; - out_iridescence->iridescence_ior = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessMinimum") == 0) - { - ++i; - out_iridescence->iridescence_thickness_min = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessMaximum") == 0) - { - ++i; - out_iridescence->iridescence_thickness_max = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessTexture") == 0) - { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_iridescence->iridescence_thickness_texture); - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - - if (i < 0) - { - return i; - } - } - - return i; -} - -static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy) -{ - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int size = tokens[i].size; - ++i; - - - for (int j = 0; j < size; ++j) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyStrength") == 0) - { - ++i; - out_anisotropy->anisotropy_strength = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyRotation") == 0) - { - ++i; - out_anisotropy->anisotropy_rotation = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyTexture") == 0) - { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_anisotropy->anisotropy_texture); - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - - if (i < 0) - { - return i; - } - } - - return i; -} - -static int cgltf_parse_json_dispersion(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_dispersion* out_dispersion) -{ - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int size = tokens[i].size; - ++i; - - - for (int j = 0; j < size; ++j) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "dispersion") == 0) - { - ++i; - out_dispersion->dispersion = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - - if (i < 0) - { - return i; - } - } - - return i; -} - static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -4357,11 +3739,11 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token int size = tokens[i].size; ++i; - for (int j = 0; j < size; ++j) + for (int j = 0; j < size; ++j) { CGLTF_CHECK_KEY(tokens[i]); - if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0) + if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0) { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri); } @@ -4381,7 +3763,7 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_image->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_image->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4441,7 +3823,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok = cgltf_json_to_int(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) { ++i; out_sampler->wrap_t @@ -4450,7 +3832,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4491,7 +3873,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) { ++i; out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk)); @@ -4499,98 +3881,11 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - ++i; - - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - if (out_texture->extensions) - { - return CGLTF_ERROR_JSON; - } - - int extensions_size = tokens[i].size; - ++i; - out_texture->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); - out_texture->extensions_count = 0; - - if (!out_texture->extensions) - { - return CGLTF_ERROR_NOMEM; - } - - for (int k = 0; k < extensions_size; ++k) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_texture_basisu") == 0) - { - out_texture->has_basisu = 1; - ++i; - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int num_properties = tokens[i].size; - ++i; - - for (int t = 0; t < num_properties; ++t) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) - { - ++i; - out_texture->basisu_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk)); - ++i; - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - if (i < 0) - { - return i; - } - } - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "EXT_texture_webp") == 0) - { - out_texture->has_webp = 1; - ++i; - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int num_properties = tokens[i].size; - ++i; - - for (int t = 0; t < num_properties; ++t) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) - { - ++i; - out_texture->webp_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk)); - ++i; - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - if (i < 0) - { - return i; - } - } - } - else - { - i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture->extensions[out_texture->extensions_count++])); - } - - if (i < 0) - { - return i; - } - } + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_texture->extensions_count, &out_texture->extensions); } else { @@ -4690,7 +3985,7 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_material->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_material->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4756,26 +4051,6 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to out_material->has_sheen = 1; i = cgltf_parse_json_sheen(options, tokens, i + 1, json_chunk, &out_material->sheen); } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_emissive_strength") == 0) - { - out_material->has_emissive_strength = 1; - i = cgltf_parse_json_emissive_strength(tokens, i + 1, json_chunk, &out_material->emissive_strength); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_iridescence") == 0) - { - out_material->has_iridescence = 1; - i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0) - { - out_material->has_anisotropy = 1; - i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_dispersion") == 0) - { - out_material->has_dispersion = 1; - i = cgltf_parse_json_dispersion(tokens, i + 1, json_chunk, &out_material->dispersion); - } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++])); @@ -4917,25 +4192,25 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_ else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0) { ++i; - out_meshopt_compression->offset = cgltf_json_to_size(tokens+i, json_chunk); + out_meshopt_compression->offset = cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0) { ++i; - out_meshopt_compression->size = cgltf_json_to_size(tokens+i, json_chunk); + out_meshopt_compression->size = cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0) { ++i; - out_meshopt_compression->stride = cgltf_json_to_size(tokens+i, json_chunk); + out_meshopt_compression->stride = cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_meshopt_compression->count = cgltf_json_to_size(tokens+i, json_chunk); + out_meshopt_compression->count = cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) @@ -5015,21 +4290,21 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const* { ++i; out_buffer_view->offset = - cgltf_json_to_size(tokens+i, json_chunk); + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0) { ++i; out_buffer_view->size = - cgltf_json_to_size(tokens+i, json_chunk); + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0) { ++i; out_buffer_view->stride = - cgltf_json_to_size(tokens+i, json_chunk); + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0) @@ -5053,7 +4328,7 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const* } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer_view->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer_view->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5147,7 +4422,7 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke { ++i; out_buffer->size = - cgltf_json_to_size(tokens+i, json_chunk); + cgltf_json_to_int(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "uri") == 0) @@ -5156,7 +4431,7 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5240,7 +4515,7 @@ static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_skin->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_skin->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5294,6 +4569,19 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_camera->name); } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens + i, json_chunk, "perspective") == 0) + { + out_camera->type = cgltf_camera_type_perspective; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "orthographic") == 0) + { + out_camera->type = cgltf_camera_type_orthographic; + } + ++i; + } else if (cgltf_json_strcmp(tokens+i, json_chunk, "perspective") == 0) { ++i; @@ -5303,11 +4591,6 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke int data_size = tokens[i].size; ++i; - if (out_camera->type != cgltf_camera_type_invalid) - { - return CGLTF_ERROR_JSON; - } - out_camera->type = cgltf_camera_type_perspective; for (int k = 0; k < data_size; ++k) @@ -5342,7 +4625,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.perspective.extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.perspective.extras); } else { @@ -5364,11 +4647,6 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke int data_size = tokens[i].size; ++i; - if (out_camera->type != cgltf_camera_type_invalid) - { - return CGLTF_ERROR_JSON; - } - out_camera->type = cgltf_camera_type_orthographic; for (int k = 0; k < data_size; ++k) @@ -5401,7 +4679,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras); } else { @@ -5416,7 +4694,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5459,14 +4737,6 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - out_light->color[0] = 1.f; - out_light->color[1] = 1.f; - out_light->color[2] = 1.f; - out_light->intensity = 1.f; - - out_light->spot_inner_cone_angle = 0.f; - out_light->spot_outer_cone_angle = 3.1415926535f / 4.0f; - int size = tokens[i].size; ++i; @@ -5547,10 +4817,6 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token } } } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_light->extras); - } else { i = cgltf_skip_json(tokens, i+1); @@ -5675,7 +4941,7 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_node->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_node->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5733,11 +4999,6 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens } } } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "EXT_mesh_gpu_instancing") == 0) - { - out_node->has_mesh_gpu_instancing = 1; - i = cgltf_parse_json_mesh_gpu_instancing(options, tokens, i + 1, json_chunk, &out_node->mesh_gpu_instancing); - } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_node->extensions[out_node->extensions_count++])); @@ -5813,7 +5074,7 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_scene->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_scene->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5895,7 +5156,7 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5975,7 +5236,7 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_channel->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_channel->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -6057,7 +5318,7 @@ static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_animation->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_animation->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -6113,7 +5374,7 @@ static int cgltf_parse_json_variant(cgltf_options* options, jsmntok_t const* tok } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_variant->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_variant->extras); } else { @@ -6177,7 +5438,7 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_asset->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_asset->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -6224,7 +5485,7 @@ cgltf_size cgltf_num_components(cgltf_type type) { } } -cgltf_size cgltf_component_size(cgltf_component_type component_type) { +static cgltf_size cgltf_component_size(cgltf_component_type component_type) { switch (component_type) { case cgltf_component_type_r_8: @@ -6242,7 +5503,7 @@ cgltf_size cgltf_component_size(cgltf_component_type component_type) { } } -cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) +static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) { cgltf_size component_size = cgltf_component_size(component_type); if (type == cgltf_type_mat2 && component_size == 1) @@ -6333,7 +5594,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_data->extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_data->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -6465,7 +5726,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, options->json_token_count = token_count; } - jsmntok_t* tokens = (jsmntok_t*)options->memory.alloc_func(options->memory.user_data, sizeof(jsmntok_t) * (options->json_token_count + 1)); + jsmntok_t* tokens = (jsmntok_t*)options->memory.alloc(options->memory.user_data, sizeof(jsmntok_t) * (options->json_token_count + 1)); if (!tokens) { @@ -6478,7 +5739,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, if (token_count <= 0) { - options->memory.free_func(options->memory.user_data, tokens); + options->memory.free(options->memory.user_data, tokens); return cgltf_result_invalid_json; } @@ -6486,11 +5747,11 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, // for invalid JSON inputs this makes sure we don't perform out of bound reads of token data tokens[token_count].type = JSMN_UNDEFINED; - cgltf_data* data = (cgltf_data*)options->memory.alloc_func(options->memory.user_data, sizeof(cgltf_data)); + cgltf_data* data = (cgltf_data*)options->memory.alloc(options->memory.user_data, sizeof(cgltf_data)); if (!data) { - options->memory.free_func(options->memory.user_data, tokens); + options->memory.free(options->memory.user_data, tokens); return cgltf_result_out_of_memory; } @@ -6500,7 +5761,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, int i = cgltf_parse_json_root(options, tokens, 0, json_chunk, data); - options->memory.free_func(options->memory.user_data, tokens); + options->memory.free(options->memory.user_data, tokens); if (i < 0) { @@ -6590,8 +5851,6 @@ static int cgltf_fixup_pointers(cgltf_data* data) for (cgltf_size i = 0; i < data->textures_count; ++i) { CGLTF_PTRFIXUP(data->textures[i].image, data->images, data->images_count); - CGLTF_PTRFIXUP(data->textures[i].basisu_image, data->images, data->images_count); - CGLTF_PTRFIXUP(data->textures[i].webp_image, data->images, data->images_count); CGLTF_PTRFIXUP(data->textures[i].sampler, data->samplers, data->samplers_count); } @@ -6625,11 +5884,6 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP(data->materials[i].sheen.sheen_color_texture.texture, data->textures, data->textures_count); CGLTF_PTRFIXUP(data->materials[i].sheen.sheen_roughness_texture.texture, data->textures, data->textures_count); - - CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count); - CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count); - - CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count); } for (cgltf_size i = 0; i < data->buffer_views_count; ++i) @@ -6671,14 +5925,6 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP(data->nodes[i].skin, data->skins, data->skins_count); CGLTF_PTRFIXUP(data->nodes[i].camera, data->cameras, data->cameras_count); CGLTF_PTRFIXUP(data->nodes[i].light, data->lights, data->lights_count); - - if (data->nodes[i].has_mesh_gpu_instancing) - { - for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m) - { - CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count); - } - } } for (cgltf_size i = 0; i < data->scenes_count; ++i) @@ -6762,7 +6008,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - ptrdiff_t start, ptrdiff_t end) { + int start, int end) { token->type = type; token->start = start; token->end = end; @@ -6775,7 +6021,7 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - ptrdiff_t start; + int start; start = parser->pos; @@ -6825,7 +6071,7 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - ptrdiff_t start = parser->pos; + int start = parser->pos; parser->pos++; @@ -7059,7 +6305,7 @@ static void jsmn_init(jsmn_parser *parser) { /* cgltf is distributed under MIT license: * - * Copyright (c) 2018-2021 Johannes Kuhlmann + * Copyright (c) 2018 Johannes Kuhlmann * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/raylib/external/dr_flac.h b/raylib/external/dr_flac.h index 14324cf..a797350 100644 --- a/raylib/external/dr_flac.h +++ b/raylib/external/dr_flac.h @@ -1,6 +1,6 @@ /* FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_flac - v0.12.42 - 2023-11-02 +dr_flac - v0.12.29 - 2021-04-02 David Reid - mackron@gmail.com @@ -210,9 +210,6 @@ Build Options #define DR_FLAC_NO_SIMD Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler. -#define DR_FLAC_NO_WCHAR - Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_FLAC_NO_STDIO is also defined. - Notes @@ -235,19 +232,19 @@ extern "C" { #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 42 +#define DRFLAC_VERSION_REVISION 29 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include /* For size_t. */ -/* Sized Types */ +/* Sized types. */ typedef signed char drflac_int8; typedef unsigned char drflac_uint8; typedef signed short drflac_int16; typedef unsigned short drflac_uint16; typedef signed int drflac_int32; typedef unsigned int drflac_uint32; -#if defined(_MSC_VER) && !defined(__clang__) +#if defined(_MSC_VER) typedef signed __int64 drflac_int64; typedef unsigned __int64 drflac_uint64; #else @@ -264,7 +261,7 @@ typedef unsigned int drflac_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) typedef drflac_uint64 drflac_uintptr; #else typedef drflac_uint32 drflac_uintptr; @@ -273,9 +270,7 @@ typedef drflac_uint8 drflac_bool8; typedef drflac_uint32 drflac_bool32; #define DRFLAC_TRUE 1 #define DRFLAC_FALSE 0 -/* End Sized Types */ -/* Decorations */ #if !defined(DRFLAC_API) #if defined(DRFLAC_DLL) #if defined(_WIN32) @@ -305,7 +300,6 @@ typedef drflac_uint32 drflac_bool32; #define DRFLAC_PRIVATE static #endif #endif -/* End Decorations */ #if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */ #define DRFLAC_DEPRECATED __declspec(deprecated) @@ -324,16 +318,6 @@ typedef drflac_uint32 drflac_bool32; DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision); DRFLAC_API const char* drflac_version_string(void); -/* Allocation Callbacks */ -typedef struct -{ - void* pUserData; - void* (* onMalloc)(size_t sz, void* pUserData); - void* (* onRealloc)(void* p, size_t sz, void* pUserData); - void (* onFree)(void* p, void* pUserData); -} drflac_allocation_callbacks; -/* End Allocation Callbacks */ - /* As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed, but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8. @@ -342,22 +326,11 @@ but also more memory. In my testing there is diminishing returns after about 4KB #define DR_FLAC_BUFFER_SIZE 4096 #endif - -/* Architecture Detection */ +/* Check if we can enable 64-bit optimizations. */ #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) #define DRFLAC_64BIT #endif -#if defined(__x86_64__) || defined(_M_X64) - #define DRFLAC_X64 -#elif defined(__i386) || defined(_M_IX86) - #define DRFLAC_X86 -#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) - #define DRFLAC_ARM -#endif -/* End Architecture Detection */ - - #ifdef DRFLAC_64BIT typedef drflac_uint64 drflac_cache_t; #else @@ -410,13 +383,15 @@ typedef enum drflac_seek_origin_current } drflac_seek_origin; -/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */ +/* Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block. */ +#pragma pack(2) typedef struct { drflac_uint64 firstPCMFrame; drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */ drflac_uint16 pcmFrameCount; } drflac_seekpoint; +#pragma pack() typedef struct { @@ -586,6 +561,14 @@ will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens. typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drflac_allocation_callbacks; + /* Structure for internal use. Only used for decoders opened with drflac_open_memory. */ typedef struct { @@ -1297,13 +1280,15 @@ typedef struct const char* pRunningData; } drflac_cuesheet_track_iterator; -/* The order of members here is important because we map this directly to the raw data within the CUESHEET metadata block. */ +/* Packing is important on this structure because we map this directly to the raw data within the CUESHEET metadata block. */ +#pragma pack(4) typedef struct { drflac_uint64 offset; drflac_uint8 index; drflac_uint8 reserved[3]; } drflac_cuesheet_track_index; +#pragma pack() typedef struct { @@ -1367,7 +1352,6 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat #include #include -/* Inline */ #ifdef _MSC_VER #define DRFLAC_INLINE __forceinline #elif defined(__GNUC__) @@ -1379,22 +1363,24 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define DRFLAC_GNUC_INLINE_HINT __inline__ + #define DRFLAC_INLINE __inline__ __attribute__((always_inline)) #else - #define DRFLAC_GNUC_INLINE_HINT inline - #endif - - #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) - #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline)) - #else - #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT + #define DRFLAC_INLINE inline __attribute__((always_inline)) #endif #elif defined(__WATCOMC__) #define DRFLAC_INLINE __inline #else #define DRFLAC_INLINE #endif -/* End Inline */ + +/* CPU architecture. */ +#if defined(__x86_64__) || defined(_M_X64) + #define DRFLAC_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRFLAC_X86 +#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64) + #define DRFLAC_ARM +#endif /* Intrinsics Support @@ -1445,6 +1431,16 @@ Unfortuantely dr_flac depends on this for a few things so we're just going to di #if defined(DRFLAC_ARM) #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) #define DRFLAC_SUPPORT_NEON + #endif + + /* Fall back to looking for the #include file. */ + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include() + #define DRFLAC_SUPPORT_NEON + #endif + #endif + + #if defined(DRFLAC_SUPPORT_NEON) #include #endif #endif @@ -1523,7 +1519,9 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) { #if defined(DRFLAC_SUPPORT_SSE41) #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41) - #if defined(__SSE4_1__) || defined(__AVX__) + #if defined(DRFLAC_X64) + return DRFLAC_TRUE; /* 64-bit targets always support SSE4.1. */ + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__) return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */ #else #if defined(DRFLAC_NO_CPUID) @@ -1588,21 +1586,18 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); #pragma aux _watcom_bswap16 = \ "xchg al, ah" \ - parm [ax] \ - value [ax] \ - modify nomemory; + parm [ax] \ + modify [ax]; #pragma aux _watcom_bswap32 = \ - "bswap eax" \ - parm [eax] \ - value [eax] \ - modify nomemory; + "bswap eax" \ + parm [eax] \ + modify [eax]; #pragma aux _watcom_bswap64 = \ "bswap eax" \ "bswap edx" \ "xchg eax,edx" \ parm [eax edx] \ - value [eax edx] \ - modify nomemory; + modify [eax edx]; #endif @@ -1632,7 +1627,6 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) #define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ -/* Result Codes */ typedef drflac_int32 drflac_result; #define DRFLAC_SUCCESS 0 #define DRFLAC_ERROR -1 /* A generic error. */ @@ -1688,10 +1682,7 @@ typedef drflac_int32 drflac_result; #define DRFLAC_CANCELLED -51 #define DRFLAC_MEMORY_ALREADY_MAPPED -52 #define DRFLAC_AT_END -53 - -#define DRFLAC_CRC_MISMATCH -100 -/* End Result Codes */ - +#define DRFLAC_CRC_MISMATCH -128 #define DRFLAC_SUBFRAME_CONSTANT 0 #define DRFLAC_SUBFRAME_VERBATIM 1 @@ -1707,10 +1698,6 @@ typedef drflac_int32 drflac_result; #define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 #define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 -#define DRFLAC_SEEKPOINT_SIZE_IN_BYTES 18 -#define DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36 -#define DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12 - #define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) @@ -1851,7 +1838,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_ulong(n); #elif defined(__GNUC__) || defined(__clang__) - #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ + #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ drflac_uint32 r; __asm__ __volatile__ ( @@ -1922,12 +1909,6 @@ static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) return n; } -static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData) -{ - const drflac_uint8* pNum = (drflac_uint8*)pData; - return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3); -} - static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) { if (drflac__is_little_endian()) { @@ -1947,12 +1928,6 @@ static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) return n; } -static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData) -{ - const drflac_uint8* pNum = (drflac_uint8*)pData; - return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24; -} - static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) { @@ -2454,10 +2429,6 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } - if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - /* This happens when we get to end of stream */ - return DRFLAC_FALSE; - } *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); bs->consumedBits += bitCountLo; @@ -2713,10 +2684,6 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) #if defined(__WATCOMC__) && defined(__386__) #define DRFLAC_IMPLEMENT_CLZ_WATCOM #endif -#ifdef __MRC__ -#include -#define DRFLAC_IMPLEMENT_CLZ_MRC -#endif static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { @@ -2757,8 +2724,6 @@ static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void) /* Fast compile time check for ARM. */ #if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) return DRFLAC_TRUE; -#elif defined(__MRC__) - return DRFLAC_TRUE; #else /* If the compiler itself does not support the intrinsic then we'll need to return false. */ #ifdef DRFLAC_HAS_LZCNT_INTRINSIC @@ -2815,7 +2780,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) return r; } - #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */ + #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */ { unsigned int r; __asm__ __volatile__ ( @@ -2868,15 +2833,6 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) #ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); -#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT -/* Use the LZCNT instruction (only available on some processors since the 2010s). */ -#pragma aux drflac__clz_watcom_lzcnt = \ - "db 0F3h, 0Fh, 0BDh, 0C0h" /* lzcnt eax, eax */ \ - parm [eax] \ - value [eax] \ - modify nomemory; -#else -/* Use the 386+-compatible implementation. */ #pragma aux drflac__clz_watcom = \ "bsr eax, eax" \ "xor eax, 31" \ @@ -2884,7 +2840,6 @@ static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); value [eax] \ modify exact [eax] nomemory; #endif -#endif static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { @@ -2896,12 +2851,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); -#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT) - return drflac__clz_watcom_lzcnt(x); #elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); -#elif defined(__MRC__) - return __cntlzw(x); #else return drflac__clz_software(x); #endif @@ -2921,24 +2872,9 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, } } - if (bs->cache == 1) { - /* Not catching this would lead to undefined behaviour: a shift of a 32-bit number by 32 or more is undefined */ - *pOffsetOut = zeroCounter + (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs) - 1; - if (!drflac__reload_cache(bs)) { - return DRFLAC_FALSE; - } - - return DRFLAC_TRUE; - } - setBitOffsetPlus1 = drflac__clz(bs->cache); setBitOffsetPlus1 += 1; - if (setBitOffsetPlus1 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - /* This happens when we get to end of stream */ - return DRFLAC_FALSE; - } - bs->consumedBits += setBitOffsetPlus1; bs->cache <<= setBitOffsetPlus1; @@ -3053,25 +2989,6 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 } -static DRFLAC_INLINE drflac_uint32 drflac__ilog2_u32(drflac_uint32 x) -{ -#if 1 /* Needs optimizing. */ - drflac_uint32 result = 0; - while (x > 0) { - result += 1; - x >>= 1; - } - - return result; -#endif -} - -static DRFLAC_INLINE drflac_bool32 drflac__use_64_bit_prediction(drflac_uint32 bitsPerSample, drflac_uint32 order, drflac_uint32 precision) -{ - /* https://web.archive.org/web/20220205005724/https://github.com/ietf-wg-cellar/flac-specification/blob/37a49aa48ba4ba12e8757badfc59c0df35435fec/rfc_backmatter.md */ - return bitsPerSample + precision + drflac__ilog2_u32(order) > 32; -} - /* The next two functions are responsible for calculating the prediction. @@ -3079,9 +2996,6 @@ The next two functions are responsible for calculating the prediction. When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. */ -#if defined(__clang__) -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { drflac_int32 prediction = 0; @@ -3317,7 +3231,7 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the sake of readability and should only be used as a reference. */ -static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 i; @@ -3356,10 +3270,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla } - if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + if (bitsPerSample+shift >= 32) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); } } @@ -3456,10 +3370,6 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } - if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - /* This happens when we get to end of stream */ - return DRFLAC_FALSE; - } } riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); @@ -3540,10 +3450,6 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } - if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - /* This happens when we get to end of stream */ - return DRFLAC_FALSE; - } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; @@ -3654,11 +3560,6 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac return DRFLAC_FALSE; } - if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - /* This happens when we get to end of stream */ - return DRFLAC_FALSE; - } - bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } @@ -3745,7 +3646,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorde return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; drflac_uint32 zeroCountPart0 = 0; @@ -3763,14 +3664,14 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); - if (lpcOrder == 0) { - return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + if (order == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } riceParamMask = (drflac_uint32)~((~0UL) << riceParam); pSamplesOutEnd = pSamplesOut + (count & ~3); - if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + if (bitsPerSample+shift > 32) { while (pSamplesOut < pSamplesOutEnd) { /* Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version @@ -3798,10 +3699,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } @@ -3829,10 +3730,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } @@ -3852,10 +3753,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b /*riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/ /* Sample reconstruction. */ - if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + if (bitsPerSample+shift > 32) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); } else { - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); } i += 1; @@ -4311,20 +4212,20 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */ - if (lpcOrder > 0 && lpcOrder <= 12) { - if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + if (order > 0 && order <= 12) { + if (bitsPerSample+shift > 32) { + return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } else { - return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } } else { - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } } #endif @@ -4463,7 +4364,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_ const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask = ~((~0UL) << riceParam); riceParamMask128 = vdupq_n_u32(riceParamMask); riceParam128 = vdupq_n_s32(riceParam); @@ -4649,13 +4550,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ int32x4_t riceParam128; int64x1_t shift64; uint32x4_t one128; - int64x2_t prediction128 = { 0 }; - uint32x4_t zeroCountPart128; - uint32x4_t riceParamPart128; const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask = ~((~0UL) << riceParam); riceParamMask128 = vdupq_n_u32(riceParamMask); riceParam128 = vdupq_n_s32(riceParam); @@ -4664,7 +4562,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ /* Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than - what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results + what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted so I think there's opportunity for this to be simplified. */ @@ -4732,6 +4630,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ /* For this version we are doing one sample at a time. */ while (pDecodedSamples < pDecodedSamplesEnd) { + int64x2_t prediction128; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || @@ -4808,41 +4710,41 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */ - if (lpcOrder > 0 && lpcOrder <= 12) { - if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + if (order > 0 && order <= 12) { + if (bitsPerSample+shift > 32) { + return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } else { - return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } } else { - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } } #endif -static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { #if defined(DRFLAC_SUPPORT_SSE41) if (drflac__gIsSSE41Supported) { - return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } else #elif defined(DRFLAC_SUPPORT_NEON) if (drflac__gIsNEONSupported) { - return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } else #endif { /* Scalar fallback. */ #if 0 - return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); #else - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); #endif } } @@ -4863,10 +4765,7 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ return DRFLAC_TRUE; } -#if defined(__clang__) -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 i; @@ -4883,10 +4782,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* pSamplesOut[i] = 0; } - if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + if (bitsPerSample >= 24) { + pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); } } @@ -4899,7 +4798,7 @@ Reads and decodes the residual for the sub-frame the decoder is currently sittin when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be ignored. The and parameters are used to determine how many residual values need to be decoded. */ -static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { drflac_uint8 residualMethod; drflac_uint8 partitionOrder; @@ -4919,7 +4818,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } /* Ignore the first values. */ - pDecodedSamples += lpcOrder; + pDecodedSamples += order; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { return DRFLAC_FALSE; @@ -4934,11 +4833,11 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } /* Validation check. */ - if ((blockSize / (1 << partitionOrder)) < lpcOrder) { + if ((blockSize / (1 << partitionOrder)) < order) { return DRFLAC_FALSE; } - samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; @@ -4959,7 +4858,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } if (riceParam != 0xFF) { - if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } else { @@ -4968,7 +4867,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ return DRFLAC_FALSE; } - if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } @@ -5137,7 +5036,7 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 pDecodedSamples[i] = sample; } - if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { return DRFLAC_FALSE; } @@ -5192,7 +5091,7 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl } } - if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } @@ -5320,9 +5219,6 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16); - if (header->blockSizeInPCMFrames == 0xFFFF) { - return DRFLAC_FALSE; /* Frame is too big. This is the size of the frame minus 1. The STREAMINFO block defines the max block size which is 16-bits. Adding one will make it 17 bits and therefore too big. */ - } header->blockSizeInPCMFrames += 1; } else { DRFLAC_ASSERT(blockSize >= 8); @@ -5361,11 +5257,6 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u header->bitsPerSample = streaminfoBitsPerSample; } - if (header->bitsPerSample != streaminfoBitsPerSample) { - /* If this subframe has a different bitsPerSample then streaminfo or the first frame, reject it */ - return DRFLAC_FALSE; - } - if (!drflac__read_uint8(bs, 8, &header->crc8)) { return DRFLAC_FALSE; } @@ -5452,11 +5343,6 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, subframeBitsPerSample += 1; } - if (subframeBitsPerSample > 32) { - /* libFLAC and ffmpeg reject 33-bit subframes as well */ - return DRFLAC_FALSE; - } - /* Need to handle wasted bits per sample. */ if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { return DRFLAC_FALSE; @@ -6127,11 +6013,6 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac return DRFLAC_FALSE; } - /* Do not use the seektable if pcmFramIndex is not coverd by it. */ - if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { - return DRFLAC_FALSE; - } - for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { break; @@ -6479,7 +6360,7 @@ static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbac } -static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks) +static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize, drflac_allocation_callbacks* pAllocationCallbacks) { /* We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that @@ -6492,7 +6373,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d for (;;) { drflac_metadata metadata; drflac_uint8 isLastBlock = 0; - drflac_uint8 blockType = 0; + drflac_uint8 blockType; drflac_uint32 blockSize; if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) { return DRFLAC_FALSE; @@ -6539,37 +6420,32 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d seektableSize = blockSize; if (onMeta) { - drflac_uint32 seekpointCount; drflac_uint32 iSeekpoint; void* pRawData; - seekpointCount = blockSize/DRFLAC_SEEKPOINT_SIZE_IN_BYTES; - - pRawData = drflac__malloc_from_callbacks(seekpointCount * sizeof(drflac_seekpoint), pAllocationCallbacks); + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; } - /* We need to read seekpoint by seekpoint and do some processing. */ - for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) { - drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; - - if (onRead(pUserData, pSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) != DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); - return DRFLAC_FALSE; - } - - /* Endian swap. */ - pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame); - pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset); - pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - metadata.data.seektable.seekpointCount = seekpointCount; + metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint); metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; + /* Endian swap. */ + for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { + drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; + pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame); + pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset); + pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount); + } + onMeta(pUserDataMD, &metadata); drflac__free_from_callbacks(pRawData, pAllocationCallbacks); @@ -6604,7 +6480,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; /* Need space for the rest of the block */ if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ @@ -6612,7 +6488,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d return DRFLAC_FALSE; } metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */ if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */ @@ -6630,7 +6506,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d return DRFLAC_FALSE; } - commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; @@ -6654,15 +6530,9 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d void* pRawData; const char* pRunningData; const char* pRunningDataEnd; - size_t bufferSize; drflac_uint8 iTrack; drflac_uint8 iIndex; - void* pTrackData; - /* - This needs to be loaded in two passes. The first pass is used to calculate the size of the memory allocation - we need for storing the necessary data. The second pass will fill that buffer with usable data. - */ pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; @@ -6683,91 +6553,38 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259; metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; - metadata.data.cuesheet.pTrackData = NULL; /* Will be filled later. */ + metadata.data.cuesheet.pTrackData = pRunningData; - /* Pass 1: Calculate the size of the buffer for the track data. */ - { - const char* pRunningDataSaved = pRunningData; /* Will be restored at the end in preparation for the second pass. */ + /* Check that the cuesheet tracks are valid before passing it to the callback */ + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + drflac_uint32 indexPointSize; - bufferSize = metadata.data.cuesheet.trackCount * DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES; - - for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { - drflac_uint8 indexCount; - drflac_uint32 indexPointSize; - - if (pRunningDataEnd - pRunningData < DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES) { - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); - return DRFLAC_FALSE; - } - - /* Skip to the index point count */ - pRunningData += 35; - - indexCount = pRunningData[0]; - pRunningData += 1; - - bufferSize += indexCount * sizeof(drflac_cuesheet_track_index); - - /* Quick validation check. */ - indexPointSize = indexCount * DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; - if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); - return DRFLAC_FALSE; - } - - pRunningData += indexPointSize; - } - - pRunningData = pRunningDataSaved; - } - - /* Pass 2: Allocate a buffer and fill the data. Validation was done in the step above so can be skipped. */ - { - char* pRunningTrackData; - - pTrackData = drflac__malloc_from_callbacks(bufferSize, pAllocationCallbacks); - if (pTrackData == NULL) { + if (pRunningDataEnd - pRunningData < 36) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - pRunningTrackData = (char*)pTrackData; - - for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { - drflac_uint8 indexCount; - - DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES); - pRunningData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; /* Skip forward, but not beyond the last byte in the CUESHEET_TRACK block which is the index count. */ - pRunningTrackData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; - - /* Grab the index count for the next part. */ - indexCount = pRunningData[0]; - pRunningData += 1; - pRunningTrackData += 1; - - /* Extract each track index. */ - for (iIndex = 0; iIndex < indexCount; ++iIndex) { - drflac_cuesheet_track_index* pTrackIndex = (drflac_cuesheet_track_index*)pRunningTrackData; - - DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES); - pRunningData += DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; - pRunningTrackData += sizeof(drflac_cuesheet_track_index); - - pTrackIndex->offset = drflac__be2host_64(pTrackIndex->offset); - } + /* Skip to the index point count */ + pRunningData += 35; + indexCount = pRunningData[0]; pRunningData += 1; + indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index); + if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } - metadata.data.cuesheet.pTrackData = pTrackData; + /* Endian swap. */ + for (iIndex = 0; iIndex < indexCount; ++iIndex) { + drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData; + pRunningData += sizeof(drflac_cuesheet_track_index); + pTrack->offset = drflac__be2host_64(pTrack->offset); + } } - /* The original data is no longer needed. */ - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); - pRawData = NULL; - onMeta(pUserDataMD, &metadata); - drflac__free_from_callbacks(pTrackData, pAllocationCallbacks); - pTrackData = NULL; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; @@ -6798,28 +6615,28 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; /* Need space for the rest of the block */ if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; + metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; /* Need space for the rest of the block */ if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; - metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; + metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; /* Need space for the picture after the block */ @@ -6897,9 +6714,9 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d } } - *pSeektablePos = seektablePos; - *pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES; - *pFirstFramePos = runningFilePos; + *pSeektablePos = seektablePos; + *pSeektableSize = seektableSize; + *pFirstFramePos = runningFilePos; return DRFLAC_TRUE; } @@ -7929,11 +7746,11 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac drflac_uint32 wholeSIMDVectorCountPerChannel; drflac_uint32 decodedSamplesAllocationSize; #ifndef DR_FLAC_NO_OGG - drflac_oggbs* pOggbs = NULL; + drflac_oggbs oggbs; #endif drflac_uint64 firstFramePos; drflac_uint64 seektablePos; - drflac_uint32 seekpointCount; + drflac_uint32 seektableSize; drflac_allocation_callbacks allocationCallbacks; drflac* pFlac; @@ -7987,21 +7804,18 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac /* There's additional data required for Ogg streams. */ if (init.container == drflac_container_ogg) { allocationSize += sizeof(drflac_oggbs); + } - pOggbs = (drflac_oggbs*)drflac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks); - if (pOggbs == NULL) { - return NULL; /*DRFLAC_OUT_OF_MEMORY;*/ - } - - DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); - pOggbs->onRead = onRead; - pOggbs->onSeek = onSeek; - pOggbs->pUserData = pUserData; - pOggbs->currentBytePos = init.oggFirstBytePos; - pOggbs->firstBytePos = init.oggFirstBytePos; - pOggbs->serialNumber = init.oggSerial; - pOggbs->bosPageHeader = init.oggBosHeader; - pOggbs->bytesRemainingInPage = 0; + DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs)); + if (init.container == drflac_container_ogg) { + oggbs.onRead = onRead; + oggbs.onSeek = onSeek; + oggbs.pUserData = pUserData; + oggbs.currentBytePos = init.oggFirstBytePos; + oggbs.firstBytePos = init.oggFirstBytePos; + oggbs.serialNumber = init.oggSerial; + oggbs.bosPageHeader = init.oggBosHeader; + oggbs.bytesRemainingInPage = 0; } #endif @@ -8010,9 +7824,9 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading and decoding the metadata. */ - firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */ - seektablePos = 0; - seekpointCount = 0; + firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */ + seektablePos = 0; + seektableSize = 0; if (init.hasMetadataBlocks) { drflac_read_proc onReadOverride = onRead; drflac_seek_proc onSeekOverride = onSeek; @@ -8022,26 +7836,20 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac if (init.container == drflac_container_ogg) { onReadOverride = drflac__on_read_ogg; onSeekOverride = drflac__on_seek_ogg; - pUserDataOverride = (void*)pOggbs; + pUserDataOverride = (void*)&oggbs; } #endif - if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { - #ifndef DR_FLAC_NO_OGG - drflac__free_from_callbacks(pOggbs, &allocationCallbacks); - #endif + if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) { return NULL; } - allocationSize += seekpointCount * sizeof(drflac_seekpoint); + allocationSize += seektableSize; } pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks); if (pFlac == NULL) { - #ifndef DR_FLAC_NO_OGG - drflac__free_from_callbacks(pOggbs, &allocationCallbacks); - #endif return NULL; } @@ -8051,12 +7859,8 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac #ifndef DR_FLAC_NO_OGG if (init.container == drflac_container_ogg) { - drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint))); - DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs)); - - /* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */ - drflac__free_from_callbacks(pOggbs, &allocationCallbacks); - pOggbs = NULL; + drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize); + *pInternalOggbs = oggbs; /* The Ogg bistream needs to be layered on top of the original bitstream. */ pFlac->bs.onRead = drflac__on_read_ogg; @@ -8080,7 +7884,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac { /* If we have a seektable we need to load it now, making sure we move back to where we were previously. */ if (seektablePos != 0) { - pFlac->seekpointCount = seekpointCount; + pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints); pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); DRFLAC_ASSERT(pFlac->bs.onSeek != NULL); @@ -8088,20 +7892,18 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac /* Seek to the seektable, then just read directly into our seektable buffer. */ if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) { - drflac_uint32 iSeekpoint; - - for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { - if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) == DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { - /* Endian swap. */ + if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) { + /* Endian swap. */ + drflac_uint32 iSeekpoint; + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame); pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset); pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount); - } else { - /* Failed to read the seektable. Pretend we don't have one. */ - pFlac->pSeekpoints = NULL; - pFlac->seekpointCount = 0; - break; } + } else { + /* Failed to read the seektable. Pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; } /* We need to seek back to where we were. If this fails it's a critical error. */ @@ -8150,11 +7952,8 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac #ifndef DR_FLAC_NO_STDIO #include -#ifndef DR_FLAC_NO_WCHAR #include /* For wcslen(), wcsrtombs() */ -#endif -/* Errno */ /* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ #include static drflac_result drflac_result_from_errno(int e) @@ -8558,9 +8357,7 @@ static drflac_result drflac_result_from_errno(int e) default: return DRFLAC_ERROR; } } -/* End Errno */ -/* fopen */ static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) { #if defined(_MSC_VER) && _MSC_VER >= 1400 @@ -8621,7 +8418,6 @@ fallback, so if you notice your compiler not detecting this properly I'm happy t #endif #endif -#ifndef DR_FLAC_NO_WCHAR static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks) { if (ppFile != NULL) { @@ -8650,23 +8446,10 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons } #else /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because - fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note - that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler - error I'll look into improving compatibility. + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. */ - - /* - Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just - need to abort with an error. If you encounter a compiler lacking such support, add it to this list - and submit a bug report and it'll be added to the library upstream. - */ - #if defined(__DJGPP__) - { - /* Nothing to do here. This will fall through to the error check below. */ - } - #else { mbstate_t mbs; size_t lenMB; @@ -8708,7 +8491,6 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } - #endif if (*ppFile == NULL) { return DRFLAC_ERROR; @@ -8717,8 +8499,6 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons return DRFLAC_SUCCESS; } -#endif -/* End fopen */ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) { @@ -8751,7 +8531,6 @@ DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocati return pFlac; } -#ifndef DR_FLAC_NO_WCHAR DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) { drflac* pFlac; @@ -8769,7 +8548,6 @@ DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_all return pFlac; } -#endif DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { @@ -8789,7 +8567,6 @@ DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_ return pFlac; } -#ifndef DR_FLAC_NO_WCHAR DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { drflac* pFlac; @@ -8807,7 +8584,6 @@ DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, dr return pFlac; } -#endif #endif /* DR_FLAC_NO_STDIO */ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) @@ -11683,7 +11459,6 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p /* High Level APIs */ -/* SIZE_MAX */ #if defined(SIZE_MAX) #define DRFLAC_SIZE_MAX SIZE_MAX #else @@ -11693,7 +11468,6 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p #define DRFLAC_SIZE_MAX 0xFFFFFFFF #endif #endif -/* End SIZE_MAX */ /* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */ @@ -11742,7 +11516,7 @@ static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ } else { \ drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ - if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \ + if (dataSize > DRFLAC_SIZE_MAX) { \ goto on_error; /* The decoded data is too big. */ \ } \ \ @@ -12007,7 +11781,7 @@ DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator return NULL; } - length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData); + length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); pIter->pRunningData += 4; pComment = pIter->pRunningData; @@ -12077,53 +11851,6 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat /* REVISION HISTORY ================ -v0.12.42 - 2023-11-02 - - Fix build for ARMv6-M. - - Fix a compilation warning with GCC. - -v0.12.41 - 2023-06-17 - - Fix an incorrect date in revision history. No functional change. - -v0.12.40 - 2023-05-22 - - Minor code restructure. No functional change. - -v0.12.39 - 2022-09-17 - - Fix compilation with DJGPP. - - Fix compilation error with Visual Studio 2019 and the ARM build. - - Fix an error with SSE 4.1 detection. - - Add support for disabling wchar_t with DR_WAV_NO_WCHAR. - - Improve compatibility with compilers which lack support for explicit struct packing. - - Improve compatibility with low-end and embedded hardware by reducing the amount of stack - allocation when loading an Ogg encapsulated file. - -v0.12.38 - 2022-04-10 - - Fix compilation error on older versions of GCC. - -v0.12.37 - 2022-02-12 - - Improve ARM detection. - -v0.12.36 - 2022-02-07 - - Fix a compilation error with the ARM build. - -v0.12.35 - 2022-02-06 - - Fix a bug due to underestimating the amount of precision required for the prediction stage. - - Fix some bugs found from fuzz testing. - -v0.12.34 - 2022-01-07 - - Fix some misalignment bugs when reading metadata. - -v0.12.33 - 2021-12-22 - - Fix a bug with seeking when the seek table does not start at PCM frame 0. - -v0.12.32 - 2021-12-11 - - Fix a warning with Clang. - -v0.12.31 - 2021-08-16 - - Silence some warnings. - -v0.12.30 - 2021-07-31 - - Fix platform detection for ARM64. - v0.12.29 - 2021-04-02 - Fix a bug where the running PCM frame index is set to an invalid value when over-seeking. - Fix a decoding error due to an incorrect validation check. @@ -12517,7 +12244,7 @@ For more information, please refer to =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== -Copyright 2023 David Reid +Copyright 2020 David Reid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/raylib/external/dr_mp3.h b/raylib/external/dr_mp3.h index e1a66d9..e28f318 100644 --- a/raylib/external/dr_mp3.h +++ b/raylib/external/dr_mp3.h @@ -1,6 +1,6 @@ /* MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_mp3 - v0.6.39 - 2024-02-27 +dr_mp3 - v0.6.27 - 2021-02-21 David Reid - mackron@gmail.com @@ -95,19 +95,19 @@ extern "C" { #define DRMP3_VERSION_MAJOR 0 #define DRMP3_VERSION_MINOR 6 -#define DRMP3_VERSION_REVISION 39 +#define DRMP3_VERSION_REVISION 27 #define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #include /* For size_t. */ -/* Sized Types */ +/* Sized types. */ typedef signed char drmp3_int8; typedef unsigned char drmp3_uint8; typedef signed short drmp3_int16; typedef unsigned short drmp3_uint16; typedef signed int drmp3_int32; typedef unsigned int drmp3_uint32; -#if defined(_MSC_VER) && !defined(__clang__) +#if defined(_MSC_VER) typedef signed __int64 drmp3_int64; typedef unsigned __int64 drmp3_uint64; #else @@ -124,7 +124,7 @@ typedef unsigned int drmp3_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) typedef drmp3_uint64 drmp3_uintptr; #else typedef drmp3_uint32 drmp3_uintptr; @@ -133,9 +133,7 @@ typedef drmp3_uint8 drmp3_bool8; typedef drmp3_uint32 drmp3_bool32; #define DRMP3_TRUE 1 #define DRMP3_FALSE 0 -/* End Sized Types */ -/* Decorations */ #if !defined(DRMP3_API) #if defined(DRMP3_DLL) #if defined(_WIN32) @@ -165,9 +163,7 @@ typedef drmp3_uint32 drmp3_bool32; #define DRMP3_PRIVATE static #endif #endif -/* End Decorations */ -/* Result Codes */ typedef drmp3_int32 drmp3_result; #define DRMP3_SUCCESS 0 #define DRMP3_ERROR -1 /* A generic error. */ @@ -223,12 +219,11 @@ typedef drmp3_int32 drmp3_result; #define DRMP3_CANCELLED -51 #define DRMP3_MEMORY_ALREADY_MAPPED -52 #define DRMP3_AT_END -53 -/* End Result Codes */ + #define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 #define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2) -/* Inline */ #ifdef _MSC_VER #define DRMP3_INLINE __forceinline #elif defined(__GNUC__) @@ -240,39 +235,21 @@ typedef drmp3_int32 drmp3_result; I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define DRMP3_GNUC_INLINE_HINT __inline__ + #define DRMP3_INLINE __inline__ __attribute__((always_inline)) #else - #define DRMP3_GNUC_INLINE_HINT inline - #endif - - #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) - #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT __attribute__((always_inline)) - #else - #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT + #define DRMP3_INLINE inline __attribute__((always_inline)) #endif #elif defined(__WATCOMC__) #define DRMP3_INLINE __inline #else #define DRMP3_INLINE #endif -/* End Inline */ DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision); DRMP3_API const char* drmp3_version_string(void); -/* Allocation Callbacks */ -typedef struct -{ - void* pUserData; - void* (* onMalloc)(size_t sz, void* pUserData); - void* (* onRealloc)(void* p, size_t sz, void* pUserData); - void (* onFree)(void* p, void* pUserData); -} drmp3_allocation_callbacks; -/* End Allocation Callbacks */ - - /* Low Level Push API ================== @@ -346,6 +323,14 @@ will be either drmp3_seek_origin_start or drmp3_seek_origin_current. */ typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin); +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drmp3_allocation_callbacks; + typedef struct { drmp3_uint32 channels; @@ -355,6 +340,7 @@ typedef struct typedef struct { drmp3dec decoder; + drmp3dec_frame_info frameInfo; drmp3_uint32 channels; drmp3_uint32 sampleRate; drmp3_read_proc onRead; @@ -609,7 +595,7 @@ DRMP3_API const char* drmp3_version_string(void) #define DR_MP3_ONLY_SIMD #endif -#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__))) +#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) #if defined(_MSC_VER) #include #endif @@ -713,9 +699,9 @@ static int drmp3_have_simd(void) #endif -#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__) +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) #define DRMP3_HAVE_ARMV6 1 -static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a) +static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(int32_t a) { drmp3_int32 x = 0; __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); @@ -726,31 +712,6 @@ static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_ar #endif -/* Standard library stuff. */ -#ifndef DRMP3_ASSERT -#include -#define DRMP3_ASSERT(expression) assert(expression) -#endif -#ifndef DRMP3_COPY_MEMORY -#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) -#endif -#ifndef DRMP3_MOVE_MEMORY -#define DRMP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz)) -#endif -#ifndef DRMP3_ZERO_MEMORY -#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) -#endif -#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p))) -#ifndef DRMP3_MALLOC -#define DRMP3_MALLOC(sz) malloc((sz)) -#endif -#ifndef DRMP3_REALLOC -#define DRMP3_REALLOC(p, sz) realloc((p), (sz)) -#endif -#ifndef DRMP3_FREE -#define DRMP3_FREE(p) free((p)) -#endif - typedef struct { const drmp3_uint8 *buf; @@ -1017,7 +978,7 @@ static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_sc static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst) { int i, k; - DRMP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) { for (k = 0; k < 12; k++) @@ -1162,14 +1123,14 @@ static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, c int cnt = scf_count[i]; if (scfsi & 8) { - DRMP3_COPY_MEMORY(scf, ist_pos, cnt); + memcpy(scf, ist_pos, cnt); } else { int bits = scf_size[i]; if (!bits) { - DRMP3_ZERO_MEMORY(scf, cnt); - DRMP3_ZERO_MEMORY(ist_pos, cnt); + memset(scf, 0, cnt); + memset(ist_pos, 0, cnt); } else { int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; @@ -1310,7 +1271,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; static const drmp3_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; -#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - (n))) +#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - n)) #define DRMP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } #define DRMP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } #define DRMP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) @@ -1429,22 +1390,12 @@ static void drmp3_L3_midside_stereo(float *left, int n) int i = 0; float *right = left + 576; #if DRMP3_HAVE_SIMD - if (drmp3_have_simd()) + if (drmp3_have_simd()) for (; i < n - 3; i += 4) { - for (; i < n - 3; i += 4) - { - drmp3_f4 vl = DRMP3_VLD(left + i); - drmp3_f4 vr = DRMP3_VLD(right + i); - DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); - DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); - } -#ifdef __GNUC__ - /* Workaround for spurious -Waggressive-loop-optimizations warning from gcc. - * For more info see: https://github.com/lieff/minimp3/issues/88 - */ - if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0) - return; -#endif + drmp3_f4 vl = DRMP3_VLD(left + i); + drmp3_f4 vr = DRMP3_VLD(right + i); + DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); + DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); } #endif for (; i < n; i++) @@ -1554,7 +1505,7 @@ static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sf *dst++ = src[2*len]; } } - DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float)); + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); } static void drmp3_L3_antialias(float *grbuf, int nbands) @@ -1723,8 +1674,8 @@ static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands) for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) { float tmp[18]; - DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp)); - DRMP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float)); + memcpy(tmp, grbuf, sizeof(tmp)); + memcpy(grbuf, overlap, 6*sizeof(float)); drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6); drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6); @@ -1768,7 +1719,7 @@ static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s) } if (remains > 0) { - DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains); + memmove(h->reserv_buf, s->maindata + pos, remains); } h->reserv = remains; } @@ -1777,8 +1728,8 @@ static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratc { int frame_bytes = (bs->limit - bs->pos)/8; int bytes_have = DRMP3_MIN(h->reserv, main_data_begin); - DRMP3_COPY_MEMORY(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin)); - DRMP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + memcpy(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin)); + memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); return h->reserv >= main_data_begin; } @@ -1878,7 +1829,7 @@ static void drmp3d_DCT_II(float *grbuf, int n) #if DRMP3_HAVE_SSE #define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) #else -#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[(i)*18], vget_low_f32(v)) +#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) #endif for (i = 0; i < 7; i++, y += 4*18) { @@ -1894,7 +1845,7 @@ static void drmp3d_DCT_II(float *grbuf, int n) DRMP3_VSAVE2(3, t[3][7]); } else { -#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[(i)*18], v) +#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v) for (i = 0; i < 7; i++, y += 4*18) { drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]); @@ -1985,8 +1936,8 @@ static drmp3_int16 drmp3d_scale_pcm(float sample) s32 -= (s32 < 0); s = (drmp3_int16)drmp3_clip_int16_arm(s32); #else - if (sample >= 32766.5f) return (drmp3_int16) 32767; - if (sample <= -32767.5f) return (drmp3_int16)-32768; + if (sample >= 32766.5) return (drmp3_int16) 32767; + if (sample <= -32767.5) return (drmp3_int16)-32768; s = (drmp3_int16)(sample + .5f); s -= (s < 0); /* away from zero, to be compliant */ #endif @@ -2117,11 +2068,7 @@ static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins) vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); #endif #else - #if DRMP3_HAVE_SSE static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; - #else - const drmp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f); - #endif a = DRMP3_VMUL(a, g_scale); b = DRMP3_VMUL(b, g_scale); #if DRMP3_HAVE_SSE @@ -2189,7 +2136,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int drmp3d_DCT_II(grbuf + 576*i, nbands); } - DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64); + memcpy(lins, qmf_state, sizeof(float)*15*64); for (i = 0; i < nbands; i += 2) { @@ -2205,7 +2152,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int } else #endif { - DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64); + memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); } } @@ -2283,7 +2230,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m } if (!frame_size) { - DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec)); + memset(dec, 0, sizeof(drmp3dec)); i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); if (!frame_size || i + frame_size > mp3_bytes) { @@ -2293,7 +2240,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m } hdr = mp3 + i; - DRMP3_COPY_MEMORY(dec->header, hdr, DRMP3_HDR_SIZE); + memcpy(dec->header, hdr, DRMP3_HDR_SIZE); info->frame_bytes = i + frame_size; info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2; info->hz = drmp3_hdr_sample_rate_hz(hdr); @@ -2319,7 +2266,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m { for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels)) { - DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); } @@ -2338,7 +2285,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m drmp3_L12_read_scale_info(hdr, bs_frame, sci); - DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); for (i = 0, igr = 0; igr < 3; igr++) { if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) @@ -2346,7 +2293,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m i = 0; drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); - DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels); } if (bs_frame->pos > bs_frame->limit) @@ -2404,9 +2351,9 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num for(; i < num_samples; i++) { float sample = in[i] * 32768.0f; - if (sample >= 32766.5f) + if (sample >= 32766.5) out[i] = (drmp3_int16) 32767; - else if (sample <= -32767.5f) + else if (sample <= -32767.5) out[i] = (drmp3_int16)-32768; else { @@ -2424,7 +2371,8 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num Main Public API ************************************************************************************************************************************************************/ -/* SIZE_MAX */ +#include /* For sin() and exp(). */ + #if defined(SIZE_MAX) #define DRMP3_SIZE_MAX SIZE_MAX #else @@ -2434,7 +2382,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num #define DRMP3_SIZE_MAX 0xFFFFFFFF #endif #endif -/* End SIZE_MAX */ /* Options. */ #ifndef DRMP3_SEEK_LEADING_MP3_FRAMES @@ -2445,10 +2392,32 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num /* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends at least 16K, but in an attempt to reduce data movement I'm making this slightly larger. */ #ifndef DRMP3_DATA_CHUNK_SIZE -#define DRMP3_DATA_CHUNK_SIZE (DRMP3_MIN_DATA_CHUNK_SIZE*4) +#define DRMP3_DATA_CHUNK_SIZE DRMP3_MIN_DATA_CHUNK_SIZE*4 #endif +/* Standard library stuff. */ +#ifndef DRMP3_ASSERT +#include +#define DRMP3_ASSERT(expression) assert(expression) +#endif +#ifndef DRMP3_COPY_MEMORY +#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRMP3_ZERO_MEMORY +#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p))) +#ifndef DRMP3_MALLOC +#define DRMP3_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRMP3_REALLOC +#define DRMP3_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRMP3_FREE +#define DRMP3_FREE(p) free((p)) +#endif + #define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0])) #define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi))) @@ -2490,6 +2459,24 @@ static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b) } +static DRMP3_INLINE double drmp3_sin(double x) +{ + /* TODO: Implement custom sin(x). */ + return sin(x); +} + +static DRMP3_INLINE double drmp3_exp(double x) +{ + /* TODO: Implement custom exp(x). */ + return exp(x); +} + +static DRMP3_INLINE double drmp3_cos(double x) +{ + return drmp3_sin((DRMP3_PI_D*0.5) - x); +} + + static void* drmp3__malloc_default(size_t sz, void* pUserData) { (void)pUserData; @@ -2662,7 +2649,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa /* First we need to move the data down. */ if (pMP3->pData != NULL) { - DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); } pMP3->dataConsumed = 0; @@ -2701,11 +2688,6 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa DRMP3_ASSERT(pMP3->pData != NULL); DRMP3_ASSERT(pMP3->dataCapacity > 0); - /* Do a runtime check here to try silencing a false-positive from clang-analyzer. */ - if (pMP3->pData == NULL) { - return 0; - } - pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */ /* Consume the data. */ @@ -2727,7 +2709,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa size_t bytesRead; /* First we need to move the data down. */ - DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); pMP3->dataConsumed = 0; if (pMP3->dataCapacity == pMP3->dataSize) { @@ -2772,22 +2754,12 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sampl return 0; } - for (;;) { - pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info); - if (pcmFramesRead > 0) { - pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header); - pMP3->pcmFramesConsumedInMP3Frame = 0; - pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; - pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; - break; - } else if (info.frame_bytes > 0) { - /* No frames were read, but it looks like we skipped past one. Read the next MP3 frame. */ - pMP3->memory.currentReadPos += (size_t)info.frame_bytes; - } else { - /* Nothing at all was read. Abort. */ - break; - } + pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info); + if (pcmFramesRead > 0) { + pMP3->pcmFramesConsumedInMP3Frame = 0; + pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; + pMP3->mp3FrameChannels = info.channels; + pMP3->mp3FrameSampleRate = info.hz; } /* Consume the data. */ @@ -2850,7 +2822,7 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm } /* Decode the first frame to confirm that it is indeed a valid MP3 stream. */ - if (drmp3_decode_next_frame(pMP3) == 0) { + if (!drmp3_decode_next_frame(pMP3)) { drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); /* The call above may have allocated memory. Need to make sure it's freed before aborting. */ return DRMP3_FALSE; /* Not a valid MP3 stream. */ } @@ -2947,7 +2919,6 @@ DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t #include #include /* For wcslen(), wcsrtombs() */ -/* Errno */ /* drmp3_result_from_errno() is only used inside DR_MP3_NO_STDIO for now. Move this out if it's ever used elsewhere. */ #include static drmp3_result drmp3_result_from_errno(int e) @@ -3351,9 +3322,7 @@ static drmp3_result drmp3_result_from_errno(int e) default: return DRMP3_ERROR; } } -/* End Errno */ -/* fopen */ static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) { #if defined(_MSC_VER) && _MSC_VER >= 1400 @@ -3442,23 +3411,10 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const } #else /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because - fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note - that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler - error I'll look into improving compatibility. + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. */ - - /* - Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just - need to abort with an error. If you encounter a compiler lacking such support, add it to this list - and submit a bug report and it'll be added to the library upstream. - */ - #if defined(__DJGPP__) - { - /* Nothing to do here. This will fall through to the error check below. */ - } - #else { mbstate_t mbs; size_t lenMB; @@ -3500,7 +3456,6 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } - #endif if (*ppFile == NULL) { return DRMP3_ERROR; @@ -3509,7 +3464,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const return DRMP3_SUCCESS; } -/* End fopen */ + static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) @@ -4222,7 +4177,7 @@ static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float); newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float); - if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) { + if (newFramesBufferSize > DRMP3_SIZE_MAX) { break; } @@ -4289,7 +4244,7 @@ static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pC oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16); newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16); - if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) { + if (newFramesBufferSize > DRMP3_SIZE_MAX) { break; } @@ -4495,48 +4450,6 @@ counts rather than sample counts. /* REVISION HISTORY ================ -v0.6.39 - 2024-02-27 - - Fix a Wdouble-promotion warning. - -v0.6.38 - 2023-11-02 - - Fix build for ARMv6-M. - -v0.6.37 - 2023-07-07 - - Silence a static analysis warning. - -v0.6.36 - 2023-06-17 - - Fix an incorrect date in revision history. No functional change. - -v0.6.35 - 2023-05-22 - - Minor code restructure. No functional change. - -v0.6.34 - 2022-09-17 - - Fix compilation with DJGPP. - - Fix compilation when compiling with x86 with no SSE2. - - Remove an unnecessary variable from the drmp3 structure. - -v0.6.33 - 2022-04-10 - - Fix compilation error with the MSVC ARM64 build. - - Fix compilation error on older versions of GCC. - - Remove some unused functions. - -v0.6.32 - 2021-12-11 - - Fix a warning with Clang. - -v0.6.31 - 2021-08-22 - - Fix a bug when loading from memory. - -v0.6.30 - 2021-08-16 - - Silence some warnings. - - Replace memory operations with DRMP3_* macros. - -v0.6.29 - 2021-08-08 - - Bring up to date with minimp3. - -v0.6.28 - 2021-07-31 - - Fix platform detection for ARM64. - - Fix a compilation error with C89. - v0.6.27 - 2021-02-21 - Fix a warning due to referencing _MSC_VER when it is undefined. @@ -4811,7 +4724,7 @@ For more information, please refer to =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== -Copyright 2023 David Reid +Copyright 2020 David Reid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/raylib/external/dr_wav.h b/raylib/external/dr_wav.h index a8207ab..be1438b 100644 --- a/raylib/external/dr_wav.h +++ b/raylib/external/dr_wav.h @@ -1,17 +1,36 @@ /* WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_wav - v0.13.16 - 2024-02-27 +dr_wav - v0.12.19 - 2021-02-21 David Reid - mackron@gmail.com GitHub: https://github.com/mackron/dr_libs */ +/* +RELEASE NOTES - VERSION 0.12 +============================ +Version 0.12 includes breaking changes to custom chunk handling. + + +Changes to Chunk Callback +------------------------- +dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been updated to include both the +container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file. + +Previously, there was no direct way to determine the container, and therefore no way to discriminate against the different IDs in the chunk header (RIFF and +Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use. + +Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk +callback which will give you information about the data format. To determine the sample format, use `drwav_fmt_get_format()`. This will return one of the +`DR_WAVE_FORMAT_*` tokens. +*/ + /* Introduction ============ This is a single file library. To use it, do something like the following in one .c file. - + ```c #define DR_WAV_IMPLEMENTATION #include "dr_wav.h" @@ -79,9 +98,7 @@ dr_wav can also be used to output WAV files. This does not currently support com drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples); ``` -Note that writing to AIFF or RIFX is not supported. - -dr_wav has support for decoding from a number of different encapsulation formats. See below for details. +dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention. Build Options @@ -94,44 +111,24 @@ Build Options #define DR_WAV_NO_STDIO Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc. -#define DR_WAV_NO_WCHAR - Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_WAV_NO_STDIO is also defined. - - -Supported Encapsulations -======================== -- RIFF (Regular WAV) -- RIFX (Big-Endian) -- AIFF (Does not currently support ADPCM) -- RF64 -- W64 - -Note that AIFF and RIFX do not support write mode, nor do they support reading of metadata. - - -Supported Encodings -=================== -- Unsigned 8-bit PCM -- Signed 12-bit PCM -- Signed 16-bit PCM -- Signed 24-bit PCM -- Signed 32-bit PCM -- IEEE 32-bit floating point -- IEEE 64-bit floating point -- A-law and u-law -- Microsoft ADPCM -- IMA ADPCM (DVI, format code 0x11) - -8-bit PCM encodings are always assumed to be unsigned. Signed 8-bit encoding can only be read with `drwav_read_raw()`. - -Note that ADPCM is not currently supported with AIFF. Contributions welcome. Notes ===== - Samples are always interleaved. - The default read function does not do any data conversion. Use `drwav_read_pcm_frames_f32()`, `drwav_read_pcm_frames_s32()` and `drwav_read_pcm_frames_s16()` - to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively. + to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively. Tested and supported internal + formats include the following: + - Unsigned 8-bit PCM + - Signed 12-bit PCM + - Signed 16-bit PCM + - Signed 24-bit PCM + - Signed 32-bit PCM + - IEEE 32-bit floating point + - IEEE 64-bit floating point + - A-law and u-law + - Microsoft ADPCM + - IMA ADPCM (DVI, format code 0x11) - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. */ @@ -146,20 +143,20 @@ extern "C" { #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) #define DRWAV_VERSION_MAJOR 0 -#define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 16 +#define DRWAV_VERSION_MINOR 12 +#define DRWAV_VERSION_REVISION 19 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include /* For size_t. */ -/* Sized Types */ +/* Sized types. */ typedef signed char drwav_int8; typedef unsigned char drwav_uint8; typedef signed short drwav_int16; typedef unsigned short drwav_uint16; typedef signed int drwav_int32; typedef unsigned int drwav_uint32; -#if defined(_MSC_VER) && !defined(__clang__) +#if defined(_MSC_VER) typedef signed __int64 drwav_int64; typedef unsigned __int64 drwav_uint64; #else @@ -176,7 +173,7 @@ typedef unsigned int drwav_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) typedef drwav_uint64 drwav_uintptr; #else typedef drwav_uint32 drwav_uintptr; @@ -185,9 +182,7 @@ typedef drwav_uint8 drwav_bool8; typedef drwav_uint32 drwav_bool32; #define DRWAV_TRUE 1 #define DRWAV_FALSE 0 -/* End Sized Types */ -/* Decorations */ #if !defined(DRWAV_API) #if defined(DRWAV_DLL) #if defined(_WIN32) @@ -217,9 +212,7 @@ typedef drwav_uint32 drwav_bool32; #define DRWAV_PRIVATE static #endif #endif -/* End Decorations */ -/* Result Codes */ typedef drwav_int32 drwav_result; #define DRWAV_SUCCESS 0 #define DRWAV_ERROR -1 /* A generic error. */ @@ -275,7 +268,6 @@ typedef drwav_int32 drwav_result; #define DRWAV_CANCELLED -51 #define DRWAV_MEMORY_ALREADY_MAPPED -52 #define DRWAV_AT_END -53 -/* End Result Codes */ /* Common data formats. */ #define DR_WAVE_FORMAT_PCM 0x1 @@ -286,23 +278,17 @@ typedef drwav_int32 drwav_result; #define DR_WAVE_FORMAT_DVI_ADPCM 0x11 #define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE +/* Constants. */ +#ifndef DRWAV_MAX_SMPL_LOOPS +#define DRWAV_MAX_SMPL_LOOPS 1 +#endif + /* Flags to pass into drwav_init_ex(), etc. */ #define DRWAV_SEQUENTIAL 0x00000001 -#define DRWAV_WITH_METADATA 0x00000002 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision); DRWAV_API const char* drwav_version_string(void); -/* Allocation Callbacks */ -typedef struct -{ - void* pUserData; - void* (* onMalloc)(size_t sz, void* pUserData); - void* (* onRealloc)(void* p, size_t sz, void* pUserData); - void (* onFree)(void* p, void* pUserData); -} drwav_allocation_callbacks; -/* End Allocation Callbacks */ - typedef enum { drwav_seek_origin_start, @@ -312,10 +298,8 @@ typedef enum typedef enum { drwav_container_riff, - drwav_container_rifx, drwav_container_w64, - drwav_container_rf64, - drwav_container_aiff + drwav_container_rf64 } drwav_container; typedef struct @@ -440,12 +424,19 @@ Use the `container` argument to discriminate the fields in `pChunkHeader->id`. I use `id.fourcc`, otherwise you should use `id.guid`. The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the -`DR_WAVE_FORMAT_*` identifiers. +`DR_WAVE_FORMAT_*` identifiers. The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk. */ typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT); +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drwav_allocation_callbacks; /* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */ typedef struct @@ -474,367 +465,32 @@ typedef struct drwav_uint32 bitsPerSample; } drwav_data_format; -typedef enum -{ - drwav_metadata_type_none = 0, - - /* - Unknown simply means a chunk that drwav does not handle specifically. You can still ask to - receive these chunks as metadata objects. It is then up to you to interpret the chunk's data. - You can also write unknown metadata to a wav file. Be careful writing unknown chunks if you - have also edited the audio data. The unknown chunks could represent offsets/sizes that no - longer correctly correspond to the audio data. - */ - drwav_metadata_type_unknown = 1 << 0, - - /* Only 1 of each of these metadata items are allowed in a wav file. */ - drwav_metadata_type_smpl = 1 << 1, - drwav_metadata_type_inst = 1 << 2, - drwav_metadata_type_cue = 1 << 3, - drwav_metadata_type_acid = 1 << 4, - drwav_metadata_type_bext = 1 << 5, - - /* - Wav files often have a LIST chunk. This is a chunk that contains a set of subchunks. For this - higher-level metadata API, we don't make a distinction between a regular chunk and a LIST - subchunk. Instead, they are all just 'metadata' items. - - There can be multiple of these metadata items in a wav file. - */ - drwav_metadata_type_list_label = 1 << 6, - drwav_metadata_type_list_note = 1 << 7, - drwav_metadata_type_list_labelled_cue_region = 1 << 8, - - drwav_metadata_type_list_info_software = 1 << 9, - drwav_metadata_type_list_info_copyright = 1 << 10, - drwav_metadata_type_list_info_title = 1 << 11, - drwav_metadata_type_list_info_artist = 1 << 12, - drwav_metadata_type_list_info_comment = 1 << 13, - drwav_metadata_type_list_info_date = 1 << 14, - drwav_metadata_type_list_info_genre = 1 << 15, - drwav_metadata_type_list_info_album = 1 << 16, - drwav_metadata_type_list_info_tracknumber = 1 << 17, - - /* Other type constants for convenience. */ - drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software - | drwav_metadata_type_list_info_copyright - | drwav_metadata_type_list_info_title - | drwav_metadata_type_list_info_artist - | drwav_metadata_type_list_info_comment - | drwav_metadata_type_list_info_date - | drwav_metadata_type_list_info_genre - | drwav_metadata_type_list_info_album - | drwav_metadata_type_list_info_tracknumber, - - drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label - | drwav_metadata_type_list_note - | drwav_metadata_type_list_labelled_cue_region, - - drwav_metadata_type_all = -2, /*0xFFFFFFFF & ~drwav_metadata_type_unknown,*/ - drwav_metadata_type_all_including_unknown = -1 /*0xFFFFFFFF,*/ -} drwav_metadata_type; - -/* -Sampler Metadata - -The sampler chunk contains information about how a sound should be played in the context of a whole -audio production, and when used in a sampler. See https://en.wikipedia.org/wiki/Sample-based_synthesis. -*/ -typedef enum -{ - drwav_smpl_loop_type_forward = 0, - drwav_smpl_loop_type_pingpong = 1, - drwav_smpl_loop_type_backward = 2 -} drwav_smpl_loop_type; +/* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */ typedef struct { - /* The ID of the associated cue point, see drwav_cue and drwav_cue_point. As with all cue point IDs, this can correspond to a label chunk to give this loop a name, see drwav_list_label_or_note. */ drwav_uint32 cuePointId; - - /* See drwav_smpl_loop_type. */ drwav_uint32 type; - - /* The byte offset of the first sample to be played in the loop. */ - drwav_uint32 firstSampleByteOffset; - - /* The byte offset into the audio data of the last sample to be played in the loop. */ - drwav_uint32 lastSampleByteOffset; - - /* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */ - drwav_uint32 sampleFraction; - - /* Number of times to play the loop. 0 means loop infinitely. */ + drwav_uint32 start; + drwav_uint32 end; + drwav_uint32 fraction; drwav_uint32 playCount; } drwav_smpl_loop; -typedef struct + typedef struct { - /* IDs for a particular MIDI manufacturer. 0 if not used. */ - drwav_uint32 manufacturerId; - drwav_uint32 productId; - - /* The period of 1 sample in nanoseconds. */ - drwav_uint32 samplePeriodNanoseconds; - - /* The MIDI root note of this file. 0 to 127. */ - drwav_uint32 midiUnityNote; - - /* The fraction of a semitone up from the given MIDI note. This is a value from 0 to UINT32_MAX, where 0 means no change and (UINT32_MAX / 2) is half a semitone (AKA 50 cents). */ + drwav_uint32 manufacturer; + drwav_uint32 product; + drwav_uint32 samplePeriod; + drwav_uint32 midiUnityNotes; drwav_uint32 midiPitchFraction; - - /* Data relating to SMPTE standards which are used for syncing audio and video. 0 if not used. */ drwav_uint32 smpteFormat; drwav_uint32 smpteOffset; - - /* drwav_smpl_loop loops. */ - drwav_uint32 sampleLoopCount; - - /* Optional sampler-specific data. */ - drwav_uint32 samplerSpecificDataSizeInBytes; - - drwav_smpl_loop* pLoops; - drwav_uint8* pSamplerSpecificData; + drwav_uint32 numSampleLoops; + drwav_uint32 samplerData; + drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS]; } drwav_smpl; -/* -Instrument Metadata - -The inst metadata contains data about how a sound should be played as part of an instrument. This -commonly read by samplers. See https://en.wikipedia.org/wiki/Sample-based_synthesis. -*/ -typedef struct -{ - drwav_int8 midiUnityNote; /* The root note of the audio as a MIDI note number. 0 to 127. */ - drwav_int8 fineTuneCents; /* -50 to +50 */ - drwav_int8 gainDecibels; /* -64 to +64 */ - drwav_int8 lowNote; /* 0 to 127 */ - drwav_int8 highNote; /* 0 to 127 */ - drwav_int8 lowVelocity; /* 1 to 127 */ - drwav_int8 highVelocity; /* 1 to 127 */ -} drwav_inst; - -/* -Cue Metadata - -Cue points are markers at specific points in the audio. They often come with an associated piece of -drwav_list_label_or_note metadata which contains the text for the marker. -*/ -typedef struct -{ - /* Unique identification value. */ - drwav_uint32 id; - - /* Set to 0. This is only relevant if there is a 'playlist' chunk - which is not supported by dr_wav. */ - drwav_uint32 playOrderPosition; - - /* Should always be "data". This represents the fourcc value of the chunk that this cue point corresponds to. dr_wav only supports a single data chunk so this should always be "data". */ - drwav_uint8 dataChunkId[4]; - - /* Set to 0. This is only relevant if there is a wave list chunk. dr_wav, like lots of readers/writers, do not support this. */ - drwav_uint32 chunkStart; - - /* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */ - drwav_uint32 blockStart; - - /* For uncompressed formats this is the byte offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */ - drwav_uint32 sampleByteOffset; -} drwav_cue_point; - -typedef struct -{ - drwav_uint32 cuePointCount; - drwav_cue_point *pCuePoints; -} drwav_cue; - -/* -Acid Metadata - -This chunk contains some information about the time signature and the tempo of the audio. -*/ -typedef enum -{ - drwav_acid_flag_one_shot = 1, /* If this is not set, then it is a loop instead of a one-shot. */ - drwav_acid_flag_root_note_set = 2, - drwav_acid_flag_stretch = 4, - drwav_acid_flag_disk_based = 8, - drwav_acid_flag_acidizer = 16 /* Not sure what this means. */ -} drwav_acid_flag; - -typedef struct -{ - /* A bit-field, see drwav_acid_flag. */ - drwav_uint32 flags; - - /* Valid if flags contains drwav_acid_flag_root_note_set. It represents the MIDI root note the file - a value from 0 to 127. */ - drwav_uint16 midiUnityNote; - - /* Reserved values that should probably be ignored. reserved1 seems to often be 128 and reserved2 is 0. */ - drwav_uint16 reserved1; - float reserved2; - - /* Number of beats. */ - drwav_uint32 numBeats; - - /* The time signature of the audio. */ - drwav_uint16 meterDenominator; - drwav_uint16 meterNumerator; - - /* Beats per minute of the track. Setting a value of 0 suggests that there is no tempo. */ - float tempo; -} drwav_acid; - -/* -Cue Label or Note metadata - -These are 2 different types of metadata, but they have the exact same format. Labels tend to be the -more common and represent a short name for a cue point. Notes might be used to represent a longer -comment. -*/ -typedef struct -{ - /* The ID of a cue point that this label or note corresponds to. */ - drwav_uint32 cuePointId; - - /* Size of the string not including any null terminator. */ - drwav_uint32 stringLength; - - /* The string. The *init_with_metadata functions null terminate this for convenience. */ - char* pString; -} drwav_list_label_or_note; - -/* -BEXT metadata, also known as Broadcast Wave Format (BWF) - -This metadata adds some extra description to an audio file. You must check the version field to -determine if the UMID or the loudness fields are valid. -*/ -typedef struct -{ - /* - These top 3 fields, and the umid field are actually defined in the standard as a statically - sized buffers. In order to reduce the size of this struct (and therefore the union in the - metadata struct), we instead store these as pointers. - */ - char* pDescription; /* Can be NULL or a null-terminated string, must be <= 256 characters. */ - char* pOriginatorName; /* Can be NULL or a null-terminated string, must be <= 32 characters. */ - char* pOriginatorReference; /* Can be NULL or a null-terminated string, must be <= 32 characters. */ - char pOriginationDate[10]; /* ASCII "yyyy:mm:dd". */ - char pOriginationTime[8]; /* ASCII "hh:mm:ss". */ - drwav_uint64 timeReference; /* First sample count since midnight. */ - drwav_uint16 version; /* Version of the BWF, check this to see if the fields below are valid. */ - - /* - Unrestricted ASCII characters containing a collection of strings terminated by CR/LF. Each - string shall contain a description of a coding process applied to the audio data. - */ - char* pCodingHistory; - drwav_uint32 codingHistorySize; - - /* Fields below this point are only valid if the version is 1 or above. */ - drwav_uint8* pUMID; /* Exactly 64 bytes of SMPTE UMID */ - - /* Fields below this point are only valid if the version is 2 or above. */ - drwav_uint16 loudnessValue; /* Integrated Loudness Value of the file in LUFS (multiplied by 100). */ - drwav_uint16 loudnessRange; /* Loudness Range of the file in LU (multiplied by 100). */ - drwav_uint16 maxTruePeakLevel; /* Maximum True Peak Level of the file expressed as dBTP (multiplied by 100). */ - drwav_uint16 maxMomentaryLoudness; /* Highest value of the Momentary Loudness Level of the file in LUFS (multiplied by 100). */ - drwav_uint16 maxShortTermLoudness; /* Highest value of the Short-Term Loudness Level of the file in LUFS (multiplied by 100). */ -} drwav_bext; - -/* -Info Text Metadata - -There a many different types of information text that can be saved in this format. This is where -things like the album name, the artists, the year it was produced, etc are saved. See -drwav_metadata_type for the full list of types that dr_wav supports. -*/ -typedef struct -{ - /* Size of the string not including any null terminator. */ - drwav_uint32 stringLength; - - /* The string. The *init_with_metadata functions null terminate this for convenience. */ - char* pString; -} drwav_list_info_text; - -/* -Labelled Cue Region Metadata - -The labelled cue region metadata is used to associate some region of audio with text. The region -starts at a cue point, and extends for the given number of samples. -*/ -typedef struct -{ - /* The ID of a cue point that this object corresponds to. */ - drwav_uint32 cuePointId; - - /* The number of samples from the cue point forwards that should be considered this region */ - drwav_uint32 sampleLength; - - /* Four characters used to say what the purpose of this region is. */ - drwav_uint8 purposeId[4]; - - /* Unsure of the exact meanings of these. It appears to be acceptable to set them all to 0. */ - drwav_uint16 country; - drwav_uint16 language; - drwav_uint16 dialect; - drwav_uint16 codePage; - - /* Size of the string not including any null terminator. */ - drwav_uint32 stringLength; - - /* The string. The *init_with_metadata functions null terminate this for convenience. */ - char* pString; -} drwav_list_labelled_cue_region; - -/* -Unknown Metadata - -This chunk just represents a type of chunk that dr_wav does not understand. - -Unknown metadata has a location attached to it. This is because wav files can have a LIST chunk -that contains subchunks. These LIST chunks can be one of two types. An adtl list, or an INFO -list. This enum is used to specify the location of a chunk that dr_wav currently doesn't support. -*/ -typedef enum -{ - drwav_metadata_location_invalid, - drwav_metadata_location_top_level, - drwav_metadata_location_inside_info_list, - drwav_metadata_location_inside_adtl_list -} drwav_metadata_location; - -typedef struct -{ - drwav_uint8 id[4]; - drwav_metadata_location chunkLocation; - drwav_uint32 dataSizeInBytes; - drwav_uint8* pData; -} drwav_unknown_metadata; - -/* -Metadata is saved as a union of all the supported types. -*/ -typedef struct -{ - /* Determines which item in the union is valid. */ - drwav_metadata_type type; - - union - { - drwav_cue cue; - drwav_smpl smpl; - drwav_acid acid; - drwav_inst inst; - drwav_bext bext; - drwav_list_label_or_note labelOrNote; /* List label or list note. */ - drwav_list_labelled_cue_region labelledCueRegion; - drwav_list_info_text infoText; /* Any of the list info types. */ - drwav_unknown_metadata unknown; - } data; -} drwav_metadata; - typedef struct { /* A pointer to the function to call when more data is needed. */ @@ -878,16 +534,13 @@ typedef struct /* The size in bytes of the data chunk. */ drwav_uint64 dataChunkDataSize; - + /* The position in the stream of the first data byte of the data chunk. This is used for seeking. */ drwav_uint64 dataChunkDataPos; /* The number of bytes remaining in the data chunk. */ drwav_uint64 bytesRemaining; - /* The current read position in PCM frames. */ - drwav_uint64 readCursorInPCMFrames; - /* Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always @@ -899,16 +552,20 @@ typedef struct drwav_bool32 isSequentialWrite; - /* A array of metadata. This is valid after the *init_with_metadata call returns. It will be valid until drwav_uninit() is called. You can take ownership of this data with drwav_take_ownership_of_metadata(). */ - drwav_metadata* pMetadata; - drwav_uint32 metadataCount; + /* smpl chunk. */ + drwav_smpl smpl; /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */ drwav__memory_stream memoryStream; drwav__memory_stream_write memoryStreamWrite; - + /* Generic data for compressed formats. This data is shared across all block-compressed formats. */ + struct + { + drwav_uint64 iCurrentPCMFrame; /* The index of the next PCM frame that will be read by drwav_read_*(). This is used with "totalPCMFrameCount" to ensure we don't read excess samples at the end of the last block. */ + } compressed; + /* Microsoft ADPCM specific data. */ struct { @@ -929,13 +586,6 @@ typedef struct drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */ drwav_uint32 cachedFrameCount; } ima; - - /* AIFF specific data. */ - struct - { - drwav_bool8 isLE; /* Will be set to true if the audio data is little-endian encoded. */ - drwav_bool8 isUnsigned; /* Only used for 8-bit samples. When set to true, will be treated as unsigned. */ - } aiff; } drwav; @@ -970,15 +620,13 @@ See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() */ DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); -DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); /* Initializes a pre-allocated drwav object for writing. -onWrite [in] The function to call when data needs to be written. -onSeek [in] The function to call when the write position needs to move. -pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. -metadata, numMetadata [in, optional] An array of metadata objects that should be written to the file. The array is not edited. You are responsible for this metadata memory and it must maintain valid until drwav_uninit() is called. +onWrite [in] The function to call when data needs to be written. +onSeek [in] The function to call when the write position needs to move. +pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. Returns true if successful; false otherwise. @@ -995,31 +643,19 @@ See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); -DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount); /* Utility function to determine the target size of the entire data to be written (including all headers and chunks). Returns the target size in bytes. -The metadata argument can be NULL meaning no metadata exists. - Useful if the application needs to know the size to allocate. Only writing to the RIFF chunk and one data chunk is currently supported. See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write() */ -DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount); - -/* -Take ownership of the metadata objects that were allocated via one of the init_with_metadata() function calls. The init_with_metdata functions perform a single heap allocation for this metadata. - -Useful if you want the data to persist beyond the lifetime of the drwav object. - -You must free the data returned from this function using drwav_free(). -*/ -DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav); +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); /* Uninitializes the given drwav object. @@ -1069,16 +705,6 @@ Returns true if successful; false otherwise. */ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex); -/* -Retrieves the current read position in pcm frames. -*/ -DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor); - -/* -Retrieves the length of the file. -*/ -DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength); - /* Writes raw audio data. @@ -1099,6 +725,7 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesTo DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); + /* Conversion Utilities */ #ifndef DR_WAV_NO_CONVERSION_API @@ -1223,9 +850,6 @@ DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks); DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); -DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); -DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); - /* Helper for initializing a wave file for writing using stdio. @@ -1252,7 +876,6 @@ The buffer should contain the contents of the entire wave file, not just the sam */ DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks); DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); -DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); /* Helper for initializing a writer which outputs data to a memory buffer. @@ -1309,7 +932,6 @@ DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data); DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data); DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data); DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data); -DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data); /* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */ DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]); @@ -1334,21 +956,14 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #ifndef dr_wav_c #define dr_wav_c -#ifdef __MRC__ -/* MrC currently doesn't compile dr_wav correctly with any optimizations enabled. */ -#pragma options opt off -#endif - #include -#include +#include /* For memcpy(), memset() */ #include /* For INT_MAX */ #ifndef DR_WAV_NO_STDIO #include -#ifndef DR_WAV_NO_WCHAR #include #endif -#endif /* Standard library stuff. */ #ifndef DRWAV_ASSERT @@ -1379,11 +994,10 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) #define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) -#define drwav_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset)) -#define DRWAV_MAX_SIMD_VECTOR_SIZE 32 +#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ -/* Architecture Detection */ +/* CPU architecture. */ #if defined(__x86_64__) || defined(_M_X64) #define DRWAV_X64 #elif defined(__i386) || defined(_M_IX86) @@ -1391,9 +1005,7 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #elif defined(__arm__) || defined(_M_ARM) #define DRWAV_ARM #endif -/* End Architecture Detection */ -/* Inline */ #ifdef _MSC_VER #define DRWAV_INLINE __forceinline #elif defined(__GNUC__) @@ -1405,24 +1017,16 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define DRWAV_GNUC_INLINE_HINT __inline__ + #define DRWAV_INLINE __inline__ __attribute__((always_inline)) #else - #define DRWAV_GNUC_INLINE_HINT inline - #endif - - #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) - #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT __attribute__((always_inline)) - #else - #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT + #define DRWAV_INLINE inline __attribute__((always_inline)) #endif #elif defined(__WATCOMC__) #define DRWAV_INLINE __inline #else #define DRWAV_INLINE #endif -/* End Inline */ -/* SIZE_MAX */ #if defined(SIZE_MAX) #define DRWAV_SIZE_MAX SIZE_MAX #else @@ -1432,11 +1036,6 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #define DRWAV_SIZE_MAX 0xFFFFFFFF #endif #endif -/* End SIZE_MAX */ - -/* Weird bit manipulation is for C89 compatibility (no direct support for 64-bit integers). */ -#define DRWAV_INT64_MIN ((drwav_int64) ((drwav_uint64)0x80000000 << 32)) -#define DRWAV_INT64_MAX ((drwav_int64)(((drwav_uint64)0x7FFFFFFF << 32) | 0xFFFFFFFF)) #if defined(_MSC_VER) && _MSC_VER >= 1400 #define DRWAV_HAS_BYTESWAP16_INTRINSIC @@ -1504,7 +1103,7 @@ static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xA static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */ static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ -/*static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};*/ /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */ static DRWAV_INLINE int drwav__is_little_endian(void) @@ -1520,7 +1119,7 @@ static DRWAV_INLINE int drwav__is_little_endian(void) } -static DRWAV_INLINE void drwav_bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) +static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) { int i; for (i = 0; i < 16; ++i) { @@ -1646,20 +1245,6 @@ static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_u } -static DRWAV_INLINE drwav_int64 drwav__bswap_s64(drwav_int64 n) -{ - return (drwav_int64)drwav__bswap64((drwav_uint64)n); -} - -static DRWAV_INLINE void drwav__bswap_samples_s64(drwav_int64* pSamples, drwav_uint64 sampleCount) -{ - drwav_uint64 iSample; - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamples[iSample] = drwav__bswap_s64(pSamples[iSample]); - } -} - - static DRWAV_INLINE float drwav__bswap_f32(float n) { union { @@ -1681,30 +1266,44 @@ static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 } -static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +static DRWAV_INLINE double drwav__bswap_f64(double n) { + union { + drwav_uint64 i; + double f; + } x; + x.f = n; + x.i = drwav__bswap64(x.i); + + return x.f; +} + +static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +{ + /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */ switch (bytesPerSample) { - case 1: - { - /* No-op. */ - } break; - case 2: + case 2: /* s16, s12 (loosely packed) */ { drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); } break; - case 3: + case 3: /* s24 */ { drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount); } break; - case 4: + case 4: /* s32 */ { drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount); } break; - case 8: - { - drwav__bswap_samples_s64((drwav_int64*)pSamples, sampleCount); - } break; default: { /* Unsupported format. */ @@ -1713,91 +1312,59 @@ static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampl } } - - -DRWAV_PRIVATE DRWAV_INLINE drwav_bool32 drwav_is_container_be(drwav_container container) +static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) { - if (container == drwav_container_rifx || container == drwav_container_aiff) { - return DRWAV_TRUE; - } else { - return DRWAV_FALSE; + switch (bytesPerSample) + { + #if 0 /* Contributions welcome for f16 support. */ + case 2: /* f16 */ + { + drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount); + } break; + #endif + case 4: /* f32 */ + { + drwav__bswap_samples_f32((float*)pSamples, sampleCount); + } break; + case 8: /* f64 */ + { + drwav__bswap_samples_f64((double*)pSamples, sampleCount); + } break; + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; } } - -DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_le(const drwav_uint8* data) +static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format) { - return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8); -} + switch (format) + { + case DR_WAVE_FORMAT_PCM: + { + drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample); + } break; -DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_be(const drwav_uint8* data) -{ - return ((drwav_uint16)data[1] << 0) | ((drwav_uint16)data[0] << 8); -} + case DR_WAVE_FORMAT_IEEE_FLOAT: + { + drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample); + } break; -DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_ex(const drwav_uint8* data, drwav_container container) -{ - if (drwav_is_container_be(container)) { - return drwav_bytes_to_u16_be(data); - } else { - return drwav_bytes_to_u16_le(data); - } -} + case DR_WAVE_FORMAT_ALAW: + case DR_WAVE_FORMAT_MULAW: + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; - -DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_le(const drwav_uint8* data) -{ - return ((drwav_uint32)data[0] << 0) | ((drwav_uint32)data[1] << 8) | ((drwav_uint32)data[2] << 16) | ((drwav_uint32)data[3] << 24); -} - -DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_be(const drwav_uint8* data) -{ - return ((drwav_uint32)data[3] << 0) | ((drwav_uint32)data[2] << 8) | ((drwav_uint32)data[1] << 16) | ((drwav_uint32)data[0] << 24); -} - -DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_ex(const drwav_uint8* data, drwav_container container) -{ - if (drwav_is_container_be(container)) { - return drwav_bytes_to_u32_be(data); - } else { - return drwav_bytes_to_u32_le(data); - } -} - - - -DRWAV_PRIVATE drwav_int64 drwav_aiff_extented_to_s64(const drwav_uint8* data) -{ - drwav_uint32 exponent = ((drwav_uint32)data[0] << 8) | data[1]; - drwav_uint64 hi = ((drwav_uint64)data[2] << 24) | ((drwav_uint64)data[3] << 16) | ((drwav_uint64)data[4] << 8) | ((drwav_uint64)data[5] << 0); - drwav_uint64 lo = ((drwav_uint64)data[6] << 24) | ((drwav_uint64)data[7] << 16) | ((drwav_uint64)data[8] << 8) | ((drwav_uint64)data[9] << 0); - drwav_uint64 significand = (hi << 32) | lo; - int sign = exponent >> 15; - - /* Remove sign bit. */ - exponent &= 0x7FFF; - - /* Special cases. */ - if (exponent == 0 && significand == 0) { - return 0; - } else if (exponent == 0x7FFF) { - return sign ? DRWAV_INT64_MIN : DRWAV_INT64_MAX; /* Infinite. */ - } - - exponent -= 16383; - - if (exponent > 63) { - return sign ? DRWAV_INT64_MIN : DRWAV_INT64_MAX; /* Too big for a 64-bit integer. */ - } else if (exponent < 1) { - return 0; /* Number is less than 1, so rounds down to 0. */ - } - - significand >>= (63 - exponent); - - if (sign) { - return -(drwav_int64)significand; - } else { - return (drwav_int64)significand; + case DR_WAVE_FORMAT_ADPCM: + case DR_WAVE_FORMAT_DVI_ADPCM: + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; } } @@ -1921,7 +1488,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_d DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut) { - if (container == drwav_container_riff || container == drwav_container_rifx || container == drwav_container_rf64 || container == drwav_container_aiff) { + if (container == drwav_container_riff || container == drwav_container_rf64) { drwav_uint8 sizeInBytes[4]; if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { @@ -1932,11 +1499,10 @@ DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void return DRWAV_INVALID_FILE; } - pHeaderOut->sizeInBytes = drwav_bytes_to_u32_ex(sizeInBytes, container); + pHeaderOut->sizeInBytes = drwav_bytes_to_u32(sizeInBytes); pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); - *pRunningBytesReadOut += 8; - } else if (container == drwav_container_w64) { + } else { drwav_uint8 sizeInBytes[8]; if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { @@ -1950,8 +1516,6 @@ DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */ pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); *pRunningBytesReadOut += 24; - } else { - return DRWAV_INVALID_FILE; } return DRWAV_SUCCESS; @@ -2005,6 +1569,115 @@ DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_ } +DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) +{ + drwav_chunk_header header; + drwav_uint8 fmt[16]; + + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + + /* Skip non-fmt chunks. */ + while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav_fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) { + if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; + + /* Try the next header. */ + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + } + + + /* Validation. */ + if (container == drwav_container_riff || container == drwav_container_rf64) { + if (!drwav_fourcc_equal(header.id.fourcc, "fmt ")) { + return DRWAV_FALSE; + } + } else { + if (!drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT)) { + return DRWAV_FALSE; + } + } + + + if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += sizeof(fmt); + + fmtOut->formatTag = drwav_bytes_to_u16(fmt + 0); + fmtOut->channels = drwav_bytes_to_u16(fmt + 2); + fmtOut->sampleRate = drwav_bytes_to_u32(fmt + 4); + fmtOut->avgBytesPerSec = drwav_bytes_to_u32(fmt + 8); + fmtOut->blockAlign = drwav_bytes_to_u16(fmt + 12); + fmtOut->bitsPerSample = drwav_bytes_to_u16(fmt + 14); + + fmtOut->extendedSize = 0; + fmtOut->validBitsPerSample = 0; + fmtOut->channelMask = 0; + memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + + if (header.sizeInBytes > 16) { + drwav_uint8 fmt_cbSize[2]; + int bytesReadSoFar = 0; + + if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { + return DRWAV_FALSE; /* Expecting more data. */ + } + *pRunningBytesReadOut += sizeof(fmt_cbSize); + + bytesReadSoFar = 18; + + fmtOut->extendedSize = drwav_bytes_to_u16(fmt_cbSize); + if (fmtOut->extendedSize > 0) { + /* Simple validation. */ + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + if (fmtOut->extendedSize != 22) { + return DRWAV_FALSE; + } + } + + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + drwav_uint8 fmtext[22]; + if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { + return DRWAV_FALSE; /* Expecting more data. */ + } + + fmtOut->validBitsPerSample = drwav_bytes_to_u16(fmtext + 0); + fmtOut->channelMask = drwav_bytes_to_u32(fmtext + 2); + drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat); + } else { + if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + } + *pRunningBytesReadOut += fmtOut->extendedSize; + + bytesReadSoFar += fmtOut->extendedSize; + } + + /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */ + if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar); + } + + if (header.paddingSize > 0) { + if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.paddingSize; + } + + return DRWAV_TRUE; +} + DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) { @@ -2039,937 +1712,19 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserDat #endif -#define DRWAV_SMPL_BYTES 36 -#define DRWAV_SMPL_LOOP_BYTES 24 -#define DRWAV_INST_BYTES 7 -#define DRWAV_ACID_BYTES 24 -#define DRWAV_CUE_BYTES 4 -#define DRWAV_BEXT_BYTES 602 -#define DRWAV_BEXT_DESCRIPTION_BYTES 256 -#define DRWAV_BEXT_ORIGINATOR_NAME_BYTES 32 -#define DRWAV_BEXT_ORIGINATOR_REF_BYTES 32 -#define DRWAV_BEXT_RESERVED_BYTES 180 -#define DRWAV_BEXT_UMID_BYTES 64 -#define DRWAV_CUE_POINT_BYTES 24 -#define DRWAV_LIST_LABEL_OR_NOTE_BYTES 4 -#define DRWAV_LIST_LABELLED_TEXT_BYTES 20 - -#define DRWAV_METADATA_ALIGNMENT 8 - -typedef enum -{ - drwav__metadata_parser_stage_count, - drwav__metadata_parser_stage_read -} drwav__metadata_parser_stage; - -typedef struct -{ - drwav_read_proc onRead; - drwav_seek_proc onSeek; - void *pReadSeekUserData; - drwav__metadata_parser_stage stage; - drwav_metadata *pMetadata; - drwav_uint32 metadataCount; - drwav_uint8 *pData; - drwav_uint8 *pDataCursor; - drwav_uint64 metadataCursor; - drwav_uint64 extraCapacity; -} drwav__metadata_parser; - -DRWAV_PRIVATE size_t drwav__metadata_memory_capacity(drwav__metadata_parser* pParser) -{ - drwav_uint64 cap = sizeof(drwav_metadata) * (drwav_uint64)pParser->metadataCount + pParser->extraCapacity; - if (cap > DRWAV_SIZE_MAX) { - return 0; /* Too big. */ - } - - return (size_t)cap; /* Safe cast thanks to the check above. */ -} - -DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pParser, size_t size, size_t align) -{ - drwav_uint8* pResult; - - if (align) { - drwav_uintptr modulo = (drwav_uintptr)pParser->pDataCursor % align; - if (modulo != 0) { - pParser->pDataCursor += align - modulo; - } - } - - pResult = pParser->pDataCursor; - - /* - Getting to the point where this function is called means there should always be memory - available. Out of memory checks should have been done at an earlier stage. - */ - DRWAV_ASSERT((pResult + size) <= (pParser->pData + drwav__metadata_memory_capacity(pParser))); - - pParser->pDataCursor += size; - return pResult; -} - -DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metadata_parser* pParser, size_t bytes, size_t align) -{ - size_t extra = bytes + (align ? (align - 1) : 0); - pParser->extraCapacity += extra; -} - -DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks) -{ - if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) { - pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData); - - pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData); - pParser->pDataCursor = pParser->pData; - - if (pParser->pData == NULL) { - return DRWAV_OUT_OF_MEMORY; - } - - /* - We don't need to worry about specifying an alignment here because malloc always returns something - of suitable alignment. This also means pParser->pMetadata is all that we need to store in order - for us to free when we are done. - */ - pParser->pMetadata = (drwav_metadata*)drwav__metadata_get_memory(pParser, sizeof(drwav_metadata) * pParser->metadataCount, 1); - pParser->metadataCursor = 0; - } - - return DRWAV_SUCCESS; -} - -DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) -{ - if (pCursor != NULL) { - return drwav__on_read(pParser->onRead, pParser->pReadSeekUserData, pBufferOut, bytesToRead, pCursor); - } else { - return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead); - } -} - -DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) -{ - drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES]; - drwav_uint64 totalBytesRead = 0; - size_t bytesJustRead; - - if (pMetadata == NULL) { - return 0; - } - - bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - DRWAV_ASSERT(pChunkHeader != NULL); - - if (pMetadata != NULL && bytesJustRead == sizeof(smplHeaderData)) { - drwav_uint32 iSampleLoop; - - pMetadata->type = drwav_metadata_type_smpl; - pMetadata->data.smpl.manufacturerId = drwav_bytes_to_u32(smplHeaderData + 0); - pMetadata->data.smpl.productId = drwav_bytes_to_u32(smplHeaderData + 4); - pMetadata->data.smpl.samplePeriodNanoseconds = drwav_bytes_to_u32(smplHeaderData + 8); - pMetadata->data.smpl.midiUnityNote = drwav_bytes_to_u32(smplHeaderData + 12); - pMetadata->data.smpl.midiPitchFraction = drwav_bytes_to_u32(smplHeaderData + 16); - pMetadata->data.smpl.smpteFormat = drwav_bytes_to_u32(smplHeaderData + 20); - pMetadata->data.smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData + 24); - pMetadata->data.smpl.sampleLoopCount = drwav_bytes_to_u32(smplHeaderData + 28); - pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32); - - /* - The loop count needs to be validated against the size of the chunk for safety so we don't - attempt to read over the boundary of the chunk. - */ - if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) { - pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); - - for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { - drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); - - if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); - } else { - break; - } - } - - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); - DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); - - drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); - } - } - } - - return totalBytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) -{ - drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES]; - drwav_uint64 totalBytesRead = 0; - size_t bytesJustRead; - - if (pMetadata == NULL) { - return 0; - } - - bytesJustRead = drwav__metadata_parser_read(pParser, cueHeaderSectionData, sizeof(cueHeaderSectionData), &totalBytesRead); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - - if (bytesJustRead == sizeof(cueHeaderSectionData)) { - pMetadata->type = drwav_metadata_type_cue; - pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData); - - /* - We need to validate the cue point count against the size of the chunk so we don't read - beyond the chunk. - */ - if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) { - pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); - DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - - if (pMetadata->data.cue.cuePointCount > 0) { - drwav_uint32 iCuePoint; - - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); - - if (bytesJustRead == sizeof(cuePointData)) { - pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); - pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; - pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); - pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); - } else { - break; - } - } - } - } - } - - return totalBytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__read_inst_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) -{ - drwav_uint8 instData[DRWAV_INST_BYTES]; - drwav_uint64 bytesRead; - - if (pMetadata == NULL) { - return 0; - } - - bytesRead = drwav__metadata_parser_read(pParser, instData, sizeof(instData), NULL); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - - if (bytesRead == sizeof(instData)) { - pMetadata->type = drwav_metadata_type_inst; - pMetadata->data.inst.midiUnityNote = (drwav_int8)instData[0]; - pMetadata->data.inst.fineTuneCents = (drwav_int8)instData[1]; - pMetadata->data.inst.gainDecibels = (drwav_int8)instData[2]; - pMetadata->data.inst.lowNote = (drwav_int8)instData[3]; - pMetadata->data.inst.highNote = (drwav_int8)instData[4]; - pMetadata->data.inst.lowVelocity = (drwav_int8)instData[5]; - pMetadata->data.inst.highVelocity = (drwav_int8)instData[6]; - } - - return bytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) -{ - drwav_uint8 acidData[DRWAV_ACID_BYTES]; - drwav_uint64 bytesRead; - - if (pMetadata == NULL) { - return 0; - } - - bytesRead = drwav__metadata_parser_read(pParser, acidData, sizeof(acidData), NULL); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - - if (bytesRead == sizeof(acidData)) { - pMetadata->type = drwav_metadata_type_acid; - pMetadata->data.acid.flags = drwav_bytes_to_u32(acidData + 0); - pMetadata->data.acid.midiUnityNote = drwav_bytes_to_u16(acidData + 4); - pMetadata->data.acid.reserved1 = drwav_bytes_to_u16(acidData + 6); - pMetadata->data.acid.reserved2 = drwav_bytes_to_f32(acidData + 8); - pMetadata->data.acid.numBeats = drwav_bytes_to_u32(acidData + 12); - pMetadata->data.acid.meterDenominator = drwav_bytes_to_u16(acidData + 16); - pMetadata->data.acid.meterNumerator = drwav_bytes_to_u16(acidData + 18); - pMetadata->data.acid.tempo = drwav_bytes_to_f32(acidData + 20); - } - - return bytesRead; -} - -DRWAV_PRIVATE size_t drwav__strlen(const char* str) -{ - size_t result = 0; - - while (*str++) { - result += 1; - } - - return result; -} - -DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead) -{ - size_t result = 0; - - while (*str++ && result < maxToRead) { - result += 1; - } - - return result; -} - -DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead) -{ - size_t len = drwav__strlen_clamped(str, maxToRead); - - if (len) { - char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1); - DRWAV_ASSERT(result != NULL); - - DRWAV_COPY_MEMORY(result, str, len); - result[len] = '\0'; - - return result; - } else { - return NULL; - } -} - -typedef struct -{ - const void* pBuffer; - size_t sizeInBytes; - size_t cursor; -} drwav_buffer_reader; - -DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader) -{ - DRWAV_ASSERT(pBuffer != NULL); - DRWAV_ASSERT(pReader != NULL); - - DRWAV_ZERO_OBJECT(pReader); - - pReader->pBuffer = pBuffer; - pReader->sizeInBytes = sizeInBytes; - pReader->cursor = 0; - - return DRWAV_SUCCESS; -} - -DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader) -{ - DRWAV_ASSERT(pReader != NULL); - - return drwav_offset_ptr(pReader->pBuffer, pReader->cursor); -} - -DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek) -{ - DRWAV_ASSERT(pReader != NULL); - - if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) { - return DRWAV_BAD_SEEK; /* Seeking too far forward. */ - } - - pReader->cursor += bytesToSeek; - - return DRWAV_SUCCESS; -} - -DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead) -{ - drwav_result result = DRWAV_SUCCESS; - size_t bytesRemaining; - - DRWAV_ASSERT(pReader != NULL); - - if (pBytesRead != NULL) { - *pBytesRead = 0; - } - - bytesRemaining = (pReader->sizeInBytes - pReader->cursor); - if (bytesToRead > bytesRemaining) { - bytesToRead = bytesRemaining; - } - - if (pDst == NULL) { - /* Seek. */ - result = drwav_buffer_reader_seek(pReader, bytesToRead); - } else { - /* Read. */ - DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead); - pReader->cursor += bytesToRead; - } - - DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes); - - if (result == DRWAV_SUCCESS) { - if (pBytesRead != NULL) { - *pBytesRead = bytesToRead; - } - } - - return DRWAV_SUCCESS; -} - -DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst) -{ - drwav_result result; - size_t bytesRead; - drwav_uint8 data[2]; - - DRWAV_ASSERT(pReader != NULL); - DRWAV_ASSERT(pDst != NULL); - - *pDst = 0; /* Safety. */ - - result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); - if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { - return result; - } - - *pDst = drwav_bytes_to_u16(data); - - return DRWAV_SUCCESS; -} - -DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst) -{ - drwav_result result; - size_t bytesRead; - drwav_uint8 data[4]; - - DRWAV_ASSERT(pReader != NULL); - DRWAV_ASSERT(pDst != NULL); - - *pDst = 0; /* Safety. */ - - result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); - if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { - return result; - } - - *pDst = drwav_bytes_to_u32(data); - - return DRWAV_SUCCESS; -} - - - -DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize) -{ - drwav_uint8 bextData[DRWAV_BEXT_BYTES]; - size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - - if (bytesRead == sizeof(bextData)) { - drwav_buffer_reader reader; - drwav_uint32 timeReferenceLow; - drwav_uint32 timeReferenceHigh; - size_t extraBytes; - - pMetadata->type = drwav_metadata_type_bext; - - if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) { - pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES); - drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES); - - pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - - pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES); - drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES); - - drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL); - drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL); - - drwav_buffer_reader_read_u32(&reader, &timeReferenceLow); - drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh); - pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; - - drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); - - pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); - drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL); - - drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue); - drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange); - drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel); - drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness); - drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness); - - DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES)); - - extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); - if (extraBytes > 0) { - pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); - DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - - bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory); - } else { - pMetadata->data.bext.pCodingHistory = NULL; - pMetadata->data.bext.codingHistorySize = 0; - } - } - } - - return bytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize, drwav_metadata_type type) -{ - drwav_uint8 cueIDBuffer[DRWAV_LIST_LABEL_OR_NOTE_BYTES]; - drwav_uint64 totalBytesRead = 0; - size_t bytesJustRead = drwav__metadata_parser_read(pParser, cueIDBuffer, sizeof(cueIDBuffer), &totalBytesRead); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - - if (bytesJustRead == sizeof(cueIDBuffer)) { - drwav_uint32 sizeIncludingNullTerminator; - - pMetadata->type = type; - pMetadata->data.labelOrNote.cuePointId = drwav_bytes_to_u32(cueIDBuffer); - - sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES; - if (sizeIncludingNullTerminator > 0) { - pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1; - pMetadata->data.labelOrNote.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); - DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - - drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); - } else { - pMetadata->data.labelOrNote.stringLength = 0; - pMetadata->data.labelOrNote.pString = NULL; - } - } - - return totalBytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize) -{ - drwav_uint8 buffer[DRWAV_LIST_LABELLED_TEXT_BYTES]; - drwav_uint64 totalBytesRead = 0; - size_t bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &totalBytesRead); - - DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); - - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 sizeIncludingNullTerminator; - - pMetadata->type = drwav_metadata_type_list_labelled_cue_region; - pMetadata->data.labelledCueRegion.cuePointId = drwav_bytes_to_u32(buffer + 0); - pMetadata->data.labelledCueRegion.sampleLength = drwav_bytes_to_u32(buffer + 4); - pMetadata->data.labelledCueRegion.purposeId[0] = buffer[8]; - pMetadata->data.labelledCueRegion.purposeId[1] = buffer[9]; - pMetadata->data.labelledCueRegion.purposeId[2] = buffer[10]; - pMetadata->data.labelledCueRegion.purposeId[3] = buffer[11]; - pMetadata->data.labelledCueRegion.country = drwav_bytes_to_u16(buffer + 12); - pMetadata->data.labelledCueRegion.language = drwav_bytes_to_u16(buffer + 14); - pMetadata->data.labelledCueRegion.dialect = drwav_bytes_to_u16(buffer + 16); - pMetadata->data.labelledCueRegion.codePage = drwav_bytes_to_u16(buffer + 18); - - sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABELLED_TEXT_BYTES; - if (sizeIncludingNullTerminator > 0) { - pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1; - pMetadata->data.labelledCueRegion.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); - DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - - drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); - } else { - pMetadata->data.labelledCueRegion.stringLength = 0; - pMetadata->data.labelledCueRegion.pString = NULL; - } - } - - return totalBytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_info_text_chunk(drwav__metadata_parser* pParser, drwav_uint64 chunkSize, drwav_metadata_type type) -{ - drwav_uint64 bytesRead = 0; - drwav_uint32 stringSizeWithNullTerminator = (drwav_uint32)chunkSize; - - if (pParser->stage == drwav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, stringSizeWithNullTerminator, 1); - } else { - drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor]; - pMetadata->type = type; - if (stringSizeWithNullTerminator > 0) { - pMetadata->data.infoText.stringLength = stringSizeWithNullTerminator - 1; - pMetadata->data.infoText.pString = (char*)drwav__metadata_get_memory(pParser, stringSizeWithNullTerminator, 1); - DRWAV_ASSERT(pMetadata->data.infoText.pString != NULL); - - bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.infoText.pString, (size_t)stringSizeWithNullTerminator, NULL); - if (bytesRead == chunkSize) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } else { - pMetadata->data.infoText.stringLength = 0; - pMetadata->data.infoText.pString = NULL; - pParser->metadataCursor += 1; - } - } - - return bytesRead; -} - -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata_parser* pParser, const drwav_uint8* pChunkId, drwav_uint64 chunkSize, drwav_metadata_location location) -{ - drwav_uint64 bytesRead = 0; - - if (location == drwav_metadata_location_invalid) { - return 0; - } - - if (drwav_fourcc_equal(pChunkId, "data") || drwav_fourcc_equal(pChunkId, "fmt ") || drwav_fourcc_equal(pChunkId, "fact")) { - return 0; - } - - if (pParser->stage == drwav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)chunkSize, 1); - } else { - drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor]; - pMetadata->type = drwav_metadata_type_unknown; - pMetadata->data.unknown.chunkLocation = location; - pMetadata->data.unknown.id[0] = pChunkId[0]; - pMetadata->data.unknown.id[1] = pChunkId[1]; - pMetadata->data.unknown.id[2] = pChunkId[2]; - pMetadata->data.unknown.id[3] = pChunkId[3]; - pMetadata->data.unknown.dataSizeInBytes = (drwav_uint32)chunkSize; - pMetadata->data.unknown.pData = (drwav_uint8 *)drwav__metadata_get_memory(pParser, (size_t)chunkSize, 1); - DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL); - - bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes, NULL); - if (bytesRead == pMetadata->data.unknown.dataSizeInBytes) { - pParser->metadataCursor += 1; - } else { - /* Failed to read. */ - } - } - - return bytesRead; -} - -DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) -{ - return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID); -} - -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes) -{ - const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc; - drwav_uint64 bytesRead = 0; - - if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_smpl, "smpl")) { - if (pChunkHeader->sizeInBytes >= DRWAV_SMPL_BYTES) { - if (pParser->stage == drwav__metadata_parser_stage_count) { - drwav_uint8 buffer[4]; - size_t bytesJustRead; - - if (!pParser->onSeek(pParser->pReadSeekUserData, 28, drwav_seek_origin_current)) { - return bytesRead; - } - bytesRead += 28; - - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 loopCount = drwav_bytes_to_u32(buffer); - drwav_uint64 calculatedLoopCount; - - /* The loop count must be validated against the size of the chunk. */ - calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES; - if (calculatedLoopCount == loopCount) { - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); - - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); - drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); - } - } else { - /* Loop count in header does not match the size of the chunk. */ - } - } - } else { - bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_inst, "inst")) { - if (pChunkHeader->sizeInBytes == DRWAV_INST_BYTES) { - if (pParser->stage == drwav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - } else { - bytesRead = drwav__read_inst_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_acid, "acid")) { - if (pChunkHeader->sizeInBytes == DRWAV_ACID_BYTES) { - if (pParser->stage == drwav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - } else { - bytesRead = drwav__read_acid_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_cue, "cue ")) { - if (pChunkHeader->sizeInBytes >= DRWAV_CUE_BYTES) { - if (pParser->stage == drwav__metadata_parser_stage_count) { - size_t cueCount; - - pParser->metadataCount += 1; - cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES; - drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT); - } else { - bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_bext, "bext")) { - if (pChunkHeader->sizeInBytes >= DRWAV_BEXT_BYTES) { - if (pParser->stage == drwav__metadata_parser_stage_count) { - /* The description field is the largest one in a bext chunk, so that is the max size of this temporary buffer. */ - char buffer[DRWAV_BEXT_DESCRIPTION_BYTES + 1]; - size_t allocSizeNeeded = DRWAV_BEXT_UMID_BYTES; /* We know we will need SMPTE umid size. */ - size_t bytesJustRead; - - buffer[DRWAV_BEXT_DESCRIPTION_BYTES] = '\0'; - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_DESCRIPTION_BYTES, &bytesRead); - if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) { - return bytesRead; - } - allocSizeNeeded += drwav__strlen(buffer) + 1; - - buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0'; - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead); - if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) { - return bytesRead; - } - allocSizeNeeded += drwav__strlen(buffer) + 1; - - buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0'; - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead); - if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) { - return bytesRead; - } - allocSizeNeeded += drwav__strlen(buffer) + 1; - allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */ - - drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); - - pParser->metadataCount += 1; - } else { - bytesRead = drwav__read_bext_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], pChunkHeader->sizeInBytes); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav_fourcc_equal(pChunkID, "LIST") || drwav_fourcc_equal(pChunkID, "list")) { - drwav_metadata_location listType = drwav_metadata_location_invalid; - while (bytesRead < pChunkHeader->sizeInBytes) { - drwav_uint8 subchunkId[4]; - drwav_uint8 subchunkSizeBuffer[4]; - drwav_uint64 subchunkDataSize; - drwav_uint64 subchunkBytesRead = 0; - drwav_uint64 bytesJustRead = drwav__metadata_parser_read(pParser, subchunkId, sizeof(subchunkId), &bytesRead); - if (bytesJustRead != sizeof(subchunkId)) { - break; - } - - /* - The first thing in a list chunk should be "adtl" or "INFO". - - - adtl means this list is a Associated Data List Chunk and will contain labels, notes - or labelled cue regions. - - INFO means this list is an Info List Chunk containing info text chunks such as IPRD - which would specifies the album of this wav file. - - No data follows the adtl or INFO id so we just make note of what type this list is and - continue. - */ - if (drwav_fourcc_equal(subchunkId, "adtl")) { - listType = drwav_metadata_location_inside_adtl_list; - continue; - } else if (drwav_fourcc_equal(subchunkId, "INFO")) { - listType = drwav_metadata_location_inside_info_list; - continue; - } - - bytesJustRead = drwav__metadata_parser_read(pParser, subchunkSizeBuffer, sizeof(subchunkSizeBuffer), &bytesRead); - if (bytesJustRead != sizeof(subchunkSizeBuffer)) { - break; - } - subchunkDataSize = drwav_bytes_to_u32(subchunkSizeBuffer); - - if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_label, "labl") || drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_note, "note")) { - if (subchunkDataSize >= DRWAV_LIST_LABEL_OR_NOTE_BYTES) { - drwav_uint64 stringSizeWithNullTerm = subchunkDataSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES; - if (pParser->stage == drwav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerm, 1); - } else { - subchunkBytesRead = drwav__read_list_label_or_note_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize, drwav_fourcc_equal(subchunkId, "labl") ? drwav_metadata_type_list_label : drwav_metadata_type_list_note); - if (subchunkBytesRead == subchunkDataSize) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_labelled_cue_region, "ltxt")) { - if (subchunkDataSize >= DRWAV_LIST_LABELLED_TEXT_BYTES) { - drwav_uint64 stringSizeWithNullTerminator = subchunkDataSize - DRWAV_LIST_LABELLED_TEXT_BYTES; - if (pParser->stage == drwav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerminator, 1); - } else { - subchunkBytesRead = drwav__read_list_labelled_cue_region_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize); - if (subchunkBytesRead == subchunkDataSize) { - pParser->metadataCursor += 1; - } else { - /* Failed to parse. */ - } - } - } else { - /* Incorrectly formed chunk. */ - } - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_software, "ISFT")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_software); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_copyright, "ICOP")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_copyright); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_title, "INAM")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_title); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_artist, "IART")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_artist); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_comment, "ICMT")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_comment); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_date, "ICRD")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_date); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_genre, "IGNR")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_genre); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_album, "IPRD")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album); - } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) { - subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber); - } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { - subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); - } - - bytesRead += subchunkBytesRead; - DRWAV_ASSERT(subchunkBytesRead <= subchunkDataSize); - - if (subchunkBytesRead < subchunkDataSize) { - drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead; - - if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, drwav_seek_origin_current)) { - break; - } - bytesRead += bytesToSeek; - } - - if ((subchunkDataSize % 2) == 1) { - if (!pParser->onSeek(pParser->pReadSeekUserData, 1, drwav_seek_origin_current)) { - break; - } - bytesRead += 1; - } - } - } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { - bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level); - } - - return bytesRead; -} - DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { - drwav_uint32 bytesPerFrame; - /* The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align. */ if ((pWav->bitsPerSample & 0x7) == 0) { /* Bits per sample is a multiple of 8. */ - bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; } else { - bytesPerFrame = pWav->fmt.blockAlign; + return pWav->fmt.blockAlign; } - - /* Validation for known formats. a-law and mu-law should be 1 byte per channel. If it's not, it's not decodable. */ - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { - if (bytesPerFrame != pWav->fmt.channels) { - return 0; /* Invalid file. */ - } - } - - return bytesPerFrame; } DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) @@ -3007,25 +1762,19 @@ DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, dr DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) { /* This function assumes drwav_preinit() has been called beforehand. */ - drwav_result result; + drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */ drwav_bool32 sequential; drwav_uint8 riff[4]; drwav_fmt fmt; unsigned short translatedFormatTag; - drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */ + drwav_bool32 foundDataChunk; + drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */ drwav_uint64 sampleCountFromFactChunk = 0; /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */ - drwav_uint64 metadataStartPos; - drwav__metadata_parser metadataParser; - drwav_bool8 isProcessingMetadata = DRWAV_FALSE; - drwav_bool8 foundChunk_fmt = DRWAV_FALSE; - drwav_bool8 foundChunk_data = DRWAV_FALSE; - drwav_bool8 isAIFCFormType = DRWAV_FALSE; /* Only used with AIFF. */ - drwav_uint64 aiffFrameCount = 0; + drwav_uint64 chunkSize; cursor = 0; sequential = (flags & DRWAV_SEQUENTIAL) != 0; - DRWAV_ZERO_OBJECT(&fmt); /* The first 4 bytes should be the RIFF identifier. */ if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { @@ -3038,8 +1787,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on */ if (drwav_fourcc_equal(riff, "RIFF")) { pWav->container = drwav_container_riff; - } else if (drwav_fourcc_equal(riff, "RIFX")) { - pWav->container = drwav_container_rifx; } else if (drwav_fourcc_equal(riff, "riff")) { int i; drwav_uint8 riff2[12]; @@ -3058,37 +1805,28 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on } } else if (drwav_fourcc_equal(riff, "RF64")) { pWav->container = drwav_container_rf64; - } else if (drwav_fourcc_equal(riff, "FORM")) { - pWav->container = drwav_container_aiff; } else { return DRWAV_FALSE; /* Unknown or unsupported container. */ } - if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) { + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { drwav_uint8 chunkSizeBytes[4]; drwav_uint8 wave[4]; + /* RIFF/WAVE */ if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { return DRWAV_FALSE; } - if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) { - if (drwav_bytes_to_u32_ex(chunkSizeBytes, pWav->container) < 36) { - /* - I've had a report of a WAV file failing to load when the size of the WAVE chunk is not encoded - and is instead just set to 0. I'm going to relax the validation here to allow these files to - load. Considering the chunk size isn't actually used this should be safe. With this change my - test suite still passes. - */ - /*return DRWAV_FALSE;*/ /* Chunk size should always be at least 36 bytes. */ - } - } else if (pWav->container == drwav_container_rf64) { - if (drwav_bytes_to_u32_le(chunkSizeBytes) != 0xFFFFFFFF) { - return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */ + if (pWav->container == drwav_container_riff) { + if (drwav_bytes_to_u32(chunkSizeBytes) < 36) { + return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */ } } else { - return DRWAV_FALSE; /* Should never hit this. */ + if (drwav_bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) { + return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */ + } } if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { @@ -3098,10 +1836,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (!drwav_fourcc_equal(wave, "WAVE")) { return DRWAV_FALSE; /* Expecting "WAVE". */ } - } else if (pWav->container == drwav_container_w64) { + } else { drwav_uint8 chunkSizeBytes[8]; drwav_uint8 wave[16]; + /* W64 */ if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { return DRWAV_FALSE; } @@ -3117,31 +1856,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) { return DRWAV_FALSE; } - } else if (pWav->container == drwav_container_aiff) { - drwav_uint8 chunkSizeBytes[4]; - drwav_uint8 aiff[4]; - - if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { - return DRWAV_FALSE; - } - - if (drwav_bytes_to_u32_be(chunkSizeBytes) < 18) { - return DRWAV_FALSE; - } - - if (drwav__on_read(pWav->onRead, pWav->pUserData, aiff, sizeof(aiff), &cursor) != sizeof(aiff)) { - return DRWAV_FALSE; - } - - if (drwav_fourcc_equal(aiff, "AIFF")) { - isAIFCFormType = DRWAV_FALSE; - } else if (drwav_fourcc_equal(aiff, "AIFC")) { - isAIFCFormType = DRWAV_TRUE; - } else { - return DRWAV_FALSE; /* Expecting "AIFF" or "AIFC". */ - } - } else { - return DRWAV_FALSE; } @@ -3150,7 +1864,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on drwav_uint8 sizeBytes[8]; drwav_uint64 bytesRemainingInChunk; drwav_chunk_header header; - result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); if (result != DRWAV_SUCCESS) { return DRWAV_FALSE; } @@ -3193,52 +1907,50 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on } - metadataStartPos = cursor; - - /* - Whether or not we are processing metadata controls how we load. We can load more efficiently when - metadata is not being processed, but we also cannot process metadata for Wave64 because I have not - been able to test it. If someone is able to test this and provide a patch I'm happy to enable it. - - Seqential mode cannot support metadata because it involves seeking backwards. - */ - isProcessingMetadata = !sequential && ((flags & DRWAV_WITH_METADATA) != 0); - - /* Don't allow processing of metadata with untested containers. */ - if (pWav->container != drwav_container_riff && pWav->container != drwav_container_rf64) { - isProcessingMetadata = DRWAV_FALSE; + /* The next bytes should be the "fmt " chunk. */ + if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) { + return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */ } - DRWAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser)); - if (isProcessingMetadata) { - metadataParser.onRead = pWav->onRead; - metadataParser.onSeek = pWav->onSeek; - metadataParser.pReadSeekUserData = pWav->pUserData; - metadataParser.stage = drwav__metadata_parser_stage_count; + /* Basic validation. */ + if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) || + (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) || + (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) || + fmt.blockAlign == 0) { + return DRWAV_FALSE; /* Probably an invalid WAV file. */ + } + + + /* Translate the internal format. */ + translatedFormatTag = fmt.formatTag; + if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0); } /* - From here on out, chunks might be in any order. In order to robustly handle metadata we'll need - to loop through every chunk and handle them as we find them. In sequential mode we need to get - out of the loop as soon as we find the data chunk because we won't be able to seek back. + We need to enumerate over each chunk for two reasons: + 1) The "data" chunk may not be the next one + 2) We may want to report each chunk back to the client + + In order to correctly report each chunk back to the client we will need to keep looping until the end of the file. */ - for (;;) { /* For each chunk... */ + foundDataChunk = DRWAV_FALSE; + + /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */ + for (;;) + { drwav_chunk_header header; - drwav_uint64 chunkSize; - - result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); if (result != DRWAV_SUCCESS) { - break; + if (!foundDataChunk) { + return DRWAV_FALSE; + } else { + break; /* Probably at the end of the file. Get out of the loop. */ + } } - chunkSize = header.sizeInBytes; - - - /* - Always tell the caller about this chunk. We cannot do this in sequential mode because the - callback is allowed to read from the file, in which case we'll need to rewind. - */ + /* Tell the client about this chunk. */ if (!sequential && onChunk != NULL) { drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); @@ -3247,355 +1959,146 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on we called the callback. */ if (callbackBytesRead > 0) { - if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) { + if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) { return DRWAV_FALSE; } } } + - - /* Explicitly handle known chunks first. */ - - /* "fmt " */ - if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "fmt ")) || - ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) { - drwav_uint8 fmtData[16]; - - foundChunk_fmt = DRWAV_TRUE; - - if (pWav->onRead(pWav->pUserData, fmtData, sizeof(fmtData)) != sizeof(fmtData)) { - return DRWAV_FALSE; - } - cursor += sizeof(fmtData); - - fmt.formatTag = drwav_bytes_to_u16_ex(fmtData + 0, pWav->container); - fmt.channels = drwav_bytes_to_u16_ex(fmtData + 2, pWav->container); - fmt.sampleRate = drwav_bytes_to_u32_ex(fmtData + 4, pWav->container); - fmt.avgBytesPerSec = drwav_bytes_to_u32_ex(fmtData + 8, pWav->container); - fmt.blockAlign = drwav_bytes_to_u16_ex(fmtData + 12, pWav->container); - fmt.bitsPerSample = drwav_bytes_to_u16_ex(fmtData + 14, pWav->container); - - fmt.extendedSize = 0; - fmt.validBitsPerSample = 0; - fmt.channelMask = 0; - DRWAV_ZERO_MEMORY(fmt.subFormat, sizeof(fmt.subFormat)); - - if (header.sizeInBytes > 16) { - drwav_uint8 fmt_cbSize[2]; - int bytesReadSoFar = 0; - - if (pWav->onRead(pWav->pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { - return DRWAV_FALSE; /* Expecting more data. */ - } - cursor += sizeof(fmt_cbSize); - - bytesReadSoFar = 18; - - fmt.extendedSize = drwav_bytes_to_u16_ex(fmt_cbSize, pWav->container); - if (fmt.extendedSize > 0) { - /* Simple validation. */ - if (fmt.formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { - if (fmt.extendedSize != 22) { - return DRWAV_FALSE; - } - } - - if (fmt.formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { - drwav_uint8 fmtext[22]; - - if (pWav->onRead(pWav->pUserData, fmtext, fmt.extendedSize) != fmt.extendedSize) { - return DRWAV_FALSE; /* Expecting more data. */ - } - - fmt.validBitsPerSample = drwav_bytes_to_u16_ex(fmtext + 0, pWav->container); - fmt.channelMask = drwav_bytes_to_u32_ex(fmtext + 2, pWav->container); - drwav_bytes_to_guid(fmtext + 6, fmt.subFormat); - } else { - if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, drwav_seek_origin_current) == DRWAV_FALSE) { - return DRWAV_FALSE; - } - } - cursor += fmt.extendedSize; - - bytesReadSoFar += fmt.extendedSize; - } - - /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */ - if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current) == DRWAV_FALSE) { - return DRWAV_FALSE; - } - cursor += (header.sizeInBytes - bytesReadSoFar); - } - - if (header.paddingSize > 0) { - if (drwav__seek_forward(pWav->onSeek, header.paddingSize, pWav->pUserData) == DRWAV_FALSE) { - break; - } - cursor += header.paddingSize; - } - - /* Go to the next chunk. Don't include this chunk in metadata. */ - continue; + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; } - /* "data" */ - if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "data")) || - ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA))) { - foundChunk_data = DRWAV_TRUE; - - pWav->dataChunkDataPos = cursor; - - if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */ + chunkSize = header.sizeInBytes; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav_fourcc_equal(header.id.fourcc, "data")) { + foundDataChunk = DRWAV_TRUE; + if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */ + dataChunkSize = chunkSize; + } + } + } else { + if (drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA)) { + foundDataChunk = DRWAV_TRUE; dataChunkSize = chunkSize; } - - /* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */ - if (sequential || !isProcessingMetadata) { - break; /* No need to keep reading beyond the data chunk. */ - } else { - chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */ - if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) { - break; - } - cursor += chunkSize; - - continue; /* There may be some more metadata to read. */ - } } - /* "fact". This is optional. Can use this to get the sample count which is useful for compressed formats. For RF64 we retrieved the sample count from the ds64 chunk earlier. */ - if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "fact")) || - ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT))) { - if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) { - drwav_uint8 sampleCount[4]; + /* + If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for + this is that we would otherwise require a backwards seek which sequential mode forbids. + */ + if (foundDataChunk && sequential) { + break; + } + + /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */ + if (pWav->container == drwav_container_riff) { + if (drwav_fourcc_equal(header.id.fourcc, "fact")) { + drwav_uint32 sampleCount; if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { return DRWAV_FALSE; } - chunkSize -= 4; + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + /* The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this for Microsoft ADPCM formats. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - sampleCountFromFactChunk = drwav_bytes_to_u32_ex(sampleCount, pWav->container); + sampleCountFromFactChunk = sampleCount; } else { sampleCountFromFactChunk = 0; } - } else if (pWav->container == drwav_container_w64) { + } + } else if (pWav->container == drwav_container_w64) { + if (drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT)) { if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { return DRWAV_FALSE; } - chunkSize -= 8; - } else if (pWav->container == drwav_container_rf64) { - /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */ - } - /* Seek to the next chunk in preparation for the next iteration. */ - chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */ - if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) { - break; + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } } - cursor += chunkSize; - - continue; + } else if (pWav->container == drwav_container_rf64) { + /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */ } + /* "smpl" chunk. */ + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav_fourcc_equal(header.id.fourcc, "smpl")) { + drwav_uint8 smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */ + if (chunkSize >= sizeof(smplHeaderData)) { + drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor); + chunkSize -= bytesJustRead; - /* "COMM". AIFF/AIFC only. */ - if (pWav->container == drwav_container_aiff && drwav_fourcc_equal(header.id.fourcc, "COMM")) { - drwav_uint8 commData[24]; - drwav_uint32 commDataBytesToRead; - drwav_uint16 channels; - drwav_uint32 frameCount; - drwav_uint16 sampleSizeInBits; - drwav_int64 sampleRate; - drwav_uint16 compressionFormat; + if (bytesJustRead == sizeof(smplHeaderData)) { + drwav_uint32 iLoop; - foundChunk_fmt = DRWAV_TRUE; + pWav->smpl.manufacturer = drwav_bytes_to_u32(smplHeaderData+0); + pWav->smpl.product = drwav_bytes_to_u32(smplHeaderData+4); + pWav->smpl.samplePeriod = drwav_bytes_to_u32(smplHeaderData+8); + pWav->smpl.midiUnityNotes = drwav_bytes_to_u32(smplHeaderData+12); + pWav->smpl.midiPitchFraction = drwav_bytes_to_u32(smplHeaderData+16); + pWav->smpl.smpteFormat = drwav_bytes_to_u32(smplHeaderData+20); + pWav->smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData+24); + pWav->smpl.numSampleLoops = drwav_bytes_to_u32(smplHeaderData+28); + pWav->smpl.samplerData = drwav_bytes_to_u32(smplHeaderData+32); - if (isAIFCFormType) { - commDataBytesToRead = 24; - if (header.sizeInBytes < commDataBytesToRead) { - return DRWAV_FALSE; /* Invalid COMM chunk. */ - } - } else { - commDataBytesToRead = 18; - if (header.sizeInBytes != commDataBytesToRead) { - return DRWAV_FALSE; /* INVALID COMM chunk. */ - } - } + for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { + drwav_uint8 smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */ + bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor); + chunkSize -= bytesJustRead; - if (drwav__on_read(pWav->onRead, pWav->pUserData, commData, commDataBytesToRead, &cursor) != commDataBytesToRead) { - return DRWAV_FALSE; - } - - - channels = drwav_bytes_to_u16_ex (commData + 0, pWav->container); - frameCount = drwav_bytes_to_u32_ex (commData + 2, pWav->container); - sampleSizeInBits = drwav_bytes_to_u16_ex (commData + 6, pWav->container); - sampleRate = drwav_aiff_extented_to_s64(commData + 8); - - if (sampleRate < 0 || sampleRate > 0xFFFFFFFF) { - return DRWAV_FALSE; /* Invalid sample rate. */ - } - - if (isAIFCFormType) { - const drwav_uint8* type = commData + 18; - - if (drwav_fourcc_equal(type, "NONE")) { - compressionFormat = DR_WAVE_FORMAT_PCM; /* PCM, big-endian. */ - } else if (drwav_fourcc_equal(type, "raw ")) { - compressionFormat = DR_WAVE_FORMAT_PCM; - - /* In my testing, it looks like when the "raw " compression type is used, 8-bit samples should be considered unsigned. */ - if (sampleSizeInBits == 8) { - pWav->aiff.isUnsigned = DRWAV_TRUE; + if (bytesJustRead == sizeof(smplLoopData)) { + pWav->smpl.loops[iLoop].cuePointId = drwav_bytes_to_u32(smplLoopData+0); + pWav->smpl.loops[iLoop].type = drwav_bytes_to_u32(smplLoopData+4); + pWav->smpl.loops[iLoop].start = drwav_bytes_to_u32(smplLoopData+8); + pWav->smpl.loops[iLoop].end = drwav_bytes_to_u32(smplLoopData+12); + pWav->smpl.loops[iLoop].fraction = drwav_bytes_to_u32(smplLoopData+16); + pWav->smpl.loops[iLoop].playCount = drwav_bytes_to_u32(smplLoopData+20); + } else { + break; /* Break from the smpl loop for loop. */ + } + } } - } else if (drwav_fourcc_equal(type, "sowt")) { - compressionFormat = DR_WAVE_FORMAT_PCM; /* PCM, little-endian. */ - pWav->aiff.isLE = DRWAV_TRUE; - } else if (drwav_fourcc_equal(type, "fl32") || drwav_fourcc_equal(type, "fl64") || drwav_fourcc_equal(type, "FL32") || drwav_fourcc_equal(type, "FL64")) { - compressionFormat = DR_WAVE_FORMAT_IEEE_FLOAT; - } else if (drwav_fourcc_equal(type, "alaw") || drwav_fourcc_equal(type, "ALAW")) { - compressionFormat = DR_WAVE_FORMAT_ALAW; - } else if (drwav_fourcc_equal(type, "ulaw") || drwav_fourcc_equal(type, "ULAW")) { - compressionFormat = DR_WAVE_FORMAT_MULAW; - } else if (drwav_fourcc_equal(type, "ima4")) { - compressionFormat = DR_WAVE_FORMAT_DVI_ADPCM; - sampleSizeInBits = 4; - - /* - I haven't been able to figure out how to get correct decoding for IMA ADPCM. Until this is figured out - we'll need to abort when we encounter such an encoding. Advice welcome! - */ - return DRWAV_FALSE; } else { - return DRWAV_FALSE; /* Unknown or unsupported compression format. Need to abort. */ - } - } else { - compressionFormat = DR_WAVE_FORMAT_PCM; /* It's a standard AIFF form which is always compressed. */ - } - - /* With AIFF we want to use the explicitly defined frame count rather than deriving it from the size of the chunk. */ - aiffFrameCount = frameCount; - - /* We should now have enough information to fill out our fmt structure. */ - fmt.formatTag = compressionFormat; - fmt.channels = channels; - fmt.sampleRate = (drwav_uint32)sampleRate; - fmt.bitsPerSample = sampleSizeInBits; - fmt.blockAlign = (drwav_uint16)(fmt.channels * fmt.bitsPerSample / 8); - fmt.avgBytesPerSec = fmt.blockAlign * fmt.sampleRate; - - if (fmt.blockAlign == 0 && compressionFormat == DR_WAVE_FORMAT_DVI_ADPCM) { - fmt.blockAlign = 34 * fmt.channels; - } - - /* - Weird one. I've seen some alaw and ulaw encoded files that for some reason set the bits per sample to 16 when - it should be 8. To get this working I need to explicitly check for this and change it. - */ - if (compressionFormat == DR_WAVE_FORMAT_ALAW || compressionFormat == DR_WAVE_FORMAT_MULAW) { - if (fmt.bitsPerSample > 8) { - fmt.bitsPerSample = 8; - fmt.blockAlign = fmt.channels; + /* Looks like invalid data. Ignore the chunk. */ } } - - /* In AIFF, samples are padded to 8 byte boundaries. We need to round up our bits per sample here. */ - fmt.bitsPerSample += (fmt.bitsPerSample & 7); - - - /* If the form type is AIFC there will be some additional data in the chunk. We need to seek past it. */ - if (isAIFCFormType) { - if (drwav__seek_forward(pWav->onSeek, (chunkSize - commDataBytesToRead), pWav->pUserData) == DRWAV_FALSE) { - return DRWAV_FALSE; - } - cursor += (chunkSize - commDataBytesToRead); - } - - /* Don't fall through or else we'll end up treating this chunk as metadata which is incorrect. */ - continue; - } - - - /* "SSND". AIFF/AIFC only. This is the AIFF equivalent of the "data" chunk. */ - if (pWav->container == drwav_container_aiff && drwav_fourcc_equal(header.id.fourcc, "SSND")) { - drwav_uint8 offsetAndBlockSizeData[8]; - drwav_uint32 offset; - - foundChunk_data = DRWAV_TRUE; - - if (drwav__on_read(pWav->onRead, pWav->pUserData, offsetAndBlockSizeData, sizeof(offsetAndBlockSizeData), &cursor) != sizeof(offsetAndBlockSizeData)) { - return DRWAV_FALSE; - } - - /* We need to seek forward by the offset. */ - offset = drwav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); - if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) { - return DRWAV_FALSE; - } - cursor += offset; - - pWav->dataChunkDataPos = cursor; - dataChunkSize = chunkSize; - - /* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */ - if (sequential || !isProcessingMetadata) { - break; /* No need to keep reading beyond the data chunk. */ - } else { - if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) { - break; - } - cursor += chunkSize; - - continue; /* There may be some more metadata to read. */ + } else { + if (drwav_guid_equal(header.id.guid, drwavGUID_W64_SMPL)) { + /* + This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution + is welcome to add support for this. + */ } } - - - /* Getting here means it's not a chunk that we care about internally, but might need to be handled as metadata by the caller. */ - if (isProcessingMetadata) { - drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown); - - /* Go back to the start of the chunk so we can normalize the position of the cursor. */ - if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) { - break; /* Failed to seek. Can't reliable read the remaining chunks. Get out. */ - } - } - - - /* Make sure we skip past the content of this chunk before we go to the next one. */ - chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */ - if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) { + /* Make sure we seek past the padding. */ + chunkSize += header.paddingSize; + if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) { break; } cursor += chunkSize; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } } - /* There's some mandatory chunks that must exist. If they were not found in the iteration above we must abort. */ - if (!foundChunk_fmt || !foundChunk_data) { + /* If we haven't found a data chunk, return an error. */ + if (!foundDataChunk) { return DRWAV_FALSE; } - /* Basic validation. */ - if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE ) || - (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS ) || - (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) || - fmt.blockAlign == 0) { - return DRWAV_FALSE; /* Probably an invalid WAV file. */ - } - - /* Translate the internal format. */ - translatedFormatTag = fmt.formatTag; - if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { - translatedFormatTag = drwav_bytes_to_u16_ex(fmt.subFormat + 0, pWav->container); - } - /* We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. */ if (!sequential) { if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { @@ -3603,79 +2106,10 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on } cursor = pWav->dataChunkDataPos; } - - - /* - At this point we should have done the initial parsing of each of our chunks, but we now need to - do a second pass to extract the actual contents of the metadata (the first pass just calculated - the length of the memory allocation). - - We only do this if we've actually got metadata to parse. - */ - if (isProcessingMetadata && metadataParser.metadataCount > 0) { - if (drwav__seek_from_start(pWav->onSeek, metadataStartPos, pWav->pUserData) == DRWAV_FALSE) { - return DRWAV_FALSE; - } - - result = drwav__metadata_alloc(&metadataParser, &pWav->allocationCallbacks); - if (result != DRWAV_SUCCESS) { - return DRWAV_FALSE; - } - - metadataParser.stage = drwav__metadata_parser_stage_read; - - for (;;) { - drwav_chunk_header header; - drwav_uint64 metadataBytesRead; - - result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); - if (result != DRWAV_SUCCESS) { - break; - } - - metadataBytesRead = drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown); - - /* Move to the end of the chunk so we can keep iterating. */ - if (drwav__seek_forward(pWav->onSeek, (header.sizeInBytes + header.paddingSize) - metadataBytesRead, pWav->pUserData) == DRWAV_FALSE) { - drwav_free(metadataParser.pMetadata, &pWav->allocationCallbacks); - return DRWAV_FALSE; - } - } - - /* Getting here means we're finished parsing the metadata. */ - pWav->pMetadata = metadataParser.pMetadata; - pWav->metadataCount = metadataParser.metadataCount; - } - + /* At this point we should be sitting on the first byte of the raw audio data. */ - /* - I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and - "data" chunks set to 0xFFFFFFFF when the file is definitely not that big. In this case we're - going to have to calculate the size by reading and discarding bytes, and then seeking back. We - cannot do this in sequential mode. We just assume that the rest of the file is audio data. - */ - if (dataChunkSize == 0xFFFFFFFF && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) && pWav->isSequentialWrite == DRWAV_FALSE) { - dataChunkSize = 0; - - for (;;) { - drwav_uint8 temp[4096]; - size_t bytesRead = pWav->onRead(pWav->pUserData, temp, sizeof(temp)); - dataChunkSize += bytesRead; - - if (bytesRead < sizeof(temp)) { - break; - } - } - } - - if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) { - drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return DRWAV_FALSE; - } - - pWav->fmt = fmt; pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; @@ -3686,16 +2120,8 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; - } else if (aiffFrameCount != 0) { - pWav->totalPCMFrameCount = aiffFrameCount; } else { - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return DRWAV_FALSE; /* Invalid file. */ - } - - pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame; + pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 totalBlockHeaderSizeInBytes; @@ -3731,17 +2157,10 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on /* Some formats only support a certain number of channels. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { if (pWav->channels > 2) { - drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); return DRWAV_FALSE; } } - /* The number of bytes per frame must be known. If not, it's an invalid file and not decodable. */ - if (drwav_get_bytes_per_pcm_frame(pWav) == 0) { - drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return DRWAV_FALSE; - } - #ifdef DR_WAV_LIBSNDFILE_COMPAT /* I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), @@ -3778,23 +2197,51 @@ DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_ return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); } -DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) + +DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize) { - if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { - return DRWAV_FALSE; + drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. */ + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; } - return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA); + return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */ } -DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav) +DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize) { - drwav_metadata *result = pWav->pMetadata; + if (dataChunkSize <= 0xFFFFFFFFUL) { + return (drwav_uint32)dataChunkSize; + } else { + return 0xFFFFFFFFUL; + } +} - pWav->pMetadata = NULL; - pWav->metadataCount = 0; +DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize) +{ + drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize); - return result; + return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */ +} + +DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize) +{ + return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ +} + +DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize) +{ + drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. */ + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + + return chunkSize; +} + +DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize) +{ + return dataChunkSize; } @@ -3807,14 +2254,6 @@ DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSiz return pWav->onWrite(pWav->pUserData, pData, dataSize); } -DRWAV_PRIVATE size_t drwav__write_byte(drwav* pWav, drwav_uint8 byte) -{ - DRWAV_ASSERT(pWav != NULL); - DRWAV_ASSERT(pWav->onWrite != NULL); - - return pWav->onWrite(pWav->pUserData, &byte, 1); -} - DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value) { DRWAV_ASSERT(pWav != NULL); @@ -3851,515 +2290,6 @@ DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value) return drwav__write(pWav, &value, 8); } -DRWAV_PRIVATE size_t drwav__write_f32ne_to_le(drwav* pWav, float value) -{ - union { - drwav_uint32 u32; - float f32; - } u; - - DRWAV_ASSERT(pWav != NULL); - DRWAV_ASSERT(pWav->onWrite != NULL); - - u.f32 = value; - - if (!drwav__is_little_endian()) { - u.u32 = drwav__bswap32(u.u32); - } - - return drwav__write(pWav, &u.u32, 4); -} - -DRWAV_PRIVATE size_t drwav__write_or_count(drwav* pWav, const void* pData, size_t dataSize) -{ - if (pWav == NULL) { - return dataSize; - } - - return drwav__write(pWav, pData, dataSize); -} - -DRWAV_PRIVATE size_t drwav__write_or_count_byte(drwav* pWav, drwav_uint8 byte) -{ - if (pWav == NULL) { - return 1; - } - - return drwav__write_byte(pWav, byte); -} - -DRWAV_PRIVATE size_t drwav__write_or_count_u16ne_to_le(drwav* pWav, drwav_uint16 value) -{ - if (pWav == NULL) { - return 2; - } - - return drwav__write_u16ne_to_le(pWav, value); -} - -DRWAV_PRIVATE size_t drwav__write_or_count_u32ne_to_le(drwav* pWav, drwav_uint32 value) -{ - if (pWav == NULL) { - return 4; - } - - return drwav__write_u32ne_to_le(pWav, value); -} - -#if 0 /* Unused for now. */ -DRWAV_PRIVATE size_t drwav__write_or_count_u64ne_to_le(drwav* pWav, drwav_uint64 value) -{ - if (pWav == NULL) { - return 8; - } - - return drwav__write_u64ne_to_le(pWav, value); -} -#endif - -DRWAV_PRIVATE size_t drwav__write_or_count_f32ne_to_le(drwav* pWav, float value) -{ - if (pWav == NULL) { - return 4; - } - - return drwav__write_f32ne_to_le(pWav, value); -} - -DRWAV_PRIVATE size_t drwav__write_or_count_string_to_fixed_size_buf(drwav* pWav, char* str, size_t bufFixedSize) -{ - size_t len; - - if (pWav == NULL) { - return bufFixedSize; - } - - len = drwav__strlen_clamped(str, bufFixedSize); - drwav__write_or_count(pWav, str, len); - - if (len < bufFixedSize) { - size_t i; - for (i = 0; i < bufFixedSize - len; ++i) { - drwav__write_byte(pWav, 0); - } - } - - return bufFixedSize; -} - - -/* pWav can be NULL meaning just count the bytes that would be written. */ -DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* pMetadatas, drwav_uint32 metadataCount) -{ - size_t bytesWritten = 0; - drwav_bool32 hasListAdtl = DRWAV_FALSE; - drwav_bool32 hasListInfo = DRWAV_FALSE; - drwav_uint32 iMetadata; - - if (pMetadatas == NULL || metadataCount == 0) { - return 0; - } - - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - drwav_metadata* pMetadata = &pMetadatas[iMetadata]; - drwav_uint32 chunkSize = 0; - - if ((pMetadata->type & drwav_metadata_type_list_all_info_strings) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list)) { - hasListInfo = DRWAV_TRUE; - } - - if ((pMetadata->type & drwav_metadata_type_list_all_adtl) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list)) { - hasListAdtl = DRWAV_TRUE; - } - - switch (pMetadata->type) { - case drwav_metadata_type_smpl: - { - drwav_uint32 iLoop; - - chunkSize = DRWAV_SMPL_BYTES + DRWAV_SMPL_LOOP_BYTES * pMetadata->data.smpl.sampleLoopCount + pMetadata->data.smpl.samplerSpecificDataSizeInBytes; - - bytesWritten += drwav__write_or_count(pWav, "smpl", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.manufacturerId); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.productId); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplePeriodNanoseconds); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiUnityNote); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiPitchFraction); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteFormat); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteOffset); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.sampleLoopCount); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplerSpecificDataSizeInBytes); - - for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); - } - - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes); - } - } break; - - case drwav_metadata_type_inst: - { - chunkSize = DRWAV_INST_BYTES; - - bytesWritten += drwav__write_or_count(pWav, "inst", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.midiUnityNote, 1); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.fineTuneCents, 1); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.gainDecibels, 1); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowNote, 1); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highNote, 1); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowVelocity, 1); - bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highVelocity, 1); - } break; - - case drwav_metadata_type_cue: - { - drwav_uint32 iCuePoint; - - chunkSize = DRWAV_CUE_BYTES + DRWAV_CUE_POINT_BYTES * pMetadata->data.cue.cuePointCount; - - bytesWritten += drwav__write_or_count(pWav, "cue ", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.cuePointCount); - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].id); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); - } - } break; - - case drwav_metadata_type_acid: - { - chunkSize = DRWAV_ACID_BYTES; - - bytesWritten += drwav__write_or_count(pWav, "acid", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.flags); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.midiUnityNote); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.reserved1); - bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.reserved2); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.numBeats); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterDenominator); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterNumerator); - bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.tempo); - } break; - - case drwav_metadata_type_bext: - { - char reservedBuf[DRWAV_BEXT_RESERVED_BYTES]; - drwav_uint32 timeReferenceLow; - drwav_uint32 timeReferenceHigh; - - chunkSize = DRWAV_BEXT_BYTES + pMetadata->data.bext.codingHistorySize; - - bytesWritten += drwav__write_or_count(pWav, "bext", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - - bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pDescription, DRWAV_BEXT_DESCRIPTION_BYTES); - bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorName, DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorReference, DRWAV_BEXT_ORIGINATOR_REF_BYTES); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate)); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime)); - - timeReferenceLow = (drwav_uint32)(pMetadata->data.bext.timeReference & 0xFFFFFFFF); - timeReferenceHigh = (drwav_uint32)(pMetadata->data.bext.timeReference >> 32); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceLow); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceHigh); - - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.version); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessValue); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessRange); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxTruePeakLevel); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness); - - DRWAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf)); - bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf)); - - if (pMetadata->data.bext.codingHistorySize > 0) { - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize); - } - } break; - - case drwav_metadata_type_unknown: - { - if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_top_level) { - chunkSize = pMetadata->data.unknown.dataSizeInBytes; - - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes); - } - } break; - - default: break; - } - if ((chunkSize % 2) != 0) { - bytesWritten += drwav__write_or_count_byte(pWav, 0); - } - } - - if (hasListInfo) { - drwav_uint32 chunkSize = 4; /* Start with 4 bytes for "INFO". */ - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - drwav_metadata* pMetadata = &pMetadatas[iMetadata]; - - if ((pMetadata->type & drwav_metadata_type_list_all_info_strings)) { - chunkSize += 8; /* For id and string size. */ - chunkSize += pMetadata->data.infoText.stringLength + 1; /* Include null terminator. */ - } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) { - chunkSize += 8; /* For id string size. */ - chunkSize += pMetadata->data.unknown.dataSizeInBytes; - } - - if ((chunkSize % 2) != 0) { - chunkSize += 1; - } - } - - bytesWritten += drwav__write_or_count(pWav, "LIST", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += drwav__write_or_count(pWav, "INFO", 4); - - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - drwav_metadata* pMetadata = &pMetadatas[iMetadata]; - drwav_uint32 subchunkSize = 0; - - if (pMetadata->type & drwav_metadata_type_list_all_info_strings) { - const char* pID = NULL; - - switch (pMetadata->type) { - case drwav_metadata_type_list_info_software: pID = "ISFT"; break; - case drwav_metadata_type_list_info_copyright: pID = "ICOP"; break; - case drwav_metadata_type_list_info_title: pID = "INAM"; break; - case drwav_metadata_type_list_info_artist: pID = "IART"; break; - case drwav_metadata_type_list_info_comment: pID = "ICMT"; break; - case drwav_metadata_type_list_info_date: pID = "ICRD"; break; - case drwav_metadata_type_list_info_genre: pID = "IGNR"; break; - case drwav_metadata_type_list_info_album: pID = "IPRD"; break; - case drwav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; - default: break; - } - - DRWAV_ASSERT(pID != NULL); - - if (pMetadata->data.infoText.stringLength) { - subchunkSize = pMetadata->data.infoText.stringLength + 1; - bytesWritten += drwav__write_or_count(pWav, pID, 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.infoText.pString, pMetadata->data.infoText.stringLength); - bytesWritten += drwav__write_or_count_byte(pWav, '\0'); - } - } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) { - if (pMetadata->data.unknown.dataSizeInBytes) { - subchunkSize = pMetadata->data.unknown.dataSizeInBytes; - - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.unknown.dataSizeInBytes); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize); - } - } - - if ((subchunkSize % 2) != 0) { - bytesWritten += drwav__write_or_count_byte(pWav, 0); - } - } - } - - if (hasListAdtl) { - drwav_uint32 chunkSize = 4; /* start with 4 bytes for "adtl" */ - - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - drwav_metadata* pMetadata = &pMetadatas[iMetadata]; - - switch (pMetadata->type) - { - case drwav_metadata_type_list_label: - case drwav_metadata_type_list_note: - { - chunkSize += 8; /* for id and chunk size */ - chunkSize += DRWAV_LIST_LABEL_OR_NOTE_BYTES; - - if (pMetadata->data.labelOrNote.stringLength > 0) { - chunkSize += pMetadata->data.labelOrNote.stringLength + 1; - } - } break; - - case drwav_metadata_type_list_labelled_cue_region: - { - chunkSize += 8; /* for id and chunk size */ - chunkSize += DRWAV_LIST_LABELLED_TEXT_BYTES; - - if (pMetadata->data.labelledCueRegion.stringLength > 0) { - chunkSize += pMetadata->data.labelledCueRegion.stringLength + 1; - } - } break; - - case drwav_metadata_type_unknown: - { - if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) { - chunkSize += 8; /* for id and chunk size */ - chunkSize += pMetadata->data.unknown.dataSizeInBytes; - } - } break; - - default: break; - } - - if ((chunkSize % 2) != 0) { - chunkSize += 1; - } - } - - bytesWritten += drwav__write_or_count(pWav, "LIST", 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += drwav__write_or_count(pWav, "adtl", 4); - - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - drwav_metadata* pMetadata = &pMetadatas[iMetadata]; - drwav_uint32 subchunkSize = 0; - - switch (pMetadata->type) - { - case drwav_metadata_type_list_label: - case drwav_metadata_type_list_note: - { - if (pMetadata->data.labelOrNote.stringLength > 0) { - const char *pID = NULL; - - if (pMetadata->type == drwav_metadata_type_list_label) { - pID = "labl"; - } - else if (pMetadata->type == drwav_metadata_type_list_note) { - pID = "note"; - } - - DRWAV_ASSERT(pID != NULL); - DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - - subchunkSize = DRWAV_LIST_LABEL_OR_NOTE_BYTES; - - bytesWritten += drwav__write_or_count(pWav, pID, 4); - subchunkSize += pMetadata->data.labelOrNote.stringLength + 1; - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize); - - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelOrNote.cuePointId); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelOrNote.pString, pMetadata->data.labelOrNote.stringLength); - bytesWritten += drwav__write_or_count_byte(pWav, '\0'); - } - } break; - - case drwav_metadata_type_list_labelled_cue_region: - { - subchunkSize = DRWAV_LIST_LABELLED_TEXT_BYTES; - - bytesWritten += drwav__write_or_count(pWav, "ltxt", 4); - if (pMetadata->data.labelledCueRegion.stringLength > 0) { - subchunkSize += pMetadata->data.labelledCueRegion.stringLength + 1; - } - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.cuePointId); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.sampleLength); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.purposeId, 4); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.country); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.language); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.dialect); - bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.codePage); - - if (pMetadata->data.labelledCueRegion.stringLength > 0) { - DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.pString, pMetadata->data.labelledCueRegion.stringLength); - bytesWritten += drwav__write_or_count_byte(pWav, '\0'); - } - } break; - - case drwav_metadata_type_unknown: - { - if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) { - subchunkSize = pMetadata->data.unknown.dataSizeInBytes; - - DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4); - bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize); - } - } break; - - default: break; - } - - if ((subchunkSize % 2) != 0) { - bytesWritten += drwav__write_or_count_byte(pWav, 0); - } - } - } - - DRWAV_ASSERT((bytesWritten % 2) == 0); - - return bytesWritten; -} - -DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize, drwav_metadata* pMetadata, drwav_uint32 metadataCount) -{ - drwav_uint64 chunkSize = 4 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, pMetadata, metadataCount) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. 8 = "data" + u32 data size. */ - if (chunkSize > 0xFFFFFFFFUL) { - chunkSize = 0xFFFFFFFFUL; - } - - return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */ -} - -DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize) -{ - if (dataChunkSize <= 0xFFFFFFFFUL) { - return (drwav_uint32)dataChunkSize; - } else { - return 0xFFFFFFFFUL; - } -} - -DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize) -{ - drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize); - - return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */ -} - -DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize) -{ - return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ -} - -DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize, drwav_metadata *metadata, drwav_uint32 numMetadata) -{ - drwav_uint64 chunkSize = 4 + 36 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, metadata, numMetadata) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. 8 = "data" + u32 data size. */ - if (chunkSize > 0xFFFFFFFFUL) { - chunkSize = 0xFFFFFFFFUL; - } - - return chunkSize; -} - -DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize) -{ - return dataChunkSize; -} - - DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -4401,7 +2331,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_for return DRWAV_TRUE; } - DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) { /* The function assumes drwav_preinit_write() was called beforehand. */ @@ -4447,11 +2376,9 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_d runningPos += drwav__write(pWav, "RF64", 4); runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */ runningPos += drwav__write(pWav, "WAVE", 4); - } else { - return DRWAV_FALSE; /* Container not supported for writing. */ } - + /* "ds64" chunk (RF64 only). */ if (pFormat->container == drwav_container_rf64) { drwav_uint32 initialds64ChunkSize = 28; /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */ @@ -4484,14 +2411,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_d runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign); runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample); - /* TODO: is a 'fact' chunk required for DR_WAVE_FORMAT_IEEE_FLOAT? */ - - if (!pWav->isSequentialWrite && pWav->pMetadata != NULL && pWav->metadataCount > 0 && (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64)) { - runningPos += drwav__write_or_count_metadata(pWav, pWav->pMetadata, pWav->metadataCount); - } - - pWav->dataChunkDataPos = runningPos; - /* "data" chunk. */ if (pFormat->container == drwav_container_riff) { drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize; @@ -4545,34 +2464,21 @@ DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks); } -DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount) +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) { - if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { - return DRWAV_FALSE; - } - - pWav->pMetadata = pMetadata; - pWav->metadataCount = metadataCount; - - return drwav_init_write__internal(pWav, pFormat, 0); -} - - -DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount) -{ - /* Casting totalFrameCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */ - drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalFrameCount * pFormat->channels * pFormat->bitsPerSample/8.0); + /* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */ + drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0); drwav_uint64 riffChunkSizeBytes; drwav_uint64 fileSizeBytes = 0; if (pFormat->container == drwav_container_riff) { - riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes, pMetadata, metadataCount); + riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes); fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ } else if (pFormat->container == drwav_container_w64) { riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes); fileSizeBytes = riffChunkSizeBytes; } else if (pFormat->container == drwav_container_rf64) { - riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes, pMetadata, metadataCount); + riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes); fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ } @@ -4582,7 +2488,6 @@ DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pF #ifndef DR_WAV_NO_STDIO -/* Errno */ /* drwav_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ #include DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e) @@ -4986,9 +2891,7 @@ DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e) default: return DRWAV_ERROR; } } -/* End Errno */ -/* fopen */ DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) { #if defined(_MSC_VER) && _MSC_VER >= 1400 @@ -5049,7 +2952,6 @@ fallback, so if you notice your compiler not detecting this properly I'm happy t #endif #endif -#ifndef DR_WAV_NO_WCHAR DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks) { if (ppFile != NULL) { @@ -5077,24 +2979,11 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, (void)pAllocationCallbacks; } #else - /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because - fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note - that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler - error I'll look into improving compatibility. + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. */ - - /* - Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just - need to abort with an error. If you encounter a compiler lacking such support, add it to this list - and submit a bug report and it'll be added to the library upstream. - */ - #if defined(__DJGPP__) - { - /* Nothing to do here. This will fall through to the error check below. */ - } - #else { mbstate_t mbs; size_t lenMB; @@ -5136,7 +3025,6 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } - #endif if (*ppFile == NULL) { return DRWAV_ERROR; @@ -5145,8 +3033,6 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, return DRWAV_SUCCESS; } -#endif -/* End fopen */ DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) @@ -5179,7 +3065,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFi fclose(pFile); return result; } - + result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); if (result != DRWAV_TRUE) { fclose(pFile); @@ -5200,7 +3086,6 @@ DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drw return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); } -#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks) { return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); @@ -5216,31 +3101,6 @@ DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename /* This takes ownership of the FILE* object. */ return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); } -#endif - -DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) -{ - FILE* pFile; - if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) { - return DRWAV_FALSE; - } - - /* This takes ownership of the FILE* object. */ - return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | DRWAV_WITH_METADATA, pAllocationCallbacks); -} - -#ifndef DR_WAV_NO_WCHAR -DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) -{ - FILE* pFile; - if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) { - return DRWAV_FALSE; - } - - /* This takes ownership of the FILE* object. */ - return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | DRWAV_WITH_METADATA, pAllocationCallbacks); -} -#endif DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) @@ -5273,7 +3133,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const ch return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); } -#ifndef DR_WAV_NO_WCHAR DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; @@ -5284,7 +3143,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const /* This takes ownership of the FILE* object. */ return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); } -#endif DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -5305,7 +3163,6 @@ DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } -#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); @@ -5324,7 +3181,6 @@ DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } -#endif #endif /* DR_WAV_NO_STDIO */ @@ -5374,7 +3230,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, dr return DRWAV_FALSE; /* Trying to seek too far forward. */ } } - + return DRWAV_TRUE; } @@ -5443,7 +3299,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offs pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */ } } - + return DRWAV_TRUE; } @@ -5469,23 +3325,6 @@ DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_ return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); } -DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) -{ - if (data == NULL || dataSize == 0) { - return DRWAV_FALSE; - } - - if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) { - return DRWAV_FALSE; - } - - pWav->memoryStream.data = (const drwav_uint8*)data; - pWav->memoryStream.dataSize = dataSize; - pWav->memoryStream.currentReadPos = 0; - - return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA); -} - DRWAV_PRIVATE drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -5552,7 +3391,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) } else { paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize); } - + if (paddingSize > 0) { drwav_uint64 paddingData = 0; drwav__write(pWav, &paddingData, paddingSize); /* Byte order does not matter for this. */ @@ -5566,7 +3405,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) if (pWav->container == drwav_container_riff) { /* The "RIFF" chunk size. */ if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { - drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); + drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize); drwav__write_u32ne_to_le(pWav, riffChunkSize); } @@ -5593,7 +3432,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) /* The "RIFF" chunk size. */ if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) { - drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize); drwav__write_u64ne_to_le(pWav, riffChunkSize); } @@ -5611,8 +3450,6 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) result = DRWAV_INVALID_FILE; } } - } else { - drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); } #ifndef DR_WAV_NO_STDIO @@ -5633,25 +3470,15 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { size_t bytesRead; - drwav_uint32 bytesPerFrame; if (pWav == NULL || bytesToRead == 0) { - return 0; /* Invalid args. */ + return 0; } if (bytesToRead > pWav->bytesRemaining) { bytesToRead = (size_t)pWav->bytesRemaining; } - if (bytesToRead == 0) { - return 0; /* At end. */ - } - - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; /* Could not determine the bytes per frame. */ - } - if (pBufferOut != NULL) { bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); } else { @@ -5688,8 +3515,6 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu } } - pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; - pWav->bytesRemaining -= bytesRead; return bytesRead; } @@ -5700,7 +3525,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 frames { drwav_uint32 bytesPerFrame; drwav_uint64 bytesToRead; /* Intentionally uint64 instead of size_t so we can do a check that we're not reading too much on 32-bit builds. */ - drwav_uint64 framesRemainingInFile; if (pWav == NULL || framesToRead == 0) { return 0; @@ -5711,11 +3535,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 frames return 0; } - framesRemainingInFile = pWav->totalPCMFrameCount - pWav->readCursorInPCMFrames; - if (framesToRead > framesRemainingInFile) { - framesToRead = framesRemainingInFile; - } - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; @@ -5743,12 +3562,7 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 frames drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); if (pBufferOut != NULL) { - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; /* Could not get the bytes per frame which means bytes per sample cannot be determined and we don't know how to byte swap. */ - } - - drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels); + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); } return framesRead; @@ -5756,50 +3570,11 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 frames DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { - drwav_uint64 framesRead = 0; - - if (drwav_is_container_be(pWav->container)) { - /* - Special case for AIFF. AIFF is a big-endian encoded format, but it supports a format that is - PCM in little-endian encoding. In this case, we fall through this branch and treate it as - little-endian. - */ - if (pWav->container != drwav_container_aiff || pWav->aiff.isLE == DRWAV_FALSE) { - if (drwav__is_little_endian()) { - framesRead = drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); - } else { - framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); - } - - goto post_process; - } - } - - /* Getting here means the data should be considered little-endian. */ if (drwav__is_little_endian()) { - framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); } else { - framesRead = drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); + return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); } - - /* - Here is where we check if we need to do a signed/unsigned conversion for AIFF. The reason we need to do this - is because dr_wav always assumes an 8-bit sample is unsigned, whereas AIFF can have signed 8-bit formats. - */ - post_process: - { - if (pWav->container == drwav_container_aiff && pWav->bitsPerSample == 8 && pWav->aiff.isUnsigned == DRWAV_FALSE) { - if (pBufferOut != NULL) { - drwav_uint64 iSample; - - for (iSample = 0; iSample < framesRead * pWav->channels; iSample += 1) { - ((drwav_uint8*)pBufferOut)[iSample] += 128; - } - } - } - } - - return framesRead; } @@ -5815,6 +3590,8 @@ DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) } if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + pWav->compressed.iCurrentPCMFrame = 0; + /* Cached data needs to be cleared for compressed formats. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { DRWAV_ZERO_OBJECT(&pWav->msadpcm); @@ -5824,10 +3601,8 @@ DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ } } - - pWav->readCursorInPCMFrames = 0; + pWav->bytesRemaining = pWav->dataChunkDataSize; - return DRWAV_TRUE; } @@ -5850,8 +3625,8 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF } /* Make sure the sample is clamped. */ - if (targetFrameIndex > pWav->totalPCMFrameCount) { - targetFrameIndex = pWav->totalPCMFrameCount; + if (targetFrameIndex >= pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount - 1; } /* @@ -5860,19 +3635,19 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF */ if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { /* TODO: This can be optimized. */ - + /* If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards, we first need to seek back to the start and then just do the same thing as a forward seek. */ - if (targetFrameIndex < pWav->readCursorInPCMFrames) { + if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) { if (!drwav_seek_to_first_pcm_frame(pWav)) { return DRWAV_FALSE; } } - if (targetFrameIndex > pWav->readCursorInPCMFrames) { - drwav_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames; + if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) { + drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame; drwav_int16 devnull[2048]; while (offsetInFrames > 0) { @@ -5902,18 +3677,12 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF drwav_uint64 currentBytePos; drwav_uint64 targetBytePos; drwav_uint64 offset; - drwav_uint32 bytesPerFrame; - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return DRWAV_FALSE; /* Not able to calculate offset. */ - } - - totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame; - /*DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);*/ + totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - targetBytePos = targetFrameIndex * bytesPerFrame; + targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); if (currentBytePos < targetBytePos) { /* Offset forwards. */ @@ -5932,49 +3701,14 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF return DRWAV_FALSE; } - pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; - pWav->bytesRemaining -= offset32; - offset -= offset32; + pWav->bytesRemaining -= offset32; + offset -= offset32; } } return DRWAV_TRUE; } -DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor) -{ - if (pCursor == NULL) { - return DRWAV_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pWav == NULL) { - return DRWAV_INVALID_ARGS; - } - - *pCursor = pWav->readCursorInPCMFrames; - - return DRWAV_SUCCESS; -} - -DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength) -{ - if (pLength == NULL) { - return DRWAV_INVALID_ARGS; - } - - *pLength = 0; /* Safety. */ - - if (pWav == NULL) { - return DRWAV_INVALID_ARGS; - } - - *pLength = pWav->totalPCMFrameCount; - - return DRWAV_SUCCESS; -} - DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) { @@ -5990,6 +3724,7 @@ DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* p return bytesWritten; } + DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) { drwav_uint64 bytesToWrite; @@ -6048,10 +3783,7 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 frame pRunningData = (const drwav_uint8*)pData; bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; - if (bytesPerSample == 0) { - return 0; /* Cannot determine bytes per sample, or bytes per sample is less than one byte. */ - } - + while (bytesToWrite > 0) { drwav_uint8 temp[4096]; drwav_uint32 sampleCount; @@ -6072,7 +3804,7 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 frame } DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); - drwav__bswap_samples(temp, sampleCount, bytesPerSample); + drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag); bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); if (bytesJustWritten == 0) { @@ -6106,7 +3838,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav /* TODO: Lots of room for optimization here. */ - while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */ /* If there are no cached frames we need to load a new block. */ @@ -6152,7 +3884,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav } /* Output anything that's cached. */ - while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { if (pBufferOut != NULL) { drwav_uint32 iSample = 0; for (iSample = 0; iSample < pWav->channels; iSample += 1) { @@ -6164,7 +3896,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav framesToRead -= 1; totalFramesRead += 1; - pWav->readCursorInPCMFrames += 1; + pWav->compressed.iCurrentPCMFrame += 1; pWav->msadpcm.cachedFrameCount -= 1; } @@ -6181,9 +3913,9 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav if (pWav->msadpcm.bytesRemainingInBlock == 0) { continue; } else { - static drwav_int32 adaptationTable[] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 + static drwav_int32 adaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 }; static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; @@ -6290,15 +4022,15 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin }; static drwav_int32 stepTable[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; DRWAV_ASSERT(pWav != NULL); @@ -6306,7 +4038,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin /* TODO: Lots of room for optimization here. */ - while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */ /* If there are no cached samples we need to load a new block. */ @@ -6325,8 +4057,8 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; /* Invalid data. */ } - pWav->ima.predictor[0] = (drwav_int16)drwav_bytes_to_u16(header + 0); - pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */ + pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedFrameCount = 1; } else { @@ -6344,9 +4076,9 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */ + pWav->ima.stepIndex[0] = header[2]; pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4); - pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */ + pWav->ima.stepIndex[1] = header[6]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; @@ -6355,7 +4087,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin } /* Output anything that's cached. */ - while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { if (pBufferOut != NULL) { drwav_uint32 iSample; for (iSample = 0; iSample < pWav->channels; iSample += 1) { @@ -6366,7 +4098,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin framesToRead -= 1; totalFramesRead += 1; - pWav->readCursorInPCMFrames += 1; + pWav->compressed.iCurrentPCMFrame += 1; pWav->ima.cachedFrameCount -= 1; } @@ -6440,40 +4172,40 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin #ifndef DR_WAV_NO_CONVERSION_API static unsigned short g_drwavAlawTable[256] = { - 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, - 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, - 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, - 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, - 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, - 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, - 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, - 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, - 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, - 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, - 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, - 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, - 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, - 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, - 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, + 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, + 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, + 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, + 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, + 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, + 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, + 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, + 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, + 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, + 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, + 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, + 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, + 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, + 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, + 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 }; static unsigned short g_drwavMulawTable[256] = { - 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, - 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, - 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, - 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, - 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, - 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, - 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, - 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, - 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, - 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, - 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, - 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, - 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, - 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, - 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, + 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, + 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, + 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, + 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, + 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, + 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, + 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, + 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, + 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, + 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, + 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, + 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, + 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, + 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 }; @@ -6491,7 +4223,7 @@ static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - size_t i; + unsigned int i; /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { @@ -6559,47 +4291,30 @@ DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; + drwav_uint8 sampleData[4096]; drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; /* Fast path. */ if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } - + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; - + while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6610,10 +4325,8 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; + drwav_uint8 sampleData[4096]; drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); @@ -6624,32 +4337,17 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; - + while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); /* Safe cast. */ - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6660,10 +4358,8 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; + drwav_uint8 sampleData[4096]; drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); @@ -6674,49 +4370,17 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; - + while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); - - /* - For some reason libsndfile seems to be returning samples of the opposite sign for a-law, but only - with AIFF files. For WAV files it seems to be the same as dr_wav. This is resulting in dr_wav's - automated tests failing. I'm not sure which is correct, but will assume dr_wav. If we're enforcing - libsndfile compatibility we'll swap the signs here. - */ - #ifdef DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == drwav_container_aiff) { - drwav_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6727,10 +4391,8 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; + drwav_uint8 sampleData[4096]; drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); @@ -6741,47 +4403,17 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_u return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); - - /* - Just like with alaw, for some reason the signs between libsndfile and dr_wav are opposite. We just need to - swap the sign if we're compiling with libsndfile compatiblity so our automated tests don't fail. - */ - #ifdef DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == drwav_container_aiff) { - drwav_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -6933,6 +4565,7 @@ DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, siz } + DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) { unsigned int i; @@ -7004,42 +4637,24 @@ DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; - drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7047,25 +4662,45 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uin return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { /* We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't want to duplicate that code. */ - drwav_uint64 totalFramesRead; + drwav_uint64 totalFramesRead = 0; drwav_int16 samples16[2048]; - totalFramesRead = 0; - while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ @@ -7080,47 +4715,30 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, d DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; + drwav_uint8 sampleData[4096]; drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } - + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7131,53 +4749,24 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; - drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); - - #ifdef DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == drwav_container_aiff) { - drwav_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7188,53 +4777,24 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; - drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); - - #ifdef DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == drwav_container_aiff) { - drwav_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7261,8 +4821,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { @@ -7277,6 +4837,10 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); + } + return 0; } @@ -7485,47 +5049,30 @@ DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; + drwav_uint8 sampleData[4096]; drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } - + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7533,7 +5080,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uin return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { /* We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't @@ -7543,13 +5090,35 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, d drwav_int16 samples16[2048]; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ @@ -7564,42 +5133,24 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, d DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; - drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7610,53 +5161,24 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; - drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); - - #ifdef DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == drwav_container_aiff) { - drwav_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7667,53 +5189,24 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096] = {0}; - drwav_uint32 bytesPerFrame; - drwav_uint32 bytesPerSample; - drwav_uint64 samplesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); - bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; /* Only byte-aligned formats are supported. */ - } - totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */ - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */ - break; - } - - drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); - - #ifdef DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == drwav_container_aiff) { - drwav_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - - pBufferOut += samplesRead; + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -7740,8 +5233,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { @@ -7756,6 +5249,10 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); + } + return 0; } @@ -7833,7 +5330,7 @@ DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t samp } for (i = 0; i < sampleCount; ++i) { - *pOut++ = (drwav_int32)(2147483648.0f * pIn[i]); + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); } } @@ -8134,7 +5631,6 @@ DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filen } -#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { drwav wav; @@ -8197,8 +5693,7 @@ DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -#endif /* DR_WAV_NO_WCHAR */ -#endif /* DR_WAV_NO_STDIO */ +#endif DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -8276,28 +5771,17 @@ DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocation DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data) { - return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8); + return (data[0] << 0) | (data[1] << 8); } DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data) { - return (drwav_int16)drwav_bytes_to_u16(data); + return (short)drwav_bytes_to_u16(data); } DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data) { - return drwav_bytes_to_u32_le(data); -} - -DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data) -{ - union { - drwav_uint32 u32; - float f32; - } value; - - value.u32 = drwav_bytes_to_u32(data); - return value.f32; + return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data) @@ -8339,89 +5823,197 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) a[3] == b[3]; } -#ifdef __MRC__ -/* Undo the pragma at the beginning of this file. */ -#pragma options opt reset -#endif - #endif /* dr_wav_c */ #endif /* DR_WAV_IMPLEMENTATION */ +/* +RELEASE NOTES - v0.11.0 +======================= +Version 0.11.0 has breaking API changes. + +Improved Client-Defined Memory Allocation +----------------------------------------- +The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The +existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom +allocation callbacks are specified. + +To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this: + + void* my_malloc(size_t sz, void* pUserData) + { + return malloc(sz); + } + void* my_realloc(void* p, size_t sz, void* pUserData) + { + return realloc(p, sz); + } + void my_free(void* p, void* pUserData) + { + free(p); + } + + ... + + drwav_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = &myData; + allocationCallbacks.onMalloc = my_malloc; + allocationCallbacks.onRealloc = my_realloc; + allocationCallbacks.onFree = my_free; + drwav_init_file(&wav, "my_file.wav", &allocationCallbacks); + +The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines. + +Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC, +DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions. + +Every API that opens a drwav object now takes this extra parameter. These include the following: + + drwav_init() + drwav_init_ex() + drwav_init_file() + drwav_init_file_ex() + drwav_init_file_w() + drwav_init_file_w_ex() + drwav_init_memory() + drwav_init_memory_ex() + drwav_init_write() + drwav_init_write_sequential() + drwav_init_write_sequential_pcm_frames() + drwav_init_file_write() + drwav_init_file_write_sequential() + drwav_init_file_write_sequential_pcm_frames() + drwav_init_file_write_w() + drwav_init_file_write_sequential_w() + drwav_init_file_write_sequential_pcm_frames_w() + drwav_init_memory_write() + drwav_init_memory_write_sequential() + drwav_init_memory_write_sequential_pcm_frames() + drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_s16_w() + drwav_open_file_and_read_pcm_frames_f32_w() + drwav_open_file_and_read_pcm_frames_s32_w() + drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_pcm_frames_s32() + +Endian Improvements +------------------- +Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility +on big-endian architectures. + + drwav_read_pcm_frames() + drwav_read_pcm_frames_s16() + drwav_read_pcm_frames_s32() + drwav_read_pcm_frames_f32() + drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_pcm_frames_s32() + drwav_open_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s16_w() + drwav_open_file_and_read_pcm_frames_s32_w() + drwav_open_file_and_read_pcm_frames_f32_w() + drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_pcm_frames_s32() + drwav_open_memory_and_read_pcm_frames_f32() + +APIs have been added to give you explicit control over whether or not audio data is read or written in big- or little-endian byte +order: + + drwav_read_pcm_frames_le() + drwav_read_pcm_frames_be() + drwav_read_pcm_frames_s16le() + drwav_read_pcm_frames_s16be() + drwav_read_pcm_frames_f32le() + drwav_read_pcm_frames_f32be() + drwav_read_pcm_frames_s32le() + drwav_read_pcm_frames_s32be() + drwav_write_pcm_frames_le() + drwav_write_pcm_frames_be() + +Removed APIs +------------ +The following APIs were deprecated in version 0.10.0 and have now been removed: + + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + + + +RELEASE NOTES - v0.10.0 +======================= +Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do +not need to upgrade. + +Removed APIs +------------ +The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0: + + drwav_read() + drwav_read_s16() + drwav_read_f32() + drwav_read_s32() + drwav_seek_to_sample() + drwav_write() + drwav_open_and_read_s16() + drwav_open_and_read_f32() + drwav_open_and_read_s32() + drwav_open_file_and_read_s16() + drwav_open_file_and_read_f32() + drwav_open_file_and_read_s32() + drwav_open_memory_and_read_s16() + drwav_open_memory_and_read_f32() + drwav_open_memory_and_read_s32() + drwav::totalSampleCount + +See release notes for version 0.9.0 at the bottom of this file for replacement APIs. + +Deprecated APIs +--------------- +The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and +drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a +drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre- +allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by +a called to one of the drwav_init*() APIs. + + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + +These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the +two different ways to initialize a drwav object. +*/ + /* REVISION HISTORY ================ -v0.13.16 - 2024-02-27 - - Fix a Wdouble-promotion warning. - -v0.13.15 - 2024-01-23 - - Relax some unnecessary validation that prevented some files from loading. - -v0.13.14 - 2023-12-02 - - Fix a warning about an unused variable. - -v0.13.13 - 2023-11-02 - - Fix a warning when compiling with Clang. - -v0.13.12 - 2023-08-07 - - Fix a possible crash in drwav_read_pcm_frames(). - -v0.13.11 - 2023-07-07 - - AIFF compatibility improvements. - -v0.13.10 - 2023-05-29 - - Fix a bug where drwav_init_with_metadata() does not decode any frames after initializtion. - -v0.13.9 - 2023-05-22 - - Add support for AIFF decoding (writing and metadata not supported). - - Add support for RIFX decoding (writing and metadata not supported). - - Fix a bug where metadata is not processed if it's located before the "fmt " chunk. - - Add a workaround for a type of malformed WAV file where the size of the "RIFF" and "data" chunks - are incorrectly set to 0xFFFFFFFF. - -v0.13.8 - 2023-03-25 - - Fix a possible null pointer dereference. - - Fix a crash when loading files with badly formed metadata. - -v0.13.7 - 2022-09-17 - - Fix compilation with DJGPP. - - Add support for disabling wchar_t with DR_WAV_NO_WCHAR. - -v0.13.6 - 2022-04-10 - - Fix compilation error on older versions of GCC. - - Remove some dependencies on the standard library. - -v0.13.5 - 2022-01-26 - - Fix an error when seeking to the end of the file. - -v0.13.4 - 2021-12-08 - - Fix some static analysis warnings. - -v0.13.3 - 2021-11-24 - - Fix an incorrect assertion when trying to endian swap 1-byte sample formats. This is now a no-op - rather than a failed assertion. - - Fix a bug with parsing of the bext chunk. - - Fix some static analysis warnings. - -v0.13.2 - 2021-10-02 - - Fix a possible buffer overflow when reading from compressed formats. - -v0.13.1 - 2021-07-31 - - Fix platform detection for ARM64. - -v0.13.0 - 2021-07-01 - - Improve support for reading and writing metadata. Use the `_with_metadata()` APIs to initialize - a WAV decoder and store the metadata within the `drwav` object. Use the `pMetadata` and - `metadataCount` members of the `drwav` object to read the data. The old way of handling metadata - via a callback is still usable and valid. - - API CHANGE: drwav_target_write_size_bytes() now takes extra parameters for calculating the - required write size when writing metadata. - - Add drwav_get_cursor_in_pcm_frames() - - Add drwav_get_length_in_pcm_frames() - - Fix a bug where drwav_read_raw() can call the read callback with a byte count of zero. - -v0.12.20 - 2021-06-11 - - Fix some undefined behavior. - v0.12.19 - 2021-02-21 - Fix a warning due to referencing _MSC_VER when it is undefined. - Minor improvements to the management of some internal state concerning the data chunk cursor. @@ -8796,7 +6388,7 @@ For more information, please refer to =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== -Copyright 2023 David Reid +Copyright 2020 David Reid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/raylib/external/glad.h b/raylib/external/glad.h index 5bb79d4..c92e184 100644 --- a/raylib/external/glad.h +++ b/raylib/external/glad.h @@ -1,300 +1,621 @@ -/** - * Loader generated by glad 2.0.0-beta on Sun Sep 18 18:12:12 2022 - * - * Generator: C/C++ - * Specification: gl - * Extensions: 116 - * - * APIs: - * - gl:core=4.3 - * - * Options: - * - ALIAS = False - * - DEBUG = False - * - HEADER_ONLY = True - * - LOADER = False - * - MX = False - * - MX_GLOBAL = False - * - ON_DEMAND = False - * - * Commandline: - * --api='gl:core=4.3' --extensions='GL_ARB_ES2_compatibility,GL_ARB_ES3_1_compatibility,GL_ARB_ES3_2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_blend_func_extended,GL_ARB_buffer_storage,GL_ARB_clear_buffer_object,GL_ARB_clear_texture,GL_ARB_color_buffer_float,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_compute_shader,GL_ARB_compute_variable_group_size,GL_ARB_copy_buffer,GL_ARB_copy_image,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_direct_state_access,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_draw_elements_base_vertex,GL_ARB_draw_indirect,GL_ARB_draw_instanced,GL_ARB_enhanced_layouts,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_coord_conventions,GL_ARB_fragment_layer_viewport,GL_ARB_fragment_program,GL_ARB_fragment_program_shadow,GL_ARB_fragment_shader,GL_ARB_fragment_shader_interlock,GL_ARB_framebuffer_no_attachments,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_geometry_shader4,GL_ARB_get_program_binary,GL_ARB_get_texture_sub_image,GL_ARB_gl_spirv,GL_ARB_gpu_shader5,GL_ARB_gpu_shader_fp64,GL_ARB_gpu_shader_int64,GL_ARB_half_float_pixel,GL_ARB_half_float_vertex,GL_ARB_instanced_arrays,GL_ARB_internalformat_query,GL_ARB_internalformat_query2,GL_ARB_map_buffer_range,GL_ARB_multi_bind,GL_ARB_multi_draw_indirect,GL_ARB_multisample,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_occlusion_query2,GL_ARB_pipeline_statistics_query,GL_ARB_query_buffer_object,GL_ARB_sample_locations,GL_ARB_sample_shading,GL_ARB_seamless_cube_map,GL_ARB_seamless_cubemap_per_texture,GL_ARB_shader_atomic_counter_ops,GL_ARB_shader_atomic_counters,GL_ARB_shader_bit_encoding,GL_ARB_shader_clock,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_storage_buffer_object,GL_ARB_shader_texture_lod,GL_ARB_shading_language_100,GL_ARB_shading_language_420pack,GL_ARB_shading_language_include,GL_ARB_shading_language_packing,GL_ARB_spirv_extensions,GL_ARB_tessellation_shader,GL_ARB_texture_border_clamp,GL_ARB_texture_buffer_object_rgb32,GL_ARB_texture_compression,GL_ARB_texture_cube_map,GL_ARB_texture_cube_map_array,GL_ARB_texture_env_add,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_filter_minmax,GL_ARB_texture_float,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_texture_mirrored_repeat,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_rg,GL_ARB_texture_storage,GL_ARB_texture_swizzle,GL_ARB_texture_view,GL_ARB_timer_query,GL_ARB_transpose_matrix,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_bgra,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_EXT_draw_instanced,GL_EXT_fog_coord,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_mirror_clamp,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_OES_compressed_paletted_texture,GL_OES_fixed_point' c --header-only - * - * Online: - * http://glad.sh/#api=gl%3Acore%3D4.3&generator=c&options=HEADER_ONLY - * - */ +/* -#ifndef GLAD_GL_H_ -#define GLAD_GL_H_ + OpenGL loader generated by glad 0.1.10a0 on Fri Jun 10 12:54:12 2016. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.3 + Profile: core + Extensions: + GL_AMD_debug_output, GL_AMD_query_buffer_object, GL_ARB_ES2_compatibility, GL_ARB_ES3_compatibility, GL_ARB_buffer_storage, GL_ARB_compatibility, GL_ARB_compressed_texture_pixel_storage, GL_ARB_debug_output, GL_ARB_depth_buffer_float, GL_ARB_depth_clamp, GL_ARB_depth_texture, GL_ARB_draw_buffers, GL_ARB_draw_buffers_blend, GL_ARB_explicit_attrib_location, GL_ARB_explicit_uniform_location, GL_ARB_fragment_program, GL_ARB_fragment_shader, GL_ARB_framebuffer_object, GL_ARB_framebuffer_sRGB, GL_ARB_multisample, GL_ARB_sample_locations, GL_ARB_texture_compression, GL_ARB_texture_float, GL_ARB_texture_multisample, GL_ARB_texture_non_power_of_two, GL_ARB_texture_rg, GL_ARB_texture_swizzle, GL_ARB_uniform_buffer_object, GL_ARB_vertex_array_object, GL_ARB_vertex_attrib_binding, GL_ARB_vertex_buffer_object, GL_ARB_vertex_program, GL_ARB_vertex_shader, GL_ATI_element_array, GL_ATI_fragment_shader, GL_ATI_vertex_array_object, GL_EXT_blend_color, GL_EXT_blend_equation_separate, GL_EXT_blend_func_separate, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, GL_EXT_framebuffer_multisample_blit_scaled, GL_EXT_framebuffer_object, GL_EXT_framebuffer_sRGB, GL_EXT_index_array_formats, GL_EXT_texture, GL_EXT_texture_compression_s3tc, GL_EXT_texture_sRGB, GL_EXT_texture_swizzle, GL_EXT_vertex_array, GL_EXT_vertex_shader + Loader: No + + Commandline: + --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --extensions="GL_AMD_debug_output,GL_AMD_query_buffer_object,GL_ARB_ES2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_buffer_storage,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_program,GL_ARB_fragment_shader,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_multisample,GL_ARB_sample_locations,GL_ARB_texture_compression,GL_ARB_texture_float,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_rg,GL_ARB_texture_swizzle,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ATI_element_array,GL_ATI_fragment_shader,GL_ATI_vertex_array_object,GL_EXT_blend_color,GL_EXT_blend_equation_separate,GL_EXT_blend_func_separate,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_index_array_formats,GL_EXT_texture,GL_EXT_texture_compression_s3tc,GL_EXT_texture_sRGB,GL_EXT_texture_swizzle,GL_EXT_vertex_array,GL_EXT_vertex_shader" + Online: + http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&extensions=GL_AMD_debug_output&extensions=GL_AMD_query_buffer_object&extensions=GL_ARB_ES2_compatibility&extensions=GL_ARB_ES3_compatibility&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_compatibility&extensions=GL_ARB_compressed_texture_pixel_storage&extensions=GL_ARB_debug_output&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_depth_texture&extensions=GL_ARB_draw_buffers&extensions=GL_ARB_draw_buffers_blend&extensions=GL_ARB_explicit_attrib_location&extensions=GL_ARB_explicit_uniform_location&extensions=GL_ARB_fragment_program&extensions=GL_ARB_fragment_shader&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_framebuffer_sRGB&extensions=GL_ARB_multisample&extensions=GL_ARB_sample_locations&extensions=GL_ARB_texture_compression&extensions=GL_ARB_texture_float&extensions=GL_ARB_texture_multisample&extensions=GL_ARB_texture_non_power_of_two&extensions=GL_ARB_texture_rg&extensions=GL_ARB_texture_swizzle&extensions=GL_ARB_uniform_buffer_object&extensions=GL_ARB_vertex_array_object&extensions=GL_ARB_vertex_attrib_binding&extensions=GL_ARB_vertex_buffer_object&extensions=GL_ARB_vertex_program&extensions=GL_ARB_vertex_shader&extensions=GL_ATI_element_array&extensions=GL_ATI_fragment_shader&extensions=GL_ATI_vertex_array_object&extensions=GL_EXT_blend_color&extensions=GL_EXT_blend_equation_separate&extensions=GL_EXT_blend_func_separate&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_multisample_blit_scaled&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_framebuffer_sRGB&extensions=GL_EXT_index_array_formats&extensions=GL_EXT_texture&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_sRGB&extensions=GL_EXT_texture_swizzle&extensions=GL_EXT_vertex_array&extensions=GL_EXT_vertex_shader +*/ + + +#ifndef __glad_h_ +#define __glad_h_ -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-id-macro" -#endif #ifdef __gl_h_ - #error OpenGL (gl.h) header already included (API: gl), remove previous include! +#error OpenGL header already included, remove this include, glad already provides it #endif -#define __gl_h_ 1 -#ifdef __gl3_h_ - #error OpenGL (gl3.h) header already included (API: gl), remove previous include! +#define __gl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 #endif -#define __gl3_h_ 1 -#ifdef __glext_h_ - #error OpenGL (glext.h) header already included (API: gl), remove previous include! -#endif -#define __glext_h_ 1 -#ifdef __gl3ext_h_ - #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include! -#endif -#define __gl3ext_h_ 1 -#ifdef __clang__ -#pragma clang diagnostic pop +//#include +#define APIENTRY __stdcall // RAY: Added #endif -#define GLAD_GL -#define GLAD_OPTION_GL_HEADER_ONLY +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +// RAY: Added +#ifndef GLAD_REALLOC + #define GLAD_REALLOC(n,sz) realloc(n,sz) +#endif +#ifndef GLAD_FREE + #define GLAD_FREE(p) free(p) +#endif #ifdef __cplusplus extern "C" { #endif -#ifndef GLAD_PLATFORM_H_ -#define GLAD_PLATFORM_H_ +struct gladGLversionStruct { + int major; + int minor; +}; -#ifndef GLAD_PLATFORM_WIN32 - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) - #define GLAD_PLATFORM_WIN32 1 - #else - #define GLAD_PLATFORM_WIN32 0 - #endif -#endif - -#ifndef GLAD_PLATFORM_APPLE - #ifdef __APPLE__ - #define GLAD_PLATFORM_APPLE 1 - #else - #define GLAD_PLATFORM_APPLE 0 - #endif -#endif - -#ifndef GLAD_PLATFORM_EMSCRIPTEN - #ifdef __EMSCRIPTEN__ - #define GLAD_PLATFORM_EMSCRIPTEN 1 - #else - #define GLAD_PLATFORM_EMSCRIPTEN 0 - #endif -#endif - -#ifndef GLAD_PLATFORM_UWP - #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) - #ifdef __has_include - #if __has_include() - #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 - #endif - #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ - #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 - #endif - #endif - - #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY - #include - #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - #define GLAD_PLATFORM_UWP 1 - #endif - #endif - - #ifndef GLAD_PLATFORM_UWP - #define GLAD_PLATFORM_UWP 0 - #endif -#endif - -#ifdef __GNUC__ - #define GLAD_GNUC_EXTENSION __extension__ -#else - #define GLAD_GNUC_EXTENSION -#endif - -#ifndef GLAD_API_CALL - #if defined(GLAD_API_CALL_EXPORT) - #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) - #if defined(GLAD_API_CALL_EXPORT_BUILD) - #if defined(__GNUC__) - #define GLAD_API_CALL __attribute__ ((dllexport)) extern - #else - #define GLAD_API_CALL __declspec(dllexport) extern - #endif - #else - #if defined(__GNUC__) - #define GLAD_API_CALL __attribute__ ((dllimport)) extern - #else - #define GLAD_API_CALL __declspec(dllimport) extern - #endif - #endif - #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) - #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern - #else - #define GLAD_API_CALL extern - #endif - #else - #define GLAD_API_CALL extern - #endif -#endif - -#ifdef APIENTRY - #define GLAD_API_PTR APIENTRY -#elif GLAD_PLATFORM_WIN32 - #define GLAD_API_PTR __stdcall -#else - #define GLAD_API_PTR -#endif +typedef void* (* GLADloadproc)(const char *name); #ifndef GLAPI -#define GLAPI GLAD_API_CALL +# if defined(GLAD_GLAPI_EXPORT) +# if defined(WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif #endif -#ifndef GLAPIENTRY -#define GLAPIENTRY GLAD_API_PTR +GLAPI struct gladGLversionStruct GLVersion; +GLAPI int gladLoadGLLoader(GLADloadproc); + +#include +//#include // RAY: Not required +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include #endif - -#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) -#define GLAD_VERSION_MAJOR(version) (version / 10000) -#define GLAD_VERSION_MINOR(version) (version % 10000) - -#define GLAD_GENERATOR_VERSION "2.0.0-beta" - -typedef void (*GLADapiproc)(void); - -typedef GLADapiproc (*GLADloadfunc)(const char *name); -typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); - -typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); -typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); - -#endif /* GLAD_PLATFORM_H_ */ - -#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_ACTIVE_PROGRAM 0x8259 -#define GL_ACTIVE_RESOURCES 0x92F5 -#define GL_ACTIVE_SUBROUTINES 0x8DE5 -#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 -#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_ACTIVE_TEXTURE_ARB 0x84E0 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_ACTIVE_VARIABLES 0x9305 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_ALL_BARRIER_BITS 0xFFFFFFFF -#define GL_ALL_SHADER_BITS 0xFFFFFFFF -#define GL_ALPHA 0x1906 -#define GL_ALPHA16F_ARB 0x881C -#define GL_ALPHA32F_ARB 0x8816 -#define GL_ALREADY_SIGNALED 0x911A +#endif +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLclampx; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef unsigned short GLhalfARB; +typedef unsigned short GLhalf; +typedef GLint GLfixed; +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; +typedef int64_t GLint64; +typedef uint64_t GLuint64; +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 -#define GL_AND 0x1501 -#define GL_AND_INVERTED 0x1504 -#define GL_AND_REVERSE 0x1502 -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ARRAY_BUFFER_ARB 0x8892 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 -#define GL_ARRAY_SIZE 0x92FB -#define GL_ARRAY_STRIDE 0x92FE -#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 -#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 -#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 -#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 -#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 -#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 -#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_AUTO_GENERATE_MIPMAP 0x8295 -#define GL_BACK 0x0405 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 #define GL_BACK_LEFT 0x0402 #define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_REPEAT 0x2901 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 -#define GL_BGRA_INTEGER 0x8D9B -#define GL_BGR_INTEGER 0x8D9A -#define GL_BLEND 0x0BE2 -#define GL_BLEND_COLOR 0x8005 -#define GL_BLEND_DST 0x0BE0 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_EQUATION 0x8009 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_BLEND_SRC 0x0BE1 -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLOCK_INDEX 0x92FD -#define GL_BLUE 0x1905 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_BOOL 0x8B56 -#define GL_BOOL_ARB 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC2_ARB 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC3_ARB 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_BOOL_VEC4_ARB 0x8B59 -#define GL_BUFFER 0x82E0 -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_ACCESS_ARB 0x88BB -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_BINDING 0x9302 -#define GL_BUFFER_DATA_SIZE 0x9303 -#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAPPED_ARB 0x88BC -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_BUFFER_MAP_POINTER_ARB 0x88BD -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_SIZE_ARB 0x8764 -#define GL_BUFFER_STORAGE_FLAGS 0x8220 -#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 -#define GL_BUFFER_USAGE 0x8765 -#define GL_BUFFER_USAGE_ARB 0x8765 -#define GL_BUFFER_VARIABLE 0x92E5 -#define GL_BYTE 0x1400 -#define GL_CAVEAT_SUPPORT 0x82B8 -#define GL_CCW 0x0901 -#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_CLAMP_READ_COLOR_ARB 0x891C -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_CLAMP_TO_BORDER_ARB 0x812D +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F -#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A -#define GL_CLEAR 0x1500 -#define GL_CLEAR_BUFFER 0x82B4 -#define GL_CLEAR_TEXTURE 0x9365 -#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 -#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 -#define GL_CLIENT_STORAGE_BIT 0x0200 -#define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6 -#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 -#define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7 -#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7 +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 @@ -303,29 +624,162 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 -#define GL_COLOR 0x1800 -#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 -#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 @@ -336,576 +790,1536 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD -#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF -#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_COMPONENTS 0x8283 -#define GL_COLOR_ENCODING 0x8296 -#define GL_COLOR_LOGIC_OP 0x0BF2 -#define GL_COLOR_RENDERABLE 0x8286 -#define GL_COLOR_SUM_ARB 0x8458 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_COMMAND_BARRIER_BIT 0x00000040 -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_COMPATIBLE_SUBROUTINES 0x8E4B -#define GL_COMPILE_STATUS 0x8B81 -#define GL_COMPRESSED_ALPHA_ARB 0x84E9 -#define GL_COMPRESSED_INTENSITY_ARB 0x84EC -#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB -#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA -#define GL_COMPRESSED_R11_EAC 0x9270 -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_RG 0x8226 -#define GL_COMPRESSED_RG11_EAC 0x9272 -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGB8_ETC2 0x9274 -#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 -#define GL_COMPRESSED_RGBA_ARB 0x84EE -#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB -#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 -#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 -#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA -#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC -#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD -#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 -#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 -#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 -#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 -#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 -#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 -#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 -#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 -#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#define GL_COMPRESSED_RGB_ARB 0x84ED -#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E -#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 -#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 -#define GL_COMPRESSED_SRGB8_ETC2 0x9275 -#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -#define GL_COMPUTE_SHADER 0x91B9 -#define GL_COMPUTE_SHADER_BIT 0x00000020 -#define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5 -#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5 -#define GL_COMPUTE_SUBROUTINE 0x92ED -#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 -#define GL_COMPUTE_TEXTURE 0x82A0 -#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 -#define GL_CONDITION_SATISFIED 0x911C -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_FLAGS 0x821E -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_COPY 0x1503 -#define GL_COPY_INVERTED 0x150C -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_READ_BUFFER_BINDING 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 -#define GL_CURRENT_MATRIX_ARB 0x8641 -#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_CURRENT_QUERY 0x8865 -#define GL_CURRENT_QUERY_ARB 0x8865 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 -#define GL_CW 0x0900 -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define GL_DEBUG_OUTPUT 0x92E0 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#define GL_DEBUG_SOURCE_API 0x8246 -#define GL_DEBUG_SOURCE_API_ARB 0x8246 -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define GL_DEBUG_SOURCE_OTHER 0x824B -#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define GL_DEBUG_TYPE_ERROR 0x824C -#define GL_DEBUG_TYPE_ERROR_ARB 0x824C -#define GL_DEBUG_TYPE_MARKER 0x8268 -#define GL_DEBUG_TYPE_OTHER 0x8251 -#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define GL_DECR 0x1E03 -#define GL_DECR_WRAP 0x8508 -#define GL_DELETE_STATUS 0x8B80 -#define GL_DEPTH 0x1801 -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_DEPTH_CLAMP 0x864F -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT16_ARB 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT24_ARB 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH_COMPONENT32_ARB 0x81A7 -#define GL_DEPTH_COMPONENTS 0x8284 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_RENDERABLE 0x8287 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE -#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF -#define GL_DITHER 0x0BD0 -#define GL_DONT_CARE 0x1100 -#define GL_DOUBLE 0x140A -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_DOUBLE_MAT2 0x8F46 -#define GL_DOUBLE_MAT2x3 0x8F49 -#define GL_DOUBLE_MAT2x4 0x8F4A -#define GL_DOUBLE_MAT3 0x8F47 -#define GL_DOUBLE_MAT3x2 0x8F4B -#define GL_DOUBLE_MAT3x4 0x8F4C -#define GL_DOUBLE_MAT4 0x8F48 -#define GL_DOUBLE_MAT4x2 0x8F4D -#define GL_DOUBLE_MAT4x3 0x8F4E -#define GL_DOUBLE_VEC2 0x8FFC -#define GL_DOUBLE_VEC3 0x8FFD -#define GL_DOUBLE_VEC4 0x8FFE -#define GL_DRAW_BUFFER 0x0C01 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER0_ARB 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER10_ARB 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER11_ARB 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER12_ARB 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER13_ARB 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER14_ARB 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_DRAW_BUFFER15_ARB 0x8834 -#define GL_DRAW_BUFFER1_ARB 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER2_ARB 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER3_ARB 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER4_ARB 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER5_ARB 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER6_ARB 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER7_ARB 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER8_ARB 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER9_ARB 0x882E -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#define GL_DRAW_INDIRECT_BUFFER 0x8F3F -#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 -#define GL_DST_ALPHA 0x0304 -#define GL_DST_COLOR 0x0306 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_DYNAMIC_COPY_ARB 0x88EA -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_DRAW_ARB 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_READ_ARB 0x88E9 -#define GL_DYNAMIC_STORAGE_BIT 0x0100 -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B -#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 -#define GL_EQUAL 0x0202 -#define GL_EQUIV 0x1509 -#define GL_EXTENSIONS 0x1F03 -#define GL_FALSE 0 -#define GL_FASTEST 0x1101 -#define GL_FILL 0x1B02 -#define GL_FILTER 0x829A -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_FIXED 0x140C -#define GL_FIXED_OES 0x140C -#define GL_FIXED_ONLY 0x891D -#define GL_FIXED_ONLY_ARB 0x891D -#define GL_FLOAT 0x1406 -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT2_ARB 0x8B5A -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT3_ARB 0x8B5B -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4 0x8B5C -#define GL_FLOAT_MAT4_ARB 0x8B5C -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC2_ARB 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC3_ARB 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_FLOAT_VEC4_ARB 0x8B52 -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D -#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 -#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 -#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 -#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 -#define GL_FOG_COORDINATE_EXT 0x8451 -#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 -#define GL_FRACTIONAL_EVEN 0x8E7C -#define GL_FRACTIONAL_ODD 0x8E7B -#define GL_FRAGMENT_DEPTH_EXT 0x8452 -#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D -#define GL_FRAGMENT_PROGRAM_ARB 0x8804 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_FRAGMENT_SHADER_ARB 0x8B30 -#define GL_FRAGMENT_SHADER_BIT 0x00000002 -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B -#define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4 -#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4 -#define GL_FRAGMENT_SUBROUTINE 0x92EC -#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 -#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_FRAMEBUFFER 0x8D40 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 -#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_FRAMEBUFFER_BLEND 0x828B -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 -#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 -#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 -#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 -#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 -#define GL_FRAMEBUFFER_EXT 0x8D40 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC -#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342 -#define GL_FRAMEBUFFER_RENDERABLE 0x8289 -#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A -#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 #define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD -#define GL_FRONT 0x0404 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_FRONT_FACE 0x0B46 -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_FULL_SUPPORT 0x82B7 -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_FUNC_SUBTRACT 0x800A -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_SHADER_ARB 0x8DD9 -#define GL_GEOMETRY_SHADER_BIT 0x00000004 -#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F -#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3 -#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3 -#define GL_GEOMETRY_SUBROUTINE 0x92EB -#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 -#define GL_GEOMETRY_TEXTURE 0x829E -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA -#define GL_GEQUAL 0x0206 -#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 -#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 -#define GL_GREATER 0x0204 -#define GL_GREEN 0x1904 -#define GL_GREEN_INTEGER 0x8D95 #define GL_HALF_FLOAT 0x140B -#define GL_HALF_FLOAT_ARB 0x140B -#define GL_HIGH_FLOAT 0x8DF2 -#define GL_HIGH_INT 0x8DF5 -#define GL_IMAGE_1D 0x904C -#define GL_IMAGE_1D_ARRAY 0x9052 -#define GL_IMAGE_2D 0x904D -#define GL_IMAGE_2D_ARRAY 0x9053 -#define GL_IMAGE_2D_MULTISAMPLE 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 -#define GL_IMAGE_2D_RECT 0x904F -#define GL_IMAGE_3D 0x904E -#define GL_IMAGE_BINDING_ACCESS 0x8F3E -#define GL_IMAGE_BINDING_FORMAT 0x906E -#define GL_IMAGE_BINDING_LAYER 0x8F3D -#define GL_IMAGE_BINDING_LAYERED 0x8F3C -#define GL_IMAGE_BINDING_LEVEL 0x8F3B -#define GL_IMAGE_BINDING_NAME 0x8F3A -#define GL_IMAGE_BUFFER 0x9051 -#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 -#define GL_IMAGE_CLASS_11_11_10 0x82C2 -#define GL_IMAGE_CLASS_1_X_16 0x82BE -#define GL_IMAGE_CLASS_1_X_32 0x82BB -#define GL_IMAGE_CLASS_1_X_8 0x82C1 -#define GL_IMAGE_CLASS_2_X_16 0x82BD -#define GL_IMAGE_CLASS_2_X_32 0x82BA -#define GL_IMAGE_CLASS_2_X_8 0x82C0 -#define GL_IMAGE_CLASS_4_X_16 0x82BC -#define GL_IMAGE_CLASS_4_X_32 0x82B9 -#define GL_IMAGE_CLASS_4_X_8 0x82BF -#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 -#define GL_IMAGE_CUBE 0x9050 -#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 -#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 -#define GL_IMAGE_PIXEL_FORMAT 0x82A9 -#define GL_IMAGE_PIXEL_TYPE 0x82AA -#define GL_IMAGE_TEXEL_SIZE 0x82A7 -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A -#define GL_INCR 0x1E02 -#define GL_INCR_WRAP 0x8507 -#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_INT 0x1404 -#define GL_INT64_ARB 0x140E -#define GL_INT64_VEC2_ARB 0x8FE9 -#define GL_INT64_VEC3_ARB 0x8FEA -#define GL_INT64_VEC4_ARB 0x8FEB -#define GL_INTENSITY16F_ARB 0x881D -#define GL_INTENSITY32F_ARB 0x8817 -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 -#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B -#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 -#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A -#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 -#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C -#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 -#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 -#define GL_INTERNALFORMAT_PREFERRED 0x8270 -#define GL_INTERNALFORMAT_RED_SIZE 0x8271 -#define GL_INTERNALFORMAT_RED_TYPE 0x8278 -#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 -#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 -#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D -#define GL_INTERNALFORMAT_SUPPORTED 0x826F -#define GL_INT_2_10_10_10_REV 0x8D9F -#define GL_INT_IMAGE_1D 0x9057 -#define GL_INT_IMAGE_1D_ARRAY 0x905D -#define GL_INT_IMAGE_2D 0x9058 -#define GL_INT_IMAGE_2D_ARRAY 0x905E -#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 -#define GL_INT_IMAGE_2D_RECT 0x905A -#define GL_INT_IMAGE_3D 0x9059 -#define GL_INT_IMAGE_BUFFER 0x905C -#define GL_INT_IMAGE_CUBE 0x905B -#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC2_ARB 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC3_ARB 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_INT_VEC4_ARB 0x8B55 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 -#define GL_INVALID_INDEX 0xFFFFFFFF -#define GL_INVALID_OPERATION 0x0502 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVERT 0x150A -#define GL_ISOLINES 0x8E7A -#define GL_IS_PER_PATCH 0x92E7 -#define GL_IS_ROW_MAJOR 0x9300 -#define GL_KEEP 0x1E00 -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_LAYER_PROVOKING_VERTEX 0x825E -#define GL_LEFT 0x0406 -#define GL_LEQUAL 0x0203 -#define GL_LESS 0x0201 -#define GL_LINE 0x1B01 -#define GL_LINEAR 0x2601 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_LINES 0x0001 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINES_ADJACENCY_ARB 0x000A -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_SMOOTH 0x0B20 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_LINE_STRIP 0x0003 -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_LINE_WIDTH_RANGE 0x0B22 -#define GL_LINK_STATUS 0x8B82 -#define GL_LOCATION 0x930E -#define GL_LOCATION_COMPONENT 0x934A -#define GL_LOCATION_INDEX 0x930F -#define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_LOW_FLOAT 0x8DF0 -#define GL_LOW_INT 0x8DF3 -#define GL_LUMINANCE16F_ARB 0x881E -#define GL_LUMINANCE32F_ARB 0x8818 -#define GL_LUMINANCE_ALPHA16F_ARB 0x881F -#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 -#define GL_MAJOR_VERSION 0x821B -#define GL_MANUAL_GENERATE_MIPMAP 0x8294 -#define GL_MAP_COHERENT_BIT 0x0080 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_PERSISTENT_BIT 0x0040 #define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat* params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint* params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean* data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble* data); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat* data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint* data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat* params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat* params); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble near, GLdouble far); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint* textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint* textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void* img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei* count, GLenum type, const void** indices, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat* params); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint* params); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint* ids); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint* ids); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint* params); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint* params); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint* buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint* buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void* data); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void* (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void** params); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum* bufs); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar* name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint* params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint* params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat* params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint* params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble* params); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat* params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint* params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void** pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean* data); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint* data); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar** varyings, GLenum bufferMode); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint* params); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint* params); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint* params); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar* name); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint* params); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint* params); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint* params); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint* value); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint* value); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat* value); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint* renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint* framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint* params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint* arrays); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +GLAPI int GLAD_GL_VERSION_3_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount); +GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar** uniformNames, GLuint* uniformIndices); +GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName); +GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar* uniformBlockName); +GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +#endif +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +GLAPI int GLAD_GL_VERSION_3_2; +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices, GLint basevertex); +GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei* count, GLenum type, const void** indices, GLsizei drawcount, const GLint* basevertex); +GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64* data); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64* data); +GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64* params); +GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat* val); +GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +#endif +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +GLAPI int GLAD_GL_VERSION_3_3; +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar* name); +GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; +#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; +#define glGetFragDataIndex glad_glGetFragDataIndex +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint* samplers); +GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers; +#define glGenSamplers glad_glGenSamplers +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint* samplers); +GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; +#define glDeleteSamplers glad_glDeleteSamplers +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); +GLAPI PFNGLISSAMPLERPROC glad_glIsSampler; +#define glIsSampler glad_glIsSampler +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); +GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler; +#define glBindSampler glad_glBindSampler +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); +GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; +#define glSamplerParameteri glad_glSamplerParameteri +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint* param); +GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; +#define glSamplerParameteriv glad_glSamplerParameteriv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); +GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; +#define glSamplerParameterf glad_glSamplerParameterf +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat* param); +GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; +#define glSamplerParameterfv glad_glSamplerParameterfv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint* param); +GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; +#define glSamplerParameterIiv glad_glSamplerParameterIiv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint* param); +GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; +#define glSamplerParameterIuiv glad_glSamplerParameterIuiv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint* params); +GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; +#define glGetSamplerParameteriv glad_glGetSamplerParameteriv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint* params); +GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; +#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat* params); +GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; +#define glGetSamplerParameterfv glad_glGetSamplerParameterfv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint* params); +GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; +#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); +GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter; +#define glQueryCounter glad_glQueryCounter +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64* params); +GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; +#define glGetQueryObjecti64v glad_glGetQueryObjecti64v +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64* params); +GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; +#define glGetQueryObjectui64v glad_glGetQueryObjectui64v +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); +GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; +#define glVertexAttribDivisor glad_glVertexAttribDivisor +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; +#define glVertexAttribP1ui glad_glVertexAttribP1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; +#define glVertexAttribP1uiv glad_glVertexAttribP1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; +#define glVertexAttribP2ui glad_glVertexAttribP2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; +#define glVertexAttribP2uiv glad_glVertexAttribP2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; +#define glVertexAttribP3ui glad_glVertexAttribP3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; +#define glVertexAttribP3uiv glad_glVertexAttribP3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; +#define glVertexAttribP4ui glad_glVertexAttribP4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; +#define glVertexAttribP4uiv glad_glVertexAttribP4uiv +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui; +#define glVertexP2ui glad_glVertexP2ui +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint* value); +GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; +#define glVertexP2uiv glad_glVertexP2uiv +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui; +#define glVertexP3ui glad_glVertexP3ui +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint* value); +GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; +#define glVertexP3uiv glad_glVertexP3uiv +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui; +#define glVertexP4ui glad_glVertexP4ui +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint* value); +GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; +#define glVertexP4uiv glad_glVertexP4uiv +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; +#define glTexCoordP1ui glad_glTexCoordP1ui +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint* coords); +GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; +#define glTexCoordP1uiv glad_glTexCoordP1uiv +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; +#define glTexCoordP2ui glad_glTexCoordP2ui +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint* coords); +GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; +#define glTexCoordP2uiv glad_glTexCoordP2uiv +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; +#define glTexCoordP3ui glad_glTexCoordP3ui +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint* coords); +GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; +#define glTexCoordP3uiv glad_glTexCoordP3uiv +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; +#define glTexCoordP4ui glad_glTexCoordP4ui +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint* coords); +GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; +#define glTexCoordP4uiv glad_glTexCoordP4uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; +#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint* coords); +GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; +#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; +#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint* coords); +GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; +#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; +#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint* coords); +GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; +#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; +#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint* coords); +GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; +#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv +typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui; +#define glNormalP3ui glad_glNormalP3ui +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint* coords); +GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; +#define glNormalP3uiv glad_glNormalP3uiv +typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui; +#define glColorP3ui glad_glColorP3ui +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint* color); +GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv; +#define glColorP3uiv glad_glColorP3uiv +typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui; +#define glColorP4ui glad_glColorP4ui +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint* color); +GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv; +#define glColorP4uiv glad_glColorP4uiv +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; +#define glSecondaryColorP3ui glad_glSecondaryColorP3ui +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint* color); +GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; +#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv +#endif +#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 +#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 +#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 +#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A +#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B +#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C +#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D +#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E +#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F +#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 +#define GL_QUERY_BUFFER_AMD 0x9192 +#define GL_QUERY_BUFFER_BINDING_AMD 0x9193 +#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15_ARB 0x8834 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_LENGTH_ARB 0x8627 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_BINDING_ARB 0x8677 +#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_CURRENT_MATRIX_ARB 0x8641 +#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 #define GL_MATRIX0_ARB 0x88C0 +#define GL_MATRIX1_ARB 0x88C1 +#define GL_MATRIX2_ARB 0x88C2 +#define GL_MATRIX3_ARB 0x88C3 +#define GL_MATRIX4_ARB 0x88C4 +#define GL_MATRIX5_ARB 0x88C5 +#define GL_MATRIX6_ARB 0x88C6 +#define GL_MATRIX7_ARB 0x88C7 +#define GL_MATRIX8_ARB 0x88C8 +#define GL_MATRIX9_ARB 0x88C9 #define GL_MATRIX10_ARB 0x88CA #define GL_MATRIX11_ARB 0x88CB #define GL_MATRIX12_ARB 0x88CC @@ -916,7 +2330,6 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_MATRIX17_ARB 0x88D1 #define GL_MATRIX18_ARB 0x88D2 #define GL_MATRIX19_ARB 0x88D3 -#define GL_MATRIX1_ARB 0x88C1 #define GL_MATRIX20_ARB 0x88D4 #define GL_MATRIX21_ARB 0x88D5 #define GL_MATRIX22_ARB 0x88D6 @@ -927,7441 +2340,1460 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_MATRIX27_ARB 0x88DB #define GL_MATRIX28_ARB 0x88DC #define GL_MATRIX29_ARB 0x88DD -#define GL_MATRIX2_ARB 0x88C2 #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF -#define GL_MATRIX3_ARB 0x88C3 -#define GL_MATRIX4_ARB 0x88C4 -#define GL_MATRIX5_ARB 0x88C5 -#define GL_MATRIX6_ARB 0x88C6 -#define GL_MATRIX7_ARB 0x88C7 -#define GL_MATRIX8_ARB 0x88C8 -#define GL_MATRIX9_ARB 0x88C9 -#define GL_MATRIX_STRIDE 0x92FF -#define GL_MAX 0x8008 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC -#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 -#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 -#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 -#define GL_MAX_COMBINED_DIMENSIONS 0x8282 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 -#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 -#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC -#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E -#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 -#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 -#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB -#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF -#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD -#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB -#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 -#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC -#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB -#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 -#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 -#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 -#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE -#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB -#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define GL_MAX_DEPTH 0x8280 -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENT_INDEX 0x8D6B -#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 -#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 -#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C -#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_FRAGMENT_SHADER_ARB 0x8B30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 -#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 -#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 -#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A -#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD -#define GL_MAX_HEIGHT 0x827F -#define GL_MAX_IMAGE_SAMPLES 0x906D -#define GL_MAX_IMAGE_UNITS 0x8F38 -#define GL_MAX_INTEGER_SAMPLES 0x9110 -#define GL_MAX_LABEL_LENGTH 0x82E8 -#define GL_MAX_LAYERS 0x8281 -#define GL_MAX_NAME_LENGTH 0x92F6 -#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 -#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 -#define GL_MAX_PATCH_VERTICES 0x8E7D -#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 -#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B -#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD -#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 -#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 -#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 -#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F -#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E -#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 -#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E -#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF -#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 -#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB -#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 -#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 -#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F -#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 -#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F -#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D -#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_MAX_SAMPLES_EXT 0x8D57 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE -#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD -#define GL_MAX_SUBROUTINES 0x8DE7 -#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD -#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB -#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C -#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 -#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 -#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 -#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 -#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 -#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE -#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC -#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D -#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 -#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 -#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 -#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A -#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 -#define GL_MAX_TESS_GEN_LEVEL 0x8E7E -#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF -#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 -#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_LOCATIONS 0x826E -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 -#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 -#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA -#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 -#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 -#define GL_MAX_VERTEX_STREAMS 0x8E71 -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE -#define GL_MAX_VIEWPORTS 0x825B -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_MAX_WIDTH 0x827E -#define GL_MEDIUM_FLOAT 0x8DF1 -#define GL_MEDIUM_INT 0x8DF4 -#define GL_MIN 0x8007 -#define GL_MINOR_VERSION 0x821C -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B -#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E -#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 -#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 -#define GL_MIPMAP 0x8293 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MIRRORED_REPEAT_ARB 0x8370 -#define GL_MIRROR_CLAMP_EXT 0x8742 -#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 -#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 -#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 -#define GL_MULTISAMPLE 0x809D +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B #define GL_MULTISAMPLE_ARB 0x809D -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 -#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382 -#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381 -#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 -#define GL_NAMED_STRING_TYPE_ARB 0x8DEA -#define GL_NAME_LENGTH 0x92F9 -#define GL_NAND 0x150E -#define GL_NEAREST 0x2600 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_NEVER 0x0200 -#define GL_NICEST 0x1102 -#define GL_NONE 0 -#define GL_NOOP 0x1505 -#define GL_NOR 0x1508 -#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 -#define GL_NORMAL_MAP_ARB 0x8511 -#define GL_NOTEQUAL 0x0205 -#define GL_NO_ERROR 0 -#define GL_NUM_ACTIVE_VARIABLES 0x9304 -#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 -#define GL_NUM_EXTENSIONS 0x821D -#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE -#define GL_NUM_SAMPLE_COUNTS 0x9380 -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 -#define GL_NUM_SPIR_V_EXTENSIONS 0x9554 -#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 -#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A -#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 -#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 -#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 -#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 -#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 -#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 -#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 -#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 -#define GL_OBJECT_SUBTYPE_ARB 0x8B4F -#define GL_OBJECT_TYPE 0x9112 -#define GL_OBJECT_TYPE_ARB 0x8B4E -#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 -#define GL_OFFSET 0x92FC -#define GL_ONE 1 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_OR 0x1507 -#define GL_OR_INVERTED 0x150D -#define GL_OR_REVERSE 0x150B -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D -#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C -#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E -#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 -#define GL_PALETTE4_RGB5_A1_OES 0x8B94 -#define GL_PALETTE4_RGB8_OES 0x8B90 -#define GL_PALETTE4_RGBA4_OES 0x8B93 -#define GL_PALETTE4_RGBA8_OES 0x8B91 -#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 -#define GL_PALETTE8_RGB5_A1_OES 0x8B99 -#define GL_PALETTE8_RGB8_OES 0x8B95 -#define GL_PALETTE8_RGBA4_OES 0x8B98 -#define GL_PALETTE8_RGBA8_OES 0x8B96 -#define GL_PATCHES 0x000E -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#define GL_PATCH_VERTICES 0x8E72 -#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_POINT 0x1B00 -#define GL_POINTS 0x0000 -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_POINT_SIZE_RANGE 0x0B12 -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_PRIMITIVES_SUBMITTED 0x82EF -#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF -#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_PROGRAM 0x82E2 -#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341 -#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340 -#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 -#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 -#define GL_PROGRAM_ATTRIBS_ARB 0x88AC -#define GL_PROGRAM_BINARY_FORMATS 0x87FF -#define GL_PROGRAM_BINARY_LENGTH 0x8741 -#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 -#define GL_PROGRAM_BINDING_ARB 0x8677 -#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B -#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 -#define GL_PROGRAM_FORMAT_ARB 0x8876 -#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 -#define GL_PROGRAM_INPUT 0x92E3 -#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 -#define GL_PROGRAM_LENGTH_ARB 0x8627 -#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 -#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 -#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE -#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 -#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA -#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 -#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A -#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 -#define GL_PROGRAM_OBJECT_ARB 0x8B40 -#define GL_PROGRAM_OUTPUT 0x92E4 -#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 -#define GL_PROGRAM_PIPELINE 0x82E4 -#define GL_PROGRAM_PIPELINE_BINDING 0x825A -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_PROGRAM_SEPARABLE 0x8258 -#define GL_PROGRAM_STRING_ARB 0x8628 -#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 -#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 -#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 -#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_QUADS 0x0007 -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_QUERY 0x82E3 -#define GL_QUERY_BUFFER 0x9192 -#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 -#define GL_QUERY_BUFFER_BINDING 0x9193 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_QUERY_COUNTER_BITS_ARB 0x8864 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_ARB 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 -#define GL_QUERY_RESULT_NO_WAIT 0x9194 -#define GL_QUERY_TARGET 0x82EA -#define GL_QUERY_WAIT 0x8E13 -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_R16 0x822A -#define GL_R16F 0x822D -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R16_SNORM 0x8F98 -#define GL_R32F 0x822E -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_R3_G3_B2 0x2A10 -#define GL_R8 0x8229 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R8_SNORM 0x8F94 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_READ_BUFFER 0x0C02 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA -#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#define GL_READ_ONLY 0x88B8 -#define GL_READ_ONLY_ARB 0x88B8 -#define GL_READ_PIXELS 0x828C -#define GL_READ_PIXELS_FORMAT 0x828D -#define GL_READ_PIXELS_TYPE 0x828E -#define GL_READ_WRITE 0x88BA -#define GL_READ_WRITE_ARB 0x88BA -#define GL_RED 0x1903 -#define GL_RED_INTEGER 0x8D94 -#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B -#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A -#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 -#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 -#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 -#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 -#define GL_REFLECTION_MAP_ARB 0x8512 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 -#define GL_RENDERBUFFER_EXT 0x8D41 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 -#define GL_RENDERER 0x1F01 -#define GL_REPEAT 0x2901 -#define GL_REPLACE 0x1E01 -#define GL_RG 0x8227 -#define GL_RG16 0x822C -#define GL_RG16F 0x822F -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG16_SNORM 0x8F99 -#define GL_RG32F 0x8230 -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_RG8 0x822B -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB 0x1907 -#define GL_RGB10 0x8052 -#define GL_RGB10_A2 0x8059 -#define GL_RGB10_A2UI 0x906F -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGB16F 0x881B -#define GL_RGB16F_ARB 0x881B -#define GL_RGB16I 0x8D89 -#define GL_RGB16UI 0x8D77 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGB32F 0x8815 -#define GL_RGB32F_ARB 0x8815 -#define GL_RGB32I 0x8D83 -#define GL_RGB32UI 0x8D71 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB565 0x8D62 -#define GL_RGB5_A1 0x8057 -#define GL_RGB8 0x8051 -#define GL_RGB8I 0x8D8F -#define GL_RGB8UI 0x8D7D -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGB9_E5 0x8C3D -#define GL_RGBA 0x1908 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_RGBA16F 0x881A -#define GL_RGBA16F_ARB 0x881A -#define GL_RGBA16I 0x8D88 -#define GL_RGBA16UI 0x8D76 -#define GL_RGBA16_SNORM 0x8F9B -#define GL_RGBA2 0x8055 -#define GL_RGBA32F 0x8814 -#define GL_RGBA32F_ARB 0x8814 -#define GL_RGBA32I 0x8D82 -#define GL_RGBA32UI 0x8D70 -#define GL_RGBA4 0x8056 -#define GL_RGBA8 0x8058 -#define GL_RGBA8I 0x8D8E -#define GL_RGBA8UI 0x8D7C -#define GL_RGBA8_SNORM 0x8F97 -#define GL_RGBA_FLOAT_MODE_ARB 0x8820 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RG_INTEGER 0x8228 -#define GL_RIGHT 0x0407 -#define GL_SAMPLER 0x82E6 -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_1D_ARB 0x8B5D -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_2D_ARB 0x8B5E -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_ARB 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_3D_ARB 0x8B5F -#define GL_SAMPLER_BINDING 0x8919 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_CUBE_ARB 0x8B60 -#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SAMPLES_PASSED_ARB 0x8914 -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_LOCATION_ARB 0x8E50 -#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F -#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 #define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_SHADING 0x8C36 -#define GL_SAMPLE_SHADING_ARB 0x8C36 -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_SET 0x150F -#define GL_SHADER 0x82E1 -#define GL_SHADER_BINARY_FORMATS 0x8DF8 -#define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 -#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 -#define GL_SHADER_IMAGE_ATOMIC 0x82A6 -#define GL_SHADER_IMAGE_LOAD 0x82A4 -#define GL_SHADER_IMAGE_STORE 0x82A5 -#define GL_SHADER_INCLUDE_ARB 0x8DAE -#define GL_SHADER_OBJECT_ARB 0x8B48 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 -#define GL_SHADER_STORAGE_BLOCK 0x92E6 -#define GL_SHADER_STORAGE_BUFFER 0x90D2 -#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 -#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF -#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 -#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 -#define GL_SHADER_TYPE 0x8B4F -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C -#define GL_SHORT 0x1402 -#define GL_SIGNALED 0x9119 -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC -#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE -#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD -#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SPIR_V_BINARY 0x9552 -#define GL_SPIR_V_BINARY_ARB 0x9552 -#define GL_SPIR_V_EXTENSIONS 0x9553 -#define GL_SRC1_ALPHA 0x8589 -#define GL_SRC1_COLOR 0x88F9 -#define GL_SRC_ALPHA 0x0302 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_SRC_COLOR 0x0300 -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB_DECODE_ARB 0x8299 -#define GL_SRGB_READ 0x8297 -#define GL_SRGB_WRITE 0x8298 -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 -#define GL_STATIC_COPY 0x88E6 -#define GL_STATIC_COPY_ARB 0x88E6 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_DRAW_ARB 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_READ_ARB 0x88E5 -#define GL_STENCIL 0x1802 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_COMPONENTS 0x8285 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_INDEX 0x1901 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_STENCIL_INDEX16_EXT 0x8D49 -#define GL_STENCIL_INDEX1_EXT 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX4_EXT 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX8_EXT 0x8D48 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_RENDERABLE 0x8288 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_STEREO 0x0C33 -#define GL_STREAM_COPY 0x88E2 -#define GL_STREAM_COPY_ARB 0x88E2 -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_DRAW_ARB 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_READ_ARB 0x88E1 -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_SYNC_STATUS 0x9114 -#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 -#define GL_TESS_CONTROL_SHADER 0x8E88 -#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 -#define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1 -#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1 -#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 -#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF -#define GL_TESS_CONTROL_TEXTURE 0x829C -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 -#define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2 -#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2 -#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA -#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 -#define GL_TESS_EVALUATION_TEXTURE 0x829D -#define GL_TESS_GEN_MODE 0x8E76 -#define GL_TESS_GEN_POINT_MODE 0x8E79 -#define GL_TESS_GEN_SPACING 0x8E77 -#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 -#define GL_TEXTURE 0x1702 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE0_ARB 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE10_ARB 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE11_ARB 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE12_ARB 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE13_ARB 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE14_ARB 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE15_ARB 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE16_ARB 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE17_ARB 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE18_ARB 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE19_ARB 0x84D3 -#define GL_TEXTURE1_ARB 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE20_ARB 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE21_ARB 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE22_ARB 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE23_ARB 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE24_ARB 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE25_ARB 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE26_ARB 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE27_ARB 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE28_ARB 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE29_ARB 0x84DD -#define GL_TEXTURE2_ARB 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE30_ARB 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_TEXTURE31_ARB 0x84DF -#define GL_TEXTURE3_ARB 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE4_ARB 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE5_ARB 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE6_ARB 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE7_ARB 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE8_ARB 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE9_ARB 0x84C9 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_TEXTURE_3D 0x806F -#define GL_TEXTURE_ALPHA_SIZE 0x805F -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_BUFFER_OFFSET 0x919D -#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F -#define GL_TEXTURE_BUFFER_SIZE 0x919E -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 -#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 -#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 -#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E +#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F +#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340 +#define GL_SAMPLE_LOCATION_ARB 0x8E50 +#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341 +#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342 +#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE #define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 -#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 -#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 -#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_TEXTURE_GATHER 0x82A2 -#define GL_TEXTURE_GATHER_SHADOW 0x82A3 -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 -#define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_IMAGE_FORMAT 0x828F -#define GL_TEXTURE_IMAGE_TYPE 0x8290 -#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F -#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF -#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE -#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 #define GL_TEXTURE_RED_TYPE_ARB 0x8C10 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_SHADOW 0x82A1 -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#define GL_TEXTURE_TARGET 0x1006 -#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 -#define GL_TEXTURE_VIEW 0x82B5 -#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD -#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB -#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE -#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF -#define GL_TIMESTAMP 0x8E28 -#define GL_TIME_ELAPSED 0x88BF -#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C -#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D -#define GL_TRANSFORM_FEEDBACK 0x8E22 -#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 -#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C -#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 -#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLES_ADJACENCY_ARB 0x000C -#define GL_TRIANGLE_FAN 0x0006 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D -#define GL_TRUE 1 -#define GL_TYPE 0x92FA -#define GL_UNDEFINED_VERTEX 0x8260 -#define GL_UNIFORM 0x92E1 -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA -#define GL_UNIFORM_BARRIER_BIT 0x00000004 -#define GL_UNIFORM_BLOCK 0x92E2 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 -#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 -#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A -#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_UNSIGNALED 0x9118 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_INT 0x1405 -#define GL_UNSIGNED_INT64_ARB 0x140F -#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB -#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C -#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 -#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 -#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 +#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 +#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 +#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 #define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_VENDOR 0x1F00 -#define GL_VERSION 0x1F02 -#define GL_VERTEX_ARRAY 0x8074 -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_RGBA32F_ARB 0x8814 +#define GL_RGB32F_ARB 0x8815 +#define GL_ALPHA32F_ARB 0x8816 +#define GL_INTENSITY32F_ARB 0x8817 +#define GL_LUMINANCE32F_ARB 0x8818 +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define GL_RGBA16F_ARB 0x881A +#define GL_RGB16F_ARB 0x881B +#define GL_ALPHA16F_ARB 0x881C +#define GL_INTENSITY16F_ARB 0x881D +#define GL_LUMINANCE16F_ARB 0x881E +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F #define GL_VERTEX_ATTRIB_BINDING 0x82D4 #define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 -#define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_VERTEX_BINDING_DIVISOR 0x82D6 #define GL_VERTEX_BINDING_OFFSET 0x82D7 #define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_READ_WRITE_ARB 0x88BA +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_DYNAMIC_COPY_ARB 0x88EA +#define GL_COLOR_SUM_ARB 0x8458 #define GL_VERTEX_PROGRAM_ARB 0x8620 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 -#define GL_VERTEX_SHADER 0x8B31 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 #define GL_VERTEX_SHADER_ARB 0x8B31 -#define GL_VERTEX_SHADER_BIT 0x00000001 -#define GL_VERTEX_SHADER_INVOCATIONS 0x82F0 -#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 -#define GL_VERTEX_SUBROUTINE 0x92E8 -#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE -#define GL_VERTEX_TEXTURE 0x829B -#define GL_VERTICES_SUBMITTED 0x82EE -#define GL_VERTICES_SUBMITTED_ARB 0x82EE -#define GL_VIEWPORT 0x0BA2 -#define GL_VIEWPORT_BOUNDS_RANGE 0x825D -#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F -#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C -#define GL_VIEW_CLASS_128_BITS 0x82C4 -#define GL_VIEW_CLASS_16_BITS 0x82CA -#define GL_VIEW_CLASS_24_BITS 0x82C9 -#define GL_VIEW_CLASS_32_BITS 0x82C8 -#define GL_VIEW_CLASS_48_BITS 0x82C7 -#define GL_VIEW_CLASS_64_BITS 0x82C6 -#define GL_VIEW_CLASS_8_BITS 0x82CB -#define GL_VIEW_CLASS_96_BITS 0x82C5 -#define GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393 -#define GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390 -#define GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391 -#define GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392 -#define GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394 -#define GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395 -#define GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388 -#define GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389 -#define GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A -#define GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B -#define GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C -#define GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D -#define GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E -#define GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F -#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 -#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 -#define GL_VIEW_CLASS_EAC_R11 0x9383 -#define GL_VIEW_CLASS_EAC_RG11 0x9384 -#define GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387 -#define GL_VIEW_CLASS_ETC2_RGB 0x9385 -#define GL_VIEW_CLASS_ETC2_RGBA 0x9386 -#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 -#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 -#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC -#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD -#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE -#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF -#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 -#define GL_WAIT_FAILED 0x911D -#define GL_WEIGHTED_AVERAGE_ARB 0x9367 -#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E -#define GL_WRITE_ONLY 0x88B9 -#define GL_WRITE_ONLY_ARB 0x88B9 -#define GL_XOR 0x1506 -#define GL_ZERO 0 - - -#ifndef __khrplatform_h_ -#define __khrplatform_h_ - -/* -** Copyright (c) 2008-2018 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Khronos platform-specific types and definitions. - * - * The master copy of khrplatform.h is maintained in the Khronos EGL - * Registry repository at https://github.com/KhronosGroup/EGL-Registry - * The last semantic modification to khrplatform.h was at commit ID: - * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 - * - * Adopters may modify this file to suit their platform. Adopters are - * encouraged to submit platform specific modifications to the Khronos - * group so that they can be included in future versions of this file. - * Please submit changes by filing pull requests or issues on - * the EGL Registry repository linked above. - * - * - * See the Implementer's Guidelines for information about where this file - * should be located on your system and for more details of its use: - * http://www.khronos.org/registry/implementers_guide.pdf - * - * This file should be included as - * #include - * by Khronos client API header files that use its types and defines. - * - * The types in khrplatform.h should only be used to define API-specific types. - * - * Types defined in khrplatform.h: - * khronos_int8_t signed 8 bit - * khronos_uint8_t unsigned 8 bit - * khronos_int16_t signed 16 bit - * khronos_uint16_t unsigned 16 bit - * khronos_int32_t signed 32 bit - * khronos_uint32_t unsigned 32 bit - * khronos_int64_t signed 64 bit - * khronos_uint64_t unsigned 64 bit - * khronos_intptr_t signed same number of bits as a pointer - * khronos_uintptr_t unsigned same number of bits as a pointer - * khronos_ssize_t signed size - * khronos_usize_t unsigned size - * khronos_float_t signed 32 bit floating point - * khronos_time_ns_t unsigned 64 bit time in nanoseconds - * khronos_utime_nanoseconds_t unsigned time interval or absolute time in - * nanoseconds - * khronos_stime_nanoseconds_t signed time interval in nanoseconds - * khronos_boolean_enum_t enumerated boolean type. This should - * only be used as a base type when a client API's boolean type is - * an enum. Client APIs which use an integer or other type for - * booleans cannot use this as the base type for their boolean. - * - * Tokens defined in khrplatform.h: - * - * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. - * - * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. - * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. - * - * Calling convention macros defined in this file: - * KHRONOS_APICALL - * KHRONOS_GLAD_API_PTR - * KHRONOS_APIATTRIBUTES - * - * These may be used in function prototypes as: - * - * KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname( - * int arg1, - * int arg2) KHRONOS_APIATTRIBUTES; - */ - -#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) -# define KHRONOS_STATIC 1 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +#define GL_FLOAT_VEC2_ARB 0x8B50 +#define GL_FLOAT_VEC3_ARB 0x8B51 +#define GL_FLOAT_VEC4_ARB 0x8B52 +#define GL_FLOAT_MAT2_ARB 0x8B5A +#define GL_FLOAT_MAT3_ARB 0x8B5B +#define GL_FLOAT_MAT4_ARB 0x8B5C +#define GL_ELEMENT_ARRAY_ATI 0x8768 +#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 +#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A +#define GL_FRAGMENT_SHADER_ATI 0x8920 +#define GL_REG_0_ATI 0x8921 +#define GL_REG_1_ATI 0x8922 +#define GL_REG_2_ATI 0x8923 +#define GL_REG_3_ATI 0x8924 +#define GL_REG_4_ATI 0x8925 +#define GL_REG_5_ATI 0x8926 +#define GL_REG_6_ATI 0x8927 +#define GL_REG_7_ATI 0x8928 +#define GL_REG_8_ATI 0x8929 +#define GL_REG_9_ATI 0x892A +#define GL_REG_10_ATI 0x892B +#define GL_REG_11_ATI 0x892C +#define GL_REG_12_ATI 0x892D +#define GL_REG_13_ATI 0x892E +#define GL_REG_14_ATI 0x892F +#define GL_REG_15_ATI 0x8930 +#define GL_REG_16_ATI 0x8931 +#define GL_REG_17_ATI 0x8932 +#define GL_REG_18_ATI 0x8933 +#define GL_REG_19_ATI 0x8934 +#define GL_REG_20_ATI 0x8935 +#define GL_REG_21_ATI 0x8936 +#define GL_REG_22_ATI 0x8937 +#define GL_REG_23_ATI 0x8938 +#define GL_REG_24_ATI 0x8939 +#define GL_REG_25_ATI 0x893A +#define GL_REG_26_ATI 0x893B +#define GL_REG_27_ATI 0x893C +#define GL_REG_28_ATI 0x893D +#define GL_REG_29_ATI 0x893E +#define GL_REG_30_ATI 0x893F +#define GL_REG_31_ATI 0x8940 +#define GL_CON_0_ATI 0x8941 +#define GL_CON_1_ATI 0x8942 +#define GL_CON_2_ATI 0x8943 +#define GL_CON_3_ATI 0x8944 +#define GL_CON_4_ATI 0x8945 +#define GL_CON_5_ATI 0x8946 +#define GL_CON_6_ATI 0x8947 +#define GL_CON_7_ATI 0x8948 +#define GL_CON_8_ATI 0x8949 +#define GL_CON_9_ATI 0x894A +#define GL_CON_10_ATI 0x894B +#define GL_CON_11_ATI 0x894C +#define GL_CON_12_ATI 0x894D +#define GL_CON_13_ATI 0x894E +#define GL_CON_14_ATI 0x894F +#define GL_CON_15_ATI 0x8950 +#define GL_CON_16_ATI 0x8951 +#define GL_CON_17_ATI 0x8952 +#define GL_CON_18_ATI 0x8953 +#define GL_CON_19_ATI 0x8954 +#define GL_CON_20_ATI 0x8955 +#define GL_CON_21_ATI 0x8956 +#define GL_CON_22_ATI 0x8957 +#define GL_CON_23_ATI 0x8958 +#define GL_CON_24_ATI 0x8959 +#define GL_CON_25_ATI 0x895A +#define GL_CON_26_ATI 0x895B +#define GL_CON_27_ATI 0x895C +#define GL_CON_28_ATI 0x895D +#define GL_CON_29_ATI 0x895E +#define GL_CON_30_ATI 0x895F +#define GL_CON_31_ATI 0x8960 +#define GL_MOV_ATI 0x8961 +#define GL_ADD_ATI 0x8963 +#define GL_MUL_ATI 0x8964 +#define GL_SUB_ATI 0x8965 +#define GL_DOT3_ATI 0x8966 +#define GL_DOT4_ATI 0x8967 +#define GL_MAD_ATI 0x8968 +#define GL_LERP_ATI 0x8969 +#define GL_CND_ATI 0x896A +#define GL_CND0_ATI 0x896B +#define GL_DOT2_ADD_ATI 0x896C +#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D +#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E +#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F +#define GL_NUM_PASSES_ATI 0x8970 +#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 +#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 +#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 +#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 +#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 +#define GL_SWIZZLE_STR_ATI 0x8976 +#define GL_SWIZZLE_STQ_ATI 0x8977 +#define GL_SWIZZLE_STR_DR_ATI 0x8978 +#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 +#define GL_SWIZZLE_STRQ_ATI 0x897A +#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B +#define GL_RED_BIT_ATI 0x00000001 +#define GL_GREEN_BIT_ATI 0x00000002 +#define GL_BLUE_BIT_ATI 0x00000004 +#define GL_2X_BIT_ATI 0x00000001 +#define GL_4X_BIT_ATI 0x00000002 +#define GL_8X_BIT_ATI 0x00000004 +#define GL_HALF_BIT_ATI 0x00000008 +#define GL_QUARTER_BIT_ATI 0x00000010 +#define GL_EIGHTH_BIT_ATI 0x00000020 +#define GL_SATURATE_BIT_ATI 0x00000040 +#define GL_COMP_BIT_ATI 0x00000002 +#define GL_NEGATE_BIT_ATI 0x00000004 +#define GL_BIAS_BIT_ATI 0x00000008 +#define GL_STATIC_ATI 0x8760 +#define GL_DYNAMIC_ATI 0x8761 +#define GL_PRESERVE_ATI 0x8762 +#define GL_DISCARD_ATI 0x8763 +#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 +#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 +#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 +#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 +#define GL_CONSTANT_COLOR_EXT 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define GL_CONSTANT_ALPHA_EXT 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define GL_BLEND_COLOR_EXT 0x8005 +#define GL_BLEND_EQUATION_RGB_EXT 0x8009 +#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D +#define GL_BLEND_DST_RGB_EXT 0x80C8 +#define GL_BLEND_SRC_RGB_EXT 0x80C9 +#define GL_BLEND_DST_ALPHA_EXT 0x80CA +#define GL_BLEND_SRC_ALPHA_EXT 0x80CB +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA +#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#define GL_IUI_V2F_EXT 0x81AD +#define GL_IUI_V3F_EXT 0x81AE +#define GL_IUI_N3F_V2F_EXT 0x81AF +#define GL_IUI_N3F_V3F_EXT 0x81B0 +#define GL_T2F_IUI_V2F_EXT 0x81B1 +#define GL_T2F_IUI_V3F_EXT 0x81B2 +#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 +#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 +#define GL_ALPHA4_EXT 0x803B +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA12_EXT 0x803D +#define GL_ALPHA16_EXT 0x803E +#define GL_LUMINANCE4_EXT 0x803F +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE12_EXT 0x8041 +#define GL_LUMINANCE16_EXT 0x8042 +#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 +#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 +#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 +#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 +#define GL_INTENSITY_EXT 0x8049 +#define GL_INTENSITY4_EXT 0x804A +#define GL_INTENSITY8_EXT 0x804B +#define GL_INTENSITY12_EXT 0x804C +#define GL_INTENSITY16_EXT 0x804D +#define GL_RGB2_EXT 0x804E +#define GL_RGB4_EXT 0x804F +#define GL_RGB5_EXT 0x8050 +#define GL_RGB8_EXT 0x8051 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB12_EXT 0x8053 +#define GL_RGB16_EXT 0x8054 +#define GL_RGBA2_EXT 0x8055 +#define GL_RGBA4_EXT 0x8056 +#define GL_RGB5_A1_EXT 0x8057 +#define GL_RGBA8_EXT 0x8058 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGBA12_EXT 0x805A +#define GL_RGBA16_EXT 0x805B +#define GL_TEXTURE_RED_SIZE_EXT 0x805C +#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D +#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E +#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 +#define GL_REPLACE_EXT 0x8062 +#define GL_PROXY_TEXTURE_1D_EXT 0x8063 +#define GL_PROXY_TEXTURE_2D_EXT 0x8064 +#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 +#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 +#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 +#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 +#define GL_VERTEX_ARRAY_EXT 0x8074 +#define GL_NORMAL_ARRAY_EXT 0x8075 +#define GL_COLOR_ARRAY_EXT 0x8076 +#define GL_INDEX_ARRAY_EXT 0x8077 +#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 +#define GL_VERTEX_SHADER_EXT 0x8780 +#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 +#define GL_OP_INDEX_EXT 0x8782 +#define GL_OP_NEGATE_EXT 0x8783 +#define GL_OP_DOT3_EXT 0x8784 +#define GL_OP_DOT4_EXT 0x8785 +#define GL_OP_MUL_EXT 0x8786 +#define GL_OP_ADD_EXT 0x8787 +#define GL_OP_MADD_EXT 0x8788 +#define GL_OP_FRAC_EXT 0x8789 +#define GL_OP_MAX_EXT 0x878A +#define GL_OP_MIN_EXT 0x878B +#define GL_OP_SET_GE_EXT 0x878C +#define GL_OP_SET_LT_EXT 0x878D +#define GL_OP_CLAMP_EXT 0x878E +#define GL_OP_FLOOR_EXT 0x878F +#define GL_OP_ROUND_EXT 0x8790 +#define GL_OP_EXP_BASE_2_EXT 0x8791 +#define GL_OP_LOG_BASE_2_EXT 0x8792 +#define GL_OP_POWER_EXT 0x8793 +#define GL_OP_RECIP_EXT 0x8794 +#define GL_OP_RECIP_SQRT_EXT 0x8795 +#define GL_OP_SUB_EXT 0x8796 +#define GL_OP_CROSS_PRODUCT_EXT 0x8797 +#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 +#define GL_OP_MOV_EXT 0x8799 +#define GL_OUTPUT_VERTEX_EXT 0x879A +#define GL_OUTPUT_COLOR0_EXT 0x879B +#define GL_OUTPUT_COLOR1_EXT 0x879C +#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D +#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E +#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F +#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 +#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 +#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 +#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 +#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 +#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 +#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 +#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 +#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 +#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 +#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA +#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB +#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC +#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD +#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE +#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF +#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 +#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 +#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 +#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 +#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 +#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 +#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 +#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 +#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 +#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 +#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA +#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB +#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC +#define GL_OUTPUT_FOG_EXT 0x87BD +#define GL_SCALAR_EXT 0x87BE +#define GL_VECTOR_EXT 0x87BF +#define GL_MATRIX_EXT 0x87C0 +#define GL_VARIANT_EXT 0x87C1 +#define GL_INVARIANT_EXT 0x87C2 +#define GL_LOCAL_CONSTANT_EXT 0x87C3 +#define GL_LOCAL_EXT 0x87C4 +#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 +#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 +#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 +#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 +#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE +#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF +#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 +#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 +#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 +#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 +#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 +#define GL_X_EXT 0x87D5 +#define GL_Y_EXT 0x87D6 +#define GL_Z_EXT 0x87D7 +#define GL_W_EXT 0x87D8 +#define GL_NEGATIVE_X_EXT 0x87D9 +#define GL_NEGATIVE_Y_EXT 0x87DA +#define GL_NEGATIVE_Z_EXT 0x87DB +#define GL_NEGATIVE_W_EXT 0x87DC +#define GL_ZERO_EXT 0x87DD +#define GL_ONE_EXT 0x87DE +#define GL_NEGATIVE_ONE_EXT 0x87DF +#define GL_NORMALIZED_RANGE_EXT 0x87E0 +#define GL_FULL_RANGE_EXT 0x87E1 +#define GL_CURRENT_VERTEX_EXT 0x87E2 +#define GL_MVP_MATRIX_EXT 0x87E3 +#define GL_VARIANT_VALUE_EXT 0x87E4 +#define GL_VARIANT_DATATYPE_EXT 0x87E5 +#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 +#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 +#define GL_VARIANT_ARRAY_EXT 0x87E8 +#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 +#define GL_INVARIANT_VALUE_EXT 0x87EA +#define GL_INVARIANT_DATATYPE_EXT 0x87EB +#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC +#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED +#ifndef GL_AMD_debug_output +#define GL_AMD_debug_output 1 +GLAPI int GLAD_GL_AMD_debug_output; +typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC)(GLenum category, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD; +#define glDebugMessageEnableAMD glad_glDebugMessageEnableAMD +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC)(GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar* buf); +GLAPI PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD; +#define glDebugMessageInsertAMD glad_glDebugMessageInsertAMD +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC)(GLDEBUGPROCAMD callback, void* userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKAMDPROC glad_glDebugMessageCallbackAMD; +#define glDebugMessageCallbackAMD glad_glDebugMessageCallbackAMD +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC)(GLuint count, GLsizei bufsize, GLenum* categories, GLuint* severities, GLuint* ids, GLsizei* lengths, GLchar* message); +GLAPI PFNGLGETDEBUGMESSAGELOGAMDPROC glad_glGetDebugMessageLogAMD; +#define glGetDebugMessageLogAMD glad_glGetDebugMessageLogAMD #endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APICALL - *------------------------------------------------------------------------- - * This precedes the return type of the function in the function prototype. - */ -#if defined(KHRONOS_STATIC) - /* If the preprocessor constant KHRONOS_STATIC is defined, make the - * header compatible with static linking. */ -# define KHRONOS_APICALL -#elif defined(_WIN32) -# define KHRONOS_APICALL __declspec(dllimport) -#elif defined (__SYMBIAN32__) -# define KHRONOS_APICALL IMPORT_C -#elif defined(__ANDROID__) -# define KHRONOS_APICALL __attribute__((visibility("default"))) -#else -# define KHRONOS_APICALL +#ifndef GL_AMD_query_buffer_object +#define GL_AMD_query_buffer_object 1 +GLAPI int GLAD_GL_AMD_query_buffer_object; #endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_GLAD_API_PTR - *------------------------------------------------------------------------- - * This follows the return type of the function and precedes the function - * name in the function prototype. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ -# define KHRONOS_GLAD_API_PTR __stdcall -#else -# define KHRONOS_GLAD_API_PTR -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIATTRIBUTES - *------------------------------------------------------------------------- - * This follows the closing parenthesis of the function prototype arguments. - */ -#if defined (__ARMCC_2__) -#define KHRONOS_APIATTRIBUTES __softfp -#else -#define KHRONOS_APIATTRIBUTES -#endif - -/*------------------------------------------------------------------------- - * basic type definitions - *-----------------------------------------------------------------------*/ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) - - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 -/* - * To support platform where unsigned long cannot be used interchangeably with - * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. - * Ideally, we could just use (u)intptr_t everywhere, but this could result in - * ABI breakage if khronos_uintptr_t is changed from unsigned long to - * unsigned long long or similar (this results in different C++ name mangling). - * To avoid changes for existing platforms, we restrict usage of intptr_t to - * platforms where the size of a pointer is larger than the size of long. - */ -#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) -#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ -#define KHRONOS_USE_INTPTR_T -#endif -#endif - -#elif defined(__VMS ) || defined(__sgi) - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) - -/* - * Win32 - */ -typedef __int32 khronos_int32_t; -typedef unsigned __int32 khronos_uint32_t; -typedef __int64 khronos_int64_t; -typedef unsigned __int64 khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__sun__) || defined(__digital__) - -/* - * Sun or Digital - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#if defined(__arch64__) || defined(_LP64) -typedef long int khronos_int64_t; -typedef unsigned long int khronos_uint64_t; -#else -typedef long long int khronos_int64_t; -typedef unsigned long long int khronos_uint64_t; -#endif /* __arch64__ */ -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif 0 - -/* - * Hypothetical platform with no float or int64 support - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#define KHRONOS_SUPPORT_INT64 0 -#define KHRONOS_SUPPORT_FLOAT 0 - -#else - -/* - * Generic fallback - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#endif - - -/* - * Types that are (so far) the same on all platforms - */ -typedef signed char khronos_int8_t; -typedef unsigned char khronos_uint8_t; -typedef signed short int khronos_int16_t; -typedef unsigned short int khronos_uint16_t; - -/* - * Types that differ between LLP64 and LP64 architectures - in LLP64, - * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears - * to be the only LLP64 architecture in current use. - */ -#ifdef KHRONOS_USE_INTPTR_T -typedef intptr_t khronos_intptr_t; -typedef uintptr_t khronos_uintptr_t; -#elif defined(_WIN64) -typedef signed long long int khronos_intptr_t; -typedef unsigned long long int khronos_uintptr_t; -#else -typedef signed long int khronos_intptr_t; -typedef unsigned long int khronos_uintptr_t; -#endif - -#if defined(_WIN64) -typedef signed long long int khronos_ssize_t; -typedef unsigned long long int khronos_usize_t; -#else -typedef signed long int khronos_ssize_t; -typedef unsigned long int khronos_usize_t; -#endif - -#if KHRONOS_SUPPORT_FLOAT -/* - * Float type - */ -typedef float khronos_float_t; -#endif - -#if KHRONOS_SUPPORT_INT64 -/* Time types - * - * These types can be used to represent a time interval in nanoseconds or - * an absolute Unadjusted System Time. Unadjusted System Time is the number - * of nanoseconds since some arbitrary system event (e.g. since the last - * time the system booted). The Unadjusted System Time is an unsigned - * 64 bit value that wraps back to 0 every 584 years. Time intervals - * may be either signed or unsigned. - */ -typedef khronos_uint64_t khronos_utime_nanoseconds_t; -typedef khronos_int64_t khronos_stime_nanoseconds_t; -#endif - -/* - * Dummy value used to pad enum types to 32 bits. - */ -#ifndef KHRONOS_MAX_ENUM -#define KHRONOS_MAX_ENUM 0x7FFFFFFF -#endif - -/* - * Enumerated boolean type - * - * Values other than zero should be considered to be true. Therefore - * comparisons should not be made against KHRONOS_TRUE. - */ -typedef enum { - KHRONOS_FALSE = 0, - KHRONOS_TRUE = 1, - KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM -} khronos_boolean_enum_t; - -#endif /* __khrplatform_h_ */ -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef khronos_int8_t GLbyte; -typedef khronos_uint8_t GLubyte; -typedef khronos_int16_t GLshort; -typedef khronos_uint16_t GLushort; -typedef int GLint; -typedef unsigned int GLuint; -typedef khronos_int32_t GLclampx; -typedef int GLsizei; -typedef khronos_float_t GLfloat; -typedef khronos_float_t GLclampf; -typedef double GLdouble; -typedef double GLclampd; -typedef void *GLeglClientBufferEXT; -typedef void *GLeglImageOES; -typedef char GLchar; -typedef char GLcharARB; -#ifdef __APPLE__ -typedef void *GLhandleARB; -#else -typedef unsigned int GLhandleARB; -#endif -typedef khronos_uint16_t GLhalf; -typedef khronos_uint16_t GLhalfARB; -typedef khronos_int32_t GLfixed; -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_intptr_t GLintptr; -#else -typedef khronos_intptr_t GLintptr; -#endif -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_intptr_t GLintptrARB; -#else -typedef khronos_intptr_t GLintptrARB; -#endif -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_ssize_t GLsizeiptr; -#else -typedef khronos_ssize_t GLsizeiptr; -#endif -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_ssize_t GLsizeiptrARB; -#else -typedef khronos_ssize_t GLsizeiptrARB; -#endif -typedef khronos_int64_t GLint64; -typedef khronos_int64_t GLint64EXT; -typedef khronos_uint64_t GLuint64; -typedef khronos_uint64_t GLuint64EXT; -typedef struct __GLsync *GLsync; -struct _cl_context; -struct _cl_event; -typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); -typedef unsigned short GLhalfNV; -typedef GLintptr GLvdpauSurfaceNV; -typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); - - -#define GL_VERSION_1_0 1 -GLAD_API_CALL int GLAD_GL_VERSION_1_0; -#define GL_VERSION_1_1 1 -GLAD_API_CALL int GLAD_GL_VERSION_1_1; -#define GL_VERSION_1_2 1 -GLAD_API_CALL int GLAD_GL_VERSION_1_2; -#define GL_VERSION_1_3 1 -GLAD_API_CALL int GLAD_GL_VERSION_1_3; -#define GL_VERSION_1_4 1 -GLAD_API_CALL int GLAD_GL_VERSION_1_4; -#define GL_VERSION_1_5 1 -GLAD_API_CALL int GLAD_GL_VERSION_1_5; -#define GL_VERSION_2_0 1 -GLAD_API_CALL int GLAD_GL_VERSION_2_0; -#define GL_VERSION_2_1 1 -GLAD_API_CALL int GLAD_GL_VERSION_2_1; -#define GL_VERSION_3_0 1 -GLAD_API_CALL int GLAD_GL_VERSION_3_0; -#define GL_VERSION_3_1 1 -GLAD_API_CALL int GLAD_GL_VERSION_3_1; -#define GL_VERSION_3_2 1 -GLAD_API_CALL int GLAD_GL_VERSION_3_2; -#define GL_VERSION_3_3 1 -GLAD_API_CALL int GLAD_GL_VERSION_3_3; -#define GL_VERSION_4_0 1 -GLAD_API_CALL int GLAD_GL_VERSION_4_0; -#define GL_VERSION_4_1 1 -GLAD_API_CALL int GLAD_GL_VERSION_4_1; -#define GL_VERSION_4_2 1 -GLAD_API_CALL int GLAD_GL_VERSION_4_2; -#define GL_VERSION_4_3 1 -GLAD_API_CALL int GLAD_GL_VERSION_4_3; +#ifndef GL_ARB_ES2_compatibility #define GL_ARB_ES2_compatibility 1 -GLAD_API_CALL int GLAD_GL_ARB_ES2_compatibility; -#define GL_ARB_ES3_1_compatibility 1 -GLAD_API_CALL int GLAD_GL_ARB_ES3_1_compatibility; -#define GL_ARB_ES3_2_compatibility 1 -GLAD_API_CALL int GLAD_GL_ARB_ES3_2_compatibility; -#define GL_ARB_ES3_compatibility 1 -GLAD_API_CALL int GLAD_GL_ARB_ES3_compatibility; -#define GL_ARB_blend_func_extended 1 -GLAD_API_CALL int GLAD_GL_ARB_blend_func_extended; -#define GL_ARB_buffer_storage 1 -GLAD_API_CALL int GLAD_GL_ARB_buffer_storage; -#define GL_ARB_clear_buffer_object 1 -GLAD_API_CALL int GLAD_GL_ARB_clear_buffer_object; -#define GL_ARB_clear_texture 1 -GLAD_API_CALL int GLAD_GL_ARB_clear_texture; -#define GL_ARB_color_buffer_float 1 -GLAD_API_CALL int GLAD_GL_ARB_color_buffer_float; -#define GL_ARB_compatibility 1 -GLAD_API_CALL int GLAD_GL_ARB_compatibility; -#define GL_ARB_compressed_texture_pixel_storage 1 -GLAD_API_CALL int GLAD_GL_ARB_compressed_texture_pixel_storage; -#define GL_ARB_compute_shader 1 -GLAD_API_CALL int GLAD_GL_ARB_compute_shader; -#define GL_ARB_compute_variable_group_size 1 -GLAD_API_CALL int GLAD_GL_ARB_compute_variable_group_size; -#define GL_ARB_copy_buffer 1 -GLAD_API_CALL int GLAD_GL_ARB_copy_buffer; -#define GL_ARB_copy_image 1 -GLAD_API_CALL int GLAD_GL_ARB_copy_image; -#define GL_ARB_debug_output 1 -GLAD_API_CALL int GLAD_GL_ARB_debug_output; -#define GL_ARB_depth_buffer_float 1 -GLAD_API_CALL int GLAD_GL_ARB_depth_buffer_float; -#define GL_ARB_depth_clamp 1 -GLAD_API_CALL int GLAD_GL_ARB_depth_clamp; -#define GL_ARB_depth_texture 1 -GLAD_API_CALL int GLAD_GL_ARB_depth_texture; -#define GL_ARB_direct_state_access 1 -GLAD_API_CALL int GLAD_GL_ARB_direct_state_access; -#define GL_ARB_draw_buffers 1 -GLAD_API_CALL int GLAD_GL_ARB_draw_buffers; -#define GL_ARB_draw_buffers_blend 1 -GLAD_API_CALL int GLAD_GL_ARB_draw_buffers_blend; -#define GL_ARB_draw_elements_base_vertex 1 -GLAD_API_CALL int GLAD_GL_ARB_draw_elements_base_vertex; -#define GL_ARB_draw_indirect 1 -GLAD_API_CALL int GLAD_GL_ARB_draw_indirect; -#define GL_ARB_draw_instanced 1 -GLAD_API_CALL int GLAD_GL_ARB_draw_instanced; -#define GL_ARB_enhanced_layouts 1 -GLAD_API_CALL int GLAD_GL_ARB_enhanced_layouts; -#define GL_ARB_explicit_attrib_location 1 -GLAD_API_CALL int GLAD_GL_ARB_explicit_attrib_location; -#define GL_ARB_explicit_uniform_location 1 -GLAD_API_CALL int GLAD_GL_ARB_explicit_uniform_location; -#define GL_ARB_fragment_coord_conventions 1 -GLAD_API_CALL int GLAD_GL_ARB_fragment_coord_conventions; -#define GL_ARB_fragment_layer_viewport 1 -GLAD_API_CALL int GLAD_GL_ARB_fragment_layer_viewport; -#define GL_ARB_fragment_program 1 -GLAD_API_CALL int GLAD_GL_ARB_fragment_program; -#define GL_ARB_fragment_program_shadow 1 -GLAD_API_CALL int GLAD_GL_ARB_fragment_program_shadow; -#define GL_ARB_fragment_shader 1 -GLAD_API_CALL int GLAD_GL_ARB_fragment_shader; -#define GL_ARB_fragment_shader_interlock 1 -GLAD_API_CALL int GLAD_GL_ARB_fragment_shader_interlock; -#define GL_ARB_framebuffer_no_attachments 1 -GLAD_API_CALL int GLAD_GL_ARB_framebuffer_no_attachments; -#define GL_ARB_framebuffer_object 1 -GLAD_API_CALL int GLAD_GL_ARB_framebuffer_object; -#define GL_ARB_framebuffer_sRGB 1 -GLAD_API_CALL int GLAD_GL_ARB_framebuffer_sRGB; -#define GL_ARB_geometry_shader4 1 -GLAD_API_CALL int GLAD_GL_ARB_geometry_shader4; -#define GL_ARB_get_program_binary 1 -GLAD_API_CALL int GLAD_GL_ARB_get_program_binary; -#define GL_ARB_get_texture_sub_image 1 -GLAD_API_CALL int GLAD_GL_ARB_get_texture_sub_image; -#define GL_ARB_gl_spirv 1 -GLAD_API_CALL int GLAD_GL_ARB_gl_spirv; -#define GL_ARB_gpu_shader5 1 -GLAD_API_CALL int GLAD_GL_ARB_gpu_shader5; -#define GL_ARB_gpu_shader_fp64 1 -GLAD_API_CALL int GLAD_GL_ARB_gpu_shader_fp64; -#define GL_ARB_gpu_shader_int64 1 -GLAD_API_CALL int GLAD_GL_ARB_gpu_shader_int64; -#define GL_ARB_half_float_pixel 1 -GLAD_API_CALL int GLAD_GL_ARB_half_float_pixel; -#define GL_ARB_half_float_vertex 1 -GLAD_API_CALL int GLAD_GL_ARB_half_float_vertex; -#define GL_ARB_instanced_arrays 1 -GLAD_API_CALL int GLAD_GL_ARB_instanced_arrays; -#define GL_ARB_internalformat_query 1 -GLAD_API_CALL int GLAD_GL_ARB_internalformat_query; -#define GL_ARB_internalformat_query2 1 -GLAD_API_CALL int GLAD_GL_ARB_internalformat_query2; -#define GL_ARB_map_buffer_range 1 -GLAD_API_CALL int GLAD_GL_ARB_map_buffer_range; -#define GL_ARB_multi_bind 1 -GLAD_API_CALL int GLAD_GL_ARB_multi_bind; -#define GL_ARB_multi_draw_indirect 1 -GLAD_API_CALL int GLAD_GL_ARB_multi_draw_indirect; -#define GL_ARB_multisample 1 -GLAD_API_CALL int GLAD_GL_ARB_multisample; -#define GL_ARB_multitexture 1 -GLAD_API_CALL int GLAD_GL_ARB_multitexture; -#define GL_ARB_occlusion_query 1 -GLAD_API_CALL int GLAD_GL_ARB_occlusion_query; -#define GL_ARB_occlusion_query2 1 -GLAD_API_CALL int GLAD_GL_ARB_occlusion_query2; -#define GL_ARB_pipeline_statistics_query 1 -GLAD_API_CALL int GLAD_GL_ARB_pipeline_statistics_query; -#define GL_ARB_query_buffer_object 1 -GLAD_API_CALL int GLAD_GL_ARB_query_buffer_object; -#define GL_ARB_sample_locations 1 -GLAD_API_CALL int GLAD_GL_ARB_sample_locations; -#define GL_ARB_sample_shading 1 -GLAD_API_CALL int GLAD_GL_ARB_sample_shading; -#define GL_ARB_seamless_cube_map 1 -GLAD_API_CALL int GLAD_GL_ARB_seamless_cube_map; -#define GL_ARB_seamless_cubemap_per_texture 1 -GLAD_API_CALL int GLAD_GL_ARB_seamless_cubemap_per_texture; -#define GL_ARB_shader_atomic_counter_ops 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_atomic_counter_ops; -#define GL_ARB_shader_atomic_counters 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_atomic_counters; -#define GL_ARB_shader_bit_encoding 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_bit_encoding; -#define GL_ARB_shader_clock 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_clock; -#define GL_ARB_shader_image_load_store 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_image_load_store; -#define GL_ARB_shader_image_size 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_image_size; -#define GL_ARB_shader_objects 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_objects; -#define GL_ARB_shader_storage_buffer_object 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_storage_buffer_object; -#define GL_ARB_shader_texture_lod 1 -GLAD_API_CALL int GLAD_GL_ARB_shader_texture_lod; -#define GL_ARB_shading_language_100 1 -GLAD_API_CALL int GLAD_GL_ARB_shading_language_100; -#define GL_ARB_shading_language_420pack 1 -GLAD_API_CALL int GLAD_GL_ARB_shading_language_420pack; -#define GL_ARB_shading_language_include 1 -GLAD_API_CALL int GLAD_GL_ARB_shading_language_include; -#define GL_ARB_shading_language_packing 1 -GLAD_API_CALL int GLAD_GL_ARB_shading_language_packing; -#define GL_ARB_spirv_extensions 1 -GLAD_API_CALL int GLAD_GL_ARB_spirv_extensions; -#define GL_ARB_tessellation_shader 1 -GLAD_API_CALL int GLAD_GL_ARB_tessellation_shader; -#define GL_ARB_texture_border_clamp 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_border_clamp; -#define GL_ARB_texture_buffer_object_rgb32 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_buffer_object_rgb32; -#define GL_ARB_texture_compression 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_compression; -#define GL_ARB_texture_cube_map 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_cube_map; -#define GL_ARB_texture_cube_map_array 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_cube_map_array; -#define GL_ARB_texture_env_add 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_env_add; -#define GL_ARB_texture_filter_anisotropic 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_filter_anisotropic; -#define GL_ARB_texture_filter_minmax 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_filter_minmax; -#define GL_ARB_texture_float 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_float; -#define GL_ARB_texture_mirror_clamp_to_edge 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_mirror_clamp_to_edge; -#define GL_ARB_texture_mirrored_repeat 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_mirrored_repeat; -#define GL_ARB_texture_multisample 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_multisample; -#define GL_ARB_texture_non_power_of_two 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_non_power_of_two; -#define GL_ARB_texture_rg 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_rg; -#define GL_ARB_texture_storage 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_storage; -#define GL_ARB_texture_swizzle 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_swizzle; -#define GL_ARB_texture_view 1 -GLAD_API_CALL int GLAD_GL_ARB_texture_view; -#define GL_ARB_timer_query 1 -GLAD_API_CALL int GLAD_GL_ARB_timer_query; -#define GL_ARB_transpose_matrix 1 -GLAD_API_CALL int GLAD_GL_ARB_transpose_matrix; -#define GL_ARB_uniform_buffer_object 1 -GLAD_API_CALL int GLAD_GL_ARB_uniform_buffer_object; -#define GL_ARB_vertex_array_bgra 1 -GLAD_API_CALL int GLAD_GL_ARB_vertex_array_bgra; -#define GL_ARB_vertex_array_object 1 -GLAD_API_CALL int GLAD_GL_ARB_vertex_array_object; -#define GL_ARB_vertex_attrib_binding 1 -GLAD_API_CALL int GLAD_GL_ARB_vertex_attrib_binding; -#define GL_ARB_vertex_buffer_object 1 -GLAD_API_CALL int GLAD_GL_ARB_vertex_buffer_object; -#define GL_ARB_vertex_program 1 -GLAD_API_CALL int GLAD_GL_ARB_vertex_program; -#define GL_ARB_vertex_shader 1 -GLAD_API_CALL int GLAD_GL_ARB_vertex_shader; -#define GL_EXT_draw_instanced 1 -GLAD_API_CALL int GLAD_GL_EXT_draw_instanced; -#define GL_EXT_fog_coord 1 -GLAD_API_CALL int GLAD_GL_EXT_fog_coord; -#define GL_EXT_framebuffer_blit 1 -GLAD_API_CALL int GLAD_GL_EXT_framebuffer_blit; -#define GL_EXT_framebuffer_multisample 1 -GLAD_API_CALL int GLAD_GL_EXT_framebuffer_multisample; -#define GL_EXT_framebuffer_object 1 -GLAD_API_CALL int GLAD_GL_EXT_framebuffer_object; -#define GL_EXT_framebuffer_sRGB 1 -GLAD_API_CALL int GLAD_GL_EXT_framebuffer_sRGB; -#define GL_EXT_texture_compression_s3tc 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; -#define GL_EXT_texture_filter_anisotropic 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic; -#define GL_EXT_texture_mirror_clamp 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_mirror_clamp; -#define GL_KHR_texture_compression_astc_hdr 1 -GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_hdr; -#define GL_KHR_texture_compression_astc_ldr 1 -GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_ldr; -#define GL_OES_compressed_paletted_texture 1 -GLAD_API_CALL int GLAD_GL_OES_compressed_paletted_texture; -#define GL_OES_fixed_point 1 -GLAD_API_CALL int GLAD_GL_OES_fixed_point; - - -typedef void (GLAD_API_PTR *PFNGLACCUMXOESPROC)(GLenum op, GLfixed value); -typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program); -typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); -typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREARBPROC)(GLenum texture); -typedef void (GLAD_API_PTR *PFNGLALPHAFUNCXOESPROC)(GLenum func, GLfixed ref); -typedef void (GLAD_API_PTR *PFNGLATTACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB obj); -typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); -typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); -typedef void (GLAD_API_PTR *PFNGLBEGINQUERYARBPROC)(GLenum target, GLuint id); -typedef void (GLAD_API_PTR *PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id); -typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); -typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONARBPROC)(GLhandleARB programObj, GLuint index, const GLcharARB * name); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERARBPROC)(GLenum target, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERSBASEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERSRANGEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint * buffers, const GLintptr * offsets, const GLsizeiptr * sizes); -typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); -typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFEREXTPROC)(GLenum target, GLuint framebuffer); -typedef void (GLAD_API_PTR *PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -typedef void (GLAD_API_PTR *PFNGLBINDIMAGETEXTURESPROC)(GLuint first, GLsizei count, const GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMARBPROC)(GLenum target, GLuint program); -typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline); -typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFEREXTPROC)(GLenum target, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); -typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERSPROC)(GLuint first, GLsizei count, const GLuint * samplers); -typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); -typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREUNITPROC)(GLuint unit, GLuint texture); -typedef void (GLAD_API_PTR *PFNGLBINDTEXTURESPROC)(GLuint first, GLsizei count, const GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id); -typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array); -typedef void (GLAD_API_PTR *PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (GLAD_API_PTR *PFNGLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count, const GLuint * buffers, const GLintptr * offsets, const GLsizei * strides); -typedef void (GLAD_API_PTR *PFNGLBITMAPXOESPROC)(GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte * bitmap); -typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (GLAD_API_PTR *PFNGLBLENDCOLORXOESPROC)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIARBPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIARBPROC)(GLuint buf, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIARBPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIARBPROC)(GLuint buf, GLenum src, GLenum dst); -typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFEREXTPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (GLAD_API_PTR *PFNGLBLITNAMEDFRAMEBUFFERPROC)(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); -typedef void (GLAD_API_PTR *PFNGLBUFFERDATAARBPROC)(GLenum target, GLsizeiptrARB size, const void * data, GLenum usage); -typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags); -typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); -typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void * data); -typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); -typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(GLenum target); -typedef GLenum (GLAD_API_PTR *PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)(GLuint framebuffer, GLenum target); -typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); -typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORARBPROC)(GLenum target, GLenum clamp); -typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); -typedef void (GLAD_API_PTR *PFNGLCLEARACCUMXOESPROC)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (GLAD_API_PTR *PFNGLCLEARCOLORXOESPROC)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth); -typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d); -typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHXOESPROC)(GLfixed depth); -typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDBUFFERDATAPROC)(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); -typedef void (GLAD_API_PTR *PFNGLCLEARTEXIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLEARTEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLIENTACTIVETEXTUREARBPROC)(GLenum texture); -typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (GLAD_API_PTR *PFNGLCLIPPLANEXOESPROC)(GLenum plane, const GLfixed * equation); -typedef void (GLAD_API_PTR *PFNGLCOLOR3XOESPROC)(GLfixed red, GLfixed green, GLfixed blue); -typedef void (GLAD_API_PTR *PFNGLCOLOR3XVOESPROC)(const GLfixed * components); -typedef void (GLAD_API_PTR *PFNGLCOLOR4XOESPROC)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (GLAD_API_PTR *PFNGLCOLOR4XVOESPROC)(const GLfixed * components); -typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); -typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERARBPROC)(GLhandleARB shaderObj); -typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERINCLUDEARBPROC)(GLuint shader, GLsizei count, const GLchar *const* path, const GLint * length); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCONVOLUTIONPARAMETERXOESPROC)(GLenum target, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLCONVOLUTIONPARAMETERXVOESPROC)(GLenum target, GLenum pname, const GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -typedef void (GLAD_API_PTR *PFNGLCOPYNAMEDBUFFERSUBDATAPROC)(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLCREATEBUFFERSPROC)(GLsizei n, GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLCREATEFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); -typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); -typedef GLhandleARB (GLAD_API_PTR *PFNGLCREATEPROGRAMOBJECTARBPROC)(void); -typedef void (GLAD_API_PTR *PFNGLCREATEPROGRAMPIPELINESPROC)(GLsizei n, GLuint * pipelines); -typedef void (GLAD_API_PTR *PFNGLCREATEQUERIESPROC)(GLenum target, GLsizei n, GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLCREATERENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLCREATESAMPLERSPROC)(GLsizei n, GLuint * samplers); -typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); -typedef GLhandleARB (GLAD_API_PTR *PFNGLCREATESHADEROBJECTARBPROC)(GLenum shaderType); -typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const* strings); -typedef void (GLAD_API_PTR *PFNGLCREATETEXTURESPROC)(GLenum target, GLsizei n, GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLCREATETRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLCREATEVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays); -typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void * userParam); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void * userParam); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); -typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSARBPROC)(GLsizei n, const GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); -typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSEXTPROC)(GLsizei n, const GLuint * framebuffers); -typedef void (GLAD_API_PTR *PFNGLDELETENAMEDSTRINGARBPROC)(GLint namelen, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLDELETEOBJECTARBPROC)(GLhandleARB obj); -typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint * pipelines); -typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMSARBPROC)(GLsizei n, const GLuint * programs); -typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESARBPROC)(GLsizei n, const GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSEXTPROC)(GLsizei n, const GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint * samplers); -typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); -typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync); -typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays); -typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); -typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEXOESPROC)(GLfixed n, GLfixed f); -typedef void (GLAD_API_PTR *PFNGLDETACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB attachedObj); -typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); -typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); -typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); -typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); -typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void * indirect); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDARBPROC)(GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDEXTPROC)(GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf); -typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs); -typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSARBPROC)(GLsizei n, const GLenum * bufs); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void * indirect); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDARBPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLuint baseinstance); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices); -typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id); -typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount); -typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream); -typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); -typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); -typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); -typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYARBPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void); -typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLENDQUERYARBPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void); -typedef void (GLAD_API_PTR *PFNGLEVALCOORD1XOESPROC)(GLfixed u); -typedef void (GLAD_API_PTR *PFNGLEVALCOORD1XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLEVALCOORD2XOESPROC)(GLfixed u, GLfixed v); -typedef void (GLAD_API_PTR *PFNGLEVALCOORD2XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLEVALUATEDEPTHVALUESARBPROC)(void); -typedef void (GLAD_API_PTR *PFNGLFEEDBACKBUFFERXOESPROC)(GLsizei n, GLenum type, const GLfixed * buffer); -typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); -typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); -typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); -typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); -typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (GLAD_API_PTR *PFNGLFOGCOORDPOINTEREXTPROC)(GLenum type, GLsizei stride, const void * pointer); -typedef void (GLAD_API_PTR *PFNGLFOGCOORDDEXTPROC)(GLdouble coord); -typedef void (GLAD_API_PTR *PFNGLFOGCOORDDVEXTPROC)(const GLdouble * coord); -typedef void (GLAD_API_PTR *PFNGLFOGCOORDFEXTPROC)(GLfloat coord); -typedef void (GLAD_API_PTR *PFNGLFOGCOORDFVEXTPROC)(const GLfloat * coord); -typedef void (GLAD_API_PTR *PFNGLFOGXOESPROC)(GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLFOGXVOESPROC)(GLenum pname, const GLfixed * param); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLenum target, GLuint start, GLsizei count, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREFACEARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLFRUSTUMXOESPROC)(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); -typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLGENBUFFERSARBPROC)(GLsizei n, GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); -typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSEXTPROC)(GLsizei n, GLuint * framebuffers); -typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint * pipelines); -typedef void (GLAD_API_PTR *PFNGLGENPROGRAMSARBPROC)(GLsizei n, GLuint * programs); -typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLGENQUERIESARBPROC)(GLsizei n, GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSEXTPROC)(GLsizei n, GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint * samplers); -typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays); -typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPEXTPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLGENERATETEXTUREMIPMAPPROC)(GLuint texture); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, GLint * size, GLenum * type, GLcharARB * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint * values); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, GLint * size, GLenum * type, GLcharARB * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformBlockName); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformName); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint * uniformIndices, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETATTACHEDOBJECTSARBPROC)(GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj); -typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); -typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); -typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB * name); -typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data); -typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVARBPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVARBPROC)(GLenum target, GLenum pname, void ** params); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data); -typedef void (GLAD_API_PTR *PFNGLGETCLIPPLANEXOESPROC)(GLenum plane, GLfixed * equation); -typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img); -typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint level, void * img); -typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLsizei bufSize, void * pixels); -typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void * pixels); -typedef void (GLAD_API_PTR *PFNGLGETCONVOLUTIONPARAMETERXVOESPROC)(GLenum target, GLenum pname, GLfixed * params); -typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); -typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); -typedef void (GLAD_API_PTR *PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble * data); -typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data); -typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); -typedef void (GLAD_API_PTR *PFNGLGETFIXEDVOESPROC)(GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat * data); -typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); -typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar * name); -typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef GLhandleARB (GLAD_API_PTR *PFNGLGETHANDLEARBPROC)(GLenum pname); -typedef void (GLAD_API_PTR *PFNGLGETHISTOGRAMPARAMETERXVOESPROC)(GLenum target, GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETINFOLOGARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 * data); -typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data); -typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data); -typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); -typedef void (GLAD_API_PTR *PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETLIGHTXOESPROC)(GLenum light, GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETMAPXVOESPROC)(GLenum target, GLenum query, GLfixed * v); -typedef void (GLAD_API_PTR *PFNGLGETMATERIALXOESPROC)(GLenum face, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)(GLuint buffer, GLenum pname, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERPARAMETERIVPROC)(GLuint buffer, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERPOINTERVPROC)(GLuint buffer, GLenum pname, void ** params); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, void * data); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLuint framebuffer, GLenum attachment, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)(GLuint framebuffer, GLenum pname, GLint * param); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)(GLuint renderbuffer, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDSTRINGARBPROC)(GLint namelen, const GLchar * name, GLsizei bufSize, GLint * stringlen, GLchar * string); -typedef void (GLAD_API_PTR *PFNGLGETNAMEDSTRINGIVARBPROC)(GLint namelen, const GLchar * name, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTPARAMETERFVARBPROC)(GLhandleARB obj, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTPARAMETERIVARBPROC)(GLhandleARB obj, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); -typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPXVPROC)(GLenum map, GLint size, GLfixed * values); -typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum pname, void ** params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMENVPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMENVPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint * params); -typedef GLuint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar * name); -typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar * name); -typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum * props, GLsizei count, GLsizei * length, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint * values); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMSTRINGARBPROC)(GLenum target, GLenum pname, void * string); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVARBPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTUI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTUIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (GLAD_API_PTR *PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVARBPROC)(GLuint id, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVARBPROC)(GLuint id, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYIVARBPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision); -typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); -typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source); -typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); -typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); -typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); -typedef GLuint (GLAD_API_PTR *PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar * name); -typedef GLint (GLAD_API_PTR *PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei * length, GLint * values); -typedef void (GLAD_API_PTR *PFNGLGETTEXENVXVOESPROC)(GLenum target, GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXGENXVOESPROC)(GLenum coord, GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels); -typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERXVOESPROC)(GLenum target, GLint level, GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERXVOESPROC)(GLenum target, GLenum pname, GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void * pixels); -typedef void (GLAD_API_PTR *PFNGLGETTEXTURELEVELPARAMETERFVPROC)(GLuint texture, GLint level, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTURELEVELPARAMETERIVPROC)(GLuint texture, GLint level, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void * pixels); -typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKI64_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint64 * param); -typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKI_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint * param); -typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKIVPROC)(GLuint xfb, GLenum pname, GLint * param); -typedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar * uniformBlockName); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const* uniformNames, GLuint * uniformIndices); -typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); -typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB * name); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVARBPROC)(GLhandleARB programObj, GLint location, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMI64VARBPROC)(GLuint program, GLint location, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVARBPROC)(GLhandleARB programObj, GLint location, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUI64VARBPROC)(GLuint program, GLint location, GLuint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXARRAYINDEXED64IVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint64 * param); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXARRAYINDEXEDIVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint * param); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXARRAYIVPROC)(GLuint vaobj, GLenum pname, GLint * param); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVARBPROC)(GLuint index, GLenum pname, void ** pointer); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVARBPROC)(GLuint index, GLenum pname, GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVARBPROC)(GLuint index, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVARBPROC)(GLuint index, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMI64VARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUI64VARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint64 * params); -typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLINDEXXOESPROC)(GLfixed component); -typedef void (GLAD_API_PTR *PFNGLINDEXXVOESPROC)(const GLfixed * component); -typedef void (GLAD_API_PTR *PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (GLAD_API_PTR *PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments); -typedef void (GLAD_API_PTR *PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum * attachments); -typedef void (GLAD_API_PTR *PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum * attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); -typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERARBPROC)(GLuint buffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); -typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index); -typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFEREXTPROC)(GLuint framebuffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISNAMEDSTRINGARBPROC)(GLint namelen, const GLchar * name); -typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); -typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMARBPROC)(GLuint program); -typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline); -typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id); -typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYARBPROC)(GLuint id); -typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFEREXTPROC)(GLuint renderbuffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint sampler); -typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); -typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync); -typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); -typedef GLboolean (GLAD_API_PTR *PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id); -typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array); -typedef void (GLAD_API_PTR *PFNGLLIGHTMODELXOESPROC)(GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLLIGHTMODELXVOESPROC)(GLenum pname, const GLfixed * param); -typedef void (GLAD_API_PTR *PFNGLLIGHTXOESPROC)(GLenum light, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLLIGHTXVOESPROC)(GLenum light, GLenum pname, const GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); -typedef void (GLAD_API_PTR *PFNGLLINEWIDTHXOESPROC)(GLfixed width); -typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMARBPROC)(GLhandleARB programObj); -typedef void (GLAD_API_PTR *PFNGLLOADMATRIXXOESPROC)(const GLfixed * m); -typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXDARBPROC)(const GLdouble * m); -typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXFARBPROC)(const GLfloat * m); -typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXXOESPROC)(const GLfixed * m); -typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode); -typedef void (GLAD_API_PTR *PFNGLMAP1XOESPROC)(GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); -typedef void (GLAD_API_PTR *PFNGLMAP2XOESPROC)(GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); -typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); -typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERARBPROC)(GLenum target, GLenum access); -typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (GLAD_API_PTR *PFNGLMAPGRID1XOESPROC)(GLint n, GLfixed u1, GLfixed u2); -typedef void (GLAD_API_PTR *PFNGLMAPGRID2XOESPROC)(GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); -typedef void * (GLAD_API_PTR *PFNGLMAPNAMEDBUFFERPROC)(GLuint buffer, GLenum access); -typedef void * (GLAD_API_PTR *PFNGLMAPNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (GLAD_API_PTR *PFNGLMATERIALXOESPROC)(GLenum face, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLMATERIALXVOESPROC)(GLenum face, GLenum pname, const GLfixed * param); -typedef void (GLAD_API_PTR *PFNGLMEMORYBARRIERPROC)(GLbitfield barriers); -typedef void (GLAD_API_PTR *PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers); -typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGPROC)(GLfloat value); -typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGARBPROC)(GLfloat value); -typedef void (GLAD_API_PTR *PFNGLMULTMATRIXXOESPROC)(const GLfixed * m); -typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXDARBPROC)(const GLdouble * m); -typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXFARBPROC)(const GLfloat * m); -typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXXOESPROC)(const GLfixed * m); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void * indirect, GLsizei drawcount, GLsizei stride); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void * indirect, GLsizei drawcount, GLsizei stride); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DARBPROC)(GLenum target, GLdouble s); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DVARBPROC)(GLenum target, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FARBPROC)(GLenum target, GLfloat s); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FVARBPROC)(GLenum target, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IARBPROC)(GLenum target, GLint s); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IVARBPROC)(GLenum target, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SARBPROC)(GLenum target, GLshort s); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SVARBPROC)(GLenum target, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1XOESPROC)(GLenum texture, GLfixed s); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1XVOESPROC)(GLenum texture, const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DARBPROC)(GLenum target, GLdouble s, GLdouble t); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DVARBPROC)(GLenum target, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FARBPROC)(GLenum target, GLfloat s, GLfloat t); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FVARBPROC)(GLenum target, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IARBPROC)(GLenum target, GLint s, GLint t); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IVARBPROC)(GLenum target, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SARBPROC)(GLenum target, GLshort s, GLshort t); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SVARBPROC)(GLenum target, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2XOESPROC)(GLenum texture, GLfixed s, GLfixed t); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2XVOESPROC)(GLenum texture, const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DARBPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DVARBPROC)(GLenum target, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FARBPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FVARBPROC)(GLenum target, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IARBPROC)(GLenum target, GLint s, GLint t, GLint r); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IVARBPROC)(GLenum target, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SARBPROC)(GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SVARBPROC)(GLenum target, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3XOESPROC)(GLenum texture, GLfixed s, GLfixed t, GLfixed r); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3XVOESPROC)(GLenum texture, const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DARBPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DVARBPROC)(GLenum target, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FARBPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FVARBPROC)(GLenum target, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IARBPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IVARBPROC)(GLenum target, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SARBPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SVARBPROC)(GLenum target, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4XOESPROC)(GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); -typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4XVOESPROC)(GLenum texture, const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERDATAPROC)(GLuint buffer, GLsizeiptr size, const void * data, GLenum usage); -typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEPROC)(GLuint buffer, GLsizeiptr size, const void * data, GLbitfield flags); -typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, const void * data); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)(GLuint framebuffer, GLenum buf); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)(GLuint framebuffer, GLsizei n, const GLenum * bufs); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)(GLuint framebuffer, GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)(GLuint framebuffer, GLenum src); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (GLAD_API_PTR *PFNGLNAMEDRENDERBUFFERSTORAGEPROC)(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLNAMEDSTRINGARBPROC)(GLenum type, GLint namelen, const GLchar * name, GLint stringlen, const GLchar * string); -typedef void (GLAD_API_PTR *PFNGLNORMAL3XOESPROC)(GLfixed nx, GLfixed ny, GLfixed nz); -typedef void (GLAD_API_PTR *PFNGLNORMAL3XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); -typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELPROC)(const void * ptr, GLsizei length, const GLchar * label); -typedef void (GLAD_API_PTR *PFNGLORTHOXOESPROC)(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); -typedef void (GLAD_API_PTR *PFNGLPASSTHROUGHXOESPROC)(GLfixed token); -typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat * values); -typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value); -typedef void (GLAD_API_PTR *PFNGLPAUSETRANSFORMFEEDBACKPROC)(void); -typedef void (GLAD_API_PTR *PFNGLPIXELMAPXPROC)(GLenum map, GLint size, const GLfixed * values); -typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); -typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLPIXELSTOREXPROC)(GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERXOESPROC)(GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLPIXELZOOMXOESPROC)(GLfixed xfactor, GLfixed yfactor); -typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); -typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERXVOESPROC)(GLenum pname, const GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size); -typedef void (GLAD_API_PTR *PFNGLPOINTSIZEXOESPROC)(GLfixed size); -typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); -typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETXOESPROC)(GLfixed factor, GLfixed units); -typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPPROC)(void); -typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXARBPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); -typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLPRIORITIZETEXTURESXOESPROC)(GLsizei n, const GLuint * textures, const GLfixed * priorities); -typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLsizei length); -typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble * params); -typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIARBPROC)(GLuint program, GLenum pname, GLint value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMSTRINGARBPROC)(GLenum target, GLenum format, GLsizei len, const void * string); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1I64ARBPROC)(GLuint program, GLint location, GLint64 x); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UI64ARBPROC)(GLuint program, GLint location, GLuint64 x); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2I64ARBPROC)(GLuint program, GLint location, GLint64 x, GLint64 y); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UI64ARBPROC)(GLuint program, GLint location, GLuint64 x, GLuint64 y); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3I64ARBPROC)(GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UI64ARBPROC)(GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4I64ARBPROC)(GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UI64ARBPROC)(GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); -typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); -typedef void (GLAD_API_PTR *PFNGLRASTERPOS2XOESPROC)(GLfixed x, GLfixed y); -typedef void (GLAD_API_PTR *PFNGLRASTERPOS2XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLRASTERPOS3XOESPROC)(GLfixed x, GLfixed y, GLfixed z); -typedef void (GLAD_API_PTR *PFNGLRASTERPOS3XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLRASTERPOS4XOESPROC)(GLfixed x, GLfixed y, GLfixed z, GLfixed w); -typedef void (GLAD_API_PTR *PFNGLRASTERPOS4XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src); -typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); -typedef void (GLAD_API_PTR *PFNGLRECTXOESPROC)(GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); -typedef void (GLAD_API_PTR *PFNGLRECTXVOESPROC)(const GLfixed * v1, const GLfixed * v2); -typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void); -typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void); -typedef void (GLAD_API_PTR *PFNGLROTATEXOESPROC)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z); -typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); -typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); -typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint * param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint * param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat * param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint * param); -typedef void (GLAD_API_PTR *PFNGLSCALEXOESPROC)(GLfixed x, GLfixed y, GLfixed z); -typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length); -typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); -typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEARBPROC)(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** string, const GLint * length); -typedef void (GLAD_API_PTR *PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); -typedef void (GLAD_API_PTR *PFNGLSPECIALIZESHADERARBPROC)(GLuint shader, const GLchar * pEntryPoint, GLuint numSpecializationConstants, const GLuint * pConstantIndex, const GLuint * pConstantValue); -typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); -typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD1XOESPROC)(GLfixed s); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD1XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD2XOESPROC)(GLfixed s, GLfixed t); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD2XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD3XOESPROC)(GLfixed s, GLfixed t, GLfixed r); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD3XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD4XOESPROC)(GLfixed s, GLfixed t, GLfixed r, GLfixed q); -typedef void (GLAD_API_PTR *PFNGLTEXCOORD4XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLTEXENVXOESPROC)(GLenum target, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLTEXENVXVOESPROC)(GLenum target, GLenum pname, const GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLTEXGENXOESPROC)(GLenum coord, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLTEXGENXVOESPROC)(GLenum coord, GLenum pname, const GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERXOESPROC)(GLenum target, GLenum pname, GLfixed param); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERXVOESPROC)(GLenum target, GLenum pname, const GLfixed * params); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXTUREBUFFERPROC)(GLuint texture, GLenum internalformat, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLTEXTUREBUFFERRANGEPROC)(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, const GLuint * params); -typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERFPROC)(GLuint texture, GLenum pname, GLfloat param); -typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, const GLfloat * param); -typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIPROC)(GLuint texture, GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, const GLint * param); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE1DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)(GLuint xfb, GLuint index, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode); -typedef void (GLAD_API_PTR *PFNGLTRANSLATEXOESPROC)(GLfixed x, GLfixed y, GLfixed z); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1DPROC)(GLint location, GLdouble x); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1FARBPROC)(GLint location, GLfloat v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1I64ARBPROC)(GLint location, GLint64 x); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1I64VARBPROC)(GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1IARBPROC)(GLint location, GLint v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVARBPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1UI64ARBPROC)(GLint location, GLuint64 x); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1UI64VARBPROC)(GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2FARBPROC)(GLint location, GLfloat v0, GLfloat v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2I64ARBPROC)(GLint location, GLint64 x, GLint64 y); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2I64VARBPROC)(GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2IARBPROC)(GLint location, GLint v0, GLint v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVARBPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2UI64ARBPROC)(GLint location, GLuint64 x, GLuint64 y); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2UI64VARBPROC)(GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3FARBPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3I64ARBPROC)(GLint location, GLint64 x, GLint64 y, GLint64 z); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3I64VARBPROC)(GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3IARBPROC)(GLint location, GLint v0, GLint v1, GLint v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVARBPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3UI64ARBPROC)(GLint location, GLuint64 x, GLuint64 y, GLuint64 z); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3UI64VARBPROC)(GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4FARBPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4I64ARBPROC)(GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4I64VARBPROC)(GLint location, GLsizei count, const GLint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4IARBPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVARBPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4UI64ARBPROC)(GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4UI64VARBPROC)(GLint location, GLsizei count, const GLuint64 * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint * indices); -typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target); -typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERARBPROC)(GLenum target); -typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPNAMEDBUFFERPROC)(GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMOBJECTARBPROC)(GLhandleARB programObj); -typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program); -typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMARBPROC)(GLhandleARB programObj); -typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline); -typedef void (GLAD_API_PTR *PFNGLVERTEX2XOESPROC)(GLfixed x); -typedef void (GLAD_API_PTR *PFNGLVERTEX2XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLVERTEX3XOESPROC)(GLfixed x, GLfixed y); -typedef void (GLAD_API_PTR *PFNGLVERTEX3XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLVERTEX4XOESPROC)(GLfixed x, GLfixed y, GLfixed z); -typedef void (GLAD_API_PTR *PFNGLVERTEX4XVOESPROC)(const GLfixed * coords); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBBINDINGPROC)(GLuint vaobj, GLuint attribindex, GLuint bindingindex); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBIFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBLFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYBINDINGDIVISORPROC)(GLuint vaobj, GLuint bindingindex, GLuint divisor); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYELEMENTBUFFERPROC)(GLuint vaobj, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYVERTEXBUFFERPROC)(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYVERTEXBUFFERSPROC)(GLuint vaobj, GLuint first, GLsizei count, const GLuint * buffers, const GLintptr * offsets, const GLsizei * strides); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DARBPROC)(GLuint index, GLdouble x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVARBPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FARBPROC)(GLuint index, GLfloat x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVARBPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SARBPROC)(GLuint index, GLshort x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVARBPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DARBPROC)(GLuint index, GLdouble x, GLdouble y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVARBPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FARBPROC)(GLuint index, GLfloat x, GLfloat y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVARBPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SARBPROC)(GLuint index, GLshort x, GLshort y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVARBPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVARBPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVARBPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVARBPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVARBPROC)(GLuint index, const GLbyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVARBPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVARBPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBARBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVARBPROC)(GLuint index, const GLubyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVARBPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVARBPROC)(GLuint index, const GLushort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVARBPROC)(GLuint index, const GLbyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVARBPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVARBPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVARBPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVARBPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVARBPROC)(GLuint index, const GLubyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVARBPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVARBPROC)(GLuint index, const GLushort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORARBPROC)(GLuint index, GLuint divisor); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERARBPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); -typedef void (GLAD_API_PTR *PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); - -GLAD_API_CALL PFNGLACCUMXOESPROC glad_glAccumxOES; -#define glAccumxOES glad_glAccumxOES -GLAD_API_CALL PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram; -#define glActiveShaderProgram glad_glActiveShaderProgram -GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; -#define glActiveTexture glad_glActiveTexture -GLAD_API_CALL PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB; -#define glActiveTextureARB glad_glActiveTextureARB -GLAD_API_CALL PFNGLALPHAFUNCXOESPROC glad_glAlphaFuncxOES; -#define glAlphaFuncxOES glad_glAlphaFuncxOES -GLAD_API_CALL PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB; -#define glAttachObjectARB glad_glAttachObjectARB -GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; -#define glAttachShader glad_glAttachShader -GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; -#define glBeginConditionalRender glad_glBeginConditionalRender -GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery; -#define glBeginQuery glad_glBeginQuery -GLAD_API_CALL PFNGLBEGINQUERYARBPROC glad_glBeginQueryARB; -#define glBeginQueryARB glad_glBeginQueryARB -GLAD_API_CALL PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed; -#define glBeginQueryIndexed glad_glBeginQueryIndexed -GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; -#define glBeginTransformFeedback glad_glBeginTransformFeedback -GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; -#define glBindAttribLocation glad_glBindAttribLocation -GLAD_API_CALL PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB; -#define glBindAttribLocationARB glad_glBindAttribLocationARB -GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; -#define glBindBuffer glad_glBindBuffer -GLAD_API_CALL PFNGLBINDBUFFERARBPROC glad_glBindBufferARB; -#define glBindBufferARB glad_glBindBufferARB -GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; -#define glBindBufferBase glad_glBindBufferBase -GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; -#define glBindBufferRange glad_glBindBufferRange -GLAD_API_CALL PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase; -#define glBindBuffersBase glad_glBindBuffersBase -GLAD_API_CALL PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange; -#define glBindBuffersRange glad_glBindBuffersRange -GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; -#define glBindFragDataLocation glad_glBindFragDataLocation -GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; -#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed -GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; -#define glBindFramebuffer glad_glBindFramebuffer -GLAD_API_CALL PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT; -#define glBindFramebufferEXT glad_glBindFramebufferEXT -GLAD_API_CALL PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture; -#define glBindImageTexture glad_glBindImageTexture -GLAD_API_CALL PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures; -#define glBindImageTextures glad_glBindImageTextures -GLAD_API_CALL PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB; -#define glBindProgramARB glad_glBindProgramARB -GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline; -#define glBindProgramPipeline glad_glBindProgramPipeline -GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; -#define glBindRenderbuffer glad_glBindRenderbuffer -GLAD_API_CALL PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT; -#define glBindRenderbufferEXT glad_glBindRenderbufferEXT -GLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler; -#define glBindSampler glad_glBindSampler -GLAD_API_CALL PFNGLBINDSAMPLERSPROC glad_glBindSamplers; -#define glBindSamplers glad_glBindSamplers -GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; -#define glBindTexture glad_glBindTexture -GLAD_API_CALL PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit; -#define glBindTextureUnit glad_glBindTextureUnit -GLAD_API_CALL PFNGLBINDTEXTURESPROC glad_glBindTextures; -#define glBindTextures glad_glBindTextures -GLAD_API_CALL PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback; -#define glBindTransformFeedback glad_glBindTransformFeedback -GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; -#define glBindVertexArray glad_glBindVertexArray -GLAD_API_CALL PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer; -#define glBindVertexBuffer glad_glBindVertexBuffer -GLAD_API_CALL PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers; -#define glBindVertexBuffers glad_glBindVertexBuffers -GLAD_API_CALL PFNGLBITMAPXOESPROC glad_glBitmapxOES; -#define glBitmapxOES glad_glBitmapxOES -GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; -#define glBlendColor glad_glBlendColor -GLAD_API_CALL PFNGLBLENDCOLORXOESPROC glad_glBlendColorxOES; -#define glBlendColorxOES glad_glBlendColorxOES -GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; -#define glBlendEquation glad_glBlendEquation -GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; -#define glBlendEquationSeparate glad_glBlendEquationSeparate -GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei; -#define glBlendEquationSeparatei glad_glBlendEquationSeparatei -GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB; -#define glBlendEquationSeparateiARB glad_glBlendEquationSeparateiARB -GLAD_API_CALL PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi; -#define glBlendEquationi glad_glBlendEquationi -GLAD_API_CALL PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB; -#define glBlendEquationiARB glad_glBlendEquationiARB -GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; -#define glBlendFunc glad_glBlendFunc -GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; -#define glBlendFuncSeparate glad_glBlendFuncSeparate -GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei; -#define glBlendFuncSeparatei glad_glBlendFuncSeparatei -GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB; -#define glBlendFuncSeparateiARB glad_glBlendFuncSeparateiARB -GLAD_API_CALL PFNGLBLENDFUNCIPROC glad_glBlendFunci; -#define glBlendFunci glad_glBlendFunci -GLAD_API_CALL PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB; -#define glBlendFunciARB glad_glBlendFunciARB -GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; -#define glBlitFramebuffer glad_glBlitFramebuffer -GLAD_API_CALL PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT; -#define glBlitFramebufferEXT glad_glBlitFramebufferEXT -GLAD_API_CALL PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer; -#define glBlitNamedFramebuffer glad_glBlitNamedFramebuffer -GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; -#define glBufferData glad_glBufferData -GLAD_API_CALL PFNGLBUFFERDATAARBPROC glad_glBufferDataARB; -#define glBufferDataARB glad_glBufferDataARB -GLAD_API_CALL PFNGLBUFFERSTORAGEPROC glad_glBufferStorage; -#define glBufferStorage glad_glBufferStorage -GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; -#define glBufferSubData glad_glBufferSubData -GLAD_API_CALL PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB; -#define glBufferSubDataARB glad_glBufferSubDataARB -GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; -#define glCheckFramebufferStatus glad_glCheckFramebufferStatus -GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT; -#define glCheckFramebufferStatusEXT glad_glCheckFramebufferStatusEXT -GLAD_API_CALL PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus; -#define glCheckNamedFramebufferStatus glad_glCheckNamedFramebufferStatus -GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor; -#define glClampColor glad_glClampColor -GLAD_API_CALL PFNGLCLAMPCOLORARBPROC glad_glClampColorARB; -#define glClampColorARB glad_glClampColorARB -GLAD_API_CALL PFNGLCLEARPROC glad_glClear; -#define glClear glad_glClear -GLAD_API_CALL PFNGLCLEARACCUMXOESPROC glad_glClearAccumxOES; -#define glClearAccumxOES glad_glClearAccumxOES -GLAD_API_CALL PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData; -#define glClearBufferData glad_glClearBufferData -GLAD_API_CALL PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData; -#define glClearBufferSubData glad_glClearBufferSubData -GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; -#define glClearBufferfi glad_glClearBufferfi -GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; -#define glClearBufferfv glad_glClearBufferfv -GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; -#define glClearBufferiv glad_glClearBufferiv -GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; -#define glClearBufferuiv glad_glClearBufferuiv -GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; -#define glClearColor glad_glClearColor -GLAD_API_CALL PFNGLCLEARCOLORXOESPROC glad_glClearColorxOES; -#define glClearColorxOES glad_glClearColorxOES -GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth; -#define glClearDepth glad_glClearDepth -GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf; -#define glClearDepthf glad_glClearDepthf -GLAD_API_CALL PFNGLCLEARDEPTHXOESPROC glad_glClearDepthxOES; -#define glClearDepthxOES glad_glClearDepthxOES -GLAD_API_CALL PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData; -#define glClearNamedBufferData glad_glClearNamedBufferData -GLAD_API_CALL PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData; -#define glClearNamedBufferSubData glad_glClearNamedBufferSubData -GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi; -#define glClearNamedFramebufferfi glad_glClearNamedFramebufferfi -GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv; -#define glClearNamedFramebufferfv glad_glClearNamedFramebufferfv -GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv; -#define glClearNamedFramebufferiv glad_glClearNamedFramebufferiv -GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv; -#define glClearNamedFramebufferuiv glad_glClearNamedFramebufferuiv -GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; -#define glClearStencil glad_glClearStencil -GLAD_API_CALL PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage; -#define glClearTexImage glad_glClearTexImage -GLAD_API_CALL PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage; -#define glClearTexSubImage glad_glClearTexSubImage -GLAD_API_CALL PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB; -#define glClientActiveTextureARB glad_glClientActiveTextureARB -GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; -#define glClientWaitSync glad_glClientWaitSync -GLAD_API_CALL PFNGLCLIPPLANEXOESPROC glad_glClipPlanexOES; -#define glClipPlanexOES glad_glClipPlanexOES -GLAD_API_CALL PFNGLCOLOR3XOESPROC glad_glColor3xOES; -#define glColor3xOES glad_glColor3xOES -GLAD_API_CALL PFNGLCOLOR3XVOESPROC glad_glColor3xvOES; -#define glColor3xvOES glad_glColor3xvOES -GLAD_API_CALL PFNGLCOLOR4XOESPROC glad_glColor4xOES; -#define glColor4xOES glad_glColor4xOES -GLAD_API_CALL PFNGLCOLOR4XVOESPROC glad_glColor4xvOES; -#define glColor4xvOES glad_glColor4xvOES -GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; -#define glColorMask glad_glColorMask -GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski; -#define glColorMaski glad_glColorMaski -GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; -#define glCompileShader glad_glCompileShader -GLAD_API_CALL PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB; -#define glCompileShaderARB glad_glCompileShaderARB -GLAD_API_CALL PFNGLCOMPILESHADERINCLUDEARBPROC glad_glCompileShaderIncludeARB; -#define glCompileShaderIncludeARB glad_glCompileShaderIncludeARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; -#define glCompressedTexImage1D glad_glCompressedTexImage1D -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB; -#define glCompressedTexImage1DARB glad_glCompressedTexImage1DARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; -#define glCompressedTexImage2D glad_glCompressedTexImage2D -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB; -#define glCompressedTexImage2DARB glad_glCompressedTexImage2DARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; -#define glCompressedTexImage3D glad_glCompressedTexImage3D -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB; -#define glCompressedTexImage3DARB glad_glCompressedTexImage3DARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; -#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB; -#define glCompressedTexSubImage1DARB glad_glCompressedTexSubImage1DARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; -#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB; -#define glCompressedTexSubImage2DARB glad_glCompressedTexSubImage2DARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; -#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB; -#define glCompressedTexSubImage3DARB glad_glCompressedTexSubImage3DARB -GLAD_API_CALL PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D; -#define glCompressedTextureSubImage1D glad_glCompressedTextureSubImage1D -GLAD_API_CALL PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D; -#define glCompressedTextureSubImage2D glad_glCompressedTextureSubImage2D -GLAD_API_CALL PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D; -#define glCompressedTextureSubImage3D glad_glCompressedTextureSubImage3D -GLAD_API_CALL PFNGLCONVOLUTIONPARAMETERXOESPROC glad_glConvolutionParameterxOES; -#define glConvolutionParameterxOES glad_glConvolutionParameterxOES -GLAD_API_CALL PFNGLCONVOLUTIONPARAMETERXVOESPROC glad_glConvolutionParameterxvOES; -#define glConvolutionParameterxvOES glad_glConvolutionParameterxvOES -GLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; -#define glCopyBufferSubData glad_glCopyBufferSubData -GLAD_API_CALL PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData; -#define glCopyImageSubData glad_glCopyImageSubData -GLAD_API_CALL PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData; -#define glCopyNamedBufferSubData glad_glCopyNamedBufferSubData -GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; -#define glCopyTexImage1D glad_glCopyTexImage1D -GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; -#define glCopyTexImage2D glad_glCopyTexImage2D -GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; -#define glCopyTexSubImage1D glad_glCopyTexSubImage1D -GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; -#define glCopyTexSubImage2D glad_glCopyTexSubImage2D -GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; -#define glCopyTexSubImage3D glad_glCopyTexSubImage3D -GLAD_API_CALL PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D; -#define glCopyTextureSubImage1D glad_glCopyTextureSubImage1D -GLAD_API_CALL PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D; -#define glCopyTextureSubImage2D glad_glCopyTextureSubImage2D -GLAD_API_CALL PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D; -#define glCopyTextureSubImage3D glad_glCopyTextureSubImage3D -GLAD_API_CALL PFNGLCREATEBUFFERSPROC glad_glCreateBuffers; -#define glCreateBuffers glad_glCreateBuffers -GLAD_API_CALL PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers; -#define glCreateFramebuffers glad_glCreateFramebuffers -GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; -#define glCreateProgram glad_glCreateProgram -GLAD_API_CALL PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB; -#define glCreateProgramObjectARB glad_glCreateProgramObjectARB -GLAD_API_CALL PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines; -#define glCreateProgramPipelines glad_glCreateProgramPipelines -GLAD_API_CALL PFNGLCREATEQUERIESPROC glad_glCreateQueries; -#define glCreateQueries glad_glCreateQueries -GLAD_API_CALL PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers; -#define glCreateRenderbuffers glad_glCreateRenderbuffers -GLAD_API_CALL PFNGLCREATESAMPLERSPROC glad_glCreateSamplers; -#define glCreateSamplers glad_glCreateSamplers -GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; -#define glCreateShader glad_glCreateShader -GLAD_API_CALL PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB; -#define glCreateShaderObjectARB glad_glCreateShaderObjectARB -GLAD_API_CALL PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv; -#define glCreateShaderProgramv glad_glCreateShaderProgramv -GLAD_API_CALL PFNGLCREATETEXTURESPROC glad_glCreateTextures; -#define glCreateTextures glad_glCreateTextures -GLAD_API_CALL PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks; -#define glCreateTransformFeedbacks glad_glCreateTransformFeedbacks -GLAD_API_CALL PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays; -#define glCreateVertexArrays glad_glCreateVertexArrays -GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; -#define glCullFace glad_glCullFace -GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; -#define glDebugMessageCallback glad_glDebugMessageCallback -GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB; -#define glDebugMessageCallbackARB glad_glDebugMessageCallbackARB -GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; -#define glDebugMessageControl glad_glDebugMessageControl -GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB; -#define glDebugMessageControlARB glad_glDebugMessageControlARB -GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; -#define glDebugMessageInsert glad_glDebugMessageInsert -GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB; -#define glDebugMessageInsertARB glad_glDebugMessageInsertARB -GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; -#define glDeleteBuffers glad_glDeleteBuffers -GLAD_API_CALL PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB; -#define glDeleteBuffersARB glad_glDeleteBuffersARB -GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; -#define glDeleteFramebuffers glad_glDeleteFramebuffers -GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT; -#define glDeleteFramebuffersEXT glad_glDeleteFramebuffersEXT -GLAD_API_CALL PFNGLDELETENAMEDSTRINGARBPROC glad_glDeleteNamedStringARB; -#define glDeleteNamedStringARB glad_glDeleteNamedStringARB -GLAD_API_CALL PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB; -#define glDeleteObjectARB glad_glDeleteObjectARB -GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; -#define glDeleteProgram glad_glDeleteProgram -GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines; -#define glDeleteProgramPipelines glad_glDeleteProgramPipelines -GLAD_API_CALL PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB; -#define glDeleteProgramsARB glad_glDeleteProgramsARB -GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries; -#define glDeleteQueries glad_glDeleteQueries -GLAD_API_CALL PFNGLDELETEQUERIESARBPROC glad_glDeleteQueriesARB; -#define glDeleteQueriesARB glad_glDeleteQueriesARB -GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; -#define glDeleteRenderbuffers glad_glDeleteRenderbuffers -GLAD_API_CALL PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT; -#define glDeleteRenderbuffersEXT glad_glDeleteRenderbuffersEXT -GLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; -#define glDeleteSamplers glad_glDeleteSamplers -GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; -#define glDeleteShader glad_glDeleteShader -GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync; -#define glDeleteSync glad_glDeleteSync -GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; -#define glDeleteTextures glad_glDeleteTextures -GLAD_API_CALL PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks; -#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks -GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; -#define glDeleteVertexArrays glad_glDeleteVertexArrays -GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; -#define glDepthFunc glad_glDepthFunc -GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; -#define glDepthMask glad_glDepthMask -GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange; -#define glDepthRange glad_glDepthRange -GLAD_API_CALL PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv; -#define glDepthRangeArrayv glad_glDepthRangeArrayv -GLAD_API_CALL PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed; -#define glDepthRangeIndexed glad_glDepthRangeIndexed -GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef; -#define glDepthRangef glad_glDepthRangef -GLAD_API_CALL PFNGLDEPTHRANGEXOESPROC glad_glDepthRangexOES; -#define glDepthRangexOES glad_glDepthRangexOES -GLAD_API_CALL PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB; -#define glDetachObjectARB glad_glDetachObjectARB -GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; -#define glDetachShader glad_glDetachShader -GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; -#define glDisable glad_glDisable -GLAD_API_CALL PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib; -#define glDisableVertexArrayAttrib glad_glDisableVertexArrayAttrib -GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; -#define glDisableVertexAttribArray glad_glDisableVertexAttribArray -GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB; -#define glDisableVertexAttribArrayARB glad_glDisableVertexAttribArrayARB -GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei; -#define glDisablei glad_glDisablei -GLAD_API_CALL PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute; -#define glDispatchCompute glad_glDispatchCompute -GLAD_API_CALL PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC glad_glDispatchComputeGroupSizeARB; -#define glDispatchComputeGroupSizeARB glad_glDispatchComputeGroupSizeARB -GLAD_API_CALL PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect; -#define glDispatchComputeIndirect glad_glDispatchComputeIndirect -GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; -#define glDrawArrays glad_glDrawArrays -GLAD_API_CALL PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect; -#define glDrawArraysIndirect glad_glDrawArraysIndirect -GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; -#define glDrawArraysInstanced glad_glDrawArraysInstanced -GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB; -#define glDrawArraysInstancedARB glad_glDrawArraysInstancedARB -GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance; -#define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance -GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT; -#define glDrawArraysInstancedEXT glad_glDrawArraysInstancedEXT -GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer; -#define glDrawBuffer glad_glDrawBuffer -GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; -#define glDrawBuffers glad_glDrawBuffers -GLAD_API_CALL PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB; -#define glDrawBuffersARB glad_glDrawBuffersARB -GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; -#define glDrawElements glad_glDrawElements -GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; -#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex -GLAD_API_CALL PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect; -#define glDrawElementsIndirect glad_glDrawElementsIndirect -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; -#define glDrawElementsInstanced glad_glDrawElementsInstanced -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB; -#define glDrawElementsInstancedARB glad_glDrawElementsInstancedARB -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance; -#define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; -#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance; -#define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT; -#define glDrawElementsInstancedEXT glad_glDrawElementsInstancedEXT -GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; -#define glDrawRangeElements glad_glDrawRangeElements -GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; -#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex -GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback; -#define glDrawTransformFeedback glad_glDrawTransformFeedback -GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced; -#define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced -GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream; -#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream -GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced; -#define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced -GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; -#define glEnable glad_glEnable -GLAD_API_CALL PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib; -#define glEnableVertexArrayAttrib glad_glEnableVertexArrayAttrib -GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; -#define glEnableVertexAttribArray glad_glEnableVertexAttribArray -GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB; -#define glEnableVertexAttribArrayARB glad_glEnableVertexAttribArrayARB -GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei; -#define glEnablei glad_glEnablei -GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; -#define glEndConditionalRender glad_glEndConditionalRender -GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery; -#define glEndQuery glad_glEndQuery -GLAD_API_CALL PFNGLENDQUERYARBPROC glad_glEndQueryARB; -#define glEndQueryARB glad_glEndQueryARB -GLAD_API_CALL PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed; -#define glEndQueryIndexed glad_glEndQueryIndexed -GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; -#define glEndTransformFeedback glad_glEndTransformFeedback -GLAD_API_CALL PFNGLEVALCOORD1XOESPROC glad_glEvalCoord1xOES; -#define glEvalCoord1xOES glad_glEvalCoord1xOES -GLAD_API_CALL PFNGLEVALCOORD1XVOESPROC glad_glEvalCoord1xvOES; -#define glEvalCoord1xvOES glad_glEvalCoord1xvOES -GLAD_API_CALL PFNGLEVALCOORD2XOESPROC glad_glEvalCoord2xOES; -#define glEvalCoord2xOES glad_glEvalCoord2xOES -GLAD_API_CALL PFNGLEVALCOORD2XVOESPROC glad_glEvalCoord2xvOES; -#define glEvalCoord2xvOES glad_glEvalCoord2xvOES -GLAD_API_CALL PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB; -#define glEvaluateDepthValuesARB glad_glEvaluateDepthValuesARB -GLAD_API_CALL PFNGLFEEDBACKBUFFERXOESPROC glad_glFeedbackBufferxOES; -#define glFeedbackBufferxOES glad_glFeedbackBufferxOES -GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync; -#define glFenceSync glad_glFenceSync -GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; -#define glFinish glad_glFinish -GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; -#define glFlush glad_glFlush -GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; -#define glFlushMappedBufferRange glad_glFlushMappedBufferRange -GLAD_API_CALL PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange; -#define glFlushMappedNamedBufferRange glad_glFlushMappedNamedBufferRange -GLAD_API_CALL PFNGLFOGCOORDPOINTEREXTPROC glad_glFogCoordPointerEXT; -#define glFogCoordPointerEXT glad_glFogCoordPointerEXT -GLAD_API_CALL PFNGLFOGCOORDDEXTPROC glad_glFogCoorddEXT; -#define glFogCoorddEXT glad_glFogCoorddEXT -GLAD_API_CALL PFNGLFOGCOORDDVEXTPROC glad_glFogCoorddvEXT; -#define glFogCoorddvEXT glad_glFogCoorddvEXT -GLAD_API_CALL PFNGLFOGCOORDFEXTPROC glad_glFogCoordfEXT; -#define glFogCoordfEXT glad_glFogCoordfEXT -GLAD_API_CALL PFNGLFOGCOORDFVEXTPROC glad_glFogCoordfvEXT; -#define glFogCoordfvEXT glad_glFogCoordfvEXT -GLAD_API_CALL PFNGLFOGXOESPROC glad_glFogxOES; -#define glFogxOES glad_glFogxOES -GLAD_API_CALL PFNGLFOGXVOESPROC glad_glFogxvOES; -#define glFogxvOES glad_glFogxvOES -GLAD_API_CALL PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri; -#define glFramebufferParameteri glad_glFramebufferParameteri -GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; -#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer -GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT; -#define glFramebufferRenderbufferEXT glad_glFramebufferRenderbufferEXT -GLAD_API_CALL PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB; -#define glFramebufferSampleLocationsfvARB glad_glFramebufferSampleLocationsfvARB -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; -#define glFramebufferTexture glad_glFramebufferTexture -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; -#define glFramebufferTexture1D glad_glFramebufferTexture1D -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT; -#define glFramebufferTexture1DEXT glad_glFramebufferTexture1DEXT -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; -#define glFramebufferTexture2D glad_glFramebufferTexture2D -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT; -#define glFramebufferTexture2DEXT glad_glFramebufferTexture2DEXT -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; -#define glFramebufferTexture3D glad_glFramebufferTexture3D -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT; -#define glFramebufferTexture3DEXT glad_glFramebufferTexture3DEXT -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB; -#define glFramebufferTextureARB glad_glFramebufferTextureARB -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB; -#define glFramebufferTextureFaceARB glad_glFramebufferTextureFaceARB -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; -#define glFramebufferTextureLayer glad_glFramebufferTextureLayer -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB; -#define glFramebufferTextureLayerARB glad_glFramebufferTextureLayerARB -GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; -#define glFrontFace glad_glFrontFace -GLAD_API_CALL PFNGLFRUSTUMXOESPROC glad_glFrustumxOES; -#define glFrustumxOES glad_glFrustumxOES -GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; -#define glGenBuffers glad_glGenBuffers -GLAD_API_CALL PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB; -#define glGenBuffersARB glad_glGenBuffersARB -GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; -#define glGenFramebuffers glad_glGenFramebuffers -GLAD_API_CALL PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT; -#define glGenFramebuffersEXT glad_glGenFramebuffersEXT -GLAD_API_CALL PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines; -#define glGenProgramPipelines glad_glGenProgramPipelines -GLAD_API_CALL PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB; -#define glGenProgramsARB glad_glGenProgramsARB -GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries; -#define glGenQueries glad_glGenQueries -GLAD_API_CALL PFNGLGENQUERIESARBPROC glad_glGenQueriesARB; -#define glGenQueriesARB glad_glGenQueriesARB -GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; -#define glGenRenderbuffers glad_glGenRenderbuffers -GLAD_API_CALL PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT; -#define glGenRenderbuffersEXT glad_glGenRenderbuffersEXT -GLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers; -#define glGenSamplers glad_glGenSamplers -GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; -#define glGenTextures glad_glGenTextures -GLAD_API_CALL PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks; -#define glGenTransformFeedbacks glad_glGenTransformFeedbacks -GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; -#define glGenVertexArrays glad_glGenVertexArrays -GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; -#define glGenerateMipmap glad_glGenerateMipmap -GLAD_API_CALL PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; -#define glGenerateMipmapEXT glad_glGenerateMipmapEXT -GLAD_API_CALL PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap; -#define glGenerateTextureMipmap glad_glGenerateTextureMipmap -GLAD_API_CALL PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv; -#define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv -GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; -#define glGetActiveAttrib glad_glGetActiveAttrib -GLAD_API_CALL PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB; -#define glGetActiveAttribARB glad_glGetActiveAttribARB -GLAD_API_CALL PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName; -#define glGetActiveSubroutineName glad_glGetActiveSubroutineName -GLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName; -#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName -GLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv; -#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv -GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; -#define glGetActiveUniform glad_glGetActiveUniform -GLAD_API_CALL PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB; -#define glGetActiveUniformARB glad_glGetActiveUniformARB -GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; -#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName -GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; -#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv -GLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; -#define glGetActiveUniformName glad_glGetActiveUniformName -GLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; -#define glGetActiveUniformsiv glad_glGetActiveUniformsiv -GLAD_API_CALL PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB; -#define glGetAttachedObjectsARB glad_glGetAttachedObjectsARB -GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; -#define glGetAttachedShaders glad_glGetAttachedShaders -GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; -#define glGetAttribLocation glad_glGetAttribLocation -GLAD_API_CALL PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB; -#define glGetAttribLocationARB glad_glGetAttribLocationARB -GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; -#define glGetBooleani_v glad_glGetBooleani_v -GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; -#define glGetBooleanv glad_glGetBooleanv -GLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; -#define glGetBufferParameteri64v glad_glGetBufferParameteri64v -GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; -#define glGetBufferParameteriv glad_glGetBufferParameteriv -GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB; -#define glGetBufferParameterivARB glad_glGetBufferParameterivARB -GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; -#define glGetBufferPointerv glad_glGetBufferPointerv -GLAD_API_CALL PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB; -#define glGetBufferPointervARB glad_glGetBufferPointervARB -GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; -#define glGetBufferSubData glad_glGetBufferSubData -GLAD_API_CALL PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB; -#define glGetBufferSubDataARB glad_glGetBufferSubDataARB -GLAD_API_CALL PFNGLGETCLIPPLANEXOESPROC glad_glGetClipPlanexOES; -#define glGetClipPlanexOES glad_glGetClipPlanexOES -GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; -#define glGetCompressedTexImage glad_glGetCompressedTexImage -GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB; -#define glGetCompressedTexImageARB glad_glGetCompressedTexImageARB -GLAD_API_CALL PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage; -#define glGetCompressedTextureImage glad_glGetCompressedTextureImage -GLAD_API_CALL PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage; -#define glGetCompressedTextureSubImage glad_glGetCompressedTextureSubImage -GLAD_API_CALL PFNGLGETCONVOLUTIONPARAMETERXVOESPROC glad_glGetConvolutionParameterxvOES; -#define glGetConvolutionParameterxvOES glad_glGetConvolutionParameterxvOES -GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; -#define glGetDebugMessageLog glad_glGetDebugMessageLog -GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB; -#define glGetDebugMessageLogARB glad_glGetDebugMessageLogARB -GLAD_API_CALL PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v; -#define glGetDoublei_v glad_glGetDoublei_v -GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev; -#define glGetDoublev glad_glGetDoublev -GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; -#define glGetError glad_glGetError -GLAD_API_CALL PFNGLGETFIXEDVOESPROC glad_glGetFixedvOES; -#define glGetFixedvOES glad_glGetFixedvOES -GLAD_API_CALL PFNGLGETFLOATI_VPROC glad_glGetFloati_v; -#define glGetFloati_v glad_glGetFloati_v -GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; -#define glGetFloatv glad_glGetFloatv -GLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; -#define glGetFragDataIndex glad_glGetFragDataIndex -GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; -#define glGetFragDataLocation glad_glGetFragDataLocation -GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; -#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv -GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT; -#define glGetFramebufferAttachmentParameterivEXT glad_glGetFramebufferAttachmentParameterivEXT -GLAD_API_CALL PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv; -#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv -GLAD_API_CALL PFNGLGETHANDLEARBPROC glad_glGetHandleARB; -#define glGetHandleARB glad_glGetHandleARB -GLAD_API_CALL PFNGLGETHISTOGRAMPARAMETERXVOESPROC glad_glGetHistogramParameterxvOES; -#define glGetHistogramParameterxvOES glad_glGetHistogramParameterxvOES -GLAD_API_CALL PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB; -#define glGetInfoLogARB glad_glGetInfoLogARB -GLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; -#define glGetInteger64i_v glad_glGetInteger64i_v -GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v; -#define glGetInteger64v glad_glGetInteger64v -GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; -#define glGetIntegeri_v glad_glGetIntegeri_v -GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; -#define glGetIntegerv glad_glGetIntegerv -GLAD_API_CALL PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v; -#define glGetInternalformati64v glad_glGetInternalformati64v -GLAD_API_CALL PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ; -#define glGetInternalformativ glad_glGetInternalformativ -GLAD_API_CALL PFNGLGETLIGHTXOESPROC glad_glGetLightxOES; -#define glGetLightxOES glad_glGetLightxOES -GLAD_API_CALL PFNGLGETMAPXVOESPROC glad_glGetMapxvOES; -#define glGetMapxvOES glad_glGetMapxvOES -GLAD_API_CALL PFNGLGETMATERIALXOESPROC glad_glGetMaterialxOES; -#define glGetMaterialxOES glad_glGetMaterialxOES -GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; -#define glGetMultisamplefv glad_glGetMultisamplefv -GLAD_API_CALL PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v; -#define glGetNamedBufferParameteri64v glad_glGetNamedBufferParameteri64v -GLAD_API_CALL PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv; -#define glGetNamedBufferParameteriv glad_glGetNamedBufferParameteriv -GLAD_API_CALL PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv; -#define glGetNamedBufferPointerv glad_glGetNamedBufferPointerv -GLAD_API_CALL PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData; -#define glGetNamedBufferSubData glad_glGetNamedBufferSubData -GLAD_API_CALL PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv; -#define glGetNamedFramebufferAttachmentParameteriv glad_glGetNamedFramebufferAttachmentParameteriv -GLAD_API_CALL PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv; -#define glGetNamedFramebufferParameteriv glad_glGetNamedFramebufferParameteriv -GLAD_API_CALL PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv; -#define glGetNamedRenderbufferParameteriv glad_glGetNamedRenderbufferParameteriv -GLAD_API_CALL PFNGLGETNAMEDSTRINGARBPROC glad_glGetNamedStringARB; -#define glGetNamedStringARB glad_glGetNamedStringARB -GLAD_API_CALL PFNGLGETNAMEDSTRINGIVARBPROC glad_glGetNamedStringivARB; -#define glGetNamedStringivARB glad_glGetNamedStringivARB -GLAD_API_CALL PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; -#define glGetObjectLabel glad_glGetObjectLabel -GLAD_API_CALL PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB; -#define glGetObjectParameterfvARB glad_glGetObjectParameterfvARB -GLAD_API_CALL PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB; -#define glGetObjectParameterivARB glad_glGetObjectParameterivARB -GLAD_API_CALL PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; -#define glGetObjectPtrLabel glad_glGetObjectPtrLabel -GLAD_API_CALL PFNGLGETPIXELMAPXVPROC glad_glGetPixelMapxv; -#define glGetPixelMapxv glad_glGetPixelMapxv -GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv; -#define glGetPointerv glad_glGetPointerv -GLAD_API_CALL PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary; -#define glGetProgramBinary glad_glGetProgramBinary -GLAD_API_CALL PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB; -#define glGetProgramEnvParameterdvARB glad_glGetProgramEnvParameterdvARB -GLAD_API_CALL PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB; -#define glGetProgramEnvParameterfvARB glad_glGetProgramEnvParameterfvARB -GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; -#define glGetProgramInfoLog glad_glGetProgramInfoLog -GLAD_API_CALL PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv; -#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv -GLAD_API_CALL PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB; -#define glGetProgramLocalParameterdvARB glad_glGetProgramLocalParameterdvARB -GLAD_API_CALL PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB; -#define glGetProgramLocalParameterfvARB glad_glGetProgramLocalParameterfvARB -GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog; -#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog -GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv; -#define glGetProgramPipelineiv glad_glGetProgramPipelineiv -GLAD_API_CALL PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex; -#define glGetProgramResourceIndex glad_glGetProgramResourceIndex -GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation; -#define glGetProgramResourceLocation glad_glGetProgramResourceLocation -GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex; -#define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex -GLAD_API_CALL PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName; -#define glGetProgramResourceName glad_glGetProgramResourceName -GLAD_API_CALL PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv; -#define glGetProgramResourceiv glad_glGetProgramResourceiv -GLAD_API_CALL PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv; -#define glGetProgramStageiv glad_glGetProgramStageiv -GLAD_API_CALL PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB; -#define glGetProgramStringARB glad_glGetProgramStringARB -GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; -#define glGetProgramiv glad_glGetProgramiv -GLAD_API_CALL PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB; -#define glGetProgramivARB glad_glGetProgramivARB -GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v; -#define glGetQueryBufferObjecti64v glad_glGetQueryBufferObjecti64v -GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv; -#define glGetQueryBufferObjectiv glad_glGetQueryBufferObjectiv -GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v; -#define glGetQueryBufferObjectui64v glad_glGetQueryBufferObjectui64v -GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv; -#define glGetQueryBufferObjectuiv glad_glGetQueryBufferObjectuiv -GLAD_API_CALL PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv; -#define glGetQueryIndexediv glad_glGetQueryIndexediv -GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; -#define glGetQueryObjecti64v glad_glGetQueryObjecti64v -GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; -#define glGetQueryObjectiv glad_glGetQueryObjectiv -GLAD_API_CALL PFNGLGETQUERYOBJECTIVARBPROC glad_glGetQueryObjectivARB; -#define glGetQueryObjectivARB glad_glGetQueryObjectivARB -GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; -#define glGetQueryObjectui64v glad_glGetQueryObjectui64v -GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; -#define glGetQueryObjectuiv glad_glGetQueryObjectuiv -GLAD_API_CALL PFNGLGETQUERYOBJECTUIVARBPROC glad_glGetQueryObjectuivARB; -#define glGetQueryObjectuivARB glad_glGetQueryObjectuivARB -GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv; -#define glGetQueryiv glad_glGetQueryiv -GLAD_API_CALL PFNGLGETQUERYIVARBPROC glad_glGetQueryivARB; -#define glGetQueryivARB glad_glGetQueryivARB -GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; -#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv -GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT; -#define glGetRenderbufferParameterivEXT glad_glGetRenderbufferParameterivEXT -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; -#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; -#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; -#define glGetSamplerParameterfv glad_glGetSamplerParameterfv -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; -#define glGetSamplerParameteriv glad_glGetSamplerParameteriv -GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; -#define glGetShaderInfoLog glad_glGetShaderInfoLog -GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; -#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat -GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; -#define glGetShaderSource glad_glGetShaderSource -GLAD_API_CALL PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB; -#define glGetShaderSourceARB glad_glGetShaderSourceARB -GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; -#define glGetShaderiv glad_glGetShaderiv -GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; -#define glGetString glad_glGetString -GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi; -#define glGetStringi glad_glGetStringi -GLAD_API_CALL PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex; -#define glGetSubroutineIndex glad_glGetSubroutineIndex -GLAD_API_CALL PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation; -#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation -GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv; -#define glGetSynciv glad_glGetSynciv -GLAD_API_CALL PFNGLGETTEXENVXVOESPROC glad_glGetTexEnvxvOES; -#define glGetTexEnvxvOES glad_glGetTexEnvxvOES -GLAD_API_CALL PFNGLGETTEXGENXVOESPROC glad_glGetTexGenxvOES; -#define glGetTexGenxvOES glad_glGetTexGenxvOES -GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage; -#define glGetTexImage glad_glGetTexImage -GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; -#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv -GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; -#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv -GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERXVOESPROC glad_glGetTexLevelParameterxvOES; -#define glGetTexLevelParameterxvOES glad_glGetTexLevelParameterxvOES -GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; -#define glGetTexParameterIiv glad_glGetTexParameterIiv -GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; -#define glGetTexParameterIuiv glad_glGetTexParameterIuiv -GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; -#define glGetTexParameterfv glad_glGetTexParameterfv -GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; -#define glGetTexParameteriv glad_glGetTexParameteriv -GLAD_API_CALL PFNGLGETTEXPARAMETERXVOESPROC glad_glGetTexParameterxvOES; -#define glGetTexParameterxvOES glad_glGetTexParameterxvOES -GLAD_API_CALL PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage; -#define glGetTextureImage glad_glGetTextureImage -GLAD_API_CALL PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv; -#define glGetTextureLevelParameterfv glad_glGetTextureLevelParameterfv -GLAD_API_CALL PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv; -#define glGetTextureLevelParameteriv glad_glGetTextureLevelParameteriv -GLAD_API_CALL PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv; -#define glGetTextureParameterIiv glad_glGetTextureParameterIiv -GLAD_API_CALL PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv; -#define glGetTextureParameterIuiv glad_glGetTextureParameterIuiv -GLAD_API_CALL PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv; -#define glGetTextureParameterfv glad_glGetTextureParameterfv -GLAD_API_CALL PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv; -#define glGetTextureParameteriv glad_glGetTextureParameteriv -GLAD_API_CALL PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage; -#define glGetTextureSubImage glad_glGetTextureSubImage -GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; -#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying -GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v; -#define glGetTransformFeedbacki64_v glad_glGetTransformFeedbacki64_v -GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v; -#define glGetTransformFeedbacki_v glad_glGetTransformFeedbacki_v -GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv; -#define glGetTransformFeedbackiv glad_glGetTransformFeedbackiv -GLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; -#define glGetUniformBlockIndex glad_glGetUniformBlockIndex -GLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; -#define glGetUniformIndices glad_glGetUniformIndices -GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; -#define glGetUniformLocation glad_glGetUniformLocation -GLAD_API_CALL PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB; -#define glGetUniformLocationARB glad_glGetUniformLocationARB -GLAD_API_CALL PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv; -#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv -GLAD_API_CALL PFNGLGETUNIFORMDVPROC glad_glGetUniformdv; -#define glGetUniformdv glad_glGetUniformdv -GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; -#define glGetUniformfv glad_glGetUniformfv -GLAD_API_CALL PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB; -#define glGetUniformfvARB glad_glGetUniformfvARB -GLAD_API_CALL PFNGLGETUNIFORMI64VARBPROC glad_glGetUniformi64vARB; -#define glGetUniformi64vARB glad_glGetUniformi64vARB -GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; -#define glGetUniformiv glad_glGetUniformiv -GLAD_API_CALL PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB; -#define glGetUniformivARB glad_glGetUniformivARB -GLAD_API_CALL PFNGLGETUNIFORMUI64VARBPROC glad_glGetUniformui64vARB; -#define glGetUniformui64vARB glad_glGetUniformui64vARB -GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; -#define glGetUniformuiv glad_glGetUniformuiv -GLAD_API_CALL PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv; -#define glGetVertexArrayIndexed64iv glad_glGetVertexArrayIndexed64iv -GLAD_API_CALL PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv; -#define glGetVertexArrayIndexediv glad_glGetVertexArrayIndexediv -GLAD_API_CALL PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv; -#define glGetVertexArrayiv glad_glGetVertexArrayiv -GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; -#define glGetVertexAttribIiv glad_glGetVertexAttribIiv -GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; -#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv -GLAD_API_CALL PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv; -#define glGetVertexAttribLdv glad_glGetVertexAttribLdv -GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; -#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv -GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB; -#define glGetVertexAttribPointervARB glad_glGetVertexAttribPointervARB -GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; -#define glGetVertexAttribdv glad_glGetVertexAttribdv -GLAD_API_CALL PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB; -#define glGetVertexAttribdvARB glad_glGetVertexAttribdvARB -GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; -#define glGetVertexAttribfv glad_glGetVertexAttribfv -GLAD_API_CALL PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB; -#define glGetVertexAttribfvARB glad_glGetVertexAttribfvARB -GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; -#define glGetVertexAttribiv glad_glGetVertexAttribiv -GLAD_API_CALL PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB; -#define glGetVertexAttribivARB glad_glGetVertexAttribivARB -GLAD_API_CALL PFNGLGETNUNIFORMI64VARBPROC glad_glGetnUniformi64vARB; -#define glGetnUniformi64vARB glad_glGetnUniformi64vARB -GLAD_API_CALL PFNGLGETNUNIFORMUI64VARBPROC glad_glGetnUniformui64vARB; -#define glGetnUniformui64vARB glad_glGetnUniformui64vARB -GLAD_API_CALL PFNGLHINTPROC glad_glHint; -#define glHint glad_glHint -GLAD_API_CALL PFNGLINDEXXOESPROC glad_glIndexxOES; -#define glIndexxOES glad_glIndexxOES -GLAD_API_CALL PFNGLINDEXXVOESPROC glad_glIndexxvOES; -#define glIndexxvOES glad_glIndexxvOES -GLAD_API_CALL PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData; -#define glInvalidateBufferData glad_glInvalidateBufferData -GLAD_API_CALL PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData; -#define glInvalidateBufferSubData glad_glInvalidateBufferSubData -GLAD_API_CALL PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer; -#define glInvalidateFramebuffer glad_glInvalidateFramebuffer -GLAD_API_CALL PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData; -#define glInvalidateNamedFramebufferData glad_glInvalidateNamedFramebufferData -GLAD_API_CALL PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData; -#define glInvalidateNamedFramebufferSubData glad_glInvalidateNamedFramebufferSubData -GLAD_API_CALL PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer; -#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer -GLAD_API_CALL PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage; -#define glInvalidateTexImage glad_glInvalidateTexImage -GLAD_API_CALL PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage; -#define glInvalidateTexSubImage glad_glInvalidateTexSubImage -GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; -#define glIsBuffer glad_glIsBuffer -GLAD_API_CALL PFNGLISBUFFERARBPROC glad_glIsBufferARB; -#define glIsBufferARB glad_glIsBufferARB -GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; -#define glIsEnabled glad_glIsEnabled -GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi; -#define glIsEnabledi glad_glIsEnabledi -GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; -#define glIsFramebuffer glad_glIsFramebuffer -GLAD_API_CALL PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT; -#define glIsFramebufferEXT glad_glIsFramebufferEXT -GLAD_API_CALL PFNGLISNAMEDSTRINGARBPROC glad_glIsNamedStringARB; -#define glIsNamedStringARB glad_glIsNamedStringARB -GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; -#define glIsProgram glad_glIsProgram -GLAD_API_CALL PFNGLISPROGRAMARBPROC glad_glIsProgramARB; -#define glIsProgramARB glad_glIsProgramARB -GLAD_API_CALL PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline; -#define glIsProgramPipeline glad_glIsProgramPipeline -GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery; -#define glIsQuery glad_glIsQuery -GLAD_API_CALL PFNGLISQUERYARBPROC glad_glIsQueryARB; -#define glIsQueryARB glad_glIsQueryARB -GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; -#define glIsRenderbuffer glad_glIsRenderbuffer -GLAD_API_CALL PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT; -#define glIsRenderbufferEXT glad_glIsRenderbufferEXT -GLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler; -#define glIsSampler glad_glIsSampler -GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; -#define glIsShader glad_glIsShader -GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync; -#define glIsSync glad_glIsSync -GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; -#define glIsTexture glad_glIsTexture -GLAD_API_CALL PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback; -#define glIsTransformFeedback glad_glIsTransformFeedback -GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; -#define glIsVertexArray glad_glIsVertexArray -GLAD_API_CALL PFNGLLIGHTMODELXOESPROC glad_glLightModelxOES; -#define glLightModelxOES glad_glLightModelxOES -GLAD_API_CALL PFNGLLIGHTMODELXVOESPROC glad_glLightModelxvOES; -#define glLightModelxvOES glad_glLightModelxvOES -GLAD_API_CALL PFNGLLIGHTXOESPROC glad_glLightxOES; -#define glLightxOES glad_glLightxOES -GLAD_API_CALL PFNGLLIGHTXVOESPROC glad_glLightxvOES; -#define glLightxvOES glad_glLightxvOES -GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; -#define glLineWidth glad_glLineWidth -GLAD_API_CALL PFNGLLINEWIDTHXOESPROC glad_glLineWidthxOES; -#define glLineWidthxOES glad_glLineWidthxOES -GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; -#define glLinkProgram glad_glLinkProgram -GLAD_API_CALL PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB; -#define glLinkProgramARB glad_glLinkProgramARB -GLAD_API_CALL PFNGLLOADMATRIXXOESPROC glad_glLoadMatrixxOES; -#define glLoadMatrixxOES glad_glLoadMatrixxOES -GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXDARBPROC glad_glLoadTransposeMatrixdARB; -#define glLoadTransposeMatrixdARB glad_glLoadTransposeMatrixdARB -GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXFARBPROC glad_glLoadTransposeMatrixfARB; -#define glLoadTransposeMatrixfARB glad_glLoadTransposeMatrixfARB -GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXXOESPROC glad_glLoadTransposeMatrixxOES; -#define glLoadTransposeMatrixxOES glad_glLoadTransposeMatrixxOES -GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp; -#define glLogicOp glad_glLogicOp -GLAD_API_CALL PFNGLMAP1XOESPROC glad_glMap1xOES; -#define glMap1xOES glad_glMap1xOES -GLAD_API_CALL PFNGLMAP2XOESPROC glad_glMap2xOES; -#define glMap2xOES glad_glMap2xOES -GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer; -#define glMapBuffer glad_glMapBuffer -GLAD_API_CALL PFNGLMAPBUFFERARBPROC glad_glMapBufferARB; -#define glMapBufferARB glad_glMapBufferARB -GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; -#define glMapBufferRange glad_glMapBufferRange -GLAD_API_CALL PFNGLMAPGRID1XOESPROC glad_glMapGrid1xOES; -#define glMapGrid1xOES glad_glMapGrid1xOES -GLAD_API_CALL PFNGLMAPGRID2XOESPROC glad_glMapGrid2xOES; -#define glMapGrid2xOES glad_glMapGrid2xOES -GLAD_API_CALL PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer; -#define glMapNamedBuffer glad_glMapNamedBuffer -GLAD_API_CALL PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange; -#define glMapNamedBufferRange glad_glMapNamedBufferRange -GLAD_API_CALL PFNGLMATERIALXOESPROC glad_glMaterialxOES; -#define glMaterialxOES glad_glMaterialxOES -GLAD_API_CALL PFNGLMATERIALXVOESPROC glad_glMaterialxvOES; -#define glMaterialxvOES glad_glMaterialxvOES -GLAD_API_CALL PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier; -#define glMemoryBarrier glad_glMemoryBarrier -GLAD_API_CALL PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion; -#define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion -GLAD_API_CALL PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading; -#define glMinSampleShading glad_glMinSampleShading -GLAD_API_CALL PFNGLMINSAMPLESHADINGARBPROC glad_glMinSampleShadingARB; -#define glMinSampleShadingARB glad_glMinSampleShadingARB -GLAD_API_CALL PFNGLMULTMATRIXXOESPROC glad_glMultMatrixxOES; -#define glMultMatrixxOES glad_glMultMatrixxOES -GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXDARBPROC glad_glMultTransposeMatrixdARB; -#define glMultTransposeMatrixdARB glad_glMultTransposeMatrixdARB -GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXFARBPROC glad_glMultTransposeMatrixfARB; -#define glMultTransposeMatrixfARB glad_glMultTransposeMatrixfARB -GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXXOESPROC glad_glMultTransposeMatrixxOES; -#define glMultTransposeMatrixxOES glad_glMultTransposeMatrixxOES -GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; -#define glMultiDrawArrays glad_glMultiDrawArrays -GLAD_API_CALL PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect; -#define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect -GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; -#define glMultiDrawElements glad_glMultiDrawElements -GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; -#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex -GLAD_API_CALL PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect; -#define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect -GLAD_API_CALL PFNGLMULTITEXCOORD1DARBPROC glad_glMultiTexCoord1dARB; -#define glMultiTexCoord1dARB glad_glMultiTexCoord1dARB -GLAD_API_CALL PFNGLMULTITEXCOORD1DVARBPROC glad_glMultiTexCoord1dvARB; -#define glMultiTexCoord1dvARB glad_glMultiTexCoord1dvARB -GLAD_API_CALL PFNGLMULTITEXCOORD1FARBPROC glad_glMultiTexCoord1fARB; -#define glMultiTexCoord1fARB glad_glMultiTexCoord1fARB -GLAD_API_CALL PFNGLMULTITEXCOORD1FVARBPROC glad_glMultiTexCoord1fvARB; -#define glMultiTexCoord1fvARB glad_glMultiTexCoord1fvARB -GLAD_API_CALL PFNGLMULTITEXCOORD1IARBPROC glad_glMultiTexCoord1iARB; -#define glMultiTexCoord1iARB glad_glMultiTexCoord1iARB -GLAD_API_CALL PFNGLMULTITEXCOORD1IVARBPROC glad_glMultiTexCoord1ivARB; -#define glMultiTexCoord1ivARB glad_glMultiTexCoord1ivARB -GLAD_API_CALL PFNGLMULTITEXCOORD1SARBPROC glad_glMultiTexCoord1sARB; -#define glMultiTexCoord1sARB glad_glMultiTexCoord1sARB -GLAD_API_CALL PFNGLMULTITEXCOORD1SVARBPROC glad_glMultiTexCoord1svARB; -#define glMultiTexCoord1svARB glad_glMultiTexCoord1svARB -GLAD_API_CALL PFNGLMULTITEXCOORD1XOESPROC glad_glMultiTexCoord1xOES; -#define glMultiTexCoord1xOES glad_glMultiTexCoord1xOES -GLAD_API_CALL PFNGLMULTITEXCOORD1XVOESPROC glad_glMultiTexCoord1xvOES; -#define glMultiTexCoord1xvOES glad_glMultiTexCoord1xvOES -GLAD_API_CALL PFNGLMULTITEXCOORD2DARBPROC glad_glMultiTexCoord2dARB; -#define glMultiTexCoord2dARB glad_glMultiTexCoord2dARB -GLAD_API_CALL PFNGLMULTITEXCOORD2DVARBPROC glad_glMultiTexCoord2dvARB; -#define glMultiTexCoord2dvARB glad_glMultiTexCoord2dvARB -GLAD_API_CALL PFNGLMULTITEXCOORD2FARBPROC glad_glMultiTexCoord2fARB; -#define glMultiTexCoord2fARB glad_glMultiTexCoord2fARB -GLAD_API_CALL PFNGLMULTITEXCOORD2FVARBPROC glad_glMultiTexCoord2fvARB; -#define glMultiTexCoord2fvARB glad_glMultiTexCoord2fvARB -GLAD_API_CALL PFNGLMULTITEXCOORD2IARBPROC glad_glMultiTexCoord2iARB; -#define glMultiTexCoord2iARB glad_glMultiTexCoord2iARB -GLAD_API_CALL PFNGLMULTITEXCOORD2IVARBPROC glad_glMultiTexCoord2ivARB; -#define glMultiTexCoord2ivARB glad_glMultiTexCoord2ivARB -GLAD_API_CALL PFNGLMULTITEXCOORD2SARBPROC glad_glMultiTexCoord2sARB; -#define glMultiTexCoord2sARB glad_glMultiTexCoord2sARB -GLAD_API_CALL PFNGLMULTITEXCOORD2SVARBPROC glad_glMultiTexCoord2svARB; -#define glMultiTexCoord2svARB glad_glMultiTexCoord2svARB -GLAD_API_CALL PFNGLMULTITEXCOORD2XOESPROC glad_glMultiTexCoord2xOES; -#define glMultiTexCoord2xOES glad_glMultiTexCoord2xOES -GLAD_API_CALL PFNGLMULTITEXCOORD2XVOESPROC glad_glMultiTexCoord2xvOES; -#define glMultiTexCoord2xvOES glad_glMultiTexCoord2xvOES -GLAD_API_CALL PFNGLMULTITEXCOORD3DARBPROC glad_glMultiTexCoord3dARB; -#define glMultiTexCoord3dARB glad_glMultiTexCoord3dARB -GLAD_API_CALL PFNGLMULTITEXCOORD3DVARBPROC glad_glMultiTexCoord3dvARB; -#define glMultiTexCoord3dvARB glad_glMultiTexCoord3dvARB -GLAD_API_CALL PFNGLMULTITEXCOORD3FARBPROC glad_glMultiTexCoord3fARB; -#define glMultiTexCoord3fARB glad_glMultiTexCoord3fARB -GLAD_API_CALL PFNGLMULTITEXCOORD3FVARBPROC glad_glMultiTexCoord3fvARB; -#define glMultiTexCoord3fvARB glad_glMultiTexCoord3fvARB -GLAD_API_CALL PFNGLMULTITEXCOORD3IARBPROC glad_glMultiTexCoord3iARB; -#define glMultiTexCoord3iARB glad_glMultiTexCoord3iARB -GLAD_API_CALL PFNGLMULTITEXCOORD3IVARBPROC glad_glMultiTexCoord3ivARB; -#define glMultiTexCoord3ivARB glad_glMultiTexCoord3ivARB -GLAD_API_CALL PFNGLMULTITEXCOORD3SARBPROC glad_glMultiTexCoord3sARB; -#define glMultiTexCoord3sARB glad_glMultiTexCoord3sARB -GLAD_API_CALL PFNGLMULTITEXCOORD3SVARBPROC glad_glMultiTexCoord3svARB; -#define glMultiTexCoord3svARB glad_glMultiTexCoord3svARB -GLAD_API_CALL PFNGLMULTITEXCOORD3XOESPROC glad_glMultiTexCoord3xOES; -#define glMultiTexCoord3xOES glad_glMultiTexCoord3xOES -GLAD_API_CALL PFNGLMULTITEXCOORD3XVOESPROC glad_glMultiTexCoord3xvOES; -#define glMultiTexCoord3xvOES glad_glMultiTexCoord3xvOES -GLAD_API_CALL PFNGLMULTITEXCOORD4DARBPROC glad_glMultiTexCoord4dARB; -#define glMultiTexCoord4dARB glad_glMultiTexCoord4dARB -GLAD_API_CALL PFNGLMULTITEXCOORD4DVARBPROC glad_glMultiTexCoord4dvARB; -#define glMultiTexCoord4dvARB glad_glMultiTexCoord4dvARB -GLAD_API_CALL PFNGLMULTITEXCOORD4FARBPROC glad_glMultiTexCoord4fARB; -#define glMultiTexCoord4fARB glad_glMultiTexCoord4fARB -GLAD_API_CALL PFNGLMULTITEXCOORD4FVARBPROC glad_glMultiTexCoord4fvARB; -#define glMultiTexCoord4fvARB glad_glMultiTexCoord4fvARB -GLAD_API_CALL PFNGLMULTITEXCOORD4IARBPROC glad_glMultiTexCoord4iARB; -#define glMultiTexCoord4iARB glad_glMultiTexCoord4iARB -GLAD_API_CALL PFNGLMULTITEXCOORD4IVARBPROC glad_glMultiTexCoord4ivARB; -#define glMultiTexCoord4ivARB glad_glMultiTexCoord4ivARB -GLAD_API_CALL PFNGLMULTITEXCOORD4SARBPROC glad_glMultiTexCoord4sARB; -#define glMultiTexCoord4sARB glad_glMultiTexCoord4sARB -GLAD_API_CALL PFNGLMULTITEXCOORD4SVARBPROC glad_glMultiTexCoord4svARB; -#define glMultiTexCoord4svARB glad_glMultiTexCoord4svARB -GLAD_API_CALL PFNGLMULTITEXCOORD4XOESPROC glad_glMultiTexCoord4xOES; -#define glMultiTexCoord4xOES glad_glMultiTexCoord4xOES -GLAD_API_CALL PFNGLMULTITEXCOORD4XVOESPROC glad_glMultiTexCoord4xvOES; -#define glMultiTexCoord4xvOES glad_glMultiTexCoord4xvOES -GLAD_API_CALL PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData; -#define glNamedBufferData glad_glNamedBufferData -GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage; -#define glNamedBufferStorage glad_glNamedBufferStorage -GLAD_API_CALL PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData; -#define glNamedBufferSubData glad_glNamedBufferSubData -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer; -#define glNamedFramebufferDrawBuffer glad_glNamedFramebufferDrawBuffer -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers; -#define glNamedFramebufferDrawBuffers glad_glNamedFramebufferDrawBuffers -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri; -#define glNamedFramebufferParameteri glad_glNamedFramebufferParameteri -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer; -#define glNamedFramebufferReadBuffer glad_glNamedFramebufferReadBuffer -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer; -#define glNamedFramebufferRenderbuffer glad_glNamedFramebufferRenderbuffer -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB; -#define glNamedFramebufferSampleLocationsfvARB glad_glNamedFramebufferSampleLocationsfvARB -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture; -#define glNamedFramebufferTexture glad_glNamedFramebufferTexture -GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer; -#define glNamedFramebufferTextureLayer glad_glNamedFramebufferTextureLayer -GLAD_API_CALL PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage; -#define glNamedRenderbufferStorage glad_glNamedRenderbufferStorage -GLAD_API_CALL PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample; -#define glNamedRenderbufferStorageMultisample glad_glNamedRenderbufferStorageMultisample -GLAD_API_CALL PFNGLNAMEDSTRINGARBPROC glad_glNamedStringARB; -#define glNamedStringARB glad_glNamedStringARB -GLAD_API_CALL PFNGLNORMAL3XOESPROC glad_glNormal3xOES; -#define glNormal3xOES glad_glNormal3xOES -GLAD_API_CALL PFNGLNORMAL3XVOESPROC glad_glNormal3xvOES; -#define glNormal3xvOES glad_glNormal3xvOES -GLAD_API_CALL PFNGLOBJECTLABELPROC glad_glObjectLabel; -#define glObjectLabel glad_glObjectLabel -GLAD_API_CALL PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; -#define glObjectPtrLabel glad_glObjectPtrLabel -GLAD_API_CALL PFNGLORTHOXOESPROC glad_glOrthoxOES; -#define glOrthoxOES glad_glOrthoxOES -GLAD_API_CALL PFNGLPASSTHROUGHXOESPROC glad_glPassThroughxOES; -#define glPassThroughxOES glad_glPassThroughxOES -GLAD_API_CALL PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv; -#define glPatchParameterfv glad_glPatchParameterfv -GLAD_API_CALL PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri; -#define glPatchParameteri glad_glPatchParameteri -GLAD_API_CALL PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback; -#define glPauseTransformFeedback glad_glPauseTransformFeedback -GLAD_API_CALL PFNGLPIXELMAPXPROC glad_glPixelMapx; -#define glPixelMapx glad_glPixelMapx -GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref; -#define glPixelStoref glad_glPixelStoref -GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; -#define glPixelStorei glad_glPixelStorei -GLAD_API_CALL PFNGLPIXELSTOREXPROC glad_glPixelStorex; -#define glPixelStorex glad_glPixelStorex -GLAD_API_CALL PFNGLPIXELTRANSFERXOESPROC glad_glPixelTransferxOES; -#define glPixelTransferxOES glad_glPixelTransferxOES -GLAD_API_CALL PFNGLPIXELZOOMXOESPROC glad_glPixelZoomxOES; -#define glPixelZoomxOES glad_glPixelZoomxOES -GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; -#define glPointParameterf glad_glPointParameterf -GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; -#define glPointParameterfv glad_glPointParameterfv -GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; -#define glPointParameteri glad_glPointParameteri -GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; -#define glPointParameteriv glad_glPointParameteriv -GLAD_API_CALL PFNGLPOINTPARAMETERXVOESPROC glad_glPointParameterxvOES; -#define glPointParameterxvOES glad_glPointParameterxvOES -GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize; -#define glPointSize glad_glPointSize -GLAD_API_CALL PFNGLPOINTSIZEXOESPROC glad_glPointSizexOES; -#define glPointSizexOES glad_glPointSizexOES -GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode; -#define glPolygonMode glad_glPolygonMode -GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; -#define glPolygonOffset glad_glPolygonOffset -GLAD_API_CALL PFNGLPOLYGONOFFSETXOESPROC glad_glPolygonOffsetxOES; -#define glPolygonOffsetxOES glad_glPolygonOffsetxOES -GLAD_API_CALL PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; -#define glPopDebugGroup glad_glPopDebugGroup -GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXARBPROC glad_glPrimitiveBoundingBoxARB; -#define glPrimitiveBoundingBoxARB glad_glPrimitiveBoundingBoxARB -GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; -#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex -GLAD_API_CALL PFNGLPRIORITIZETEXTURESXOESPROC glad_glPrioritizeTexturesxOES; -#define glPrioritizeTexturesxOES glad_glPrioritizeTexturesxOES -GLAD_API_CALL PFNGLPROGRAMBINARYPROC glad_glProgramBinary; -#define glProgramBinary glad_glProgramBinary -GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB; -#define glProgramEnvParameter4dARB glad_glProgramEnvParameter4dARB -GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB; -#define glProgramEnvParameter4dvARB glad_glProgramEnvParameter4dvARB -GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB; -#define glProgramEnvParameter4fARB glad_glProgramEnvParameter4fARB -GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB; -#define glProgramEnvParameter4fvARB glad_glProgramEnvParameter4fvARB -GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB; -#define glProgramLocalParameter4dARB glad_glProgramLocalParameter4dARB -GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB; -#define glProgramLocalParameter4dvARB glad_glProgramLocalParameter4dvARB -GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB; -#define glProgramLocalParameter4fARB glad_glProgramLocalParameter4fARB -GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB; -#define glProgramLocalParameter4fvARB glad_glProgramLocalParameter4fvARB -GLAD_API_CALL PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri; -#define glProgramParameteri glad_glProgramParameteri -GLAD_API_CALL PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB; -#define glProgramParameteriARB glad_glProgramParameteriARB -GLAD_API_CALL PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB; -#define glProgramStringARB glad_glProgramStringARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d; -#define glProgramUniform1d glad_glProgramUniform1d -GLAD_API_CALL PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv; -#define glProgramUniform1dv glad_glProgramUniform1dv -GLAD_API_CALL PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f; -#define glProgramUniform1f glad_glProgramUniform1f -GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv; -#define glProgramUniform1fv glad_glProgramUniform1fv -GLAD_API_CALL PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i; -#define glProgramUniform1i glad_glProgramUniform1i -GLAD_API_CALL PFNGLPROGRAMUNIFORM1I64ARBPROC glad_glProgramUniform1i64ARB; -#define glProgramUniform1i64ARB glad_glProgramUniform1i64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM1I64VARBPROC glad_glProgramUniform1i64vARB; -#define glProgramUniform1i64vARB glad_glProgramUniform1i64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv; -#define glProgramUniform1iv glad_glProgramUniform1iv -GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui; -#define glProgramUniform1ui glad_glProgramUniform1ui -GLAD_API_CALL PFNGLPROGRAMUNIFORM1UI64ARBPROC glad_glProgramUniform1ui64ARB; -#define glProgramUniform1ui64ARB glad_glProgramUniform1ui64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM1UI64VARBPROC glad_glProgramUniform1ui64vARB; -#define glProgramUniform1ui64vARB glad_glProgramUniform1ui64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv; -#define glProgramUniform1uiv glad_glProgramUniform1uiv -GLAD_API_CALL PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d; -#define glProgramUniform2d glad_glProgramUniform2d -GLAD_API_CALL PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv; -#define glProgramUniform2dv glad_glProgramUniform2dv -GLAD_API_CALL PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f; -#define glProgramUniform2f glad_glProgramUniform2f -GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv; -#define glProgramUniform2fv glad_glProgramUniform2fv -GLAD_API_CALL PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i; -#define glProgramUniform2i glad_glProgramUniform2i -GLAD_API_CALL PFNGLPROGRAMUNIFORM2I64ARBPROC glad_glProgramUniform2i64ARB; -#define glProgramUniform2i64ARB glad_glProgramUniform2i64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM2I64VARBPROC glad_glProgramUniform2i64vARB; -#define glProgramUniform2i64vARB glad_glProgramUniform2i64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv; -#define glProgramUniform2iv glad_glProgramUniform2iv -GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui; -#define glProgramUniform2ui glad_glProgramUniform2ui -GLAD_API_CALL PFNGLPROGRAMUNIFORM2UI64ARBPROC glad_glProgramUniform2ui64ARB; -#define glProgramUniform2ui64ARB glad_glProgramUniform2ui64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM2UI64VARBPROC glad_glProgramUniform2ui64vARB; -#define glProgramUniform2ui64vARB glad_glProgramUniform2ui64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv; -#define glProgramUniform2uiv glad_glProgramUniform2uiv -GLAD_API_CALL PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d; -#define glProgramUniform3d glad_glProgramUniform3d -GLAD_API_CALL PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv; -#define glProgramUniform3dv glad_glProgramUniform3dv -GLAD_API_CALL PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f; -#define glProgramUniform3f glad_glProgramUniform3f -GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv; -#define glProgramUniform3fv glad_glProgramUniform3fv -GLAD_API_CALL PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i; -#define glProgramUniform3i glad_glProgramUniform3i -GLAD_API_CALL PFNGLPROGRAMUNIFORM3I64ARBPROC glad_glProgramUniform3i64ARB; -#define glProgramUniform3i64ARB glad_glProgramUniform3i64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM3I64VARBPROC glad_glProgramUniform3i64vARB; -#define glProgramUniform3i64vARB glad_glProgramUniform3i64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv; -#define glProgramUniform3iv glad_glProgramUniform3iv -GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui; -#define glProgramUniform3ui glad_glProgramUniform3ui -GLAD_API_CALL PFNGLPROGRAMUNIFORM3UI64ARBPROC glad_glProgramUniform3ui64ARB; -#define glProgramUniform3ui64ARB glad_glProgramUniform3ui64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM3UI64VARBPROC glad_glProgramUniform3ui64vARB; -#define glProgramUniform3ui64vARB glad_glProgramUniform3ui64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv; -#define glProgramUniform3uiv glad_glProgramUniform3uiv -GLAD_API_CALL PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d; -#define glProgramUniform4d glad_glProgramUniform4d -GLAD_API_CALL PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv; -#define glProgramUniform4dv glad_glProgramUniform4dv -GLAD_API_CALL PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f; -#define glProgramUniform4f glad_glProgramUniform4f -GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv; -#define glProgramUniform4fv glad_glProgramUniform4fv -GLAD_API_CALL PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i; -#define glProgramUniform4i glad_glProgramUniform4i -GLAD_API_CALL PFNGLPROGRAMUNIFORM4I64ARBPROC glad_glProgramUniform4i64ARB; -#define glProgramUniform4i64ARB glad_glProgramUniform4i64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM4I64VARBPROC glad_glProgramUniform4i64vARB; -#define glProgramUniform4i64vARB glad_glProgramUniform4i64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv; -#define glProgramUniform4iv glad_glProgramUniform4iv -GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui; -#define glProgramUniform4ui glad_glProgramUniform4ui -GLAD_API_CALL PFNGLPROGRAMUNIFORM4UI64ARBPROC glad_glProgramUniform4ui64ARB; -#define glProgramUniform4ui64ARB glad_glProgramUniform4ui64ARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM4UI64VARBPROC glad_glProgramUniform4ui64vARB; -#define glProgramUniform4ui64vARB glad_glProgramUniform4ui64vARB -GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv; -#define glProgramUniform4uiv glad_glProgramUniform4uiv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv; -#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv; -#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv; -#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv; -#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv; -#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv; -#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv; -#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv; -#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv; -#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv; -#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv; -#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv; -#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv; -#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv; -#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv; -#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv; -#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv; -#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv; -#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv -GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; -#define glProvokingVertex glad_glProvokingVertex -GLAD_API_CALL PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; -#define glPushDebugGroup glad_glPushDebugGroup -GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter; -#define glQueryCounter glad_glQueryCounter -GLAD_API_CALL PFNGLRASTERPOS2XOESPROC glad_glRasterPos2xOES; -#define glRasterPos2xOES glad_glRasterPos2xOES -GLAD_API_CALL PFNGLRASTERPOS2XVOESPROC glad_glRasterPos2xvOES; -#define glRasterPos2xvOES glad_glRasterPos2xvOES -GLAD_API_CALL PFNGLRASTERPOS3XOESPROC glad_glRasterPos3xOES; -#define glRasterPos3xOES glad_glRasterPos3xOES -GLAD_API_CALL PFNGLRASTERPOS3XVOESPROC glad_glRasterPos3xvOES; -#define glRasterPos3xvOES glad_glRasterPos3xvOES -GLAD_API_CALL PFNGLRASTERPOS4XOESPROC glad_glRasterPos4xOES; -#define glRasterPos4xOES glad_glRasterPos4xOES -GLAD_API_CALL PFNGLRASTERPOS4XVOESPROC glad_glRasterPos4xvOES; -#define glRasterPos4xvOES glad_glRasterPos4xvOES -GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer; -#define glReadBuffer glad_glReadBuffer -GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; -#define glReadPixels glad_glReadPixels -GLAD_API_CALL PFNGLRECTXOESPROC glad_glRectxOES; -#define glRectxOES glad_glRectxOES -GLAD_API_CALL PFNGLRECTXVOESPROC glad_glRectxvOES; -#define glRectxvOES glad_glRectxvOES -GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +GLAPI int GLAD_GL_ARB_ES2_compatibility; +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(); +GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; #define glReleaseShaderCompiler glad_glReleaseShaderCompiler -GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; -#define glRenderbufferStorage glad_glRenderbufferStorage -GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT; -#define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT -GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; -#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample -GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; -#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT -GLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback; -#define glResumeTransformFeedback glad_glResumeTransformFeedback -GLAD_API_CALL PFNGLROTATEXOESPROC glad_glRotatexOES; -#define glRotatexOES glad_glRotatexOES -GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; -#define glSampleCoverage glad_glSampleCoverage -GLAD_API_CALL PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; -#define glSampleCoverageARB glad_glSampleCoverageARB -GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski; -#define glSampleMaski glad_glSampleMaski -GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; -#define glSamplerParameterIiv glad_glSamplerParameterIiv -GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; -#define glSamplerParameterIuiv glad_glSamplerParameterIuiv -GLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; -#define glSamplerParameterf glad_glSamplerParameterf -GLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; -#define glSamplerParameterfv glad_glSamplerParameterfv -GLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; -#define glSamplerParameteri glad_glSamplerParameteri -GLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; -#define glSamplerParameteriv glad_glSamplerParameteriv -GLAD_API_CALL PFNGLSCALEXOESPROC glad_glScalexOES; -#define glScalexOES glad_glScalexOES -GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; -#define glScissor glad_glScissor -GLAD_API_CALL PFNGLSCISSORARRAYVPROC glad_glScissorArrayv; -#define glScissorArrayv glad_glScissorArrayv -GLAD_API_CALL PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed; -#define glScissorIndexed glad_glScissorIndexed -GLAD_API_CALL PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv; -#define glScissorIndexedv glad_glScissorIndexedv -GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary; +typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length); +GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary; #define glShaderBinary glad_glShaderBinary -GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; -#define glShaderSource glad_glShaderSource -GLAD_API_CALL PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB; -#define glShaderSourceARB glad_glShaderSourceARB -GLAD_API_CALL PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding; -#define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding -GLAD_API_CALL PFNGLSPECIALIZESHADERARBPROC glad_glSpecializeShaderARB; -#define glSpecializeShaderARB glad_glSpecializeShaderARB -GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; -#define glStencilFunc glad_glStencilFunc -GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; -#define glStencilFuncSeparate glad_glStencilFuncSeparate -GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; -#define glStencilMask glad_glStencilMask -GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; -#define glStencilMaskSeparate glad_glStencilMaskSeparate -GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; -#define glStencilOp glad_glStencilOp -GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; -#define glStencilOpSeparate glad_glStencilOpSeparate -GLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer; -#define glTexBuffer glad_glTexBuffer -GLAD_API_CALL PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange; -#define glTexBufferRange glad_glTexBufferRange -GLAD_API_CALL PFNGLTEXCOORD1XOESPROC glad_glTexCoord1xOES; -#define glTexCoord1xOES glad_glTexCoord1xOES -GLAD_API_CALL PFNGLTEXCOORD1XVOESPROC glad_glTexCoord1xvOES; -#define glTexCoord1xvOES glad_glTexCoord1xvOES -GLAD_API_CALL PFNGLTEXCOORD2XOESPROC glad_glTexCoord2xOES; -#define glTexCoord2xOES glad_glTexCoord2xOES -GLAD_API_CALL PFNGLTEXCOORD2XVOESPROC glad_glTexCoord2xvOES; -#define glTexCoord2xvOES glad_glTexCoord2xvOES -GLAD_API_CALL PFNGLTEXCOORD3XOESPROC glad_glTexCoord3xOES; -#define glTexCoord3xOES glad_glTexCoord3xOES -GLAD_API_CALL PFNGLTEXCOORD3XVOESPROC glad_glTexCoord3xvOES; -#define glTexCoord3xvOES glad_glTexCoord3xvOES -GLAD_API_CALL PFNGLTEXCOORD4XOESPROC glad_glTexCoord4xOES; -#define glTexCoord4xOES glad_glTexCoord4xOES -GLAD_API_CALL PFNGLTEXCOORD4XVOESPROC glad_glTexCoord4xvOES; -#define glTexCoord4xvOES glad_glTexCoord4xvOES -GLAD_API_CALL PFNGLTEXENVXOESPROC glad_glTexEnvxOES; -#define glTexEnvxOES glad_glTexEnvxOES -GLAD_API_CALL PFNGLTEXENVXVOESPROC glad_glTexEnvxvOES; -#define glTexEnvxvOES glad_glTexEnvxvOES -GLAD_API_CALL PFNGLTEXGENXOESPROC glad_glTexGenxOES; -#define glTexGenxOES glad_glTexGenxOES -GLAD_API_CALL PFNGLTEXGENXVOESPROC glad_glTexGenxvOES; -#define glTexGenxvOES glad_glTexGenxvOES -GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D; -#define glTexImage1D glad_glTexImage1D -GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; -#define glTexImage2D glad_glTexImage2D -GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; -#define glTexImage2DMultisample glad_glTexImage2DMultisample -GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D; -#define glTexImage3D glad_glTexImage3D -GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; -#define glTexImage3DMultisample glad_glTexImage3DMultisample -GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; -#define glTexParameterIiv glad_glTexParameterIiv -GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; -#define glTexParameterIuiv glad_glTexParameterIuiv -GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; -#define glTexParameterf glad_glTexParameterf -GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; -#define glTexParameterfv glad_glTexParameterfv -GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; -#define glTexParameteri glad_glTexParameteri -GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; -#define glTexParameteriv glad_glTexParameteriv -GLAD_API_CALL PFNGLTEXPARAMETERXOESPROC glad_glTexParameterxOES; -#define glTexParameterxOES glad_glTexParameterxOES -GLAD_API_CALL PFNGLTEXPARAMETERXVOESPROC glad_glTexParameterxvOES; -#define glTexParameterxvOES glad_glTexParameterxvOES -GLAD_API_CALL PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D; -#define glTexStorage1D glad_glTexStorage1D -GLAD_API_CALL PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D; -#define glTexStorage2D glad_glTexStorage2D -GLAD_API_CALL PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample; -#define glTexStorage2DMultisample glad_glTexStorage2DMultisample -GLAD_API_CALL PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D; -#define glTexStorage3D glad_glTexStorage3D -GLAD_API_CALL PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample; -#define glTexStorage3DMultisample glad_glTexStorage3DMultisample -GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; -#define glTexSubImage1D glad_glTexSubImage1D -GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; -#define glTexSubImage2D glad_glTexSubImage2D -GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; -#define glTexSubImage3D glad_glTexSubImage3D -GLAD_API_CALL PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer; -#define glTextureBuffer glad_glTextureBuffer -GLAD_API_CALL PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange; -#define glTextureBufferRange glad_glTextureBufferRange -GLAD_API_CALL PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv; -#define glTextureParameterIiv glad_glTextureParameterIiv -GLAD_API_CALL PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv; -#define glTextureParameterIuiv glad_glTextureParameterIuiv -GLAD_API_CALL PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf; -#define glTextureParameterf glad_glTextureParameterf -GLAD_API_CALL PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv; -#define glTextureParameterfv glad_glTextureParameterfv -GLAD_API_CALL PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri; -#define glTextureParameteri glad_glTextureParameteri -GLAD_API_CALL PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv; -#define glTextureParameteriv glad_glTextureParameteriv -GLAD_API_CALL PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D; -#define glTextureStorage1D glad_glTextureStorage1D -GLAD_API_CALL PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D; -#define glTextureStorage2D glad_glTextureStorage2D -GLAD_API_CALL PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample; -#define glTextureStorage2DMultisample glad_glTextureStorage2DMultisample -GLAD_API_CALL PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D; -#define glTextureStorage3D glad_glTextureStorage3D -GLAD_API_CALL PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample; -#define glTextureStorage3DMultisample glad_glTextureStorage3DMultisample -GLAD_API_CALL PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D; -#define glTextureSubImage1D glad_glTextureSubImage1D -GLAD_API_CALL PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D; -#define glTextureSubImage2D glad_glTextureSubImage2D -GLAD_API_CALL PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D; -#define glTextureSubImage3D glad_glTextureSubImage3D -GLAD_API_CALL PFNGLTEXTUREVIEWPROC glad_glTextureView; -#define glTextureView glad_glTextureView -GLAD_API_CALL PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase; -#define glTransformFeedbackBufferBase glad_glTransformFeedbackBufferBase -GLAD_API_CALL PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange; -#define glTransformFeedbackBufferRange glad_glTransformFeedbackBufferRange -GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; -#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings -GLAD_API_CALL PFNGLTRANSLATEXOESPROC glad_glTranslatexOES; -#define glTranslatexOES glad_glTranslatexOES -GLAD_API_CALL PFNGLUNIFORM1DPROC glad_glUniform1d; -#define glUniform1d glad_glUniform1d -GLAD_API_CALL PFNGLUNIFORM1DVPROC glad_glUniform1dv; -#define glUniform1dv glad_glUniform1dv -GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; -#define glUniform1f glad_glUniform1f -GLAD_API_CALL PFNGLUNIFORM1FARBPROC glad_glUniform1fARB; -#define glUniform1fARB glad_glUniform1fARB -GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; -#define glUniform1fv glad_glUniform1fv -GLAD_API_CALL PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB; -#define glUniform1fvARB glad_glUniform1fvARB -GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; -#define glUniform1i glad_glUniform1i -GLAD_API_CALL PFNGLUNIFORM1I64ARBPROC glad_glUniform1i64ARB; -#define glUniform1i64ARB glad_glUniform1i64ARB -GLAD_API_CALL PFNGLUNIFORM1I64VARBPROC glad_glUniform1i64vARB; -#define glUniform1i64vARB glad_glUniform1i64vARB -GLAD_API_CALL PFNGLUNIFORM1IARBPROC glad_glUniform1iARB; -#define glUniform1iARB glad_glUniform1iARB -GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; -#define glUniform1iv glad_glUniform1iv -GLAD_API_CALL PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB; -#define glUniform1ivARB glad_glUniform1ivARB -GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui; -#define glUniform1ui glad_glUniform1ui -GLAD_API_CALL PFNGLUNIFORM1UI64ARBPROC glad_glUniform1ui64ARB; -#define glUniform1ui64ARB glad_glUniform1ui64ARB -GLAD_API_CALL PFNGLUNIFORM1UI64VARBPROC glad_glUniform1ui64vARB; -#define glUniform1ui64vARB glad_glUniform1ui64vARB -GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; -#define glUniform1uiv glad_glUniform1uiv -GLAD_API_CALL PFNGLUNIFORM2DPROC glad_glUniform2d; -#define glUniform2d glad_glUniform2d -GLAD_API_CALL PFNGLUNIFORM2DVPROC glad_glUniform2dv; -#define glUniform2dv glad_glUniform2dv -GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; -#define glUniform2f glad_glUniform2f -GLAD_API_CALL PFNGLUNIFORM2FARBPROC glad_glUniform2fARB; -#define glUniform2fARB glad_glUniform2fARB -GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; -#define glUniform2fv glad_glUniform2fv -GLAD_API_CALL PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB; -#define glUniform2fvARB glad_glUniform2fvARB -GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; -#define glUniform2i glad_glUniform2i -GLAD_API_CALL PFNGLUNIFORM2I64ARBPROC glad_glUniform2i64ARB; -#define glUniform2i64ARB glad_glUniform2i64ARB -GLAD_API_CALL PFNGLUNIFORM2I64VARBPROC glad_glUniform2i64vARB; -#define glUniform2i64vARB glad_glUniform2i64vARB -GLAD_API_CALL PFNGLUNIFORM2IARBPROC glad_glUniform2iARB; -#define glUniform2iARB glad_glUniform2iARB -GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; -#define glUniform2iv glad_glUniform2iv -GLAD_API_CALL PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB; -#define glUniform2ivARB glad_glUniform2ivARB -GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui; -#define glUniform2ui glad_glUniform2ui -GLAD_API_CALL PFNGLUNIFORM2UI64ARBPROC glad_glUniform2ui64ARB; -#define glUniform2ui64ARB glad_glUniform2ui64ARB -GLAD_API_CALL PFNGLUNIFORM2UI64VARBPROC glad_glUniform2ui64vARB; -#define glUniform2ui64vARB glad_glUniform2ui64vARB -GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; -#define glUniform2uiv glad_glUniform2uiv -GLAD_API_CALL PFNGLUNIFORM3DPROC glad_glUniform3d; -#define glUniform3d glad_glUniform3d -GLAD_API_CALL PFNGLUNIFORM3DVPROC glad_glUniform3dv; -#define glUniform3dv glad_glUniform3dv -GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; -#define glUniform3f glad_glUniform3f -GLAD_API_CALL PFNGLUNIFORM3FARBPROC glad_glUniform3fARB; -#define glUniform3fARB glad_glUniform3fARB -GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; -#define glUniform3fv glad_glUniform3fv -GLAD_API_CALL PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB; -#define glUniform3fvARB glad_glUniform3fvARB -GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; -#define glUniform3i glad_glUniform3i -GLAD_API_CALL PFNGLUNIFORM3I64ARBPROC glad_glUniform3i64ARB; -#define glUniform3i64ARB glad_glUniform3i64ARB -GLAD_API_CALL PFNGLUNIFORM3I64VARBPROC glad_glUniform3i64vARB; -#define glUniform3i64vARB glad_glUniform3i64vARB -GLAD_API_CALL PFNGLUNIFORM3IARBPROC glad_glUniform3iARB; -#define glUniform3iARB glad_glUniform3iARB -GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; -#define glUniform3iv glad_glUniform3iv -GLAD_API_CALL PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB; -#define glUniform3ivARB glad_glUniform3ivARB -GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui; -#define glUniform3ui glad_glUniform3ui -GLAD_API_CALL PFNGLUNIFORM3UI64ARBPROC glad_glUniform3ui64ARB; -#define glUniform3ui64ARB glad_glUniform3ui64ARB -GLAD_API_CALL PFNGLUNIFORM3UI64VARBPROC glad_glUniform3ui64vARB; -#define glUniform3ui64vARB glad_glUniform3ui64vARB -GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; -#define glUniform3uiv glad_glUniform3uiv -GLAD_API_CALL PFNGLUNIFORM4DPROC glad_glUniform4d; -#define glUniform4d glad_glUniform4d -GLAD_API_CALL PFNGLUNIFORM4DVPROC glad_glUniform4dv; -#define glUniform4dv glad_glUniform4dv -GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; -#define glUniform4f glad_glUniform4f -GLAD_API_CALL PFNGLUNIFORM4FARBPROC glad_glUniform4fARB; -#define glUniform4fARB glad_glUniform4fARB -GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; -#define glUniform4fv glad_glUniform4fv -GLAD_API_CALL PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB; -#define glUniform4fvARB glad_glUniform4fvARB -GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; -#define glUniform4i glad_glUniform4i -GLAD_API_CALL PFNGLUNIFORM4I64ARBPROC glad_glUniform4i64ARB; -#define glUniform4i64ARB glad_glUniform4i64ARB -GLAD_API_CALL PFNGLUNIFORM4I64VARBPROC glad_glUniform4i64vARB; -#define glUniform4i64vARB glad_glUniform4i64vARB -GLAD_API_CALL PFNGLUNIFORM4IARBPROC glad_glUniform4iARB; -#define glUniform4iARB glad_glUniform4iARB -GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; -#define glUniform4iv glad_glUniform4iv -GLAD_API_CALL PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB; -#define glUniform4ivARB glad_glUniform4ivARB -GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui; -#define glUniform4ui glad_glUniform4ui -GLAD_API_CALL PFNGLUNIFORM4UI64ARBPROC glad_glUniform4ui64ARB; -#define glUniform4ui64ARB glad_glUniform4ui64ARB -GLAD_API_CALL PFNGLUNIFORM4UI64VARBPROC glad_glUniform4ui64vARB; -#define glUniform4ui64vARB glad_glUniform4ui64vARB -GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; -#define glUniform4uiv glad_glUniform4uiv -GLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; -#define glUniformBlockBinding glad_glUniformBlockBinding -GLAD_API_CALL PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv; -#define glUniformMatrix2dv glad_glUniformMatrix2dv -GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; -#define glUniformMatrix2fv glad_glUniformMatrix2fv -GLAD_API_CALL PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB; -#define glUniformMatrix2fvARB glad_glUniformMatrix2fvARB -GLAD_API_CALL PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv; -#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv -GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; -#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv -GLAD_API_CALL PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv; -#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv -GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; -#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv -GLAD_API_CALL PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv; -#define glUniformMatrix3dv glad_glUniformMatrix3dv -GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; -#define glUniformMatrix3fv glad_glUniformMatrix3fv -GLAD_API_CALL PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB; -#define glUniformMatrix3fvARB glad_glUniformMatrix3fvARB -GLAD_API_CALL PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv; -#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv -GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; -#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv -GLAD_API_CALL PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv; -#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv -GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; -#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv -GLAD_API_CALL PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv; -#define glUniformMatrix4dv glad_glUniformMatrix4dv -GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; -#define glUniformMatrix4fv glad_glUniformMatrix4fv -GLAD_API_CALL PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB; -#define glUniformMatrix4fvARB glad_glUniformMatrix4fvARB -GLAD_API_CALL PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv; -#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv -GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; -#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv -GLAD_API_CALL PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv; -#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv -GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; -#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv -GLAD_API_CALL PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv; -#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv -GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; -#define glUnmapBuffer glad_glUnmapBuffer -GLAD_API_CALL PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB; -#define glUnmapBufferARB glad_glUnmapBufferARB -GLAD_API_CALL PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer; -#define glUnmapNamedBuffer glad_glUnmapNamedBuffer -GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; -#define glUseProgram glad_glUseProgram -GLAD_API_CALL PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB; -#define glUseProgramObjectARB glad_glUseProgramObjectARB -GLAD_API_CALL PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages; -#define glUseProgramStages glad_glUseProgramStages -GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; -#define glValidateProgram glad_glValidateProgram -GLAD_API_CALL PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB; -#define glValidateProgramARB glad_glValidateProgramARB -GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline; -#define glValidateProgramPipeline glad_glValidateProgramPipeline -GLAD_API_CALL PFNGLVERTEX2XOESPROC glad_glVertex2xOES; -#define glVertex2xOES glad_glVertex2xOES -GLAD_API_CALL PFNGLVERTEX2XVOESPROC glad_glVertex2xvOES; -#define glVertex2xvOES glad_glVertex2xvOES -GLAD_API_CALL PFNGLVERTEX3XOESPROC glad_glVertex3xOES; -#define glVertex3xOES glad_glVertex3xOES -GLAD_API_CALL PFNGLVERTEX3XVOESPROC glad_glVertex3xvOES; -#define glVertex3xvOES glad_glVertex3xvOES -GLAD_API_CALL PFNGLVERTEX4XOESPROC glad_glVertex4xOES; -#define glVertex4xOES glad_glVertex4xOES -GLAD_API_CALL PFNGLVERTEX4XVOESPROC glad_glVertex4xvOES; -#define glVertex4xvOES glad_glVertex4xvOES -GLAD_API_CALL PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding; -#define glVertexArrayAttribBinding glad_glVertexArrayAttribBinding -GLAD_API_CALL PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat; -#define glVertexArrayAttribFormat glad_glVertexArrayAttribFormat -GLAD_API_CALL PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat; -#define glVertexArrayAttribIFormat glad_glVertexArrayAttribIFormat -GLAD_API_CALL PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat; -#define glVertexArrayAttribLFormat glad_glVertexArrayAttribLFormat -GLAD_API_CALL PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor; -#define glVertexArrayBindingDivisor glad_glVertexArrayBindingDivisor -GLAD_API_CALL PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer; -#define glVertexArrayElementBuffer glad_glVertexArrayElementBuffer -GLAD_API_CALL PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer; -#define glVertexArrayVertexBuffer glad_glVertexArrayVertexBuffer -GLAD_API_CALL PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers; -#define glVertexArrayVertexBuffers glad_glVertexArrayVertexBuffers -GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; -#define glVertexAttrib1d glad_glVertexAttrib1d -GLAD_API_CALL PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB; -#define glVertexAttrib1dARB glad_glVertexAttrib1dARB -GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; -#define glVertexAttrib1dv glad_glVertexAttrib1dv -GLAD_API_CALL PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB; -#define glVertexAttrib1dvARB glad_glVertexAttrib1dvARB -GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; -#define glVertexAttrib1f glad_glVertexAttrib1f -GLAD_API_CALL PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB; -#define glVertexAttrib1fARB glad_glVertexAttrib1fARB -GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; -#define glVertexAttrib1fv glad_glVertexAttrib1fv -GLAD_API_CALL PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB; -#define glVertexAttrib1fvARB glad_glVertexAttrib1fvARB -GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; -#define glVertexAttrib1s glad_glVertexAttrib1s -GLAD_API_CALL PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB; -#define glVertexAttrib1sARB glad_glVertexAttrib1sARB -GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; -#define glVertexAttrib1sv glad_glVertexAttrib1sv -GLAD_API_CALL PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB; -#define glVertexAttrib1svARB glad_glVertexAttrib1svARB -GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; -#define glVertexAttrib2d glad_glVertexAttrib2d -GLAD_API_CALL PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB; -#define glVertexAttrib2dARB glad_glVertexAttrib2dARB -GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; -#define glVertexAttrib2dv glad_glVertexAttrib2dv -GLAD_API_CALL PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB; -#define glVertexAttrib2dvARB glad_glVertexAttrib2dvARB -GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; -#define glVertexAttrib2f glad_glVertexAttrib2f -GLAD_API_CALL PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB; -#define glVertexAttrib2fARB glad_glVertexAttrib2fARB -GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; -#define glVertexAttrib2fv glad_glVertexAttrib2fv -GLAD_API_CALL PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB; -#define glVertexAttrib2fvARB glad_glVertexAttrib2fvARB -GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; -#define glVertexAttrib2s glad_glVertexAttrib2s -GLAD_API_CALL PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB; -#define glVertexAttrib2sARB glad_glVertexAttrib2sARB -GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; -#define glVertexAttrib2sv glad_glVertexAttrib2sv -GLAD_API_CALL PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB; -#define glVertexAttrib2svARB glad_glVertexAttrib2svARB -GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; -#define glVertexAttrib3d glad_glVertexAttrib3d -GLAD_API_CALL PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB; -#define glVertexAttrib3dARB glad_glVertexAttrib3dARB -GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; -#define glVertexAttrib3dv glad_glVertexAttrib3dv -GLAD_API_CALL PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB; -#define glVertexAttrib3dvARB glad_glVertexAttrib3dvARB -GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; -#define glVertexAttrib3f glad_glVertexAttrib3f -GLAD_API_CALL PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB; -#define glVertexAttrib3fARB glad_glVertexAttrib3fARB -GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; -#define glVertexAttrib3fv glad_glVertexAttrib3fv -GLAD_API_CALL PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB; -#define glVertexAttrib3fvARB glad_glVertexAttrib3fvARB -GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; -#define glVertexAttrib3s glad_glVertexAttrib3s -GLAD_API_CALL PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB; -#define glVertexAttrib3sARB glad_glVertexAttrib3sARB -GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; -#define glVertexAttrib3sv glad_glVertexAttrib3sv -GLAD_API_CALL PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB; -#define glVertexAttrib3svARB glad_glVertexAttrib3svARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; -#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv -GLAD_API_CALL PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB; -#define glVertexAttrib4NbvARB glad_glVertexAttrib4NbvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; -#define glVertexAttrib4Niv glad_glVertexAttrib4Niv -GLAD_API_CALL PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB; -#define glVertexAttrib4NivARB glad_glVertexAttrib4NivARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; -#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv -GLAD_API_CALL PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB; -#define glVertexAttrib4NsvARB glad_glVertexAttrib4NsvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; -#define glVertexAttrib4Nub glad_glVertexAttrib4Nub -GLAD_API_CALL PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB; -#define glVertexAttrib4NubARB glad_glVertexAttrib4NubARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; -#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv -GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB; -#define glVertexAttrib4NubvARB glad_glVertexAttrib4NubvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; -#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv -GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB; -#define glVertexAttrib4NuivARB glad_glVertexAttrib4NuivARB -GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; -#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv -GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB; -#define glVertexAttrib4NusvARB glad_glVertexAttrib4NusvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; -#define glVertexAttrib4bv glad_glVertexAttrib4bv -GLAD_API_CALL PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB; -#define glVertexAttrib4bvARB glad_glVertexAttrib4bvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; -#define glVertexAttrib4d glad_glVertexAttrib4d -GLAD_API_CALL PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB; -#define glVertexAttrib4dARB glad_glVertexAttrib4dARB -GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; -#define glVertexAttrib4dv glad_glVertexAttrib4dv -GLAD_API_CALL PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB; -#define glVertexAttrib4dvARB glad_glVertexAttrib4dvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; -#define glVertexAttrib4f glad_glVertexAttrib4f -GLAD_API_CALL PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB; -#define glVertexAttrib4fARB glad_glVertexAttrib4fARB -GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; -#define glVertexAttrib4fv glad_glVertexAttrib4fv -GLAD_API_CALL PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB; -#define glVertexAttrib4fvARB glad_glVertexAttrib4fvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; -#define glVertexAttrib4iv glad_glVertexAttrib4iv -GLAD_API_CALL PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB; -#define glVertexAttrib4ivARB glad_glVertexAttrib4ivARB -GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; -#define glVertexAttrib4s glad_glVertexAttrib4s -GLAD_API_CALL PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB; -#define glVertexAttrib4sARB glad_glVertexAttrib4sARB -GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; -#define glVertexAttrib4sv glad_glVertexAttrib4sv -GLAD_API_CALL PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB; -#define glVertexAttrib4svARB glad_glVertexAttrib4svARB -GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; -#define glVertexAttrib4ubv glad_glVertexAttrib4ubv -GLAD_API_CALL PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB; -#define glVertexAttrib4ubvARB glad_glVertexAttrib4ubvARB -GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; -#define glVertexAttrib4uiv glad_glVertexAttrib4uiv -GLAD_API_CALL PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB; -#define glVertexAttrib4uivARB glad_glVertexAttrib4uivARB -GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; -#define glVertexAttrib4usv glad_glVertexAttrib4usv -GLAD_API_CALL PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB; -#define glVertexAttrib4usvARB glad_glVertexAttrib4usvARB -GLAD_API_CALL PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding; -#define glVertexAttribBinding glad_glVertexAttribBinding -GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; -#define glVertexAttribDivisor glad_glVertexAttribDivisor -GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB; -#define glVertexAttribDivisorARB glad_glVertexAttribDivisorARB -GLAD_API_CALL PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat; +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d); +GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +#endif +#ifndef GL_ARB_ES3_compatibility +#define GL_ARB_ES3_compatibility 1 +GLAPI int GLAD_GL_ARB_ES3_compatibility; +#endif +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 +GLAPI int GLAD_GL_ARB_buffer_storage; +typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags); +GLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage; +#define glBufferStorage glad_glBufferStorage +#endif +#ifndef GL_ARB_compatibility +#define GL_ARB_compatibility 1 +GLAPI int GLAD_GL_ARB_compatibility; +#endif +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_ARB_compressed_texture_pixel_storage 1 +GLAPI int GLAD_GL_ARB_compressed_texture_pixel_storage; +#endif +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +GLAPI int GLAD_GL_ARB_debug_output; +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB; +#define glDebugMessageControlARB glad_glDebugMessageControlARB +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); +GLAPI PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB; +#define glDebugMessageInsertARB glad_glDebugMessageInsertARB +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void* userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB; +#define glDebugMessageCallbackARB glad_glDebugMessageCallbackARB +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog); +GLAPI PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB; +#define glGetDebugMessageLogARB glad_glGetDebugMessageLogARB +#endif +#ifndef GL_ARB_depth_buffer_float +#define GL_ARB_depth_buffer_float 1 +GLAPI int GLAD_GL_ARB_depth_buffer_float; +#endif +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +GLAPI int GLAD_GL_ARB_depth_clamp; +#endif +#ifndef GL_ARB_depth_texture +#define GL_ARB_depth_texture 1 +GLAPI int GLAD_GL_ARB_depth_texture; +#endif +#ifndef GL_ARB_draw_buffers +#define GL_ARB_draw_buffers 1 +GLAPI int GLAD_GL_ARB_draw_buffers; +typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC)(GLsizei n, const GLenum* bufs); +GLAPI PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB; +#define glDrawBuffersARB glad_glDrawBuffersARB +#endif +#ifndef GL_ARB_draw_buffers_blend +#define GL_ARB_draw_buffers_blend 1 +GLAPI int GLAD_GL_ARB_draw_buffers_blend; +typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC)(GLuint buf, GLenum mode); +GLAPI PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB; +#define glBlendEquationiARB glad_glBlendEquationiARB +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB; +#define glBlendEquationSeparateiARB glad_glBlendEquationSeparateiARB +typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC)(GLuint buf, GLenum src, GLenum dst); +GLAPI PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB; +#define glBlendFunciARB glad_glBlendFunciARB +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB; +#define glBlendFuncSeparateiARB glad_glBlendFuncSeparateiARB +#endif +#ifndef GL_ARB_explicit_attrib_location +#define GL_ARB_explicit_attrib_location 1 +GLAPI int GLAD_GL_ARB_explicit_attrib_location; +#endif +#ifndef GL_ARB_explicit_uniform_location +#define GL_ARB_explicit_uniform_location 1 +GLAPI int GLAD_GL_ARB_explicit_uniform_location; +#endif +#ifndef GL_ARB_fragment_program +#define GL_ARB_fragment_program 1 +GLAPI int GLAD_GL_ARB_fragment_program; +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC)(GLenum target, GLenum format, GLsizei len, const void* string); +GLAPI PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB; +#define glProgramStringARB glad_glProgramStringARB +typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC)(GLenum target, GLuint program); +GLAPI PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB; +#define glBindProgramARB glad_glBindProgramARB +typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC)(GLsizei n, const GLuint* programs); +GLAPI PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB; +#define glDeleteProgramsARB glad_glDeleteProgramsARB +typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC)(GLsizei n, GLuint* programs); +GLAPI PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB; +#define glGenProgramsARB glad_glGenProgramsARB +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB; +#define glProgramEnvParameter4dARB glad_glProgramEnvParameter4dARB +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble* params); +GLAPI PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB; +#define glProgramEnvParameter4dvARB glad_glProgramEnvParameter4dvARB +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB; +#define glProgramEnvParameter4fARB glad_glProgramEnvParameter4fARB +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat* params); +GLAPI PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB; +#define glProgramEnvParameter4fvARB glad_glProgramEnvParameter4fvARB +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB; +#define glProgramLocalParameter4dARB glad_glProgramLocalParameter4dARB +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble* params); +GLAPI PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB; +#define glProgramLocalParameter4dvARB glad_glProgramLocalParameter4dvARB +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB; +#define glProgramLocalParameter4fARB glad_glProgramLocalParameter4fARB +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat* params); +GLAPI PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB; +#define glProgramLocalParameter4fvARB glad_glProgramLocalParameter4fvARB +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble* params); +GLAPI PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB; +#define glGetProgramEnvParameterdvARB glad_glGetProgramEnvParameterdvARB +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat* params); +GLAPI PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB; +#define glGetProgramEnvParameterfvARB glad_glGetProgramEnvParameterfvARB +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble* params); +GLAPI PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB; +#define glGetProgramLocalParameterdvARB glad_glGetProgramLocalParameterdvARB +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat* params); +GLAPI PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB; +#define glGetProgramLocalParameterfvARB glad_glGetProgramLocalParameterfvARB +typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB; +#define glGetProgramivARB glad_glGetProgramivARB +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC)(GLenum target, GLenum pname, void* string); +GLAPI PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB; +#define glGetProgramStringARB glad_glGetProgramStringARB +typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC)(GLuint program); +GLAPI PFNGLISPROGRAMARBPROC glad_glIsProgramARB; +#define glIsProgramARB glad_glIsProgramARB +#endif +#ifndef GL_ARB_fragment_shader +#define GL_ARB_fragment_shader 1 +GLAPI int GLAD_GL_ARB_fragment_shader; +#endif +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +GLAPI int GLAD_GL_ARB_framebuffer_object; +#endif +#ifndef GL_ARB_framebuffer_sRGB +#define GL_ARB_framebuffer_sRGB 1 +GLAPI int GLAD_GL_ARB_framebuffer_sRGB; +#endif +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +GLAPI int GLAD_GL_ARB_multisample; +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +#define glSampleCoverageARB glad_glSampleCoverageARB +#endif +#ifndef GL_ARB_sample_locations +#define GL_ARB_sample_locations 1 +GLAPI int GLAD_GL_ARB_sample_locations; +typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLenum target, GLuint start, GLsizei count, const GLfloat* v); +GLAPI PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB; +#define glFramebufferSampleLocationsfvARB glad_glFramebufferSampleLocationsfvARB +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v); +GLAPI PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB; +#define glNamedFramebufferSampleLocationsfvARB glad_glNamedFramebufferSampleLocationsfvARB +typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC)(); +GLAPI PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB; +#define glEvaluateDepthValuesARB glad_glEvaluateDepthValuesARB +#endif +#ifndef GL_ARB_texture_compression +#define GL_ARB_texture_compression 1 +GLAPI int GLAD_GL_ARB_texture_compression; +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB; +#define glCompressedTexImage3DARB glad_glCompressedTexImage3DARB +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB; +#define glCompressedTexImage2DARB glad_glCompressedTexImage2DARB +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB; +#define glCompressedTexImage1DARB glad_glCompressedTexImage1DARB +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB; +#define glCompressedTexSubImage3DARB glad_glCompressedTexSubImage3DARB +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB; +#define glCompressedTexSubImage2DARB glad_glCompressedTexSubImage2DARB +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB; +#define glCompressedTexSubImage1DARB glad_glCompressedTexSubImage1DARB +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint level, void* img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB; +#define glGetCompressedTexImageARB glad_glGetCompressedTexImageARB +#endif +#ifndef GL_ARB_texture_float +#define GL_ARB_texture_float 1 +GLAPI int GLAD_GL_ARB_texture_float; +#endif +#ifndef GL_ARB_texture_multisample +#define GL_ARB_texture_multisample 1 +GLAPI int GLAD_GL_ARB_texture_multisample; +#endif +#ifndef GL_ARB_texture_non_power_of_two +#define GL_ARB_texture_non_power_of_two 1 +GLAPI int GLAD_GL_ARB_texture_non_power_of_two; +#endif +#ifndef GL_ARB_texture_rg +#define GL_ARB_texture_rg 1 +GLAPI int GLAD_GL_ARB_texture_rg; +#endif +#ifndef GL_ARB_texture_swizzle +#define GL_ARB_texture_swizzle 1 +GLAPI int GLAD_GL_ARB_texture_swizzle; +#endif +#ifndef GL_ARB_uniform_buffer_object +#define GL_ARB_uniform_buffer_object 1 +GLAPI int GLAD_GL_ARB_uniform_buffer_object; +#endif +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +GLAPI int GLAD_GL_ARB_vertex_array_object; +#endif +#ifndef GL_ARB_vertex_attrib_binding +#define GL_ARB_vertex_attrib_binding 1 +GLAPI int GLAD_GL_ARB_vertex_attrib_binding; +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer; +#define glBindVertexBuffer glad_glBindVertexBuffer +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat; #define glVertexAttribFormat glad_glVertexAttribFormat -GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; -#define glVertexAttribI1i glad_glVertexAttribI1i -GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; -#define glVertexAttribI1iv glad_glVertexAttribI1iv -GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; -#define glVertexAttribI1ui glad_glVertexAttribI1ui -GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; -#define glVertexAttribI1uiv glad_glVertexAttribI1uiv -GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; -#define glVertexAttribI2i glad_glVertexAttribI2i -GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; -#define glVertexAttribI2iv glad_glVertexAttribI2iv -GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; -#define glVertexAttribI2ui glad_glVertexAttribI2ui -GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; -#define glVertexAttribI2uiv glad_glVertexAttribI2uiv -GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; -#define glVertexAttribI3i glad_glVertexAttribI3i -GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; -#define glVertexAttribI3iv glad_glVertexAttribI3iv -GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; -#define glVertexAttribI3ui glad_glVertexAttribI3ui -GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; -#define glVertexAttribI3uiv glad_glVertexAttribI3uiv -GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; -#define glVertexAttribI4bv glad_glVertexAttribI4bv -GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; -#define glVertexAttribI4i glad_glVertexAttribI4i -GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; -#define glVertexAttribI4iv glad_glVertexAttribI4iv -GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; -#define glVertexAttribI4sv glad_glVertexAttribI4sv -GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; -#define glVertexAttribI4ubv glad_glVertexAttribI4ubv -GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; -#define glVertexAttribI4ui glad_glVertexAttribI4ui -GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; -#define glVertexAttribI4uiv glad_glVertexAttribI4uiv -GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; -#define glVertexAttribI4usv glad_glVertexAttribI4usv -GLAD_API_CALL PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat; +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat; #define glVertexAttribIFormat glad_glVertexAttribIFormat -GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; -#define glVertexAttribIPointer glad_glVertexAttribIPointer -GLAD_API_CALL PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d; -#define glVertexAttribL1d glad_glVertexAttribL1d -GLAD_API_CALL PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv; -#define glVertexAttribL1dv glad_glVertexAttribL1dv -GLAD_API_CALL PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d; -#define glVertexAttribL2d glad_glVertexAttribL2d -GLAD_API_CALL PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv; -#define glVertexAttribL2dv glad_glVertexAttribL2dv -GLAD_API_CALL PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d; -#define glVertexAttribL3d glad_glVertexAttribL3d -GLAD_API_CALL PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv; -#define glVertexAttribL3dv glad_glVertexAttribL3dv -GLAD_API_CALL PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d; -#define glVertexAttribL4d glad_glVertexAttribL4d -GLAD_API_CALL PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv; -#define glVertexAttribL4dv glad_glVertexAttribL4dv -GLAD_API_CALL PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat; +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat; #define glVertexAttribLFormat glad_glVertexAttribLFormat -GLAD_API_CALL PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer; -#define glVertexAttribLPointer glad_glVertexAttribLPointer -GLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; -#define glVertexAttribP1ui glad_glVertexAttribP1ui -GLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; -#define glVertexAttribP1uiv glad_glVertexAttribP1uiv -GLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; -#define glVertexAttribP2ui glad_glVertexAttribP2ui -GLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; -#define glVertexAttribP2uiv glad_glVertexAttribP2uiv -GLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; -#define glVertexAttribP3ui glad_glVertexAttribP3ui -GLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; -#define glVertexAttribP3uiv glad_glVertexAttribP3uiv -GLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; -#define glVertexAttribP4ui glad_glVertexAttribP4ui -GLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; -#define glVertexAttribP4uiv glad_glVertexAttribP4uiv -GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; -#define glVertexAttribPointer glad_glVertexAttribPointer -GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB; -#define glVertexAttribPointerARB glad_glVertexAttribPointerARB -GLAD_API_CALL PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor; +typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex); +GLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding; +#define glVertexAttribBinding glad_glVertexAttribBinding +typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor); +GLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor; #define glVertexBindingDivisor glad_glVertexBindingDivisor -GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; -#define glViewport glad_glViewport -GLAD_API_CALL PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv; -#define glViewportArrayv glad_glViewportArrayv -GLAD_API_CALL PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf; -#define glViewportIndexedf glad_glViewportIndexedf -GLAD_API_CALL PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv; -#define glViewportIndexedfv glad_glViewportIndexedfv -GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync; -#define glWaitSync glad_glWaitSync - - - - - -GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr); -GLAD_API_CALL int gladLoadGL( GLADloadfunc load); - - +#endif +#ifndef GL_ARB_vertex_buffer_object +#define GL_ARB_vertex_buffer_object 1 +GLAPI int GLAD_GL_ARB_vertex_buffer_object; +typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERARBPROC glad_glBindBufferARB; +#define glBindBufferARB glad_glBindBufferARB +typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC)(GLsizei n, const GLuint* buffers); +GLAPI PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB; +#define glDeleteBuffersARB glad_glDeleteBuffersARB +typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC)(GLsizei n, GLuint* buffers); +GLAPI PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB; +#define glGenBuffersARB glad_glGenBuffersARB +typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERARBPROC glad_glIsBufferARB; +#define glIsBufferARB glad_glIsBufferARB +typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC)(GLenum target, GLsizeiptrARB size, const void* data, GLenum usage); +GLAPI PFNGLBUFFERDATAARBPROC glad_glBufferDataARB; +#define glBufferDataARB glad_glBufferDataARB +typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void* data); +GLAPI PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB; +#define glBufferSubDataARB glad_glBufferSubDataARB +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void* data); +GLAPI PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB; +#define glGetBufferSubDataARB glad_glGetBufferSubDataARB +typedef void* (APIENTRYP PFNGLMAPBUFFERARBPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERARBPROC glad_glMapBufferARB; +#define glMapBufferARB glad_glMapBufferARB +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB; +#define glUnmapBufferARB glad_glUnmapBufferARB +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB; +#define glGetBufferParameterivARB glad_glGetBufferParameterivARB +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC)(GLenum target, GLenum pname, void** params); +GLAPI PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB; +#define glGetBufferPointervARB glad_glGetBufferPointervARB +#endif +#ifndef GL_ARB_vertex_program +#define GL_ARB_vertex_program 1 +GLAPI int GLAD_GL_ARB_vertex_program; +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB; +#define glVertexAttrib1dARB glad_glVertexAttrib1dARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB; +#define glVertexAttrib1dvARB glad_glVertexAttrib1dvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB; +#define glVertexAttrib1fARB glad_glVertexAttrib1fARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB; +#define glVertexAttrib1fvARB glad_glVertexAttrib1fvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB; +#define glVertexAttrib1sARB glad_glVertexAttrib1sARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB; +#define glVertexAttrib1svARB glad_glVertexAttrib1svARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB; +#define glVertexAttrib2dARB glad_glVertexAttrib2dARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB; +#define glVertexAttrib2dvARB glad_glVertexAttrib2dvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB; +#define glVertexAttrib2fARB glad_glVertexAttrib2fARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB; +#define glVertexAttrib2fvARB glad_glVertexAttrib2fvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB; +#define glVertexAttrib2sARB glad_glVertexAttrib2sARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB; +#define glVertexAttrib2svARB glad_glVertexAttrib2svARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB; +#define glVertexAttrib3dARB glad_glVertexAttrib3dARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB; +#define glVertexAttrib3dvARB glad_glVertexAttrib3dvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB; +#define glVertexAttrib3fARB glad_glVertexAttrib3fARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB; +#define glVertexAttrib3fvARB glad_glVertexAttrib3fvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB; +#define glVertexAttrib3sARB glad_glVertexAttrib3sARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB; +#define glVertexAttrib3svARB glad_glVertexAttrib3svARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB; +#define glVertexAttrib4NbvARB glad_glVertexAttrib4NbvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB; +#define glVertexAttrib4NivARB glad_glVertexAttrib4NivARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB; +#define glVertexAttrib4NsvARB glad_glVertexAttrib4NsvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB; +#define glVertexAttrib4NubARB glad_glVertexAttrib4NubARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB; +#define glVertexAttrib4NubvARB glad_glVertexAttrib4NubvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB; +#define glVertexAttrib4NuivARB glad_glVertexAttrib4NuivARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB; +#define glVertexAttrib4NusvARB glad_glVertexAttrib4NusvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB; +#define glVertexAttrib4bvARB glad_glVertexAttrib4bvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB; +#define glVertexAttrib4dARB glad_glVertexAttrib4dARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB; +#define glVertexAttrib4dvARB glad_glVertexAttrib4dvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB; +#define glVertexAttrib4fARB glad_glVertexAttrib4fARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB; +#define glVertexAttrib4fvARB glad_glVertexAttrib4fvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB; +#define glVertexAttrib4ivARB glad_glVertexAttrib4ivARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB; +#define glVertexAttrib4sARB glad_glVertexAttrib4sARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB; +#define glVertexAttrib4svARB glad_glVertexAttrib4svARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB; +#define glVertexAttrib4ubvARB glad_glVertexAttrib4ubvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB; +#define glVertexAttrib4uivARB glad_glVertexAttrib4uivARB +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB; +#define glVertexAttrib4usvARB glad_glVertexAttrib4usvARB +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB; +#define glVertexAttribPointerARB glad_glVertexAttribPointerARB +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB; +#define glEnableVertexAttribArrayARB glad_glEnableVertexAttribArrayARB +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB; +#define glDisableVertexAttribArrayARB glad_glDisableVertexAttribArrayARB +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC)(GLuint index, GLenum pname, GLdouble* params); +GLAPI PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB; +#define glGetVertexAttribdvARB glad_glGetVertexAttribdvARB +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC)(GLuint index, GLenum pname, GLfloat* params); +GLAPI PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB; +#define glGetVertexAttribfvARB glad_glGetVertexAttribfvARB +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC)(GLuint index, GLenum pname, GLint* params); +GLAPI PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB; +#define glGetVertexAttribivARB glad_glGetVertexAttribivARB +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC)(GLuint index, GLenum pname, void** pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB; +#define glGetVertexAttribPointervARB glad_glGetVertexAttribPointervARB +#endif +#ifndef GL_ARB_vertex_shader +#define GL_ARB_vertex_shader 1 +GLAPI int GLAD_GL_ARB_vertex_shader; +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC)(GLhandleARB programObj, GLuint index, const GLcharARB* name); +GLAPI PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB; +#define glBindAttribLocationARB glad_glBindAttribLocationARB +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLcharARB* name); +GLAPI PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB; +#define glGetActiveAttribARB glad_glGetActiveAttribARB +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB* name); +GLAPI PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB; +#define glGetAttribLocationARB glad_glGetAttribLocationARB +#endif +#ifndef GL_ATI_element_array +#define GL_ATI_element_array 1 +GLAPI int GLAD_GL_ATI_element_array; +typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC)(GLenum type, const void* pointer); +GLAPI PFNGLELEMENTPOINTERATIPROC glad_glElementPointerATI; +#define glElementPointerATI glad_glElementPointerATI +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC)(GLenum mode, GLsizei count); +GLAPI PFNGLDRAWELEMENTARRAYATIPROC glad_glDrawElementArrayATI; +#define glDrawElementArrayATI glad_glDrawElementArrayATI +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count); +GLAPI PFNGLDRAWRANGEELEMENTARRAYATIPROC glad_glDrawRangeElementArrayATI; +#define glDrawRangeElementArrayATI glad_glDrawRangeElementArrayATI +#endif +#ifndef GL_ATI_fragment_shader +#define GL_ATI_fragment_shader 1 +GLAPI int GLAD_GL_ATI_fragment_shader; +typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC)(GLuint range); +GLAPI PFNGLGENFRAGMENTSHADERSATIPROC glad_glGenFragmentShadersATI; +#define glGenFragmentShadersATI glad_glGenFragmentShadersATI +typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC)(GLuint id); +GLAPI PFNGLBINDFRAGMENTSHADERATIPROC glad_glBindFragmentShaderATI; +#define glBindFragmentShaderATI glad_glBindFragmentShaderATI +typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC)(GLuint id); +GLAPI PFNGLDELETEFRAGMENTSHADERATIPROC glad_glDeleteFragmentShaderATI; +#define glDeleteFragmentShaderATI glad_glDeleteFragmentShaderATI +typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC)(); +GLAPI PFNGLBEGINFRAGMENTSHADERATIPROC glad_glBeginFragmentShaderATI; +#define glBeginFragmentShaderATI glad_glBeginFragmentShaderATI +typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC)(); +GLAPI PFNGLENDFRAGMENTSHADERATIPROC glad_glEndFragmentShaderATI; +#define glEndFragmentShaderATI glad_glEndFragmentShaderATI +typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC)(GLuint dst, GLuint coord, GLenum swizzle); +GLAPI PFNGLPASSTEXCOORDATIPROC glad_glPassTexCoordATI; +#define glPassTexCoordATI glad_glPassTexCoordATI +typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC)(GLuint dst, GLuint interp, GLenum swizzle); +GLAPI PFNGLSAMPLEMAPATIPROC glad_glSampleMapATI; +#define glSampleMapATI glad_glSampleMapATI +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC)(GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI PFNGLCOLORFRAGMENTOP1ATIPROC glad_glColorFragmentOp1ATI; +#define glColorFragmentOp1ATI glad_glColorFragmentOp1ATI +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC)(GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI PFNGLCOLORFRAGMENTOP2ATIPROC glad_glColorFragmentOp2ATI; +#define glColorFragmentOp2ATI glad_glColorFragmentOp2ATI +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC)(GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI PFNGLCOLORFRAGMENTOP3ATIPROC glad_glColorFragmentOp3ATI; +#define glColorFragmentOp3ATI glad_glColorFragmentOp3ATI +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC)(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI PFNGLALPHAFRAGMENTOP1ATIPROC glad_glAlphaFragmentOp1ATI; +#define glAlphaFragmentOp1ATI glad_glAlphaFragmentOp1ATI +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC)(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI PFNGLALPHAFRAGMENTOP2ATIPROC glad_glAlphaFragmentOp2ATI; +#define glAlphaFragmentOp2ATI glad_glAlphaFragmentOp2ATI +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC)(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI PFNGLALPHAFRAGMENTOP3ATIPROC glad_glAlphaFragmentOp3ATI; +#define glAlphaFragmentOp3ATI glad_glAlphaFragmentOp3ATI +typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC)(GLuint dst, const GLfloat* value); +GLAPI PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glad_glSetFragmentShaderConstantATI; +#define glSetFragmentShaderConstantATI glad_glSetFragmentShaderConstantATI +#endif +#ifndef GL_ATI_vertex_array_object +#define GL_ATI_vertex_array_object 1 +GLAPI int GLAD_GL_ATI_vertex_array_object; +typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC)(GLsizei size, const void* pointer, GLenum usage); +GLAPI PFNGLNEWOBJECTBUFFERATIPROC glad_glNewObjectBufferATI; +#define glNewObjectBufferATI glad_glNewObjectBufferATI +typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC)(GLuint buffer); +GLAPI PFNGLISOBJECTBUFFERATIPROC glad_glIsObjectBufferATI; +#define glIsObjectBufferATI glad_glIsObjectBufferATI +typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC)(GLuint buffer, GLuint offset, GLsizei size, const void* pointer, GLenum preserve); +GLAPI PFNGLUPDATEOBJECTBUFFERATIPROC glad_glUpdateObjectBufferATI; +#define glUpdateObjectBufferATI glad_glUpdateObjectBufferATI +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC)(GLuint buffer, GLenum pname, GLfloat* params); +GLAPI PFNGLGETOBJECTBUFFERFVATIPROC glad_glGetObjectBufferfvATI; +#define glGetObjectBufferfvATI glad_glGetObjectBufferfvATI +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC)(GLuint buffer, GLenum pname, GLint* params); +GLAPI PFNGLGETOBJECTBUFFERIVATIPROC glad_glGetObjectBufferivATI; +#define glGetObjectBufferivATI glad_glGetObjectBufferivATI +typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC)(GLuint buffer); +GLAPI PFNGLFREEOBJECTBUFFERATIPROC glad_glFreeObjectBufferATI; +#define glFreeObjectBufferATI glad_glFreeObjectBufferATI +typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC)(GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI PFNGLARRAYOBJECTATIPROC glad_glArrayObjectATI; +#define glArrayObjectATI glad_glArrayObjectATI +typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC)(GLenum array, GLenum pname, GLfloat* params); +GLAPI PFNGLGETARRAYOBJECTFVATIPROC glad_glGetArrayObjectfvATI; +#define glGetArrayObjectfvATI glad_glGetArrayObjectfvATI +typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC)(GLenum array, GLenum pname, GLint* params); +GLAPI PFNGLGETARRAYOBJECTIVATIPROC glad_glGetArrayObjectivATI; +#define glGetArrayObjectivATI glad_glGetArrayObjectivATI +typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC)(GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI PFNGLVARIANTARRAYOBJECTATIPROC glad_glVariantArrayObjectATI; +#define glVariantArrayObjectATI glad_glVariantArrayObjectATI +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC)(GLuint id, GLenum pname, GLfloat* params); +GLAPI PFNGLGETVARIANTARRAYOBJECTFVATIPROC glad_glGetVariantArrayObjectfvATI; +#define glGetVariantArrayObjectfvATI glad_glGetVariantArrayObjectfvATI +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC)(GLuint id, GLenum pname, GLint* params); +GLAPI PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI; +#define glGetVariantArrayObjectivATI glad_glGetVariantArrayObjectivATI +#endif +#ifndef GL_EXT_blend_color +#define GL_EXT_blend_color 1 +GLAPI int GLAD_GL_EXT_blend_color; +typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT; +#define glBlendColorEXT glad_glBlendColorEXT +#endif +#ifndef GL_EXT_blend_equation_separate +#define GL_EXT_blend_equation_separate 1 +GLAPI int GLAD_GL_EXT_blend_equation_separate; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT; +#define glBlendEquationSeparateEXT glad_glBlendEquationSeparateEXT +#endif +#ifndef GL_EXT_blend_func_separate +#define GL_EXT_blend_func_separate 1 +GLAPI int GLAD_GL_EXT_blend_func_separate; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT; +#define glBlendFuncSeparateEXT glad_glBlendFuncSeparateEXT +#endif +#ifndef GL_EXT_debug_marker +#define GL_EXT_debug_marker 1 +GLAPI int GLAD_GL_EXT_debug_marker; +typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC)(GLsizei length, const GLchar *marker); +GLAPI PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; +#define glInsertEventMarkerEXT glad_glInsertEventMarkerEXT +typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC)(GLsizei length, const GLchar *marker); +GLAPI PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; +#define glPushGroupMarkerEXT glad_glPushGroupMarkerEXT +typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC)(void); +GLAPI PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; +#define glPopGroupMarkerEXT glad_glPopGroupMarkerEXT +#endif +#ifndef GL_EXT_framebuffer_blit +#define GL_EXT_framebuffer_blit 1 +GLAPI int GLAD_GL_EXT_framebuffer_blit; +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT; +#define glBlitFramebufferEXT glad_glBlitFramebufferEXT +#endif +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +GLAPI int GLAD_GL_EXT_framebuffer_multisample; +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; +#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT +#endif +#ifndef GL_EXT_framebuffer_multisample_blit_scaled +#define GL_EXT_framebuffer_multisample_blit_scaled 1 +GLAPI int GLAD_GL_EXT_framebuffer_multisample_blit_scaled; +#endif +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +GLAPI int GLAD_GL_EXT_framebuffer_object; +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT; +#define glIsRenderbufferEXT glad_glIsRenderbufferEXT +typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT; +#define glBindRenderbufferEXT glad_glBindRenderbufferEXT +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC)(GLsizei n, const GLuint* renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT; +#define glDeleteRenderbuffersEXT glad_glDeleteRenderbuffersEXT +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC)(GLsizei n, GLuint* renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT; +#define glGenRenderbuffersEXT glad_glGenRenderbuffersEXT +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT; +#define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT; +#define glGetRenderbufferParameterivEXT glad_glGetRenderbufferParameterivEXT +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT; +#define glIsFramebufferEXT glad_glIsFramebufferEXT +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT; +#define glBindFramebufferEXT glad_glBindFramebufferEXT +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC)(GLsizei n, const GLuint* framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT; +#define glDeleteFramebuffersEXT glad_glDeleteFramebuffersEXT +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC)(GLsizei n, GLuint* framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT; +#define glGenFramebuffersEXT glad_glGenFramebuffersEXT +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT; +#define glCheckFramebufferStatusEXT glad_glCheckFramebufferStatusEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT; +#define glFramebufferTexture1DEXT glad_glFramebufferTexture1DEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT; +#define glFramebufferTexture2DEXT glad_glFramebufferTexture2DEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT; +#define glFramebufferTexture3DEXT glad_glFramebufferTexture3DEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT; +#define glFramebufferRenderbufferEXT glad_glFramebufferRenderbufferEXT +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)(GLenum target, GLenum attachment, GLenum pname, GLint* params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT; +#define glGetFramebufferAttachmentParameterivEXT glad_glGetFramebufferAttachmentParameterivEXT +typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; +#define glGenerateMipmapEXT glad_glGenerateMipmapEXT +#endif +#ifndef GL_EXT_framebuffer_sRGB +#define GL_EXT_framebuffer_sRGB 1 +GLAPI int GLAD_GL_EXT_framebuffer_sRGB; +#endif +#ifndef GL_EXT_index_array_formats +#define GL_EXT_index_array_formats 1 +GLAPI int GLAD_GL_EXT_index_array_formats; +#endif +#ifndef GL_EXT_texture +#define GL_EXT_texture 1 +GLAPI int GLAD_GL_EXT_texture; +#endif +#ifndef GL_EXT_texture_compression_s3tc +#define GL_EXT_texture_compression_s3tc 1 +GLAPI int GLAD_GL_EXT_texture_compression_s3tc; +#endif +#ifndef GL_EXT_texture_sRGB +#define GL_EXT_texture_sRGB 1 +GLAPI int GLAD_GL_EXT_texture_sRGB; +#endif +#ifndef GL_EXT_texture_swizzle +#define GL_EXT_texture_swizzle 1 +GLAPI int GLAD_GL_EXT_texture_swizzle; +#endif +#ifndef GL_EXT_vertex_array +#define GL_EXT_vertex_array 1 +GLAPI int GLAD_GL_EXT_vertex_array; +typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC)(GLint i); +GLAPI PFNGLARRAYELEMENTEXTPROC glad_glArrayElementEXT; +#define glArrayElementEXT glad_glArrayElementEXT +typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC)(GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer); +GLAPI PFNGLCOLORPOINTEREXTPROC glad_glColorPointerEXT; +#define glColorPointerEXT glad_glColorPointerEXT +typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSEXTPROC glad_glDrawArraysEXT; +#define glDrawArraysEXT glad_glDrawArraysEXT +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC)(GLsizei stride, GLsizei count, const GLboolean* pointer); +GLAPI PFNGLEDGEFLAGPOINTEREXTPROC glad_glEdgeFlagPointerEXT; +#define glEdgeFlagPointerEXT glad_glEdgeFlagPointerEXT +typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC)(GLenum pname, void** params); +GLAPI PFNGLGETPOINTERVEXTPROC glad_glGetPointervEXT; +#define glGetPointervEXT glad_glGetPointervEXT +typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC)(GLenum type, GLsizei stride, GLsizei count, const void* pointer); +GLAPI PFNGLINDEXPOINTEREXTPROC glad_glIndexPointerEXT; +#define glIndexPointerEXT glad_glIndexPointerEXT +typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC)(GLenum type, GLsizei stride, GLsizei count, const void* pointer); +GLAPI PFNGLNORMALPOINTEREXTPROC glad_glNormalPointerEXT; +#define glNormalPointerEXT glad_glNormalPointerEXT +typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC)(GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer); +GLAPI PFNGLTEXCOORDPOINTEREXTPROC glad_glTexCoordPointerEXT; +#define glTexCoordPointerEXT glad_glTexCoordPointerEXT +typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC)(GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer); +GLAPI PFNGLVERTEXPOINTEREXTPROC glad_glVertexPointerEXT; +#define glVertexPointerEXT glad_glVertexPointerEXT +#endif +#ifndef GL_EXT_vertex_shader +#define GL_EXT_vertex_shader 1 +GLAPI int GLAD_GL_EXT_vertex_shader; +typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC)(); +GLAPI PFNGLBEGINVERTEXSHADEREXTPROC glad_glBeginVertexShaderEXT; +#define glBeginVertexShaderEXT glad_glBeginVertexShaderEXT +typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC)(); +GLAPI PFNGLENDVERTEXSHADEREXTPROC glad_glEndVertexShaderEXT; +#define glEndVertexShaderEXT glad_glEndVertexShaderEXT +typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC)(GLuint id); +GLAPI PFNGLBINDVERTEXSHADEREXTPROC glad_glBindVertexShaderEXT; +#define glBindVertexShaderEXT glad_glBindVertexShaderEXT +typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC)(GLuint range); +GLAPI PFNGLGENVERTEXSHADERSEXTPROC glad_glGenVertexShadersEXT; +#define glGenVertexShadersEXT glad_glGenVertexShadersEXT +typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC)(GLuint id); +GLAPI PFNGLDELETEVERTEXSHADEREXTPROC glad_glDeleteVertexShaderEXT; +#define glDeleteVertexShaderEXT glad_glDeleteVertexShaderEXT +typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC)(GLenum op, GLuint res, GLuint arg1); +GLAPI PFNGLSHADEROP1EXTPROC glad_glShaderOp1EXT; +#define glShaderOp1EXT glad_glShaderOp1EXT +typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC)(GLenum op, GLuint res, GLuint arg1, GLuint arg2); +GLAPI PFNGLSHADEROP2EXTPROC glad_glShaderOp2EXT; +#define glShaderOp2EXT glad_glShaderOp2EXT +typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC)(GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +GLAPI PFNGLSHADEROP3EXTPROC glad_glShaderOp3EXT; +#define glShaderOp3EXT glad_glShaderOp3EXT +typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC)(GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI PFNGLSWIZZLEEXTPROC glad_glSwizzleEXT; +#define glSwizzleEXT glad_glSwizzleEXT +typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC)(GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI PFNGLWRITEMASKEXTPROC glad_glWriteMaskEXT; +#define glWriteMaskEXT glad_glWriteMaskEXT +typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC)(GLuint res, GLuint src, GLuint num); +GLAPI PFNGLINSERTCOMPONENTEXTPROC glad_glInsertComponentEXT; +#define glInsertComponentEXT glad_glInsertComponentEXT +typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC)(GLuint res, GLuint src, GLuint num); +GLAPI PFNGLEXTRACTCOMPONENTEXTPROC glad_glExtractComponentEXT; +#define glExtractComponentEXT glad_glExtractComponentEXT +typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC)(GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +GLAPI PFNGLGENSYMBOLSEXTPROC glad_glGenSymbolsEXT; +#define glGenSymbolsEXT glad_glGenSymbolsEXT +typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC)(GLuint id, GLenum type, const void* addr); +GLAPI PFNGLSETINVARIANTEXTPROC glad_glSetInvariantEXT; +#define glSetInvariantEXT glad_glSetInvariantEXT +typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC)(GLuint id, GLenum type, const void* addr); +GLAPI PFNGLSETLOCALCONSTANTEXTPROC glad_glSetLocalConstantEXT; +#define glSetLocalConstantEXT glad_glSetLocalConstantEXT +typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC)(GLuint id, const GLbyte* addr); +GLAPI PFNGLVARIANTBVEXTPROC glad_glVariantbvEXT; +#define glVariantbvEXT glad_glVariantbvEXT +typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC)(GLuint id, const GLshort* addr); +GLAPI PFNGLVARIANTSVEXTPROC glad_glVariantsvEXT; +#define glVariantsvEXT glad_glVariantsvEXT +typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC)(GLuint id, const GLint* addr); +GLAPI PFNGLVARIANTIVEXTPROC glad_glVariantivEXT; +#define glVariantivEXT glad_glVariantivEXT +typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC)(GLuint id, const GLfloat* addr); +GLAPI PFNGLVARIANTFVEXTPROC glad_glVariantfvEXT; +#define glVariantfvEXT glad_glVariantfvEXT +typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC)(GLuint id, const GLdouble* addr); +GLAPI PFNGLVARIANTDVEXTPROC glad_glVariantdvEXT; +#define glVariantdvEXT glad_glVariantdvEXT +typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC)(GLuint id, const GLubyte* addr); +GLAPI PFNGLVARIANTUBVEXTPROC glad_glVariantubvEXT; +#define glVariantubvEXT glad_glVariantubvEXT +typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC)(GLuint id, const GLushort* addr); +GLAPI PFNGLVARIANTUSVEXTPROC glad_glVariantusvEXT; +#define glVariantusvEXT glad_glVariantusvEXT +typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC)(GLuint id, const GLuint* addr); +GLAPI PFNGLVARIANTUIVEXTPROC glad_glVariantuivEXT; +#define glVariantuivEXT glad_glVariantuivEXT +typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC)(GLuint id, GLenum type, GLuint stride, const void* addr); +GLAPI PFNGLVARIANTPOINTEREXTPROC glad_glVariantPointerEXT; +#define glVariantPointerEXT glad_glVariantPointerEXT +typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC)(GLuint id); +GLAPI PFNGLENABLEVARIANTCLIENTSTATEEXTPROC glad_glEnableVariantClientStateEXT; +#define glEnableVariantClientStateEXT glad_glEnableVariantClientStateEXT +typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC)(GLuint id); +GLAPI PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC glad_glDisableVariantClientStateEXT; +#define glDisableVariantClientStateEXT glad_glDisableVariantClientStateEXT +typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC)(GLenum light, GLenum value); +GLAPI PFNGLBINDLIGHTPARAMETEREXTPROC glad_glBindLightParameterEXT; +#define glBindLightParameterEXT glad_glBindLightParameterEXT +typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC)(GLenum face, GLenum value); +GLAPI PFNGLBINDMATERIALPARAMETEREXTPROC glad_glBindMaterialParameterEXT; +#define glBindMaterialParameterEXT glad_glBindMaterialParameterEXT +typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC)(GLenum unit, GLenum coord, GLenum value); +GLAPI PFNGLBINDTEXGENPARAMETEREXTPROC glad_glBindTexGenParameterEXT; +#define glBindTexGenParameterEXT glad_glBindTexGenParameterEXT +typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC)(GLenum unit, GLenum value); +GLAPI PFNGLBINDTEXTUREUNITPARAMETEREXTPROC glad_glBindTextureUnitParameterEXT; +#define glBindTextureUnitParameterEXT glad_glBindTextureUnitParameterEXT +typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC)(GLenum value); +GLAPI PFNGLBINDPARAMETEREXTPROC glad_glBindParameterEXT; +#define glBindParameterEXT glad_glBindParameterEXT +typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC)(GLuint id, GLenum cap); +GLAPI PFNGLISVARIANTENABLEDEXTPROC glad_glIsVariantEnabledEXT; +#define glIsVariantEnabledEXT glad_glIsVariantEnabledEXT +typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC)(GLuint id, GLenum value, GLboolean* data); +GLAPI PFNGLGETVARIANTBOOLEANVEXTPROC glad_glGetVariantBooleanvEXT; +#define glGetVariantBooleanvEXT glad_glGetVariantBooleanvEXT +typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC)(GLuint id, GLenum value, GLint* data); +GLAPI PFNGLGETVARIANTINTEGERVEXTPROC glad_glGetVariantIntegervEXT; +#define glGetVariantIntegervEXT glad_glGetVariantIntegervEXT +typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC)(GLuint id, GLenum value, GLfloat* data); +GLAPI PFNGLGETVARIANTFLOATVEXTPROC glad_glGetVariantFloatvEXT; +#define glGetVariantFloatvEXT glad_glGetVariantFloatvEXT +typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC)(GLuint id, GLenum value, void** data); +GLAPI PFNGLGETVARIANTPOINTERVEXTPROC glad_glGetVariantPointervEXT; +#define glGetVariantPointervEXT glad_glGetVariantPointervEXT +typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC)(GLuint id, GLenum value, GLboolean* data); +GLAPI PFNGLGETINVARIANTBOOLEANVEXTPROC glad_glGetInvariantBooleanvEXT; +#define glGetInvariantBooleanvEXT glad_glGetInvariantBooleanvEXT +typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC)(GLuint id, GLenum value, GLint* data); +GLAPI PFNGLGETINVARIANTINTEGERVEXTPROC glad_glGetInvariantIntegervEXT; +#define glGetInvariantIntegervEXT glad_glGetInvariantIntegervEXT +typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC)(GLuint id, GLenum value, GLfloat* data); +GLAPI PFNGLGETINVARIANTFLOATVEXTPROC glad_glGetInvariantFloatvEXT; +#define glGetInvariantFloatvEXT glad_glGetInvariantFloatvEXT +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC)(GLuint id, GLenum value, GLboolean* data); +GLAPI PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC glad_glGetLocalConstantBooleanvEXT; +#define glGetLocalConstantBooleanvEXT glad_glGetLocalConstantBooleanvEXT +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC)(GLuint id, GLenum value, GLint* data); +GLAPI PFNGLGETLOCALCONSTANTINTEGERVEXTPROC glad_glGetLocalConstantIntegervEXT; +#define glGetLocalConstantIntegervEXT glad_glGetLocalConstantIntegervEXT +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC)(GLuint id, GLenum value, GLfloat* data); +GLAPI PFNGLGETLOCALCONSTANTFLOATVEXTPROC glad_glGetLocalConstantFloatvEXT; +#define glGetLocalConstantFloatvEXT glad_glGetLocalConstantFloatvEXT +#endif #ifdef __cplusplus } #endif + #endif -/* Source */ -#ifdef GLAD_GL_IMPLEMENTATION +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION SECTION +// + +#ifdef GLAD_IMPLEMENTATION + #include #include #include -#ifndef GLAD_IMPL_UTIL_C_ -#define GLAD_IMPL_UTIL_C_ - -#ifdef _MSC_VER -#define GLAD_IMPL_UTIL_SSCANF sscanf_s -#else -#define GLAD_IMPL_UTIL_SSCANF sscanf -#endif - -#endif /* GLAD_IMPL_UTIL_C_ */ - -#ifdef __cplusplus -extern "C" { -#endif - - - -int GLAD_GL_VERSION_1_0 = 0; -int GLAD_GL_VERSION_1_1 = 0; -int GLAD_GL_VERSION_1_2 = 0; -int GLAD_GL_VERSION_1_3 = 0; -int GLAD_GL_VERSION_1_4 = 0; -int GLAD_GL_VERSION_1_5 = 0; -int GLAD_GL_VERSION_2_0 = 0; -int GLAD_GL_VERSION_2_1 = 0; -int GLAD_GL_VERSION_3_0 = 0; -int GLAD_GL_VERSION_3_1 = 0; -int GLAD_GL_VERSION_3_2 = 0; -int GLAD_GL_VERSION_3_3 = 0; -int GLAD_GL_VERSION_4_0 = 0; -int GLAD_GL_VERSION_4_1 = 0; -int GLAD_GL_VERSION_4_2 = 0; -int GLAD_GL_VERSION_4_3 = 0; -int GLAD_GL_ARB_ES2_compatibility = 0; -int GLAD_GL_ARB_ES3_1_compatibility = 0; -int GLAD_GL_ARB_ES3_2_compatibility = 0; -int GLAD_GL_ARB_ES3_compatibility = 0; -int GLAD_GL_ARB_blend_func_extended = 0; -int GLAD_GL_ARB_buffer_storage = 0; -int GLAD_GL_ARB_clear_buffer_object = 0; -int GLAD_GL_ARB_clear_texture = 0; -int GLAD_GL_ARB_color_buffer_float = 0; -int GLAD_GL_ARB_compatibility = 0; -int GLAD_GL_ARB_compressed_texture_pixel_storage = 0; -int GLAD_GL_ARB_compute_shader = 0; -int GLAD_GL_ARB_compute_variable_group_size = 0; -int GLAD_GL_ARB_copy_buffer = 0; -int GLAD_GL_ARB_copy_image = 0; -int GLAD_GL_ARB_debug_output = 0; -int GLAD_GL_ARB_depth_buffer_float = 0; -int GLAD_GL_ARB_depth_clamp = 0; -int GLAD_GL_ARB_depth_texture = 0; -int GLAD_GL_ARB_direct_state_access = 0; -int GLAD_GL_ARB_draw_buffers = 0; -int GLAD_GL_ARB_draw_buffers_blend = 0; -int GLAD_GL_ARB_draw_elements_base_vertex = 0; -int GLAD_GL_ARB_draw_indirect = 0; -int GLAD_GL_ARB_draw_instanced = 0; -int GLAD_GL_ARB_enhanced_layouts = 0; -int GLAD_GL_ARB_explicit_attrib_location = 0; -int GLAD_GL_ARB_explicit_uniform_location = 0; -int GLAD_GL_ARB_fragment_coord_conventions = 0; -int GLAD_GL_ARB_fragment_layer_viewport = 0; -int GLAD_GL_ARB_fragment_program = 0; -int GLAD_GL_ARB_fragment_program_shadow = 0; -int GLAD_GL_ARB_fragment_shader = 0; -int GLAD_GL_ARB_fragment_shader_interlock = 0; -int GLAD_GL_ARB_framebuffer_no_attachments = 0; -int GLAD_GL_ARB_framebuffer_object = 0; -int GLAD_GL_ARB_framebuffer_sRGB = 0; -int GLAD_GL_ARB_geometry_shader4 = 0; -int GLAD_GL_ARB_get_program_binary = 0; -int GLAD_GL_ARB_get_texture_sub_image = 0; -int GLAD_GL_ARB_gl_spirv = 0; -int GLAD_GL_ARB_gpu_shader5 = 0; -int GLAD_GL_ARB_gpu_shader_fp64 = 0; -int GLAD_GL_ARB_gpu_shader_int64 = 0; -int GLAD_GL_ARB_half_float_pixel = 0; -int GLAD_GL_ARB_half_float_vertex = 0; -int GLAD_GL_ARB_instanced_arrays = 0; -int GLAD_GL_ARB_internalformat_query = 0; -int GLAD_GL_ARB_internalformat_query2 = 0; -int GLAD_GL_ARB_map_buffer_range = 0; -int GLAD_GL_ARB_multi_bind = 0; -int GLAD_GL_ARB_multi_draw_indirect = 0; -int GLAD_GL_ARB_multisample = 0; -int GLAD_GL_ARB_multitexture = 0; -int GLAD_GL_ARB_occlusion_query = 0; -int GLAD_GL_ARB_occlusion_query2 = 0; -int GLAD_GL_ARB_pipeline_statistics_query = 0; -int GLAD_GL_ARB_query_buffer_object = 0; -int GLAD_GL_ARB_sample_locations = 0; -int GLAD_GL_ARB_sample_shading = 0; -int GLAD_GL_ARB_seamless_cube_map = 0; -int GLAD_GL_ARB_seamless_cubemap_per_texture = 0; -int GLAD_GL_ARB_shader_atomic_counter_ops = 0; -int GLAD_GL_ARB_shader_atomic_counters = 0; -int GLAD_GL_ARB_shader_bit_encoding = 0; -int GLAD_GL_ARB_shader_clock = 0; -int GLAD_GL_ARB_shader_image_load_store = 0; -int GLAD_GL_ARB_shader_image_size = 0; -int GLAD_GL_ARB_shader_objects = 0; -int GLAD_GL_ARB_shader_storage_buffer_object = 0; -int GLAD_GL_ARB_shader_texture_lod = 0; -int GLAD_GL_ARB_shading_language_100 = 0; -int GLAD_GL_ARB_shading_language_420pack = 0; -int GLAD_GL_ARB_shading_language_include = 0; -int GLAD_GL_ARB_shading_language_packing = 0; -int GLAD_GL_ARB_spirv_extensions = 0; -int GLAD_GL_ARB_tessellation_shader = 0; -int GLAD_GL_ARB_texture_border_clamp = 0; -int GLAD_GL_ARB_texture_buffer_object_rgb32 = 0; -int GLAD_GL_ARB_texture_compression = 0; -int GLAD_GL_ARB_texture_cube_map = 0; -int GLAD_GL_ARB_texture_cube_map_array = 0; -int GLAD_GL_ARB_texture_env_add = 0; -int GLAD_GL_ARB_texture_filter_anisotropic = 0; -int GLAD_GL_ARB_texture_filter_minmax = 0; -int GLAD_GL_ARB_texture_float = 0; -int GLAD_GL_ARB_texture_mirror_clamp_to_edge = 0; -int GLAD_GL_ARB_texture_mirrored_repeat = 0; -int GLAD_GL_ARB_texture_multisample = 0; -int GLAD_GL_ARB_texture_non_power_of_two = 0; -int GLAD_GL_ARB_texture_rg = 0; -int GLAD_GL_ARB_texture_storage = 0; -int GLAD_GL_ARB_texture_swizzle = 0; -int GLAD_GL_ARB_texture_view = 0; -int GLAD_GL_ARB_timer_query = 0; -int GLAD_GL_ARB_transpose_matrix = 0; -int GLAD_GL_ARB_uniform_buffer_object = 0; -int GLAD_GL_ARB_vertex_array_bgra = 0; -int GLAD_GL_ARB_vertex_array_object = 0; -int GLAD_GL_ARB_vertex_attrib_binding = 0; -int GLAD_GL_ARB_vertex_buffer_object = 0; -int GLAD_GL_ARB_vertex_program = 0; -int GLAD_GL_ARB_vertex_shader = 0; -int GLAD_GL_EXT_draw_instanced = 0; -int GLAD_GL_EXT_fog_coord = 0; -int GLAD_GL_EXT_framebuffer_blit = 0; -int GLAD_GL_EXT_framebuffer_multisample = 0; -int GLAD_GL_EXT_framebuffer_object = 0; -int GLAD_GL_EXT_framebuffer_sRGB = 0; -int GLAD_GL_EXT_texture_compression_s3tc = 0; -int GLAD_GL_EXT_texture_filter_anisotropic = 0; -int GLAD_GL_EXT_texture_mirror_clamp = 0; -int GLAD_GL_KHR_texture_compression_astc_hdr = 0; -int GLAD_GL_KHR_texture_compression_astc_ldr = 0; -int GLAD_GL_OES_compressed_paletted_texture = 0; -int GLAD_GL_OES_fixed_point = 0; - - - -PFNGLACCUMXOESPROC glad_glAccumxOES = NULL; -PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL; -PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; -PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB = NULL; -PFNGLALPHAFUNCXOESPROC glad_glAlphaFuncxOES = NULL; -PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB = NULL; -PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; -PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; -PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; -PFNGLBEGINQUERYARBPROC glad_glBeginQueryARB = NULL; -PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL; -PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; -PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; -PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB = NULL; -PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; -PFNGLBINDBUFFERARBPROC glad_glBindBufferARB = NULL; -PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; -PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; -PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase = NULL; -PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange = NULL; -PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; -PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; -PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; -PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT = NULL; -PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL; -PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL; -PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB = NULL; -PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL; -PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; -PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT = NULL; -PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; -PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL; -PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; -PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit = NULL; -PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL; -PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL; -PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; -PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL; -PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL; -PFNGLBITMAPXOESPROC glad_glBitmapxOES = NULL; -PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; -PFNGLBLENDCOLORXOESPROC glad_glBlendColorxOES = NULL; -PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; -PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; -PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL; -PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB = NULL; -PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL; -PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB = NULL; -PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; -PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; -PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL; -PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB = NULL; -PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL; -PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB = NULL; -PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; -PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT = NULL; -PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer = NULL; -PFNGLBUFFERDATAPROC glad_glBufferData = NULL; -PFNGLBUFFERDATAARBPROC glad_glBufferDataARB = NULL; -PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL; -PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; -PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT = NULL; -PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus = NULL; -PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; -PFNGLCLAMPCOLORARBPROC glad_glClampColorARB = NULL; -PFNGLCLEARPROC glad_glClear = NULL; -PFNGLCLEARACCUMXOESPROC glad_glClearAccumxOES = NULL; -PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL; -PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL; -PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; -PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; -PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; -PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; -PFNGLCLEARCOLORPROC glad_glClearColor = NULL; -PFNGLCLEARCOLORXOESPROC glad_glClearColorxOES = NULL; -PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; -PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; -PFNGLCLEARDEPTHXOESPROC glad_glClearDepthxOES = NULL; -PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData = NULL; -PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData = NULL; -PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi = NULL; -PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv = NULL; -PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv = NULL; -PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv = NULL; -PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; -PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL; -PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL; -PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB = NULL; -PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; -PFNGLCLIPPLANEXOESPROC glad_glClipPlanexOES = NULL; -PFNGLCOLOR3XOESPROC glad_glColor3xOES = NULL; -PFNGLCOLOR3XVOESPROC glad_glColor3xvOES = NULL; -PFNGLCOLOR4XOESPROC glad_glColor4xOES = NULL; -PFNGLCOLOR4XVOESPROC glad_glColor4xvOES = NULL; -PFNGLCOLORMASKPROC glad_glColorMask = NULL; -PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; -PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; -PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB = NULL; -PFNGLCOMPILESHADERINCLUDEARBPROC glad_glCompileShaderIncludeARB = NULL; -PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; -PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB = NULL; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; -PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB = NULL; -PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; -PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB = NULL; -PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D = NULL; -PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D = NULL; -PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D = NULL; -PFNGLCONVOLUTIONPARAMETERXOESPROC glad_glConvolutionParameterxOES = NULL; -PFNGLCONVOLUTIONPARAMETERXVOESPROC glad_glConvolutionParameterxvOES = NULL; -PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; -PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL; -PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData = NULL; -PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; -PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; -PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; -PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D = NULL; -PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D = NULL; -PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D = NULL; -PFNGLCREATEBUFFERSPROC glad_glCreateBuffers = NULL; -PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers = NULL; -PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; -PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB = NULL; -PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines = NULL; -PFNGLCREATEQUERIESPROC glad_glCreateQueries = NULL; -PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers = NULL; -PFNGLCREATESAMPLERSPROC glad_glCreateSamplers = NULL; -PFNGLCREATESHADERPROC glad_glCreateShader = NULL; -PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB = NULL; -PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL; -PFNGLCREATETEXTURESPROC glad_glCreateTextures = NULL; -PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks = NULL; -PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays = NULL; -PFNGLCULLFACEPROC glad_glCullFace = NULL; -PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL; -PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL; -PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL; -PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL; -PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL; -PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL; -PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; -PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB = NULL; -PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; -PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT = NULL; -PFNGLDELETENAMEDSTRINGARBPROC glad_glDeleteNamedStringARB = NULL; -PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB = NULL; -PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; -PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL; -PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB = NULL; -PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; -PFNGLDELETEQUERIESARBPROC glad_glDeleteQueriesARB = NULL; -PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; -PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT = NULL; -PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; -PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; -PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; -PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; -PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL; -PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; -PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; -PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; -PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; -PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL; -PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL; -PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; -PFNGLDEPTHRANGEXOESPROC glad_glDepthRangexOES = NULL; -PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB = NULL; -PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; -PFNGLDISABLEPROC glad_glDisable = NULL; -PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib = NULL; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; -PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB = NULL; -PFNGLDISABLEIPROC glad_glDisablei = NULL; -PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL; -PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC glad_glDispatchComputeGroupSizeARB = NULL; -PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL; -PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; -PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL; -PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; -PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB = NULL; -PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL; -PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT = NULL; -PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; -PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; -PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB = NULL; -PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; -PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; -PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL; -PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; -PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL; -PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT = NULL; -PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; -PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; -PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL; -PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL; -PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL; -PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL; -PFNGLENABLEPROC glad_glEnable = NULL; -PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib = NULL; -PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; -PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB = NULL; -PFNGLENABLEIPROC glad_glEnablei = NULL; -PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; -PFNGLENDQUERYPROC glad_glEndQuery = NULL; -PFNGLENDQUERYARBPROC glad_glEndQueryARB = NULL; -PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL; -PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; -PFNGLEVALCOORD1XOESPROC glad_glEvalCoord1xOES = NULL; -PFNGLEVALCOORD1XVOESPROC glad_glEvalCoord1xvOES = NULL; -PFNGLEVALCOORD2XOESPROC glad_glEvalCoord2xOES = NULL; -PFNGLEVALCOORD2XVOESPROC glad_glEvalCoord2xvOES = NULL; -PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB = NULL; -PFNGLFEEDBACKBUFFERXOESPROC glad_glFeedbackBufferxOES = NULL; -PFNGLFENCESYNCPROC glad_glFenceSync = NULL; -PFNGLFINISHPROC glad_glFinish = NULL; -PFNGLFLUSHPROC glad_glFlush = NULL; -PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; -PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange = NULL; -PFNGLFOGCOORDPOINTEREXTPROC glad_glFogCoordPointerEXT = NULL; -PFNGLFOGCOORDDEXTPROC glad_glFogCoorddEXT = NULL; -PFNGLFOGCOORDDVEXTPROC glad_glFogCoorddvEXT = NULL; -PFNGLFOGCOORDFEXTPROC glad_glFogCoordfEXT = NULL; -PFNGLFOGCOORDFVEXTPROC glad_glFogCoordfvEXT = NULL; -PFNGLFOGXOESPROC glad_glFogxOES = NULL; -PFNGLFOGXVOESPROC glad_glFogxvOES = NULL; -PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL; -PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; -PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL; -PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB = NULL; -PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; -PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; -PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; -PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; -PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL; -PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB = NULL; -PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB = NULL; -PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; -PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB = NULL; -PFNGLFRONTFACEPROC glad_glFrontFace = NULL; -PFNGLFRUSTUMXOESPROC glad_glFrustumxOES = NULL; -PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; -PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB = NULL; -PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; -PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT = NULL; -PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL; -PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB = NULL; -PFNGLGENQUERIESPROC glad_glGenQueries = NULL; -PFNGLGENQUERIESARBPROC glad_glGenQueriesARB = NULL; -PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; -PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT = NULL; -PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; -PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; -PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL; -PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; -PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; -PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL; -PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap = NULL; -PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL; -PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; -PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB = NULL; -PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL; -PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL; -PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL; -PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; -PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB = NULL; -PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; -PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; -PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; -PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; -PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB = NULL; -PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; -PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; -PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB = NULL; -PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; -PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; -PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; -PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; -PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB = NULL; -PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; -PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB = NULL; -PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; -PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB = NULL; -PFNGLGETCLIPPLANEXOESPROC glad_glGetClipPlanexOES = NULL; -PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; -PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB = NULL; -PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage = NULL; -PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL; -PFNGLGETCONVOLUTIONPARAMETERXVOESPROC glad_glGetConvolutionParameterxvOES = NULL; -PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL; -PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB = NULL; -PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL; -PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; -PFNGLGETERRORPROC glad_glGetError = NULL; -PFNGLGETFIXEDVOESPROC glad_glGetFixedvOES = NULL; -PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL; -PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; -PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; -PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL; -PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL; -PFNGLGETHANDLEARBPROC glad_glGetHandleARB = NULL; -PFNGLGETHISTOGRAMPARAMETERXVOESPROC glad_glGetHistogramParameterxvOES = NULL; -PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB = NULL; -PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; -PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; -PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; -PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; -PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL; -PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL; -PFNGLGETLIGHTXOESPROC glad_glGetLightxOES = NULL; -PFNGLGETMAPXVOESPROC glad_glGetMapxvOES = NULL; -PFNGLGETMATERIALXOESPROC glad_glGetMaterialxOES = NULL; -PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; -PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v = NULL; -PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv = NULL; -PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv = NULL; -PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData = NULL; -PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv = NULL; -PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv = NULL; -PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv = NULL; -PFNGLGETNAMEDSTRINGARBPROC glad_glGetNamedStringARB = NULL; -PFNGLGETNAMEDSTRINGIVARBPROC glad_glGetNamedStringivARB = NULL; -PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL; -PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB = NULL; -PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB = NULL; -PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL; -PFNGLGETPIXELMAPXVPROC glad_glGetPixelMapxv = NULL; -PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; -PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL; -PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB = NULL; -PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB = NULL; -PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; -PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL; -PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB = NULL; -PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB = NULL; -PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL; -PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL; -PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL; -PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL; -PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL; -PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL; -PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL; -PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL; -PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB = NULL; -PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; -PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB = NULL; -PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v = NULL; -PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv = NULL; -PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v = NULL; -PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv = NULL; -PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL; -PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; -PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; -PFNGLGETQUERYOBJECTIVARBPROC glad_glGetQueryObjectivARB = NULL; -PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; -PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; -PFNGLGETQUERYOBJECTUIVARBPROC glad_glGetQueryObjectuivARB = NULL; -PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; -PFNGLGETQUERYIVARBPROC glad_glGetQueryivARB = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT = NULL; -PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; -PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; -PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; -PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; -PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; -PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; -PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; -PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB = NULL; -PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; -PFNGLGETSTRINGPROC glad_glGetString = NULL; -PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; -PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL; -PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL; -PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; -PFNGLGETTEXENVXVOESPROC glad_glGetTexEnvxvOES = NULL; -PFNGLGETTEXGENXVOESPROC glad_glGetTexGenxvOES = NULL; -PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; -PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; -PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; -PFNGLGETTEXLEVELPARAMETERXVOESPROC glad_glGetTexLevelParameterxvOES = NULL; -PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; -PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; -PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; -PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; -PFNGLGETTEXPARAMETERXVOESPROC glad_glGetTexParameterxvOES = NULL; -PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage = NULL; -PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv = NULL; -PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv = NULL; -PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv = NULL; -PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv = NULL; -PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv = NULL; -PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv = NULL; -PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL; -PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; -PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v = NULL; -PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v = NULL; -PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv = NULL; -PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; -PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; -PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; -PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB = NULL; -PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL; -PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL; -PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; -PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB = NULL; -PFNGLGETUNIFORMI64VARBPROC glad_glGetUniformi64vARB = NULL; -PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; -PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB = NULL; -PFNGLGETUNIFORMUI64VARBPROC glad_glGetUniformui64vARB = NULL; -PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; -PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv = NULL; -PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv = NULL; -PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv = NULL; -PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; -PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; -PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL; -PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; -PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB = NULL; -PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; -PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB = NULL; -PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; -PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB = NULL; -PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; -PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB = NULL; -PFNGLGETNUNIFORMI64VARBPROC glad_glGetnUniformi64vARB = NULL; -PFNGLGETNUNIFORMUI64VARBPROC glad_glGetnUniformui64vARB = NULL; -PFNGLHINTPROC glad_glHint = NULL; -PFNGLINDEXXOESPROC glad_glIndexxOES = NULL; -PFNGLINDEXXVOESPROC glad_glIndexxvOES = NULL; -PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL; -PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL; -PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL; -PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData = NULL; -PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData = NULL; -PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL; -PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL; -PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL; -PFNGLISBUFFERPROC glad_glIsBuffer = NULL; -PFNGLISBUFFERARBPROC glad_glIsBufferARB = NULL; -PFNGLISENABLEDPROC glad_glIsEnabled = NULL; -PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; -PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; -PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT = NULL; -PFNGLISNAMEDSTRINGARBPROC glad_glIsNamedStringARB = NULL; -PFNGLISPROGRAMPROC glad_glIsProgram = NULL; -PFNGLISPROGRAMARBPROC glad_glIsProgramARB = NULL; -PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL; -PFNGLISQUERYPROC glad_glIsQuery = NULL; -PFNGLISQUERYARBPROC glad_glIsQueryARB = NULL; -PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; -PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT = NULL; -PFNGLISSAMPLERPROC glad_glIsSampler = NULL; -PFNGLISSHADERPROC glad_glIsShader = NULL; -PFNGLISSYNCPROC glad_glIsSync = NULL; -PFNGLISTEXTUREPROC glad_glIsTexture = NULL; -PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL; -PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; -PFNGLLIGHTMODELXOESPROC glad_glLightModelxOES = NULL; -PFNGLLIGHTMODELXVOESPROC glad_glLightModelxvOES = NULL; -PFNGLLIGHTXOESPROC glad_glLightxOES = NULL; -PFNGLLIGHTXVOESPROC glad_glLightxvOES = NULL; -PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; -PFNGLLINEWIDTHXOESPROC glad_glLineWidthxOES = NULL; -PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; -PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB = NULL; -PFNGLLOADMATRIXXOESPROC glad_glLoadMatrixxOES = NULL; -PFNGLLOADTRANSPOSEMATRIXDARBPROC glad_glLoadTransposeMatrixdARB = NULL; -PFNGLLOADTRANSPOSEMATRIXFARBPROC glad_glLoadTransposeMatrixfARB = NULL; -PFNGLLOADTRANSPOSEMATRIXXOESPROC glad_glLoadTransposeMatrixxOES = NULL; -PFNGLLOGICOPPROC glad_glLogicOp = NULL; -PFNGLMAP1XOESPROC glad_glMap1xOES = NULL; -PFNGLMAP2XOESPROC glad_glMap2xOES = NULL; -PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; -PFNGLMAPBUFFERARBPROC glad_glMapBufferARB = NULL; -PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; -PFNGLMAPGRID1XOESPROC glad_glMapGrid1xOES = NULL; -PFNGLMAPGRID2XOESPROC glad_glMapGrid2xOES = NULL; -PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer = NULL; -PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange = NULL; -PFNGLMATERIALXOESPROC glad_glMaterialxOES = NULL; -PFNGLMATERIALXVOESPROC glad_glMaterialxvOES = NULL; -PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL; -PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL; -PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL; -PFNGLMINSAMPLESHADINGARBPROC glad_glMinSampleShadingARB = NULL; -PFNGLMULTMATRIXXOESPROC glad_glMultMatrixxOES = NULL; -PFNGLMULTTRANSPOSEMATRIXDARBPROC glad_glMultTransposeMatrixdARB = NULL; -PFNGLMULTTRANSPOSEMATRIXFARBPROC glad_glMultTransposeMatrixfARB = NULL; -PFNGLMULTTRANSPOSEMATRIXXOESPROC glad_glMultTransposeMatrixxOES = NULL; -PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; -PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL; -PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; -PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; -PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL; -PFNGLMULTITEXCOORD1DARBPROC glad_glMultiTexCoord1dARB = NULL; -PFNGLMULTITEXCOORD1DVARBPROC glad_glMultiTexCoord1dvARB = NULL; -PFNGLMULTITEXCOORD1FARBPROC glad_glMultiTexCoord1fARB = NULL; -PFNGLMULTITEXCOORD1FVARBPROC glad_glMultiTexCoord1fvARB = NULL; -PFNGLMULTITEXCOORD1IARBPROC glad_glMultiTexCoord1iARB = NULL; -PFNGLMULTITEXCOORD1IVARBPROC glad_glMultiTexCoord1ivARB = NULL; -PFNGLMULTITEXCOORD1SARBPROC glad_glMultiTexCoord1sARB = NULL; -PFNGLMULTITEXCOORD1SVARBPROC glad_glMultiTexCoord1svARB = NULL; -PFNGLMULTITEXCOORD1XOESPROC glad_glMultiTexCoord1xOES = NULL; -PFNGLMULTITEXCOORD1XVOESPROC glad_glMultiTexCoord1xvOES = NULL; -PFNGLMULTITEXCOORD2DARBPROC glad_glMultiTexCoord2dARB = NULL; -PFNGLMULTITEXCOORD2DVARBPROC glad_glMultiTexCoord2dvARB = NULL; -PFNGLMULTITEXCOORD2FARBPROC glad_glMultiTexCoord2fARB = NULL; -PFNGLMULTITEXCOORD2FVARBPROC glad_glMultiTexCoord2fvARB = NULL; -PFNGLMULTITEXCOORD2IARBPROC glad_glMultiTexCoord2iARB = NULL; -PFNGLMULTITEXCOORD2IVARBPROC glad_glMultiTexCoord2ivARB = NULL; -PFNGLMULTITEXCOORD2SARBPROC glad_glMultiTexCoord2sARB = NULL; -PFNGLMULTITEXCOORD2SVARBPROC glad_glMultiTexCoord2svARB = NULL; -PFNGLMULTITEXCOORD2XOESPROC glad_glMultiTexCoord2xOES = NULL; -PFNGLMULTITEXCOORD2XVOESPROC glad_glMultiTexCoord2xvOES = NULL; -PFNGLMULTITEXCOORD3DARBPROC glad_glMultiTexCoord3dARB = NULL; -PFNGLMULTITEXCOORD3DVARBPROC glad_glMultiTexCoord3dvARB = NULL; -PFNGLMULTITEXCOORD3FARBPROC glad_glMultiTexCoord3fARB = NULL; -PFNGLMULTITEXCOORD3FVARBPROC glad_glMultiTexCoord3fvARB = NULL; -PFNGLMULTITEXCOORD3IARBPROC glad_glMultiTexCoord3iARB = NULL; -PFNGLMULTITEXCOORD3IVARBPROC glad_glMultiTexCoord3ivARB = NULL; -PFNGLMULTITEXCOORD3SARBPROC glad_glMultiTexCoord3sARB = NULL; -PFNGLMULTITEXCOORD3SVARBPROC glad_glMultiTexCoord3svARB = NULL; -PFNGLMULTITEXCOORD3XOESPROC glad_glMultiTexCoord3xOES = NULL; -PFNGLMULTITEXCOORD3XVOESPROC glad_glMultiTexCoord3xvOES = NULL; -PFNGLMULTITEXCOORD4DARBPROC glad_glMultiTexCoord4dARB = NULL; -PFNGLMULTITEXCOORD4DVARBPROC glad_glMultiTexCoord4dvARB = NULL; -PFNGLMULTITEXCOORD4FARBPROC glad_glMultiTexCoord4fARB = NULL; -PFNGLMULTITEXCOORD4FVARBPROC glad_glMultiTexCoord4fvARB = NULL; -PFNGLMULTITEXCOORD4IARBPROC glad_glMultiTexCoord4iARB = NULL; -PFNGLMULTITEXCOORD4IVARBPROC glad_glMultiTexCoord4ivARB = NULL; -PFNGLMULTITEXCOORD4SARBPROC glad_glMultiTexCoord4sARB = NULL; -PFNGLMULTITEXCOORD4SVARBPROC glad_glMultiTexCoord4svARB = NULL; -PFNGLMULTITEXCOORD4XOESPROC glad_glMultiTexCoord4xOES = NULL; -PFNGLMULTITEXCOORD4XVOESPROC glad_glMultiTexCoord4xvOES = NULL; -PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData = NULL; -PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage = NULL; -PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData = NULL; -PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer = NULL; -PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers = NULL; -PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri = NULL; -PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer = NULL; -PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer = NULL; -PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB = NULL; -PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture = NULL; -PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer = NULL; -PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage = NULL; -PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample = NULL; -PFNGLNAMEDSTRINGARBPROC glad_glNamedStringARB = NULL; -PFNGLNORMAL3XOESPROC glad_glNormal3xOES = NULL; -PFNGLNORMAL3XVOESPROC glad_glNormal3xvOES = NULL; -PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL; -PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL; -PFNGLORTHOXOESPROC glad_glOrthoxOES = NULL; -PFNGLPASSTHROUGHXOESPROC glad_glPassThroughxOES = NULL; -PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL; -PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL; -PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL; -PFNGLPIXELMAPXPROC glad_glPixelMapx = NULL; -PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; -PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; -PFNGLPIXELSTOREXPROC glad_glPixelStorex = NULL; -PFNGLPIXELTRANSFERXOESPROC glad_glPixelTransferxOES = NULL; -PFNGLPIXELZOOMXOESPROC glad_glPixelZoomxOES = NULL; -PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; -PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; -PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; -PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; -PFNGLPOINTPARAMETERXVOESPROC glad_glPointParameterxvOES = NULL; -PFNGLPOINTSIZEPROC glad_glPointSize = NULL; -PFNGLPOINTSIZEXOESPROC glad_glPointSizexOES = NULL; -PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; -PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; -PFNGLPOLYGONOFFSETXOESPROC glad_glPolygonOffsetxOES = NULL; -PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL; -PFNGLPRIMITIVEBOUNDINGBOXARBPROC glad_glPrimitiveBoundingBoxARB = NULL; -PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; -PFNGLPRIORITIZETEXTURESXOESPROC glad_glPrioritizeTexturesxOES = NULL; -PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL; -PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB = NULL; -PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB = NULL; -PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB = NULL; -PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB = NULL; -PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB = NULL; -PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB = NULL; -PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB = NULL; -PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB = NULL; -PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL; -PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB = NULL; -PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB = NULL; -PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL; -PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL; -PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL; -PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL; -PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL; -PFNGLPROGRAMUNIFORM1I64ARBPROC glad_glProgramUniform1i64ARB = NULL; -PFNGLPROGRAMUNIFORM1I64VARBPROC glad_glProgramUniform1i64vARB = NULL; -PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL; -PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL; -PFNGLPROGRAMUNIFORM1UI64ARBPROC glad_glProgramUniform1ui64ARB = NULL; -PFNGLPROGRAMUNIFORM1UI64VARBPROC glad_glProgramUniform1ui64vARB = NULL; -PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL; -PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL; -PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL; -PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL; -PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL; -PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL; -PFNGLPROGRAMUNIFORM2I64ARBPROC glad_glProgramUniform2i64ARB = NULL; -PFNGLPROGRAMUNIFORM2I64VARBPROC glad_glProgramUniform2i64vARB = NULL; -PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL; -PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL; -PFNGLPROGRAMUNIFORM2UI64ARBPROC glad_glProgramUniform2ui64ARB = NULL; -PFNGLPROGRAMUNIFORM2UI64VARBPROC glad_glProgramUniform2ui64vARB = NULL; -PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL; -PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL; -PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL; -PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL; -PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL; -PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL; -PFNGLPROGRAMUNIFORM3I64ARBPROC glad_glProgramUniform3i64ARB = NULL; -PFNGLPROGRAMUNIFORM3I64VARBPROC glad_glProgramUniform3i64vARB = NULL; -PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL; -PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL; -PFNGLPROGRAMUNIFORM3UI64ARBPROC glad_glProgramUniform3ui64ARB = NULL; -PFNGLPROGRAMUNIFORM3UI64VARBPROC glad_glProgramUniform3ui64vARB = NULL; -PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL; -PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL; -PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL; -PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL; -PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL; -PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL; -PFNGLPROGRAMUNIFORM4I64ARBPROC glad_glProgramUniform4i64ARB = NULL; -PFNGLPROGRAMUNIFORM4I64VARBPROC glad_glProgramUniform4i64vARB = NULL; -PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL; -PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL; -PFNGLPROGRAMUNIFORM4UI64ARBPROC glad_glProgramUniform4ui64ARB = NULL; -PFNGLPROGRAMUNIFORM4UI64VARBPROC glad_glProgramUniform4ui64vARB = NULL; -PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL; -PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL; -PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; -PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL; -PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; -PFNGLRASTERPOS2XOESPROC glad_glRasterPos2xOES = NULL; -PFNGLRASTERPOS2XVOESPROC glad_glRasterPos2xvOES = NULL; -PFNGLRASTERPOS3XOESPROC glad_glRasterPos3xOES = NULL; -PFNGLRASTERPOS3XVOESPROC glad_glRasterPos3xvOES = NULL; -PFNGLRASTERPOS4XOESPROC glad_glRasterPos4xOES = NULL; -PFNGLRASTERPOS4XVOESPROC glad_glRasterPos4xvOES = NULL; -PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; -PFNGLREADPIXELSPROC glad_glReadPixels = NULL; -PFNGLRECTXOESPROC glad_glRectxOES = NULL; -PFNGLRECTXVOESPROC glad_glRectxvOES = NULL; -PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; -PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; -PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL; -PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL; -PFNGLROTATEXOESPROC glad_glRotatexOES = NULL; -PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; -PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB = NULL; -PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; -PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; -PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; -PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; -PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; -PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; -PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; -PFNGLSCALEXOESPROC glad_glScalexOES = NULL; -PFNGLSCISSORPROC glad_glScissor = NULL; -PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL; -PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL; -PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL; -PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; -PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; -PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB = NULL; -PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL; -PFNGLSPECIALIZESHADERARBPROC glad_glSpecializeShaderARB = NULL; -PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; -PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; -PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; -PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; -PFNGLSTENCILOPPROC glad_glStencilOp = NULL; -PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; -PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; -PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL; -PFNGLTEXCOORD1XOESPROC glad_glTexCoord1xOES = NULL; -PFNGLTEXCOORD1XVOESPROC glad_glTexCoord1xvOES = NULL; -PFNGLTEXCOORD2XOESPROC glad_glTexCoord2xOES = NULL; -PFNGLTEXCOORD2XVOESPROC glad_glTexCoord2xvOES = NULL; -PFNGLTEXCOORD3XOESPROC glad_glTexCoord3xOES = NULL; -PFNGLTEXCOORD3XVOESPROC glad_glTexCoord3xvOES = NULL; -PFNGLTEXCOORD4XOESPROC glad_glTexCoord4xOES = NULL; -PFNGLTEXCOORD4XVOESPROC glad_glTexCoord4xvOES = NULL; -PFNGLTEXENVXOESPROC glad_glTexEnvxOES = NULL; -PFNGLTEXENVXVOESPROC glad_glTexEnvxvOES = NULL; -PFNGLTEXGENXOESPROC glad_glTexGenxOES = NULL; -PFNGLTEXGENXVOESPROC glad_glTexGenxvOES = NULL; -PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; -PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; -PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; -PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; -PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; -PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; -PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; -PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; -PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; -PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; -PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; -PFNGLTEXPARAMETERXOESPROC glad_glTexParameterxOES = NULL; -PFNGLTEXPARAMETERXVOESPROC glad_glTexParameterxvOES = NULL; -PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL; -PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL; -PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL; -PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL; -PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL; -PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; -PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; -PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; -PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer = NULL; -PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange = NULL; -PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv = NULL; -PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv = NULL; -PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf = NULL; -PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv = NULL; -PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri = NULL; -PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv = NULL; -PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D = NULL; -PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D = NULL; -PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample = NULL; -PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D = NULL; -PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample = NULL; -PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D = NULL; -PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D = NULL; -PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D = NULL; -PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL; -PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase = NULL; -PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange = NULL; -PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; -PFNGLTRANSLATEXOESPROC glad_glTranslatexOES = NULL; -PFNGLUNIFORM1DPROC glad_glUniform1d = NULL; -PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL; -PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; -PFNGLUNIFORM1FARBPROC glad_glUniform1fARB = NULL; -PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; -PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB = NULL; -PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; -PFNGLUNIFORM1I64ARBPROC glad_glUniform1i64ARB = NULL; -PFNGLUNIFORM1I64VARBPROC glad_glUniform1i64vARB = NULL; -PFNGLUNIFORM1IARBPROC glad_glUniform1iARB = NULL; -PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; -PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB = NULL; -PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; -PFNGLUNIFORM1UI64ARBPROC glad_glUniform1ui64ARB = NULL; -PFNGLUNIFORM1UI64VARBPROC glad_glUniform1ui64vARB = NULL; -PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; -PFNGLUNIFORM2DPROC glad_glUniform2d = NULL; -PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL; -PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; -PFNGLUNIFORM2FARBPROC glad_glUniform2fARB = NULL; -PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; -PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB = NULL; -PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; -PFNGLUNIFORM2I64ARBPROC glad_glUniform2i64ARB = NULL; -PFNGLUNIFORM2I64VARBPROC glad_glUniform2i64vARB = NULL; -PFNGLUNIFORM2IARBPROC glad_glUniform2iARB = NULL; -PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; -PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB = NULL; -PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; -PFNGLUNIFORM2UI64ARBPROC glad_glUniform2ui64ARB = NULL; -PFNGLUNIFORM2UI64VARBPROC glad_glUniform2ui64vARB = NULL; -PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; -PFNGLUNIFORM3DPROC glad_glUniform3d = NULL; -PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL; -PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; -PFNGLUNIFORM3FARBPROC glad_glUniform3fARB = NULL; -PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; -PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB = NULL; -PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; -PFNGLUNIFORM3I64ARBPROC glad_glUniform3i64ARB = NULL; -PFNGLUNIFORM3I64VARBPROC glad_glUniform3i64vARB = NULL; -PFNGLUNIFORM3IARBPROC glad_glUniform3iARB = NULL; -PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; -PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB = NULL; -PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; -PFNGLUNIFORM3UI64ARBPROC glad_glUniform3ui64ARB = NULL; -PFNGLUNIFORM3UI64VARBPROC glad_glUniform3ui64vARB = NULL; -PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; -PFNGLUNIFORM4DPROC glad_glUniform4d = NULL; -PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL; -PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; -PFNGLUNIFORM4FARBPROC glad_glUniform4fARB = NULL; -PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; -PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB = NULL; -PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; -PFNGLUNIFORM4I64ARBPROC glad_glUniform4i64ARB = NULL; -PFNGLUNIFORM4I64VARBPROC glad_glUniform4i64vARB = NULL; -PFNGLUNIFORM4IARBPROC glad_glUniform4iARB = NULL; -PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; -PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB = NULL; -PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; -PFNGLUNIFORM4UI64ARBPROC glad_glUniform4ui64ARB = NULL; -PFNGLUNIFORM4UI64VARBPROC glad_glUniform4ui64vARB = NULL; -PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; -PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; -PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL; -PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; -PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB = NULL; -PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL; -PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; -PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL; -PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; -PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL; -PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; -PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB = NULL; -PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL; -PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; -PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL; -PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; -PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL; -PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; -PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB = NULL; -PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL; -PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; -PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL; -PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; -PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL; -PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; -PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB = NULL; -PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer = NULL; -PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; -PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB = NULL; -PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL; -PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; -PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB = NULL; -PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL; -PFNGLVERTEX2XOESPROC glad_glVertex2xOES = NULL; -PFNGLVERTEX2XVOESPROC glad_glVertex2xvOES = NULL; -PFNGLVERTEX3XOESPROC glad_glVertex3xOES = NULL; -PFNGLVERTEX3XVOESPROC glad_glVertex3xvOES = NULL; -PFNGLVERTEX4XOESPROC glad_glVertex4xOES = NULL; -PFNGLVERTEX4XVOESPROC glad_glVertex4xvOES = NULL; -PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding = NULL; -PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat = NULL; -PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat = NULL; -PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat = NULL; -PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor = NULL; -PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer = NULL; -PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer = NULL; -PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers = NULL; -PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; -PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB = NULL; -PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; -PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB = NULL; -PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; -PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB = NULL; -PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; -PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB = NULL; -PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; -PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB = NULL; -PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; -PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB = NULL; -PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; -PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB = NULL; -PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; -PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB = NULL; -PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; -PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB = NULL; -PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; -PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB = NULL; -PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; -PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB = NULL; -PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; -PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB = NULL; -PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; -PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB = NULL; -PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; -PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB = NULL; -PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; -PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB = NULL; -PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; -PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB = NULL; -PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; -PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB = NULL; -PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; -PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB = NULL; -PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; -PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB = NULL; -PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; -PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB = NULL; -PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; -PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB = NULL; -PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; -PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB = NULL; -PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; -PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB = NULL; -PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; -PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB = NULL; -PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; -PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB = NULL; -PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; -PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB = NULL; -PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; -PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB = NULL; -PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; -PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB = NULL; -PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; -PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB = NULL; -PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; -PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB = NULL; -PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; -PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB = NULL; -PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; -PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB = NULL; -PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; -PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB = NULL; -PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; -PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB = NULL; -PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; -PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB = NULL; -PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; -PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB = NULL; -PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL; -PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; -PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB = NULL; -PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL; -PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; -PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; -PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; -PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; -PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; -PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; -PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; -PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; -PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; -PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; -PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; -PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; -PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; -PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; -PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; -PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; -PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; -PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; -PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; -PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; -PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL; -PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; -PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL; -PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL; -PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL; -PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL; -PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL; -PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL; -PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL; -PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL; -PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL; -PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL; -PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; -PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; -PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; -PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; -PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; -PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; -PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; -PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; -PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; -PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB = NULL; -PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL; -PFNGLVIEWPORTPROC glad_glViewport = NULL; -PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL; -PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL; -PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL; -PFNGLWAITSYNCPROC glad_glWaitSync = NULL; - - -static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_1_0) return; - glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); - glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); - glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); - glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, "glClearDepth"); - glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); - glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); - glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); - glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); - glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); - glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, "glDepthRange"); - glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); - glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, "glDrawBuffer"); - glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); - glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); - glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); - glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); - glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); - glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, "glGetDoublev"); - glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); - glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); - glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); - glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); - glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, "glGetTexImage"); - glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv"); - glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv"); - glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); - glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); - glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); - glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); - glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); - glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, "glLogicOp"); - glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, "glPixelStoref"); - glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); - glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, "glPointSize"); - glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, "glPolygonMode"); - glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer"); - glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); - glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); - glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); - glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); - glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); - glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, "glTexImage1D"); - glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); - glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); - glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); - glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); - glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); - glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); -} -static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_1_1) return; - glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); - glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, "glCopyTexImage1D"); - glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); - glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, "glCopyTexSubImage1D"); - glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); - glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); - glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); - glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); - glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); - glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv"); - glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); - glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); - glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, "glTexSubImage1D"); - glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); -} -static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_1_2) return; - glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D"); - glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements"); - glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D"); - glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D"); -} -static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_1_3) return; - glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); - glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, "glCompressedTexImage1D"); - glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); - glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D"); - glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, "glCompressedTexSubImage1D"); - glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); - glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D"); - glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, "glGetCompressedTexImage"); - glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); -} -static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_1_4) return; - glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); - glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); - glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); - glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, "glMultiDrawArrays"); - glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, "glMultiDrawElements"); - glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, "glPointParameterf"); - glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, "glPointParameterfv"); - glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, "glPointParameteri"); - glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, "glPointParameteriv"); -} -static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_1_5) return; - glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery"); - glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); - glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); - glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); - glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); - glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries"); - glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery"); - glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); - glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries"); - glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); - glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv"); - glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, "glGetBufferSubData"); - glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, "glGetQueryObjectiv"); - glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv"); - glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv"); - glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); - glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery"); - glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, "glMapBuffer"); - glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer"); -} -static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_2_0) return; - glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); - glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); - glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); - glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); - glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); - glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); - glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); - glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); - glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); - glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); - glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers"); - glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); - glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); - glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); - glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); - glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); - glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); - glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); - glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); - glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); - glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); - glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); - glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); - glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); - glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); - glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, "glGetVertexAttribdv"); - glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); - glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); - glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); - glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); - glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); - glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); - glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); - glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); - glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); - glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); - glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); - glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); - glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); - glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); - glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); - glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); - glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); - glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); - glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); - glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); - glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); - glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); - glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); - glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); - glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); - glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); - glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); - glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); - glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); - glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); - glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, "glVertexAttrib1d"); - glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, "glVertexAttrib1dv"); - glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); - glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); - glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, "glVertexAttrib1s"); - glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, "glVertexAttrib1sv"); - glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, "glVertexAttrib2d"); - glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, "glVertexAttrib2dv"); - glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); - glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); - glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, "glVertexAttrib2s"); - glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, "glVertexAttrib2sv"); - glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, "glVertexAttrib3d"); - glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, "glVertexAttrib3dv"); - glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); - glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); - glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, "glVertexAttrib3s"); - glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, "glVertexAttrib3sv"); - glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, "glVertexAttrib4Nbv"); - glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, "glVertexAttrib4Niv"); - glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, "glVertexAttrib4Nsv"); - glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, "glVertexAttrib4Nub"); - glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, "glVertexAttrib4Nubv"); - glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, "glVertexAttrib4Nuiv"); - glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, "glVertexAttrib4Nusv"); - glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, "glVertexAttrib4bv"); - glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, "glVertexAttrib4d"); - glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, "glVertexAttrib4dv"); - glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); - glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); - glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, "glVertexAttrib4iv"); - glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, "glVertexAttrib4s"); - glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, "glVertexAttrib4sv"); - glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, "glVertexAttrib4ubv"); - glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, "glVertexAttrib4uiv"); - glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, "glVertexAttrib4usv"); - glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); -} -static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_2_1) return; - glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv"); - glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv"); - glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv"); - glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv"); - glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv"); - glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv"); -} -static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_3_0) return; - glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load(userptr, "glBeginConditionalRender"); - glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange"); - glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load(userptr, "glBindFragDataLocation"); - glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); - glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); - glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray"); - glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer"); - glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); - glad_glClampColor = (PFNGLCLAMPCOLORPROC) load(userptr, "glClampColor"); - glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi"); - glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv"); - glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv"); - glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv"); - glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, "glColorMaski"); - glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); - glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); - glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays"); - glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, "glDisablei"); - glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, "glEnablei"); - glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load(userptr, "glEndConditionalRender"); - glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback"); - glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange"); - glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); - glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D"); - glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); - glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D"); - glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer"); - glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); - glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); - glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays"); - glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); - glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, "glGetBooleani_v"); - glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation"); - glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v"); - glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); - glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi"); - glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, "glGetTexParameterIiv"); - glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, "glGetTexParameterIuiv"); - glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying"); - glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv"); - glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv"); - glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv"); - glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, "glIsEnabledi"); - glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); - glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); - glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray"); - glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange"); - glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); - glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample"); - glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, "glTexParameterIiv"); - glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, "glTexParameterIuiv"); - glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings"); - glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui"); - glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv"); - glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui"); - glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv"); - glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui"); - glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv"); - glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui"); - glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv"); - glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load(userptr, "glVertexAttribI1i"); - glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load(userptr, "glVertexAttribI1iv"); - glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load(userptr, "glVertexAttribI1ui"); - glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load(userptr, "glVertexAttribI1uiv"); - glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load(userptr, "glVertexAttribI2i"); - glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load(userptr, "glVertexAttribI2iv"); - glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load(userptr, "glVertexAttribI2ui"); - glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load(userptr, "glVertexAttribI2uiv"); - glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load(userptr, "glVertexAttribI3i"); - glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load(userptr, "glVertexAttribI3iv"); - glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load(userptr, "glVertexAttribI3ui"); - glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load(userptr, "glVertexAttribI3uiv"); - glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load(userptr, "glVertexAttribI4bv"); - glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i"); - glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv"); - glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load(userptr, "glVertexAttribI4sv"); - glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load(userptr, "glVertexAttribI4ubv"); - glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui"); - glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv"); - glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load(userptr, "glVertexAttribI4usv"); - glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer"); -} -static void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_3_1) return; - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange"); - glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData"); - glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, "glDrawArraysInstanced"); - glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, "glDrawElementsInstanced"); - glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName"); - glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv"); - glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load(userptr, "glGetActiveUniformName"); - glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v"); - glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex"); - glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices"); - glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load(userptr, "glPrimitiveRestartIndex"); - glad_glTexBuffer = (PFNGLTEXBUFFERPROC) load(userptr, "glTexBuffer"); - glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding"); -} -static void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_3_2) return; - glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync"); - glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync"); - glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glDrawElementsBaseVertex"); - glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, "glDrawElementsInstancedBaseVertex"); - glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, "glDrawRangeElementsBaseVertex"); - glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync"); - glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load(userptr, "glFramebufferTexture"); - glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, "glGetBufferParameteri64v"); - glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, "glGetInteger64i_v"); - glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v"); - glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv"); - glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv"); - glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync"); - glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glMultiDrawElementsBaseVertex"); - glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load(userptr, "glProvokingVertex"); - glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski"); - glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, "glTexImage2DMultisample"); - glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, "glTexImage3DMultisample"); - glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync"); -} -static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_3_3) return; - glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load(userptr, "glBindFragDataLocationIndexed"); - glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, "glBindSampler"); - glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, "glDeleteSamplers"); - glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, "glGenSamplers"); - glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load(userptr, "glGetFragDataIndex"); - glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, "glGetQueryObjecti64v"); - glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, "glGetQueryObjectui64v"); - glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load(userptr, "glGetSamplerParameterIiv"); - glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load(userptr, "glGetSamplerParameterIuiv"); - glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, "glGetSamplerParameterfv"); - glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, "glGetSamplerParameteriv"); - glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, "glIsSampler"); - glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, "glQueryCounter"); - glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load(userptr, "glSamplerParameterIiv"); - glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load(userptr, "glSamplerParameterIuiv"); - glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, "glSamplerParameterf"); - glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, "glSamplerParameterfv"); - glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, "glSamplerParameteri"); - glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, "glSamplerParameteriv"); - glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, "glVertexAttribDivisor"); - glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load(userptr, "glVertexAttribP1ui"); - glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load(userptr, "glVertexAttribP1uiv"); - glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load(userptr, "glVertexAttribP2ui"); - glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load(userptr, "glVertexAttribP2uiv"); - glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load(userptr, "glVertexAttribP3ui"); - glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load(userptr, "glVertexAttribP3uiv"); - glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load(userptr, "glVertexAttribP4ui"); - glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load(userptr, "glVertexAttribP4uiv"); -} -static void glad_gl_load_GL_VERSION_4_0( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_4_0) return; - glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC) load(userptr, "glBeginQueryIndexed"); - glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) load(userptr, "glBindTransformFeedback"); - glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC) load(userptr, "glBlendEquationSeparatei"); - glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC) load(userptr, "glBlendEquationi"); - glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC) load(userptr, "glBlendFuncSeparatei"); - glad_glBlendFunci = (PFNGLBLENDFUNCIPROC) load(userptr, "glBlendFunci"); - glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) load(userptr, "glDeleteTransformFeedbacks"); - glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) load(userptr, "glDrawArraysIndirect"); - glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) load(userptr, "glDrawElementsIndirect"); - glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC) load(userptr, "glDrawTransformFeedback"); - glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) load(userptr, "glDrawTransformFeedbackStream"); - glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC) load(userptr, "glEndQueryIndexed"); - glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) load(userptr, "glGenTransformFeedbacks"); - glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC) load(userptr, "glGetActiveSubroutineName"); - glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) load(userptr, "glGetActiveSubroutineUniformName"); - glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) load(userptr, "glGetActiveSubroutineUniformiv"); - glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC) load(userptr, "glGetProgramStageiv"); - glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC) load(userptr, "glGetQueryIndexediv"); - glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC) load(userptr, "glGetSubroutineIndex"); - glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) load(userptr, "glGetSubroutineUniformLocation"); - glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC) load(userptr, "glGetUniformSubroutineuiv"); - glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC) load(userptr, "glGetUniformdv"); - glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) load(userptr, "glIsTransformFeedback"); - glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC) load(userptr, "glMinSampleShading"); - glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC) load(userptr, "glPatchParameterfv"); - glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) load(userptr, "glPatchParameteri"); - glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) load(userptr, "glPauseTransformFeedback"); - glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) load(userptr, "glResumeTransformFeedback"); - glad_glUniform1d = (PFNGLUNIFORM1DPROC) load(userptr, "glUniform1d"); - glad_glUniform1dv = (PFNGLUNIFORM1DVPROC) load(userptr, "glUniform1dv"); - glad_glUniform2d = (PFNGLUNIFORM2DPROC) load(userptr, "glUniform2d"); - glad_glUniform2dv = (PFNGLUNIFORM2DVPROC) load(userptr, "glUniform2dv"); - glad_glUniform3d = (PFNGLUNIFORM3DPROC) load(userptr, "glUniform3d"); - glad_glUniform3dv = (PFNGLUNIFORM3DVPROC) load(userptr, "glUniform3dv"); - glad_glUniform4d = (PFNGLUNIFORM4DPROC) load(userptr, "glUniform4d"); - glad_glUniform4dv = (PFNGLUNIFORM4DVPROC) load(userptr, "glUniform4dv"); - glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC) load(userptr, "glUniformMatrix2dv"); - glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC) load(userptr, "glUniformMatrix2x3dv"); - glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC) load(userptr, "glUniformMatrix2x4dv"); - glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC) load(userptr, "glUniformMatrix3dv"); - glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC) load(userptr, "glUniformMatrix3x2dv"); - glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC) load(userptr, "glUniformMatrix3x4dv"); - glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC) load(userptr, "glUniformMatrix4dv"); - glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC) load(userptr, "glUniformMatrix4x2dv"); - glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC) load(userptr, "glUniformMatrix4x3dv"); - glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC) load(userptr, "glUniformSubroutinesuiv"); -} -static void glad_gl_load_GL_VERSION_4_1( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_4_1) return; - glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC) load(userptr, "glActiveShaderProgram"); - glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC) load(userptr, "glBindProgramPipeline"); - glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); - glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC) load(userptr, "glCreateShaderProgramv"); - glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC) load(userptr, "glDeleteProgramPipelines"); - glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC) load(userptr, "glDepthRangeArrayv"); - glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC) load(userptr, "glDepthRangeIndexed"); - glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); - glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC) load(userptr, "glGenProgramPipelines"); - glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC) load(userptr, "glGetDoublei_v"); - glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC) load(userptr, "glGetFloati_v"); - glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, "glGetProgramBinary"); - glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC) load(userptr, "glGetProgramPipelineInfoLog"); - glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC) load(userptr, "glGetProgramPipelineiv"); - glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); - glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC) load(userptr, "glGetVertexAttribLdv"); - glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC) load(userptr, "glIsProgramPipeline"); - glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, "glProgramBinary"); - glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, "glProgramParameteri"); - glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC) load(userptr, "glProgramUniform1d"); - glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC) load(userptr, "glProgramUniform1dv"); - glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC) load(userptr, "glProgramUniform1f"); - glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC) load(userptr, "glProgramUniform1fv"); - glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC) load(userptr, "glProgramUniform1i"); - glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC) load(userptr, "glProgramUniform1iv"); - glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC) load(userptr, "glProgramUniform1ui"); - glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC) load(userptr, "glProgramUniform1uiv"); - glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC) load(userptr, "glProgramUniform2d"); - glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC) load(userptr, "glProgramUniform2dv"); - glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC) load(userptr, "glProgramUniform2f"); - glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC) load(userptr, "glProgramUniform2fv"); - glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC) load(userptr, "glProgramUniform2i"); - glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC) load(userptr, "glProgramUniform2iv"); - glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC) load(userptr, "glProgramUniform2ui"); - glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC) load(userptr, "glProgramUniform2uiv"); - glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC) load(userptr, "glProgramUniform3d"); - glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC) load(userptr, "glProgramUniform3dv"); - glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC) load(userptr, "glProgramUniform3f"); - glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC) load(userptr, "glProgramUniform3fv"); - glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC) load(userptr, "glProgramUniform3i"); - glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC) load(userptr, "glProgramUniform3iv"); - glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC) load(userptr, "glProgramUniform3ui"); - glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC) load(userptr, "glProgramUniform3uiv"); - glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC) load(userptr, "glProgramUniform4d"); - glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC) load(userptr, "glProgramUniform4dv"); - glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC) load(userptr, "glProgramUniform4f"); - glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC) load(userptr, "glProgramUniform4fv"); - glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC) load(userptr, "glProgramUniform4i"); - glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC) load(userptr, "glProgramUniform4iv"); - glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC) load(userptr, "glProgramUniform4ui"); - glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC) load(userptr, "glProgramUniform4uiv"); - glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC) load(userptr, "glProgramUniformMatrix2dv"); - glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC) load(userptr, "glProgramUniformMatrix2fv"); - glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) load(userptr, "glProgramUniformMatrix2x3dv"); - glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) load(userptr, "glProgramUniformMatrix2x3fv"); - glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) load(userptr, "glProgramUniformMatrix2x4dv"); - glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) load(userptr, "glProgramUniformMatrix2x4fv"); - glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC) load(userptr, "glProgramUniformMatrix3dv"); - glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC) load(userptr, "glProgramUniformMatrix3fv"); - glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) load(userptr, "glProgramUniformMatrix3x2dv"); - glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) load(userptr, "glProgramUniformMatrix3x2fv"); - glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) load(userptr, "glProgramUniformMatrix3x4dv"); - glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) load(userptr, "glProgramUniformMatrix3x4fv"); - glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC) load(userptr, "glProgramUniformMatrix4dv"); - glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC) load(userptr, "glProgramUniformMatrix4fv"); - glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) load(userptr, "glProgramUniformMatrix4x2dv"); - glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) load(userptr, "glProgramUniformMatrix4x2fv"); - glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) load(userptr, "glProgramUniformMatrix4x3dv"); - glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) load(userptr, "glProgramUniformMatrix4x3fv"); - glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); - glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC) load(userptr, "glScissorArrayv"); - glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC) load(userptr, "glScissorIndexed"); - glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC) load(userptr, "glScissorIndexedv"); - glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); - glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC) load(userptr, "glUseProgramStages"); - glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC) load(userptr, "glValidateProgramPipeline"); - glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC) load(userptr, "glVertexAttribL1d"); - glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC) load(userptr, "glVertexAttribL1dv"); - glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC) load(userptr, "glVertexAttribL2d"); - glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC) load(userptr, "glVertexAttribL2dv"); - glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC) load(userptr, "glVertexAttribL3d"); - glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC) load(userptr, "glVertexAttribL3dv"); - glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC) load(userptr, "glVertexAttribL4d"); - glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC) load(userptr, "glVertexAttribL4dv"); - glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC) load(userptr, "glVertexAttribLPointer"); - glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC) load(userptr, "glViewportArrayv"); - glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC) load(userptr, "glViewportIndexedf"); - glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC) load(userptr, "glViewportIndexedfv"); -} -static void glad_gl_load_GL_VERSION_4_2( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_4_2) return; - glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC) load(userptr, "glBindImageTexture"); - glad_glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) load(userptr, "glDrawArraysInstancedBaseInstance"); - glad_glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) load(userptr, "glDrawElementsInstancedBaseInstance"); - glad_glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) load(userptr, "glDrawElementsInstancedBaseVertexBaseInstance"); - glad_glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) load(userptr, "glDrawTransformFeedbackInstanced"); - glad_glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) load(userptr, "glDrawTransformFeedbackStreamInstanced"); - glad_glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) load(userptr, "glGetActiveAtomicCounterBufferiv"); - glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC) load(userptr, "glGetInternalformativ"); - glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC) load(userptr, "glMemoryBarrier"); - glad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC) load(userptr, "glTexStorage1D"); - glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC) load(userptr, "glTexStorage2D"); - glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC) load(userptr, "glTexStorage3D"); -} -static void glad_gl_load_GL_VERSION_4_3( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_VERSION_4_3) return; - glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC) load(userptr, "glBindVertexBuffer"); - glad_glClearBufferData = (PFNGLCLEARBUFFERDATAPROC) load(userptr, "glClearBufferData"); - glad_glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC) load(userptr, "glClearBufferSubData"); - glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC) load(userptr, "glCopyImageSubData"); - glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load(userptr, "glDebugMessageCallback"); - glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load(userptr, "glDebugMessageControl"); - glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load(userptr, "glDebugMessageInsert"); - glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC) load(userptr, "glDispatchCompute"); - glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC) load(userptr, "glDispatchComputeIndirect"); - glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC) load(userptr, "glFramebufferParameteri"); - glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load(userptr, "glGetDebugMessageLog"); - glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC) load(userptr, "glGetFramebufferParameteriv"); - glad_glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC) load(userptr, "glGetInternalformati64v"); - glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load(userptr, "glGetObjectLabel"); - glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load(userptr, "glGetObjectPtrLabel"); - glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv"); - glad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC) load(userptr, "glGetProgramInterfaceiv"); - glad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC) load(userptr, "glGetProgramResourceIndex"); - glad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC) load(userptr, "glGetProgramResourceLocation"); - glad_glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) load(userptr, "glGetProgramResourceLocationIndex"); - glad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC) load(userptr, "glGetProgramResourceName"); - glad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC) load(userptr, "glGetProgramResourceiv"); - glad_glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC) load(userptr, "glInvalidateBufferData"); - glad_glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC) load(userptr, "glInvalidateBufferSubData"); - glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC) load(userptr, "glInvalidateFramebuffer"); - glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC) load(userptr, "glInvalidateSubFramebuffer"); - glad_glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC) load(userptr, "glInvalidateTexImage"); - glad_glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC) load(userptr, "glInvalidateTexSubImage"); - glad_glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC) load(userptr, "glMultiDrawArraysIndirect"); - glad_glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC) load(userptr, "glMultiDrawElementsIndirect"); - glad_glObjectLabel = (PFNGLOBJECTLABELPROC) load(userptr, "glObjectLabel"); - glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load(userptr, "glObjectPtrLabel"); - glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load(userptr, "glPopDebugGroup"); - glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load(userptr, "glPushDebugGroup"); - glad_glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC) load(userptr, "glShaderStorageBlockBinding"); - glad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC) load(userptr, "glTexBufferRange"); - glad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC) load(userptr, "glTexStorage2DMultisample"); - glad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC) load(userptr, "glTexStorage3DMultisample"); - glad_glTextureView = (PFNGLTEXTUREVIEWPROC) load(userptr, "glTextureView"); - glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC) load(userptr, "glVertexAttribBinding"); - glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC) load(userptr, "glVertexAttribFormat"); - glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC) load(userptr, "glVertexAttribIFormat"); - glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC) load(userptr, "glVertexAttribLFormat"); - glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC) load(userptr, "glVertexBindingDivisor"); -} -static void glad_gl_load_GL_ARB_ES2_compatibility( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_ES2_compatibility) return; - glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); - glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); - glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); - glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); - glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); -} -static void glad_gl_load_GL_ARB_ES3_1_compatibility( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_ES3_1_compatibility) return; - glad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC) load(userptr, "glMemoryBarrierByRegion"); -} -static void glad_gl_load_GL_ARB_ES3_2_compatibility( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_ES3_2_compatibility) return; - glad_glPrimitiveBoundingBoxARB = (PFNGLPRIMITIVEBOUNDINGBOXARBPROC) load(userptr, "glPrimitiveBoundingBoxARB"); -} -static void glad_gl_load_GL_ARB_blend_func_extended( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_blend_func_extended) return; - glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load(userptr, "glBindFragDataLocationIndexed"); - glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load(userptr, "glGetFragDataIndex"); -} -static void glad_gl_load_GL_ARB_buffer_storage( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_buffer_storage) return; - glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC) load(userptr, "glBufferStorage"); -} -static void glad_gl_load_GL_ARB_clear_buffer_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_clear_buffer_object) return; - glad_glClearBufferData = (PFNGLCLEARBUFFERDATAPROC) load(userptr, "glClearBufferData"); - glad_glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC) load(userptr, "glClearBufferSubData"); -} -static void glad_gl_load_GL_ARB_clear_texture( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_clear_texture) return; - glad_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC) load(userptr, "glClearTexImage"); - glad_glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC) load(userptr, "glClearTexSubImage"); -} -static void glad_gl_load_GL_ARB_color_buffer_float( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_color_buffer_float) return; - glad_glClampColorARB = (PFNGLCLAMPCOLORARBPROC) load(userptr, "glClampColorARB"); -} -static void glad_gl_load_GL_ARB_compute_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_compute_shader) return; - glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC) load(userptr, "glDispatchCompute"); - glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC) load(userptr, "glDispatchComputeIndirect"); -} -static void glad_gl_load_GL_ARB_compute_variable_group_size( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_compute_variable_group_size) return; - glad_glDispatchComputeGroupSizeARB = (PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) load(userptr, "glDispatchComputeGroupSizeARB"); -} -static void glad_gl_load_GL_ARB_copy_buffer( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_copy_buffer) return; - glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData"); -} -static void glad_gl_load_GL_ARB_copy_image( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_copy_image) return; - glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC) load(userptr, "glCopyImageSubData"); -} -static void glad_gl_load_GL_ARB_debug_output( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_debug_output) return; - glad_glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) load(userptr, "glDebugMessageCallbackARB"); - glad_glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) load(userptr, "glDebugMessageControlARB"); - glad_glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) load(userptr, "glDebugMessageInsertARB"); - glad_glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) load(userptr, "glGetDebugMessageLogARB"); -} -static void glad_gl_load_GL_ARB_direct_state_access( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_direct_state_access) return; - glad_glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC) load(userptr, "glBindTextureUnit"); - glad_glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC) load(userptr, "glBlitNamedFramebuffer"); - glad_glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckNamedFramebufferStatus"); - glad_glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC) load(userptr, "glClearNamedBufferData"); - glad_glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC) load(userptr, "glClearNamedBufferSubData"); - glad_glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) load(userptr, "glClearNamedFramebufferfi"); - glad_glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) load(userptr, "glClearNamedFramebufferfv"); - glad_glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) load(userptr, "glClearNamedFramebufferiv"); - glad_glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) load(userptr, "glClearNamedFramebufferuiv"); - glad_glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) load(userptr, "glCompressedTextureSubImage1D"); - glad_glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) load(userptr, "glCompressedTextureSubImage2D"); - glad_glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) load(userptr, "glCompressedTextureSubImage3D"); - glad_glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC) load(userptr, "glCopyNamedBufferSubData"); - glad_glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC) load(userptr, "glCopyTextureSubImage1D"); - glad_glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC) load(userptr, "glCopyTextureSubImage2D"); - glad_glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC) load(userptr, "glCopyTextureSubImage3D"); - glad_glCreateBuffers = (PFNGLCREATEBUFFERSPROC) load(userptr, "glCreateBuffers"); - glad_glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC) load(userptr, "glCreateFramebuffers"); - glad_glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC) load(userptr, "glCreateProgramPipelines"); - glad_glCreateQueries = (PFNGLCREATEQUERIESPROC) load(userptr, "glCreateQueries"); - glad_glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC) load(userptr, "glCreateRenderbuffers"); - glad_glCreateSamplers = (PFNGLCREATESAMPLERSPROC) load(userptr, "glCreateSamplers"); - glad_glCreateTextures = (PFNGLCREATETEXTURESPROC) load(userptr, "glCreateTextures"); - glad_glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC) load(userptr, "glCreateTransformFeedbacks"); - glad_glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC) load(userptr, "glCreateVertexArrays"); - glad_glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC) load(userptr, "glDisableVertexArrayAttrib"); - glad_glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC) load(userptr, "glEnableVertexArrayAttrib"); - glad_glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) load(userptr, "glFlushMappedNamedBufferRange"); - glad_glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC) load(userptr, "glGenerateTextureMipmap"); - glad_glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) load(userptr, "glGetCompressedTextureImage"); - glad_glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) load(userptr, "glGetNamedBufferParameteri64v"); - glad_glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC) load(userptr, "glGetNamedBufferParameteriv"); - glad_glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC) load(userptr, "glGetNamedBufferPointerv"); - glad_glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC) load(userptr, "glGetNamedBufferSubData"); - glad_glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetNamedFramebufferAttachmentParameteriv"); - glad_glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) load(userptr, "glGetNamedFramebufferParameteriv"); - glad_glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetNamedRenderbufferParameteriv"); - glad_glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC) load(userptr, "glGetQueryBufferObjecti64v"); - glad_glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC) load(userptr, "glGetQueryBufferObjectiv"); - glad_glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC) load(userptr, "glGetQueryBufferObjectui64v"); - glad_glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC) load(userptr, "glGetQueryBufferObjectuiv"); - glad_glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC) load(userptr, "glGetTextureImage"); - glad_glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC) load(userptr, "glGetTextureLevelParameterfv"); - glad_glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC) load(userptr, "glGetTextureLevelParameteriv"); - glad_glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC) load(userptr, "glGetTextureParameterIiv"); - glad_glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC) load(userptr, "glGetTextureParameterIuiv"); - glad_glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC) load(userptr, "glGetTextureParameterfv"); - glad_glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC) load(userptr, "glGetTextureParameteriv"); - glad_glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC) load(userptr, "glGetTransformFeedbacki64_v"); - glad_glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC) load(userptr, "glGetTransformFeedbacki_v"); - glad_glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC) load(userptr, "glGetTransformFeedbackiv"); - glad_glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC) load(userptr, "glGetVertexArrayIndexed64iv"); - glad_glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC) load(userptr, "glGetVertexArrayIndexediv"); - glad_glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC) load(userptr, "glGetVertexArrayiv"); - glad_glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) load(userptr, "glInvalidateNamedFramebufferData"); - glad_glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) load(userptr, "glInvalidateNamedFramebufferSubData"); - glad_glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC) load(userptr, "glMapNamedBuffer"); - glad_glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC) load(userptr, "glMapNamedBufferRange"); - glad_glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC) load(userptr, "glNamedBufferData"); - glad_glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC) load(userptr, "glNamedBufferStorage"); - glad_glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC) load(userptr, "glNamedBufferSubData"); - glad_glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) load(userptr, "glNamedFramebufferDrawBuffer"); - glad_glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) load(userptr, "glNamedFramebufferDrawBuffers"); - glad_glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) load(userptr, "glNamedFramebufferParameteri"); - glad_glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) load(userptr, "glNamedFramebufferReadBuffer"); - glad_glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glNamedFramebufferRenderbuffer"); - glad_glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) load(userptr, "glNamedFramebufferTexture"); - glad_glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glNamedFramebufferTextureLayer"); - glad_glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC) load(userptr, "glNamedRenderbufferStorage"); - glad_glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glNamedRenderbufferStorageMultisample"); - glad_glTextureBuffer = (PFNGLTEXTUREBUFFERPROC) load(userptr, "glTextureBuffer"); - glad_glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC) load(userptr, "glTextureBufferRange"); - glad_glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC) load(userptr, "glTextureParameterIiv"); - glad_glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC) load(userptr, "glTextureParameterIuiv"); - glad_glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC) load(userptr, "glTextureParameterf"); - glad_glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC) load(userptr, "glTextureParameterfv"); - glad_glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC) load(userptr, "glTextureParameteri"); - glad_glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC) load(userptr, "glTextureParameteriv"); - glad_glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC) load(userptr, "glTextureStorage1D"); - glad_glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC) load(userptr, "glTextureStorage2D"); - glad_glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) load(userptr, "glTextureStorage2DMultisample"); - glad_glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC) load(userptr, "glTextureStorage3D"); - glad_glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) load(userptr, "glTextureStorage3DMultisample"); - glad_glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC) load(userptr, "glTextureSubImage1D"); - glad_glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC) load(userptr, "glTextureSubImage2D"); - glad_glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC) load(userptr, "glTextureSubImage3D"); - glad_glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) load(userptr, "glTransformFeedbackBufferBase"); - glad_glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) load(userptr, "glTransformFeedbackBufferRange"); - glad_glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC) load(userptr, "glUnmapNamedBuffer"); - glad_glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC) load(userptr, "glVertexArrayAttribBinding"); - glad_glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC) load(userptr, "glVertexArrayAttribFormat"); - glad_glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC) load(userptr, "glVertexArrayAttribIFormat"); - glad_glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC) load(userptr, "glVertexArrayAttribLFormat"); - glad_glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC) load(userptr, "glVertexArrayBindingDivisor"); - glad_glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC) load(userptr, "glVertexArrayElementBuffer"); - glad_glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC) load(userptr, "glVertexArrayVertexBuffer"); - glad_glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC) load(userptr, "glVertexArrayVertexBuffers"); -} -static void glad_gl_load_GL_ARB_draw_buffers( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_draw_buffers) return; - glad_glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) load(userptr, "glDrawBuffersARB"); -} -static void glad_gl_load_GL_ARB_draw_buffers_blend( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_draw_buffers_blend) return; - glad_glBlendEquationSeparateiARB = (PFNGLBLENDEQUATIONSEPARATEIARBPROC) load(userptr, "glBlendEquationSeparateiARB"); - glad_glBlendEquationiARB = (PFNGLBLENDEQUATIONIARBPROC) load(userptr, "glBlendEquationiARB"); - glad_glBlendFuncSeparateiARB = (PFNGLBLENDFUNCSEPARATEIARBPROC) load(userptr, "glBlendFuncSeparateiARB"); - glad_glBlendFunciARB = (PFNGLBLENDFUNCIARBPROC) load(userptr, "glBlendFunciARB"); -} -static void glad_gl_load_GL_ARB_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_draw_elements_base_vertex) return; - glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glDrawElementsBaseVertex"); - glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, "glDrawElementsInstancedBaseVertex"); - glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, "glDrawRangeElementsBaseVertex"); - glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glMultiDrawElementsBaseVertex"); -} -static void glad_gl_load_GL_ARB_draw_indirect( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_draw_indirect) return; - glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) load(userptr, "glDrawArraysIndirect"); - glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) load(userptr, "glDrawElementsIndirect"); -} -static void glad_gl_load_GL_ARB_draw_instanced( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_draw_instanced) return; - glad_glDrawArraysInstancedARB = (PFNGLDRAWARRAYSINSTANCEDARBPROC) load(userptr, "glDrawArraysInstancedARB"); - glad_glDrawElementsInstancedARB = (PFNGLDRAWELEMENTSINSTANCEDARBPROC) load(userptr, "glDrawElementsInstancedARB"); -} -static void glad_gl_load_GL_ARB_fragment_program( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_fragment_program) return; - glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) load(userptr, "glBindProgramARB"); - glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) load(userptr, "glDeleteProgramsARB"); - glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) load(userptr, "glGenProgramsARB"); - glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) load(userptr, "glGetProgramEnvParameterdvARB"); - glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) load(userptr, "glGetProgramEnvParameterfvARB"); - glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) load(userptr, "glGetProgramLocalParameterdvARB"); - glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) load(userptr, "glGetProgramLocalParameterfvARB"); - glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) load(userptr, "glGetProgramStringARB"); - glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) load(userptr, "glGetProgramivARB"); - glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC) load(userptr, "glIsProgramARB"); - glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) load(userptr, "glProgramEnvParameter4dARB"); - glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) load(userptr, "glProgramEnvParameter4dvARB"); - glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) load(userptr, "glProgramEnvParameter4fARB"); - glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) load(userptr, "glProgramEnvParameter4fvARB"); - glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) load(userptr, "glProgramLocalParameter4dARB"); - glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) load(userptr, "glProgramLocalParameter4dvARB"); - glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) load(userptr, "glProgramLocalParameter4fARB"); - glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) load(userptr, "glProgramLocalParameter4fvARB"); - glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) load(userptr, "glProgramStringARB"); -} -static void glad_gl_load_GL_ARB_framebuffer_no_attachments( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_framebuffer_no_attachments) return; - glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC) load(userptr, "glFramebufferParameteri"); - glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC) load(userptr, "glGetFramebufferParameteriv"); -} -static void glad_gl_load_GL_ARB_framebuffer_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_framebuffer_object) return; - glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); - glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); - glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer"); - glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); - glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); - glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); - glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); - glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D"); - glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); - glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D"); - glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer"); - glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); - glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); - glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); - glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); - glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); - glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); - glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); - glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); - glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample"); -} -static void glad_gl_load_GL_ARB_geometry_shader4( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_geometry_shader4) return; - glad_glFramebufferTextureARB = (PFNGLFRAMEBUFFERTEXTUREARBPROC) load(userptr, "glFramebufferTextureARB"); - glad_glFramebufferTextureFaceARB = (PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) load(userptr, "glFramebufferTextureFaceARB"); - glad_glFramebufferTextureLayerARB = (PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) load(userptr, "glFramebufferTextureLayerARB"); - glad_glProgramParameteriARB = (PFNGLPROGRAMPARAMETERIARBPROC) load(userptr, "glProgramParameteriARB"); -} -static void glad_gl_load_GL_ARB_get_program_binary( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_get_program_binary) return; - glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, "glGetProgramBinary"); - glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, "glProgramBinary"); - glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, "glProgramParameteri"); -} -static void glad_gl_load_GL_ARB_get_texture_sub_image( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_get_texture_sub_image) return; - glad_glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) load(userptr, "glGetCompressedTextureSubImage"); - glad_glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC) load(userptr, "glGetTextureSubImage"); -} -static void glad_gl_load_GL_ARB_gl_spirv( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_gl_spirv) return; - glad_glSpecializeShaderARB = (PFNGLSPECIALIZESHADERARBPROC) load(userptr, "glSpecializeShaderARB"); -} -static void glad_gl_load_GL_ARB_gpu_shader_fp64( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_gpu_shader_fp64) return; - glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC) load(userptr, "glGetUniformdv"); - glad_glUniform1d = (PFNGLUNIFORM1DPROC) load(userptr, "glUniform1d"); - glad_glUniform1dv = (PFNGLUNIFORM1DVPROC) load(userptr, "glUniform1dv"); - glad_glUniform2d = (PFNGLUNIFORM2DPROC) load(userptr, "glUniform2d"); - glad_glUniform2dv = (PFNGLUNIFORM2DVPROC) load(userptr, "glUniform2dv"); - glad_glUniform3d = (PFNGLUNIFORM3DPROC) load(userptr, "glUniform3d"); - glad_glUniform3dv = (PFNGLUNIFORM3DVPROC) load(userptr, "glUniform3dv"); - glad_glUniform4d = (PFNGLUNIFORM4DPROC) load(userptr, "glUniform4d"); - glad_glUniform4dv = (PFNGLUNIFORM4DVPROC) load(userptr, "glUniform4dv"); - glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC) load(userptr, "glUniformMatrix2dv"); - glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC) load(userptr, "glUniformMatrix2x3dv"); - glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC) load(userptr, "glUniformMatrix2x4dv"); - glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC) load(userptr, "glUniformMatrix3dv"); - glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC) load(userptr, "glUniformMatrix3x2dv"); - glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC) load(userptr, "glUniformMatrix3x4dv"); - glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC) load(userptr, "glUniformMatrix4dv"); - glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC) load(userptr, "glUniformMatrix4x2dv"); - glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC) load(userptr, "glUniformMatrix4x3dv"); -} -static void glad_gl_load_GL_ARB_gpu_shader_int64( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_gpu_shader_int64) return; - glad_glGetUniformi64vARB = (PFNGLGETUNIFORMI64VARBPROC) load(userptr, "glGetUniformi64vARB"); - glad_glGetUniformui64vARB = (PFNGLGETUNIFORMUI64VARBPROC) load(userptr, "glGetUniformui64vARB"); - glad_glGetnUniformi64vARB = (PFNGLGETNUNIFORMI64VARBPROC) load(userptr, "glGetnUniformi64vARB"); - glad_glGetnUniformui64vARB = (PFNGLGETNUNIFORMUI64VARBPROC) load(userptr, "glGetnUniformui64vARB"); - glad_glProgramUniform1i64ARB = (PFNGLPROGRAMUNIFORM1I64ARBPROC) load(userptr, "glProgramUniform1i64ARB"); - glad_glProgramUniform1i64vARB = (PFNGLPROGRAMUNIFORM1I64VARBPROC) load(userptr, "glProgramUniform1i64vARB"); - glad_glProgramUniform1ui64ARB = (PFNGLPROGRAMUNIFORM1UI64ARBPROC) load(userptr, "glProgramUniform1ui64ARB"); - glad_glProgramUniform1ui64vARB = (PFNGLPROGRAMUNIFORM1UI64VARBPROC) load(userptr, "glProgramUniform1ui64vARB"); - glad_glProgramUniform2i64ARB = (PFNGLPROGRAMUNIFORM2I64ARBPROC) load(userptr, "glProgramUniform2i64ARB"); - glad_glProgramUniform2i64vARB = (PFNGLPROGRAMUNIFORM2I64VARBPROC) load(userptr, "glProgramUniform2i64vARB"); - glad_glProgramUniform2ui64ARB = (PFNGLPROGRAMUNIFORM2UI64ARBPROC) load(userptr, "glProgramUniform2ui64ARB"); - glad_glProgramUniform2ui64vARB = (PFNGLPROGRAMUNIFORM2UI64VARBPROC) load(userptr, "glProgramUniform2ui64vARB"); - glad_glProgramUniform3i64ARB = (PFNGLPROGRAMUNIFORM3I64ARBPROC) load(userptr, "glProgramUniform3i64ARB"); - glad_glProgramUniform3i64vARB = (PFNGLPROGRAMUNIFORM3I64VARBPROC) load(userptr, "glProgramUniform3i64vARB"); - glad_glProgramUniform3ui64ARB = (PFNGLPROGRAMUNIFORM3UI64ARBPROC) load(userptr, "glProgramUniform3ui64ARB"); - glad_glProgramUniform3ui64vARB = (PFNGLPROGRAMUNIFORM3UI64VARBPROC) load(userptr, "glProgramUniform3ui64vARB"); - glad_glProgramUniform4i64ARB = (PFNGLPROGRAMUNIFORM4I64ARBPROC) load(userptr, "glProgramUniform4i64ARB"); - glad_glProgramUniform4i64vARB = (PFNGLPROGRAMUNIFORM4I64VARBPROC) load(userptr, "glProgramUniform4i64vARB"); - glad_glProgramUniform4ui64ARB = (PFNGLPROGRAMUNIFORM4UI64ARBPROC) load(userptr, "glProgramUniform4ui64ARB"); - glad_glProgramUniform4ui64vARB = (PFNGLPROGRAMUNIFORM4UI64VARBPROC) load(userptr, "glProgramUniform4ui64vARB"); - glad_glUniform1i64ARB = (PFNGLUNIFORM1I64ARBPROC) load(userptr, "glUniform1i64ARB"); - glad_glUniform1i64vARB = (PFNGLUNIFORM1I64VARBPROC) load(userptr, "glUniform1i64vARB"); - glad_glUniform1ui64ARB = (PFNGLUNIFORM1UI64ARBPROC) load(userptr, "glUniform1ui64ARB"); - glad_glUniform1ui64vARB = (PFNGLUNIFORM1UI64VARBPROC) load(userptr, "glUniform1ui64vARB"); - glad_glUniform2i64ARB = (PFNGLUNIFORM2I64ARBPROC) load(userptr, "glUniform2i64ARB"); - glad_glUniform2i64vARB = (PFNGLUNIFORM2I64VARBPROC) load(userptr, "glUniform2i64vARB"); - glad_glUniform2ui64ARB = (PFNGLUNIFORM2UI64ARBPROC) load(userptr, "glUniform2ui64ARB"); - glad_glUniform2ui64vARB = (PFNGLUNIFORM2UI64VARBPROC) load(userptr, "glUniform2ui64vARB"); - glad_glUniform3i64ARB = (PFNGLUNIFORM3I64ARBPROC) load(userptr, "glUniform3i64ARB"); - glad_glUniform3i64vARB = (PFNGLUNIFORM3I64VARBPROC) load(userptr, "glUniform3i64vARB"); - glad_glUniform3ui64ARB = (PFNGLUNIFORM3UI64ARBPROC) load(userptr, "glUniform3ui64ARB"); - glad_glUniform3ui64vARB = (PFNGLUNIFORM3UI64VARBPROC) load(userptr, "glUniform3ui64vARB"); - glad_glUniform4i64ARB = (PFNGLUNIFORM4I64ARBPROC) load(userptr, "glUniform4i64ARB"); - glad_glUniform4i64vARB = (PFNGLUNIFORM4I64VARBPROC) load(userptr, "glUniform4i64vARB"); - glad_glUniform4ui64ARB = (PFNGLUNIFORM4UI64ARBPROC) load(userptr, "glUniform4ui64ARB"); - glad_glUniform4ui64vARB = (PFNGLUNIFORM4UI64VARBPROC) load(userptr, "glUniform4ui64vARB"); -} -static void glad_gl_load_GL_ARB_instanced_arrays( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_instanced_arrays) return; - glad_glVertexAttribDivisorARB = (PFNGLVERTEXATTRIBDIVISORARBPROC) load(userptr, "glVertexAttribDivisorARB"); -} -static void glad_gl_load_GL_ARB_internalformat_query( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_internalformat_query) return; - glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC) load(userptr, "glGetInternalformativ"); -} -static void glad_gl_load_GL_ARB_internalformat_query2( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_internalformat_query2) return; - glad_glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC) load(userptr, "glGetInternalformati64v"); -} -static void glad_gl_load_GL_ARB_map_buffer_range( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_map_buffer_range) return; - glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange"); - glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange"); -} -static void glad_gl_load_GL_ARB_multi_bind( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_multi_bind) return; - glad_glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC) load(userptr, "glBindBuffersBase"); - glad_glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC) load(userptr, "glBindBuffersRange"); - glad_glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC) load(userptr, "glBindImageTextures"); - glad_glBindSamplers = (PFNGLBINDSAMPLERSPROC) load(userptr, "glBindSamplers"); - glad_glBindTextures = (PFNGLBINDTEXTURESPROC) load(userptr, "glBindTextures"); - glad_glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC) load(userptr, "glBindVertexBuffers"); -} -static void glad_gl_load_GL_ARB_multi_draw_indirect( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_multi_draw_indirect) return; - glad_glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC) load(userptr, "glMultiDrawArraysIndirect"); - glad_glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC) load(userptr, "glMultiDrawElementsIndirect"); -} -static void glad_gl_load_GL_ARB_multisample( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_multisample) return; - glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC) load(userptr, "glSampleCoverageARB"); -} -static void glad_gl_load_GL_ARB_multitexture( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_multitexture) return; - glad_glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) load(userptr, "glActiveTextureARB"); - glad_glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) load(userptr, "glClientActiveTextureARB"); - glad_glMultiTexCoord1dARB = (PFNGLMULTITEXCOORD1DARBPROC) load(userptr, "glMultiTexCoord1dARB"); - glad_glMultiTexCoord1dvARB = (PFNGLMULTITEXCOORD1DVARBPROC) load(userptr, "glMultiTexCoord1dvARB"); - glad_glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC) load(userptr, "glMultiTexCoord1fARB"); - glad_glMultiTexCoord1fvARB = (PFNGLMULTITEXCOORD1FVARBPROC) load(userptr, "glMultiTexCoord1fvARB"); - glad_glMultiTexCoord1iARB = (PFNGLMULTITEXCOORD1IARBPROC) load(userptr, "glMultiTexCoord1iARB"); - glad_glMultiTexCoord1ivARB = (PFNGLMULTITEXCOORD1IVARBPROC) load(userptr, "glMultiTexCoord1ivARB"); - glad_glMultiTexCoord1sARB = (PFNGLMULTITEXCOORD1SARBPROC) load(userptr, "glMultiTexCoord1sARB"); - glad_glMultiTexCoord1svARB = (PFNGLMULTITEXCOORD1SVARBPROC) load(userptr, "glMultiTexCoord1svARB"); - glad_glMultiTexCoord2dARB = (PFNGLMULTITEXCOORD2DARBPROC) load(userptr, "glMultiTexCoord2dARB"); - glad_glMultiTexCoord2dvARB = (PFNGLMULTITEXCOORD2DVARBPROC) load(userptr, "glMultiTexCoord2dvARB"); - glad_glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) load(userptr, "glMultiTexCoord2fARB"); - glad_glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC) load(userptr, "glMultiTexCoord2fvARB"); - glad_glMultiTexCoord2iARB = (PFNGLMULTITEXCOORD2IARBPROC) load(userptr, "glMultiTexCoord2iARB"); - glad_glMultiTexCoord2ivARB = (PFNGLMULTITEXCOORD2IVARBPROC) load(userptr, "glMultiTexCoord2ivARB"); - glad_glMultiTexCoord2sARB = (PFNGLMULTITEXCOORD2SARBPROC) load(userptr, "glMultiTexCoord2sARB"); - glad_glMultiTexCoord2svARB = (PFNGLMULTITEXCOORD2SVARBPROC) load(userptr, "glMultiTexCoord2svARB"); - glad_glMultiTexCoord3dARB = (PFNGLMULTITEXCOORD3DARBPROC) load(userptr, "glMultiTexCoord3dARB"); - glad_glMultiTexCoord3dvARB = (PFNGLMULTITEXCOORD3DVARBPROC) load(userptr, "glMultiTexCoord3dvARB"); - glad_glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC) load(userptr, "glMultiTexCoord3fARB"); - glad_glMultiTexCoord3fvARB = (PFNGLMULTITEXCOORD3FVARBPROC) load(userptr, "glMultiTexCoord3fvARB"); - glad_glMultiTexCoord3iARB = (PFNGLMULTITEXCOORD3IARBPROC) load(userptr, "glMultiTexCoord3iARB"); - glad_glMultiTexCoord3ivARB = (PFNGLMULTITEXCOORD3IVARBPROC) load(userptr, "glMultiTexCoord3ivARB"); - glad_glMultiTexCoord3sARB = (PFNGLMULTITEXCOORD3SARBPROC) load(userptr, "glMultiTexCoord3sARB"); - glad_glMultiTexCoord3svARB = (PFNGLMULTITEXCOORD3SVARBPROC) load(userptr, "glMultiTexCoord3svARB"); - glad_glMultiTexCoord4dARB = (PFNGLMULTITEXCOORD4DARBPROC) load(userptr, "glMultiTexCoord4dARB"); - glad_glMultiTexCoord4dvARB = (PFNGLMULTITEXCOORD4DVARBPROC) load(userptr, "glMultiTexCoord4dvARB"); - glad_glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) load(userptr, "glMultiTexCoord4fARB"); - glad_glMultiTexCoord4fvARB = (PFNGLMULTITEXCOORD4FVARBPROC) load(userptr, "glMultiTexCoord4fvARB"); - glad_glMultiTexCoord4iARB = (PFNGLMULTITEXCOORD4IARBPROC) load(userptr, "glMultiTexCoord4iARB"); - glad_glMultiTexCoord4ivARB = (PFNGLMULTITEXCOORD4IVARBPROC) load(userptr, "glMultiTexCoord4ivARB"); - glad_glMultiTexCoord4sARB = (PFNGLMULTITEXCOORD4SARBPROC) load(userptr, "glMultiTexCoord4sARB"); - glad_glMultiTexCoord4svARB = (PFNGLMULTITEXCOORD4SVARBPROC) load(userptr, "glMultiTexCoord4svARB"); -} -static void glad_gl_load_GL_ARB_occlusion_query( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_occlusion_query) return; - glad_glBeginQueryARB = (PFNGLBEGINQUERYARBPROC) load(userptr, "glBeginQueryARB"); - glad_glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) load(userptr, "glDeleteQueriesARB"); - glad_glEndQueryARB = (PFNGLENDQUERYARBPROC) load(userptr, "glEndQueryARB"); - glad_glGenQueriesARB = (PFNGLGENQUERIESARBPROC) load(userptr, "glGenQueriesARB"); - glad_glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) load(userptr, "glGetQueryObjectivARB"); - glad_glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) load(userptr, "glGetQueryObjectuivARB"); - glad_glGetQueryivARB = (PFNGLGETQUERYIVARBPROC) load(userptr, "glGetQueryivARB"); - glad_glIsQueryARB = (PFNGLISQUERYARBPROC) load(userptr, "glIsQueryARB"); -} -static void glad_gl_load_GL_ARB_sample_locations( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_sample_locations) return; - glad_glEvaluateDepthValuesARB = (PFNGLEVALUATEDEPTHVALUESARBPROC) load(userptr, "glEvaluateDepthValuesARB"); - glad_glFramebufferSampleLocationsfvARB = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) load(userptr, "glFramebufferSampleLocationsfvARB"); - glad_glNamedFramebufferSampleLocationsfvARB = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) load(userptr, "glNamedFramebufferSampleLocationsfvARB"); -} -static void glad_gl_load_GL_ARB_sample_shading( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_sample_shading) return; - glad_glMinSampleShadingARB = (PFNGLMINSAMPLESHADINGARBPROC) load(userptr, "glMinSampleShadingARB"); -} -static void glad_gl_load_GL_ARB_shader_atomic_counters( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_shader_atomic_counters) return; - glad_glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) load(userptr, "glGetActiveAtomicCounterBufferiv"); -} -static void glad_gl_load_GL_ARB_shader_image_load_store( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_shader_image_load_store) return; - glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC) load(userptr, "glBindImageTexture"); - glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC) load(userptr, "glMemoryBarrier"); -} -static void glad_gl_load_GL_ARB_shader_objects( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_shader_objects) return; - glad_glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) load(userptr, "glAttachObjectARB"); - glad_glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) load(userptr, "glCompileShaderARB"); - glad_glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) load(userptr, "glCreateProgramObjectARB"); - glad_glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) load(userptr, "glCreateShaderObjectARB"); - glad_glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) load(userptr, "glDeleteObjectARB"); - glad_glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) load(userptr, "glDetachObjectARB"); - glad_glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) load(userptr, "glGetActiveUniformARB"); - glad_glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) load(userptr, "glGetAttachedObjectsARB"); - glad_glGetHandleARB = (PFNGLGETHANDLEARBPROC) load(userptr, "glGetHandleARB"); - glad_glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) load(userptr, "glGetInfoLogARB"); - glad_glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) load(userptr, "glGetObjectParameterfvARB"); - glad_glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) load(userptr, "glGetObjectParameterivARB"); - glad_glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) load(userptr, "glGetShaderSourceARB"); - glad_glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) load(userptr, "glGetUniformLocationARB"); - glad_glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) load(userptr, "glGetUniformfvARB"); - glad_glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) load(userptr, "glGetUniformivARB"); - glad_glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) load(userptr, "glLinkProgramARB"); - glad_glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) load(userptr, "glShaderSourceARB"); - glad_glUniform1fARB = (PFNGLUNIFORM1FARBPROC) load(userptr, "glUniform1fARB"); - glad_glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) load(userptr, "glUniform1fvARB"); - glad_glUniform1iARB = (PFNGLUNIFORM1IARBPROC) load(userptr, "glUniform1iARB"); - glad_glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) load(userptr, "glUniform1ivARB"); - glad_glUniform2fARB = (PFNGLUNIFORM2FARBPROC) load(userptr, "glUniform2fARB"); - glad_glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) load(userptr, "glUniform2fvARB"); - glad_glUniform2iARB = (PFNGLUNIFORM2IARBPROC) load(userptr, "glUniform2iARB"); - glad_glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) load(userptr, "glUniform2ivARB"); - glad_glUniform3fARB = (PFNGLUNIFORM3FARBPROC) load(userptr, "glUniform3fARB"); - glad_glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) load(userptr, "glUniform3fvARB"); - glad_glUniform3iARB = (PFNGLUNIFORM3IARBPROC) load(userptr, "glUniform3iARB"); - glad_glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) load(userptr, "glUniform3ivARB"); - glad_glUniform4fARB = (PFNGLUNIFORM4FARBPROC) load(userptr, "glUniform4fARB"); - glad_glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) load(userptr, "glUniform4fvARB"); - glad_glUniform4iARB = (PFNGLUNIFORM4IARBPROC) load(userptr, "glUniform4iARB"); - glad_glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) load(userptr, "glUniform4ivARB"); - glad_glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) load(userptr, "glUniformMatrix2fvARB"); - glad_glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) load(userptr, "glUniformMatrix3fvARB"); - glad_glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) load(userptr, "glUniformMatrix4fvARB"); - glad_glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) load(userptr, "glUseProgramObjectARB"); - glad_glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) load(userptr, "glValidateProgramARB"); -} -static void glad_gl_load_GL_ARB_shader_storage_buffer_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_shader_storage_buffer_object) return; - glad_glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC) load(userptr, "glShaderStorageBlockBinding"); -} -static void glad_gl_load_GL_ARB_shading_language_include( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_shading_language_include) return; - glad_glCompileShaderIncludeARB = (PFNGLCOMPILESHADERINCLUDEARBPROC) load(userptr, "glCompileShaderIncludeARB"); - glad_glDeleteNamedStringARB = (PFNGLDELETENAMEDSTRINGARBPROC) load(userptr, "glDeleteNamedStringARB"); - glad_glGetNamedStringARB = (PFNGLGETNAMEDSTRINGARBPROC) load(userptr, "glGetNamedStringARB"); - glad_glGetNamedStringivARB = (PFNGLGETNAMEDSTRINGIVARBPROC) load(userptr, "glGetNamedStringivARB"); - glad_glIsNamedStringARB = (PFNGLISNAMEDSTRINGARBPROC) load(userptr, "glIsNamedStringARB"); - glad_glNamedStringARB = (PFNGLNAMEDSTRINGARBPROC) load(userptr, "glNamedStringARB"); -} -static void glad_gl_load_GL_ARB_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_tessellation_shader) return; - glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC) load(userptr, "glPatchParameterfv"); - glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) load(userptr, "glPatchParameteri"); -} -static void glad_gl_load_GL_ARB_texture_compression( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_texture_compression) return; - glad_glCompressedTexImage1DARB = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) load(userptr, "glCompressedTexImage1DARB"); - glad_glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) load(userptr, "glCompressedTexImage2DARB"); - glad_glCompressedTexImage3DARB = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) load(userptr, "glCompressedTexImage3DARB"); - glad_glCompressedTexSubImage1DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) load(userptr, "glCompressedTexSubImage1DARB"); - glad_glCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) load(userptr, "glCompressedTexSubImage2DARB"); - glad_glCompressedTexSubImage3DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) load(userptr, "glCompressedTexSubImage3DARB"); - glad_glGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) load(userptr, "glGetCompressedTexImageARB"); -} -static void glad_gl_load_GL_ARB_texture_multisample( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_texture_multisample) return; - glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv"); - glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski"); - glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, "glTexImage2DMultisample"); - glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, "glTexImage3DMultisample"); -} -static void glad_gl_load_GL_ARB_texture_storage( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_texture_storage) return; - glad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC) load(userptr, "glTexStorage1D"); - glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC) load(userptr, "glTexStorage2D"); - glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC) load(userptr, "glTexStorage3D"); -} -static void glad_gl_load_GL_ARB_texture_view( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_texture_view) return; - glad_glTextureView = (PFNGLTEXTUREVIEWPROC) load(userptr, "glTextureView"); -} -static void glad_gl_load_GL_ARB_timer_query( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_timer_query) return; - glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, "glGetQueryObjecti64v"); - glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, "glGetQueryObjectui64v"); - glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, "glQueryCounter"); -} -static void glad_gl_load_GL_ARB_transpose_matrix( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_transpose_matrix) return; - glad_glLoadTransposeMatrixdARB = (PFNGLLOADTRANSPOSEMATRIXDARBPROC) load(userptr, "glLoadTransposeMatrixdARB"); - glad_glLoadTransposeMatrixfARB = (PFNGLLOADTRANSPOSEMATRIXFARBPROC) load(userptr, "glLoadTransposeMatrixfARB"); - glad_glMultTransposeMatrixdARB = (PFNGLMULTTRANSPOSEMATRIXDARBPROC) load(userptr, "glMultTransposeMatrixdARB"); - glad_glMultTransposeMatrixfARB = (PFNGLMULTTRANSPOSEMATRIXFARBPROC) load(userptr, "glMultTransposeMatrixfARB"); -} -static void glad_gl_load_GL_ARB_uniform_buffer_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_uniform_buffer_object) return; - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange"); - glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName"); - glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv"); - glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load(userptr, "glGetActiveUniformName"); - glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v"); - glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex"); - glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices"); - glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding"); -} -static void glad_gl_load_GL_ARB_vertex_array_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_vertex_array_object) return; - glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray"); - glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays"); - glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays"); - glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray"); -} -static void glad_gl_load_GL_ARB_vertex_attrib_binding( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_vertex_attrib_binding) return; - glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC) load(userptr, "glBindVertexBuffer"); - glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC) load(userptr, "glVertexAttribBinding"); - glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC) load(userptr, "glVertexAttribFormat"); - glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC) load(userptr, "glVertexAttribIFormat"); - glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC) load(userptr, "glVertexAttribLFormat"); - glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC) load(userptr, "glVertexBindingDivisor"); -} -static void glad_gl_load_GL_ARB_vertex_buffer_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_vertex_buffer_object) return; - glad_glBindBufferARB = (PFNGLBINDBUFFERARBPROC) load(userptr, "glBindBufferARB"); - glad_glBufferDataARB = (PFNGLBUFFERDATAARBPROC) load(userptr, "glBufferDataARB"); - glad_glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) load(userptr, "glBufferSubDataARB"); - glad_glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) load(userptr, "glDeleteBuffersARB"); - glad_glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) load(userptr, "glGenBuffersARB"); - glad_glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) load(userptr, "glGetBufferParameterivARB"); - glad_glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) load(userptr, "glGetBufferPointervARB"); - glad_glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) load(userptr, "glGetBufferSubDataARB"); - glad_glIsBufferARB = (PFNGLISBUFFERARBPROC) load(userptr, "glIsBufferARB"); - glad_glMapBufferARB = (PFNGLMAPBUFFERARBPROC) load(userptr, "glMapBufferARB"); - glad_glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC) load(userptr, "glUnmapBufferARB"); -} -static void glad_gl_load_GL_ARB_vertex_program( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_vertex_program) return; - glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) load(userptr, "glBindProgramARB"); - glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) load(userptr, "glDeleteProgramsARB"); - glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glDisableVertexAttribArrayARB"); - glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glEnableVertexAttribArrayARB"); - glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) load(userptr, "glGenProgramsARB"); - glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) load(userptr, "glGetProgramEnvParameterdvARB"); - glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) load(userptr, "glGetProgramEnvParameterfvARB"); - glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) load(userptr, "glGetProgramLocalParameterdvARB"); - glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) load(userptr, "glGetProgramLocalParameterfvARB"); - glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) load(userptr, "glGetProgramStringARB"); - glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) load(userptr, "glGetProgramivARB"); - glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) load(userptr, "glGetVertexAttribPointervARB"); - glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) load(userptr, "glGetVertexAttribdvARB"); - glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) load(userptr, "glGetVertexAttribfvARB"); - glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) load(userptr, "glGetVertexAttribivARB"); - glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC) load(userptr, "glIsProgramARB"); - glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) load(userptr, "glProgramEnvParameter4dARB"); - glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) load(userptr, "glProgramEnvParameter4dvARB"); - glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) load(userptr, "glProgramEnvParameter4fARB"); - glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) load(userptr, "glProgramEnvParameter4fvARB"); - glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) load(userptr, "glProgramLocalParameter4dARB"); - glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) load(userptr, "glProgramLocalParameter4dvARB"); - glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) load(userptr, "glProgramLocalParameter4fARB"); - glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) load(userptr, "glProgramLocalParameter4fvARB"); - glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) load(userptr, "glProgramStringARB"); - glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) load(userptr, "glVertexAttrib1dARB"); - glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) load(userptr, "glVertexAttrib1dvARB"); - glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) load(userptr, "glVertexAttrib1fARB"); - glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) load(userptr, "glVertexAttrib1fvARB"); - glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) load(userptr, "glVertexAttrib1sARB"); - glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) load(userptr, "glVertexAttrib1svARB"); - glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) load(userptr, "glVertexAttrib2dARB"); - glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) load(userptr, "glVertexAttrib2dvARB"); - glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) load(userptr, "glVertexAttrib2fARB"); - glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) load(userptr, "glVertexAttrib2fvARB"); - glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) load(userptr, "glVertexAttrib2sARB"); - glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) load(userptr, "glVertexAttrib2svARB"); - glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) load(userptr, "glVertexAttrib3dARB"); - glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) load(userptr, "glVertexAttrib3dvARB"); - glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) load(userptr, "glVertexAttrib3fARB"); - glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) load(userptr, "glVertexAttrib3fvARB"); - glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) load(userptr, "glVertexAttrib3sARB"); - glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) load(userptr, "glVertexAttrib3svARB"); - glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) load(userptr, "glVertexAttrib4NbvARB"); - glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) load(userptr, "glVertexAttrib4NivARB"); - glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) load(userptr, "glVertexAttrib4NsvARB"); - glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) load(userptr, "glVertexAttrib4NubARB"); - glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) load(userptr, "glVertexAttrib4NubvARB"); - glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) load(userptr, "glVertexAttrib4NuivARB"); - glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) load(userptr, "glVertexAttrib4NusvARB"); - glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) load(userptr, "glVertexAttrib4bvARB"); - glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) load(userptr, "glVertexAttrib4dARB"); - glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) load(userptr, "glVertexAttrib4dvARB"); - glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) load(userptr, "glVertexAttrib4fARB"); - glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) load(userptr, "glVertexAttrib4fvARB"); - glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) load(userptr, "glVertexAttrib4ivARB"); - glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) load(userptr, "glVertexAttrib4sARB"); - glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) load(userptr, "glVertexAttrib4svARB"); - glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) load(userptr, "glVertexAttrib4ubvARB"); - glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) load(userptr, "glVertexAttrib4uivARB"); - glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) load(userptr, "glVertexAttrib4usvARB"); - glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) load(userptr, "glVertexAttribPointerARB"); -} -static void glad_gl_load_GL_ARB_vertex_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ARB_vertex_shader) return; - glad_glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) load(userptr, "glBindAttribLocationARB"); - glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glDisableVertexAttribArrayARB"); - glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glEnableVertexAttribArrayARB"); - glad_glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) load(userptr, "glGetActiveAttribARB"); - glad_glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) load(userptr, "glGetAttribLocationARB"); - glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) load(userptr, "glGetVertexAttribPointervARB"); - glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) load(userptr, "glGetVertexAttribdvARB"); - glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) load(userptr, "glGetVertexAttribfvARB"); - glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) load(userptr, "glGetVertexAttribivARB"); - glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) load(userptr, "glVertexAttrib1dARB"); - glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) load(userptr, "glVertexAttrib1dvARB"); - glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) load(userptr, "glVertexAttrib1fARB"); - glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) load(userptr, "glVertexAttrib1fvARB"); - glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) load(userptr, "glVertexAttrib1sARB"); - glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) load(userptr, "glVertexAttrib1svARB"); - glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) load(userptr, "glVertexAttrib2dARB"); - glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) load(userptr, "glVertexAttrib2dvARB"); - glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) load(userptr, "glVertexAttrib2fARB"); - glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) load(userptr, "glVertexAttrib2fvARB"); - glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) load(userptr, "glVertexAttrib2sARB"); - glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) load(userptr, "glVertexAttrib2svARB"); - glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) load(userptr, "glVertexAttrib3dARB"); - glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) load(userptr, "glVertexAttrib3dvARB"); - glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) load(userptr, "glVertexAttrib3fARB"); - glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) load(userptr, "glVertexAttrib3fvARB"); - glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) load(userptr, "glVertexAttrib3sARB"); - glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) load(userptr, "glVertexAttrib3svARB"); - glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) load(userptr, "glVertexAttrib4NbvARB"); - glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) load(userptr, "glVertexAttrib4NivARB"); - glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) load(userptr, "glVertexAttrib4NsvARB"); - glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) load(userptr, "glVertexAttrib4NubARB"); - glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) load(userptr, "glVertexAttrib4NubvARB"); - glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) load(userptr, "glVertexAttrib4NuivARB"); - glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) load(userptr, "glVertexAttrib4NusvARB"); - glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) load(userptr, "glVertexAttrib4bvARB"); - glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) load(userptr, "glVertexAttrib4dARB"); - glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) load(userptr, "glVertexAttrib4dvARB"); - glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) load(userptr, "glVertexAttrib4fARB"); - glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) load(userptr, "glVertexAttrib4fvARB"); - glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) load(userptr, "glVertexAttrib4ivARB"); - glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) load(userptr, "glVertexAttrib4sARB"); - glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) load(userptr, "glVertexAttrib4svARB"); - glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) load(userptr, "glVertexAttrib4ubvARB"); - glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) load(userptr, "glVertexAttrib4uivARB"); - glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) load(userptr, "glVertexAttrib4usvARB"); - glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) load(userptr, "glVertexAttribPointerARB"); -} -static void glad_gl_load_GL_EXT_draw_instanced( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_draw_instanced) return; - glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); - glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); -} -static void glad_gl_load_GL_EXT_fog_coord( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_fog_coord) return; - glad_glFogCoordPointerEXT = (PFNGLFOGCOORDPOINTEREXTPROC) load(userptr, "glFogCoordPointerEXT"); - glad_glFogCoorddEXT = (PFNGLFOGCOORDDEXTPROC) load(userptr, "glFogCoorddEXT"); - glad_glFogCoorddvEXT = (PFNGLFOGCOORDDVEXTPROC) load(userptr, "glFogCoorddvEXT"); - glad_glFogCoordfEXT = (PFNGLFOGCOORDFEXTPROC) load(userptr, "glFogCoordfEXT"); - glad_glFogCoordfvEXT = (PFNGLFOGCOORDFVEXTPROC) load(userptr, "glFogCoordfvEXT"); -} -static void glad_gl_load_GL_EXT_framebuffer_blit( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_framebuffer_blit) return; - glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) load(userptr, "glBlitFramebufferEXT"); -} -static void glad_gl_load_GL_EXT_framebuffer_multisample( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_framebuffer_multisample) return; - glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) load(userptr, "glRenderbufferStorageMultisampleEXT"); -} -static void glad_gl_load_GL_EXT_framebuffer_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_framebuffer_object) return; - glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) load(userptr, "glBindFramebufferEXT"); - glad_glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) load(userptr, "glBindRenderbufferEXT"); - glad_glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) load(userptr, "glCheckFramebufferStatusEXT"); - glad_glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) load(userptr, "glDeleteFramebuffersEXT"); - glad_glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) load(userptr, "glDeleteRenderbuffersEXT"); - glad_glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) load(userptr, "glFramebufferRenderbufferEXT"); - glad_glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) load(userptr, "glFramebufferTexture1DEXT"); - glad_glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) load(userptr, "glFramebufferTexture2DEXT"); - glad_glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) load(userptr, "glFramebufferTexture3DEXT"); - glad_glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) load(userptr, "glGenFramebuffersEXT"); - glad_glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) load(userptr, "glGenRenderbuffersEXT"); - glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) load(userptr, "glGenerateMipmapEXT"); - glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) load(userptr, "glGetFramebufferAttachmentParameterivEXT"); - glad_glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) load(userptr, "glGetRenderbufferParameterivEXT"); - glad_glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) load(userptr, "glIsFramebufferEXT"); - glad_glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) load(userptr, "glIsRenderbufferEXT"); - glad_glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) load(userptr, "glRenderbufferStorageEXT"); -} -static void glad_gl_load_GL_OES_fixed_point( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_fixed_point) return; - glad_glAccumxOES = (PFNGLACCUMXOESPROC) load(userptr, "glAccumxOES"); - glad_glAlphaFuncxOES = (PFNGLALPHAFUNCXOESPROC) load(userptr, "glAlphaFuncxOES"); - glad_glBitmapxOES = (PFNGLBITMAPXOESPROC) load(userptr, "glBitmapxOES"); - glad_glBlendColorxOES = (PFNGLBLENDCOLORXOESPROC) load(userptr, "glBlendColorxOES"); - glad_glClearAccumxOES = (PFNGLCLEARACCUMXOESPROC) load(userptr, "glClearAccumxOES"); - glad_glClearColorxOES = (PFNGLCLEARCOLORXOESPROC) load(userptr, "glClearColorxOES"); - glad_glClearDepthxOES = (PFNGLCLEARDEPTHXOESPROC) load(userptr, "glClearDepthxOES"); - glad_glClipPlanexOES = (PFNGLCLIPPLANEXOESPROC) load(userptr, "glClipPlanexOES"); - glad_glColor3xOES = (PFNGLCOLOR3XOESPROC) load(userptr, "glColor3xOES"); - glad_glColor3xvOES = (PFNGLCOLOR3XVOESPROC) load(userptr, "glColor3xvOES"); - glad_glColor4xOES = (PFNGLCOLOR4XOESPROC) load(userptr, "glColor4xOES"); - glad_glColor4xvOES = (PFNGLCOLOR4XVOESPROC) load(userptr, "glColor4xvOES"); - glad_glConvolutionParameterxOES = (PFNGLCONVOLUTIONPARAMETERXOESPROC) load(userptr, "glConvolutionParameterxOES"); - glad_glConvolutionParameterxvOES = (PFNGLCONVOLUTIONPARAMETERXVOESPROC) load(userptr, "glConvolutionParameterxvOES"); - glad_glDepthRangexOES = (PFNGLDEPTHRANGEXOESPROC) load(userptr, "glDepthRangexOES"); - glad_glEvalCoord1xOES = (PFNGLEVALCOORD1XOESPROC) load(userptr, "glEvalCoord1xOES"); - glad_glEvalCoord1xvOES = (PFNGLEVALCOORD1XVOESPROC) load(userptr, "glEvalCoord1xvOES"); - glad_glEvalCoord2xOES = (PFNGLEVALCOORD2XOESPROC) load(userptr, "glEvalCoord2xOES"); - glad_glEvalCoord2xvOES = (PFNGLEVALCOORD2XVOESPROC) load(userptr, "glEvalCoord2xvOES"); - glad_glFeedbackBufferxOES = (PFNGLFEEDBACKBUFFERXOESPROC) load(userptr, "glFeedbackBufferxOES"); - glad_glFogxOES = (PFNGLFOGXOESPROC) load(userptr, "glFogxOES"); - glad_glFogxvOES = (PFNGLFOGXVOESPROC) load(userptr, "glFogxvOES"); - glad_glFrustumxOES = (PFNGLFRUSTUMXOESPROC) load(userptr, "glFrustumxOES"); - glad_glGetClipPlanexOES = (PFNGLGETCLIPPLANEXOESPROC) load(userptr, "glGetClipPlanexOES"); - glad_glGetConvolutionParameterxvOES = (PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) load(userptr, "glGetConvolutionParameterxvOES"); - glad_glGetFixedvOES = (PFNGLGETFIXEDVOESPROC) load(userptr, "glGetFixedvOES"); - glad_glGetHistogramParameterxvOES = (PFNGLGETHISTOGRAMPARAMETERXVOESPROC) load(userptr, "glGetHistogramParameterxvOES"); - glad_glGetLightxOES = (PFNGLGETLIGHTXOESPROC) load(userptr, "glGetLightxOES"); - glad_glGetMapxvOES = (PFNGLGETMAPXVOESPROC) load(userptr, "glGetMapxvOES"); - glad_glGetMaterialxOES = (PFNGLGETMATERIALXOESPROC) load(userptr, "glGetMaterialxOES"); - glad_glGetPixelMapxv = (PFNGLGETPIXELMAPXVPROC) load(userptr, "glGetPixelMapxv"); - glad_glGetTexEnvxvOES = (PFNGLGETTEXENVXVOESPROC) load(userptr, "glGetTexEnvxvOES"); - glad_glGetTexGenxvOES = (PFNGLGETTEXGENXVOESPROC) load(userptr, "glGetTexGenxvOES"); - glad_glGetTexLevelParameterxvOES = (PFNGLGETTEXLEVELPARAMETERXVOESPROC) load(userptr, "glGetTexLevelParameterxvOES"); - glad_glGetTexParameterxvOES = (PFNGLGETTEXPARAMETERXVOESPROC) load(userptr, "glGetTexParameterxvOES"); - glad_glIndexxOES = (PFNGLINDEXXOESPROC) load(userptr, "glIndexxOES"); - glad_glIndexxvOES = (PFNGLINDEXXVOESPROC) load(userptr, "glIndexxvOES"); - glad_glLightModelxOES = (PFNGLLIGHTMODELXOESPROC) load(userptr, "glLightModelxOES"); - glad_glLightModelxvOES = (PFNGLLIGHTMODELXVOESPROC) load(userptr, "glLightModelxvOES"); - glad_glLightxOES = (PFNGLLIGHTXOESPROC) load(userptr, "glLightxOES"); - glad_glLightxvOES = (PFNGLLIGHTXVOESPROC) load(userptr, "glLightxvOES"); - glad_glLineWidthxOES = (PFNGLLINEWIDTHXOESPROC) load(userptr, "glLineWidthxOES"); - glad_glLoadMatrixxOES = (PFNGLLOADMATRIXXOESPROC) load(userptr, "glLoadMatrixxOES"); - glad_glLoadTransposeMatrixxOES = (PFNGLLOADTRANSPOSEMATRIXXOESPROC) load(userptr, "glLoadTransposeMatrixxOES"); - glad_glMap1xOES = (PFNGLMAP1XOESPROC) load(userptr, "glMap1xOES"); - glad_glMap2xOES = (PFNGLMAP2XOESPROC) load(userptr, "glMap2xOES"); - glad_glMapGrid1xOES = (PFNGLMAPGRID1XOESPROC) load(userptr, "glMapGrid1xOES"); - glad_glMapGrid2xOES = (PFNGLMAPGRID2XOESPROC) load(userptr, "glMapGrid2xOES"); - glad_glMaterialxOES = (PFNGLMATERIALXOESPROC) load(userptr, "glMaterialxOES"); - glad_glMaterialxvOES = (PFNGLMATERIALXVOESPROC) load(userptr, "glMaterialxvOES"); - glad_glMultMatrixxOES = (PFNGLMULTMATRIXXOESPROC) load(userptr, "glMultMatrixxOES"); - glad_glMultTransposeMatrixxOES = (PFNGLMULTTRANSPOSEMATRIXXOESPROC) load(userptr, "glMultTransposeMatrixxOES"); - glad_glMultiTexCoord1xOES = (PFNGLMULTITEXCOORD1XOESPROC) load(userptr, "glMultiTexCoord1xOES"); - glad_glMultiTexCoord1xvOES = (PFNGLMULTITEXCOORD1XVOESPROC) load(userptr, "glMultiTexCoord1xvOES"); - glad_glMultiTexCoord2xOES = (PFNGLMULTITEXCOORD2XOESPROC) load(userptr, "glMultiTexCoord2xOES"); - glad_glMultiTexCoord2xvOES = (PFNGLMULTITEXCOORD2XVOESPROC) load(userptr, "glMultiTexCoord2xvOES"); - glad_glMultiTexCoord3xOES = (PFNGLMULTITEXCOORD3XOESPROC) load(userptr, "glMultiTexCoord3xOES"); - glad_glMultiTexCoord3xvOES = (PFNGLMULTITEXCOORD3XVOESPROC) load(userptr, "glMultiTexCoord3xvOES"); - glad_glMultiTexCoord4xOES = (PFNGLMULTITEXCOORD4XOESPROC) load(userptr, "glMultiTexCoord4xOES"); - glad_glMultiTexCoord4xvOES = (PFNGLMULTITEXCOORD4XVOESPROC) load(userptr, "glMultiTexCoord4xvOES"); - glad_glNormal3xOES = (PFNGLNORMAL3XOESPROC) load(userptr, "glNormal3xOES"); - glad_glNormal3xvOES = (PFNGLNORMAL3XVOESPROC) load(userptr, "glNormal3xvOES"); - glad_glOrthoxOES = (PFNGLORTHOXOESPROC) load(userptr, "glOrthoxOES"); - glad_glPassThroughxOES = (PFNGLPASSTHROUGHXOESPROC) load(userptr, "glPassThroughxOES"); - glad_glPixelMapx = (PFNGLPIXELMAPXPROC) load(userptr, "glPixelMapx"); - glad_glPixelStorex = (PFNGLPIXELSTOREXPROC) load(userptr, "glPixelStorex"); - glad_glPixelTransferxOES = (PFNGLPIXELTRANSFERXOESPROC) load(userptr, "glPixelTransferxOES"); - glad_glPixelZoomxOES = (PFNGLPIXELZOOMXOESPROC) load(userptr, "glPixelZoomxOES"); - glad_glPointParameterxvOES = (PFNGLPOINTPARAMETERXVOESPROC) load(userptr, "glPointParameterxvOES"); - glad_glPointSizexOES = (PFNGLPOINTSIZEXOESPROC) load(userptr, "glPointSizexOES"); - glad_glPolygonOffsetxOES = (PFNGLPOLYGONOFFSETXOESPROC) load(userptr, "glPolygonOffsetxOES"); - glad_glPrioritizeTexturesxOES = (PFNGLPRIORITIZETEXTURESXOESPROC) load(userptr, "glPrioritizeTexturesxOES"); - glad_glRasterPos2xOES = (PFNGLRASTERPOS2XOESPROC) load(userptr, "glRasterPos2xOES"); - glad_glRasterPos2xvOES = (PFNGLRASTERPOS2XVOESPROC) load(userptr, "glRasterPos2xvOES"); - glad_glRasterPos3xOES = (PFNGLRASTERPOS3XOESPROC) load(userptr, "glRasterPos3xOES"); - glad_glRasterPos3xvOES = (PFNGLRASTERPOS3XVOESPROC) load(userptr, "glRasterPos3xvOES"); - glad_glRasterPos4xOES = (PFNGLRASTERPOS4XOESPROC) load(userptr, "glRasterPos4xOES"); - glad_glRasterPos4xvOES = (PFNGLRASTERPOS4XVOESPROC) load(userptr, "glRasterPos4xvOES"); - glad_glRectxOES = (PFNGLRECTXOESPROC) load(userptr, "glRectxOES"); - glad_glRectxvOES = (PFNGLRECTXVOESPROC) load(userptr, "glRectxvOES"); - glad_glRotatexOES = (PFNGLROTATEXOESPROC) load(userptr, "glRotatexOES"); - glad_glScalexOES = (PFNGLSCALEXOESPROC) load(userptr, "glScalexOES"); - glad_glTexCoord1xOES = (PFNGLTEXCOORD1XOESPROC) load(userptr, "glTexCoord1xOES"); - glad_glTexCoord1xvOES = (PFNGLTEXCOORD1XVOESPROC) load(userptr, "glTexCoord1xvOES"); - glad_glTexCoord2xOES = (PFNGLTEXCOORD2XOESPROC) load(userptr, "glTexCoord2xOES"); - glad_glTexCoord2xvOES = (PFNGLTEXCOORD2XVOESPROC) load(userptr, "glTexCoord2xvOES"); - glad_glTexCoord3xOES = (PFNGLTEXCOORD3XOESPROC) load(userptr, "glTexCoord3xOES"); - glad_glTexCoord3xvOES = (PFNGLTEXCOORD3XVOESPROC) load(userptr, "glTexCoord3xvOES"); - glad_glTexCoord4xOES = (PFNGLTEXCOORD4XOESPROC) load(userptr, "glTexCoord4xOES"); - glad_glTexCoord4xvOES = (PFNGLTEXCOORD4XVOESPROC) load(userptr, "glTexCoord4xvOES"); - glad_glTexEnvxOES = (PFNGLTEXENVXOESPROC) load(userptr, "glTexEnvxOES"); - glad_glTexEnvxvOES = (PFNGLTEXENVXVOESPROC) load(userptr, "glTexEnvxvOES"); - glad_glTexGenxOES = (PFNGLTEXGENXOESPROC) load(userptr, "glTexGenxOES"); - glad_glTexGenxvOES = (PFNGLTEXGENXVOESPROC) load(userptr, "glTexGenxvOES"); - glad_glTexParameterxOES = (PFNGLTEXPARAMETERXOESPROC) load(userptr, "glTexParameterxOES"); - glad_glTexParameterxvOES = (PFNGLTEXPARAMETERXVOESPROC) load(userptr, "glTexParameterxvOES"); - glad_glTranslatexOES = (PFNGLTRANSLATEXOESPROC) load(userptr, "glTranslatexOES"); - glad_glVertex2xOES = (PFNGLVERTEX2XOESPROC) load(userptr, "glVertex2xOES"); - glad_glVertex2xvOES = (PFNGLVERTEX2XVOESPROC) load(userptr, "glVertex2xvOES"); - glad_glVertex3xOES = (PFNGLVERTEX3XOESPROC) load(userptr, "glVertex3xOES"); - glad_glVertex3xvOES = (PFNGLVERTEX3XVOESPROC) load(userptr, "glVertex3xvOES"); - glad_glVertex4xOES = (PFNGLVERTEX4XOESPROC) load(userptr, "glVertex4xOES"); - glad_glVertex4xvOES = (PFNGLVERTEX4XVOESPROC) load(userptr, "glVertex4xvOES"); -} - - +struct gladGLversionStruct GLVersion; #if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) -#define GLAD_GL_IS_SOME_NEW_VERSION 1 -#else -#define GLAD_GL_IS_SOME_NEW_VERSION 0 +#define _GLAD_IS_SOME_NEW_VERSION 1 #endif -static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { -#if GLAD_GL_IS_SOME_NEW_VERSION - if(GLAD_VERSION_MAJOR(version) < 3) { -#else - (void) version; - (void) out_num_exts_i; - (void) out_exts_i; +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static const char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { #endif - if (glad_glGetString == NULL) { - return 0; - } - *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); -#if GLAD_GL_IS_SOME_NEW_VERSION + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION } else { - unsigned int index = 0; - unsigned int num_exts_i = 0; - char **exts_i = NULL; - if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { - return 0; - } - glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); + int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); if (num_exts_i > 0) { - exts_i = (char **) GLAD_MALLOC(num_exts_i * (sizeof *exts_i)); + exts_i = (const char **)GLAD_REALLOC((void *)exts_i, num_exts_i * sizeof *exts_i); } + if (exts_i == NULL) { return 0; } + for(index = 0; index < num_exts_i; index++) { - const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); - size_t len = strlen(gl_str_tmp) + 1; - - char *local_str = (char*) GLAD_MALLOC(len * sizeof(char)); - if(local_str != NULL) { - memcpy(local_str, gl_str_tmp, len * sizeof(char)); - } - - exts_i[index] = local_str; + exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, index); } - - *out_num_exts_i = num_exts_i; - *out_exts_i = exts_i; } #endif return 1; } -static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { + +static void free_exts(void) { if (exts_i != NULL) { - unsigned int index; - for(index = 0; index < num_exts_i; index++) { - GLAD_FREE((void *) (exts_i[index])); - } - GLAD_FREE((void *)exts_i); + GLAD_FREE((char **)exts_i); exts_i = NULL; } } -static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { - if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif const char *extensions; const char *loc; const char *terminator; @@ -8369,11 +3801,13 @@ static int glad_gl_has_extension(int version, const char *exts, unsigned int num if(extensions == NULL || ext == NULL) { return 0; } + while(1) { loc = strstr(extensions, ext); if(loc == NULL) { return 0; } + terminator = loc + strlen(ext); if((loc == extensions || *(loc - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { @@ -8381,164 +3815,1574 @@ static int glad_gl_has_extension(int version, const char *exts, unsigned int num } extensions = terminator; } +#ifdef _GLAD_IS_SOME_NEW_VERSION } else { - unsigned int index; + int index; + for(index = 0; index < num_exts_i; index++) { const char *e = exts_i[index]; + if(strcmp(e, ext) == 0) { return 1; } } } +#endif + return 0; } - -static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { - return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +int GLAD_GL_VERSION_1_0; +int GLAD_GL_VERSION_1_1; +int GLAD_GL_VERSION_1_2; +int GLAD_GL_VERSION_1_3; +int GLAD_GL_VERSION_1_4; +int GLAD_GL_VERSION_1_5; +int GLAD_GL_VERSION_2_0; +int GLAD_GL_VERSION_2_1; +int GLAD_GL_VERSION_3_0; +int GLAD_GL_VERSION_3_1; +int GLAD_GL_VERSION_3_2; +int GLAD_GL_VERSION_3_3; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +PFNGLBINDSAMPLERPROC glad_glBindSampler; +PFNGLLINEWIDTHPROC glad_glLineWidth; +PFNGLCOLORP3UIVPROC glad_glColorP3uiv; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +PFNGLCOMPILESHADERPROC glad_glCompileShader; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; +PFNGLVERTEXP4UIPROC glad_glVertexP4ui; +PFNGLENABLEIPROC glad_glEnablei; +PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; +PFNGLCREATESHADERPROC glad_glCreateShader; +PFNGLISBUFFERPROC glad_glIsBuffer; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +PFNGLHINTPROC glad_glHint; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +PFNGLVERTEXP2UIPROC glad_glVertexP2ui; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +PFNGLPOINTSIZEPROC glad_glPointSize; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +PFNGLWAITSYNCPROC glad_glWaitSync; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +PFNGLUNIFORM3IPROC glad_glUniform3i; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +PFNGLUNIFORM3FPROC glad_glUniform3f; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; +PFNGLCOLORMASKIPROC glad_glColorMaski; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; +PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; +PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +PFNGLDRAWARRAYSPROC glad_glDrawArrays; +PFNGLUNIFORM1UIPROC glad_glUniform1ui; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +PFNGLCLEARPROC glad_glClear; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +PFNGLISENABLEDPROC glad_glIsEnabled; +PFNGLSTENCILOPPROC glad_glStencilOp; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +PFNGLGETQUERYIVPROC glad_glGetQueryiv; +PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +PFNGLISSHADERPROC glad_glIsShader; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +PFNGLENABLEPROC glad_glEnable; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; +PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +PFNGLFLUSHPROC glad_glFlush; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +PFNGLFENCESYNCPROC glad_glFenceSync; +PFNGLCOLORP3UIPROC glad_glColorP3ui; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +PFNGLGENSAMPLERSPROC glad_glGenSamplers; +PFNGLCLAMPCOLORPROC glad_glClampColor; +PFNGLUNIFORM4IVPROC glad_glUniform4iv; +PFNGLCLEARSTENCILPROC glad_glClearStencil; +PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; +PFNGLGENTEXTURESPROC glad_glGenTextures; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +PFNGLISSYNCPROC glad_glIsSync; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +PFNGLUNIFORM2IPROC glad_glUniform2i; +PFNGLUNIFORM2FPROC glad_glUniform2f; +PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +PFNGLGENQUERIESPROC glad_glGenQueries; +PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +PFNGLISENABLEDIPROC glad_glIsEnabledi; +PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; +PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; +PFNGLUNIFORM2IVPROC glad_glUniform2iv; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +PFNGLGETSHADERIVPROC glad_glGetShaderiv; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +PFNGLGETDOUBLEVPROC glad_glGetDoublev; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; +PFNGLUNIFORM3FVPROC glad_glUniform3fv; +PFNGLDEPTHRANGEPROC glad_glDepthRange; +PFNGLMAPBUFFERPROC glad_glMapBuffer; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +PFNGLDELETESYNCPROC glad_glDeleteSync; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +PFNGLUNIFORM3IVPROC glad_glUniform3iv; +PFNGLPOLYGONMODEPROC glad_glPolygonMode; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +PFNGLUSEPROGRAMPROC glad_glUseProgram; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +PFNGLFINISHPROC glad_glFinish; +PFNGLDELETESHADERPROC glad_glDeleteShader; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +PFNGLVIEWPORTPROC glad_glViewport; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +PFNGLUNIFORM2UIPROC glad_glUniform2ui; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +PFNGLCLEARDEPTHPROC glad_glClearDepth; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +PFNGLTEXBUFFERPROC glad_glTexBuffer; +PFNGLPIXELSTOREIPROC glad_glPixelStorei; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +PFNGLPIXELSTOREFPROC glad_glPixelStoref; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; +PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; +PFNGLLINKPROGRAMPROC glad_glLinkProgram; +PFNGLBINDTEXTUREPROC glad_glBindTexture; +PFNGLGETSTRINGPROC glad_glGetString; +PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; +PFNGLDETACHSHADERPROC glad_glDetachShader; +PFNGLENDQUERYPROC glad_glEndQuery; +PFNGLNORMALP3UIPROC glad_glNormalP3ui; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; +PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; +PFNGLUNIFORM1FPROC glad_glUniform1f; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +PFNGLUNIFORM1IPROC glad_glUniform1i; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +PFNGLDISABLEPROC glad_glDisable; +PFNGLLOGICOPPROC glad_glLogicOp; +PFNGLUNIFORM4UIPROC glad_glUniform4ui; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +PFNGLCULLFACEPROC glad_glCullFace; +PFNGLGETSTRINGIPROC glad_glGetStringi; +PFNGLATTACHSHADERPROC glad_glAttachShader; +PFNGLQUERYCOUNTERPROC glad_glQueryCounter; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +PFNGLDRAWELEMENTSPROC glad_glDrawElements; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +PFNGLUNIFORM1IVPROC glad_glUniform1iv; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +PFNGLREADBUFFERPROC glad_glReadBuffer; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +PFNGLBLENDCOLORPROC glad_glBlendColor; +PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; +PFNGLISPROGRAMPROC glad_glIsProgram; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +PFNGLUNIFORM4IPROC glad_glUniform4i; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +PFNGLREADPIXELSPROC glad_glReadPixels; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +PFNGLUNIFORM4FPROC glad_glUniform4f; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +PFNGLSTENCILFUNCPROC glad_glStencilFunc; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +PFNGLCOLORP4UIPROC glad_glColorP4ui; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +PFNGLGENBUFFERSPROC glad_glGenBuffers; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +PFNGLBLENDFUNCPROC glad_glBlendFunc; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +PFNGLSCISSORPROC glad_glScissor; +PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +PFNGLCLEARCOLORPROC glad_glClearColor; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +PFNGLCOLORP4UIVPROC glad_glColorP4uiv; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +PFNGLUNIFORM3UIPROC glad_glUniform3ui; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +PFNGLUNIFORM2FVPROC glad_glUniform2fv; +PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +PFNGLDEPTHFUNCPROC glad_glDepthFunc; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +PFNGLCOLORMASKPROC glad_glColorMask; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +PFNGLUNIFORM4FVPROC glad_glUniform4fv; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +PFNGLISSAMPLERPROC glad_glIsSampler; +PFNGLVERTEXP3UIPROC glad_glVertexP3ui; +PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +PFNGLDISABLEIPROC glad_glDisablei; +PFNGLSHADERSOURCEPROC glad_glShaderSource; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +PFNGLGETSYNCIVPROC glad_glGetSynciv; +PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; +PFNGLBEGINQUERYPROC glad_glBeginQuery; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +PFNGLBINDBUFFERPROC glad_glBindBuffer; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +PFNGLBUFFERDATAPROC glad_glBufferData; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; +PFNGLGETERRORPROC glad_glGetError; +PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; +PFNGLGETFLOATVPROC glad_glGetFloatv; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; +PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; +PFNGLGETINTEGERVPROC glad_glGetIntegerv; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +PFNGLISQUERYPROC glad_glIsQuery; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +PFNGLSTENCILMASKPROC glad_glStencilMask; +PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; +PFNGLISTEXTUREPROC glad_glIsTexture; +PFNGLUNIFORM1FVPROC glad_glUniform1fv; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; +PFNGLDEPTHMASKPROC glad_glDepthMask; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +PFNGLFRONTFACEPROC glad_glFrontFace; +int GLAD_GL_ARB_texture_compression; +int GLAD_GL_ARB_texture_swizzle; +int GLAD_GL_ATI_fragment_shader; +int GLAD_GL_EXT_texture_sRGB; +int GLAD_GL_ARB_explicit_attrib_location; +int GLAD_GL_ARB_ES3_compatibility; +int GLAD_GL_EXT_blend_color; +int GLAD_GL_EXT_framebuffer_sRGB; +int GLAD_GL_EXT_index_array_formats; +int GLAD_GL_ARB_vertex_shader; +int GLAD_GL_ARB_vertex_attrib_binding; +int GLAD_GL_ARB_vertex_program; +int GLAD_GL_EXT_texture_compression_s3tc; +int GLAD_GL_EXT_debug_marker; +int GLAD_GL_EXT_texture_swizzle; +int GLAD_GL_ARB_texture_multisample; +int GLAD_GL_ARB_texture_rg; +int GLAD_GL_ARB_texture_float; +int GLAD_GL_ARB_compressed_texture_pixel_storage; +int GLAD_GL_ARB_framebuffer_sRGB; +int GLAD_GL_ARB_vertex_array_object; +int GLAD_GL_ARB_depth_clamp; +int GLAD_GL_ARB_fragment_shader; +int GLAD_GL_ATI_vertex_array_object; +int GLAD_GL_ARB_vertex_buffer_object; +int GLAD_GL_ARB_fragment_program; +int GLAD_GL_EXT_framebuffer_multisample; +int GLAD_GL_ARB_framebuffer_object; +int GLAD_GL_ARB_draw_buffers_blend; +int GLAD_GL_EXT_vertex_shader; +int GLAD_GL_EXT_blend_func_separate; +int GLAD_GL_ARB_texture_non_power_of_two; +int GLAD_GL_EXT_texture; +int GLAD_GL_ARB_buffer_storage; +int GLAD_GL_ARB_explicit_uniform_location; +int GLAD_GL_EXT_framebuffer_object; +int GLAD_GL_EXT_framebuffer_multisample_blit_scaled; +int GLAD_GL_AMD_debug_output; +int GLAD_GL_ARB_depth_buffer_float; +int GLAD_GL_ARB_multisample; +int GLAD_GL_ARB_compatibility; +int GLAD_GL_ARB_depth_texture; +int GLAD_GL_ARB_sample_locations; +int GLAD_GL_ARB_ES2_compatibility; +int GLAD_GL_AMD_query_buffer_object; +int GLAD_GL_EXT_framebuffer_blit; +int GLAD_GL_EXT_vertex_array; +int GLAD_GL_ARB_draw_buffers; +int GLAD_GL_EXT_blend_equation_separate; +int GLAD_GL_ATI_element_array; +int GLAD_GL_ARB_debug_output; +int GLAD_GL_ARB_uniform_buffer_object; +PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD; +PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD; +PFNGLDEBUGMESSAGECALLBACKAMDPROC glad_glDebugMessageCallbackAMD; +PFNGLGETDEBUGMESSAGELOGAMDPROC glad_glGetDebugMessageLogAMD; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +PFNGLSHADERBINARYPROC glad_glShaderBinary; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +PFNGLBUFFERSTORAGEPROC glad_glBufferStorage; +PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB; +PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB; +PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB; +PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB; +PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB; +PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB; +PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB; +PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB; +PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB; +PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB; +PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB; +PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB; +PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB; +PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB; +PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB; +PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB; +PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB; +PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB; +PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB; +PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB; +PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB; +PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB; +PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB; +PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB; +PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB; +PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB; +PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB; +PFNGLISPROGRAMARBPROC glad_glIsProgramARB; +PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB; +PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB; +PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB; +PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB; +PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB; +PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB; +PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB; +PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB; +PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB; +PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB; +PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer; +PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat; +PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat; +PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat; +PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding; +PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor; +PFNGLBINDBUFFERARBPROC glad_glBindBufferARB; +PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB; +PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB; +PFNGLISBUFFERARBPROC glad_glIsBufferARB; +PFNGLBUFFERDATAARBPROC glad_glBufferDataARB; +PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB; +PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB; +PFNGLMAPBUFFERARBPROC glad_glMapBufferARB; +PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB; +PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB; +PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB; +PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB; +PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB; +PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB; +PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB; +PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB; +PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB; +PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB; +PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB; +PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB; +PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB; +PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB; +PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB; +PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB; +PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB; +PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB; +PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB; +PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB; +PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB; +PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB; +PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB; +PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB; +PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB; +PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB; +PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB; +PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB; +PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB; +PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB; +PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB; +PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB; +PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB; +PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB; +PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB; +PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB; +PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB; +PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB; +PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB; +PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB; +PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB; +PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB; +PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB; +PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB; +PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB; +PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB; +PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB; +PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB; +PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB; +PFNGLELEMENTPOINTERATIPROC glad_glElementPointerATI; +PFNGLDRAWELEMENTARRAYATIPROC glad_glDrawElementArrayATI; +PFNGLDRAWRANGEELEMENTARRAYATIPROC glad_glDrawRangeElementArrayATI; +PFNGLGENFRAGMENTSHADERSATIPROC glad_glGenFragmentShadersATI; +PFNGLBINDFRAGMENTSHADERATIPROC glad_glBindFragmentShaderATI; +PFNGLDELETEFRAGMENTSHADERATIPROC glad_glDeleteFragmentShaderATI; +PFNGLBEGINFRAGMENTSHADERATIPROC glad_glBeginFragmentShaderATI; +PFNGLENDFRAGMENTSHADERATIPROC glad_glEndFragmentShaderATI; +PFNGLPASSTEXCOORDATIPROC glad_glPassTexCoordATI; +PFNGLSAMPLEMAPATIPROC glad_glSampleMapATI; +PFNGLCOLORFRAGMENTOP1ATIPROC glad_glColorFragmentOp1ATI; +PFNGLCOLORFRAGMENTOP2ATIPROC glad_glColorFragmentOp2ATI; +PFNGLCOLORFRAGMENTOP3ATIPROC glad_glColorFragmentOp3ATI; +PFNGLALPHAFRAGMENTOP1ATIPROC glad_glAlphaFragmentOp1ATI; +PFNGLALPHAFRAGMENTOP2ATIPROC glad_glAlphaFragmentOp2ATI; +PFNGLALPHAFRAGMENTOP3ATIPROC glad_glAlphaFragmentOp3ATI; +PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glad_glSetFragmentShaderConstantATI; +PFNGLNEWOBJECTBUFFERATIPROC glad_glNewObjectBufferATI; +PFNGLISOBJECTBUFFERATIPROC glad_glIsObjectBufferATI; +PFNGLUPDATEOBJECTBUFFERATIPROC glad_glUpdateObjectBufferATI; +PFNGLGETOBJECTBUFFERFVATIPROC glad_glGetObjectBufferfvATI; +PFNGLGETOBJECTBUFFERIVATIPROC glad_glGetObjectBufferivATI; +PFNGLFREEOBJECTBUFFERATIPROC glad_glFreeObjectBufferATI; +PFNGLARRAYOBJECTATIPROC glad_glArrayObjectATI; +PFNGLGETARRAYOBJECTFVATIPROC glad_glGetArrayObjectfvATI; +PFNGLGETARRAYOBJECTIVATIPROC glad_glGetArrayObjectivATI; +PFNGLVARIANTARRAYOBJECTATIPROC glad_glVariantArrayObjectATI; +PFNGLGETVARIANTARRAYOBJECTFVATIPROC glad_glGetVariantArrayObjectfvATI; +PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI; +PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT; +PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT; +PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT; +PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; +PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; +PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; +PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; +PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT; +PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT; +PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT; +PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT; +PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT; +PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT; +PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT; +PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT; +PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT; +PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; +PFNGLARRAYELEMENTEXTPROC glad_glArrayElementEXT; +PFNGLCOLORPOINTEREXTPROC glad_glColorPointerEXT; +PFNGLDRAWARRAYSEXTPROC glad_glDrawArraysEXT; +PFNGLEDGEFLAGPOINTEREXTPROC glad_glEdgeFlagPointerEXT; +PFNGLGETPOINTERVEXTPROC glad_glGetPointervEXT; +PFNGLINDEXPOINTEREXTPROC glad_glIndexPointerEXT; +PFNGLNORMALPOINTEREXTPROC glad_glNormalPointerEXT; +PFNGLTEXCOORDPOINTEREXTPROC glad_glTexCoordPointerEXT; +PFNGLVERTEXPOINTEREXTPROC glad_glVertexPointerEXT; +PFNGLBEGINVERTEXSHADEREXTPROC glad_glBeginVertexShaderEXT; +PFNGLENDVERTEXSHADEREXTPROC glad_glEndVertexShaderEXT; +PFNGLBINDVERTEXSHADEREXTPROC glad_glBindVertexShaderEXT; +PFNGLGENVERTEXSHADERSEXTPROC glad_glGenVertexShadersEXT; +PFNGLDELETEVERTEXSHADEREXTPROC glad_glDeleteVertexShaderEXT; +PFNGLSHADEROP1EXTPROC glad_glShaderOp1EXT; +PFNGLSHADEROP2EXTPROC glad_glShaderOp2EXT; +PFNGLSHADEROP3EXTPROC glad_glShaderOp3EXT; +PFNGLSWIZZLEEXTPROC glad_glSwizzleEXT; +PFNGLWRITEMASKEXTPROC glad_glWriteMaskEXT; +PFNGLINSERTCOMPONENTEXTPROC glad_glInsertComponentEXT; +PFNGLEXTRACTCOMPONENTEXTPROC glad_glExtractComponentEXT; +PFNGLGENSYMBOLSEXTPROC glad_glGenSymbolsEXT; +PFNGLSETINVARIANTEXTPROC glad_glSetInvariantEXT; +PFNGLSETLOCALCONSTANTEXTPROC glad_glSetLocalConstantEXT; +PFNGLVARIANTBVEXTPROC glad_glVariantbvEXT; +PFNGLVARIANTSVEXTPROC glad_glVariantsvEXT; +PFNGLVARIANTIVEXTPROC glad_glVariantivEXT; +PFNGLVARIANTFVEXTPROC glad_glVariantfvEXT; +PFNGLVARIANTDVEXTPROC glad_glVariantdvEXT; +PFNGLVARIANTUBVEXTPROC glad_glVariantubvEXT; +PFNGLVARIANTUSVEXTPROC glad_glVariantusvEXT; +PFNGLVARIANTUIVEXTPROC glad_glVariantuivEXT; +PFNGLVARIANTPOINTEREXTPROC glad_glVariantPointerEXT; +PFNGLENABLEVARIANTCLIENTSTATEEXTPROC glad_glEnableVariantClientStateEXT; +PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC glad_glDisableVariantClientStateEXT; +PFNGLBINDLIGHTPARAMETEREXTPROC glad_glBindLightParameterEXT; +PFNGLBINDMATERIALPARAMETEREXTPROC glad_glBindMaterialParameterEXT; +PFNGLBINDTEXGENPARAMETEREXTPROC glad_glBindTexGenParameterEXT; +PFNGLBINDTEXTUREUNITPARAMETEREXTPROC glad_glBindTextureUnitParameterEXT; +PFNGLBINDPARAMETEREXTPROC glad_glBindParameterEXT; +PFNGLISVARIANTENABLEDEXTPROC glad_glIsVariantEnabledEXT; +PFNGLGETVARIANTBOOLEANVEXTPROC glad_glGetVariantBooleanvEXT; +PFNGLGETVARIANTINTEGERVEXTPROC glad_glGetVariantIntegervEXT; +PFNGLGETVARIANTFLOATVEXTPROC glad_glGetVariantFloatvEXT; +PFNGLGETVARIANTPOINTERVEXTPROC glad_glGetVariantPointervEXT; +PFNGLGETINVARIANTBOOLEANVEXTPROC glad_glGetInvariantBooleanvEXT; +PFNGLGETINVARIANTINTEGERVEXTPROC glad_glGetInvariantIntegervEXT; +PFNGLGETINVARIANTFLOATVEXTPROC glad_glGetInvariantFloatvEXT; +PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC glad_glGetLocalConstantBooleanvEXT; +PFNGLGETLOCALCONSTANTINTEGERVEXTPROC glad_glGetLocalConstantIntegervEXT; +PFNGLGETLOCALCONSTANTFLOATVEXTPROC glad_glGetLocalConstantFloatvEXT; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_VERSION_3_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_1) return; + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); + glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); +} +static void load_GL_VERSION_3_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_2) return; + glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); + glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); + glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); + glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); + glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void load_GL_VERSION_3_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_3) return; + glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed"); + glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex"); + glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); + glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); + glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); + glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); + glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); + glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); + glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); + glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); + glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); + glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); + glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); + glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); + glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); + glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); + glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter"); + glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v"); + glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v"); + glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); + glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui"); + glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv"); + glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui"); + glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv"); + glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui"); + glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv"); + glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui"); + glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv"); + glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui"); + glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv"); + glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui"); + glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv"); + glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui"); + glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv"); + glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui"); + glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv"); + glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui"); + glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv"); + glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui"); + glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv"); + glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui"); + glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv"); + glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui"); + glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv"); + glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui"); + glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv"); + glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui"); + glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv"); + glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui"); + glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv"); + glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui"); + glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv"); + glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui"); + glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv"); + glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui"); + glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv"); + glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); + glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); +} +static void load_GL_AMD_debug_output(GLADloadproc load) { + if(!GLAD_GL_AMD_debug_output) return; + glad_glDebugMessageEnableAMD = (PFNGLDEBUGMESSAGEENABLEAMDPROC)load("glDebugMessageEnableAMD"); + glad_glDebugMessageInsertAMD = (PFNGLDEBUGMESSAGEINSERTAMDPROC)load("glDebugMessageInsertAMD"); + glad_glDebugMessageCallbackAMD = (PFNGLDEBUGMESSAGECALLBACKAMDPROC)load("glDebugMessageCallbackAMD"); + glad_glGetDebugMessageLogAMD = (PFNGLGETDEBUGMESSAGELOGAMDPROC)load("glGetDebugMessageLogAMD"); +} +static void load_GL_ARB_ES2_compatibility(GLADloadproc load) { + if(!GLAD_GL_ARB_ES2_compatibility) return; + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); +} +static void load_GL_ARB_buffer_storage(GLADloadproc load) { + if(!GLAD_GL_ARB_buffer_storage) return; + glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage"); +} +static void load_GL_ARB_debug_output(GLADloadproc load) { + if(!GLAD_GL_ARB_debug_output) return; + glad_glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC)load("glDebugMessageControlARB"); + glad_glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC)load("glDebugMessageInsertARB"); + glad_glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)load("glDebugMessageCallbackARB"); + glad_glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC)load("glGetDebugMessageLogARB"); +} +static void load_GL_ARB_draw_buffers(GLADloadproc load) { + if(!GLAD_GL_ARB_draw_buffers) return; + glad_glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC)load("glDrawBuffersARB"); +} +static void load_GL_ARB_draw_buffers_blend(GLADloadproc load) { + if(!GLAD_GL_ARB_draw_buffers_blend) return; + glad_glBlendEquationiARB = (PFNGLBLENDEQUATIONIARBPROC)load("glBlendEquationiARB"); + glad_glBlendEquationSeparateiARB = (PFNGLBLENDEQUATIONSEPARATEIARBPROC)load("glBlendEquationSeparateiARB"); + glad_glBlendFunciARB = (PFNGLBLENDFUNCIARBPROC)load("glBlendFunciARB"); + glad_glBlendFuncSeparateiARB = (PFNGLBLENDFUNCSEPARATEIARBPROC)load("glBlendFuncSeparateiARB"); +} +static void load_GL_ARB_fragment_program(GLADloadproc load) { + if(!GLAD_GL_ARB_fragment_program) return; + glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)load("glProgramStringARB"); + glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)load("glBindProgramARB"); + glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)load("glDeleteProgramsARB"); + glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)load("glGenProgramsARB"); + glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC)load("glProgramEnvParameter4dARB"); + glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)load("glProgramEnvParameter4dvARB"); + glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC)load("glProgramEnvParameter4fARB"); + glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)load("glProgramEnvParameter4fvARB"); + glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)load("glProgramLocalParameter4dARB"); + glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)load("glProgramLocalParameter4dvARB"); + glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)load("glProgramLocalParameter4fARB"); + glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)load("glProgramLocalParameter4fvARB"); + glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)load("glGetProgramEnvParameterdvARB"); + glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)load("glGetProgramEnvParameterfvARB"); + glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)load("glGetProgramLocalParameterdvARB"); + glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)load("glGetProgramLocalParameterfvARB"); + glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)load("glGetProgramivARB"); + glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)load("glGetProgramStringARB"); + glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC)load("glIsProgramARB"); +} +static void load_GL_ARB_framebuffer_object(GLADloadproc load) { + if(!GLAD_GL_ARB_framebuffer_object) return; + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); +} +static void load_GL_ARB_multisample(GLADloadproc load) { + if(!GLAD_GL_ARB_multisample) return; + glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC)load("glSampleCoverageARB"); +} +static void load_GL_ARB_sample_locations(GLADloadproc load) { + if(!GLAD_GL_ARB_sample_locations) return; + glad_glFramebufferSampleLocationsfvARB = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)load("glFramebufferSampleLocationsfvARB"); + glad_glNamedFramebufferSampleLocationsfvARB = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)load("glNamedFramebufferSampleLocationsfvARB"); + glad_glEvaluateDepthValuesARB = (PFNGLEVALUATEDEPTHVALUESARBPROC)load("glEvaluateDepthValuesARB"); +} +static void load_GL_ARB_texture_compression(GLADloadproc load) { + if(!GLAD_GL_ARB_texture_compression) return; + glad_glCompressedTexImage3DARB = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)load("glCompressedTexImage3DARB"); + glad_glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)load("glCompressedTexImage2DARB"); + glad_glCompressedTexImage1DARB = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)load("glCompressedTexImage1DARB"); + glad_glCompressedTexSubImage3DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)load("glCompressedTexSubImage3DARB"); + glad_glCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)load("glCompressedTexSubImage2DARB"); + glad_glCompressedTexSubImage1DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)load("glCompressedTexSubImage1DARB"); + glad_glGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)load("glGetCompressedTexImageARB"); +} +static void load_GL_ARB_texture_multisample(GLADloadproc load) { + if(!GLAD_GL_ARB_texture_multisample) return; + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void load_GL_ARB_uniform_buffer_object(GLADloadproc load) { + if(!GLAD_GL_ARB_uniform_buffer_object) return; + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); +} +static void load_GL_ARB_vertex_array_object(GLADloadproc load) { + if(!GLAD_GL_ARB_vertex_array_object) return; + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_ARB_vertex_attrib_binding(GLADloadproc load) { + if(!GLAD_GL_ARB_vertex_attrib_binding) return; + glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load("glBindVertexBuffer"); + glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load("glVertexAttribFormat"); + glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load("glVertexAttribIFormat"); + glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)load("glVertexAttribLFormat"); + glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load("glVertexAttribBinding"); + glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load("glVertexBindingDivisor"); +} +static void load_GL_ARB_vertex_buffer_object(GLADloadproc load) { + if(!GLAD_GL_ARB_vertex_buffer_object) return; + glad_glBindBufferARB = (PFNGLBINDBUFFERARBPROC)load("glBindBufferARB"); + glad_glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)load("glDeleteBuffersARB"); + glad_glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)load("glGenBuffersARB"); + glad_glIsBufferARB = (PFNGLISBUFFERARBPROC)load("glIsBufferARB"); + glad_glBufferDataARB = (PFNGLBUFFERDATAARBPROC)load("glBufferDataARB"); + glad_glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)load("glBufferSubDataARB"); + glad_glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)load("glGetBufferSubDataARB"); + glad_glMapBufferARB = (PFNGLMAPBUFFERARBPROC)load("glMapBufferARB"); + glad_glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)load("glUnmapBufferARB"); + glad_glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)load("glGetBufferParameterivARB"); + glad_glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)load("glGetBufferPointervARB"); +} +static void load_GL_ARB_vertex_program(GLADloadproc load) { + if(!GLAD_GL_ARB_vertex_program) return; + glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC)load("glVertexAttrib1dARB"); + glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC)load("glVertexAttrib1dvARB"); + glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)load("glVertexAttrib1fARB"); + glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC)load("glVertexAttrib1fvARB"); + glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC)load("glVertexAttrib1sARB"); + glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC)load("glVertexAttrib1svARB"); + glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC)load("glVertexAttrib2dARB"); + glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC)load("glVertexAttrib2dvARB"); + glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC)load("glVertexAttrib2fARB"); + glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC)load("glVertexAttrib2fvARB"); + glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC)load("glVertexAttrib2sARB"); + glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC)load("glVertexAttrib2svARB"); + glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC)load("glVertexAttrib3dARB"); + glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC)load("glVertexAttrib3dvARB"); + glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC)load("glVertexAttrib3fARB"); + glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC)load("glVertexAttrib3fvARB"); + glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC)load("glVertexAttrib3sARB"); + glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC)load("glVertexAttrib3svARB"); + glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC)load("glVertexAttrib4NbvARB"); + glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC)load("glVertexAttrib4NivARB"); + glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC)load("glVertexAttrib4NsvARB"); + glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC)load("glVertexAttrib4NubARB"); + glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC)load("glVertexAttrib4NubvARB"); + glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC)load("glVertexAttrib4NuivARB"); + glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC)load("glVertexAttrib4NusvARB"); + glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC)load("glVertexAttrib4bvARB"); + glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC)load("glVertexAttrib4dARB"); + glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC)load("glVertexAttrib4dvARB"); + glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC)load("glVertexAttrib4fARB"); + glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC)load("glVertexAttrib4fvARB"); + glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC)load("glVertexAttrib4ivARB"); + glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC)load("glVertexAttrib4sARB"); + glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC)load("glVertexAttrib4svARB"); + glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC)load("glVertexAttrib4ubvARB"); + glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC)load("glVertexAttrib4uivARB"); + glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC)load("glVertexAttrib4usvARB"); + glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)load("glVertexAttribPointerARB"); + glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)load("glEnableVertexAttribArrayARB"); + glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)load("glDisableVertexAttribArrayARB"); + glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)load("glProgramStringARB"); + glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)load("glBindProgramARB"); + glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)load("glDeleteProgramsARB"); + glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)load("glGenProgramsARB"); + glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC)load("glProgramEnvParameter4dARB"); + glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)load("glProgramEnvParameter4dvARB"); + glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC)load("glProgramEnvParameter4fARB"); + glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)load("glProgramEnvParameter4fvARB"); + glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)load("glProgramLocalParameter4dARB"); + glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)load("glProgramLocalParameter4dvARB"); + glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)load("glProgramLocalParameter4fARB"); + glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)load("glProgramLocalParameter4fvARB"); + glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)load("glGetProgramEnvParameterdvARB"); + glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)load("glGetProgramEnvParameterfvARB"); + glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)load("glGetProgramLocalParameterdvARB"); + glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)load("glGetProgramLocalParameterfvARB"); + glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)load("glGetProgramivARB"); + glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)load("glGetProgramStringARB"); + glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC)load("glGetVertexAttribdvARB"); + glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC)load("glGetVertexAttribfvARB"); + glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC)load("glGetVertexAttribivARB"); + glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)load("glGetVertexAttribPointervARB"); + glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC)load("glIsProgramARB"); +} +static void load_GL_ARB_vertex_shader(GLADloadproc load) { + if(!GLAD_GL_ARB_vertex_shader) return; + glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)load("glVertexAttrib1fARB"); + glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC)load("glVertexAttrib1sARB"); + glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC)load("glVertexAttrib1dARB"); + glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC)load("glVertexAttrib2fARB"); + glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC)load("glVertexAttrib2sARB"); + glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC)load("glVertexAttrib2dARB"); + glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC)load("glVertexAttrib3fARB"); + glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC)load("glVertexAttrib3sARB"); + glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC)load("glVertexAttrib3dARB"); + glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC)load("glVertexAttrib4fARB"); + glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC)load("glVertexAttrib4sARB"); + glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC)load("glVertexAttrib4dARB"); + glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC)load("glVertexAttrib4NubARB"); + glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC)load("glVertexAttrib1fvARB"); + glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC)load("glVertexAttrib1svARB"); + glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC)load("glVertexAttrib1dvARB"); + glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC)load("glVertexAttrib2fvARB"); + glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC)load("glVertexAttrib2svARB"); + glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC)load("glVertexAttrib2dvARB"); + glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC)load("glVertexAttrib3fvARB"); + glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC)load("glVertexAttrib3svARB"); + glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC)load("glVertexAttrib3dvARB"); + glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC)load("glVertexAttrib4fvARB"); + glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC)load("glVertexAttrib4svARB"); + glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC)load("glVertexAttrib4dvARB"); + glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC)load("glVertexAttrib4ivARB"); + glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC)load("glVertexAttrib4bvARB"); + glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC)load("glVertexAttrib4ubvARB"); + glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC)load("glVertexAttrib4usvARB"); + glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC)load("glVertexAttrib4uivARB"); + glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC)load("glVertexAttrib4NbvARB"); + glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC)load("glVertexAttrib4NsvARB"); + glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC)load("glVertexAttrib4NivARB"); + glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC)load("glVertexAttrib4NubvARB"); + glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC)load("glVertexAttrib4NusvARB"); + glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC)load("glVertexAttrib4NuivARB"); + glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)load("glVertexAttribPointerARB"); + glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)load("glEnableVertexAttribArrayARB"); + glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)load("glDisableVertexAttribArrayARB"); + glad_glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)load("glBindAttribLocationARB"); + glad_glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC)load("glGetActiveAttribARB"); + glad_glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)load("glGetAttribLocationARB"); + glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC)load("glGetVertexAttribdvARB"); + glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC)load("glGetVertexAttribfvARB"); + glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC)load("glGetVertexAttribivARB"); + glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)load("glGetVertexAttribPointervARB"); +} +static void load_GL_ATI_element_array(GLADloadproc load) { + if(!GLAD_GL_ATI_element_array) return; + glad_glElementPointerATI = (PFNGLELEMENTPOINTERATIPROC)load("glElementPointerATI"); + glad_glDrawElementArrayATI = (PFNGLDRAWELEMENTARRAYATIPROC)load("glDrawElementArrayATI"); + glad_glDrawRangeElementArrayATI = (PFNGLDRAWRANGEELEMENTARRAYATIPROC)load("glDrawRangeElementArrayATI"); +} +static void load_GL_ATI_fragment_shader(GLADloadproc load) { + if(!GLAD_GL_ATI_fragment_shader) return; + glad_glGenFragmentShadersATI = (PFNGLGENFRAGMENTSHADERSATIPROC)load("glGenFragmentShadersATI"); + glad_glBindFragmentShaderATI = (PFNGLBINDFRAGMENTSHADERATIPROC)load("glBindFragmentShaderATI"); + glad_glDeleteFragmentShaderATI = (PFNGLDELETEFRAGMENTSHADERATIPROC)load("glDeleteFragmentShaderATI"); + glad_glBeginFragmentShaderATI = (PFNGLBEGINFRAGMENTSHADERATIPROC)load("glBeginFragmentShaderATI"); + glad_glEndFragmentShaderATI = (PFNGLENDFRAGMENTSHADERATIPROC)load("glEndFragmentShaderATI"); + glad_glPassTexCoordATI = (PFNGLPASSTEXCOORDATIPROC)load("glPassTexCoordATI"); + glad_glSampleMapATI = (PFNGLSAMPLEMAPATIPROC)load("glSampleMapATI"); + glad_glColorFragmentOp1ATI = (PFNGLCOLORFRAGMENTOP1ATIPROC)load("glColorFragmentOp1ATI"); + glad_glColorFragmentOp2ATI = (PFNGLCOLORFRAGMENTOP2ATIPROC)load("glColorFragmentOp2ATI"); + glad_glColorFragmentOp3ATI = (PFNGLCOLORFRAGMENTOP3ATIPROC)load("glColorFragmentOp3ATI"); + glad_glAlphaFragmentOp1ATI = (PFNGLALPHAFRAGMENTOP1ATIPROC)load("glAlphaFragmentOp1ATI"); + glad_glAlphaFragmentOp2ATI = (PFNGLALPHAFRAGMENTOP2ATIPROC)load("glAlphaFragmentOp2ATI"); + glad_glAlphaFragmentOp3ATI = (PFNGLALPHAFRAGMENTOP3ATIPROC)load("glAlphaFragmentOp3ATI"); + glad_glSetFragmentShaderConstantATI = (PFNGLSETFRAGMENTSHADERCONSTANTATIPROC)load("glSetFragmentShaderConstantATI"); +} +static void load_GL_ATI_vertex_array_object(GLADloadproc load) { + if(!GLAD_GL_ATI_vertex_array_object) return; + glad_glNewObjectBufferATI = (PFNGLNEWOBJECTBUFFERATIPROC)load("glNewObjectBufferATI"); + glad_glIsObjectBufferATI = (PFNGLISOBJECTBUFFERATIPROC)load("glIsObjectBufferATI"); + glad_glUpdateObjectBufferATI = (PFNGLUPDATEOBJECTBUFFERATIPROC)load("glUpdateObjectBufferATI"); + glad_glGetObjectBufferfvATI = (PFNGLGETOBJECTBUFFERFVATIPROC)load("glGetObjectBufferfvATI"); + glad_glGetObjectBufferivATI = (PFNGLGETOBJECTBUFFERIVATIPROC)load("glGetObjectBufferivATI"); + glad_glFreeObjectBufferATI = (PFNGLFREEOBJECTBUFFERATIPROC)load("glFreeObjectBufferATI"); + glad_glArrayObjectATI = (PFNGLARRAYOBJECTATIPROC)load("glArrayObjectATI"); + glad_glGetArrayObjectfvATI = (PFNGLGETARRAYOBJECTFVATIPROC)load("glGetArrayObjectfvATI"); + glad_glGetArrayObjectivATI = (PFNGLGETARRAYOBJECTIVATIPROC)load("glGetArrayObjectivATI"); + glad_glVariantArrayObjectATI = (PFNGLVARIANTARRAYOBJECTATIPROC)load("glVariantArrayObjectATI"); + glad_glGetVariantArrayObjectfvATI = (PFNGLGETVARIANTARRAYOBJECTFVATIPROC)load("glGetVariantArrayObjectfvATI"); + glad_glGetVariantArrayObjectivATI = (PFNGLGETVARIANTARRAYOBJECTIVATIPROC)load("glGetVariantArrayObjectivATI"); +} +static void load_GL_EXT_blend_color(GLADloadproc load) { + if(!GLAD_GL_EXT_blend_color) return; + glad_glBlendColorEXT = (PFNGLBLENDCOLOREXTPROC)load("glBlendColorEXT"); +} +static void load_GL_EXT_blend_equation_separate(GLADloadproc load) { + if(!GLAD_GL_EXT_blend_equation_separate) return; + glad_glBlendEquationSeparateEXT = (PFNGLBLENDEQUATIONSEPARATEEXTPROC)load("glBlendEquationSeparateEXT"); +} +static void load_GL_EXT_blend_func_separate(GLADloadproc load) { + if(!GLAD_GL_EXT_blend_func_separate) return; + glad_glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)load("glBlendFuncSeparateEXT"); +} +static void load_GL_EXT_debug_marker(GLADloadproc load) { + if(!GLAD_GL_EXT_debug_marker) return; + glad_glInsertEventMarkerEXT = (PFNGLINSERTEVENTMARKEREXTPROC)load("glInsertEventMarkerEXT"); + glad_glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC)load("glPushGroupMarkerEXT"); + glad_glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC)load("glPopGroupMarkerEXT"); +} +static void load_GL_EXT_framebuffer_blit(GLADloadproc load) { + if(!GLAD_GL_EXT_framebuffer_blit) return; + glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)load("glBlitFramebufferEXT"); +} +static void load_GL_EXT_framebuffer_multisample(GLADloadproc load) { + if(!GLAD_GL_EXT_framebuffer_multisample) return; + glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)load("glRenderbufferStorageMultisampleEXT"); +} +static void load_GL_EXT_framebuffer_object(GLADloadproc load) { + if(!GLAD_GL_EXT_framebuffer_object) return; + glad_glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)load("glIsRenderbufferEXT"); + glad_glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)load("glBindRenderbufferEXT"); + glad_glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)load("glDeleteRenderbuffersEXT"); + glad_glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)load("glGenRenderbuffersEXT"); + glad_glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)load("glRenderbufferStorageEXT"); + glad_glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)load("glGetRenderbufferParameterivEXT"); + glad_glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)load("glIsFramebufferEXT"); + glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)load("glBindFramebufferEXT"); + glad_glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)load("glDeleteFramebuffersEXT"); + glad_glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)load("glGenFramebuffersEXT"); + glad_glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)load("glCheckFramebufferStatusEXT"); + glad_glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)load("glFramebufferTexture1DEXT"); + glad_glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)load("glFramebufferTexture2DEXT"); + glad_glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)load("glFramebufferTexture3DEXT"); + glad_glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)load("glFramebufferRenderbufferEXT"); + glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT"); + glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT"); +} +static void load_GL_EXT_vertex_array(GLADloadproc load) { + if(!GLAD_GL_EXT_vertex_array) return; + glad_glArrayElementEXT = (PFNGLARRAYELEMENTEXTPROC)load("glArrayElementEXT"); + glad_glColorPointerEXT = (PFNGLCOLORPOINTEREXTPROC)load("glColorPointerEXT"); + glad_glDrawArraysEXT = (PFNGLDRAWARRAYSEXTPROC)load("glDrawArraysEXT"); + glad_glEdgeFlagPointerEXT = (PFNGLEDGEFLAGPOINTEREXTPROC)load("glEdgeFlagPointerEXT"); + glad_glGetPointervEXT = (PFNGLGETPOINTERVEXTPROC)load("glGetPointervEXT"); + glad_glIndexPointerEXT = (PFNGLINDEXPOINTEREXTPROC)load("glIndexPointerEXT"); + glad_glNormalPointerEXT = (PFNGLNORMALPOINTEREXTPROC)load("glNormalPointerEXT"); + glad_glTexCoordPointerEXT = (PFNGLTEXCOORDPOINTEREXTPROC)load("glTexCoordPointerEXT"); + glad_glVertexPointerEXT = (PFNGLVERTEXPOINTEREXTPROC)load("glVertexPointerEXT"); +} +static void load_GL_EXT_vertex_shader(GLADloadproc load) { + if(!GLAD_GL_EXT_vertex_shader) return; + glad_glBeginVertexShaderEXT = (PFNGLBEGINVERTEXSHADEREXTPROC)load("glBeginVertexShaderEXT"); + glad_glEndVertexShaderEXT = (PFNGLENDVERTEXSHADEREXTPROC)load("glEndVertexShaderEXT"); + glad_glBindVertexShaderEXT = (PFNGLBINDVERTEXSHADEREXTPROC)load("glBindVertexShaderEXT"); + glad_glGenVertexShadersEXT = (PFNGLGENVERTEXSHADERSEXTPROC)load("glGenVertexShadersEXT"); + glad_glDeleteVertexShaderEXT = (PFNGLDELETEVERTEXSHADEREXTPROC)load("glDeleteVertexShaderEXT"); + glad_glShaderOp1EXT = (PFNGLSHADEROP1EXTPROC)load("glShaderOp1EXT"); + glad_glShaderOp2EXT = (PFNGLSHADEROP2EXTPROC)load("glShaderOp2EXT"); + glad_glShaderOp3EXT = (PFNGLSHADEROP3EXTPROC)load("glShaderOp3EXT"); + glad_glSwizzleEXT = (PFNGLSWIZZLEEXTPROC)load("glSwizzleEXT"); + glad_glWriteMaskEXT = (PFNGLWRITEMASKEXTPROC)load("glWriteMaskEXT"); + glad_glInsertComponentEXT = (PFNGLINSERTCOMPONENTEXTPROC)load("glInsertComponentEXT"); + glad_glExtractComponentEXT = (PFNGLEXTRACTCOMPONENTEXTPROC)load("glExtractComponentEXT"); + glad_glGenSymbolsEXT = (PFNGLGENSYMBOLSEXTPROC)load("glGenSymbolsEXT"); + glad_glSetInvariantEXT = (PFNGLSETINVARIANTEXTPROC)load("glSetInvariantEXT"); + glad_glSetLocalConstantEXT = (PFNGLSETLOCALCONSTANTEXTPROC)load("glSetLocalConstantEXT"); + glad_glVariantbvEXT = (PFNGLVARIANTBVEXTPROC)load("glVariantbvEXT"); + glad_glVariantsvEXT = (PFNGLVARIANTSVEXTPROC)load("glVariantsvEXT"); + glad_glVariantivEXT = (PFNGLVARIANTIVEXTPROC)load("glVariantivEXT"); + glad_glVariantfvEXT = (PFNGLVARIANTFVEXTPROC)load("glVariantfvEXT"); + glad_glVariantdvEXT = (PFNGLVARIANTDVEXTPROC)load("glVariantdvEXT"); + glad_glVariantubvEXT = (PFNGLVARIANTUBVEXTPROC)load("glVariantubvEXT"); + glad_glVariantusvEXT = (PFNGLVARIANTUSVEXTPROC)load("glVariantusvEXT"); + glad_glVariantuivEXT = (PFNGLVARIANTUIVEXTPROC)load("glVariantuivEXT"); + glad_glVariantPointerEXT = (PFNGLVARIANTPOINTEREXTPROC)load("glVariantPointerEXT"); + glad_glEnableVariantClientStateEXT = (PFNGLENABLEVARIANTCLIENTSTATEEXTPROC)load("glEnableVariantClientStateEXT"); + glad_glDisableVariantClientStateEXT = (PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC)load("glDisableVariantClientStateEXT"); + glad_glBindLightParameterEXT = (PFNGLBINDLIGHTPARAMETEREXTPROC)load("glBindLightParameterEXT"); + glad_glBindMaterialParameterEXT = (PFNGLBINDMATERIALPARAMETEREXTPROC)load("glBindMaterialParameterEXT"); + glad_glBindTexGenParameterEXT = (PFNGLBINDTEXGENPARAMETEREXTPROC)load("glBindTexGenParameterEXT"); + glad_glBindTextureUnitParameterEXT = (PFNGLBINDTEXTUREUNITPARAMETEREXTPROC)load("glBindTextureUnitParameterEXT"); + glad_glBindParameterEXT = (PFNGLBINDPARAMETEREXTPROC)load("glBindParameterEXT"); + glad_glIsVariantEnabledEXT = (PFNGLISVARIANTENABLEDEXTPROC)load("glIsVariantEnabledEXT"); + glad_glGetVariantBooleanvEXT = (PFNGLGETVARIANTBOOLEANVEXTPROC)load("glGetVariantBooleanvEXT"); + glad_glGetVariantIntegervEXT = (PFNGLGETVARIANTINTEGERVEXTPROC)load("glGetVariantIntegervEXT"); + glad_glGetVariantFloatvEXT = (PFNGLGETVARIANTFLOATVEXTPROC)load("glGetVariantFloatvEXT"); + glad_glGetVariantPointervEXT = (PFNGLGETVARIANTPOINTERVEXTPROC)load("glGetVariantPointervEXT"); + glad_glGetInvariantBooleanvEXT = (PFNGLGETINVARIANTBOOLEANVEXTPROC)load("glGetInvariantBooleanvEXT"); + glad_glGetInvariantIntegervEXT = (PFNGLGETINVARIANTINTEGERVEXTPROC)load("glGetInvariantIntegervEXT"); + glad_glGetInvariantFloatvEXT = (PFNGLGETINVARIANTFLOATVEXTPROC)load("glGetInvariantFloatvEXT"); + glad_glGetLocalConstantBooleanvEXT = (PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC)load("glGetLocalConstantBooleanvEXT"); + glad_glGetLocalConstantIntegervEXT = (PFNGLGETLOCALCONSTANTINTEGERVEXTPROC)load("glGetLocalConstantIntegervEXT"); + glad_glGetLocalConstantFloatvEXT = (PFNGLGETLOCALCONSTANTFLOATVEXTPROC)load("glGetLocalConstantFloatvEXT"); +} +static int find_extensionsGL(void) { + if (!get_exts()) return 0; + GLAD_GL_AMD_debug_output = has_ext("GL_AMD_debug_output"); + GLAD_GL_AMD_query_buffer_object = has_ext("GL_AMD_query_buffer_object"); + GLAD_GL_ARB_ES2_compatibility = has_ext("GL_ARB_ES2_compatibility"); + GLAD_GL_ARB_ES3_compatibility = has_ext("GL_ARB_ES3_compatibility"); + GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage"); + GLAD_GL_ARB_compatibility = has_ext("GL_ARB_compatibility"); + GLAD_GL_ARB_compressed_texture_pixel_storage = has_ext("GL_ARB_compressed_texture_pixel_storage"); + GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output"); + GLAD_GL_ARB_depth_buffer_float = has_ext("GL_ARB_depth_buffer_float"); + GLAD_GL_ARB_depth_clamp = has_ext("GL_ARB_depth_clamp"); + GLAD_GL_ARB_depth_texture = has_ext("GL_ARB_depth_texture"); + GLAD_GL_ARB_draw_buffers = has_ext("GL_ARB_draw_buffers"); + GLAD_GL_ARB_draw_buffers_blend = has_ext("GL_ARB_draw_buffers_blend"); + GLAD_GL_ARB_explicit_attrib_location = has_ext("GL_ARB_explicit_attrib_location"); + GLAD_GL_ARB_explicit_uniform_location = has_ext("GL_ARB_explicit_uniform_location"); + GLAD_GL_ARB_fragment_program = has_ext("GL_ARB_fragment_program"); + GLAD_GL_ARB_fragment_shader = has_ext("GL_ARB_fragment_shader"); + GLAD_GL_ARB_framebuffer_object = has_ext("GL_ARB_framebuffer_object"); + GLAD_GL_ARB_framebuffer_sRGB = has_ext("GL_ARB_framebuffer_sRGB"); + GLAD_GL_ARB_multisample = has_ext("GL_ARB_multisample"); + GLAD_GL_ARB_sample_locations = has_ext("GL_ARB_sample_locations"); + GLAD_GL_ARB_texture_compression = has_ext("GL_ARB_texture_compression"); + GLAD_GL_ARB_texture_float = has_ext("GL_ARB_texture_float"); + GLAD_GL_ARB_texture_multisample = has_ext("GL_ARB_texture_multisample"); + GLAD_GL_ARB_texture_non_power_of_two = has_ext("GL_ARB_texture_non_power_of_two"); + GLAD_GL_ARB_texture_rg = has_ext("GL_ARB_texture_rg"); + GLAD_GL_ARB_texture_swizzle = has_ext("GL_ARB_texture_swizzle"); + GLAD_GL_ARB_uniform_buffer_object = has_ext("GL_ARB_uniform_buffer_object"); + GLAD_GL_ARB_vertex_array_object = has_ext("GL_ARB_vertex_array_object"); + GLAD_GL_ARB_vertex_attrib_binding = has_ext("GL_ARB_vertex_attrib_binding"); + GLAD_GL_ARB_vertex_buffer_object = has_ext("GL_ARB_vertex_buffer_object"); + GLAD_GL_ARB_vertex_program = has_ext("GL_ARB_vertex_program"); + GLAD_GL_ARB_vertex_shader = has_ext("GL_ARB_vertex_shader"); + GLAD_GL_ATI_element_array = has_ext("GL_ATI_element_array"); + GLAD_GL_ATI_fragment_shader = has_ext("GL_ATI_fragment_shader"); + GLAD_GL_ATI_vertex_array_object = has_ext("GL_ATI_vertex_array_object"); + GLAD_GL_EXT_blend_color = has_ext("GL_EXT_blend_color"); + GLAD_GL_EXT_blend_equation_separate = has_ext("GL_EXT_blend_equation_separate"); + GLAD_GL_EXT_blend_func_separate = has_ext("GL_EXT_blend_func_separate"); + GLAD_GL_EXT_debug_marker = has_ext("GL_EXT_debug_marker"); + GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit"); + GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample"); + GLAD_GL_EXT_framebuffer_multisample_blit_scaled = has_ext("GL_EXT_framebuffer_multisample_blit_scaled"); + GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object"); + GLAD_GL_EXT_framebuffer_sRGB = has_ext("GL_EXT_framebuffer_sRGB"); + GLAD_GL_EXT_index_array_formats = has_ext("GL_EXT_index_array_formats"); + GLAD_GL_EXT_texture = has_ext("GL_EXT_texture"); + GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc"); + GLAD_GL_EXT_texture_sRGB = has_ext("GL_EXT_texture_sRGB"); + GLAD_GL_EXT_texture_swizzle = has_ext("GL_EXT_texture_swizzle"); + GLAD_GL_EXT_vertex_array = has_ext("GL_EXT_vertex_array"); + GLAD_GL_EXT_vertex_shader = has_ext("GL_EXT_vertex_shader"); + free_exts(); + return 1; } -static int glad_gl_find_extensions_gl( int version) { - const char *exts = NULL; - unsigned int num_exts_i = 0; - char **exts_i = NULL; - if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; +static void find_coreGL(void) { - GLAD_GL_ARB_ES2_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_ES2_compatibility"); - GLAD_GL_ARB_ES3_1_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_ES3_1_compatibility"); - GLAD_GL_ARB_ES3_2_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_ES3_2_compatibility"); - GLAD_GL_ARB_ES3_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_ES3_compatibility"); - GLAD_GL_ARB_blend_func_extended = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_blend_func_extended"); - GLAD_GL_ARB_buffer_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_buffer_storage"); - GLAD_GL_ARB_clear_buffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_clear_buffer_object"); - GLAD_GL_ARB_clear_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_clear_texture"); - GLAD_GL_ARB_color_buffer_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_color_buffer_float"); - GLAD_GL_ARB_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_compatibility"); - GLAD_GL_ARB_compressed_texture_pixel_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_compressed_texture_pixel_storage"); - GLAD_GL_ARB_compute_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_compute_shader"); - GLAD_GL_ARB_compute_variable_group_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_compute_variable_group_size"); - GLAD_GL_ARB_copy_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_copy_buffer"); - GLAD_GL_ARB_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_copy_image"); - GLAD_GL_ARB_debug_output = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_debug_output"); - GLAD_GL_ARB_depth_buffer_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_depth_buffer_float"); - GLAD_GL_ARB_depth_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_depth_clamp"); - GLAD_GL_ARB_depth_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_depth_texture"); - GLAD_GL_ARB_direct_state_access = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_direct_state_access"); - GLAD_GL_ARB_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_buffers"); - GLAD_GL_ARB_draw_buffers_blend = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_buffers_blend"); - GLAD_GL_ARB_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_elements_base_vertex"); - GLAD_GL_ARB_draw_indirect = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_indirect"); - GLAD_GL_ARB_draw_instanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_instanced"); - GLAD_GL_ARB_enhanced_layouts = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_enhanced_layouts"); - GLAD_GL_ARB_explicit_attrib_location = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_explicit_attrib_location"); - GLAD_GL_ARB_explicit_uniform_location = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_explicit_uniform_location"); - GLAD_GL_ARB_fragment_coord_conventions = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_coord_conventions"); - GLAD_GL_ARB_fragment_layer_viewport = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_layer_viewport"); - GLAD_GL_ARB_fragment_program = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_program"); - GLAD_GL_ARB_fragment_program_shadow = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_program_shadow"); - GLAD_GL_ARB_fragment_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_shader"); - GLAD_GL_ARB_fragment_shader_interlock = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_shader_interlock"); - GLAD_GL_ARB_framebuffer_no_attachments = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_framebuffer_no_attachments"); - GLAD_GL_ARB_framebuffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_framebuffer_object"); - GLAD_GL_ARB_framebuffer_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_framebuffer_sRGB"); - GLAD_GL_ARB_geometry_shader4 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_geometry_shader4"); - GLAD_GL_ARB_get_program_binary = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_get_program_binary"); - GLAD_GL_ARB_get_texture_sub_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_get_texture_sub_image"); - GLAD_GL_ARB_gl_spirv = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_gl_spirv"); - GLAD_GL_ARB_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_gpu_shader5"); - GLAD_GL_ARB_gpu_shader_fp64 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_gpu_shader_fp64"); - GLAD_GL_ARB_gpu_shader_int64 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_gpu_shader_int64"); - GLAD_GL_ARB_half_float_pixel = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_half_float_pixel"); - GLAD_GL_ARB_half_float_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_half_float_vertex"); - GLAD_GL_ARB_instanced_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_instanced_arrays"); - GLAD_GL_ARB_internalformat_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_internalformat_query"); - GLAD_GL_ARB_internalformat_query2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_internalformat_query2"); - GLAD_GL_ARB_map_buffer_range = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_map_buffer_range"); - GLAD_GL_ARB_multi_bind = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multi_bind"); - GLAD_GL_ARB_multi_draw_indirect = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multi_draw_indirect"); - GLAD_GL_ARB_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multisample"); - GLAD_GL_ARB_multitexture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multitexture"); - GLAD_GL_ARB_occlusion_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_occlusion_query"); - GLAD_GL_ARB_occlusion_query2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_occlusion_query2"); - GLAD_GL_ARB_pipeline_statistics_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_pipeline_statistics_query"); - GLAD_GL_ARB_query_buffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_query_buffer_object"); - GLAD_GL_ARB_sample_locations = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_sample_locations"); - GLAD_GL_ARB_sample_shading = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_sample_shading"); - GLAD_GL_ARB_seamless_cube_map = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_seamless_cube_map"); - GLAD_GL_ARB_seamless_cubemap_per_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_seamless_cubemap_per_texture"); - GLAD_GL_ARB_shader_atomic_counter_ops = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_atomic_counter_ops"); - GLAD_GL_ARB_shader_atomic_counters = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_atomic_counters"); - GLAD_GL_ARB_shader_bit_encoding = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_bit_encoding"); - GLAD_GL_ARB_shader_clock = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_clock"); - GLAD_GL_ARB_shader_image_load_store = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_image_load_store"); - GLAD_GL_ARB_shader_image_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_image_size"); - GLAD_GL_ARB_shader_objects = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_objects"); - GLAD_GL_ARB_shader_storage_buffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_storage_buffer_object"); - GLAD_GL_ARB_shader_texture_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_texture_lod"); - GLAD_GL_ARB_shading_language_100 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shading_language_100"); - GLAD_GL_ARB_shading_language_420pack = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shading_language_420pack"); - GLAD_GL_ARB_shading_language_include = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shading_language_include"); - GLAD_GL_ARB_shading_language_packing = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shading_language_packing"); - GLAD_GL_ARB_spirv_extensions = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_spirv_extensions"); - GLAD_GL_ARB_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_tessellation_shader"); - GLAD_GL_ARB_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_border_clamp"); - GLAD_GL_ARB_texture_buffer_object_rgb32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_buffer_object_rgb32"); - GLAD_GL_ARB_texture_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_compression"); - GLAD_GL_ARB_texture_cube_map = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_cube_map"); - GLAD_GL_ARB_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_cube_map_array"); - GLAD_GL_ARB_texture_env_add = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_env_add"); - GLAD_GL_ARB_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_filter_anisotropic"); - GLAD_GL_ARB_texture_filter_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_filter_minmax"); - GLAD_GL_ARB_texture_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_float"); - GLAD_GL_ARB_texture_mirror_clamp_to_edge = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_mirror_clamp_to_edge"); - GLAD_GL_ARB_texture_mirrored_repeat = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_mirrored_repeat"); - GLAD_GL_ARB_texture_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_multisample"); - GLAD_GL_ARB_texture_non_power_of_two = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_non_power_of_two"); - GLAD_GL_ARB_texture_rg = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_rg"); - GLAD_GL_ARB_texture_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_storage"); - GLAD_GL_ARB_texture_swizzle = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_swizzle"); - GLAD_GL_ARB_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_view"); - GLAD_GL_ARB_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_timer_query"); - GLAD_GL_ARB_transpose_matrix = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_transpose_matrix"); - GLAD_GL_ARB_uniform_buffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_uniform_buffer_object"); - GLAD_GL_ARB_vertex_array_bgra = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_array_bgra"); - GLAD_GL_ARB_vertex_array_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_array_object"); - GLAD_GL_ARB_vertex_attrib_binding = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_attrib_binding"); - GLAD_GL_ARB_vertex_buffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_buffer_object"); - GLAD_GL_ARB_vertex_program = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_program"); - GLAD_GL_ARB_vertex_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_shader"); - GLAD_GL_EXT_draw_instanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_instanced"); - GLAD_GL_EXT_fog_coord = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_fog_coord"); - GLAD_GL_EXT_framebuffer_blit = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_blit"); - GLAD_GL_EXT_framebuffer_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_multisample"); - GLAD_GL_EXT_framebuffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_object"); - GLAD_GL_EXT_framebuffer_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_sRGB"); - GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc"); - GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_anisotropic"); - GLAD_GL_EXT_texture_mirror_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_mirror_clamp"); - GLAD_GL_KHR_texture_compression_astc_hdr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_hdr"); - GLAD_GL_KHR_texture_compression_astc_ldr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_ldr"); - GLAD_GL_OES_compressed_paletted_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_paletted_texture"); - GLAD_GL_OES_fixed_point = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fixed_point"); + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; - glad_gl_free_extensions(exts_i, num_exts_i); - - return 1; -} - -static int glad_gl_find_core_gl(void) { - int i; const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", - "OpenGL SC ", NULL }; - int major = 0; - int minor = 0; - version = (const char*) glad_glGetString(GL_VERSION); - if (!version) return 0; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + for (i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { @@ -8547,136 +5391,84 @@ static int glad_gl_find_core_gl(void) { } } - GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); - - GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; - GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; - GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; - GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; - GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; - GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; - GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; - GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; - GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; - GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; - GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; - GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; - GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4; - GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4; - GLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4; - GLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4; - - return GLAD_MAKE_VERSION(major, minor); -} - -int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) { - int version; - - glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); - if(glad_glGetString == NULL) return 0; - if(glad_glGetString(GL_VERSION) == NULL) return 0; - version = glad_gl_find_core_gl(); - - glad_gl_load_GL_VERSION_1_0(load, userptr); - glad_gl_load_GL_VERSION_1_1(load, userptr); - glad_gl_load_GL_VERSION_1_2(load, userptr); - glad_gl_load_GL_VERSION_1_3(load, userptr); - glad_gl_load_GL_VERSION_1_4(load, userptr); - glad_gl_load_GL_VERSION_1_5(load, userptr); - glad_gl_load_GL_VERSION_2_0(load, userptr); - glad_gl_load_GL_VERSION_2_1(load, userptr); - glad_gl_load_GL_VERSION_3_0(load, userptr); - glad_gl_load_GL_VERSION_3_1(load, userptr); - glad_gl_load_GL_VERSION_3_2(load, userptr); - glad_gl_load_GL_VERSION_3_3(load, userptr); - glad_gl_load_GL_VERSION_4_0(load, userptr); - glad_gl_load_GL_VERSION_4_1(load, userptr); - glad_gl_load_GL_VERSION_4_2(load, userptr); - glad_gl_load_GL_VERSION_4_3(load, userptr); - - if (!glad_gl_find_extensions_gl(version)) return 0; - glad_gl_load_GL_ARB_ES2_compatibility(load, userptr); - glad_gl_load_GL_ARB_ES3_1_compatibility(load, userptr); - glad_gl_load_GL_ARB_ES3_2_compatibility(load, userptr); - glad_gl_load_GL_ARB_blend_func_extended(load, userptr); - glad_gl_load_GL_ARB_buffer_storage(load, userptr); - glad_gl_load_GL_ARB_clear_buffer_object(load, userptr); - glad_gl_load_GL_ARB_clear_texture(load, userptr); - glad_gl_load_GL_ARB_color_buffer_float(load, userptr); - glad_gl_load_GL_ARB_compute_shader(load, userptr); - glad_gl_load_GL_ARB_compute_variable_group_size(load, userptr); - glad_gl_load_GL_ARB_copy_buffer(load, userptr); - glad_gl_load_GL_ARB_copy_image(load, userptr); - glad_gl_load_GL_ARB_debug_output(load, userptr); - glad_gl_load_GL_ARB_direct_state_access(load, userptr); - glad_gl_load_GL_ARB_draw_buffers(load, userptr); - glad_gl_load_GL_ARB_draw_buffers_blend(load, userptr); - glad_gl_load_GL_ARB_draw_elements_base_vertex(load, userptr); - glad_gl_load_GL_ARB_draw_indirect(load, userptr); - glad_gl_load_GL_ARB_draw_instanced(load, userptr); - glad_gl_load_GL_ARB_fragment_program(load, userptr); - glad_gl_load_GL_ARB_framebuffer_no_attachments(load, userptr); - glad_gl_load_GL_ARB_framebuffer_object(load, userptr); - glad_gl_load_GL_ARB_geometry_shader4(load, userptr); - glad_gl_load_GL_ARB_get_program_binary(load, userptr); - glad_gl_load_GL_ARB_get_texture_sub_image(load, userptr); - glad_gl_load_GL_ARB_gl_spirv(load, userptr); - glad_gl_load_GL_ARB_gpu_shader_fp64(load, userptr); - glad_gl_load_GL_ARB_gpu_shader_int64(load, userptr); - glad_gl_load_GL_ARB_instanced_arrays(load, userptr); - glad_gl_load_GL_ARB_internalformat_query(load, userptr); - glad_gl_load_GL_ARB_internalformat_query2(load, userptr); - glad_gl_load_GL_ARB_map_buffer_range(load, userptr); - glad_gl_load_GL_ARB_multi_bind(load, userptr); - glad_gl_load_GL_ARB_multi_draw_indirect(load, userptr); - glad_gl_load_GL_ARB_multisample(load, userptr); - glad_gl_load_GL_ARB_multitexture(load, userptr); - glad_gl_load_GL_ARB_occlusion_query(load, userptr); - glad_gl_load_GL_ARB_sample_locations(load, userptr); - glad_gl_load_GL_ARB_sample_shading(load, userptr); - glad_gl_load_GL_ARB_shader_atomic_counters(load, userptr); - glad_gl_load_GL_ARB_shader_image_load_store(load, userptr); - glad_gl_load_GL_ARB_shader_objects(load, userptr); - glad_gl_load_GL_ARB_shader_storage_buffer_object(load, userptr); - glad_gl_load_GL_ARB_shading_language_include(load, userptr); - glad_gl_load_GL_ARB_tessellation_shader(load, userptr); - glad_gl_load_GL_ARB_texture_compression(load, userptr); - glad_gl_load_GL_ARB_texture_multisample(load, userptr); - glad_gl_load_GL_ARB_texture_storage(load, userptr); - glad_gl_load_GL_ARB_texture_view(load, userptr); - glad_gl_load_GL_ARB_timer_query(load, userptr); - glad_gl_load_GL_ARB_transpose_matrix(load, userptr); - glad_gl_load_GL_ARB_uniform_buffer_object(load, userptr); - glad_gl_load_GL_ARB_vertex_array_object(load, userptr); - glad_gl_load_GL_ARB_vertex_attrib_binding(load, userptr); - glad_gl_load_GL_ARB_vertex_buffer_object(load, userptr); - glad_gl_load_GL_ARB_vertex_program(load, userptr); - glad_gl_load_GL_ARB_vertex_shader(load, userptr); - glad_gl_load_GL_EXT_draw_instanced(load, userptr); - glad_gl_load_GL_EXT_fog_coord(load, userptr); - glad_gl_load_GL_EXT_framebuffer_blit(load, userptr); - glad_gl_load_GL_EXT_framebuffer_multisample(load, userptr); - glad_gl_load_GL_EXT_framebuffer_object(load, userptr); - glad_gl_load_GL_OES_fixed_point(load, userptr); - - - - return version; -} - - -int gladLoadGL( GLADloadfunc load) { - return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); -} - - - - - - -#ifdef __cplusplus -} +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); #endif -#endif /* GLAD_GL_IMPLEMENTATION */ + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; + GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; + if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) { + max_loaded_major = 3; + max_loaded_minor = 3; + } +} +int gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + load_GL_VERSION_3_3(load); + + if (!find_extensionsGL()) return 0; + load_GL_AMD_debug_output(load); + load_GL_ARB_ES2_compatibility(load); + load_GL_ARB_buffer_storage(load); + load_GL_ARB_debug_output(load); + load_GL_ARB_draw_buffers(load); + load_GL_ARB_draw_buffers_blend(load); + load_GL_ARB_fragment_program(load); + load_GL_ARB_framebuffer_object(load); + load_GL_ARB_multisample(load); + load_GL_ARB_sample_locations(load); + load_GL_ARB_texture_compression(load); + load_GL_ARB_texture_multisample(load); + load_GL_ARB_uniform_buffer_object(load); + load_GL_ARB_vertex_array_object(load); + load_GL_ARB_vertex_attrib_binding(load); + load_GL_ARB_vertex_buffer_object(load); + load_GL_ARB_vertex_program(load); + load_GL_ARB_vertex_shader(load); + load_GL_ATI_element_array(load); + load_GL_ATI_fragment_shader(load); + load_GL_ATI_vertex_array_object(load); + load_GL_EXT_blend_color(load); + load_GL_EXT_blend_equation_separate(load); + load_GL_EXT_blend_func_separate(load); + load_GL_EXT_debug_marker(load); + load_GL_EXT_framebuffer_blit(load); + load_GL_EXT_framebuffer_multisample(load); + load_GL_EXT_framebuffer_object(load); + load_GL_EXT_vertex_array(load); + load_GL_EXT_vertex_shader(load); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + +#endif // GLAD_IMPLEMENTATION diff --git a/raylib/external/glad_gles2.h b/raylib/external/glad_gles2.h deleted file mode 100644 index 6c753d0..0000000 --- a/raylib/external/glad_gles2.h +++ /dev/null @@ -1,4774 +0,0 @@ -/** - * Loader generated by glad 2.0.2 on Wed Dec 28 13:28:51 2022 - * - * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 - * - * Generator: C/C++ - * Specification: gl - * Extensions: 170 - * - * APIs: - * - gles2=2.0 - * - * Options: - * - ALIAS = False - * - DEBUG = False - * - HEADER_ONLY = True - * - LOADER = False - * - MX = False - * - ON_DEMAND = False - * - * Commandline: - * --api='gles2=2.0' --extensions='GL_EXT_EGL_image_array,GL_EXT_EGL_image_storage,GL_EXT_EGL_image_storage_compression,GL_EXT_YUV_target,GL_EXT_base_instance,GL_EXT_blend_func_extended,GL_EXT_blend_minmax,GL_EXT_buffer_storage,GL_EXT_clear_texture,GL_EXT_clip_control,GL_EXT_clip_cull_distance,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_conservative_depth,GL_EXT_copy_image,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_clamp,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers,GL_EXT_draw_buffers_indexed,GL_EXT_draw_elements_base_vertex,GL_EXT_draw_instanced,GL_EXT_draw_transform_feedback,GL_EXT_external_buffer,GL_EXT_float_blend,GL_EXT_fragment_shading_rate,GL_EXT_geometry_point_size,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_instanced_arrays,GL_EXT_map_buffer_range,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_multi_draw_arrays,GL_EXT_multi_draw_indirect,GL_EXT_multisampled_compatibility,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_multiview_draw_buffers,GL_EXT_multiview_tessellation_geometry_shader,GL_EXT_multiview_texture_multisample,GL_EXT_multiview_timer_query,GL_EXT_occlusion_query_boolean,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_pvrtc_sRGB,GL_EXT_raster_multisample,GL_EXT_read_format_bgra,GL_EXT_render_snorm,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_depth_stencil,GL_EXT_separate_shader_objects,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_group_vote,GL_EXT_shader_implicit_conversions,GL_EXT_shader_integer_mix,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_shader_pixel_local_storage,GL_EXT_shader_pixel_local_storage2,GL_EXT_shader_samples_identical,GL_EXT_shader_texture_lod,GL_EXT_shadow_samplers,GL_EXT_sparse_texture,GL_EXT_sparse_texture2,GL_EXT_tessellation_point_size,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_compression_astc_decode_mode,GL_EXT_texture_compression_bptc,GL_EXT_texture_compression_dxt1,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_compression_s3tc_srgb,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_format_sRGB_override,GL_EXT_texture_mirror_clamp_to_edge,GL_EXT_texture_norm16,GL_EXT_texture_query_lod,GL_EXT_texture_rg,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_RG8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shadow_lod,GL_EXT_texture_storage,GL_EXT_texture_storage_compression,GL_EXT_texture_type_2_10_10_10_REV,GL_EXT_texture_view,GL_EXT_unpack_subimage,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_shader_subgroup,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_compressed_ETC1_RGB8_sub_texture,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_copy_image,GL_OES_depth24,GL_OES_depth32,GL_OES_depth_texture,GL_OES_draw_buffers_indexed,GL_OES_draw_elements_base_vertex,GL_OES_element_index_uint,GL_OES_fbo_render_mipmap,GL_OES_fragment_precision_high,GL_OES_geometry_point_size,GL_OES_geometry_shader,GL_OES_get_program_binary,GL_OES_gpu_shader5,GL_OES_mapbuffer,GL_OES_packed_depth_stencil,GL_OES_primitive_bounding_box,GL_OES_required_internalformat,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_io_blocks,GL_OES_shader_multisample_interpolation,GL_OES_standard_derivatives,GL_OES_stencil1,GL_OES_stencil4,GL_OES_surfaceless_context,GL_OES_tessellation_point_size,GL_OES_tessellation_shader,GL_OES_texture_3D,GL_OES_texture_border_clamp,GL_OES_texture_buffer,GL_OES_texture_compression_astc,GL_OES_texture_cube_map_array,GL_OES_texture_float,GL_OES_texture_float_linear,GL_OES_texture_half_float,GL_OES_texture_half_float_linear,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_texture_view,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OES_vertex_type_10_10_10_2,GL_OES_viewport_array' c --header-only - * - * Online: - * http://glad.sh/#api=gles2%3D2.0&generator=c&options=HEADER_ONLY - * - */ - -#ifndef GLAD_GLES2_H_ -#define GLAD_GLES2_H_ - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-id-macro" -#endif -#ifdef __gl2_h_ - #error OpenGL ES 2 header already included (API: gles2), remove previous include! -#endif -#define __gl2_h_ 1 -#ifdef __gles2_gl2_h_ - #error OpenGL ES 2 header already included (API: gles2), remove previous include! -#endif -#define __gles2_gl2_h_ 1 -#ifdef __gl3_h_ - #error OpenGL ES 3 header already included (API: gles2), remove previous include! -#endif -#define __gl3_h_ 1 -#ifdef __gles2_gl3_h_ - #error OpenGL ES 3 header already included (API: gles2), remove previous include! -#endif -#define __gles2_gl3_h_ 1 -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#define GLAD_GLES2 -#define GLAD_OPTION_GLES2_HEADER_ONLY - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef GLAD_PLATFORM_H_ -#define GLAD_PLATFORM_H_ - -#ifndef GLAD_PLATFORM_WIN32 - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) - #define GLAD_PLATFORM_WIN32 1 - #else - #define GLAD_PLATFORM_WIN32 0 - #endif -#endif - -#ifndef GLAD_PLATFORM_APPLE - #ifdef __APPLE__ - #define GLAD_PLATFORM_APPLE 1 - #else - #define GLAD_PLATFORM_APPLE 0 - #endif -#endif - -#ifndef GLAD_PLATFORM_EMSCRIPTEN - #ifdef __EMSCRIPTEN__ - #define GLAD_PLATFORM_EMSCRIPTEN 1 - #else - #define GLAD_PLATFORM_EMSCRIPTEN 0 - #endif -#endif - -#ifndef GLAD_PLATFORM_UWP - #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) - #ifdef __has_include - #if __has_include() - #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 - #endif - #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ - #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 - #endif - #endif - - #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY - #include - #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - #define GLAD_PLATFORM_UWP 1 - #endif - #endif - - #ifndef GLAD_PLATFORM_UWP - #define GLAD_PLATFORM_UWP 0 - #endif -#endif - -#ifdef __GNUC__ - #define GLAD_GNUC_EXTENSION __extension__ -#else - #define GLAD_GNUC_EXTENSION -#endif - -#define GLAD_UNUSED(x) (void)(x) - -#ifndef GLAD_API_CALL - #if defined(GLAD_API_CALL_EXPORT) - #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) - #if defined(GLAD_API_CALL_EXPORT_BUILD) - #if defined(__GNUC__) - #define GLAD_API_CALL __attribute__ ((dllexport)) extern - #else - #define GLAD_API_CALL __declspec(dllexport) extern - #endif - #else - #if defined(__GNUC__) - #define GLAD_API_CALL __attribute__ ((dllimport)) extern - #else - #define GLAD_API_CALL __declspec(dllimport) extern - #endif - #endif - #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) - #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern - #else - #define GLAD_API_CALL extern - #endif - #else - #define GLAD_API_CALL extern - #endif -#endif - -#ifdef APIENTRY - #define GLAD_API_PTR APIENTRY -#elif GLAD_PLATFORM_WIN32 - #define GLAD_API_PTR __stdcall -#else - #define GLAD_API_PTR -#endif - -#ifndef GLAPI -#define GLAPI GLAD_API_CALL -#endif - -#ifndef GLAPIENTRY -#define GLAPIENTRY GLAD_API_PTR -#endif - -#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) -#define GLAD_VERSION_MAJOR(version) (version / 10000) -#define GLAD_VERSION_MINOR(version) (version % 10000) - -#define GLAD_GENERATOR_VERSION "2.0.2" - -typedef void (*GLADapiproc)(void); - -typedef GLADapiproc (*GLADloadfunc)(const char *name); -typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); - -typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); -typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); - -#endif /* GLAD_PLATFORM_H_ */ - -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_ACTIVE_PROGRAM_EXT 0x8259 -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_ALIASED_POINT_SIZE_RANGE 0x846D -#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF -#define GL_ALPHA 0x1906 -#define GL_ALPHA16F_EXT 0x881C -#define GL_ALPHA32F_EXT 0x8816 -#define GL_ALPHA8_EXT 0x803C -#define GL_ALPHA8_OES 0x803C -#define GL_ALPHA_BITS 0x0D55 -#define GL_ALWAYS 0x0207 -#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A -#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_BACK 0x0405 -#define GL_BGRA8_EXT 0x93A1 -#define GL_BGRA_EXT 0x80E1 -#define GL_BLEND 0x0BE2 -#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 -#define GL_BLEND_COLOR 0x8005 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_EQUATION 0x8009 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLUE_BITS 0x0D54 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_BUFFER_ACCESS_OES 0x88BB -#define GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F -#define GL_BUFFER_KHR 0x82E0 -#define GL_BUFFER_MAPPED_OES 0x88BC -#define GL_BUFFER_MAP_POINTER_OES 0x88BD -#define GL_BUFFER_OBJECT_EXT 0x9151 -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_STORAGE_FLAGS_EXT 0x8220 -#define GL_BUFFER_USAGE 0x8765 -#define GL_BYTE 0x1400 -#define GL_CCW 0x0901 -#define GL_CLAMP_TO_BORDER_EXT 0x812D -#define GL_CLAMP_TO_BORDER_OES 0x812D -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000 -#define GL_CLIENT_STORAGE_BIT_EXT 0x0200 -#define GL_CLIP_DEPTH_MODE 0x935D -#define GL_CLIP_DEPTH_MODE_EXT 0x935D -#define GL_CLIP_DISTANCE0_EXT 0x3000 -#define GL_CLIP_DISTANCE1_EXT 0x3001 -#define GL_CLIP_DISTANCE2_EXT 0x3002 -#define GL_CLIP_DISTANCE3_EXT 0x3003 -#define GL_CLIP_DISTANCE4_EXT 0x3004 -#define GL_CLIP_DISTANCE5_EXT 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE6_EXT 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_CLIP_DISTANCE7_EXT 0x3007 -#define GL_CLIP_ORIGIN 0x935C -#define GL_CLIP_ORIGIN_EXT 0x935C -#define GL_CLIP_PLANE0 0x3000 -#define GL_CLIP_PLANE1 0x3001 -#define GL_CLIP_PLANE2 0x3002 -#define GL_CLIP_PLANE3 0x3003 -#define GL_CLIP_PLANE4 0x3004 -#define GL_CLIP_PLANE5 0x3005 -#define GL_COLORBURN_KHR 0x929A -#define GL_COLORDODGE_KHR 0x9299 -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 -#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA -#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB -#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC -#define GL_COLOR_ATTACHMENT13_EXT 0x8CED -#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE -#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF -#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 -#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 -#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 -#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 -#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 -#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 -#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 -#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 -#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 -#define GL_COLOR_ATTACHMENT_EXT 0x90F0 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_EXT 0x1800 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E -#define GL_COMPILE_STATUS 0x8B81 -#define GL_COMPLETION_STATUS_KHR 0x91B1 -#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB -#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 -#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 -#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA -#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC -#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD -#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 -#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 -#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 -#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 -#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 -#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 -#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 -#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 -#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 -#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 -#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 -#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 -#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 -#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 -#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 -#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 -#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 -#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 -#define GL_COMPRESSED_RGBA_BPTC_UNORM_EXT 0x8E8C -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT 0x8E8E -#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT 0x8E8F -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 -#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT 0x8E8D -#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 -#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0 -#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 -#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1 -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F -#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 -#define GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 -#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 -#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 -#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 -#define GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT 0x00000010 -#define GL_CONTEXT_LOST_KHR 0x0507 -#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC -#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB -#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 -#define GL_CONTEXT_ROBUST_ACCESS_KHR 0x90F3 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_CURRENT_QUERY_EXT 0x8865 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_CW 0x0900 -#define GL_D3D12_FENCE_VALUE_EXT 0x9595 -#define GL_DARKEN_KHR 0x9297 -#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 -#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D -#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 -#define GL_DEBUG_OUTPUT_KHR 0x92E0 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 -#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 -#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 -#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 -#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B -#define GL_DEBUG_SOURCE_API_KHR 0x8246 -#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A -#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B -#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D -#define GL_DEBUG_TYPE_ERROR_KHR 0x824C -#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 -#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 -#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 -#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A -#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F -#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E -#define GL_DECODE_EXT 0x8A49 -#define GL_DECR 0x1E03 -#define GL_DECR_WRAP 0x8508 -#define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581 -#define GL_DELETE_STATUS 0x8B80 -#define GL_DEPTH24_STENCIL8_OES 0x88F0 -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_DEPTH_BITS 0x0D56 -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_DEPTH_CLAMP_EXT 0x864F -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT16_OES 0x81A5 -#define GL_DEPTH_COMPONENT24_OES 0x81A6 -#define GL_DEPTH_COMPONENT32_OES 0x81A7 -#define GL_DEPTH_EXT 0x1801 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_STENCIL_OES 0x84F9 -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DEVICE_LUID_EXT 0x9599 -#define GL_DEVICE_NODE_MASK_EXT 0x959A -#define GL_DEVICE_UUID_EXT 0x9597 -#define GL_DIFFERENCE_KHR 0x929E -#define GL_DITHER 0x0BD0 -#define GL_DONT_CARE 0x1100 -#define GL_DRAW_BUFFER0_EXT 0x8825 -#define GL_DRAW_BUFFER10_EXT 0x882F -#define GL_DRAW_BUFFER11_EXT 0x8830 -#define GL_DRAW_BUFFER12_EXT 0x8831 -#define GL_DRAW_BUFFER13_EXT 0x8832 -#define GL_DRAW_BUFFER14_EXT 0x8833 -#define GL_DRAW_BUFFER15_EXT 0x8834 -#define GL_DRAW_BUFFER1_EXT 0x8826 -#define GL_DRAW_BUFFER2_EXT 0x8827 -#define GL_DRAW_BUFFER3_EXT 0x8828 -#define GL_DRAW_BUFFER4_EXT 0x8829 -#define GL_DRAW_BUFFER5_EXT 0x882A -#define GL_DRAW_BUFFER6_EXT 0x882B -#define GL_DRAW_BUFFER7_EXT 0x882C -#define GL_DRAW_BUFFER8_EXT 0x882D -#define GL_DRAW_BUFFER9_EXT 0x882E -#define GL_DRAW_BUFFER_EXT 0x0C01 -#define GL_DRIVER_UUID_EXT 0x9598 -#define GL_DST_ALPHA 0x0304 -#define GL_DST_COLOR 0x0306 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100 -#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_EQUAL 0x0202 -#define GL_ETC1_RGB8_OES 0x8D64 -#define GL_EXCLUSION_KHR 0x92A0 -#define GL_EXCLUSIVE_EXT 0x8F11 -#define GL_EXTENSIONS 0x1F03 -#define GL_FALSE 0 -#define GL_FASTEST 0x1101 -#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D -#define GL_FIRST_VERTEX_CONVENTION_OES 0x8E4D -#define GL_FIXED 0x140C -#define GL_FLOAT 0x1406 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_FRACTIONAL_EVEN_EXT 0x8E7C -#define GL_FRACTIONAL_EVEN_OES 0x8E7C -#define GL_FRACTIONAL_ODD_EXT 0x8E7B -#define GL_FRACTIONAL_ODD_OES 0x8E7B -#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES 0x8E5D -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B -#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 -#define GL_FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_DEFAULT_FRAMEBUFFER_SUPPORTED_EXT 0x96DF -#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT 0x96D2 -#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT 0x96D5 -#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT 0x96D4 -#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT 0x96D6 -#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT 0x96D3 -#define GL_FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT 0x8F6F -#define GL_FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT 0x96DE -#define GL_FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT 0x96DD -#define GL_FRAMEBUFFER 0x8D40 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES 0x8DA7 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT 0x9312 -#define GL_FRAMEBUFFER_DEFAULT_LAYERS_OES 0x9312 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 -#define GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT 0x9652 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 -#define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219 -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_FRONT 0x0404 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_FRONT_FACE 0x0B46 -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_FUNC_SUBTRACT 0x800A -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_GEOMETRY_LINKED_INPUT_TYPE_EXT 0x8917 -#define GL_GEOMETRY_LINKED_INPUT_TYPE_OES 0x8917 -#define GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT 0x8918 -#define GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES 0x8918 -#define GL_GEOMETRY_LINKED_VERTICES_OUT_EXT 0x8916 -#define GL_GEOMETRY_LINKED_VERTICES_OUT_OES 0x8916 -#define GL_GEOMETRY_SHADER_BIT_EXT 0x00000004 -#define GL_GEOMETRY_SHADER_BIT_OES 0x00000004 -#define GL_GEOMETRY_SHADER_EXT 0x8DD9 -#define GL_GEOMETRY_SHADER_INVOCATIONS_EXT 0x887F -#define GL_GEOMETRY_SHADER_INVOCATIONS_OES 0x887F -#define GL_GEOMETRY_SHADER_OES 0x8DD9 -#define GL_GEQUAL 0x0206 -#define GL_GPU_DISJOINT_EXT 0x8FBB -#define GL_GREATER 0x0204 -#define GL_GREEN_BITS 0x0D53 -#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 -#define GL_GUILTY_CONTEXT_RESET_KHR 0x8253 -#define GL_HALF_FLOAT_OES 0x8D61 -#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B -#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C -#define GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594 -#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A -#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589 -#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 -#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 -#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588 -#define GL_HARDLIGHT_KHR 0x929B -#define GL_HIGH_FLOAT 0x8DF2 -#define GL_HIGH_INT 0x8DF5 -#define GL_HSL_COLOR_KHR 0x92AF -#define GL_HSL_HUE_KHR 0x92AD -#define GL_HSL_LUMINOSITY_KHR 0x92B0 -#define GL_HSL_SATURATION_KHR 0x92AE -#define GL_IMAGE_BUFFER_EXT 0x9051 -#define GL_IMAGE_BUFFER_OES 0x9051 -#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 -#define GL_IMAGE_CUBE_MAP_ARRAY_OES 0x9054 -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A -#define GL_INCLUSIVE_EXT 0x8F10 -#define GL_INCR 0x1E02 -#define GL_INCR_WRAP 0x8507 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 -#define GL_INNOCENT_CONTEXT_RESET_KHR 0x8254 -#define GL_INT 0x1404 -#define GL_INT_10_10_10_2_OES 0x8DF7 -#define GL_INT_IMAGE_BUFFER_EXT 0x905C -#define GL_INT_IMAGE_BUFFER_OES 0x905C -#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F -#define GL_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x905F -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910C -#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 -#define GL_INT_SAMPLER_BUFFER_OES 0x8DD0 -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900E -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900E -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_INVALID_OPERATION 0x0502 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVERT 0x150A -#define GL_ISOLINES_EXT 0x8E7A -#define GL_ISOLINES_OES 0x8E7A -#define GL_IS_PER_PATCH_EXT 0x92E7 -#define GL_IS_PER_PATCH_OES 0x92E7 -#define GL_KEEP 0x1E00 -#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E -#define GL_LAST_VERTEX_CONVENTION_OES 0x8E4E -#define GL_LAYER_PROVOKING_VERTEX_EXT 0x825E -#define GL_LAYER_PROVOKING_VERTEX_OES 0x825E -#define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E -#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531 -#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530 -#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F -#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 -#define GL_LAYOUT_GENERAL_EXT 0x958D -#define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 -#define GL_LAYOUT_TRANSFER_DST_EXT 0x9593 -#define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 -#define GL_LEQUAL 0x0203 -#define GL_LESS 0x0201 -#define GL_LIGHTEN_KHR 0x9298 -#define GL_LINEAR 0x2601 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_LINEAR_TILING_EXT 0x9585 -#define GL_LINES 0x0001 -#define GL_LINES_ADJACENCY_EXT 0x000A -#define GL_LINES_ADJACENCY_OES 0x000A -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B -#define GL_LINE_STRIP_ADJACENCY_OES 0x000B -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINK_STATUS 0x8B82 -#define GL_LOCATION_INDEX_EXT 0x930F -#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 -#define GL_LOSE_CONTEXT_ON_RESET_KHR 0x8252 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_LOWER_LEFT_EXT 0x8CA1 -#define GL_LOW_FLOAT 0x8DF0 -#define GL_LOW_INT 0x8DF3 -#define GL_LUID_SIZE_EXT 8 -#define GL_LUMINANCE 0x1909 -#define GL_LUMINANCE16F_EXT 0x881E -#define GL_LUMINANCE32F_EXT 0x8818 -#define GL_LUMINANCE4_ALPHA4_OES 0x8043 -#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 -#define GL_LUMINANCE8_ALPHA8_OES 0x8045 -#define GL_LUMINANCE8_EXT 0x8040 -#define GL_LUMINANCE8_OES 0x8040 -#define GL_LUMINANCE_ALPHA 0x190A -#define GL_LUMINANCE_ALPHA16F_EXT 0x881F -#define GL_LUMINANCE_ALPHA32F_EXT 0x8819 -#define GL_MAP_COHERENT_BIT_EXT 0x0080 -#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010 -#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008 -#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004 -#define GL_MAP_PERSISTENT_BIT_EXT 0x0040 -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_READ_BIT_EXT 0x0001 -#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_WRITE_BIT_EXT 0x0002 -#define GL_MAX 0x8008 -#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 -#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32 -#define GL_MAX_CLIP_PLANES 0x0D32 -#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF -#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA -#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8A32 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8A32 -#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E1E -#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E1E -#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E1F -#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E1F -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_MAX_CULL_DISTANCES 0x82F9 -#define GL_MAX_CULL_DISTANCES_EXT 0x82F9 -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C -#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 -#define GL_MAX_DRAW_BUFFERS_EXT 0x8824 -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC -#define GL_MAX_EXT 0x8008 -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5C -#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT 0x96DC -#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT 0x96DB -#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT 0x96DA -#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT 0x96D8 -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#define GL_MAX_FRAMEBUFFER_LAYERS_EXT 0x9317 -#define GL_MAX_FRAMEBUFFER_LAYERS_OES 0x9317 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT 0x92D5 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES 0x92D5 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT 0x92CF -#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES 0x92CF -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT 0x90CD -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES 0x90CD -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT 0x9123 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT 0x9124 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES 0x9124 -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES 0x8DE0 -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT 0x8E5A -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES 0x8E5A -#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT 0x90D7 -#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES 0x90D7 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES 0x8C29 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES 0x8DE1 -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT 0x8A2C -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES 0x8A2C -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8DDF -#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 -#define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2 -#define GL_MAX_PATCH_VERTICES_EXT 0x8E7D -#define GL_MAX_PATCH_VERTICES_OES 0x8E7D -#define GL_MAX_RASTER_SAMPLES_EXT 0x9329 -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_MAX_SAMPLES_EXT 0x8D57 -#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT 0x9650 -#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT 0x9651 -#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 -#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 -#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT 0x8F67 -#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT 0x9199 -#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT 0x919A -#define GL_MAX_SPARSE_TEXTURE_SIZE_EXT 0x9198 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT 0x92D3 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES 0x92D3 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT 0x92CD -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES 0x92CD -#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT 0x90CB -#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES 0x90CB -#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT 0x886C -#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES 0x886C -#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT 0x8E83 -#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES 0x8E83 -#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT 0x90D8 -#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES 0x90D8 -#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT 0x8E81 -#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES 0x8E81 -#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT 0x8E85 -#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES 0x8E85 -#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT 0x8E89 -#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES 0x8E89 -#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E7F -#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E7F -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT 0x92D4 -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES 0x92D4 -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT 0x92CE -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES 0x92CE -#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT 0x90CC -#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES 0x90CC -#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT 0x886D -#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES 0x886D -#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT 0x8E86 -#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES 0x8E86 -#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT 0x90D9 -#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES 0x90D9 -#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT 0x8E82 -#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES 0x8E82 -#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT 0x8E8A -#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES 0x8E8A -#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E80 -#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E80 -#define GL_MAX_TESS_GEN_LEVEL_EXT 0x8E7E -#define GL_MAX_TESS_GEN_LEVEL_OES 0x8E7E -#define GL_MAX_TESS_PATCH_COMPONENTS_EXT 0x8E84 -#define GL_MAX_TESS_PATCH_COMPONENTS_OES 0x8E84 -#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B -#define GL_MAX_TEXTURE_BUFFER_SIZE_OES 0x8C2B -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF -#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VIEWPORTS_OES 0x825B -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 -#define GL_MEDIUM_FLOAT 0x8DF1 -#define GL_MEDIUM_INT 0x8DF4 -#define GL_MIN 0x8007 -#define GL_MIN_EXT 0x8007 -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5B -#define GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT 0x96D9 -#define GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT 0x96D7 -#define GL_MIN_SAMPLE_SHADING_VALUE_OES 0x8C37 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 -#define GL_MULTIPLY_KHR 0x9294 -#define GL_MULTISAMPLE_EXT 0x809D -#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B -#define GL_MULTIVIEW_EXT 0x90F1 -#define GL_NEAREST 0x2600 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_NEGATIVE_ONE_TO_ONE 0x935E -#define GL_NEGATIVE_ONE_TO_ONE_EXT 0x935E -#define GL_NEVER 0x0200 -#define GL_NICEST 0x1102 -#define GL_NONE 0 -#define GL_NOTEQUAL 0x0205 -#define GL_NO_ERROR 0 -#define GL_NO_RESET_NOTIFICATION_EXT 0x8261 -#define GL_NO_RESET_NOTIFICATION_KHR 0x8261 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_NUM_DEVICE_UUIDS_EXT 0x9596 -#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_NUM_SPARSE_LEVELS_EXT 0x91AA -#define GL_NUM_SURFACE_COMPRESSION_FIXED_RATES_EXT 0x8F6E -#define GL_NUM_TILING_TYPES_EXT 0x9582 -#define GL_NUM_VIRTUAL_PAGE_SIZES_EXT 0x91A8 -#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 -#define GL_ONE 1 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB -#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_OPTIMAL_TILING_EXT 0x9584 -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_OVERLAY_KHR 0x9296 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 -#define GL_PALETTE4_RGB5_A1_OES 0x8B94 -#define GL_PALETTE4_RGB8_OES 0x8B90 -#define GL_PALETTE4_RGBA4_OES 0x8B93 -#define GL_PALETTE4_RGBA8_OES 0x8B91 -#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 -#define GL_PALETTE8_RGB5_A1_OES 0x8B99 -#define GL_PALETTE8_RGB8_OES 0x8B95 -#define GL_PALETTE8_RGBA4_OES 0x8B98 -#define GL_PALETTE8_RGBA8_OES 0x8B96 -#define GL_PATCHES_EXT 0x000E -#define GL_PATCHES_OES 0x000E -#define GL_PATCH_VERTICES_EXT 0x8E72 -#define GL_PATCH_VERTICES_OES 0x8E72 -#define GL_POINTS 0x0000 -#define GL_POLYGON_OFFSET_CLAMP 0x8E1B -#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 -#define GL_PRIMITIVES_GENERATED_OES 0x8C87 -#define GL_PRIMITIVE_BOUNDING_BOX_EXT 0x92BE -#define GL_PRIMITIVE_BOUNDING_BOX_OES 0x92BE -#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 -#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES 0x8221 -#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF -#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 -#define GL_PROGRAM_KHR 0x82E2 -#define GL_PROGRAM_OBJECT_EXT 0x8B40 -#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A -#define GL_PROGRAM_PIPELINE_KHR 0x82E4 -#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F -#define GL_PROGRAM_SEPARABLE_EXT 0x8258 -#define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B -#define GL_QUADS_EXT 0x0007 -#define GL_QUADS_OES 0x0007 -#define GL_QUERY_COUNTER_BITS_EXT 0x8864 -#define GL_QUERY_KHR 0x82E3 -#define GL_QUERY_OBJECT_EXT 0x9153 -#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 -#define GL_QUERY_RESULT_EXT 0x8866 -#define GL_R16F_EXT 0x822D -#define GL_R16_EXT 0x822A -#define GL_R16_SNORM_EXT 0x8F98 -#define GL_R32F_EXT 0x822E -#define GL_R8_EXT 0x8229 -#define GL_R8_SNORM 0x8F94 -#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A -#define GL_RASTER_MULTISAMPLE_EXT 0x9327 -#define GL_RASTER_SAMPLES_EXT 0x9328 -#define GL_READ_BUFFER_EXT 0x0C02 -#define GL_RED_BITS 0x0D52 -#define GL_RED_EXT 0x1903 -#define GL_REFERENCED_BY_GEOMETRY_SHADER_EXT 0x9309 -#define GL_REFERENCED_BY_GEOMETRY_SHADER_OES 0x9309 -#define GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT 0x9307 -#define GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES 0x9307 -#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT 0x9308 -#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES 0x9308 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERER 0x1F01 -#define GL_REPEAT 0x2901 -#define GL_REPLACE 0x1E01 -#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 -#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 -#define GL_RESET_NOTIFICATION_STRATEGY_KHR 0x8256 -#define GL_RG16F_EXT 0x822F -#define GL_RG16_EXT 0x822C -#define GL_RG16_SNORM_EXT 0x8F99 -#define GL_RG32F_EXT 0x8230 -#define GL_RG8_EXT 0x822B -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB 0x1907 -#define GL_RGB10_A2_EXT 0x8059 -#define GL_RGB10_EXT 0x8052 -#define GL_RGB16F_EXT 0x881B -#define GL_RGB16_EXT 0x8054 -#define GL_RGB16_SNORM_EXT 0x8F9A -#define GL_RGB32F_EXT 0x8815 -#define GL_RGB565 0x8D62 -#define GL_RGB565_OES 0x8D62 -#define GL_RGB5_A1 0x8057 -#define GL_RGB5_A1_OES 0x8057 -#define GL_RGB8_OES 0x8051 -#define GL_RGBA 0x1908 -#define GL_RGBA16F_EXT 0x881A -#define GL_RGBA16_EXT 0x805B -#define GL_RGBA16_SNORM_EXT 0x8F9B -#define GL_RGBA32F_EXT 0x8814 -#define GL_RGBA4 0x8056 -#define GL_RGBA4_OES 0x8056 -#define GL_RGBA8_OES 0x8058 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_RG_EXT 0x8227 -#define GL_SAMPLER 0x82E6 -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910B -#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62 -#define GL_SAMPLER_3D_OES 0x8B5F -#define GL_SAMPLER_BUFFER_EXT 0x8DC2 -#define GL_SAMPLER_BUFFER_OES 0x8DC2 -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_OES 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT 0x900D -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES 0x900D -#define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7 -#define GL_SAMPLER_EXTERNAL_OES 0x8D66 -#define GL_SAMPLER_KHR 0x82E6 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_SHADING_OES 0x8C36 -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_SCREEN_KHR 0x9295 -#define GL_SHADER_BINARY_FORMATS 0x8DF8 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_SHADER_KHR 0x82E1 -#define GL_SHADER_OBJECT_EXT 0x8B48 -#define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_SHADER_TYPE 0x8B4F -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_SHADING_RATE_1X1_PIXELS_EXT 0x96A6 -#define GL_SHADING_RATE_1X1_PIXELS_QCOM 0x96A6 -#define GL_SHADING_RATE_1X2_PIXELS_EXT 0x96A7 -#define GL_SHADING_RATE_1X2_PIXELS_QCOM 0x96A7 -#define GL_SHADING_RATE_1X4_PIXELS_EXT 0x96AA -#define GL_SHADING_RATE_1X4_PIXELS_QCOM 0x96AA -#define GL_SHADING_RATE_2X1_PIXELS_EXT 0x96A8 -#define GL_SHADING_RATE_2X1_PIXELS_QCOM 0x96A8 -#define GL_SHADING_RATE_2X2_PIXELS_EXT 0x96A9 -#define GL_SHADING_RATE_2X2_PIXELS_QCOM 0x96A9 -#define GL_SHADING_RATE_2X4_PIXELS_EXT 0x96AD -#define GL_SHADING_RATE_2X4_PIXELS_QCOM 0x96AD -#define GL_SHADING_RATE_4X1_PIXELS_EXT 0x96AB -#define GL_SHADING_RATE_4X1_PIXELS_QCOM 0x96AB -#define GL_SHADING_RATE_4X2_PIXELS_EXT 0x96AC -#define GL_SHADING_RATE_4X2_PIXELS_QCOM 0x96AC -#define GL_SHADING_RATE_4X4_PIXELS_EXT 0x96AE -#define GL_SHADING_RATE_4X4_PIXELS_QCOM 0x96AE -#define GL_SHADING_RATE_ATTACHMENT_EXT 0x96D1 -#define GL_SHADING_RATE_EXT 0x96D0 -#define GL_SHORT 0x1402 -#define GL_SKIP_DECODE_EXT 0x8A4A -#define GL_SOFTLIGHT_KHR 0x929C -#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT 0x91A9 -#define GL_SR8_EXT 0x8FBD -#define GL_SRC1_ALPHA_EXT 0x8589 -#define GL_SRC1_COLOR_EXT 0x88F9 -#define GL_SRC_ALPHA 0x0302 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_SRC_ALPHA_SATURATE_EXT 0x0308 -#define GL_SRC_COLOR 0x0300 -#define GL_SRG8_EXT 0x8FBE -#define GL_SRGB8_ALPHA8_EXT 0x8C43 -#define GL_SRGB_ALPHA_EXT 0x8C42 -#define GL_SRGB_EXT 0x8C40 -#define GL_STACK_OVERFLOW_KHR 0x0503 -#define GL_STACK_UNDERFLOW_KHR 0x0504 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_STENCIL_BITS 0x0D57 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_EXT 0x1802 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_INDEX1_OES 0x8D46 -#define GL_STENCIL_INDEX4_OES 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX8_OES 0x8D48 -#define GL_STENCIL_INDEX_OES 0x1901 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_STREAM_DRAW 0x88E0 -#define GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004 -#define GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008 -#define GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001 -#define GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040 -#define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 -#define GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010 -#define GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020 -#define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 -#define GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 -#define GL_SUBGROUP_SIZE_KHR 0x9532 -#define GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534 -#define GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_SURFACE_COMPRESSION_EXT 0x96C0 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_10BPC_EXT 0x96CD -#define GL_SURFACE_COMPRESSION_FIXED_RATE_11BPC_EXT 0x96CE -#define GL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT 0x96CF -#define GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT 0x96C4 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_2BPC_EXT 0x96C5 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_3BPC_EXT 0x96C6 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_4BPC_EXT 0x96C7 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_5BPC_EXT 0x96C8 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_6BPC_EXT 0x96C9 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_7BPC_EXT 0x96CA -#define GL_SURFACE_COMPRESSION_FIXED_RATE_8BPC_EXT 0x96CB -#define GL_SURFACE_COMPRESSION_FIXED_RATE_9BPC_EXT 0x96CC -#define GL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT 0x96C2 -#define GL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT 0x96C1 -#define GL_TESS_CONTROL_OUTPUT_VERTICES_EXT 0x8E75 -#define GL_TESS_CONTROL_OUTPUT_VERTICES_OES 0x8E75 -#define GL_TESS_CONTROL_SHADER_BIT_EXT 0x00000008 -#define GL_TESS_CONTROL_SHADER_BIT_OES 0x00000008 -#define GL_TESS_CONTROL_SHADER_EXT 0x8E88 -#define GL_TESS_CONTROL_SHADER_OES 0x8E88 -#define GL_TESS_EVALUATION_SHADER_BIT_EXT 0x00000010 -#define GL_TESS_EVALUATION_SHADER_BIT_OES 0x00000010 -#define GL_TESS_EVALUATION_SHADER_EXT 0x8E87 -#define GL_TESS_EVALUATION_SHADER_OES 0x8E87 -#define GL_TESS_GEN_MODE_EXT 0x8E76 -#define GL_TESS_GEN_MODE_OES 0x8E76 -#define GL_TESS_GEN_POINT_MODE_EXT 0x8E79 -#define GL_TESS_GEN_POINT_MODE_OES 0x8E79 -#define GL_TESS_GEN_SPACING_EXT 0x8E77 -#define GL_TESS_GEN_SPACING_OES 0x8E77 -#define GL_TESS_GEN_VERTEX_ORDER_EXT 0x8E78 -#define GL_TESS_GEN_VERTEX_ORDER_OES 0x8E78 -#define GL_TEXTURE 0x1702 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES 0x9102 -#define GL_TEXTURE_3D 0x806F -#define GL_TEXTURE_3D_OES 0x806F -#define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69 -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES 0x9105 -#define GL_TEXTURE_BINDING_3D_OES 0x806A -#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C -#define GL_TEXTURE_BINDING_BUFFER_OES 0x8C2C -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT 0x900A -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES 0x900A -#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 -#define GL_TEXTURE_BORDER_COLOR_EXT 0x1004 -#define GL_TEXTURE_BORDER_COLOR_OES 0x1004 -#define GL_TEXTURE_BUFFER_BINDING_EXT 0x8C2A -#define GL_TEXTURE_BUFFER_BINDING_OES 0x8C2A -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES 0x8C2D -#define GL_TEXTURE_BUFFER_EXT 0x8C2A -#define GL_TEXTURE_BUFFER_OES 0x8C2A -#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT 0x919F -#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES 0x919F -#define GL_TEXTURE_BUFFER_OFFSET_EXT 0x919D -#define GL_TEXTURE_BUFFER_OFFSET_OES 0x919D -#define GL_TEXTURE_BUFFER_SIZE_EXT 0x919E -#define GL_TEXTURE_BUFFER_SIZE_OES 0x919E -#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D -#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_CUBE_MAP_ARRAY_EXT 0x9009 -#define GL_TEXTURE_CUBE_MAP_ARRAY_OES 0x9009 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 -#define GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT 0x8FBF -#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F -#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE -#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_PROTECTED_EXT 0x8BFA -#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 -#define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 -#define GL_TEXTURE_SPARSE_EXT 0x91A6 -#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define GL_TEXTURE_TILING_EXT 0x9580 -#define GL_TEXTURE_VIEW_MIN_LAYER_EXT 0x82DD -#define GL_TEXTURE_VIEW_MIN_LAYER_OES 0x82DD -#define GL_TEXTURE_VIEW_MIN_LEVEL_EXT 0x82DB -#define GL_TEXTURE_VIEW_MIN_LEVEL_OES 0x82DB -#define GL_TEXTURE_VIEW_NUM_LAYERS_EXT 0x82DE -#define GL_TEXTURE_VIEW_NUM_LAYERS_OES 0x82DE -#define GL_TEXTURE_VIEW_NUM_LEVELS_EXT 0x82DC -#define GL_TEXTURE_VIEW_NUM_LEVELS_OES 0x82DC -#define GL_TEXTURE_WRAP_R_OES 0x8072 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_TILING_TYPES_EXT 0x9583 -#define GL_TIMESTAMP_EXT 0x8E28 -#define GL_TIME_ELAPSED_EXT 0x88BF -#define GL_TRANSFORM_FEEDBACK 0x8E22 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLES_ADJACENCY_EXT 0x000C -#define GL_TRIANGLES_ADJACENCY_OES 0x000C -#define GL_TRIANGLE_FAN 0x0006 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D -#define GL_TRIANGLE_STRIP_ADJACENCY_OES 0x000D -#define GL_TRUE 1 -#define GL_UNDEFINED_VERTEX_EXT 0x8260 -#define GL_UNDEFINED_VERTEX_OES 0x8260 -#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 -#define GL_UNKNOWN_CONTEXT_RESET_KHR 0x8255 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2 -#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4 -#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_UNSIGNED_INT 0x1405 -#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 -#define GL_UNSIGNED_INT_24_8_OES 0x84FA -#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 -#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 -#define GL_UNSIGNED_INT_IMAGE_BUFFER_OES 0x9067 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x906A -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910D -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_OES 0x8DD8 -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900F -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900F -#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_UPPER_LEFT_EXT 0x8CA2 -#define GL_UUID_SIZE_EXT 16 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_VENDOR 0x1F00 -#define GL_VERSION 0x1F02 -#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 -#define GL_VERTEX_ARRAY_KHR 0x8074 -#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT 0x88FE -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_VERTEX_SHADER_BIT_EXT 0x00000001 -#define GL_VIEWPORT 0x0BA2 -#define GL_VIEWPORT_BOUNDS_RANGE_OES 0x825D -#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES 0x825F -#define GL_VIEWPORT_SUBPIXEL_BITS_OES 0x825C -#define GL_VIRTUAL_PAGE_SIZE_INDEX_EXT 0x91A7 -#define GL_VIRTUAL_PAGE_SIZE_X_EXT 0x9195 -#define GL_VIRTUAL_PAGE_SIZE_Y_EXT 0x9196 -#define GL_VIRTUAL_PAGE_SIZE_Z_EXT 0x9197 -#define GL_WEIGHTED_AVERAGE_ARB 0x9367 -#define GL_WEIGHTED_AVERAGE_EXT 0x9367 -#define GL_WINDOW_RECTANGLE_EXT 0x8F12 -#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 -#define GL_WRITE_ONLY_OES 0x88B9 -#define GL_ZERO 0 -#define GL_ZERO_TO_ONE 0x935F -#define GL_ZERO_TO_ONE_EXT 0x935F - - -#ifndef __khrplatform_h_ -#define __khrplatform_h_ - -/* -** Copyright (c) 2008-2018 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Khronos platform-specific types and definitions. - * - * The master copy of khrplatform.h is maintained in the Khronos EGL - * Registry repository at https://github.com/KhronosGroup/EGL-Registry - * The last semantic modification to khrplatform.h was at commit ID: - * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 - * - * Adopters may modify this file to suit their platform. Adopters are - * encouraged to submit platform specific modifications to the Khronos - * group so that they can be included in future versions of this file. - * Please submit changes by filing pull requests or issues on - * the EGL Registry repository linked above. - * - * - * See the Implementer's Guidelines for information about where this file - * should be located on your system and for more details of its use: - * http://www.khronos.org/registry/implementers_guide.pdf - * - * This file should be included as - * #include - * by Khronos client API header files that use its types and defines. - * - * The types in khrplatform.h should only be used to define API-specific types. - * - * Types defined in khrplatform.h: - * khronos_int8_t signed 8 bit - * khronos_uint8_t unsigned 8 bit - * khronos_int16_t signed 16 bit - * khronos_uint16_t unsigned 16 bit - * khronos_int32_t signed 32 bit - * khronos_uint32_t unsigned 32 bit - * khronos_int64_t signed 64 bit - * khronos_uint64_t unsigned 64 bit - * khronos_intptr_t signed same number of bits as a pointer - * khronos_uintptr_t unsigned same number of bits as a pointer - * khronos_ssize_t signed size - * khronos_usize_t unsigned size - * khronos_float_t signed 32 bit floating point - * khronos_time_ns_t unsigned 64 bit time in nanoseconds - * khronos_utime_nanoseconds_t unsigned time interval or absolute time in - * nanoseconds - * khronos_stime_nanoseconds_t signed time interval in nanoseconds - * khronos_boolean_enum_t enumerated boolean type. This should - * only be used as a base type when a client API's boolean type is - * an enum. Client APIs which use an integer or other type for - * booleans cannot use this as the base type for their boolean. - * - * Tokens defined in khrplatform.h: - * - * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. - * - * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. - * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. - * - * Calling convention macros defined in this file: - * KHRONOS_APICALL - * KHRONOS_GLAD_API_PTR - * KHRONOS_APIATTRIBUTES - * - * These may be used in function prototypes as: - * - * KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname( - * int arg1, - * int arg2) KHRONOS_APIATTRIBUTES; - */ - -#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) -# define KHRONOS_STATIC 1 -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APICALL - *------------------------------------------------------------------------- - * This precedes the return type of the function in the function prototype. - */ -#if defined(KHRONOS_STATIC) - /* If the preprocessor constant KHRONOS_STATIC is defined, make the - * header compatible with static linking. */ -# define KHRONOS_APICALL -#elif defined(_WIN32) -# define KHRONOS_APICALL __declspec(dllimport) -#elif defined (__SYMBIAN32__) -# define KHRONOS_APICALL IMPORT_C -#elif defined(__ANDROID__) -# define KHRONOS_APICALL __attribute__((visibility("default"))) -#else -# define KHRONOS_APICALL -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_GLAD_API_PTR - *------------------------------------------------------------------------- - * This follows the return type of the function and precedes the function - * name in the function prototype. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ -# define KHRONOS_GLAD_API_PTR __stdcall -#else -# define KHRONOS_GLAD_API_PTR -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIATTRIBUTES - *------------------------------------------------------------------------- - * This follows the closing parenthesis of the function prototype arguments. - */ -#if defined (__ARMCC_2__) -#define KHRONOS_APIATTRIBUTES __softfp -#else -#define KHRONOS_APIATTRIBUTES -#endif - -/*------------------------------------------------------------------------- - * basic type definitions - *-----------------------------------------------------------------------*/ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) - - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 -/* - * To support platform where unsigned long cannot be used interchangeably with - * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. - * Ideally, we could just use (u)intptr_t everywhere, but this could result in - * ABI breakage if khronos_uintptr_t is changed from unsigned long to - * unsigned long long or similar (this results in different C++ name mangling). - * To avoid changes for existing platforms, we restrict usage of intptr_t to - * platforms where the size of a pointer is larger than the size of long. - */ -#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) -#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ -#define KHRONOS_USE_INTPTR_T -#endif -#endif - -#elif defined(__VMS ) || defined(__sgi) - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) - -/* - * Win32 - */ -typedef __int32 khronos_int32_t; -typedef unsigned __int32 khronos_uint32_t; -typedef __int64 khronos_int64_t; -typedef unsigned __int64 khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__sun__) || defined(__digital__) - -/* - * Sun or Digital - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#if defined(__arch64__) || defined(_LP64) -typedef long int khronos_int64_t; -typedef unsigned long int khronos_uint64_t; -#else -typedef long long int khronos_int64_t; -typedef unsigned long long int khronos_uint64_t; -#endif /* __arch64__ */ -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif 0 - -/* - * Hypothetical platform with no float or int64 support - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#define KHRONOS_SUPPORT_INT64 0 -#define KHRONOS_SUPPORT_FLOAT 0 - -#else - -/* - * Generic fallback - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#endif - - -/* - * Types that are (so far) the same on all platforms - */ -typedef signed char khronos_int8_t; -typedef unsigned char khronos_uint8_t; -typedef signed short int khronos_int16_t; -typedef unsigned short int khronos_uint16_t; - -/* - * Types that differ between LLP64 and LP64 architectures - in LLP64, - * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears - * to be the only LLP64 architecture in current use. - */ -#ifdef KHRONOS_USE_INTPTR_T -typedef intptr_t khronos_intptr_t; -typedef uintptr_t khronos_uintptr_t; -#elif defined(_WIN64) -typedef signed long long int khronos_intptr_t; -typedef unsigned long long int khronos_uintptr_t; -#else -typedef signed long int khronos_intptr_t; -typedef unsigned long int khronos_uintptr_t; -#endif - -#if defined(_WIN64) -typedef signed long long int khronos_ssize_t; -typedef unsigned long long int khronos_usize_t; -#else -typedef signed long int khronos_ssize_t; -typedef unsigned long int khronos_usize_t; -#endif - -#if KHRONOS_SUPPORT_FLOAT -/* - * Float type - */ -typedef float khronos_float_t; -#endif - -#if KHRONOS_SUPPORT_INT64 -/* Time types - * - * These types can be used to represent a time interval in nanoseconds or - * an absolute Unadjusted System Time. Unadjusted System Time is the number - * of nanoseconds since some arbitrary system event (e.g. since the last - * time the system booted). The Unadjusted System Time is an unsigned - * 64 bit value that wraps back to 0 every 584 years. Time intervals - * may be either signed or unsigned. - */ -typedef khronos_uint64_t khronos_utime_nanoseconds_t; -typedef khronos_int64_t khronos_stime_nanoseconds_t; -#endif - -/* - * Dummy value used to pad enum types to 32 bits. - */ -#ifndef KHRONOS_MAX_ENUM -#define KHRONOS_MAX_ENUM 0x7FFFFFFF -#endif - -/* - * Enumerated boolean type - * - * Values other than zero should be considered to be true. Therefore - * comparisons should not be made against KHRONOS_TRUE. - */ -typedef enum { - KHRONOS_FALSE = 0, - KHRONOS_TRUE = 1, - KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM -} khronos_boolean_enum_t; - -#endif /* __khrplatform_h_ */ -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef khronos_int8_t GLbyte; -typedef khronos_uint8_t GLubyte; -typedef khronos_int16_t GLshort; -typedef khronos_uint16_t GLushort; -typedef int GLint; -typedef unsigned int GLuint; -typedef khronos_int32_t GLclampx; -typedef int GLsizei; -typedef khronos_float_t GLfloat; -typedef khronos_float_t GLclampf; -typedef double GLdouble; -typedef double GLclampd; -typedef void *GLeglClientBufferEXT; -typedef void *GLeglImageOES; -typedef char GLchar; -typedef char GLcharARB; -#ifdef __APPLE__ -typedef void *GLhandleARB; -#else -typedef unsigned int GLhandleARB; -#endif -typedef khronos_uint16_t GLhalf; -typedef khronos_uint16_t GLhalfARB; -typedef khronos_int32_t GLfixed; -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_intptr_t GLintptr; -#else -typedef khronos_intptr_t GLintptr; -#endif -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_intptr_t GLintptrARB; -#else -typedef khronos_intptr_t GLintptrARB; -#endif -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_ssize_t GLsizeiptr; -#else -typedef khronos_ssize_t GLsizeiptr; -#endif -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) -typedef khronos_ssize_t GLsizeiptrARB; -#else -typedef khronos_ssize_t GLsizeiptrARB; -#endif -typedef khronos_int64_t GLint64; -typedef khronos_int64_t GLint64EXT; -typedef khronos_uint64_t GLuint64; -typedef khronos_uint64_t GLuint64EXT; -typedef struct __GLsync *GLsync; -struct _cl_context; -struct _cl_event; -typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); -typedef unsigned short GLhalfNV; -typedef GLintptr GLvdpauSurfaceNV; -typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); - - -#define GL_ES_VERSION_2_0 1 -GLAD_API_CALL int GLAD_GL_ES_VERSION_2_0; -#define GL_EXT_EGL_image_array 1 -GLAD_API_CALL int GLAD_GL_EXT_EGL_image_array; -#define GL_EXT_EGL_image_storage 1 -GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage; -#define GL_EXT_EGL_image_storage_compression 1 -GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage_compression; -#define GL_EXT_YUV_target 1 -GLAD_API_CALL int GLAD_GL_EXT_YUV_target; -#define GL_EXT_base_instance 1 -GLAD_API_CALL int GLAD_GL_EXT_base_instance; -#define GL_EXT_blend_func_extended 1 -GLAD_API_CALL int GLAD_GL_EXT_blend_func_extended; -#define GL_EXT_blend_minmax 1 -GLAD_API_CALL int GLAD_GL_EXT_blend_minmax; -#define GL_EXT_buffer_storage 1 -GLAD_API_CALL int GLAD_GL_EXT_buffer_storage; -#define GL_EXT_clear_texture 1 -GLAD_API_CALL int GLAD_GL_EXT_clear_texture; -#define GL_EXT_clip_control 1 -GLAD_API_CALL int GLAD_GL_EXT_clip_control; -#define GL_EXT_clip_cull_distance 1 -GLAD_API_CALL int GLAD_GL_EXT_clip_cull_distance; -#define GL_EXT_color_buffer_float 1 -GLAD_API_CALL int GLAD_GL_EXT_color_buffer_float; -#define GL_EXT_color_buffer_half_float 1 -GLAD_API_CALL int GLAD_GL_EXT_color_buffer_half_float; -#define GL_EXT_conservative_depth 1 -GLAD_API_CALL int GLAD_GL_EXT_conservative_depth; -#define GL_EXT_copy_image 1 -GLAD_API_CALL int GLAD_GL_EXT_copy_image; -#define GL_EXT_debug_label 1 -GLAD_API_CALL int GLAD_GL_EXT_debug_label; -#define GL_EXT_debug_marker 1 -GLAD_API_CALL int GLAD_GL_EXT_debug_marker; -#define GL_EXT_depth_clamp 1 -GLAD_API_CALL int GLAD_GL_EXT_depth_clamp; -#define GL_EXT_discard_framebuffer 1 -GLAD_API_CALL int GLAD_GL_EXT_discard_framebuffer; -#define GL_EXT_disjoint_timer_query 1 -GLAD_API_CALL int GLAD_GL_EXT_disjoint_timer_query; -#define GL_EXT_draw_buffers 1 -GLAD_API_CALL int GLAD_GL_EXT_draw_buffers; -#define GL_EXT_draw_buffers_indexed 1 -GLAD_API_CALL int GLAD_GL_EXT_draw_buffers_indexed; -#define GL_EXT_draw_elements_base_vertex 1 -GLAD_API_CALL int GLAD_GL_EXT_draw_elements_base_vertex; -#define GL_EXT_draw_instanced 1 -GLAD_API_CALL int GLAD_GL_EXT_draw_instanced; -#define GL_EXT_draw_transform_feedback 1 -GLAD_API_CALL int GLAD_GL_EXT_draw_transform_feedback; -#define GL_EXT_external_buffer 1 -GLAD_API_CALL int GLAD_GL_EXT_external_buffer; -#define GL_EXT_float_blend 1 -GLAD_API_CALL int GLAD_GL_EXT_float_blend; -#define GL_EXT_fragment_shading_rate 1 -GLAD_API_CALL int GLAD_GL_EXT_fragment_shading_rate; -#define GL_EXT_geometry_point_size 1 -GLAD_API_CALL int GLAD_GL_EXT_geometry_point_size; -#define GL_EXT_geometry_shader 1 -GLAD_API_CALL int GLAD_GL_EXT_geometry_shader; -#define GL_EXT_gpu_shader5 1 -GLAD_API_CALL int GLAD_GL_EXT_gpu_shader5; -#define GL_EXT_instanced_arrays 1 -GLAD_API_CALL int GLAD_GL_EXT_instanced_arrays; -#define GL_EXT_map_buffer_range 1 -GLAD_API_CALL int GLAD_GL_EXT_map_buffer_range; -#define GL_EXT_memory_object 1 -GLAD_API_CALL int GLAD_GL_EXT_memory_object; -#define GL_EXT_memory_object_fd 1 -GLAD_API_CALL int GLAD_GL_EXT_memory_object_fd; -#define GL_EXT_memory_object_win32 1 -GLAD_API_CALL int GLAD_GL_EXT_memory_object_win32; -#define GL_EXT_multi_draw_arrays 1 -GLAD_API_CALL int GLAD_GL_EXT_multi_draw_arrays; -#define GL_EXT_multi_draw_indirect 1 -GLAD_API_CALL int GLAD_GL_EXT_multi_draw_indirect; -#define GL_EXT_multisampled_compatibility 1 -GLAD_API_CALL int GLAD_GL_EXT_multisampled_compatibility; -#define GL_EXT_multisampled_render_to_texture 1 -GLAD_API_CALL int GLAD_GL_EXT_multisampled_render_to_texture; -#define GL_EXT_multisampled_render_to_texture2 1 -GLAD_API_CALL int GLAD_GL_EXT_multisampled_render_to_texture2; -#define GL_EXT_multiview_draw_buffers 1 -GLAD_API_CALL int GLAD_GL_EXT_multiview_draw_buffers; -#define GL_EXT_multiview_tessellation_geometry_shader 1 -GLAD_API_CALL int GLAD_GL_EXT_multiview_tessellation_geometry_shader; -#define GL_EXT_multiview_texture_multisample 1 -GLAD_API_CALL int GLAD_GL_EXT_multiview_texture_multisample; -#define GL_EXT_multiview_timer_query 1 -GLAD_API_CALL int GLAD_GL_EXT_multiview_timer_query; -#define GL_EXT_occlusion_query_boolean 1 -GLAD_API_CALL int GLAD_GL_EXT_occlusion_query_boolean; -#define GL_EXT_polygon_offset_clamp 1 -GLAD_API_CALL int GLAD_GL_EXT_polygon_offset_clamp; -#define GL_EXT_post_depth_coverage 1 -GLAD_API_CALL int GLAD_GL_EXT_post_depth_coverage; -#define GL_EXT_primitive_bounding_box 1 -GLAD_API_CALL int GLAD_GL_EXT_primitive_bounding_box; -#define GL_EXT_protected_textures 1 -GLAD_API_CALL int GLAD_GL_EXT_protected_textures; -#define GL_EXT_pvrtc_sRGB 1 -GLAD_API_CALL int GLAD_GL_EXT_pvrtc_sRGB; -#define GL_EXT_raster_multisample 1 -GLAD_API_CALL int GLAD_GL_EXT_raster_multisample; -#define GL_EXT_read_format_bgra 1 -GLAD_API_CALL int GLAD_GL_EXT_read_format_bgra; -#define GL_EXT_render_snorm 1 -GLAD_API_CALL int GLAD_GL_EXT_render_snorm; -#define GL_EXT_robustness 1 -GLAD_API_CALL int GLAD_GL_EXT_robustness; -#define GL_EXT_sRGB 1 -GLAD_API_CALL int GLAD_GL_EXT_sRGB; -#define GL_EXT_sRGB_write_control 1 -GLAD_API_CALL int GLAD_GL_EXT_sRGB_write_control; -#define GL_EXT_semaphore 1 -GLAD_API_CALL int GLAD_GL_EXT_semaphore; -#define GL_EXT_semaphore_fd 1 -GLAD_API_CALL int GLAD_GL_EXT_semaphore_fd; -#define GL_EXT_semaphore_win32 1 -GLAD_API_CALL int GLAD_GL_EXT_semaphore_win32; -#define GL_EXT_separate_depth_stencil 1 -GLAD_API_CALL int GLAD_GL_EXT_separate_depth_stencil; -#define GL_EXT_separate_shader_objects 1 -GLAD_API_CALL int GLAD_GL_EXT_separate_shader_objects; -#define GL_EXT_shader_framebuffer_fetch 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_framebuffer_fetch; -#define GL_EXT_shader_framebuffer_fetch_non_coherent 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent; -#define GL_EXT_shader_group_vote 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_group_vote; -#define GL_EXT_shader_implicit_conversions 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_implicit_conversions; -#define GL_EXT_shader_integer_mix 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_integer_mix; -#define GL_EXT_shader_io_blocks 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_io_blocks; -#define GL_EXT_shader_non_constant_global_initializers 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_non_constant_global_initializers; -#define GL_EXT_shader_pixel_local_storage 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_pixel_local_storage; -#define GL_EXT_shader_pixel_local_storage2 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_pixel_local_storage2; -#define GL_EXT_shader_samples_identical 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_samples_identical; -#define GL_EXT_shader_texture_lod 1 -GLAD_API_CALL int GLAD_GL_EXT_shader_texture_lod; -#define GL_EXT_shadow_samplers 1 -GLAD_API_CALL int GLAD_GL_EXT_shadow_samplers; -#define GL_EXT_sparse_texture 1 -GLAD_API_CALL int GLAD_GL_EXT_sparse_texture; -#define GL_EXT_sparse_texture2 1 -GLAD_API_CALL int GLAD_GL_EXT_sparse_texture2; -#define GL_EXT_tessellation_point_size 1 -GLAD_API_CALL int GLAD_GL_EXT_tessellation_point_size; -#define GL_EXT_tessellation_shader 1 -GLAD_API_CALL int GLAD_GL_EXT_tessellation_shader; -#define GL_EXT_texture_border_clamp 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_border_clamp; -#define GL_EXT_texture_buffer 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_buffer; -#define GL_EXT_texture_compression_astc_decode_mode 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_astc_decode_mode; -#define GL_EXT_texture_compression_bptc 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_bptc; -#define GL_EXT_texture_compression_dxt1 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_dxt1; -#define GL_EXT_texture_compression_rgtc 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_rgtc; -#define GL_EXT_texture_compression_s3tc 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; -#define GL_EXT_texture_compression_s3tc_srgb 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc_srgb; -#define GL_EXT_texture_cube_map_array 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_cube_map_array; -#define GL_EXT_texture_filter_anisotropic 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic; -#define GL_EXT_texture_filter_minmax 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_filter_minmax; -#define GL_EXT_texture_format_BGRA8888 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_format_BGRA8888; -#define GL_EXT_texture_format_sRGB_override 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_format_sRGB_override; -#define GL_EXT_texture_mirror_clamp_to_edge 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_mirror_clamp_to_edge; -#define GL_EXT_texture_norm16 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_norm16; -#define GL_EXT_texture_query_lod 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_query_lod; -#define GL_EXT_texture_rg 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_rg; -#define GL_EXT_texture_sRGB_R8 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_R8; -#define GL_EXT_texture_sRGB_RG8 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_RG8; -#define GL_EXT_texture_sRGB_decode 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_decode; -#define GL_EXT_texture_shadow_lod 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_shadow_lod; -#define GL_EXT_texture_storage 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_storage; -#define GL_EXT_texture_storage_compression 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_storage_compression; -#define GL_EXT_texture_type_2_10_10_10_REV 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_type_2_10_10_10_REV; -#define GL_EXT_texture_view 1 -GLAD_API_CALL int GLAD_GL_EXT_texture_view; -#define GL_EXT_unpack_subimage 1 -GLAD_API_CALL int GLAD_GL_EXT_unpack_subimage; -#define GL_EXT_win32_keyed_mutex 1 -GLAD_API_CALL int GLAD_GL_EXT_win32_keyed_mutex; -#define GL_EXT_window_rectangles 1 -GLAD_API_CALL int GLAD_GL_EXT_window_rectangles; -#define GL_KHR_blend_equation_advanced 1 -GLAD_API_CALL int GLAD_GL_KHR_blend_equation_advanced; -#define GL_KHR_blend_equation_advanced_coherent 1 -GLAD_API_CALL int GLAD_GL_KHR_blend_equation_advanced_coherent; -#define GL_KHR_context_flush_control 1 -GLAD_API_CALL int GLAD_GL_KHR_context_flush_control; -#define GL_KHR_debug 1 -GLAD_API_CALL int GLAD_GL_KHR_debug; -#define GL_KHR_no_error 1 -GLAD_API_CALL int GLAD_GL_KHR_no_error; -#define GL_KHR_parallel_shader_compile 1 -GLAD_API_CALL int GLAD_GL_KHR_parallel_shader_compile; -#define GL_KHR_robust_buffer_access_behavior 1 -GLAD_API_CALL int GLAD_GL_KHR_robust_buffer_access_behavior; -#define GL_KHR_robustness 1 -GLAD_API_CALL int GLAD_GL_KHR_robustness; -#define GL_KHR_shader_subgroup 1 -GLAD_API_CALL int GLAD_GL_KHR_shader_subgroup; -#define GL_KHR_texture_compression_astc_hdr 1 -GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_hdr; -#define GL_KHR_texture_compression_astc_ldr 1 -GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_ldr; -#define GL_KHR_texture_compression_astc_sliced_3d 1 -GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_sliced_3d; -#define GL_OES_EGL_image 1 -GLAD_API_CALL int GLAD_GL_OES_EGL_image; -#define GL_OES_EGL_image_external 1 -GLAD_API_CALL int GLAD_GL_OES_EGL_image_external; -#define GL_OES_EGL_image_external_essl3 1 -GLAD_API_CALL int GLAD_GL_OES_EGL_image_external_essl3; -#define GL_OES_compressed_ETC1_RGB8_sub_texture 1 -GLAD_API_CALL int GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture; -#define GL_OES_compressed_ETC1_RGB8_texture 1 -GLAD_API_CALL int GLAD_GL_OES_compressed_ETC1_RGB8_texture; -#define GL_OES_compressed_paletted_texture 1 -GLAD_API_CALL int GLAD_GL_OES_compressed_paletted_texture; -#define GL_OES_copy_image 1 -GLAD_API_CALL int GLAD_GL_OES_copy_image; -#define GL_OES_depth24 1 -GLAD_API_CALL int GLAD_GL_OES_depth24; -#define GL_OES_depth32 1 -GLAD_API_CALL int GLAD_GL_OES_depth32; -#define GL_OES_depth_texture 1 -GLAD_API_CALL int GLAD_GL_OES_depth_texture; -#define GL_OES_draw_buffers_indexed 1 -GLAD_API_CALL int GLAD_GL_OES_draw_buffers_indexed; -#define GL_OES_draw_elements_base_vertex 1 -GLAD_API_CALL int GLAD_GL_OES_draw_elements_base_vertex; -#define GL_OES_element_index_uint 1 -GLAD_API_CALL int GLAD_GL_OES_element_index_uint; -#define GL_OES_fbo_render_mipmap 1 -GLAD_API_CALL int GLAD_GL_OES_fbo_render_mipmap; -#define GL_OES_fragment_precision_high 1 -GLAD_API_CALL int GLAD_GL_OES_fragment_precision_high; -#define GL_OES_geometry_point_size 1 -GLAD_API_CALL int GLAD_GL_OES_geometry_point_size; -#define GL_OES_geometry_shader 1 -GLAD_API_CALL int GLAD_GL_OES_geometry_shader; -#define GL_OES_get_program_binary 1 -GLAD_API_CALL int GLAD_GL_OES_get_program_binary; -#define GL_OES_gpu_shader5 1 -GLAD_API_CALL int GLAD_GL_OES_gpu_shader5; -#define GL_OES_mapbuffer 1 -GLAD_API_CALL int GLAD_GL_OES_mapbuffer; -#define GL_OES_packed_depth_stencil 1 -GLAD_API_CALL int GLAD_GL_OES_packed_depth_stencil; -#define GL_OES_primitive_bounding_box 1 -GLAD_API_CALL int GLAD_GL_OES_primitive_bounding_box; -#define GL_OES_required_internalformat 1 -GLAD_API_CALL int GLAD_GL_OES_required_internalformat; -#define GL_OES_rgb8_rgba8 1 -GLAD_API_CALL int GLAD_GL_OES_rgb8_rgba8; -#define GL_OES_sample_shading 1 -GLAD_API_CALL int GLAD_GL_OES_sample_shading; -#define GL_OES_sample_variables 1 -GLAD_API_CALL int GLAD_GL_OES_sample_variables; -#define GL_OES_shader_image_atomic 1 -GLAD_API_CALL int GLAD_GL_OES_shader_image_atomic; -#define GL_OES_shader_io_blocks 1 -GLAD_API_CALL int GLAD_GL_OES_shader_io_blocks; -#define GL_OES_shader_multisample_interpolation 1 -GLAD_API_CALL int GLAD_GL_OES_shader_multisample_interpolation; -#define GL_OES_standard_derivatives 1 -GLAD_API_CALL int GLAD_GL_OES_standard_derivatives; -#define GL_OES_stencil1 1 -GLAD_API_CALL int GLAD_GL_OES_stencil1; -#define GL_OES_stencil4 1 -GLAD_API_CALL int GLAD_GL_OES_stencil4; -#define GL_OES_surfaceless_context 1 -GLAD_API_CALL int GLAD_GL_OES_surfaceless_context; -#define GL_OES_tessellation_point_size 1 -GLAD_API_CALL int GLAD_GL_OES_tessellation_point_size; -#define GL_OES_tessellation_shader 1 -GLAD_API_CALL int GLAD_GL_OES_tessellation_shader; -#define GL_OES_texture_3D 1 -GLAD_API_CALL int GLAD_GL_OES_texture_3D; -#define GL_OES_texture_border_clamp 1 -GLAD_API_CALL int GLAD_GL_OES_texture_border_clamp; -#define GL_OES_texture_buffer 1 -GLAD_API_CALL int GLAD_GL_OES_texture_buffer; -#define GL_OES_texture_compression_astc 1 -GLAD_API_CALL int GLAD_GL_OES_texture_compression_astc; -#define GL_OES_texture_cube_map_array 1 -GLAD_API_CALL int GLAD_GL_OES_texture_cube_map_array; -#define GL_OES_texture_float 1 -GLAD_API_CALL int GLAD_GL_OES_texture_float; -#define GL_OES_texture_float_linear 1 -GLAD_API_CALL int GLAD_GL_OES_texture_float_linear; -#define GL_OES_texture_half_float 1 -GLAD_API_CALL int GLAD_GL_OES_texture_half_float; -#define GL_OES_texture_half_float_linear 1 -GLAD_API_CALL int GLAD_GL_OES_texture_half_float_linear; -#define GL_OES_texture_npot 1 -GLAD_API_CALL int GLAD_GL_OES_texture_npot; -#define GL_OES_texture_stencil8 1 -GLAD_API_CALL int GLAD_GL_OES_texture_stencil8; -#define GL_OES_texture_storage_multisample_2d_array 1 -GLAD_API_CALL int GLAD_GL_OES_texture_storage_multisample_2d_array; -#define GL_OES_texture_view 1 -GLAD_API_CALL int GLAD_GL_OES_texture_view; -#define GL_OES_vertex_array_object 1 -GLAD_API_CALL int GLAD_GL_OES_vertex_array_object; -#define GL_OES_vertex_half_float 1 -GLAD_API_CALL int GLAD_GL_OES_vertex_half_float; -#define GL_OES_vertex_type_10_10_10_2 1 -GLAD_API_CALL int GLAD_GL_OES_vertex_type_10_10_10_2; -#define GL_OES_viewport_array 1 -GLAD_API_CALL int GLAD_GL_OES_viewport_array; - - -typedef GLboolean (GLAD_API_PTR *PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC)(GLuint memory, GLuint64 key, GLuint timeout); -typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMEXTPROC)(GLuint pipeline, GLuint program); -typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); -typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); -typedef void (GLAD_API_PTR *PFNGLBEGINQUERYEXTPROC)(GLenum target, GLuint id); -typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONEXTPROC)(GLuint program, GLuint color, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); -typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEEXTPROC)(GLuint pipeline); -typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); -typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYOESPROC)(GLuint array); -typedef void (GLAD_API_PTR *PFNGLBLENDBARRIERKHRPROC)(void); -typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIEXTPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIOESPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIEXTPROC)(GLuint buf, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIOESPROC)(GLuint buf, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIEXTPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIOESPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIEXTPROC)(GLuint buf, GLenum src, GLenum dst); -typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIOESPROC)(GLuint buf, GLenum src, GLenum dst); -typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); -typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEEXTPROC)(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags); -typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEEXTERNALEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); -typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEMEMEXTPROC)(GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); -typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); -typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d); -typedef void (GLAD_API_PTR *PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC)(GLsizei offset, GLsizei n, const GLuint * values); -typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); -typedef void (GLAD_API_PTR *PFNGLCLEARTEXIMAGEEXTPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLEARTEXSUBIMAGEEXTPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * data); -typedef void (GLAD_API_PTR *PFNGLCLIPCONTROLEXTPROC)(GLenum origin, GLenum depth); -typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -typedef void (GLAD_API_PTR *PFNGLCOLORMASKIEXTPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (GLAD_API_PTR *PFNGLCOLORMASKIOESPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DOESPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); -typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAEXTPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAOESPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLCREATEMEMORYOBJECTSEXTPROC)(GLsizei n, GLuint * memoryObjects); -typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); -typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); -typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVEXTPROC)(GLenum type, GLsizei count, const GLchar *const* strings); -typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void * userParam); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); -typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); -typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); -typedef void (GLAD_API_PTR *PFNGLDELETEMEMORYOBJECTSEXTPROC)(GLsizei n, const GLuint * memoryObjects); -typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESEXTPROC)(GLsizei n, const GLuint * pipelines); -typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESEXTPROC)(GLsizei n, const GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLDELETESEMAPHORESEXTPROC)(GLsizei n, const GLuint * semaphores); -typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); -typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSOESPROC)(GLsizei n, const GLuint * arrays); -typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); -typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYFVOESPROC)(GLuint first, GLsizei count, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDFOESPROC)(GLuint index, GLfloat n, GLfloat f); -typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); -typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); -typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); -typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISABLEIEXTPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISABLEIOESPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLDISCARDFRAMEBUFFEREXTPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDEXTPROC)(GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSEXTPROC)(GLsizei n, const GLenum * bufs); -typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSINDEXEDEXTPROC)(GLint n, const GLenum * location, const GLint * indices); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXOESPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLuint baseinstance); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); -typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKEXTPROC)(GLenum mode, GLuint id); -typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC)(GLenum mode, GLuint id, GLsizei instancecount); -typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)(GLenum target, GLeglImageOES image); -typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC)(GLenum target, GLeglImageOES image, const GLint * attrib_list); -typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target, GLeglImageOES image); -typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC)(GLuint texture, GLeglImageOES image, const GLint * attrib_list); -typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); -typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); -typedef void (GLAD_API_PTR *PFNGLENABLEIEXTPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLENABLEIOESPROC)(GLenum target, GLuint index); -typedef void (GLAD_API_PTR *PFNGLENDQUERYEXTPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); -typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); -typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC)(void); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target, GLsizei size); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERSHADINGRATEEXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint baseLayer, GLsizei numLayers, GLsizei texelWidth, GLsizei texelHeight); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DOESPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREEXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREOESPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); -typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); -typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); -typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESEXTPROC)(GLsizei n, GLuint * pipelines); -typedef void (GLAD_API_PTR *PFNGLGENQUERIESEXTPROC)(GLsizei n, GLuint * ids); -typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); -typedef void (GLAD_API_PTR *PFNGLGENSEMAPHORESEXTPROC)(GLsizei n, GLuint * semaphores); -typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); -typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSOESPROC)(GLsizei n, GLuint * arrays); -typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); -typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVOESPROC)(GLenum target, GLenum pname, void ** params); -typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); -typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); -typedef void (GLAD_API_PTR *PFNGLGETFLOATI_VOESPROC)(GLenum target, GLuint index, GLfloat * data); -typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); -typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXEXTPROC)(GLuint program, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETFRAGMENTSHADINGRATESEXTPROC)(GLsizei samples, GLsizei maxCount, GLsizei * count, GLenum * shadingRates); -typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); -typedef GLsizei (GLAD_API_PTR *PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target); -typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSEXTPROC)(void); -typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void); -typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VEXTPROC)(GLenum pname, GLint64 * data); -typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VEXTPROC)(GLenum target, GLuint index, GLint * data); -typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); -typedef void (GLAD_API_PTR *PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint memoryObject, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELEXTPROC)(GLenum type, GLuint object, GLsizei bufSize, GLsizei * length, GLchar * label); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); -typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); -typedef void (GLAD_API_PTR *PFNGLGETPOINTERVKHRPROC)(GLenum pname, void ** params); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYOESPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVEXTPROC)(GLuint pipeline, GLenum pname, GLint * params); -typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program, GLenum programInterface, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VEXTPROC)(GLuint id, GLenum pname, GLint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVEXTPROC)(GLuint id, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VEXTPROC)(GLuint id, GLenum pname, GLuint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVEXTPROC)(GLuint id, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETQUERYIVEXTPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVEXTPROC)(GLuint sampler, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVEXTPROC)(GLuint sampler, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC)(GLuint semaphore, GLenum pname, GLuint64 * params); -typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); -typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision); -typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); -typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); -typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVEXTPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVEXTPROC)(GLenum target, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); -typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEI_VEXTPROC)(GLenum target, GLuint index, GLubyte * data); -typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEVEXTPROC)(GLenum pname, GLubyte * data); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVEXTPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVEXTPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); -typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint * params); -typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); -typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYFDEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, GLint fd); -typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, void * handle); -typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYWIN32NAMEEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, const void * name); -typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREFDEXTPROC)(GLuint semaphore, GLenum handleType, GLint fd); -typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC)(GLuint semaphore, GLenum handleType, void * handle); -typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC)(GLuint semaphore, GLenum handleType, const void * name); -typedef void (GLAD_API_PTR *PFNGLINSERTEVENTMARKEREXTPROC)(GLsizei length, const GLchar * marker); -typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); -typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIEXTPROC)(GLenum target, GLuint index); -typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIOESPROC)(GLenum target, GLuint index); -typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISMEMORYOBJECTEXTPROC)(GLuint memoryObject); -typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); -typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEEXTPROC)(GLuint pipeline); -typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYEXTPROC)(GLuint id); -typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); -typedef GLboolean (GLAD_API_PTR *PFNGLISSEMAPHOREEXTPROC)(GLuint semaphore); -typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); -typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); -typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYOESPROC)(GLuint array); -typedef void (GLAD_API_PTR *PFNGLLABELOBJECTEXTPROC)(GLenum type, GLuint object, GLsizei length, const GLchar * label); -typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); -typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); -typedef void * (GLAD_API_PTR *PFNGLMAPBUFFEROESPROC)(GLenum target, GLenum access); -typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (GLAD_API_PTR *PFNGLMAXSHADERCOMPILERTHREADSKHRPROC)(GLuint count); -typedef void (GLAD_API_PTR *PFNGLMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint memoryObject, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGOESPROC)(GLfloat value); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSEXTPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC)(GLenum mode, const void * indirect, GLsizei drawcount, GLsizei stride); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSEXTPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei primcount); -typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC)(GLenum mode, GLenum type, const void * indirect, GLsizei drawcount, GLsizei stride); -typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); -typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC)(GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); -typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei length, const GLchar * label); -typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIEXTPROC)(GLenum pname, GLint value); -typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIOESPROC)(GLenum pname, GLint value); -typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); -typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETCLAMPEXTPROC)(GLfloat factor, GLfloat units, GLfloat clamp); -typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPKHRPROC)(void); -typedef void (GLAD_API_PTR *PFNGLPOPGROUPMARKEREXTPROC)(void); -typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXEXTPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); -typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXOESPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); -typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYOESPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLint length); -typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIEXTPROC)(GLuint program, GLenum pname, GLint value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FEXTPROC)(GLuint program, GLint location, GLfloat v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IEXTPROC)(GLuint program, GLint location, GLint v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIEXTPROC)(GLuint program, GLint location, GLuint v0); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); -typedef void (GLAD_API_PTR *PFNGLPUSHGROUPMARKEREXTPROC)(GLsizei length, const GLchar * marker); -typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTEREXTPROC)(GLuint id, GLenum target); -typedef void (GLAD_API_PTR *PFNGLRASTERSAMPLESEXTPROC)(GLuint samples, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLREADBUFFERINDEXEDEXTPROC)(GLenum src, GLint index); -typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); -typedef void (GLAD_API_PTR *PFNGLREADNPIXELSEXTPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); -typedef void (GLAD_API_PTR *PFNGLREADNPIXELSKHRPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); -typedef GLboolean (GLAD_API_PTR *PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC)(GLuint memory, GLuint64 key); -typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void); -typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVEXTPROC)(GLuint sampler, GLenum pname, const GLint * param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, const GLint * param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVEXTPROC)(GLuint sampler, GLenum pname, const GLuint * param); -typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, const GLuint * param); -typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVOESPROC)(GLuint first, GLsizei count, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDOESPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVOESPROC)(GLuint index, const GLint * v); -typedef void (GLAD_API_PTR *PFNGLSEMAPHOREPARAMETERUI64VEXTPROC)(GLuint semaphore, GLenum pname, const GLuint64 * params); -typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length); -typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); -typedef void (GLAD_API_PTR *PFNGLSHADINGRATECOMBINEROPSEXTPROC)(GLenum combinerOp0, GLenum combinerOp1); -typedef void (GLAD_API_PTR *PFNGLSHADINGRATEEXTPROC)(GLenum rate); -typedef void (GLAD_API_PTR *PFNGLSIGNALSEMAPHOREEXTPROC)(GLuint semaphore, GLuint numBufferBarriers, const GLuint * buffers, GLuint numTextureBarriers, const GLuint * textures, const GLenum * dstLayouts); -typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); -typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); -typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (GLAD_API_PTR *PFNGLTEXBUFFEREXTPROC)(GLenum target, GLenum internalformat, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLTEXBUFFEROESPROC)(GLenum target, GLenum internalformat, GLuint buffer); -typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEEXTPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEOESPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DOESPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXPAGECOMMITMENTEXTPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVEXTPROC)(GLenum target, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVEXTPROC)(GLenum target, GLenum pname, const GLuint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, const GLuint * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); -typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE1DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEATTRIBS2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, const GLint * attrib_list); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEATTRIBS3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, const GLint * attrib_list); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE1DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DEXTPROC)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DEXTPROC)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); -typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWEXTPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWOESPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); -typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); -typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); -typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFEROESPROC)(GLenum target); -typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESEXTPROC)(GLuint pipeline, GLbitfield stages, GLuint program); -typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); -typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEEXTPROC)(GLuint pipeline); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISOREXTPROC)(GLuint index, GLuint divisor); -typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVOESPROC)(GLuint first, GLsizei count, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFOESPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVOESPROC)(GLuint index, const GLfloat * v); -typedef void (GLAD_API_PTR *PFNGLWAITSEMAPHOREEXTPROC)(GLuint semaphore, GLuint numBufferBarriers, const GLuint * buffers, GLuint numTextureBarriers, const GLuint * textures, const GLenum * srcLayouts); -typedef void (GLAD_API_PTR *PFNGLWINDOWRECTANGLESEXTPROC)(GLenum mode, GLsizei count, const GLint * box); - -GLAD_API_CALL PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT; -#define glAcquireKeyedMutexWin32EXT glad_glAcquireKeyedMutexWin32EXT -GLAD_API_CALL PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT; -#define glActiveShaderProgramEXT glad_glActiveShaderProgramEXT -GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; -#define glActiveTexture glad_glActiveTexture -GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; -#define glAttachShader glad_glAttachShader -GLAD_API_CALL PFNGLBEGINQUERYEXTPROC glad_glBeginQueryEXT; -#define glBeginQueryEXT glad_glBeginQueryEXT -GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; -#define glBindAttribLocation glad_glBindAttribLocation -GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; -#define glBindBuffer glad_glBindBuffer -GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT; -#define glBindFragDataLocationEXT glad_glBindFragDataLocationEXT -GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC glad_glBindFragDataLocationIndexedEXT; -#define glBindFragDataLocationIndexedEXT glad_glBindFragDataLocationIndexedEXT -GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; -#define glBindFramebuffer glad_glBindFramebuffer -GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT; -#define glBindProgramPipelineEXT glad_glBindProgramPipelineEXT -GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; -#define glBindRenderbuffer glad_glBindRenderbuffer -GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; -#define glBindTexture glad_glBindTexture -GLAD_API_CALL PFNGLBINDVERTEXARRAYOESPROC glad_glBindVertexArrayOES; -#define glBindVertexArrayOES glad_glBindVertexArrayOES -GLAD_API_CALL PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR; -#define glBlendBarrierKHR glad_glBlendBarrierKHR -GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; -#define glBlendColor glad_glBlendColor -GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; -#define glBlendEquation glad_glBlendEquation -GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; -#define glBlendEquationSeparate glad_glBlendEquationSeparate -GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIEXTPROC glad_glBlendEquationSeparateiEXT; -#define glBlendEquationSeparateiEXT glad_glBlendEquationSeparateiEXT -GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIOESPROC glad_glBlendEquationSeparateiOES; -#define glBlendEquationSeparateiOES glad_glBlendEquationSeparateiOES -GLAD_API_CALL PFNGLBLENDEQUATIONIEXTPROC glad_glBlendEquationiEXT; -#define glBlendEquationiEXT glad_glBlendEquationiEXT -GLAD_API_CALL PFNGLBLENDEQUATIONIOESPROC glad_glBlendEquationiOES; -#define glBlendEquationiOES glad_glBlendEquationiOES -GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; -#define glBlendFunc glad_glBlendFunc -GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; -#define glBlendFuncSeparate glad_glBlendFuncSeparate -GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIEXTPROC glad_glBlendFuncSeparateiEXT; -#define glBlendFuncSeparateiEXT glad_glBlendFuncSeparateiEXT -GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIOESPROC glad_glBlendFuncSeparateiOES; -#define glBlendFuncSeparateiOES glad_glBlendFuncSeparateiOES -GLAD_API_CALL PFNGLBLENDFUNCIEXTPROC glad_glBlendFunciEXT; -#define glBlendFunciEXT glad_glBlendFunciEXT -GLAD_API_CALL PFNGLBLENDFUNCIOESPROC glad_glBlendFunciOES; -#define glBlendFunciOES glad_glBlendFunciOES -GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; -#define glBufferData glad_glBufferData -GLAD_API_CALL PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT; -#define glBufferStorageEXT glad_glBufferStorageEXT -GLAD_API_CALL PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT; -#define glBufferStorageExternalEXT glad_glBufferStorageExternalEXT -GLAD_API_CALL PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT; -#define glBufferStorageMemEXT glad_glBufferStorageMemEXT -GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; -#define glBufferSubData glad_glBufferSubData -GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; -#define glCheckFramebufferStatus glad_glCheckFramebufferStatus -GLAD_API_CALL PFNGLCLEARPROC glad_glClear; -#define glClear glad_glClear -GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; -#define glClearColor glad_glClearColor -GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf; -#define glClearDepthf glad_glClearDepthf -GLAD_API_CALL PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC glad_glClearPixelLocalStorageuiEXT; -#define glClearPixelLocalStorageuiEXT glad_glClearPixelLocalStorageuiEXT -GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; -#define glClearStencil glad_glClearStencil -GLAD_API_CALL PFNGLCLEARTEXIMAGEEXTPROC glad_glClearTexImageEXT; -#define glClearTexImageEXT glad_glClearTexImageEXT -GLAD_API_CALL PFNGLCLEARTEXSUBIMAGEEXTPROC glad_glClearTexSubImageEXT; -#define glClearTexSubImageEXT glad_glClearTexSubImageEXT -GLAD_API_CALL PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT; -#define glClipControlEXT glad_glClipControlEXT -GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; -#define glColorMask glad_glColorMask -GLAD_API_CALL PFNGLCOLORMASKIEXTPROC glad_glColorMaskiEXT; -#define glColorMaskiEXT glad_glColorMaskiEXT -GLAD_API_CALL PFNGLCOLORMASKIOESPROC glad_glColorMaskiOES; -#define glColorMaskiOES glad_glColorMaskiOES -GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; -#define glCompileShader glad_glCompileShader -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; -#define glCompressedTexImage2D glad_glCompressedTexImage2D -GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DOESPROC glad_glCompressedTexImage3DOES; -#define glCompressedTexImage3DOES glad_glCompressedTexImage3DOES -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; -#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D -GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glad_glCompressedTexSubImage3DOES; -#define glCompressedTexSubImage3DOES glad_glCompressedTexSubImage3DOES -GLAD_API_CALL PFNGLCOPYIMAGESUBDATAEXTPROC glad_glCopyImageSubDataEXT; -#define glCopyImageSubDataEXT glad_glCopyImageSubDataEXT -GLAD_API_CALL PFNGLCOPYIMAGESUBDATAOESPROC glad_glCopyImageSubDataOES; -#define glCopyImageSubDataOES glad_glCopyImageSubDataOES -GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; -#define glCopyTexImage2D glad_glCopyTexImage2D -GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; -#define glCopyTexSubImage2D glad_glCopyTexSubImage2D -GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DOESPROC glad_glCopyTexSubImage3DOES; -#define glCopyTexSubImage3DOES glad_glCopyTexSubImage3DOES -GLAD_API_CALL PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT; -#define glCreateMemoryObjectsEXT glad_glCreateMemoryObjectsEXT -GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; -#define glCreateProgram glad_glCreateProgram -GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; -#define glCreateShader glad_glCreateShader -GLAD_API_CALL PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT; -#define glCreateShaderProgramvEXT glad_glCreateShaderProgramvEXT -GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; -#define glCullFace glad_glCullFace -GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; -#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR -GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; -#define glDebugMessageControlKHR glad_glDebugMessageControlKHR -GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; -#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR -GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; -#define glDeleteBuffers glad_glDeleteBuffers -GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; -#define glDeleteFramebuffers glad_glDeleteFramebuffers -GLAD_API_CALL PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT; -#define glDeleteMemoryObjectsEXT glad_glDeleteMemoryObjectsEXT -GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; -#define glDeleteProgram glad_glDeleteProgram -GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT; -#define glDeleteProgramPipelinesEXT glad_glDeleteProgramPipelinesEXT -GLAD_API_CALL PFNGLDELETEQUERIESEXTPROC glad_glDeleteQueriesEXT; -#define glDeleteQueriesEXT glad_glDeleteQueriesEXT -GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; -#define glDeleteRenderbuffers glad_glDeleteRenderbuffers -GLAD_API_CALL PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT; -#define glDeleteSemaphoresEXT glad_glDeleteSemaphoresEXT -GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; -#define glDeleteShader glad_glDeleteShader -GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; -#define glDeleteTextures glad_glDeleteTextures -GLAD_API_CALL PFNGLDELETEVERTEXARRAYSOESPROC glad_glDeleteVertexArraysOES; -#define glDeleteVertexArraysOES glad_glDeleteVertexArraysOES -GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; -#define glDepthFunc glad_glDepthFunc -GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; -#define glDepthMask glad_glDepthMask -GLAD_API_CALL PFNGLDEPTHRANGEARRAYFVOESPROC glad_glDepthRangeArrayfvOES; -#define glDepthRangeArrayfvOES glad_glDepthRangeArrayfvOES -GLAD_API_CALL PFNGLDEPTHRANGEINDEXEDFOESPROC glad_glDepthRangeIndexedfOES; -#define glDepthRangeIndexedfOES glad_glDepthRangeIndexedfOES -GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef; -#define glDepthRangef glad_glDepthRangef -GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; -#define glDetachShader glad_glDetachShader -GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; -#define glDisable glad_glDisable -GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; -#define glDisableVertexAttribArray glad_glDisableVertexAttribArray -GLAD_API_CALL PFNGLDISABLEIEXTPROC glad_glDisableiEXT; -#define glDisableiEXT glad_glDisableiEXT -GLAD_API_CALL PFNGLDISABLEIOESPROC glad_glDisableiOES; -#define glDisableiOES glad_glDisableiOES -GLAD_API_CALL PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT; -#define glDiscardFramebufferEXT glad_glDiscardFramebufferEXT -GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; -#define glDrawArrays glad_glDrawArrays -GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawArraysInstancedBaseInstanceEXT; -#define glDrawArraysInstancedBaseInstanceEXT glad_glDrawArraysInstancedBaseInstanceEXT -GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT; -#define glDrawArraysInstancedEXT glad_glDrawArraysInstancedEXT -GLAD_API_CALL PFNGLDRAWBUFFERSEXTPROC glad_glDrawBuffersEXT; -#define glDrawBuffersEXT glad_glDrawBuffersEXT -GLAD_API_CALL PFNGLDRAWBUFFERSINDEXEDEXTPROC glad_glDrawBuffersIndexedEXT; -#define glDrawBuffersIndexedEXT glad_glDrawBuffersIndexedEXT -GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; -#define glDrawElements glad_glDrawElements -GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXEXTPROC glad_glDrawElementsBaseVertexEXT; -#define glDrawElementsBaseVertexEXT glad_glDrawElementsBaseVertexEXT -GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXOESPROC glad_glDrawElementsBaseVertexOES; -#define glDrawElementsBaseVertexOES glad_glDrawElementsBaseVertexOES -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseInstanceEXT; -#define glDrawElementsInstancedBaseInstanceEXT glad_glDrawElementsInstancedBaseInstanceEXT -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT; -#define glDrawElementsInstancedBaseVertexBaseInstanceEXT glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC glad_glDrawElementsInstancedBaseVertexEXT; -#define glDrawElementsInstancedBaseVertexEXT glad_glDrawElementsInstancedBaseVertexEXT -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC glad_glDrawElementsInstancedBaseVertexOES; -#define glDrawElementsInstancedBaseVertexOES glad_glDrawElementsInstancedBaseVertexOES -GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT; -#define glDrawElementsInstancedEXT glad_glDrawElementsInstancedEXT -GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC glad_glDrawRangeElementsBaseVertexEXT; -#define glDrawRangeElementsBaseVertexEXT glad_glDrawRangeElementsBaseVertexEXT -GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC glad_glDrawRangeElementsBaseVertexOES; -#define glDrawRangeElementsBaseVertexOES glad_glDrawRangeElementsBaseVertexOES -GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKEXTPROC glad_glDrawTransformFeedbackEXT; -#define glDrawTransformFeedbackEXT glad_glDrawTransformFeedbackEXT -GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC glad_glDrawTransformFeedbackInstancedEXT; -#define glDrawTransformFeedbackInstancedEXT glad_glDrawTransformFeedbackInstancedEXT -GLAD_API_CALL PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glad_glEGLImageTargetRenderbufferStorageOES; -#define glEGLImageTargetRenderbufferStorageOES glad_glEGLImageTargetRenderbufferStorageOES -GLAD_API_CALL PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT; -#define glEGLImageTargetTexStorageEXT glad_glEGLImageTargetTexStorageEXT -GLAD_API_CALL PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES; -#define glEGLImageTargetTexture2DOES glad_glEGLImageTargetTexture2DOES -GLAD_API_CALL PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT; -#define glEGLImageTargetTextureStorageEXT glad_glEGLImageTargetTextureStorageEXT -GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; -#define glEnable glad_glEnable -GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; -#define glEnableVertexAttribArray glad_glEnableVertexAttribArray -GLAD_API_CALL PFNGLENABLEIEXTPROC glad_glEnableiEXT; -#define glEnableiEXT glad_glEnableiEXT -GLAD_API_CALL PFNGLENABLEIOESPROC glad_glEnableiOES; -#define glEnableiOES glad_glEnableiOES -GLAD_API_CALL PFNGLENDQUERYEXTPROC glad_glEndQueryEXT; -#define glEndQueryEXT glad_glEndQueryEXT -GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; -#define glFinish glad_glFinish -GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; -#define glFlush glad_glFlush -GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC glad_glFlushMappedBufferRangeEXT; -#define glFlushMappedBufferRangeEXT glad_glFlushMappedBufferRangeEXT -GLAD_API_CALL PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT; -#define glFramebufferFetchBarrierEXT glad_glFramebufferFetchBarrierEXT -GLAD_API_CALL PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glFramebufferPixelLocalStorageSizeEXT; -#define glFramebufferPixelLocalStorageSizeEXT glad_glFramebufferPixelLocalStorageSizeEXT -GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; -#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer -GLAD_API_CALL PFNGLFRAMEBUFFERSHADINGRATEEXTPROC glad_glFramebufferShadingRateEXT; -#define glFramebufferShadingRateEXT glad_glFramebufferShadingRateEXT -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; -#define glFramebufferTexture2D glad_glFramebufferTexture2D -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glad_glFramebufferTexture2DMultisampleEXT; -#define glFramebufferTexture2DMultisampleEXT glad_glFramebufferTexture2DMultisampleEXT -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DOESPROC glad_glFramebufferTexture3DOES; -#define glFramebufferTexture3DOES glad_glFramebufferTexture3DOES -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT; -#define glFramebufferTextureEXT glad_glFramebufferTextureEXT -GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREOESPROC glad_glFramebufferTextureOES; -#define glFramebufferTextureOES glad_glFramebufferTextureOES -GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; -#define glFrontFace glad_glFrontFace -GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; -#define glGenBuffers glad_glGenBuffers -GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; -#define glGenFramebuffers glad_glGenFramebuffers -GLAD_API_CALL PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT; -#define glGenProgramPipelinesEXT glad_glGenProgramPipelinesEXT -GLAD_API_CALL PFNGLGENQUERIESEXTPROC glad_glGenQueriesEXT; -#define glGenQueriesEXT glad_glGenQueriesEXT -GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; -#define glGenRenderbuffers glad_glGenRenderbuffers -GLAD_API_CALL PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT; -#define glGenSemaphoresEXT glad_glGenSemaphoresEXT -GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; -#define glGenTextures glad_glGenTextures -GLAD_API_CALL PFNGLGENVERTEXARRAYSOESPROC glad_glGenVertexArraysOES; -#define glGenVertexArraysOES glad_glGenVertexArraysOES -GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; -#define glGenerateMipmap glad_glGenerateMipmap -GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; -#define glGetActiveAttrib glad_glGetActiveAttrib -GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; -#define glGetActiveUniform glad_glGetActiveUniform -GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; -#define glGetAttachedShaders glad_glGetAttachedShaders -GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; -#define glGetAttribLocation glad_glGetAttribLocation -GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; -#define glGetBooleanv glad_glGetBooleanv -GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; -#define glGetBufferParameteriv glad_glGetBufferParameteriv -GLAD_API_CALL PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES; -#define glGetBufferPointervOES glad_glGetBufferPointervOES -GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; -#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR -GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; -#define glGetError glad_glGetError -GLAD_API_CALL PFNGLGETFLOATI_VOESPROC glad_glGetFloati_vOES; -#define glGetFloati_vOES glad_glGetFloati_vOES -GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; -#define glGetFloatv glad_glGetFloatv -GLAD_API_CALL PFNGLGETFRAGDATAINDEXEXTPROC glad_glGetFragDataIndexEXT; -#define glGetFragDataIndexEXT glad_glGetFragDataIndexEXT -GLAD_API_CALL PFNGLGETFRAGMENTSHADINGRATESEXTPROC glad_glGetFragmentShadingRatesEXT; -#define glGetFragmentShadingRatesEXT glad_glGetFragmentShadingRatesEXT -GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; -#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv -GLAD_API_CALL PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glGetFramebufferPixelLocalStorageSizeEXT; -#define glGetFramebufferPixelLocalStorageSizeEXT glad_glGetFramebufferPixelLocalStorageSizeEXT -GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSEXTPROC glad_glGetGraphicsResetStatusEXT; -#define glGetGraphicsResetStatusEXT glad_glGetGraphicsResetStatusEXT -GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR; -#define glGetGraphicsResetStatusKHR glad_glGetGraphicsResetStatusKHR -GLAD_API_CALL PFNGLGETINTEGER64VEXTPROC glad_glGetInteger64vEXT; -#define glGetInteger64vEXT glad_glGetInteger64vEXT -GLAD_API_CALL PFNGLGETINTEGERI_VEXTPROC glad_glGetIntegeri_vEXT; -#define glGetIntegeri_vEXT glad_glGetIntegeri_vEXT -GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; -#define glGetIntegerv glad_glGetIntegerv -GLAD_API_CALL PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT; -#define glGetMemoryObjectParameterivEXT glad_glGetMemoryObjectParameterivEXT -GLAD_API_CALL PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT; -#define glGetObjectLabelEXT glad_glGetObjectLabelEXT -GLAD_API_CALL PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; -#define glGetObjectLabelKHR glad_glGetObjectLabelKHR -GLAD_API_CALL PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; -#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR -GLAD_API_CALL PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; -#define glGetPointervKHR glad_glGetPointervKHR -GLAD_API_CALL PFNGLGETPROGRAMBINARYOESPROC glad_glGetProgramBinaryOES; -#define glGetProgramBinaryOES glad_glGetProgramBinaryOES -GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; -#define glGetProgramInfoLog glad_glGetProgramInfoLog -GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT; -#define glGetProgramPipelineInfoLogEXT glad_glGetProgramPipelineInfoLogEXT -GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT; -#define glGetProgramPipelineivEXT glad_glGetProgramPipelineivEXT -GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC glad_glGetProgramResourceLocationIndexEXT; -#define glGetProgramResourceLocationIndexEXT glad_glGetProgramResourceLocationIndexEXT -GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; -#define glGetProgramiv glad_glGetProgramiv -GLAD_API_CALL PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT; -#define glGetQueryObjecti64vEXT glad_glGetQueryObjecti64vEXT -GLAD_API_CALL PFNGLGETQUERYOBJECTIVEXTPROC glad_glGetQueryObjectivEXT; -#define glGetQueryObjectivEXT glad_glGetQueryObjectivEXT -GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT; -#define glGetQueryObjectui64vEXT glad_glGetQueryObjectui64vEXT -GLAD_API_CALL PFNGLGETQUERYOBJECTUIVEXTPROC glad_glGetQueryObjectuivEXT; -#define glGetQueryObjectuivEXT glad_glGetQueryObjectuivEXT -GLAD_API_CALL PFNGLGETQUERYIVEXTPROC glad_glGetQueryivEXT; -#define glGetQueryivEXT glad_glGetQueryivEXT -GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; -#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVEXTPROC glad_glGetSamplerParameterIivEXT; -#define glGetSamplerParameterIivEXT glad_glGetSamplerParameterIivEXT -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES; -#define glGetSamplerParameterIivOES glad_glGetSamplerParameterIivOES -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVEXTPROC glad_glGetSamplerParameterIuivEXT; -#define glGetSamplerParameterIuivEXT glad_glGetSamplerParameterIuivEXT -GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES; -#define glGetSamplerParameterIuivOES glad_glGetSamplerParameterIuivOES -GLAD_API_CALL PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT; -#define glGetSemaphoreParameterui64vEXT glad_glGetSemaphoreParameterui64vEXT -GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; -#define glGetShaderInfoLog glad_glGetShaderInfoLog -GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; -#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat -GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; -#define glGetShaderSource glad_glGetShaderSource -GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; -#define glGetShaderiv glad_glGetShaderiv -GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; -#define glGetString glad_glGetString -GLAD_API_CALL PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT; -#define glGetTexParameterIivEXT glad_glGetTexParameterIivEXT -GLAD_API_CALL PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES; -#define glGetTexParameterIivOES glad_glGetTexParameterIivOES -GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT; -#define glGetTexParameterIuivEXT glad_glGetTexParameterIuivEXT -GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES; -#define glGetTexParameterIuivOES glad_glGetTexParameterIuivOES -GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; -#define glGetTexParameterfv glad_glGetTexParameterfv -GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; -#define glGetTexParameteriv glad_glGetTexParameteriv -GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; -#define glGetUniformLocation glad_glGetUniformLocation -GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; -#define glGetUniformfv glad_glGetUniformfv -GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; -#define glGetUniformiv glad_glGetUniformiv -GLAD_API_CALL PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT; -#define glGetUnsignedBytei_vEXT glad_glGetUnsignedBytei_vEXT -GLAD_API_CALL PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT; -#define glGetUnsignedBytevEXT glad_glGetUnsignedBytevEXT -GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; -#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv -GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; -#define glGetVertexAttribfv glad_glGetVertexAttribfv -GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; -#define glGetVertexAttribiv glad_glGetVertexAttribiv -GLAD_API_CALL PFNGLGETNUNIFORMFVEXTPROC glad_glGetnUniformfvEXT; -#define glGetnUniformfvEXT glad_glGetnUniformfvEXT -GLAD_API_CALL PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR; -#define glGetnUniformfvKHR glad_glGetnUniformfvKHR -GLAD_API_CALL PFNGLGETNUNIFORMIVEXTPROC glad_glGetnUniformivEXT; -#define glGetnUniformivEXT glad_glGetnUniformivEXT -GLAD_API_CALL PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR; -#define glGetnUniformivKHR glad_glGetnUniformivKHR -GLAD_API_CALL PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR; -#define glGetnUniformuivKHR glad_glGetnUniformuivKHR -GLAD_API_CALL PFNGLHINTPROC glad_glHint; -#define glHint glad_glHint -GLAD_API_CALL PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT; -#define glImportMemoryFdEXT glad_glImportMemoryFdEXT -GLAD_API_CALL PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT; -#define glImportMemoryWin32HandleEXT glad_glImportMemoryWin32HandleEXT -GLAD_API_CALL PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT; -#define glImportMemoryWin32NameEXT glad_glImportMemoryWin32NameEXT -GLAD_API_CALL PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT; -#define glImportSemaphoreFdEXT glad_glImportSemaphoreFdEXT -GLAD_API_CALL PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT; -#define glImportSemaphoreWin32HandleEXT glad_glImportSemaphoreWin32HandleEXT -GLAD_API_CALL PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT; -#define glImportSemaphoreWin32NameEXT glad_glImportSemaphoreWin32NameEXT -GLAD_API_CALL PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; -#define glInsertEventMarkerEXT glad_glInsertEventMarkerEXT -GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; -#define glIsBuffer glad_glIsBuffer -GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; -#define glIsEnabled glad_glIsEnabled -GLAD_API_CALL PFNGLISENABLEDIEXTPROC glad_glIsEnablediEXT; -#define glIsEnablediEXT glad_glIsEnablediEXT -GLAD_API_CALL PFNGLISENABLEDIOESPROC glad_glIsEnablediOES; -#define glIsEnablediOES glad_glIsEnablediOES -GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; -#define glIsFramebuffer glad_glIsFramebuffer -GLAD_API_CALL PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT; -#define glIsMemoryObjectEXT glad_glIsMemoryObjectEXT -GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; -#define glIsProgram glad_glIsProgram -GLAD_API_CALL PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT; -#define glIsProgramPipelineEXT glad_glIsProgramPipelineEXT -GLAD_API_CALL PFNGLISQUERYEXTPROC glad_glIsQueryEXT; -#define glIsQueryEXT glad_glIsQueryEXT -GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; -#define glIsRenderbuffer glad_glIsRenderbuffer -GLAD_API_CALL PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT; -#define glIsSemaphoreEXT glad_glIsSemaphoreEXT -GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; -#define glIsShader glad_glIsShader -GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; -#define glIsTexture glad_glIsTexture -GLAD_API_CALL PFNGLISVERTEXARRAYOESPROC glad_glIsVertexArrayOES; -#define glIsVertexArrayOES glad_glIsVertexArrayOES -GLAD_API_CALL PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT; -#define glLabelObjectEXT glad_glLabelObjectEXT -GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; -#define glLineWidth glad_glLineWidth -GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; -#define glLinkProgram glad_glLinkProgram -GLAD_API_CALL PFNGLMAPBUFFEROESPROC glad_glMapBufferOES; -#define glMapBufferOES glad_glMapBufferOES -GLAD_API_CALL PFNGLMAPBUFFERRANGEEXTPROC glad_glMapBufferRangeEXT; -#define glMapBufferRangeEXT glad_glMapBufferRangeEXT -GLAD_API_CALL PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR; -#define glMaxShaderCompilerThreadsKHR glad_glMaxShaderCompilerThreadsKHR -GLAD_API_CALL PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT; -#define glMemoryObjectParameterivEXT glad_glMemoryObjectParameterivEXT -GLAD_API_CALL PFNGLMINSAMPLESHADINGOESPROC glad_glMinSampleShadingOES; -#define glMinSampleShadingOES glad_glMinSampleShadingOES -GLAD_API_CALL PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT; -#define glMultiDrawArraysEXT glad_glMultiDrawArraysEXT -GLAD_API_CALL PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC glad_glMultiDrawArraysIndirectEXT; -#define glMultiDrawArraysIndirectEXT glad_glMultiDrawArraysIndirectEXT -GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC glad_glMultiDrawElementsBaseVertexEXT; -#define glMultiDrawElementsBaseVertexEXT glad_glMultiDrawElementsBaseVertexEXT -GLAD_API_CALL PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT; -#define glMultiDrawElementsEXT glad_glMultiDrawElementsEXT -GLAD_API_CALL PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC glad_glMultiDrawElementsIndirectEXT; -#define glMultiDrawElementsIndirectEXT glad_glMultiDrawElementsIndirectEXT -GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT; -#define glNamedBufferStorageExternalEXT glad_glNamedBufferStorageExternalEXT -GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT; -#define glNamedBufferStorageMemEXT glad_glNamedBufferStorageMemEXT -GLAD_API_CALL PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; -#define glObjectLabelKHR glad_glObjectLabelKHR -GLAD_API_CALL PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; -#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR -GLAD_API_CALL PFNGLPATCHPARAMETERIEXTPROC glad_glPatchParameteriEXT; -#define glPatchParameteriEXT glad_glPatchParameteriEXT -GLAD_API_CALL PFNGLPATCHPARAMETERIOESPROC glad_glPatchParameteriOES; -#define glPatchParameteriOES glad_glPatchParameteriOES -GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; -#define glPixelStorei glad_glPixelStorei -GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; -#define glPolygonOffset glad_glPolygonOffset -GLAD_API_CALL PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT; -#define glPolygonOffsetClampEXT glad_glPolygonOffsetClampEXT -GLAD_API_CALL PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; -#define glPopDebugGroupKHR glad_glPopDebugGroupKHR -GLAD_API_CALL PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; -#define glPopGroupMarkerEXT glad_glPopGroupMarkerEXT -GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXEXTPROC glad_glPrimitiveBoundingBoxEXT; -#define glPrimitiveBoundingBoxEXT glad_glPrimitiveBoundingBoxEXT -GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXOESPROC glad_glPrimitiveBoundingBoxOES; -#define glPrimitiveBoundingBoxOES glad_glPrimitiveBoundingBoxOES -GLAD_API_CALL PFNGLPROGRAMBINARYOESPROC glad_glProgramBinaryOES; -#define glProgramBinaryOES glad_glProgramBinaryOES -GLAD_API_CALL PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT; -#define glProgramParameteriEXT glad_glProgramParameteriEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT; -#define glProgramUniform1fEXT glad_glProgramUniform1fEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT; -#define glProgramUniform1fvEXT glad_glProgramUniform1fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT; -#define glProgramUniform1iEXT glad_glProgramUniform1iEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT; -#define glProgramUniform1ivEXT glad_glProgramUniform1ivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT; -#define glProgramUniform1uiEXT glad_glProgramUniform1uiEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT; -#define glProgramUniform1uivEXT glad_glProgramUniform1uivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT; -#define glProgramUniform2fEXT glad_glProgramUniform2fEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT; -#define glProgramUniform2fvEXT glad_glProgramUniform2fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT; -#define glProgramUniform2iEXT glad_glProgramUniform2iEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT; -#define glProgramUniform2ivEXT glad_glProgramUniform2ivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT; -#define glProgramUniform2uiEXT glad_glProgramUniform2uiEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT; -#define glProgramUniform2uivEXT glad_glProgramUniform2uivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT; -#define glProgramUniform3fEXT glad_glProgramUniform3fEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT; -#define glProgramUniform3fvEXT glad_glProgramUniform3fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT; -#define glProgramUniform3iEXT glad_glProgramUniform3iEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT; -#define glProgramUniform3ivEXT glad_glProgramUniform3ivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT; -#define glProgramUniform3uiEXT glad_glProgramUniform3uiEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT; -#define glProgramUniform3uivEXT glad_glProgramUniform3uivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT; -#define glProgramUniform4fEXT glad_glProgramUniform4fEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT; -#define glProgramUniform4fvEXT glad_glProgramUniform4fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT; -#define glProgramUniform4iEXT glad_glProgramUniform4iEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT; -#define glProgramUniform4ivEXT glad_glProgramUniform4ivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT; -#define glProgramUniform4uiEXT glad_glProgramUniform4uiEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT; -#define glProgramUniform4uivEXT glad_glProgramUniform4uivEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT; -#define glProgramUniformMatrix2fvEXT glad_glProgramUniformMatrix2fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT; -#define glProgramUniformMatrix2x3fvEXT glad_glProgramUniformMatrix2x3fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT; -#define glProgramUniformMatrix2x4fvEXT glad_glProgramUniformMatrix2x4fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT; -#define glProgramUniformMatrix3fvEXT glad_glProgramUniformMatrix3fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT; -#define glProgramUniformMatrix3x2fvEXT glad_glProgramUniformMatrix3x2fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT; -#define glProgramUniformMatrix3x4fvEXT glad_glProgramUniformMatrix3x4fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT; -#define glProgramUniformMatrix4fvEXT glad_glProgramUniformMatrix4fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT; -#define glProgramUniformMatrix4x2fvEXT glad_glProgramUniformMatrix4x2fvEXT -GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT; -#define glProgramUniformMatrix4x3fvEXT glad_glProgramUniformMatrix4x3fvEXT -GLAD_API_CALL PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; -#define glPushDebugGroupKHR glad_glPushDebugGroupKHR -GLAD_API_CALL PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; -#define glPushGroupMarkerEXT glad_glPushGroupMarkerEXT -GLAD_API_CALL PFNGLQUERYCOUNTEREXTPROC glad_glQueryCounterEXT; -#define glQueryCounterEXT glad_glQueryCounterEXT -GLAD_API_CALL PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT; -#define glRasterSamplesEXT glad_glRasterSamplesEXT -GLAD_API_CALL PFNGLREADBUFFERINDEXEDEXTPROC glad_glReadBufferIndexedEXT; -#define glReadBufferIndexedEXT glad_glReadBufferIndexedEXT -GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; -#define glReadPixels glad_glReadPixels -GLAD_API_CALL PFNGLREADNPIXELSEXTPROC glad_glReadnPixelsEXT; -#define glReadnPixelsEXT glad_glReadnPixelsEXT -GLAD_API_CALL PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR; -#define glReadnPixelsKHR glad_glReadnPixelsKHR -GLAD_API_CALL PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT; -#define glReleaseKeyedMutexWin32EXT glad_glReleaseKeyedMutexWin32EXT -GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; -#define glReleaseShaderCompiler glad_glReleaseShaderCompiler -GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; -#define glRenderbufferStorage glad_glRenderbufferStorage -GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; -#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT -GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; -#define glSampleCoverage glad_glSampleCoverage -GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVEXTPROC glad_glSamplerParameterIivEXT; -#define glSamplerParameterIivEXT glad_glSamplerParameterIivEXT -GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES; -#define glSamplerParameterIivOES glad_glSamplerParameterIivOES -GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVEXTPROC glad_glSamplerParameterIuivEXT; -#define glSamplerParameterIuivEXT glad_glSamplerParameterIuivEXT -GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES; -#define glSamplerParameterIuivOES glad_glSamplerParameterIuivOES -GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; -#define glScissor glad_glScissor -GLAD_API_CALL PFNGLSCISSORARRAYVOESPROC glad_glScissorArrayvOES; -#define glScissorArrayvOES glad_glScissorArrayvOES -GLAD_API_CALL PFNGLSCISSORINDEXEDOESPROC glad_glScissorIndexedOES; -#define glScissorIndexedOES glad_glScissorIndexedOES -GLAD_API_CALL PFNGLSCISSORINDEXEDVOESPROC glad_glScissorIndexedvOES; -#define glScissorIndexedvOES glad_glScissorIndexedvOES -GLAD_API_CALL PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT; -#define glSemaphoreParameterui64vEXT glad_glSemaphoreParameterui64vEXT -GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary; -#define glShaderBinary glad_glShaderBinary -GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; -#define glShaderSource glad_glShaderSource -GLAD_API_CALL PFNGLSHADINGRATECOMBINEROPSEXTPROC glad_glShadingRateCombinerOpsEXT; -#define glShadingRateCombinerOpsEXT glad_glShadingRateCombinerOpsEXT -GLAD_API_CALL PFNGLSHADINGRATEEXTPROC glad_glShadingRateEXT; -#define glShadingRateEXT glad_glShadingRateEXT -GLAD_API_CALL PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT; -#define glSignalSemaphoreEXT glad_glSignalSemaphoreEXT -GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; -#define glStencilFunc glad_glStencilFunc -GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; -#define glStencilFuncSeparate glad_glStencilFuncSeparate -GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; -#define glStencilMask glad_glStencilMask -GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; -#define glStencilMaskSeparate glad_glStencilMaskSeparate -GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; -#define glStencilOp glad_glStencilOp -GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; -#define glStencilOpSeparate glad_glStencilOpSeparate -GLAD_API_CALL PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT; -#define glTexBufferEXT glad_glTexBufferEXT -GLAD_API_CALL PFNGLTEXBUFFEROESPROC glad_glTexBufferOES; -#define glTexBufferOES glad_glTexBufferOES -GLAD_API_CALL PFNGLTEXBUFFERRANGEEXTPROC glad_glTexBufferRangeEXT; -#define glTexBufferRangeEXT glad_glTexBufferRangeEXT -GLAD_API_CALL PFNGLTEXBUFFERRANGEOESPROC glad_glTexBufferRangeOES; -#define glTexBufferRangeOES glad_glTexBufferRangeOES -GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; -#define glTexImage2D glad_glTexImage2D -GLAD_API_CALL PFNGLTEXIMAGE3DOESPROC glad_glTexImage3DOES; -#define glTexImage3DOES glad_glTexImage3DOES -GLAD_API_CALL PFNGLTEXPAGECOMMITMENTEXTPROC glad_glTexPageCommitmentEXT; -#define glTexPageCommitmentEXT glad_glTexPageCommitmentEXT -GLAD_API_CALL PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT; -#define glTexParameterIivEXT glad_glTexParameterIivEXT -GLAD_API_CALL PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES; -#define glTexParameterIivOES glad_glTexParameterIivOES -GLAD_API_CALL PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT; -#define glTexParameterIuivEXT glad_glTexParameterIuivEXT -GLAD_API_CALL PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES; -#define glTexParameterIuivOES glad_glTexParameterIuivOES -GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; -#define glTexParameterf glad_glTexParameterf -GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; -#define glTexParameterfv glad_glTexParameterfv -GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; -#define glTexParameteri glad_glTexParameteri -GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; -#define glTexParameteriv glad_glTexParameteriv -GLAD_API_CALL PFNGLTEXSTORAGE1DEXTPROC glad_glTexStorage1DEXT; -#define glTexStorage1DEXT glad_glTexStorage1DEXT -GLAD_API_CALL PFNGLTEXSTORAGE2DEXTPROC glad_glTexStorage2DEXT; -#define glTexStorage2DEXT glad_glTexStorage2DEXT -GLAD_API_CALL PFNGLTEXSTORAGE3DEXTPROC glad_glTexStorage3DEXT; -#define glTexStorage3DEXT glad_glTexStorage3DEXT -GLAD_API_CALL PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC glad_glTexStorage3DMultisampleOES; -#define glTexStorage3DMultisampleOES glad_glTexStorage3DMultisampleOES -GLAD_API_CALL PFNGLTEXSTORAGEATTRIBS2DEXTPROC glad_glTexStorageAttribs2DEXT; -#define glTexStorageAttribs2DEXT glad_glTexStorageAttribs2DEXT -GLAD_API_CALL PFNGLTEXSTORAGEATTRIBS3DEXTPROC glad_glTexStorageAttribs3DEXT; -#define glTexStorageAttribs3DEXT glad_glTexStorageAttribs3DEXT -GLAD_API_CALL PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT; -#define glTexStorageMem2DEXT glad_glTexStorageMem2DEXT -GLAD_API_CALL PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT; -#define glTexStorageMem2DMultisampleEXT glad_glTexStorageMem2DMultisampleEXT -GLAD_API_CALL PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT; -#define glTexStorageMem3DEXT glad_glTexStorageMem3DEXT -GLAD_API_CALL PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT; -#define glTexStorageMem3DMultisampleEXT glad_glTexStorageMem3DMultisampleEXT -GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; -#define glTexSubImage2D glad_glTexSubImage2D -GLAD_API_CALL PFNGLTEXSUBIMAGE3DOESPROC glad_glTexSubImage3DOES; -#define glTexSubImage3DOES glad_glTexSubImage3DOES -GLAD_API_CALL PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT; -#define glTextureStorage1DEXT glad_glTextureStorage1DEXT -GLAD_API_CALL PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT; -#define glTextureStorage2DEXT glad_glTextureStorage2DEXT -GLAD_API_CALL PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT; -#define glTextureStorage3DEXT glad_glTextureStorage3DEXT -GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT; -#define glTextureStorageMem2DEXT glad_glTextureStorageMem2DEXT -GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT; -#define glTextureStorageMem2DMultisampleEXT glad_glTextureStorageMem2DMultisampleEXT -GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT; -#define glTextureStorageMem3DEXT glad_glTextureStorageMem3DEXT -GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT; -#define glTextureStorageMem3DMultisampleEXT glad_glTextureStorageMem3DMultisampleEXT -GLAD_API_CALL PFNGLTEXTUREVIEWEXTPROC glad_glTextureViewEXT; -#define glTextureViewEXT glad_glTextureViewEXT -GLAD_API_CALL PFNGLTEXTUREVIEWOESPROC glad_glTextureViewOES; -#define glTextureViewOES glad_glTextureViewOES -GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; -#define glUniform1f glad_glUniform1f -GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; -#define glUniform1fv glad_glUniform1fv -GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; -#define glUniform1i glad_glUniform1i -GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; -#define glUniform1iv glad_glUniform1iv -GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; -#define glUniform2f glad_glUniform2f -GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; -#define glUniform2fv glad_glUniform2fv -GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; -#define glUniform2i glad_glUniform2i -GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; -#define glUniform2iv glad_glUniform2iv -GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; -#define glUniform3f glad_glUniform3f -GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; -#define glUniform3fv glad_glUniform3fv -GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; -#define glUniform3i glad_glUniform3i -GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; -#define glUniform3iv glad_glUniform3iv -GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; -#define glUniform4f glad_glUniform4f -GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; -#define glUniform4fv glad_glUniform4fv -GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; -#define glUniform4i glad_glUniform4i -GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; -#define glUniform4iv glad_glUniform4iv -GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; -#define glUniformMatrix2fv glad_glUniformMatrix2fv -GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; -#define glUniformMatrix3fv glad_glUniformMatrix3fv -GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; -#define glUniformMatrix4fv glad_glUniformMatrix4fv -GLAD_API_CALL PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES; -#define glUnmapBufferOES glad_glUnmapBufferOES -GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; -#define glUseProgram glad_glUseProgram -GLAD_API_CALL PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT; -#define glUseProgramStagesEXT glad_glUseProgramStagesEXT -GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; -#define glValidateProgram glad_glValidateProgram -GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT; -#define glValidateProgramPipelineEXT glad_glValidateProgramPipelineEXT -GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; -#define glVertexAttrib1f glad_glVertexAttrib1f -GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; -#define glVertexAttrib1fv glad_glVertexAttrib1fv -GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; -#define glVertexAttrib2f glad_glVertexAttrib2f -GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; -#define glVertexAttrib2fv glad_glVertexAttrib2fv -GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; -#define glVertexAttrib3f glad_glVertexAttrib3f -GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; -#define glVertexAttrib3fv glad_glVertexAttrib3fv -GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; -#define glVertexAttrib4f glad_glVertexAttrib4f -GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; -#define glVertexAttrib4fv glad_glVertexAttrib4fv -GLAD_API_CALL PFNGLVERTEXATTRIBDIVISOREXTPROC glad_glVertexAttribDivisorEXT; -#define glVertexAttribDivisorEXT glad_glVertexAttribDivisorEXT -GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; -#define glVertexAttribPointer glad_glVertexAttribPointer -GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; -#define glViewport glad_glViewport -GLAD_API_CALL PFNGLVIEWPORTARRAYVOESPROC glad_glViewportArrayvOES; -#define glViewportArrayvOES glad_glViewportArrayvOES -GLAD_API_CALL PFNGLVIEWPORTINDEXEDFOESPROC glad_glViewportIndexedfOES; -#define glViewportIndexedfOES glad_glViewportIndexedfOES -GLAD_API_CALL PFNGLVIEWPORTINDEXEDFVOESPROC glad_glViewportIndexedfvOES; -#define glViewportIndexedfvOES glad_glViewportIndexedfvOES -GLAD_API_CALL PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT; -#define glWaitSemaphoreEXT glad_glWaitSemaphoreEXT -GLAD_API_CALL PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT; -#define glWindowRectanglesEXT glad_glWindowRectanglesEXT - - - - - -GLAD_API_CALL int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr); -GLAD_API_CALL int gladLoadGLES2( GLADloadfunc load); - - - -#ifdef __cplusplus -} -#endif -#endif - -/* Source */ -#ifdef GLAD_GLES2_IMPLEMENTATION -/** - * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 - */ -#include -#include -#include - -#ifndef GLAD_IMPL_UTIL_C_ -#define GLAD_IMPL_UTIL_C_ - -#ifdef _MSC_VER -#define GLAD_IMPL_UTIL_SSCANF sscanf_s -#else -#define GLAD_IMPL_UTIL_SSCANF sscanf -#endif - -#endif /* GLAD_IMPL_UTIL_C_ */ - -#ifdef __cplusplus -extern "C" { -#endif - - - -int GLAD_GL_ES_VERSION_2_0 = 0; -int GLAD_GL_EXT_EGL_image_array = 0; -int GLAD_GL_EXT_EGL_image_storage = 0; -int GLAD_GL_EXT_EGL_image_storage_compression = 0; -int GLAD_GL_EXT_YUV_target = 0; -int GLAD_GL_EXT_base_instance = 0; -int GLAD_GL_EXT_blend_func_extended = 0; -int GLAD_GL_EXT_blend_minmax = 0; -int GLAD_GL_EXT_buffer_storage = 0; -int GLAD_GL_EXT_clear_texture = 0; -int GLAD_GL_EXT_clip_control = 0; -int GLAD_GL_EXT_clip_cull_distance = 0; -int GLAD_GL_EXT_color_buffer_float = 0; -int GLAD_GL_EXT_color_buffer_half_float = 0; -int GLAD_GL_EXT_conservative_depth = 0; -int GLAD_GL_EXT_copy_image = 0; -int GLAD_GL_EXT_debug_label = 0; -int GLAD_GL_EXT_debug_marker = 0; -int GLAD_GL_EXT_depth_clamp = 0; -int GLAD_GL_EXT_discard_framebuffer = 0; -int GLAD_GL_EXT_disjoint_timer_query = 0; -int GLAD_GL_EXT_draw_buffers = 0; -int GLAD_GL_EXT_draw_buffers_indexed = 0; -int GLAD_GL_EXT_draw_elements_base_vertex = 0; -int GLAD_GL_EXT_draw_instanced = 0; -int GLAD_GL_EXT_draw_transform_feedback = 0; -int GLAD_GL_EXT_external_buffer = 0; -int GLAD_GL_EXT_float_blend = 0; -int GLAD_GL_EXT_fragment_shading_rate = 0; -int GLAD_GL_EXT_geometry_point_size = 0; -int GLAD_GL_EXT_geometry_shader = 0; -int GLAD_GL_EXT_gpu_shader5 = 0; -int GLAD_GL_EXT_instanced_arrays = 0; -int GLAD_GL_EXT_map_buffer_range = 0; -int GLAD_GL_EXT_memory_object = 0; -int GLAD_GL_EXT_memory_object_fd = 0; -int GLAD_GL_EXT_memory_object_win32 = 0; -int GLAD_GL_EXT_multi_draw_arrays = 0; -int GLAD_GL_EXT_multi_draw_indirect = 0; -int GLAD_GL_EXT_multisampled_compatibility = 0; -int GLAD_GL_EXT_multisampled_render_to_texture = 0; -int GLAD_GL_EXT_multisampled_render_to_texture2 = 0; -int GLAD_GL_EXT_multiview_draw_buffers = 0; -int GLAD_GL_EXT_multiview_tessellation_geometry_shader = 0; -int GLAD_GL_EXT_multiview_texture_multisample = 0; -int GLAD_GL_EXT_multiview_timer_query = 0; -int GLAD_GL_EXT_occlusion_query_boolean = 0; -int GLAD_GL_EXT_polygon_offset_clamp = 0; -int GLAD_GL_EXT_post_depth_coverage = 0; -int GLAD_GL_EXT_primitive_bounding_box = 0; -int GLAD_GL_EXT_protected_textures = 0; -int GLAD_GL_EXT_pvrtc_sRGB = 0; -int GLAD_GL_EXT_raster_multisample = 0; -int GLAD_GL_EXT_read_format_bgra = 0; -int GLAD_GL_EXT_render_snorm = 0; -int GLAD_GL_EXT_robustness = 0; -int GLAD_GL_EXT_sRGB = 0; -int GLAD_GL_EXT_sRGB_write_control = 0; -int GLAD_GL_EXT_semaphore = 0; -int GLAD_GL_EXT_semaphore_fd = 0; -int GLAD_GL_EXT_semaphore_win32 = 0; -int GLAD_GL_EXT_separate_depth_stencil = 0; -int GLAD_GL_EXT_separate_shader_objects = 0; -int GLAD_GL_EXT_shader_framebuffer_fetch = 0; -int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = 0; -int GLAD_GL_EXT_shader_group_vote = 0; -int GLAD_GL_EXT_shader_implicit_conversions = 0; -int GLAD_GL_EXT_shader_integer_mix = 0; -int GLAD_GL_EXT_shader_io_blocks = 0; -int GLAD_GL_EXT_shader_non_constant_global_initializers = 0; -int GLAD_GL_EXT_shader_pixel_local_storage = 0; -int GLAD_GL_EXT_shader_pixel_local_storage2 = 0; -int GLAD_GL_EXT_shader_samples_identical = 0; -int GLAD_GL_EXT_shader_texture_lod = 0; -int GLAD_GL_EXT_shadow_samplers = 0; -int GLAD_GL_EXT_sparse_texture = 0; -int GLAD_GL_EXT_sparse_texture2 = 0; -int GLAD_GL_EXT_tessellation_point_size = 0; -int GLAD_GL_EXT_tessellation_shader = 0; -int GLAD_GL_EXT_texture_border_clamp = 0; -int GLAD_GL_EXT_texture_buffer = 0; -int GLAD_GL_EXT_texture_compression_astc_decode_mode = 0; -int GLAD_GL_EXT_texture_compression_bptc = 0; -int GLAD_GL_EXT_texture_compression_dxt1 = 0; -int GLAD_GL_EXT_texture_compression_rgtc = 0; -int GLAD_GL_EXT_texture_compression_s3tc = 0; -int GLAD_GL_EXT_texture_compression_s3tc_srgb = 0; -int GLAD_GL_EXT_texture_cube_map_array = 0; -int GLAD_GL_EXT_texture_filter_anisotropic = 0; -int GLAD_GL_EXT_texture_filter_minmax = 0; -int GLAD_GL_EXT_texture_format_BGRA8888 = 0; -int GLAD_GL_EXT_texture_format_sRGB_override = 0; -int GLAD_GL_EXT_texture_mirror_clamp_to_edge = 0; -int GLAD_GL_EXT_texture_norm16 = 0; -int GLAD_GL_EXT_texture_query_lod = 0; -int GLAD_GL_EXT_texture_rg = 0; -int GLAD_GL_EXT_texture_sRGB_R8 = 0; -int GLAD_GL_EXT_texture_sRGB_RG8 = 0; -int GLAD_GL_EXT_texture_sRGB_decode = 0; -int GLAD_GL_EXT_texture_shadow_lod = 0; -int GLAD_GL_EXT_texture_storage = 0; -int GLAD_GL_EXT_texture_storage_compression = 0; -int GLAD_GL_EXT_texture_type_2_10_10_10_REV = 0; -int GLAD_GL_EXT_texture_view = 0; -int GLAD_GL_EXT_unpack_subimage = 0; -int GLAD_GL_EXT_win32_keyed_mutex = 0; -int GLAD_GL_EXT_window_rectangles = 0; -int GLAD_GL_KHR_blend_equation_advanced = 0; -int GLAD_GL_KHR_blend_equation_advanced_coherent = 0; -int GLAD_GL_KHR_context_flush_control = 0; -int GLAD_GL_KHR_debug = 0; -int GLAD_GL_KHR_no_error = 0; -int GLAD_GL_KHR_parallel_shader_compile = 0; -int GLAD_GL_KHR_robust_buffer_access_behavior = 0; -int GLAD_GL_KHR_robustness = 0; -int GLAD_GL_KHR_shader_subgroup = 0; -int GLAD_GL_KHR_texture_compression_astc_hdr = 0; -int GLAD_GL_KHR_texture_compression_astc_ldr = 0; -int GLAD_GL_KHR_texture_compression_astc_sliced_3d = 0; -int GLAD_GL_OES_EGL_image = 0; -int GLAD_GL_OES_EGL_image_external = 0; -int GLAD_GL_OES_EGL_image_external_essl3 = 0; -int GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture = 0; -int GLAD_GL_OES_compressed_ETC1_RGB8_texture = 0; -int GLAD_GL_OES_compressed_paletted_texture = 0; -int GLAD_GL_OES_copy_image = 0; -int GLAD_GL_OES_depth24 = 0; -int GLAD_GL_OES_depth32 = 0; -int GLAD_GL_OES_depth_texture = 0; -int GLAD_GL_OES_draw_buffers_indexed = 0; -int GLAD_GL_OES_draw_elements_base_vertex = 0; -int GLAD_GL_OES_element_index_uint = 0; -int GLAD_GL_OES_fbo_render_mipmap = 0; -int GLAD_GL_OES_fragment_precision_high = 0; -int GLAD_GL_OES_geometry_point_size = 0; -int GLAD_GL_OES_geometry_shader = 0; -int GLAD_GL_OES_get_program_binary = 0; -int GLAD_GL_OES_gpu_shader5 = 0; -int GLAD_GL_OES_mapbuffer = 0; -int GLAD_GL_OES_packed_depth_stencil = 0; -int GLAD_GL_OES_primitive_bounding_box = 0; -int GLAD_GL_OES_required_internalformat = 0; -int GLAD_GL_OES_rgb8_rgba8 = 0; -int GLAD_GL_OES_sample_shading = 0; -int GLAD_GL_OES_sample_variables = 0; -int GLAD_GL_OES_shader_image_atomic = 0; -int GLAD_GL_OES_shader_io_blocks = 0; -int GLAD_GL_OES_shader_multisample_interpolation = 0; -int GLAD_GL_OES_standard_derivatives = 0; -int GLAD_GL_OES_stencil1 = 0; -int GLAD_GL_OES_stencil4 = 0; -int GLAD_GL_OES_surfaceless_context = 0; -int GLAD_GL_OES_tessellation_point_size = 0; -int GLAD_GL_OES_tessellation_shader = 0; -int GLAD_GL_OES_texture_3D = 0; -int GLAD_GL_OES_texture_border_clamp = 0; -int GLAD_GL_OES_texture_buffer = 0; -int GLAD_GL_OES_texture_compression_astc = 0; -int GLAD_GL_OES_texture_cube_map_array = 0; -int GLAD_GL_OES_texture_float = 0; -int GLAD_GL_OES_texture_float_linear = 0; -int GLAD_GL_OES_texture_half_float = 0; -int GLAD_GL_OES_texture_half_float_linear = 0; -int GLAD_GL_OES_texture_npot = 0; -int GLAD_GL_OES_texture_stencil8 = 0; -int GLAD_GL_OES_texture_storage_multisample_2d_array = 0; -int GLAD_GL_OES_texture_view = 0; -int GLAD_GL_OES_vertex_array_object = 0; -int GLAD_GL_OES_vertex_half_float = 0; -int GLAD_GL_OES_vertex_type_10_10_10_2 = 0; -int GLAD_GL_OES_viewport_array = 0; - - - -PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT = NULL; -PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT = NULL; -PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; -PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; -PFNGLBEGINQUERYEXTPROC glad_glBeginQueryEXT = NULL; -PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; -PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; -PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT = NULL; -PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC glad_glBindFragDataLocationIndexedEXT = NULL; -PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; -PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT = NULL; -PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; -PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; -PFNGLBINDVERTEXARRAYOESPROC glad_glBindVertexArrayOES = NULL; -PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR = NULL; -PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; -PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; -PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; -PFNGLBLENDEQUATIONSEPARATEIEXTPROC glad_glBlendEquationSeparateiEXT = NULL; -PFNGLBLENDEQUATIONSEPARATEIOESPROC glad_glBlendEquationSeparateiOES = NULL; -PFNGLBLENDEQUATIONIEXTPROC glad_glBlendEquationiEXT = NULL; -PFNGLBLENDEQUATIONIOESPROC glad_glBlendEquationiOES = NULL; -PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; -PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; -PFNGLBLENDFUNCSEPARATEIEXTPROC glad_glBlendFuncSeparateiEXT = NULL; -PFNGLBLENDFUNCSEPARATEIOESPROC glad_glBlendFuncSeparateiOES = NULL; -PFNGLBLENDFUNCIEXTPROC glad_glBlendFunciEXT = NULL; -PFNGLBLENDFUNCIOESPROC glad_glBlendFunciOES = NULL; -PFNGLBUFFERDATAPROC glad_glBufferData = NULL; -PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT = NULL; -PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT = NULL; -PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT = NULL; -PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; -PFNGLCLEARPROC glad_glClear = NULL; -PFNGLCLEARCOLORPROC glad_glClearColor = NULL; -PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; -PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC glad_glClearPixelLocalStorageuiEXT = NULL; -PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; -PFNGLCLEARTEXIMAGEEXTPROC glad_glClearTexImageEXT = NULL; -PFNGLCLEARTEXSUBIMAGEEXTPROC glad_glClearTexSubImageEXT = NULL; -PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT = NULL; -PFNGLCOLORMASKPROC glad_glColorMask = NULL; -PFNGLCOLORMASKIEXTPROC glad_glColorMaskiEXT = NULL; -PFNGLCOLORMASKIOESPROC glad_glColorMaskiOES = NULL; -PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; -PFNGLCOMPRESSEDTEXIMAGE3DOESPROC glad_glCompressedTexImage3DOES = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glad_glCompressedTexSubImage3DOES = NULL; -PFNGLCOPYIMAGESUBDATAEXTPROC glad_glCopyImageSubDataEXT = NULL; -PFNGLCOPYIMAGESUBDATAOESPROC glad_glCopyImageSubDataOES = NULL; -PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE3DOESPROC glad_glCopyTexSubImage3DOES = NULL; -PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT = NULL; -PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; -PFNGLCREATESHADERPROC glad_glCreateShader = NULL; -PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT = NULL; -PFNGLCULLFACEPROC glad_glCullFace = NULL; -PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; -PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; -PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; -PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; -PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; -PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT = NULL; -PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; -PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT = NULL; -PFNGLDELETEQUERIESEXTPROC glad_glDeleteQueriesEXT = NULL; -PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; -PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT = NULL; -PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; -PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; -PFNGLDELETEVERTEXARRAYSOESPROC glad_glDeleteVertexArraysOES = NULL; -PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; -PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; -PFNGLDEPTHRANGEARRAYFVOESPROC glad_glDepthRangeArrayfvOES = NULL; -PFNGLDEPTHRANGEINDEXEDFOESPROC glad_glDepthRangeIndexedfOES = NULL; -PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; -PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; -PFNGLDISABLEPROC glad_glDisable = NULL; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; -PFNGLDISABLEIEXTPROC glad_glDisableiEXT = NULL; -PFNGLDISABLEIOESPROC glad_glDisableiOES = NULL; -PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT = NULL; -PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; -PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawArraysInstancedBaseInstanceEXT = NULL; -PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT = NULL; -PFNGLDRAWBUFFERSEXTPROC glad_glDrawBuffersEXT = NULL; -PFNGLDRAWBUFFERSINDEXEDEXTPROC glad_glDrawBuffersIndexedEXT = NULL; -PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; -PFNGLDRAWELEMENTSBASEVERTEXEXTPROC glad_glDrawElementsBaseVertexEXT = NULL; -PFNGLDRAWELEMENTSBASEVERTEXOESPROC glad_glDrawElementsBaseVertexOES = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseInstanceEXT = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC glad_glDrawElementsInstancedBaseVertexEXT = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC glad_glDrawElementsInstancedBaseVertexOES = NULL; -PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT = NULL; -PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC glad_glDrawRangeElementsBaseVertexEXT = NULL; -PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC glad_glDrawRangeElementsBaseVertexOES = NULL; -PFNGLDRAWTRANSFORMFEEDBACKEXTPROC glad_glDrawTransformFeedbackEXT = NULL; -PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC glad_glDrawTransformFeedbackInstancedEXT = NULL; -PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glad_glEGLImageTargetRenderbufferStorageOES = NULL; -PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT = NULL; -PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES = NULL; -PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT = NULL; -PFNGLENABLEPROC glad_glEnable = NULL; -PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; -PFNGLENABLEIEXTPROC glad_glEnableiEXT = NULL; -PFNGLENABLEIOESPROC glad_glEnableiOES = NULL; -PFNGLENDQUERYEXTPROC glad_glEndQueryEXT = NULL; -PFNGLFINISHPROC glad_glFinish = NULL; -PFNGLFLUSHPROC glad_glFlush = NULL; -PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC glad_glFlushMappedBufferRangeEXT = NULL; -PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT = NULL; -PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glFramebufferPixelLocalStorageSizeEXT = NULL; -PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; -PFNGLFRAMEBUFFERSHADINGRATEEXTPROC glad_glFramebufferShadingRateEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; -PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glad_glFramebufferTexture2DMultisampleEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE3DOESPROC glad_glFramebufferTexture3DOES = NULL; -PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT = NULL; -PFNGLFRAMEBUFFERTEXTUREOESPROC glad_glFramebufferTextureOES = NULL; -PFNGLFRONTFACEPROC glad_glFrontFace = NULL; -PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; -PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; -PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT = NULL; -PFNGLGENQUERIESEXTPROC glad_glGenQueriesEXT = NULL; -PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; -PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT = NULL; -PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; -PFNGLGENVERTEXARRAYSOESPROC glad_glGenVertexArraysOES = NULL; -PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; -PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; -PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; -PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; -PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; -PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; -PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; -PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES = NULL; -PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL; -PFNGLGETERRORPROC glad_glGetError = NULL; -PFNGLGETFLOATI_VOESPROC glad_glGetFloati_vOES = NULL; -PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; -PFNGLGETFRAGDATAINDEXEXTPROC glad_glGetFragDataIndexEXT = NULL; -PFNGLGETFRAGMENTSHADINGRATESEXTPROC glad_glGetFragmentShadingRatesEXT = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; -PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glGetFramebufferPixelLocalStorageSizeEXT = NULL; -PFNGLGETGRAPHICSRESETSTATUSEXTPROC glad_glGetGraphicsResetStatusEXT = NULL; -PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR = NULL; -PFNGLGETINTEGER64VEXTPROC glad_glGetInteger64vEXT = NULL; -PFNGLGETINTEGERI_VEXTPROC glad_glGetIntegeri_vEXT = NULL; -PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; -PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT = NULL; -PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT = NULL; -PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL; -PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL; -PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL; -PFNGLGETPROGRAMBINARYOESPROC glad_glGetProgramBinaryOES = NULL; -PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; -PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT = NULL; -PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT = NULL; -PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC glad_glGetProgramResourceLocationIndexEXT = NULL; -PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; -PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT = NULL; -PFNGLGETQUERYOBJECTIVEXTPROC glad_glGetQueryObjectivEXT = NULL; -PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT = NULL; -PFNGLGETQUERYOBJECTUIVEXTPROC glad_glGetQueryObjectuivEXT = NULL; -PFNGLGETQUERYIVEXTPROC glad_glGetQueryivEXT = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; -PFNGLGETSAMPLERPARAMETERIIVEXTPROC glad_glGetSamplerParameterIivEXT = NULL; -PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES = NULL; -PFNGLGETSAMPLERPARAMETERIUIVEXTPROC glad_glGetSamplerParameterIuivEXT = NULL; -PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES = NULL; -PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT = NULL; -PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; -PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; -PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; -PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; -PFNGLGETSTRINGPROC glad_glGetString = NULL; -PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT = NULL; -PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES = NULL; -PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT = NULL; -PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES = NULL; -PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; -PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; -PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; -PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; -PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; -PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT = NULL; -PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT = NULL; -PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; -PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; -PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; -PFNGLGETNUNIFORMFVEXTPROC glad_glGetnUniformfvEXT = NULL; -PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR = NULL; -PFNGLGETNUNIFORMIVEXTPROC glad_glGetnUniformivEXT = NULL; -PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR = NULL; -PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR = NULL; -PFNGLHINTPROC glad_glHint = NULL; -PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT = NULL; -PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT = NULL; -PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT = NULL; -PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT = NULL; -PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT = NULL; -PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT = NULL; -PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT = NULL; -PFNGLISBUFFERPROC glad_glIsBuffer = NULL; -PFNGLISENABLEDPROC glad_glIsEnabled = NULL; -PFNGLISENABLEDIEXTPROC glad_glIsEnablediEXT = NULL; -PFNGLISENABLEDIOESPROC glad_glIsEnablediOES = NULL; -PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; -PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT = NULL; -PFNGLISPROGRAMPROC glad_glIsProgram = NULL; -PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT = NULL; -PFNGLISQUERYEXTPROC glad_glIsQueryEXT = NULL; -PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; -PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT = NULL; -PFNGLISSHADERPROC glad_glIsShader = NULL; -PFNGLISTEXTUREPROC glad_glIsTexture = NULL; -PFNGLISVERTEXARRAYOESPROC glad_glIsVertexArrayOES = NULL; -PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT = NULL; -PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; -PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; -PFNGLMAPBUFFEROESPROC glad_glMapBufferOES = NULL; -PFNGLMAPBUFFERRANGEEXTPROC glad_glMapBufferRangeEXT = NULL; -PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR = NULL; -PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT = NULL; -PFNGLMINSAMPLESHADINGOESPROC glad_glMinSampleShadingOES = NULL; -PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT = NULL; -PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC glad_glMultiDrawArraysIndirectEXT = NULL; -PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC glad_glMultiDrawElementsBaseVertexEXT = NULL; -PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT = NULL; -PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC glad_glMultiDrawElementsIndirectEXT = NULL; -PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT = NULL; -PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT = NULL; -PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL; -PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL; -PFNGLPATCHPARAMETERIEXTPROC glad_glPatchParameteriEXT = NULL; -PFNGLPATCHPARAMETERIOESPROC glad_glPatchParameteriOES = NULL; -PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; -PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; -PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT = NULL; -PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL; -PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT = NULL; -PFNGLPRIMITIVEBOUNDINGBOXEXTPROC glad_glPrimitiveBoundingBoxEXT = NULL; -PFNGLPRIMITIVEBOUNDINGBOXOESPROC glad_glPrimitiveBoundingBoxOES = NULL; -PFNGLPROGRAMBINARYOESPROC glad_glProgramBinaryOES = NULL; -PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT = NULL; -PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT = NULL; -PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT = NULL; -PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT = NULL; -PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT = NULL; -PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT = NULL; -PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT = NULL; -PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT = NULL; -PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT = NULL; -PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT = NULL; -PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT = NULL; -PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT = NULL; -PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT = NULL; -PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT = NULL; -PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT = NULL; -PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT = NULL; -PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT = NULL; -PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT = NULL; -PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT = NULL; -PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT = NULL; -PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT = NULL; -PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT = NULL; -PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT = NULL; -PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT = NULL; -PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT = NULL; -PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL; -PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT = NULL; -PFNGLQUERYCOUNTEREXTPROC glad_glQueryCounterEXT = NULL; -PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT = NULL; -PFNGLREADBUFFERINDEXEDEXTPROC glad_glReadBufferIndexedEXT = NULL; -PFNGLREADPIXELSPROC glad_glReadPixels = NULL; -PFNGLREADNPIXELSEXTPROC glad_glReadnPixelsEXT = NULL; -PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR = NULL; -PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT = NULL; -PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; -PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL; -PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; -PFNGLSAMPLERPARAMETERIIVEXTPROC glad_glSamplerParameterIivEXT = NULL; -PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES = NULL; -PFNGLSAMPLERPARAMETERIUIVEXTPROC glad_glSamplerParameterIuivEXT = NULL; -PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES = NULL; -PFNGLSCISSORPROC glad_glScissor = NULL; -PFNGLSCISSORARRAYVOESPROC glad_glScissorArrayvOES = NULL; -PFNGLSCISSORINDEXEDOESPROC glad_glScissorIndexedOES = NULL; -PFNGLSCISSORINDEXEDVOESPROC glad_glScissorIndexedvOES = NULL; -PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT = NULL; -PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; -PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; -PFNGLSHADINGRATECOMBINEROPSEXTPROC glad_glShadingRateCombinerOpsEXT = NULL; -PFNGLSHADINGRATEEXTPROC glad_glShadingRateEXT = NULL; -PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT = NULL; -PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; -PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; -PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; -PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; -PFNGLSTENCILOPPROC glad_glStencilOp = NULL; -PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; -PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT = NULL; -PFNGLTEXBUFFEROESPROC glad_glTexBufferOES = NULL; -PFNGLTEXBUFFERRANGEEXTPROC glad_glTexBufferRangeEXT = NULL; -PFNGLTEXBUFFERRANGEOESPROC glad_glTexBufferRangeOES = NULL; -PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; -PFNGLTEXIMAGE3DOESPROC glad_glTexImage3DOES = NULL; -PFNGLTEXPAGECOMMITMENTEXTPROC glad_glTexPageCommitmentEXT = NULL; -PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT = NULL; -PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES = NULL; -PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT = NULL; -PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES = NULL; -PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; -PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; -PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; -PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; -PFNGLTEXSTORAGE1DEXTPROC glad_glTexStorage1DEXT = NULL; -PFNGLTEXSTORAGE2DEXTPROC glad_glTexStorage2DEXT = NULL; -PFNGLTEXSTORAGE3DEXTPROC glad_glTexStorage3DEXT = NULL; -PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC glad_glTexStorage3DMultisampleOES = NULL; -PFNGLTEXSTORAGEATTRIBS2DEXTPROC glad_glTexStorageAttribs2DEXT = NULL; -PFNGLTEXSTORAGEATTRIBS3DEXTPROC glad_glTexStorageAttribs3DEXT = NULL; -PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT = NULL; -PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT = NULL; -PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT = NULL; -PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT = NULL; -PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; -PFNGLTEXSUBIMAGE3DOESPROC glad_glTexSubImage3DOES = NULL; -PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT = NULL; -PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT = NULL; -PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT = NULL; -PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT = NULL; -PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT = NULL; -PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT = NULL; -PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT = NULL; -PFNGLTEXTUREVIEWEXTPROC glad_glTextureViewEXT = NULL; -PFNGLTEXTUREVIEWOESPROC glad_glTextureViewOES = NULL; -PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; -PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; -PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; -PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; -PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; -PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; -PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; -PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; -PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; -PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; -PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; -PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; -PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; -PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; -PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; -PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; -PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; -PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; -PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; -PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES = NULL; -PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; -PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT = NULL; -PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; -PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT = NULL; -PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; -PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; -PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; -PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; -PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; -PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; -PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; -PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; -PFNGLVERTEXATTRIBDIVISOREXTPROC glad_glVertexAttribDivisorEXT = NULL; -PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; -PFNGLVIEWPORTPROC glad_glViewport = NULL; -PFNGLVIEWPORTARRAYVOESPROC glad_glViewportArrayvOES = NULL; -PFNGLVIEWPORTINDEXEDFOESPROC glad_glViewportIndexedfOES = NULL; -PFNGLVIEWPORTINDEXEDFVOESPROC glad_glViewportIndexedfvOES = NULL; -PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT = NULL; -PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT = NULL; - - -static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_ES_VERSION_2_0) return; - glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); - glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); - glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); - glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); - glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); - glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); - glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); - glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); - glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); - glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); - glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); - glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); - glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); - glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); - glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); - glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); - glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); - glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); - glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); - glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); - glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); - glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); - glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); - glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); - glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); - glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); - glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); - glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); - glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); - glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); - glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); - glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); - glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); - glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); - glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); - glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); - glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); - glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); - glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); - glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); - glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); - glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); - glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); - glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); - glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); - glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); - glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); - glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); - glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); - glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); - glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); - glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); - glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); - glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); - glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); - glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); - glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); - glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); - glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); - glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); - glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); - glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); - glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); - glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); - glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); - glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); - glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); - glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); - glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); - glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); - glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); - glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); - glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); - glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); - glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); - glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); - glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); - glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); - glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); - glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); - glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); - glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); - glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); - glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); - glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); - glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); - glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); - glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); - glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); - glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); - glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); - glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); - glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); - glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); - glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); - glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); - glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); - glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); - glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); - glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); - glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); - glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); - glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); - glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); - glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); - glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); - glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); - glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); - glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); - glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); - glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); - glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); - glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); - glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); - glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); - glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); - glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); - glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); - glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); - glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); - glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); - glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); - glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); - glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); - glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); - glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); - glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); - glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); - glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); - glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); - glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); - glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); - glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); - glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); - glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); - glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); - glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); - glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); - glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); - glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); - glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); - glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); -} -static void glad_gl_load_GL_EXT_EGL_image_storage( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_EGL_image_storage) return; - glad_glEGLImageTargetTexStorageEXT = (PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) load(userptr, "glEGLImageTargetTexStorageEXT"); - glad_glEGLImageTargetTextureStorageEXT = (PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) load(userptr, "glEGLImageTargetTextureStorageEXT"); -} -static void glad_gl_load_GL_EXT_base_instance( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_base_instance) return; - glad_glDrawArraysInstancedBaseInstanceEXT = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) load(userptr, "glDrawArraysInstancedBaseInstanceEXT"); - glad_glDrawElementsInstancedBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) load(userptr, "glDrawElementsInstancedBaseInstanceEXT"); - glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) load(userptr, "glDrawElementsInstancedBaseVertexBaseInstanceEXT"); -} -static void glad_gl_load_GL_EXT_blend_func_extended( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_blend_func_extended) return; - glad_glBindFragDataLocationEXT = (PFNGLBINDFRAGDATALOCATIONEXTPROC) load(userptr, "glBindFragDataLocationEXT"); - glad_glBindFragDataLocationIndexedEXT = (PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) load(userptr, "glBindFragDataLocationIndexedEXT"); - glad_glGetFragDataIndexEXT = (PFNGLGETFRAGDATAINDEXEXTPROC) load(userptr, "glGetFragDataIndexEXT"); - glad_glGetProgramResourceLocationIndexEXT = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) load(userptr, "glGetProgramResourceLocationIndexEXT"); -} -static void glad_gl_load_GL_EXT_buffer_storage( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_buffer_storage) return; - glad_glBufferStorageEXT = (PFNGLBUFFERSTORAGEEXTPROC) load(userptr, "glBufferStorageEXT"); -} -static void glad_gl_load_GL_EXT_clear_texture( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_clear_texture) return; - glad_glClearTexImageEXT = (PFNGLCLEARTEXIMAGEEXTPROC) load(userptr, "glClearTexImageEXT"); - glad_glClearTexSubImageEXT = (PFNGLCLEARTEXSUBIMAGEEXTPROC) load(userptr, "glClearTexSubImageEXT"); -} -static void glad_gl_load_GL_EXT_clip_control( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_clip_control) return; - glad_glClipControlEXT = (PFNGLCLIPCONTROLEXTPROC) load(userptr, "glClipControlEXT"); -} -static void glad_gl_load_GL_EXT_copy_image( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_copy_image) return; - glad_glCopyImageSubDataEXT = (PFNGLCOPYIMAGESUBDATAEXTPROC) load(userptr, "glCopyImageSubDataEXT"); -} -static void glad_gl_load_GL_EXT_debug_label( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_debug_label) return; - glad_glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC) load(userptr, "glGetObjectLabelEXT"); - glad_glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC) load(userptr, "glLabelObjectEXT"); -} -static void glad_gl_load_GL_EXT_debug_marker( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_debug_marker) return; - glad_glInsertEventMarkerEXT = (PFNGLINSERTEVENTMARKEREXTPROC) load(userptr, "glInsertEventMarkerEXT"); - glad_glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC) load(userptr, "glPopGroupMarkerEXT"); - glad_glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC) load(userptr, "glPushGroupMarkerEXT"); -} -static void glad_gl_load_GL_EXT_discard_framebuffer( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_discard_framebuffer) return; - glad_glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC) load(userptr, "glDiscardFramebufferEXT"); -} -static void glad_gl_load_GL_EXT_disjoint_timer_query( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_disjoint_timer_query) return; - glad_glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) load(userptr, "glBeginQueryEXT"); - glad_glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) load(userptr, "glDeleteQueriesEXT"); - glad_glEndQueryEXT = (PFNGLENDQUERYEXTPROC) load(userptr, "glEndQueryEXT"); - glad_glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) load(userptr, "glGenQueriesEXT"); - glad_glGetInteger64vEXT = (PFNGLGETINTEGER64VEXTPROC) load(userptr, "glGetInteger64vEXT"); - glad_glGetQueryObjecti64vEXT = (PFNGLGETQUERYOBJECTI64VEXTPROC) load(userptr, "glGetQueryObjecti64vEXT"); - glad_glGetQueryObjectivEXT = (PFNGLGETQUERYOBJECTIVEXTPROC) load(userptr, "glGetQueryObjectivEXT"); - glad_glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC) load(userptr, "glGetQueryObjectui64vEXT"); - glad_glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC) load(userptr, "glGetQueryObjectuivEXT"); - glad_glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) load(userptr, "glGetQueryivEXT"); - glad_glIsQueryEXT = (PFNGLISQUERYEXTPROC) load(userptr, "glIsQueryEXT"); - glad_glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC) load(userptr, "glQueryCounterEXT"); -} -static void glad_gl_load_GL_EXT_draw_buffers( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_draw_buffers) return; - glad_glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC) load(userptr, "glDrawBuffersEXT"); -} -static void glad_gl_load_GL_EXT_draw_buffers_indexed( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_draw_buffers_indexed) return; - glad_glBlendEquationSeparateiEXT = (PFNGLBLENDEQUATIONSEPARATEIEXTPROC) load(userptr, "glBlendEquationSeparateiEXT"); - glad_glBlendEquationiEXT = (PFNGLBLENDEQUATIONIEXTPROC) load(userptr, "glBlendEquationiEXT"); - glad_glBlendFuncSeparateiEXT = (PFNGLBLENDFUNCSEPARATEIEXTPROC) load(userptr, "glBlendFuncSeparateiEXT"); - glad_glBlendFunciEXT = (PFNGLBLENDFUNCIEXTPROC) load(userptr, "glBlendFunciEXT"); - glad_glColorMaskiEXT = (PFNGLCOLORMASKIEXTPROC) load(userptr, "glColorMaskiEXT"); - glad_glDisableiEXT = (PFNGLDISABLEIEXTPROC) load(userptr, "glDisableiEXT"); - glad_glEnableiEXT = (PFNGLENABLEIEXTPROC) load(userptr, "glEnableiEXT"); - glad_glIsEnablediEXT = (PFNGLISENABLEDIEXTPROC) load(userptr, "glIsEnablediEXT"); -} -static void glad_gl_load_GL_EXT_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_draw_elements_base_vertex) return; - glad_glDrawElementsBaseVertexEXT = (PFNGLDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glDrawElementsBaseVertexEXT"); - glad_glDrawElementsInstancedBaseVertexEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) load(userptr, "glDrawElementsInstancedBaseVertexEXT"); - glad_glDrawRangeElementsBaseVertexEXT = (PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) load(userptr, "glDrawRangeElementsBaseVertexEXT"); - glad_glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glMultiDrawElementsBaseVertexEXT"); -} -static void glad_gl_load_GL_EXT_draw_instanced( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_draw_instanced) return; - glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); - glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); -} -static void glad_gl_load_GL_EXT_draw_transform_feedback( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_draw_transform_feedback) return; - glad_glDrawTransformFeedbackEXT = (PFNGLDRAWTRANSFORMFEEDBACKEXTPROC) load(userptr, "glDrawTransformFeedbackEXT"); - glad_glDrawTransformFeedbackInstancedEXT = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC) load(userptr, "glDrawTransformFeedbackInstancedEXT"); -} -static void glad_gl_load_GL_EXT_external_buffer( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_external_buffer) return; - glad_glBufferStorageExternalEXT = (PFNGLBUFFERSTORAGEEXTERNALEXTPROC) load(userptr, "glBufferStorageExternalEXT"); - glad_glNamedBufferStorageExternalEXT = (PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) load(userptr, "glNamedBufferStorageExternalEXT"); -} -static void glad_gl_load_GL_EXT_fragment_shading_rate( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_fragment_shading_rate) return; - glad_glFramebufferShadingRateEXT = (PFNGLFRAMEBUFFERSHADINGRATEEXTPROC) load(userptr, "glFramebufferShadingRateEXT"); - glad_glGetFragmentShadingRatesEXT = (PFNGLGETFRAGMENTSHADINGRATESEXTPROC) load(userptr, "glGetFragmentShadingRatesEXT"); - glad_glShadingRateCombinerOpsEXT = (PFNGLSHADINGRATECOMBINEROPSEXTPROC) load(userptr, "glShadingRateCombinerOpsEXT"); - glad_glShadingRateEXT = (PFNGLSHADINGRATEEXTPROC) load(userptr, "glShadingRateEXT"); -} -static void glad_gl_load_GL_EXT_geometry_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_geometry_shader) return; - glad_glFramebufferTextureEXT = (PFNGLFRAMEBUFFERTEXTUREEXTPROC) load(userptr, "glFramebufferTextureEXT"); -} -static void glad_gl_load_GL_EXT_instanced_arrays( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_instanced_arrays) return; - glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); - glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); - glad_glVertexAttribDivisorEXT = (PFNGLVERTEXATTRIBDIVISOREXTPROC) load(userptr, "glVertexAttribDivisorEXT"); -} -static void glad_gl_load_GL_EXT_map_buffer_range( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_map_buffer_range) return; - glad_glFlushMappedBufferRangeEXT = (PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) load(userptr, "glFlushMappedBufferRangeEXT"); - glad_glMapBufferRangeEXT = (PFNGLMAPBUFFERRANGEEXTPROC) load(userptr, "glMapBufferRangeEXT"); -} -static void glad_gl_load_GL_EXT_memory_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_memory_object) return; - glad_glBufferStorageMemEXT = (PFNGLBUFFERSTORAGEMEMEXTPROC) load(userptr, "glBufferStorageMemEXT"); - glad_glCreateMemoryObjectsEXT = (PFNGLCREATEMEMORYOBJECTSEXTPROC) load(userptr, "glCreateMemoryObjectsEXT"); - glad_glDeleteMemoryObjectsEXT = (PFNGLDELETEMEMORYOBJECTSEXTPROC) load(userptr, "glDeleteMemoryObjectsEXT"); - glad_glGetMemoryObjectParameterivEXT = (PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) load(userptr, "glGetMemoryObjectParameterivEXT"); - glad_glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load(userptr, "glGetUnsignedBytei_vEXT"); - glad_glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load(userptr, "glGetUnsignedBytevEXT"); - glad_glIsMemoryObjectEXT = (PFNGLISMEMORYOBJECTEXTPROC) load(userptr, "glIsMemoryObjectEXT"); - glad_glMemoryObjectParameterivEXT = (PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) load(userptr, "glMemoryObjectParameterivEXT"); - glad_glNamedBufferStorageMemEXT = (PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) load(userptr, "glNamedBufferStorageMemEXT"); - glad_glTexStorageMem2DEXT = (PFNGLTEXSTORAGEMEM2DEXTPROC) load(userptr, "glTexStorageMem2DEXT"); - glad_glTexStorageMem2DMultisampleEXT = (PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) load(userptr, "glTexStorageMem2DMultisampleEXT"); - glad_glTexStorageMem3DEXT = (PFNGLTEXSTORAGEMEM3DEXTPROC) load(userptr, "glTexStorageMem3DEXT"); - glad_glTexStorageMem3DMultisampleEXT = (PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) load(userptr, "glTexStorageMem3DMultisampleEXT"); - glad_glTextureStorageMem2DEXT = (PFNGLTEXTURESTORAGEMEM2DEXTPROC) load(userptr, "glTextureStorageMem2DEXT"); - glad_glTextureStorageMem2DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) load(userptr, "glTextureStorageMem2DMultisampleEXT"); - glad_glTextureStorageMem3DEXT = (PFNGLTEXTURESTORAGEMEM3DEXTPROC) load(userptr, "glTextureStorageMem3DEXT"); - glad_glTextureStorageMem3DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) load(userptr, "glTextureStorageMem3DMultisampleEXT"); -} -static void glad_gl_load_GL_EXT_memory_object_fd( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_memory_object_fd) return; - glad_glImportMemoryFdEXT = (PFNGLIMPORTMEMORYFDEXTPROC) load(userptr, "glImportMemoryFdEXT"); -} -static void glad_gl_load_GL_EXT_memory_object_win32( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_memory_object_win32) return; - glad_glImportMemoryWin32HandleEXT = (PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) load(userptr, "glImportMemoryWin32HandleEXT"); - glad_glImportMemoryWin32NameEXT = (PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) load(userptr, "glImportMemoryWin32NameEXT"); -} -static void glad_gl_load_GL_EXT_multi_draw_arrays( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_multi_draw_arrays) return; - glad_glMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) load(userptr, "glMultiDrawArraysEXT"); - glad_glMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) load(userptr, "glMultiDrawElementsEXT"); -} -static void glad_gl_load_GL_EXT_multi_draw_indirect( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_multi_draw_indirect) return; - glad_glMultiDrawArraysIndirectEXT = (PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC) load(userptr, "glMultiDrawArraysIndirectEXT"); - glad_glMultiDrawElementsIndirectEXT = (PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC) load(userptr, "glMultiDrawElementsIndirectEXT"); -} -static void glad_gl_load_GL_EXT_multisampled_render_to_texture( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_multisampled_render_to_texture) return; - glad_glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) load(userptr, "glFramebufferTexture2DMultisampleEXT"); - glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) load(userptr, "glRenderbufferStorageMultisampleEXT"); -} -static void glad_gl_load_GL_EXT_multiview_draw_buffers( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_multiview_draw_buffers) return; - glad_glDrawBuffersIndexedEXT = (PFNGLDRAWBUFFERSINDEXEDEXTPROC) load(userptr, "glDrawBuffersIndexedEXT"); - glad_glGetIntegeri_vEXT = (PFNGLGETINTEGERI_VEXTPROC) load(userptr, "glGetIntegeri_vEXT"); - glad_glReadBufferIndexedEXT = (PFNGLREADBUFFERINDEXEDEXTPROC) load(userptr, "glReadBufferIndexedEXT"); -} -static void glad_gl_load_GL_EXT_occlusion_query_boolean( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_occlusion_query_boolean) return; - glad_glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) load(userptr, "glBeginQueryEXT"); - glad_glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) load(userptr, "glDeleteQueriesEXT"); - glad_glEndQueryEXT = (PFNGLENDQUERYEXTPROC) load(userptr, "glEndQueryEXT"); - glad_glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) load(userptr, "glGenQueriesEXT"); - glad_glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC) load(userptr, "glGetQueryObjectuivEXT"); - glad_glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) load(userptr, "glGetQueryivEXT"); - glad_glIsQueryEXT = (PFNGLISQUERYEXTPROC) load(userptr, "glIsQueryEXT"); -} -static void glad_gl_load_GL_EXT_polygon_offset_clamp( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_polygon_offset_clamp) return; - glad_glPolygonOffsetClampEXT = (PFNGLPOLYGONOFFSETCLAMPEXTPROC) load(userptr, "glPolygonOffsetClampEXT"); -} -static void glad_gl_load_GL_EXT_primitive_bounding_box( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_primitive_bounding_box) return; - glad_glPrimitiveBoundingBoxEXT = (PFNGLPRIMITIVEBOUNDINGBOXEXTPROC) load(userptr, "glPrimitiveBoundingBoxEXT"); -} -static void glad_gl_load_GL_EXT_raster_multisample( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_raster_multisample) return; - glad_glRasterSamplesEXT = (PFNGLRASTERSAMPLESEXTPROC) load(userptr, "glRasterSamplesEXT"); -} -static void glad_gl_load_GL_EXT_robustness( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_robustness) return; - glad_glGetGraphicsResetStatusEXT = (PFNGLGETGRAPHICSRESETSTATUSEXTPROC) load(userptr, "glGetGraphicsResetStatusEXT"); - glad_glGetnUniformfvEXT = (PFNGLGETNUNIFORMFVEXTPROC) load(userptr, "glGetnUniformfvEXT"); - glad_glGetnUniformivEXT = (PFNGLGETNUNIFORMIVEXTPROC) load(userptr, "glGetnUniformivEXT"); - glad_glReadnPixelsEXT = (PFNGLREADNPIXELSEXTPROC) load(userptr, "glReadnPixelsEXT"); -} -static void glad_gl_load_GL_EXT_semaphore( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_semaphore) return; - glad_glDeleteSemaphoresEXT = (PFNGLDELETESEMAPHORESEXTPROC) load(userptr, "glDeleteSemaphoresEXT"); - glad_glGenSemaphoresEXT = (PFNGLGENSEMAPHORESEXTPROC) load(userptr, "glGenSemaphoresEXT"); - glad_glGetSemaphoreParameterui64vEXT = (PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) load(userptr, "glGetSemaphoreParameterui64vEXT"); - glad_glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load(userptr, "glGetUnsignedBytei_vEXT"); - glad_glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load(userptr, "glGetUnsignedBytevEXT"); - glad_glIsSemaphoreEXT = (PFNGLISSEMAPHOREEXTPROC) load(userptr, "glIsSemaphoreEXT"); - glad_glSemaphoreParameterui64vEXT = (PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) load(userptr, "glSemaphoreParameterui64vEXT"); - glad_glSignalSemaphoreEXT = (PFNGLSIGNALSEMAPHOREEXTPROC) load(userptr, "glSignalSemaphoreEXT"); - glad_glWaitSemaphoreEXT = (PFNGLWAITSEMAPHOREEXTPROC) load(userptr, "glWaitSemaphoreEXT"); -} -static void glad_gl_load_GL_EXT_semaphore_fd( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_semaphore_fd) return; - glad_glImportSemaphoreFdEXT = (PFNGLIMPORTSEMAPHOREFDEXTPROC) load(userptr, "glImportSemaphoreFdEXT"); -} -static void glad_gl_load_GL_EXT_semaphore_win32( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_semaphore_win32) return; - glad_glImportSemaphoreWin32HandleEXT = (PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) load(userptr, "glImportSemaphoreWin32HandleEXT"); - glad_glImportSemaphoreWin32NameEXT = (PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) load(userptr, "glImportSemaphoreWin32NameEXT"); -} -static void glad_gl_load_GL_EXT_separate_shader_objects( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_separate_shader_objects) return; - glad_glActiveShaderProgramEXT = (PFNGLACTIVESHADERPROGRAMEXTPROC) load(userptr, "glActiveShaderProgramEXT"); - glad_glBindProgramPipelineEXT = (PFNGLBINDPROGRAMPIPELINEEXTPROC) load(userptr, "glBindProgramPipelineEXT"); - glad_glCreateShaderProgramvEXT = (PFNGLCREATESHADERPROGRAMVEXTPROC) load(userptr, "glCreateShaderProgramvEXT"); - glad_glDeleteProgramPipelinesEXT = (PFNGLDELETEPROGRAMPIPELINESEXTPROC) load(userptr, "glDeleteProgramPipelinesEXT"); - glad_glGenProgramPipelinesEXT = (PFNGLGENPROGRAMPIPELINESEXTPROC) load(userptr, "glGenProgramPipelinesEXT"); - glad_glGetProgramPipelineInfoLogEXT = (PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) load(userptr, "glGetProgramPipelineInfoLogEXT"); - glad_glGetProgramPipelineivEXT = (PFNGLGETPROGRAMPIPELINEIVEXTPROC) load(userptr, "glGetProgramPipelineivEXT"); - glad_glIsProgramPipelineEXT = (PFNGLISPROGRAMPIPELINEEXTPROC) load(userptr, "glIsProgramPipelineEXT"); - glad_glProgramParameteriEXT = (PFNGLPROGRAMPARAMETERIEXTPROC) load(userptr, "glProgramParameteriEXT"); - glad_glProgramUniform1fEXT = (PFNGLPROGRAMUNIFORM1FEXTPROC) load(userptr, "glProgramUniform1fEXT"); - glad_glProgramUniform1fvEXT = (PFNGLPROGRAMUNIFORM1FVEXTPROC) load(userptr, "glProgramUniform1fvEXT"); - glad_glProgramUniform1iEXT = (PFNGLPROGRAMUNIFORM1IEXTPROC) load(userptr, "glProgramUniform1iEXT"); - glad_glProgramUniform1ivEXT = (PFNGLPROGRAMUNIFORM1IVEXTPROC) load(userptr, "glProgramUniform1ivEXT"); - glad_glProgramUniform1uiEXT = (PFNGLPROGRAMUNIFORM1UIEXTPROC) load(userptr, "glProgramUniform1uiEXT"); - glad_glProgramUniform1uivEXT = (PFNGLPROGRAMUNIFORM1UIVEXTPROC) load(userptr, "glProgramUniform1uivEXT"); - glad_glProgramUniform2fEXT = (PFNGLPROGRAMUNIFORM2FEXTPROC) load(userptr, "glProgramUniform2fEXT"); - glad_glProgramUniform2fvEXT = (PFNGLPROGRAMUNIFORM2FVEXTPROC) load(userptr, "glProgramUniform2fvEXT"); - glad_glProgramUniform2iEXT = (PFNGLPROGRAMUNIFORM2IEXTPROC) load(userptr, "glProgramUniform2iEXT"); - glad_glProgramUniform2ivEXT = (PFNGLPROGRAMUNIFORM2IVEXTPROC) load(userptr, "glProgramUniform2ivEXT"); - glad_glProgramUniform2uiEXT = (PFNGLPROGRAMUNIFORM2UIEXTPROC) load(userptr, "glProgramUniform2uiEXT"); - glad_glProgramUniform2uivEXT = (PFNGLPROGRAMUNIFORM2UIVEXTPROC) load(userptr, "glProgramUniform2uivEXT"); - glad_glProgramUniform3fEXT = (PFNGLPROGRAMUNIFORM3FEXTPROC) load(userptr, "glProgramUniform3fEXT"); - glad_glProgramUniform3fvEXT = (PFNGLPROGRAMUNIFORM3FVEXTPROC) load(userptr, "glProgramUniform3fvEXT"); - glad_glProgramUniform3iEXT = (PFNGLPROGRAMUNIFORM3IEXTPROC) load(userptr, "glProgramUniform3iEXT"); - glad_glProgramUniform3ivEXT = (PFNGLPROGRAMUNIFORM3IVEXTPROC) load(userptr, "glProgramUniform3ivEXT"); - glad_glProgramUniform3uiEXT = (PFNGLPROGRAMUNIFORM3UIEXTPROC) load(userptr, "glProgramUniform3uiEXT"); - glad_glProgramUniform3uivEXT = (PFNGLPROGRAMUNIFORM3UIVEXTPROC) load(userptr, "glProgramUniform3uivEXT"); - glad_glProgramUniform4fEXT = (PFNGLPROGRAMUNIFORM4FEXTPROC) load(userptr, "glProgramUniform4fEXT"); - glad_glProgramUniform4fvEXT = (PFNGLPROGRAMUNIFORM4FVEXTPROC) load(userptr, "glProgramUniform4fvEXT"); - glad_glProgramUniform4iEXT = (PFNGLPROGRAMUNIFORM4IEXTPROC) load(userptr, "glProgramUniform4iEXT"); - glad_glProgramUniform4ivEXT = (PFNGLPROGRAMUNIFORM4IVEXTPROC) load(userptr, "glProgramUniform4ivEXT"); - glad_glProgramUniform4uiEXT = (PFNGLPROGRAMUNIFORM4UIEXTPROC) load(userptr, "glProgramUniform4uiEXT"); - glad_glProgramUniform4uivEXT = (PFNGLPROGRAMUNIFORM4UIVEXTPROC) load(userptr, "glProgramUniform4uivEXT"); - glad_glProgramUniformMatrix2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) load(userptr, "glProgramUniformMatrix2fvEXT"); - glad_glProgramUniformMatrix2x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) load(userptr, "glProgramUniformMatrix2x3fvEXT"); - glad_glProgramUniformMatrix2x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) load(userptr, "glProgramUniformMatrix2x4fvEXT"); - glad_glProgramUniformMatrix3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) load(userptr, "glProgramUniformMatrix3fvEXT"); - glad_glProgramUniformMatrix3x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) load(userptr, "glProgramUniformMatrix3x2fvEXT"); - glad_glProgramUniformMatrix3x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) load(userptr, "glProgramUniformMatrix3x4fvEXT"); - glad_glProgramUniformMatrix4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) load(userptr, "glProgramUniformMatrix4fvEXT"); - glad_glProgramUniformMatrix4x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) load(userptr, "glProgramUniformMatrix4x2fvEXT"); - glad_glProgramUniformMatrix4x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) load(userptr, "glProgramUniformMatrix4x3fvEXT"); - glad_glUseProgramStagesEXT = (PFNGLUSEPROGRAMSTAGESEXTPROC) load(userptr, "glUseProgramStagesEXT"); - glad_glValidateProgramPipelineEXT = (PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) load(userptr, "glValidateProgramPipelineEXT"); -} -static void glad_gl_load_GL_EXT_shader_framebuffer_fetch_non_coherent( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent) return; - glad_glFramebufferFetchBarrierEXT = (PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) load(userptr, "glFramebufferFetchBarrierEXT"); -} -static void glad_gl_load_GL_EXT_shader_pixel_local_storage2( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_shader_pixel_local_storage2) return; - glad_glClearPixelLocalStorageuiEXT = (PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC) load(userptr, "glClearPixelLocalStorageuiEXT"); - glad_glFramebufferPixelLocalStorageSizeEXT = (PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) load(userptr, "glFramebufferPixelLocalStorageSizeEXT"); - glad_glGetFramebufferPixelLocalStorageSizeEXT = (PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) load(userptr, "glGetFramebufferPixelLocalStorageSizeEXT"); -} -static void glad_gl_load_GL_EXT_sparse_texture( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_sparse_texture) return; - glad_glTexPageCommitmentEXT = (PFNGLTEXPAGECOMMITMENTEXTPROC) load(userptr, "glTexPageCommitmentEXT"); -} -static void glad_gl_load_GL_EXT_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_tessellation_shader) return; - glad_glPatchParameteriEXT = (PFNGLPATCHPARAMETERIEXTPROC) load(userptr, "glPatchParameteriEXT"); -} -static void glad_gl_load_GL_EXT_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_texture_border_clamp) return; - glad_glGetSamplerParameterIivEXT = (PFNGLGETSAMPLERPARAMETERIIVEXTPROC) load(userptr, "glGetSamplerParameterIivEXT"); - glad_glGetSamplerParameterIuivEXT = (PFNGLGETSAMPLERPARAMETERIUIVEXTPROC) load(userptr, "glGetSamplerParameterIuivEXT"); - glad_glGetTexParameterIivEXT = (PFNGLGETTEXPARAMETERIIVEXTPROC) load(userptr, "glGetTexParameterIivEXT"); - glad_glGetTexParameterIuivEXT = (PFNGLGETTEXPARAMETERIUIVEXTPROC) load(userptr, "glGetTexParameterIuivEXT"); - glad_glSamplerParameterIivEXT = (PFNGLSAMPLERPARAMETERIIVEXTPROC) load(userptr, "glSamplerParameterIivEXT"); - glad_glSamplerParameterIuivEXT = (PFNGLSAMPLERPARAMETERIUIVEXTPROC) load(userptr, "glSamplerParameterIuivEXT"); - glad_glTexParameterIivEXT = (PFNGLTEXPARAMETERIIVEXTPROC) load(userptr, "glTexParameterIivEXT"); - glad_glTexParameterIuivEXT = (PFNGLTEXPARAMETERIUIVEXTPROC) load(userptr, "glTexParameterIuivEXT"); -} -static void glad_gl_load_GL_EXT_texture_buffer( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_texture_buffer) return; - glad_glTexBufferEXT = (PFNGLTEXBUFFEREXTPROC) load(userptr, "glTexBufferEXT"); - glad_glTexBufferRangeEXT = (PFNGLTEXBUFFERRANGEEXTPROC) load(userptr, "glTexBufferRangeEXT"); -} -static void glad_gl_load_GL_EXT_texture_storage( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_texture_storage) return; - glad_glTexStorage1DEXT = (PFNGLTEXSTORAGE1DEXTPROC) load(userptr, "glTexStorage1DEXT"); - glad_glTexStorage2DEXT = (PFNGLTEXSTORAGE2DEXTPROC) load(userptr, "glTexStorage2DEXT"); - glad_glTexStorage3DEXT = (PFNGLTEXSTORAGE3DEXTPROC) load(userptr, "glTexStorage3DEXT"); - glad_glTextureStorage1DEXT = (PFNGLTEXTURESTORAGE1DEXTPROC) load(userptr, "glTextureStorage1DEXT"); - glad_glTextureStorage2DEXT = (PFNGLTEXTURESTORAGE2DEXTPROC) load(userptr, "glTextureStorage2DEXT"); - glad_glTextureStorage3DEXT = (PFNGLTEXTURESTORAGE3DEXTPROC) load(userptr, "glTextureStorage3DEXT"); -} -static void glad_gl_load_GL_EXT_texture_storage_compression( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_texture_storage_compression) return; - glad_glTexStorageAttribs2DEXT = (PFNGLTEXSTORAGEATTRIBS2DEXTPROC) load(userptr, "glTexStorageAttribs2DEXT"); - glad_glTexStorageAttribs3DEXT = (PFNGLTEXSTORAGEATTRIBS3DEXTPROC) load(userptr, "glTexStorageAttribs3DEXT"); -} -static void glad_gl_load_GL_EXT_texture_view( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_texture_view) return; - glad_glTextureViewEXT = (PFNGLTEXTUREVIEWEXTPROC) load(userptr, "glTextureViewEXT"); -} -static void glad_gl_load_GL_EXT_win32_keyed_mutex( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_win32_keyed_mutex) return; - glad_glAcquireKeyedMutexWin32EXT = (PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) load(userptr, "glAcquireKeyedMutexWin32EXT"); - glad_glReleaseKeyedMutexWin32EXT = (PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) load(userptr, "glReleaseKeyedMutexWin32EXT"); -} -static void glad_gl_load_GL_EXT_window_rectangles( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_EXT_window_rectangles) return; - glad_glWindowRectanglesEXT = (PFNGLWINDOWRECTANGLESEXTPROC) load(userptr, "glWindowRectanglesEXT"); -} -static void glad_gl_load_GL_KHR_blend_equation_advanced( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_KHR_blend_equation_advanced) return; - glad_glBlendBarrierKHR = (PFNGLBLENDBARRIERKHRPROC) load(userptr, "glBlendBarrierKHR"); -} -static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_KHR_debug) return; - glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC) load(userptr, "glDebugMessageCallbackKHR"); - glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC) load(userptr, "glDebugMessageControlKHR"); - glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC) load(userptr, "glDebugMessageInsertKHR"); - glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC) load(userptr, "glGetDebugMessageLogKHR"); - glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC) load(userptr, "glGetObjectLabelKHR"); - glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC) load(userptr, "glGetObjectPtrLabelKHR"); - glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC) load(userptr, "glGetPointervKHR"); - glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC) load(userptr, "glObjectLabelKHR"); - glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC) load(userptr, "glObjectPtrLabelKHR"); - glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC) load(userptr, "glPopDebugGroupKHR"); - glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC) load(userptr, "glPushDebugGroupKHR"); -} -static void glad_gl_load_GL_KHR_parallel_shader_compile( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_KHR_parallel_shader_compile) return; - glad_glMaxShaderCompilerThreadsKHR = (PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) load(userptr, "glMaxShaderCompilerThreadsKHR"); -} -static void glad_gl_load_GL_KHR_robustness( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_KHR_robustness) return; - glad_glGetGraphicsResetStatusKHR = (PFNGLGETGRAPHICSRESETSTATUSKHRPROC) load(userptr, "glGetGraphicsResetStatusKHR"); - glad_glGetnUniformfvKHR = (PFNGLGETNUNIFORMFVKHRPROC) load(userptr, "glGetnUniformfvKHR"); - glad_glGetnUniformivKHR = (PFNGLGETNUNIFORMIVKHRPROC) load(userptr, "glGetnUniformivKHR"); - glad_glGetnUniformuivKHR = (PFNGLGETNUNIFORMUIVKHRPROC) load(userptr, "glGetnUniformuivKHR"); - glad_glReadnPixelsKHR = (PFNGLREADNPIXELSKHRPROC) load(userptr, "glReadnPixelsKHR"); -} -static void glad_gl_load_GL_OES_EGL_image( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_EGL_image) return; - glad_glEGLImageTargetRenderbufferStorageOES = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) load(userptr, "glEGLImageTargetRenderbufferStorageOES"); - glad_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) load(userptr, "glEGLImageTargetTexture2DOES"); -} -static void glad_gl_load_GL_OES_copy_image( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_copy_image) return; - glad_glCopyImageSubDataOES = (PFNGLCOPYIMAGESUBDATAOESPROC) load(userptr, "glCopyImageSubDataOES"); -} -static void glad_gl_load_GL_OES_draw_buffers_indexed( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_draw_buffers_indexed) return; - glad_glBlendEquationSeparateiOES = (PFNGLBLENDEQUATIONSEPARATEIOESPROC) load(userptr, "glBlendEquationSeparateiOES"); - glad_glBlendEquationiOES = (PFNGLBLENDEQUATIONIOESPROC) load(userptr, "glBlendEquationiOES"); - glad_glBlendFuncSeparateiOES = (PFNGLBLENDFUNCSEPARATEIOESPROC) load(userptr, "glBlendFuncSeparateiOES"); - glad_glBlendFunciOES = (PFNGLBLENDFUNCIOESPROC) load(userptr, "glBlendFunciOES"); - glad_glColorMaskiOES = (PFNGLCOLORMASKIOESPROC) load(userptr, "glColorMaskiOES"); - glad_glDisableiOES = (PFNGLDISABLEIOESPROC) load(userptr, "glDisableiOES"); - glad_glEnableiOES = (PFNGLENABLEIOESPROC) load(userptr, "glEnableiOES"); - glad_glIsEnablediOES = (PFNGLISENABLEDIOESPROC) load(userptr, "glIsEnablediOES"); -} -static void glad_gl_load_GL_OES_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_draw_elements_base_vertex) return; - glad_glDrawElementsBaseVertexOES = (PFNGLDRAWELEMENTSBASEVERTEXOESPROC) load(userptr, "glDrawElementsBaseVertexOES"); - glad_glDrawElementsInstancedBaseVertexOES = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) load(userptr, "glDrawElementsInstancedBaseVertexOES"); - glad_glDrawRangeElementsBaseVertexOES = (PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) load(userptr, "glDrawRangeElementsBaseVertexOES"); - glad_glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glMultiDrawElementsBaseVertexEXT"); -} -static void glad_gl_load_GL_OES_geometry_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_geometry_shader) return; - glad_glFramebufferTextureOES = (PFNGLFRAMEBUFFERTEXTUREOESPROC) load(userptr, "glFramebufferTextureOES"); -} -static void glad_gl_load_GL_OES_get_program_binary( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_get_program_binary) return; - glad_glGetProgramBinaryOES = (PFNGLGETPROGRAMBINARYOESPROC) load(userptr, "glGetProgramBinaryOES"); - glad_glProgramBinaryOES = (PFNGLPROGRAMBINARYOESPROC) load(userptr, "glProgramBinaryOES"); -} -static void glad_gl_load_GL_OES_mapbuffer( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_mapbuffer) return; - glad_glGetBufferPointervOES = (PFNGLGETBUFFERPOINTERVOESPROC) load(userptr, "glGetBufferPointervOES"); - glad_glMapBufferOES = (PFNGLMAPBUFFEROESPROC) load(userptr, "glMapBufferOES"); - glad_glUnmapBufferOES = (PFNGLUNMAPBUFFEROESPROC) load(userptr, "glUnmapBufferOES"); -} -static void glad_gl_load_GL_OES_primitive_bounding_box( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_primitive_bounding_box) return; - glad_glPrimitiveBoundingBoxOES = (PFNGLPRIMITIVEBOUNDINGBOXOESPROC) load(userptr, "glPrimitiveBoundingBoxOES"); -} -static void glad_gl_load_GL_OES_sample_shading( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_sample_shading) return; - glad_glMinSampleShadingOES = (PFNGLMINSAMPLESHADINGOESPROC) load(userptr, "glMinSampleShadingOES"); -} -static void glad_gl_load_GL_OES_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_tessellation_shader) return; - glad_glPatchParameteriOES = (PFNGLPATCHPARAMETERIOESPROC) load(userptr, "glPatchParameteriOES"); -} -static void glad_gl_load_GL_OES_texture_3D( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_texture_3D) return; - glad_glCompressedTexImage3DOES = (PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) load(userptr, "glCompressedTexImage3DOES"); - glad_glCompressedTexSubImage3DOES = (PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) load(userptr, "glCompressedTexSubImage3DOES"); - glad_glCopyTexSubImage3DOES = (PFNGLCOPYTEXSUBIMAGE3DOESPROC) load(userptr, "glCopyTexSubImage3DOES"); - glad_glFramebufferTexture3DOES = (PFNGLFRAMEBUFFERTEXTURE3DOESPROC) load(userptr, "glFramebufferTexture3DOES"); - glad_glTexImage3DOES = (PFNGLTEXIMAGE3DOESPROC) load(userptr, "glTexImage3DOES"); - glad_glTexSubImage3DOES = (PFNGLTEXSUBIMAGE3DOESPROC) load(userptr, "glTexSubImage3DOES"); -} -static void glad_gl_load_GL_OES_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_texture_border_clamp) return; - glad_glGetSamplerParameterIivOES = (PFNGLGETSAMPLERPARAMETERIIVOESPROC) load(userptr, "glGetSamplerParameterIivOES"); - glad_glGetSamplerParameterIuivOES = (PFNGLGETSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glGetSamplerParameterIuivOES"); - glad_glGetTexParameterIivOES = (PFNGLGETTEXPARAMETERIIVOESPROC) load(userptr, "glGetTexParameterIivOES"); - glad_glGetTexParameterIuivOES = (PFNGLGETTEXPARAMETERIUIVOESPROC) load(userptr, "glGetTexParameterIuivOES"); - glad_glSamplerParameterIivOES = (PFNGLSAMPLERPARAMETERIIVOESPROC) load(userptr, "glSamplerParameterIivOES"); - glad_glSamplerParameterIuivOES = (PFNGLSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glSamplerParameterIuivOES"); - glad_glTexParameterIivOES = (PFNGLTEXPARAMETERIIVOESPROC) load(userptr, "glTexParameterIivOES"); - glad_glTexParameterIuivOES = (PFNGLTEXPARAMETERIUIVOESPROC) load(userptr, "glTexParameterIuivOES"); -} -static void glad_gl_load_GL_OES_texture_buffer( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_texture_buffer) return; - glad_glTexBufferOES = (PFNGLTEXBUFFEROESPROC) load(userptr, "glTexBufferOES"); - glad_glTexBufferRangeOES = (PFNGLTEXBUFFERRANGEOESPROC) load(userptr, "glTexBufferRangeOES"); -} -static void glad_gl_load_GL_OES_texture_storage_multisample_2d_array( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_texture_storage_multisample_2d_array) return; - glad_glTexStorage3DMultisampleOES = (PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC) load(userptr, "glTexStorage3DMultisampleOES"); -} -static void glad_gl_load_GL_OES_texture_view( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_texture_view) return; - glad_glTextureViewOES = (PFNGLTEXTUREVIEWOESPROC) load(userptr, "glTextureViewOES"); -} -static void glad_gl_load_GL_OES_vertex_array_object( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_vertex_array_object) return; - glad_glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC) load(userptr, "glBindVertexArrayOES"); - glad_glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC) load(userptr, "glDeleteVertexArraysOES"); - glad_glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC) load(userptr, "glGenVertexArraysOES"); - glad_glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC) load(userptr, "glIsVertexArrayOES"); -} -static void glad_gl_load_GL_OES_viewport_array( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_GL_OES_viewport_array) return; - glad_glDepthRangeArrayfvOES = (PFNGLDEPTHRANGEARRAYFVOESPROC) load(userptr, "glDepthRangeArrayfvOES"); - glad_glDepthRangeIndexedfOES = (PFNGLDEPTHRANGEINDEXEDFOESPROC) load(userptr, "glDepthRangeIndexedfOES"); - glad_glDisableiOES = (PFNGLDISABLEIOESPROC) load(userptr, "glDisableiOES"); - glad_glEnableiOES = (PFNGLENABLEIOESPROC) load(userptr, "glEnableiOES"); - glad_glGetFloati_vOES = (PFNGLGETFLOATI_VOESPROC) load(userptr, "glGetFloati_vOES"); - glad_glIsEnablediOES = (PFNGLISENABLEDIOESPROC) load(userptr, "glIsEnablediOES"); - glad_glScissorArrayvOES = (PFNGLSCISSORARRAYVOESPROC) load(userptr, "glScissorArrayvOES"); - glad_glScissorIndexedOES = (PFNGLSCISSORINDEXEDOESPROC) load(userptr, "glScissorIndexedOES"); - glad_glScissorIndexedvOES = (PFNGLSCISSORINDEXEDVOESPROC) load(userptr, "glScissorIndexedvOES"); - glad_glViewportArrayvOES = (PFNGLVIEWPORTARRAYVOESPROC) load(userptr, "glViewportArrayvOES"); - glad_glViewportIndexedfOES = (PFNGLVIEWPORTINDEXEDFOESPROC) load(userptr, "glViewportIndexedfOES"); - glad_glViewportIndexedfvOES = (PFNGLVIEWPORTINDEXEDFVOESPROC) load(userptr, "glViewportIndexedfvOES"); -} - - - -#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) -#define GLAD_GL_IS_SOME_NEW_VERSION 1 -#else -#define GLAD_GL_IS_SOME_NEW_VERSION 0 -#endif - -static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { -#if GLAD_GL_IS_SOME_NEW_VERSION - if(GLAD_VERSION_MAJOR(version) < 3) { -#else - GLAD_UNUSED(version); - GLAD_UNUSED(out_num_exts_i); - GLAD_UNUSED(out_exts_i); -#endif - if (glad_glGetString == NULL) { - return 0; - } - *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); -#if GLAD_GL_IS_SOME_NEW_VERSION - } else { - unsigned int index = 0; - unsigned int num_exts_i = 0; - char **exts_i = NULL; - if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { - return 0; - } - glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); - if (num_exts_i > 0) { - exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); - } - if (exts_i == NULL) { - return 0; - } - for(index = 0; index < num_exts_i; index++) { - const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); - size_t len = strlen(gl_str_tmp) + 1; - - char *local_str = (char*) malloc(len * sizeof(char)); - if(local_str != NULL) { - memcpy(local_str, gl_str_tmp, len * sizeof(char)); - } - - exts_i[index] = local_str; - } - - *out_num_exts_i = num_exts_i; - *out_exts_i = exts_i; - } -#endif - return 1; -} -static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { - if (exts_i != NULL) { - unsigned int index; - for(index = 0; index < num_exts_i; index++) { - free((void *) (exts_i[index])); - } - free((void *)exts_i); - exts_i = NULL; - } -} -static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { - if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { - const char *extensions; - const char *loc; - const char *terminator; - extensions = exts; - if(extensions == NULL || ext == NULL) { - return 0; - } - while(1) { - loc = strstr(extensions, ext); - if(loc == NULL) { - return 0; - } - terminator = loc + strlen(ext); - if((loc == extensions || *(loc - 1) == ' ') && - (*terminator == ' ' || *terminator == '\0')) { - return 1; - } - extensions = terminator; - } - } else { - unsigned int index; - for(index = 0; index < num_exts_i; index++) { - const char *e = exts_i[index]; - if(strcmp(e, ext) == 0) { - return 1; - } - } - } - return 0; -} - -static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { - return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); -} - -static int glad_gl_find_extensions_gles2( int version) { - const char *exts = NULL; - unsigned int num_exts_i = 0; - char **exts_i = NULL; - if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; - - GLAD_GL_EXT_EGL_image_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_array"); - GLAD_GL_EXT_EGL_image_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_storage"); - GLAD_GL_EXT_EGL_image_storage_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_storage_compression"); - GLAD_GL_EXT_YUV_target = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_YUV_target"); - GLAD_GL_EXT_base_instance = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_base_instance"); - GLAD_GL_EXT_blend_func_extended = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_func_extended"); - GLAD_GL_EXT_blend_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_minmax"); - GLAD_GL_EXT_buffer_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_buffer_storage"); - GLAD_GL_EXT_clear_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clear_texture"); - GLAD_GL_EXT_clip_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clip_control"); - GLAD_GL_EXT_clip_cull_distance = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clip_cull_distance"); - GLAD_GL_EXT_color_buffer_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_color_buffer_float"); - GLAD_GL_EXT_color_buffer_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_color_buffer_half_float"); - GLAD_GL_EXT_conservative_depth = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_conservative_depth"); - GLAD_GL_EXT_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_copy_image"); - GLAD_GL_EXT_debug_label = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_debug_label"); - GLAD_GL_EXT_debug_marker = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_debug_marker"); - GLAD_GL_EXT_depth_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_depth_clamp"); - GLAD_GL_EXT_discard_framebuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_discard_framebuffer"); - GLAD_GL_EXT_disjoint_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_disjoint_timer_query"); - GLAD_GL_EXT_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_buffers"); - GLAD_GL_EXT_draw_buffers_indexed = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_buffers_indexed"); - GLAD_GL_EXT_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_elements_base_vertex"); - GLAD_GL_EXT_draw_instanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_instanced"); - GLAD_GL_EXT_draw_transform_feedback = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_transform_feedback"); - GLAD_GL_EXT_external_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_external_buffer"); - GLAD_GL_EXT_float_blend = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_float_blend"); - GLAD_GL_EXT_fragment_shading_rate = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_fragment_shading_rate"); - GLAD_GL_EXT_geometry_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_geometry_point_size"); - GLAD_GL_EXT_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_geometry_shader"); - GLAD_GL_EXT_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_gpu_shader5"); - GLAD_GL_EXT_instanced_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_instanced_arrays"); - GLAD_GL_EXT_map_buffer_range = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_map_buffer_range"); - GLAD_GL_EXT_memory_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object"); - GLAD_GL_EXT_memory_object_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_fd"); - GLAD_GL_EXT_memory_object_win32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_win32"); - GLAD_GL_EXT_multi_draw_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multi_draw_arrays"); - GLAD_GL_EXT_multi_draw_indirect = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multi_draw_indirect"); - GLAD_GL_EXT_multisampled_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_compatibility"); - GLAD_GL_EXT_multisampled_render_to_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_render_to_texture"); - GLAD_GL_EXT_multisampled_render_to_texture2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_render_to_texture2"); - GLAD_GL_EXT_multiview_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_draw_buffers"); - GLAD_GL_EXT_multiview_tessellation_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_tessellation_geometry_shader"); - GLAD_GL_EXT_multiview_texture_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_texture_multisample"); - GLAD_GL_EXT_multiview_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_timer_query"); - GLAD_GL_EXT_occlusion_query_boolean = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_occlusion_query_boolean"); - GLAD_GL_EXT_polygon_offset_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_polygon_offset_clamp"); - GLAD_GL_EXT_post_depth_coverage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_post_depth_coverage"); - GLAD_GL_EXT_primitive_bounding_box = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_primitive_bounding_box"); - GLAD_GL_EXT_protected_textures = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_protected_textures"); - GLAD_GL_EXT_pvrtc_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_pvrtc_sRGB"); - GLAD_GL_EXT_raster_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_raster_multisample"); - GLAD_GL_EXT_read_format_bgra = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_read_format_bgra"); - GLAD_GL_EXT_render_snorm = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_render_snorm"); - GLAD_GL_EXT_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_robustness"); - GLAD_GL_EXT_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sRGB"); - GLAD_GL_EXT_sRGB_write_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sRGB_write_control"); - GLAD_GL_EXT_semaphore = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore"); - GLAD_GL_EXT_semaphore_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore_fd"); - GLAD_GL_EXT_semaphore_win32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore_win32"); - GLAD_GL_EXT_separate_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_separate_depth_stencil"); - GLAD_GL_EXT_separate_shader_objects = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_separate_shader_objects"); - GLAD_GL_EXT_shader_framebuffer_fetch = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_framebuffer_fetch"); - GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_framebuffer_fetch_non_coherent"); - GLAD_GL_EXT_shader_group_vote = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_group_vote"); - GLAD_GL_EXT_shader_implicit_conversions = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_implicit_conversions"); - GLAD_GL_EXT_shader_integer_mix = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_integer_mix"); - GLAD_GL_EXT_shader_io_blocks = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_io_blocks"); - GLAD_GL_EXT_shader_non_constant_global_initializers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_non_constant_global_initializers"); - GLAD_GL_EXT_shader_pixel_local_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_pixel_local_storage"); - GLAD_GL_EXT_shader_pixel_local_storage2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_pixel_local_storage2"); - GLAD_GL_EXT_shader_samples_identical = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_samples_identical"); - GLAD_GL_EXT_shader_texture_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_texture_lod"); - GLAD_GL_EXT_shadow_samplers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shadow_samplers"); - GLAD_GL_EXT_sparse_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sparse_texture"); - GLAD_GL_EXT_sparse_texture2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sparse_texture2"); - GLAD_GL_EXT_tessellation_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_tessellation_point_size"); - GLAD_GL_EXT_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_tessellation_shader"); - GLAD_GL_EXT_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_border_clamp"); - GLAD_GL_EXT_texture_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_buffer"); - GLAD_GL_EXT_texture_compression_astc_decode_mode = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_astc_decode_mode"); - GLAD_GL_EXT_texture_compression_bptc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_bptc"); - GLAD_GL_EXT_texture_compression_dxt1 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_dxt1"); - GLAD_GL_EXT_texture_compression_rgtc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_rgtc"); - GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc"); - GLAD_GL_EXT_texture_compression_s3tc_srgb = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc_srgb"); - GLAD_GL_EXT_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_cube_map_array"); - GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_anisotropic"); - GLAD_GL_EXT_texture_filter_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_minmax"); - GLAD_GL_EXT_texture_format_BGRA8888 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_BGRA8888"); - GLAD_GL_EXT_texture_format_sRGB_override = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_sRGB_override"); - GLAD_GL_EXT_texture_mirror_clamp_to_edge = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_mirror_clamp_to_edge"); - GLAD_GL_EXT_texture_norm16 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_norm16"); - GLAD_GL_EXT_texture_query_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_query_lod"); - GLAD_GL_EXT_texture_rg = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_rg"); - GLAD_GL_EXT_texture_sRGB_R8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_R8"); - GLAD_GL_EXT_texture_sRGB_RG8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_RG8"); - GLAD_GL_EXT_texture_sRGB_decode = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_decode"); - GLAD_GL_EXT_texture_shadow_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_shadow_lod"); - GLAD_GL_EXT_texture_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_storage"); - GLAD_GL_EXT_texture_storage_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_storage_compression"); - GLAD_GL_EXT_texture_type_2_10_10_10_REV = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_type_2_10_10_10_REV"); - GLAD_GL_EXT_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_view"); - GLAD_GL_EXT_unpack_subimage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_unpack_subimage"); - GLAD_GL_EXT_win32_keyed_mutex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_win32_keyed_mutex"); - GLAD_GL_EXT_window_rectangles = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_window_rectangles"); - GLAD_GL_KHR_blend_equation_advanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_blend_equation_advanced"); - GLAD_GL_KHR_blend_equation_advanced_coherent = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_blend_equation_advanced_coherent"); - GLAD_GL_KHR_context_flush_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_context_flush_control"); - GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug"); - GLAD_GL_KHR_no_error = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_no_error"); - GLAD_GL_KHR_parallel_shader_compile = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_parallel_shader_compile"); - GLAD_GL_KHR_robust_buffer_access_behavior = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_robust_buffer_access_behavior"); - GLAD_GL_KHR_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_robustness"); - GLAD_GL_KHR_shader_subgroup = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_shader_subgroup"); - GLAD_GL_KHR_texture_compression_astc_hdr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_hdr"); - GLAD_GL_KHR_texture_compression_astc_ldr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_ldr"); - GLAD_GL_KHR_texture_compression_astc_sliced_3d = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_sliced_3d"); - GLAD_GL_OES_EGL_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image"); - GLAD_GL_OES_EGL_image_external = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image_external"); - GLAD_GL_OES_EGL_image_external_essl3 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image_external_essl3"); - GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_ETC1_RGB8_sub_texture"); - GLAD_GL_OES_compressed_ETC1_RGB8_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_ETC1_RGB8_texture"); - GLAD_GL_OES_compressed_paletted_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_paletted_texture"); - GLAD_GL_OES_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_copy_image"); - GLAD_GL_OES_depth24 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth24"); - GLAD_GL_OES_depth32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth32"); - GLAD_GL_OES_depth_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth_texture"); - GLAD_GL_OES_draw_buffers_indexed = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_draw_buffers_indexed"); - GLAD_GL_OES_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_draw_elements_base_vertex"); - GLAD_GL_OES_element_index_uint = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_element_index_uint"); - GLAD_GL_OES_fbo_render_mipmap = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fbo_render_mipmap"); - GLAD_GL_OES_fragment_precision_high = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fragment_precision_high"); - GLAD_GL_OES_geometry_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_geometry_point_size"); - GLAD_GL_OES_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_geometry_shader"); - GLAD_GL_OES_get_program_binary = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_get_program_binary"); - GLAD_GL_OES_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_gpu_shader5"); - GLAD_GL_OES_mapbuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_mapbuffer"); - GLAD_GL_OES_packed_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_packed_depth_stencil"); - GLAD_GL_OES_primitive_bounding_box = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_primitive_bounding_box"); - GLAD_GL_OES_required_internalformat = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_required_internalformat"); - GLAD_GL_OES_rgb8_rgba8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_rgb8_rgba8"); - GLAD_GL_OES_sample_shading = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_sample_shading"); - GLAD_GL_OES_sample_variables = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_sample_variables"); - GLAD_GL_OES_shader_image_atomic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_image_atomic"); - GLAD_GL_OES_shader_io_blocks = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_io_blocks"); - GLAD_GL_OES_shader_multisample_interpolation = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_multisample_interpolation"); - GLAD_GL_OES_standard_derivatives = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_standard_derivatives"); - GLAD_GL_OES_stencil1 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_stencil1"); - GLAD_GL_OES_stencil4 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_stencil4"); - GLAD_GL_OES_surfaceless_context = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_surfaceless_context"); - GLAD_GL_OES_tessellation_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_tessellation_point_size"); - GLAD_GL_OES_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_tessellation_shader"); - GLAD_GL_OES_texture_3D = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_3D"); - GLAD_GL_OES_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_border_clamp"); - GLAD_GL_OES_texture_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_buffer"); - GLAD_GL_OES_texture_compression_astc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_compression_astc"); - GLAD_GL_OES_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_cube_map_array"); - GLAD_GL_OES_texture_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_float"); - GLAD_GL_OES_texture_float_linear = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_float_linear"); - GLAD_GL_OES_texture_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_half_float"); - GLAD_GL_OES_texture_half_float_linear = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_half_float_linear"); - GLAD_GL_OES_texture_npot = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_npot"); - GLAD_GL_OES_texture_stencil8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_stencil8"); - GLAD_GL_OES_texture_storage_multisample_2d_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_storage_multisample_2d_array"); - GLAD_GL_OES_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_view"); - GLAD_GL_OES_vertex_array_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_array_object"); - GLAD_GL_OES_vertex_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_half_float"); - GLAD_GL_OES_vertex_type_10_10_10_2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_type_10_10_10_2"); - GLAD_GL_OES_viewport_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_viewport_array"); - - glad_gl_free_extensions(exts_i, num_exts_i); - - return 1; -} - -static int glad_gl_find_core_gles2(void) { - int i; - const char* version; - const char* prefixes[] = { - "OpenGL ES-CM ", - "OpenGL ES-CL ", - "OpenGL ES ", - "OpenGL SC ", - NULL - }; - int major = 0; - int minor = 0; - version = (const char*) glad_glGetString(GL_VERSION); - if (!version) return 0; - for (i = 0; prefixes[i]; i++) { - const size_t length = strlen(prefixes[i]); - if (strncmp(version, prefixes[i], length) == 0) { - version += length; - break; - } - } - - GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); - - GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; - - return GLAD_MAKE_VERSION(major, minor); -} - -int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) { - int version; - - glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); - if(glad_glGetString == NULL) return 0; - if(glad_glGetString(GL_VERSION) == NULL) return 0; - version = glad_gl_find_core_gles2(); - - glad_gl_load_GL_ES_VERSION_2_0(load, userptr); - - if (!glad_gl_find_extensions_gles2(version)) return 0; - glad_gl_load_GL_EXT_EGL_image_storage(load, userptr); - glad_gl_load_GL_EXT_base_instance(load, userptr); - glad_gl_load_GL_EXT_blend_func_extended(load, userptr); - glad_gl_load_GL_EXT_buffer_storage(load, userptr); - glad_gl_load_GL_EXT_clear_texture(load, userptr); - glad_gl_load_GL_EXT_clip_control(load, userptr); - glad_gl_load_GL_EXT_copy_image(load, userptr); - glad_gl_load_GL_EXT_debug_label(load, userptr); - glad_gl_load_GL_EXT_debug_marker(load, userptr); - glad_gl_load_GL_EXT_discard_framebuffer(load, userptr); - glad_gl_load_GL_EXT_disjoint_timer_query(load, userptr); - glad_gl_load_GL_EXT_draw_buffers(load, userptr); - glad_gl_load_GL_EXT_draw_buffers_indexed(load, userptr); - glad_gl_load_GL_EXT_draw_elements_base_vertex(load, userptr); - glad_gl_load_GL_EXT_draw_instanced(load, userptr); - glad_gl_load_GL_EXT_draw_transform_feedback(load, userptr); - glad_gl_load_GL_EXT_external_buffer(load, userptr); - glad_gl_load_GL_EXT_fragment_shading_rate(load, userptr); - glad_gl_load_GL_EXT_geometry_shader(load, userptr); - glad_gl_load_GL_EXT_instanced_arrays(load, userptr); - glad_gl_load_GL_EXT_map_buffer_range(load, userptr); - glad_gl_load_GL_EXT_memory_object(load, userptr); - glad_gl_load_GL_EXT_memory_object_fd(load, userptr); - glad_gl_load_GL_EXT_memory_object_win32(load, userptr); - glad_gl_load_GL_EXT_multi_draw_arrays(load, userptr); - glad_gl_load_GL_EXT_multi_draw_indirect(load, userptr); - glad_gl_load_GL_EXT_multisampled_render_to_texture(load, userptr); - glad_gl_load_GL_EXT_multiview_draw_buffers(load, userptr); - glad_gl_load_GL_EXT_occlusion_query_boolean(load, userptr); - glad_gl_load_GL_EXT_polygon_offset_clamp(load, userptr); - glad_gl_load_GL_EXT_primitive_bounding_box(load, userptr); - glad_gl_load_GL_EXT_raster_multisample(load, userptr); - glad_gl_load_GL_EXT_robustness(load, userptr); - glad_gl_load_GL_EXT_semaphore(load, userptr); - glad_gl_load_GL_EXT_semaphore_fd(load, userptr); - glad_gl_load_GL_EXT_semaphore_win32(load, userptr); - glad_gl_load_GL_EXT_separate_shader_objects(load, userptr); - glad_gl_load_GL_EXT_shader_framebuffer_fetch_non_coherent(load, userptr); - glad_gl_load_GL_EXT_shader_pixel_local_storage2(load, userptr); - glad_gl_load_GL_EXT_sparse_texture(load, userptr); - glad_gl_load_GL_EXT_tessellation_shader(load, userptr); - glad_gl_load_GL_EXT_texture_border_clamp(load, userptr); - glad_gl_load_GL_EXT_texture_buffer(load, userptr); - glad_gl_load_GL_EXT_texture_storage(load, userptr); - glad_gl_load_GL_EXT_texture_storage_compression(load, userptr); - glad_gl_load_GL_EXT_texture_view(load, userptr); - glad_gl_load_GL_EXT_win32_keyed_mutex(load, userptr); - glad_gl_load_GL_EXT_window_rectangles(load, userptr); - glad_gl_load_GL_KHR_blend_equation_advanced(load, userptr); - glad_gl_load_GL_KHR_debug(load, userptr); - glad_gl_load_GL_KHR_parallel_shader_compile(load, userptr); - glad_gl_load_GL_KHR_robustness(load, userptr); - glad_gl_load_GL_OES_EGL_image(load, userptr); - glad_gl_load_GL_OES_copy_image(load, userptr); - glad_gl_load_GL_OES_draw_buffers_indexed(load, userptr); - glad_gl_load_GL_OES_draw_elements_base_vertex(load, userptr); - glad_gl_load_GL_OES_geometry_shader(load, userptr); - glad_gl_load_GL_OES_get_program_binary(load, userptr); - glad_gl_load_GL_OES_mapbuffer(load, userptr); - glad_gl_load_GL_OES_primitive_bounding_box(load, userptr); - glad_gl_load_GL_OES_sample_shading(load, userptr); - glad_gl_load_GL_OES_tessellation_shader(load, userptr); - glad_gl_load_GL_OES_texture_3D(load, userptr); - glad_gl_load_GL_OES_texture_border_clamp(load, userptr); - glad_gl_load_GL_OES_texture_buffer(load, userptr); - glad_gl_load_GL_OES_texture_storage_multisample_2d_array(load, userptr); - glad_gl_load_GL_OES_texture_view(load, userptr); - glad_gl_load_GL_OES_vertex_array_object(load, userptr); - glad_gl_load_GL_OES_viewport_array(load, userptr); - - - - return version; -} - - -int gladLoadGLES2( GLADloadfunc load) { - return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); -} - - - - - - -#ifdef __cplusplus -} -#endif - -#endif /* GLAD_GLES2_IMPLEMENTATION */ - diff --git a/raylib/external/glfw/LICENSE.md b/raylib/external/glfw/COPYING.txt similarity index 93% rename from raylib/external/glfw/LICENSE.md rename to raylib/external/glfw/COPYING.txt index 7494a3f..ad16462 100644 --- a/raylib/external/glfw/LICENSE.md +++ b/raylib/external/glfw/COPYING.txt @@ -1,6 +1,5 @@ Copyright (c) 2002-2006 Marcus Geelnard - -Copyright (c) 2006-2019 Camilla Löwy +Copyright (c) 2006-2016 Camilla Berglund This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/raylib/external/glfw/deps/getopt.c b/raylib/external/glfw/deps/getopt.c new file mode 100644 index 0000000..9743046 --- /dev/null +++ b/raylib/external/glfw/deps/getopt.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "getopt.h" + +#include +#include + +const int no_argument = 0; +const int required_argument = 1; +const int optional_argument = 2; + +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; + +static char* optcursor = NULL; + +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. + +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE +*/ +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; + + optarg = NULL; + opterr = 0; + optopt = 0; + + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) + goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') + optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for example, + "-oarg"), then it is returned in optarg, otherwise optarg is set + to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string pointed to by + an element of argv, then optarg shall contain the next element + of argv, and optind shall be incremented by 2. If the resulting + value of optind is greater than argc, this indicates a missing + option-argument, and getopt() shall return an error indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind shall be + incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall return the + colon character ( ':' ) if the first character of optstring + was a colon, or a question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') + ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; +} + +/* Implementation based on [1]. + +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +*/ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) + return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) + *longindex = (int) (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a variable + which shall be set to val if the option is found, but left unchanged if + the option is not found. */ + if (match->flag) + *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) + ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) + retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and BSD-based + implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/raylib/external/glfw/deps/getopt.h b/raylib/external/glfw/deps/getopt.h new file mode 100644 index 0000000..e1eb540 --- /dev/null +++ b/raylib/external/glfw/deps/getopt.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +extern const int no_argument; +extern const int required_argument; +extern const int optional_argument; + +extern char* optarg; +extern int optind, opterr, optopt; + +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; + +int getopt(int argc, char* const argv[], const char* optstring); + +int getopt_long(int argc, char* const argv[], + const char* optstring, const struct option* longopts, int* longindex); + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_GETOPT_PORT_H diff --git a/raylib/external/glfw/deps/glad/gl.h b/raylib/external/glfw/deps/glad/gl.h new file mode 100644 index 0000000..5c7879f --- /dev/null +++ b/raylib/external/glfw/deps/glad/gl.h @@ -0,0 +1,3840 @@ +/** + * Loader generated by glad 2.0.0-beta on Sun Apr 14 17:03:32 2019 + * + * Generator: C/C++ + * Specification: gl + * Extensions: 3 + * + * APIs: + * - gl:compatibility=3.3 + * + * Options: + * - MX_GLOBAL = False + * - LOADER = False + * - ALIAS = False + * - HEADER_ONLY = False + * - DEBUG = False + * - MX = False + * + * Commandline: + * --api='gl:compatibility=3.3' --extensions='GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug' c + * + * Online: + * http://glad.sh/#api=gl%3Acompatibility%3D3.3&extensions=GL_ARB_multisample%2CGL_ARB_robustness%2CGL_KHR_debug&generator=c&options= + * + */ + +#ifndef GLAD_GL_H_ +#define GLAD_GL_H_ + +#ifdef __gl_h_ + #error OpenGL header already included (API: gl), remove previous include! +#endif +#define __gl_h_ 1 + + +#define GLAD_GL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(const char *name, void *userptr); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define GL_2D 0x0600 +#define GL_2_BYTES 0x1407 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_3_BYTES 0x1408 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_4_BYTES 0x1409 +#define GL_ACCUM 0x0100 +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ADD 0x0104 +#define GL_ADD_SIGNED 0x8574 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_ALPHA 0x1906 +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_ALPHA_BITS 0x0D55 +#define GL_ALPHA_INTEGER 0x8D97 +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_ALWAYS 0x0207 +#define GL_AMBIENT 0x1200 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_AND 0x1501 +#define GL_AND_INVERTED 0x1504 +#define GL_AND_REVERSE 0x1502 +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_AUX_BUFFERS 0x0C00 +#define GL_BACK 0x0405 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_BGRA_INTEGER 0x8D9B +#define GL_BGR_INTEGER 0x8D9A +#define GL_BITMAP 0x1A00 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLUE 0x1905 +#define GL_BLUE_BIAS 0x0D1B +#define GL_BLUE_BITS 0x0D54 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_BUFFER 0x82E0 +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_BYTE 0x1400 +#define GL_C3F_V3F 0x2A24 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_CCW 0x0901 +#define GL_CLAMP 0x2900 +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLEAR 0x1500 +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_COEFF 0x0A00 +#define GL_COLOR 0x1800 +#define GL_COLOR_ARRAY 0x8076 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_INDEX 0x1900 +#define GL_COLOR_INDEXES 0x1603 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_COLOR_SUM 0x8458 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_COMBINE 0x8570 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_RG 0x8226 +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CONDITION_SATISFIED 0x911C +#define GL_CONSTANT 0x8576 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_FLAGS 0x821E +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_COORD_REPLACE 0x8862 +#define GL_COPY 0x1503 +#define GL_COPY_INVERTED 0x150C +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_CURRENT_BIT 0x00000001 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_CURRENT_QUERY 0x8865 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_CW 0x0900 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DECAL 0x2101 +#define GL_DECR 0x1E03 +#define GL_DECR_WRAP 0x8508 +#define GL_DELETE_STATUS 0x8B80 +#define GL_DEPTH 0x1801 +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_DEPTH_BIAS 0x0D1F +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_DEPTH_CLAMP 0x864F +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DIFFUSE 0x1201 +#define GL_DISPLAY_LIST 0x82E7 +#define GL_DITHER 0x0BD0 +#define GL_DOMAIN 0x0A02 +#define GL_DONT_CARE 0x1100 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +#define GL_DOUBLE 0x140A +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_DST_ALPHA 0x0304 +#define GL_DST_COLOR 0x0306 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_EDGE_FLAG 0x0B43 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_EMISSION 0x1600 +#define GL_ENABLE_BIT 0x00002000 +#define GL_EQUAL 0x0202 +#define GL_EQUIV 0x1509 +#define GL_EVAL_BIT 0x00010000 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 +#define GL_EXTENSIONS 0x1F03 +#define GL_EYE_LINEAR 0x2400 +#define GL_EYE_PLANE 0x2502 +#define GL_FALSE 0 +#define GL_FASTEST 0x1101 +#define GL_FEEDBACK 0x1C01 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_FILL 0x1B02 +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_FIXED_ONLY 0x891D +#define GL_FLAT 0x1D00 +#define GL_FLOAT 0x1406 +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4 0x8B5C +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FOG 0x0B60 +#define GL_FOG_BIT 0x00000080 +#define GL_FOG_COLOR 0x0B66 +#define GL_FOG_COORD 0x8451 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_END 0x0B64 +#define GL_FOG_HINT 0x0C54 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_START 0x0B63 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRONT 0x0404 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_FRONT_FACE 0x0B46 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEQUAL 0x0206 +#define GL_GREATER 0x0204 +#define GL_GREEN 0x1904 +#define GL_GREEN_BIAS 0x0D19 +#define GL_GREEN_BITS 0x0D53 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_HALF_FLOAT 0x140B +#define GL_HINT_BIT 0x00008000 +#define GL_INCR 0x1E02 +#define GL_INCR_WRAP 0x8507 +#define GL_INDEX 0x8222 +#define GL_INDEX_ARRAY 0x8077 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_BITS 0x0D51 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_INDEX_MODE 0x0C30 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_INT 0x1404 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_INTERPOLATE 0x8575 +#define GL_INT_2_10_10_10_REV 0x8D9F +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_INVALID_OPERATION 0x0502 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVERT 0x150A +#define GL_KEEP 0x1E00 +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_LEFT 0x0406 +#define GL_LEQUAL 0x0203 +#define GL_LESS 0x0201 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LINE 0x1B01 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINES 0x0001 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_BIT 0x00000004 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_LINE_TOKEN 0x0702 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINK_STATUS 0x8B82 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_BIT 0x00020000 +#define GL_LIST_INDEX 0x0B33 +#define GL_LIST_MODE 0x0B30 +#define GL_LOAD 0x0101 +#define GL_LOGIC_OP 0x0BF1 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_MAJOR_VERSION 0x821B +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_STENCIL 0x0D11 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_MAX 0x8008 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MIN 0x8007 +#define GL_MINOR_VERSION 0x821C +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MODELVIEW 0x1700 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_MODULATE 0x2100 +#define GL_MULT 0x0103 +#define GL_MULTISAMPLE 0x809D +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +#define GL_N3F_V3F 0x2A25 +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_NAND 0x150E +#define GL_NEAREST 0x2600 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEVER 0x0200 +#define GL_NICEST 0x1102 +#define GL_NONE 0 +#define GL_NOOP 0x1505 +#define GL_NOR 0x1508 +#define GL_NORMALIZE 0x0BA1 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_MAP 0x8511 +#define GL_NOTEQUAL 0x0205 +#define GL_NO_ERROR 0 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_NUM_EXTENSIONS 0x821D +#define GL_OBJECT_LINEAR 0x2401 +#define GL_OBJECT_PLANE 0x2501 +#define GL_OBJECT_TYPE 0x9112 +#define GL_ONE 1 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_OPERAND2_RGB 0x8592 +#define GL_OR 0x1507 +#define GL_ORDER 0x0A01 +#define GL_OR_INVERTED 0x150D +#define GL_OR_REVERSE 0x150B +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_POINT 0x1B00 +#define GL_POINTS 0x0000 +#define GL_POINT_BIT 0x00000002 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_POINT_SPRITE 0x8861 +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_POINT_TOKEN 0x0701 +#define GL_POLYGON 0x0009 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_POSITION 0x1203 +#define GL_PREVIOUS 0x8578 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_PROGRAM 0x82E2 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_PROJECTION 0x1701 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_Q 0x2003 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_QUADS 0x0007 +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_QUAD_STRIP 0x0008 +#define GL_QUERY 0x82E3 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_QUERY_WAIT 0x8E13 +#define GL_R 0x2002 +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_R16 0x822A +#define GL_R16F 0x822D +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R16_SNORM 0x8F98 +#define GL_R32F 0x822E +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_R3_G3_B2 0x2A10 +#define GL_R8 0x8229 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R8_SNORM 0x8F94 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_READ_BUFFER 0x0C02 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_READ_ONLY 0x88B8 +#define GL_READ_WRITE 0x88BA +#define GL_RED 0x1903 +#define GL_RED_BIAS 0x0D15 +#define GL_RED_BITS 0x0D52 +#define GL_RED_INTEGER 0x8D94 +#define GL_RED_SCALE 0x0D14 +#define GL_REFLECTION_MAP 0x8512 +#define GL_RENDER 0x1C00 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERER 0x1F01 +#define GL_RENDER_MODE 0x0C40 +#define GL_REPEAT 0x2901 +#define GL_REPLACE 0x1E01 +#define GL_RESCALE_NORMAL 0x803A +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_RETURN 0x0102 +#define GL_RG 0x8227 +#define GL_RG16 0x822C +#define GL_RG16F 0x822F +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG16_SNORM 0x8F99 +#define GL_RG32F 0x8230 +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_RG8 0x822B +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB 0x1907 +#define GL_RGB10 0x8052 +#define GL_RGB10_A2 0x8059 +#define GL_RGB10_A2UI 0x906F +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGB16F 0x881B +#define GL_RGB16I 0x8D89 +#define GL_RGB16UI 0x8D77 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGB32F 0x8815 +#define GL_RGB32I 0x8D83 +#define GL_RGB32UI 0x8D71 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB5_A1 0x8057 +#define GL_RGB8 0x8051 +#define GL_RGB8I 0x8D8F +#define GL_RGB8UI 0x8D7D +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGB9_E5 0x8C3D +#define GL_RGBA 0x1908 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_RGBA16F 0x881A +#define GL_RGBA16I 0x8D88 +#define GL_RGBA16UI 0x8D76 +#define GL_RGBA16_SNORM 0x8F9B +#define GL_RGBA2 0x8055 +#define GL_RGBA32F 0x8814 +#define GL_RGBA32I 0x8D82 +#define GL_RGBA32UI 0x8D70 +#define GL_RGBA4 0x8056 +#define GL_RGBA8 0x8058 +#define GL_RGBA8I 0x8D8E +#define GL_RGBA8UI 0x8D7C +#define GL_RGBA8_SNORM 0x8F97 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_RGBA_MODE 0x0C31 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGB_SCALE 0x8573 +#define GL_RG_INTEGER 0x8228 +#define GL_RIGHT 0x0407 +#define GL_S 0x2000 +#define GL_SAMPLER 0x82E6 +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SELECT 0x1C02 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_SET 0x150F +#define GL_SHADER 0x82E1 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_TYPE 0x8B4F +#define GL_SHADE_MODEL 0x0B54 +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_SHININESS 0x1601 +#define GL_SHORT 0x1402 +#define GL_SIGNALED 0x9119 +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SMOOTH 0x1D01 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_SOURCE2_RGB 0x8582 +#define GL_SPECULAR 0x1202 +#define GL_SPHERE_MAP 0x2402 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_ALPHA 0x8589 +#define GL_SRC1_COLOR 0x88F9 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_ALPHA 0x858A +#define GL_SRC2_RGB 0x8582 +#define GL_SRC_ALPHA 0x0302 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_SRC_COLOR 0x0300 +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_STATIC_COPY 0x88E6 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_INDEX 0x1901 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STEREO 0x0C33 +#define GL_STREAM_COPY 0x88E2 +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_SUBTRACT 0x84E7 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_SYNC_STATUS 0x9114 +#define GL_T 0x2001 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_T4F_V4F 0x2A28 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_TEXTURE_3D 0x806F +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_TEXTURE_ENV 0x2300 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_TIMESTAMP 0x8E28 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_FAN 0x0006 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_TRUE 1 +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNSIGNALED 0x9118 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_INT 0x1405 +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_VENDOR 0x1F00 +#define GL_VERSION 0x1F02 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_VIEWPORT 0x0BA2 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_WAIT_FAILED 0x911D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_WRITE_ONLY 0x88B9 +#define GL_XOR 0x1506 +#define GL_ZERO 0 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 + + +#include +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptr; +#else +typedef khronos_intptr_t GLintptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptrARB; +#else +typedef khronos_intptr_t GLintptrARB; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptr; +#else +typedef khronos_ssize_t GLsizeiptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptrARB; +#else +typedef khronos_ssize_t GLsizeiptrARB; +#endif +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void ( *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void ( *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void ( *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void ( *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void ( *GLVULKANPROCNV)(void); + + +#define GL_VERSION_1_0 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_0; +#define GL_VERSION_1_1 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_1; +#define GL_VERSION_1_2 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_2; +#define GL_VERSION_1_3 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_3; +#define GL_VERSION_1_4 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_4; +#define GL_VERSION_1_5 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_5; +#define GL_VERSION_2_0 1 +GLAD_API_CALL int GLAD_GL_VERSION_2_0; +#define GL_VERSION_2_1 1 +GLAD_API_CALL int GLAD_GL_VERSION_2_1; +#define GL_VERSION_3_0 1 +GLAD_API_CALL int GLAD_GL_VERSION_3_0; +#define GL_VERSION_3_1 1 +GLAD_API_CALL int GLAD_GL_VERSION_3_1; +#define GL_VERSION_3_2 1 +GLAD_API_CALL int GLAD_GL_VERSION_3_2; +#define GL_VERSION_3_3 1 +GLAD_API_CALL int GLAD_GL_VERSION_3_3; +#define GL_ARB_multisample 1 +GLAD_API_CALL int GLAD_GL_ARB_multisample; +#define GL_ARB_robustness 1 +GLAD_API_CALL int GLAD_GL_ARB_robustness; +#define GL_KHR_debug 1 +GLAD_API_CALL int GLAD_GL_KHR_debug; + + +typedef void (GLAD_API_PTR *PFNGLACCUMPROC)(GLenum op, GLfloat value); +typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); +typedef GLboolean (GLAD_API_PTR *PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint * textures, GLboolean * residences); +typedef void (GLAD_API_PTR *PFNGLARRAYELEMENTPROC)(GLint i); +typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLBEGINPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); +typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array); +typedef void (GLAD_API_PTR *PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte * bitmap); +typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); +typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); +typedef void (GLAD_API_PTR *PFNGLCALLLISTPROC)(GLuint list); +typedef void (GLAD_API_PTR *PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void * lists); +typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth); +typedef void (GLAD_API_PTR *PFNGLCLEARINDEXPROC)(GLfloat c); +typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); +typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GLAD_API_PTR *PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble * equation); +typedef void (GLAD_API_PTR *PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UBVPROC)(const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UIVPROC)(const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3USVPROC)(const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UBVPROC)(const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UIVPROC)(const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4USVPROC)(const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (GLAD_API_PTR *PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); +typedef void (GLAD_API_PTR *PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint * color); +typedef void (GLAD_API_PTR *PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); +typedef void (GLAD_API_PTR *PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint * color); +typedef void (GLAD_API_PTR *PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); +typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void * userParam); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); +typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint * samplers); +typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync); +typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays); +typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); +typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); +typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLDISABLECLIENTSTATEPROC)(GLenum array); +typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLEDGEFLAGVPROC)(const GLboolean * flag); +typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLENABLECLIENTSTATEPROC)(GLenum array); +typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLENDPROC)(void); +typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void); +typedef void (GLAD_API_PTR *PFNGLENDLISTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DPROC)(GLdouble u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DVPROC)(const GLdouble * u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FPROC)(GLfloat u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FVPROC)(const GLfloat * u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DVPROC)(const GLdouble * u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FVPROC)(const GLfloat * u); +typedef void (GLAD_API_PTR *PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); +typedef void (GLAD_API_PTR *PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +typedef void (GLAD_API_PTR *PFNGLEVALPOINT1PROC)(GLint i); +typedef void (GLAD_API_PTR *PFNGLEVALPOINT2PROC)(GLint i, GLint j); +typedef void (GLAD_API_PTR *PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat * buffer); +typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDDPROC)(GLdouble coord); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDDVPROC)(const GLdouble * coord); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDFPROC)(GLfloat coord); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDFVPROC)(const GLfloat * coord); +typedef void (GLAD_API_PTR *PFNGLFOGFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLFOGFVPROC)(GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLFOGIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLFOGIVPROC)(GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); +typedef GLuint (GLAD_API_PTR *PFNGLGENLISTSPROC)(GLsizei range); +typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint * samplers); +typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays); +typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformBlockName); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformName); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint * uniformIndices, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); +typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data); +typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data); +typedef void (GLAD_API_PTR *PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble * equation); +typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img); +typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); +typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data); +typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); +typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar * name); +typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); +typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSARBPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint * v); +typedef void (GLAD_API_PTR *PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat * values); +typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint * values); +typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort * values); +typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte * mask); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); +typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); +typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); +typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * values); +typedef void (GLAD_API_PTR *PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name); +typedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar * uniformBlockName); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const* uniformNames, GLuint * uniformIndices); +typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNCOLORTABLEARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void * table); +typedef void (GLAD_API_PTR *PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint lod, GLsizei bufSize, void * img); +typedef void (GLAD_API_PTR *PFNGLGETNCONVOLUTIONFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void * image); +typedef void (GLAD_API_PTR *PFNGLGETNHISTOGRAMARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void * values); +typedef void (GLAD_API_PTR *PFNGLGETNMAPDVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLGETNMAPFVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLGETNMAPIVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint * v); +typedef void (GLAD_API_PTR *PFNGLGETNMINMAXARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void * values); +typedef void (GLAD_API_PTR *PFNGLGETNPIXELMAPFVARBPROC)(GLenum map, GLsizei bufSize, GLfloat * values); +typedef void (GLAD_API_PTR *PFNGLGETNPIXELMAPUIVARBPROC)(GLenum map, GLsizei bufSize, GLuint * values); +typedef void (GLAD_API_PTR *PFNGLGETNPIXELMAPUSVARBPROC)(GLenum map, GLsizei bufSize, GLushort * values); +typedef void (GLAD_API_PTR *PFNGLGETNPOLYGONSTIPPLEARBPROC)(GLsizei bufSize, GLubyte * pattern); +typedef void (GLAD_API_PTR *PFNGLGETNSEPARABLEFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void * row, GLsizei columnBufSize, void * column, void * span); +typedef void (GLAD_API_PTR *PFNGLGETNTEXIMAGEARBPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void * img); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMDVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLINDEXMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLINDEXDPROC)(GLdouble c); +typedef void (GLAD_API_PTR *PFNGLINDEXDVPROC)(const GLdouble * c); +typedef void (GLAD_API_PTR *PFNGLINDEXFPROC)(GLfloat c); +typedef void (GLAD_API_PTR *PFNGLINDEXFVPROC)(const GLfloat * c); +typedef void (GLAD_API_PTR *PFNGLINDEXIPROC)(GLint c); +typedef void (GLAD_API_PTR *PFNGLINDEXIVPROC)(const GLint * c); +typedef void (GLAD_API_PTR *PFNGLINDEXSPROC)(GLshort c); +typedef void (GLAD_API_PTR *PFNGLINDEXSVPROC)(const GLshort * c); +typedef void (GLAD_API_PTR *PFNGLINDEXUBPROC)(GLubyte c); +typedef void (GLAD_API_PTR *PFNGLINDEXUBVPROC)(const GLubyte * c); +typedef void (GLAD_API_PTR *PFNGLINITNAMESPROC)(void); +typedef void (GLAD_API_PTR *PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void * pointer); +typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISLISTPROC)(GLuint list); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); +typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id); +typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint sampler); +typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); +typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync); +typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); +typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); +typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); +typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLLISTBASEPROC)(GLuint base); +typedef void (GLAD_API_PTR *PFNGLLOADIDENTITYPROC)(void); +typedef void (GLAD_API_PTR *PFNGLLOADMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLLOADMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLLOADNAMEPROC)(GLuint name); +typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode); +typedef void (GLAD_API_PTR *PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble * points); +typedef void (GLAD_API_PTR *PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat * points); +typedef void (GLAD_API_PTR *PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble * points); +typedef void (GLAD_API_PTR *PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat * points); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GLAD_API_PTR *PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); +typedef void (GLAD_API_PTR *PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); +typedef void (GLAD_API_PTR *PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +typedef void (GLAD_API_PTR *PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLMATRIXMODEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLMULTMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLMULTMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLNEWLISTPROC)(GLuint list, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELPROC)(const void * ptr, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAD_API_PTR *PFNGLPASSTHROUGHPROC)(GLfloat token); +typedef void (GLAD_API_PTR *PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat * values); +typedef void (GLAD_API_PTR *PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint * values); +typedef void (GLAD_API_PTR *PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort * values); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size); +typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void (GLAD_API_PTR *PFNGLPOLYGONSTIPPLEPROC)(const GLubyte * mask); +typedef void (GLAD_API_PTR *PFNGLPOPATTRIBPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPCLIENTATTRIBPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPMATRIXPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPNAMEPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint * textures, const GLfloat * priorities); +typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLPUSHATTRIBPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); +typedef void (GLAD_API_PTR *PFNGLPUSHMATRIXPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPUSHNAMEPROC)(GLuint name); +typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IPROC)(GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src); +typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); +typedef void (GLAD_API_PTR *PFNGLREADNPIXELSARBPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); +typedef void (GLAD_API_PTR *PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +typedef void (GLAD_API_PTR *PFNGLRECTDVPROC)(const GLdouble * v1, const GLdouble * v2); +typedef void (GLAD_API_PTR *PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +typedef void (GLAD_API_PTR *PFNGLRECTFVPROC)(const GLfloat * v1, const GLfloat * v2); +typedef void (GLAD_API_PTR *PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); +typedef void (GLAD_API_PTR *PFNGLRECTIVPROC)(const GLint * v1, const GLint * v2); +typedef void (GLAD_API_PTR *PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +typedef void (GLAD_API_PTR *PFNGLRECTSVPROC)(const GLshort * v1, const GLshort * v2); +typedef GLint (GLAD_API_PTR *PFNGLRENDERMODEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); +typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USVPROC)(const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint * color); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint * buffer); +typedef void (GLAD_API_PTR *PFNGLSHADEMODELPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DPROC)(GLdouble s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FPROC)(GLfloat s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SPROC)(GLshort s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IPROC)(GLint s, GLint t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint * coords); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); +typedef void (GLAD_API_PTR *PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode); +typedef void (GLAD_API_PTR *PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX2IPROC)(GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX2SPROC)(GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); +typedef void (GLAD_API_PTR *PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SVPROC)(const GLshort * v); + +GLAD_API_CALL PFNGLACCUMPROC glad_glAccum; +#define glAccum glad_glAccum +GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +GLAD_API_CALL PFNGLALPHAFUNCPROC glad_glAlphaFunc; +#define glAlphaFunc glad_glAlphaFunc +GLAD_API_CALL PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +#define glAreTexturesResident glad_glAreTexturesResident +GLAD_API_CALL PFNGLARRAYELEMENTPROC glad_glArrayElement; +#define glArrayElement glad_glArrayElement +GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +GLAD_API_CALL PFNGLBEGINPROC glad_glBegin; +#define glBegin glad_glBegin +GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; +#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed +GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +GLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler; +#define glBindSampler glad_glBindSampler +GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +GLAD_API_CALL PFNGLBITMAPPROC glad_glBitmap; +#define glBitmap glad_glBitmap +GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +GLAD_API_CALL PFNGLCALLLISTPROC glad_glCallList; +#define glCallList glad_glCallList +GLAD_API_CALL PFNGLCALLLISTSPROC glad_glCallLists; +#define glCallLists glad_glCallLists +GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +GLAD_API_CALL PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +GLAD_API_CALL PFNGLCLEARACCUMPROC glad_glClearAccum; +#define glClearAccum glad_glClearAccum +GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +GLAD_API_CALL PFNGLCLEARINDEXPROC glad_glClearIndex; +#define glClearIndex glad_glClearIndex +GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +GLAD_API_CALL PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +#define glClientActiveTexture glad_glClientActiveTexture +GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +GLAD_API_CALL PFNGLCLIPPLANEPROC glad_glClipPlane; +#define glClipPlane glad_glClipPlane +GLAD_API_CALL PFNGLCOLOR3BPROC glad_glColor3b; +#define glColor3b glad_glColor3b +GLAD_API_CALL PFNGLCOLOR3BVPROC glad_glColor3bv; +#define glColor3bv glad_glColor3bv +GLAD_API_CALL PFNGLCOLOR3DPROC glad_glColor3d; +#define glColor3d glad_glColor3d +GLAD_API_CALL PFNGLCOLOR3DVPROC glad_glColor3dv; +#define glColor3dv glad_glColor3dv +GLAD_API_CALL PFNGLCOLOR3FPROC glad_glColor3f; +#define glColor3f glad_glColor3f +GLAD_API_CALL PFNGLCOLOR3FVPROC glad_glColor3fv; +#define glColor3fv glad_glColor3fv +GLAD_API_CALL PFNGLCOLOR3IPROC glad_glColor3i; +#define glColor3i glad_glColor3i +GLAD_API_CALL PFNGLCOLOR3IVPROC glad_glColor3iv; +#define glColor3iv glad_glColor3iv +GLAD_API_CALL PFNGLCOLOR3SPROC glad_glColor3s; +#define glColor3s glad_glColor3s +GLAD_API_CALL PFNGLCOLOR3SVPROC glad_glColor3sv; +#define glColor3sv glad_glColor3sv +GLAD_API_CALL PFNGLCOLOR3UBPROC glad_glColor3ub; +#define glColor3ub glad_glColor3ub +GLAD_API_CALL PFNGLCOLOR3UBVPROC glad_glColor3ubv; +#define glColor3ubv glad_glColor3ubv +GLAD_API_CALL PFNGLCOLOR3UIPROC glad_glColor3ui; +#define glColor3ui glad_glColor3ui +GLAD_API_CALL PFNGLCOLOR3UIVPROC glad_glColor3uiv; +#define glColor3uiv glad_glColor3uiv +GLAD_API_CALL PFNGLCOLOR3USPROC glad_glColor3us; +#define glColor3us glad_glColor3us +GLAD_API_CALL PFNGLCOLOR3USVPROC glad_glColor3usv; +#define glColor3usv glad_glColor3usv +GLAD_API_CALL PFNGLCOLOR4BPROC glad_glColor4b; +#define glColor4b glad_glColor4b +GLAD_API_CALL PFNGLCOLOR4BVPROC glad_glColor4bv; +#define glColor4bv glad_glColor4bv +GLAD_API_CALL PFNGLCOLOR4DPROC glad_glColor4d; +#define glColor4d glad_glColor4d +GLAD_API_CALL PFNGLCOLOR4DVPROC glad_glColor4dv; +#define glColor4dv glad_glColor4dv +GLAD_API_CALL PFNGLCOLOR4FPROC glad_glColor4f; +#define glColor4f glad_glColor4f +GLAD_API_CALL PFNGLCOLOR4FVPROC glad_glColor4fv; +#define glColor4fv glad_glColor4fv +GLAD_API_CALL PFNGLCOLOR4IPROC glad_glColor4i; +#define glColor4i glad_glColor4i +GLAD_API_CALL PFNGLCOLOR4IVPROC glad_glColor4iv; +#define glColor4iv glad_glColor4iv +GLAD_API_CALL PFNGLCOLOR4SPROC glad_glColor4s; +#define glColor4s glad_glColor4s +GLAD_API_CALL PFNGLCOLOR4SVPROC glad_glColor4sv; +#define glColor4sv glad_glColor4sv +GLAD_API_CALL PFNGLCOLOR4UBPROC glad_glColor4ub; +#define glColor4ub glad_glColor4ub +GLAD_API_CALL PFNGLCOLOR4UBVPROC glad_glColor4ubv; +#define glColor4ubv glad_glColor4ubv +GLAD_API_CALL PFNGLCOLOR4UIPROC glad_glColor4ui; +#define glColor4ui glad_glColor4ui +GLAD_API_CALL PFNGLCOLOR4UIVPROC glad_glColor4uiv; +#define glColor4uiv glad_glColor4uiv +GLAD_API_CALL PFNGLCOLOR4USPROC glad_glColor4us; +#define glColor4us glad_glColor4us +GLAD_API_CALL PFNGLCOLOR4USVPROC glad_glColor4usv; +#define glColor4usv glad_glColor4usv +GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +GLAD_API_CALL PFNGLCOLORMATERIALPROC glad_glColorMaterial; +#define glColorMaterial glad_glColorMaterial +GLAD_API_CALL PFNGLCOLORP3UIPROC glad_glColorP3ui; +#define glColorP3ui glad_glColorP3ui +GLAD_API_CALL PFNGLCOLORP3UIVPROC glad_glColorP3uiv; +#define glColorP3uiv glad_glColorP3uiv +GLAD_API_CALL PFNGLCOLORP4UIPROC glad_glColorP4ui; +#define glColorP4ui glad_glColorP4ui +GLAD_API_CALL PFNGLCOLORP4UIVPROC glad_glColorP4uiv; +#define glColorP4uiv glad_glColorP4uiv +GLAD_API_CALL PFNGLCOLORPOINTERPROC glad_glColorPointer; +#define glColorPointer glad_glColorPointer +GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +GLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +GLAD_API_CALL PFNGLCOPYPIXELSPROC glad_glCopyPixels; +#define glCopyPixels glad_glCopyPixels +GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; +#define glDebugMessageCallback glad_glDebugMessageCallback +GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; +#define glDebugMessageControl glad_glDebugMessageControl +GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; +#define glDebugMessageInsert glad_glDebugMessageInsert +GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +GLAD_API_CALL PFNGLDELETELISTSPROC glad_glDeleteLists; +#define glDeleteLists glad_glDeleteLists +GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +GLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; +#define glDeleteSamplers glad_glDeleteSamplers +GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +GLAD_API_CALL PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +#define glDisableClientState glad_glDisableClientState +GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +GLAD_API_CALL PFNGLDRAWPIXELSPROC glad_glDrawPixels; +#define glDrawPixels glad_glDrawPixels +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +GLAD_API_CALL PFNGLEDGEFLAGPROC glad_glEdgeFlag; +#define glEdgeFlag glad_glEdgeFlag +GLAD_API_CALL PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +#define glEdgeFlagPointer glad_glEdgeFlagPointer +GLAD_API_CALL PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +#define glEdgeFlagv glad_glEdgeFlagv +GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +GLAD_API_CALL PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +#define glEnableClientState glad_glEnableClientState +GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +GLAD_API_CALL PFNGLENDPROC glad_glEnd; +#define glEnd glad_glEnd +GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +GLAD_API_CALL PFNGLENDLISTPROC glad_glEndList; +#define glEndList glad_glEndList +GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +GLAD_API_CALL PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +#define glEvalCoord1d glad_glEvalCoord1d +GLAD_API_CALL PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +#define glEvalCoord1dv glad_glEvalCoord1dv +GLAD_API_CALL PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +#define glEvalCoord1f glad_glEvalCoord1f +GLAD_API_CALL PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +#define glEvalCoord1fv glad_glEvalCoord1fv +GLAD_API_CALL PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +#define glEvalCoord2d glad_glEvalCoord2d +GLAD_API_CALL PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +#define glEvalCoord2dv glad_glEvalCoord2dv +GLAD_API_CALL PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +#define glEvalCoord2f glad_glEvalCoord2f +GLAD_API_CALL PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +#define glEvalCoord2fv glad_glEvalCoord2fv +GLAD_API_CALL PFNGLEVALMESH1PROC glad_glEvalMesh1; +#define glEvalMesh1 glad_glEvalMesh1 +GLAD_API_CALL PFNGLEVALMESH2PROC glad_glEvalMesh2; +#define glEvalMesh2 glad_glEvalMesh2 +GLAD_API_CALL PFNGLEVALPOINT1PROC glad_glEvalPoint1; +#define glEvalPoint1 glad_glEvalPoint1 +GLAD_API_CALL PFNGLEVALPOINT2PROC glad_glEvalPoint2; +#define glEvalPoint2 glad_glEvalPoint2 +GLAD_API_CALL PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +#define glFeedbackBuffer glad_glFeedbackBuffer +GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +GLAD_API_CALL PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +#define glFogCoordPointer glad_glFogCoordPointer +GLAD_API_CALL PFNGLFOGCOORDDPROC glad_glFogCoordd; +#define glFogCoordd glad_glFogCoordd +GLAD_API_CALL PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +#define glFogCoorddv glad_glFogCoorddv +GLAD_API_CALL PFNGLFOGCOORDFPROC glad_glFogCoordf; +#define glFogCoordf glad_glFogCoordf +GLAD_API_CALL PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +#define glFogCoordfv glad_glFogCoordfv +GLAD_API_CALL PFNGLFOGFPROC glad_glFogf; +#define glFogf glad_glFogf +GLAD_API_CALL PFNGLFOGFVPROC glad_glFogfv; +#define glFogfv glad_glFogfv +GLAD_API_CALL PFNGLFOGIPROC glad_glFogi; +#define glFogi glad_glFogi +GLAD_API_CALL PFNGLFOGIVPROC glad_glFogiv; +#define glFogiv glad_glFogiv +GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +GLAD_API_CALL PFNGLFRUSTUMPROC glad_glFrustum; +#define glFrustum glad_glFrustum +GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +GLAD_API_CALL PFNGLGENLISTSPROC glad_glGenLists; +#define glGenLists glad_glGenLists +GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +GLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers; +#define glGenSamplers glad_glGenSamplers +GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +GLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +GLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +GLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +GLAD_API_CALL PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +#define glGetClipPlane glad_glGetClipPlane +GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; +#define glGetDebugMessageLog glad_glGetDebugMessageLog +GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +GLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; +#define glGetFragDataIndex glad_glGetFragDataIndex +GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; +#define glGetGraphicsResetStatusARB glad_glGetGraphicsResetStatusARB +GLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +GLAD_API_CALL PFNGLGETLIGHTFVPROC glad_glGetLightfv; +#define glGetLightfv glad_glGetLightfv +GLAD_API_CALL PFNGLGETLIGHTIVPROC glad_glGetLightiv; +#define glGetLightiv glad_glGetLightiv +GLAD_API_CALL PFNGLGETMAPDVPROC glad_glGetMapdv; +#define glGetMapdv glad_glGetMapdv +GLAD_API_CALL PFNGLGETMAPFVPROC glad_glGetMapfv; +#define glGetMapfv glad_glGetMapfv +GLAD_API_CALL PFNGLGETMAPIVPROC glad_glGetMapiv; +#define glGetMapiv glad_glGetMapiv +GLAD_API_CALL PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +#define glGetMaterialfv glad_glGetMaterialfv +GLAD_API_CALL PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +#define glGetMaterialiv glad_glGetMaterialiv +GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +GLAD_API_CALL PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; +#define glGetObjectLabel glad_glGetObjectLabel +GLAD_API_CALL PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; +#define glGetObjectPtrLabel glad_glGetObjectPtrLabel +GLAD_API_CALL PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +#define glGetPixelMapfv glad_glGetPixelMapfv +GLAD_API_CALL PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +#define glGetPixelMapuiv glad_glGetPixelMapuiv +GLAD_API_CALL PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +#define glGetPixelMapusv glad_glGetPixelMapusv +GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv; +#define glGetPointerv glad_glGetPointerv +GLAD_API_CALL PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +#define glGetPolygonStipple glad_glGetPolygonStipple +GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; +#define glGetQueryObjecti64v glad_glGetQueryObjecti64v +GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; +#define glGetQueryObjectui64v glad_glGetQueryObjectui64v +GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; +#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; +#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; +#define glGetSamplerParameterfv glad_glGetSamplerParameterfv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; +#define glGetSamplerParameteriv glad_glGetSamplerParameteriv +GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +GLAD_API_CALL PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +#define glGetTexEnvfv glad_glGetTexEnvfv +GLAD_API_CALL PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +#define glGetTexEnviv glad_glGetTexEnviv +GLAD_API_CALL PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +#define glGetTexGendv glad_glGetTexGendv +GLAD_API_CALL PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +#define glGetTexGenfv glad_glGetTexGenfv +GLAD_API_CALL PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +#define glGetTexGeniv glad_glGetTexGeniv +GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +GLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +GLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +GLAD_API_CALL PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; +#define glGetnColorTableARB glad_glGetnColorTableARB +GLAD_API_CALL PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; +#define glGetnCompressedTexImageARB glad_glGetnCompressedTexImageARB +GLAD_API_CALL PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; +#define glGetnConvolutionFilterARB glad_glGetnConvolutionFilterARB +GLAD_API_CALL PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; +#define glGetnHistogramARB glad_glGetnHistogramARB +GLAD_API_CALL PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; +#define glGetnMapdvARB glad_glGetnMapdvARB +GLAD_API_CALL PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; +#define glGetnMapfvARB glad_glGetnMapfvARB +GLAD_API_CALL PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; +#define glGetnMapivARB glad_glGetnMapivARB +GLAD_API_CALL PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; +#define glGetnMinmaxARB glad_glGetnMinmaxARB +GLAD_API_CALL PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; +#define glGetnPixelMapfvARB glad_glGetnPixelMapfvARB +GLAD_API_CALL PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; +#define glGetnPixelMapuivARB glad_glGetnPixelMapuivARB +GLAD_API_CALL PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; +#define glGetnPixelMapusvARB glad_glGetnPixelMapusvARB +GLAD_API_CALL PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; +#define glGetnPolygonStippleARB glad_glGetnPolygonStippleARB +GLAD_API_CALL PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; +#define glGetnSeparableFilterARB glad_glGetnSeparableFilterARB +GLAD_API_CALL PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; +#define glGetnTexImageARB glad_glGetnTexImageARB +GLAD_API_CALL PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; +#define glGetnUniformdvARB glad_glGetnUniformdvARB +GLAD_API_CALL PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; +#define glGetnUniformfvARB glad_glGetnUniformfvARB +GLAD_API_CALL PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; +#define glGetnUniformivARB glad_glGetnUniformivARB +GLAD_API_CALL PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; +#define glGetnUniformuivARB glad_glGetnUniformuivARB +GLAD_API_CALL PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +GLAD_API_CALL PFNGLINDEXMASKPROC glad_glIndexMask; +#define glIndexMask glad_glIndexMask +GLAD_API_CALL PFNGLINDEXPOINTERPROC glad_glIndexPointer; +#define glIndexPointer glad_glIndexPointer +GLAD_API_CALL PFNGLINDEXDPROC glad_glIndexd; +#define glIndexd glad_glIndexd +GLAD_API_CALL PFNGLINDEXDVPROC glad_glIndexdv; +#define glIndexdv glad_glIndexdv +GLAD_API_CALL PFNGLINDEXFPROC glad_glIndexf; +#define glIndexf glad_glIndexf +GLAD_API_CALL PFNGLINDEXFVPROC glad_glIndexfv; +#define glIndexfv glad_glIndexfv +GLAD_API_CALL PFNGLINDEXIPROC glad_glIndexi; +#define glIndexi glad_glIndexi +GLAD_API_CALL PFNGLINDEXIVPROC glad_glIndexiv; +#define glIndexiv glad_glIndexiv +GLAD_API_CALL PFNGLINDEXSPROC glad_glIndexs; +#define glIndexs glad_glIndexs +GLAD_API_CALL PFNGLINDEXSVPROC glad_glIndexsv; +#define glIndexsv glad_glIndexsv +GLAD_API_CALL PFNGLINDEXUBPROC glad_glIndexub; +#define glIndexub glad_glIndexub +GLAD_API_CALL PFNGLINDEXUBVPROC glad_glIndexubv; +#define glIndexubv glad_glIndexubv +GLAD_API_CALL PFNGLINITNAMESPROC glad_glInitNames; +#define glInitNames glad_glInitNames +GLAD_API_CALL PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +#define glInterleavedArrays glad_glInterleavedArrays +GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +GLAD_API_CALL PFNGLISLISTPROC glad_glIsList; +#define glIsList glad_glIsList +GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +GLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler; +#define glIsSampler glad_glIsSampler +GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +GLAD_API_CALL PFNGLLIGHTMODELFPROC glad_glLightModelf; +#define glLightModelf glad_glLightModelf +GLAD_API_CALL PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +#define glLightModelfv glad_glLightModelfv +GLAD_API_CALL PFNGLLIGHTMODELIPROC glad_glLightModeli; +#define glLightModeli glad_glLightModeli +GLAD_API_CALL PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +#define glLightModeliv glad_glLightModeliv +GLAD_API_CALL PFNGLLIGHTFPROC glad_glLightf; +#define glLightf glad_glLightf +GLAD_API_CALL PFNGLLIGHTFVPROC glad_glLightfv; +#define glLightfv glad_glLightfv +GLAD_API_CALL PFNGLLIGHTIPROC glad_glLighti; +#define glLighti glad_glLighti +GLAD_API_CALL PFNGLLIGHTIVPROC glad_glLightiv; +#define glLightiv glad_glLightiv +GLAD_API_CALL PFNGLLINESTIPPLEPROC glad_glLineStipple; +#define glLineStipple glad_glLineStipple +GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +GLAD_API_CALL PFNGLLISTBASEPROC glad_glListBase; +#define glListBase glad_glListBase +GLAD_API_CALL PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +#define glLoadIdentity glad_glLoadIdentity +GLAD_API_CALL PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +#define glLoadMatrixd glad_glLoadMatrixd +GLAD_API_CALL PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +#define glLoadMatrixf glad_glLoadMatrixf +GLAD_API_CALL PFNGLLOADNAMEPROC glad_glLoadName; +#define glLoadName glad_glLoadName +GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd +GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf +GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +GLAD_API_CALL PFNGLMAP1DPROC glad_glMap1d; +#define glMap1d glad_glMap1d +GLAD_API_CALL PFNGLMAP1FPROC glad_glMap1f; +#define glMap1f glad_glMap1f +GLAD_API_CALL PFNGLMAP2DPROC glad_glMap2d; +#define glMap2d glad_glMap2d +GLAD_API_CALL PFNGLMAP2FPROC glad_glMap2f; +#define glMap2f glad_glMap2f +GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +GLAD_API_CALL PFNGLMAPGRID1DPROC glad_glMapGrid1d; +#define glMapGrid1d glad_glMapGrid1d +GLAD_API_CALL PFNGLMAPGRID1FPROC glad_glMapGrid1f; +#define glMapGrid1f glad_glMapGrid1f +GLAD_API_CALL PFNGLMAPGRID2DPROC glad_glMapGrid2d; +#define glMapGrid2d glad_glMapGrid2d +GLAD_API_CALL PFNGLMAPGRID2FPROC glad_glMapGrid2f; +#define glMapGrid2f glad_glMapGrid2f +GLAD_API_CALL PFNGLMATERIALFPROC glad_glMaterialf; +#define glMaterialf glad_glMaterialf +GLAD_API_CALL PFNGLMATERIALFVPROC glad_glMaterialfv; +#define glMaterialfv glad_glMaterialfv +GLAD_API_CALL PFNGLMATERIALIPROC glad_glMateriali; +#define glMateriali glad_glMateriali +GLAD_API_CALL PFNGLMATERIALIVPROC glad_glMaterialiv; +#define glMaterialiv glad_glMaterialiv +GLAD_API_CALL PFNGLMATRIXMODEPROC glad_glMatrixMode; +#define glMatrixMode glad_glMatrixMode +GLAD_API_CALL PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +#define glMultMatrixd glad_glMultMatrixd +GLAD_API_CALL PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +#define glMultMatrixf glad_glMultMatrixf +GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +#define glMultTransposeMatrixd glad_glMultTransposeMatrixd +GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +#define glMultTransposeMatrixf glad_glMultTransposeMatrixf +GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +GLAD_API_CALL PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +#define glMultiTexCoord1d glad_glMultiTexCoord1d +GLAD_API_CALL PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +#define glMultiTexCoord1dv glad_glMultiTexCoord1dv +GLAD_API_CALL PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +#define glMultiTexCoord1f glad_glMultiTexCoord1f +GLAD_API_CALL PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +#define glMultiTexCoord1fv glad_glMultiTexCoord1fv +GLAD_API_CALL PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +#define glMultiTexCoord1i glad_glMultiTexCoord1i +GLAD_API_CALL PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +#define glMultiTexCoord1iv glad_glMultiTexCoord1iv +GLAD_API_CALL PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +#define glMultiTexCoord1s glad_glMultiTexCoord1s +GLAD_API_CALL PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +#define glMultiTexCoord1sv glad_glMultiTexCoord1sv +GLAD_API_CALL PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +#define glMultiTexCoord2d glad_glMultiTexCoord2d +GLAD_API_CALL PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +#define glMultiTexCoord2dv glad_glMultiTexCoord2dv +GLAD_API_CALL PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +#define glMultiTexCoord2f glad_glMultiTexCoord2f +GLAD_API_CALL PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +#define glMultiTexCoord2fv glad_glMultiTexCoord2fv +GLAD_API_CALL PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +#define glMultiTexCoord2i glad_glMultiTexCoord2i +GLAD_API_CALL PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +#define glMultiTexCoord2iv glad_glMultiTexCoord2iv +GLAD_API_CALL PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +#define glMultiTexCoord2s glad_glMultiTexCoord2s +GLAD_API_CALL PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +#define glMultiTexCoord2sv glad_glMultiTexCoord2sv +GLAD_API_CALL PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +#define glMultiTexCoord3d glad_glMultiTexCoord3d +GLAD_API_CALL PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +#define glMultiTexCoord3dv glad_glMultiTexCoord3dv +GLAD_API_CALL PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +#define glMultiTexCoord3f glad_glMultiTexCoord3f +GLAD_API_CALL PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +#define glMultiTexCoord3fv glad_glMultiTexCoord3fv +GLAD_API_CALL PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +#define glMultiTexCoord3i glad_glMultiTexCoord3i +GLAD_API_CALL PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +#define glMultiTexCoord3iv glad_glMultiTexCoord3iv +GLAD_API_CALL PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +#define glMultiTexCoord3s glad_glMultiTexCoord3s +GLAD_API_CALL PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +#define glMultiTexCoord3sv glad_glMultiTexCoord3sv +GLAD_API_CALL PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +#define glMultiTexCoord4d glad_glMultiTexCoord4d +GLAD_API_CALL PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +#define glMultiTexCoord4dv glad_glMultiTexCoord4dv +GLAD_API_CALL PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +#define glMultiTexCoord4f glad_glMultiTexCoord4f +GLAD_API_CALL PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +#define glMultiTexCoord4fv glad_glMultiTexCoord4fv +GLAD_API_CALL PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +#define glMultiTexCoord4i glad_glMultiTexCoord4i +GLAD_API_CALL PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +#define glMultiTexCoord4iv glad_glMultiTexCoord4iv +GLAD_API_CALL PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +#define glMultiTexCoord4s glad_glMultiTexCoord4s +GLAD_API_CALL PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +#define glMultiTexCoord4sv glad_glMultiTexCoord4sv +GLAD_API_CALL PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; +#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui +GLAD_API_CALL PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; +#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv +GLAD_API_CALL PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; +#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui +GLAD_API_CALL PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; +#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv +GLAD_API_CALL PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; +#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui +GLAD_API_CALL PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; +#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv +GLAD_API_CALL PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; +#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui +GLAD_API_CALL PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; +#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv +GLAD_API_CALL PFNGLNEWLISTPROC glad_glNewList; +#define glNewList glad_glNewList +GLAD_API_CALL PFNGLNORMAL3BPROC glad_glNormal3b; +#define glNormal3b glad_glNormal3b +GLAD_API_CALL PFNGLNORMAL3BVPROC glad_glNormal3bv; +#define glNormal3bv glad_glNormal3bv +GLAD_API_CALL PFNGLNORMAL3DPROC glad_glNormal3d; +#define glNormal3d glad_glNormal3d +GLAD_API_CALL PFNGLNORMAL3DVPROC glad_glNormal3dv; +#define glNormal3dv glad_glNormal3dv +GLAD_API_CALL PFNGLNORMAL3FPROC glad_glNormal3f; +#define glNormal3f glad_glNormal3f +GLAD_API_CALL PFNGLNORMAL3FVPROC glad_glNormal3fv; +#define glNormal3fv glad_glNormal3fv +GLAD_API_CALL PFNGLNORMAL3IPROC glad_glNormal3i; +#define glNormal3i glad_glNormal3i +GLAD_API_CALL PFNGLNORMAL3IVPROC glad_glNormal3iv; +#define glNormal3iv glad_glNormal3iv +GLAD_API_CALL PFNGLNORMAL3SPROC glad_glNormal3s; +#define glNormal3s glad_glNormal3s +GLAD_API_CALL PFNGLNORMAL3SVPROC glad_glNormal3sv; +#define glNormal3sv glad_glNormal3sv +GLAD_API_CALL PFNGLNORMALP3UIPROC glad_glNormalP3ui; +#define glNormalP3ui glad_glNormalP3ui +GLAD_API_CALL PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; +#define glNormalP3uiv glad_glNormalP3uiv +GLAD_API_CALL PFNGLNORMALPOINTERPROC glad_glNormalPointer; +#define glNormalPointer glad_glNormalPointer +GLAD_API_CALL PFNGLOBJECTLABELPROC glad_glObjectLabel; +#define glObjectLabel glad_glObjectLabel +GLAD_API_CALL PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; +#define glObjectPtrLabel glad_glObjectPtrLabel +GLAD_API_CALL PFNGLORTHOPROC glad_glOrtho; +#define glOrtho glad_glOrtho +GLAD_API_CALL PFNGLPASSTHROUGHPROC glad_glPassThrough; +#define glPassThrough glad_glPassThrough +GLAD_API_CALL PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +#define glPixelMapfv glad_glPixelMapfv +GLAD_API_CALL PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +#define glPixelMapuiv glad_glPixelMapuiv +GLAD_API_CALL PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +#define glPixelMapusv glad_glPixelMapusv +GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +GLAD_API_CALL PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +#define glPixelTransferf glad_glPixelTransferf +GLAD_API_CALL PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +#define glPixelTransferi glad_glPixelTransferi +GLAD_API_CALL PFNGLPIXELZOOMPROC glad_glPixelZoom; +#define glPixelZoom glad_glPixelZoom +GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +GLAD_API_CALL PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +#define glPolygonStipple glad_glPolygonStipple +GLAD_API_CALL PFNGLPOPATTRIBPROC glad_glPopAttrib; +#define glPopAttrib glad_glPopAttrib +GLAD_API_CALL PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +#define glPopClientAttrib glad_glPopClientAttrib +GLAD_API_CALL PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; +#define glPopDebugGroup glad_glPopDebugGroup +GLAD_API_CALL PFNGLPOPMATRIXPROC glad_glPopMatrix; +#define glPopMatrix glad_glPopMatrix +GLAD_API_CALL PFNGLPOPNAMEPROC glad_glPopName; +#define glPopName glad_glPopName +GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +GLAD_API_CALL PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +#define glPrioritizeTextures glad_glPrioritizeTextures +GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +GLAD_API_CALL PFNGLPUSHATTRIBPROC glad_glPushAttrib; +#define glPushAttrib glad_glPushAttrib +GLAD_API_CALL PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +#define glPushClientAttrib glad_glPushClientAttrib +GLAD_API_CALL PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; +#define glPushDebugGroup glad_glPushDebugGroup +GLAD_API_CALL PFNGLPUSHMATRIXPROC glad_glPushMatrix; +#define glPushMatrix glad_glPushMatrix +GLAD_API_CALL PFNGLPUSHNAMEPROC glad_glPushName; +#define glPushName glad_glPushName +GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter; +#define glQueryCounter glad_glQueryCounter +GLAD_API_CALL PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +#define glRasterPos2d glad_glRasterPos2d +GLAD_API_CALL PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +#define glRasterPos2dv glad_glRasterPos2dv +GLAD_API_CALL PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +#define glRasterPos2f glad_glRasterPos2f +GLAD_API_CALL PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +#define glRasterPos2fv glad_glRasterPos2fv +GLAD_API_CALL PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +#define glRasterPos2i glad_glRasterPos2i +GLAD_API_CALL PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +#define glRasterPos2iv glad_glRasterPos2iv +GLAD_API_CALL PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +#define glRasterPos2s glad_glRasterPos2s +GLAD_API_CALL PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +#define glRasterPos2sv glad_glRasterPos2sv +GLAD_API_CALL PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +#define glRasterPos3d glad_glRasterPos3d +GLAD_API_CALL PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +#define glRasterPos3dv glad_glRasterPos3dv +GLAD_API_CALL PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +#define glRasterPos3f glad_glRasterPos3f +GLAD_API_CALL PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +#define glRasterPos3fv glad_glRasterPos3fv +GLAD_API_CALL PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +#define glRasterPos3i glad_glRasterPos3i +GLAD_API_CALL PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +#define glRasterPos3iv glad_glRasterPos3iv +GLAD_API_CALL PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +#define glRasterPos3s glad_glRasterPos3s +GLAD_API_CALL PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +#define glRasterPos3sv glad_glRasterPos3sv +GLAD_API_CALL PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +#define glRasterPos4d glad_glRasterPos4d +GLAD_API_CALL PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +#define glRasterPos4dv glad_glRasterPos4dv +GLAD_API_CALL PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +#define glRasterPos4f glad_glRasterPos4f +GLAD_API_CALL PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +#define glRasterPos4fv glad_glRasterPos4fv +GLAD_API_CALL PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +#define glRasterPos4i glad_glRasterPos4i +GLAD_API_CALL PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +#define glRasterPos4iv glad_glRasterPos4iv +GLAD_API_CALL PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +#define glRasterPos4s glad_glRasterPos4s +GLAD_API_CALL PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +#define glRasterPos4sv glad_glRasterPos4sv +GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +GLAD_API_CALL PFNGLREADNPIXELSPROC glad_glReadnPixels; +#define glReadnPixels glad_glReadnPixels +GLAD_API_CALL PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; +#define glReadnPixelsARB glad_glReadnPixelsARB +GLAD_API_CALL PFNGLRECTDPROC glad_glRectd; +#define glRectd glad_glRectd +GLAD_API_CALL PFNGLRECTDVPROC glad_glRectdv; +#define glRectdv glad_glRectdv +GLAD_API_CALL PFNGLRECTFPROC glad_glRectf; +#define glRectf glad_glRectf +GLAD_API_CALL PFNGLRECTFVPROC glad_glRectfv; +#define glRectfv glad_glRectfv +GLAD_API_CALL PFNGLRECTIPROC glad_glRecti; +#define glRecti glad_glRecti +GLAD_API_CALL PFNGLRECTIVPROC glad_glRectiv; +#define glRectiv glad_glRectiv +GLAD_API_CALL PFNGLRECTSPROC glad_glRects; +#define glRects glad_glRects +GLAD_API_CALL PFNGLRECTSVPROC glad_glRectsv; +#define glRectsv glad_glRectsv +GLAD_API_CALL PFNGLRENDERMODEPROC glad_glRenderMode; +#define glRenderMode glad_glRenderMode +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +GLAD_API_CALL PFNGLROTATEDPROC glad_glRotated; +#define glRotated glad_glRotated +GLAD_API_CALL PFNGLROTATEFPROC glad_glRotatef; +#define glRotatef glad_glRotatef +GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +GLAD_API_CALL PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +#define glSampleCoverageARB glad_glSampleCoverageARB +GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; +#define glSamplerParameterIiv glad_glSamplerParameterIiv +GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; +#define glSamplerParameterIuiv glad_glSamplerParameterIuiv +GLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; +#define glSamplerParameterf glad_glSamplerParameterf +GLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; +#define glSamplerParameterfv glad_glSamplerParameterfv +GLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; +#define glSamplerParameteri glad_glSamplerParameteri +GLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; +#define glSamplerParameteriv glad_glSamplerParameteriv +GLAD_API_CALL PFNGLSCALEDPROC glad_glScaled; +#define glScaled glad_glScaled +GLAD_API_CALL PFNGLSCALEFPROC glad_glScalef; +#define glScalef glad_glScalef +GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +GLAD_API_CALL PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +#define glSecondaryColor3b glad_glSecondaryColor3b +GLAD_API_CALL PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +#define glSecondaryColor3bv glad_glSecondaryColor3bv +GLAD_API_CALL PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +#define glSecondaryColor3d glad_glSecondaryColor3d +GLAD_API_CALL PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +#define glSecondaryColor3dv glad_glSecondaryColor3dv +GLAD_API_CALL PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +#define glSecondaryColor3f glad_glSecondaryColor3f +GLAD_API_CALL PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +#define glSecondaryColor3fv glad_glSecondaryColor3fv +GLAD_API_CALL PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +#define glSecondaryColor3i glad_glSecondaryColor3i +GLAD_API_CALL PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +#define glSecondaryColor3iv glad_glSecondaryColor3iv +GLAD_API_CALL PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +#define glSecondaryColor3s glad_glSecondaryColor3s +GLAD_API_CALL PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +#define glSecondaryColor3sv glad_glSecondaryColor3sv +GLAD_API_CALL PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +#define glSecondaryColor3ub glad_glSecondaryColor3ub +GLAD_API_CALL PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +#define glSecondaryColor3ubv glad_glSecondaryColor3ubv +GLAD_API_CALL PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +#define glSecondaryColor3ui glad_glSecondaryColor3ui +GLAD_API_CALL PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +#define glSecondaryColor3uiv glad_glSecondaryColor3uiv +GLAD_API_CALL PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +#define glSecondaryColor3us glad_glSecondaryColor3us +GLAD_API_CALL PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +#define glSecondaryColor3usv glad_glSecondaryColor3usv +GLAD_API_CALL PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; +#define glSecondaryColorP3ui glad_glSecondaryColorP3ui +GLAD_API_CALL PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; +#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv +GLAD_API_CALL PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +#define glSecondaryColorPointer glad_glSecondaryColorPointer +GLAD_API_CALL PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +#define glSelectBuffer glad_glSelectBuffer +GLAD_API_CALL PFNGLSHADEMODELPROC glad_glShadeModel; +#define glShadeModel glad_glShadeModel +GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +GLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +GLAD_API_CALL PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +#define glTexCoord1d glad_glTexCoord1d +GLAD_API_CALL PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +#define glTexCoord1dv glad_glTexCoord1dv +GLAD_API_CALL PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +#define glTexCoord1f glad_glTexCoord1f +GLAD_API_CALL PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +#define glTexCoord1fv glad_glTexCoord1fv +GLAD_API_CALL PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +#define glTexCoord1i glad_glTexCoord1i +GLAD_API_CALL PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +#define glTexCoord1iv glad_glTexCoord1iv +GLAD_API_CALL PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +#define glTexCoord1s glad_glTexCoord1s +GLAD_API_CALL PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +#define glTexCoord1sv glad_glTexCoord1sv +GLAD_API_CALL PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +#define glTexCoord2d glad_glTexCoord2d +GLAD_API_CALL PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +#define glTexCoord2dv glad_glTexCoord2dv +GLAD_API_CALL PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +#define glTexCoord2f glad_glTexCoord2f +GLAD_API_CALL PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +#define glTexCoord2fv glad_glTexCoord2fv +GLAD_API_CALL PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +#define glTexCoord2i glad_glTexCoord2i +GLAD_API_CALL PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +#define glTexCoord2iv glad_glTexCoord2iv +GLAD_API_CALL PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +#define glTexCoord2s glad_glTexCoord2s +GLAD_API_CALL PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +#define glTexCoord2sv glad_glTexCoord2sv +GLAD_API_CALL PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +#define glTexCoord3d glad_glTexCoord3d +GLAD_API_CALL PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +#define glTexCoord3dv glad_glTexCoord3dv +GLAD_API_CALL PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +#define glTexCoord3f glad_glTexCoord3f +GLAD_API_CALL PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +#define glTexCoord3fv glad_glTexCoord3fv +GLAD_API_CALL PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +#define glTexCoord3i glad_glTexCoord3i +GLAD_API_CALL PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +#define glTexCoord3iv glad_glTexCoord3iv +GLAD_API_CALL PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +#define glTexCoord3s glad_glTexCoord3s +GLAD_API_CALL PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +#define glTexCoord3sv glad_glTexCoord3sv +GLAD_API_CALL PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +#define glTexCoord4d glad_glTexCoord4d +GLAD_API_CALL PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +#define glTexCoord4dv glad_glTexCoord4dv +GLAD_API_CALL PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +#define glTexCoord4f glad_glTexCoord4f +GLAD_API_CALL PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +#define glTexCoord4fv glad_glTexCoord4fv +GLAD_API_CALL PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +#define glTexCoord4i glad_glTexCoord4i +GLAD_API_CALL PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +#define glTexCoord4iv glad_glTexCoord4iv +GLAD_API_CALL PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +#define glTexCoord4s glad_glTexCoord4s +GLAD_API_CALL PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +#define glTexCoord4sv glad_glTexCoord4sv +GLAD_API_CALL PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; +#define glTexCoordP1ui glad_glTexCoordP1ui +GLAD_API_CALL PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; +#define glTexCoordP1uiv glad_glTexCoordP1uiv +GLAD_API_CALL PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; +#define glTexCoordP2ui glad_glTexCoordP2ui +GLAD_API_CALL PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; +#define glTexCoordP2uiv glad_glTexCoordP2uiv +GLAD_API_CALL PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; +#define glTexCoordP3ui glad_glTexCoordP3ui +GLAD_API_CALL PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; +#define glTexCoordP3uiv glad_glTexCoordP3uiv +GLAD_API_CALL PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; +#define glTexCoordP4ui glad_glTexCoordP4ui +GLAD_API_CALL PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; +#define glTexCoordP4uiv glad_glTexCoordP4uiv +GLAD_API_CALL PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +#define glTexCoordPointer glad_glTexCoordPointer +GLAD_API_CALL PFNGLTEXENVFPROC glad_glTexEnvf; +#define glTexEnvf glad_glTexEnvf +GLAD_API_CALL PFNGLTEXENVFVPROC glad_glTexEnvfv; +#define glTexEnvfv glad_glTexEnvfv +GLAD_API_CALL PFNGLTEXENVIPROC glad_glTexEnvi; +#define glTexEnvi glad_glTexEnvi +GLAD_API_CALL PFNGLTEXENVIVPROC glad_glTexEnviv; +#define glTexEnviv glad_glTexEnviv +GLAD_API_CALL PFNGLTEXGENDPROC glad_glTexGend; +#define glTexGend glad_glTexGend +GLAD_API_CALL PFNGLTEXGENDVPROC glad_glTexGendv; +#define glTexGendv glad_glTexGendv +GLAD_API_CALL PFNGLTEXGENFPROC glad_glTexGenf; +#define glTexGenf glad_glTexGenf +GLAD_API_CALL PFNGLTEXGENFVPROC glad_glTexGenfv; +#define glTexGenfv glad_glTexGenfv +GLAD_API_CALL PFNGLTEXGENIPROC glad_glTexGeni; +#define glTexGeni glad_glTexGeni +GLAD_API_CALL PFNGLTEXGENIVPROC glad_glTexGeniv; +#define glTexGeniv glad_glTexGeniv +GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +GLAD_API_CALL PFNGLTRANSLATEDPROC glad_glTranslated; +#define glTranslated glad_glTranslated +GLAD_API_CALL PFNGLTRANSLATEFPROC glad_glTranslatef; +#define glTranslatef glad_glTranslatef +GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +GLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +GLAD_API_CALL PFNGLVERTEX2DPROC glad_glVertex2d; +#define glVertex2d glad_glVertex2d +GLAD_API_CALL PFNGLVERTEX2DVPROC glad_glVertex2dv; +#define glVertex2dv glad_glVertex2dv +GLAD_API_CALL PFNGLVERTEX2FPROC glad_glVertex2f; +#define glVertex2f glad_glVertex2f +GLAD_API_CALL PFNGLVERTEX2FVPROC glad_glVertex2fv; +#define glVertex2fv glad_glVertex2fv +GLAD_API_CALL PFNGLVERTEX2IPROC glad_glVertex2i; +#define glVertex2i glad_glVertex2i +GLAD_API_CALL PFNGLVERTEX2IVPROC glad_glVertex2iv; +#define glVertex2iv glad_glVertex2iv +GLAD_API_CALL PFNGLVERTEX2SPROC glad_glVertex2s; +#define glVertex2s glad_glVertex2s +GLAD_API_CALL PFNGLVERTEX2SVPROC glad_glVertex2sv; +#define glVertex2sv glad_glVertex2sv +GLAD_API_CALL PFNGLVERTEX3DPROC glad_glVertex3d; +#define glVertex3d glad_glVertex3d +GLAD_API_CALL PFNGLVERTEX3DVPROC glad_glVertex3dv; +#define glVertex3dv glad_glVertex3dv +GLAD_API_CALL PFNGLVERTEX3FPROC glad_glVertex3f; +#define glVertex3f glad_glVertex3f +GLAD_API_CALL PFNGLVERTEX3FVPROC glad_glVertex3fv; +#define glVertex3fv glad_glVertex3fv +GLAD_API_CALL PFNGLVERTEX3IPROC glad_glVertex3i; +#define glVertex3i glad_glVertex3i +GLAD_API_CALL PFNGLVERTEX3IVPROC glad_glVertex3iv; +#define glVertex3iv glad_glVertex3iv +GLAD_API_CALL PFNGLVERTEX3SPROC glad_glVertex3s; +#define glVertex3s glad_glVertex3s +GLAD_API_CALL PFNGLVERTEX3SVPROC glad_glVertex3sv; +#define glVertex3sv glad_glVertex3sv +GLAD_API_CALL PFNGLVERTEX4DPROC glad_glVertex4d; +#define glVertex4d glad_glVertex4d +GLAD_API_CALL PFNGLVERTEX4DVPROC glad_glVertex4dv; +#define glVertex4dv glad_glVertex4dv +GLAD_API_CALL PFNGLVERTEX4FPROC glad_glVertex4f; +#define glVertex4f glad_glVertex4f +GLAD_API_CALL PFNGLVERTEX4FVPROC glad_glVertex4fv; +#define glVertex4fv glad_glVertex4fv +GLAD_API_CALL PFNGLVERTEX4IPROC glad_glVertex4i; +#define glVertex4i glad_glVertex4i +GLAD_API_CALL PFNGLVERTEX4IVPROC glad_glVertex4iv; +#define glVertex4iv glad_glVertex4iv +GLAD_API_CALL PFNGLVERTEX4SPROC glad_glVertex4s; +#define glVertex4s glad_glVertex4s +GLAD_API_CALL PFNGLVERTEX4SVPROC glad_glVertex4sv; +#define glVertex4sv glad_glVertex4sv +GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; +#define glVertexAttribDivisor glad_glVertexAttribDivisor +GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +GLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; +#define glVertexAttribP1ui glad_glVertexAttribP1ui +GLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; +#define glVertexAttribP1uiv glad_glVertexAttribP1uiv +GLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; +#define glVertexAttribP2ui glad_glVertexAttribP2ui +GLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; +#define glVertexAttribP2uiv glad_glVertexAttribP2uiv +GLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; +#define glVertexAttribP3ui glad_glVertexAttribP3ui +GLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; +#define glVertexAttribP3uiv glad_glVertexAttribP3uiv +GLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; +#define glVertexAttribP4ui glad_glVertexAttribP4ui +GLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; +#define glVertexAttribP4uiv glad_glVertexAttribP4uiv +GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +GLAD_API_CALL PFNGLVERTEXP2UIPROC glad_glVertexP2ui; +#define glVertexP2ui glad_glVertexP2ui +GLAD_API_CALL PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; +#define glVertexP2uiv glad_glVertexP2uiv +GLAD_API_CALL PFNGLVERTEXP3UIPROC glad_glVertexP3ui; +#define glVertexP3ui glad_glVertexP3ui +GLAD_API_CALL PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; +#define glVertexP3uiv glad_glVertexP3uiv +GLAD_API_CALL PFNGLVERTEXP4UIPROC glad_glVertexP4ui; +#define glVertexP4ui glad_glVertexP4ui +GLAD_API_CALL PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; +#define glVertexP4uiv glad_glVertexP4uiv +GLAD_API_CALL PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +#define glVertexPointer glad_glVertexPointer +GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +GLAD_API_CALL PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +#define glWindowPos2d glad_glWindowPos2d +GLAD_API_CALL PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +#define glWindowPos2dv glad_glWindowPos2dv +GLAD_API_CALL PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +#define glWindowPos2f glad_glWindowPos2f +GLAD_API_CALL PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +#define glWindowPos2fv glad_glWindowPos2fv +GLAD_API_CALL PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +#define glWindowPos2i glad_glWindowPos2i +GLAD_API_CALL PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +#define glWindowPos2iv glad_glWindowPos2iv +GLAD_API_CALL PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +#define glWindowPos2s glad_glWindowPos2s +GLAD_API_CALL PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +#define glWindowPos2sv glad_glWindowPos2sv +GLAD_API_CALL PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +#define glWindowPos3d glad_glWindowPos3d +GLAD_API_CALL PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +#define glWindowPos3dv glad_glWindowPos3dv +GLAD_API_CALL PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +#define glWindowPos3f glad_glWindowPos3f +GLAD_API_CALL PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +#define glWindowPos3fv glad_glWindowPos3fv +GLAD_API_CALL PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +#define glWindowPos3i glad_glWindowPos3i +GLAD_API_CALL PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +#define glWindowPos3iv glad_glWindowPos3iv +GLAD_API_CALL PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +#define glWindowPos3s glad_glWindowPos3s +GLAD_API_CALL PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +#define glWindowPos3sv glad_glWindowPos3sv + + +GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadGL( GLADloadfunc load); + + + + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/raylib/external/glfw/deps/glad/khrplatform.h b/raylib/external/glfw/deps/glad/khrplatform.h new file mode 100644 index 0000000..975bbff --- /dev/null +++ b/raylib/external/glfw/deps/glad/khrplatform.h @@ -0,0 +1,282 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/raylib/external/glfw/deps/glad/vk_platform.h b/raylib/external/glfw/deps/glad/vk_platform.h new file mode 100644 index 0000000..d7d22e1 --- /dev/null +++ b/raylib/external/glfw/deps/glad/vk_platform.h @@ -0,0 +1,92 @@ +/* */ +/* File: vk_platform.h */ +/* */ +/* +** Copyright (c) 2014-2017 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +#ifndef VK_PLATFORM_H_ +#define VK_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* +*************************************************************************************************** +* Platform-specific directives and type declarations +*************************************************************************************************** +*/ + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that Vulkan clients call Vulkan commands + * with the same calling conventions that the Vulkan implementation expects. + * + * VKAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * VKAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); + * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); + */ +#if defined(_WIN32) + /* On Windows, Vulkan commands use the stdcall convention */ + #define VKAPI_ATTR + #define VKAPI_CALL __stdcall + #define VKAPI_PTR VKAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 + #error "Vulkan isn't supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) + /* On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" */ + /* calling convention, i.e. float parameters are passed in registers. This */ + /* is true even if the rest of the application passes floats on the stack, */ + /* as it does by default when compiling for the armeabi-v7a NDK ABI. */ + #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) + #define VKAPI_CALL + #define VKAPI_PTR VKAPI_ATTR +#else + /* On other platforms, use the default calling convention */ + #define VKAPI_ATTR + #define VKAPI_CALL + #define VKAPI_PTR +#endif + +#include + +#if !defined(VK_NO_STDINT_H) + #if defined(_MSC_VER) && (_MSC_VER < 1600) + typedef signed __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef signed __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + #else + #include + #endif +#endif /* !defined(VK_NO_STDINT_H) */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif diff --git a/raylib/external/glfw/deps/glad/vulkan.h b/raylib/external/glfw/deps/glad/vulkan.h new file mode 100644 index 0000000..6bace71 --- /dev/null +++ b/raylib/external/glfw/deps/glad/vulkan.h @@ -0,0 +1,3480 @@ +/** + * Loader generated by glad 2.0.0-beta on Sun Apr 14 17:03:38 2019 + * + * Generator: C/C++ + * Specification: vk + * Extensions: 3 + * + * APIs: + * - vulkan=1.1 + * + * Options: + * - MX_GLOBAL = False + * - LOADER = False + * - ALIAS = False + * - HEADER_ONLY = False + * - DEBUG = False + * - MX = False + * + * Commandline: + * --api='vulkan=1.1' --extensions='VK_EXT_debug_report,VK_KHR_surface,VK_KHR_swapchain' c + * + * Online: + * http://glad.sh/#api=vulkan%3D1.1&extensions=VK_EXT_debug_report%2CVK_KHR_surface%2CVK_KHR_swapchain&generator=c&options= + * + */ + +#ifndef GLAD_VULKAN_H_ +#define GLAD_VULKAN_H_ + +#ifdef VULKAN_H_ + #error header already included (API: vulkan), remove previous include! +#endif +#define VULKAN_H_ 1 + +#ifdef VULKAN_CORE_H_ + #error header already included (API: vulkan), remove previous include! +#endif +#define VULKAN_CORE_H_ 1 + + +#define GLAD_VULKAN + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(const char *name, void *userptr); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define VK_ATTACHMENT_UNUSED (~0U) +#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 +#define VK_FALSE 0 +#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" +#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 +#define VK_LOD_CLAMP_NONE 1000.0f +#define VK_LUID_SIZE 8 +#define VK_MAX_DESCRIPTION_SIZE 256 +#define VK_MAX_DEVICE_GROUP_SIZE 32 +#define VK_MAX_EXTENSION_NAME_SIZE 256 +#define VK_MAX_MEMORY_HEAPS 16 +#define VK_MAX_MEMORY_TYPES 32 +#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 +#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1) +#define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_REMAINING_ARRAY_LAYERS (~0U) +#define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_SUBPASS_EXTERNAL (~0U) +#define VK_TRUE 1 +#define VK_UUID_SIZE 16 +#define VK_WHOLE_SIZE (~0ULL) + + +#include +#define VK_MAKE_VERSION(major, minor, patch) \ + (((major) << 22) | ((minor) << 12) | (patch)) +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) +/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */ +/*#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 */ +/* Vulkan 1.0 version number */ +#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)/* Patch version should always be set to 0 */ +/* Vulkan 1.1 version number */ +#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)/* Patch version should always be set to 0 */ +/* Version of this file */ +#define VK_HEADER_VERSION 106 +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; +#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif +#endif +#define VK_NULL_HANDLE 0 + + + + + + + + +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_HANDLE(VkCommandBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) +typedef enum VkAttachmentLoadOp { + VK_ATTACHMENT_LOAD_OP_LOAD = 0, + VK_ATTACHMENT_LOAD_OP_CLEAR = 1, + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2 +} VkAttachmentLoadOp; +typedef enum VkAttachmentStoreOp { + VK_ATTACHMENT_STORE_OP_STORE = 0, + VK_ATTACHMENT_STORE_OP_DONT_CARE = 1 +} VkAttachmentStoreOp; +typedef enum VkBlendFactor { + VK_BLEND_FACTOR_ZERO = 0, + VK_BLEND_FACTOR_ONE = 1, + VK_BLEND_FACTOR_SRC_COLOR = 2, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, + VK_BLEND_FACTOR_DST_COLOR = 4, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, + VK_BLEND_FACTOR_SRC_ALPHA = 6, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, + VK_BLEND_FACTOR_DST_ALPHA = 8, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, + VK_BLEND_FACTOR_CONSTANT_COLOR = 10, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, + VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, + VK_BLEND_FACTOR_SRC1_COLOR = 15, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, + VK_BLEND_FACTOR_SRC1_ALPHA = 17, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18 +} VkBlendFactor; +typedef enum VkBlendOp { + VK_BLEND_OP_ADD = 0, + VK_BLEND_OP_SUBTRACT = 1, + VK_BLEND_OP_REVERSE_SUBTRACT = 2, + VK_BLEND_OP_MIN = 3, + VK_BLEND_OP_MAX = 4 +} VkBlendOp; +typedef enum VkBorderColor { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, + VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, + VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5 +} VkBorderColor; + +typedef enum VkPipelineCacheHeaderVersion { + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1 +} VkPipelineCacheHeaderVersion; + +typedef enum VkDeviceQueueCreateFlagBits { + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 1 +} VkDeviceQueueCreateFlagBits; +typedef enum VkBufferCreateFlagBits { + VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 1, + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 2, + VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 4, + VK_BUFFER_CREATE_PROTECTED_BIT = 8 +} VkBufferCreateFlagBits; +typedef enum VkBufferUsageFlagBits { + VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 1, + VK_BUFFER_USAGE_TRANSFER_DST_BIT = 2, + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 4, + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 8, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 16, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 32, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 64, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 128, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 256 +} VkBufferUsageFlagBits; +typedef enum VkColorComponentFlagBits { + VK_COLOR_COMPONENT_R_BIT = 1, + VK_COLOR_COMPONENT_G_BIT = 2, + VK_COLOR_COMPONENT_B_BIT = 4, + VK_COLOR_COMPONENT_A_BIT = 8 +} VkColorComponentFlagBits; +typedef enum VkComponentSwizzle { + VK_COMPONENT_SWIZZLE_IDENTITY = 0, + VK_COMPONENT_SWIZZLE_ZERO = 1, + VK_COMPONENT_SWIZZLE_ONE = 2, + VK_COMPONENT_SWIZZLE_R = 3, + VK_COMPONENT_SWIZZLE_G = 4, + VK_COMPONENT_SWIZZLE_B = 5, + VK_COMPONENT_SWIZZLE_A = 6 +} VkComponentSwizzle; +typedef enum VkCommandPoolCreateFlagBits { + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 1, + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 2, + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 4 +} VkCommandPoolCreateFlagBits; +typedef enum VkCommandPoolResetFlagBits { + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 1 +} VkCommandPoolResetFlagBits; +typedef enum VkCommandBufferResetFlagBits { + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 1 +} VkCommandBufferResetFlagBits; +typedef enum VkCommandBufferLevel { + VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1 +} VkCommandBufferLevel; +typedef enum VkCommandBufferUsageFlagBits { + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 1, + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 2, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 4 +} VkCommandBufferUsageFlagBits; +typedef enum VkCompareOp { + VK_COMPARE_OP_NEVER = 0, + VK_COMPARE_OP_LESS = 1, + VK_COMPARE_OP_EQUAL = 2, + VK_COMPARE_OP_LESS_OR_EQUAL = 3, + VK_COMPARE_OP_GREATER = 4, + VK_COMPARE_OP_NOT_EQUAL = 5, + VK_COMPARE_OP_GREATER_OR_EQUAL = 6, + VK_COMPARE_OP_ALWAYS = 7 +} VkCompareOp; +typedef enum VkCullModeFlagBits { + VK_CULL_MODE_NONE = 0, + VK_CULL_MODE_FRONT_BIT = 1, + VK_CULL_MODE_BACK_BIT = 2, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003 +} VkCullModeFlagBits; +typedef enum VkDescriptorType { + VK_DESCRIPTOR_TYPE_SAMPLER = 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10 +} VkDescriptorType; +typedef enum VkDynamicState { + VK_DYNAMIC_STATE_VIEWPORT = 0, + VK_DYNAMIC_STATE_SCISSOR = 1, + VK_DYNAMIC_STATE_LINE_WIDTH = 2, + VK_DYNAMIC_STATE_DEPTH_BIAS = 3, + VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, + VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, + VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1) +} VkDynamicState; +typedef enum VkFenceCreateFlagBits { + VK_FENCE_CREATE_SIGNALED_BIT = 1 +} VkFenceCreateFlagBits; +typedef enum VkPolygonMode { + VK_POLYGON_MODE_FILL = 0, + VK_POLYGON_MODE_LINE = 1, + VK_POLYGON_MODE_POINT = 2 +} VkPolygonMode; +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033 +} VkFormat; +typedef enum VkFormatFeatureFlagBits { + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 1, + VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 2, + VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 4, + VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 8, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 16, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 32, + VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 64, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 128, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 256, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 512, + VK_FORMAT_FEATURE_BLIT_SRC_BIT = 1024, + VK_FORMAT_FEATURE_BLIT_DST_BIT = 2048, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 4096, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 16384, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 32768, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 131072, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 262144, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 524288, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 1048576, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 2097152, + VK_FORMAT_FEATURE_DISJOINT_BIT = 4194304, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 8388608 +} VkFormatFeatureFlagBits; +typedef enum VkFrontFace { + VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, + VK_FRONT_FACE_CLOCKWISE = 1 +} VkFrontFace; +typedef enum VkImageAspectFlagBits { + VK_IMAGE_ASPECT_COLOR_BIT = 1, + VK_IMAGE_ASPECT_DEPTH_BIT = 2, + VK_IMAGE_ASPECT_STENCIL_BIT = 4, + VK_IMAGE_ASPECT_METADATA_BIT = 8, + VK_IMAGE_ASPECT_PLANE_0_BIT = 16, + VK_IMAGE_ASPECT_PLANE_1_BIT = 32, + VK_IMAGE_ASPECT_PLANE_2_BIT = 64 +} VkImageAspectFlagBits; +typedef enum VkImageCreateFlagBits { + VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 1, + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 2, + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 4, + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 8, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 16, + VK_IMAGE_CREATE_ALIAS_BIT = 1024, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 64, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 32, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 128, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 256, + VK_IMAGE_CREATE_PROTECTED_BIT = 2048, + VK_IMAGE_CREATE_DISJOINT_BIT = 512 +} VkImageCreateFlagBits; +typedef enum VkImageLayout { + VK_IMAGE_LAYOUT_UNDEFINED = 0, + VK_IMAGE_LAYOUT_GENERAL = 1, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, + VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002 +} VkImageLayout; +typedef enum VkImageTiling { + VK_IMAGE_TILING_OPTIMAL = 0, + VK_IMAGE_TILING_LINEAR = 1 +} VkImageTiling; +typedef enum VkImageType { + VK_IMAGE_TYPE_1D = 0, + VK_IMAGE_TYPE_2D = 1, + VK_IMAGE_TYPE_3D = 2 +} VkImageType; +typedef enum VkImageUsageFlagBits { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 1, + VK_IMAGE_USAGE_TRANSFER_DST_BIT = 2, + VK_IMAGE_USAGE_SAMPLED_BIT = 4, + VK_IMAGE_USAGE_STORAGE_BIT = 8, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 16, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 32, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 64, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 128 +} VkImageUsageFlagBits; + +typedef enum VkImageViewType { + VK_IMAGE_VIEW_TYPE_1D = 0, + VK_IMAGE_VIEW_TYPE_2D = 1, + VK_IMAGE_VIEW_TYPE_3D = 2, + VK_IMAGE_VIEW_TYPE_CUBE = 3, + VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, + VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6 +} VkImageViewType; +typedef enum VkSharingMode { + VK_SHARING_MODE_EXCLUSIVE = 0, + VK_SHARING_MODE_CONCURRENT = 1 +} VkSharingMode; +typedef enum VkIndexType { + VK_INDEX_TYPE_UINT16 = 0, + VK_INDEX_TYPE_UINT32 = 1 +} VkIndexType; +typedef enum VkLogicOp { + VK_LOGIC_OP_CLEAR = 0, + VK_LOGIC_OP_AND = 1, + VK_LOGIC_OP_AND_REVERSE = 2, + VK_LOGIC_OP_COPY = 3, + VK_LOGIC_OP_AND_INVERTED = 4, + VK_LOGIC_OP_NO_OP = 5, + VK_LOGIC_OP_XOR = 6, + VK_LOGIC_OP_OR = 7, + VK_LOGIC_OP_NOR = 8, + VK_LOGIC_OP_EQUIVALENT = 9, + VK_LOGIC_OP_INVERT = 10, + VK_LOGIC_OP_OR_REVERSE = 11, + VK_LOGIC_OP_COPY_INVERTED = 12, + VK_LOGIC_OP_OR_INVERTED = 13, + VK_LOGIC_OP_NAND = 14, + VK_LOGIC_OP_SET = 15 +} VkLogicOp; +typedef enum VkMemoryHeapFlagBits { + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 1, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 2 +} VkMemoryHeapFlagBits; +typedef enum VkAccessFlagBits { + VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 1, + VK_ACCESS_INDEX_READ_BIT = 2, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 4, + VK_ACCESS_UNIFORM_READ_BIT = 8, + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 16, + VK_ACCESS_SHADER_READ_BIT = 32, + VK_ACCESS_SHADER_WRITE_BIT = 64, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 128, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 256, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 512, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 1024, + VK_ACCESS_TRANSFER_READ_BIT = 2048, + VK_ACCESS_TRANSFER_WRITE_BIT = 4096, + VK_ACCESS_HOST_READ_BIT = 8192, + VK_ACCESS_HOST_WRITE_BIT = 16384, + VK_ACCESS_MEMORY_READ_BIT = 32768, + VK_ACCESS_MEMORY_WRITE_BIT = 65536 +} VkAccessFlagBits; +typedef enum VkMemoryPropertyFlagBits { + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 1, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 2, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 4, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 8, + VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 16, + VK_MEMORY_PROPERTY_PROTECTED_BIT = 32 +} VkMemoryPropertyFlagBits; +typedef enum VkPhysicalDeviceType { + VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + VK_PHYSICAL_DEVICE_TYPE_CPU = 4 +} VkPhysicalDeviceType; +typedef enum VkPipelineBindPoint { + VK_PIPELINE_BIND_POINT_GRAPHICS = 0, + VK_PIPELINE_BIND_POINT_COMPUTE = 1 +} VkPipelineBindPoint; +typedef enum VkPipelineCreateFlagBits { + VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 1, + VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 2, + VK_PIPELINE_CREATE_DERIVATIVE_BIT = 4, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 8, + VK_PIPELINE_CREATE_DISPATCH_BASE = 16 +} VkPipelineCreateFlagBits; +typedef enum VkPrimitiveTopology { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10 +} VkPrimitiveTopology; +typedef enum VkQueryControlFlagBits { + VK_QUERY_CONTROL_PRECISE_BIT = 1 +} VkQueryControlFlagBits; +typedef enum VkQueryPipelineStatisticFlagBits { + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 1, + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 2, + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 4, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 8, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 16, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 32, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 64, + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 128, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 256, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 512, + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 1024 +} VkQueryPipelineStatisticFlagBits; +typedef enum VkQueryResultFlagBits { + VK_QUERY_RESULT_64_BIT = 1, + VK_QUERY_RESULT_WAIT_BIT = 2, + VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 4, + VK_QUERY_RESULT_PARTIAL_BIT = 8 +} VkQueryResultFlagBits; +typedef enum VkQueryType { + VK_QUERY_TYPE_OCCLUSION = 0, + VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, + VK_QUERY_TYPE_TIMESTAMP = 2 +} VkQueryType; +typedef enum VkQueueFlagBits { + VK_QUEUE_GRAPHICS_BIT = 1, + VK_QUEUE_COMPUTE_BIT = 2, + VK_QUEUE_TRANSFER_BIT = 4, + VK_QUEUE_SPARSE_BINDING_BIT = 8, + VK_QUEUE_PROTECTED_BIT = 16 +} VkQueueFlagBits; +typedef enum VkSubpassContents { + VK_SUBPASS_CONTENTS_INLINE = 0, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1 +} VkSubpassContents; +typedef enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, + VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001 +} VkResult; +typedef enum VkShaderStageFlagBits { + VK_SHADER_STAGE_VERTEX_BIT = 1, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 2, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 4, + VK_SHADER_STAGE_GEOMETRY_BIT = 8, + VK_SHADER_STAGE_FRAGMENT_BIT = 16, + VK_SHADER_STAGE_COMPUTE_BIT = 32, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, + VK_SHADER_STAGE_ALL = 0x7FFFFFFF +} VkShaderStageFlagBits; +typedef enum VkSparseMemoryBindFlagBits { + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 1 +} VkSparseMemoryBindFlagBits; +typedef enum VkStencilFaceFlagBits { + VK_STENCIL_FACE_FRONT_BIT = 1, + VK_STENCIL_FACE_BACK_BIT = 2, + VK_STENCIL_FRONT_AND_BACK = 0x00000003 +} VkStencilFaceFlagBits; +typedef enum VkStencilOp { + VK_STENCIL_OP_KEEP = 0, + VK_STENCIL_OP_ZERO = 1, + VK_STENCIL_OP_REPLACE = 2, + VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, + VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, + VK_STENCIL_OP_INVERT = 5, + VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7 +} VkStencilOp; +typedef enum VkStructureType { + VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, + VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, + VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, + VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, + VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, + VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, + VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT +} VkStructureType; +typedef enum VkSystemAllocationScope { + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4 +} VkSystemAllocationScope; +typedef enum VkInternalAllocationType { + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0 +} VkInternalAllocationType; +typedef enum VkSamplerAddressMode { + VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3 +} VkSamplerAddressMode; +typedef enum VkFilter { + VK_FILTER_NEAREST = 0, + VK_FILTER_LINEAR = 1 +} VkFilter; +typedef enum VkSamplerMipmapMode { + VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1 +} VkSamplerMipmapMode; +typedef enum VkVertexInputRate { + VK_VERTEX_INPUT_RATE_VERTEX = 0, + VK_VERTEX_INPUT_RATE_INSTANCE = 1 +} VkVertexInputRate; +typedef enum VkPipelineStageFlagBits { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 1, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 2, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 4, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 8, + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 16, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 32, + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 64, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 128, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 256, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 512, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 1024, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 2048, + VK_PIPELINE_STAGE_TRANSFER_BIT = 4096, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 8192, + VK_PIPELINE_STAGE_HOST_BIT = 16384, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 32768, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 65536 +} VkPipelineStageFlagBits; +typedef enum VkSparseImageFormatFlagBits { + VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 1, + VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 2, + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 4 +} VkSparseImageFormatFlagBits; +typedef enum VkSampleCountFlagBits { + VK_SAMPLE_COUNT_1_BIT = 1, + VK_SAMPLE_COUNT_2_BIT = 2, + VK_SAMPLE_COUNT_4_BIT = 4, + VK_SAMPLE_COUNT_8_BIT = 8, + VK_SAMPLE_COUNT_16_BIT = 16, + VK_SAMPLE_COUNT_32_BIT = 32, + VK_SAMPLE_COUNT_64_BIT = 64 +} VkSampleCountFlagBits; +typedef enum VkAttachmentDescriptionFlagBits { + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 1 +} VkAttachmentDescriptionFlagBits; +typedef enum VkDescriptorPoolCreateFlagBits { + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 1 +} VkDescriptorPoolCreateFlagBits; +typedef enum VkDependencyFlagBits { + VK_DEPENDENCY_BY_REGION_BIT = 1, + VK_DEPENDENCY_DEVICE_GROUP_BIT = 4, + VK_DEPENDENCY_VIEW_LOCAL_BIT = 2 +} VkDependencyFlagBits; +typedef enum VkObjectType { + VK_OBJECT_TYPE_UNKNOWN = 0, + VK_OBJECT_TYPE_INSTANCE = 1, + VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, + VK_OBJECT_TYPE_DEVICE = 3, + VK_OBJECT_TYPE_QUEUE = 4, + VK_OBJECT_TYPE_SEMAPHORE = 5, + VK_OBJECT_TYPE_COMMAND_BUFFER = 6, + VK_OBJECT_TYPE_FENCE = 7, + VK_OBJECT_TYPE_DEVICE_MEMORY = 8, + VK_OBJECT_TYPE_BUFFER = 9, + VK_OBJECT_TYPE_IMAGE = 10, + VK_OBJECT_TYPE_EVENT = 11, + VK_OBJECT_TYPE_QUERY_POOL = 12, + VK_OBJECT_TYPE_BUFFER_VIEW = 13, + VK_OBJECT_TYPE_IMAGE_VIEW = 14, + VK_OBJECT_TYPE_SHADER_MODULE = 15, + VK_OBJECT_TYPE_PIPELINE_CACHE = 16, + VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, + VK_OBJECT_TYPE_RENDER_PASS = 18, + VK_OBJECT_TYPE_PIPELINE = 19, + VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, + VK_OBJECT_TYPE_SAMPLER = 21, + VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, + VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, + VK_OBJECT_TYPE_FRAMEBUFFER = 24, + VK_OBJECT_TYPE_COMMAND_POOL = 25, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, + VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, + VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000 +} VkObjectType; +typedef enum VkDescriptorUpdateTemplateType { + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0 +} VkDescriptorUpdateTemplateType; + +typedef enum VkPointClippingBehavior { + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1 +} VkPointClippingBehavior; +typedef enum VkColorSpaceKHR { + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, + VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR +} VkColorSpaceKHR; +typedef enum VkCompositeAlphaFlagBitsKHR { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 1, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 2, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 4, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 8 +} VkCompositeAlphaFlagBitsKHR; +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3 +} VkPresentModeKHR; +typedef enum VkSurfaceTransformFlagBitsKHR { + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 1, + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 2, + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 4, + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 8, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 16, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 32, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 64, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 128, + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 256 +} VkSurfaceTransformFlagBitsKHR; +typedef enum VkDebugReportFlagBitsEXT { + VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 1, + VK_DEBUG_REPORT_WARNING_BIT_EXT = 2, + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 4, + VK_DEBUG_REPORT_ERROR_BIT_EXT = 8, + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 16 +} VkDebugReportFlagBitsEXT; +typedef enum VkDebugReportObjectTypeEXT { + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, + VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, + VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, + VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, + VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, + VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, + VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, + VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, + VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, + VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, + VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, + VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, + VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, + VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000 +} VkDebugReportObjectTypeEXT; +typedef enum VkExternalMemoryHandleTypeFlagBits { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 1, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 4, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 8, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 16, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 32, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 64 +} VkExternalMemoryHandleTypeFlagBits; +typedef enum VkExternalMemoryFeatureFlagBits { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 1, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 2, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 4 +} VkExternalMemoryFeatureFlagBits; +typedef enum VkExternalSemaphoreHandleTypeFlagBits { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 1, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 4, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 8, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 16 +} VkExternalSemaphoreHandleTypeFlagBits; +typedef enum VkExternalSemaphoreFeatureFlagBits { + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 1, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 2 +} VkExternalSemaphoreFeatureFlagBits; +typedef enum VkSemaphoreImportFlagBits { + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 1 +} VkSemaphoreImportFlagBits; +typedef enum VkExternalFenceHandleTypeFlagBits { + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 1, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 4, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 8 +} VkExternalFenceHandleTypeFlagBits; +typedef enum VkExternalFenceFeatureFlagBits { + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 1, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 2 +} VkExternalFenceFeatureFlagBits; +typedef enum VkFenceImportFlagBits { + VK_FENCE_IMPORT_TEMPORARY_BIT = 1 +} VkFenceImportFlagBits; +typedef enum VkPeerMemoryFeatureFlagBits { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 1, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 2, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 4, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 8 +} VkPeerMemoryFeatureFlagBits; +typedef enum VkMemoryAllocateFlagBits { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 1 +} VkMemoryAllocateFlagBits; +typedef enum VkDeviceGroupPresentModeFlagBitsKHR { + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 1, + VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 2, + VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 4, + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 8 +} VkDeviceGroupPresentModeFlagBitsKHR; +typedef enum VkSwapchainCreateFlagBitsKHR { + VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 1, + VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 2 +} VkSwapchainCreateFlagBitsKHR; +typedef enum VkSubgroupFeatureFlagBits { + VK_SUBGROUP_FEATURE_BASIC_BIT = 1, + VK_SUBGROUP_FEATURE_VOTE_BIT = 2, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 4, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 8, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 16, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 32, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 64, + VK_SUBGROUP_FEATURE_QUAD_BIT = 128 +} VkSubgroupFeatureFlagBits; +typedef enum VkTessellationDomainOrigin { + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1 +} VkTessellationDomainOrigin; +typedef enum VkSamplerYcbcrModelConversion { + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4 +} VkSamplerYcbcrModelConversion; +typedef enum VkSamplerYcbcrRange { + VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1 +} VkSamplerYcbcrRange; +typedef enum VkChromaLocation { + VK_CHROMA_LOCATION_COSITED_EVEN = 0, + VK_CHROMA_LOCATION_MIDPOINT = 1 +} VkChromaLocation; +typedef enum VkVendorId { + VK_VENDOR_ID_VIV = 0x10001, + VK_VENDOR_ID_VSI = 0x10002, + VK_VENDOR_ID_KAZAN = 0x10003 +} VkVendorId; +typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); +typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); +typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); +typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); +typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); +typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); +typedef struct VkBaseOutStructure { + VkStructureType sType; + struct VkBaseOutStructure * pNext; +} VkBaseOutStructure; +typedef struct VkBaseInStructure { + VkStructureType sType; + const struct VkBaseInStructure * pNext; +} VkBaseInStructure; +typedef struct VkOffset2D { + int32_t x; + int32_t y; +} VkOffset2D; +typedef struct VkOffset3D { + int32_t x; + int32_t y; + int32_t z; +} VkOffset3D; +typedef struct VkExtent2D { + uint32_t width; + uint32_t height; +} VkExtent2D; +typedef struct VkExtent3D { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkExtent3D; +typedef struct VkViewport { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} VkViewport; +typedef struct VkRect2D { + VkOffset2D offset; + VkExtent2D extent; +} VkRect2D; +typedef struct VkClearRect { + VkRect2D rect; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkClearRect; +typedef struct VkComponentMapping { + VkComponentSwizzle r; + VkComponentSwizzle g; + VkComponentSwizzle b; + VkComponentSwizzle a; +} VkComponentMapping; +typedef struct VkExtensionProperties { + char extensionName [ VK_MAX_EXTENSION_NAME_SIZE ]; + uint32_t specVersion; +} VkExtensionProperties; +typedef struct VkLayerProperties { + char layerName [ VK_MAX_EXTENSION_NAME_SIZE ]; + uint32_t specVersion; + uint32_t implementationVersion; + char description [ VK_MAX_DESCRIPTION_SIZE ]; +} VkLayerProperties; +typedef struct VkApplicationInfo { + VkStructureType sType; + const void * pNext; + const char * pApplicationName; + uint32_t applicationVersion; + const char * pEngineName; + uint32_t engineVersion; + uint32_t apiVersion; +} VkApplicationInfo; +typedef struct VkAllocationCallbacks { + void * pUserData; + PFN_vkAllocationFunction pfnAllocation; + PFN_vkReallocationFunction pfnReallocation; + PFN_vkFreeFunction pfnFree; + PFN_vkInternalAllocationNotification pfnInternalAllocation; + PFN_vkInternalFreeNotification pfnInternalFree; +} VkAllocationCallbacks; +typedef struct VkDescriptorImageInfo { + VkSampler sampler; + VkImageView imageView; + VkImageLayout imageLayout; +} VkDescriptorImageInfo; +typedef struct VkCopyDescriptorSet { + VkStructureType sType; + const void * pNext; + VkDescriptorSet srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; +} VkCopyDescriptorSet; +typedef struct VkDescriptorPoolSize { + VkDescriptorType type; + uint32_t descriptorCount; +} VkDescriptorPoolSize; +typedef struct VkDescriptorSetAllocateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorPool descriptorPool; + uint32_t descriptorSetCount; + const VkDescriptorSetLayout * pSetLayouts; +} VkDescriptorSetAllocateInfo; +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry * pMapEntries; + size_t dataSize; + const void * pData; +} VkSpecializationInfo; +typedef struct VkVertexInputBindingDescription { + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; +} VkVertexInputBindingDescription; +typedef struct VkVertexInputAttributeDescription { + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription; +typedef struct VkStencilOpState { + VkStencilOp failOp; + VkStencilOp passOp; + VkStencilOp depthFailOp; + VkCompareOp compareOp; + uint32_t compareMask; + uint32_t writeMask; + uint32_t reference; +} VkStencilOpState; +typedef struct VkCommandBufferAllocateInfo { + VkStructureType sType; + const void * pNext; + VkCommandPool commandPool; + VkCommandBufferLevel level; + uint32_t commandBufferCount; +} VkCommandBufferAllocateInfo; +typedef union VkClearColorValue { + float float32 [4]; + int32_t int32 [4]; + uint32_t uint32 [4]; +} VkClearColorValue; +typedef struct VkClearDepthStencilValue { + float depth; + uint32_t stencil; +} VkClearDepthStencilValue; +typedef union VkClearValue { + VkClearColorValue color; + VkClearDepthStencilValue depthStencil; +} VkClearValue; +typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; +} VkAttachmentReference; +typedef struct VkDrawIndirectCommand { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +} VkDrawIndirectCommand; +typedef struct VkDrawIndexedIndirectCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +} VkDrawIndexedIndirectCommand; +typedef struct VkDispatchIndirectCommand { + uint32_t x; + uint32_t y; + uint32_t z; +} VkDispatchIndirectCommand; +typedef struct VkSurfaceFormatKHR { + VkFormat format; + VkColorSpaceKHR colorSpace; +} VkSurfaceFormatKHR; +typedef struct VkPresentInfoKHR { + VkStructureType sType; + const void * pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + uint32_t swapchainCount; + const VkSwapchainKHR * pSwapchains; + const uint32_t * pImageIndices; + VkResult * pResults; +} VkPresentInfoKHR; +typedef struct VkPhysicalDeviceExternalImageFormatInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalImageFormatInfo; +typedef struct VkPhysicalDeviceExternalSemaphoreInfo { + VkStructureType sType; + const void * pNext; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalSemaphoreInfo; +typedef struct VkPhysicalDeviceExternalFenceInfo { + VkStructureType sType; + const void * pNext; + VkExternalFenceHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalFenceInfo; +typedef struct VkPhysicalDeviceMultiviewProperties { + VkStructureType sType; + void * pNext; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; +} VkPhysicalDeviceMultiviewProperties; +typedef struct VkRenderPassMultiviewCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t subpassCount; + const uint32_t * pViewMasks; + uint32_t dependencyCount; + const int32_t * pViewOffsets; + uint32_t correlationMaskCount; + const uint32_t * pCorrelationMasks; +} VkRenderPassMultiviewCreateInfo; +typedef struct VkBindBufferMemoryDeviceGroupInfo { + VkStructureType sType; + const void * pNext; + uint32_t deviceIndexCount; + const uint32_t * pDeviceIndices; +} VkBindBufferMemoryDeviceGroupInfo; +typedef struct VkBindImageMemoryDeviceGroupInfo { + VkStructureType sType; + const void * pNext; + uint32_t deviceIndexCount; + const uint32_t * pDeviceIndices; + uint32_t splitInstanceBindRegionCount; + const VkRect2D * pSplitInstanceBindRegions; +} VkBindImageMemoryDeviceGroupInfo; +typedef struct VkDeviceGroupRenderPassBeginInfo { + VkStructureType sType; + const void * pNext; + uint32_t deviceMask; + uint32_t deviceRenderAreaCount; + const VkRect2D * pDeviceRenderAreas; +} VkDeviceGroupRenderPassBeginInfo; +typedef struct VkDeviceGroupCommandBufferBeginInfo { + VkStructureType sType; + const void * pNext; + uint32_t deviceMask; +} VkDeviceGroupCommandBufferBeginInfo; +typedef struct VkDeviceGroupSubmitInfo { + VkStructureType sType; + const void * pNext; + uint32_t waitSemaphoreCount; + const uint32_t * pWaitSemaphoreDeviceIndices; + uint32_t commandBufferCount; + const uint32_t * pCommandBufferDeviceMasks; + uint32_t signalSemaphoreCount; + const uint32_t * pSignalSemaphoreDeviceIndices; +} VkDeviceGroupSubmitInfo; +typedef struct VkDeviceGroupBindSparseInfo { + VkStructureType sType; + const void * pNext; + uint32_t resourceDeviceIndex; + uint32_t memoryDeviceIndex; +} VkDeviceGroupBindSparseInfo; +typedef struct VkImageSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkSwapchainKHR swapchain; +} VkImageSwapchainCreateInfoKHR; +typedef struct VkBindImageMemorySwapchainInfoKHR { + VkStructureType sType; + const void * pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndex; +} VkBindImageMemorySwapchainInfoKHR; +typedef struct VkAcquireNextImageInfoKHR { + VkStructureType sType; + const void * pNext; + VkSwapchainKHR swapchain; + uint64_t timeout; + VkSemaphore semaphore; + VkFence fence; + uint32_t deviceMask; +} VkAcquireNextImageInfoKHR; +typedef struct VkDeviceGroupPresentInfoKHR { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const uint32_t * pDeviceMasks; + VkDeviceGroupPresentModeFlagBitsKHR mode; +} VkDeviceGroupPresentInfoKHR; +typedef struct VkDeviceGroupDeviceCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t physicalDeviceCount; + const VkPhysicalDevice * pPhysicalDevices; +} VkDeviceGroupDeviceCreateInfo; +typedef struct VkDescriptorUpdateTemplateEntry { + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + size_t offset; + size_t stride; +} VkDescriptorUpdateTemplateEntry; +typedef struct VkBufferMemoryRequirementsInfo2 { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; +} VkBufferMemoryRequirementsInfo2; +typedef struct VkImageMemoryRequirementsInfo2 { + VkStructureType sType; + const void * pNext; + VkImage image; +} VkImageMemoryRequirementsInfo2; +typedef struct VkImageSparseMemoryRequirementsInfo2 { + VkStructureType sType; + const void * pNext; + VkImage image; +} VkImageSparseMemoryRequirementsInfo2; +typedef struct VkPhysicalDevicePointClippingProperties { + VkStructureType sType; + void * pNext; + VkPointClippingBehavior pointClippingBehavior; +} VkPhysicalDevicePointClippingProperties; +typedef struct VkMemoryDedicatedAllocateInfo { + VkStructureType sType; + const void * pNext; + VkImage image; + VkBuffer buffer; +} VkMemoryDedicatedAllocateInfo; +typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkTessellationDomainOrigin domainOrigin; +} VkPipelineTessellationDomainOriginStateCreateInfo; +typedef struct VkSamplerYcbcrConversionInfo { + VkStructureType sType; + const void * pNext; + VkSamplerYcbcrConversion conversion; +} VkSamplerYcbcrConversionInfo; +typedef struct VkBindImagePlaneMemoryInfo { + VkStructureType sType; + const void * pNext; + VkImageAspectFlagBits planeAspect; +} VkBindImagePlaneMemoryInfo; +typedef struct VkImagePlaneMemoryRequirementsInfo { + VkStructureType sType; + const void * pNext; + VkImageAspectFlagBits planeAspect; +} VkImagePlaneMemoryRequirementsInfo; +typedef struct VkSamplerYcbcrConversionImageFormatProperties { + VkStructureType sType; + void * pNext; + uint32_t combinedImageSamplerDescriptorCount; +} VkSamplerYcbcrConversionImageFormatProperties; +typedef uint32_t VkSampleMask; +typedef uint32_t VkBool32; +typedef uint32_t VkFlags; +typedef uint64_t VkDeviceSize; +typedef VkFlags VkFramebufferCreateFlags; +typedef VkFlags VkQueryPoolCreateFlags; +typedef VkFlags VkRenderPassCreateFlags; +typedef VkFlags VkSamplerCreateFlags; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkPipelineCacheCreateFlags; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineShaderStageCreateFlags; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; +typedef VkFlags VkBufferViewCreateFlags; +typedef VkFlags VkInstanceCreateFlags; +typedef VkFlags VkDeviceCreateFlags; +typedef VkFlags VkDeviceQueueCreateFlags; +typedef VkFlags VkQueueFlags; +typedef VkFlags VkMemoryPropertyFlags; +typedef VkFlags VkMemoryHeapFlags; +typedef VkFlags VkAccessFlags; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferCreateFlags; +typedef VkFlags VkShaderStageFlags; +typedef VkFlags VkImageUsageFlags; +typedef VkFlags VkImageCreateFlags; +typedef VkFlags VkImageViewCreateFlags; +typedef VkFlags VkPipelineCreateFlags; +typedef VkFlags VkColorComponentFlags; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; +typedef VkFlags VkFormatFeatureFlags; +typedef VkFlags VkQueryControlFlags; +typedef VkFlags VkQueryResultFlags; +typedef VkFlags VkShaderModuleCreateFlags; +typedef VkFlags VkEventCreateFlags; +typedef VkFlags VkCommandPoolCreateFlags; +typedef VkFlags VkCommandPoolResetFlags; +typedef VkFlags VkCommandBufferResetFlags; +typedef VkFlags VkCommandBufferUsageFlags; +typedef VkFlags VkQueryPipelineStatisticFlags; +typedef VkFlags VkMemoryMapFlags; +typedef VkFlags VkImageAspectFlags; +typedef VkFlags VkSparseMemoryBindFlags; +typedef VkFlags VkSparseImageFormatFlags; +typedef VkFlags VkSubpassDescriptionFlags; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkSampleCountFlags; +typedef VkFlags VkAttachmentDescriptionFlags; +typedef VkFlags VkStencilFaceFlags; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; +typedef VkFlags VkDependencyFlags; +typedef VkFlags VkSubgroupFeatureFlags; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; +typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; +typedef VkFlags VkSwapchainCreateFlagsKHR; +typedef VkFlags VkPeerMemoryFeatureFlags; +typedef VkFlags VkMemoryAllocateFlags; +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +typedef VkFlags VkDebugReportFlagsEXT; +typedef VkFlags VkCommandPoolTrimFlags; +typedef VkFlags VkExternalMemoryHandleTypeFlags; +typedef VkFlags VkExternalMemoryFeatureFlags; +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; +typedef VkFlags VkExternalSemaphoreFeatureFlags; +typedef VkFlags VkSemaphoreImportFlags; +typedef VkFlags VkExternalFenceHandleTypeFlags; +typedef VkFlags VkExternalFenceFeatureFlags; +typedef VkFlags VkFenceImportFlags; +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); +typedef struct VkDeviceQueueCreateInfo { + VkStructureType sType; + const void * pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float * pQueuePriorities; +} VkDeviceQueueCreateInfo; +typedef struct VkInstanceCreateInfo { + VkStructureType sType; + const void * pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo * pApplicationInfo; + uint32_t enabledLayerCount; + const char * const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char * const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; +typedef struct VkMemoryAllocateInfo { + VkStructureType sType; + const void * pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; +typedef struct VkMappedMemoryRange { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; +typedef struct VkWriteDescriptorSet { + VkStructureType sType; + const void * pNext; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo * pImageInfo; + const VkDescriptorBufferInfo * pBufferInfo; + const VkBufferView * pTexelBufferView; +} VkWriteDescriptorSet; +typedef struct VkBufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; +} VkBufferCreateInfo; +typedef struct VkBufferViewCreateInfo { + VkStructureType sType; + const void * pNext; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; +typedef struct VkMemoryBarrier { + VkStructureType sType; + const void * pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; +typedef struct VkBufferMemoryBarrier { + VkStructureType sType; + const void * pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; +typedef struct VkImageMemoryBarrier { + VkStructureType sType; + const void * pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; +typedef struct VkImageCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; +typedef struct VkImageViewCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind * pBinds; +} VkSparseBufferMemoryBindInfo; +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind * pBinds; +} VkSparseImageOpaqueMemoryBindInfo; +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind * pBinds; +} VkSparseImageMemoryBindInfo; +typedef struct VkBindSparseInfo { + VkStructureType sType; + const void * pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo * pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo * pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo * pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore * pSignalSemaphores; +} VkBindSparseInfo; +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets [2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets [2]; +} VkImageBlit; +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void * pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t * pCode; +} VkShaderModuleCreateInfo; +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler * pImmutableSamplers; +} VkDescriptorSetLayoutBinding; +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding * pBindings; +} VkDescriptorSetLayoutCreateInfo; +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize * pPoolSizes; +} VkDescriptorPoolCreateInfo; +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char * pName; + const VkSpecializationInfo * pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription * pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription * pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport * pViewports; + uint32_t scissorCount; + const VkRect2D * pScissors; +} VkPipelineViewportStateCreateInfo; +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask * pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState * pAttachments; + float blendConstants [4]; +} VkPipelineColorBlendStateCreateInfo; +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState * pDynamicStates; +} VkPipelineDynamicStateCreateInfo; +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineVertexInputStateCreateInfo * pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo * pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo * pTessellationState; + const VkPipelineViewportStateCreateInfo * pViewportState; + const VkPipelineRasterizationStateCreateInfo * pRasterizationState; + const VkPipelineMultisampleStateCreateInfo * pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo * pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo * pColorBlendState; + const VkPipelineDynamicStateCreateInfo * pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void * pInitialData; +} VkPipelineCacheCreateInfo; +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; +} VkPipelineLayoutCreateInfo; +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void * pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void * pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void * pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo * pInheritanceInfo; +} VkCommandBufferBeginInfo; +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void * pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue * pClearValues; +} VkRenderPassBeginInfo; +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription; +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference * pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference * pColorAttachments; + const VkAttachmentReference * pResolveAttachments; + const VkAttachmentReference * pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t * pPreserveAttachments; +} VkSubpassDescription; +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void * pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription * pAttachments; + uint32_t subpassCount; + const VkSubpassDescription * pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency * pDependencies; +} VkRenderPassCreateInfo; +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void * pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void * pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount [3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize [3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions [2]; + float viewportBoundsRange [2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange [2]; + float lineWidthRange [2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void * pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView * pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; +typedef struct VkSubmitInfo { + VkStructureType sType; + const void * pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + const VkPipelineStageFlags * pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer * pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore * pSignalSemaphores; +} VkSubmitInfo; +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void * pUserData; +} VkDebugReportCallbackCreateInfoEXT; +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; +typedef struct VkFormatProperties2 { + VkStructureType sType; + void * pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void * pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void * pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void * pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; +typedef struct VkPhysicalDeviceVariablePointersFeatures { + VkStructureType sType; + void * pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointersFeatures; +typedef struct VkPhysicalDeviceVariablePointerFeatures VkPhysicalDeviceVariablePointerFeatures; +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void * pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void * pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void * pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void * pNext; + uint8_t deviceUUID [ VK_UUID_SIZE ]; + uint8_t driverUUID [ VK_UUID_SIZE ]; + uint8_t deviceLUID [ VK_LUID_SIZE ]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void * pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void * pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void * pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void * pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices [ VK_MAX_DEVICE_GROUP_SIZE ]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void * pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void * pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + const void * pNext; + uint32_t presentMask [ VK_MAX_DEVICE_GROUP_SIZE ]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry * pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference * pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void * pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void * pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void * pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; +typedef struct VkMemoryRequirements2KHR VkMemoryRequirements2KHR; +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void * pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void * pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void * pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void * pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void * pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void * pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void * pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void * pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void * pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParametersFeatures; +typedef struct VkPhysicalDeviceShaderDrawParameterFeatures VkPhysicalDeviceShaderDrawParameterFeatures; +typedef struct VkPhysicalDeviceProperties { + uint32_t apiVersion; + uint32_t driverVersion; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceType deviceType; + char deviceName [ VK_MAX_PHYSICAL_DEVICE_NAME_SIZE ]; + uint8_t pipelineCacheUUID [ VK_UUID_SIZE ]; + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceSparseProperties sparseProperties; +} VkPhysicalDeviceProperties; +typedef struct VkDeviceCreateInfo { + VkStructureType sType; + const void * pNext; + VkDeviceCreateFlags flags; + uint32_t queueCreateInfoCount; + const VkDeviceQueueCreateInfo * pQueueCreateInfos; + uint32_t enabledLayerCount; + const char * const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char * const* ppEnabledExtensionNames; + const VkPhysicalDeviceFeatures * pEnabledFeatures; +} VkDeviceCreateInfo; +typedef struct VkPhysicalDeviceMemoryProperties { + uint32_t memoryTypeCount; + VkMemoryType memoryTypes [ VK_MAX_MEMORY_TYPES ]; + uint32_t memoryHeapCount; + VkMemoryHeap memoryHeaps [ VK_MAX_MEMORY_HEAPS ]; +} VkPhysicalDeviceMemoryProperties; +typedef struct VkPhysicalDeviceProperties2 { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceProperties properties; +} VkPhysicalDeviceProperties2; +typedef struct VkPhysicalDeviceMemoryProperties2 { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceMemoryProperties memoryProperties; +} VkPhysicalDeviceMemoryProperties2; + + +#define VK_VERSION_1_0 1 +GLAD_API_CALL int GLAD_VK_VERSION_1_0; +#define VK_VERSION_1_1 1 +GLAD_API_CALL int GLAD_VK_VERSION_1_1; +#define VK_EXT_debug_report 1 +GLAD_API_CALL int GLAD_VK_EXT_debug_report; +#define VK_KHR_surface 1 +GLAD_API_CALL int GLAD_VK_KHR_surface; +#define VK_KHR_swapchain 1 +GLAD_API_CALL int GLAD_VK_KHR_swapchain; + + +typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR * pAcquireInfo, uint32_t * pImageIndex); +typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t * pImageIndex); +typedef VkResult (GLAD_API_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo * pAllocateInfo, VkCommandBuffer * pCommandBuffers); +typedef VkResult (GLAD_API_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo * pAllocateInfo, VkDescriptorSet * pDescriptorSets); +typedef VkResult (GLAD_API_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo * pAllocateInfo, const VkAllocationCallbacks * pAllocator, VkDeviceMemory * pMemory); +typedef VkResult (GLAD_API_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo * pBeginInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo * pBindInfos); +typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo * pBindInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, VkSubpassContents contents); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t * pDynamicOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit * pRegions, VkFilter filter); +typedef void (GLAD_API_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment * pAttachments, uint32_t rectCount, const VkClearRect * pRects); +typedef void (GLAD_API_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue * pColor, uint32_t rangeCount, const VkImageSubresourceRange * pRanges); +typedef void (GLAD_API_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue * pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange * pRanges); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (GLAD_API_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (GLAD_API_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers); +typedef void (GLAD_API_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); +typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers); +typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void * pValues); +typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants [4]); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (GLAD_API_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D * pScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport * pViewports); +typedef void (GLAD_API_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void * pData); +typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBuffer * pBuffer); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBufferView * pView); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCommandPool * pCommandPool); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDebugReportCallbackEXT * pCallback); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorPool * pDescriptorPool); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorSetLayout * pSetLayout); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice * pDevice); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkEvent * pEvent); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFramebuffer * pFramebuffer); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImage * pImage); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImageView * pView); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkInstance * pInstance); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineCache * pPipelineCache); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineLayout * pPipelineLayout); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkQueryPool * pQueryPool); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSampler * pSampler); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSamplerYcbcrConversion * pYcbcrConversion); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSemaphore * pSemaphore); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkShaderModule * pShaderModule); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSwapchainKHR * pSwapchain); +typedef void (GLAD_API_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char * pLayerPrefix, const char * pMessage); +typedef void (GLAD_API_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks * pAllocator); +typedef VkResult (GLAD_API_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); +typedef VkResult (GLAD_API_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char * pLayerName, uint32_t * pPropertyCount, VkExtensionProperties * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkLayerProperties * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char * pLayerName, uint32_t * pPropertyCount, VkExtensionProperties * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t * pPropertyCount, VkLayerProperties * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t * pApiVersion); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t * pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties * pPhysicalDeviceGroupProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t * pPhysicalDeviceCount, VkPhysicalDevice * pPhysicalDevices); +typedef VkResult (GLAD_API_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges); +typedef void (GLAD_API_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers); +typedef VkResult (GLAD_API_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets); +typedef void (GLAD_API_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, VkDescriptorSetLayoutSupport * pSupport); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags * pPeerMemoryFeatures); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR * pDeviceGroupPresentCapabilities); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR * pModes); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize * pCommittedMemoryInBytes); +typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char * pName); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue * pQueue); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2 * pQueueInfo, VkQueue * pQueue); +typedef VkResult (GLAD_API_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); +typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements * pSparseMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource * pSubresource, VkSubresourceLayout * pLayout); +typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char * pName); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo, VkExternalBufferProperties * pExternalBufferProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo * pExternalFenceInfo, VkExternalFenceProperties * pExternalFenceProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo * pExternalSemaphoreInfo, VkExternalSemaphoreProperties * pExternalSemaphoreProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures * pFeatures); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 * pFeatures); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties * pFormatProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 * pFormatProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties * pImageFormatProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo, VkImageFormatProperties2 * pImageFormatProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties * pMemoryProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 * pMemoryProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pRectCount, VkRect2D * pRects); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties * pProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 * pProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties * pQueueFamilyProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties2 * pQueueFamilyProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t * pPropertyCount, VkSparseImageFormatProperties * pProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo, uint32_t * pPropertyCount, VkSparseImageFormatProperties2 * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR * pSurfaceCapabilities); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pSurfaceFormatCount, VkSurfaceFormatKHR * pSurfaceFormats); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pPresentModeCount, VkPresentModeKHR * pPresentModes); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 * pSupported); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t * pDataSize, void * pData); +typedef VkResult (GLAD_API_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void * pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (GLAD_API_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D * pGranularity); +typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t * pSwapchainImageCount, VkImage * pSwapchainImages); +typedef VkResult (GLAD_API_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges); +typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void ** ppData); +typedef VkResult (GLAD_API_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache * pSrcCaches); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo * pBindInfo, VkFence fence); +typedef VkResult (GLAD_API_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR * pPresentInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo * pSubmits, VkFence fence); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); +typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); +typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); +typedef VkResult (GLAD_API_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); +typedef VkResult (GLAD_API_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); +typedef VkResult (GLAD_API_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences); +typedef VkResult (GLAD_API_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); +typedef void (GLAD_API_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +typedef void (GLAD_API_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void * pData); +typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet * pDescriptorCopies); +typedef VkResult (GLAD_API_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences, VkBool32 waitAll, uint64_t timeout); + +GLAD_API_CALL PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR; +#define vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR +GLAD_API_CALL PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR; +#define vkAcquireNextImageKHR glad_vkAcquireNextImageKHR +GLAD_API_CALL PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers; +#define vkAllocateCommandBuffers glad_vkAllocateCommandBuffers +GLAD_API_CALL PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets; +#define vkAllocateDescriptorSets glad_vkAllocateDescriptorSets +GLAD_API_CALL PFN_vkAllocateMemory glad_vkAllocateMemory; +#define vkAllocateMemory glad_vkAllocateMemory +GLAD_API_CALL PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer; +#define vkBeginCommandBuffer glad_vkBeginCommandBuffer +GLAD_API_CALL PFN_vkBindBufferMemory glad_vkBindBufferMemory; +#define vkBindBufferMemory glad_vkBindBufferMemory +GLAD_API_CALL PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2; +#define vkBindBufferMemory2 glad_vkBindBufferMemory2 +GLAD_API_CALL PFN_vkBindImageMemory glad_vkBindImageMemory; +#define vkBindImageMemory glad_vkBindImageMemory +GLAD_API_CALL PFN_vkBindImageMemory2 glad_vkBindImageMemory2; +#define vkBindImageMemory2 glad_vkBindImageMemory2 +GLAD_API_CALL PFN_vkCmdBeginQuery glad_vkCmdBeginQuery; +#define vkCmdBeginQuery glad_vkCmdBeginQuery +GLAD_API_CALL PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass; +#define vkCmdBeginRenderPass glad_vkCmdBeginRenderPass +GLAD_API_CALL PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets; +#define vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets +GLAD_API_CALL PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer; +#define vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer +GLAD_API_CALL PFN_vkCmdBindPipeline glad_vkCmdBindPipeline; +#define vkCmdBindPipeline glad_vkCmdBindPipeline +GLAD_API_CALL PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers; +#define vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers +GLAD_API_CALL PFN_vkCmdBlitImage glad_vkCmdBlitImage; +#define vkCmdBlitImage glad_vkCmdBlitImage +GLAD_API_CALL PFN_vkCmdClearAttachments glad_vkCmdClearAttachments; +#define vkCmdClearAttachments glad_vkCmdClearAttachments +GLAD_API_CALL PFN_vkCmdClearColorImage glad_vkCmdClearColorImage; +#define vkCmdClearColorImage glad_vkCmdClearColorImage +GLAD_API_CALL PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage; +#define vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage +GLAD_API_CALL PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer; +#define vkCmdCopyBuffer glad_vkCmdCopyBuffer +GLAD_API_CALL PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage; +#define vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage +GLAD_API_CALL PFN_vkCmdCopyImage glad_vkCmdCopyImage; +#define vkCmdCopyImage glad_vkCmdCopyImage +GLAD_API_CALL PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer; +#define vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer +GLAD_API_CALL PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults; +#define vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults +GLAD_API_CALL PFN_vkCmdDispatch glad_vkCmdDispatch; +#define vkCmdDispatch glad_vkCmdDispatch +GLAD_API_CALL PFN_vkCmdDispatchBase glad_vkCmdDispatchBase; +#define vkCmdDispatchBase glad_vkCmdDispatchBase +GLAD_API_CALL PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect; +#define vkCmdDispatchIndirect glad_vkCmdDispatchIndirect +GLAD_API_CALL PFN_vkCmdDraw glad_vkCmdDraw; +#define vkCmdDraw glad_vkCmdDraw +GLAD_API_CALL PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed; +#define vkCmdDrawIndexed glad_vkCmdDrawIndexed +GLAD_API_CALL PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect; +#define vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect +GLAD_API_CALL PFN_vkCmdDrawIndirect glad_vkCmdDrawIndirect; +#define vkCmdDrawIndirect glad_vkCmdDrawIndirect +GLAD_API_CALL PFN_vkCmdEndQuery glad_vkCmdEndQuery; +#define vkCmdEndQuery glad_vkCmdEndQuery +GLAD_API_CALL PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass; +#define vkCmdEndRenderPass glad_vkCmdEndRenderPass +GLAD_API_CALL PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands; +#define vkCmdExecuteCommands glad_vkCmdExecuteCommands +GLAD_API_CALL PFN_vkCmdFillBuffer glad_vkCmdFillBuffer; +#define vkCmdFillBuffer glad_vkCmdFillBuffer +GLAD_API_CALL PFN_vkCmdNextSubpass glad_vkCmdNextSubpass; +#define vkCmdNextSubpass glad_vkCmdNextSubpass +GLAD_API_CALL PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier; +#define vkCmdPipelineBarrier glad_vkCmdPipelineBarrier +GLAD_API_CALL PFN_vkCmdPushConstants glad_vkCmdPushConstants; +#define vkCmdPushConstants glad_vkCmdPushConstants +GLAD_API_CALL PFN_vkCmdResetEvent glad_vkCmdResetEvent; +#define vkCmdResetEvent glad_vkCmdResetEvent +GLAD_API_CALL PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool; +#define vkCmdResetQueryPool glad_vkCmdResetQueryPool +GLAD_API_CALL PFN_vkCmdResolveImage glad_vkCmdResolveImage; +#define vkCmdResolveImage glad_vkCmdResolveImage +GLAD_API_CALL PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants; +#define vkCmdSetBlendConstants glad_vkCmdSetBlendConstants +GLAD_API_CALL PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias; +#define vkCmdSetDepthBias glad_vkCmdSetDepthBias +GLAD_API_CALL PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds; +#define vkCmdSetDepthBounds glad_vkCmdSetDepthBounds +GLAD_API_CALL PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask; +#define vkCmdSetDeviceMask glad_vkCmdSetDeviceMask +GLAD_API_CALL PFN_vkCmdSetEvent glad_vkCmdSetEvent; +#define vkCmdSetEvent glad_vkCmdSetEvent +GLAD_API_CALL PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth; +#define vkCmdSetLineWidth glad_vkCmdSetLineWidth +GLAD_API_CALL PFN_vkCmdSetScissor glad_vkCmdSetScissor; +#define vkCmdSetScissor glad_vkCmdSetScissor +GLAD_API_CALL PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask; +#define vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask +GLAD_API_CALL PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference; +#define vkCmdSetStencilReference glad_vkCmdSetStencilReference +GLAD_API_CALL PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask; +#define vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask +GLAD_API_CALL PFN_vkCmdSetViewport glad_vkCmdSetViewport; +#define vkCmdSetViewport glad_vkCmdSetViewport +GLAD_API_CALL PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer; +#define vkCmdUpdateBuffer glad_vkCmdUpdateBuffer +GLAD_API_CALL PFN_vkCmdWaitEvents glad_vkCmdWaitEvents; +#define vkCmdWaitEvents glad_vkCmdWaitEvents +GLAD_API_CALL PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp; +#define vkCmdWriteTimestamp glad_vkCmdWriteTimestamp +GLAD_API_CALL PFN_vkCreateBuffer glad_vkCreateBuffer; +#define vkCreateBuffer glad_vkCreateBuffer +GLAD_API_CALL PFN_vkCreateBufferView glad_vkCreateBufferView; +#define vkCreateBufferView glad_vkCreateBufferView +GLAD_API_CALL PFN_vkCreateCommandPool glad_vkCreateCommandPool; +#define vkCreateCommandPool glad_vkCreateCommandPool +GLAD_API_CALL PFN_vkCreateComputePipelines glad_vkCreateComputePipelines; +#define vkCreateComputePipelines glad_vkCreateComputePipelines +GLAD_API_CALL PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT; +#define vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT +GLAD_API_CALL PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool; +#define vkCreateDescriptorPool glad_vkCreateDescriptorPool +GLAD_API_CALL PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout; +#define vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout +GLAD_API_CALL PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate; +#define vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate +GLAD_API_CALL PFN_vkCreateDevice glad_vkCreateDevice; +#define vkCreateDevice glad_vkCreateDevice +GLAD_API_CALL PFN_vkCreateEvent glad_vkCreateEvent; +#define vkCreateEvent glad_vkCreateEvent +GLAD_API_CALL PFN_vkCreateFence glad_vkCreateFence; +#define vkCreateFence glad_vkCreateFence +GLAD_API_CALL PFN_vkCreateFramebuffer glad_vkCreateFramebuffer; +#define vkCreateFramebuffer glad_vkCreateFramebuffer +GLAD_API_CALL PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines; +#define vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines +GLAD_API_CALL PFN_vkCreateImage glad_vkCreateImage; +#define vkCreateImage glad_vkCreateImage +GLAD_API_CALL PFN_vkCreateImageView glad_vkCreateImageView; +#define vkCreateImageView glad_vkCreateImageView +GLAD_API_CALL PFN_vkCreateInstance glad_vkCreateInstance; +#define vkCreateInstance glad_vkCreateInstance +GLAD_API_CALL PFN_vkCreatePipelineCache glad_vkCreatePipelineCache; +#define vkCreatePipelineCache glad_vkCreatePipelineCache +GLAD_API_CALL PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout; +#define vkCreatePipelineLayout glad_vkCreatePipelineLayout +GLAD_API_CALL PFN_vkCreateQueryPool glad_vkCreateQueryPool; +#define vkCreateQueryPool glad_vkCreateQueryPool +GLAD_API_CALL PFN_vkCreateRenderPass glad_vkCreateRenderPass; +#define vkCreateRenderPass glad_vkCreateRenderPass +GLAD_API_CALL PFN_vkCreateSampler glad_vkCreateSampler; +#define vkCreateSampler glad_vkCreateSampler +GLAD_API_CALL PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion; +#define vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion +GLAD_API_CALL PFN_vkCreateSemaphore glad_vkCreateSemaphore; +#define vkCreateSemaphore glad_vkCreateSemaphore +GLAD_API_CALL PFN_vkCreateShaderModule glad_vkCreateShaderModule; +#define vkCreateShaderModule glad_vkCreateShaderModule +GLAD_API_CALL PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR; +#define vkCreateSwapchainKHR glad_vkCreateSwapchainKHR +GLAD_API_CALL PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT; +#define vkDebugReportMessageEXT glad_vkDebugReportMessageEXT +GLAD_API_CALL PFN_vkDestroyBuffer glad_vkDestroyBuffer; +#define vkDestroyBuffer glad_vkDestroyBuffer +GLAD_API_CALL PFN_vkDestroyBufferView glad_vkDestroyBufferView; +#define vkDestroyBufferView glad_vkDestroyBufferView +GLAD_API_CALL PFN_vkDestroyCommandPool glad_vkDestroyCommandPool; +#define vkDestroyCommandPool glad_vkDestroyCommandPool +GLAD_API_CALL PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT; +#define vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT +GLAD_API_CALL PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool; +#define vkDestroyDescriptorPool glad_vkDestroyDescriptorPool +GLAD_API_CALL PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout; +#define vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout +GLAD_API_CALL PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate; +#define vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate +GLAD_API_CALL PFN_vkDestroyDevice glad_vkDestroyDevice; +#define vkDestroyDevice glad_vkDestroyDevice +GLAD_API_CALL PFN_vkDestroyEvent glad_vkDestroyEvent; +#define vkDestroyEvent glad_vkDestroyEvent +GLAD_API_CALL PFN_vkDestroyFence glad_vkDestroyFence; +#define vkDestroyFence glad_vkDestroyFence +GLAD_API_CALL PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer; +#define vkDestroyFramebuffer glad_vkDestroyFramebuffer +GLAD_API_CALL PFN_vkDestroyImage glad_vkDestroyImage; +#define vkDestroyImage glad_vkDestroyImage +GLAD_API_CALL PFN_vkDestroyImageView glad_vkDestroyImageView; +#define vkDestroyImageView glad_vkDestroyImageView +GLAD_API_CALL PFN_vkDestroyInstance glad_vkDestroyInstance; +#define vkDestroyInstance glad_vkDestroyInstance +GLAD_API_CALL PFN_vkDestroyPipeline glad_vkDestroyPipeline; +#define vkDestroyPipeline glad_vkDestroyPipeline +GLAD_API_CALL PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache; +#define vkDestroyPipelineCache glad_vkDestroyPipelineCache +GLAD_API_CALL PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout; +#define vkDestroyPipelineLayout glad_vkDestroyPipelineLayout +GLAD_API_CALL PFN_vkDestroyQueryPool glad_vkDestroyQueryPool; +#define vkDestroyQueryPool glad_vkDestroyQueryPool +GLAD_API_CALL PFN_vkDestroyRenderPass glad_vkDestroyRenderPass; +#define vkDestroyRenderPass glad_vkDestroyRenderPass +GLAD_API_CALL PFN_vkDestroySampler glad_vkDestroySampler; +#define vkDestroySampler glad_vkDestroySampler +GLAD_API_CALL PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion; +#define vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion +GLAD_API_CALL PFN_vkDestroySemaphore glad_vkDestroySemaphore; +#define vkDestroySemaphore glad_vkDestroySemaphore +GLAD_API_CALL PFN_vkDestroyShaderModule glad_vkDestroyShaderModule; +#define vkDestroyShaderModule glad_vkDestroyShaderModule +GLAD_API_CALL PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR; +#define vkDestroySurfaceKHR glad_vkDestroySurfaceKHR +GLAD_API_CALL PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR; +#define vkDestroySwapchainKHR glad_vkDestroySwapchainKHR +GLAD_API_CALL PFN_vkDeviceWaitIdle glad_vkDeviceWaitIdle; +#define vkDeviceWaitIdle glad_vkDeviceWaitIdle +GLAD_API_CALL PFN_vkEndCommandBuffer glad_vkEndCommandBuffer; +#define vkEndCommandBuffer glad_vkEndCommandBuffer +GLAD_API_CALL PFN_vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties; +#define vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties +GLAD_API_CALL PFN_vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties; +#define vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties +GLAD_API_CALL PFN_vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties; +#define vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties +GLAD_API_CALL PFN_vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties; +#define vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties +GLAD_API_CALL PFN_vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion; +#define vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion +GLAD_API_CALL PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups; +#define vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups +GLAD_API_CALL PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices; +#define vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices +GLAD_API_CALL PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges; +#define vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges +GLAD_API_CALL PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers; +#define vkFreeCommandBuffers glad_vkFreeCommandBuffers +GLAD_API_CALL PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets; +#define vkFreeDescriptorSets glad_vkFreeDescriptorSets +GLAD_API_CALL PFN_vkFreeMemory glad_vkFreeMemory; +#define vkFreeMemory glad_vkFreeMemory +GLAD_API_CALL PFN_vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements; +#define vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements +GLAD_API_CALL PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2; +#define vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2 +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport; +#define vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport +GLAD_API_CALL PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures; +#define vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures +GLAD_API_CALL PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR; +#define vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR +GLAD_API_CALL PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR; +#define vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR +GLAD_API_CALL PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment; +#define vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment +GLAD_API_CALL PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr; +#define vkGetDeviceProcAddr glad_vkGetDeviceProcAddr +GLAD_API_CALL PFN_vkGetDeviceQueue glad_vkGetDeviceQueue; +#define vkGetDeviceQueue glad_vkGetDeviceQueue +GLAD_API_CALL PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2; +#define vkGetDeviceQueue2 glad_vkGetDeviceQueue2 +GLAD_API_CALL PFN_vkGetEventStatus glad_vkGetEventStatus; +#define vkGetEventStatus glad_vkGetEventStatus +GLAD_API_CALL PFN_vkGetFenceStatus glad_vkGetFenceStatus; +#define vkGetFenceStatus glad_vkGetFenceStatus +GLAD_API_CALL PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements; +#define vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements +GLAD_API_CALL PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2; +#define vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 +GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements; +#define vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements +GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2; +#define vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2 +GLAD_API_CALL PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout; +#define vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout +GLAD_API_CALL PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr; +#define vkGetInstanceProcAddr glad_vkGetInstanceProcAddr +GLAD_API_CALL PFN_vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties; +#define vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties; +#define vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties; +#define vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures; +#define vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures +GLAD_API_CALL PFN_vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2; +#define vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2 +GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties; +#define vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2; +#define vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 +GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties; +#define vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2; +#define vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2 +GLAD_API_CALL PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties; +#define vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2; +#define vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2 +GLAD_API_CALL PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR; +#define vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties; +#define vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2; +#define vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2 +GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties; +#define vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2; +#define vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 +GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties; +#define vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties +GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2; +#define vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2 +GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR; +#define vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR; +#define vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR; +#define vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR +GLAD_API_CALL PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData; +#define vkGetPipelineCacheData glad_vkGetPipelineCacheData +GLAD_API_CALL PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults; +#define vkGetQueryPoolResults glad_vkGetQueryPoolResults +GLAD_API_CALL PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity; +#define vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity +GLAD_API_CALL PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR; +#define vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR +GLAD_API_CALL PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges; +#define vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges +GLAD_API_CALL PFN_vkMapMemory glad_vkMapMemory; +#define vkMapMemory glad_vkMapMemory +GLAD_API_CALL PFN_vkMergePipelineCaches glad_vkMergePipelineCaches; +#define vkMergePipelineCaches glad_vkMergePipelineCaches +GLAD_API_CALL PFN_vkQueueBindSparse glad_vkQueueBindSparse; +#define vkQueueBindSparse glad_vkQueueBindSparse +GLAD_API_CALL PFN_vkQueuePresentKHR glad_vkQueuePresentKHR; +#define vkQueuePresentKHR glad_vkQueuePresentKHR +GLAD_API_CALL PFN_vkQueueSubmit glad_vkQueueSubmit; +#define vkQueueSubmit glad_vkQueueSubmit +GLAD_API_CALL PFN_vkQueueWaitIdle glad_vkQueueWaitIdle; +#define vkQueueWaitIdle glad_vkQueueWaitIdle +GLAD_API_CALL PFN_vkResetCommandBuffer glad_vkResetCommandBuffer; +#define vkResetCommandBuffer glad_vkResetCommandBuffer +GLAD_API_CALL PFN_vkResetCommandPool glad_vkResetCommandPool; +#define vkResetCommandPool glad_vkResetCommandPool +GLAD_API_CALL PFN_vkResetDescriptorPool glad_vkResetDescriptorPool; +#define vkResetDescriptorPool glad_vkResetDescriptorPool +GLAD_API_CALL PFN_vkResetEvent glad_vkResetEvent; +#define vkResetEvent glad_vkResetEvent +GLAD_API_CALL PFN_vkResetFences glad_vkResetFences; +#define vkResetFences glad_vkResetFences +GLAD_API_CALL PFN_vkSetEvent glad_vkSetEvent; +#define vkSetEvent glad_vkSetEvent +GLAD_API_CALL PFN_vkTrimCommandPool glad_vkTrimCommandPool; +#define vkTrimCommandPool glad_vkTrimCommandPool +GLAD_API_CALL PFN_vkUnmapMemory glad_vkUnmapMemory; +#define vkUnmapMemory glad_vkUnmapMemory +GLAD_API_CALL PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate; +#define vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate +GLAD_API_CALL PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets; +#define vkUpdateDescriptorSets glad_vkUpdateDescriptorSets +GLAD_API_CALL PFN_vkWaitForFences glad_vkWaitForFences; +#define vkWaitForFences glad_vkWaitForFences + + +GLAD_API_CALL int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadVulkan( VkPhysicalDevice physical_device, GLADloadfunc load); + + + + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/raylib/external/glfw/deps/glad_gl.c b/raylib/external/glfw/deps/glad_gl.c new file mode 100644 index 0000000..2d4c87f --- /dev/null +++ b/raylib/external/glfw/deps/glad_gl.c @@ -0,0 +1,1791 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + + +int GLAD_GL_VERSION_1_0 = 0; +int GLAD_GL_VERSION_1_1 = 0; +int GLAD_GL_VERSION_1_2 = 0; +int GLAD_GL_VERSION_1_3 = 0; +int GLAD_GL_VERSION_1_4 = 0; +int GLAD_GL_VERSION_1_5 = 0; +int GLAD_GL_VERSION_2_0 = 0; +int GLAD_GL_VERSION_2_1 = 0; +int GLAD_GL_VERSION_3_0 = 0; +int GLAD_GL_VERSION_3_1 = 0; +int GLAD_GL_VERSION_3_2 = 0; +int GLAD_GL_VERSION_3_3 = 0; +int GLAD_GL_ARB_multisample = 0; +int GLAD_GL_ARB_robustness = 0; +int GLAD_GL_KHR_debug = 0; + + + +PFNGLACCUMPROC glad_glAccum = NULL; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL; +PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL; +PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINPROC glad_glBegin = NULL; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; +PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; +PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; +PFNGLBITMAPPROC glad_glBitmap = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCALLLISTPROC glad_glCallList = NULL; +PFNGLCALLLISTSPROC glad_glCallLists = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARACCUMPROC glad_glClearAccum = NULL; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; +PFNGLCLEARINDEXPROC glad_glClearIndex = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; +PFNGLCLIPPLANEPROC glad_glClipPlane = NULL; +PFNGLCOLOR3BPROC glad_glColor3b = NULL; +PFNGLCOLOR3BVPROC glad_glColor3bv = NULL; +PFNGLCOLOR3DPROC glad_glColor3d = NULL; +PFNGLCOLOR3DVPROC glad_glColor3dv = NULL; +PFNGLCOLOR3FPROC glad_glColor3f = NULL; +PFNGLCOLOR3FVPROC glad_glColor3fv = NULL; +PFNGLCOLOR3IPROC glad_glColor3i = NULL; +PFNGLCOLOR3IVPROC glad_glColor3iv = NULL; +PFNGLCOLOR3SPROC glad_glColor3s = NULL; +PFNGLCOLOR3SVPROC glad_glColor3sv = NULL; +PFNGLCOLOR3UBPROC glad_glColor3ub = NULL; +PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL; +PFNGLCOLOR3UIPROC glad_glColor3ui = NULL; +PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL; +PFNGLCOLOR3USPROC glad_glColor3us = NULL; +PFNGLCOLOR3USVPROC glad_glColor3usv = NULL; +PFNGLCOLOR4BPROC glad_glColor4b = NULL; +PFNGLCOLOR4BVPROC glad_glColor4bv = NULL; +PFNGLCOLOR4DPROC glad_glColor4d = NULL; +PFNGLCOLOR4DVPROC glad_glColor4dv = NULL; +PFNGLCOLOR4FPROC glad_glColor4f = NULL; +PFNGLCOLOR4FVPROC glad_glColor4fv = NULL; +PFNGLCOLOR4IPROC glad_glColor4i = NULL; +PFNGLCOLOR4IVPROC glad_glColor4iv = NULL; +PFNGLCOLOR4SPROC glad_glColor4s = NULL; +PFNGLCOLOR4SVPROC glad_glColor4sv = NULL; +PFNGLCOLOR4UBPROC glad_glColor4ub = NULL; +PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL; +PFNGLCOLOR4UIPROC glad_glColor4ui = NULL; +PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL; +PFNGLCOLOR4USPROC glad_glColor4us = NULL; +PFNGLCOLOR4USVPROC glad_glColor4usv = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; +PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL; +PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; +PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; +PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; +PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; +PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; +PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL; +PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL; +PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETELISTSPROC glad_glDeleteLists = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEIPROC glad_glDisablei = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; +PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; +PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL; +PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL; +PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEIPROC glad_glEnablei = NULL; +PFNGLENDPROC glad_glEnd = NULL; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; +PFNGLENDLISTPROC glad_glEndList = NULL; +PFNGLENDQUERYPROC glad_glEndQuery = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; +PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL; +PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL; +PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL; +PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL; +PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL; +PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL; +PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL; +PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL; +PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL; +PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL; +PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL; +PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL; +PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL; +PFNGLFENCESYNCPROC glad_glFenceSync = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; +PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL; +PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL; +PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL; +PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL; +PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL; +PFNGLFOGFPROC glad_glFogf = NULL; +PFNGLFOGFVPROC glad_glFogfv = NULL; +PFNGLFOGIPROC glad_glFogi = NULL; +PFNGLFOGIVPROC glad_glFogiv = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLFRUSTUMPROC glad_glFrustum = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENLISTSPROC glad_glGenLists = NULL; +PFNGLGENQUERIESPROC glad_glGenQueries = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; +PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; +PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL; +PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB = NULL; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL; +PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL; +PFNGLGETMAPDVPROC glad_glGetMapdv = NULL; +PFNGLGETMAPFVPROC glad_glGetMapfv = NULL; +PFNGLGETMAPIVPROC glad_glGetMapiv = NULL; +PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL; +PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; +PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL; +PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL; +PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL; +PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL; +PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL; +PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; +PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; +PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; +PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; +PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; +PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; +PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; +PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; +PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL; +PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL; +PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL; +PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL; +PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB = NULL; +PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB = NULL; +PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB = NULL; +PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB = NULL; +PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB = NULL; +PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB = NULL; +PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB = NULL; +PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB = NULL; +PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB = NULL; +PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB = NULL; +PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB = NULL; +PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB = NULL; +PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB = NULL; +PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB = NULL; +PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB = NULL; +PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB = NULL; +PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB = NULL; +PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLINDEXMASKPROC glad_glIndexMask = NULL; +PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL; +PFNGLINDEXDPROC glad_glIndexd = NULL; +PFNGLINDEXDVPROC glad_glIndexdv = NULL; +PFNGLINDEXFPROC glad_glIndexf = NULL; +PFNGLINDEXFVPROC glad_glIndexfv = NULL; +PFNGLINDEXIPROC glad_glIndexi = NULL; +PFNGLINDEXIVPROC glad_glIndexiv = NULL; +PFNGLINDEXSPROC glad_glIndexs = NULL; +PFNGLINDEXSVPROC glad_glIndexsv = NULL; +PFNGLINDEXUBPROC glad_glIndexub = NULL; +PFNGLINDEXUBVPROC glad_glIndexubv = NULL; +PFNGLINITNAMESPROC glad_glInitNames = NULL; +PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISLISTPROC glad_glIsList = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISQUERYPROC glad_glIsQuery = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSAMPLERPROC glad_glIsSampler = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISSYNCPROC glad_glIsSync = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; +PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL; +PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL; +PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL; +PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL; +PFNGLLIGHTFPROC glad_glLightf = NULL; +PFNGLLIGHTFVPROC glad_glLightfv = NULL; +PFNGLLIGHTIPROC glad_glLighti = NULL; +PFNGLLIGHTIVPROC glad_glLightiv = NULL; +PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLLISTBASEPROC glad_glListBase = NULL; +PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL; +PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL; +PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL; +PFNGLLOADNAMEPROC glad_glLoadName = NULL; +PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL; +PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL; +PFNGLLOGICOPPROC glad_glLogicOp = NULL; +PFNGLMAP1DPROC glad_glMap1d = NULL; +PFNGLMAP1FPROC glad_glMap1f = NULL; +PFNGLMAP2DPROC glad_glMap2d = NULL; +PFNGLMAP2FPROC glad_glMap2f = NULL; +PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; +PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL; +PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL; +PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL; +PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL; +PFNGLMATERIALFPROC glad_glMaterialf = NULL; +PFNGLMATERIALFVPROC glad_glMaterialfv = NULL; +PFNGLMATERIALIPROC glad_glMateriali = NULL; +PFNGLMATERIALIVPROC glad_glMaterialiv = NULL; +PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL; +PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL; +PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL; +PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL; +PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; +PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL; +PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL; +PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL; +PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL; +PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL; +PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL; +PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL; +PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL; +PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL; +PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL; +PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL; +PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL; +PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL; +PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL; +PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL; +PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL; +PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL; +PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL; +PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL; +PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL; +PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL; +PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL; +PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL; +PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL; +PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL; +PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL; +PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL; +PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL; +PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL; +PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL; +PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL; +PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL; +PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; +PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; +PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; +PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; +PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; +PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL; +PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; +PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; +PFNGLNEWLISTPROC glad_glNewList = NULL; +PFNGLNORMAL3BPROC glad_glNormal3b = NULL; +PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL; +PFNGLNORMAL3DPROC glad_glNormal3d = NULL; +PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL; +PFNGLNORMAL3FPROC glad_glNormal3f = NULL; +PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL; +PFNGLNORMAL3IPROC glad_glNormal3i = NULL; +PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL; +PFNGLNORMAL3SPROC glad_glNormal3s = NULL; +PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL; +PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; +PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; +PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL; +PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL; +PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL; +PFNGLORTHOPROC glad_glOrtho = NULL; +PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL; +PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL; +PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL; +PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL; +PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL; +PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL; +PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; +PFNGLPOINTSIZEPROC glad_glPointSize = NULL; +PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL; +PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL; +PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL; +PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL; +PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL; +PFNGLPOPNAMEPROC glad_glPopName = NULL; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; +PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; +PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL; +PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL; +PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL; +PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL; +PFNGLPUSHNAMEPROC glad_glPushName = NULL; +PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; +PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL; +PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL; +PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL; +PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL; +PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL; +PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL; +PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL; +PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL; +PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL; +PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL; +PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL; +PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL; +PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL; +PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL; +PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL; +PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL; +PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL; +PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL; +PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL; +PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL; +PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL; +PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL; +PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL; +PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL; +PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLREADNPIXELSPROC glad_glReadnPixels = NULL; +PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB = NULL; +PFNGLRECTDPROC glad_glRectd = NULL; +PFNGLRECTDVPROC glad_glRectdv = NULL; +PFNGLRECTFPROC glad_glRectf = NULL; +PFNGLRECTFVPROC glad_glRectfv = NULL; +PFNGLRECTIPROC glad_glRecti = NULL; +PFNGLRECTIVPROC glad_glRectiv = NULL; +PFNGLRECTSPROC glad_glRects = NULL; +PFNGLRECTSVPROC glad_glRectsv = NULL; +PFNGLRENDERMODEPROC glad_glRenderMode = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; +PFNGLROTATEDPROC glad_glRotated = NULL; +PFNGLROTATEFPROC glad_glRotatef = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB = NULL; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; +PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; +PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; +PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; +PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; +PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; +PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; +PFNGLSCALEDPROC glad_glScaled = NULL; +PFNGLSCALEFPROC glad_glScalef = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL; +PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL; +PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL; +PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL; +PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL; +PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL; +PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL; +PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL; +PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL; +PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL; +PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL; +PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL; +PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL; +PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL; +PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL; +PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL; +PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; +PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; +PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL; +PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL; +PFNGLSHADEMODELPROC glad_glShadeModel = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; +PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL; +PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL; +PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL; +PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL; +PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL; +PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL; +PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL; +PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL; +PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL; +PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL; +PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL; +PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL; +PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL; +PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL; +PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL; +PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL; +PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL; +PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL; +PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL; +PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL; +PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL; +PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL; +PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL; +PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL; +PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL; +PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL; +PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL; +PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL; +PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL; +PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL; +PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL; +PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL; +PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; +PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; +PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; +PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; +PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; +PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; +PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL; +PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL; +PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL; +PFNGLTEXENVFPROC glad_glTexEnvf = NULL; +PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL; +PFNGLTEXENVIPROC glad_glTexEnvi = NULL; +PFNGLTEXENVIVPROC glad_glTexEnviv = NULL; +PFNGLTEXGENDPROC glad_glTexGend = NULL; +PFNGLTEXGENDVPROC glad_glTexGendv = NULL; +PFNGLTEXGENFPROC glad_glTexGenf = NULL; +PFNGLTEXGENFVPROC glad_glTexGenfv = NULL; +PFNGLTEXGENIPROC glad_glTexGeni = NULL; +PFNGLTEXGENIVPROC glad_glTexGeniv = NULL; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; +PFNGLTRANSLATEDPROC glad_glTranslated = NULL; +PFNGLTRANSLATEFPROC glad_glTranslatef = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVERTEX2DPROC glad_glVertex2d = NULL; +PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL; +PFNGLVERTEX2FPROC glad_glVertex2f = NULL; +PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL; +PFNGLVERTEX2IPROC glad_glVertex2i = NULL; +PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL; +PFNGLVERTEX2SPROC glad_glVertex2s = NULL; +PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL; +PFNGLVERTEX3DPROC glad_glVertex3d = NULL; +PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL; +PFNGLVERTEX3FPROC glad_glVertex3f = NULL; +PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL; +PFNGLVERTEX3IPROC glad_glVertex3i = NULL; +PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL; +PFNGLVERTEX3SPROC glad_glVertex3s = NULL; +PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL; +PFNGLVERTEX4DPROC glad_glVertex4d = NULL; +PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL; +PFNGLVERTEX4FPROC glad_glVertex4f = NULL; +PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL; +PFNGLVERTEX4IPROC glad_glVertex4i = NULL; +PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL; +PFNGLVERTEX4SPROC glad_glVertex4s = NULL; +PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; +PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; +PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; +PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; +PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; +PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; +PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; +PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; +PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; +PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; +PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL; +PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL; +PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; +PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; +PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL; +PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +PFNGLWAITSYNCPROC glad_glWaitSync = NULL; +PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL; +PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL; +PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL; +PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL; +PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL; +PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL; +PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL; +PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL; +PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL; +PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL; +PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL; +PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL; +PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL; +PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; +PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; +PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; + + +static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_0) return; + glAccum = (PFNGLACCUMPROC) load("glAccum", userptr); + glAlphaFunc = (PFNGLALPHAFUNCPROC) load("glAlphaFunc", userptr); + glBegin = (PFNGLBEGINPROC) load("glBegin", userptr); + glBitmap = (PFNGLBITMAPPROC) load("glBitmap", userptr); + glBlendFunc = (PFNGLBLENDFUNCPROC) load("glBlendFunc", userptr); + glCallList = (PFNGLCALLLISTPROC) load("glCallList", userptr); + glCallLists = (PFNGLCALLLISTSPROC) load("glCallLists", userptr); + glClear = (PFNGLCLEARPROC) load("glClear", userptr); + glClearAccum = (PFNGLCLEARACCUMPROC) load("glClearAccum", userptr); + glClearColor = (PFNGLCLEARCOLORPROC) load("glClearColor", userptr); + glClearDepth = (PFNGLCLEARDEPTHPROC) load("glClearDepth", userptr); + glClearIndex = (PFNGLCLEARINDEXPROC) load("glClearIndex", userptr); + glClearStencil = (PFNGLCLEARSTENCILPROC) load("glClearStencil", userptr); + glClipPlane = (PFNGLCLIPPLANEPROC) load("glClipPlane", userptr); + glColor3b = (PFNGLCOLOR3BPROC) load("glColor3b", userptr); + glColor3bv = (PFNGLCOLOR3BVPROC) load("glColor3bv", userptr); + glColor3d = (PFNGLCOLOR3DPROC) load("glColor3d", userptr); + glColor3dv = (PFNGLCOLOR3DVPROC) load("glColor3dv", userptr); + glColor3f = (PFNGLCOLOR3FPROC) load("glColor3f", userptr); + glColor3fv = (PFNGLCOLOR3FVPROC) load("glColor3fv", userptr); + glColor3i = (PFNGLCOLOR3IPROC) load("glColor3i", userptr); + glColor3iv = (PFNGLCOLOR3IVPROC) load("glColor3iv", userptr); + glColor3s = (PFNGLCOLOR3SPROC) load("glColor3s", userptr); + glColor3sv = (PFNGLCOLOR3SVPROC) load("glColor3sv", userptr); + glColor3ub = (PFNGLCOLOR3UBPROC) load("glColor3ub", userptr); + glColor3ubv = (PFNGLCOLOR3UBVPROC) load("glColor3ubv", userptr); + glColor3ui = (PFNGLCOLOR3UIPROC) load("glColor3ui", userptr); + glColor3uiv = (PFNGLCOLOR3UIVPROC) load("glColor3uiv", userptr); + glColor3us = (PFNGLCOLOR3USPROC) load("glColor3us", userptr); + glColor3usv = (PFNGLCOLOR3USVPROC) load("glColor3usv", userptr); + glColor4b = (PFNGLCOLOR4BPROC) load("glColor4b", userptr); + glColor4bv = (PFNGLCOLOR4BVPROC) load("glColor4bv", userptr); + glColor4d = (PFNGLCOLOR4DPROC) load("glColor4d", userptr); + glColor4dv = (PFNGLCOLOR4DVPROC) load("glColor4dv", userptr); + glColor4f = (PFNGLCOLOR4FPROC) load("glColor4f", userptr); + glColor4fv = (PFNGLCOLOR4FVPROC) load("glColor4fv", userptr); + glColor4i = (PFNGLCOLOR4IPROC) load("glColor4i", userptr); + glColor4iv = (PFNGLCOLOR4IVPROC) load("glColor4iv", userptr); + glColor4s = (PFNGLCOLOR4SPROC) load("glColor4s", userptr); + glColor4sv = (PFNGLCOLOR4SVPROC) load("glColor4sv", userptr); + glColor4ub = (PFNGLCOLOR4UBPROC) load("glColor4ub", userptr); + glColor4ubv = (PFNGLCOLOR4UBVPROC) load("glColor4ubv", userptr); + glColor4ui = (PFNGLCOLOR4UIPROC) load("glColor4ui", userptr); + glColor4uiv = (PFNGLCOLOR4UIVPROC) load("glColor4uiv", userptr); + glColor4us = (PFNGLCOLOR4USPROC) load("glColor4us", userptr); + glColor4usv = (PFNGLCOLOR4USVPROC) load("glColor4usv", userptr); + glColorMask = (PFNGLCOLORMASKPROC) load("glColorMask", userptr); + glColorMaterial = (PFNGLCOLORMATERIALPROC) load("glColorMaterial", userptr); + glCopyPixels = (PFNGLCOPYPIXELSPROC) load("glCopyPixels", userptr); + glCullFace = (PFNGLCULLFACEPROC) load("glCullFace", userptr); + glDeleteLists = (PFNGLDELETELISTSPROC) load("glDeleteLists", userptr); + glDepthFunc = (PFNGLDEPTHFUNCPROC) load("glDepthFunc", userptr); + glDepthMask = (PFNGLDEPTHMASKPROC) load("glDepthMask", userptr); + glDepthRange = (PFNGLDEPTHRANGEPROC) load("glDepthRange", userptr); + glDisable = (PFNGLDISABLEPROC) load("glDisable", userptr); + glDrawBuffer = (PFNGLDRAWBUFFERPROC) load("glDrawBuffer", userptr); + glDrawPixels = (PFNGLDRAWPIXELSPROC) load("glDrawPixels", userptr); + glEdgeFlag = (PFNGLEDGEFLAGPROC) load("glEdgeFlag", userptr); + glEdgeFlagv = (PFNGLEDGEFLAGVPROC) load("glEdgeFlagv", userptr); + glEnable = (PFNGLENABLEPROC) load("glEnable", userptr); + glEnd = (PFNGLENDPROC) load("glEnd", userptr); + glEndList = (PFNGLENDLISTPROC) load("glEndList", userptr); + glEvalCoord1d = (PFNGLEVALCOORD1DPROC) load("glEvalCoord1d", userptr); + glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC) load("glEvalCoord1dv", userptr); + glEvalCoord1f = (PFNGLEVALCOORD1FPROC) load("glEvalCoord1f", userptr); + glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC) load("glEvalCoord1fv", userptr); + glEvalCoord2d = (PFNGLEVALCOORD2DPROC) load("glEvalCoord2d", userptr); + glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC) load("glEvalCoord2dv", userptr); + glEvalCoord2f = (PFNGLEVALCOORD2FPROC) load("glEvalCoord2f", userptr); + glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC) load("glEvalCoord2fv", userptr); + glEvalMesh1 = (PFNGLEVALMESH1PROC) load("glEvalMesh1", userptr); + glEvalMesh2 = (PFNGLEVALMESH2PROC) load("glEvalMesh2", userptr); + glEvalPoint1 = (PFNGLEVALPOINT1PROC) load("glEvalPoint1", userptr); + glEvalPoint2 = (PFNGLEVALPOINT2PROC) load("glEvalPoint2", userptr); + glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC) load("glFeedbackBuffer", userptr); + glFinish = (PFNGLFINISHPROC) load("glFinish", userptr); + glFlush = (PFNGLFLUSHPROC) load("glFlush", userptr); + glFogf = (PFNGLFOGFPROC) load("glFogf", userptr); + glFogfv = (PFNGLFOGFVPROC) load("glFogfv", userptr); + glFogi = (PFNGLFOGIPROC) load("glFogi", userptr); + glFogiv = (PFNGLFOGIVPROC) load("glFogiv", userptr); + glFrontFace = (PFNGLFRONTFACEPROC) load("glFrontFace", userptr); + glFrustum = (PFNGLFRUSTUMPROC) load("glFrustum", userptr); + glGenLists = (PFNGLGENLISTSPROC) load("glGenLists", userptr); + glGetBooleanv = (PFNGLGETBOOLEANVPROC) load("glGetBooleanv", userptr); + glGetClipPlane = (PFNGLGETCLIPPLANEPROC) load("glGetClipPlane", userptr); + glGetDoublev = (PFNGLGETDOUBLEVPROC) load("glGetDoublev", userptr); + glGetError = (PFNGLGETERRORPROC) load("glGetError", userptr); + glGetFloatv = (PFNGLGETFLOATVPROC) load("glGetFloatv", userptr); + glGetIntegerv = (PFNGLGETINTEGERVPROC) load("glGetIntegerv", userptr); + glGetLightfv = (PFNGLGETLIGHTFVPROC) load("glGetLightfv", userptr); + glGetLightiv = (PFNGLGETLIGHTIVPROC) load("glGetLightiv", userptr); + glGetMapdv = (PFNGLGETMAPDVPROC) load("glGetMapdv", userptr); + glGetMapfv = (PFNGLGETMAPFVPROC) load("glGetMapfv", userptr); + glGetMapiv = (PFNGLGETMAPIVPROC) load("glGetMapiv", userptr); + glGetMaterialfv = (PFNGLGETMATERIALFVPROC) load("glGetMaterialfv", userptr); + glGetMaterialiv = (PFNGLGETMATERIALIVPROC) load("glGetMaterialiv", userptr); + glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC) load("glGetPixelMapfv", userptr); + glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC) load("glGetPixelMapuiv", userptr); + glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC) load("glGetPixelMapusv", userptr); + glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC) load("glGetPolygonStipple", userptr); + glGetString = (PFNGLGETSTRINGPROC) load("glGetString", userptr); + glGetTexEnvfv = (PFNGLGETTEXENVFVPROC) load("glGetTexEnvfv", userptr); + glGetTexEnviv = (PFNGLGETTEXENVIVPROC) load("glGetTexEnviv", userptr); + glGetTexGendv = (PFNGLGETTEXGENDVPROC) load("glGetTexGendv", userptr); + glGetTexGenfv = (PFNGLGETTEXGENFVPROC) load("glGetTexGenfv", userptr); + glGetTexGeniv = (PFNGLGETTEXGENIVPROC) load("glGetTexGeniv", userptr); + glGetTexImage = (PFNGLGETTEXIMAGEPROC) load("glGetTexImage", userptr); + glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load("glGetTexLevelParameterfv", userptr); + glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load("glGetTexLevelParameteriv", userptr); + glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load("glGetTexParameterfv", userptr); + glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load("glGetTexParameteriv", userptr); + glHint = (PFNGLHINTPROC) load("glHint", userptr); + glIndexMask = (PFNGLINDEXMASKPROC) load("glIndexMask", userptr); + glIndexd = (PFNGLINDEXDPROC) load("glIndexd", userptr); + glIndexdv = (PFNGLINDEXDVPROC) load("glIndexdv", userptr); + glIndexf = (PFNGLINDEXFPROC) load("glIndexf", userptr); + glIndexfv = (PFNGLINDEXFVPROC) load("glIndexfv", userptr); + glIndexi = (PFNGLINDEXIPROC) load("glIndexi", userptr); + glIndexiv = (PFNGLINDEXIVPROC) load("glIndexiv", userptr); + glIndexs = (PFNGLINDEXSPROC) load("glIndexs", userptr); + glIndexsv = (PFNGLINDEXSVPROC) load("glIndexsv", userptr); + glInitNames = (PFNGLINITNAMESPROC) load("glInitNames", userptr); + glIsEnabled = (PFNGLISENABLEDPROC) load("glIsEnabled", userptr); + glIsList = (PFNGLISLISTPROC) load("glIsList", userptr); + glLightModelf = (PFNGLLIGHTMODELFPROC) load("glLightModelf", userptr); + glLightModelfv = (PFNGLLIGHTMODELFVPROC) load("glLightModelfv", userptr); + glLightModeli = (PFNGLLIGHTMODELIPROC) load("glLightModeli", userptr); + glLightModeliv = (PFNGLLIGHTMODELIVPROC) load("glLightModeliv", userptr); + glLightf = (PFNGLLIGHTFPROC) load("glLightf", userptr); + glLightfv = (PFNGLLIGHTFVPROC) load("glLightfv", userptr); + glLighti = (PFNGLLIGHTIPROC) load("glLighti", userptr); + glLightiv = (PFNGLLIGHTIVPROC) load("glLightiv", userptr); + glLineStipple = (PFNGLLINESTIPPLEPROC) load("glLineStipple", userptr); + glLineWidth = (PFNGLLINEWIDTHPROC) load("glLineWidth", userptr); + glListBase = (PFNGLLISTBASEPROC) load("glListBase", userptr); + glLoadIdentity = (PFNGLLOADIDENTITYPROC) load("glLoadIdentity", userptr); + glLoadMatrixd = (PFNGLLOADMATRIXDPROC) load("glLoadMatrixd", userptr); + glLoadMatrixf = (PFNGLLOADMATRIXFPROC) load("glLoadMatrixf", userptr); + glLoadName = (PFNGLLOADNAMEPROC) load("glLoadName", userptr); + glLogicOp = (PFNGLLOGICOPPROC) load("glLogicOp", userptr); + glMap1d = (PFNGLMAP1DPROC) load("glMap1d", userptr); + glMap1f = (PFNGLMAP1FPROC) load("glMap1f", userptr); + glMap2d = (PFNGLMAP2DPROC) load("glMap2d", userptr); + glMap2f = (PFNGLMAP2FPROC) load("glMap2f", userptr); + glMapGrid1d = (PFNGLMAPGRID1DPROC) load("glMapGrid1d", userptr); + glMapGrid1f = (PFNGLMAPGRID1FPROC) load("glMapGrid1f", userptr); + glMapGrid2d = (PFNGLMAPGRID2DPROC) load("glMapGrid2d", userptr); + glMapGrid2f = (PFNGLMAPGRID2FPROC) load("glMapGrid2f", userptr); + glMaterialf = (PFNGLMATERIALFPROC) load("glMaterialf", userptr); + glMaterialfv = (PFNGLMATERIALFVPROC) load("glMaterialfv", userptr); + glMateriali = (PFNGLMATERIALIPROC) load("glMateriali", userptr); + glMaterialiv = (PFNGLMATERIALIVPROC) load("glMaterialiv", userptr); + glMatrixMode = (PFNGLMATRIXMODEPROC) load("glMatrixMode", userptr); + glMultMatrixd = (PFNGLMULTMATRIXDPROC) load("glMultMatrixd", userptr); + glMultMatrixf = (PFNGLMULTMATRIXFPROC) load("glMultMatrixf", userptr); + glNewList = (PFNGLNEWLISTPROC) load("glNewList", userptr); + glNormal3b = (PFNGLNORMAL3BPROC) load("glNormal3b", userptr); + glNormal3bv = (PFNGLNORMAL3BVPROC) load("glNormal3bv", userptr); + glNormal3d = (PFNGLNORMAL3DPROC) load("glNormal3d", userptr); + glNormal3dv = (PFNGLNORMAL3DVPROC) load("glNormal3dv", userptr); + glNormal3f = (PFNGLNORMAL3FPROC) load("glNormal3f", userptr); + glNormal3fv = (PFNGLNORMAL3FVPROC) load("glNormal3fv", userptr); + glNormal3i = (PFNGLNORMAL3IPROC) load("glNormal3i", userptr); + glNormal3iv = (PFNGLNORMAL3IVPROC) load("glNormal3iv", userptr); + glNormal3s = (PFNGLNORMAL3SPROC) load("glNormal3s", userptr); + glNormal3sv = (PFNGLNORMAL3SVPROC) load("glNormal3sv", userptr); + glOrtho = (PFNGLORTHOPROC) load("glOrtho", userptr); + glPassThrough = (PFNGLPASSTHROUGHPROC) load("glPassThrough", userptr); + glPixelMapfv = (PFNGLPIXELMAPFVPROC) load("glPixelMapfv", userptr); + glPixelMapuiv = (PFNGLPIXELMAPUIVPROC) load("glPixelMapuiv", userptr); + glPixelMapusv = (PFNGLPIXELMAPUSVPROC) load("glPixelMapusv", userptr); + glPixelStoref = (PFNGLPIXELSTOREFPROC) load("glPixelStoref", userptr); + glPixelStorei = (PFNGLPIXELSTOREIPROC) load("glPixelStorei", userptr); + glPixelTransferf = (PFNGLPIXELTRANSFERFPROC) load("glPixelTransferf", userptr); + glPixelTransferi = (PFNGLPIXELTRANSFERIPROC) load("glPixelTransferi", userptr); + glPixelZoom = (PFNGLPIXELZOOMPROC) load("glPixelZoom", userptr); + glPointSize = (PFNGLPOINTSIZEPROC) load("glPointSize", userptr); + glPolygonMode = (PFNGLPOLYGONMODEPROC) load("glPolygonMode", userptr); + glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC) load("glPolygonStipple", userptr); + glPopAttrib = (PFNGLPOPATTRIBPROC) load("glPopAttrib", userptr); + glPopMatrix = (PFNGLPOPMATRIXPROC) load("glPopMatrix", userptr); + glPopName = (PFNGLPOPNAMEPROC) load("glPopName", userptr); + glPushAttrib = (PFNGLPUSHATTRIBPROC) load("glPushAttrib", userptr); + glPushMatrix = (PFNGLPUSHMATRIXPROC) load("glPushMatrix", userptr); + glPushName = (PFNGLPUSHNAMEPROC) load("glPushName", userptr); + glRasterPos2d = (PFNGLRASTERPOS2DPROC) load("glRasterPos2d", userptr); + glRasterPos2dv = (PFNGLRASTERPOS2DVPROC) load("glRasterPos2dv", userptr); + glRasterPos2f = (PFNGLRASTERPOS2FPROC) load("glRasterPos2f", userptr); + glRasterPos2fv = (PFNGLRASTERPOS2FVPROC) load("glRasterPos2fv", userptr); + glRasterPos2i = (PFNGLRASTERPOS2IPROC) load("glRasterPos2i", userptr); + glRasterPos2iv = (PFNGLRASTERPOS2IVPROC) load("glRasterPos2iv", userptr); + glRasterPos2s = (PFNGLRASTERPOS2SPROC) load("glRasterPos2s", userptr); + glRasterPos2sv = (PFNGLRASTERPOS2SVPROC) load("glRasterPos2sv", userptr); + glRasterPos3d = (PFNGLRASTERPOS3DPROC) load("glRasterPos3d", userptr); + glRasterPos3dv = (PFNGLRASTERPOS3DVPROC) load("glRasterPos3dv", userptr); + glRasterPos3f = (PFNGLRASTERPOS3FPROC) load("glRasterPos3f", userptr); + glRasterPos3fv = (PFNGLRASTERPOS3FVPROC) load("glRasterPos3fv", userptr); + glRasterPos3i = (PFNGLRASTERPOS3IPROC) load("glRasterPos3i", userptr); + glRasterPos3iv = (PFNGLRASTERPOS3IVPROC) load("glRasterPos3iv", userptr); + glRasterPos3s = (PFNGLRASTERPOS3SPROC) load("glRasterPos3s", userptr); + glRasterPos3sv = (PFNGLRASTERPOS3SVPROC) load("glRasterPos3sv", userptr); + glRasterPos4d = (PFNGLRASTERPOS4DPROC) load("glRasterPos4d", userptr); + glRasterPos4dv = (PFNGLRASTERPOS4DVPROC) load("glRasterPos4dv", userptr); + glRasterPos4f = (PFNGLRASTERPOS4FPROC) load("glRasterPos4f", userptr); + glRasterPos4fv = (PFNGLRASTERPOS4FVPROC) load("glRasterPos4fv", userptr); + glRasterPos4i = (PFNGLRASTERPOS4IPROC) load("glRasterPos4i", userptr); + glRasterPos4iv = (PFNGLRASTERPOS4IVPROC) load("glRasterPos4iv", userptr); + glRasterPos4s = (PFNGLRASTERPOS4SPROC) load("glRasterPos4s", userptr); + glRasterPos4sv = (PFNGLRASTERPOS4SVPROC) load("glRasterPos4sv", userptr); + glReadBuffer = (PFNGLREADBUFFERPROC) load("glReadBuffer", userptr); + glReadPixels = (PFNGLREADPIXELSPROC) load("glReadPixels", userptr); + glRectd = (PFNGLRECTDPROC) load("glRectd", userptr); + glRectdv = (PFNGLRECTDVPROC) load("glRectdv", userptr); + glRectf = (PFNGLRECTFPROC) load("glRectf", userptr); + glRectfv = (PFNGLRECTFVPROC) load("glRectfv", userptr); + glRecti = (PFNGLRECTIPROC) load("glRecti", userptr); + glRectiv = (PFNGLRECTIVPROC) load("glRectiv", userptr); + glRects = (PFNGLRECTSPROC) load("glRects", userptr); + glRectsv = (PFNGLRECTSVPROC) load("glRectsv", userptr); + glRenderMode = (PFNGLRENDERMODEPROC) load("glRenderMode", userptr); + glRotated = (PFNGLROTATEDPROC) load("glRotated", userptr); + glRotatef = (PFNGLROTATEFPROC) load("glRotatef", userptr); + glScaled = (PFNGLSCALEDPROC) load("glScaled", userptr); + glScalef = (PFNGLSCALEFPROC) load("glScalef", userptr); + glScissor = (PFNGLSCISSORPROC) load("glScissor", userptr); + glSelectBuffer = (PFNGLSELECTBUFFERPROC) load("glSelectBuffer", userptr); + glShadeModel = (PFNGLSHADEMODELPROC) load("glShadeModel", userptr); + glStencilFunc = (PFNGLSTENCILFUNCPROC) load("glStencilFunc", userptr); + glStencilMask = (PFNGLSTENCILMASKPROC) load("glStencilMask", userptr); + glStencilOp = (PFNGLSTENCILOPPROC) load("glStencilOp", userptr); + glTexCoord1d = (PFNGLTEXCOORD1DPROC) load("glTexCoord1d", userptr); + glTexCoord1dv = (PFNGLTEXCOORD1DVPROC) load("glTexCoord1dv", userptr); + glTexCoord1f = (PFNGLTEXCOORD1FPROC) load("glTexCoord1f", userptr); + glTexCoord1fv = (PFNGLTEXCOORD1FVPROC) load("glTexCoord1fv", userptr); + glTexCoord1i = (PFNGLTEXCOORD1IPROC) load("glTexCoord1i", userptr); + glTexCoord1iv = (PFNGLTEXCOORD1IVPROC) load("glTexCoord1iv", userptr); + glTexCoord1s = (PFNGLTEXCOORD1SPROC) load("glTexCoord1s", userptr); + glTexCoord1sv = (PFNGLTEXCOORD1SVPROC) load("glTexCoord1sv", userptr); + glTexCoord2d = (PFNGLTEXCOORD2DPROC) load("glTexCoord2d", userptr); + glTexCoord2dv = (PFNGLTEXCOORD2DVPROC) load("glTexCoord2dv", userptr); + glTexCoord2f = (PFNGLTEXCOORD2FPROC) load("glTexCoord2f", userptr); + glTexCoord2fv = (PFNGLTEXCOORD2FVPROC) load("glTexCoord2fv", userptr); + glTexCoord2i = (PFNGLTEXCOORD2IPROC) load("glTexCoord2i", userptr); + glTexCoord2iv = (PFNGLTEXCOORD2IVPROC) load("glTexCoord2iv", userptr); + glTexCoord2s = (PFNGLTEXCOORD2SPROC) load("glTexCoord2s", userptr); + glTexCoord2sv = (PFNGLTEXCOORD2SVPROC) load("glTexCoord2sv", userptr); + glTexCoord3d = (PFNGLTEXCOORD3DPROC) load("glTexCoord3d", userptr); + glTexCoord3dv = (PFNGLTEXCOORD3DVPROC) load("glTexCoord3dv", userptr); + glTexCoord3f = (PFNGLTEXCOORD3FPROC) load("glTexCoord3f", userptr); + glTexCoord3fv = (PFNGLTEXCOORD3FVPROC) load("glTexCoord3fv", userptr); + glTexCoord3i = (PFNGLTEXCOORD3IPROC) load("glTexCoord3i", userptr); + glTexCoord3iv = (PFNGLTEXCOORD3IVPROC) load("glTexCoord3iv", userptr); + glTexCoord3s = (PFNGLTEXCOORD3SPROC) load("glTexCoord3s", userptr); + glTexCoord3sv = (PFNGLTEXCOORD3SVPROC) load("glTexCoord3sv", userptr); + glTexCoord4d = (PFNGLTEXCOORD4DPROC) load("glTexCoord4d", userptr); + glTexCoord4dv = (PFNGLTEXCOORD4DVPROC) load("glTexCoord4dv", userptr); + glTexCoord4f = (PFNGLTEXCOORD4FPROC) load("glTexCoord4f", userptr); + glTexCoord4fv = (PFNGLTEXCOORD4FVPROC) load("glTexCoord4fv", userptr); + glTexCoord4i = (PFNGLTEXCOORD4IPROC) load("glTexCoord4i", userptr); + glTexCoord4iv = (PFNGLTEXCOORD4IVPROC) load("glTexCoord4iv", userptr); + glTexCoord4s = (PFNGLTEXCOORD4SPROC) load("glTexCoord4s", userptr); + glTexCoord4sv = (PFNGLTEXCOORD4SVPROC) load("glTexCoord4sv", userptr); + glTexEnvf = (PFNGLTEXENVFPROC) load("glTexEnvf", userptr); + glTexEnvfv = (PFNGLTEXENVFVPROC) load("glTexEnvfv", userptr); + glTexEnvi = (PFNGLTEXENVIPROC) load("glTexEnvi", userptr); + glTexEnviv = (PFNGLTEXENVIVPROC) load("glTexEnviv", userptr); + glTexGend = (PFNGLTEXGENDPROC) load("glTexGend", userptr); + glTexGendv = (PFNGLTEXGENDVPROC) load("glTexGendv", userptr); + glTexGenf = (PFNGLTEXGENFPROC) load("glTexGenf", userptr); + glTexGenfv = (PFNGLTEXGENFVPROC) load("glTexGenfv", userptr); + glTexGeni = (PFNGLTEXGENIPROC) load("glTexGeni", userptr); + glTexGeniv = (PFNGLTEXGENIVPROC) load("glTexGeniv", userptr); + glTexImage1D = (PFNGLTEXIMAGE1DPROC) load("glTexImage1D", userptr); + glTexImage2D = (PFNGLTEXIMAGE2DPROC) load("glTexImage2D", userptr); + glTexParameterf = (PFNGLTEXPARAMETERFPROC) load("glTexParameterf", userptr); + glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load("glTexParameterfv", userptr); + glTexParameteri = (PFNGLTEXPARAMETERIPROC) load("glTexParameteri", userptr); + glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load("glTexParameteriv", userptr); + glTranslated = (PFNGLTRANSLATEDPROC) load("glTranslated", userptr); + glTranslatef = (PFNGLTRANSLATEFPROC) load("glTranslatef", userptr); + glVertex2d = (PFNGLVERTEX2DPROC) load("glVertex2d", userptr); + glVertex2dv = (PFNGLVERTEX2DVPROC) load("glVertex2dv", userptr); + glVertex2f = (PFNGLVERTEX2FPROC) load("glVertex2f", userptr); + glVertex2fv = (PFNGLVERTEX2FVPROC) load("glVertex2fv", userptr); + glVertex2i = (PFNGLVERTEX2IPROC) load("glVertex2i", userptr); + glVertex2iv = (PFNGLVERTEX2IVPROC) load("glVertex2iv", userptr); + glVertex2s = (PFNGLVERTEX2SPROC) load("glVertex2s", userptr); + glVertex2sv = (PFNGLVERTEX2SVPROC) load("glVertex2sv", userptr); + glVertex3d = (PFNGLVERTEX3DPROC) load("glVertex3d", userptr); + glVertex3dv = (PFNGLVERTEX3DVPROC) load("glVertex3dv", userptr); + glVertex3f = (PFNGLVERTEX3FPROC) load("glVertex3f", userptr); + glVertex3fv = (PFNGLVERTEX3FVPROC) load("glVertex3fv", userptr); + glVertex3i = (PFNGLVERTEX3IPROC) load("glVertex3i", userptr); + glVertex3iv = (PFNGLVERTEX3IVPROC) load("glVertex3iv", userptr); + glVertex3s = (PFNGLVERTEX3SPROC) load("glVertex3s", userptr); + glVertex3sv = (PFNGLVERTEX3SVPROC) load("glVertex3sv", userptr); + glVertex4d = (PFNGLVERTEX4DPROC) load("glVertex4d", userptr); + glVertex4dv = (PFNGLVERTEX4DVPROC) load("glVertex4dv", userptr); + glVertex4f = (PFNGLVERTEX4FPROC) load("glVertex4f", userptr); + glVertex4fv = (PFNGLVERTEX4FVPROC) load("glVertex4fv", userptr); + glVertex4i = (PFNGLVERTEX4IPROC) load("glVertex4i", userptr); + glVertex4iv = (PFNGLVERTEX4IVPROC) load("glVertex4iv", userptr); + glVertex4s = (PFNGLVERTEX4SPROC) load("glVertex4s", userptr); + glVertex4sv = (PFNGLVERTEX4SVPROC) load("glVertex4sv", userptr); + glViewport = (PFNGLVIEWPORTPROC) load("glViewport", userptr); +} +static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_1) return; + glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC) load("glAreTexturesResident", userptr); + glArrayElement = (PFNGLARRAYELEMENTPROC) load("glArrayElement", userptr); + glBindTexture = (PFNGLBINDTEXTUREPROC) load("glBindTexture", userptr); + glColorPointer = (PFNGLCOLORPOINTERPROC) load("glColorPointer", userptr); + glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load("glCopyTexImage1D", userptr); + glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load("glCopyTexImage2D", userptr); + glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load("glCopyTexSubImage1D", userptr); + glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load("glCopyTexSubImage2D", userptr); + glDeleteTextures = (PFNGLDELETETEXTURESPROC) load("glDeleteTextures", userptr); + glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC) load("glDisableClientState", userptr); + glDrawArrays = (PFNGLDRAWARRAYSPROC) load("glDrawArrays", userptr); + glDrawElements = (PFNGLDRAWELEMENTSPROC) load("glDrawElements", userptr); + glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC) load("glEdgeFlagPointer", userptr); + glEnableClientState = (PFNGLENABLECLIENTSTATEPROC) load("glEnableClientState", userptr); + glGenTextures = (PFNGLGENTEXTURESPROC) load("glGenTextures", userptr); + glGetPointerv = (PFNGLGETPOINTERVPROC) load("glGetPointerv", userptr); + glIndexPointer = (PFNGLINDEXPOINTERPROC) load("glIndexPointer", userptr); + glIndexub = (PFNGLINDEXUBPROC) load("glIndexub", userptr); + glIndexubv = (PFNGLINDEXUBVPROC) load("glIndexubv", userptr); + glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC) load("glInterleavedArrays", userptr); + glIsTexture = (PFNGLISTEXTUREPROC) load("glIsTexture", userptr); + glNormalPointer = (PFNGLNORMALPOINTERPROC) load("glNormalPointer", userptr); + glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load("glPolygonOffset", userptr); + glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC) load("glPopClientAttrib", userptr); + glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC) load("glPrioritizeTextures", userptr); + glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC) load("glPushClientAttrib", userptr); + glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC) load("glTexCoordPointer", userptr); + glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load("glTexSubImage1D", userptr); + glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load("glTexSubImage2D", userptr); + glVertexPointer = (PFNGLVERTEXPOINTERPROC) load("glVertexPointer", userptr); +} +static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_2) return; + glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load("glCopyTexSubImage3D", userptr); + glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load("glDrawRangeElements", userptr); + glTexImage3D = (PFNGLTEXIMAGE3DPROC) load("glTexImage3D", userptr); + glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load("glTexSubImage3D", userptr); +} +static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_3) return; + glActiveTexture = (PFNGLACTIVETEXTUREPROC) load("glActiveTexture", userptr); + glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC) load("glClientActiveTexture", userptr); + glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load("glCompressedTexImage1D", userptr); + glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load("glCompressedTexImage2D", userptr); + glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load("glCompressedTexImage3D", userptr); + glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load("glCompressedTexSubImage1D", userptr); + glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load("glCompressedTexSubImage2D", userptr); + glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load("glCompressedTexSubImage3D", userptr); + glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load("glGetCompressedTexImage", userptr); + glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC) load("glLoadTransposeMatrixd", userptr); + glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC) load("glLoadTransposeMatrixf", userptr); + glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC) load("glMultTransposeMatrixd", userptr); + glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC) load("glMultTransposeMatrixf", userptr); + glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC) load("glMultiTexCoord1d", userptr); + glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC) load("glMultiTexCoord1dv", userptr); + glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC) load("glMultiTexCoord1f", userptr); + glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC) load("glMultiTexCoord1fv", userptr); + glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC) load("glMultiTexCoord1i", userptr); + glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC) load("glMultiTexCoord1iv", userptr); + glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC) load("glMultiTexCoord1s", userptr); + glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC) load("glMultiTexCoord1sv", userptr); + glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC) load("glMultiTexCoord2d", userptr); + glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC) load("glMultiTexCoord2dv", userptr); + glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC) load("glMultiTexCoord2f", userptr); + glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC) load("glMultiTexCoord2fv", userptr); + glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC) load("glMultiTexCoord2i", userptr); + glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC) load("glMultiTexCoord2iv", userptr); + glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC) load("glMultiTexCoord2s", userptr); + glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC) load("glMultiTexCoord2sv", userptr); + glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC) load("glMultiTexCoord3d", userptr); + glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC) load("glMultiTexCoord3dv", userptr); + glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC) load("glMultiTexCoord3f", userptr); + glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC) load("glMultiTexCoord3fv", userptr); + glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC) load("glMultiTexCoord3i", userptr); + glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC) load("glMultiTexCoord3iv", userptr); + glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC) load("glMultiTexCoord3s", userptr); + glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC) load("glMultiTexCoord3sv", userptr); + glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC) load("glMultiTexCoord4d", userptr); + glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC) load("glMultiTexCoord4dv", userptr); + glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC) load("glMultiTexCoord4f", userptr); + glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC) load("glMultiTexCoord4fv", userptr); + glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC) load("glMultiTexCoord4i", userptr); + glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC) load("glMultiTexCoord4iv", userptr); + glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC) load("glMultiTexCoord4s", userptr); + glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC) load("glMultiTexCoord4sv", userptr); + glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load("glSampleCoverage", userptr); +} +static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_4) return; + glBlendColor = (PFNGLBLENDCOLORPROC) load("glBlendColor", userptr); + glBlendEquation = (PFNGLBLENDEQUATIONPROC) load("glBlendEquation", userptr); + glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load("glBlendFuncSeparate", userptr); + glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC) load("glFogCoordPointer", userptr); + glFogCoordd = (PFNGLFOGCOORDDPROC) load("glFogCoordd", userptr); + glFogCoorddv = (PFNGLFOGCOORDDVPROC) load("glFogCoorddv", userptr); + glFogCoordf = (PFNGLFOGCOORDFPROC) load("glFogCoordf", userptr); + glFogCoordfv = (PFNGLFOGCOORDFVPROC) load("glFogCoordfv", userptr); + glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load("glMultiDrawArrays", userptr); + glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load("glMultiDrawElements", userptr); + glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load("glPointParameterf", userptr); + glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load("glPointParameterfv", userptr); + glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load("glPointParameteri", userptr); + glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load("glPointParameteriv", userptr); + glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC) load("glSecondaryColor3b", userptr); + glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC) load("glSecondaryColor3bv", userptr); + glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC) load("glSecondaryColor3d", userptr); + glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC) load("glSecondaryColor3dv", userptr); + glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC) load("glSecondaryColor3f", userptr); + glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC) load("glSecondaryColor3fv", userptr); + glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC) load("glSecondaryColor3i", userptr); + glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC) load("glSecondaryColor3iv", userptr); + glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC) load("glSecondaryColor3s", userptr); + glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC) load("glSecondaryColor3sv", userptr); + glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC) load("glSecondaryColor3ub", userptr); + glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC) load("glSecondaryColor3ubv", userptr); + glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC) load("glSecondaryColor3ui", userptr); + glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC) load("glSecondaryColor3uiv", userptr); + glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC) load("glSecondaryColor3us", userptr); + glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC) load("glSecondaryColor3usv", userptr); + glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC) load("glSecondaryColorPointer", userptr); + glWindowPos2d = (PFNGLWINDOWPOS2DPROC) load("glWindowPos2d", userptr); + glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC) load("glWindowPos2dv", userptr); + glWindowPos2f = (PFNGLWINDOWPOS2FPROC) load("glWindowPos2f", userptr); + glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC) load("glWindowPos2fv", userptr); + glWindowPos2i = (PFNGLWINDOWPOS2IPROC) load("glWindowPos2i", userptr); + glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC) load("glWindowPos2iv", userptr); + glWindowPos2s = (PFNGLWINDOWPOS2SPROC) load("glWindowPos2s", userptr); + glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC) load("glWindowPos2sv", userptr); + glWindowPos3d = (PFNGLWINDOWPOS3DPROC) load("glWindowPos3d", userptr); + glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC) load("glWindowPos3dv", userptr); + glWindowPos3f = (PFNGLWINDOWPOS3FPROC) load("glWindowPos3f", userptr); + glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC) load("glWindowPos3fv", userptr); + glWindowPos3i = (PFNGLWINDOWPOS3IPROC) load("glWindowPos3i", userptr); + glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC) load("glWindowPos3iv", userptr); + glWindowPos3s = (PFNGLWINDOWPOS3SPROC) load("glWindowPos3s", userptr); + glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC) load("glWindowPos3sv", userptr); +} +static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_5) return; + glBeginQuery = (PFNGLBEGINQUERYPROC) load("glBeginQuery", userptr); + glBindBuffer = (PFNGLBINDBUFFERPROC) load("glBindBuffer", userptr); + glBufferData = (PFNGLBUFFERDATAPROC) load("glBufferData", userptr); + glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load("glBufferSubData", userptr); + glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load("glDeleteBuffers", userptr); + glDeleteQueries = (PFNGLDELETEQUERIESPROC) load("glDeleteQueries", userptr); + glEndQuery = (PFNGLENDQUERYPROC) load("glEndQuery", userptr); + glGenBuffers = (PFNGLGENBUFFERSPROC) load("glGenBuffers", userptr); + glGenQueries = (PFNGLGENQUERIESPROC) load("glGenQueries", userptr); + glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load("glGetBufferParameteriv", userptr); + glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load("glGetBufferPointerv", userptr); + glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load("glGetBufferSubData", userptr); + glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load("glGetQueryObjectiv", userptr); + glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load("glGetQueryObjectuiv", userptr); + glGetQueryiv = (PFNGLGETQUERYIVPROC) load("glGetQueryiv", userptr); + glIsBuffer = (PFNGLISBUFFERPROC) load("glIsBuffer", userptr); + glIsQuery = (PFNGLISQUERYPROC) load("glIsQuery", userptr); + glMapBuffer = (PFNGLMAPBUFFERPROC) load("glMapBuffer", userptr); + glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load("glUnmapBuffer", userptr); +} +static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_2_0) return; + glAttachShader = (PFNGLATTACHSHADERPROC) load("glAttachShader", userptr); + glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load("glBindAttribLocation", userptr); + glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load("glBlendEquationSeparate", userptr); + glCompileShader = (PFNGLCOMPILESHADERPROC) load("glCompileShader", userptr); + glCreateProgram = (PFNGLCREATEPROGRAMPROC) load("glCreateProgram", userptr); + glCreateShader = (PFNGLCREATESHADERPROC) load("glCreateShader", userptr); + glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load("glDeleteProgram", userptr); + glDeleteShader = (PFNGLDELETESHADERPROC) load("glDeleteShader", userptr); + glDetachShader = (PFNGLDETACHSHADERPROC) load("glDetachShader", userptr); + glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load("glDisableVertexAttribArray", userptr); + glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load("glDrawBuffers", userptr); + glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load("glEnableVertexAttribArray", userptr); + glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load("glGetActiveAttrib", userptr); + glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load("glGetActiveUniform", userptr); + glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load("glGetAttachedShaders", userptr); + glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load("glGetAttribLocation", userptr); + glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load("glGetProgramInfoLog", userptr); + glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load("glGetProgramiv", userptr); + glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load("glGetShaderInfoLog", userptr); + glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load("glGetShaderSource", userptr); + glGetShaderiv = (PFNGLGETSHADERIVPROC) load("glGetShaderiv", userptr); + glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load("glGetUniformLocation", userptr); + glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load("glGetUniformfv", userptr); + glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load("glGetUniformiv", userptr); + glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load("glGetVertexAttribPointerv", userptr); + glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load("glGetVertexAttribdv", userptr); + glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load("glGetVertexAttribfv", userptr); + glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load("glGetVertexAttribiv", userptr); + glIsProgram = (PFNGLISPROGRAMPROC) load("glIsProgram", userptr); + glIsShader = (PFNGLISSHADERPROC) load("glIsShader", userptr); + glLinkProgram = (PFNGLLINKPROGRAMPROC) load("glLinkProgram", userptr); + glShaderSource = (PFNGLSHADERSOURCEPROC) load("glShaderSource", userptr); + glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load("glStencilFuncSeparate", userptr); + glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load("glStencilMaskSeparate", userptr); + glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load("glStencilOpSeparate", userptr); + glUniform1f = (PFNGLUNIFORM1FPROC) load("glUniform1f", userptr); + glUniform1fv = (PFNGLUNIFORM1FVPROC) load("glUniform1fv", userptr); + glUniform1i = (PFNGLUNIFORM1IPROC) load("glUniform1i", userptr); + glUniform1iv = (PFNGLUNIFORM1IVPROC) load("glUniform1iv", userptr); + glUniform2f = (PFNGLUNIFORM2FPROC) load("glUniform2f", userptr); + glUniform2fv = (PFNGLUNIFORM2FVPROC) load("glUniform2fv", userptr); + glUniform2i = (PFNGLUNIFORM2IPROC) load("glUniform2i", userptr); + glUniform2iv = (PFNGLUNIFORM2IVPROC) load("glUniform2iv", userptr); + glUniform3f = (PFNGLUNIFORM3FPROC) load("glUniform3f", userptr); + glUniform3fv = (PFNGLUNIFORM3FVPROC) load("glUniform3fv", userptr); + glUniform3i = (PFNGLUNIFORM3IPROC) load("glUniform3i", userptr); + glUniform3iv = (PFNGLUNIFORM3IVPROC) load("glUniform3iv", userptr); + glUniform4f = (PFNGLUNIFORM4FPROC) load("glUniform4f", userptr); + glUniform4fv = (PFNGLUNIFORM4FVPROC) load("glUniform4fv", userptr); + glUniform4i = (PFNGLUNIFORM4IPROC) load("glUniform4i", userptr); + glUniform4iv = (PFNGLUNIFORM4IVPROC) load("glUniform4iv", userptr); + glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load("glUniformMatrix2fv", userptr); + glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load("glUniformMatrix3fv", userptr); + glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load("glUniformMatrix4fv", userptr); + glUseProgram = (PFNGLUSEPROGRAMPROC) load("glUseProgram", userptr); + glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load("glValidateProgram", userptr); + glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load("glVertexAttrib1d", userptr); + glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load("glVertexAttrib1dv", userptr); + glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load("glVertexAttrib1f", userptr); + glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load("glVertexAttrib1fv", userptr); + glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load("glVertexAttrib1s", userptr); + glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load("glVertexAttrib1sv", userptr); + glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load("glVertexAttrib2d", userptr); + glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load("glVertexAttrib2dv", userptr); + glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load("glVertexAttrib2f", userptr); + glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load("glVertexAttrib2fv", userptr); + glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load("glVertexAttrib2s", userptr); + glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load("glVertexAttrib2sv", userptr); + glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load("glVertexAttrib3d", userptr); + glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load("glVertexAttrib3dv", userptr); + glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load("glVertexAttrib3f", userptr); + glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load("glVertexAttrib3fv", userptr); + glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load("glVertexAttrib3s", userptr); + glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load("glVertexAttrib3sv", userptr); + glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load("glVertexAttrib4Nbv", userptr); + glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load("glVertexAttrib4Niv", userptr); + glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load("glVertexAttrib4Nsv", userptr); + glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load("glVertexAttrib4Nub", userptr); + glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load("glVertexAttrib4Nubv", userptr); + glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load("glVertexAttrib4Nuiv", userptr); + glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load("glVertexAttrib4Nusv", userptr); + glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load("glVertexAttrib4bv", userptr); + glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load("glVertexAttrib4d", userptr); + glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load("glVertexAttrib4dv", userptr); + glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load("glVertexAttrib4f", userptr); + glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load("glVertexAttrib4fv", userptr); + glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load("glVertexAttrib4iv", userptr); + glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load("glVertexAttrib4s", userptr); + glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load("glVertexAttrib4sv", userptr); + glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load("glVertexAttrib4ubv", userptr); + glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load("glVertexAttrib4uiv", userptr); + glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load("glVertexAttrib4usv", userptr); + glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load("glVertexAttribPointer", userptr); +} +static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_2_1) return; + glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load("glUniformMatrix2x3fv", userptr); + glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load("glUniformMatrix2x4fv", userptr); + glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load("glUniformMatrix3x2fv", userptr); + glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load("glUniformMatrix3x4fv", userptr); + glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load("glUniformMatrix4x2fv", userptr); + glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load("glUniformMatrix4x3fv", userptr); +} +static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_3_0) return; + glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load("glBeginConditionalRender", userptr); + glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load("glBeginTransformFeedback", userptr); + glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load("glBindBufferBase", userptr); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load("glBindBufferRange", userptr); + glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load("glBindFragDataLocation", userptr); + glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load("glBindFramebuffer", userptr); + glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load("glBindRenderbuffer", userptr); + glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load("glBindVertexArray", userptr); + glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load("glBlitFramebuffer", userptr); + glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load("glCheckFramebufferStatus", userptr); + glClampColor = (PFNGLCLAMPCOLORPROC) load("glClampColor", userptr); + glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load("glClearBufferfi", userptr); + glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load("glClearBufferfv", userptr); + glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load("glClearBufferiv", userptr); + glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load("glClearBufferuiv", userptr); + glColorMaski = (PFNGLCOLORMASKIPROC) load("glColorMaski", userptr); + glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load("glDeleteFramebuffers", userptr); + glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load("glDeleteRenderbuffers", userptr); + glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load("glDeleteVertexArrays", userptr); + glDisablei = (PFNGLDISABLEIPROC) load("glDisablei", userptr); + glEnablei = (PFNGLENABLEIPROC) load("glEnablei", userptr); + glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load("glEndConditionalRender", userptr); + glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load("glEndTransformFeedback", userptr); + glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load("glFlushMappedBufferRange", userptr); + glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load("glFramebufferRenderbuffer", userptr); + glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load("glFramebufferTexture1D", userptr); + glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load("glFramebufferTexture2D", userptr); + glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load("glFramebufferTexture3D", userptr); + glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load("glFramebufferTextureLayer", userptr); + glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load("glGenFramebuffers", userptr); + glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load("glGenRenderbuffers", userptr); + glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load("glGenVertexArrays", userptr); + glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load("glGenerateMipmap", userptr); + glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load("glGetBooleani_v", userptr); + glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load("glGetFragDataLocation", userptr); + glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load("glGetFramebufferAttachmentParameteriv", userptr); + glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load("glGetIntegeri_v", userptr); + glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load("glGetRenderbufferParameteriv", userptr); + glGetStringi = (PFNGLGETSTRINGIPROC) load("glGetStringi", userptr); + glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load("glGetTexParameterIiv", userptr); + glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load("glGetTexParameterIuiv", userptr); + glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load("glGetTransformFeedbackVarying", userptr); + glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load("glGetUniformuiv", userptr); + glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load("glGetVertexAttribIiv", userptr); + glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load("glGetVertexAttribIuiv", userptr); + glIsEnabledi = (PFNGLISENABLEDIPROC) load("glIsEnabledi", userptr); + glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load("glIsFramebuffer", userptr); + glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load("glIsRenderbuffer", userptr); + glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load("glIsVertexArray", userptr); + glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load("glMapBufferRange", userptr); + glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load("glRenderbufferStorage", userptr); + glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load("glRenderbufferStorageMultisample", userptr); + glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load("glTexParameterIiv", userptr); + glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load("glTexParameterIuiv", userptr); + glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load("glTransformFeedbackVaryings", userptr); + glUniform1ui = (PFNGLUNIFORM1UIPROC) load("glUniform1ui", userptr); + glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load("glUniform1uiv", userptr); + glUniform2ui = (PFNGLUNIFORM2UIPROC) load("glUniform2ui", userptr); + glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load("glUniform2uiv", userptr); + glUniform3ui = (PFNGLUNIFORM3UIPROC) load("glUniform3ui", userptr); + glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load("glUniform3uiv", userptr); + glUniform4ui = (PFNGLUNIFORM4UIPROC) load("glUniform4ui", userptr); + glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load("glUniform4uiv", userptr); + glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load("glVertexAttribI1i", userptr); + glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load("glVertexAttribI1iv", userptr); + glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load("glVertexAttribI1ui", userptr); + glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load("glVertexAttribI1uiv", userptr); + glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load("glVertexAttribI2i", userptr); + glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load("glVertexAttribI2iv", userptr); + glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load("glVertexAttribI2ui", userptr); + glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load("glVertexAttribI2uiv", userptr); + glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load("glVertexAttribI3i", userptr); + glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load("glVertexAttribI3iv", userptr); + glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load("glVertexAttribI3ui", userptr); + glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load("glVertexAttribI3uiv", userptr); + glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load("glVertexAttribI4bv", userptr); + glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load("glVertexAttribI4i", userptr); + glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load("glVertexAttribI4iv", userptr); + glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load("glVertexAttribI4sv", userptr); + glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load("glVertexAttribI4ubv", userptr); + glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load("glVertexAttribI4ui", userptr); + glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load("glVertexAttribI4uiv", userptr); + glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load("glVertexAttribI4usv", userptr); + glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load("glVertexAttribIPointer", userptr); +} +static void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_3_1) return; + glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load("glBindBufferBase", userptr); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load("glBindBufferRange", userptr); + glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load("glCopyBufferSubData", userptr); + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load("glDrawArraysInstanced", userptr); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load("glDrawElementsInstanced", userptr); + glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load("glGetActiveUniformBlockName", userptr); + glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load("glGetActiveUniformBlockiv", userptr); + glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load("glGetActiveUniformName", userptr); + glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load("glGetActiveUniformsiv", userptr); + glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load("glGetIntegeri_v", userptr); + glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load("glGetUniformBlockIndex", userptr); + glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load("glGetUniformIndices", userptr); + glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load("glPrimitiveRestartIndex", userptr); + glTexBuffer = (PFNGLTEXBUFFERPROC) load("glTexBuffer", userptr); + glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load("glUniformBlockBinding", userptr); +} +static void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_3_2) return; + glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load("glClientWaitSync", userptr); + glDeleteSync = (PFNGLDELETESYNCPROC) load("glDeleteSync", userptr); + glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load("glDrawElementsBaseVertex", userptr); + glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load("glDrawElementsInstancedBaseVertex", userptr); + glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load("glDrawRangeElementsBaseVertex", userptr); + glFenceSync = (PFNGLFENCESYNCPROC) load("glFenceSync", userptr); + glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load("glFramebufferTexture", userptr); + glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load("glGetBufferParameteri64v", userptr); + glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load("glGetInteger64i_v", userptr); + glGetInteger64v = (PFNGLGETINTEGER64VPROC) load("glGetInteger64v", userptr); + glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load("glGetMultisamplefv", userptr); + glGetSynciv = (PFNGLGETSYNCIVPROC) load("glGetSynciv", userptr); + glIsSync = (PFNGLISSYNCPROC) load("glIsSync", userptr); + glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load("glMultiDrawElementsBaseVertex", userptr); + glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load("glProvokingVertex", userptr); + glSampleMaski = (PFNGLSAMPLEMASKIPROC) load("glSampleMaski", userptr); + glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load("glTexImage2DMultisample", userptr); + glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load("glTexImage3DMultisample", userptr); + glWaitSync = (PFNGLWAITSYNCPROC) load("glWaitSync", userptr); +} +static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_3_3) return; + glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load("glBindFragDataLocationIndexed", userptr); + glBindSampler = (PFNGLBINDSAMPLERPROC) load("glBindSampler", userptr); + glColorP3ui = (PFNGLCOLORP3UIPROC) load("glColorP3ui", userptr); + glColorP3uiv = (PFNGLCOLORP3UIVPROC) load("glColorP3uiv", userptr); + glColorP4ui = (PFNGLCOLORP4UIPROC) load("glColorP4ui", userptr); + glColorP4uiv = (PFNGLCOLORP4UIVPROC) load("glColorP4uiv", userptr); + glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load("glDeleteSamplers", userptr); + glGenSamplers = (PFNGLGENSAMPLERSPROC) load("glGenSamplers", userptr); + glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load("glGetFragDataIndex", userptr); + glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load("glGetQueryObjecti64v", userptr); + glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load("glGetQueryObjectui64v", userptr); + glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load("glGetSamplerParameterIiv", userptr); + glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load("glGetSamplerParameterIuiv", userptr); + glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load("glGetSamplerParameterfv", userptr); + glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load("glGetSamplerParameteriv", userptr); + glIsSampler = (PFNGLISSAMPLERPROC) load("glIsSampler", userptr); + glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC) load("glMultiTexCoordP1ui", userptr); + glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC) load("glMultiTexCoordP1uiv", userptr); + glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC) load("glMultiTexCoordP2ui", userptr); + glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC) load("glMultiTexCoordP2uiv", userptr); + glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC) load("glMultiTexCoordP3ui", userptr); + glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC) load("glMultiTexCoordP3uiv", userptr); + glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC) load("glMultiTexCoordP4ui", userptr); + glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC) load("glMultiTexCoordP4uiv", userptr); + glNormalP3ui = (PFNGLNORMALP3UIPROC) load("glNormalP3ui", userptr); + glNormalP3uiv = (PFNGLNORMALP3UIVPROC) load("glNormalP3uiv", userptr); + glQueryCounter = (PFNGLQUERYCOUNTERPROC) load("glQueryCounter", userptr); + glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load("glSamplerParameterIiv", userptr); + glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load("glSamplerParameterIuiv", userptr); + glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load("glSamplerParameterf", userptr); + glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load("glSamplerParameterfv", userptr); + glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load("glSamplerParameteri", userptr); + glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load("glSamplerParameteriv", userptr); + glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC) load("glSecondaryColorP3ui", userptr); + glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC) load("glSecondaryColorP3uiv", userptr); + glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC) load("glTexCoordP1ui", userptr); + glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC) load("glTexCoordP1uiv", userptr); + glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC) load("glTexCoordP2ui", userptr); + glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC) load("glTexCoordP2uiv", userptr); + glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC) load("glTexCoordP3ui", userptr); + glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC) load("glTexCoordP3uiv", userptr); + glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC) load("glTexCoordP4ui", userptr); + glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC) load("glTexCoordP4uiv", userptr); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load("glVertexAttribDivisor", userptr); + glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load("glVertexAttribP1ui", userptr); + glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load("glVertexAttribP1uiv", userptr); + glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load("glVertexAttribP2ui", userptr); + glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load("glVertexAttribP2uiv", userptr); + glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load("glVertexAttribP3ui", userptr); + glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load("glVertexAttribP3uiv", userptr); + glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load("glVertexAttribP4ui", userptr); + glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load("glVertexAttribP4uiv", userptr); + glVertexP2ui = (PFNGLVERTEXP2UIPROC) load("glVertexP2ui", userptr); + glVertexP2uiv = (PFNGLVERTEXP2UIVPROC) load("glVertexP2uiv", userptr); + glVertexP3ui = (PFNGLVERTEXP3UIPROC) load("glVertexP3ui", userptr); + glVertexP3uiv = (PFNGLVERTEXP3UIVPROC) load("glVertexP3uiv", userptr); + glVertexP4ui = (PFNGLVERTEXP4UIPROC) load("glVertexP4ui", userptr); + glVertexP4uiv = (PFNGLVERTEXP4UIVPROC) load("glVertexP4uiv", userptr); +} +static void glad_gl_load_GL_ARB_multisample( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_multisample) return; + glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load("glSampleCoverage", userptr); + glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC) load("glSampleCoverageARB", userptr); +} +static void glad_gl_load_GL_ARB_robustness( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_robustness) return; + glGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC) load("glGetGraphicsResetStatusARB", userptr); + glGetnColorTableARB = (PFNGLGETNCOLORTABLEARBPROC) load("glGetnColorTableARB", userptr); + glGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) load("glGetnCompressedTexImageARB", userptr); + glGetnConvolutionFilterARB = (PFNGLGETNCONVOLUTIONFILTERARBPROC) load("glGetnConvolutionFilterARB", userptr); + glGetnHistogramARB = (PFNGLGETNHISTOGRAMARBPROC) load("glGetnHistogramARB", userptr); + glGetnMapdvARB = (PFNGLGETNMAPDVARBPROC) load("glGetnMapdvARB", userptr); + glGetnMapfvARB = (PFNGLGETNMAPFVARBPROC) load("glGetnMapfvARB", userptr); + glGetnMapivARB = (PFNGLGETNMAPIVARBPROC) load("glGetnMapivARB", userptr); + glGetnMinmaxARB = (PFNGLGETNMINMAXARBPROC) load("glGetnMinmaxARB", userptr); + glGetnPixelMapfvARB = (PFNGLGETNPIXELMAPFVARBPROC) load("glGetnPixelMapfvARB", userptr); + glGetnPixelMapuivARB = (PFNGLGETNPIXELMAPUIVARBPROC) load("glGetnPixelMapuivARB", userptr); + glGetnPixelMapusvARB = (PFNGLGETNPIXELMAPUSVARBPROC) load("glGetnPixelMapusvARB", userptr); + glGetnPolygonStippleARB = (PFNGLGETNPOLYGONSTIPPLEARBPROC) load("glGetnPolygonStippleARB", userptr); + glGetnSeparableFilterARB = (PFNGLGETNSEPARABLEFILTERARBPROC) load("glGetnSeparableFilterARB", userptr); + glGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC) load("glGetnTexImageARB", userptr); + glGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC) load("glGetnUniformdvARB", userptr); + glGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC) load("glGetnUniformfvARB", userptr); + glGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC) load("glGetnUniformivARB", userptr); + glGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC) load("glGetnUniformuivARB", userptr); + glReadnPixels = (PFNGLREADNPIXELSPROC) load("glReadnPixels", userptr); + glReadnPixelsARB = (PFNGLREADNPIXELSARBPROC) load("glReadnPixelsARB", userptr); +} +static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_debug) return; + glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load("glDebugMessageCallback", userptr); + glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load("glDebugMessageControl", userptr); + glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load("glDebugMessageInsert", userptr); + glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load("glGetDebugMessageLog", userptr); + glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load("glGetObjectLabel", userptr); + glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load("glGetObjectPtrLabel", userptr); + glGetPointerv = (PFNGLGETPOINTERVPROC) load("glGetPointerv", userptr); + glObjectLabel = (PFNGLOBJECTLABELPROC) load("glObjectLabel", userptr); + glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load("glObjectPtrLabel", userptr); + glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load("glPopDebugGroup", userptr); + glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load("glPushDebugGroup", userptr); +} + + + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define GLAD_GL_IS_SOME_NEW_VERSION 1 +#else +#define GLAD_GL_IS_SOME_NEW_VERSION 0 +#endif + +static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { +#if GLAD_GL_IS_SOME_NEW_VERSION + if(GLAD_VERSION_MAJOR(version) < 3) { +#else + (void) version; + (void) out_num_exts_i; + (void) out_exts_i; +#endif + if (glGetString == NULL) { + return 0; + } + *out_exts = (const char *)glGetString(GL_EXTENSIONS); +#if GLAD_GL_IS_SOME_NEW_VERSION + } else { + unsigned int index = 0; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (glGetStringi == NULL || glGetIntegerv == NULL) { + return 0; + } + glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); + } + if (exts_i == NULL) { + return 0; + } + for(index = 0; index < num_exts_i; index++) { + const char *gl_str_tmp = (const char*) glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp) + 1; + + char *local_str = (char*) malloc(len * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, len * sizeof(char)); + } + + exts_i[index] = local_str; + } + + *out_num_exts_i = num_exts_i; + *out_exts_i = exts_i; + } +#endif + return 1; +} +static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { + if (exts_i != NULL) { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + free((void *) (exts_i[index])); + } + free((void *)exts_i); + exts_i = NULL; + } +} +static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { + if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } + } else { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + if(strcmp(e, ext) == 0) { + return 1; + } + } + } + return 0; +} + +static GLADapiproc glad_gl_get_proc_from_userptr(const char* name, void *userptr) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_gl_find_extensions_gl( int version) { + const char *exts = NULL; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; + + GLAD_GL_ARB_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multisample"); + GLAD_GL_ARB_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_robustness"); + GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug"); + + glad_gl_free_extensions(exts_i, num_exts_i); + + return 1; +} + +static int glad_gl_find_core_gl(void) { + int i, major, minor; + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + version = (const char*) glGetString(GL_VERSION); + if (!version) return 0; + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + + GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); + + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; + GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) { + int version; + + glGetString = (PFNGLGETSTRINGPROC) load("glGetString", userptr); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + version = glad_gl_find_core_gl(); + + glad_gl_load_GL_VERSION_1_0(load, userptr); + glad_gl_load_GL_VERSION_1_1(load, userptr); + glad_gl_load_GL_VERSION_1_2(load, userptr); + glad_gl_load_GL_VERSION_1_3(load, userptr); + glad_gl_load_GL_VERSION_1_4(load, userptr); + glad_gl_load_GL_VERSION_1_5(load, userptr); + glad_gl_load_GL_VERSION_2_0(load, userptr); + glad_gl_load_GL_VERSION_2_1(load, userptr); + glad_gl_load_GL_VERSION_3_0(load, userptr); + glad_gl_load_GL_VERSION_3_1(load, userptr); + glad_gl_load_GL_VERSION_3_2(load, userptr); + glad_gl_load_GL_VERSION_3_3(load, userptr); + + if (!glad_gl_find_extensions_gl(version)) return 0; + glad_gl_load_GL_ARB_multisample(load, userptr); + glad_gl_load_GL_ARB_robustness(load, userptr); + glad_gl_load_GL_KHR_debug(load, userptr); + + + + return version; +} + + +int gladLoadGL( GLADloadfunc load) { + return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + diff --git a/raylib/external/glfw/deps/glad_vulkan.c b/raylib/external/glfw/deps/glad_vulkan.c new file mode 100644 index 0000000..5adfbbb --- /dev/null +++ b/raylib/external/glfw/deps/glad_vulkan.c @@ -0,0 +1,593 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + + +int GLAD_VK_VERSION_1_0 = 0; +int GLAD_VK_VERSION_1_1 = 0; +int GLAD_VK_EXT_debug_report = 0; +int GLAD_VK_KHR_surface = 0; +int GLAD_VK_KHR_swapchain = 0; + + + +PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR = NULL; +PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR = NULL; +PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers = NULL; +PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets = NULL; +PFN_vkAllocateMemory glad_vkAllocateMemory = NULL; +PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer = NULL; +PFN_vkBindBufferMemory glad_vkBindBufferMemory = NULL; +PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2 = NULL; +PFN_vkBindImageMemory glad_vkBindImageMemory = NULL; +PFN_vkBindImageMemory2 glad_vkBindImageMemory2 = NULL; +PFN_vkCmdBeginQuery glad_vkCmdBeginQuery = NULL; +PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass = NULL; +PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets = NULL; +PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer = NULL; +PFN_vkCmdBindPipeline glad_vkCmdBindPipeline = NULL; +PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers = NULL; +PFN_vkCmdBlitImage glad_vkCmdBlitImage = NULL; +PFN_vkCmdClearAttachments glad_vkCmdClearAttachments = NULL; +PFN_vkCmdClearColorImage glad_vkCmdClearColorImage = NULL; +PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage = NULL; +PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer = NULL; +PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage = NULL; +PFN_vkCmdCopyImage glad_vkCmdCopyImage = NULL; +PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer = NULL; +PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults = NULL; +PFN_vkCmdDispatch glad_vkCmdDispatch = NULL; +PFN_vkCmdDispatchBase glad_vkCmdDispatchBase = NULL; +PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect = NULL; +PFN_vkCmdDraw glad_vkCmdDraw = NULL; +PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed = NULL; +PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect = NULL; +PFN_vkCmdDrawIndirect glad_vkCmdDrawIndirect = NULL; +PFN_vkCmdEndQuery glad_vkCmdEndQuery = NULL; +PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass = NULL; +PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands = NULL; +PFN_vkCmdFillBuffer glad_vkCmdFillBuffer = NULL; +PFN_vkCmdNextSubpass glad_vkCmdNextSubpass = NULL; +PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier = NULL; +PFN_vkCmdPushConstants glad_vkCmdPushConstants = NULL; +PFN_vkCmdResetEvent glad_vkCmdResetEvent = NULL; +PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool = NULL; +PFN_vkCmdResolveImage glad_vkCmdResolveImage = NULL; +PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants = NULL; +PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias = NULL; +PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds = NULL; +PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask = NULL; +PFN_vkCmdSetEvent glad_vkCmdSetEvent = NULL; +PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth = NULL; +PFN_vkCmdSetScissor glad_vkCmdSetScissor = NULL; +PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask = NULL; +PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference = NULL; +PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask = NULL; +PFN_vkCmdSetViewport glad_vkCmdSetViewport = NULL; +PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer = NULL; +PFN_vkCmdWaitEvents glad_vkCmdWaitEvents = NULL; +PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp = NULL; +PFN_vkCreateBuffer glad_vkCreateBuffer = NULL; +PFN_vkCreateBufferView glad_vkCreateBufferView = NULL; +PFN_vkCreateCommandPool glad_vkCreateCommandPool = NULL; +PFN_vkCreateComputePipelines glad_vkCreateComputePipelines = NULL; +PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT = NULL; +PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool = NULL; +PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout = NULL; +PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate = NULL; +PFN_vkCreateDevice glad_vkCreateDevice = NULL; +PFN_vkCreateEvent glad_vkCreateEvent = NULL; +PFN_vkCreateFence glad_vkCreateFence = NULL; +PFN_vkCreateFramebuffer glad_vkCreateFramebuffer = NULL; +PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines = NULL; +PFN_vkCreateImage glad_vkCreateImage = NULL; +PFN_vkCreateImageView glad_vkCreateImageView = NULL; +PFN_vkCreateInstance glad_vkCreateInstance = NULL; +PFN_vkCreatePipelineCache glad_vkCreatePipelineCache = NULL; +PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout = NULL; +PFN_vkCreateQueryPool glad_vkCreateQueryPool = NULL; +PFN_vkCreateRenderPass glad_vkCreateRenderPass = NULL; +PFN_vkCreateSampler glad_vkCreateSampler = NULL; +PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion = NULL; +PFN_vkCreateSemaphore glad_vkCreateSemaphore = NULL; +PFN_vkCreateShaderModule glad_vkCreateShaderModule = NULL; +PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR = NULL; +PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT = NULL; +PFN_vkDestroyBuffer glad_vkDestroyBuffer = NULL; +PFN_vkDestroyBufferView glad_vkDestroyBufferView = NULL; +PFN_vkDestroyCommandPool glad_vkDestroyCommandPool = NULL; +PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT = NULL; +PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool = NULL; +PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout = NULL; +PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate = NULL; +PFN_vkDestroyDevice glad_vkDestroyDevice = NULL; +PFN_vkDestroyEvent glad_vkDestroyEvent = NULL; +PFN_vkDestroyFence glad_vkDestroyFence = NULL; +PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer = NULL; +PFN_vkDestroyImage glad_vkDestroyImage = NULL; +PFN_vkDestroyImageView glad_vkDestroyImageView = NULL; +PFN_vkDestroyInstance glad_vkDestroyInstance = NULL; +PFN_vkDestroyPipeline glad_vkDestroyPipeline = NULL; +PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache = NULL; +PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout = NULL; +PFN_vkDestroyQueryPool glad_vkDestroyQueryPool = NULL; +PFN_vkDestroyRenderPass glad_vkDestroyRenderPass = NULL; +PFN_vkDestroySampler glad_vkDestroySampler = NULL; +PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion = NULL; +PFN_vkDestroySemaphore glad_vkDestroySemaphore = NULL; +PFN_vkDestroyShaderModule glad_vkDestroyShaderModule = NULL; +PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR = NULL; +PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR = NULL; +PFN_vkDeviceWaitIdle glad_vkDeviceWaitIdle = NULL; +PFN_vkEndCommandBuffer glad_vkEndCommandBuffer = NULL; +PFN_vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties = NULL; +PFN_vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties = NULL; +PFN_vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties = NULL; +PFN_vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties = NULL; +PFN_vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion = NULL; +PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups = NULL; +PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices = NULL; +PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges = NULL; +PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers = NULL; +PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets = NULL; +PFN_vkFreeMemory glad_vkFreeMemory = NULL; +PFN_vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements = NULL; +PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2 = NULL; +PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport = NULL; +PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures = NULL; +PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR = NULL; +PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR = NULL; +PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment = NULL; +PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr = NULL; +PFN_vkGetDeviceQueue glad_vkGetDeviceQueue = NULL; +PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2 = NULL; +PFN_vkGetEventStatus glad_vkGetEventStatus = NULL; +PFN_vkGetFenceStatus glad_vkGetFenceStatus = NULL; +PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements = NULL; +PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 = NULL; +PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements = NULL; +PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2 = NULL; +PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout = NULL; +PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr = NULL; +PFN_vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties = NULL; +PFN_vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties = NULL; +PFN_vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties = NULL; +PFN_vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures = NULL; +PFN_vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2 = NULL; +PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties = NULL; +PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 = NULL; +PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties = NULL; +PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2 = NULL; +PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties = NULL; +PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2 = NULL; +PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR = NULL; +PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties = NULL; +PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2 = NULL; +PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties = NULL; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 = NULL; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties = NULL; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2 = NULL; +PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = NULL; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR = NULL; +PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR = NULL; +PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR = NULL; +PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData = NULL; +PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults = NULL; +PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity = NULL; +PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR = NULL; +PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges = NULL; +PFN_vkMapMemory glad_vkMapMemory = NULL; +PFN_vkMergePipelineCaches glad_vkMergePipelineCaches = NULL; +PFN_vkQueueBindSparse glad_vkQueueBindSparse = NULL; +PFN_vkQueuePresentKHR glad_vkQueuePresentKHR = NULL; +PFN_vkQueueSubmit glad_vkQueueSubmit = NULL; +PFN_vkQueueWaitIdle glad_vkQueueWaitIdle = NULL; +PFN_vkResetCommandBuffer glad_vkResetCommandBuffer = NULL; +PFN_vkResetCommandPool glad_vkResetCommandPool = NULL; +PFN_vkResetDescriptorPool glad_vkResetDescriptorPool = NULL; +PFN_vkResetEvent glad_vkResetEvent = NULL; +PFN_vkResetFences glad_vkResetFences = NULL; +PFN_vkSetEvent glad_vkSetEvent = NULL; +PFN_vkTrimCommandPool glad_vkTrimCommandPool = NULL; +PFN_vkUnmapMemory glad_vkUnmapMemory = NULL; +PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate = NULL; +PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets = NULL; +PFN_vkWaitForFences glad_vkWaitForFences = NULL; + + +static void glad_vk_load_VK_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VERSION_1_0) return; + vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers) load("vkAllocateCommandBuffers", userptr); + vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets) load("vkAllocateDescriptorSets", userptr); + vkAllocateMemory = (PFN_vkAllocateMemory) load("vkAllocateMemory", userptr); + vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer) load("vkBeginCommandBuffer", userptr); + vkBindBufferMemory = (PFN_vkBindBufferMemory) load("vkBindBufferMemory", userptr); + vkBindImageMemory = (PFN_vkBindImageMemory) load("vkBindImageMemory", userptr); + vkCmdBeginQuery = (PFN_vkCmdBeginQuery) load("vkCmdBeginQuery", userptr); + vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass) load("vkCmdBeginRenderPass", userptr); + vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets) load("vkCmdBindDescriptorSets", userptr); + vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer) load("vkCmdBindIndexBuffer", userptr); + vkCmdBindPipeline = (PFN_vkCmdBindPipeline) load("vkCmdBindPipeline", userptr); + vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers) load("vkCmdBindVertexBuffers", userptr); + vkCmdBlitImage = (PFN_vkCmdBlitImage) load("vkCmdBlitImage", userptr); + vkCmdClearAttachments = (PFN_vkCmdClearAttachments) load("vkCmdClearAttachments", userptr); + vkCmdClearColorImage = (PFN_vkCmdClearColorImage) load("vkCmdClearColorImage", userptr); + vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage) load("vkCmdClearDepthStencilImage", userptr); + vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer) load("vkCmdCopyBuffer", userptr); + vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage) load("vkCmdCopyBufferToImage", userptr); + vkCmdCopyImage = (PFN_vkCmdCopyImage) load("vkCmdCopyImage", userptr); + vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer) load("vkCmdCopyImageToBuffer", userptr); + vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults) load("vkCmdCopyQueryPoolResults", userptr); + vkCmdDispatch = (PFN_vkCmdDispatch) load("vkCmdDispatch", userptr); + vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect) load("vkCmdDispatchIndirect", userptr); + vkCmdDraw = (PFN_vkCmdDraw) load("vkCmdDraw", userptr); + vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed) load("vkCmdDrawIndexed", userptr); + vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect) load("vkCmdDrawIndexedIndirect", userptr); + vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect) load("vkCmdDrawIndirect", userptr); + vkCmdEndQuery = (PFN_vkCmdEndQuery) load("vkCmdEndQuery", userptr); + vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass) load("vkCmdEndRenderPass", userptr); + vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands) load("vkCmdExecuteCommands", userptr); + vkCmdFillBuffer = (PFN_vkCmdFillBuffer) load("vkCmdFillBuffer", userptr); + vkCmdNextSubpass = (PFN_vkCmdNextSubpass) load("vkCmdNextSubpass", userptr); + vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier) load("vkCmdPipelineBarrier", userptr); + vkCmdPushConstants = (PFN_vkCmdPushConstants) load("vkCmdPushConstants", userptr); + vkCmdResetEvent = (PFN_vkCmdResetEvent) load("vkCmdResetEvent", userptr); + vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool) load("vkCmdResetQueryPool", userptr); + vkCmdResolveImage = (PFN_vkCmdResolveImage) load("vkCmdResolveImage", userptr); + vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants) load("vkCmdSetBlendConstants", userptr); + vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias) load("vkCmdSetDepthBias", userptr); + vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds) load("vkCmdSetDepthBounds", userptr); + vkCmdSetEvent = (PFN_vkCmdSetEvent) load("vkCmdSetEvent", userptr); + vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth) load("vkCmdSetLineWidth", userptr); + vkCmdSetScissor = (PFN_vkCmdSetScissor) load("vkCmdSetScissor", userptr); + vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask) load("vkCmdSetStencilCompareMask", userptr); + vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference) load("vkCmdSetStencilReference", userptr); + vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask) load("vkCmdSetStencilWriteMask", userptr); + vkCmdSetViewport = (PFN_vkCmdSetViewport) load("vkCmdSetViewport", userptr); + vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer) load("vkCmdUpdateBuffer", userptr); + vkCmdWaitEvents = (PFN_vkCmdWaitEvents) load("vkCmdWaitEvents", userptr); + vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp) load("vkCmdWriteTimestamp", userptr); + vkCreateBuffer = (PFN_vkCreateBuffer) load("vkCreateBuffer", userptr); + vkCreateBufferView = (PFN_vkCreateBufferView) load("vkCreateBufferView", userptr); + vkCreateCommandPool = (PFN_vkCreateCommandPool) load("vkCreateCommandPool", userptr); + vkCreateComputePipelines = (PFN_vkCreateComputePipelines) load("vkCreateComputePipelines", userptr); + vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool) load("vkCreateDescriptorPool", userptr); + vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout) load("vkCreateDescriptorSetLayout", userptr); + vkCreateDevice = (PFN_vkCreateDevice) load("vkCreateDevice", userptr); + vkCreateEvent = (PFN_vkCreateEvent) load("vkCreateEvent", userptr); + vkCreateFence = (PFN_vkCreateFence) load("vkCreateFence", userptr); + vkCreateFramebuffer = (PFN_vkCreateFramebuffer) load("vkCreateFramebuffer", userptr); + vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines) load("vkCreateGraphicsPipelines", userptr); + vkCreateImage = (PFN_vkCreateImage) load("vkCreateImage", userptr); + vkCreateImageView = (PFN_vkCreateImageView) load("vkCreateImageView", userptr); + vkCreateInstance = (PFN_vkCreateInstance) load("vkCreateInstance", userptr); + vkCreatePipelineCache = (PFN_vkCreatePipelineCache) load("vkCreatePipelineCache", userptr); + vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout) load("vkCreatePipelineLayout", userptr); + vkCreateQueryPool = (PFN_vkCreateQueryPool) load("vkCreateQueryPool", userptr); + vkCreateRenderPass = (PFN_vkCreateRenderPass) load("vkCreateRenderPass", userptr); + vkCreateSampler = (PFN_vkCreateSampler) load("vkCreateSampler", userptr); + vkCreateSemaphore = (PFN_vkCreateSemaphore) load("vkCreateSemaphore", userptr); + vkCreateShaderModule = (PFN_vkCreateShaderModule) load("vkCreateShaderModule", userptr); + vkDestroyBuffer = (PFN_vkDestroyBuffer) load("vkDestroyBuffer", userptr); + vkDestroyBufferView = (PFN_vkDestroyBufferView) load("vkDestroyBufferView", userptr); + vkDestroyCommandPool = (PFN_vkDestroyCommandPool) load("vkDestroyCommandPool", userptr); + vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool) load("vkDestroyDescriptorPool", userptr); + vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout) load("vkDestroyDescriptorSetLayout", userptr); + vkDestroyDevice = (PFN_vkDestroyDevice) load("vkDestroyDevice", userptr); + vkDestroyEvent = (PFN_vkDestroyEvent) load("vkDestroyEvent", userptr); + vkDestroyFence = (PFN_vkDestroyFence) load("vkDestroyFence", userptr); + vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer) load("vkDestroyFramebuffer", userptr); + vkDestroyImage = (PFN_vkDestroyImage) load("vkDestroyImage", userptr); + vkDestroyImageView = (PFN_vkDestroyImageView) load("vkDestroyImageView", userptr); + vkDestroyInstance = (PFN_vkDestroyInstance) load("vkDestroyInstance", userptr); + vkDestroyPipeline = (PFN_vkDestroyPipeline) load("vkDestroyPipeline", userptr); + vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache) load("vkDestroyPipelineCache", userptr); + vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout) load("vkDestroyPipelineLayout", userptr); + vkDestroyQueryPool = (PFN_vkDestroyQueryPool) load("vkDestroyQueryPool", userptr); + vkDestroyRenderPass = (PFN_vkDestroyRenderPass) load("vkDestroyRenderPass", userptr); + vkDestroySampler = (PFN_vkDestroySampler) load("vkDestroySampler", userptr); + vkDestroySemaphore = (PFN_vkDestroySemaphore) load("vkDestroySemaphore", userptr); + vkDestroyShaderModule = (PFN_vkDestroyShaderModule) load("vkDestroyShaderModule", userptr); + vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle) load("vkDeviceWaitIdle", userptr); + vkEndCommandBuffer = (PFN_vkEndCommandBuffer) load("vkEndCommandBuffer", userptr); + vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties) load("vkEnumerateDeviceExtensionProperties", userptr); + vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties) load("vkEnumerateDeviceLayerProperties", userptr); + vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) load("vkEnumerateInstanceExtensionProperties", userptr); + vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties) load("vkEnumerateInstanceLayerProperties", userptr); + vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices) load("vkEnumeratePhysicalDevices", userptr); + vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges) load("vkFlushMappedMemoryRanges", userptr); + vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers) load("vkFreeCommandBuffers", userptr); + vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets) load("vkFreeDescriptorSets", userptr); + vkFreeMemory = (PFN_vkFreeMemory) load("vkFreeMemory", userptr); + vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements) load("vkGetBufferMemoryRequirements", userptr); + vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment) load("vkGetDeviceMemoryCommitment", userptr); + vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) load("vkGetDeviceProcAddr", userptr); + vkGetDeviceQueue = (PFN_vkGetDeviceQueue) load("vkGetDeviceQueue", userptr); + vkGetEventStatus = (PFN_vkGetEventStatus) load("vkGetEventStatus", userptr); + vkGetFenceStatus = (PFN_vkGetFenceStatus) load("vkGetFenceStatus", userptr); + vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements) load("vkGetImageMemoryRequirements", userptr); + vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements) load("vkGetImageSparseMemoryRequirements", userptr); + vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout) load("vkGetImageSubresourceLayout", userptr); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) load("vkGetInstanceProcAddr", userptr); + vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures) load("vkGetPhysicalDeviceFeatures", userptr); + vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties) load("vkGetPhysicalDeviceFormatProperties", userptr); + vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties) load("vkGetPhysicalDeviceImageFormatProperties", userptr); + vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) load("vkGetPhysicalDeviceMemoryProperties", userptr); + vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) load("vkGetPhysicalDeviceProperties", userptr); + vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties) load("vkGetPhysicalDeviceQueueFamilyProperties", userptr); + vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties) load("vkGetPhysicalDeviceSparseImageFormatProperties", userptr); + vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData) load("vkGetPipelineCacheData", userptr); + vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults) load("vkGetQueryPoolResults", userptr); + vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity) load("vkGetRenderAreaGranularity", userptr); + vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges) load("vkInvalidateMappedMemoryRanges", userptr); + vkMapMemory = (PFN_vkMapMemory) load("vkMapMemory", userptr); + vkMergePipelineCaches = (PFN_vkMergePipelineCaches) load("vkMergePipelineCaches", userptr); + vkQueueBindSparse = (PFN_vkQueueBindSparse) load("vkQueueBindSparse", userptr); + vkQueueSubmit = (PFN_vkQueueSubmit) load("vkQueueSubmit", userptr); + vkQueueWaitIdle = (PFN_vkQueueWaitIdle) load("vkQueueWaitIdle", userptr); + vkResetCommandBuffer = (PFN_vkResetCommandBuffer) load("vkResetCommandBuffer", userptr); + vkResetCommandPool = (PFN_vkResetCommandPool) load("vkResetCommandPool", userptr); + vkResetDescriptorPool = (PFN_vkResetDescriptorPool) load("vkResetDescriptorPool", userptr); + vkResetEvent = (PFN_vkResetEvent) load("vkResetEvent", userptr); + vkResetFences = (PFN_vkResetFences) load("vkResetFences", userptr); + vkSetEvent = (PFN_vkSetEvent) load("vkSetEvent", userptr); + vkUnmapMemory = (PFN_vkUnmapMemory) load("vkUnmapMemory", userptr); + vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets) load("vkUpdateDescriptorSets", userptr); + vkWaitForFences = (PFN_vkWaitForFences) load("vkWaitForFences", userptr); +} +static void glad_vk_load_VK_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VERSION_1_1) return; + vkBindBufferMemory2 = (PFN_vkBindBufferMemory2) load("vkBindBufferMemory2", userptr); + vkBindImageMemory2 = (PFN_vkBindImageMemory2) load("vkBindImageMemory2", userptr); + vkCmdDispatchBase = (PFN_vkCmdDispatchBase) load("vkCmdDispatchBase", userptr); + vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask) load("vkCmdSetDeviceMask", userptr); + vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate) load("vkCreateDescriptorUpdateTemplate", userptr); + vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion) load("vkCreateSamplerYcbcrConversion", userptr); + vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate) load("vkDestroyDescriptorUpdateTemplate", userptr); + vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion) load("vkDestroySamplerYcbcrConversion", userptr); + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) load("vkEnumerateInstanceVersion", userptr); + vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups) load("vkEnumeratePhysicalDeviceGroups", userptr); + vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2) load("vkGetBufferMemoryRequirements2", userptr); + vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport) load("vkGetDescriptorSetLayoutSupport", userptr); + vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures) load("vkGetDeviceGroupPeerMemoryFeatures", userptr); + vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2) load("vkGetDeviceQueue2", userptr); + vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2) load("vkGetImageMemoryRequirements2", userptr); + vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2) load("vkGetImageSparseMemoryRequirements2", userptr); + vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties) load("vkGetPhysicalDeviceExternalBufferProperties", userptr); + vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties) load("vkGetPhysicalDeviceExternalFenceProperties", userptr); + vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties) load("vkGetPhysicalDeviceExternalSemaphoreProperties", userptr); + vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2) load("vkGetPhysicalDeviceFeatures2", userptr); + vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2) load("vkGetPhysicalDeviceFormatProperties2", userptr); + vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2) load("vkGetPhysicalDeviceImageFormatProperties2", userptr); + vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2) load("vkGetPhysicalDeviceMemoryProperties2", userptr); + vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) load("vkGetPhysicalDeviceProperties2", userptr); + vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2) load("vkGetPhysicalDeviceQueueFamilyProperties2", userptr); + vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2) load("vkGetPhysicalDeviceSparseImageFormatProperties2", userptr); + vkTrimCommandPool = (PFN_vkTrimCommandPool) load("vkTrimCommandPool", userptr); + vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate) load("vkUpdateDescriptorSetWithTemplate", userptr); +} +static void glad_vk_load_VK_EXT_debug_report( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_debug_report) return; + vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT) load("vkCreateDebugReportCallbackEXT", userptr); + vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT) load("vkDebugReportMessageEXT", userptr); + vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT) load("vkDestroyDebugReportCallbackEXT", userptr); +} +static void glad_vk_load_VK_KHR_surface( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_surface) return; + vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR) load("vkDestroySurfaceKHR", userptr); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR) load("vkGetPhysicalDeviceSurfaceCapabilitiesKHR", userptr); + vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR) load("vkGetPhysicalDeviceSurfaceFormatsKHR", userptr); + vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) load("vkGetPhysicalDeviceSurfacePresentModesKHR", userptr); + vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) load("vkGetPhysicalDeviceSurfaceSupportKHR", userptr); +} +static void glad_vk_load_VK_KHR_swapchain( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_swapchain) return; + vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR) load("vkAcquireNextImage2KHR", userptr); + vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) load("vkAcquireNextImageKHR", userptr); + vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) load("vkCreateSwapchainKHR", userptr); + vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) load("vkDestroySwapchainKHR", userptr); + vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR) load("vkGetDeviceGroupPresentCapabilitiesKHR", userptr); + vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR) load("vkGetDeviceGroupSurfacePresentModesKHR", userptr); + vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR) load("vkGetPhysicalDevicePresentRectanglesKHR", userptr); + vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) load("vkGetSwapchainImagesKHR", userptr); + vkQueuePresentKHR = (PFN_vkQueuePresentKHR) load("vkQueuePresentKHR", userptr); +} + + + +static int glad_vk_get_extensions( VkPhysicalDevice physical_device, uint32_t *out_extension_count, char ***out_extensions) { + uint32_t i; + uint32_t instance_extension_count = 0; + uint32_t device_extension_count = 0; + uint32_t max_extension_count; + uint32_t total_extension_count; + char **extensions; + VkExtensionProperties *ext_properties; + VkResult result; + + if (vkEnumerateInstanceExtensionProperties == NULL || (physical_device != NULL && vkEnumerateDeviceExtensionProperties == NULL)) { + return 0; + } + + result = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL); + if (result != VK_SUCCESS) { + return 0; + } + + if (physical_device != NULL) { + result = vkEnumerateDeviceExtensionProperties(physical_device, NULL, &device_extension_count, NULL); + if (result != VK_SUCCESS) { + return 0; + } + } + + total_extension_count = instance_extension_count + device_extension_count; + max_extension_count = instance_extension_count > device_extension_count + ? instance_extension_count : device_extension_count; + + ext_properties = (VkExtensionProperties*) malloc(max_extension_count * sizeof(VkExtensionProperties)); + if (ext_properties == NULL) { + return 0; + } + + result = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, ext_properties); + if (result != VK_SUCCESS) { + free((void*) ext_properties); + return 0; + } + + extensions = (char**) calloc(total_extension_count, sizeof(char*)); + if (extensions == NULL) { + free((void*) ext_properties); + return 0; + } + + for (i = 0; i < instance_extension_count; ++i) { + VkExtensionProperties ext = ext_properties[i]; + + size_t extension_name_length = strlen(ext.extensionName) + 1; + extensions[i] = (char*) malloc(extension_name_length * sizeof(char)); + memcpy(extensions[i], ext.extensionName, extension_name_length * sizeof(char)); + } + + if (physical_device != NULL) { + result = vkEnumerateDeviceExtensionProperties(physical_device, NULL, &device_extension_count, ext_properties); + if (result != VK_SUCCESS) { + for (i = 0; i < instance_extension_count; ++i) { + free((void*) extensions[i]); + } + free(extensions); + return 0; + } + + for (i = 0; i < device_extension_count; ++i) { + VkExtensionProperties ext = ext_properties[i]; + + size_t extension_name_length = strlen(ext.extensionName) + 1; + extensions[instance_extension_count + i] = (char*) malloc(extension_name_length * sizeof(char)); + memcpy(extensions[instance_extension_count + i], ext.extensionName, extension_name_length * sizeof(char)); + } + } + + free((void*) ext_properties); + + *out_extension_count = total_extension_count; + *out_extensions = extensions; + + return 1; +} + +static void glad_vk_free_extensions(uint32_t extension_count, char **extensions) { + uint32_t i; + + for(i = 0; i < extension_count ; ++i) { + free((void*) (extensions[i])); + } + + free((void*) extensions); +} + +static int glad_vk_has_extension(const char *name, uint32_t extension_count, char **extensions) { + uint32_t i; + + for (i = 0; i < extension_count; ++i) { + if(strcmp(name, extensions[i]) == 0) { + return 1; + } + } + + return 0; +} + +static GLADapiproc glad_vk_get_proc_from_userptr(const char* name, void *userptr) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { + uint32_t extension_count = 0; + char **extensions = NULL; + if (!glad_vk_get_extensions(physical_device, &extension_count, &extensions)) return 0; + + GLAD_VK_EXT_debug_report = glad_vk_has_extension("VK_EXT_debug_report", extension_count, extensions); + GLAD_VK_KHR_surface = glad_vk_has_extension("VK_KHR_surface", extension_count, extensions); + GLAD_VK_KHR_swapchain = glad_vk_has_extension("VK_KHR_swapchain", extension_count, extensions); + + glad_vk_free_extensions(extension_count, extensions); + + return 1; +} + +static int glad_vk_find_core_vulkan( VkPhysicalDevice physical_device) { + int major = 1; + int minor = 0; + +#ifdef VK_VERSION_1_1 + if (vkEnumerateInstanceVersion != NULL) { + uint32_t version; + VkResult result; + + result = vkEnumerateInstanceVersion(&version); + if (result == VK_SUCCESS) { + major = (int) VK_VERSION_MAJOR(version); + minor = (int) VK_VERSION_MINOR(version); + } + } +#endif + + if (physical_device != NULL && vkGetPhysicalDeviceProperties != NULL) { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(physical_device, &properties); + + major = (int) VK_VERSION_MAJOR(properties.apiVersion); + minor = (int) VK_VERSION_MINOR(properties.apiVersion); + } + + GLAD_VK_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_VK_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc load, void *userptr) { + int version; + +#ifdef VK_VERSION_1_1 + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) load("vkEnumerateInstanceVersion", userptr); +#endif + version = glad_vk_find_core_vulkan( physical_device); + if (!version) { + return 0; + } + + glad_vk_load_VK_VERSION_1_0(load, userptr); + glad_vk_load_VK_VERSION_1_1(load, userptr); + + if (!glad_vk_find_extensions_vulkan( physical_device)) return 0; + glad_vk_load_VK_EXT_debug_report(load, userptr); + glad_vk_load_VK_KHR_surface(load, userptr); + glad_vk_load_VK_KHR_swapchain(load, userptr); + + + return version; +} + + +int gladLoadVulkan( VkPhysicalDevice physical_device, GLADloadfunc load) { + return gladLoadVulkanUserPtr( physical_device, glad_vk_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + diff --git a/raylib/external/glfw/deps/mingw/_mingw_dxhelper.h b/raylib/external/glfw/deps/mingw/_mingw_dxhelper.h new file mode 100644 index 0000000..849e291 --- /dev/null +++ b/raylib/external/glfw/deps/mingw/_mingw_dxhelper.h @@ -0,0 +1,117 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS) +#define NONAMELESSUNION 1 +#endif +#if defined(NONAMELESSSTRUCT) && \ + !defined(NONAMELESSUNION) +#define NONAMELESSUNION 1 +#endif +#if defined(NONAMELESSUNION) && \ + !defined(NONAMELESSSTRUCT) +#define NONAMELESSSTRUCT 1 +#endif +#if !defined(__GNU_EXTENSION) +#if defined(__GNUC__) || defined(__GNUG__) +#define __GNU_EXTENSION __extension__ +#else +#define __GNU_EXTENSION +#endif +#endif /* __extension__ */ + +#ifndef __ANONYMOUS_DEFINED +#define __ANONYMOUS_DEFINED +#if defined(__GNUC__) || defined(__GNUG__) +#define _ANONYMOUS_UNION __extension__ +#define _ANONYMOUS_STRUCT __extension__ +#else +#define _ANONYMOUS_UNION +#define _ANONYMOUS_STRUCT +#endif +#ifndef NONAMELESSUNION +#define _UNION_NAME(x) +#define _STRUCT_NAME(x) +#else /* NONAMELESSUNION */ +#define _UNION_NAME(x) x +#define _STRUCT_NAME(x) x +#endif +#endif /* __ANONYMOUS_DEFINED */ + +#ifndef DUMMYUNIONNAME +# ifdef NONAMELESSUNION +# define DUMMYUNIONNAME u +# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */ +# define DUMMYUNIONNAME2 u2 +# define DUMMYUNIONNAME3 u3 +# define DUMMYUNIONNAME4 u4 +# define DUMMYUNIONNAME5 u5 +# define DUMMYUNIONNAME6 u6 +# define DUMMYUNIONNAME7 u7 +# define DUMMYUNIONNAME8 u8 +# define DUMMYUNIONNAME9 u9 +# else /* NONAMELESSUNION */ +# define DUMMYUNIONNAME +# define DUMMYUNIONNAME1 /* Wine uses this variant */ +# define DUMMYUNIONNAME2 +# define DUMMYUNIONNAME3 +# define DUMMYUNIONNAME4 +# define DUMMYUNIONNAME5 +# define DUMMYUNIONNAME6 +# define DUMMYUNIONNAME7 +# define DUMMYUNIONNAME8 +# define DUMMYUNIONNAME9 +# endif +#endif /* DUMMYUNIONNAME */ + +#if !defined(DUMMYUNIONNAME1) /* MinGW does not define this one */ +# ifdef NONAMELESSUNION +# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */ +# else +# define DUMMYUNIONNAME1 /* Wine uses this variant */ +# endif +#endif /* DUMMYUNIONNAME1 */ + +#ifndef DUMMYSTRUCTNAME +# ifdef NONAMELESSUNION +# define DUMMYSTRUCTNAME s +# define DUMMYSTRUCTNAME1 s1 /* Wine uses this variant */ +# define DUMMYSTRUCTNAME2 s2 +# define DUMMYSTRUCTNAME3 s3 +# define DUMMYSTRUCTNAME4 s4 +# define DUMMYSTRUCTNAME5 s5 +# else +# define DUMMYSTRUCTNAME +# define DUMMYSTRUCTNAME1 /* Wine uses this variant */ +# define DUMMYSTRUCTNAME2 +# define DUMMYSTRUCTNAME3 +# define DUMMYSTRUCTNAME4 +# define DUMMYSTRUCTNAME5 +# endif +#endif /* DUMMYSTRUCTNAME */ + +/* These are for compatibility with the Wine source tree */ + +#ifndef WINELIB_NAME_AW +# ifdef __MINGW_NAME_AW +# define WINELIB_NAME_AW __MINGW_NAME_AW +# else +# ifdef UNICODE +# define WINELIB_NAME_AW(func) func##W +# else +# define WINELIB_NAME_AW(func) func##A +# endif +# endif +#endif /* WINELIB_NAME_AW */ + +#ifndef DECL_WINELIB_TYPE_AW +# ifdef __MINGW_TYPEDEF_AW +# define DECL_WINELIB_TYPE_AW __MINGW_TYPEDEF_AW +# else +# define DECL_WINELIB_TYPE_AW(type) typedef WINELIB_NAME_AW(type) type; +# endif +#endif /* DECL_WINELIB_TYPE_AW */ + diff --git a/raylib/external/glfw/deps/mingw/dinput.h b/raylib/external/glfw/deps/mingw/dinput.h new file mode 100644 index 0000000..b575480 --- /dev/null +++ b/raylib/external/glfw/deps/mingw/dinput.h @@ -0,0 +1,2467 @@ +/* + * Copyright (C) the Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DINPUT_INCLUDED__ +#define __DINPUT_INCLUDED__ + +#define COM_NO_WINDOWS_H +#include +#include <_mingw_dxhelper.h> + +#ifndef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0800 +#endif + +/* Classes */ +DEFINE_GUID(CLSID_DirectInput, 0x25E609E0,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice, 0x25E609E1,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(CLSID_DirectInput8, 0x25E609E4,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice8, 0x25E609E5,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* Interfaces */ +DEFINE_GUID(IID_IDirectInputA, 0x89521360,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputW, 0x89521361,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2A, 0x5944E662,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2W, 0x5944E663,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput7A, 0x9A4CB684,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInput7W, 0x9A4CB685,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInput8A, 0xBF798030,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); +DEFINE_GUID(IID_IDirectInput8W, 0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); +DEFINE_GUID(IID_IDirectInputDeviceA, 0x5944E680,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDeviceW, 0x5944E681,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2A, 0x5944E682,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2W, 0x5944E683,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice7A, 0x57D7C6BC,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInputDevice7W, 0x57D7C6BD,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInputDevice8A, 0x54D41080,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); +DEFINE_GUID(IID_IDirectInputDevice8W, 0x54D41081,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); +DEFINE_GUID(IID_IDirectInputEffect, 0xE7E1F7C0,0x88D2,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +/* Predefined object types */ +DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RxAxis,0xA36D02F4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RyAxis,0xA36D02F5,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RzAxis,0xA36D02E3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Slider,0xA36D02E4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Button,0xA36D02F0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Key, 0x55728220,0xD33C,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_POV, 0xA36D02F2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Unknown,0xA36D02F3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* Predefined product GUIDs */ +DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboard, 0x6F1D2B61,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Joystick, 0x6F1D2B70,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysMouseEm, 0x6F1D2B80,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysMouseEm2, 0x6F1D2B81,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboardEm, 0x6F1D2B82,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboardEm2,0x6F1D2B83,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* predefined forcefeedback effects */ +DEFINE_GUID(GUID_ConstantForce, 0x13541C20,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_RampForce, 0x13541C21,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Square, 0x13541C22,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Sine, 0x13541C23,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Triangle, 0x13541C24,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothUp, 0x13541C25,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothDown, 0x13541C26,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Spring, 0x13541C27,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Damper, 0x13541C28,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Inertia, 0x13541C29,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Friction, 0x13541C2A,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_CustomForce, 0x13541C2B,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +typedef struct IDirectInputA *LPDIRECTINPUTA; +typedef struct IDirectInputW *LPDIRECTINPUTW; +typedef struct IDirectInput2A *LPDIRECTINPUT2A; +typedef struct IDirectInput2W *LPDIRECTINPUT2W; +typedef struct IDirectInput7A *LPDIRECTINPUT7A; +typedef struct IDirectInput7W *LPDIRECTINPUT7W; +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct IDirectInput8A *LPDIRECTINPUT8A; +typedef struct IDirectInput8W *LPDIRECTINPUT8W; +#endif /* DI8 */ +typedef struct IDirectInputDeviceA *LPDIRECTINPUTDEVICEA; +typedef struct IDirectInputDeviceW *LPDIRECTINPUTDEVICEW; +#if DIRECTINPUT_VERSION >= 0x0500 +typedef struct IDirectInputDevice2A *LPDIRECTINPUTDEVICE2A; +typedef struct IDirectInputDevice2W *LPDIRECTINPUTDEVICE2W; +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x0700 +typedef struct IDirectInputDevice7A *LPDIRECTINPUTDEVICE7A; +typedef struct IDirectInputDevice7W *LPDIRECTINPUTDEVICE7W; +#endif /* DI7 */ +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct IDirectInputDevice8A *LPDIRECTINPUTDEVICE8A; +typedef struct IDirectInputDevice8W *LPDIRECTINPUTDEVICE8W; +#endif /* DI8 */ +#if DIRECTINPUT_VERSION >= 0x0500 +typedef struct IDirectInputEffect *LPDIRECTINPUTEFFECT; +#endif /* DI5 */ +typedef struct SysKeyboardA *LPSYSKEYBOARDA; +typedef struct SysMouseA *LPSYSMOUSEA; + +#define IID_IDirectInput WINELIB_NAME_AW(IID_IDirectInput) +#define IDirectInput WINELIB_NAME_AW(IDirectInput) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT) +#define IID_IDirectInput2 WINELIB_NAME_AW(IID_IDirectInput2) +#define IDirectInput2 WINELIB_NAME_AW(IDirectInput2) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT2) +#define IID_IDirectInput7 WINELIB_NAME_AW(IID_IDirectInput7) +#define IDirectInput7 WINELIB_NAME_AW(IDirectInput7) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT7) +#if DIRECTINPUT_VERSION >= 0x0800 +#define IID_IDirectInput8 WINELIB_NAME_AW(IID_IDirectInput8) +#define IDirectInput8 WINELIB_NAME_AW(IDirectInput8) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT8) +#endif /* DI8 */ +#define IID_IDirectInputDevice WINELIB_NAME_AW(IID_IDirectInputDevice) +#define IDirectInputDevice WINELIB_NAME_AW(IDirectInputDevice) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE) +#if DIRECTINPUT_VERSION >= 0x0500 +#define IID_IDirectInputDevice2 WINELIB_NAME_AW(IID_IDirectInputDevice2) +#define IDirectInputDevice2 WINELIB_NAME_AW(IDirectInputDevice2) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE2) +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x0700 +#define IID_IDirectInputDevice7 WINELIB_NAME_AW(IID_IDirectInputDevice7) +#define IDirectInputDevice7 WINELIB_NAME_AW(IDirectInputDevice7) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE7) +#endif /* DI7 */ +#if DIRECTINPUT_VERSION >= 0x0800 +#define IID_IDirectInputDevice8 WINELIB_NAME_AW(IID_IDirectInputDevice8) +#define IDirectInputDevice8 WINELIB_NAME_AW(IDirectInputDevice8) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE8) +#endif /* DI8 */ + +#define DI_OK S_OK +#define DI_NOTATTACHED S_FALSE +#define DI_BUFFEROVERFLOW S_FALSE +#define DI_PROPNOEFFECT S_FALSE +#define DI_NOEFFECT S_FALSE +#define DI_POLLEDDEVICE ((HRESULT)0x00000002L) +#define DI_DOWNLOADSKIPPED ((HRESULT)0x00000003L) +#define DI_EFFECTRESTARTED ((HRESULT)0x00000004L) +#define DI_TRUNCATED ((HRESULT)0x00000008L) +#define DI_SETTINGSNOTSAVED ((HRESULT)0x0000000BL) +#define DI_TRUNCATEDANDRESTARTED ((HRESULT)0x0000000CL) +#define DI_WRITEPROTECT ((HRESULT)0x00000013L) + +#define DIERR_OLDDIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION) +#define DIERR_BETADIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP) +#define DIERR_BADDRIVERVER \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL) +#define DIERR_DEVICENOTREG REGDB_E_CLASSNOTREG +#define DIERR_NOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) +#define DIERR_OBJECTNOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) +#define DIERR_INVALIDPARAM E_INVALIDARG +#define DIERR_NOINTERFACE E_NOINTERFACE +#define DIERR_GENERIC E_FAIL +#define DIERR_OUTOFMEMORY E_OUTOFMEMORY +#define DIERR_UNSUPPORTED E_NOTIMPL +#define DIERR_NOTINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY) +#define DIERR_ALREADYINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED) +#define DIERR_NOAGGREGATION CLASS_E_NOAGGREGATION +#define DIERR_OTHERAPPHASPRIO E_ACCESSDENIED +#define DIERR_INPUTLOST \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT) +#define DIERR_ACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY) +#define DIERR_NOTACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS) +#define DIERR_READONLY E_ACCESSDENIED +#define DIERR_HANDLEEXISTS E_ACCESSDENIED +#ifndef E_PENDING +#define E_PENDING 0x8000000AL +#endif +#define DIERR_INSUFFICIENTPRIVS 0x80040200L +#define DIERR_DEVICEFULL 0x80040201L +#define DIERR_MOREDATA 0x80040202L +#define DIERR_NOTDOWNLOADED 0x80040203L +#define DIERR_HASEFFECTS 0x80040204L +#define DIERR_NOTEXCLUSIVEACQUIRED 0x80040205L +#define DIERR_INCOMPLETEEFFECT 0x80040206L +#define DIERR_NOTBUFFERED 0x80040207L +#define DIERR_EFFECTPLAYING 0x80040208L +#define DIERR_UNPLUGGED 0x80040209L +#define DIERR_REPORTFULL 0x8004020AL +#define DIERR_MAPFILEFAIL 0x8004020BL + +#define DIENUM_STOP 0 +#define DIENUM_CONTINUE 1 + +#define DIEDFL_ALLDEVICES 0x00000000 +#define DIEDFL_ATTACHEDONLY 0x00000001 +#define DIEDFL_FORCEFEEDBACK 0x00000100 +#define DIEDFL_INCLUDEALIASES 0x00010000 +#define DIEDFL_INCLUDEPHANTOMS 0x00020000 +#define DIEDFL_INCLUDEHIDDEN 0x00040000 + +#define DIDEVTYPE_DEVICE 1 +#define DIDEVTYPE_MOUSE 2 +#define DIDEVTYPE_KEYBOARD 3 +#define DIDEVTYPE_JOYSTICK 4 +#define DIDEVTYPE_HID 0x00010000 + +#define DI8DEVCLASS_ALL 0 +#define DI8DEVCLASS_DEVICE 1 +#define DI8DEVCLASS_POINTER 2 +#define DI8DEVCLASS_KEYBOARD 3 +#define DI8DEVCLASS_GAMECTRL 4 + +#define DI8DEVTYPE_DEVICE 0x11 +#define DI8DEVTYPE_MOUSE 0x12 +#define DI8DEVTYPE_KEYBOARD 0x13 +#define DI8DEVTYPE_JOYSTICK 0x14 +#define DI8DEVTYPE_GAMEPAD 0x15 +#define DI8DEVTYPE_DRIVING 0x16 +#define DI8DEVTYPE_FLIGHT 0x17 +#define DI8DEVTYPE_1STPERSON 0x18 +#define DI8DEVTYPE_DEVICECTRL 0x19 +#define DI8DEVTYPE_SCREENPOINTER 0x1A +#define DI8DEVTYPE_REMOTE 0x1B +#define DI8DEVTYPE_SUPPLEMENTAL 0x1C + +#define DIDEVTYPEMOUSE_UNKNOWN 1 +#define DIDEVTYPEMOUSE_TRADITIONAL 2 +#define DIDEVTYPEMOUSE_FINGERSTICK 3 +#define DIDEVTYPEMOUSE_TOUCHPAD 4 +#define DIDEVTYPEMOUSE_TRACKBALL 5 + +#define DIDEVTYPEKEYBOARD_UNKNOWN 0 +#define DIDEVTYPEKEYBOARD_PCXT 1 +#define DIDEVTYPEKEYBOARD_OLIVETTI 2 +#define DIDEVTYPEKEYBOARD_PCAT 3 +#define DIDEVTYPEKEYBOARD_PCENH 4 +#define DIDEVTYPEKEYBOARD_NOKIA1050 5 +#define DIDEVTYPEKEYBOARD_NOKIA9140 6 +#define DIDEVTYPEKEYBOARD_NEC98 7 +#define DIDEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DIDEVTYPEKEYBOARD_NEC98106 9 +#define DIDEVTYPEKEYBOARD_JAPAN106 10 +#define DIDEVTYPEKEYBOARD_JAPANAX 11 +#define DIDEVTYPEKEYBOARD_J3100 12 + +#define DIDEVTYPEJOYSTICK_UNKNOWN 1 +#define DIDEVTYPEJOYSTICK_TRADITIONAL 2 +#define DIDEVTYPEJOYSTICK_FLIGHTSTICK 3 +#define DIDEVTYPEJOYSTICK_GAMEPAD 4 +#define DIDEVTYPEJOYSTICK_RUDDER 5 +#define DIDEVTYPEJOYSTICK_WHEEL 6 +#define DIDEVTYPEJOYSTICK_HEADTRACKER 7 + +#define DI8DEVTYPEMOUSE_UNKNOWN 1 +#define DI8DEVTYPEMOUSE_TRADITIONAL 2 +#define DI8DEVTYPEMOUSE_FINGERSTICK 3 +#define DI8DEVTYPEMOUSE_TOUCHPAD 4 +#define DI8DEVTYPEMOUSE_TRACKBALL 5 +#define DI8DEVTYPEMOUSE_ABSOLUTE 6 + +#define DI8DEVTYPEKEYBOARD_UNKNOWN 0 +#define DI8DEVTYPEKEYBOARD_PCXT 1 +#define DI8DEVTYPEKEYBOARD_OLIVETTI 2 +#define DI8DEVTYPEKEYBOARD_PCAT 3 +#define DI8DEVTYPEKEYBOARD_PCENH 4 +#define DI8DEVTYPEKEYBOARD_NOKIA1050 5 +#define DI8DEVTYPEKEYBOARD_NOKIA9140 6 +#define DI8DEVTYPEKEYBOARD_NEC98 7 +#define DI8DEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DI8DEVTYPEKEYBOARD_NEC98106 9 +#define DI8DEVTYPEKEYBOARD_JAPAN106 10 +#define DI8DEVTYPEKEYBOARD_JAPANAX 11 +#define DI8DEVTYPEKEYBOARD_J3100 12 + +#define DI8DEVTYPE_LIMITEDGAMESUBTYPE 1 + +#define DI8DEVTYPEJOYSTICK_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEJOYSTICK_STANDARD 2 + +#define DI8DEVTYPEGAMEPAD_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEGAMEPAD_STANDARD 2 +#define DI8DEVTYPEGAMEPAD_TILT 3 + +#define DI8DEVTYPEDRIVING_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEDRIVING_COMBINEDPEDALS 2 +#define DI8DEVTYPEDRIVING_DUALPEDALS 3 +#define DI8DEVTYPEDRIVING_THREEPEDALS 4 +#define DI8DEVTYPEDRIVING_HANDHELD 5 + +#define DI8DEVTYPEFLIGHT_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEFLIGHT_STICK 2 +#define DI8DEVTYPEFLIGHT_YOKE 3 +#define DI8DEVTYPEFLIGHT_RC 4 + +#define DI8DEVTYPE1STPERSON_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPE1STPERSON_UNKNOWN 2 +#define DI8DEVTYPE1STPERSON_SIXDOF 3 +#define DI8DEVTYPE1STPERSON_SHOOTER 4 + +#define DI8DEVTYPESCREENPTR_UNKNOWN 2 +#define DI8DEVTYPESCREENPTR_LIGHTGUN 3 +#define DI8DEVTYPESCREENPTR_LIGHTPEN 4 +#define DI8DEVTYPESCREENPTR_TOUCH 5 + +#define DI8DEVTYPEREMOTE_UNKNOWN 2 + +#define DI8DEVTYPEDEVICECTRL_UNKNOWN 2 +#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION 3 +#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED 4 + +#define DI8DEVTYPESUPPLEMENTAL_UNKNOWN 2 +#define DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER 3 +#define DI8DEVTYPESUPPLEMENTAL_HEADTRACKER 4 +#define DI8DEVTYPESUPPLEMENTAL_HANDTRACKER 5 +#define DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE 6 +#define DI8DEVTYPESUPPLEMENTAL_SHIFTER 7 +#define DI8DEVTYPESUPPLEMENTAL_THROTTLE 8 +#define DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE 9 +#define DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS 10 +#define DI8DEVTYPESUPPLEMENTAL_DUALPEDALS 11 +#define DI8DEVTYPESUPPLEMENTAL_THREEPEDALS 12 +#define DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS 13 + +#define GET_DIDEVICE_TYPE(dwDevType) LOBYTE(dwDevType) +#define GET_DIDEVICE_SUBTYPE(dwDevType) HIBYTE(dwDevType) + +typedef struct DIDEVICEOBJECTINSTANCE_DX3A { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3A, *LPDIDEVICEOBJECTINSTANCE_DX3A; +typedef const DIDEVICEOBJECTINSTANCE_DX3A *LPCDIDEVICEOBJECTINSTANCE_DX3A; +typedef struct DIDEVICEOBJECTINSTANCE_DX3W { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3W, *LPDIDEVICEOBJECTINSTANCE_DX3W; +typedef const DIDEVICEOBJECTINSTANCE_DX3W *LPCDIDEVICEOBJECTINSTANCE_DX3W; + +DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE_DX3) + +typedef struct DIDEVICEOBJECTINSTANCEA { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEA, *LPDIDEVICEOBJECTINSTANCEA; +typedef const DIDEVICEOBJECTINSTANCEA *LPCDIDEVICEOBJECTINSTANCEA; + +typedef struct DIDEVICEOBJECTINSTANCEW { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEW, *LPDIDEVICEOBJECTINSTANCEW; +typedef const DIDEVICEOBJECTINSTANCEW *LPCDIDEVICEOBJECTINSTANCEW; + +DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE) +DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE) + +typedef struct DIDEVICEINSTANCE_DX3A { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3A, *LPDIDEVICEINSTANCE_DX3A; +typedef const DIDEVICEINSTANCE_DX3A *LPCDIDEVICEINSTANCE_DX3A; +typedef struct DIDEVICEINSTANCE_DX3W { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3W, *LPDIDEVICEINSTANCE_DX3W; +typedef const DIDEVICEINSTANCE_DX3W *LPCDIDEVICEINSTANCE_DX3W; + +DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE_DX3) + +typedef struct DIDEVICEINSTANCEA { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEA, *LPDIDEVICEINSTANCEA; +typedef const DIDEVICEINSTANCEA *LPCDIDEVICEINSTANCEA; + +typedef struct DIDEVICEINSTANCEW { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEW, *LPDIDEVICEINSTANCEW; +typedef const DIDEVICEINSTANCEW *LPCDIDEVICEINSTANCEW; + +DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE) +DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE) + +typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKA)(LPCDIDEVICEINSTANCEA,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKW)(LPCDIDEVICEINSTANCEW,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESCALLBACK) + +#define DIEDBS_MAPPEDPRI1 0x00000001 +#define DIEDBS_MAPPEDPRI2 0x00000002 +#define DIEDBS_RECENTDEVICE 0x00000010 +#define DIEDBS_NEWDEVICE 0x00000020 + +#define DIEDBSFL_ATTACHEDONLY 0x00000000 +#define DIEDBSFL_THISUSER 0x00000010 +#define DIEDBSFL_FORCEFEEDBACK DIEDFL_FORCEFEEDBACK +#define DIEDBSFL_AVAILABLEDEVICES 0x00001000 +#define DIEDBSFL_MULTIMICEKEYBOARDS 0x00002000 +#define DIEDBSFL_NONGAMINGDEVICES 0x00004000 +#define DIEDBSFL_VALID 0x00007110 + +#if DIRECTINPUT_VERSION >= 0x0800 +typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBA)(LPCDIDEVICEINSTANCEA,LPDIRECTINPUTDEVICE8A,DWORD,DWORD,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBW)(LPCDIDEVICEINSTANCEW,LPDIRECTINPUTDEVICE8W,DWORD,DWORD,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESBYSEMANTICSCB) +#endif + +typedef BOOL (CALLBACK *LPDICONFIGUREDEVICESCALLBACK)(LPUNKNOWN,LPVOID); + +typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKA)(LPCDIDEVICEOBJECTINSTANCEA,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKW)(LPCDIDEVICEOBJECTINSTANCEW,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICEOBJECTSCALLBACK) + +#if DIRECTINPUT_VERSION >= 0x0500 +typedef BOOL (CALLBACK *LPDIENUMCREATEDEFFECTOBJECTSCALLBACK)(LPDIRECTINPUTEFFECT, LPVOID); +#endif + +#define DIK_ESCAPE 0x01 +#define DIK_1 0x02 +#define DIK_2 0x03 +#define DIK_3 0x04 +#define DIK_4 0x05 +#define DIK_5 0x06 +#define DIK_6 0x07 +#define DIK_7 0x08 +#define DIK_8 0x09 +#define DIK_9 0x0A +#define DIK_0 0x0B +#define DIK_MINUS 0x0C /* - on main keyboard */ +#define DIK_EQUALS 0x0D +#define DIK_BACK 0x0E /* backspace */ +#define DIK_TAB 0x0F +#define DIK_Q 0x10 +#define DIK_W 0x11 +#define DIK_E 0x12 +#define DIK_R 0x13 +#define DIK_T 0x14 +#define DIK_Y 0x15 +#define DIK_U 0x16 +#define DIK_I 0x17 +#define DIK_O 0x18 +#define DIK_P 0x19 +#define DIK_LBRACKET 0x1A +#define DIK_RBRACKET 0x1B +#define DIK_RETURN 0x1C /* Enter on main keyboard */ +#define DIK_LCONTROL 0x1D +#define DIK_A 0x1E +#define DIK_S 0x1F +#define DIK_D 0x20 +#define DIK_F 0x21 +#define DIK_G 0x22 +#define DIK_H 0x23 +#define DIK_J 0x24 +#define DIK_K 0x25 +#define DIK_L 0x26 +#define DIK_SEMICOLON 0x27 +#define DIK_APOSTROPHE 0x28 +#define DIK_GRAVE 0x29 /* accent grave */ +#define DIK_LSHIFT 0x2A +#define DIK_BACKSLASH 0x2B +#define DIK_Z 0x2C +#define DIK_X 0x2D +#define DIK_C 0x2E +#define DIK_V 0x2F +#define DIK_B 0x30 +#define DIK_N 0x31 +#define DIK_M 0x32 +#define DIK_COMMA 0x33 +#define DIK_PERIOD 0x34 /* . on main keyboard */ +#define DIK_SLASH 0x35 /* / on main keyboard */ +#define DIK_RSHIFT 0x36 +#define DIK_MULTIPLY 0x37 /* * on numeric keypad */ +#define DIK_LMENU 0x38 /* left Alt */ +#define DIK_SPACE 0x39 +#define DIK_CAPITAL 0x3A +#define DIK_F1 0x3B +#define DIK_F2 0x3C +#define DIK_F3 0x3D +#define DIK_F4 0x3E +#define DIK_F5 0x3F +#define DIK_F6 0x40 +#define DIK_F7 0x41 +#define DIK_F8 0x42 +#define DIK_F9 0x43 +#define DIK_F10 0x44 +#define DIK_NUMLOCK 0x45 +#define DIK_SCROLL 0x46 /* Scroll Lock */ +#define DIK_NUMPAD7 0x47 +#define DIK_NUMPAD8 0x48 +#define DIK_NUMPAD9 0x49 +#define DIK_SUBTRACT 0x4A /* - on numeric keypad */ +#define DIK_NUMPAD4 0x4B +#define DIK_NUMPAD5 0x4C +#define DIK_NUMPAD6 0x4D +#define DIK_ADD 0x4E /* + on numeric keypad */ +#define DIK_NUMPAD1 0x4F +#define DIK_NUMPAD2 0x50 +#define DIK_NUMPAD3 0x51 +#define DIK_NUMPAD0 0x52 +#define DIK_DECIMAL 0x53 /* . on numeric keypad */ +#define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */ +#define DIK_F11 0x57 +#define DIK_F12 0x58 +#define DIK_F13 0x64 /* (NEC PC98) */ +#define DIK_F14 0x65 /* (NEC PC98) */ +#define DIK_F15 0x66 /* (NEC PC98) */ +#define DIK_KANA 0x70 /* (Japanese keyboard) */ +#define DIK_ABNT_C1 0x73 /* / ? on Portugese (Brazilian) keyboards */ +#define DIK_CONVERT 0x79 /* (Japanese keyboard) */ +#define DIK_NOCONVERT 0x7B /* (Japanese keyboard) */ +#define DIK_YEN 0x7D /* (Japanese keyboard) */ +#define DIK_ABNT_C2 0x7E /* Numpad . on Portugese (Brazilian) keyboards */ +#define DIK_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */ +#define DIK_CIRCUMFLEX 0x90 /* (Japanese keyboard) */ +#define DIK_AT 0x91 /* (NEC PC98) */ +#define DIK_COLON 0x92 /* (NEC PC98) */ +#define DIK_UNDERLINE 0x93 /* (NEC PC98) */ +#define DIK_KANJI 0x94 /* (Japanese keyboard) */ +#define DIK_STOP 0x95 /* (NEC PC98) */ +#define DIK_AX 0x96 /* (Japan AX) */ +#define DIK_UNLABELED 0x97 /* (J3100) */ +#define DIK_NEXTTRACK 0x99 /* Next Track */ +#define DIK_NUMPADENTER 0x9C /* Enter on numeric keypad */ +#define DIK_RCONTROL 0x9D +#define DIK_MUTE 0xA0 /* Mute */ +#define DIK_CALCULATOR 0xA1 /* Calculator */ +#define DIK_PLAYPAUSE 0xA2 /* Play / Pause */ +#define DIK_MEDIASTOP 0xA4 /* Media Stop */ +#define DIK_VOLUMEDOWN 0xAE /* Volume - */ +#define DIK_VOLUMEUP 0xB0 /* Volume + */ +#define DIK_WEBHOME 0xB2 /* Web home */ +#define DIK_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */ +#define DIK_DIVIDE 0xB5 /* / on numeric keypad */ +#define DIK_SYSRQ 0xB7 +#define DIK_RMENU 0xB8 /* right Alt */ +#define DIK_PAUSE 0xC5 /* Pause */ +#define DIK_HOME 0xC7 /* Home on arrow keypad */ +#define DIK_UP 0xC8 /* UpArrow on arrow keypad */ +#define DIK_PRIOR 0xC9 /* PgUp on arrow keypad */ +#define DIK_LEFT 0xCB /* LeftArrow on arrow keypad */ +#define DIK_RIGHT 0xCD /* RightArrow on arrow keypad */ +#define DIK_END 0xCF /* End on arrow keypad */ +#define DIK_DOWN 0xD0 /* DownArrow on arrow keypad */ +#define DIK_NEXT 0xD1 /* PgDn on arrow keypad */ +#define DIK_INSERT 0xD2 /* Insert on arrow keypad */ +#define DIK_DELETE 0xD3 /* Delete on arrow keypad */ +#define DIK_LWIN 0xDB /* Left Windows key */ +#define DIK_RWIN 0xDC /* Right Windows key */ +#define DIK_APPS 0xDD /* AppMenu key */ +#define DIK_POWER 0xDE +#define DIK_SLEEP 0xDF +#define DIK_WAKE 0xE3 /* System Wake */ +#define DIK_WEBSEARCH 0xE5 /* Web Search */ +#define DIK_WEBFAVORITES 0xE6 /* Web Favorites */ +#define DIK_WEBREFRESH 0xE7 /* Web Refresh */ +#define DIK_WEBSTOP 0xE8 /* Web Stop */ +#define DIK_WEBFORWARD 0xE9 /* Web Forward */ +#define DIK_WEBBACK 0xEA /* Web Back */ +#define DIK_MYCOMPUTER 0xEB /* My Computer */ +#define DIK_MAIL 0xEC /* Mail */ +#define DIK_MEDIASELECT 0xED /* Media Select */ + +#define DIK_BACKSPACE DIK_BACK /* backspace */ +#define DIK_NUMPADSTAR DIK_MULTIPLY /* * on numeric keypad */ +#define DIK_LALT DIK_LMENU /* left Alt */ +#define DIK_CAPSLOCK DIK_CAPITAL /* CapsLock */ +#define DIK_NUMPADMINUS DIK_SUBTRACT /* - on numeric keypad */ +#define DIK_NUMPADPLUS DIK_ADD /* + on numeric keypad */ +#define DIK_NUMPADPERIOD DIK_DECIMAL /* . on numeric keypad */ +#define DIK_NUMPADSLASH DIK_DIVIDE /* / on numeric keypad */ +#define DIK_RALT DIK_RMENU /* right Alt */ +#define DIK_UPARROW DIK_UP /* UpArrow on arrow keypad */ +#define DIK_PGUP DIK_PRIOR /* PgUp on arrow keypad */ +#define DIK_LEFTARROW DIK_LEFT /* LeftArrow on arrow keypad */ +#define DIK_RIGHTARROW DIK_RIGHT /* RightArrow on arrow keypad */ +#define DIK_DOWNARROW DIK_DOWN /* DownArrow on arrow keypad */ +#define DIK_PGDN DIK_NEXT /* PgDn on arrow keypad */ + +#define DIDFT_ALL 0x00000000 +#define DIDFT_RELAXIS 0x00000001 +#define DIDFT_ABSAXIS 0x00000002 +#define DIDFT_AXIS 0x00000003 +#define DIDFT_PSHBUTTON 0x00000004 +#define DIDFT_TGLBUTTON 0x00000008 +#define DIDFT_BUTTON 0x0000000C +#define DIDFT_POV 0x00000010 +#define DIDFT_COLLECTION 0x00000040 +#define DIDFT_NODATA 0x00000080 +#define DIDFT_ANYINSTANCE 0x00FFFF00 +#define DIDFT_INSTANCEMASK DIDFT_ANYINSTANCE +#define DIDFT_MAKEINSTANCE(n) ((WORD)(n) << 8) +#define DIDFT_GETTYPE(n) LOBYTE(n) +#define DIDFT_GETINSTANCE(n) LOWORD((n) >> 8) +#define DIDFT_FFACTUATOR 0x01000000 +#define DIDFT_FFEFFECTTRIGGER 0x02000000 +#if DIRECTINPUT_VERSION >= 0x050a +#define DIDFT_OUTPUT 0x10000000 +#define DIDFT_VENDORDEFINED 0x04000000 +#define DIDFT_ALIAS 0x08000000 +#endif /* DI5a */ +#ifndef DIDFT_OPTIONAL +#define DIDFT_OPTIONAL 0x80000000 +#endif +#define DIDFT_ENUMCOLLECTION(n) ((WORD)(n) << 8) +#define DIDFT_NOCOLLECTION 0x00FFFF00 + +#define DIDF_ABSAXIS 0x00000001 +#define DIDF_RELAXIS 0x00000002 + +#define DIGDD_PEEK 0x00000001 + +#define DISEQUENCE_COMPARE(dwSq1,cmp,dwSq2) ((int)((dwSq1) - (dwSq2)) cmp 0) + +typedef struct DIDEVICEOBJECTDATA_DX3 { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +} DIDEVICEOBJECTDATA_DX3,*LPDIDEVICEOBJECTDATA_DX3; +typedef const DIDEVICEOBJECTDATA_DX3 *LPCDIDEVICEOBJECTDATA_DX3; + +typedef struct DIDEVICEOBJECTDATA { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +#if(DIRECTINPUT_VERSION >= 0x0800) + UINT_PTR uAppData; +#endif /* DIRECTINPUT_VERSION >= 0x0800 */ +} DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA; +typedef const DIDEVICEOBJECTDATA *LPCDIDEVICEOBJECTDATA; + +typedef struct _DIOBJECTDATAFORMAT { + const GUID *pguid; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; +} DIOBJECTDATAFORMAT, *LPDIOBJECTDATAFORMAT; +typedef const DIOBJECTDATAFORMAT *LPCDIOBJECTDATAFORMAT; + +typedef struct _DIDATAFORMAT { + DWORD dwSize; + DWORD dwObjSize; + DWORD dwFlags; + DWORD dwDataSize; + DWORD dwNumObjs; + LPDIOBJECTDATAFORMAT rgodf; +} DIDATAFORMAT, *LPDIDATAFORMAT; +typedef const DIDATAFORMAT *LPCDIDATAFORMAT; + +#if DIRECTINPUT_VERSION >= 0x0500 +#define DIDOI_FFACTUATOR 0x00000001 +#define DIDOI_FFEFFECTTRIGGER 0x00000002 +#define DIDOI_POLLED 0x00008000 +#define DIDOI_ASPECTPOSITION 0x00000100 +#define DIDOI_ASPECTVELOCITY 0x00000200 +#define DIDOI_ASPECTACCEL 0x00000300 +#define DIDOI_ASPECTFORCE 0x00000400 +#define DIDOI_ASPECTMASK 0x00000F00 +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x050a +#define DIDOI_GUIDISUSAGE 0x00010000 +#endif /* DI5a */ + +typedef struct DIPROPHEADER { + DWORD dwSize; + DWORD dwHeaderSize; + DWORD dwObj; + DWORD dwHow; +} DIPROPHEADER,*LPDIPROPHEADER; +typedef const DIPROPHEADER *LPCDIPROPHEADER; + +#define DIPH_DEVICE 0 +#define DIPH_BYOFFSET 1 +#define DIPH_BYID 2 +#if DIRECTINPUT_VERSION >= 0x050a +#define DIPH_BYUSAGE 3 + +#define DIMAKEUSAGEDWORD(UsagePage, Usage) (DWORD)MAKELONG(Usage, UsagePage) +#endif /* DI5a */ + +typedef struct DIPROPDWORD { + DIPROPHEADER diph; + DWORD dwData; +} DIPROPDWORD, *LPDIPROPDWORD; +typedef const DIPROPDWORD *LPCDIPROPDWORD; + +typedef struct DIPROPRANGE { + DIPROPHEADER diph; + LONG lMin; + LONG lMax; +} DIPROPRANGE, *LPDIPROPRANGE; +typedef const DIPROPRANGE *LPCDIPROPRANGE; + +#define DIPROPRANGE_NOMIN ((LONG)0x80000000) +#define DIPROPRANGE_NOMAX ((LONG)0x7FFFFFFF) + +#if DIRECTINPUT_VERSION >= 0x050a +typedef struct DIPROPCAL { + DIPROPHEADER diph; + LONG lMin; + LONG lCenter; + LONG lMax; +} DIPROPCAL, *LPDIPROPCAL; +typedef const DIPROPCAL *LPCDIPROPCAL; + +typedef struct DIPROPCALPOV { + DIPROPHEADER diph; + LONG lMin[5]; + LONG lMax[5]; +} DIPROPCALPOV, *LPDIPROPCALPOV; +typedef const DIPROPCALPOV *LPCDIPROPCALPOV; + +typedef struct DIPROPGUIDANDPATH { + DIPROPHEADER diph; + GUID guidClass; + WCHAR wszPath[MAX_PATH]; +} DIPROPGUIDANDPATH, *LPDIPROPGUIDANDPATH; +typedef const DIPROPGUIDANDPATH *LPCDIPROPGUIDANDPATH; + +typedef struct DIPROPSTRING { + DIPROPHEADER diph; + WCHAR wsz[MAX_PATH]; +} DIPROPSTRING, *LPDIPROPSTRING; +typedef const DIPROPSTRING *LPCDIPROPSTRING; +#endif /* DI5a */ + +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct DIPROPPOINTER { + DIPROPHEADER diph; + UINT_PTR uData; +} DIPROPPOINTER, *LPDIPROPPOINTER; +typedef const DIPROPPOINTER *LPCDIPROPPOINTER; +#endif /* DI8 */ + +/* special property GUIDs */ +#ifdef __cplusplus +#define MAKEDIPROP(prop) (*(const GUID *)(prop)) +#else +#define MAKEDIPROP(prop) ((REFGUID)(prop)) +#endif +#define DIPROP_BUFFERSIZE MAKEDIPROP(1) +#define DIPROP_AXISMODE MAKEDIPROP(2) + +#define DIPROPAXISMODE_ABS 0 +#define DIPROPAXISMODE_REL 1 + +#define DIPROP_GRANULARITY MAKEDIPROP(3) +#define DIPROP_RANGE MAKEDIPROP(4) +#define DIPROP_DEADZONE MAKEDIPROP(5) +#define DIPROP_SATURATION MAKEDIPROP(6) +#define DIPROP_FFGAIN MAKEDIPROP(7) +#define DIPROP_FFLOAD MAKEDIPROP(8) +#define DIPROP_AUTOCENTER MAKEDIPROP(9) + +#define DIPROPAUTOCENTER_OFF 0 +#define DIPROPAUTOCENTER_ON 1 + +#define DIPROP_CALIBRATIONMODE MAKEDIPROP(10) + +#define DIPROPCALIBRATIONMODE_COOKED 0 +#define DIPROPCALIBRATIONMODE_RAW 1 + +#if DIRECTINPUT_VERSION >= 0x050a +#define DIPROP_CALIBRATION MAKEDIPROP(11) +#define DIPROP_GUIDANDPATH MAKEDIPROP(12) +#define DIPROP_INSTANCENAME MAKEDIPROP(13) +#define DIPROP_PRODUCTNAME MAKEDIPROP(14) +#endif + +#if DIRECTINPUT_VERSION >= 0x5B2 +#define DIPROP_JOYSTICKID MAKEDIPROP(15) +#define DIPROP_GETPORTDISPLAYNAME MAKEDIPROP(16) +#endif + +#if DIRECTINPUT_VERSION >= 0x0700 +#define DIPROP_PHYSICALRANGE MAKEDIPROP(18) +#define DIPROP_LOGICALRANGE MAKEDIPROP(19) +#endif + +#if(DIRECTINPUT_VERSION >= 0x0800) +#define DIPROP_KEYNAME MAKEDIPROP(20) +#define DIPROP_CPOINTS MAKEDIPROP(21) +#define DIPROP_APPDATA MAKEDIPROP(22) +#define DIPROP_SCANCODE MAKEDIPROP(23) +#define DIPROP_VIDPID MAKEDIPROP(24) +#define DIPROP_USERNAME MAKEDIPROP(25) +#define DIPROP_TYPENAME MAKEDIPROP(26) + +#define MAXCPOINTSNUM 8 + +typedef struct _CPOINT { + LONG lP; + DWORD dwLog; +} CPOINT, *PCPOINT; + +typedef struct DIPROPCPOINTS { + DIPROPHEADER diph; + DWORD dwCPointsNum; + CPOINT cp[MAXCPOINTSNUM]; +} DIPROPCPOINTS, *LPDIPROPCPOINTS; +typedef const DIPROPCPOINTS *LPCDIPROPCPOINTS; +#endif /* DI8 */ + + +typedef struct DIDEVCAPS_DX3 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +} DIDEVCAPS_DX3, *LPDIDEVCAPS_DX3; + +typedef struct DIDEVCAPS { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFSamplePeriod; + DWORD dwFFMinTimeResolution; + DWORD dwFirmwareRevision; + DWORD dwHardwareRevision; + DWORD dwFFDriverVersion; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVCAPS,*LPDIDEVCAPS; + +#define DIDC_ATTACHED 0x00000001 +#define DIDC_POLLEDDEVICE 0x00000002 +#define DIDC_EMULATED 0x00000004 +#define DIDC_POLLEDDATAFORMAT 0x00000008 +#define DIDC_FORCEFEEDBACK 0x00000100 +#define DIDC_FFATTACK 0x00000200 +#define DIDC_FFFADE 0x00000400 +#define DIDC_SATURATION 0x00000800 +#define DIDC_POSNEGCOEFFICIENTS 0x00001000 +#define DIDC_POSNEGSATURATION 0x00002000 +#define DIDC_DEADBAND 0x00004000 +#define DIDC_STARTDELAY 0x00008000 +#define DIDC_ALIAS 0x00010000 +#define DIDC_PHANTOM 0x00020000 +#define DIDC_HIDDEN 0x00040000 + + +/* SetCooperativeLevel dwFlags */ +#define DISCL_EXCLUSIVE 0x00000001 +#define DISCL_NONEXCLUSIVE 0x00000002 +#define DISCL_FOREGROUND 0x00000004 +#define DISCL_BACKGROUND 0x00000008 +#define DISCL_NOWINKEY 0x00000010 + +#if (DIRECTINPUT_VERSION >= 0x0500) +/* Device FF flags */ +#define DISFFC_RESET 0x00000001 +#define DISFFC_STOPALL 0x00000002 +#define DISFFC_PAUSE 0x00000004 +#define DISFFC_CONTINUE 0x00000008 +#define DISFFC_SETACTUATORSON 0x00000010 +#define DISFFC_SETACTUATORSOFF 0x00000020 + +#define DIGFFS_EMPTY 0x00000001 +#define DIGFFS_STOPPED 0x00000002 +#define DIGFFS_PAUSED 0x00000004 +#define DIGFFS_ACTUATORSON 0x00000010 +#define DIGFFS_ACTUATORSOFF 0x00000020 +#define DIGFFS_POWERON 0x00000040 +#define DIGFFS_POWEROFF 0x00000080 +#define DIGFFS_SAFETYSWITCHON 0x00000100 +#define DIGFFS_SAFETYSWITCHOFF 0x00000200 +#define DIGFFS_USERFFSWITCHON 0x00000400 +#define DIGFFS_USERFFSWITCHOFF 0x00000800 +#define DIGFFS_DEVICELOST 0x80000000 + +/* Effect flags */ +#define DIEFT_ALL 0x00000000 + +#define DIEFT_CONSTANTFORCE 0x00000001 +#define DIEFT_RAMPFORCE 0x00000002 +#define DIEFT_PERIODIC 0x00000003 +#define DIEFT_CONDITION 0x00000004 +#define DIEFT_CUSTOMFORCE 0x00000005 +#define DIEFT_HARDWARE 0x000000FF +#define DIEFT_FFATTACK 0x00000200 +#define DIEFT_FFFADE 0x00000400 +#define DIEFT_SATURATION 0x00000800 +#define DIEFT_POSNEGCOEFFICIENTS 0x00001000 +#define DIEFT_POSNEGSATURATION 0x00002000 +#define DIEFT_DEADBAND 0x00004000 +#define DIEFT_STARTDELAY 0x00008000 +#define DIEFT_GETTYPE(n) LOBYTE(n) + +#define DIEFF_OBJECTIDS 0x00000001 +#define DIEFF_OBJECTOFFSETS 0x00000002 +#define DIEFF_CARTESIAN 0x00000010 +#define DIEFF_POLAR 0x00000020 +#define DIEFF_SPHERICAL 0x00000040 + +#define DIEP_DURATION 0x00000001 +#define DIEP_SAMPLEPERIOD 0x00000002 +#define DIEP_GAIN 0x00000004 +#define DIEP_TRIGGERBUTTON 0x00000008 +#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 +#define DIEP_AXES 0x00000020 +#define DIEP_DIRECTION 0x00000040 +#define DIEP_ENVELOPE 0x00000080 +#define DIEP_TYPESPECIFICPARAMS 0x00000100 +#if(DIRECTINPUT_VERSION >= 0x0600) +#define DIEP_STARTDELAY 0x00000200 +#define DIEP_ALLPARAMS_DX5 0x000001FF +#define DIEP_ALLPARAMS 0x000003FF +#else +#define DIEP_ALLPARAMS 0x000001FF +#endif /* DIRECTINPUT_VERSION >= 0x0600 */ +#define DIEP_START 0x20000000 +#define DIEP_NORESTART 0x40000000 +#define DIEP_NODOWNLOAD 0x80000000 +#define DIEB_NOTRIGGER 0xFFFFFFFF + +#define DIES_SOLO 0x00000001 +#define DIES_NODOWNLOAD 0x80000000 + +#define DIEGES_PLAYING 0x00000001 +#define DIEGES_EMULATED 0x00000002 + +#define DI_DEGREES 100 +#define DI_FFNOMINALMAX 10000 +#define DI_SECONDS 1000000 + +typedef struct DICONSTANTFORCE { + LONG lMagnitude; +} DICONSTANTFORCE, *LPDICONSTANTFORCE; +typedef const DICONSTANTFORCE *LPCDICONSTANTFORCE; + +typedef struct DIRAMPFORCE { + LONG lStart; + LONG lEnd; +} DIRAMPFORCE, *LPDIRAMPFORCE; +typedef const DIRAMPFORCE *LPCDIRAMPFORCE; + +typedef struct DIPERIODIC { + DWORD dwMagnitude; + LONG lOffset; + DWORD dwPhase; + DWORD dwPeriod; +} DIPERIODIC, *LPDIPERIODIC; +typedef const DIPERIODIC *LPCDIPERIODIC; + +typedef struct DICONDITION { + LONG lOffset; + LONG lPositiveCoefficient; + LONG lNegativeCoefficient; + DWORD dwPositiveSaturation; + DWORD dwNegativeSaturation; + LONG lDeadBand; +} DICONDITION, *LPDICONDITION; +typedef const DICONDITION *LPCDICONDITION; + +typedef struct DICUSTOMFORCE { + DWORD cChannels; + DWORD dwSamplePeriod; + DWORD cSamples; + LPLONG rglForceData; +} DICUSTOMFORCE, *LPDICUSTOMFORCE; +typedef const DICUSTOMFORCE *LPCDICUSTOMFORCE; + +typedef struct DIENVELOPE { + DWORD dwSize; + DWORD dwAttackLevel; + DWORD dwAttackTime; + DWORD dwFadeLevel; + DWORD dwFadeTime; +} DIENVELOPE, *LPDIENVELOPE; +typedef const DIENVELOPE *LPCDIENVELOPE; + +typedef struct DIEFFECT_DX5 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +} DIEFFECT_DX5, *LPDIEFFECT_DX5; +typedef const DIEFFECT_DX5 *LPCDIEFFECT_DX5; + +typedef struct DIEFFECT { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +#if(DIRECTINPUT_VERSION >= 0x0600) + DWORD dwStartDelay; +#endif /* DIRECTINPUT_VERSION >= 0x0600 */ +} DIEFFECT, *LPDIEFFECT; +typedef const DIEFFECT *LPCDIEFFECT; +typedef DIEFFECT DIEFFECT_DX6; +typedef LPDIEFFECT LPDIEFFECT_DX6; + +typedef struct DIEFFECTINFOA { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + CHAR tszName[MAX_PATH]; +} DIEFFECTINFOA, *LPDIEFFECTINFOA; +typedef const DIEFFECTINFOA *LPCDIEFFECTINFOA; + +typedef struct DIEFFECTINFOW { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + WCHAR tszName[MAX_PATH]; +} DIEFFECTINFOW, *LPDIEFFECTINFOW; +typedef const DIEFFECTINFOW *LPCDIEFFECTINFOW; + +DECL_WINELIB_TYPE_AW(DIEFFECTINFO) +DECL_WINELIB_TYPE_AW(LPDIEFFECTINFO) +DECL_WINELIB_TYPE_AW(LPCDIEFFECTINFO) + +typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKA)(LPCDIEFFECTINFOA, LPVOID); +typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKW)(LPCDIEFFECTINFOW, LPVOID); + +typedef struct DIEFFESCAPE { + DWORD dwSize; + DWORD dwCommand; + LPVOID lpvInBuffer; + DWORD cbInBuffer; + LPVOID lpvOutBuffer; + DWORD cbOutBuffer; +} DIEFFESCAPE, *LPDIEFFESCAPE; + +typedef struct DIJOYSTATE { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG rglSlider[2]; + DWORD rgdwPOV[4]; + BYTE rgbButtons[32]; +} DIJOYSTATE, *LPDIJOYSTATE; + +typedef struct DIJOYSTATE2 { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG rglSlider[2]; + DWORD rgdwPOV[4]; + BYTE rgbButtons[128]; + LONG lVX; /* 'v' as in velocity */ + LONG lVY; + LONG lVZ; + LONG lVRx; + LONG lVRy; + LONG lVRz; + LONG rglVSlider[2]; + LONG lAX; /* 'a' as in acceleration */ + LONG lAY; + LONG lAZ; + LONG lARx; + LONG lARy; + LONG lARz; + LONG rglASlider[2]; + LONG lFX; /* 'f' as in force */ + LONG lFY; + LONG lFZ; + LONG lFRx; /* 'fr' as in rotational force aka torque */ + LONG lFRy; + LONG lFRz; + LONG rglFSlider[2]; +} DIJOYSTATE2, *LPDIJOYSTATE2; + +#define DIJOFS_X FIELD_OFFSET(DIJOYSTATE, lX) +#define DIJOFS_Y FIELD_OFFSET(DIJOYSTATE, lY) +#define DIJOFS_Z FIELD_OFFSET(DIJOYSTATE, lZ) +#define DIJOFS_RX FIELD_OFFSET(DIJOYSTATE, lRx) +#define DIJOFS_RY FIELD_OFFSET(DIJOYSTATE, lRy) +#define DIJOFS_RZ FIELD_OFFSET(DIJOYSTATE, lRz) +#define DIJOFS_SLIDER(n) (FIELD_OFFSET(DIJOYSTATE, rglSlider) + \ + (n) * sizeof(LONG)) +#define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE, rgdwPOV) + \ + (n) * sizeof(DWORD)) +#define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE, rgbButtons) + (n)) +#define DIJOFS_BUTTON0 DIJOFS_BUTTON(0) +#define DIJOFS_BUTTON1 DIJOFS_BUTTON(1) +#define DIJOFS_BUTTON2 DIJOFS_BUTTON(2) +#define DIJOFS_BUTTON3 DIJOFS_BUTTON(3) +#define DIJOFS_BUTTON4 DIJOFS_BUTTON(4) +#define DIJOFS_BUTTON5 DIJOFS_BUTTON(5) +#define DIJOFS_BUTTON6 DIJOFS_BUTTON(6) +#define DIJOFS_BUTTON7 DIJOFS_BUTTON(7) +#define DIJOFS_BUTTON8 DIJOFS_BUTTON(8) +#define DIJOFS_BUTTON9 DIJOFS_BUTTON(9) +#define DIJOFS_BUTTON10 DIJOFS_BUTTON(10) +#define DIJOFS_BUTTON11 DIJOFS_BUTTON(11) +#define DIJOFS_BUTTON12 DIJOFS_BUTTON(12) +#define DIJOFS_BUTTON13 DIJOFS_BUTTON(13) +#define DIJOFS_BUTTON14 DIJOFS_BUTTON(14) +#define DIJOFS_BUTTON15 DIJOFS_BUTTON(15) +#define DIJOFS_BUTTON16 DIJOFS_BUTTON(16) +#define DIJOFS_BUTTON17 DIJOFS_BUTTON(17) +#define DIJOFS_BUTTON18 DIJOFS_BUTTON(18) +#define DIJOFS_BUTTON19 DIJOFS_BUTTON(19) +#define DIJOFS_BUTTON20 DIJOFS_BUTTON(20) +#define DIJOFS_BUTTON21 DIJOFS_BUTTON(21) +#define DIJOFS_BUTTON22 DIJOFS_BUTTON(22) +#define DIJOFS_BUTTON23 DIJOFS_BUTTON(23) +#define DIJOFS_BUTTON24 DIJOFS_BUTTON(24) +#define DIJOFS_BUTTON25 DIJOFS_BUTTON(25) +#define DIJOFS_BUTTON26 DIJOFS_BUTTON(26) +#define DIJOFS_BUTTON27 DIJOFS_BUTTON(27) +#define DIJOFS_BUTTON28 DIJOFS_BUTTON(28) +#define DIJOFS_BUTTON29 DIJOFS_BUTTON(29) +#define DIJOFS_BUTTON30 DIJOFS_BUTTON(30) +#define DIJOFS_BUTTON31 DIJOFS_BUTTON(31) +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +/* DInput 7 structures, types */ +#if(DIRECTINPUT_VERSION >= 0x0700) +typedef struct DIFILEEFFECT { + DWORD dwSize; + GUID GuidEffect; + LPCDIEFFECT lpDiEffect; + CHAR szFriendlyName[MAX_PATH]; +} DIFILEEFFECT, *LPDIFILEEFFECT; + +typedef const DIFILEEFFECT *LPCDIFILEEFFECT; +typedef BOOL (CALLBACK *LPDIENUMEFFECTSINFILECALLBACK)(LPCDIFILEEFFECT , LPVOID); +#endif /* DIRECTINPUT_VERSION >= 0x0700 */ + +/* DInput 8 structures and types */ +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct _DIACTIONA { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + __GNU_EXTENSION union { + LPCSTR lptszActionName; + UINT uResIdString; + } DUMMYUNIONNAME; + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} DIACTIONA, *LPDIACTIONA; +typedef const DIACTIONA *LPCDIACTIONA; + +typedef struct _DIACTIONW { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + __GNU_EXTENSION union { + LPCWSTR lptszActionName; + UINT uResIdString; + } DUMMYUNIONNAME; + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} DIACTIONW, *LPDIACTIONW; +typedef const DIACTIONW *LPCDIACTIONW; + +DECL_WINELIB_TYPE_AW(DIACTION) +DECL_WINELIB_TYPE_AW(LPDIACTION) +DECL_WINELIB_TYPE_AW(LPCDIACTION) + +#define DIA_FORCEFEEDBACK 0x00000001 +#define DIA_APPMAPPED 0x00000002 +#define DIA_APPNOMAP 0x00000004 +#define DIA_NORANGE 0x00000008 +#define DIA_APPFIXED 0x00000010 + +#define DIAH_UNMAPPED 0x00000000 +#define DIAH_USERCONFIG 0x00000001 +#define DIAH_APPREQUESTED 0x00000002 +#define DIAH_HWAPP 0x00000004 +#define DIAH_HWDEFAULT 0x00000008 +#define DIAH_DEFAULT 0x00000020 +#define DIAH_ERROR 0x80000000 + +typedef struct _DIACTIONFORMATA { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONA rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + CHAR tszActionMap[MAX_PATH]; +} DIACTIONFORMATA, *LPDIACTIONFORMATA; +typedef const DIACTIONFORMATA *LPCDIACTIONFORMATA; + +typedef struct _DIACTIONFORMATW { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONW rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + WCHAR tszActionMap[MAX_PATH]; +} DIACTIONFORMATW, *LPDIACTIONFORMATW; +typedef const DIACTIONFORMATW *LPCDIACTIONFORMATW; + +DECL_WINELIB_TYPE_AW(DIACTIONFORMAT) +DECL_WINELIB_TYPE_AW(LPDIACTIONFORMAT) +DECL_WINELIB_TYPE_AW(LPCDIACTIONFORMAT) + +#define DIAFTS_NEWDEVICELOW 0xFFFFFFFF +#define DIAFTS_NEWDEVICEHIGH 0xFFFFFFFF +#define DIAFTS_UNUSEDDEVICELOW 0x00000000 +#define DIAFTS_UNUSEDDEVICEHIGH 0x00000000 + +#define DIDBAM_DEFAULT 0x00000000 +#define DIDBAM_PRESERVE 0x00000001 +#define DIDBAM_INITIALIZE 0x00000002 +#define DIDBAM_HWDEFAULTS 0x00000004 + +#define DIDSAM_DEFAULT 0x00000000 +#define DIDSAM_NOUSER 0x00000001 +#define DIDSAM_FORCESAVE 0x00000002 + +#define DICD_DEFAULT 0x00000000 +#define DICD_EDIT 0x00000001 + +#ifndef D3DCOLOR_DEFINED +typedef DWORD D3DCOLOR; +#define D3DCOLOR_DEFINED +#endif + +typedef struct _DICOLORSET { + DWORD dwSize; + D3DCOLOR cTextFore; + D3DCOLOR cTextHighlight; + D3DCOLOR cCalloutLine; + D3DCOLOR cCalloutHighlight; + D3DCOLOR cBorder; + D3DCOLOR cControlFill; + D3DCOLOR cHighlightFill; + D3DCOLOR cAreaFill; +} DICOLORSET, *LPDICOLORSET; +typedef const DICOLORSET *LPCDICOLORSET; + +typedef struct _DICONFIGUREDEVICESPARAMSA { + DWORD dwSize; + DWORD dwcUsers; + LPSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATA lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} DICONFIGUREDEVICESPARAMSA, *LPDICONFIGUREDEVICESPARAMSA; +typedef const DICONFIGUREDEVICESPARAMSA *LPCDICONFIGUREDEVICESPARAMSA; + +typedef struct _DICONFIGUREDEVICESPARAMSW { + DWORD dwSize; + DWORD dwcUsers; + LPWSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATW lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} DICONFIGUREDEVICESPARAMSW, *LPDICONFIGUREDEVICESPARAMSW; +typedef const DICONFIGUREDEVICESPARAMSW *LPCDICONFIGUREDEVICESPARAMSW; + +DECL_WINELIB_TYPE_AW(DICONFIGUREDEVICESPARAMS) +DECL_WINELIB_TYPE_AW(LPDICONFIGUREDEVICESPARAMS) +DECL_WINELIB_TYPE_AW(LPCDICONFIGUREDEVICESPARAMS) + +#define DIDIFT_CONFIGURATION 0x00000001 +#define DIDIFT_OVERLAY 0x00000002 + +#define DIDAL_CENTERED 0x00000000 +#define DIDAL_LEFTALIGNED 0x00000001 +#define DIDAL_RIGHTALIGNED 0x00000002 +#define DIDAL_MIDDLE 0x00000000 +#define DIDAL_TOPALIGNED 0x00000004 +#define DIDAL_BOTTOMALIGNED 0x00000008 + +typedef struct _DIDEVICEIMAGEINFOA { + CHAR tszImagePath[MAX_PATH]; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT rgptCalloutLine[5]; + RECT rcCalloutRect; + DWORD dwTextAlign; +} DIDEVICEIMAGEINFOA, *LPDIDEVICEIMAGEINFOA; +typedef const DIDEVICEIMAGEINFOA *LPCDIDEVICEIMAGEINFOA; + +typedef struct _DIDEVICEIMAGEINFOW { + WCHAR tszImagePath[MAX_PATH]; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT rgptCalloutLine[5]; + RECT rcCalloutRect; + DWORD dwTextAlign; +} DIDEVICEIMAGEINFOW, *LPDIDEVICEIMAGEINFOW; +typedef const DIDEVICEIMAGEINFOW *LPCDIDEVICEIMAGEINFOW; + +DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFO) +DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFO) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFO) + +typedef struct _DIDEVICEIMAGEINFOHEADERA { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOA lprgImageInfoArray; +} DIDEVICEIMAGEINFOHEADERA, *LPDIDEVICEIMAGEINFOHEADERA; +typedef const DIDEVICEIMAGEINFOHEADERA *LPCDIDEVICEIMAGEINFOHEADERA; + +typedef struct _DIDEVICEIMAGEINFOHEADERW { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOW lprgImageInfoArray; +} DIDEVICEIMAGEINFOHEADERW, *LPDIDEVICEIMAGEINFOHEADERW; +typedef const DIDEVICEIMAGEINFOHEADERW *LPCDIDEVICEIMAGEINFOHEADERW; + +DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFOHEADER) +DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFOHEADER) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFOHEADER) + +#endif /* DI8 */ + + +/***************************************************************************** + * IDirectInputEffect interface + */ +#if (DIRECTINPUT_VERSION >= 0x0500) +#undef INTERFACE +#define INTERFACE IDirectInputEffect +DECLARE_INTERFACE_(IDirectInputEffect,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputEffect methods ***/ + STDMETHOD(Initialize)(THIS_ HINSTANCE, DWORD, REFGUID) PURE; + STDMETHOD(GetEffectGuid)(THIS_ LPGUID) PURE; + STDMETHOD(GetParameters)(THIS_ LPDIEFFECT, DWORD) PURE; + STDMETHOD(SetParameters)(THIS_ LPCDIEFFECT, DWORD) PURE; + STDMETHOD(Start)(THIS_ DWORD, DWORD) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetEffectStatus)(THIS_ LPDWORD) PURE; + STDMETHOD(Download)(THIS) PURE; + STDMETHOD(Unload)(THIS) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputEffect_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputEffect_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputEffect methods ***/ +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->lpVtbl->GetEffectGuid(p,a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->lpVtbl->GetParameters(p,a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->lpVtbl->SetParameters(p,a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->lpVtbl->Start(p,a,b) +#define IDirectInputEffect_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->lpVtbl->GetEffectStatus(p,a) +#define IDirectInputEffect_Download(p) (p)->lpVtbl->Download(p) +#define IDirectInputEffect_Unload(p) (p)->lpVtbl->Unload(p) +#define IDirectInputEffect_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#else +/*** IUnknown methods ***/ +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputEffect_AddRef(p) (p)->AddRef() +#define IDirectInputEffect_Release(p) (p)->Release() +/*** IDirectInputEffect methods ***/ +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->GetEffectGuid(a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->GetParameters(a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->SetParameters(a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->Start(a,b) +#define IDirectInputEffect_Stop(p) (p)->Stop() +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->GetEffectStatus(a) +#define IDirectInputEffect_Download(p) (p)->Download() +#define IDirectInputEffect_Unload(p) (p)->Unload() +#define IDirectInputEffect_Escape(p,a) (p)->Escape(a) +#endif + +#endif /* DI5 */ + + +/***************************************************************************** + * IDirectInputDeviceA interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDeviceA +DECLARE_INTERFACE_(IDirectInputDeviceA,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; +}; + +/***************************************************************************** + * IDirectInputDeviceW interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDeviceW +DECLARE_INTERFACE_(IDirectInputDeviceW,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice_AddRef(p) (p)->AddRef() +#define IDirectInputDevice_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice_Acquire(p) (p)->Acquire() +#define IDirectInputDevice_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#endif + + +#if (DIRECTINPUT_VERSION >= 0x0500) +/***************************************************************************** + * IDirectInputDevice2A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice2A +DECLARE_INTERFACE_(IDirectInputDevice2A,IDirectInputDeviceA) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice2W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice2W +DECLARE_INTERFACE_(IDirectInputDevice2W,IDirectInputDeviceW) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice2_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice2_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice2_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice2_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice2_AddRef(p) (p)->AddRef() +#define IDirectInputDevice2_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice2_Acquire(p) (p)->Acquire() +#define IDirectInputDevice2_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice2_Poll(p) (p)->Poll() +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +#endif +#endif /* DI5 */ + +#if DIRECTINPUT_VERSION >= 0x0700 +/***************************************************************************** + * IDirectInputDevice7A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice7A +DECLARE_INTERFACE_(IDirectInputDevice7A,IDirectInputDevice2A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7A methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice7W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice7W +DECLARE_INTERFACE_(IDirectInputDevice7W,IDirectInputDevice2W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7W methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice7_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice7_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice7_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice7_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice7_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice7_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice7_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice7_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice7_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice7_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice7_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice7_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice7_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice7_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice7_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice7_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice7_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice7_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice7_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice7_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice7_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d) +#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice7_AddRef(p) (p)->AddRef() +#define IDirectInputDevice7_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice7_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice7_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice7_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice7_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice7_Acquire(p) (p)->Acquire() +#define IDirectInputDevice7_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice7_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice7_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice7_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice7_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice7_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice7_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice7_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice7_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice7_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice7_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice7_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice7_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice7_Poll(p) (p)->Poll() +#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d) +#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d) +#endif + +#endif /* DI7 */ + +#if DIRECTINPUT_VERSION >= 0x0800 +/***************************************************************************** + * IDirectInputDevice8A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice8A +DECLARE_INTERFACE_(IDirectInputDevice8A,IDirectInputDevice7A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7A methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; + /*** IDirectInputDevice8A methods ***/ + STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice8W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice8W +DECLARE_INTERFACE_(IDirectInputDevice8W,IDirectInputDevice7W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7W methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; + /*** IDirectInputDevice8W methods ***/ + STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice8_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice8_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice8_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice8_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice8_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice8_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice8_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice8_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice8_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice8_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice8_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice8_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice8_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice8_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice8_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice8_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice8_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice8_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice8_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice8_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d) +#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d) +/*** IDirectInputDevice8 methods ***/ +#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->lpVtbl->BuildActionMap(p,a,b,c) +#define IDirectInputDevice8_SetActionMap(p,a,b,c) (p)->lpVtbl->SetActionMap(p,a,b,c) +#define IDirectInputDevice8_GetImageInfo(p,a) (p)->lpVtbl->GetImageInfo(p,a) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice8_AddRef(p) (p)->AddRef() +#define IDirectInputDevice8_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice8_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice8_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice8_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice8_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice8_Acquire(p) (p)->Acquire() +#define IDirectInputDevice8_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice8_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice8_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice8_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice8_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice8_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice8_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice8_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice8_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice8_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice8_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice8_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice8_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice8_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice8_Poll(p) (p)->Poll() +#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d) +#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d) +/*** IDirectInputDevice8 methods ***/ +#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->BuildActionMap(a,b,c) +#define IDirectInputDevice8_SetActionMap(p,a,b,c) (p)->SetActionMap(a,b,c) +#define IDirectInputDevice8_GetImageInfo(p,a) (p)->GetImageInfo(a) +#endif + +#endif /* DI8 */ + +/* "Standard" Mouse report... */ +typedef struct DIMOUSESTATE { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[4]; +} DIMOUSESTATE; + +#if DIRECTINPUT_VERSION >= 0x0700 +/* "Standard" Mouse report for DInput 7... */ +typedef struct DIMOUSESTATE2 { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[8]; +} DIMOUSESTATE2; +#endif /* DI7 */ + +#define DIMOFS_X FIELD_OFFSET(DIMOUSESTATE, lX) +#define DIMOFS_Y FIELD_OFFSET(DIMOUSESTATE, lY) +#define DIMOFS_Z FIELD_OFFSET(DIMOUSESTATE, lZ) +#define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 0) +#define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 1) +#define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 2) +#define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 3) +#if DIRECTINPUT_VERSION >= 0x0700 +#define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4) +#define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5) +#define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6) +#define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7) +#endif /* DI7 */ + +#ifdef __cplusplus +extern "C" { +#endif +extern const DIDATAFORMAT c_dfDIMouse; +#if DIRECTINPUT_VERSION >= 0x0700 +extern const DIDATAFORMAT c_dfDIMouse2; /* DX 7 */ +#endif /* DI7 */ +extern const DIDATAFORMAT c_dfDIKeyboard; +#if DIRECTINPUT_VERSION >= 0x0500 +extern const DIDATAFORMAT c_dfDIJoystick; +extern const DIDATAFORMAT c_dfDIJoystick2; +#endif /* DI5 */ +#ifdef __cplusplus +}; +#endif + +/***************************************************************************** + * IDirectInputA interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputA +DECLARE_INTERFACE_(IDirectInputA,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; +}; + +/***************************************************************************** + * IDirectInputW interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputW +DECLARE_INTERFACE_(IDirectInputW,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#else +/*** IUnknown methods ***/ +#define IDirectInput_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput_AddRef(p) (p)->AddRef() +#define IDirectInput_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput_Initialize(p,a,b) (p)->Initialize(a,b) +#endif + +/***************************************************************************** + * IDirectInput2A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput2A +DECLARE_INTERFACE_(IDirectInput2A,IDirectInputA) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; +}; + +/***************************************************************************** + * IDirectInput2W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput2W +DECLARE_INTERFACE_(IDirectInput2W,IDirectInputW) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput2_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput2_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#else +/*** IUnknown methods ***/ +#define IDirectInput2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput2_AddRef(p) (p)->AddRef() +#define IDirectInput2_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->Initialize(a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput2_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#endif + +/***************************************************************************** + * IDirectInput7A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput7A +DECLARE_INTERFACE_(IDirectInput7A,IDirectInput2A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; + /*** IDirectInput7A methods ***/ + STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE; +}; + +/***************************************************************************** + * IDirectInput7W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput7W +DECLARE_INTERFACE_(IDirectInput7W,IDirectInput2W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; + /*** IDirectInput7W methods ***/ + STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput7_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput7_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput7_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput7_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput7_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput7_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +/*** IDirectInput7 methods ***/ +#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->lpVtbl->CreateDeviceEx(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInput7_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput7_AddRef(p) (p)->AddRef() +#define IDirectInput7_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput7_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput7_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput7_Initialize(p,a,b) (p)->Initialize(a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput7_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +/*** IDirectInput7 methods ***/ +#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->CreateDeviceEx(a,b,c,d) +#endif + + +#if DIRECTINPUT_VERSION >= 0x0800 +/***************************************************************************** + * IDirectInput8A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput8A +DECLARE_INTERFACE_(IDirectInput8A,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInput8A methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8A *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; + STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE; +}; + +/***************************************************************************** + * IDirectInput8W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput8W +DECLARE_INTERFACE_(IDirectInput8W,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInput8W methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; + STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE; +}; +#undef INTERFACE + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput8 methods ***/ +#define IDirectInput8_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput8_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput8_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput8_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput8_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectInput8_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->lpVtbl->EnumDevicesBySemantics(p,a,b,c,d,e) +#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->lpVtbl->ConfigureDevices(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInput8_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput8_AddRef(p) (p)->AddRef() +#define IDirectInput8_Release(p) (p)->Release() +/*** IDirectInput8 methods ***/ +#define IDirectInput8_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput8_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput8_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput8_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput8_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectInput8_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->EnumDevicesBySemantics(a,b,c,d,e) +#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->ConfigureDevices(a,b,c,d) +#endif + +#endif /* DI8 */ + +/* Export functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if DIRECTINPUT_VERSION >= 0x0800 +HRESULT WINAPI DirectInput8Create(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); +#else /* DI < 8 */ +HRESULT WINAPI DirectInputCreateA(HINSTANCE,DWORD,LPDIRECTINPUTA *,LPUNKNOWN); +HRESULT WINAPI DirectInputCreateW(HINSTANCE,DWORD,LPDIRECTINPUTW *,LPUNKNOWN); +#define DirectInputCreate WINELIB_NAME_AW(DirectInputCreate) + +HRESULT WINAPI DirectInputCreateEx(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); +#endif /* DI8 */ + +#ifdef __cplusplus +}; +#endif + +#endif /* __DINPUT_INCLUDED__ */ diff --git a/raylib/external/glfw/deps/mingw/xinput.h b/raylib/external/glfw/deps/mingw/xinput.h new file mode 100644 index 0000000..d3ca726 --- /dev/null +++ b/raylib/external/glfw/deps/mingw/xinput.h @@ -0,0 +1,239 @@ +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_XINPUT_H +#define __WINE_XINPUT_H + +#include + +/* + * Bitmasks for the joysticks buttons, determines what has + * been pressed on the joystick, these need to be mapped + * to whatever device you're using instead of an xbox 360 + * joystick + */ + +#define XINPUT_GAMEPAD_DPAD_UP 0x0001 +#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 +#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 +#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 +#define XINPUT_GAMEPAD_START 0x0010 +#define XINPUT_GAMEPAD_BACK 0x0020 +#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 +#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 +#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 +#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 +#define XINPUT_GAMEPAD_A 0x1000 +#define XINPUT_GAMEPAD_B 0x2000 +#define XINPUT_GAMEPAD_X 0x4000 +#define XINPUT_GAMEPAD_Y 0x8000 + +/* + * Defines the flags used to determine if the user is pushing + * down on a button, not holding a button, etc + */ + +#define XINPUT_KEYSTROKE_KEYDOWN 0x0001 +#define XINPUT_KEYSTROKE_KEYUP 0x0002 +#define XINPUT_KEYSTROKE_REPEAT 0x0004 + +/* + * Defines the codes which are returned by XInputGetKeystroke + */ + +#define VK_PAD_A 0x5800 +#define VK_PAD_B 0x5801 +#define VK_PAD_X 0x5802 +#define VK_PAD_Y 0x5803 +#define VK_PAD_RSHOULDER 0x5804 +#define VK_PAD_LSHOULDER 0x5805 +#define VK_PAD_LTRIGGER 0x5806 +#define VK_PAD_RTRIGGER 0x5807 +#define VK_PAD_DPAD_UP 0x5810 +#define VK_PAD_DPAD_DOWN 0x5811 +#define VK_PAD_DPAD_LEFT 0x5812 +#define VK_PAD_DPAD_RIGHT 0x5813 +#define VK_PAD_START 0x5814 +#define VK_PAD_BACK 0x5815 +#define VK_PAD_LTHUMB_PRESS 0x5816 +#define VK_PAD_RTHUMB_PRESS 0x5817 +#define VK_PAD_LTHUMB_UP 0x5820 +#define VK_PAD_LTHUMB_DOWN 0x5821 +#define VK_PAD_LTHUMB_RIGHT 0x5822 +#define VK_PAD_LTHUMB_LEFT 0x5823 +#define VK_PAD_LTHUMB_UPLEFT 0x5824 +#define VK_PAD_LTHUMB_UPRIGHT 0x5825 +#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826 +#define VK_PAD_LTHUMB_DOWNLEFT 0x5827 +#define VK_PAD_RTHUMB_UP 0x5830 +#define VK_PAD_RTHUMB_DOWN 0x5831 +#define VK_PAD_RTHUMB_RIGHT 0x5832 +#define VK_PAD_RTHUMB_LEFT 0x5833 +#define VK_PAD_RTHUMB_UPLEFT 0x5834 +#define VK_PAD_RTHUMB_UPRIGHT 0x5835 +#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836 +#define VK_PAD_RTHUMB_DOWNLEFT 0x5837 + +/* + * Deadzones are for analogue joystick controls on the joypad + * which determine when input should be assumed to be in the + * middle of the pad. This is a threshold to stop a joypad + * controlling the game when the player isn't touching the + * controls. + */ + +#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 +#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 +#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 + + +/* + * Defines what type of abilities the type of joystick has + * DEVTYPE_GAMEPAD is available for all joysticks, however + * there may be more specific identifiers for other joysticks + * which are being used. + */ + +#define XINPUT_DEVTYPE_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04 +#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 + +/* + * These are used with the XInputGetCapabilities function to + * determine the abilities to the joystick which has been + * plugged in. + */ + +#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004 +#define XINPUT_FLAG_GAMEPAD 0x00000001 + +/* + * Defines the status of the battery if one is used in the + * attached joystick. The first two define if the joystick + * supports a battery. Disconnected means that the joystick + * isn't connected. Wired shows that the joystick is a wired + * joystick. + */ + +#define BATTERY_DEVTYPE_GAMEPAD 0x00 +#define BATTERY_DEVTYPE_HEADSET 0x01 +#define BATTERY_TYPE_DISCONNECTED 0x00 +#define BATTERY_TYPE_WIRED 0x01 +#define BATTERY_TYPE_ALKALINE 0x02 +#define BATTERY_TYPE_NIMH 0x03 +#define BATTERY_TYPE_UNKNOWN 0xFF +#define BATTERY_LEVEL_EMPTY 0x00 +#define BATTERY_LEVEL_LOW 0x01 +#define BATTERY_LEVEL_MEDIUM 0x02 +#define BATTERY_LEVEL_FULL 0x03 + +/* + * How many joysticks can be used with this library. Games that + * use the xinput library will not go over this number. + */ + +#define XUSER_MAX_COUNT 4 +#define XUSER_INDEX_ANY 0x000000FF + +/* + * Defines the structure of an xbox 360 joystick. + */ + +typedef struct _XINPUT_GAMEPAD { + WORD wButtons; + BYTE bLeftTrigger; + BYTE bRightTrigger; + SHORT sThumbLX; + SHORT sThumbLY; + SHORT sThumbRX; + SHORT sThumbRY; +} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; + +typedef struct _XINPUT_STATE { + DWORD dwPacketNumber; + XINPUT_GAMEPAD Gamepad; +} XINPUT_STATE, *PXINPUT_STATE; + +/* + * Defines the structure of how much vibration is set on both the + * right and left motors in a joystick. If you're not using a 360 + * joystick you will have to map these to your device. + */ + +typedef struct _XINPUT_VIBRATION { + WORD wLeftMotorSpeed; + WORD wRightMotorSpeed; +} XINPUT_VIBRATION, *PXINPUT_VIBRATION; + +/* + * Defines the structure for what kind of abilities the joystick has + * such abilities are things such as if the joystick has the ability + * to send and receive audio, if the joystick is in fact a driving + * wheel or perhaps if the joystick is some kind of dance pad or + * guitar. + */ + +typedef struct _XINPUT_CAPABILITIES { + BYTE Type; + BYTE SubType; + WORD Flags; + XINPUT_GAMEPAD Gamepad; + XINPUT_VIBRATION Vibration; +} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES; + +/* + * Defines the structure for a joystick input event which is + * retrieved using the function XInputGetKeystroke + */ +typedef struct _XINPUT_KEYSTROKE { + WORD VirtualKey; + WCHAR Unicode; + WORD Flags; + BYTE UserIndex; + BYTE HidCode; +} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE; + +typedef struct _XINPUT_BATTERY_INFORMATION +{ + BYTE BatteryType; + BYTE BatteryLevel; +} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION; + +#ifdef __cplusplus +extern "C" { +#endif + +void WINAPI XInputEnable(WINBOOL); +DWORD WINAPI XInputSetState(DWORD, XINPUT_VIBRATION*); +DWORD WINAPI XInputGetState(DWORD, XINPUT_STATE*); +DWORD WINAPI XInputGetKeystroke(DWORD, DWORD, PXINPUT_KEYSTROKE); +DWORD WINAPI XInputGetCapabilities(DWORD, DWORD, XINPUT_CAPABILITIES*); +DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD, GUID*, GUID*); +DWORD WINAPI XInputGetBatteryInformation(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*); + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_XINPUT_H */ diff --git a/raylib/external/glfw/deps/vs2008/stdint.h b/raylib/external/glfw/deps/vs2008/stdint.h new file mode 100644 index 0000000..d02608a --- /dev/null +++ b/raylib/external/glfw/deps/vs2008/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/raylib/external/glfw/include/GLFW/glfw3.h b/raylib/external/glfw/include/GLFW/glfw3.h index 9c55ac9..7d9dee0 100644 --- a/raylib/external/glfw/include/GLFW/glfw3.h +++ b/raylib/external/glfw/include/GLFW/glfw3.h @@ -190,9 +190,6 @@ extern "C" { #else /*__APPLE__*/ #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif #endif /*__APPLE__*/ @@ -262,12 +259,13 @@ extern "C" { /* We are building GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllexport) #elif defined(_WIN32) && defined(GLFW_DLL) - /* We are calling a GLFW Win32 DLL */ + /* We are calling GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - /* We are building GLFW as a Unix shared library */ + /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) #else + /* We are building or calling GLFW as a static library */ #define GLFWAPI #endif @@ -278,24 +276,23 @@ extern "C" { /*! @name GLFW version macros * @{ */ -/*! @brief The major version number of the GLFW header. +/*! @brief The major version number of the GLFW library. * - * The major version number of the GLFW header. This is incremented when the - * API is changed in non-compatible ways. + * This is incremented when the API is changed in non-compatible ways. * @ingroup init */ #define GLFW_VERSION_MAJOR 3 -/*! @brief The minor version number of the GLFW header. +/*! @brief The minor version number of the GLFW library. * - * The minor version number of the GLFW header. This is incremented when - * features are added to the API but it remains backward-compatible. + * This is incremented when features are added to the API but it remains + * backward-compatible. * @ingroup init */ #define GLFW_VERSION_MINOR 4 -/*! @brief The revision number of the GLFW header. +/*! @brief The revision number of the GLFW library. * - * The revision number of the GLFW header. This is incremented when a bug fix - * release is made that does not contain any API changes. + * This is incremented when a bug fix release is made that does not contain any + * API changes. * @ingroup init */ #define GLFW_VERSION_REVISION 0 @@ -361,15 +358,10 @@ extern "C" { #define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN) #define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP) #define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN) - -/*! @ingroup input - */ -#define GLFW_KEY_UNKNOWN -1 - /*! @} */ -/*! @defgroup keys Keyboard key tokens - * @brief Keyboard key tokens. +/*! @defgroup keys Keyboard keys + * @brief Keyboard key IDs. * * See [key input](@ref input_key) for how these are used. * @@ -379,7 +371,7 @@ extern "C" { * * The naming of the key codes follow these rules: * - The US keyboard layout is used - * - Names of printable alphanumeric characters are used (e.g. "A", "R", + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", * "3", etc.) * - For non-alphanumeric characters, Unicode:ish names are used (e.g. * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not @@ -392,6 +384,9 @@ extern "C" { * @{ */ +/* The unknown key */ +#define GLFW_KEY_UNKNOWN -1 + /* Printable keys */ #define GLFW_KEY_SPACE 32 #define GLFW_KEY_APOSTROPHE 39 /* ' */ @@ -721,7 +716,7 @@ extern "C" { * GLFW could not find support for the requested API on the system. * * @analysis The installed graphics driver does not support the requested - * API, or does not support it via the chosen context creation API. + * API, or does not support it via the chosen context creation backend. * Below are a few examples. * * @par @@ -790,7 +785,7 @@ extern "C" { /*! @brief The specified cursor shape is not available. * * The specified standard cursor shape is not available, either because the - * current platform cursor theme does not provide it or because it is not + * current system cursor theme does not provide it or because it is not * available on the platform. * * @analysis Platform or system settings limitation. Pick another @@ -825,28 +820,6 @@ extern "C" { * updating any existing out parameters. */ #define GLFW_FEATURE_UNIMPLEMENTED 0x0001000D -/*! @brief Platform unavailable or no matching platform was found. - * - * If emitted during initialization, no matching platform was found. If the @ref - * GLFW_PLATFORM init hint was set to `GLFW_ANY_PLATFORM`, GLFW could not detect any of - * the platforms supported by this library binary, except for the Null platform. If the - * init hint was set to a specific platform, it is either not supported by this library - * binary or GLFW was not able to detect it. - * - * If emitted by a native access function, GLFW was initialized for a different platform - * than the function is for. - * - * @analysis Failure to detect any platform usually only happens on non-macOS Unix - * systems, either when no window system is running or the program was run from - * a terminal that does not have the necessary environment variables. Fall back to - * a different platform if possible or notify the user that no usable platform was - * detected. - * - * Failure to detect a specific platform may have the same cause as above or be because - * support for that platform was not compiled in. Call @ref glfwPlatformSupported to - * check whether a specific platform is supported by a library binary. - */ -#define GLFW_PLATFORM_UNAVAILABLE 0x0001000E /*! @} */ /*! @addtogroup window @@ -929,18 +902,6 @@ extern "C" { */ #define GLFW_MOUSE_PASSTHROUGH 0x0002000D -/*! @brief Initial position x-coordinate window hint. - * - * Initial position x-coordinate [window hint](@ref GLFW_POSITION_X). - */ -#define GLFW_POSITION_X 0x0002000E - -/*! @brief Initial position y-coordinate window hint. - * - * Initial position y-coordinate [window hint](@ref GLFW_POSITION_Y). - */ -#define GLFW_POSITION_Y 0x0002000F - /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). @@ -1016,10 +977,9 @@ extern "C" { * Monitor refresh rate [hint](@ref GLFW_REFRESH_RATE). */ #define GLFW_REFRESH_RATE 0x0002100F -/*! @brief Framebuffer double buffering hint and attribute. +/*! @brief Framebuffer double buffering hint. * - * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER_hint) and - * [attribute](@ref GLFW_DOUBLEBUFFER_attrib). + * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). */ #define GLFW_DOUBLEBUFFER 0x00021010 @@ -1041,7 +1001,7 @@ extern "C" { * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). */ #define GLFW_CONTEXT_VERSION_MINOR 0x00022003 -/*! @brief Context client API revision number attribute. +/*! @brief Context client API revision number hint and attribute. * * Context client API revision number * [attribute](@ref GLFW_CONTEXT_REVISION_attrib). @@ -1098,15 +1058,8 @@ extern "C" { * [window hint](@ref GLFW_SCALE_TO_MONITOR). */ #define GLFW_SCALE_TO_MONITOR 0x0002200C -/*! @brief Window framebuffer scaling - * [window hint](@ref GLFW_SCALE_FRAMEBUFFER_hint). - */ -#define GLFW_SCALE_FRAMEBUFFER 0x0002200D -/*! @brief Legacy name for compatibility. - * - * This is an alias for the - * [GLFW_SCALE_FRAMEBUFFER](@ref GLFW_SCALE_FRAMEBUFFER_hint) window hint for - * compatibility with earlier versions. +/*! @brief macOS specific + * [window hint](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint). */ #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 /*! @brief macOS specific @@ -1126,15 +1079,6 @@ extern "C" { */ #define GLFW_X11_INSTANCE_NAME 0x00024002 #define GLFW_WIN32_KEYBOARD_MENU 0x00025001 -/*! @brief Win32 specific [window hint](@ref GLFW_WIN32_SHOWDEFAULT_hint). - */ -#define GLFW_WIN32_SHOWDEFAULT 0x00025002 -/*! @brief Wayland specific - * [window hint](@ref GLFW_WAYLAND_APP_ID_hint). - * - * Allows specification of the Wayland app_id. - */ -#define GLFW_WAYLAND_APP_ID 0x00026001 /*! @} */ #define GLFW_NO_API 0 @@ -1158,7 +1102,6 @@ extern "C" { #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_DISABLED 0x00034003 -#define GLFW_CURSOR_CAPTURED 0x00034004 #define GLFW_ANY_RELEASE_BEHAVIOR 0 #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 @@ -1176,16 +1119,11 @@ extern "C" { #define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007 #define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008 -#define GLFW_WAYLAND_PREFER_LIBDECOR 0x00038001 -#define GLFW_WAYLAND_DISABLE_LIBDECOR 0x00038002 - -#define GLFW_ANY_POSITION 0x80000000 - /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. * * These are the [standard cursor shapes](@ref cursor_standard) that can be - * requested from the platform (window system). + * requested from the window system. * * @ingroup input * @{ */ @@ -1230,11 +1168,11 @@ extern "C" { * @note @macos This shape is provided by a private system API and may fail * with @ref GLFW_CURSOR_UNAVAILABLE in the future. * - * @note @wayland This shape is provided by a newer standard not supported by - * all cursor themes. - * * @note @x11 This shape is provided by a newer standard not supported by all * cursor themes. + * + * @note @wayland This shape is provided by a newer standard not supported by + * all cursor themes. */ #define GLFW_RESIZE_NWSE_CURSOR 0x00036007 /*! @brief The top-right to bottom-left diagonal resize/move arrow shape. @@ -1245,11 +1183,11 @@ extern "C" { * @note @macos This shape is provided by a private system API and may fail * with @ref GLFW_CURSOR_UNAVAILABLE in the future. * - * @note @wayland This shape is provided by a newer standard not supported by - * all cursor themes. - * * @note @x11 This shape is provided by a newer standard not supported by all * cursor themes. + * + * @note @wayland This shape is provided by a newer standard not supported by + * all cursor themes. */ #define GLFW_RESIZE_NESW_CURSOR 0x00036008 /*! @brief The omni-directional resize/move cursor shape. @@ -1263,11 +1201,11 @@ extern "C" { * The operation-not-allowed shape. This is usually a circle with a diagonal * line through it. * - * @note @wayland This shape is provided by a newer standard not supported by - * all cursor themes. - * * @note @x11 This shape is provided by a newer standard not supported by all * cursor themes. + * + * @note @wayland This shape is provided by a newer standard not supported by + * all cursor themes. */ #define GLFW_NOT_ALLOWED_CURSOR 0x0003600A /*! @brief Legacy name for compatibility. @@ -1302,11 +1240,6 @@ extern "C" { * ANGLE rendering backend [init hint](@ref GLFW_ANGLE_PLATFORM_TYPE_hint). */ #define GLFW_ANGLE_PLATFORM_TYPE 0x00050002 -/*! @brief Platform selection init hint. - * - * Platform selection [init hint](@ref GLFW_PLATFORM). - */ -#define GLFW_PLATFORM 0x00050003 /*! @brief macOS specific init hint. * * macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint). @@ -1317,30 +1250,6 @@ extern "C" { * macOS specific [init hint](@ref GLFW_COCOA_MENUBAR_hint). */ #define GLFW_COCOA_MENUBAR 0x00051002 -/*! @brief X11 specific init hint. - * - * X11 specific [init hint](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint). - */ -#define GLFW_X11_XCB_VULKAN_SURFACE 0x00052001 -/*! @brief Wayland specific init hint. - * - * Wayland specific [init hint](@ref GLFW_WAYLAND_LIBDECOR_hint). - */ -#define GLFW_WAYLAND_LIBDECOR 0x00053001 -/*! @} */ - -/*! @addtogroup init - * @{ */ -/*! @brief Hint value that enables automatic platform selection. - * - * Hint value for @ref GLFW_PLATFORM that enables automatic platform selection. - */ -#define GLFW_ANY_PLATFORM 0x00060000 -#define GLFW_PLATFORM_WIN32 0x00060001 -#define GLFW_PLATFORM_COCOA 0x00060002 -#define GLFW_PLATFORM_WAYLAND 0x00060003 -#define GLFW_PLATFORM_X11 0x00060004 -#define GLFW_PLATFORM_NULL 0x00060005 /*! @} */ #define GLFW_DONT_CARE -1 @@ -1414,157 +1323,6 @@ typedef struct GLFWwindow GLFWwindow; */ typedef struct GLFWcursor GLFWcursor; -/*! @brief The function pointer type for memory allocation callbacks. - * - * This is the function pointer type for memory allocation callbacks. A memory - * allocation callback function has the following signature: - * @code - * void* function_name(size_t size, void* user) - * @endcode - * - * This function must return either a memory block at least `size` bytes long, - * or `NULL` if allocation failed. Note that not all parts of GLFW handle allocation - * failures gracefully yet. - * - * This function must support being called during @ref glfwInit but before the library is - * flagged as initialized, as well as during @ref glfwTerminate after the library is no - * longer flagged as initialized. - * - * Any memory allocated via this function will be deallocated via the same allocator - * during library termination or earlier. - * - * Any memory allocated via this function must be suitably aligned for any object type. - * If you are using C99 or earlier, this alignment is platform-dependent but will be the - * same as what `malloc` provides. If you are using C11 or later, this is the value of - * `alignof(max_align_t)`. - * - * The size will always be greater than zero. Allocations of size zero are filtered out - * before reaching the custom allocator. - * - * If this function returns `NULL`, GLFW will emit @ref GLFW_OUT_OF_MEMORY. - * - * This function must not call any GLFW function. - * - * @param[in] size The minimum size, in bytes, of the memory block. - * @param[in] user The user-defined pointer from the allocator. - * @return The address of the newly allocated memory block, or `NULL` if an - * error occurred. - * - * @pointer_lifetime The returned memory block must be valid at least until it - * is deallocated. - * - * @reentrancy This function should not call any GLFW function. - * - * @thread_safety This function must support being called from any thread that calls GLFW - * functions. - * - * @sa @ref init_allocator - * @sa @ref GLFWallocator - * - * @since Added in version 3.4. - * - * @ingroup init - */ -typedef void* (* GLFWallocatefun)(size_t size, void* user); - -/*! @brief The function pointer type for memory reallocation callbacks. - * - * This is the function pointer type for memory reallocation callbacks. - * A memory reallocation callback function has the following signature: - * @code - * void* function_name(void* block, size_t size, void* user) - * @endcode - * - * This function must return a memory block at least `size` bytes long, or - * `NULL` if allocation failed. Note that not all parts of GLFW handle allocation - * failures gracefully yet. - * - * This function must support being called during @ref glfwInit but before the library is - * flagged as initialized, as well as during @ref glfwTerminate after the library is no - * longer flagged as initialized. - * - * Any memory allocated via this function will be deallocated via the same allocator - * during library termination or earlier. - * - * Any memory allocated via this function must be suitably aligned for any object type. - * If you are using C99 or earlier, this alignment is platform-dependent but will be the - * same as what `realloc` provides. If you are using C11 or later, this is the value of - * `alignof(max_align_t)`. - * - * The block address will never be `NULL` and the size will always be greater than zero. - * Reallocations of a block to size zero are converted into deallocations before reaching - * the custom allocator. Reallocations of `NULL` to a non-zero size are converted into - * regular allocations before reaching the custom allocator. - * - * If this function returns `NULL`, GLFW will emit @ref GLFW_OUT_OF_MEMORY. - * - * This function must not call any GLFW function. - * - * @param[in] block The address of the memory block to reallocate. - * @param[in] size The new minimum size, in bytes, of the memory block. - * @param[in] user The user-defined pointer from the allocator. - * @return The address of the newly allocated or resized memory block, or - * `NULL` if an error occurred. - * - * @pointer_lifetime The returned memory block must be valid at least until it - * is deallocated. - * - * @reentrancy This function should not call any GLFW function. - * - * @thread_safety This function must support being called from any thread that calls GLFW - * functions. - * - * @sa @ref init_allocator - * @sa @ref GLFWallocator - * - * @since Added in version 3.4. - * - * @ingroup init - */ -typedef void* (* GLFWreallocatefun)(void* block, size_t size, void* user); - -/*! @brief The function pointer type for memory deallocation callbacks. - * - * This is the function pointer type for memory deallocation callbacks. - * A memory deallocation callback function has the following signature: - * @code - * void function_name(void* block, void* user) - * @endcode - * - * This function may deallocate the specified memory block. This memory block - * will have been allocated with the same allocator. - * - * This function must support being called during @ref glfwInit but before the library is - * flagged as initialized, as well as during @ref glfwTerminate after the library is no - * longer flagged as initialized. - * - * The block address will never be `NULL`. Deallocations of `NULL` are filtered out - * before reaching the custom allocator. - * - * If this function returns `NULL`, GLFW will emit @ref GLFW_OUT_OF_MEMORY. - * - * This function must not call any GLFW function. - * - * @param[in] block The address of the memory block to deallocate. - * @param[in] user The user-defined pointer from the allocator. - * - * @pointer_lifetime The specified memory block will not be accessed by GLFW - * after this function is called. - * - * @reentrancy This function should not call any GLFW function. - * - * @thread_safety This function must support being called from any thread that calls GLFW - * functions. - * - * @sa @ref init_allocator - * @sa @ref GLFWallocator - * - * @since Added in version 3.4. - * - * @ingroup init - */ -typedef void (* GLFWdeallocatefun)(void* block, void* user); - /*! @brief The function pointer type for error callbacks. * * This is the function pointer type for error callbacks. An error callback @@ -1587,7 +1345,7 @@ typedef void (* GLFWdeallocatefun)(void* block, void* user); * * @ingroup init */ -typedef void (* GLFWerrorfun)(int error_code, const char* description); +typedef void (* GLFWerrorfun)(int,const char*); /*! @brief The function pointer type for window position callbacks. * @@ -1610,7 +1368,7 @@ typedef void (* GLFWerrorfun)(int error_code, const char* description); * * @ingroup window */ -typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos); +typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); /*! @brief The function pointer type for window size callbacks. * @@ -1632,7 +1390,7 @@ typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos); * * @ingroup window */ -typedef void (* GLFWwindowsizefun)(GLFWwindow* window, int width, int height); +typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); /*! @brief The function pointer type for window close callbacks. * @@ -1652,7 +1410,7 @@ typedef void (* GLFWwindowsizefun)(GLFWwindow* window, int width, int height); * * @ingroup window */ -typedef void (* GLFWwindowclosefun)(GLFWwindow* window); +typedef void (* GLFWwindowclosefun)(GLFWwindow*); /*! @brief The function pointer type for window content refresh callbacks. * @@ -1672,7 +1430,7 @@ typedef void (* GLFWwindowclosefun)(GLFWwindow* window); * * @ingroup window */ -typedef void (* GLFWwindowrefreshfun)(GLFWwindow* window); +typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); /*! @brief The function pointer type for window focus callbacks. * @@ -1693,7 +1451,7 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow* window); * * @ingroup window */ -typedef void (* GLFWwindowfocusfun)(GLFWwindow* window, int focused); +typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); /*! @brief The function pointer type for window iconify callbacks. * @@ -1714,7 +1472,7 @@ typedef void (* GLFWwindowfocusfun)(GLFWwindow* window, int focused); * * @ingroup window */ -typedef void (* GLFWwindowiconifyfun)(GLFWwindow* window, int iconified); +typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); /*! @brief The function pointer type for window maximize callbacks. * @@ -1735,7 +1493,7 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow* window, int iconified); * * @ingroup window */ -typedef void (* GLFWwindowmaximizefun)(GLFWwindow* window, int maximized); +typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int); /*! @brief The function pointer type for framebuffer size callbacks. * @@ -1756,7 +1514,7 @@ typedef void (* GLFWwindowmaximizefun)(GLFWwindow* window, int maximized); * * @ingroup window */ -typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int height); +typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); /*! @brief The function pointer type for window content scale callbacks. * @@ -1777,7 +1535,7 @@ typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int heigh * * @ingroup window */ -typedef void (* GLFWwindowcontentscalefun)(GLFWwindow* window, float xscale, float yscale); +typedef void (* GLFWwindowcontentscalefun)(GLFWwindow*,float,float); /*! @brief The function pointer type for mouse button callbacks. * @@ -1803,7 +1561,7 @@ typedef void (* GLFWwindowcontentscalefun)(GLFWwindow* window, float xscale, flo * * @ingroup input */ -typedef void (* GLFWmousebuttonfun)(GLFWwindow* window, int button, int action, int mods); +typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); /*! @brief The function pointer type for cursor position callbacks. * @@ -1826,7 +1584,7 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow* window, int button, int action, * * @ingroup input */ -typedef void (* GLFWcursorposfun)(GLFWwindow* window, double xpos, double ypos); +typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); /*! @brief The function pointer type for cursor enter/leave callbacks. * @@ -1847,7 +1605,7 @@ typedef void (* GLFWcursorposfun)(GLFWwindow* window, double xpos, double ypos); * * @ingroup input */ -typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); +typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); /*! @brief The function pointer type for scroll callbacks. * @@ -1868,7 +1626,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); * * @ingroup input */ -typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffset); +typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); /*! @brief The function pointer type for keyboard key callbacks. * @@ -1880,7 +1638,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffse * * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. - * @param[in] scancode The platform-specific scancode of the key. + * @param[in] scancode The system-specific scancode of the key. * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. Future * releases may add more actions. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were @@ -1894,7 +1652,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffse * * @ingroup input */ -typedef void (* GLFWkeyfun)(GLFWwindow* window, int key, int scancode, int action, int mods); +typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); /*! @brief The function pointer type for Unicode character callbacks. * @@ -1915,7 +1673,7 @@ typedef void (* GLFWkeyfun)(GLFWwindow* window, int key, int scancode, int actio * * @ingroup input */ -typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint); +typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); /*! @brief The function pointer type for Unicode character with modifiers * callbacks. @@ -1942,7 +1700,7 @@ typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint); * * @ingroup input */ -typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods); +typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); /*! @brief The function pointer type for path drop callbacks. * @@ -1966,7 +1724,7 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int * * @ingroup input */ -typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* paths[]); +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char*[]); /*! @brief The function pointer type for monitor configuration callbacks. * @@ -1987,7 +1745,7 @@ typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* pat * * @ingroup monitor */ -typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); +typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); /*! @brief The function pointer type for joystick configuration callbacks. * @@ -2008,7 +1766,7 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); * * @ingroup input */ -typedef void (* GLFWjoystickfun)(int jid, int event); +typedef void (* GLFWjoystickfun)(int,int); /*! @brief Video mode type. * @@ -2122,38 +1880,6 @@ typedef struct GLFWgamepadstate float axes[6]; } GLFWgamepadstate; -/*! @brief Custom heap memory allocator. - * - * This describes a custom heap memory allocator for GLFW. To set an allocator, pass it - * to @ref glfwInitAllocator before initializing the library. - * - * @sa @ref init_allocator - * @sa @ref glfwInitAllocator - * - * @since Added in version 3.4. - * - * @ingroup init - */ -typedef struct GLFWallocator -{ - /*! The memory allocation function. See @ref GLFWallocatefun for details about - * allocation function. - */ - GLFWallocatefun allocate; - /*! The memory reallocation function. See @ref GLFWreallocatefun for details about - * reallocation function. - */ - GLFWreallocatefun reallocate; - /*! The memory deallocation function. See @ref GLFWdeallocatefun for details about - * deallocation function. - */ - GLFWdeallocatefun deallocate; - /*! The user pointer for this custom allocator. This value will be passed to the - * allocator functions. - */ - void* user; -} GLFWallocator; - /************************************************************************* * GLFW API functions @@ -2172,15 +1898,10 @@ typedef struct GLFWallocator * Additional calls to this function after successful initialization but before * termination will return `GLFW_TRUE` immediately. * - * The @ref GLFW_PLATFORM init hint controls which platforms are considered during - * initialization. This also depends on which platforms the library was compiled to - * support. - * * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_PLATFORM_UNAVAILABLE and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * * @remark @macos This function will change the current directory of the * application to the `Contents/Resources` subdirectory of the application's @@ -2195,13 +1916,6 @@ typedef struct GLFWallocator * and dock icon can be disabled entirely with the @ref GLFW_COCOA_MENUBAR init * hint. * - * @remark __Wayland, X11:__ If the library was compiled with support for both - * Wayland and X11, and the @ref GLFW_PLATFORM init hint is set to - * `GLFW_ANY_PLATFORM`, the `XDG_SESSION_TYPE` environment variable affects - * which platform is picked. If the environment variable is not set, or is set - * to something other than `wayland` or `x11`, the regular detection mechanism - * will be used instead. - * * @remark @x11 This function will set the `LC_CTYPE` category of the * application locale according to the current environment if that category is * still "C". This is because the "C" locale breaks Unicode text input. @@ -2209,8 +1923,6 @@ typedef struct GLFWallocator * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init - * @sa @ref glfwInitHint - * @sa @ref glfwInitAllocator * @sa @ref glfwTerminate * * @since Added in version 1.0. @@ -2285,85 +1997,6 @@ GLFWAPI void glfwTerminate(void); */ GLFWAPI void glfwInitHint(int hint, int value); -/*! @brief Sets the init allocator to the desired value. - * - * To use the default allocator, call this function with a `NULL` argument. - * - * If you specify an allocator struct, every member must be a valid function - * pointer. If any member is `NULL`, this function will emit @ref - * GLFW_INVALID_VALUE and the init allocator will be unchanged. - * - * The functions in the allocator must fulfil a number of requirements. See the - * documentation for @ref GLFWallocatefun, @ref GLFWreallocatefun and @ref - * GLFWdeallocatefun for details. - * - * @param[in] allocator The allocator to use at the next initialization, or - * `NULL` to use the default one. - * - * @errors Possible errors include @ref GLFW_INVALID_VALUE. - * - * @pointer_lifetime The specified allocator is copied before this function - * returns. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref init_allocator - * @sa @ref glfwInit - * - * @since Added in version 3.4. - * - * @ingroup init - */ -GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator); - -#if defined(VK_VERSION_1_0) - -/*! @brief Sets the desired Vulkan `vkGetInstanceProcAddr` function. - * - * This function sets the `vkGetInstanceProcAddr` function that GLFW will use for all - * Vulkan related entry point queries. - * - * This feature is mostly useful on macOS, if your copy of the Vulkan loader is in - * a location where GLFW cannot find it through dynamic loading, or if you are still - * using the static library version of the loader. - * - * If set to `NULL`, GLFW will try to load the Vulkan loader dynamically by its standard - * name and get this function from there. This is the default behavior. - * - * The standard name of the loader is `vulkan-1.dll` on Windows, `libvulkan.so.1` on - * Linux and other Unix-like systems and `libvulkan.1.dylib` on macOS. If your code is - * also loading it via these names then you probably don't need to use this function. - * - * The function address you set is never reset by GLFW, but it only takes effect during - * initialization. Once GLFW has been initialized, any updates will be ignored until the - * library is terminated and initialized again. - * - * @param[in] loader The address of the function to use, or `NULL`. - * - * @par Loader function signature - * @code - * PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance instance, const char* name) - * @endcode - * For more information about this function, see the - * [Vulkan Registry](https://www.khronos.org/registry/vulkan/). - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref vulkan_loader - * @sa @ref glfwInit - * - * @since Added in version 3.4. - * - * @ingroup init - */ -GLFWAPI void glfwInitVulkanLoader(PFN_vkGetInstanceProcAddr loader); - -#endif /*VK_VERSION_1_0*/ - /*! @brief Retrieves the version of the GLFW library. * * This function retrieves the major, minor and revision numbers of the GLFW @@ -2394,18 +2027,15 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); /*! @brief Returns a string describing the compile-time configuration. * * This function returns the compile-time generated - * [version string](@ref intro_version_string) of the GLFW library binary. It describes - * the version, platforms, compiler and any platform or operating system specific - * compile-time options. It should not be confused with the OpenGL or OpenGL ES version - * string, queried with `glGetString`. + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. * * __Do not use the version string__ to parse the GLFW library version. The * @ref glfwGetVersion function provides the version of the running library * binary in numerical format. * - * __Do not use the version string__ to parse what platforms are supported. The @ref - * glfwPlatformSupported function lets you query platform support. - * * @return The ASCII encoded GLFW version string. * * @errors None. @@ -2502,51 +2132,6 @@ GLFWAPI int glfwGetError(const char** description); */ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun callback); -/*! @brief Returns the currently selected platform. - * - * This function returns the platform that was selected during initialization. The - * returned value will be one of `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, - * `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`. - * - * @return The currently selected platform, or zero if an error occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref platform - * @sa @ref glfwPlatformSupported - * - * @since Added in version 3.4. - * - * @ingroup init - */ -GLFWAPI int glfwGetPlatform(void); - -/*! @brief Returns whether the library includes support for the specified platform. - * - * This function returns whether the library was compiled with support for the specified - * platform. The platform must be one of `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, - * `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`. - * - * @param[in] platform The platform to query. - * @return `GLFW_TRUE` if the platform is supported, or `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_INVALID_ENUM. - * - * @remark This function may be called before @ref glfwInit. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref platform - * @sa @ref glfwGetPlatform - * - * @since Added in version 3.4. - * - * @ingroup init - */ -GLFWAPI int glfwPlatformSupported(int platform); - /*! @brief Returns the currently connected monitors. * * This function returns an array of handles for all currently connected @@ -2630,7 +2215,7 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * This function returns the position, in screen coordinates, of the upper-left * corner of the work area of the specified monitor along with the work area * size in screen coordinates. The work area is defined as the area of the - * monitor not occluded by the window system task bar where present. If no + * monitor not occluded by the operating system task bar where present. If no * task bar exists then the work area is the monitor resolution in screen * coordinates. * @@ -2661,11 +2246,10 @@ GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, * This function returns the size, in millimetres, of the display area of the * specified monitor. * - * Some platforms do not provide accurate monitor size information, either - * because the monitor [EDID][] data is incorrect or because the driver does - * not report it accurately. - * - * [EDID]: https://en.wikipedia.org/wiki/Extended_display_identification_data + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. * * Any or all of the size arguments may be `NULL`. If an error occurs, all * non-`NULL` size arguments will be set to zero. @@ -2678,8 +2262,8 @@ GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @remark @win32 On Windows 8 and earlier the physical size is calculated from - * the current resolution and system DPI instead of querying the monitor EDID data. + * @remark @win32 calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. * * @thread_safety This function must only be called from the main thread. * @@ -2712,9 +2296,6 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland Fractional scaling information is not yet available for - * monitors, so this function only returns integer content scales. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_scale @@ -2836,9 +2417,8 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun callback); * * This function returns an array of all video modes supported by the specified * monitor. The returned array is sorted in ascending order, first by color - * bit depth (the sum of all channel depths), then by resolution area (the - * product of width and height), then resolution width and finally by refresh - * rate. + * bit depth (the sum of all channel depths) and then by resolution area (the + * product of width and height). * * @param[in] monitor The monitor to query. * @param[out] count Where to store the number of video modes in the returned @@ -2911,11 +2491,11 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE, - * @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark @wayland Gamma handling is a privileged protocol, this function - * will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE. + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * @@ -2935,11 +2515,11 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); * @return The current gamma ramp, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR - * and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @remark @wayland Gamma handling is a privileged protocol, this function - * will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while * returning `NULL`. * * @pointer_lifetime The returned structure and its arrays are allocated and @@ -2974,8 +2554,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR - * and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @remark The size of the specified gamma ramp should match the size of the * current ramp for that monitor. @@ -2983,7 +2563,7 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); * @remark @win32 The gamma ramp size must be 256. * * @remark @wayland Gamma handling is a privileged protocol, this function - * will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE. + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified gamma ramp is copied before this function * returns. @@ -3126,10 +2706,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * OpenGL or OpenGL ES context. * * By default, newly created windows use the placement recommended by the - * window system. To create the window at a specific position, set the @ref - * GLFW_POSITION_X and @ref GLFW_POSITION_Y window hints before creation. To - * restore the default behavior, set either or both hints back to - * `GLFW_ANY_POSITION`. + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. * * As long as at least one full screen window is not iconified, the screensaver * is prohibited from starting. @@ -3155,8 +2735,8 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref - * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. * * @remark @win32 Window creation will fail if the Microsoft GDI software * OpenGL implementation is the only one available. @@ -3178,35 +2758,23 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * @remark @macos The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. * For more information on bundles, see the - * [Bundle Programming Guide][bundle-guide] in the Mac Developer Library. - * - * [bundle-guide]: https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/ + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. * * @remark @macos On OS X 10.10 and later the window frame will not be rendered * at full resolution on Retina displays unless the - * [GLFW_SCALE_FRAMEBUFFER](@ref GLFW_SCALE_FRAMEBUFFER_hint) + * [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) * hint is `GLFW_TRUE` and the `NSHighResolutionCapable` key is enabled in the * application bundle's `Info.plist`. For more information, see - * [High Resolution Guidelines for OS X][hidpi-guide] in the Mac Developer - * Library. The GLFW test and example programs use a custom `Info.plist` - * template for this, which can be found as `CMake/Info.plist.in` in the source - * tree. - * - * [hidpi-guide]: https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/Info.plist.in` in the source tree. * * @remark @macos When activating frame autosaving with * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified * window size and position may be overridden by previously saved values. * - * @remark @wayland GLFW uses [libdecor][] where available to create its window - * decorations. This in turn uses server-side XDG decorations where available - * and provides high quality client-side decorations on compositors like GNOME. - * If both XDG decorations and libdecor are unavailable, GLFW falls back to - * a very simple set of window decorations that only support moving, resizing - * and the window manager's right-click menu. - * - * [libdecor]: https://gitlab.freedesktop.org/libdecor/libdecor - * * @remark @x11 Some window managers will not respect the placement of * initially hidden windows. * @@ -3223,6 +2791,20 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * [GLFW_X11_INSTANCE_NAME](@ref GLFW_X11_INSTANCE_NAME_hint) window hints to * override this. * + * @remark @wayland Compositors should implement the xdg-decoration protocol + * for GLFW to decorate the window properly. If this protocol isn't + * supported, or if the compositor prefers client-side decorations, a very + * simple fallback frame will be drawn using the wp_viewporter protocol. A + * compositor can still emit close, maximize or fullscreen events, using for + * instance a keybind mechanism. If neither of these protocols is supported, + * the window won't be decorated. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size or refresh rate. + * + * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol + * to be implemented in the user's compositor. + * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation @@ -3305,38 +2887,6 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); */ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); -/*! @brief Returns the title of the specified window. - * - * This function returns the window title, encoded as UTF-8, of the specified - * window. This is the title set previously by @ref glfwCreateWindow - * or @ref glfwSetWindowTitle. - * - * @param[in] window The window to query. - * @return The UTF-8 encoded window title, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @remark The returned title is currently a copy of the title last set by @ref - * glfwCreateWindow or @ref glfwSetWindowTitle. It does not include any - * additional text which may be appended by the platform or another program. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the next call to @ref - * glfwGetWindowTitle or @ref glfwSetWindowTitle, or until the library is - * terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_title - * @sa @ref glfwSetWindowTitle - * - * @since Added in version 3.4. - * - * @ingroup window - */ -GLFWAPI const char* glfwGetWindowTitle(GLFWwindow* window); - /*! @brief Sets the title of the specified window. * * This function sets the window title, encoded as UTF-8, of the specified @@ -3354,7 +2904,6 @@ GLFWAPI const char* glfwGetWindowTitle(GLFWwindow* window); * @thread_safety This function must only be called from the main thread. * * @sa @ref window_title - * @sa @ref glfwGetWindowTitle * * @since Added in version 1.0. * @glfw3 Added window handle parameter. @@ -3385,8 +2934,7 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * count is zero. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref - * GLFW_FEATURE_UNAVAILABLE (see remarks). + * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * * @pointer_lifetime The specified image data is copied before this function * returns. @@ -3394,9 +2942,8 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * @remark @macos Regular windows do not have icons on macOS. This function * will emit @ref GLFW_FEATURE_UNAVAILABLE. The dock icon will be the same as * the application bundle's icon. For more information on bundles, see the - * [Bundle Programming Guide][bundle-guide] in the Mac Developer Library. - * - * [bundle-guide]: https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/ + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. * * @remark @wayland There is no existing protocol to change an icon, the * window will thus inherit the one defined in the application's desktop file. @@ -3620,6 +3167,9 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size. + * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size @@ -3709,7 +3259,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int * regardless of their DPI and scaling settings. This relies on the system DPI * and scaling settings being somewhat correct. * - * On platforms where each monitors can have its own content scale, the window + * On systems where each monitors can have its own content scale, the window * content scale will depend on which monitor the system considers the window * to be on. * @@ -3797,9 +3347,8 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity); * previously restored. If the window is already iconified, this function does * nothing. * - * If the specified window is a full screen window, GLFW restores the original - * video mode of the monitor. The window's desired video mode is set again - * when the window is restored. + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. * * @param[in] window The window to iconify. * @@ -3829,8 +3378,8 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); * (minimized) or maximized. If the window is already restored, this function * does nothing. * - * If the specified window is an iconified full screen window, its desired - * video mode is set again for its monitor when the window is restored. + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. * * @param[in] window The window to restore. * @@ -3891,11 +3440,6 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland Because Wayland wants every frame of the desktop to be - * complete, this function does not immediately make the window visible. - * Instead it will become visible the next time the window framebuffer is - * updated after this call. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide @@ -3951,11 +3495,11 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * * @param[in] window The window to give input focus. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * - * @remark @wayland The compositor will likely ignore focus requests unless - * another window created by the same application already has input focus. + * @remark @wayland It is not possible for an application to set the input + * focus. This function will emit @ref GLFW_FEATURE_UNAVAILABLE. * * @thread_safety This function must only be called from the main thread. * @@ -4060,6 +3604,9 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); * @remark @wayland The desired window position is ignored, as there is no way * for an application to set this property. * + * @remark @wayland Setting the window to full screen will not attempt to + * change the mode, no matter what the requested size or refresh rate. + * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor @@ -4095,9 +3642,6 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int * errors. However, this function should not fail as long as it is passed * valid arguments and the library has been [initialized](@ref intro_init). * - * @remark @wayland The Wayland protocol provides no way to check whether a - * window is iconfied, so @ref GLFW_ICONIFIED always returns `GLFW_FALSE`. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs @@ -4132,15 +3676,11 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * @param[in] value `GLFW_TRUE` or `GLFW_FALSE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref - * GLFW_FEATURE_UNAVAILABLE (see remarks). + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark Calling @ref glfwGetWindowAttrib will always return the latest * value, even if that value is ignored by the current mode of the window. * - * @remark @wayland The [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) window attribute is - * not supported. Setting this will emit @ref GLFW_FEATURE_UNAVAILABLE. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs @@ -4687,8 +4227,6 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual * and unlimited cursor movement. This is useful for implementing for * example 3D camera controls. - * - `GLFW_CURSOR_CAPTURED` makes the cursor visible and confines it to the - * content area of the window. * * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are @@ -4815,8 +4353,8 @@ GLFWAPI int glfwRawMouseMotionSupported(void); * @param[in] scancode The scancode of the key to query. * @return The UTF-8 encoded, layout-specific name of the key, or `NULL`. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE, @ref GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @remark The contents of the returned string may change when a keyboard * layout change event is received. @@ -4838,18 +4376,15 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode); * * This function returns the platform-specific scancode of the specified key. * - * If the specified [key token](@ref keys) corresponds to a physical key not - * supported on the current platform then this method will return `-1`. - * Calling this function with anything other than a key token will return `-1` - * and generate a @ref GLFW_INVALID_ENUM error. + * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this + * method will return `-1`. * - * @param[in] key Any [key token](@ref keys). - * @return The platform-specific scancode for the key, or `-1` if the key is - * not supported on the current platform or an [error](@ref error_handling) - * occurred. + * @param[in] key Any [named key](@ref keys). + * @return The platform-specific scancode for the key, or `-1` if an + * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function may be called from any thread. * @@ -4866,7 +4401,8 @@ GLFWAPI int glfwGetKeyScancode(int key); * * This function returns the last state reported for the specified key to the * specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. The action `GLFW_REPEAT` is only reported to the key callback. + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to + * the key callback. * * If the @ref GLFW_STICKY_KEYS input mode is enabled, this function returns * `GLFW_PRESS` the first time you call it for a key that was pressed, even if @@ -4990,11 +4526,11 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * @param[in] ypos The desired y-coordinate, relative to the top edge of the * content area. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @remark @wayland This function will only work when the cursor mode is - * `GLFW_CURSOR_DISABLED`, otherwise it will emit @ref GLFW_FEATURE_UNAVAILABLE. + * `GLFW_CURSOR_DISABLED`, otherwise it will do nothing. * * @thread_safety This function must only be called from the main thread. * @@ -5027,8 +4563,8 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @return The handle of the created cursor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified image data is copied before this function * returns. @@ -5158,9 +4694,9 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * [character callback](@ref glfwSetCharCallback) instead. * * When a window loses input focus, it will generate synthetic key release - * events for all pressed keys with associated key tokens. You can tell these - * events from user-generated events by the fact that the synthetic ones are - * generated after the focus loss event has been processed, i.e. after the + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that @@ -5441,6 +4977,8 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun ca * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * + * @remark @wayland File drop is currently unimplemented. + * * @thread_safety This function must only be called from the main thread. * * @sa @ref path_drop @@ -5841,8 +5379,6 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string); * joystick is not present, does not have a mapping or an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref GLFW_INVALID_ENUM. - * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified joystick is * disconnected, the gamepad mappings are updated or the library is terminated. @@ -5907,11 +5443,6 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @win32 The clipboard on Windows has a single global lock for reading and - * writing. GLFW tries to acquire it a few times, which is almost always enough. If it - * cannot acquire the lock then this function emits @ref GLFW_PLATFORM_ERROR and returns. - * It is safe to try this multiple times. - * * @pointer_lifetime The specified string is copied before this function * returns. * @@ -5937,13 +5468,8 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_FORMAT_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. - * - * @remark @win32 The clipboard on Windows has a single global lock for reading and - * writing. GLFW tries to acquire it a few times, which is almost always enough. If it - * cannot acquire the lock then this function emits @ref GLFW_PLATFORM_ERROR and returns. - * It is safe to try this multiple times. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the next call to @ref @@ -5972,7 +5498,7 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * * The resolution of the timer is system dependent, but is usually on the order * of a few micro- or nanoseconds. It uses the highest-resolution monotonic - * time source on each operating system. + * time source on each supported platform. * * @return The current time, in seconds, or zero if an * [error](@ref error_handling) occurred. @@ -6067,15 +5593,12 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. It can also detach the current context from - * the calling thread without making a new one current by passing in `NULL`. + * current on the calling thread. A context must only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. * - * A context must only be made current on a single thread at a time and each - * thread can have only a single current context at a time. Making a context - * current detaches any previously current context on the calling thread. - * - * When moving a context between threads, you must detach it (make it - * non-current) on the old thread before making it current on the new one. + * When moving a context between threads, you must make it non-current on the + * old thread before making it current on the new one. * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control @@ -6090,10 +5613,6 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * - * @remarks If the previously current context was created via a different - * context creation API than the one passed to this function, GLFW will still - * detach the previous one from its API before making the new one current. - * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. * @@ -6190,7 +5709,7 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. * * @remark This function is not called during context creation, leaving the - * swap interval set to whatever is the default for that API. This is done + * swap interval set to whatever is the default on that platform. This is done * because some swap interval extensions used by GLFW do not allow the swap * interval to be reset to zero once it has been set to a non-zero value. * @@ -6294,11 +5813,13 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); * This function returns whether the Vulkan loader and any minimally functional * ICD have been found. * - * The availability of a Vulkan loader and even an ICD does not by itself guarantee that - * surface creation or even instance creation is possible. Call @ref - * glfwGetRequiredInstanceExtensions to check whether the extensions necessary for Vulkan - * surface creation are available and @ref glfwGetPhysicalDevicePresentationSupport to - * check whether a queue family of a physical device supports image presentation. + * The availability of a Vulkan loader and even an ICD does not by itself + * guarantee that surface creation or even instance creation is possible. + * For example, on Fermi systems Nvidia will install an ICD that provides no + * actual Vulkan support. Call @ref glfwGetRequiredInstanceExtensions to check + * whether the extensions necessary for Vulkan surface creation are available + * and @ref glfwGetPhysicalDevicePresentationSupport to check whether a queue + * family of a physical device supports image presentation. * * @return `GLFW_TRUE` if Vulkan is minimally available, or `GLFW_FALSE` * otherwise. @@ -6344,6 +5865,10 @@ GLFWAPI int glfwVulkanSupported(void); * returned array, as it is an error to specify an extension more than once in * the `VkInstanceCreateInfo` struct. * + * @remark @macos This function currently supports either the + * `VK_MVK_macos_surface` extension from MoltenVK or `VK_EXT_metal_surface` + * extension. + * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is guaranteed to be valid only until the * library is terminated. @@ -6425,7 +5950,7 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* p * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * * @remark @macos This function currently always returns `GLFW_TRUE`, as the - * `VK_MVK_macos_surface` and `VK_EXT_metal_surface` extensions do not provide + * `VK_MVK_macos_surface` extension does not provide * a `vkGetPhysicalDevice*PresentationSupport` type function. * * @thread_safety This function may be called from any thread. For @@ -6482,21 +6007,12 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhys * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should * eliminate almost all occurrences of these errors. * - * @remark @macos GLFW prefers the `VK_EXT_metal_surface` extension, with the - * `VK_MVK_macos_surface` extension as a fallback. The name of the selected - * extension, if any, is included in the array returned by @ref - * glfwGetRequiredInstanceExtensions. + * @remark @macos This function currently only supports the + * `VK_MVK_macos_surface` extension from MoltenVK. * * @remark @macos This function creates and sets a `CAMetalLayer` instance for * the window content view, which is required for MoltenVK to function. * - * @remark @x11 By default GLFW prefers the `VK_KHR_xcb_surface` extension, - * with the `VK_KHR_xlib_surface` extension as a fallback. You can make - * `VK_KHR_xlib_surface` the preferred extension by setting the - * [GLFW_X11_XCB_VULKAN_SURFACE](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint) init - * hint. The name of the selected extension, if any, is included in the array - * returned by @ref glfwGetRequiredInstanceExtensions. - * * @thread_safety This function may be called from any thread. For * synchronization details of Vulkan objects, see the Vulkan specification. * @@ -6533,7 +6049,6 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window */ #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY - #define GLFW_GLAPIENTRY_DEFINED #endif /* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ diff --git a/raylib/external/glfw/include/GLFW/glfw3native.h b/raylib/external/glfw/include/GLFW/glfw3native.h index 92f0d32..ba6a16b 100644 --- a/raylib/external/glfw/include/GLFW/glfw3native.h +++ b/raylib/external/glfw/include/GLFW/glfw3native.h @@ -74,16 +74,6 @@ extern "C" { * and which platform-specific headers to include. It is then up your (by * definition platform-specific) code to handle which of these should be * defined. - * - * If you do not want the platform-specific headers to be included, define - * `GLFW_NATIVE_INCLUDE_NONE` before including the @ref glfw3native.h header. - * - * @code - * #define GLFW_EXPOSE_NATIVE_WIN32 - * #define GLFW_EXPOSE_NATIVE_WGL - * #define GLFW_NATIVE_INCLUDE_NONE - * #include - * @endcode */ @@ -91,71 +81,50 @@ extern "C" { * System headers and types *************************************************************************/ -#if !defined(GLFW_NATIVE_INCLUDE_NONE) +#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL) + // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for + // example to allow applications to correctly declare a GL_ARB_debug_output + // callback) but windows.h assumes no one will define APIENTRY before it does + #if defined(GLFW_APIENTRY_DEFINED) + #undef APIENTRY + #undef GLFW_APIENTRY_DEFINED + #endif +// @raysan5: Actually, only HWND handler needs to be defined +// Including windows.h could suppose symbols re-definition issues (i.e Rectangle type) +//#include + typedef void *PVOID; + typedef PVOID HANDLE; + typedef HANDLE HWND; +#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL) + #include + #if defined(__OBJC__) + #import + #else + #include + typedef void* id; + #endif +#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX) + #include + #include +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + #include +#endif - #if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL) - /* This is a workaround for the fact that glfw3.h needs to export APIENTRY (for - * example to allow applications to correctly declare a GL_KHR_debug callback) - * but windows.h assumes no one will define APIENTRY before it does - */ - #if defined(GLFW_APIENTRY_DEFINED) - #undef APIENTRY - #undef GLFW_APIENTRY_DEFINED - #endif - #include - #endif - - #if defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL) - #if defined(__OBJC__) - #import - #else - #include - #include - #endif - #endif - - #if defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX) - #include - #include - #endif - - #if defined(GLFW_EXPOSE_NATIVE_WAYLAND) - #include - #endif - - #if defined(GLFW_EXPOSE_NATIVE_WGL) - /* WGL is declared by windows.h */ - #endif - #if defined(GLFW_EXPOSE_NATIVE_NSGL) - /* NSGL is declared by Cocoa.h */ - #endif - #if defined(GLFW_EXPOSE_NATIVE_GLX) - /* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by - * default it also acts as an OpenGL header - * However, glx.h will include gl.h, which will define it unconditionally - */ - #if defined(GLFW_GLAPIENTRY_DEFINED) - #undef GLAPIENTRY - #undef GLFW_GLAPIENTRY_DEFINED - #endif - #include - #endif - #if defined(GLFW_EXPOSE_NATIVE_EGL) - #include - #endif - #if defined(GLFW_EXPOSE_NATIVE_OSMESA) - /* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by - * default it also acts as an OpenGL header - * However, osmesa.h will include gl.h, which will define it unconditionally - */ - #if defined(GLFW_GLAPIENTRY_DEFINED) - #undef GLAPIENTRY - #undef GLFW_GLAPIENTRY_DEFINED - #endif - #include - #endif - -#endif /*GLFW_NATIVE_INCLUDE_NONE*/ +#if defined(GLFW_EXPOSE_NATIVE_WGL) + /* WGL is declared by windows.h */ +#endif +#if defined(GLFW_EXPOSE_NATIVE_NSGL) + /* NSGL is declared by Cocoa.h */ +#endif +#if defined(GLFW_EXPOSE_NATIVE_GLX) + #include +#endif +#if defined(GLFW_EXPOSE_NATIVE_EGL) + #include +#endif +#if defined(GLFW_EXPOSE_NATIVE_OSMESA) + #include +#endif /************************************************************************* @@ -169,9 +138,6 @@ extern "C" { * of the specified monitor, or `NULL` if an [error](@ref error_handling) * occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -187,9 +153,6 @@ GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -204,17 +167,6 @@ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); * @return The `HWND` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * - * @remark The `HDC` associated with the window can be queried with the - * [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc) - * function. - * @code - * HDC dc = GetDC(glfwGetWin32Window(window)); - * @endcode - * This DC is private and does not need to be released. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -231,17 +183,6 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); * @return The `HGLRC` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_UNAVAILABLE and @ref GLFW_NO_WINDOW_CONTEXT. - * - * @remark The `HDC` associated with the window can be queried with the - * [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc) - * function. - * @code - * HDC dc = GetDC(glfwGetWin32Window(window)); - * @endcode - * This DC is private and does not need to be released. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -258,9 +199,6 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); * @return The `CGDirectDisplayID` of the specified monitor, or * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -275,9 +213,6 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); * @return The `NSWindow` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -286,23 +221,6 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); * @ingroup native */ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); - -/*! @brief Returns the `NSView` of the specified window. - * - * @return The `NSView` of the specified window, or `nil` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.4. - * - * @ingroup native - */ -GLFWAPI id glfwGetCocoaView(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_NSGL) @@ -311,9 +229,6 @@ GLFWAPI id glfwGetCocoaView(GLFWwindow* window); * @return The `NSOpenGLContext` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_UNAVAILABLE and @ref GLFW_NO_WINDOW_CONTEXT. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -330,9 +245,6 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); * @return The `Display` used by GLFW, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -347,9 +259,6 @@ GLFWAPI Display* glfwGetX11Display(void); * @return The `RRCrtc` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -364,9 +273,6 @@ GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); * @return The `RROutput` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -381,9 +287,6 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); * @return The `Window` of the specified window, or `None` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -397,8 +300,8 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); * * @param[in] string A UTF-8 encoded string. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified string is copied before this function * returns. @@ -423,8 +326,8 @@ GLFWAPI void glfwSetX11SelectionString(const char* string); * @return The contents of the selection as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the next call to @ref @@ -450,9 +353,6 @@ GLFWAPI const char* glfwGetX11SelectionString(void); * @return The `GLXContext` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -467,9 +367,6 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); * @return The `GLXWindow` of the specified window, or `None` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -486,9 +383,6 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); * @return The `struct wl_display*` used by GLFW, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -503,9 +397,6 @@ GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); * @return The `struct wl_output*` of the specified monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -520,9 +411,6 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); * @return The main `struct wl_surface*` of the specified window, or `NULL` if * an [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_UNAVAILABLE. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -539,11 +427,6 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @remark Because EGL is initialized on demand, this function will return - * `EGL_NO_DISPLAY` until the first context has been created via EGL. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -558,9 +441,6 @@ GLFWAPI EGLDisplay glfwGetEGLDisplay(void); * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_NO_WINDOW_CONTEXT. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -575,9 +455,6 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_NO_WINDOW_CONTEXT. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -601,9 +478,6 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_NO_WINDOW_CONTEXT. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -625,9 +499,6 @@ GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_NO_WINDOW_CONTEXT. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * @@ -642,9 +513,6 @@ GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height * @return The `OSMesaContext` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_NO_WINDOW_CONTEXT. - * * @thread_safety This function may be called from any thread. Access is not * synchronized. * diff --git a/raylib/external/glfw/include/GLFW/vendor.go b/raylib/external/glfw/include/GLFW/vendor.go deleted file mode 100644 index 0fb2a0f..0000000 --- a/raylib/external/glfw/include/GLFW/vendor.go +++ /dev/null @@ -1,4 +0,0 @@ -//go:build required -// +build required - -package vendor diff --git a/raylib/external/glfw/src/cocoa_init.m b/raylib/external/glfw/src/cocoa_init.m index f34d985..7cad8b8 100644 --- a/raylib/external/glfw/src/cocoa_init.m +++ b/raylib/external/glfw/src/cocoa_init.m @@ -1,8 +1,7 @@ //======================================================================== -// GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -24,11 +23,10 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" - -#if defined(_GLFW_COCOA) - #include // For MAXPATHLEN // Needed for _NSGetProgname @@ -77,6 +75,7 @@ static void changeToResourcesDirectory(void) // static void createMenuBar(void) { + size_t i; NSString* appName = nil; NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; NSString* nameKeys[] = @@ -88,7 +87,7 @@ static void createMenuBar(void) // Try to figure out what the calling application is called - for (size_t i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++) + for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++) { id name = bundleInfo[nameKeys[i]]; if (name && @@ -176,8 +175,10 @@ static void createMenuBar(void) // Create key code translation tables // -static void createKeyTablesCocoa(void) +static void createKeyTables(void) { + int scancode; + memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes)); memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes)); @@ -250,7 +251,7 @@ static void createKeyTablesCocoa(void) _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10; _glfw.ns.keycodes[0x67] = GLFW_KEY_F11; _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12; - _glfw.ns.keycodes[0x69] = GLFW_KEY_PRINT_SCREEN; + _glfw.ns.keycodes[0x69] = GLFW_KEY_F13; _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14; _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16; @@ -296,7 +297,7 @@ static void createKeyTablesCocoa(void) _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY; _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT; - for (int scancode = 0; scancode < 256; scancode++) + for (scancode = 0; scancode < 256; scancode++) { // Store the reverse translation for faster key name lookup if (_glfw.ns.keycodes[scancode] >= 0) @@ -306,7 +307,7 @@ static void createKeyTablesCocoa(void) // Retrieve Unicode data for the current keyboard layout // -static GLFWbool updateUnicodeData(void) +static GLFWbool updateUnicodeDataNS(void) { if (_glfw.ns.inputSource) { @@ -376,7 +377,7 @@ static GLFWbool initializeTIS(void) _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = *kPropertyUnicodeKeyLayoutData; - return updateUnicodeData(); + return updateUnicodeDataNS(); } @interface GLFWHelper : NSObject @@ -386,7 +387,7 @@ static GLFWbool initializeTIS(void) - (void)selectedKeyboardInputSourceChanged:(NSObject* )object { - updateUnicodeData(); + updateUnicodeDataNS(); } - (void)doNothing:(id)object @@ -402,7 +403,9 @@ static GLFWbool initializeTIS(void) - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) _glfwInputWindowCloseRequest(window); return NSTerminateCancel; @@ -410,19 +413,24 @@ static GLFWbool initializeTIS(void) - (void)applicationDidChangeScreenParameters:(NSNotification *) notification { - for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) { if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; } - _glfwPollMonitorsCocoa(); + _glfwPollMonitorsNS(); } - (void)applicationWillFinishLaunching:(NSNotification *)notification { if (_glfw.hints.init.ns.menubar) { + // In case we are unbundled, make us a proper UI application + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + // Menu bar setup must go between sharedApplication and finishLaunching // in order to properly emulate the behavior of NSApplicationMain @@ -439,14 +447,16 @@ static GLFWbool initializeTIS(void) - (void)applicationDidFinishLaunching:(NSNotification *)notification { - _glfwPostEmptyEventCocoa(); + _glfwPlatformPostEmptyEvent(); [NSApp stop:nil]; } - (void)applicationDidHide:(NSNotification *)notification { - for (int i = 0; i < _glfw.monitorCount; i++) - _glfwRestoreVideoModeCocoa(_glfw.monitors[i]); + int i; + + for (i = 0; i < _glfw.monitorCount; i++) + _glfwRestoreVideoModeNS(_glfw.monitors[i]); } @end // GLFWApplicationDelegate @@ -456,32 +466,24 @@ static GLFWbool initializeTIS(void) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -void* _glfwLoadLocalVulkanLoaderCocoa(void) +void* _glfwLoadLocalVulkanLoaderNS(void) { CFBundleRef bundle = CFBundleGetMainBundle(); if (!bundle) return NULL; - CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle); - if (!frameworksUrl) + CFURLRef url = + CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib")); + if (!url) return NULL; - CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent( - kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false); - if (!loaderUrl) - { - CFRelease(frameworksUrl); - return NULL; - } - char path[PATH_MAX]; void* handle = NULL; - if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1)) - handle = _glfwPlatformLoadModule(path); + if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1)) + handle = _glfw_dlopen(path); - CFRelease(loaderUrl); - CFRelease(frameworksUrl); + CFRelease(url); return handle; } @@ -490,89 +492,7 @@ void* _glfwLoadLocalVulkanLoaderCocoa(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) -{ - const _GLFWplatform cocoa = - { - .platformID = GLFW_PLATFORM_COCOA, - .init = _glfwInitCocoa, - .terminate = _glfwTerminateCocoa, - .getCursorPos = _glfwGetCursorPosCocoa, - .setCursorPos = _glfwSetCursorPosCocoa, - .setCursorMode = _glfwSetCursorModeCocoa, - .setRawMouseMotion = _glfwSetRawMouseMotionCocoa, - .rawMouseMotionSupported = _glfwRawMouseMotionSupportedCocoa, - .createCursor = _glfwCreateCursorCocoa, - .createStandardCursor = _glfwCreateStandardCursorCocoa, - .destroyCursor = _glfwDestroyCursorCocoa, - .setCursor = _glfwSetCursorCocoa, - .getScancodeName = _glfwGetScancodeNameCocoa, - .getKeyScancode = _glfwGetKeyScancodeCocoa, - .setClipboardString = _glfwSetClipboardStringCocoa, - .getClipboardString = _glfwGetClipboardStringCocoa, - .initJoysticks = _glfwInitJoysticksCocoa, - .terminateJoysticks = _glfwTerminateJoysticksCocoa, - .pollJoystick = _glfwPollJoystickCocoa, - .getMappingName = _glfwGetMappingNameCocoa, - .updateGamepadGUID = _glfwUpdateGamepadGUIDCocoa, - .freeMonitor = _glfwFreeMonitorCocoa, - .getMonitorPos = _glfwGetMonitorPosCocoa, - .getMonitorContentScale = _glfwGetMonitorContentScaleCocoa, - .getMonitorWorkarea = _glfwGetMonitorWorkareaCocoa, - .getVideoModes = _glfwGetVideoModesCocoa, - .getVideoMode = _glfwGetVideoModeCocoa, - .getGammaRamp = _glfwGetGammaRampCocoa, - .setGammaRamp = _glfwSetGammaRampCocoa, - .createWindow = _glfwCreateWindowCocoa, - .destroyWindow = _glfwDestroyWindowCocoa, - .setWindowTitle = _glfwSetWindowTitleCocoa, - .setWindowIcon = _glfwSetWindowIconCocoa, - .getWindowPos = _glfwGetWindowPosCocoa, - .setWindowPos = _glfwSetWindowPosCocoa, - .getWindowSize = _glfwGetWindowSizeCocoa, - .setWindowSize = _glfwSetWindowSizeCocoa, - .setWindowSizeLimits = _glfwSetWindowSizeLimitsCocoa, - .setWindowAspectRatio = _glfwSetWindowAspectRatioCocoa, - .getFramebufferSize = _glfwGetFramebufferSizeCocoa, - .getWindowFrameSize = _glfwGetWindowFrameSizeCocoa, - .getWindowContentScale = _glfwGetWindowContentScaleCocoa, - .iconifyWindow = _glfwIconifyWindowCocoa, - .restoreWindow = _glfwRestoreWindowCocoa, - .maximizeWindow = _glfwMaximizeWindowCocoa, - .showWindow = _glfwShowWindowCocoa, - .hideWindow = _glfwHideWindowCocoa, - .requestWindowAttention = _glfwRequestWindowAttentionCocoa, - .focusWindow = _glfwFocusWindowCocoa, - .setWindowMonitor = _glfwSetWindowMonitorCocoa, - .windowFocused = _glfwWindowFocusedCocoa, - .windowIconified = _glfwWindowIconifiedCocoa, - .windowVisible = _glfwWindowVisibleCocoa, - .windowMaximized = _glfwWindowMaximizedCocoa, - .windowHovered = _glfwWindowHoveredCocoa, - .framebufferTransparent = _glfwFramebufferTransparentCocoa, - .getWindowOpacity = _glfwGetWindowOpacityCocoa, - .setWindowResizable = _glfwSetWindowResizableCocoa, - .setWindowDecorated = _glfwSetWindowDecoratedCocoa, - .setWindowFloating = _glfwSetWindowFloatingCocoa, - .setWindowOpacity = _glfwSetWindowOpacityCocoa, - .setWindowMousePassthrough = _glfwSetWindowMousePassthroughCocoa, - .pollEvents = _glfwPollEventsCocoa, - .waitEvents = _glfwWaitEventsCocoa, - .waitEventsTimeout = _glfwWaitEventsTimeoutCocoa, - .postEmptyEvent = _glfwPostEmptyEventCocoa, - .getEGLPlatform = _glfwGetEGLPlatformCocoa, - .getEGLNativeDisplay = _glfwGetEGLNativeDisplayCocoa, - .getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa, - .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsCocoa, - .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportCocoa, - .createWindowSurface = _glfwCreateWindowSurfaceCocoa - }; - - *platform = cocoa; - return GLFW_TRUE; -} - -int _glfwInitCocoa(void) +int _glfwPlatformInit(void) { @autoreleasepool { @@ -619,7 +539,7 @@ int _glfwInitCocoa(void) name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; - createKeyTablesCocoa(); + createKeyTables(); _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); if (!_glfw.ns.eventSource) @@ -630,21 +550,19 @@ int _glfwInitCocoa(void) if (!initializeTIS()) return GLFW_FALSE; - _glfwPollMonitorsCocoa(); + _glfwInitTimerNS(); + + _glfwPollMonitorsNS(); if (![[NSRunningApplication currentApplication] isFinishedLaunching]) [NSApp run]; - // In case we are unbundled, make us a proper UI application - if (_glfw.hints.init.ns.menubar) - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - return GLFW_TRUE; } // autoreleasepool } -void _glfwTerminateCocoa(void) +void _glfwPlatformTerminate(void) { @autoreleasepool { @@ -683,14 +601,19 @@ void _glfwTerminateCocoa(void) if (_glfw.ns.keyUpMonitor) [NSEvent removeMonitor:_glfw.ns.keyUpMonitor]; - _glfw_free(_glfw.ns.clipboardString); + free(_glfw.ns.clipboardString); _glfwTerminateNSGL(); - _glfwTerminateEGL(); - _glfwTerminateOSMesa(); } // autoreleasepool } -#endif // _GLFW_COCOA +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa" +#if defined(_GLFW_BUILD_DLL) + " dynamic" +#endif + ; +} diff --git a/raylib/external/glfw/src/cocoa_joystick.h b/raylib/external/glfw/src/cocoa_joystick.h index 2f46dfc..23d2b86 100644 --- a/raylib/external/glfw/src/cocoa_joystick.h +++ b/raylib/external/glfw/src/cocoa_joystick.h @@ -26,10 +26,13 @@ #include #include +#include #include -#define GLFW_COCOA_JOYSTICK_STATE _GLFWjoystickNS ns; -#define GLFW_COCOA_LIBRARY_JOYSTICK_STATE +#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyJoystick; } + +#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X" // Cocoa-specific per-joystick data // @@ -41,9 +44,3 @@ typedef struct _GLFWjoystickNS CFMutableArrayRef hats; } _GLFWjoystickNS; -GLFWbool _glfwInitJoysticksCocoa(void); -void _glfwTerminateJoysticksCocoa(void); -GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode); -const char* _glfwGetMappingNameCocoa(void); -void _glfwUpdateGamepadGUIDCocoa(char* guid); - diff --git a/raylib/external/glfw/src/cocoa_joystick.m b/raylib/external/glfw/src/cocoa_joystick.m index d5de479..4a64fb0 100644 --- a/raylib/external/glfw/src/cocoa_joystick.m +++ b/raylib/external/glfw/src/cocoa_joystick.m @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_COCOA) - #include #include #include @@ -96,21 +96,25 @@ static CFComparisonResult compareElements(const void* fp, // static void closeJoystick(_GLFWjoystick* js) { - _glfwInputJoystick(js, GLFW_DISCONNECTED); + int i; - for (int i = 0; i < CFArrayGetCount(js->ns.axes); i++) - _glfw_free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); + if (!js->present) + return; + + for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) + free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); CFRelease(js->ns.axes); - for (int i = 0; i < CFArrayGetCount(js->ns.buttons); i++) - _glfw_free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i)); + for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) + free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i)); CFRelease(js->ns.buttons); - for (int i = 0; i < CFArrayGetCount(js->ns.hats); i++) - _glfw_free((void*) CFArrayGetValueAtIndex(js->ns.hats, i)); + for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) + free((void*) CFArrayGetValueAtIndex(js->ns.hats, i)); CFRelease(js->ns.hats); _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Callback for user-initiated joystick addition @@ -123,6 +127,7 @@ static void matchCallback(void* context, int jid; char name[256]; char guid[33]; + CFIndex i; CFTypeRef property; uint32_t vendor = 0, product = 0, version = 0; _GLFWjoystick* js; @@ -134,14 +139,6 @@ static void matchCallback(void* context, return; } - CFArrayRef elements = - IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); - - // It is reportedly possible for this to fail on macOS 13 Ventura - // if the application does not have input monitoring permissions - if (!elements) - return; - axes = CFArrayCreateMutable(NULL, 0, NULL); buttons = CFArrayCreateMutable(NULL, 0, NULL); hats = CFArrayCreateMutable(NULL, 0, NULL); @@ -185,7 +182,10 @@ static void matchCallback(void* context, name[8], name[9], name[10]); } - for (CFIndex i = 0; i < CFArrayGetCount(elements); i++) + CFArrayRef elements = + IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); + + for (i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef native = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i); @@ -251,7 +251,7 @@ static void matchCallback(void* context, if (target) { - _GLFWjoyelementNS* element = _glfw_calloc(1, sizeof(_GLFWjoyelementNS)); + _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS)); element->native = native; element->usage = usage; element->index = (int) CFArrayGetCount(target); @@ -290,11 +290,13 @@ static void removeCallback(void* context, void* sender, IOHIDDeviceRef device) { - for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].ns.device == device) + if (_glfw.joysticks[jid].ns.device == device) { - closeJoystick(&_glfw.joysticks[jid]); + closeJoystick(_glfw.joysticks + jid); break; } } @@ -305,7 +307,7 @@ static void removeCallback(void* context, ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwInitJoysticksCocoa(void) +GLFWbool _glfwPlatformInitJoysticks(void) { CFMutableArrayRef matching; const long usages[] = @@ -382,13 +384,12 @@ GLFWbool _glfwInitJoysticksCocoa(void) return GLFW_TRUE; } -void _glfwTerminateJoysticksCocoa(void) +void _glfwPlatformTerminateJoysticks(void) { - for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) - { - if (_glfw.joysticks[jid].connected) - closeJoystick(&_glfw.joysticks[jid]); - } + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + closeJoystick(_glfw.joysticks + jid); if (_glfw.ns.hidManager) { @@ -398,11 +399,13 @@ void _glfwTerminateJoysticksCocoa(void) } -GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { if (mode & _GLFW_POLL_AXES) { - for (CFIndex i = 0; i < CFArrayGetCount(js->ns.axes); i++) + CFIndex i; + + for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) { _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.axes, i); @@ -427,7 +430,9 @@ GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode) if (mode & _GLFW_POLL_BUTTONS) { - for (CFIndex i = 0; i < CFArrayGetCount(js->ns.buttons); i++) + CFIndex i; + + for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) { _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); @@ -436,7 +441,7 @@ GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode) _glfwInputJoystickButton(js, (int) i, state); } - for (CFIndex i = 0; i < CFArrayGetCount(js->ns.hats); i++) + for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) { const int states[9] = { @@ -461,15 +466,10 @@ GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode) } } - return js->connected; + return js->present; } -const char* _glfwGetMappingNameCocoa(void) -{ - return "Mac OS X"; -} - -void _glfwUpdateGamepadGUIDCocoa(char* guid) +void _glfwPlatformUpdateGamepadGUID(char* guid) { if ((strncmp(guid + 4, "000000000000", 12) == 0) && (strncmp(guid + 20, "000000000000", 12) == 0)) @@ -481,5 +481,3 @@ void _glfwUpdateGamepadGUIDCocoa(char* guid) } } -#endif // _GLFW_COCOA - diff --git a/raylib/external/glfw/src/cocoa_monitor.m b/raylib/external/glfw/src/cocoa_monitor.m index a2bcc2f..2bb8373 100644 --- a/raylib/external/glfw/src/cocoa_monitor.m +++ b/raylib/external/glfw/src/cocoa_monitor.m @@ -1,9 +1,8 @@ //======================================================================== -// GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -25,11 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_COCOA) - #include #include #include @@ -40,31 +39,18 @@ // Get the name of the specified display, or NULL // -static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) +static char* getDisplayName(CGDirectDisplayID displayID) { - // IOKit doesn't work on Apple Silicon anymore - // Luckily, 10.15 introduced -[NSScreen localizedName]. - // Use it if available, and fall back to IOKit otherwise. - if (screen) - { - if ([screen respondsToSelector:@selector(localizedName)]) - { - NSString* name = [screen valueForKey:@"localizedName"]; - if (name) - return _glfw_strdup([name UTF8String]); - } - } - io_iterator_t it; io_service_t service; CFDictionaryRef info; - if (IOServiceGetMatchingServices(MACH_PORT_NULL, + if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"), &it) != 0) { // This may happen if a desktop Mac is running headless - return _glfw_strdup("Display"); + return NULL; } while ((service = IOIteratorNext(it)) != 0) @@ -99,7 +85,11 @@ static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) IOObjectRelease(it); if (!service) - return _glfw_strdup("Display"); + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find service port for display"); + return NULL; + } CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); @@ -111,13 +101,13 @@ static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) { // This may happen if a desktop Mac is running headless CFRelease(info); - return _glfw_strdup("Display"); + return NULL; } const CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8); - char* name = _glfw_calloc(size + 1, 1); + char* name = calloc(size + 1, 1); CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8); CFRelease(info); @@ -219,6 +209,31 @@ static void endFadeReservation(CGDisplayFadeReservationToken token) } } +// Finds and caches the NSScreen corresponding to the specified monitor +// +static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor) +{ + if (monitor->ns.screen) + return GLFW_TRUE; + + for (NSScreen* screen in [NSScreen screens]) + { + NSNumber* displayID = [screen deviceDescription][@"NSScreenNumber"]; + + // HACK: Compare unit numbers instead of display IDs to work around + // display replacement on machines with automatic graphics + // switching + if (monitor->ns.unitNumber == CGDisplayUnitNumber([displayID unsignedIntValue])) + { + monitor->ns.screen = screen; + return GLFW_TRUE; + } + } + + _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find a screen for monitor"); + return GLFW_FALSE; +} + // Returns the display refresh rate queried from the I/O registry // static double getFallbackRefreshRate(CGDirectDisplayID displayID) @@ -228,7 +243,7 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID) io_iterator_t it; io_service_t service; - if (IOServiceGetMatchingServices(MACH_PORT_NULL, + if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) { @@ -294,11 +309,11 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID) // Poll for changes in the set of connected monitors // -void _glfwPollMonitorsCocoa(void) +void _glfwPollMonitorsNS(void) { uint32_t displayCount; CGGetOnlineDisplayList(0, NULL, &displayCount); - CGDirectDisplayID* displays = _glfw_calloc(displayCount, sizeof(CGDirectDisplayID)); + CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID)); CGGetOnlineDisplayList(displayCount, displays, &displayCount); for (int i = 0; i < _glfw.monitorCount; i++) @@ -308,7 +323,7 @@ void _glfwPollMonitorsCocoa(void) uint32_t disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { - disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); @@ -319,48 +334,29 @@ void _glfwPollMonitorsCocoa(void) if (CGDisplayIsAsleep(displays[i])) continue; - const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]); - NSScreen* screen = nil; - - for (screen in [NSScreen screens]) - { - NSNumber* screenNumber = [screen deviceDescription][@"NSScreenNumber"]; - - // HACK: Compare unit numbers instead of display IDs to work around - // display replacement on machines with automatic graphics - // switching - if (CGDisplayUnitNumber([screenNumber unsignedIntValue]) == unitNumber) - break; - } - // HACK: Compare unit numbers instead of display IDs to work around // display replacement on machines with automatic graphics // switching - uint32_t j; - for (j = 0; j < disconnectedCount; j++) + const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]); + for (uint32_t j = 0; j < disconnectedCount; j++) { if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber) { - disconnected[j]->ns.screen = screen; disconnected[j] = NULL; break; } } - if (j < disconnectedCount) - continue; - const CGSize size = CGDisplayScreenSize(displays[i]); - char* name = getMonitorName(displays[i], screen); + char* name = getDisplayName(displays[i]); if (!name) - continue; + name = _glfw_strdup("Unknown"); _GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; monitor->ns.unitNumber = unitNumber; - monitor->ns.screen = screen; - _glfw_free(name); + free(name); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]); if (CGDisplayModeGetRefreshRate(mode) == 0.0) @@ -376,16 +372,16 @@ void _glfwPollMonitorsCocoa(void) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } - _glfw_free(disconnected); - _glfw_free(displays); + free(disconnected); + free(displays); } // Change the current video mode // -void _glfwSetVideoModeCocoa(_GLFWmonitor* monitor, const GLFWvidmode* desired) +void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) { GLFWvidmode current; - _glfwGetVideoModeCocoa(monitor, ¤t); + _glfwPlatformGetVideoMode(monitor, ¤t); const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); if (_glfwCompareVideoModes(¤t, best) == 0) @@ -425,7 +421,7 @@ void _glfwSetVideoModeCocoa(_GLFWmonitor* monitor, const GLFWvidmode* desired) // Restore the previously saved (original) video mode // -void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor) +void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor) { if (monitor->ns.previousMode) { @@ -444,11 +440,11 @@ void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwFreeMonitorCocoa(_GLFWmonitor* monitor) +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } -void _glfwGetMonitorPosCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { @autoreleasepool { @@ -462,16 +458,13 @@ void _glfwGetMonitorPosCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos) } // autoreleasepool } -void _glfwGetMonitorContentScaleCocoa(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) { @autoreleasepool { - if (!monitor->ns.screen) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Cannot query content scale without screen"); - } + if (!refreshMonitorScreen(monitor)) + return; const NSRect points = [monitor->ns.screen frame]; const NSRect pixels = [monitor->ns.screen convertRectToBacking:points]; @@ -484,24 +477,21 @@ void _glfwGetMonitorContentScaleCocoa(_GLFWmonitor* monitor, } // autoreleasepool } -void _glfwGetMonitorWorkareaCocoa(_GLFWmonitor* monitor, - int* xpos, int* ypos, - int* width, int* height) +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) { @autoreleasepool { - if (!monitor->ns.screen) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Cannot query workarea without screen"); - } + if (!refreshMonitorScreen(monitor)) + return; const NSRect frameRect = [monitor->ns.screen visibleFrame]; if (xpos) *xpos = frameRect.origin.x; if (ypos) - *ypos = _glfwTransformYCocoa(frameRect.origin.y + frameRect.size.height - 1); + *ypos = _glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1); if (width) *width = frameRect.size.width; if (height) @@ -510,7 +500,7 @@ void _glfwGetMonitorWorkareaCocoa(_GLFWmonitor* monitor, } // autoreleasepool } -GLFWvidmode* _glfwGetVideoModesCocoa(_GLFWmonitor* monitor, int* count) +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { @autoreleasepool { @@ -518,7 +508,7 @@ GLFWvidmode* _glfwGetVideoModesCocoa(_GLFWmonitor* monitor, int* count) CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); const CFIndex found = CFArrayGetCount(modes); - GLFWvidmode* result = _glfw_calloc(found, sizeof(GLFWvidmode)); + GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode)); for (CFIndex i = 0; i < found; i++) { @@ -537,7 +527,7 @@ GLFWvidmode* _glfwGetVideoModesCocoa(_GLFWmonitor* monitor, int* count) } // Skip duplicate modes - if (j < *count) + if (i < *count) continue; (*count)++; @@ -550,30 +540,23 @@ GLFWvidmode* _glfwGetVideoModesCocoa(_GLFWmonitor* monitor, int* count) } // autoreleasepool } -GLFWbool _glfwGetVideoModeCocoa(_GLFWmonitor* monitor, GLFWvidmode *mode) +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) { @autoreleasepool { CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID); - if (!native) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to query display mode"); - return GLFW_FALSE; - } - *mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate); CGDisplayModeRelease(native); - return GLFW_TRUE; } // autoreleasepool } -GLFWbool _glfwGetGammaRampCocoa(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { @autoreleasepool { uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID); - CGGammaValue* values = _glfw_calloc(size * 3, sizeof(CGGammaValue)); + CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); CGGetDisplayTransferByTable(monitor->ns.displayID, size, @@ -591,17 +574,17 @@ GLFWbool _glfwGetGammaRampCocoa(_GLFWmonitor* monitor, GLFWgammaramp* ramp) ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); } - _glfw_free(values); + free(values); return GLFW_TRUE; } // autoreleasepool } -void _glfwSetGammaRampCocoa(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { @autoreleasepool { - CGGammaValue* values = _glfw_calloc(ramp->size * 3, sizeof(CGGammaValue)); + CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); for (unsigned int i = 0; i < ramp->size; i++) { @@ -616,7 +599,7 @@ void _glfwSetGammaRampCocoa(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) values + ramp->size, values + ramp->size * 2); - _glfw_free(values); + free(values); } // autoreleasepool } @@ -630,15 +613,6 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay); - - if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Cocoa: Platform not initialized"); - return kCGNullDirectDisplay; - } - return monitor->ns.displayID; } -#endif // _GLFW_COCOA - diff --git a/raylib/external/glfw/src/cocoa_platform.h b/raylib/external/glfw/src/cocoa_platform.h index 3991455..01dcd87 100644 --- a/raylib/external/glfw/src/cocoa_platform.h +++ b/raylib/external/glfw/src/cocoa_platform.h @@ -25,15 +25,13 @@ //======================================================================== #include +#include #include -#include // NOTE: All of NSGL was deprecated in the 10.14 SDK // This disables the pointless warnings for every symbol we use -#ifndef GL_SILENCE_DEPRECATION #define GL_SILENCE_DEPRECATION -#endif #if defined(__OBJC__) #import @@ -42,15 +40,8 @@ typedef void* id; #endif // NOTE: Many Cocoa enum values have been renamed and we need to build across -// SDK versions where one is unavailable or deprecated. -// We use the newer names in code and replace them with the older names if -// the base SDK does not provide the newer names. - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400 - #define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval - #define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity -#endif - +// SDK versions where one is unavailable or the other deprecated +// We use the newer names in code and these macros to handle compatibility #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 #define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat #define NSEventMaskAny NSAnyEventMask @@ -69,15 +60,6 @@ typedef void* id; #define NSWindowStyleMaskTitled NSTitledWindowMask #endif -// NOTE: Many Cocoa dynamically linked constants have been renamed and we need -// to build across SDK versions where one is unavailable or deprecated. -// We use the newer names in code and replace them with the older names if -// the deployment target is older than the newer names. - -#if MAC_OS_X_VERSION_MIN_REQUIRED < 101300 - #define NSPasteboardTypeURL NSURLPboardType -#endif - typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; typedef VkFlags VkMetalSurfaceCreateFlagsEXT; @@ -100,13 +82,19 @@ typedef struct VkMetalSurfaceCreateInfoEXT typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*); -#define GLFW_COCOA_WINDOW_STATE _GLFWwindowNS ns; -#define GLFW_COCOA_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns; -#define GLFW_COCOA_MONITOR_STATE _GLFWmonitorNS ns; -#define GLFW_COCOA_CURSOR_STATE _GLFWcursorNS ns; +#include "posix_thread.h" +#include "cocoa_joystick.h" +#include "nsgl_context.h" -#define GLFW_NSGL_CONTEXT_STATE _GLFWcontextNSGL nsgl; -#define GLFW_NSGL_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl; +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns // HIToolbox.framework pointer typedefs #define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData @@ -118,22 +106,6 @@ typedef UInt8 (*PFN_LMGetKbdType)(void); #define LMGetKbdType _glfw.ns.tis.GetKbdType -// NSGL-specific per-context data -// -typedef struct _GLFWcontextNSGL -{ - id pixelFormat; - id object; -} _GLFWcontextNSGL; - -// NSGL-specific global data -// -typedef struct _GLFWlibraryNSGL -{ - // dlopen handle for OpenGL.framework (for glfwGetProcAddress) - CFBundleRef framework; -} _GLFWlibraryNSGL; - // Cocoa-specific per-window data // typedef struct _GLFWwindowNS @@ -145,7 +117,7 @@ typedef struct _GLFWwindowNS GLFWbool maximized; GLFWbool occluded; - GLFWbool scaleFramebuffer; + GLFWbool retina; // Cached window properties to filter out duplicate events int width, height; @@ -156,6 +128,7 @@ typedef struct _GLFWwindowNS // since the last cursor motion event was processed // This is kept to counteract Cocoa doing the same internally double cursorWarpDeltaX, cursorWarpDeltaY; + } _GLFWwindowNS; // Cocoa-specific global data @@ -189,6 +162,7 @@ typedef struct _GLFWlibraryNS PFN_LMGetKbdType GetKbdType; CFStringRef kPropertyUnicodeKeyLayoutData; } tis; + } _GLFWlibraryNS; // Cocoa-specific per-monitor data @@ -200,6 +174,7 @@ typedef struct _GLFWmonitorNS uint32_t unitNumber; id screen; double fallbackRefreshRate; + } _GLFWmonitorNS; // Cocoa-specific per-cursor data @@ -207,96 +182,25 @@ typedef struct _GLFWmonitorNS typedef struct _GLFWcursorNS { id object; + } _GLFWcursorNS; +// Cocoa-specific global timer data +// +typedef struct _GLFWtimerNS +{ + uint64_t frequency; -GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform); -int _glfwInitCocoa(void); -void _glfwTerminateCocoa(void); +} _GLFWtimerNS; -GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyWindowCocoa(_GLFWwindow* window); -void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title); -void _glfwSetWindowIconCocoa(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwGetWindowPosCocoa(_GLFWwindow* window, int* xpos, int* ypos); -void _glfwSetWindowPosCocoa(_GLFWwindow* window, int xpos, int ypos); -void _glfwGetWindowSizeCocoa(_GLFWwindow* window, int* width, int* height); -void _glfwSetWindowSizeCocoa(_GLFWwindow* window, int width, int height); -void _glfwSetWindowSizeLimitsCocoa(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); -void _glfwSetWindowAspectRatioCocoa(_GLFWwindow* window, int numer, int denom); -void _glfwGetFramebufferSizeCocoa(_GLFWwindow* window, int* width, int* height); -void _glfwGetWindowFrameSizeCocoa(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); -void _glfwGetWindowContentScaleCocoa(_GLFWwindow* window, float* xscale, float* yscale); -void _glfwIconifyWindowCocoa(_GLFWwindow* window); -void _glfwRestoreWindowCocoa(_GLFWwindow* window); -void _glfwMaximizeWindowCocoa(_GLFWwindow* window); -void _glfwShowWindowCocoa(_GLFWwindow* window); -void _glfwHideWindowCocoa(_GLFWwindow* window); -void _glfwRequestWindowAttentionCocoa(_GLFWwindow* window); -void _glfwFocusWindowCocoa(_GLFWwindow* window); -void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); -GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window); -GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window); -GLFWbool _glfwWindowVisibleCocoa(_GLFWwindow* window); -GLFWbool _glfwWindowMaximizedCocoa(_GLFWwindow* window); -GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window); -GLFWbool _glfwFramebufferTransparentCocoa(_GLFWwindow* window); -void _glfwSetWindowResizableCocoa(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowDecoratedCocoa(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled); -float _glfwGetWindowOpacityCocoa(_GLFWwindow* window); -void _glfwSetWindowOpacityCocoa(_GLFWwindow* window, float opacity); -void _glfwSetWindowMousePassthroughCocoa(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetRawMouseMotionCocoa(_GLFWwindow *window, GLFWbool enabled); -GLFWbool _glfwRawMouseMotionSupportedCocoa(void); +void _glfwInitTimerNS(void); -void _glfwPollEventsCocoa(void); -void _glfwWaitEventsCocoa(void); -void _glfwWaitEventsTimeoutCocoa(double timeout); -void _glfwPostEmptyEventCocoa(void); +void _glfwPollMonitorsNS(void); +void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); -void _glfwGetCursorPosCocoa(_GLFWwindow* window, double* xpos, double* ypos); -void _glfwSetCursorPosCocoa(_GLFWwindow* window, double xpos, double ypos); -void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode); -const char* _glfwGetScancodeNameCocoa(int scancode); -int _glfwGetKeyScancodeCocoa(int key); -GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); -GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape); -void _glfwDestroyCursorCocoa(_GLFWcursor* cursor); -void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor); -void _glfwSetClipboardStringCocoa(const char* string); -const char* _glfwGetClipboardStringCocoa(void); +float _glfwTransformYNS(float y); -EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs); -EGLNativeDisplayType _glfwGetEGLNativeDisplayCocoa(void); -EGLNativeWindowType _glfwGetEGLNativeWindowCocoa(_GLFWwindow* window); - -void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions); -GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); -VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -void _glfwFreeMonitorCocoa(_GLFWmonitor* monitor); -void _glfwGetMonitorPosCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos); -void _glfwGetMonitorContentScaleCocoa(_GLFWmonitor* monitor, float* xscale, float* yscale); -void _glfwGetMonitorWorkareaCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); -GLFWvidmode* _glfwGetVideoModesCocoa(_GLFWmonitor* monitor, int* count); -GLFWbool _glfwGetVideoModeCocoa(_GLFWmonitor* monitor, GLFWvidmode* mode); -GLFWbool _glfwGetGammaRampCocoa(_GLFWmonitor* monitor, GLFWgammaramp* ramp); -void _glfwSetGammaRampCocoa(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); - -void _glfwPollMonitorsCocoa(void); -void _glfwSetVideoModeCocoa(_GLFWmonitor* monitor, const GLFWvidmode* desired); -void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor); - -float _glfwTransformYCocoa(float y); - -void* _glfwLoadLocalVulkanLoaderCocoa(void); - -GLFWbool _glfwInitNSGL(void); -void _glfwTerminateNSGL(void); -GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContextNSGL(_GLFWwindow* window); +void* _glfwLoadLocalVulkanLoaderNS(void); diff --git a/raylib/external/glfw/src/cocoa_time.c b/raylib/external/glfw/src/cocoa_time.c index d56f145..4bf646c 100644 --- a/raylib/external/glfw/src/cocoa_time.c +++ b/raylib/external/glfw/src/cocoa_time.c @@ -23,19 +23,21 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(GLFW_BUILD_COCOA_TIMER) - #include ////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// +////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformInitTimer(void) +// Initialise timer +// +void _glfwInitTimerNS(void) { mach_timebase_info_data_t info; mach_timebase_info(&info); @@ -43,6 +45,11 @@ void _glfwPlatformInitTimer(void) _glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer; } + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + uint64_t _glfwPlatformGetTimerValue(void) { return mach_absolute_time(); @@ -53,5 +60,3 @@ uint64_t _glfwPlatformGetTimerFrequency(void) return _glfw.timer.ns.frequency; } -#endif // GLFW_BUILD_COCOA_TIMER - diff --git a/raylib/external/glfw/src/cocoa_time.h b/raylib/external/glfw/src/cocoa_time.h deleted file mode 100644 index 3512e8b..0000000 --- a/raylib/external/glfw/src/cocoa_time.h +++ /dev/null @@ -1,35 +0,0 @@ -//======================================================================== -// GLFW 3.4 macOS - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2009-2021 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#define GLFW_COCOA_LIBRARY_TIMER_STATE _GLFWtimerNS ns; - -// Cocoa-specific global timer data -// -typedef struct _GLFWtimerNS -{ - uint64_t frequency; -} _GLFWtimerNS; - diff --git a/raylib/external/glfw/src/cocoa_window.m b/raylib/external/glfw/src/cocoa_window.m index 949cace..81b22e2 100644 --- a/raylib/external/glfw/src/cocoa_window.m +++ b/raylib/external/glfw/src/cocoa_window.m @@ -23,17 +23,33 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_COCOA) - #include #include -// HACK: This enum value is missing from framework headers on OS X 10.11 despite -// having been (according to documentation) added in Mac OS X 10.7 -#define NSWindowCollectionBehaviorFullScreenNone (1 << 9) +// Returns the style mask corresponding to the window settings +// +static NSUInteger getStyleMask(_GLFWwindow* window) +{ + NSUInteger styleMask = NSWindowStyleMaskMiniaturizable; + + if (window->monitor || !window->decorated) + styleMask |= NSWindowStyleMaskBorderless; + else + { + styleMask |= NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable; + + if (window->resizable) + styleMask |= NSWindowStyleMaskResizable; + } + + return styleMask; +} // Returns whether the cursor is in the content area of the specified window // @@ -89,20 +105,19 @@ static void updateCursorMode(_GLFWwindow* window) if (window->cursorMode == GLFW_CURSOR_DISABLED) { _glfw.ns.disabledCursorWindow = window; - _glfwGetCursorPosCocoa(window, - &_glfw.ns.restoreCursorPosX, - &_glfw.ns.restoreCursorPosY); + _glfwPlatformGetCursorPos(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); _glfwCenterCursorInContentArea(window); CGAssociateMouseAndMouseCursorPosition(false); } else if (_glfw.ns.disabledCursorWindow == window) { _glfw.ns.disabledCursorWindow = NULL; - _glfwSetCursorPosCocoa(window, - _glfw.ns.restoreCursorPosX, - _glfw.ns.restoreCursorPosY); - // NOTE: The matching CGAssociateMouseAndMouseCursorPosition call is - // made in _glfwSetCursorPosCocoa as part of a workaround + CGAssociateMouseAndMouseCursorPosition(true); + _glfwPlatformSetCursorPos(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); } if (cursorInContentArea(window)) @@ -111,12 +126,12 @@ static void updateCursorMode(_GLFWwindow* window) // Make the specified window and its video mode active on its monitor // -static void acquireMonitorCocoa(_GLFWwindow* window) +static void acquireMonitor(_GLFWwindow* window) { - _glfwSetVideoModeCocoa(window->monitor, &window->videoMode); + _glfwSetVideoModeNS(window->monitor, &window->videoMode); const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); const NSRect frame = NSMakeRect(bounds.origin.x, - _glfwTransformYCocoa(bounds.origin.y + bounds.size.height - 1), + _glfwTransformYNS(bounds.origin.y + bounds.size.height - 1), bounds.size.width, bounds.size.height); @@ -127,13 +142,13 @@ static void acquireMonitorCocoa(_GLFWwindow* window) // Remove the window and restore the original video mode // -static void releaseMonitorCocoa(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfwInputMonitorWindow(window->monitor, NULL); - _glfwRestoreVideoModeCocoa(window->monitor); + _glfwRestoreVideoModeNS(window->monitor); } // Translates macOS key modifiers into GLFW ones @@ -158,7 +173,7 @@ static int translateFlags(NSUInteger flags) // Translates a macOS keycode to a GLFW keycode // -static int translateKeyCocoa(unsigned int key) +static int translateKey(unsigned int key) { if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0])) return GLFW_KEY_UNKNOWN; @@ -228,7 +243,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidResize:(NSNotification *)notification { - if (window->context.source == GLFW_NATIVE_CONTEXT_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window) @@ -263,21 +278,21 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidMove:(NSNotification *)notification { - if (window->context.source == GLFW_NATIVE_CONTEXT_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window) _glfwCenterCursorInContentArea(window); int x, y; - _glfwGetWindowPosCocoa(window, &x, &y); + _glfwPlatformGetWindowPos(window, &x, &y); _glfwInputWindowPos(window, x, y); } - (void)windowDidMiniaturize:(NSNotification *)notification { if (window->monitor) - releaseMonitorCocoa(window); + releaseMonitor(window); _glfwInputWindowIconify(window, GLFW_TRUE); } @@ -285,7 +300,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidDeminiaturize:(NSNotification *)notification { if (window->monitor) - acquireMonitorCocoa(window); + acquireMonitor(window); _glfwInputWindowIconify(window, GLFW_FALSE); } @@ -302,22 +317,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidResignKey:(NSNotification *)notification { if (window->monitor && window->autoIconify) - _glfwIconifyWindowCocoa(window); + _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); } - (void)windowDidChangeOcclusionState:(NSNotification* )notification { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 - if ([window->ns.object respondsToSelector:@selector(occlusionState)]) - { - if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) - window->ns.occluded = GLFW_FALSE; - else - window->ns.occluded = GLFW_TRUE; - } -#endif + if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) + window->ns.occluded = GLFW_FALSE; + else + window->ns.occluded = GLFW_TRUE; } @end @@ -350,7 +360,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; markedText = [[NSMutableAttributedString alloc] init]; [self updateTrackingAreas]; - [self registerForDraggedTypes:@[NSPasteboardTypeURL]]; + // NOTE: kUTTypeURL corresponds to NSPasteboardTypeURL but is available + // on 10.7 without having been deprecated yet + [self registerForDraggedTypes:@[(__bridge NSString*) kUTTypeURL]]; } return self; @@ -385,7 +397,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)updateLayer { - if (window->context.source == GLFW_NATIVE_CONTEXT_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; _glfwInputWindowDamage(window); @@ -508,18 +520,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; { const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - const float xscale = fbRect.size.width / contentRect.size.width; - const float yscale = fbRect.size.height / contentRect.size.height; - - if (xscale != window->ns.xscale || yscale != window->ns.yscale) - { - if (window->ns.scaleFramebuffer && window->ns.layer) - [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; - - window->ns.xscale = xscale; - window->ns.yscale = yscale; - _glfwInputWindowContentScale(window, xscale, yscale); - } if (fbRect.size.width != window->ns.fbWidth || fbRect.size.height != window->ns.fbHeight) @@ -528,6 +528,19 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; window->ns.fbHeight = fbRect.size.height; _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); } + + const float xscale = fbRect.size.width / contentRect.size.width; + const float yscale = fbRect.size.height / contentRect.size.height; + + if (xscale != window->ns.xscale || yscale != window->ns.yscale) + { + window->ns.xscale = xscale; + window->ns.yscale = yscale; + _glfwInputWindowContentScale(window, xscale, yscale); + + if (window->ns.retina && window->ns.layer) + [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; + } } - (void)drawRect:(NSRect)rect @@ -561,7 +574,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)keyDown:(NSEvent *)event { - const int key = translateKeyCocoa([event keyCode]); + const int key = translateKey([event keyCode]); const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); @@ -574,7 +587,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; int action; const unsigned int modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; - const int key = translateKeyCocoa([event keyCode]); + const int key = translateKey([event keyCode]); const int mods = translateFlags(modifierFlags); const NSUInteger keyFlag = translateKeyToModifierFlag(key); @@ -593,7 +606,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)keyUp:(NSEvent *)event { - const int key = translateKeyCocoa([event keyCode]); + const int key = translateKey([event keyCode]); const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods); } @@ -634,7 +647,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSUInteger count = [urls count]; if (count) { - char** paths = _glfw_calloc(count, sizeof(char*)); + char** paths = calloc(count, sizeof(char*)); for (NSUInteger i = 0; i < count; i++) paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]); @@ -642,8 +655,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _glfwInputDrop(window, (int) count, (const char**) paths); for (NSUInteger i = 0; i < count; i++) - _glfw_free(paths[i]); - _glfw_free(paths); + free(paths[i]); + free(paths); } return YES; @@ -790,41 +803,17 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, GLFWvidmode mode; int xpos, ypos; - _glfwGetVideoModeCocoa(window->monitor, &mode); - _glfwGetMonitorPosCocoa(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height); } else - { - if (wndconfig->xpos == GLFW_ANY_POSITION || - wndconfig->ypos == GLFW_ANY_POSITION) - { - contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); - } - else - { - const int xpos = wndconfig->xpos; - const int ypos = _glfwTransformYCocoa(wndconfig->ypos + wndconfig->height - 1); - contentRect = NSMakeRect(xpos, ypos, wndconfig->width, wndconfig->height); - } - } - - NSUInteger styleMask = NSWindowStyleMaskMiniaturizable; - - if (window->monitor || !window->decorated) - styleMask |= NSWindowStyleMaskBorderless; - else - { - styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); - - if (window->resizable) - styleMask |= NSWindowStyleMaskResizable; - } + contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); window->ns.object = [[GLFWWindow alloc] initWithContentRect:contentRect - styleMask:styleMask + styleMask:getStyleMask(window) backing:NSBackingStoreBuffered defer:NO]; @@ -838,14 +827,10 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; else { - if (wndconfig->xpos == GLFW_ANY_POSITION || - wndconfig->ypos == GLFW_ANY_POSITION) - { - [(NSWindow*) window->ns.object center]; - _glfw.ns.cascadePoint = - NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: - NSPointFromCGPoint(_glfw.ns.cascadePoint)]); - } + [(NSWindow*) window->ns.object center]; + _glfw.ns.cascadePoint = + NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: + NSPointFromCGPoint(_glfw.ns.cascadePoint)]); if (wndconfig->resizable) { @@ -854,12 +839,6 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, NSWindowCollectionBehaviorManaged; [window->ns.object setCollectionBehavior:behavior]; } - else - { - const NSWindowCollectionBehavior behavior = - NSWindowCollectionBehaviorFullScreenNone; - [window->ns.object setCollectionBehavior:behavior]; - } if (wndconfig->floating) [window->ns.object setLevel:NSFloatingWindowLevel]; @@ -872,7 +851,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setFrameAutosaveName:@(wndconfig->ns.frameName)]; window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; - window->ns.scaleFramebuffer = wndconfig->scaleFramebuffer; + window->ns.retina = wndconfig->ns.retina; if (fbconfig->transparent) { @@ -893,8 +872,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setTabbingMode:NSWindowTabbingModeDisallowed]; #endif - _glfwGetWindowSizeCocoa(window, &window->ns.width, &window->ns.height); - _glfwGetFramebufferSizeCocoa(window, &window->ns.fbWidth, &window->ns.fbHeight); + _glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height); + _glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight); return GLFW_TRUE; } @@ -906,7 +885,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, // Transforms a y-coordinate between the CG display and NS screen spaces // -float _glfwTransformYCocoa(float y) +float _glfwTransformYNS(float y) { return CGDisplayBounds(CGMainDisplayID()).size.height - y - 1; } @@ -916,10 +895,10 @@ float _glfwTransformYCocoa(float y) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { @autoreleasepool { @@ -954,31 +933,13 @@ GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } - - if (!_glfwRefreshContextAttribs(window, ctxconfig)) - return GLFW_FALSE; } - if (wndconfig->mousePassthrough) - _glfwSetWindowMousePassthroughCocoa(window, GLFW_TRUE); - if (window->monitor) { - _glfwShowWindowCocoa(window); - _glfwFocusWindowCocoa(window); - acquireMonitorCocoa(window); - - if (wndconfig->centerCursor) - _glfwCenterCursorInContentArea(window); - } - else - { - if (wndconfig->visible) - { - _glfwShowWindowCocoa(window); - if (wndconfig->focused) - _glfwFocusWindowCocoa(window); - } + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + acquireMonitor(window); } return GLFW_TRUE; @@ -986,7 +947,7 @@ GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, } // autoreleasepool } -void _glfwDestroyWindowCocoa(_GLFWwindow* window) +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { @autoreleasepool { @@ -996,7 +957,7 @@ void _glfwDestroyWindowCocoa(_GLFWwindow* window) [window->ns.object orderOut:nil]; if (window->monitor) - releaseMonitorCocoa(window); + releaseMonitor(window); if (window->context.destroy) window->context.destroy(window); @@ -1012,12 +973,12 @@ void _glfwDestroyWindowCocoa(_GLFWwindow* window) window->ns.object = nil; // HACK: Allow Cocoa to catch up before returning - _glfwPollEventsCocoa(); + _glfwPlatformPollEvents(); } // autoreleasepool } -void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title) +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { @autoreleasepool { NSString* string = @(title); @@ -1028,14 +989,14 @@ void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title) } // autoreleasepool } -void _glfwSetWindowIconCocoa(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) { _glfwInputError(GLFW_FEATURE_UNAVAILABLE, "Cocoa: Regular windows do not have icons on macOS"); } -void _glfwGetWindowPosCocoa(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { @autoreleasepool { @@ -1045,24 +1006,24 @@ void _glfwGetWindowPosCocoa(_GLFWwindow* window, int* xpos, int* ypos) if (xpos) *xpos = contentRect.origin.x; if (ypos) - *ypos = _glfwTransformYCocoa(contentRect.origin.y + contentRect.size.height - 1); + *ypos = _glfwTransformYNS(contentRect.origin.y + contentRect.size.height - 1); } // autoreleasepool } -void _glfwSetWindowPosCocoa(_GLFWwindow* window, int x, int y) +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y) { @autoreleasepool { const NSRect contentRect = [window->ns.view frame]; - const NSRect dummyRect = NSMakeRect(x, _glfwTransformYCocoa(y + contentRect.size.height - 1), 0, 0); + const NSRect dummyRect = NSMakeRect(x, _glfwTransformYNS(y + contentRect.size.height - 1), 0, 0); const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect]; [window->ns.object setFrameOrigin:frameRect.origin]; } // autoreleasepool } -void _glfwGetWindowSizeCocoa(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { @autoreleasepool { @@ -1076,14 +1037,14 @@ void _glfwGetWindowSizeCocoa(_GLFWwindow* window, int* width, int* height) } // autoreleasepool } -void _glfwSetWindowSizeCocoa(_GLFWwindow* window, int width, int height) +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { @autoreleasepool { if (window->monitor) { if (window->monitor->window == window) - acquireMonitorCocoa(window); + acquireMonitor(window); } else { @@ -1098,9 +1059,9 @@ void _glfwSetWindowSizeCocoa(_GLFWwindow* window, int width, int height) } // autoreleasepool } -void _glfwSetWindowSizeLimitsCocoa(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { @autoreleasepool { @@ -1117,7 +1078,7 @@ void _glfwSetWindowSizeLimitsCocoa(_GLFWwindow* window, } // autoreleasepool } -void _glfwSetWindowAspectRatioCocoa(_GLFWwindow* window, int numer, int denom) +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { @autoreleasepool { if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) @@ -1127,7 +1088,7 @@ void _glfwSetWindowAspectRatioCocoa(_GLFWwindow* window, int numer, int denom) } // autoreleasepool } -void _glfwGetFramebufferSizeCocoa(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { @autoreleasepool { @@ -1142,9 +1103,9 @@ void _glfwGetFramebufferSizeCocoa(_GLFWwindow* window, int* width, int* height) } // autoreleasepool } -void _glfwGetWindowFrameSizeCocoa(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { @autoreleasepool { @@ -1165,8 +1126,8 @@ void _glfwGetWindowFrameSizeCocoa(_GLFWwindow* window, } // autoreleasepool } -void _glfwGetWindowContentScaleCocoa(_GLFWwindow* window, - float* xscale, float* yscale) +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) { @autoreleasepool { @@ -1181,14 +1142,14 @@ void _glfwGetWindowContentScaleCocoa(_GLFWwindow* window, } // autoreleasepool } -void _glfwIconifyWindowCocoa(_GLFWwindow* window) +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { @autoreleasepool { [window->ns.object miniaturize:nil]; } // autoreleasepool } -void _glfwRestoreWindowCocoa(_GLFWwindow* window) +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { @autoreleasepool { if ([window->ns.object isMiniaturized]) @@ -1198,7 +1159,7 @@ void _glfwRestoreWindowCocoa(_GLFWwindow* window) } // autoreleasepool } -void _glfwMaximizeWindowCocoa(_GLFWwindow* window) +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { @autoreleasepool { if (![window->ns.object isZoomed]) @@ -1206,28 +1167,28 @@ void _glfwMaximizeWindowCocoa(_GLFWwindow* window) } // autoreleasepool } -void _glfwShowWindowCocoa(_GLFWwindow* window) +void _glfwPlatformShowWindow(_GLFWwindow* window) { @autoreleasepool { [window->ns.object orderFront:nil]; } // autoreleasepool } -void _glfwHideWindowCocoa(_GLFWwindow* window) +void _glfwPlatformHideWindow(_GLFWwindow* window) { @autoreleasepool { [window->ns.object orderOut:nil]; } // autoreleasepool } -void _glfwRequestWindowAttentionCocoa(_GLFWwindow* window) +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { @autoreleasepool { [NSApp requestUserAttention:NSInformationalRequest]; } // autoreleasepool } -void _glfwFocusWindowCocoa(_GLFWwindow* window) +void _glfwPlatformFocusWindow(_GLFWwindow* window) { @autoreleasepool { // Make us the active application @@ -1239,11 +1200,11 @@ void _glfwFocusWindowCocoa(_GLFWwindow* window) } // autoreleasepool } -void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { @autoreleasepool { @@ -1252,16 +1213,15 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, if (monitor) { if (monitor->window == window) - acquireMonitorCocoa(window); + acquireMonitor(window); } else { const NSRect contentRect = - NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1), width, height); - const NSUInteger styleMask = [window->ns.object styleMask]; + NSMakeRect(xpos, _glfwTransformYNS(ypos + height - 1), width, height); const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect - styleMask:styleMask]; + styleMask:getStyleMask(window)]; [window->ns.object setFrame:frameRect display:YES]; } @@ -1270,35 +1230,15 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, } if (window->monitor) - releaseMonitorCocoa(window); + releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); // HACK: Allow the state cached in Cocoa to catch up to reality // TODO: Solve this in a less terrible way - _glfwPollEventsCocoa(); - - NSUInteger styleMask = [window->ns.object styleMask]; - - if (window->monitor) - { - styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable); - styleMask |= NSWindowStyleMaskBorderless; - } - else - { - if (window->decorated) - { - styleMask &= ~NSWindowStyleMaskBorderless; - styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); - } - - if (window->resizable) - styleMask |= NSWindowStyleMaskResizable; - else - styleMask &= ~NSWindowStyleMaskResizable; - } + _glfwPlatformPollEvents(); + const NSUInteger styleMask = getStyleMask(window); [window->ns.object setStyleMask:styleMask]; // HACK: Changing the style mask can cause the first responder to be cleared [window->ns.object makeFirstResponder:window->ns.view]; @@ -1308,11 +1248,11 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; [window->ns.object setHasShadow:NO]; - acquireMonitorCocoa(window); + acquireMonitor(window); } else { - NSRect contentRect = NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1), + NSRect contentRect = NSMakeRect(xpos, _glfwTransformYNS(ypos + height - 1), width, height); NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect styleMask:styleMask]; @@ -1344,20 +1284,6 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, else [window->ns.object setLevel:NSNormalWindowLevel]; - if (window->resizable) - { - const NSWindowCollectionBehavior behavior = - NSWindowCollectionBehaviorFullScreenPrimary | - NSWindowCollectionBehaviorManaged; - [window->ns.object setCollectionBehavior:behavior]; - } - else - { - const NSWindowCollectionBehavior behavior = - NSWindowCollectionBehaviorFullScreenNone; - [window->ns.object setCollectionBehavior:behavior]; - } - [window->ns.object setHasShadow:YES]; // HACK: Clearing NSWindowStyleMaskTitled resets and disables the window // title property but the miniwindow title property is unaffected @@ -1367,40 +1293,35 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, } // autoreleasepool } -GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window) +int _glfwPlatformWindowFocused(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isKeyWindow]; } // autoreleasepool } -GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window) +int _glfwPlatformWindowIconified(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isMiniaturized]; } // autoreleasepool } -GLFWbool _glfwWindowVisibleCocoa(_GLFWwindow* window) +int _glfwPlatformWindowVisible(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isVisible]; } // autoreleasepool } -GLFWbool _glfwWindowMaximizedCocoa(_GLFWwindow* window) +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { @autoreleasepool { - - if (window->resizable) - return [window->ns.object isZoomed]; - else - return GLFW_FALSE; - + return [window->ns.object isZoomed]; } // autoreleasepool } -GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window) +int _glfwPlatformWindowHovered(_GLFWwindow* window) { @autoreleasepool { @@ -1418,60 +1339,29 @@ GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window) } // autoreleasepool } -GLFWbool _glfwFramebufferTransparentCocoa(_GLFWwindow* window) +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { @autoreleasepool { return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; } // autoreleasepool } -void _glfwSetWindowResizableCocoa(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { - - const NSUInteger styleMask = [window->ns.object styleMask]; - if (enabled) - { - [window->ns.object setStyleMask:(styleMask | NSWindowStyleMaskResizable)]; - const NSWindowCollectionBehavior behavior = - NSWindowCollectionBehaviorFullScreenPrimary | - NSWindowCollectionBehaviorManaged; - [window->ns.object setCollectionBehavior:behavior]; - } - else - { - [window->ns.object setStyleMask:(styleMask & ~NSWindowStyleMaskResizable)]; - const NSWindowCollectionBehavior behavior = - NSWindowCollectionBehaviorFullScreenNone; - [window->ns.object setCollectionBehavior:behavior]; - } - + [window->ns.object setStyleMask:getStyleMask(window)]; } // autoreleasepool } -void _glfwSetWindowDecoratedCocoa(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { - - NSUInteger styleMask = [window->ns.object styleMask]; - if (enabled) - { - styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); - styleMask &= ~NSWindowStyleMaskBorderless; - } - else - { - styleMask |= NSWindowStyleMaskBorderless; - styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); - } - - [window->ns.object setStyleMask:styleMask]; + [window->ns.object setStyleMask:getStyleMask(window)]; [window->ns.object makeFirstResponder:window->ns.view]; - } // autoreleasepool } -void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { if (enabled) @@ -1481,39 +1371,39 @@ void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled) } // autoreleasepool } -void _glfwSetWindowMousePassthroughCocoa(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { [window->ns.object setIgnoresMouseEvents:enabled]; } } -float _glfwGetWindowOpacityCocoa(_GLFWwindow* window) +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { @autoreleasepool { return (float) [window->ns.object alphaValue]; } // autoreleasepool } -void _glfwSetWindowOpacityCocoa(_GLFWwindow* window, float opacity) +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { @autoreleasepool { [window->ns.object setAlphaValue:opacity]; } // autoreleasepool } -void _glfwSetRawMouseMotionCocoa(_GLFWwindow *window, GLFWbool enabled) +void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, "Cocoa: Raw mouse motion not yet implemented"); } -GLFWbool _glfwRawMouseMotionSupportedCocoa(void) +GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_FALSE; } -void _glfwPollEventsCocoa(void) +void _glfwPlatformPollEvents(void) { @autoreleasepool { @@ -1532,7 +1422,7 @@ void _glfwPollEventsCocoa(void) } // autoreleasepool } -void _glfwWaitEventsCocoa(void) +void _glfwPlatformWaitEvents(void) { @autoreleasepool { @@ -1545,12 +1435,12 @@ void _glfwWaitEventsCocoa(void) dequeue:YES]; [NSApp sendEvent:event]; - _glfwPollEventsCocoa(); + _glfwPlatformPollEvents(); } // autoreleasepool } -void _glfwWaitEventsTimeoutCocoa(double timeout) +void _glfwPlatformWaitEventsTimeout(double timeout) { @autoreleasepool { @@ -1562,12 +1452,12 @@ void _glfwWaitEventsTimeoutCocoa(double timeout) if (event) [NSApp sendEvent:event]; - _glfwPollEventsCocoa(); + _glfwPlatformPollEvents(); } // autoreleasepool } -void _glfwPostEmptyEventCocoa(void) +void _glfwPlatformPostEmptyEvent(void) { @autoreleasepool { @@ -1585,7 +1475,7 @@ void _glfwPostEmptyEventCocoa(void) } // autoreleasepool } -void _glfwGetCursorPosCocoa(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { @autoreleasepool { @@ -1601,7 +1491,7 @@ void _glfwGetCursorPosCocoa(_GLFWwindow* window, double* xpos, double* ypos) } // autoreleasepool } -void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y) +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { @autoreleasepool { @@ -1626,46 +1516,32 @@ void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y) const NSPoint globalPoint = globalRect.origin; CGWarpMouseCursorPosition(CGPointMake(globalPoint.x, - _glfwTransformYCocoa(globalPoint.y))); + _glfwTransformYNS(globalPoint.y))); } - // HACK: Calling this right after setting the cursor position prevents macOS - // from freezing the cursor for a fraction of a second afterwards - if (window->cursorMode != GLFW_CURSOR_DISABLED) - CGAssociateMouseAndMouseCursorPosition(true); - } // autoreleasepool } -void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode) +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { @autoreleasepool { - - if (mode == GLFW_CURSOR_CAPTURED) - { - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Cocoa: Captured cursor mode not yet implemented"); - } - - if (_glfwWindowFocusedCocoa(window)) + if (_glfwPlatformWindowFocused(window)) updateCursorMode(window); - } // autoreleasepool } -const char* _glfwGetScancodeNameCocoa(int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { @autoreleasepool { - if (scancode < 0 || scancode > 0xff) + if (scancode < 0 || scancode > 0xff || + _glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); return NULL; } const int key = _glfw.ns.keycodes[scancode]; - if (key == GLFW_KEY_UNKNOWN) - return NULL; UInt32 deadKeyState = 0; UniChar characters[4]; @@ -1703,14 +1579,14 @@ const char* _glfwGetScancodeNameCocoa(int scancode) } // autoreleasepool } -int _glfwGetKeyScancodeCocoa(int key) +int _glfwPlatformGetKeyScancode(int key) { return _glfw.ns.scancodes[key]; } -GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { @autoreleasepool { @@ -1752,28 +1628,21 @@ GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor, } // autoreleasepool } -GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape) +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { @autoreleasepool { SEL cursorSelector = NULL; // HACK: Try to use a private message - switch (shape) - { - case GLFW_RESIZE_EW_CURSOR: - cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor"); - break; - case GLFW_RESIZE_NS_CURSOR: - cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor"); - break; - case GLFW_RESIZE_NWSE_CURSOR: - cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor"); - break; - case GLFW_RESIZE_NESW_CURSOR: - cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor"); - break; - } + if (shape == GLFW_RESIZE_EW_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor"); + else if (shape == GLFW_RESIZE_NS_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor"); + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor"); + else if (shape == GLFW_RESIZE_NESW_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor"); if (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) { @@ -1784,33 +1653,22 @@ GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape) if (!cursor->ns.object) { - switch (shape) - { - case GLFW_ARROW_CURSOR: - cursor->ns.object = [NSCursor arrowCursor]; - break; - case GLFW_IBEAM_CURSOR: - cursor->ns.object = [NSCursor IBeamCursor]; - break; - case GLFW_CROSSHAIR_CURSOR: - cursor->ns.object = [NSCursor crosshairCursor]; - break; - case GLFW_POINTING_HAND_CURSOR: - cursor->ns.object = [NSCursor pointingHandCursor]; - break; - case GLFW_RESIZE_EW_CURSOR: - cursor->ns.object = [NSCursor resizeLeftRightCursor]; - break; - case GLFW_RESIZE_NS_CURSOR: - cursor->ns.object = [NSCursor resizeUpDownCursor]; - break; - case GLFW_RESIZE_ALL_CURSOR: - cursor->ns.object = [NSCursor closedHandCursor]; - break; - case GLFW_NOT_ALLOWED_CURSOR: - cursor->ns.object = [NSCursor operationNotAllowedCursor]; - break; - } + if (shape == GLFW_ARROW_CURSOR) + cursor->ns.object = [NSCursor arrowCursor]; + else if (shape == GLFW_IBEAM_CURSOR) + cursor->ns.object = [NSCursor IBeamCursor]; + else if (shape == GLFW_CROSSHAIR_CURSOR) + cursor->ns.object = [NSCursor crosshairCursor]; + else if (shape == GLFW_POINTING_HAND_CURSOR) + cursor->ns.object = [NSCursor pointingHandCursor]; + else if (shape == GLFW_RESIZE_EW_CURSOR) + cursor->ns.object = [NSCursor resizeLeftRightCursor]; + else if (shape == GLFW_RESIZE_NS_CURSOR) + cursor->ns.object = [NSCursor resizeUpDownCursor]; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + cursor->ns.object = [NSCursor closedHandCursor]; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + cursor->ns.object = [NSCursor operationNotAllowedCursor]; } if (!cursor->ns.object) @@ -1826,7 +1684,7 @@ GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape) } // autoreleasepool } -void _glfwDestroyCursorCocoa(_GLFWcursor* cursor) +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { @autoreleasepool { if (cursor->ns.object) @@ -1834,7 +1692,7 @@ void _glfwDestroyCursorCocoa(_GLFWcursor* cursor) } // autoreleasepool } -void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { @autoreleasepool { if (cursorInContentArea(window)) @@ -1842,7 +1700,7 @@ void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor) } // autoreleasepool } -void _glfwSetClipboardStringCocoa(const char* string) +void _glfwPlatformSetClipboardString(const char* string) { @autoreleasepool { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; @@ -1851,7 +1709,7 @@ void _glfwSetClipboardStringCocoa(const char* string) } // autoreleasepool } -const char* _glfwGetClipboardStringCocoa(void) +const char* _glfwPlatformGetClipboardString(void) { @autoreleasepool { @@ -1872,7 +1730,7 @@ const char* _glfwGetClipboardStringCocoa(void) return NULL; } - _glfw_free(_glfw.ns.clipboardString); + free(_glfw.ns.clipboardString); _glfw.ns.clipboardString = _glfw_strdup([object UTF8String]); return _glfw.ns.clipboardString; @@ -1880,7 +1738,7 @@ const char* _glfwGetClipboardStringCocoa(void) } // autoreleasepool } -EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) { @@ -1900,7 +1758,7 @@ EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs) if (type) { - *attribs = _glfw_calloc(3, sizeof(EGLint)); + *attribs = calloc(3, sizeof(EGLint)); (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; (*attribs)[1] = type; (*attribs)[2] = EGL_NONE; @@ -1911,17 +1769,17 @@ EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs) return 0; } -EGLNativeDisplayType _glfwGetEGLNativeDisplayCocoa(void) +EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void) { return EGL_DEFAULT_DISPLAY; } -EGLNativeWindowType _glfwGetEGLNativeWindowCocoa(_GLFWwindow* window) +EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window) { return window->ns.layer; } -void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions) +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface) { @@ -1935,17 +1793,17 @@ void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions) } } -GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { return GLFW_TRUE; } -VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { @autoreleasepool { @@ -1969,7 +1827,7 @@ VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, return VK_ERROR_EXTENSION_NOT_PRESENT; } - if (window->ns.scaleFramebuffer) + if (window->ns.retina) [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; [window->ns.view setLayer:window->ns.layer]; @@ -2042,31 +1900,6 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); - - if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "Cocoa: Platform not initialized"); - return nil; - } - return window->ns.object; } -GLFWAPI id glfwGetCocoaView(GLFWwindow* handle) -{ - _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT_OR_RETURN(nil); - - if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "Cocoa: Platform not initialized"); - return nil; - } - - return window->ns.view; -} - -#endif // _GLFW_COCOA - diff --git a/raylib/external/glfw/src/context.c b/raylib/external/glfw/src/context.c index cc1fac4..48311e5 100644 --- a/raylib/external/glfw/src/context.c +++ b/raylib/external/glfw/src/context.c @@ -24,6 +24,8 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" @@ -46,6 +48,16 @@ // GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) { + if (ctxconfig->share) + { + if (ctxconfig->client == GLFW_NO_API || + ctxconfig->share->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return GLFW_FALSE; + } + } + if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && ctxconfig->source != GLFW_EGL_CONTEXT_API && ctxconfig->source != GLFW_OSMESA_CONTEXT_API) @@ -66,23 +78,6 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) return GLFW_FALSE; } - if (ctxconfig->share) - { - if (ctxconfig->client == GLFW_NO_API || - ctxconfig->share->context.client == GLFW_NO_API) - { - _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); - return GLFW_FALSE; - } - - if (ctxconfig->source != ctxconfig->share->context.source) - { - _glfwInputError(GLFW_INVALID_ENUM, - "Context creation APIs do not match between contexts"); - return GLFW_FALSE; - } - } - if (ctxconfig->client == GLFW_OPENGL_API) { if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || @@ -201,6 +196,12 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, continue; } + if (desired->doublebuffer != current->doublebuffer) + { + // Double buffering is a hard constraint + continue; + } + // Count number of missing buffers { missing = 0; @@ -361,8 +362,6 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, previous = _glfwPlatformGetTls(&_glfw.contextSlot); glfwMakeContextCurrent((GLFWwindow*) window); - if (_glfwPlatformGetTls(&_glfw.contextSlot) != window) - return GLFW_FALSE; window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.getProcAddress("glGetIntegerv"); @@ -571,9 +570,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) window->context.getProcAddress("glClear"); glClear(GL_COLOR_BUFFER_BIT); - - if (window->doublebuffer) - window->context.swapBuffers(window); + window->context.swapBuffers(window); } glfwMakeContextCurrent((GLFWwindow*) previous); @@ -616,12 +613,10 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFWwindow* previous; + _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); _GLFW_REQUIRE_INIT(); - previous = _glfwPlatformGetTls(&_glfw.contextSlot); - if (window && window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, diff --git a/raylib/external/glfw/src/egl_context.c b/raylib/external/glfw/src/egl_context.c index ef65dd3..533ed8e 100644 --- a/raylib/external/glfw/src/egl_context.c +++ b/raylib/external/glfw/src/egl_context.c @@ -24,6 +24,8 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" @@ -86,30 +88,13 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib) // Return the EGLConfig most closely matching the specified hints // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig, + const _GLFWfbconfig* desired, EGLConfig* result) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; - int i, nativeCount, usableCount, apiBit; - GLFWbool wrongApiAvailable = GLFW_FALSE; - - if (ctxconfig->client == GLFW_OPENGL_ES_API) - { - if (ctxconfig->major == 1) - apiBit = EGL_OPENGL_ES_BIT; - else - apiBit = EGL_OPENGL_ES2_BIT; - } - else - apiBit = EGL_OPENGL_BIT; - - if (fbconfig->stereo) - { - _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported"); - return GLFW_FALSE; - } + int i, nativeCount, usableCount; eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) @@ -118,10 +103,10 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, return GLFW_FALSE; } - nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig)); + nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); - usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; for (i = 0; i < nativeCount; i++) @@ -138,7 +123,6 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, continue; #if defined(_GLFW_X11) - if (_glfw.platform.platformID == GLFW_PLATFORM_X11) { XVisualInfo vi = {0}; @@ -147,7 +131,7 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, if (!vi.visualid) continue; - if (fbconfig->transparent) + if (desired->transparent) { int count; XVisualInfo* vis = @@ -161,10 +145,23 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, } #endif // _GLFW_X11 - if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit)) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { - wrongApiAvailable = GLFW_TRUE; - continue; + if (ctxconfig->major == 1) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) + continue; + } + else + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT)) + continue; + } + } + else if (ctxconfig->client == GLFW_OPENGL_API) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) + continue; } u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); @@ -175,63 +172,19 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); -#if defined(_GLFW_WAYLAND) - if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) - { - // NOTE: The wl_surface opaque region is no guarantee that its buffer - // is presented as opaque, if it also has an alpha channel - // HACK: If EGL_EXT_present_opaque is unavailable, ignore any config - // with an alpha channel to ensure the buffer is opaque - if (!_glfw.egl.EXT_present_opaque) - { - if (!fbconfig->transparent && u->alphaBits > 0) - continue; - } - } -#endif // _GLFW_WAYLAND - u->samples = getEGLConfigAttrib(n, EGL_SAMPLES); - u->doublebuffer = fbconfig->doublebuffer; + u->doublebuffer = GLFW_TRUE; u->handle = (uintptr_t) n; usableCount++; } - closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) *result = (EGLConfig) closest->handle; - else - { - if (wrongApiAvailable) - { - if (ctxconfig->client == GLFW_OPENGL_ES_API) - { - if (ctxconfig->major == 1) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "EGL: Failed to find support for OpenGL ES 1.x"); - } - else - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "EGL: Failed to find support for OpenGL ES 2 or later"); - } - } - else - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "EGL: Failed to find support for OpenGL"); - } - } - else - { - _glfwInputError(GLFW_FORMAT_UNAVAILABLE, - "EGL: Failed to find a suitable EGLConfig"); - } - } - _glfw_free(nativeConfigs); - _glfw_free(usableConfigs); + free(nativeConfigs); + free(usableConfigs); return closest != NULL; } @@ -277,15 +230,6 @@ static void swapBuffersEGL(_GLFWwindow* window) return; } -#if defined(_GLFW_WAYLAND) - if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) - { - // NOTE: Swapping buffers on a hidden window on Wayland makes it visible - if (!window->wl.visible) - return; - } -#endif - eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); } @@ -309,12 +253,11 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - assert(window != NULL); if (window->context.egl.client) { - GLFWglproc proc = (GLFWglproc) - _glfwPlatformGetModuleSymbol(window->context.egl.client, procname); + GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, + procname); if (proc) return proc; } @@ -324,14 +267,15 @@ static GLFWglproc getProcAddressEGL(const char* procname) static void destroyContextEGL(_GLFWwindow* window) { +#if defined(_GLFW_X11) // NOTE: Do not unload libGL.so.1 while the X11 display is still open, // as it will make XCloseDisplay segfault - if (_glfw.platform.platformID != GLFW_PLATFORM_X11 || - window->context.client != GLFW_OPENGL_API) + if (window->context.client != GLFW_OPENGL_API) +#endif // _GLFW_X11 { if (window->context.egl.client) { - _glfwPlatformFreeModule(window->context.egl.client); + _glfw_dlclose(window->context.egl.client); window->context.egl.client = NULL; } } @@ -372,8 +316,6 @@ GLFWbool _glfwInitEGL(void) "libEGL.dylib", #elif defined(__CYGWIN__) "libEGL-1.so", -#elif defined(__OpenBSD__) || defined(__NetBSD__) - "libEGL.so", #else "libEGL.so.1", #endif @@ -385,7 +327,7 @@ GLFWbool _glfwInitEGL(void) for (i = 0; sonames[i]; i++) { - _glfw.egl.handle = _glfwPlatformLoadModule(sonames[i]); + _glfw.egl.handle = _glfw_dlopen(sonames[i]); if (_glfw.egl.handle) break; } @@ -399,37 +341,37 @@ GLFWbool _glfwInitEGL(void) _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigAttrib"); + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); _glfw.egl.GetConfigs = (PFN_eglGetConfigs) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigs"); + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); _glfw.egl.GetDisplay = (PFN_eglGetDisplay) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetDisplay"); + _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); _glfw.egl.GetError = (PFN_eglGetError) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetError"); + _glfw_dlsym(_glfw.egl.handle, "eglGetError"); _glfw.egl.Initialize = (PFN_eglInitialize) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglInitialize"); + _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); _glfw.egl.Terminate = (PFN_eglTerminate) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglTerminate"); + _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); _glfw.egl.BindAPI = (PFN_eglBindAPI) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglBindAPI"); + _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); _glfw.egl.CreateContext = (PFN_eglCreateContext) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateContext"); + _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); _glfw.egl.DestroySurface = (PFN_eglDestroySurface) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroySurface"); + _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); _glfw.egl.DestroyContext = (PFN_eglDestroyContext) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroyContext"); + _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateWindowSurface"); + _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglMakeCurrent"); + _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapBuffers"); + _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); _glfw.egl.SwapInterval = (PFN_eglSwapInterval) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapInterval"); + _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); _glfw.egl.QueryString = (PFN_eglQueryString) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString"); + _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress) - _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress"); + _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); if (!_glfw.egl.GetConfigAttrib || !_glfw.egl.GetConfigs || @@ -487,18 +429,18 @@ GLFWbool _glfwInitEGL(void) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); } - _glfw.egl.platform = _glfw.platform.getEGLPlatform(&attribs); + _glfw.egl.platform = _glfwPlatformGetEGLPlatform(&attribs); if (_glfw.egl.platform) { _glfw.egl.display = eglGetPlatformDisplayEXT(_glfw.egl.platform, - _glfw.platform.getEGLNativeDisplay(), + _glfwPlatformGetEGLNativeDisplay(), attribs); } else - _glfw.egl.display = eglGetDisplay(_glfw.platform.getEGLNativeDisplay()); + _glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay()); - _glfw_free(attribs); + free(attribs); if (_glfw.egl.display == EGL_NO_DISPLAY) { @@ -530,8 +472,6 @@ GLFWbool _glfwInitEGL(void) extensionSupportedEGL("EGL_KHR_get_all_proc_addresses"); _glfw.egl.KHR_context_flush_control = extensionSupportedEGL("EGL_KHR_context_flush_control"); - _glfw.egl.EXT_present_opaque = - extensionSupportedEGL("EGL_EXT_present_opaque"); return GLFW_TRUE; } @@ -548,12 +488,12 @@ void _glfwTerminateEGL(void) if (_glfw.egl.handle) { - _glfwPlatformFreeModule(_glfw.egl.handle); + _glfw_dlclose(_glfw.egl.handle); _glfw.egl.handle = NULL; } } -#define SET_ATTRIB(a, v) \ +#define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -582,7 +522,11 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, share = ctxconfig->share->context.egl.handle; if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); return GLFW_FALSE; + } if (ctxconfig->client == GLFW_OPENGL_ES_API) { @@ -627,57 +571,57 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_NO_RESET_NOTIFICATION_KHR); + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_LOSE_CONTEXT_ON_RESET_KHR); + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR); } flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; } - if (ctxconfig->major != 1 || ctxconfig->minor != 0) - { - SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); - SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); - } - if (ctxconfig->noerror) { if (_glfw.egl.KHR_create_context_no_error) - SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + } + + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); + setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); } if (mask) - SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); if (flags) - SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags); + setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); } else { if (ctxconfig->client == GLFW_OPENGL_ES_API) - SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); + setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); } if (_glfw.egl.KHR_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); } } - SET_ATTRIB(EGL_NONE, EGL_NONE); + setAttrib(EGL_NONE, EGL_NONE); window->context.egl.handle = eglCreateContext(_glfw.egl.display, config, share, attribs); @@ -696,21 +640,12 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (fbconfig->sRGB) { if (_glfw.egl.KHR_gl_colorspace) - SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); } - if (!fbconfig->doublebuffer) - SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); + setAttrib(EGL_NONE, EGL_NONE); - if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) - { - if (_glfw.egl.EXT_present_opaque) - SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); - } - - SET_ATTRIB(EGL_NONE, EGL_NONE); - - native = _glfw.platform.getEGLNativeWindow(window); + native = _glfwPlatformGetEGLNativeWindow(window); // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT // despite reporting EGL_EXT_platform_base if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE) @@ -748,8 +683,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, "libGLES_CM.dll", #elif defined(_GLFW_COCOA) "libGLESv1_CM.dylib", -#elif defined(__OpenBSD__) || defined(__NetBSD__) - "libGLESv1_CM.so", #else "libGLESv1_CM.so.1", "libGLES_CM.so.1", @@ -767,8 +700,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, "libGLESv2.dylib", #elif defined(__CYGWIN__) "libGLESv2-2.so", -#elif defined(__OpenBSD__) || defined(__NetBSD__) - "libGLESv2.so", #else "libGLESv2.so.2", #endif @@ -780,10 +711,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, _GLFW_OPENGL_LIBRARY, #elif defined(_GLFW_WIN32) #elif defined(_GLFW_COCOA) -#elif defined(__OpenBSD__) || defined(__NetBSD__) - "libGL.so", #else - "libOpenGL.so.0", "libGL.so.1", #endif NULL @@ -806,7 +734,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) continue; - window->context.egl.client = _glfwPlatformLoadModule(sonames[i]); + window->context.egl.client = _glfw_dlopen(sonames[i]); if (window->context.egl.client) break; } @@ -829,7 +757,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef SET_ATTRIB +#undef setAttrib // Returns the Visual and depth of the chosen EGLConfig // @@ -846,7 +774,11 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, const long vimask = VisualScreenMask | VisualIDMask; if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); return GLFW_FALSE; + } eglGetConfigAttrib(_glfw.egl.display, native, EGL_NATIVE_VISUAL_ID, &visualID); @@ -886,7 +818,7 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); - if (window->context.source != GLFW_EGL_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_CONTEXT; @@ -900,7 +832,7 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); - if (window->context.source != GLFW_EGL_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_SURFACE; diff --git a/raylib/external/glfw/src/egl_context.h b/raylib/external/glfw/src/egl_context.h new file mode 100644 index 0000000..9de424c --- /dev/null +++ b/raylib/external/glfw/src/egl_context.h @@ -0,0 +1,227 @@ +//======================================================================== +// GLFW 3.4 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#if defined(_GLFW_WIN32) + #define EGLAPIENTRY __stdcall +#else + #define EGLAPIENTRY +#endif + +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300a +#define EGL_BAD_NATIVE_WINDOW 0x300b +#define EGL_BAD_PARAMETER 0x300c +#define EGL_BAD_SURFACE 0x300d +#define EGL_CONTEXT_LOST 0x300e +#define EGL_COLOR_BUFFER_TYPE 0x303f +#define EGL_RGB_BUFFER 0x308e +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SAMPLES 0x3031 +#define EGL_OPENGL_ES_API 0x30a0 +#define EGL_OPENGL_API 0x30a2 +#define EGL_NONE 0x3038 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_NATIVE_VISUAL_ID 0x302e +#define EGL_NO_SURFACE ((EGLSurface) 0) +#define EGL_NO_DISPLAY ((EGLDisplay) 0) +#define EGL_NO_CONTEXT ((EGLContext) 0) +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) + +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd +#define EGL_CONTEXT_FLAGS_KHR 0x30fc +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 +#define EGL_GL_COLORSPACE_KHR 0x309d +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 +#define EGL_PLATFORM_X11_EXT 0x31d5 +#define EGL_PLATFORM_WAYLAND_EXT 0x31d8 +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320d +#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320e +#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450 +#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489 +#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348f + +typedef int EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void* EGLConfig; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLSurface; + +typedef void* EGLNativeDisplayType; +typedef void* EGLNativeWindowType; + +// EGL function pointer typedefs +typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); +typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); +typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum); +typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); +typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); +typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); +typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*); +#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib +#define eglGetConfigs _glfw.egl.GetConfigs +#define eglGetDisplay _glfw.egl.GetDisplay +#define eglGetError _glfw.egl.GetError +#define eglInitialize _glfw.egl.Initialize +#define eglTerminate _glfw.egl.Terminate +#define eglBindAPI _glfw.egl.BindAPI +#define eglCreateContext _glfw.egl.CreateContext +#define eglDestroySurface _glfw.egl.DestroySurface +#define eglDestroyContext _glfw.egl.DestroyContext +#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface +#define eglMakeCurrent _glfw.egl.MakeCurrent +#define eglSwapBuffers _glfw.egl.SwapBuffers +#define eglSwapInterval _glfw.egl.SwapInterval +#define eglQueryString _glfw.egl.QueryString +#define eglGetProcAddress _glfw.egl.GetProcAddress + +typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum,void*,const EGLint*); +typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay,EGLConfig,void*,const EGLint*); +#define eglGetPlatformDisplayEXT _glfw.egl.GetPlatformDisplayEXT +#define eglCreatePlatformWindowSurfaceEXT _glfw.egl.CreatePlatformWindowSurfaceEXT + +// EGL-specific per-context data +// +typedef struct _GLFWcontextEGL +{ + EGLConfig config; + EGLContext handle; + EGLSurface surface; + + void* client; + +} _GLFWcontextEGL; + +// EGL-specific global data +// +typedef struct _GLFWlibraryEGL +{ + EGLenum platform; + EGLDisplay display; + EGLint major, minor; + GLFWbool prefix; + + GLFWbool KHR_create_context; + GLFWbool KHR_create_context_no_error; + GLFWbool KHR_gl_colorspace; + GLFWbool KHR_get_all_proc_addresses; + GLFWbool KHR_context_flush_control; + GLFWbool EXT_client_extensions; + GLFWbool EXT_platform_base; + GLFWbool EXT_platform_x11; + GLFWbool EXT_platform_wayland; + GLFWbool ANGLE_platform_angle; + GLFWbool ANGLE_platform_angle_opengl; + GLFWbool ANGLE_platform_angle_d3d; + GLFWbool ANGLE_platform_angle_vulkan; + GLFWbool ANGLE_platform_angle_metal; + + void* handle; + + PFN_eglGetConfigAttrib GetConfigAttrib; + PFN_eglGetConfigs GetConfigs; + PFN_eglGetDisplay GetDisplay; + PFN_eglGetError GetError; + PFN_eglInitialize Initialize; + PFN_eglTerminate Terminate; + PFN_eglBindAPI BindAPI; + PFN_eglCreateContext CreateContext; + PFN_eglDestroySurface DestroySurface; + PFN_eglDestroyContext DestroyContext; + PFN_eglCreateWindowSurface CreateWindowSurface; + PFN_eglMakeCurrent MakeCurrent; + PFN_eglSwapBuffers SwapBuffers; + PFN_eglSwapInterval SwapInterval; + PFN_eglQueryString QueryString; + PFN_eglGetProcAddress GetProcAddress; + + PFNEGLGETPLATFORMDISPLAYEXTPROC GetPlatformDisplayEXT; + PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC CreatePlatformWindowSurfaceEXT; + +} _GLFWlibraryEGL; + + +GLFWbool _glfwInitEGL(void); +void _glfwTerminateEGL(void); +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +#if defined(_GLFW_X11) +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth); +#endif /*_GLFW_X11*/ + diff --git a/raylib/external/glfw/src/fractional-scale-v1-client-protocol-code.h b/raylib/external/glfw/src/fractional-scale-v1-client-protocol-code.h deleted file mode 100644 index f847c1e..0000000 --- a/raylib/external/glfw/src/fractional-scale-v1-client-protocol-code.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * Copyright © 2022 Kenny Levinsen - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include "wayland-util.h" - -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - -extern const struct wl_interface wl_surface_interface; -extern const struct wl_interface wp_fractional_scale_v1_interface; - -static const struct wl_interface *fractional_scale_v1_types[] = { - NULL, - &wp_fractional_scale_v1_interface, - &wl_surface_interface, -}; - -static const struct wl_message wp_fractional_scale_manager_v1_requests[] = { - { "destroy", "", fractional_scale_v1_types + 0 }, - { "get_fractional_scale", "no", fractional_scale_v1_types + 1 }, -}; - -WL_PRIVATE const struct wl_interface wp_fractional_scale_manager_v1_interface = { - "wp_fractional_scale_manager_v1", 1, - 2, wp_fractional_scale_manager_v1_requests, - 0, NULL, -}; - -static const struct wl_message wp_fractional_scale_v1_requests[] = { - { "destroy", "", fractional_scale_v1_types + 0 }, -}; - -static const struct wl_message wp_fractional_scale_v1_events[] = { - { "preferred_scale", "u", fractional_scale_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wp_fractional_scale_v1_interface = { - "wp_fractional_scale_v1", 1, - 1, wp_fractional_scale_v1_requests, - 1, wp_fractional_scale_v1_events, -}; - diff --git a/raylib/external/glfw/src/fractional-scale-v1-client-protocol.h b/raylib/external/glfw/src/fractional-scale-v1-client-protocol.h deleted file mode 100644 index 8df7558..0000000 --- a/raylib/external/glfw/src/fractional-scale-v1-client-protocol.h +++ /dev/null @@ -1,264 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H -#define FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_fractional_scale_v1 The fractional_scale_v1 protocol - * Protocol for requesting fractional surface scales - * - * @section page_desc_fractional_scale_v1 Description - * - * This protocol allows a compositor to suggest for surfaces to render at - * fractional scales. - * - * A client can submit scaled content by utilizing wp_viewport. This is done by - * creating a wp_viewport object for the surface and setting the destination - * rectangle to the surface size before the scale factor is applied. - * - * The buffer size is calculated by multiplying the surface size by the - * intended scale. - * - * The wl_surface buffer scale should remain set to 1. - * - * If a surface has a surface-local size of 100 px by 50 px and wishes to - * submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should - * be used and the wp_viewport destination rectangle should be 100 px by 50 px. - * - * For toplevel surfaces, the size is rounded halfway away from zero. The - * rounding algorithm for subsurface position and size is not defined. - * - * @section page_ifaces_fractional_scale_v1 Interfaces - * - @subpage page_iface_wp_fractional_scale_manager_v1 - fractional surface scale information - * - @subpage page_iface_wp_fractional_scale_v1 - fractional scale interface to a wl_surface - * @section page_copyright_fractional_scale_v1 Copyright - *
- *
- * Copyright © 2022 Kenny Levinsen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- * 
- */ -struct wl_surface; -struct wp_fractional_scale_manager_v1; -struct wp_fractional_scale_v1; - -#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE -#define WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE -/** - * @page page_iface_wp_fractional_scale_manager_v1 wp_fractional_scale_manager_v1 - * @section page_iface_wp_fractional_scale_manager_v1_desc Description - * - * A global interface for requesting surfaces to use fractional scales. - * @section page_iface_wp_fractional_scale_manager_v1_api API - * See @ref iface_wp_fractional_scale_manager_v1. - */ -/** - * @defgroup iface_wp_fractional_scale_manager_v1 The wp_fractional_scale_manager_v1 interface - * - * A global interface for requesting surfaces to use fractional scales. - */ -extern const struct wl_interface wp_fractional_scale_manager_v1_interface; -#endif -#ifndef WP_FRACTIONAL_SCALE_V1_INTERFACE -#define WP_FRACTIONAL_SCALE_V1_INTERFACE -/** - * @page page_iface_wp_fractional_scale_v1 wp_fractional_scale_v1 - * @section page_iface_wp_fractional_scale_v1_desc Description - * - * An additional interface to a wl_surface object which allows the compositor - * to inform the client of the preferred scale. - * @section page_iface_wp_fractional_scale_v1_api API - * See @ref iface_wp_fractional_scale_v1. - */ -/** - * @defgroup iface_wp_fractional_scale_v1 The wp_fractional_scale_v1 interface - * - * An additional interface to a wl_surface object which allows the compositor - * to inform the client of the preferred scale. - */ -extern const struct wl_interface wp_fractional_scale_v1_interface; -#endif - -#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM -#define WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM -enum wp_fractional_scale_manager_v1_error { - /** - * the surface already has a fractional_scale object associated - */ - WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS = 0, -}; -#endif /* WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM */ - -#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY 0 -#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE 1 - - -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - */ -#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - */ -#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE_SINCE_VERSION 1 - -/** @ingroup iface_wp_fractional_scale_manager_v1 */ -static inline void -wp_fractional_scale_manager_v1_set_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1, user_data); -} - -/** @ingroup iface_wp_fractional_scale_manager_v1 */ -static inline void * -wp_fractional_scale_manager_v1_get_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1); -} - -static inline uint32_t -wp_fractional_scale_manager_v1_get_version(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1); -} - -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - * - * Informs the server that the client will not be using this protocol - * object anymore. This does not affect any other objects, - * wp_fractional_scale_v1 objects included. - */ -static inline void -wp_fractional_scale_manager_v1_destroy(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, - WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - * - * Create an add-on object for the the wl_surface to let the compositor - * request fractional scales. If the given wl_surface already has a - * wp_fractional_scale_v1 object associated, the fractional_scale_exists - * protocol error is raised. - */ -static inline struct wp_fractional_scale_v1 * -wp_fractional_scale_manager_v1_get_fractional_scale(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, - WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE, &wp_fractional_scale_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), 0, NULL, surface); - - return (struct wp_fractional_scale_v1 *) id; -} - -/** - * @ingroup iface_wp_fractional_scale_v1 - * @struct wp_fractional_scale_v1_listener - */ -struct wp_fractional_scale_v1_listener { - /** - * notify of new preferred scale - * - * Notification of a new preferred scale for this surface that - * the compositor suggests that the client should use. - * - * The sent scale is the numerator of a fraction with a denominator - * of 120. - * @param scale the new preferred scale - */ - void (*preferred_scale)(void *data, - struct wp_fractional_scale_v1 *wp_fractional_scale_v1, - uint32_t scale); -}; - -/** - * @ingroup iface_wp_fractional_scale_v1 - */ -static inline int -wp_fractional_scale_v1_add_listener(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, - const struct wp_fractional_scale_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wp_fractional_scale_v1, - (void (**)(void)) listener, data); -} - -#define WP_FRACTIONAL_SCALE_V1_DESTROY 0 - -/** - * @ingroup iface_wp_fractional_scale_v1 - */ -#define WP_FRACTIONAL_SCALE_V1_PREFERRED_SCALE_SINCE_VERSION 1 - -/** - * @ingroup iface_wp_fractional_scale_v1 - */ -#define WP_FRACTIONAL_SCALE_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_wp_fractional_scale_v1 */ -static inline void -wp_fractional_scale_v1_set_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_v1, user_data); -} - -/** @ingroup iface_wp_fractional_scale_v1 */ -static inline void * -wp_fractional_scale_v1_get_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_v1); -} - -static inline uint32_t -wp_fractional_scale_v1_get_version(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1); -} - -/** - * @ingroup iface_wp_fractional_scale_v1 - * - * Destroy the fractional scale object. When this object is destroyed, - * preferred_scale events will no longer be sent. - */ -static inline void -wp_fractional_scale_v1_destroy(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_v1, - WP_FRACTIONAL_SCALE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1), WL_MARSHAL_FLAG_DESTROY); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/raylib/external/glfw/src/glx_context.c b/raylib/external/glfw/src/glx_context.c index 7082682..7ccd137 100644 --- a/raylib/external/glfw/src/glx_context.c +++ b/raylib/external/glfw/src/glx_context.c @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_X11) - #include #include #include @@ -55,7 +55,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; - int nativeCount, usableCount; + int i, nativeCount, usableCount; const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; @@ -73,10 +73,10 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, return GLFW_FALSE; } - usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; - for (int i = 0; i < nativeCount; i++) + for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; _GLFWfbconfig* u = usableConfigs + usableCount; @@ -92,9 +92,6 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, continue; } - if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER) != desired->doublebuffer) - continue; - if (desired->transparent) { XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n); @@ -122,6 +119,8 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, if (getGLXFBConfigAttrib(n, GLX_STEREO)) u->stereo = GLFW_TRUE; + if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER)) + u->doublebuffer = GLFW_TRUE; if (_glfw.glx.ARB_multisample) u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); @@ -138,7 +137,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, *result = (GLXFBConfig) closest->handle; XFree(nativeConfigs); - _glfw_free(usableConfigs); + free(usableConfigs); return closest != NULL; } @@ -190,7 +189,6 @@ static void swapBuffersGLX(_GLFWwindow* window) static void swapIntervalGLX(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - assert(window != NULL); if (_glfw.glx.EXT_swap_control) { @@ -227,10 +225,7 @@ static GLFWglproc getProcAddressGLX(const char* procname) else if (_glfw.glx.GetProcAddressARB) return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); else - { - // NOTE: glvnd provides GLX 1.4, so this can only happen with libGL - return _glfwPlatformGetModuleSymbol(_glfw.glx.handle, procname); - } + return _glfw_dlsym(_glfw.glx.handle, procname); } static void destroyContextGLX(_GLFWwindow* window) @@ -257,16 +252,14 @@ static void destroyContextGLX(_GLFWwindow* window) // GLFWbool _glfwInitGLX(void) { + int i; const char* sonames[] = { #if defined(_GLFW_GLX_LIBRARY) _GLFW_GLX_LIBRARY, #elif defined(__CYGWIN__) "libGL-1.so", -#elif defined(__OpenBSD__) || defined(__NetBSD__) - "libGL.so", #else - "libGLX.so.0", "libGL.so.1", "libGL.so", #endif @@ -276,9 +269,9 @@ GLFWbool _glfwInitGLX(void) if (_glfw.glx.handle) return GLFW_TRUE; - for (int i = 0; sonames[i]; i++) + for (i = 0; sonames[i]; i++) { - _glfw.glx.handle = _glfwPlatformLoadModule(sonames[i]); + _glfw.glx.handle = _glfw_dlopen(sonames[i]); if (_glfw.glx.handle) break; } @@ -289,32 +282,36 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } - _glfw.glx.GetFBConfigs = (PFNGLXGETFBCONFIGSPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetFBConfigs"); - _glfw.glx.GetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetFBConfigAttrib"); - _glfw.glx.GetClientString = (PFNGLXGETCLIENTSTRINGPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetClientString"); - _glfw.glx.QueryExtension = (PFNGLXQUERYEXTENSIONPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXQueryExtension"); - _glfw.glx.QueryVersion = (PFNGLXQUERYVERSIONPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXQueryVersion"); - _glfw.glx.DestroyContext = (PFNGLXDESTROYCONTEXTPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXDestroyContext"); - _glfw.glx.MakeCurrent = (PFNGLXMAKECURRENTPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXMakeCurrent"); - _glfw.glx.SwapBuffers = (PFNGLXSWAPBUFFERSPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXSwapBuffers"); - _glfw.glx.QueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRINGPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXQueryExtensionsString"); - _glfw.glx.CreateNewContext = (PFNGLXCREATENEWCONTEXTPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateNewContext"); - _glfw.glx.CreateWindow = (PFNGLXCREATEWINDOWPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateWindow"); - _glfw.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXDestroyWindow"); - _glfw.glx.GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetVisualFromFBConfig"); + _glfw.glx.GetFBConfigs = + _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs"); + _glfw.glx.GetFBConfigAttrib = + _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); + _glfw.glx.GetClientString = + _glfw_dlsym(_glfw.glx.handle, "glXGetClientString"); + _glfw.glx.QueryExtension = + _glfw_dlsym(_glfw.glx.handle, "glXQueryExtension"); + _glfw.glx.QueryVersion = + _glfw_dlsym(_glfw.glx.handle, "glXQueryVersion"); + _glfw.glx.DestroyContext = + _glfw_dlsym(_glfw.glx.handle, "glXDestroyContext"); + _glfw.glx.MakeCurrent = + _glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent"); + _glfw.glx.SwapBuffers = + _glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers"); + _glfw.glx.QueryExtensionsString = + _glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); + _glfw.glx.CreateNewContext = + _glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext"); + _glfw.glx.CreateWindow = + _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow"); + _glfw.glx.DestroyWindow = + _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow"); + _glfw.glx.GetProcAddress = + _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress"); + _glfw.glx.GetProcAddressARB = + _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); + _glfw.glx.GetVisualFromFBConfig = + _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); if (!_glfw.glx.GetFBConfigs || !_glfw.glx.GetFBConfigAttrib || @@ -328,6 +325,8 @@ GLFWbool _glfwInitGLX(void) !_glfw.glx.CreateNewContext || !_glfw.glx.CreateWindow || !_glfw.glx.DestroyWindow || + !_glfw.glx.GetProcAddress || + !_glfw.glx.GetProcAddressARB || !_glfw.glx.GetVisualFromFBConfig) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -335,12 +334,6 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } - // NOTE: Unlike GLX 1.3 entry points these are not required to be present - _glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress"); - _glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB"); - if (!glXQueryExtension(_glfw.x11.display, &_glfw.glx.errorBase, &_glfw.glx.eventBase)) @@ -431,16 +424,16 @@ GLFWbool _glfwInitGLX(void) void _glfwTerminateGLX(void) { // NOTE: This function must not call any X11 functions, as it is called - // after XCloseDisplay (see _glfwTerminateX11 for details) + // after XCloseDisplay (see _glfwPlatformTerminate for details) if (_glfw.glx.handle) { - _glfwPlatformFreeModule(_glfw.glx.handle); + _glfw_dlclose(_glfw.glx.handle); _glfw.glx.handle = NULL; } } -#define SET_ATTRIB(a, v) \ +#define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -528,13 +521,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_NO_RESET_NOTIFICATION_ARB); + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_LOSE_CONTEXT_ON_RESET_ARB); + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); } flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -547,13 +540,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -561,7 +554,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.glx.ARB_create_context_no_error) - SET_ATTRIB(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -569,17 +562,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - SET_ATTRIB(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - SET_ATTRIB(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) - SET_ATTRIB(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) - SET_ATTRIB(GLX_CONTEXT_FLAGS_ARB, flags); + setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); - SET_ATTRIB(None, None); + setAttrib(None, None); window->context.glx.handle = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, @@ -636,7 +629,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_TRUE; } -#undef SET_ATTRIB +#undef setAttrib // Returns the Visual and depth of the chosen GLXFBConfig // @@ -680,13 +673,7 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "GLX: Platform not initialized"); - return NULL; - } - - if (window->context.source != GLFW_NATIVE_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -700,13 +687,7 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "GLX: Platform not initialized"); - return None; - } - - if (window->context.source != GLFW_NATIVE_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return None; @@ -715,5 +696,3 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) return window->context.glx.window; } -#endif // _GLFW_X11 - diff --git a/raylib/external/glfw/src/glx_context.h b/raylib/external/glfw/src/glx_context.h new file mode 100644 index 0000000..94f07e2 --- /dev/null +++ b/raylib/external/glfw/src/glx_context.h @@ -0,0 +1,181 @@ +//======================================================================== +// GLFW 3.4 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define GLX_VENDOR 1 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_DOUBLEBUFFER 5 +#define GLX_STEREO 6 +#define GLX_AUX_BUFFERS 7 +#define GLX_RED_SIZE 8 +#define GLX_GREEN_SIZE 9 +#define GLX_BLUE_SIZE 10 +#define GLX_ALPHA_SIZE 11 +#define GLX_DEPTH_SIZE 12 +#define GLX_STENCIL_SIZE 13 +#define GLX_ACCUM_RED_SIZE 14 +#define GLX_ACCUM_GREEN_SIZE 15 +#define GLX_ACCUM_BLUE_SIZE 16 +#define GLX_ACCUM_ALPHA_SIZE 17 +#define GLX_SAMPLES 0x186a1 +#define GLX_VISUAL_ID 0x800b + +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 + +typedef XID GLXWindow; +typedef XID GLXDrawable; +typedef struct __GLXFBConfig* GLXFBConfig; +typedef struct __GLXcontext* GLXContext; +typedef void (*__GLXextproc)(void); + +typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); +typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); +typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); +typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*); +typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext); +typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); +typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); +typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); +typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); +typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool); +typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName); +typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); +typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); +typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); +typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); + +typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); +typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); + +// libGL.so function pointer typedefs +#define glXGetFBConfigs _glfw.glx.GetFBConfigs +#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib +#define glXGetClientString _glfw.glx.GetClientString +#define glXQueryExtension _glfw.glx.QueryExtension +#define glXQueryVersion _glfw.glx.QueryVersion +#define glXDestroyContext _glfw.glx.DestroyContext +#define glXMakeCurrent _glfw.glx.MakeCurrent +#define glXSwapBuffers _glfw.glx.SwapBuffers +#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString +#define glXCreateNewContext _glfw.glx.CreateNewContext +#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig +#define glXCreateWindow _glfw.glx.CreateWindow +#define glXDestroyWindow _glfw.glx.DestroyWindow + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx + + +// GLX-specific per-context data +// +typedef struct _GLFWcontextGLX +{ + GLXContext handle; + GLXWindow window; + +} _GLFWcontextGLX; + +// GLX-specific global data +// +typedef struct _GLFWlibraryGLX +{ + int major, minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // GLX 1.3 functions + PFNGLXGETFBCONFIGSPROC GetFBConfigs; + PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; + PFNGLXGETCLIENTSTRINGPROC GetClientString; + PFNGLXQUERYEXTENSIONPROC QueryExtension; + PFNGLXQUERYVERSIONPROC QueryVersion; + PFNGLXDESTROYCONTEXTPROC DestroyContext; + PFNGLXMAKECURRENTPROC MakeCurrent; + PFNGLXSWAPBUFFERSPROC SwapBuffers; + PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; + PFNGLXCREATENEWCONTEXTPROC CreateNewContext; + PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; + PFNGLXCREATEWINDOWPROC CreateWindow; + PFNGLXDESTROYWINDOWPROC DestroyWindow; + + // GLX 1.4 and extension functions + PFNGLXGETPROCADDRESSPROC GetProcAddress; + PFNGLXGETPROCADDRESSPROC GetProcAddressARB; + PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; + PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; + PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool SGI_swap_control; + GLFWbool EXT_swap_control; + GLFWbool MESA_swap_control; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_no_error; + GLFWbool ARB_context_flush_control; + +} _GLFWlibraryGLX; + +GLFWbool _glfwInitGLX(void); +void _glfwTerminateGLX(void); +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContextGLX(_GLFWwindow* window); +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth); + diff --git a/raylib/external/glfw/src/init.c b/raylib/external/glfw/src/init.c index 532264e..a7b5af6 100644 --- a/raylib/external/glfw/src/init.c +++ b/raylib/external/glfw/src/init.c @@ -24,8 +24,11 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" +#include "mappings.h" #include #include @@ -34,61 +37,29 @@ #include -// NOTE: The global variables below comprise all mutable global data in GLFW -// Any other mutable global variable is a bug +// The global variables below comprise all mutable global data in GLFW +// +// Any other global variable is a bug -// This contains all mutable state shared between compilation units of GLFW +// Global state shared between compilation units of GLFW // _GLFWlibrary _glfw = { GLFW_FALSE }; // These are outside of _glfw so they can be used before initialization and -// after termination without special handling when _glfw is cleared to zero +// after termination // static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback; -static GLFWallocator _glfwInitAllocator; static _GLFWinitconfig _glfwInitHints = { - .hatButtons = GLFW_TRUE, - .angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE, - .platformID = GLFW_ANY_PLATFORM, - .vulkanLoader = NULL, - .ns = + GLFW_TRUE, // hat buttons + GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend { - .menubar = GLFW_TRUE, - .chdir = GLFW_TRUE - }, - .x11 = - { - .xcbVulkanSurface = GLFW_TRUE, - }, - .wl = - { - .libdecorMode = GLFW_WAYLAND_PREFER_LIBDECOR - }, + GLFW_TRUE, // macOS menu bar + GLFW_TRUE // macOS bundle chdir + } }; -// The allocation function used when no custom allocator is set -// -static void* defaultAllocate(size_t size, void* user) -{ - return malloc(size); -} - -// The deallocation function used when no custom allocator is set -// -static void defaultDeallocate(void* block, void* user) -{ - free(block); -} - -// The reallocation function used when no custom allocator is set -// -static void* defaultReallocate(void* block, size_t size, void* user) -{ - return realloc(block, size); -} - // Terminate the library // static void terminate(void) @@ -107,21 +78,21 @@ static void terminate(void) { _GLFWmonitor* monitor = _glfw.monitors[i]; if (monitor->originalRamp.size) - _glfw.platform.setGammaRamp(monitor, &monitor->originalRamp); + _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); _glfwFreeMonitor(monitor); } - _glfw_free(_glfw.monitors); + free(_glfw.monitors); _glfw.monitors = NULL; _glfw.monitorCount = 0; - _glfw_free(_glfw.mappings); + free(_glfw.mappings); _glfw.mappings = NULL; _glfw.mappingCount = 0; _glfwTerminateVulkan(); - _glfw.platform.terminateJoysticks(); - _glfw.platform.terminate(); + _glfwPlatformTerminateJoysticks(); + _glfwPlatformTerminate(); _glfw.initialized = GLFW_FALSE; @@ -129,7 +100,7 @@ static void terminate(void) { _GLFWerror* error = _glfw.errorListHead; _glfw.errorListHead = error->next; - _glfw_free(error); + free(error); } _glfwPlatformDestroyTls(&_glfw.contextSlot); @@ -144,159 +115,36 @@ static void terminate(void) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Encode a Unicode code point to a UTF-8 stream -// Based on cutef8 by Jeff Bezanson (Public Domain) -// -size_t _glfwEncodeUTF8(char* s, uint32_t codepoint) -{ - size_t count = 0; - - if (codepoint < 0x80) - s[count++] = (char) codepoint; - else if (codepoint < 0x800) - { - s[count++] = (codepoint >> 6) | 0xc0; - s[count++] = (codepoint & 0x3f) | 0x80; - } - else if (codepoint < 0x10000) - { - s[count++] = (codepoint >> 12) | 0xe0; - s[count++] = ((codepoint >> 6) & 0x3f) | 0x80; - s[count++] = (codepoint & 0x3f) | 0x80; - } - else if (codepoint < 0x110000) - { - s[count++] = (codepoint >> 18) | 0xf0; - s[count++] = ((codepoint >> 12) & 0x3f) | 0x80; - s[count++] = ((codepoint >> 6) & 0x3f) | 0x80; - s[count++] = (codepoint & 0x3f) | 0x80; - } - - return count; -} - -// Splits and translates a text/uri-list into separate file paths -// NOTE: This function destroys the provided string -// -char** _glfwParseUriList(char* text, int* count) -{ - const char* prefix = "file://"; - char** paths = NULL; - char* line; - - *count = 0; - - while ((line = strtok(text, "\r\n"))) - { - char* path; - - text = NULL; - - if (line[0] == '#') - continue; - - if (strncmp(line, prefix, strlen(prefix)) == 0) - { - line += strlen(prefix); - // TODO: Validate hostname - while (*line != '/') - line++; - } - - (*count)++; - - path = _glfw_calloc(strlen(line) + 1, 1); - paths = _glfw_realloc(paths, *count * sizeof(char*)); - paths[*count - 1] = path; - - while (*line) - { - if (line[0] == '%' && line[1] && line[2]) - { - const char digits[3] = { line[1], line[2], '\0' }; - *path = (char) strtol(digits, NULL, 16); - line += 2; - } - else - *path = *line; - - path++; - line++; - } - } - - return paths; -} - char* _glfw_strdup(const char* source) { const size_t length = strlen(source); - char* result = _glfw_calloc(length + 1, 1); + char* result = calloc(length + 1, 1); strcpy(result, source); return result; } -int _glfw_min(int a, int b) +float _glfw_fminf(float a, float b) { - return a < b ? a : b; -} - -int _glfw_max(int a, int b) -{ - return a > b ? a : b; -} - -void* _glfw_calloc(size_t count, size_t size) -{ - if (count && size) - { - void* block; - - if (count > SIZE_MAX / size) - { - _glfwInputError(GLFW_INVALID_VALUE, "Allocation size overflow"); - return NULL; - } - - block = _glfw.allocator.allocate(count * size, _glfw.allocator.user); - if (block) - return memset(block, 0, count * size); - else - { - _glfwInputError(GLFW_OUT_OF_MEMORY, NULL); - return NULL; - } - } + if (a != a) + return b; + else if (b != b) + return a; + else if (a < b) + return a; else - return NULL; + return b; } -void* _glfw_realloc(void* block, size_t size) +float _glfw_fmaxf(float a, float b) { - if (block && size) - { - void* resized = _glfw.allocator.reallocate(block, size, _glfw.allocator.user); - if (resized) - return resized; - else - { - _glfwInputError(GLFW_OUT_OF_MEMORY, NULL); - return NULL; - } - } - else if (block) - { - _glfw_free(block); - return NULL; - } + if (a != a) + return b; + else if (b != b) + return a; + else if (a > b) + return a; else - return _glfw_calloc(1, size); -} - -void _glfw_free(void* block) -{ - if (block) - _glfw.allocator.deallocate(block, _glfw.allocator.user); + return b; } @@ -349,8 +197,6 @@ void _glfwInputError(int code, const char* format, ...) strcpy(description, "The requested feature cannot be implemented for this platform"); else if (code == GLFW_FEATURE_UNIMPLEMENTED) strcpy(description, "The requested feature has not yet been implemented for this platform"); - else if (code == GLFW_PLATFORM_UNAVAILABLE) - strcpy(description, "The requested platform is unavailable"); else strcpy(description, "ERROR: UNKNOWN GLFW ERROR"); } @@ -360,7 +206,7 @@ void _glfwInputError(int code, const char* format, ...) error = _glfwPlatformGetTls(&_glfw.errorSlot); if (!error) { - error = _glfw_calloc(1, sizeof(_GLFWerror)); + error = calloc(1, sizeof(_GLFWerror)); _glfwPlatformSetTls(&_glfw.errorSlot, error); _glfwPlatformLockMutex(&_glfw.errorLock); error->next = _glfw.errorListHead; @@ -391,18 +237,7 @@ GLFWAPI int glfwInit(void) memset(&_glfw, 0, sizeof(_glfw)); _glfw.hints.init = _glfwInitHints; - _glfw.allocator = _glfwInitAllocator; - if (!_glfw.allocator.allocate) - { - _glfw.allocator.allocate = defaultAllocate; - _glfw.allocator.reallocate = defaultReallocate; - _glfw.allocator.deallocate = defaultDeallocate; - } - - if (!_glfwSelectPlatform(_glfw.hints.init.platformID, &_glfw.platform)) - return GLFW_FALSE; - - if (!_glfw.platform.init()) + if (!_glfwPlatformInit()) { terminate(); return GLFW_FALSE; @@ -418,14 +253,24 @@ GLFWAPI int glfwInit(void) _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); - _glfwInitGamepadMappings(); - - _glfwPlatformInitTimer(); + _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); - _glfw.initialized = GLFW_TRUE; - glfwDefaultWindowHints(); + + { + int i; + + for (i = 0; _glfwDefaultMappings[i]; i++) + { + if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i])) + { + terminate(); + return GLFW_FALSE; + } + } + } + return GLFW_TRUE; } @@ -447,45 +292,18 @@ GLFWAPI void glfwInitHint(int hint, int value) case GLFW_ANGLE_PLATFORM_TYPE: _glfwInitHints.angleType = value; return; - case GLFW_PLATFORM: - _glfwInitHints.platformID = value; - return; case GLFW_COCOA_CHDIR_RESOURCES: _glfwInitHints.ns.chdir = value; return; case GLFW_COCOA_MENUBAR: _glfwInitHints.ns.menubar = value; return; - case GLFW_X11_XCB_VULKAN_SURFACE: - _glfwInitHints.x11.xcbVulkanSurface = value; - return; - case GLFW_WAYLAND_LIBDECOR: - _glfwInitHints.wl.libdecorMode = value; - return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid init hint 0x%08X", hint); } -GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator) -{ - if (allocator) - { - if (allocator->allocate && allocator->reallocate && allocator->deallocate) - _glfwInitAllocator = *allocator; - else - _glfwInputError(GLFW_INVALID_VALUE, "Missing function in allocator"); - } - else - memset(&_glfwInitAllocator, 0, sizeof(GLFWallocator)); -} - -GLFWAPI void glfwInitVulkanLoader(PFN_vkGetInstanceProcAddr loader) -{ - _glfwInitHints.vulkanLoader = loader; -} - GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) { if (major != NULL) @@ -496,6 +314,11 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) *rev = GLFW_VERSION_REVISION; } +GLFWAPI const char* glfwGetVersionString(void) +{ + return _glfwPlatformGetVersionString(); +} + GLFWAPI int glfwGetError(const char** description) { _GLFWerror* error; @@ -522,7 +345,7 @@ GLFWAPI int glfwGetError(const char** description) GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) { - _GLFW_SWAP(GLFWerrorfun, _glfwErrorCallback, cbfun); + _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); return cbfun; } diff --git a/raylib/external/glfw/src/input.c b/raylib/external/glfw/src/input.c index 7b3b340..226f835 100644 --- a/raylib/external/glfw/src/input.c +++ b/raylib/external/glfw/src/input.c @@ -24,9 +24,10 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#include "mappings.h" #include #include @@ -42,22 +43,15 @@ #define _GLFW_JOYSTICK_BUTTON 2 #define _GLFW_JOYSTICK_HATBIT 3 -#define GLFW_MOD_MASK (GLFW_MOD_SHIFT | \ - GLFW_MOD_CONTROL | \ - GLFW_MOD_ALT | \ - GLFW_MOD_SUPER | \ - GLFW_MOD_CAPS_LOCK | \ - GLFW_MOD_NUM_LOCK) - // Initializes the platform joystick API if it has not been already // static GLFWbool initJoysticks(void) { if (!_glfw.joysticksInitialized) { - if (!_glfw.platform.initJoysticks()) + if (!_glfwPlatformInitJoysticks()) { - _glfw.platform.terminateJoysticks(); + _glfwPlatformTerminateJoysticks(); return GLFW_FALSE; } } @@ -107,13 +101,25 @@ static _GLFWmapping* findValidMapping(const _GLFWjoystick* js) for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { if (!isValidElementForJoystick(mapping->buttons + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid button in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); return NULL; + } } for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) { if (!isValidElementForJoystick(mapping->axes + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid axis in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); return NULL; + } } } @@ -239,9 +245,8 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) } else { - const char* name = _glfw.platform.getMappingName(); - length = strlen(name); - if (strncmp(c, name, length) != 0) + length = strlen(_GLFW_PLATFORM_MAPPING_NAME); + if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) return GLFW_FALSE; } @@ -258,7 +263,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) mapping->guid[i] += 'a' - 'A'; } - _glfw.platform.updateGamepadGUID(mapping->guid); + _glfwPlatformUpdateGamepadGUID(mapping->guid); return GLFW_TRUE; } @@ -271,12 +276,6 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) // void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) { - assert(window != NULL); - assert(key >= 0 || key == GLFW_KEY_UNKNOWN); - assert(key <= GLFW_KEY_LAST); - assert(action == GLFW_PRESS || action == GLFW_RELEASE); - assert(mods == (mods & GLFW_MOD_MASK)); - if (key >= 0 && key <= GLFW_KEY_LAST) { GLFWbool repeated = GLFW_FALSE; @@ -306,12 +305,8 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m // Notifies shared code of a Unicode codepoint input event // The 'plain' parameter determines whether to emit a regular character event // -void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool plain) +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain) { - assert(window != NULL); - assert(mods == (mods & GLFW_MOD_MASK)); - assert(plain == GLFW_TRUE || plain == GLFW_FALSE); - if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return; @@ -332,12 +327,6 @@ void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool // void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) { - assert(window != NULL); - assert(xoffset > -FLT_MAX); - assert(xoffset < FLT_MAX); - assert(yoffset > -FLT_MAX); - assert(yoffset < FLT_MAX); - if (window->callbacks.scroll) window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); } @@ -346,12 +335,6 @@ void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) // void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) { - assert(window != NULL); - assert(button >= 0); - assert(button <= GLFW_MOUSE_BUTTON_LAST); - assert(action == GLFW_PRESS || action == GLFW_RELEASE); - assert(mods == (mods & GLFW_MOD_MASK)); - if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) return; @@ -372,12 +355,6 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) // void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) { - assert(window != NULL); - assert(xpos > -FLT_MAX); - assert(xpos < FLT_MAX); - assert(ypos > -FLT_MAX); - assert(ypos < FLT_MAX); - if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos) return; @@ -392,9 +369,6 @@ void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) // void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) { - assert(window != NULL); - assert(entered == GLFW_TRUE || entered == GLFW_FALSE); - if (window->callbacks.cursorEnter) window->callbacks.cursorEnter((GLFWwindow*) window, entered); } @@ -403,10 +377,6 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) // void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) { - assert(window != NULL); - assert(count > 0); - assert(paths != NULL); - if (window->callbacks.drop) window->callbacks.drop((GLFWwindow*) window, count, paths); } @@ -415,26 +385,16 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) // void _glfwInputJoystick(_GLFWjoystick* js, int event) { - assert(js != NULL); - assert(event == GLFW_CONNECTED || event == GLFW_DISCONNECTED); - - if (event == GLFW_CONNECTED) - js->connected = GLFW_TRUE; - else if (event == GLFW_DISCONNECTED) - js->connected = GLFW_FALSE; + const int jid = (int) (js - _glfw.joysticks); if (_glfw.callbacks.joystick) - _glfw.callbacks.joystick((int) (js - _glfw.joysticks), event); + _glfw.callbacks.joystick(jid, event); } // Notifies shared code of the new value of a joystick axis // void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) { - assert(js != NULL); - assert(axis >= 0); - assert(axis < js->axisCount); - js->axes[axis] = value; } @@ -442,11 +402,6 @@ void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) // void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) { - assert(js != NULL); - assert(button >= 0); - assert(button < js->buttonCount); - assert(value == GLFW_PRESS || value == GLFW_RELEASE); - js->buttons[button] = value; } @@ -454,19 +409,7 @@ void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) // void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { - int base; - - assert(js != NULL); - assert(hat >= 0); - assert(hat < js->hatCount); - - // Valid hat values only use the least significant nibble - assert((value & 0xf0) == 0); - // Valid hat values do not have both bits of an axis set - assert((value & GLFW_HAT_LEFT) == 0 || (value & GLFW_HAT_RIGHT) == 0); - assert((value & GLFW_HAT_UP) == 0 || (value & GLFW_HAT_DOWN) == 0); - - base = js->buttonCount + hat * 4; + const int base = js->buttonCount + hat * 4; js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; @@ -481,21 +424,6 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Adds the built-in set of gamepad mappings -// -void _glfwInitGamepadMappings(void) -{ - size_t i; - const size_t count = sizeof(_glfwDefaultMappings) / sizeof(char*); - _glfw.mappings = _glfw_calloc(count, sizeof(_GLFWmapping)); - - for (i = 0; i < count; i++) - { - if (parseMapping(&_glfw.mappings[_glfw.mappingCount], _glfwDefaultMappings[i])) - _glfw.mappingCount++; - } -} - // Returns an available joystick object with arrays and name allocated // _GLFWjoystick* _glfwAllocJoystick(const char* name, @@ -509,7 +437,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].allocated) + if (!_glfw.joysticks[jid].present) break; } @@ -517,15 +445,15 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, return NULL; js = _glfw.joysticks + jid; - js->allocated = GLFW_TRUE; - js->axes = _glfw_calloc(axisCount, sizeof(float)); - js->buttons = _glfw_calloc(buttonCount + (size_t) hatCount * 4, 1); - js->hats = _glfw_calloc(hatCount, 1); + js->present = GLFW_TRUE; + js->name = _glfw_strdup(name); + js->axes = calloc(axisCount, sizeof(float)); + js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1); + js->hats = calloc(hatCount, 1); js->axisCount = axisCount; js->buttonCount = buttonCount; js->hatCount = hatCount; - strncpy(js->name, name, sizeof(js->name) - 1); strncpy(js->guid, guid, sizeof(js->guid) - 1); js->mapping = findValidMapping(js); @@ -536,9 +464,10 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, // void _glfwFreeJoystick(_GLFWjoystick* js) { - _glfw_free(js->axes); - _glfw_free(js->buttons); - _glfw_free(js->hats); + free(js->name); + free(js->axes); + free(js->buttons); + free(js->hats); memset(js, 0, sizeof(_GLFWjoystick)); } @@ -548,8 +477,8 @@ void _glfwCenterCursorInContentArea(_GLFWwindow* window) { int width, height; - _glfw.platform.getWindowSize(window, &width, &height); - _glfw.platform.setCursorPos(window, width / 2.0, height / 2.0); + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } @@ -589,109 +518,96 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) _GLFW_REQUIRE_INIT(); - switch (mode) + if (mode == GLFW_CURSOR) { - case GLFW_CURSOR: + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED) { - if (value != GLFW_CURSOR_NORMAL && - value != GLFW_CURSOR_HIDDEN && - value != GLFW_CURSOR_DISABLED && - value != GLFW_CURSOR_CAPTURED) - { - _glfwInputError(GLFW_INVALID_ENUM, - "Invalid cursor mode 0x%08X", - value); - return; - } - - if (window->cursorMode == value) - return; - - window->cursorMode = value; - - _glfw.platform.getCursorPos(window, - &window->virtualCursorPosX, - &window->virtualCursorPosY); - _glfw.platform.setCursorMode(window, value); + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode 0x%08X", + value); return; } - case GLFW_STICKY_KEYS: - { - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->stickyKeys == value) - return; - - if (!value) - { - int i; - - // Release all sticky keys - for (i = 0; i <= GLFW_KEY_LAST; i++) - { - if (window->keys[i] == _GLFW_STICK) - window->keys[i] = GLFW_RELEASE; - } - } - - window->stickyKeys = value; + if (window->cursorMode == value) return; - } - case GLFW_STICKY_MOUSE_BUTTONS: - { - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->stickyMouseButtons == value) - return; + window->cursorMode = value; - if (!value) - { - int i; - - // Release all sticky mouse buttons - for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) - { - if (window->mouseButtons[i] == _GLFW_STICK) - window->mouseButtons[i] = GLFW_RELEASE; - } - } - - window->stickyMouseButtons = value; - return; - } - - case GLFW_LOCK_KEY_MODS: - { - window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; - return; - } - - case GLFW_RAW_MOUSE_MOTION: - { - if (!_glfw.platform.rawMouseMotionSupported()) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Raw mouse motion is not supported on this system"); - return; - } - - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->rawMouseMotion == value) - return; - - window->rawMouseMotion = value; - _glfw.platform.setRawMouseMotion(window, value); - return; - } + _glfwPlatformGetCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); + _glfwPlatformSetCursorMode(window, value); } + else if (mode == GLFW_STICKY_KEYS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyKeys == value) + return; - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); + if (!value) + { + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->keys[i] == _GLFW_STICK) + window->keys[i] = GLFW_RELEASE; + } + } + + window->stickyKeys = value; + } + else if (mode == GLFW_STICKY_MOUSE_BUTTONS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyMouseButtons == value) + return; + + if (!value) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == _GLFW_STICK) + window->mouseButtons[i] = GLFW_RELEASE; + } + } + + window->stickyMouseButtons = value; + } + else if (mode == GLFW_LOCK_KEY_MODS) + { + window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; + } + else if (mode == GLFW_RAW_MOUSE_MOTION) + { + if (!_glfwPlatformRawMouseMotionSupported()) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Raw mouse motion is not supported on this system"); + return; + } + + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->rawMouseMotion == value) + return; + + window->rawMouseMotion = value; + _glfwPlatformSetRawMouseMotion(window, value); + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } GLFWAPI int glfwRawMouseMotionSupported(void) { _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - return _glfw.platform.rawMouseMotionSupported(); + return _glfwPlatformRawMouseMotionSupported(); } GLFWAPI const char* glfwGetKeyName(int key, int scancode) @@ -700,12 +616,6 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode) if (key != GLFW_KEY_UNKNOWN) { - if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) - { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); - return NULL; - } - if (key != GLFW_KEY_KP_EQUAL && (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) @@ -713,23 +623,23 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode) return NULL; } - scancode = _glfw.platform.getKeyScancode(key); + scancode = _glfwPlatformGetKeyScancode(key); } - return _glfw.platform.getScancodeName(scancode); + return _glfwPlatformGetScancodeName(scancode); } GLFWAPI int glfwGetKeyScancode(int key) { - _GLFW_REQUIRE_INIT_OR_RETURN(0); + _GLFW_REQUIRE_INIT_OR_RETURN(-1); if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); - return -1; + return GLFW_RELEASE; } - return _glfw.platform.getKeyScancode(key); + return _glfwPlatformGetKeyScancode(key); } GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) @@ -798,7 +708,7 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) *ypos = window->virtualCursorPosY; } else - _glfw.platform.getCursorPos(window, xpos, ypos); + _glfwPlatformGetCursorPos(window, xpos, ypos); } GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) @@ -817,7 +727,7 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) return; } - if (!_glfw.platform.windowFocused(window)) + if (!_glfwPlatformWindowFocused(window)) return; if (window->cursorMode == GLFW_CURSOR_DISABLED) @@ -829,7 +739,7 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) else { // Update system cursor position - _glfw.platform.setCursorPos(window, xpos, ypos); + _glfwPlatformSetCursorPos(window, xpos, ypos); } } @@ -838,21 +748,14 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) _GLFWcursor* cursor; assert(image != NULL); - assert(image->pixels != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (image->width <= 0 || image->height <= 0) - { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid image dimensions for cursor"); - return NULL; - } - - cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); + cursor = calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; - if (!_glfw.platform.createCursor(cursor, image, xhot, yhot)) + if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) { glfwDestroyCursor((GLFWcursor*) cursor); return NULL; @@ -882,11 +785,11 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) return NULL; } - cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); + cursor = calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; - if (!_glfw.platform.createStandardCursor(cursor, shape)) + if (!_glfwPlatformCreateStandardCursor(cursor, shape)) { glfwDestroyCursor((GLFWcursor*) cursor); return NULL; @@ -915,7 +818,7 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) } } - _glfw.platform.destroyCursor(cursor); + _glfwPlatformDestroyCursor(cursor); // Unlink cursor from global linked list { @@ -927,7 +830,7 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) *prev = cursor->next; } - _glfw_free(cursor); + free(cursor); } GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) @@ -940,7 +843,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) window->cursor = cursor; - _glfw.platform.setCursor(window, cursor); + _glfwPlatformSetCursor(window, cursor); } GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) @@ -949,7 +852,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWkeyfun, window->callbacks.key, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); return cbfun; } @@ -959,7 +862,7 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWcharfun, window->callbacks.character, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); return cbfun; } @@ -969,7 +872,7 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmods assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWcharmodsfun, window->callbacks.charmods, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); return cbfun; } @@ -980,7 +883,7 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWmousebuttonfun, window->callbacks.mouseButton, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); return cbfun; } @@ -991,7 +894,7 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWcursorposfun, window->callbacks.cursorPos, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); return cbfun; } @@ -1002,7 +905,7 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWcursorenterfun, window->callbacks.cursorEnter, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); return cbfun; } @@ -1013,7 +916,7 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWscrollfun, window->callbacks.scroll, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); return cbfun; } @@ -1023,7 +926,7 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWdropfun, window->callbacks.drop, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); return cbfun; } @@ -1046,10 +949,10 @@ GLFWAPI int glfwJoystickPresent(int jid) return GLFW_FALSE; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return GLFW_FALSE; - return _glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE); + return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) @@ -1074,10 +977,10 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) return NULL; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return NULL; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_AXES)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) return NULL; *count = js->axisCount; @@ -1106,10 +1009,10 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) return NULL; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return NULL; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; if (_glfw.hints.init.hatButtons) @@ -1142,10 +1045,10 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) return NULL; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return NULL; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; *count = js->hatCount; @@ -1171,10 +1074,10 @@ GLFWAPI const char* glfwGetJoystickName(int jid) return NULL; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return NULL; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; return js->name; @@ -1199,10 +1102,10 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid) return NULL; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return NULL; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; return js->guid; @@ -1218,7 +1121,7 @@ GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) _GLFW_REQUIRE_INIT(); js = _glfw.joysticks + jid; - if (!js->allocated) + if (!js->present) return; js->userPointer = pointer; @@ -1234,7 +1137,7 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); js = _glfw.joysticks + jid; - if (!js->allocated) + if (!js->present) return NULL; return js->userPointer; @@ -1247,7 +1150,7 @@ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) if (!initJoysticks()) return NULL; - _GLFW_SWAP(GLFWjoystickfun, _glfw.callbacks.joystick, cbfun); + _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); return cbfun; } @@ -1285,8 +1188,8 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) { _glfw.mappingCount++; _glfw.mappings = - _glfw_realloc(_glfw.mappings, - sizeof(_GLFWmapping) * _glfw.mappingCount); + realloc(_glfw.mappings, + sizeof(_GLFWmapping) * _glfw.mappingCount); _glfw.mappings[_glfw.mappingCount - 1] = mapping; } } @@ -1304,7 +1207,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->connected) + if (js->present) js->mapping = findValidMapping(js); } @@ -1330,10 +1233,10 @@ GLFWAPI int glfwJoystickIsGamepad(int jid) return GLFW_FALSE; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return GLFW_FALSE; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return GLFW_FALSE; return js->mapping != NULL; @@ -1358,10 +1261,10 @@ GLFWAPI const char* glfwGetGamepadName(int jid) return NULL; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return NULL; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; if (!js->mapping) @@ -1393,10 +1296,10 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) return GLFW_FALSE; js = _glfw.joysticks + jid; - if (!js->connected) + if (!js->present) return GLFW_FALSE; - if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_ALL)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) return GLFW_FALSE; if (!js->mapping) @@ -1438,7 +1341,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) if (e->type == _GLFW_JOYSTICK_AXIS) { const float value = js->axes[e->index] * e->axisScale + e->axisOffset; - state->axes[i] = fminf(fmaxf(value, -1.f), 1.f); + state->axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.f), 1.f); } else if (e->type == _GLFW_JOYSTICK_HATBIT) { @@ -1461,13 +1364,13 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) assert(string != NULL); _GLFW_REQUIRE_INIT(); - _glfw.platform.setClipboardString(string); + _glfwPlatformSetClipboardString(string); } GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfw.platform.getClipboardString(); + return _glfwPlatformGetClipboardString(); } GLFWAPI double glfwGetTime(void) @@ -1502,4 +1405,3 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void) _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerFrequency(); } - diff --git a/raylib/external/glfw/src/internal.h b/raylib/external/glfw/src/internal.h index 8873359..48053cd 100644 --- a/raylib/external/glfw/src/internal.h +++ b/raylib/external/glfw/src/internal.h @@ -59,7 +59,6 @@ #define _GLFW_MESSAGE_SIZE 1024 typedef int GLFWbool; -typedef void (*GLFWproc)(void); typedef struct _GLFWerror _GLFWerror; typedef struct _GLFWinitconfig _GLFWinitconfig; @@ -68,7 +67,6 @@ typedef struct _GLFWctxconfig _GLFWctxconfig; typedef struct _GLFWfbconfig _GLFWfbconfig; typedef struct _GLFWcontext _GLFWcontext; typedef struct _GLFWwindow _GLFWwindow; -typedef struct _GLFWplatform _GLFWplatform; typedef struct _GLFWlibrary _GLFWlibrary; typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; @@ -78,6 +76,13 @@ typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWtls _GLFWtls; typedef struct _GLFWmutex _GLFWmutex; +typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); +typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); +typedef void (* _GLFWswapintervalfun)(int); +typedef int (* _GLFWextensionsupportedfun)(const char*); +typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*); +typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); + #define GL_VERSION 0x1f02 #define GL_NONE 0 #define GL_COLOR_BUFFER_BIT 0x00004000 @@ -108,159 +113,6 @@ typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum); typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*); typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint); -#define EGL_SUCCESS 0x3000 -#define EGL_NOT_INITIALIZED 0x3001 -#define EGL_BAD_ACCESS 0x3002 -#define EGL_BAD_ALLOC 0x3003 -#define EGL_BAD_ATTRIBUTE 0x3004 -#define EGL_BAD_CONFIG 0x3005 -#define EGL_BAD_CONTEXT 0x3006 -#define EGL_BAD_CURRENT_SURFACE 0x3007 -#define EGL_BAD_DISPLAY 0x3008 -#define EGL_BAD_MATCH 0x3009 -#define EGL_BAD_NATIVE_PIXMAP 0x300a -#define EGL_BAD_NATIVE_WINDOW 0x300b -#define EGL_BAD_PARAMETER 0x300c -#define EGL_BAD_SURFACE 0x300d -#define EGL_CONTEXT_LOST 0x300e -#define EGL_COLOR_BUFFER_TYPE 0x303f -#define EGL_RGB_BUFFER 0x308e -#define EGL_SURFACE_TYPE 0x3033 -#define EGL_WINDOW_BIT 0x0004 -#define EGL_RENDERABLE_TYPE 0x3040 -#define EGL_OPENGL_ES_BIT 0x0001 -#define EGL_OPENGL_ES2_BIT 0x0004 -#define EGL_OPENGL_BIT 0x0008 -#define EGL_ALPHA_SIZE 0x3021 -#define EGL_BLUE_SIZE 0x3022 -#define EGL_GREEN_SIZE 0x3023 -#define EGL_RED_SIZE 0x3024 -#define EGL_DEPTH_SIZE 0x3025 -#define EGL_STENCIL_SIZE 0x3026 -#define EGL_SAMPLES 0x3031 -#define EGL_OPENGL_ES_API 0x30a0 -#define EGL_OPENGL_API 0x30a2 -#define EGL_NONE 0x3038 -#define EGL_RENDER_BUFFER 0x3086 -#define EGL_SINGLE_BUFFER 0x3085 -#define EGL_EXTENSIONS 0x3055 -#define EGL_CONTEXT_CLIENT_VERSION 0x3098 -#define EGL_NATIVE_VISUAL_ID 0x302e -#define EGL_NO_SURFACE ((EGLSurface) 0) -#define EGL_NO_DISPLAY ((EGLDisplay) 0) -#define EGL_NO_CONTEXT ((EGLContext) 0) -#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) - -#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 -#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 -#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 -#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 -#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd -#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be -#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf -#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 -#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 -#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb -#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd -#define EGL_CONTEXT_FLAGS_KHR 0x30fc -#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 -#define EGL_GL_COLORSPACE_KHR 0x309d -#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 -#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 -#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 -#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 -#define EGL_PLATFORM_X11_EXT 0x31d5 -#define EGL_PLATFORM_WAYLAND_EXT 0x31d8 -#define EGL_PRESENT_OPAQUE_EXT 0x31df -#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 -#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 -#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320d -#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320e -#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 -#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450 -#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489 -#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348f - -typedef int EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; -typedef void* EGLConfig; -typedef void* EGLContext; -typedef void* EGLDisplay; -typedef void* EGLSurface; - -typedef void* EGLNativeDisplayType; -typedef void* EGLNativeWindowType; - -// EGL function pointer typedefs -typedef EGLBoolean (APIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); -typedef EGLBoolean (APIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); -typedef EGLDisplay (APIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); -typedef EGLint (APIENTRY * PFN_eglGetError)(void); -typedef EGLBoolean (APIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); -typedef EGLBoolean (APIENTRY * PFN_eglTerminate)(EGLDisplay); -typedef EGLBoolean (APIENTRY * PFN_eglBindAPI)(EGLenum); -typedef EGLContext (APIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); -typedef EGLBoolean (APIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); -typedef EGLBoolean (APIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); -typedef EGLSurface (APIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); -typedef EGLBoolean (APIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); -typedef EGLBoolean (APIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); -typedef EGLBoolean (APIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); -typedef const char* (APIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); -typedef GLFWglproc (APIENTRY * PFN_eglGetProcAddress)(const char*); -#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib -#define eglGetConfigs _glfw.egl.GetConfigs -#define eglGetDisplay _glfw.egl.GetDisplay -#define eglGetError _glfw.egl.GetError -#define eglInitialize _glfw.egl.Initialize -#define eglTerminate _glfw.egl.Terminate -#define eglBindAPI _glfw.egl.BindAPI -#define eglCreateContext _glfw.egl.CreateContext -#define eglDestroySurface _glfw.egl.DestroySurface -#define eglDestroyContext _glfw.egl.DestroyContext -#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface -#define eglMakeCurrent _glfw.egl.MakeCurrent -#define eglSwapBuffers _glfw.egl.SwapBuffers -#define eglSwapInterval _glfw.egl.SwapInterval -#define eglQueryString _glfw.egl.QueryString -#define eglGetProcAddress _glfw.egl.GetProcAddress - -typedef EGLDisplay (APIENTRY * PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum,void*,const EGLint*); -typedef EGLSurface (APIENTRY * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay,EGLConfig,void*,const EGLint*); -#define eglGetPlatformDisplayEXT _glfw.egl.GetPlatformDisplayEXT -#define eglCreatePlatformWindowSurfaceEXT _glfw.egl.CreatePlatformWindowSurfaceEXT - -#define OSMESA_RGBA 0x1908 -#define OSMESA_FORMAT 0x22 -#define OSMESA_DEPTH_BITS 0x30 -#define OSMESA_STENCIL_BITS 0x31 -#define OSMESA_ACCUM_BITS 0x32 -#define OSMESA_PROFILE 0x33 -#define OSMESA_CORE_PROFILE 0x34 -#define OSMESA_COMPAT_PROFILE 0x35 -#define OSMESA_CONTEXT_MAJOR_VERSION 0x36 -#define OSMESA_CONTEXT_MINOR_VERSION 0x37 - -typedef void* OSMesaContext; -typedef void (*OSMESAproc)(void); - -typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); -typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); -typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); -typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); -typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); -typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); -typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); -#define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt -#define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs -#define OSMesaDestroyContext _glfw.osmesa.DestroyContext -#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent -#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer -#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer -#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress - #define VK_NULL_HANDLE 0 typedef void* VkInstance; @@ -318,14 +170,39 @@ typedef struct VkExtensionProperties typedef void (APIENTRY * PFN_vkVoidFunction)(void); -typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*); -typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); -#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr +#if defined(_GLFW_VULKAN_STATIC) + PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*); + VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*); +#else + typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*); + typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); + #define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties + #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr +#endif -#include "platform.h" +#if defined(_GLFW_COCOA) + #include "cocoa_platform.h" +#elif defined(_GLFW_WIN32) + #include "win32_platform.h" +#elif defined(_GLFW_X11) + #include "x11_platform.h" +#elif defined(_GLFW_WAYLAND) + #include "wl_platform.h" +#elif defined(_GLFW_OSMESA) + #include "null_platform.h" +#else + #error "No supported window creation API selected" +#endif -#define GLFW_NATIVE_INCLUDE_NONE -#include "../include/GLFW/glfw3native.h" +#include "egl_context.h" +#include "osmesa_context.h" + +// Constructs a version number string from the public header macros +#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r +#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r) +#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \ + GLFW_VERSION_MINOR, \ + GLFW_VERSION_REVISION) // Checks for whether the library has been initialized #define _GLFW_REQUIRE_INIT() \ @@ -342,12 +219,12 @@ typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const c } // Swaps the provided pointers -#define _GLFW_SWAP(type, x, y) \ - { \ - type t; \ - t = x; \ - x = y; \ - y = t; \ +#define _GLFW_SWAP_POINTERS(x, y) \ + { \ + void* t; \ + t = x; \ + x = y; \ + y = t; \ } // Per-thread error structure @@ -367,18 +244,10 @@ struct _GLFWinitconfig { GLFWbool hatButtons; int angleType; - int platformID; - PFN_vkGetInstanceProcAddr vulkanLoader; struct { GLFWbool menubar; GLFWbool chdir; } ns; - struct { - GLFWbool xcbVulkanSurface; - } x11; - struct { - int libdecorMode; - } wl; }; // Window configuration @@ -389,8 +258,6 @@ struct _GLFWinitconfig // struct _GLFWwndconfig { - int xpos; - int ypos; int width; int height; const char* title; @@ -405,8 +272,8 @@ struct _GLFWwndconfig GLFWbool focusOnShow; GLFWbool mousePassthrough; GLFWbool scaleToMonitor; - GLFWbool scaleFramebuffer; struct { + GLFWbool retina; char frameName[256]; } ns; struct { @@ -415,11 +282,7 @@ struct _GLFWwndconfig } x11; struct { GLFWbool keymenu; - GLFWbool showDefault; } win32; - struct { - char appId[256]; - } wl; }; // Context configuration @@ -487,33 +350,23 @@ struct _GLFWcontext int robustness; int release; - PFNGLGETSTRINGIPROC GetStringi; + PFNGLGETSTRINGIPROC GetStringi; PFNGLGETINTEGERVPROC GetIntegerv; - PFNGLGETSTRINGPROC GetString; + PFNGLGETSTRINGPROC GetString; - void (*makeCurrent)(_GLFWwindow*); - void (*swapBuffers)(_GLFWwindow*); - void (*swapInterval)(int); - int (*extensionSupported)(const char*); - GLFWglproc (*getProcAddress)(const char*); - void (*destroy)(_GLFWwindow*); + _GLFWmakecontextcurrentfun makeCurrent; + _GLFWswapbuffersfun swapBuffers; + _GLFWswapintervalfun swapInterval; + _GLFWextensionsupportedfun extensionSupported; + _GLFWgetprocaddressfun getProcAddress; + _GLFWdestroycontextfun destroy; - struct { - EGLConfig config; - EGLContext handle; - EGLSurface surface; - void* client; - } egl; - - struct { - OSMesaContext handle; - int width; - int height; - void* buffer; - } osmesa; - - // This is defined in platform.h - GLFW_PLATFORM_CONTEXT_STATE + // This is defined in the context API's context.h + _GLFW_PLATFORM_CONTEXT_STATE; + // This is defined in egl_context.h + _GLFWcontextEGL egl; + // This is defined in osmesa_context.h + _GLFWcontextOSMesa osmesa; }; // Window and context structure @@ -531,11 +384,9 @@ struct _GLFWwindow GLFWbool mousePassthrough; GLFWbool shouldClose; void* userPointer; - GLFWbool doublebuffer; GLFWvidmode videoMode; _GLFWmonitor* monitor; _GLFWcursor* cursor; - char* title; int minwidth, minheight; int maxwidth, maxheight; @@ -554,34 +405,34 @@ struct _GLFWwindow _GLFWcontext context; struct { - GLFWwindowposfun pos; - GLFWwindowsizefun size; - GLFWwindowclosefun close; - GLFWwindowrefreshfun refresh; - GLFWwindowfocusfun focus; - GLFWwindowiconifyfun iconify; - GLFWwindowmaximizefun maximize; - GLFWframebuffersizefun fbsize; + GLFWwindowposfun pos; + GLFWwindowsizefun size; + GLFWwindowclosefun close; + GLFWwindowrefreshfun refresh; + GLFWwindowfocusfun focus; + GLFWwindowiconifyfun iconify; + GLFWwindowmaximizefun maximize; + GLFWframebuffersizefun fbsize; GLFWwindowcontentscalefun scale; - GLFWmousebuttonfun mouseButton; - GLFWcursorposfun cursorPos; - GLFWcursorenterfun cursorEnter; - GLFWscrollfun scroll; - GLFWkeyfun key; - GLFWcharfun character; - GLFWcharmodsfun charmods; - GLFWdropfun drop; + GLFWmousebuttonfun mouseButton; + GLFWcursorposfun cursorPos; + GLFWcursorenterfun cursorEnter; + GLFWscrollfun scroll; + GLFWkeyfun key; + GLFWcharfun character; + GLFWcharmodsfun charmods; + GLFWdropfun drop; } callbacks; - // This is defined in platform.h - GLFW_PLATFORM_WINDOW_STATE + // This is defined in the window API's platform.h + _GLFW_PLATFORM_WINDOW_STATE; }; // Monitor structure // struct _GLFWmonitor { - char name[128]; + char* name; void* userPointer; // Physical dimensions in millimeters. @@ -597,8 +448,8 @@ struct _GLFWmonitor GLFWgammaramp originalRamp; GLFWgammaramp currentRamp; - // This is defined in platform.h - GLFW_PLATFORM_MONITOR_STATE + // This is defined in the window API's platform.h + _GLFW_PLATFORM_MONITOR_STATE; }; // Cursor structure @@ -606,8 +457,9 @@ struct _GLFWmonitor struct _GLFWcursor { _GLFWcursor* next; - // This is defined in platform.h - GLFW_PLATFORM_CURSOR_STATE + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_CURSOR_STATE; }; // Gamepad mapping element structure @@ -634,121 +486,36 @@ struct _GLFWmapping // struct _GLFWjoystick { - GLFWbool allocated; - GLFWbool connected; + GLFWbool present; float* axes; int axisCount; unsigned char* buttons; int buttonCount; unsigned char* hats; int hatCount; - char name[128]; + char* name; void* userPointer; char guid[33]; _GLFWmapping* mapping; - // This is defined in platform.h - GLFW_PLATFORM_JOYSTICK_STATE + // This is defined in the joystick API's joystick.h + _GLFW_PLATFORM_JOYSTICK_STATE; }; // Thread local storage structure // struct _GLFWtls { - // This is defined in platform.h - GLFW_PLATFORM_TLS_STATE + // This is defined in the platform's thread.h + _GLFW_PLATFORM_TLS_STATE; }; // Mutex structure // struct _GLFWmutex { - // This is defined in platform.h - GLFW_PLATFORM_MUTEX_STATE -}; - -// Platform API structure -// -struct _GLFWplatform -{ - int platformID; - // init - GLFWbool (*init)(void); - void (*terminate)(void); - // input - void (*getCursorPos)(_GLFWwindow*,double*,double*); - void (*setCursorPos)(_GLFWwindow*,double,double); - void (*setCursorMode)(_GLFWwindow*,int); - void (*setRawMouseMotion)(_GLFWwindow*,GLFWbool); - GLFWbool (*rawMouseMotionSupported)(void); - GLFWbool (*createCursor)(_GLFWcursor*,const GLFWimage*,int,int); - GLFWbool (*createStandardCursor)(_GLFWcursor*,int); - void (*destroyCursor)(_GLFWcursor*); - void (*setCursor)(_GLFWwindow*,_GLFWcursor*); - const char* (*getScancodeName)(int); - int (*getKeyScancode)(int); - void (*setClipboardString)(const char*); - const char* (*getClipboardString)(void); - GLFWbool (*initJoysticks)(void); - void (*terminateJoysticks)(void); - GLFWbool (*pollJoystick)(_GLFWjoystick*,int); - const char* (*getMappingName)(void); - void (*updateGamepadGUID)(char*); - // monitor - void (*freeMonitor)(_GLFWmonitor*); - void (*getMonitorPos)(_GLFWmonitor*,int*,int*); - void (*getMonitorContentScale)(_GLFWmonitor*,float*,float*); - void (*getMonitorWorkarea)(_GLFWmonitor*,int*,int*,int*,int*); - GLFWvidmode* (*getVideoModes)(_GLFWmonitor*,int*); - GLFWbool (*getVideoMode)(_GLFWmonitor*,GLFWvidmode*); - GLFWbool (*getGammaRamp)(_GLFWmonitor*,GLFWgammaramp*); - void (*setGammaRamp)(_GLFWmonitor*,const GLFWgammaramp*); - // window - GLFWbool (*createWindow)(_GLFWwindow*,const _GLFWwndconfig*,const _GLFWctxconfig*,const _GLFWfbconfig*); - void (*destroyWindow)(_GLFWwindow*); - void (*setWindowTitle)(_GLFWwindow*,const char*); - void (*setWindowIcon)(_GLFWwindow*,int,const GLFWimage*); - void (*getWindowPos)(_GLFWwindow*,int*,int*); - void (*setWindowPos)(_GLFWwindow*,int,int); - void (*getWindowSize)(_GLFWwindow*,int*,int*); - void (*setWindowSize)(_GLFWwindow*,int,int); - void (*setWindowSizeLimits)(_GLFWwindow*,int,int,int,int); - void (*setWindowAspectRatio)(_GLFWwindow*,int,int); - void (*getFramebufferSize)(_GLFWwindow*,int*,int*); - void (*getWindowFrameSize)(_GLFWwindow*,int*,int*,int*,int*); - void (*getWindowContentScale)(_GLFWwindow*,float*,float*); - void (*iconifyWindow)(_GLFWwindow*); - void (*restoreWindow)(_GLFWwindow*); - void (*maximizeWindow)(_GLFWwindow*); - void (*showWindow)(_GLFWwindow*); - void (*hideWindow)(_GLFWwindow*); - void (*requestWindowAttention)(_GLFWwindow*); - void (*focusWindow)(_GLFWwindow*); - void (*setWindowMonitor)(_GLFWwindow*,_GLFWmonitor*,int,int,int,int,int); - GLFWbool (*windowFocused)(_GLFWwindow*); - GLFWbool (*windowIconified)(_GLFWwindow*); - GLFWbool (*windowVisible)(_GLFWwindow*); - GLFWbool (*windowMaximized)(_GLFWwindow*); - GLFWbool (*windowHovered)(_GLFWwindow*); - GLFWbool (*framebufferTransparent)(_GLFWwindow*); - float (*getWindowOpacity)(_GLFWwindow*); - void (*setWindowResizable)(_GLFWwindow*,GLFWbool); - void (*setWindowDecorated)(_GLFWwindow*,GLFWbool); - void (*setWindowFloating)(_GLFWwindow*,GLFWbool); - void (*setWindowOpacity)(_GLFWwindow*,float); - void (*setWindowMousePassthrough)(_GLFWwindow*,GLFWbool); - void (*pollEvents)(void); - void (*waitEvents)(void); - void (*waitEventsTimeout)(double); - void (*postEmptyEvent)(void); - // EGL - EGLenum (*getEGLPlatform)(EGLint**); - EGLNativeDisplayType (*getEGLNativeDisplay)(void); - EGLNativeWindowType (*getEGLNativeWindow)(_GLFWwindow*); - // vulkan - void (*getRequiredInstanceExtensions)(char**); - GLFWbool (*getPhysicalDevicePresentationSupport)(VkInstance,VkPhysicalDevice,uint32_t); - VkResult (*createWindowSurface)(VkInstance,_GLFWwindow*,const VkAllocationCallbacks*,VkSurfaceKHR*); + // This is defined in the platform's thread.h + _GLFW_PLATFORM_MUTEX_STATE; }; // Library global data @@ -756,9 +523,6 @@ struct _GLFWplatform struct _GLFWlibrary { GLFWbool initialized; - GLFWallocator allocator; - - _GLFWplatform platform; struct { _GLFWinitconfig init; @@ -786,80 +550,30 @@ struct _GLFWlibrary struct { uint64_t offset; - // This is defined in platform.h - GLFW_PLATFORM_LIBRARY_TIMER_STATE + // This is defined in the platform's time.h + _GLFW_PLATFORM_LIBRARY_TIMER_STATE; } timer; - struct { - EGLenum platform; - EGLDisplay display; - EGLint major, minor; - GLFWbool prefix; - - GLFWbool KHR_create_context; - GLFWbool KHR_create_context_no_error; - GLFWbool KHR_gl_colorspace; - GLFWbool KHR_get_all_proc_addresses; - GLFWbool KHR_context_flush_control; - GLFWbool EXT_client_extensions; - GLFWbool EXT_platform_base; - GLFWbool EXT_platform_x11; - GLFWbool EXT_platform_wayland; - GLFWbool EXT_present_opaque; - GLFWbool ANGLE_platform_angle; - GLFWbool ANGLE_platform_angle_opengl; - GLFWbool ANGLE_platform_angle_d3d; - GLFWbool ANGLE_platform_angle_vulkan; - GLFWbool ANGLE_platform_angle_metal; - - void* handle; - - PFN_eglGetConfigAttrib GetConfigAttrib; - PFN_eglGetConfigs GetConfigs; - PFN_eglGetDisplay GetDisplay; - PFN_eglGetError GetError; - PFN_eglInitialize Initialize; - PFN_eglTerminate Terminate; - PFN_eglBindAPI BindAPI; - PFN_eglCreateContext CreateContext; - PFN_eglDestroySurface DestroySurface; - PFN_eglDestroyContext DestroyContext; - PFN_eglCreateWindowSurface CreateWindowSurface; - PFN_eglMakeCurrent MakeCurrent; - PFN_eglSwapBuffers SwapBuffers; - PFN_eglSwapInterval SwapInterval; - PFN_eglQueryString QueryString; - PFN_eglGetProcAddress GetProcAddress; - - PFNEGLGETPLATFORMDISPLAYEXTPROC GetPlatformDisplayEXT; - PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC CreatePlatformWindowSurfaceEXT; - } egl; - - struct { - void* handle; - - PFN_OSMesaCreateContextExt CreateContextExt; - PFN_OSMesaCreateContextAttribs CreateContextAttribs; - PFN_OSMesaDestroyContext DestroyContext; - PFN_OSMesaMakeCurrent MakeCurrent; - PFN_OSMesaGetColorBuffer GetColorBuffer; - PFN_OSMesaGetDepthBuffer GetDepthBuffer; - PFN_OSMesaGetProcAddress GetProcAddress; - - } osmesa; - struct { GLFWbool available; void* handle; char* extensions[2]; +#if !defined(_GLFW_VULKAN_STATIC) + PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; +#endif GLFWbool KHR_surface; +#if defined(_GLFW_WIN32) GLFWbool KHR_win32_surface; +#elif defined(_GLFW_COCOA) GLFWbool MVK_macos_surface; GLFWbool EXT_metal_surface; +#elif defined(_GLFW_X11) GLFWbool KHR_xlib_surface; GLFWbool KHR_xcb_surface; +#elif defined(_GLFW_WAYLAND) GLFWbool KHR_wayland_surface; +#endif } vk; struct { @@ -867,10 +581,16 @@ struct _GLFWlibrary GLFWjoystickfun joystick; } callbacks; - // These are defined in platform.h - GLFW_PLATFORM_LIBRARY_WINDOW_STATE - GLFW_PLATFORM_LIBRARY_CONTEXT_STATE - GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE + // This is defined in the window API's platform.h + _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; + // This is defined in the context API's context.h + _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; + // This is defined in the platform's joystick.h + _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; + // This is defined in egl_context.h + _GLFWlibraryEGL egl; + // This is defined in osmesa_context.h + _GLFWlibraryOSMesa osmesa; }; // Global state shared between compilation units of GLFW @@ -882,10 +602,108 @@ extern _GLFWlibrary _glfw; ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformInitTimer(void); +int _glfwPlatformInit(void); +void _glfwPlatformTerminate(void); +const char* _glfwPlatformGetVersionString(void); + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); +void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled); +GLFWbool _glfwPlatformRawMouseMotionSupported(void); +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, int xhot, int yhot); +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); + +const char* _glfwPlatformGetScancodeName(int scancode); +int _glfwPlatformGetKeyScancode(int key); + +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor); +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale); +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height); +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +void _glfwPlatformSetClipboardString(const char* string); +const char* _glfwPlatformGetClipboardString(void); + +GLFWbool _glfwPlatformInitJoysticks(void); +void _glfwPlatformTerminateJoysticks(void); +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); +void _glfwPlatformUpdateGamepadGUID(char* guid); + uint64_t _glfwPlatformGetTimerValue(void); uint64_t _glfwPlatformGetTimerFrequency(void); +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwPlatformDestroyWindow(_GLFWwindow* window); +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images); +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight); +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom); +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale); +void _glfwPlatformIconifyWindow(_GLFWwindow* window); +void _glfwPlatformRestoreWindow(_GLFWwindow* window); +void _glfwPlatformMaximizeWindow(_GLFWwindow* window); +void _glfwPlatformShowWindow(_GLFWwindow* window); +void _glfwPlatformHideWindow(_GLFWwindow* window); +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); +void _glfwPlatformFocusWindow(_GLFWwindow* window); +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, + int xpos, int ypos, int width, int height, + int refreshRate); +int _glfwPlatformWindowFocused(_GLFWwindow* window); +int _glfwPlatformWindowIconified(_GLFWwindow* window); +int _glfwPlatformWindowVisible(_GLFWwindow* window); +int _glfwPlatformWindowMaximized(_GLFWwindow* window); +int _glfwPlatformWindowHovered(_GLFWwindow* window); +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); + +void _glfwPlatformPollEvents(void); +void _glfwPlatformWaitEvents(void); +void _glfwPlatformWaitEventsTimeout(double timeout); +void _glfwPlatformPostEmptyEvent(void); + +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs); +EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void); +EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window); + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily); +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface); + GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls); void* _glfwPlatformGetTls(_GLFWtls* tls); @@ -896,10 +714,6 @@ void _glfwPlatformDestroyMutex(_GLFWmutex* mutex); void _glfwPlatformLockMutex(_GLFWmutex* mutex); void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); -void* _glfwPlatformLoadModule(const char* path); -void _glfwPlatformFreeModule(void* module); -GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name); - ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// @@ -920,7 +734,7 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); void _glfwInputChar(_GLFWwindow* window, - uint32_t codepoint, int mods, GLFWbool plain); + unsigned int codepoint, int mods, GLFWbool plain); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); @@ -946,8 +760,6 @@ void _glfwInputError(int code, const char* format, ...); ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwSelectPlatform(int platformID, _GLFWplatform* platform); - GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions); const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, const _GLFWfbconfig* alternatives, @@ -965,7 +777,6 @@ void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); void _glfwFreeGammaArrays(GLFWgammaramp* ramp); void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); -void _glfwInitGamepadMappings(void); _GLFWjoystick* _glfwAllocJoystick(const char* name, const char* guid, int axisCount, @@ -974,36 +785,11 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, void _glfwFreeJoystick(_GLFWjoystick* js); void _glfwCenterCursorInContentArea(_GLFWwindow* window); -GLFWbool _glfwInitEGL(void); -void _glfwTerminateEGL(void); -GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig); -#if defined(_GLFW_X11) -GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig, - Visual** visual, int* depth); -#endif /*_GLFW_X11*/ - -GLFWbool _glfwInitOSMesa(void); -void _glfwTerminateOSMesa(void); -GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig); - GLFWbool _glfwInitVulkan(int mode); void _glfwTerminateVulkan(void); const char* _glfwGetVulkanResultString(VkResult result); -size_t _glfwEncodeUTF8(char* s, uint32_t codepoint); -char** _glfwParseUriList(char* text, int* count); - char* _glfw_strdup(const char* source); -int _glfw_min(int a, int b); -int _glfw_max(int a, int b); - -void* _glfw_calloc(size_t count, size_t size); -void* _glfw_realloc(void* pointer, size_t size); -void _glfw_free(void* pointer); +float _glfw_fminf(float a, float b); +float _glfw_fmaxf(float a, float b); diff --git a/raylib/external/glfw/src/linux_joystick.c b/raylib/external/glfw/src/linux_joystick.c index 07d41d3..122bc66 100644 --- a/raylib/external/glfw/src/linux_joystick.c +++ b/raylib/external/glfw/src/linux_joystick.c @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(GLFW_BUILD_LINUX_JOYSTICK) - #include #include #include @@ -128,14 +128,14 @@ static GLFWbool openJoystickDevice(const char* path) { for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].connected) + if (!_glfw.joysticks[jid].present) continue; if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) return GLFW_FALSE; } _GLFWjoystickLinux linjs = {0}; - linjs.fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + linjs.fd = open(path, O_RDONLY | O_NONBLOCK); if (linjs.fd == -1) return GLFW_FALSE; @@ -157,7 +157,7 @@ static GLFWbool openJoystickDevice(const char* path) } // Ensure this device supports the events expected of a joystick - if (!isBitSet(EV_ABS, evBits)) + if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits)) { close(linjs.fd); return GLFW_FALSE; @@ -245,9 +245,9 @@ static GLFWbool openJoystickDevice(const char* path) // static void closeJoystick(_GLFWjoystick* js) { - _glfwInputJoystick(js, GLFW_DISCONNECTED); close(js->linjs.fd); _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Lexically compare joysticks by name; used by qsort @@ -307,7 +307,7 @@ void _glfwDetectJoystickConnectionLinux(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwInitJoysticksLinux(void) +GLFWbool _glfwPlatformInitJoysticks(void) { const char* dirname = "/dev/input"; @@ -324,8 +324,7 @@ GLFWbool _glfwInitJoysticksLinux(void) // Continue without device connection notifications if inotify fails - _glfw.linjs.regexCompiled = (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) == 0); - if (!_glfw.linjs.regexCompiled) + if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); return GLFW_FALSE; @@ -362,12 +361,14 @@ GLFWbool _glfwInitJoysticksLinux(void) return GLFW_TRUE; } -void _glfwTerminateJoysticksLinux(void) +void _glfwPlatformTerminateJoysticks(void) { - for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->connected) + if (js->present) closeJoystick(js); } @@ -377,13 +378,11 @@ void _glfwTerminateJoysticksLinux(void) inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch); close(_glfw.linjs.inotify); - } - - if (_glfw.linjs.regexCompiled) regfree(&_glfw.linjs.regex); + } } -GLFWbool _glfwPollJoystickLinux(_GLFWjoystick* js, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { // Read all queued events (non-blocking) for (;;) @@ -420,17 +419,10 @@ GLFWbool _glfwPollJoystickLinux(_GLFWjoystick* js, int mode) handleAbsEvent(js, e.code, e.value); } - return js->connected; + return js->present; } -const char* _glfwGetMappingNameLinux(void) -{ - return "Linux"; -} - -void _glfwUpdateGamepadGUIDLinux(char* guid) +void _glfwPlatformUpdateGamepadGUID(char* guid) { } -#endif // GLFW_BUILD_LINUX_JOYSTICK - diff --git a/raylib/external/glfw/src/linux_joystick.h b/raylib/external/glfw/src/linux_joystick.h index 64462b0..05d5488 100644 --- a/raylib/external/glfw/src/linux_joystick.h +++ b/raylib/external/glfw/src/linux_joystick.h @@ -28,8 +28,10 @@ #include #include -#define GLFW_LINUX_JOYSTICK_STATE _GLFWjoystickLinux linjs; -#define GLFW_LINUX_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs; +#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs + +#define _GLFW_PLATFORM_MAPPING_NAME "Linux" // Linux-specific joystick data // @@ -50,15 +52,8 @@ typedef struct _GLFWlibraryLinux int inotify; int watch; regex_t regex; - GLFWbool regexCompiled; GLFWbool dropped; } _GLFWlibraryLinux; void _glfwDetectJoystickConnectionLinux(void); -GLFWbool _glfwInitJoysticksLinux(void); -void _glfwTerminateJoysticksLinux(void); -GLFWbool _glfwPollJoystickLinux(_GLFWjoystick* js, int mode); -const char* _glfwGetMappingNameLinux(void); -void _glfwUpdateGamepadGUIDLinux(char* guid); - diff --git a/raylib/external/glfw/src/mappings.h b/raylib/external/glfw/src/mappings.h index 7b0f35a..4c3f02f 100644 --- a/raylib/external/glfw/src/mappings.h +++ b/raylib/external/glfw/src/mappings.h @@ -31,7 +31,7 @@ // all available in SDL_GameControllerDB. Do not edit this file. Any gamepad // mappings not specific to GLFW should be submitted to SDL_GameControllerDB. // This file can be re-generated from mappings.h.in and the upstream -// gamecontrollerdb.txt with the 'update_mappings' CMake target. +// gamecontrollerdb.txt with the GenerateMappings.cmake script. //======================================================================== // All gamepad mappings not labeled GLFW are copied from the @@ -60,27 +60,23 @@ const char* _glfwDefaultMappings[] = { -#if defined(_GLFW_WIN32) "03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,", "03000000c82d00002038000000000000,8bitdo,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,", "03000000c82d000011ab000000000000,8BitDo F30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,", "03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00000151000000000000,8BitDo M30 ModKit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,", "03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,", "03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,", -"03000000c82d00000451000000000000,8BitDo N30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,start:b11,platform:Windows,", "03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", +"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", +"03000000c82d00015900000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", +"03000000c82d00065280000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", "03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,", "03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", @@ -88,24 +84,20 @@ const char* _glfwDefaultMappings[] = "03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", +"03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00000351000000000000,8BitDo SN30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", "03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", -"03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,", "03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,", -"03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,", -"03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,", "030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,", -"03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", "030000006f0e00001413000000000000,Afterglow,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", @@ -116,9 +108,7 @@ const char* _glfwDefaultMappings[] = "030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000d62000001d57000000000000,Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", -"03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,", -"03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows,", -"03000000ef0500000300000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,", +"03000000869800002400000000007801,Astro C40 TR,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,", "030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", @@ -134,7 +124,6 @@ const char* _glfwDefaultMappings[] = "03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,", "030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,", -"03000000120c0000210e000000000000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", "03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,", "03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", @@ -175,6 +164,7 @@ const char* _glfwDefaultMappings[] = "03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", "03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000006f0e00000102000000007801,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,", "030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,", "030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", @@ -225,7 +215,6 @@ const char* _glfwDefaultMappings[] = "030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,", "030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,", "030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,", -"03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000bd12000003c0000000000000,JY-P70UR,a:b1,b:b0,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b4,x:b3,y:b2,platform:Windows,", "03000000242f00002d00000000000000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", "03000000242f00008a00000000000000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", @@ -253,7 +242,6 @@ const char* _glfwDefaultMappings[] = "03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", "030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,", -"030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,", "03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,", "03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", "03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", @@ -272,16 +260,13 @@ const char* _glfwDefaultMappings[] = "03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,", "03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,", "030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", -"03000000921200004b46000000000000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,", -"03000000790000004518000000000000,NEXILUX GAMECUBE Controller Adapter,platform:Windows,a:b1,b:b0,x:b2,y:b3,start:b9,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,", -"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,", +"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,", "03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,", "03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,", "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,", "03000000550900001472000000000000,NVIDIA Controller v01.04,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,", "030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows,", -"03000000d620000013a7000000000000,NSW wired controller,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,", "03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,", @@ -290,7 +275,6 @@ const char* _glfwDefaultMappings[] = "030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", "030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", "030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,", -"030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", "03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", @@ -315,7 +299,6 @@ const char* _glfwDefaultMappings[] = "030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", "030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", "030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", -"03000000ff000000cb01000000000000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,", "03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,", "03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,", "03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,", @@ -353,7 +336,7 @@ const char* _glfwDefaultMappings[] = "03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", "03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", "03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", -"03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,", +"03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b0,y:b1,platform:Windows,", "03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,", "03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", "03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", @@ -365,8 +348,7 @@ const char* _glfwDefaultMappings[] = "03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,", "0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,", "030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,", -"03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,", -"03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,", +"030000005e0400008e02000000007801,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,", "03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "030000008f0e00000800000000000000,SpeedLink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", @@ -409,9 +391,10 @@ const char* _glfwDefaultMappings[] = "03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", "030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", "030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", -"0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,", +"0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows,", "030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", -"030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"030000005e040000ff02000000007801,Xbox One Elite Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "03000000ac0500005b05000000000000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", @@ -419,16 +402,6 @@ const char* _glfwDefaultMappings[] = "03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", "03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -#endif // _GLFW_WIN32 - -#if defined(_GLFW_COCOA) "030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,", "03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", @@ -442,38 +415,27 @@ const char* _glfwDefaultMappings[] = "03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,", -"03000000c82d00004028000000010000,8Bitdo SN30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Mac OS X,", "03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", -"03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,", +"03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,", "03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,", "03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,", -"03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", -"03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", "03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", -"03000000ef0500000300000000020000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,", -"03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,", -"03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,", "03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,", "03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,", "03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000120c0000200e000000010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000120c0000210e000000010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,", "03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,", "03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", "03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000280400000140000000020000,Gravis Gamepad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,", -"030000008f0e00000300000007010000,GreenAsia Inc. USB Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,", "030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", @@ -504,13 +466,11 @@ const char* _glfwDefaultMappings[] = "03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000380700008433000000010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000380700008483000000010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", "03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,", "0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,", "03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,", -"03000000790000000018000000010000,Mayflash Wii U Pro Controller Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,", "03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,", "03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,", @@ -518,19 +478,15 @@ const char* _glfwDefaultMappings[] = "03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,", "03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,", "03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,", -"03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,", -"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,", +"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,", "03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000d620000011a7000010050000,Nintendo Switch PowerA Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", "030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", "03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,", "030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,", "030000004c050000da0c000000010000,Playstation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", -"030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", -"03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,", "030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", "030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", "030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", @@ -557,7 +513,7 @@ const char* _glfwDefaultMappings[] = "03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,", "030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,", "0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,", -"030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"30000004c050000e60c0000000100000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,", @@ -565,7 +521,6 @@ const char* _glfwDefaultMappings[] = "03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,", "03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,", "03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,", -"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,", "03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,", "03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,", "03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", @@ -581,11 +536,9 @@ const char* _glfwDefaultMappings[] = "050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,", "050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,", "030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", -"030000006f0e00000104000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,", -"03000000c62400003a54000000000000,Xbox One PowerA Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", @@ -598,9 +551,6 @@ const char* _glfwDefaultMappings[] = "03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,", "03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", -#endif // _GLFW_COCOA - -#if defined(GLFW_BUILD_LINUX_JOYSTICK) "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", "05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", "05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,", @@ -627,14 +577,12 @@ const char* _glfwDefaultMappings[] = "03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", "05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", "05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", -"03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", -"030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000020010000,8BitDo Wireless Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000c82d00000031000011010000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", "03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", "05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", -"050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,", "05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,", "05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,", -"03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", @@ -642,29 +590,16 @@ const char* _glfwDefaultMappings[] = "03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", "030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,", "05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", -"03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,", -"05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,", "03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", -"03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,", -"03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,", "05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,", "05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,", -"03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,", -"05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,", -"03000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,", -"05000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,", "03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,", -"03000000ef0500000300000000010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,", "03000000c62400001b89000011010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", "03000000c21100000791000011010000,Be1 GC101 Controller 1.03 mode,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", -"05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,", -"03000000120c0000200e000011010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", -"03000000120c0000210e000011010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", -"03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", "03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,", "03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,", @@ -680,7 +615,6 @@ const char* _glfwDefaultMappings[] = "030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", -"03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", "03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", @@ -729,7 +663,6 @@ const char* _glfwDefaultMappings[] = "050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,", "030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,", "050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,", -"03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "03000000242f00002d00000011010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,", "030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", @@ -745,7 +678,6 @@ const char* _glfwDefaultMappings[] = "030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,", "030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,", -"050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", @@ -759,9 +691,8 @@ const char* _glfwDefaultMappings[] = "03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", -"03000000242f0000f700000001010000,Magic-S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,", -"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,", +"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,", "03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,", "03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,", "0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", @@ -791,18 +722,13 @@ const char* _glfwDefaultMappings[] = "03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,", "030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", "030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", -"03000000790000004518000010010000,NEXILUX GAMECUBE Controller Adapter,a:b1,b:b0,x:b2,y:b3,start:b9,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,platform:Linux,", -"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,", -"060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,", +"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,", "060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,", "030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,", -"03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,", -"050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,back:b5,leftshoulder:b2,leftstick:b6,leftx:a1,lefty:a0~,rightshoulder:b4,start:b0,x:b7,y:b10,platform:Linux,", -"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,", +"03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b0,y:b3,platform:Linux,", "050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", -"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,", -"050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0~,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,", -"050000007e0500001720000001000000,Nintendo Switch SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,", +"050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,", +"030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,", "050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,", "05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", "030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,", @@ -813,7 +739,6 @@ const char* _glfwDefaultMappings[] = "19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,", "19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,", "030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,", -"03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,", "05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,", "05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,", "03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,", @@ -829,16 +754,13 @@ const char* _glfwDefaultMappings[] = "030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", "030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", "030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", +"05000000491900000204000000000000,PG-9118,x:b76,a:b73,b:b74,y:b77,back:b83,start:b84,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b79,lefttrigger:b81,rightshoulder:b80,righttrigger:b82,leftstick:b86,rightstick:b87,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,", "0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", -"05000000491900000204000000000000,PG-9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,", -"030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", "03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", -"03000000d62000000228000001010000,PowerA Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", -"03000000c62400001a54000001010000,PowerA Xbox One Mini Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,", "03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", @@ -848,7 +770,6 @@ const char* _glfwDefaultMappings[] = "030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", "030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", -"050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", "050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", "050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", "050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", @@ -870,9 +791,7 @@ const char* _glfwDefaultMappings[] = "050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", "030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", "050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", -"03000000ff000000cb01000010010000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,", "03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,", -"030000009b2800004200000001010000,Raphnet Technologies Dual NES to USB v2.0,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,", "030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,", "030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,", "030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,", @@ -899,8 +818,6 @@ const char* _glfwDefaultMappings[] = "030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", -"03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,", -"03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,", "03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,", "03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,", "03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,", @@ -908,28 +825,27 @@ const char* _glfwDefaultMappings[] = "03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,", "03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", "03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", +"03000000a30600001005000000010000,Saitek Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,", "03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,", +"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,", "03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "03000000bc2000000055000010010000,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", -"030000005f140000c501000010010000,SHANWAN Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", -"030000004c050000e60c000011810000,Sony DualSense,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", -"050000004c050000e60c000000810000,Sony DualSense ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", "03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,", "030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", -"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", -"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", -"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,", -"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", -"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,", +"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,", +"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,", "03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", -"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", -"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", -"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", "03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", @@ -941,7 +857,6 @@ const char* _glfwDefaultMappings[] = "0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", "03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", "030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", -"030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,", "030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,", "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", @@ -988,7 +903,6 @@ const char* _glfwDefaultMappings[] = "030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", -"030000005e040000120b000005050000,XBox Series pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", "03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", @@ -996,7 +910,89 @@ const char* _glfwDefaultMappings[] = "03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,", "03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", "03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", -"03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,", -#endif // GLFW_BUILD_LINUX_JOYSTICK +"05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,", +"050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,", +"05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,", +"05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,", +"05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,", +"0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android,", +"64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,", +"7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android,", +"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,", +"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000005509000014720000df7f3f00,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,", +"050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"030000004c050000cc09000000006800,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,", +"050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,", +"050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,", +"050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,", +"62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,", +"32633532643734376632656664383733,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,", +"61303162353165316365336436343139,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,", +"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,", +"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,", +"050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,", +"30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,", +"050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,", +"050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,", +"34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,", +"050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,", +"05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,", +"05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,", +"05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,", +"05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,", +"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,", +"05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,", +"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,", +"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,", +"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,", +"050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,", +"050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,", +"050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,", +"05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,", +"05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,", +"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,", +"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,", +"050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,", +"050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,", +"050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,", + +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +NULL }; diff --git a/raylib/external/glfw/src/mappings.h.in b/raylib/external/glfw/src/mappings.h.in deleted file mode 100644 index ed62368..0000000 --- a/raylib/external/glfw/src/mappings.h.in +++ /dev/null @@ -1,82 +0,0 @@ -//======================================================================== -// GLFW 3.4 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2006-2018 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== -// As mappings.h.in, this file is used by CMake to produce the mappings.h -// header file. If you are adding a GLFW specific gamepad mapping, this is -// where to put it. -//======================================================================== -// As mappings.h, this provides all pre-defined gamepad mappings, including -// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad -// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. -// This file can be re-generated from mappings.h.in and the upstream -// gamecontrollerdb.txt with the 'update_mappings' CMake target. -//======================================================================== - -// All gamepad mappings not labeled GLFW are copied from the -// SDL_GameControllerDB project under the following license: -// -// Simple DirectMedia Layer -// Copyright (C) 1997-2013 Sam Lantinga -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the -// use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. - -const char* _glfwDefaultMappings[] = -{ -#if defined(_GLFW_WIN32) -@GLFW_WIN32_MAPPINGS@ -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -#endif // _GLFW_WIN32 - -#if defined(_GLFW_COCOA) -@GLFW_COCOA_MAPPINGS@ -#endif // _GLFW_COCOA - -#if defined(GLFW_BUILD_LINUX_JOYSTICK) -@GLFW_LINUX_MAPPINGS@ -#endif // GLFW_BUILD_LINUX_JOYSTICK -}; - diff --git a/raylib/external/glfw/src/monitor.c b/raylib/external/glfw/src/monitor.c index efc286d..394026f 100644 --- a/raylib/external/glfw/src/monitor.c +++ b/raylib/external/glfw/src/monitor.c @@ -24,6 +24,8 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" @@ -72,13 +74,13 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) if (monitor->modes) return GLFW_TRUE; - modes = _glfw.platform.getVideoModes(monitor, &modeCount); + modes = _glfwPlatformGetVideoModes(monitor, &modeCount); if (!modes) return GLFW_FALSE; qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); - _glfw_free(monitor->modes); + free(monitor->modes); monitor->modes = modes; monitor->modeCount = modeCount; @@ -94,16 +96,11 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) // void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) { - assert(monitor != NULL); - assert(action == GLFW_CONNECTED || action == GLFW_DISCONNECTED); - assert(placement == _GLFW_INSERT_FIRST || placement == _GLFW_INSERT_LAST); - if (action == GLFW_CONNECTED) { _glfw.monitorCount++; _glfw.monitors = - _glfw_realloc(_glfw.monitors, - sizeof(_GLFWmonitor*) * _glfw.monitorCount); + realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount); if (placement == _GLFW_INSERT_FIRST) { @@ -125,10 +122,10 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) if (window->monitor == monitor) { int width, height, xoff, yoff; - _glfw.platform.getWindowSize(window, &width, &height); - _glfw.platform.setWindowMonitor(window, NULL, 0, 0, width, height, 0); - _glfw.platform.getWindowFrameSize(window, &xoff, &yoff, NULL, NULL); - _glfw.platform.setWindowPos(window, xoff, yoff); + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL); + _glfwPlatformSetWindowPos(window, xoff, yoff); } } @@ -157,7 +154,6 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) // void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) { - assert(monitor != NULL); monitor->window = window; } @@ -170,11 +166,12 @@ void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) // _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) { - _GLFWmonitor* monitor = _glfw_calloc(1, sizeof(_GLFWmonitor)); + _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); monitor->widthMM = widthMM; monitor->heightMM = heightMM; - strncpy(monitor->name, name, sizeof(monitor->name) - 1); + if (name) + monitor->name = _glfw_strdup(name); return monitor; } @@ -186,22 +183,23 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor) if (monitor == NULL) return; - _glfw.platform.freeMonitor(monitor); + _glfwPlatformFreeMonitor(monitor); _glfwFreeGammaArrays(&monitor->originalRamp); _glfwFreeGammaArrays(&monitor->currentRamp); - _glfw_free(monitor->modes); - _glfw_free(monitor); + free(monitor->modes); + free(monitor->name); + free(monitor); } // Allocates red, green and blue value arrays of the specified size // void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) { - ramp->red = _glfw_calloc(size, sizeof(unsigned short)); - ramp->green = _glfw_calloc(size, sizeof(unsigned short)); - ramp->blue = _glfw_calloc(size, sizeof(unsigned short)); + ramp->red = calloc(size, sizeof(unsigned short)); + ramp->green = calloc(size, sizeof(unsigned short)); + ramp->blue = calloc(size, sizeof(unsigned short)); ramp->size = size; } @@ -209,9 +207,9 @@ void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) // void _glfwFreeGammaArrays(GLFWgammaramp* ramp) { - _glfw_free(ramp->red); - _glfw_free(ramp->green); - _glfw_free(ramp->blue); + free(ramp->red); + free(ramp->green); + free(ramp->blue); memset(ramp, 0, sizeof(GLFWgammaramp)); } @@ -335,7 +333,7 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) _GLFW_REQUIRE_INIT(); - _glfw.platform.getMonitorPos(monitor, xpos, ypos); + _glfwPlatformGetMonitorPos(monitor, xpos, ypos); } GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, @@ -356,7 +354,7 @@ GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, _GLFW_REQUIRE_INIT(); - _glfw.platform.getMonitorWorkarea(monitor, xpos, ypos, width, height); + _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height); } GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) @@ -389,7 +387,7 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle, *yscale = 0.f; _GLFW_REQUIRE_INIT(); - _glfw.platform.getMonitorContentScale(monitor, xscale, yscale); + _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale); } GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) @@ -422,7 +420,7 @@ GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle) GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWmonitorfun, _glfw.callbacks.monitor, cbfun); + _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); return cbfun; } @@ -450,9 +448,7 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (!_glfw.platform.getVideoMode(monitor, &monitor->currentMode)) - return NULL; - + _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); return &monitor->currentMode; } @@ -478,7 +474,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) if (!original) return; - values = _glfw_calloc(original->size, sizeof(unsigned short)); + values = calloc(original->size, sizeof(unsigned short)); for (i = 0; i < original->size; i++) { @@ -489,7 +485,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) // Apply gamma curve value = powf(value, 1.f / gamma) * 65535.f + 0.5f; // Clamp to value range - value = fminf(value, 65535.f); + value = _glfw_fminf(value, 65535.f); values[i] = (unsigned short) value; } @@ -500,7 +496,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) ramp.size = original->size; glfwSetGammaRamp(handle, &ramp); - _glfw_free(values); + free(values); } GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) @@ -511,7 +507,7 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _glfwFreeGammaArrays(&monitor->currentRamp); - if (!_glfw.platform.getGammaRamp(monitor, &monitor->currentRamp)) + if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp)) return NULL; return &monitor->currentRamp; @@ -527,8 +523,6 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) assert(ramp->green != NULL); assert(ramp->blue != NULL); - _GLFW_REQUIRE_INIT(); - if (ramp->size <= 0) { _glfwInputError(GLFW_INVALID_VALUE, @@ -537,12 +531,14 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) return; } + _GLFW_REQUIRE_INIT(); + if (!monitor->originalRamp.size) { - if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp)) + if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp)) return; } - _glfw.platform.setGammaRamp(monitor, ramp); + _glfwPlatformSetGammaRamp(monitor, ramp); } diff --git a/raylib/external/glfw/src/nsgl_context.h b/raylib/external/glfw/src/nsgl_context.h new file mode 100644 index 0000000..9c31436 --- /dev/null +++ b/raylib/external/glfw/src/nsgl_context.h @@ -0,0 +1,66 @@ +//======================================================================== +// GLFW 3.4 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +// NOTE: Many Cocoa enum values have been renamed and we need to build across +// SDK versions where one is unavailable or the other deprecated +// We use the newer names in code and these macros to handle compatibility +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400 + #define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval + #define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity +#endif + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl + +#include + + +// NSGL-specific per-context data +// +typedef struct _GLFWcontextNSGL +{ + id pixelFormat; + id object; + +} _GLFWcontextNSGL; + +// NSGL-specific global data +// +typedef struct _GLFWlibraryNSGL +{ + // dlopen handle for OpenGL.framework (for glfwGetProcAddress) + CFBundleRef framework; + +} _GLFWlibraryNSGL; + + +GLFWbool _glfwInitNSGL(void); +void _glfwTerminateNSGL(void); +GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContextNSGL(_GLFWwindow* window); + diff --git a/raylib/external/glfw/src/nsgl_context.m b/raylib/external/glfw/src/nsgl_context.m index daa8367..3f73f7a 100644 --- a/raylib/external/glfw/src/nsgl_context.m +++ b/raylib/external/glfw/src/nsgl_context.m @@ -23,11 +23,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_COCOA) - #include #include @@ -81,10 +81,11 @@ static void swapIntervalNSGL(int interval) @autoreleasepool { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - assert(window != NULL); - - [window->context.nsgl.object setValues:&interval - forParameter:NSOpenGLContextParameterSwapInterval]; + if (window) + { + [window->context.nsgl.object setValues:&interval + forParameter:NSOpenGLContextParameterSwapInterval]; + } } // autoreleasepool } @@ -161,7 +162,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, - "NSGL: OpenGL ES is not available via NSGL"); + "NSGL: OpenGL ES is not available on macOS"); return GLFW_FALSE; } @@ -175,13 +176,6 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, } } - if (ctxconfig->major >= 3 && ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) - { - _glfwInputError(GLFW_VERSION_UNAVAILABLE, - "NSGL: The compatibility profile is not available on macOS"); - return GLFW_FALSE; - } - // Context robustness modes (GL_KHR_robustness) are not yet supported by // macOS but are not a hard constraint, so ignore and continue @@ -194,45 +188,45 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but // are not a hard constraint, so ignore and continue -#define ADD_ATTRIB(a) \ +#define addAttrib(a) \ { \ assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ } -#define SET_ATTRIB(a, v) { ADD_ATTRIB(a); ADD_ATTRIB(v); } +#define setAttrib(a, v) { addAttrib(a); addAttrib(v); } NSOpenGLPixelFormatAttribute attribs[40]; int index = 0; - ADD_ATTRIB(NSOpenGLPFAAccelerated); - ADD_ATTRIB(NSOpenGLPFAClosestPolicy); + addAttrib(NSOpenGLPFAAccelerated); + addAttrib(NSOpenGLPFAClosestPolicy); if (ctxconfig->nsgl.offline) { - ADD_ATTRIB(NSOpenGLPFAAllowOfflineRenderers); + addAttrib(NSOpenGLPFAAllowOfflineRenderers); // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in // Info.plist for unbundled applications // HACK: This assumes that NSOpenGLPixelFormat will remain // a straightforward wrapper of its CGL counterpart - ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching); + addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 if (ctxconfig->major >= 4) { - SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); } else #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ if (ctxconfig->major >= 3) { - SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } if (ctxconfig->major <= 2) { if (fbconfig->auxBuffers != GLFW_DONT_CARE) - SET_ATTRIB(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); if (fbconfig->accumRedBits != GLFW_DONT_CARE && fbconfig->accumGreenBits != GLFW_DONT_CARE && @@ -244,7 +238,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, fbconfig->accumBlueBits + fbconfig->accumAlphaBits; - SET_ATTRIB(NSOpenGLPFAAccumSize, accumBits); + setAttrib(NSOpenGLPFAAccumSize, accumBits); } } @@ -262,17 +256,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, else if (colorBits < 15) colorBits = 15; - SET_ATTRIB(NSOpenGLPFAColorSize, colorBits); + setAttrib(NSOpenGLPFAColorSize, colorBits); } if (fbconfig->alphaBits != GLFW_DONT_CARE) - SET_ATTRIB(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); if (fbconfig->depthBits != GLFW_DONT_CARE) - SET_ATTRIB(NSOpenGLPFADepthSize, fbconfig->depthBits); + setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); if (fbconfig->stencilBits != GLFW_DONT_CARE) - SET_ATTRIB(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); if (fbconfig->stereo) { @@ -281,33 +275,33 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, "NSGL: Stereo rendering is deprecated"); return GLFW_FALSE; #else - ADD_ATTRIB(NSOpenGLPFAStereo); + addAttrib(NSOpenGLPFAStereo); #endif } if (fbconfig->doublebuffer) - ADD_ATTRIB(NSOpenGLPFADoubleBuffer); + addAttrib(NSOpenGLPFADoubleBuffer); if (fbconfig->samples != GLFW_DONT_CARE) { if (fbconfig->samples == 0) { - SET_ATTRIB(NSOpenGLPFASampleBuffers, 0); + setAttrib(NSOpenGLPFASampleBuffers, 0); } else { - SET_ATTRIB(NSOpenGLPFASampleBuffers, 1); - SET_ATTRIB(NSOpenGLPFASamples, fbconfig->samples); + setAttrib(NSOpenGLPFASampleBuffers, 1); + setAttrib(NSOpenGLPFASamples, fbconfig->samples); } } // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB // framebuffer, so there's no need (and no way) to request it - ADD_ATTRIB(0); + addAttrib(0); -#undef ADD_ATTRIB -#undef SET_ATTRIB +#undef addAttrib +#undef setAttrib window->context.nsgl.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; @@ -340,7 +334,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, forParameter:NSOpenGLContextParameterSurfaceOpacity]; } - [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.scaleFramebuffer]; + [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina]; [window->context.nsgl.object setView:window->ns.view]; @@ -364,14 +358,7 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); - if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "NSGL: Platform not initialized"); - return nil; - } - - if (window->context.source != GLFW_NATIVE_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return nil; @@ -380,5 +367,3 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) return window->context.nsgl.object; } -#endif // _GLFW_COCOA - diff --git a/raylib/external/glfw/src/null_init.c b/raylib/external/glfw/src/null_init.c index 88940fc..57aafd5 100644 --- a/raylib/external/glfw/src/null_init.c +++ b/raylib/external/glfw/src/null_init.c @@ -24,241 +24,34 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" #include -#include ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) +int _glfwPlatformInit(void) { - const _GLFWplatform null = - { - .platformID = GLFW_PLATFORM_NULL, - .init = _glfwInitNull, - .terminate = _glfwTerminateNull, - .getCursorPos = _glfwGetCursorPosNull, - .setCursorPos = _glfwSetCursorPosNull, - .setCursorMode = _glfwSetCursorModeNull, - .setRawMouseMotion = _glfwSetRawMouseMotionNull, - .rawMouseMotionSupported = _glfwRawMouseMotionSupportedNull, - .createCursor = _glfwCreateCursorNull, - .createStandardCursor = _glfwCreateStandardCursorNull, - .destroyCursor = _glfwDestroyCursorNull, - .setCursor = _glfwSetCursorNull, - .getScancodeName = _glfwGetScancodeNameNull, - .getKeyScancode = _glfwGetKeyScancodeNull, - .setClipboardString = _glfwSetClipboardStringNull, - .getClipboardString = _glfwGetClipboardStringNull, - .initJoysticks = _glfwInitJoysticksNull, - .terminateJoysticks = _glfwTerminateJoysticksNull, - .pollJoystick = _glfwPollJoystickNull, - .getMappingName = _glfwGetMappingNameNull, - .updateGamepadGUID = _glfwUpdateGamepadGUIDNull, - .freeMonitor = _glfwFreeMonitorNull, - .getMonitorPos = _glfwGetMonitorPosNull, - .getMonitorContentScale = _glfwGetMonitorContentScaleNull, - .getMonitorWorkarea = _glfwGetMonitorWorkareaNull, - .getVideoModes = _glfwGetVideoModesNull, - .getVideoMode = _glfwGetVideoModeNull, - .getGammaRamp = _glfwGetGammaRampNull, - .setGammaRamp = _glfwSetGammaRampNull, - .createWindow = _glfwCreateWindowNull, - .destroyWindow = _glfwDestroyWindowNull, - .setWindowTitle = _glfwSetWindowTitleNull, - .setWindowIcon = _glfwSetWindowIconNull, - .getWindowPos = _glfwGetWindowPosNull, - .setWindowPos = _glfwSetWindowPosNull, - .getWindowSize = _glfwGetWindowSizeNull, - .setWindowSize = _glfwSetWindowSizeNull, - .setWindowSizeLimits = _glfwSetWindowSizeLimitsNull, - .setWindowAspectRatio = _glfwSetWindowAspectRatioNull, - .getFramebufferSize = _glfwGetFramebufferSizeNull, - .getWindowFrameSize = _glfwGetWindowFrameSizeNull, - .getWindowContentScale = _glfwGetWindowContentScaleNull, - .iconifyWindow = _glfwIconifyWindowNull, - .restoreWindow = _glfwRestoreWindowNull, - .maximizeWindow = _glfwMaximizeWindowNull, - .showWindow = _glfwShowWindowNull, - .hideWindow = _glfwHideWindowNull, - .requestWindowAttention = _glfwRequestWindowAttentionNull, - .focusWindow = _glfwFocusWindowNull, - .setWindowMonitor = _glfwSetWindowMonitorNull, - .windowFocused = _glfwWindowFocusedNull, - .windowIconified = _glfwWindowIconifiedNull, - .windowVisible = _glfwWindowVisibleNull, - .windowMaximized = _glfwWindowMaximizedNull, - .windowHovered = _glfwWindowHoveredNull, - .framebufferTransparent = _glfwFramebufferTransparentNull, - .getWindowOpacity = _glfwGetWindowOpacityNull, - .setWindowResizable = _glfwSetWindowResizableNull, - .setWindowDecorated = _glfwSetWindowDecoratedNull, - .setWindowFloating = _glfwSetWindowFloatingNull, - .setWindowOpacity = _glfwSetWindowOpacityNull, - .setWindowMousePassthrough = _glfwSetWindowMousePassthroughNull, - .pollEvents = _glfwPollEventsNull, - .waitEvents = _glfwWaitEventsNull, - .waitEventsTimeout = _glfwWaitEventsTimeoutNull, - .postEmptyEvent = _glfwPostEmptyEventNull, - .getEGLPlatform = _glfwGetEGLPlatformNull, - .getEGLNativeDisplay = _glfwGetEGLNativeDisplayNull, - .getEGLNativeWindow = _glfwGetEGLNativeWindowNull, - .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsNull, - .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportNull, - .createWindowSurface = _glfwCreateWindowSurfaceNull - }; - - *platform = null; - return GLFW_TRUE; -} - -int _glfwInitNull(void) -{ - int scancode; - - memset(_glfw.null.keycodes, -1, sizeof(_glfw.null.keycodes)); - memset(_glfw.null.scancodes, -1, sizeof(_glfw.null.scancodes)); - - _glfw.null.keycodes[GLFW_NULL_SC_SPACE] = GLFW_KEY_SPACE; - _glfw.null.keycodes[GLFW_NULL_SC_APOSTROPHE] = GLFW_KEY_APOSTROPHE; - _glfw.null.keycodes[GLFW_NULL_SC_COMMA] = GLFW_KEY_COMMA; - _glfw.null.keycodes[GLFW_NULL_SC_MINUS] = GLFW_KEY_MINUS; - _glfw.null.keycodes[GLFW_NULL_SC_PERIOD] = GLFW_KEY_PERIOD; - _glfw.null.keycodes[GLFW_NULL_SC_SLASH] = GLFW_KEY_SLASH; - _glfw.null.keycodes[GLFW_NULL_SC_0] = GLFW_KEY_0; - _glfw.null.keycodes[GLFW_NULL_SC_1] = GLFW_KEY_1; - _glfw.null.keycodes[GLFW_NULL_SC_2] = GLFW_KEY_2; - _glfw.null.keycodes[GLFW_NULL_SC_3] = GLFW_KEY_3; - _glfw.null.keycodes[GLFW_NULL_SC_4] = GLFW_KEY_4; - _glfw.null.keycodes[GLFW_NULL_SC_5] = GLFW_KEY_5; - _glfw.null.keycodes[GLFW_NULL_SC_6] = GLFW_KEY_6; - _glfw.null.keycodes[GLFW_NULL_SC_7] = GLFW_KEY_7; - _glfw.null.keycodes[GLFW_NULL_SC_8] = GLFW_KEY_8; - _glfw.null.keycodes[GLFW_NULL_SC_9] = GLFW_KEY_9; - _glfw.null.keycodes[GLFW_NULL_SC_SEMICOLON] = GLFW_KEY_SEMICOLON; - _glfw.null.keycodes[GLFW_NULL_SC_EQUAL] = GLFW_KEY_EQUAL; - _glfw.null.keycodes[GLFW_NULL_SC_A] = GLFW_KEY_A; - _glfw.null.keycodes[GLFW_NULL_SC_B] = GLFW_KEY_B; - _glfw.null.keycodes[GLFW_NULL_SC_C] = GLFW_KEY_C; - _glfw.null.keycodes[GLFW_NULL_SC_D] = GLFW_KEY_D; - _glfw.null.keycodes[GLFW_NULL_SC_E] = GLFW_KEY_E; - _glfw.null.keycodes[GLFW_NULL_SC_F] = GLFW_KEY_F; - _glfw.null.keycodes[GLFW_NULL_SC_G] = GLFW_KEY_G; - _glfw.null.keycodes[GLFW_NULL_SC_H] = GLFW_KEY_H; - _glfw.null.keycodes[GLFW_NULL_SC_I] = GLFW_KEY_I; - _glfw.null.keycodes[GLFW_NULL_SC_J] = GLFW_KEY_J; - _glfw.null.keycodes[GLFW_NULL_SC_K] = GLFW_KEY_K; - _glfw.null.keycodes[GLFW_NULL_SC_L] = GLFW_KEY_L; - _glfw.null.keycodes[GLFW_NULL_SC_M] = GLFW_KEY_M; - _glfw.null.keycodes[GLFW_NULL_SC_N] = GLFW_KEY_N; - _glfw.null.keycodes[GLFW_NULL_SC_O] = GLFW_KEY_O; - _glfw.null.keycodes[GLFW_NULL_SC_P] = GLFW_KEY_P; - _glfw.null.keycodes[GLFW_NULL_SC_Q] = GLFW_KEY_Q; - _glfw.null.keycodes[GLFW_NULL_SC_R] = GLFW_KEY_R; - _glfw.null.keycodes[GLFW_NULL_SC_S] = GLFW_KEY_S; - _glfw.null.keycodes[GLFW_NULL_SC_T] = GLFW_KEY_T; - _glfw.null.keycodes[GLFW_NULL_SC_U] = GLFW_KEY_U; - _glfw.null.keycodes[GLFW_NULL_SC_V] = GLFW_KEY_V; - _glfw.null.keycodes[GLFW_NULL_SC_W] = GLFW_KEY_W; - _glfw.null.keycodes[GLFW_NULL_SC_X] = GLFW_KEY_X; - _glfw.null.keycodes[GLFW_NULL_SC_Y] = GLFW_KEY_Y; - _glfw.null.keycodes[GLFW_NULL_SC_Z] = GLFW_KEY_Z; - _glfw.null.keycodes[GLFW_NULL_SC_LEFT_BRACKET] = GLFW_KEY_LEFT_BRACKET; - _glfw.null.keycodes[GLFW_NULL_SC_BACKSLASH] = GLFW_KEY_BACKSLASH; - _glfw.null.keycodes[GLFW_NULL_SC_RIGHT_BRACKET] = GLFW_KEY_RIGHT_BRACKET; - _glfw.null.keycodes[GLFW_NULL_SC_GRAVE_ACCENT] = GLFW_KEY_GRAVE_ACCENT; - _glfw.null.keycodes[GLFW_NULL_SC_WORLD_1] = GLFW_KEY_WORLD_1; - _glfw.null.keycodes[GLFW_NULL_SC_WORLD_2] = GLFW_KEY_WORLD_2; - _glfw.null.keycodes[GLFW_NULL_SC_ESCAPE] = GLFW_KEY_ESCAPE; - _glfw.null.keycodes[GLFW_NULL_SC_ENTER] = GLFW_KEY_ENTER; - _glfw.null.keycodes[GLFW_NULL_SC_TAB] = GLFW_KEY_TAB; - _glfw.null.keycodes[GLFW_NULL_SC_BACKSPACE] = GLFW_KEY_BACKSPACE; - _glfw.null.keycodes[GLFW_NULL_SC_INSERT] = GLFW_KEY_INSERT; - _glfw.null.keycodes[GLFW_NULL_SC_DELETE] = GLFW_KEY_DELETE; - _glfw.null.keycodes[GLFW_NULL_SC_RIGHT] = GLFW_KEY_RIGHT; - _glfw.null.keycodes[GLFW_NULL_SC_LEFT] = GLFW_KEY_LEFT; - _glfw.null.keycodes[GLFW_NULL_SC_DOWN] = GLFW_KEY_DOWN; - _glfw.null.keycodes[GLFW_NULL_SC_UP] = GLFW_KEY_UP; - _glfw.null.keycodes[GLFW_NULL_SC_PAGE_UP] = GLFW_KEY_PAGE_UP; - _glfw.null.keycodes[GLFW_NULL_SC_PAGE_DOWN] = GLFW_KEY_PAGE_DOWN; - _glfw.null.keycodes[GLFW_NULL_SC_HOME] = GLFW_KEY_HOME; - _glfw.null.keycodes[GLFW_NULL_SC_END] = GLFW_KEY_END; - _glfw.null.keycodes[GLFW_NULL_SC_CAPS_LOCK] = GLFW_KEY_CAPS_LOCK; - _glfw.null.keycodes[GLFW_NULL_SC_SCROLL_LOCK] = GLFW_KEY_SCROLL_LOCK; - _glfw.null.keycodes[GLFW_NULL_SC_NUM_LOCK] = GLFW_KEY_NUM_LOCK; - _glfw.null.keycodes[GLFW_NULL_SC_PRINT_SCREEN] = GLFW_KEY_PRINT_SCREEN; - _glfw.null.keycodes[GLFW_NULL_SC_PAUSE] = GLFW_KEY_PAUSE; - _glfw.null.keycodes[GLFW_NULL_SC_F1] = GLFW_KEY_F1; - _glfw.null.keycodes[GLFW_NULL_SC_F2] = GLFW_KEY_F2; - _glfw.null.keycodes[GLFW_NULL_SC_F3] = GLFW_KEY_F3; - _glfw.null.keycodes[GLFW_NULL_SC_F4] = GLFW_KEY_F4; - _glfw.null.keycodes[GLFW_NULL_SC_F5] = GLFW_KEY_F5; - _glfw.null.keycodes[GLFW_NULL_SC_F6] = GLFW_KEY_F6; - _glfw.null.keycodes[GLFW_NULL_SC_F7] = GLFW_KEY_F7; - _glfw.null.keycodes[GLFW_NULL_SC_F8] = GLFW_KEY_F8; - _glfw.null.keycodes[GLFW_NULL_SC_F9] = GLFW_KEY_F9; - _glfw.null.keycodes[GLFW_NULL_SC_F10] = GLFW_KEY_F10; - _glfw.null.keycodes[GLFW_NULL_SC_F11] = GLFW_KEY_F11; - _glfw.null.keycodes[GLFW_NULL_SC_F12] = GLFW_KEY_F12; - _glfw.null.keycodes[GLFW_NULL_SC_F13] = GLFW_KEY_F13; - _glfw.null.keycodes[GLFW_NULL_SC_F14] = GLFW_KEY_F14; - _glfw.null.keycodes[GLFW_NULL_SC_F15] = GLFW_KEY_F15; - _glfw.null.keycodes[GLFW_NULL_SC_F16] = GLFW_KEY_F16; - _glfw.null.keycodes[GLFW_NULL_SC_F17] = GLFW_KEY_F17; - _glfw.null.keycodes[GLFW_NULL_SC_F18] = GLFW_KEY_F18; - _glfw.null.keycodes[GLFW_NULL_SC_F19] = GLFW_KEY_F19; - _glfw.null.keycodes[GLFW_NULL_SC_F20] = GLFW_KEY_F20; - _glfw.null.keycodes[GLFW_NULL_SC_F21] = GLFW_KEY_F21; - _glfw.null.keycodes[GLFW_NULL_SC_F22] = GLFW_KEY_F22; - _glfw.null.keycodes[GLFW_NULL_SC_F23] = GLFW_KEY_F23; - _glfw.null.keycodes[GLFW_NULL_SC_F24] = GLFW_KEY_F24; - _glfw.null.keycodes[GLFW_NULL_SC_F25] = GLFW_KEY_F25; - _glfw.null.keycodes[GLFW_NULL_SC_KP_0] = GLFW_KEY_KP_0; - _glfw.null.keycodes[GLFW_NULL_SC_KP_1] = GLFW_KEY_KP_1; - _glfw.null.keycodes[GLFW_NULL_SC_KP_2] = GLFW_KEY_KP_2; - _glfw.null.keycodes[GLFW_NULL_SC_KP_3] = GLFW_KEY_KP_3; - _glfw.null.keycodes[GLFW_NULL_SC_KP_4] = GLFW_KEY_KP_4; - _glfw.null.keycodes[GLFW_NULL_SC_KP_5] = GLFW_KEY_KP_5; - _glfw.null.keycodes[GLFW_NULL_SC_KP_6] = GLFW_KEY_KP_6; - _glfw.null.keycodes[GLFW_NULL_SC_KP_7] = GLFW_KEY_KP_7; - _glfw.null.keycodes[GLFW_NULL_SC_KP_8] = GLFW_KEY_KP_8; - _glfw.null.keycodes[GLFW_NULL_SC_KP_9] = GLFW_KEY_KP_9; - _glfw.null.keycodes[GLFW_NULL_SC_KP_DECIMAL] = GLFW_KEY_KP_DECIMAL; - _glfw.null.keycodes[GLFW_NULL_SC_KP_DIVIDE] = GLFW_KEY_KP_DIVIDE; - _glfw.null.keycodes[GLFW_NULL_SC_KP_MULTIPLY] = GLFW_KEY_KP_MULTIPLY; - _glfw.null.keycodes[GLFW_NULL_SC_KP_SUBTRACT] = GLFW_KEY_KP_SUBTRACT; - _glfw.null.keycodes[GLFW_NULL_SC_KP_ADD] = GLFW_KEY_KP_ADD; - _glfw.null.keycodes[GLFW_NULL_SC_KP_ENTER] = GLFW_KEY_KP_ENTER; - _glfw.null.keycodes[GLFW_NULL_SC_KP_EQUAL] = GLFW_KEY_KP_EQUAL; - _glfw.null.keycodes[GLFW_NULL_SC_LEFT_SHIFT] = GLFW_KEY_LEFT_SHIFT; - _glfw.null.keycodes[GLFW_NULL_SC_LEFT_CONTROL] = GLFW_KEY_LEFT_CONTROL; - _glfw.null.keycodes[GLFW_NULL_SC_LEFT_ALT] = GLFW_KEY_LEFT_ALT; - _glfw.null.keycodes[GLFW_NULL_SC_LEFT_SUPER] = GLFW_KEY_LEFT_SUPER; - _glfw.null.keycodes[GLFW_NULL_SC_RIGHT_SHIFT] = GLFW_KEY_RIGHT_SHIFT; - _glfw.null.keycodes[GLFW_NULL_SC_RIGHT_CONTROL] = GLFW_KEY_RIGHT_CONTROL; - _glfw.null.keycodes[GLFW_NULL_SC_RIGHT_ALT] = GLFW_KEY_RIGHT_ALT; - _glfw.null.keycodes[GLFW_NULL_SC_RIGHT_SUPER] = GLFW_KEY_RIGHT_SUPER; - _glfw.null.keycodes[GLFW_NULL_SC_MENU] = GLFW_KEY_MENU; - - for (scancode = GLFW_NULL_SC_FIRST; scancode < GLFW_NULL_SC_LAST; scancode++) - { - if (_glfw.null.keycodes[scancode] > 0) - _glfw.null.scancodes[_glfw.null.keycodes[scancode]] = scancode; - } - + _glfwInitTimerPOSIX(); _glfwPollMonitorsNull(); + return GLFW_TRUE; } -void _glfwTerminateNull(void) +void _glfwPlatformTerminate(void) { free(_glfw.null.clipboardString); _glfwTerminateOSMesa(); - _glfwTerminateEGL(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " null OSMesa"; } diff --git a/raylib/external/glfw/src/null_joystick.c b/raylib/external/glfw/src/null_joystick.c index ec1f6b5..27756a6 100644 --- a/raylib/external/glfw/src/null_joystick.c +++ b/raylib/external/glfw/src/null_joystick.c @@ -23,6 +23,8 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" @@ -31,26 +33,21 @@ ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwInitJoysticksNull(void) +GLFWbool _glfwPlatformInitJoysticks(void) { return GLFW_TRUE; } -void _glfwTerminateJoysticksNull(void) +void _glfwPlatformTerminateJoysticks(void) { } -GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { return GLFW_FALSE; } -const char* _glfwGetMappingNameNull(void) -{ - return ""; -} - -void _glfwUpdateGamepadGUIDNull(char* guid) +void _glfwPlatformUpdateGamepadGUID(char* guid) { } diff --git a/raylib/external/glfw/src/null_joystick.h b/raylib/external/glfw/src/null_joystick.h index a2199c5..5d19a45 100644 --- a/raylib/external/glfw/src/null_joystick.h +++ b/raylib/external/glfw/src/null_joystick.h @@ -24,9 +24,8 @@ // //======================================================================== -GLFWbool _glfwInitJoysticksNull(void); -void _glfwTerminateJoysticksNull(void); -GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode); -const char* _glfwGetMappingNameNull(void); -void _glfwUpdateGamepadGUIDNull(char* guid); +#define _GLFW_PLATFORM_JOYSTICK_STATE struct { int dummyJoystick; } +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; } + +#define _GLFW_PLATFORM_MAPPING_NAME "" diff --git a/raylib/external/glfw/src/null_monitor.c b/raylib/external/glfw/src/null_monitor.c index d818f45..8301eb3 100644 --- a/raylib/external/glfw/src/null_monitor.c +++ b/raylib/external/glfw/src/null_monitor.c @@ -24,6 +24,8 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" @@ -63,12 +65,12 @@ void _glfwPollMonitorsNull(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwFreeMonitorNull(_GLFWmonitor* monitor) +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { _glfwFreeGammaArrays(&monitor->null.ramp); } -void _glfwGetMonitorPosNull(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (xpos) *xpos = 0; @@ -76,8 +78,8 @@ void _glfwGetMonitorPosNull(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = 0; } -void _glfwGetMonitorContentScaleNull(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) { if (xscale) *xscale = 1.f; @@ -85,9 +87,9 @@ void _glfwGetMonitorContentScaleNull(_GLFWmonitor* monitor, *yscale = 1.f; } -void _glfwGetMonitorWorkareaNull(_GLFWmonitor* monitor, - int* xpos, int* ypos, - int* width, int* height) +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) { const GLFWvidmode mode = getVideoMode(); @@ -101,35 +103,32 @@ void _glfwGetMonitorWorkareaNull(_GLFWmonitor* monitor, *height = mode.height - 10; } -GLFWvidmode* _glfwGetVideoModesNull(_GLFWmonitor* monitor, int* found) +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { - GLFWvidmode* mode = _glfw_calloc(1, sizeof(GLFWvidmode)); + GLFWvidmode* mode = calloc(1, sizeof(GLFWvidmode)); *mode = getVideoMode(); *found = 1; return mode; } -GLFWbool _glfwGetVideoModeNull(_GLFWmonitor* monitor, GLFWvidmode* mode) +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { *mode = getVideoMode(); - return GLFW_TRUE; } -GLFWbool _glfwGetGammaRampNull(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { if (!monitor->null.ramp.size) { - unsigned int i; - _glfwAllocGammaArrays(&monitor->null.ramp, 256); - for (i = 0; i < monitor->null.ramp.size; i++) + for (unsigned int i = 0; i < monitor->null.ramp.size; i++) { const float gamma = 2.2f; float value; value = i / (float) (monitor->null.ramp.size - 1); value = powf(value, 1.f / gamma) * 65535.f + 0.5f; - value = fminf(value, 65535.f); + value = _glfw_fminf(value, 65535.f); monitor->null.ramp.red[i] = (unsigned short) value; monitor->null.ramp.green[i] = (unsigned short) value; @@ -144,7 +143,7 @@ GLFWbool _glfwGetGammaRampNull(_GLFWmonitor* monitor, GLFWgammaramp* ramp) return GLFW_TRUE; } -void _glfwSetGammaRampNull(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { if (monitor->null.ramp.size != ramp->size) { diff --git a/raylib/external/glfw/src/null_platform.h b/raylib/external/glfw/src/null_platform.h index 4843a76..49436dc 100644 --- a/raylib/external/glfw/src/null_platform.h +++ b/raylib/external/glfw/src/null_platform.h @@ -25,136 +25,29 @@ // //======================================================================== -#define GLFW_NULL_WINDOW_STATE _GLFWwindowNull null; -#define GLFW_NULL_LIBRARY_WINDOW_STATE _GLFWlibraryNull null; -#define GLFW_NULL_MONITOR_STATE _GLFWmonitorNull null; +#include -#define GLFW_NULL_CONTEXT_STATE -#define GLFW_NULL_CURSOR_STATE -#define GLFW_NULL_LIBRARY_CONTEXT_STATE +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNull null +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNull null -#define GLFW_NULL_SC_FIRST GLFW_NULL_SC_SPACE -#define GLFW_NULL_SC_SPACE 1 -#define GLFW_NULL_SC_APOSTROPHE 2 -#define GLFW_NULL_SC_COMMA 3 -#define GLFW_NULL_SC_MINUS 4 -#define GLFW_NULL_SC_PERIOD 5 -#define GLFW_NULL_SC_SLASH 6 -#define GLFW_NULL_SC_0 7 -#define GLFW_NULL_SC_1 8 -#define GLFW_NULL_SC_2 9 -#define GLFW_NULL_SC_3 10 -#define GLFW_NULL_SC_4 11 -#define GLFW_NULL_SC_5 12 -#define GLFW_NULL_SC_6 13 -#define GLFW_NULL_SC_7 14 -#define GLFW_NULL_SC_8 15 -#define GLFW_NULL_SC_9 16 -#define GLFW_NULL_SC_SEMICOLON 17 -#define GLFW_NULL_SC_EQUAL 18 -#define GLFW_NULL_SC_LEFT_BRACKET 19 -#define GLFW_NULL_SC_BACKSLASH 20 -#define GLFW_NULL_SC_RIGHT_BRACKET 21 -#define GLFW_NULL_SC_GRAVE_ACCENT 22 -#define GLFW_NULL_SC_WORLD_1 23 -#define GLFW_NULL_SC_WORLD_2 24 -#define GLFW_NULL_SC_ESCAPE 25 -#define GLFW_NULL_SC_ENTER 26 -#define GLFW_NULL_SC_TAB 27 -#define GLFW_NULL_SC_BACKSPACE 28 -#define GLFW_NULL_SC_INSERT 29 -#define GLFW_NULL_SC_DELETE 30 -#define GLFW_NULL_SC_RIGHT 31 -#define GLFW_NULL_SC_LEFT 32 -#define GLFW_NULL_SC_DOWN 33 -#define GLFW_NULL_SC_UP 34 -#define GLFW_NULL_SC_PAGE_UP 35 -#define GLFW_NULL_SC_PAGE_DOWN 36 -#define GLFW_NULL_SC_HOME 37 -#define GLFW_NULL_SC_END 38 -#define GLFW_NULL_SC_CAPS_LOCK 39 -#define GLFW_NULL_SC_SCROLL_LOCK 40 -#define GLFW_NULL_SC_NUM_LOCK 41 -#define GLFW_NULL_SC_PRINT_SCREEN 42 -#define GLFW_NULL_SC_PAUSE 43 -#define GLFW_NULL_SC_A 44 -#define GLFW_NULL_SC_B 45 -#define GLFW_NULL_SC_C 46 -#define GLFW_NULL_SC_D 47 -#define GLFW_NULL_SC_E 48 -#define GLFW_NULL_SC_F 49 -#define GLFW_NULL_SC_G 50 -#define GLFW_NULL_SC_H 51 -#define GLFW_NULL_SC_I 52 -#define GLFW_NULL_SC_J 53 -#define GLFW_NULL_SC_K 54 -#define GLFW_NULL_SC_L 55 -#define GLFW_NULL_SC_M 56 -#define GLFW_NULL_SC_N 57 -#define GLFW_NULL_SC_O 58 -#define GLFW_NULL_SC_P 59 -#define GLFW_NULL_SC_Q 60 -#define GLFW_NULL_SC_R 61 -#define GLFW_NULL_SC_S 62 -#define GLFW_NULL_SC_T 63 -#define GLFW_NULL_SC_U 64 -#define GLFW_NULL_SC_V 65 -#define GLFW_NULL_SC_W 66 -#define GLFW_NULL_SC_X 67 -#define GLFW_NULL_SC_Y 68 -#define GLFW_NULL_SC_Z 69 -#define GLFW_NULL_SC_F1 70 -#define GLFW_NULL_SC_F2 71 -#define GLFW_NULL_SC_F3 72 -#define GLFW_NULL_SC_F4 73 -#define GLFW_NULL_SC_F5 74 -#define GLFW_NULL_SC_F6 75 -#define GLFW_NULL_SC_F7 76 -#define GLFW_NULL_SC_F8 77 -#define GLFW_NULL_SC_F9 78 -#define GLFW_NULL_SC_F10 79 -#define GLFW_NULL_SC_F11 80 -#define GLFW_NULL_SC_F12 81 -#define GLFW_NULL_SC_F13 82 -#define GLFW_NULL_SC_F14 83 -#define GLFW_NULL_SC_F15 84 -#define GLFW_NULL_SC_F16 85 -#define GLFW_NULL_SC_F17 86 -#define GLFW_NULL_SC_F18 87 -#define GLFW_NULL_SC_F19 88 -#define GLFW_NULL_SC_F20 89 -#define GLFW_NULL_SC_F21 90 -#define GLFW_NULL_SC_F22 91 -#define GLFW_NULL_SC_F23 92 -#define GLFW_NULL_SC_F24 93 -#define GLFW_NULL_SC_F25 94 -#define GLFW_NULL_SC_KP_0 95 -#define GLFW_NULL_SC_KP_1 96 -#define GLFW_NULL_SC_KP_2 97 -#define GLFW_NULL_SC_KP_3 98 -#define GLFW_NULL_SC_KP_4 99 -#define GLFW_NULL_SC_KP_5 100 -#define GLFW_NULL_SC_KP_6 101 -#define GLFW_NULL_SC_KP_7 102 -#define GLFW_NULL_SC_KP_8 103 -#define GLFW_NULL_SC_KP_9 104 -#define GLFW_NULL_SC_KP_DECIMAL 105 -#define GLFW_NULL_SC_KP_DIVIDE 106 -#define GLFW_NULL_SC_KP_MULTIPLY 107 -#define GLFW_NULL_SC_KP_SUBTRACT 108 -#define GLFW_NULL_SC_KP_ADD 109 -#define GLFW_NULL_SC_KP_ENTER 110 -#define GLFW_NULL_SC_KP_EQUAL 111 -#define GLFW_NULL_SC_LEFT_SHIFT 112 -#define GLFW_NULL_SC_LEFT_CONTROL 113 -#define GLFW_NULL_SC_LEFT_ALT 114 -#define GLFW_NULL_SC_LEFT_SUPER 115 -#define GLFW_NULL_SC_RIGHT_SHIFT 116 -#define GLFW_NULL_SC_RIGHT_CONTROL 117 -#define GLFW_NULL_SC_RIGHT_ALT 118 -#define GLFW_NULL_SC_RIGHT_SUPER 119 -#define GLFW_NULL_SC_MENU 120 -#define GLFW_NULL_SC_LAST GLFW_NULL_SC_MENU +#define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; } +#define _GLFW_PLATFORM_CURSOR_STATE struct { int dummyCursor; } +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; } + +#include "posix_time.h" +#include "posix_thread.h" +#include "null_joystick.h" + +#if defined(_GLFW_WIN32) + #define _glfw_dlopen(name) LoadLibraryA(name) + #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) + #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) +#else + #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) + #define _glfw_dlclose(handle) dlclose(handle) + #define _glfw_dlsym(handle, name) dlsym(handle, name) +#endif // Null-specific per-window data // @@ -164,6 +57,7 @@ typedef struct _GLFWwindowNull int ypos; int width; int height; + char* title; GLFWbool visible; GLFWbool iconified; GLFWbool maximized; @@ -189,83 +83,7 @@ typedef struct _GLFWlibraryNull int ycursor; char* clipboardString; _GLFWwindow* focusedWindow; - uint16_t keycodes[GLFW_NULL_SC_LAST + 1]; - uint8_t scancodes[GLFW_KEY_LAST + 1]; } _GLFWlibraryNull; void _glfwPollMonitorsNull(void); -GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform); -int _glfwInitNull(void); -void _glfwTerminateNull(void); - -void _glfwFreeMonitorNull(_GLFWmonitor* monitor); -void _glfwGetMonitorPosNull(_GLFWmonitor* monitor, int* xpos, int* ypos); -void _glfwGetMonitorContentScaleNull(_GLFWmonitor* monitor, float* xscale, float* yscale); -void _glfwGetMonitorWorkareaNull(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); -GLFWvidmode* _glfwGetVideoModesNull(_GLFWmonitor* monitor, int* found); -GLFWbool _glfwGetVideoModeNull(_GLFWmonitor* monitor, GLFWvidmode* mode); -GLFWbool _glfwGetGammaRampNull(_GLFWmonitor* monitor, GLFWgammaramp* ramp); -void _glfwSetGammaRampNull(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); - -GLFWbool _glfwCreateWindowNull(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyWindowNull(_GLFWwindow* window); -void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title); -void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwSetWindowMonitorNull(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); -void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos); -void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos); -void _glfwGetWindowSizeNull(_GLFWwindow* window, int* width, int* height); -void _glfwSetWindowSizeNull(_GLFWwindow* window, int width, int height); -void _glfwSetWindowSizeLimitsNull(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); -void _glfwSetWindowAspectRatioNull(_GLFWwindow* window, int n, int d); -void _glfwGetFramebufferSizeNull(_GLFWwindow* window, int* width, int* height); -void _glfwGetWindowFrameSizeNull(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); -void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* yscale); -void _glfwIconifyWindowNull(_GLFWwindow* window); -void _glfwRestoreWindowNull(_GLFWwindow* window); -void _glfwMaximizeWindowNull(_GLFWwindow* window); -GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window); -GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window); -GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window); -void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled); -float _glfwGetWindowOpacityNull(_GLFWwindow* window); -void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity); -void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled); -GLFWbool _glfwRawMouseMotionSupportedNull(void); -void _glfwShowWindowNull(_GLFWwindow* window); -void _glfwRequestWindowAttentionNull(_GLFWwindow* window); -void _glfwHideWindowNull(_GLFWwindow* window); -void _glfwFocusWindowNull(_GLFWwindow* window); -GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window); -GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window); -GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window); -void _glfwPollEventsNull(void); -void _glfwWaitEventsNull(void); -void _glfwWaitEventsTimeoutNull(double timeout); -void _glfwPostEmptyEventNull(void); -void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos); -void _glfwSetCursorPosNull(_GLFWwindow* window, double x, double y); -void _glfwSetCursorModeNull(_GLFWwindow* window, int mode); -GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); -GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape); -void _glfwDestroyCursorNull(_GLFWcursor* cursor); -void _glfwSetCursorNull(_GLFWwindow* window, _GLFWcursor* cursor); -void _glfwSetClipboardStringNull(const char* string); -const char* _glfwGetClipboardStringNull(void); -const char* _glfwGetScancodeNameNull(int scancode); -int _glfwGetKeyScancodeNull(int key); - -EGLenum _glfwGetEGLPlatformNull(EGLint** attribs); -EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void); -EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window); - -void _glfwGetRequiredInstanceExtensionsNull(char** extensions); -GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); -VkResult _glfwCreateWindowSurfaceNull(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -void _glfwPollMonitorsNull(void); - diff --git a/raylib/external/glfw/src/null_window.c b/raylib/external/glfw/src/null_window.c index cd23ae0..3e44664 100644 --- a/raylib/external/glfw/src/null_window.c +++ b/raylib/external/glfw/src/null_window.c @@ -1,9 +1,8 @@ //======================================================================== -// GLFW 3.4 (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -25,6 +24,8 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" @@ -38,34 +39,34 @@ static void applySizeLimits(_GLFWwindow* window, int* width, int* height) *height = (int) (*width / ratio); } - if (window->minwidth != GLFW_DONT_CARE) - *width = _glfw_max(*width, window->minwidth); - else if (window->maxwidth != GLFW_DONT_CARE) - *width = _glfw_min(*width, window->maxwidth); + if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth) + *width = window->minwidth; + else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth) + *width = window->maxwidth; - if (window->minheight != GLFW_DONT_CARE) - *height = _glfw_min(*height, window->minheight); - else if (window->maxheight != GLFW_DONT_CARE) - *height = _glfw_max(*height, window->maxheight); + if (window->minheight != GLFW_DONT_CARE && *height < window->minheight) + *height = window->minheight; + else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight) + *height = window->maxheight; } static void fitToMonitor(_GLFWwindow* window) { GLFWvidmode mode; - _glfwGetVideoModeNull(window->monitor, &mode); - _glfwGetMonitorPosNull(window->monitor, - &window->null.xpos, - &window->null.ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, + &window->null.xpos, + &window->null.ypos); window->null.width = mode.width; window->null.height = mode.height; } -static void acquireMonitorNull(_GLFWwindow* window) +static void acquireMonitor(_GLFWwindow* window) { _glfwInputMonitorWindow(window->monitor, window); } -static void releaseMonitorNull(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; @@ -81,17 +82,8 @@ static int createNativeWindow(_GLFWwindow* window, fitToMonitor(window); else { - if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION) - { - window->null.xpos = 17; - window->null.ypos = 17; - } - else - { - window->null.xpos = wndconfig->xpos; - window->null.ypos = wndconfig->ypos; - } - + window->null.xpos = 17; + window->null.ypos = 17; window->null.width = wndconfig->width; window->null.height = wndconfig->height; } @@ -111,10 +103,10 @@ static int createNativeWindow(_GLFWwindow* window, ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwCreateWindowNull(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; @@ -129,47 +121,27 @@ GLFWbool _glfwCreateWindowNull(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } - else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) + else { - if (!_glfwInitEGL()) - return GLFW_FALSE; - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; - } - - if (!_glfwRefreshContextAttribs(window, ctxconfig)) + _glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available"); return GLFW_FALSE; + } } - if (wndconfig->mousePassthrough) - _glfwSetWindowMousePassthroughNull(window, GLFW_TRUE); - if (window->monitor) { - _glfwShowWindowNull(window); - _glfwFocusWindowNull(window); - acquireMonitorNull(window); - - if (wndconfig->centerCursor) - _glfwCenterCursorInContentArea(window); - } - else - { - if (wndconfig->visible) - { - _glfwShowWindowNull(window); - if (wndconfig->focused) - _glfwFocusWindowNull(window); - } + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + acquireMonitor(window); } return GLFW_TRUE; } -void _glfwDestroyWindowNull(_GLFWwindow* window) +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window->monitor) - releaseMonitorNull(window); + releaseMonitor(window); if (_glfw.null.focusedWindow == window) _glfw.null.focusedWindow = NULL; @@ -178,50 +150,51 @@ void _glfwDestroyWindowNull(_GLFWwindow* window) window->context.destroy(window); } -void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title) +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { } -void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images) +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, + const GLFWimage* images) { } -void _glfwSetWindowMonitorNull(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { if (window->monitor == monitor) { if (!monitor) { - _glfwSetWindowPosNull(window, xpos, ypos); - _glfwSetWindowSizeNull(window, width, height); + _glfwPlatformSetWindowPos(window, xpos, ypos); + _glfwPlatformSetWindowSize(window, width, height); } return; } if (window->monitor) - releaseMonitorNull(window); + releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); if (window->monitor) { window->null.visible = GLFW_TRUE; - acquireMonitorNull(window); + acquireMonitor(window); fitToMonitor(window); } else { - _glfwSetWindowPosNull(window, xpos, ypos); - _glfwSetWindowSizeNull(window, width, height); + _glfwPlatformSetWindowPos(window, xpos, ypos); + _glfwPlatformSetWindowSize(window, width, height); } } -void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { if (xpos) *xpos = window->null.xpos; @@ -229,7 +202,7 @@ void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos) *ypos = window->null.ypos; } -void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos) +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { if (window->monitor) return; @@ -242,7 +215,7 @@ void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos) } } -void _glfwGetWindowSizeNull(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->null.width; @@ -250,7 +223,7 @@ void _glfwGetWindowSizeNull(_GLFWwindow* window, int* width, int* height) *height = window->null.height; } -void _glfwSetWindowSizeNull(_GLFWwindow* window, int width, int height) +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) return; @@ -259,31 +232,30 @@ void _glfwSetWindowSizeNull(_GLFWwindow* window, int width, int height) { window->null.width = width; window->null.height = height; - _glfwInputFramebufferSize(window, width, height); - _glfwInputWindowDamage(window); _glfwInputWindowSize(window, width, height); + _glfwInputFramebufferSize(window, width, height); } } -void _glfwSetWindowSizeLimitsNull(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { int width = window->null.width; int height = window->null.height; applySizeLimits(window, &width, &height); - _glfwSetWindowSizeNull(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); } -void _glfwSetWindowAspectRatioNull(_GLFWwindow* window, int n, int d) +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) { int width = window->null.width; int height = window->null.height; applySizeLimits(window, &width, &height); - _glfwSetWindowSizeNull(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); } -void _glfwGetFramebufferSizeNull(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->null.width; @@ -291,9 +263,9 @@ void _glfwGetFramebufferSizeNull(_GLFWwindow* window, int* width, int* height) *height = window->null.height; } -void _glfwGetWindowFrameSizeNull(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { if (window->null.decorated && !window->monitor) { @@ -319,7 +291,8 @@ void _glfwGetWindowFrameSizeNull(_GLFWwindow* window, } } -void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* yscale) +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) { if (xscale) *xscale = 1.f; @@ -327,7 +300,7 @@ void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* y *yscale = 1.f; } -void _glfwIconifyWindowNull(_GLFWwindow* window) +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (_glfw.null.focusedWindow == window) { @@ -341,11 +314,11 @@ void _glfwIconifyWindowNull(_GLFWwindow* window) _glfwInputWindowIconify(window, GLFW_TRUE); if (window->monitor) - releaseMonitorNull(window); + releaseMonitor(window); } } -void _glfwRestoreWindowNull(_GLFWwindow* window) +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { if (window->null.iconified) { @@ -353,7 +326,7 @@ void _glfwRestoreWindowNull(_GLFWwindow* window) _glfwInputWindowIconify(window, GLFW_FALSE); if (window->monitor) - acquireMonitorNull(window); + acquireMonitor(window); } else if (window->null.maximized) { @@ -362,7 +335,7 @@ void _glfwRestoreWindowNull(_GLFWwindow* window) } } -void _glfwMaximizeWindowNull(_GLFWwindow* window) +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { if (!window->null.maximized) { @@ -371,12 +344,12 @@ void _glfwMaximizeWindowNull(_GLFWwindow* window) } } -GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window) +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { return window->null.maximized; } -GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window) +int _glfwPlatformWindowHovered(_GLFWwindow* window) { return _glfw.null.xcursor >= window->null.xpos && _glfw.null.ycursor >= window->null.ypos && @@ -384,59 +357,59 @@ GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window) _glfw.null.ycursor <= window->null.ypos + window->null.height - 1; } -GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window) +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return window->null.transparent; } -void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { window->null.resizable = enabled; } -void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { window->null.decorated = enabled; } -void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { window->null.floating = enabled; } -void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled) { } -float _glfwGetWindowOpacityNull(_GLFWwindow* window) +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { return window->null.opacity; } -void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity) +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { window->null.opacity = opacity; } -void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled) +void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { } -GLFWbool _glfwRawMouseMotionSupportedNull(void) +GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_TRUE; } -void _glfwShowWindowNull(_GLFWwindow* window) +void _glfwPlatformShowWindow(_GLFWwindow* window) { window->null.visible = GLFW_TRUE; } -void _glfwRequestWindowAttentionNull(_GLFWwindow* window) +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { } -void _glfwHideWindowNull(_GLFWwindow* window) +void _glfwPlatformHideWindow(_GLFWwindow* window) { if (_glfw.null.focusedWindow == window) { @@ -447,61 +420,59 @@ void _glfwHideWindowNull(_GLFWwindow* window) window->null.visible = GLFW_FALSE; } -void _glfwFocusWindowNull(_GLFWwindow* window) +void _glfwPlatformFocusWindow(_GLFWwindow* window) { - _GLFWwindow* previous; - if (_glfw.null.focusedWindow == window) return; if (!window->null.visible) return; - previous = _glfw.null.focusedWindow; + _GLFWwindow* previous = _glfw.null.focusedWindow; _glfw.null.focusedWindow = window; if (previous) { _glfwInputWindowFocus(previous, GLFW_FALSE); if (previous->monitor && previous->autoIconify) - _glfwIconifyWindowNull(previous); + _glfwPlatformIconifyWindow(previous); } _glfwInputWindowFocus(window, GLFW_TRUE); } -GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window) +int _glfwPlatformWindowFocused(_GLFWwindow* window) { return _glfw.null.focusedWindow == window; } -GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window) +int _glfwPlatformWindowIconified(_GLFWwindow* window) { return window->null.iconified; } -GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window) +int _glfwPlatformWindowVisible(_GLFWwindow* window) { return window->null.visible; } -void _glfwPollEventsNull(void) +void _glfwPlatformPollEvents(void) { } -void _glfwWaitEventsNull(void) +void _glfwPlatformWaitEvents(void) { } -void _glfwWaitEventsTimeoutNull(double timeout) +void _glfwPlatformWaitEventsTimeout(double timeout) { } -void _glfwPostEmptyEventNull(void) +void _glfwPlatformPostEmptyEvent(void) { } -void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { if (xpos) *xpos = _glfw.null.xcursor - window->null.xpos; @@ -509,210 +480,189 @@ void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos) *ypos = _glfw.null.ycursor - window->null.ypos; } -void _glfwSetCursorPosNull(_GLFWwindow* window, double x, double y) +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { _glfw.null.xcursor = window->null.xpos + (int) x; _glfw.null.ycursor = window->null.ypos + (int) y; } -void _glfwSetCursorModeNull(_GLFWwindow* window, int mode) +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { } -GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { return GLFW_TRUE; } -GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape) +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { return GLFW_TRUE; } -void _glfwDestroyCursorNull(_GLFWcursor* cursor) +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { } -void _glfwSetCursorNull(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { } -void _glfwSetClipboardStringNull(const char* string) +void _glfwPlatformSetClipboardString(const char* string) { char* copy = _glfw_strdup(string); - _glfw_free(_glfw.null.clipboardString); + free(_glfw.null.clipboardString); _glfw.null.clipboardString = copy; } -const char* _glfwGetClipboardStringNull(void) +const char* _glfwPlatformGetClipboardString(void) { return _glfw.null.clipboardString; } -EGLenum _glfwGetEGLPlatformNull(EGLint** attribs) +const char* _glfwPlatformGetScancodeName(int scancode) { - return 0; -} - -EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void) -{ - return 0; -} - -EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window) -{ - return 0; -} - -const char* _glfwGetScancodeNameNull(int scancode) -{ - if (scancode < GLFW_NULL_SC_FIRST || scancode > GLFW_NULL_SC_LAST) - { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); - return NULL; - } - switch (scancode) { - case GLFW_NULL_SC_APOSTROPHE: + case GLFW_KEY_APOSTROPHE: return "'"; - case GLFW_NULL_SC_COMMA: + case GLFW_KEY_COMMA: return ","; - case GLFW_NULL_SC_MINUS: - case GLFW_NULL_SC_KP_SUBTRACT: + case GLFW_KEY_MINUS: + case GLFW_KEY_KP_SUBTRACT: return "-"; - case GLFW_NULL_SC_PERIOD: - case GLFW_NULL_SC_KP_DECIMAL: + case GLFW_KEY_PERIOD: + case GLFW_KEY_KP_DECIMAL: return "."; - case GLFW_NULL_SC_SLASH: - case GLFW_NULL_SC_KP_DIVIDE: + case GLFW_KEY_SLASH: + case GLFW_KEY_KP_DIVIDE: return "/"; - case GLFW_NULL_SC_SEMICOLON: + case GLFW_KEY_SEMICOLON: return ";"; - case GLFW_NULL_SC_EQUAL: - case GLFW_NULL_SC_KP_EQUAL: + case GLFW_KEY_EQUAL: + case GLFW_KEY_KP_EQUAL: return "="; - case GLFW_NULL_SC_LEFT_BRACKET: + case GLFW_KEY_LEFT_BRACKET: return "["; - case GLFW_NULL_SC_RIGHT_BRACKET: + case GLFW_KEY_RIGHT_BRACKET: return "]"; - case GLFW_NULL_SC_KP_MULTIPLY: + case GLFW_KEY_KP_MULTIPLY: return "*"; - case GLFW_NULL_SC_KP_ADD: + case GLFW_KEY_KP_ADD: return "+"; - case GLFW_NULL_SC_BACKSLASH: - case GLFW_NULL_SC_WORLD_1: - case GLFW_NULL_SC_WORLD_2: + case GLFW_KEY_BACKSLASH: + case GLFW_KEY_WORLD_1: + case GLFW_KEY_WORLD_2: return "\\"; - case GLFW_NULL_SC_0: - case GLFW_NULL_SC_KP_0: + case GLFW_KEY_0: + case GLFW_KEY_KP_0: return "0"; - case GLFW_NULL_SC_1: - case GLFW_NULL_SC_KP_1: + case GLFW_KEY_1: + case GLFW_KEY_KP_1: return "1"; - case GLFW_NULL_SC_2: - case GLFW_NULL_SC_KP_2: + case GLFW_KEY_2: + case GLFW_KEY_KP_2: return "2"; - case GLFW_NULL_SC_3: - case GLFW_NULL_SC_KP_3: + case GLFW_KEY_3: + case GLFW_KEY_KP_3: return "3"; - case GLFW_NULL_SC_4: - case GLFW_NULL_SC_KP_4: + case GLFW_KEY_4: + case GLFW_KEY_KP_4: return "4"; - case GLFW_NULL_SC_5: - case GLFW_NULL_SC_KP_5: + case GLFW_KEY_5: + case GLFW_KEY_KP_5: return "5"; - case GLFW_NULL_SC_6: - case GLFW_NULL_SC_KP_6: + case GLFW_KEY_6: + case GLFW_KEY_KP_6: return "6"; - case GLFW_NULL_SC_7: - case GLFW_NULL_SC_KP_7: + case GLFW_KEY_7: + case GLFW_KEY_KP_7: return "7"; - case GLFW_NULL_SC_8: - case GLFW_NULL_SC_KP_8: + case GLFW_KEY_8: + case GLFW_KEY_KP_8: return "8"; - case GLFW_NULL_SC_9: - case GLFW_NULL_SC_KP_9: + case GLFW_KEY_9: + case GLFW_KEY_KP_9: return "9"; - case GLFW_NULL_SC_A: + case GLFW_KEY_A: return "a"; - case GLFW_NULL_SC_B: + case GLFW_KEY_B: return "b"; - case GLFW_NULL_SC_C: + case GLFW_KEY_C: return "c"; - case GLFW_NULL_SC_D: + case GLFW_KEY_D: return "d"; - case GLFW_NULL_SC_E: + case GLFW_KEY_E: return "e"; - case GLFW_NULL_SC_F: + case GLFW_KEY_F: return "f"; - case GLFW_NULL_SC_G: + case GLFW_KEY_G: return "g"; - case GLFW_NULL_SC_H: + case GLFW_KEY_H: return "h"; - case GLFW_NULL_SC_I: + case GLFW_KEY_I: return "i"; - case GLFW_NULL_SC_J: + case GLFW_KEY_J: return "j"; - case GLFW_NULL_SC_K: + case GLFW_KEY_K: return "k"; - case GLFW_NULL_SC_L: + case GLFW_KEY_L: return "l"; - case GLFW_NULL_SC_M: + case GLFW_KEY_M: return "m"; - case GLFW_NULL_SC_N: + case GLFW_KEY_N: return "n"; - case GLFW_NULL_SC_O: + case GLFW_KEY_O: return "o"; - case GLFW_NULL_SC_P: + case GLFW_KEY_P: return "p"; - case GLFW_NULL_SC_Q: + case GLFW_KEY_Q: return "q"; - case GLFW_NULL_SC_R: + case GLFW_KEY_R: return "r"; - case GLFW_NULL_SC_S: + case GLFW_KEY_S: return "s"; - case GLFW_NULL_SC_T: + case GLFW_KEY_T: return "t"; - case GLFW_NULL_SC_U: + case GLFW_KEY_U: return "u"; - case GLFW_NULL_SC_V: + case GLFW_KEY_V: return "v"; - case GLFW_NULL_SC_W: + case GLFW_KEY_W: return "w"; - case GLFW_NULL_SC_X: + case GLFW_KEY_X: return "x"; - case GLFW_NULL_SC_Y: + case GLFW_KEY_Y: return "y"; - case GLFW_NULL_SC_Z: + case GLFW_KEY_Z: return "z"; } return NULL; } -int _glfwGetKeyScancodeNull(int key) +int _glfwPlatformGetKeyScancode(int key) { - return _glfw.null.scancodes[key]; + return key; } -void _glfwGetRequiredInstanceExtensionsNull(char** extensions) +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { } -GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { return GLFW_FALSE; } -VkResult _glfwCreateWindowSurfaceNull(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { // This seems like the most appropriate error to return here return VK_ERROR_EXTENSION_NOT_PRESENT; diff --git a/raylib/external/glfw/src/osmesa_context.c b/raylib/external/glfw/src/osmesa_context.c index 2f12adf..70e8675 100644 --- a/raylib/external/glfw/src/osmesa_context.c +++ b/raylib/external/glfw/src/osmesa_context.c @@ -24,29 +24,32 @@ // distribution. // //======================================================================== - -#include "internal.h" +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include #include #include +#include "internal.h" + + static void makeContextCurrentOSMesa(_GLFWwindow* window) { if (window) { int width, height; - _glfw.platform.getFramebufferSize(window, &width, &height); + _glfwPlatformGetFramebufferSize(window, &width, &height); // Check to see if we need to allocate a new buffer if ((window->context.osmesa.buffer == NULL) || (width != window->context.osmesa.width) || (height != window->context.osmesa.height)) { - _glfw_free(window->context.osmesa.buffer); + free(window->context.osmesa.buffer); // Allocate the new buffer (width * height * 8-bit RGBA) - window->context.osmesa.buffer = _glfw_calloc(4, (size_t) width * height); + window->context.osmesa.buffer = calloc(4, (size_t) width * height); window->context.osmesa.width = width; window->context.osmesa.height = height; } @@ -80,7 +83,7 @@ static void destroyContextOSMesa(_GLFWwindow* window) if (window->context.osmesa.buffer) { - _glfw_free(window->context.osmesa.buffer); + free(window->context.osmesa.buffer); window->context.osmesa.width = 0; window->context.osmesa.height = 0; } @@ -121,8 +124,6 @@ GLFWbool _glfwInitOSMesa(void) "libOSMesa.8.dylib", #elif defined(__CYGWIN__) "libOSMesa-8.so", -#elif defined(__OpenBSD__) || defined(__NetBSD__) - "libOSMesa.so", #else "libOSMesa.so.8", "libOSMesa.so.6", @@ -135,7 +136,7 @@ GLFWbool _glfwInitOSMesa(void) for (i = 0; sonames[i]; i++) { - _glfw.osmesa.handle = _glfwPlatformLoadModule(sonames[i]); + _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); if (_glfw.osmesa.handle) break; } @@ -147,19 +148,19 @@ GLFWbool _glfwInitOSMesa(void) } _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextExt"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt"); _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaDestroyContext"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaMakeCurrent"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress) - _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetProcAddress"); + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); if (!_glfw.osmesa.CreateContextExt || !_glfw.osmesa.DestroyContext || @@ -182,12 +183,12 @@ void _glfwTerminateOSMesa(void) { if (_glfw.osmesa.handle) { - _glfwPlatformFreeModule(_glfw.osmesa.handle); + _glfw_dlclose(_glfw.osmesa.handle); _glfw.osmesa.handle = NULL; } } -#define SET_ATTRIB(a, v) \ +#define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -218,24 +219,24 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, { int index = 0, attribs[40]; - SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA); - SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits); - SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits); - SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits); + setAttrib(OSMESA_FORMAT, OSMESA_RGBA); + setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits); + setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits); + setAttrib(OSMESA_ACCUM_BITS, accumBits); if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) { - SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE); + setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); } else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) { - SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); + setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); - SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); + setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); + setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); } if (ctxconfig->forward) @@ -245,7 +246,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, return GLFW_FALSE; } - SET_ATTRIB(0, 0); + setAttrib(0, 0); window->context.osmesa.handle = OSMesaCreateContextAttribs(attribs, share); @@ -284,7 +285,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, return GLFW_TRUE; } -#undef SET_ATTRIB +#undef setAttrib ////////////////////////////////////////////////////////////////////////// @@ -301,12 +302,6 @@ GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width, _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - if (window->context.source != GLFW_OSMESA_CONTEXT_API) - { - _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); - return GLFW_FALSE; - } - if (!OSMesaGetColorBuffer(window->context.osmesa.handle, &mesaWidth, &mesaHeight, &mesaFormat, &mesaBuffer)) @@ -340,12 +335,6 @@ GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle, _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - if (window->context.source != GLFW_OSMESA_CONTEXT_API) - { - _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); - return GLFW_FALSE; - } - if (!OSMesaGetDepthBuffer(window->context.osmesa.handle, &mesaWidth, &mesaHeight, &mesaBytes, &mesaBuffer)) @@ -372,7 +361,7 @@ GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.source != GLFW_OSMESA_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; diff --git a/raylib/external/glfw/src/osmesa_context.h b/raylib/external/glfw/src/osmesa_context.h new file mode 100644 index 0000000..ce1f1a2 --- /dev/null +++ b/raylib/external/glfw/src/osmesa_context.h @@ -0,0 +1,90 @@ +//======================================================================== +// GLFW 3.4 OSMesa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2016-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define OSMESA_RGBA 0x1908 +#define OSMESA_FORMAT 0x22 +#define OSMESA_DEPTH_BITS 0x30 +#define OSMESA_STENCIL_BITS 0x31 +#define OSMESA_ACCUM_BITS 0x32 +#define OSMESA_PROFILE 0x33 +#define OSMESA_CORE_PROFILE 0x34 +#define OSMESA_COMPAT_PROFILE 0x35 +#define OSMESA_CONTEXT_MAJOR_VERSION 0x36 +#define OSMESA_CONTEXT_MINOR_VERSION 0x37 + +typedef void* OSMesaContext; +typedef void (*OSMESAproc)(void); + +typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); +typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); +typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); +typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); +typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); +typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); +typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); +#define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt +#define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs +#define OSMesaDestroyContext _glfw.osmesa.DestroyContext +#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent +#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer +#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer +#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress + +// OSMesa-specific per-context data +// +typedef struct _GLFWcontextOSMesa +{ + OSMesaContext handle; + int width; + int height; + void* buffer; + +} _GLFWcontextOSMesa; + +// OSMesa-specific global data +// +typedef struct _GLFWlibraryOSMesa +{ + void* handle; + + PFN_OSMesaCreateContextExt CreateContextExt; + PFN_OSMesaCreateContextAttribs CreateContextAttribs; + PFN_OSMesaDestroyContext DestroyContext; + PFN_OSMesaMakeCurrent MakeCurrent; + PFN_OSMesaGetColorBuffer GetColorBuffer; + PFN_OSMesaGetDepthBuffer GetDepthBuffer; + PFN_OSMesaGetProcAddress GetProcAddress; + +} _GLFWlibraryOSMesa; + + +GLFWbool _glfwInitOSMesa(void); +void _glfwTerminateOSMesa(void); +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + diff --git a/raylib/external/glfw/src/platform.c b/raylib/external/glfw/src/platform.c deleted file mode 100644 index c4b0a36..0000000 --- a/raylib/external/glfw/src/platform.c +++ /dev/null @@ -1,204 +0,0 @@ -//======================================================================== -// GLFW 3.4 (modified for raylib) - www.glfw.org; www.raylib.com -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2018 Camilla Löwy -// Copyright (c) 2024 M374LX -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#include "internal.h" - -#include -#include - -// These construct a string literal from individual numeric constants -#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r -#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r) - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -static const struct -{ - int ID; - GLFWbool (*connect)(int,_GLFWplatform*); -} supportedPlatforms[] = -{ -#if defined(_GLFW_WIN32) - { GLFW_PLATFORM_WIN32, _glfwConnectWin32 }, -#endif -#if defined(_GLFW_COCOA) - { GLFW_PLATFORM_COCOA, _glfwConnectCocoa }, -#endif -#if defined(_GLFW_WAYLAND) - { GLFW_PLATFORM_WAYLAND, _glfwConnectWayland }, -#endif -#if defined(_GLFW_X11) - { GLFW_PLATFORM_X11, _glfwConnectX11 }, -#endif -}; - -GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform) -{ - const size_t count = sizeof(supportedPlatforms) / sizeof(supportedPlatforms[0]); - size_t i; - - if (desiredID != GLFW_ANY_PLATFORM && - desiredID != GLFW_PLATFORM_WIN32 && - desiredID != GLFW_PLATFORM_COCOA && - desiredID != GLFW_PLATFORM_WAYLAND && - desiredID != GLFW_PLATFORM_X11 && - desiredID != GLFW_PLATFORM_NULL) - { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", desiredID); - return GLFW_FALSE; - } - -#if defined(_GLFW_WAYLAND) && defined(_GLFW_X11) - if (desiredID == GLFW_ANY_PLATFORM) - { - const char* const session = getenv("XDG_SESSION_TYPE"); - if (session) - { - // Only follow XDG_SESSION_TYPE if it is set correctly and the - // environment looks plausble; otherwise fall back to detection - if (strcmp(session, "wayland") == 0 && getenv("WAYLAND_DISPLAY")) - desiredID = GLFW_PLATFORM_WAYLAND; - else if (strcmp(session, "x11") == 0 && getenv("DISPLAY")) - desiredID = GLFW_PLATFORM_X11; - } - } -#endif - - if (desiredID == GLFW_ANY_PLATFORM) - { - // If there is exactly one platform available for auto-selection, let it emit the - // error on failure as the platform-specific error description may be more helpful - if (count == 1) - return supportedPlatforms[0].connect(supportedPlatforms[0].ID, platform); - - for (i = 0; i < count; i++) - { - if (supportedPlatforms[i].connect(desiredID, platform)) - return GLFW_TRUE; - } - - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Failed to detect any supported platform"); - } - else - { - for (i = 0; i < count; i++) - { - if (supportedPlatforms[i].ID == desiredID) - return supportedPlatforms[i].connect(desiredID, platform); - } - - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "The requested platform is not supported"); - } - - return GLFW_FALSE; -} - -////////////////////////////////////////////////////////////////////////// -////// GLFW public API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI int glfwGetPlatform(void) -{ - _GLFW_REQUIRE_INIT_OR_RETURN(0); - return _glfw.platform.platformID; -} - -GLFWAPI int glfwPlatformSupported(int platformID) -{ - const size_t count = sizeof(supportedPlatforms) / sizeof(supportedPlatforms[0]); - size_t i; - - if (platformID != GLFW_PLATFORM_WIN32 && - platformID != GLFW_PLATFORM_COCOA && - platformID != GLFW_PLATFORM_WAYLAND && - platformID != GLFW_PLATFORM_X11 && - platformID != GLFW_PLATFORM_NULL) - { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", platformID); - return GLFW_FALSE; - } - - if (platformID == GLFW_PLATFORM_NULL) - return GLFW_TRUE; - - for (i = 0; i < count; i++) - { - if (platformID == supportedPlatforms[i].ID) - return GLFW_TRUE; - } - - return GLFW_FALSE; -} - -GLFWAPI const char* glfwGetVersionString(void) -{ - return _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, - GLFW_VERSION_MINOR, - GLFW_VERSION_REVISION) -#if defined(_GLFW_WIN32) - " Win32 WGL" -#endif -#if defined(_GLFW_COCOA) - " Cocoa NSGL" -#endif -#if defined(_GLFW_WAYLAND) - " Wayland" -#endif -#if defined(_GLFW_X11) - " X11 GLX" -#endif - " Null" - " EGL" - " OSMesa" -#if defined(__MINGW64_VERSION_MAJOR) - " MinGW-w64" -#elif defined(__MINGW32__) - " MinGW" -#elif defined(_MSC_VER) - " VisualC" -#endif -#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) - " hybrid-GPU" -#endif -#if defined(_POSIX_MONOTONIC_CLOCK) - " monotonic" -#endif -#if defined(_GLFW_BUILD_DLL) -#if defined(_WIN32) - " DLL" -#elif defined(__APPLE__) - " dynamic" -#else - " shared" -#endif -#endif - ; -} - diff --git a/raylib/external/glfw/src/platform.h b/raylib/external/glfw/src/platform.h deleted file mode 100644 index 75652dc..0000000 --- a/raylib/external/glfw/src/platform.h +++ /dev/null @@ -1,212 +0,0 @@ -//======================================================================== -// GLFW 3.4 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2018 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#if defined(GLFW_BUILD_WIN32_TIMER) || \ - defined(GLFW_BUILD_WIN32_MODULE) || \ - defined(GLFW_BUILD_WIN32_THREAD) || \ - defined(GLFW_BUILD_COCOA_TIMER) || \ - defined(GLFW_BUILD_POSIX_TIMER) || \ - defined(GLFW_BUILD_POSIX_MODULE) || \ - defined(GLFW_BUILD_POSIX_THREAD) || \ - defined(GLFW_BUILD_POSIX_POLL) || \ - defined(GLFW_BUILD_LINUX_JOYSTICK) - #error "You must not define these; define zero or more _GLFW_ macros instead" -#endif - -#include "null_platform.h" -#define GLFW_EXPOSE_NATIVE_EGL -#define GLFW_EXPOSE_NATIVE_OSMESA - -#if defined(_GLFW_WIN32) - #include "win32_platform.h" - #define GLFW_EXPOSE_NATIVE_WIN32 - #define GLFW_EXPOSE_NATIVE_WGL -#else - #define GLFW_WIN32_WINDOW_STATE - #define GLFW_WIN32_MONITOR_STATE - #define GLFW_WIN32_CURSOR_STATE - #define GLFW_WIN32_LIBRARY_WINDOW_STATE - #define GLFW_WGL_CONTEXT_STATE - #define GLFW_WGL_LIBRARY_CONTEXT_STATE -#endif - -#if defined(_GLFW_COCOA) - #include "cocoa_platform.h" - #define GLFW_EXPOSE_NATIVE_COCOA - #define GLFW_EXPOSE_NATIVE_NSGL -#else - #define GLFW_COCOA_WINDOW_STATE - #define GLFW_COCOA_MONITOR_STATE - #define GLFW_COCOA_CURSOR_STATE - #define GLFW_COCOA_LIBRARY_WINDOW_STATE - #define GLFW_NSGL_CONTEXT_STATE - #define GLFW_NSGL_LIBRARY_CONTEXT_STATE -#endif - -#if defined(_GLFW_WAYLAND) - #include "wl_platform.h" - #define GLFW_EXPOSE_NATIVE_WAYLAND -#else - #define GLFW_WAYLAND_WINDOW_STATE - #define GLFW_WAYLAND_MONITOR_STATE - #define GLFW_WAYLAND_CURSOR_STATE - #define GLFW_WAYLAND_LIBRARY_WINDOW_STATE -#endif - -#if defined(_GLFW_X11) - #include "x11_platform.h" - #define GLFW_EXPOSE_NATIVE_X11 - #define GLFW_EXPOSE_NATIVE_GLX -#else - #define GLFW_X11_WINDOW_STATE - #define GLFW_X11_MONITOR_STATE - #define GLFW_X11_CURSOR_STATE - #define GLFW_X11_LIBRARY_WINDOW_STATE - #define GLFW_GLX_CONTEXT_STATE - #define GLFW_GLX_LIBRARY_CONTEXT_STATE -#endif - -#include "null_joystick.h" - -#if defined(_GLFW_WIN32) - #include "win32_joystick.h" -#else - #define GLFW_WIN32_JOYSTICK_STATE - #define GLFW_WIN32_LIBRARY_JOYSTICK_STATE -#endif - -#if defined(_GLFW_COCOA) - #include "cocoa_joystick.h" -#else - #define GLFW_COCOA_JOYSTICK_STATE - #define GLFW_COCOA_LIBRARY_JOYSTICK_STATE -#endif - -#if (defined(_GLFW_X11) || defined(_GLFW_WAYLAND)) && defined(__linux__) - #define GLFW_BUILD_LINUX_JOYSTICK -#endif - -#if defined(GLFW_BUILD_LINUX_JOYSTICK) - #include "linux_joystick.h" -#else - #define GLFW_LINUX_JOYSTICK_STATE - #define GLFW_LINUX_LIBRARY_JOYSTICK_STATE -#endif - -#define GLFW_PLATFORM_WINDOW_STATE \ - GLFW_WIN32_WINDOW_STATE \ - GLFW_COCOA_WINDOW_STATE \ - GLFW_WAYLAND_WINDOW_STATE \ - GLFW_X11_WINDOW_STATE \ - GLFW_NULL_WINDOW_STATE \ - -#define GLFW_PLATFORM_MONITOR_STATE \ - GLFW_WIN32_MONITOR_STATE \ - GLFW_COCOA_MONITOR_STATE \ - GLFW_WAYLAND_MONITOR_STATE \ - GLFW_X11_MONITOR_STATE \ - GLFW_NULL_MONITOR_STATE \ - -#define GLFW_PLATFORM_CURSOR_STATE \ - GLFW_WIN32_CURSOR_STATE \ - GLFW_COCOA_CURSOR_STATE \ - GLFW_WAYLAND_CURSOR_STATE \ - GLFW_X11_CURSOR_STATE \ - GLFW_NULL_CURSOR_STATE \ - -#define GLFW_PLATFORM_JOYSTICK_STATE \ - GLFW_WIN32_JOYSTICK_STATE \ - GLFW_COCOA_JOYSTICK_STATE \ - GLFW_LINUX_JOYSTICK_STATE - -#define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \ - GLFW_WIN32_LIBRARY_WINDOW_STATE \ - GLFW_COCOA_LIBRARY_WINDOW_STATE \ - GLFW_WAYLAND_LIBRARY_WINDOW_STATE \ - GLFW_X11_LIBRARY_WINDOW_STATE \ - GLFW_NULL_LIBRARY_WINDOW_STATE \ - -#define GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ - GLFW_WIN32_LIBRARY_JOYSTICK_STATE \ - GLFW_COCOA_LIBRARY_JOYSTICK_STATE \ - GLFW_LINUX_LIBRARY_JOYSTICK_STATE - -#define GLFW_PLATFORM_CONTEXT_STATE \ - GLFW_WGL_CONTEXT_STATE \ - GLFW_NSGL_CONTEXT_STATE \ - GLFW_GLX_CONTEXT_STATE - -#define GLFW_PLATFORM_LIBRARY_CONTEXT_STATE \ - GLFW_WGL_LIBRARY_CONTEXT_STATE \ - GLFW_NSGL_LIBRARY_CONTEXT_STATE \ - GLFW_GLX_LIBRARY_CONTEXT_STATE - -#if defined(_WIN32) - #define GLFW_BUILD_WIN32_THREAD -#else - #define GLFW_BUILD_POSIX_THREAD -#endif - -#if defined(GLFW_BUILD_WIN32_THREAD) - #include "win32_thread.h" - #define GLFW_PLATFORM_TLS_STATE GLFW_WIN32_TLS_STATE - #define GLFW_PLATFORM_MUTEX_STATE GLFW_WIN32_MUTEX_STATE -#elif defined(GLFW_BUILD_POSIX_THREAD) - #include "posix_thread.h" - #define GLFW_PLATFORM_TLS_STATE GLFW_POSIX_TLS_STATE - #define GLFW_PLATFORM_MUTEX_STATE GLFW_POSIX_MUTEX_STATE -#endif - -#if defined(_WIN32) - #define GLFW_BUILD_WIN32_TIMER -#elif defined(__APPLE__) - #define GLFW_BUILD_COCOA_TIMER -#else - #define GLFW_BUILD_POSIX_TIMER -#endif - -#if defined(GLFW_BUILD_WIN32_TIMER) - #include "win32_time.h" - #define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_WIN32_LIBRARY_TIMER_STATE -#elif defined(GLFW_BUILD_COCOA_TIMER) - #include "cocoa_time.h" - #define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_COCOA_LIBRARY_TIMER_STATE -#elif defined(GLFW_BUILD_POSIX_TIMER) - #include "posix_time.h" - #define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_POSIX_LIBRARY_TIMER_STATE -#endif - -#if defined(_WIN32) - #define GLFW_BUILD_WIN32_MODULE -#else - #define GLFW_BUILD_POSIX_MODULE -#endif - -#if defined(_GLFW_WAYLAND) || defined(_GLFW_X11) - #define GLFW_BUILD_POSIX_POLL -#endif - diff --git a/raylib/external/glfw/src/posix_module.c b/raylib/external/glfw/src/posix_module.c deleted file mode 100644 index 7d81c67..0000000 --- a/raylib/external/glfw/src/posix_module.c +++ /dev/null @@ -1,53 +0,0 @@ -//======================================================================== -// GLFW 3.4 POSIX - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2021 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#include "internal.h" - -#if defined(GLFW_BUILD_POSIX_MODULE) - -#include - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void* _glfwPlatformLoadModule(const char* path) -{ - return dlopen(path, RTLD_LAZY | RTLD_LOCAL); -} - -void _glfwPlatformFreeModule(void* module) -{ - dlclose(module); -} - -GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name) -{ - return dlsym(module, name); -} - -#endif // GLFW_BUILD_POSIX_MODULE - diff --git a/raylib/external/glfw/src/posix_poll.c b/raylib/external/glfw/src/posix_poll.c deleted file mode 100644 index b53e36e..0000000 --- a/raylib/external/glfw/src/posix_poll.c +++ /dev/null @@ -1,83 +0,0 @@ -//======================================================================== -// GLFW 3.4 POSIX - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2022 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#define _GNU_SOURCE - -#include "internal.h" - -#if defined(GLFW_BUILD_POSIX_POLL) - -#include -#include -#include - -GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout) -{ - for (;;) - { - if (timeout) - { - const uint64_t base = _glfwPlatformGetTimerValue(); - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) - const time_t seconds = (time_t) *timeout; - const long nanoseconds = (long) ((*timeout - seconds) * 1e9); - const struct timespec ts = { seconds, nanoseconds }; - const int result = ppoll(fds, count, &ts, NULL); -#elif defined(__NetBSD__) - const time_t seconds = (time_t) *timeout; - const long nanoseconds = (long) ((*timeout - seconds) * 1e9); - const struct timespec ts = { seconds, nanoseconds }; - const int result = pollts(fds, count, &ts, NULL); -#else - const int milliseconds = (int) (*timeout * 1e3); - const int result = poll(fds, count, milliseconds); -#endif - const int error = errno; // clock_gettime may overwrite our error - - *timeout -= (_glfwPlatformGetTimerValue() - base) / - (double) _glfwPlatformGetTimerFrequency(); - - if (result > 0) - return GLFW_TRUE; - else if (result == -1 && error != EINTR && error != EAGAIN) - return GLFW_FALSE; - else if (*timeout <= 0.0) - return GLFW_FALSE; - } - else - { - const int result = poll(fds, count, -1); - if (result > 0) - return GLFW_TRUE; - else if (result == -1 && errno != EINTR && errno != EAGAIN) - return GLFW_FALSE; - } - } -} - -#endif // GLFW_BUILD_POSIX_POLL - diff --git a/raylib/external/glfw/src/posix_poll.h b/raylib/external/glfw/src/posix_poll.h deleted file mode 100644 index 4bdd244..0000000 --- a/raylib/external/glfw/src/posix_poll.h +++ /dev/null @@ -1,30 +0,0 @@ -//======================================================================== -// GLFW 3.4 POSIX - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2022 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#include - -GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout); - diff --git a/raylib/external/glfw/src/posix_thread.c b/raylib/external/glfw/src/posix_thread.c index 3c355a5..0236145 100644 --- a/raylib/external/glfw/src/posix_thread.c +++ b/raylib/external/glfw/src/posix_thread.c @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(GLFW_BUILD_POSIX_THREAD) - #include #include @@ -103,5 +103,3 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) pthread_mutex_unlock(&mutex->posix.handle); } -#endif // GLFW_BUILD_POSIX_THREAD - diff --git a/raylib/external/glfw/src/posix_thread.h b/raylib/external/glfw/src/posix_thread.h index 5a5d7b7..85ce596 100644 --- a/raylib/external/glfw/src/posix_thread.h +++ b/raylib/external/glfw/src/posix_thread.h @@ -27,8 +27,8 @@ #include -#define GLFW_POSIX_TLS_STATE _GLFWtlsPOSIX posix; -#define GLFW_POSIX_MUTEX_STATE _GLFWmutexPOSIX posix; +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data @@ -37,6 +37,7 @@ typedef struct _GLFWtlsPOSIX { GLFWbool allocated; pthread_key_t key; + } _GLFWtlsPOSIX; // POSIX-specific mutex data @@ -45,5 +46,6 @@ typedef struct _GLFWmutexPOSIX { GLFWbool allocated; pthread_mutex_t handle; + } _GLFWmutexPOSIX; diff --git a/raylib/external/glfw/src/posix_time.c b/raylib/external/glfw/src/posix_time.c index a172408..2fedfa8 100644 --- a/raylib/external/glfw/src/posix_time.c +++ b/raylib/external/glfw/src/posix_time.c @@ -24,36 +24,63 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +//#define _POSIX_C_SOURCE 199309L #include "internal.h" -#if defined(GLFW_BUILD_POSIX_TIMER) - #include #include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerPOSIX(void) +{ +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + _glfw.timer.posix.monotonic = GLFW_TRUE; + _glfw.timer.posix.frequency = 1000000000; + } + else +#endif + { + _glfw.timer.posix.monotonic = GLFW_FALSE; + _glfw.timer.posix.frequency = 1000000; + } +} ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformInitTimer(void) -{ - _glfw.timer.posix.clock = CLOCK_REALTIME; - _glfw.timer.posix.frequency = 1000000000; - -#if defined(_POSIX_MONOTONIC_CLOCK) - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - _glfw.timer.posix.clock = CLOCK_MONOTONIC; -#endif -} - uint64_t _glfwPlatformGetTimerValue(void) { - struct timespec ts; - clock_gettime(_glfw.timer.posix.clock, &ts); - return (uint64_t) ts.tv_sec * _glfw.timer.posix.frequency + (uint64_t) ts.tv_nsec; +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + if (_glfw.timer.posix.monotonic) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; + } + else +#endif + { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; + } } uint64_t _glfwPlatformGetTimerFrequency(void) @@ -61,5 +88,3 @@ uint64_t _glfwPlatformGetTimerFrequency(void) return _glfw.timer.posix.frequency; } -#endif // GLFW_BUILD_POSIX_TIMER - diff --git a/raylib/external/glfw/src/posix_time.h b/raylib/external/glfw/src/posix_time.h index 94374ad..9b59a18 100644 --- a/raylib/external/glfw/src/posix_time.h +++ b/raylib/external/glfw/src/posix_time.h @@ -25,17 +25,20 @@ // //======================================================================== -#define GLFW_POSIX_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix; +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix #include -#include // POSIX-specific global timer data // typedef struct _GLFWtimerPOSIX { - clockid_t clock; + GLFWbool monotonic; uint64_t frequency; + } _GLFWtimerPOSIX; + +void _glfwInitTimerPOSIX(void); + diff --git a/raylib/external/glfw/src/vendor.go b/raylib/external/glfw/src/vendor.go deleted file mode 100644 index 0fb2a0f..0000000 --- a/raylib/external/glfw/src/vendor.go +++ /dev/null @@ -1,4 +0,0 @@ -//go:build required -// +build required - -package vendor diff --git a/raylib/external/glfw/src/vulkan.c b/raylib/external/glfw/src/vulkan.c index d9fabde..b534052 100644 --- a/raylib/external/glfw/src/vulkan.c +++ b/raylib/external/glfw/src/vulkan.c @@ -24,6 +24,8 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" @@ -43,52 +45,45 @@ GLFWbool _glfwInitVulkan(int mode) { VkResult err; VkExtensionProperties* ep; - PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; uint32_t i, count; if (_glfw.vk.available) return GLFW_TRUE; - if (_glfw.hints.init.vulkanLoader) - _glfw.vk.GetInstanceProcAddr = _glfw.hints.init.vulkanLoader; - else - { +#if !defined(_GLFW_VULKAN_STATIC) #if defined(_GLFW_VULKAN_LIBRARY) - _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY); + _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY); #elif defined(_GLFW_WIN32) - _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll"); + _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); #elif defined(_GLFW_COCOA) - _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib"); - if (!_glfw.vk.handle) - _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa(); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so"); + _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); + if (!_glfw.vk.handle) + _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS(); #else - _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1"); + _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); #endif - if (!_glfw.vk.handle) - { - if (mode == _GLFW_REQUIRE_LOADER) - _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); + if (!_glfw.vk.handle) + { + if (mode == _GLFW_REQUIRE_LOADER) + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); - return GLFW_FALSE; - } - - _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) - _glfwPlatformGetModuleSymbol(_glfw.vk.handle, "vkGetInstanceProcAddr"); - if (!_glfw.vk.GetInstanceProcAddr) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "Vulkan: Loader does not export vkGetInstanceProcAddr"); - - _glfwTerminateVulkan(); - return GLFW_FALSE; - } + return GLFW_FALSE; } - vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) + _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) + _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); + if (!_glfw.vk.GetInstanceProcAddr) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Loader does not export vkGetInstanceProcAddr"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); - if (!vkEnumerateInstanceExtensionProperties) + if (!_glfw.vk.EnumerateInstanceExtensionProperties) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); @@ -96,6 +91,7 @@ GLFWbool _glfwInitVulkan(int mode) _glfwTerminateVulkan(); return GLFW_FALSE; } +#endif // _GLFW_VULKAN_STATIC err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); if (err) @@ -112,7 +108,7 @@ GLFWbool _glfwInitVulkan(int mode) return GLFW_FALSE; } - ep = _glfw_calloc(count, sizeof(VkExtensionProperties)); + ep = calloc(count, sizeof(VkExtensionProperties)); err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); if (err) @@ -121,7 +117,7 @@ GLFWbool _glfwInitVulkan(int mode) "Vulkan: Failed to query instance extensions: %s", _glfwGetVulkanResultString(err)); - _glfw_free(ep); + free(ep); _glfwTerminateVulkan(); return GLFW_FALSE; } @@ -130,33 +126,40 @@ GLFWbool _glfwInitVulkan(int mode) { if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0) _glfw.vk.KHR_surface = GLFW_TRUE; +#if defined(_GLFW_WIN32) else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0) _glfw.vk.KHR_win32_surface = GLFW_TRUE; +#elif defined(_GLFW_COCOA) else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) _glfw.vk.MVK_macos_surface = GLFW_TRUE; else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0) _glfw.vk.EXT_metal_surface = GLFW_TRUE; +#elif defined(_GLFW_X11) else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) _glfw.vk.KHR_xlib_surface = GLFW_TRUE; else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0) _glfw.vk.KHR_xcb_surface = GLFW_TRUE; +#elif defined(_GLFW_WAYLAND) else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) _glfw.vk.KHR_wayland_surface = GLFW_TRUE; +#endif } - _glfw_free(ep); + free(ep); _glfw.vk.available = GLFW_TRUE; - _glfw.platform.getRequiredInstanceExtensions(_glfw.vk.extensions); + _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions); return GLFW_TRUE; } void _glfwTerminateVulkan(void) { +#if !defined(_GLFW_VULKAN_STATIC) if (_glfw.vk.handle) - _glfwPlatformFreeModule(_glfw.vk.handle); + _glfw_dlclose(_glfw.vk.handle); +#endif } const char* _glfwGetVulkanResultString(VkResult result) @@ -254,16 +257,17 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) return NULL; - // NOTE: Vulkan 1.0 and 1.1 vkGetInstanceProcAddr cannot return itself - if (strcmp(procname, "vkGetInstanceProcAddr") == 0) - return (GLFWvkproc) vkGetInstanceProcAddr; - proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); +#if defined(_GLFW_VULKAN_STATIC) if (!proc) { - if (_glfw.vk.handle) - proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname); + if (strcmp(procname, "vkGetInstanceProcAddr") == 0) + return (GLFWvkproc) vkGetInstanceProcAddr; } +#else + if (!proc) + proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); +#endif return proc; } @@ -287,9 +291,9 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, return GLFW_FALSE; } - return _glfw.platform.getPhysicalDevicePresentationSupport(instance, - device, - queuefamily); + return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, + device, + queuefamily); } GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, @@ -323,6 +327,6 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; } - return _glfw.platform.createWindowSurface(instance, window, allocator, surface); + return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); } diff --git a/raylib/external/glfw/src/wayland-client-protocol-code.h b/raylib/external/glfw/src/wayland-client-protocol-code.h deleted file mode 100644 index d640bb4..0000000 --- a/raylib/external/glfw/src/wayland-client-protocol-code.h +++ /dev/null @@ -1,538 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * Copyright © 2008-2011 Kristian Høgsberg - * Copyright © 2010-2011 Intel Corporation - * Copyright © 2012-2013 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include "wayland-util.h" - -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - -extern const struct wl_interface wl_buffer_interface; -extern const struct wl_interface wl_callback_interface; -extern const struct wl_interface wl_data_device_interface; -extern const struct wl_interface wl_data_offer_interface; -extern const struct wl_interface wl_data_source_interface; -extern const struct wl_interface wl_keyboard_interface; -extern const struct wl_interface wl_output_interface; -extern const struct wl_interface wl_pointer_interface; -extern const struct wl_interface wl_region_interface; -extern const struct wl_interface wl_registry_interface; -extern const struct wl_interface wl_seat_interface; -extern const struct wl_interface wl_shell_surface_interface; -extern const struct wl_interface wl_shm_pool_interface; -extern const struct wl_interface wl_subsurface_interface; -extern const struct wl_interface wl_surface_interface; -extern const struct wl_interface wl_touch_interface; - -static const struct wl_interface *wayland_types[] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - &wl_callback_interface, - &wl_registry_interface, - &wl_surface_interface, - &wl_region_interface, - &wl_buffer_interface, - NULL, - NULL, - NULL, - NULL, - NULL, - &wl_shm_pool_interface, - NULL, - NULL, - &wl_data_source_interface, - &wl_surface_interface, - &wl_surface_interface, - NULL, - &wl_data_source_interface, - NULL, - &wl_data_offer_interface, - NULL, - &wl_surface_interface, - NULL, - NULL, - &wl_data_offer_interface, - &wl_data_offer_interface, - &wl_data_source_interface, - &wl_data_device_interface, - &wl_seat_interface, - &wl_shell_surface_interface, - &wl_surface_interface, - &wl_seat_interface, - NULL, - &wl_seat_interface, - NULL, - NULL, - &wl_surface_interface, - NULL, - NULL, - NULL, - NULL, - NULL, - &wl_output_interface, - &wl_seat_interface, - NULL, - &wl_surface_interface, - NULL, - NULL, - NULL, - &wl_output_interface, - &wl_buffer_interface, - NULL, - NULL, - &wl_callback_interface, - &wl_region_interface, - &wl_region_interface, - &wl_output_interface, - &wl_output_interface, - &wl_pointer_interface, - &wl_keyboard_interface, - &wl_touch_interface, - NULL, - &wl_surface_interface, - NULL, - NULL, - NULL, - &wl_surface_interface, - NULL, - NULL, - NULL, - &wl_surface_interface, - NULL, - &wl_surface_interface, - NULL, - NULL, - &wl_surface_interface, - NULL, - NULL, - &wl_surface_interface, - NULL, - NULL, - NULL, - &wl_subsurface_interface, - &wl_surface_interface, - &wl_surface_interface, - &wl_surface_interface, - &wl_surface_interface, - &wl_registry_interface, -}; - -static const struct wl_message wl_display_requests[] = { - { "sync", "n", wayland_types + 8 }, - { "get_registry", "n", wayland_types + 9 }, -}; - -static const struct wl_message wl_display_events[] = { - { "error", "ous", wayland_types + 0 }, - { "delete_id", "u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_display_interface = { - "wl_display", 1, - 2, wl_display_requests, - 2, wl_display_events, -}; - -static const struct wl_message wl_registry_requests[] = { - { "bind", "usun", wayland_types + 0 }, -}; - -static const struct wl_message wl_registry_events[] = { - { "global", "usu", wayland_types + 0 }, - { "global_remove", "u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_registry_interface = { - "wl_registry", 1, - 1, wl_registry_requests, - 2, wl_registry_events, -}; - -static const struct wl_message wl_callback_events[] = { - { "done", "u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_callback_interface = { - "wl_callback", 1, - 0, NULL, - 1, wl_callback_events, -}; - -static const struct wl_message wl_compositor_requests[] = { - { "create_surface", "n", wayland_types + 10 }, - { "create_region", "n", wayland_types + 11 }, -}; - -WL_PRIVATE const struct wl_interface wl_compositor_interface = { - "wl_compositor", 6, - 2, wl_compositor_requests, - 0, NULL, -}; - -static const struct wl_message wl_shm_pool_requests[] = { - { "create_buffer", "niiiiu", wayland_types + 12 }, - { "destroy", "", wayland_types + 0 }, - { "resize", "i", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_shm_pool_interface = { - "wl_shm_pool", 2, - 3, wl_shm_pool_requests, - 0, NULL, -}; - -static const struct wl_message wl_shm_requests[] = { - { "create_pool", "nhi", wayland_types + 18 }, - { "release", "2", wayland_types + 0 }, -}; - -static const struct wl_message wl_shm_events[] = { - { "format", "u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_shm_interface = { - "wl_shm", 2, - 2, wl_shm_requests, - 1, wl_shm_events, -}; - -static const struct wl_message wl_buffer_requests[] = { - { "destroy", "", wayland_types + 0 }, -}; - -static const struct wl_message wl_buffer_events[] = { - { "release", "", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_buffer_interface = { - "wl_buffer", 1, - 1, wl_buffer_requests, - 1, wl_buffer_events, -}; - -static const struct wl_message wl_data_offer_requests[] = { - { "accept", "u?s", wayland_types + 0 }, - { "receive", "sh", wayland_types + 0 }, - { "destroy", "", wayland_types + 0 }, - { "finish", "3", wayland_types + 0 }, - { "set_actions", "3uu", wayland_types + 0 }, -}; - -static const struct wl_message wl_data_offer_events[] = { - { "offer", "s", wayland_types + 0 }, - { "source_actions", "3u", wayland_types + 0 }, - { "action", "3u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_data_offer_interface = { - "wl_data_offer", 3, - 5, wl_data_offer_requests, - 3, wl_data_offer_events, -}; - -static const struct wl_message wl_data_source_requests[] = { - { "offer", "s", wayland_types + 0 }, - { "destroy", "", wayland_types + 0 }, - { "set_actions", "3u", wayland_types + 0 }, -}; - -static const struct wl_message wl_data_source_events[] = { - { "target", "?s", wayland_types + 0 }, - { "send", "sh", wayland_types + 0 }, - { "cancelled", "", wayland_types + 0 }, - { "dnd_drop_performed", "3", wayland_types + 0 }, - { "dnd_finished", "3", wayland_types + 0 }, - { "action", "3u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_data_source_interface = { - "wl_data_source", 3, - 3, wl_data_source_requests, - 6, wl_data_source_events, -}; - -static const struct wl_message wl_data_device_requests[] = { - { "start_drag", "?oo?ou", wayland_types + 21 }, - { "set_selection", "?ou", wayland_types + 25 }, - { "release", "2", wayland_types + 0 }, -}; - -static const struct wl_message wl_data_device_events[] = { - { "data_offer", "n", wayland_types + 27 }, - { "enter", "uoff?o", wayland_types + 28 }, - { "leave", "", wayland_types + 0 }, - { "motion", "uff", wayland_types + 0 }, - { "drop", "", wayland_types + 0 }, - { "selection", "?o", wayland_types + 33 }, -}; - -WL_PRIVATE const struct wl_interface wl_data_device_interface = { - "wl_data_device", 3, - 3, wl_data_device_requests, - 6, wl_data_device_events, -}; - -static const struct wl_message wl_data_device_manager_requests[] = { - { "create_data_source", "n", wayland_types + 34 }, - { "get_data_device", "no", wayland_types + 35 }, -}; - -WL_PRIVATE const struct wl_interface wl_data_device_manager_interface = { - "wl_data_device_manager", 3, - 2, wl_data_device_manager_requests, - 0, NULL, -}; - -static const struct wl_message wl_shell_requests[] = { - { "get_shell_surface", "no", wayland_types + 37 }, -}; - -WL_PRIVATE const struct wl_interface wl_shell_interface = { - "wl_shell", 1, - 1, wl_shell_requests, - 0, NULL, -}; - -static const struct wl_message wl_shell_surface_requests[] = { - { "pong", "u", wayland_types + 0 }, - { "move", "ou", wayland_types + 39 }, - { "resize", "ouu", wayland_types + 41 }, - { "set_toplevel", "", wayland_types + 0 }, - { "set_transient", "oiiu", wayland_types + 44 }, - { "set_fullscreen", "uu?o", wayland_types + 48 }, - { "set_popup", "ouoiiu", wayland_types + 51 }, - { "set_maximized", "?o", wayland_types + 57 }, - { "set_title", "s", wayland_types + 0 }, - { "set_class", "s", wayland_types + 0 }, -}; - -static const struct wl_message wl_shell_surface_events[] = { - { "ping", "u", wayland_types + 0 }, - { "configure", "uii", wayland_types + 0 }, - { "popup_done", "", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_shell_surface_interface = { - "wl_shell_surface", 1, - 10, wl_shell_surface_requests, - 3, wl_shell_surface_events, -}; - -static const struct wl_message wl_surface_requests[] = { - { "destroy", "", wayland_types + 0 }, - { "attach", "?oii", wayland_types + 58 }, - { "damage", "iiii", wayland_types + 0 }, - { "frame", "n", wayland_types + 61 }, - { "set_opaque_region", "?o", wayland_types + 62 }, - { "set_input_region", "?o", wayland_types + 63 }, - { "commit", "", wayland_types + 0 }, - { "set_buffer_transform", "2i", wayland_types + 0 }, - { "set_buffer_scale", "3i", wayland_types + 0 }, - { "damage_buffer", "4iiii", wayland_types + 0 }, - { "offset", "5ii", wayland_types + 0 }, -}; - -static const struct wl_message wl_surface_events[] = { - { "enter", "o", wayland_types + 64 }, - { "leave", "o", wayland_types + 65 }, - { "preferred_buffer_scale", "6i", wayland_types + 0 }, - { "preferred_buffer_transform", "6u", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_surface_interface = { - "wl_surface", 6, - 11, wl_surface_requests, - 4, wl_surface_events, -}; - -static const struct wl_message wl_seat_requests[] = { - { "get_pointer", "n", wayland_types + 66 }, - { "get_keyboard", "n", wayland_types + 67 }, - { "get_touch", "n", wayland_types + 68 }, - { "release", "5", wayland_types + 0 }, -}; - -static const struct wl_message wl_seat_events[] = { - { "capabilities", "u", wayland_types + 0 }, - { "name", "2s", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_seat_interface = { - "wl_seat", 10, - 4, wl_seat_requests, - 2, wl_seat_events, -}; - -static const struct wl_message wl_pointer_requests[] = { - { "set_cursor", "u?oii", wayland_types + 69 }, - { "release", "3", wayland_types + 0 }, -}; - -static const struct wl_message wl_pointer_events[] = { - { "enter", "uoff", wayland_types + 73 }, - { "leave", "uo", wayland_types + 77 }, - { "motion", "uff", wayland_types + 0 }, - { "button", "uuuu", wayland_types + 0 }, - { "axis", "uuf", wayland_types + 0 }, - { "frame", "5", wayland_types + 0 }, - { "axis_source", "5u", wayland_types + 0 }, - { "axis_stop", "5uu", wayland_types + 0 }, - { "axis_discrete", "5ui", wayland_types + 0 }, - { "axis_value120", "8ui", wayland_types + 0 }, - { "axis_relative_direction", "9uu", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_pointer_interface = { - "wl_pointer", 10, - 2, wl_pointer_requests, - 11, wl_pointer_events, -}; - -static const struct wl_message wl_keyboard_requests[] = { - { "release", "3", wayland_types + 0 }, -}; - -static const struct wl_message wl_keyboard_events[] = { - { "keymap", "uhu", wayland_types + 0 }, - { "enter", "uoa", wayland_types + 79 }, - { "leave", "uo", wayland_types + 82 }, - { "key", "uuuu", wayland_types + 0 }, - { "modifiers", "uuuuu", wayland_types + 0 }, - { "repeat_info", "4ii", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_keyboard_interface = { - "wl_keyboard", 10, - 1, wl_keyboard_requests, - 6, wl_keyboard_events, -}; - -static const struct wl_message wl_touch_requests[] = { - { "release", "3", wayland_types + 0 }, -}; - -static const struct wl_message wl_touch_events[] = { - { "down", "uuoiff", wayland_types + 84 }, - { "up", "uui", wayland_types + 0 }, - { "motion", "uiff", wayland_types + 0 }, - { "frame", "", wayland_types + 0 }, - { "cancel", "", wayland_types + 0 }, - { "shape", "6iff", wayland_types + 0 }, - { "orientation", "6if", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_touch_interface = { - "wl_touch", 10, - 1, wl_touch_requests, - 7, wl_touch_events, -}; - -static const struct wl_message wl_output_requests[] = { - { "release", "3", wayland_types + 0 }, -}; - -static const struct wl_message wl_output_events[] = { - { "geometry", "iiiiissi", wayland_types + 0 }, - { "mode", "uiii", wayland_types + 0 }, - { "done", "2", wayland_types + 0 }, - { "scale", "2i", wayland_types + 0 }, - { "name", "4s", wayland_types + 0 }, - { "description", "4s", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_output_interface = { - "wl_output", 4, - 1, wl_output_requests, - 6, wl_output_events, -}; - -static const struct wl_message wl_region_requests[] = { - { "destroy", "", wayland_types + 0 }, - { "add", "iiii", wayland_types + 0 }, - { "subtract", "iiii", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_region_interface = { - "wl_region", 1, - 3, wl_region_requests, - 0, NULL, -}; - -static const struct wl_message wl_subcompositor_requests[] = { - { "destroy", "", wayland_types + 0 }, - { "get_subsurface", "noo", wayland_types + 90 }, -}; - -WL_PRIVATE const struct wl_interface wl_subcompositor_interface = { - "wl_subcompositor", 1, - 2, wl_subcompositor_requests, - 0, NULL, -}; - -static const struct wl_message wl_subsurface_requests[] = { - { "destroy", "", wayland_types + 0 }, - { "set_position", "ii", wayland_types + 0 }, - { "place_above", "o", wayland_types + 93 }, - { "place_below", "o", wayland_types + 94 }, - { "set_sync", "", wayland_types + 0 }, - { "set_desync", "", wayland_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wl_subsurface_interface = { - "wl_subsurface", 1, - 6, wl_subsurface_requests, - 0, NULL, -}; - -static const struct wl_message wl_fixes_requests[] = { - { "destroy", "", wayland_types + 0 }, - { "destroy_registry", "o", wayland_types + 95 }, -}; - -WL_PRIVATE const struct wl_interface wl_fixes_interface = { - "wl_fixes", 1, - 2, wl_fixes_requests, - 0, NULL, -}; - diff --git a/raylib/external/glfw/src/wayland-client-protocol.h b/raylib/external/glfw/src/wayland-client-protocol.h deleted file mode 100644 index fadb460..0000000 --- a/raylib/external/glfw/src/wayland-client-protocol.h +++ /dev/null @@ -1,6522 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef WAYLAND_CLIENT_PROTOCOL_H -#define WAYLAND_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_wayland The wayland protocol - * @section page_ifaces_wayland Interfaces - * - @subpage page_iface_wl_display - core global object - * - @subpage page_iface_wl_registry - global registry object - * - @subpage page_iface_wl_callback - callback object - * - @subpage page_iface_wl_compositor - the compositor singleton - * - @subpage page_iface_wl_shm_pool - a shared memory pool - * - @subpage page_iface_wl_shm - shared memory support - * - @subpage page_iface_wl_buffer - content for a wl_surface - * - @subpage page_iface_wl_data_offer - offer to transfer data - * - @subpage page_iface_wl_data_source - offer to transfer data - * - @subpage page_iface_wl_data_device - data transfer device - * - @subpage page_iface_wl_data_device_manager - data transfer interface - * - @subpage page_iface_wl_shell - create desktop-style surfaces - * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface - * - @subpage page_iface_wl_surface - an onscreen surface - * - @subpage page_iface_wl_seat - group of input devices - * - @subpage page_iface_wl_pointer - pointer input device - * - @subpage page_iface_wl_keyboard - keyboard input device - * - @subpage page_iface_wl_touch - touchscreen input device - * - @subpage page_iface_wl_output - compositor output region - * - @subpage page_iface_wl_region - region interface - * - @subpage page_iface_wl_subcompositor - sub-surface compositing - * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface - * - @subpage page_iface_wl_fixes - wayland protocol fixes - * @section page_copyright_wayland Copyright - *
- *
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2012-2013 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- * 
- */ -struct wl_buffer; -struct wl_callback; -struct wl_compositor; -struct wl_data_device; -struct wl_data_device_manager; -struct wl_data_offer; -struct wl_data_source; -struct wl_display; -struct wl_fixes; -struct wl_keyboard; -struct wl_output; -struct wl_pointer; -struct wl_region; -struct wl_registry; -struct wl_seat; -struct wl_shell; -struct wl_shell_surface; -struct wl_shm; -struct wl_shm_pool; -struct wl_subcompositor; -struct wl_subsurface; -struct wl_surface; -struct wl_touch; - -#ifndef WL_DISPLAY_INTERFACE -#define WL_DISPLAY_INTERFACE -/** - * @page page_iface_wl_display wl_display - * @section page_iface_wl_display_desc Description - * - * The core global object. This is a special singleton object. It - * is used for internal Wayland protocol features. - * @section page_iface_wl_display_api API - * See @ref iface_wl_display. - */ -/** - * @defgroup iface_wl_display The wl_display interface - * - * The core global object. This is a special singleton object. It - * is used for internal Wayland protocol features. - */ -extern const struct wl_interface wl_display_interface; -#endif -#ifndef WL_REGISTRY_INTERFACE -#define WL_REGISTRY_INTERFACE -/** - * @page page_iface_wl_registry wl_registry - * @section page_iface_wl_registry_desc Description - * - * The singleton global registry object. The server has a number of - * global objects that are available to all clients. These objects - * typically represent an actual object in the server (for example, - * an input device) or they are singleton objects that provide - * extension functionality. - * - * When a client creates a registry object, the registry object - * will emit a global event for each global currently in the - * registry. Globals come and go as a result of device or - * monitor hotplugs, reconfiguration or other events, and the - * registry will send out global and global_remove events to - * keep the client up to date with the changes. To mark the end - * of the initial burst of events, the client can use the - * wl_display.sync request immediately after calling - * wl_display.get_registry. - * - * A client can bind to a global object by using the bind - * request. This creates a client-side handle that lets the object - * emit events to the client and lets the client invoke requests on - * the object. - * @section page_iface_wl_registry_api API - * See @ref iface_wl_registry. - */ -/** - * @defgroup iface_wl_registry The wl_registry interface - * - * The singleton global registry object. The server has a number of - * global objects that are available to all clients. These objects - * typically represent an actual object in the server (for example, - * an input device) or they are singleton objects that provide - * extension functionality. - * - * When a client creates a registry object, the registry object - * will emit a global event for each global currently in the - * registry. Globals come and go as a result of device or - * monitor hotplugs, reconfiguration or other events, and the - * registry will send out global and global_remove events to - * keep the client up to date with the changes. To mark the end - * of the initial burst of events, the client can use the - * wl_display.sync request immediately after calling - * wl_display.get_registry. - * - * A client can bind to a global object by using the bind - * request. This creates a client-side handle that lets the object - * emit events to the client and lets the client invoke requests on - * the object. - */ -extern const struct wl_interface wl_registry_interface; -#endif -#ifndef WL_CALLBACK_INTERFACE -#define WL_CALLBACK_INTERFACE -/** - * @page page_iface_wl_callback wl_callback - * @section page_iface_wl_callback_desc Description - * - * Clients can handle the 'done' event to get notified when - * the related request is done. - * - * Note, because wl_callback objects are created from multiple independent - * factory interfaces, the wl_callback interface is frozen at version 1. - * @section page_iface_wl_callback_api API - * See @ref iface_wl_callback. - */ -/** - * @defgroup iface_wl_callback The wl_callback interface - * - * Clients can handle the 'done' event to get notified when - * the related request is done. - * - * Note, because wl_callback objects are created from multiple independent - * factory interfaces, the wl_callback interface is frozen at version 1. - */ -extern const struct wl_interface wl_callback_interface; -#endif -#ifndef WL_COMPOSITOR_INTERFACE -#define WL_COMPOSITOR_INTERFACE -/** - * @page page_iface_wl_compositor wl_compositor - * @section page_iface_wl_compositor_desc Description - * - * A compositor. This object is a singleton global. The - * compositor is in charge of combining the contents of multiple - * surfaces into one displayable output. - * @section page_iface_wl_compositor_api API - * See @ref iface_wl_compositor. - */ -/** - * @defgroup iface_wl_compositor The wl_compositor interface - * - * A compositor. This object is a singleton global. The - * compositor is in charge of combining the contents of multiple - * surfaces into one displayable output. - */ -extern const struct wl_interface wl_compositor_interface; -#endif -#ifndef WL_SHM_POOL_INTERFACE -#define WL_SHM_POOL_INTERFACE -/** - * @page page_iface_wl_shm_pool wl_shm_pool - * @section page_iface_wl_shm_pool_desc Description - * - * The wl_shm_pool object encapsulates a piece of memory shared - * between the compositor and client. Through the wl_shm_pool - * object, the client can allocate shared memory wl_buffer objects. - * All objects created through the same pool share the same - * underlying mapped memory. Reusing the mapped memory avoids the - * setup/teardown overhead and is useful when interactively resizing - * a surface or for many small buffers. - * @section page_iface_wl_shm_pool_api API - * See @ref iface_wl_shm_pool. - */ -/** - * @defgroup iface_wl_shm_pool The wl_shm_pool interface - * - * The wl_shm_pool object encapsulates a piece of memory shared - * between the compositor and client. Through the wl_shm_pool - * object, the client can allocate shared memory wl_buffer objects. - * All objects created through the same pool share the same - * underlying mapped memory. Reusing the mapped memory avoids the - * setup/teardown overhead and is useful when interactively resizing - * a surface or for many small buffers. - */ -extern const struct wl_interface wl_shm_pool_interface; -#endif -#ifndef WL_SHM_INTERFACE -#define WL_SHM_INTERFACE -/** - * @page page_iface_wl_shm wl_shm - * @section page_iface_wl_shm_desc Description - * - * A singleton global object that provides support for shared - * memory. - * - * Clients can create wl_shm_pool objects using the create_pool - * request. - * - * On binding the wl_shm object one or more format events - * are emitted to inform clients about the valid pixel formats - * that can be used for buffers. - * @section page_iface_wl_shm_api API - * See @ref iface_wl_shm. - */ -/** - * @defgroup iface_wl_shm The wl_shm interface - * - * A singleton global object that provides support for shared - * memory. - * - * Clients can create wl_shm_pool objects using the create_pool - * request. - * - * On binding the wl_shm object one or more format events - * are emitted to inform clients about the valid pixel formats - * that can be used for buffers. - */ -extern const struct wl_interface wl_shm_interface; -#endif -#ifndef WL_BUFFER_INTERFACE -#define WL_BUFFER_INTERFACE -/** - * @page page_iface_wl_buffer wl_buffer - * @section page_iface_wl_buffer_desc Description - * - * A buffer provides the content for a wl_surface. Buffers are - * created through factory interfaces such as wl_shm, wp_linux_buffer_params - * (from the linux-dmabuf protocol extension) or similar. It has a width and - * a height and can be attached to a wl_surface, but the mechanism by which a - * client provides and updates the contents is defined by the buffer factory - * interface. - * - * Color channels are assumed to be electrical rather than optical (in other - * words, encoded with a transfer function) unless otherwise specified. If - * the buffer uses a format that has an alpha channel, the alpha channel is - * assumed to be premultiplied into the electrical color channel values - * (after transfer function encoding) unless otherwise specified. - * - * Note, because wl_buffer objects are created from multiple independent - * factory interfaces, the wl_buffer interface is frozen at version 1. - * @section page_iface_wl_buffer_api API - * See @ref iface_wl_buffer. - */ -/** - * @defgroup iface_wl_buffer The wl_buffer interface - * - * A buffer provides the content for a wl_surface. Buffers are - * created through factory interfaces such as wl_shm, wp_linux_buffer_params - * (from the linux-dmabuf protocol extension) or similar. It has a width and - * a height and can be attached to a wl_surface, but the mechanism by which a - * client provides and updates the contents is defined by the buffer factory - * interface. - * - * Color channels are assumed to be electrical rather than optical (in other - * words, encoded with a transfer function) unless otherwise specified. If - * the buffer uses a format that has an alpha channel, the alpha channel is - * assumed to be premultiplied into the electrical color channel values - * (after transfer function encoding) unless otherwise specified. - * - * Note, because wl_buffer objects are created from multiple independent - * factory interfaces, the wl_buffer interface is frozen at version 1. - */ -extern const struct wl_interface wl_buffer_interface; -#endif -#ifndef WL_DATA_OFFER_INTERFACE -#define WL_DATA_OFFER_INTERFACE -/** - * @page page_iface_wl_data_offer wl_data_offer - * @section page_iface_wl_data_offer_desc Description - * - * A wl_data_offer represents a piece of data offered for transfer - * by another client (the source client). It is used by the - * copy-and-paste and drag-and-drop mechanisms. The offer - * describes the different mime types that the data can be - * converted to and provides the mechanism for transferring the - * data directly from the source client. - * @section page_iface_wl_data_offer_api API - * See @ref iface_wl_data_offer. - */ -/** - * @defgroup iface_wl_data_offer The wl_data_offer interface - * - * A wl_data_offer represents a piece of data offered for transfer - * by another client (the source client). It is used by the - * copy-and-paste and drag-and-drop mechanisms. The offer - * describes the different mime types that the data can be - * converted to and provides the mechanism for transferring the - * data directly from the source client. - */ -extern const struct wl_interface wl_data_offer_interface; -#endif -#ifndef WL_DATA_SOURCE_INTERFACE -#define WL_DATA_SOURCE_INTERFACE -/** - * @page page_iface_wl_data_source wl_data_source - * @section page_iface_wl_data_source_desc Description - * - * The wl_data_source object is the source side of a wl_data_offer. - * It is created by the source client in a data transfer and - * provides a way to describe the offered data and a way to respond - * to requests to transfer the data. - * @section page_iface_wl_data_source_api API - * See @ref iface_wl_data_source. - */ -/** - * @defgroup iface_wl_data_source The wl_data_source interface - * - * The wl_data_source object is the source side of a wl_data_offer. - * It is created by the source client in a data transfer and - * provides a way to describe the offered data and a way to respond - * to requests to transfer the data. - */ -extern const struct wl_interface wl_data_source_interface; -#endif -#ifndef WL_DATA_DEVICE_INTERFACE -#define WL_DATA_DEVICE_INTERFACE -/** - * @page page_iface_wl_data_device wl_data_device - * @section page_iface_wl_data_device_desc Description - * - * There is one wl_data_device per seat which can be obtained - * from the global wl_data_device_manager singleton. - * - * A wl_data_device provides access to inter-client data transfer - * mechanisms such as copy-and-paste and drag-and-drop. - * @section page_iface_wl_data_device_api API - * See @ref iface_wl_data_device. - */ -/** - * @defgroup iface_wl_data_device The wl_data_device interface - * - * There is one wl_data_device per seat which can be obtained - * from the global wl_data_device_manager singleton. - * - * A wl_data_device provides access to inter-client data transfer - * mechanisms such as copy-and-paste and drag-and-drop. - */ -extern const struct wl_interface wl_data_device_interface; -#endif -#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE -#define WL_DATA_DEVICE_MANAGER_INTERFACE -/** - * @page page_iface_wl_data_device_manager wl_data_device_manager - * @section page_iface_wl_data_device_manager_desc Description - * - * The wl_data_device_manager is a singleton global object that - * provides access to inter-client data transfer mechanisms such as - * copy-and-paste and drag-and-drop. These mechanisms are tied to - * a wl_seat and this interface lets a client get a wl_data_device - * corresponding to a wl_seat. - * - * Depending on the version bound, the objects created from the bound - * wl_data_device_manager object will have different requirements for - * functioning properly. See wl_data_source.set_actions, - * wl_data_offer.accept and wl_data_offer.finish for details. - * @section page_iface_wl_data_device_manager_api API - * See @ref iface_wl_data_device_manager. - */ -/** - * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface - * - * The wl_data_device_manager is a singleton global object that - * provides access to inter-client data transfer mechanisms such as - * copy-and-paste and drag-and-drop. These mechanisms are tied to - * a wl_seat and this interface lets a client get a wl_data_device - * corresponding to a wl_seat. - * - * Depending on the version bound, the objects created from the bound - * wl_data_device_manager object will have different requirements for - * functioning properly. See wl_data_source.set_actions, - * wl_data_offer.accept and wl_data_offer.finish for details. - */ -extern const struct wl_interface wl_data_device_manager_interface; -#endif -#ifndef WL_SHELL_INTERFACE -#define WL_SHELL_INTERFACE -/** - * @page page_iface_wl_shell wl_shell - * @section page_iface_wl_shell_desc Description - * - * This interface is implemented by servers that provide - * desktop-style user interfaces. - * - * It allows clients to associate a wl_shell_surface with - * a basic surface. - * - * Note! This protocol is deprecated and not intended for production use. - * For desktop-style user interfaces, use xdg_shell. Compositors and clients - * should not implement this interface. - * @section page_iface_wl_shell_api API - * See @ref iface_wl_shell. - */ -/** - * @defgroup iface_wl_shell The wl_shell interface - * - * This interface is implemented by servers that provide - * desktop-style user interfaces. - * - * It allows clients to associate a wl_shell_surface with - * a basic surface. - * - * Note! This protocol is deprecated and not intended for production use. - * For desktop-style user interfaces, use xdg_shell. Compositors and clients - * should not implement this interface. - */ -extern const struct wl_interface wl_shell_interface; -#endif -#ifndef WL_SHELL_SURFACE_INTERFACE -#define WL_SHELL_SURFACE_INTERFACE -/** - * @page page_iface_wl_shell_surface wl_shell_surface - * @section page_iface_wl_shell_surface_desc Description - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides requests to treat surfaces like toplevel, fullscreen - * or popup windows, move, resize or maximize them, associate - * metadata like title and class, etc. - * - * On the server side the object is automatically destroyed when - * the related wl_surface is destroyed. On the client side, - * wl_shell_surface_destroy() must be called before destroying - * the wl_surface object. - * @section page_iface_wl_shell_surface_api API - * See @ref iface_wl_shell_surface. - */ -/** - * @defgroup iface_wl_shell_surface The wl_shell_surface interface - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides requests to treat surfaces like toplevel, fullscreen - * or popup windows, move, resize or maximize them, associate - * metadata like title and class, etc. - * - * On the server side the object is automatically destroyed when - * the related wl_surface is destroyed. On the client side, - * wl_shell_surface_destroy() must be called before destroying - * the wl_surface object. - */ -extern const struct wl_interface wl_shell_surface_interface; -#endif -#ifndef WL_SURFACE_INTERFACE -#define WL_SURFACE_INTERFACE -/** - * @page page_iface_wl_surface wl_surface - * @section page_iface_wl_surface_desc Description - * - * A surface is a rectangular area that may be displayed on zero - * or more outputs, and shown any number of times at the compositor's - * discretion. They can present wl_buffers, receive user input, and - * define a local coordinate system. - * - * The size of a surface (and relative positions on it) is described - * in surface-local coordinates, which may differ from the buffer - * coordinates of the pixel content, in case a buffer_transform - * or a buffer_scale is used. - * - * A surface without a "role" is fairly useless: a compositor does - * not know where, when or how to present it. The role is the - * purpose of a wl_surface. Examples of roles are a cursor for a - * pointer (as set by wl_pointer.set_cursor), a drag icon - * (wl_data_device.start_drag), a sub-surface - * (wl_subcompositor.get_subsurface), and a window as defined by a - * shell protocol (e.g. wl_shell.get_shell_surface). - * - * A surface can have only one role at a time. Initially a - * wl_surface does not have a role. Once a wl_surface is given a - * role, it is set permanently for the whole lifetime of the - * wl_surface object. Giving the current role again is allowed, - * unless explicitly forbidden by the relevant interface - * specification. - * - * Surface roles are given by requests in other interfaces such as - * wl_pointer.set_cursor. The request should explicitly mention - * that this request gives a role to a wl_surface. Often, this - * request also creates a new protocol object that represents the - * role and adds additional functionality to wl_surface. When a - * client wants to destroy a wl_surface, they must destroy this role - * object before the wl_surface, otherwise a defunct_role_object error is - * sent. - * - * Destroying the role object does not remove the role from the - * wl_surface, but it may stop the wl_surface from "playing the role". - * For instance, if a wl_subsurface object is destroyed, the wl_surface - * it was created for will be unmapped and forget its position and - * z-order. It is allowed to create a wl_subsurface for the same - * wl_surface again, but it is not allowed to use the wl_surface as - * a cursor (cursor is a different role than sub-surface, and role - * switching is not allowed). - * @section page_iface_wl_surface_api API - * See @ref iface_wl_surface. - */ -/** - * @defgroup iface_wl_surface The wl_surface interface - * - * A surface is a rectangular area that may be displayed on zero - * or more outputs, and shown any number of times at the compositor's - * discretion. They can present wl_buffers, receive user input, and - * define a local coordinate system. - * - * The size of a surface (and relative positions on it) is described - * in surface-local coordinates, which may differ from the buffer - * coordinates of the pixel content, in case a buffer_transform - * or a buffer_scale is used. - * - * A surface without a "role" is fairly useless: a compositor does - * not know where, when or how to present it. The role is the - * purpose of a wl_surface. Examples of roles are a cursor for a - * pointer (as set by wl_pointer.set_cursor), a drag icon - * (wl_data_device.start_drag), a sub-surface - * (wl_subcompositor.get_subsurface), and a window as defined by a - * shell protocol (e.g. wl_shell.get_shell_surface). - * - * A surface can have only one role at a time. Initially a - * wl_surface does not have a role. Once a wl_surface is given a - * role, it is set permanently for the whole lifetime of the - * wl_surface object. Giving the current role again is allowed, - * unless explicitly forbidden by the relevant interface - * specification. - * - * Surface roles are given by requests in other interfaces such as - * wl_pointer.set_cursor. The request should explicitly mention - * that this request gives a role to a wl_surface. Often, this - * request also creates a new protocol object that represents the - * role and adds additional functionality to wl_surface. When a - * client wants to destroy a wl_surface, they must destroy this role - * object before the wl_surface, otherwise a defunct_role_object error is - * sent. - * - * Destroying the role object does not remove the role from the - * wl_surface, but it may stop the wl_surface from "playing the role". - * For instance, if a wl_subsurface object is destroyed, the wl_surface - * it was created for will be unmapped and forget its position and - * z-order. It is allowed to create a wl_subsurface for the same - * wl_surface again, but it is not allowed to use the wl_surface as - * a cursor (cursor is a different role than sub-surface, and role - * switching is not allowed). - */ -extern const struct wl_interface wl_surface_interface; -#endif -#ifndef WL_SEAT_INTERFACE -#define WL_SEAT_INTERFACE -/** - * @page page_iface_wl_seat wl_seat - * @section page_iface_wl_seat_desc Description - * - * A seat is a group of keyboards, pointer and touch devices. This - * object is published as a global during start up, or when such a - * device is hot plugged. A seat typically has a pointer and - * maintains a keyboard focus and a pointer focus. - * @section page_iface_wl_seat_api API - * See @ref iface_wl_seat. - */ -/** - * @defgroup iface_wl_seat The wl_seat interface - * - * A seat is a group of keyboards, pointer and touch devices. This - * object is published as a global during start up, or when such a - * device is hot plugged. A seat typically has a pointer and - * maintains a keyboard focus and a pointer focus. - */ -extern const struct wl_interface wl_seat_interface; -#endif -#ifndef WL_POINTER_INTERFACE -#define WL_POINTER_INTERFACE -/** - * @page page_iface_wl_pointer wl_pointer - * @section page_iface_wl_pointer_desc Description - * - * The wl_pointer interface represents one or more input devices, - * such as mice, which control the pointer location and pointer_focus - * of a seat. - * - * The wl_pointer interface generates motion, enter and leave - * events for the surfaces that the pointer is located over, - * and button and axis events for button presses, button releases - * and scrolling. - * @section page_iface_wl_pointer_api API - * See @ref iface_wl_pointer. - */ -/** - * @defgroup iface_wl_pointer The wl_pointer interface - * - * The wl_pointer interface represents one or more input devices, - * such as mice, which control the pointer location and pointer_focus - * of a seat. - * - * The wl_pointer interface generates motion, enter and leave - * events for the surfaces that the pointer is located over, - * and button and axis events for button presses, button releases - * and scrolling. - */ -extern const struct wl_interface wl_pointer_interface; -#endif -#ifndef WL_KEYBOARD_INTERFACE -#define WL_KEYBOARD_INTERFACE -/** - * @page page_iface_wl_keyboard wl_keyboard - * @section page_iface_wl_keyboard_desc Description - * - * The wl_keyboard interface represents one or more keyboards - * associated with a seat. - * - * Each wl_keyboard has the following logical state: - * - * - an active surface (possibly null), - * - the keys currently logically down, - * - the active modifiers, - * - the active group. - * - * By default, the active surface is null, the keys currently logically down - * are empty, the active modifiers and the active group are 0. - * @section page_iface_wl_keyboard_api API - * See @ref iface_wl_keyboard. - */ -/** - * @defgroup iface_wl_keyboard The wl_keyboard interface - * - * The wl_keyboard interface represents one or more keyboards - * associated with a seat. - * - * Each wl_keyboard has the following logical state: - * - * - an active surface (possibly null), - * - the keys currently logically down, - * - the active modifiers, - * - the active group. - * - * By default, the active surface is null, the keys currently logically down - * are empty, the active modifiers and the active group are 0. - */ -extern const struct wl_interface wl_keyboard_interface; -#endif -#ifndef WL_TOUCH_INTERFACE -#define WL_TOUCH_INTERFACE -/** - * @page page_iface_wl_touch wl_touch - * @section page_iface_wl_touch_desc Description - * - * The wl_touch interface represents a touchscreen - * associated with a seat. - * - * Touch interactions can consist of one or more contacts. - * For each contact, a series of events is generated, starting - * with a down event, followed by zero or more motion events, - * and ending with an up event. Events relating to the same - * contact point can be identified by the ID of the sequence. - * @section page_iface_wl_touch_api API - * See @ref iface_wl_touch. - */ -/** - * @defgroup iface_wl_touch The wl_touch interface - * - * The wl_touch interface represents a touchscreen - * associated with a seat. - * - * Touch interactions can consist of one or more contacts. - * For each contact, a series of events is generated, starting - * with a down event, followed by zero or more motion events, - * and ending with an up event. Events relating to the same - * contact point can be identified by the ID of the sequence. - */ -extern const struct wl_interface wl_touch_interface; -#endif -#ifndef WL_OUTPUT_INTERFACE -#define WL_OUTPUT_INTERFACE -/** - * @page page_iface_wl_output wl_output - * @section page_iface_wl_output_desc Description - * - * An output describes part of the compositor geometry. The - * compositor works in the 'compositor coordinate system' and an - * output corresponds to a rectangular area in that space that is - * actually visible. This typically corresponds to a monitor that - * displays part of the compositor space. This object is published - * as global during start up, or when a monitor is hotplugged. - * @section page_iface_wl_output_api API - * See @ref iface_wl_output. - */ -/** - * @defgroup iface_wl_output The wl_output interface - * - * An output describes part of the compositor geometry. The - * compositor works in the 'compositor coordinate system' and an - * output corresponds to a rectangular area in that space that is - * actually visible. This typically corresponds to a monitor that - * displays part of the compositor space. This object is published - * as global during start up, or when a monitor is hotplugged. - */ -extern const struct wl_interface wl_output_interface; -#endif -#ifndef WL_REGION_INTERFACE -#define WL_REGION_INTERFACE -/** - * @page page_iface_wl_region wl_region - * @section page_iface_wl_region_desc Description - * - * A region object describes an area. - * - * Region objects are used to describe the opaque and input - * regions of a surface. - * @section page_iface_wl_region_api API - * See @ref iface_wl_region. - */ -/** - * @defgroup iface_wl_region The wl_region interface - * - * A region object describes an area. - * - * Region objects are used to describe the opaque and input - * regions of a surface. - */ -extern const struct wl_interface wl_region_interface; -#endif -#ifndef WL_SUBCOMPOSITOR_INTERFACE -#define WL_SUBCOMPOSITOR_INTERFACE -/** - * @page page_iface_wl_subcompositor wl_subcompositor - * @section page_iface_wl_subcompositor_desc Description - * - * The global interface exposing sub-surface compositing capabilities. - * A wl_surface, that has sub-surfaces associated, is called the - * parent surface. Sub-surfaces can be arbitrarily nested and create - * a tree of sub-surfaces. - * - * The root surface in a tree of sub-surfaces is the main - * surface. The main surface cannot be a sub-surface, because - * sub-surfaces must always have a parent. - * - * A main surface with its sub-surfaces forms a (compound) window. - * For window management purposes, this set of wl_surface objects is - * to be considered as a single window, and it should also behave as - * such. - * - * The aim of sub-surfaces is to offload some of the compositing work - * within a window from clients to the compositor. A prime example is - * a video player with decorations and video in separate wl_surface - * objects. This should allow the compositor to pass YUV video buffer - * processing to dedicated overlay hardware when possible. - * @section page_iface_wl_subcompositor_api API - * See @ref iface_wl_subcompositor. - */ -/** - * @defgroup iface_wl_subcompositor The wl_subcompositor interface - * - * The global interface exposing sub-surface compositing capabilities. - * A wl_surface, that has sub-surfaces associated, is called the - * parent surface. Sub-surfaces can be arbitrarily nested and create - * a tree of sub-surfaces. - * - * The root surface in a tree of sub-surfaces is the main - * surface. The main surface cannot be a sub-surface, because - * sub-surfaces must always have a parent. - * - * A main surface with its sub-surfaces forms a (compound) window. - * For window management purposes, this set of wl_surface objects is - * to be considered as a single window, and it should also behave as - * such. - * - * The aim of sub-surfaces is to offload some of the compositing work - * within a window from clients to the compositor. A prime example is - * a video player with decorations and video in separate wl_surface - * objects. This should allow the compositor to pass YUV video buffer - * processing to dedicated overlay hardware when possible. - */ -extern const struct wl_interface wl_subcompositor_interface; -#endif -#ifndef WL_SUBSURFACE_INTERFACE -#define WL_SUBSURFACE_INTERFACE -/** - * @page page_iface_wl_subsurface wl_subsurface - * @section page_iface_wl_subsurface_desc Description - * - * An additional interface to a wl_surface object, which has been - * made a sub-surface. A sub-surface has one parent surface. A - * sub-surface's size and position are not limited to that of the parent. - * Particularly, a sub-surface is not automatically clipped to its - * parent's area. - * - * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied - * and the parent surface is mapped. The order of which one happens - * first is irrelevant. A sub-surface is hidden if the parent becomes - * hidden, or if a NULL wl_buffer is applied. These rules apply - * recursively through the tree of surfaces. - * - * The behaviour of a wl_surface.commit request on a sub-surface - * depends on the sub-surface's mode. The possible modes are - * synchronized and desynchronized, see methods - * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized - * mode caches the wl_surface state to be applied when the parent's - * state gets applied, and desynchronized mode applies the pending - * wl_surface state directly. A sub-surface is initially in the - * synchronized mode. - * - * Sub-surfaces also have another kind of state, which is managed by - * wl_subsurface requests, as opposed to wl_surface requests. This - * state includes the sub-surface position relative to the parent - * surface (wl_subsurface.set_position), and the stacking order of - * the parent and its sub-surfaces (wl_subsurface.place_above and - * .place_below). This state is applied when the parent surface's - * wl_surface state is applied, regardless of the sub-surface's mode. - * As the exception, set_sync and set_desync are effective immediately. - * - * The main surface can be thought to be always in desynchronized mode, - * since it does not have a parent in the sub-surfaces sense. - * - * Even if a sub-surface is in desynchronized mode, it will behave as - * in synchronized mode, if its parent surface behaves as in - * synchronized mode. This rule is applied recursively throughout the - * tree of surfaces. This means, that one can set a sub-surface into - * synchronized mode, and then assume that all its child and grand-child - * sub-surfaces are synchronized, too, without explicitly setting them. - * - * Destroying a sub-surface takes effect immediately. If you need to - * synchronize the removal of a sub-surface to the parent surface update, - * unmap the sub-surface first by attaching a NULL wl_buffer, update parent, - * and then destroy the sub-surface. - * - * If the parent wl_surface object is destroyed, the sub-surface is - * unmapped. - * - * A sub-surface never has the keyboard focus of any seat. - * - * The wl_surface.offset request is ignored: clients must use set_position - * instead to move the sub-surface. - * @section page_iface_wl_subsurface_api API - * See @ref iface_wl_subsurface. - */ -/** - * @defgroup iface_wl_subsurface The wl_subsurface interface - * - * An additional interface to a wl_surface object, which has been - * made a sub-surface. A sub-surface has one parent surface. A - * sub-surface's size and position are not limited to that of the parent. - * Particularly, a sub-surface is not automatically clipped to its - * parent's area. - * - * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied - * and the parent surface is mapped. The order of which one happens - * first is irrelevant. A sub-surface is hidden if the parent becomes - * hidden, or if a NULL wl_buffer is applied. These rules apply - * recursively through the tree of surfaces. - * - * The behaviour of a wl_surface.commit request on a sub-surface - * depends on the sub-surface's mode. The possible modes are - * synchronized and desynchronized, see methods - * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized - * mode caches the wl_surface state to be applied when the parent's - * state gets applied, and desynchronized mode applies the pending - * wl_surface state directly. A sub-surface is initially in the - * synchronized mode. - * - * Sub-surfaces also have another kind of state, which is managed by - * wl_subsurface requests, as opposed to wl_surface requests. This - * state includes the sub-surface position relative to the parent - * surface (wl_subsurface.set_position), and the stacking order of - * the parent and its sub-surfaces (wl_subsurface.place_above and - * .place_below). This state is applied when the parent surface's - * wl_surface state is applied, regardless of the sub-surface's mode. - * As the exception, set_sync and set_desync are effective immediately. - * - * The main surface can be thought to be always in desynchronized mode, - * since it does not have a parent in the sub-surfaces sense. - * - * Even if a sub-surface is in desynchronized mode, it will behave as - * in synchronized mode, if its parent surface behaves as in - * synchronized mode. This rule is applied recursively throughout the - * tree of surfaces. This means, that one can set a sub-surface into - * synchronized mode, and then assume that all its child and grand-child - * sub-surfaces are synchronized, too, without explicitly setting them. - * - * Destroying a sub-surface takes effect immediately. If you need to - * synchronize the removal of a sub-surface to the parent surface update, - * unmap the sub-surface first by attaching a NULL wl_buffer, update parent, - * and then destroy the sub-surface. - * - * If the parent wl_surface object is destroyed, the sub-surface is - * unmapped. - * - * A sub-surface never has the keyboard focus of any seat. - * - * The wl_surface.offset request is ignored: clients must use set_position - * instead to move the sub-surface. - */ -extern const struct wl_interface wl_subsurface_interface; -#endif -#ifndef WL_FIXES_INTERFACE -#define WL_FIXES_INTERFACE -/** - * @page page_iface_wl_fixes wl_fixes - * @section page_iface_wl_fixes_desc Description - * - * This global fixes problems with other core-protocol interfaces that - * cannot be fixed in these interfaces themselves. - * @section page_iface_wl_fixes_api API - * See @ref iface_wl_fixes. - */ -/** - * @defgroup iface_wl_fixes The wl_fixes interface - * - * This global fixes problems with other core-protocol interfaces that - * cannot be fixed in these interfaces themselves. - */ -extern const struct wl_interface wl_fixes_interface; -#endif - -#ifndef WL_DISPLAY_ERROR_ENUM -#define WL_DISPLAY_ERROR_ENUM -/** - * @ingroup iface_wl_display - * global error values - * - * These errors are global and can be emitted in response to any - * server request. - */ -enum wl_display_error { - /** - * server couldn't find object - */ - WL_DISPLAY_ERROR_INVALID_OBJECT = 0, - /** - * method doesn't exist on the specified interface or malformed request - */ - WL_DISPLAY_ERROR_INVALID_METHOD = 1, - /** - * server is out of memory - */ - WL_DISPLAY_ERROR_NO_MEMORY = 2, - /** - * implementation error in compositor - */ - WL_DISPLAY_ERROR_IMPLEMENTATION = 3, -}; -#endif /* WL_DISPLAY_ERROR_ENUM */ - -/** - * @ingroup iface_wl_display - * @struct wl_display_listener - */ -struct wl_display_listener { - /** - * fatal error event - * - * The error event is sent out when a fatal (non-recoverable) - * error has occurred. The object_id argument is the object where - * the error occurred, most often in response to a request to that - * object. The code identifies the error and is defined by the - * object interface. As such, each interface defines its own set of - * error codes. The message is a brief description of the error, - * for (debugging) convenience. - * @param object_id object where the error occurred - * @param code error code - * @param message error description - */ - void (*error)(void *data, - struct wl_display *wl_display, - void *object_id, - uint32_t code, - const char *message); - /** - * acknowledge object ID deletion - * - * This event is used internally by the object ID management - * logic. When a client deletes an object that it had created, the - * server will send this event to acknowledge that it has seen the - * delete request. When the client receives this event, it will - * know that it can safely reuse the object ID. - * @param id deleted object ID - */ - void (*delete_id)(void *data, - struct wl_display *wl_display, - uint32_t id); -}; - -/** - * @ingroup iface_wl_display - */ -static inline int -wl_display_add_listener(struct wl_display *wl_display, - const struct wl_display_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_display, - (void (**)(void)) listener, data); -} - -#define WL_DISPLAY_SYNC 0 -#define WL_DISPLAY_GET_REGISTRY 1 - -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_ERROR_SINCE_VERSION 1 -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_SYNC_SINCE_VERSION 1 -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 - -/** @ingroup iface_wl_display */ -static inline void -wl_display_set_user_data(struct wl_display *wl_display, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data); -} - -/** @ingroup iface_wl_display */ -static inline void * -wl_display_get_user_data(struct wl_display *wl_display) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_display); -} - -static inline uint32_t -wl_display_get_version(struct wl_display *wl_display) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_display); -} - -/** - * @ingroup iface_wl_display - * - * The sync request asks the server to emit the 'done' event - * on the returned wl_callback object. Since requests are - * handled in-order and events are delivered in-order, this can - * be used as a barrier to ensure all previous requests and the - * resulting events have been handled. - * - * The object returned by this request will be destroyed by the - * compositor after the callback is fired and as such the client must not - * attempt to use it after that point. - * - * The callback_data passed in the callback is undefined and should be ignored. - */ -static inline struct wl_callback * -wl_display_sync(struct wl_display *wl_display) -{ - struct wl_proxy *callback; - - callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, - WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); - - return (struct wl_callback *) callback; -} - -/** - * @ingroup iface_wl_display - * - * This request creates a registry object that allows the client - * to list and bind the global objects available from the - * compositor. - * - * It should be noted that the server side resources consumed in - * response to a get_registry request can only be released when the - * client disconnects, not when the client side proxy is destroyed. - * Therefore, clients should invoke get_registry as infrequently as - * possible to avoid wasting memory. - */ -static inline struct wl_registry * -wl_display_get_registry(struct wl_display *wl_display) -{ - struct wl_proxy *registry; - - registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, - WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); - - return (struct wl_registry *) registry; -} - -/** - * @ingroup iface_wl_registry - * @struct wl_registry_listener - */ -struct wl_registry_listener { - /** - * announce global object - * - * Notify the client of global objects. - * - * The event notifies the client that a global object with the - * given name is now available, and it implements the given version - * of the given interface. - * @param name numeric name of the global object - * @param interface interface implemented by the object - * @param version interface version - */ - void (*global)(void *data, - struct wl_registry *wl_registry, - uint32_t name, - const char *interface, - uint32_t version); - /** - * announce removal of global object - * - * Notify the client of removed global objects. - * - * This event notifies the client that the global identified by - * name is no longer available. If the client bound to the global - * using the bind request, the client should now destroy that - * object. - * - * The object remains valid and requests to the object will be - * ignored until the client destroys it, to avoid races between the - * global going away and a client sending a request to it. - * @param name numeric name of the global object - */ - void (*global_remove)(void *data, - struct wl_registry *wl_registry, - uint32_t name); -}; - -/** - * @ingroup iface_wl_registry - */ -static inline int -wl_registry_add_listener(struct wl_registry *wl_registry, - const struct wl_registry_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_registry, - (void (**)(void)) listener, data); -} - -#define WL_REGISTRY_BIND 0 - -/** - * @ingroup iface_wl_registry - */ -#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_registry - */ -#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_registry - */ -#define WL_REGISTRY_BIND_SINCE_VERSION 1 - -/** @ingroup iface_wl_registry */ -static inline void -wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data); -} - -/** @ingroup iface_wl_registry */ -static inline void * -wl_registry_get_user_data(struct wl_registry *wl_registry) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_registry); -} - -static inline uint32_t -wl_registry_get_version(struct wl_registry *wl_registry) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_registry); -} - -/** @ingroup iface_wl_registry */ -static inline void -wl_registry_destroy(struct wl_registry *wl_registry) -{ - wl_proxy_destroy((struct wl_proxy *) wl_registry); -} - -/** - * @ingroup iface_wl_registry - * - * Binds a new, client-created object to the server using the - * specified name as the identifier. - */ -static inline void * -wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry, - WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL); - - return (void *) id; -} - -/** - * @ingroup iface_wl_callback - * @struct wl_callback_listener - */ -struct wl_callback_listener { - /** - * done event - * - * Notify the client when the related request is done. - * @param callback_data request-specific data for the callback - */ - void (*done)(void *data, - struct wl_callback *wl_callback, - uint32_t callback_data); -}; - -/** - * @ingroup iface_wl_callback - */ -static inline int -wl_callback_add_listener(struct wl_callback *wl_callback, - const struct wl_callback_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_callback, - (void (**)(void)) listener, data); -} - -/** - * @ingroup iface_wl_callback - */ -#define WL_CALLBACK_DONE_SINCE_VERSION 1 - - -/** @ingroup iface_wl_callback */ -static inline void -wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data); -} - -/** @ingroup iface_wl_callback */ -static inline void * -wl_callback_get_user_data(struct wl_callback *wl_callback) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_callback); -} - -static inline uint32_t -wl_callback_get_version(struct wl_callback *wl_callback) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_callback); -} - -/** @ingroup iface_wl_callback */ -static inline void -wl_callback_destroy(struct wl_callback *wl_callback) -{ - wl_proxy_destroy((struct wl_proxy *) wl_callback); -} - -#define WL_COMPOSITOR_CREATE_SURFACE 0 -#define WL_COMPOSITOR_CREATE_REGION 1 - - -/** - * @ingroup iface_wl_compositor - */ -#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_compositor - */ -#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 - -/** @ingroup iface_wl_compositor */ -static inline void -wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data); -} - -/** @ingroup iface_wl_compositor */ -static inline void * -wl_compositor_get_user_data(struct wl_compositor *wl_compositor) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor); -} - -static inline uint32_t -wl_compositor_get_version(struct wl_compositor *wl_compositor) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_compositor); -} - -/** @ingroup iface_wl_compositor */ -static inline void -wl_compositor_destroy(struct wl_compositor *wl_compositor) -{ - wl_proxy_destroy((struct wl_proxy *) wl_compositor); -} - -/** - * @ingroup iface_wl_compositor - * - * Ask the compositor to create a new surface. - */ -static inline struct wl_surface * -wl_compositor_create_surface(struct wl_compositor *wl_compositor) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); - - return (struct wl_surface *) id; -} - -/** - * @ingroup iface_wl_compositor - * - * Ask the compositor to create a new region. - */ -static inline struct wl_region * -wl_compositor_create_region(struct wl_compositor *wl_compositor) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); - - return (struct wl_region *) id; -} - -#define WL_SHM_POOL_CREATE_BUFFER 0 -#define WL_SHM_POOL_DESTROY 1 -#define WL_SHM_POOL_RESIZE 2 - - -/** - * @ingroup iface_wl_shm_pool - */ -#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shm_pool - */ -#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shm_pool - */ -#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 - -/** @ingroup iface_wl_shm_pool */ -static inline void -wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data); -} - -/** @ingroup iface_wl_shm_pool */ -static inline void * -wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool); -} - -static inline uint32_t -wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool); -} - -/** - * @ingroup iface_wl_shm_pool - * - * Create a wl_buffer object from the pool. - * - * The buffer is created offset bytes into the pool and has - * width and height as specified. The stride argument specifies - * the number of bytes from the beginning of one row to the beginning - * of the next. The format is the pixel format of the buffer and - * must be one of those advertised through the wl_shm.format event. - * - * A buffer will keep a reference to the pool it was created from - * so it is valid to destroy the pool immediately after creating - * a buffer from it. - */ -static inline struct wl_buffer * -wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format); - - return (struct wl_buffer *) id; -} - -/** - * @ingroup iface_wl_shm_pool - * - * Destroy the shared memory pool. - * - * The mmapped memory will be released when all - * buffers that have been created from this pool - * are gone. - */ -static inline void -wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_shm_pool - * - * This request will cause the server to remap the backing memory - * for the pool from the file descriptor passed when the pool was - * created, but using the new size. This request can only be - * used to make the pool bigger. - * - * This request only changes the amount of bytes that are mmapped - * by the server and does not touch the file corresponding to the - * file descriptor passed at creation time. It is the client's - * responsibility to ensure that the file is at least as big as - * the new pool size. - */ -static inline void -wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size); -} - -#ifndef WL_SHM_ERROR_ENUM -#define WL_SHM_ERROR_ENUM -/** - * @ingroup iface_wl_shm - * wl_shm error values - * - * These errors can be emitted in response to wl_shm requests. - */ -enum wl_shm_error { - /** - * buffer format is not known - */ - WL_SHM_ERROR_INVALID_FORMAT = 0, - /** - * invalid size or stride during pool or buffer creation - */ - WL_SHM_ERROR_INVALID_STRIDE = 1, - /** - * mmapping the file descriptor failed - */ - WL_SHM_ERROR_INVALID_FD = 2, -}; -#endif /* WL_SHM_ERROR_ENUM */ - -#ifndef WL_SHM_FORMAT_ENUM -#define WL_SHM_FORMAT_ENUM -/** - * @ingroup iface_wl_shm - * pixel formats - * - * This describes the memory layout of an individual pixel. - * - * All renderers should support argb8888 and xrgb8888 but any other - * formats are optional and may not be supported by the particular - * renderer in use. - * - * The drm format codes match the macros defined in drm_fourcc.h, except - * argb8888 and xrgb8888. The formats actually supported by the compositor - * will be reported by the format event. - * - * For all wl_shm formats and unless specified in another protocol - * extension, pre-multiplied alpha is used for pixel values. - */ -enum wl_shm_format { - /** - * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian - */ - WL_SHM_FORMAT_ARGB8888 = 0, - /** - * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XRGB8888 = 1, - /** - * 8-bit color index format, [7:0] C - */ - WL_SHM_FORMAT_C8 = 0x20203843, - /** - * 8-bit RGB format, [7:0] R:G:B 3:3:2 - */ - WL_SHM_FORMAT_RGB332 = 0x38424752, - /** - * 8-bit BGR format, [7:0] B:G:R 2:3:3 - */ - WL_SHM_FORMAT_BGR233 = 0x38524742, - /** - * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian - */ - WL_SHM_FORMAT_XRGB4444 = 0x32315258, - /** - * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian - */ - WL_SHM_FORMAT_XBGR4444 = 0x32314258, - /** - * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian - */ - WL_SHM_FORMAT_RGBX4444 = 0x32315852, - /** - * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian - */ - WL_SHM_FORMAT_BGRX4444 = 0x32315842, - /** - * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian - */ - WL_SHM_FORMAT_ARGB4444 = 0x32315241, - /** - * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian - */ - WL_SHM_FORMAT_ABGR4444 = 0x32314241, - /** - * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian - */ - WL_SHM_FORMAT_RGBA4444 = 0x32314152, - /** - * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian - */ - WL_SHM_FORMAT_BGRA4444 = 0x32314142, - /** - * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian - */ - WL_SHM_FORMAT_XRGB1555 = 0x35315258, - /** - * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian - */ - WL_SHM_FORMAT_XBGR1555 = 0x35314258, - /** - * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian - */ - WL_SHM_FORMAT_RGBX5551 = 0x35315852, - /** - * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian - */ - WL_SHM_FORMAT_BGRX5551 = 0x35315842, - /** - * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian - */ - WL_SHM_FORMAT_ARGB1555 = 0x35315241, - /** - * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian - */ - WL_SHM_FORMAT_ABGR1555 = 0x35314241, - /** - * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian - */ - WL_SHM_FORMAT_RGBA5551 = 0x35314152, - /** - * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian - */ - WL_SHM_FORMAT_BGRA5551 = 0x35314142, - /** - * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian - */ - WL_SHM_FORMAT_RGB565 = 0x36314752, - /** - * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian - */ - WL_SHM_FORMAT_BGR565 = 0x36314742, - /** - * 24-bit RGB format, [23:0] R:G:B little endian - */ - WL_SHM_FORMAT_RGB888 = 0x34324752, - /** - * 24-bit BGR format, [23:0] B:G:R little endian - */ - WL_SHM_FORMAT_BGR888 = 0x34324742, - /** - * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XBGR8888 = 0x34324258, - /** - * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian - */ - WL_SHM_FORMAT_RGBX8888 = 0x34325852, - /** - * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian - */ - WL_SHM_FORMAT_BGRX8888 = 0x34325842, - /** - * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian - */ - WL_SHM_FORMAT_ABGR8888 = 0x34324241, - /** - * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian - */ - WL_SHM_FORMAT_RGBA8888 = 0x34324152, - /** - * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian - */ - WL_SHM_FORMAT_BGRA8888 = 0x34324142, - /** - * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian - */ - WL_SHM_FORMAT_XRGB2101010 = 0x30335258, - /** - * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian - */ - WL_SHM_FORMAT_XBGR2101010 = 0x30334258, - /** - * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian - */ - WL_SHM_FORMAT_RGBX1010102 = 0x30335852, - /** - * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian - */ - WL_SHM_FORMAT_BGRX1010102 = 0x30335842, - /** - * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian - */ - WL_SHM_FORMAT_ARGB2101010 = 0x30335241, - /** - * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian - */ - WL_SHM_FORMAT_ABGR2101010 = 0x30334241, - /** - * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian - */ - WL_SHM_FORMAT_RGBA1010102 = 0x30334152, - /** - * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian - */ - WL_SHM_FORMAT_BGRA1010102 = 0x30334142, - /** - * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_YUYV = 0x56595559, - /** - * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_YVYU = 0x55595659, - /** - * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_UYVY = 0x59565955, - /** - * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_VYUY = 0x59555956, - /** - * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian - */ - WL_SHM_FORMAT_AYUV = 0x56555941, - /** - * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV12 = 0x3231564e, - /** - * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane - */ - WL_SHM_FORMAT_NV21 = 0x3132564e, - /** - * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV16 = 0x3631564e, - /** - * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane - */ - WL_SHM_FORMAT_NV61 = 0x3136564e, - /** - * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV410 = 0x39565559, - /** - * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU410 = 0x39555659, - /** - * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV411 = 0x31315559, - /** - * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU411 = 0x31315659, - /** - * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV420 = 0x32315559, - /** - * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU420 = 0x32315659, - /** - * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV422 = 0x36315559, - /** - * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU422 = 0x36315659, - /** - * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV444 = 0x34325559, - /** - * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU444 = 0x34325659, - /** - * [7:0] R - */ - WL_SHM_FORMAT_R8 = 0x20203852, - /** - * [15:0] R little endian - */ - WL_SHM_FORMAT_R16 = 0x20363152, - /** - * [15:0] R:G 8:8 little endian - */ - WL_SHM_FORMAT_RG88 = 0x38384752, - /** - * [15:0] G:R 8:8 little endian - */ - WL_SHM_FORMAT_GR88 = 0x38385247, - /** - * [31:0] R:G 16:16 little endian - */ - WL_SHM_FORMAT_RG1616 = 0x32334752, - /** - * [31:0] G:R 16:16 little endian - */ - WL_SHM_FORMAT_GR1616 = 0x32335247, - /** - * [63:0] x:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XRGB16161616F = 0x48345258, - /** - * [63:0] x:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XBGR16161616F = 0x48344258, - /** - * [63:0] A:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ARGB16161616F = 0x48345241, - /** - * [63:0] A:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ABGR16161616F = 0x48344241, - /** - * [31:0] X:Y:Cb:Cr 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XYUV8888 = 0x56555958, - /** - * [23:0] Cr:Cb:Y 8:8:8 little endian - */ - WL_SHM_FORMAT_VUY888 = 0x34325556, - /** - * Y followed by U then V, 10:10:10. Non-linear modifier only - */ - WL_SHM_FORMAT_VUY101010 = 0x30335556, - /** - * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels - */ - WL_SHM_FORMAT_Y210 = 0x30313259, - /** - * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels - */ - WL_SHM_FORMAT_Y212 = 0x32313259, - /** - * [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels - */ - WL_SHM_FORMAT_Y216 = 0x36313259, - /** - * [31:0] A:Cr:Y:Cb 2:10:10:10 little endian - */ - WL_SHM_FORMAT_Y410 = 0x30313459, - /** - * [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian - */ - WL_SHM_FORMAT_Y412 = 0x32313459, - /** - * [63:0] A:Cr:Y:Cb 16:16:16:16 little endian - */ - WL_SHM_FORMAT_Y416 = 0x36313459, - /** - * [31:0] X:Cr:Y:Cb 2:10:10:10 little endian - */ - WL_SHM_FORMAT_XVYU2101010 = 0x30335658, - /** - * [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian - */ - WL_SHM_FORMAT_XVYU12_16161616 = 0x36335658, - /** - * [63:0] X:Cr:Y:Cb 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XVYU16161616 = 0x38345658, - /** - * [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian - */ - WL_SHM_FORMAT_Y0L0 = 0x304c3059, - /** - * [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian - */ - WL_SHM_FORMAT_X0L0 = 0x304c3058, - /** - * [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian - */ - WL_SHM_FORMAT_Y0L2 = 0x324c3059, - /** - * [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian - */ - WL_SHM_FORMAT_X0L2 = 0x324c3058, - WL_SHM_FORMAT_YUV420_8BIT = 0x38305559, - WL_SHM_FORMAT_YUV420_10BIT = 0x30315559, - WL_SHM_FORMAT_XRGB8888_A8 = 0x38415258, - WL_SHM_FORMAT_XBGR8888_A8 = 0x38414258, - WL_SHM_FORMAT_RGBX8888_A8 = 0x38415852, - WL_SHM_FORMAT_BGRX8888_A8 = 0x38415842, - WL_SHM_FORMAT_RGB888_A8 = 0x38413852, - WL_SHM_FORMAT_BGR888_A8 = 0x38413842, - WL_SHM_FORMAT_RGB565_A8 = 0x38413552, - WL_SHM_FORMAT_BGR565_A8 = 0x38413542, - /** - * non-subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV24 = 0x3432564e, - /** - * non-subsampled Cb:Cr plane - */ - WL_SHM_FORMAT_NV42 = 0x3234564e, - /** - * 2x1 subsampled Cr:Cb plane, 10 bit per channel - */ - WL_SHM_FORMAT_P210 = 0x30313250, - /** - * 2x2 subsampled Cr:Cb plane 10 bits per channel - */ - WL_SHM_FORMAT_P010 = 0x30313050, - /** - * 2x2 subsampled Cr:Cb plane 12 bits per channel - */ - WL_SHM_FORMAT_P012 = 0x32313050, - /** - * 2x2 subsampled Cr:Cb plane 16 bits per channel - */ - WL_SHM_FORMAT_P016 = 0x36313050, - /** - * [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian - */ - WL_SHM_FORMAT_AXBXGXRX106106106106 = 0x30314241, - /** - * 2x2 subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV15 = 0x3531564e, - WL_SHM_FORMAT_Q410 = 0x30313451, - WL_SHM_FORMAT_Q401 = 0x31303451, - /** - * [63:0] x:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XRGB16161616 = 0x38345258, - /** - * [63:0] x:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XBGR16161616 = 0x38344258, - /** - * [63:0] A:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ARGB16161616 = 0x38345241, - /** - * [63:0] A:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ABGR16161616 = 0x38344241, - /** - * [7:0] C0:C1:C2:C3:C4:C5:C6:C7 1:1:1:1:1:1:1:1 eight pixels/byte - */ - WL_SHM_FORMAT_C1 = 0x20203143, - /** - * [7:0] C0:C1:C2:C3 2:2:2:2 four pixels/byte - */ - WL_SHM_FORMAT_C2 = 0x20203243, - /** - * [7:0] C0:C1 4:4 two pixels/byte - */ - WL_SHM_FORMAT_C4 = 0x20203443, - /** - * [7:0] D0:D1:D2:D3:D4:D5:D6:D7 1:1:1:1:1:1:1:1 eight pixels/byte - */ - WL_SHM_FORMAT_D1 = 0x20203144, - /** - * [7:0] D0:D1:D2:D3 2:2:2:2 four pixels/byte - */ - WL_SHM_FORMAT_D2 = 0x20203244, - /** - * [7:0] D0:D1 4:4 two pixels/byte - */ - WL_SHM_FORMAT_D4 = 0x20203444, - /** - * [7:0] D - */ - WL_SHM_FORMAT_D8 = 0x20203844, - /** - * [7:0] R0:R1:R2:R3:R4:R5:R6:R7 1:1:1:1:1:1:1:1 eight pixels/byte - */ - WL_SHM_FORMAT_R1 = 0x20203152, - /** - * [7:0] R0:R1:R2:R3 2:2:2:2 four pixels/byte - */ - WL_SHM_FORMAT_R2 = 0x20203252, - /** - * [7:0] R0:R1 4:4 two pixels/byte - */ - WL_SHM_FORMAT_R4 = 0x20203452, - /** - * [15:0] x:R 6:10 little endian - */ - WL_SHM_FORMAT_R10 = 0x20303152, - /** - * [15:0] x:R 4:12 little endian - */ - WL_SHM_FORMAT_R12 = 0x20323152, - /** - * [31:0] A:Cr:Cb:Y 8:8:8:8 little endian - */ - WL_SHM_FORMAT_AVUY8888 = 0x59555641, - /** - * [31:0] X:Cr:Cb:Y 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XVUY8888 = 0x59555658, - /** - * 2x2 subsampled Cr:Cb plane 10 bits per channel packed - */ - WL_SHM_FORMAT_P030 = 0x30333050, -}; -#endif /* WL_SHM_FORMAT_ENUM */ - -/** - * @ingroup iface_wl_shm - * @struct wl_shm_listener - */ -struct wl_shm_listener { - /** - * pixel format description - * - * Informs the client about a valid pixel format that can be used - * for buffers. Known formats include argb8888 and xrgb8888. - * @param format buffer pixel format - */ - void (*format)(void *data, - struct wl_shm *wl_shm, - uint32_t format); -}; - -/** - * @ingroup iface_wl_shm - */ -static inline int -wl_shm_add_listener(struct wl_shm *wl_shm, - const struct wl_shm_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_shm, - (void (**)(void)) listener, data); -} - -#define WL_SHM_CREATE_POOL 0 -#define WL_SHM_RELEASE 1 - -/** - * @ingroup iface_wl_shm - */ -#define WL_SHM_FORMAT_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_shm - */ -#define WL_SHM_CREATE_POOL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shm - */ -#define WL_SHM_RELEASE_SINCE_VERSION 2 - -/** @ingroup iface_wl_shm */ -static inline void -wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data); -} - -/** @ingroup iface_wl_shm */ -static inline void * -wl_shm_get_user_data(struct wl_shm *wl_shm) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shm); -} - -static inline uint32_t -wl_shm_get_version(struct wl_shm *wl_shm) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shm); -} - -/** @ingroup iface_wl_shm */ -static inline void -wl_shm_destroy(struct wl_shm *wl_shm) -{ - wl_proxy_destroy((struct wl_proxy *) wl_shm); -} - -/** - * @ingroup iface_wl_shm - * - * Create a new wl_shm_pool object. - * - * The pool can be used to create shared memory based buffer - * objects. The server will mmap size bytes of the passed file - * descriptor, to use as backing memory for the pool. - */ -static inline struct wl_shm_pool * -wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm, - WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size); - - return (struct wl_shm_pool *) id; -} - -/** - * @ingroup iface_wl_shm - * - * Using this request a client can tell the server that it is not going to - * use the shm object anymore. - * - * Objects created via this interface remain unaffected. - */ -static inline void -wl_shm_release(struct wl_shm *wl_shm) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shm, - WL_SHM_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_buffer - * @struct wl_buffer_listener - */ -struct wl_buffer_listener { - /** - * compositor releases buffer - * - * Sent when this wl_buffer is no longer used by the compositor. - * The client is now free to reuse or destroy this buffer and its - * backing storage. - * - * If a client receives a release event before the frame callback - * requested in the same wl_surface.commit that attaches this - * wl_buffer to a surface, then the client is immediately free to - * reuse the buffer and its backing storage, and does not need a - * second buffer for the next surface content update. Typically - * this is possible, when the compositor maintains a copy of the - * wl_surface contents, e.g. as a GL texture. This is an important - * optimization for GL(ES) compositors with wl_shm clients. - */ - void (*release)(void *data, - struct wl_buffer *wl_buffer); -}; - -/** - * @ingroup iface_wl_buffer - */ -static inline int -wl_buffer_add_listener(struct wl_buffer *wl_buffer, - const struct wl_buffer_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_buffer, - (void (**)(void)) listener, data); -} - -#define WL_BUFFER_DESTROY 0 - -/** - * @ingroup iface_wl_buffer - */ -#define WL_BUFFER_RELEASE_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_buffer - */ -#define WL_BUFFER_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_wl_buffer */ -static inline void -wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data); -} - -/** @ingroup iface_wl_buffer */ -static inline void * -wl_buffer_get_user_data(struct wl_buffer *wl_buffer) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer); -} - -static inline uint32_t -wl_buffer_get_version(struct wl_buffer *wl_buffer) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_buffer); -} - -/** - * @ingroup iface_wl_buffer - * - * Destroy a buffer. If and how you need to release the backing - * storage is defined by the buffer factory interface. - * - * For possible side-effects to a surface, see wl_surface.attach. - */ -static inline void -wl_buffer_destroy(struct wl_buffer *wl_buffer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer, - WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_DATA_OFFER_ERROR_ENUM -#define WL_DATA_OFFER_ERROR_ENUM -enum wl_data_offer_error { - /** - * finish request was called untimely - */ - WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, - /** - * action mask contains invalid values - */ - WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, - /** - * action argument has an invalid value - */ - WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, - /** - * offer doesn't accept this request - */ - WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, -}; -#endif /* WL_DATA_OFFER_ERROR_ENUM */ - -/** - * @ingroup iface_wl_data_offer - * @struct wl_data_offer_listener - */ -struct wl_data_offer_listener { - /** - * advertise offered mime type - * - * Sent immediately after creating the wl_data_offer object. One - * event per offered mime type. - * @param mime_type offered mime type - */ - void (*offer)(void *data, - struct wl_data_offer *wl_data_offer, - const char *mime_type); - /** - * notify the source-side available actions - * - * This event indicates the actions offered by the data source. - * It will be sent immediately after creating the wl_data_offer - * object, or anytime the source side changes its offered actions - * through wl_data_source.set_actions. - * @param source_actions actions offered by the data source - * @since 3 - */ - void (*source_actions)(void *data, - struct wl_data_offer *wl_data_offer, - uint32_t source_actions); - /** - * notify the selected action - * - * This event indicates the action selected by the compositor - * after matching the source/destination side actions. Only one - * action (or none) will be offered here. - * - * This event can be emitted multiple times during the - * drag-and-drop operation in response to destination side action - * changes through wl_data_offer.set_actions. - * - * This event will no longer be emitted after wl_data_device.drop - * happened on the drag-and-drop destination, the client must honor - * the last action received, or the last preferred one set through - * wl_data_offer.set_actions when handling an "ask" action. - * - * Compositors may also change the selected action on the fly, - * mainly in response to keyboard modifier changes during the - * drag-and-drop operation. - * - * The most recent action received is always the valid one. Prior - * to receiving wl_data_device.drop, the chosen action may change - * (e.g. due to keyboard modifiers being pressed). At the time of - * receiving wl_data_device.drop the drag-and-drop destination must - * honor the last action received. - * - * Action changes may still happen after wl_data_device.drop, - * especially on "ask" actions, where the drag-and-drop destination - * may choose another action afterwards. Action changes happening - * at this stage are always the result of inter-client negotiation, - * the compositor shall no longer be able to induce a different - * action. - * - * Upon "ask" actions, it is expected that the drag-and-drop - * destination may potentially choose a different action and/or - * mime type, based on wl_data_offer.source_actions and finally - * chosen by the user (e.g. popping up a menu with the available - * options). The final wl_data_offer.set_actions and - * wl_data_offer.accept requests must happen before the call to - * wl_data_offer.finish. - * @param dnd_action action selected by the compositor - * @since 3 - */ - void (*action)(void *data, - struct wl_data_offer *wl_data_offer, - uint32_t dnd_action); -}; - -/** - * @ingroup iface_wl_data_offer - */ -static inline int -wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer, - const struct wl_data_offer_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer, - (void (**)(void)) listener, data); -} - -#define WL_DATA_OFFER_ACCEPT 0 -#define WL_DATA_OFFER_RECEIVE 1 -#define WL_DATA_OFFER_DESTROY 2 -#define WL_DATA_OFFER_FINISH 3 -#define WL_DATA_OFFER_SET_ACTIONS 4 - -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 - -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 - -/** @ingroup iface_wl_data_offer */ -static inline void -wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data); -} - -/** @ingroup iface_wl_data_offer */ -static inline void * -wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer); -} - -static inline uint32_t -wl_data_offer_get_version(struct wl_data_offer *wl_data_offer) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_offer); -} - -/** - * @ingroup iface_wl_data_offer - * - * Indicate that the client can accept the given mime type, or - * NULL for not accepted. - * - * For objects of version 2 or older, this request is used by the - * client to give feedback whether the client can receive the given - * mime type, or NULL if none is accepted; the feedback does not - * determine whether the drag-and-drop operation succeeds or not. - * - * For objects of version 3 or newer, this request determines the - * final result of the drag-and-drop operation. If the end result - * is that no mime types were accepted, the drag-and-drop operation - * will be cancelled and the corresponding drag source will receive - * wl_data_source.cancelled. Clients may still use this event in - * conjunction with wl_data_source.action for feedback. - */ -static inline void -wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type); -} - -/** - * @ingroup iface_wl_data_offer - * - * To transfer the offered data, the client issues this request - * and indicates the mime type it wants to receive. The transfer - * happens through the passed file descriptor (typically created - * with the pipe system call). The source client writes the data - * in the mime type representation requested and then closes the - * file descriptor. - * - * The receiving client reads from the read end of the pipe until - * EOF and then closes its end, at which point the transfer is - * complete. - * - * This request may happen multiple times for different mime types, - * both before and after wl_data_device.drop. Drag-and-drop destination - * clients may preemptively fetch data or examine it more closely to - * determine acceptance. - */ -static inline void -wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd); -} - -/** - * @ingroup iface_wl_data_offer - * - * Destroy the data offer. - */ -static inline void -wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_data_offer - * - * Notifies the compositor that the drag destination successfully - * finished the drag-and-drop operation. - * - * Upon receiving this request, the compositor will emit - * wl_data_source.dnd_finished on the drag source client. - * - * It is a client error to perform other requests than - * wl_data_offer.destroy after this one. It is also an error to perform - * this request after a NULL mime type has been set in - * wl_data_offer.accept or no action was received through - * wl_data_offer.action. - * - * If wl_data_offer.finish request is received for a non drag and drop - * operation, the invalid_finish protocol error is raised. - */ -static inline void -wl_data_offer_finish(struct wl_data_offer *wl_data_offer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0); -} - -/** - * @ingroup iface_wl_data_offer - * - * Sets the actions that the destination side client supports for - * this operation. This request may trigger the emission of - * wl_data_source.action and wl_data_offer.action events if the compositor - * needs to change the selected action. - * - * This request can be called multiple times throughout the - * drag-and-drop operation, typically in response to wl_data_device.enter - * or wl_data_device.motion events. - * - * This request determines the final result of the drag-and-drop - * operation. If the end result is that no action is accepted, - * the drag source will receive wl_data_source.cancelled. - * - * The dnd_actions argument must contain only values expressed in the - * wl_data_device_manager.dnd_actions enum, and the preferred_action - * argument must only contain one of those values set, otherwise it - * will result in a protocol error. - * - * While managing an "ask" action, the destination drag-and-drop client - * may perform further wl_data_offer.receive requests, and is expected - * to perform one last wl_data_offer.set_actions request with a preferred - * action other than "ask" (and optionally wl_data_offer.accept) before - * requesting wl_data_offer.finish, in order to convey the action selected - * by the user. If the preferred action is not in the - * wl_data_offer.source_actions mask, an error will be raised. - * - * If the "ask" action is dismissed (e.g. user cancellation), the client - * is expected to perform wl_data_offer.destroy right away. - * - * This request can only be made on drag-and-drop offers, a protocol error - * will be raised otherwise. - */ -static inline void -wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action); -} - -#ifndef WL_DATA_SOURCE_ERROR_ENUM -#define WL_DATA_SOURCE_ERROR_ENUM -enum wl_data_source_error { - /** - * action mask contains invalid values - */ - WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, - /** - * source doesn't accept this request - */ - WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, -}; -#endif /* WL_DATA_SOURCE_ERROR_ENUM */ - -/** - * @ingroup iface_wl_data_source - * @struct wl_data_source_listener - */ -struct wl_data_source_listener { - /** - * a target accepts an offered mime type - * - * Sent when a target accepts pointer_focus or motion events. If - * a target does not accept any of the offered types, type is NULL. - * - * Used for feedback during drag-and-drop. - * @param mime_type mime type accepted by the target - */ - void (*target)(void *data, - struct wl_data_source *wl_data_source, - const char *mime_type); - /** - * send the data - * - * Request for data from the client. Send the data as the - * specified mime type over the passed file descriptor, then close - * it. - * @param mime_type mime type for the data - * @param fd file descriptor for the data - */ - void (*send)(void *data, - struct wl_data_source *wl_data_source, - const char *mime_type, - int32_t fd); - /** - * selection was cancelled - * - * This data source is no longer valid. There are several reasons - * why this could happen: - * - * - The data source has been replaced by another data source. - - * The drag-and-drop operation was performed, but the drop - * destination did not accept any of the mime types offered through - * wl_data_source.target. - The drag-and-drop operation was - * performed, but the drop destination did not select any of the - * actions present in the mask offered through - * wl_data_source.action. - The drag-and-drop operation was - * performed but didn't happen over a surface. - The compositor - * cancelled the drag-and-drop operation (e.g. compositor dependent - * timeouts to avoid stale drag-and-drop transfers). - * - * The client should clean up and destroy this data source. - * - * For objects of version 2 or older, wl_data_source.cancelled will - * only be emitted if the data source was replaced by another data - * source. - */ - void (*cancelled)(void *data, - struct wl_data_source *wl_data_source); - /** - * the drag-and-drop operation physically finished - * - * The user performed the drop action. This event does not - * indicate acceptance, wl_data_source.cancelled may still be - * emitted afterwards if the drop destination does not accept any - * mime type. - * - * However, this event might however not be received if the - * compositor cancelled the drag-and-drop operation before this - * event could happen. - * - * Note that the data_source may still be used in the future and - * should not be destroyed here. - * @since 3 - */ - void (*dnd_drop_performed)(void *data, - struct wl_data_source *wl_data_source); - /** - * the drag-and-drop operation concluded - * - * The drop destination finished interoperating with this data - * source, so the client is now free to destroy this data source - * and free all associated data. - * - * If the action used to perform the operation was "move", the - * source can now delete the transferred data. - * @since 3 - */ - void (*dnd_finished)(void *data, - struct wl_data_source *wl_data_source); - /** - * notify the selected action - * - * This event indicates the action selected by the compositor - * after matching the source/destination side actions. Only one - * action (or none) will be offered here. - * - * This event can be emitted multiple times during the - * drag-and-drop operation, mainly in response to destination side - * changes through wl_data_offer.set_actions, and as the data - * device enters/leaves surfaces. - * - * It is only possible to receive this event after - * wl_data_source.dnd_drop_performed if the drag-and-drop operation - * ended in an "ask" action, in which case the final - * wl_data_source.action event will happen immediately before - * wl_data_source.dnd_finished. - * - * Compositors may also change the selected action on the fly, - * mainly in response to keyboard modifier changes during the - * drag-and-drop operation. - * - * The most recent action received is always the valid one. The - * chosen action may change alongside negotiation (e.g. an "ask" - * action can turn into a "move" operation), so the effects of the - * final action must always be applied in - * wl_data_offer.dnd_finished. - * - * Clients can trigger cursor surface changes from this point, so - * they reflect the current action. - * @param dnd_action action selected by the compositor - * @since 3 - */ - void (*action)(void *data, - struct wl_data_source *wl_data_source, - uint32_t dnd_action); -}; - -/** - * @ingroup iface_wl_data_source - */ -static inline int -wl_data_source_add_listener(struct wl_data_source *wl_data_source, - const struct wl_data_source_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_data_source, - (void (**)(void)) listener, data); -} - -#define WL_DATA_SOURCE_OFFER 0 -#define WL_DATA_SOURCE_DESTROY 1 -#define WL_DATA_SOURCE_SET_ACTIONS 2 - -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 - -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 - -/** @ingroup iface_wl_data_source */ -static inline void -wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data); -} - -/** @ingroup iface_wl_data_source */ -static inline void * -wl_data_source_get_user_data(struct wl_data_source *wl_data_source) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source); -} - -static inline uint32_t -wl_data_source_get_version(struct wl_data_source *wl_data_source) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_source); -} - -/** - * @ingroup iface_wl_data_source - * - * This request adds a mime type to the set of mime types - * advertised to targets. Can be called several times to offer - * multiple types. - */ -static inline void -wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type); -} - -/** - * @ingroup iface_wl_data_source - * - * Destroy the data source. - */ -static inline void -wl_data_source_destroy(struct wl_data_source *wl_data_source) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_data_source - * - * Sets the actions that the source side client supports for this - * operation. This request may trigger wl_data_source.action and - * wl_data_offer.action events if the compositor needs to change the - * selected action. - * - * The dnd_actions argument must contain only values expressed in the - * wl_data_device_manager.dnd_actions enum, otherwise it will result - * in a protocol error. - * - * This request must be made once only, and can only be made on sources - * used in drag-and-drop, so it must be performed before - * wl_data_device.start_drag. Attempting to use the source other than - * for drag-and-drop will raise a protocol error. - */ -static inline void -wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions); -} - -#ifndef WL_DATA_DEVICE_ERROR_ENUM -#define WL_DATA_DEVICE_ERROR_ENUM -enum wl_data_device_error { - /** - * given wl_surface has another role - */ - WL_DATA_DEVICE_ERROR_ROLE = 0, - /** - * source has already been used - */ - WL_DATA_DEVICE_ERROR_USED_SOURCE = 1, -}; -#endif /* WL_DATA_DEVICE_ERROR_ENUM */ - -/** - * @ingroup iface_wl_data_device - * @struct wl_data_device_listener - */ -struct wl_data_device_listener { - /** - * introduce a new wl_data_offer - * - * The data_offer event introduces a new wl_data_offer object, - * which will subsequently be used in either the data_device.enter - * event (for drag-and-drop) or the data_device.selection event - * (for selections). Immediately following the - * data_device.data_offer event, the new data_offer object will - * send out data_offer.offer events to describe the mime types it - * offers. - * @param id the new data_offer object - */ - void (*data_offer)(void *data, - struct wl_data_device *wl_data_device, - struct wl_data_offer *id); - /** - * initiate drag-and-drop session - * - * This event is sent when an active drag-and-drop pointer enters - * a surface owned by the client. The position of the pointer at - * enter time is provided by the x and y arguments, in - * surface-local coordinates. - * @param serial serial number of the enter event - * @param surface client surface entered - * @param x surface-local x coordinate - * @param y surface-local y coordinate - * @param id source data_offer object - */ - void (*enter)(void *data, - struct wl_data_device *wl_data_device, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t x, - wl_fixed_t y, - struct wl_data_offer *id); - /** - * end drag-and-drop session - * - * This event is sent when the drag-and-drop pointer leaves the - * surface and the session ends. The client must destroy the - * wl_data_offer introduced at enter time at this point. - */ - void (*leave)(void *data, - struct wl_data_device *wl_data_device); - /** - * drag-and-drop session motion - * - * This event is sent when the drag-and-drop pointer moves within - * the currently focused surface. The new position of the pointer - * is provided by the x and y arguments, in surface-local - * coordinates. - * @param time timestamp with millisecond granularity - * @param x surface-local x coordinate - * @param y surface-local y coordinate - */ - void (*motion)(void *data, - struct wl_data_device *wl_data_device, - uint32_t time, - wl_fixed_t x, - wl_fixed_t y); - /** - * end drag-and-drop session successfully - * - * The event is sent when a drag-and-drop operation is ended - * because the implicit grab is removed. - * - * The drag-and-drop destination is expected to honor the last - * action received through wl_data_offer.action, if the resulting - * action is "copy" or "move", the destination can still perform - * wl_data_offer.receive requests, and is expected to end all - * transfers with a wl_data_offer.finish request. - * - * If the resulting action is "ask", the action will not be - * considered final. The drag-and-drop destination is expected to - * perform one last wl_data_offer.set_actions request, or - * wl_data_offer.destroy in order to cancel the operation. - */ - void (*drop)(void *data, - struct wl_data_device *wl_data_device); - /** - * advertise new selection - * - * The selection event is sent out to notify the client of a new - * wl_data_offer for the selection for this device. The - * data_device.data_offer and the data_offer.offer events are sent - * out immediately before this event to introduce the data offer - * object. The selection event is sent to a client immediately - * before receiving keyboard focus and when a new selection is set - * while the client has keyboard focus. The data_offer is valid - * until a new data_offer or NULL is received or until the client - * loses keyboard focus. Switching surface with keyboard focus - * within the same client doesn't mean a new selection will be - * sent. The client must destroy the previous selection data_offer, - * if any, upon receiving this event. - * @param id selection data_offer object - */ - void (*selection)(void *data, - struct wl_data_device *wl_data_device, - struct wl_data_offer *id); -}; - -/** - * @ingroup iface_wl_data_device - */ -static inline int -wl_data_device_add_listener(struct wl_data_device *wl_data_device, - const struct wl_data_device_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_data_device, - (void (**)(void)) listener, data); -} - -#define WL_DATA_DEVICE_START_DRAG 0 -#define WL_DATA_DEVICE_SET_SELECTION 1 -#define WL_DATA_DEVICE_RELEASE 2 - -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 - -/** @ingroup iface_wl_data_device */ -static inline void -wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data); -} - -/** @ingroup iface_wl_data_device */ -static inline void * -wl_data_device_get_user_data(struct wl_data_device *wl_data_device) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device); -} - -static inline uint32_t -wl_data_device_get_version(struct wl_data_device *wl_data_device) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_device); -} - -/** @ingroup iface_wl_data_device */ -static inline void -wl_data_device_destroy(struct wl_data_device *wl_data_device) -{ - wl_proxy_destroy((struct wl_proxy *) wl_data_device); -} - -/** - * @ingroup iface_wl_data_device - * - * This request asks the compositor to start a drag-and-drop - * operation on behalf of the client. - * - * The source argument is the data source that provides the data - * for the eventual data transfer. If source is NULL, enter, leave - * and motion events are sent only to the client that initiated the - * drag and the client is expected to handle the data passing - * internally. If source is destroyed, the drag-and-drop session will be - * cancelled. - * - * The origin surface is the surface where the drag originates and - * the client must have an active implicit grab that matches the - * serial. - * - * The icon surface is an optional (can be NULL) surface that - * provides an icon to be moved around with the cursor. Initially, - * the top-left corner of the icon surface is placed at the cursor - * hotspot, but subsequent wl_surface.offset requests can move the - * relative position. Attach requests must be confirmed with - * wl_surface.commit as usual. The icon surface is given the role of - * a drag-and-drop icon. If the icon surface already has another role, - * it raises a protocol error. - * - * The input region is ignored for wl_surfaces with the role of a - * drag-and-drop icon. - * - * The given source may not be used in any further set_selection or - * start_drag requests. Attempting to reuse a previously-used source - * may send a used_source error. - */ -static inline void -wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial); -} - -/** - * @ingroup iface_wl_data_device - * - * This request asks the compositor to set the selection - * to the data from the source on behalf of the client. - * - * To unset the selection, set the source to NULL. - * - * The given source may not be used in any further set_selection or - * start_drag requests. Attempting to reuse a previously-used source - * may send a used_source error. - */ -static inline void -wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial); -} - -/** - * @ingroup iface_wl_data_device - * - * This request destroys the data device. - */ -static inline void -wl_data_device_release(struct wl_data_device *wl_data_device) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM -#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM -/** - * @ingroup iface_wl_data_device_manager - * drag and drop actions - * - * This is a bitmask of the available/preferred actions in a - * drag-and-drop operation. - * - * In the compositor, the selected action is a result of matching the - * actions offered by the source and destination sides. "action" events - * with a "none" action will be sent to both source and destination if - * there is no match. All further checks will effectively happen on - * (source actions ∩ destination actions). - * - * In addition, compositors may also pick different actions in - * reaction to key modifiers being pressed. One common design that - * is used in major toolkits (and the behavior recommended for - * compositors) is: - * - * - If no modifiers are pressed, the first match (in bit order) - * will be used. - * - Pressing Shift selects "move", if enabled in the mask. - * - Pressing Control selects "copy", if enabled in the mask. - * - * Behavior beyond that is considered implementation-dependent. - * Compositors may for example bind other modifiers (like Alt/Meta) - * or drags initiated with other buttons than BTN_LEFT to specific - * actions (e.g. "ask"). - */ -enum wl_data_device_manager_dnd_action { - /** - * no action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, - /** - * copy action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, - /** - * move action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, - /** - * ask action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, -}; -#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ - -#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0 -#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1 - - -/** - * @ingroup iface_wl_data_device_manager - */ -#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device_manager - */ -#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 - -/** @ingroup iface_wl_data_device_manager */ -static inline void -wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data); -} - -/** @ingroup iface_wl_data_device_manager */ -static inline void * -wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager); -} - -static inline uint32_t -wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager); -} - -/** @ingroup iface_wl_data_device_manager */ -static inline void -wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager) -{ - wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager); -} - -/** - * @ingroup iface_wl_data_device_manager - * - * Create a new data source. - */ -static inline struct wl_data_source * -wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, - WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL); - - return (struct wl_data_source *) id; -} - -/** - * @ingroup iface_wl_data_device_manager - * - * Create a new data device for a given seat. - */ -static inline struct wl_data_device * -wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, - WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat); - - return (struct wl_data_device *) id; -} - -#ifndef WL_SHELL_ERROR_ENUM -#define WL_SHELL_ERROR_ENUM -enum wl_shell_error { - /** - * given wl_surface has another role - */ - WL_SHELL_ERROR_ROLE = 0, -}; -#endif /* WL_SHELL_ERROR_ENUM */ - -#define WL_SHELL_GET_SHELL_SURFACE 0 - - -/** - * @ingroup iface_wl_shell - */ -#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 - -/** @ingroup iface_wl_shell */ -static inline void -wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data); -} - -/** @ingroup iface_wl_shell */ -static inline void * -wl_shell_get_user_data(struct wl_shell *wl_shell) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shell); -} - -static inline uint32_t -wl_shell_get_version(struct wl_shell *wl_shell) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shell); -} - -/** @ingroup iface_wl_shell */ -static inline void -wl_shell_destroy(struct wl_shell *wl_shell) -{ - wl_proxy_destroy((struct wl_proxy *) wl_shell); -} - -/** - * @ingroup iface_wl_shell - * - * Create a shell surface for an existing surface. This gives - * the wl_surface the role of a shell surface. If the wl_surface - * already has another role, it raises a protocol error. - * - * Only one shell surface can be associated with a given surface. - */ -static inline struct wl_shell_surface * -wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell, - WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface); - - return (struct wl_shell_surface *) id; -} - -#ifndef WL_SHELL_SURFACE_RESIZE_ENUM -#define WL_SHELL_SURFACE_RESIZE_ENUM -/** - * @ingroup iface_wl_shell_surface - * edge values for resizing - * - * These values are used to indicate which edge of a surface - * is being dragged in a resize operation. The server may - * use this information to adapt its behavior, e.g. choose - * an appropriate cursor image. - */ -enum wl_shell_surface_resize { - /** - * no edge - */ - WL_SHELL_SURFACE_RESIZE_NONE = 0, - /** - * top edge - */ - WL_SHELL_SURFACE_RESIZE_TOP = 1, - /** - * bottom edge - */ - WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, - /** - * left edge - */ - WL_SHELL_SURFACE_RESIZE_LEFT = 4, - /** - * top and left edges - */ - WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, - /** - * bottom and left edges - */ - WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, - /** - * right edge - */ - WL_SHELL_SURFACE_RESIZE_RIGHT = 8, - /** - * top and right edges - */ - WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, - /** - * bottom and right edges - */ - WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, -}; -#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ - -#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM -#define WL_SHELL_SURFACE_TRANSIENT_ENUM -/** - * @ingroup iface_wl_shell_surface - * details of transient behaviour - * - * These flags specify details of the expected behaviour - * of transient surfaces. Used in the set_transient request. - */ -enum wl_shell_surface_transient { - /** - * do not set keyboard focus - */ - WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, -}; -#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ - -#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM -#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM -/** - * @ingroup iface_wl_shell_surface - * different method to set the surface fullscreen - * - * Hints to indicate to the compositor how to deal with a conflict - * between the dimensions of the surface and the dimensions of the - * output. The compositor is free to ignore this parameter. - */ -enum wl_shell_surface_fullscreen_method { - /** - * no preference, apply default policy - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, - /** - * scale, preserve the surface's aspect ratio and center on output - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, - /** - * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, - /** - * no upscaling, center on output and add black borders to compensate size mismatch - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, -}; -#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ - -/** - * @ingroup iface_wl_shell_surface - * @struct wl_shell_surface_listener - */ -struct wl_shell_surface_listener { - /** - * ping client - * - * Ping a client to check if it is receiving events and sending - * requests. A client is expected to reply with a pong request. - * @param serial serial number of the ping - */ - void (*ping)(void *data, - struct wl_shell_surface *wl_shell_surface, - uint32_t serial); - /** - * suggest resize - * - * The configure event asks the client to resize its surface. - * - * The size is a hint, in the sense that the client is free to - * ignore it if it doesn't resize, pick a smaller size (to satisfy - * aspect ratio or resize in steps of NxM pixels). - * - * The edges parameter provides a hint about how the surface was - * resized. The client may use this information to decide how to - * adjust its content to the new size (e.g. a scrolling area might - * adjust its content position to leave the viewable content - * unmoved). - * - * The client is free to dismiss all but the last configure event - * it received. - * - * The width and height arguments specify the size of the window in - * surface-local coordinates. - * @param edges how the surface was resized - * @param width new width of the surface - * @param height new height of the surface - */ - void (*configure)(void *data, - struct wl_shell_surface *wl_shell_surface, - uint32_t edges, - int32_t width, - int32_t height); - /** - * popup interaction is done - * - * The popup_done event is sent out when a popup grab is broken, - * that is, when the user clicks a surface that doesn't belong to - * the client owning the popup surface. - */ - void (*popup_done)(void *data, - struct wl_shell_surface *wl_shell_surface); -}; - -/** - * @ingroup iface_wl_shell_surface - */ -static inline int -wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, - const struct wl_shell_surface_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface, - (void (**)(void)) listener, data); -} - -#define WL_SHELL_SURFACE_PONG 0 -#define WL_SHELL_SURFACE_MOVE 1 -#define WL_SHELL_SURFACE_RESIZE 2 -#define WL_SHELL_SURFACE_SET_TOPLEVEL 3 -#define WL_SHELL_SURFACE_SET_TRANSIENT 4 -#define WL_SHELL_SURFACE_SET_FULLSCREEN 5 -#define WL_SHELL_SURFACE_SET_POPUP 6 -#define WL_SHELL_SURFACE_SET_MAXIMIZED 7 -#define WL_SHELL_SURFACE_SET_TITLE 8 -#define WL_SHELL_SURFACE_SET_CLASS 9 - -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 - -/** @ingroup iface_wl_shell_surface */ -static inline void -wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data); -} - -/** @ingroup iface_wl_shell_surface */ -static inline void * -wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface); -} - -static inline uint32_t -wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface); -} - -/** @ingroup iface_wl_shell_surface */ -static inline void -wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface) -{ - wl_proxy_destroy((struct wl_proxy *) wl_shell_surface); -} - -/** - * @ingroup iface_wl_shell_surface - * - * A client must respond to a ping event with a pong request or - * the client may be deemed unresponsive. - */ -static inline void -wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Start a pointer-driven move of the surface. - * - * This request must be used in response to a button press event. - * The server may ignore move requests depending on the state of - * the surface (e.g. fullscreen or maximized). - */ -static inline void -wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Start a pointer-driven resizing of the surface. - * - * This request must be used in response to a button press event. - * The server may ignore resize requests depending on the state of - * the surface (e.g. fullscreen or maximized). - */ -static inline void -wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a toplevel surface. - * - * A toplevel surface is not fullscreen, maximized or transient. - */ -static inline void -wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface relative to an existing surface. - * - * The x and y arguments specify the location of the upper left - * corner of the surface relative to the upper left corner of the - * parent surface, in surface-local coordinates. - * - * The flags argument controls details of the transient behaviour. - */ -static inline void -wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a fullscreen surface. - * - * If an output parameter is given then the surface will be made - * fullscreen on that output. If the client does not specify the - * output then the compositor will apply its policy - usually - * choosing the output on which the surface has the biggest surface - * area. - * - * The client may specify a method to resolve a size conflict - * between the output size and the surface size - this is provided - * through the method parameter. - * - * The framerate parameter is used only when the method is set - * to "driver", to indicate the preferred framerate. A value of 0 - * indicates that the client does not care about framerate. The - * framerate is specified in mHz, that is framerate of 60000 is 60Hz. - * - * A method of "scale" or "driver" implies a scaling operation of - * the surface, either via a direct scaling operation or a change of - * the output mode. This will override any kind of output scaling, so - * that mapping a surface with a buffer size equal to the mode can - * fill the screen independent of buffer_scale. - * - * A method of "fill" means we don't scale up the buffer, however - * any output scale is applied. This means that you may run into - * an edge case where the application maps a buffer with the same - * size of the output mode but buffer_scale 1 (thus making a - * surface larger than the output). In this case it is allowed to - * downscale the results to fit the screen. - * - * The compositor must reply to this request with a configure event - * with the dimensions for the output on which the surface will - * be made fullscreen. - */ -static inline void -wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a popup. - * - * A popup surface is a transient surface with an added pointer - * grab. - * - * An existing implicit grab will be changed to owner-events mode, - * and the popup grab will continue after the implicit grab ends - * (i.e. releasing the mouse button does not cause the popup to - * be unmapped). - * - * The popup grab continues until the window is destroyed or a - * mouse button is pressed in any other client's window. A click - * in any of the client's surfaces is reported as normal, however, - * clicks in other clients' surfaces will be discarded and trigger - * the callback. - * - * The x and y arguments specify the location of the upper left - * corner of the surface relative to the upper left corner of the - * parent surface, in surface-local coordinates. - */ -static inline void -wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a maximized surface. - * - * If an output parameter is given then the surface will be - * maximized on that output. If the client does not specify the - * output then the compositor will apply its policy - usually - * choosing the output on which the surface has the biggest surface - * area. - * - * The compositor will reply with a configure event telling - * the expected new surface size. The operation is completed - * on the next buffer attach to this surface. - * - * A maximized surface typically fills the entire output it is - * bound to, except for desktop elements such as panels. This is - * the main difference between a maximized shell surface and a - * fullscreen shell surface. - * - * The details depend on the compositor implementation. - */ -static inline void -wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Set a short title for the surface. - * - * This string may be used to identify the surface in a task bar, - * window list, or other user interface elements provided by the - * compositor. - * - * The string must be encoded in UTF-8. - */ -static inline void -wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Set a class for the surface. - * - * The surface class identifies the general class of applications - * to which the surface belongs. A common convention is to use the - * file name (or the full path if it is a non-standard location) of - * the application's .desktop file as the class. - */ -static inline void -wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_); -} - -#ifndef WL_SURFACE_ERROR_ENUM -#define WL_SURFACE_ERROR_ENUM -/** - * @ingroup iface_wl_surface - * wl_surface error values - * - * These errors can be emitted in response to wl_surface requests. - */ -enum wl_surface_error { - /** - * buffer scale value is invalid - */ - WL_SURFACE_ERROR_INVALID_SCALE = 0, - /** - * buffer transform value is invalid - */ - WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, - /** - * buffer size is invalid - */ - WL_SURFACE_ERROR_INVALID_SIZE = 2, - /** - * buffer offset is invalid - */ - WL_SURFACE_ERROR_INVALID_OFFSET = 3, - /** - * surface was destroyed before its role object - */ - WL_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 4, -}; -#endif /* WL_SURFACE_ERROR_ENUM */ - -/** - * @ingroup iface_wl_surface - * @struct wl_surface_listener - */ -struct wl_surface_listener { - /** - * surface enters an output - * - * This is emitted whenever a surface's creation, movement, or - * resizing results in some part of it being within the scanout - * region of an output. - * - * Note that a surface may be overlapping with zero or more - * outputs. - * @param output output entered by the surface - */ - void (*enter)(void *data, - struct wl_surface *wl_surface, - struct wl_output *output); - /** - * surface leaves an output - * - * This is emitted whenever a surface's creation, movement, or - * resizing results in it no longer having any part of it within - * the scanout region of an output. - * - * Clients should not use the number of outputs the surface is on - * for frame throttling purposes. The surface might be hidden even - * if no leave event has been sent, and the compositor might expect - * new surface content updates even if no enter event has been - * sent. The frame event should be used instead. - * @param output output left by the surface - */ - void (*leave)(void *data, - struct wl_surface *wl_surface, - struct wl_output *output); - /** - * preferred buffer scale for the surface - * - * This event indicates the preferred buffer scale for this - * surface. It is sent whenever the compositor's preference - * changes. - * - * Before receiving this event the preferred buffer scale for this - * surface is 1. - * - * It is intended that scaling aware clients use this event to - * scale their content and use wl_surface.set_buffer_scale to - * indicate the scale they have rendered with. This allows clients - * to supply a higher detail buffer. - * - * The compositor shall emit a scale value greater than 0. - * @param factor preferred scaling factor - * @since 6 - */ - void (*preferred_buffer_scale)(void *data, - struct wl_surface *wl_surface, - int32_t factor); - /** - * preferred buffer transform for the surface - * - * This event indicates the preferred buffer transform for this - * surface. It is sent whenever the compositor's preference - * changes. - * - * Before receiving this event the preferred buffer transform for - * this surface is normal. - * - * Applying this transformation to the surface buffer contents and - * using wl_surface.set_buffer_transform might allow the compositor - * to use the surface buffer more efficiently. - * @param transform preferred transform - * @since 6 - */ - void (*preferred_buffer_transform)(void *data, - struct wl_surface *wl_surface, - uint32_t transform); -}; - -/** - * @ingroup iface_wl_surface - */ -static inline int -wl_surface_add_listener(struct wl_surface *wl_surface, - const struct wl_surface_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_surface, - (void (**)(void)) listener, data); -} - -#define WL_SURFACE_DESTROY 0 -#define WL_SURFACE_ATTACH 1 -#define WL_SURFACE_DAMAGE 2 -#define WL_SURFACE_FRAME 3 -#define WL_SURFACE_SET_OPAQUE_REGION 4 -#define WL_SURFACE_SET_INPUT_REGION 5 -#define WL_SURFACE_COMMIT 6 -#define WL_SURFACE_SET_BUFFER_TRANSFORM 7 -#define WL_SURFACE_SET_BUFFER_SCALE 8 -#define WL_SURFACE_DAMAGE_BUFFER 9 -#define WL_SURFACE_OFFSET 10 - -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION 6 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION 6 - -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_ATTACH_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_DAMAGE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_FRAME_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_COMMIT_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_OFFSET_SINCE_VERSION 5 - -/** @ingroup iface_wl_surface */ -static inline void -wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data); -} - -/** @ingroup iface_wl_surface */ -static inline void * -wl_surface_get_user_data(struct wl_surface *wl_surface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_surface); -} - -static inline uint32_t -wl_surface_get_version(struct wl_surface *wl_surface) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_surface); -} - -/** - * @ingroup iface_wl_surface - * - * Deletes the surface and invalidates its object ID. - */ -static inline void -wl_surface_destroy(struct wl_surface *wl_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_surface - * - * Set a buffer as the content of this surface. - * - * The new size of the surface is calculated based on the buffer - * size transformed by the inverse buffer_transform and the - * inverse buffer_scale. This means that at commit time the supplied - * buffer size must be an integer multiple of the buffer_scale. If - * that's not the case, an invalid_size error is sent. - * - * The x and y arguments specify the location of the new pending - * buffer's upper left corner, relative to the current buffer's upper - * left corner, in surface-local coordinates. In other words, the - * x and y, combined with the new surface size define in which - * directions the surface's size changes. Setting anything other than 0 - * as x and y arguments is discouraged, and should instead be replaced - * with using the separate wl_surface.offset request. - * - * When the bound wl_surface version is 5 or higher, passing any - * non-zero x or y is a protocol violation, and will result in an - * 'invalid_offset' error being raised. The x and y arguments are ignored - * and do not change the pending state. To achieve equivalent semantics, - * use wl_surface.offset. - * - * Surface contents are double-buffered state, see wl_surface.commit. - * - * The initial surface contents are void; there is no content. - * wl_surface.attach assigns the given wl_buffer as the pending - * wl_buffer. wl_surface.commit makes the pending wl_buffer the new - * surface contents, and the size of the surface becomes the size - * calculated from the wl_buffer, as described above. After commit, - * there is no pending buffer until the next attach. - * - * Committing a pending wl_buffer allows the compositor to read the - * pixels in the wl_buffer. The compositor may access the pixels at - * any time after the wl_surface.commit request. When the compositor - * will not access the pixels anymore, it will send the - * wl_buffer.release event. Only after receiving wl_buffer.release, - * the client may reuse the wl_buffer. A wl_buffer that has been - * attached and then replaced by another attach instead of committed - * will not receive a release event, and is not used by the - * compositor. - * - * If a pending wl_buffer has been committed to more than one wl_surface, - * the delivery of wl_buffer.release events becomes undefined. A well - * behaved client should not rely on wl_buffer.release events in this - * case. Alternatively, a client could create multiple wl_buffer objects - * from the same backing storage or use wp_linux_buffer_release. - * - * Destroying the wl_buffer after wl_buffer.release does not change - * the surface contents. Destroying the wl_buffer before wl_buffer.release - * is allowed as long as the underlying buffer storage isn't re-used (this - * can happen e.g. on client process termination). However, if the client - * destroys the wl_buffer before receiving the wl_buffer.release event and - * mutates the underlying buffer storage, the surface contents become - * undefined immediately. - * - * If wl_surface.attach is sent with a NULL wl_buffer, the - * following wl_surface.commit will remove the surface content. - * - * If a pending wl_buffer has been destroyed, the result is not specified. - * Many compositors are known to remove the surface content on the following - * wl_surface.commit, but this behaviour is not universal. Clients seeking to - * maximise compatibility should not destroy pending buffers and should - * ensure that they explicitly remove content from surfaces, even after - * destroying buffers. - */ -static inline void -wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y); -} - -/** - * @ingroup iface_wl_surface - * - * This request is used to describe the regions where the pending - * buffer is different from the current surface contents, and where - * the surface therefore needs to be repainted. The compositor - * ignores the parts of the damage that fall outside of the surface. - * - * Damage is double-buffered state, see wl_surface.commit. - * - * The damage rectangle is specified in surface-local coordinates, - * where x and y specify the upper left corner of the damage rectangle. - * - * The initial value for pending damage is empty: no damage. - * wl_surface.damage adds pending damage: the new pending damage - * is the union of old pending damage and the given rectangle. - * - * wl_surface.commit assigns pending damage as the current damage, - * and clears pending damage. The server will clear the current - * damage as it repaints the surface. - * - * Note! New clients should not use this request. Instead damage can be - * posted with wl_surface.damage_buffer which uses buffer coordinates - * instead of surface coordinates. - */ -static inline void -wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); -} - -/** - * @ingroup iface_wl_surface - * - * Request a notification when it is a good time to start drawing a new - * frame, by creating a frame callback. This is useful for throttling - * redrawing operations, and driving animations. - * - * When a client is animating on a wl_surface, it can use the 'frame' - * request to get notified when it is a good time to draw and commit the - * next frame of animation. If the client commits an update earlier than - * that, it is likely that some updates will not make it to the display, - * and the client is wasting resources by drawing too often. - * - * The frame request will take effect on the next wl_surface.commit. - * The notification will only be posted for one frame unless - * requested again. For a wl_surface, the notifications are posted in - * the order the frame requests were committed. - * - * The server must send the notifications so that a client - * will not send excessive updates, while still allowing - * the highest possible update rate for clients that wait for the reply - * before drawing again. The server should give some time for the client - * to draw and commit after sending the frame callback events to let it - * hit the next output refresh. - * - * A server should avoid signaling the frame callbacks if the - * surface is not visible in any way, e.g. the surface is off-screen, - * or completely obscured by other opaque surfaces. - * - * The object returned by this request will be destroyed by the - * compositor after the callback is fired and as such the client must not - * attempt to use it after that point. - * - * The callback_data passed in the callback is the current time, in - * milliseconds, with an undefined base. - */ -static inline struct wl_callback * -wl_surface_frame(struct wl_surface *wl_surface) -{ - struct wl_proxy *callback; - - callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL); - - return (struct wl_callback *) callback; -} - -/** - * @ingroup iface_wl_surface - * - * This request sets the region of the surface that contains - * opaque content. - * - * The opaque region is an optimization hint for the compositor - * that lets it optimize the redrawing of content behind opaque - * regions. Setting an opaque region is not required for correct - * behaviour, but marking transparent content as opaque will result - * in repaint artifacts. - * - * The opaque region is specified in surface-local coordinates. - * - * The compositor ignores the parts of the opaque region that fall - * outside of the surface. - * - * Opaque region is double-buffered state, see wl_surface.commit. - * - * wl_surface.set_opaque_region changes the pending opaque region. - * wl_surface.commit copies the pending region to the current region. - * Otherwise, the pending and current regions are never changed. - * - * The initial value for an opaque region is empty. Setting the pending - * opaque region has copy semantics, and the wl_region object can be - * destroyed immediately. A NULL wl_region causes the pending opaque - * region to be set to empty. - */ -static inline void -wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); -} - -/** - * @ingroup iface_wl_surface - * - * This request sets the region of the surface that can receive - * pointer and touch events. - * - * Input events happening outside of this region will try the next - * surface in the server surface stack. The compositor ignores the - * parts of the input region that fall outside of the surface. - * - * The input region is specified in surface-local coordinates. - * - * Input region is double-buffered state, see wl_surface.commit. - * - * wl_surface.set_input_region changes the pending input region. - * wl_surface.commit copies the pending region to the current region. - * Otherwise the pending and current regions are never changed, - * except cursor and icon surfaces are special cases, see - * wl_pointer.set_cursor and wl_data_device.start_drag. - * - * The initial value for an input region is infinite. That means the - * whole surface will accept input. Setting the pending input region - * has copy semantics, and the wl_region object can be destroyed - * immediately. A NULL wl_region causes the input region to be set - * to infinite. - */ -static inline void -wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); -} - -/** - * @ingroup iface_wl_surface - * - * Surface state (input, opaque, and damage regions, attached buffers, - * etc.) is double-buffered. Protocol requests modify the pending state, - * as opposed to the active state in use by the compositor. - * - * A commit request atomically creates a content update from the pending - * state, even if the pending state has not been touched. The content - * update is placed in a queue until it becomes active. After commit, the - * new pending state is as documented for each related request. - * - * When the content update is applied, the wl_buffer is applied before all - * other state. This means that all coordinates in double-buffered state - * are relative to the newly attached wl_buffers, except for - * wl_surface.attach itself. If there is no newly attached wl_buffer, the - * coordinates are relative to the previous content update. - * - * All requests that need a commit to become effective are documented - * to affect double-buffered state. - * - * Other interfaces may add further double-buffered surface state. - */ -static inline void -wl_surface_commit(struct wl_surface *wl_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0); -} - -/** - * @ingroup iface_wl_surface - * - * This request sets the transformation that the client has already applied - * to the content of the buffer. The accepted values for the transform - * parameter are the values for wl_output.transform. - * - * The compositor applies the inverse of this transformation whenever it - * uses the buffer contents. - * - * Buffer transform is double-buffered state, see wl_surface.commit. - * - * A newly created surface has its buffer transformation set to normal. - * - * wl_surface.set_buffer_transform changes the pending buffer - * transformation. wl_surface.commit copies the pending buffer - * transformation to the current one. Otherwise, the pending and current - * values are never changed. - * - * The purpose of this request is to allow clients to render content - * according to the output transform, thus permitting the compositor to - * use certain optimizations even if the display is rotated. Using - * hardware overlays and scanning out a client buffer for fullscreen - * surfaces are examples of such optimizations. Those optimizations are - * highly dependent on the compositor implementation, so the use of this - * request should be considered on a case-by-case basis. - * - * Note that if the transform value includes 90 or 270 degree rotation, - * the width of the buffer will become the surface height and the height - * of the buffer will become the surface width. - * - * If transform is not one of the values from the - * wl_output.transform enum the invalid_transform protocol error - * is raised. - */ -static inline void -wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform); -} - -/** - * @ingroup iface_wl_surface - * - * This request sets an optional scaling factor on how the compositor - * interprets the contents of the buffer attached to the window. - * - * Buffer scale is double-buffered state, see wl_surface.commit. - * - * A newly created surface has its buffer scale set to 1. - * - * wl_surface.set_buffer_scale changes the pending buffer scale. - * wl_surface.commit copies the pending buffer scale to the current one. - * Otherwise, the pending and current values are never changed. - * - * The purpose of this request is to allow clients to supply higher - * resolution buffer data for use on high resolution outputs. It is - * intended that you pick the same buffer scale as the scale of the - * output that the surface is displayed on. This means the compositor - * can avoid scaling when rendering the surface on that output. - * - * Note that if the scale is larger than 1, then you have to attach - * a buffer that is larger (by a factor of scale in each dimension) - * than the desired surface size. - * - * If scale is not greater than 0 the invalid_scale protocol error is - * raised. - */ -static inline void -wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale); -} - -/** - * @ingroup iface_wl_surface - * - * This request is used to describe the regions where the pending - * buffer is different from the current surface contents, and where - * the surface therefore needs to be repainted. The compositor - * ignores the parts of the damage that fall outside of the surface. - * - * Damage is double-buffered state, see wl_surface.commit. - * - * The damage rectangle is specified in buffer coordinates, - * where x and y specify the upper left corner of the damage rectangle. - * - * The initial value for pending damage is empty: no damage. - * wl_surface.damage_buffer adds pending damage: the new pending - * damage is the union of old pending damage and the given rectangle. - * - * wl_surface.commit assigns pending damage as the current damage, - * and clears pending damage. The server will clear the current - * damage as it repaints the surface. - * - * This request differs from wl_surface.damage in only one way - it - * takes damage in buffer coordinates instead of surface-local - * coordinates. While this generally is more intuitive than surface - * coordinates, it is especially desirable when using wp_viewport - * or when a drawing library (like EGL) is unaware of buffer scale - * and buffer transform. - * - * Note: Because buffer transformation changes and damage requests may - * be interleaved in the protocol stream, it is impossible to determine - * the actual mapping between surface and buffer damage until - * wl_surface.commit time. Therefore, compositors wishing to take both - * kinds of damage into account will have to accumulate damage from the - * two requests separately and only transform from one to the other - * after receiving the wl_surface.commit. - */ -static inline void -wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); -} - -/** - * @ingroup iface_wl_surface - * - * The x and y arguments specify the location of the new pending - * buffer's upper left corner, relative to the current buffer's upper - * left corner, in surface-local coordinates. In other words, the - * x and y, combined with the new surface size define in which - * directions the surface's size changes. - * - * The exact semantics of wl_surface.offset are role-specific. Refer to - * the documentation of specific roles for more information. - * - * Surface location offset is double-buffered state, see - * wl_surface.commit. - * - * This request is semantically equivalent to and the replaces the x and y - * arguments in the wl_surface.attach request in wl_surface versions prior - * to 5. See wl_surface.attach for details. - */ -static inline void -wl_surface_offset(struct wl_surface *wl_surface, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y); -} - -#ifndef WL_SEAT_CAPABILITY_ENUM -#define WL_SEAT_CAPABILITY_ENUM -/** - * @ingroup iface_wl_seat - * seat capability bitmask - * - * This is a bitmask of capabilities this seat has; if a member is - * set, then it is present on the seat. - */ -enum wl_seat_capability { - /** - * the seat has pointer devices - */ - WL_SEAT_CAPABILITY_POINTER = 1, - /** - * the seat has one or more keyboards - */ - WL_SEAT_CAPABILITY_KEYBOARD = 2, - /** - * the seat has touch devices - */ - WL_SEAT_CAPABILITY_TOUCH = 4, -}; -#endif /* WL_SEAT_CAPABILITY_ENUM */ - -#ifndef WL_SEAT_ERROR_ENUM -#define WL_SEAT_ERROR_ENUM -/** - * @ingroup iface_wl_seat - * wl_seat error values - * - * These errors can be emitted in response to wl_seat requests. - */ -enum wl_seat_error { - /** - * get_pointer, get_keyboard or get_touch called on seat without the matching capability - */ - WL_SEAT_ERROR_MISSING_CAPABILITY = 0, -}; -#endif /* WL_SEAT_ERROR_ENUM */ - -/** - * @ingroup iface_wl_seat - * @struct wl_seat_listener - */ -struct wl_seat_listener { - /** - * seat capabilities changed - * - * This is emitted whenever a seat gains or loses the pointer, - * keyboard or touch capabilities. The argument is a capability - * enum containing the complete set of capabilities this seat has. - * - * When the pointer capability is added, a client may create a - * wl_pointer object using the wl_seat.get_pointer request. This - * object will receive pointer events until the capability is - * removed in the future. - * - * When the pointer capability is removed, a client should destroy - * the wl_pointer objects associated with the seat where the - * capability was removed, using the wl_pointer.release request. No - * further pointer events will be received on these objects. - * - * In some compositors, if a seat regains the pointer capability - * and a client has a previously obtained wl_pointer object of - * version 4 or less, that object may start sending pointer events - * again. This behavior is considered a misinterpretation of the - * intended behavior and must not be relied upon by the client. - * wl_pointer objects of version 5 or later must not send events if - * created before the most recent event notifying the client of an - * added pointer capability. - * - * The above behavior also applies to wl_keyboard and wl_touch with - * the keyboard and touch capabilities, respectively. - * @param capabilities capabilities of the seat - */ - void (*capabilities)(void *data, - struct wl_seat *wl_seat, - uint32_t capabilities); - /** - * unique identifier for this seat - * - * In a multi-seat configuration the seat name can be used by - * clients to help identify which physical devices the seat - * represents. - * - * The seat name is a UTF-8 string with no convention defined for - * its contents. Each name is unique among all wl_seat globals. The - * name is only guaranteed to be unique for the current compositor - * instance. - * - * The same seat names are used for all clients. Thus, the name can - * be shared across processes to refer to a specific wl_seat - * global. - * - * The name event is sent after binding to the seat global. This - * event is only sent once per seat object, and the name does not - * change over the lifetime of the wl_seat global. - * - * Compositors may re-use the same seat name if the wl_seat global - * is destroyed and re-created later. - * @param name seat identifier - * @since 2 - */ - void (*name)(void *data, - struct wl_seat *wl_seat, - const char *name); -}; - -/** - * @ingroup iface_wl_seat - */ -static inline int -wl_seat_add_listener(struct wl_seat *wl_seat, - const struct wl_seat_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_seat, - (void (**)(void)) listener, data); -} - -#define WL_SEAT_GET_POINTER 0 -#define WL_SEAT_GET_KEYBOARD 1 -#define WL_SEAT_GET_TOUCH 2 -#define WL_SEAT_RELEASE 3 - -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_NAME_SINCE_VERSION 2 - -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_GET_POINTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_RELEASE_SINCE_VERSION 5 - -/** @ingroup iface_wl_seat */ -static inline void -wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data); -} - -/** @ingroup iface_wl_seat */ -static inline void * -wl_seat_get_user_data(struct wl_seat *wl_seat) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_seat); -} - -static inline uint32_t -wl_seat_get_version(struct wl_seat *wl_seat) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_seat); -} - -/** @ingroup iface_wl_seat */ -static inline void -wl_seat_destroy(struct wl_seat *wl_seat) -{ - wl_proxy_destroy((struct wl_proxy *) wl_seat); -} - -/** - * @ingroup iface_wl_seat - * - * The ID provided will be initialized to the wl_pointer interface - * for this seat. - * - * This request only takes effect if the seat has the pointer - * capability, or has had the pointer capability in the past. - * It is a protocol violation to issue this request on a seat that has - * never had the pointer capability. The missing_capability error will - * be sent in this case. - */ -static inline struct wl_pointer * -wl_seat_get_pointer(struct wl_seat *wl_seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); - - return (struct wl_pointer *) id; -} - -/** - * @ingroup iface_wl_seat - * - * The ID provided will be initialized to the wl_keyboard interface - * for this seat. - * - * This request only takes effect if the seat has the keyboard - * capability, or has had the keyboard capability in the past. - * It is a protocol violation to issue this request on a seat that has - * never had the keyboard capability. The missing_capability error will - * be sent in this case. - */ -static inline struct wl_keyboard * -wl_seat_get_keyboard(struct wl_seat *wl_seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); - - return (struct wl_keyboard *) id; -} - -/** - * @ingroup iface_wl_seat - * - * The ID provided will be initialized to the wl_touch interface - * for this seat. - * - * This request only takes effect if the seat has the touch - * capability, or has had the touch capability in the past. - * It is a protocol violation to issue this request on a seat that has - * never had the touch capability. The missing_capability error will - * be sent in this case. - */ -static inline struct wl_touch * -wl_seat_get_touch(struct wl_seat *wl_seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); - - return (struct wl_touch *) id; -} - -/** - * @ingroup iface_wl_seat - * - * Using this request a client can tell the server that it is not going to - * use the seat object anymore. - */ -static inline void -wl_seat_release(struct wl_seat *wl_seat) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_POINTER_ERROR_ENUM -#define WL_POINTER_ERROR_ENUM -enum wl_pointer_error { - /** - * given wl_surface has another role - */ - WL_POINTER_ERROR_ROLE = 0, -}; -#endif /* WL_POINTER_ERROR_ENUM */ - -#ifndef WL_POINTER_BUTTON_STATE_ENUM -#define WL_POINTER_BUTTON_STATE_ENUM -/** - * @ingroup iface_wl_pointer - * physical button state - * - * Describes the physical state of a button that produced the button - * event. - */ -enum wl_pointer_button_state { - /** - * the button is not pressed - */ - WL_POINTER_BUTTON_STATE_RELEASED = 0, - /** - * the button is pressed - */ - WL_POINTER_BUTTON_STATE_PRESSED = 1, -}; -#endif /* WL_POINTER_BUTTON_STATE_ENUM */ - -#ifndef WL_POINTER_AXIS_ENUM -#define WL_POINTER_AXIS_ENUM -/** - * @ingroup iface_wl_pointer - * axis types - * - * Describes the axis types of scroll events. - */ -enum wl_pointer_axis { - /** - * vertical axis - */ - WL_POINTER_AXIS_VERTICAL_SCROLL = 0, - /** - * horizontal axis - */ - WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, -}; -#endif /* WL_POINTER_AXIS_ENUM */ - -#ifndef WL_POINTER_AXIS_SOURCE_ENUM -#define WL_POINTER_AXIS_SOURCE_ENUM -/** - * @ingroup iface_wl_pointer - * axis source types - * - * Describes the source types for axis events. This indicates to the - * client how an axis event was physically generated; a client may - * adjust the user interface accordingly. For example, scroll events - * from a "finger" source may be in a smooth coordinate space with - * kinetic scrolling whereas a "wheel" source may be in discrete steps - * of a number of lines. - * - * The "continuous" axis source is a device generating events in a - * continuous coordinate space, but using something other than a - * finger. One example for this source is button-based scrolling where - * the vertical motion of a device is converted to scroll events while - * a button is held down. - * - * The "wheel tilt" axis source indicates that the actual device is a - * wheel but the scroll event is not caused by a rotation but a - * (usually sideways) tilt of the wheel. - */ -enum wl_pointer_axis_source { - /** - * a physical wheel rotation - */ - WL_POINTER_AXIS_SOURCE_WHEEL = 0, - /** - * finger on a touch surface - */ - WL_POINTER_AXIS_SOURCE_FINGER = 1, - /** - * continuous coordinate space - */ - WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, - /** - * a physical wheel tilt - * @since 6 - */ - WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, -}; -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 -#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ - -#ifndef WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM -#define WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM -/** - * @ingroup iface_wl_pointer - * axis relative direction - * - * This specifies the direction of the physical motion that caused a - * wl_pointer.axis event, relative to the wl_pointer.axis direction. - */ -enum wl_pointer_axis_relative_direction { - /** - * physical motion matches axis direction - */ - WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL = 0, - /** - * physical motion is the inverse of the axis direction - */ - WL_POINTER_AXIS_RELATIVE_DIRECTION_INVERTED = 1, -}; -#endif /* WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM */ - -/** - * @ingroup iface_wl_pointer - * @struct wl_pointer_listener - */ -struct wl_pointer_listener { - /** - * enter event - * - * Notification that this seat's pointer is focused on a certain - * surface. - * - * When a seat's focus enters a surface, the pointer image is - * undefined and a client should respond to this event by setting - * an appropriate pointer image with the set_cursor request. - * @param serial serial number of the enter event - * @param surface surface entered by the pointer - * @param surface_x surface-local x coordinate - * @param surface_y surface-local y coordinate - */ - void (*enter)(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t surface_x, - wl_fixed_t surface_y); - /** - * leave event - * - * Notification that this seat's pointer is no longer focused on - * a certain surface. - * - * The leave notification is sent before the enter notification for - * the new focus. - * @param serial serial number of the leave event - * @param surface surface left by the pointer - */ - void (*leave)(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface); - /** - * pointer motion event - * - * Notification of pointer location change. The arguments - * surface_x and surface_y are the location relative to the focused - * surface. - * @param time timestamp with millisecond granularity - * @param surface_x surface-local x coordinate - * @param surface_y surface-local y coordinate - */ - void (*motion)(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - wl_fixed_t surface_x, - wl_fixed_t surface_y); - /** - * pointer button event - * - * Mouse button click and release notifications. - * - * The location of the click is given by the last motion or enter - * event. The time argument is a timestamp with millisecond - * granularity, with an undefined base. - * - * The button is a button code as defined in the Linux kernel's - * linux/input-event-codes.h header file, e.g. BTN_LEFT. - * - * Any 16-bit button code value is reserved for future additions to - * the kernel's event code list. All other button codes above - * 0xFFFF are currently undefined but may be used in future - * versions of this protocol. - * @param serial serial number of the button event - * @param time timestamp with millisecond granularity - * @param button button that produced the event - * @param state physical state of the button - */ - void (*button)(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state); - /** - * axis event - * - * Scroll and other axis notifications. - * - * For scroll events (vertical and horizontal scroll axes), the - * value parameter is the length of a vector along the specified - * axis in a coordinate space identical to those of motion events, - * representing a relative movement along the specified axis. - * - * For devices that support movements non-parallel to axes multiple - * axis events will be emitted. - * - * When applicable, for example for touch pads, the server can - * choose to emit scroll events where the motion vector is - * equivalent to a motion event vector. - * - * When applicable, a client can transform its content relative to - * the scroll distance. - * @param time timestamp with millisecond granularity - * @param axis axis type - * @param value length of vector in surface-local coordinate space - */ - void (*axis)(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value); - /** - * end of a pointer event sequence - * - * Indicates the end of a set of events that logically belong - * together. A client is expected to accumulate the data in all - * events within the frame before proceeding. - * - * All wl_pointer events before a wl_pointer.frame event belong - * logically together. For example, in a diagonal scroll motion the - * compositor will send an optional wl_pointer.axis_source event, - * two wl_pointer.axis events (horizontal and vertical) and finally - * a wl_pointer.frame event. The client may use this information to - * calculate a diagonal vector for scrolling. - * - * When multiple wl_pointer.axis events occur within the same - * frame, the motion vector is the combined motion of all events. - * When a wl_pointer.axis and a wl_pointer.axis_stop event occur - * within the same frame, this indicates that axis movement in one - * axis has stopped but continues in the other axis. When multiple - * wl_pointer.axis_stop events occur within the same frame, this - * indicates that these axes stopped in the same instance. - * - * A wl_pointer.frame event is sent for every logical event group, - * even if the group only contains a single wl_pointer event. - * Specifically, a client may get a sequence: motion, frame, - * button, frame, axis, frame, axis_stop, frame. - * - * The wl_pointer.enter and wl_pointer.leave events are logical - * events generated by the compositor and not the hardware. These - * events are also grouped by a wl_pointer.frame. When a pointer - * moves from one surface to another, a compositor should group the - * wl_pointer.leave event within the same wl_pointer.frame. - * However, a client must not rely on wl_pointer.leave and - * wl_pointer.enter being in the same wl_pointer.frame. - * Compositor-specific policies may require the wl_pointer.leave - * and wl_pointer.enter event being split across multiple - * wl_pointer.frame groups. - * @since 5 - */ - void (*frame)(void *data, - struct wl_pointer *wl_pointer); - /** - * axis source event - * - * Source information for scroll and other axes. - * - * This event does not occur on its own. It is sent before a - * wl_pointer.frame event and carries the source information for - * all events within that frame. - * - * The source specifies how this event was generated. If the source - * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event - * will be sent when the user lifts the finger off the device. - * - * If the source is wl_pointer.axis_source.wheel, - * wl_pointer.axis_source.wheel_tilt or - * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event - * may or may not be sent. Whether a compositor sends an axis_stop - * event for these sources is hardware-specific and - * implementation-dependent; clients must not rely on receiving an - * axis_stop event for these scroll sources and should treat scroll - * sequences from these scroll sources as unterminated by default. - * - * This event is optional. If the source is unknown for a - * particular axis event sequence, no event is sent. Only one - * wl_pointer.axis_source event is permitted per frame. - * - * The order of wl_pointer.axis_discrete and wl_pointer.axis_source - * is not guaranteed. - * @param axis_source source of the axis event - * @since 5 - */ - void (*axis_source)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis_source); - /** - * axis stop event - * - * Stop notification for scroll and other axes. - * - * For some wl_pointer.axis_source types, a wl_pointer.axis_stop - * event is sent to notify a client that the axis sequence has - * terminated. This enables the client to implement kinetic - * scrolling. See the wl_pointer.axis_source documentation for - * information on when this event may be generated. - * - * Any wl_pointer.axis events with the same axis_source after this - * event should be considered as the start of a new axis motion. - * - * The timestamp is to be interpreted identical to the timestamp in - * the wl_pointer.axis event. The timestamp value may be the same - * as a preceding wl_pointer.axis event. - * @param time timestamp with millisecond granularity - * @param axis the axis stopped with this event - * @since 5 - */ - void (*axis_stop)(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - uint32_t axis); - /** - * axis click event - * - * Discrete step information for scroll and other axes. - * - * This event carries the axis value of the wl_pointer.axis event - * in discrete steps (e.g. mouse wheel clicks). - * - * This event is deprecated with wl_pointer version 8 - this event - * is not sent to clients supporting version 8 or later. - * - * This event does not occur on its own, it is coupled with a - * wl_pointer.axis event that represents this axis value on a - * continuous scale. The protocol guarantees that each - * axis_discrete event is always followed by exactly one axis event - * with the same axis number within the same wl_pointer.frame. Note - * that the protocol allows for other events to occur between the - * axis_discrete and its coupled axis event, including other - * axis_discrete or axis events. A wl_pointer.frame must not - * contain more than one axis_discrete event per axis type. - * - * This event is optional; continuous scrolling devices like - * two-finger scrolling on touchpads do not have discrete steps and - * do not generate this event. - * - * The discrete value carries the directional information. e.g. a - * value of -2 is two steps towards the negative direction of this - * axis. - * - * The axis number is identical to the axis number in the - * associated axis event. - * - * The order of wl_pointer.axis_discrete and wl_pointer.axis_source - * is not guaranteed. - * @param axis axis type - * @param discrete number of steps - * @since 5 - * @deprecated Deprecated since version 8 - */ - void (*axis_discrete)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis, - int32_t discrete); - /** - * axis high-resolution scroll event - * - * Discrete high-resolution scroll information. - * - * This event carries high-resolution wheel scroll information, - * with each multiple of 120 representing one logical scroll step - * (a wheel detent). For example, an axis_value120 of 30 is one - * quarter of a logical scroll step in the positive direction, a - * value120 of -240 are two logical scroll steps in the negative - * direction within the same hardware event. Clients that rely on - * discrete scrolling should accumulate the value120 to multiples - * of 120 before processing the event. - * - * The value120 must not be zero. - * - * This event replaces the wl_pointer.axis_discrete event in - * clients supporting wl_pointer version 8 or later. - * - * Where a wl_pointer.axis_source event occurs in the same - * wl_pointer.frame, the axis source applies to this event. - * - * The order of wl_pointer.axis_value120 and wl_pointer.axis_source - * is not guaranteed. - * @param axis axis type - * @param value120 scroll distance as fraction of 120 - * @since 8 - */ - void (*axis_value120)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis, - int32_t value120); - /** - * axis relative physical direction event - * - * Relative directional information of the entity causing the - * axis motion. - * - * For a wl_pointer.axis event, the - * wl_pointer.axis_relative_direction event specifies the movement - * direction of the entity causing the wl_pointer.axis event. For - * example: - if a user's fingers on a touchpad move down and this - * causes a wl_pointer.axis vertical_scroll down event, the - * physical direction is 'identical' - if a user's fingers on a - * touchpad move down and this causes a wl_pointer.axis - * vertical_scroll up scroll up event ('natural scrolling'), the - * physical direction is 'inverted'. - * - * A client may use this information to adjust scroll motion of - * components. Specifically, enabling natural scrolling causes the - * content to change direction compared to traditional scrolling. - * Some widgets like volume control sliders should usually match - * the physical direction regardless of whether natural scrolling - * is active. This event enables clients to match the scroll - * direction of a widget to the physical direction. - * - * This event does not occur on its own, it is coupled with a - * wl_pointer.axis event that represents this axis value. The - * protocol guarantees that each axis_relative_direction event is - * always followed by exactly one axis event with the same axis - * number within the same wl_pointer.frame. Note that the protocol - * allows for other events to occur between the - * axis_relative_direction and its coupled axis event. - * - * The axis number is identical to the axis number in the - * associated axis event. - * - * The order of wl_pointer.axis_relative_direction, - * wl_pointer.axis_discrete and wl_pointer.axis_source is not - * guaranteed. - * @param axis axis type - * @param direction physical direction relative to axis motion - * @since 9 - */ - void (*axis_relative_direction)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis, - uint32_t direction); -}; - -/** - * @ingroup iface_wl_pointer - */ -static inline int -wl_pointer_add_listener(struct wl_pointer *wl_pointer, - const struct wl_pointer_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_pointer, - (void (**)(void)) listener, data); -} - -#define WL_POINTER_SET_CURSOR 0 -#define WL_POINTER_RELEASE 1 - -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_MOTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_BUTTON_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_FRAME_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_VALUE120_SINCE_VERSION 8 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION 9 - -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_pointer */ -static inline void -wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data); -} - -/** @ingroup iface_wl_pointer */ -static inline void * -wl_pointer_get_user_data(struct wl_pointer *wl_pointer) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer); -} - -static inline uint32_t -wl_pointer_get_version(struct wl_pointer *wl_pointer) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_pointer); -} - -/** @ingroup iface_wl_pointer */ -static inline void -wl_pointer_destroy(struct wl_pointer *wl_pointer) -{ - wl_proxy_destroy((struct wl_proxy *) wl_pointer); -} - -/** - * @ingroup iface_wl_pointer - * - * Set the pointer surface, i.e., the surface that contains the - * pointer image (cursor). This request gives the surface the role - * of a cursor. If the surface already has another role, it raises - * a protocol error. - * - * The cursor actually changes only if the pointer - * focus for this device is one of the requesting client's surfaces - * or the surface parameter is the current pointer surface. If - * there was a previous surface set with this request it is - * replaced. If surface is NULL, the pointer image is hidden. - * - * The parameters hotspot_x and hotspot_y define the position of - * the pointer surface relative to the pointer location. Its - * top-left corner is always at (x, y) - (hotspot_x, hotspot_y), - * where (x, y) are the coordinates of the pointer location, in - * surface-local coordinates. - * - * On wl_surface.offset requests to the pointer surface, hotspot_x - * and hotspot_y are decremented by the x and y parameters - * passed to the request. The offset must be applied by - * wl_surface.commit as usual. - * - * The hotspot can also be updated by passing the currently set - * pointer surface to this request with new values for hotspot_x - * and hotspot_y. - * - * The input region is ignored for wl_surfaces with the role of - * a cursor. When the use as a cursor ends, the wl_surface is - * unmapped. - * - * The serial parameter must match the latest wl_pointer.enter - * serial number sent to the client. Otherwise the request will be - * ignored. - */ -static inline void -wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, - WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y); -} - -/** - * @ingroup iface_wl_pointer - * - * Using this request a client can tell the server that it is not going to - * use the pointer object anymore. - * - * This request destroys the pointer proxy object, so clients must not call - * wl_pointer_destroy() after using this request. - */ -static inline void -wl_pointer_release(struct wl_pointer *wl_pointer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, - WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM -#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM -/** - * @ingroup iface_wl_keyboard - * keyboard mapping format - * - * This specifies the format of the keymap provided to the - * client with the wl_keyboard.keymap event. - */ -enum wl_keyboard_keymap_format { - /** - * no keymap; client must understand how to interpret the raw keycode - */ - WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, - /** - * libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode - */ - WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, -}; -#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ - -#ifndef WL_KEYBOARD_KEY_STATE_ENUM -#define WL_KEYBOARD_KEY_STATE_ENUM -/** - * @ingroup iface_wl_keyboard - * physical key state - * - * Describes the physical state of a key that produced the key event. - * - * Since version 10, the key can be in a "repeated" pseudo-state which - * means the same as "pressed", but is used to signal repetition in the - * key event. - * - * The key may only enter the repeated state after entering the pressed - * state and before entering the released state. This event may be - * generated multiple times while the key is down. - */ -enum wl_keyboard_key_state { - /** - * key is not pressed - */ - WL_KEYBOARD_KEY_STATE_RELEASED = 0, - /** - * key is pressed - */ - WL_KEYBOARD_KEY_STATE_PRESSED = 1, - /** - * key was repeated - * @since 10 - */ - WL_KEYBOARD_KEY_STATE_REPEATED = 2, -}; -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_KEY_STATE_REPEATED_SINCE_VERSION 10 -#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ - -/** - * @ingroup iface_wl_keyboard - * @struct wl_keyboard_listener - */ -struct wl_keyboard_listener { - /** - * keyboard mapping - * - * This event provides a file descriptor to the client which can - * be memory-mapped in read-only mode to provide a keyboard mapping - * description. - * - * From version 7 onwards, the fd must be mapped with MAP_PRIVATE - * by the recipient, as MAP_SHARED may fail. - * @param format keymap format - * @param fd keymap file descriptor - * @param size keymap size, in bytes - */ - void (*keymap)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t format, - int32_t fd, - uint32_t size); - /** - * enter event - * - * Notification that this seat's keyboard focus is on a certain - * surface. - * - * The compositor must send the wl_keyboard.modifiers event after - * this event. - * - * In the wl_keyboard logical state, this event sets the active - * surface to the surface argument and the keys currently logically - * down to the keys in the keys argument. The compositor must not - * send this event if the wl_keyboard already had an active surface - * immediately before this event. - * - * Clients should not use the list of pressed keys to emulate - * key-press events. The order of keys in the list is unspecified. - * @param serial serial number of the enter event - * @param surface surface gaining keyboard focus - * @param keys the keys currently logically down - */ - void (*enter)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - struct wl_surface *surface, - struct wl_array *keys); - /** - * leave event - * - * Notification that this seat's keyboard focus is no longer on a - * certain surface. - * - * The leave notification is sent before the enter notification for - * the new focus. - * - * In the wl_keyboard logical state, this event resets all values - * to their defaults. The compositor must not send this event if - * the active surface of the wl_keyboard was not equal to the - * surface argument immediately before this event. - * @param serial serial number of the leave event - * @param surface surface that lost keyboard focus - */ - void (*leave)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - struct wl_surface *surface); - /** - * key event - * - * A key was pressed or released. The time argument is a - * timestamp with millisecond granularity, with an undefined base. - * - * The key is a platform-specific key code that can be interpreted - * by feeding it to the keyboard mapping (see the keymap event). - * - * If this event produces a change in modifiers, then the resulting - * wl_keyboard.modifiers event must be sent after this event. - * - * In the wl_keyboard logical state, this event adds the key to the - * keys currently logically down (if the state argument is pressed) - * or removes the key from the keys currently logically down (if - * the state argument is released). The compositor must not send - * this event if the wl_keyboard did not have an active surface - * immediately before this event. The compositor must not send this - * event if state is pressed (resp. released) and the key was - * already logically down (resp. was not logically down) - * immediately before this event. - * - * Since version 10, compositors may send key events with the - * "repeated" key state when a wl_keyboard.repeat_info event with a - * rate argument of 0 has been received. This allows the compositor - * to take over the responsibility of key repetition. - * @param serial serial number of the key event - * @param time timestamp with millisecond granularity - * @param key key that produced the event - * @param state physical state of the key - */ - void (*key)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - uint32_t time, - uint32_t key, - uint32_t state); - /** - * modifier and group state - * - * Notifies clients that the modifier and/or group state has - * changed, and it should update its local state. - * - * The compositor may send this event without a surface of the - * client having keyboard focus, for example to tie modifier - * information to pointer focus instead. If a modifier event with - * pressed modifiers is sent without a prior enter event, the - * client can assume the modifier state is valid until it receives - * the next wl_keyboard.modifiers event. In order to reset the - * modifier state again, the compositor can send a - * wl_keyboard.modifiers event with no pressed modifiers. - * - * In the wl_keyboard logical state, this event updates the - * modifiers and group. - * @param serial serial number of the modifiers event - * @param mods_depressed depressed modifiers - * @param mods_latched latched modifiers - * @param mods_locked locked modifiers - * @param group keyboard layout - */ - void (*modifiers)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - uint32_t mods_depressed, - uint32_t mods_latched, - uint32_t mods_locked, - uint32_t group); - /** - * repeat rate and delay - * - * Informs the client about the keyboard's repeat rate and delay. - * - * This event is sent as soon as the wl_keyboard object has been - * created, and is guaranteed to be received by the client before - * any key press event. - * - * Negative values for either rate or delay are illegal. A rate of - * zero will disable any repeating (regardless of the value of - * delay). - * - * This event can be sent later on as well with a new value if - * necessary, so clients should continue listening for the event - * past the creation of wl_keyboard. - * @param rate the rate of repeating keys in characters per second - * @param delay delay in milliseconds since key down until repeating starts - * @since 4 - */ - void (*repeat_info)(void *data, - struct wl_keyboard *wl_keyboard, - int32_t rate, - int32_t delay); -}; - -/** - * @ingroup iface_wl_keyboard - */ -static inline int -wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard, - const struct wl_keyboard_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard, - (void (**)(void)) listener, data); -} - -#define WL_KEYBOARD_RELEASE 0 - -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_KEY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 - -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_keyboard */ -static inline void -wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data); -} - -/** @ingroup iface_wl_keyboard */ -static inline void * -wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard); -} - -static inline uint32_t -wl_keyboard_get_version(struct wl_keyboard *wl_keyboard) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_keyboard); -} - -/** @ingroup iface_wl_keyboard */ -static inline void -wl_keyboard_destroy(struct wl_keyboard *wl_keyboard) -{ - wl_proxy_destroy((struct wl_proxy *) wl_keyboard); -} - -/** - * @ingroup iface_wl_keyboard - */ -static inline void -wl_keyboard_release(struct wl_keyboard *wl_keyboard) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard, - WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_touch - * @struct wl_touch_listener - */ -struct wl_touch_listener { - /** - * touch down event and beginning of a touch sequence - * - * A new touch point has appeared on the surface. This touch - * point is assigned a unique ID. Future events from this touch - * point reference this ID. The ID ceases to be valid after a touch - * up event and may be reused in the future. - * @param serial serial number of the touch down event - * @param time timestamp with millisecond granularity - * @param surface surface touched - * @param id the unique ID of this touch point - * @param x surface-local x coordinate - * @param y surface-local y coordinate - */ - void (*down)(void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - struct wl_surface *surface, - int32_t id, - wl_fixed_t x, - wl_fixed_t y); - /** - * end of a touch event sequence - * - * The touch point has disappeared. No further events will be - * sent for this touch point and the touch point's ID is released - * and may be reused in a future touch down event. - * @param serial serial number of the touch up event - * @param time timestamp with millisecond granularity - * @param id the unique ID of this touch point - */ - void (*up)(void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - int32_t id); - /** - * update of touch point coordinates - * - * A touch point has changed coordinates. - * @param time timestamp with millisecond granularity - * @param id the unique ID of this touch point - * @param x surface-local x coordinate - * @param y surface-local y coordinate - */ - void (*motion)(void *data, - struct wl_touch *wl_touch, - uint32_t time, - int32_t id, - wl_fixed_t x, - wl_fixed_t y); - /** - * end of touch frame event - * - * Indicates the end of a set of events that logically belong - * together. A client is expected to accumulate the data in all - * events within the frame before proceeding. - * - * A wl_touch.frame terminates at least one event but otherwise no - * guarantee is provided about the set of events within a frame. A - * client must assume that any state not updated in a frame is - * unchanged from the previously known state. - */ - void (*frame)(void *data, - struct wl_touch *wl_touch); - /** - * touch session cancelled - * - * Sent if the compositor decides the touch stream is a global - * gesture. No further events are sent to the clients from that - * particular gesture. Touch cancellation applies to all touch - * points currently active on this client's surface. The client is - * responsible for finalizing the touch points, future touch points - * on this surface may reuse the touch point ID. - * - * No frame event is required after the cancel event. - */ - void (*cancel)(void *data, - struct wl_touch *wl_touch); - /** - * update shape of touch point - * - * Sent when a touchpoint has changed its shape. - * - * This event does not occur on its own. It is sent before a - * wl_touch.frame event and carries the new shape information for - * any previously reported, or new touch points of that frame. - * - * Other events describing the touch point such as wl_touch.down, - * wl_touch.motion or wl_touch.orientation may be sent within the - * same wl_touch.frame. A client should treat these events as a - * single logical touch point update. The order of wl_touch.shape, - * wl_touch.orientation and wl_touch.motion is not guaranteed. A - * wl_touch.down event is guaranteed to occur before the first - * wl_touch.shape event for this touch ID but both events may occur - * within the same wl_touch.frame. - * - * A touchpoint shape is approximated by an ellipse through the - * major and minor axis length. The major axis length describes the - * longer diameter of the ellipse, while the minor axis length - * describes the shorter diameter. Major and minor are orthogonal - * and both are specified in surface-local coordinates. The center - * of the ellipse is always at the touchpoint location as reported - * by wl_touch.down or wl_touch.move. - * - * This event is only sent by the compositor if the touch device - * supports shape reports. The client has to make reasonable - * assumptions about the shape if it did not receive this event. - * @param id the unique ID of this touch point - * @param major length of the major axis in surface-local coordinates - * @param minor length of the minor axis in surface-local coordinates - * @since 6 - */ - void (*shape)(void *data, - struct wl_touch *wl_touch, - int32_t id, - wl_fixed_t major, - wl_fixed_t minor); - /** - * update orientation of touch point - * - * Sent when a touchpoint has changed its orientation. - * - * This event does not occur on its own. It is sent before a - * wl_touch.frame event and carries the new shape information for - * any previously reported, or new touch points of that frame. - * - * Other events describing the touch point such as wl_touch.down, - * wl_touch.motion or wl_touch.shape may be sent within the same - * wl_touch.frame. A client should treat these events as a single - * logical touch point update. The order of wl_touch.shape, - * wl_touch.orientation and wl_touch.motion is not guaranteed. A - * wl_touch.down event is guaranteed to occur before the first - * wl_touch.orientation event for this touch ID but both events may - * occur within the same wl_touch.frame. - * - * The orientation describes the clockwise angle of a touchpoint's - * major axis to the positive surface y-axis and is normalized to - * the -180 to +180 degree range. The granularity of orientation - * depends on the touch device, some devices only support binary - * rotation values between 0 and 90 degrees. - * - * This event is only sent by the compositor if the touch device - * supports orientation reports. - * @param id the unique ID of this touch point - * @param orientation angle between major axis and positive surface y-axis in degrees - * @since 6 - */ - void (*orientation)(void *data, - struct wl_touch *wl_touch, - int32_t id, - wl_fixed_t orientation); -}; - -/** - * @ingroup iface_wl_touch - */ -static inline int -wl_touch_add_listener(struct wl_touch *wl_touch, - const struct wl_touch_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_touch, - (void (**)(void)) listener, data); -} - -#define WL_TOUCH_RELEASE 0 - -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_DOWN_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_UP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_MOTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_FRAME_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_CANCEL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_SHAPE_SINCE_VERSION 6 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 - -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_touch */ -static inline void -wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data); -} - -/** @ingroup iface_wl_touch */ -static inline void * -wl_touch_get_user_data(struct wl_touch *wl_touch) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_touch); -} - -static inline uint32_t -wl_touch_get_version(struct wl_touch *wl_touch) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_touch); -} - -/** @ingroup iface_wl_touch */ -static inline void -wl_touch_destroy(struct wl_touch *wl_touch) -{ - wl_proxy_destroy((struct wl_proxy *) wl_touch); -} - -/** - * @ingroup iface_wl_touch - */ -static inline void -wl_touch_release(struct wl_touch *wl_touch) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_touch, - WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_OUTPUT_SUBPIXEL_ENUM -#define WL_OUTPUT_SUBPIXEL_ENUM -/** - * @ingroup iface_wl_output - * subpixel geometry information - * - * This enumeration describes how the physical - * pixels on an output are laid out. - */ -enum wl_output_subpixel { - /** - * unknown geometry - */ - WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, - /** - * no geometry - */ - WL_OUTPUT_SUBPIXEL_NONE = 1, - /** - * horizontal RGB - */ - WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, - /** - * horizontal BGR - */ - WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, - /** - * vertical RGB - */ - WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, - /** - * vertical BGR - */ - WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, -}; -#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ - -#ifndef WL_OUTPUT_TRANSFORM_ENUM -#define WL_OUTPUT_TRANSFORM_ENUM -/** - * @ingroup iface_wl_output - * transformation applied to buffer contents - * - * This describes transformations that clients and compositors apply to - * buffer contents. - * - * The flipped values correspond to an initial flip around a - * vertical axis followed by rotation. - * - * The purpose is mainly to allow clients to render accordingly and - * tell the compositor, so that for fullscreen surfaces, the - * compositor will still be able to scan out directly from client - * surfaces. - */ -enum wl_output_transform { - /** - * no transform - */ - WL_OUTPUT_TRANSFORM_NORMAL = 0, - /** - * 90 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_90 = 1, - /** - * 180 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_180 = 2, - /** - * 270 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_270 = 3, - /** - * 180 degree flip around a vertical axis - */ - WL_OUTPUT_TRANSFORM_FLIPPED = 4, - /** - * flip and rotate 90 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, - /** - * flip and rotate 180 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, - /** - * flip and rotate 270 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, -}; -#endif /* WL_OUTPUT_TRANSFORM_ENUM */ - -#ifndef WL_OUTPUT_MODE_ENUM -#define WL_OUTPUT_MODE_ENUM -/** - * @ingroup iface_wl_output - * mode information - * - * These flags describe properties of an output mode. - * They are used in the flags bitfield of the mode event. - */ -enum wl_output_mode { - /** - * indicates this is the current mode - */ - WL_OUTPUT_MODE_CURRENT = 0x1, - /** - * indicates this is the preferred mode - */ - WL_OUTPUT_MODE_PREFERRED = 0x2, -}; -#endif /* WL_OUTPUT_MODE_ENUM */ - -/** - * @ingroup iface_wl_output - * @struct wl_output_listener - */ -struct wl_output_listener { - /** - * properties of the output - * - * The geometry event describes geometric properties of the - * output. The event is sent when binding to the output object and - * whenever any of the properties change. - * - * The physical size can be set to zero if it doesn't make sense - * for this output (e.g. for projectors or virtual outputs). - * - * The geometry event will be followed by a done event (starting - * from version 2). - * - * Clients should use wl_surface.preferred_buffer_transform instead - * of the transform advertised by this event to find the preferred - * buffer transform to use for a surface. - * - * Note: wl_output only advertises partial information about the - * output position and identification. Some compositors, for - * instance those not implementing a desktop-style output layout or - * those exposing virtual outputs, might fake this information. - * Instead of using x and y, clients should use - * xdg_output.logical_position. Instead of using make and model, - * clients should use name and description. - * @param x x position within the global compositor space - * @param y y position within the global compositor space - * @param physical_width width in millimeters of the output - * @param physical_height height in millimeters of the output - * @param subpixel subpixel orientation of the output - * @param make textual description of the manufacturer - * @param model textual description of the model - * @param transform additional transformation applied to buffer contents during presentation - */ - void (*geometry)(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform); - /** - * advertise available modes for the output - * - * The mode event describes an available mode for the output. - * - * The event is sent when binding to the output object and there - * will always be one mode, the current mode. The event is sent - * again if an output changes mode, for the mode that is now - * current. In other words, the current mode is always the last - * mode that was received with the current flag set. - * - * Non-current modes are deprecated. A compositor can decide to - * only advertise the current mode and never send other modes. - * Clients should not rely on non-current modes. - * - * The size of a mode is given in physical hardware units of the - * output device. This is not necessarily the same as the output - * size in the global compositor space. For instance, the output - * may be scaled, as described in wl_output.scale, or transformed, - * as described in wl_output.transform. Clients willing to retrieve - * the output size in the global compositor space should use - * xdg_output.logical_size instead. - * - * The vertical refresh rate can be set to zero if it doesn't make - * sense for this output (e.g. for virtual outputs). - * - * The mode event will be followed by a done event (starting from - * version 2). - * - * Clients should not use the refresh rate to schedule frames. - * Instead, they should use the wl_surface.frame event or the - * presentation-time protocol. - * - * Note: this information is not always meaningful for all outputs. - * Some compositors, such as those exposing virtual outputs, might - * fake the refresh rate or the size. - * @param flags bitfield of mode flags - * @param width width of the mode in hardware units - * @param height height of the mode in hardware units - * @param refresh vertical refresh rate in mHz - */ - void (*mode)(void *data, - struct wl_output *wl_output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh); - /** - * sent all information about output - * - * This event is sent after all other properties have been sent - * after binding to the output object and after any other property - * changes done after that. This allows changes to the output - * properties to be seen as atomic, even if they happen via - * multiple events. - * @since 2 - */ - void (*done)(void *data, - struct wl_output *wl_output); - /** - * output scaling properties - * - * This event contains scaling geometry information that is not - * in the geometry event. It may be sent after binding the output - * object or if the output scale changes later. The compositor will - * emit a non-zero, positive value for scale. If it is not sent, - * the client should assume a scale of 1. - * - * A scale larger than 1 means that the compositor will - * automatically scale surface buffers by this amount when - * rendering. This is used for very high resolution displays where - * applications rendering at the native resolution would be too - * small to be legible. - * - * Clients should use wl_surface.preferred_buffer_scale instead of - * this event to find the preferred buffer scale to use for a - * surface. - * - * The scale event will be followed by a done event. - * @param factor scaling factor of output - * @since 2 - */ - void (*scale)(void *data, - struct wl_output *wl_output, - int32_t factor); - /** - * name of this output - * - * Many compositors will assign user-friendly names to their - * outputs, show them to the user, allow the user to refer to an - * output, etc. The client may wish to know this name as well to - * offer the user similar behaviors. - * - * The name is a UTF-8 string with no convention defined for its - * contents. Each name is unique among all wl_output globals. The - * name is only guaranteed to be unique for the compositor - * instance. - * - * The same output name is used for all clients for a given - * wl_output global. Thus, the name can be shared across processes - * to refer to a specific wl_output global. - * - * The name is not guaranteed to be persistent across sessions, - * thus cannot be used to reliably identify an output in e.g. - * configuration files. - * - * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. - * However, do not assume that the name is a reflection of an - * underlying DRM connector, X11 connection, etc. - * - * The name event is sent after binding the output object. This - * event is only sent once per output object, and the name does not - * change over the lifetime of the wl_output global. - * - * Compositors may re-use the same output name if the wl_output - * global is destroyed and re-created later. Compositors should - * avoid re-using the same name if possible. - * - * The name event will be followed by a done event. - * @param name output name - * @since 4 - */ - void (*name)(void *data, - struct wl_output *wl_output, - const char *name); - /** - * human-readable description of this output - * - * Many compositors can produce human-readable descriptions of - * their outputs. The client may wish to know this description as - * well, e.g. for output selection purposes. - * - * The description is a UTF-8 string with no convention defined for - * its contents. The description is not guaranteed to be unique - * among all wl_output globals. Examples might include 'Foocorp 11" - * Display' or 'Virtual X11 output via :1'. - * - * The description event is sent after binding the output object - * and whenever the description changes. The description is - * optional, and may not be sent at all. - * - * The description event will be followed by a done event. - * @param description output description - * @since 4 - */ - void (*description)(void *data, - struct wl_output *wl_output, - const char *description); -}; - -/** - * @ingroup iface_wl_output - */ -static inline int -wl_output_add_listener(struct wl_output *wl_output, - const struct wl_output_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_output, - (void (**)(void)) listener, data); -} - -#define WL_OUTPUT_RELEASE 0 - -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_MODE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_DONE_SINCE_VERSION 2 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_SCALE_SINCE_VERSION 2 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_NAME_SINCE_VERSION 4 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_DESCRIPTION_SINCE_VERSION 4 - -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_output */ -static inline void -wl_output_set_user_data(struct wl_output *wl_output, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data); -} - -/** @ingroup iface_wl_output */ -static inline void * -wl_output_get_user_data(struct wl_output *wl_output) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_output); -} - -static inline uint32_t -wl_output_get_version(struct wl_output *wl_output) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_output); -} - -/** @ingroup iface_wl_output */ -static inline void -wl_output_destroy(struct wl_output *wl_output) -{ - wl_proxy_destroy((struct wl_proxy *) wl_output); -} - -/** - * @ingroup iface_wl_output - * - * Using this request a client can tell the server that it is not going to - * use the output object anymore. - */ -static inline void -wl_output_release(struct wl_output *wl_output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_output, - WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY); -} - -#define WL_REGION_DESTROY 0 -#define WL_REGION_ADD 1 -#define WL_REGION_SUBTRACT 2 - - -/** - * @ingroup iface_wl_region - */ -#define WL_REGION_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_region - */ -#define WL_REGION_ADD_SINCE_VERSION 1 -/** - * @ingroup iface_wl_region - */ -#define WL_REGION_SUBTRACT_SINCE_VERSION 1 - -/** @ingroup iface_wl_region */ -static inline void -wl_region_set_user_data(struct wl_region *wl_region, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data); -} - -/** @ingroup iface_wl_region */ -static inline void * -wl_region_get_user_data(struct wl_region *wl_region) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_region); -} - -static inline uint32_t -wl_region_get_version(struct wl_region *wl_region) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_region); -} - -/** - * @ingroup iface_wl_region - * - * Destroy the region. This will invalidate the object ID. - */ -static inline void -wl_region_destroy(struct wl_region *wl_region) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_region, - WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_region - * - * Add the specified rectangle to the region. - */ -static inline void -wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_region, - WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); -} - -/** - * @ingroup iface_wl_region - * - * Subtract the specified rectangle from the region. - */ -static inline void -wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_region, - WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); -} - -#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM -#define WL_SUBCOMPOSITOR_ERROR_ENUM -enum wl_subcompositor_error { - /** - * the to-be sub-surface is invalid - */ - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, - /** - * the to-be sub-surface parent is invalid - */ - WL_SUBCOMPOSITOR_ERROR_BAD_PARENT = 1, -}; -#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ - -#define WL_SUBCOMPOSITOR_DESTROY 0 -#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1 - - -/** - * @ingroup iface_wl_subcompositor - */ -#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subcompositor - */ -#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 - -/** @ingroup iface_wl_subcompositor */ -static inline void -wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data); -} - -/** @ingroup iface_wl_subcompositor */ -static inline void * -wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor); -} - -static inline uint32_t -wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor); -} - -/** - * @ingroup iface_wl_subcompositor - * - * Informs the server that the client will not be using this - * protocol object anymore. This does not affect any other - * objects, wl_subsurface objects included. - */ -static inline void -wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, - WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_subcompositor - * - * Create a sub-surface interface for the given surface, and - * associate it with the given parent surface. This turns a - * plain wl_surface into a sub-surface. - * - * The to-be sub-surface must not already have another role, and it - * must not have an existing wl_subsurface object. Otherwise the - * bad_surface protocol error is raised. - * - * Adding sub-surfaces to a parent is a double-buffered operation on the - * parent (see wl_surface.commit). The effect of adding a sub-surface - * becomes visible on the next time the state of the parent surface is - * applied. - * - * The parent surface must not be one of the child surface's descendants, - * and the parent must be different from the child surface, otherwise the - * bad_parent protocol error is raised. - * - * This request modifies the behaviour of wl_surface.commit request on - * the sub-surface, see the documentation on wl_subsurface interface. - */ -static inline struct wl_subsurface * -wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, - WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent); - - return (struct wl_subsurface *) id; -} - -#ifndef WL_SUBSURFACE_ERROR_ENUM -#define WL_SUBSURFACE_ERROR_ENUM -enum wl_subsurface_error { - /** - * wl_surface is not a sibling or the parent - */ - WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, -}; -#endif /* WL_SUBSURFACE_ERROR_ENUM */ - -#define WL_SUBSURFACE_DESTROY 0 -#define WL_SUBSURFACE_SET_POSITION 1 -#define WL_SUBSURFACE_PLACE_ABOVE 2 -#define WL_SUBSURFACE_PLACE_BELOW 3 -#define WL_SUBSURFACE_SET_SYNC 4 -#define WL_SUBSURFACE_SET_DESYNC 5 - - -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 - -/** @ingroup iface_wl_subsurface */ -static inline void -wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data); -} - -/** @ingroup iface_wl_subsurface */ -static inline void * -wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface); -} - -static inline uint32_t -wl_subsurface_get_version(struct wl_subsurface *wl_subsurface) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_subsurface); -} - -/** - * @ingroup iface_wl_subsurface - * - * The sub-surface interface is removed from the wl_surface object - * that was turned into a sub-surface with a - * wl_subcompositor.get_subsurface request. The wl_surface's association - * to the parent is deleted. The wl_surface is unmapped immediately. - */ -static inline void -wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_subsurface - * - * This schedules a sub-surface position change. - * The sub-surface will be moved so that its origin (top left - * corner pixel) will be at the location x, y of the parent surface - * coordinate system. The coordinates are not restricted to the parent - * surface area. Negative values are allowed. - * - * The scheduled coordinates will take effect whenever the state of the - * parent surface is applied. - * - * If more than one set_position request is invoked by the client before - * the commit of the parent surface, the position of a new request always - * replaces the scheduled position from any previous request. - * - * The initial position is 0, 0. - */ -static inline void -wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y); -} - -/** - * @ingroup iface_wl_subsurface - * - * This sub-surface is taken from the stack, and put back just - * above the reference surface, changing the z-order of the sub-surfaces. - * The reference surface must be one of the sibling surfaces, or the - * parent surface. Using any other surface, including this sub-surface, - * will cause a protocol error. - * - * The z-order is double-buffered. Requests are handled in order and - * applied immediately to a pending state. The final pending state is - * copied to the active state the next time the state of the parent - * surface is applied. - * - * A new sub-surface is initially added as the top-most in the stack - * of its siblings and parent. - */ -static inline void -wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); -} - -/** - * @ingroup iface_wl_subsurface - * - * The sub-surface is placed just below the reference surface. - * See wl_subsurface.place_above. - */ -static inline void -wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); -} - -/** - * @ingroup iface_wl_subsurface - * - * Change the commit behaviour of the sub-surface to synchronized - * mode, also described as the parent dependent mode. - * - * In synchronized mode, wl_surface.commit on a sub-surface will - * accumulate the committed state in a cache, but the state will - * not be applied and hence will not change the compositor output. - * The cached state is applied to the sub-surface immediately after - * the parent surface's state is applied. This ensures atomic - * updates of the parent and all its synchronized sub-surfaces. - * Applying the cached state will invalidate the cache, so further - * parent surface commits do not (re-)apply old state. - * - * See wl_subsurface for the recursive effect of this mode. - */ -static inline void -wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); -} - -/** - * @ingroup iface_wl_subsurface - * - * Change the commit behaviour of the sub-surface to desynchronized - * mode, also described as independent or freely running mode. - * - * In desynchronized mode, wl_surface.commit on a sub-surface will - * apply the pending state directly, without caching, as happens - * normally with a wl_surface. Calling wl_surface.commit on the - * parent surface has no effect on the sub-surface's wl_surface - * state. This mode allows a sub-surface to be updated on its own. - * - * If cached state exists when wl_surface.commit is called in - * desynchronized mode, the pending state is added to the cached - * state, and applied as a whole. This invalidates the cache. - * - * Note: even if a sub-surface is set to desynchronized, a parent - * sub-surface may override it to behave as synchronized. For details, - * see wl_subsurface. - * - * If a surface's parent surface behaves as desynchronized, then - * the cached state is applied on set_desync. - */ -static inline void -wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); -} - -#define WL_FIXES_DESTROY 0 -#define WL_FIXES_DESTROY_REGISTRY 1 - - -/** - * @ingroup iface_wl_fixes - */ -#define WL_FIXES_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_fixes - */ -#define WL_FIXES_DESTROY_REGISTRY_SINCE_VERSION 1 - -/** @ingroup iface_wl_fixes */ -static inline void -wl_fixes_set_user_data(struct wl_fixes *wl_fixes, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_fixes, user_data); -} - -/** @ingroup iface_wl_fixes */ -static inline void * -wl_fixes_get_user_data(struct wl_fixes *wl_fixes) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_fixes); -} - -static inline uint32_t -wl_fixes_get_version(struct wl_fixes *wl_fixes) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_fixes); -} - -/** - * @ingroup iface_wl_fixes - */ -static inline void -wl_fixes_destroy(struct wl_fixes *wl_fixes) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_fixes, - WL_FIXES_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_fixes), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_fixes - * - * This request destroys a wl_registry object. - * - * The client should no longer use the wl_registry after making this - * request. - * - * The compositor will emit a wl_display.delete_id event with the object ID - * of the registry and will no longer emit any events on the registry. The - * client should re-use the object ID once it receives the - * wl_display.delete_id event. - */ -static inline void -wl_fixes_destroy_registry(struct wl_fixes *wl_fixes, struct wl_registry *registry) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_fixes, - WL_FIXES_DESTROY_REGISTRY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_fixes), 0, registry); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol-code.h b/raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c similarity index 70% rename from raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol-code.h rename to raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c index 0399e11..31e3f56 100644 --- a/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol-code.h +++ b/raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2015 Samsung Electronics Co., Ltd @@ -23,45 +23,34 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface wl_surface_interface; extern const struct wl_interface zwp_idle_inhibitor_v1_interface; -static const struct wl_interface *idle_inhibit_unstable_v1_types[] = { +static const struct wl_interface *idle_inhibit_unstable_v1_wl_ii_types[] = { &zwp_idle_inhibitor_v1_interface, &wl_surface_interface, }; static const struct wl_message zwp_idle_inhibit_manager_v1_requests[] = { - { "destroy", "", idle_inhibit_unstable_v1_types + 0 }, - { "create_inhibitor", "no", idle_inhibit_unstable_v1_types + 0 }, + { "destroy", "", idle_inhibit_unstable_v1_wl_ii_types + 0 }, + { "create_inhibitor", "no", idle_inhibit_unstable_v1_wl_ii_types + 0 }, }; -WL_PRIVATE const struct wl_interface zwp_idle_inhibit_manager_v1_interface = { +WL_EXPORT const struct wl_interface zwp_idle_inhibit_manager_v1_interface = { "zwp_idle_inhibit_manager_v1", 1, 2, zwp_idle_inhibit_manager_v1_requests, 0, NULL, }; static const struct wl_message zwp_idle_inhibitor_v1_requests[] = { - { "destroy", "", idle_inhibit_unstable_v1_types + 0 }, + { "destroy", "", idle_inhibit_unstable_v1_wl_ii_types + 0 }, }; -WL_PRIVATE const struct wl_interface zwp_idle_inhibitor_v1_interface = { +WL_EXPORT const struct wl_interface zwp_idle_inhibitor_v1_interface = { "zwp_idle_inhibitor_v1", 1, 1, zwp_idle_inhibitor_v1_requests, 0, NULL, diff --git a/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol.h b/raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h similarity index 91% rename from raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h index ef97ceb..65ece1f 100644 --- a/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H #define IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -45,8 +45,6 @@ struct wl_surface; struct zwp_idle_inhibit_manager_v1; struct zwp_idle_inhibitor_v1; -#ifndef ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE -#define ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE /** * @page page_iface_zwp_idle_inhibit_manager_v1 zwp_idle_inhibit_manager_v1 * @section page_iface_zwp_idle_inhibit_manager_v1_desc Description @@ -83,9 +81,6 @@ struct zwp_idle_inhibitor_v1; * interface version number is reset. */ extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface; -#endif -#ifndef ZWP_IDLE_INHIBITOR_V1_INTERFACE -#define ZWP_IDLE_INHIBITOR_V1_INTERFACE /** * @page page_iface_zwp_idle_inhibitor_v1 zwp_idle_inhibitor_v1 * @section page_iface_zwp_idle_inhibitor_v1_desc Description @@ -122,7 +117,6 @@ extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface; * de-idles and re-idles the inhibitor will take effect. */ extern const struct wl_interface zwp_idle_inhibitor_v1_interface; -#endif #define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY 0 #define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR 1 @@ -165,8 +159,10 @@ zwp_idle_inhibit_manager_v1_get_version(struct zwp_idle_inhibit_manager_v1 *zwp_ static inline void zwp_idle_inhibit_manager_v1_destroy(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1, - ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_idle_inhibit_manager_v1, + ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_idle_inhibit_manager_v1); } /** @@ -179,8 +175,8 @@ zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1, - ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), 0, NULL, surface); + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_idle_inhibit_manager_v1, + ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, NULL, surface); return (struct zwp_idle_inhibitor_v1 *) id; } @@ -221,8 +217,10 @@ zwp_idle_inhibitor_v1_get_version(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibit static inline void zwp_idle_inhibitor_v1_destroy(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibitor_v1, - ZWP_IDLE_INHIBITOR_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_idle_inhibitor_v1, + ZWP_IDLE_INHIBITOR_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_idle_inhibitor_v1); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol-code.h b/raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c similarity index 68% rename from raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol-code.h rename to raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c index 4184538..7f9f06b 100644 --- a/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol-code.h +++ b/raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2014 Jonas Ådahl @@ -24,28 +24,17 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface wl_pointer_interface; extern const struct wl_interface wl_region_interface; extern const struct wl_interface wl_surface_interface; extern const struct wl_interface zwp_confined_pointer_v1_interface; extern const struct wl_interface zwp_locked_pointer_v1_interface; -static const struct wl_interface *pointer_constraints_unstable_v1_types[] = { +static const struct wl_interface *pointer_constraints_unstable_v1_wl_pc_types[] = { NULL, NULL, &zwp_locked_pointer_v1_interface, @@ -63,45 +52,45 @@ static const struct wl_interface *pointer_constraints_unstable_v1_types[] = { }; static const struct wl_message zwp_pointer_constraints_v1_requests[] = { - { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, - { "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 2 }, - { "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 7 }, + { "destroy", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, + { "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_wl_pc_types + 2 }, + { "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_wl_pc_types + 7 }, }; -WL_PRIVATE const struct wl_interface zwp_pointer_constraints_v1_interface = { +WL_EXPORT const struct wl_interface zwp_pointer_constraints_v1_interface = { "zwp_pointer_constraints_v1", 1, 3, zwp_pointer_constraints_v1_requests, 0, NULL, }; static const struct wl_message zwp_locked_pointer_v1_requests[] = { - { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, - { "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_types + 0 }, - { "set_region", "?o", pointer_constraints_unstable_v1_types + 12 }, + { "destroy", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, + { "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_wl_pc_types + 0 }, + { "set_region", "?o", pointer_constraints_unstable_v1_wl_pc_types + 12 }, }; static const struct wl_message zwp_locked_pointer_v1_events[] = { - { "locked", "", pointer_constraints_unstable_v1_types + 0 }, - { "unlocked", "", pointer_constraints_unstable_v1_types + 0 }, + { "locked", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, + { "unlocked", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, }; -WL_PRIVATE const struct wl_interface zwp_locked_pointer_v1_interface = { +WL_EXPORT const struct wl_interface zwp_locked_pointer_v1_interface = { "zwp_locked_pointer_v1", 1, 3, zwp_locked_pointer_v1_requests, 2, zwp_locked_pointer_v1_events, }; static const struct wl_message zwp_confined_pointer_v1_requests[] = { - { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, - { "set_region", "?o", pointer_constraints_unstable_v1_types + 13 }, + { "destroy", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, + { "set_region", "?o", pointer_constraints_unstable_v1_wl_pc_types + 13 }, }; static const struct wl_message zwp_confined_pointer_v1_events[] = { - { "confined", "", pointer_constraints_unstable_v1_types + 0 }, - { "unconfined", "", pointer_constraints_unstable_v1_types + 0 }, + { "confined", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, + { "unconfined", "", pointer_constraints_unstable_v1_wl_pc_types + 0 }, }; -WL_PRIVATE const struct wl_interface zwp_confined_pointer_v1_interface = { +WL_EXPORT const struct wl_interface zwp_confined_pointer_v1_interface = { "zwp_confined_pointer_v1", 1, 2, zwp_confined_pointer_v1_requests, 2, zwp_confined_pointer_v1_events, diff --git a/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol.h b/raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h similarity index 88% rename from raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h index dd7b871..f66f8d7 100644 --- a/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H #define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -73,8 +73,6 @@ struct zwp_confined_pointer_v1; struct zwp_locked_pointer_v1; struct zwp_pointer_constraints_v1; -#ifndef ZWP_POINTER_CONSTRAINTS_V1_INTERFACE -#define ZWP_POINTER_CONSTRAINTS_V1_INTERFACE /** * @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1 * @section page_iface_zwp_pointer_constraints_v1_desc Description @@ -113,9 +111,6 @@ struct zwp_pointer_constraints_v1; * 'already_constrained' error will be raised. */ extern const struct wl_interface zwp_pointer_constraints_v1_interface; -#endif -#ifndef ZWP_LOCKED_POINTER_V1_INTERFACE -#define ZWP_LOCKED_POINTER_V1_INTERFACE /** * @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1 * @section page_iface_zwp_locked_pointer_v1_desc Description @@ -174,9 +169,6 @@ extern const struct wl_interface zwp_pointer_constraints_v1_interface; * destroyed. */ extern const struct wl_interface zwp_locked_pointer_v1_interface; -#endif -#ifndef ZWP_CONFINED_POINTER_V1_INTERFACE -#define ZWP_CONFINED_POINTER_V1_INTERFACE /** * @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1 * @section page_iface_zwp_confined_pointer_v1_desc Description @@ -221,7 +213,6 @@ extern const struct wl_interface zwp_locked_pointer_v1_interface; * be destroyed. */ extern const struct wl_interface zwp_confined_pointer_v1_interface; -#endif #ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM #define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM @@ -244,30 +235,15 @@ enum zwp_pointer_constraints_v1_error { #define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM /** * @ingroup iface_zwp_pointer_constraints_v1 - * constraint lifetime + * the pointer constraint may reactivate * - * These values represent different lifetime semantics. They are passed - * as arguments to the factory requests to specify how the constraint - * lifetimes should be managed. + * A persistent pointer constraint may again reactivate once it has + * been deactivated. See the corresponding deactivation event + * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for + * details. */ enum zwp_pointer_constraints_v1_lifetime { - /** - * the pointer constraint is defunct once deactivated - * - * A oneshot pointer constraint will never reactivate once it has - * been deactivated. See the corresponding deactivation event - * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) - * for details. - */ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1, - /** - * the pointer constraint may reactivate - * - * A persistent pointer constraint may again reactivate once it - * has been deactivated. See the corresponding deactivation event - * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) - * for details. - */ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2, }; #endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */ @@ -319,8 +295,10 @@ zwp_pointer_constraints_v1_get_version(struct zwp_pointer_constraints_v1 *zwp_po static inline void zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1, - ZWP_POINTER_CONSTRAINTS_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_pointer_constraints_v1, + ZWP_POINTER_CONSTRAINTS_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_pointer_constraints_v1); } /** @@ -366,8 +344,8 @@ zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_p { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1, - ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime); + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_pointer_constraints_v1, + ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, NULL, surface, pointer, region, lifetime); return (struct zwp_locked_pointer_v1 *) id; } @@ -398,8 +376,8 @@ zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zw { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1, - ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime); + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_pointer_constraints_v1, + ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, NULL, surface, pointer, region, lifetime); return (struct zwp_confined_pointer_v1 *) id; } @@ -497,8 +475,10 @@ zwp_locked_pointer_v1_get_version(struct zwp_locked_pointer_v1 *zwp_locked_point static inline void zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1, - ZWP_LOCKED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1, + ZWP_LOCKED_POINTER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_locked_pointer_v1); } /** @@ -512,14 +492,15 @@ zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v * information to warp the pointer upon unlock in order to avoid pointer * jumps. * - * The cursor position hint is double-buffered state, see - * wl_surface.commit. + * The cursor position hint is double buffered. The new hint will only take + * effect when the associated surface gets it pending state applied. See + * wl_surface.commit for details. */ static inline void zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1, - ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, surface_x, surface_y); + wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1, + ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, surface_x, surface_y); } /** @@ -527,15 +508,17 @@ zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp * * Set a new region used to lock the pointer. * - * The new lock region is double-buffered, see wl_surface.commit. + * The new lock region is double-buffered. The new lock region will + * only take effect when the associated surface gets its pending state + * applied. See wl_surface.commit for details. * * For details about the lock region, see wp_locked_pointer. */ static inline void zwp_locked_pointer_v1_set_region(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, struct wl_region *region) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1, - ZWP_LOCKED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, region); + wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1, + ZWP_LOCKED_POINTER_V1_SET_REGION, region); } /** @@ -626,8 +609,10 @@ zwp_confined_pointer_v1_get_version(struct zwp_confined_pointer_v1 *zwp_confined static inline void zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1, - ZWP_CONFINED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_confined_pointer_v1, + ZWP_CONFINED_POINTER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_confined_pointer_v1); } /** @@ -635,7 +620,9 @@ zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_poi * * Set a new region used to confine the pointer. * - * The new confine region is double-buffered, see wl_surface.commit. + * The new confine region is double-buffered. The new confine region will + * only take effect when the associated surface gets its pending state + * applied. See wl_surface.commit for details. * * If the confinement is active when the new confinement region is applied * and the pointer ends up outside of newly applied region, the pointer may @@ -651,8 +638,8 @@ zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_poi static inline void zwp_confined_pointer_v1_set_region(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, struct wl_region *region) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1, - ZWP_CONFINED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), 0, region); + wl_proxy_marshal((struct wl_proxy *) zwp_confined_pointer_v1, + ZWP_CONFINED_POINTER_V1_SET_REGION, region); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol-code.h b/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c similarity index 69% rename from raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol-code.h rename to raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c index 605149b..f6010c9 100644 --- a/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol-code.h +++ b/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2014 Jonas Ådahl @@ -24,25 +24,14 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface wl_pointer_interface; extern const struct wl_interface zwp_relative_pointer_v1_interface; -static const struct wl_interface *relative_pointer_unstable_v1_types[] = { +static const struct wl_interface *relative_pointer_unstable_v1_wl_rp_types[] = { NULL, NULL, NULL, @@ -54,25 +43,25 @@ static const struct wl_interface *relative_pointer_unstable_v1_types[] = { }; static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = { - { "destroy", "", relative_pointer_unstable_v1_types + 0 }, - { "get_relative_pointer", "no", relative_pointer_unstable_v1_types + 6 }, + { "destroy", "", relative_pointer_unstable_v1_wl_rp_types + 0 }, + { "get_relative_pointer", "no", relative_pointer_unstable_v1_wl_rp_types + 6 }, }; -WL_PRIVATE const struct wl_interface zwp_relative_pointer_manager_v1_interface = { +WL_EXPORT const struct wl_interface zwp_relative_pointer_manager_v1_interface = { "zwp_relative_pointer_manager_v1", 1, 2, zwp_relative_pointer_manager_v1_requests, 0, NULL, }; static const struct wl_message zwp_relative_pointer_v1_requests[] = { - { "destroy", "", relative_pointer_unstable_v1_types + 0 }, + { "destroy", "", relative_pointer_unstable_v1_wl_rp_types + 0 }, }; static const struct wl_message zwp_relative_pointer_v1_events[] = { - { "relative_motion", "uuffff", relative_pointer_unstable_v1_types + 0 }, + { "relative_motion", "uuffff", relative_pointer_unstable_v1_wl_rp_types + 0 }, }; -WL_PRIVATE const struct wl_interface zwp_relative_pointer_v1_interface = { +WL_EXPORT const struct wl_interface zwp_relative_pointer_v1_interface = { "zwp_relative_pointer_v1", 1, 1, zwp_relative_pointer_v1_requests, 1, zwp_relative_pointer_v1_events, diff --git a/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol.h b/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h similarity index 92% rename from raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h index 5c79482..633d084 100644 --- a/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H #define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -73,8 +73,6 @@ struct wl_pointer; struct zwp_relative_pointer_manager_v1; struct zwp_relative_pointer_v1; -#ifndef ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE -#define ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE /** * @page page_iface_zwp_relative_pointer_manager_v1 zwp_relative_pointer_manager_v1 * @section page_iface_zwp_relative_pointer_manager_v1_desc Description @@ -91,9 +89,6 @@ struct zwp_relative_pointer_v1; * given pointer. */ extern const struct wl_interface zwp_relative_pointer_manager_v1_interface; -#endif -#ifndef ZWP_RELATIVE_POINTER_V1_INTERFACE -#define ZWP_RELATIVE_POINTER_V1_INTERFACE /** * @page page_iface_zwp_relative_pointer_v1 zwp_relative_pointer_v1 * @section page_iface_zwp_relative_pointer_v1_desc Description @@ -114,7 +109,6 @@ extern const struct wl_interface zwp_relative_pointer_manager_v1_interface; * focus. */ extern const struct wl_interface zwp_relative_pointer_v1_interface; -#endif #define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY 0 #define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER 1 @@ -158,8 +152,10 @@ zwp_relative_pointer_manager_v1_get_version(struct zwp_relative_pointer_manager_ static inline void zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1, - ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_relative_pointer_manager_v1, + ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_relative_pointer_manager_v1); } /** @@ -173,8 +169,8 @@ zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1, - ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), 0, NULL, pointer); + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_relative_pointer_manager_v1, + ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, NULL, pointer); return (struct zwp_relative_pointer_v1 *) id; } @@ -286,8 +282,10 @@ zwp_relative_pointer_v1_get_version(struct zwp_relative_pointer_v1 *zwp_relative static inline void zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_v1, - ZWP_RELATIVE_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zwp_relative_pointer_v1, + ZWP_RELATIVE_POINTER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_relative_pointer_v1); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/viewporter-client-protocol-code.h b/raylib/external/glfw/src/wayland-viewporter-client-protocol.c similarity index 68% rename from raylib/external/glfw/src/viewporter-client-protocol-code.h rename to raylib/external/glfw/src/wayland-viewporter-client-protocol.c index d685858..ce05aec 100644 --- a/raylib/external/glfw/src/viewporter-client-protocol-code.h +++ b/raylib/external/glfw/src/wayland-viewporter-client-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2013-2016 Collabora, Ltd. @@ -23,25 +23,14 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface wl_surface_interface; extern const struct wl_interface wp_viewport_interface; -static const struct wl_interface *viewporter_types[] = { +static const struct wl_interface *viewporter_wl_v_types[] = { NULL, NULL, NULL, @@ -51,23 +40,23 @@ static const struct wl_interface *viewporter_types[] = { }; static const struct wl_message wp_viewporter_requests[] = { - { "destroy", "", viewporter_types + 0 }, - { "get_viewport", "no", viewporter_types + 4 }, + { "destroy", "", viewporter_wl_v_types + 0 }, + { "get_viewport", "no", viewporter_wl_v_types + 4 }, }; -WL_PRIVATE const struct wl_interface wp_viewporter_interface = { +WL_EXPORT const struct wl_interface wp_viewporter_interface = { "wp_viewporter", 1, 2, wp_viewporter_requests, 0, NULL, }; static const struct wl_message wp_viewport_requests[] = { - { "destroy", "", viewporter_types + 0 }, - { "set_source", "ffff", viewporter_types + 0 }, - { "set_destination", "ii", viewporter_types + 0 }, + { "destroy", "", viewporter_wl_v_types + 0 }, + { "set_source", "ffff", viewporter_wl_v_types + 0 }, + { "set_destination", "ii", viewporter_wl_v_types + 0 }, }; -WL_PRIVATE const struct wl_interface wp_viewport_interface = { +WL_EXPORT const struct wl_interface wp_viewport_interface = { "wp_viewport", 1, 3, wp_viewport_requests, 0, NULL, diff --git a/raylib/external/glfw/src/viewporter-client-protocol.h b/raylib/external/glfw/src/wayland-viewporter-client-protocol.h similarity index 88% rename from raylib/external/glfw/src/viewporter-client-protocol.h rename to raylib/external/glfw/src/wayland-viewporter-client-protocol.h index f286095..90a4407 100644 --- a/raylib/external/glfw/src/viewporter-client-protocol.h +++ b/raylib/external/glfw/src/wayland-viewporter-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef VIEWPORTER_CLIENT_PROTOCOL_H #define VIEWPORTER_CLIENT_PROTOCOL_H @@ -45,8 +45,6 @@ struct wl_surface; struct wp_viewport; struct wp_viewporter; -#ifndef WP_VIEWPORTER_INTERFACE -#define WP_VIEWPORTER_INTERFACE /** * @page page_iface_wp_viewporter wp_viewporter * @section page_iface_wp_viewporter_desc Description @@ -71,9 +69,6 @@ struct wp_viewporter; * surface size. */ extern const struct wl_interface wp_viewporter_interface; -#endif -#ifndef WP_VIEWPORT_INTERFACE -#define WP_VIEWPORT_INTERFACE /** * @page page_iface_wp_viewport wp_viewport * @section page_iface_wp_viewport_desc Description @@ -86,7 +81,8 @@ extern const struct wl_interface wp_viewporter_interface; * src_y, src_width, src_height), and the destination size (dst_width, * dst_height). The contents of the source rectangle are scaled to the * destination size, and content outside the source rectangle is ignored. - * This state is double-buffered, see wl_surface.commit. + * This state is double-buffered, and is applied on the next + * wl_surface.commit. * * The two parts of crop and scale state are independent: the source * rectangle, and the destination size. Initially both are unset, that @@ -125,6 +121,12 @@ extern const struct wl_interface wp_viewporter_interface; * when the surface state is applied. A NULL wl_buffer does not raise the * out_of_buffer error. * + * The x, y arguments of wl_surface.attach are applied as normal to + * the surface. They indicate how many pixels to remove from the + * surface size from the left and the top. In other words, they are + * still in the surface-local coordinate system, just like dst_width + * and dst_height are. + * * If the wl_surface associated with the wp_viewport is destroyed, * all wp_viewport requests except 'destroy' raise the protocol error * no_surface. @@ -146,7 +148,8 @@ extern const struct wl_interface wp_viewporter_interface; * src_y, src_width, src_height), and the destination size (dst_width, * dst_height). The contents of the source rectangle are scaled to the * destination size, and content outside the source rectangle is ignored. - * This state is double-buffered, see wl_surface.commit. + * This state is double-buffered, and is applied on the next + * wl_surface.commit. * * The two parts of crop and scale state are independent: the source * rectangle, and the destination size. Initially both are unset, that @@ -185,6 +188,12 @@ extern const struct wl_interface wp_viewporter_interface; * when the surface state is applied. A NULL wl_buffer does not raise the * out_of_buffer error. * + * The x, y arguments of wl_surface.attach are applied as normal to + * the surface. They indicate how many pixels to remove from the + * surface size from the left and the top. In other words, they are + * still in the surface-local coordinate system, just like dst_width + * and dst_height are. + * * If the wl_surface associated with the wp_viewport is destroyed, * all wp_viewport requests except 'destroy' raise the protocol error * no_surface. @@ -194,7 +203,6 @@ extern const struct wl_interface wp_viewporter_interface; * on the next wl_surface.commit. */ extern const struct wl_interface wp_viewport_interface; -#endif #ifndef WP_VIEWPORTER_ERROR_ENUM #define WP_VIEWPORTER_ERROR_ENUM @@ -249,8 +257,10 @@ wp_viewporter_get_version(struct wp_viewporter *wp_viewporter) static inline void wp_viewporter_destroy(struct wp_viewporter *wp_viewporter) { - wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter, - WP_VIEWPORTER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wp_viewporter); } /** @@ -266,8 +276,8 @@ wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surfac { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter, - WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), 0, NULL, surface); + id = wl_proxy_marshal_constructor((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, NULL, surface); return (struct wp_viewport *) id; } @@ -341,8 +351,10 @@ wp_viewport_get_version(struct wp_viewport *wp_viewport) static inline void wp_viewport_destroy(struct wp_viewport *wp_viewport) { - wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, - WP_VIEWPORT_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wp_viewport); } /** @@ -357,13 +369,14 @@ wp_viewport_destroy(struct wp_viewport *wp_viewport) * or negative, or x or y are negative, raise the bad_value protocol * error. * - * The crop and scale state is double-buffered, see wl_surface.commit. + * The crop and scale state is double-buffered state, and will be + * applied on the next wl_surface.commit. */ static inline void wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, - WP_VIEWPORT_SET_SOURCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, x, y, width, height); + wl_proxy_marshal((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_SOURCE, x, y, width, height); } /** @@ -378,13 +391,14 @@ wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t * contains zero or negative values raises the bad_value protocol * error. * - * The crop and scale state is double-buffered, see wl_surface.commit. + * The crop and scale state is double-buffered state, and will be + * applied on the next wl_surface.commit. */ static inline void wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, - WP_VIEWPORT_SET_DESTINATION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, width, height); + wl_proxy_marshal((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_DESTINATION, width, height); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol-code.h b/raylib/external/glfw/src/wayland-xdg-decoration-client-protocol.c similarity index 82% rename from raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol-code.h rename to raylib/external/glfw/src/wayland-xdg-decoration-client-protocol.c index 85496af..e95c405 100644 --- a/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol-code.h +++ b/raylib/external/glfw/src/wayland-xdg-decoration-client-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2018 Simon Ser @@ -23,21 +23,10 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface xdg_toplevel_interface; extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; @@ -52,7 +41,7 @@ static const struct wl_message zxdg_decoration_manager_v1_requests[] = { { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 }, }; -WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = { +WL_EXPORT const struct wl_interface zxdg_decoration_manager_v1_interface = { "zxdg_decoration_manager_v1", 1, 2, zxdg_decoration_manager_v1_requests, 0, NULL, @@ -68,7 +57,7 @@ static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { { "configure", "u", xdg_decoration_unstable_v1_types + 0 }, }; -WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = { +WL_EXPORT const struct wl_interface zxdg_toplevel_decoration_v1_interface = { "zxdg_toplevel_decoration_v1", 1, 3, zxdg_toplevel_decoration_v1_requests, 1, zxdg_toplevel_decoration_v1_events, diff --git a/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol.h b/raylib/external/glfw/src/wayland-xdg-decoration-client-protocol.h similarity index 86% rename from raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/wayland-xdg-decoration-client-protocol.h index 217af20..a2eebd7 100644 --- a/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/wayland-xdg-decoration-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H #define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -45,8 +45,6 @@ struct xdg_toplevel; struct zxdg_decoration_manager_v1; struct zxdg_toplevel_decoration_v1; -#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE -#define ZXDG_DECORATION_MANAGER_V1_INTERFACE /** * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1 * @section page_iface_zxdg_decoration_manager_v1_desc Description @@ -103,9 +101,6 @@ struct zxdg_toplevel_decoration_v1; * interface version number is reset. */ extern const struct wl_interface zxdg_decoration_manager_v1_interface; -#endif -#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE -#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE /** * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1 * @section page_iface_zxdg_toplevel_decoration_v1_desc Description @@ -130,7 +125,6 @@ extern const struct wl_interface zxdg_decoration_manager_v1_interface; * xdg_toplevel. */ extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; -#endif #define ZXDG_DECORATION_MANAGER_V1_DESTROY 0 #define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1 @@ -174,8 +168,10 @@ zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_d static inline void zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, - ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zxdg_decoration_manager_v1); } /** @@ -194,8 +190,8 @@ zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manage { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, - ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel); + id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, NULL, toplevel); return (struct zxdg_toplevel_decoration_v1 *) id; } @@ -215,10 +211,6 @@ enum zxdg_toplevel_decoration_v1_error { * xdg_toplevel destroyed before the decoration object */ ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2, - /** - * invalid mode - */ - ZXDG_TOPLEVEL_DECORATION_V1_ERROR_INVALID_MODE = 3, }; #endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */ @@ -248,12 +240,13 @@ enum zxdg_toplevel_decoration_v1_mode { */ struct zxdg_toplevel_decoration_v1_listener { /** - * notify a decoration mode change + * suggest a surface change * - * The configure event configures the effective decoration mode. - * The configured state should not be applied immediately. Clients - * must send an ack_configure in response to this event. See - * xdg_surface.configure and xdg_surface.ack_configure for details. + * The configure event asks the client to change its decoration + * mode. The configured state should not be applied immediately. + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. * * A configure event can be sent at any time. The specified mode * must be obeyed by the client. @@ -326,8 +319,10 @@ zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg static inline void zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, - ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zxdg_toplevel_decoration_v1); } /** @@ -337,7 +332,7 @@ zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_top * that the client prefers the provided decoration mode. * * After requesting a decoration mode, the compositor will respond by - * emitting an xdg_surface.configure event. The client should then update + * emitting a xdg_surface.configure event. The client should then update * its content, drawing it without decorations if the received mode is * server-side decorations. The client must also acknowledge the configure * when committing the new content (see xdg_surface.ack_configure). @@ -346,20 +341,17 @@ zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_top * different mode instead. * * Clients whose decoration mode depend on the xdg_toplevel state may send - * a set_mode request in response to an xdg_surface.configure event and wait + * a set_mode request in response to a xdg_surface.configure event and wait * for the next xdg_surface.configure event to prevent unwanted state. * Such clients are responsible for preventing configure loops and must * make sure not to send multiple successive set_mode requests with the * same decoration mode. - * - * If an invalid mode is supplied by the client, the invalid_mode protocol - * error is raised by the compositor. */ static inline void zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) { - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, - ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode); + wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, mode); } /** @@ -373,8 +365,8 @@ zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_to static inline void zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) { - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, - ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0); + wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/xdg-shell-client-protocol-code.h b/raylib/external/glfw/src/wayland-xdg-shell-client-protocol.c similarity index 50% rename from raylib/external/glfw/src/xdg-shell-client-protocol-code.h rename to raylib/external/glfw/src/wayland-xdg-shell-client-protocol.c index d698c2c..d7d11ab 100644 --- a/raylib/external/glfw/src/xdg-shell-client-protocol-code.h +++ b/raylib/external/glfw/src/wayland-xdg-shell-client-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2008-2013 Kristian Høgsberg @@ -28,21 +28,10 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface wl_output_interface; extern const struct wl_interface wl_seat_interface; extern const struct wl_interface wl_surface_interface; @@ -51,7 +40,7 @@ extern const struct wl_interface xdg_positioner_interface; extern const struct wl_interface xdg_surface_interface; extern const struct wl_interface xdg_toplevel_interface; -static const struct wl_interface *xdg_shell_types[] = { +static const struct wl_interface *xdg_shell_wl_xs_types[] = { NULL, NULL, NULL, @@ -81,103 +70,101 @@ static const struct wl_interface *xdg_shell_types[] = { }; static const struct wl_message xdg_wm_base_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "create_positioner", "n", xdg_shell_types + 4 }, - { "get_xdg_surface", "no", xdg_shell_types + 5 }, - { "pong", "u", xdg_shell_types + 0 }, + { "destroy", "", xdg_shell_wl_xs_types + 0 }, + { "create_positioner", "n", xdg_shell_wl_xs_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_wl_xs_types + 5 }, + { "pong", "u", xdg_shell_wl_xs_types + 0 }, }; static const struct wl_message xdg_wm_base_events[] = { - { "ping", "u", xdg_shell_types + 0 }, + { "ping", "u", xdg_shell_wl_xs_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { - "xdg_wm_base", 6, +WL_EXPORT const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 3, 4, xdg_wm_base_requests, 1, xdg_wm_base_events, }; static const struct wl_message xdg_positioner_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "set_size", "ii", xdg_shell_types + 0 }, - { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, - { "set_anchor", "u", xdg_shell_types + 0 }, - { "set_gravity", "u", xdg_shell_types + 0 }, - { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, - { "set_offset", "ii", xdg_shell_types + 0 }, - { "set_reactive", "3", xdg_shell_types + 0 }, - { "set_parent_size", "3ii", xdg_shell_types + 0 }, - { "set_parent_configure", "3u", xdg_shell_types + 0 }, + { "destroy", "", xdg_shell_wl_xs_types + 0 }, + { "set_size", "ii", xdg_shell_wl_xs_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_wl_xs_types + 0 }, + { "set_anchor", "u", xdg_shell_wl_xs_types + 0 }, + { "set_gravity", "u", xdg_shell_wl_xs_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_wl_xs_types + 0 }, + { "set_offset", "ii", xdg_shell_wl_xs_types + 0 }, + { "set_reactive", "3", xdg_shell_wl_xs_types + 0 }, + { "set_parent_size", "3ii", xdg_shell_wl_xs_types + 0 }, + { "set_parent_configure", "3u", xdg_shell_wl_xs_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_positioner_interface = { - "xdg_positioner", 6, +WL_EXPORT const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 3, 10, xdg_positioner_requests, 0, NULL, }; static const struct wl_message xdg_surface_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "get_toplevel", "n", xdg_shell_types + 7 }, - { "get_popup", "n?oo", xdg_shell_types + 8 }, - { "set_window_geometry", "iiii", xdg_shell_types + 0 }, - { "ack_configure", "u", xdg_shell_types + 0 }, + { "destroy", "", xdg_shell_wl_xs_types + 0 }, + { "get_toplevel", "n", xdg_shell_wl_xs_types + 7 }, + { "get_popup", "n?oo", xdg_shell_wl_xs_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_wl_xs_types + 0 }, + { "ack_configure", "u", xdg_shell_wl_xs_types + 0 }, }; static const struct wl_message xdg_surface_events[] = { - { "configure", "u", xdg_shell_types + 0 }, + { "configure", "u", xdg_shell_wl_xs_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_surface_interface = { - "xdg_surface", 6, +WL_EXPORT const struct wl_interface xdg_surface_interface = { + "xdg_surface", 3, 5, xdg_surface_requests, 1, xdg_surface_events, }; static const struct wl_message xdg_toplevel_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "set_parent", "?o", xdg_shell_types + 11 }, - { "set_title", "s", xdg_shell_types + 0 }, - { "set_app_id", "s", xdg_shell_types + 0 }, - { "show_window_menu", "ouii", xdg_shell_types + 12 }, - { "move", "ou", xdg_shell_types + 16 }, - { "resize", "ouu", xdg_shell_types + 18 }, - { "set_max_size", "ii", xdg_shell_types + 0 }, - { "set_min_size", "ii", xdg_shell_types + 0 }, - { "set_maximized", "", xdg_shell_types + 0 }, - { "unset_maximized", "", xdg_shell_types + 0 }, - { "set_fullscreen", "?o", xdg_shell_types + 21 }, - { "unset_fullscreen", "", xdg_shell_types + 0 }, - { "set_minimized", "", xdg_shell_types + 0 }, + { "destroy", "", xdg_shell_wl_xs_types + 0 }, + { "set_parent", "?o", xdg_shell_wl_xs_types + 11 }, + { "set_title", "s", xdg_shell_wl_xs_types + 0 }, + { "set_app_id", "s", xdg_shell_wl_xs_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_wl_xs_types + 12 }, + { "move", "ou", xdg_shell_wl_xs_types + 16 }, + { "resize", "ouu", xdg_shell_wl_xs_types + 18 }, + { "set_max_size", "ii", xdg_shell_wl_xs_types + 0 }, + { "set_min_size", "ii", xdg_shell_wl_xs_types + 0 }, + { "set_maximized", "", xdg_shell_wl_xs_types + 0 }, + { "unset_maximized", "", xdg_shell_wl_xs_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_wl_xs_types + 21 }, + { "unset_fullscreen", "", xdg_shell_wl_xs_types + 0 }, + { "set_minimized", "", xdg_shell_wl_xs_types + 0 }, }; static const struct wl_message xdg_toplevel_events[] = { - { "configure", "iia", xdg_shell_types + 0 }, - { "close", "", xdg_shell_types + 0 }, - { "configure_bounds", "4ii", xdg_shell_types + 0 }, - { "wm_capabilities", "5a", xdg_shell_types + 0 }, + { "configure", "iia", xdg_shell_wl_xs_types + 0 }, + { "close", "", xdg_shell_wl_xs_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { - "xdg_toplevel", 6, +WL_EXPORT const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 3, 14, xdg_toplevel_requests, - 4, xdg_toplevel_events, + 2, xdg_toplevel_events, }; static const struct wl_message xdg_popup_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "grab", "ou", xdg_shell_types + 22 }, - { "reposition", "3ou", xdg_shell_types + 24 }, + { "destroy", "", xdg_shell_wl_xs_types + 0 }, + { "grab", "ou", xdg_shell_wl_xs_types + 22 }, + { "reposition", "3ou", xdg_shell_wl_xs_types + 24 }, }; static const struct wl_message xdg_popup_events[] = { - { "configure", "iiii", xdg_shell_types + 0 }, - { "popup_done", "", xdg_shell_types + 0 }, - { "repositioned", "3u", xdg_shell_types + 0 }, + { "configure", "iiii", xdg_shell_wl_xs_types + 0 }, + { "popup_done", "", xdg_shell_wl_xs_types + 0 }, + { "repositioned", "3u", xdg_shell_wl_xs_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_popup_interface = { - "xdg_popup", 6, +WL_EXPORT const struct wl_interface xdg_popup_interface = { + "xdg_popup", 3, 3, xdg_popup_requests, 3, xdg_popup_events, }; diff --git a/raylib/external/glfw/src/xdg-shell-client-protocol.h b/raylib/external/glfw/src/wayland-xdg-shell-client-protocol.h similarity index 72% rename from raylib/external/glfw/src/xdg-shell-client-protocol.h rename to raylib/external/glfw/src/wayland-xdg-shell-client-protocol.h index 1f077b4..6e80367 100644 --- a/raylib/external/glfw/src/xdg-shell-client-protocol.h +++ b/raylib/external/glfw/src/wayland-xdg-shell-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.23.1 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef XDG_SHELL_CLIENT_PROTOCOL_H #define XDG_SHELL_CLIENT_PROTOCOL_H @@ -58,8 +58,6 @@ struct xdg_surface; struct xdg_toplevel; struct xdg_wm_base; -#ifndef XDG_WM_BASE_INTERFACE -#define XDG_WM_BASE_INTERFACE /** * @page page_iface_xdg_wm_base xdg_wm_base * @section page_iface_xdg_wm_base_desc Description @@ -82,9 +80,6 @@ struct xdg_wm_base; * creating transient windows such as popup menus. */ extern const struct wl_interface xdg_wm_base_interface; -#endif -#ifndef XDG_POSITIONER_INTERFACE -#define XDG_POSITIONER_INTERFACE /** * @page page_iface_xdg_positioner xdg_positioner * @section page_iface_xdg_positioner_desc Description @@ -107,7 +102,7 @@ extern const struct wl_interface xdg_wm_base_interface; * For an xdg_positioner object to be considered complete, it must have a * non-zero size set by set_size, and a non-zero anchor rectangle set by * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an invalid_positioner error. + * positioning a surface raises an error. * @section page_iface_xdg_positioner_api API * See @ref iface_xdg_positioner. */ @@ -132,12 +127,9 @@ extern const struct wl_interface xdg_wm_base_interface; * For an xdg_positioner object to be considered complete, it must have a * non-zero size set by set_size, and a non-zero anchor rectangle set by * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an invalid_positioner error. + * positioning a surface raises an error. */ extern const struct wl_interface xdg_positioner_interface; -#endif -#ifndef XDG_SURFACE_INTERFACE -#define XDG_SURFACE_INTERFACE /** * @page page_iface_xdg_surface xdg_surface * @section page_iface_xdg_surface_desc Description @@ -167,14 +159,6 @@ extern const struct wl_interface xdg_positioner_interface; * manipulate a buffer prior to the first xdg_surface.configure call must * also be treated as errors. * - * After creating a role-specific object and setting it up (e.g. by sending - * the title, app ID, size constraints, parent, etc), the client must - * perform an initial commit without any buffer attached. The compositor - * will reply with initial wl_surface state such as - * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure - * event. The client must acknowledge it and is then allowed to attach a - * buffer to map the surface. - * * Mapping an xdg_surface-based role surface is defined as making it * possible for the surface to be shown by the compositor. Note that * a mapped surface is not guaranteed to be visible once it is mapped. @@ -188,8 +172,7 @@ extern const struct wl_interface xdg_positioner_interface; * * A newly-unmapped surface is considered to have met condition (1) out * of the 3 required conditions for mapping a surface if its role surface - * has not been destroyed, i.e. the client must perform the initial commit - * again before attaching a buffer. + * has not been destroyed. * @section page_iface_xdg_surface_api API * See @ref iface_xdg_surface. */ @@ -221,14 +204,6 @@ extern const struct wl_interface xdg_positioner_interface; * manipulate a buffer prior to the first xdg_surface.configure call must * also be treated as errors. * - * After creating a role-specific object and setting it up (e.g. by sending - * the title, app ID, size constraints, parent, etc), the client must - * perform an initial commit without any buffer attached. The compositor - * will reply with initial wl_surface state such as - * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure - * event. The client must acknowledge it and is then allowed to attach a - * buffer to map the surface. - * * Mapping an xdg_surface-based role surface is defined as making it * possible for the surface to be shown by the compositor. Note that * a mapped surface is not guaranteed to be visible once it is mapped. @@ -242,13 +217,9 @@ extern const struct wl_interface xdg_positioner_interface; * * A newly-unmapped surface is considered to have met condition (1) out * of the 3 required conditions for mapping a surface if its role surface - * has not been destroyed, i.e. the client must perform the initial commit - * again before attaching a buffer. + * has not been destroyed. */ extern const struct wl_interface xdg_surface_interface; -#endif -#ifndef XDG_TOPLEVEL_INTERFACE -#define XDG_TOPLEVEL_INTERFACE /** * @page page_iface_xdg_toplevel xdg_toplevel * @section page_iface_xdg_toplevel_desc Description @@ -259,19 +230,11 @@ extern const struct wl_interface xdg_surface_interface; * id, and well as trigger user interactive operations such as interactive * resize and move. * - * A xdg_toplevel by default is responsible for providing the full intended - * visual representation of the toplevel, which depending on the window - * state, may mean things like a title bar, window controls and drop shadow. - * * Unmapping an xdg_toplevel means that the surface cannot be shown * by the compositor until it is explicitly mapped again. * All active operations (e.g., move, resize) are canceled and all * attributes (e.g. title, state, stacking, ...) are discarded for - * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to - * the state it had right after xdg_surface.get_toplevel. The client - * can re-map the toplevel by performing a commit without any buffer - * attached, waiting for a configure event and handling it as usual (see - * xdg_surface description). + * an xdg_toplevel surface when it is unmapped. * * Attaching a null buffer to a toplevel unmaps the surface. * @section page_iface_xdg_toplevel_api API @@ -286,26 +249,15 @@ extern const struct wl_interface xdg_surface_interface; * id, and well as trigger user interactive operations such as interactive * resize and move. * - * A xdg_toplevel by default is responsible for providing the full intended - * visual representation of the toplevel, which depending on the window - * state, may mean things like a title bar, window controls and drop shadow. - * * Unmapping an xdg_toplevel means that the surface cannot be shown * by the compositor until it is explicitly mapped again. * All active operations (e.g., move, resize) are canceled and all * attributes (e.g. title, state, stacking, ...) are discarded for - * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to - * the state it had right after xdg_surface.get_toplevel. The client - * can re-map the toplevel by performing a commit without any buffer - * attached, waiting for a configure event and handling it as usual (see - * xdg_surface description). + * an xdg_toplevel surface when it is unmapped. * * Attaching a null buffer to a toplevel unmaps the surface. */ extern const struct wl_interface xdg_toplevel_interface; -#endif -#ifndef XDG_POPUP_INTERFACE -#define XDG_POPUP_INTERFACE /** * @page page_iface_xdg_popup xdg_popup * @section page_iface_xdg_popup_desc Description @@ -366,7 +318,6 @@ extern const struct wl_interface xdg_toplevel_interface; * for the xdg_popup state to take effect. */ extern const struct wl_interface xdg_popup_interface; -#endif #ifndef XDG_WM_BASE_ERROR_ENUM #define XDG_WM_BASE_ERROR_ENUM @@ -395,10 +346,6 @@ enum xdg_wm_base_error { * the client provided an invalid positioner */ XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, - /** - * the client didn’t respond to a ping event in time - */ - XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, }; #endif /* XDG_WM_BASE_ERROR_ENUM */ @@ -418,9 +365,7 @@ struct xdg_wm_base_listener { * Compositors can use this to determine if the client is still * alive. It's unspecified what will happen if the client doesn't * respond to the ping request, or in what timeframe. Clients - * should try to respond in a reasonable amount of time. The - * “unresponsive” error is provided for compositors that wish - * to disconnect unresponsive clients. + * should try to respond in a reasonable amount of time. * * A compositor is free to ping in any way it wants, but a client * must always respond to any xdg_wm_base object it created. @@ -496,13 +441,15 @@ xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) * * Destroying a bound xdg_wm_base object while there are surfaces * still alive created by this xdg_wm_base object instance is illegal - * and will result in a defunct_surfaces error. + * and will result in a protocol error. */ static inline void xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_wm_base); } /** @@ -517,8 +464,8 @@ xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL); + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, NULL); return (struct xdg_positioner *) id; } @@ -528,9 +475,7 @@ xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) * * This creates an xdg_surface for the given surface. While xdg_surface * itself is not a role, the corresponding surface may only be assigned - * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is - * illegal to create an xdg_surface for a wl_surface which already has an - * assigned role and this will result in a role error. + * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. * * This creates an xdg_surface for the given surface. An xdg_surface is * used as basis to define a role to a given surface, such as xdg_toplevel @@ -545,8 +490,8 @@ xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface * { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface); + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface); return (struct xdg_surface *) id; } @@ -555,14 +500,13 @@ xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface * * @ingroup iface_xdg_wm_base * * A client must respond to a ping event with a pong request or - * the client may be deemed unresponsive. See xdg_wm_base.ping - * and xdg_wm_base.error.unresponsive. + * the client may be deemed unresponsive. See xdg_wm_base.ping. */ static inline void xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial); + wl_proxy_marshal((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_PONG, serial); } #ifndef XDG_POSITIONER_ERROR_ENUM @@ -609,106 +553,17 @@ enum xdg_positioner_gravity { #define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM /** * @ingroup iface_xdg_positioner - * constraint adjustments + * vertically resize the surface * - * The constraint adjustment value define ways the compositor will adjust - * the position of the surface, if the unadjusted position would result - * in the surface being partly constrained. - * - * Whether a surface is considered 'constrained' is left to the compositor - * to determine. For example, the surface may be partly outside the - * compositor's defined 'work area', thus necessitating the child surface's - * position be adjusted until it is entirely inside the work area. - * - * The adjustments can be combined, according to a defined precedence: 1) - * Flip, 2) Slide, 3) Resize. + * Resize the surface vertically so that it is completely unconstrained. */ enum xdg_positioner_constraint_adjustment { - /** - * don't move the child surface when constrained - * - * Don't alter the surface position even if it is constrained on - * some axis, for example partially outside the edge of an output. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, - /** - * move along the x axis until unconstrained - * - * Slide the surface along the x axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the x - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the x axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, - /** - * move along the y axis until unconstrained - * - * Slide the surface along the y axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the y - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the y axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, - /** - * invert the anchor and gravity on the x axis - * - * Invert the anchor and gravity on the x axis if the surface is - * constrained on the x axis. For example, if the left edge of the - * surface is constrained, the gravity is 'left' and the anchor is - * 'left', change the gravity to 'right' and the anchor to 'right'. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_x adjustment will be the one - * before the adjustment. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, - /** - * invert the anchor and gravity on the y axis - * - * Invert the anchor and gravity on the y axis if the surface is - * constrained on the y axis. For example, if the bottom edge of - * the surface is constrained, the gravity is 'bottom' and the - * anchor is 'bottom', change the gravity to 'top' and the anchor - * to 'top'. - * - * The adjusted position is calculated given the original anchor - * rectangle and offset, but with the new flipped anchor and - * gravity values. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_y adjustment will be the one - * before the adjustment. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, - /** - * horizontally resize the surface - * - * Resize the surface horizontally so that it is completely - * unconstrained. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, - /** - * vertically resize the surface - * - * Resize the surface vertically so that it is completely - * unconstrained. - */ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, }; #endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ @@ -794,8 +649,10 @@ xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) static inline void xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_positioner); } /** @@ -810,8 +667,8 @@ xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) static inline void xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_SIZE, width, height); } /** @@ -831,8 +688,8 @@ xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, in static inline void xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR_RECT, x, y, width, height); } /** @@ -848,8 +705,8 @@ xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, static inline void xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR, anchor); } /** @@ -860,14 +717,13 @@ xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor * specified (e.g. 'bottom_right' or 'top_left'), then the child surface * will be placed towards the specified gravity; otherwise, the child * surface will be centered over the anchor point on any axis that had no - * gravity specified. If the gravity is not in the ‘gravity’ enum, an - * invalid_input error is raised. + * gravity specified. */ static inline void xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_GRAVITY, gravity); } /** @@ -890,8 +746,8 @@ xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravi static inline void xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, constraint_adjustment); } /** @@ -912,8 +768,8 @@ xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, static inline void xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_OFFSET, x, y); } /** @@ -929,8 +785,8 @@ xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int3 static inline void xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_REACTIVE); } /** @@ -947,14 +803,14 @@ xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) static inline void xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_SIZE, parent_width, parent_height); } /** * @ingroup iface_xdg_positioner * - * Set the serial of an xdg_surface.configure event this positioner will be + * Set the serial of a xdg_surface.configure event this positioner will be * used in response to. The compositor may use this information together * with set_parent_size to determine what future state the popup should be * constrained using. @@ -962,37 +818,16 @@ xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t pa static inline void xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial); + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_CONFIGURE, serial); } #ifndef XDG_SURFACE_ERROR_ENUM #define XDG_SURFACE_ERROR_ENUM enum xdg_surface_error { - /** - * Surface was not fully constructed - */ XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, - /** - * Surface was already constructed - */ XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, - /** - * Attaching a buffer to an unconfigured surface - */ XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, - /** - * Invalid serial number when acking a configure event - */ - XDG_SURFACE_ERROR_INVALID_SERIAL = 4, - /** - * Width or height was zero or negative - */ - XDG_SURFACE_ERROR_INVALID_SIZE = 5, - /** - * Surface was destroyed before its role object - */ - XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, }; #endif /* XDG_SURFACE_ERROR_ENUM */ @@ -1097,14 +932,15 @@ xdg_surface_get_version(struct xdg_surface *xdg_surface) * @ingroup iface_xdg_surface * * Destroy the xdg_surface object. An xdg_surface must only be destroyed - * after its role object has been destroyed, otherwise - * a defunct_role_object error is raised. + * after its role object has been destroyed. */ static inline void xdg_surface_destroy(struct xdg_surface *xdg_surface) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_surface); } /** @@ -1121,8 +957,8 @@ xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL); + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, NULL); return (struct xdg_toplevel *) id; } @@ -1144,8 +980,8 @@ xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *paren { struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner); + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_POPUP, &xdg_popup_interface, NULL, parent, positioner); return (struct xdg_popup *) id; } @@ -1158,7 +994,8 @@ xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *paren * portions like drop-shadows which should be ignored for the * purposes of aligning, placing and constraining windows. * - * The window geometry is double-buffered state, see wl_surface.commit. + * The window geometry is double buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. * * When maintaining a position, the compositor should treat the (x, y) * coordinate of the window geometry as the top left corner of the window. @@ -1174,28 +1011,19 @@ xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *paren * commit. This unset is meant for extremely simple clients. * * The arguments are given in the surface-local coordinate space of - * the wl_surface associated with this xdg_surface, and may extend outside - * of the wl_surface itself to mark parts of the subsurface tree as part of - * the window geometry. + * the wl_surface associated with this xdg_surface. * - * When applied, the effective window geometry will be the set window - * geometry clamped to the bounding rectangle of the combined - * geometry of the surface of the xdg_surface and the associated + * The width and height must be greater than zero. Setting an invalid size + * will raise an error. When applied, the effective window geometry will be + * the set window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the associated * subsurfaces. - * - * The effective geometry will not be recalculated unless a new call to - * set_window_geometry is done and the new pending surface state is - * subsequently applied. - * - * The width and height of the effective window geometry must be - * greater than zero. Setting an invalid size will raise an - * invalid_size error. */ static inline void xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height); + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height); } /** @@ -1212,8 +1040,6 @@ xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int3 * * If the client receives multiple configure events before it * can respond to one, it only has to ack the last configure event. - * Acking a configure event that was never sent raises an invalid_serial - * error. * * A client is not required to commit immediately after sending * an ack_configure request - it may even ack_configure several times @@ -1222,43 +1048,14 @@ xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int3 * A client may send multiple ack_configure requests before committing, but * only the last request sent before a commit indicates which configure * event the client really is responding to. - * - * Sending an ack_configure request consumes the serial number sent with - * the request, as well as serial numbers sent by all configure events - * sent on this xdg_surface prior to the configure event referenced by - * the committed serial. - * - * It is an error to issue multiple ack_configure requests referencing a - * serial from the same configure event, or to issue an ack_configure - * request referencing a serial from a configure event issued before the - * event identified by the last ack_configure request for the same - * xdg_surface. Doing so will raise an invalid_serial error. */ static inline void xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial); + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, serial); } -#ifndef XDG_TOPLEVEL_ERROR_ENUM -#define XDG_TOPLEVEL_ERROR_ENUM -enum xdg_toplevel_error { - /** - * provided value is not a valid variant of the resize_edge enum - */ - XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, - /** - * invalid parent toplevel - */ - XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, - /** - * client provided an invalid min or max size - */ - XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, -}; -#endif /* XDG_TOPLEVEL_ERROR_ENUM */ - #ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM #define XDG_TOPLEVEL_RESIZE_EDGE_ENUM /** @@ -1285,111 +1082,44 @@ enum xdg_toplevel_resize_edge { #define XDG_TOPLEVEL_STATE_ENUM /** * @ingroup iface_xdg_toplevel - * types of state on the surface + * the surface is tiled * - * The different state values used on the surface. This is designed for - * state values like maximized, fullscreen. It is paired with the - * configure event to ensure that both the client and the compositor - * setting the state can be synchronized. - * - * States set in this way are double-buffered, see wl_surface.commit. + * The window is currently in a tiled layout and the bottom edge is + * considered to be adjacent to another part of the tiling grid. */ enum xdg_toplevel_state { /** * the surface is maximized - * the surface is maximized - * - * The surface is maximized. The window geometry specified in the - * configure event must be obeyed by the client, or the - * xdg_wm_base.invalid_surface_state error is raised. - * - * The client should draw without shadow or other decoration - * outside of the window geometry. */ XDG_TOPLEVEL_STATE_MAXIMIZED = 1, /** * the surface is fullscreen - * the surface is fullscreen - * - * The surface is fullscreen. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. For a surface to cover the whole fullscreened area, - * the geometry dimensions must be obeyed by the client. For more - * details, see xdg_toplevel.set_fullscreen. */ XDG_TOPLEVEL_STATE_FULLSCREEN = 2, /** * the surface is being resized - * the surface is being resized - * - * The surface is being resized. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. Clients that have aspect ratio or cell sizing - * configuration can use a smaller size, however. */ XDG_TOPLEVEL_STATE_RESIZING = 3, /** * the surface is now activated - * the surface is now activated - * - * Client window decorations should be painted as if the window - * is active. Do not assume this means that the window actually has - * keyboard or pointer focus. */ XDG_TOPLEVEL_STATE_ACTIVATED = 4, /** - * the surface’s left edge is tiled - * - * The window is currently in a tiled layout and the left edge is - * considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the left edge. * @since 2 */ XDG_TOPLEVEL_STATE_TILED_LEFT = 5, /** - * the surface’s right edge is tiled - * - * The window is currently in a tiled layout and the right edge - * is considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the right edge. * @since 2 */ XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, /** - * the surface’s top edge is tiled - * - * The window is currently in a tiled layout and the top edge is - * considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the top edge. * @since 2 */ XDG_TOPLEVEL_STATE_TILED_TOP = 7, /** - * the surface’s bottom edge is tiled - * - * The window is currently in a tiled layout and the bottom edge - * is considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the bottom edge. * @since 2 */ XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, - /** - * surface repaint is suspended - * - * The surface is currently not ordinarily being repainted; for - * example because its content is occluded by another window, or - * its outputs are switched off due to screen locking. - * @since 6 - */ - XDG_TOPLEVEL_STATE_SUSPENDED = 9, }; /** * @ingroup iface_xdg_toplevel @@ -1407,34 +1137,8 @@ enum xdg_toplevel_state { * @ingroup iface_xdg_toplevel */ #define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 #endif /* XDG_TOPLEVEL_STATE_ENUM */ -#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM -#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM -enum xdg_toplevel_wm_capabilities { - /** - * show_window_menu is available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, - /** - * set_maximized and unset_maximized are available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, - /** - * set_fullscreen and unset_fullscreen are available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, - /** - * set_minimized is available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, -}; -#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ - /** * @ingroup iface_xdg_toplevel * @struct xdg_toplevel_listener @@ -1484,61 +1188,6 @@ struct xdg_toplevel_listener { */ void (*close)(void *data, struct xdg_toplevel *xdg_toplevel); - /** - * recommended window geometry bounds - * - * The configure_bounds event may be sent prior to a - * xdg_toplevel.configure event to communicate the bounds a window - * geometry size is recommended to constrain to. - * - * The passed width and height are in surface coordinate space. If - * width and height are 0, it means bounds is unknown and - * equivalent to as if no configure_bounds event was ever sent for - * this surface. - * - * The bounds can for example correspond to the size of a monitor - * excluding any panels or other shell components, so that a - * surface isn't created in a way that it cannot fit. - * - * The bounds may change at any point, and in such a case, a new - * xdg_toplevel.configure_bounds will be sent, followed by - * xdg_toplevel.configure and xdg_surface.configure. - * @since 4 - */ - void (*configure_bounds)(void *data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height); - /** - * compositor capabilities - * - * This event advertises the capabilities supported by the - * compositor. If a capability isn't supported, clients should hide - * or disable the UI elements that expose this functionality. For - * instance, if the compositor doesn't advertise support for - * minimized toplevels, a button triggering the set_minimized - * request should not be displayed. - * - * The compositor will ignore requests it doesn't support. For - * instance, a compositor which doesn't advertise support for - * minimized will ignore set_minimized requests. - * - * Compositors must send this event once before the first - * xdg_surface.configure event. When the capabilities change, - * compositors must send this event again and then send an - * xdg_surface.configure event. - * - * The configured state should not be applied immediately. See - * xdg_surface.configure for details. - * - * The capabilities are sent as an array of 32-bit unsigned - * integers in native endianness. - * @param capabilities array of 32-bit capabilities - * @since 5 - */ - void (*wm_capabilities)(void *data, - struct xdg_toplevel *xdg_toplevel, - struct wl_array *capabilities); }; /** @@ -1575,14 +1224,6 @@ xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, * @ingroup iface_xdg_toplevel */ #define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 /** * @ingroup iface_xdg_toplevel @@ -1670,8 +1311,10 @@ xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) static inline void xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_toplevel); } /** @@ -1680,29 +1323,25 @@ xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) * Set the "parent" of this surface. This surface should be stacked * above the parent surface and all other ancestor surfaces. * - * Parent surfaces should be set on dialogs, toolboxes, or other + * Parent windows should be set on dialogs, toolboxes, or other * "auxiliary" surfaces, so that the parent is raised when the dialog * is raised. * - * Setting a null parent for a child surface unsets its parent. Setting - * a null parent for a surface which currently has no parent is a no-op. + * Setting a null parent for a child window removes any parent-child + * relationship for the child. Setting a null parent for a window which + * currently has no parent is a no-op. * - * Only mapped surfaces can have child surfaces. Setting a parent which - * is not mapped is equivalent to setting a null parent. If a surface - * becomes unmapped, its children's parent is set to the parent of - * the now-unmapped surface. If the now-unmapped surface has no parent, - * its children's parent is unset. If the now-unmapped surface becomes - * mapped again, its parent-child relationship is not restored. - * - * The parent toplevel must not be one of the child toplevel's - * descendants, and the parent must be different from the child toplevel, - * otherwise the invalid_parent protocol error is raised. + * If the parent is unmapped then its children are managed as + * though the parent of the now-unmapped parent has become the + * parent of this surface. If no parent exists for the now-unmapped + * parent then the children are managed as though they have no + * parent surface. */ static inline void xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_PARENT, parent); } /** @@ -1719,8 +1358,8 @@ xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel * static inline void xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_TITLE, title); } /** @@ -1748,13 +1387,13 @@ xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) * application identifiers and how they relate to well-known D-Bus * names and .desktop files. * - * [0] https://standards.freedesktop.org/desktop-entry-spec/ + * [0] http://standards.freedesktop.org/desktop-entry-spec/ */ static inline void xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_APP_ID, app_id); } /** @@ -1767,8 +1406,7 @@ xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) * This request asks the compositor to pop up such a window menu at * the given position, relative to the local surface coordinates of * the parent surface. There are no guarantees as to what menu items - * the window menu contains, or even if a window menu will be drawn - * at all. + * the window menu contains. * * This request must be used in response to some sort of user action * like a button press, key press, or touch down event. @@ -1776,8 +1414,8 @@ xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) static inline void xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SHOW_WINDOW_MENU, seat, serial, x, y); } /** @@ -1803,8 +1441,8 @@ xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat static inline void xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_MOVE, seat, serial); } /** @@ -1834,19 +1472,18 @@ xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint3 * guarantee that the device focus will return when the resize is * completed. * - * The edges parameter specifies how the surface should be resized, and - * is one of the values of the resize_edge enum. Values not matching - * a variant of the enum will cause the invalid_resize_edge protocol error. - * The compositor may use this information to update the surface position - * for example when dragging the top left corner. The compositor may also - * use this information to adapt its behavior, e.g. choose an appropriate - * cursor image. + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. The compositor + * may use this information to update the surface position for + * example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an + * appropriate cursor image. */ static inline void xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_RESIZE, seat, serial, edges); } /** @@ -1860,7 +1497,8 @@ xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uin * The width and height arguments are in window geometry coordinates. * See xdg_surface.set_window_geometry. * - * Values set in this way are double-buffered, see wl_surface.commit. + * Values set in this way are double-buffered. They will get applied + * on the next commit. * * The compositor can use this information to allow or disallow * different states like maximize or fullscreen and draw accurate @@ -1880,17 +1518,17 @@ xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uin * request. * * Requesting a maximum size to be smaller than the minimum size of - * a surface is illegal and will result in an invalid_size error. + * a surface is illegal and will result in a protocol error. * * The width and height must be greater than or equal to zero. Using - * strictly negative values for width or height will result in a - * invalid_size error. + * strictly negative values for width and height will result in a + * protocol error. */ static inline void xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAX_SIZE, width, height); } /** @@ -1904,7 +1542,8 @@ xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int3 * The width and height arguments are in window geometry coordinates. * See xdg_surface.set_window_geometry. * - * Values set in this way are double-buffered, see wl_surface.commit. + * Values set in this way are double-buffered. They will get applied + * on the next commit. * * The compositor can use this information to allow or disallow * different states like maximize or fullscreen and draw accurate @@ -1924,17 +1563,17 @@ xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int3 * request. * * Requesting a minimum size to be larger than the maximum size of - * a surface is illegal and will result in an invalid_size error. + * a surface is illegal and will result in a protocol error. * * The width and height must be greater than or equal to zero. Using * strictly negative values for width and height will result in a - * invalid_size error. + * protocol error. */ static inline void xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MIN_SIZE, width, height); } /** @@ -1963,8 +1602,8 @@ xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int3 static inline void xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAXIMIZED); } /** @@ -1995,8 +1634,8 @@ xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) static inline void xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_MAXIMIZED); } /** @@ -2029,8 +1668,8 @@ xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) static inline void xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_FULLSCREEN, output); } /** @@ -2057,8 +1696,8 @@ xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output static inline void xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_FULLSCREEN); } /** @@ -2076,8 +1715,8 @@ xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) static inline void xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MINIMIZED); } #ifndef XDG_POPUP_ERROR_ENUM @@ -2226,14 +1865,16 @@ xdg_popup_get_version(struct xdg_popup *xdg_popup) * This destroys the popup. Explicitly destroying the xdg_popup * object will also dismiss the popup, and unmap the surface. * - * If this xdg_popup is not the "topmost" popup, the - * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + * If this xdg_popup is not the "topmost" popup, a protocol error + * will be sent. */ static inline void xdg_popup_destroy(struct xdg_popup *xdg_popup) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, - XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY); + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_popup); } /** @@ -2265,6 +1906,10 @@ xdg_popup_destroy(struct xdg_popup *xdg_popup) * nested grabbing popup as well. When a compositor dismisses popups, it * will follow the same dismissing order as required from the client. * + * The parent of a grabbing popup must either be another xdg_popup with an + * active explicit grab, or an xdg_popup or xdg_toplevel, if there are no + * explicit grabs already taken. + * * If the topmost grabbing popup is destroyed, the grab will be returned to * the parent of the popup, if that parent previously had an explicit grab. * @@ -2280,8 +1925,8 @@ xdg_popup_destroy(struct xdg_popup *xdg_popup) static inline void xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, - XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial); + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_GRAB, seat, serial); } /** @@ -2304,18 +1949,18 @@ xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t seria * * If the popup is repositioned in response to a configure event for its * parent, the client should send an xdg_positioner.set_parent_configure - * and possibly an xdg_positioner.set_parent_size request to allow the + * and possibly a xdg_positioner.set_parent_size request to allow the * compositor to properly constrain the popup. * * If the popup is repositioned together with a parent that is being * resized, but not in response to a configure event, the client should - * send an xdg_positioner.set_parent_size request. + * send a xdg_positioner.set_parent_size request. */ static inline void xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) { - wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, - XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token); + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_REPOSITION, positioner, token); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/wgl_context.c b/raylib/external/glfw/src/wgl_context.c index 8a23ffc..4f9a6ff 100644 --- a/raylib/external/glfw/src/wgl_context.c +++ b/raylib/external/glfw/src/wgl_context.c @@ -24,20 +24,21 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(_GLFW_WIN32) - #include +#include #include // Return the value corresponding to the specified attribute // -static int findPixelFormatAttribValueWGL(const int* attribs, - int attribCount, - const int* values, - int attrib) +static int findPixelFormatAttribValue(const int* attribs, + int attribCount, + const int* values, + int attrib) { int i; @@ -52,19 +53,19 @@ static int findPixelFormatAttribValueWGL(const int* attribs, return 0; } -#define ADD_ATTRIB(a) \ +#define addAttrib(a) \ { \ assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \ attribs[attribCount++] = a; \ } -#define FIND_ATTRIB_VALUE(a) \ - findPixelFormatAttribValueWGL(attribs, attribCount, values, a) +#define findAttribValue(a) \ + findPixelFormatAttribValue(attribs, attribCount, values, a) // Return a list of available and usable framebuffer configs // -static int choosePixelFormatWGL(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +static int choosePixelFormat(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; @@ -72,69 +73,64 @@ static int choosePixelFormatWGL(_GLFWwindow* window, int attribs[40]; int values[sizeof(attribs) / sizeof(attribs[0])]; - nativeCount = DescribePixelFormat(window->context.wgl.dc, - 1, - sizeof(PIXELFORMATDESCRIPTOR), - NULL); - if (_glfw.wgl.ARB_pixel_format) { - ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB); - ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB); - ADD_ATTRIB(WGL_PIXEL_TYPE_ARB); - ADD_ATTRIB(WGL_ACCELERATION_ARB); - ADD_ATTRIB(WGL_RED_BITS_ARB); - ADD_ATTRIB(WGL_RED_SHIFT_ARB); - ADD_ATTRIB(WGL_GREEN_BITS_ARB); - ADD_ATTRIB(WGL_GREEN_SHIFT_ARB); - ADD_ATTRIB(WGL_BLUE_BITS_ARB); - ADD_ATTRIB(WGL_BLUE_SHIFT_ARB); - ADD_ATTRIB(WGL_ALPHA_BITS_ARB); - ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB); - ADD_ATTRIB(WGL_DEPTH_BITS_ARB); - ADD_ATTRIB(WGL_STENCIL_BITS_ARB); - ADD_ATTRIB(WGL_ACCUM_BITS_ARB); - ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB); - ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB); - ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB); - ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB); - ADD_ATTRIB(WGL_AUX_BUFFERS_ARB); - ADD_ATTRIB(WGL_STEREO_ARB); - ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB); - - if (_glfw.wgl.ARB_multisample) - ADD_ATTRIB(WGL_SAMPLES_ARB); - - if (ctxconfig->client == GLFW_OPENGL_API) - { - if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) - ADD_ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); - } - else - { - if (_glfw.wgl.EXT_colorspace) - ADD_ATTRIB(WGL_COLORSPACE_EXT); - } - - // NOTE: In a Parallels VM WGL_ARB_pixel_format returns fewer pixel formats than - // DescribePixelFormat, violating the guarantees of the extension spec - // HACK: Iterate through the minimum of both counts - const int attrib = WGL_NUMBER_PIXEL_FORMATS_ARB; - int extensionCount; if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc, - 1, 0, 1, &attrib, &extensionCount)) + 1, 0, 1, &attrib, &nativeCount)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve pixel format attribute"); return 0; } - nativeCount = _glfw_min(nativeCount, extensionCount); + addAttrib(WGL_SUPPORT_OPENGL_ARB); + addAttrib(WGL_DRAW_TO_WINDOW_ARB); + addAttrib(WGL_PIXEL_TYPE_ARB); + addAttrib(WGL_ACCELERATION_ARB); + addAttrib(WGL_RED_BITS_ARB); + addAttrib(WGL_RED_SHIFT_ARB); + addAttrib(WGL_GREEN_BITS_ARB); + addAttrib(WGL_GREEN_SHIFT_ARB); + addAttrib(WGL_BLUE_BITS_ARB); + addAttrib(WGL_BLUE_SHIFT_ARB); + addAttrib(WGL_ALPHA_BITS_ARB); + addAttrib(WGL_ALPHA_SHIFT_ARB); + addAttrib(WGL_DEPTH_BITS_ARB); + addAttrib(WGL_STENCIL_BITS_ARB); + addAttrib(WGL_ACCUM_BITS_ARB); + addAttrib(WGL_ACCUM_RED_BITS_ARB); + addAttrib(WGL_ACCUM_GREEN_BITS_ARB); + addAttrib(WGL_ACCUM_BLUE_BITS_ARB); + addAttrib(WGL_ACCUM_ALPHA_BITS_ARB); + addAttrib(WGL_AUX_BUFFERS_ARB); + addAttrib(WGL_STEREO_ARB); + addAttrib(WGL_DOUBLE_BUFFER_ARB); + + if (_glfw.wgl.ARB_multisample) + addAttrib(WGL_SAMPLES_ARB); + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) + addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + } + else + { + if (_glfw.wgl.EXT_colorspace) + addAttrib(WGL_COLORSPACE_EXT); + } + } + else + { + nativeCount = DescribePixelFormat(window->context.wgl.dc, + 1, + sizeof(PIXELFORMATDESCRIPTOR), + NULL); } - usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); for (i = 0; i < nativeCount; i++) { @@ -153,52 +149,51 @@ static int choosePixelFormatWGL(_GLFWwindow* window, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve pixel format attributes"); - _glfw_free(usableConfigs); + free(usableConfigs); return 0; } - if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) || - !FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB)) + if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) || + !findAttribValue(WGL_DRAW_TO_WINDOW_ARB)) { continue; } - if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) + if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) continue; - if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) + if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) continue; - if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer) - continue; + u->redBits = findAttribValue(WGL_RED_BITS_ARB); + u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB); + u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB); + u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB); - u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB); - u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB); - u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB); - u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB); + u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB); + u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB); - u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB); - u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB); + u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB); + u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB); + u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB); + u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB); - u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB); - u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB); - u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_BITS_ARB); - u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB); + u->auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB); - u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB); - - if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB)) + if (findAttribValue(WGL_STEREO_ARB)) u->stereo = GLFW_TRUE; + if (findAttribValue(WGL_DOUBLE_BUFFER_ARB)) + u->doublebuffer = GLFW_TRUE; if (_glfw.wgl.ARB_multisample) - u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB); + u->samples = findAttribValue(WGL_SAMPLES_ARB); if (ctxconfig->client == GLFW_OPENGL_API) { if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) { - if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) u->sRGB = GLFW_TRUE; } } @@ -206,7 +201,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window, { if (_glfw.wgl.EXT_colorspace) { - if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) + if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) u->sRGB = GLFW_TRUE; } } @@ -225,7 +220,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to describe pixel format"); - _glfw_free(usableConfigs); + free(usableConfigs); return 0; } @@ -244,9 +239,6 @@ static int choosePixelFormatWGL(_GLFWwindow* window, if (pfd.iPixelType != PFD_TYPE_RGBA) continue; - if (!!(pfd.dwFlags & PFD_DOUBLEBUFFER) != fbconfig->doublebuffer) - continue; - u->redBits = pfd.cRedBits; u->greenBits = pfd.cGreenBits; u->blueBits = pfd.cBlueBits; @@ -264,6 +256,8 @@ static int choosePixelFormatWGL(_GLFWwindow* window, if (pfd.dwFlags & PFD_STEREO) u->stereo = GLFW_TRUE; + if (pfd.dwFlags & PFD_DOUBLEBUFFER) + u->doublebuffer = GLFW_TRUE; } u->handle = pixelFormat; @@ -275,7 +269,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window, _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: The driver does not appear to support OpenGL"); - _glfw_free(usableConfigs); + free(usableConfigs); return 0; } @@ -285,18 +279,18 @@ static int choosePixelFormatWGL(_GLFWwindow* window, _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "WGL: Failed to find a suitable pixel format"); - _glfw_free(usableConfigs); + free(usableConfigs); return 0; } pixelFormat = (int) closest->handle; - _glfw_free(usableConfigs); + free(usableConfigs); return pixelFormat; } -#undef ADD_ATTRIB -#undef FIND_ATTRIB_VALUE +#undef addAttrib +#undef findAttribValue static void makeContextCurrentWGL(_GLFWwindow* window) { @@ -327,12 +321,14 @@ static void swapBuffersWGL(_GLFWwindow* window) { if (!window->monitor) { - // HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7 - if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater()) + if (IsWindowsVistaOrGreater()) { - BOOL enabled = FALSE; + // DWM Composition is always enabled on Win8+ + BOOL enabled = IsWindows8OrGreater(); - if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) + // HACK: Use DwmFlush when desktop composition is enabled + if (enabled || + (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)) { int count = abs(window->context.wgl.interval); while (count--) @@ -347,19 +343,20 @@ static void swapBuffersWGL(_GLFWwindow* window) static void swapIntervalWGL(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - assert(window != NULL); window->context.wgl.interval = interval; if (!window->monitor) { - // HACK: Disable WGL swap interval when desktop composition is enabled on Windows - // Vista and 7 to avoid interfering with DWM vsync - if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater()) + if (IsWindowsVistaOrGreater()) { - BOOL enabled = FALSE; + // DWM Composition is always enabled on Win8+ + BOOL enabled = IsWindows8OrGreater(); - if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) + // HACK: Disable WGL swap interval when desktop composition is enabled to + // avoid interfering with DWM vsync + if (enabled || + (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)) interval = 0; } } @@ -389,7 +386,7 @@ static GLFWglproc getProcAddressWGL(const char* procname) if (proc) return proc; - return (GLFWglproc) _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, procname); + return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); } static void destroyContextWGL(_GLFWwindow* window) @@ -401,6 +398,11 @@ static void destroyContextWGL(_GLFWwindow* window) } } + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + // Initialize WGL // GLFWbool _glfwInitWGL(void) @@ -412,7 +414,7 @@ GLFWbool _glfwInitWGL(void) if (_glfw.wgl.instance) return GLFW_TRUE; - _glfw.wgl.instance = _glfwPlatformLoadModule("opengl32.dll"); + _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); if (!_glfw.wgl.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -421,19 +423,19 @@ GLFWbool _glfwInitWGL(void) } _glfw.wgl.CreateContext = (PFN_wglCreateContext) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglCreateContext"); + GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); _glfw.wgl.DeleteContext = (PFN_wglDeleteContext) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglDeleteContext"); + GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetProcAddress"); + GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentDC"); + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); _glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentContext"); + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext"); _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglMakeCurrent"); + GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); _glfw.wgl.ShareLists = (PFN_wglShareLists) - _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglShareLists"); + GetProcAddress(_glfw.wgl.instance, "wglShareLists"); // NOTE: A dummy context has to be created for opengl32.dll to load the // OpenGL ICD, from which we can then query WGL extensions @@ -526,10 +528,10 @@ GLFWbool _glfwInitWGL(void) void _glfwTerminateWGL(void) { if (_glfw.wgl.instance) - _glfwPlatformFreeModule(_glfw.wgl.instance); + FreeLibrary(_glfw.wgl.instance); } -#define SET_ATTRIB(a, v) \ +#define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -558,7 +560,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_FALSE; } - pixelFormat = choosePixelFormatWGL(window, ctxconfig, fbconfig); + pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig); if (!pixelFormat) return GLFW_FALSE; @@ -637,13 +639,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_NO_RESET_NOTIFICATION_ARB); + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_LOSE_CONTEXT_ON_RESET_ARB); + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); } flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -656,13 +658,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -670,7 +672,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.wgl.ARB_create_context_no_error) - SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -678,17 +680,17 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) - SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags); + setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); - SET_ATTRIB(0, 0); + setAttrib(0, 0); window->context.wgl.handle = wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs); @@ -771,21 +773,19 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef SET_ATTRIB +#undef setAttrib + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "WGL: Platform not initialized"); - return NULL; - } - - if (window->context.source != GLFW_NATIVE_CONTEXT_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -794,5 +794,3 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) return window->context.wgl.handle; } -#endif // _GLFW_WIN32 - diff --git a/raylib/external/glfw/src/wgl_context.h b/raylib/external/glfw/src/wgl_context.h new file mode 100644 index 0000000..2cf7e4e --- /dev/null +++ b/raylib/external/glfw/src/wgl_context.h @@ -0,0 +1,160 @@ +//======================================================================== +// GLFW 3.4 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2018 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201a +#define WGL_ALPHA_BITS_ARB 0x201b +#define WGL_ALPHA_SHIFT_ARB 0x201c +#define WGL_ACCUM_BITS_ARB 0x201d +#define WGL_ACCUM_RED_BITS_ARB 0x201e +#define WGL_ACCUM_GREEN_BITS_ARB 0x201f +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_STEREO_ARB 0x2012 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_SAMPLES_ARB 0x2042 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 +#define WGL_COLORSPACE_EXT 0x309d +#define WGL_COLORSPACE_SRGB_EXT 0x3089 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 + +// WGL extension pointer typedefs +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); +typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); +typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC); +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*); +#define wglSwapIntervalEXT _glfw.wgl.SwapIntervalEXT +#define wglGetPixelFormatAttribivARB _glfw.wgl.GetPixelFormatAttribivARB +#define wglGetExtensionsStringEXT _glfw.wgl.GetExtensionsStringEXT +#define wglGetExtensionsStringARB _glfw.wgl.GetExtensionsStringARB +#define wglCreateContextAttribsARB _glfw.wgl.CreateContextAttribsARB + +// opengl32.dll function pointer typedefs +typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC); +typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); +typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); +typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); +typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void); +typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); +typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); +#define wglCreateContext _glfw.wgl.CreateContext +#define wglDeleteContext _glfw.wgl.DeleteContext +#define wglGetProcAddress _glfw.wgl.GetProcAddress +#define wglGetCurrentDC _glfw.wgl.GetCurrentDC +#define wglGetCurrentContext _glfw.wgl.GetCurrentContext +#define wglMakeCurrent _glfw.wgl.MakeCurrent +#define wglShareLists _glfw.wgl.ShareLists + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl + + +// WGL-specific per-context data +// +typedef struct _GLFWcontextWGL +{ + HDC dc; + HGLRC handle; + int interval; + +} _GLFWcontextWGL; + +// WGL-specific global data +// +typedef struct _GLFWlibraryWGL +{ + HINSTANCE instance; + PFN_wglCreateContext CreateContext; + PFN_wglDeleteContext DeleteContext; + PFN_wglGetProcAddress GetProcAddress; + PFN_wglGetCurrentDC GetCurrentDC; + PFN_wglGetCurrentContext GetCurrentContext; + PFN_wglMakeCurrent MakeCurrent; + PFN_wglShareLists ShareLists; + + PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; + PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; + PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; + PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool EXT_swap_control; + GLFWbool EXT_colorspace; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_pixel_format; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool ARB_create_context_no_error; + GLFWbool ARB_context_flush_control; + +} _GLFWlibraryWGL; + + +GLFWbool _glfwInitWGL(void); +void _glfwTerminateWGL(void); +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + diff --git a/raylib/external/glfw/src/win32_init.c b/raylib/external/glfw/src/win32_init.c index d86e35e..f6995e5 100644 --- a/raylib/external/glfw/src/win32_init.c +++ b/raylib/external/glfw/src/win32_init.c @@ -1,9 +1,8 @@ //======================================================================== -// GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -25,12 +24,13 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(_GLFW_WIN32) - #include +#include static const GUID _glfw_GUID_DEVINTERFACE_HID = {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; @@ -39,10 +39,6 @@ static const GUID _glfw_GUID_DEVINTERFACE_HID = #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) -#if defined(_GLFW_BUILD_DLL) - #pragma message("These symbols must be exported by the executable and have no effect in a DLL") -#endif - // Executables (but not DLLs) exporting this symbol with this value will be // automatically directed to the high-performance GPU on Nvidia Optimus systems // with up-to-date drivers @@ -72,17 +68,18 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) // static GLFWbool loadLibraries(void) { - if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (const WCHAR*) &_glfw, - (HMODULE*) &_glfw.win32.instance)) + _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); + if (!_glfw.win32.winmm.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to retrieve own module handle"); + "Win32: Failed to load winmm.dll"); return GLFW_FALSE; } - _glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll"); + _glfw.win32.winmm.GetTime = (PFN_timeGetTime) + GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); + + _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); if (!_glfw.win32.user32.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -91,25 +88,23 @@ static GLFWbool loadLibraries(void) } _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDPIAware"); + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); _glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "EnableNonClientDpiScaling"); + GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling"); _glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext"); + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext"); _glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow"); + GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow"); _glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi"); - _glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi) - _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetSystemMetricsForDpi"); + GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi"); - _glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll"); + _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); if (_glfw.win32.dinput8.instance) { _glfw.win32.dinput8.Create = (PFN_DirectInput8Create) - _glfwPlatformGetModuleSymbol(_glfw.win32.dinput8.instance, "DirectInput8Create"); + GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); } { @@ -126,46 +121,46 @@ static GLFWbool loadLibraries(void) for (i = 0; names[i]; i++) { - _glfw.win32.xinput.instance = _glfwPlatformLoadModule(names[i]); + _glfw.win32.xinput.instance = LoadLibraryA(names[i]); if (_glfw.win32.xinput.instance) { _glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities) - _glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetCapabilities"); + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); _glfw.win32.xinput.GetState = (PFN_XInputGetState) - _glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetState"); + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); break; } } } - _glfw.win32.dwmapi.instance = _glfwPlatformLoadModule("dwmapi.dll"); + _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); if (_glfw.win32.dwmapi.instance) { _glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled) - _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) - _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmFlush"); + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) - _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); _glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor) - _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor"); + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor"); } - _glfw.win32.shcore.instance = _glfwPlatformLoadModule("shcore.dll"); + _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); if (_glfw.win32.shcore.instance) { _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness) - _glfwPlatformGetModuleSymbol(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); + GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); _glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor) - _glfwPlatformGetModuleSymbol(_glfw.win32.shcore.instance, "GetDpiForMonitor"); + GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); } - _glfw.win32.ntdll.instance = _glfwPlatformLoadModule("ntdll.dll"); + _glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll"); if (_glfw.win32.ntdll.instance) { _glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo) - _glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); + GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); } return GLFW_TRUE; @@ -176,27 +171,30 @@ static GLFWbool loadLibraries(void) static void freeLibraries(void) { if (_glfw.win32.xinput.instance) - _glfwPlatformFreeModule(_glfw.win32.xinput.instance); + FreeLibrary(_glfw.win32.xinput.instance); if (_glfw.win32.dinput8.instance) - _glfwPlatformFreeModule(_glfw.win32.dinput8.instance); + FreeLibrary(_glfw.win32.dinput8.instance); + + if (_glfw.win32.winmm.instance) + FreeLibrary(_glfw.win32.winmm.instance); if (_glfw.win32.user32.instance) - _glfwPlatformFreeModule(_glfw.win32.user32.instance); + FreeLibrary(_glfw.win32.user32.instance); if (_glfw.win32.dwmapi.instance) - _glfwPlatformFreeModule(_glfw.win32.dwmapi.instance); + FreeLibrary(_glfw.win32.dwmapi.instance); if (_glfw.win32.shcore.instance) - _glfwPlatformFreeModule(_glfw.win32.shcore.instance); + FreeLibrary(_glfw.win32.shcore.instance); if (_glfw.win32.ntdll.instance) - _glfwPlatformFreeModule(_glfw.win32.ntdll.instance); + FreeLibrary(_glfw.win32.ntdll.instance); } // Create key code translation tables // -static void createKeyTablesWin32(void) +static void createKeyTables(void) { int scancode; @@ -264,6 +262,7 @@ static void createKeyTablesWin32(void) _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE; _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK; @@ -332,69 +331,20 @@ static void createKeyTablesWin32(void) } } -// Window procedure for the hidden helper window -// -static LRESULT CALLBACK helperWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_DISPLAYCHANGE: - _glfwPollMonitorsWin32(); - break; - - case WM_DEVICECHANGE: - { - if (!_glfw.joysticksInitialized) - break; - - if (wParam == DBT_DEVICEARRIVAL) - { - DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; - if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) - _glfwDetectJoystickConnectionWin32(); - } - else if (wParam == DBT_DEVICEREMOVECOMPLETE) - { - DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; - if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) - _glfwDetectJoystickDisconnectionWin32(); - } - - break; - } - } - - return DefWindowProcW(hWnd, uMsg, wParam, lParam); -} - // Creates a dummy window for behind-the-scenes work // static GLFWbool createHelperWindow(void) { MSG msg; - WNDCLASSEXW wc = { sizeof(wc) }; - - wc.style = CS_OWNDC; - wc.lpfnWndProc = (WNDPROC) helperWindowProc; - wc.hInstance = _glfw.win32.instance; - wc.lpszClassName = L"GLFW3 Helper"; - - _glfw.win32.helperWindowClass = RegisterClassExW(&wc); - if (!_glfw.win32.helperWindowClass) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to register helper window class"); - return GLFW_FALSE; - } _glfw.win32.helperWindowHandle = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, - MAKEINTATOM(_glfw.win32.helperWindowClass), + _GLFW_WNDCLASSNAME, L"GLFW message window", WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1, 1, NULL, NULL, - _glfw.win32.instance, + GetModuleHandleW(NULL), NULL); if (!_glfw.win32.helperWindowHandle) @@ -431,6 +381,7 @@ static GLFWbool createHelperWindow(void) return GLFW_TRUE; } + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -450,13 +401,13 @@ WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) return NULL; } - target = _glfw_calloc(count, sizeof(WCHAR)); + target = calloc(count, sizeof(WCHAR)); if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string from UTF-8"); - _glfw_free(target); + free(target); return NULL; } @@ -478,13 +429,13 @@ char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) return NULL; } - target = _glfw_calloc(size, 1); + target = calloc(size, 1); if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string to UTF-8"); - _glfw_free(target); + free(target); return NULL; } @@ -543,7 +494,7 @@ void _glfwUpdateKeyNamesWin32(void) vk = vks[key - GLFW_KEY_KP_0]; } else - vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK); + vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), @@ -551,8 +502,6 @@ void _glfwUpdateKeyNamesWin32(void) if (length == -1) { - // This is a dead key, so we need a second simulated key press - // to make it output its own character (usually a diacritic) length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), 0); @@ -568,8 +517,7 @@ void _glfwUpdateKeyNamesWin32(void) } } -// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the -// application having a correct embedded manifest +// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h // BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) { @@ -599,134 +547,84 @@ BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build) return RtlVerifyVersionInfo(&osvi, mask, cond) == 0; } -GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform) -{ - const _GLFWplatform win32 = - { - .platformID = GLFW_PLATFORM_WIN32, - .init = _glfwInitWin32, - .terminate = _glfwTerminateWin32, - .getCursorPos = _glfwGetCursorPosWin32, - .setCursorPos = _glfwSetCursorPosWin32, - .setCursorMode = _glfwSetCursorModeWin32, - .setRawMouseMotion = _glfwSetRawMouseMotionWin32, - .rawMouseMotionSupported = _glfwRawMouseMotionSupportedWin32, - .createCursor = _glfwCreateCursorWin32, - .createStandardCursor = _glfwCreateStandardCursorWin32, - .destroyCursor = _glfwDestroyCursorWin32, - .setCursor = _glfwSetCursorWin32, - .getScancodeName = _glfwGetScancodeNameWin32, - .getKeyScancode = _glfwGetKeyScancodeWin32, - .setClipboardString = _glfwSetClipboardStringWin32, - .getClipboardString = _glfwGetClipboardStringWin32, - .initJoysticks = _glfwInitJoysticksWin32, - .terminateJoysticks = _glfwTerminateJoysticksWin32, - .pollJoystick = _glfwPollJoystickWin32, - .getMappingName = _glfwGetMappingNameWin32, - .updateGamepadGUID = _glfwUpdateGamepadGUIDWin32, - .freeMonitor = _glfwFreeMonitorWin32, - .getMonitorPos = _glfwGetMonitorPosWin32, - .getMonitorContentScale = _glfwGetMonitorContentScaleWin32, - .getMonitorWorkarea = _glfwGetMonitorWorkareaWin32, - .getVideoModes = _glfwGetVideoModesWin32, - .getVideoMode = _glfwGetVideoModeWin32, - .getGammaRamp = _glfwGetGammaRampWin32, - .setGammaRamp = _glfwSetGammaRampWin32, - .createWindow = _glfwCreateWindowWin32, - .destroyWindow = _glfwDestroyWindowWin32, - .setWindowTitle = _glfwSetWindowTitleWin32, - .setWindowIcon = _glfwSetWindowIconWin32, - .getWindowPos = _glfwGetWindowPosWin32, - .setWindowPos = _glfwSetWindowPosWin32, - .getWindowSize = _glfwGetWindowSizeWin32, - .setWindowSize = _glfwSetWindowSizeWin32, - .setWindowSizeLimits = _glfwSetWindowSizeLimitsWin32, - .setWindowAspectRatio = _glfwSetWindowAspectRatioWin32, - .getFramebufferSize = _glfwGetFramebufferSizeWin32, - .getWindowFrameSize = _glfwGetWindowFrameSizeWin32, - .getWindowContentScale = _glfwGetWindowContentScaleWin32, - .iconifyWindow = _glfwIconifyWindowWin32, - .restoreWindow = _glfwRestoreWindowWin32, - .maximizeWindow = _glfwMaximizeWindowWin32, - .showWindow = _glfwShowWindowWin32, - .hideWindow = _glfwHideWindowWin32, - .requestWindowAttention = _glfwRequestWindowAttentionWin32, - .focusWindow = _glfwFocusWindowWin32, - .setWindowMonitor = _glfwSetWindowMonitorWin32, - .windowFocused = _glfwWindowFocusedWin32, - .windowIconified = _glfwWindowIconifiedWin32, - .windowVisible = _glfwWindowVisibleWin32, - .windowMaximized = _glfwWindowMaximizedWin32, - .windowHovered = _glfwWindowHoveredWin32, - .framebufferTransparent = _glfwFramebufferTransparentWin32, - .getWindowOpacity = _glfwGetWindowOpacityWin32, - .setWindowResizable = _glfwSetWindowResizableWin32, - .setWindowDecorated = _glfwSetWindowDecoratedWin32, - .setWindowFloating = _glfwSetWindowFloatingWin32, - .setWindowOpacity = _glfwSetWindowOpacityWin32, - .setWindowMousePassthrough = _glfwSetWindowMousePassthroughWin32, - .pollEvents = _glfwPollEventsWin32, - .waitEvents = _glfwWaitEventsWin32, - .waitEventsTimeout = _glfwWaitEventsTimeoutWin32, - .postEmptyEvent = _glfwPostEmptyEventWin32, - .getEGLPlatform = _glfwGetEGLPlatformWin32, - .getEGLNativeDisplay = _glfwGetEGLNativeDisplayWin32, - .getEGLNativeWindow = _glfwGetEGLNativeWindowWin32, - .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWin32, - .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWin32, - .createWindowSurface = _glfwCreateWindowSurfaceWin32 - }; - *platform = win32; - return GLFW_TRUE; -} +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// -int _glfwInitWin32(void) +int _glfwPlatformInit(void) { + // To make SetForegroundWindow work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfw.win32.foregroundLockTimeout, 0); + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), + SPIF_SENDCHANGE); + if (!loadLibraries()) return GLFW_FALSE; - createKeyTablesWin32(); + createKeyTables(); _glfwUpdateKeyNamesWin32(); - if (_glfwIsWindows10Version1703OrGreaterWin32()) + if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); else if (IsWindows8Point1OrGreater()) SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); else if (IsWindowsVistaOrGreater()) SetProcessDPIAware(); + if (!_glfwRegisterWindowClassWin32()) + return GLFW_FALSE; + if (!createHelperWindow()) return GLFW_FALSE; + _glfwInitTimerWin32(); + _glfwPollMonitorsWin32(); return GLFW_TRUE; } -void _glfwTerminateWin32(void) +void _glfwPlatformTerminate(void) { - if (_glfw.win32.blankCursor) - DestroyIcon((HICON) _glfw.win32.blankCursor); - if (_glfw.win32.deviceNotificationHandle) UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle); if (_glfw.win32.helperWindowHandle) DestroyWindow(_glfw.win32.helperWindowHandle); - if (_glfw.win32.helperWindowClass) - UnregisterClassW(MAKEINTATOM(_glfw.win32.helperWindowClass), _glfw.win32.instance); - if (_glfw.win32.mainWindowClass) - UnregisterClassW(MAKEINTATOM(_glfw.win32.mainWindowClass), _glfw.win32.instance); - _glfw_free(_glfw.win32.clipboardString); - _glfw_free(_glfw.win32.rawInput); + _glfwUnregisterWindowClassWin32(); + + // Restore previous foreground lock timeout system setting + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + UIntToPtr(_glfw.win32.foregroundLockTimeout), + SPIF_SENDCHANGE); + + free(_glfw.win32.clipboardString); + free(_glfw.win32.rawInput); _glfwTerminateWGL(); _glfwTerminateEGL(); - _glfwTerminateOSMesa(); freeLibraries(); } -#endif // _GLFW_WIN32 +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Win32 WGL EGL OSMesa" +#if defined(__MINGW32__) + " MinGW" +#elif defined(_MSC_VER) + " VisualC" +#endif +#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) + " hybrid-GPU" +#endif +#if defined(_GLFW_BUILD_DLL) + " DLL" +#endif + ; +} diff --git a/raylib/external/glfw/src/win32_joystick.c b/raylib/external/glfw/src/win32_joystick.c index 59389a9..9c71d11 100644 --- a/raylib/external/glfw/src/win32_joystick.c +++ b/raylib/external/glfw/src/win32_joystick.c @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(_GLFW_WIN32) - #include #include @@ -199,11 +199,11 @@ static GLFWbool supportsXInput(const GUID* guid) if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0) return GLFW_FALSE; - ridl = _glfw_calloc(count, sizeof(RAWINPUTDEVICELIST)); + ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1) { - _glfw_free(ridl); + free(ridl); return GLFW_FALSE; } @@ -248,7 +248,7 @@ static GLFWbool supportsXInput(const GUID* guid) } } - _glfw_free(ridl); + free(ridl); return result; } @@ -256,16 +256,16 @@ static GLFWbool supportsXInput(const GUID* guid) // static void closeJoystick(_GLFWjoystick* js) { - _glfwInputJoystick(js, GLFW_DISCONNECTED); - if (js->win32.device) { IDirectInputDevice8_Unacquire(js->win32.device); IDirectInputDevice8_Release(js->win32.device); } - _glfw_free(js->win32.objects); + free(js->win32.objects); + _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); } // DirectInput device object enumeration callback @@ -357,7 +357,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { js = _glfw.joysticks + jid; - if (js->connected) + if (js->present) { if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) return DIENUM_CONTINUE; @@ -416,8 +416,8 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) memset(&data, 0, sizeof(data)); data.device = device; - data.objects = _glfw_calloc(dc.dwAxes + (size_t) dc.dwButtons + dc.dwPOVs, - sizeof(_GLFWjoyobjectWin32)); + data.objects = calloc(dc.dwAxes + (size_t) dc.dwButtons + dc.dwPOVs, + sizeof(_GLFWjoyobjectWin32)); if (FAILED(IDirectInputDevice8_EnumObjects(device, deviceObjectCallback, @@ -428,7 +428,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) "Win32: Failed to enumerate device objects"); IDirectInputDevice8_Release(device); - _glfw_free(data.objects); + free(data.objects); return DIENUM_CONTINUE; } @@ -445,7 +445,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) "Win32: Failed to convert joystick name to UTF-8"); IDirectInputDevice8_Release(device); - _glfw_free(data.objects); + free(data.objects); return DIENUM_STOP; } @@ -473,7 +473,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) if (!js) { IDirectInputDevice8_Release(device); - _glfw_free(data.objects); + free(data.objects); return DIENUM_STOP; } @@ -508,7 +508,7 @@ void _glfwDetectJoystickConnectionWin32(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].connected && + if (_glfw.joysticks[jid].present && _glfw.joysticks[jid].win32.device == NULL && _glfw.joysticks[jid].win32.index == index) { @@ -560,8 +560,8 @@ void _glfwDetectJoystickDisconnectionWin32(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->connected) - _glfwPollJoystickWin32(js, _GLFW_POLL_PRESENCE); + if (js->present) + _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } } @@ -570,11 +570,11 @@ void _glfwDetectJoystickDisconnectionWin32(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwInitJoysticksWin32(void) +GLFWbool _glfwPlatformInitJoysticks(void) { if (_glfw.win32.dinput8.instance) { - if (FAILED(DirectInput8Create(_glfw.win32.instance, + if (FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void**) &_glfw.win32.dinput8.api, @@ -590,7 +590,7 @@ GLFWbool _glfwInitJoysticksWin32(void) return GLFW_TRUE; } -void _glfwTerminateJoysticksWin32(void) +void _glfwPlatformTerminateJoysticks(void) { int jid; @@ -601,13 +601,13 @@ void _glfwTerminateJoysticksWin32(void) IDirectInput8_Release(_glfw.win32.dinput8.api); } -GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { if (js->win32.device) { int i, ai = 0, bi = 0, pi = 0; HRESULT result; - DIJOYSTATE state = {0}; + DIJOYSTATE state; IDirectInputDevice8_Poll(js->win32.device); result = IDirectInputDevice8_GetDeviceState(js->win32.device, @@ -734,25 +734,13 @@ GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode) if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) dpad |= GLFW_HAT_LEFT; - // Treat invalid combinations as neither being pressed - // while preserving what data can be preserved - if ((dpad & GLFW_HAT_RIGHT) && (dpad & GLFW_HAT_LEFT)) - dpad &= ~(GLFW_HAT_RIGHT | GLFW_HAT_LEFT); - if ((dpad & GLFW_HAT_UP) && (dpad & GLFW_HAT_DOWN)) - dpad &= ~(GLFW_HAT_UP | GLFW_HAT_DOWN); - _glfwInputJoystickHat(js, 0, dpad); } return GLFW_TRUE; } -const char* _glfwGetMappingNameWin32(void) -{ - return "Windows"; -} - -void _glfwUpdateGamepadGUIDWin32(char* guid) +void _glfwPlatformUpdateGamepadGUID(char* guid) { if (strcmp(guid + 20, "504944564944") == 0) { @@ -763,5 +751,3 @@ void _glfwUpdateGamepadGUIDWin32(char* guid) } } -#endif // _GLFW_WIN32 - diff --git a/raylib/external/glfw/src/win32_joystick.h b/raylib/external/glfw/src/win32_joystick.h index 9ab6438..b6a7adc 100644 --- a/raylib/external/glfw/src/win32_joystick.h +++ b/raylib/external/glfw/src/win32_joystick.h @@ -24,8 +24,10 @@ // //======================================================================== -#define GLFW_WIN32_JOYSTICK_STATE _GLFWjoystickWin32 win32; -#define GLFW_WIN32_LIBRARY_JOYSTICK_STATE +#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; } + +#define _GLFW_PLATFORM_MAPPING_NAME "Windows" // Joystick element (axis, button or slider) // diff --git a/raylib/external/glfw/src/win32_module.c b/raylib/external/glfw/src/win32_module.c deleted file mode 100644 index 47c8dff..0000000 --- a/raylib/external/glfw/src/win32_module.c +++ /dev/null @@ -1,51 +0,0 @@ -//======================================================================== -// GLFW 3.4 Win32 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2021 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#include "internal.h" - -#if defined(GLFW_BUILD_WIN32_MODULE) - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void* _glfwPlatformLoadModule(const char* path) -{ - return LoadLibraryA(path); -} - -void _glfwPlatformFreeModule(void* module) -{ - FreeLibrary((HMODULE) module); -} - -GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name) -{ - return (GLFWproc) GetProcAddress((HMODULE) module, name); -} - -#endif // GLFW_BUILD_WIN32_MODULE - diff --git a/raylib/external/glfw/src/win32_monitor.c b/raylib/external/glfw/src/win32_monitor.c index 87c85b9..b4c53e4 100644 --- a/raylib/external/glfw/src/win32_monitor.c +++ b/raylib/external/glfw/src/win32_monitor.c @@ -24,14 +24,15 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(_GLFW_WIN32) - #include #include #include +#include #include @@ -95,7 +96,7 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, DeleteDC(dc); monitor = _glfwAllocMonitor(name, widthMM, heightMM); - _glfw_free(name); + free(name); if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) monitor->win32.modesPruned = GLFW_TRUE; @@ -144,7 +145,7 @@ void _glfwPollMonitorsWin32(void) disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { - disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); @@ -196,7 +197,7 @@ void _glfwPollMonitorsWin32(void) monitor = createMonitor(&adapter, &display); if (!monitor) { - _glfw_free(disconnected); + free(disconnected); return; } @@ -226,7 +227,7 @@ void _glfwPollMonitorsWin32(void) monitor = createMonitor(&adapter, NULL); if (!monitor) { - _glfw_free(disconnected); + free(disconnected); return; } @@ -240,7 +241,7 @@ void _glfwPollMonitorsWin32(void) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } - _glfw_free(disconnected); + free(disconnected); } // Change the current video mode @@ -253,7 +254,7 @@ void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) LONG result; best = _glfwChooseVideoMode(monitor, desired); - _glfwGetVideoModeWin32(monitor, ¤t); + _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return; @@ -313,23 +314,12 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) } } -void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) { UINT xdpi, ydpi; - if (xscale) - *xscale = 0.f; - if (yscale) - *yscale = 0.f; - if (IsWindows8Point1OrGreater()) - { - if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI"); - return; - } - } + GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); else { const HDC dc = GetDC(NULL); @@ -349,11 +339,11 @@ void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* ys ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwFreeMonitorWin32(_GLFWmonitor* monitor) +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } -void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); @@ -370,18 +360,18 @@ void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = dm.dmPosition.y; } -void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) { - _glfwGetHMONITORContentScaleWin32(monitor->win32.handle, xscale, yscale); + _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale); } -void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor, - int* xpos, int* ypos, - int* width, int* height) +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) { MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfoW(monitor->win32.handle, &mi); + GetMonitorInfo(monitor->win32.handle, &mi); if (xpos) *xpos = mi.rcWork.left; @@ -393,7 +383,7 @@ void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor, *height = mi.rcWork.bottom - mi.rcWork.top; } -GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count) +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { int modeIndex = 0, size = 0; GLFWvidmode* result = NULL; @@ -452,7 +442,7 @@ GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count) if (*count == size) { size += 128; - result = (GLFWvidmode*) _glfw_realloc(result, size * sizeof(GLFWvidmode)); + result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode)); } (*count)++; @@ -462,25 +452,21 @@ GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count) if (!*count) { // HACK: Report the current mode if no valid modes were found - result = _glfw_calloc(1, sizeof(GLFWvidmode)); - _glfwGetVideoModeWin32(monitor, result); + result = calloc(1, sizeof(GLFWvidmode)); + _glfwPlatformGetVideoMode(monitor, result); *count = 1; } return result; } -GLFWbool _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode) +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - if (!EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query display settings"); - return GLFW_FALSE; - } + EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); mode->width = dm.dmPelsWidth; mode->height = dm.dmPelsHeight; @@ -489,11 +475,9 @@ GLFWbool _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode) &mode->redBits, &mode->greenBits, &mode->blueBits); - - return GLFW_TRUE; } -GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { HDC dc; WORD values[3][256]; @@ -511,7 +495,7 @@ GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp) return GLFW_TRUE; } -void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { HDC dc; WORD values[3][256]; @@ -541,13 +525,6 @@ GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized"); - return NULL; - } - return monitor->win32.publicAdapterName; } @@ -555,15 +532,6 @@ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized"); - return NULL; - } - return monitor->win32.publicDisplayName; } -#endif // _GLFW_WIN32 - diff --git a/raylib/external/glfw/src/win32_platform.h b/raylib/external/glfw/src/win32_platform.h index 7e3d884..4f52051 100644 --- a/raylib/external/glfw/src/win32_platform.h +++ b/raylib/external/glfw/src/win32_platform.h @@ -39,8 +39,8 @@ #endif // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for -// example to allow applications to correctly declare a GL_KHR_debug callback) -// but windows.h assumes no one will define APIENTRY before it does +// example to allow applications to correctly declare a GL_ARB_debug_output +// callback) but windows.h assumes no one will define APIENTRY before it does #undef APIENTRY // GLFW on Windows is Unicode only and does not work in MBCS mode @@ -162,9 +162,7 @@ typedef enum #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4) #endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ -// Replacement for versionhelpers.h macros, as we cannot rely on the -// application having a correct embedded manifest -// +// HACK: Define versionhelpers.h functions manually as MinGW lacks the header #define IsWindowsVistaOrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \ LOBYTE(_WIN32_WINNT_VISTA), 0) @@ -178,11 +176,9 @@ typedef enum _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \ LOBYTE(_WIN32_WINNT_WINBLUE), 0) -// Windows 10 Anniversary Update -#define _glfwIsWindows10Version1607OrGreaterWin32() \ +#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \ _glfwIsWindows10BuildOrGreaterWin32(14393) -// Windows 10 Creators Update -#define _glfwIsWindows10Version1703OrGreaterWin32() \ +#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \ _glfwIsWindows10BuildOrGreaterWin32(15063) // HACK: Define macros that some xinput.h variants don't @@ -219,56 +215,9 @@ typedef enum #define DIDFT_OPTIONAL 0x80000000 #endif -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_TYPE_RGBA_ARB 0x202b -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_NO_ACCELERATION_ARB 0x2025 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_RED_SHIFT_ARB 0x2016 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_GREEN_SHIFT_ARB 0x2018 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_BLUE_SHIFT_ARB 0x201a -#define WGL_ALPHA_BITS_ARB 0x201b -#define WGL_ALPHA_SHIFT_ARB 0x201c -#define WGL_ACCUM_BITS_ARB 0x201d -#define WGL_ACCUM_RED_BITS_ARB 0x201e -#define WGL_ACCUM_GREEN_BITS_ARB 0x201f -#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 -#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_AUX_BUFFERS_ARB 0x2024 -#define WGL_STEREO_ARB 0x2012 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_SAMPLES_ARB 0x2042 -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 -#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 -#define WGL_COLORSPACE_EXT 0x309d -#define WGL_COLORSPACE_SRGB_EXT 0x3089 - -#define ERROR_INVALID_VERSION_ARB 0x2095 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 +// winmm.dll function pointer typedefs +typedef DWORD (WINAPI * PFN_timeGetTime)(void); +#define timeGetTime _glfw.win32.winmm.GetTime // xinput.dll function pointer typedefs typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); @@ -287,14 +236,12 @@ typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND); typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE); typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND); typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); -typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT); #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ #define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_ #define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_ #define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_ #define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_ -#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_ // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); @@ -316,34 +263,6 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*, typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG); #define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_ -// WGL extension pointer typedefs -typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); -typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); -typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC); -typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*); -#define wglSwapIntervalEXT _glfw.wgl.SwapIntervalEXT -#define wglGetPixelFormatAttribivARB _glfw.wgl.GetPixelFormatAttribivARB -#define wglGetExtensionsStringEXT _glfw.wgl.GetExtensionsStringEXT -#define wglGetExtensionsStringARB _glfw.wgl.GetExtensionsStringARB -#define wglCreateContextAttribsARB _glfw.wgl.CreateContextAttribsARB - -// opengl32.dll function pointer typedefs -typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC); -typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); -typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); -typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); -typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void); -typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); -typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); -#define wglCreateContext _glfw.wgl.CreateContext -#define wglDeleteContext _glfw.wgl.DeleteContext -#define wglGetProcAddress _glfw.wgl.GetProcAddress -#define wglGetCurrentDC _glfw.wgl.GetCurrentDC -#define wglGetCurrentContext _glfw.wgl.GetCurrentContext -#define wglMakeCurrent _glfw.wgl.MakeCurrent -#define wglShareLists _glfw.wgl.ShareLists - typedef VkFlags VkWin32SurfaceCreateFlagsKHR; typedef struct VkWin32SurfaceCreateInfoKHR @@ -358,55 +277,25 @@ typedef struct VkWin32SurfaceCreateInfoKHR typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); -#define GLFW_WIN32_WINDOW_STATE _GLFWwindowWin32 win32; -#define GLFW_WIN32_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32; -#define GLFW_WIN32_MONITOR_STATE _GLFWmonitorWin32 win32; -#define GLFW_WIN32_CURSOR_STATE _GLFWcursorWin32 win32; +#include "win32_joystick.h" +#include "wgl_context.h" -#define GLFW_WGL_CONTEXT_STATE _GLFWcontextWGL wgl; -#define GLFW_WGL_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl; +#if !defined(_GLFW_WNDCLASSNAME) + #define _GLFW_WNDCLASSNAME L"GLFW30" +#endif +#define _glfw_dlopen(name) LoadLibraryA(name) +#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) +#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) -// WGL-specific per-context data -// -typedef struct _GLFWcontextWGL -{ - HDC dc; - HGLRC handle; - int interval; -} _GLFWcontextWGL; +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerWin32 win32 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32 -// WGL-specific global data -// -typedef struct _GLFWlibraryWGL -{ - HINSTANCE instance; - PFN_wglCreateContext CreateContext; - PFN_wglDeleteContext DeleteContext; - PFN_wglGetProcAddress GetProcAddress; - PFN_wglGetCurrentDC GetCurrentDC; - PFN_wglGetCurrentContext GetCurrentContext; - PFN_wglMakeCurrent MakeCurrent; - PFN_wglShareLists ShareLists; - - PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; - PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; - PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; - PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; - PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; - GLFWbool EXT_swap_control; - GLFWbool EXT_colorspace; - GLFWbool ARB_multisample; - GLFWbool ARB_framebuffer_sRGB; - GLFWbool EXT_framebuffer_sRGB; - GLFWbool ARB_pixel_format; - GLFWbool ARB_create_context; - GLFWbool ARB_create_context_profile; - GLFWbool EXT_create_context_es2_profile; - GLFWbool ARB_create_context_robustness; - GLFWbool ARB_create_context_no_error; - GLFWbool ARB_context_flush_control; -} _GLFWlibraryWGL; // Win32-specific per-window data // @@ -424,26 +313,21 @@ typedef struct _GLFWwindowWin32 GLFWbool transparent; GLFWbool scaleToMonitor; GLFWbool keymenu; - GLFWbool showDefault; - - // Cached size used to filter out duplicate events - int width, height; // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY; - // The last received high surrogate when decoding pairs of UTF-16 messages + // The last recevied high surrogate when decoding pairs of UTF-16 messages WCHAR highSurrogate; + } _GLFWwindowWin32; // Win32-specific global data // typedef struct _GLFWlibraryWin32 { - HINSTANCE instance; HWND helperWindowHandle; - ATOM helperWindowClass; - ATOM mainWindowClass; HDEVNOTIFY deviceNotificationHandle; + DWORD foregroundLockTimeout; int acquiredMonitorCount; char* clipboardString; short int keycodes[512]; @@ -453,13 +337,14 @@ typedef struct _GLFWlibraryWin32 double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; - // The window the cursor is captured in - _GLFWwindow* capturedCursorWindow; RAWINPUT* rawInput; int rawInputSize; UINT mouseTrailSize; - // The cursor handle to use to hide the cursor (NULL or a transparent cursor) - HCURSOR blankCursor; + + struct { + HINSTANCE instance; + PFN_timeGetTime GetTime; + } winmm; struct { HINSTANCE instance; @@ -481,7 +366,6 @@ typedef struct _GLFWlibraryWin32 PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; PFN_GetDpiForWindow GetDpiForWindow_; PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_; - PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_; } user32; struct { @@ -502,6 +386,7 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; } ntdll; + } _GLFWlibraryWin32; // Win32-specific per-monitor data @@ -516,6 +401,7 @@ typedef struct _GLFWmonitorWin32 char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged; + } _GLFWmonitorWin32; // Win32-specific per-cursor data @@ -523,12 +409,39 @@ typedef struct _GLFWmonitorWin32 typedef struct _GLFWcursorWin32 { HCURSOR handle; + } _GLFWcursorWin32; +// Win32-specific global timer data +// +typedef struct _GLFWtimerWin32 +{ + GLFWbool hasPC; + uint64_t frequency; -GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform); -int _glfwInitWin32(void); -void _glfwTerminateWin32(void); +} _GLFWtimerWin32; + +// Win32-specific thread local storage data +// +typedef struct _GLFWtlsWin32 +{ + GLFWbool allocated; + DWORD index; + +} _GLFWtlsWin32; + +// Win32-specific mutex data +// +typedef struct _GLFWmutexWin32 +{ + GLFWbool allocated; + CRITICAL_SECTION section; + +} _GLFWmutexWin32; + + +GLFWbool _glfwRegisterWindowClassWin32(void); +void _glfwUnregisterWindowClassWin32(void); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); @@ -537,91 +450,10 @@ BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build); void _glfwInputErrorWin32(int error, const char* description); void _glfwUpdateKeyNamesWin32(void); +void _glfwInitTimerWin32(void); + void _glfwPollMonitorsWin32(void); void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); -void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); - -GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyWindowWin32(_GLFWwindow* window); -void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title); -void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos); -void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos); -void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height); -void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height); -void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); -void _glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom); -void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height); -void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); -void _glfwGetWindowContentScaleWin32(_GLFWwindow* window, float* xscale, float* yscale); -void _glfwIconifyWindowWin32(_GLFWwindow* window); -void _glfwRestoreWindowWin32(_GLFWwindow* window); -void _glfwMaximizeWindowWin32(_GLFWwindow* window); -void _glfwShowWindowWin32(_GLFWwindow* window); -void _glfwHideWindowWin32(_GLFWwindow* window); -void _glfwRequestWindowAttentionWin32(_GLFWwindow* window); -void _glfwFocusWindowWin32(_GLFWwindow* window); -void _glfwSetWindowMonitorWin32(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); -GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window); -GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window); -GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window); -GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window); -GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window); -GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window); -void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled); -float _glfwGetWindowOpacityWin32(_GLFWwindow* window); -void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity); - -void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled); -GLFWbool _glfwRawMouseMotionSupportedWin32(void); - -void _glfwPollEventsWin32(void); -void _glfwWaitEventsWin32(void); -void _glfwWaitEventsTimeoutWin32(double timeout); -void _glfwPostEmptyEventWin32(void); - -void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos); -void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos); -void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode); -const char* _glfwGetScancodeNameWin32(int scancode); -int _glfwGetKeyScancodeWin32(int key); -GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); -GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape); -void _glfwDestroyCursorWin32(_GLFWcursor* cursor); -void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor); -void _glfwSetClipboardStringWin32(const char* string); -const char* _glfwGetClipboardStringWin32(void); - -EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs); -EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void); -EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window); - -void _glfwGetRequiredInstanceExtensionsWin32(char** extensions); -GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); -VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -void _glfwFreeMonitorWin32(_GLFWmonitor* monitor); -void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos); -void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor, float* xscale, float* yscale); -void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); -GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count); -GLFWbool _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode); -GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp); -void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); - -GLFWbool _glfwInitJoysticksWin32(void); -void _glfwTerminateJoysticksWin32(void); -GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode); -const char* _glfwGetMappingNameWin32(void); -void _glfwUpdateGamepadGUIDWin32(char* guid); - -GLFWbool _glfwInitWGL(void); -void _glfwTerminateWGL(void); -GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig); +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); diff --git a/raylib/external/glfw/src/win32_thread.c b/raylib/external/glfw/src/win32_thread.c index 212e666..53b34af 100644 --- a/raylib/external/glfw/src/win32_thread.c +++ b/raylib/external/glfw/src/win32_thread.c @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(GLFW_BUILD_WIN32_THREAD) - #include @@ -43,7 +43,8 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) tls->win32.index = TlsAlloc(); if (tls->win32.index == TLS_OUT_OF_INDEXES) { - _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to allocate TLS index"); + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate TLS index"); return GLFW_FALSE; } @@ -96,5 +97,3 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) LeaveCriticalSection(&mutex->win32.section); } -#endif // GLFW_BUILD_WIN32_THREAD - diff --git a/raylib/external/glfw/src/win32_thread.h b/raylib/external/glfw/src/win32_thread.h deleted file mode 100644 index dd5948f..0000000 --- a/raylib/external/glfw/src/win32_thread.h +++ /dev/null @@ -1,53 +0,0 @@ -//======================================================================== -// GLFW 3.4 Win32 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2017 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for -// example to allow applications to correctly declare a GL_KHR_debug callback) -// but windows.h assumes no one will define APIENTRY before it does -#undef APIENTRY - -#include - -#define GLFW_WIN32_TLS_STATE _GLFWtlsWin32 win32; -#define GLFW_WIN32_MUTEX_STATE _GLFWmutexWin32 win32; - -// Win32-specific thread local storage data -// -typedef struct _GLFWtlsWin32 -{ - GLFWbool allocated; - DWORD index; -} _GLFWtlsWin32; - -// Win32-specific mutex data -// -typedef struct _GLFWmutexWin32 -{ - GLFWbool allocated; - CRITICAL_SECTION section; -} _GLFWmutexWin32; - diff --git a/raylib/external/glfw/src/win32_time.c b/raylib/external/glfw/src/win32_time.c index a38e15d..721b0d0 100644 --- a/raylib/external/glfw/src/win32_time.c +++ b/raylib/external/glfw/src/win32_time.c @@ -24,25 +24,49 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(GLFW_BUILD_WIN32_TIMER) + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerWin32(void) +{ + uint64_t frequency; + + if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) + { + _glfw.timer.win32.hasPC = GLFW_TRUE; + _glfw.timer.win32.frequency = frequency; + } + else + { + _glfw.timer.win32.hasPC = GLFW_FALSE; + _glfw.timer.win32.frequency = 1000; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformInitTimer(void) -{ - QueryPerformanceFrequency((LARGE_INTEGER*) &_glfw.timer.win32.frequency); -} - uint64_t _glfwPlatformGetTimerValue(void) { - uint64_t value; - QueryPerformanceCounter((LARGE_INTEGER*) &value); - return value; + if (_glfw.timer.win32.hasPC) + { + uint64_t value; + QueryPerformanceCounter((LARGE_INTEGER*) &value); + return value; + } + else + return (uint64_t) timeGetTime(); } uint64_t _glfwPlatformGetTimerFrequency(void) @@ -50,5 +74,3 @@ uint64_t _glfwPlatformGetTimerFrequency(void) return _glfw.timer.win32.frequency; } -#endif // GLFW_BUILD_WIN32_TIMER - diff --git a/raylib/external/glfw/src/win32_time.h b/raylib/external/glfw/src/win32_time.h deleted file mode 100644 index ef57a5a..0000000 --- a/raylib/external/glfw/src/win32_time.h +++ /dev/null @@ -1,43 +0,0 @@ -//======================================================================== -// GLFW 3.4 Win32 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2017 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for -// example to allow applications to correctly declare a GL_KHR_debug callback) -// but windows.h assumes no one will define APIENTRY before it does -#undef APIENTRY - -#include - -#define GLFW_WIN32_LIBRARY_TIMER_STATE _GLFWtimerWin32 win32; - -// Win32-specific global timer data -// -typedef struct _GLFWtimerWin32 -{ - uint64_t frequency; -} _GLFWtimerWin32; - diff --git a/raylib/external/glfw/src/win32_window.c b/raylib/external/glfw/src/win32_window.c index 3762b76..8cb5050 100644 --- a/raylib/external/glfw/src/win32_window.c +++ b/raylib/external/glfw/src/win32_window.c @@ -1,9 +1,8 @@ //======================================================================== -// GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -25,13 +24,14 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" -#if defined(_GLFW_WIN32) - #include #include +#include #include #include #include @@ -98,7 +98,8 @@ static const GLFWimage* chooseImage(int count, const GLFWimage* images, // Creates an RGBA icon or cursor // -static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon) +static HICON createIcon(const GLFWimage* image, + int xhot, int yhot, GLFWbool icon) { int i; HDC dc; @@ -185,38 +186,53 @@ static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool ico return handle; } +// Translate content area size to full window size according to styles and DPI +// +static void getFullWindowSize(DWORD style, DWORD exStyle, + int contentWidth, int contentHeight, + int* fullWidth, int* fullHeight, + UINT dpi) +{ + RECT rect = { 0, 0, contentWidth, contentHeight }; + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); + else + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + + *fullWidth = rect.right - rect.left; + *fullHeight = rect.bottom - rect.top; +} + // Enforce the content area aspect ratio based on which edge is being dragged // static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) { - RECT frame = {0}; + int xoff, yoff; + UINT dpi = USER_DEFAULT_SCREEN_DPI; const float ratio = (float) window->numer / (float) window->denom; - const DWORD style = getWindowStyle(window); - const DWORD exStyle = getWindowExStyle(window); - if (_glfwIsWindows10Version1607OrGreaterWin32()) - { - AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle, - GetDpiForWindow(window->win32.handle)); - } - else - AdjustWindowRectEx(&frame, style, FALSE, exStyle); + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + dpi = GetDpiForWindow(window->win32.handle); + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff, dpi); if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) { - area->bottom = area->top + (frame.bottom - frame.top) + - (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio); + area->bottom = area->top + yoff + + (int) ((area->right - area->left - xoff) / ratio); } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) { - area->top = area->bottom - (frame.bottom - frame.top) - - (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio); + area->top = area->bottom - yoff - + (int) ((area->right - area->left - xoff) / ratio); } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) { - area->right = area->left + (frame.right - frame.left) + - (int) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio); + area->right = area->left + xoff + + (int) ((area->bottom - area->top - yoff) * ratio); } } @@ -224,8 +240,7 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) // static void updateCursorImage(_GLFWwindow* window) { - if (window->cursorMode == GLFW_CURSOR_NORMAL || - window->cursorMode == GLFW_CURSOR_CAPTURED) + if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (window->cursor) SetCursor(window->cursor->win32.handle); @@ -233,32 +248,23 @@ static void updateCursorImage(_GLFWwindow* window) SetCursor(LoadCursorW(NULL, IDC_ARROW)); } else + SetCursor(NULL); +} + +// Updates the cursor clip rect +// +static void updateClipRect(_GLFWwindow* window) +{ + if (window) { - // NOTE: Via Remote Desktop, setting the cursor to NULL does not hide it. - // HACK: When running locally, it is set to NULL, but when connected via Remote - // Desktop, this is a transparent cursor. - SetCursor(_glfw.win32.blankCursor); + RECT clipRect; + GetClientRect(window->win32.handle, &clipRect); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); + ClipCursor(&clipRect); } -} - -// Sets the cursor clip rect to the window content area -// -static void captureCursor(_GLFWwindow* window) -{ - RECT clipRect; - GetClientRect(window->win32.handle, &clipRect); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); - ClipCursor(&clipRect); - _glfw.win32.capturedCursorWindow = window; -} - -// Disabled clip cursor -// -static void releaseCursor(void) -{ - ClipCursor(NULL); - _glfw.win32.capturedCursorWindow = NULL; + else + ClipCursor(NULL); } // Enables WM_INPUT messages for the mouse for the specified window @@ -292,12 +298,12 @@ static void disableRawMouseMotion(_GLFWwindow* window) static void disableCursor(_GLFWwindow* window) { _glfw.win32.disabledCursorWindow = window; - _glfwGetCursorPosWin32(window, - &_glfw.win32.restoreCursorPosX, - &_glfw.win32.restoreCursorPosY); + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window); - captureCursor(window); + updateClipRect(window); if (window->rawMouseMotion) enableRawMouseMotion(window); @@ -311,10 +317,10 @@ static void enableCursor(_GLFWwindow* window) disableRawMouseMotion(window); _glfw.win32.disabledCursorWindow = NULL; - releaseCursor(); - _glfwSetCursorPosWin32(window, - _glfw.win32.restoreCursorPosX, - _glfw.win32.restoreCursorPosY); + updateClipRect(NULL); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); updateCursorImage(window); } @@ -349,7 +355,7 @@ static void updateWindowStyles(const _GLFWwindow* window) GetClientRect(window->win32.handle, &rect); - if (_glfwIsWindows10Version1607OrGreaterWin32()) + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, getWindowExStyle(window), @@ -429,7 +435,7 @@ static int getKeyMods(void) static void fitToMonitor(_GLFWwindow* window) { MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfoW(window->monitor->win32.handle, &mi); + GetMonitorInfo(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, @@ -440,7 +446,7 @@ static void fitToMonitor(_GLFWwindow* window) // Make the specified window and its video mode active on its monitor // -static void acquireMonitorWin32(_GLFWwindow* window) +static void acquireMonitor(_GLFWwindow* window) { if (!_glfw.win32.acquiredMonitorCount) { @@ -448,8 +454,8 @@ static void acquireMonitorWin32(_GLFWwindow* window) // HACK: When mouse trails are enabled the cursor becomes invisible when // the OpenGL ICD switches to page flipping - SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); - SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0); + SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); + SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0); } if (!window->monitor->window) @@ -461,7 +467,7 @@ static void acquireMonitorWin32(_GLFWwindow* window) // Remove the window and restore the original video mode // -static void releaseMonitorWin32(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; @@ -471,84 +477,58 @@ static void releaseMonitorWin32(_GLFWwindow* window) { SetThreadExecutionState(ES_CONTINUOUS); - // HACK: Restore mouse trail length saved in acquireMonitorWin32 - SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); + // HACK: Restore mouse trail length saved in acquireMonitor + SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); } _glfwInputMonitorWindow(window->monitor, NULL); _glfwRestoreVideoModeWin32(window->monitor); } -// Manually maximize the window, for when SW_MAXIMIZE cannot be used +// Window callback function (handles window messages) // -static void maximizeWindowManually(_GLFWwindow* window) -{ - RECT rect; - DWORD style; - MONITORINFO mi = { sizeof(mi) }; - - GetMonitorInfoW(MonitorFromWindow(window->win32.handle, - MONITOR_DEFAULTTONEAREST), &mi); - - rect = mi.rcWork; - - if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) - { - rect.right = _glfw_min(rect.right, rect.left + window->maxwidth); - rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight); - } - - style = GetWindowLongW(window->win32.handle, GWL_STYLE); - style |= WS_MAXIMIZE; - SetWindowLongW(window->win32.handle, GWL_STYLE, style); - - if (window->decorated) - { - const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - - if (_glfwIsWindows10Version1607OrGreaterWin32()) - { - const UINT dpi = GetDpiForWindow(window->win32.handle); - AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); - OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi)); - } - else - { - AdjustWindowRectEx(&rect, style, FALSE, exStyle); - OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION)); - } - - rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom); - } - - SetWindowPos(window->win32.handle, HWND_TOP, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); -} - -// Window procedure for user-created windows -// -static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) { _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); if (!window) { - if (uMsg == WM_NCCREATE) - { - if (_glfwIsWindows10Version1607OrGreaterWin32()) - { - const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam; - const _GLFWwndconfig* wndconfig = cs->lpCreateParams; + // This is the message handling for the hidden helper window + // and for a regular window during its initial creation - // On per-monitor DPI aware V1 systems, only enable - // non-client scaling for windows that scale the client area - // We need WM_GETDPISCALEDSIZE from V2 to keep the client - // area static when the non-client area is scaled - if (wndconfig && wndconfig->scaleToMonitor) + switch (uMsg) + { + case WM_NCCREATE: + { + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) EnableNonClientDpiScaling(hWnd); + + break; + } + + case WM_DISPLAYCHANGE: + _glfwPollMonitorsWin32(); + break; + + case WM_DEVICECHANGE: + { + if (!_glfw.joysticksInitialized) + break; + + if (wParam == DBT_DEVICEARRIVAL) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickConnectionWin32(); + } + else if (wParam == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickDisconnectionWin32(); + } + + break; } } @@ -578,8 +558,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l { if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - captureCursor(window); window->win32.frameAction = GLFW_FALSE; } @@ -598,8 +576,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - captureCursor(window); return 0; } @@ -608,11 +584,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l { if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - releaseCursor(); if (window->monitor && window->autoIconify) - _glfwIconifyWindowWin32(window); + _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); return 0; @@ -666,7 +640,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l window->win32.highSurrogate = (WCHAR) wParam; else { - uint32_t codepoint = 0; + unsigned int codepoint = 0; if (wParam >= 0xdc00 && wParam <= 0xdfff) { @@ -700,7 +674,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l return TRUE; } - _glfwInputChar(window, (uint32_t) wParam, getKeyMods(), GLFW_TRUE); + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_TRUE); return 0; } @@ -721,18 +695,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); } - // HACK: Alt+PrtSc has a different scancode than just PrtSc - if (scancode == 0x54) - scancode = 0x137; - - // HACK: Ctrl+Pause has a different scancode than just Pause - if (scancode == 0x146) - scancode = 0x45; - - // HACK: CJK IME sets the extended bit for right Shift - if (scancode == 0x136) - scancode = 0x36; - key = _glfw.win32.keycodes[scancode]; // The Ctrl keys require special handling @@ -784,7 +746,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l { // HACK: Release both Shift keys on Shift up event, as when both // are pressed the first release does not emit any event - // NOTE: The other half of this is in _glfwPollEventsWin32 + // NOTE: The other half of this is in _glfwPlatformPollEvents _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); } @@ -912,8 +874,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); if (size > (UINT) _glfw.win32.rawInputSize) { - _glfw_free(_glfw.win32.rawInput); - _glfw.win32.rawInput = _glfw_calloc(size, 1); + free(_glfw.win32.rawInput); + _glfw.win32.rawInput = calloc(size, 1); _glfw.win32.rawInputSize = size; } @@ -930,28 +892,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l data = _glfw.win32.rawInput; if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { - POINT pos = {0}; - int width, height; - - if (data->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) - { - pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN); - pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN); - width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - } - else - { - width = GetSystemMetrics(SM_CXSCREEN); - height = GetSystemMetrics(SM_CYSCREEN); - } - - pos.x += (int) ((data->data.mouse.lLastX / 65535.f) * width); - pos.y += (int) ((data->data.mouse.lLastY / 65535.f) * height); - ScreenToClient(window->win32.handle, &pos); - - dx = pos.x - window->win32.lastCursorPosX; - dy = pos.y - window->win32.lastCursorPosY; + dx = data->data.mouse.lLastX - window->win32.lastCursorPosX; + dy = data->data.mouse.lLastY - window->win32.lastCursorPosY; } else { @@ -999,8 +941,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l // resizing the window or using the window menu if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - releaseCursor(); break; } @@ -1015,23 +955,19 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l // resizing the window or using the menu if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - captureCursor(window); break; } case WM_SIZE: { - const int width = LOWORD(lParam); - const int height = HIWORD(lParam); const GLFWbool iconified = wParam == SIZE_MINIMIZED; const GLFWbool maximized = wParam == SIZE_MAXIMIZED || (window->win32.maximized && wParam != SIZE_RESTORED); - if (_glfw.win32.capturedCursorWindow == window) - captureCursor(window); + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); if (window->win32.iconified != iconified) _glfwInputWindowIconify(window, iconified); @@ -1039,22 +975,16 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l if (window->win32.maximized != maximized) _glfwInputWindowMaximize(window, maximized); - if (width != window->win32.width || height != window->win32.height) - { - window->win32.width = width; - window->win32.height = height; - - _glfwInputFramebufferSize(window, width, height); - _glfwInputWindowSize(window, width, height); - } + _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); + _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); if (window->monitor && window->win32.iconified != iconified) { if (iconified) - releaseMonitorWin32(window); + releaseMonitor(window); else { - acquireMonitorWin32(window); + acquireMonitor(window); fitToMonitor(window); } } @@ -1066,8 +996,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l case WM_MOVE: { - if (_glfw.win32.capturedCursorWindow == window) - captureCursor(window); + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly @@ -1091,34 +1021,31 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l case WM_GETMINMAXINFO: { - RECT frame = {0}; + int xoff, yoff; + UINT dpi = USER_DEFAULT_SCREEN_DPI; MINMAXINFO* mmi = (MINMAXINFO*) lParam; - const DWORD style = getWindowStyle(window); - const DWORD exStyle = getWindowExStyle(window); if (window->monitor) break; - if (_glfwIsWindows10Version1607OrGreaterWin32()) - { - AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle, - GetDpiForWindow(window->win32.handle)); - } - else - AdjustWindowRectEx(&frame, style, FALSE, exStyle); + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + dpi = GetDpiForWindow(window->win32.handle); + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff, dpi); if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) { - mmi->ptMinTrackSize.x = window->minwidth + frame.right - frame.left; - mmi->ptMinTrackSize.y = window->minheight + frame.bottom - frame.top; + mmi->ptMinTrackSize.x = window->minwidth + xoff; + mmi->ptMinTrackSize.y = window->minheight + yoff; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) { - mmi->ptMaxTrackSize.x = window->maxwidth + frame.right - frame.left; - mmi->ptMaxTrackSize.y = window->maxheight + frame.bottom - frame.top; + mmi->ptMaxTrackSize.x = window->maxwidth + xoff; + mmi->ptMaxTrackSize.y = window->maxheight + yoff; } if (!window->decorated) @@ -1129,7 +1056,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi); - GetMonitorInfoW(mh, &mi); + GetMonitorInfo(mh, &mi); mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; @@ -1176,7 +1103,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l break; // Adjust the window size to keep the content area size constant - if (_glfwIsWindows10Version1703OrGreaterWin32()) + if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) { RECT source = {0}, target = {0}; SIZE* size = (SIZE*) lParam; @@ -1203,11 +1130,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; - // Resize windowed mode windows that either permit rescaling or that - // need it to compensate for non-client area scaling - if (!window->monitor && - (window->win32.scaleToMonitor || - _glfwIsWindows10Version1703OrGreaterWin32())) + // Only apply the suggested size if the OS is new enough to have + // sent a WM_GETDPISCALEDSIZE before this + if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) { RECT* suggested = (RECT*) lParam; SetWindowPos(window->win32.handle, HWND_TOP, @@ -1240,7 +1165,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l int i; const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); - char** paths = _glfw_calloc(count, sizeof(char*)); + char** paths = calloc(count, sizeof(char*)); // Move the mouse to the position of the drop DragQueryPoint(drop, &pt); @@ -1249,19 +1174,19 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l for (i = 0; i < count; i++) { const UINT length = DragQueryFileW(drop, i, NULL, 0); - WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR)); + WCHAR* buffer = calloc((size_t) length + 1, sizeof(WCHAR)); DragQueryFileW(drop, i, buffer, length + 1); paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); - _glfw_free(buffer); + free(buffer); } _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) - _glfw_free(paths[i]); - _glfw_free(paths); + free(paths[i]); + free(paths); DragFinish(drop); return 0; @@ -1277,108 +1202,36 @@ static int createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { - int frameX, frameY, frameWidth, frameHeight; + int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; DWORD style = getWindowStyle(window); DWORD exStyle = getWindowExStyle(window); - if (!_glfw.win32.mainWindowClass) - { - WNDCLASSEXW wc = { sizeof(wc) }; - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.lpfnWndProc = windowProc; - wc.hInstance = _glfw.win32.instance; - wc.hCursor = LoadCursorW(NULL, IDC_ARROW); -#if defined(_GLFW_WNDCLASSNAME) - wc.lpszClassName = _GLFW_WNDCLASSNAME; -#else - wc.lpszClassName = L"GLFW30"; -#endif - // Load user-provided icon if available - wc.hIcon = LoadImageW(GetModuleHandleW(NULL), - L"GLFW_ICON", IMAGE_ICON, - 0, 0, LR_DEFAULTSIZE | LR_SHARED); - if (!wc.hIcon) - { - // No user-provided icon found, load default icon - wc.hIcon = LoadImageW(NULL, - IDI_APPLICATION, IMAGE_ICON, - 0, 0, LR_DEFAULTSIZE | LR_SHARED); - } - - _glfw.win32.mainWindowClass = RegisterClassExW(&wc); - if (!_glfw.win32.mainWindowClass) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to register window class"); - return GLFW_FALSE; - } - } - - if (GetSystemMetrics(SM_REMOTESESSION)) - { - // NOTE: On Remote Desktop, setting the cursor to NULL does not hide it - // HACK: Create a transparent cursor and always set that instead of NULL - // When not on Remote Desktop, this handle is NULL and normal hiding is used - if (!_glfw.win32.blankCursor) - { - const int cursorWidth = GetSystemMetrics(SM_CXCURSOR); - const int cursorHeight = GetSystemMetrics(SM_CYCURSOR); - - unsigned char* cursorPixels = _glfw_calloc(cursorWidth * cursorHeight, 4); - if (!cursorPixels) - return GLFW_FALSE; - - // NOTE: Windows checks whether the image is fully transparent and if so - // just ignores the alpha channel and makes the whole cursor opaque - // HACK: Make one pixel slightly less transparent - cursorPixels[3] = 1; - - const GLFWimage cursorImage = { cursorWidth, cursorHeight, cursorPixels }; - _glfw.win32.blankCursor = createIcon(&cursorImage, 0, 0, FALSE); - _glfw_free(cursorPixels); - - if (!_glfw.win32.blankCursor) - return GLFW_FALSE; - } - } - if (window->monitor) { - MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfoW(window->monitor->win32.handle, &mi); + GLFWvidmode mode; // NOTE: This window placement is temporary and approximate, as the // correct position and size cannot be known until the monitor // video mode has been picked in _glfwSetVideoModeWin32 - frameX = mi.rcMonitor.left; - frameY = mi.rcMonitor.top; - frameWidth = mi.rcMonitor.right - mi.rcMonitor.left; - frameHeight = mi.rcMonitor.bottom - mi.rcMonitor.top; + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + fullWidth = mode.width; + fullHeight = mode.height; } else { - RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; + xpos = CW_USEDEFAULT; + ypos = CW_USEDEFAULT; window->win32.maximized = wndconfig->maximized; if (wndconfig->maximized) style |= WS_MAXIMIZE; - AdjustWindowRectEx(&rect, style, FALSE, exStyle); - - if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION) - { - frameX = CW_USEDEFAULT; - frameY = CW_USEDEFAULT; - } - else - { - frameX = wndconfig->xpos + rect.left; - frameY = wndconfig->ypos + rect.top; - } - - frameWidth = rect.right - rect.left; - frameHeight = rect.bottom - rect.top; + getFullWindowSize(style, exStyle, + wndconfig->width, wndconfig->height, + &fullWidth, &fullHeight, + USER_DEFAULT_SCREEN_DPI); } wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); @@ -1386,17 +1239,17 @@ static int createNativeWindow(_GLFWwindow* window, return GLFW_FALSE; window->win32.handle = CreateWindowExW(exStyle, - MAKEINTATOM(_glfw.win32.mainWindowClass), + _GLFW_WNDCLASSNAME, wideTitle, style, - frameX, frameY, - frameWidth, frameHeight, + xpos, ypos, + fullWidth, fullHeight, NULL, // No parent window NULL, // No window menu - _glfw.win32.instance, - (LPVOID) wndconfig); + GetModuleHandleW(NULL), + NULL); - _glfw_free(wideTitle); + free(wideTitle); if (!window->win32.handle) { @@ -1419,33 +1272,27 @@ static int createNativeWindow(_GLFWwindow* window, window->win32.scaleToMonitor = wndconfig->scaleToMonitor; window->win32.keymenu = wndconfig->win32.keymenu; - window->win32.showDefault = wndconfig->win32.showDefault; + // Adjust window rect to account for DPI scaling of the window frame and + // (if enabled) DPI scaling of the content area + // This cannot be done until we know what monitor the window was placed on if (!window->monitor) { RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; WINDOWPLACEMENT wp = { sizeof(wp) }; - const HMONITOR mh = MonitorFromWindow(window->win32.handle, - MONITOR_DEFAULTTONEAREST); - - // Adjust window rect to account for DPI scaling of the window frame and - // (if enabled) DPI scaling of the content area - // This cannot be done until we know what monitor the window was placed on - // Only update the restored window rect as the window may be maximized if (wndconfig->scaleToMonitor) { float xscale, yscale; - _glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale); - - if (xscale > 0.f && yscale > 0.f) - { - rect.right = (int) (rect.right * xscale); - rect.bottom = (int) (rect.bottom * yscale); - } + _glfwPlatformGetWindowContentScale(window, &xscale, &yscale); + rect.right = (int) (rect.right * xscale); + rect.bottom = (int) (rect.bottom * yscale); } - if (_glfwIsWindows10Version1607OrGreaterWin32()) + ClientToScreen(window->win32.handle, (POINT*) &rect.left); + ClientToScreen(window->win32.handle, (POINT*) &rect.right); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, GetDpiForWindow(window->win32.handle)); @@ -1453,30 +1300,11 @@ static int createNativeWindow(_GLFWwindow* window, else AdjustWindowRectEx(&rect, style, FALSE, exStyle); + // Only update the restored window rect as the window may be maximized GetWindowPlacement(window->win32.handle, &wp); - OffsetRect(&rect, - wp.rcNormalPosition.left - rect.left, - wp.rcNormalPosition.top - rect.top); - wp.rcNormalPosition = rect; wp.showCmd = SW_HIDE; SetWindowPlacement(window->win32.handle, &wp); - - // Adjust rect of maximized undecorated window, because by default Windows will - // make such a window cover the whole monitor instead of its workarea - - if (wndconfig->maximized && !wndconfig->decorated) - { - MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfoW(mh, &mi); - - SetWindowPos(window->win32.handle, HWND_TOP, - mi.rcWork.left, - mi.rcWork.top, - mi.rcWork.right - mi.rcWork.left, - mi.rcWork.bottom - mi.rcWork.top, - SWP_NOACTIVATE | SWP_NOZORDER); - } } DragAcceptFiles(window->win32.handle, TRUE); @@ -1487,15 +1315,66 @@ static int createNativeWindow(_GLFWwindow* window, window->win32.transparent = GLFW_TRUE; } - _glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height); + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Registers the GLFW window class +// +GLFWbool _glfwRegisterWindowClassWin32(void) +{ + WNDCLASSEXW wc; + + ZeroMemory(&wc, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) windowProc; + wc.hInstance = GetModuleHandleW(NULL); + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.lpszClassName = _GLFW_WNDCLASSNAME; + + // Load user-provided icon if available + wc.hIcon = LoadImageW(GetModuleHandleW(NULL), + L"GLFW_ICON", IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + if (!wc.hIcon) + { + // No user-provided icon found, load default icon + wc.hIcon = LoadImageW(NULL, + IDI_APPLICATION, IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + } + + if (!RegisterClassExW(&wc)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window class"); + return GLFW_FALSE; + } return GLFW_TRUE; } -GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +// Unregisters the GLFW window class +// +void _glfwUnregisterWindowClassWin32(void) +{ + UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; @@ -1523,50 +1402,29 @@ GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } - - if (!_glfwRefreshContextAttribs(window, ctxconfig)) - return GLFW_FALSE; } - if (wndconfig->mousePassthrough) - _glfwSetWindowMousePassthroughWin32(window, GLFW_TRUE); - if (window->monitor) { - _glfwShowWindowWin32(window); - _glfwFocusWindowWin32(window); - acquireMonitorWin32(window); + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + acquireMonitor(window); fitToMonitor(window); - - if (wndconfig->centerCursor) - _glfwCenterCursorInContentArea(window); - } - else - { - if (wndconfig->visible) - { - _glfwShowWindowWin32(window); - if (wndconfig->focused) - _glfwFocusWindowWin32(window); - } } return GLFW_TRUE; } -void _glfwDestroyWindowWin32(_GLFWwindow* window) +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window->monitor) - releaseMonitorWin32(window); + releaseMonitor(window); if (window->context.destroy) window->context.destroy(window); if (_glfw.win32.disabledCursorWindow == window) - enableCursor(window); - - if (_glfw.win32.capturedCursorWindow == window) - releaseCursor(); + _glfw.win32.disabledCursorWindow = NULL; if (window->win32.handle) { @@ -1582,17 +1440,18 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window) DestroyIcon(window->win32.smallIcon); } -void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title) +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); if (!wideTitle) return; SetWindowTextW(window->win32.handle, wideTitle); - _glfw_free(wideTitle); + free(wideTitle); } -void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images) +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) { HICON bigIcon = NULL, smallIcon = NULL; @@ -1614,8 +1473,8 @@ void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* im smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); } - SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); - SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); + SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); + SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); if (window->win32.bigIcon) DestroyIcon(window->win32.bigIcon); @@ -1630,7 +1489,7 @@ void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* im } } -void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { POINT pos = { 0, 0 }; ClientToScreen(window->win32.handle, &pos); @@ -1641,11 +1500,11 @@ void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos) *ypos = pos.y; } -void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos) +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { RECT rect = { xpos, ypos, xpos, ypos }; - if (_glfwIsWindows10Version1607OrGreaterWin32()) + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1661,7 +1520,7 @@ void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos) SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); } -void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { RECT area; GetClientRect(window->win32.handle, &area); @@ -1672,13 +1531,13 @@ void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height) *height = area.bottom; } -void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) { if (window->monitor->window == window) { - acquireMonitorWin32(window); + acquireMonitor(window); fitToMonitor(window); } } @@ -1686,7 +1545,7 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) { RECT rect = { 0, 0, width, height }; - if (_glfwIsWindows10Version1607OrGreaterWin32()) + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1704,9 +1563,9 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) } } -void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { RECT area; @@ -1723,7 +1582,7 @@ void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, area.bottom - area.top, TRUE); } -void _glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom) +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { RECT area; @@ -1738,22 +1597,22 @@ void _glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom) area.bottom - area.top, TRUE); } -void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { - _glfwGetWindowSizeWin32(window, width, height); + _glfwPlatformGetWindowSize(window, width, height); } -void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { RECT rect; int width, height; - _glfwGetWindowSizeWin32(window, &width, &height); + _glfwPlatformGetWindowSize(window, &width, &height); SetRect(&rect, 0, 0, width, height); - if (_glfwIsWindows10Version1607OrGreaterWin32()) + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1775,74 +1634,56 @@ void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, *bottom = rect.bottom - height; } -void _glfwGetWindowContentScaleWin32(_GLFWwindow* window, float* xscale, float* yscale) +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) { const HANDLE handle = MonitorFromWindow(window->win32.handle, MONITOR_DEFAULTTONEAREST); - _glfwGetHMONITORContentScaleWin32(handle, xscale, yscale); + _glfwGetMonitorContentScaleWin32(handle, xscale, yscale); } -void _glfwIconifyWindowWin32(_GLFWwindow* window) +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_MINIMIZE); } -void _glfwRestoreWindowWin32(_GLFWwindow* window) +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_RESTORE); } -void _glfwMaximizeWindowWin32(_GLFWwindow* window) +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - if (IsWindowVisible(window->win32.handle)) - ShowWindow(window->win32.handle, SW_MAXIMIZE); - else - maximizeWindowManually(window); + ShowWindow(window->win32.handle, SW_MAXIMIZE); } -void _glfwShowWindowWin32(_GLFWwindow* window) +void _glfwPlatformShowWindow(_GLFWwindow* window) { - int showCommand = SW_SHOWNA; - - if (window->win32.showDefault) - { - // NOTE: GLFW windows currently do not seem to match the Windows 10 definition of - // a main window, so even SW_SHOWDEFAULT does nothing - // This definition is undocumented and can change (source: Raymond Chen) - // HACK: Apply the STARTUPINFO show command manually if available - STARTUPINFOW si = { sizeof(si) }; - GetStartupInfoW(&si); - if (si.dwFlags & STARTF_USESHOWWINDOW) - showCommand = si.wShowWindow; - - window->win32.showDefault = GLFW_FALSE; - } - - ShowWindow(window->win32.handle, showCommand); + ShowWindow(window->win32.handle, SW_SHOWNA); } -void _glfwHideWindowWin32(_GLFWwindow* window) +void _glfwPlatformHideWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_HIDE); } -void _glfwRequestWindowAttentionWin32(_GLFWwindow* window) +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { FlashWindow(window->win32.handle, TRUE); } -void _glfwFocusWindowWin32(_GLFWwindow* window) +void _glfwPlatformFocusWindow(_GLFWwindow* window) { BringWindowToTop(window->win32.handle); SetForegroundWindow(window->win32.handle); SetFocus(window->win32.handle); } -void _glfwSetWindowMonitorWin32(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { if (window->monitor == monitor) { @@ -1850,7 +1691,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, { if (monitor->window == window) { - acquireMonitorWin32(window); + acquireMonitor(window); fitToMonitor(window); } } @@ -1858,7 +1699,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, { RECT rect = { xpos, ypos, xpos + width, ypos + height }; - if (_glfwIsWindows10Version1607OrGreaterWin32()) + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1880,7 +1721,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, } if (window->monitor) - releaseMonitorWin32(window); + releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); @@ -1898,9 +1739,9 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, flags |= SWP_FRAMECHANGED; } - acquireMonitorWin32(window); + acquireMonitor(window); - GetMonitorInfoW(window->monitor->win32.handle, &mi); + GetMonitorInfo(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, @@ -1929,7 +1770,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, else after = HWND_NOTOPMOST; - if (_glfwIsWindows10Version1607OrGreaterWin32()) + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1948,32 +1789,32 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, } } -GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window) +int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); } -GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window) +int _glfwPlatformWindowIconified(_GLFWwindow* window) { return IsIconic(window->win32.handle); } -GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window) +int _glfwPlatformWindowVisible(_GLFWwindow* window) { return IsWindowVisible(window->win32.handle); } -GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window) +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { return IsZoomed(window->win32.handle); } -GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window) +int _glfwPlatformWindowHovered(_GLFWwindow* window) { return cursorInContentArea(window); } -GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window) +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { BOOL composition, opaque; DWORD color; @@ -2000,24 +1841,24 @@ GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window) return GLFW_TRUE; } -void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { updateWindowStyles(window); } -void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { updateWindowStyles(window); } -void _glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST; SetWindowPos(window->win32.handle, after, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } -void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled) { COLORREF key = 0; BYTE alpha = 0; @@ -2047,7 +1888,7 @@ void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled) SetLayeredWindowAttributes(window->win32.handle, key, alpha, flags); } -float _glfwGetWindowOpacityWin32(_GLFWwindow* window) +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { BYTE alpha; DWORD flags; @@ -2062,7 +1903,7 @@ float _glfwGetWindowOpacityWin32(_GLFWwindow* window) return 1.f; } -void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity) +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); if (opacity < 1.f || (exStyle & WS_EX_TRANSPARENT)) @@ -2083,7 +1924,7 @@ void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity) } } -void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled) +void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { if (_glfw.win32.disabledCursorWindow != window) return; @@ -2094,12 +1935,12 @@ void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled) disableRawMouseMotion(window); } -GLFWbool _glfwRawMouseMotionSupportedWin32(void) +GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_TRUE; } -void _glfwPollEventsWin32(void) +void _glfwPlatformPollEvents(void) { MSG msg; HWND handle; @@ -2169,39 +2010,38 @@ void _glfwPollEventsWin32(void) if (window) { int width, height; - _glfwGetWindowSizeWin32(window, &width, &height); + _glfwPlatformGetWindowSize(window, &width, &height); // NOTE: Re-center the cursor only if it has moved since the last call, // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE - // The re-center is required in order to prevent the mouse cursor stopping at the edges of the screen. if (window->win32.lastCursorPosX != width / 2 || window->win32.lastCursorPosY != height / 2) { - _glfwSetCursorPosWin32(window, width / 2, height / 2); + _glfwPlatformSetCursorPos(window, width / 2, height / 2); } } } -void _glfwWaitEventsWin32(void) +void _glfwPlatformWaitEvents(void) { WaitMessage(); - _glfwPollEventsWin32(); + _glfwPlatformPollEvents(); } -void _glfwWaitEventsTimeoutWin32(double timeout) +void _glfwPlatformWaitEventsTimeout(double timeout) { - MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLINPUT); + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); - _glfwPollEventsWin32(); + _glfwPlatformPollEvents(); } -void _glfwPostEmptyEventWin32(void) +void _glfwPlatformPostEmptyEvent(void) { - PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); + PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); } -void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { POINT pos; @@ -2216,7 +2056,7 @@ void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos) } } -void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos) +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) { POINT pos = { (int) xpos, (int) ypos }; @@ -2228,68 +2068,39 @@ void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos) SetCursorPos(pos.x, pos.y); } -void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode) +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - if (_glfwWindowFocusedWin32(window)) + if (mode == GLFW_CURSOR_DISABLED) { - if (mode == GLFW_CURSOR_DISABLED) - { - _glfwGetCursorPosWin32(window, - &_glfw.win32.restoreCursorPosX, - &_glfw.win32.restoreCursorPosY); - _glfwCenterCursorInContentArea(window); - if (window->rawMouseMotion) - enableRawMouseMotion(window); - } - else if (_glfw.win32.disabledCursorWindow == window) - { - if (window->rawMouseMotion) - disableRawMouseMotion(window); - } - - if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED) - captureCursor(window); - else - releaseCursor(); - - if (mode == GLFW_CURSOR_DISABLED) - _glfw.win32.disabledCursorWindow = window; - else if (_glfw.win32.disabledCursorWindow == window) - { - _glfw.win32.disabledCursorWindow = NULL; - _glfwSetCursorPosWin32(window, - _glfw.win32.restoreCursorPosX, - _glfw.win32.restoreCursorPosY); - } + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); } - - if (cursorInContentArea(window)) + else if (_glfw.win32.disabledCursorWindow == window) + enableCursor(window); + else if (cursorInContentArea(window)) updateCursorImage(window); } -const char* _glfwGetScancodeNameWin32(int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { - if (scancode < 0 || scancode > (KF_EXTENDED | 0xff)) + if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) || + _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); return NULL; } - const int key = _glfw.win32.keycodes[scancode]; - if (key == GLFW_KEY_UNKNOWN) - return NULL; - - return _glfw.win32.keynames[key]; + return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; } -int _glfwGetKeyScancodeWin32(int key) +int _glfwPlatformGetKeyScancode(int key) { return _glfw.win32.scancodes[key]; } -GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); if (!cursor->win32.handle) @@ -2298,45 +2109,34 @@ GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor, return GLFW_TRUE; } -GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape) +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { int id = 0; - switch (shape) + if (shape == GLFW_ARROW_CURSOR) + id = OCR_NORMAL; + else if (shape == GLFW_IBEAM_CURSOR) + id = OCR_IBEAM; + else if (shape == GLFW_CROSSHAIR_CURSOR) + id = OCR_CROSS; + else if (shape == GLFW_POINTING_HAND_CURSOR) + id = OCR_HAND; + else if (shape == GLFW_RESIZE_EW_CURSOR) + id = OCR_SIZEWE; + else if (shape == GLFW_RESIZE_NS_CURSOR) + id = OCR_SIZENS; + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + id = OCR_SIZENWSE; + else if (shape == GLFW_RESIZE_NESW_CURSOR) + id = OCR_SIZENESW; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + id = OCR_SIZEALL; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + id = OCR_NO; + else { - case GLFW_ARROW_CURSOR: - id = OCR_NORMAL; - break; - case GLFW_IBEAM_CURSOR: - id = OCR_IBEAM; - break; - case GLFW_CROSSHAIR_CURSOR: - id = OCR_CROSS; - break; - case GLFW_POINTING_HAND_CURSOR: - id = OCR_HAND; - break; - case GLFW_RESIZE_EW_CURSOR: - id = OCR_SIZEWE; - break; - case GLFW_RESIZE_NS_CURSOR: - id = OCR_SIZENS; - break; - case GLFW_RESIZE_NWSE_CURSOR: - id = OCR_SIZENWSE; - break; - case GLFW_RESIZE_NESW_CURSOR: - id = OCR_SIZENESW; - break; - case GLFW_RESIZE_ALL_CURSOR: - id = OCR_SIZEALL; - break; - case GLFW_NOT_ALLOWED_CURSOR: - id = OCR_NO; - break; - default: - _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor"); - return GLFW_FALSE; + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor"); + return GLFW_FALSE; } cursor->win32.handle = LoadImageW(NULL, @@ -2352,21 +2152,21 @@ GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape) return GLFW_TRUE; } -void _glfwDestroyCursorWin32(_GLFWcursor* cursor) +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->win32.handle) DestroyIcon((HICON) cursor->win32.handle); } -void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { if (cursorInContentArea(window)) updateCursorImage(window); } -void _glfwSetClipboardStringWin32(const char* string) +void _glfwPlatformSetClipboardString(const char* string) { - int characterCount, tries = 0; + int characterCount; HANDLE object; WCHAR* buffer; @@ -2394,20 +2194,12 @@ void _glfwSetClipboardStringWin32(const char* string) MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); GlobalUnlock(object); - // NOTE: Retry clipboard opening a few times as some other application may have it - // open and also the Windows Clipboard History reads it after each update - while (!OpenClipboard(_glfw.win32.helperWindowHandle)) + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) { - Sleep(1); - tries++; - - if (tries == 3) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to open clipboard"); - GlobalFree(object); - return; - } + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + GlobalFree(object); + return; } EmptyClipboard(); @@ -2415,25 +2207,16 @@ void _glfwSetClipboardStringWin32(const char* string) CloseClipboard(); } -const char* _glfwGetClipboardStringWin32(void) +const char* _glfwPlatformGetClipboardString(void) { HANDLE object; WCHAR* buffer; - int tries = 0; - // NOTE: Retry clipboard opening a few times as some other application may have it - // open and also the Windows Clipboard History reads it after each update - while (!OpenClipboard(_glfw.win32.helperWindowHandle)) + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) { - Sleep(1); - tries++; - - if (tries == 3) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to open clipboard"); - return NULL; - } + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + return NULL; } object = GetClipboardData(CF_UNICODETEXT); @@ -2454,7 +2237,7 @@ const char* _glfwGetClipboardStringWin32(void) return NULL; } - _glfw_free(_glfw.win32.clipboardString); + free(_glfw.win32.clipboardString); _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer); GlobalUnlock(object); @@ -2463,7 +2246,7 @@ const char* _glfwGetClipboardStringWin32(void) return _glfw.win32.clipboardString; } -EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) { @@ -2493,7 +2276,7 @@ EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs) if (type) { - *attribs = _glfw_calloc(3, sizeof(EGLint)); + *attribs = calloc(3, sizeof(EGLint)); (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; (*attribs)[1] = type; (*attribs)[2] = EGL_NONE; @@ -2504,17 +2287,17 @@ EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs) return 0; } -EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void) +EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void) { return GetDC(_glfw.win32.helperWindowHandle); } -EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window) +EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window) { return window->win32.handle; } -void _glfwGetRequiredInstanceExtensionsWin32(char** extensions) +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface) return; @@ -2523,9 +2306,9 @@ void _glfwGetRequiredInstanceExtensionsWin32(char** extensions) extensions[1] = "VK_KHR_win32_surface"; } -GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = @@ -2541,10 +2324,10 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); } -VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { VkResult err; VkWin32SurfaceCreateInfoKHR sci; @@ -2561,7 +2344,7 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - sci.hinstance = _glfw.win32.instance; + sci.hinstance = GetModuleHandle(NULL); sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); @@ -2575,20 +2358,15 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, return err; } + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "Win32: Platform not initialized"); - return NULL; - } - return window->win32.handle; } -#endif // _GLFW_WIN32 - diff --git a/raylib/external/glfw/src/window.c b/raylib/external/glfw/src/window.c index 1463d16..efcb412 100644 --- a/raylib/external/glfw/src/window.c +++ b/raylib/external/glfw/src/window.c @@ -25,6 +25,8 @@ // distribution. // //======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== #include "internal.h" @@ -42,9 +44,6 @@ // void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) { - assert(window != NULL); - assert(focused == GLFW_TRUE || focused == GLFW_FALSE); - if (window->callbacks.focus) window->callbacks.focus((GLFWwindow*) window, focused); @@ -56,7 +55,7 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) { if (window->keys[key] == GLFW_PRESS) { - const int scancode = _glfw.platform.getKeyScancode(key); + const int scancode = _glfwPlatformGetKeyScancode(key); _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0); } } @@ -74,8 +73,6 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) // void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) { - assert(window != NULL); - if (window->callbacks.pos) window->callbacks.pos((GLFWwindow*) window, x, y); } @@ -85,10 +82,6 @@ void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) // void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) { - assert(window != NULL); - assert(width >= 0); - assert(height >= 0); - if (window->callbacks.size) window->callbacks.size((GLFWwindow*) window, width, height); } @@ -97,9 +90,6 @@ void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) // void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) { - assert(window != NULL); - assert(iconified == GLFW_TRUE || iconified == GLFW_FALSE); - if (window->callbacks.iconify) window->callbacks.iconify((GLFWwindow*) window, iconified); } @@ -108,9 +98,6 @@ void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) // void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) { - assert(window != NULL); - assert(maximized == GLFW_TRUE || maximized == GLFW_FALSE); - if (window->callbacks.maximize) window->callbacks.maximize((GLFWwindow*) window, maximized); } @@ -120,10 +107,6 @@ void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) // void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) { - assert(window != NULL); - assert(width >= 0); - assert(height >= 0); - if (window->callbacks.fbsize) window->callbacks.fbsize((GLFWwindow*) window, width, height); } @@ -133,12 +116,6 @@ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) // void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale) { - assert(window != NULL); - assert(xscale > 0.f); - assert(xscale < FLT_MAX); - assert(yscale > 0.f); - assert(yscale < FLT_MAX); - if (window->callbacks.scale) window->callbacks.scale((GLFWwindow*) window, xscale, yscale); } @@ -147,8 +124,6 @@ void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscal // void _glfwInputWindowDamage(_GLFWwindow* window) { - assert(window != NULL); - if (window->callbacks.refresh) window->callbacks.refresh((GLFWwindow*) window); } @@ -157,8 +132,6 @@ void _glfwInputWindowDamage(_GLFWwindow* window) // void _glfwInputWindowCloseRequest(_GLFWwindow* window) { - assert(window != NULL); - window->shouldClose = GLFW_TRUE; if (window->callbacks.close) @@ -169,7 +142,6 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window) // void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) { - assert(window != NULL); window->monitor = monitor; } @@ -214,7 +186,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; - window = _glfw_calloc(1, sizeof(_GLFWwindow)); + window = calloc(1, sizeof(_GLFWwindow)); window->next = _glfw.windowListHead; _glfw.windowListHead = window; @@ -234,22 +206,47 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->mousePassthrough = wndconfig.mousePassthrough; window->cursorMode = GLFW_CURSOR_NORMAL; - window->doublebuffer = fbconfig.doublebuffer; - window->minwidth = GLFW_DONT_CARE; window->minheight = GLFW_DONT_CARE; window->maxwidth = GLFW_DONT_CARE; window->maxheight = GLFW_DONT_CARE; window->numer = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE; - window->title = _glfw_strdup(title); - if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig)) + // Open the actual window and create its context + if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { glfwDestroyWindow((GLFWwindow*) window); return NULL; } + if (ctxconfig.client != GLFW_NO_API) + { + if (!_glfwRefreshContextAttribs(window, &ctxconfig)) + { + glfwDestroyWindow((GLFWwindow*) window); + return NULL; + } + } + + if (wndconfig.mousePassthrough) + _glfwPlatformSetWindowMousePassthrough(window, GLFW_TRUE); + + if (window->monitor) + { + if (wndconfig.centerCursor) + _glfwCenterCursorInContentArea(window); + } + else + { + if (wndconfig.visible) + { + _glfwPlatformShowWindow(window); + if (wndconfig.focused) + _glfwPlatformFocusWindow(window); + } + } + return (GLFWwindow*) window; } @@ -273,9 +270,6 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.autoIconify = GLFW_TRUE; _glfw.hints.window.centerCursor = GLFW_TRUE; _glfw.hints.window.focusOnShow = GLFW_TRUE; - _glfw.hints.window.xpos = GLFW_ANY_POSITION; - _glfw.hints.window.ypos = GLFW_ANY_POSITION; - _glfw.hints.window.scaleFramebuffer = GLFW_TRUE; // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, // double buffered @@ -290,6 +284,9 @@ void glfwDefaultWindowHints(void) // The default is to select the highest available refresh rate _glfw.hints.refreshRate = GLFW_DONT_CARE; + + // The default is to use full Retina resolution framebuffers + _glfw.hints.window.ns.retina = GLFW_TRUE; } GLFWAPI void glfwWindowHint(int hint, int value) @@ -367,28 +364,18 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_VISIBLE: _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_POSITION_X: - _glfw.hints.window.xpos = value; - return; - case GLFW_POSITION_Y: - _glfw.hints.window.ypos = value; + case GLFW_COCOA_RETINA_FRAMEBUFFER: + _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_WIN32_KEYBOARD_MENU: _glfw.hints.window.win32.keymenu = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_WIN32_SHOWDEFAULT: - _glfw.hints.window.win32.showDefault = value ? GLFW_TRUE : GLFW_FALSE; - return; case GLFW_COCOA_GRAPHICS_SWITCHING: _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_SCALE_TO_MONITOR: _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_SCALE_FRAMEBUFFER: - case GLFW_COCOA_RETINA_FRAMEBUFFER: - _glfw.hints.window.scaleFramebuffer = value ? GLFW_TRUE : GLFW_FALSE; - return; case GLFW_CENTER_CURSOR: _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; return; @@ -456,10 +443,6 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value) strncpy(_glfw.hints.window.x11.instanceName, value, sizeof(_glfw.hints.window.x11.instanceName) - 1); return; - case GLFW_WAYLAND_APP_ID: - strncpy(_glfw.hints.window.wl.appId, value, - sizeof(_glfw.hints.window.wl.appId) - 1); - return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint); @@ -483,7 +466,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) glfwMakeContextCurrent(NULL); - _glfw.platform.destroyWindow(window); + _glfwPlatformDestroyWindow(window); // Unlink window from global linked list { @@ -495,8 +478,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) *prev = window->next; } - _glfw_free(window->title); - _glfw_free(window); + free(window); } GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) @@ -517,16 +499,6 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) window->shouldClose = value; } -GLFWAPI const char* glfwGetWindowTitle(GLFWwindow* handle) -{ - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); - - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - return window->title; -} - GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -534,45 +506,19 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) assert(title != NULL); _GLFW_REQUIRE_INIT(); - - char* prev = window->title; - window->title = _glfw_strdup(title); - - _glfw.platform.setWindowTitle(window, title); - _glfw_free(prev); + _glfwPlatformSetWindowTitle(window, title); } GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, int count, const GLFWimage* images) { - int i; _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); assert(count >= 0); assert(count == 0 || images != NULL); _GLFW_REQUIRE_INIT(); - - if (count < 0) - { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid image count for window icon"); - return; - } - - for (i = 0; i < count; i++) - { - assert(images[i].pixels != NULL); - - if (images[i].width <= 0 || images[i].height <= 0) - { - _glfwInputError(GLFW_INVALID_VALUE, - "Invalid image dimensions for window icon"); - return; - } - } - - _glfw.platform.setWindowIcon(window, count, images); + _glfwPlatformSetWindowIcon(window, count, images); } GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) @@ -586,7 +532,7 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) *ypos = 0; _GLFW_REQUIRE_INIT(); - _glfw.platform.getWindowPos(window, xpos, ypos); + _glfwPlatformGetWindowPos(window, xpos, ypos); } GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) @@ -599,7 +545,7 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) if (window->monitor) return; - _glfw.platform.setWindowPos(window, xpos, ypos); + _glfwPlatformSetWindowPos(window, xpos, ypos); } GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) @@ -613,7 +559,7 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) *height = 0; _GLFW_REQUIRE_INIT(); - _glfw.platform.getWindowSize(window, width, height); + _glfwPlatformGetWindowSize(window, width, height); } GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) @@ -628,7 +574,7 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) window->videoMode.width = width; window->videoMode.height = height; - _glfw.platform.setWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); } GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, @@ -671,9 +617,9 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, if (window->monitor || !window->resizable) return; - _glfw.platform.setWindowSizeLimits(window, - minwidth, minheight, - maxwidth, maxheight); + _glfwPlatformSetWindowSizeLimits(window, + minwidth, minheight, + maxwidth, maxheight); } GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) @@ -702,7 +648,7 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) if (window->monitor || !window->resizable) return; - _glfw.platform.setWindowAspectRatio(window, numer, denom); + _glfwPlatformSetWindowAspectRatio(window, numer, denom); } GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) @@ -716,7 +662,7 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) *height = 0; _GLFW_REQUIRE_INIT(); - _glfw.platform.getFramebufferSize(window, width, height); + _glfwPlatformGetFramebufferSize(window, width, height); } GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, @@ -736,7 +682,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, *bottom = 0; _GLFW_REQUIRE_INIT(); - _glfw.platform.getWindowFrameSize(window, left, top, right, bottom); + _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); } GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, @@ -751,7 +697,7 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, *yscale = 0.f; _GLFW_REQUIRE_INIT(); - _glfw.platform.getWindowContentScale(window, xscale, yscale); + _glfwPlatformGetWindowContentScale(window, xscale, yscale); } GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) @@ -759,8 +705,8 @@ GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); - _GLFW_REQUIRE_INIT_OR_RETURN(0.f); - return _glfw.platform.getWindowOpacity(window); + _GLFW_REQUIRE_INIT_OR_RETURN(1.f); + return _glfwPlatformGetWindowOpacity(window); } GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) @@ -779,7 +725,7 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) return; } - _glfw.platform.setWindowOpacity(window, opacity); + _glfwPlatformSetWindowOpacity(window, opacity); } GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) @@ -788,7 +734,7 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) assert(window != NULL); _GLFW_REQUIRE_INIT(); - _glfw.platform.iconifyWindow(window); + _glfwPlatformIconifyWindow(window); } GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) @@ -797,7 +743,7 @@ GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) assert(window != NULL); _GLFW_REQUIRE_INIT(); - _glfw.platform.restoreWindow(window); + _glfwPlatformRestoreWindow(window); } GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) @@ -810,7 +756,7 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) if (window->monitor) return; - _glfw.platform.maximizeWindow(window); + _glfwPlatformMaximizeWindow(window); } GLFWAPI void glfwShowWindow(GLFWwindow* handle) @@ -823,10 +769,10 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) if (window->monitor) return; - _glfw.platform.showWindow(window); + _glfwPlatformShowWindow(window); if (window->focusOnShow) - _glfw.platform.focusWindow(window); + _glfwPlatformFocusWindow(window); } GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) @@ -836,7 +782,7 @@ GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - _glfw.platform.requestWindowAttention(window); + _glfwPlatformRequestWindowAttention(window); } GLFWAPI void glfwHideWindow(GLFWwindow* handle) @@ -849,7 +795,7 @@ GLFWAPI void glfwHideWindow(GLFWwindow* handle) if (window->monitor) return; - _glfw.platform.hideWindow(window); + _glfwPlatformHideWindow(window); } GLFWAPI void glfwFocusWindow(GLFWwindow* handle) @@ -859,7 +805,7 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - _glfw.platform.focusWindow(window); + _glfwPlatformFocusWindow(window); } GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) @@ -872,21 +818,21 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) switch (attrib) { case GLFW_FOCUSED: - return _glfw.platform.windowFocused(window); + return _glfwPlatformWindowFocused(window); case GLFW_ICONIFIED: - return _glfw.platform.windowIconified(window); + return _glfwPlatformWindowIconified(window); case GLFW_VISIBLE: - return _glfw.platform.windowVisible(window); + return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: - return _glfw.platform.windowMaximized(window); + return _glfwPlatformWindowMaximized(window); case GLFW_HOVERED: - return _glfw.platform.windowHovered(window); + return _glfwPlatformWindowHovered(window); case GLFW_FOCUS_ON_SHOW: return window->focusOnShow; case GLFW_MOUSE_PASSTHROUGH: return window->mousePassthrough; case GLFW_TRANSPARENT_FRAMEBUFFER: - return _glfw.platform.framebufferTransparent(window); + return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; case GLFW_DECORATED: @@ -895,8 +841,6 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->floating; case GLFW_AUTO_ICONIFY: return window->autoIconify; - case GLFW_DOUBLEBUFFER: - return window->doublebuffer; case GLFW_CLIENT_API: return window->context.client; case GLFW_CONTEXT_CREATION_API: @@ -934,41 +878,47 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) value = value ? GLFW_TRUE : GLFW_FALSE; - switch (attrib) + if (attrib == GLFW_AUTO_ICONIFY) + window->autoIconify = value; + else if (attrib == GLFW_RESIZABLE) { - case GLFW_AUTO_ICONIFY: - window->autoIconify = value; + if (window->resizable == value) return; - case GLFW_RESIZABLE: - window->resizable = value; - if (!window->monitor) - _glfw.platform.setWindowResizable(window, value); - return; - - case GLFW_DECORATED: - window->decorated = value; - if (!window->monitor) - _glfw.platform.setWindowDecorated(window, value); - return; - - case GLFW_FLOATING: - window->floating = value; - if (!window->monitor) - _glfw.platform.setWindowFloating(window, value); - return; - - case GLFW_FOCUS_ON_SHOW: - window->focusOnShow = value; - return; - - case GLFW_MOUSE_PASSTHROUGH: - window->mousePassthrough = value; - _glfw.platform.setWindowMousePassthrough(window, value); - return; + window->resizable = value; + if (!window->monitor) + _glfwPlatformSetWindowResizable(window, value); } + else if (attrib == GLFW_DECORATED) + { + if (window->decorated == value) + return; - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); + window->decorated = value; + if (!window->monitor) + _glfwPlatformSetWindowDecorated(window, value); + } + else if (attrib == GLFW_FLOATING) + { + if (window->floating == value) + return; + + window->floating = value; + if (!window->monitor) + _glfwPlatformSetWindowFloating(window, value); + } + else if (attrib == GLFW_FOCUS_ON_SHOW) + window->focusOnShow = value; + else if (attrib == GLFW_MOUSE_PASSTHROUGH) + { + if (window->mousePassthrough == value) + return; + + window->mousePassthrough = value; + _glfwPlatformSetWindowMousePassthrough(window, value); + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); } GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) @@ -1014,9 +964,9 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, window->videoMode.height = height; window->videoMode.refreshRate = refreshRate; - _glfw.platform.setWindowMonitor(window, monitor, - xpos, ypos, width, height, - refreshRate); + _glfwPlatformSetWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); } GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) @@ -1044,7 +994,7 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowposfun, window->callbacks.pos, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); return cbfun; } @@ -1055,7 +1005,7 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowsizefun, window->callbacks.size, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); return cbfun; } @@ -1066,7 +1016,7 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowclosefun, window->callbacks.close, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); return cbfun; } @@ -1077,7 +1027,7 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowrefreshfun, window->callbacks.refresh, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); return cbfun; } @@ -1088,7 +1038,7 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowfocusfun, window->callbacks.focus, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); return cbfun; } @@ -1099,7 +1049,7 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowiconifyfun, window->callbacks.iconify, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); return cbfun; } @@ -1110,7 +1060,7 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowmaximizefun, window->callbacks.maximize, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.maximize, cbfun); return cbfun; } @@ -1121,7 +1071,7 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWframebuffersizefun, window->callbacks.fbsize, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); return cbfun; } @@ -1132,20 +1082,20 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP(GLFWwindowcontentscalefun, window->callbacks.scale, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.scale, cbfun); return cbfun; } GLFWAPI void glfwPollEvents(void) { _GLFW_REQUIRE_INIT(); - _glfw.platform.pollEvents(); + _glfwPlatformPollEvents(); } GLFWAPI void glfwWaitEvents(void) { _GLFW_REQUIRE_INIT(); - _glfw.platform.waitEvents(); + _glfwPlatformWaitEvents(); } GLFWAPI void glfwWaitEventsTimeout(double timeout) @@ -1161,12 +1111,12 @@ GLFWAPI void glfwWaitEventsTimeout(double timeout) return; } - _glfw.platform.waitEventsTimeout(timeout); + _glfwPlatformWaitEventsTimeout(timeout); } GLFWAPI void glfwPostEmptyEvent(void) { _GLFW_REQUIRE_INIT(); - _glfw.platform.postEmptyEvent(); + _glfwPlatformPostEmptyEvent(); } diff --git a/raylib/external/glfw/src/wl_init.c b/raylib/external/glfw/src/wl_init.c index 2428c72..c076e70 100644 --- a/raylib/external/glfw/src/wl_init.c +++ b/raylib/external/glfw/src/wl_init.c @@ -1,8 +1,7 @@ //======================================================================== -// GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -24,11 +23,14 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +//#define _POSIX_C_SOURCE 199309L #include "internal.h" -#if defined(_GLFW_WAYLAND) - +#include #include #include #include @@ -39,72 +41,746 @@ #include #include #include -#include +#include -#include "wayland-client-protocol.h" -#include "xdg-shell-client-protocol.h" -#include "xdg-decoration-unstable-v1-client-protocol.h" -#include "viewporter-client-protocol.h" -#include "relative-pointer-unstable-v1-client-protocol.h" -#include "pointer-constraints-unstable-v1-client-protocol.h" -#include "fractional-scale-v1-client-protocol.h" -#include "xdg-activation-v1-client-protocol.h" -#include "idle-inhibit-unstable-v1-client-protocol.h" -// NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of -// wl_interface pointers 'types', making it impossible to combine several unmodified -// private-code files into a single compilation unit -// HACK: We override this name with a macro for each file, allowing them to coexist +static inline int min(int n1, int n2) +{ + return n1 < n2 ? n1 : n2; +} -#define types _glfw_wayland_types -#include "wayland-client-protocol-code.h" -#undef types +static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, + int* which) +{ + int focus; + _GLFWwindow* window = _glfw.windowListHead; + if (!which) + which = &focus; + while (window) + { + if (surface == window->wl.decorations.top.surface) + { + *which = topDecoration; + break; + } + if (surface == window->wl.decorations.left.surface) + { + *which = leftDecoration; + break; + } + if (surface == window->wl.decorations.right.surface) + { + *which = rightDecoration; + break; + } + if (surface == window->wl.decorations.bottom.surface) + { + *which = bottomDecoration; + break; + } + window = window->next; + } + return window; +} -#define types _glfw_xdg_shell_types -#include "xdg-shell-client-protocol-code.h" -#undef types +static void pointerHandleEnter(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t sx, + wl_fixed_t sy) +{ + // Happens in the case we just destroyed the surface. + if (!surface) + return; -#define types _glfw_xdg_decoration_types -#include "xdg-decoration-unstable-v1-client-protocol-code.h" -#undef types + int focus = 0; + _GLFWwindow* window = wl_surface_get_user_data(surface); + if (!window) + { + window = findWindowFromDecorationSurface(surface, &focus); + if (!window) + return; + } -#define types _glfw_viewporter_types -#include "viewporter-client-protocol-code.h" -#undef types + window->wl.decorations.focus = focus; + _glfw.wl.serial = serial; + _glfw.wl.pointerFocus = window; -#define types _glfw_relative_pointer_types -#include "relative-pointer-unstable-v1-client-protocol-code.h" -#undef types + window->wl.hovered = GLFW_TRUE; -#define types _glfw_pointer_constraints_types -#include "pointer-constraints-unstable-v1-client-protocol-code.h" -#undef types + _glfwPlatformSetCursor(window, window->wl.currentCursor); + _glfwInputCursorEnter(window, GLFW_TRUE); +} -#define types _glfw_fractional_scale_types -#include "fractional-scale-v1-client-protocol-code.h" -#undef types +static void pointerHandleLeave(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; -#define types _glfw_xdg_activation_types -#include "xdg-activation-v1-client-protocol-code.h" -#undef types + if (!window) + return; -#define types _glfw_idle_inhibit_types -#include "idle-inhibit-unstable-v1-client-protocol-code.h" -#undef types + window->wl.hovered = GLFW_FALSE; -static void wmBaseHandlePing(void* userData, + _glfw.wl.serial = serial; + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GLFW_FALSE); + _glfw.wl.cursorPreviousName = NULL; +} + +static void setCursor(_GLFWwindow* window, const char* name) +{ + struct wl_buffer* buffer; + struct wl_cursor* cursor; + struct wl_cursor_image* image; + struct wl_surface* surface = _glfw.wl.cursorSurface; + struct wl_cursor_theme* theme = _glfw.wl.cursorTheme; + int scale = 1; + + if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI) + { + // We only support up to scale=2 for now, since libwayland-cursor + // requires us to load a different theme for each size. + scale = 2; + theme = _glfw.wl.cursorThemeHiDPI; + } + + cursor = wl_cursor_theme_get_cursor(theme, name); + if (!cursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor not found"); + return; + } + // TODO: handle animated cursors too. + image = cursor->images[0]; + + if (!image) + return; + + buffer = wl_cursor_image_get_buffer(image); + if (!buffer) + return; + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, + surface, + image->hotspot_x / scale, + image->hotspot_y / scale); + wl_surface_set_buffer_scale(surface, scale); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + image->width, image->height); + wl_surface_commit(surface); + _glfw.wl.cursorPreviousName = name; +} + +static void pointerHandleMotion(void* data, + struct wl_pointer* pointer, + uint32_t time, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + const char* cursorName = NULL; + double x, y; + + if (!window) + return; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + return; + x = wl_fixed_to_double(sx); + y = wl_fixed_to_double(sy); + + switch (window->wl.decorations.focus) + { + case mainWindow: + window->wl.cursorPosX = x; + window->wl.cursorPosY = y; + _glfwInputCursorPos(window, x, y); + _glfw.wl.cursorPreviousName = NULL; + return; + case topDecoration: + if (y < _GLFW_DECORATION_WIDTH) + cursorName = "n-resize"; + else + cursorName = "left_ptr"; + break; + case leftDecoration: + if (y < _GLFW_DECORATION_WIDTH) + cursorName = "nw-resize"; + else + cursorName = "w-resize"; + break; + case rightDecoration: + if (y < _GLFW_DECORATION_WIDTH) + cursorName = "ne-resize"; + else + cursorName = "e-resize"; + break; + case bottomDecoration: + if (x < _GLFW_DECORATION_WIDTH) + cursorName = "sw-resize"; + else if (x > window->wl.width + _GLFW_DECORATION_WIDTH) + cursorName = "se-resize"; + else + cursorName = "s-resize"; + break; + default: + assert(0); + } + if (_glfw.wl.cursorPreviousName != cursorName) + setCursor(window, cursorName); +} + +static void pointerHandleButton(void* data, + struct wl_pointer* pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + int glfwButton; + uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; + + if (!window) + return; + if (button == BTN_LEFT) + { + switch (window->wl.decorations.focus) + { + case mainWindow: + break; + case topDecoration: + if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else + { + xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); + } + break; + case leftDecoration: + if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; + else + edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; + break; + case rightDecoration: + if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; + else + edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + break; + case bottomDecoration: + if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) + edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; + else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) + edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; + else + edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + break; + default: + assert(0); + } + if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) + { + xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, + serial, edges); + } + } + else if (button == BTN_RIGHT) + { + if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel) + { + xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, + _glfw.wl.seat, serial, + window->wl.cursorPosX, + window->wl.cursorPosY); + return; + } + } + + // Don’t pass the button to the user if it was related to a decoration. + if (window->wl.decorations.focus != mainWindow) + return; + + _glfw.wl.serial = serial; + + /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev + * codes. */ + glfwButton = button - BTN_LEFT; + + _glfwInputMouseClick(window, + glfwButton, + state == WL_POINTER_BUTTON_STATE_PRESSED + ? GLFW_PRESS + : GLFW_RELEASE, + _glfw.wl.xkb.modifiers); +} + +static void pointerHandleAxis(void* data, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + double x = 0.0, y = 0.0; + // Wayland scroll events are in pointer motion coordinate space (think two + // finger scroll). The factor 10 is commonly used to convert to "scroll + // step means 1.0. + const double scrollFactor = 1.0 / 10.0; + + if (!window) + return; + + assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL || + axis == WL_POINTER_AXIS_VERTICAL_SCROLL); + + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + x = -wl_fixed_to_double(value) * scrollFactor; + else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + y = -wl_fixed_to_double(value) * scrollFactor; + + _glfwInputScroll(window, x, y); +} + +static const struct wl_pointer_listener pointerListener = { + pointerHandleEnter, + pointerHandleLeave, + pointerHandleMotion, + pointerHandleButton, + pointerHandleAxis, +}; + +static void keyboardHandleKeymap(void* data, + struct wl_keyboard* keyboard, + uint32_t format, + int fd, + uint32_t size) +{ + struct xkb_keymap* keymap; + struct xkb_state* state; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H + struct xkb_compose_table* composeTable; + struct xkb_compose_state* composeState; +#endif + + char* mapStr; + const char* locale; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, + mapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); + munmap(mapStr, size); + close(fd); + + if (!keymap) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to compile keymap"); + return; + } + + state = xkb_state_new(keymap); + if (!state) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB state"); + xkb_keymap_unref(keymap); + return; + } + + // Look up the preferred locale, falling back to "C" as default. + locale = getenv("LC_ALL"); + if (!locale) + locale = getenv("LC_CTYPE"); + if (!locale) + locale = getenv("LANG"); + if (!locale) + locale = "C"; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H + composeTable = + xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, + XKB_COMPOSE_COMPILE_NO_FLAGS); + if (composeTable) + { + composeState = + xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + xkb_compose_table_unref(composeTable); + if (composeState) + _glfw.wl.xkb.composeState = composeState; + else + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB compose state"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB compose table"); + } +#endif + + xkb_keymap_unref(_glfw.wl.xkb.keymap); + xkb_state_unref(_glfw.wl.xkb.state); + _glfw.wl.xkb.keymap = keymap; + _glfw.wl.xkb.state = state; + + _glfw.wl.xkb.controlMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); + _glfw.wl.xkb.altMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); + _glfw.wl.xkb.shiftMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); + _glfw.wl.xkb.superMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); + _glfw.wl.xkb.capsLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); + _glfw.wl.xkb.numLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); +} + +static void keyboardHandleEnter(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) +{ + // Happens in the case we just destroyed the surface. + if (!surface) + return; + + _GLFWwindow* window = wl_surface_get_user_data(surface); + if (!window) + { + window = findWindowFromDecorationSurface(surface, NULL); + if (!window) + return; + } + + _glfw.wl.serial = serial; + _glfw.wl.keyboardFocus = window; + _glfwInputWindowFocus(window, GLFW_TRUE); +} + +static void keyboardHandleLeave(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + _glfw.wl.serial = serial; + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); +} + +static int toGLFWKeyCode(uint32_t key) +{ + if (key < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0])) + return _glfw.wl.keycodes[key]; + + return GLFW_KEY_UNKNOWN; +} + +#ifdef HAVE_XKBCOMMON_COMPOSE_H +static xkb_keysym_t composeSymbol(xkb_keysym_t sym) +{ + if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) + return sym; + if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) + != XKB_COMPOSE_FEED_ACCEPTED) + return sym; + switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) + { + case XKB_COMPOSE_COMPOSED: + return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); + case XKB_COMPOSE_COMPOSING: + case XKB_COMPOSE_CANCELLED: + return XKB_KEY_NoSymbol; + case XKB_COMPOSE_NOTHING: + default: + return sym; + } +} +#endif + +static GLFWbool inputChar(_GLFWwindow* window, uint32_t key) +{ + uint32_t code, numSyms; + long cp; + const xkb_keysym_t *syms; + xkb_keysym_t sym; + + code = key + 8; + numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms); + + if (numSyms == 1) + { +#ifdef HAVE_XKBCOMMON_COMPOSE_H + sym = composeSymbol(syms[0]); +#else + sym = syms[0]; +#endif + cp = _glfwKeySym2Unicode(sym); + if (cp != -1) + { + const int mods = _glfw.wl.xkb.modifiers; + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + _glfwInputChar(window, cp, mods, plain); + } + } + + return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]); +} + +static void keyboardHandleKey(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) +{ + int keyCode; + int action; + _GLFWwindow* window = _glfw.wl.keyboardFocus; + GLFWbool shouldRepeat; + struct itimerspec timer = {}; + + if (!window) + return; + + keyCode = toGLFWKeyCode(key); + action = state == WL_KEYBOARD_KEY_STATE_PRESSED + ? GLFW_PRESS : GLFW_RELEASE; + + _glfw.wl.serial = serial; + _glfwInputKey(window, keyCode, key, action, + _glfw.wl.xkb.modifiers); + + if (action == GLFW_PRESS) + { + shouldRepeat = inputChar(window, key); + + if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0) + { + _glfw.wl.keyboardLastKey = keyCode; + _glfw.wl.keyboardLastScancode = key; + if (_glfw.wl.keyboardRepeatRate > 1) + timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate; + else + timer.it_interval.tv_sec = 1; + timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000; + timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000; + } + } + timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL); +} + +static void keyboardHandleModifiers(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t modsDepressed, + uint32_t modsLatched, + uint32_t modsLocked, + uint32_t group) +{ + xkb_mod_mask_t mask; + unsigned int modifiers = 0; + + _glfw.wl.serial = serial; + + if (!_glfw.wl.xkb.keymap) + return; + + xkb_state_update_mask(_glfw.wl.xkb.state, + modsDepressed, + modsLatched, + modsLocked, + 0, + 0, + group); + + mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, + XKB_STATE_MODS_DEPRESSED | + XKB_STATE_LAYOUT_DEPRESSED | + XKB_STATE_MODS_LATCHED | + XKB_STATE_LAYOUT_LATCHED); + if (mask & _glfw.wl.xkb.controlMask) + modifiers |= GLFW_MOD_CONTROL; + if (mask & _glfw.wl.xkb.altMask) + modifiers |= GLFW_MOD_ALT; + if (mask & _glfw.wl.xkb.shiftMask) + modifiers |= GLFW_MOD_SHIFT; + if (mask & _glfw.wl.xkb.superMask) + modifiers |= GLFW_MOD_SUPER; + if (mask & _glfw.wl.xkb.capsLockMask) + modifiers |= GLFW_MOD_CAPS_LOCK; + if (mask & _glfw.wl.xkb.numLockMask) + modifiers |= GLFW_MOD_NUM_LOCK; + _glfw.wl.xkb.modifiers = modifiers; +} + +#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION +static void keyboardHandleRepeatInfo(void* data, + struct wl_keyboard* keyboard, + int32_t rate, + int32_t delay) +{ + if (keyboard != _glfw.wl.keyboard) + return; + + _glfw.wl.keyboardRepeatRate = rate; + _glfw.wl.keyboardRepeatDelay = delay; +} +#endif + +static const struct wl_keyboard_listener keyboardListener = { + keyboardHandleKeymap, + keyboardHandleEnter, + keyboardHandleLeave, + keyboardHandleKey, + keyboardHandleModifiers, +#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION + keyboardHandleRepeatInfo, +#endif +}; + +static void seatHandleCapabilities(void* data, + struct wl_seat* seat, + enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) + { + _glfw.wl.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) + { + wl_pointer_destroy(_glfw.wl.pointer); + _glfw.wl.pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) + { + _glfw.wl.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) + { + wl_keyboard_destroy(_glfw.wl.keyboard); + _glfw.wl.keyboard = NULL; + } +} + +static void seatHandleName(void* data, + struct wl_seat* seat, + const char* name) +{ +} + +static const struct wl_seat_listener seatListener = { + seatHandleCapabilities, + seatHandleName, +}; + +static void dataOfferHandleOffer(void* data, + struct wl_data_offer* dataOffer, + const char* mimeType) +{ +} + +static const struct wl_data_offer_listener dataOfferListener = { + dataOfferHandleOffer, +}; + +static void dataDeviceHandleDataOffer(void* data, + struct wl_data_device* dataDevice, + struct wl_data_offer* id) +{ + if (_glfw.wl.dataOffer) + wl_data_offer_destroy(_glfw.wl.dataOffer); + + _glfw.wl.dataOffer = id; + wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL); +} + +static void dataDeviceHandleEnter(void* data, + struct wl_data_device* dataDevice, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer *id) +{ +} + +static void dataDeviceHandleLeave(void* data, + struct wl_data_device* dataDevice) +{ +} + +static void dataDeviceHandleMotion(void* data, + struct wl_data_device* dataDevice, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) +{ +} + +static void dataDeviceHandleDrop(void* data, + struct wl_data_device* dataDevice) +{ +} + +static void dataDeviceHandleSelection(void* data, + struct wl_data_device* dataDevice, + struct wl_data_offer* id) +{ +} + +static const struct wl_data_device_listener dataDeviceListener = { + dataDeviceHandleDataOffer, + dataDeviceHandleEnter, + dataDeviceHandleLeave, + dataDeviceHandleMotion, + dataDeviceHandleDrop, + dataDeviceHandleSelection, +}; + +static void wmBaseHandlePing(void* data, struct xdg_wm_base* wmBase, uint32_t serial) { xdg_wm_base_pong(wmBase, serial); } -static const struct xdg_wm_base_listener wmBaseListener = -{ +static const struct xdg_wm_base_listener wmBaseListener = { wmBaseHandlePing }; -static void registryHandleGlobal(void* userData, +static void registryHandleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, @@ -112,9 +788,10 @@ static void registryHandleGlobal(void* userData, { if (strcmp(interface, "wl_compositor") == 0) { + _glfw.wl.compositorVersion = min(3, version); _glfw.wl.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, - _glfw_min(3, version)); + _glfw.wl.compositorVersion); } else if (strcmp(interface, "wl_subcompositor") == 0) { @@ -134,10 +811,11 @@ static void registryHandleGlobal(void* userData, { if (!_glfw.wl.seat) { + _glfw.wl.seatVersion = min(4, version); _glfw.wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, - _glfw_min(4, version)); - _glfwAddSeatListenerWayland(_glfw.wl.seat); + _glfw.wl.seatVersion); + wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); } } else if (strcmp(interface, "wl_data_device_manager") == 0) @@ -188,29 +866,18 @@ static void registryHandleGlobal(void* userData, &zwp_idle_inhibit_manager_v1_interface, 1); } - else if (strcmp(interface, "xdg_activation_v1") == 0) - { - _glfw.wl.activationManager = - wl_registry_bind(registry, name, - &xdg_activation_v1_interface, - 1); - } - else if (strcmp(interface, "wp_fractional_scale_manager_v1") == 0) - { - _glfw.wl.fractionalScaleManager = - wl_registry_bind(registry, name, - &wp_fractional_scale_manager_v1_interface, - 1); - } } -static void registryHandleGlobalRemove(void* userData, - struct wl_registry* registry, +static void registryHandleGlobalRemove(void *data, + struct wl_registry *registry, uint32_t name) { - for (int i = 0; i < _glfw.monitorCount; ++i) + int i; + _GLFWmonitor* monitor; + + for (i = 0; i < _glfw.monitorCount; ++i) { - _GLFWmonitor* monitor = _glfw.monitors[i]; + monitor = _glfw.monitors[i]; if (monitor->wl.name == name) { _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0); @@ -220,46 +887,17 @@ static void registryHandleGlobalRemove(void* userData, } -static const struct wl_registry_listener registryListener = -{ +static const struct wl_registry_listener registryListener = { registryHandleGlobal, registryHandleGlobalRemove }; -void libdecorHandleError(struct libdecor* context, - enum libdecor_error error, - const char* message) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: libdecor error %u: %s", - error, message); -} - -static const struct libdecor_interface libdecorInterface = -{ - libdecorHandleError -}; - -static void libdecorReadyCallback(void* userData, - struct wl_callback* callback, - uint32_t time) -{ - _glfw.wl.libdecor.ready = GLFW_TRUE; - - assert(_glfw.wl.libdecor.callback == callback); - wl_callback_destroy(_glfw.wl.libdecor.callback); - _glfw.wl.libdecor.callback = NULL; -} - -static const struct wl_callback_listener libdecorReadyListener = -{ - libdecorReadyCallback -}; - // Create key code translation tables // -static void createKeyTablesWayland(void) +static void createKeyTables(void) { + int scancode; + memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes)); memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes)); @@ -321,7 +959,7 @@ static void createKeyTablesWayland(void) _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; - _glfw.wl.keycodes[KEY_COMPOSE] = GLFW_KEY_MENU; + _glfw.wl.keycodes[KEY_MENU] = GLFW_KEY_MENU; _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; @@ -364,7 +1002,7 @@ static void createKeyTablesWayland(void) _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23; _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24; _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; - _glfw.wl.keycodes[KEY_KPASTERISK] = GLFW_KEY_KP_MULTIPLY; + _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0; @@ -377,452 +1015,124 @@ static void createKeyTablesWayland(void) _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7; _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8; _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9; - _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_DECIMAL; + _glfw.wl.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; - _glfw.wl.keycodes[KEY_102ND] = GLFW_KEY_WORLD_2; - for (int scancode = 0; scancode < 256; scancode++) + for (scancode = 0; scancode < 256; scancode++) { if (_glfw.wl.keycodes[scancode] > 0) _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode; } } -static GLFWbool loadCursorTheme(void) -{ - int cursorSize = 16; - - const char* sizeString = getenv("XCURSOR_SIZE"); - if (sizeString) - { - errno = 0; - const long cursorSizeLong = strtol(sizeString, NULL, 10); - if (errno == 0 && cursorSizeLong > 0 && cursorSizeLong < INT_MAX) - cursorSize = (int) cursorSizeLong; - } - - const char* themeName = getenv("XCURSOR_THEME"); - - _glfw.wl.cursorTheme = wl_cursor_theme_load(themeName, cursorSize, _glfw.wl.shm); - if (!_glfw.wl.cursorTheme) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load default cursor theme"); - return GLFW_FALSE; - } - - // If this happens to be NULL, we just fallback to the scale=1 version. - _glfw.wl.cursorThemeHiDPI = - wl_cursor_theme_load(themeName, cursorSize * 2, _glfw.wl.shm); - - _glfw.wl.cursorSurface = wl_compositor_create_surface(_glfw.wl.compositor); - _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); - return GLFW_TRUE; -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform) +int _glfwPlatformInit(void) { - const _GLFWplatform wayland = - { - .platformID = GLFW_PLATFORM_WAYLAND, - .init = _glfwInitWayland, - .terminate = _glfwTerminateWayland, - .getCursorPos = _glfwGetCursorPosWayland, - .setCursorPos = _glfwSetCursorPosWayland, - .setCursorMode = _glfwSetCursorModeWayland, - .setRawMouseMotion = _glfwSetRawMouseMotionWayland, - .rawMouseMotionSupported = _glfwRawMouseMotionSupportedWayland, - .createCursor = _glfwCreateCursorWayland, - .createStandardCursor = _glfwCreateStandardCursorWayland, - .destroyCursor = _glfwDestroyCursorWayland, - .setCursor = _glfwSetCursorWayland, - .getScancodeName = _glfwGetScancodeNameWayland, - .getKeyScancode = _glfwGetKeyScancodeWayland, - .setClipboardString = _glfwSetClipboardStringWayland, - .getClipboardString = _glfwGetClipboardStringWayland, -#if defined(GLFW_BUILD_LINUX_JOYSTICK) - .initJoysticks = _glfwInitJoysticksLinux, - .terminateJoysticks = _glfwTerminateJoysticksLinux, - .pollJoystick = _glfwPollJoystickLinux, - .getMappingName = _glfwGetMappingNameLinux, - .updateGamepadGUID = _glfwUpdateGamepadGUIDLinux, -#else - .initJoysticks = _glfwInitJoysticksNull, - .terminateJoysticks = _glfwTerminateJoysticksNull, - .pollJoystick = _glfwPollJoystickNull, - .getMappingName = _glfwGetMappingNameNull, - .updateGamepadGUID = _glfwUpdateGamepadGUIDNull, -#endif - .freeMonitor = _glfwFreeMonitorWayland, - .getMonitorPos = _glfwGetMonitorPosWayland, - .getMonitorContentScale = _glfwGetMonitorContentScaleWayland, - .getMonitorWorkarea = _glfwGetMonitorWorkareaWayland, - .getVideoModes = _glfwGetVideoModesWayland, - .getVideoMode = _glfwGetVideoModeWayland, - .getGammaRamp = _glfwGetGammaRampWayland, - .setGammaRamp = _glfwSetGammaRampWayland, - .createWindow = _glfwCreateWindowWayland, - .destroyWindow = _glfwDestroyWindowWayland, - .setWindowTitle = _glfwSetWindowTitleWayland, - .setWindowIcon = _glfwSetWindowIconWayland, - .getWindowPos = _glfwGetWindowPosWayland, - .setWindowPos = _glfwSetWindowPosWayland, - .getWindowSize = _glfwGetWindowSizeWayland, - .setWindowSize = _glfwSetWindowSizeWayland, - .setWindowSizeLimits = _glfwSetWindowSizeLimitsWayland, - .setWindowAspectRatio = _glfwSetWindowAspectRatioWayland, - .getFramebufferSize = _glfwGetFramebufferSizeWayland, - .getWindowFrameSize = _glfwGetWindowFrameSizeWayland, - .getWindowContentScale = _glfwGetWindowContentScaleWayland, - .iconifyWindow = _glfwIconifyWindowWayland, - .restoreWindow = _glfwRestoreWindowWayland, - .maximizeWindow = _glfwMaximizeWindowWayland, - .showWindow = _glfwShowWindowWayland, - .hideWindow = _glfwHideWindowWayland, - .requestWindowAttention = _glfwRequestWindowAttentionWayland, - .focusWindow = _glfwFocusWindowWayland, - .setWindowMonitor = _glfwSetWindowMonitorWayland, - .windowFocused = _glfwWindowFocusedWayland, - .windowIconified = _glfwWindowIconifiedWayland, - .windowVisible = _glfwWindowVisibleWayland, - .windowMaximized = _glfwWindowMaximizedWayland, - .windowHovered = _glfwWindowHoveredWayland, - .framebufferTransparent = _glfwFramebufferTransparentWayland, - .getWindowOpacity = _glfwGetWindowOpacityWayland, - .setWindowResizable = _glfwSetWindowResizableWayland, - .setWindowDecorated = _glfwSetWindowDecoratedWayland, - .setWindowFloating = _glfwSetWindowFloatingWayland, - .setWindowOpacity = _glfwSetWindowOpacityWayland, - .setWindowMousePassthrough = _glfwSetWindowMousePassthroughWayland, - .pollEvents = _glfwPollEventsWayland, - .waitEvents = _glfwWaitEventsWayland, - .waitEventsTimeout = _glfwWaitEventsTimeoutWayland, - .postEmptyEvent = _glfwPostEmptyEventWayland, - .getEGLPlatform = _glfwGetEGLPlatformWayland, - .getEGLNativeDisplay = _glfwGetEGLNativeDisplayWayland, - .getEGLNativeWindow = _glfwGetEGLNativeWindowWayland, - .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWayland, - .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWayland, - .createWindowSurface = _glfwCreateWindowSurfaceWayland - }; + const char *cursorTheme; + const char *cursorSizeStr; + char *cursorSizeEnd; + long cursorSizeLong; + int cursorSize; + int i; + _GLFWmonitor* monitor; - void* module = _glfwPlatformLoadModule("libwayland-client.so.0"); - if (!module) - { - if (platformID == GLFW_PLATFORM_WAYLAND) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load libwayland-client"); - } - - return GLFW_FALSE; - } - - PFN_wl_display_connect wl_display_connect = (PFN_wl_display_connect) - _glfwPlatformGetModuleSymbol(module, "wl_display_connect"); - if (!wl_display_connect) - { - if (platformID == GLFW_PLATFORM_WAYLAND) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load libwayland-client entry point"); - } - - _glfwPlatformFreeModule(module); - return GLFW_FALSE; - } - - struct wl_display* display = wl_display_connect(NULL); - if (!display) - { - if (platformID == GLFW_PLATFORM_WAYLAND) - _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to connect to display"); - - _glfwPlatformFreeModule(module); - return GLFW_FALSE; - } - - _glfw.wl.display = display; - _glfw.wl.client.handle = module; - - *platform = wayland; - return GLFW_TRUE; -} - -int _glfwInitWayland(void) -{ - // These must be set before any failure checks - _glfw.wl.keyRepeatTimerfd = -1; - _glfw.wl.cursorTimerfd = -1; - - _glfw.wl.tag = glfwGetVersionString(); - - _glfw.wl.client.display_flush = (PFN_wl_display_flush) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_flush"); - _glfw.wl.client.display_cancel_read = (PFN_wl_display_cancel_read) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_cancel_read"); - _glfw.wl.client.display_dispatch_pending = (PFN_wl_display_dispatch_pending) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_dispatch_pending"); - _glfw.wl.client.display_read_events = (PFN_wl_display_read_events) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_read_events"); - _glfw.wl.client.display_disconnect = (PFN_wl_display_disconnect) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_disconnect"); - _glfw.wl.client.display_roundtrip = (PFN_wl_display_roundtrip) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_roundtrip"); - _glfw.wl.client.display_get_fd = (PFN_wl_display_get_fd) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_get_fd"); - _glfw.wl.client.display_prepare_read = (PFN_wl_display_prepare_read) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_prepare_read"); - _glfw.wl.client.proxy_marshal = (PFN_wl_proxy_marshal) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal"); - _glfw.wl.client.proxy_add_listener = (PFN_wl_proxy_add_listener) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_add_listener"); - _glfw.wl.client.proxy_destroy = (PFN_wl_proxy_destroy) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_destroy"); - _glfw.wl.client.proxy_marshal_constructor = (PFN_wl_proxy_marshal_constructor) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_constructor"); - _glfw.wl.client.proxy_marshal_constructor_versioned = (PFN_wl_proxy_marshal_constructor_versioned) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_constructor_versioned"); - _glfw.wl.client.proxy_get_user_data = (PFN_wl_proxy_get_user_data) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_user_data"); - _glfw.wl.client.proxy_set_user_data = (PFN_wl_proxy_set_user_data) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_user_data"); - _glfw.wl.client.proxy_get_tag = (PFN_wl_proxy_get_tag) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_tag"); - _glfw.wl.client.proxy_set_tag = (PFN_wl_proxy_set_tag) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_tag"); - _glfw.wl.client.proxy_get_version = (PFN_wl_proxy_get_version) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_version"); - _glfw.wl.client.proxy_marshal_flags = (PFN_wl_proxy_marshal_flags) - _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_flags"); - - if (!_glfw.wl.client.display_flush || - !_glfw.wl.client.display_cancel_read || - !_glfw.wl.client.display_dispatch_pending || - !_glfw.wl.client.display_read_events || - !_glfw.wl.client.display_disconnect || - !_glfw.wl.client.display_roundtrip || - !_glfw.wl.client.display_get_fd || - !_glfw.wl.client.display_prepare_read || - !_glfw.wl.client.proxy_marshal || - !_glfw.wl.client.proxy_add_listener || - !_glfw.wl.client.proxy_destroy || - !_glfw.wl.client.proxy_marshal_constructor || - !_glfw.wl.client.proxy_marshal_constructor_versioned || - !_glfw.wl.client.proxy_get_user_data || - !_glfw.wl.client.proxy_set_user_data || - !_glfw.wl.client.proxy_get_tag || - !_glfw.wl.client.proxy_set_tag) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load libwayland-client entry point"); - return GLFW_FALSE; - } - - _glfw.wl.cursor.handle = _glfwPlatformLoadModule("libwayland-cursor.so.0"); + _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0"); if (!_glfw.wl.cursor.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load libwayland-cursor"); + "Wayland: Failed to open libwayland-cursor"); return GLFW_FALSE; } _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load) - _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_load"); + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load"); _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy) - _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy"); + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy"); _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor) - _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor"); + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor"); _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer) - _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer"); + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer"); - _glfw.wl.egl.handle = _glfwPlatformLoadModule("libwayland-egl.so.1"); + _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1"); if (!_glfw.wl.egl.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load libwayland-egl"); + "Wayland: Failed to open libwayland-egl"); return GLFW_FALSE; } _glfw.wl.egl.window_create = (PFN_wl_egl_window_create) - _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_create"); + _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create"); _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy) - _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_destroy"); + _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy"); _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize) - _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_resize"); + _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize"); - _glfw.wl.xkb.handle = _glfwPlatformLoadModule("libxkbcommon.so.0"); + _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0"); if (!_glfw.wl.xkb.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load libxkbcommon"); + "Wayland: Failed to open libxkbcommon"); return GLFW_FALSE; } _glfw.wl.xkb.context_new = (PFN_xkb_context_new) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_context_new"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_context_unref"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_unref"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats"); - _glfw.wl.xkb.keymap_key_get_syms_by_level = (PFN_xkb_keymap_key_get_syms_by_level) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_key_get_syms_by_level"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats"); _glfw.wl.xkb.state_new = (PFN_xkb_state_new) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_new"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_unref"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_update_mask"); - _glfw.wl.xkb.state_key_get_layout = (PFN_xkb_state_key_get_layout) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_key_get_layout"); - _glfw.wl.xkb.state_mod_index_is_active = (PFN_xkb_state_mod_index_is_active) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_mod_index_is_active"); - _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); - _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); - _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_new"); - _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); - _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); - _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); - _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); + _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); - if (!_glfw.wl.xkb.context_new || - !_glfw.wl.xkb.context_unref || - !_glfw.wl.xkb.keymap_new_from_string || - !_glfw.wl.xkb.keymap_unref || - !_glfw.wl.xkb.keymap_mod_get_index || - !_glfw.wl.xkb.keymap_key_repeats || - !_glfw.wl.xkb.keymap_key_get_syms_by_level || - !_glfw.wl.xkb.state_new || - !_glfw.wl.xkb.state_unref || - !_glfw.wl.xkb.state_key_get_syms || - !_glfw.wl.xkb.state_update_mask || - !_glfw.wl.xkb.state_key_get_layout || - !_glfw.wl.xkb.state_mod_index_is_active || - !_glfw.wl.xkb.compose_table_new_from_locale || - !_glfw.wl.xkb.compose_table_unref || - !_glfw.wl.xkb.compose_state_new || - !_glfw.wl.xkb.compose_state_unref || - !_glfw.wl.xkb.compose_state_feed || - !_glfw.wl.xkb.compose_state_get_status || - !_glfw.wl.xkb.compose_state_get_one_sym) +#ifdef HAVE_XKBCOMMON_COMPOSE_H + _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); + _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); + _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); + _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); + _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); + _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); + _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); +#endif + + _glfw.wl.display = wl_display_connect(NULL); + if (!_glfw.wl.display) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to load all entry points from libxkbcommon"); + "Wayland: Failed to connect to display"); return GLFW_FALSE; } - if (_glfw.hints.init.wl.libdecorMode == GLFW_WAYLAND_PREFER_LIBDECOR) - _glfw.wl.libdecor.handle = _glfwPlatformLoadModule("libdecor-0.so.0"); - - if (_glfw.wl.libdecor.handle) - { - _glfw.wl.libdecor.libdecor_new_ = (PFN_libdecor_new) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_new"); - _glfw.wl.libdecor.libdecor_unref_ = (PFN_libdecor_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_unref"); - _glfw.wl.libdecor.libdecor_get_fd_ = (PFN_libdecor_get_fd) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_get_fd"); - _glfw.wl.libdecor.libdecor_dispatch_ = (PFN_libdecor_dispatch) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_dispatch"); - _glfw.wl.libdecor.libdecor_decorate_ = (PFN_libdecor_decorate) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_decorate"); - _glfw.wl.libdecor.libdecor_frame_unref_ = (PFN_libdecor_frame_unref) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unref"); - _glfw.wl.libdecor.libdecor_frame_set_app_id_ = (PFN_libdecor_frame_set_app_id) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_app_id"); - _glfw.wl.libdecor.libdecor_frame_set_title_ = (PFN_libdecor_frame_set_title) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_title"); - _glfw.wl.libdecor.libdecor_frame_set_minimized_ = (PFN_libdecor_frame_set_minimized) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_minimized"); - _glfw.wl.libdecor.libdecor_frame_set_fullscreen_ = (PFN_libdecor_frame_set_fullscreen) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_fullscreen"); - _glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ = (PFN_libdecor_frame_unset_fullscreen) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_fullscreen"); - _glfw.wl.libdecor.libdecor_frame_map_ = (PFN_libdecor_frame_map) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_map"); - _glfw.wl.libdecor.libdecor_frame_commit_ = (PFN_libdecor_frame_commit) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_commit"); - _glfw.wl.libdecor.libdecor_frame_set_min_content_size_ = (PFN_libdecor_frame_set_min_content_size) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_min_content_size"); - _glfw.wl.libdecor.libdecor_frame_set_max_content_size_ = (PFN_libdecor_frame_set_max_content_size) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_max_content_size"); - _glfw.wl.libdecor.libdecor_frame_set_maximized_ = (PFN_libdecor_frame_set_maximized) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_maximized"); - _glfw.wl.libdecor.libdecor_frame_unset_maximized_ = (PFN_libdecor_frame_unset_maximized) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_maximized"); - _glfw.wl.libdecor.libdecor_frame_set_capabilities_ = (PFN_libdecor_frame_set_capabilities) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_capabilities"); - _glfw.wl.libdecor.libdecor_frame_unset_capabilities_ = (PFN_libdecor_frame_unset_capabilities) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_capabilities"); - _glfw.wl.libdecor.libdecor_frame_set_visibility_ = (PFN_libdecor_frame_set_visibility) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_visibility"); - _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ = (PFN_libdecor_frame_get_xdg_toplevel) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_get_xdg_toplevel"); - _glfw.wl.libdecor.libdecor_configuration_get_content_size_ = (PFN_libdecor_configuration_get_content_size) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_configuration_get_content_size"); - _glfw.wl.libdecor.libdecor_configuration_get_window_state_ = (PFN_libdecor_configuration_get_window_state) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_configuration_get_window_state"); - _glfw.wl.libdecor.libdecor_state_new_ = (PFN_libdecor_state_new) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_state_new"); - _glfw.wl.libdecor.libdecor_state_free_ = (PFN_libdecor_state_free) - _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_state_free"); - - if (!_glfw.wl.libdecor.libdecor_new_ || - !_glfw.wl.libdecor.libdecor_unref_ || - !_glfw.wl.libdecor.libdecor_get_fd_ || - !_glfw.wl.libdecor.libdecor_dispatch_ || - !_glfw.wl.libdecor.libdecor_decorate_ || - !_glfw.wl.libdecor.libdecor_frame_unref_ || - !_glfw.wl.libdecor.libdecor_frame_set_app_id_ || - !_glfw.wl.libdecor.libdecor_frame_set_title_ || - !_glfw.wl.libdecor.libdecor_frame_set_minimized_ || - !_glfw.wl.libdecor.libdecor_frame_set_fullscreen_ || - !_glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ || - !_glfw.wl.libdecor.libdecor_frame_map_ || - !_glfw.wl.libdecor.libdecor_frame_commit_ || - !_glfw.wl.libdecor.libdecor_frame_set_min_content_size_ || - !_glfw.wl.libdecor.libdecor_frame_set_max_content_size_ || - !_glfw.wl.libdecor.libdecor_frame_set_maximized_ || - !_glfw.wl.libdecor.libdecor_frame_unset_maximized_ || - !_glfw.wl.libdecor.libdecor_frame_set_capabilities_ || - !_glfw.wl.libdecor.libdecor_frame_unset_capabilities_ || - !_glfw.wl.libdecor.libdecor_frame_set_visibility_ || - !_glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ || - !_glfw.wl.libdecor.libdecor_configuration_get_content_size_ || - !_glfw.wl.libdecor.libdecor_configuration_get_window_state_ || - !_glfw.wl.libdecor.libdecor_state_new_ || - !_glfw.wl.libdecor.libdecor_state_free_) - { - _glfwPlatformFreeModule(_glfw.wl.libdecor.handle); - memset(&_glfw.wl.libdecor, 0, sizeof(_glfw.wl.libdecor)); - } - } - _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); - createKeyTablesWayland(); + createKeyTables(); _glfw.wl.xkb.context = xkb_context_new(0); if (!_glfw.wl.xkb.context) @@ -838,27 +1148,22 @@ int _glfwInitWayland(void) // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); - if (_glfw.wl.libdecor.handle) + for (i = 0; i < _glfw.monitorCount; ++i) { - _glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface); - if (_glfw.wl.libdecor.context) + monitor = _glfw.monitors[i]; + if (monitor->widthMM <= 0 || monitor->heightMM <= 0) { - // Perform an initial dispatch and flush to get the init started - libdecor_dispatch(_glfw.wl.libdecor.context, 0); - - // Create sync point to "know" when libdecor is ready for use - _glfw.wl.libdecor.callback = wl_display_sync(_glfw.wl.display); - wl_callback_add_listener(_glfw.wl.libdecor.callback, - &libdecorReadyListener, - NULL); + // If Wayland does not provide a physical size, assume the default 96 DPI + monitor->widthMM = (int) (monitor->modes[monitor->wl.currentMode].width * 25.4f / 96.f); + monitor->heightMM = (int) (monitor->modes[monitor->wl.currentMode].height * 25.4f / 96.f); } } - if (wl_seat_get_version(_glfw.wl.seat) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) - { - _glfw.wl.keyRepeatTimerfd = - timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); - } + _glfwInitTimerPOSIX(); + + _glfw.wl.timerfd = -1; + if (_glfw.wl.seatVersion >= 4) + _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); if (!_glfw.wl.wmBase) { @@ -867,56 +1172,66 @@ int _glfwInitWayland(void) return GLFW_FALSE; } - if (!_glfw.wl.shm) + if (_glfw.wl.pointer && _glfw.wl.shm) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to find wl_shm in your compositor"); - return GLFW_FALSE; + cursorTheme = getenv("XCURSOR_THEME"); + cursorSizeStr = getenv("XCURSOR_SIZE"); + cursorSize = 32; + if (cursorSizeStr) + { + errno = 0; + cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10); + if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX) + cursorSize = (int)cursorSizeLong; + } + _glfw.wl.cursorTheme = + wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm); + if (!_glfw.wl.cursorTheme) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to load default cursor theme"); + return GLFW_FALSE; + } + // If this happens to be NULL, we just fallback to the scale=1 version. + _glfw.wl.cursorThemeHiDPI = + wl_cursor_theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm); + _glfw.wl.cursorSurface = + wl_compositor_create_surface(_glfw.wl.compositor); + _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); } - if (!loadCursorTheme()) - return GLFW_FALSE; - if (_glfw.wl.seat && _glfw.wl.dataDeviceManager) { _glfw.wl.dataDevice = wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager, _glfw.wl.seat); - _glfwAddDataDeviceListenerWayland(_glfw.wl.dataDevice); + wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL); + _glfw.wl.clipboardString = malloc(4096); + if (!_glfw.wl.clipboardString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to allocate clipboard memory"); + return GLFW_FALSE; + } + _glfw.wl.clipboardSize = 4096; } return GLFW_TRUE; } -void _glfwTerminateWayland(void) +void _glfwPlatformTerminate(void) { _glfwTerminateEGL(); - _glfwTerminateOSMesa(); - - if (_glfw.wl.libdecor.context) - { - // Allow libdecor to finish receiving all its requested globals - // and ensure the associated sync callback object is destroyed - while (!_glfw.wl.libdecor.ready) - _glfwWaitEventsWayland(); - - libdecor_unref(_glfw.wl.libdecor.context); - } - - if (_glfw.wl.libdecor.handle) - { - _glfwPlatformFreeModule(_glfw.wl.libdecor.handle); - _glfw.wl.libdecor.handle = NULL; - } - if (_glfw.wl.egl.handle) { - _glfwPlatformFreeModule(_glfw.wl.egl.handle); + _glfw_dlclose(_glfw.wl.egl.handle); _glfw.wl.egl.handle = NULL; } +#ifdef HAVE_XKBCOMMON_COMPOSE_H if (_glfw.wl.xkb.composeState) xkb_compose_state_unref(_glfw.wl.xkb.composeState); +#endif if (_glfw.wl.xkb.keymap) xkb_keymap_unref(_glfw.wl.xkb.keymap); if (_glfw.wl.xkb.state) @@ -925,7 +1240,7 @@ void _glfwTerminateWayland(void) xkb_context_unref(_glfw.wl.xkb.context); if (_glfw.wl.xkb.handle) { - _glfwPlatformFreeModule(_glfw.wl.xkb.handle); + _glfw_dlclose(_glfw.wl.xkb.handle); _glfw.wl.xkb.handle = NULL; } @@ -935,15 +1250,10 @@ void _glfwTerminateWayland(void) wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI); if (_glfw.wl.cursor.handle) { - _glfwPlatformFreeModule(_glfw.wl.cursor.handle); + _glfw_dlclose(_glfw.wl.cursor.handle); _glfw.wl.cursor.handle = NULL; } - for (unsigned int i = 0; i < _glfw.wl.offerCount; i++) - wl_data_offer_destroy(_glfw.wl.offers[i].offer); - - _glfw_free(_glfw.wl.offers); - if (_glfw.wl.cursorSurface) wl_surface_destroy(_glfw.wl.cursorSurface); if (_glfw.wl.subcompositor) @@ -958,14 +1268,12 @@ void _glfwTerminateWayland(void) zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager); if (_glfw.wl.wmBase) xdg_wm_base_destroy(_glfw.wl.wmBase); - if (_glfw.wl.selectionOffer) - wl_data_offer_destroy(_glfw.wl.selectionOffer); - if (_glfw.wl.dragOffer) - wl_data_offer_destroy(_glfw.wl.dragOffer); - if (_glfw.wl.selectionSource) - wl_data_source_destroy(_glfw.wl.selectionSource); + if (_glfw.wl.dataSource) + wl_data_source_destroy(_glfw.wl.dataSource); if (_glfw.wl.dataDevice) wl_data_device_destroy(_glfw.wl.dataDevice); + if (_glfw.wl.dataOffer) + wl_data_offer_destroy(_glfw.wl.dataOffer); if (_glfw.wl.dataDeviceManager) wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager); if (_glfw.wl.pointer) @@ -980,10 +1288,6 @@ void _glfwTerminateWayland(void) zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); if (_glfw.wl.idleInhibitManager) zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); - if (_glfw.wl.activationManager) - xdg_activation_v1_destroy(_glfw.wl.activationManager); - if (_glfw.wl.fractionalScaleManager) - wp_fractional_scale_manager_v1_destroy(_glfw.wl.fractionalScaleManager); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) @@ -992,13 +1296,28 @@ void _glfwTerminateWayland(void) wl_display_disconnect(_glfw.wl.display); } - if (_glfw.wl.keyRepeatTimerfd >= 0) - close(_glfw.wl.keyRepeatTimerfd); + if (_glfw.wl.timerfd >= 0) + close(_glfw.wl.timerfd); if (_glfw.wl.cursorTimerfd >= 0) close(_glfw.wl.cursorTimerfd); - _glfw_free(_glfw.wl.clipboardString); + if (_glfw.wl.clipboardString) + free(_glfw.wl.clipboardString); + if (_glfw.wl.clipboardSendString) + free(_glfw.wl.clipboardSendString); } -#endif // _GLFW_WAYLAND - +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Wayland EGL OSMesa" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif + " evdev" +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} diff --git a/raylib/external/glfw/src/wl_monitor.c b/raylib/external/glfw/src/wl_monitor.c index df30313..a6356de 100644 --- a/raylib/external/glfw/src/wl_monitor.c +++ b/raylib/external/glfw/src/wl_monitor.c @@ -23,21 +23,19 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_WAYLAND) - #include #include #include #include #include -#include "wayland-client-protocol.h" - -static void outputHandleGeometry(void* userData, +static void outputHandleGeometry(void* data, struct wl_output* output, int32_t x, int32_t y, @@ -48,25 +46,26 @@ static void outputHandleGeometry(void* userData, const char* model, int32_t transform) { - struct _GLFWmonitor* monitor = userData; + struct _GLFWmonitor *monitor = data; + char name[1024]; monitor->wl.x = x; monitor->wl.y = y; monitor->widthMM = physicalWidth; monitor->heightMM = physicalHeight; - if (strlen(monitor->name) == 0) - snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); + snprintf(name, sizeof(name), "%s %s", make, model); + monitor->name = _glfw_strdup(name); } -static void outputHandleMode(void* userData, +static void outputHandleMode(void* data, struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { - struct _GLFWmonitor* monitor = userData; + struct _GLFWmonitor *monitor = data; GLFWvidmode mode; mode.width = width; @@ -78,77 +77,34 @@ static void outputHandleMode(void* userData, monitor->modeCount++; monitor->modes = - _glfw_realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); + realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); monitor->modes[monitor->modeCount - 1] = mode; if (flags & WL_OUTPUT_MODE_CURRENT) monitor->wl.currentMode = monitor->modeCount - 1; } -static void outputHandleDone(void* userData, struct wl_output* output) +static void outputHandleDone(void* data, struct wl_output* output) { - struct _GLFWmonitor* monitor = userData; - - if (monitor->widthMM <= 0 || monitor->heightMM <= 0) - { - // If Wayland does not provide a physical size, assume the default 96 DPI - const GLFWvidmode* mode = &monitor->modes[monitor->wl.currentMode]; - monitor->widthMM = (int) (mode->width * 25.4f / 96.f); - monitor->heightMM = (int) (mode->height * 25.4f / 96.f); - } - - for (int i = 0; i < _glfw.monitorCount; i++) - { - if (_glfw.monitors[i] == monitor) - return; - } + struct _GLFWmonitor *monitor = data; _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } -static void outputHandleScale(void* userData, +static void outputHandleScale(void* data, struct wl_output* output, int32_t factor) { - struct _GLFWmonitor* monitor = userData; + struct _GLFWmonitor *monitor = data; monitor->wl.scale = factor; - - for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) - { - for (size_t i = 0; i < window->wl.outputScaleCount; i++) - { - if (window->wl.outputScales[i].output == monitor->wl.output) - { - window->wl.outputScales[i].factor = monitor->wl.scale; - _glfwUpdateBufferScaleFromOutputsWayland(window); - break; - } - } - } } -void outputHandleName(void* userData, struct wl_output* wl_output, const char* name) -{ - struct _GLFWmonitor* monitor = userData; - - strncpy(monitor->name, name, sizeof(monitor->name) - 1); -} - -void outputHandleDescription(void* userData, - struct wl_output* wl_output, - const char* description) -{ -} - -static const struct wl_output_listener outputListener = -{ +static const struct wl_output_listener outputListener = { outputHandleGeometry, outputHandleMode, outputHandleDone, outputHandleScale, - outputHandleName, - outputHandleDescription, }; @@ -158,6 +114,9 @@ static const struct wl_output_listener outputListener = void _glfwAddOutputWayland(uint32_t name, uint32_t version) { + _GLFWmonitor *monitor; + struct wl_output *output; + if (version < 2) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -165,22 +124,23 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) return; } - version = _glfw_min(version, WL_OUTPUT_NAME_SINCE_VERSION); + // The actual name of this output will be set in the geometry handler. + monitor = _glfwAllocMonitor(NULL, 0, 0); - struct wl_output* output = wl_registry_bind(_glfw.wl.registry, - name, - &wl_output_interface, - version); + output = wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + 2); if (!output) + { + _glfwFreeMonitor(monitor); return; + } - // The actual name of this output will be set in the geometry handler - _GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0); monitor->wl.scale = 1; monitor->wl.output = output; monitor->wl.name = name; - wl_proxy_set_tag((struct wl_proxy*) output, &_glfw.wl.tag); wl_output_add_listener(output, &outputListener, monitor); } @@ -189,13 +149,13 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwFreeMonitorWayland(_GLFWmonitor* monitor) +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { if (monitor->wl.output) wl_output_destroy(monitor->wl.output); } -void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (xpos) *xpos = monitor->wl.x; @@ -203,8 +163,8 @@ void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = monitor->wl.y; } -void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) { if (xscale) *xscale = (float) monitor->wl.scale; @@ -212,9 +172,9 @@ void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, *yscale = (float) monitor->wl.scale; } -void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor, - int* xpos, int* ypos, - int* width, int* height) +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) { if (xpos) *xpos = monitor->wl.x; @@ -226,26 +186,26 @@ void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor, *height = monitor->modes[monitor->wl.currentMode].height; } -GLFWvidmode* _glfwGetVideoModesWayland(_GLFWmonitor* monitor, int* found) +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { *found = monitor->modeCount; return monitor->modes; } -GLFWbool _glfwGetVideoModeWayland(_GLFWmonitor* monitor, GLFWvidmode* mode) +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { *mode = monitor->modes[monitor->wl.currentMode]; - return GLFW_TRUE; } -GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { _glfwInputError(GLFW_FEATURE_UNAVAILABLE, "Wayland: Gamma ramp access is not available"); return GLFW_FALSE; } -void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, + const GLFWgammaramp* ramp) { _glfwInputError(GLFW_FEATURE_UNAVAILABLE, "Wayland: Gamma ramp access is not available"); @@ -260,15 +220,6 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Wayland: Platform not initialized"); - return NULL; - } - return monitor->wl.output; } -#endif // _GLFW_WAYLAND - diff --git a/raylib/external/glfw/src/wl_platform.h b/raylib/external/glfw/src/wl_platform.h index 149cd24..966155f 100644 --- a/raylib/external/glfw/src/wl_platform.h +++ b/raylib/external/glfw/src/wl_platform.h @@ -24,11 +24,12 @@ // //======================================================================== -#include +#include #include +#ifdef HAVE_XKBCOMMON_COMPOSE_H #include - -#include +#endif +#include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -44,100 +45,33 @@ typedef struct VkWaylandSurfaceCreateInfoKHR typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); +#include "posix_thread.h" +#include "posix_time.h" +#ifdef __linux__ +#include "linux_joystick.h" +#else +#include "null_joystick.h" +#endif #include "xkb_unicode.h" -#include "posix_poll.h" -typedef int (* PFN_wl_display_flush)(struct wl_display* display); -typedef void (* PFN_wl_display_cancel_read)(struct wl_display* display); -typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display* display); -typedef int (* PFN_wl_display_read_events)(struct wl_display* display); -typedef struct wl_display* (* PFN_wl_display_connect)(const char*); -typedef void (* PFN_wl_display_disconnect)(struct wl_display*); -typedef int (* PFN_wl_display_roundtrip)(struct wl_display*); -typedef int (* PFN_wl_display_get_fd)(struct wl_display*); -typedef int (* PFN_wl_display_prepare_read)(struct wl_display*); -typedef void (* PFN_wl_proxy_marshal)(struct wl_proxy*,uint32_t,...); -typedef int (* PFN_wl_proxy_add_listener)(struct wl_proxy*,void(**)(void),void*); -typedef void (* PFN_wl_proxy_destroy)(struct wl_proxy*); -typedef struct wl_proxy* (* PFN_wl_proxy_marshal_constructor)(struct wl_proxy*,uint32_t,const struct wl_interface*,...); -typedef struct wl_proxy* (* PFN_wl_proxy_marshal_constructor_versioned)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,...); -typedef void* (* PFN_wl_proxy_get_user_data)(struct wl_proxy*); -typedef void (* PFN_wl_proxy_set_user_data)(struct wl_proxy*,void*); -typedef void (* PFN_wl_proxy_set_tag)(struct wl_proxy*,const char*const*); -typedef const char* const* (* PFN_wl_proxy_get_tag)(struct wl_proxy*); -typedef uint32_t (* PFN_wl_proxy_get_version)(struct wl_proxy*); -typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,uint32_t,...); -#define wl_display_flush _glfw.wl.client.display_flush -#define wl_display_cancel_read _glfw.wl.client.display_cancel_read -#define wl_display_dispatch_pending _glfw.wl.client.display_dispatch_pending -#define wl_display_read_events _glfw.wl.client.display_read_events -#define wl_display_disconnect _glfw.wl.client.display_disconnect -#define wl_display_roundtrip _glfw.wl.client.display_roundtrip -#define wl_display_get_fd _glfw.wl.client.display_get_fd -#define wl_display_prepare_read _glfw.wl.client.display_prepare_read -#define wl_proxy_marshal _glfw.wl.client.proxy_marshal -#define wl_proxy_add_listener _glfw.wl.client.proxy_add_listener -#define wl_proxy_destroy _glfw.wl.client.proxy_destroy -#define wl_proxy_marshal_constructor _glfw.wl.client.proxy_marshal_constructor -#define wl_proxy_marshal_constructor_versioned _glfw.wl.client.proxy_marshal_constructor_versioned -#define wl_proxy_get_user_data _glfw.wl.client.proxy_get_user_data -#define wl_proxy_set_user_data _glfw.wl.client.proxy_set_user_data -#define wl_proxy_get_tag _glfw.wl.client.proxy_get_tag -#define wl_proxy_set_tag _glfw.wl.client.proxy_set_tag -#define wl_proxy_get_version _glfw.wl.client.proxy_get_version -#define wl_proxy_marshal_flags _glfw.wl.client.proxy_marshal_flags +#include "wayland-xdg-shell-client-protocol.h" +#include "wayland-xdg-decoration-client-protocol.h" +#include "wayland-viewporter-client-protocol.h" +#include "wayland-relative-pointer-unstable-v1-client-protocol.h" +#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" +#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" -struct wl_shm; -struct wl_output; +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) -#define wl_display_interface _glfw_wl_display_interface -#define wl_subcompositor_interface _glfw_wl_subcompositor_interface -#define wl_compositor_interface _glfw_wl_compositor_interface -#define wl_shm_interface _glfw_wl_shm_interface -#define wl_data_device_manager_interface _glfw_wl_data_device_manager_interface -#define wl_shell_interface _glfw_wl_shell_interface -#define wl_buffer_interface _glfw_wl_buffer_interface -#define wl_callback_interface _glfw_wl_callback_interface -#define wl_data_device_interface _glfw_wl_data_device_interface -#define wl_data_offer_interface _glfw_wl_data_offer_interface -#define wl_data_source_interface _glfw_wl_data_source_interface -#define wl_keyboard_interface _glfw_wl_keyboard_interface -#define wl_output_interface _glfw_wl_output_interface -#define wl_pointer_interface _glfw_wl_pointer_interface -#define wl_region_interface _glfw_wl_region_interface -#define wl_registry_interface _glfw_wl_registry_interface -#define wl_seat_interface _glfw_wl_seat_interface -#define wl_shell_surface_interface _glfw_wl_shell_surface_interface -#define wl_shm_pool_interface _glfw_wl_shm_pool_interface -#define wl_subsurface_interface _glfw_wl_subsurface_interface -#define wl_surface_interface _glfw_wl_surface_interface -#define wl_touch_interface _glfw_wl_touch_interface -#define zwp_idle_inhibitor_v1_interface _glfw_zwp_idle_inhibitor_v1_interface -#define zwp_idle_inhibit_manager_v1_interface _glfw_zwp_idle_inhibit_manager_v1_interface -#define zwp_confined_pointer_v1_interface _glfw_zwp_confined_pointer_v1_interface -#define zwp_locked_pointer_v1_interface _glfw_zwp_locked_pointer_v1_interface -#define zwp_pointer_constraints_v1_interface _glfw_zwp_pointer_constraints_v1_interface -#define zwp_relative_pointer_v1_interface _glfw_zwp_relative_pointer_v1_interface -#define zwp_relative_pointer_manager_v1_interface _glfw_zwp_relative_pointer_manager_v1_interface -#define wp_viewport_interface _glfw_wp_viewport_interface -#define wp_viewporter_interface _glfw_wp_viewporter_interface -#define xdg_toplevel_interface _glfw_xdg_toplevel_interface -#define zxdg_toplevel_decoration_v1_interface _glfw_zxdg_toplevel_decoration_v1_interface -#define zxdg_decoration_manager_v1_interface _glfw_zxdg_decoration_manager_v1_interface -#define xdg_popup_interface _glfw_xdg_popup_interface -#define xdg_positioner_interface _glfw_xdg_positioner_interface -#define xdg_surface_interface _glfw_xdg_surface_interface -#define xdg_toplevel_interface _glfw_xdg_toplevel_interface -#define xdg_wm_base_interface _glfw_xdg_wm_base_interface -#define xdg_activation_v1_interface _glfw_xdg_activation_v1_interface -#define xdg_activation_token_v1_interface _glfw_xdg_activation_token_v1_interface -#define wl_surface_interface _glfw_wl_surface_interface -#define wp_fractional_scale_v1_interface _glfw_wp_fractional_scale_v1_interface +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl -#define GLFW_WAYLAND_WINDOW_STATE _GLFWwindowWayland wl; -#define GLFW_WAYLAND_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl; -#define GLFW_WAYLAND_MONITOR_STATE _GLFWmonitorWayland wl; -#define GLFW_WAYLAND_CURSOR_STATE _GLFWcursorWayland wl; +#define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; } +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; } struct wl_cursor_image { uint32_t width; @@ -173,27 +107,24 @@ typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*); typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*); typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t); -typedef int (* PFN_xkb_keymap_key_get_syms_by_level)(struct xkb_keymap*,xkb_keycode_t,xkb_layout_index_t,xkb_level_index_t,const xkb_keysym_t**); typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); typedef void (* PFN_xkb_state_unref)(struct xkb_state*); typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t); -typedef xkb_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xkb_keycode_t); -typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_index_t,enum xkb_state_component); +typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); #define xkb_context_new _glfw.wl.xkb.context_new #define xkb_context_unref _glfw.wl.xkb.context_unref #define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string #define xkb_keymap_unref _glfw.wl.xkb.keymap_unref #define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index #define xkb_keymap_key_repeats _glfw.wl.xkb.keymap_key_repeats -#define xkb_keymap_key_get_syms_by_level _glfw.wl.xkb.keymap_key_get_syms_by_level #define xkb_state_new _glfw.wl.xkb.state_new #define xkb_state_unref _glfw.wl.xkb.state_unref #define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms #define xkb_state_update_mask _glfw.wl.xkb.state_update_mask -#define xkb_state_key_get_layout _glfw.wl.xkb.state_key_get_layout -#define xkb_state_mod_index_is_active _glfw.wl.xkb.state_mod_index_is_active +#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods +#ifdef HAVE_XKBCOMMON_COMPOSE_H typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); @@ -208,211 +139,78 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st #define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed #define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym +#endif -struct libdecor; -struct libdecor_frame; -struct libdecor_state; -struct libdecor_configuration; +#define _GLFW_DECORATION_WIDTH 4 +#define _GLFW_DECORATION_TOP 24 +#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH) +#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH) -enum libdecor_error +typedef enum _GLFWdecorationSideWayland { - LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, - LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION, -}; + mainWindow, + topDecoration, + leftDecoration, + rightDecoration, + bottomDecoration, -enum libdecor_window_state -{ - LIBDECOR_WINDOW_STATE_NONE = 0, - LIBDECOR_WINDOW_STATE_ACTIVE = 1, - LIBDECOR_WINDOW_STATE_MAXIMIZED = 2, - LIBDECOR_WINDOW_STATE_FULLSCREEN = 4, - LIBDECOR_WINDOW_STATE_TILED_LEFT = 8, - LIBDECOR_WINDOW_STATE_TILED_RIGHT = 16, - LIBDECOR_WINDOW_STATE_TILED_TOP = 32, - LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 64 -}; +} _GLFWdecorationSideWayland; -enum libdecor_capabilities -{ - LIBDECOR_ACTION_MOVE = 1, - LIBDECOR_ACTION_RESIZE = 2, - LIBDECOR_ACTION_MINIMIZE = 4, - LIBDECOR_ACTION_FULLSCREEN = 8, - LIBDECOR_ACTION_CLOSE = 16 -}; - -struct libdecor_interface -{ - void (* error)(struct libdecor*,enum libdecor_error,const char*); - void (* reserved0)(void); - void (* reserved1)(void); - void (* reserved2)(void); - void (* reserved3)(void); - void (* reserved4)(void); - void (* reserved5)(void); - void (* reserved6)(void); - void (* reserved7)(void); - void (* reserved8)(void); - void (* reserved9)(void); -}; - -struct libdecor_frame_interface -{ - void (* configure)(struct libdecor_frame*,struct libdecor_configuration*,void*); - void (* close)(struct libdecor_frame*,void*); - void (* commit)(struct libdecor_frame*,void*); - void (* dismiss_popup)(struct libdecor_frame*,const char*,void*); - void (* reserved0)(void); - void (* reserved1)(void); - void (* reserved2)(void); - void (* reserved3)(void); - void (* reserved4)(void); - void (* reserved5)(void); - void (* reserved6)(void); - void (* reserved7)(void); - void (* reserved8)(void); - void (* reserved9)(void); -}; - -typedef struct libdecor* (* PFN_libdecor_new)(struct wl_display*,const struct libdecor_interface*); -typedef void (* PFN_libdecor_unref)(struct libdecor*); -typedef int (* PFN_libdecor_get_fd)(struct libdecor*); -typedef int (* PFN_libdecor_dispatch)(struct libdecor*,int); -typedef struct libdecor_frame* (* PFN_libdecor_decorate)(struct libdecor*,struct wl_surface*,const struct libdecor_frame_interface*,void*); -typedef void (* PFN_libdecor_frame_unref)(struct libdecor_frame*); -typedef void (* PFN_libdecor_frame_set_app_id)(struct libdecor_frame*,const char*); -typedef void (* PFN_libdecor_frame_set_title)(struct libdecor_frame*,const char*); -typedef void (* PFN_libdecor_frame_set_minimized)(struct libdecor_frame*); -typedef void (* PFN_libdecor_frame_set_fullscreen)(struct libdecor_frame*,struct wl_output*); -typedef void (* PFN_libdecor_frame_unset_fullscreen)(struct libdecor_frame*); -typedef void (* PFN_libdecor_frame_map)(struct libdecor_frame*); -typedef void (* PFN_libdecor_frame_commit)(struct libdecor_frame*,struct libdecor_state*,struct libdecor_configuration*); -typedef void (* PFN_libdecor_frame_set_min_content_size)(struct libdecor_frame*,int,int); -typedef void (* PFN_libdecor_frame_set_max_content_size)(struct libdecor_frame*,int,int); -typedef void (* PFN_libdecor_frame_set_maximized)(struct libdecor_frame*); -typedef void (* PFN_libdecor_frame_unset_maximized)(struct libdecor_frame*); -typedef void (* PFN_libdecor_frame_set_capabilities)(struct libdecor_frame*,enum libdecor_capabilities); -typedef void (* PFN_libdecor_frame_unset_capabilities)(struct libdecor_frame*,enum libdecor_capabilities); -typedef void (* PFN_libdecor_frame_set_visibility)(struct libdecor_frame*,bool visible); -typedef struct xdg_toplevel* (* PFN_libdecor_frame_get_xdg_toplevel)(struct libdecor_frame*); -typedef bool (* PFN_libdecor_configuration_get_content_size)(struct libdecor_configuration*,struct libdecor_frame*,int*,int*); -typedef bool (* PFN_libdecor_configuration_get_window_state)(struct libdecor_configuration*,enum libdecor_window_state*); -typedef struct libdecor_state* (* PFN_libdecor_state_new)(int,int); -typedef void (* PFN_libdecor_state_free)(struct libdecor_state*); -#define libdecor_new _glfw.wl.libdecor.libdecor_new_ -#define libdecor_unref _glfw.wl.libdecor.libdecor_unref_ -#define libdecor_get_fd _glfw.wl.libdecor.libdecor_get_fd_ -#define libdecor_dispatch _glfw.wl.libdecor.libdecor_dispatch_ -#define libdecor_decorate _glfw.wl.libdecor.libdecor_decorate_ -#define libdecor_frame_unref _glfw.wl.libdecor.libdecor_frame_unref_ -#define libdecor_frame_set_app_id _glfw.wl.libdecor.libdecor_frame_set_app_id_ -#define libdecor_frame_set_title _glfw.wl.libdecor.libdecor_frame_set_title_ -#define libdecor_frame_set_minimized _glfw.wl.libdecor.libdecor_frame_set_minimized_ -#define libdecor_frame_set_fullscreen _glfw.wl.libdecor.libdecor_frame_set_fullscreen_ -#define libdecor_frame_unset_fullscreen _glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ -#define libdecor_frame_map _glfw.wl.libdecor.libdecor_frame_map_ -#define libdecor_frame_commit _glfw.wl.libdecor.libdecor_frame_commit_ -#define libdecor_frame_set_min_content_size _glfw.wl.libdecor.libdecor_frame_set_min_content_size_ -#define libdecor_frame_set_max_content_size _glfw.wl.libdecor.libdecor_frame_set_max_content_size_ -#define libdecor_frame_set_maximized _glfw.wl.libdecor.libdecor_frame_set_maximized_ -#define libdecor_frame_unset_maximized _glfw.wl.libdecor.libdecor_frame_unset_maximized_ -#define libdecor_frame_set_capabilities _glfw.wl.libdecor.libdecor_frame_set_capabilities_ -#define libdecor_frame_unset_capabilities _glfw.wl.libdecor.libdecor_frame_unset_capabilities_ -#define libdecor_frame_set_visibility _glfw.wl.libdecor.libdecor_frame_set_visibility_ -#define libdecor_frame_get_xdg_toplevel _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ -#define libdecor_configuration_get_content_size _glfw.wl.libdecor.libdecor_configuration_get_content_size_ -#define libdecor_configuration_get_window_state _glfw.wl.libdecor.libdecor_configuration_get_window_state_ -#define libdecor_state_new _glfw.wl.libdecor.libdecor_state_new_ -#define libdecor_state_free _glfw.wl.libdecor.libdecor_state_free_ - -typedef struct _GLFWfallbackEdgeWayland +typedef struct _GLFWdecorationWayland { struct wl_surface* surface; struct wl_subsurface* subsurface; struct wp_viewport* viewport; -} _GLFWfallbackEdgeWayland; -typedef struct _GLFWofferWayland -{ - struct wl_data_offer* offer; - GLFWbool text_plain_utf8; - GLFWbool text_uri_list; -} _GLFWofferWayland; - -typedef struct _GLFWscaleWayland -{ - struct wl_output* output; - int32_t factor; -} _GLFWscaleWayland; +} _GLFWdecorationWayland; // Wayland-specific per-window data // typedef struct _GLFWwindowWayland { int width, height; - int fbWidth, fbHeight; GLFWbool visible; GLFWbool maximized; - GLFWbool activated; - GLFWbool fullscreen; GLFWbool hovered; GLFWbool transparent; - GLFWbool scaleFramebuffer; struct wl_surface* surface; + struct wl_egl_window* native; struct wl_callback* callback; - struct { - struct wl_egl_window* window; - } egl; - - struct { - int width, height; - GLFWbool maximized; - GLFWbool iconified; - GLFWbool activated; - GLFWbool fullscreen; - } pending; - struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; struct zxdg_toplevel_decoration_v1* decoration; - uint32_t decorationMode; } xdg; - struct { - struct libdecor_frame* frame; - } libdecor; - _GLFWcursor* currentCursor; double cursorPosX, cursorPosY; - char* appId; + char* title; // We need to track the monitors the window spans on to calculate the // optimal scaling factor. - int32_t bufferScale; - _GLFWscaleWayland* outputScales; - size_t outputScaleCount; - size_t outputScaleSize; - - struct wp_viewport* scalingViewport; - uint32_t scalingNumerator; - struct wp_fractional_scale_v1* fractionalScale; - - struct zwp_relative_pointer_v1* relativePointer; - struct zwp_locked_pointer_v1* lockedPointer; - struct zwp_confined_pointer_v1* confinedPointer; - - struct zwp_idle_inhibitor_v1* idleInhibitor; - struct xdg_activation_token_v1* activationToken; + int scale; + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; struct { - GLFWbool decorations; - struct wl_buffer* buffer; - _GLFWfallbackEdgeWayland top, left, right, bottom; - struct wl_surface* focus; - } fallback; + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + } pointerLock; + + struct zwp_idle_inhibitor_v1* idleInhibitor; + + GLFWbool wasFullscreen; + + struct { + GLFWbool serverSide; + struct wl_buffer* buffer; + _GLFWdecorationWayland top, left, right, bottom; + int focus; + } decorations; + } _GLFWwindowWayland; // Wayland-specific global data @@ -429,26 +227,17 @@ typedef struct _GLFWlibraryWayland struct wl_keyboard* keyboard; struct wl_data_device_manager* dataDeviceManager; struct wl_data_device* dataDevice; + struct wl_data_offer* dataOffer; + struct wl_data_source* dataSource; struct xdg_wm_base* wmBase; struct zxdg_decoration_manager_v1* decorationManager; struct wp_viewporter* viewporter; struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_idle_inhibit_manager_v1* idleInhibitManager; - struct xdg_activation_v1* activationManager; - struct wp_fractional_scale_manager_v1* fractionalScaleManager; - _GLFWofferWayland* offers; - unsigned int offerCount; - - struct wl_data_offer* selectionOffer; - struct wl_data_source* selectionSource; - - struct wl_data_offer* dragOffer; - _GLFWwindow* dragFocus; - uint32_t dragSerial; - - const char* tag; + int compositorVersion; + int seatVersion; struct wl_cursor_theme* cursorTheme; struct wl_cursor_theme* cursorThemeHiDPI; @@ -456,17 +245,18 @@ typedef struct _GLFWlibraryWayland const char* cursorPreviousName; int cursorTimerfd; uint32_t serial; - uint32_t pointerEnterSerial; - - int keyRepeatTimerfd; - int32_t keyRepeatRate; - int32_t keyRepeatDelay; - int keyRepeatScancode; + int32_t keyboardRepeatRate; + int32_t keyboardRepeatDelay; + int keyboardLastKey; + int keyboardLastScancode; char* clipboardString; + size_t clipboardSize; + char* clipboardSendString; + size_t clipboardSendSize; + int timerfd; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1]; - char keynames[GLFW_KEY_LAST + 1][5]; struct { void* handle; @@ -474,14 +264,16 @@ typedef struct _GLFWlibraryWayland struct xkb_keymap* keymap; struct xkb_state* state; +#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_state* composeState; +#endif - xkb_mod_index_t controlIndex; - xkb_mod_index_t altIndex; - xkb_mod_index_t shiftIndex; - xkb_mod_index_t superIndex; - xkb_mod_index_t capsLockIndex; - xkb_mod_index_t numLockIndex; + xkb_mod_mask_t controlMask; + xkb_mod_mask_t altMask; + xkb_mod_mask_t shiftMask; + xkb_mod_mask_t superMask; + xkb_mod_mask_t capsLockMask; + xkb_mod_mask_t numLockMask; unsigned int modifiers; PFN_xkb_context_new context_new; @@ -490,14 +282,13 @@ typedef struct _GLFWlibraryWayland PFN_xkb_keymap_unref keymap_unref; PFN_xkb_keymap_mod_get_index keymap_mod_get_index; PFN_xkb_keymap_key_repeats keymap_key_repeats; - PFN_xkb_keymap_key_get_syms_by_level keymap_key_get_syms_by_level; PFN_xkb_state_new state_new; PFN_xkb_state_unref state_unref; PFN_xkb_state_key_get_syms state_key_get_syms; PFN_xkb_state_update_mask state_update_mask; - PFN_xkb_state_key_get_layout state_key_get_layout; - PFN_xkb_state_mod_index_is_active state_mod_index_is_active; + PFN_xkb_state_serialize_mods state_serialize_mods; +#ifdef HAVE_XKBCOMMON_COMPOSE_H PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; PFN_xkb_compose_table_unref compose_table_unref; PFN_xkb_compose_state_new compose_state_new; @@ -505,34 +296,12 @@ typedef struct _GLFWlibraryWayland PFN_xkb_compose_state_feed compose_state_feed; PFN_xkb_compose_state_get_status compose_state_get_status; PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; +#endif } xkb; _GLFWwindow* pointerFocus; _GLFWwindow* keyboardFocus; - struct { - void* handle; - PFN_wl_display_flush display_flush; - PFN_wl_display_cancel_read display_cancel_read; - PFN_wl_display_dispatch_pending display_dispatch_pending; - PFN_wl_display_read_events display_read_events; - PFN_wl_display_disconnect display_disconnect; - PFN_wl_display_roundtrip display_roundtrip; - PFN_wl_display_get_fd display_get_fd; - PFN_wl_display_prepare_read display_prepare_read; - PFN_wl_proxy_marshal proxy_marshal; - PFN_wl_proxy_add_listener proxy_add_listener; - PFN_wl_proxy_destroy proxy_destroy; - PFN_wl_proxy_marshal_constructor proxy_marshal_constructor; - PFN_wl_proxy_marshal_constructor_versioned proxy_marshal_constructor_versioned; - PFN_wl_proxy_get_user_data proxy_get_user_data; - PFN_wl_proxy_set_user_data proxy_set_user_data; - PFN_wl_proxy_get_tag proxy_get_tag; - PFN_wl_proxy_set_tag proxy_set_tag; - PFN_wl_proxy_get_version proxy_get_version; - PFN_wl_proxy_marshal_flags proxy_marshal_flags; - } client; - struct { void* handle; @@ -550,37 +319,6 @@ typedef struct _GLFWlibraryWayland PFN_wl_egl_window_resize window_resize; } egl; - struct { - void* handle; - struct libdecor* context; - struct wl_callback* callback; - GLFWbool ready; - PFN_libdecor_new libdecor_new_; - PFN_libdecor_unref libdecor_unref_; - PFN_libdecor_get_fd libdecor_get_fd_; - PFN_libdecor_dispatch libdecor_dispatch_; - PFN_libdecor_decorate libdecor_decorate_; - PFN_libdecor_frame_unref libdecor_frame_unref_; - PFN_libdecor_frame_set_app_id libdecor_frame_set_app_id_; - PFN_libdecor_frame_set_title libdecor_frame_set_title_; - PFN_libdecor_frame_set_minimized libdecor_frame_set_minimized_; - PFN_libdecor_frame_set_fullscreen libdecor_frame_set_fullscreen_; - PFN_libdecor_frame_unset_fullscreen libdecor_frame_unset_fullscreen_; - PFN_libdecor_frame_map libdecor_frame_map_; - PFN_libdecor_frame_commit libdecor_frame_commit_; - PFN_libdecor_frame_set_min_content_size libdecor_frame_set_min_content_size_; - PFN_libdecor_frame_set_max_content_size libdecor_frame_set_max_content_size_; - PFN_libdecor_frame_set_maximized libdecor_frame_set_maximized_; - PFN_libdecor_frame_unset_maximized libdecor_frame_unset_maximized_; - PFN_libdecor_frame_set_capabilities libdecor_frame_set_capabilities_; - PFN_libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_; - PFN_libdecor_frame_set_visibility libdecor_frame_set_visibility_; - PFN_libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_; - PFN_libdecor_configuration_get_content_size libdecor_configuration_get_content_size_; - PFN_libdecor_configuration_get_window_state libdecor_configuration_get_window_state_; - PFN_libdecor_state_new libdecor_state_new_; - PFN_libdecor_state_free libdecor_state_free_; - } libdecor; } _GLFWlibraryWayland; // Wayland-specific per-monitor data @@ -593,7 +331,8 @@ typedef struct _GLFWmonitorWayland int x; int y; - int32_t scale; + int scale; + } _GLFWmonitorWayland; // Wayland-specific per-cursor data @@ -608,84 +347,6 @@ typedef struct _GLFWcursorWayland int currentImage; } _GLFWcursorWayland; -GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform); -int _glfwInitWayland(void); -void _glfwTerminateWayland(void); - -GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyWindowWayland(_GLFWwindow* window); -void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title); -void _glfwSetWindowIconWayland(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos); -void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos); -void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height); -void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height); -void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); -void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom); -void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height); -void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); -void _glfwGetWindowContentScaleWayland(_GLFWwindow* window, float* xscale, float* yscale); -void _glfwIconifyWindowWayland(_GLFWwindow* window); -void _glfwRestoreWindowWayland(_GLFWwindow* window); -void _glfwMaximizeWindowWayland(_GLFWwindow* window); -void _glfwShowWindowWayland(_GLFWwindow* window); -void _glfwHideWindowWayland(_GLFWwindow* window); -void _glfwRequestWindowAttentionWayland(_GLFWwindow* window); -void _glfwFocusWindowWayland(_GLFWwindow* window); -void _glfwSetWindowMonitorWayland(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); -GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window); -GLFWbool _glfwWindowIconifiedWayland(_GLFWwindow* window); -GLFWbool _glfwWindowVisibleWayland(_GLFWwindow* window); -GLFWbool _glfwWindowMaximizedWayland(_GLFWwindow* window); -GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window); -GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window); -void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled); -float _glfwGetWindowOpacityWayland(_GLFWwindow* window); -void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity); -void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled); - -void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled); -GLFWbool _glfwRawMouseMotionSupportedWayland(void); - -void _glfwPollEventsWayland(void); -void _glfwWaitEventsWayland(void); -void _glfwWaitEventsTimeoutWayland(double timeout); -void _glfwPostEmptyEventWayland(void); - -void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos); -void _glfwSetCursorPosWayland(_GLFWwindow* window, double xpos, double ypos); -void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode); -const char* _glfwGetScancodeNameWayland(int scancode); -int _glfwGetKeyScancodeWayland(int key); -GLFWbool _glfwCreateCursorWayland(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); -GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape); -void _glfwDestroyCursorWayland(_GLFWcursor* cursor); -void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor); -void _glfwSetClipboardStringWayland(const char* string); -const char* _glfwGetClipboardStringWayland(void); - -EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs); -EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void); -EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window); - -void _glfwGetRequiredInstanceExtensionsWayland(char** extensions); -GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); -VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -void _glfwFreeMonitorWayland(_GLFWmonitor* monitor); -void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos); -void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, float* xscale, float* yscale); -void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); -GLFWvidmode* _glfwGetVideoModesWayland(_GLFWmonitor* monitor, int* count); -GLFWbool _glfwGetVideoModeWayland(_GLFWmonitor* monitor, GLFWvidmode* mode); -GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp); -void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); void _glfwAddOutputWayland(uint32_t name, uint32_t version); -void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window); - -void _glfwAddSeatListenerWayland(struct wl_seat* seat); -void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device); diff --git a/raylib/external/glfw/src/wl_window.c b/raylib/external/glfw/src/wl_window.c index 505166e..7b315d7 100644 --- a/raylib/external/glfw/src/wl_window.c +++ b/raylib/external/glfw/src/wl_window.c @@ -1,8 +1,7 @@ //======================================================================== -// GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -24,37 +23,23 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #define _GNU_SOURCE #include "internal.h" -#if defined(_GLFW_WAYLAND) - #include #include #include -#include #include #include #include #include #include #include -#include -#include "wayland-client-protocol.h" -#include "xdg-shell-client-protocol.h" -#include "xdg-decoration-unstable-v1-client-protocol.h" -#include "viewporter-client-protocol.h" -#include "relative-pointer-unstable-v1-client-protocol.h" -#include "pointer-constraints-unstable-v1-client-protocol.h" -#include "xdg-activation-v1-client-protocol.h" -#include "idle-inhibit-unstable-v1-client-protocol.h" -#include "fractional-scale-v1-client-protocol.h" - -#define GLFW_BORDER_SIZE 4 -#define GLFW_CAPTION_HEIGHT 24 static int createTmpfileCloexec(char* tmpname) { @@ -119,12 +104,12 @@ static int createAnonymousFile(off_t size) return -1; } - name = _glfw_calloc(strlen(path) + sizeof(template), 1); + name = calloc(strlen(path) + sizeof(template), 1); strcpy(name, path); strcat(name, template); fd = createTmpfileCloexec(name); - _glfw_free(name); + free(name); if (fd < 0) return -1; } @@ -146,34 +131,37 @@ static int createAnonymousFile(off_t size) static struct wl_buffer* createShmBuffer(const GLFWimage* image) { - const int stride = image->width * 4; - const int length = image->width * image->height * 4; + struct wl_shm_pool* pool; + struct wl_buffer* buffer; + int stride = image->width * 4; + int length = image->width * image->height * 4; + void* data; + int fd, i; - const int fd = createAnonymousFile(length); + fd = createAnonymousFile(length); if (fd < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create buffer file of size %d: %s", + "Wayland: Creating a buffer file for %d B failed: %s", length, strerror(errno)); return NULL; } - void* data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to map file: %s", strerror(errno)); + "Wayland: mmap failed: %s", strerror(errno)); close(fd); return NULL; } - struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); close(fd); - unsigned char* source = (unsigned char*) image->pixels; unsigned char* target = data; - for (int i = 0; i < image->width * image->height; i++, source += 4) + for (i = 0; i < image->width * image->height; i++, source += 4) { unsigned int alpha = source[3]; @@ -183,7 +171,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) *target++ = (unsigned char) alpha; } - struct wl_buffer* buffer = + buffer = wl_shm_pool_create_buffer(pool, 0, image->width, image->height, @@ -194,112 +182,107 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) return buffer; } -static void createFallbackEdge(_GLFWwindow* window, - _GLFWfallbackEdgeWayland* edge, - struct wl_surface* parent, - struct wl_buffer* buffer, - int x, int y, - int width, int height) +static void createDecoration(_GLFWdecorationWayland* decoration, + struct wl_surface* parent, + struct wl_buffer* buffer, GLFWbool opaque, + int x, int y, + int width, int height) { - edge->surface = wl_compositor_create_surface(_glfw.wl.compositor); - wl_surface_set_user_data(edge->surface, window); - wl_proxy_set_tag((struct wl_proxy*) edge->surface, &_glfw.wl.tag); - edge->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, - edge->surface, parent); - wl_subsurface_set_position(edge->subsurface, x, y); - edge->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter, - edge->surface); - wp_viewport_set_destination(edge->viewport, width, height); - wl_surface_attach(edge->surface, buffer, 0, 0); + struct wl_region* region; - struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor); - wl_region_add(region, 0, 0, width, height); - wl_surface_set_opaque_region(edge->surface, region); - wl_surface_commit(edge->surface); - wl_region_destroy(region); + decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor); + decoration->subsurface = + wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, + decoration->surface, parent); + wl_subsurface_set_position(decoration->subsurface, x, y); + decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter, + decoration->surface); + wp_viewport_set_destination(decoration->viewport, width, height); + wl_surface_attach(decoration->surface, buffer, 0, 0); + + if (opaque) + { + region = wl_compositor_create_region(_glfw.wl.compositor); + wl_region_add(region, 0, 0, width, height); + wl_surface_set_opaque_region(decoration->surface, region); + wl_surface_commit(decoration->surface); + wl_region_destroy(region); + } + else + wl_surface_commit(decoration->surface); } -static void createFallbackDecorations(_GLFWwindow* window) +static void createDecorations(_GLFWwindow* window) { unsigned char data[] = { 224, 224, 224, 255 }; const GLFWimage image = { 1, 1, data }; + GLFWbool opaque = (data[3] == 255); - if (!_glfw.wl.viewporter) + if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide) return; - if (!window->wl.fallback.buffer) - window->wl.fallback.buffer = createShmBuffer(&image); - if (!window->wl.fallback.buffer) + if (!window->wl.decorations.buffer) + window->wl.decorations.buffer = createShmBuffer(&image); + if (!window->wl.decorations.buffer) return; - createFallbackEdge(window, &window->wl.fallback.top, window->wl.surface, - window->wl.fallback.buffer, - 0, -GLFW_CAPTION_HEIGHT, - window->wl.width, GLFW_CAPTION_HEIGHT); - createFallbackEdge(window, &window->wl.fallback.left, window->wl.surface, - window->wl.fallback.buffer, - -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT, - GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); - createFallbackEdge(window, &window->wl.fallback.right, window->wl.surface, - window->wl.fallback.buffer, - window->wl.width, -GLFW_CAPTION_HEIGHT, - GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); - createFallbackEdge(window, &window->wl.fallback.bottom, window->wl.surface, - window->wl.fallback.buffer, - -GLFW_BORDER_SIZE, window->wl.height, - window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); - - window->wl.fallback.decorations = GLFW_TRUE; + createDecoration(&window->wl.decorations.top, window->wl.surface, + window->wl.decorations.buffer, opaque, + 0, -_GLFW_DECORATION_TOP, + window->wl.width, _GLFW_DECORATION_TOP); + createDecoration(&window->wl.decorations.left, window->wl.surface, + window->wl.decorations.buffer, opaque, + -_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP, + _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + createDecoration(&window->wl.decorations.right, window->wl.surface, + window->wl.decorations.buffer, opaque, + window->wl.width, -_GLFW_DECORATION_TOP, + _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + createDecoration(&window->wl.decorations.bottom, window->wl.surface, + window->wl.decorations.buffer, opaque, + -_GLFW_DECORATION_WIDTH, window->wl.height, + window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); } -static void destroyFallbackEdge(_GLFWfallbackEdgeWayland* edge) +static void destroyDecoration(_GLFWdecorationWayland* decoration) { - if (edge->subsurface) - wl_subsurface_destroy(edge->subsurface); - if (edge->surface) - wl_surface_destroy(edge->surface); - if (edge->viewport) - wp_viewport_destroy(edge->viewport); - - edge->surface = NULL; - edge->subsurface = NULL; - edge->viewport = NULL; + if (decoration->surface) + wl_surface_destroy(decoration->surface); + if (decoration->subsurface) + wl_subsurface_destroy(decoration->subsurface); + if (decoration->viewport) + wp_viewport_destroy(decoration->viewport); + decoration->surface = NULL; + decoration->subsurface = NULL; + decoration->viewport = NULL; } -static void destroyFallbackDecorations(_GLFWwindow* window) +static void destroyDecorations(_GLFWwindow* window) { - window->wl.fallback.decorations = GLFW_FALSE; - - destroyFallbackEdge(&window->wl.fallback.top); - destroyFallbackEdge(&window->wl.fallback.left); - destroyFallbackEdge(&window->wl.fallback.right); - destroyFallbackEdge(&window->wl.fallback.bottom); + destroyDecoration(&window->wl.decorations.top); + destroyDecoration(&window->wl.decorations.left); + destroyDecoration(&window->wl.decorations.right); + destroyDecoration(&window->wl.decorations.bottom); } -static void xdgDecorationHandleConfigure(void* userData, +static void xdgDecorationHandleConfigure(void* data, struct zxdg_toplevel_decoration_v1* decoration, uint32_t mode) { - _GLFWwindow* window = userData; + _GLFWwindow* window = data; - window->wl.xdg.decorationMode = mode; + window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) - { - if (window->decorated && !window->monitor) - createFallbackDecorations(window); - } - else - destroyFallbackDecorations(window); + if (!window->wl.decorations.serverSide) + createDecorations(window); } -static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = -{ +static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = { xdgDecorationHandleConfigure, }; // Makes the surface considered as XRGB instead of ARGB. -static void setContentAreaOpaque(_GLFWwindow* window) +static void setOpaqueRegion(_GLFWwindow* window) { struct wl_region* region; @@ -309,172 +292,119 @@ static void setContentAreaOpaque(_GLFWwindow* window) wl_region_add(region, 0, 0, window->wl.width, window->wl.height); wl_surface_set_opaque_region(window->wl.surface, region); + wl_surface_commit(window->wl.surface); wl_region_destroy(region); } -static void resizeFramebuffer(_GLFWwindow* window) + +static void resizeWindow(_GLFWwindow* window) { - if (window->wl.fractionalScale) - { - window->wl.fbWidth = (window->wl.width * window->wl.scalingNumerator) / 120; - window->wl.fbHeight = (window->wl.height * window->wl.scalingNumerator) / 120; - } - else - { - window->wl.fbWidth = window->wl.width * window->wl.bufferScale; - window->wl.fbHeight = window->wl.height * window->wl.bufferScale; - } - - if (window->wl.egl.window) - { - wl_egl_window_resize(window->wl.egl.window, - window->wl.fbWidth, - window->wl.fbHeight, - 0, 0); - } - + int scale = window->wl.scale; + int scaledWidth = window->wl.width * scale; + int scaledHeight = window->wl.height * scale; + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); if (!window->wl.transparent) - setContentAreaOpaque(window); + setOpaqueRegion(window); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); + _glfwInputWindowContentScale(window, scale, scale); - _glfwInputFramebufferSize(window, window->wl.fbWidth, window->wl.fbHeight); -} - -static GLFWbool resizeWindow(_GLFWwindow* window, int width, int height) -{ - width = _glfw_max(width, 1); - height = _glfw_max(height, 1); - - if (width == window->wl.width && height == window->wl.height) - return GLFW_FALSE; - - window->wl.width = width; - window->wl.height = height; - - resizeFramebuffer(window); - - if (window->wl.scalingViewport) - { - wp_viewport_set_destination(window->wl.scalingViewport, - window->wl.width, - window->wl.height); - } - - if (window->wl.fallback.decorations) - { - wp_viewport_set_destination(window->wl.fallback.top.viewport, - window->wl.width, - GLFW_CAPTION_HEIGHT); - wl_surface_commit(window->wl.fallback.top.surface); - - wp_viewport_set_destination(window->wl.fallback.left.viewport, - GLFW_BORDER_SIZE, - window->wl.height + GLFW_CAPTION_HEIGHT); - wl_surface_commit(window->wl.fallback.left.surface); - - wl_subsurface_set_position(window->wl.fallback.right.subsurface, - window->wl.width, -GLFW_CAPTION_HEIGHT); - wp_viewport_set_destination(window->wl.fallback.right.viewport, - GLFW_BORDER_SIZE, - window->wl.height + GLFW_CAPTION_HEIGHT); - wl_surface_commit(window->wl.fallback.right.surface); - - wl_subsurface_set_position(window->wl.fallback.bottom.subsurface, - -GLFW_BORDER_SIZE, window->wl.height); - wp_viewport_set_destination(window->wl.fallback.bottom.viewport, - window->wl.width + GLFW_BORDER_SIZE * 2, - GLFW_BORDER_SIZE); - wl_surface_commit(window->wl.fallback.bottom.surface); - } - - return GLFW_TRUE; -} - -void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window) -{ - if (wl_compositor_get_version(_glfw.wl.compositor) < - WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) - { - return; - } - - if (!window->wl.scaleFramebuffer) + if (!window->wl.decorations.top.surface) return; - // When using fractional scaling, the buffer scale should remain at 1 - if (window->wl.fractionalScale) + // Top decoration. + wp_viewport_set_destination(window->wl.decorations.top.viewport, + window->wl.width, _GLFW_DECORATION_TOP); + wl_surface_commit(window->wl.decorations.top.surface); + + // Left decoration. + wp_viewport_set_destination(window->wl.decorations.left.viewport, + _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + wl_surface_commit(window->wl.decorations.left.surface); + + // Right decoration. + wl_subsurface_set_position(window->wl.decorations.right.subsurface, + window->wl.width, -_GLFW_DECORATION_TOP); + wp_viewport_set_destination(window->wl.decorations.right.viewport, + _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + wl_surface_commit(window->wl.decorations.right.surface); + + // Bottom decoration. + wl_subsurface_set_position(window->wl.decorations.bottom.subsurface, + -_GLFW_DECORATION_WIDTH, window->wl.height); + wp_viewport_set_destination(window->wl.decorations.bottom.viewport, + window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); + wl_surface_commit(window->wl.decorations.bottom.surface); +} + +static void checkScaleChange(_GLFWwindow* window) +{ + int scale = 1; + int i; + int monitorScale; + + // Check if we will be able to set the buffer scale or not. + if (_glfw.wl.compositorVersion < 3) return; // Get the scale factor from the highest scale monitor. - int32_t maxScale = 1; - - for (size_t i = 0; i < window->wl.outputScaleCount; i++) - maxScale = _glfw_max(window->wl.outputScales[i].factor, maxScale); + for (i = 0; i < window->wl.monitorsCount; ++i) + { + monitorScale = window->wl.monitors[i]->wl.scale; + if (scale < monitorScale) + scale = monitorScale; + } // Only change the framebuffer size if the scale changed. - if (window->wl.bufferScale != maxScale) + if (scale != window->wl.scale) { - window->wl.bufferScale = maxScale; - wl_surface_set_buffer_scale(window->wl.surface, maxScale); - _glfwInputWindowContentScale(window, maxScale, maxScale); - resizeFramebuffer(window); - - if (window->wl.visible) - _glfwInputWindowDamage(window); + window->wl.scale = scale; + wl_surface_set_buffer_scale(window->wl.surface, scale); + resizeWindow(window); } } -static void surfaceHandleEnter(void* userData, - struct wl_surface* surface, - struct wl_output* output) +static void surfaceHandleEnter(void *data, + struct wl_surface *surface, + struct wl_output *output) { - if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag) - return; - - _GLFWwindow* window = userData; + _GLFWwindow* window = data; _GLFWmonitor* monitor = wl_output_get_user_data(output); - if (!window || !monitor) - return; - if (window->wl.outputScaleCount + 1 > window->wl.outputScaleSize) + if (window->wl.monitorsCount + 1 > window->wl.monitorsSize) { - window->wl.outputScaleSize++; - window->wl.outputScales = - _glfw_realloc(window->wl.outputScales, - window->wl.outputScaleSize * sizeof(_GLFWscaleWayland)); + ++window->wl.monitorsSize; + window->wl.monitors = + realloc(window->wl.monitors, + window->wl.monitorsSize * sizeof(_GLFWmonitor*)); } - window->wl.outputScaleCount++; - window->wl.outputScales[window->wl.outputScaleCount - 1] = - (_GLFWscaleWayland) { output, monitor->wl.scale }; + window->wl.monitors[window->wl.monitorsCount++] = monitor; - _glfwUpdateBufferScaleFromOutputsWayland(window); + checkScaleChange(window); } -static void surfaceHandleLeave(void* userData, - struct wl_surface* surface, - struct wl_output* output) +static void surfaceHandleLeave(void *data, + struct wl_surface *surface, + struct wl_output *output) { - if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag) - return; + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + GLFWbool found; + int i; - _GLFWwindow* window = userData; - - for (size_t i = 0; i < window->wl.outputScaleCount; i++) + for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i) { - if (window->wl.outputScales[i].output == output) - { - window->wl.outputScales[i] = - window->wl.outputScales[window->wl.outputScaleCount - 1]; - window->wl.outputScaleCount--; - break; - } + if (monitor == window->wl.monitors[i]) + found = GLFW_TRUE; + if (found) + window->wl.monitors[i] = window->wl.monitors[i + 1]; } + window->wl.monitors[--window->wl.monitorsCount] = NULL; - _glfwUpdateBufferScaleFromOutputsWayland(window); + checkScaleChange(window); } -static const struct wl_surface_listener surfaceListener = -{ +static const struct wl_surface_listener surfaceListener = { surfaceHandleEnter, surfaceHandleLeave }; @@ -488,7 +418,7 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) _glfw.wl.idleInhibitManager, window->wl.surface); if (!window->wl.idleInhibitor) _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create idle inhibitor"); + "Wayland: Idle inhibitor creation failed"); } else if (!enable && window->wl.idleInhibitor) { @@ -497,463 +427,139 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) } } -// Make the specified window and its video mode active on its monitor -// -static void acquireMonitorWayland(_GLFWwindow* window) +static GLFWbool createSurface(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) { - if (window->wl.libdecor.frame) - { - libdecor_frame_set_fullscreen(window->wl.libdecor.frame, - window->monitor->wl.output); - } - else if (window->wl.xdg.toplevel) - { - xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, - window->monitor->wl.output); - } + window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); + if (!window->wl.surface) + return GLFW_FALSE; + wl_surface_add_listener(window->wl.surface, + &surfaceListener, + window); + + wl_surface_set_user_data(window->wl.surface, window); + + window->wl.native = wl_egl_window_create(window->wl.surface, + wndconfig->width, + wndconfig->height); + if (!window->wl.native) + return GLFW_FALSE; + + window->wl.width = wndconfig->width; + window->wl.height = wndconfig->height; + window->wl.scale = 1; + + if (!window->wl.transparent) + setOpaqueRegion(window); + + return GLFW_TRUE; +} + +static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, + int refreshRate) +{ + if (window->wl.xdg.toplevel) + { + xdg_toplevel_set_fullscreen( + window->wl.xdg.toplevel, + monitor->wl.output); + } setIdleInhibitor(window, GLFW_TRUE); - - if (window->wl.fallback.decorations) - destroyFallbackDecorations(window); + if (!window->wl.decorations.serverSide) + destroyDecorations(window); } -// Remove the window and restore the original video mode -// -static void releaseMonitorWayland(_GLFWwindow* window) -{ - if (window->wl.libdecor.frame) - libdecor_frame_unset_fullscreen(window->wl.libdecor.frame); - else if (window->wl.xdg.toplevel) - xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); - - setIdleInhibitor(window, GLFW_FALSE); - - if (!window->wl.libdecor.frame && - window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) - { - if (window->decorated) - createFallbackDecorations(window); - } -} - -void fractionalScaleHandlePreferredScale(void* userData, - struct wp_fractional_scale_v1* fractionalScale, - uint32_t numerator) -{ - _GLFWwindow* window = userData; - - window->wl.scalingNumerator = numerator; - _glfwInputWindowContentScale(window, numerator / 120.f, numerator / 120.f); - resizeFramebuffer(window); - - if (window->wl.visible) - _glfwInputWindowDamage(window); -} - -const struct wp_fractional_scale_v1_listener fractionalScaleListener = -{ - fractionalScaleHandlePreferredScale, -}; - -static void xdgToplevelHandleConfigure(void* userData, +static void xdgToplevelHandleConfigure(void* data, struct xdg_toplevel* toplevel, int32_t width, int32_t height, struct wl_array* states) { - _GLFWwindow* window = userData; + _GLFWwindow* window = data; + float aspectRatio; + float targetRatio; uint32_t* state; - - window->wl.pending.activated = GLFW_FALSE; - window->wl.pending.maximized = GLFW_FALSE; - window->wl.pending.fullscreen = GLFW_FALSE; + GLFWbool maximized = GLFW_FALSE; + GLFWbool fullscreen = GLFW_FALSE; + GLFWbool activated = GLFW_FALSE; wl_array_for_each(state, states) { switch (*state) { case XDG_TOPLEVEL_STATE_MAXIMIZED: - window->wl.pending.maximized = GLFW_TRUE; + maximized = GLFW_TRUE; break; case XDG_TOPLEVEL_STATE_FULLSCREEN: - window->wl.pending.fullscreen = GLFW_TRUE; + fullscreen = GLFW_TRUE; break; case XDG_TOPLEVEL_STATE_RESIZING: break; case XDG_TOPLEVEL_STATE_ACTIVATED: - window->wl.pending.activated = GLFW_TRUE; + activated = GLFW_TRUE; break; } } - if (width && height) + if (width != 0 && height != 0) { - if (window->wl.fallback.decorations) + if (!maximized && !fullscreen) { - window->wl.pending.width = _glfw_max(0, width - GLFW_BORDER_SIZE * 2); - window->wl.pending.height = - _glfw_max(0, height - GLFW_BORDER_SIZE - GLFW_CAPTION_HEIGHT); + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + aspectRatio = (float)width / (float)height; + targetRatio = (float)window->numer / (float)window->denom; + if (aspectRatio < targetRatio) + height = width / targetRatio; + else if (aspectRatio > targetRatio) + width = height * targetRatio; + } } - else + + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); + } + + if (window->wl.wasFullscreen && window->autoIconify) + { + if (!activated || !fullscreen) { - window->wl.pending.width = width; - window->wl.pending.height = height; + _glfwPlatformIconifyWindow(window); + window->wl.wasFullscreen = GLFW_FALSE; } } - else - { - window->wl.pending.width = window->wl.width; - window->wl.pending.height = window->wl.height; - } + if (fullscreen && activated) + window->wl.wasFullscreen = GLFW_TRUE; + _glfwInputWindowFocus(window, activated); } -static void xdgToplevelHandleClose(void* userData, +static void xdgToplevelHandleClose(void* data, struct xdg_toplevel* toplevel) { - _GLFWwindow* window = userData; + _GLFWwindow* window = data; _glfwInputWindowCloseRequest(window); } -static const struct xdg_toplevel_listener xdgToplevelListener = -{ +static const struct xdg_toplevel_listener xdgToplevelListener = { xdgToplevelHandleConfigure, xdgToplevelHandleClose }; -static void xdgSurfaceHandleConfigure(void* userData, +static void xdgSurfaceHandleConfigure(void* data, struct xdg_surface* surface, uint32_t serial) { - _GLFWwindow* window = userData; - xdg_surface_ack_configure(surface, serial); - - if (window->wl.activated != window->wl.pending.activated) - { - window->wl.activated = window->wl.pending.activated; - if (!window->wl.activated) - { - if (window->monitor && window->autoIconify) - xdg_toplevel_set_minimized(window->wl.xdg.toplevel); - } - } - - if (window->wl.maximized != window->wl.pending.maximized) - { - window->wl.maximized = window->wl.pending.maximized; - _glfwInputWindowMaximize(window, window->wl.maximized); - } - - window->wl.fullscreen = window->wl.pending.fullscreen; - - int width = window->wl.pending.width; - int height = window->wl.pending.height; - - if (!window->wl.maximized && !window->wl.fullscreen) - { - if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) - { - const float aspectRatio = (float) width / (float) height; - const float targetRatio = (float) window->numer / (float) window->denom; - if (aspectRatio < targetRatio) - height = width / targetRatio; - else if (aspectRatio > targetRatio) - width = height * targetRatio; - } - } - - if (resizeWindow(window, width, height)) - { - _glfwInputWindowSize(window, window->wl.width, window->wl.height); - - if (window->wl.visible) - _glfwInputWindowDamage(window); - } - - if (!window->wl.visible) - { - // Allow the window to be mapped only if it either has no XDG - // decorations or they have already received a configure event - if (!window->wl.xdg.decoration || window->wl.xdg.decorationMode) - { - window->wl.visible = GLFW_TRUE; - _glfwInputWindowDamage(window); - } - } } -static const struct xdg_surface_listener xdgSurfaceListener = -{ +static const struct xdg_surface_listener xdgSurfaceListener = { xdgSurfaceHandleConfigure }; -void libdecorFrameHandleConfigure(struct libdecor_frame* frame, - struct libdecor_configuration* config, - void* userData) +static void setXdgDecorations(_GLFWwindow* window) { - _GLFWwindow* window = userData; - int width, height; - - enum libdecor_window_state windowState; - GLFWbool fullscreen, activated, maximized; - - if (libdecor_configuration_get_window_state(config, &windowState)) - { - fullscreen = (windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0; - activated = (windowState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0; - maximized = (windowState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0; - } - else - { - fullscreen = window->wl.fullscreen; - activated = window->wl.activated; - maximized = window->wl.maximized; - } - - if (!libdecor_configuration_get_content_size(config, frame, &width, &height)) - { - width = window->wl.width; - height = window->wl.height; - } - - if (!maximized && !fullscreen) - { - if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) - { - const float aspectRatio = (float) width / (float) height; - const float targetRatio = (float) window->numer / (float) window->denom; - if (aspectRatio < targetRatio) - height = width / targetRatio; - else if (aspectRatio > targetRatio) - width = height * targetRatio; - } - } - - struct libdecor_state* frameState = libdecor_state_new(width, height); - libdecor_frame_commit(frame, frameState, config); - libdecor_state_free(frameState); - - if (window->wl.activated != activated) - { - window->wl.activated = activated; - if (!window->wl.activated) - { - if (window->monitor && window->autoIconify) - libdecor_frame_set_minimized(window->wl.libdecor.frame); - } - } - - if (window->wl.maximized != maximized) - { - window->wl.maximized = maximized; - _glfwInputWindowMaximize(window, window->wl.maximized); - } - - window->wl.fullscreen = fullscreen; - - GLFWbool damaged = GLFW_FALSE; - - if (!window->wl.visible) - { - window->wl.visible = GLFW_TRUE; - damaged = GLFW_TRUE; - } - - if (resizeWindow(window, width, height)) - { - _glfwInputWindowSize(window, window->wl.width, window->wl.height); - damaged = GLFW_TRUE; - } - - if (damaged) - _glfwInputWindowDamage(window); - else - wl_surface_commit(window->wl.surface); -} - -void libdecorFrameHandleClose(struct libdecor_frame* frame, void* userData) -{ - _GLFWwindow* window = userData; - _glfwInputWindowCloseRequest(window); -} - -void libdecorFrameHandleCommit(struct libdecor_frame* frame, void* userData) -{ - _GLFWwindow* window = userData; - wl_surface_commit(window->wl.surface); -} - -void libdecorFrameHandleDismissPopup(struct libdecor_frame* frame, - const char* seatName, - void* userData) -{ -} - -static const struct libdecor_frame_interface libdecorFrameInterface = -{ - libdecorFrameHandleConfigure, - libdecorFrameHandleClose, - libdecorFrameHandleCommit, - libdecorFrameHandleDismissPopup -}; - -static GLFWbool createLibdecorFrame(_GLFWwindow* window) -{ - // Allow libdecor to finish initialization of itself and its plugin - while (!_glfw.wl.libdecor.ready) - _glfwWaitEventsWayland(); - - window->wl.libdecor.frame = libdecor_decorate(_glfw.wl.libdecor.context, - window->wl.surface, - &libdecorFrameInterface, - window); - if (!window->wl.libdecor.frame) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create libdecor frame"); - return GLFW_FALSE; - } - - struct libdecor_state* frameState = - libdecor_state_new(window->wl.width, window->wl.height); - libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL); - libdecor_state_free(frameState); - - if (strlen(window->wl.appId)) - libdecor_frame_set_app_id(window->wl.libdecor.frame, window->wl.appId); - - libdecor_frame_set_title(window->wl.libdecor.frame, window->title); - - if (window->minwidth != GLFW_DONT_CARE && - window->minheight != GLFW_DONT_CARE) - { - libdecor_frame_set_min_content_size(window->wl.libdecor.frame, - window->minwidth, - window->minheight); - } - - if (window->maxwidth != GLFW_DONT_CARE && - window->maxheight != GLFW_DONT_CARE) - { - libdecor_frame_set_max_content_size(window->wl.libdecor.frame, - window->maxwidth, - window->maxheight); - } - - if (!window->resizable) - { - libdecor_frame_unset_capabilities(window->wl.libdecor.frame, - LIBDECOR_ACTION_RESIZE); - } - - if (window->monitor) - { - libdecor_frame_set_fullscreen(window->wl.libdecor.frame, - window->monitor->wl.output); - setIdleInhibitor(window, GLFW_TRUE); - } - else - { - if (window->wl.maximized) - libdecor_frame_set_maximized(window->wl.libdecor.frame); - - if (!window->decorated) - libdecor_frame_set_visibility(window->wl.libdecor.frame, false); - - setIdleInhibitor(window, GLFW_FALSE); - } - - libdecor_frame_map(window->wl.libdecor.frame); - wl_display_roundtrip(_glfw.wl.display); - return GLFW_TRUE; -} - -static void updateXdgSizeLimits(_GLFWwindow* window) -{ - int minwidth, minheight, maxwidth, maxheight; - - if (window->resizable) - { - if (window->minwidth == GLFW_DONT_CARE || window->minheight == GLFW_DONT_CARE) - minwidth = minheight = 0; - else - { - minwidth = window->minwidth; - minheight = window->minheight; - - if (window->wl.fallback.decorations) - { - minwidth += GLFW_BORDER_SIZE * 2; - minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; - } - } - - if (window->maxwidth == GLFW_DONT_CARE || window->maxheight == GLFW_DONT_CARE) - maxwidth = maxheight = 0; - else - { - maxwidth = window->maxwidth; - maxheight = window->maxheight; - - if (window->wl.fallback.decorations) - { - maxwidth += GLFW_BORDER_SIZE * 2; - maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; - } - } - } - else - { - minwidth = maxwidth = window->wl.width; - minheight = maxheight = window->wl.height; - } - - xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight); - xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); -} - -static GLFWbool createXdgShellObjects(_GLFWwindow* window) -{ - window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, - window->wl.surface); - if (!window->wl.xdg.surface) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create xdg-surface for window"); - return GLFW_FALSE; - } - - xdg_surface_add_listener(window->wl.xdg.surface, &xdgSurfaceListener, window); - - window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface); - if (!window->wl.xdg.toplevel) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create xdg-toplevel for window"); - return GLFW_FALSE; - } - - xdg_toplevel_add_listener(window->wl.xdg.toplevel, &xdgToplevelListener, window); - - if (window->wl.appId) - xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId); - - xdg_toplevel_set_title(window->wl.xdg.toplevel, window->title); - - if (window->monitor) - { - xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, window->monitor->wl.output); - setIdleInhibitor(window, GLFW_TRUE); - } - else - { - if (window->wl.maximized) - xdg_toplevel_set_maximized(window->wl.xdg.toplevel); - - setIdleInhibitor(window, GLFW_FALSE); - } - if (_glfw.wl.decorationManager) { window->wl.xdg.decoration = @@ -962,124 +568,82 @@ static GLFWbool createXdgShellObjects(_GLFWwindow* window) zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration, &xdgDecorationListener, window); - - uint32_t mode; - - if (window->decorated) - mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - else - mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - - zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode); + zxdg_toplevel_decoration_v1_set_mode( + window->wl.xdg.decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else { - if (window->decorated && !window->monitor) - createFallbackDecorations(window); + window->wl.decorations.serverSide = GLFW_FALSE; + createDecorations(window); } - - updateXdgSizeLimits(window); - - wl_surface_commit(window->wl.surface); - wl_display_roundtrip(_glfw.wl.display); - return GLFW_TRUE; } -static GLFWbool createShellObjects(_GLFWwindow* window) +static GLFWbool createXdgSurface(_GLFWwindow* window) { - if (_glfw.wl.libdecor.context) + window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, + window->wl.surface); + if (!window->wl.xdg.surface) { - if (createLibdecorFrame(window)) - return GLFW_TRUE; - } - - return createXdgShellObjects(window); -} - -static void destroyShellObjects(_GLFWwindow* window) -{ - destroyFallbackDecorations(window); - - if (window->wl.libdecor.frame) - libdecor_frame_unref(window->wl.libdecor.frame); - - if (window->wl.xdg.decoration) - zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); - - if (window->wl.xdg.toplevel) - xdg_toplevel_destroy(window->wl.xdg.toplevel); - - if (window->wl.xdg.surface) - xdg_surface_destroy(window->wl.xdg.surface); - - window->wl.libdecor.frame = NULL; - window->wl.xdg.decoration = NULL; - window->wl.xdg.decorationMode = 0; - window->wl.xdg.toplevel = NULL; - window->wl.xdg.surface = NULL; -} - -static GLFWbool createNativeSurface(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig) -{ - window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); - if (!window->wl.surface) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create window surface"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: xdg-surface creation failed"); return GLFW_FALSE; } - wl_proxy_set_tag((struct wl_proxy*) window->wl.surface, &_glfw.wl.tag); - wl_surface_add_listener(window->wl.surface, - &surfaceListener, - window); + xdg_surface_add_listener(window->wl.xdg.surface, + &xdgSurfaceListener, + window); - window->wl.width = wndconfig->width; - window->wl.height = wndconfig->height; - window->wl.fbWidth = wndconfig->width; - window->wl.fbHeight = wndconfig->height; - window->wl.appId = _glfw_strdup(wndconfig->wl.appId); - - window->wl.bufferScale = 1; - window->wl.scalingNumerator = 120; - window->wl.scaleFramebuffer = wndconfig->scaleFramebuffer; - - window->wl.maximized = wndconfig->maximized; - - window->wl.transparent = fbconfig->transparent; - if (!window->wl.transparent) - setContentAreaOpaque(window); - - if (_glfw.wl.fractionalScaleManager) + window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface); + if (!window->wl.xdg.toplevel) { - if (window->wl.scaleFramebuffer) - { - window->wl.scalingViewport = - wp_viewporter_get_viewport(_glfw.wl.viewporter, window->wl.surface); - - wp_viewport_set_destination(window->wl.scalingViewport, - window->wl.width, - window->wl.height); - - window->wl.fractionalScale = - wp_fractional_scale_manager_v1_get_fractional_scale( - _glfw.wl.fractionalScaleManager, - window->wl.surface); - - wp_fractional_scale_v1_add_listener(window->wl.fractionalScale, - &fractionalScaleListener, - window); - } + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: xdg-toplevel creation failed"); + return GLFW_FALSE; } + xdg_toplevel_add_listener(window->wl.xdg.toplevel, + &xdgToplevelListener, + window); + + if (window->wl.title) + xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title); + + if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) + xdg_toplevel_set_min_size(window->wl.xdg.toplevel, + window->minwidth, window->minheight); + if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) + xdg_toplevel_set_max_size(window->wl.xdg.toplevel, + window->maxwidth, window->maxheight); + + if (window->monitor) + { + xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, + window->monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); + } + else if (window->wl.maximized) + { + xdg_toplevel_set_maximized(window->wl.xdg.toplevel); + setIdleInhibitor(window, GLFW_FALSE); + setXdgDecorations(window); + } + else + { + setIdleInhibitor(window, GLFW_FALSE); + setXdgDecorations(window); + } + + wl_surface_commit(window->wl.surface); + wl_display_roundtrip(_glfw.wl.display); + return GLFW_TRUE; } static void setCursorImage(_GLFWwindow* window, _GLFWcursorWayland* cursorWayland) { - struct itimerspec timer = {0}; + struct itimerspec timer = {}; struct wl_cursor* wlCursor = cursorWayland->cursor; struct wl_cursor_image* image; struct wl_buffer* buffer; @@ -1090,7 +654,7 @@ static void setCursorImage(_GLFWwindow* window, buffer = cursorWayland->buffer; else { - if (window->wl.bufferScale > 1 && cursorWayland->cursorHiDPI) + if (window->wl.scale > 1 && cursorWayland->cursorHiDPI) { wlCursor = cursorWayland->cursorHiDPI; scale = 2; @@ -1111,7 +675,7 @@ static void setCursorImage(_GLFWwindow* window, cursorWayland->yhot = image->hotspot_y; } - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, surface, cursorWayland->xhot / scale, cursorWayland->yhot / scale); @@ -1126,7 +690,7 @@ static void incrementCursorImage(_GLFWwindow* window) { _GLFWcursor* cursor; - if (!window || !window->wl.hovered) + if (!window || window->wl.decorations.focus != mainWindow) return; cursor = window->wl.currentCursor; @@ -1138,998 +702,93 @@ static void incrementCursorImage(_GLFWwindow* window) } } -static GLFWbool flushDisplay(void) +static void handleEvents(int timeout) { - while (wl_display_flush(_glfw.wl.display) == -1) - { - if (errno != EAGAIN) - return GLFW_FALSE; - - struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLOUT }; - - while (poll(&fd, 1, -1) == -1) - { - if (errno != EINTR && errno != EAGAIN) - return GLFW_FALSE; - } - } - - return GLFW_TRUE; -} - -static int translateKeyWayland(uint32_t scancode) -{ - if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0])) - return _glfw.wl.keycodes[scancode]; - - return GLFW_KEY_UNKNOWN; -} - -static xkb_keysym_t composeSymbol(xkb_keysym_t sym) -{ - if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) - return sym; - if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) - != XKB_COMPOSE_FEED_ACCEPTED) - return sym; - switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) - { - case XKB_COMPOSE_COMPOSED: - return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); - case XKB_COMPOSE_COMPOSING: - case XKB_COMPOSE_CANCELLED: - return XKB_KEY_NoSymbol; - case XKB_COMPOSE_NOTHING: - default: - return sym; - } -} - -static void inputText(_GLFWwindow* window, uint32_t scancode) -{ - const xkb_keysym_t* keysyms; - const xkb_keycode_t keycode = scancode + 8; - - if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1) - { - const xkb_keysym_t keysym = composeSymbol(keysyms[0]); - const uint32_t codepoint = _glfwKeySym2Unicode(keysym); - if (codepoint != GLFW_INVALID_CODEPOINT) - { - const int mods = _glfw.wl.xkb.modifiers; - const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); - _glfwInputChar(window, codepoint, mods, plain); - } - } -} - -static void handleEvents(double* timeout) -{ -#if defined(GLFW_BUILD_LINUX_JOYSTICK) - if (_glfw.joysticksInitialized) - _glfwDetectJoystickConnectionLinux(); -#endif - - GLFWbool event = GLFW_FALSE; - enum { DISPLAY_FD, KEYREPEAT_FD, CURSOR_FD, LIBDECOR_FD }; - struct pollfd fds[] = - { - [DISPLAY_FD] = { wl_display_get_fd(_glfw.wl.display), POLLIN }, - [KEYREPEAT_FD] = { _glfw.wl.keyRepeatTimerfd, POLLIN }, - [CURSOR_FD] = { _glfw.wl.cursorTimerfd, POLLIN }, - [LIBDECOR_FD] = { -1, POLLIN } + struct wl_display* display = _glfw.wl.display; + struct pollfd fds[] = { + { wl_display_get_fd(display), POLLIN }, + { _glfw.wl.timerfd, POLLIN }, + { _glfw.wl.cursorTimerfd, POLLIN }, }; + ssize_t read_ret; + uint64_t repeats, i; - if (_glfw.wl.libdecor.context) - fds[LIBDECOR_FD].fd = libdecor_get_fd(_glfw.wl.libdecor.context); + while (wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); - while (!event) + // If an error different from EAGAIN happens, we have likely been + // disconnected from the Wayland session, try to handle that the best we + // can. + if (wl_display_flush(display) < 0 && errno != EAGAIN) { - while (wl_display_prepare_read(_glfw.wl.display) != 0) + _GLFWwindow* window = _glfw.windowListHead; + while (window) { - if (wl_display_dispatch_pending(_glfw.wl.display) > 0) - return; + _glfwInputWindowCloseRequest(window); + window = window->next; } + wl_display_cancel_read(display); + return; + } - // If an error other than EAGAIN happens, we have likely been disconnected - // from the Wayland session; try to handle that the best we can. - if (!flushDisplay()) + if (poll(fds, 3, timeout) > 0) + { + if (fds[0].revents & POLLIN) { - wl_display_cancel_read(_glfw.wl.display); - - _GLFWwindow* window = _glfw.windowListHead; - while (window) - { - _glfwInputWindowCloseRequest(window); - window = window->next; - } - - return; - } - - if (!_glfwPollPOSIX(fds, sizeof(fds) / sizeof(fds[0]), timeout)) - { - wl_display_cancel_read(_glfw.wl.display); - return; - } - - if (fds[DISPLAY_FD].revents & POLLIN) - { - wl_display_read_events(_glfw.wl.display); - if (wl_display_dispatch_pending(_glfw.wl.display) > 0) - event = GLFW_TRUE; + wl_display_read_events(display); + wl_display_dispatch_pending(display); } else - wl_display_cancel_read(_glfw.wl.display); - - if (fds[KEYREPEAT_FD].revents & POLLIN) { - uint64_t repeats; + wl_display_cancel_read(display); + } - if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8) + if (fds[1].revents & POLLIN) + { + read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats)); + if (read_ret != 8) + return; + + if (_glfw.wl.keyboardFocus) { - for (uint64_t i = 0; i < repeats; i++) + for (i = 0; i < repeats; ++i) { _glfwInputKey(_glfw.wl.keyboardFocus, - translateKeyWayland(_glfw.wl.keyRepeatScancode), - _glfw.wl.keyRepeatScancode, - GLFW_PRESS, + _glfw.wl.keyboardLastKey, + _glfw.wl.keyboardLastScancode, + GLFW_REPEAT, _glfw.wl.xkb.modifiers); - inputText(_glfw.wl.keyboardFocus, _glfw.wl.keyRepeatScancode); } - - event = GLFW_TRUE; } } - if (fds[CURSOR_FD].revents & POLLIN) + if (fds[2].revents & POLLIN) { - uint64_t repeats; - - if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8) - incrementCursorImage(_glfw.wl.pointerFocus); - } - - if (fds[LIBDECOR_FD].revents & POLLIN) - { - if (libdecor_dispatch(_glfw.wl.libdecor.context, 0) > 0) - event = GLFW_TRUE; - } - } -} - -// Reads the specified data offer as the specified MIME type -// -static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mimeType) -{ - int fds[2]; - - if (pipe2(fds, O_CLOEXEC) == -1) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create pipe for data offer: %s", - strerror(errno)); - return NULL; - } - - wl_data_offer_receive(offer, mimeType, fds[1]); - flushDisplay(); - close(fds[1]); - - char* string = NULL; - size_t size = 0; - size_t length = 0; - - for (;;) - { - const size_t readSize = 4096; - const size_t requiredSize = length + readSize + 1; - if (requiredSize > size) - { - char* longer = _glfw_realloc(string, requiredSize); - if (!longer) - { - _glfwInputError(GLFW_OUT_OF_MEMORY, NULL); - close(fds[0]); - return NULL; - } - - string = longer; - size = requiredSize; - } - - const ssize_t result = read(fds[0], string + length, readSize); - if (result == 0) - break; - else if (result == -1) - { - if (errno == EINTR) - continue; - - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to read from data offer pipe: %s", - strerror(errno)); - close(fds[0]); - return NULL; - } - - length += result; - } - - close(fds[0]); - - string[length] = '\0'; - return string; -} - -static void pointerHandleEnter(void* userData, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface, - wl_fixed_t sx, - wl_fixed_t sy) -{ - // Happens in the case we just destroyed the surface. - if (!surface) - return; - - if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag) - return; - - _GLFWwindow* window = wl_surface_get_user_data(surface); - - _glfw.wl.serial = serial; - _glfw.wl.pointerEnterSerial = serial; - _glfw.wl.pointerFocus = window; - - if (surface == window->wl.surface) - { - window->wl.hovered = GLFW_TRUE; - _glfwSetCursorWayland(window, window->wl.currentCursor); - _glfwInputCursorEnter(window, GLFW_TRUE); - } - else - { - if (window->wl.fallback.decorations) - window->wl.fallback.focus = surface; - } -} - -static void pointerHandleLeave(void* userData, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface) -{ - if (!surface) - return; - - if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag) - return; - - _GLFWwindow* window = _glfw.wl.pointerFocus; - if (!window) - return; - - _glfw.wl.serial = serial; - _glfw.wl.pointerFocus = NULL; - _glfw.wl.cursorPreviousName = NULL; - - if (window->wl.hovered) - { - window->wl.hovered = GLFW_FALSE; - _glfwInputCursorEnter(window, GLFW_FALSE); - } - else - { - if (window->wl.fallback.decorations) - window->wl.fallback.focus = NULL; - } -} - -static void pointerHandleMotion(void* userData, - struct wl_pointer* pointer, - uint32_t time, - wl_fixed_t sx, - wl_fixed_t sy) -{ - _GLFWwindow* window = _glfw.wl.pointerFocus; - if (!window) - return; - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - return; - - const double xpos = wl_fixed_to_double(sx); - const double ypos = wl_fixed_to_double(sy); - window->wl.cursorPosX = xpos; - window->wl.cursorPosY = ypos; - - if (window->wl.hovered) - { - _glfw.wl.cursorPreviousName = NULL; - _glfwInputCursorPos(window, xpos, ypos); - return; - } - - if (window->wl.fallback.decorations) - { - const char* cursorName = "left_ptr"; - - if (window->resizable) - { - if (window->wl.fallback.focus == window->wl.fallback.top.surface) - { - if (ypos < GLFW_BORDER_SIZE) - cursorName = "n-resize"; - } - else if (window->wl.fallback.focus == window->wl.fallback.left.surface) - { - if (ypos < GLFW_BORDER_SIZE) - cursorName = "nw-resize"; - else - cursorName = "w-resize"; - } - else if (window->wl.fallback.focus == window->wl.fallback.right.surface) - { - if (ypos < GLFW_BORDER_SIZE) - cursorName = "ne-resize"; - else - cursorName = "e-resize"; - } - else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface) - { - if (xpos < GLFW_BORDER_SIZE) - cursorName = "sw-resize"; - else if (xpos > window->wl.width + GLFW_BORDER_SIZE) - cursorName = "se-resize"; - else - cursorName = "s-resize"; - } - } - - if (_glfw.wl.cursorPreviousName != cursorName) - { - struct wl_surface* surface = _glfw.wl.cursorSurface; - struct wl_cursor_theme* theme = _glfw.wl.cursorTheme; - int scale = 1; - - if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI) - { - // We only support up to scale=2 for now, since libwayland-cursor - // requires us to load a different theme for each size. - scale = 2; - theme = _glfw.wl.cursorThemeHiDPI; - } - - struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName); - if (!cursor) + read_ret = read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)); + if (read_ret != 8) return; - // TODO: handle animated cursors too. - struct wl_cursor_image* image = cursor->images[0]; - if (!image) - return; - - struct wl_buffer* buffer = wl_cursor_image_get_buffer(image); - if (!buffer) - return; - - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, - surface, - image->hotspot_x / scale, - image->hotspot_y / scale); - wl_surface_set_buffer_scale(surface, scale); - wl_surface_attach(surface, buffer, 0, 0); - wl_surface_damage(surface, 0, 0, image->width, image->height); - wl_surface_commit(surface); - - _glfw.wl.cursorPreviousName = cursorName; + incrementCursorImage(_glfw.wl.pointerFocus); } } -} - -static void pointerHandleButton(void* userData, - struct wl_pointer* pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - _GLFWwindow* window = _glfw.wl.pointerFocus; - if (!window) - return; - - if (window->wl.hovered) - { - _glfw.wl.serial = serial; - - _glfwInputMouseClick(window, - button - BTN_LEFT, - state == WL_POINTER_BUTTON_STATE_PRESSED, - _glfw.wl.xkb.modifiers); - return; - } - - if (window->wl.fallback.decorations) - { - if (button == BTN_LEFT) - { - uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; - - if (window->wl.fallback.focus == window->wl.fallback.top.surface) - { - if (window->wl.cursorPosY < GLFW_BORDER_SIZE) - edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else - xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); - } - else if (window->wl.fallback.focus == window->wl.fallback.left.surface) - { - if (window->wl.cursorPosY < GLFW_BORDER_SIZE) - edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - else - edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - } - else if (window->wl.fallback.focus == window->wl.fallback.right.surface) - { - if (window->wl.cursorPosY < GLFW_BORDER_SIZE) - edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - else - edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - } - else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface) - { - if (window->wl.cursorPosX < GLFW_BORDER_SIZE) - edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE) - edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; - else - edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; - } - - if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) - { - xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, - serial, edges); - } - } - else if (button == BTN_RIGHT) - { - if (window->wl.xdg.toplevel) - { - xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, - _glfw.wl.seat, serial, - window->wl.cursorPosX, - window->wl.cursorPosY); - } - } - } -} - -static void pointerHandleAxis(void* userData, - struct wl_pointer* pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) -{ - _GLFWwindow* window = _glfw.wl.pointerFocus; - if (!window) - return; - - // NOTE: 10 units of motion per mouse wheel step seems to be a common ratio - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) - _glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0); - else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) - _glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0); -} - -static const struct wl_pointer_listener pointerListener = -{ - pointerHandleEnter, - pointerHandleLeave, - pointerHandleMotion, - pointerHandleButton, - pointerHandleAxis, -}; - -static void keyboardHandleKeymap(void* userData, - struct wl_keyboard* keyboard, - uint32_t format, - int fd, - uint32_t size) -{ - struct xkb_keymap* keymap; - struct xkb_state* state; - struct xkb_compose_table* composeTable; - struct xkb_compose_state* composeState; - - char* mapStr; - const char* locale; - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) - { - close(fd); - return; - } - - mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (mapStr == MAP_FAILED) { - close(fd); - return; - } - - keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, - mapStr, - XKB_KEYMAP_FORMAT_TEXT_V1, - 0); - munmap(mapStr, size); - close(fd); - - if (!keymap) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to compile keymap"); - return; - } - - state = xkb_state_new(keymap); - if (!state) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create XKB state"); - xkb_keymap_unref(keymap); - return; - } - - // Look up the preferred locale, falling back to "C" as default. - locale = getenv("LC_ALL"); - if (!locale) - locale = getenv("LC_CTYPE"); - if (!locale) - locale = getenv("LANG"); - if (!locale) - locale = "C"; - - composeTable = - xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, - XKB_COMPOSE_COMPILE_NO_FLAGS); - if (composeTable) - { - composeState = - xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); - xkb_compose_table_unref(composeTable); - if (composeState) - _glfw.wl.xkb.composeState = composeState; - else - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create XKB compose state"); - } else { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create XKB compose table"); - } - - xkb_keymap_unref(_glfw.wl.xkb.keymap); - xkb_state_unref(_glfw.wl.xkb.state); - _glfw.wl.xkb.keymap = keymap; - _glfw.wl.xkb.state = state; - - _glfw.wl.xkb.controlIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); - _glfw.wl.xkb.altIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); - _glfw.wl.xkb.shiftIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); - _glfw.wl.xkb.superIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); - _glfw.wl.xkb.capsLockIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); - _glfw.wl.xkb.numLockIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); -} - -static void keyboardHandleEnter(void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - struct wl_surface* surface, - struct wl_array* keys) -{ - // Happens in the case we just destroyed the surface. - if (!surface) - return; - - if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag) - return; - - _GLFWwindow* window = wl_surface_get_user_data(surface); - if (surface != window->wl.surface) - return; - - _glfw.wl.serial = serial; - _glfw.wl.keyboardFocus = window; - _glfwInputWindowFocus(window, GLFW_TRUE); -} - -static void keyboardHandleLeave(void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - struct wl_surface* surface) -{ - _GLFWwindow* window = _glfw.wl.keyboardFocus; - - if (!window) - return; - - struct itimerspec timer = {0}; - timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL); - - _glfw.wl.serial = serial; - _glfw.wl.keyboardFocus = NULL; - _glfwInputWindowFocus(window, GLFW_FALSE); -} - -static void keyboardHandleKey(void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - uint32_t time, - uint32_t scancode, - uint32_t state) -{ - _GLFWwindow* window = _glfw.wl.keyboardFocus; - if (!window) - return; - - const int key = translateKeyWayland(scancode); - const int action = - state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE; - - _glfw.wl.serial = serial; - - struct itimerspec timer = {0}; - - if (action == GLFW_PRESS) - { - const xkb_keycode_t keycode = scancode + 8; - - if (xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode) && - _glfw.wl.keyRepeatRate > 0) - { - _glfw.wl.keyRepeatScancode = scancode; - if (_glfw.wl.keyRepeatRate > 1) - timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyRepeatRate; - else - timer.it_interval.tv_sec = 1; - - timer.it_value.tv_sec = _glfw.wl.keyRepeatDelay / 1000; - timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000; - } - } - - timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL); - - _glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers); - - if (action == GLFW_PRESS) - inputText(window, scancode); -} - -static void keyboardHandleModifiers(void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - uint32_t modsDepressed, - uint32_t modsLatched, - uint32_t modsLocked, - uint32_t group) -{ - _glfw.wl.serial = serial; - - if (!_glfw.wl.xkb.keymap) - return; - - xkb_state_update_mask(_glfw.wl.xkb.state, - modsDepressed, - modsLatched, - modsLocked, - 0, - 0, - group); - - _glfw.wl.xkb.modifiers = 0; - - struct - { - xkb_mod_index_t index; - unsigned int bit; - } modifiers[] = - { - { _glfw.wl.xkb.controlIndex, GLFW_MOD_CONTROL }, - { _glfw.wl.xkb.altIndex, GLFW_MOD_ALT }, - { _glfw.wl.xkb.shiftIndex, GLFW_MOD_SHIFT }, - { _glfw.wl.xkb.superIndex, GLFW_MOD_SUPER }, - { _glfw.wl.xkb.capsLockIndex, GLFW_MOD_CAPS_LOCK }, - { _glfw.wl.xkb.numLockIndex, GLFW_MOD_NUM_LOCK } - }; - - for (size_t i = 0; i < sizeof(modifiers) / sizeof(modifiers[0]); i++) - { - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - modifiers[i].index, - XKB_STATE_MODS_EFFECTIVE) == 1) - { - _glfw.wl.xkb.modifiers |= modifiers[i].bit; - } + wl_display_cancel_read(display); } } -static void keyboardHandleRepeatInfo(void* userData, - struct wl_keyboard* keyboard, - int32_t rate, - int32_t delay) -{ - if (keyboard != _glfw.wl.keyboard) - return; - - _glfw.wl.keyRepeatRate = rate; - _glfw.wl.keyRepeatDelay = delay; -} - -static const struct wl_keyboard_listener keyboardListener = -{ - keyboardHandleKeymap, - keyboardHandleEnter, - keyboardHandleLeave, - keyboardHandleKey, - keyboardHandleModifiers, - keyboardHandleRepeatInfo, -}; - -static void seatHandleCapabilities(void* userData, - struct wl_seat* seat, - enum wl_seat_capability caps) -{ - if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) - { - _glfw.wl.pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); - } - else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) - { - wl_pointer_destroy(_glfw.wl.pointer); - _glfw.wl.pointer = NULL; - } - - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) - { - _glfw.wl.keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); - } - else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) - { - wl_keyboard_destroy(_glfw.wl.keyboard); - _glfw.wl.keyboard = NULL; - } -} - -static void seatHandleName(void* userData, - struct wl_seat* seat, - const char* name) -{ -} - -static const struct wl_seat_listener seatListener = -{ - seatHandleCapabilities, - seatHandleName, -}; - -static void dataOfferHandleOffer(void* userData, - struct wl_data_offer* offer, - const char* mimeType) -{ - for (unsigned int i = 0; i < _glfw.wl.offerCount; i++) - { - if (_glfw.wl.offers[i].offer == offer) - { - if (strcmp(mimeType, "text/plain;charset=utf-8") == 0) - _glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE; - else if (strcmp(mimeType, "text/uri-list") == 0) - _glfw.wl.offers[i].text_uri_list = GLFW_TRUE; - - break; - } - } -} - -static const struct wl_data_offer_listener dataOfferListener = -{ - dataOfferHandleOffer -}; - -static void dataDeviceHandleDataOffer(void* userData, - struct wl_data_device* device, - struct wl_data_offer* offer) -{ - _GLFWofferWayland* offers = - _glfw_realloc(_glfw.wl.offers, - sizeof(_GLFWofferWayland) * (_glfw.wl.offerCount + 1)); - if (!offers) - { - _glfwInputError(GLFW_OUT_OF_MEMORY, NULL); - return; - } - - _glfw.wl.offers = offers; - _glfw.wl.offerCount++; - - _glfw.wl.offers[_glfw.wl.offerCount - 1] = (_GLFWofferWayland) { offer }; - wl_data_offer_add_listener(offer, &dataOfferListener, NULL); -} - -static void dataDeviceHandleEnter(void* userData, - struct wl_data_device* device, - uint32_t serial, - struct wl_surface* surface, - wl_fixed_t x, - wl_fixed_t y, - struct wl_data_offer* offer) -{ - if (_glfw.wl.dragOffer) - { - wl_data_offer_destroy(_glfw.wl.dragOffer); - _glfw.wl.dragOffer = NULL; - _glfw.wl.dragFocus = NULL; - } - - for (unsigned int i = 0; i < _glfw.wl.offerCount; i++) - { - if (_glfw.wl.offers[i].offer == offer) - { - _GLFWwindow* window = NULL; - - if (surface) - { - if (wl_proxy_get_tag((struct wl_proxy*) surface) == &_glfw.wl.tag) - window = wl_surface_get_user_data(surface); - } - - if (surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list) - { - _glfw.wl.dragOffer = offer; - _glfw.wl.dragFocus = window; - _glfw.wl.dragSerial = serial; - } - - _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1]; - _glfw.wl.offerCount--; - break; - } - } - - if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag) - return; - - if (_glfw.wl.dragOffer) - wl_data_offer_accept(offer, serial, "text/uri-list"); - else - { - wl_data_offer_accept(offer, serial, NULL); - wl_data_offer_destroy(offer); - } -} - -static void dataDeviceHandleLeave(void* userData, - struct wl_data_device* device) -{ - if (_glfw.wl.dragOffer) - { - wl_data_offer_destroy(_glfw.wl.dragOffer); - _glfw.wl.dragOffer = NULL; - _glfw.wl.dragFocus = NULL; - } -} - -static void dataDeviceHandleMotion(void* userData, - struct wl_data_device* device, - uint32_t time, - wl_fixed_t x, - wl_fixed_t y) -{ -} - -static void dataDeviceHandleDrop(void* userData, - struct wl_data_device* device) -{ - if (!_glfw.wl.dragOffer) - return; - - char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list"); - if (string) - { - int count; - char** paths = _glfwParseUriList(string, &count); - if (paths) - _glfwInputDrop(_glfw.wl.dragFocus, count, (const char**) paths); - - for (int i = 0; i < count; i++) - _glfw_free(paths[i]); - - _glfw_free(paths); - } - - _glfw_free(string); -} - -static void dataDeviceHandleSelection(void* userData, - struct wl_data_device* device, - struct wl_data_offer* offer) -{ - if (_glfw.wl.selectionOffer) - { - wl_data_offer_destroy(_glfw.wl.selectionOffer); - _glfw.wl.selectionOffer = NULL; - } - - for (unsigned int i = 0; i < _glfw.wl.offerCount; i++) - { - if (_glfw.wl.offers[i].offer == offer) - { - if (_glfw.wl.offers[i].text_plain_utf8) - _glfw.wl.selectionOffer = offer; - else - wl_data_offer_destroy(offer); - - _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1]; - _glfw.wl.offerCount--; - break; - } - } -} - -const struct wl_data_device_listener dataDeviceListener = -{ - dataDeviceHandleDataOffer, - dataDeviceHandleEnter, - dataDeviceHandleLeave, - dataDeviceHandleMotion, - dataDeviceHandleDrop, - dataDeviceHandleSelection, -}; - -static void xdgActivationHandleDone(void* userData, - struct xdg_activation_token_v1* activationToken, - const char* token) -{ - _GLFWwindow* window = userData; - - if (activationToken != window->wl.activationToken) - return; - - xdg_activation_v1_activate(_glfw.wl.activationManager, token, window->wl.surface); - xdg_activation_token_v1_destroy(window->wl.activationToken); - window->wl.activationToken = NULL; -} - -static const struct xdg_activation_token_v1_listener xdgActivationListener = -{ - xdgActivationHandleDone -}; - -void _glfwAddSeatListenerWayland(struct wl_seat* seat) -{ - wl_seat_add_listener(seat, &seatListener, NULL); -} - -void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device) -{ - wl_data_device_add_listener(device, &dataDeviceListener, NULL); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { - if (!createNativeSurface(window, wndconfig, fbconfig)) + window->wl.transparent = fbconfig->transparent; + + if (!createSurface(window, wndconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -2137,16 +796,6 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, if (ctxconfig->source == GLFW_EGL_CONTEXT_API || ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { - window->wl.egl.window = wl_egl_window_create(window->wl.surface, - window->wl.fbWidth, - window->wl.fbHeight); - if (!window->wl.egl.window) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create EGL window"); - return GLFW_FALSE; - } - if (!_glfwInitEGL()) return GLFW_FALSE; if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) @@ -2159,80 +808,93 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } - - if (!_glfwRefreshContextAttribs(window, ctxconfig)) - return GLFW_FALSE; } - if (wndconfig->mousePassthrough) - _glfwSetWindowMousePassthroughWayland(window, GLFW_TRUE); + if (wndconfig->title) + window->wl.title = _glfw_strdup(wndconfig->title); - if (window->monitor || wndconfig->visible) + if (wndconfig->visible) { - if (!createShellObjects(window)) + if (!createXdgSurface(window)) return GLFW_FALSE; + + window->wl.visible = GLFW_TRUE; } + else + { + window->wl.xdg.surface = NULL; + window->wl.xdg.toplevel = NULL; + window->wl.visible = GLFW_FALSE; + } + + window->wl.currentCursor = NULL; + + window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*)); + window->wl.monitorsCount = 0; + window->wl.monitorsSize = 1; return GLFW_TRUE; } -void _glfwDestroyWindowWayland(_GLFWwindow* window) +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window == _glfw.wl.pointerFocus) + { _glfw.wl.pointerFocus = NULL; - + _glfwInputCursorEnter(window, GLFW_FALSE); + } if (window == _glfw.wl.keyboardFocus) + { _glfw.wl.keyboardFocus = NULL; - - if (window->wl.activationToken) - xdg_activation_token_v1_destroy(window->wl.activationToken); + _glfwInputWindowFocus(window, GLFW_FALSE); + } if (window->wl.idleInhibitor) zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); - if (window->wl.relativePointer) - zwp_relative_pointer_v1_destroy(window->wl.relativePointer); - - if (window->wl.lockedPointer) - zwp_locked_pointer_v1_destroy(window->wl.lockedPointer); - - if (window->wl.confinedPointer) - zwp_confined_pointer_v1_destroy(window->wl.confinedPointer); - if (window->context.destroy) window->context.destroy(window); - destroyShellObjects(window); + destroyDecorations(window); + if (window->wl.xdg.decoration) + zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); - if (window->wl.fallback.buffer) - wl_buffer_destroy(window->wl.fallback.buffer); + if (window->wl.decorations.buffer) + wl_buffer_destroy(window->wl.decorations.buffer); - if (window->wl.egl.window) - wl_egl_window_destroy(window->wl.egl.window); + if (window->wl.native) + wl_egl_window_destroy(window->wl.native); + + if (window->wl.xdg.toplevel) + xdg_toplevel_destroy(window->wl.xdg.toplevel); + + if (window->wl.xdg.surface) + xdg_surface_destroy(window->wl.xdg.surface); if (window->wl.surface) wl_surface_destroy(window->wl.surface); - _glfw_free(window->wl.appId); - _glfw_free(window->wl.outputScales); + free(window->wl.title); + free(window->wl.monitors); } -void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title) +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { - if (window->wl.libdecor.frame) - libdecor_frame_set_title(window->wl.libdecor.frame, title); - else if (window->wl.xdg.toplevel) + if (window->wl.title) + free(window->wl.title); + window->wl.title = _glfw_strdup(title); + if (window->wl.xdg.toplevel) xdg_toplevel_set_title(window->wl.xdg.toplevel, title); } -void _glfwSetWindowIconWayland(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) { _glfwInputError(GLFW_FEATURE_UNAVAILABLE, "Wayland: The platform does not support setting the window icon"); } -void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { // A Wayland client is not aware of its position, so just warn and leave it // as (0, 0) @@ -2241,7 +903,7 @@ void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos) "Wayland: The platform does not provide the window position"); } -void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos) +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { // A Wayland client can not set its position, so just warn @@ -2249,7 +911,7 @@ void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos) "Wayland: The platform does not support setting the window position"); } -void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->wl.width; @@ -2257,353 +919,217 @@ void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height) *height = window->wl.height; } -void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height) +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { - if (window->monitor) - { - // Video mode setting is not available on Wayland - } - else - { - if (!resizeWindow(window, width, height)) - return; - - if (window->wl.libdecor.frame) - { - struct libdecor_state* frameState = - libdecor_state_new(window->wl.width, window->wl.height); - libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL); - libdecor_state_free(frameState); - } - - if (window->wl.visible) - _glfwInputWindowDamage(window); - } + window->wl.width = width; + window->wl.height = height; + resizeWindow(window); } -void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { - if (window->wl.libdecor.frame) + if (window->wl.xdg.toplevel) { if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) minwidth = minheight = 0; - if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) maxwidth = maxheight = 0; - - libdecor_frame_set_min_content_size(window->wl.libdecor.frame, - minwidth, minheight); - libdecor_frame_set_max_content_size(window->wl.libdecor.frame, - maxwidth, maxheight); - } - else if (window->wl.xdg.toplevel) - updateXdgSizeLimits(window); -} - -void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom) -{ - if (window->wl.maximized || window->wl.fullscreen) - return; - - int width = window->wl.width, height = window->wl.height; - - if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) - { - const float aspectRatio = (float) width / (float) height; - const float targetRatio = (float) numer / (float) denom; - if (aspectRatio < targetRatio) - height /= targetRatio; - else if (aspectRatio > targetRatio) - width *= targetRatio; - } - - if (resizeWindow(window, width, height)) - { - if (window->wl.libdecor.frame) - { - struct libdecor_state* frameState = - libdecor_state_new(window->wl.width, window->wl.height); - libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL); - libdecor_state_free(frameState); - } - - _glfwInputWindowSize(window, window->wl.width, window->wl.height); - - if (window->wl.visible) - _glfwInputWindowDamage(window); - } -} - -void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height) -{ - if (width) - *width = window->wl.fbWidth; - if (height) - *height = window->wl.fbHeight; -} - -void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) -{ - if (window->wl.fallback.decorations) - { - if (top) - *top = GLFW_CAPTION_HEIGHT; - if (left) - *left = GLFW_BORDER_SIZE; - if (right) - *right = GLFW_BORDER_SIZE; - if (bottom) - *bottom = GLFW_BORDER_SIZE; - } -} - -void _glfwGetWindowContentScaleWayland(_GLFWwindow* window, - float* xscale, float* yscale) -{ - if (window->wl.fractionalScale) - { - if (xscale) - *xscale = (float) window->wl.scalingNumerator / 120.f; - if (yscale) - *yscale = (float) window->wl.scalingNumerator / 120.f; - } - else - { - if (xscale) - *xscale = (float) window->wl.bufferScale; - if (yscale) - *yscale = (float) window->wl.bufferScale; - } -} - -void _glfwIconifyWindowWayland(_GLFWwindow* window) -{ - if (window->wl.libdecor.frame) - libdecor_frame_set_minimized(window->wl.libdecor.frame); - else if (window->wl.xdg.toplevel) - xdg_toplevel_set_minimized(window->wl.xdg.toplevel); -} - -void _glfwRestoreWindowWayland(_GLFWwindow* window) -{ - if (window->monitor) - { - // There is no way to unset minimized, or even to know if we are - // minimized, so there is nothing to do in this case. - } - else - { - // We assume we are not minimized and act only on maximization - - if (window->wl.maximized) - { - if (window->wl.libdecor.frame) - libdecor_frame_unset_maximized(window->wl.libdecor.frame); - else if (window->wl.xdg.toplevel) - xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); - else - window->wl.maximized = GLFW_FALSE; - } - } -} - -void _glfwMaximizeWindowWayland(_GLFWwindow* window) -{ - if (window->wl.libdecor.frame) - libdecor_frame_set_maximized(window->wl.libdecor.frame); - else if (window->wl.xdg.toplevel) - xdg_toplevel_set_maximized(window->wl.xdg.toplevel); - else - window->wl.maximized = GLFW_TRUE; -} - -void _glfwShowWindowWayland(_GLFWwindow* window) -{ - if (!window->wl.libdecor.frame && !window->wl.xdg.toplevel) - { - // NOTE: The XDG surface and role are created here so command-line applications - // with off-screen windows do not appear in for example the Unity dock - createShellObjects(window); - } -} - -void _glfwHideWindowWayland(_GLFWwindow* window) -{ - if (window->wl.visible) - { - window->wl.visible = GLFW_FALSE; - destroyShellObjects(window); - - wl_surface_attach(window->wl.surface, NULL, 0, 0); + xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight); + xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); wl_surface_commit(window->wl.surface); } } -void _glfwRequestWindowAttentionWayland(_GLFWwindow* window) +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, + int numer, int denom) { - if (!_glfw.wl.activationManager) - return; - - // We're about to overwrite this with a new request - if (window->wl.activationToken) - xdg_activation_token_v1_destroy(window->wl.activationToken); - - window->wl.activationToken = - xdg_activation_v1_get_activation_token(_glfw.wl.activationManager); - xdg_activation_token_v1_add_listener(window->wl.activationToken, - &xdgActivationListener, - window); - - xdg_activation_token_v1_commit(window->wl.activationToken); + // TODO: find out how to trigger a resize. + // The actual limits are checked in the xdg_toplevel::configure handler. + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Wayland: Window aspect ratio not yet implemented"); } -void _glfwFocusWindowWayland(_GLFWwindow* window) +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, + int* width, int* height) { - if (!_glfw.wl.activationManager) - return; - - if (window->wl.activationToken) - xdg_activation_token_v1_destroy(window->wl.activationToken); - - window->wl.activationToken = - xdg_activation_v1_get_activation_token(_glfw.wl.activationManager); - xdg_activation_token_v1_add_listener(window->wl.activationToken, - &xdgActivationListener, - window); - - xdg_activation_token_v1_set_serial(window->wl.activationToken, - _glfw.wl.serial, - _glfw.wl.seat); - - _GLFWwindow* requester = _glfw.wl.keyboardFocus; - if (requester) - { - xdg_activation_token_v1_set_surface(window->wl.activationToken, - requester->wl.surface); - - if (requester->wl.appId) - { - xdg_activation_token_v1_set_app_id(window->wl.activationToken, - requester->wl.appId); - } - } - - xdg_activation_token_v1_commit(window->wl.activationToken); + _glfwPlatformGetWindowSize(window, width, height); + if (width) + *width *= window->wl.scale; + if (height) + *height *= window->wl.scale; } -void _glfwSetWindowMonitorWayland(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { - if (window->monitor == monitor) + if (window->decorated && !window->monitor && !window->wl.decorations.serverSide) { - if (!monitor) - _glfwSetWindowSizeWayland(window, width, height); - - return; + if (top) + *top = _GLFW_DECORATION_TOP; + if (left) + *left = _GLFW_DECORATION_WIDTH; + if (right) + *right = _GLFW_DECORATION_WIDTH; + if (bottom) + *bottom = _GLFW_DECORATION_WIDTH; } +} - if (window->monitor) - releaseMonitorWayland(window); +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = (float) window->wl.scale; + if (yscale) + *yscale = (float) window->wl.scale; +} - _glfwInputWindowMonitor(window, monitor); +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + if (window->wl.xdg.toplevel) + xdg_toplevel_set_minimized(window->wl.xdg.toplevel); +} - if (window->monitor) - acquireMonitorWayland(window); +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + if (window->wl.xdg.toplevel) + { + if (window->monitor) + xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); + if (window->wl.maximized) + xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); + // There is no way to unset minimized, or even to know if we are + // minimized, so there is nothing to do in this case. + } + _glfwInputWindowMonitor(window, NULL); + window->wl.maximized = GLFW_FALSE; +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (window->wl.xdg.toplevel) + { + xdg_toplevel_set_maximized(window->wl.xdg.toplevel); + } + window->wl.maximized = GLFW_TRUE; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + if (!window->wl.visible) + { + createXdgSurface(window); + window->wl.visible = GLFW_TRUE; + } +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + if (window->wl.xdg.toplevel) + { + xdg_toplevel_destroy(window->wl.xdg.toplevel); + xdg_surface_destroy(window->wl.xdg.surface); + window->wl.xdg.toplevel = NULL; + window->wl.xdg.surface = NULL; + } + window->wl.visible = GLFW_FALSE; +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + // TODO + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Wayland: Window attention request not implemented yet"); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The platform does not support setting the input focus"); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (monitor) + { + setFullscreen(window, monitor, refreshRate); + } else - _glfwSetWindowSizeWayland(window, width, height); + { + if (window->wl.xdg.toplevel) + xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); + setIdleInhibitor(window, GLFW_FALSE); + if (!_glfw.wl.decorationManager) + createDecorations(window); + } + _glfwInputWindowMonitor(window, monitor); } -GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window) +int _glfwPlatformWindowFocused(_GLFWwindow* window) { return _glfw.wl.keyboardFocus == window; } -GLFWbool _glfwWindowIconifiedWayland(_GLFWwindow* window) +int _glfwPlatformWindowIconified(_GLFWwindow* window) { // xdg-shell doesn’t give any way to request whether a surface is // iconified. return GLFW_FALSE; } -GLFWbool _glfwWindowVisibleWayland(_GLFWwindow* window) +int _glfwPlatformWindowVisible(_GLFWwindow* window) { return window->wl.visible; } -GLFWbool _glfwWindowMaximizedWayland(_GLFWwindow* window) +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { return window->wl.maximized; } -GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window) +int _glfwPlatformWindowHovered(_GLFWwindow* window) { return window->wl.hovered; } -GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window) +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return window->wl.transparent; } -void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { - if (window->wl.libdecor.frame) - { - if (enabled) - { - libdecor_frame_set_capabilities(window->wl.libdecor.frame, - LIBDECOR_ACTION_RESIZE); - } - else - { - libdecor_frame_unset_capabilities(window->wl.libdecor.frame, - LIBDECOR_ACTION_RESIZE); - } - } - else if (window->wl.xdg.toplevel) - updateXdgSizeLimits(window); + // TODO + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Wayland: Window attribute setting not implemented yet"); } -void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { - if (window->wl.libdecor.frame) - { - libdecor_frame_set_visibility(window->wl.libdecor.frame, enabled); - } - else if (window->wl.xdg.decoration) - { - uint32_t mode; - - if (enabled) - mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - else - mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - - zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode); - } - else if (window->wl.xdg.toplevel) + if (!window->monitor) { if (enabled) - createFallbackDecorations(window); + createDecorations(window); else - destroyFallbackDecorations(window); + destroyDecorations(window); } } -void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { - _glfwInputError(GLFW_FEATURE_UNAVAILABLE, - "Wayland: Platform does not support making a window floating"); + // TODO + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Wayland: Window attribute setting not implemented yet"); } -void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled) { if (enabled) { @@ -2612,53 +1138,52 @@ void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled wl_region_destroy(region); } else - wl_surface_set_input_region(window->wl.surface, NULL); + wl_surface_set_input_region(window->wl.surface, 0); + wl_surface_commit(window->wl.surface); } -float _glfwGetWindowOpacityWayland(_GLFWwindow* window) +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { return 1.f; } -void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity) +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { _glfwInputError(GLFW_FEATURE_UNAVAILABLE, "Wayland: The platform does not support setting the window opacity"); } -void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { // This is handled in relativePointerHandleRelativeMotion } -GLFWbool _glfwRawMouseMotionSupportedWayland(void) +GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_TRUE; } -void _glfwPollEventsWayland(void) +void _glfwPlatformPollEvents(void) { - double timeout = 0.0; - handleEvents(&timeout); + handleEvents(0); } -void _glfwWaitEventsWayland(void) +void _glfwPlatformWaitEvents(void) { - handleEvents(NULL); + handleEvents(-1); } -void _glfwWaitEventsTimeoutWayland(double timeout) +void _glfwPlatformWaitEventsTimeout(double timeout) { - handleEvents(&timeout); + handleEvents((int) (timeout * 1e3)); } -void _glfwPostEmptyEventWayland(void) +void _glfwPlatformPostEmptyEvent(void) { wl_display_sync(_glfw.wl.display); - flushDisplay(); } -void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { if (xpos) *xpos = window->wl.cursorPosX; @@ -2666,82 +1191,40 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos) *ypos = window->wl.cursorPosY; } -void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y) +static GLFWbool isPointerLocked(_GLFWwindow* window); + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { - _glfwInputError(GLFW_FEATURE_UNAVAILABLE, - "Wayland: The platform does not support setting the cursor position"); + if (isPointerLocked(window)) + { + zwp_locked_pointer_v1_set_cursor_position_hint( + window->wl.pointerLock.lockedPointer, + wl_fixed_from_double(x), wl_fixed_from_double(y)); + wl_surface_commit(window->wl.surface); + } } -void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode) +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - _glfwSetCursorWayland(window, window->wl.currentCursor); + _glfwPlatformSetCursor(window, window->wl.currentCursor); } -const char* _glfwGetScancodeNameWayland(int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { - if (scancode < 0 || scancode > 255) - { - _glfwInputError(GLFW_INVALID_VALUE, - "Wayland: Invalid scancode %i", - scancode); - return NULL; - } - - const int key = _glfw.wl.keycodes[scancode]; - if (key == GLFW_KEY_UNKNOWN) - return NULL; - - const xkb_keycode_t keycode = scancode + 8; - const xkb_layout_index_t layout = - xkb_state_key_get_layout(_glfw.wl.xkb.state, keycode); - if (layout == XKB_LAYOUT_INVALID) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to retrieve layout for key name"); - return NULL; - } - - const xkb_keysym_t* keysyms = NULL; - xkb_keymap_key_get_syms_by_level(_glfw.wl.xkb.keymap, - keycode, - layout, - 0, - &keysyms); - if (keysyms == NULL) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to retrieve keysym for key name"); - return NULL; - } - - const uint32_t codepoint = _glfwKeySym2Unicode(keysyms[0]); - if (codepoint == GLFW_INVALID_CODEPOINT) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to retrieve codepoint for key name"); - return NULL; - } - - const size_t count = _glfwEncodeUTF8(_glfw.wl.keynames[key], codepoint); - if (count == 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to encode codepoint for key name"); - return NULL; - } - - _glfw.wl.keynames[key][count] = '\0'; - return _glfw.wl.keynames[key]; + // TODO + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Wayland: Key names not yet implemented"); + return NULL; } -int _glfwGetKeyScancodeWayland(int key) +int _glfwPlatformGetKeyScancode(int key) { return _glfw.wl.scancodes[key]; } -GLFWbool _glfwCreateCursorWayland(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { cursor->wl.buffer = createShmBuffer(image); if (!cursor->wl.buffer) @@ -2754,44 +1237,31 @@ GLFWbool _glfwCreateCursorWayland(_GLFWcursor* cursor, return GLFW_TRUE; } -GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape) +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { const char* name = NULL; // Try the XDG names first - switch (shape) - { - case GLFW_ARROW_CURSOR: - name = "default"; - break; - case GLFW_IBEAM_CURSOR: - name = "text"; - break; - case GLFW_CROSSHAIR_CURSOR: - name = "crosshair"; - break; - case GLFW_POINTING_HAND_CURSOR: - name = "pointer"; - break; - case GLFW_RESIZE_EW_CURSOR: - name = "ew-resize"; - break; - case GLFW_RESIZE_NS_CURSOR: - name = "ns-resize"; - break; - case GLFW_RESIZE_NWSE_CURSOR: - name = "nwse-resize"; - break; - case GLFW_RESIZE_NESW_CURSOR: - name = "nesw-resize"; - break; - case GLFW_RESIZE_ALL_CURSOR: - name = "all-scroll"; - break; - case GLFW_NOT_ALLOWED_CURSOR: - name = "not-allowed"; - break; - } + if (shape == GLFW_ARROW_CURSOR) + name = "default"; + else if (shape == GLFW_IBEAM_CURSOR) + name = "text"; + else if (shape == GLFW_CROSSHAIR_CURSOR) + name = "crosshair"; + else if (shape == GLFW_POINTING_HAND_CURSOR) + name = "pointer"; + else if (shape == GLFW_RESIZE_EW_CURSOR) + name = "ew-resize"; + else if (shape == GLFW_RESIZE_NS_CURSOR) + name = "ns-resize"; + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + name = "nwse-resize"; + else if (shape == GLFW_RESIZE_NESW_CURSOR) + name = "nesw-resize"; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + name = "all-scroll"; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + name = "not-allowed"; cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); @@ -2804,39 +1274,31 @@ GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape) if (!cursor->wl.cursor) { // Fall back to the core X11 names - switch (shape) + if (shape == GLFW_ARROW_CURSOR) + name = "left_ptr"; + else if (shape == GLFW_IBEAM_CURSOR) + name = "xterm"; + else if (shape == GLFW_CROSSHAIR_CURSOR) + name = "crosshair"; + else if (shape == GLFW_POINTING_HAND_CURSOR) + name = "hand2"; + else if (shape == GLFW_RESIZE_EW_CURSOR) + name = "sb_h_double_arrow"; + else if (shape == GLFW_RESIZE_NS_CURSOR) + name = "sb_v_double_arrow"; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + name = "fleur"; + else { - case GLFW_ARROW_CURSOR: - name = "left_ptr"; - break; - case GLFW_IBEAM_CURSOR: - name = "xterm"; - break; - case GLFW_CROSSHAIR_CURSOR: - name = "crosshair"; - break; - case GLFW_POINTING_HAND_CURSOR: - name = "hand2"; - break; - case GLFW_RESIZE_EW_CURSOR: - name = "sb_h_double_arrow"; - break; - case GLFW_RESIZE_NS_CURSOR: - name = "sb_v_double_arrow"; - break; - case GLFW_RESIZE_ALL_CURSOR: - name = "fleur"; - break; - default: - _glfwInputError(GLFW_CURSOR_UNAVAILABLE, - "Wayland: Standard cursor shape unavailable"); - return GLFW_FALSE; + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "Wayland: Standard cursor shape unavailable"); + return GLFW_FALSE; } cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); if (!cursor->wl.cursor) { - _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create standard cursor \"%s\"", name); return GLFW_FALSE; @@ -2855,7 +1317,7 @@ GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape) return GLFW_TRUE; } -void _glfwDestroyCursorWayland(_GLFWcursor* cursor) +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { // If it's a standard cursor we don't need to do anything here if (cursor->wl.cursor) @@ -2865,7 +1327,7 @@ void _glfwDestroyCursorWayland(_GLFWcursor* cursor) wl_buffer_destroy(cursor->wl.buffer); } -static void relativePointerHandleRelativeMotion(void* userData, +static void relativePointerHandleRelativeMotion(void* data, struct zwp_relative_pointer_v1* pointer, uint32_t timeHi, uint32_t timeLo, @@ -2874,7 +1336,7 @@ static void relativePointerHandleRelativeMotion(void* userData, wl_fixed_t dxUnaccel, wl_fixed_t dyUnaccel) { - _GLFWwindow* window = userData; + _GLFWwindow* window = data; double xpos = window->virtualCursorPosX; double ypos = window->virtualCursorPosY; @@ -2895,104 +1357,89 @@ static void relativePointerHandleRelativeMotion(void* userData, _glfwInputCursorPos(window, xpos, ypos); } -static const struct zwp_relative_pointer_v1_listener relativePointerListener = -{ +static const struct zwp_relative_pointer_v1_listener relativePointerListener = { relativePointerHandleRelativeMotion }; -static void lockedPointerHandleLocked(void* userData, +static void lockedPointerHandleLocked(void* data, struct zwp_locked_pointer_v1* lockedPointer) { } -static void lockedPointerHandleUnlocked(void* userData, +static void unlockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer = + window->wl.pointerLock.relativePointer; + struct zwp_locked_pointer_v1* lockedPointer = + window->wl.pointerLock.lockedPointer; + + zwp_relative_pointer_v1_destroy(relativePointer); + zwp_locked_pointer_v1_destroy(lockedPointer); + + window->wl.pointerLock.relativePointer = NULL; + window->wl.pointerLock.lockedPointer = NULL; +} + +static void lockPointer(_GLFWwindow* window); + +static void lockedPointerHandleUnlocked(void* data, struct zwp_locked_pointer_v1* lockedPointer) { } -static const struct zwp_locked_pointer_v1_listener lockedPointerListener = -{ +static const struct zwp_locked_pointer_v1_listener lockedPointerListener = { lockedPointerHandleLocked, lockedPointerHandleUnlocked }; static void lockPointer(_GLFWwindow* window) { + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + if (!_glfw.wl.relativePointerManager) { - _glfwInputError(GLFW_FEATURE_UNAVAILABLE, - "Wayland: The compositor does not support pointer locking"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: no relative pointer manager"); return; } - window->wl.relativePointer = + relativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer( _glfw.wl.relativePointerManager, _glfw.wl.pointer); - zwp_relative_pointer_v1_add_listener(window->wl.relativePointer, + zwp_relative_pointer_v1_add_listener(relativePointer, &relativePointerListener, window); - window->wl.lockedPointer = + lockedPointer = zwp_pointer_constraints_v1_lock_pointer( _glfw.wl.pointerConstraints, window->wl.surface, _glfw.wl.pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); - zwp_locked_pointer_v1_add_listener(window->wl.lockedPointer, + zwp_locked_pointer_v1_add_listener(lockedPointer, &lockedPointerListener, window); + + window->wl.pointerLock.relativePointer = relativePointer; + window->wl.pointerLock.lockedPointer = lockedPointer; + + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, + NULL, 0, 0); } -static void unlockPointer(_GLFWwindow* window) +static GLFWbool isPointerLocked(_GLFWwindow* window) { - zwp_relative_pointer_v1_destroy(window->wl.relativePointer); - window->wl.relativePointer = NULL; - - zwp_locked_pointer_v1_destroy(window->wl.lockedPointer); - window->wl.lockedPointer = NULL; + return window->wl.pointerLock.lockedPointer != NULL; } -static void confinedPointerHandleConfined(void* userData, - struct zwp_confined_pointer_v1* confinedPointer) +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { -} + struct wl_cursor* defaultCursor; + struct wl_cursor* defaultCursorHiDPI = NULL; -static void confinedPointerHandleUnconfined(void* userData, - struct zwp_confined_pointer_v1* confinedPointer) -{ -} - -static const struct zwp_confined_pointer_v1_listener confinedPointerListener = -{ - confinedPointerHandleConfined, - confinedPointerHandleUnconfined -}; - -static void confinePointer(_GLFWwindow* window) -{ - window->wl.confinedPointer = - zwp_pointer_constraints_v1_confine_pointer( - _glfw.wl.pointerConstraints, - window->wl.surface, - _glfw.wl.pointer, - NULL, - ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); - - zwp_confined_pointer_v1_add_listener(window->wl.confinedPointer, - &confinedPointerListener, - window); -} - -static void unconfinePointer(_GLFWwindow* window) -{ - zwp_confined_pointer_v1_destroy(window->wl.confinedPointer); - window->wl.confinedPointer = NULL; -} - -void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor) -{ if (!_glfw.wl.pointer) return; @@ -3000,58 +1447,32 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor) // If we're not in the correct window just save the cursor // the next time the pointer enters the window the cursor will change - if (!window->wl.hovered) + if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow) return; - // Update pointer lock to match cursor mode - if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - if (window->wl.confinedPointer) - unconfinePointer(window); - if (!window->wl.lockedPointer) - lockPointer(window); - } - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - { - if (window->wl.lockedPointer) - unlockPointer(window); - if (!window->wl.confinedPointer) - confinePointer(window); - } - else if (window->cursorMode == GLFW_CURSOR_NORMAL || - window->cursorMode == GLFW_CURSOR_HIDDEN) - { - if (window->wl.lockedPointer) - unlockPointer(window); - else if (window->wl.confinedPointer) - unconfinePointer(window); - } + // Unlock possible pointer lock if no longer disabled. + if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) + unlockPointer(window); - if (window->cursorMode == GLFW_CURSOR_NORMAL || - window->cursorMode == GLFW_CURSOR_CAPTURED) + if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (cursor) setCursorImage(window, &cursor->wl); else { - struct wl_cursor* defaultCursor = - wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr"); + defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, + "left_ptr"); if (!defaultCursor) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Standard cursor not found"); return; } - - struct wl_cursor* defaultCursorHiDPI = NULL; if (_glfw.wl.cursorThemeHiDPI) - { defaultCursorHiDPI = - wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, "left_ptr"); - } - - _GLFWcursorWayland cursorWayland = - { + wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, + "left_ptr"); + _GLFWcursorWayland cursorWayland = { defaultCursor, defaultCursorHiDPI, NULL, @@ -3059,22 +1480,25 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor) 0, 0, 0 }; - setCursorImage(window, &cursorWayland); } } - else if (window->cursorMode == GLFW_CURSOR_HIDDEN || - window->cursorMode == GLFW_CURSOR_DISABLED) + else if (window->cursorMode == GLFW_CURSOR_DISABLED) { - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0); + if (!isPointerLocked(window)) + lockPointer(window); + } + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0); } } -static void dataSourceHandleTarget(void* userData, - struct wl_data_source* source, +static void dataSourceHandleTarget(void* data, + struct wl_data_source* dataSource, const char* mimeType) { - if (_glfw.wl.selectionSource != source) + if (_glfw.wl.dataSource != dataSource) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Unknown clipboard data source"); @@ -3082,115 +1506,200 @@ static void dataSourceHandleTarget(void* userData, } } -static void dataSourceHandleSend(void* userData, - struct wl_data_source* source, +static void dataSourceHandleSend(void* data, + struct wl_data_source* dataSource, const char* mimeType, int fd) { - // Ignore it if this is an outdated or invalid request - if (_glfw.wl.selectionSource != source || - strcmp(mimeType, "text/plain;charset=utf-8") != 0) + const char* string = _glfw.wl.clipboardSendString; + size_t len = _glfw.wl.clipboardSendSize; + int ret; + + if (_glfw.wl.dataSource != dataSource) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unknown clipboard data source"); + return; + } + + if (!string) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Copy requested from an invalid string"); + return; + } + + if (strcmp(mimeType, "text/plain;charset=utf-8") != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Wrong MIME type asked from clipboard"); close(fd); return; } - char* string = _glfw.wl.clipboardString; - size_t length = strlen(string); - - while (length > 0) + while (len > 0) { - const ssize_t result = write(fd, string, length); - if (result == -1) + ret = write(fd, string, len); + if (ret == -1 && errno == EINTR) + continue; + if (ret == -1) { - if (errno == EINTR) - continue; - + // TODO: also report errno maybe. _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Error while writing the clipboard: %s", - strerror(errno)); - break; + "Wayland: Error while writing the clipboard"); + close(fd); + return; } - - length -= result; - string += result; + len -= ret; } - close(fd); } -static void dataSourceHandleCancelled(void* userData, - struct wl_data_source* source) +static void dataSourceHandleCancelled(void* data, + struct wl_data_source* dataSource) { - wl_data_source_destroy(source); + wl_data_source_destroy(dataSource); - if (_glfw.wl.selectionSource != source) + if (_glfw.wl.dataSource != dataSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unknown clipboard data source"); return; + } - _glfw.wl.selectionSource = NULL; + _glfw.wl.dataSource = NULL; } -static const struct wl_data_source_listener dataSourceListener = -{ +static const struct wl_data_source_listener dataSourceListener = { dataSourceHandleTarget, dataSourceHandleSend, dataSourceHandleCancelled, }; -void _glfwSetClipboardStringWayland(const char* string) +void _glfwPlatformSetClipboardString(const char* string) { - if (_glfw.wl.selectionSource) + if (_glfw.wl.dataSource) { - wl_data_source_destroy(_glfw.wl.selectionSource); - _glfw.wl.selectionSource = NULL; + wl_data_source_destroy(_glfw.wl.dataSource); + _glfw.wl.dataSource = NULL; } - char* copy = _glfw_strdup(string); - if (!copy) + if (_glfw.wl.clipboardSendString) { - _glfwInputError(GLFW_OUT_OF_MEMORY, NULL); - return; + free(_glfw.wl.clipboardSendString); + _glfw.wl.clipboardSendString = NULL; } - _glfw_free(_glfw.wl.clipboardString); - _glfw.wl.clipboardString = copy; - - _glfw.wl.selectionSource = - wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager); - if (!_glfw.wl.selectionSource) + _glfw.wl.clipboardSendString = strdup(string); + if (!_glfw.wl.clipboardSendString) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create clipboard data source"); + "Wayland: Impossible to allocate clipboard string"); return; } - wl_data_source_add_listener(_glfw.wl.selectionSource, + _glfw.wl.clipboardSendSize = strlen(string); + _glfw.wl.dataSource = + wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager); + if (!_glfw.wl.dataSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to create clipboard source"); + free(_glfw.wl.clipboardSendString); + return; + } + wl_data_source_add_listener(_glfw.wl.dataSource, &dataSourceListener, NULL); - wl_data_source_offer(_glfw.wl.selectionSource, "text/plain;charset=utf-8"); + wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8"); wl_data_device_set_selection(_glfw.wl.dataDevice, - _glfw.wl.selectionSource, + _glfw.wl.dataSource, _glfw.wl.serial); } -const char* _glfwGetClipboardStringWayland(void) +static GLFWbool growClipboardString(void) { - if (!_glfw.wl.selectionOffer) + char* clipboard = _glfw.wl.clipboardString; + + clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2); + if (!clipboard) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to grow clipboard string"); + return GLFW_FALSE; + } + _glfw.wl.clipboardString = clipboard; + _glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2; + return GLFW_TRUE; +} + +const char* _glfwPlatformGetClipboardString(void) +{ + int fds[2]; + int ret; + size_t len = 0; + + if (!_glfw.wl.dataOffer) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, - "Wayland: No clipboard data available"); + "No clipboard data has been sent yet"); return NULL; } - if (_glfw.wl.selectionSource) - return _glfw.wl.clipboardString; + ret = pipe2(fds, O_CLOEXEC); + if (ret < 0) + { + // TODO: also report errno maybe? + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to create clipboard pipe fds"); + return NULL; + } - _glfw_free(_glfw.wl.clipboardString); - _glfw.wl.clipboardString = - readDataOfferAsString(_glfw.wl.selectionOffer, "text/plain;charset=utf-8"); + wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]); + close(fds[1]); + + // XXX: this is a huge hack, this function shouldn’t be synchronous! + handleEvents(-1); + + while (1) + { + // Grow the clipboard if we need to paste something bigger, there is no + // shrink operation yet. + if (len + 4096 > _glfw.wl.clipboardSize) + { + if (!growClipboardString()) + { + close(fds[0]); + return NULL; + } + } + + // Then read from the fd to the clipboard, handling all known errors. + ret = read(fds[0], _glfw.wl.clipboardString + len, 4096); + if (ret == 0) + break; + if (ret == -1 && errno == EINTR) + continue; + if (ret == -1) + { + // TODO: also report errno maybe. + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to read from clipboard fd"); + close(fds[0]); + return NULL; + } + len += ret; + } + close(fds[0]); + if (len + 1 > _glfw.wl.clipboardSize) + { + if (!growClipboardString()) + return NULL; + } + _glfw.wl.clipboardString[len] = '\0'; return _glfw.wl.clipboardString; } -EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_wayland) return EGL_PLATFORM_WAYLAND_EXT; @@ -3198,17 +1707,17 @@ EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs) return 0; } -EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void) +EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void) { return _glfw.wl.display; } -EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window) +EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window) { - return window->wl.egl.window; + return window->wl.native; } -void _glfwGetRequiredInstanceExtensionsWayland(char** extensions) +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface) return; @@ -3217,9 +1726,9 @@ void _glfwGetRequiredInstanceExtensionsWayland(char** extensions) extensions[1] = "VK_KHR_wayland_surface"; } -GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = @@ -3237,10 +1746,10 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, _glfw.wl.display); } -VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { VkResult err; VkWaylandSurfaceCreateInfoKHR sci; @@ -3279,14 +1788,6 @@ VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, GLFWAPI struct wl_display* glfwGetWaylandDisplay(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "Wayland: Platform not initialized"); - return NULL; - } - return _glfw.wl.display; } @@ -3294,16 +1795,6 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "Wayland: Platform not initialized"); - return NULL; - } - return window->wl.surface; } -#endif // _GLFW_WAYLAND - diff --git a/raylib/external/glfw/src/x11_init.c b/raylib/external/glfw/src/x11_init.c index 000bde2..dd24f11 100644 --- a/raylib/external/glfw/src/x11_init.c +++ b/raylib/external/glfw/src/x11_init.c @@ -1,9 +1,8 @@ //======================================================================== -// GLFW 3.4 X11 (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -25,20 +24,17 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_X11) - #include #include #include #include #include #include -#include -#include -#include // Translate the X11 KeySyms for a key to a GLFW key code @@ -211,9 +207,9 @@ static int translateKeySyms(const KeySym* keysyms, int width) // Create key code translation tables // -static void createKeyTablesX11(void) +static void createKeyTables(void) { - int scancodeMin, scancodeMax; + int scancode, scancodeMin, scancodeMax; memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); @@ -359,7 +355,7 @@ static void createKeyTablesX11(void) }; // Find the X11 key code -> GLFW key code mapping - for (int scancode = scancodeMin; scancode <= scancodeMax; scancode++) + for (scancode = scancodeMin; scancode <= scancodeMax; scancode++) { int key = GLFW_KEY_UNKNOWN; @@ -418,7 +414,7 @@ static void createKeyTablesX11(void) scancodeMax - scancodeMin + 1, &width); - for (int scancode = scancodeMin; scancode <= scancodeMax; scancode++) + for (scancode = scancodeMin; scancode <= scancodeMax; scancode++) { // Translate the un-translated key codes using traditional X11 KeySym // lookups @@ -605,21 +601,17 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { -#if defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so"); -#else - _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1"); -#endif + _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1"); if (_glfw.x11.vidmode.handle) { _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp) - _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp) - _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize) - _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); _glfw.x11.vidmode.available = XF86VidModeQueryExtension(_glfw.x11.display, @@ -628,18 +620,16 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so"); + _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); #else - _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6"); + _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); #endif if (_glfw.x11.xi.handle) { _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) - _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XIQueryVersion"); + _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) - _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XISelectEvents"); + _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); if (XQueryExtension(_glfw.x11.display, "XInputExtension", @@ -660,50 +650,48 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so"); + _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); #else - _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2"); + _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); #endif if (_glfw.x11.randr.handle) { _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRAllocGamma"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeScreenResources"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputInfo"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryExtension"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryVersion"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSelectInput"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) - _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); if (XRRQueryExtension(_glfw.x11.display, &_glfw.x11.randr.eventBase, @@ -754,43 +742,39 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so"); + _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); #else - _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1"); + _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); #endif if (_glfw.x11.xcursor.handle) { _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) - _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageCreate"); + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) - _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) - _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme) - _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetTheme"); + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme"); _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize) - _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize"); + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize"); _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage) - _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage"); + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage"); } #if defined(__CYGWIN__) - _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so"); + _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); #else - _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1"); + _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); #endif if (_glfw.x11.xinerama.handle) { _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) - _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaIsActive"); + _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); + _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) - _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); + _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); if (XineramaQueryExtension(_glfw.x11.display, &_glfw.x11.xinerama.major, @@ -829,38 +813,30 @@ static GLFWbool initExtensions(void) XkbGroupStateMask, XkbGroupStateMask); } - if (_glfw.hints.init.x11.xcbVulkanSurface) - { #if defined(__CYGWIN__) - _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so"); + _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); #else - _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1"); + _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); #endif - } - if (_glfw.x11.x11xcb.handle) { _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) - _glfwPlatformGetModuleSymbol(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); + _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); } #if defined(__CYGWIN__) - _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so"); + _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); #else - _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1"); + _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); #endif if (_glfw.x11.xrender.handle) { _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryExtension"); + _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) - _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryVersion"); + _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) - _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); + _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); if (XRenderQueryExtension(_glfw.x11.display, &_glfw.x11.xrender.errorBase, @@ -876,22 +852,20 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so"); + _glfw.x11.xshape.handle = _glfw_dlopen("libXext-6.so"); #else - _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6"); + _glfw.x11.xshape.handle = _glfw_dlopen("libXext.so.6"); #endif if (_glfw.x11.xshape.handle) { _glfw.x11.xshape.QueryExtension = (PFN_XShapeQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryExtension"); + _glfw_dlsym(_glfw.x11.xshape.handle, "XShapeQueryExtension"); _glfw.x11.xshape.ShapeCombineRegion = (PFN_XShapeCombineRegion) - _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineRegion"); + _glfw_dlsym(_glfw.x11.xshape.handle, "XShapeCombineRegion"); _glfw.x11.xshape.QueryVersion = (PFN_XShapeQueryVersion) - _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryVersion"); + _glfw_dlsym(_glfw.x11.xshape.handle, "XShapeQueryVersion"); _glfw.x11.xshape.ShapeCombineMask = (PFN_XShapeCombineMask) - _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineMask"); + _glfw_dlsym(_glfw.x11.xshape.handle, "XShapeCombineMask"); if (XShapeQueryExtension(_glfw.x11.display, &_glfw.x11.xshape.errorBase, @@ -909,7 +883,7 @@ static GLFWbool initExtensions(void) // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. - createKeyTablesX11(); + createKeyTables(); // String format atoms _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); @@ -1029,7 +1003,7 @@ static Cursor createHiddenCursor(void) { unsigned char pixels[16 * 16 * 4] = { 0 }; GLFWimage image = { 16, 16, pixels }; - return _glfwCreateNativeCursorX11(&image, 0, 0); + return _glfwCreateCursorX11(&image, 0, 0); } // Create a helper window for IPC @@ -1046,37 +1020,6 @@ static Window createHelperWindow(void) CWEventMask, &wa); } -// Create the pipe for empty events without assumuing the OS has pipe2(2) -// -static GLFWbool createEmptyEventPipe(void) -{ - if (pipe(_glfw.x11.emptyEventPipe) != 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to create empty event pipe: %s", - strerror(errno)); - return GLFW_FALSE; - } - - for (int i = 0; i < 2; i++) - { - const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0); - const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0); - - if (sf == -1 || df == -1 || - fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 || - fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to set flags for empty event pipe: %s", - strerror(errno)); - return GLFW_FALSE; - } - } - - return GLFW_TRUE; -} - // X error handler // static int errorHandler(Display *display, XErrorEvent* event) @@ -1097,9 +1040,8 @@ static int errorHandler(Display *display, XErrorEvent* event) // void _glfwGrabErrorHandlerX11(void) { - assert(_glfw.x11.errorHandler == NULL); _glfw.x11.errorCode = Success; - _glfw.x11.errorHandler = XSetErrorHandler(errorHandler); + XSetErrorHandler(errorHandler); } // Clears the X error handler callback @@ -1108,8 +1050,7 @@ void _glfwReleaseErrorHandlerX11(void) { // Synchronize to make sure all commands are processed XSync(_glfw.x11.display, False); - XSetErrorHandler(_glfw.x11.errorHandler); - _glfw.x11.errorHandler = NULL; + XSetErrorHandler(NULL); } // Reports the specified error, appending information about the last X error @@ -1125,8 +1066,9 @@ void _glfwInputErrorX11(int error, const char* message) // Creates a native cursor object from the specified image and hotspot // -Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot) +Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) { + int i; Cursor cursor; if (!_glfw.x11.xcursor.handle) @@ -1142,7 +1084,7 @@ Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot) unsigned char* source = (unsigned char*) image->pixels; XcursorPixel* target = native->pixels; - for (int i = 0; i < image->width * image->height; i++, target++, source += 4) + for (i = 0; i < image->width * image->height; i++, target++, source += 4) { unsigned int alpha = source[3]; @@ -1163,92 +1105,8 @@ Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) +int _glfwPlatformInit(void) { - const _GLFWplatform x11 = - { - .platformID = GLFW_PLATFORM_X11, - .init = _glfwInitX11, - .terminate = _glfwTerminateX11, - .getCursorPos = _glfwGetCursorPosX11, - .setCursorPos = _glfwSetCursorPosX11, - .setCursorMode = _glfwSetCursorModeX11, - .setRawMouseMotion = _glfwSetRawMouseMotionX11, - .rawMouseMotionSupported = _glfwRawMouseMotionSupportedX11, - .createCursor = _glfwCreateCursorX11, - .createStandardCursor = _glfwCreateStandardCursorX11, - .destroyCursor = _glfwDestroyCursorX11, - .setCursor = _glfwSetCursorX11, - .getScancodeName = _glfwGetScancodeNameX11, - .getKeyScancode = _glfwGetKeyScancodeX11, - .setClipboardString = _glfwSetClipboardStringX11, - .getClipboardString = _glfwGetClipboardStringX11, -#if defined(GLFW_BUILD_LINUX_JOYSTICK) - .initJoysticks = _glfwInitJoysticksLinux, - .terminateJoysticks = _glfwTerminateJoysticksLinux, - .pollJoystick = _glfwPollJoystickLinux, - .getMappingName = _glfwGetMappingNameLinux, - .updateGamepadGUID = _glfwUpdateGamepadGUIDLinux, -#else - .initJoysticks = _glfwInitJoysticksNull, - .terminateJoysticks = _glfwTerminateJoysticksNull, - .pollJoystick = _glfwPollJoystickNull, - .getMappingName = _glfwGetMappingNameNull, - .updateGamepadGUID = _glfwUpdateGamepadGUIDNull, -#endif - .freeMonitor = _glfwFreeMonitorX11, - .getMonitorPos = _glfwGetMonitorPosX11, - .getMonitorContentScale = _glfwGetMonitorContentScaleX11, - .getMonitorWorkarea = _glfwGetMonitorWorkareaX11, - .getVideoModes = _glfwGetVideoModesX11, - .getVideoMode = _glfwGetVideoModeX11, - .getGammaRamp = _glfwGetGammaRampX11, - .setGammaRamp = _glfwSetGammaRampX11, - .createWindow = _glfwCreateWindowX11, - .destroyWindow = _glfwDestroyWindowX11, - .setWindowTitle = _glfwSetWindowTitleX11, - .setWindowIcon = _glfwSetWindowIconX11, - .getWindowPos = _glfwGetWindowPosX11, - .setWindowPos = _glfwSetWindowPosX11, - .getWindowSize = _glfwGetWindowSizeX11, - .setWindowSize = _glfwSetWindowSizeX11, - .setWindowSizeLimits = _glfwSetWindowSizeLimitsX11, - .setWindowAspectRatio = _glfwSetWindowAspectRatioX11, - .getFramebufferSize = _glfwGetFramebufferSizeX11, - .getWindowFrameSize = _glfwGetWindowFrameSizeX11, - .getWindowContentScale = _glfwGetWindowContentScaleX11, - .iconifyWindow = _glfwIconifyWindowX11, - .restoreWindow = _glfwRestoreWindowX11, - .maximizeWindow = _glfwMaximizeWindowX11, - .showWindow = _glfwShowWindowX11, - .hideWindow = _glfwHideWindowX11, - .requestWindowAttention = _glfwRequestWindowAttentionX11, - .focusWindow = _glfwFocusWindowX11, - .setWindowMonitor = _glfwSetWindowMonitorX11, - .windowFocused = _glfwWindowFocusedX11, - .windowIconified = _glfwWindowIconifiedX11, - .windowVisible = _glfwWindowVisibleX11, - .windowMaximized = _glfwWindowMaximizedX11, - .windowHovered = _glfwWindowHoveredX11, - .framebufferTransparent = _glfwFramebufferTransparentX11, - .getWindowOpacity = _glfwGetWindowOpacityX11, - .setWindowResizable = _glfwSetWindowResizableX11, - .setWindowDecorated = _glfwSetWindowDecoratedX11, - .setWindowFloating = _glfwSetWindowFloatingX11, - .setWindowOpacity = _glfwSetWindowOpacityX11, - .setWindowMousePassthrough = _glfwSetWindowMousePassthroughX11, - .pollEvents = _glfwPollEventsX11, - .waitEvents = _glfwWaitEventsX11, - .waitEventsTimeout = _glfwWaitEventsTimeoutX11, - .postEmptyEvent = _glfwPostEmptyEventX11, - .getEGLPlatform = _glfwGetEGLPlatformX11, - .getEGLNativeDisplay = _glfwGetEGLNativeDisplayX11, - .getEGLNativeWindow = _glfwGetEGLNativeWindowX11, - .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsX11, - .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportX11, - .createWindowSurface = _glfwCreateWindowSurfaceX11 - }; - // HACK: If the application has left the locale as "C" then both wide // character text input and explicit UTF-8 input via XIM will break // This sets the CTYPE part of the current locale from the environment @@ -1257,280 +1115,251 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) setlocale(LC_CTYPE, ""); #if defined(__CYGWIN__) - void* module = _glfwPlatformLoadModule("libX11-6.so"); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - void* module = _glfwPlatformLoadModule("libX11.so"); + _glfw.x11.xlib.handle = _glfw_dlopen("libX11-6.so"); #else - void* module = _glfwPlatformLoadModule("libX11.so.6"); + _glfw.x11.xlib.handle = _glfw_dlopen("libX11.so.6"); #endif - if (!module) + if (!_glfw.x11.xlib.handle) { - if (platformID == GLFW_PLATFORM_X11) - _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib"); - + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib"); return GLFW_FALSE; } - PFN_XInitThreads XInitThreads = (PFN_XInitThreads) - _glfwPlatformGetModuleSymbol(module, "XInitThreads"); - PFN_XrmInitialize XrmInitialize = (PFN_XrmInitialize) - _glfwPlatformGetModuleSymbol(module, "XrmInitialize"); - PFN_XOpenDisplay XOpenDisplay = (PFN_XOpenDisplay) - _glfwPlatformGetModuleSymbol(module, "XOpenDisplay"); - if (!XInitThreads || !XrmInitialize || !XOpenDisplay) - { - if (platformID == GLFW_PLATFORM_X11) - _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib entry point"); + _glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint) + _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocClassHint"); + _glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints) + _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocSizeHints"); + _glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints) + _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocWMHints"); + _glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty) + _glfw_dlsym(_glfw.x11.xlib.handle, "XChangeProperty"); + _glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes) + _glfw_dlsym(_glfw.x11.xlib.handle, "XChangeWindowAttributes"); + _glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCheckIfEvent"); + _glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent"); + _glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCloseDisplay"); + _glfw.x11.xlib.CloseIM = (PFN_XCloseIM) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCloseIM"); + _glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection) + _glfw_dlsym(_glfw.x11.xlib.handle, "XConvertSelection"); + _glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateColormap"); + _glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateFontCursor"); + _glfw.x11.xlib.CreateIC = (PFN_XCreateIC) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateIC"); + _glfw.x11.xlib.CreateRegion = (PFN_XCreateRegion) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateRegion"); + _glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateWindow"); + _glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDefineCursor"); + _glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteContext"); + _glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteProperty"); + _glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyIC"); + _glfw.x11.xlib.DestroyRegion = (PFN_XDestroyRegion) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyRegion"); + _glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyWindow"); + _glfw.x11.xlib.DisplayKeycodes = (PFN_XDisplayKeycodes) + _glfw_dlsym(_glfw.x11.xlib.handle, "XDisplayKeycodes"); + _glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued) + _glfw_dlsym(_glfw.x11.xlib.handle, "XEventsQueued"); + _glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFilterEvent"); + _glfw.x11.xlib.FindContext = (PFN_XFindContext) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFindContext"); + _glfw.x11.xlib.Flush = (PFN_XFlush) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFlush"); + _glfw.x11.xlib.Free = (PFN_XFree) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFree"); + _glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeColormap"); + _glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeCursor"); + _glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData) + _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeEventData"); + _glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetErrorText"); + _glfw.x11.xlib.GetEventData = (PFN_XGetEventData) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetEventData"); + _glfw.x11.xlib.GetICValues = (PFN_XGetICValues) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetICValues"); + _glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetIMValues"); + _glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetInputFocus"); + _glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetKeyboardMapping"); + _glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetScreenSaver"); + _glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetSelectionOwner"); + _glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetVisualInfo"); + _glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWMNormalHints"); + _glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowAttributes"); + _glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowProperty"); + _glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer) + _glfw_dlsym(_glfw.x11.xlib.handle, "XGrabPointer"); + _glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XIconifyWindow"); + _glfw.x11.xlib.InitThreads = (PFN_XInitThreads) + _glfw_dlsym(_glfw.x11.xlib.handle, "XInitThreads"); + _glfw.x11.xlib.InternAtom = (PFN_XInternAtom) + _glfw_dlsym(_glfw.x11.xlib.handle, "XInternAtom"); + _glfw.x11.xlib.LookupString = (PFN_XLookupString) + _glfw_dlsym(_glfw.x11.xlib.handle, "XLookupString"); + _glfw.x11.xlib.MapRaised = (PFN_XMapRaised) + _glfw_dlsym(_glfw.x11.xlib.handle, "XMapRaised"); + _glfw.x11.xlib.MapWindow = (PFN_XMapWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XMapWindow"); + _glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XMoveResizeWindow"); + _glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XMoveWindow"); + _glfw.x11.xlib.NextEvent = (PFN_XNextEvent) + _glfw_dlsym(_glfw.x11.xlib.handle, "XNextEvent"); + _glfw.x11.xlib.OpenDisplay = (PFN_XOpenDisplay) + _glfw_dlsym(_glfw.x11.xlib.handle, "XOpenDisplay"); + _glfw.x11.xlib.OpenIM = (PFN_XOpenIM) + _glfw_dlsym(_glfw.x11.xlib.handle, "XOpenIM"); + _glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent) + _glfw_dlsym(_glfw.x11.xlib.handle, "XPeekEvent"); + _glfw.x11.xlib.Pending = (PFN_XPending) + _glfw_dlsym(_glfw.x11.xlib.handle, "XPending"); + _glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension) + _glfw_dlsym(_glfw.x11.xlib.handle, "XQueryExtension"); + _glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer) + _glfw_dlsym(_glfw.x11.xlib.handle, "XQueryPointer"); + _glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XRaiseWindow"); + _glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback) + _glfw_dlsym(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback"); + _glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XResizeWindow"); + _glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString) + _glfw_dlsym(_glfw.x11.xlib.handle, "XResourceManagerString"); + _glfw.x11.xlib.SaveContext = (PFN_XSaveContext) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSaveContext"); + _glfw.x11.xlib.SelectInput = (PFN_XSelectInput) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSelectInput"); + _glfw.x11.xlib.SendEvent = (PFN_XSendEvent) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSendEvent"); + _glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetClassHint"); + _glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetErrorHandler"); + _glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetICFocus"); + _glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetIMValues"); + _glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetInputFocus"); + _glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetLocaleModifiers"); + _glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetScreenSaver"); + _glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetSelectionOwner"); + _glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMHints"); + _glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMNormalHints"); + _glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMProtocols"); + _glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSupportsLocale"); + _glfw.x11.xlib.Sync = (PFN_XSync) + _glfw_dlsym(_glfw.x11.xlib.handle, "XSync"); + _glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates) + _glfw_dlsym(_glfw.x11.xlib.handle, "XTranslateCoordinates"); + _glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor) + _glfw_dlsym(_glfw.x11.xlib.handle, "XUndefineCursor"); + _glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer) + _glfw_dlsym(_glfw.x11.xlib.handle, "XUngrabPointer"); + _glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow) + _glfw_dlsym(_glfw.x11.xlib.handle, "XUnmapWindow"); + _glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus) + _glfw_dlsym(_glfw.x11.xlib.handle, "XUnsetICFocus"); + _glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual) + _glfw_dlsym(_glfw.x11.xlib.handle, "XVisualIDFromVisual"); + _glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer) + _glfw_dlsym(_glfw.x11.xlib.handle, "XWarpPointer"); + _glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeKeyboard"); + _glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeNames"); + _glfw.x11.xkb.GetMap = (PFN_XkbGetMap) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetMap"); + _glfw.x11.xkb.GetNames = (PFN_XkbGetNames) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetNames"); + _glfw.x11.xkb.GetState = (PFN_XkbGetState) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetState"); + _glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym"); + _glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbQueryExtension"); + _glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbSelectEventDetails"); + _glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat) + _glfw_dlsym(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat"); + _glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase) + _glfw_dlsym(_glfw.x11.xlib.handle, "XrmDestroyDatabase"); + _glfw.x11.xrm.GetResource = (PFN_XrmGetResource) + _glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetResource"); + _glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase) + _glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetStringDatabase"); + _glfw.x11.xrm.Initialize = (PFN_XrmInitialize) + _glfw_dlsym(_glfw.x11.xlib.handle, "XrmInitialize"); + _glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark) + _glfw_dlsym(_glfw.x11.xlib.handle, "XrmUniqueQuark"); + _glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback) + _glfw_dlsym(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback"); + _glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString) + _glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8LookupString"); + _glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties) + _glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8SetWMProperties"); - _glfwPlatformFreeModule(module); - return GLFW_FALSE; - } + if (_glfw.x11.xlib.utf8LookupString && _glfw.x11.xlib.utf8SetWMProperties) + _glfw.x11.xlib.utf8 = GLFW_TRUE; XInitThreads(); XrmInitialize(); - Display* display = XOpenDisplay(NULL); - if (!display) + _glfw.x11.display = XOpenDisplay(NULL); + if (!_glfw.x11.display) { - if (platformID == GLFW_PLATFORM_X11) + const char* display = getenv("DISPLAY"); + if (display) { - const char* name = getenv("DISPLAY"); - if (name) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "X11: Failed to open display %s", name); - } - else - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, - "X11: The DISPLAY environment variable is missing"); - } + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to open display %s", display); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The DISPLAY environment variable is missing"); } - _glfwPlatformFreeModule(module); return GLFW_FALSE; } - _glfw.x11.display = display; - _glfw.x11.xlib.handle = module; - - *platform = x11; - return GLFW_TRUE; -} - -int _glfwInitX11(void) -{ - _glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocClassHint"); - _glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocSizeHints"); - _glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocWMHints"); - _glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XChangeProperty"); - _glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XChangeWindowAttributes"); - _glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCheckIfEvent"); - _glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent"); - _glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCloseDisplay"); - _glfw.x11.xlib.CloseIM = (PFN_XCloseIM) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCloseIM"); - _glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XConvertSelection"); - _glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateColormap"); - _glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateFontCursor"); - _glfw.x11.xlib.CreateIC = (PFN_XCreateIC) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateIC"); - _glfw.x11.xlib.CreateRegion = (PFN_XCreateRegion) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateRegion"); - _glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateWindow"); - _glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDefineCursor"); - _glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDeleteContext"); - _glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDeleteProperty"); - _glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyIC"); - _glfw.x11.xlib.DestroyRegion = (PFN_XDestroyRegion) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyRegion"); - _glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyWindow"); - _glfw.x11.xlib.DisplayKeycodes = (PFN_XDisplayKeycodes) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDisplayKeycodes"); - _glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XEventsQueued"); - _glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFilterEvent"); - _glfw.x11.xlib.FindContext = (PFN_XFindContext) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFindContext"); - _glfw.x11.xlib.Flush = (PFN_XFlush) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFlush"); - _glfw.x11.xlib.Free = (PFN_XFree) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFree"); - _glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeColormap"); - _glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeCursor"); - _glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeEventData"); - _glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetErrorText"); - _glfw.x11.xlib.GetEventData = (PFN_XGetEventData) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetEventData"); - _glfw.x11.xlib.GetICValues = (PFN_XGetICValues) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetICValues"); - _glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetIMValues"); - _glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetInputFocus"); - _glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetKeyboardMapping"); - _glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetScreenSaver"); - _glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetSelectionOwner"); - _glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetVisualInfo"); - _glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWMNormalHints"); - _glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWindowAttributes"); - _glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWindowProperty"); - _glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGrabPointer"); - _glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XIconifyWindow"); - _glfw.x11.xlib.InternAtom = (PFN_XInternAtom) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XInternAtom"); - _glfw.x11.xlib.LookupString = (PFN_XLookupString) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XLookupString"); - _glfw.x11.xlib.MapRaised = (PFN_XMapRaised) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMapRaised"); - _glfw.x11.xlib.MapWindow = (PFN_XMapWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMapWindow"); - _glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMoveResizeWindow"); - _glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMoveWindow"); - _glfw.x11.xlib.NextEvent = (PFN_XNextEvent) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XNextEvent"); - _glfw.x11.xlib.OpenIM = (PFN_XOpenIM) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XOpenIM"); - _glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XPeekEvent"); - _glfw.x11.xlib.Pending = (PFN_XPending) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XPending"); - _glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XQueryExtension"); - _glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XQueryPointer"); - _glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XRaiseWindow"); - _glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback"); - _glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XResizeWindow"); - _glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XResourceManagerString"); - _glfw.x11.xlib.SaveContext = (PFN_XSaveContext) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSaveContext"); - _glfw.x11.xlib.SelectInput = (PFN_XSelectInput) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSelectInput"); - _glfw.x11.xlib.SendEvent = (PFN_XSendEvent) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSendEvent"); - _glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetClassHint"); - _glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetErrorHandler"); - _glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetICFocus"); - _glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetIMValues"); - _glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetInputFocus"); - _glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetLocaleModifiers"); - _glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetScreenSaver"); - _glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetSelectionOwner"); - _glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMHints"); - _glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMNormalHints"); - _glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMProtocols"); - _glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSupportsLocale"); - _glfw.x11.xlib.Sync = (PFN_XSync) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSync"); - _glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XTranslateCoordinates"); - _glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUndefineCursor"); - _glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUngrabPointer"); - _glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnmapWindow"); - _glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnsetICFocus"); - _glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XVisualIDFromVisual"); - _glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XWarpPointer"); - _glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbFreeKeyboard"); - _glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbFreeNames"); - _glfw.x11.xkb.GetMap = (PFN_XkbGetMap) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetMap"); - _glfw.x11.xkb.GetNames = (PFN_XkbGetNames) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetNames"); - _glfw.x11.xkb.GetState = (PFN_XkbGetState) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetState"); - _glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym"); - _glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbQueryExtension"); - _glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbSelectEventDetails"); - _glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat"); - _glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmDestroyDatabase"); - _glfw.x11.xrm.GetResource = (PFN_XrmGetResource) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmGetResource"); - _glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmGetStringDatabase"); - _glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmUniqueQuark"); - _glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback"); - _glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8LookupString"); - _glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties) - _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8SetWMProperties"); - - if (_glfw.x11.xlib.utf8LookupString && _glfw.x11.xlib.utf8SetWMProperties) - _glfw.x11.xlib.utf8 = GLFW_TRUE; - _glfw.x11.screen = DefaultScreen(_glfw.x11.display); _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); _glfw.x11.context = XUniqueContext(); getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); - if (!createEmptyEventPipe()) - return GLFW_FALSE; - if (!initExtensions()) return GLFW_FALSE; @@ -1548,11 +1377,13 @@ int _glfwInitX11(void) NULL); } + _glfwInitTimerPOSIX(); + _glfwPollMonitorsX11(); return GLFW_TRUE; } -void _glfwTerminateX11(void) +void _glfwPlatformTerminate(void) { if (_glfw.x11.helperWindowHandle) { @@ -1572,8 +1403,8 @@ void _glfwTerminateX11(void) _glfw.x11.hiddenCursorHandle = (Cursor) 0; } - _glfw_free(_glfw.x11.primarySelectionString); - _glfw_free(_glfw.x11.clipboardString); + free(_glfw.x11.primarySelectionString); + free(_glfw.x11.clipboardString); XUnregisterIMInstantiateCallback(_glfw.x11.display, NULL, NULL, NULL, @@ -1594,47 +1425,46 @@ void _glfwTerminateX11(void) if (_glfw.x11.x11xcb.handle) { - _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle); + _glfw_dlclose(_glfw.x11.x11xcb.handle); _glfw.x11.x11xcb.handle = NULL; } if (_glfw.x11.xcursor.handle) { - _glfwPlatformFreeModule(_glfw.x11.xcursor.handle); + _glfw_dlclose(_glfw.x11.xcursor.handle); _glfw.x11.xcursor.handle = NULL; } if (_glfw.x11.randr.handle) { - _glfwPlatformFreeModule(_glfw.x11.randr.handle); + _glfw_dlclose(_glfw.x11.randr.handle); _glfw.x11.randr.handle = NULL; } if (_glfw.x11.xinerama.handle) { - _glfwPlatformFreeModule(_glfw.x11.xinerama.handle); + _glfw_dlclose(_glfw.x11.xinerama.handle); _glfw.x11.xinerama.handle = NULL; } if (_glfw.x11.xrender.handle) { - _glfwPlatformFreeModule(_glfw.x11.xrender.handle); + _glfw_dlclose(_glfw.x11.xrender.handle); _glfw.x11.xrender.handle = NULL; } if (_glfw.x11.vidmode.handle) { - _glfwPlatformFreeModule(_glfw.x11.vidmode.handle); + _glfw_dlclose(_glfw.x11.vidmode.handle); _glfw.x11.vidmode.handle = NULL; } if (_glfw.x11.xi.handle) { - _glfwPlatformFreeModule(_glfw.x11.xi.handle); + _glfw_dlclose(_glfw.x11.xi.handle); _glfw.x11.xi.handle = NULL; } - _glfwTerminateOSMesa(); // NOTE: These need to be unloaded after XCloseDisplay, as they register // cleanup callbacks that get called by that function _glfwTerminateEGL(); @@ -1642,16 +1472,25 @@ void _glfwTerminateX11(void) if (_glfw.x11.xlib.handle) { - _glfwPlatformFreeModule(_glfw.x11.xlib.handle); + _glfw_dlclose(_glfw.x11.xlib.handle); _glfw.x11.xlib.handle = NULL; } - - if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1]) - { - close(_glfw.x11.emptyEventPipe[0]); - close(_glfw.x11.emptyEventPipe[1]); - } } -#endif // _GLFW_X11 +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " X11 GLX EGL OSMesa" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif +#if defined(__linux__) + " evdev" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} diff --git a/raylib/external/glfw/src/x11_monitor.c b/raylib/external/glfw/src/x11_monitor.c index 38af7e0..8de8659 100644 --- a/raylib/external/glfw/src/x11_monitor.c +++ b/raylib/external/glfw/src/x11_monitor.c @@ -24,11 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_X11) - #include #include #include @@ -116,7 +116,7 @@ void _glfwPollMonitorsX11(void) disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { - disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); @@ -209,7 +209,7 @@ void _glfwPollMonitorsX11(void) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } - _glfw_free(disconnected); + free(disconnected); } else { @@ -232,7 +232,7 @@ void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) RRMode native = None; const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); - _glfwGetVideoModeX11(monitor, ¤t); + _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return; @@ -310,11 +310,11 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwFreeMonitorX11(_GLFWmonitor* monitor) +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } -void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { @@ -336,8 +336,8 @@ void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos) } } -void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; @@ -345,9 +345,7 @@ void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, *yscale = _glfw.x11.contentScaleY; } -void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor, - int* xpos, int* ypos, - int* width, int* height) +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0; @@ -439,7 +437,7 @@ void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor, *height = areaHeight; } -GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count) +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { GLFWvidmode* result; @@ -452,7 +450,7 @@ GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count) XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); - result = _glfw_calloc(oi->nmode, sizeof(GLFWvidmode)); + result = calloc(oi->nmode, sizeof(GLFWvidmode)); for (int i = 0; i < oi->nmode; i++) { @@ -484,38 +482,31 @@ GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count) else { *count = 1; - result = _glfw_calloc(1, sizeof(GLFWvidmode)); - _glfwGetVideoModeX11(monitor, result); + result = calloc(1, sizeof(GLFWvidmode)); + _glfwPlatformGetVideoMode(monitor, result); } return result; } -GLFWbool _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode) +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); - const XRRModeInfo* mi = NULL; - XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + if (ci) { - mi = getModeInfo(sr, ci->mode); - if (mi) + const XRRModeInfo* mi = getModeInfo(sr, ci->mode); + if (mi) // mi can be NULL if the monitor has been disconnected *mode = vidmodeFromModeInfo(mi, ci); XRRFreeCrtcInfo(ci); } XRRFreeScreenResources(sr); - - if (!mi) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to query video mode"); - return GLFW_FALSE; - } } else { @@ -526,11 +517,9 @@ GLFWbool _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode) _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), &mode->redBits, &mode->greenBits, &mode->blueBits); } - - return GLFW_TRUE; } -GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { @@ -568,7 +557,7 @@ GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp) } } -void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { @@ -613,13 +602,6 @@ GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); - return None; - } - return monitor->x11.crtc; } @@ -627,15 +609,6 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); - return None; - } - return monitor->x11.output; } -#endif // _GLFW_X11 - diff --git a/raylib/external/glfw/src/x11_platform.h b/raylib/external/glfw/src/x11_platform.h index 14e363d..c5137bc 100644 --- a/raylib/external/glfw/src/x11_platform.h +++ b/raylib/external/glfw/src/x11_platform.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -50,53 +51,6 @@ // The Shape extension provides custom window shapes #include -#define GLX_VENDOR 1 -#define GLX_RGBA_BIT 0x00000001 -#define GLX_WINDOW_BIT 0x00000001 -#define GLX_DRAWABLE_TYPE 0x8010 -#define GLX_RENDER_TYPE 0x8011 -#define GLX_RGBA_TYPE 0x8014 -#define GLX_DOUBLEBUFFER 5 -#define GLX_STEREO 6 -#define GLX_AUX_BUFFERS 7 -#define GLX_RED_SIZE 8 -#define GLX_GREEN_SIZE 9 -#define GLX_BLUE_SIZE 10 -#define GLX_ALPHA_SIZE 11 -#define GLX_DEPTH_SIZE 12 -#define GLX_STENCIL_SIZE 13 -#define GLX_ACCUM_RED_SIZE 14 -#define GLX_ACCUM_GREEN_SIZE 15 -#define GLX_ACCUM_BLUE_SIZE 16 -#define GLX_ACCUM_ALPHA_SIZE 17 -#define GLX_SAMPLES 0x186a1 -#define GLX_VISUAL_ID 0x800b - -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2 -#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define GLX_CONTEXT_FLAGS_ARB 0x2094 -#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 -#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 -#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 -#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 -#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 - -typedef XID GLXWindow; -typedef XID GLXDrawable; -typedef struct __GLXFBConfig* GLXFBConfig; -typedef struct __GLXcontext* GLXContext; -typedef void (*__GLXextproc)(void); - typedef XClassHint* (* PFN_XAllocClassHint)(void); typedef XSizeHints* (* PFN_XAllocSizeHints)(void); typedef XWMHints* (* PFN_XAllocWMHints)(void); @@ -243,6 +197,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char #define XGetWindowProperty _glfw.x11.xlib.GetWindowProperty #define XGrabPointer _glfw.x11.xlib.GrabPointer #define XIconifyWindow _glfw.x11.xlib.IconifyWindow +#define XInitThreads _glfw.x11.xlib.InitThreads #define XInternAtom _glfw.x11.xlib.InternAtom #define XLookupString _glfw.x11.xlib.LookupString #define XMapRaised _glfw.x11.xlib.MapRaised @@ -250,6 +205,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char #define XMoveResizeWindow _glfw.x11.xlib.MoveResizeWindow #define XMoveWindow _glfw.x11.xlib.MoveWindow #define XNextEvent _glfw.x11.xlib.NextEvent +#define XOpenDisplay _glfw.x11.xlib.OpenDisplay #define XOpenIM _glfw.x11.xlib.OpenIM #define XPeekEvent _glfw.x11.xlib.PeekEvent #define XPending _glfw.x11.xlib.Pending @@ -294,6 +250,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char #define XrmDestroyDatabase _glfw.x11.xrm.DestroyDatabase #define XrmGetResource _glfw.x11.xrm.GetResource #define XrmGetStringDatabase _glfw.x11.xrm.GetStringDatabase +#define XrmInitialize _glfw.x11.xrm.Initialize #define XrmUniqueQuark _glfw.x11.xrm.UniqueQuark #define XUnregisterIMInstantiateCallback _glfw.x11.xlib.UnregisterIMInstantiateCallback #define Xutf8LookupString _glfw.x11.xlib.utf8LookupString @@ -391,41 +348,6 @@ typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); #define XShapeCombineRegion _glfw.x11.xshape.ShapeCombineRegion #define XShapeCombineMask _glfw.x11.xshape.ShapeCombineMask -typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); -typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); -typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); -typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*); -typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext); -typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); -typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); -typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); -typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); -typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool); -typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName); -typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); -typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); -typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); -typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); - -typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); -typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); -typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); - -// libGL.so function pointer typedefs -#define glXGetFBConfigs _glfw.glx.GetFBConfigs -#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib -#define glXGetClientString _glfw.glx.GetClientString -#define glXQueryExtension _glfw.glx.QueryExtension -#define glXQueryVersion _glfw.glx.QueryVersion -#define glXDestroyContext _glfw.glx.DestroyContext -#define glXMakeCurrent _glfw.glx.MakeCurrent -#define glXSwapBuffers _glfw.glx.SwapBuffers -#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString -#define glXCreateNewContext _glfw.glx.CreateNewContext -#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig -#define glXCreateWindow _glfw.glx.CreateWindow -#define glXDestroyWindow _glfw.glx.DestroyWindow - typedef VkFlags VkXlibSurfaceCreateFlagsKHR; typedef VkFlags VkXcbSurfaceCreateFlagsKHR; @@ -452,72 +374,26 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(V typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); +#include "posix_thread.h" +#include "posix_time.h" #include "xkb_unicode.h" -#include "posix_poll.h" +#include "glx_context.h" +#if defined(__linux__) +#include "linux_joystick.h" +#else +#include "null_joystick.h" +#endif -#define GLFW_X11_WINDOW_STATE _GLFWwindowX11 x11; -#define GLFW_X11_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11; -#define GLFW_X11_MONITOR_STATE _GLFWmonitorX11 x11; -#define GLFW_X11_CURSOR_STATE _GLFWcursorX11 x11; +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) -#define GLFW_GLX_CONTEXT_STATE _GLFWcontextGLX glx; -#define GLFW_GLX_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx; +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 -// GLX-specific per-context data -// -typedef struct _GLFWcontextGLX -{ - GLXContext handle; - GLXWindow window; -} _GLFWcontextGLX; - -// GLX-specific global data -// -typedef struct _GLFWlibraryGLX -{ - int major, minor; - int eventBase; - int errorBase; - - void* handle; - - // GLX 1.3 functions - PFNGLXGETFBCONFIGSPROC GetFBConfigs; - PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; - PFNGLXGETCLIENTSTRINGPROC GetClientString; - PFNGLXQUERYEXTENSIONPROC QueryExtension; - PFNGLXQUERYVERSIONPROC QueryVersion; - PFNGLXDESTROYCONTEXTPROC DestroyContext; - PFNGLXMAKECURRENTPROC MakeCurrent; - PFNGLXSWAPBUFFERSPROC SwapBuffers; - PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; - PFNGLXCREATENEWCONTEXTPROC CreateNewContext; - PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; - PFNGLXCREATEWINDOWPROC CreateWindow; - PFNGLXDESTROYWINDOWPROC DestroyWindow; - - // GLX 1.4 and extension functions - PFNGLXGETPROCADDRESSPROC GetProcAddress; - PFNGLXGETPROCADDRESSPROC GetProcAddressARB; - PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; - PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; - PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; - PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; - GLFWbool SGI_swap_control; - GLFWbool EXT_swap_control; - GLFWbool MESA_swap_control; - GLFWbool ARB_multisample; - GLFWbool ARB_framebuffer_sRGB; - GLFWbool EXT_framebuffer_sRGB; - GLFWbool ARB_create_context; - GLFWbool ARB_create_context_profile; - GLFWbool ARB_create_context_robustness; - GLFWbool EXT_create_context_es2_profile; - GLFWbool ARB_create_context_no_error; - GLFWbool ARB_context_flush_control; -} _GLFWlibraryGLX; - // X11-specific per-window data // typedef struct _GLFWwindowX11 @@ -546,6 +422,7 @@ typedef struct _GLFWwindowX11 // The time of the last KeyPress event per keycode, for discarding // duplicate key events generated for some keys by ibus Time keyPressTimes[256]; + } _GLFWwindowX11; // X11-specific global data @@ -566,8 +443,6 @@ typedef struct _GLFWlibraryX11 XContext context; // XIM input method XIM im; - // The previous X error handler, to be restored later - XErrorHandler errorHandler; // Most recent error code received by X error handler int errorCode; // Primary selection string (while the primary selection is owned) @@ -584,7 +459,6 @@ typedef struct _GLFWlibraryX11 double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; - int emptyEventPipe[2]; // Window manager atoms Atom NET_SUPPORTED; @@ -689,6 +563,7 @@ typedef struct _GLFWlibraryX11 PFN_XGetWindowProperty GetWindowProperty; PFN_XGrabPointer GrabPointer; PFN_XIconifyWindow IconifyWindow; + PFN_XInitThreads InitThreads; PFN_XInternAtom InternAtom; PFN_XLookupString LookupString; PFN_XMapRaised MapRaised; @@ -696,6 +571,7 @@ typedef struct _GLFWlibraryX11 PFN_XMoveResizeWindow MoveResizeWindow; PFN_XMoveWindow MoveWindow; PFN_XNextEvent NextEvent; + PFN_XOpenDisplay OpenDisplay; PFN_XOpenIM OpenIM; PFN_XPeekEvent PeekEvent; PFN_XPending Pending; @@ -737,6 +613,7 @@ typedef struct _GLFWlibraryX11 PFN_XrmDestroyDatabase DestroyDatabase; PFN_XrmGetResource GetResource; PFN_XrmGetStringDatabase GetStringDatabase; + PFN_XrmInitialize Initialize; PFN_XrmUniqueQuark UniqueQuark; } xrm; @@ -874,6 +751,7 @@ typedef struct _GLFWlibraryX11 PFN_XShapeQueryVersion QueryVersion; PFN_XShapeCombineMask ShapeCombineMask; } xshape; + } _GLFWlibraryX11; // X11-specific per-monitor data @@ -887,6 +765,7 @@ typedef struct _GLFWmonitorX11 // Index of corresponding Xinerama screen, // for EWMH full screen window placement int index; + } _GLFWmonitorX11; // X11-specific per-cursor data @@ -894,89 +773,15 @@ typedef struct _GLFWmonitorX11 typedef struct _GLFWcursorX11 { Cursor handle; + } _GLFWcursorX11; -GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform); -int _glfwInitX11(void); -void _glfwTerminateX11(void); - -GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyWindowX11(_GLFWwindow* window); -void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title); -void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos); -void _glfwSetWindowPosX11(_GLFWwindow* window, int xpos, int ypos); -void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height); -void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height); -void _glfwSetWindowSizeLimitsX11(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); -void _glfwSetWindowAspectRatioX11(_GLFWwindow* window, int numer, int denom); -void _glfwGetFramebufferSizeX11(_GLFWwindow* window, int* width, int* height); -void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); -void _glfwGetWindowContentScaleX11(_GLFWwindow* window, float* xscale, float* yscale); -void _glfwIconifyWindowX11(_GLFWwindow* window); -void _glfwRestoreWindowX11(_GLFWwindow* window); -void _glfwMaximizeWindowX11(_GLFWwindow* window); -void _glfwShowWindowX11(_GLFWwindow* window); -void _glfwHideWindowX11(_GLFWwindow* window); -void _glfwRequestWindowAttentionX11(_GLFWwindow* window); -void _glfwFocusWindowX11(_GLFWwindow* window); -void _glfwSetWindowMonitorX11(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); -GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window); -GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window); -GLFWbool _glfwWindowVisibleX11(_GLFWwindow* window); -GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window); -GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window); -GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window); -void _glfwSetWindowResizableX11(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled); -void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled); -float _glfwGetWindowOpacityX11(_GLFWwindow* window); -void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity); -void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled); - -void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled); -GLFWbool _glfwRawMouseMotionSupportedX11(void); - -void _glfwPollEventsX11(void); -void _glfwWaitEventsX11(void); -void _glfwWaitEventsTimeoutX11(double timeout); -void _glfwPostEmptyEventX11(void); - -void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos); -void _glfwSetCursorPosX11(_GLFWwindow* window, double xpos, double ypos); -void _glfwSetCursorModeX11(_GLFWwindow* window, int mode); -const char* _glfwGetScancodeNameX11(int scancode); -int _glfwGetKeyScancodeX11(int key); -GLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); -GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape); -void _glfwDestroyCursorX11(_GLFWcursor* cursor); -void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor); -void _glfwSetClipboardStringX11(const char* string); -const char* _glfwGetClipboardStringX11(void); - -EGLenum _glfwGetEGLPlatformX11(EGLint** attribs); -EGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void); -EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window); - -void _glfwGetRequiredInstanceExtensionsX11(char** extensions); -GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); -VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -void _glfwFreeMonitorX11(_GLFWmonitor* monitor); -void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos); -void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, float* xscale, float* yscale); -void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); -GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count); -GLFWbool _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode); -GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp); -void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); - void _glfwPollMonitorsX11(void); void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor); -Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot); +Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot); unsigned long _glfwGetWindowPropertyX11(Window window, Atom property, @@ -991,14 +796,3 @@ void _glfwInputErrorX11(int error, const char* message); void _glfwPushSelectionToManagerX11(void); void _glfwCreateInputContextX11(_GLFWwindow* window); -GLFWbool _glfwInitGLX(void); -void _glfwTerminateGLX(void); -GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContextGLX(_GLFWwindow* window); -GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig, - Visual** visual, int* depth); - diff --git a/raylib/external/glfw/src/x11_window.c b/raylib/external/glfw/src/x11_window.c index 49e60a5..4cd3294 100644 --- a/raylib/external/glfw/src/x11_window.c +++ b/raylib/external/glfw/src/x11_window.c @@ -1,9 +1,8 @@ //======================================================================== -// GLFW 3.4 X11 (modified for raylib) - www.glfw.org; www.raylib.com +// GLFW 3.4 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy -// Copyright (c) 2024 M374LX // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -25,15 +24,15 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_X11) - #include #include -#include +#include #include #include @@ -57,80 +56,50 @@ #define _GLFW_XDND_VERSION 5 -// Wait for event data to arrive on the X11 display socket + +// Wait for data to arrive using select // This avoids blocking other threads via the per-display Xlib lock that also // covers GLX functions // -static GLFWbool waitForX11Event(double* timeout) +static GLFWbool waitForEvent(double* timeout) { - struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN }; + fd_set fds; + const int fd = ConnectionNumber(_glfw.x11.display); + int count = fd + 1; - while (!XPending(_glfw.x11.display)) +#if defined(__linux__) + if (_glfw.linjs.inotify > fd) + count = _glfw.linjs.inotify + 1; +#endif + for (;;) { - if (!_glfwPollPOSIX(&fd, 1, timeout)) - return GLFW_FALSE; - } - - return GLFW_TRUE; -} - -// Wait for event data to arrive on any event file descriptor -// This avoids blocking other threads via the per-display Xlib lock that also -// covers GLX functions -// -static GLFWbool waitForAnyEvent(double* timeout) -{ - enum { XLIB_FD, PIPE_FD, INOTIFY_FD }; - struct pollfd fds[] = - { - [XLIB_FD] = { ConnectionNumber(_glfw.x11.display), POLLIN }, - [PIPE_FD] = { _glfw.x11.emptyEventPipe[0], POLLIN }, - [INOTIFY_FD] = { -1, POLLIN } - }; - -#if defined(GLFW_BUILD_LINUX_JOYSTICK) - if (_glfw.joysticksInitialized) - fds[INOTIFY_FD].fd = _glfw.linjs.inotify; + FD_ZERO(&fds); + FD_SET(fd, &fds); +#if defined(__linux__) + if (_glfw.linjs.inotify > 0) + FD_SET(_glfw.linjs.inotify, &fds); #endif - while (!XPending(_glfw.x11.display)) - { - if (!_glfwPollPOSIX(fds, sizeof(fds) / sizeof(fds[0]), timeout)) - return GLFW_FALSE; - - for (int i = 1; i < sizeof(fds) / sizeof(fds[0]); i++) + if (timeout) { - if (fds[i].revents & POLLIN) + const long seconds = (long) *timeout; + const long microseconds = (long) ((*timeout - seconds) * 1e6); + struct timeval tv = { seconds, microseconds }; + const uint64_t base = _glfwPlatformGetTimerValue(); + + const int result = select(count, &fds, NULL, NULL, &tv); + const int error = errno; + + *timeout -= (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); + + if (result > 0) return GLFW_TRUE; + if ((result == -1 && error == EINTR) || *timeout <= 0.0) + return GLFW_FALSE; } - } - - return GLFW_TRUE; -} - -// Writes a byte to the empty event pipe -// -static void writeEmptyEvent(void) -{ - for (;;) - { - const char byte = 0; - const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1); - if (result == 1 || (result == -1 && errno != EINTR)) - break; - } -} - -// Drains available data from the empty event pipe -// -static void drainEmptyEvents(void) -{ - for (;;) - { - char dummy[64]; - const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy)); - if (result == -1 && errno != EINTR) - break; + else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) + return GLFW_TRUE; } } @@ -147,7 +116,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) VisibilityNotify, &dummy)) { - if (!waitForX11Event(&timeout)) + if (!waitForEvent(&timeout)) return GLFW_FALSE; } @@ -236,9 +205,9 @@ static int translateState(int state) // Translates an X11 key code to a GLFW key token // -static int translateKeyX11(int scancode) +static int translateKey(int scancode) { - // Use the pre-filled LUT (see createKeyTablesX11() in x11_init.c) + // Use the pre-filled LUT (see createKeyTables() in x11_init.c) if (scancode < 0 || scancode > 255) return GLFW_KEY_UNKNOWN; @@ -272,11 +241,6 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height) { XSizeHints* hints = XAllocSizeHints(); - long supplied; - XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied); - - hints->flags &= ~(PMinSize | PMaxSize | PAspect); - if (!window->monitor) { if (window->resizable) @@ -313,6 +277,9 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height) } } + hints->flags |= PWinGravity; + hints->win_gravity = StaticGravity; + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); XFree(hints); } @@ -411,13 +378,95 @@ static void updateWindowMode(_GLFWwindow* window) } } +// Splits and translates a text/uri-list into separate file paths +// NOTE: This function destroys the provided string +// +static char** parseUriList(char* text, int* count) +{ + const char* prefix = "file://"; + char** paths = NULL; + char* line; + + *count = 0; + + while ((line = strtok(text, "\r\n"))) + { + text = NULL; + + if (line[0] == '#') + continue; + + if (strncmp(line, prefix, strlen(prefix)) == 0) + { + line += strlen(prefix); + // TODO: Validate hostname + while (*line != '/') + line++; + } + + (*count)++; + + char* path = calloc(strlen(line) + 1, 1); + paths = realloc(paths, *count * sizeof(char*)); + paths[*count - 1] = path; + + while (*line) + { + if (line[0] == '%' && line[1] && line[2]) + { + const char digits[3] = { line[1], line[2], '\0' }; + *path = strtol(digits, NULL, 16); + line += 2; + } + else + *path = *line; + + path++; + line++; + } + } + + return paths; +} + +// Encode a Unicode code point to a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +static size_t encodeUTF8(char* s, unsigned int ch) +{ + size_t count = 0; + + if (ch < 0x80) + s[count++] = (char) ch; + else if (ch < 0x800) + { + s[count++] = (ch >> 6) | 0xc0; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x10000) + { + s[count++] = (ch >> 12) | 0xe0; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x110000) + { + s[count++] = (ch >> 18) | 0xf0; + s[count++] = ((ch >> 12) & 0x3f) | 0x80; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + + return count; +} + // Decode a Unicode code point from a UTF-8 stream // Based on cutef8 by Jeff Bezanson (Public Domain) // -static uint32_t decodeUTF8(const char** s) +static unsigned int decodeUTF8(const char** s) { - uint32_t codepoint = 0, count = 0; - static const uint32_t offsets[] = + unsigned int ch = 0, count = 0; + static const unsigned int offsets[] = { 0x00000000u, 0x00003080u, 0x000e2080u, 0x03c82080u, 0xfa082080u, 0x82082080u @@ -425,13 +474,13 @@ static uint32_t decodeUTF8(const char** s) do { - codepoint = (codepoint << 6) + (unsigned char) **s; + ch = (ch << 6) + (unsigned char) **s; (*s)++; count++; } while ((**s & 0xc0) == 0x80); assert(count <= 6); - return codepoint - offsets[count - 1]; + return ch - offsets[count - 1]; } // Convert the specified Latin-1 string to UTF-8 @@ -444,11 +493,11 @@ static char* convertLatin1toUTF8(const char* source) for (sp = source; *sp; sp++) size += (*sp & 0x80) ? 2 : 1; - char* target = _glfw_calloc(size, 1); + char* target = calloc(size, 1); char* tp = target; for (sp = source; *sp; sp++) - tp += _glfwEncodeUTF8(tp, *sp); + tp += encodeUTF8(tp, *sp); return target; } @@ -457,8 +506,7 @@ static char* convertLatin1toUTF8(const char* source) // static void updateCursorImage(_GLFWwindow* window) { - if (window->cursorMode == GLFW_CURSOR_NORMAL || - window->cursorMode == GLFW_CURSOR_CAPTURED) + if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (window->cursor) { @@ -475,25 +523,6 @@ static void updateCursorImage(_GLFWwindow* window) } } -// Grabs the cursor and confines it to the window -// -static void captureCursor(_GLFWwindow* window) -{ - XGrabPointer(_glfw.x11.display, window->x11.handle, True, - ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - GrabModeAsync, GrabModeAsync, - window->x11.handle, - None, - CurrentTime); -} - -// Ungrabs the cursor -// -static void releaseCursor(void) -{ - XUngrabPointer(_glfw.x11.display, CurrentTime); -} - // Enable XI2 raw mouse motion events // static void enableRawMouseMotion(_GLFWwindow* window) @@ -531,12 +560,17 @@ static void disableCursor(_GLFWwindow* window) enableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = window; - _glfwGetCursorPosX11(window, - &_glfw.x11.restoreCursorPosX, - &_glfw.x11.restoreCursorPosY); + _glfwPlatformGetCursorPos(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window); - captureCursor(window); + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, + _glfw.x11.hiddenCursorHandle, + CurrentTime); } // Exit disabled cursor mode for the specified window @@ -547,10 +581,10 @@ static void enableCursor(_GLFWwindow* window) disableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = NULL; - releaseCursor(); - _glfwSetCursorPosX11(window, - _glfw.x11.restoreCursorPosX, - _glfw.x11.restoreCursorPosY); + XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); updateCursorImage(window); } @@ -577,14 +611,6 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, height *= _glfw.x11.contentScaleY; } - int xpos = 0, ypos = 0; - - if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION) - { - xpos = wndconfig->xpos; - ypos = wndconfig->ypos; - } - // Create a colormap based on the visual used by the current context window->x11.colormap = XCreateColormap(_glfw.x11.display, _glfw.x11.root, @@ -605,7 +631,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, window->x11.parent = _glfw.x11.root; window->x11.handle = XCreateWindow(_glfw.x11.display, _glfw.x11.root, - xpos, ypos, + 0, 0, // Position width, height, 0, // Border width depth, // Color depth @@ -629,7 +655,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, (XPointer) window); if (!wndconfig->decorated) - _glfwSetWindowDecoratedX11(window, GLFW_FALSE); + _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); if (_glfw.x11.NET_WM_STATE && !window->monitor) { @@ -708,37 +734,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, XFree(hints); } - // Set ICCCM WM_NORMAL_HINTS property - { - XSizeHints* hints = XAllocSizeHints(); - if (!hints) - { - _glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate size hints"); - return GLFW_FALSE; - } - - if (!wndconfig->resizable) - { - hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = width; - hints->min_height = hints->max_height = height; - } - - // HACK: Explicitly setting PPosition to any value causes some WMs, notably - // Compiz and Metacity, to honor the position of unmapped windows - if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION) - { - hints->flags |= PPosition; - hints->x = 0; - hints->y = 0; - } - - hints->flags |= PWinGravity; - hints->win_gravity = StaticGravity; - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - XFree(hints); - } + updateNormalHints(window, width, height); // Set ICCCM WM_CLASS property { @@ -781,9 +777,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, if (_glfw.x11.im) _glfwCreateInputContextX11(window); - _glfwSetWindowTitleX11(window, wndconfig->title); - _glfwGetWindowPosX11(window, &window->x11.xpos, &window->x11.ypos); - _glfwGetWindowSizeX11(window, &window->x11.width, &window->x11.height); + _glfwPlatformSetWindowTitle(window, wndconfig->title); + _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); + _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); return GLFW_TRUE; } @@ -792,6 +788,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, // static Atom writeTargetToProperty(const XSelectionRequestEvent* request) { + int i; char* selectionString = NULL; const Atom formats[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const int formatCount = sizeof(formats) / sizeof(formats[0]); @@ -834,13 +831,14 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) // Multiple conversions were requested Atom* targets; - const unsigned long count = - _glfwGetWindowPropertyX11(request->requestor, - request->property, - _glfw.x11.ATOM_PAIR, - (unsigned char**) &targets); + unsigned long i, count; - for (unsigned long i = 0; i < count; i += 2) + count = _glfwGetWindowPropertyX11(request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + (unsigned char**) &targets); + + for (i = 0; i < count; i += 2) { int j; @@ -898,7 +896,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) // Conversion to a data target was requested - for (int i = 0; i < formatCount; i++) + for (i = 0; i < formatCount; i++) { if (request->target == formats[i]) { @@ -922,6 +920,20 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) return None; } +static void handleSelectionClear(XEvent* event) +{ + if (event->xselectionclear.selection == _glfw.x11.PRIMARY) + { + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = NULL; + } + else + { + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; + } +} + static void handleSelectionRequest(XEvent* event) { const XSelectionRequestEvent* request = &event->xselectionrequest; @@ -956,7 +968,7 @@ static const char* getSelectionString(Atom selection) return *selectionString; } - _glfw_free(*selectionString); + free(*selectionString); *selectionString = NULL; for (size_t i = 0; i < targetCount; i++) @@ -979,7 +991,7 @@ static const char* getSelectionString(Atom selection) SelectionNotify, ¬ification)) { - waitForX11Event(NULL); + waitForEvent(NULL); } if (notification.xselection.property == None) @@ -1015,7 +1027,7 @@ static const char* getSelectionString(Atom selection) isSelPropNewValueNotify, (XPointer) ¬ification)) { - waitForX11Event(NULL); + waitForEvent(NULL); } XFree(data); @@ -1035,23 +1047,20 @@ static const char* getSelectionString(Atom selection) if (itemCount) { size += itemCount; - string = _glfw_realloc(string, size); + string = realloc(string, size); string[size - itemCount - 1] = '\0'; strcat(string, data); } if (!itemCount) { - if (string) + if (targets[i] == XA_STRING) { - if (targets[i] == XA_STRING) - { - *selectionString = convertLatin1toUTF8(string); - _glfw_free(string); - } - else - *selectionString = string; + *selectionString = convertLatin1toUTF8(string); + free(string); } + else + *selectionString = string; break; } @@ -1082,7 +1091,7 @@ static const char* getSelectionString(Atom selection) // Make the specified window and its video mode active on its monitor // -static void acquireMonitorX11(_GLFWwindow* window) +static void acquireMonitor(_GLFWwindow* window) { if (_glfw.x11.saver.count == 0) { @@ -1109,8 +1118,8 @@ static void acquireMonitorX11(_GLFWwindow* window) GLFWvidmode mode; // Manually position the window over its monitor - _glfwGetMonitorPosX11(window->monitor, &xpos, &ypos); - _glfwGetVideoModeX11(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, mode.width, mode.height); @@ -1121,7 +1130,7 @@ static void acquireMonitorX11(_GLFWwindow* window) // Remove the window and restore the original video mode // -static void releaseMonitorX11(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; @@ -1217,7 +1226,12 @@ static void processEvent(XEvent *event) return; } - if (event->type == SelectionRequest) + if (event->type == SelectionClear) + { + handleSelectionClear(event); + return; + } + else if (event->type == SelectionRequest) { handleSelectionRequest(event); return; @@ -1243,7 +1257,7 @@ static void processEvent(XEvent *event) case KeyPress: { - const int key = translateKeyX11(keycode); + const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); @@ -1257,7 +1271,7 @@ static void processEvent(XEvent *event) // (the server never sends a timestamp of zero) // NOTE: Timestamp difference is compared to handle wrap-around Time diff = event->xkey.time - window->x11.keyPressTimes[keycode]; - if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31))) + if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31))) { if (keycode) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); @@ -1279,7 +1293,7 @@ static void processEvent(XEvent *event) if (status == XBufferOverflow) { - chars = _glfw_calloc(count + 1, 1); + chars = calloc(count + 1, 1); count = Xutf8LookupString(window->x11.ic, &event->xkey, chars, count, @@ -1295,7 +1309,7 @@ static void processEvent(XEvent *event) } if (chars != buffer) - _glfw_free(chars); + free(chars); } } else @@ -1305,9 +1319,9 @@ static void processEvent(XEvent *event) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - const uint32_t codepoint = _glfwKeySym2Unicode(keysym); - if (codepoint != GLFW_INVALID_CODEPOINT) - _glfwInputChar(window, codepoint, mods, plain); + const long character = _glfwKeySym2Unicode(keysym); + if (character != -1) + _glfwInputChar(window, character, mods, plain); } return; @@ -1315,7 +1329,7 @@ static void processEvent(XEvent *event) case KeyRelease: { - const int key = translateKeyX11(keycode); + const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); if (!_glfw.x11.xkb.detectable) @@ -1489,9 +1503,6 @@ static void processEvent(XEvent *event) if (event->xconfigure.width != window->x11.width || event->xconfigure.height != window->x11.height) { - window->x11.width = event->xconfigure.width; - window->x11.height = event->xconfigure.height; - _glfwInputFramebufferSize(window, event->xconfigure.width, event->xconfigure.height); @@ -1499,6 +1510,9 @@ static void processEvent(XEvent *event) _glfwInputWindowSize(window, event->xconfigure.width, event->xconfigure.height); + + window->x11.width = event->xconfigure.width; + window->x11.height = event->xconfigure.height; } int xpos = event->xconfigure.x; @@ -1526,10 +1540,9 @@ static void processEvent(XEvent *event) if (xpos != window->x11.xpos || ypos != window->x11.ypos) { + _glfwInputWindowPos(window, xpos, ypos); window->x11.xpos = xpos; window->x11.ypos = ypos; - - _glfwInputWindowPos(window, xpos, ypos); } return; @@ -1575,7 +1588,7 @@ static void processEvent(XEvent *event) else if (event->xclient.message_type == _glfw.x11.XdndEnter) { // A drag operation has entered the window - unsigned long count; + unsigned long i, count; Atom* formats = NULL; const GLFWbool list = event->xclient.data.l[1] & 1; @@ -1599,7 +1612,7 @@ static void processEvent(XEvent *event) formats = (Atom*) event->xclient.data.l + 2; } - for (unsigned int i = 0; i < count; i++) + for (i = 0; i < count; i++) { if (formats[i] == _glfw.x11.text_uri_list) { @@ -1705,14 +1718,14 @@ static void processEvent(XEvent *event) if (result) { - int count; - char** paths = _glfwParseUriList(data, &count); + int i, count; + char** paths = parseUriList(data, &count); _glfwInputDrop(window, count, (const char**) paths); - for (int i = 0; i < count; i++) - _glfw_free(paths[i]); - _glfw_free(paths); + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); } if (data) @@ -1749,8 +1762,6 @@ static void processEvent(XEvent *event) if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - captureCursor(window); if (window->x11.ic) XSetICFocus(window->x11.ic); @@ -1771,14 +1782,12 @@ static void processEvent(XEvent *event) if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - releaseCursor(); if (window->x11.ic) XUnsetICFocus(window->x11.ic); if (window->monitor && window->autoIconify) - _glfwIconifyWindowX11(window); + _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); return; @@ -1807,9 +1816,9 @@ static void processEvent(XEvent *event) if (window->monitor) { if (iconified) - releaseMonitorX11(window); + releaseMonitor(window); else - acquireMonitorX11(window); + acquireMonitor(window); } window->x11.iconified = iconified; @@ -1818,7 +1827,7 @@ static void processEvent(XEvent *event) } else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) { - const GLFWbool maximized = _glfwWindowMaximizedX11(window); + const GLFWbool maximized = _glfwPlatformWindowMaximized(window); if (window->x11.maximized != maximized) { window->x11.maximized = maximized; @@ -1899,6 +1908,10 @@ void _glfwPushSelectionToManagerX11(void) handleSelectionRequest(&event); break; + case SelectionClear: + handleSelectionClear(&event); + break; + case SelectionNotify: { if (event.xselection.target == _glfw.x11.SAVE_TARGETS) @@ -1916,7 +1929,7 @@ void _glfwPushSelectionToManagerX11(void) } } - waitForX11Event(NULL); + waitForEvent(NULL); } } @@ -1957,7 +1970,7 @@ void _glfwCreateInputContextX11(_GLFWwindow* window) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, +int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) @@ -2014,44 +2027,26 @@ GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } - - if (!_glfwRefreshContextAttribs(window, ctxconfig)) - return GLFW_FALSE; } - if (wndconfig->mousePassthrough) - _glfwSetWindowMousePassthroughX11(window, GLFW_TRUE); - if (window->monitor) { - _glfwShowWindowX11(window); + _glfwPlatformShowWindow(window); updateWindowMode(window); - acquireMonitorX11(window); - - if (wndconfig->centerCursor) - _glfwCenterCursorInContentArea(window); - } - else - { - if (wndconfig->visible) - { - _glfwShowWindowX11(window); - if (wndconfig->focused) - _glfwFocusWindowX11(window); - } + acquireMonitor(window); } XFlush(_glfw.x11.display); return GLFW_TRUE; } -void _glfwDestroyWindowX11(_GLFWwindow* window) +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (_glfw.x11.disabledCursorWindow == window) - enableCursor(window); + _glfw.x11.disabledCursorWindow = NULL; if (window->monitor) - releaseMonitorX11(window); + releaseMonitor(window); if (window->x11.ic) { @@ -2079,7 +2074,7 @@ void _glfwDestroyWindowX11(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title) +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { if (_glfw.x11.xlib.utf8) { @@ -2103,38 +2098,33 @@ void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title) XFlush(_glfw.x11.display); } -void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images) +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) { if (count) { - int longCount = 0; + int i, j, longCount = 0; - for (int i = 0; i < count; i++) + for (i = 0; i < count; i++) longCount += 2 + images[i].width * images[i].height; - unsigned long* icon = _glfw_calloc(longCount, sizeof(unsigned long)); - unsigned long* target = icon; + long* icon = calloc(longCount, sizeof(long)); + long* target = icon; - for (int i = 0; i < count; i++) + for (i = 0; i < count; i++) { *target++ = images[i].width; *target++ = images[i].height; - for (int j = 0; j < images[i].width * images[i].height; j++) + for (j = 0; j < images[i].width * images[i].height; j++) { - *target++ = (((unsigned long) images[i].pixels[j * 4 + 0]) << 16) | - (((unsigned long) images[i].pixels[j * 4 + 1]) << 8) | - (((unsigned long) images[i].pixels[j * 4 + 2]) << 0) | - (((unsigned long) images[i].pixels[j * 4 + 3]) << 24); + *target++ = (images[i].pixels[j * 4 + 0] << 16) | + (images[i].pixels[j * 4 + 1] << 8) | + (images[i].pixels[j * 4 + 2] << 0) | + (images[i].pixels[j * 4 + 3] << 24); } } - // NOTE: XChangeProperty expects 32-bit values like the image data above to be - // placed in the 32 least significant bits of individual longs. This is - // true even if long is 64-bit and a WM protocol calls for "packed" data. - // This is because of a historical mistake that then became part of the Xlib - // ABI. Xlib will pack these values into a regular array of 32-bit values - // before sending it over the wire. XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_ICON, XA_CARDINAL, 32, @@ -2142,7 +2132,7 @@ void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* imag (unsigned char*) icon, longCount); - _glfw_free(icon); + free(icon); } else { @@ -2153,7 +2143,7 @@ void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* imag XFlush(_glfw.x11.display); } -void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { Window dummy; int x, y; @@ -2167,11 +2157,11 @@ void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos) *ypos = y; } -void _glfwSetWindowPosX11(_GLFWwindow* window, int xpos, int ypos) +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { // HACK: Explicitly setting PPosition to any value causes some WMs, notably // Compiz and Metacity, to honor the position of unmapped windows - if (!_glfwWindowVisibleX11(window)) + if (!_glfwPlatformWindowVisible(window)) { long supplied; XSizeHints* hints = XAllocSizeHints(); @@ -2191,7 +2181,7 @@ void _glfwSetWindowPosX11(_GLFWwindow* window, int xpos, int ypos) XFlush(_glfw.x11.display); } -void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { XWindowAttributes attribs; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); @@ -2202,12 +2192,12 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height) *height = attribs.height; } -void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) { if (window->monitor->window == window) - acquireMonitorX11(window); + acquireMonitor(window); } else { @@ -2220,32 +2210,32 @@ void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) XFlush(_glfw.x11.display); } -void _glfwSetWindowSizeLimitsX11(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { int width, height; - _glfwGetWindowSizeX11(window, &width, &height); + _glfwPlatformGetWindowSize(window, &width, &height); updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } -void _glfwSetWindowAspectRatioX11(_GLFWwindow* window, int numer, int denom) +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { int width, height; - _glfwGetWindowSizeX11(window, &width, &height); + _glfwPlatformGetWindowSize(window, &width, &height); updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } -void _glfwGetFramebufferSizeX11(_GLFWwindow* window, int* width, int* height) +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { - _glfwGetWindowSizeX11(window, width, height); + _glfwPlatformGetWindowSize(window, width, height); } -void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { long* extents = NULL; @@ -2255,7 +2245,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, if (_glfw.x11.NET_FRAME_EXTENTS == None) return; - if (!_glfwWindowVisibleX11(window) && + if (!_glfwPlatformWindowVisible(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { XEvent event; @@ -2276,7 +2266,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, isFrameExtentsEvent, (XPointer) window)) { - if (!waitForX11Event(&timeout)) + if (!waitForEvent(&timeout)) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); @@ -2304,7 +2294,8 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, XFree(extents); } -void _glfwGetWindowContentScaleX11(_GLFWwindow* window, float* xscale, float* yscale) +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; @@ -2312,7 +2303,7 @@ void _glfwGetWindowContentScaleX11(_GLFWwindow* window, float* xscale, float* ys *yscale = _glfw.x11.contentScaleY; } -void _glfwIconifyWindowX11(_GLFWwindow* window) +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect) { @@ -2327,7 +2318,7 @@ void _glfwIconifyWindowX11(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwRestoreWindowX11(_GLFWwindow* window) +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect) { @@ -2338,12 +2329,12 @@ void _glfwRestoreWindowX11(_GLFWwindow* window) return; } - if (_glfwWindowIconifiedX11(window)) + if (_glfwPlatformWindowIconified(window)) { XMapWindow(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } - else if (_glfwWindowVisibleX11(window)) + else if (_glfwPlatformWindowVisible(window)) { if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && @@ -2361,7 +2352,7 @@ void _glfwRestoreWindowX11(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwMaximizeWindowX11(_GLFWwindow* window) +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || @@ -2370,7 +2361,7 @@ void _glfwMaximizeWindowX11(_GLFWwindow* window) return; } - if (_glfwWindowVisibleX11(window)) + if (_glfwPlatformWindowVisible(window)) { sendEventToWM(window, _glfw.x11.NET_WM_STATE, @@ -2426,22 +2417,22 @@ void _glfwMaximizeWindowX11(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwShowWindowX11(_GLFWwindow* window) +void _glfwPlatformShowWindow(_GLFWwindow* window) { - if (_glfwWindowVisibleX11(window)) + if (_glfwPlatformWindowVisible(window)) return; XMapWindow(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } -void _glfwHideWindowX11(_GLFWwindow* window) +void _glfwPlatformHideWindow(_GLFWwindow* window) { XUnmapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); } -void _glfwRequestWindowAttentionX11(_GLFWwindow* window) +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) return; @@ -2453,11 +2444,11 @@ void _glfwRequestWindowAttentionX11(_GLFWwindow* window) 0, 1, 0); } -void _glfwFocusWindowX11(_GLFWwindow* window) +void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); - else if (_glfwWindowVisibleX11(window)) + else if (_glfwPlatformWindowVisible(window)) { XRaiseWindow(_glfw.x11.display, window->x11.handle); XSetInputFocus(_glfw.x11.display, window->x11.handle, @@ -2467,18 +2458,18 @@ void _glfwFocusWindowX11(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwSetWindowMonitorX11(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { if (window->monitor == monitor) { if (monitor) { if (monitor->window == window) - acquireMonitorX11(window); + acquireMonitor(window); } else { @@ -2494,25 +2485,21 @@ void _glfwSetWindowMonitorX11(_GLFWwindow* window, } if (window->monitor) - { - _glfwSetWindowDecoratedX11(window, window->decorated); - _glfwSetWindowFloatingX11(window, window->floating); - releaseMonitorX11(window); - } + releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); updateNormalHints(window, width, height); if (window->monitor) { - if (!_glfwWindowVisibleX11(window)) + if (!_glfwPlatformWindowVisible(window)) { XMapRaised(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } updateWindowMode(window); - acquireMonitorX11(window); + acquireMonitor(window); } else { @@ -2524,7 +2511,7 @@ void _glfwSetWindowMonitorX11(_GLFWwindow* window, XFlush(_glfw.x11.display); } -GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window) +int _glfwPlatformWindowFocused(_GLFWwindow* window) { Window focused; int state; @@ -2533,21 +2520,22 @@ GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window) return window->x11.handle == focused; } -GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window) +int _glfwPlatformWindowIconified(_GLFWwindow* window) { return getWindowState(window) == IconicState; } -GLFWbool _glfwWindowVisibleX11(_GLFWwindow* window) +int _glfwPlatformWindowVisible(_GLFWwindow* window) { XWindowAttributes wa; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); return wa.map_state == IsViewable; } -GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window) +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { Atom* states; + unsigned long i; GLFWbool maximized = GLFW_FALSE; if (!_glfw.x11.NET_WM_STATE || @@ -2563,7 +2551,7 @@ GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window) XA_ATOM, (unsigned char**) &states); - for (unsigned long i = 0; i < count; i++) + for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) @@ -2579,7 +2567,7 @@ GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window) return maximized; } -GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window) +int _glfwPlatformWindowHovered(_GLFWwindow* window) { Window w = _glfw.x11.root; while (w) @@ -2607,7 +2595,7 @@ GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window) return GLFW_FALSE; } -GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window) +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { if (!window->x11.transparent) return GLFW_FALSE; @@ -2615,14 +2603,14 @@ GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window) return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } -void _glfwSetWindowResizableX11(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { int width, height; - _glfwGetWindowSizeX11(window, &width, &height); + _glfwPlatformGetWindowSize(window, &width, &height); updateNormalHints(window, width, height); } -void _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { struct { @@ -2644,12 +2632,12 @@ void _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled) sizeof(hints) / sizeof(long)); } -void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE) return; - if (_glfwWindowVisibleX11(window)) + if (_glfwPlatformWindowVisible(window)) { const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; sendEventToWM(window, @@ -2661,19 +2649,35 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled) else { Atom* states = NULL; - const unsigned long count = - _glfwGetWindowPropertyX11(window->x11.handle, - _glfw.x11.NET_WM_STATE, - XA_ATOM, - (unsigned char**) &states); + unsigned long i, count; + + count = _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); // NOTE: We don't check for failure as this property may not exist yet // and that's fine (and we'll create it implicitly with append) if (enabled) { - unsigned long i; + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) + break; + } + if (i < count) + return; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, + 1); + } + else if (states) + { for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) @@ -2681,27 +2685,14 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled) } if (i == count) - { - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeAppend, - (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, - 1); - } - } - else if (states) - { - for (unsigned long i = 0; i < count; i++) - { - if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) - { - states[i] = states[count - 1]; - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) states, count - 1); - break; - } - } + return; + + states[i] = states[count - 1]; + count--; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) states, count); } if (states) @@ -2711,7 +2702,7 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled) XFlush(_glfw.x11.display); } -void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled) +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled) { if (!_glfw.x11.xshape.available) return; @@ -2730,7 +2721,7 @@ void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled) } } -float _glfwGetWindowOpacityX11(_GLFWwindow* window) +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { float opacity = 1.f; @@ -2753,7 +2744,7 @@ float _glfwGetWindowOpacityX11(_GLFWwindow* window) return opacity; } -void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity) +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); XChangeProperty(_glfw.x11.display, window->x11.handle, @@ -2761,7 +2752,7 @@ void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity) PropModeReplace, (unsigned char*) &value, 1); } -void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled) +void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { if (!_glfw.x11.xi.available) return; @@ -2775,16 +2766,16 @@ void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled) disableRawMouseMotion(window); } -GLFWbool _glfwRawMouseMotionSupportedX11(void) +GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return _glfw.x11.xi.available; } -void _glfwPollEventsX11(void) +void _glfwPlatformPollEvents(void) { - drainEmptyEvents(); + _GLFWwindow* window; -#if defined(GLFW_BUILD_LINUX_JOYSTICK) +#if defined(__linux__) if (_glfw.joysticksInitialized) _glfwDetectJoystickConnectionLinux(); #endif @@ -2797,42 +2788,55 @@ void _glfwPollEventsX11(void) processEvent(&event); } - _GLFWwindow* window = _glfw.x11.disabledCursorWindow; + window = _glfw.x11.disabledCursorWindow; if (window) { int width, height; - _glfwGetWindowSizeX11(window, &width, &height); + _glfwPlatformGetWindowSize(window, &width, &height); // NOTE: Re-center the cursor only if it has moved since the last call, // to avoid breaking glfwWaitEvents with MotionNotify if (window->x11.lastCursorPosX != width / 2 || window->x11.lastCursorPosY != height / 2) { - _glfwSetCursorPosX11(window, width / 2, height / 2); + _glfwPlatformSetCursorPos(window, width / 2, height / 2); } } XFlush(_glfw.x11.display); } -void _glfwWaitEventsX11(void) +void _glfwPlatformWaitEvents(void) { - waitForAnyEvent(NULL); - _glfwPollEventsX11(); + while (!XPending(_glfw.x11.display)) + waitForEvent(NULL); + + _glfwPlatformPollEvents(); } -void _glfwWaitEventsTimeoutX11(double timeout) +void _glfwPlatformWaitEventsTimeout(double timeout) { - waitForAnyEvent(&timeout); - _glfwPollEventsX11(); + while (!XPending(_glfw.x11.display)) + { + if (!waitForEvent(&timeout)) + break; + } + + _glfwPlatformPollEvents(); } -void _glfwPostEmptyEventX11(void) +void _glfwPlatformPostEmptyEvent(void) { - writeEmptyEvent(); + XEvent event = { ClientMessage }; + event.xclient.window = _glfw.x11.helperWindowHandle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NULL_; + + XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event); + XFlush(_glfw.x11.display); } -void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { Window root, child; int rootX, rootY, childX, childY; @@ -2849,7 +2853,7 @@ void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos) *ypos = childY; } -void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y) +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { // Store the new position so it can be recognized later window->x11.warpCursorPosX = (int) x; @@ -2860,70 +2864,44 @@ void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y) XFlush(_glfw.x11.display); } -void _glfwSetCursorModeX11(_GLFWwindow* window, int mode) +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - if (_glfwWindowFocusedX11(window)) + if (mode == GLFW_CURSOR_DISABLED) { - if (mode == GLFW_CURSOR_DISABLED) - { - _glfwGetCursorPosX11(window, - &_glfw.x11.restoreCursorPosX, - &_glfw.x11.restoreCursorPosY); - _glfwCenterCursorInContentArea(window); - if (window->rawMouseMotion) - enableRawMouseMotion(window); - } - else if (_glfw.x11.disabledCursorWindow == window) - { - if (window->rawMouseMotion) - disableRawMouseMotion(window); - } - - if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED) - captureCursor(window); - else - releaseCursor(); - - if (mode == GLFW_CURSOR_DISABLED) - _glfw.x11.disabledCursorWindow = window; - else if (_glfw.x11.disabledCursorWindow == window) - { - _glfw.x11.disabledCursorWindow = NULL; - _glfwSetCursorPosX11(window, - _glfw.x11.restoreCursorPosX, - _glfw.x11.restoreCursorPosY); - } + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); } + else if (_glfw.x11.disabledCursorWindow == window) + enableCursor(window); + else + updateCursorImage(window); - updateCursorImage(window); XFlush(_glfw.x11.display); } -const char* _glfwGetScancodeNameX11(int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { if (!_glfw.x11.xkb.available) return NULL; - if (scancode < 0 || scancode > 0xff) + if (scancode < 0 || scancode > 0xff || + _glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); return NULL; } const int key = _glfw.x11.keycodes[scancode]; - if (key == GLFW_KEY_UNKNOWN) - return NULL; - const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0); if (keysym == NoSymbol) return NULL; - const uint32_t codepoint = _glfwKeySym2Unicode(keysym); - if (codepoint == GLFW_INVALID_CODEPOINT) + const long ch = _glfwKeySym2Unicode(keysym); + if (ch == -1) return NULL; - const size_t count = _glfwEncodeUTF8(_glfw.x11.keynames[key], codepoint); + const size_t count = encodeUTF8(_glfw.x11.keynames[key], (unsigned int) ch); if (count == 0) return NULL; @@ -2931,23 +2909,23 @@ const char* _glfwGetScancodeNameX11(int scancode) return _glfw.x11.keynames[key]; } -int _glfwGetKeyScancodeX11(int key) +int _glfwPlatformGetKeyScancode(int key) { return _glfw.x11.scancodes[key]; } -GLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor, +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { - cursor->x11.handle = _glfwCreateNativeCursorX11(image, xhot, yhot); + cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot); if (!cursor->x11.handle) return GLFW_FALSE; return GLFW_TRUE; } -GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape) +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { if (_glfw.x11.xcursor.handle) { @@ -2957,39 +2935,26 @@ GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape) const int size = XcursorGetDefaultSize(_glfw.x11.display); const char* name = NULL; - switch (shape) - { - case GLFW_ARROW_CURSOR: - name = "default"; - break; - case GLFW_IBEAM_CURSOR: - name = "text"; - break; - case GLFW_CROSSHAIR_CURSOR: - name = "crosshair"; - break; - case GLFW_POINTING_HAND_CURSOR: - name = "pointer"; - break; - case GLFW_RESIZE_EW_CURSOR: - name = "ew-resize"; - break; - case GLFW_RESIZE_NS_CURSOR: - name = "ns-resize"; - break; - case GLFW_RESIZE_NWSE_CURSOR: - name = "nwse-resize"; - break; - case GLFW_RESIZE_NESW_CURSOR: - name = "nesw-resize"; - break; - case GLFW_RESIZE_ALL_CURSOR: - name = "all-scroll"; - break; - case GLFW_NOT_ALLOWED_CURSOR: - name = "not-allowed"; - break; - } + if (shape == GLFW_ARROW_CURSOR) + name = "default"; + else if (shape == GLFW_IBEAM_CURSOR) + name = "text"; + else if (shape == GLFW_CROSSHAIR_CURSOR) + name = "crosshair"; + else if (shape == GLFW_POINTING_HAND_CURSOR) + name = "pointer"; + else if (shape == GLFW_RESIZE_EW_CURSOR) + name = "ew-resize"; + else if (shape == GLFW_RESIZE_NS_CURSOR) + name = "ns-resize"; + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + name = "nwse-resize"; + else if (shape == GLFW_RESIZE_NESW_CURSOR) + name = "nesw-resize"; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + name = "all-scroll"; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + name = "not-allowed"; XcursorImage* image = XcursorLibraryLoadImage(name, theme, size); if (image) @@ -3004,33 +2969,25 @@ GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape) { unsigned int native = 0; - switch (shape) + if (shape == GLFW_ARROW_CURSOR) + native = XC_left_ptr; + else if (shape == GLFW_IBEAM_CURSOR) + native = XC_xterm; + else if (shape == GLFW_CROSSHAIR_CURSOR) + native = XC_crosshair; + else if (shape == GLFW_POINTING_HAND_CURSOR) + native = XC_hand2; + else if (shape == GLFW_RESIZE_EW_CURSOR) + native = XC_sb_h_double_arrow; + else if (shape == GLFW_RESIZE_NS_CURSOR) + native = XC_sb_v_double_arrow; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + native = XC_fleur; + else { - case GLFW_ARROW_CURSOR: - native = XC_left_ptr; - break; - case GLFW_IBEAM_CURSOR: - native = XC_xterm; - break; - case GLFW_CROSSHAIR_CURSOR: - native = XC_crosshair; - break; - case GLFW_POINTING_HAND_CURSOR: - native = XC_hand2; - break; - case GLFW_RESIZE_EW_CURSOR: - native = XC_sb_h_double_arrow; - break; - case GLFW_RESIZE_NS_CURSOR: - native = XC_sb_v_double_arrow; - break; - case GLFW_RESIZE_ALL_CURSOR: - native = XC_fleur; - break; - default: - _glfwInputError(GLFW_CURSOR_UNAVAILABLE, - "X11: Standard cursor shape unavailable"); - return GLFW_FALSE; + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "X11: Standard cursor shape unavailable"); + return GLFW_FALSE; } cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); @@ -3045,26 +3002,25 @@ GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape) return GLFW_TRUE; } -void _glfwDestroyCursorX11(_GLFWcursor* cursor) +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->x11.handle) XFreeCursor(_glfw.x11.display, cursor->x11.handle); } -void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { - if (window->cursorMode == GLFW_CURSOR_NORMAL || - window->cursorMode == GLFW_CURSOR_CAPTURED) + if (window->cursorMode == GLFW_CURSOR_NORMAL) { updateCursorImage(window); XFlush(_glfw.x11.display); } } -void _glfwSetClipboardStringX11(const char* string) +void _glfwPlatformSetClipboardString(const char* string) { char* copy = _glfw_strdup(string); - _glfw_free(_glfw.x11.clipboardString); + free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = copy; XSetSelectionOwner(_glfw.x11.display, @@ -3080,12 +3036,12 @@ void _glfwSetClipboardStringX11(const char* string) } } -const char* _glfwGetClipboardStringX11(void) +const char* _glfwPlatformGetClipboardString(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } -EGLenum _glfwGetEGLPlatformX11(EGLint** attribs) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) { @@ -3105,7 +3061,7 @@ EGLenum _glfwGetEGLPlatformX11(EGLint** attribs) if (type) { - *attribs = _glfw_calloc(5, sizeof(EGLint)); + *attribs = calloc(5, sizeof(EGLint)); (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; (*attribs)[1] = type; (*attribs)[2] = EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE; @@ -3121,12 +3077,12 @@ EGLenum _glfwGetEGLPlatformX11(EGLint** attribs) return 0; } -EGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void) +EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void) { return _glfw.x11.display; } -EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window) +EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window) { if (_glfw.egl.platform) return &window->x11.handle; @@ -3134,7 +3090,7 @@ EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window) return (EGLNativeWindowType) window->x11.handle; } -void _glfwGetRequiredInstanceExtensionsX11(char** extensions) +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (!_glfw.vk.KHR_surface) return; @@ -3155,7 +3111,7 @@ void _glfwGetRequiredInstanceExtensionsX11(char** extensions) extensions[1] = "VK_KHR_xlib_surface"; } -GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { @@ -3208,10 +3164,10 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, } } -VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { @@ -3291,13 +3247,6 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, GLFWAPI Display* glfwGetX11Display(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); - return NULL; - } - return _glfw.x11.display; } @@ -3305,13 +3254,6 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); - return None; - } - return window->x11.handle; } @@ -3319,13 +3261,7 @@ GLFWAPI void glfwSetX11SelectionString(const char* string) { _GLFW_REQUIRE_INIT(); - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); - return; - } - - _glfw_free(_glfw.x11.primarySelectionString); + free(_glfw.x11.primarySelectionString); _glfw.x11.primarySelectionString = _glfw_strdup(string); XSetSelectionOwner(_glfw.x11.display, @@ -3344,15 +3280,6 @@ GLFWAPI void glfwSetX11SelectionString(const char* string) GLFWAPI const char* glfwGetX11SelectionString(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (_glfw.platform.platformID != GLFW_PLATFORM_X11) - { - _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); - return NULL; - } - return getSelectionString(_glfw.x11.PRIMARY); } -#endif // _GLFW_X11 - diff --git a/raylib/external/glfw/src/xdg-activation-v1-client-protocol-code.h b/raylib/external/glfw/src/xdg-activation-v1-client-protocol-code.h deleted file mode 100644 index ceece5a..0000000 --- a/raylib/external/glfw/src/xdg-activation-v1-client-protocol-code.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * Copyright © 2020 Aleix Pol Gonzalez - * Copyright © 2020 Carlos Garnacho - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include "wayland-util.h" - -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - -extern const struct wl_interface wl_seat_interface; -extern const struct wl_interface wl_surface_interface; -extern const struct wl_interface xdg_activation_token_v1_interface; - -static const struct wl_interface *xdg_activation_v1_types[] = { - NULL, - &xdg_activation_token_v1_interface, - NULL, - &wl_surface_interface, - NULL, - &wl_seat_interface, - &wl_surface_interface, -}; - -static const struct wl_message xdg_activation_v1_requests[] = { - { "destroy", "", xdg_activation_v1_types + 0 }, - { "get_activation_token", "n", xdg_activation_v1_types + 1 }, - { "activate", "so", xdg_activation_v1_types + 2 }, -}; - -WL_PRIVATE const struct wl_interface xdg_activation_v1_interface = { - "xdg_activation_v1", 1, - 3, xdg_activation_v1_requests, - 0, NULL, -}; - -static const struct wl_message xdg_activation_token_v1_requests[] = { - { "set_serial", "uo", xdg_activation_v1_types + 4 }, - { "set_app_id", "s", xdg_activation_v1_types + 0 }, - { "set_surface", "o", xdg_activation_v1_types + 6 }, - { "commit", "", xdg_activation_v1_types + 0 }, - { "destroy", "", xdg_activation_v1_types + 0 }, -}; - -static const struct wl_message xdg_activation_token_v1_events[] = { - { "done", "s", xdg_activation_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_activation_token_v1_interface = { - "xdg_activation_token_v1", 1, - 5, xdg_activation_token_v1_requests, - 1, xdg_activation_token_v1_events, -}; - diff --git a/raylib/external/glfw/src/xdg-activation-v1-client-protocol.h b/raylib/external/glfw/src/xdg-activation-v1-client-protocol.h deleted file mode 100644 index b26c548..0000000 --- a/raylib/external/glfw/src/xdg-activation-v1-client-protocol.h +++ /dev/null @@ -1,415 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H -#define XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_xdg_activation_v1 The xdg_activation_v1 protocol - * Protocol for requesting activation of surfaces - * - * @section page_desc_xdg_activation_v1 Description - * - * The way for a client to pass focus to another toplevel is as follows. - * - * The client that intends to activate another toplevel uses the - * xdg_activation_v1.get_activation_token request to get an activation token. - * This token is then forwarded to the client, which is supposed to activate - * one of its surfaces, through a separate band of communication. - * - * One established way of doing this is through the XDG_ACTIVATION_TOKEN - * environment variable of a newly launched child process. The child process - * should unset the environment variable again right after reading it out in - * order to avoid propagating it to other child processes. - * - * Another established way exists for Applications implementing the D-Bus - * interface org.freedesktop.Application, which should get their token under - * activation-token on their platform_data. - * - * In general activation tokens may be transferred across clients through - * means not described in this protocol. - * - * The client to be activated will then pass the token - * it received to the xdg_activation_v1.activate request. The compositor can - * then use this token to decide how to react to the activation request. - * - * The token the activating client gets may be ineffective either already at - * the time it receives it, for example if it was not focused, for focus - * stealing prevention. The activating client will have no way to discover - * the validity of the token, and may still forward it to the to be activated - * client. - * - * The created activation token may optionally get information attached to it - * that can be used by the compositor to identify the application that we - * intend to activate. This can for example be used to display a visual hint - * about what application is being started. - * - * Warning! The protocol described in this file is currently in the testing - * phase. Backward compatible changes may be added together with the - * corresponding interface version bump. Backward incompatible changes can - * only be done by creating a new major version of the extension. - * - * @section page_ifaces_xdg_activation_v1 Interfaces - * - @subpage page_iface_xdg_activation_v1 - interface for activating surfaces - * - @subpage page_iface_xdg_activation_token_v1 - an exported activation handle - * @section page_copyright_xdg_activation_v1 Copyright - *
- *
- * Copyright © 2020 Aleix Pol Gonzalez 
- * Copyright © 2020 Carlos Garnacho 
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- * 
- */ -struct wl_seat; -struct wl_surface; -struct xdg_activation_token_v1; -struct xdg_activation_v1; - -#ifndef XDG_ACTIVATION_V1_INTERFACE -#define XDG_ACTIVATION_V1_INTERFACE -/** - * @page page_iface_xdg_activation_v1 xdg_activation_v1 - * @section page_iface_xdg_activation_v1_desc Description - * - * A global interface used for informing the compositor about applications - * being activated or started, or for applications to request to be - * activated. - * @section page_iface_xdg_activation_v1_api API - * See @ref iface_xdg_activation_v1. - */ -/** - * @defgroup iface_xdg_activation_v1 The xdg_activation_v1 interface - * - * A global interface used for informing the compositor about applications - * being activated or started, or for applications to request to be - * activated. - */ -extern const struct wl_interface xdg_activation_v1_interface; -#endif -#ifndef XDG_ACTIVATION_TOKEN_V1_INTERFACE -#define XDG_ACTIVATION_TOKEN_V1_INTERFACE -/** - * @page page_iface_xdg_activation_token_v1 xdg_activation_token_v1 - * @section page_iface_xdg_activation_token_v1_desc Description - * - * An object for setting up a token and receiving a token handle that can - * be passed as an activation token to another client. - * - * The object is created using the xdg_activation_v1.get_activation_token - * request. This object should then be populated with the app_id, surface - * and serial information and committed. The compositor shall then issue a - * done event with the token. In case the request's parameters are invalid, - * the compositor will provide an invalid token. - * @section page_iface_xdg_activation_token_v1_api API - * See @ref iface_xdg_activation_token_v1. - */ -/** - * @defgroup iface_xdg_activation_token_v1 The xdg_activation_token_v1 interface - * - * An object for setting up a token and receiving a token handle that can - * be passed as an activation token to another client. - * - * The object is created using the xdg_activation_v1.get_activation_token - * request. This object should then be populated with the app_id, surface - * and serial information and committed. The compositor shall then issue a - * done event with the token. In case the request's parameters are invalid, - * the compositor will provide an invalid token. - */ -extern const struct wl_interface xdg_activation_token_v1_interface; -#endif - -#define XDG_ACTIVATION_V1_DESTROY 0 -#define XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN 1 -#define XDG_ACTIVATION_V1_ACTIVATE 2 - - -/** - * @ingroup iface_xdg_activation_v1 - */ -#define XDG_ACTIVATION_V1_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_v1 - */ -#define XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_v1 - */ -#define XDG_ACTIVATION_V1_ACTIVATE_SINCE_VERSION 1 - -/** @ingroup iface_xdg_activation_v1 */ -static inline void -xdg_activation_v1_set_user_data(struct xdg_activation_v1 *xdg_activation_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_activation_v1, user_data); -} - -/** @ingroup iface_xdg_activation_v1 */ -static inline void * -xdg_activation_v1_get_user_data(struct xdg_activation_v1 *xdg_activation_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_activation_v1); -} - -static inline uint32_t -xdg_activation_v1_get_version(struct xdg_activation_v1 *xdg_activation_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1); -} - -/** - * @ingroup iface_xdg_activation_v1 - * - * Notify the compositor that the xdg_activation object will no longer be - * used. - * - * The child objects created via this interface are unaffected and should - * be destroyed separately. - */ -static inline void -xdg_activation_v1_destroy(struct xdg_activation_v1 *xdg_activation_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1, - XDG_ACTIVATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_activation_v1 - * - * Creates an xdg_activation_token_v1 object that will provide - * the initiating client with a unique token for this activation. This - * token should be offered to the clients to be activated. - */ -static inline struct xdg_activation_token_v1 * -xdg_activation_v1_get_activation_token(struct xdg_activation_v1 *xdg_activation_v1) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1, - XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN, &xdg_activation_token_v1_interface, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), 0, NULL); - - return (struct xdg_activation_token_v1 *) id; -} - -/** - * @ingroup iface_xdg_activation_v1 - * - * Requests surface activation. It's up to the compositor to display - * this information as desired, for example by placing the surface above - * the rest. - * - * The compositor may know who requested this by checking the activation - * token and might decide not to follow through with the activation if it's - * considered unwanted. - * - * Compositors can ignore unknown activation tokens when an invalid - * token is passed. - */ -static inline void -xdg_activation_v1_activate(struct xdg_activation_v1 *xdg_activation_v1, const char *token, struct wl_surface *surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1, - XDG_ACTIVATION_V1_ACTIVATE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), 0, token, surface); -} - -#ifndef XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM -#define XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM -enum xdg_activation_token_v1_error { - /** - * The token has already been used previously - */ - XDG_ACTIVATION_TOKEN_V1_ERROR_ALREADY_USED = 0, -}; -#endif /* XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_activation_token_v1 - * @struct xdg_activation_token_v1_listener - */ -struct xdg_activation_token_v1_listener { - /** - * the exported activation token - * - * The 'done' event contains the unique token of this activation - * request and notifies that the provider is done. - * @param token the exported activation token - */ - void (*done)(void *data, - struct xdg_activation_token_v1 *xdg_activation_token_v1, - const char *token); -}; - -/** - * @ingroup iface_xdg_activation_token_v1 - */ -static inline int -xdg_activation_token_v1_add_listener(struct xdg_activation_token_v1 *xdg_activation_token_v1, - const struct xdg_activation_token_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_activation_token_v1, - (void (**)(void)) listener, data); -} - -#define XDG_ACTIVATION_TOKEN_V1_SET_SERIAL 0 -#define XDG_ACTIVATION_TOKEN_V1_SET_APP_ID 1 -#define XDG_ACTIVATION_TOKEN_V1_SET_SURFACE 2 -#define XDG_ACTIVATION_TOKEN_V1_COMMIT 3 -#define XDG_ACTIVATION_TOKEN_V1_DESTROY 4 - -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_DONE_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_SET_SERIAL_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_SET_APP_ID_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_SET_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_COMMIT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_xdg_activation_token_v1 */ -static inline void -xdg_activation_token_v1_set_user_data(struct xdg_activation_token_v1 *xdg_activation_token_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_activation_token_v1, user_data); -} - -/** @ingroup iface_xdg_activation_token_v1 */ -static inline void * -xdg_activation_token_v1_get_user_data(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_activation_token_v1); -} - -static inline uint32_t -xdg_activation_token_v1_get_version(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * Provides information about the seat and serial event that requested the - * token. - * - * The serial can come from an input or focus event. For instance, if a - * click triggers the launch of a third-party client, the launcher client - * should send a set_serial request with the serial and seat from the - * wl_pointer.button event. - * - * Some compositors might refuse to activate toplevels when the token - * doesn't have a valid and recent enough event serial. - * - * Must be sent before commit. This information is optional. - */ -static inline void -xdg_activation_token_v1_set_serial(struct xdg_activation_token_v1 *xdg_activation_token_v1, uint32_t serial, struct wl_seat *seat) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_SET_SERIAL, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, serial, seat); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * The requesting client can specify an app_id to associate the token - * being created with it. - * - * Must be sent before commit. This information is optional. - */ -static inline void -xdg_activation_token_v1_set_app_id(struct xdg_activation_token_v1 *xdg_activation_token_v1, const char *app_id) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, app_id); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * This request sets the surface requesting the activation. Note, this is - * different from the surface that will be activated. - * - * Some compositors might refuse to activate toplevels when the token - * doesn't have a requesting surface. - * - * Must be sent before commit. This information is optional. - */ -static inline void -xdg_activation_token_v1_set_surface(struct xdg_activation_token_v1 *xdg_activation_token_v1, struct wl_surface *surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_SET_SURFACE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, surface); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * Requests an activation token based on the different parameters that - * have been offered through set_serial, set_surface and set_app_id. - */ -static inline void -xdg_activation_token_v1_commit(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * Notify the compositor that the xdg_activation_token_v1 object will no - * longer be used. The received token stays valid. - */ -static inline void -xdg_activation_token_v1_destroy(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), WL_MARSHAL_FLAG_DESTROY); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/raylib/external/glfw/src/xkb_unicode.c b/raylib/external/glfw/src/xkb_unicode.c index 6b8dfca..2772ea0 100644 --- a/raylib/external/glfw/src/xkb_unicode.c +++ b/raylib/external/glfw/src/xkb_unicode.c @@ -24,10 +24,11 @@ // distribution. // //======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== #include "internal.h" -#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) /* * Marcus: This code was originally written by Markus G. Kuhn. @@ -906,7 +907,7 @@ static const struct codepair { // Convert XKB KeySym to Unicode // -uint32_t _glfwKeySym2Unicode(unsigned int keysym) +long _glfwKeySym2Unicode(unsigned int keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; @@ -936,8 +937,6 @@ uint32_t _glfwKeySym2Unicode(unsigned int keysym) } // No matching Unicode value found - return GLFW_INVALID_CODEPOINT; + return -1; } -#endif // _GLFW_WAYLAND or _GLFW_X11 - diff --git a/raylib/external/glfw/src/xkb_unicode.h b/raylib/external/glfw/src/xkb_unicode.h index b07408f..76d83ff 100644 --- a/raylib/external/glfw/src/xkb_unicode.h +++ b/raylib/external/glfw/src/xkb_unicode.h @@ -24,7 +24,5 @@ // //======================================================================== -#define GLFW_INVALID_CODEPOINT 0xffffffffu - -uint32_t _glfwKeySym2Unicode(unsigned int keysym); +long _glfwKeySym2Unicode(unsigned int keysym); diff --git a/raylib/external/jar_xm.h b/raylib/external/jar_xm.h index 422d82c..ea7a328 100644 --- a/raylib/external/jar_xm.h +++ b/raylib/external/jar_xm.h @@ -75,7 +75,7 @@ struct jar_xm_context_s; typedef struct jar_xm_context_s jar_xm_context_t; #ifdef __cplusplus -extern "C" { +extern "C" { #endif //** Create a XM context. @@ -363,7 +363,7 @@ struct jar_xm_sample_s { uint16_t num_patterns; uint16_t num_instruments; uint16_t linear_interpolation; - uint16_t ramping; + uint16_t ramping; jar_xm_frequency_type_t frequency_type; uint8_t pattern_table[PATTERN_ORDER_TABLE_LENGTH]; @@ -457,7 +457,7 @@ struct jar_xm_sample_s { uint16_t default_tempo; // Number of ticks per row uint16_t default_bpm; float default_global_volume; - + uint16_t tempo; // Number of ticks per row uint16_t bpm; float global_volume; @@ -518,10 +518,6 @@ int jar_xm_create_context(jar_xm_context_t** ctxp, const char* moddata, uint32_t return jar_xm_create_context_safe(ctxp, moddata, SIZE_MAX, rate); } -#ifdef ALIGN -#undef ALIGN -#endif - #define ALIGN(x, b) (((x) + ((b) - 1)) & ~((b) - 1)) #define ALIGN_PTR(x, b) (void*)(((uintptr_t)(x) + ((b) - 1)) & ~((b) - 1)) int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) { @@ -712,7 +708,7 @@ int jar_xm_check_sanity_postload(jar_xm_context_t* ctx) { if(ctx->module.pattern_table[i] >= ctx->module.num_patterns) { if(i+1 == ctx->module.length && ctx->module.length > 1) { DEBUG("trimming invalid POT at pos %X", i); - --ctx->module.length; + --ctx->module.length; } else { DEBUG("module has invalid POT, pos %X references nonexistent pattern %X", i, ctx->module.pattern_table[i]); return 1; @@ -802,7 +798,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd mod->num_patterns = READ_U16(offset + 10); mod->num_instruments = READ_U16(offset + 12); mod->patterns = (jar_xm_pattern_t*)mempool; - mod->linear_interpolation = 1; // Linear interpolation can be set after loading + mod->linear_interpolation = 0; // Linear interpolation can be set after loading mod->ramping = 1; // ramping can be set after loading mempool += mod->num_patterns * sizeof(jar_xm_pattern_t); mempool = ALIGN_PTR(mempool, 16); @@ -827,7 +823,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd pat->slots = (jar_xm_pattern_slot_t*)mempool; mempool += mod->num_channels * pat->num_rows * sizeof(jar_xm_pattern_slot_t); offset += READ_U32(offset); /* Pattern header length */ - + if(packed_patterndata_size == 0) { /* No pattern data is present */ memset(pat->slots, 0, sizeof(jar_xm_pattern_slot_t) * pat->num_rows * mod->num_channels); } else { @@ -1208,7 +1204,7 @@ static void jar_xm_tone_portamento(jar_xm_context_t* ctx, jar_xm_channel_context } static void jar_xm_pitch_slide(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, float period_offset) { - /* Don't ask about the 4.f coefficient. I found mention of it nowhere. Found by ear. */ + /* Don't ask about the 4.f coefficient. I found mention of it nowhere. Found by ear™. */ if(ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES) {period_offset *= 4.f; } ch->period += period_offset; jar_xm_CLAMP_DOWN(ch->period); @@ -1240,7 +1236,7 @@ static void jar_xm_post_pattern_change(jar_xm_context_t* ctx) { /* Loop if necessary */ if(ctx->current_table_index >= ctx->module.length) { ctx->current_table_index = ctx->module.restart_position; - ctx->tempo =ctx->default_tempo; // reset to file default value + ctx->tempo =ctx->default_tempo; // reset to file default value ctx->bpm = ctx->default_bpm; // reset to file default value ctx->global_volume = ctx->default_global_volume; // reset to file default value } @@ -1511,7 +1507,7 @@ static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_chan jar_xm_volume_slide(ch, ch->fine_volume_slide_param); break; case 0xD: /* EDy: Note delay */ - /* XXX: figure this out better. EDx triggers the note even when there no note and no instrument. But ED0 acts like like a ghost note, EDx (x != 0) does not. */ + /* XXX: figure this out better. EDx triggers the note even when there no note and no instrument. But ED0 acts like like a ghost note, EDx (x ≠ 0) does not. */ if(s->note == 0 && s->instrument == 0) { unsigned int flags = jar_xm_TRIGGER_KEEP_VOLUME; if(ch->current->effect_param & 0x0F) { @@ -1590,7 +1586,7 @@ static void jar_xm_trigger_note(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch->sample_position = 0.f; ch->ping = true; }; - + if (!(flags & jar_xm_TRIGGER_KEEP_VOLUME)) { if(ch->sample != NULL) { ch->volume = ch->sample->volume; @@ -1669,7 +1665,7 @@ static void jar_xm_row(jar_xm_context_t* ctx) { /* No E6y loop is in effect (or we are in the first pass) */ ctx->loop_count = (ctx->row_loop_count[MAX_NUM_ROWS * ctx->current_table_index + ctx->current_row]++); } - + /// Move to next row ctx->current_row++; /* uint8 warning: can increment from 255 to 0, in which case it is still necessary to go the next pattern. */ if (!ctx->position_jump && !ctx->pattern_break && (ctx->current_row >= cur->num_rows || ctx->current_row == 0)) { @@ -1725,7 +1721,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { if(ctx->current_tick == 0) { jar_xm_row(ctx); // We have processed all ticks and we run the row } - + jar_xm_module_t* mod = &(ctx->module); for(uint8_t i = 0; i < ctx->module.num_channels; ++i) { jar_xm_channel_context_t* ch = ctx->channels + i; @@ -1799,7 +1795,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { if(ch->current->effect_param > 0) { char arp_offset = ctx->tempo % 3; switch(arp_offset) { - case 2: /* 0 -> x -> 0 -> y -> x -> ... */ + case 2: /* 0 -> x -> 0 -> y -> x -> … */ if(ctx->current_tick == 1) { ch->arp_in_progress = true; ch->arp_note_offset = ch->current->effect_param >> 4; @@ -1807,7 +1803,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { break; } /* No break here, this is intended */ - case 1: /* 0 -> 0 -> y -> x -> ... */ + case 1: /* 0 -> 0 -> y -> x -> … */ if(ctx->current_tick == 0) { ch->arp_in_progress = false; ch->arp_note_offset = 0; @@ -1815,7 +1811,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { break; } /* No break here, this is intended */ - case 0: /* 0 -> y -> x -> ... */ + case 0: /* 0 -> y -> x -> … */ jar_xm_arpeggio(ctx, ch, ch->current->effect_param, ctx->current_tick - arp_offset); default: break; @@ -1889,7 +1885,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { } break; case 16: /* Fxy: Set tempo/BPM */ - break; + break; case 17: /* Hxy: Global volume slide */ if(ctx->current_tick == 0) break; if((ch->global_volume_slide_param & 0xF0) && (ch->global_volume_slide_param & 0x0F)) { break; }; /* Invalid state */ @@ -1908,7 +1904,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { if(ctx->current_tick == ch->current->effect_param) { jar_xm_key_off(ch); }; break; case 21: /* Lxx: Set envelope position */ - break; + break; case 25: /* Pxy: Panning slide */ if(ctx->current_tick == 0) break; jar_xm_panning_slide(ch, ch->panning_slide_param); @@ -2109,7 +2105,7 @@ static void jar_xm_next_of_sample(jar_xm_context_t* ctx, jar_xm_channel_context_ // gather all channel audio into stereo float static void jar_xm_mixdown(jar_xm_context_t* ctx, float* left, float* right) { jar_xm_module_t* mod = &(ctx->module); - + if(ctx->remaining_samples_in_tick <= 0) { jar_xm_tick(ctx); }; @@ -2146,7 +2142,7 @@ static void jar_xm_mixdown(jar_xm_context_t* ctx, float* left, float* right) { // apply brick wall limiter when audio goes beyond bounderies if(*left < -1.0) {*left = -1.0;} else if(*left > 1.0) {*left = 1.0;}; - if(*right < -1.0) {*right = -1.0;} else if(*right > 1.0) {*right = 1.0;}; + if(*right < -1.0) {*right = -1.0;} else if(*right > 1.0) {*right = 1.0;}; }; void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples) { @@ -2248,7 +2244,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const return 6; break; } - + return 0; } @@ -2257,11 +2253,10 @@ void jar_xm_reset(jar_xm_context_t* ctx) { for (uint16_t i = 0; i < jar_xm_get_number_of_channels(ctx); i++) { jar_xm_cut_note(&ctx->channels[i]); } - ctx->generated_samples = 0; ctx->current_row = 0; ctx->current_table_index = 0; ctx->current_tick = 0; - ctx->tempo =ctx->default_tempo; // reset to file default value + ctx->tempo =ctx->default_tempo; // reset to file default value ctx->bpm = ctx->default_bpm; // reset to file default value ctx->global_volume = ctx->default_global_volume; // reset to file default value } @@ -2287,7 +2282,7 @@ void jar_xm_table_jump(jar_xm_context_t* ctx, int table_ptr) { } else { ctx->current_table_index = 0; ctx->module.restart_position = 0; // The reason to jump is to start a new loop or track - ctx->tempo =ctx->default_tempo; // reset to file default value + ctx->tempo =ctx->default_tempo; // reset to file default value ctx->bpm = ctx->default_bpm; // reset to file default value ctx->global_volume = ctx->default_global_volume; // reset to file default value }; @@ -2388,31 +2383,31 @@ void jar_xm_debug(jar_xm_context_t *ctx) { y += size; DrawText(TextFormat("LCT = %i", ctx->loop_count), x, y, size, WHITE); y += size; DrawText(TextFormat("MAX LCT = %i", ctx->max_loop_count), x, y, size, WHITE); x = size * 12; y = 0; - + y += size; DrawText(TextFormat("CUR TCK = %i", ctx->current_tick), x, y, size, WHITE); y += size; DrawText(TextFormat("XTR TCK = %i", ctx->extra_ticks), x, y, size, WHITE); y += size; DrawText(TextFormat("TCK/ROW = %i", ctx->tempo), x, y, size, ORANGE); y += size; DrawText(TextFormat("SPL TCK = %f", ctx->remaining_samples_in_tick), x, y, size, WHITE); y += size; DrawText(TextFormat("GEN SPL = %i", ctx->generated_samples), x, y, size, WHITE); y += size * 7; - + x = 0; size=16; // TIMELINE OF MODULE for (int i=0; i < ctx->module.length; i++) { if (i == ctx->jump_dest) { if (ctx->position_jump) { - DrawRectangle(i * size * 2, y - size, size * 2, size, GOLD); + DrawRectangle(i * size * 2, y - size, size * 2, size, GOLD); } else { - DrawRectangle(i * size * 2, y - size, size * 2, size, BROWN); + DrawRectangle(i * size * 2, y - size, size * 2, size, BROWN); }; }; if (i == ctx->current_table_index) { // DrawText(TextFormat("%02X", ctx->current_tick), i * size * 2, y - size, size, WHITE); - DrawRectangle(i * size * 2, y, size * 2, size, RED); + DrawRectangle(i * size * 2, y, size * 2, size, RED); DrawText(TextFormat("%02X", ctx->current_row), i * size * 2, y - size, size, YELLOW); } else { - DrawRectangle(i * size * 2, y, size * 2, size, ORANGE); + DrawRectangle(i * size * 2, y, size * 2, size, ORANGE); }; DrawText(TextFormat("%02X", ctx->module.pattern_table[i]), i * size * 2, y, size, WHITE); }; @@ -2431,19 +2426,19 @@ void jar_xm_debug(jar_xm_context_t *ctx) { DrawText("FX", x + size * 6, y, size, YELLOW); x += 9 * size; }; - x += size; + x += size; for (int j=(ctx->current_row - 14); j<(ctx->current_row + 15); j++) { y += size; x = 0; if (j >=0 && j < (cur->num_rows)) { - DrawRectangle(x, y, size * 2, size, BROWN); + DrawRectangle(x, y, size * 2, size, BROWN); DrawText(TextFormat("%02X",j), x, y, size, WHITE); x += 2 * size; for(uint8_t i = 0; i < ctx->module.num_channels; i++) { if (j==(ctx->current_row)) { - DrawRectangle(x, y, 8 * size, size, DARKGREEN); + DrawRectangle(x, y, 8 * size, size, DARKGREEN); } else { - DrawRectangle(x, y, 8 * size, size, DARKGRAY); + DrawRectangle(x, y, 8 * size, size, DARKGRAY); }; jar_xm_pattern_slot_t *s = cur->slots + j * ctx->module.num_channels + i; // jar_xm_channel_context_t *ch = ctx->channels + i; diff --git a/raylib/external/m3d.h b/raylib/external/m3d.h deleted file mode 100644 index 6abaad1..0000000 --- a/raylib/external/m3d.h +++ /dev/null @@ -1,6547 +0,0 @@ -/* - * m3d.h - * https://gitlab.com/bztsrc/model3d - * - * Copyright (C) 2020 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * @brief ANSI C89 / C++11 single header importer / exporter SDK for the Model 3D (.M3D) format - * https://gitlab.com/bztsrc/model3d - * - * PNG decompressor included from (with minor modifications to make it C89 valid): - * stb_image - v2.13 - public domain image loader - http://nothings.org/stb_image.h - * - * @version: 1.0.0 - */ - -#ifndef _M3D_H_ -#define _M3D_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/*** configuration ***/ -#ifndef M3D_MALLOC -# define M3D_MALLOC(sz) malloc(sz) -#endif -#ifndef M3D_REALLOC -# define M3D_REALLOC(p,nsz) realloc(p,nsz) -#endif -#ifndef M3D_FREE -# define M3D_FREE(p) free(p) -#endif -#ifndef M3D_LOG -# define M3D_LOG(x) -#endif -#ifndef M3D_APIVERSION -#define M3D_APIVERSION 0x0100 -#ifndef M3D_DOUBLE -typedef float M3D_FLOAT; -#ifndef M3D_EPSILON -/* carefully choosen for IEEE 754 don't change */ -#define M3D_EPSILON ((M3D_FLOAT)1e-7) -#endif -#else -typedef double M3D_FLOAT; -#ifndef M3D_EPSILON -#define M3D_EPSILON ((M3D_FLOAT)1e-14) -#endif -#endif -#if !defined(M3D_SMALLINDEX) -typedef uint32_t M3D_INDEX; -typedef uint16_t M3D_VOXEL; -#define M3D_UNDEF 0xffffffff -#define M3D_INDEXMAX 0xfffffffe -#define M3D_VOXUNDEF 0xffff -#define M3D_VOXCLEAR 0xfffe -#else -typedef uint16_t M3D_INDEX; -typedef uint8_t M3D_VOXEL; -#define M3D_UNDEF 0xffff -#define M3D_INDEXMAX 0xfffe -#define M3D_VOXUNDEF 0xff -#define M3D_VOXCLEAR 0xfe -#endif -#define M3D_NOTDEFINED 0xffffffff -#ifndef M3D_NUMBONE -#define M3D_NUMBONE 4 -#endif -#ifndef M3D_BONEMAXLEVEL -#define M3D_BONEMAXLEVEL 64 -#endif -#ifndef _MSC_VER -#ifndef _inline -#define _inline __inline__ -#endif -#define _pack __attribute__((packed)) -#define _unused __attribute__((unused)) -#else -#define _inline -#define _pack -#define _unused __pragma(warning(suppress:4100)) -#endif -#ifndef __cplusplus -#define _register register -#else -#define _register -#endif - -/*** File format structures ***/ - -/** - * M3D file format structure - * 3DMO m3dchunk_t file header chunk, may followed by compressed data - * PRVW preview chunk (optional) - * HEAD m3dhdr_t model header chunk - * n x m3dchunk_t more chunks follow - * CMAP color map chunk (optional) - * TMAP texture map chunk (optional) - * VRTS vertex data chunk (optional if it's a material library) - * BONE bind-pose skeleton, bone hierarchy chunk (optional) - * n x m3db_t contains propably more, but at least one bone - * n x m3ds_t skin group records - * MTRL* material chunk(s), can be more (optional) - * n x m3dp_t each material contains propapbly more, but at least one property - * the properties are configurable with a static array, see m3d_propertytypes - * n x m3dchunk_t at least one, but maybe more face chunks - * PROC* procedural face, or - * MESH* triangle mesh (vertex index list) or - * VOXT, VOXD* voxel image (converted to mesh) or - * SHPE* mathematical shapes like parameterized surfaces - * LBLS* annotation label chunks, can be more (optional) - * ACTN* action chunk(s), animation-pose skeletons, can be more (optional) - * n x m3dfr_t each action contains probably more, but at least one frame - * n x m3dtr_t each frame contains probably more, but at least one transformation - * ASET* inlined asset chunk(s), can be more (optional) - * OMD3 end chunk - * - * Typical chunks for a game engine: 3DMO, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, OMD3 - * Typical chunks for distibution: 3DMO, PRVW, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, ASET, OMD3 - * Typical chunks for voxel image: 3DMO, HEAD, CMAP, MTRL, VOXT, VOXD, VOXD, VOXD, OMD3 - * Typical chunks for CAD software: 3DMO, PRVW, HEAD, CMAP, TMAP, VRTS, MTRL, SHPE, LBLS, OMD3 - */ -#ifdef _MSC_VER -#pragma pack(push) -#pragma pack(1) -#endif - -typedef struct { - char magic[4]; - uint32_t length; - float scale; /* deliberately not M3D_FLOAT */ - uint32_t types; -} _pack m3dhdr_t; - -typedef struct { - char magic[4]; - uint32_t length; -} _pack m3dchunk_t; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif - -/*** in-memory model structure ***/ - -/* textmap entry */ -typedef struct { - M3D_FLOAT u; - M3D_FLOAT v; -} m3dti_t; -#define m3d_textureindex_t m3dti_t - -/* texture */ -typedef struct { - char *name; /* texture name */ - uint8_t *d; /* pixels data */ - uint16_t w; /* width */ - uint16_t h; /* height */ - uint8_t f; /* format, 1 = grayscale, 2 = grayscale+alpha, 3 = rgb, 4 = rgba */ -} m3dtx_t; -#define m3d_texturedata_t m3dtx_t - -typedef struct { - M3D_INDEX vertexid; - M3D_FLOAT weight; -} m3dw_t; -#define m3d_weight_t m3dw_t - -/* bone entry */ -typedef struct { - M3D_INDEX parent; /* parent bone index */ - char *name; /* name for this bone */ - M3D_INDEX pos; /* vertex index position */ - M3D_INDEX ori; /* vertex index orientation (quaternion) */ - M3D_INDEX numweight; /* number of controlled vertices */ - m3dw_t *weight; /* weights for those vertices */ - M3D_FLOAT mat4[16]; /* transformation matrix */ -} m3db_t; -#define m3d_bone_t m3db_t - -/* skin: bone per vertex entry */ -typedef struct { - M3D_INDEX boneid[M3D_NUMBONE]; - M3D_FLOAT weight[M3D_NUMBONE]; -} m3ds_t; -#define m3d_skin_t m3ds_t - -/* vertex entry */ -typedef struct { - M3D_FLOAT x; /* 3D coordinates and weight */ - M3D_FLOAT y; - M3D_FLOAT z; - M3D_FLOAT w; - uint32_t color; /* default vertex color */ - M3D_INDEX skinid; /* skin index */ -#ifdef M3D_VERTEXTYPE - uint8_t type; -#endif -} m3dv_t; -#define m3d_vertex_t m3dv_t - -/* material property formats */ -enum { - m3dpf_color, - m3dpf_uint8, - m3dpf_uint16, - m3dpf_uint32, - m3dpf_float, - m3dpf_map -}; -typedef struct { - uint8_t format; - uint8_t id; -#ifdef M3D_ASCII -#define M3D_PROPERTYDEF(f,i,n) { (f), (i), (char*)(n) } - char *key; -#else -#define M3D_PROPERTYDEF(f,i,n) { (f), (i) } -#endif -} m3dpd_t; - -/* material property types */ -/* You shouldn't change the first 8 display and first 4 physical property. Assign the rest as you like. */ -enum { - m3dp_Kd = 0, /* scalar display properties */ - m3dp_Ka, - m3dp_Ks, - m3dp_Ns, - m3dp_Ke, - m3dp_Tf, - m3dp_Km, - m3dp_d, - m3dp_il, - - m3dp_Pr = 64, /* scalar physical properties */ - m3dp_Pm, - m3dp_Ps, - m3dp_Ni, - m3dp_Nt, - - m3dp_map_Kd = 128, /* textured display map properties */ - m3dp_map_Ka, - m3dp_map_Ks, - m3dp_map_Ns, - m3dp_map_Ke, - m3dp_map_Tf, - m3dp_map_Km, /* bump map */ - m3dp_map_D, - m3dp_map_N, /* normal map */ - - m3dp_map_Pr = 192, /* textured physical map properties */ - m3dp_map_Pm, - m3dp_map_Ps, - m3dp_map_Ni, - m3dp_map_Nt -}; -enum { /* aliases */ - m3dp_bump = m3dp_map_Km, - m3dp_map_il = m3dp_map_N, - m3dp_refl = m3dp_map_Pm -}; - -/* material property */ -typedef struct { - uint8_t type; /* property type, see "m3dp_*" enumeration */ - union { - uint32_t color; /* if value is a color, m3dpf_color */ - uint32_t num; /* if value is a number, m3dpf_uint8, m3pf_uint16, m3dpf_uint32 */ - float fnum; /* if value is a floating point number, m3dpf_float */ - M3D_INDEX textureid; /* if value is a texture, m3dpf_map */ - } value; -} m3dp_t; -#define m3d_property_t m3dp_t - -/* material entry */ -typedef struct { - char *name; /* name of the material */ - uint8_t numprop; /* number of properties */ - m3dp_t *prop; /* properties array */ -} m3dm_t; -#define m3d_material_t m3dm_t - -/* face entry */ -typedef struct { - M3D_INDEX materialid; /* material index */ - M3D_INDEX vertex[3]; /* 3D points of the triangle in CCW order */ - M3D_INDEX normal[3]; /* normal vectors */ - M3D_INDEX texcoord[3]; /* UV coordinates */ -#ifdef M3D_VERTEXMAX - M3D_INDEX paramid; /* parameter index */ - M3D_INDEX vertmax[3]; /* maximum 3D points of the triangle in CCW order */ -#endif -} m3df_t; -#define m3d_face_t m3df_t - -typedef struct { - uint16_t count; - char *name; -} m3dvi_t; -#define m3d_voxelitem_t m3dvi_t -#define m3d_parameter_t m3dvi_t - -/* voxel types (voxel palette) */ -typedef struct { - char *name; /* technical name of the voxel */ - uint8_t rotation; /* rotation info */ - uint16_t voxshape; /* voxel shape */ - M3D_INDEX materialid; /* material index */ - uint32_t color; /* default voxel color */ - M3D_INDEX skinid; /* skin index */ - uint8_t numitem; /* number of sub-voxels */ - m3dvi_t *item; /* list of sub-voxels */ -} m3dvt_t; -#define m3d_voxeltype_t m3dvt_t - -/* voxel data blocks */ -typedef struct { - char *name; /* name of the block */ - int32_t x, y, z; /* position */ - uint32_t w, h, d; /* dimension */ - uint8_t uncertain; /* probability */ - uint8_t groupid; /* block group id */ - M3D_VOXEL *data; /* voxel data, indices to voxel type */ -} m3dvx_t; -#define m3d_voxel_t m3dvx_t - -/* shape command types. must match the row in m3d_commandtypes */ -enum { - /* special commands */ - m3dc_use = 0, /* use material */ - m3dc_inc, /* include another shape */ - m3dc_mesh, /* include part of polygon mesh */ - /* approximations */ - m3dc_div, /* subdivision by constant resolution for both u, v */ - m3dc_sub, /* subdivision by constant, different for u and v */ - m3dc_len, /* spacial subdivision by maxlength */ - m3dc_dist, /* subdivision by maxdistance and maxangle */ - /* modifiers */ - m3dc_degu, /* degree for both u, v */ - m3dc_deg, /* separate degree for u and v */ - m3dc_rangeu, /* range for u */ - m3dc_range, /* range for u and v */ - m3dc_paru, /* u parameters (knots) */ - m3dc_parv, /* v parameters */ - m3dc_trim, /* outer trimming curve */ - m3dc_hole, /* inner trimming curve */ - m3dc_scrv, /* spacial curve */ - m3dc_sp, /* special points */ - /* helper curves */ - m3dc_bez1, /* Bezier 1D */ - m3dc_bsp1, /* B-spline 1D */ - m3dc_bez2, /* bezier 2D */ - m3dc_bsp2, /* B-spline 2D */ - /* surfaces */ - m3dc_bezun, /* Bezier 3D with control, UV, normal */ - m3dc_bezu, /* with control and UV */ - m3dc_bezn, /* with control and normal */ - m3dc_bez, /* control points only */ - m3dc_nurbsun, /* B-spline 3D */ - m3dc_nurbsu, - m3dc_nurbsn, - m3dc_nurbs, - m3dc_conn, /* connect surfaces */ - /* geometrical */ - m3dc_line, - m3dc_polygon, - m3dc_circle, - m3dc_cylinder, - m3dc_shpere, - m3dc_torus, - m3dc_cone, - m3dc_cube -}; - -/* shape command argument types */ -enum { - m3dcp_mi_t = 1, /* material index */ - m3dcp_hi_t, /* shape index */ - m3dcp_fi_t, /* face index */ - m3dcp_ti_t, /* texture map index */ - m3dcp_vi_t, /* vertex index */ - m3dcp_qi_t, /* vertex index for quaternions */ - m3dcp_vc_t, /* coordinate or radius, float scalar */ - m3dcp_i1_t, /* int8 scalar */ - m3dcp_i2_t, /* int16 scalar */ - m3dcp_i4_t, /* int32 scalar */ - m3dcp_va_t /* variadic arguments */ -}; - -#define M3D_CMDMAXARG 8 /* if you increase this, add more arguments to the macro below */ -typedef struct { -#ifdef M3D_ASCII -#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } - char *key; -#else -#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } -#endif - uint8_t p; - uint8_t a[M3D_CMDMAXARG]; -} m3dcd_t; - -/* shape command */ -typedef struct { - uint16_t type; /* shape type */ - uint32_t *arg; /* arguments array */ -} m3dc_t; -#define m3d_shapecommand_t m3dc_t - -/* shape entry */ -typedef struct { - char *name; /* name of the mathematical shape */ - M3D_INDEX group; /* group this shape belongs to or -1 */ - uint32_t numcmd; /* number of commands */ - m3dc_t *cmd; /* commands array */ -} m3dh_t; -#define m3d_shape_t m3dh_t - -/* label entry */ -typedef struct { - char *name; /* name of the annotation layer or NULL */ - char *lang; /* language code or NULL */ - char *text; /* the label text */ - uint32_t color; /* color */ - M3D_INDEX vertexid; /* the vertex the label refers to */ -} m3dl_t; -#define m3d_label_t m3dl_t - -/* frame transformations / working copy skeleton entry */ -typedef struct { - M3D_INDEX boneid; /* selects a node in bone hierarchy */ - M3D_INDEX pos; /* vertex index new position */ - M3D_INDEX ori; /* vertex index new orientation (quaternion) */ -} m3dtr_t; -#define m3d_transform_t m3dtr_t - -/* animation frame entry */ -typedef struct { - uint32_t msec; /* frame's position on the timeline, timestamp */ - M3D_INDEX numtransform; /* number of transformations in this frame */ - m3dtr_t *transform; /* transformations */ -} m3dfr_t; -#define m3d_frame_t m3dfr_t - -/* model action entry */ -typedef struct { - char *name; /* name of the action */ - uint32_t durationmsec; /* duration in millisec (1/1000 sec) */ - M3D_INDEX numframe; /* number of frames in this animation */ - m3dfr_t *frame; /* frames array */ -} m3da_t; -#define m3d_action_t m3da_t - -/* inlined asset */ -typedef struct { - char *name; /* asset name (same pointer as in texture[].name) */ - uint8_t *data; /* compressed asset data */ - uint32_t length; /* compressed data length */ -} m3di_t; -#define m3d_inlinedasset_t m3di_t - -/*** in-memory model structure ***/ -#define M3D_FLG_FREERAW (1<<0) -#define M3D_FLG_FREESTR (1<<1) -#define M3D_FLG_MTLLIB (1<<2) -#define M3D_FLG_GENNORM (1<<3) - -typedef struct { - m3dhdr_t *raw; /* pointer to raw data */ - char flags; /* internal flags */ - signed char errcode; /* returned error code */ - char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s, vd_s, vp_s; /* decoded sizes for types */ - char *name; /* name of the model, like "Utah teapot" */ - char *license; /* usage condition or license, like "MIT", "LGPL" or "BSD-3clause" */ - char *author; /* nickname, email, homepage or github URL etc. */ - char *desc; /* comments, descriptions. May contain '\n' newline character */ - M3D_FLOAT scale; /* the model's bounding cube's size in SI meters */ - M3D_INDEX numcmap; - uint32_t *cmap; /* color map */ - M3D_INDEX numtmap; - m3dti_t *tmap; /* texture map indices */ - M3D_INDEX numtexture; - m3dtx_t *texture; /* uncompressed textures */ - M3D_INDEX numbone; - m3db_t *bone; /* bone hierarchy */ - M3D_INDEX numvertex; - m3dv_t *vertex; /* vertex data */ - M3D_INDEX numskin; - m3ds_t *skin; /* skin data */ - M3D_INDEX nummaterial; - m3dm_t *material; /* material list */ -#ifdef M3D_VERTEXMAX - M3D_INDEX numparam; - m3dvi_t *param; /* parameters and their values list */ -#endif - M3D_INDEX numface; - m3df_t *face; /* model face, polygon (triangle) mesh */ - M3D_INDEX numvoxtype; - m3dvt_t *voxtype; /* model face, voxel types */ - M3D_INDEX numvoxel; - m3dvx_t *voxel; /* model face, cubes compressed into voxels */ - M3D_INDEX numshape; - m3dh_t *shape; /* model face, shape commands */ - M3D_INDEX numlabel; - m3dl_t *label; /* annotation labels */ - M3D_INDEX numaction; - m3da_t *action; /* action animations */ - M3D_INDEX numinlined; - m3di_t *inlined; /* inlined assets */ - M3D_INDEX numextra; - m3dchunk_t **extra; /* unknown chunks, application / engine specific data probably */ - m3di_t preview; /* preview chunk */ -} m3d_t; - -/*** export parameters ***/ -#define M3D_EXP_INT8 0 -#define M3D_EXP_INT16 1 -#define M3D_EXP_FLOAT 2 -#define M3D_EXP_DOUBLE 3 - -#define M3D_EXP_NOCMAP (1<<0) -#define M3D_EXP_NOMATERIAL (1<<1) -#define M3D_EXP_NOFACE (1<<2) -#define M3D_EXP_NONORMAL (1<<3) -#define M3D_EXP_NOTXTCRD (1<<4) -#define M3D_EXP_FLIPTXTCRD (1<<5) -#define M3D_EXP_NORECALC (1<<6) -#define M3D_EXP_IDOSUCK (1<<7) -#define M3D_EXP_NOBONE (1<<8) -#define M3D_EXP_NOACTION (1<<9) -#define M3D_EXP_INLINE (1<<10) -#define M3D_EXP_EXTRA (1<<11) -#define M3D_EXP_NOZLIB (1<<14) -#define M3D_EXP_ASCII (1<<15) -#define M3D_EXP_NOVRTMAX (1<<16) - -/*** error codes ***/ -#define M3D_SUCCESS 0 -#define M3D_ERR_ALLOC -1 -#define M3D_ERR_BADFILE -2 -#define M3D_ERR_UNIMPL -65 -#define M3D_ERR_UNKPROP -66 -#define M3D_ERR_UNKMESH -67 -#define M3D_ERR_UNKIMG -68 -#define M3D_ERR_UNKFRAME -69 -#define M3D_ERR_UNKCMD -70 -#define M3D_ERR_UNKVOX -71 -#define M3D_ERR_TRUNC -72 -#define M3D_ERR_CMAP -73 -#define M3D_ERR_TMAP -74 -#define M3D_ERR_VRTS -75 -#define M3D_ERR_BONE -76 -#define M3D_ERR_MTRL -77 -#define M3D_ERR_SHPE -78 -#define M3D_ERR_VOXT -79 - -#define M3D_ERR_ISFATAL(x) ((x) < 0 && (x) > -65) - -/* callbacks */ -typedef unsigned char *(*m3dread_t)(char *filename, unsigned int *size); /* read file contents into buffer */ -typedef void (*m3dfree_t)(void *buffer); /* free file contents buffer */ -typedef int (*m3dtxsc_t)(const char *name, const void *script, uint32_t len, m3dtx_t *output); /* interpret texture script */ -typedef int (*m3dprsc_t)(const char *name, const void *script, uint32_t len, m3d_t *model); /* interpret surface script */ -#endif /* ifndef M3D_APIVERSION */ - -/*** C prototypes ***/ -/* import / export */ -m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib); -unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size); -void m3d_free(m3d_t *model); -/* generate animation pose skeleton */ -m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t *skeleton); -m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec); - -/* private prototypes used by both importer and exporter */ -char *_m3d_safestr(char *in, int morelines); - -/*** C implementation ***/ -#ifdef M3D_IMPLEMENTATION -#if !defined(M3D_NOIMPORTER) || defined(M3D_EXPORTER) -/* material property definitions */ -static m3dpd_t m3d_propertytypes[] = { - M3D_PROPERTYDEF(m3dpf_color, m3dp_Kd, "Kd"), /* diffuse color */ - M3D_PROPERTYDEF(m3dpf_color, m3dp_Ka, "Ka"), /* ambient color */ - M3D_PROPERTYDEF(m3dpf_color, m3dp_Ks, "Ks"), /* specular color */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_Ns, "Ns"), /* specular exponent */ - M3D_PROPERTYDEF(m3dpf_color, m3dp_Ke, "Ke"), /* emissive (emitting light of this color) */ - M3D_PROPERTYDEF(m3dpf_color, m3dp_Tf, "Tf"), /* transmission color */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_Km, "Km"), /* bump strength */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_d, "d"), /* dissolve (transparency) */ - M3D_PROPERTYDEF(m3dpf_uint8, m3dp_il, "il"), /* illumination model (informational, ignored by PBR-shaders) */ - - M3D_PROPERTYDEF(m3dpf_float, m3dp_Pr, "Pr"), /* roughness */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_Pm, "Pm"), /* metallic, also reflection */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_Ps, "Ps"), /* sheen */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_Ni, "Ni"), /* index of refraction (optical density) */ - M3D_PROPERTYDEF(m3dpf_float, m3dp_Nt, "Nt"), /* thickness of face in millimeter, for printing */ - - /* aliases, note that "map_*" aliases are handled automatically */ - M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Km, "bump"), - M3D_PROPERTYDEF(m3dpf_map, m3dp_map_N, "map_N"),/* as normal map has no scalar version, it's counterpart is 'il' */ - M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Pm, "refl") -}; -/* shape command definitions. if more commands start with the same string, the longer must come first */ -static m3dcd_t m3d_commandtypes[] = { - /* technical */ - M3D_CMDDEF(m3dc_use, "use", 1, m3dcp_mi_t, 0, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_inc, "inc", 3, m3dcp_hi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_mesh, "mesh", 1, m3dcp_fi_t, m3dcp_fi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0), - /* approximations */ - M3D_CMDDEF(m3dc_div, "div", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_sub, "sub", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_len, "len", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_dist, "dist", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), - /* modifiers */ - M3D_CMDDEF(m3dc_degu, "degu", 1, m3dcp_i1_t, 0, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_deg, "deg", 2, m3dcp_i1_t, m3dcp_i1_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_rangeu, "rangeu", 1, m3dcp_ti_t, 0, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_range, "range", 2, m3dcp_ti_t, m3dcp_ti_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_paru, "paru", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_parv, "parv", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_trim, "trim", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_hole, "hole", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_scrv, "scrv", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_sp, "sp", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - /* helper curves */ - M3D_CMDDEF(m3dc_bez1, "bez1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_bsp1, "bsp1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_bez2, "bez2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_bsp2, "bsp2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - /* surfaces */ - M3D_CMDDEF(m3dc_bezun, "bezun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_bezu, "bezu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_bezn, "bezn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_bez, "bez", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_nurbsun, "nurbsun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_nurbsu, "nurbsu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_nurbsn, "nurbsn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_nurbs, "nurbs", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_conn, "conn", 6, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0), - /* geometrical */ - M3D_CMDDEF(m3dc_line, "line", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_polygon, "polygon", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_circle, "circle", 3, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_cylinder,"cylinder",6, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0), - M3D_CMDDEF(m3dc_shpere, "shpere", 2, m3dcp_vi_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_torus, "torus", 4, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_cone, "cone", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), - M3D_CMDDEF(m3dc_cube, "cube", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0) -}; -#endif - -#include -#include - -#if !defined(M3D_NOIMPORTER) && !defined(STBI_INCLUDE_STB_IMAGE_H) -/* PNG decompressor from - - stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h -*/ -static const char *_m3dstbi__g_failure_reason; - -enum -{ - STBI_default = 0, - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -typedef unsigned short _m3dstbi_us; - -typedef uint16_t _m3dstbi__uint16; -typedef int16_t _m3dstbi__int16; -typedef uint32_t _m3dstbi__uint32; -typedef int32_t _m3dstbi__int32; - -typedef struct -{ - _m3dstbi__uint32 img_x, img_y; - int img_n, img_out_n; - - void *io_user_data; - - int read_from_callbacks; - int buflen; - unsigned char buffer_start[128]; - - unsigned char *img_buffer, *img_buffer_end; - unsigned char *img_buffer_original, *img_buffer_original_end; -} _m3dstbi__context; - -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; -} _m3dstbi__result_info; - -#define STBI_ASSERT(v) -#define STBI_NOTUSED(v) (void)sizeof(v) -#define STBI__BYTECAST(x) ((unsigned char) ((x) & 255)) -#define STBI_MALLOC(sz) M3D_MALLOC(sz) -#define STBI_REALLOC(p,newsz) M3D_REALLOC(p,newsz) -#define STBI_FREE(p) M3D_FREE(p) -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) - -_inline static unsigned char _m3dstbi__get8(_m3dstbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - return 0; -} - -_inline static int _m3dstbi__at_eof(_m3dstbi__context *s) -{ - return s->img_buffer >= s->img_buffer_end; -} - -static void _m3dstbi__skip(_m3dstbi__context *s, int n) -{ - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - s->img_buffer += n; -} - -static int _m3dstbi__getn(_m3dstbi__context *s, unsigned char *buffer, int n) -{ - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int _m3dstbi__get16be(_m3dstbi__context *s) -{ - int z = _m3dstbi__get8(s); - return (z << 8) + _m3dstbi__get8(s); -} - -static _m3dstbi__uint32 _m3dstbi__get32be(_m3dstbi__context *s) -{ - _m3dstbi__uint32 z = _m3dstbi__get16be(s); - return (z << 16) + _m3dstbi__get16be(s); -} - -#define _m3dstbi__err(x,y) _m3dstbi__errstr(y) -static int _m3dstbi__errstr(const char *str) -{ - _m3dstbi__g_failure_reason = str; - return 0; -} - -_inline static void *_m3dstbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - -static int _m3dstbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - return a <= 2147483647 - b; -} - -static int _m3dstbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; - return a <= 2147483647/b; -} - -static int _m3dstbi__mad2sizes_valid(int a, int b, int add) -{ - return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__addsizes_valid(a*b, add); -} - -static int _m3dstbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__mul2sizes_valid(a*b, c) && - _m3dstbi__addsizes_valid(a*b*c, add); -} - -static void *_m3dstbi__malloc_mad2(int a, int b, int add) -{ - if (!_m3dstbi__mad2sizes_valid(a, b, add)) return NULL; - return _m3dstbi__malloc(a*b + add); -} - -static void *_m3dstbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!_m3dstbi__mad3sizes_valid(a, b, c, add)) return NULL; - return _m3dstbi__malloc(a*b*c + add); -} - -static unsigned char _m3dstbi__compute_y(int r, int g, int b) -{ - return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *_m3dstbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) _m3dstbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - _m3dstbi__err("outofmem", "Out of memory"); - return NULL; - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} - -static _m3dstbi__uint16 _m3dstbi__compute_y_16(int r, int g, int b) -{ - return (_m3dstbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static _m3dstbi__uint16 *_m3dstbi__convert_format16(_m3dstbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - _m3dstbi__uint16 *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (_m3dstbi__uint16 *) _m3dstbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - _m3dstbi__err("outofmem", "Out of memory"); - return NULL; - } - - for (j=0; j < (int) y; ++j) { - _m3dstbi__uint16 *src = data + j * x * img_n ; - _m3dstbi__uint16 *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} - -#define STBI__ZFAST_BITS 9 -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) - -typedef struct -{ - _m3dstbi__uint16 fast[1 << STBI__ZFAST_BITS]; - _m3dstbi__uint16 firstcode[16]; - int maxcode[17]; - _m3dstbi__uint16 firstsymbol[16]; - unsigned char size[288]; - _m3dstbi__uint16 value[288]; -} _m3dstbi__zhuffman; - -_inline static int _m3dstbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -_inline static int _m3dstbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - return _m3dstbi__bitreverse16(v) >> (16-bits); -} - -static int _m3dstbi__zbuild_huffman(_m3dstbi__zhuffman *z, unsigned char *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return _m3dstbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (_m3dstbi__uint16) code; - z->firstsymbol[i] = (_m3dstbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return _m3dstbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - _m3dstbi__uint16 fastv = (_m3dstbi__uint16) ((s << 9) | i); - z->size [c] = (unsigned char ) s; - z->value[c] = (_m3dstbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = _m3dstbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -typedef struct -{ - unsigned char *zbuffer, *zbuffer_end; - int num_bits; - _m3dstbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - _m3dstbi__zhuffman z_length, z_distance; -} _m3dstbi__zbuf; - -_inline static unsigned char _m3dstbi__zget8(_m3dstbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void _m3dstbi__fill_bits(_m3dstbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) _m3dstbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -_inline static unsigned int _m3dstbi__zreceive(_m3dstbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) _m3dstbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int _m3dstbi__zhuffman_decode_slowpath(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) -{ - int b,s,k; - k = _m3dstbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -_inline static int _m3dstbi__zhuffman_decode(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) _m3dstbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return _m3dstbi__zhuffman_decode_slowpath(a, z); -} - -static int _m3dstbi__zexpand(_m3dstbi__zbuf *z, char *zout, int n) -{ - char *q; - int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return _m3dstbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return _m3dstbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static int _m3dstbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int _m3dstbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int _m3dstbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int _m3dstbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int _m3dstbi__parse_huffman_block(_m3dstbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = _m3dstbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); - if (zout >= a->zout_end) { - if (!_m3dstbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - unsigned char *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = _m3dstbi__zlength_base[z]; - if (_m3dstbi__zlength_extra[z]) len += _m3dstbi__zreceive(a, _m3dstbi__zlength_extra[z]); - z = _m3dstbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); - dist = _m3dstbi__zdist_base[z]; - if (_m3dstbi__zdist_extra[z]) dist += _m3dstbi__zreceive(a, _m3dstbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return _m3dstbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!_m3dstbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (unsigned char *) (zout - dist); - if (dist == 1) { - unsigned char v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } -} - -static int _m3dstbi__compute_huffman_codes(_m3dstbi__zbuf *a) -{ - static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - _m3dstbi__zhuffman z_codelength; - unsigned char lencodes[286+32+137]; - unsigned char codelength_sizes[19]; - int i,n; - - int hlit = _m3dstbi__zreceive(a,5) + 257; - int hdist = _m3dstbi__zreceive(a,5) + 1; - int hclen = _m3dstbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = _m3dstbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (unsigned char) s; - } - if (!_m3dstbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < ntot) { - int c = _m3dstbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (unsigned char) c; - else { - unsigned char fill = 0; - if (c == 16) { - c = _m3dstbi__zreceive(a,2)+3; - if (n == 0) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) - c = _m3dstbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); - c = _m3dstbi__zreceive(a,7)+11; - } - if (ntot - n < c) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; - } - } - if (n != ntot) return _m3dstbi__err("bad codelengths","Corrupt PNG"); - if (!_m3dstbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!_m3dstbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -_inline static int _m3dstbi__parse_uncompressed_block(_m3dstbi__zbuf *a) -{ - unsigned char header[4]; - int len,nlen,k; - if (a->num_bits & 7) - _m3dstbi__zreceive(a, a->num_bits & 7); - k = 0; - while (a->num_bits > 0) { - header[k++] = (unsigned char) (a->code_buffer & 255); - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - while (k < 4) - header[k++] = _m3dstbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return _m3dstbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return _m3dstbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!_m3dstbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int _m3dstbi__parse_zlib_header(_m3dstbi__zbuf *a) -{ - int cmf = _m3dstbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = _m3dstbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return _m3dstbi__err("bad zlib header","Corrupt PNG"); - if (flg & 32) return _m3dstbi__err("no preset dict","Corrupt PNG"); - if (cm != 8) return _m3dstbi__err("bad compression","Corrupt PNG"); - return 1; -} - -static unsigned char _m3dstbi__zdefault_length[288], _m3dstbi__zdefault_distance[32]; -static void _m3dstbi__init_zdefaults(void) -{ - int i; - for (i=0; i <= 143; ++i) _m3dstbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) _m3dstbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) _m3dstbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) _m3dstbi__zdefault_length[i] = 8; - - for (i=0; i <= 31; ++i) _m3dstbi__zdefault_distance[i] = 5; -} - -static int _m3dstbi__parse_zlib(_m3dstbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!_m3dstbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = _m3dstbi__zreceive(a,1); - type = _m3dstbi__zreceive(a,2); - if (type == 0) { - if (!_m3dstbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - if (!_m3dstbi__zbuild_huffman(&a->z_length , _m3dstbi__zdefault_length , 288)) return 0; - if (!_m3dstbi__zbuild_huffman(&a->z_distance, _m3dstbi__zdefault_distance, 32)) return 0; - } else { - if (!_m3dstbi__compute_huffman_codes(a)) return 0; - } - if (!_m3dstbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int _m3dstbi__do_zlib(_m3dstbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - _m3dstbi__init_zdefaults(); - return _m3dstbi__parse_zlib(a, parse_header); -} - -char *_m3dstbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - _m3dstbi__zbuf a; - char *p = (char *) _m3dstbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (unsigned char *) buffer; - a.zbuffer_end = (unsigned char *) buffer + len; - if (_m3dstbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -typedef struct -{ - _m3dstbi__uint32 length; - _m3dstbi__uint32 type; -} _m3dstbi__pngchunk; - -static _m3dstbi__pngchunk _m3dstbi__get_chunk_header(_m3dstbi__context *s) -{ - _m3dstbi__pngchunk c; - c.length = _m3dstbi__get32be(s); - c.type = _m3dstbi__get32be(s); - return c; -} - -_inline static int _m3dstbi__check_png_header(_m3dstbi__context *s) -{ - static unsigned char png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (_m3dstbi__get8(s) != png_sig[i]) return _m3dstbi__err("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - _m3dstbi__context *s; - unsigned char *idata, *expanded, *out; - int depth; -} _m3dstbi__png; - - -enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static unsigned char first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static int _m3dstbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -static unsigned char _m3dstbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; - -static int _m3dstbi__create_png_image_raw(_m3dstbi__png *a, unsigned char *raw, _m3dstbi__uint32 raw_len, int out_n, _m3dstbi__uint32 x, _m3dstbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16? 2 : 1); - _m3dstbi__context *s = a->s; - _m3dstbi__uint32 i,j,stride = x*out_n*bytes; - _m3dstbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; - - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (unsigned char *) _m3dstbi__malloc_mad3(x, y, output_bytes, 0); - if (!a->out) return _m3dstbi__err("outofmem", "Out of memory"); - - if (!_m3dstbi__mad3sizes_valid(img_n, x, depth, 7)) return _m3dstbi__err("too large", "Corrupt PNG"); - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); - } else { - if (raw_len < img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); - } - - for (j=0; j < y; ++j) { - unsigned char *cur = a->out + stride*j; - unsigned char *prior = cur - stride; - int filter = *raw++; - - if (filter > 4) - return _m3dstbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; - filter_bytes = 1; - width = img_width_bytes; - } - prior = cur - stride; - - if (j == 0) filter = first_row_filter[filter]; - - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; - cur[filter_bytes+1] = 255; - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - if (depth == 16) { - cur = a->out + stride*j; - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - if (depth < 8) { - for (j=0; j < y; ++j) { - unsigned char *cur = a->out + stride*j; - unsigned char *in = a->out + stride*j + x*out_n - img_width_bytes; - unsigned char scale = (color == 0) ? _m3dstbi__depth_scale_table[depth] : 1; - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } - } - } else if (depth == 16) { - unsigned char *cur = a->out; - _m3dstbi__uint16 *cur16 = (_m3dstbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } - } - - return 1; -} - -static int _m3dstbi__create_png_image(_m3dstbi__png *a, unsigned char *image_data, _m3dstbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - unsigned char *final; - int p; - if (!interlaced) - return _m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - final = (unsigned char *) _m3dstbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - _m3dstbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!_m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int _m3dstbi__compute_transparency(_m3dstbi__png *z, unsigned char tc[3], int out_n) -{ - _m3dstbi__context *s = z->s; - _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; - unsigned char *p = z->out; - - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int _m3dstbi__compute_transparency16(_m3dstbi__png *z, _m3dstbi__uint16 tc[3], int out_n) -{ - _m3dstbi__context *s = z->s; - _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; - _m3dstbi__uint16 *p = (_m3dstbi__uint16*) z->out; - - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int _m3dstbi__expand_png_palette(_m3dstbi__png *a, unsigned char *palette, int len, int pal_img_n) -{ - _m3dstbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - unsigned char *p, *temp_out, *orig = a->out; - - p = (unsigned char *) _m3dstbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); - - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) - -static int _m3dstbi__parse_png_file(_m3dstbi__png *z, int scan, int req_comp) -{ - unsigned char palette[1024], pal_img_n=0; - unsigned char has_trans=0, tc[3]; - _m3dstbi__uint16 tc16[3]; - _m3dstbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0; - _m3dstbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!_m3dstbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - _m3dstbi__pngchunk c = _m3dstbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - _m3dstbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return _m3dstbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return _m3dstbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = _m3dstbi__get32be(s); if (s->img_x > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); - s->img_y = _m3dstbi__get32be(s); if (s->img_y > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); - z->depth = _m3dstbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return _m3dstbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = _m3dstbi__get8(s); if (color > 6) return _m3dstbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return _m3dstbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return _m3dstbi__err("bad ctype","Corrupt PNG"); - comp = _m3dstbi__get8(s); if (comp) return _m3dstbi__err("bad comp method","Corrupt PNG"); - filter= _m3dstbi__get8(s); if (filter) return _m3dstbi__err("bad filter method","Corrupt PNG"); - interlace = _m3dstbi__get8(s); if (interlace>1) return _m3dstbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return _m3dstbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return _m3dstbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return _m3dstbi__err("too large","Corrupt PNG"); - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = _m3dstbi__get8(s); - palette[i*4+1] = _m3dstbi__get8(s); - palette[i*4+2] = _m3dstbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return _m3dstbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return _m3dstbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = _m3dstbi__get8(s); - } else { - if (!(s->img_n & 1)) return _m3dstbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (_m3dstbi__uint32) s->img_n*2) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (_m3dstbi__uint16)_m3dstbi__get16be(s); - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (unsigned char)(_m3dstbi__get16be(s) & 255) * _m3dstbi__depth_scale_table[z->depth]; - } - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return _m3dstbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - _m3dstbi__uint32 idata_limit_old = idata_limit; - unsigned char *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (unsigned char *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!_m3dstbi__getn(s, z->idata+ioff,c.length)) return _m3dstbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - _m3dstbi__uint32 raw_len, bpl; - if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return _m3dstbi__err("no IDAT","Corrupt PNG"); - bpl = (s->img_x * z->depth + 7) / 8; - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (unsigned char *) _m3dstbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, 1); - if (z->expanded == NULL) return 0; - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!_m3dstbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!_m3dstbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!_m3dstbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (pal_img_n) { - s->img_n = pal_img_n; - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!_m3dstbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } - - default: - if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - return _m3dstbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type"); - } - _m3dstbi__skip(s, c.length); - break; - } - _m3dstbi__get32be(s); - } -} - -static void *_m3dstbi__do_png(_m3dstbi__png *p, int *x, int *y, int *n, int req_comp, _m3dstbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) { _m3dstbi__err("bad req_comp", "Internal error"); return NULL; } - if (_m3dstbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) - ri->bits_per_channel = 8; - else - ri->bits_per_channel = p->depth; - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = _m3dstbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = _m3dstbi__convert_format16((_m3dstbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static void *_m3dstbi__png_load(_m3dstbi__context *s, int *x, int *y, int *comp, int req_comp, _m3dstbi__result_info *ri) -{ - _m3dstbi__png p; - p.s = s; - return _m3dstbi__do_png(&p, x,y,comp,req_comp, ri); -} -#define stbi__context _m3dstbi__context -#define stbi__result_info _m3dstbi__result_info -#define stbi__png_load _m3dstbi__png_load -#define stbi_zlib_decode_malloc_guesssize_headerflag _m3dstbi_zlib_decode_malloc_guesssize_headerflag -#endif -#if !defined(M3D_NOIMPORTER) && defined(STBI_INCLUDE_STB_IMAGE_H) && !defined(STB_IMAGE_IMPLEMENTATION) -#error "stb_image.h included without STB_IMAGE_IMPLEMENTATION. Sorry, we need some stuff defined inside the ifguard for proper integration" -#endif - -#if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H) -/* zlib_compressor from - - stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h -*/ -typedef unsigned char _m3dstbiw__uc; -typedef unsigned short _m3dstbiw__us; - -typedef uint16_t _m3dstbiw__uint16; -typedef int16_t _m3dstbiw__int16; -typedef uint32_t _m3dstbiw__uint32; -typedef int32_t _m3dstbiw__int32; - -#define STBIW_MALLOC(s) M3D_MALLOC(s) -#define STBIW_REALLOC(p,ns) M3D_REALLOC(p,ns) -#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) -#define STBIW_FREE M3D_FREE -#define STBIW_MEMMOVE memmove -#define STBIW_UCHAR (uint8_t) -#define STBIW_ASSERT(x) -#define _m3dstbiw___sbraw(a) ((int *) (a) - 2) -#define _m3dstbiw___sbm(a) _m3dstbiw___sbraw(a)[0] -#define _m3dstbiw___sbn(a) _m3dstbiw___sbraw(a)[1] - -#define _m3dstbiw___sbneedgrow(a,n) ((a)==0 || _m3dstbiw___sbn(a)+n >= _m3dstbiw___sbm(a)) -#define _m3dstbiw___sbmaybegrow(a,n) (_m3dstbiw___sbneedgrow(a,(n)) ? _m3dstbiw___sbgrow(a,n) : 0) -#define _m3dstbiw___sbgrow(a,n) _m3dstbiw___sbgrowf((void **) &(a), (n), sizeof(*(a))) - -#define _m3dstbiw___sbpush(a, v) (_m3dstbiw___sbmaybegrow(a,1), (a)[_m3dstbiw___sbn(a)++] = (v)) -#define _m3dstbiw___sbcount(a) ((a) ? _m3dstbiw___sbn(a) : 0) -#define _m3dstbiw___sbfree(a) ((a) ? STBIW_FREE(_m3dstbiw___sbraw(a)),0 : 0) - -static void *_m3dstbiw___sbgrowf(void **arr, int increment, int itemsize) -{ - int m = *arr ? 2*_m3dstbiw___sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? _m3dstbiw___sbraw(*arr) : 0, *arr ? (_m3dstbiw___sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); - STBIW_ASSERT(p); - if (p) { - if (!*arr) ((int *) p)[1] = 0; - *arr = (void *) ((int *) p + 2); - _m3dstbiw___sbm(*arr) = m; - } - return *arr; -} - -static unsigned char *_m3dstbiw___zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) -{ - while (*bitcount >= 8) { - _m3dstbiw___sbpush(data, STBIW_UCHAR(*bitbuffer)); - *bitbuffer >>= 8; - *bitcount -= 8; - } - return data; -} - -static int _m3dstbiw___zlib_bitrev(int code, int codebits) -{ - int res=0; - while (codebits--) { - res = (res << 1) | (code & 1); - code >>= 1; - } - return res; -} - -static unsigned int _m3dstbiw___zlib_countm(unsigned char *a, unsigned char *b, int limit) -{ - int i; - for (i=0; i < limit && i < 258; ++i) - if (a[i] != b[i]) break; - return i; -} - -static unsigned int _m3dstbiw___zhash(unsigned char *data) -{ - _m3dstbiw__uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; -} - -#define _m3dstbiw___zlib_flush() (out = _m3dstbiw___zlib_flushf(out, &bitbuf, &bitcount)) -#define _m3dstbiw___zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), _m3dstbiw___zlib_flush()) -#define _m3dstbiw___zlib_huffa(b,c) _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(b,c),c) -#define _m3dstbiw___zlib_huff1(n) _m3dstbiw___zlib_huffa(0x30 + (n), 8) -#define _m3dstbiw___zlib_huff2(n) _m3dstbiw___zlib_huffa(0x190 + (n)-144, 9) -#define _m3dstbiw___zlib_huff3(n) _m3dstbiw___zlib_huffa(0 + (n)-256,7) -#define _m3dstbiw___zlib_huff4(n) _m3dstbiw___zlib_huffa(0xc0 + (n)-280,8) -#define _m3dstbiw___zlib_huff(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : (n) <= 255 ? _m3dstbiw___zlib_huff2(n) : (n) <= 279 ? _m3dstbiw___zlib_huff3(n) : _m3dstbiw___zlib_huff4(n)) -#define _m3dstbiw___zlib_huffb(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : _m3dstbiw___zlib_huff2(n)) - -#define _m3dstbiw___ZHASH 16384 - -unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) -{ - static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; - static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; - static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; - static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; - unsigned int bitbuf=0; - int i,j, bitcount=0; - unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(_m3dstbiw___ZHASH * sizeof(char**)); - if (hash_table == NULL) - return NULL; - if (quality < 5) quality = 5; - - _m3dstbiw___sbpush(out, 0x78); - _m3dstbiw___sbpush(out, 0x5e); - _m3dstbiw___zlib_add(1,1); - _m3dstbiw___zlib_add(1,2); - - for (i=0; i < _m3dstbiw___ZHASH; ++i) - hash_table[i] = NULL; - - i=0; - while (i < data_len-3) { - int h = _m3dstbiw___zhash(data+i)&(_m3dstbiw___ZHASH-1), best=3; - unsigned char *bestloc = 0; - unsigned char **hlist = hash_table[h]; - int n = _m3dstbiw___sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32768) { - int d = _m3dstbiw___zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) best=d,bestloc=hlist[j]; - } - } - if (hash_table[h] && _m3dstbiw___sbn(hash_table[h]) == 2*quality) { - STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - _m3dstbiw___sbn(hash_table[h]) = quality; - } - _m3dstbiw___sbpush(hash_table[h],data+i); - - if (bestloc) { - h = _m3dstbiw___zhash(data+i+1)&(_m3dstbiw___ZHASH-1); - hlist = hash_table[h]; - n = _m3dstbiw___sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32767) { - int e = _m3dstbiw___zlib_countm(hlist[j], data+i+1, data_len-i-1); - if (e > best) { - bestloc = NULL; - break; - } - } - } - } - - if (bestloc) { - int d = (int) (data+i - bestloc); - STBIW_ASSERT(d <= 32767 && best <= 258); - for (j=0; best > lengthc[j+1]-1; ++j); - _m3dstbiw___zlib_huff(j+257); - if (lengtheb[j]) _m3dstbiw___zlib_add(best - lengthc[j], lengtheb[j]); - for (j=0; d > distc[j+1]-1; ++j); - _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(j,5),5); - if (disteb[j]) _m3dstbiw___zlib_add(d - distc[j], disteb[j]); - i += best; - } else { - _m3dstbiw___zlib_huffb(data[i]); - ++i; - } - } - for (;i < data_len; ++i) - _m3dstbiw___zlib_huffb(data[i]); - _m3dstbiw___zlib_huff(256); - while (bitcount) - _m3dstbiw___zlib_add(0,1); - - for (i=0; i < _m3dstbiw___ZHASH; ++i) - (void) _m3dstbiw___sbfree(hash_table[i]); - STBIW_FREE(hash_table); - - { - unsigned int s1=1, s2=0; - int blocklen = (int) (data_len % 5552); - j=0; - while (j < data_len) { - for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; - s1 %= 65521, s2 %= 65521; - j += blocklen; - blocklen = 5552; - } - _m3dstbiw___sbpush(out, STBIW_UCHAR(s2 >> 8)); - _m3dstbiw___sbpush(out, STBIW_UCHAR(s2)); - _m3dstbiw___sbpush(out, STBIW_UCHAR(s1 >> 8)); - _m3dstbiw___sbpush(out, STBIW_UCHAR(s1)); - } - *out_len = _m3dstbiw___sbn(out); - STBIW_MEMMOVE(_m3dstbiw___sbraw(out), out, *out_len); - return (unsigned char *) _m3dstbiw___sbraw(out); -} -#define stbi_zlib_compress _m3dstbi_zlib_compress -#else -unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality); -#endif - -#define M3D_CHUNKMAGIC(m, a,b,c,d) ((m)[0]==(a) && (m)[1]==(b) && (m)[2]==(c) && (m)[3]==(d)) - -#ifdef M3D_ASCII -#include /* get sprintf */ -#include /* sprintf and strtod cares about number locale */ -#endif -#ifdef M3D_PROFILING -#include -#endif - -#if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII) -/* helper functions for the ASCII parser */ -static char *_m3d_findarg(char *s) { - while(s && *s && *s != ' ' && *s != '\t' && *s != '\r' && *s != '\n') s++; - while(s && *s && (*s == ' ' || *s == '\t')) s++; - return s; -} -static char *_m3d_findnl(char *s) { - while(s && *s && *s != '\r' && *s != '\n') s++; - if(*s == '\r') s++; - if(*s == '\n') s++; - return s; -} -static char *_m3d_gethex(char *s, uint32_t *ret) -{ - if(*s == '#') s++; - *ret = 0; - for(; *s; s++) { - if(*s >= '0' && *s <= '9') { *ret <<= 4; *ret += (uint32_t)(*s-'0'); } - else if(*s >= 'a' && *s <= 'f') { *ret <<= 4; *ret += (uint32_t)(*s-'a'+10); } - else if(*s >= 'A' && *s <= 'F') { *ret <<= 4; *ret += (uint32_t)(*s-'A'+10); } - else break; - } - return _m3d_findarg(s); -} -static char *_m3d_getint(char *s, uint32_t *ret) -{ - char *e = s; - if(!s || !*s || *s == '\r' || *s == '\n') return s; - for(; *e >= '0' && *e <= '9'; e++); - *ret = atoi(s); - return e; -} -static char *_m3d_getfloat(char *s, M3D_FLOAT *ret) -{ - char *e = s; - if(!s || !*s || *s == '\r' || *s == '\n') return s; - for(; *e == '-' || *e == '+' || *e == '.' || (*e >= '0' && *e <= '9') || *e == 'e' || *e == 'E'; e++); - *ret = (M3D_FLOAT)strtod(s, NULL); - return _m3d_findarg(e); -} -#endif -#if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_ASCII) || defined(M3D_EXPORTER)) -/* helper function to create safe strings */ -char *_m3d_safestr(char *in, int morelines) -{ - char *out, *o, *i = in; - int l; - if(!in || !*in) { - out = (char*)M3D_MALLOC(1); - if(!out) return NULL; - out[0] =0; - } else { - for(o = in, l = 0; *o && ((morelines & 1) || (*o != '\r' && *o != '\n')) && l < 256; o++, l++); - out = o = (char*)M3D_MALLOC(l+1); - if(!out) return NULL; - while(*i == ' ' || *i == '\t' || *i == '\r' || (morelines && *i == '\n')) i++; - for(; *i && (morelines || (*i != '\r' && *i != '\n')); i++) { - if(*i == '\r') continue; - if(*i == '\n') { - if(morelines >= 3 && o > out && *(o-1) == '\n') break; - if(i > in && *(i-1) == '\n') continue; - if(morelines & 1) { - if(morelines == 1) *o++ = '\r'; - *o++ = '\n'; - } else - break; - } else - if(*i == ' ' || *i == '\t') { - *o++ = morelines? ' ' : '_'; - } else - *o++ = !morelines && (*i == '/' || *i == '\\') ? '_' : *i; - } - for(; o > out && (*(o-1) == ' ' || *(o-1) == '\t' || *(o-1) == '\r' || *(o-1) == '\n'); o--); - *o = 0; - out = (char*)M3D_REALLOC(out, (uintptr_t)o - (uintptr_t)out + 1); - } - return out; -} -#endif -#ifndef M3D_NOIMPORTER -/* helper function to load and decode/generate a texture */ -M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char *fn) -{ - unsigned int i, len = 0; - unsigned char *buff = NULL; - char *fn2; - unsigned int w, h; - stbi__context s; - stbi__result_info ri; - - /* failsafe */ - if(!fn || !*fn) return M3D_UNDEF; - /* do we have loaded this texture already? */ - for(i = 0; i < model->numtexture; i++) - if(!strcmp(fn, model->texture[i].name)) return i; - /* see if it's inlined in the model */ - if(model->inlined) { - for(i = 0; i < model->numinlined; i++) - if(!strcmp(fn, model->inlined[i].name)) { - buff = model->inlined[i].data; - len = model->inlined[i].length; - freecb = NULL; - break; - } - } - /* try to load from external source */ - if(!buff && readfilecb) { - i = (unsigned int)strlen(fn); - if(i < 5 || fn[i - 4] != '.') { - fn2 = (char*)M3D_MALLOC(i + 5); - if(!fn2) { model->errcode = M3D_ERR_ALLOC; return M3D_UNDEF; } - memcpy(fn2, fn, i); - memcpy(fn2+i, ".png", 5); - buff = (*readfilecb)(fn2, &len); - M3D_FREE(fn2); - } - if(!buff) { - buff = (*readfilecb)(fn, &len); - if(!buff) return M3D_UNDEF; - } - } - /* add to textures array */ - i = model->numtexture++; - model->texture = (m3dtx_t*)M3D_REALLOC(model->texture, model->numtexture * sizeof(m3dtx_t)); - if(!model->texture) { - if(buff && freecb) (*freecb)(buff); - model->errcode = M3D_ERR_ALLOC; - return M3D_UNDEF; - } - model->texture[i].name = fn; - model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL; - if(buff) { - if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') { - s.read_from_callbacks = 0; - s.img_buffer = s.img_buffer_original = (unsigned char *) buff; - s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len; - /* don't use model->texture[i].w directly, it's a uint16_t */ - w = h = len = 0; - ri.bits_per_channel = 8; - model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri); - model->texture[i].w = w; - model->texture[i].h = h; - model->texture[i].f = (uint8_t)len; - } else { -#ifdef M3D_TX_INTERP - if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) { - M3D_LOG("Unable to generate texture"); - M3D_LOG(fn); - } -#else - M3D_LOG("Unimplemented interpreter"); - M3D_LOG(fn); -#endif - } - if(freecb) (*freecb)(buff); - } - if(!model->texture[i].d) - model->errcode = M3D_ERR_UNKIMG; - return i; -} - -/* helper function to load and generate a procedural surface */ -void _m3d_getpr(m3d_t *model, _unused m3dread_t readfilecb, _unused m3dfree_t freecb, _unused char *fn) -{ -#ifdef M3D_PR_INTERP - unsigned int i, len = 0; - unsigned char *buff = readfilecb && fn && *fn ? (*readfilecb)(fn, &len) : NULL; - - if(!buff && fn && *fn && model->inlined) { - for(i = 0; i < model->numinlined; i++) - if(!strcmp(fn, model->inlined[i].name)) { - buff = model->inlined[i].data; - len = model->inlined[i].length; - freecb = NULL; - break; - } - } - if(!buff || !len || (model->errcode = M3D_PR_INTERP(fn, buff, len, model)) != M3D_SUCCESS) { - M3D_LOG("Unable to generate procedural surface"); - M3D_LOG(fn); - model->errcode = M3D_ERR_UNKIMG; - } - if(freecb && buff) (*freecb)(buff); -#else - (void)readfilecb; - (void)freecb; - (void)fn; - M3D_LOG("Unimplemented interpreter"); - M3D_LOG(fn); - model->errcode = M3D_ERR_UNIMPL; -#endif -} -/* helpers to read indices from data stream */ -#define M3D_GETSTR(x) do{offs=0;data=_m3d_getidx(data,model->si_s,&offs);x=offs?((char*)model->raw+16+offs):NULL;}while(0) -_inline static unsigned char *_m3d_getidx(unsigned char *data, char type, M3D_INDEX *idx) -{ - switch(type) { - case 1: *idx = data[0] > 253 ? (int8_t)data[0] : data[0]; data++; break; - case 2: *idx = *((uint16_t*)data) > 65533 ? *((int16_t*)data) : *((uint16_t*)data); data += 2; break; - case 4: *idx = *((int32_t*)data); data += 4; break; - } - return data; -} - -#ifndef M3D_NOANIMATION -/* multiply 4 x 4 matrices. Do not use float *r[16] as argument, because some compilers misinterpret that as - * 16 pointers each pointing to a float, but we need a single pointer to 16 floats. */ -void _m3d_mul(M3D_FLOAT *r, M3D_FLOAT *a, M3D_FLOAT *b) -{ - r[ 0] = b[ 0] * a[ 0] + b[ 4] * a[ 1] + b[ 8] * a[ 2] + b[12] * a[ 3]; - r[ 1] = b[ 1] * a[ 0] + b[ 5] * a[ 1] + b[ 9] * a[ 2] + b[13] * a[ 3]; - r[ 2] = b[ 2] * a[ 0] + b[ 6] * a[ 1] + b[10] * a[ 2] + b[14] * a[ 3]; - r[ 3] = b[ 3] * a[ 0] + b[ 7] * a[ 1] + b[11] * a[ 2] + b[15] * a[ 3]; - r[ 4] = b[ 0] * a[ 4] + b[ 4] * a[ 5] + b[ 8] * a[ 6] + b[12] * a[ 7]; - r[ 5] = b[ 1] * a[ 4] + b[ 5] * a[ 5] + b[ 9] * a[ 6] + b[13] * a[ 7]; - r[ 6] = b[ 2] * a[ 4] + b[ 6] * a[ 5] + b[10] * a[ 6] + b[14] * a[ 7]; - r[ 7] = b[ 3] * a[ 4] + b[ 7] * a[ 5] + b[11] * a[ 6] + b[15] * a[ 7]; - r[ 8] = b[ 0] * a[ 8] + b[ 4] * a[ 9] + b[ 8] * a[10] + b[12] * a[11]; - r[ 9] = b[ 1] * a[ 8] + b[ 5] * a[ 9] + b[ 9] * a[10] + b[13] * a[11]; - r[10] = b[ 2] * a[ 8] + b[ 6] * a[ 9] + b[10] * a[10] + b[14] * a[11]; - r[11] = b[ 3] * a[ 8] + b[ 7] * a[ 9] + b[11] * a[10] + b[15] * a[11]; - r[12] = b[ 0] * a[12] + b[ 4] * a[13] + b[ 8] * a[14] + b[12] * a[15]; - r[13] = b[ 1] * a[12] + b[ 5] * a[13] + b[ 9] * a[14] + b[13] * a[15]; - r[14] = b[ 2] * a[12] + b[ 6] * a[13] + b[10] * a[14] + b[14] * a[15]; - r[15] = b[ 3] * a[12] + b[ 7] * a[13] + b[11] * a[14] + b[15] * a[15]; -} -/* calculate 4 x 4 matrix inverse */ -void _m3d_inv(M3D_FLOAT *m) -{ - M3D_FLOAT r[16]; - M3D_FLOAT det = - m[ 0]*m[ 5]*m[10]*m[15] - m[ 0]*m[ 5]*m[11]*m[14] + m[ 0]*m[ 6]*m[11]*m[13] - m[ 0]*m[ 6]*m[ 9]*m[15] - + m[ 0]*m[ 7]*m[ 9]*m[14] - m[ 0]*m[ 7]*m[10]*m[13] - m[ 1]*m[ 6]*m[11]*m[12] + m[ 1]*m[ 6]*m[ 8]*m[15] - - m[ 1]*m[ 7]*m[ 8]*m[14] + m[ 1]*m[ 7]*m[10]*m[12] - m[ 1]*m[ 4]*m[10]*m[15] + m[ 1]*m[ 4]*m[11]*m[14] - + m[ 2]*m[ 7]*m[ 8]*m[13] - m[ 2]*m[ 7]*m[ 9]*m[12] + m[ 2]*m[ 4]*m[ 9]*m[15] - m[ 2]*m[ 4]*m[11]*m[13] - + m[ 2]*m[ 5]*m[11]*m[12] - m[ 2]*m[ 5]*m[ 8]*m[15] - m[ 3]*m[ 4]*m[ 9]*m[14] + m[ 3]*m[ 4]*m[10]*m[13] - - m[ 3]*m[ 5]*m[10]*m[12] + m[ 3]*m[ 5]*m[ 8]*m[14] - m[ 3]*m[ 6]*m[ 8]*m[13] + m[ 3]*m[ 6]*m[ 9]*m[12]; - if(det == (M3D_FLOAT)0.0 || det == (M3D_FLOAT)-0.0) det = (M3D_FLOAT)1.0; else det = (M3D_FLOAT)1.0 / det; - r[ 0] = det *(m[ 5]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 7]*(m[ 9]*m[14] - m[10]*m[13])); - r[ 1] = -det*(m[ 1]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 3]*(m[ 9]*m[14] - m[10]*m[13])); - r[ 2] = det *(m[ 1]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[13] - m[ 5]*m[15]) + m[ 3]*(m[ 5]*m[14] - m[ 6]*m[13])); - r[ 3] = -det*(m[ 1]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 9] - m[ 5]*m[11]) + m[ 3]*(m[ 5]*m[10] - m[ 6]*m[ 9])); - r[ 4] = -det*(m[ 4]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[14] - m[10]*m[12])); - r[ 5] = det *(m[ 0]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[14] - m[10]*m[12])); - r[ 6] = -det*(m[ 0]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[14] - m[ 6]*m[12])); - r[ 7] = det *(m[ 0]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[10] - m[ 6]*m[ 8])); - r[ 8] = det *(m[ 4]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 5]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[13] - m[ 9]*m[12])); - r[ 9] = -det*(m[ 0]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 1]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[13] - m[ 9]*m[12])); - r[10] = det *(m[ 0]*(m[ 5]*m[15] - m[ 7]*m[13]) + m[ 1]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[13] - m[ 5]*m[12])); - r[11] = -det*(m[ 0]*(m[ 5]*m[11] - m[ 7]*m[ 9]) + m[ 1]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[ 9] - m[ 5]*m[ 8])); - r[12] = -det*(m[ 4]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 5]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 6]*(m[ 8]*m[13] - m[ 9]*m[12])); - r[13] = det *(m[ 0]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 1]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 2]*(m[ 8]*m[13] - m[ 9]*m[12])); - r[14] = -det*(m[ 0]*(m[ 5]*m[14] - m[ 6]*m[13]) + m[ 1]*(m[ 6]*m[12] - m[ 4]*m[14]) + m[ 2]*(m[ 4]*m[13] - m[ 5]*m[12])); - r[15] = det *(m[ 0]*(m[ 5]*m[10] - m[ 6]*m[ 9]) + m[ 1]*(m[ 6]*m[ 8] - m[ 4]*m[10]) + m[ 2]*(m[ 4]*m[ 9] - m[ 5]*m[ 8])); - memcpy(m, &r, sizeof(r)); -} -/* compose a coloumn major 4 x 4 matrix from vec3 position and vec4 orientation/rotation quaternion */ -void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q) -{ - if(q->x == (M3D_FLOAT)0.0 && q->y == (M3D_FLOAT)0.0 && q->z >=(M3D_FLOAT) 0.7071065 && q->z <= (M3D_FLOAT)0.7071075 && - q->w == (M3D_FLOAT)0.0) { - r[ 1] = r[ 2] = r[ 4] = r[ 6] = r[ 8] = r[ 9] = (M3D_FLOAT)0.0; - r[ 0] = r[ 5] = r[10] = (M3D_FLOAT)-1.0; - } else { - r[ 0] = 1 - 2 * (q->y * q->y + q->z * q->z); if(r[ 0]>-M3D_EPSILON && r[ 0]x * q->y - q->z * q->w); if(r[ 1]>-M3D_EPSILON && r[ 1]x * q->z + q->y * q->w); if(r[ 2]>-M3D_EPSILON && r[ 2]x * q->y + q->z * q->w); if(r[ 4]>-M3D_EPSILON && r[ 4]x * q->x + q->z * q->z); if(r[ 5]>-M3D_EPSILON && r[ 5]y * q->z - q->x * q->w); if(r[ 6]>-M3D_EPSILON && r[ 6]x * q->z - q->y * q->w); if(r[ 8]>-M3D_EPSILON && r[ 8]y * q->z + q->x * q->w); if(r[ 9]>-M3D_EPSILON && r[ 9]x * q->x + q->y * q->y); if(r[10]>-M3D_EPSILON && r[10]x; r[ 7] = p->y; r[11] = p->z; - r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; -} -#endif -#if !defined(M3D_NOANIMATION) || !defined(M3D_NONORMALS) -/* portable fast inverse square root calculation. returns 1/sqrt(x) */ -static M3D_FLOAT _m3d_rsq(M3D_FLOAT x) -{ -#ifdef M3D_DOUBLE - return ((M3D_FLOAT)15.0/(M3D_FLOAT)8.0) + ((M3D_FLOAT)-5.0/(M3D_FLOAT)4.0)*x + ((M3D_FLOAT)3.0/(M3D_FLOAT)8.0)*x*x; -#else - /* John Carmack's */ - float x2 = x * 0.5f; - uint32_t *i = (uint32_t*)&x; - *i = (0x5f3759df - (*i >> 1)); - return x * (1.5f - (x2 * x * x)); -#endif -} -#endif - -/** - * Function to decode a Model 3D into in-memory format - */ -m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib) -{ - unsigned char *end, *chunk, *buff, weights[8]; - unsigned int i, j, k, l, n, am, len = 0, reclen, offs; -#ifndef M3D_NOVOXELS - int32_t min_x, min_y, min_z, max_x, max_y, max_z, sx, sy, sz, x, y, z; - M3D_INDEX edge[8], enorm; -#endif - char *name, *lang; - float f; - m3d_t *model; - M3D_INDEX mi; -#ifdef M3D_VERTEXMAX - M3D_INDEX pi; -#endif - M3D_FLOAT w; - m3dcd_t *cd; - m3dtx_t *tx; - m3dh_t *h; - m3dm_t *m; - m3da_t *a; - m3di_t *t; -#ifndef M3D_NONORMALS - char neednorm = 0; - m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb; -#endif -#ifndef M3D_NOANIMATION - M3D_FLOAT r[16]; -#endif -#if !defined(M3D_NOWEIGHTS) || !defined(M3D_NOANIMATION) - m3db_t *b; -#endif -#ifndef M3D_NOWEIGHTS - m3ds_t *sk; -#endif -#ifdef M3D_ASCII - m3ds_t s; - M3D_INDEX bi[M3D_BONEMAXLEVEL+1], level; - const char *ol; - char *ptr, *pe, *fn; -#endif -#ifdef M3D_PROFILING - struct timeval tv0, tv1, tvd; - gettimeofday(&tv0, NULL); -#endif - - if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O') -#ifdef M3D_ASCII - && !M3D_CHUNKMAGIC(data, '3','d','m','o') -#endif - )) return NULL; - model = (m3d_t*)M3D_MALLOC(sizeof(m3d_t)); - if(!model) { - M3D_LOG("Out of memory"); - return NULL; - } - memset(model, 0, sizeof(m3d_t)); - - if(mtllib) { - model->nummaterial = mtllib->nummaterial; - model->material = mtllib->material; - model->numtexture = mtllib->numtexture; - model->texture = mtllib->texture; - model->flags |= M3D_FLG_MTLLIB; - } -#ifdef M3D_ASCII - /* ASCII variant? */ - if(M3D_CHUNKMAGIC(data, '3','d','m','o')) { - model->errcode = M3D_ERR_BADFILE; - model->flags |= M3D_FLG_FREESTR; - model->raw = (m3dhdr_t*)data; - ptr = (char*)data; - ol = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - /* parse header. Don't use sscanf, that's incredibly slow */ - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - pe = _m3d_findnl(ptr); - model->scale = (float)strtod(ptr, NULL); ptr = pe; - if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0; - model->name = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); - if(!*ptr) goto asciiend; - model->license = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); - if(!*ptr) goto asciiend; - model->author = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); - if(!*ptr) goto asciiend; - if(*ptr != '\r' && *ptr != '\n') - model->desc = _m3d_safestr(ptr, 3); - while(*ptr) { - while(*ptr && *ptr!='\n') ptr++; - ptr++; if(*ptr=='\r') ptr++; - if(*ptr == '\n') break; - } - - /* the main chunk reader loop */ - while(*ptr) { - while(*ptr && (*ptr == '\r' || *ptr == '\n')) ptr++; - if(!*ptr || (ptr[0]=='E' && ptr[1]=='n' && ptr[2]=='d')) break; - /* make sure there's at least one data row */ - pe = ptr; ptr = _m3d_findnl(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - /* Preview chunk */ - if(!memcmp(pe, "Preview", 7)) { - if(readfilecb) { - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - model->preview.data = (*readfilecb)(pe, &model->preview.length); - M3D_FREE(pe); - } - while(*ptr && *ptr != '\r' && *ptr != '\n') - ptr = _m3d_findnl(ptr); - } else - /* texture map chunk */ - if(!memcmp(pe, "Textmap", 7)) { - if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); goto asciiend; } - while(*ptr && *ptr != '\r' && *ptr != '\n') { - i = model->numtmap++; - model->tmap = (m3dti_t*)M3D_REALLOC(model->tmap, model->numtmap * sizeof(m3dti_t)); - if(!model->tmap) goto memerr; - ptr = _m3d_getfloat(ptr, &model->tmap[i].u); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - _m3d_getfloat(ptr, &model->tmap[i].v); - ptr = _m3d_findnl(ptr); - } - } else - /* vertex chunk */ - if(!memcmp(pe, "Vertex", 6)) { - if(model->vertex) { M3D_LOG("More vertex chunks, should be unique"); goto asciiend; } - while(*ptr && *ptr != '\r' && *ptr != '\n') { - i = model->numvertex++; - model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); - if(!model->vertex) goto memerr; - memset(&model->vertex[i], 0, sizeof(m3dv_t)); - model->vertex[i].skinid = M3D_UNDEF; - model->vertex[i].color = 0; - model->vertex[i].w = (M3D_FLOAT)1.0; - ptr = _m3d_getfloat(ptr, &model->vertex[i].x); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getfloat(ptr, &model->vertex[i].y); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getfloat(ptr, &model->vertex[i].z); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getfloat(ptr, &model->vertex[i].w); - if(!*ptr) goto asciiend; - if(*ptr == '#') { - ptr = _m3d_gethex(ptr, &model->vertex[i].color); - if(!*ptr) goto asciiend; - } - /* parse skin */ - memset(&s, 0, sizeof(m3ds_t)); - for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &k); - s.boneid[j] = (M3D_INDEX)k; - if(*ptr == ':') { - ptr++; - ptr = _m3d_getfloat(ptr, &s.weight[j]); - w += s.weight[j]; - } else if(!j) - s.weight[j] = (M3D_FLOAT)1.0; - if(!*ptr) goto asciiend; - } - if(s.boneid[0] != M3D_UNDEF && s.weight[0] > (M3D_FLOAT)0.0) { - if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) - for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++) - s.weight[j] /= w; - k = M3D_NOTDEFINED; - if(model->skin) { - for(j = 0; j < model->numskin; j++) - if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; } - } - if(k == M3D_NOTDEFINED) { - k = model->numskin++; - model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t)); - if(!model->skin) goto memerr; - memcpy(&model->skin[k], &s, sizeof(m3ds_t)); - } - model->vertex[i].skinid = (M3D_INDEX)k; - } - ptr = _m3d_findnl(ptr); - } - } else - /* Skeleton, bone hierarchy */ - if(!memcmp(pe, "Bones", 5)) { - if(model->bone) { M3D_LOG("More bones chunks, should be unique"); goto asciiend; } - bi[0] = M3D_UNDEF; - while(*ptr && *ptr != '\r' && *ptr != '\n') { - i = model->numbone++; - model->bone = (m3db_t*)M3D_REALLOC(model->bone, model->numbone * sizeof(m3db_t)); - if(!model->bone) goto memerr; - for(level = 0; *ptr == '/'; ptr++, level++); - if(level > M3D_BONEMAXLEVEL || !*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - bi[level+1] = i; - model->bone[i].numweight = 0; - model->bone[i].weight = NULL; - model->bone[i].parent = bi[level]; - ptr = _m3d_getint(ptr, &k); - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - model->bone[i].pos = (M3D_INDEX)k; - ptr = _m3d_getint(ptr, &k); - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - model->bone[i].ori = (M3D_INDEX)k; - model->vertex[k].skinid = M3D_INDEXMAX; - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - model->bone[i].name = pe; - ptr = _m3d_findnl(ptr); - } - } else - /* material chunk */ - if(!memcmp(pe, "Material", 8)) { - pe = _m3d_findarg(pe); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - pe = _m3d_safestr(pe, 0); - if(!pe || !*pe) goto asciiend; - for(i = 0; i < model->nummaterial; i++) - if(!strcmp(pe, model->material[i].name)) { - M3D_LOG("Multiple definitions for material"); - M3D_LOG(pe); - M3D_FREE(pe); - pe = NULL; - while(*ptr && *ptr != '\r' && *ptr != '\n') ptr = _m3d_findnl(ptr); - break; - } - if(!pe) continue; - i = model->nummaterial++; - if(model->flags & M3D_FLG_MTLLIB) { - m = model->material; - model->material = (m3dm_t*)M3D_MALLOC(model->nummaterial * sizeof(m3dm_t)); - if(!model->material) goto memerr; - memcpy(model->material, m, (model->nummaterial - 1) * sizeof(m3dm_t)); - if(model->texture) { - tx = model->texture; - model->texture = (m3dtx_t*)M3D_MALLOC(model->numtexture * sizeof(m3dtx_t)); - if(!model->texture) goto memerr; - memcpy(model->texture, tx, model->numtexture * sizeof(m3dm_t)); - } - model->flags &= ~M3D_FLG_MTLLIB; - } else { - model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); - if(!model->material) goto memerr; - } - m = &model->material[i]; - m->name = pe; - m->numprop = 0; - m->prop = NULL; - while(*ptr && *ptr != '\r' && *ptr != '\n') { - k = n = 256; - if(*ptr == 'm' && *(ptr+1) == 'a' && *(ptr+2) == 'p' && *(ptr+3) == '_') { - k = m3dpf_map; - ptr += 4; - } - for(j = 0; j < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); j++) - if(!memcmp(ptr, m3d_propertytypes[j].key, strlen(m3d_propertytypes[j].key))) { - n = m3d_propertytypes[j].id; - if(k != m3dpf_map) k = m3d_propertytypes[j].format; - break; - } - if(n != 256 && k != 256) { - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - j = m->numprop++; - m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); - if(!m->prop) goto memerr; - m->prop[j].type = n + (k == m3dpf_map && n < 128 ? 128 : 0); - switch(k) { - case m3dpf_color: ptr = _m3d_gethex(ptr, &m->prop[j].value.color); break; - case m3dpf_uint8: - case m3dpf_uint16: - case m3dpf_uint32: ptr = _m3d_getint(ptr, &m->prop[j].value.num); break; - case m3dpf_float: ptr = _m3d_getfloat(ptr, &m->prop[j].value.fnum); break; - case m3dpf_map: - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - m->prop[j].value.textureid = _m3d_gettx(model, readfilecb, freecb, pe); - if(model->errcode == M3D_ERR_ALLOC) { M3D_FREE(pe); goto memerr; } - /* this error code only returned if readfilecb was specified */ - if(m->prop[j].value.textureid == M3D_UNDEF) { - M3D_LOG("Texture not found"); - M3D_LOG(pe); - m->numprop--; - } - M3D_FREE(pe); - break; - } - } else { - M3D_LOG("Unknown material property in"); - M3D_LOG(m->name); - model->errcode = M3D_ERR_UNKPROP; - } - ptr = _m3d_findnl(ptr); - } - if(!m->numprop) model->nummaterial--; - } else - /* procedural */ - if(!memcmp(pe, "Procedural", 10)) { - pe = _m3d_safestr(ptr, 0); - _m3d_getpr(model, readfilecb, freecb, pe); - M3D_FREE(pe); - while(*ptr && *ptr != '\r' && *ptr != '\n') ptr = _m3d_findnl(ptr); - } else - /* mesh */ - if(!memcmp(pe, "Mesh", 4)) { - mi = M3D_UNDEF; -#ifdef M3D_VERTEXMAX - pi = M3D_UNDEF; -#endif - while(*ptr && *ptr != '\r' && *ptr != '\n') { - if(*ptr == 'u') { - ptr = _m3d_findarg(ptr); - if(!*ptr) goto asciiend; - mi = M3D_UNDEF; - if(*ptr != '\r' && *ptr != '\n') { - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - for(j = 0; j < model->nummaterial; j++) - if(!strcmp(pe, model->material[j].name)) { mi = (M3D_INDEX)j; break; } - if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { - mi = model->nummaterial++; - model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); - if(!model->material) goto memerr; - model->material[mi].name = pe; - model->material[mi].numprop = 1; - model->material[mi].prop = NULL; - } else - M3D_FREE(pe); - } - } else - if(*ptr == 'p') { - ptr = _m3d_findarg(ptr); - if(!*ptr) goto asciiend; -#ifdef M3D_VERTEXMAX - pi = M3D_UNDEF; - if(*ptr != '\r' && *ptr != '\n') { - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - for(j = 0; j < model->numparam; j++) - if(!strcmp(pe, model->param[j].name)) { pi = (M3D_INDEX)j; break; } - if(pi == M3D_UNDEF) { - pi = model->numparam++; - model->param = (m3dvi_t*)M3D_REALLOC(model->param, model->numparam * sizeof(m3dvi_t)); - if(!model->param) goto memerr; - model->param[pi].name = pe; - model->param[pi].count = 0; - } else - M3D_FREE(pe); - } -#endif - } else { - i = model->numface++; - model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); - if(!model->face) goto memerr; - memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */ - model->face[i].materialid = mi; -#ifdef M3D_VERTEXMAX - model->face[i].paramid = pi; -#endif - /* hardcoded triangles. */ - for(j = 0; j < 3; j++) { - /* vertex */ - ptr = _m3d_getint(ptr, &k); - model->face[i].vertex[j] = (M3D_INDEX)k; - if(!*ptr) goto asciiend; - if(*ptr == '/') { - ptr++; - if(*ptr != '/') { - /* texcoord */ - ptr = _m3d_getint(ptr, &k); - model->face[i].texcoord[j] = (M3D_INDEX)k; - if(!*ptr) goto asciiend; - } - if(*ptr == '/') { - ptr++; - /* normal */ - ptr = _m3d_getint(ptr, &k); - model->face[i].normal[j] = (M3D_INDEX)k; - if(!*ptr) goto asciiend; - } - if(*ptr == '/') { - ptr++; - /* maximum */ - ptr = _m3d_getint(ptr, &k); -#ifdef M3D_VERTEXMAX - model->face[i].vertmax[j] = (M3D_INDEX)k; -#endif - if(!*ptr) goto asciiend; - } - } -#ifndef M3D_NONORMALS - if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; -#endif - ptr = _m3d_findarg(ptr); - } - } - ptr = _m3d_findnl(ptr); - } - } else - /* voxel types chunk */ - if(!memcmp(pe, "VoxTypes", 8) || !memcmp(pe, "Voxtypes", 8)) { - if(model->voxtype) { M3D_LOG("More voxel types chunks, should be unique"); goto asciiend; } - while(*ptr && *ptr != '\r' && *ptr != '\n') { - i = model->numvoxtype++; - model->voxtype = (m3dvt_t*)M3D_REALLOC(model->voxtype, model->numvoxtype * sizeof(m3dvt_t)); - if(!model->voxtype) goto memerr; - memset(&model->voxtype[i], 0, sizeof(m3dvt_t)); - model->voxtype[i].materialid = M3D_UNDEF; - model->voxtype[i].skinid = M3D_UNDEF; - ptr = _m3d_gethex(ptr, &model->voxtype[i].color); - if(!*ptr) goto asciiend; - if(*ptr == '/') { - ptr = _m3d_gethex(ptr, &k); - model->voxtype[i].rotation = k; - if(!*ptr) goto asciiend; - if(*ptr == '/') { - ptr = _m3d_gethex(ptr, &k); - model->voxtype[i].voxshape = k; - if(!*ptr) goto asciiend; - } - } - while(*ptr == ' ' || *ptr == '\t') ptr++; - if(*ptr == '\r' || *ptr == '\n') { ptr = _m3d_findnl(ptr); continue; } - /* name */ - if(*ptr != '-') { - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - model->voxtype[i].name = pe; - for(j = 0; j < model->nummaterial; j++) - if(!strcmp(pe, model->material[j].name)) { model->voxtype[i].materialid = (M3D_INDEX)j; break; } - } - ptr = _m3d_findarg(ptr); - /* parse skin */ - memset(&s, 0, sizeof(m3ds_t)); - for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '{' && *ptr != '\r' && *ptr != '\n'; j++) { - ptr = _m3d_getint(ptr, &k); - s.boneid[j] = (M3D_INDEX)k; - if(*ptr == ':') { - ptr++; - ptr = _m3d_getfloat(ptr, &s.weight[j]); - w += s.weight[j]; - } else if(!j) - s.weight[j] = (M3D_FLOAT)1.0; - if(!*ptr) goto asciiend; - ptr = _m3d_findarg(ptr); - } - if(s.boneid[0] != M3D_UNDEF && s.weight[0] > (M3D_FLOAT)0.0) { - if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) - for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++) - s.weight[j] /= w; - k = M3D_NOTDEFINED; - if(model->skin) { - for(j = 0; j < model->numskin; j++) - if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; } - } - if(k == M3D_NOTDEFINED) { - k = model->numskin++; - model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t)); - if(!model->skin) goto memerr; - memcpy(&model->skin[k], &s, sizeof(m3ds_t)); - } - model->voxtype[i].skinid = (M3D_INDEX)k; - } - /* parse item list */ - if(*ptr == '{') { - while(*ptr == '{' || *ptr == ' ' || *ptr == '\t') ptr++; - while(*ptr && *ptr != '}' && *ptr != '\r' && *ptr != '\n') { - ptr = _m3d_getint(ptr, &k); - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '}' || *ptr == '\r' || *ptr == '\n') goto asciiend; - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - ptr = _m3d_findarg(ptr); - j = model->voxtype[i].numitem++; - model->voxtype[i].item = (m3dvi_t*)M3D_REALLOC(model->voxtype[i].item, - model->voxtype[i].numitem * sizeof(m3dvi_t)); - if(!model->voxtype[i].item) goto memerr; - model->voxtype[i].item[j].count = k; - model->voxtype[i].item[j].name = pe; - } - if(*ptr != '}') goto asciiend; - } - ptr = _m3d_findnl(ptr); - } - } else - /* voxel data */ - if(!memcmp(pe, "Voxel", 5)) { - if(!model->voxtype) { M3D_LOG("No voxel type chunk before voxel data"); goto asciiend; } - pe = _m3d_findarg(pe); - if(!*pe) goto asciiend; - if(*pe == '\r' || *pe == '\n') pe = NULL; - else pe = _m3d_safestr(pe, 0); - i = model->numvoxel++; - model->voxel = (m3dvx_t*)M3D_REALLOC(model->voxel, model->numvoxel * sizeof(m3dvx_t)); - if(!model->voxel) goto memerr; - memset(&model->voxel[i], 0, sizeof(m3dvx_t)); - model->voxel[i].name = pe; - k = l = 0; - while(*ptr && *ptr != '\r' && *ptr != '\n') { - switch(*ptr) { - case 'u': - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].uncertain = ((n > 0 && n < 256 ? n : 0) * 255) / 100; - ptr = _m3d_findarg(ptr); - if(*ptr && *ptr != '\r' && *ptr != '\n') { - ptr = _m3d_getint(ptr, &n); - model->voxel[i].groupid = n > 0 && n < 256 ? n : 0; - } - break; - case 'p': - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].x = n; - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].y = n; - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].z = n; - break; - case 'd': - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].w = n; - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].h = n; - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getint(ptr, &n); - model->voxel[i].d = n; - break; - case 'l': - if(model->voxel[i].data) { l++; k = 0; } - else { - if(!model->voxel[i].w || !model->voxel[i].h || !model->voxel[i].d) { - M3D_LOG("No voxel dimension before layer data"); - goto asciiend; - } - model->voxel[i].data = (M3D_VOXEL*)M3D_MALLOC( - model->voxel[i].w * model->voxel[i].h * model->voxel[i].d * sizeof(M3D_VOXEL)); - if(!model->voxel[i].data) goto memerr; - } - break; - default: - if(!model->voxel[i].data || l >= model->voxel[i].h || k >= model->voxel[i].d) { - M3D_LOG("Missing voxel attributes or out of bound data"); - goto asciiend; - } - for(n = l * model->voxel[i].w * model->voxel[i].d + k * model->voxel[i].w; - j < model->voxel[i].w && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { - ptr = _m3d_getint(ptr, &am); - if(am >= model->numvoxtype) goto asciiend; - model->voxel[i].data[n + j] = am; - } - k++; - break; - } - ptr = _m3d_findnl(ptr); - } - } else - /* mathematical shape */ - if(!memcmp(pe, "Shape", 5)) { - pe = _m3d_findarg(pe); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - pe = _m3d_safestr(pe, 0); - if(!pe || !*pe) goto asciiend; - i = model->numshape++; - model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3ds_t)); - if(!model->shape) goto memerr; - h = &model->shape[i]; - h->name = pe; - h->group = M3D_UNDEF; - h->numcmd = 0; - h->cmd = NULL; - while(*ptr && *ptr != '\r' && *ptr != '\n') { - if(!memcmp(ptr, "group", 5)) { - ptr = _m3d_findarg(ptr); - ptr = _m3d_getint(ptr, &h->group); - ptr = _m3d_findnl(ptr); - if(h->group != M3D_UNDEF && h->group >= model->numbone) { - M3D_LOG("Unknown bone id as shape group in shape"); - M3D_LOG(pe); - h->group = M3D_UNDEF; - model->errcode = M3D_ERR_SHPE; - } - continue; - } - for(cd = NULL, k = 0; k < (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])); k++) { - j = (unsigned int)strlen(m3d_commandtypes[k].key); - if(!memcmp(ptr, m3d_commandtypes[k].key, j) && (ptr[j] == ' ' || ptr[j] == '\r' || ptr[j] == '\n')) - { cd = &m3d_commandtypes[k]; break; } - } - if(cd) { - j = h->numcmd++; - h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); - if(!h->cmd) goto memerr; - h->cmd[j].type = k; - h->cmd[j].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); - if(!h->cmd[j].arg) goto memerr; - memset(h->cmd[j].arg, 0, cd->p * sizeof(uint32_t)); - for(k = n = 0, l = cd->p; k < l; k++) { - ptr = _m3d_findarg(ptr); - if(!*ptr) goto asciiend; - if(*ptr == '[') { - ptr = _m3d_findarg(ptr + 1); - if(!*ptr) goto asciiend; - } - if(*ptr == ']' || *ptr == '\r' || *ptr == '\n') break; - switch(cd->a[((k - n) % (cd->p - n)) + n]) { - case m3dcp_mi_t: - mi = M3D_UNDEF; - if(*ptr != '\r' && *ptr != '\n') { - pe = _m3d_safestr(ptr, 0); - if(!pe || !*pe) goto asciiend; - for(n = 0; n < model->nummaterial; n++) - if(!strcmp(pe, model->material[n].name)) { mi = (M3D_INDEX)n; break; } - if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { - mi = model->nummaterial++; - model->material = (m3dm_t*)M3D_REALLOC(model->material, - model->nummaterial * sizeof(m3dm_t)); - if(!model->material) goto memerr; - model->material[mi].name = pe; - model->material[mi].numprop = 1; - model->material[mi].prop = NULL; - } else - M3D_FREE(pe); - } - h->cmd[j].arg[k] = mi; - break; - case m3dcp_vc_t: -#ifdef M3D_DOUBLE - _m3d_getfloat(ptr, &w); f = w; - memcpy(&h->cmd[j].arg[k], &f, 4); -#else - _m3d_getfloat(ptr, (float*)&h->cmd[j].arg[k]); -#endif - break; - case m3dcp_va_t: - ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); - n = k + 1; l += (h->cmd[j].arg[k] - 1) * (cd->p - k - 1); - h->cmd[j].arg = (uint32_t*)M3D_REALLOC(h->cmd[j].arg, l * sizeof(uint32_t)); - if(!h->cmd[j].arg) goto memerr; - memset(&h->cmd[j].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); - break; - case m3dcp_qi_t: - ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); - model->vertex[h->cmd[i].arg[k]].skinid = M3D_INDEXMAX; - break; - default: - ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); - break; - } - } - } else { - M3D_LOG("Unknown shape command in"); - M3D_LOG(h->name); - model->errcode = M3D_ERR_UNKCMD; - } - ptr = _m3d_findnl(ptr); - } - if(!h->numcmd) model->numshape--; - } else - /* annotation labels */ - if(!memcmp(pe, "Labels", 6)) { - pe = _m3d_findarg(pe); - if(!*pe) goto asciiend; - if(*pe == '\r' || *pe == '\n') pe = NULL; - else pe = _m3d_safestr(pe, 0); - k = 0; fn = NULL; - while(*ptr && *ptr != '\r' && *ptr != '\n') { - if(*ptr == 'c') { - ptr = _m3d_findarg(ptr); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - ptr = _m3d_gethex(ptr, &k); - } else - if(*ptr == 'l') { - ptr = _m3d_findarg(ptr); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - fn = _m3d_safestr(ptr, 2); - } else { - i = model->numlabel++; - model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); - if(!model->label) goto memerr; - model->label[i].name = pe; - model->label[i].lang = fn; - model->label[i].color = k; - ptr = _m3d_getint(ptr, &j); - model->label[i].vertexid = (M3D_INDEX)j; - ptr = _m3d_findarg(ptr); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - model->label[i].text = _m3d_safestr(ptr, 2); - } - ptr = _m3d_findnl(ptr); - } - } else - /* action */ - if(!memcmp(pe, "Action", 6)) { - pe = _m3d_findarg(pe); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - pe = _m3d_getint(pe, &k); - pe = _m3d_findarg(pe); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - pe = _m3d_safestr(pe, 0); - if(!pe || !*pe) goto asciiend; - i = model->numaction++; - model->action = (m3da_t*)M3D_REALLOC(model->action, model->numaction * sizeof(m3da_t)); - if(!model->action) goto memerr; - a = &model->action[i]; - a->name = pe; - a->durationmsec = k; - /* skip the first frame marker as there's always at least one frame */ - a->numframe = 1; - a->frame = (m3dfr_t*)M3D_MALLOC(sizeof(m3dfr_t)); - if(!a->frame) goto memerr; - a->frame[0].msec = 0; - a->frame[0].numtransform = 0; - a->frame[0].transform = NULL; - i = 0; - if(*ptr == 'f') - ptr = _m3d_findnl(ptr); - while(*ptr && *ptr != '\r' && *ptr != '\n') { - if(*ptr == 'f') { - i = a->numframe++; - a->frame = (m3dfr_t*)M3D_REALLOC(a->frame, a->numframe * sizeof(m3dfr_t)); - if(!a->frame) goto memerr; - ptr = _m3d_findarg(ptr); - ptr = _m3d_getint(ptr, &a->frame[i].msec); - a->frame[i].numtransform = 0; - a->frame[i].transform = NULL; - } else { - j = a->frame[i].numtransform++; - a->frame[i].transform = (m3dtr_t*)M3D_REALLOC(a->frame[i].transform, - a->frame[i].numtransform * sizeof(m3dtr_t)); - if(!a->frame[i].transform) goto memerr; - ptr = _m3d_getint(ptr, &k); - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - a->frame[i].transform[j].boneid = (M3D_INDEX)k; - ptr = _m3d_getint(ptr, &k); - ptr = _m3d_findarg(ptr); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - a->frame[i].transform[j].pos = (M3D_INDEX)k; - ptr = _m3d_getint(ptr, &k); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - a->frame[i].transform[j].ori = (M3D_INDEX)k; - model->vertex[k].skinid = M3D_INDEXMAX; - } - ptr = _m3d_findnl(ptr); - } - } else - /* inlined assets chunk */ - if(!memcmp(pe, "Assets", 6)) { - while(*ptr && *ptr != '\r' && *ptr != '\n') { - if(readfilecb) { - pe = _m3d_safestr(ptr, 2); - if(!pe || !*pe) goto asciiend; - i = model->numinlined++; - model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t)); - if(!model->inlined) goto memerr; - t = &model->inlined[i]; - model->inlined[i].data = (*readfilecb)(pe, &model->inlined[i].length); - if(model->inlined[i].data) { - fn = strrchr(pe, '.'); - if(fn && (fn[1] == 'p' || fn[1] == 'P') && (fn[2] == 'n' || fn[2] == 'N') && - (fn[3] == 'g' || fn[3] == 'G')) *fn = 0; - fn = strrchr(pe, '/'); - if(!fn) fn = strrchr(pe, '\\'); - if(!fn) fn = pe; else fn++; - model->inlined[i].name = _m3d_safestr(fn, 0); - } else - model->numinlined--; - M3D_FREE(pe); - } - ptr = _m3d_findnl(ptr); - } - } else - /* extra chunks */ - if(!memcmp(pe, "Extra", 5)) { - pe = _m3d_findarg(pe); - if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; - buff = (unsigned char*)_m3d_findnl(ptr); - k = ((uint32_t)((uintptr_t)buff - (uintptr_t)ptr) / 3) + 1; - i = model->numextra++; - model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); - if(!model->extra) goto memerr; - model->extra[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t)); - if(!model->extra[i]) goto memerr; - memcpy(&model->extra[i]->magic, pe, 4); - model->extra[i]->length = sizeof(m3dchunk_t); - pe = (char*)model->extra[i] + sizeof(m3dchunk_t); - while(*ptr && *ptr != '\r' && *ptr != '\n') { - ptr = _m3d_gethex(ptr, &k); - *pe++ = (uint8_t)k; - model->extra[i]->length++; - } - } else - goto asciiend; - } - model->errcode = M3D_SUCCESS; -asciiend: - setlocale(LC_NUMERIC, ol); - goto postprocess; - } -#endif - /* Binary variant */ - len = ((m3dhdr_t*)data)->length - 8; - data += 8; - if(M3D_CHUNKMAGIC(data, 'P','R','V','W')) { - /* optional preview chunk */ - model->preview.length = ((m3dchunk_t*)data)->length; - model->preview.data = data + sizeof(m3dchunk_t); - data += model->preview.length; - len -= model->preview.length; - } - if(!M3D_CHUNKMAGIC(data, 'H','E','A','D')) { - buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data, len, 4096, (int*)&len, 1); - if(!buff || !len || !M3D_CHUNKMAGIC(buff, 'H','E','A','D')) { - if(buff) M3D_FREE(buff); - M3D_FREE(model); - return NULL; - } - buff = (unsigned char*)M3D_REALLOC(buff, len); - model->flags |= M3D_FLG_FREERAW; /* mark that we have to free the raw buffer */ - data = buff; -#ifdef M3D_PROFILING - gettimeofday(&tv1, NULL); - tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; - tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; - if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } - printf(" Deflate model %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); - memcpy(&tv0, &tv1, sizeof(struct timeval)); -#endif - } - model->raw = (m3dhdr_t*)data; - end = data + len; - - /* parse header */ - data += sizeof(m3dhdr_t); - M3D_LOG((char*)data); - model->name = (char*)data; - for(; data < end && *data; data++) {}; data++; - model->license = (char*)data; - for(; data < end && *data; data++) {}; data++; - model->author = (char*)data; - for(; data < end && *data; data++) {}; data++; - model->desc = (char*)data; - chunk = (unsigned char*)model->raw + model->raw->length; - model->scale = (M3D_FLOAT)model->raw->scale; - if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0; - model->vc_s = 1 << ((model->raw->types >> 0) & 3); /* vertex coordinate size */ - model->vi_s = 1 << ((model->raw->types >> 2) & 3); /* vertex index size */ - model->si_s = 1 << ((model->raw->types >> 4) & 3); /* string offset size */ - model->ci_s = 1 << ((model->raw->types >> 6) & 3); /* color index size */ - model->ti_s = 1 << ((model->raw->types >> 8) & 3); /* tmap index size */ - model->bi_s = 1 << ((model->raw->types >>10) & 3); /* bone index size */ - model->nb_s = 1 << ((model->raw->types >>12) & 3); /* number of bones per vertex */ - model->sk_s = 1 << ((model->raw->types >>14) & 3); /* skin index size */ - model->fc_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */ - model->hi_s = 1 << ((model->raw->types >>18) & 3); /* shape index size */ - model->fi_s = 1 << ((model->raw->types >>20) & 3); /* face index size */ - model->vd_s = 1 << ((model->raw->types >>22) & 3); /* voxel dimension size */ - model->vp_s = 1 << ((model->raw->types >>24) & 3); /* voxel pixel size */ - if(model->ci_s == 8) model->ci_s = 0; /* optional indices */ - if(model->ti_s == 8) model->ti_s = 0; - if(model->bi_s == 8) model->bi_s = 0; - if(model->sk_s == 8) model->sk_s = 0; - if(model->fc_s == 8) model->fc_s = 0; - if(model->hi_s == 8) model->hi_s = 0; - if(model->fi_s == 8) model->fi_s = 0; - - /* variable limit checks */ - if(sizeof(M3D_FLOAT) == 4 && model->vc_s > 4) { - M3D_LOG("Double precision coordinates not supported, truncating to float..."); - model->errcode = M3D_ERR_TRUNC; - } - if((sizeof(M3D_INDEX) == 2 && (model->vi_s > 2 || model->si_s > 2 || model->ci_s > 2 || model->ti_s > 2 || - model->bi_s > 2 || model->sk_s > 2 || model->fc_s > 2 || model->hi_s > 2 || model->fi_s > 2)) || - (sizeof(M3D_VOXEL) < (size_t)model->vp_s && model->vp_s != 8)) { - M3D_LOG("32 bit indices not supported, unable to load model"); - M3D_FREE(model); - return NULL; - } - if(model->vi_s > 4 || model->si_s > 4 || model->vp_s == 4) { - M3D_LOG("Invalid index size, unable to load model"); - M3D_FREE(model); - return NULL; - } - if(!M3D_CHUNKMAGIC(end - 4, 'O','M','D','3')) { - M3D_LOG("Missing end chunk"); - M3D_FREE(model); - return NULL; - } - if(model->nb_s > M3D_NUMBONE) { - M3D_LOG("Model has more bones per vertex than what importer was configured to support"); - model->errcode = M3D_ERR_TRUNC; - } - - /* look for inlined assets in advance, material and procedural chunks may need them */ - buff = chunk; - while(buff < end && !M3D_CHUNKMAGIC(buff, 'O','M','D','3')) { - data = buff; - len = ((m3dchunk_t*)data)->length; - buff += len; - if(len < sizeof(m3dchunk_t) || buff >= end) { - M3D_LOG("Invalid chunk size"); - break; - } - len -= sizeof(m3dchunk_t) + model->si_s; - - /* inlined assets */ - if(M3D_CHUNKMAGIC(data, 'A','S','E','T') && len > 0) { - M3D_LOG("Inlined asset"); - i = model->numinlined++; - model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t)); - if(!model->inlined) { -memerr: M3D_LOG("Out of memory"); - model->errcode = M3D_ERR_ALLOC; - return model; - } - data += sizeof(m3dchunk_t); - t = &model->inlined[i]; - M3D_GETSTR(t->name); - M3D_LOG(t->name); - t->data = (uint8_t*)data; - t->length = len; - } - } - - /* parse chunks */ - while(chunk < end && !M3D_CHUNKMAGIC(chunk, 'O','M','D','3')) { - data = chunk; - len = ((m3dchunk_t*)chunk)->length; - chunk += len; - if(len < sizeof(m3dchunk_t) || chunk >= end) { - M3D_LOG("Invalid chunk size"); - break; - } - len -= sizeof(m3dchunk_t); - - /* color map */ - if(M3D_CHUNKMAGIC(data, 'C','M','A','P')) { - M3D_LOG("Color map"); - if(model->cmap) { M3D_LOG("More color map chunks, should be unique"); model->errcode = M3D_ERR_CMAP; continue; } - if(!model->ci_s) { M3D_LOG("Color map chunk, shouldn't be any"); model->errcode = M3D_ERR_CMAP; continue; } - model->numcmap = len / sizeof(uint32_t); - model->cmap = (uint32_t*)(data + sizeof(m3dchunk_t)); - } else - /* texture map */ - if(M3D_CHUNKMAGIC(data, 'T','M','A','P')) { - M3D_LOG("Texture map"); - if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); model->errcode = M3D_ERR_TMAP; continue; } - if(!model->ti_s) { M3D_LOG("Texture map chunk, shouldn't be any"); model->errcode = M3D_ERR_TMAP; continue; } - reclen = model->vc_s + model->vc_s; - model->numtmap = len / reclen; - model->tmap = (m3dti_t*)M3D_MALLOC(model->numtmap * sizeof(m3dti_t)); - if(!model->tmap) goto memerr; - for(i = 0, data += sizeof(m3dchunk_t); data < chunk; i++) { - switch(model->vc_s) { - case 1: - model->tmap[i].u = (M3D_FLOAT)((uint8_t)data[0]) / (M3D_FLOAT)255.0; - model->tmap[i].v = (M3D_FLOAT)((uint8_t)data[1]) / (M3D_FLOAT)255.0; - break; - case 2: - model->tmap[i].u = (M3D_FLOAT)(*((uint16_t*)(data+0))) / (M3D_FLOAT)65535.0; - model->tmap[i].v = (M3D_FLOAT)(*((uint16_t*)(data+2))) / (M3D_FLOAT)65535.0; - break; - case 4: - model->tmap[i].u = (M3D_FLOAT)(*((float*)(data+0))); - model->tmap[i].v = (M3D_FLOAT)(*((float*)(data+4))); - break; - case 8: - model->tmap[i].u = (M3D_FLOAT)(*((double*)(data+0))); - model->tmap[i].v = (M3D_FLOAT)(*((double*)(data+8))); - break; - } - data += reclen; - } - } else - /* vertex list */ - if(M3D_CHUNKMAGIC(data, 'V','R','T','S')) { - M3D_LOG("Vertex list"); - if(model->vertex) { M3D_LOG("More vertex chunks, should be unique"); model->errcode = M3D_ERR_VRTS; continue; } - if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; - reclen = model->ci_s + model->sk_s + 4 * model->vc_s; - model->numvertex = len / reclen; - model->vertex = (m3dv_t*)M3D_MALLOC(model->numvertex * sizeof(m3dv_t)); - if(!model->vertex) goto memerr; - memset(model->vertex, 0, model->numvertex * sizeof(m3dv_t)); - for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < model->numvertex; i++) { - switch(model->vc_s) { - case 1: - model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / (M3D_FLOAT)127.0; - model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / (M3D_FLOAT)127.0; - model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / (M3D_FLOAT)127.0; - model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / (M3D_FLOAT)127.0; - data += 4; - break; - case 2: - model->vertex[i].x = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)32767.0; - model->vertex[i].y = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)32767.0; - model->vertex[i].z = (M3D_FLOAT)(*((int16_t*)(data+4))) / (M3D_FLOAT)32767.0; - model->vertex[i].w = (M3D_FLOAT)(*((int16_t*)(data+6))) / (M3D_FLOAT)32767.0; - data += 8; - break; - case 4: - model->vertex[i].x = (M3D_FLOAT)(*((float*)(data+0))); - model->vertex[i].y = (M3D_FLOAT)(*((float*)(data+4))); - model->vertex[i].z = (M3D_FLOAT)(*((float*)(data+8))); - model->vertex[i].w = (M3D_FLOAT)(*((float*)(data+12))); - data += 16; - break; - case 8: - model->vertex[i].x = (M3D_FLOAT)(*((double*)(data+0))); - model->vertex[i].y = (M3D_FLOAT)(*((double*)(data+8))); - model->vertex[i].z = (M3D_FLOAT)(*((double*)(data+16))); - model->vertex[i].w = (M3D_FLOAT)(*((double*)(data+24))); - data += 32; - break; - } - switch(model->ci_s) { - case 1: model->vertex[i].color = model->cmap ? model->cmap[data[0]] : 0; data++; break; - case 2: model->vertex[i].color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; - case 4: model->vertex[i].color = *((uint32_t*)data); data += 4; break; - /* case 8: break; */ - } - model->vertex[i].skinid = M3D_UNDEF; - data = _m3d_getidx(data, model->sk_s, &model->vertex[i].skinid); - } - } else - /* skeleton: bone hierarchy and skin */ - if(M3D_CHUNKMAGIC(data, 'B','O','N','E')) { - M3D_LOG("Skeleton"); - if(model->bone) { M3D_LOG("More bone chunks, should be unique"); model->errcode = M3D_ERR_BONE; continue; } - if(!model->bi_s) { M3D_LOG("Bone chunk, shouldn't be any"); model->errcode=M3D_ERR_BONE; continue; } - if(!model->vertex) { M3D_LOG("No vertex chunk before bones"); model->errcode = M3D_ERR_VRTS; break; } - data += sizeof(m3dchunk_t); - model->numbone = 0; - data = _m3d_getidx(data, model->bi_s, &model->numbone); - if(model->numbone) { - model->bone = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t)); - if(!model->bone) goto memerr; - } - model->numskin = 0; - data = _m3d_getidx(data, model->sk_s, &model->numskin); - /* read bone hierarchy */ - for(i = 0; data < chunk && i < model->numbone; i++) { - data = _m3d_getidx(data, model->bi_s, &model->bone[i].parent); - M3D_GETSTR(model->bone[i].name); - data = _m3d_getidx(data, model->vi_s, &model->bone[i].pos); - data = _m3d_getidx(data, model->vi_s, &model->bone[i].ori); - model->bone[i].numweight = 0; - model->bone[i].weight = NULL; - } - if(i != model->numbone) { M3D_LOG("Truncated bone chunk"); model->numbone = i; model->numskin = 0; model->errcode = M3D_ERR_BONE; } - /* read skin definitions */ - if(model->numskin) { - model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); - if(!model->skin) goto memerr; - for(i = 0; data < chunk && i < model->numskin; i++) { - for(j = 0; j < M3D_NUMBONE; j++) { - model->skin[i].boneid[j] = M3D_UNDEF; - model->skin[i].weight[j] = (M3D_FLOAT)0.0; - } - memset(&weights, 0, sizeof(weights)); - if(model->nb_s == 1) weights[0] = 255; - else { - memcpy(&weights, data, model->nb_s); - data += model->nb_s; - } - for(j = 0, w = (M3D_FLOAT)0.0; j < (unsigned int)model->nb_s; j++) { - if(weights[j]) { - if(j >= M3D_NUMBONE) - data += model->bi_s; - else { - model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / (M3D_FLOAT)255.0; - w += model->skin[i].weight[j]; - data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]); - } - } - } - /* this can occur if model has more bones than what the importer is configured to handle */ - if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) { - for(j = 0; j < M3D_NUMBONE; j++) - model->skin[i].weight[j] /= w; - } - } - if(i != model->numskin) { M3D_LOG("Truncated skin in bone chunk"); model->numskin = i; model->errcode = M3D_ERR_BONE; } - } - } else - /* material */ - if(M3D_CHUNKMAGIC(data, 'M','T','R','L')) { - data += sizeof(m3dchunk_t); - M3D_GETSTR(name); - M3D_LOG("Material"); - M3D_LOG(name); - if(model->ci_s < 4 && !model->numcmap) model->errcode = M3D_ERR_CMAP; - for(i = 0; i < model->nummaterial; i++) - if(!strcmp(name, model->material[i].name)) { - model->errcode = M3D_ERR_MTRL; - M3D_LOG("Multiple definitions for material"); - M3D_LOG(name); - name = NULL; - break; - } - if(name) { - i = model->nummaterial++; - if(model->flags & M3D_FLG_MTLLIB) { - m = model->material; - model->material = (m3dm_t*)M3D_MALLOC(model->nummaterial * sizeof(m3dm_t)); - if(!model->material) goto memerr; - memcpy(model->material, m, (model->nummaterial - 1) * sizeof(m3dm_t)); - if(model->texture) { - tx = model->texture; - model->texture = (m3dtx_t*)M3D_MALLOC(model->numtexture * sizeof(m3dtx_t)); - if(!model->texture) goto memerr; - memcpy(model->texture, tx, model->numtexture * sizeof(m3dm_t)); - } - model->flags &= ~M3D_FLG_MTLLIB; - } else { - model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); - if(!model->material) goto memerr; - } - m = &model->material[i]; - m->numprop = 0; - m->name = name; - m->prop = (m3dp_t*)M3D_MALLOC((len / 2) * sizeof(m3dp_t)); - if(!m->prop) goto memerr; - while(data < chunk) { - i = m->numprop++; - m->prop[i].type = *data++; - m->prop[i].value.num = 0; - if(m->prop[i].type >= 128) - k = m3dpf_map; - else { - for(k = 256, j = 0; j < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); j++) - if(m->prop[i].type == m3d_propertytypes[j].id) { k = m3d_propertytypes[j].format; break; } - } - switch(k) { - case m3dpf_color: - switch(model->ci_s) { - case 1: m->prop[i].value.color = model->cmap ? model->cmap[data[0]] : 0; data++; break; - case 2: m->prop[i].value.color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; - case 4: m->prop[i].value.color = *((uint32_t*)data); data += 4; break; - } - break; - - case m3dpf_uint8: m->prop[i].value.num = *data++; break; - case m3dpf_uint16:m->prop[i].value.num = *((uint16_t*)data); data += 2; break; - case m3dpf_uint32:m->prop[i].value.num = *((uint32_t*)data); data += 4; break; - case m3dpf_float: m->prop[i].value.fnum = *((float*)data); data += 4; break; - - case m3dpf_map: - M3D_GETSTR(name); - m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, name); - if(model->errcode == M3D_ERR_ALLOC) goto memerr; - /* this error code only returned if readfilecb was specified */ - if(m->prop[i].value.textureid == M3D_UNDEF) { - M3D_LOG("Texture not found"); - M3D_LOG(m->name); - m->numprop--; - } - break; - - default: - M3D_LOG("Unknown material property in"); - M3D_LOG(m->name); - model->errcode = M3D_ERR_UNKPROP; - data = chunk; - break; - } - } - m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); - if(!m->prop) goto memerr; - } - } else - /* face */ - if(M3D_CHUNKMAGIC(data, 'P','R','O','C')) { - /* procedural surface */ - M3D_GETSTR(name); - M3D_LOG("Procedural surface"); - M3D_LOG(name); - _m3d_getpr(model, readfilecb, freecb, name); - } else - if(M3D_CHUNKMAGIC(data, 'M','E','S','H')) { - M3D_LOG("Mesh data"); - if(!model->vertex) { M3D_LOG("No vertex chunk before mesh"); model->errcode = M3D_ERR_VRTS; } - /* mesh */ - data += sizeof(m3dchunk_t); - mi = M3D_UNDEF; -#ifdef M3D_VERTEXMAX - pi = M3D_UNDEF; -#endif - am = model->numface; - while(data < chunk) { - k = *data++; - n = k >> 4; - k &= 15; - if(!n) { - if(!k) { - /* use material */ - mi = M3D_UNDEF; - M3D_GETSTR(name); - if(name) { - for(j = 0; j < model->nummaterial; j++) - if(!strcmp(name, model->material[j].name)) { - mi = (M3D_INDEX)j; - break; - } - if(mi == M3D_UNDEF) model->errcode = M3D_ERR_MTRL; - } - } else { - /* use parameter */ - M3D_GETSTR(name); -#ifdef M3D_VERTEXMAX - pi = M3D_UNDEF; - if(name) { - for(j = 0; j < model->numparam; j++) - if(!strcmp(name, model->param[j].name)) { - pi = (M3D_INDEX)j; - break; - } - if(pi == M3D_UNDEF) { - pi = model->numparam++; - model->param = (m3dvi_t*)M3D_REALLOC(model->param, model->numparam * sizeof(m3dvi_t)); - if(!model->param) goto memerr; - model->param[pi].name = name; - model->param[pi].count = 0; - } - } -#endif - } - continue; - } - if(n != 3) { M3D_LOG("Only triangle mesh supported for now"); model->errcode = M3D_ERR_UNKMESH; return model; } - i = model->numface++; - if(model->numface > am) { - am = model->numface + 4095; - model->face = (m3df_t*)M3D_REALLOC(model->face, am * sizeof(m3df_t)); - if(!model->face) goto memerr; - } - memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */ - model->face[i].materialid = mi; -#ifdef M3D_VERTEXMAX - model->face[i].paramid = pi; -#endif - for(j = 0; data < chunk && j < n; j++) { - /* vertex */ - data = _m3d_getidx(data, model->vi_s, &model->face[i].vertex[j]); - /* texcoord */ - if(k & 1) - data = _m3d_getidx(data, model->ti_s, &model->face[i].texcoord[j]); - /* normal */ - if(k & 2) - data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]); -#ifndef M3D_NONORMALS - if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; -#endif - /* maximum */ - if(k & 4) -#ifdef M3D_VERTEXMAX - data = _m3d_getidx(data, model->vi_s, &model->face[i].vertmax[j]); -#else - data += model->vi_s; -#endif - } - if(j != n) { M3D_LOG("Invalid mesh"); model->numface = 0; model->errcode = M3D_ERR_UNKMESH; return model; } - } - model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); - } else - if(M3D_CHUNKMAGIC(data, 'V','O','X','T')) { - /* voxel types */ - M3D_LOG("Voxel types list"); - if(model->voxtype) { M3D_LOG("More voxel type chunks, should be unique"); model->errcode = M3D_ERR_VOXT; continue; } - if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; - reclen = model->ci_s + model->si_s + 3 + model->sk_s; - k = len / reclen; - model->voxtype = (m3dvt_t*)M3D_MALLOC(k * sizeof(m3dvt_t)); - if(!model->voxtype) goto memerr; - memset(model->voxtype, 0, k * sizeof(m3dvt_t)); - model->numvoxtype = 0; - for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < k; i++) { - switch(model->ci_s) { - case 1: model->voxtype[i].color = model->cmap ? model->cmap[data[0]] : 0; data++; break; - case 2: model->voxtype[i].color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; - case 4: model->voxtype[i].color = *((uint32_t*)data); data += 4; break; - /* case 8: break; */ - } - M3D_GETSTR(name); - model->voxtype[i].materialid = M3D_UNDEF; - if(name) { - model->voxtype[i].name = name; -/* - for(j = 0; j < model->nummaterial; j++) - if(!strcmp(name, model->material[j].name)) { - model->voxtype[i].materialid = (M3D_INDEX)j; - break; - } -*/ - } - j = *data++; - model->voxtype[i].rotation = j & 0xBF; - model->voxtype[i].voxshape = ((j & 0x40) << 2) | *data++; - model->voxtype[i].numitem = *data++; - model->voxtype[i].skinid = M3D_UNDEF; - data = _m3d_getidx(data, model->sk_s, &model->voxtype[i].skinid); - if(model->voxtype[i].numitem) { - model->voxtype[i].item = (m3dvi_t*)M3D_MALLOC(model->voxtype[i].numitem * sizeof(m3dvi_t)); - if(!model->voxtype[i].item) goto memerr; - memset(model->voxtype[i].item, 0, model->voxtype[i].numitem * sizeof(m3dvi_t)); - for(j = 0; j < model->voxtype[i].numitem; j++) { - model->voxtype[i].item[j].count = *data++; - model->voxtype[i].item[j].count |= (*data++) << 8; - M3D_GETSTR(model->voxtype[i].item[j].name); - } - } - } - model->numvoxtype = i; - if(k != model->numvoxtype) { - model->voxtype = (m3dvt_t*)M3D_REALLOC(model->voxtype, model->numvoxtype * sizeof(m3dvt_t)); - if(!model->voxtype) goto memerr; - } - } else - if(M3D_CHUNKMAGIC(data, 'V','O','X','D')) { - /* voxel data */ - data += sizeof(m3dchunk_t); - M3D_GETSTR(name); - M3D_LOG("Voxel Data Layer"); - M3D_LOG(name); - if(model->vd_s > 4 || model->vp_s > 2) { M3D_LOG("No voxel index size"); model->errcode = M3D_ERR_UNKVOX; continue; } - if(!model->voxtype) { M3D_LOG("No voxel type chunk before voxel data"); model->errcode = M3D_ERR_VOXT; } - i = model->numvoxel++; - model->voxel = (m3dvx_t*)M3D_REALLOC(model->voxel, model->numvoxel * sizeof(m3dvx_t)); - if(!model->voxel) goto memerr; - memset(&model->voxel[i], 0, sizeof(m3dvx_t)); - model->voxel[i].name = name; - switch(model->vd_s) { - case 1: - model->voxel[i].x = (int32_t)((int8_t)data[0]); - model->voxel[i].y = (int32_t)((int8_t)data[1]); - model->voxel[i].z = (int32_t)((int8_t)data[2]); - model->voxel[i].w = (uint32_t)(data[3]); - model->voxel[i].h = (uint32_t)(data[4]); - model->voxel[i].d = (uint32_t)(data[5]); - data += 6; - break; - case 2: - model->voxel[i].x = (int32_t)(*((int16_t*)(data+0))); - model->voxel[i].y = (int32_t)(*((int16_t*)(data+2))); - model->voxel[i].z = (int32_t)(*((int16_t*)(data+4))); - model->voxel[i].w = (uint32_t)(*((uint16_t*)(data+6))); - model->voxel[i].h = (uint32_t)(*((uint16_t*)(data+8))); - model->voxel[i].d = (uint32_t)(*((uint16_t*)(data+10))); - data += 12; - break; - case 4: - model->voxel[i].x = *((int32_t*)(data+0)); - model->voxel[i].y = *((int32_t*)(data+4)); - model->voxel[i].z = *((int32_t*)(data+8)); - model->voxel[i].w = *((uint32_t*)(data+12)); - model->voxel[i].h = *((uint32_t*)(data+16)); - model->voxel[i].d = *((uint32_t*)(data+20)); - data += 24; - break; - } - model->voxel[i].uncertain = *data++; - model->voxel[i].groupid = *data++; - k = model->voxel[i].w * model->voxel[i].h * model->voxel[i].d; - model->voxel[i].data = (M3D_VOXEL*)M3D_MALLOC(k * sizeof(M3D_VOXEL)); - if(!model->voxel[i].data) goto memerr; - memset(model->voxel[i].data, 0xff, k * sizeof(M3D_VOXEL)); - for(j = 0; data < chunk && j < k;) { - l = ((*data++) & 0x7F) + 1; - if(data[-1] & 0x80) { - data = _m3d_getidx(data, model->vp_s, &mi); - while(l-- && j < k) model->voxel[i].data[j++] = (M3D_VOXEL)mi; - } else - while(l-- && j < k) { - data = _m3d_getidx(data, model->vp_s, &mi); - model->voxel[i].data[j++] = (M3D_VOXEL)mi; - } - } - } else - if(M3D_CHUNKMAGIC(data, 'S','H','P','E')) { - /* mathematical shape */ - data += sizeof(m3dchunk_t); - M3D_GETSTR(name); - M3D_LOG("Mathematical Shape"); - M3D_LOG(name); - i = model->numshape++; - model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3dh_t)); - if(!model->shape) goto memerr; - h = &model->shape[i]; - h->numcmd = 0; - h->cmd = NULL; - h->name = name; - h->group = M3D_UNDEF; - data = _m3d_getidx(data, model->bi_s, &h->group); - if(h->group != M3D_UNDEF && h->group >= model->numbone) { - M3D_LOG("Unknown bone id as shape group in shape"); - M3D_LOG(name); - h->group = M3D_UNDEF; - model->errcode = M3D_ERR_SHPE; - } - while(data < chunk) { - i = h->numcmd++; - h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); - if(!h->cmd) goto memerr; - h->cmd[i].type = *data++; - if(h->cmd[i].type & 0x80) { - h->cmd[i].type &= 0x7F; - h->cmd[i].type |= (*data++ << 7); - } - if(h->cmd[i].type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0]))) { - M3D_LOG("Unknown shape command in"); - M3D_LOG(h->name); - model->errcode = M3D_ERR_UNKCMD; - break; - } - cd = &m3d_commandtypes[h->cmd[i].type]; - h->cmd[i].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); - if(!h->cmd[i].arg) goto memerr; - memset(h->cmd[i].arg, 0, cd->p * sizeof(uint32_t)); - for(k = n = 0, l = cd->p; k < l; k++) - switch(cd->a[((k - n) % (cd->p - n)) + n]) { - case m3dcp_mi_t: - h->cmd[i].arg[k] = M3D_NOTDEFINED; - M3D_GETSTR(name); - if(name) { - for(n = 0; n < model->nummaterial; n++) - if(!strcmp(name, model->material[n].name)) { - h->cmd[i].arg[k] = n; - break; - } - if(h->cmd[i].arg[k] == M3D_NOTDEFINED) model->errcode = M3D_ERR_MTRL; - } - break; - case m3dcp_vc_t: - f = 0.0f; - switch(model->vc_s) { - case 1: f = (float)((int8_t)data[0]) / 127; break; - case 2: f = (float)(*((int16_t*)(data+0))) / 32767; break; - case 4: f = (float)(*((float*)(data+0))); break; - case 8: f = (float)(*((double*)(data+0))); break; - } - memcpy(&h->cmd[i].arg[k], &f, 4); - data += model->vc_s; - break; - case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break; - case m3dcp_fi_t: data = _m3d_getidx(data, model->fi_s, &h->cmd[i].arg[k]); break; - case m3dcp_ti_t: data = _m3d_getidx(data, model->ti_s, &h->cmd[i].arg[k]); break; - case m3dcp_qi_t: - case m3dcp_vi_t: data = _m3d_getidx(data, model->vi_s, &h->cmd[i].arg[k]); break; - case m3dcp_i1_t: data = _m3d_getidx(data, 1, &h->cmd[i].arg[k]); break; - case m3dcp_i2_t: data = _m3d_getidx(data, 2, &h->cmd[i].arg[k]); break; - case m3dcp_i4_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); break; - case m3dcp_va_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); - n = k + 1; l += (h->cmd[i].arg[k] - 1) * (cd->p - k - 1); - h->cmd[i].arg = (uint32_t*)M3D_REALLOC(h->cmd[i].arg, l * sizeof(uint32_t)); - if(!h->cmd[i].arg) goto memerr; - memset(&h->cmd[i].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); - break; - } - } - } else - /* annotation label list */ - if(M3D_CHUNKMAGIC(data, 'L','B','L','S')) { - data += sizeof(m3dchunk_t); - M3D_GETSTR(name); - M3D_GETSTR(lang); - M3D_LOG("Label list"); - if(name) { M3D_LOG(name); } - if(lang) { M3D_LOG(lang); } - if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; - k = 0; - switch(model->ci_s) { - case 1: k = model->cmap ? model->cmap[data[0]] : 0; data++; break; - case 2: k = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; - case 4: k = *((uint32_t*)data); data += 4; break; - /* case 8: break; */ - } - reclen = model->vi_s + model->si_s; - i = model->numlabel; model->numlabel += len / reclen; - model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); - if(!model->label) goto memerr; - memset(&model->label[i], 0, (model->numlabel - i) * sizeof(m3dl_t)); - for(; data < chunk && i < model->numlabel; i++) { - model->label[i].name = name; - model->label[i].lang = lang; - model->label[i].color = k; - data = _m3d_getidx(data, model->vi_s, &model->label[i].vertexid); - M3D_GETSTR(model->label[i].text); - } - } else - /* action */ - if(M3D_CHUNKMAGIC(data, 'A','C','T','N')) { - M3D_LOG("Action"); - i = model->numaction++; - model->action = (m3da_t*)M3D_REALLOC(model->action, model->numaction * sizeof(m3da_t)); - if(!model->action) goto memerr; - a = &model->action[i]; - data += sizeof(m3dchunk_t); - M3D_GETSTR(a->name); - M3D_LOG(a->name); - a->numframe = *((uint16_t*)data); data += 2; - if(a->numframe < 1) { - model->numaction--; - } else { - a->durationmsec = *((uint32_t*)data); data += 4; - a->frame = (m3dfr_t*)M3D_MALLOC(a->numframe * sizeof(m3dfr_t)); - if(!a->frame) goto memerr; - for(i = 0; data < chunk && i < a->numframe; i++) { - a->frame[i].msec = *((uint32_t*)data); data += 4; - a->frame[i].numtransform = 0; a->frame[i].transform = NULL; - data = _m3d_getidx(data, model->fc_s, &a->frame[i].numtransform); - if(a->frame[i].numtransform > 0) { - a->frame[i].transform = (m3dtr_t*)M3D_MALLOC(a->frame[i].numtransform * sizeof(m3dtr_t)); - for(j = 0; j < a->frame[i].numtransform; j++) { - data = _m3d_getidx(data, model->bi_s, &a->frame[i].transform[j].boneid); - data = _m3d_getidx(data, model->vi_s, &a->frame[i].transform[j].pos); - data = _m3d_getidx(data, model->vi_s, &a->frame[i].transform[j].ori); - } - } - } - } - } else { - i = model->numextra++; - model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); - if(!model->extra) goto memerr; - model->extra[i] = (m3dchunk_t*)data; - } - } - /* calculate normals, normalize skin weights, create bone/vertex cross-references and calculate transform matrices */ -#ifdef M3D_ASCII -postprocess: -#endif - if(model) { - M3D_LOG("Post-process"); -#ifdef M3D_PROFILING - gettimeofday(&tv1, NULL); - tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; - tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; - if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } - printf(" Parsing chunks %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); -#endif -#ifndef M3D_NOVOXELS - if(model->numvoxel && model->voxel) { - M3D_LOG("Converting voxels into vertices and mesh"); - /* add normals */ - enorm = model->numvertex; model->numvertex += 6; - model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); - if(!model->vertex) goto memerr; - memset(&model->vertex[enorm], 0, 6 * sizeof(m3dv_t)); - for(l = 0; l < 6; l++) - model->vertex[enorm+l].skinid = M3D_UNDEF; - model->vertex[enorm+0].y = (M3D_FLOAT)-1.0; - model->vertex[enorm+1].z = (M3D_FLOAT)-1.0; - model->vertex[enorm+2].x = (M3D_FLOAT)-1.0; - model->vertex[enorm+3].y = (M3D_FLOAT)1.0; - model->vertex[enorm+4].z = (M3D_FLOAT)1.0; - model->vertex[enorm+5].x = (M3D_FLOAT)1.0; - /* this is a fast, not so memory efficient version, only basic face culling used */ - min_x = min_y = min_z = 2147483647L; - max_x = max_y = max_z = -2147483647L; - for(i = 0; i < model->numvoxel; i++) { - if(model->voxel[i].x + (int32_t)model->voxel[i].w > max_x) max_x = model->voxel[i].x + (int32_t)model->voxel[i].w; - if(model->voxel[i].x < min_x) min_x = model->voxel[i].x; - if(model->voxel[i].y + (int32_t)model->voxel[i].h > max_y) max_y = model->voxel[i].y + (int32_t)model->voxel[i].h; - if(model->voxel[i].y < min_y) min_y = model->voxel[i].y; - if(model->voxel[i].z + (int32_t)model->voxel[i].d > max_z) max_z = model->voxel[i].z + (int32_t)model->voxel[i].d; - if(model->voxel[i].z < min_z) min_z = model->voxel[i].z; - } - i = (-min_x > max_x ? -min_x : max_x); - j = (-min_y > max_y ? -min_y : max_y); - k = (-min_z > max_z ? -min_z : max_z); - if(j > i) i = j; - if(k > i) i = k; - if(i <= 1) i = 1; - w = (M3D_FLOAT)1.0 / (M3D_FLOAT)i; - if(i >= 254) model->vc_s = 2; - if(i >= 65534) model->vc_s = 4; - for(i = 0; i < model->numvoxel; i++) { - sx = model->voxel[i].w; sz = model->voxel[i].d; sy = model->voxel[i].h; - for(y = 0, j = 0; y < sy; y++) - for(z = 0; z < sz; z++) - for(x = 0; x < sx; x++, j++) - if(model->voxel[i].data[j] < model->numvoxtype) { - k = 0; - /* 16__32 ____ - * /| /| /|2 /| - *64_128 | /_8_/ 32 - * | 1_|_2 |4|_|_| - * |/ |/ |/ 1|/ - * 4___8 |16_| */ - k = n = am = 0; - if(!y || model->voxel[i].data[j - sx*sz] >= model->numvoxtype) { n++; am |= 1; k |= 1|2|4|8; } - if(!z || model->voxel[i].data[j - sx] >= model->numvoxtype) { n++; am |= 2; k |= 1|2|16|32; } - if(!x || model->voxel[i].data[j - 1] >= model->numvoxtype) { n++; am |= 4; k |= 1|4|16|64; } - if(y == sy-1 || model->voxel[i].data[j + sx*sz] >= model->numvoxtype) { n++; am |= 8; k |= 16|32|64|128; } - if(z == sz-1 || model->voxel[i].data[j + sx] >= model->numvoxtype) { n++; am |= 16; k |= 4|8|64|128; } - if(x == sx-1 || model->voxel[i].data[j + 1] >= model->numvoxtype) { n++; am |= 32; k |= 2|8|32|128; } - if(k) { - memset(edge, 255, sizeof(edge)); - for(l = 0, len = 1, reclen = model->numvertex; l < 8; l++, len <<= 1) - if(k & len) edge[l] = model->numvertex++; - model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); - if(!model->vertex) goto memerr; - memset(&model->vertex[reclen], 0, (model->numvertex-reclen) * sizeof(m3dv_t)); - for(l = reclen; l < model->numvertex; l++) { - model->vertex[l].skinid = model->voxtype[model->voxel[i].data[j]].skinid; - model->vertex[l].color = model->voxtype[model->voxel[i].data[j]].color; - } - l = reclen; - if(k & 1) { - model->vertex[l].x = (model->voxel[i].x + x) * w; - model->vertex[l].y = (model->voxel[i].y + y) * w; - model->vertex[l].z = (model->voxel[i].z + z) * w; - l++; - } - if(k & 2) { - model->vertex[l].x = (model->voxel[i].x + x + 1) * w; - model->vertex[l].y = (model->voxel[i].y + y) * w; - model->vertex[l].z = (model->voxel[i].z + z) * w; - l++; - } - if(k & 4) { - model->vertex[l].x = (model->voxel[i].x + x) * w; - model->vertex[l].y = (model->voxel[i].y + y) * w; - model->vertex[l].z = (model->voxel[i].z + z + 1) * w; - l++; - } - if(k & 8) { - model->vertex[l].x = (model->voxel[i].x + x + 1) * w; - model->vertex[l].y = (model->voxel[i].y + y) * w; - model->vertex[l].z = (model->voxel[i].z + z + 1) * w; - l++; - } - if(k & 16) { - model->vertex[l].x = (model->voxel[i].x + x) * w; - model->vertex[l].y = (model->voxel[i].y + y + 1) * w; - model->vertex[l].z = (model->voxel[i].z + z) * w; - l++; - } - if(k & 32) { - model->vertex[l].x = (model->voxel[i].x + x + 1) * w; - model->vertex[l].y = (model->voxel[i].y + y + 1) * w; - model->vertex[l].z = (model->voxel[i].z + z) * w; - l++; - } - if(k & 64) { - model->vertex[l].x = (model->voxel[i].x + x) * w; - model->vertex[l].y = (model->voxel[i].y + y + 1) * w; - model->vertex[l].z = (model->voxel[i].z + z + 1) * w; - l++; - } - if(k & 128) { - model->vertex[l].x = (model->voxel[i].x + x + 1) * w; - model->vertex[l].y = (model->voxel[i].y + y + 1) * w; - model->vertex[l].z = (model->voxel[i].z + z + 1) * w; - l++; - } - n <<= 1; - l = model->numface; model->numface += n; - model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); - if(!model->face) goto memerr; - memset(&model->face[l], 255, n * sizeof(m3df_t)); - for(reclen = l; reclen < model->numface; reclen++) - model->face[reclen].materialid = model->voxtype[model->voxel[i].data[j]].materialid; - if(am & 1) { /* bottom */ - model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[1]; model->face[l].vertex[2] = edge[2]; - model->face[l+1].vertex[0] = edge[2]; model->face[l+1].vertex[1] = edge[1]; model->face[l+1].vertex[2] = edge[3]; - model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = - model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm; - l += 2; - } - if(am & 2) { /* north */ - model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[4]; model->face[l].vertex[2] = edge[1]; - model->face[l+1].vertex[0] = edge[1]; model->face[l+1].vertex[1] = edge[4]; model->face[l+1].vertex[2] = edge[5]; - model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = - model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+1; - l += 2; - } - if(am & 4) { /* west */ - model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[2]; model->face[l].vertex[2] = edge[4]; - model->face[l+1].vertex[0] = edge[2]; model->face[l+1].vertex[1] = edge[6]; model->face[l+1].vertex[2] = edge[4]; - model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = - model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+2; - l += 2; - } - if(am & 8) { /* top */ - model->face[l].vertex[0] = edge[4]; model->face[l].vertex[1] = edge[6]; model->face[l].vertex[2] = edge[5]; - model->face[l+1].vertex[0] = edge[5]; model->face[l+1].vertex[1] = edge[6]; model->face[l+1].vertex[2] = edge[7]; - model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = - model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+3; - l += 2; - } - if(am & 16) { /* south */ - model->face[l].vertex[0] = edge[2]; model->face[l].vertex[1] = edge[7]; model->face[l].vertex[2] = edge[6]; - model->face[l+1].vertex[0] = edge[7]; model->face[l+1].vertex[1] = edge[2]; model->face[l+1].vertex[2] = edge[3]; - model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = - model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+4; - l += 2; - } - if(am & 32) { /* east */ - model->face[l].vertex[0] = edge[1]; model->face[l].vertex[1] = edge[5]; model->face[l].vertex[2] = edge[7]; - model->face[l+1].vertex[0] = edge[1]; model->face[l+1].vertex[1] = edge[7]; model->face[l+1].vertex[2] = edge[3]; - model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = - model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+5; - l += 2; - } - } - } - } - } -#endif -#ifndef M3D_NONORMALS - if(model->numface && model->face && neednorm) { - /* if they are missing, calculate triangle normals into a temporary buffer */ - norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t)); - if(!norm) goto memerr; - for(i = 0, n = model->numvertex; i < model->numface; i++) - if(model->face[i].normal[0] == M3D_UNDEF) { - v0 = &model->vertex[model->face[i].vertex[0]]; - v1 = &model->vertex[model->face[i].vertex[1]]; - v2 = &model->vertex[model->face[i].vertex[2]]; - va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z; - vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z; - v0 = &norm[i]; - v0->x = (va.y * vb.z) - (va.z * vb.y); - v0->y = (va.z * vb.x) - (va.x * vb.z); - v0->z = (va.x * vb.y) - (va.y * vb.x); - w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); - v0->x *= w; v0->y *= w; v0->z *= w; - model->face[i].normal[0] = model->face[i].vertex[0] + n; - model->face[i].normal[1] = model->face[i].vertex[1] + n; - model->face[i].normal[2] = model->face[i].vertex[2] + n; - } - /* this is the fast way, we don't care if a normal is repeated in model->vertex */ - M3D_LOG("Generating normals"); - model->flags |= M3D_FLG_GENNORM; - model->numvertex <<= 1; - model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); - if(!model->vertex) goto memerr; - memset(&model->vertex[n], 0, n * sizeof(m3dv_t)); - for(i = 0; i < model->numface; i++) - for(j = 0; j < 3; j++) { - v0 = &model->vertex[model->face[i].vertex[j] + n]; - v0->x += norm[i].x; - v0->y += norm[i].y; - v0->z += norm[i].z; - } - /* for each vertex, take the average of the temporary normals and use that */ - for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) { - w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); - v0->x *= w; v0->y *= w; v0->z *= w; - v0->skinid = M3D_UNDEF; - } - M3D_FREE(norm); - } -#endif - if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) { -#ifndef M3D_NOWEIGHTS - M3D_LOG("Generating weight cross-reference"); - for(i = 0; i < model->numvertex; i++) { - if(model->vertex[i].skinid < model->numskin) { - sk = &model->skin[model->vertex[i].skinid]; - w = (M3D_FLOAT)0.0; - for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) - w += sk->weight[j]; - for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) { - sk->weight[j] /= w; - b = &model->bone[sk->boneid[j]]; - k = b->numweight++; - b->weight = (m3dw_t*)M3D_REALLOC(b->weight, b->numweight * sizeof(m3da_t)); - if(!b->weight) goto memerr; - b->weight[k].vertexid = i; - b->weight[k].weight = sk->weight[j]; - } - } - } -#endif -#ifndef M3D_NOANIMATION - M3D_LOG("Calculating bone transformation matrices"); - for(i = 0; i < model->numbone; i++) { - b = &model->bone[i]; - if(model->bone[i].parent == M3D_UNDEF) { - _m3d_mat((M3D_FLOAT*)&b->mat4, &model->vertex[b->pos], &model->vertex[b->ori]); - } else { - _m3d_mat((M3D_FLOAT*)&r, &model->vertex[b->pos], &model->vertex[b->ori]); - _m3d_mul((M3D_FLOAT*)&b->mat4, (M3D_FLOAT*)&model->bone[b->parent].mat4, (M3D_FLOAT*)&r); - } - } - for(i = 0; i < model->numbone; i++) - _m3d_inv((M3D_FLOAT*)&model->bone[i].mat4); -#endif - } -#ifdef M3D_PROFILING - gettimeofday(&tv0, NULL); - tvd.tv_sec = tv0.tv_sec - tv1.tv_sec; - tvd.tv_usec = tv0.tv_usec - tv1.tv_usec; - if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } - printf(" Post-process %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); -#endif - } - return model; -} - -/** - * Calculates skeletons for animation frames, returns a working copy (should be freed after use) - */ -m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t *skeleton) -{ - unsigned int i; - M3D_INDEX s = frameid; - m3dfr_t *fr; - - if(!model || !model->numbone || !model->bone || (actionid != M3D_UNDEF && (!model->action || - actionid >= model->numaction || frameid >= model->action[actionid].numframe))) { - model->errcode = M3D_ERR_UNKFRAME; - return skeleton; - } - model->errcode = M3D_SUCCESS; - if(!skeleton) { - skeleton = (m3dtr_t*)M3D_MALLOC(model->numbone * sizeof(m3dtr_t)); - if(!skeleton) { - model->errcode = M3D_ERR_ALLOC; - return NULL; - } - goto gen; - } - if(actionid == M3D_UNDEF || !frameid) { -gen: s = 0; - for(i = 0; i < model->numbone; i++) { - skeleton[i].boneid = i; - skeleton[i].pos = model->bone[i].pos; - skeleton[i].ori = model->bone[i].ori; - } - } - if(actionid < model->numaction && (frameid || !model->action[actionid].frame[0].msec)) { - for(; s <= frameid; s++) { - fr = &model->action[actionid].frame[s]; - for(i = 0; i < fr->numtransform; i++) { - skeleton[fr->transform[i].boneid].pos = fr->transform[i].pos; - skeleton[fr->transform[i].boneid].ori = fr->transform[i].ori; - } - } - } - return skeleton; -} - -#ifndef M3D_NOANIMATION -/** - * Returns interpolated animation-pose, a working copy (should be freed after use) - */ -m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) -{ - unsigned int i, j, l; - M3D_FLOAT r[16], t, c, d, s; - m3db_t *ret; - m3dv_t *v, *p, *f; - m3dtr_t *tmp; - m3dfr_t *fr; - - if(!model || !model->numbone || !model->bone) { - model->errcode = M3D_ERR_UNKFRAME; - return NULL; - } - ret = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t)); - if(!ret) { - model->errcode = M3D_ERR_ALLOC; - return NULL; - } - memcpy(ret, model->bone, model->numbone * sizeof(m3db_t)); - for(i = 0; i < model->numbone; i++) - _m3d_inv((M3D_FLOAT*)&ret[i].mat4); - if(!model->action || actionid >= model->numaction) { - model->errcode = M3D_ERR_UNKFRAME; - return ret; - } - msec %= model->action[actionid].durationmsec; - model->errcode = M3D_SUCCESS; - fr = &model->action[actionid].frame[0]; - for(j = l = 0; j < model->action[actionid].numframe && model->action[actionid].frame[j].msec <= msec; j++) { - fr = &model->action[actionid].frame[j]; - l = fr->msec; - for(i = 0; i < fr->numtransform; i++) { - ret[fr->transform[i].boneid].pos = fr->transform[i].pos; - ret[fr->transform[i].boneid].ori = fr->transform[i].ori; - } - } - if(l != msec) { - model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, (model->numvertex + 2 * model->numbone) * sizeof(m3dv_t)); - if(!model->vertex) { - free(ret); - model->errcode = M3D_ERR_ALLOC; - return NULL; - } - tmp = (m3dtr_t*)M3D_MALLOC(model->numbone * sizeof(m3dtr_t)); - if(tmp) { - for(i = 0; i < model->numbone; i++) { - tmp[i].pos = ret[i].pos; - tmp[i].ori = ret[i].ori; - } - fr = &model->action[actionid].frame[j % model->action[actionid].numframe]; - t = l >= fr->msec ? (M3D_FLOAT)1.0 : (M3D_FLOAT)(msec - l) / (M3D_FLOAT)(fr->msec - l); - for(i = 0; i < fr->numtransform; i++) { - tmp[fr->transform[i].boneid].pos = fr->transform[i].pos; - tmp[fr->transform[i].boneid].ori = fr->transform[i].ori; - } - for(i = 0, j = model->numvertex; i < model->numbone; i++) { - /* interpolation of position */ - if(ret[i].pos != tmp[i].pos) { - p = &model->vertex[ret[i].pos]; - f = &model->vertex[tmp[i].pos]; - v = &model->vertex[j]; - v->x = p->x + t * (f->x - p->x); - v->y = p->y + t * (f->y - p->y); - v->z = p->z + t * (f->z - p->z); - ret[i].pos = j++; - } - /* interpolation of orientation */ - if(ret[i].ori != tmp[i].ori) { - p = &model->vertex[ret[i].ori]; - f = &model->vertex[tmp[i].ori]; - v = &model->vertex[j]; - d = p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z; - if(d < 0) { d = -d; s = (M3D_FLOAT)-1.0; } else s = (M3D_FLOAT)1.0; -#if 0 - /* don't use SLERP, requires two more variables, libm linkage and it is slow (but nice) */ - a = (M3D_FLOAT)1.0 - t; b = t; - if(d < (M3D_FLOAT)0.999999) { c = acosf(d); b = 1 / sinf(c); a = sinf(a * c) * b; b *= sinf(t * c) * s; } - v->x = p->x * a + f->x * b; - v->y = p->y * a + f->y * b; - v->z = p->z * a + f->z * b; - v->w = p->w * a + f->w * b; -#else - /* approximated NLERP, original approximation by Arseny Kapoulkine, heavily optimized by me */ - c = t - (M3D_FLOAT)0.5; t += t * c * (t - (M3D_FLOAT)1.0) * (((M3D_FLOAT)1.0904 + d * ((M3D_FLOAT)-3.2452 + - d * ((M3D_FLOAT)3.55645 - d * (M3D_FLOAT)1.43519))) * c * c + ((M3D_FLOAT)0.848013 + d * - ((M3D_FLOAT)-1.06021 + d * (M3D_FLOAT)0.215638))); - v->x = p->x + t * (s * f->x - p->x); - v->y = p->y + t * (s * f->y - p->y); - v->z = p->z + t * (s * f->z - p->z); - v->w = p->w + t * (s * f->w - p->w); - d = _m3d_rsq(v->w * v->w + v->x * v->x + v->y * v->y + v->z * v->z); - v->x *= d; v->y *= d; v->z *= d; v->w *= d; -#endif - ret[i].ori = j++; - } - } - M3D_FREE(tmp); - } - } - for(i = 0; i < model->numbone; i++) { - if(ret[i].parent == M3D_UNDEF) { - _m3d_mat((M3D_FLOAT*)&ret[i].mat4, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); - } else { - _m3d_mat((M3D_FLOAT*)&r, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); - _m3d_mul((M3D_FLOAT*)&ret[i].mat4, (M3D_FLOAT*)&ret[ret[i].parent].mat4, (M3D_FLOAT*)&r); - } - } - return ret; -} - -#endif /* M3D_NOANIMATION */ - -#endif /* M3D_IMPLEMENTATION */ - -#if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_EXPORTER)) -/** - * Free the in-memory model - */ -void m3d_free(m3d_t *model) -{ - unsigned int i, j; - - if(!model) return; -#ifdef M3D_ASCII - /* if model imported from ASCII, we have to free all strings as well */ - if(model->flags & M3D_FLG_FREESTR) { - if(model->name) M3D_FREE(model->name); - if(model->license) M3D_FREE(model->license); - if(model->author) M3D_FREE(model->author); - if(model->desc) M3D_FREE(model->desc); - if(model->bone) - for(i = 0; i < model->numbone; i++) - if(model->bone[i].name) - M3D_FREE(model->bone[i].name); - if(model->shape) - for(i = 0; i < model->numshape; i++) - if(model->shape[i].name) - M3D_FREE(model->shape[i].name); - if(model->numvoxtype) - for(i = 0; i < model->numvoxtype; i++) { - if(model->voxtype[i].name) - M3D_FREE(model->voxtype[i].name); - for(j = 0; j < model->voxtype[i].numitem; j++) - if(model->voxtype[i].item[j].name) - M3D_FREE(model->voxtype[i].item[j].name); - } - if(model->numvoxel) - for(i = 0; i < model->numvoxel; i++) - if(model->voxel[i].name) - M3D_FREE(model->voxel[i].name); - if(model->material) - for(i = 0; i < model->nummaterial; i++) - if(model->material[i].name) - M3D_FREE(model->material[i].name); - if(model->action) - for(i = 0; i < model->numaction; i++) - if(model->action[i].name) - M3D_FREE(model->action[i].name); - if(model->texture) - for(i = 0; i < model->numtexture; i++) - if(model->texture[i].name) - M3D_FREE(model->texture[i].name); - if(model->inlined) - for(i = 0; i < model->numinlined; i++) { - if(model->inlined[i].name) - M3D_FREE(model->inlined[i].name); - if(model->inlined[i].data) - M3D_FREE(model->inlined[i].data); - } - if(model->extra) - for(i = 0; i < model->numextra; i++) - if(model->extra[i]) - M3D_FREE(model->extra[i]); - if(model->label) - for(i = 0; i < model->numlabel; i++) { - if(model->label[i].name) { - for(j = i + 1; j < model->numlabel; j++) - if(model->label[j].name == model->label[i].name) - model->label[j].name = NULL; - M3D_FREE(model->label[i].name); - } - if(model->label[i].lang) { - for(j = i + 1; j < model->numlabel; j++) - if(model->label[j].lang == model->label[i].lang) - model->label[j].lang = NULL; - M3D_FREE(model->label[i].lang); - } - if(model->label[i].text) - M3D_FREE(model->label[i].text); - } - if(model->preview.data) - M3D_FREE(model->preview.data); - } -#endif - if(model->flags & M3D_FLG_FREERAW) M3D_FREE(model->raw); - - if(model->tmap) M3D_FREE(model->tmap); - if(model->bone) { - for(i = 0; i < model->numbone; i++) - if(model->bone[i].weight) - M3D_FREE(model->bone[i].weight); - M3D_FREE(model->bone); - } - if(model->skin) M3D_FREE(model->skin); - if(model->vertex) M3D_FREE(model->vertex); - if(model->face) M3D_FREE(model->face); - if(model->voxtype) { - for(i = 0; i < model->numvoxtype; i++) - if(model->voxtype[i].item) - M3D_FREE(model->voxtype[i].item); - M3D_FREE(model->voxtype); - } - if(model->voxel) { - for(i = 0; i < model->numvoxel; i++) - if(model->voxel[i].data) - M3D_FREE(model->voxel[i].data); - M3D_FREE(model->voxel); - } - if(model->shape) { - for(i = 0; i < model->numshape; i++) { - if(model->shape[i].cmd) { - for(j = 0; j < model->shape[i].numcmd; j++) - if(model->shape[i].cmd[j].arg) M3D_FREE(model->shape[i].cmd[j].arg); - M3D_FREE(model->shape[i].cmd); - } - } - M3D_FREE(model->shape); - } - if(model->material && !(model->flags & M3D_FLG_MTLLIB)) { - for(i = 0; i < model->nummaterial; i++) - if(model->material[i].prop) M3D_FREE(model->material[i].prop); - M3D_FREE(model->material); - } - if(model->texture) { - for(i = 0; i < model->numtexture; i++) - if(model->texture[i].d) M3D_FREE(model->texture[i].d); - M3D_FREE(model->texture); - } - if(model->action) { - for(i = 0; i < model->numaction; i++) { - if(model->action[i].frame) { - for(j = 0; j < model->action[i].numframe; j++) - if(model->action[i].frame[j].transform) M3D_FREE(model->action[i].frame[j].transform); - M3D_FREE(model->action[i].frame); - } - } - M3D_FREE(model->action); - } - if(model->label) M3D_FREE(model->label); - if(model->inlined) M3D_FREE(model->inlined); - if(model->extra) M3D_FREE(model->extra); - free(model); -} -#endif - -#ifdef M3D_EXPORTER -typedef struct { - char *str; - uint32_t offs; -} m3dstr_t; - -typedef struct { - m3dti_t data; - M3D_INDEX oldidx; - M3D_INDEX newidx; -} m3dtisave_t; - -typedef struct { - m3dv_t data; - M3D_INDEX oldidx; - M3D_INDEX newidx; - unsigned char norm; -} m3dvsave_t; - -typedef struct { - m3ds_t data; - M3D_INDEX oldidx; - M3D_INDEX newidx; -} m3dssave_t; - -typedef struct { - m3df_t data; - int group; - uint8_t opacity; -} m3dfsave_t; - -/* create unique list of strings */ -static m3dstr_t *_m3d_addstr(m3dstr_t *str, uint32_t *numstr, char *s) -{ - uint32_t i; - if(!s || !*s) return str; - if(str) { - for(i = 0; i < *numstr; i++) - if(str[i].str == s || !strcmp(str[i].str, s)) return str; - } - str = (m3dstr_t*)M3D_REALLOC(str, ((*numstr) + 1) * sizeof(m3dstr_t)); - str[*numstr].str = s; - str[*numstr].offs = 0; - (*numstr)++; - return str; -} - -/* add strings to header */ -m3dhdr_t *_m3d_addhdr(m3dhdr_t *h, m3dstr_t *s) -{ - int i; - char *safe = _m3d_safestr(s->str, 0); - i = (int)strlen(safe); - h = (m3dhdr_t*)M3D_REALLOC(h, h->length + i+1); - if(!h) { M3D_FREE(safe); return NULL; } - memcpy((uint8_t*)h + h->length, safe, i+1); - s->offs = h->length - 16; - h->length += i+1; - M3D_FREE(safe); - return h; -} - -/* return offset of string */ -static uint32_t _m3d_stridx(m3dstr_t *str, uint32_t numstr, char *s) -{ - uint32_t i; - char *safe; - if(!s || !*s) return 0; - if(str) { - safe = _m3d_safestr(s, 0); - if(!safe) return 0; - if(!*safe) { - free(safe); - return 0; - } - for(i = 0; i < numstr; i++) - if(!strcmp(str[i].str, s)) { - free(safe); - return str[i].offs; - } - free(safe); - } - return 0; -} - -/* compare to faces by their material */ -static int _m3d_facecmp(const void *a, const void *b) { - const m3dfsave_t *A = (const m3dfsave_t*)a, *B = (const m3dfsave_t*)b; - return A->group != B->group ? A->group - B->group : (A->opacity != B->opacity ? (int)B->opacity - (int)A->opacity : - (int)A->data.materialid - (int)B->data.materialid); -} -/* compare face groups */ -static int _m3d_grpcmp(const void *a, const void *b) { return *((uint32_t*)a) - *((uint32_t*)b); } -/* compare UVs */ -static int _m3d_ticmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3dti_t)); } -/* compare skin groups */ -static int _m3d_skincmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3ds_t)); } -/* compare vertices */ -static int _m3d_vrtxcmp(const void *a, const void *b) { - int c = memcmp(a, b, 3 * sizeof(M3D_FLOAT)); - if(c) return c; - c = ((m3dvsave_t*)a)->norm - ((m3dvsave_t*)b)->norm; - if(c) return c; - return memcmp(a, b, sizeof(m3dv_t)); -} -/* compare labels */ -static _inline int _m3d_strcmp(char *a, char *b) -{ - if(a == NULL && b != NULL) return -1; - if(a != NULL && b == NULL) return 1; - if(a == NULL && b == NULL) return 0; - return strcmp(a, b); -} -static int _m3d_lblcmp(const void *a, const void *b) { - const m3dl_t *A = (const m3dl_t*)a, *B = (const m3dl_t*)b; - int c = _m3d_strcmp(A->lang, B->lang); - if(!c) c = _m3d_strcmp(A->name, B->name); - if(!c) c = _m3d_strcmp(A->text, B->text); - return c; -} -/* compare two colors by HSV value */ -_inline static int _m3d_cmapcmp(const void *a, const void *b) -{ - uint8_t *A = (uint8_t*)a, *B = (uint8_t*)b; - _register int m, vA, vB; - /* get HSV value for A */ - m = A[2] < A[1]? A[2] : A[1]; if(A[0] < m) m = A[0]; - vA = A[2] > A[1]? A[2] : A[1]; if(A[0] > vA) vA = A[0]; - /* get HSV value for B */ - m = B[2] < B[1]? B[2] : B[1]; if(B[0] < m) m = B[0]; - vB = B[2] > B[1]? B[2] : B[1]; if(B[0] > vB) vB = B[0]; - return vA - vB; -} - -/* create sorted list of colors */ -static uint32_t *_m3d_addcmap(uint32_t *cmap, uint32_t *numcmap, uint32_t color) -{ - uint32_t i; - if(cmap) { - for(i = 0; i < *numcmap; i++) - if(cmap[i] == color) return cmap; - } - cmap = (uint32_t*)M3D_REALLOC(cmap, ((*numcmap) + 1) * sizeof(uint32_t)); - for(i = 0; i < *numcmap && _m3d_cmapcmp(&color, &cmap[i]) > 0; i++); - if(i < *numcmap) memmove(&cmap[i+1], &cmap[i], ((*numcmap) - i)*sizeof(uint32_t)); - cmap[i] = color; - (*numcmap)++; - return cmap; -} - -/* look up a color and return its index */ -static uint32_t _m3d_cmapidx(uint32_t *cmap, uint32_t numcmap, uint32_t color) -{ - uint32_t i; - if(numcmap >= 65536) - return color; - for(i = 0; i < numcmap; i++) - if(cmap[i] == color) return i; - return 0; -} - -/* add index to output */ -static unsigned char *_m3d_addidx(unsigned char *out, char type, uint32_t idx) { - switch(type) { - case 1: *out++ = (uint8_t)(idx); break; - case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = (uint32_t)(idx); out += 4; break; - /* case 0: case 8: break; */ - } - return out; -} - -/* round a vertex position */ -static void _m3d_round(int quality, m3dv_t *src, m3dv_t *dst) -{ - _register int t; - /* copy additional attributes */ - if(src != dst) memcpy(dst, src, sizeof(m3dv_t)); - /* round according to quality */ - switch(quality) { - case M3D_EXP_INT8: - t = (int)(src->x * 127 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)127.0; - t = (int)(src->y * 127 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)127.0; - t = (int)(src->z * 127 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)127.0; - t = (int)(src->w * 127 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)127.0; - break; - case M3D_EXP_INT16: - t = (int)(src->x * 32767 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; - t = (int)(src->y * 32767 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; - t = (int)(src->z * 32767 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; - t = (int)(src->w * 32767 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; - break; - } - if(dst->x == (M3D_FLOAT)-0.0) dst->x = (M3D_FLOAT)0.0; - if(dst->y == (M3D_FLOAT)-0.0) dst->y = (M3D_FLOAT)0.0; - if(dst->z == (M3D_FLOAT)-0.0) dst->z = (M3D_FLOAT)0.0; - if(dst->w == (M3D_FLOAT)-0.0) dst->w = (M3D_FLOAT)0.0; -} - -#ifdef M3D_ASCII -/* add a bone to ascii output */ -static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level, M3D_INDEX *vrtxidx) -{ - uint32_t i, j; - char *sn; - - if(level > M3D_BONEMAXLEVEL || !bone) return ptr; - for(i = 0; i < numbone; i++) { - if(bone[i].parent == parent) { - for(j = 0; j < level; j++) *ptr++ = '/'; - sn = _m3d_safestr(bone[i].name, 0); - ptr += sprintf(ptr, "%d %d %s\r\n", vrtxidx[bone[i].pos], vrtxidx[bone[i].ori], sn); - M3D_FREE(sn); - ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1, vrtxidx); - } - } - return ptr; -} -#endif - -/** - * Function to encode an in-memory model into on storage Model 3D format - */ -unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size) -{ -#ifdef M3D_ASCII - const char *ol; - char *ptr; -#endif - char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s, vd_s, vp_s; - char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL; - unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE < 8 ? 8 : M3D_NUMBONE], *norm = NULL; - unsigned int i, j, k, l, n, o, len, chunklen, *length; - int maxvox = 0, minvox = 0; - M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z, mw; - M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL; -#ifdef M3D_VERTEXMAX - M3D_INDEX lastp; -#endif - uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0; - uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL; - uint8_t *opa = NULL; - m3dcd_t *cd; - m3dc_t *cmd; - m3dstr_t *str = NULL; - m3dvsave_t *vrtx = NULL, vertex; - m3dtisave_t *tmap = NULL, tcoord; - m3dssave_t *skin = NULL, sk; - m3dfsave_t *face = NULL; - m3dhdr_t *h = NULL; - m3dm_t *m; - m3da_t *a; - - if(!model) { - if(size) *size = 0; - return NULL; - } - model->errcode = M3D_SUCCESS; -#ifdef M3D_ASCII - if(flags & M3D_EXP_ASCII) quality = M3D_EXP_DOUBLE; -#endif - vrtxidx = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX)); - if(!vrtxidx) goto memerr; - memset(vrtxidx, 255, model->numvertex * sizeof(M3D_INDEX)); - if(model->numvertex && !(flags & M3D_EXP_NONORMAL)){ - norm = (unsigned char*)M3D_MALLOC(model->numvertex * sizeof(unsigned char)); - if(!norm) goto memerr; - memset(norm, 0, model->numvertex * sizeof(unsigned char)); - } - if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { - mtrlidx = (M3D_INDEX*)M3D_MALLOC(model->nummaterial * sizeof(M3D_INDEX)); - if(!mtrlidx) goto memerr; - memset(mtrlidx, 255, model->nummaterial * sizeof(M3D_INDEX)); - opa = (uint8_t*)M3D_MALLOC(model->nummaterial * 2 * sizeof(M3D_INDEX)); - if(!opa) goto memerr; - memset(opa, 255, model->nummaterial * 2 * sizeof(M3D_INDEX)); - } - if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { - tmapidx = (M3D_INDEX*)M3D_MALLOC(model->numtmap * sizeof(M3D_INDEX)); - if(!tmapidx) goto memerr; - memset(tmapidx, 255, model->numtmap * sizeof(M3D_INDEX)); - } - /** collect array elements that are actually referenced **/ - if(!(flags & M3D_EXP_NOFACE)) { - /* face */ - if(model->numface && model->face) { - M3D_LOG("Processing mesh face"); - face = (m3dfsave_t*)M3D_MALLOC(model->numface * sizeof(m3dfsave_t)); - if(!face) goto memerr; - for(i = 0; i < model->numface; i++) { - memcpy(&face[i].data, &model->face[i], sizeof(m3df_t)); - face[i].group = 0; - face[i].opacity = 255; - if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid < model->nummaterial) { - if(model->material[model->face[i].materialid].numprop) { - mtrlidx[model->face[i].materialid] = 0; - if(opa[model->face[i].materialid * 2]) { - m = &model->material[model->face[i].materialid]; - for(j = 0; j < m->numprop; j++) - if(m->prop[j].type == m3dp_Kd) { - opa[model->face[i].materialid * 2 + 1] = ((uint8_t*)&m->prop[j].value.color)[3]; - break; - } - for(j = 0; j < m->numprop; j++) - if(m->prop[j].type == m3dp_d) { - opa[model->face[i].materialid * 2 + 1] = (uint8_t)(m->prop[j].value.fnum * 255); - break; - } - opa[model->face[i].materialid * 2] = 0; - } - face[i].opacity = opa[model->face[i].materialid * 2 + 1]; - } else - face[i].data.materialid = M3D_UNDEF; - } - for(j = 0; j < 3; j++) { - k = model->face[i].vertex[j]; - if(k < model->numvertex) - vrtxidx[k] = 0; - if(!(flags & M3D_EXP_NOCMAP)) { - cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color); - if(!cmap) goto memerr; - } - k = model->face[i].normal[j]; - if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) { - vrtxidx[k] = 0; - norm[k] = 1; - } - k = model->face[i].texcoord[j]; - if(k < model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) - tmapidx[k] = 0; -#ifdef M3D_VERTEXMAX - k = model->face[i].vertmax[j]; - if(k < model->numvertex && !(flags & M3D_EXP_NOVRTMAX)) - vrtxidx[k] = 0; -#endif - } - /* convert from CW to CCW */ - if(flags & M3D_EXP_IDOSUCK) { - j = face[i].data.vertex[1]; - face[i].data.vertex[1] = face[i].data.vertex[2]; - face[i].data.vertex[2] = j; - j = face[i].data.normal[1]; - face[i].data.normal[1] = face[i].data.normal[2]; - face[i].data.normal[2] = j; - j = face[i].data.texcoord[1]; - face[i].data.texcoord[1] = face[i].data.texcoord[2]; - face[i].data.texcoord[2] = j; -#ifdef M3D_VERTEXMAX - j = face[i].data.vertmax[1]; - face[i].data.vertmax[1] = face[i].data.vertmax[2]; - face[i].data.vertmax[2] = j; -#endif - } - } - } - if((model->numvoxtype && model->voxtype) || (model->numvoxel && model->voxel)) { - M3D_LOG("Processing voxel face"); - for(i = 0; i < model->numvoxtype; i++) { - str = _m3d_addstr(str, &numstr, model->voxtype[i].name); - if(model->voxtype[i].name && !str) goto memerr; - if(!(flags & M3D_EXP_NOCMAP)) { - cmap = _m3d_addcmap(cmap, &numcmap, model->voxtype[i].color); - if(!cmap) goto memerr; - } - for(j = 0; j < model->voxtype[i].numitem; j++) { - str = _m3d_addstr(str, &numstr, model->voxtype[i].item[j].name); - if(model->voxtype[i].item[j].name && !str) goto memerr; - } - } - for(i = 0; i < model->numvoxel; i++) { - str = _m3d_addstr(str, &numstr, model->voxel[i].name); - if(model->voxel[i].name && !str) goto memerr; - if(model->voxel[i].x < minvox) minvox = model->voxel[i].x; - if(model->voxel[i].x + (int)model->voxel[i].w > maxvox) maxvox = model->voxel[i].x + model->voxel[i].w; - if(model->voxel[i].y < minvox) minvox = model->voxel[i].y; - if(model->voxel[i].y + (int)model->voxel[i].h > maxvox) maxvox = model->voxel[i].y + model->voxel[i].h; - if(model->voxel[i].z < minvox) minvox = model->voxel[i].z; - if(model->voxel[i].z + (int)model->voxel[i].d > maxvox) maxvox = model->voxel[i].z + model->voxel[i].d; - } - } - if(model->numshape && model->shape) { - M3D_LOG("Processing shape face"); - for(i = 0; i < model->numshape; i++) { - if(!model->shape[i].numcmd) continue; - str = _m3d_addstr(str, &numstr, model->shape[i].name); - if(model->shape[i].name && !str) goto memerr; - for(j = 0; j < model->shape[i].numcmd; j++) { - cmd = &model->shape[i].cmd[j]; - if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) - continue; - if(cmd->type == m3dc_mesh) { - if(numgrp + 2 < maxgrp) { - maxgrp += 1024; - grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t)); - if(!grpidx) goto memerr; - if(!numgrp) { - grpidx[0] = 0; - grpidx[1] = model->numface; - numgrp += 2; - } - } - grpidx[numgrp + 0] = cmd->arg[0]; - grpidx[numgrp + 1] = cmd->arg[0] + cmd->arg[1]; - numgrp += 2; - } - cd = &m3d_commandtypes[cmd->type]; - for(k = n = 0, l = cd->p; k < l; k++) - switch(cd->a[((k - n) % (cd->p - n)) + n]) { - case m3dcp_mi_t: - if(!(flags & M3D_EXP_NOMATERIAL) && cmd->arg[k] < model->nummaterial) - mtrlidx[cmd->arg[k]] = 0; - break; - case m3dcp_ti_t: - if(!(flags & M3D_EXP_NOTXTCRD) && cmd->arg[k] < model->numtmap) - tmapidx[cmd->arg[k]] = 0; - break; - case m3dcp_qi_t: - case m3dcp_vi_t: - if(cmd->arg[k] < model->numvertex) - vrtxidx[cmd->arg[k]] = 0; - break; - case m3dcp_va_t: - n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); - break; - } - } - } - } - if(model->numface && face) { - if(numgrp && grpidx) { - qsort(grpidx, numgrp, sizeof(uint32_t), _m3d_grpcmp); - for(i = j = 0; i < model->numface && j < numgrp; i++) { - while(j < numgrp && grpidx[j] < i) j++; - face[i].group = j; - } - } - qsort(face, model->numface, sizeof(m3dfsave_t), _m3d_facecmp); - } - if(grpidx) { M3D_FREE(grpidx); grpidx = NULL; } - if(model->numlabel && model->label) { - M3D_LOG("Processing annotation labels"); - for(i = 0; i < model->numlabel; i++) { - str = _m3d_addstr(str, &numstr, model->label[i].name); - str = _m3d_addstr(str, &numstr, model->label[i].lang); - str = _m3d_addstr(str, &numstr, model->label[i].text); - if(!(flags & M3D_EXP_NOCMAP)) { - cmap = _m3d_addcmap(cmap, &numcmap, model->label[i].color); - if(!cmap) goto memerr; - } - if(model->label[i].vertexid < model->numvertex) - vrtxidx[model->label[i].vertexid] = 0; - } - qsort(model->label, model->numlabel, sizeof(m3dl_t), _m3d_lblcmp); - } - } else if(!(flags & M3D_EXP_NOMATERIAL)) { - /* without a face, simply add all materials, because it can be an mtllib */ - for(i = 0; i < model->nummaterial; i++) - mtrlidx[i] = i; - } - /* bind-pose skeleton */ - if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { - M3D_LOG("Processing bones"); - for(i = 0; i < model->numbone; i++) { - str = _m3d_addstr(str, &numstr, model->bone[i].name); - if(!str) goto memerr; - k = model->bone[i].pos; - if(k < model->numvertex) - vrtxidx[k] = 0; - k = model->bone[i].ori; - if(k < model->numvertex) - vrtxidx[k] = 0; - } - } - /* actions, animated skeleton poses */ - if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { - M3D_LOG("Processing action list"); - for(j = 0; j < model->numaction; j++) { - a = &model->action[j]; - str = _m3d_addstr(str, &numstr, a->name); - if(!str) goto memerr; - if(a->numframe > 65535) a->numframe = 65535; - for(i = 0; i < a->numframe; i++) { - for(l = 0; l < a->frame[i].numtransform; l++) { - k = a->frame[i].transform[l].pos; - if(k < model->numvertex) - vrtxidx[k] = 0; - k = a->frame[i].transform[l].ori; - if(k < model->numvertex) - vrtxidx[k] = 0; - } - if(l > maxt) maxt = l; - } - } - } - /* add colors to color map and texture names to string table */ - if(!(flags & M3D_EXP_NOMATERIAL)) { - M3D_LOG("Processing materials"); - for(i = k = 0; i < model->nummaterial; i++) { - if(mtrlidx[i] == M3D_UNDEF || !model->material[i].numprop) continue; - mtrlidx[i] = k++; - m = &model->material[i]; - str = _m3d_addstr(str, &numstr, m->name); - if(!str) goto memerr; - if(m->prop) - for(j = 0; j < m->numprop; j++) { - if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) { - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) { - if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) { - ((uint8_t*)&m->prop[j].value.color)[3] = opa[i * 2 + 1]; - cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color); - if(!cmap) goto memerr; - break; - } - } - } - if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture && - model->texture[m->prop[j].value.textureid].name) { - str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name); - if(!str) goto memerr; - } - } - } - } - /* if there's only one black color, don't store it */ - if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0; - - /** compress lists **/ - if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { - M3D_LOG("Compressing tmap"); - tmap = (m3dtisave_t*)M3D_MALLOC(model->numtmap * sizeof(m3dtisave_t)); - if(!tmap) goto memerr; - for(i = 0; i < model->numtmap; i++) { - if(tmapidx[i] == M3D_UNDEF) continue; - switch(quality) { - case M3D_EXP_INT8: - l = (unsigned int)(model->tmap[i].u * 255); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)255.0; - l = (unsigned int)(model->tmap[i].v * 255); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)255.0; - break; - case M3D_EXP_INT16: - l = (unsigned int)(model->tmap[i].u * 65535); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; - l = (unsigned int)(model->tmap[i].v * 65535); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; - break; - default: - tcoord.data.u = model->tmap[i].u; - tcoord.data.v = model->tmap[i].v; - break; - } - if(flags & M3D_EXP_FLIPTXTCRD) - tcoord.data.v = (M3D_FLOAT)1.0 - tcoord.data.v; - tcoord.oldidx = i; - memcpy(&tmap[numtmap++], &tcoord, sizeof(m3dtisave_t)); - } - if(numtmap) { - qsort(tmap, numtmap, sizeof(m3dtisave_t), _m3d_ticmp); - memcpy(&tcoord.data, &tmap[0], sizeof(m3dti_t)); - for(i = 0; i < numtmap; i++) { - if(memcmp(&tcoord.data, &tmap[i].data, sizeof(m3dti_t))) { - memcpy(&tcoord.data, &tmap[i].data, sizeof(m3dti_t)); - maxtmap++; - } - tmap[i].newidx = maxtmap; - tmapidx[tmap[i].oldidx] = maxtmap; - } - maxtmap++; - } - } - if(model->numskin && model->skin && !(flags & M3D_EXP_NOBONE)) { - M3D_LOG("Compressing skin"); - skinidx = (M3D_INDEX*)M3D_MALLOC(model->numskin * sizeof(M3D_INDEX)); - if(!skinidx) goto memerr; - skin = (m3dssave_t*)M3D_MALLOC(model->numskin * sizeof(m3dssave_t)); - if(!skin) goto memerr; - memset(skinidx, 255, model->numskin * sizeof(M3D_INDEX)); - for(i = 0; i < model->numvertex; i++) { - if(vrtxidx[i] != M3D_UNDEF && model->vertex[i].skinid < model->numskin) - skinidx[model->vertex[i].skinid] = 0; - } - for(i = 0; i < model->numskin; i++) { - if(skinidx[i] == M3D_UNDEF) continue; - memset(&sk, 0, sizeof(m3dssave_t)); - for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF; j++) { - sk.data.boneid[j] = model->skin[i].boneid[j]; - sk.data.weight[j] = model->skin[i].weight[j] > (M3D_FLOAT)0.0 ? model->skin[i].weight[j] : (M3D_FLOAT)0.01; - min_x += sk.data.weight[j]; - } - if(j > maxbone) maxbone = j; - if(min_x != (M3D_FLOAT)1.0 && min_x != (M3D_FLOAT)0.0) - for(j = 0; j < M3D_NUMBONE && sk.data.weight[j] > (M3D_FLOAT)0.0; j++) - sk.data.weight[j] /= min_x; - sk.oldidx = i; - memcpy(&skin[numskin++], &sk, sizeof(m3dssave_t)); - } - if(numskin) { - qsort(skin, numskin, sizeof(m3dssave_t), _m3d_skincmp); - memcpy(&sk.data, &skin[0].data, sizeof(m3ds_t)); - for(i = 0; i < numskin; i++) { - if(memcmp(&sk.data, &skin[i].data, sizeof(m3ds_t))) { - memcpy(&sk.data, &skin[i].data, sizeof(m3ds_t)); - maxskin++; - } - skin[i].newidx = maxskin; - skinidx[skin[i].oldidx] = maxskin; - } - maxskin++; - } - } - - M3D_LOG("Compressing vertex list"); - min_x = min_y = min_z = (M3D_FLOAT)1e10; - max_x = max_y = max_z = (M3D_FLOAT)-1e10; - if(vrtxidx) { - vrtx = (m3dvsave_t*)M3D_MALLOC(model->numvertex * sizeof(m3dvsave_t)); - if(!vrtx) goto memerr; - for(i = numvrtx = 0; i < model->numvertex; i++) { - if(vrtxidx[i] == M3D_UNDEF) continue; - _m3d_round(quality, &model->vertex[i], &vertex.data); - vertex.norm = norm ? norm[i] : 0; - if(vertex.data.skinid != M3D_INDEXMAX && !vertex.norm) { - vertex.data.skinid = vertex.data.skinid != M3D_UNDEF && skinidx ? skinidx[vertex.data.skinid] : M3D_UNDEF; - if(vertex.data.x > max_x) max_x = vertex.data.x; - if(vertex.data.x < min_x) min_x = vertex.data.x; - if(vertex.data.y > max_y) max_y = vertex.data.y; - if(vertex.data.y < min_y) min_y = vertex.data.y; - if(vertex.data.z > max_z) max_z = vertex.data.z; - if(vertex.data.z < min_z) min_z = vertex.data.z; - } -#ifdef M3D_VERTEXTYPE - vertex.data.type = 0; -#endif - vertex.oldidx = i; - memcpy(&vrtx[numvrtx++], &vertex, sizeof(m3dvsave_t)); - } - if(numvrtx) { - qsort(vrtx, numvrtx, sizeof(m3dvsave_t), _m3d_vrtxcmp); - memcpy(&vertex.data, &vrtx[0].data, sizeof(m3dv_t)); - for(i = 0; i < numvrtx; i++) { - if(memcmp(&vertex.data, &vrtx[i].data, vrtx[i].norm ? 3 * sizeof(M3D_FLOAT) : sizeof(m3dv_t))) { - memcpy(&vertex.data, &vrtx[i].data, sizeof(m3dv_t)); - maxvrtx++; - } - vrtx[i].newidx = maxvrtx; - vrtxidx[vrtx[i].oldidx] = maxvrtx; - } - maxvrtx++; - } - } - if(norm) { M3D_FREE(norm); norm = NULL; } - - /* normalize to bounding cube */ - if(numvrtx && !(flags & M3D_EXP_NORECALC)) { - M3D_LOG("Normalizing coordinates"); - if(min_x < (M3D_FLOAT)0.0) min_x = -min_x; - if(max_x < (M3D_FLOAT)0.0) max_x = -max_x; - if(min_y < (M3D_FLOAT)0.0) min_y = -min_y; - if(max_y < (M3D_FLOAT)0.0) max_y = -max_y; - if(min_z < (M3D_FLOAT)0.0) min_z = -min_z; - if(max_z < (M3D_FLOAT)0.0) max_z = -max_z; - scale = min_x; - if(max_x > scale) scale = max_x; - if(min_y > scale) scale = min_y; - if(max_y > scale) scale = max_y; - if(min_z > scale) scale = min_z; - if(max_z > scale) scale = max_z; - if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; - if(scale != (M3D_FLOAT)1.0) { - for(i = 0; i < numvrtx; i++) { - if(vrtx[i].data.skinid == M3D_INDEXMAX) continue; - vrtx[i].data.x /= scale; - vrtx[i].data.y /= scale; - vrtx[i].data.z /= scale; - } - } - } - if(model->scale > (M3D_FLOAT)0.0) scale = model->scale; - if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; - - /* meta info */ - sn = _m3d_safestr(model->name && *model->name ? model->name : (char*)"(noname)", 2); - sl = _m3d_safestr(model->license ? model->license : (char*)"MIT", 2); - sa = _m3d_safestr(model->author ? model->author : getenv("LOGNAME"), 2); - if(!sn || !sl || !sa) { -memerr: if(vrtxidx) M3D_FREE(vrtxidx); - if(mtrlidx) M3D_FREE(mtrlidx); - if(tmapidx) M3D_FREE(tmapidx); - if(skinidx) M3D_FREE(skinidx); - if(grpidx) M3D_FREE(grpidx); - if(norm) M3D_FREE(norm); - if(face) M3D_FREE(face); - if(cmap) M3D_FREE(cmap); - if(tmap) M3D_FREE(tmap); - if(skin) M3D_FREE(skin); - if(str) M3D_FREE(str); - if(vrtx) M3D_FREE(vrtx); - if(sn) M3D_FREE(sn); - if(sl) M3D_FREE(sl); - if(sa) M3D_FREE(sa); - if(sd) M3D_FREE(sd); - if(out) M3D_FREE(out); - if(opa) free(opa); - if(h) M3D_FREE(h); - M3D_LOG("Out of memory"); - model->errcode = M3D_ERR_ALLOC; - return NULL; - } - - M3D_LOG("Serializing model"); -#ifdef M3D_ASCII - if(flags & M3D_EXP_ASCII) { - /* use CRLF to make model creators on Win happy... */ - sd = _m3d_safestr(model->desc, 1); - if(!sd) goto memerr; - ol = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "C"); - /* header */ - len = 64 + (unsigned int)(strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd)); - out = (unsigned char*)M3D_MALLOC(len); - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr = (char*)out; - ptr += sprintf(ptr, "3dmodel %g\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n", scale, - sn, sl, sa, sd); - M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd); - sl = sa = sd = NULL; - /* preview chunk */ - if(model->preview.data && model->preview.length) { - sl = _m3d_safestr(sn, 0); - if(sl) { -/* gcc thinks that "ptr is used after free", well, gcc is simply wrong. */ -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuse-after-free" -#endif - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)20 + strlen(sl)); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl); - M3D_FREE(sl); sl = NULL; - } - } - M3D_FREE(sn); sn = NULL; - /* texture map */ - if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { -/* interestingly gcc does not complain about "ptr is used after free" here, although the code is 100% the same */ - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxtmap * 32) + (uintptr_t)12); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Textmap\r\n"); - last = M3D_UNDEF; - for(i = 0; i < numtmap; i++) { - if(tmap[i].newidx == last) continue; - last = tmap[i].newidx; - ptr += sprintf(ptr, "%g %g\r\n", tmap[i].data.u, tmap[i].data.v); - } - ptr += sprintf(ptr, "\r\n"); - } - /* vertex chunk */ - if(numvrtx && vrtx && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxvrtx * 128) + (uintptr_t)10); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Vertex\r\n"); - last = M3D_UNDEF; - for(i = 0; i < numvrtx; i++) { - if(vrtx[i].newidx == last) continue; - last = vrtx[i].newidx; - ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].data.x, vrtx[i].data.y, vrtx[i].data.z, vrtx[i].data.w); - if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].data.color) - ptr += sprintf(ptr, " #%08x", vrtx[i].data.color); - if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && vrtx[i].data.skinid < M3D_INDEXMAX) { - if(skin[vrtx[i].data.skinid].data.weight[0] == (M3D_FLOAT)1.0) - ptr += sprintf(ptr, " %d", skin[vrtx[i].data.skinid].data.boneid[0]); - else - for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].data.skinid].data.boneid[j] != M3D_UNDEF && - skin[vrtx[i].data.skinid].data.weight[j] > (M3D_FLOAT)0.0; j++) - ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].data.skinid].data.boneid[j], - skin[vrtx[i].data.skinid].data.weight[j]); - } - ptr += sprintf(ptr, "\r\n"); - } - ptr += sprintf(ptr, "\r\n"); - } - /* bones chunk */ - if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)9); - for(i = 0; i < model->numbone; i++) { - len += (unsigned int)strlen(model->bone[i].name) + 128; - } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Bones\r\n"); - ptr = _m3d_prtbone(ptr, model->bone, model->numbone, M3D_UNDEF, 0, vrtxidx); - ptr += sprintf(ptr, "\r\n"); - } - /* materials */ - if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { - for(j = 0; j < model->nummaterial; j++) { - if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; - m = &model->material[j]; - sn = _m3d_safestr(m->name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)12); - for(i = 0; i < m->numprop; i++) { - if(m->prop[i].type < 128) - len += 32; - else if(m->prop[i].value.textureid < model->numtexture && model->texture[m->prop[i].value.textureid].name) - len += (unsigned int)strlen(model->texture[m->prop[i].value.textureid].name) + 16; - } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Material %s\r\n", sn); - M3D_FREE(sn); sn = NULL; - for(i = 0; i < m->numprop; i++) { - k = 256; - if(m->prop[i].type >= 128) { - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) - if(m->prop[i].type == m3d_propertytypes[l].id) { - sn = m3d_propertytypes[l].key; - break; - } - if(!sn) - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) - if(m->prop[i].type - 128 == m3d_propertytypes[l].id) { - sn = m3d_propertytypes[l].key; - break; - } - k = sn ? m3dpf_map : 256; - } else { - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) - if(m->prop[i].type == m3d_propertytypes[l].id) { - sn = m3d_propertytypes[l].key; - k = m3d_propertytypes[l].format; - break; - } - } - switch(k) { - case m3dpf_color: ptr += sprintf(ptr, "%s #%08x\r\n", sn, m->prop[i].value.color); break; - case m3dpf_uint8: - case m3dpf_uint16: - case m3dpf_uint32: ptr += sprintf(ptr, "%s %d\r\n", sn, m->prop[i].value.num); break; - case m3dpf_float: ptr += sprintf(ptr, "%s %g\r\n", sn, m->prop[i].value.fnum); break; - case m3dpf_map: - if(m->prop[i].value.textureid < model->numtexture && - model->texture[m->prop[i].value.textureid].name) { - sl = _m3d_safestr(model->texture[m->prop[i].value.textureid].name, 0); - if(!sl) { setlocale(LC_NUMERIC, ol); goto memerr; } - if(*sl) - ptr += sprintf(ptr, "map_%s %s\r\n", sn, sl); - M3D_FREE(sn); M3D_FREE(sl); sl = NULL; - } - break; - } - sn = NULL; - } - ptr += sprintf(ptr, "\r\n"); - } - } - /* procedural face */ - if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { - /* all inlined assets which are not textures should be procedural surfaces */ - for(j = 0; j < model->numinlined; j++) { - if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length || !model->inlined[j].data || - (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G')) - continue; - for(i = k = 0; i < model->numtexture; i++) { - if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } - } - if(k) continue; - sn = _m3d_safestr(model->inlined[j].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)18); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Procedural\r\n%s\r\n\r\n", sn); - M3D_FREE(sn); sn = NULL; - } - } - /* mesh face */ - if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(model->numface * 128) + (uintptr_t)6); - last = M3D_UNDEF; -#ifdef M3D_VERTEXMAX - lastp = M3D_UNDEF; -#endif - if(!(flags & M3D_EXP_NOMATERIAL)) - for(i = 0; i < model->numface; i++) { - j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; - if(j != last) { - last = j; - if(last < model->nummaterial) - len += (unsigned int)strlen(model->material[last].name); - len += 6; - } -#ifdef M3D_VERTEXMAX - j = face[i].data.paramid < model->numparam ? face[i].data.paramid : M3D_UNDEF; - if(j != lastp) { - lastp = j; - if(lastp < model->numparam) - len += (unsigned int)strlen(model->param[lastp].name); - len += 6; - } -#endif - } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Mesh\r\n"); - last = M3D_UNDEF; -#ifdef M3D_VERTEXMAX - lastp = M3D_UNDEF; -#endif - for(i = 0; i < model->numface; i++) { - j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; - if(!(flags & M3D_EXP_NOMATERIAL) && j != last) { - last = j; - if(last < model->nummaterial) { - sn = _m3d_safestr(model->material[last].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "use %s\r\n", sn); - M3D_FREE(sn); sn = NULL; - } else - ptr += sprintf(ptr, "use\r\n"); - } -#ifdef M3D_VERTEXMAX - j = face[i].data.paramid < model->numparam ? face[i].data.paramid : M3D_UNDEF; - if(!(flags & M3D_EXP_NOVRTMAX) && j != lastp) { - lastp = j; - if(lastp < model->numparam) { - sn = _m3d_safestr(model->param[lastp].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "par %s\r\n", sn); - M3D_FREE(sn); sn = NULL; - } else - ptr += sprintf(ptr, "par\r\n"); - } -#endif - /* hardcoded triangles. Should be repeated as many times as the number of edges in polygon */ - for(j = 0; j < 3; j++) { - ptr += sprintf(ptr, "%s%d", j?" ":"", vrtxidx[face[i].data.vertex[j]]); - k = l = M3D_NOTDEFINED; - if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].data.texcoord[j] != M3D_UNDEF) && - (tmapidx[face[i].data.texcoord[j]] != M3D_UNDEF)) { - k = tmapidx[face[i].data.texcoord[j]]; - ptr += sprintf(ptr, "/%d", k); - } - if(!(flags & M3D_EXP_NONORMAL) && (face[i].data.normal[j] != M3D_UNDEF)) { - l = vrtxidx[face[i].data.normal[j]]; - ptr += sprintf(ptr, "%s/%d", k == M3D_NOTDEFINED? "/" : "", l); - } -#ifdef M3D_VERTEXMAX - if(!(flags & M3D_EXP_NOVRTMAX) && (face[i].data.vertmax[j] != M3D_UNDEF)) { - ptr += sprintf(ptr, "%s%s/%d", k == M3D_NOTDEFINED? "/" : "", l == M3D_NOTDEFINED? "/" : "", - vrtxidx[face[i].data.vertmax[j]]); - } -#endif - } - ptr += sprintf(ptr, "\r\n"); - } - ptr += sprintf(ptr, "\r\n"); - } - /* voxel face */ - if(model->numvoxtype && model->voxtype && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(model->numvoxtype * 128) + (uintptr_t)10); - for(i = 0; i < model->numvoxtype; i++) { - if(model->voxtype[i].name) len += (unsigned int)strlen(model->voxtype[i].name); - for(j = 0; j < model->voxtype[i].numitem; j++) - if(model->voxtype[i].item[j].name) - len += (unsigned int)strlen(model->voxtype[i].item[j].name) + 6; - } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "VoxTypes\r\n"); - for(i = 0; i < model->numvoxtype; i++) { - ptr += sprintf(ptr, "#%08x", model->voxtype[i].color); - if(model->voxtype[i].rotation) - ptr += sprintf(ptr, "/%02x", model->voxtype[i].rotation); - if(model->voxtype[i].voxshape) - ptr += sprintf(ptr, "%s/%03x", model->voxtype[i].rotation ? "" : "/", model->voxtype[i].voxshape); - sn = _m3d_safestr(model->voxtype[i].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, " %s", sn && sn[0] ? sn : "-"); - M3D_FREE(sn); sn = NULL; - if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && model->voxtype[i].skinid < M3D_INDEXMAX) { - if(skin[skinidx[model->voxtype[i].skinid]].data.weight[0] == (M3D_FLOAT)1.0) - ptr += sprintf(ptr, " %d", skin[skinidx[model->voxtype[i].skinid]].data.boneid[0]); - else - for(j = 0; j < M3D_NUMBONE && skin[skinidx[model->voxtype[i].skinid]].data.boneid[j] != M3D_UNDEF && - skin[skinidx[model->voxtype[i].skinid]].data.weight[j] > (M3D_FLOAT)0.0; j++) - ptr += sprintf(ptr, " %d:%g", skin[skinidx[model->voxtype[i].skinid]].data.boneid[j], - skin[skinidx[model->voxtype[i].skinid]].data.weight[j]); - } - if(model->voxtype[i].numitem && model->voxtype[i].item) { - for(j = k = 0; j < model->voxtype[i].numitem; j++) { - if(!model->voxtype[i].item[j].count || !model->voxtype[i].item[j].name || - !model->voxtype[i].item[j].name[0]) continue; - if(!k) { ptr += sprintf(ptr, " {"); k = 1; } - sn = _m3d_safestr(model->voxtype[i].item[j].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, " %d %s", model->voxtype[i].item[j].count, sn); - M3D_FREE(sn); sn = NULL; - } - if(k) ptr += sprintf(ptr, " }"); - } - while(ptr[-1] == '-' || ptr[-1] == ' ') ptr--; - ptr += sprintf(ptr, "\r\n"); - } - ptr += sprintf(ptr, "\r\n"); - } - if(model->numvoxel && model->voxel && !(flags & M3D_EXP_NOFACE)) { - for(i = 0; i < model->numvoxel; i++) { - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)128); - if(model->voxel[i].name) len += (unsigned int)strlen(model->voxel[i].name); - len += model->voxel[i].h * ((model->voxel[i].w * 6 + 2) * model->voxel[i].d + 9); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Voxel"); - sn = _m3d_safestr(model->voxel[i].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - if(sn && sn[0]) - ptr += sprintf(ptr, " %s", sn); - M3D_FREE(sn); sn = NULL; - ptr += sprintf(ptr, "\r\n"); - if(model->voxel[i].uncertain) - ptr += sprintf(ptr, "uncertain %d %d\r\n", (model->voxel[i].uncertain * 100) / 255, model->voxel[i].groupid); - if(model->voxel[i].x || model->voxel[i].y || model->voxel[i].z) - ptr += sprintf(ptr, "pos %d %d %d\r\n", model->voxel[i].x, model->voxel[i].y, model->voxel[i].z); - ptr += sprintf(ptr, "dim %d %d %d\r\n", model->voxel[i].w, model->voxel[i].h, model->voxel[i].d); - for(j = n = 0; j < model->voxel[i].h; j++) { - ptr += sprintf(ptr, "layer\r\n"); - for(k = 0; k < model->voxel[i].d; k++) { - for(l = 0; l < model->voxel[i].w; l++, n++) { - switch(model->voxel[i].data[n]) { - case M3D_VOXCLEAR: *ptr++ = '-'; break; - case M3D_VOXUNDEF: *ptr++ = '.'; break; - default: ptr += sprintf(ptr, "%d", model->voxel[i].data[n]); break; - } - *ptr++ = ' '; - } - ptr--; - ptr += sprintf(ptr, "\r\n"); - } - } - ptr += sprintf(ptr, "\r\n"); - } - } - /* mathematical shapes face */ - if(model->numshape && model->numshape && !(flags & M3D_EXP_NOFACE)) { - for(j = 0; j < model->numshape; j++) { - sn = _m3d_safestr(model->shape[j].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)33); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Shape %s\r\n", sn); - M3D_FREE(sn); sn = NULL; - if(model->shape[j].group != M3D_UNDEF && !(flags & M3D_EXP_NOBONE)) - ptr += sprintf(ptr, "group %d\r\n", model->shape[j].group); - for(i = 0; i < model->shape[j].numcmd; i++) { - cmd = &model->shape[j].cmd[i]; - if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) - continue; - cd = &m3d_commandtypes[cmd->type]; - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(cd->key) + (uintptr_t)3); - for(k = 0; k < cd->p; k++) - switch(cd->a[k]) { - case m3dcp_mi_t: if(cmd->arg[k] != M3D_NOTDEFINED) { len += (unsigned int)strlen(model->material[cmd->arg[k]].name) + 1; } break; - case m3dcp_va_t: len += cmd->arg[k] * (cd->p - k - 1) * 16; k = cd->p; break; - default: len += 16; break; - } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "%s", cd->key); - for(k = n = 0, l = cd->p; k < l; k++) { - switch(cd->a[((k - n) % (cd->p - n)) + n]) { - case m3dcp_mi_t: - if(cmd->arg[k] != M3D_NOTDEFINED) { - sn = _m3d_safestr(model->material[cmd->arg[k]].name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, " %s", sn); - M3D_FREE(sn); sn = NULL; - } - break; - case m3dcp_vc_t: ptr += sprintf(ptr, " %g", *((float*)&cmd->arg[k])); break; - case m3dcp_va_t: ptr += sprintf(ptr, " %d[", cmd->arg[k]); - n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); - break; - default: ptr += sprintf(ptr, " %d", cmd->arg[k]); break; - } - } - ptr += sprintf(ptr, "%s\r\n", l > cd->p ? " ]" : ""); - } - ptr += sprintf(ptr, "\r\n"); - } - } - /* annotation labels */ - if(model->numlabel && model->label && !(flags & M3D_EXP_NOFACE)) { - for(i = 0, j = 3, length = NULL; i < model->numlabel; i++) { - if(model->label[i].name) j += (unsigned int)strlen(model->label[i].name); - if(model->label[i].lang) j += (unsigned int)strlen(model->label[i].lang); - if(model->label[i].text) j += (unsigned int)strlen(model->label[i].text); - j += 40; - } - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - for(i = 0; i < model->numlabel; i++) { - if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { - sl = model->label[i].lang; - sn = model->label[i].name; - sd = _m3d_safestr(sn, 0); - if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } - if(i) ptr += sprintf(ptr, "\r\n"); - ptr += sprintf(ptr, "Labels %s\r\n", sd); - M3D_FREE(sd); sd = NULL; - if(model->label[i].color) - ptr += sprintf(ptr, "color #0x%08x\r\n", model->label[i].color); - if(sl && *sl) { - sd = _m3d_safestr(sl, 0); - if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } - ptr += sprintf(ptr, "lang %s\r\n", sd); - M3D_FREE(sd); sd = NULL; - } - } - sd = _m3d_safestr(model->label[i].text, 2); - if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } - ptr += sprintf(ptr, "%d %s\r\n", model->label[i].vertexid, sd); - M3D_FREE(sd); sd = NULL; - } - ptr += sprintf(ptr, "\r\n"); - sn = sl = NULL; - } - /* actions */ - if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { - for(j = 0; j < model->numaction; j++) { - a = &model->action[j]; - sn = _m3d_safestr(a->name, 0); - if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)48); - for(i = 0; i < a->numframe; i++) - len += a->frame[i].numtransform * 128 + 8; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Action %d %s\r\n", a->durationmsec, sn); - M3D_FREE(sn); sn = NULL; - for(i = 0; i < a->numframe; i++) { - ptr += sprintf(ptr, "frame %d\r\n", a->frame[i].msec); - for(k = 0; k < a->frame[i].numtransform; k++) { - ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, - vrtxidx[a->frame[i].transform[k].pos], vrtxidx[a->frame[i].transform[k].ori]); - } - } - ptr += sprintf(ptr, "\r\n"); - } - } - /* inlined assets */ - if(model->numinlined && model->inlined) { - for(i = j = 0; i < model->numinlined; i++) - if(model->inlined[i].name) - j += (unsigned int)strlen(model->inlined[i].name) + 6; - if(j > 0) { - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j + (uintptr_t)16); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Assets\r\n"); - for(i = 0; i < model->numinlined; i++) - if(model->inlined[i].name) - ptr += sprintf(ptr, "%s%s\r\n", model->inlined[i].name, strrchr(model->inlined[i].name, '.') ? "" : ".png"); - ptr += sprintf(ptr, "\r\n"); - } - } - /* extra info */ - if(model->numextra && (flags & M3D_EXP_EXTRA)) { - for(i = 0; i < model->numextra; i++) { - if(model->extra[i]->length < 9) continue; - ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)17 + (uintptr_t)(model->extra[i]->length * 3)); - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; - if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr += sprintf(ptr, "Extra %c%c%c%c\r\n", - model->extra[i]->magic[0] > ' ' ? model->extra[i]->magic[0] : '_', - model->extra[i]->magic[1] > ' ' ? model->extra[i]->magic[1] : '_', - model->extra[i]->magic[2] > ' ' ? model->extra[i]->magic[2] : '_', - model->extra[i]->magic[3] > ' ' ? model->extra[i]->magic[3] : '_'); - for(j = 0; j < model->extra[i]->length; j++) - ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->extra + sizeof(m3dchunk_t) + j)); - ptr--; - ptr += sprintf(ptr, "\r\n\r\n"); - } - } - setlocale(LC_NUMERIC, ol); - len = (unsigned int)((uintptr_t)ptr - (uintptr_t)out); - out = (unsigned char*)M3D_REALLOC(out, len + 1); - if(!out) goto memerr; - out[len] = 0; - } else -#endif - { - /* stricly only use LF (newline) in binary */ - sd = _m3d_safestr(model->desc, 3); - if(!sd) goto memerr; - /* header */ - h = (m3dhdr_t*)M3D_MALLOC(sizeof(m3dhdr_t) + strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd) + 4); - if(!h) goto memerr; - memcpy((uint8_t*)h, "HEAD", 4); - h->length = sizeof(m3dhdr_t); - h->scale = scale; - i = (unsigned int)strlen(sn); memcpy((uint8_t*)h + h->length, sn, i+1); h->length += i+1; M3D_FREE(sn); - i = (unsigned int)strlen(sl); memcpy((uint8_t*)h + h->length, sl, i+1); h->length += i+1; M3D_FREE(sl); - i = (unsigned int)strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa); - i = (unsigned int)strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd); - sn = sl = sa = sd = NULL; - if(model->inlined) - for(i = 0; i < model->numinlined; i++) { - if(model->inlined[i].name && *model->inlined[i].name && model->inlined[i].length > 0) { - str = _m3d_addstr(str, &numstr, model->inlined[i].name); - if(!str) goto memerr; - } - } - if(str) - for(i = 0; i < numstr; i++) { - h = _m3d_addhdr(h, &str[i]); - if(!h) goto memerr; - } - vc_s = quality == M3D_EXP_INT8? 1 : (quality == M3D_EXP_INT16? 2 : (quality == M3D_EXP_DOUBLE? 8 : 4)); - vi_s = maxvrtx < 254 ? 1 : (maxvrtx < 65534 ? 2 : 4); - si_s = h->length - 16 < 254 ? 1 : (h->length - 16 < 65534 ? 2 : 4); - ci_s = !numcmap || !cmap ? 0 : (numcmap < 254 ? 1 : (numcmap < 65534 ? 2 : 4)); - ti_s = !maxtmap || !tmap ? 0 : (maxtmap < 254 ? 1 : (maxtmap < 65534 ? 2 : 4)); - bi_s = !model->numbone || !model->bone || (flags & M3D_EXP_NOBONE)? 0 : (model->numbone < 254 ? 1 : - (model->numbone < 65534 ? 2 : 4)); - nb_s = maxbone < 2 ? 1 : (maxbone == 2 ? 2 : (maxbone <= 4 ? 4 : 8)); - sk_s = !bi_s || !maxskin || !skin ? 0 : (maxskin < 254 ? 1 : (maxskin < 65534 ? 2 : 4)); - fc_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4); - hi_s = !model->numshape || !model->shape || (flags & M3D_EXP_NOFACE)? 0 : (model->numshape < 254 ? 1 : - (model->numshape < 65534 ? 2 : 4)); - fi_s = !model->numface || !model->face || (flags & M3D_EXP_NOFACE)? 0 : (model->numface < 254 ? 1 : - (model->numface < 65534 ? 2 : 4)); - vd_s = !model->numvoxel || !model->voxel || (flags & M3D_EXP_NOFACE)? 0 : (minvox >= -128 && maxvox <= 127 ? 1 : - (minvox >= -32768 && maxvox <= 32767 ? 2 : 4)); - vp_s = !model->numvoxtype || !model->voxtype || (flags & M3D_EXP_NOFACE)? 0 : (model->numvoxtype < 254 ? 1 : - (model->numvoxtype < 65534 ? 2 : 4)); - h->types = (vc_s == 8 ? (3<<0) : (vc_s == 2 ? (1<<0) : (vc_s == 1 ? (0<<0) : (2<<0)))) | - (vi_s == 2 ? (1<<2) : (vi_s == 1 ? (0<<2) : (2<<2))) | - (si_s == 2 ? (1<<4) : (si_s == 1 ? (0<<4) : (2<<4))) | - (ci_s == 2 ? (1<<6) : (ci_s == 1 ? (0<<6) : (ci_s == 4 ? (2<<6) : (3<<6)))) | - (ti_s == 2 ? (1<<8) : (ti_s == 1 ? (0<<8) : (ti_s == 4 ? (2<<8) : (3<<8)))) | - (bi_s == 2 ? (1<<10): (bi_s == 1 ? (0<<10): (bi_s == 4 ? (2<<10) : (3<<10)))) | - (nb_s == 2 ? (1<<12): (nb_s == 1 ? (0<<12): (2<<12))) | - (sk_s == 2 ? (1<<14): (sk_s == 1 ? (0<<14): (sk_s == 4 ? (2<<14) : (3<<14)))) | - (fc_s == 2 ? (1<<16): (fc_s == 1 ? (0<<16): (2<<16))) | - (hi_s == 2 ? (1<<18): (hi_s == 1 ? (0<<18): (hi_s == 4 ? (2<<18) : (3<<18)))) | - (fi_s == 2 ? (1<<20): (fi_s == 1 ? (0<<20): (fi_s == 4 ? (2<<20) : (3<<20)))) | - (vd_s == 2 ? (1<<22): (vd_s == 1 ? (0<<22): (vd_s == 4 ? (2<<22) : (3<<22)))) | - (vp_s == 2 ? (1<<24): (vp_s == 1 ? (0<<24): (vp_s == 4 ? (2<<24) : (3<<24)))); - len = h->length; - /* color map */ - if(numcmap && cmap && ci_s < 4 && !(flags & M3D_EXP_NOCMAP)) { - chunklen = 8 + numcmap * sizeof(uint32_t); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "CMAP", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; - memcpy((uint8_t*)h + len + 8, cmap, chunklen - 8); - len += chunklen; - } else numcmap = 0; - /* texture map */ - if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { - chunklen = 8 + maxtmap * vc_s * 2; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "TMAP", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - last = M3D_UNDEF; - for(i = 0; i < numtmap; i++) { - if(tmap[i].newidx == last) continue; - last = tmap[i].newidx; - switch(vc_s) { - case 1: *out++ = (uint8_t)(tmap[i].data.u * 255); *out++ = (uint8_t)(tmap[i].data.v * 255); break; - case 2: - *((uint16_t*)out) = (uint16_t)(tmap[i].data.u * 65535); out += 2; - *((uint16_t*)out) = (uint16_t)(tmap[i].data.v * 65535); out += 2; - break; - case 4: *((float*)out) = tmap[i].data.u; out += 4; *((float*)out) = tmap[i].data.v; out += 4; break; - case 8: *((double*)out) = tmap[i].data.u; out += 8; *((double*)out) = tmap[i].data.v; out += 8; break; - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - out = NULL; - len += *length; - } - /* vertex */ - if(numvrtx && vrtx) { - chunklen = 8 + maxvrtx * (ci_s + sk_s + 4 * vc_s); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "VRTS", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - last = M3D_UNDEF; - for(i = 0; i < numvrtx; i++) { - if(vrtx[i].newidx == last) continue; - last = vrtx[i].newidx; - switch(vc_s) { - case 1: - *out++ = (int8_t)(vrtx[i].data.x * 127); - *out++ = (int8_t)(vrtx[i].data.y * 127); - *out++ = (int8_t)(vrtx[i].data.z * 127); - *out++ = (int8_t)(vrtx[i].data.w * 127); - break; - case 2: - *((int16_t*)out) = (int16_t)(vrtx[i].data.x * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].data.y * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].data.z * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].data.w * 32767); out += 2; - break; - case 4: - *((float*)out) = vrtx[i].data.x; out += 4; - *((float*)out) = vrtx[i].data.y; out += 4; - *((float*)out) = vrtx[i].data.z; out += 4; - *((float*)out) = vrtx[i].data.w; out += 4; - break; - case 8: - *((double*)out) = vrtx[i].data.x; out += 8; - *((double*)out) = vrtx[i].data.y; out += 8; - *((double*)out) = vrtx[i].data.z; out += 8; - *((double*)out) = vrtx[i].data.w; out += 8; - break; - } - idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].data.color); - switch(ci_s) { - case 1: *out++ = (uint8_t)(idx); break; - case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = vrtx[i].data.color; out += 4; break; - } - out = _m3d_addidx(out, sk_s, vrtx[i].data.skinid); - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - out = NULL; - len += *length; - } - /* bones chunk */ - if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { - i = 8 + bi_s + sk_s + model->numbone * (bi_s + si_s + 2*vi_s); - chunklen = i + numskin * nb_s * (bi_s + 1); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "BONE", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, bi_s, model->numbone); - out = _m3d_addidx(out, sk_s, maxskin); - for(i = 0; i < model->numbone; i++) { - out = _m3d_addidx(out, bi_s, model->bone[i].parent); - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->bone[i].name)); - out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].pos]); - out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].ori]); - } - if(numskin && skin && sk_s) { - last = M3D_UNDEF; - for(i = 0; i < numskin; i++) { - if(skin[i].newidx == last) continue; - last = skin[i].newidx; - memset(&weights, 0, nb_s); - for(j = k = l = 0, mw = 0.0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && - skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++) { - if(mw < skin[i].data.weight[j]) { mw = skin[i].data.weight[j]; k = j; } - weights[j] = (uint8_t)(skin[i].data.weight[j] * 255); - if(!weights[j]) { weights[j]++; l--; } - } - weights[k] += l; - switch(nb_s) { - case 1: weights[0] = 255; break; - case 2: memcpy(out, weights, 2); out += 2; break; - case 4: memcpy(out, weights, 4); out += 4; break; - case 8: memcpy(out, weights, 8); out += 8; break; - } - for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && weights[j]; j++) { - out = _m3d_addidx(out, bi_s, skin[i].data.boneid[j]); - *length += bi_s; - } - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - out = NULL; - len += *length; - } - /* materials */ - if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { - for(j = 0; j < model->nummaterial; j++) { - if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; - m = &model->material[j]; - chunklen = 12 + si_s + m->numprop * 5; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "MTRL", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, m->name)); - for(i = 0; i < m->numprop; i++) { - if(m->prop[i].type >= 128) { - if(m->prop[i].value.textureid >= model->numtexture || - !model->texture[m->prop[i].value.textureid].name) continue; - k = m3dpf_map; - } else { - for(k = 256, l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) - if(m->prop[i].type == m3d_propertytypes[l].id) { k = m3d_propertytypes[l].format; break; } - } - if(k == 256) continue; - *out++ = m->prop[i].type; - switch(k) { - case m3dpf_color: - if(!(flags & M3D_EXP_NOCMAP)) { - idx = _m3d_cmapidx(cmap, numcmap, m->prop[i].value.color); - switch(ci_s) { - case 1: *out++ = (uint8_t)(idx); break; - case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = (uint32_t)(m->prop[i].value.color); out += 4; break; - } - } else out--; - break; - case m3dpf_uint8: *out++ = m->prop[i].value.num; break; - case m3dpf_uint16: *((uint16_t*)out) = m->prop[i].value.num; out += 2; break; - case m3dpf_uint32: *((uint32_t*)out) = m->prop[i].value.num; out += 4; break; - case m3dpf_float: *((float*)out) = m->prop[i].value.fnum; out += 4; break; - - case m3dpf_map: - idx = _m3d_stridx(str, numstr, model->texture[m->prop[i].value.textureid].name); - out = _m3d_addidx(out, si_s, idx); - break; - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - out = NULL; - } - } - /* procedural face */ - if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { - /* all inlined assets which are not textures should be procedural surfaces */ - for(j = 0; j < model->numinlined; j++) { - if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length < 4 || - !model->inlined[j].data || (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && - model->inlined[j].data[3] == 'G')) - continue; - for(i = k = 0; i < model->numtexture; i++) { - if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } - } - if(k) continue; - numproc++; - chunklen = 8 + si_s; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "PROC", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name)); - out = NULL; - len += chunklen; - } - } - /* mesh face */ - if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { - chunklen = 8 + si_s + model->numface * (9 * vi_s + 3 * ti_s + si_s + 1); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "MESH", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - last = M3D_UNDEF; -#ifdef M3D_VERTEXMAX - lastp = M3D_UNDEF; -#endif - for(i = 0; i < model->numface; i++) { - if(!(flags & M3D_EXP_NOMATERIAL) && face[i].data.materialid != last) { - last = face[i].data.materialid; - idx = last < model->nummaterial ? _m3d_stridx(str, numstr, model->material[last].name) : 0; - *out++ = 0; - out = _m3d_addidx(out, si_s, idx); - } -#ifdef M3D_VERTEXMAX - if(!(flags & M3D_EXP_NOVRTMAX) && face[i].data.paramid != lastp) { - lastp = face[i].data.paramid; - idx = lastp < model->numparam ? _m3d_stridx(str, numstr, model->param[lastp].name) : 0; - *out++ = 0; - out = _m3d_addidx(out, si_s, idx); - } -#endif - /* hardcoded triangles. */ - k = (3 << 4) | - (((flags & M3D_EXP_NOTXTCRD) || !ti_s || face[i].data.texcoord[0] == M3D_UNDEF || - face[i].data.texcoord[1] == M3D_UNDEF || face[i].data.texcoord[2] == M3D_UNDEF) ? 0 : 1) | - (((flags & M3D_EXP_NONORMAL) || face[i].data.normal[0] == M3D_UNDEF || - face[i].data.normal[1] == M3D_UNDEF || face[i].data.normal[2] == M3D_UNDEF) ? 0 : 2) -#ifdef M3D_VERTEXMAX - | (((flags & M3D_EXP_NOVRTMAX) || face[i].data.vertmax[0] == M3D_UNDEF || - face[i].data.vertmax[1] == M3D_UNDEF || face[i].data.vertmax[2] == M3D_UNDEF) ? 0 : 4) -#endif - ; - *out++ = k; - for(j = 0; j < 3; j++) { - out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]); - if(k & 1) - out = _m3d_addidx(out, ti_s, tmapidx[face[i].data.texcoord[j]]); - if(k & 2) - out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.normal[j]]); -#ifdef M3D_VERTEXMAX - if(k & 4) - out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertmax[j]]); -#endif - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - out = NULL; - } - /* voxel face */ - if(model->numvoxtype && model->voxtype && !(flags & M3D_EXP_NOFACE)) { - chunklen = 8 + si_s + model->numvoxtype * (ci_s + si_s + 3 + sk_s); - for(i = 0; i < model->numvoxtype; i++) - chunklen += model->voxtype[i].numitem * (2 + si_s); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "VOXT", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - for(i = 0; i < model->numvoxtype; i++) { - if(!(flags & M3D_EXP_NOCMAP)) { - idx = _m3d_cmapidx(cmap, numcmap, model->voxtype[i].color); - switch(ci_s) { - case 1: *out++ = (uint8_t)(idx); break; - case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = (uint32_t)(model->voxtype[i].color); out += 4; break; - } - } - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->voxtype[i].name)); - *out++ = (model->voxtype[i].rotation & 0xBF) | (((model->voxtype[i].voxshape >> 8) & 1) << 6); - *out++ = model->voxtype[i].voxshape; - *out++ = model->voxtype[i].numitem; - if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin) - out = _m3d_addidx(out, sk_s, skinidx[model->voxtype[i].skinid]); - for(j = 0; j < model->voxtype[i].numitem; j++) { - out = _m3d_addidx(out, 2, model->voxtype[i].item[j].count); - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->voxtype[i].item[j].name)); - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - out = NULL; - } - if(model->numvoxel && model->voxel && !(flags & M3D_EXP_NOFACE)) { - for(j = 0; j < model->numvoxel; j++) { - chunklen = 8 + si_s + 6 * vd_s + 2 + model->voxel[j].w * model->voxel[j].h * model->voxel[j].d * 3; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "VOXD", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->voxel[j].name)); - out = _m3d_addidx(out, vd_s, model->voxel[j].x); - out = _m3d_addidx(out, vd_s, model->voxel[j].y); - out = _m3d_addidx(out, vd_s, model->voxel[j].z); - out = _m3d_addidx(out, vd_s, model->voxel[j].w); - out = _m3d_addidx(out, vd_s, model->voxel[j].h); - out = _m3d_addidx(out, vd_s, model->voxel[j].d); - *out++ = model->voxel[j].uncertain; - *out++ = model->voxel[j].groupid; - /* RLE compress voxel data */ - n = model->voxel[j].w * model->voxel[j].h * model->voxel[j].d; - k = o = 0; out[o++] = 0; - for(i = 0; i < n; i++) { - for(l = 1; l < 128 && i + l < n && model->voxel[j].data[i] == model->voxel[j].data[i + l]; l++); - if(l > 1) { - l--; - if(out[k]) { out[k]--; out[o++] = 0x80 | l; } - else out[k] = 0x80 | l; - switch(vp_s) { - case 1: out[o++] = model->voxel[j].data[i]; break; - default: *((uint16_t*)(out + o)) = model->voxel[j].data[i]; o += 2; break; - } - k = o; out[o++] = 0; - i += l; - continue; - } - out[k]++; - switch(vp_s) { - case 1: out[o++] = model->voxel[j].data[i]; break; - default: *((uint16_t*)(out + o)) = model->voxel[j].data[i]; o += 2; break; - } - if(out[k] > 127) { out[k]--; k = o; out[o++] = 0; } - } - if(!(out[k] & 0x80)) { if(out[k]) out[k]--; else o--; } - *length = (uint32_t)((uintptr_t)out + (uintptr_t)o - (uintptr_t)((uint8_t*)h + len)); - len += *length; - out = NULL; - } - } - /* mathematical shapes face */ - if(model->numshape && model->shape && !(flags & M3D_EXP_NOFACE)) { - for(j = 0; j < model->numshape; j++) { - chunklen = 12 + si_s + model->shape[j].numcmd * (M3D_CMDMAXARG + 1) * 4; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "SHPE", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->shape[j].name)); - out = _m3d_addidx(out, bi_s, model->shape[j].group); - for(i = 0; i < model->shape[j].numcmd; i++) { - cmd = &model->shape[j].cmd[i]; - if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) - continue; - cd = &m3d_commandtypes[cmd->type]; - *out++ = (cmd->type & 0x7F) | (cmd->type > 127 ? 0x80 : 0); - if(cmd->type > 127) *out++ = (cmd->type >> 7) & 0xff; - for(k = n = 0, l = cd->p; k < l; k++) { - switch(cd->a[((k - n) % (cd->p - n)) + n]) { - case m3dcp_mi_t: - out = _m3d_addidx(out, si_s, cmd->arg[k] < model->nummaterial ? - _m3d_stridx(str, numstr, model->material[cmd->arg[k]].name) : 0); - break; - case m3dcp_vc_t: - min_x = *((float*)&cmd->arg[k]); - switch(vc_s) { - case 1: *out++ = (int8_t)(min_x * 127); break; - case 2: *((int16_t*)out) = (int16_t)(min_x * 32767); out += 2; break; - case 4: *((float*)out) = min_x; out += 4; break; - case 8: *((double*)out) = min_x; out += 8; break; - } - break; - case m3dcp_hi_t: out = _m3d_addidx(out, hi_s, cmd->arg[k]); break; - case m3dcp_fi_t: out = _m3d_addidx(out, fi_s, cmd->arg[k]); break; - case m3dcp_ti_t: out = _m3d_addidx(out, ti_s, cmd->arg[k]); break; - case m3dcp_qi_t: - case m3dcp_vi_t: out = _m3d_addidx(out, vi_s, cmd->arg[k]); break; - case m3dcp_i1_t: out = _m3d_addidx(out, 1, cmd->arg[k]); break; - case m3dcp_i2_t: out = _m3d_addidx(out, 2, cmd->arg[k]); break; - case m3dcp_i4_t: out = _m3d_addidx(out, 4, cmd->arg[k]); break; - case m3dcp_va_t: out = _m3d_addidx(out, 4, cmd->arg[k]); - n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); - break; - } - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - out = NULL; - } - } - /* annotation labels */ - if(model->numlabel && model->label) { - for(i = 0, length = NULL; i < model->numlabel; i++) { - if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { - sl = model->label[i].lang; - sn = model->label[i].name; - if(length) { - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - } - chunklen = 8 + 2 * si_s + ci_s + model->numlabel * (vi_s + si_s); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) { sn = NULL; sl = NULL; goto memerr; } - memcpy((uint8_t*)h + len, "LBLS", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].name)); - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].lang)); - idx = _m3d_cmapidx(cmap, numcmap, model->label[i].color); - switch(ci_s) { - case 1: *out++ = (uint8_t)(idx); break; - case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = model->label[i].color; out += 4; break; - } - } - out = _m3d_addidx(out, vi_s, vrtxidx[model->label[i].vertexid]); - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].text)); - } - if(length) { - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - } - out = NULL; - sn = sl = NULL; - } - /* actions */ - if(model->numaction && model->action && model->numbone && model->bone && !(flags & M3D_EXP_NOACTION)) { - for(j = 0; j < model->numaction; j++) { - a = &model->action[j]; - chunklen = 14 + si_s + a->numframe * (4 + fc_s + maxt * (bi_s + 2 * vi_s)); - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "ACTN", 4); - length = (uint32_t*)((uint8_t*)h + len + 4); - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, a->name)); - *((uint16_t*)out) = (uint16_t)(a->numframe); out += 2; - *((uint32_t*)out) = (uint32_t)(a->durationmsec); out += 4; - for(i = 0; i < a->numframe; i++) { - *((uint32_t*)out) = (uint32_t)(a->frame[i].msec); out += 4; - out = _m3d_addidx(out, fc_s, a->frame[i].numtransform); - for(k = 0; k < a->frame[i].numtransform; k++) { - out = _m3d_addidx(out, bi_s, a->frame[i].transform[k].boneid); - out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].pos]); - out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].ori]); - } - } - *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); - len += *length; - out = NULL; - } - } - /* inlined assets */ - if(model->numinlined && model->inlined && (numproc || (flags & M3D_EXP_INLINE))) { - for(j = 0; j < model->numinlined; j++) { - if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length<4 || !model->inlined[j].data) - continue; - if(!(flags & M3D_EXP_INLINE)) { - if(model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G') - continue; - for(i = k = 0; i < model->numtexture; i++) { - if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } - } - if(k) continue; - } - chunklen = 8 + si_s + model->inlined[j].length; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "ASET", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; - out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name)); - memcpy(out, model->inlined[j].data, model->inlined[j].length); - out = NULL; - len += chunklen; - } - } - /* extra chunks */ - if(model->numextra && model->extra && (flags & M3D_EXP_EXTRA)) { - for(j = 0; j < model->numextra; j++) { - if(!model->extra[j] || model->extra[j]->length < 8) - continue; - chunklen = model->extra[j]->length; - h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, model->extra[j], chunklen); - len += chunklen; - } - } - /* add end chunk */ - h = (m3dhdr_t*)M3D_REALLOC(h, len + 4); - if(!h) goto memerr; - memcpy((uint8_t*)h + len, "OMD3", 4); - len += 4; - /* zlib compress */ - if(!(flags & M3D_EXP_NOZLIB)) { - M3D_LOG("Deflating chunks"); - z = stbi_zlib_compress((unsigned char *)h, len, (int*)&l, 9); - if(z && l > 0 && l < len) { len = l; M3D_FREE(h); h = (m3dhdr_t*)z; } - } - /* add file header at the begining */ - len += 8; - out = (unsigned char*)M3D_MALLOC(len); - if(!out) goto memerr; - memcpy(out, "3DMO", 4); - *((uint32_t*)(out + 4)) = len; - /* preview image chunk, must be the first if exists */ - if(model->preview.data && model->preview.length) { - chunklen = 8 + model->preview.length; - out = (unsigned char*)M3D_REALLOC(out, len + chunklen); - if(!out) goto memerr; - memcpy((uint8_t*)out + 8, "PRVW", 4); - *((uint32_t*)((uint8_t*)out + 8 + 4)) = chunklen; - memcpy((uint8_t*)out + 8 + 8, model->preview.data, model->preview.length); - *((uint32_t*)(out + 4)) += chunklen; - } else - chunklen = 0; - memcpy(out + 8 + chunklen, h, len - 8); - } - if(size) *size = out ? len : 0; - if(vrtxidx) M3D_FREE(vrtxidx); - if(mtrlidx) M3D_FREE(mtrlidx); - if(tmapidx) M3D_FREE(tmapidx); - if(skinidx) M3D_FREE(skinidx); - if(norm) M3D_FREE(norm); - if(face) M3D_FREE(face); - if(cmap) M3D_FREE(cmap); - if(tmap) M3D_FREE(tmap); - if(skin) M3D_FREE(skin); - if(str) M3D_FREE(str); - if(vrtx) M3D_FREE(vrtx); - if(opa) free(opa); - if(h) M3D_FREE(h); - return out; -} -#endif - -#endif - -#ifdef __cplusplus -} -#ifdef M3D_CPPWRAPPER -#include -#include -#include - -/*** C++ wrapper class ***/ -namespace M3D { -#ifdef M3D_IMPLEMENTATION - - class Model { - public: - m3d_t *model; - - public: - Model() { - this->model = (m3d_t*)malloc(sizeof(m3d_t)); memset(this->model, 0, sizeof(m3d_t)); - } - Model(_unused const std::string &data, _unused m3dread_t ReadFileCB, - _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { -#ifndef M3D_NOIMPORTER - this->model = m3d_load((unsigned char *)data.data(), ReadFileCB, FreeCB, mtllib.model); -#else - Model(); -#endif - } - Model(_unused const std::vector data, _unused m3dread_t ReadFileCB, - _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { -#ifndef M3D_NOIMPORTER - this->model = m3d_load((unsigned char *)&data[0], ReadFileCB, FreeCB, mtllib.model); -#else - Model(); -#endif - } - Model(_unused const unsigned char *data, _unused m3dread_t ReadFileCB, - _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { -#ifndef M3D_NOIMPORTER - this->model = m3d_load((unsigned char*)data, ReadFileCB, FreeCB, mtllib.model); -#else - Model(); -#endif - } - ~Model() { m3d_free(this->model); } - - public: - m3d_t *getCStruct() { return this->model; } - std::string getName() { return std::string(this->model->name); } - void setName(std::string name) { this->model->name = (char*)name.c_str(); } - std::string getLicense() { return std::string(this->model->license); } - void setLicense(std::string license) { this->model->license = (char*)license.c_str(); } - std::string getAuthor() { return std::string(this->model->author); } - void setAuthor(std::string author) { this->model->author = (char*)author.c_str(); } - std::string getDescription() { return std::string(this->model->desc); } - void setDescription(std::string desc) { this->model->desc = (char*)desc.c_str(); } - float getScale() { return this->model->scale; } - void setScale(float scale) { this->model->scale = scale; } - std::vector getPreview() { return this->model->preview.data ? - std::vector(this->model->preview.data, this->model->preview.data + this->model->preview.length) : - std::vector(); } - std::vector getColorMap() { return this->model->cmap ? std::vector(this->model->cmap, - this->model->cmap + this->model->numcmap) : std::vector(); } - std::vector getTextureMap() { return this->model->tmap ? std::vector(this->model->tmap, - this->model->tmap + this->model->numtmap) : std::vector(); } - std::vector getTextures() { return this->model->texture ? std::vector(this->model->texture, - this->model->texture + this->model->numtexture) : std::vector(); } - std::string getTextureName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numtexture ? - std::string(this->model->texture[idx].name) : nullptr; } - std::vector getBones() { return this->model->bone ? std::vector(this->model->bone, this->model->bone + - this->model->numbone) : std::vector(); } - std::string getBoneName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numbone ? - std::string(this->model->bone[idx].name) : nullptr; } - std::vector getMaterials() { return this->model->material ? std::vector(this->model->material, - this->model->material + this->model->nummaterial) : std::vector(); } - std::string getMaterialName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->nummaterial ? - std::string(this->model->material[idx].name) : nullptr; } - int getMaterialPropertyInt(int idx, int type) { - if (idx < 0 || (unsigned int)idx >= this->model->nummaterial || type < 0 || type >= 127 || - !this->model->material[idx].prop) return -1; - for (int i = 0; i < this->model->material[idx].numprop; i++) { - if (this->model->material[idx].prop[i].type == type) - return this->model->material[idx].prop[i].value.num; - } - return -1; - } - uint32_t getMaterialPropertyColor(int idx, int type) { return this->getMaterialPropertyInt(idx, type); } - float getMaterialPropertyFloat(int idx, int type) { - if (idx < 0 || (unsigned int)idx >= this->model->nummaterial || type < 0 || type >= 127 || - !this->model->material[idx].prop) return -1.0f; - for (int i = 0; i < this->model->material[idx].numprop; i++) { - if (this->model->material[idx].prop[i].type == type) - return this->model->material[idx].prop[i].value.fnum; - } - return -1.0f; - } - m3dtx_t* getMaterialPropertyMap(int idx, int type) { - if (idx < 0 || (unsigned int)idx >= this->model->nummaterial || type < 128 || type > 255 || - !this->model->material[idx].prop) return nullptr; - for (int i = 0; i < this->model->material[idx].numprop; i++) { - if (this->model->material[idx].prop[i].type == type) - return this->model->material[idx].prop[i].value.textureid < this->model->numtexture ? - &this->model->texture[this->model->material[idx].prop[i].value.textureid] : nullptr; - } - return nullptr; - } - std::vector getVertices() { return this->model->vertex ? std::vector(this->model->vertex, - this->model->vertex + this->model->numvertex) : std::vector(); } - std::vector getFace() { return this->model->face ? std::vector(this->model->face, this->model->face + - this->model->numface) : std::vector(); } - std::vector getVoxelTypes() { return this->model->voxtype ? std::vector(this->model->voxtype, - this->model->voxtype + this->model->numvoxtype) : std::vector(); } - std::string getVoxelTypeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxtype && - this->model->voxtype[idx].name && this->model->voxtype[idx].name[0] ? - std::string(this->model->voxtype[idx].name) : nullptr; } - std::vector getVoxelTypeItems(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxtype && - this->model->voxtype[idx].item ? std::vector(this->model->voxtype[idx].item, - this->model->voxtype[idx].item + this->model->voxtype[idx].numitem) : std::vector(); } - std::vector getVoxelBlocks() { return this->model->voxel ? std::vector(this->model->voxel, - this->model->voxel + this->model->numvoxel) : std::vector(); } - std::string getVoxelBlockName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxel && - this->model->voxel[idx].name && this->model->voxel[idx].name[0] ? - std::string(this->model->voxel[idx].name) : nullptr; } - std::vector getVoxelBlockData(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxel && - this->model->voxel[idx].data ? std::vector(this->model->voxel[idx].data, - this->model->voxel[idx].data + this->model->voxel[idx].w*this->model->voxel[idx].h*this->model->voxel[idx].d) : - std::vector(); } - std::vector getShape() { return this->model->shape ? std::vector(this->model->shape, - this->model->shape + this->model->numshape) : std::vector(); } - std::string getShapeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && - this->model->shape[idx].name && this->model->shape[idx].name[0] ? - std::string(this->model->shape[idx].name) : nullptr; } - unsigned int getShapeGroup(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape ? - this->model->shape[idx].group : 0xFFFFFFFF; } - std::vector getShapeCommands(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && - this->model->shape[idx].cmd ? std::vector(this->model->shape[idx].cmd, this->model->shape[idx].cmd + - this->model->shape[idx].numcmd) : std::vector(); } - std::vector getAnnotationLabels() { return this->model->label ? std::vector(this->model->label, - this->model->label + this->model->numlabel) : std::vector(); } - std::vector getSkin() { return this->model->skin ? std::vector(this->model->skin, this->model->skin + - this->model->numskin) : std::vector(); } - std::vector getActions() { return this->model->action ? std::vector(this->model->action, - this->model->action + this->model->numaction) : std::vector(); } - std::string getActionName(int aidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? - std::string(this->model->action[aidx].name) : nullptr; } - unsigned int getActionDuration(int aidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? - this->model->action[aidx].durationmsec : 0; } - std::vector getActionFrames(int aidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? - std::vector(this->model->action[aidx].frame, this->model->action[aidx].frame + - this->model->action[aidx].numframe) : std::vector(); } - unsigned int getActionFrameTimestamp(int aidx, int fidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction? - (fidx >= 0 && (unsigned int)fidx < this->model->action[aidx].numframe ? - this->model->action[aidx].frame[fidx].msec : 0) : 0; } - std::vector getActionFrameTransforms(int aidx, int fidx) { - return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? ( - fidx >= 0 && (unsigned int)fidx < this->model->action[aidx].numframe ? - std::vector(this->model->action[aidx].frame[fidx].transform, - this->model->action[aidx].frame[fidx].transform + this->model->action[aidx].frame[fidx].numtransform) : - std::vector()) : std::vector(); } - std::vector getActionFrame(int aidx, int fidx, std::vector skeleton) { - m3dtr_t *pose = m3d_frame(this->model, (unsigned int)aidx, (unsigned int)fidx, - skeleton.size() ? &skeleton[0] : nullptr); - return std::vector(pose, pose + this->model->numbone); } - std::vector getActionPose(int aidx, unsigned int msec) { - m3db_t *pose = m3d_pose(this->model, (unsigned int)aidx, (unsigned int)msec); - return std::vector(pose, pose + this->model->numbone); } - std::vector getInlinedAssets() { return this->model->inlined ? std::vector(this->model->inlined, - this->model->inlined + this->model->numinlined) : std::vector(); } - std::vector> getExtras() { return this->model->extra ? - std::vector>(this->model->extra, - this->model->extra + this->model->numextra) : std::vector>(); } - std::vector Save(_unused int quality, _unused int flags) { -#ifdef M3D_EXPORTER - unsigned int size; - unsigned char *ptr = m3d_save(this->model, quality, flags, &size); - return ptr && size ? std::vector(ptr, ptr + size) : std::vector(); -#else - return std::vector(); -#endif - } - }; - -#else - class Model { - private: - m3d_t *model; - - public: - Model(const std::string &data, m3dread_t ReadFileCB, m3dfree_t FreeCB); - Model(const std::vector data, m3dread_t ReadFileCB, m3dfree_t FreeCB); - Model(const unsigned char *data, m3dread_t ReadFileCB, m3dfree_t FreeCB); - Model(); - ~Model(); - - public: - m3d_t *getCStruct(); - std::string getName(); - void setName(std::string name); - std::string getLicense(); - void setLicense(std::string license); - std::string getAuthor(); - void setAuthor(std::string author); - std::string getDescription(); - void setDescription(std::string desc); - float getScale(); - void setScale(float scale); - std::vector getPreview(); - std::vector getColorMap(); - std::vector getTextureMap(); - std::vector getTextures(); - std::string getTextureName(int idx); - std::vector getBones(); - std::string getBoneName(int idx); - std::vector getMaterials(); - std::string getMaterialName(int idx); - int getMaterialPropertyInt(int idx, int type); - uint32_t getMaterialPropertyColor(int idx, int type); - float getMaterialPropertyFloat(int idx, int type); - m3dtx_t* getMaterialPropertyMap(int idx, int type); - std::vector getVertices(); - std::vector getFace(); - std::vector getVoxelTypes(); - std::string getVoxelTypeName(int idx); - std::vector getVoxelTypeItems(int idx); - std::vector getVoxelBlocks(); - std::string getVoxelBlockName(int idx); - std::vector getVoxelBlockData(int idx); - std::vector getShape(); - std::string getShapeName(int idx); - unsigned int getShapeGroup(int idx); - std::vector getShapeCommands(int idx); - std::vector getAnnotationLabels(); - std::vector getSkin(); - std::vector getActions(); - std::string getActionName(int aidx); - unsigned int getActionDuration(int aidx); - std::vector getActionFrames(int aidx); - unsigned int getActionFrameTimestamp(int aidx, int fidx); - std::vector getActionFrameTransforms(int aidx, int fidx); - std::vector getActionFrame(int aidx, int fidx, std::vector skeleton); - std::vector getActionPose(int aidx, unsigned int msec); - std::vector getInlinedAssets(); - std::vector> getExtras(); - std::vector Save(int quality, int flags); - }; - -#endif /* impl */ -} -#endif - -#endif /* __cplusplus */ - -#endif diff --git a/raylib/external/miniaudio.h b/raylib/external/miniaudio.h index c74bebe..60522da 100644 --- a/raylib/external/miniaudio.h +++ b/raylib/external/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.22 - 2025-02-24 +miniaudio - v0.10.33 - 2021-04-04 David Reid - mackron@gmail.com @@ -12,57 +12,25 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -To use miniaudio, include "miniaudio.h": +miniaudio is a single file library for audio playback and capture. To use it, do the following in one .c file: ```c + #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" ``` -The implementation is contained in "miniaudio.c". Just compile this like any other source file. You -can include miniaudio.c if you want to compile your project as a single translation unit: +You can do `#include "miniaudio.h"` in other parts of the program just like any other header. - ```c - #include "miniaudio.c" - ``` +miniaudio uses the concept of a "device" as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from, +and then move data to/from the device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a callback which you specify when +initializing the device. -miniaudio includes both low level and high level APIs. The low level API is good for those who want -to do all of their mixing themselves and only require a light weight interface to the underlying -audio device. The high level API is good for those who have complex mixing and effect requirements. +When initializing the device you first need to configure it. The device configuration allows you to specify things like the format of the data delivered via +the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from. -In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles -to opaque objects which means you need to allocate memory for objects yourself. In the examples -presented in this documentation you will often see objects declared on the stack. You need to be -careful when translating these examples to your own code so that you don't accidentally declare -your objects on the stack and then cause them to become invalid once the function returns. In -addition, you must ensure the memory address of your objects remain the same throughout their -lifetime. You therefore cannot be making copies of your objects. - -A config/init pattern is used throughout the entire library. The idea is that you set up a config -object and pass that into the initialization routine. The advantage to this system is that the -config object can be initialized with logical defaults and new properties added to it without -breaking the API. The config object can be allocated on the stack and does not need to be -maintained after initialization of the corresponding object. - - -1.1. Low Level API ------------------- -The low level API gives you access to the raw audio data of an audio device. It supports playback, -capture, full-duplex and loopback (WASAPI only). You can enumerate over devices to determine which -physical device(s) you want to connect to. - -The low level API uses the concept of a "device" as the abstraction for physical devices. The idea -is that you choose a physical device to emit or capture audio from, and then move data to/from the -device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a -callback which you specify when initializing the device. - -When initializing the device you first need to configure it. The device configuration allows you to -specify things like the format of the data delivered via the callback, the size of the internal -buffer and the ID of the device you want to emit or capture audio from. - -Once you have the device configuration set up you can initialize the device. When initializing a -device you need to allocate memory for the device object beforehand. This gives the application -complete control over how the memory is allocated. In the example below we initialize a playback -device on the stack, but you could allocate it on the heap if that suits your situation better. +Once you have the device configuration set up you can initialize the device. When initializing a device you need to allocate memory for the device object +beforehand. This gives the application complete control over how the memory is allocated. In the example below we initialize a playback device on the stack, +but you could allocate it on the heap if that suits your situation better. ```c void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) @@ -90,32 +58,25 @@ device on the stack, but you could allocate it on the heap if that suits your si // Do something here. Probably your program's main loop. - ma_device_uninit(&device); + ma_device_uninit(&device); // This will stop the device so no need to do that manually. return 0; } ``` -In the example above, `data_callback()` is where audio data is written and read from the device. -The idea is in playback mode you cause sound to be emitted from the speakers by writing audio data -to the output buffer (`pOutput` in the example). In capture mode you read data from the input -buffer (`pInput`) to extract sound captured by the microphone. The `frameCount` parameter tells you -how many frames can be written to the output buffer and read from the input buffer. A "frame" is -one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 -samples: one for the left, one for the right. The channel count is defined by the device config. -The size in bytes of an individual sample is defined by the sample format which is also specified -in the device config. Multi-channel audio data is always interleaved, which means the samples for -each frame are stored next to each other in memory. For example, in a stereo stream the first pair -of samples will be the left and right samples for the first frame, the second pair of samples will -be the left and right samples for the second frame, etc. +In the example above, `data_callback()` is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted +from the speakers by writing audio data to the output buffer (`pOutput` in the example). In capture mode you read data from the input buffer (`pInput`) to +extract sound captured by the microphone. The `frameCount` parameter tells you how many frames can be written to the output buffer and read from the input +buffer. A "frame" is one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 samples: one for the left, one for the right. +The channel count is defined by the device config. The size in bytes of an individual sample is defined by the sample format which is also specified in the +device config. Multi-channel audio data is always interleaved, which means the samples for each frame are stored next to each other in memory. For example, in +a stereo stream the first pair of samples will be the left and right samples for the first frame, the second pair of samples will be the left and right samples +for the second frame, etc. -The configuration of the device is defined by the `ma_device_config` structure. The config object -is always initialized with `ma_device_config_init()`. It's important to always initialize the -config with this function as it initializes it with logical defaults and ensures your program -doesn't break when new members are added to the `ma_device_config` structure. The example above -uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` takes -a single parameter, which is whether or not the device is a playback, capture, duplex or loopback -device (loopback devices are not supported on all backends). The `config.playback.format` member -sets the sample format which can be one of the following (all formats are native-endian): +The configuration of the device is defined by the `ma_device_config` structure. The config object is always initialized with `ma_device_config_init()`. It's +important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn't break when new members +are added to the `ma_device_config` structure. The example above uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` +takes a single parameter, which is whether or not the device is a playback, capture, duplex or loopback device (loopback devices are not supported on all +backends). The `config.playback.format` member sets the sample format which can be one of the following (all formats are native-endian): +---------------+----------------------------------------+---------------------------+ | Symbol | Description | Range | @@ -127,30 +88,22 @@ sets the sample format which can be one of the following (all formats are native | ma_format_u8 | 8-bit unsigned integer | [0, 255] | +---------------+----------------------------------------+---------------------------+ -The `config.playback.channels` member sets the number of channels to use with the device. The -channel count cannot exceed MA_MAX_CHANNELS. The `config.sampleRate` member sets the sample rate -(which must be the same for both playback and capture in full-duplex configurations). This is -usually set to 44100 or 48000, but can be set to anything. It's recommended to keep this between -8000 and 384000, however. +The `config.playback.channels` member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The +`config.sampleRate` member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to +44100 or 48000, but can be set to anything. It's recommended to keep this between 8000 and 384000, however. -Note that leaving the format, channel count and/or sample rate at their default values will result -in the internal device's native configuration being used which is useful if you want to avoid the -overhead of miniaudio's automatic data conversion. +Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device's native configuration being used +which is useful if you want to avoid the overhead of miniaudio's automatic data conversion. -In addition to the sample format, channel count and sample rate, the data callback and user data -pointer are also set via the config. The user data pointer is not passed into the callback as a -parameter, but is instead set to the `pUserData` member of `ma_device` which you can access -directly since all miniaudio structures are transparent. +In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is +not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio +structures are transparent. -Initializing the device is done with `ma_device_init()`. This will return a result code telling you -what went wrong, if anything. On success it will return `MA_SUCCESS`. After initialization is -complete the device will be in a stopped state. To start it, use `ma_device_start()`. -Uninitializing the device will stop it, which is what the example above does, but you can also stop -the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again. -Note that it's important to never stop or start the device from inside the callback. This will -result in a deadlock. Instead you set a variable or signal an event indicating that the device -needs to stop and handle it in a different thread. The following APIs must never be called inside -the callback: +Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return +`MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop +it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again. +Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an +event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback: ```c ma_device_init() @@ -160,14 +113,12 @@ the callback: ma_device_stop() ``` -You must never try uninitializing and reinitializing a device inside the callback. You must also -never try to stop and start it from inside the callback. There are a few other things you shouldn't -do in the callback depending on your requirements, however this isn't so much a thread-safety -thing, but rather a real-time processing thing which is beyond the scope of this introduction. +You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There +are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a +real-time processing thing which is beyond the scope of this introduction. -The example above demonstrates the initialization of a playback device, but it works exactly the -same for capture. All you need to do is change the device type from `ma_device_type_playback` to -`ma_device_type_capture` when setting up the config, like so: +The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type +from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so: ```c ma_device_config config = ma_device_config_init(ma_device_type_capture); @@ -175,9 +126,8 @@ same for capture. All you need to do is change the device type from `ma_device_t config.capture.channels = MY_CHANNEL_COUNT; ``` -In the data callback you just read from the input buffer (`pInput` in the example above) and leave -the output buffer alone (it will be set to NULL when the device type is set to -`ma_device_type_capture`). +In the data callback you just read from the input buffer (`pInput` in the example above) and leave the output buffer alone (it will be set to NULL when the +device type is set to `ma_device_type_capture`). These are the available device types and how you should handle the buffers in the callback: @@ -190,29 +140,23 @@ These are the available device types and how you should handle the buffers in th | ma_device_type_loopback | Read from input buffer, leave output buffer untouched. | +-------------------------+--------------------------------------------------------+ -You will notice in the example above that the sample format and channel count is specified -separately for playback and capture. This is to support different data formats between the playback -and capture devices in a full-duplex system. An example may be that you want to capture audio data -as a monaural stream (one channel), but output sound to a stereo speaker system. Note that if you -use different formats between playback and capture in a full-duplex configuration you will need to -convert the data yourself. There are functions available to help you do this which will be -explained later. +You will notice in the example above that the sample format and channel count is specified separately for playback and capture. This is to support different +data formats between the playback and capture devices in a full-duplex system. An example may be that you want to capture audio data as a monaural stream (one +channel), but output sound to a stereo speaker system. Note that if you use different formats between playback and capture in a full-duplex configuration you +will need to convert the data yourself. There are functions available to help you do this which will be explained later. -The example above did not specify a physical device to connect to which means it will use the -operating system's default device. If you have multiple physical devices connected and you want to -use a specific one you will need to specify the device ID in the configuration, like so: +The example above did not specify a physical device to connect to which means it will use the operating system's default device. If you have multiple physical +devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so: ```c config.playback.pDeviceID = pMyPlaybackDeviceID; // Only if requesting a playback or duplex device. config.capture.pDeviceID = pMyCaptureDeviceID; // Only if requesting a capture, duplex or loopback device. ``` -To retrieve the device ID you will need to perform device enumeration, however this requires the -use of a new concept called the "context". Conceptually speaking the context sits above the device. -There is one context to many devices. The purpose of the context is to represent the backend at a -more global level and to perform operations outside the scope of an individual device. Mainly it is -used for performing run-time linking against backend libraries, initializing backends and -enumerating devices. The example below shows how to enumerate devices. +To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept called the "context". Conceptually +speaking the context sits above the device. There is one context to many devices. The purpose of the context is to represent the backend at a more global level +and to perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing +backends and enumerating devices. The example below shows how to enumerate devices. ```c ma_context context; @@ -253,245 +197,55 @@ enumerating devices. The example below shows how to enumerate devices. ma_context_uninit(&context); ``` -The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. -The first parameter is a pointer to a list of `ma_backend` values which are used to override the -default backend priorities. When this is NULL, as in this example, miniaudio's default priorities -are used. The second parameter is the number of backends listed in the array pointed to by the -first parameter. The third parameter is a pointer to a `ma_context_config` object which can be -NULL, in which case defaults are used. The context configuration is used for setting the logging -callback, custom memory allocation callbacks, user-defined data and some backend-specific -configurations. +The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. The first parameter is a pointer to a list of `ma_backend` +values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio's default priorities are used. The second +parameter is the number of backends listed in the array pointed to by the first parameter. The third parameter is a pointer to a `ma_context_config` object +which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks, +user-defined data and some backend-specific configurations. -Once the context has been initialized you can enumerate devices. In the example above we use the -simpler `ma_context_get_devices()`, however you can also use a callback for handling devices by -using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer -to a pointer that will, upon output, be set to a pointer to a buffer containing a list of -`ma_device_info` structures. You also provide a pointer to an unsigned integer that will receive -the number of items in the returned buffer. Do not free the returned buffers as their memory is -managed internally by miniaudio. +Once the context has been initialized you can enumerate devices. In the example above we use the simpler `ma_context_get_devices()`, however you can also use a +callback for handling devices by using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer to a pointer that will, +upon output, be set to a pointer to a buffer containing a list of `ma_device_info` structures. You also provide a pointer to an unsigned integer that will +receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio. -The `ma_device_info` structure contains an `id` member which is the ID you pass to the device -config. It also contains the name of the device which is useful for presenting a list of devices -to the user via the UI. +The `ma_device_info` structure contains an `id` member which is the ID you pass to the device config. It also contains the name of the device which is useful +for presenting a list of devices to the user via the UI. -When creating your own context you will want to pass it to `ma_device_init()` when initializing the -device. Passing in NULL, like we do in the first example, will result in miniaudio creating the -context for you, which you don't want to do since you've already created a context. Note that -internally the context is only tracked by it's pointer which means you must not change the location -of the `ma_context` object. If this is an issue, consider using `malloc()` to allocate memory for -the context. - - -1.2. High Level API -------------------- -The high level API consists of three main parts: - - * Resource management for loading and streaming sounds. - * A node graph for advanced mixing and effect processing. - * A high level "engine" that wraps around the resource manager and node graph. - -The resource manager (`ma_resource_manager`) is used for loading sounds. It supports loading sounds -fully into memory and also streaming. It will also deal with reference counting for you which -avoids the same sound being loaded multiple times. - -The node graph is used for mixing and effect processing. The idea is that you connect a number of -nodes into the graph by connecting each node's outputs to another node's inputs. Each node can -implement its own effect. By chaining nodes together, advanced mixing and effect processing can -be achieved. - -The engine encapsulates both the resource manager and the node graph to create a simple, easy to -use high level API. The resource manager and node graph APIs are covered in more later sections of -this manual. - -The code below shows how you can initialize an engine using it's default configuration. - - ```c - ma_result result; - ma_engine engine; - - result = ma_engine_init(NULL, &engine); - if (result != MA_SUCCESS) { - return result; // Failed to initialize the engine. - } - ``` - -This creates an engine instance which will initialize a device internally which you can access with -`ma_engine_get_device()`. It will also initialize a resource manager for you which can be accessed -with `ma_engine_get_resource_manager()`. The engine itself is a node graph (`ma_node_graph`) which -means you can pass a pointer to the engine object into any of the `ma_node_graph` APIs (with a -cast). Alternatively, you can use `ma_engine_get_node_graph()` instead of a cast. - -Note that all objects in miniaudio, including the `ma_engine` object in the example above, are -transparent structures. There are no handles to opaque structures in miniaudio which means you need -to be mindful of how you declare them. In the example above we are declaring it on the stack, but -this will result in the struct being invalidated once the function encapsulating it returns. If -allocating the engine on the heap is more appropriate, you can easily do so with a standard call -to `malloc()` or whatever heap allocation routine you like: - - ```c - ma_engine* pEngine = malloc(sizeof(*pEngine)); - ``` - -The `ma_engine` API uses the same config/init pattern used all throughout miniaudio. To configure -an engine, you can fill out a `ma_engine_config` object and pass it into the first parameter of -`ma_engine_init()`: - - ```c - ma_result result; - ma_engine engine; - ma_engine_config engineConfig; - - engineConfig = ma_engine_config_init(); - engineConfig.pResourceManager = &myCustomResourceManager; // <-- Initialized as some earlier stage. - - result = ma_engine_init(&engineConfig, &engine); - if (result != MA_SUCCESS) { - return result; - } - ``` - -This creates an engine instance using a custom config. In this particular example it's showing how -you can specify a custom resource manager rather than having the engine initialize one internally. -This is particularly useful if you want to have multiple engine's share the same resource manager. - -The engine must be uninitialized with `ma_engine_uninit()` when it's no longer needed. - -By default the engine will be started, but nothing will be playing because no sounds have been -initialized. The easiest but least flexible way of playing a sound is like so: - - ```c - ma_engine_play_sound(&engine, "my_sound.wav", NULL); - ``` - -This plays what miniaudio calls an "inline" sound. It plays the sound once, and then puts the -internal sound up for recycling. The last parameter is used to specify which sound group the sound -should be associated with which will be explained later. This particular way of playing a sound is -simple, but lacks flexibility and features. A more flexible way of playing a sound is to first -initialize a sound: - - ```c - ma_result result; - ma_sound sound; - - result = ma_sound_init_from_file(&engine, "my_sound.wav", 0, NULL, NULL, &sound); - if (result != MA_SUCCESS) { - return result; - } - - ma_sound_start(&sound); - ``` - -This returns a `ma_sound` object which represents a single instance of the specified sound file. If -you want to play the same file multiple times simultaneously, you need to create one sound for each -instance. - -Sounds should be uninitialized with `ma_sound_uninit()`. - -Sounds are not started by default. Start a sound with `ma_sound_start()` and stop it with -`ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use -`ma_sound_seek_to_pcm_frame(&sound, 0)` to seek back to the start of a sound. By default, starting -and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound -the be started and/or stopped at a specific time. This can be done with the following functions: - - ```c - ma_sound_set_start_time_in_pcm_frames() - ma_sound_set_start_time_in_milliseconds() - ma_sound_set_stop_time_in_pcm_frames() - ma_sound_set_stop_time_in_milliseconds() - ``` - -The start/stop time needs to be specified based on the absolute timer which is controlled by the -engine. The current global time in PCM frames can be retrieved with -`ma_engine_get_time_in_pcm_frames()`. The engine's global time can be changed with -`ma_engine_set_time_in_pcm_frames()` for synchronization purposes if required. Note that scheduling -a start time still requires an explicit call to `ma_sound_start()` before anything will play: - - ```c - ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time_in_pcm_frames(&engine) + (ma_engine_get_sample_rate(&engine) * 2); - ma_sound_start(&sound); - ``` - -The third parameter of `ma_sound_init_from_file()` is a set of flags that control how the sound be -loaded and a few options on which features should be enabled for that sound. By default, the sound -is synchronously loaded fully into memory straight from the file system without any kind of -decoding. If you want to decode the sound before storing it in memory, you need to specify the -`MA_SOUND_FLAG_DECODE` flag. This is useful if you want to incur the cost of decoding at an earlier -stage, such as a loading stage. Without this option, decoding will happen dynamically at mixing -time which might be too expensive on the audio thread. - -If you want to load the sound asynchronously, you can specify the `MA_SOUND_FLAG_ASYNC` flag. This -will result in `ma_sound_init_from_file()` returning quickly, but the sound will not start playing -until the sound has had some audio decoded. - -The fourth parameter is a pointer to sound group. A sound group is used as a mechanism to organise -sounds into groups which have their own effect processing and volume control. An example is a game -which might have separate groups for sfx, voice and music. Each of these groups have their own -independent volume control. Use `ma_sound_group_init()` or `ma_sound_group_init_ex()` to initialize -a sound group. - -Sounds and sound groups are nodes in the engine's node graph and can be plugged into any `ma_node` -API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex -effect chains. - -A sound can have its volume changed with `ma_sound_set_volume()`. If you prefer decibel volume -control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear. - -Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know -a sound will never have its pitch changed with `ma_sound_set_pitch()` or via the doppler effect, -you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization. - -By default, sounds and sound groups have spatialization enabled. If you don't ever want to -spatialize your sounds, initialize the sound with the `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. The -spatialization model is fairly simple and is roughly on feature parity with OpenAL. HRTF and -environmental occlusion are not currently supported, but planned for the future. The supported -features include: - - * Sound and listener positioning and orientation with cones - * Attenuation models: none, inverse, linear and exponential - * Doppler effect - -Sounds can be faded in and out with `ma_sound_set_fade_in_pcm_frames()`. - -To check if a sound is currently playing, you can use `ma_sound_is_playing()`. To check if a sound -is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled with -`ma_sound_set_looping()`. Use `ma_sound_is_looping()` to check whether or not the sound is looping. +When creating your own context you will want to pass it to `ma_device_init()` when initializing the device. Passing in NULL, like we do in the first example, +will result in miniaudio creating the context for you, which you don't want to do since you've already created a context. Note that internally the context is +only tracked by it's pointer which means you must not change the location of the `ma_context` object. If this is an issue, consider using `malloc()` to +allocate memory for the context. 2. Building =========== -miniaudio should work cleanly out of the box without the need to download or install any -dependencies. See below for platform-specific details. - -Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. - -If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, -etc. you need to link with `-latomic`. +miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. 2.1. Windows ------------ -The Windows build should compile cleanly on all popular compilers without the need to configure any -include paths nor link to any libraries. - -The UWP build may require linking to mmdevapi.lib if you get errors about an unresolved external -symbol for `ActivateAudioInterfaceAsync()`. - +The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries. 2.2. macOS and iOS ------------------ -The macOS build should compile cleanly without the need to download any dependencies nor link to -any libraries or frameworks. The iOS build needs to be compiled as Objective-C and will need to -link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling -through the command line requires linking to `-lpthread` and `-lm`. +The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be +compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling through the command line +requires linking to `-lpthread` and `-lm`. -Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's -notarization process. To fix this there are two options. The first is to compile with -`-DMA_NO_RUNTIME_LINKING` which in turn will require linking with -`-framework CoreFoundation -framework CoreAudio -framework AudioToolbox`. If you get errors about -AudioToolbox, try with `-framework AudioUnit` instead. You may get this when using older versions -of iOS. Alternatively, if you would rather keep using runtime linking you can add the following to -your entitlements.xcent file: +Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's notarization process. To fix this there are two options. The +first is to use the `MA_NO_RUNTIME_LINKING` option, like so: + + ```c + #ifdef __APPLE__ + #define MA_NO_RUNTIME_LINKING + #endif + #define MINIAUDIO_IMPLEMENTATION + #include "miniaudio.h" + ``` + +This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. Alternatively, if you would rather keep using runtime +linking you can add the following to your entitlements.xcent file: ``` com.apple.security.cs.allow-dyld-environment-variables @@ -500,56 +254,31 @@ your entitlements.xcent file: ``` -See this discussion for more info: https://github.com/mackron/miniaudio/issues/203. - 2.3. Linux ---------- -The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any -development packages. You may need to link with `-latomic` if you're compiling for 32-bit ARM. - +The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any development packages. 2.4. BSD -------- -The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses -sndio and FreeBSD uses OSS. You may need to link with `-latomic` if you're compiling for 32-bit -ARM. - +The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS. 2.5. Android ------------ -AAudio is the highest priority backend on Android. This should work out of the box without needing -any kind of compiler configuration. Support for AAudio starts with Android 8 which means older -versions will fall back to OpenSL|ES which requires API level 16+. - -There have been reports that the OpenSL|ES backend fails to initialize on some Android based -devices due to `dlopen()` failing to open "libOpenSLES.so". If this happens on your platform -you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES. +AAudio is the highest priority backend on Android. This should work out of the box without needing any kind of compiler configuration. Support for AAudio +starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+. +There have been reports that the OpenSL|ES backend fails to initialize on some Android based devices due to `dlopen()` failing to open "libOpenSLES.so". If +this happens on your platform you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES. 2.6. Emscripten --------------- -The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. -You cannot use `-std=c*` compiler flags, nor `-ansi`. - -You can enable the use of AudioWorkets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling -with the following options: - - -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY - -An example for compiling with AudioWorklet support might look like this: - - emcc program.c -o bin/program.html -DMA_ENABLE_AUDIO_WORKLETS -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY - -To run locally, you'll need to use emrun: - - emrun bin/program.html - +The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use -std=c* compiler flags, nor -ansi. 2.7. Build Options ------------------ -`#define` these options before including miniaudio.c, or pass them as compiler flags: +`#define` these options before including miniaudio.h. +----------------------------------+--------------------------------------------------------------------+ | Option | Description | @@ -580,8 +309,6 @@ To run locally, you'll need to use emrun: +----------------------------------+--------------------------------------------------------------------+ | MA_NO_WEBAUDIO | Disables the Web Audio backend. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_CUSTOM | Disables support for custom backends. | - +----------------------------------+--------------------------------------------------------------------+ | MA_NO_NULL | Disables the null backend. | +----------------------------------+--------------------------------------------------------------------+ | MA_ENABLE_ONLY_SPECIFIC_BACKENDS | Disables all backends by default and requires `MA_ENABLE_*` to | @@ -626,9 +353,6 @@ To run locally, you'll need to use emrun: | MA_ENABLE_WEBAUDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | | | enable the Web Audio backend. | +----------------------------------+--------------------------------------------------------------------+ - | MA_ENABLE_CUSTOM | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | - | | enable custom backends. | - +----------------------------------+--------------------------------------------------------------------+ | MA_ENABLE_NULL | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | | | enable the null backend. | +----------------------------------+--------------------------------------------------------------------+ @@ -642,45 +366,28 @@ To run locally, you'll need to use emrun: +----------------------------------+--------------------------------------------------------------------+ | MA_NO_MP3 | Disables the built-in MP3 decoder. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_DEVICE_IO | Disables playback and recording. This will disable `ma_context` | - | | and `ma_device` APIs. This is useful if you only want to use | - | | miniaudio's data conversion and/or decoding APIs. | + | MA_NO_DEVICE_IO | Disables playback and recording. This will disable ma_context and | + | | ma_device APIs. This is useful if you only want to use miniaudio's | + | | data conversion and/or decoding APIs. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_RESOURCE_MANAGER | Disables the resource manager. When using the engine this will | - | | also disable the following functions: | - | | | - | | ``` | - | | ma_sound_init_from_file() | - | | ma_sound_init_from_file_w() | - | | ma_sound_init_copy() | - | | ma_engine_play_sound_ex() | - | | ma_engine_play_sound() | - | | ``` | - | | | - | | The only way to initialize a `ma_sound` object is to initialize it | - | | from a data source. | - +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_NODE_GRAPH | Disables the node graph API. This will also disable the engine API | - | | because it depends on the node graph. | - +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_ENGINE | Disables the engine API. | - +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_THREADING | Disables the `ma_thread`, `ma_mutex`, `ma_semaphore` and | - | | `ma_event` APIs. This option is useful if you only need to use | - | | miniaudio for data conversion, decoding and/or encoding. Some | - | | families of APIs require threading which means the following | - | | options must also be set: | + | MA_NO_THREADING | Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs. | + | | This option is useful if you only need to use miniaudio for data | + | | conversion, decoding and/or encoding. Some families of APIs | + | | require threading which means the following options must also be | + | | set: | | | | | | ``` | | | MA_NO_DEVICE_IO | | | ``` | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_GENERATION | Disables generation APIs such a `ma_waveform` and `ma_noise`. | + | MA_NO_GENERATION | Disables generation APIs such a ma_waveform and ma_noise. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_SSE2 | Disables SSE2 optimizations. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_AVX2 | Disables AVX2 optimizations. | +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_AVX512 | Disables AVX-512 optimizations. | + +----------------------------------+--------------------------------------------------------------------+ | MA_NO_NEON | Disables NEON optimizations. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_RUNTIME_LINKING | Disables runtime linking. This is useful for passing Apple's | @@ -692,66 +399,55 @@ To run locally, you'll need to use emrun: | | You may need to enable this if your target platform does not allow | | | runtime linking via `dlopen()`. | +----------------------------------+--------------------------------------------------------------------+ - | MA_USE_STDINT | (Pass this in as a compiler flag. Do not `#define` this before | - | | miniaudio.c) Forces the use of stdint.h for sized types. | + | MA_LOG_LEVEL [level] | Sets the logging level. Set `level` to one of the following: | + | | | + | | ``` | + | | MA_LOG_LEVEL_VERBOSE | + | | MA_LOG_LEVEL_INFO | + | | MA_LOG_LEVEL_WARNING | + | | MA_LOG_LEVEL_ERROR | + | | ``` | +----------------------------------+--------------------------------------------------------------------+ - | MA_DEBUG_OUTPUT | Enable `printf()` output of debug logs (`MA_LOG_LEVEL_DEBUG`). | + | MA_DEBUG_OUTPUT | Enable `printf()` debug output. | +----------------------------------+--------------------------------------------------------------------+ | MA_COINIT_VALUE | Windows only. The value to pass to internal calls to | | | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`. | +----------------------------------+--------------------------------------------------------------------+ - | MA_FORCE_UWP | Windows only. Affects only the WASAPI backend. Will force the | - | | WASAPI backend to use the UWP code path instead of the regular | - | | desktop path. This is normally auto-detected and should rarely be | - | | needed to be used explicitly, but can be useful for debugging. | - +----------------------------------+--------------------------------------------------------------------+ - | MA_ON_THREAD_ENTRY | Defines some code that will be executed as soon as an internal | - | | miniaudio-managed thread is created. This will be the first thing | - | | to be executed by the thread entry point. | - +----------------------------------+--------------------------------------------------------------------+ - | MA_ON_THREAD_EXIT | Defines some code that will be executed from the entry point of an | - | | internal miniaudio-managed thread upon exit. This will be the last | - | | thing to be executed before the thread's entry point exits. | - +----------------------------------+--------------------------------------------------------------------+ - | MA_THREAD_DEFAULT_STACK_SIZE | If set, specifies the default stack size used by miniaudio-managed | - | | threads. | - +----------------------------------+--------------------------------------------------------------------+ | MA_API | Controls how public APIs should be decorated. Default is `extern`. | +----------------------------------+--------------------------------------------------------------------+ + | MA_DLL | If set, configures MA_API to either import or export APIs | + | | depending on whether or not the implementation is being defined. | + | | If defining the implementation, MA_API will be configured to | + | | export. Otherwise it will be configured to import. This has no | + | | effect if MA_API is defined externally. | + +----------------------------------+--------------------------------------------------------------------+ 3. Definitions ============== -This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity -in the use of terms throughout the audio space, so this section is intended to clarify how miniaudio -uses each term. +This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this +section is intended to clarify how miniaudio uses each term. 3.1. Sample ----------- -A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit -floating point number. +A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number. 3.2. Frame / PCM Frame ---------------------- -A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 -samples, a mono frame is 1 sample, a 5.1 surround sound frame is 6 samples, etc. The terms "frame" -and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. -If ever miniaudio needs to refer to a compressed frame, such as a FLAC frame, it will always -clarify what it's referring to with something like "FLAC frame". +A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame +is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio +needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame". 3.3. Channel ------------ -A stream of monaural audio that is emitted from an individual speaker in a speaker system, or -received from an individual microphone in a microphone system. A stereo stream has two channels (a -left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio -systems refer to a channel as a complex audio stream that's mixed with other channels to produce -the final mix - this is completely different to miniaudio's use of the term "channel" and should -not be confused. +A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A +stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as +a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and +should not be confused. 3.4. Sample Rate ---------------- -The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number -of PCM frames that are processed per second. +The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second. 3.5. Formats ------------ @@ -771,1748 +467,38 @@ All formats are native-endian. -4. Data Sources -=============== -The data source abstraction in miniaudio is used for retrieving audio data from some source. A few -examples include `ma_decoder`, `ma_noise` and `ma_waveform`. You will need to be familiar with data -sources in order to make sense of some of the higher level concepts in miniaudio. - -The `ma_data_source` API is a generic interface for reading from a data source. Any object that -implements the data source interface can be plugged into any `ma_data_source` function. - -To read data from a data source: - - ```c - ma_result result; - ma_uint64 framesRead; - - result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, &framesRead); - if (result != MA_SUCCESS) { - return result; // Failed to read data from the data source. - } - ``` - -If you don't need the number of frames that were successfully read you can pass in `NULL` to the -`pFramesRead` parameter. If this returns a value less than the number of frames requested it means -the end of the file has been reached. `MA_AT_END` will be returned only when the number of frames -read is 0. - -When calling any data source function, with the exception of `ma_data_source_init()` and -`ma_data_source_uninit()`, you can pass in any object that implements a data source. For example, -you could plug in a decoder like so: - - ```c - ma_result result; - ma_uint64 framesRead; - ma_decoder decoder; // <-- This would be initialized with `ma_decoder_init_*()`. - - result = ma_data_source_read_pcm_frames(&decoder, pFramesOut, frameCount, &framesRead); - if (result != MA_SUCCESS) { - return result; // Failed to read data from the decoder. - } - ``` - -If you want to seek forward you can pass in `NULL` to the `pFramesOut` parameter. Alternatively you -can use `ma_data_source_seek_pcm_frames()`. - -To seek to a specific PCM frame: - - ```c - result = ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex); - if (result != MA_SUCCESS) { - return result; // Failed to seek to PCM frame. - } - ``` - -You can retrieve the total length of a data source in PCM frames, but note that some data sources -may not have the notion of a length, such as noise and waveforms, and others may just not have a -way of determining the length such as some decoders. To retrieve the length: - - ```c - ma_uint64 length; - - result = ma_data_source_get_length_in_pcm_frames(pDataSource, &length); - if (result != MA_SUCCESS) { - return result; // Failed to retrieve the length. - } - ``` - -Care should be taken when retrieving the length of a data source where the underlying decoder is -pulling data from a data stream with an undefined length, such as internet radio or some kind of -broadcast. If you do this, `ma_data_source_get_length_in_pcm_frames()` may never return. - -The current position of the cursor in PCM frames can also be retrieved: - - ```c - ma_uint64 cursor; - - result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor); - if (result != MA_SUCCESS) { - return result; // Failed to retrieve the cursor. - } - ``` - -You will often need to know the data format that will be returned after reading. This can be -retrieved like so: - - ```c - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_channel channelMap[MA_MAX_CHANNELS]; - - result = ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS); - if (result != MA_SUCCESS) { - return result; // Failed to retrieve data format. - } - ``` - -If you do not need a specific data format property, just pass in NULL to the respective parameter. - -There may be cases where you want to implement something like a sound bank where you only want to -read data within a certain range of the underlying data. To do this you can use a range: - - ```c - result = ma_data_source_set_range_in_pcm_frames(pDataSource, rangeBegInFrames, rangeEndInFrames); - if (result != MA_SUCCESS) { - return result; // Failed to set the range. - } - ``` - -This is useful if you have a sound bank where many sounds are stored in the same file and you want -the data source to only play one of those sub-sounds. Note that once the range is set, everything -that takes a position, such as cursors and loop points, should always be relatvie to the start of -the range. When the range is set, any previously defined loop point will be reset. - -Custom loop points can also be used with data sources. By default, data sources will loop after -they reach the end of the data source, but if you need to loop at a specific location, you can do -the following: - - ```c - result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); - if (result != MA_SUCCESS) { - return result; // Failed to set the loop point. - } - ``` - -The loop point is relative to the current range. - -It's sometimes useful to chain data sources together so that a seamless transition can be achieved. -To do this, you can use chaining: - - ```c - ma_decoder decoder1; - ma_decoder decoder2; - - // ... initialize decoders with ma_decoder_init_*() ... - - result = ma_data_source_set_next(&decoder1, &decoder2); - if (result != MA_SUCCESS) { - return result; // Failed to set the next data source. - } - - result = ma_data_source_read_pcm_frames(&decoder1, pFramesOut, frameCount, pFramesRead); - if (result != MA_SUCCESS) { - return result; // Failed to read from the decoder. - } - ``` - -In the example above we're using decoders. When reading from a chain, you always want to read from -the top level data source in the chain. In the example above, `decoder1` is the top level data -source in the chain. When `decoder1` reaches the end, `decoder2` will start seamlessly without any -gaps. - -Note that when looping is enabled, only the current data source will be looped. You can loop the -entire chain by linking in a loop like so: - - ```c - ma_data_source_set_next(&decoder1, &decoder2); // decoder1 -> decoder2 - ma_data_source_set_next(&decoder2, &decoder1); // decoder2 -> decoder1 (loop back to the start). - ``` - -Note that setting up chaining is not thread safe, so care needs to be taken if you're dynamically -changing links while the audio thread is in the middle of reading. - -Do not use `ma_decoder_seek_to_pcm_frame()` as a means to reuse a data source to play multiple -instances of the same sound simultaneously. This can be extremely inefficient depending on the type -of data source and can result in glitching due to subtle changes to the state of internal filters. -Instead, initialize multiple data sources for each instance. - - -4.1. Custom Data Sources ------------------------- -You can implement a custom data source by implementing the functions in `ma_data_source_vtable`. -Your custom object must have `ma_data_source_base` as it's first member: - - ```c - struct my_data_source - { - ma_data_source_base base; - ... - }; - ``` - -In your initialization routine, you need to call `ma_data_source_init()` in order to set up the -base object (`ma_data_source_base`): - - ```c - static ma_result my_data_source_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) - { - // Read data here. Output in the same format returned by my_data_source_get_data_format(). - } - - static ma_result my_data_source_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) - { - // Seek to a specific PCM frame here. Return MA_NOT_IMPLEMENTED if seeking is not supported. - } - - static ma_result my_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) - { - // Return the format of the data here. - } - - static ma_result my_data_source_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) - { - // Retrieve the current position of the cursor here. Return MA_NOT_IMPLEMENTED and set *pCursor to 0 if there is no notion of a cursor. - } - - static ma_result my_data_source_get_length(ma_data_source* pDataSource, ma_uint64* pLength) - { - // Retrieve the length in PCM frames here. Return MA_NOT_IMPLEMENTED and set *pLength to 0 if there is no notion of a length or if the length is unknown. - } - - static ma_data_source_vtable g_my_data_source_vtable = - { - my_data_source_read, - my_data_source_seek, - my_data_source_get_data_format, - my_data_source_get_cursor, - my_data_source_get_length - }; - - ma_result my_data_source_init(my_data_source* pMyDataSource) - { - ma_result result; - ma_data_source_config baseConfig; - - baseConfig = ma_data_source_config_init(); - baseConfig.vtable = &g_my_data_source_vtable; - - result = ma_data_source_init(&baseConfig, &pMyDataSource->base); - if (result != MA_SUCCESS) { - return result; - } - - // ... do the initialization of your custom data source here ... - - return MA_SUCCESS; - } - - void my_data_source_uninit(my_data_source* pMyDataSource) - { - // ... do the uninitialization of your custom data source here ... - - // You must uninitialize the base data source. - ma_data_source_uninit(&pMyDataSource->base); - } - ``` - -Note that `ma_data_source_init()` and `ma_data_source_uninit()` are never called directly outside -of the custom data source. It's up to the custom data source itself to call these within their own -init/uninit functions. - - - -5. Engine -========= -The `ma_engine` API is a high level API for managing and mixing sounds and effect processing. The -`ma_engine` object encapsulates a resource manager and a node graph, both of which will be -explained in more detail later. - -Sounds are called `ma_sound` and are created from an engine. Sounds can be associated with a mixing -group called `ma_sound_group` which are also created from the engine. Both `ma_sound` and -`ma_sound_group` objects are nodes within the engine's node graph. - -When the engine is initialized, it will normally create a device internally. If you would rather -manage the device yourself, you can do so and just pass a pointer to it via the engine config when -you initialize the engine. You can also just use the engine without a device, which again can be -configured via the engine config. - -The most basic way to initialize the engine is with a default config, like so: - - ```c - ma_result result; - ma_engine engine; - - result = ma_engine_init(NULL, &engine); - if (result != MA_SUCCESS) { - return result; // Failed to initialize the engine. - } - ``` - -This will result in the engine initializing a playback device using the operating system's default -device. This will be sufficient for many use cases, but if you need more flexibility you'll want to -configure the engine with an engine config: - - ```c - ma_result result; - ma_engine engine; - ma_engine_config engineConfig; - - engineConfig = ma_engine_config_init(); - engineConfig.pDevice = &myDevice; - - result = ma_engine_init(&engineConfig, &engine); - if (result != MA_SUCCESS) { - return result; // Failed to initialize the engine. - } - ``` - -In the example above we're passing in a pre-initialized device. Since the caller is the one in -control of the device's data callback, it's their responsibility to manually call -`ma_engine_read_pcm_frames()` from inside their data callback: - - ```c - void playback_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) - { - ma_engine_read_pcm_frames(&g_Engine, pOutput, frameCount, NULL); - } - ``` - -You can also use the engine independent of a device entirely: - - ```c - ma_result result; - ma_engine engine; - ma_engine_config engineConfig; - - engineConfig = ma_engine_config_init(); - engineConfig.noDevice = MA_TRUE; - engineConfig.channels = 2; // Must be set when not using a device. - engineConfig.sampleRate = 48000; // Must be set when not using a device. - - result = ma_engine_init(&engineConfig, &engine); - if (result != MA_SUCCESS) { - return result; // Failed to initialize the engine. - } - ``` - -Note that when you're not using a device, you must set the channel count and sample rate in the -config or else miniaudio won't know what to use (miniaudio will use the device to determine this -normally). When not using a device, you need to use `ma_engine_read_pcm_frames()` to process audio -data from the engine. This kind of setup is useful if you want to do something like offline -processing or want to use a different audio system for playback such as SDL. - -When a sound is loaded it goes through a resource manager. By default the engine will initialize a -resource manager internally, but you can also specify a pre-initialized resource manager: - - ```c - ma_result result; - ma_engine engine1; - ma_engine engine2; - ma_engine_config engineConfig; - - engineConfig = ma_engine_config_init(); - engineConfig.pResourceManager = &myResourceManager; - - ma_engine_init(&engineConfig, &engine1); - ma_engine_init(&engineConfig, &engine2); - ``` - -In this example we are initializing two engines, both of which are sharing the same resource -manager. This is especially useful for saving memory when loading the same file across multiple -engines. If you were not to use a shared resource manager, each engine instance would use their own -which would result in any sounds that are used between both engine's being loaded twice. By using -a shared resource manager, it would only be loaded once. Using multiple engine's is useful when you -need to output to multiple playback devices, such as in a local multiplayer game where each player -is using their own set of headphones. - -By default an engine will be in a started state. To make it so the engine is not automatically -started you can configure it as such: - - ```c - engineConfig.noAutoStart = MA_TRUE; - - // The engine will need to be started manually. - ma_engine_start(&engine); - - // Later on the engine can be stopped with ma_engine_stop(). - ma_engine_stop(&engine); - ``` - -The concept of starting or stopping an engine is only relevant when using the engine with a -device. Attempting to start or stop an engine that is not associated with a device will result in -`MA_INVALID_OPERATION`. - -The master volume of the engine can be controlled with `ma_engine_set_volume()` which takes a -linear scale, with 0 resulting in silence and anything above 1 resulting in amplification. If you -prefer decibel based volume control, use `ma_volume_db_to_linear()` to convert from dB to linear. - -When a sound is spatialized, it is done so relative to a listener. An engine can be configured to -have multiple listeners which can be configured via the config: - - ```c - engineConfig.listenerCount = 2; - ``` - -The maximum number of listeners is restricted to `MA_ENGINE_MAX_LISTENERS`. By default, when a -sound is spatialized, it will be done so relative to the closest listener. You can also pin a sound -to a specific listener which will be explained later. Listener's have a position, direction, cone, -and velocity (for doppler effect). A listener is referenced by an index, the meaning of which is up -to the caller (the index is 0 based and cannot go beyond the listener count, minus 1). The -position, direction and velocity are all specified in absolute terms: - - ```c - ma_engine_listener_set_position(&engine, listenerIndex, worldPosX, worldPosY, worldPosZ); - ``` - -The direction of the listener represents it's forward vector. The listener's up vector can also be -specified and defaults to +1 on the Y axis. - - ```c - ma_engine_listener_set_direction(&engine, listenerIndex, forwardX, forwardY, forwardZ); - ma_engine_listener_set_world_up(&engine, listenerIndex, 0, 1, 0); - ``` - -The engine supports directional attenuation. The listener can have a cone the controls how sound is -attenuated based on the listener's direction. When a sound is between the inner and outer cones, it -will be attenuated between 1 and the cone's outer gain: - - ```c - ma_engine_listener_set_cone(&engine, listenerIndex, innerAngleInRadians, outerAngleInRadians, outerGain); - ``` - -When a sound is inside the inner code, no directional attenuation is applied. When the sound is -outside of the outer cone, the attenuation will be set to `outerGain` in the example above. When -the sound is in between the inner and outer cones, the attenuation will be interpolated between 1 -and the outer gain. - -The engine's coordinate system follows the OpenGL coordinate system where positive X points right, -positive Y points up and negative Z points forward. - -The simplest and least flexible way to play a sound is like so: - - ```c - ma_engine_play_sound(&engine, "my_sound.wav", pGroup); - ``` - -This is a "fire and forget" style of function. The engine will manage the `ma_sound` object -internally. When the sound finishes playing, it'll be put up for recycling. For more flexibility -you'll want to initialize a sound object: - - ```c - ma_sound sound; - - result = ma_sound_init_from_file(&engine, "my_sound.wav", flags, pGroup, NULL, &sound); - if (result != MA_SUCCESS) { - return result; // Failed to load sound. - } - ``` - -Sounds need to be uninitialized with `ma_sound_uninit()`. - -The example above loads a sound from a file. If the resource manager has been disabled you will not -be able to use this function and instead you'll need to initialize a sound directly from a data -source: - - ```c - ma_sound sound; - - result = ma_sound_init_from_data_source(&engine, &dataSource, flags, pGroup, &sound); - if (result != MA_SUCCESS) { - return result; - } - ``` - -Each `ma_sound` object represents a single instance of the sound. If you want to play the same -sound multiple times at the same time, you need to initialize a separate `ma_sound` object. - -For the most flexibility when initializing sounds, use `ma_sound_init_ex()`. This uses miniaudio's -standard config/init pattern: - - ```c - ma_sound sound; - ma_sound_config soundConfig; - - soundConfig = ma_sound_config_init(); - soundConfig.pFilePath = NULL; // Set this to load from a file path. - soundConfig.pDataSource = NULL; // Set this to initialize from an existing data source. - soundConfig.pInitialAttachment = &someNodeInTheNodeGraph; - soundConfig.initialAttachmentInputBusIndex = 0; - soundConfig.channelsIn = 1; - soundConfig.channelsOut = 0; // Set to 0 to use the engine's native channel count. - - result = ma_sound_init_ex(&soundConfig, &sound); - if (result != MA_SUCCESS) { - return result; - } - ``` - -In the example above, the sound is being initialized without a file nor a data source. This is -valid, in which case the sound acts as a node in the middle of the node graph. This means you can -connect other sounds to this sound and allow it to act like a sound group. Indeed, this is exactly -what a `ma_sound_group` is. - -When loading a sound, you specify a set of flags that control how the sound is loaded and what -features are enabled for that sound. When no flags are set, the sound will be fully loaded into -memory in exactly the same format as how it's stored on the file system. The resource manager will -allocate a block of memory and then load the file directly into it. When reading audio data, it -will be decoded dynamically on the fly. In order to save processing time on the audio thread, it -might be beneficial to pre-decode the sound. You can do this with the `MA_SOUND_FLAG_DECODE` flag: - - ```c - ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE, pGroup, NULL, &sound); - ``` - -By default, sounds will be loaded synchronously, meaning `ma_sound_init_*()` will not return until -the sound has been fully loaded. If this is prohibitive you can instead load sounds asynchronously -by specifying the `MA_SOUND_FLAG_ASYNC` flag: - - ```c - ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, NULL, &sound); - ``` - -This will result in `ma_sound_init_*()` returning quickly, but the sound won't yet have been fully -loaded. When you start the sound, it won't output anything until some sound is available. The sound -will start outputting audio before the sound has been fully decoded when the `MA_SOUND_FLAG_DECODE` -is specified. - -If you need to wait for an asynchronously loaded sound to be fully loaded, you can use a fence. A -fence in miniaudio is a simple synchronization mechanism which simply blocks until it's internal -counter hit's zero. You can specify a fence like so: - - ```c - ma_result result; - ma_fence fence; - ma_sound sounds[4]; - - result = ma_fence_init(&fence); - if (result != MA_SUCCESS) { - return result; - } - - // Load some sounds asynchronously. - for (int iSound = 0; iSound < 4; iSound += 1) { - ma_sound_init_from_file(&engine, mySoundFilesPaths[iSound], MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, &fence, &sounds[iSound]); - } - - // ... do some other stuff here in the mean time ... - - // Wait for all sounds to finish loading. - ma_fence_wait(&fence); - ``` - -If loading the entire sound into memory is prohibitive, you can also configure the engine to stream -the audio data: - - ```c - ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_STREAM, pGroup, NULL, &sound); - ``` - -When streaming sounds, 2 seconds worth of audio data is stored in memory. Although it should work -fine, it's inefficient to use streaming for short sounds. Streaming is useful for things like music -tracks in games. - -When loading a sound from a file path, the engine will reference count the file to prevent it from -being loaded if it's already in memory. When you uninitialize a sound, the reference count will be -decremented, and if it hits zero, the sound will be unloaded from memory. This reference counting -system is not used for streams. The engine will use a 64-bit hash of the file name when comparing -file paths which means there's a small chance you might encounter a name collision. If this is an -issue, you'll need to use a different name for one of the colliding file paths, or just not load -from files and instead load from a data source. - -You can use `ma_sound_init_copy()` to initialize a copy of another sound. Note, however, that this -only works for sounds that were initialized with `ma_sound_init_from_file()` and without the -`MA_SOUND_FLAG_STREAM` flag. - -When you initialize a sound, if you specify a sound group the sound will be attached to that group -automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint. -If you would instead rather leave the sound unattached by default, you can specify the -`MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT` flag. This is useful if you want to set up a complex node -graph. - -Sounds are not started by default. To start a sound, use `ma_sound_start()`. Stop a sound with -`ma_sound_stop()`. - -Sounds can have their volume controlled with `ma_sound_set_volume()` in the same way as the -engine's master volume. - -Sounds support stereo panning and pitching. Set the pan with `ma_sound_set_pan()`. Setting the pan -to 0 will result in an unpanned sound. Setting it to -1 will shift everything to the left, whereas -+1 will shift it to the right. The pitch can be controlled with `ma_sound_set_pitch()`. A larger -value will result in a higher pitch. The pitch must be greater than 0. - -The engine supports 3D spatialization of sounds. By default sounds will have spatialization -enabled, but if a sound does not need to be spatialized it's best to disable it. There are two ways -to disable spatialization of a sound: - - ```c - // Disable spatialization at initialization time via a flag: - ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, &sound); - - // Dynamically disable or enable spatialization post-initialization: - ma_sound_set_spatialization_enabled(&sound, isSpatializationEnabled); - ``` - -By default sounds will be spatialized based on the closest listener. If a sound should always be -spatialized relative to a specific listener it can be pinned to one: - - ```c - ma_sound_set_pinned_listener_index(&sound, listenerIndex); - ``` - -Like listeners, sounds have a position. By default, the position of a sound is in absolute space, -but it can be changed to be relative to a listener: - - ```c - ma_sound_set_positioning(&sound, ma_positioning_relative); - ``` - -Note that relative positioning of a sound only makes sense if there is either only one listener, or -the sound is pinned to a specific listener. To set the position of a sound: - - ```c - ma_sound_set_position(&sound, posX, posY, posZ); - ``` - -The direction works the same way as a listener and represents the sound's forward direction: - - ```c - ma_sound_set_direction(&sound, forwardX, forwardY, forwardZ); - ``` - -Sound's also have a cone for controlling directional attenuation. This works exactly the same as -listeners: - - ```c - ma_sound_set_cone(&sound, innerAngleInRadians, outerAngleInRadians, outerGain); - ``` - -The velocity of a sound is used for doppler effect and can be set as such: - - ```c - ma_sound_set_velocity(&sound, velocityX, velocityY, velocityZ); - ``` - -The engine supports different attenuation models which can be configured on a per-sound basis. By -default the attenuation model is set to `ma_attenuation_model_inverse` which is the equivalent to -OpenAL's `AL_INVERSE_DISTANCE_CLAMPED`. Configure the attenuation model like so: - - ```c - ma_sound_set_attenuation_model(&sound, ma_attenuation_model_inverse); - ``` - -The supported attenuation models include the following: - - +----------------------------------+----------------------------------------------+ - | ma_attenuation_model_none | No distance attenuation. | - +----------------------------------+----------------------------------------------+ - | ma_attenuation_model_inverse | Equivalent to `AL_INVERSE_DISTANCE_CLAMPED`. | - +----------------------------------+----------------------------------------------+ - | ma_attenuation_model_linear | Linear attenuation. | - +----------------------------------+----------------------------------------------+ - | ma_attenuation_model_exponential | Exponential attenuation. | - +----------------------------------+----------------------------------------------+ - -To control how quickly a sound rolls off as it moves away from the listener, you need to configure -the rolloff: - - ```c - ma_sound_set_rolloff(&sound, rolloff); - ``` - -You can control the minimum and maximum gain to apply from spatialization: - - ```c - ma_sound_set_min_gain(&sound, minGain); - ma_sound_set_max_gain(&sound, maxGain); - ``` - -Likewise, in the calculation of attenuation, you can control the minimum and maximum distances for -the attenuation calculation. This is useful if you want to ensure sounds don't drop below a certain -volume after the listener moves further away and to have sounds play a maximum volume when the -listener is within a certain distance: - - ```c - ma_sound_set_min_distance(&sound, minDistance); - ma_sound_set_max_distance(&sound, maxDistance); - ``` - -The engine's spatialization system supports doppler effect. The doppler factor can be configure on -a per-sound basis like so: - - ```c - ma_sound_set_doppler_factor(&sound, dopplerFactor); - ``` - -You can fade sounds in and out with `ma_sound_set_fade_in_pcm_frames()` and -`ma_sound_set_fade_in_milliseconds()`. Set the volume to -1 to use the current volume as the -starting volume: - - ```c - // Fade in over 1 second. - ma_sound_set_fade_in_milliseconds(&sound, 0, 1, 1000); - - // ... sometime later ... - - // Fade out over 1 second, starting from the current volume. - ma_sound_set_fade_in_milliseconds(&sound, -1, 0, 1000); - ``` - -By default sounds will start immediately, but sometimes for timing and synchronization purposes it -can be useful to schedule a sound to start or stop: - - ```c - // Start the sound in 1 second from now. - ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time_in_pcm_frames(&engine) + (ma_engine_get_sample_rate(&engine) * 1)); - - // Stop the sound in 2 seconds from now. - ma_sound_set_stop_time_in_pcm_frames(&sound, ma_engine_get_time_in_pcm_frames(&engine) + (ma_engine_get_sample_rate(&engine) * 2)); - ``` - -Note that scheduling a start time still requires an explicit call to `ma_sound_start()` before -anything will play. - -The time is specified in global time which is controlled by the engine. You can get the engine's -current time with `ma_engine_get_time_in_pcm_frames()`. The engine's global time is incremented -automatically as audio data is read, but it can be reset with `ma_engine_set_time_in_pcm_frames()` -in case it needs to be resynchronized for some reason. - -To determine whether or not a sound is currently playing, use `ma_sound_is_playing()`. This will -take the scheduled start and stop times into account. - -Whether or not a sound should loop can be controlled with `ma_sound_set_looping()`. Sounds will not -be looping by default. Use `ma_sound_is_looping()` to determine whether or not a sound is looping. - -Use `ma_sound_at_end()` to determine whether or not a sound is currently at the end. For a looping -sound this should never return true. Alternatively, you can configure a callback that will be fired -when the sound reaches the end. Note that the callback is fired from the audio thread which means -you cannot be uninitializing sound from the callback. To set the callback you can use -`ma_sound_set_end_callback()`. Alternatively, if you're using `ma_sound_init_ex()`, you can pass it -into the config like so: - - ```c - soundConfig.endCallback = my_end_callback; - soundConfig.pEndCallbackUserData = pMyEndCallbackUserData; - ``` - -The end callback is declared like so: - - ```c - void my_end_callback(void* pUserData, ma_sound* pSound) - { - ... - } - ``` - -Internally a sound wraps around a data source. Some APIs exist to control the underlying data -source, mainly for convenience: - - ```c - ma_sound_seek_to_pcm_frame(&sound, frameIndex); - ma_sound_get_data_format(&sound, &format, &channels, &sampleRate, pChannelMap, channelMapCapacity); - ma_sound_get_cursor_in_pcm_frames(&sound, &cursor); - ma_sound_get_length_in_pcm_frames(&sound, &length); - ``` - -Sound groups have the same API as sounds, only they are called `ma_sound_group`, and since they do -not have any notion of a data source, anything relating to a data source is unavailable. - -Internally, sound data is loaded via the `ma_decoder` API which means by default it only supports -file formats that have built-in support in miniaudio. You can extend this to support any kind of -file format through the use of custom decoders. To do this you'll need to use a self-managed -resource manager and configure it appropriately. See the "Resource Management" section below for -details on how to set this up. - - -6. Resource Management -====================== -Many programs will want to manage sound resources for things such as reference counting and -streaming. This is supported by miniaudio via the `ma_resource_manager` API. - -The resource manager is mainly responsible for the following: - - * Loading of sound files into memory with reference counting. - * Streaming of sound data. - -When loading a sound file, the resource manager will give you back a `ma_data_source` compatible -object called `ma_resource_manager_data_source`. This object can be passed into any -`ma_data_source` API which is how you can read and seek audio data. When loading a sound file, you -specify whether or not you want the sound to be fully loaded into memory (and optionally -pre-decoded) or streamed. When loading into memory, you can also specify whether or not you want -the data to be loaded asynchronously. - -The example below is how you can initialize a resource manager using it's default configuration: - - ```c - ma_resource_manager_config config; - ma_resource_manager resourceManager; - - config = ma_resource_manager_config_init(); - result = ma_resource_manager_init(&config, &resourceManager); - if (result != MA_SUCCESS) { - ma_device_uninit(&device); - printf("Failed to initialize the resource manager."); - return -1; - } - ``` - -You can configure the format, channels and sample rate of the decoded audio data. By default it -will use the file's native data format, but you can configure it to use a consistent format. This -is useful for offloading the cost of data conversion to load time rather than dynamically -converting at mixing time. To do this, you configure the decoded format, channels and sample rate -like the code below: - - ```c - config = ma_resource_manager_config_init(); - config.decodedFormat = device.playback.format; - config.decodedChannels = device.playback.channels; - config.decodedSampleRate = device.sampleRate; - ``` - -In the code above, the resource manager will be configured so that any decoded audio data will be -pre-converted at load time to the device's native data format. If instead you used defaults and -the data format of the file did not match the device's data format, you would need to convert the -data at mixing time which may be prohibitive in high-performance and large scale scenarios like -games. - -Internally the resource manager uses the `ma_decoder` API to load sounds. This means by default it -only supports decoders that are built into miniaudio. It's possible to support additional encoding -formats through the use of custom decoders. To do so, pass in your `ma_decoding_backend_vtable` -vtables into the resource manager config: - - ```c - ma_decoding_backend_vtable* pCustomBackendVTables[] = - { - &g_ma_decoding_backend_vtable_libvorbis, - &g_ma_decoding_backend_vtable_libopus - }; - - ... - - resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables; - resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); - resourceManagerConfig.pCustomDecodingBackendUserData = NULL; - ``` - -This system can allow you to support any kind of file format. See the "Decoding" section for -details on how to implement custom decoders. The miniaudio repository includes examples for Opus -via libopus and libopusfile and Vorbis via libvorbis and libvorbisfile. - -Asynchronicity is achieved via a job system. When an operation needs to be performed, such as the -decoding of a page, a job will be posted to a queue which will then be processed by a job thread. -By default there will be only one job thread running, but this can be configured, like so: - - ```c - config = ma_resource_manager_config_init(); - config.jobThreadCount = MY_JOB_THREAD_COUNT; - ``` - -By default job threads are managed internally by the resource manager, however you can also self -manage your job threads if, for example, you want to integrate the job processing into your -existing job infrastructure, or if you simply don't like the way the resource manager does it. To -do this, just set the job thread count to 0 and process jobs manually. To process jobs, you first -need to retrieve a job using `ma_resource_manager_next_job()` and then process it using -`ma_job_process()`: - - ```c - config = ma_resource_manager_config_init(); - config.jobThreadCount = 0; // Don't manage any job threads internally. - config.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; // Optional. Makes `ma_resource_manager_next_job()` non-blocking. - - // ... Initialize your custom job threads ... - - void my_custom_job_thread(...) - { - for (;;) { - ma_job job; - ma_result result = ma_resource_manager_next_job(pMyResourceManager, &job); - if (result != MA_SUCCESS) { - if (result == MA_NO_DATA_AVAILABLE) { - // No jobs are available. Keep going. Will only get this if the resource manager was initialized - // with MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. - continue; - } else if (result == MA_CANCELLED) { - // MA_JOB_TYPE_QUIT was posted. Exit. - break; - } else { - // Some other error occurred. - break; - } - } - - ma_job_process(&job); - } - } - ``` - -In the example above, the `MA_JOB_TYPE_QUIT` event is the used as the termination -indicator, but you can use whatever you would like to terminate the thread. The call to -`ma_resource_manager_next_job()` is blocking by default, but can be configured to be non-blocking -by initializing the resource manager with the `MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING` configuration -flag. Note that the `MA_JOB_TYPE_QUIT` will never be removed from the job queue. This -is to give every thread the opportunity to catch the event and terminate naturally. - -When loading a file, it's sometimes convenient to be able to customize how files are opened and -read instead of using standard `fopen()`, `fclose()`, etc. which is what miniaudio will use by -default. This can be done by setting `pVFS` member of the resource manager's config: - - ```c - // Initialize your custom VFS object. See documentation for VFS for information on how to do this. - my_custom_vfs vfs = my_custom_vfs_init(); - - config = ma_resource_manager_config_init(); - config.pVFS = &vfs; - ``` - -This is particularly useful in programs like games where you want to read straight from an archive -rather than the normal file system. If you do not specify a custom VFS, the resource manager will -use the operating system's normal file operations. - -To load a sound file and create a data source, call `ma_resource_manager_data_source_init()`. When -loading a sound you need to specify the file path and options for how the sounds should be loaded. -By default a sound will be loaded synchronously. The returned data source is owned by the caller -which means the caller is responsible for the allocation and freeing of the data source. Below is -an example for initializing a data source: - - ```c - ma_resource_manager_data_source dataSource; - ma_result result = ma_resource_manager_data_source_init(pResourceManager, pFilePath, flags, &dataSource); - if (result != MA_SUCCESS) { - // Error. - } - - // ... - - // A ma_resource_manager_data_source object is compatible with the `ma_data_source` API. To read data, just call - // the `ma_data_source_read_pcm_frames()` like you would with any normal data source. - result = ma_data_source_read_pcm_frames(&dataSource, pDecodedData, frameCount, &framesRead); - if (result != MA_SUCCESS) { - // Failed to read PCM frames. - } - - // ... - - ma_resource_manager_data_source_uninit(&dataSource); - ``` - -The `flags` parameter specifies how you want to perform loading of the sound file. It can be a -combination of the following flags: - - ``` - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING - ``` - -When no flags are specified (set to 0), the sound will be fully loaded into memory, but not -decoded, meaning the raw file data will be stored in memory, and then dynamically decoded when -`ma_data_source_read_pcm_frames()` is called. To instead decode the audio data before storing it in -memory, use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` flag. By default, the sound file will -be loaded synchronously, meaning `ma_resource_manager_data_source_init()` will only return after -the entire file has been loaded. This is good for simplicity, but can be prohibitively slow. You -can instead load the sound asynchronously using the `MA_RESOURCE_MANAGER_DATA_SOURCE_ASYNC` flag. -This will result in `ma_resource_manager_data_source_init()` returning quickly, but no data will be -returned by `ma_data_source_read_pcm_frames()` until some data is available. When no data is -available because the asynchronous decoding hasn't caught up, `MA_BUSY` will be returned by -`ma_data_source_read_pcm_frames()`. - -For large sounds, it's often prohibitive to store the entire file in memory. To mitigate this, you -can instead stream audio data which you can do by specifying the -`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. When streaming, data will be decoded in 1 -second pages. When a new page needs to be decoded, a job will be posted to the job queue and then -subsequently processed in a job thread. - -The `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING` flag can be used so that the sound will loop -when it reaches the end by default. It's recommended you use this flag when you want to have a -looping streaming sound. If you try loading a very short sound as a stream, you will get a glitch. -This is because the resource manager needs to pre-fill the initial buffer at initialization time, -and if you don't specify the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING` flag, the resource -manager will assume the sound is not looping and will stop filling the buffer when it reaches the -end, therefore resulting in a discontinuous buffer. - -For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means -multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in -the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be -matched up with a call to `ma_resource_manager_data_source_uninit()`. Sometimes it can be useful -for a program to register self-managed raw audio data and associate it with a file path. Use the -`ma_resource_manager_register_*()` and `ma_resource_manager_unregister_*()` APIs to do this. -`ma_resource_manager_register_decoded_data()` is used to associate a pointer to raw, self-managed -decoded audio data in the specified data format with the specified name. Likewise, -`ma_resource_manager_register_encoded_data()` is used to associate a pointer to raw self-managed -encoded audio data (the raw file data) with the specified name. Note that these names need not be -actual file paths. When `ma_resource_manager_data_source_init()` is called (without the -`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag), the resource manager will look for these -explicitly registered data buffers and, if found, will use it as the backing data for the data -source. Note that the resource manager does *not* make a copy of this data so it is up to the -caller to ensure the pointer stays valid for its lifetime. Use -`ma_resource_manager_unregister_data()` to unregister the self-managed data. You can also use -`ma_resource_manager_register_file()` and `ma_resource_manager_unregister_file()` to register and -unregister a file. It does not make sense to use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` -flag with a self-managed data pointer. - - -6.1. Asynchronous Loading and Synchronization ---------------------------------------------- -When loading asynchronously, it can be useful to poll whether or not loading has finished. Use -`ma_resource_manager_data_source_result()` to determine this. For in-memory sounds, this will -return `MA_SUCCESS` when the file has been *entirely* decoded. If the sound is still being decoded, -`MA_BUSY` will be returned. Otherwise, some other error code will be returned if the sound failed -to load. For streaming data sources, `MA_SUCCESS` will be returned when the first page has been -decoded and the sound is ready to be played. If the first page is still being decoded, `MA_BUSY` -will be returned. Otherwise, some other error code will be returned if the sound failed to load. - -In addition to polling, you can also use a simple synchronization object called a "fence" to wait -for asynchronously loaded sounds to finish. This is called `ma_fence`. The advantage to using a -fence is that it can be used to wait for a group of sounds to finish loading rather than waiting -for sounds on an individual basis. There are two stages to loading a sound: - - * Initialization of the internal decoder; and - * Completion of decoding of the file (the file is fully decoded) - -You can specify separate fences for each of the different stages. Waiting for the initialization -of the internal decoder is important for when you need to know the sample format, channels and -sample rate of the file. - -The example below shows how you could use a fence when loading a number of sounds: - - ```c - // This fence will be released when all sounds are finished loading entirely. - ma_fence fence; - ma_fence_init(&fence); - - // This will be passed into the initialization routine for each sound. - ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init(); - notifications.done.pFence = &fence; - - // Now load a bunch of sounds: - for (iSound = 0; iSound < soundCount; iSound += 1) { - ma_resource_manager_data_source_init(pResourceManager, pSoundFilePaths[iSound], flags, ¬ifications, &pSoundSources[iSound]); - } - - // ... DO SOMETHING ELSE WHILE SOUNDS ARE LOADING ... - - // Wait for loading of sounds to finish. - ma_fence_wait(&fence); - ``` - -In the example above we used a fence for waiting until the entire file has been fully decoded. If -you only need to wait for the initialization of the internal decoder to complete, you can use the -`init` member of the `ma_resource_manager_pipeline_notifications` object: - - ```c - notifications.init.pFence = &fence; - ``` - -If a fence is not appropriate for your situation, you can instead use a callback that is fired on -an individual sound basis. This is done in a very similar way to fences: - - ```c - typedef struct - { - ma_async_notification_callbacks cb; - void* pMyData; - } my_notification; - - void my_notification_callback(ma_async_notification* pNotification) - { - my_notification* pMyNotification = (my_notification*)pNotification; - - // Do something in response to the sound finishing loading. - } - - ... - - my_notification myCallback; - myCallback.cb.onSignal = my_notification_callback; - myCallback.pMyData = pMyData; - - ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init(); - notifications.done.pNotification = &myCallback; - - ma_resource_manager_data_source_init(pResourceManager, "my_sound.wav", flags, ¬ifications, &mySound); - ``` - -In the example above we just extend the `ma_async_notification_callbacks` object and pass an -instantiation into the `ma_resource_manager_pipeline_notifications` in the same way as we did with -the fence, only we set `pNotification` instead of `pFence`. You can set both of these at the same -time and they should both work as expected. If using the `pNotification` system, you need to ensure -your `ma_async_notification_callbacks` object stays valid. - - - -6.2. Resource Manager Implementation Details --------------------------------------------- -Resources are managed in two main ways: - - * By storing the entire sound inside an in-memory buffer (referred to as a data buffer) - * By streaming audio data on the fly (referred to as a data stream) - -A resource managed data source (`ma_resource_manager_data_source`) encapsulates a data buffer or -data stream, depending on whether or not the data source was initialized with the -`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. If so, it will make use of a -`ma_resource_manager_data_stream` object. Otherwise it will use a `ma_resource_manager_data_buffer` -object. Both of these objects are data sources which means they can be used with any -`ma_data_source_*()` API. - -Another major feature of the resource manager is the ability to asynchronously decode audio files. -This relieves the audio thread of time-consuming decoding which can negatively affect scalability -due to the audio thread needing to complete it's work extremely quickly to avoid glitching. -Asynchronous decoding is achieved through a job system. There is a central multi-producer, -multi-consumer, fixed-capacity job queue. When some asynchronous work needs to be done, a job is -posted to the queue which is then read by a job thread. The number of job threads can be -configured for improved scalability, and job threads can all run in parallel without needing to -worry about the order of execution (how this is achieved is explained below). - -When a sound is being loaded asynchronously, playback can begin before the sound has been fully -decoded. This enables the application to start playback of the sound quickly, while at the same -time allowing to resource manager to keep loading in the background. Since there may be less -threads than the number of sounds being loaded at a given time, a simple scheduling system is used -to keep decoding time balanced and fair. The resource manager solves this by splitting decoding -into chunks called pages. By default, each page is 1 second long. When a page has been decoded, a -new job will be posted to start decoding the next page. By dividing up decoding into pages, an -individual sound shouldn't ever delay every other sound from having their first page decoded. Of -course, when loading many sounds at the same time, there will always be an amount of time required -to process jobs in the queue so in heavy load situations there will still be some delay. To -determine if a data source is ready to have some frames read, use -`ma_resource_manager_data_source_get_available_frames()`. This will return the number of frames -available starting from the current position. - - -6.2.1. Job Queue ----------------- -The resource manager uses a job queue which is multi-producer, multi-consumer, and fixed-capacity. -This job queue is not currently lock-free, and instead uses a spinlock to achieve thread-safety. -Only a fixed number of jobs can be allocated and inserted into the queue which is done through a -lock-free data structure for allocating an index into a fixed sized array, with reference counting -for mitigation of the ABA problem. The reference count is 32-bit. - -For many types of jobs it's important that they execute in a specific order. In these cases, jobs -are executed serially. For the resource manager, serial execution of jobs is only required on a -per-object basis (per data buffer or per data stream). Each of these objects stores an execution -counter. When a job is posted it is associated with an execution counter. When the job is -processed, it checks if the execution counter of the job equals the execution counter of the -owning object and if so, processes the job. If the counters are not equal, the job will be posted -back onto the job queue for later processing. When the job finishes processing the execution order -of the main object is incremented. This system means the no matter how many job threads are -executing, decoding of an individual sound will always get processed serially. The advantage to -having multiple threads comes into play when loading multiple sounds at the same time. - -The resource manager's job queue is not 100% lock-free and will use a spinlock to achieve -thread-safety for a very small section of code. This is only relevant when the resource manager -uses more than one job thread. If only using a single job thread, which is the default, the -lock should never actually wait in practice. The amount of time spent locking should be quite -short, but it's something to be aware of for those who have pedantic lock-free requirements and -need to use more than one job thread. There are plans to remove this lock in a future version. - -In addition, posting a job will release a semaphore, which on Win32 is implemented with -`ReleaseSemaphore` and on POSIX platforms via a condition variable: - - ```c - pthread_mutex_lock(&pSemaphore->lock); - { - pSemaphore->value += 1; - pthread_cond_signal(&pSemaphore->cond); - } - pthread_mutex_unlock(&pSemaphore->lock); - ``` - -Again, this is relevant for those with strict lock-free requirements in the audio thread. To avoid -this, you can use non-blocking mode (via the `MA_JOB_QUEUE_FLAG_NON_BLOCKING` -flag) and implement your own job processing routine (see the "Resource Manager" section above for -details on how to do this). - - - -6.2.2. Data Buffers -------------------- -When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag is excluded at initialization time, the -resource manager will try to load the data into an in-memory data buffer. Before doing so, however, -it will first check if the specified file is already loaded. If so, it will increment a reference -counter and just use the already loaded data. This saves both time and memory. When the data buffer -is uninitialized, the reference counter will be decremented. If the counter hits zero, the file -will be unloaded. This is a detail to keep in mind because it could result in excessive loading and -unloading of a sound. For example, the following sequence will result in a file be loaded twice, -once after the other: - - ```c - ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer0); // Refcount = 1. Initial load. - ma_resource_manager_data_source_uninit(&myDataBuffer0); // Refcount = 0. Unloaded. - - ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer1); // Refcount = 1. Reloaded because previous uninit() unloaded it. - ma_resource_manager_data_source_uninit(&myDataBuffer1); // Refcount = 0. Unloaded. - ``` - -A binary search tree (BST) is used for storing data buffers as it has good balance between -efficiency and simplicity. The key of the BST is a 64-bit hash of the file path that was passed -into `ma_resource_manager_data_source_init()`. The advantage of using a hash is that it saves -memory over storing the entire path, has faster comparisons, and results in a mostly balanced BST -due to the random nature of the hash. The disadvantages are that file names are case-sensitive and -there's a small chance of name collisions. If case-sensitivity is an issue, you should normalize -your file names to upper- or lower-case before initializing your data sources. If name collisions -become an issue, you'll need to change the name of one of the colliding names or just not use the -resource manager. - -When a sound file has not already been loaded and the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` -flag is excluded, the file will be decoded synchronously by the calling thread. There are two -options for controlling how the audio is stored in the data buffer - encoded or decoded. When the -`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` option is excluded, the raw file data will be stored -in memory. Otherwise the sound will be decoded before storing it in memory. Synchronous loading is -a very simple and standard process of simply adding an item to the BST, allocating a block of -memory and then decoding (if `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` is specified). - -When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag is specified, loading of the data buffer -is done asynchronously. In this case, a job is posted to the queue to start loading and then the -function immediately returns, setting an internal result code to `MA_BUSY`. This result code is -returned when the program calls `ma_resource_manager_data_source_result()`. When decoding has fully -completed `MA_SUCCESS` will be returned. This can be used to know if loading has fully completed. - -When loading asynchronously, a single job is posted to the queue of the type -`MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE`. This involves making a copy of the file path and -associating it with job. When the job is processed by the job thread, it will first load the file -using the VFS associated with the resource manager. When using a custom VFS, it's important that it -be completely thread-safe because it will be used from one or more job threads at the same time. -Individual files should only ever be accessed by one thread at a time, however. After opening the -file via the VFS, the job will determine whether or not the file is being decoded. If not, it -simply allocates a block of memory and loads the raw file contents into it and returns. On the -other hand, when the file is being decoded, it will first allocate a decoder on the heap and -initialize it. Then it will check if the length of the file is known. If so it will allocate a -block of memory to store the decoded output and initialize it to silence. If the size is unknown, -it will allocate room for one page. After memory has been allocated, the first page will be -decoded. If the sound is shorter than a page, the result code will be set to `MA_SUCCESS` and the -completion event will be signalled and loading is now complete. If, however, there is more to -decode, a job with the code `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` is posted. This job -will decode the next page and perform the same process if it reaches the end. If there is more to -decode, the job will post another `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` job which will -keep on happening until the sound has been fully decoded. For sounds of an unknown length, each -page will be linked together as a linked list. Internally this is implemented via the -`ma_paged_audio_buffer` object. - - -6.2.3. Data Streams -------------------- -Data streams only ever store two pages worth of data for each instance. They are most useful for -large sounds like music tracks in games that would consume too much memory if fully decoded in -memory. After every frame from a page has been read, a job will be posted to load the next page -which is done from the VFS. - -For data streams, the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag will determine whether or -not initialization of the data source waits until the two pages have been decoded. When unset, -`ma_resource_manager_data_source_init()` will wait until the two pages have been loaded, otherwise -it will return immediately. - -When frames are read from a data stream using `ma_resource_manager_data_source_read_pcm_frames()`, -`MA_BUSY` will be returned if there are no frames available. If there are some frames available, -but less than the number requested, `MA_SUCCESS` will be returned, but the actual number of frames -read will be less than the number requested. Due to the asynchronous nature of data streams, -seeking is also asynchronous. If the data stream is in the middle of a seek, `MA_BUSY` will be -returned when trying to read frames. - -When `ma_resource_manager_data_source_read_pcm_frames()` results in a page getting fully consumed -a job is posted to load the next page. This will be posted from the same thread that called -`ma_resource_manager_data_source_read_pcm_frames()`. - -Data streams are uninitialized by posting a job to the queue, but the function won't return until -that job has been processed. The reason for this is that the caller owns the data stream object and -therefore miniaudio needs to ensure everything completes before handing back control to the caller. -Also, if the data stream is uninitialized while pages are in the middle of decoding, they must -complete before destroying any underlying object and the job system handles this cleanly. - -Note that when a new page needs to be loaded, a job will be posted to the resource manager's job -thread from the audio thread. You must keep in mind the details mentioned in the "Job Queue" -section above regarding locking when posting an event if you require a strictly lock-free audio -thread. - - - -7. Node Graph -============= -miniaudio's routing infrastructure follows a node graph paradigm. The idea is that you create a -node whose outputs are attached to inputs of another node, thereby creating a graph. There are -different types of nodes, with each node in the graph processing input data to produce output, -which is then fed through the chain. Each node in the graph can apply their own custom effects. At -the start of the graph will usually be one or more data source nodes which have no inputs and -instead pull their data from a data source. At the end of the graph is an endpoint which represents -the end of the chain and is where the final output is ultimately extracted from. - -Each node has a number of input buses and a number of output buses. An output bus from a node is -attached to an input bus of another. Multiple nodes can connect their output buses to another -node's input bus, in which case their outputs will be mixed before processing by the node. Below is -a diagram that illustrates a hypothetical node graph setup: - - ``` - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Data flows left to right >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - +---------------+ +-----------------+ - | Data Source 1 =----+ +----------+ +----= Low Pass Filter =----+ - +---------------+ | | =----+ +-----------------+ | +----------+ - +----= Splitter | +----= ENDPOINT | - +---------------+ | | =----+ +-----------------+ | +----------+ - | Data Source 2 =----+ +----------+ +----= Echo / Delay =----+ - +---------------+ +-----------------+ - ``` - -In the above graph, it starts with two data sources whose outputs are attached to the input of a -splitter node. It's at this point that the two data sources are mixed. After mixing, the splitter -performs it's processing routine and produces two outputs which is simply a duplication of the -input stream. One output is attached to a low pass filter, whereas the other output is attached to -a echo/delay. The outputs of the low pass filter and the echo are attached to the endpoint, and -since they're both connected to the same input bus, they'll be mixed. - -Each input bus must be configured to accept the same number of channels, but the number of channels -used by input buses can be different to the number of channels for output buses in which case -miniaudio will automatically convert the input data to the output channel count before processing. -The number of channels of an output bus of one node must match the channel count of the input bus -it's attached to. The channel counts cannot be changed after the node has been initialized. If you -attempt to attach an output bus to an input bus with a different channel count, attachment will -fail. - -To use a node graph, you first need to initialize a `ma_node_graph` object. This is essentially a -container around the entire graph. The `ma_node_graph` object is required for some thread-safety -issues which will be explained later. A `ma_node_graph` object is initialized using miniaudio's -standard config/init system: - - ```c - ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(myChannelCount); - - result = ma_node_graph_init(&nodeGraphConfig, NULL, &nodeGraph); // Second parameter is a pointer to allocation callbacks. - if (result != MA_SUCCESS) { - // Failed to initialize node graph. - } - ``` - -When you initialize the node graph, you're specifying the channel count of the endpoint. The -endpoint is a special node which has one input bus and one output bus, both of which have the -same channel count, which is specified in the config. Any nodes that connect directly to the -endpoint must be configured such that their output buses have the same channel count. When you read -audio data from the node graph, it'll have the channel count you specified in the config. To read -data from the graph: - - ```c - ma_uint32 framesRead; - result = ma_node_graph_read_pcm_frames(&nodeGraph, pFramesOut, frameCount, &framesRead); - if (result != MA_SUCCESS) { - // Failed to read data from the node graph. - } - ``` - -When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in -data from its input attachments, which in turn recursively pull in data from their inputs, and so -on. At the start of the graph there will be some kind of data source node which will have zero -inputs and will instead read directly from a data source. The base nodes don't literally need to -read from a `ma_data_source` object, but they will always have some kind of underlying object that -sources some kind of audio. The `ma_data_source_node` node can be used to read from a -`ma_data_source`. Data is always in floating-point format and in the number of channels you -specified when the graph was initialized. The sample rate is defined by the underlying data sources. -It's up to you to ensure they use a consistent and appropriate sample rate. - -The `ma_node` API is designed to allow custom nodes to be implemented with relative ease, but -miniaudio includes a few stock nodes for common functionality. This is how you would initialize a -node which reads directly from a data source (`ma_data_source_node`) which is an example of one -of the stock nodes that comes with miniaudio: - - ```c - ma_data_source_node_config config = ma_data_source_node_config_init(pMyDataSource); - - ma_data_source_node dataSourceNode; - result = ma_data_source_node_init(&nodeGraph, &config, NULL, &dataSourceNode); - if (result != MA_SUCCESS) { - // Failed to create data source node. - } - ``` - -The data source node will use the output channel count to determine the channel count of the output -bus. There will be 1 output bus and 0 input buses (data will be drawn directly from the data -source). The data source must output to floating-point (`ma_format_f32`) or else an error will be -returned from `ma_data_source_node_init()`. - -By default the node will not be attached to the graph. To do so, use `ma_node_attach_output_bus()`: - - ```c - result = ma_node_attach_output_bus(&dataSourceNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); - if (result != MA_SUCCESS) { - // Failed to attach node. - } - ``` - -The code above connects the data source node directly to the endpoint. Since the data source node -has only a single output bus, the index will always be 0. Likewise, the endpoint only has a single -input bus which means the input bus index will also always be 0. - -To detach a specific output bus, use `ma_node_detach_output_bus()`. To detach all output buses, use -`ma_node_detach_all_output_buses()`. If you want to just move the output bus from one attachment to -another, you do not need to detach first. You can just call `ma_node_attach_output_bus()` and it'll -deal with it for you. - -Less frequently you may want to create a specialized node. This will be a node where you implement -your own processing callback to apply a custom effect of some kind. This is similar to initializing -one of the stock node types, only this time you need to specify a pointer to a vtable containing a -pointer to the processing function and the number of input and output buses. Example: - - ```c - static void my_custom_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) - { - // Do some processing of ppFramesIn (one stream of audio data per input bus) - const float* pFramesIn_0 = ppFramesIn[0]; // Input bus @ index 0. - const float* pFramesIn_1 = ppFramesIn[1]; // Input bus @ index 1. - float* pFramesOut_0 = ppFramesOut[0]; // Output bus @ index 0. - - // Do some processing. On input, `pFrameCountIn` will be the number of input frames in each - // buffer in `ppFramesIn` and `pFrameCountOut` will be the capacity of each of the buffers - // in `ppFramesOut`. On output, `pFrameCountIn` should be set to the number of input frames - // your node consumed and `pFrameCountOut` should be set the number of output frames that - // were produced. - // - // You should process as many frames as you can. If your effect consumes input frames at the - // same rate as output frames (always the case, unless you're doing resampling), you need - // only look at `ppFramesOut` and process that exact number of frames. If you're doing - // resampling, you'll need to be sure to set both `pFrameCountIn` and `pFrameCountOut` - // properly. - } - - static ma_node_vtable my_custom_node_vtable = - { - my_custom_node_process_pcm_frames, // The function that will be called to process your custom node. This is where you'd implement your effect processing. - NULL, // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames. - 2, // 2 input buses. - 1, // 1 output bus. - 0 // Default flags. - }; - - ... - - // Each bus needs to have a channel count specified. To do this you need to specify the channel - // counts in an array and then pass that into the node config. - ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable. - ma_uint32 outputChannels[1]; // Equal in size to the number of output channels specified in the vtable. - - inputChannels[0] = channelsIn; - inputChannels[1] = channelsIn; - outputChannels[0] = channelsOut; - - ma_node_config nodeConfig = ma_node_config_init(); - nodeConfig.vtable = &my_custom_node_vtable; - nodeConfig.pInputChannels = inputChannels; - nodeConfig.pOutputChannels = outputChannels; - - ma_node_base node; - result = ma_node_init(&nodeGraph, &nodeConfig, NULL, &node); - if (result != MA_SUCCESS) { - // Failed to initialize node. - } - ``` - -When initializing a custom node, as in the code above, you'll normally just place your vtable in -static space. The number of input and output buses are specified as part of the vtable. If you need -a variable number of buses on a per-node bases, the vtable should have the relevant bus count set -to `MA_NODE_BUS_COUNT_UNKNOWN`. In this case, the bus count should be set in the node config: - - ```c - static ma_node_vtable my_custom_node_vtable = - { - my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing. - NULL, // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames. - MA_NODE_BUS_COUNT_UNKNOWN, // The number of input buses is determined on a per-node basis. - 1, // 1 output bus. - 0 // Default flags. - }; - - ... - - ma_node_config nodeConfig = ma_node_config_init(); - nodeConfig.vtable = &my_custom_node_vtable; - nodeConfig.inputBusCount = myBusCount; // <-- Since the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN, the input bus count should be set here. - nodeConfig.pInputChannels = inputChannels; // <-- Make sure there are nodeConfig.inputBusCount elements in this array. - nodeConfig.pOutputChannels = outputChannels; // <-- The vtable specifies 1 output bus, so there must be 1 element in this array. - ``` - -In the above example it's important to never set the `inputBusCount` and `outputBusCount` members -to anything other than their defaults if the vtable specifies an explicit count. They can only be -set if the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN in the relevant bus count. - -Most often you'll want to create a structure to encapsulate your node with some extra data. You -need to make sure the `ma_node_base` object is your first member of the structure: - - ```c - typedef struct - { - ma_node_base base; // <-- Make sure this is always the first member. - float someCustomData; - } my_custom_node; - ``` - -By doing this, your object will be compatible with all `ma_node` APIs and you can attach it to the -graph just like any other node. - -In the custom processing callback (`my_custom_node_process_pcm_frames()` in the example above), the -number of channels for each bus is what was specified by the config when the node was initialized -with `ma_node_init()`. In addition, all attachments to each of the input buses will have been -pre-mixed by miniaudio. The config allows you to specify different channel counts for each -individual input and output bus. It's up to the effect to handle it appropriate, and if it can't, -return an error in it's initialization routine. - -Custom nodes can be assigned some flags to describe their behaviour. These are set via the vtable -and include the following: - - +-----------------------------------------+---------------------------------------------------+ - | Flag Name | Description | - +-----------------------------------------+---------------------------------------------------+ - | MA_NODE_FLAG_PASSTHROUGH | Useful for nodes that do not do any kind of audio | - | | processing, but are instead used for tracking | - | | time, handling events, etc. Also used by the | - | | internal endpoint node. It reads directly from | - | | the input bus to the output bus. Nodes with this | - | | flag must have exactly 1 input bus and 1 output | - | | bus, and both buses must have the same channel | - | | counts. | - +-----------------------------------------+---------------------------------------------------+ - | MA_NODE_FLAG_CONTINUOUS_PROCESSING | Causes the processing callback to be called even | - | | when no data is available to be read from input | - | | attachments. When a node has at least one input | - | | bus, but there are no inputs attached or the | - | | inputs do not deliver any data, the node's | - | | processing callback will not get fired. This flag | - | | will make it so the callback is always fired | - | | regardless of whether or not any input data is | - | | received. This is useful for effects like | - | | echos where there will be a tail of audio data | - | | that still needs to be processed even when the | - | | original data sources have reached their ends. It | - | | may also be useful for nodes that must always | - | | have their processing callback fired when there | - | | are no inputs attached. | - +-----------------------------------------+---------------------------------------------------+ - | MA_NODE_FLAG_ALLOW_NULL_INPUT | Used in conjunction with | - | | `MA_NODE_FLAG_CONTINUOUS_PROCESSING`. When this | - | | is set, the `ppFramesIn` parameter of the | - | | processing callback will be set to NULL when | - | | there are no input frames are available. When | - | | this is unset, silence will be posted to the | - | | processing callback. | - +-----------------------------------------+---------------------------------------------------+ - | MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES | Used to tell miniaudio that input and output | - | | frames are processed at different rates. You | - | | should set this for any nodes that perform | - | | resampling. | - +-----------------------------------------+---------------------------------------------------+ - | MA_NODE_FLAG_SILENT_OUTPUT | Used to tell miniaudio that a node produces only | - | | silent output. This is useful for nodes where you | - | | don't want the output to contribute to the final | - | | mix. An example might be if you want split your | - | | stream and have one branch be output to a file. | - | | When using this flag, you should avoid writing to | - | | the output buffer of the node's processing | - | | callback because miniaudio will ignore it anyway. | - +-----------------------------------------+---------------------------------------------------+ - - -If you need to make a copy of an audio stream for effect processing you can use a splitter node -called `ma_splitter_node`. This takes has 1 input bus and splits the stream into 2 output buses. -You can use it like this: - - ```c - ma_splitter_node_config splitterNodeConfig = ma_splitter_node_config_init(channels); - - ma_splitter_node splitterNode; - result = ma_splitter_node_init(&nodeGraph, &splitterNodeConfig, NULL, &splitterNode); - if (result != MA_SUCCESS) { - // Failed to create node. - } - - // Attach your output buses to two different input buses (can be on two different nodes). - ma_node_attach_output_bus(&splitterNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); // Attach directly to the endpoint. - ma_node_attach_output_bus(&splitterNode, 1, &myEffectNode, 0); // Attach to input bus 0 of some effect node. - ``` - -The volume of an output bus can be configured on a per-bus basis: - - ```c - ma_node_set_output_bus_volume(&splitterNode, 0, 0.5f); - ma_node_set_output_bus_volume(&splitterNode, 1, 0.5f); - ``` - -In the code above we're using the splitter node from before and changing the volume of each of the -copied streams. - -You can start and stop a node with the following: - - ```c - ma_node_set_state(&splitterNode, ma_node_state_started); // The default state. - ma_node_set_state(&splitterNode, ma_node_state_stopped); - ``` - -By default the node is in a started state, but since it won't be connected to anything won't -actually be invoked by the node graph until it's connected. When you stop a node, data will not be -read from any of its input connections. You can use this property to stop a group of sounds -atomically. - -You can configure the initial state of a node in it's config: - - ```c - nodeConfig.initialState = ma_node_state_stopped; - ``` - -Note that for the stock specialized nodes, all of their configs will have a `nodeConfig` member -which is the config to use with the base node. This is where the initial state can be configured -for specialized nodes: - - ```c - dataSourceNodeConfig.nodeConfig.initialState = ma_node_state_stopped; - ``` - -When using a specialized node like `ma_data_source_node` or `ma_splitter_node`, be sure to not -modify the `vtable` member of the `nodeConfig` object. - - -7.1. Timing ------------ -The node graph supports starting and stopping nodes at scheduled times. This is especially useful -for data source nodes where you want to get the node set up, but only start playback at a specific -time. There are two clocks: local and global. - -A local clock is per-node, whereas the global clock is per graph. Scheduling starts and stops can -only be done based on the global clock because the local clock will not be running while the node -is stopped. The global clocks advances whenever `ma_node_graph_read_pcm_frames()` is called. On the -other hand, the local clock only advances when the node's processing callback is fired, and is -advanced based on the output frame count. - -To retrieve the global time, use `ma_node_graph_get_time()`. The global time can be set with -`ma_node_graph_set_time()` which might be useful if you want to do seeking on a global timeline. -Getting and setting the local time is similar. Use `ma_node_get_time()` to retrieve the local time, -and `ma_node_set_time()` to set the local time. The global and local times will be advanced by the -audio thread, so care should be taken to avoid data races. Ideally you should avoid calling these -outside of the node processing callbacks which are always run on the audio thread. - -There is basic support for scheduling the starting and stopping of nodes. You can only schedule one -start and one stop at a time. This is mainly intended for putting nodes into a started or stopped -state in a frame-exact manner. Without this mechanism, starting and stopping of a node is limited -to the resolution of a call to `ma_node_graph_read_pcm_frames()` which would typically be in blocks -of several milliseconds. The following APIs can be used for scheduling node states: - - ```c - ma_node_set_state_time() - ma_node_get_state_time() - ``` - -The time is absolute and must be based on the global clock. An example is below: - - ```c - ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1); // Delay starting to 1 second. - ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5); // Delay stopping to 5 seconds. - ``` - -An example for changing the state using a relative time. - - ```c - ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1 + ma_node_graph_get_time(&myNodeGraph)); - ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5 + ma_node_graph_get_time(&myNodeGraph)); - ``` - -Note that due to the nature of multi-threading the times may not be 100% exact. If this is an -issue, consider scheduling state changes from within a processing callback. An idea might be to -have some kind of passthrough trigger node that is used specifically for tracking time and handling -events. - - - -7.2. Thread Safety and Locking ------------------------------- -When processing audio, it's ideal not to have any kind of locking in the audio thread. Since it's -expected that `ma_node_graph_read_pcm_frames()` would be run on the audio thread, it does so -without the use of any locks. This section discusses the implementation used by miniaudio and goes -over some of the compromises employed by miniaudio to achieve this goal. Note that the current -implementation may not be ideal - feedback and critiques are most welcome. - -The node graph API is not *entirely* lock-free. Only `ma_node_graph_read_pcm_frames()` is expected -to be lock-free. Attachment, detachment and uninitialization of nodes use locks to simplify the -implementation, but are crafted in a way such that such locking is not required when reading audio -data from the graph. Locking in these areas are achieved by means of spinlocks. - -The main complication with keeping `ma_node_graph_read_pcm_frames()` lock-free stems from the fact -that a node can be uninitialized, and it's memory potentially freed, while in the middle of being -processed on the audio thread. There are times when the audio thread will be referencing a node, -which means the uninitialization process of a node needs to make sure it delays returning until the -audio thread is finished so that control is not handed back to the caller thereby giving them a -chance to free the node's memory. - -When the audio thread is processing a node, it does so by reading from each of the output buses of -the node. In order for a node to process data for one of its output buses, it needs to read from -each of its input buses, and so on an so forth. It follows that once all output buses of a node -are detached, the node as a whole will be disconnected and no further processing will occur unless -it's output buses are reattached, which won't be happening when the node is being uninitialized. -By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can -simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By -doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output -nodes, followed by each of the attachments to each of its input nodes, and then do any final clean -up. - -With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as -it takes to process the output bus being detached. This will happen if it's called at just the -wrong moment where the audio thread has just iterated it and has just started processing. The -caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which -includes the cost of recursively processing its inputs. This is the biggest compromise made with -the approach taken by miniaudio for its lock-free processing system. The cost of detaching nodes -earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching -higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass -detachments, detach starting from the lowest level nodes and work your way towards the final -endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not -running, detachment will be fast and detachment in any order will be the same. The reason nodes -need to wait for their input attachments to complete is due to the potential for desyncs between -data sources. If the node was to terminate processing mid way through processing its inputs, -there's a chance that some of the underlying data sources will have been read, but then others not. -That will then result in a potential desynchronization when detaching and reattaching higher-level -nodes. A possible solution to this is to have an option when detaching to terminate processing -before processing all input attachments which should be fairly simple. - -Another compromise, albeit less significant, is locking when attaching and detaching nodes. This -locking is achieved by means of a spinlock in order to reduce memory overhead. A lock is present -for each input bus and output bus. When an output bus is connected to an input bus, both the output -bus and input bus is locked. This locking is specifically for attaching and detaching across -different threads and does not affect `ma_node_graph_read_pcm_frames()` in any way. The locking and -unlocking is mostly self-explanatory, but a slightly less intuitive aspect comes into it when -considering that iterating over attachments must not break as a result of attaching or detaching a -node while iteration is occurring. - -Attaching and detaching are both quite simple. When an output bus of a node is attached to an input -bus of another node, it's added to a linked list. Basically, an input bus is a linked list, where -each item in the list is and output bus. We have some intentional (and convenient) restrictions on -what can done with the linked list in order to simplify the implementation. First of all, whenever -something needs to iterate over the list, it must do so in a forward direction. Backwards iteration -is not supported. Also, items can only be added to the start of the list. - -The linked list is a doubly-linked list where each item in the list (an output bus) holds a pointer -to the next item in the list, and another to the previous item. A pointer to the previous item is -only required for fast detachment of the node - it is never used in iteration. This is an -important property because it means from the perspective of iteration, attaching and detaching of -an item can be done with a single atomic assignment. This is exploited by both the attachment and -detachment process. When attaching the node, the first thing that is done is the setting of the -local "next" and "previous" pointers of the node. After that, the item is "attached" to the list -by simply performing an atomic exchange with the head pointer. After that, the node is "attached" -to the list from the perspective of iteration. Even though the "previous" pointer of the next item -hasn't yet been set, from the perspective of iteration it's been attached because iteration will -only be happening in a forward direction which means the "previous" pointer won't actually ever get -used. The same general process applies to detachment. See `ma_node_attach_output_bus()` and -`ma_node_detach_output_bus()` for the implementation of this mechanism. - - - -8. Decoding +4. Decoding =========== -The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from -devices and can be used independently. Built-in support is included for the following formats: +The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from devices and can be used independently. The following formats are +supported: - +---------+ - | Format | - +---------+ - | WAV | - | MP3 | - | FLAC | - +---------+ + +---------+------------------+----------+ + | Format | Decoding Backend | Built-In | + +---------+------------------+----------+ + | WAV | dr_wav | Yes | + | MP3 | dr_mp3 | Yes | + | FLAC | dr_flac | Yes | + | Vorbis | stb_vorbis | No | + +---------+------------------+----------+ -You can disable the built-in decoders by specifying one or more of the following options before the -miniaudio implementation: +Vorbis is supported via stb_vorbis which can be enabled by including the header section before the implementation of miniaudio, like the following: + + ```c + #define STB_VORBIS_HEADER_ONLY + #include "extras/stb_vorbis.c" // Enables Vorbis decoding. + + #define MINIAUDIO_IMPLEMENTATION + #include "miniaudio.h" + + // The stb_vorbis implementation must come after the implementation of miniaudio. + #undef STB_VORBIS_HEADER_ONLY + #include "extras/stb_vorbis.c" + ``` + +A copy of stb_vorbis is included in the "extras" folder in the miniaudio repository (https://github.com/mackron/miniaudio). + +Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the built-in decoders by specifying one or more of the +following options before the miniaudio implementation: ```c #define MA_NO_WAV @@ -2520,12 +506,10 @@ miniaudio implementation: #define MA_NO_FLAC ``` -miniaudio supports the ability to plug in custom decoders. See the section below for details on how -to use custom decoders. +Disabling built-in decoding libraries is useful if you use these libraries independantly of the `ma_decoder` API. -A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with -`ma_decoder_init_memory()`, or from data delivered via callbacks with `ma_decoder_init()`. Here is -an example for loading a decoder from a file: +A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with `ma_decoder_init_memory()`, or from data delivered via callbacks +with `ma_decoder_init()`. Here is an example for loading a decoder from a file: ```c ma_decoder decoder; @@ -2539,23 +523,20 @@ an example for loading a decoder from a file: ma_decoder_uninit(&decoder); ``` -When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object -(the `NULL` argument in the example above) which allows you to configure the output format, channel -count, sample rate and channel map: +When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object (the `NULL` argument in the example above) which allows you +to configure the output format, channel count, sample rate and channel map: ```c ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000); ``` -When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the -same as that defined by the decoding backend. +When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the same as that defined by the decoding backend. -Data is read from the decoder as PCM frames. This will output the number of PCM frames actually -read. If this is less than the requested number of PCM frames it means you've reached the end. The -return value will be `MA_AT_END` if no samples have been read and the end has been reached. +Data is read from the decoder as PCM frames. This will return the number of PCM frames actually read. If the return value is less than the requested number of +PCM frames it means you've reached the end: ```c - ma_result result = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead, &framesRead); + ma_uint64 framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead); if (framesRead < framesToRead) { // Reached the end. } @@ -2576,105 +557,37 @@ If you want to loop back to the start, you can simply seek back to the first PCM ma_decoder_seek_to_pcm_frame(pDecoder, 0); ``` -When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding -backend. This can be unnecessarily inefficient if the type is already known. In this case you can -use `encodingFormat` variable in the device config to specify a specific encoding format you want -to decode: +When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type +is already known. In this case you can use the `_wav`, `_mp3`, etc. varients of the aforementioned initialization APIs: ```c - decoderConfig.encodingFormat = ma_encoding_format_wav; + ma_decoder_init_wav() + ma_decoder_init_mp3() + ma_decoder_init_memory_wav() + ma_decoder_init_memory_mp3() + ma_decoder_init_file_wav() + ma_decoder_init_file_mp3() + etc. ``` -See the `ma_encoding_format` enum for possible encoding formats. - -The `ma_decoder_init_file()` API will try using the file extension to determine which decoding -backend to prefer. - - -8.1. Custom Decoders --------------------- -It's possible to implement a custom decoder and plug it into miniaudio. This is extremely useful -when you want to use the `ma_decoder` API, but need to support an encoding format that's not one of -the stock formats supported by miniaudio. This can be put to particularly good use when using the -`ma_engine` and/or `ma_resource_manager` APIs because they use `ma_decoder` internally. If, for -example, you wanted to support Opus, you can do so with a custom decoder (there if a reference -Opus decoder in the "extras" folder of the miniaudio repository which uses libopus + libopusfile). - -A custom decoder must implement a data source. A vtable called `ma_decoding_backend_vtable` needs -to be implemented which is then passed into the decoder config: - - ```c - ma_decoding_backend_vtable* pCustomBackendVTables[] = - { - &g_ma_decoding_backend_vtable_libvorbis, - &g_ma_decoding_backend_vtable_libopus - }; - - ... - - decoderConfig = ma_decoder_config_init_default(); - decoderConfig.pCustomBackendUserData = NULL; - decoderConfig.ppCustomBackendVTables = pCustomBackendVTables; - decoderConfig.customBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); - ``` - -The `ma_decoding_backend_vtable` vtable has the following functions: - - ``` - onInit - onInitFile - onInitFileW - onInitMemory - onUninit - ``` - -There are only two functions that must be implemented - `onInit` and `onUninit`. The other -functions can be implemented for a small optimization for loading from a file path or memory. If -these are not specified, miniaudio will deal with it for you via a generic implementation. - -When you initialize a custom data source (by implementing the `onInit` function in the vtable) you -will need to output a pointer to a `ma_data_source` which implements your custom decoder. See the -section about data sources for details on how to implement this. Alternatively, see the -"custom_decoders" example in the miniaudio repository. - -The `onInit` function takes a pointer to some callbacks for the purpose of reading raw audio data -from some arbitrary source. You'll use these functions to read from the raw data and perform the -decoding. When you call them, you will pass in the `pReadSeekTellUserData` pointer to the relevant -parameter. - -The `pConfig` parameter in `onInit` can be used to configure the backend if appropriate. It's only -used as a hint and can be ignored. However, if any of the properties are relevant to your decoder, -an optimal implementation will handle the relevant properties appropriately. - -If memory allocation is required, it should be done so via the specified allocation callbacks if -possible (the `pAllocationCallbacks` parameter). - -If an error occurs when initializing the decoder, you should leave `ppBackend` unset, or set to -NULL, and make sure everything is cleaned up appropriately and an appropriate result code returned. -When multiple custom backends are specified, miniaudio will cycle through the vtables in the order -they're listed in the array that's passed into the decoder config so it's important that your -initialization routine is clean. - -When a decoder is uninitialized, the `onUninit` callback will be fired which will give you an -opportunity to clean up and internal data. +The `ma_decoder_init_file()` API will try using the file extension to determine which decoding backend to prefer. -9. Encoding +5. Encoding =========== -The `ma_encoding` API is used for writing audio files. The only supported output format is WAV. -This can be disabled by specifying the following option before the implementation of miniaudio: +The `ma_encoding` API is used for writing audio files. The only supported output format is WAV which is achieved via dr_wav which is amalgamated into the +implementation section of miniaudio. This can be disabled by specifying the following option before the implementation of miniaudio: ```c #define MA_NO_WAV ``` -An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data -delivered via callbacks with `ma_encoder_init()`. Below is an example for initializing an encoder -to output to a file. +An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data delivered via callbacks with `ma_encoder_init()`. Below is an +example for initializing an encoder to output to a file. ```c - ma_encoder_config config = ma_encoder_config_init(ma_encoding_format_wav, FORMAT, CHANNELS, SAMPLE_RATE); + ma_encoder_config config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE); ma_encoder encoder; ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder); if (result != MA_SUCCESS) { @@ -2686,54 +599,40 @@ to output to a file. ma_encoder_uninit(&encoder); ``` -When initializing an encoder you must specify a config which is initialized with -`ma_encoder_config_init()`. Here you must specify the file type, the output sample format, output -channel count and output sample rate. The following file types are supported: +When initializing an encoder you must specify a config which is initialized with `ma_encoder_config_init()`. Here you must specify the file type, the output +sample format, output channel count and output sample rate. The following file types are supported: +------------------------+-------------+ | Enum | Description | +------------------------+-------------+ - | ma_encoding_format_wav | WAV | + | ma_resource_format_wav | WAV | +------------------------+-------------+ -If the format, channel count or sample rate is not supported by the output file type an error will -be returned. The encoder will not perform data conversion so you will need to convert it before -outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the -example below: +If the format, channel count or sample rate is not supported by the output file type an error will be returned. The encoder will not perform data conversion so +you will need to convert it before outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the example below: ```c - ma_uint64 framesWritten; - result = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite, &framesWritten); - if (result != MA_SUCCESS) { - ... handle error ... - } + framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite); ``` -The `framesWritten` variable will contain the number of PCM frames that were actually written. This -is optionally and you can pass in `NULL` if you need this. - Encoders must be uninitialized with `ma_encoder_uninit()`. - -10. Data Conversion -=================== -A data conversion API is included with miniaudio which supports the majority of data conversion -requirements. This supports conversion between sample formats, channel counts (with channel -mapping) and sample rates. +6. Data Conversion +================== +A data conversion API is included with miniaudio which supports the majority of data conversion requirements. This supports conversion between sample formats, +channel counts (with channel mapping) and sample rates. -10.1. Sample Format Conversion ------------------------------- -Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and -`ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` to convert between two specific -formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use -`ma_convert_pcm_frames_format()` to convert PCM frames where you want to specify the frame count -and channel count as a variable instead of the total sample count. +6.1. Sample Format Conversion +----------------------------- +Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` +to convert between two specific formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use `ma_convert_pcm_frames_format()` to convert +PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count. -10.1.1. Dithering ------------------ +6.1.1. Dithering +---------------- Dithering can be set using the ditherMode parameter. The different dithering modes include the following, in order of efficiency: @@ -2746,9 +645,8 @@ The different dithering modes include the following, in order of efficiency: | Triangle | ma_dither_mode_triangle | +-----------+--------------------------+ -Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be -ignored for conversions where dithering is not needed. Dithering is available for the following -conversions: +Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be ignored for conversions where dithering is not needed. +Dithering is available for the following conversions: ``` s16 -> u8 @@ -2760,16 +658,14 @@ conversions: f32 -> s16 ``` -Note that it is not an error to pass something other than ma_dither_mode_none for conversions where -dither is not used. It will just be ignored. +Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored. -10.2. Channel Conversion ------------------------- -Channel conversion is used for channel rearrangement and conversion from one channel count to -another. The `ma_channel_converter` API is used for channel conversion. Below is an example of -initializing a simple channel converter which converts from mono to stereo. +6.2. Channel Conversion +----------------------- +Channel conversion is used for channel rearrangement and conversion from one channel count to another. The `ma_channel_converter` API is used for channel +conversion. Below is an example of initializing a simple channel converter which converts from mono to stereo. ```c ma_channel_converter_config config = ma_channel_converter_config_init( @@ -2780,7 +676,7 @@ initializing a simple channel converter which converts from mono to stereo. NULL, // Output channel map ma_channel_mix_mode_default); // The mixing algorithm to use when combining channels. - result = ma_channel_converter_init(&config, NULL, &converter); + result = ma_channel_converter_init(&config, &converter); if (result != MA_SUCCESS) { // Error. } @@ -2795,43 +691,34 @@ To perform the conversion simply call `ma_channel_converter_process_pcm_frames() } ``` -It is up to the caller to ensure the output buffer is large enough to accommodate the new PCM -frames. +It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM frames. Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported. -10.2.1. Channel Mapping ------------------------ -In addition to converting from one channel count to another, like the example above, the channel -converter can also be used to rearrange channels. When initializing the channel converter, you can -optionally pass in channel maps for both the input and output frames. If the channel counts are the -same, and each channel map contains the same channel positions with the exception that they're in -a different order, a simple shuffling of the channels will be performed. If, however, there is not -a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed -based on a mixing mode which is specified when initializing the `ma_channel_converter_config` -object. +6.2.1. Channel Mapping +---------------------- +In addition to converting from one channel count to another, like the example above, the channel converter can also be used to rearrange channels. When +initializing the channel converter, you can optionally pass in channel maps for both the input and output frames. If the channel counts are the same, and each +channel map contains the same channel positions with the exception that they're in a different order, a simple shuffling of the channels will be performed. If, +however, there is not a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed based on a mixing mode which is +specified when initializing the `ma_channel_converter_config` object. -When converting from mono to multi-channel, the mono channel is simply copied to each output -channel. When going the other way around, the audio of each output channel is simply averaged and -copied to the mono channel. +When converting from mono to multi-channel, the mono channel is simply copied to each output channel. When going the other way around, the audio of each output +channel is simply averaged and copied to the mono channel. -In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess -channels and silence extra channels. For example, converting from 4 to 2 channels, the 3rd and 4th -channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and -4th channels. +In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess channels and silence extra channels. For example, converting +from 4 to 2 channels, the 3rd and 4th channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and 4th channels. -The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a -simple distribution between input and output. Imagine sitting in the middle of a room, with -speakers on the walls representing channel positions. The `MA_CHANNEL_FRONT_LEFT` position can be -thought of as being in the corner of the front and left walls. +The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a simple distribution between input and output. Imagine sitting +in the middle of a room, with speakers on the walls representing channel positions. The MA_CHANNEL_FRONT_LEFT position can be thought of as being in the corner +of the front and left walls. -Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined -weights. Custom weights can be passed in as the last parameter of +Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined weights. Custom weights can be passed in as the last parameter of `ma_channel_converter_config_init()`. -Predefined channel maps can be retrieved with `ma_channel_map_init_standard()`. This takes a -`ma_standard_channel_map` enum as its first parameter, which can be one of the following: +Predefined channel maps can be retrieved with `ma_get_standard_channel_map()`. This takes a `ma_standard_channel_map` enum as it's first parameter, which can +be one of the following: +-----------------------------------+-----------------------------------------------------------+ | Name | Description | @@ -2903,10 +790,9 @@ Below are the channel maps used by default in miniaudio (`ma_standard_channel_ma -10.3. Resampling ----------------- -Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something -like the following: +6.3. Resampling +--------------- +Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something like the following: ```c ma_resampler_config config = ma_resampler_config_init( @@ -2917,7 +803,7 @@ like the following: ma_resample_algorithm_linear); ma_resampler resampler; - ma_result result = ma_resampler_init(&config, NULL, &resampler); + ma_result result = ma_resampler_init(&config, &resampler); if (result != MA_SUCCESS) { // An error occurred... } @@ -2943,128 +829,104 @@ The following example shows how data can be processed // number of output frames written. ``` -To initialize the resampler you first need to set up a config (`ma_resampler_config`) with -`ma_resampler_config_init()`. You need to specify the sample format you want to use, the number of -channels, the input and output sample rate, and the algorithm. +To initialize the resampler you first need to set up a config (`ma_resampler_config`) with `ma_resampler_config_init()`. You need to specify the sample format +you want to use, the number of channels, the input and output sample rate, and the algorithm. -The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format -you will need to perform pre- and post-conversions yourself where necessary. Note that the format -is the same for both input and output. The format cannot be changed after initialization. +The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format you will need to perform pre- and post-conversions yourself +where necessary. Note that the format is the same for both input and output. The format cannot be changed after initialization. -The resampler supports multiple channels and is always interleaved (both input and output). The -channel count cannot be changed after initialization. +The resampler supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization. -The sample rates can be anything other than zero, and are always specified in hertz. They should be -set to something like 44100, etc. The sample rate is the only configuration property that can be -changed after initialization. +The sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the +only configuration property that can be changed after initialization. -The miniaudio resampler has built-in support for the following algorithms: +The miniaudio resampler supports multiple algorithms: +-----------+------------------------------+ | Algorithm | Enum Token | +-----------+------------------------------+ | Linear | ma_resample_algorithm_linear | - | Custom | ma_resample_algorithm_custom | + | Speex | ma_resample_algorithm_speex | +-----------+------------------------------+ +Because Speex is not public domain it is strictly opt-in and the code is stored in separate files. if you opt-in to the Speex backend you will need to consider +it's license, the text of which can be found in it's source files in "extras/speex_resampler". Details on how to opt-in to the Speex resampler is explained in +the Speex Resampler section below. + The algorithm cannot be changed after initialization. -Processing always happens on a per PCM frame basis and always assumes interleaved input and output. -De-interleaved processing is not supported. To process frames, use -`ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you -can fit in the output buffer and the number of input frames contained in the input buffer. On -output these variables contain the number of output frames that were written to the output buffer -and the number of input frames that were consumed in the process. You can pass in NULL for the -input buffer in which case it will be treated as an infinitely large buffer of zeros. The output -buffer can also be NULL, in which case the processing will be treated as seek. +Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process +frames, use `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number of +input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the +number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large +buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek. -The sample rate can be changed dynamically on the fly. You can change this with explicit sample -rates with `ma_resampler_set_rate()` and also with a decimal ratio with -`ma_resampler_set_rate_ratio()`. The ratio is in/out. +The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with `ma_resampler_set_rate()` and also with a decimal +ratio with `ma_resampler_set_rate_ratio()`. The ratio is in/out. -Sometimes it's useful to know exactly how many input frames will be required to output a specific -number of frames. You can calculate this with `ma_resampler_get_required_input_frame_count()`. -Likewise, it's sometimes useful to know exactly how many frames would be output given a certain -number of input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`. +Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with +`ma_resampler_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of +input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`. -Due to the nature of how resampling works, the resampler introduces some latency. This can be -retrieved in terms of both the input rate and the output rate with -`ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`. +Due to the nature of how resampling works, the resampler introduces some latency. This can be retrieved in terms of both the input rate and the output rate +with `ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`. -10.3.1. Resampling Algorithms ------------------------------ -The choice of resampling algorithm depends on your situation and requirements. +6.3.1. Resampling Algorithms +---------------------------- +The choice of resampling algorithm depends on your situation and requirements. The linear resampler is the most efficient and has the least amount of latency, +but at the expense of poorer quality. The Speex resampler is higher quality, but slower with more latency. It also performs several heap allocations internally +for memory management. -10.3.1.1. Linear Resampling ---------------------------- -The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, -some control over the quality of the linear resampler which may make it a suitable option depending -on your requirements. +6.3.1.1. Linear Resampling +-------------------------- +The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, some control over the quality of the linear resampler which +may make it a suitable option depending on your requirements. -The linear resampler performs low-pass filtering before or after downsampling or upsampling, -depending on the sample rates you're converting between. When decreasing the sample rate, the -low-pass filter will be applied before downsampling. When increasing the rate it will be performed -after upsampling. By default a fourth order low-pass filter will be applied. This can be configured -via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. +The linear resampler performs low-pass filtering before or after downsampling or upsampling, depending on the sample rates you're converting between. When +decreasing the sample rate, the low-pass filter will be applied before downsampling. When increasing the rate it will be performed after upsampling. By default +a fourth order low-pass filter will be applied. This can be configured via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. -The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of -the input and output sample rates (Nyquist Frequency). +The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of the input and output sample rates (Nyquist Frequency). This +can be controlled with the `lpfNyquistFactor` config variable. This defaults to 1, and should be in the range of 0..1, although a value of 0 does not make +sense and should be avoided. A value of 1 will use the Nyquist Frequency as the cutoff. A value of 0.5 will use half the Nyquist Frequency as the cutoff, etc. +Values less than 1 will result in more washed out sound due to more of the higher frequencies being removed. This config variable has no impact on performance +and is a purely perceptual configuration. -The API for the linear resampler is the same as the main resampler API, only it's called -`ma_linear_resampler`. +The API for the linear resampler is the same as the main resampler API, only it's called `ma_linear_resampler`. -10.3.2. Custom Resamplers +6.3.1.2. Speex Resampling ------------------------- -You can implement a custom resampler by using the `ma_resample_algorithm_custom` resampling -algorithm and setting a vtable in the resampler config: +The Speex resampler is made up of third party code which is released under the BSD license. Because it is licensed differently to miniaudio, which is public +domain, it is strictly opt-in and all of it's code is stored in separate files. If you opt-in to the Speex resampler you must consider the license text in it's +source files. To opt-in, you must first `#include` the following file before the implementation of miniaudio.h: ```c - ma_resampler_config config = ma_resampler_config_init(..., ma_resample_algorithm_custom); - config.pBackendVTable = &g_customResamplerVTable; + #include "extras/speex_resampler/ma_speex_resampler.h" ``` -Custom resamplers are useful if the stock algorithms are not appropriate for your use case. You -need to implement the required functions in `ma_resampling_backend_vtable`. Note that not all -functions in the vtable need to be implemented, but if it's possible to implement, they should be. +Both the header and implementation is contained within the same file. The implementation can be included in your program like so: -You can use the `ma_linear_resampler` object for an example on how to implement the vtable. The -`onGetHeapSize` callback is used to calculate the size of any internal heap allocation the custom -resampler will need to make given the supplied config. When you initialize the resampler via the -`onInit` callback, you'll be given a pointer to a heap allocation which is where you should store -the heap allocated data. You should not free this data in `onUninit` because miniaudio will manage -it for you. + ```c + #define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION + #include "extras/speex_resampler/ma_speex_resampler.h" + ``` -The `onProcess` callback is where the actual resampling takes place. On input, `pFrameCountIn` -points to a variable containing the number of frames in the `pFramesIn` buffer and -`pFrameCountOut` points to a variable containing the capacity in frames of the `pFramesOut` buffer. -On output, `pFrameCountIn` should be set to the number of input frames that were fully consumed, -whereas `pFrameCountOut` should be set to the number of frames that were written to `pFramesOut`. +Note that even if you opt-in to the Speex backend, miniaudio won't use it unless you explicitly ask for it in the respective config of the object you are +initializing. If you try to use the Speex resampler without opting in, initialization of the `ma_resampler` object will fail with `MA_NO_BACKEND`. -The `onSetRate` callback is optional and is used for dynamically changing the sample rate. If -dynamic rate changes are not supported, you can set this callback to NULL. - -The `onGetInputLatency` and `onGetOutputLatency` functions are used for retrieving the latency in -input and output rates respectively. These can be NULL in which case latency calculations will be -assumed to be NULL. - -The `onGetRequiredInputFrameCount` callback is used to give miniaudio a hint as to how many input -frames are required to be available to produce the given number of output frames. Likewise, the -`onGetExpectedOutputFrameCount` callback is used to determine how many output frames will be -produced given the specified number of input frames. miniaudio will use these as a hint, but they -are optional and can be set to NULL if you're unable to implement them. +The only configuration option to consider with the Speex resampler is the `speex.quality` config variable. This is a value between 0 and 10, with 0 being +the fastest with the poorest quality and 10 being the slowest with the highest quality. The default value is 3. -10.4. General Data Conversion ------------------------------ -The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and -resampling into one operation. This is what miniaudio uses internally to convert between the format -requested when the device was initialized and the format of the backend's native device. The API -for general data conversion is very similar to the resampling API. Create a `ma_data_converter` -object like this: +6.4. General Data Conversion +---------------------------- +The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and resampling into one operation. This is what miniaudio uses +internally to convert between the format requested when the device was initialized and the format of the backend's native device. The API for general data +conversion is very similar to the resampling API. Create a `ma_data_converter` object like this: ```c ma_data_converter_config config = ma_data_converter_config_init( @@ -3077,15 +939,14 @@ object like this: ); ma_data_converter converter; - ma_result result = ma_data_converter_init(&config, NULL, &converter); + ma_result result = ma_data_converter_init(&config, &converter); if (result != MA_SUCCESS) { // An error occurred... } ``` -In the example above we use `ma_data_converter_config_init()` to initialize the config, however -there's many more properties that can be configured, such as channel maps and resampling quality. -Something like the following may be more suitable depending on your requirements: +In the example above we use `ma_data_converter_config_init()` to initialize the config, however there's many more properties that can be configured, such as +channel maps and resampling quality. Something like the following may be more suitable depending on your requirements: ```c ma_data_converter_config config = ma_data_converter_config_init_default(); @@ -3095,14 +956,14 @@ Something like the following may be more suitable depending on your requirements config.channelsOut = outputChannels; config.sampleRateIn = inputSampleRate; config.sampleRateOut = outputSampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_flac, config.channelMapIn, sizeof(config.channelMapIn)/sizeof(config.channelMapIn[0]), config.channelCountIn); + ma_get_standard_channel_map(ma_standard_channel_map_flac, config.channelCountIn, config.channelMapIn); config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER; ``` Do the following to uninitialize the data converter: ```c - ma_data_converter_uninit(&converter, NULL); + ma_data_converter_uninit(&converter); ``` The following example shows how data can be processed @@ -3119,47 +980,38 @@ The following example shows how data can be processed // of output frames written. ``` -The data converter supports multiple channels and is always interleaved (both input and output). -The channel count cannot be changed after initialization. +The data converter supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization. -Sample rates can be anything other than zero, and are always specified in hertz. They should be set -to something like 44100, etc. The sample rate is the only configuration property that can be -changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of -`ma_data_converter_config` is set to `MA_TRUE`. To change the sample rate, use -`ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. -The resampling algorithm cannot be changed after initialization. +Sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the only +configuration property that can be changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of `ma_data_converter_config` is +set to `MA_TRUE`. To change the sample rate, use `ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. The +resampling algorithm cannot be changed after initialization. -Processing always happens on a per PCM frame basis and always assumes interleaved input and output. -De-interleaved processing is not supported. To process frames, use -`ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames -you can fit in the output buffer and the number of input frames contained in the input buffer. On -output these variables contain the number of output frames that were written to the output buffer -and the number of input frames that were consumed in the process. You can pass in NULL for the -input buffer in which case it will be treated as an infinitely large -buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated -as seek. +Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process +frames, use `ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number +of input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the +number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large +buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek. -Sometimes it's useful to know exactly how many input frames will be required to output a specific -number of frames. You can calculate this with `ma_data_converter_get_required_input_frame_count()`. -Likewise, it's sometimes useful to know exactly how many frames would be output given a certain -number of input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`. +Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with +`ma_data_converter_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of +input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`. -Due to the nature of how resampling works, the data converter introduces some latency if resampling -is required. This can be retrieved in terms of both the input rate and the output rate with -`ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`. +Due to the nature of how resampling works, the data converter introduces some latency if resampling is required. This can be retrieved in terms of both the +input rate and the output rate with `ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`. -11. Filtering -============= +7. Filtering +============ -11.1. Biquad Filtering ----------------------- +7.1. Biquad Filtering +--------------------- Biquad filtering is achieved with the `ma_biquad` API. Example: ```c ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2); - ma_result result = ma_biquad_init(&config, NULL, &biquad); + ma_result result = ma_biquad_init(&config, &biquad); if (result != MA_SUCCESS) { // Error. } @@ -3169,33 +1021,28 @@ Biquad filtering is achieved with the `ma_biquad` API. Example: ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount); ``` -Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, -b1 and b2, and the denominator coefficients are a0, a1 and a2. The a0 coefficient is required and -coefficients must not be pre-normalized. +Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, b1 and b2, and the denominator coefficients are a0, a1 and +a2. The a0 coefficient is required and coefficients must not be pre-normalized. -Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format -you need to convert it yourself beforehand. When using `ma_format_s16` the biquad filter will use -fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used. +Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. When using +`ma_format_s16` the biquad filter will use fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used. Input and output frames are always interleaved. -Filtering can be applied in-place by passing in the same pointer for both the input and output -buffers, like so: +Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so: ```c ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount); ``` -If you need to change the values of the coefficients, but maintain the values in the registers you -can do so with `ma_biquad_reinit()`. This is useful if you need to change the properties of the -filter while keeping the values of registers valid to avoid glitching. Do not use -`ma_biquad_init()` for this as it will do a full initialization which involves clearing the -registers to 0. Note that changing the format or channel count after initialization is invalid and -will result in an error. +If you need to change the values of the coefficients, but maintain the values in the registers you can do so with `ma_biquad_reinit()`. This is useful if you +need to change the properties of the filter while keeping the values of registers valid to avoid glitching. Do not use `ma_biquad_init()` for this as it will +do a full initialization which involves clearing the registers to 0. Note that changing the format or channel count after initialization is invalid and will +result in an error. -11.2. Low-Pass Filtering ------------------------- +7.2. Low-Pass Filtering +----------------------- Low-pass filtering is achieved with the following APIs: +---------+------------------------------------------+ @@ -3220,18 +1067,16 @@ Low-pass filter example: ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount); ``` -Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format -you need to convert it yourself beforehand. Input and output frames are always interleaved. +Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. Input and output +frames are always interleaved. -Filtering can be applied in-place by passing in the same pointer for both the input and output -buffers, like so: +Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so: ```c ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount); ``` -The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, -you can chain first and second order filters together. +The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, you can chain first and second order filters together. ```c for (iFilter = 0; iFilter < filterCount; iFilter += 1) { @@ -3239,22 +1084,19 @@ you can chain first and second order filters together. } ``` -If you need to change the configuration of the filter, but need to maintain the state of internal -registers you can do so with `ma_lpf_reinit()`. This may be useful if you need to change the sample -rate and/or cutoff frequency dynamically while maintaining smooth transitions. Note that changing the -format or channel count after initialization is invalid and will result in an error. +If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be +useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel +count after initialization is invalid and will result in an error. -The `ma_lpf` object supports a configurable order, but if you only need a first order filter you -may want to consider using `ma_lpf1`. Likewise, if you only need a second order filter you can use -`ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient. +The `ma_lpf` object supports a configurable order, but if you only need a first order filter you may want to consider using `ma_lpf1`. Likewise, if you only +need a second order filter you can use `ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient. -If an even filter order is specified, a series of second order filters will be processed in a -chain. If an odd filter order is specified, a first order filter will be applied, followed by a -series of second order filters in a chain. +If an even filter order is specified, a series of second order filters will be processed in a chain. If an odd filter order is specified, a first order filter +will be applied, followed by a series of second order filters in a chain. -11.3. High-Pass Filtering -------------------------- +7.3. High-Pass Filtering +------------------------ High-pass filtering is achieved with the following APIs: +---------+-------------------------------------------+ @@ -3265,12 +1107,12 @@ High-pass filtering is achieved with the following APIs: | ma_hpf | High order high-pass filter (Butterworth) | +---------+-------------------------------------------+ -High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, -`ma_hpf2` and `ma_hpf`. See example code for low-pass filters for example usage. +High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, `ma_hpf2` and `ma_hpf`. See example code for low-pass filters +for example usage. -11.4. Band-Pass Filtering -------------------------- +7.4. Band-Pass Filtering +------------------------ Band-pass filtering is achieved with the following APIs: +---------+-------------------------------+ @@ -3280,14 +1122,13 @@ Band-pass filtering is achieved with the following APIs: | ma_bpf | High order band-pass filter | +---------+-------------------------------+ -Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and -`ma_hpf`. See example code for low-pass filters for example usage. Note that the order for -band-pass filters must be an even number which means there is no first order band-pass filter, -unlike low-pass and high-pass filters. +Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and `ma_hpf`. See example code for low-pass filters for example +usage. Note that the order for band-pass filters must be an even number which means there is no first order band-pass filter, unlike low-pass and high-pass +filters. -11.5. Notch Filtering ---------------------- +7.5. Notch Filtering +-------------------- Notch filtering is achieved with the following APIs: +-----------+------------------------------------------+ @@ -3297,7 +1138,7 @@ Notch filtering is achieved with the following APIs: +-----------+------------------------------------------+ -11.6. Peaking EQ Filtering +7.6. Peaking EQ Filtering ------------------------- Peaking filtering is achieved with the following APIs: @@ -3308,8 +1149,8 @@ Peaking filtering is achieved with the following APIs: +----------+------------------------------------------+ -11.7. Low Shelf Filtering -------------------------- +7.7. Low Shelf Filtering +------------------------ Low shelf filtering is achieved with the following APIs: +-------------+------------------------------------------+ @@ -3318,12 +1159,11 @@ Low shelf filtering is achieved with the following APIs: | ma_loshelf2 | Second order low shelf filter | +-------------+------------------------------------------+ -Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to -just turn them down rather than eliminate them entirely. +Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to just turn them down rather than eliminate them entirely. -11.8. High Shelf Filtering --------------------------- +7.8. High Shelf Filtering +------------------------- High shelf filtering is achieved with the following APIs: +-------------+------------------------------------------+ @@ -3332,20 +1172,18 @@ High shelf filtering is achieved with the following APIs: | ma_hishelf2 | Second order high shelf filter | +-------------+------------------------------------------+ -The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` -instead of `ma_loshelf`. Where a low shelf filter is used to adjust the volume of low frequencies, -the high shelf filter does the same thing for high frequencies. +The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` instead of `ma_loshelf`. Where a low shelf filter is used to +adjust the volume of low frequencies, the high shelf filter does the same thing for high frequencies. -12. Waveform and Noise Generation -================================= +8. Waveform and Noise Generation +================================ -12.1. Waveforms ---------------- -miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved -with the `ma_waveform` API. Example: +8.1. Waveforms +-------------- +miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the `ma_waveform` API. Example: ```c ma_waveform_config config = ma_waveform_config_init( @@ -3367,12 +1205,11 @@ with the `ma_waveform` API. Example: ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount); ``` -The amplitude, frequency, type, and sample rate can be changed dynamically with -`ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, `ma_waveform_set_type()`, and -`ma_waveform_set_sample_rate()` respectively. +The amplitude, frequency, type, and sample rate can be changed dynamically with `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, +`ma_waveform_set_type()`, and `ma_waveform_set_sample_rate()` respectively. -You can invert the waveform by setting the amplitude to a negative value. You can use this to -control whether or not a sawtooth has a positive or negative ramp, for example. +You can invert the waveform by setting the amplitude to a negative value. You can use this to control whether or not a sawtooth has a positive or negative +ramp, for example. Below are the supported waveform types: @@ -3387,8 +1224,8 @@ Below are the supported waveform types: -12.2. Noise ------------ +8.2. Noise +---------- miniaudio supports generation of white, pink and Brownian noise via the `ma_noise` API. Example: ```c @@ -3410,16 +1247,13 @@ miniaudio supports generation of white, pink and Brownian noise via the `ma_nois ma_noise_read_pcm_frames(&noise, pOutput, frameCount); ``` -The noise API uses simple LCG random number generation. It supports a custom seed which is useful -for things like automated testing requiring reproducibility. Setting the seed to zero will default -to `MA_DEFAULT_LCG_SEED`. +The noise API uses simple LCG random number generation. It supports a custom seed which is useful for things like automated testing requiring reproducibility. +Setting the seed to zero will default to `MA_DEFAULT_LCG_SEED`. -The amplitude and seed can be changed dynamically with `ma_noise_set_amplitude()` and -`ma_noise_set_seed()` respectively. +The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, `ma_noise_set_seed()`, and `ma_noise_set_type()` respectively. -By default, the noise API will use different values for different channels. So, for example, the -left side in a stereo stream will be different to the right side. To instead have each channel use -the same random value, set the `duplicateChannels` member of the noise config to true, like so: +By default, the noise API will use different values for different channels. So, for example, the left side in a stereo stream will be different to the right +side. To instead have each channel use the same random value, set the `duplicateChannels` member of the noise config to true, like so: ```c config.duplicateChannels = MA_TRUE; @@ -3437,13 +1271,12 @@ Below are the supported noise types. -13. Audio Buffers -================= -miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can -read from memory that's managed by the application, but can also handle the memory management for -you internally. Memory management is flexible and should support most use cases. +9. Audio Buffers +================ +miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can read from memory that's managed by the application, but +can also handle the memory management for you internally. Memory management is flexible and should support most use cases. -Audio buffers are initialized using the standard configuration system used everywhere in miniaudio: +Audio buffers are initialised using the standard configuration system used everywhere in miniaudio: ```c ma_audio_buffer_config config = ma_audio_buffer_config_init( @@ -3464,14 +1297,11 @@ Audio buffers are initialized using the standard configuration system used every ma_audio_buffer_uninit(&buffer); ``` -In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an -application can do self-managed memory allocation. If you would rather make a copy of the data, use -`ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`. +In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an application can do self-managed memory allocation. If you +would rather make a copy of the data, use `ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`. -Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the -raw audio data in a contiguous block of memory. That is, the raw audio data will be located -immediately after the `ma_audio_buffer` structure. To do this, use -`ma_audio_buffer_alloc_and_init()`: +Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the raw audio data in a contiguous block of memory. That is, +the raw audio data will be located immediately after the `ma_audio_buffer` structure. To do this, use `ma_audio_buffer_alloc_and_init()`: ```c ma_audio_buffer_config config = ma_audio_buffer_config_init( @@ -3492,18 +1322,13 @@ immediately after the `ma_audio_buffer` structure. To do this, use ma_audio_buffer_uninit_and_free(&buffer); ``` -If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it -with `ma_audio_buffer_uninit_and_free()`. In the example above, the memory pointed to by -`pExistingData` will be copied into the buffer, which is contrary to the behavior of -`ma_audio_buffer_init()`. +If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it with `ma_audio_buffer_uninit_and_free()`. In the example above, +the memory pointed to by `pExistingData` will be copied into the buffer, which is contrary to the behavior of `ma_audio_buffer_init()`. -An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the -cursor moves forward. The last parameter (`loop`) can be used to determine if the buffer should -loop. The return value is the number of frames actually read. If this is less than the number of -frames requested it means the end has been reached. This should never happen if the `loop` -parameter is set to true. If you want to manually loop back to the start, you can do so with with -`ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an -audio buffer. +An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the cursor moves forward. The last parameter (`loop`) can be +used to determine if the buffer should loop. The return value is the number of frames actually read. If this is less than the number of frames requested it +means the end has been reached. This should never happen if the `loop` parameter is set to true. If you want to manually loop back to the start, you can do so +with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an audio buffer. ```c ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping); @@ -3512,8 +1337,8 @@ audio buffer. } ``` -Sometimes you may want to avoid the cost of data movement between the internal buffer and the -output buffer. Instead you can use memory mapping to retrieve a pointer to a segment of data: +Sometimes you may want to avoid the cost of data movement between the internal buffer and the output buffer. Instead you can use memory mapping to retrieve a +pointer to a segment of data: ```c void* pMappedFrames; @@ -3529,30 +1354,23 @@ output buffer. Instead you can use memory mapping to retrieve a pointer to a seg } ``` -When you use memory mapping, the read cursor is increment by the frame count passed in to -`ma_audio_buffer_unmap()`. If you decide not to process every frame you can pass in a value smaller -than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is -that it does not handle looping for you. You can determine if the buffer is at the end for the -purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of -`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` -as an error when returned by `ma_audio_buffer_unmap()`. +When you use memory mapping, the read cursor is increment by the frame count passed in to `ma_audio_buffer_unmap()`. If you decide not to process every frame +you can pass in a value smaller than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is that it does not handle looping +for you. You can determine if the buffer is at the end for the purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of +`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` as an error when returned by `ma_audio_buffer_unmap()`. -14. Ring Buffers +10. Ring Buffers ================ -miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via -the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates on bytes, whereas the `ma_pcm_rb` -operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around -`ma_rb`. +miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates +on bytes, whereas the `ma_pcm_rb` operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around `ma_rb`. -Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved -streams. The caller can also allocate their own backing memory for the ring buffer to use -internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for -you. +Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for +the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for you. -The examples below use the PCM frame variant of the ring buffer since that's most likely the one -you will want to use. To initialize a ring buffer, do something like the following: +The examples below use the PCM frame variant of the ring buffer since that's most likely the one you will want to use. To initialize a ring buffer, do +something like the following: ```c ma_pcm_rb rb; @@ -3562,74 +1380,55 @@ you will want to use. To initialize a ring buffer, do something like the followi } ``` -The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because -it's the PCM variant of the ring buffer API. For the regular ring buffer that operates on bytes you -would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes -instead of frames. The fourth parameter is an optional pre-allocated buffer and the fifth parameter -is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation routines. -Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used. +The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because it's the PCM varient of the ring buffer API. For the regular +ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The +fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation +routines. Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used. -Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is -offset from each other based on the stride. To manage your sub-buffers you can use -`ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and -`ma_pcm_rb_get_subbuffer_ptr()`. +Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your +sub-buffers you can use `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and `ma_pcm_rb_get_subbuffer_ptr()`. -Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section -of the ring buffer. You specify the number of frames you need, and on output it will set to what -was actually acquired. If the read or write pointer is positioned such that the number of frames -requested will require a loop, it will be clamped to the end of the buffer. Therefore, the number -of frames you're given may be less than the number you requested. +Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you +need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require +a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested. -After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the -buffer and then "commit" it with `ma_pcm_rb_commit_read()` or `ma_pcm_rb_commit_write()`. This is -where the read/write pointers are updated. When you commit you need to pass in the buffer that was -returned by the earlier call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is -only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and -`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was -originally requested. +After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or +`ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier +call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and +`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was originally requested. -If you want to correct for drift between the write pointer and the read pointer you can use a -combination of `ma_pcm_rb_pointer_distance()`, `ma_pcm_rb_seek_read()` and -`ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only -move the read pointer forward via the consumer thread, and the write pointer forward by the -producer thread. If there is too much space between the pointers, move the read pointer forward. If +If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`, +`ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via +the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If there is too little space between the pointers, move the write pointer forward. -You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` -API. This is exactly the same, only you will use the `ma_rb` functions instead of `ma_pcm_rb` and -instead of frame counts you will pass around byte counts. +You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the same, only you will use the `ma_rb` +functions instead of `ma_pcm_rb` and instead of frame counts you will pass around byte counts. -The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most -significant bit being used to encode a loop flag and the internally managed buffers always being -aligned to `MA_SIMD_ALIGNMENT`. +The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most significant bit being used to encode a loop flag and the internally +managed buffers always being aligned to MA_SIMD_ALIGNMENT. -Note that the ring buffer is only thread safe when used by a single consumer thread and single -producer thread. +Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread. -15. Backends +11. Backends ============ -The following backends are supported by miniaudio. These are listed in order of default priority. -When no backend is specified when initializing a context or device, miniaudio will attempt to use -each of these backends in the order listed in the table below. - -Note that backends that are not usable by the build target will not be included in the build. For -example, ALSA, which is specific to Linux, will not be included in the Windows build. +The following backends are supported by miniaudio. +-------------+-----------------------+--------------------------------------------------------+ | Name | Enum Name | Supported Operating Systems | +-------------+-----------------------+--------------------------------------------------------+ | WASAPI | ma_backend_wasapi | Windows Vista+ | | DirectSound | ma_backend_dsound | Windows XP+ | - | WinMM | ma_backend_winmm | Windows 95+ | + | WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) | | Core Audio | ma_backend_coreaudio | macOS, iOS | + | ALSA | ma_backend_alsa | Linux | + | PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) | + | JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) | | sndio | ma_backend_sndio | OpenBSD | | audio(4) | ma_backend_audio4 | NetBSD, OpenBSD | | OSS | ma_backend_oss | FreeBSD | - | PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) | - | ALSA | ma_backend_alsa | Linux | - | JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) | | AAudio | ma_backend_aaudio | Android 8+ | | OpenSL ES | ma_backend_opensl | Android (API level 16+) | | Web Audio | ma_backend_webaudio | Web (via Emscripten) | @@ -3639,42 +1438,28 @@ example, ALSA, which is specific to Linux, will not be included in the Windows b Some backends have some nuance details you may want to be aware of. -15.1. WASAPI +11.1. WASAPI ------------ -- Low-latency shared mode will be disabled when using an application-defined sample rate which is - different to the device's native sample rate. To work around this, set `wasapi.noAutoConvertSRC` - to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing - when the `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC - will result in miniaudio's internal resampler being used instead which will in turn enable the - use of low-latency shared mode. +- Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device's native sample rate. To work around + this, set `wasapi.noAutoConvertSRC` to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the + `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio's internal resampler being used instead + which will in turn enable the use of low-latency shared mode. -15.2. PulseAudio +11.2. PulseAudio ---------------- - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki: - https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. - Alternatively, consider using a different backend such as ALSA. + https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. Alternatively, consider using a different backend such as ALSA. -15.3. Android +11.3. Android ------------- -- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: - `` -- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a - limitation with OpenSL|ES. -- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration - API (devices are enumerated through Java). You can however perform your own device enumeration - through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it - to ma_device_init(). -- The backend API will perform resampling where possible. The reason for this as opposed to using - miniaudio's built-in resampler is to take advantage of any potential device-specific - optimizations the driver may implement. +- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: `` +- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES. +- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however + perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init(). +- The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any + potential device-specific optimizations the driver may implement. -BSD ---- -- The sndio backend is currently only enabled on OpenBSD builds. -- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can - use it. - -15.4. UWP +11.4. UWP --------- - UWP only supports default playback and capture devices. - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): @@ -3688,54 +1473,29 @@ BSD
``` -15.5. Web Audio / Emscripten +11.5. Web Audio / Emscripten ---------------------------- - You cannot use `-std=c*` compiler flags, nor `-ansi`. This only applies to the Emscripten build. -- The first time a context is initialized it will create a global object called "miniaudio" whose - primary purpose is to act as a factory for device objects. -- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as - they've been deprecated. -- Google has implemented a policy in their browsers that prevent automatic media output without - first receiving some kind of user input. The following web page has additional details: - https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device - may fail if you try to start playback without first handling some kind of user input. +- The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects. +- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated. +- Google has implemented a policy in their browsers that prevent automatic media output without first receiving some kind of user input. The following web page + has additional details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback + without first handling some kind of user input. -16. Optimization Tips -===================== -See below for some tips on improving performance. - -16.1. Low Level API -------------------- -- In the data callback, if your data is already clipped prior to copying it into the output buffer, - set the `noClip` config option in the device config to true. This will disable miniaudio's built - in clipping function. -- By default, miniaudio will pre-silence the data callback's output buffer. If you know that you - will always write valid data to the output buffer you can disable pre-silencing by setting the - `noPreSilence` config option in the device config to true. - -16.2. High Level API --------------------- -- If a sound does not require doppler or pitch shifting, consider disabling pitching by - initializing the sound with the `MA_SOUND_FLAG_NO_PITCH` flag. -- If a sound does not require spatialization, disable it by initializing the sound with the - `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. It can be re-enabled again post-initialization with - `ma_sound_set_spatialization_enabled()`. -- If you know all of your sounds will always be the same sample rate, set the engine's sample - rate to match that of the sounds. Likewise, if you're using a self-managed resource manager, - consider setting the decoded sample rate to match your sounds. By configuring everything to - use a consistent sample rate, sample rate conversion can be avoided. - - - -17. Miscellaneous Notes +12. Miscellaneous Notes ======================= -- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for - WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though - not all have been tested. -- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This - is due to 64-bit file APIs not being available. +- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as + PulseAudio may naturally support it, though not all have been tested. +- The contents of the output buffer passed into the data callback will always be pre-initialized to silence unless the `noPreZeroedOutputBuffer` config variable + in `ma_device_config` is set to true, in which case it'll be undefined which will require you to write something to the entire buffer. +- By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as `ma_format_f32`. If you are doing + clipping yourself, you can disable this overhead by setting `noClip` to true in the device config. +- The sndio backend is currently only enabled on OpenBSD builds. +- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it. +- Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations. +- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available. */ #ifndef miniaudio_h @@ -3749,8 +1509,8 @@ extern "C" { #define MA_XSTRINGIFY(x) MA_STRINGIFY(x) #define MA_VERSION_MAJOR 0 -#define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 22 +#define MA_VERSION_MINOR 10 +#define MA_VERSION_REVISION 33 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -3766,53 +1526,65 @@ extern "C" { #endif #endif - -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) || defined(__ppc64__) - #define MA_SIZEOF_PTR 8 +/* Platform/backend detection. */ +#ifdef _WIN32 + #define MA_WIN32 + #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + #define MA_WIN32_UWP + #else + #define MA_WIN32_DESKTOP + #endif #else - #define MA_SIZEOF_PTR 4 + #define MA_POSIX + #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ + + #ifdef __unix__ + #define MA_UNIX + #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define MA_BSD + #endif + #endif + #ifdef __linux__ + #define MA_LINUX + #endif + #ifdef __APPLE__ + #define MA_APPLE + #endif + #ifdef __ANDROID__ + #define MA_ANDROID + #endif + #ifdef __EMSCRIPTEN__ + #define MA_EMSCRIPTEN + #endif #endif #include /* For size_t. */ /* Sized types. */ -#if defined(MA_USE_STDINT) - #include - typedef int8_t ma_int8; - typedef uint8_t ma_uint8; - typedef int16_t ma_int16; - typedef uint16_t ma_uint16; - typedef int32_t ma_int32; - typedef uint32_t ma_uint32; - typedef int64_t ma_int64; - typedef uint64_t ma_uint64; +typedef signed char ma_int8; +typedef unsigned char ma_uint8; +typedef signed short ma_int16; +typedef unsigned short ma_uint16; +typedef signed int ma_int32; +typedef unsigned int ma_uint32; +#if defined(_MSC_VER) + typedef signed __int64 ma_int64; + typedef unsigned __int64 ma_uint64; #else - typedef signed char ma_int8; - typedef unsigned char ma_uint8; - typedef signed short ma_int16; - typedef unsigned short ma_uint16; - typedef signed int ma_int32; - typedef unsigned int ma_uint32; - #if defined(_MSC_VER) && !defined(__clang__) - typedef signed __int64 ma_int64; - typedef unsigned __int64 ma_uint64; - #else - #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wlong-long" - #if defined(__clang__) - #pragma GCC diagnostic ignored "-Wc++11-long-long" - #endif - #endif - typedef signed long long ma_int64; - typedef unsigned long long ma_uint64; - #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic pop + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" #endif #endif -#endif /* MA_USE_STDINT */ - -#if MA_SIZEOF_PTR == 8 + typedef signed long long ma_int64; + typedef unsigned long long ma_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) typedef ma_uint64 ma_uintptr; #else typedef ma_uint32 ma_uintptr; @@ -3823,24 +1595,9 @@ typedef ma_uint32 ma_bool32; #define MA_TRUE 1 #define MA_FALSE 0 -/* These float types are not used universally by miniaudio. It's to simplify some macro expansion for atomic types. */ -typedef float ma_float; -typedef double ma_double; - typedef void* ma_handle; typedef void* ma_ptr; - -/* -ma_proc is annoying because when compiling with GCC we get pedantic warnings about converting -between `void*` and `void (*)()`. We can't use `void (*)()` with MSVC however, because we'll get -warning C4191 about "type cast between incompatible function types". To work around this I'm going -to use a different data type depending on the compiler. -*/ -#if defined(__GNUC__) -typedef void (*ma_proc)(void); -#else -typedef void* ma_proc; -#endif +typedef void (* ma_proc)(void); #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) typedef ma_uint16 wchar_t; @@ -3858,96 +1615,8 @@ typedef ma_uint16 wchar_t; #endif -/* Platform/backend detection. */ -#if defined(_WIN32) || defined(__COSMOPOLITAN__) - #define MA_WIN32 - #if defined(MA_FORCE_UWP) || (defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PC_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) || (defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) - #define MA_WIN32_UWP - #elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES) - #define MA_WIN32_GDK - #else - #define MA_WIN32_DESKTOP - #endif -#endif -#if !defined(_WIN32) /* If it's not Win32, assume POSIX. */ - #define MA_POSIX - - /* - Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. - You can use this to avoid including pthread.h in the header section. The downside is that it - results in some fixed sized structures being declared for the various types that are used in - miniaudio. The risk here is that these types might be too small for a given platform. This - risk is yours to take and no support will be offered if you enable this option. - */ - #ifndef MA_NO_PTHREAD_IN_HEADER - #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ - typedef pthread_t ma_pthread_t; - typedef pthread_mutex_t ma_pthread_mutex_t; - typedef pthread_cond_t ma_pthread_cond_t; - #else - typedef ma_uintptr ma_pthread_t; - typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; - typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; - #endif - - #if defined(__unix__) - #define MA_UNIX - #endif - #if defined(__linux__) - #define MA_LINUX - #endif - #if defined(__APPLE__) - #define MA_APPLE - #endif - #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #define MA_BSD - #endif - #if defined(__ANDROID__) - #define MA_ANDROID - #endif - #if defined(__EMSCRIPTEN__) - #define MA_EMSCRIPTEN - #endif - #if defined(__ORBIS__) - #define MA_ORBIS - #endif - #if defined(__PROSPERO__) - #define MA_PROSPERO - #endif - #if defined(__NX__) - #define MA_NX - #endif - #if defined(__BEOS__) || defined(__HAIKU__) - #define MA_BEOS - #endif - #if defined(__HAIKU__) - #define MA_HAIKU - #endif -#endif - -#if defined(__has_c_attribute) - #if __has_c_attribute(fallthrough) - #define MA_FALLTHROUGH [[fallthrough]] - #endif -#endif -#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) && (defined(__clang__) || defined(__GNUC__)) - #if __has_attribute(fallthrough) - #define MA_FALLTHROUGH __attribute__((fallthrough)) - #endif -#endif -#if !defined(MA_FALLTHROUGH) - #define MA_FALLTHROUGH ((void)0) -#endif - #ifdef _MSC_VER #define MA_INLINE __forceinline - - /* noinline was introduced in Visual Studio 2005. */ - #if _MSC_VER >= 1400 - #define MA_NO_INLINE __declspec(noinline) - #else - #define MA_NO_INLINE - #endif #elif defined(__GNUC__) /* I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when @@ -3957,298 +1626,237 @@ typedef ma_uint16 wchar_t; I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define MA_GNUC_INLINE_HINT __inline__ + #define MA_INLINE __inline__ __attribute__((always_inline)) #else - #define MA_GNUC_INLINE_HINT inline - #endif - - #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) - #define MA_INLINE MA_GNUC_INLINE_HINT __attribute__((always_inline)) - #define MA_NO_INLINE __attribute__((noinline)) - #else - #define MA_INLINE MA_GNUC_INLINE_HINT - #define MA_NO_INLINE __attribute__((noinline)) + #define MA_INLINE inline __attribute__((always_inline)) #endif #elif defined(__WATCOMC__) #define MA_INLINE __inline - #define MA_NO_INLINE #else #define MA_INLINE - #define MA_NO_INLINE -#endif - -/* MA_DLL is not officially supported. You're on your own if you want to use this. */ -#if defined(MA_DLL) - #if defined(_WIN32) - #define MA_DLL_IMPORT __declspec(dllimport) - #define MA_DLL_EXPORT __declspec(dllexport) - #define MA_DLL_PRIVATE static - #else - #if defined(__GNUC__) && __GNUC__ >= 4 - #define MA_DLL_IMPORT __attribute__((visibility("default"))) - #define MA_DLL_EXPORT __attribute__((visibility("default"))) - #define MA_DLL_PRIVATE __attribute__((visibility("hidden"))) - #else - #define MA_DLL_IMPORT - #define MA_DLL_EXPORT - #define MA_DLL_PRIVATE static - #endif - #endif #endif #if !defined(MA_API) #if defined(MA_DLL) + #if defined(_WIN32) + #define MA_DLL_IMPORT __declspec(dllimport) + #define MA_DLL_EXPORT __declspec(dllexport) + #define MA_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define MA_DLL_IMPORT __attribute__((visibility("default"))) + #define MA_DLL_EXPORT __attribute__((visibility("default"))) + #define MA_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define MA_DLL_IMPORT + #define MA_DLL_EXPORT + #define MA_DLL_PRIVATE static + #endif + #endif + #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION) #define MA_API MA_DLL_EXPORT #else #define MA_API MA_DLL_IMPORT #endif - #else - #define MA_API extern - #endif -#endif - -#if !defined(MA_STATIC) - #if defined(MA_DLL) #define MA_PRIVATE MA_DLL_PRIVATE #else + #define MA_API extern #define MA_PRIVATE static #endif #endif - -/* SIMD alignment in bytes. Currently set to 32 bytes in preparation for future AVX optimizations. */ -#define MA_SIMD_ALIGNMENT 32 - -/* -Special wchar_t type to ensure any structures in the public sections that reference it have a -consistent size across all platforms. - -On Windows, wchar_t is 2 bytes, whereas everywhere else it's 4 bytes. Since Windows likes to use -wchar_t for its IDs, we need a special explicitly sized wchar type that is always 2 bytes on all -platforms. -*/ -#if !defined(MA_POSIX) && defined(MA_WIN32) -typedef wchar_t ma_wchar_win32; -#else -typedef ma_uint16 ma_wchar_win32; -#endif - +/* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */ +#define MA_SIMD_ALIGNMENT 64 /* Logging Levels ============== -Log levels are only used to give logging callbacks some context as to the severity of a log message -so they can do filtering. All log levels will be posted to registered logging callbacks. If you -don't want to output a certain log level you can discriminate against the log level in the callback. +A log level will automatically include the lower levels. For example, verbose logging will enable everything. The warning log level will only include warnings +and errors, but will ignore informational and verbose logging. If you only want to handle a specific log level, implement a custom log callback (see +ma_context_init() for details) and interrogate the `logLevel` parameter. -MA_LOG_LEVEL_DEBUG - Used for debugging. Useful for debug and test builds, but should be disabled in release builds. +By default the log level will be set to MA_LOG_LEVEL_ERROR, but you can change this by defining MA_LOG_LEVEL before the implementation of miniaudio. + +MA_LOG_LEVEL_VERBOSE + Mainly intended for debugging. This will enable all log levels and can be triggered from within the data callback so care must be taken when enabling this + in production environments. MA_LOG_LEVEL_INFO - Informational logging. Useful for debugging. This will never be called from within the data - callback. + Informational logging. Useful for debugging. This will also enable warning and error logs. This will never be called from within the data callback. MA_LOG_LEVEL_WARNING - Warnings. You should enable this in you development builds and action them when encountered. These - logs usually indicate a potential problem or misconfiguration, but still allow you to keep - running. This will never be called from within the data callback. + Warnings. You should enable this in you development builds and action them when encounted. This will also enable error logs. These logs usually indicate a + potential problem or misconfiguration, but still allow you to keep running. This will never be called from within the data callback. MA_LOG_LEVEL_ERROR - Error logging. This will be fired when an operation fails and is subsequently aborted. This can - be fired from within the data callback, in which case the device will be stopped. You should - always have this log level enabled. + Error logging. This will be fired when an operation fails and is subsequently aborted. This can be fired from within the data callback, in which case the + device will be stopped. You should always have this log level enabled. */ -typedef enum -{ - MA_LOG_LEVEL_DEBUG = 4, - MA_LOG_LEVEL_INFO = 3, - MA_LOG_LEVEL_WARNING = 2, - MA_LOG_LEVEL_ERROR = 1 -} ma_log_level; +#define MA_LOG_LEVEL_VERBOSE 4 +#define MA_LOG_LEVEL_INFO 3 +#define MA_LOG_LEVEL_WARNING 2 +#define MA_LOG_LEVEL_ERROR 1 + +#ifndef MA_LOG_LEVEL +#define MA_LOG_LEVEL MA_LOG_LEVEL_ERROR +#endif /* -Variables needing to be accessed atomically should be declared with this macro for two reasons: - - 1) It allows people who read the code to identify a variable as such; and - 2) It forces alignment on platforms where it's required or optimal. - -Note that for x86/64, alignment is not strictly necessary, but does have some performance -implications. Where supported by the compiler, alignment will be used, but otherwise if the CPU -architecture does not require it, it will simply leave it unaligned. This is the case with old -versions of Visual Studio, which I've confirmed with at least VC6. +An annotation for variables which must be used atomically. This doesn't actually do anything - it's +just used as a way for humans to identify variables that should be used atomically. */ -#if !defined(_MSC_VER) && defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) - #include - #define MA_ATOMIC(alignment, type) _Alignas(alignment) type -#else - #if defined(__GNUC__) - /* GCC-style compilers. */ - #define MA_ATOMIC(alignment, type) type __attribute__((aligned(alignment))) - #elif defined(_MSC_VER) && _MSC_VER > 1200 /* 1200 = VC6. Alignment not supported, but not necessary because x86 is the only supported target. */ - /* MSVC. */ - #define MA_ATOMIC(alignment, type) __declspec(align(alignment)) type - #else - /* Other compilers. */ - #define MA_ATOMIC(alignment, type) type - #endif -#endif +#define MA_ATOMIC typedef struct ma_context ma_context; typedef struct ma_device ma_device; typedef ma_uint8 ma_channel; -typedef enum -{ - MA_CHANNEL_NONE = 0, - MA_CHANNEL_MONO = 1, - MA_CHANNEL_FRONT_LEFT = 2, - MA_CHANNEL_FRONT_RIGHT = 3, - MA_CHANNEL_FRONT_CENTER = 4, - MA_CHANNEL_LFE = 5, - MA_CHANNEL_BACK_LEFT = 6, - MA_CHANNEL_BACK_RIGHT = 7, - MA_CHANNEL_FRONT_LEFT_CENTER = 8, - MA_CHANNEL_FRONT_RIGHT_CENTER = 9, - MA_CHANNEL_BACK_CENTER = 10, - MA_CHANNEL_SIDE_LEFT = 11, - MA_CHANNEL_SIDE_RIGHT = 12, - MA_CHANNEL_TOP_CENTER = 13, - MA_CHANNEL_TOP_FRONT_LEFT = 14, - MA_CHANNEL_TOP_FRONT_CENTER = 15, - MA_CHANNEL_TOP_FRONT_RIGHT = 16, - MA_CHANNEL_TOP_BACK_LEFT = 17, - MA_CHANNEL_TOP_BACK_CENTER = 18, - MA_CHANNEL_TOP_BACK_RIGHT = 19, - MA_CHANNEL_AUX_0 = 20, - MA_CHANNEL_AUX_1 = 21, - MA_CHANNEL_AUX_2 = 22, - MA_CHANNEL_AUX_3 = 23, - MA_CHANNEL_AUX_4 = 24, - MA_CHANNEL_AUX_5 = 25, - MA_CHANNEL_AUX_6 = 26, - MA_CHANNEL_AUX_7 = 27, - MA_CHANNEL_AUX_8 = 28, - MA_CHANNEL_AUX_9 = 29, - MA_CHANNEL_AUX_10 = 30, - MA_CHANNEL_AUX_11 = 31, - MA_CHANNEL_AUX_12 = 32, - MA_CHANNEL_AUX_13 = 33, - MA_CHANNEL_AUX_14 = 34, - MA_CHANNEL_AUX_15 = 35, - MA_CHANNEL_AUX_16 = 36, - MA_CHANNEL_AUX_17 = 37, - MA_CHANNEL_AUX_18 = 38, - MA_CHANNEL_AUX_19 = 39, - MA_CHANNEL_AUX_20 = 40, - MA_CHANNEL_AUX_21 = 41, - MA_CHANNEL_AUX_22 = 42, - MA_CHANNEL_AUX_23 = 43, - MA_CHANNEL_AUX_24 = 44, - MA_CHANNEL_AUX_25 = 45, - MA_CHANNEL_AUX_26 = 46, - MA_CHANNEL_AUX_27 = 47, - MA_CHANNEL_AUX_28 = 48, - MA_CHANNEL_AUX_29 = 49, - MA_CHANNEL_AUX_30 = 50, - MA_CHANNEL_AUX_31 = 51, - MA_CHANNEL_LEFT = MA_CHANNEL_FRONT_LEFT, - MA_CHANNEL_RIGHT = MA_CHANNEL_FRONT_RIGHT, - MA_CHANNEL_POSITION_COUNT = (MA_CHANNEL_AUX_31 + 1) -} _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */ - -typedef enum -{ - MA_SUCCESS = 0, - MA_ERROR = -1, /* A generic error. */ - MA_INVALID_ARGS = -2, - MA_INVALID_OPERATION = -3, - MA_OUT_OF_MEMORY = -4, - MA_OUT_OF_RANGE = -5, - MA_ACCESS_DENIED = -6, - MA_DOES_NOT_EXIST = -7, - MA_ALREADY_EXISTS = -8, - MA_TOO_MANY_OPEN_FILES = -9, - MA_INVALID_FILE = -10, - MA_TOO_BIG = -11, - MA_PATH_TOO_LONG = -12, - MA_NAME_TOO_LONG = -13, - MA_NOT_DIRECTORY = -14, - MA_IS_DIRECTORY = -15, - MA_DIRECTORY_NOT_EMPTY = -16, - MA_AT_END = -17, - MA_NO_SPACE = -18, - MA_BUSY = -19, - MA_IO_ERROR = -20, - MA_INTERRUPT = -21, - MA_UNAVAILABLE = -22, - MA_ALREADY_IN_USE = -23, - MA_BAD_ADDRESS = -24, - MA_BAD_SEEK = -25, - MA_BAD_PIPE = -26, - MA_DEADLOCK = -27, - MA_TOO_MANY_LINKS = -28, - MA_NOT_IMPLEMENTED = -29, - MA_NO_MESSAGE = -30, - MA_BAD_MESSAGE = -31, - MA_NO_DATA_AVAILABLE = -32, - MA_INVALID_DATA = -33, - MA_TIMEOUT = -34, - MA_NO_NETWORK = -35, - MA_NOT_UNIQUE = -36, - MA_NOT_SOCKET = -37, - MA_NO_ADDRESS = -38, - MA_BAD_PROTOCOL = -39, - MA_PROTOCOL_UNAVAILABLE = -40, - MA_PROTOCOL_NOT_SUPPORTED = -41, - MA_PROTOCOL_FAMILY_NOT_SUPPORTED = -42, - MA_ADDRESS_FAMILY_NOT_SUPPORTED = -43, - MA_SOCKET_NOT_SUPPORTED = -44, - MA_CONNECTION_RESET = -45, - MA_ALREADY_CONNECTED = -46, - MA_NOT_CONNECTED = -47, - MA_CONNECTION_REFUSED = -48, - MA_NO_HOST = -49, - MA_IN_PROGRESS = -50, - MA_CANCELLED = -51, - MA_MEMORY_ALREADY_MAPPED = -52, - - /* General non-standard errors. */ - MA_CRC_MISMATCH = -100, - - /* General miniaudio-specific errors. */ - MA_FORMAT_NOT_SUPPORTED = -200, - MA_DEVICE_TYPE_NOT_SUPPORTED = -201, - MA_SHARE_MODE_NOT_SUPPORTED = -202, - MA_NO_BACKEND = -203, - MA_NO_DEVICE = -204, - MA_API_NOT_FOUND = -205, - MA_INVALID_DEVICE_CONFIG = -206, - MA_LOOP = -207, - MA_BACKEND_NOT_ENABLED = -208, - - /* State errors. */ - MA_DEVICE_NOT_INITIALIZED = -300, - MA_DEVICE_ALREADY_INITIALIZED = -301, - MA_DEVICE_NOT_STARTED = -302, - MA_DEVICE_NOT_STOPPED = -303, - - /* Operation errors. */ - MA_FAILED_TO_INIT_BACKEND = -400, - MA_FAILED_TO_OPEN_BACKEND_DEVICE = -401, - MA_FAILED_TO_START_BACKEND_DEVICE = -402, - MA_FAILED_TO_STOP_BACKEND_DEVICE = -403 -} ma_result; +#define MA_CHANNEL_NONE 0 +#define MA_CHANNEL_MONO 1 +#define MA_CHANNEL_FRONT_LEFT 2 +#define MA_CHANNEL_FRONT_RIGHT 3 +#define MA_CHANNEL_FRONT_CENTER 4 +#define MA_CHANNEL_LFE 5 +#define MA_CHANNEL_BACK_LEFT 6 +#define MA_CHANNEL_BACK_RIGHT 7 +#define MA_CHANNEL_FRONT_LEFT_CENTER 8 +#define MA_CHANNEL_FRONT_RIGHT_CENTER 9 +#define MA_CHANNEL_BACK_CENTER 10 +#define MA_CHANNEL_SIDE_LEFT 11 +#define MA_CHANNEL_SIDE_RIGHT 12 +#define MA_CHANNEL_TOP_CENTER 13 +#define MA_CHANNEL_TOP_FRONT_LEFT 14 +#define MA_CHANNEL_TOP_FRONT_CENTER 15 +#define MA_CHANNEL_TOP_FRONT_RIGHT 16 +#define MA_CHANNEL_TOP_BACK_LEFT 17 +#define MA_CHANNEL_TOP_BACK_CENTER 18 +#define MA_CHANNEL_TOP_BACK_RIGHT 19 +#define MA_CHANNEL_AUX_0 20 +#define MA_CHANNEL_AUX_1 21 +#define MA_CHANNEL_AUX_2 22 +#define MA_CHANNEL_AUX_3 23 +#define MA_CHANNEL_AUX_4 24 +#define MA_CHANNEL_AUX_5 25 +#define MA_CHANNEL_AUX_6 26 +#define MA_CHANNEL_AUX_7 27 +#define MA_CHANNEL_AUX_8 28 +#define MA_CHANNEL_AUX_9 29 +#define MA_CHANNEL_AUX_10 30 +#define MA_CHANNEL_AUX_11 31 +#define MA_CHANNEL_AUX_12 32 +#define MA_CHANNEL_AUX_13 33 +#define MA_CHANNEL_AUX_14 34 +#define MA_CHANNEL_AUX_15 35 +#define MA_CHANNEL_AUX_16 36 +#define MA_CHANNEL_AUX_17 37 +#define MA_CHANNEL_AUX_18 38 +#define MA_CHANNEL_AUX_19 39 +#define MA_CHANNEL_AUX_20 40 +#define MA_CHANNEL_AUX_21 41 +#define MA_CHANNEL_AUX_22 42 +#define MA_CHANNEL_AUX_23 43 +#define MA_CHANNEL_AUX_24 44 +#define MA_CHANNEL_AUX_25 45 +#define MA_CHANNEL_AUX_26 46 +#define MA_CHANNEL_AUX_27 47 +#define MA_CHANNEL_AUX_28 48 +#define MA_CHANNEL_AUX_29 49 +#define MA_CHANNEL_AUX_30 50 +#define MA_CHANNEL_AUX_31 51 +#define MA_CHANNEL_LEFT MA_CHANNEL_FRONT_LEFT +#define MA_CHANNEL_RIGHT MA_CHANNEL_FRONT_RIGHT +#define MA_CHANNEL_POSITION_COUNT (MA_CHANNEL_AUX_31 + 1) -#define MA_MIN_CHANNELS 1 +typedef int ma_result; +#define MA_SUCCESS 0 +#define MA_ERROR -1 /* A generic error. */ +#define MA_INVALID_ARGS -2 +#define MA_INVALID_OPERATION -3 +#define MA_OUT_OF_MEMORY -4 +#define MA_OUT_OF_RANGE -5 +#define MA_ACCESS_DENIED -6 +#define MA_DOES_NOT_EXIST -7 +#define MA_ALREADY_EXISTS -8 +#define MA_TOO_MANY_OPEN_FILES -9 +#define MA_INVALID_FILE -10 +#define MA_TOO_BIG -11 +#define MA_PATH_TOO_LONG -12 +#define MA_NAME_TOO_LONG -13 +#define MA_NOT_DIRECTORY -14 +#define MA_IS_DIRECTORY -15 +#define MA_DIRECTORY_NOT_EMPTY -16 +#define MA_END_OF_FILE -17 +#define MA_NO_SPACE -18 +#define MA_BUSY -19 +#define MA_IO_ERROR -20 +#define MA_INTERRUPT -21 +#define MA_UNAVAILABLE -22 +#define MA_ALREADY_IN_USE -23 +#define MA_BAD_ADDRESS -24 +#define MA_BAD_SEEK -25 +#define MA_BAD_PIPE -26 +#define MA_DEADLOCK -27 +#define MA_TOO_MANY_LINKS -28 +#define MA_NOT_IMPLEMENTED -29 +#define MA_NO_MESSAGE -30 +#define MA_BAD_MESSAGE -31 +#define MA_NO_DATA_AVAILABLE -32 +#define MA_INVALID_DATA -33 +#define MA_TIMEOUT -34 +#define MA_NO_NETWORK -35 +#define MA_NOT_UNIQUE -36 +#define MA_NOT_SOCKET -37 +#define MA_NO_ADDRESS -38 +#define MA_BAD_PROTOCOL -39 +#define MA_PROTOCOL_UNAVAILABLE -40 +#define MA_PROTOCOL_NOT_SUPPORTED -41 +#define MA_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define MA_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define MA_SOCKET_NOT_SUPPORTED -44 +#define MA_CONNECTION_RESET -45 +#define MA_ALREADY_CONNECTED -46 +#define MA_NOT_CONNECTED -47 +#define MA_CONNECTION_REFUSED -48 +#define MA_NO_HOST -49 +#define MA_IN_PROGRESS -50 +#define MA_CANCELLED -51 +#define MA_MEMORY_ALREADY_MAPPED -52 +#define MA_AT_END -53 + +/* General miniaudio-specific errors. */ +#define MA_FORMAT_NOT_SUPPORTED -100 +#define MA_DEVICE_TYPE_NOT_SUPPORTED -101 +#define MA_SHARE_MODE_NOT_SUPPORTED -102 +#define MA_NO_BACKEND -103 +#define MA_NO_DEVICE -104 +#define MA_API_NOT_FOUND -105 +#define MA_INVALID_DEVICE_CONFIG -106 +#define MA_LOOP -107 + +/* State errors. */ +#define MA_DEVICE_NOT_INITIALIZED -200 +#define MA_DEVICE_ALREADY_INITIALIZED -201 +#define MA_DEVICE_NOT_STARTED -202 +#define MA_DEVICE_NOT_STOPPED -203 + +/* Operation errors. */ +#define MA_FAILED_TO_INIT_BACKEND -300 +#define MA_FAILED_TO_OPEN_BACKEND_DEVICE -301 +#define MA_FAILED_TO_START_BACKEND_DEVICE -302 +#define MA_FAILED_TO_STOP_BACKEND_DEVICE -303 + + +#define MA_MIN_CHANNELS 1 #ifndef MA_MAX_CHANNELS -#define MA_MAX_CHANNELS 254 +#define MA_MAX_CHANNELS 32 #endif + #ifndef MA_MAX_FILTER_ORDER -#define MA_MAX_FILTER_ORDER 8 +#define MA_MAX_FILTER_ORDER 8 #endif typedef enum @@ -4293,14 +1901,14 @@ typedef enum ma_standard_sample_rate_32000 = 32000, /* Lows */ ma_standard_sample_rate_24000 = 24000, ma_standard_sample_rate_22050 = 22050, - + ma_standard_sample_rate_88200 = 88200, /* Highs */ ma_standard_sample_rate_96000 = 96000, ma_standard_sample_rate_176400 = 176400, ma_standard_sample_rate_192000 = 192000, ma_standard_sample_rate_16000 = 16000, /* Extreme lows */ - ma_standard_sample_rate_11025 = 11025, + ma_standard_sample_rate_11025 = 11250, ma_standard_sample_rate_8000 = 8000, ma_standard_sample_rate_352800 = 352800, /* Extreme highs */ @@ -4311,13 +1919,18 @@ typedef enum ma_standard_sample_rate_count = 14 /* Need to maintain the count manually. Make sure this is updated if items are added to enum. */ } ma_standard_sample_rate; +/* These are deprecated. Use ma_standard_sample_rate_min and ma_standard_sample_rate_max. */ +#define MA_MIN_SAMPLE_RATE (ma_uint32)ma_standard_sample_rate_min +#define MA_MAX_SAMPLE_RATE (ma_uint32)ma_standard_sample_rate_max + typedef enum { ma_channel_mix_mode_rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */ ma_channel_mix_mode_simple, /* Drop excess channels; zeroed out extra channels. */ - ma_channel_mix_mode_custom_weights, /* Use custom weights specified in ma_channel_converter_config. */ - ma_channel_mix_mode_default = ma_channel_mix_mode_rectangular + ma_channel_mix_mode_custom_weights, /* Use custom weights specified in ma_channel_router_config. */ + ma_channel_mix_mode_planar_blend = ma_channel_mix_mode_rectangular, + ma_channel_mix_mode_default = ma_channel_mix_mode_planar_blend } ma_channel_mix_mode; typedef enum @@ -4354,118 +1967,65 @@ typedef struct } ma_lcg; -/* -Atomics. - -These are typesafe structures to prevent errors as a result of forgetting to reference variables atomically. It's too -easy to introduce subtle bugs where you accidentally do a regular assignment instead of an atomic load/store, etc. By -using a struct we can enforce the use of atomics at compile time. - -These types are declared in the header section because we need to reference them in structs below, but functions for -using them are only exposed in the implementation section. I do not want these to be part of the public API. - -There's a few downsides to this system. The first is that you need to declare a new struct for each type. Below are -some macros to help with the declarations. They will be named like so: - - ma_atomic_uint32 - atomic ma_uint32 - ma_atomic_int32 - atomic ma_int32 - ma_atomic_uint64 - atomic ma_uint64 - ma_atomic_float - atomic float - ma_atomic_bool32 - atomic ma_bool32 - -The other downside is that atomic pointers are extremely messy. You need to declare a new struct for each specific -type of pointer you need to make atomic. For example, an atomic ma_node* will look like this: - - MA_ATOMIC_SAFE_TYPE_IMPL_PTR(node) - -Which will declare a type struct that's named like so: - - ma_atomic_ptr_node - -Functions to use the atomic types are declared in the implementation section. All atomic functions are prefixed with -the name of the struct. For example: - - ma_atomic_uint32_set() - Atomic store of ma_uint32 - ma_atomic_uint32_get() - Atomic load of ma_uint32 - etc. - -For pointer types it's the same, which makes them a bit messy to use due to the length of each function name, but in -return you get type safety and enforcement of atomic operations. -*/ -#define MA_ATOMIC_SAFE_TYPE_DECL(c89TypeExtension, typeSize, type) \ - typedef struct \ - { \ - MA_ATOMIC(typeSize, ma_##type) value; \ - } ma_atomic_##type; \ - -#define MA_ATOMIC_SAFE_TYPE_DECL_PTR(type) \ - typedef struct \ - { \ - MA_ATOMIC(MA_SIZEOF_PTR, ma_##type*) value; \ - } ma_atomic_ptr_##type; \ - -MA_ATOMIC_SAFE_TYPE_DECL(32, 4, uint32) -MA_ATOMIC_SAFE_TYPE_DECL(i32, 4, int32) -MA_ATOMIC_SAFE_TYPE_DECL(64, 8, uint64) -MA_ATOMIC_SAFE_TYPE_DECL(f32, 4, float) -MA_ATOMIC_SAFE_TYPE_DECL(32, 4, bool32) - +#ifndef MA_NO_THREADING +/* Thread priorities should be ordered such that the default priority of the worker thread is 0. */ +typedef enum +{ + ma_thread_priority_idle = -5, + ma_thread_priority_lowest = -4, + ma_thread_priority_low = -3, + ma_thread_priority_normal = -2, + ma_thread_priority_high = -1, + ma_thread_priority_highest = 0, + ma_thread_priority_realtime = 1, + ma_thread_priority_default = 0 +} ma_thread_priority; /* Spinlocks are 32-bit for compatibility reasons. */ typedef ma_uint32 ma_spinlock; -#ifndef MA_NO_THREADING - /* Thread priorities should be ordered such that the default priority of the worker thread is 0. */ - typedef enum - { - ma_thread_priority_idle = -5, - ma_thread_priority_lowest = -4, - ma_thread_priority_low = -3, - ma_thread_priority_normal = -2, - ma_thread_priority_high = -1, - ma_thread_priority_highest = 0, - ma_thread_priority_realtime = 1, - ma_thread_priority_default = 0 - } ma_thread_priority; +#if defined(MA_WIN32) +typedef ma_handle ma_thread; +#endif +#if defined(MA_POSIX) +typedef pthread_t ma_thread; +#endif - #if defined(MA_POSIX) - typedef ma_pthread_t ma_thread; - #elif defined(MA_WIN32) - typedef ma_handle ma_thread; - #endif +#if defined(MA_WIN32) +typedef ma_handle ma_mutex; +#endif +#if defined(MA_POSIX) +typedef pthread_mutex_t ma_mutex; +#endif - #if defined(MA_POSIX) - typedef ma_pthread_mutex_t ma_mutex; - #elif defined(MA_WIN32) - typedef ma_handle ma_mutex; - #endif +#if defined(MA_WIN32) +typedef ma_handle ma_event; +#endif +#if defined(MA_POSIX) +typedef struct +{ + ma_uint32 value; + pthread_mutex_t lock; + pthread_cond_t cond; +} ma_event; +#endif /* MA_POSIX */ - #if defined(MA_POSIX) - typedef struct - { - ma_uint32 value; - ma_pthread_mutex_t lock; - ma_pthread_cond_t cond; - } ma_event; - #elif defined(MA_WIN32) - typedef ma_handle ma_event; - #endif - - #if defined(MA_POSIX) - typedef struct - { - int value; - ma_pthread_mutex_t lock; - ma_pthread_cond_t cond; - } ma_semaphore; - #elif defined(MA_WIN32) - typedef ma_handle ma_semaphore; - #endif +#if defined(MA_WIN32) +typedef ma_handle ma_semaphore; +#endif +#if defined(MA_POSIX) +typedef struct +{ + int value; + pthread_mutex_t lock; + pthread_cond_t cond; +} ma_semaphore; +#endif /* MA_POSIX */ #else - /* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */ - #ifndef MA_NO_DEVICE_IO - #error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO"; - #endif +/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */ +#ifndef MA_NO_DEVICE_IO +#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO"; +#endif #endif /* MA_NO_THREADING */ @@ -4480,81 +2040,6 @@ Retrieves the version of miniaudio as a string which can be useful for logging p MA_API const char* ma_version_string(void); -/************************************************************************************************************************************************************** - -Logging - -**************************************************************************************************************************************************************/ -#include /* For va_list. */ - -#if defined(__has_attribute) - #if __has_attribute(format) - #define MA_ATTRIBUTE_FORMAT(fmt, va) __attribute__((format(printf, fmt, va))) - #endif -#endif -#ifndef MA_ATTRIBUTE_FORMAT -#define MA_ATTRIBUTE_FORMAT(fmt, va) -#endif - -#ifndef MA_MAX_LOG_CALLBACKS -#define MA_MAX_LOG_CALLBACKS 4 -#endif - - -/* -The callback for handling log messages. - - -Parameters ----------- -pUserData (in) - The user data pointer that was passed into ma_log_register_callback(). - -logLevel (in) - The log level. This can be one of the following: - - +----------------------+ - | Log Level | - +----------------------+ - | MA_LOG_LEVEL_DEBUG | - | MA_LOG_LEVEL_INFO | - | MA_LOG_LEVEL_WARNING | - | MA_LOG_LEVEL_ERROR | - +----------------------+ - -pMessage (in) - The log message. -*/ -typedef void (* ma_log_callback_proc)(void* pUserData, ma_uint32 level, const char* pMessage); - -typedef struct -{ - ma_log_callback_proc onLog; - void* pUserData; -} ma_log_callback; - -MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog, void* pUserData); - - -typedef struct -{ - ma_log_callback callbacks[MA_MAX_LOG_CALLBACKS]; - ma_uint32 callbackCount; - ma_allocation_callbacks allocationCallbacks; /* Need to store these persistently because ma_log_postv() might need to allocate a buffer on the heap. */ -#ifndef MA_NO_THREADING - ma_mutex lock; /* For thread safety just to make it easier and safer for the logging implementation. */ -#endif -} ma_log; - -MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks, ma_log* pLog); -MA_API void ma_log_uninit(ma_log* pLog); -MA_API ma_result ma_log_register_callback(ma_log* pLog, ma_log_callback callback); -MA_API ma_result ma_log_unregister_callback(ma_log* pLog, ma_log_callback callback); -MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage); -MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat, va_list args); -MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat, ...) MA_ATTRIBUTE_FORMAT(3, 4); - - /************************************************************************************************************************************************************** Biquad Filtering @@ -4589,20 +2074,12 @@ typedef struct ma_biquad_coefficient b2; ma_biquad_coefficient a1; ma_biquad_coefficient a2; - ma_biquad_coefficient* pR1; - ma_biquad_coefficient* pR2; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + ma_biquad_coefficient r1[MA_MAX_CHANNELS]; + ma_biquad_coefficient r2[MA_MAX_CHANNELS]; } ma_biquad; -MA_API ma_result ma_biquad_get_heap_size(const ma_biquad_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_biquad_init_preallocated(const ma_biquad_config* pConfig, void* pHeap, ma_biquad* pBQ); -MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad* pBQ); -MA_API void ma_biquad_uninit(ma_biquad* pBQ, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ); MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ); -MA_API ma_result ma_biquad_clear_cache(ma_biquad* pBQ); MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ); @@ -4629,19 +2106,11 @@ typedef struct ma_format format; ma_uint32 channels; ma_biquad_coefficient a; - ma_biquad_coefficient* pR1; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + ma_biquad_coefficient r1[MA_MAX_CHANNELS]; } ma_lpf1; -MA_API ma_result ma_lpf1_get_heap_size(const ma_lpf1_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_lpf1_init_preallocated(const ma_lpf1_config* pConfig, void* pHeap, ma_lpf1* pLPF); -MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf1* pLPF); -MA_API void ma_lpf1_uninit(ma_lpf1* pLPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF); MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF); -MA_API ma_result ma_lpf1_clear_cache(ma_lpf1* pLPF); MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF); @@ -4650,12 +2119,8 @@ typedef struct ma_biquad bq; /* The second order low-pass filter is implemented as a biquad filter. */ } ma_lpf2; -MA_API ma_result ma_lpf2_get_heap_size(const ma_lpf2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* pHeap, ma_lpf2* pHPF); -MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf2* pLPF); -MA_API void ma_lpf2_uninit(ma_lpf2* pLPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF); MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF); -MA_API ma_result ma_lpf2_clear_cache(ma_lpf2* pLPF); MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF); @@ -4678,20 +2143,12 @@ typedef struct ma_uint32 sampleRate; ma_uint32 lpf1Count; ma_uint32 lpf2Count; - ma_lpf1* pLPF1; - ma_lpf2* pLPF2; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + ma_lpf1 lpf1[1]; + ma_lpf2 lpf2[MA_MAX_FILTER_ORDER/2]; } ma_lpf; -MA_API ma_result ma_lpf_get_heap_size(const ma_lpf_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF); -MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf* pLPF); -MA_API void ma_lpf_uninit(ma_lpf* pLPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF); MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF); -MA_API ma_result ma_lpf_clear_cache(ma_lpf* pLPF); MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF); @@ -4718,17 +2175,10 @@ typedef struct ma_format format; ma_uint32 channels; ma_biquad_coefficient a; - ma_biquad_coefficient* pR1; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + ma_biquad_coefficient r1[MA_MAX_CHANNELS]; } ma_hpf1; -MA_API ma_result ma_hpf1_get_heap_size(const ma_hpf1_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_hpf1_init_preallocated(const ma_hpf1_config* pConfig, void* pHeap, ma_hpf1* pLPF); -MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf1* pHPF); -MA_API void ma_hpf1_uninit(ma_hpf1* pHPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF); MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF); MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF); @@ -4738,10 +2188,7 @@ typedef struct ma_biquad bq; /* The second order high-pass filter is implemented as a biquad filter. */ } ma_hpf2; -MA_API ma_result ma_hpf2_get_heap_size(const ma_hpf2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* pHeap, ma_hpf2* pHPF); -MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf2* pHPF); -MA_API void ma_hpf2_uninit(ma_hpf2* pHPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF); MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF); MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF); @@ -4765,18 +2212,11 @@ typedef struct ma_uint32 sampleRate; ma_uint32 hpf1Count; ma_uint32 hpf2Count; - ma_hpf1* pHPF1; - ma_hpf2* pHPF2; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + ma_hpf1 hpf1[1]; + ma_hpf2 hpf2[MA_MAX_FILTER_ORDER/2]; } ma_hpf; -MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_hpf_init_preallocated(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pLPF); -MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf* pHPF); -MA_API void ma_hpf_uninit(ma_hpf* pHPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF); MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF); MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF); @@ -4803,10 +2243,7 @@ typedef struct ma_biquad bq; /* The second order band-pass filter is implemented as a biquad filter. */ } ma_bpf2; -MA_API ma_result ma_bpf2_get_heap_size(const ma_bpf2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* pHeap, ma_bpf2* pBPF); -MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf2* pBPF); -MA_API void ma_bpf2_uninit(ma_bpf2* pBPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF); MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF); MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF); @@ -4828,17 +2265,10 @@ typedef struct ma_format format; ma_uint32 channels; ma_uint32 bpf2Count; - ma_bpf2* pBPF2; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + ma_bpf2 bpf2[MA_MAX_FILTER_ORDER/2]; } ma_bpf; -MA_API ma_result ma_bpf_get_heap_size(const ma_bpf_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF); -MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf* pBPF); -MA_API void ma_bpf_uninit(ma_bpf* pBPF, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF); MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF); MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF); @@ -4856,7 +2286,7 @@ typedef struct ma_uint32 sampleRate; double q; double frequency; -} ma_notch2_config, ma_notch_config; +} ma_notch2_config; MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency); @@ -4865,10 +2295,7 @@ typedef struct ma_biquad bq; } ma_notch2; -MA_API ma_result ma_notch2_get_heap_size(const ma_notch2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, void* pHeap, ma_notch2* pFilter); -MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch2* pFilter); -MA_API void ma_notch2_uninit(ma_notch2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter); MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter); MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter); @@ -4887,7 +2314,7 @@ typedef struct double gainDB; double q; double frequency; -} ma_peak2_config, ma_peak_config; +} ma_peak2_config; MA_API ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); @@ -4896,10 +2323,7 @@ typedef struct ma_biquad bq; } ma_peak2; -MA_API ma_result ma_peak2_get_heap_size(const ma_peak2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void* pHeap, ma_peak2* pFilter); -MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak2* pFilter); -MA_API void ma_peak2_uninit(ma_peak2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter); MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter); MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter); @@ -4918,7 +2342,7 @@ typedef struct double gainDB; double shelfSlope; double frequency; -} ma_loshelf2_config, ma_loshelf_config; +} ma_loshelf2_config; MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency); @@ -4927,10 +2351,7 @@ typedef struct ma_biquad bq; } ma_loshelf2; -MA_API ma_result ma_loshelf2_get_heap_size(const ma_loshelf2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig, void* pHeap, ma_loshelf2* pFilter); -MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf2* pFilter); -MA_API void ma_loshelf2_uninit(ma_loshelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter); MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter); MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter); @@ -4949,7 +2370,7 @@ typedef struct double gainDB; double shelfSlope; double frequency; -} ma_hishelf2_config, ma_hishelf_config; +} ma_hishelf2_config; MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency); @@ -4958,330 +2379,13 @@ typedef struct ma_biquad bq; } ma_hishelf2; -MA_API ma_result ma_hishelf2_get_heap_size(const ma_hishelf2_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig, void* pHeap, ma_hishelf2* pFilter); -MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf2* pFilter); -MA_API void ma_hishelf2_uninit(ma_hishelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter); MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter); MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter); -/* -Delay -*/ -typedef struct -{ - ma_uint32 channels; - ma_uint32 sampleRate; - ma_uint32 delayInFrames; - ma_bool32 delayStart; /* Set to true to delay the start of the output; false otherwise. */ - float wet; /* 0..1. Default = 1. */ - float dry; /* 0..1. Default = 1. */ - float decay; /* 0..1. Default = 0 (no feedback). Feedback decay. Use this for echo. */ -} ma_delay_config; - -MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay); - - -typedef struct -{ - ma_delay_config config; - ma_uint32 cursor; /* Feedback is written to this cursor. Always equal or in front of the read cursor. */ - ma_uint32 bufferSizeInFrames; - float* pBuffer; -} ma_delay; - -MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay); -MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount); -MA_API void ma_delay_set_wet(ma_delay* pDelay, float value); -MA_API float ma_delay_get_wet(const ma_delay* pDelay); -MA_API void ma_delay_set_dry(ma_delay* pDelay, float value); -MA_API float ma_delay_get_dry(const ma_delay* pDelay); -MA_API void ma_delay_set_decay(ma_delay* pDelay, float value); -MA_API float ma_delay_get_decay(const ma_delay* pDelay); - - -/* Gainer for smooth volume changes. */ -typedef struct -{ - ma_uint32 channels; - ma_uint32 smoothTimeInFrames; -} ma_gainer_config; - -MA_API ma_gainer_config ma_gainer_config_init(ma_uint32 channels, ma_uint32 smoothTimeInFrames); - - -typedef struct -{ - ma_gainer_config config; - ma_uint32 t; - float masterVolume; - float* pOldGains; - float* pNewGains; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; -} ma_gainer; - -MA_API ma_result ma_gainer_get_heap_size(const ma_gainer_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, void* pHeap, ma_gainer* pGainer); -MA_API ma_result ma_gainer_init(const ma_gainer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_gainer* pGainer); -MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); -MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain); -MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains); -MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume); -MA_API ma_result ma_gainer_get_master_volume(const ma_gainer* pGainer, float* pVolume); - - - -/* Stereo panner. */ -typedef enum -{ - ma_pan_mode_balance = 0, /* Does not blend one side with the other. Technically just a balance. Compatible with other popular audio engines and therefore the default. */ - ma_pan_mode_pan /* A true pan. The sound from one side will "move" to the other side and blend with it. */ -} ma_pan_mode; - -typedef struct -{ - ma_format format; - ma_uint32 channels; - ma_pan_mode mode; - float pan; -} ma_panner_config; - -MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels); - - -typedef struct -{ - ma_format format; - ma_uint32 channels; - ma_pan_mode mode; - float pan; /* -1..1 where 0 is no pan, -1 is left side, +1 is right side. Defaults to 0. */ -} ma_panner; - -MA_API ma_result ma_panner_init(const ma_panner_config* pConfig, ma_panner* pPanner); -MA_API ma_result ma_panner_process_pcm_frames(ma_panner* pPanner, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); -MA_API void ma_panner_set_mode(ma_panner* pPanner, ma_pan_mode mode); -MA_API ma_pan_mode ma_panner_get_mode(const ma_panner* pPanner); -MA_API void ma_panner_set_pan(ma_panner* pPanner, float pan); -MA_API float ma_panner_get_pan(const ma_panner* pPanner); - - - -/* Fader. */ -typedef struct -{ - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; -} ma_fader_config; - -MA_API ma_fader_config ma_fader_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate); - -typedef struct -{ - ma_fader_config config; - float volumeBeg; /* If volumeBeg and volumeEnd is equal to 1, no fading happens (ma_fader_process_pcm_frames() will run as a passthrough). */ - float volumeEnd; - ma_uint64 lengthInFrames; /* The total length of the fade. */ - ma_int64 cursorInFrames; /* The current time in frames. Incremented by ma_fader_process_pcm_frames(). Signed because it'll be offset by startOffsetInFrames in set_fade_ex(). */ -} ma_fader; - -MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader); -MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); -MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); -MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames); -MA_API void ma_fader_set_fade_ex(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames, ma_int64 startOffsetInFrames); -MA_API float ma_fader_get_current_volume(const ma_fader* pFader); - - - -/* Spatializer. */ -typedef struct -{ - float x; - float y; - float z; -} ma_vec3f; - -typedef struct -{ - ma_vec3f v; - ma_spinlock lock; -} ma_atomic_vec3f; - -typedef enum -{ - ma_attenuation_model_none, /* No distance attenuation and no spatialization. */ - ma_attenuation_model_inverse, /* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */ - ma_attenuation_model_linear, /* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */ - ma_attenuation_model_exponential /* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */ -} ma_attenuation_model; - -typedef enum -{ - ma_positioning_absolute, - ma_positioning_relative -} ma_positioning; - -typedef enum -{ - ma_handedness_right, - ma_handedness_left -} ma_handedness; - - -typedef struct -{ - ma_uint32 channelsOut; - ma_channel* pChannelMapOut; - ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ - float coneInnerAngleInRadians; - float coneOuterAngleInRadians; - float coneOuterGain; - float speedOfSound; - ma_vec3f worldUp; -} ma_spatializer_listener_config; - -MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uint32 channelsOut); - - -typedef struct -{ - ma_spatializer_listener_config config; - ma_atomic_vec3f position; /* The absolute position of the listener. */ - ma_atomic_vec3f direction; /* The direction the listener is facing. The world up vector is config.worldUp. */ - ma_atomic_vec3f velocity; - ma_bool32 isEnabled; - - /* Memory management. */ - ma_bool32 _ownsHeap; - void* _pHeap; -} ma_spatializer_listener; - -MA_API ma_result ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config* pConfig, void* pHeap, ma_spatializer_listener* pListener); -MA_API ma_result ma_spatializer_listener_init(const ma_spatializer_listener_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_uninit(ma_spatializer_listener* pListener, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_channel* ma_spatializer_listener_get_channel_map(ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_set_cone(ma_spatializer_listener* pListener, float innerAngleInRadians, float outerAngleInRadians, float outerGain); -MA_API void ma_spatializer_listener_get_cone(const ma_spatializer_listener* pListener, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); -MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListener, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound); -MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_set_world_up(ma_spatializer_listener* pListener, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener* pListener); -MA_API void ma_spatializer_listener_set_enabled(ma_spatializer_listener* pListener, ma_bool32 isEnabled); -MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener* pListener); - - -typedef struct -{ - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_channel* pChannelMapIn; - ma_attenuation_model attenuationModel; - ma_positioning positioning; - ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ - float minGain; - float maxGain; - float minDistance; - float maxDistance; - float rolloff; - float coneInnerAngleInRadians; - float coneOuterAngleInRadians; - float coneOuterGain; - float dopplerFactor; /* Set to 0 to disable doppler effect. */ - float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */ - float minSpatializationChannelGain; /* The minimal scaling factor to apply to channel gains when accounting for the direction of the sound relative to the listener. Must be in the range of 0..1. Smaller values means more aggressive directional panning, larger values means more subtle directional panning. */ - ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ -} ma_spatializer_config; - -MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma_uint32 channelsOut); - - -typedef struct -{ - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_channel* pChannelMapIn; - ma_attenuation_model attenuationModel; - ma_positioning positioning; - ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ - float minGain; - float maxGain; - float minDistance; - float maxDistance; - float rolloff; - float coneInnerAngleInRadians; - float coneOuterAngleInRadians; - float coneOuterGain; - float dopplerFactor; /* Set to 0 to disable doppler effect. */ - float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */ - ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ - ma_atomic_vec3f position; - ma_atomic_vec3f direction; - ma_atomic_vec3f velocity; /* For doppler effect. */ - float dopplerPitch; /* Will be updated by ma_spatializer_process_pcm_frames() and can be used by higher level functions to apply a pitch shift for doppler effect. */ - float minSpatializationChannelGain; - ma_gainer gainer; /* For smooth gain transitions. */ - float* pNewChannelGainsOut; /* An offset of _pHeap. Used by ma_spatializer_process_pcm_frames() to store new channel gains. The number of elements in this array is equal to config.channelsOut. */ - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; -} ma_spatializer; - -MA_API ma_result ma_spatializer_get_heap_size(const ma_spatializer_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* pConfig, void* pHeap, ma_spatializer* pSpatializer); -MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer); -MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); -MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer, float volume); -MA_API ma_result ma_spatializer_get_master_volume(const ma_spatializer* pSpatializer, float* pVolume); -MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer); -MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel); -MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning); -MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff); -MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain); -MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain); -MA_API float ma_spatializer_get_max_gain(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_min_distance(ma_spatializer* pSpatializer, float minDistance); -MA_API float ma_spatializer_get_min_distance(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float maxDistance); -MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAngleInRadians, float outerAngleInRadians, float outerGain); -MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); -MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor); -MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor); -MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z); -MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer); -MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir); - - - /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -5319,111 +2423,80 @@ typedef struct ma_uint32 inTimeFrac; union { - float* f32; - ma_int16* s16; + float f32[MA_MAX_CHANNELS]; + ma_int16 s16[MA_MAX_CHANNELS]; } x0; /* The previous input frame. */ union { - float* f32; - ma_int16* s16; + float f32[MA_MAX_CHANNELS]; + ma_int16 s16[MA_MAX_CHANNELS]; } x1; /* The next input frame. */ ma_lpf lpf; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; } ma_linear_resampler; -MA_API ma_result ma_linear_resampler_get_heap_size(const ma_linear_resampler_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler_config* pConfig, void* pHeap, ma_linear_resampler* pResampler); -MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler); -MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler); +MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler); MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut); +MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount); +MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount); MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler); MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler); -MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); -MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); -MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler); - - -typedef struct ma_resampler_config ma_resampler_config; - -typedef void ma_resampling_backend; -typedef struct -{ - ma_result (* onGetHeapSize )(void* pUserData, const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes); - ma_result (* onInit )(void* pUserData, const ma_resampler_config* pConfig, void* pHeap, ma_resampling_backend** ppBackend); - void (* onUninit )(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks); - ma_result (* onProcess )(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); - ma_result (* onSetRate )(void* pUserData, ma_resampling_backend* pBackend, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); /* Optional. Rate changes will be disabled. */ - ma_uint64 (* onGetInputLatency )(void* pUserData, const ma_resampling_backend* pBackend); /* Optional. Latency will be reported as 0. */ - ma_uint64 (* onGetOutputLatency )(void* pUserData, const ma_resampling_backend* pBackend); /* Optional. Latency will be reported as 0. */ - ma_result (* onGetRequiredInputFrameCount )(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); /* Optional. Latency mitigation will be disabled. */ - ma_result (* onGetExpectedOutputFrameCount)(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); /* Optional. Latency mitigation will be disabled. */ - ma_result (* onReset )(void* pUserData, ma_resampling_backend* pBackend); -} ma_resampling_backend_vtable; typedef enum { - ma_resample_algorithm_linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */ - ma_resample_algorithm_custom, + ma_resample_algorithm_linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */ + ma_resample_algorithm_speex } ma_resample_algorithm; -struct ma_resampler_config +typedef struct { ma_format format; /* Must be either ma_format_f32 or ma_format_s16. */ ma_uint32 channels; ma_uint32 sampleRateIn; ma_uint32 sampleRateOut; - ma_resample_algorithm algorithm; /* When set to ma_resample_algorithm_custom, pBackendVTable will be used. */ - ma_resampling_backend_vtable* pBackendVTable; - void* pBackendUserData; + ma_resample_algorithm algorithm; struct { ma_uint32 lpfOrder; + double lpfNyquistFactor; } linear; -}; + struct + { + int quality; /* 0 to 10. Defaults to 3. */ + } speex; +} ma_resampler_config; MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm); typedef struct { - ma_resampling_backend* pBackend; - ma_resampling_backend_vtable* pBackendVTable; - void* pBackendUserData; - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRateIn; - ma_uint32 sampleRateOut; + ma_resampler_config config; union { ma_linear_resampler linear; - } state; /* State for stock resamplers so we can avoid a malloc. For stock resamplers, pBackend will point here. */ - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + struct + { + void* pSpeexResamplerState; /* SpeexResamplerState* */ + } speex; + } state; } ma_resampler; -MA_API ma_result ma_resampler_get_heap_size(const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConfig, void* pHeap, ma_resampler* pResampler); - /* Initializes a new resampler object from a config. */ -MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resampler* pResampler); +MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler); /* Uninitializes a resampler. */ -MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API void ma_resampler_uninit(ma_resampler* pResampler); /* Converts the given input data. -Both the input and output frames must be in the format specified in the config when the resampler was initialized. +Both the input and output frames must be in the format specified in the config when the resampler was initilized. On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use @@ -5446,7 +2519,7 @@ MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const /* -Sets the input and output sample rate. +Sets the input and output sample sample rate. */ MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); @@ -5457,6 +2530,23 @@ The ration is in/out. */ MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio); + +/* +Calculates the number of whole input frames that would need to be read from the client in order to output the specified +number of output frames. + +The returned value does not include cached input frames. It only returns the number of extra frames that would need to be +read from the input buffer in order to output the specified number of output frames. +*/ +MA_API ma_uint64 ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount); + +/* +Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of +input frames. +*/ +MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount); + + /* Retrieves the latency introduced by the resampler in input frames. */ @@ -5467,25 +2557,6 @@ Retrieves the latency introduced by the resampler in output frames. */ MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler); -/* -Calculates the number of whole input frames that would need to be read from the client in order to output the specified -number of output frames. - -The returned value does not include cached input frames. It only returns the number of extra frames that would need to be -read from the input buffer in order to output the specified number of output frames. -*/ -MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); - -/* -Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of -input frames. -*/ -MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); - -/* -Resets the resampler's timer and clears its internal cache. -*/ -MA_API ma_result ma_resampler_reset(ma_resampler* pResampler); /************************************************************************************************************************************************************** @@ -5493,34 +2564,15 @@ MA_API ma_result ma_resampler_reset(ma_resampler* pResampler); Channel Conversion **************************************************************************************************************************************************************/ -typedef enum -{ - ma_channel_conversion_path_unknown, - ma_channel_conversion_path_passthrough, - ma_channel_conversion_path_mono_out, /* Converting to mono. */ - ma_channel_conversion_path_mono_in, /* Converting from mono. */ - ma_channel_conversion_path_shuffle, /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */ - ma_channel_conversion_path_weights /* Blended based on weights. */ -} ma_channel_conversion_path; - -typedef enum -{ - ma_mono_expansion_mode_duplicate = 0, /* The default. */ - ma_mono_expansion_mode_average, /* Average the mono channel across all channels. */ - ma_mono_expansion_mode_stereo_only, /* Duplicate to the left and right channels only and ignore the others. */ - ma_mono_expansion_mode_default = ma_mono_expansion_mode_duplicate -} ma_mono_expansion_mode; - typedef struct { ma_format format; ma_uint32 channelsIn; ma_uint32 channelsOut; - const ma_channel* pChannelMapIn; - const ma_channel* pChannelMapOut; + ma_channel channelMapIn[MA_MAX_CHANNELS]; + ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_channel_mix_mode mixingMode; - ma_bool32 calculateLFEFromSpatialChannels; /* When an output LFE channel is present, but no input LFE, set to true to set the output LFE to the average of all spatial channels (LR, FR, etc.). Ignored when an input LFE is present. */ - float** ppWeights; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ + float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ } ma_channel_converter_config; MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode); @@ -5530,29 +2582,24 @@ typedef struct ma_format format; ma_uint32 channelsIn; ma_uint32 channelsOut; + ma_channel channelMapIn[MA_MAX_CHANNELS]; + ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_channel_mix_mode mixingMode; - ma_channel_conversion_path conversionPath; - ma_channel* pChannelMapIn; - ma_channel* pChannelMapOut; - ma_uint8* pShuffleTable; /* Indexed by output channel index. */ union { - float** f32; - ma_int32** s16; - } weights; /* [in][out] */ - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; + float f32[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; + ma_int32 s16[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; + } weights; + ma_bool8 isPassthrough; + ma_bool8 isSimpleShuffle; + ma_bool8 isSimpleMonoExpansion; + ma_bool8 isStereoToMono; + ma_uint8 shuffleTable[MA_MAX_CHANNELS]; } ma_channel_converter; -MA_API ma_result ma_channel_converter_get_heap_size(const ma_channel_converter_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_converter_config* pConfig, void* pHeap, ma_channel_converter* pConverter); -MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_channel_converter* pConverter); -MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, ma_channel_converter* pConverter); +MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter); MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); -MA_API ma_result ma_channel_converter_get_input_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_channel_converter_get_output_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); /************************************************************************************************************************************************************** @@ -5568,40 +2615,33 @@ typedef struct ma_uint32 channelsOut; ma_uint32 sampleRateIn; ma_uint32 sampleRateOut; - ma_channel* pChannelMapIn; - ma_channel* pChannelMapOut; + ma_channel channelMapIn[MA_MAX_CHANNELS]; + ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_dither_mode ditherMode; ma_channel_mix_mode channelMixMode; - ma_bool32 calculateLFEFromSpatialChannels; /* When an output LFE channel is present, but no input LFE, set to true to set the output LFE to the average of all spatial channels (LR, FR, etc.). Ignored when an input LFE is present. */ - float** ppChannelWeights; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ - ma_bool32 allowDynamicSampleRate; - ma_resampler_config resampling; + float channelWeights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */ + struct + { + ma_resample_algorithm algorithm; + ma_bool32 allowDynamicSampleRate; + struct + { + ma_uint32 lpfOrder; + double lpfNyquistFactor; + } linear; + struct + { + int quality; + } speex; + } resampling; } ma_data_converter_config; MA_API ma_data_converter_config ma_data_converter_config_init_default(void); MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); - -typedef enum -{ - ma_data_converter_execution_path_passthrough, /* No conversion. */ - ma_data_converter_execution_path_format_only, /* Only format conversion. */ - ma_data_converter_execution_path_channels_only, /* Only channel conversion. */ - ma_data_converter_execution_path_resample_only, /* Only resampling. */ - ma_data_converter_execution_path_resample_first, /* All conversions, but resample as the first step. */ - ma_data_converter_execution_path_channels_first /* All conversions, but channels as the first step. */ -} ma_data_converter_execution_path; - typedef struct { - ma_format formatIn; - ma_format formatOut; - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_uint32 sampleRateIn; - ma_uint32 sampleRateOut; - ma_dither_mode ditherMode; - ma_data_converter_execution_path executionPath; /* The execution path the data converter will follow when processing. */ + ma_data_converter_config config; ma_channel_converter channelConverter; ma_resampler resampler; ma_bool8 hasPreFormatConversion; @@ -5609,26 +2649,17 @@ typedef struct ma_bool8 hasChannelConverter; ma_bool8 hasResampler; ma_bool8 isPassthrough; - - /* Memory management. */ - ma_bool8 _ownsHeap; - void* _pHeap; } ma_data_converter; -MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter); -MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter); -MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, ma_data_converter* pConverter); +MA_API void ma_data_converter_uninit(ma_data_converter* pConverter); MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut); +MA_API ma_uint64 ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount); +MA_API ma_uint64 ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount); MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter); MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter); -MA_API ma_result ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); -MA_API ma_result ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); -MA_API ma_result ma_data_converter_get_input_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_data_converter_get_output_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_data_converter_reset(ma_data_converter* pConverter); /************************************************************************************************************************************************************ @@ -5675,36 +2706,25 @@ MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_ui Channel Maps ************************************************************************************************************************************************************/ -/* -This is used in the shuffle table to indicate that the channel index is undefined and should be ignored. -*/ -#define MA_CHANNEL_INDEX_NULL 255 - -/* -Retrieves the channel position of the specified channel in the given channel map. - -The pChannelMap parameter can be null, in which case miniaudio's default channel map will be assumed. -*/ -MA_API ma_channel ma_channel_map_get_channel(const ma_channel* pChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex); /* Initializes a blank channel map. When a blank channel map is specified anywhere it indicates that the native channel map should be used. */ -MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channels); +MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap); /* Helper for retrieving a standard channel map. -The output channel map buffer must have a capacity of at least `channelMapCap`. +The output channel map buffer must have a capacity of at least `channels`. */ -MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels); +MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap); /* Copies a channel map. -Both input and output channel map buffers must have a capacity of at least `channels`. +Both input and output channel map buffers must have a capacity of at at least `channels`. */ MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); @@ -5713,7 +2733,7 @@ Copies a channel map if one is specified, otherwise copies the default channel m The output buffer must have a capacity of at least `channels`. If not NULL, the input channel map must also have a capacity of at least `channels`. */ -MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels); +MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); /* @@ -5728,7 +2748,7 @@ Invalid channel maps: The channel map buffer must have a capacity of at least `channels`. */ -MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels); +MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap); /* Helper for comparing two channel maps for equality. @@ -5737,14 +2757,14 @@ This assumes the channel count is the same between the two. Both channels map buffers must have a capacity of at least `channels`. */ -MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels); +MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB); /* Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE). The channel map buffer must have a capacity of at least `channels`. */ -MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels); +MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap); /* Helper for determining whether or not a channel is present in the given channel map. @@ -5753,28 +2773,6 @@ The channel map buffer must have a capacity of at least `channels`. */ MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition); -/* -Find a channel position in the given channel map. Returns MA_TRUE if the channel is found; MA_FALSE otherwise. The -index of the channel is output to `pChannelIndex`. - -The channel map buffer must have a capacity of at least `channels`. -*/ -MA_API ma_bool32 ma_channel_map_find_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition, ma_uint32* pChannelIndex); - -/* -Generates a string representing the given channel map. - -This is for printing and debugging purposes, not serialization/deserialization. - -Returns the length of the string, not including the null terminator. -*/ -MA_API size_t ma_channel_map_to_string(const ma_channel* pChannelMap, ma_uint32 channels, char* pBufferOut, size_t bufferCap); - -/* -Retrieves a human readable version of a channel position. -*/ -MA_API const char* ma_channel_position_to_string(ma_channel channel); - /************************************************************************************************************************************************************ @@ -5795,199 +2793,6 @@ MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_forma MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig); -/************************************************************************************************************************************************************ - -Data Source - -************************************************************************************************************************************************************/ -typedef void ma_data_source; - -#define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 0x00000001 - -typedef struct -{ - ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); - ma_result (* onSeek)(ma_data_source* pDataSource, ma_uint64 frameIndex); - ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); - ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor); - ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength); - ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping); - ma_uint32 flags; -} ma_data_source_vtable; - -typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource); - -typedef struct -{ - const ma_data_source_vtable* vtable; -} ma_data_source_config; - -MA_API ma_data_source_config ma_data_source_config_init(void); - - -typedef struct -{ - const ma_data_source_vtable* vtable; - ma_uint64 rangeBegInFrames; - ma_uint64 rangeEndInFrames; /* Set to -1 for unranged (default). */ - ma_uint64 loopBegInFrames; /* Relative to rangeBegInFrames. */ - ma_uint64 loopEndInFrames; /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */ - ma_data_source* pCurrent; /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */ - ma_data_source* pNext; /* When set to NULL, onGetNext will be used. */ - ma_data_source_get_next_proc onGetNext; /* Will be used when pNext is NULL. If both are NULL, no next will be used. */ - MA_ATOMIC(4, ma_bool32) isLooping; -} ma_data_source_base; - -MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource); -MA_API void ma_data_source_uninit(ma_data_source* pDataSource); -MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ -MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */ -MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex); -MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked); /* Can only seek forward. Abstraction to ma_data_source_seek_pcm_frames() */ -MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds); /* Abstraction to ma_data_source_seek_to_pcm_frame() */ -MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor); -MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ -MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor); -MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength); -MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping); -MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source* pDataSource); -MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames); -MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames); -MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames); -MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames); -MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource); -MA_API ma_data_source* ma_data_source_get_current(const ma_data_source* pDataSource); -MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource); -MA_API ma_data_source* ma_data_source_get_next(const ma_data_source* pDataSource); -MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext); -MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source* pDataSource); - - -typedef struct -{ - ma_data_source_base ds; - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_uint64 cursor; - ma_uint64 sizeInFrames; - const void* pData; -} ma_audio_buffer_ref; - -MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef); -MA_API void ma_audio_buffer_ref_uninit(ma_audio_buffer_ref* pAudioBufferRef); -MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames); -MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop); -MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex); -MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount); -MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ -MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef); -MA_API ma_result ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pCursor); -MA_API ma_result ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pLength); -MA_API ma_result ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames); - - - -typedef struct -{ - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_uint64 sizeInFrames; - const void* pData; /* If set to NULL, will allocate a block of memory for you. */ - ma_allocation_callbacks allocationCallbacks; -} ma_audio_buffer_config; - -MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint64 sizeInFrames, const void* pData, const ma_allocation_callbacks* pAllocationCallbacks); - -typedef struct -{ - ma_audio_buffer_ref ref; - ma_allocation_callbacks allocationCallbacks; - ma_bool32 ownsData; /* Used to control whether or not miniaudio owns the data buffer. If set to true, pData will be freed in ma_audio_buffer_uninit(). */ - ma_uint8 _pExtraData[1]; /* For allocating a buffer with the memory located directly after the other memory of the structure. */ -} ma_audio_buffer; - -MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer); -MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer); -MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer); /* Always copies the data. Doesn't make sense to use this otherwise. Use ma_audio_buffer_uninit_and_free() to uninit. */ -MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer); -MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer); -MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop); -MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex); -MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount); -MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ -MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer); -MA_API ma_result ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pCursor); -MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pLength); -MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames); - - -/* -Paged Audio Buffer -================== -A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It -can be used for cases where audio data is streamed in asynchronously while allowing data to be read -at the same time. - -This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across -simultaneously across different threads, however only one thread at a time can append, and only one -thread at a time can read and seek. -*/ -typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page; -struct ma_paged_audio_buffer_page -{ - MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pNext; - ma_uint64 sizeInFrames; - ma_uint8 pAudioData[1]; -}; - -typedef struct -{ - ma_format format; - ma_uint32 channels; - ma_paged_audio_buffer_page head; /* Dummy head for the lock-free algorithm. Always has a size of 0. */ - MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pTail; /* Never null. Initially set to &head. */ -} ma_paged_audio_buffer_data; - -MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData); -MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData); -MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData); -MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength); -MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage); -MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage); -MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks); - - -typedef struct -{ - ma_paged_audio_buffer_data* pData; /* Must not be null. */ -} ma_paged_audio_buffer_config; - -MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData); - - -typedef struct -{ - ma_data_source_base ds; - ma_paged_audio_buffer_data* pData; /* Audio data is read from here. Cannot be null. */ - ma_paged_audio_buffer_page* pCurrent; - ma_uint64 relativeCursor; /* Relative to the current page. */ - ma_uint64 absoluteCursor; -} ma_paged_audio_buffer; - -MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer); -MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer); -MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Returns MA_AT_END if no more pages available. */ -MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex); -MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor); -MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength); - - - /************************************************************************************************************************************************************ Ring Buffer @@ -5999,10 +2804,10 @@ typedef struct ma_uint32 subbufferSizeInBytes; ma_uint32 subbufferCount; ma_uint32 subbufferStrideInBytes; - MA_ATOMIC(4, ma_uint32) encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ - MA_ATOMIC(4, ma_uint32) encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ - ma_bool8 ownsBuffer; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */ - ma_bool8 clearOnWriteAcquire; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */ + MA_ATOMIC ma_uint32 encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ + MA_ATOMIC ma_uint32 encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ + ma_bool8 ownsBuffer; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */ + ma_bool8 clearOnWriteAcquire; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */ ma_allocation_callbacks allocationCallbacks; } ma_rb; @@ -6011,9 +2816,9 @@ MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocate MA_API void ma_rb_uninit(ma_rb* pRB); MA_API void ma_rb_reset(ma_rb* pRB); MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut); -MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes); +MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut); MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut); -MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes); +MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut); MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes); MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes); MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB); /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hits the write pointer. */ @@ -6027,11 +2832,9 @@ MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pB typedef struct { - ma_data_source_base ds; ma_rb rb; ma_format format; ma_uint32 channels; - ma_uint32 sampleRate; /* Not required for the ring buffer itself, but useful for associating the data with some sample rate, particularly for data sources. */ } ma_pcm_rb; MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB); @@ -6039,9 +2842,9 @@ MA_API ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB); MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB); MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut); -MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames); +MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut); MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut); -MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames); +MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut); MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames); MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames); MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB); /* Return value is in frames. */ @@ -6051,10 +2854,6 @@ MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB); MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB); MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex); MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer); -MA_API ma_format ma_pcm_rb_get_format(const ma_pcm_rb* pRB); -MA_API ma_uint32 ma_pcm_rb_get_channels(const ma_pcm_rb* pRB); -MA_API ma_uint32 ma_pcm_rb_get_sample_rate(const ma_pcm_rb* pRB); -MA_API void ma_pcm_rb_set_sample_rate(ma_pcm_rb* pRB, ma_uint32 sampleRate); /* @@ -6087,22 +2886,17 @@ Retrieves a human readable description of the given result code. MA_API const char* ma_result_description(ma_result result); /* -malloc() +malloc(). Calls MA_MALLOC(). */ MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); /* -calloc() -*/ -MA_API void* ma_calloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); - -/* -realloc() +realloc(). Calls MA_REALLOC(). */ MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); /* -free() +free(). Calls MA_FREE(). */ MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); @@ -6144,419 +2938,6 @@ MA_API const char* ma_log_level_to_string(ma_uint32 logLevel); - -/************************************************************************************************************************************************************ - -Synchronization - -************************************************************************************************************************************************************/ -/* -Locks a spinlock. -*/ -MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock); - -/* -Locks a spinlock, but does not yield() when looping. -*/ -MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock); - -/* -Unlocks a spinlock. -*/ -MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock); - - -#ifndef MA_NO_THREADING - -/* -Creates a mutex. - -A mutex must be created from a valid context. A mutex is initially unlocked. -*/ -MA_API ma_result ma_mutex_init(ma_mutex* pMutex); - -/* -Deletes a mutex. -*/ -MA_API void ma_mutex_uninit(ma_mutex* pMutex); - -/* -Locks a mutex with an infinite timeout. -*/ -MA_API void ma_mutex_lock(ma_mutex* pMutex); - -/* -Unlocks a mutex. -*/ -MA_API void ma_mutex_unlock(ma_mutex* pMutex); - - -/* -Initializes an auto-reset event. -*/ -MA_API ma_result ma_event_init(ma_event* pEvent); - -/* -Uninitializes an auto-reset event. -*/ -MA_API void ma_event_uninit(ma_event* pEvent); - -/* -Waits for the specified auto-reset event to become signalled. -*/ -MA_API ma_result ma_event_wait(ma_event* pEvent); - -/* -Signals the specified auto-reset event. -*/ -MA_API ma_result ma_event_signal(ma_event* pEvent); - - -MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore); -MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore); -MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore); -MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore); -#endif /* MA_NO_THREADING */ - - -/* -Fence -===== -This locks while the counter is larger than 0. Counter can be incremented and decremented by any -thread, but care needs to be taken when waiting. It is possible for one thread to acquire the -fence just as another thread returns from ma_fence_wait(). - -The idea behind a fence is to allow you to wait for a group of operations to complete. When an -operation starts, the counter is incremented which locks the fence. When the operation completes, -the fence will be released which decrements the counter. ma_fence_wait() will block until the -counter hits zero. - -If threading is disabled, ma_fence_wait() will spin on the counter. -*/ -typedef struct -{ -#ifndef MA_NO_THREADING - ma_event e; -#endif - ma_uint32 counter; -} ma_fence; - -MA_API ma_result ma_fence_init(ma_fence* pFence); -MA_API void ma_fence_uninit(ma_fence* pFence); -MA_API ma_result ma_fence_acquire(ma_fence* pFence); /* Increment counter. */ -MA_API ma_result ma_fence_release(ma_fence* pFence); /* Decrement counter. */ -MA_API ma_result ma_fence_wait(ma_fence* pFence); /* Wait for counter to reach 0. */ - - - -/* -Notification callback for asynchronous operations. -*/ -typedef void ma_async_notification; - -typedef struct -{ - void (* onSignal)(ma_async_notification* pNotification); -} ma_async_notification_callbacks; - -MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification); - - -/* -Simple polling notification. - -This just sets a variable when the notification has been signalled which is then polled with ma_async_notification_poll_is_signalled() -*/ -typedef struct -{ - ma_async_notification_callbacks cb; - ma_bool32 signalled; -} ma_async_notification_poll; - -MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll); -MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll); - - -/* -Event Notification - -This uses an ma_event. If threading is disabled (MA_NO_THREADING), initialization will fail. -*/ -typedef struct -{ - ma_async_notification_callbacks cb; -#ifndef MA_NO_THREADING - ma_event e; -#endif -} ma_async_notification_event; - -MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent); -MA_API ma_result ma_async_notification_event_uninit(ma_async_notification_event* pNotificationEvent); -MA_API ma_result ma_async_notification_event_wait(ma_async_notification_event* pNotificationEvent); -MA_API ma_result ma_async_notification_event_signal(ma_async_notification_event* pNotificationEvent); - - - - -/************************************************************************************************************************************************************ - -Job Queue - -************************************************************************************************************************************************************/ - -/* -Slot Allocator --------------- -The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocate an index that can be used -as the insertion point for an object. - -Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs. - -The slot index is stored in the low 32 bits. The reference counter is stored in the high 32 bits: - - +-----------------+-----------------+ - | 32 Bits | 32 Bits | - +-----------------+-----------------+ - | Reference Count | Slot Index | - +-----------------+-----------------+ -*/ -typedef struct -{ - ma_uint32 capacity; /* The number of slots to make available. */ -} ma_slot_allocator_config; - -MA_API ma_slot_allocator_config ma_slot_allocator_config_init(ma_uint32 capacity); - - -typedef struct -{ - MA_ATOMIC(4, ma_uint32) bitfield; /* Must be used atomically because the allocation and freeing routines need to make copies of this which must never be optimized away by the compiler. */ -} ma_slot_allocator_group; - -typedef struct -{ - ma_slot_allocator_group* pGroups; /* Slots are grouped in chunks of 32. */ - ma_uint32* pSlots; /* 32 bits for reference counting for ABA mitigation. */ - ma_uint32 count; /* Allocation count. */ - ma_uint32 capacity; - - /* Memory management. */ - ma_bool32 _ownsHeap; - void* _pHeap; -} ma_slot_allocator; - -MA_API ma_result ma_slot_allocator_get_heap_size(const ma_slot_allocator_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_slot_allocator_init_preallocated(const ma_slot_allocator_config* pConfig, void* pHeap, ma_slot_allocator* pAllocator); -MA_API ma_result ma_slot_allocator_init(const ma_slot_allocator_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_slot_allocator* pAllocator); -MA_API void ma_slot_allocator_uninit(ma_slot_allocator* pAllocator, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint64* pSlot); -MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot); - - -typedef struct ma_job ma_job; - -/* -Callback for processing a job. Each job type will have their own processing callback which will be -called by ma_job_process(). -*/ -typedef ma_result (* ma_job_proc)(ma_job* pJob); - -/* When a job type is added here an callback needs to be added go "g_jobVTable" in the implementation section. */ -typedef enum -{ - /* Miscellaneous. */ - MA_JOB_TYPE_QUIT = 0, - MA_JOB_TYPE_CUSTOM, - - /* Resource Manager. */ - MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE, - MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE, - MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE, - MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER, - MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER, - MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM, - MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM, - MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM, - MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM, - - /* Device. */ - MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE, - - /* Count. Must always be last. */ - MA_JOB_TYPE_COUNT -} ma_job_type; - -struct ma_job -{ - union - { - struct - { - ma_uint16 code; /* Job type. */ - ma_uint16 slot; /* Index into a ma_slot_allocator. */ - ma_uint32 refcount; - } breakup; - ma_uint64 allocation; - } toc; /* 8 bytes. We encode the job code into the slot allocation data to save space. */ - MA_ATOMIC(8, ma_uint64) next; /* refcount + slot for the next item. Does not include the job code. */ - ma_uint32 order; /* Execution order. Used to create a data dependency and ensure a job is executed in order. Usage is contextual depending on the job type. */ - - union - { - /* Miscellaneous. */ - struct - { - ma_job_proc proc; - ma_uintptr data0; - ma_uintptr data1; - } custom; - - /* Resource Manager */ - union - { - struct - { - /*ma_resource_manager**/ void* pResourceManager; - /*ma_resource_manager_data_buffer_node**/ void* pDataBufferNode; - char* pFilePath; - wchar_t* pFilePathW; - ma_uint32 flags; /* Resource manager data source flags that were used when initializing the data buffer. */ - ma_async_notification* pInitNotification; /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */ - ma_async_notification* pDoneNotification; /* Signalled when the data buffer has been fully decoded. Will be passed through to MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE when decoding. */ - ma_fence* pInitFence; /* Released when initialization of the decoder is complete. */ - ma_fence* pDoneFence; /* Released if initialization of the decoder fails. Passed through to PAGE_DATA_BUFFER_NODE untouched if init is successful. */ - } loadDataBufferNode; - struct - { - /*ma_resource_manager**/ void* pResourceManager; - /*ma_resource_manager_data_buffer_node**/ void* pDataBufferNode; - ma_async_notification* pDoneNotification; - ma_fence* pDoneFence; - } freeDataBufferNode; - struct - { - /*ma_resource_manager**/ void* pResourceManager; - /*ma_resource_manager_data_buffer_node**/ void* pDataBufferNode; - /*ma_decoder**/ void* pDecoder; - ma_async_notification* pDoneNotification; /* Signalled when the data buffer has been fully decoded. */ - ma_fence* pDoneFence; /* Passed through from LOAD_DATA_BUFFER_NODE and released when the data buffer completes decoding or an error occurs. */ - } pageDataBufferNode; - - struct - { - /*ma_resource_manager_data_buffer**/ void* pDataBuffer; - ma_async_notification* pInitNotification; /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */ - ma_async_notification* pDoneNotification; /* Signalled when the data buffer has been fully decoded. */ - ma_fence* pInitFence; /* Released when the data buffer has been initialized and the format/channels/rate can be retrieved. */ - ma_fence* pDoneFence; /* Released when the data buffer has been fully decoded. */ - ma_uint64 rangeBegInPCMFrames; - ma_uint64 rangeEndInPCMFrames; - ma_uint64 loopPointBegInPCMFrames; - ma_uint64 loopPointEndInPCMFrames; - ma_uint32 isLooping; - } loadDataBuffer; - struct - { - /*ma_resource_manager_data_buffer**/ void* pDataBuffer; - ma_async_notification* pDoneNotification; - ma_fence* pDoneFence; - } freeDataBuffer; - - struct - { - /*ma_resource_manager_data_stream**/ void* pDataStream; - char* pFilePath; /* Allocated when the job is posted, freed by the job thread after loading. */ - wchar_t* pFilePathW; /* ^ As above ^. Only used if pFilePath is NULL. */ - ma_uint64 initialSeekPoint; - ma_async_notification* pInitNotification; /* Signalled after the first two pages have been decoded and frames can be read from the stream. */ - ma_fence* pInitFence; - } loadDataStream; - struct - { - /*ma_resource_manager_data_stream**/ void* pDataStream; - ma_async_notification* pDoneNotification; - ma_fence* pDoneFence; - } freeDataStream; - struct - { - /*ma_resource_manager_data_stream**/ void* pDataStream; - ma_uint32 pageIndex; /* The index of the page to decode into. */ - } pageDataStream; - struct - { - /*ma_resource_manager_data_stream**/ void* pDataStream; - ma_uint64 frameIndex; - } seekDataStream; - } resourceManager; - - /* Device. */ - union - { - union - { - struct - { - /*ma_device**/ void* pDevice; - /*ma_device_type*/ ma_uint32 deviceType; - } reroute; - } aaudio; - } device; - } data; -}; - -MA_API ma_job ma_job_init(ma_uint16 code); -MA_API ma_result ma_job_process(ma_job* pJob); - - -/* -When set, ma_job_queue_next() will not wait and no semaphore will be signaled in -ma_job_queue_post(). ma_job_queue_next() will return MA_NO_DATA_AVAILABLE if nothing is available. - -This flag should always be used for platforms that do not support multithreading. -*/ -typedef enum -{ - MA_JOB_QUEUE_FLAG_NON_BLOCKING = 0x00000001 -} ma_job_queue_flags; - -typedef struct -{ - ma_uint32 flags; - ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. */ -} ma_job_queue_config; - -MA_API ma_job_queue_config ma_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity); - - -typedef struct -{ - ma_uint32 flags; /* Flags passed in at initialization time. */ - ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. Set by the config. */ - MA_ATOMIC(8, ma_uint64) head; /* The first item in the list. Required for removing from the top of the list. */ - MA_ATOMIC(8, ma_uint64) tail; /* The last item in the list. Required for appending to the end of the list. */ -#ifndef MA_NO_THREADING - ma_semaphore sem; /* Only used when MA_JOB_QUEUE_FLAG_NON_BLOCKING is unset. */ -#endif - ma_slot_allocator allocator; - ma_job* pJobs; -#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE - ma_spinlock lock; -#endif - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; -} ma_job_queue; - -MA_API ma_result ma_job_queue_get_heap_size(const ma_job_queue_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_job_queue_init_preallocated(const ma_job_queue_config* pConfig, void* pHeap, ma_job_queue* pQueue); -MA_API ma_result ma_job_queue_init(const ma_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_job_queue* pQueue); -MA_API void ma_job_queue_uninit(ma_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_job_queue_post(ma_job_queue* pQueue, const ma_job* pJob); -MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob); /* Returns MA_CANCELLED if the next job is a quit job. */ - - - /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -6571,20 +2952,15 @@ This section contains the APIs for device playback and capture. Here is where yo /* Some backends are only supported on certain platforms. */ #if defined(MA_WIN32) #define MA_SUPPORT_WASAPI - - #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ + #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ #define MA_SUPPORT_DSOUND #define MA_SUPPORT_WINMM - - /* Don't enable JACK here if compiling with Cosmopolitan. It'll be enabled in the Linux section below. */ - #if !defined(__COSMOPOLITAN__) - #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ - #endif + #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ #endif #endif -#if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO) +#if defined(MA_UNIX) #if defined(MA_LINUX) - #if !defined(MA_ANDROID) && !defined(__COSMOPOLITAN__) /* ALSA is not supported on Android. */ + #if !defined(MA_ANDROID) /* ALSA is not supported on Android. */ #define MA_SUPPORT_ALSA #endif #endif @@ -6592,6 +2968,10 @@ This section contains the APIs for device playback and capture. Here is where yo #define MA_SUPPORT_PULSEAUDIO #define MA_SUPPORT_JACK #endif + #if defined(MA_ANDROID) + #define MA_SUPPORT_AAUDIO + #define MA_SUPPORT_OPENSL + #endif #if defined(__OpenBSD__) /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */ #define MA_SUPPORT_SNDIO /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */ #endif @@ -6602,10 +2982,6 @@ This section contains the APIs for device playback and capture. Here is where yo #define MA_SUPPORT_OSS /* Only support OSS on specific platforms with known support. */ #endif #endif -#if defined(MA_ANDROID) - #define MA_SUPPORT_AAUDIO - #define MA_SUPPORT_OPENSL -#endif #if defined(MA_APPLE) #define MA_SUPPORT_COREAUDIO #endif @@ -6668,17 +3044,11 @@ This section contains the APIs for device playback and capture. Here is where yo #define MA_HAS_NULL #endif -typedef enum -{ - ma_device_state_uninitialized = 0, - ma_device_state_stopped = 1, /* The device's default state after initialization. */ - ma_device_state_started = 2, /* The device is started and is requesting and/or delivering audio data. */ - ma_device_state_starting = 3, /* Transitioning from a stopped state to started. */ - ma_device_state_stopping = 4 /* Transitioning from a started state to stopped. */ -} ma_device_state; - -MA_ATOMIC_SAFE_TYPE_DECL(i32, 4, device_state) - +#define MA_STATE_UNINITIALIZED 0 +#define MA_STATE_STOPPED 1 /* The device's default state after initialization. */ +#define MA_STATE_STARTED 2 /* The device is started and is requesting and/or delivering audio data. */ +#define MA_STATE_STARTING 3 /* Transitioning from a stopped state to started. */ +#define MA_STATE_STOPPING 4 /* Transitioning from a started state to stopped. */ #ifdef MA_SUPPORT_WASAPI /* We need a IMMNotificationClient object for WASAPI. */ @@ -6713,115 +3083,6 @@ typedef enum #define MA_BACKEND_COUNT (ma_backend_null+1) -/* -Device job thread. This is used by backends that require asynchronous processing of certain -operations. It is not used by all backends. - -The device job thread is made up of a thread and a job queue. You can post a job to the thread with -ma_device_job_thread_post(). The thread will do the processing of the job. -*/ -typedef struct -{ - ma_bool32 noThread; /* Set this to true if you want to process jobs yourself. */ - ma_uint32 jobQueueCapacity; - ma_uint32 jobQueueFlags; -} ma_device_job_thread_config; - -MA_API ma_device_job_thread_config ma_device_job_thread_config_init(void); - -typedef struct -{ - ma_thread thread; - ma_job_queue jobQueue; - ma_bool32 _hasThread; -} ma_device_job_thread; - -MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_job_thread* pJobThread); -MA_API void ma_device_job_thread_uninit(ma_device_job_thread* pJobThread, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_device_job_thread_post(ma_device_job_thread* pJobThread, const ma_job* pJob); -MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_job* pJob); - - - -/* Device notification types. */ -typedef enum -{ - ma_device_notification_type_started, - ma_device_notification_type_stopped, - ma_device_notification_type_rerouted, - ma_device_notification_type_interruption_began, - ma_device_notification_type_interruption_ended, - ma_device_notification_type_unlocked -} ma_device_notification_type; - -typedef struct -{ - ma_device* pDevice; - ma_device_notification_type type; - union - { - struct - { - int _unused; - } started; - struct - { - int _unused; - } stopped; - struct - { - int _unused; - } rerouted; - struct - { - int _unused; - } interruption; - } data; -} ma_device_notification; - -/* -The notification callback for when the application should be notified of a change to the device. - -This callback is used for notifying the application of changes such as when the device has started, -stopped, rerouted or an interruption has occurred. Note that not all backends will post all -notification types. For example, some backends will perform automatic stream routing without any -kind of notification to the host program which means miniaudio will never know about it and will -never be able to fire the rerouted notification. You should keep this in mind when designing your -program. - -The stopped notification will *not* get fired when a device is rerouted. - - -Parameters ----------- -pNotification (in) - A pointer to a structure containing information about the event. Use the `pDevice` member of - this object to retrieve the relevant device. The `type` member can be used to discriminate - against each of the notification types. - - -Remarks -------- -Do not restart or uninitialize the device from the callback. - -Not all notifications will be triggered by all backends, however the started and stopped events -should be reliable for all backends. Some backends do not have a good way to detect device -stoppages due to unplugging the device which may result in the stopped callback not getting -fired. This has been observed with at least one BSD variant. - -The rerouted notification is fired *after* the reroute has occurred. The stopped notification will -*not* get fired when a device is rerouted. The following backends are known to do automatic stream -rerouting, but do not have a way to be notified of the change: - - * DirectSound - -The interruption notifications are used on mobile platforms for detecting when audio is interrupted -due to things like an incoming phone call. Currently this is only implemented on iOS. None of the -Android backends will report this notification. -*/ -typedef void (* ma_device_notification_proc)(const ma_device_notification* pNotification); - - /* The callback for processing audio data from the device. @@ -6862,18 +3123,13 @@ callback. The following APIs cannot be called from inside the callback: The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread. */ -typedef void (* ma_device_data_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - - - +typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); /* -DEPRECATED. Use ma_device_notification_proc instead. - The callback for when the device has been stopped. This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces -such as being unplugged or an internal error occurring. +such as being unplugged or an internal error occuring. Parameters @@ -6886,7 +3142,41 @@ Remarks ------- Do not restart or uninitialize the device from the callback. */ -typedef void (* ma_stop_proc)(ma_device* pDevice); /* DEPRECATED. Use ma_device_notification_proc instead. */ +typedef void (* ma_stop_proc)(ma_device* pDevice); + +/* +The callback for handling log messages. + + +Parameters +---------- +pContext (in) + A pointer to the context the log message originated from. + +pDevice (in) + A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context. + +logLevel (in) + The log level. This can be one of the following: + + +----------------------+ + | Log Level | + +----------------------+ + | MA_LOG_LEVEL_VERBOSE | + | MA_LOG_LEVEL_INFO | + | MA_LOG_LEVEL_WARNING | + | MA_LOG_LEVEL_ERROR | + +----------------------+ + +message (in) + The log message. + + +Remarks +------- +Do not modify the state of the device from inside the callback. +*/ +typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message); typedef enum { @@ -6905,7 +3195,7 @@ typedef enum /* iOS/tvOS/watchOS session categories. */ typedef enum { - ma_ios_session_category_default = 0, /* AVAudioSessionCategoryPlayAndRecord. */ + ma_ios_session_category_default = 0, /* AVAudioSessionCategoryPlayAndRecord with AVAudioSessionCategoryOptionDefaultToSpeaker. */ ma_ios_session_category_none, /* Leave the session category unchanged. */ ma_ios_session_category_ambient, /* AVAudioSessionCategoryAmbient */ ma_ios_session_category_solo_ambient, /* AVAudioSessionCategorySoloAmbient */ @@ -6950,44 +3240,36 @@ typedef enum ma_opensl_recording_preset_voice_unprocessed /* SL_ANDROID_RECORDING_PRESET_UNPROCESSED */ } ma_opensl_recording_preset; -/* WASAPI audio thread priority characteristics. */ -typedef enum -{ - ma_wasapi_usage_default = 0, - ma_wasapi_usage_games, - ma_wasapi_usage_pro_audio, -} ma_wasapi_usage; - /* AAudio usage types. */ typedef enum { ma_aaudio_usage_default = 0, /* Leaves the usage type unset. */ - ma_aaudio_usage_media, /* AAUDIO_USAGE_MEDIA */ - ma_aaudio_usage_voice_communication, /* AAUDIO_USAGE_VOICE_COMMUNICATION */ - ma_aaudio_usage_voice_communication_signalling, /* AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING */ - ma_aaudio_usage_alarm, /* AAUDIO_USAGE_ALARM */ - ma_aaudio_usage_notification, /* AAUDIO_USAGE_NOTIFICATION */ - ma_aaudio_usage_notification_ringtone, /* AAUDIO_USAGE_NOTIFICATION_RINGTONE */ - ma_aaudio_usage_notification_event, /* AAUDIO_USAGE_NOTIFICATION_EVENT */ - ma_aaudio_usage_assistance_accessibility, /* AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY */ - ma_aaudio_usage_assistance_navigation_guidance, /* AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */ - ma_aaudio_usage_assistance_sonification, /* AAUDIO_USAGE_ASSISTANCE_SONIFICATION */ - ma_aaudio_usage_game, /* AAUDIO_USAGE_GAME */ - ma_aaudio_usage_assitant, /* AAUDIO_USAGE_ASSISTANT */ + ma_aaudio_usage_announcement, /* AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT */ ma_aaudio_usage_emergency, /* AAUDIO_SYSTEM_USAGE_EMERGENCY */ ma_aaudio_usage_safety, /* AAUDIO_SYSTEM_USAGE_SAFETY */ ma_aaudio_usage_vehicle_status, /* AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS */ - ma_aaudio_usage_announcement /* AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT */ + ma_aaudio_usage_alarm, /* AAUDIO_USAGE_ALARM */ + ma_aaudio_usage_assistance_accessibility, /* AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY */ + ma_aaudio_usage_assistance_navigation_guidance, /* AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */ + ma_aaudio_usage_assistance_sonification, /* AAUDIO_USAGE_ASSISTANCE_SONIFICATION */ + ma_aaudio_usage_assitant, /* AAUDIO_USAGE_ASSISTANT */ + ma_aaudio_usage_game, /* AAUDIO_USAGE_GAME */ + ma_aaudio_usage_media, /* AAUDIO_USAGE_MEDIA */ + ma_aaudio_usage_notification, /* AAUDIO_USAGE_NOTIFICATION */ + ma_aaudio_usage_notification_event, /* AAUDIO_USAGE_NOTIFICATION_EVENT */ + ma_aaudio_usage_notification_ringtone, /* AAUDIO_USAGE_NOTIFICATION_RINGTONE */ + ma_aaudio_usage_voice_communication, /* AAUDIO_USAGE_VOICE_COMMUNICATION */ + ma_aaudio_usage_voice_communication_signalling /* AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING */ } ma_aaudio_usage; /* AAudio content types. */ typedef enum { ma_aaudio_content_type_default = 0, /* Leaves the content type unset. */ - ma_aaudio_content_type_speech, /* AAUDIO_CONTENT_TYPE_SPEECH */ - ma_aaudio_content_type_music, /* AAUDIO_CONTENT_TYPE_MUSIC */ ma_aaudio_content_type_movie, /* AAUDIO_CONTENT_TYPE_MOVIE */ - ma_aaudio_content_type_sonification /* AAUDIO_CONTENT_TYPE_SONIFICATION */ + ma_aaudio_content_type_music, /* AAUDIO_CONTENT_TYPE_MUSIC */ + ma_aaudio_content_type_sonification, /* AAUDIO_CONTENT_TYPE_SONIFICATION */ + ma_aaudio_content_type_speech /* AAUDIO_CONTENT_TYPE_SPEECH */ } ma_aaudio_content_type; /* AAudio input presets. */ @@ -6996,19 +3278,12 @@ typedef enum ma_aaudio_input_preset_default = 0, /* Leaves the input preset unset. */ ma_aaudio_input_preset_generic, /* AAUDIO_INPUT_PRESET_GENERIC */ ma_aaudio_input_preset_camcorder, /* AAUDIO_INPUT_PRESET_CAMCORDER */ + ma_aaudio_input_preset_unprocessed, /* AAUDIO_INPUT_PRESET_UNPROCESSED */ ma_aaudio_input_preset_voice_recognition, /* AAUDIO_INPUT_PRESET_VOICE_RECOGNITION */ ma_aaudio_input_preset_voice_communication, /* AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION */ - ma_aaudio_input_preset_unprocessed, /* AAUDIO_INPUT_PRESET_UNPROCESSED */ ma_aaudio_input_preset_voice_performance /* AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE */ } ma_aaudio_input_preset; -typedef enum -{ - ma_aaudio_allow_capture_default = 0, /* Leaves the allowed capture policy unset. */ - ma_aaudio_allow_capture_by_all, /* AAUDIO_ALLOW_CAPTURE_BY_ALL */ - ma_aaudio_allow_capture_by_system, /* AAUDIO_ALLOW_CAPTURE_BY_SYSTEM */ - ma_aaudio_allow_capture_by_none /* AAUDIO_ALLOW_CAPTURE_BY_NONE */ -} ma_aaudio_allowed_capture_policy; typedef union { @@ -7018,7 +3293,7 @@ typedef union typedef union { - ma_wchar_win32 wasapi[64]; /* WASAPI uses a wchar_t string for identification. */ + wchar_t wasapi[64]; /* WASAPI uses a wchar_t string for identification. */ ma_uint8 dsound[16]; /* DirectSound uses a GUID for identification. */ /*UINT_PTR*/ ma_uint32 winmm; /* When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. */ char alsa[256]; /* ALSA uses a name string for identification. */ @@ -7040,8 +3315,6 @@ typedef union int nullbackend; /* The null backend uses an integer for device IDs. */ } ma_device_id; -MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id* pB); - typedef struct ma_context_config ma_context_config; typedef struct ma_device_config ma_device_config; @@ -7049,17 +3322,30 @@ typedef struct ma_backend_callbacks ma_backend_callbacks; #define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */ -#ifndef MA_MAX_DEVICE_NAME_LENGTH -#define MA_MAX_DEVICE_NAME_LENGTH 255 -#endif - typedef struct { /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */ ma_device_id id; - char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* +1 for null terminator. */ + char name[256]; ma_bool32 isDefault; + /* + Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize + a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion + pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided + here mainly for informational purposes or in the rare case that someone might find it useful. + + These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices(). + */ + ma_uint32 formatCount; + ma_format formats[ma_format_count]; + ma_uint32 minChannels; + ma_uint32 maxChannels; + ma_uint32 minSampleRate; + ma_uint32 maxSampleRate; + + + /* Experimental. Don't use these right now. */ ma_uint32 nativeDataFormatCount; struct { @@ -7078,23 +3364,30 @@ struct ma_device_config ma_uint32 periodSizeInMilliseconds; ma_uint32 periods; ma_performance_profile performanceProfile; - ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */ - ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will not be clipped after returning. Only applies when the playback sample format is f32. */ - ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */ - ma_bool8 noFixedSizedCallback; /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */ - ma_device_data_proc dataCallback; - ma_device_notification_proc notificationCallback; + ma_bool8 noPreZeroedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */ + ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ + ma_device_callback_proc dataCallback; ma_stop_proc stopCallback; void* pUserData; - ma_resampler_config resampling; + struct + { + ma_resample_algorithm algorithm; + struct + { + ma_uint32 lpfOrder; + } linear; + struct + { + int quality; + } speex; + } resampling; struct { const ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; - ma_channel* pChannelMap; + ma_channel channelMap[MA_MAX_CHANNELS]; ma_channel_mix_mode channelMixMode; - ma_bool32 calculateLFEFromSpatialChannels; /* When an output LFE channel is present, but no input LFE, set to true to set the output LFE to the average of all spatial channels (LR, FR, etc.). Ignored when an input LFE is present. */ ma_share_mode shareMode; } playback; struct @@ -7102,21 +3395,17 @@ struct ma_device_config const ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; - ma_channel* pChannelMap; + ma_channel channelMap[MA_MAX_CHANNELS]; ma_channel_mix_mode channelMixMode; - ma_bool32 calculateLFEFromSpatialChannels; /* When an output LFE channel is present, but no input LFE, set to true to set the output LFE to the average of all spatial channels (LR, FR, etc.). Ignored when an input LFE is present. */ ma_share_mode shareMode; } capture; struct { - ma_wasapi_usage usage; /* When configured, uses Avrt APIs to set the thread characteristics. */ - ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ - ma_bool8 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */ - ma_bool8 noAutoStreamRouting; /* Disables automatic stream routing. */ - ma_bool8 noHardwareOffloading; /* Disables WASAPI's hardware offloading feature. */ - ma_uint32 loopbackProcessID; /* The process ID to include or exclude for loopback mode. Set to 0 to capture audio from all processes. Ignored when an explicit device ID is specified. */ - ma_bool8 loopbackProcessExclude; /* When set to true, excludes the process specified by loopbackProcessID. By default, the process will be included. */ + ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ + ma_bool8 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */ + ma_bool8 noAutoStreamRouting; /* Disables automatic stream routing. */ + ma_bool8 noHardwareOffloading; /* Disables WASAPI's hardware offloading feature. */ } wasapi; struct { @@ -7129,7 +3418,6 @@ struct ma_device_config { const char* pStreamNamePlayback; const char* pStreamNameCapture; - int channelMap; } pulse; struct { @@ -7139,23 +3427,18 @@ struct ma_device_config { ma_opensl_stream_type streamType; ma_opensl_recording_preset recordingPreset; - ma_bool32 enableCompatibilityWorkarounds; } opensl; struct { ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; - ma_aaudio_allowed_capture_policy allowedCapturePolicy; - ma_bool32 noAutoStartAfterReroute; - ma_bool32 enableCompatibilityWorkarounds; - ma_bool32 allowSetBufferCapacity; } aaudio; }; /* -The callback for handling device enumeration. This is fired from `ma_context_enumerate_devices()`. +The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`. Parameters @@ -7215,14 +3498,14 @@ callbacks defined in this structure. Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration -needs to stop and the `onContextEnumerateDevices()` function returns with a success code. +needs to stop and the `onContextEnumerateDevices()` function return with a success code. Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID, and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the case when the device ID is NULL, in which case information about the default device needs to be retrieved. Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created. -This is a little bit more complicated than initialization of the context due to its more complicated configuration. When initializing a +This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input, the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to the requested format. The conversion between the format requested by the application and the device's native format will be handled @@ -7230,11 +3513,11 @@ internally by miniaudio. On input, if the sample format is set to `ma_format_unknown`, the backend is free to use whatever sample format it desires, so long as it's supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for -sample rate. For the channel map, the default should be used when `ma_channel_map_is_blank()` returns true (all channels set to +sample rate. For the channel map, the default should be used when `ma_channel_map_blank()` returns true (all channels set to `MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the -sample rate will need to be determined before calculating the period size in frames. On output, all members of the `ma_device_descriptor` +sample rate will need to be determined before calculating the period size in frames. On output, all members of the `ma_device_data_format` object should be set to a valid value, except for `periodSizeInMilliseconds` which is optional (`periodSizeInFrames` *must* be set). Starting and stopping of the device is done with `onDeviceStart()` and `onDeviceStop()` and should be self-explanatory. If the backend uses @@ -7243,23 +3526,20 @@ asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and `onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the -backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within its callback. +backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback. This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback. -If the backend requires absolute flexibility with its data delivery, it can optionally implement the `onDeviceDataLoop()` callback +If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceWorkerThread()` callback which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional. -The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been -encountered. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback. +The audio thread should run data delivery logic in a loop while `ma_device_get_state() == MA_STATE_STARTED` and no errors have been +encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback. The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this -callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated +callback. When the device is stopped, the `ma_device_get_state() == MA_STATE_STARTED` condition will fail and the loop will be terminated which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback, look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to wake up the audio thread. - -If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the -`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient. */ struct ma_backend_callbacks { @@ -7275,21 +3555,16 @@ struct ma_backend_callbacks ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten); ma_result (* onDeviceDataLoop)(ma_device* pDevice); ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice); - ma_result (* onDeviceGetInfo)(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo); }; struct ma_context_config { - ma_log* pLog; + ma_log_proc logCallback; ma_thread_priority threadPriority; size_t threadStackSize; void* pUserData; ma_allocation_callbacks allocationCallbacks; struct - { - ma_handle hWnd; /* HWND. Optional window handle to pass into SetCooperativeLevel(). Will default to the foreground window, and if that fails, the desktop window. */ - } dsound; - struct { ma_bool32 useVerboseDeviceEnumeration; } alsa; @@ -7330,7 +3605,7 @@ typedef struct ma_device_type deviceType; void* pAudioClient; void** ppAudioClientService; - ma_result* pResult; /* The result from creating the audio client service. */ + ma_result result; /* The result from creating the audio client service. */ } createAudioClient; struct { @@ -7344,8 +3619,7 @@ struct ma_context { ma_backend_callbacks callbacks; ma_backend backend; /* DirectSound, ALSA, etc. */ - ma_log* pLog; - ma_log log; /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */ + ma_log_proc logCallback; ma_thread_priority threadPriority; size_t threadStackSize; void* pUserData; @@ -7368,17 +3642,11 @@ struct ma_context ma_uint32 commandIndex; ma_uint32 commandCount; ma_context_command__wasapi commands[4]; - ma_handle hAvrt; - ma_proc AvSetMmThreadCharacteristicsA; - ma_proc AvRevertMmThreadcharacteristics; - ma_handle hMMDevapi; - ma_proc ActivateAudioInterfaceAsync; } wasapi; #endif #ifdef MA_SUPPORT_DSOUND struct { - ma_handle hWnd; /* Can be null. */ ma_handle hDSoundDLL; ma_proc DirectSoundCreate; ma_proc DirectSoundEnumerateA; @@ -7458,7 +3726,6 @@ struct ma_context ma_proc snd_pcm_start; ma_proc snd_pcm_drop; ma_proc snd_pcm_drain; - ma_proc snd_pcm_reset; ma_proc snd_device_name_hint; ma_proc snd_device_name_get_hint; ma_proc snd_card_get_index; @@ -7471,13 +3738,9 @@ struct ma_context ma_proc snd_pcm_avail; ma_proc snd_pcm_avail_update; ma_proc snd_pcm_wait; - ma_proc snd_pcm_nonblock; ma_proc snd_pcm_info; ma_proc snd_pcm_info_sizeof; ma_proc snd_pcm_info_get_name; - ma_proc snd_pcm_poll_descriptors; - ma_proc snd_pcm_poll_descriptors_count; - ma_proc snd_pcm_poll_descriptors_revents; ma_proc snd_config_update_free_global; ma_mutex internalDeviceEnumLock; @@ -7535,9 +3798,6 @@ struct ma_context ma_proc pa_stream_get_device_name; ma_proc pa_stream_set_write_callback; ma_proc pa_stream_set_read_callback; - ma_proc pa_stream_set_suspended_callback; - ma_proc pa_stream_set_moved_callback; - ma_proc pa_stream_is_suspended; ma_proc pa_stream_flush; ma_proc pa_stream_drain; ma_proc pa_stream_is_corked; @@ -7552,8 +3812,6 @@ struct ma_context /*pa_mainloop**/ ma_ptr pMainLoop; /*pa_context**/ ma_ptr pPulseContext; - char* pApplicationName; /* Set when the context is initialized. Used by devices for their local pa_context objects. */ - char* pServerName; /* Set when the context is initialized. Used by devices for their local pa_context objects. */ } pulse; #endif #ifdef MA_SUPPORT_JACK @@ -7668,7 +3926,6 @@ struct ma_context ma_proc AAudioStreamBuilder_setUsage; ma_proc AAudioStreamBuilder_setContentType; ma_proc AAudioStreamBuilder_setInputPreset; - ma_proc AAudioStreamBuilder_setAllowedCapturePolicy; ma_proc AAudioStreamBuilder_openStream; ma_proc AAudioStream_close; ma_proc AAudioStream_getState; @@ -7681,7 +3938,6 @@ struct ma_context ma_proc AAudioStream_getFramesPerBurst; ma_proc AAudioStream_requestStart; ma_proc AAudioStream_requestStop; - ma_device_job_thread jobThread; /* For processing operations outside of the error callback, specifically device disconnections and rerouting. */ } aaudio; #endif #ifdef MA_SUPPORT_OPENSL @@ -7714,11 +3970,10 @@ struct ma_context union { -#if defined(MA_WIN32) +#ifdef MA_WIN32 struct { /*HMODULE*/ ma_handle hOle32DLL; - ma_proc CoInitialize; ma_proc CoInitializeEx; ma_proc CoUninitialize; ma_proc CoCreateInstance; @@ -7734,14 +3989,27 @@ struct ma_context ma_proc RegOpenKeyExA; ma_proc RegCloseKey; ma_proc RegQueryValueExA; - - /*HRESULT*/ long CoInitializeResult; } win32; #endif #ifdef MA_POSIX struct { - int _unused; + ma_handle pthreadSO; + ma_proc pthread_create; + ma_proc pthread_join; + ma_proc pthread_mutex_init; + ma_proc pthread_mutex_destroy; + ma_proc pthread_mutex_lock; + ma_proc pthread_mutex_unlock; + ma_proc pthread_cond_init; + ma_proc pthread_cond_destroy; + ma_proc pthread_cond_wait; + ma_proc pthread_cond_signal; + ma_proc pthread_attr_init; + ma_proc pthread_attr_destroy; + ma_proc pthread_attr_setschedpolicy; + ma_proc pthread_attr_getschedparam; + ma_proc pthread_attr_setschedparam; } posix; #endif int _unused; @@ -7753,39 +4021,37 @@ struct ma_device ma_context* pContext; ma_device_type type; ma_uint32 sampleRate; - ma_atomic_device_state state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ - ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */ - ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */ - ma_stop_proc onStop; /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */ - void* pUserData; /* Application defined data. */ + MA_ATOMIC ma_uint32 state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ + ma_device_callback_proc onData; /* Set once at initialization time and should not be changed after. */ + ma_stop_proc onStop; /* Set once at initialization time and should not be changed after. */ + void* pUserData; /* Application defined data. */ ma_mutex startStopLock; ma_event wakeupEvent; ma_event startEvent; ma_event stopEvent; ma_thread thread; - ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */ - ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ - ma_bool8 noPreSilencedOutputBuffer; + ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */ + ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ + ma_bool8 noPreZeroedOutputBuffer; ma_bool8 noClip; - ma_bool8 noDisableDenormals; - ma_bool8 noFixedSizedCallback; - ma_atomic_float masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ - ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ + MA_ATOMIC float masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ + ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ struct { ma_resample_algorithm algorithm; - ma_resampling_backend_vtable* pBackendVTable; - void* pBackendUserData; struct { ma_uint32 lpfOrder; } linear; + struct + { + int quality; + } speex; } resampling; struct { - ma_device_id* pID; /* Set to NULL if using default ID, otherwise set to the address of "id". */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ - char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */ + char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_format format; ma_uint32 channels; @@ -7797,21 +4063,12 @@ struct ma_device ma_uint32 internalPeriodSizeInFrames; ma_uint32 internalPeriods; ma_channel_mix_mode channelMixMode; - ma_bool32 calculateLFEFromSpatialChannels; ma_data_converter converter; - void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */ - ma_uint32 intermediaryBufferCap; - ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */ - void* pInputCache; /* In external format. Can be null. */ - ma_uint64 inputCacheCap; - ma_uint64 inputCacheConsumed; - ma_uint64 inputCacheRemaining; } playback; struct { - ma_device_id* pID; /* Set to NULL if using default ID, otherwise set to the address of "id". */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ - char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */ + char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_format format; ma_uint32 channels; @@ -7823,11 +4080,7 @@ struct ma_device ma_uint32 internalPeriodSizeInFrames; ma_uint32 internalPeriods; ma_channel_mix_mode channelMixMode; - ma_bool32 calculateLFEFromSpatialChannels; ma_data_converter converter; - void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */ - ma_uint32 intermediaryBufferCap; - ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */ } capture; union @@ -7843,24 +4096,16 @@ struct ma_device ma_IMMNotificationClient notificationClient; /*HANDLE*/ ma_handle hEventPlayback; /* Auto reset. Initialized to signaled. */ /*HANDLE*/ ma_handle hEventCapture; /* Auto reset. Initialized to unsignaled. */ - ma_uint32 actualBufferSizeInFramesPlayback; /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ - ma_uint32 actualBufferSizeInFramesCapture; + ma_uint32 actualPeriodSizeInFramesPlayback; /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ + ma_uint32 actualPeriodSizeInFramesCapture; ma_uint32 originalPeriodSizeInFrames; ma_uint32 originalPeriodSizeInMilliseconds; ma_uint32 originalPeriods; ma_performance_profile originalPerformanceProfile; ma_uint32 periodSizeInFramesPlayback; ma_uint32 periodSizeInFramesCapture; - void* pMappedBufferCapture; - ma_uint32 mappedBufferCaptureCap; - ma_uint32 mappedBufferCaptureLen; - void* pMappedBufferPlayback; - ma_uint32 mappedBufferPlaybackCap; - ma_uint32 mappedBufferPlaybackLen; - ma_atomic_bool32 isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ - ma_atomic_bool32 isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ - ma_uint32 loopbackProcessID; - ma_bool8 loopbackProcessExclude; + MA_ATOMIC ma_bool32 isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + MA_ATOMIC ma_bool32 isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ ma_bool8 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */ ma_bool8 noHardwareOffloading; @@ -7868,9 +4113,6 @@ struct ma_device ma_bool8 allowPlaybackAutoStreamRouting; ma_bool8 isDetachedPlayback; ma_bool8 isDetachedCapture; - ma_wasapi_usage usage; - void* hAvrtHandle; - ma_mutex rerouteLock; } wasapi; #endif #ifdef MA_SUPPORT_DSOUND @@ -7907,12 +4149,6 @@ struct ma_device { /*snd_pcm_t**/ ma_ptr pPCMPlayback; /*snd_pcm_t**/ ma_ptr pPCMCapture; - /*struct pollfd**/ void* pPollDescriptorsPlayback; - /*struct pollfd**/ void* pPollDescriptorsCapture; - int pollDescriptorCountPlayback; - int pollDescriptorCountCapture; - int wakeupfdPlayback; /* eventfd for waking up from poll() when the playback device is stopped. */ - int wakeupfdCapture; /* eventfd for waking up from poll() when the capture device is stopped. */ ma_bool8 isUsingMMapPlayback; ma_bool8 isUsingMMapCapture; } alsa; @@ -7920,8 +4156,6 @@ struct ma_device #ifdef MA_SUPPORT_PULSEAUDIO struct { - /*pa_mainloop**/ ma_ptr pMainLoop; - /*pa_context**/ ma_ptr pPulseContext; /*pa_stream**/ ma_ptr pStreamPlayback; /*pa_stream**/ ma_ptr pStreamCapture; } pulse; @@ -7930,8 +4164,8 @@ struct ma_device struct { /*jack_client_t**/ ma_ptr pClient; - /*jack_port_t**/ ma_ptr* ppPortsPlayback; - /*jack_port_t**/ ma_ptr* ppPortsCapture; + /*jack_port_t**/ ma_ptr pPortsPlayback[MA_MAX_CHANNELS]; + /*jack_port_t**/ ma_ptr pPortsCapture[MA_MAX_CHANNELS]; float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */ float* pIntermediaryBufferCapture; } jack; @@ -7954,7 +4188,7 @@ struct ma_device ma_bool32 isDefaultCaptureDevice; ma_bool32 isSwitchingPlaybackDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ ma_bool32 isSwitchingCaptureDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ - void* pNotificationHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */ + void* pRouteChangeHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */ } coreaudio; #endif #ifdef MA_SUPPORT_SNDIO @@ -7985,12 +4219,6 @@ struct ma_device { /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; - ma_mutex rerouteLock; - ma_aaudio_usage usage; - ma_aaudio_content_type contentType; - ma_aaudio_input_preset inputPreset; - ma_aaudio_allowed_capture_policy allowedCapturePolicy; - ma_bool32 noAutoStartAfterReroute; } aaudio; #endif #ifdef MA_SUPPORT_OPENSL @@ -8015,13 +4243,8 @@ struct ma_device #ifdef MA_SUPPORT_WEBAUDIO struct { - /* AudioWorklets path. */ - /* EMSCRIPTEN_WEBAUDIO_T */ int audioContext; - /* EMSCRIPTEN_WEBAUDIO_T */ int audioWorklet; - float* pIntermediaryBuffer; - void* pStackBuffer; - ma_result initResult; /* Set to MA_BUSY while initialization is in progress. */ - int deviceIndex; /* We store the device in a list on the JavaScript side. This is used to map our C object to the JS object. */ + int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */ + int indexCapture; } webaudio; #endif #ifdef MA_SUPPORT_NULL @@ -8039,7 +4262,7 @@ struct ma_device ma_uint32 currentPeriodFramesRemainingCapture; ma_uint64 lastProcessedFramePlayback; ma_uint64 lastProcessedFrameCapture; - ma_atomic_bool32 isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */ + MA_ATOMIC ma_bool32 isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */ } null_device; #endif }; @@ -8131,9 +4354,8 @@ When `backends` is NULL, the default priority order will be used. Below is a lis The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings can then be set directly on the structure. Below are the members of the `ma_context_config` object. - pLog - A pointer to the `ma_log` to post log messages to. Can be NULL if the application does not - require logging. See the `ma_log` API for details on how to use the logging system. + logCallback + Callback for handling log messages from miniaudio. threadPriority The desired priority to use for the audio thread. Allowable values include the following: @@ -8151,9 +4373,6 @@ can then be set directly on the structure. Below are the members of the `ma_cont | ma_thread_priority_default | |--------------------------------------| - threadStackSize - The desired size of the stack for the audio thread. Defaults to the operating system's default. - pUserData A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`. @@ -8208,12 +4427,6 @@ can then be set directly on the structure. Below are the members of the `ma_cont | ma_ios_session_category_option_allow_air_play | AVAudioSessionCategoryOptionAllowAirPlay | |---------------------------------------------------------------------------|------------------------------------------------------------------| - coreaudio.noAudioSessionActivate - iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. - - coreaudio.noAudioSessionDeactivate - iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. - jack.pClientName The name of the client to pass to `jack_client_open()`. @@ -8257,12 +4470,9 @@ ma_backend backends[] = { ma_backend_dsound }; -ma_log log; -ma_log_init(&log); -ma_log_register_callback(&log, ma_log_callback_init(my_log_callbac, pMyLogUserData)); - ma_context_config config = ma_context_config_init(); -config.pLog = &log; // Specify a custom log object in the config so any logs that are posted from ma_context_init() are captured. +config.logCallback = my_log_callback; +config.pUserData = pMyUserData; ma_context context; ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context); @@ -8272,9 +4482,6 @@ if (result != MA_SUCCESS) { // Couldn't find an appropriate backend. } } - -// You could also attach a log callback post-initialization: -ma_log_register_callback(ma_context_get_log(&context), ma_log_callback_init(my_log_callback, pMyLogUserData)); ``` @@ -8317,25 +4524,6 @@ This is mainly for the purpose of bindings to know how much memory to allocate. */ MA_API size_t ma_context_sizeof(void); -/* -Retrieves a pointer to the log object associated with this context. - - -Remarks -------- -Pass the returned pointer to `ma_log_post()`, `ma_log_postv()` or `ma_log_postf()` to post a log -message. - -You can attach your own logging callback to the log with `ma_log_register_callback()` - - -Return Value ------------- -A pointer to the `ma_log` object that the context uses to post log messages. If some error occurs, -NULL will be returned. -*/ -MA_API ma_log* ma_context_get_log(ma_context* pContext); - /* Enumerates over every device (both playback and capture). @@ -8409,10 +4597,6 @@ Retrieves basic information about every active playback and/or capture device. This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos` parameters. If you do not want to incur the overhead of these allocations consider using `ma_context_enumerate_devices()` which will instead use a callback. -Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require -opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using `ma_context_get_device_info()` for this, -but don't call it from within the enumeration callback. - Parameters ---------- @@ -8454,7 +4638,7 @@ The returned pointers will become invalid upon the next call this this function, See Also -------- -ma_context_enumerate_devices() +ma_context_get_devices() */ MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount); @@ -8473,6 +4657,10 @@ deviceType (in) pDeviceID (in) The ID of the device being queried. +shareMode (in) + The share mode to query for device capabilities. This should be set to whatever you're intending on using when initializing the device. If you're unsure, + set this to `ma_share_mode_shared`. + pDeviceInfo (out) A pointer to the `ma_device_info` structure that will receive the device information. @@ -8498,7 +4686,7 @@ the requested share mode is unsupported. This leaves pDeviceInfo unmodified in the result of an error. */ -MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo); +MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo); /* Determines if the given context supports loopback mode. @@ -8593,7 +4781,7 @@ from a microphone. Whether or not you should send or receive data from the devic playback, capture, full-duplex or loopback. (Note that loopback mode is only supported on select backends.) Sending and receiving audio data to and from the device is done via a callback which is fired by miniaudio at periodic time intervals. -The frequency at which data is delivered to and from a device depends on the size of its period. The size of the period can be defined in terms of PCM frames +The frequency at which data is delivered to and from a device depends on the size of it's period. The size of the period can be defined in terms of PCM frames or milliseconds, whichever is more convenient. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and increased risk of glitching due to the more frequent and granular data deliver intervals. The size of a period will depend on your requirements, but miniaudio's defaults should work fine for most scenarios. If you're building a game you should leave this fairly small, whereas if you're building a simple @@ -8667,31 +4855,24 @@ then be set directly on the structure. Below are the members of the `ma_device_c performanceProfile A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or - `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at its default value. + `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value. - noPreSilencedOutputBuffer + noPreZeroedOutputBuffer When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of the output buffer will be cleared the zero. You can use this to avoid the overhead of zeroing out the buffer if you can guarantee that your data callback will write to every sample in the output buffer, or if you are doing your own clearing. noClip - When set to true, the contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or - not to clip. When set to false (default), the contents of the output buffer passed into the data callback will be clipped after returning. This only + When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. When set to false (default), the + contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only applies when the playback sample format is f32. - noDisableDenormals - By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals. - - noFixedSizedCallback - Allows miniaudio to fire the data callback with any frame count. When this is set to false (the default), the data callback will be fired with a - consistent frame count as specified by `periodSizeInFrames` or `periodSizeInMilliseconds`. When set to true, miniaudio will fire the callback with - whatever the backend requests, which could be anything. - dataCallback The callback to fire whenever data is ready to be delivered to or from the device. - notificationCallback - The callback to fire when something has changed with the device, such as whether or not it has been started or stopped. + stopCallback + The callback to fire whenever the device has stopped, either explicitly via `ma_device_stop()`, or implicitly due to things like the device being + disconnected. pUserData The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`. @@ -8700,14 +4881,8 @@ then be set directly on the structure. Below are the members of the `ma_device_c The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`. - resampling.pBackendVTable - A pointer to an optional vtable that can be used for plugging in a custom resampler. - - resampling.pBackendUserData - A pointer that will passed to callbacks in pBackendVTable. - resampling.linear.lpfOrder - The linear resampler applies a low-pass filter as part of its processing for anti-aliasing. This setting controls the order of the filter. The higher + The linear resampler applies a low-pass filter as part of it's procesing for anti-aliasing. This setting controls the order of the filter. The higher the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. @@ -8723,9 +4898,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c The number of channels to use for playback. When set to 0 the device's native channel count will be used. This can be retrieved after initialization from the device object directly with `device.playback.channels`. - playback.pChannelMap + playback.channelMap The channel map to use for playback. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the - device object direct with `device.playback.pChannelMap`. When set, the buffer should contain `channels` items. + device object direct with `device.playback.channelMap`. playback.shareMode The preferred share mode to use for playback. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify @@ -8744,9 +4919,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c The number of channels to use for capture. When set to 0 the device's native channel count will be used. This can be retrieved after initialization from the device object directly with `device.capture.channels`. - capture.pChannelMap + capture.channelMap The channel map to use for capture. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the - device object direct with `device.capture.pChannelMap`. When set, the buffer should contain `channels` items. + device object direct with `device.capture.channelMap`. capture.shareMode The preferred share mode to use for capture. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify @@ -8784,9 +4959,6 @@ then be set directly on the structure. Below are the members of the `ma_device_c pulse.pStreamNameCapture PulseAudio only. Sets the stream name for capture. - pulse.channelMap - PulseAudio only. Sets the channel map that is requested from PulseAudio. See MA_PA_CHANNEL_MAP_* constants. Defaults to MA_PA_CHANNEL_MAP_AIFF. - coreaudio.allowNominalSampleRateChange Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate @@ -8794,30 +4966,6 @@ then be set directly on the structure. Below are the members of the `ma_device_c find the closest match between the sample rate requested in the device config and the sample rates natively supported by the hardware. When set to false, the sample rate currently set by the operating system will always be used. - opensl.streamType - OpenSL only. Explicitly sets the stream type. If left unset (`ma_opensl_stream_type_default`), the - stream type will be left unset. Think of this as the type of audio you're playing. - - opensl.recordingPreset - OpenSL only. Explicitly sets the type of recording your program will be doing. When left - unset, the recording preset will be left unchanged. - - aaudio.usage - AAudio only. Explicitly sets the nature of the audio the program will be consuming. When - left unset, the usage will be left unchanged. - - aaudio.contentType - AAudio only. Sets the content type. When left unset, the content type will be left unchanged. - - aaudio.inputPreset - AAudio only. Explicitly sets the type of recording your program will be doing. When left - unset, the input preset will be left unchanged. - - aaudio.noAutoStartAfterReroute - AAudio only. Controls whether or not the device should be automatically restarted after a - stream reroute. When set to false (default) the device will be restarted automatically; - otherwise the device will be stopped. - Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device. @@ -8960,7 +5108,7 @@ Unsafe. It is not safe to call this inside any callback. Remarks ------- -You only need to use this function if you want to configure the context differently to its defaults. You should never use this function if you want to manage +You only need to use this function if you want to configure the context differently to it's defaults. You should never use this function if you want to manage your own context. See the documentation for `ma_context_init()` for information on the different context configuration options. @@ -9009,107 +5157,6 @@ ma_device_stop() */ MA_API void ma_device_uninit(ma_device* pDevice); - -/* -Retrieves a pointer to the context that owns the given device. -*/ -MA_API ma_context* ma_device_get_context(ma_device* pDevice); - -/* -Helper function for retrieving the log object associated with the context that owns this device. -*/ -MA_API ma_log* ma_device_get_log(ma_device* pDevice); - - -/* -Retrieves information about the device. - - -Parameters ----------- -pDevice (in) - A pointer to the device whose information is being retrieved. - -type (in) - The device type. This parameter is required for duplex devices. When retrieving device - information, you are doing so for an individual playback or capture device. - -pDeviceInfo (out) - A pointer to the `ma_device_info` that will receive the device information. - - -Return Value ------------- -MA_SUCCESS if successful; any other error code otherwise. - - -Thread Safety -------------- -Unsafe. This should be considered unsafe because it may be calling into the backend which may or -may not be safe. - - -Callback Safety ---------------- -Unsafe. You should avoid calling this in the data callback because it may call into the backend -which may or may not be safe. -*/ -MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo); - - -/* -Retrieves the name of the device. - - -Parameters ----------- -pDevice (in) - A pointer to the device whose information is being retrieved. - -type (in) - The device type. This parameter is required for duplex devices. When retrieving device - information, you are doing so for an individual playback or capture device. - -pName (out) - A pointer to the buffer that will receive the name. - -nameCap (in) - The capacity of the output buffer, including space for the null terminator. - -pLengthNotIncludingNullTerminator (out, optional) - A pointer to the variable that will receive the length of the name, not including the null - terminator. - - -Return Value ------------- -MA_SUCCESS if successful; any other error code otherwise. - - -Thread Safety -------------- -Unsafe. This should be considered unsafe because it may be calling into the backend which may or -may not be safe. - - -Callback Safety ---------------- -Unsafe. You should avoid calling this in the data callback because it may call into the backend -which may or may not be safe. - - -Remarks -------- -If the name does not fully fit into the output buffer, it'll be truncated. You can pass in NULL to -`pName` if you want to first get the length of the name for the purpose of memory allocation of the -output buffer. Allocating a buffer of size `MA_MAX_DEVICE_NAME_LENGTH + 1` should be enough for -most cases and will avoid the need for the inefficiency of calling this function twice. - -This is implemented in terms of `ma_device_get_info()`. -*/ -MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator); - - /* Starts the device. For playback devices this begins playback. For capture devices it begins recording. @@ -9192,6 +5239,8 @@ speakers or received from the microphone which can in turn result in de-syncs. Do not call this in any callback. +This will be called implicitly by `ma_device_uninit()`. + See Also -------- @@ -9247,17 +5296,17 @@ Return Value ------------ The current state of the device. The return value will be one of the following: - +-------------------------------+------------------------------------------------------------------------------+ - | ma_device_state_uninitialized | Will only be returned if the device is in the middle of initialization. | - +-------------------------------+------------------------------------------------------------------------------+ - | ma_device_state_stopped | The device is stopped. The initial state of the device after initialization. | - +-------------------------------+------------------------------------------------------------------------------+ - | ma_device_state_started | The device started and requesting and/or delivering audio data. | - +-------------------------------+------------------------------------------------------------------------------+ - | ma_device_state_starting | The device is in the process of starting. | - +-------------------------------+------------------------------------------------------------------------------+ - | ma_device_state_stopping | The device is in the process of stopping. | - +-------------------------------+------------------------------------------------------------------------------+ + +------------------------+------------------------------------------------------------------------------+ + | MA_STATE_UNINITIALIZED | Will only be returned if the device is in the middle of initialization. | + +------------------------+------------------------------------------------------------------------------+ + | MA_STATE_STOPPED | The device is stopped. The initial state of the device after initialization. | + +------------------------+------------------------------------------------------------------------------+ + | MA_STATE_STARTED | The device started and requesting and/or delivering audio data. | + +------------------------+------------------------------------------------------------------------------+ + | MA_STATE_STARTING | The device is in the process of starting. | + +------------------------+------------------------------------------------------------------------------+ + | MA_STATE_STOPPING | The device is in the process of stopping. | + +------------------------+------------------------------------------------------------------------------+ Thread Safety @@ -9276,71 +5325,22 @@ Remarks The general flow of a devices state goes like this: ``` - ma_device_init() -> ma_device_state_uninitialized -> ma_device_state_stopped - ma_device_start() -> ma_device_state_starting -> ma_device_state_started - ma_device_stop() -> ma_device_state_stopping -> ma_device_state_stopped + ma_device_init() -> MA_STATE_UNINITIALIZED -> MA_STATE_STOPPED + ma_device_start() -> MA_STATE_STARTING -> MA_STATE_STARTED + ma_device_stop() -> MA_STATE_STOPPING -> MA_STATE_STOPPED ``` When the state of the device is changed with `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, the value returned by this function could potentially be out of sync. If this is significant to your program you need to implement your own synchronization. */ -MA_API ma_device_state ma_device_get_state(const ma_device* pDevice); - - -/* -Performs post backend initialization routines for setting up internal data conversion. - -This should be called whenever the backend is initialized. The only time this should be called from -outside of miniaudio is if you're implementing a custom backend, and you would only do it if you -are reinitializing the backend due to rerouting or reinitializing for some reason. - - -Parameters ----------- -pDevice [in] - A pointer to the device. - -deviceType [in] - The type of the device that was just reinitialized. - -pPlaybackDescriptor [in] - The descriptor of the playback device containing the internal data format and buffer sizes. - -pPlaybackDescriptor [in] - The descriptor of the capture device containing the internal data format and buffer sizes. - - -Return Value ------------- -MA_SUCCESS if successful; any other error otherwise. - - -Thread Safety -------------- -Unsafe. This will be reinitializing internal data converters which may be in use by another thread. - - -Callback Safety ---------------- -Unsafe. This will be reinitializing internal data converters which may be in use by the callback. - - -Remarks -------- -For a duplex device, you can call this for only one side of the system. This is why the deviceType -is specified as a parameter rather than deriving it from the device. - -You do not need to call this manually unless you are doing a custom backend, in which case you need -only do it if you're manually performing rerouting or reinitialization. -*/ -MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPlaybackDescriptor, const ma_device_descriptor* pCaptureDescriptor); +MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice); /* Sets the master volume factor for the device. -The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_volume_db()` to use decibel notation, where 0 is full volume and +The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_gain_db()` to use decibel notation, where 0 is full volume and values less than 0 decreases the volume. @@ -9350,14 +5350,14 @@ pDevice (in) A pointer to the device whose volume is being set. volume (in) - The new volume factor. Must be >= 0. + The new volume factor. Must be within the range of [0, 1]. Return Value ------------ MA_SUCCESS if the volume was set successfully. MA_INVALID_ARGS if pDevice is NULL. -MA_INVALID_ARGS if volume is negative. +MA_INVALID_ARGS if the volume factor is not within the range of [0, 1]. Thread Safety @@ -9380,8 +5380,8 @@ This does not change the operating system's volume. It only affects the volume f See Also -------- ma_device_get_master_volume() -ma_device_set_master_volume_db() -ma_device_get_master_volume_db() +ma_device_set_master_volume_gain_db() +ma_device_get_master_volume_gain_db() */ MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume); @@ -9473,7 +5473,7 @@ ma_device_get_master_volume_gain_db() ma_device_set_master_volume() ma_device_get_master_volume() */ -MA_API ma_result ma_device_set_master_volume_db(ma_device* pDevice, float gainDB); +MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB); /* Retrieves the master gain in decibels. @@ -9512,11 +5512,11 @@ If an error occurs, `*pGainDB` will be set to 0. See Also -------- -ma_device_set_master_volume_db() +ma_device_set_master_volume_gain_db() ma_device_set_master_volume() ma_device_get_master_volume() */ -MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB); +MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB); /* @@ -9626,11 +5626,6 @@ Retrieves a friendly name for a backend. */ MA_API const char* ma_get_backend_name(ma_backend backend); -/* -Retrieves the backend enum from the given name. -*/ -MA_API ma_result ma_get_backend_from_name(const char* pBackendName, ma_backend* pBackend); - /* Determines whether or not the given backend is available by the compilation environment. */ @@ -9717,15 +5712,84 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend); #endif /* MA_NO_DEVICE_IO */ +#ifndef MA_NO_THREADING + +/* +Locks a spinlock. +*/ +MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock); + +/* +Locks a spinlock, but does not yield() when looping. +*/ +MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock); + +/* +Unlocks a spinlock. +*/ +MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock); + + +/* +Creates a mutex. + +A mutex must be created from a valid context. A mutex is initially unlocked. +*/ +MA_API ma_result ma_mutex_init(ma_mutex* pMutex); + +/* +Deletes a mutex. +*/ +MA_API void ma_mutex_uninit(ma_mutex* pMutex); + +/* +Locks a mutex with an infinite timeout. +*/ +MA_API void ma_mutex_lock(ma_mutex* pMutex); + +/* +Unlocks a mutex. +*/ +MA_API void ma_mutex_unlock(ma_mutex* pMutex); + + +/* +Initializes an auto-reset event. +*/ +MA_API ma_result ma_event_init(ma_event* pEvent); + +/* +Uninitializes an auto-reset event. +*/ +MA_API void ma_event_uninit(ma_event* pEvent); + +/* +Waits for the specified auto-reset event to become signalled. +*/ +MA_API ma_result ma_event_wait(ma_event* pEvent); + +/* +Signals the specified auto-reset event. +*/ +MA_API ma_result ma_event_signal(ma_event* pEvent); +#endif /* MA_NO_THREADING */ + /************************************************************************************************************************************************************ -Utilities +Utiltities ************************************************************************************************************************************************************/ /* -Calculates a buffer size in milliseconds (rounded up) from the specified number of frames and sample rate. +Adjust buffer size based on a scaling factor. + +This just multiplies the base size by the scaling factor, making sure it's a size of at least 1. +*/ +MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale); + +/* +Calculates a buffer size in milliseconds from the specified number of frames and sample rate. */ MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate); @@ -9748,6 +5812,7 @@ For all formats except `ma_format_u8`, the output buffer will be filled with 0. makes more sense for the purpose of mixing to initialize it to the center point. */ MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels); +static MA_INLINE void ma_zero_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels) { ma_silence_pcm_frames(p, frameCount, format, channels); } /* @@ -9760,14 +5825,10 @@ static MA_INLINE const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, /* -Clips samples. +Clips f32 samples. */ -MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count); -MA_API void ma_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count); -MA_API void ma_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count); -MA_API void ma_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count); -MA_API void ma_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count); -MA_API void ma_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels); +MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount); +static MA_INLINE void ma_clip_pcm_frames_f32(float* p, ma_uint64 frameCount, ma_uint32 channels) { ma_clip_samples_f32(p, frameCount*channels); } /* Helper for applying a volume factor to samples. @@ -9786,11 +5847,11 @@ MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, fl MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor); MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pFramesOut, const ma_uint8* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pFramesOut, const ma_int16* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pFramesOut, const ma_int32* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor); MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor); @@ -9800,35 +5861,94 @@ MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 f MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor); MA_API void ma_apply_volume_factor_pcm_frames(void* pFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_per_channel_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float* pChannelGains); - - -MA_API void ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count, float volume); -MA_API void ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count, float volume); -MA_API void ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count, float volume); -MA_API void ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count, float volume); -MA_API void ma_copy_and_apply_volume_and_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count, float volume); -MA_API void ma_copy_and_apply_volume_and_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float volume); - /* Helper for converting a linear factor to gain in decibels. */ -MA_API float ma_volume_linear_to_db(float factor); +MA_API float ma_factor_to_gain_db(float factor); /* Helper for converting gain in decibels to a linear factor. */ -MA_API float ma_volume_db_to_linear(float gain); +MA_API float ma_gain_db_to_factor(float gain); -/* -Mixes the specified number of frames in floating point format with a volume factor. +typedef void ma_data_source; -This will run on an optimized path when the volume is equal to 1. -*/ -MA_API ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume); +typedef struct +{ + ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); + ma_result (* onSeek)(ma_data_source* pDataSource, ma_uint64 frameIndex); + ma_result (* onMap)(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ + ma_result (* onUnmap)(ma_data_source* pDataSource, ma_uint64 frameCount); + ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); + ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor); + ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength); +} ma_data_source_callbacks; +MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ +MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */ +MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex); +MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount); +MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ +MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); +MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor); +MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ + + + + +typedef struct +{ + ma_data_source_callbacks ds; + ma_format format; + ma_uint32 channels; + ma_uint64 cursor; + ma_uint64 sizeInFrames; + const void* pData; +} ma_audio_buffer_ref; + +MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef); +MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames); +MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop); +MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex); +MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount); +MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ +MA_API ma_result ma_audio_buffer_ref_at_end(ma_audio_buffer_ref* pAudioBufferRef); +MA_API ma_result ma_audio_buffer_ref_get_available_frames(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames); + + + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint64 sizeInFrames; + const void* pData; /* If set to NULL, will allocate a block of memory for you. */ + ma_allocation_callbacks allocationCallbacks; +} ma_audio_buffer_config; + +MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint64 sizeInFrames, const void* pData, const ma_allocation_callbacks* pAllocationCallbacks); + +typedef struct +{ + ma_audio_buffer_ref ref; + ma_allocation_callbacks allocationCallbacks; + ma_bool32 ownsData; /* Used to control whether or not miniaudio owns the data buffer. If set to true, pData will be freed in ma_audio_buffer_uninit(). */ + ma_uint8 _pExtraData[1]; /* For allocating a buffer with the memory located directly after the other memory of the structure. */ +} ma_audio_buffer; + +MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer); +MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer); +MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer); /* Always copies the data. Doesn't make sense to use this otherwise. Use ma_audio_buffer_uninit_and_free() to uninit. */ +MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer); +MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer); +MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop); +MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex); +MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount); +MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ +MA_API ma_result ma_audio_buffer_at_end(ma_audio_buffer* pAudioBuffer); +MA_API ma_result ma_audio_buffer_get_available_frames(ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames); @@ -9844,11 +5964,8 @@ appropriate for a given situation. typedef void ma_vfs; typedef ma_handle ma_vfs_file; -typedef enum -{ - MA_OPEN_MODE_READ = 0x00000001, - MA_OPEN_MODE_WRITE = 0x00000002 -} ma_open_mode_flags; +#define MA_OPEN_MODE_READ 0x00000001 +#define MA_OPEN_MODE_WRITE 0x00000002 typedef enum { @@ -9894,21 +6011,12 @@ MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_c -typedef ma_result (* ma_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead); -typedef ma_result (* ma_seek_proc)(void* pUserData, ma_int64 offset, ma_seek_origin origin); -typedef ma_result (* ma_tell_proc)(void* pUserData, ma_int64* pCursor); - - #if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING) typedef enum { - ma_encoding_format_unknown = 0, - ma_encoding_format_wav, - ma_encoding_format_flac, - ma_encoding_format_mp3, - ma_encoding_format_vorbis -} ma_encoding_format; + ma_resource_format_wav +} ma_resource_format; #endif /************************************************************************************************************************************************************ @@ -9923,67 +6031,59 @@ you do your own synchronization. #ifndef MA_NO_DECODING typedef struct ma_decoder ma_decoder; - -typedef struct -{ - ma_format preferredFormat; - ma_uint32 seekPointCount; /* Set to > 0 to generate a seektable if the decoding backend supports it. */ -} ma_decoding_backend_config; - -MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat, ma_uint32 seekPointCount); - - -typedef struct -{ - ma_result (* onInit )(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); - ma_result (* onInitFile )(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ - ma_result (* onInitFileW )(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ - ma_result (* onInitMemory)(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ - void (* onUninit )(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks); -} ma_decoding_backend_vtable; - - -typedef ma_result (* ma_decoder_read_proc)(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead); /* Returns the number of bytes read. */ -typedef ma_result (* ma_decoder_seek_proc)(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin); -typedef ma_result (* ma_decoder_tell_proc)(ma_decoder* pDecoder, ma_int64* pCursor); +typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */ +typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin); /* Origin will never be ma_seek_origin_end. */ +typedef ma_uint64 (* ma_decoder_read_pcm_frames_proc) (ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); /* Returns the number of frames read. Output data is in internal format. */ +typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc) (ma_decoder* pDecoder, ma_uint64 frameIndex); +typedef ma_result (* ma_decoder_uninit_proc) (ma_decoder* pDecoder); +typedef ma_uint64 (* ma_decoder_get_length_in_pcm_frames_proc)(ma_decoder* pDecoder); typedef struct { ma_format format; /* Set to 0 or ma_format_unknown to use the stream's internal format. */ ma_uint32 channels; /* Set to 0 to use the stream's internal channels. */ ma_uint32 sampleRate; /* Set to 0 to use the stream's internal sample rate. */ - ma_channel* pChannelMap; + ma_channel channelMap[MA_MAX_CHANNELS]; ma_channel_mix_mode channelMixMode; ma_dither_mode ditherMode; - ma_resampler_config resampling; + struct + { + ma_resample_algorithm algorithm; + struct + { + ma_uint32 lpfOrder; + } linear; + struct + { + int quality; + } speex; + } resampling; ma_allocation_callbacks allocationCallbacks; - ma_encoding_format encodingFormat; - ma_uint32 seekPointCount; /* When set to > 0, specifies the number of seek points to use for the generation of a seek table. Not all decoding backends support this. */ - ma_decoding_backend_vtable** ppCustomBackendVTables; - ma_uint32 customBackendCount; - void* pCustomBackendUserData; } ma_decoder_config; struct ma_decoder { - ma_data_source_base ds; - ma_data_source* pBackend; /* The decoding backend we'll be pulling data from. */ - const ma_decoding_backend_vtable* pBackendVTable; /* The vtable for the decoding backend. This needs to be stored so we can access the onUninit() callback. */ - void* pBackendUserData; + ma_data_source_callbacks ds; ma_decoder_read_proc onRead; ma_decoder_seek_proc onSeek; - ma_decoder_tell_proc onTell; void* pUserData; - ma_uint64 readPointerInPCMFrames; /* In output sample rate. Used for keeping track of how many frames are available for decoding. */ - ma_format outputFormat; - ma_uint32 outputChannels; - ma_uint32 outputSampleRate; - ma_data_converter converter; /* Data conversion is achieved by running frames through this. */ - void* pInputCache; /* In input format. Can be null if it's not needed. */ - ma_uint64 inputCacheCap; /* The capacity of the input cache. */ - ma_uint64 inputCacheConsumed; /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */ - ma_uint64 inputCacheRemaining; /* The number of valid frames remaining in the cache. */ + ma_uint64 readPointerInBytes; /* In internal encoded data. */ + ma_uint64 readPointerInPCMFrames; /* In output sample rate. Used for keeping track of how many frames are available for decoding. */ + ma_format internalFormat; + ma_uint32 internalChannels; + ma_uint32 internalSampleRate; + ma_channel internalChannelMap[MA_MAX_CHANNELS]; + ma_format outputFormat; + ma_uint32 outputChannels; + ma_uint32 outputSampleRate; + ma_channel outputChannelMap[MA_MAX_CHANNELS]; + ma_data_converter converter; /* <-- Data conversion is achieved by running frames through this. */ ma_allocation_callbacks allocationCallbacks; + ma_decoder_read_pcm_frames_proc onReadPCMFrames; + ma_decoder_seek_to_pcm_frame_proc onSeekToPCMFrame; + ma_decoder_uninit_proc onUninit; + ma_decoder_get_length_in_pcm_frames_proc onGetLengthInPCMFrames; + void* pInternalDecoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */ union { struct @@ -9997,43 +6097,51 @@ struct ma_decoder size_t dataSize; size_t currentReadPos; } memory; /* Only used for decoders that were opened against a block of memory. */ - } data; + } backend; }; MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate); -MA_API ma_decoder_config ma_decoder_config_init_default(void); MA_API ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder); + MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder); + MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); + MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); + MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); + MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -/* -Uninitializes a decoder. -*/ MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder); -/* -Reads PCM frames from the given decoder. - -This is not thread safe without your own synchronization. -*/ -MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); - -/* -Seeks to a PCM frame based on its absolute index. - -This is not thread safe without your own synchronization. -*/ -MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex); - -/* -Retrieves the decoder's output data format. -*/ -MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); - /* Retrieves the current position of the read cursor in PCM frames. */ @@ -10053,7 +6161,21 @@ For MP3's, this will decode the entire file. Do not call this in time critical s This function is not thread safe without your own synchronization. */ -MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength); +MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder); + +/* +Reads PCM frames from the given decoder. + +This is not thread safe without your own synchronization. +*/ +MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); + +/* +Seeks to a PCM frame based on it's absolute index. + +This is not thread safe without your own synchronization. +*/ +MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex); /* Retrieves the number of frames that can be read before reaching the end. @@ -10088,22 +6210,22 @@ Encoders do not perform any format conversion for you. If your target format doe #ifndef MA_NO_ENCODING typedef struct ma_encoder ma_encoder; -typedef ma_result (* ma_encoder_write_proc) (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite, size_t* pBytesWritten); -typedef ma_result (* ma_encoder_seek_proc) (ma_encoder* pEncoder, ma_int64 offset, ma_seek_origin origin); +typedef size_t (* ma_encoder_write_proc) (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite); /* Returns the number of bytes written. */ +typedef ma_bool32 (* ma_encoder_seek_proc) (ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin); typedef ma_result (* ma_encoder_init_proc) (ma_encoder* pEncoder); typedef void (* ma_encoder_uninit_proc) (ma_encoder* pEncoder); -typedef ma_result (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten); +typedef ma_uint64 (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount); typedef struct { - ma_encoding_format encodingFormat; + ma_resource_format resourceFormat; ma_format format; ma_uint32 channels; ma_uint32 sampleRate; ma_allocation_callbacks allocationCallbacks; } ma_encoder_config; -MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); +MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); struct ma_encoder { @@ -10114,24 +6236,15 @@ struct ma_encoder ma_encoder_uninit_proc onUninit; ma_encoder_write_pcm_frames_proc onWritePCMFrames; void* pUserData; - void* pInternalEncoder; - union - { - struct - { - ma_vfs* pVFS; - ma_vfs_file file; - } vfs; - } data; + void* pInternalEncoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */ + void* pFile; /* FILE*. Only used when initialized with ma_encoder_init_file(). */ }; MA_API ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder); -MA_API ma_result ma_encoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); -MA_API ma_result ma_encoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); MA_API void ma_encoder_uninit(ma_encoder* pEncoder); -MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten); +MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount); #endif /* MA_NO_ENCODING */ @@ -10164,48 +6277,20 @@ MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 ch typedef struct { - ma_data_source_base ds; + ma_data_source_callbacks ds; ma_waveform_config config; double advance; double time; } ma_waveform; MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform); -MA_API void ma_waveform_uninit(ma_waveform* pWaveform); -MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount); MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex); MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude); MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency); MA_API ma_result ma_waveform_set_type(ma_waveform* pWaveform, ma_waveform_type type); MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate); -typedef struct -{ - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - double dutyCycle; - double amplitude; - double frequency; -} ma_pulsewave_config; - -MA_API ma_pulsewave_config ma_pulsewave_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double dutyCycle, double amplitude, double frequency); - -typedef struct -{ - ma_waveform waveform; - ma_pulsewave_config config; -} ma_pulsewave; - -MA_API ma_result ma_pulsewave_init(const ma_pulsewave_config* pConfig, ma_pulsewave* pWaveform); -MA_API void ma_pulsewave_uninit(ma_pulsewave* pWaveform); -MA_API ma_result ma_pulsewave_read_pcm_frames(ma_pulsewave* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_pulsewave_seek_to_pcm_frame(ma_pulsewave* pWaveform, ma_uint64 frameIndex); -MA_API ma_result ma_pulsewave_set_amplitude(ma_pulsewave* pWaveform, double amplitude); -MA_API ma_result ma_pulsewave_set_frequency(ma_pulsewave* pWaveform, double frequency); -MA_API ma_result ma_pulsewave_set_sample_rate(ma_pulsewave* pWaveform, ma_uint32 sampleRate); -MA_API ma_result ma_pulsewave_set_duty_cycle(ma_pulsewave* pWaveform, double dutyCycle); - typedef enum { ma_noise_type_white, @@ -10213,7 +6298,6 @@ typedef enum ma_noise_type_brownian } ma_noise_type; - typedef struct { ma_format format; @@ -10228,1274 +6312,38 @@ MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels typedef struct { - ma_data_source_base ds; + ma_data_source_callbacks ds; ma_noise_config config; ma_lcg lcg; union { struct { - double** bin; - double* accumulation; - ma_uint32* counter; + double bin[MA_MAX_CHANNELS][16]; + double accumulation[MA_MAX_CHANNELS]; + ma_uint32 counter[MA_MAX_CHANNELS]; } pink; struct { - double* accumulation; + double accumulation[MA_MAX_CHANNELS]; } brownian; } state; - - /* Memory management. */ - void* _pHeap; - ma_bool32 _ownsHeap; } ma_noise; -MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise); -MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise); -MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise); +MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount); MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude); MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed); MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type); #endif /* MA_NO_GENERATION */ - - -/************************************************************************************************************************************************************ - -Resource Manager - -************************************************************************************************************************************************************/ -/* The resource manager cannot be enabled if there is no decoder. */ -#if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_NO_DECODING) -#define MA_NO_RESOURCE_MANAGER -#endif - -#ifndef MA_NO_RESOURCE_MANAGER -typedef struct ma_resource_manager ma_resource_manager; -typedef struct ma_resource_manager_data_buffer_node ma_resource_manager_data_buffer_node; -typedef struct ma_resource_manager_data_buffer ma_resource_manager_data_buffer; -typedef struct ma_resource_manager_data_stream ma_resource_manager_data_stream; -typedef struct ma_resource_manager_data_source ma_resource_manager_data_source; - -typedef enum -{ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM = 0x00000001, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE = 0x00000002, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT = 0x00000008, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH = 0x00000010, /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING = 0x00000020 /* When set, configures the data source to loop by default. */ -} ma_resource_manager_data_source_flags; - - -/* -Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional. -*/ -typedef struct -{ - ma_async_notification* pNotification; - ma_fence* pFence; -} ma_resource_manager_pipeline_stage_notification; - -typedef struct -{ - ma_resource_manager_pipeline_stage_notification init; /* Initialization of the decoder. */ - ma_resource_manager_pipeline_stage_notification done; /* Decoding fully completed. */ -} ma_resource_manager_pipeline_notifications; - -MA_API ma_resource_manager_pipeline_notifications ma_resource_manager_pipeline_notifications_init(void); - - - -/* BEGIN BACKWARDS COMPATIBILITY */ -/* TODO: Remove this block in version 0.12. */ -#if 1 -#define ma_resource_manager_job ma_job -#define ma_resource_manager_job_init ma_job_init -#define MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING MA_JOB_QUEUE_FLAG_NON_BLOCKING -#define ma_resource_manager_job_queue_config ma_job_queue_config -#define ma_resource_manager_job_queue_config_init ma_job_queue_config_init -#define ma_resource_manager_job_queue ma_job_queue -#define ma_resource_manager_job_queue_get_heap_size ma_job_queue_get_heap_size -#define ma_resource_manager_job_queue_init_preallocated ma_job_queue_init_preallocated -#define ma_resource_manager_job_queue_init ma_job_queue_init -#define ma_resource_manager_job_queue_uninit ma_job_queue_uninit -#define ma_resource_manager_job_queue_post ma_job_queue_post -#define ma_resource_manager_job_queue_next ma_job_queue_next -#endif -/* END BACKWARDS COMPATIBILITY */ - - - - -/* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */ -#ifndef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT -#define MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT 64 -#endif - -typedef enum -{ - /* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */ - MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING = 0x00000001, - - /* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */ - MA_RESOURCE_MANAGER_FLAG_NO_THREADING = 0x00000002 -} ma_resource_manager_flags; - -typedef struct -{ - const char* pFilePath; - const wchar_t* pFilePathW; - const ma_resource_manager_pipeline_notifications* pNotifications; - ma_uint64 initialSeekPointInPCMFrames; - ma_uint64 rangeBegInPCMFrames; - ma_uint64 rangeEndInPCMFrames; - ma_uint64 loopPointBegInPCMFrames; - ma_uint64 loopPointEndInPCMFrames; - ma_uint32 flags; - ma_bool32 isLooping; /* Deprecated. Use the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING flag in `flags` instead. */ -} ma_resource_manager_data_source_config; - -MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void); - - -typedef enum -{ - ma_resource_manager_data_supply_type_unknown = 0, /* Used for determining whether or the data supply has been initialized. */ - ma_resource_manager_data_supply_type_encoded, /* Data supply is an encoded buffer. Connector is ma_decoder. */ - ma_resource_manager_data_supply_type_decoded, /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */ - ma_resource_manager_data_supply_type_decoded_paged /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */ -} ma_resource_manager_data_supply_type; - -typedef struct -{ - MA_ATOMIC(4, ma_resource_manager_data_supply_type) type; /* Read and written from different threads so needs to be accessed atomically. */ - union - { - struct - { - const void* pData; - size_t sizeInBytes; - } encoded; - struct - { - const void* pData; - ma_uint64 totalFrameCount; - ma_uint64 decodedFrameCount; - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - } decoded; - struct - { - ma_paged_audio_buffer_data data; - ma_uint64 decodedFrameCount; - ma_uint32 sampleRate; - } decodedPaged; - } backend; -} ma_resource_manager_data_supply; - -struct ma_resource_manager_data_buffer_node -{ - ma_uint32 hashedName32; /* The hashed name. This is the key. */ - ma_uint32 refCount; - MA_ATOMIC(4, ma_result) result; /* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */ - MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ - MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ - ma_bool32 isDataOwnedByResourceManager; /* Set to true when the underlying data buffer was allocated the resource manager. Set to false if it is owned by the application (via ma_resource_manager_register_*()). */ - ma_resource_manager_data_supply data; - ma_resource_manager_data_buffer_node* pParent; - ma_resource_manager_data_buffer_node* pChildLo; - ma_resource_manager_data_buffer_node* pChildHi; -}; - -struct ma_resource_manager_data_buffer -{ - ma_data_source_base ds; /* Base data source. A data buffer is a data source. */ - ma_resource_manager* pResourceManager; /* A pointer to the resource manager that owns this buffer. */ - ma_resource_manager_data_buffer_node* pNode; /* The data node. This is reference counted and is what supplies the data. */ - ma_uint32 flags; /* The flags that were passed used to initialize the buffer. */ - MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ - MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ - ma_uint64 seekTargetInPCMFrames; /* Only updated by the public API. Never written nor read from the job thread. */ - ma_bool32 seekToCursorOnNextRead; /* On the next read we need to seek to the frame cursor. */ - MA_ATOMIC(4, ma_result) result; /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */ - MA_ATOMIC(4, ma_bool32) isLooping; /* Can be read and written by different threads at the same time. Must be used atomically. */ - ma_atomic_bool32 isConnectorInitialized; /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */ - union - { - ma_decoder decoder; /* Supply type is ma_resource_manager_data_supply_type_encoded */ - ma_audio_buffer buffer; /* Supply type is ma_resource_manager_data_supply_type_decoded */ - ma_paged_audio_buffer pagedBuffer; /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */ - } connector; /* Connects this object to the node's data supply. */ -}; - -struct ma_resource_manager_data_stream -{ - ma_data_source_base ds; /* Base data source. A data stream is a data source. */ - ma_resource_manager* pResourceManager; /* A pointer to the resource manager that owns this data stream. */ - ma_uint32 flags; /* The flags that were passed used to initialize the stream. */ - ma_decoder decoder; /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */ - ma_bool32 isDecoderInitialized; /* Required for determining whether or not the decoder should be uninitialized in MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM. */ - ma_uint64 totalLengthInPCMFrames; /* This is calculated when first loaded by the MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM. */ - ma_uint32 relativeCursor; /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */ - MA_ATOMIC(8, ma_uint64) absoluteCursor; /* The playback cursor, in absolute position starting from the start of the file. */ - ma_uint32 currentPageIndex; /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */ - MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ - MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ - - /* Written by the public API, read by the job thread. */ - MA_ATOMIC(4, ma_bool32) isLooping; /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */ - - /* Written by the job thread, read by the public API. */ - void* pPageData; /* Buffer containing the decoded data of each page. Allocated once at initialization time. */ - MA_ATOMIC(4, ma_uint32) pageFrameCount[2]; /* The number of valid PCM frames in each page. Used to determine the last valid frame. */ - - /* Written and read by both the public API and the job thread. These must be atomic. */ - MA_ATOMIC(4, ma_result) result; /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */ - MA_ATOMIC(4, ma_bool32) isDecoderAtEnd; /* Whether or not the decoder has reached the end. */ - MA_ATOMIC(4, ma_bool32) isPageValid[2]; /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */ - MA_ATOMIC(4, ma_bool32) seekCounter; /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */ -}; - -struct ma_resource_manager_data_source -{ - union - { - ma_resource_manager_data_buffer buffer; - ma_resource_manager_data_stream stream; - } backend; /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */ - - ma_uint32 flags; /* The flags that were passed in to ma_resource_manager_data_source_init(). */ - MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ - MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ -}; - -typedef struct -{ - ma_allocation_callbacks allocationCallbacks; - ma_log* pLog; - ma_format decodedFormat; /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */ - ma_uint32 decodedChannels; /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */ - ma_uint32 decodedSampleRate; /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */ - ma_uint32 jobThreadCount; /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */ - size_t jobThreadStackSize; - ma_uint32 jobQueueCapacity; /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */ - ma_uint32 flags; - ma_vfs* pVFS; /* Can be NULL in which case defaults will be used. */ - ma_decoding_backend_vtable** ppCustomDecodingBackendVTables; - ma_uint32 customDecodingBackendCount; - void* pCustomDecodingBackendUserData; -} ma_resource_manager_config; - -MA_API ma_resource_manager_config ma_resource_manager_config_init(void); - -struct ma_resource_manager -{ - ma_resource_manager_config config; - ma_resource_manager_data_buffer_node* pRootDataBufferNode; /* The root buffer in the binary tree. */ -#ifndef MA_NO_THREADING - ma_mutex dataBufferBSTLock; /* For synchronizing access to the data buffer binary tree. */ - ma_thread jobThreads[MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]; /* The threads for executing jobs. */ -#endif - ma_job_queue jobQueue; /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */ - ma_default_vfs defaultVFS; /* Only used if a custom VFS is not specified. */ - ma_log log; /* Only used if no log was specified in the config. */ -}; - -/* Init. */ -MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager); -MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager); -MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager); - -/* Registration. */ -MA_API ma_result ma_resource_manager_register_file(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags); -MA_API ma_result ma_resource_manager_register_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags); -MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */ -MA_API ma_result ma_resource_manager_register_decoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); -MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes); /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */ -MA_API ma_result ma_resource_manager_register_encoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, size_t sizeInBytes); -MA_API ma_result ma_resource_manager_unregister_file(ma_resource_manager* pResourceManager, const char* pFilePath); -MA_API ma_result ma_resource_manager_unregister_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath); -MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName); -MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName); - -/* Data Buffers. */ -MA_API ma_result ma_resource_manager_data_buffer_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex); -MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_manager_data_buffer* pDataBuffer, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor); -MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength); -MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping); -MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer); -MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames); - -/* Data Streams. */ -MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_stream* pDataStream); -MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream); -MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream); -MA_API ma_result ma_resource_manager_data_stream_uninit(ma_resource_manager_data_stream* pDataStream); -MA_API ma_result ma_resource_manager_data_stream_read_pcm_frames(ma_resource_manager_data_stream* pDataStream, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameIndex); -MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pCursor); -MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength); -MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream); -MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping); -MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream); -MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames); - -/* Data Sources. */ -MA_API ma_result ma_resource_manager_data_source_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex); -MA_API ma_result ma_resource_manager_data_source_get_data_format(ma_resource_manager_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pCursor); -MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength); -MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping); -MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource); -MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames); - -/* Job management. */ -MA_API ma_result ma_resource_manager_post_job(ma_resource_manager* pResourceManager, const ma_job* pJob); -MA_API ma_result ma_resource_manager_post_job_quit(ma_resource_manager* pResourceManager); /* Helper for posting a quit job. */ -MA_API ma_result ma_resource_manager_next_job(ma_resource_manager* pResourceManager, ma_job* pJob); -MA_API ma_result ma_resource_manager_process_job(ma_resource_manager* pResourceManager, ma_job* pJob); /* DEPRECATED. Use ma_job_process(). Will be removed in version 0.12. */ -MA_API ma_result ma_resource_manager_process_next_job(ma_resource_manager* pResourceManager); /* Returns MA_CANCELLED if a MA_JOB_TYPE_QUIT job is found. In non-blocking mode, returns MA_NO_DATA_AVAILABLE if no jobs are available. */ -#endif /* MA_NO_RESOURCE_MANAGER */ - - - -/************************************************************************************************************************************************************ - -Node Graph - -************************************************************************************************************************************************************/ -#ifndef MA_NO_NODE_GRAPH -/* Must never exceed 254. */ -#ifndef MA_MAX_NODE_BUS_COUNT -#define MA_MAX_NODE_BUS_COUNT 254 -#endif - -/* Used internally by miniaudio for memory management. Must never exceed MA_MAX_NODE_BUS_COUNT. */ -#ifndef MA_MAX_NODE_LOCAL_BUS_COUNT -#define MA_MAX_NODE_LOCAL_BUS_COUNT 2 -#endif - -/* Use this when the bus count is determined by the node instance rather than the vtable. */ -#define MA_NODE_BUS_COUNT_UNKNOWN 255 - - -/* For some internal memory management of ma_node_graph. */ -typedef struct -{ - size_t offset; - size_t sizeInBytes; - unsigned char _data[1]; -} ma_stack; - - -typedef struct ma_node_graph ma_node_graph; -typedef void ma_node; - - -/* Node flags. */ -typedef enum -{ - MA_NODE_FLAG_PASSTHROUGH = 0x00000001, - MA_NODE_FLAG_CONTINUOUS_PROCESSING = 0x00000002, - MA_NODE_FLAG_ALLOW_NULL_INPUT = 0x00000004, - MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES = 0x00000008, - MA_NODE_FLAG_SILENT_OUTPUT = 0x00000010 -} ma_node_flags; - - -/* The playback state of a node. Either started or stopped. */ -typedef enum -{ - ma_node_state_started = 0, - ma_node_state_stopped = 1 -} ma_node_state; - - -typedef struct -{ - /* - Extended processing callback. This callback is used for effects that process input and output - at different rates (i.e. they perform resampling). This is similar to the simple version, only - they take two separate frame counts: one for input, and one for output. - - On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas - `pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`. - - On output, set `pFrameCountOut` to the number of PCM frames that were actually output and set - `pFrameCountIn` to the number of input frames that were consumed. - */ - void (* onProcess)(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut); - - /* - A callback for retrieving the number of input frames that are required to output the - specified number of output frames. You would only want to implement this when the node performs - resampling. This is optional, even for nodes that perform resampling, but it does offer a - small reduction in latency as it allows miniaudio to calculate the exact number of input frames - to read at a time instead of having to estimate. - */ - ma_result (* onGetRequiredInputFrameCount)(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount); - - /* - The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn` - parameters of the callbacks above. - */ - ma_uint8 inputBusCount; - - /* - The number of output buses. This is how many sub-buffers will be contained in the `ppFramesOut` - parameters of the callbacks above. - */ - ma_uint8 outputBusCount; - - /* - Flags describing characteristics of the node. This is currently just a placeholder for some - ideas for later on. - */ - ma_uint32 flags; -} ma_node_vtable; - -typedef struct -{ - const ma_node_vtable* vtable; /* Should never be null. Initialization of the node will fail if so. */ - ma_node_state initialState; /* Defaults to ma_node_state_started. */ - ma_uint32 inputBusCount; /* Only used if the vtable specifies an input bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise must be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */ - ma_uint32 outputBusCount; /* Only used if the vtable specifies an output bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */ - const ma_uint32* pInputChannels; /* The number of elements are determined by the input bus count as determined by the vtable, or `inputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */ - const ma_uint32* pOutputChannels; /* The number of elements are determined by the output bus count as determined by the vtable, or `outputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */ -} ma_node_config; - -MA_API ma_node_config ma_node_config_init(void); - - -/* -A node has multiple output buses. An output bus is attached to an input bus as an item in a linked -list. Think of the input bus as a linked list, with the output bus being an item in that list. -*/ -typedef struct ma_node_output_bus ma_node_output_bus; -struct ma_node_output_bus -{ - /* Immutable. */ - ma_node* pNode; /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */ - ma_uint8 outputBusIndex; /* The index of the output bus on pNode that this output bus represents. */ - ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ - - /* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */ - ma_uint8 inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. Will only be used within the spinlock so does not need to be atomic. */ - MA_ATOMIC(4, ma_uint32) flags; /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */ - MA_ATOMIC(4, ma_uint32) refCount; /* Reference count for some thread-safety when detaching. */ - MA_ATOMIC(4, ma_bool32) isAttached; /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */ - MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ - MA_ATOMIC(4, float) volume; /* Linear. */ - MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pNext; /* If null, it's the tail node or detached. */ - MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pPrev; /* If null, it's the head node or detached. */ - MA_ATOMIC(MA_SIZEOF_PTR, ma_node*) pInputNode; /* The node that this output bus is attached to. Required for detaching. */ -}; - -/* -A node has multiple input buses. The output buses of a node are connecting to the input busses of -another. An input bus is essentially just a linked list of output buses. -*/ -typedef struct ma_node_input_bus ma_node_input_bus; -struct ma_node_input_bus -{ - /* Mutable via multiple threads. */ - ma_node_output_bus head; /* Dummy head node for simplifying some lock-free thread-safety stuff. */ - MA_ATOMIC(4, ma_uint32) nextCounter; /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */ - MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ - - /* Set once at startup. */ - ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ -}; - - -typedef struct ma_node_base ma_node_base; -struct ma_node_base -{ - /* These variables are set once at startup. */ - ma_node_graph* pNodeGraph; /* The graph this node belongs to. */ - const ma_node_vtable* vtable; - ma_uint32 inputBusCount; - ma_uint32 outputBusCount; - ma_node_input_bus* pInputBuses; - ma_node_output_bus* pOutputBuses; - float* pCachedData; /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ - ma_uint16 cachedDataCapInFramesPerBus; /* The capacity of the input data cache in frames, per bus. */ - - /* These variables are read and written only from the audio thread. */ - ma_uint16 cachedFrameCountOut; - ma_uint16 cachedFrameCountIn; - ma_uint16 consumedFrameCountIn; - - /* These variables are read and written between different threads. */ - MA_ATOMIC(4, ma_node_state) state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */ - MA_ATOMIC(8, ma_uint64) stateTimes[2]; /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */ - MA_ATOMIC(8, ma_uint64) localTime; /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */ - - /* Memory management. */ - ma_node_input_bus _inputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT]; - ma_node_output_bus _outputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT]; - void* _pHeap; /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */ - ma_bool32 _ownsHeap; /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */ -}; - -MA_API ma_result ma_node_get_heap_size(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode); -MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode); -MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode); -MA_API ma_uint32 ma_node_get_input_bus_count(const ma_node* pNode); -MA_API ma_uint32 ma_node_get_output_bus_count(const ma_node* pNode); -MA_API ma_uint32 ma_node_get_input_channels(const ma_node* pNode, ma_uint32 inputBusIndex); -MA_API ma_uint32 ma_node_get_output_channels(const ma_node* pNode, ma_uint32 outputBusIndex); -MA_API ma_result ma_node_attach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex, ma_node* pOtherNode, ma_uint32 otherNodeInputBusIndex); -MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex); -MA_API ma_result ma_node_detach_all_output_buses(ma_node* pNode); -MA_API ma_result ma_node_set_output_bus_volume(ma_node* pNode, ma_uint32 outputBusIndex, float volume); -MA_API float ma_node_get_output_bus_volume(const ma_node* pNode, ma_uint32 outputBusIndex); -MA_API ma_result ma_node_set_state(ma_node* pNode, ma_node_state state); -MA_API ma_node_state ma_node_get_state(const ma_node* pNode); -MA_API ma_result ma_node_set_state_time(ma_node* pNode, ma_node_state state, ma_uint64 globalTime); -MA_API ma_uint64 ma_node_get_state_time(const ma_node* pNode, ma_node_state state); -MA_API ma_node_state ma_node_get_state_by_time(const ma_node* pNode, ma_uint64 globalTime); -MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_uint64 globalTimeBeg, ma_uint64 globalTimeEnd); -MA_API ma_uint64 ma_node_get_time(const ma_node* pNode); -MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime); - - -typedef struct -{ - ma_uint32 channels; - ma_uint32 processingSizeInFrames; /* This is the preferred processing size for node processing callbacks unless overridden by a node itself. Can be 0 in which case it will be based on the frame count passed into ma_node_graph_read_pcm_frames(), but will not be well defined. */ - size_t preMixStackSizeInBytes; /* Defaults to 512KB per channel. Reducing this will save memory, but the depth of your node graph will be more restricted. */ -} ma_node_graph_config; - -MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels); - - -struct ma_node_graph -{ - /* Immutable. */ - ma_node_base base; /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */ - ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ - float* pProcessingCache; /* This will be allocated when processingSizeInFrames is non-zero. This is needed because ma_node_graph_read_pcm_frames() can be called with a variable number of frames, and we may need to do some buffering in situations where the caller requests a frame count that's not a multiple of processingSizeInFrames. */ - ma_uint32 processingCacheFramesRemaining; - ma_uint32 processingSizeInFrames; - - /* Read and written by multiple threads. */ - MA_ATOMIC(4, ma_bool32) isReading; - - /* Modified only by the audio thread. */ - ma_stack* pPreMixStack; -}; - -MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph); -MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph); -MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph); -MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph); -MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime); - - - -/* Data source node. 0 input buses, 1 output bus. Used for reading from a data source. */ -typedef struct -{ - ma_node_config nodeConfig; - ma_data_source* pDataSource; -} ma_data_source_node_config; - -MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource); - - -typedef struct -{ - ma_node_base base; - ma_data_source* pDataSource; -} ma_data_source_node; - -MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode); -MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping); -MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode); - - -/* Splitter Node. 1 input, many outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */ -typedef struct -{ - ma_node_config nodeConfig; - ma_uint32 channels; - ma_uint32 outputBusCount; -} ma_splitter_node_config; - -MA_API ma_splitter_node_config ma_splitter_node_config_init(ma_uint32 channels); - - -typedef struct -{ - ma_node_base base; -} ma_splitter_node; - -MA_API ma_result ma_splitter_node_init(ma_node_graph* pNodeGraph, const ma_splitter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_splitter_node* pSplitterNode); -MA_API void ma_splitter_node_uninit(ma_splitter_node* pSplitterNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -Biquad Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_biquad_config biquad; -} ma_biquad_node_config; - -MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2); - - -typedef struct -{ - ma_node_base baseNode; - ma_biquad biquad; -} ma_biquad_node; - -MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode); -MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode); -MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -Low Pass Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_lpf_config lpf; -} ma_lpf_node_config; - -MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); - - -typedef struct -{ - ma_node_base baseNode; - ma_lpf lpf; -} ma_lpf_node; - -MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode); -MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode); -MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -High Pass Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_hpf_config hpf; -} ma_hpf_node_config; - -MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); - - -typedef struct -{ - ma_node_base baseNode; - ma_hpf hpf; -} ma_hpf_node; - -MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode); -MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode); -MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -Band Pass Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_bpf_config bpf; -} ma_bpf_node_config; - -MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); - - -typedef struct -{ - ma_node_base baseNode; - ma_bpf bpf; -} ma_bpf_node; - -MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode); -MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode); -MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -Notching Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_notch_config notch; -} ma_notch_node_config; - -MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency); - - -typedef struct -{ - ma_node_base baseNode; - ma_notch2 notch; -} ma_notch_node; - -MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode); -MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode); -MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -Peaking Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_peak_config peak; -} ma_peak_node_config; - -MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); - - -typedef struct -{ - ma_node_base baseNode; - ma_peak2 peak; -} ma_peak_node; - -MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode); -MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode); -MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -Low Shelf Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_loshelf_config loshelf; -} ma_loshelf_node_config; - -MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); - - -typedef struct -{ - ma_node_base baseNode; - ma_loshelf2 loshelf; -} ma_loshelf_node; - -MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode); -MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode); -MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -/* -High Shelf Filter Node -*/ -typedef struct -{ - ma_node_config nodeConfig; - ma_hishelf_config hishelf; -} ma_hishelf_node_config; - -MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); - - -typedef struct -{ - ma_node_base baseNode; - ma_hishelf2 hishelf; -} ma_hishelf_node; - -MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode); -MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode); -MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -typedef struct -{ - ma_node_config nodeConfig; - ma_delay_config delay; -} ma_delay_node_config; - -MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay); - - -typedef struct -{ - ma_node_base baseNode; - ma_delay delay; -} ma_delay_node; - -MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode); -MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value); -MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode); -MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value); -MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode); -MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value); -MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode); -#endif /* MA_NO_NODE_GRAPH */ - - -/* SECTION: miniaudio_engine.h */ -/************************************************************************************************************************************************************ - -Engine - -************************************************************************************************************************************************************/ -#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) -typedef struct ma_engine ma_engine; -typedef struct ma_sound ma_sound; - - -/* Sound flags. */ -typedef enum -{ - /* Resource manager flags. */ - MA_SOUND_FLAG_STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */ - MA_SOUND_FLAG_DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */ - MA_SOUND_FLAG_ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */ - MA_SOUND_FLAG_WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */ - MA_SOUND_FLAG_UNKNOWN_LENGTH = 0x00000010, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH */ - MA_SOUND_FLAG_LOOPING = 0x00000020, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING */ - - /* ma_sound specific flags. */ - MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT = 0x00001000, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */ - MA_SOUND_FLAG_NO_PITCH = 0x00002000, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */ - MA_SOUND_FLAG_NO_SPATIALIZATION = 0x00004000 /* Disable spatialization. */ -} ma_sound_flags; - -#ifndef MA_ENGINE_MAX_LISTENERS -#define MA_ENGINE_MAX_LISTENERS 4 -#endif - -#define MA_LISTENER_INDEX_CLOSEST ((ma_uint8)-1) - -typedef enum -{ - ma_engine_node_type_sound, - ma_engine_node_type_group -} ma_engine_node_type; - -typedef struct -{ - ma_engine* pEngine; - ma_engine_node_type type; - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_uint32 sampleRate; /* Only used when the type is set to ma_engine_node_type_sound. */ - ma_uint32 volumeSmoothTimeInPCMFrames; /* The number of frames to smooth over volume changes. Defaults to 0 in which case no smoothing is used. */ - ma_mono_expansion_mode monoExpansionMode; - ma_bool8 isPitchDisabled; /* Pitching can be explicitly disabled with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ - ma_bool8 isSpatializationDisabled; /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ - ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ -} ma_engine_node_config; - -MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags); - - -/* Base node object for both ma_sound and ma_sound_group. */ -typedef struct -{ - ma_node_base baseNode; /* Must be the first member for compatibility with the ma_node API. */ - ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ - ma_uint32 sampleRate; /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */ - ma_uint32 volumeSmoothTimeInPCMFrames; - ma_mono_expansion_mode monoExpansionMode; - ma_fader fader; - ma_linear_resampler resampler; /* For pitch shift. */ - ma_spatializer spatializer; - ma_panner panner; - ma_gainer volumeGainer; /* This will only be used if volumeSmoothTimeInPCMFrames is > 0. */ - ma_atomic_float volume; /* Defaults to 1. */ - MA_ATOMIC(4, float) pitch; - float oldPitch; /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */ - float oldDopplerPitch; /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */ - MA_ATOMIC(4, ma_bool32) isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */ - MA_ATOMIC(4, ma_bool32) isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */ - MA_ATOMIC(4, ma_uint32) pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ - - /* When setting a fade, it's not done immediately in ma_sound_set_fade(). It's deferred to the audio thread which means we need to store the settings here. */ - struct - { - ma_atomic_float volumeBeg; - ma_atomic_float volumeEnd; - ma_atomic_uint64 fadeLengthInFrames; /* <-- Defaults to (~(ma_uint64)0) which is used to indicate that no fade should be applied. */ - ma_atomic_uint64 absoluteGlobalTimeInFrames; /* <-- The time to start the fade. */ - } fadeSettings; - - /* Memory management. */ - ma_bool8 _ownsHeap; - void* _pHeap; -} ma_engine_node; - -MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes); -MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode); -MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode); -MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks); - - -#define MA_SOUND_SOURCE_CHANNEL_COUNT 0xFFFFFFFF - -/* Callback for when a sound reaches the end. */ -typedef void (* ma_sound_end_proc)(void* pUserData, ma_sound* pSound); - -typedef struct -{ - const char* pFilePath; /* Set this to load from the resource manager. */ - const wchar_t* pFilePathW; /* Set this to load from the resource manager. */ - ma_data_source* pDataSource; /* Set this to load from an existing data source. */ - ma_node* pInitialAttachment; /* If set, the sound will be attached to an input of this node. This can be set to a ma_sound. If set to NULL, the sound will be attached directly to the endpoint unless MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT is set in `flags`. */ - ma_uint32 initialAttachmentInputBusIndex; /* The index of the input bus of pInitialAttachment to attach the sound to. */ - ma_uint32 channelsIn; /* Ignored if using a data source as input (the data source's channel count will be used always). Otherwise, setting to 0 will cause the engine's channel count to be used. */ - ma_uint32 channelsOut; /* Set this to 0 (default) to use the engine's channel count. Set to MA_SOUND_SOURCE_CHANNEL_COUNT to use the data source's channel count (only used if using a data source as input). */ - ma_mono_expansion_mode monoExpansionMode; /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */ - ma_uint32 flags; /* A combination of MA_SOUND_FLAG_* flags. */ - ma_uint32 volumeSmoothTimeInPCMFrames; /* The number of frames to smooth over volume changes. Defaults to 0 in which case no smoothing is used. */ - ma_uint64 initialSeekPointInPCMFrames; /* Initializes the sound such that it's seeked to this location by default. */ - ma_uint64 rangeBegInPCMFrames; - ma_uint64 rangeEndInPCMFrames; - ma_uint64 loopPointBegInPCMFrames; - ma_uint64 loopPointEndInPCMFrames; - ma_sound_end_proc endCallback; /* Fired when the sound reaches the end. Will be fired from the audio thread. Do not restart, uninitialize or otherwise change the state of the sound from here. Instead fire an event or set a variable to indicate to a different thread to change the start of the sound. Will not be fired in response to a scheduled stop with ma_sound_set_stop_time_*(). */ - void* pEndCallbackUserData; -#ifndef MA_NO_RESOURCE_MANAGER - ma_resource_manager_pipeline_notifications initNotifications; -#endif - ma_fence* pDoneFence; /* Deprecated. Use initNotifications instead. Released when the resource manager has finished decoding the entire sound. Not used with streams. */ - ma_bool32 isLooping; /* Deprecated. Use the MA_SOUND_FLAG_LOOPING flag in `flags` instead. */ -} ma_sound_config; - -MA_API ma_sound_config ma_sound_config_init(void); /* Deprecated. Will be removed in version 0.12. Use ma_sound_config_2() instead. */ -MA_API ma_sound_config ma_sound_config_init_2(ma_engine* pEngine); /* Will be renamed to ma_sound_config_init() in version 0.12. */ - -struct ma_sound -{ - ma_engine_node engineNode; /* Must be the first member for compatibility with the ma_node API. */ - ma_data_source* pDataSource; - MA_ATOMIC(8, ma_uint64) seekTarget; /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */ - MA_ATOMIC(4, ma_bool32) atEnd; - ma_sound_end_proc endCallback; - void* pEndCallbackUserData; - ma_bool8 ownsDataSource; - - /* - We're declaring a resource manager data source object here to save us a malloc when loading a - sound via the resource manager, which I *think* will be the most common scenario. - */ -#ifndef MA_NO_RESOURCE_MANAGER - ma_resource_manager_data_source* pResourceManagerDataSource; -#endif -}; - -/* Structure specifically for sounds played with ma_engine_play_sound(). Making this a separate structure to reduce overhead. */ -typedef struct ma_sound_inlined ma_sound_inlined; -struct ma_sound_inlined -{ - ma_sound sound; - ma_sound_inlined* pNext; - ma_sound_inlined* pPrev; -}; - -/* A sound group is just a sound. */ -typedef ma_sound_config ma_sound_group_config; -typedef ma_sound ma_sound_group; - -MA_API ma_sound_group_config ma_sound_group_config_init(void); /* Deprecated. Will be removed in version 0.12. Use ma_sound_config_2() instead. */ -MA_API ma_sound_group_config ma_sound_group_config_init_2(ma_engine* pEngine); /* Will be renamed to ma_sound_config_init() in version 0.12. */ - -typedef void (* ma_engine_process_proc)(void* pUserData, float* pFramesOut, ma_uint64 frameCount); - -typedef struct -{ -#if !defined(MA_NO_RESOURCE_MANAGER) - ma_resource_manager* pResourceManager; /* Can be null in which case a resource manager will be created for you. */ -#endif -#if !defined(MA_NO_DEVICE_IO) - ma_context* pContext; - ma_device* pDevice; /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */ - ma_device_id* pPlaybackDeviceID; /* The ID of the playback device to use with the default listener. */ - ma_device_data_proc dataCallback; /* Can be null. Can be used to provide a custom device data callback. */ - ma_device_notification_proc notificationCallback; -#endif - ma_log* pLog; /* When set to NULL, will use the context's log. */ - ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ - ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ - ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native channel count of the device. */ - ma_uint32 periodSizeInFrames; /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ - ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ - ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ - ma_uint32 gainSmoothTimeInMilliseconds; /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */ - ma_uint32 defaultVolumeSmoothTimeInPCMFrames; /* Defaults to 0. Controls the default amount of smoothing to apply to volume changes to sounds. High values means more smoothing at the expense of high latency (will take longer to reach the new volume). */ - ma_uint32 preMixStackSizeInBytes; /* A stack is used for internal processing in the node graph. This allows you to configure the size of this stack. Smaller values will reduce the maximum depth of your node graph. You should rarely need to modify this. */ - ma_allocation_callbacks allocationCallbacks; - ma_bool32 noAutoStart; /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */ - ma_bool32 noDevice; /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */ - ma_mono_expansion_mode monoExpansionMode; /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */ - ma_vfs* pResourceManagerVFS; /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */ - ma_engine_process_proc onProcess; /* Fired at the end of each call to ma_engine_read_pcm_frames(). For engine's that manage their own internal device (the default configuration), this will be fired from the audio thread, and you do not need to call ma_engine_read_pcm_frames() manually in order to trigger this. */ - void* pProcessUserData; /* User data that's passed into onProcess. */ -} ma_engine_config; - -MA_API ma_engine_config ma_engine_config_init(void); - - -struct ma_engine -{ - ma_node_graph nodeGraph; /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ -#if !defined(MA_NO_RESOURCE_MANAGER) - ma_resource_manager* pResourceManager; -#endif -#if !defined(MA_NO_DEVICE_IO) - ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ -#endif - ma_log* pLog; - ma_uint32 sampleRate; - ma_uint32 listenerCount; - ma_spatializer_listener listeners[MA_ENGINE_MAX_LISTENERS]; - ma_allocation_callbacks allocationCallbacks; - ma_bool8 ownsResourceManager; - ma_bool8 ownsDevice; - ma_spinlock inlinedSoundLock; /* For synchronizing access to the inlined sound list. */ - ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ - MA_ATOMIC(4, ma_uint32) inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ - ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ - ma_uint32 defaultVolumeSmoothTimeInPCMFrames; - ma_mono_expansion_mode monoExpansionMode; - ma_engine_process_proc onProcess; - void* pProcessUserData; -}; - -MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine); -MA_API void ma_engine_uninit(ma_engine* pEngine); -MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_node_graph* ma_engine_get_node_graph(ma_engine* pEngine); -#if !defined(MA_NO_RESOURCE_MANAGER) -MA_API ma_resource_manager* ma_engine_get_resource_manager(ma_engine* pEngine); -#endif -MA_API ma_device* ma_engine_get_device(ma_engine* pEngine); -MA_API ma_log* ma_engine_get_log(ma_engine* pEngine); -MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine); -MA_API ma_uint64 ma_engine_get_time_in_pcm_frames(const ma_engine* pEngine); -MA_API ma_uint64 ma_engine_get_time_in_milliseconds(const ma_engine* pEngine); -MA_API ma_result ma_engine_set_time_in_pcm_frames(ma_engine* pEngine, ma_uint64 globalTime); -MA_API ma_result ma_engine_set_time_in_milliseconds(ma_engine* pEngine, ma_uint64 globalTime); -MA_API ma_uint64 ma_engine_get_time(const ma_engine* pEngine); /* Deprecated. Use ma_engine_get_time_in_pcm_frames(). Will be removed in version 0.12. */ -MA_API ma_result ma_engine_set_time(ma_engine* pEngine, ma_uint64 globalTime); /* Deprecated. Use ma_engine_set_time_in_pcm_frames(). Will be removed in version 0.12. */ -MA_API ma_uint32 ma_engine_get_channels(const ma_engine* pEngine); -MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine); - -MA_API ma_result ma_engine_start(ma_engine* pEngine); -MA_API ma_result ma_engine_stop(ma_engine* pEngine); -MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume); -MA_API float ma_engine_get_volume(ma_engine* pEngine); -MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB); -MA_API float ma_engine_get_gain_db(ma_engine* pEngine); - -MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine); -MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ); -MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); -MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex); -MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); -MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex); -MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); -MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex); -MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain); -MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); -MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); -MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex); -MA_API void ma_engine_listener_set_enabled(ma_engine* pEngine, ma_uint32 listenerIndex, ma_bool32 isEnabled); -MA_API ma_bool32 ma_engine_listener_is_enabled(const ma_engine* pEngine, ma_uint32 listenerIndex); - -#ifndef MA_NO_RESOURCE_MANAGER -MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex); -MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup); /* Fire and forget. */ -#endif - -#ifndef MA_NO_RESOURCE_MANAGER -MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound); -MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound); -MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound); -#endif -MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound); -MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound); -MA_API void ma_sound_uninit(ma_sound* pSound); -MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound); -MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound); -MA_API ma_result ma_sound_start(ma_sound* pSound); -MA_API ma_result ma_sound_stop(ma_sound* pSound); -MA_API ma_result ma_sound_stop_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. */ -MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. */ -MA_API void ma_sound_set_volume(ma_sound* pSound, float volume); -MA_API float ma_sound_get_volume(const ma_sound* pSound); -MA_API void ma_sound_set_pan(ma_sound* pSound, float pan); -MA_API float ma_sound_get_pan(const ma_sound* pSound); -MA_API void ma_sound_set_pan_mode(ma_sound* pSound, ma_pan_mode panMode); -MA_API ma_pan_mode ma_sound_get_pan_mode(const ma_sound* pSound); -MA_API void ma_sound_set_pitch(ma_sound* pSound, float pitch); -MA_API float ma_sound_get_pitch(const ma_sound* pSound); -MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enabled); -MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound); -MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex); -MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound); -MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound); -MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound); -MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z); -MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound); -MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z); -MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound); -MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z); -MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound); -MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel); -MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound); -MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning); -MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound); -MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff); -MA_API float ma_sound_get_rolloff(const ma_sound* pSound); -MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain); -MA_API float ma_sound_get_min_gain(const ma_sound* pSound); -MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain); -MA_API float ma_sound_get_max_gain(const ma_sound* pSound); -MA_API void ma_sound_set_min_distance(ma_sound* pSound, float minDistance); -MA_API float ma_sound_get_min_distance(const ma_sound* pSound); -MA_API void ma_sound_set_max_distance(ma_sound* pSound, float maxDistance); -MA_API float ma_sound_get_max_distance(const ma_sound* pSound); -MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float outerAngleInRadians, float outerGain); -MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); -MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor); -MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound); -MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor); -MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound); -MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); -MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); -MA_API void ma_sound_set_fade_start_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames, ma_uint64 absoluteGlobalTimeInFrames); -MA_API void ma_sound_set_fade_start_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds, ma_uint64 absoluteGlobalTimeInMilliseconds); -MA_API float ma_sound_get_current_fade_volume(const ma_sound* pSound); -MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames); -MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds); -MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames); -MA_API void ma_sound_set_stop_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds); -MA_API void ma_sound_set_stop_time_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 stopAbsoluteGlobalTimeInFrames, ma_uint64 fadeLengthInFrames); -MA_API void ma_sound_set_stop_time_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 stopAbsoluteGlobalTimeInMilliseconds, ma_uint64 fadeLengthInMilliseconds); -MA_API ma_bool32 ma_sound_is_playing(const ma_sound* pSound); -MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound); -MA_API ma_uint64 ma_sound_get_time_in_milliseconds(const ma_sound* pSound); -MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping); -MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); -MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); -MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ -MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */ -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor); -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength); -MA_API ma_result ma_sound_set_end_callback(ma_sound* pSound, ma_sound_end_proc callback, void* pUserData); - -MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); -MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup); -MA_API void ma_sound_group_uninit(ma_sound_group* pGroup); -MA_API ma_engine* ma_sound_group_get_engine(const ma_sound_group* pGroup); -MA_API ma_result ma_sound_group_start(ma_sound_group* pGroup); -MA_API ma_result ma_sound_group_stop(ma_sound_group* pGroup); -MA_API void ma_sound_group_set_volume(ma_sound_group* pGroup, float volume); -MA_API float ma_sound_group_get_volume(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_pan(ma_sound_group* pGroup, float pan); -MA_API float ma_sound_group_get_pan(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_pan_mode(ma_sound_group* pGroup, ma_pan_mode panMode); -MA_API ma_pan_mode ma_sound_group_get_pan_mode(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_pitch(ma_sound_group* pGroup, float pitch); -MA_API float ma_sound_group_get_pitch(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma_bool32 enabled); -MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex); -MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup); -MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup); -MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z); -MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z); -MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z); -MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel); -MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning); -MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff); -MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain); -MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain); -MA_API float ma_sound_group_get_max_gain(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_min_distance(ma_sound_group* pGroup, float minDistance); -MA_API float ma_sound_group_get_min_distance(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_max_distance(ma_sound_group* pGroup, float maxDistance); -MA_API float ma_sound_group_get_max_distance(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRadians, float outerAngleInRadians, float outerGain); -MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); -MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor); -MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor); -MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup); -MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); -MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); -MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup); -MA_API void ma_sound_group_set_start_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames); -MA_API void ma_sound_group_set_start_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds); -MA_API void ma_sound_group_set_stop_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames); -MA_API void ma_sound_group_set_stop_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds); -MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup); -MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup); -#endif /* MA_NO_ENGINE */ -/* END SECTION: miniaudio_engine.h */ - #ifdef __cplusplus } #endif #endif /* miniaudio_h */ -/* -This is for preventing greying out of the implementation section. -*/ -#if defined(Q_CREATOR_RUN) || defined(__INTELLISENSE__) || defined(__CDT_PARSER__) -#define MINIAUDIO_IMPLEMENTATION -#endif /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -11509,10 +6357,8 @@ IMPLEMENTATION #define miniaudio_c #include -#include /* For INT_MAX */ -#include /* sin(), etc. */ -#include /* For malloc(), free(), wcstombs(). */ -#include /* For memset() */ +#include /* For INT_MAX */ +#include /* sin(), etc. */ #include #include @@ -11520,37 +6366,14 @@ IMPLEMENTATION #include /* For strcasecmp(). */ #include /* For wcslen(), wcsrtombs() */ #endif -#ifdef _MSC_VER - #include /* For _controlfp_s constants */ -#endif -#if defined(MA_WIN32) - #include - - /* - There's a possibility that WIN32_LEAN_AND_MEAN has been defined which will exclude some symbols - such as STGM_READ and CLSCTL_ALL. We need to check these and define them ourselves if they're - unavailable. - */ - #ifndef STGM_READ - #define STGM_READ 0x00000000L - #endif - #ifndef CLSCTX_ALL - #define CLSCTX_ALL 23 - #endif - - /* IUnknown is used by both the WASAPI and DirectSound backends. It easier to just declare our version here. */ - typedef struct ma_IUnknown ma_IUnknown; -#endif - -#if !defined(MA_WIN32) +#ifdef MA_WIN32 +#include +#else +#include /* For malloc(), free(), wcstombs(). */ +#include /* For memset() */ #include #include /* select() (used for ma_sleep()). */ -#include -#endif - -#ifdef MA_NX -#include /* For nanosleep() */ #endif #include /* For fstat(), etc. */ @@ -11559,8 +6382,6 @@ IMPLEMENTATION #include #endif - -/* Architecture Detection */ #if !defined(MA_64BIT) && !defined(MA_32BIT) #ifdef _WIN32 #ifdef _WIN64 @@ -11590,23 +6411,22 @@ IMPLEMENTATION #endif #endif -#if defined(__arm__) || defined(_M_ARM) -#define MA_ARM32 -#endif -#if defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) -#define MA_ARM64 -#endif - +/* Architecture Detection */ #if defined(__x86_64__) || defined(_M_X64) #define MA_X64 #elif defined(__i386) || defined(_M_IX86) #define MA_X86 -#elif defined(MA_ARM32) || defined(MA_ARM64) +#elif defined(__arm__) || defined(_M_ARM) #define MA_ARM #endif +/* Cannot currently support AVX-512 if AVX is disabled. */ +#if !defined(MA_NO_AVX512) && defined(MA_NO_AVX2) +#define MA_NO_AVX512 +#endif + /* Intrinsics Support */ -#if (defined(MA_X64) || defined(MA_X86)) && !defined(__COSMOPOLITAN__) +#if defined(MA_X64) || defined(MA_X86) #if defined(_MSC_VER) && !defined(__clang__) /* MSVC. */ #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2) /* 2005 */ @@ -11618,6 +6438,9 @@ IMPLEMENTATION #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2) /* 2012 */ #define MA_SUPPORT_AVX2 #endif + #if _MSC_VER >= 1910 && !defined(MA_NO_AVX512) /* 2017 */ + #define MA_SUPPORT_AVX512 + #endif #else /* Assume GNUC-style. */ #if defined(__SSE2__) && !defined(MA_NO_SSE2) @@ -11629,6 +6452,9 @@ IMPLEMENTATION #if defined(__AVX2__) && !defined(MA_NO_AVX2) #define MA_SUPPORT_AVX2 #endif + #if defined(__AVX512F__) && !defined(MA_NO_AVX512) + #define MA_SUPPORT_AVX512 + #endif #endif /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ @@ -11642,9 +6468,14 @@ IMPLEMENTATION #if !defined(MA_SUPPORT_AVX2) && !defined(MA_NO_AVX2) && __has_include() #define MA_SUPPORT_AVX2 #endif + #if !defined(MA_SUPPORT_AVX512) && !defined(MA_NO_AVX512) && __has_include() + #define MA_SUPPORT_AVX512 + #endif #endif - #if defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX) + #if defined(MA_SUPPORT_AVX512) + #include /* Not a mistake. Intentionally including instead of because otherwise the compiler will complain. */ + #elif defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX) #include #elif defined(MA_SUPPORT_SSE2) #include @@ -11654,6 +6485,16 @@ IMPLEMENTATION #if defined(MA_ARM) #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) #define MA_SUPPORT_NEON + #endif + + /* Fall back to looking for the #include file. */ + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(MA_SUPPORT_NEON) && !defined(MA_NO_NEON) && __has_include() + #define MA_SUPPORT_NEON + #endif + #endif + + #if defined(MA_SUPPORT_NEON) #include #endif #endif @@ -11662,7 +6503,6 @@ IMPLEMENTATION #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4752) /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */ - #pragma warning(disable:4049) /* compiler limit : terminating line number emission */ #endif #if defined(MA_X64) || defined(MA_X86) @@ -11695,7 +6535,7 @@ IMPLEMENTATION What's basically happening is that we're saving and restoring the ebx register manually. */ - #if defined(MA_X86) && defined(__PIC__) + #if defined(DRFLAC_X86) && defined(__PIC__) __asm__ __volatile__ ( "xchg{l} {%%}ebx, %k1;" "cpuid;" @@ -11824,6 +6664,41 @@ static MA_INLINE ma_bool32 ma_has_avx2(void) #endif } +static MA_INLINE ma_bool32 ma_has_avx512f(void) +{ +#if defined(MA_SUPPORT_AVX512) + #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX512) + #if defined(__AVX512F__) + return MA_TRUE; /* If the compiler is allowed to freely generate AVX-512F code we can assume support. */ + #else + /* AVX-512 requires both CPU and OS support. */ + #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV) + return MA_FALSE; + #else + int info1[4]; + int info7[4]; + ma_cpuid(info1, 1); + ma_cpuid(info7, 7); + if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 16)) != 0)) { + ma_uint64 xrc = ma_xgetbv(0); + if ((xrc & 0xE6) == 0xE6) { + return MA_TRUE; + } else { + return MA_FALSE; + } + } else { + return MA_FALSE; + } + #endif + #endif + #else + return MA_FALSE; /* AVX-512F is only supported on x86 and x64 architectures. */ + #endif +#else + return MA_FALSE; /* No compiler support. */ +#endif +} + static MA_INLINE ma_bool32 ma_has_neon(void) { #if defined(MA_SUPPORT_NEON) @@ -11842,6 +6717,23 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif } +#define MA_SIMD_NONE 0 +#define MA_SIMD_SSE2 1 +#define MA_SIMD_AVX2 2 +#define MA_SIMD_NEON 3 + +#ifndef MA_PREFERRED_SIMD + # if defined(MA_SUPPORT_SSE2) && defined(MA_PREFER_SSE2) + #define MA_PREFERRED_SIMD MA_SIMD_SSE2 + #elif defined(MA_SUPPORT_AVX2) && defined(MA_PREFER_AVX2) + #define MA_PREFERRED_SIMD MA_SIMD_AVX2 + #elif defined(MA_SUPPORT_NEON) && defined(MA_PREFER_NEON) + #define MA_PREFERRED_SIMD MA_SIMD_NEON + #else + #define MA_PREFERRED_SIMD MA_SIMD_NONE + #endif +#endif + #if defined(__has_builtin) #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x) #else @@ -11856,7 +6748,7 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #elif defined(_MSC_VER) #define MA_ASSUME(x) __assume(x) #else - #define MA_ASSUME(x) (void)(x) + #define MA_ASSUME(x) while(0) #endif #endif @@ -11955,7 +6847,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) (void)milliseconds; MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */ #else - #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_NX) + #if _POSIX_C_SOURCE >= 199309L struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; @@ -11970,7 +6862,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) } #endif -static MA_INLINE void ma_sleep(ma_uint32 milliseconds) +static void ma_sleep(ma_uint32 milliseconds) { #ifdef MA_WIN32 ma_sleep__win32(milliseconds); @@ -11981,7 +6873,7 @@ static MA_INLINE void ma_sleep(ma_uint32 milliseconds) } #endif -static MA_INLINE void ma_yield(void) +static MA_INLINE void ma_yield() { #if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) /* x86/x64 */ @@ -11991,7 +6883,7 @@ static MA_INLINE void ma_yield(void) #else #if defined(__DMC__) /* Digital Mars does not recognize the PAUSE opcode. Fall back to NOP. */ - __asm nop; + __asm nop; #else __asm pause; #endif @@ -11999,7 +6891,7 @@ static MA_INLINE void ma_yield(void) #else __asm__ __volatile__ ("pause"); #endif -#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) +#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) /* ARM */ #if defined(_MSC_VER) /* Apparently there is a __yield() intrinsic that's compatible with ARM, but I cannot find documentation for it nor can I find where it's declared. */ @@ -12013,110 +6905,6 @@ static MA_INLINE void ma_yield(void) } -#define MA_MM_DENORMALS_ZERO_MASK 0x0040 -#define MA_MM_FLUSH_ZERO_MASK 0x8000 - -static MA_INLINE unsigned int ma_disable_denormals(void) -{ - unsigned int prevState; - - #if defined(_MSC_VER) - { - /* - Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't - know which version of Visual Studio first added support for _controlfp_s(), but I do know - that VC6 lacks support. _MSC_VER = 1200 is VC6, but if you get compilation errors on older - versions of Visual Studio, let me know and I'll make the necessary adjustment. - */ - #if _MSC_VER <= 1200 - { - prevState = _statusfp(); - _controlfp(prevState | _DN_FLUSH, _MCW_DN); - } - #else - { - unsigned int unused; - _controlfp_s(&prevState, 0, 0); - _controlfp_s(&unused, prevState | _DN_FLUSH, _MCW_DN); - } - #endif - } - #elif defined(MA_X86) || defined(MA_X64) - { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ - { - prevState = _mm_getcsr(); - _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK); - } - #else - { - /* x88/64, but no support for _mm_getcsr()/_mm_setcsr(). May need to fall back to inlined assembly here. */ - prevState = 0; - } - #endif - } - #else - { - /* Unknown or unsupported architecture. No-op. */ - prevState = 0; - } - #endif - - return prevState; -} - -static MA_INLINE void ma_restore_denormals(unsigned int prevState) -{ - #if defined(_MSC_VER) - { - /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */ - #if _MSC_VER <= 1200 - { - _controlfp(prevState, _MCW_DN); - } - #else - { - unsigned int unused; - _controlfp_s(&unused, prevState, _MCW_DN); - } - #endif - } - #elif defined(MA_X86) || defined(MA_X64) - { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ - { - _mm_setcsr(prevState); - } - #else - { - /* x88/64, but no support for _mm_getcsr()/_mm_setcsr(). May need to fall back to inlined assembly here. */ - (void)prevState; - } - #endif - } - #else - { - /* Unknown or unsupported architecture. No-op. */ - (void)prevState; - } - #endif -} - - -#ifdef MA_ANDROID -#include - -int ma_android_sdk_version() -{ - char sdkVersion[PROP_VALUE_MAX + 1] = {0, }; - if (__system_property_get("ro.build.version.sdk", sdkVersion)) { - return atoi(sdkVersion); - } - - return 0; -} -#endif - #ifndef MA_COINIT_VALUE #define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED */ @@ -12270,149 +7058,114 @@ MA_API const char* ma_version_string(void) Standard Library Stuff ******************************************************************************/ -#ifndef MA_ASSERT -#define MA_ASSERT(condition) assert(condition) -#endif - #ifndef MA_MALLOC -#define MA_MALLOC(sz) malloc((sz)) +#ifdef MA_WIN32 +#define MA_MALLOC(sz) HeapAlloc(GetProcessHeap(), 0, (sz)) +#else +#define MA_MALLOC(sz) malloc((sz)) #endif +#endif + #ifndef MA_REALLOC -#define MA_REALLOC(p, sz) realloc((p), (sz)) +#ifdef MA_WIN32 +#define MA_REALLOC(p, sz) (((sz) > 0) ? ((p) ? HeapReAlloc(GetProcessHeap(), 0, (p), (sz)) : HeapAlloc(GetProcessHeap(), 0, (sz))) : ((VOID*)(size_t)(HeapFree(GetProcessHeap(), 0, (p)) & 0))) +#else +#define MA_REALLOC(p, sz) realloc((p), (sz)) #endif +#endif + #ifndef MA_FREE -#define MA_FREE(p) free((p)) +#ifdef MA_WIN32 +#define MA_FREE(p) HeapFree(GetProcessHeap(), 0, (p)) +#else +#define MA_FREE(p) free((p)) +#endif #endif - -static MA_INLINE void ma_zero_memory_default(void* p, size_t sz) -{ - if (p == NULL) { - MA_ASSERT(sz == 0); /* If this is triggered there's an error with the calling code. */ - return; - } - - if (sz > 0) { - memset(p, 0, sz); - } -} - #ifndef MA_ZERO_MEMORY -#define MA_ZERO_MEMORY(p, sz) ma_zero_memory_default((p), (sz)) +#ifdef MA_WIN32 +#define MA_ZERO_MEMORY(p, sz) ZeroMemory((p), (sz)) +#else +#define MA_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif +#endif + #ifndef MA_COPY_MEMORY -#define MA_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#ifdef MA_WIN32 +#define MA_COPY_MEMORY(dst, src, sz) CopyMemory((dst), (src), (sz)) +#else +#define MA_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) #endif -#ifndef MA_MOVE_MEMORY -#define MA_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz)) #endif -#define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p), sizeof(*(p))) +#ifndef MA_ASSERT +#ifdef MA_WIN32 +#define MA_ASSERT(condition) assert(condition) +#else +#define MA_ASSERT(condition) assert(condition) +#endif +#endif -#define ma_countof(x) (sizeof(x) / sizeof(x[0])) -#define ma_max(x, y) (((x) > (y)) ? (x) : (y)) -#define ma_min(x, y) (((x) < (y)) ? (x) : (y)) -#define ma_abs(x) (((x) > 0) ? (x) : -(x)) -#define ma_clamp(x, lo, hi) (ma_max(lo, ma_min(x, hi))) -#define ma_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset)) -#define ma_align(x, a) (((x) + ((a)-1)) & ~((a)-1)) -#define ma_align_64(x) ma_align(x, 8) +#define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p), sizeof(*(p))) + +#define ma_countof(x) (sizeof(x) / sizeof(x[0])) +#define ma_max(x, y) (((x) > (y)) ? (x) : (y)) +#define ma_min(x, y) (((x) < (y)) ? (x) : (y)) +#define ma_abs(x) (((x) > 0) ? (x) : -(x)) +#define ma_clamp(x, lo, hi) (ma_max(lo, ma_min(x, hi))) +#define ma_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset)) #define ma_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (channels)) -static MA_INLINE double ma_sind(double x) +static MA_INLINE double ma_sin(double x) { /* TODO: Implement custom sin(x). */ return sin(x); } -static MA_INLINE double ma_expd(double x) +static MA_INLINE double ma_exp(double x) { /* TODO: Implement custom exp(x). */ return exp(x); } -static MA_INLINE double ma_logd(double x) +static MA_INLINE double ma_log(double x) { /* TODO: Implement custom log(x). */ return log(x); } -static MA_INLINE double ma_powd(double x, double y) +static MA_INLINE double ma_pow(double x, double y) { /* TODO: Implement custom pow(x, y). */ return pow(x, y); } -static MA_INLINE double ma_sqrtd(double x) +static MA_INLINE double ma_sqrt(double x) { /* TODO: Implement custom sqrt(x). */ return sqrt(x); } -static MA_INLINE float ma_rsqrtf(float x) +static MA_INLINE double ma_cos(double x) { - #if defined(MA_SUPPORT_SSE2) && !defined(MA_NO_SSE2) && (defined(MA_X64) || (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)) - { - /* - For SSE we can use RSQRTSS. - - This Stack Overflow post suggests that compilers don't necessarily generate optimal code - when using intrinsics: - - https://web.archive.org/web/20221211012522/https://stackoverflow.com/questions/32687079/getting-fewest-instructions-for-rsqrtss-wrapper - - I'm going to do something similar here, but a bit simpler. - */ - #if defined(__GNUC__) || defined(__clang__) - { - float result; - __asm__ __volatile__("rsqrtss %1, %0" : "=x"(result) : "x"(x)); - return result; - } - #else - { - return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ps1(x))); - } - #endif - } - #else - { - return 1 / (float)ma_sqrtd(x); - } - #endif + return ma_sin((MA_PI_D*0.5) - x); } - -static MA_INLINE float ma_sinf(float x) +static MA_INLINE double ma_log10(double x) { - return (float)ma_sind((float)x); -} - -static MA_INLINE double ma_cosd(double x) -{ - return ma_sind((MA_PI_D*0.5) - x); -} - -static MA_INLINE float ma_cosf(float x) -{ - return (float)ma_cosd((float)x); -} - -static MA_INLINE double ma_log10d(double x) -{ - return ma_logd(x) * 0.43429448190325182765; + return ma_log(x) * 0.43429448190325182765; } static MA_INLINE float ma_powf(float x, float y) { - return (float)ma_powd((double)x, (double)y); + return (float)ma_pow((double)x, (double)y); } static MA_INLINE float ma_log10f(float x) { - return (float)ma_log10d((double)x); + return (float)ma_log10((double)x); } @@ -12444,11 +7197,8 @@ Return Values: 34: ERANGE Not using symbolic constants for errors because I want to avoid #including errno.h - -These are marked as no-inline because of some bad code generation by Clang. None of these functions -are used in any performance-critical code within miniaudio. */ -MA_API MA_NO_INLINE int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) +MA_API int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) { size_t i; @@ -12476,7 +7226,7 @@ MA_API MA_NO_INLINE int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char return 34; } -MA_API MA_NO_INLINE int ma_wcscpy_s(wchar_t* dst, size_t dstCap, const wchar_t* src) +MA_API int ma_wcscpy_s(wchar_t* dst, size_t dstCap, const wchar_t* src) { size_t i; @@ -12505,7 +7255,7 @@ MA_API MA_NO_INLINE int ma_wcscpy_s(wchar_t* dst, size_t dstCap, const wchar_t* } -MA_API MA_NO_INLINE int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) +MA_API int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) { size_t maxcount; size_t i; @@ -12539,7 +7289,7 @@ MA_API MA_NO_INLINE int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const cha return 34; } -MA_API MA_NO_INLINE int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) +MA_API int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) { char* dstorig; @@ -12581,7 +7331,7 @@ MA_API MA_NO_INLINE int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char return 0; } -MA_API MA_NO_INLINE int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) +MA_API int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) { char* dstorig; @@ -12627,7 +7377,7 @@ MA_API MA_NO_INLINE int ma_strncat_s(char* dst, size_t dstSizeInBytes, const cha return 0; } -MA_API MA_NO_INLINE int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) +MA_API int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) { int sign; unsigned int valueU; @@ -12696,7 +7446,7 @@ MA_API MA_NO_INLINE int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, i return 0; } -MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) +MA_API int ma_strcmp(const char* str1, const char* str2) { if (str1 == str2) return 0; @@ -12719,7 +7469,7 @@ MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } -MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) +MA_API int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) { int result; @@ -12736,17 +7486,10 @@ MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA return result; } -MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) { - size_t sz; - char* dst; - - if (src == NULL) { - return NULL; - } - - sz = strlen(src)+1; - dst = (char*)ma_malloc(sz, pAllocationCallbacks); + size_t sz = strlen(src)+1; + char* dst = (char*)ma_malloc(sz, pAllocationCallbacks); if (dst == NULL) { return NULL; } @@ -12756,7 +7499,7 @@ MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_ca return dst; } -MA_API MA_NO_INLINE wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks) { size_t sz = wcslen(src)+1; wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks); @@ -12770,408 +7513,406 @@ MA_API MA_NO_INLINE wchar_t* ma_copy_string_w(const wchar_t* src, const ma_alloc } - #include static ma_result ma_result_from_errno(int e) { - if (e == 0) { - return MA_SUCCESS; - } -#ifdef EPERM - else if (e == EPERM) { return MA_INVALID_OPERATION; } -#endif -#ifdef ENOENT - else if (e == ENOENT) { return MA_DOES_NOT_EXIST; } -#endif -#ifdef ESRCH - else if (e == ESRCH) { return MA_DOES_NOT_EXIST; } -#endif -#ifdef EINTR - else if (e == EINTR) { return MA_INTERRUPT; } -#endif -#ifdef EIO - else if (e == EIO) { return MA_IO_ERROR; } -#endif -#ifdef ENXIO - else if (e == ENXIO) { return MA_DOES_NOT_EXIST; } -#endif -#ifdef E2BIG - else if (e == E2BIG) { return MA_INVALID_ARGS; } -#endif -#ifdef ENOEXEC - else if (e == ENOEXEC) { return MA_INVALID_FILE; } -#endif -#ifdef EBADF - else if (e == EBADF) { return MA_INVALID_FILE; } -#endif -#ifdef ECHILD - else if (e == ECHILD) { return MA_ERROR; } -#endif -#ifdef EAGAIN - else if (e == EAGAIN) { return MA_UNAVAILABLE; } -#endif -#ifdef ENOMEM - else if (e == ENOMEM) { return MA_OUT_OF_MEMORY; } -#endif -#ifdef EACCES - else if (e == EACCES) { return MA_ACCESS_DENIED; } -#endif -#ifdef EFAULT - else if (e == EFAULT) { return MA_BAD_ADDRESS; } -#endif -#ifdef ENOTBLK - else if (e == ENOTBLK) { return MA_ERROR; } -#endif -#ifdef EBUSY - else if (e == EBUSY) { return MA_BUSY; } -#endif -#ifdef EEXIST - else if (e == EEXIST) { return MA_ALREADY_EXISTS; } -#endif -#ifdef EXDEV - else if (e == EXDEV) { return MA_ERROR; } -#endif -#ifdef ENODEV - else if (e == ENODEV) { return MA_DOES_NOT_EXIST; } -#endif -#ifdef ENOTDIR - else if (e == ENOTDIR) { return MA_NOT_DIRECTORY; } -#endif -#ifdef EISDIR - else if (e == EISDIR) { return MA_IS_DIRECTORY; } -#endif -#ifdef EINVAL - else if (e == EINVAL) { return MA_INVALID_ARGS; } -#endif -#ifdef ENFILE - else if (e == ENFILE) { return MA_TOO_MANY_OPEN_FILES; } -#endif -#ifdef EMFILE - else if (e == EMFILE) { return MA_TOO_MANY_OPEN_FILES; } -#endif -#ifdef ENOTTY - else if (e == ENOTTY) { return MA_INVALID_OPERATION; } -#endif -#ifdef ETXTBSY - else if (e == ETXTBSY) { return MA_BUSY; } -#endif -#ifdef EFBIG - else if (e == EFBIG) { return MA_TOO_BIG; } -#endif -#ifdef ENOSPC - else if (e == ENOSPC) { return MA_NO_SPACE; } -#endif -#ifdef ESPIPE - else if (e == ESPIPE) { return MA_BAD_SEEK; } -#endif -#ifdef EROFS - else if (e == EROFS) { return MA_ACCESS_DENIED; } -#endif -#ifdef EMLINK - else if (e == EMLINK) { return MA_TOO_MANY_LINKS; } -#endif -#ifdef EPIPE - else if (e == EPIPE) { return MA_BAD_PIPE; } -#endif -#ifdef EDOM - else if (e == EDOM) { return MA_OUT_OF_RANGE; } -#endif -#ifdef ERANGE - else if (e == ERANGE) { return MA_OUT_OF_RANGE; } -#endif -#ifdef EDEADLK - else if (e == EDEADLK) { return MA_DEADLOCK; } -#endif -#ifdef ENAMETOOLONG - else if (e == ENAMETOOLONG) { return MA_PATH_TOO_LONG; } -#endif -#ifdef ENOLCK - else if (e == ENOLCK) { return MA_ERROR; } -#endif -#ifdef ENOSYS - else if (e == ENOSYS) { return MA_NOT_IMPLEMENTED; } -#endif -#ifdef ENOTEMPTY - else if (e == ENOTEMPTY) { return MA_DIRECTORY_NOT_EMPTY; } -#endif -#ifdef ELOOP - else if (e == ELOOP) { return MA_TOO_MANY_LINKS; } -#endif -#ifdef ENOMSG - else if (e == ENOMSG) { return MA_NO_MESSAGE; } -#endif -#ifdef EIDRM - else if (e == EIDRM) { return MA_ERROR; } -#endif -#ifdef ECHRNG - else if (e == ECHRNG) { return MA_ERROR; } -#endif -#ifdef EL2NSYNC - else if (e == EL2NSYNC) { return MA_ERROR; } -#endif -#ifdef EL3HLT - else if (e == EL3HLT) { return MA_ERROR; } -#endif -#ifdef EL3RST - else if (e == EL3RST) { return MA_ERROR; } -#endif -#ifdef ELNRNG - else if (e == ELNRNG) { return MA_OUT_OF_RANGE; } -#endif -#ifdef EUNATCH - else if (e == EUNATCH) { return MA_ERROR; } -#endif -#ifdef ENOCSI - else if (e == ENOCSI) { return MA_ERROR; } -#endif -#ifdef EL2HLT - else if (e == EL2HLT) { return MA_ERROR; } -#endif -#ifdef EBADE - else if (e == EBADE) { return MA_ERROR; } -#endif -#ifdef EBADR - else if (e == EBADR) { return MA_ERROR; } -#endif -#ifdef EXFULL - else if (e == EXFULL) { return MA_ERROR; } -#endif -#ifdef ENOANO - else if (e == ENOANO) { return MA_ERROR; } -#endif -#ifdef EBADRQC - else if (e == EBADRQC) { return MA_ERROR; } -#endif -#ifdef EBADSLT - else if (e == EBADSLT) { return MA_ERROR; } -#endif -#ifdef EBFONT - else if (e == EBFONT) { return MA_INVALID_FILE; } -#endif -#ifdef ENOSTR - else if (e == ENOSTR) { return MA_ERROR; } -#endif -#ifdef ENODATA - else if (e == ENODATA) { return MA_NO_DATA_AVAILABLE; } -#endif -#ifdef ETIME - else if (e == ETIME) { return MA_TIMEOUT; } -#endif -#ifdef ENOSR - else if (e == ENOSR) { return MA_NO_DATA_AVAILABLE; } -#endif -#ifdef ENONET - else if (e == ENONET) { return MA_NO_NETWORK; } -#endif -#ifdef ENOPKG - else if (e == ENOPKG) { return MA_ERROR; } -#endif -#ifdef EREMOTE - else if (e == EREMOTE) { return MA_ERROR; } -#endif -#ifdef ENOLINK - else if (e == ENOLINK) { return MA_ERROR; } -#endif -#ifdef EADV - else if (e == EADV) { return MA_ERROR; } -#endif -#ifdef ESRMNT - else if (e == ESRMNT) { return MA_ERROR; } -#endif -#ifdef ECOMM - else if (e == ECOMM) { return MA_ERROR; } -#endif -#ifdef EPROTO - else if (e == EPROTO) { return MA_ERROR; } -#endif -#ifdef EMULTIHOP - else if (e == EMULTIHOP) { return MA_ERROR; } -#endif -#ifdef EDOTDOT - else if (e == EDOTDOT) { return MA_ERROR; } -#endif -#ifdef EBADMSG - else if (e == EBADMSG) { return MA_BAD_MESSAGE; } -#endif -#ifdef EOVERFLOW - else if (e == EOVERFLOW) { return MA_TOO_BIG; } -#endif -#ifdef ENOTUNIQ - else if (e == ENOTUNIQ) { return MA_NOT_UNIQUE; } -#endif -#ifdef EBADFD - else if (e == EBADFD) { return MA_ERROR; } -#endif -#ifdef EREMCHG - else if (e == EREMCHG) { return MA_ERROR; } -#endif -#ifdef ELIBACC - else if (e == ELIBACC) { return MA_ACCESS_DENIED; } -#endif -#ifdef ELIBBAD - else if (e == ELIBBAD) { return MA_INVALID_FILE; } -#endif -#ifdef ELIBSCN - else if (e == ELIBSCN) { return MA_INVALID_FILE; } -#endif -#ifdef ELIBMAX - else if (e == ELIBMAX) { return MA_ERROR; } -#endif -#ifdef ELIBEXEC - else if (e == ELIBEXEC) { return MA_ERROR; } -#endif -#ifdef EILSEQ - else if (e == EILSEQ) { return MA_INVALID_DATA; } -#endif -#ifdef ERESTART - else if (e == ERESTART) { return MA_ERROR; } -#endif -#ifdef ESTRPIPE - else if (e == ESTRPIPE) { return MA_ERROR; } -#endif -#ifdef EUSERS - else if (e == EUSERS) { return MA_ERROR; } -#endif -#ifdef ENOTSOCK - else if (e == ENOTSOCK) { return MA_NOT_SOCKET; } -#endif -#ifdef EDESTADDRREQ - else if (e == EDESTADDRREQ) { return MA_NO_ADDRESS; } -#endif -#ifdef EMSGSIZE - else if (e == EMSGSIZE) { return MA_TOO_BIG; } -#endif -#ifdef EPROTOTYPE - else if (e == EPROTOTYPE) { return MA_BAD_PROTOCOL; } -#endif -#ifdef ENOPROTOOPT - else if (e == ENOPROTOOPT) { return MA_PROTOCOL_UNAVAILABLE; } -#endif -#ifdef EPROTONOSUPPORT - else if (e == EPROTONOSUPPORT) { return MA_PROTOCOL_NOT_SUPPORTED; } -#endif -#ifdef ESOCKTNOSUPPORT - else if (e == ESOCKTNOSUPPORT) { return MA_SOCKET_NOT_SUPPORTED; } -#endif -#ifdef EOPNOTSUPP - else if (e == EOPNOTSUPP) { return MA_INVALID_OPERATION; } -#endif -#ifdef EPFNOSUPPORT - else if (e == EPFNOSUPPORT) { return MA_PROTOCOL_FAMILY_NOT_SUPPORTED; } -#endif -#ifdef EAFNOSUPPORT - else if (e == EAFNOSUPPORT) { return MA_ADDRESS_FAMILY_NOT_SUPPORTED; } -#endif -#ifdef EADDRINUSE - else if (e == EADDRINUSE) { return MA_ALREADY_IN_USE; } -#endif -#ifdef EADDRNOTAVAIL - else if (e == EADDRNOTAVAIL) { return MA_ERROR; } -#endif -#ifdef ENETDOWN - else if (e == ENETDOWN) { return MA_NO_NETWORK; } -#endif -#ifdef ENETUNREACH - else if (e == ENETUNREACH) { return MA_NO_NETWORK; } -#endif -#ifdef ENETRESET - else if (e == ENETRESET) { return MA_NO_NETWORK; } -#endif -#ifdef ECONNABORTED - else if (e == ECONNABORTED) { return MA_NO_NETWORK; } -#endif -#ifdef ECONNRESET - else if (e == ECONNRESET) { return MA_CONNECTION_RESET; } -#endif -#ifdef ENOBUFS - else if (e == ENOBUFS) { return MA_NO_SPACE; } -#endif -#ifdef EISCONN - else if (e == EISCONN) { return MA_ALREADY_CONNECTED; } -#endif -#ifdef ENOTCONN - else if (e == ENOTCONN) { return MA_NOT_CONNECTED; } -#endif -#ifdef ESHUTDOWN - else if (e == ESHUTDOWN) { return MA_ERROR; } -#endif -#ifdef ETOOMANYREFS - else if (e == ETOOMANYREFS) { return MA_ERROR; } -#endif -#ifdef ETIMEDOUT - else if (e == ETIMEDOUT) { return MA_TIMEOUT; } -#endif -#ifdef ECONNREFUSED - else if (e == ECONNREFUSED) { return MA_CONNECTION_REFUSED; } -#endif -#ifdef EHOSTDOWN - else if (e == EHOSTDOWN) { return MA_NO_HOST; } -#endif -#ifdef EHOSTUNREACH - else if (e == EHOSTUNREACH) { return MA_NO_HOST; } -#endif -#ifdef EALREADY - else if (e == EALREADY) { return MA_IN_PROGRESS; } -#endif -#ifdef EINPROGRESS - else if (e == EINPROGRESS) { return MA_IN_PROGRESS; } -#endif -#ifdef ESTALE - else if (e == ESTALE) { return MA_INVALID_FILE; } -#endif -#ifdef EUCLEAN - else if (e == EUCLEAN) { return MA_ERROR; } -#endif -#ifdef ENOTNAM - else if (e == ENOTNAM) { return MA_ERROR; } -#endif -#ifdef ENAVAIL - else if (e == ENAVAIL) { return MA_ERROR; } -#endif -#ifdef EISNAM - else if (e == EISNAM) { return MA_ERROR; } -#endif -#ifdef EREMOTEIO - else if (e == EREMOTEIO) { return MA_IO_ERROR; } -#endif -#ifdef EDQUOT - else if (e == EDQUOT) { return MA_NO_SPACE; } -#endif -#ifdef ENOMEDIUM - else if (e == ENOMEDIUM) { return MA_DOES_NOT_EXIST; } -#endif -#ifdef EMEDIUMTYPE - else if (e == EMEDIUMTYPE) { return MA_ERROR; } -#endif -#ifdef ECANCELED - else if (e == ECANCELED) { return MA_CANCELLED; } -#endif -#ifdef ENOKEY - else if (e == ENOKEY) { return MA_ERROR; } -#endif -#ifdef EKEYEXPIRED - else if (e == EKEYEXPIRED) { return MA_ERROR; } -#endif -#ifdef EKEYREVOKED - else if (e == EKEYREVOKED) { return MA_ERROR; } -#endif -#ifdef EKEYREJECTED - else if (e == EKEYREJECTED) { return MA_ERROR; } -#endif -#ifdef EOWNERDEAD - else if (e == EOWNERDEAD) { return MA_ERROR; } -#endif -#ifdef ENOTRECOVERABLE - else if (e == ENOTRECOVERABLE) { return MA_ERROR; } -#endif -#ifdef ERFKILL - else if (e == ERFKILL) { return MA_ERROR; } -#endif -#ifdef EHWPOISON - else if (e == EHWPOISON) { return MA_ERROR; } -#endif - else { - return MA_ERROR; + switch (e) + { + case 0: return MA_SUCCESS; + #ifdef EPERM + case EPERM: return MA_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return MA_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return MA_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return MA_INTERRUPT; + #endif + #ifdef EIO + case EIO: return MA_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return MA_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return MA_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return MA_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return MA_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return MA_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return MA_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return MA_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return MA_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return MA_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return MA_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return MA_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return MA_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return MA_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return MA_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return MA_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return MA_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return MA_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return MA_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return MA_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return MA_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return MA_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return MA_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return MA_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return MA_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return MA_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return MA_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return MA_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return MA_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return MA_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return MA_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return MA_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return MA_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return MA_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return MA_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return MA_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return MA_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return MA_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return MA_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return MA_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return MA_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return MA_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return MA_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return MA_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return MA_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return MA_ERROR; + #endif + #ifdef EBADE + case EBADE: return MA_ERROR; + #endif + #ifdef EBADR + case EBADR: return MA_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return MA_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return MA_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return MA_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return MA_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return MA_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return MA_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return MA_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return MA_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return MA_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return MA_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return MA_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return MA_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return MA_ERROR; + #endif + #ifdef EADV + case EADV: return MA_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return MA_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return MA_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return MA_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return MA_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return MA_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return MA_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return MA_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return MA_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return MA_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return MA_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return MA_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return MA_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return MA_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return MA_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return MA_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return MA_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return MA_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return MA_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return MA_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return MA_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return MA_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return MA_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return MA_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return MA_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return MA_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return MA_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return MA_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return MA_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return MA_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return MA_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return MA_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return MA_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return MA_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return MA_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return MA_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return MA_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return MA_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return MA_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return MA_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return MA_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return MA_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return MA_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return MA_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return MA_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return MA_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return MA_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return MA_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return MA_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return MA_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return MA_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return MA_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return MA_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return MA_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return MA_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return MA_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return MA_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return MA_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return MA_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return MA_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return MA_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return MA_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return MA_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return MA_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return MA_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return MA_ERROR; + #endif + default: return MA_ERROR; } } @@ -13407,451 +8148,7 @@ static MA_INLINE unsigned int ma_count_set_bits(unsigned int x) -/************************************************************************************************************************************************************** - -Allocation Callbacks - -**************************************************************************************************************************************************************/ -static void* ma__malloc_default(size_t sz, void* pUserData) -{ - (void)pUserData; - return MA_MALLOC(sz); -} - -static void* ma__realloc_default(void* p, size_t sz, void* pUserData) -{ - (void)pUserData; - return MA_REALLOC(p, sz); -} - -static void ma__free_default(void* p, void* pUserData) -{ - (void)pUserData; - MA_FREE(p); -} - -static ma_allocation_callbacks ma_allocation_callbacks_init_default(void) -{ - ma_allocation_callbacks callbacks; - callbacks.pUserData = NULL; - callbacks.onMalloc = ma__malloc_default; - callbacks.onRealloc = ma__realloc_default; - callbacks.onFree = ma__free_default; - - return callbacks; -} - -static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst, const ma_allocation_callbacks* pSrc) -{ - if (pDst == NULL) { - return MA_INVALID_ARGS; - } - - if (pSrc == NULL) { - *pDst = ma_allocation_callbacks_init_default(); - } else { - if (pSrc->pUserData == NULL && pSrc->onFree == NULL && pSrc->onMalloc == NULL && pSrc->onRealloc == NULL) { - *pDst = ma_allocation_callbacks_init_default(); - } else { - if (pSrc->onFree == NULL || (pSrc->onMalloc == NULL && pSrc->onRealloc == NULL)) { - return MA_INVALID_ARGS; /* Invalid allocation callbacks. */ - } else { - *pDst = *pSrc; - } - } - } - - return MA_SUCCESS; -} - - - - -/************************************************************************************************************************************************************** - -Logging - -**************************************************************************************************************************************************************/ -MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) -{ - switch (logLevel) - { - case MA_LOG_LEVEL_DEBUG: return "DEBUG"; - case MA_LOG_LEVEL_INFO: return "INFO"; - case MA_LOG_LEVEL_WARNING: return "WARNING"; - case MA_LOG_LEVEL_ERROR: return "ERROR"; - default: return "ERROR"; - } -} - -#if defined(MA_DEBUG_OUTPUT) -#if defined(MA_ANDROID) - #include -#endif - -/* Customize this to use a specific tag in __android_log_print() for debug output messages. */ -#ifndef MA_ANDROID_LOG_TAG -#define MA_ANDROID_LOG_TAG "miniaudio" -#endif - -void ma_log_callback_debug(void* pUserData, ma_uint32 level, const char* pMessage) -{ - (void)pUserData; - - /* Special handling for some platforms. */ - #if defined(MA_ANDROID) - { - /* Android. */ - __android_log_print(ANDROID_LOG_DEBUG, MA_ANDROID_LOG_TAG, "%s: %s", ma_log_level_to_string(level), pMessage); - } - #else - { - /* Everything else. */ - printf("%s: %s", ma_log_level_to_string(level), pMessage); - } - #endif -} -#endif - -MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog, void* pUserData) -{ - ma_log_callback callback; - - MA_ZERO_OBJECT(&callback); - callback.onLog = onLog; - callback.pUserData = pUserData; - - return callback; -} - - -MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks, ma_log* pLog) -{ - if (pLog == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pLog); - ma_allocation_callbacks_init_copy(&pLog->allocationCallbacks, pAllocationCallbacks); - - /* We need a mutex for thread safety. */ - #ifndef MA_NO_THREADING - { - ma_result result = ma_mutex_init(&pLog->lock); - if (result != MA_SUCCESS) { - return result; - } - } - #endif - - /* If we're using debug output, enable it. */ - #if defined(MA_DEBUG_OUTPUT) - { - ma_log_register_callback(pLog, ma_log_callback_init(ma_log_callback_debug, NULL)); /* Doesn't really matter if this fails. */ - } - #endif - - return MA_SUCCESS; -} - -MA_API void ma_log_uninit(ma_log* pLog) -{ - if (pLog == NULL) { - return; - } - -#ifndef MA_NO_THREADING - ma_mutex_uninit(&pLog->lock); -#endif -} - -static void ma_log_lock(ma_log* pLog) -{ -#ifndef MA_NO_THREADING - ma_mutex_lock(&pLog->lock); -#else - (void)pLog; -#endif -} - -static void ma_log_unlock(ma_log* pLog) -{ -#ifndef MA_NO_THREADING - ma_mutex_unlock(&pLog->lock); -#else - (void)pLog; -#endif -} - -MA_API ma_result ma_log_register_callback(ma_log* pLog, ma_log_callback callback) -{ - ma_result result = MA_SUCCESS; - - if (pLog == NULL || callback.onLog == NULL) { - return MA_INVALID_ARGS; - } - - ma_log_lock(pLog); - { - if (pLog->callbackCount == ma_countof(pLog->callbacks)) { - result = MA_OUT_OF_MEMORY; /* Reached the maximum allowed log callbacks. */ - } else { - pLog->callbacks[pLog->callbackCount] = callback; - pLog->callbackCount += 1; - } - } - ma_log_unlock(pLog); - - return result; -} - -MA_API ma_result ma_log_unregister_callback(ma_log* pLog, ma_log_callback callback) -{ - if (pLog == NULL) { - return MA_INVALID_ARGS; - } - - ma_log_lock(pLog); - { - ma_uint32 iLog; - for (iLog = 0; iLog < pLog->callbackCount; ) { - if (pLog->callbacks[iLog].onLog == callback.onLog) { - /* Found. Move everything down a slot. */ - ma_uint32 jLog; - for (jLog = iLog; jLog < pLog->callbackCount-1; jLog += 1) { - pLog->callbacks[jLog] = pLog->callbacks[jLog + 1]; - } - - pLog->callbackCount -= 1; - } else { - /* Not found. */ - iLog += 1; - } - } - } - ma_log_unlock(pLog); - - return MA_SUCCESS; -} - -MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage) -{ - if (pLog == NULL || pMessage == NULL) { - return MA_INVALID_ARGS; - } - - ma_log_lock(pLog); - { - ma_uint32 iLog; - for (iLog = 0; iLog < pLog->callbackCount; iLog += 1) { - if (pLog->callbacks[iLog].onLog) { - pLog->callbacks[iLog].onLog(pLog->callbacks[iLog].pUserData, level, pMessage); - } - } - } - ma_log_unlock(pLog); - - return MA_SUCCESS; -} - - -/* -We need to emulate _vscprintf() for the VC6 build. This can be more efficient, but since it's only VC6, and it's just a -logging function, I'm happy to keep this simple. In the VC6 build we can implement this in terms of _vsnprintf(). -*/ -#if defined(_MSC_VER) && _MSC_VER < 1900 -static int ma_vscprintf(const ma_allocation_callbacks* pAllocationCallbacks, const char* format, va_list args) -{ -#if _MSC_VER > 1200 - return _vscprintf(format, args); -#else - int result; - char* pTempBuffer = NULL; - size_t tempBufferCap = 1024; - - if (format == NULL) { - errno = EINVAL; - return -1; - } - - for (;;) { - char* pNewTempBuffer = (char*)ma_realloc(pTempBuffer, tempBufferCap, pAllocationCallbacks); - if (pNewTempBuffer == NULL) { - ma_free(pTempBuffer, pAllocationCallbacks); - errno = ENOMEM; - return -1; /* Out of memory. */ - } - - pTempBuffer = pNewTempBuffer; - - result = _vsnprintf(pTempBuffer, tempBufferCap, format, args); - ma_free(pTempBuffer, NULL); - - if (result != -1) { - break; /* Got it. */ - } - - /* Buffer wasn't big enough. Ideally it'd be nice to use an error code to know the reason for sure, but this is reliable enough. */ - tempBufferCap *= 2; - } - - return result; -#endif -} -#endif - -MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat, va_list args) -{ - if (pLog == NULL || pFormat == NULL) { - return MA_INVALID_ARGS; - } - - #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) || (defined(__cplusplus) && __cplusplus >= 201103L) - { - ma_result result; - int length; - char pFormattedMessageStack[1024]; - char* pFormattedMessageHeap = NULL; - - /* First try formatting into our fixed sized stack allocated buffer. If this is too small we'll fallback to a heap allocation. */ - length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args); - if (length < 0) { - return MA_INVALID_OPERATION; /* An error occurred when trying to convert the buffer. */ - } - - if ((size_t)length < sizeof(pFormattedMessageStack)) { - /* The string was written to the stack. */ - result = ma_log_post(pLog, level, pFormattedMessageStack); - } else { - /* The stack buffer was too small, try the heap. */ - pFormattedMessageHeap = (char*)ma_malloc(length + 1, &pLog->allocationCallbacks); - if (pFormattedMessageHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - - length = vsnprintf(pFormattedMessageHeap, length + 1, pFormat, args); - if (length < 0) { - ma_free(pFormattedMessageHeap, &pLog->allocationCallbacks); - return MA_INVALID_OPERATION; - } - - result = ma_log_post(pLog, level, pFormattedMessageHeap); - ma_free(pFormattedMessageHeap, &pLog->allocationCallbacks); - } - - return result; - } - #else - { - /* - Without snprintf() we need to first measure the string and then heap allocate it. I'm only aware of Visual Studio having support for this without snprintf(), so we'll - need to restrict this branch to Visual Studio. For other compilers we need to just not support formatted logging because I don't want the security risk of overflowing - a fixed sized stack allocated buffer. - */ - #if defined(_MSC_VER) && _MSC_VER >= 1200 /* 1200 = VC6 */ - { - ma_result result; - int formattedLen; - char* pFormattedMessage = NULL; - va_list args2; - - #if _MSC_VER >= 1800 - { - va_copy(args2, args); - } - #else - { - args2 = args; - } - #endif - - formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); - va_end(args2); - - if (formattedLen <= 0) { - return MA_INVALID_OPERATION; - } - - pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks); - if (pFormattedMessage == NULL) { - return MA_OUT_OF_MEMORY; - } - - /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ - #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ - { - vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args); - } - #else - { - vsprintf(pFormattedMessage, pFormat, args); - } - #endif - - result = ma_log_post(pLog, level, pFormattedMessage); - ma_free(pFormattedMessage, &pLog->allocationCallbacks); - - return result; - } - #else - { - /* Can't do anything because we don't have a safe way of to emulate vsnprintf() without a manual solution. */ - (void)level; - (void)args; - - return MA_INVALID_OPERATION; - } - #endif - } - #endif -} - -MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat, ...) -{ - ma_result result; - va_list args; - - if (pLog == NULL || pFormat == NULL) { - return MA_INVALID_ARGS; - } - - va_start(args, pFormat); - { - result = ma_log_postv(pLog, level, pFormat, args); - } - va_end(args); - - return result; -} - - - -static MA_INLINE ma_uint8 ma_clip_u8(ma_int32 x) -{ - return (ma_uint8)(ma_clamp(x, -128, 127) + 128); -} - -static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x) -{ - return (ma_int16)ma_clamp(x, -32768, 32767); -} - -static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x) -{ - return (ma_int64)ma_clamp(x, -8388608, 8388607); -} - -static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x) -{ - /* This dance is to silence warnings with -std=c89. A good compiler should be able to optimize this away. */ - ma_int64 clipMin; - ma_int64 clipMax; - clipMin = -((ma_int64)2147483647 + 1); - clipMax = (ma_int64)2147483647; - - return (ma_int32)ma_clamp(x, clipMin, clipMax); -} - +/* Clamps an f32 sample to -1..1 */ static MA_INLINE float ma_clip_f32(float x) { if (x < -1) return -1; @@ -13859,7 +8156,6 @@ static MA_INLINE float ma_clip_f32(float x) return x; } - static MA_INLINE float ma_mix_f32(float x, float y, float a) { return x*(1-a) + y*a; @@ -13884,6 +8180,12 @@ static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a) return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a)); } #endif +#if defined(MA_SUPPORT_AVX512) +static MA_INLINE __m512 ma_mix_f32_fast__avx512(__m512 x, __m512 y, __m512 a) +{ + return _mm512_add_ps(x, _mm512_mul_ps(_mm512_sub_ps(y, x), a)); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a) { @@ -13926,27 +8228,6 @@ static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b) } -static ma_uint32 ma_ffs_32(ma_uint32 x) -{ - ma_uint32 i; - - /* Just a naive implementation just to get things working for now. Will optimize this later. */ - for (i = 0; i < 32; i += 1) { - if ((x & (1U << i)) != 0) { - return i; - } - } - - return i; -} - -static MA_INLINE ma_int16 ma_float_to_fixed_16(float x) -{ - return (ma_int16)(x * (1 << 8)); -} - - - /* Random Number Generation @@ -14096,94 +8377,108 @@ Atomics **************************************************************************************************************************************************************/ /* c89atomic.h begin */ -#ifndef ma_atomic_h +#ifndef c89atomic_h +#define c89atomic_h #if defined(__cplusplus) extern "C" { #endif -#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wlong-long" - #if defined(__clang__) - #pragma GCC diagnostic ignored "-Wc++11-long-long" +typedef signed char c89atomic_int8; +typedef unsigned char c89atomic_uint8; +typedef signed short c89atomic_int16; +typedef unsigned short c89atomic_uint16; +typedef signed int c89atomic_int32; +typedef unsigned int c89atomic_uint32; +#if defined(_MSC_VER) + typedef signed __int64 c89atomic_int64; + typedef unsigned __int64 c89atomic_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long c89atomic_int64; + typedef unsigned long long c89atomic_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop #endif #endif -typedef int ma_atomic_memory_order; -#define MA_ATOMIC_HAS_8 -#define MA_ATOMIC_HAS_16 -#define MA_ATOMIC_HAS_32 -#define MA_ATOMIC_HAS_64 +typedef int c89atomic_memory_order; +typedef unsigned char c89atomic_bool; +#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT) +#ifdef _WIN32 +#ifdef _WIN64 +#define C89ATOMIC_64BIT +#else +#define C89ATOMIC_32BIT +#endif +#endif +#endif +#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT) +#ifdef __GNUC__ +#ifdef __LP64__ +#define C89ATOMIC_64BIT +#else +#define C89ATOMIC_32BIT +#endif +#endif +#endif +#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT) +#include +#if INTPTR_MAX == INT64_MAX +#define C89ATOMIC_64BIT +#else +#define C89ATOMIC_32BIT +#endif +#endif +#if defined(__x86_64__) || defined(_M_X64) +#define C89ATOMIC_X64 +#elif defined(__i386) || defined(_M_IX86) +#define C89ATOMIC_X86 +#elif defined(__arm__) || defined(_M_ARM) +#define C89ATOMIC_ARM +#endif +#if defined(_MSC_VER) + #define C89ATOMIC_INLINE __forceinline +#elif defined(__GNUC__) + #if defined(__STRICT_ANSI__) + #define C89ATOMIC_INLINE __inline__ __attribute__((always_inline)) + #else + #define C89ATOMIC_INLINE inline __attribute__((always_inline)) + #endif +#elif defined(__WATCOMC__) || defined(__DMC__) + #define C89ATOMIC_INLINE __inline +#else + #define C89ATOMIC_INLINE +#endif +#define C89ATOMIC_HAS_8 +#define C89ATOMIC_HAS_16 +#define C89ATOMIC_HAS_32 +#define C89ATOMIC_HAS_64 #if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__) - #define MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, ma_atomicType, msvcType) \ - ma_atomicType result; \ - switch (order) \ - { \ - case ma_atomic_memory_order_relaxed: \ - { \ - result = (ma_atomicType)intrin##_nf((volatile msvcType*)dst, (msvcType)src); \ - } break; \ - case ma_atomic_memory_order_consume: \ - case ma_atomic_memory_order_acquire: \ - { \ - result = (ma_atomicType)intrin##_acq((volatile msvcType*)dst, (msvcType)src); \ - } break; \ - case ma_atomic_memory_order_release: \ - { \ - result = (ma_atomicType)intrin##_rel((volatile msvcType*)dst, (msvcType)src); \ - } break; \ - case ma_atomic_memory_order_acq_rel: \ - case ma_atomic_memory_order_seq_cst: \ - default: \ - { \ - result = (ma_atomicType)intrin((volatile msvcType*)dst, (msvcType)src); \ - } break; \ - } \ - return result; - #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, desired, order, intrin, ma_atomicType, msvcType) \ - ma_atomicType result; \ - switch (order) \ - { \ - case ma_atomic_memory_order_relaxed: \ - { \ - result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ - } break; \ - case ma_atomic_memory_order_consume: \ - case ma_atomic_memory_order_acquire: \ - { \ - result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ - } break; \ - case ma_atomic_memory_order_release: \ - { \ - result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ - } break; \ - case ma_atomic_memory_order_acq_rel: \ - case ma_atomic_memory_order_seq_cst: \ - default: \ - { \ - result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ - } break; \ - } \ - return result; - #define ma_atomic_memory_order_relaxed 0 - #define ma_atomic_memory_order_consume 1 - #define ma_atomic_memory_order_acquire 2 - #define ma_atomic_memory_order_release 3 - #define ma_atomic_memory_order_acq_rel 4 - #define ma_atomic_memory_order_seq_cst 5 - #if _MSC_VER < 1600 && defined(MA_X86) - #define MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY + #define c89atomic_memory_order_relaxed 0 + #define c89atomic_memory_order_consume 1 + #define c89atomic_memory_order_acquire 2 + #define c89atomic_memory_order_release 3 + #define c89atomic_memory_order_acq_rel 4 + #define c89atomic_memory_order_seq_cst 5 + #if _MSC_VER < 1600 && defined(C89ATOMIC_32BIT) + #define C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY #endif #if _MSC_VER < 1600 - #undef MA_ATOMIC_HAS_8 - #undef MA_ATOMIC_HAS_16 + #undef C89ATOMIC_HAS_8 + #undef C89ATOMIC_HAS_16 #endif - #if !defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if !defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY) #include #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired) { - ma_uint8 result = 0; + c89atomic_uint8 result = 0; __asm { mov ecx, dst mov al, expected @@ -14194,10 +8489,10 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired) { - ma_uint16 result = 0; + c89atomic_uint16 result = 0; __asm { mov ecx, dst mov ax, expected @@ -14208,10 +8503,10 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired) { - ma_uint32 result = 0; + c89atomic_uint32 result = 0; __asm { mov ecx, dst mov eax, expected @@ -14222,11 +8517,11 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + #if defined(C89ATOMIC_HAS_64) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired) { - ma_uint32 resultEAX = 0; - ma_uint32 resultEDX = 0; + c89atomic_uint32 resultEAX = 0; + c89atomic_uint32 resultEDX = 0; __asm { mov esi, dst mov eax, dword ptr expected @@ -14237,28 +8532,28 @@ typedef int ma_atomic_memory_order; mov resultEAX, eax mov resultEDX, edx } - return ((ma_uint64)resultEDX << 32) | resultEAX; + return ((c89atomic_uint64)resultEDX << 32) | resultEAX; } #endif #else - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_compare_and_swap_8( dst, expected, desired) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected) + #if defined(C89ATOMIC_HAS_8) + #define c89atomic_compare_and_swap_8( dst, expected, desired) (c89atomic_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected) #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected) + #if defined(C89ATOMIC_HAS_16) + #define c89atomic_compare_and_swap_16(dst, expected, desired) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected) #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) + #if defined(C89ATOMIC_HAS_32) + #define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)desired, (ma_int64)expected) + #if defined(C89ATOMIC_HAS_64) + #define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile long long*)dst, (long long)desired, (long long)expected) #endif #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 result = 0; + c89atomic_uint8 result = 0; (void)order; __asm { mov ecx, dst @@ -14269,10 +8564,10 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 result = 0; + c89atomic_uint16 result = 0; (void)order; __asm { mov ecx, dst @@ -14283,10 +8578,10 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 result = 0; + c89atomic_uint32 result = 0; (void)order; __asm { mov ecx, dst @@ -14298,68 +8593,52 @@ typedef int ma_atomic_memory_order; } #endif #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); - #else (void)order; - return (ma_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); - #endif + return (c89atomic_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, ma_uint16, short); - #else (void)order; - return (ma_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); - #endif + return (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, ma_uint32, long); - #else (void)order; - return (ma_uint32)_InterlockedExchange((volatile long*)dst, (long)src); - #endif + return (c89atomic_uint32)_InterlockedExchange((volatile long*)dst, (long)src); } #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); - #else (void)order; - return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); - #endif + return (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); } #else #endif #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) && !defined(C89ATOMIC_64BIT) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; + c89atomic_uint64 oldValue; do { oldValue = *dst; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); (void)order; return oldValue; } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 result = 0; + c89atomic_uint8 result = 0; (void)order; __asm { mov ecx, dst @@ -14370,10 +8649,10 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 result = 0; + c89atomic_uint16 result = 0; (void)order; __asm { mov ecx, dst @@ -14384,10 +8663,10 @@ typedef int ma_atomic_memory_order; return result; } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 result = 0; + c89atomic_uint32 result = 0; (void)order; __asm { mov ecx, dst @@ -14399,67 +8678,51 @@ typedef int ma_atomic_memory_order; } #endif #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); - #else (void)order; - return (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); - #endif + return (c89atomic_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, ma_uint16, short); - #else (void)order; - return (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); - #endif + return (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, ma_uint32, long); - #else (void)order; - return (ma_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); - #endif + return (c89atomic_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); } #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); - #else (void)order; - return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); - #endif + return (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); } #else #endif #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) && !defined(C89ATOMIC_64BIT) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(c89atomic_memory_order order) { (void)order; __asm { @@ -14467,1076 +8730,985 @@ typedef int ma_atomic_memory_order; } } #else - #if defined(MA_X64) - #define ma_atomic_thread_fence(order) __faststorefence(), (void)order - #elif defined(MA_ARM64) - #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order + #if defined(C89ATOMIC_X64) + #define c89atomic_thread_fence(order) __faststorefence(), (void)order #else - static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) + static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order) { - volatile ma_uint32 barrier = 0; - ma_atomic_fetch_add_explicit_32(&barrier, 0, order); + volatile c89atomic_uint32 barrier = 0; + c89atomic_fetch_add_explicit_32(&barrier, 0, order); } #endif #endif - #define ma_atomic_compiler_fence() ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) + #define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst) + #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); - #else (void)order; - return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); - #endif + return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0); } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); - #else (void)order; - return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); - #endif + return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0); } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); - #else (void)order; - return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); - #endif + return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0); } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); - #else (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); - #endif + return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0); } #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #if defined(C89ATOMIC_HAS_8) + #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order) #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #if defined(C89ATOMIC_HAS_16) + #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order) #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #if defined(C89ATOMIC_HAS_32) + #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order) #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) + #if defined(C89ATOMIC_HAS_64) + #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order) #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue - src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue - src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue & src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue & src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue ^ src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue ^ src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_8) + static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue | src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_16) + static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue | src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_32) + static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #if defined(C89ATOMIC_HAS_64) + static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; - #endif } #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) + #if defined(C89ATOMIC_HAS_8) + #define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order) #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) + #if defined(C89ATOMIC_HAS_16) + #define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order) #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) + #if defined(C89ATOMIC_HAS_32) + #define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order) #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) + #if defined(C89ATOMIC_HAS_64) + #define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order) #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) + #if defined(C89ATOMIC_HAS_8) + #define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order) #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) + #if defined(C89ATOMIC_HAS_16) + #define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order) #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) + #if defined(C89ATOMIC_HAS_32) + #define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order) #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) + #if defined(C89ATOMIC_HAS_64) + #define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order) #endif - #if defined(MA_ATOMIC_HAS_8) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #if defined(C89ATOMIC_HAS_8) + typedef c89atomic_uint8 c89atomic_flag; + #define c89atomic_flag_test_and_set_explicit(ptr, order) (c89atomic_bool)c89atomic_test_and_set_explicit_8(ptr, order) + #define c89atomic_flag_clear_explicit(ptr, order) c89atomic_clear_explicit_8(ptr, order) + #define c89atoimc_flag_load_explicit(ptr, order) c89atomic_load_explicit_8(ptr, order) #else - typedef ma_uint32 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_32(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) + typedef c89atomic_uint32 c89atomic_flag; + #define c89atomic_flag_test_and_set_explicit(ptr, order) (c89atomic_bool)c89atomic_test_and_set_explicit_32(ptr, order) + #define c89atomic_flag_clear_explicit(ptr, order) c89atomic_clear_explicit_32(ptr, order) + #define c89atoimc_flag_load_explicit(ptr, order) c89atomic_load_explicit_32(ptr, order) #endif #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) - #define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE - #define MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE - #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED - #define ma_atomic_memory_order_consume __ATOMIC_CONSUME - #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE - #define ma_atomic_memory_order_release __ATOMIC_RELEASE - #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL - #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") - #define ma_atomic_thread_fence(order) __atomic_thread_fence(order) - #define ma_atomic_signal_fence(order) __atomic_signal_fence(order) - #define ma_atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) - #define ma_atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) - #define ma_atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) - #define ma_atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) - #define ma_atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) __atomic_store_n(dst, src, order) - #define ma_atomic_load_explicit_8( dst, order) __atomic_load_n(dst, order) - #define ma_atomic_load_explicit_16(dst, order) __atomic_load_n(dst, order) - #define ma_atomic_load_explicit_32(dst, order) __atomic_load_n(dst, order) - #define ma_atomic_load_explicit_64(dst, order) __atomic_load_n(dst, order) - #define ma_atomic_exchange_explicit_8( dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) - #define ma_atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) - #define ma_atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) - #define ma_atomic_fetch_add_explicit_64(dst, src, order) __atomic_fetch_add(dst, src, order) - #define ma_atomic_fetch_sub_explicit_8( dst, src, order) __atomic_fetch_sub(dst, src, order) - #define ma_atomic_fetch_sub_explicit_16(dst, src, order) __atomic_fetch_sub(dst, src, order) - #define ma_atomic_fetch_sub_explicit_32(dst, src, order) __atomic_fetch_sub(dst, src, order) - #define ma_atomic_fetch_sub_explicit_64(dst, src, order) __atomic_fetch_sub(dst, src, order) - #define ma_atomic_fetch_or_explicit_8( dst, src, order) __atomic_fetch_or(dst, src, order) - #define ma_atomic_fetch_or_explicit_16(dst, src, order) __atomic_fetch_or(dst, src, order) - #define ma_atomic_fetch_or_explicit_32(dst, src, order) __atomic_fetch_or(dst, src, order) - #define ma_atomic_fetch_or_explicit_64(dst, src, order) __atomic_fetch_or(dst, src, order) - #define ma_atomic_fetch_xor_explicit_8( dst, src, order) __atomic_fetch_xor(dst, src, order) - #define ma_atomic_fetch_xor_explicit_16(dst, src, order) __atomic_fetch_xor(dst, src, order) - #define ma_atomic_fetch_xor_explicit_32(dst, src, order) __atomic_fetch_xor(dst, src, order) - #define ma_atomic_fetch_xor_explicit_64(dst, src, order) __atomic_fetch_xor(dst, src, order) - #define ma_atomic_fetch_and_explicit_8( dst, src, order) __atomic_fetch_and(dst, src, order) - #define ma_atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) - #define ma_atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) - #define ma_atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return expected; - } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return expected; - } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return expected; - } - #if defined(__clang__) - #pragma clang diagnostic push - #if __clang_major__ >= 8 - #pragma clang diagnostic ignored "-Watomic-alignment" - #endif - #endif - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return expected; - } - #if defined(__clang__) - #pragma clang diagnostic pop - #endif - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(dst, order) (ma_bool32)__atomic_test_and_set(dst, order) - #define ma_atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE + #define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE + #define c89atomic_memory_order_relaxed __ATOMIC_RELAXED + #define c89atomic_memory_order_consume __ATOMIC_CONSUME + #define c89atomic_memory_order_acquire __ATOMIC_ACQUIRE + #define c89atomic_memory_order_release __ATOMIC_RELEASE + #define c89atomic_memory_order_acq_rel __ATOMIC_ACQ_REL + #define c89atomic_memory_order_seq_cst __ATOMIC_SEQ_CST + #define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory") + #define c89atomic_thread_fence(order) __atomic_thread_fence(order) + #define c89atomic_signal_fence(order) __atomic_signal_fence(order) + #define c89atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) + #define c89atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) + #define c89atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) + #define c89atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) + #define c89atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) + #define c89atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) + #define c89atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) + #define c89atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) + #define c89atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) + #define c89atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) + #define c89atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) + #define c89atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) + #define c89atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) + #define c89atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) + #define c89atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) + #define c89atomic_store_explicit_64(dst, src, order) __atomic_store_n(dst, src, order) + #define c89atomic_load_explicit_8( dst, order) __atomic_load_n(dst, order) + #define c89atomic_load_explicit_16(dst, order) __atomic_load_n(dst, order) + #define c89atomic_load_explicit_32(dst, order) __atomic_load_n(dst, order) + #define c89atomic_load_explicit_64(dst, order) __atomic_load_n(dst, order) + #define c89atomic_exchange_explicit_8( dst, src, order) __atomic_exchange_n(dst, src, order) + #define c89atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) + #define c89atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) + #define c89atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) + #define c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define c89atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) + #define c89atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) + #define c89atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) + #define c89atomic_fetch_add_explicit_64(dst, src, order) __atomic_fetch_add(dst, src, order) + #define c89atomic_fetch_sub_explicit_8( dst, src, order) __atomic_fetch_sub(dst, src, order) + #define c89atomic_fetch_sub_explicit_16(dst, src, order) __atomic_fetch_sub(dst, src, order) + #define c89atomic_fetch_sub_explicit_32(dst, src, order) __atomic_fetch_sub(dst, src, order) + #define c89atomic_fetch_sub_explicit_64(dst, src, order) __atomic_fetch_sub(dst, src, order) + #define c89atomic_fetch_or_explicit_8( dst, src, order) __atomic_fetch_or(dst, src, order) + #define c89atomic_fetch_or_explicit_16(dst, src, order) __atomic_fetch_or(dst, src, order) + #define c89atomic_fetch_or_explicit_32(dst, src, order) __atomic_fetch_or(dst, src, order) + #define c89atomic_fetch_or_explicit_64(dst, src, order) __atomic_fetch_or(dst, src, order) + #define c89atomic_fetch_xor_explicit_8( dst, src, order) __atomic_fetch_xor(dst, src, order) + #define c89atomic_fetch_xor_explicit_16(dst, src, order) __atomic_fetch_xor(dst, src, order) + #define c89atomic_fetch_xor_explicit_32(dst, src, order) __atomic_fetch_xor(dst, src, order) + #define c89atomic_fetch_xor_explicit_64(dst, src, order) __atomic_fetch_xor(dst, src, order) + #define c89atomic_fetch_and_explicit_8( dst, src, order) __atomic_fetch_and(dst, src, order) + #define c89atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) + #define c89atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) + #define c89atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) + #define c89atomic_compare_and_swap_8 (dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + typedef c89atomic_uint8 c89atomic_flag; + #define c89atomic_flag_test_and_set_explicit(dst, order) (c89atomic_bool)__atomic_test_and_set(dst, order) + #define c89atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) + #define c89atoimc_flag_load_explicit(ptr, order) c89atomic_load_explicit_8(ptr, order) #else - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") + #define c89atomic_memory_order_relaxed 1 + #define c89atomic_memory_order_consume 2 + #define c89atomic_memory_order_acquire 3 + #define c89atomic_memory_order_release 4 + #define c89atomic_memory_order_acq_rel 5 + #define c89atomic_memory_order_seq_cst 6 + #define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory") #if defined(__GNUC__) - #define ma_atomic_thread_fence(order) __sync_synchronize(), (void)order - static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #define c89atomic_thread_fence(order) __sync_synchronize(), (void)order + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - if (order > ma_atomic_memory_order_acquire) { + if (order > c89atomic_memory_order_acquire) { __sync_synchronize(); } return __sync_lock_test_and_set(dst, src); } - static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 oldValue; + c89atomic_uint16 oldValue; do { oldValue = *dst; } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 oldValue; + c89atomic_uint32 oldValue; do { oldValue = *dst; } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; + c89atomic_uint64 oldValue; do { oldValue = *dst; } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } - static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } - static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } - static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } - static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } - static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } - static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } - static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } - static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } - static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } - static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } - static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } - #define ma_atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #else - #if defined(MA_X86) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") - #elif defined(MA_X64) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") + #if defined(C89ATOMIC_X86) + #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") + #elif defined(C89ATOMIC_X64) + #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") #else #error Unsupported architecture. Please submit a feature request. #endif - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired) { - ma_uint8 result; - #if defined(MA_X86) || defined(MA_X64) + c89atomic_uint8 result; + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired) { - ma_uint16 result; - #if defined(MA_X86) || defined(MA_X64) + c89atomic_uint16 result; + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired) { - ma_uint32 result; - #if defined(MA_X86) || defined(MA_X64) + c89atomic_uint32 result; + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired) { - volatile ma_uint64 result; - #if defined(MA_X86) - ma_uint32 resultEAX; - ma_uint32 resultEDX; + volatile c89atomic_uint64 result; + #if defined(C89ATOMIC_X86) + c89atomic_uint32 resultEAX; + c89atomic_uint32 resultEDX; __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc"); - result = ((ma_uint64)resultEDX << 32) | resultEAX; - #elif defined(MA_X64) + result = ((c89atomic_uint64)resultEDX << 32) | resultEAX; + #elif defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 result = 0; + c89atomic_uint8 result = 0; (void)order; - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 result = 0; + c89atomic_uint16 result = 0; (void)order; - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 result; + c89atomic_uint32 result; (void)order; - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 result; + c89atomic_uint64 result; (void)order; - #if defined(MA_X86) + #if defined(C89ATOMIC_X86) do { result = *dst; - } while (ma_atomic_compare_and_swap_64(dst, result, src) != result); - #elif defined(MA_X64) + } while (c89atomic_compare_and_swap_64(dst, result, src) != result); + #elif defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 result; + c89atomic_uint8 result; (void)order; - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 result; + c89atomic_uint16 result; (void)order; - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 result; + c89atomic_uint32 result; (void)order; - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } - static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - #if defined(MA_X86) - ma_uint64 oldValue; - ma_uint64 newValue; + #if defined(C89ATOMIC_X86) + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; (void)order; do { oldValue = *dst; newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); return oldValue; - #elif defined(MA_X64) - ma_uint64 result; + #elif defined(C89ATOMIC_X64) + c89atomic_uint64 result; (void)order; __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); return result; #endif } - static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue - src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue - src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue & src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue & src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue ^ src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue ^ src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; + c89atomic_uint8 oldValue; + c89atomic_uint8 newValue; do { oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint8)(oldValue | src); + } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; + c89atomic_uint16 oldValue; + c89atomic_uint16 newValue; do { oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + newValue = (c89atomic_uint16)(oldValue | src); + } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; + c89atomic_uint32 oldValue; + c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } - static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; + c89atomic_uint64 oldValue; + c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) + #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; - return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); + return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0); } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; - return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); + return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0); } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; - return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); + return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0); } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; - return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); + return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0); } - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order) + #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order) + #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order) + #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order) + #define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order) + #define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order) + #define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order) + #define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order) + #define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order) + #define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order) + #define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order) + #define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order) + typedef c89atomic_uint8 c89atomic_flag; + #define c89atomic_flag_test_and_set_explicit(ptr, order) (c89atomic_bool)c89atomic_test_and_set_explicit_8(ptr, order) + #define c89atomic_flag_clear_explicit(ptr, order) c89atomic_clear_explicit_8(ptr, order) + #define c89atoimc_flag_load_explicit(ptr, order) c89atomic_load_explicit_8(ptr, order) #endif -#if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +#if !defined(C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) + #if defined(C89ATOMIC_HAS_8) + c89atomic_bool c89atomic_compare_exchange_strong_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8* expected, c89atomic_uint8 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - ma_uint8 expectedValue; - ma_uint8 result; + c89atomic_uint8 expectedValue; + c89atomic_uint8 result; (void)successOrder; (void)failureOrder; - expectedValue = ma_atomic_load_explicit_8(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_8(dst, expectedValue, desired); + expectedValue = c89atomic_load_explicit_8(expected, c89atomic_memory_order_seq_cst); + result = c89atomic_compare_and_swap_8(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { - ma_atomic_store_explicit_8(expected, result, failureOrder); + c89atomic_store_explicit_8(expected, result, failureOrder); return 0; } } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + #if defined(C89ATOMIC_HAS_16) + c89atomic_bool c89atomic_compare_exchange_strong_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16* expected, c89atomic_uint16 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - ma_uint16 expectedValue; - ma_uint16 result; + c89atomic_uint16 expectedValue; + c89atomic_uint16 result; (void)successOrder; (void)failureOrder; - expectedValue = ma_atomic_load_explicit_16(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_16(dst, expectedValue, desired); + expectedValue = c89atomic_load_explicit_16(expected, c89atomic_memory_order_seq_cst); + result = c89atomic_compare_and_swap_16(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { - ma_atomic_store_explicit_16(expected, result, failureOrder); + c89atomic_store_explicit_16(expected, result, failureOrder); return 0; } } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + #if defined(C89ATOMIC_HAS_32) + c89atomic_bool c89atomic_compare_exchange_strong_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32* expected, c89atomic_uint32 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - ma_uint32 expectedValue; - ma_uint32 result; + c89atomic_uint32 expectedValue; + c89atomic_uint32 result; (void)successOrder; (void)failureOrder; - expectedValue = ma_atomic_load_explicit_32(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_32(dst, expectedValue, desired); + expectedValue = c89atomic_load_explicit_32(expected, c89atomic_memory_order_seq_cst); + result = c89atomic_compare_and_swap_32(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { - ma_atomic_store_explicit_32(expected, result, failureOrder); + c89atomic_store_explicit_32(expected, result, failureOrder); return 0; } } #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + #if defined(C89ATOMIC_HAS_64) + c89atomic_bool c89atomic_compare_exchange_strong_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64* expected, c89atomic_uint64 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - ma_uint64 expectedValue; - ma_uint64 result; + c89atomic_uint64 expectedValue; + c89atomic_uint64 result; (void)successOrder; (void)failureOrder; - expectedValue = ma_atomic_load_explicit_64(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_64(dst, expectedValue, desired); + expectedValue = c89atomic_load_explicit_64(expected, c89atomic_memory_order_seq_cst); + result = c89atomic_compare_and_swap_64(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { - ma_atomic_store_explicit_64(expected, result, failureOrder); + c89atomic_store_explicit_64(expected, result, failureOrder); return 0; } } #endif - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) + #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) #endif -#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE) - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) +#if !defined(C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_8(volatile void* ptr) { (void)ptr; return 1; } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_16(volatile void* ptr) { (void)ptr; return 1; } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_32(volatile void* ptr) { (void)ptr; return 1; } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_64(volatile void* ptr) { (void)ptr; - #if defined(MA_64BIT) + #if defined(C89ATOMIC_64BIT) return 1; #else - #if defined(MA_X86) || defined(MA_X64) + #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) return 1; #else return 0; @@ -15544,542 +9716,446 @@ typedef int ma_atomic_memory_order; #endif } #endif -#if defined(MA_64BIT) - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) +#if defined(C89ATOMIC_64BIT) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr) { - return ma_atomic_is_lock_free_64((volatile ma_uint64*)ptr); + return c89atomic_is_lock_free_64((volatile c89atomic_uint64*)ptr); } - static MA_INLINE void* ma_atomic_load_explicit_ptr(volatile void** ptr, ma_atomic_memory_order order) + static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order) { - return (void*)ma_atomic_load_explicit_64((volatile ma_uint64*)ptr, order); + return (void*)c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order); } - static MA_INLINE void ma_atomic_store_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { - ma_atomic_store_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); + c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order); } - static MA_INLINE void* ma_atomic_exchange_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { - return (void*)ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); + return (void*)c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) { - return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)desired); + return (void*)c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)desired); } -#elif defined(MA_32BIT) - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) +#elif defined(C89ATOMIC_32BIT) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr) { - return ma_atomic_is_lock_free_32((volatile ma_uint32*)ptr); + return c89atomic_is_lock_free_32((volatile c89atomic_uint32*)ptr); } - static MA_INLINE void* ma_atomic_load_explicit_ptr(volatile void** ptr, ma_atomic_memory_order order) + static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order) { - return (void*)ma_atomic_load_explicit_32((volatile ma_uint32*)ptr, order); + return (void*)c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order); } - static MA_INLINE void ma_atomic_store_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { - ma_atomic_store_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); + c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order); } - static MA_INLINE void* ma_atomic_exchange_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { - return (void*)ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); + return (void*)c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) { - return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)desired); + return (void*)c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)desired); } #else #error Unsupported architecture. #endif -#define ma_atomic_flag_test_and_set(ptr) ma_atomic_flag_test_and_set_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_flag_clear(ptr) ma_atomic_flag_clear_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_ptr(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_ptr(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_8( ptr) ma_atomic_test_and_set_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_16(ptr) ma_atomic_test_and_set_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_32(ptr) ma_atomic_test_and_set_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_64(ptr) ma_atomic_test_and_set_explicit_64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_8( ptr) ma_atomic_clear_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_16(ptr) ma_atomic_clear_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_32(ptr) ma_atomic_clear_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_64(ptr) ma_atomic_clear_explicit_64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_8( dst, src) ma_atomic_store_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_16(dst, src) ma_atomic_store_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_32(dst, src) ma_atomic_store_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_64(dst, src) ma_atomic_store_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_8( ptr) ma_atomic_load_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_16(ptr) ma_atomic_load_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_32(ptr) ma_atomic_load_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_64(ptr) ma_atomic_load_explicit_64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_8( dst, src) ma_atomic_exchange_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_16(dst, src) ma_atomic_exchange_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_32(dst, src) ma_atomic_exchange_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_64(dst, src) ma_atomic_exchange_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_16( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_32( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_64( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_8( dst, src) ma_atomic_fetch_add_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_16(dst, src) ma_atomic_fetch_add_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_32(dst, src) ma_atomic_fetch_add_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_64(dst, src) ma_atomic_fetch_add_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_8( dst, src) ma_atomic_fetch_sub_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_16(dst, src) ma_atomic_fetch_sub_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_32(dst, src) ma_atomic_fetch_sub_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_64(dst, src) ma_atomic_fetch_sub_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_8( dst, src) ma_atomic_fetch_or_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_16(dst, src) ma_atomic_fetch_or_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_32(dst, src) ma_atomic_fetch_or_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_64(dst, src) ma_atomic_fetch_or_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_8( dst, src) ma_atomic_fetch_xor_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_16(dst, src) ma_atomic_fetch_xor_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_32(dst, src) ma_atomic_fetch_xor_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_64(dst, src) ma_atomic_fetch_xor_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_8( dst, src) ma_atomic_fetch_and_explicit_8 (dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_16(dst, src) ma_atomic_fetch_and_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_32(dst, src) ma_atomic_fetch_and_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_64(dst, src) ma_atomic_fetch_and_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_explicit_i8( ptr, order) (ma_int8 )ma_atomic_test_and_set_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_test_and_set_explicit_i16(ptr, order) (ma_int16)ma_atomic_test_and_set_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_test_and_set_explicit_i32(ptr, order) (ma_int32)ma_atomic_test_and_set_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_test_and_set_explicit_i64(ptr, order) (ma_int64)ma_atomic_test_and_set_explicit_64((ma_uint64*)ptr, order) -#define ma_atomic_clear_explicit_i8( ptr, order) ma_atomic_clear_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_clear_explicit_i16(ptr, order) ma_atomic_clear_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_clear_explicit_i32(ptr, order) ma_atomic_clear_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_clear_explicit_i64(ptr, order) ma_atomic_clear_explicit_64((ma_uint64*)ptr, order) -#define ma_atomic_store_explicit_i8( dst, src, order) ma_atomic_store_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_store_explicit_i16(dst, src, order) ma_atomic_store_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_store_explicit_i32(dst, src, order) ma_atomic_store_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_store_explicit_i64(dst, src, order) ma_atomic_store_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_load_explicit_i8( ptr, order) (ma_int8 )ma_atomic_load_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_load_explicit_i16(ptr, order) (ma_int16)ma_atomic_load_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_load_explicit_i32(ptr, order) (ma_int32)ma_atomic_load_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_load_explicit_i64(ptr, order) (ma_int64)ma_atomic_load_explicit_64((ma_uint64*)ptr, order) -#define ma_atomic_exchange_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_exchange_explicit_8 ((ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_exchange_explicit_i16(dst, src, order) (ma_int16)ma_atomic_exchange_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_exchange_explicit_i32(dst, src, order) (ma_int32)ma_atomic_exchange_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_exchange_explicit_i64(dst, src, order) (ma_int64)ma_atomic_exchange_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) -#define ma_atomic_fetch_add_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_add_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_fetch_add_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_add_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_fetch_add_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_add_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_fetch_add_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_add_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_fetch_sub_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_sub_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_fetch_sub_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_sub_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_fetch_sub_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_sub_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_fetch_sub_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_sub_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_fetch_or_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_or_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_fetch_or_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_or_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_fetch_or_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_or_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_fetch_or_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_or_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_fetch_xor_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_xor_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_fetch_xor_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_xor_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_fetch_xor_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_xor_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_fetch_xor_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_xor_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_fetch_and_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_and_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) -#define ma_atomic_fetch_and_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_and_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) -#define ma_atomic_fetch_and_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_and_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) -#define ma_atomic_fetch_and_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_and_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_test_and_set_i8( ptr) ma_atomic_test_and_set_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i16(ptr) ma_atomic_test_and_set_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i32(ptr) ma_atomic_test_and_set_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i64(ptr) ma_atomic_test_and_set_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i8( ptr) ma_atomic_clear_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i16(ptr) ma_atomic_clear_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i32(ptr) ma_atomic_clear_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i64(ptr) ma_atomic_clear_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_i8( dst, src) ma_atomic_store_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_i16(dst, src) ma_atomic_store_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_i32(dst, src) ma_atomic_store_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_i64(dst, src) ma_atomic_store_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_i8( ptr) ma_atomic_load_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_i16(ptr) ma_atomic_load_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_i32(ptr) ma_atomic_load_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_i64(ptr) ma_atomic_load_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_i8( dst, src) ma_atomic_exchange_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_i16(dst, src) ma_atomic_exchange_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_i32(dst, src) ma_atomic_exchange_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_i64(dst, src) ma_atomic_exchange_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i16(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_i8( dst, src) ma_atomic_fetch_add_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_i16(dst, src) ma_atomic_fetch_add_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_i32(dst, src) ma_atomic_fetch_add_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_i64(dst, src) ma_atomic_fetch_add_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_i8( dst, src) ma_atomic_fetch_sub_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_i16(dst, src) ma_atomic_fetch_sub_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_i32(dst, src) ma_atomic_fetch_sub_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_i64(dst, src) ma_atomic_fetch_sub_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_i8( dst, src) ma_atomic_fetch_or_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_i16(dst, src) ma_atomic_fetch_or_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_i32(dst, src) ma_atomic_fetch_or_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_i64(dst, src) ma_atomic_fetch_or_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_i8( dst, src) ma_atomic_fetch_xor_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_i16(dst, src) ma_atomic_fetch_xor_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_i32(dst, src) ma_atomic_fetch_xor_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_i64(dst, src) ma_atomic_fetch_xor_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_i8( dst, src) ma_atomic_fetch_and_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_i16(dst, src) ma_atomic_fetch_and_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_i32(dst, src) ma_atomic_fetch_and_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_i64(dst, src) ma_atomic_fetch_and_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_and_swap_i8( dst, expected, dedsired) (ma_int8 )ma_atomic_compare_and_swap_8( (ma_uint8* )dst, (ma_uint8 )expected, (ma_uint8 )dedsired) -#define ma_atomic_compare_and_swap_i16(dst, expected, dedsired) (ma_int16)ma_atomic_compare_and_swap_16((ma_uint16*)dst, (ma_uint16)expected, (ma_uint16)dedsired) -#define ma_atomic_compare_and_swap_i32(dst, expected, dedsired) (ma_int32)ma_atomic_compare_and_swap_32((ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)dedsired) -#define ma_atomic_compare_and_swap_i64(dst, expected, dedsired) (ma_int64)ma_atomic_compare_and_swap_64((ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)dedsired) +#define c89atomic_flag_test_and_set(ptr) c89atomic_flag_test_and_set_explicit(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_flag_clear(ptr) c89atomic_flag_clear_explicit(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_store_ptr(dst, src) c89atomic_store_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst) +#define c89atomic_load_ptr(ptr) c89atomic_load_explicit_ptr((volatile void**)ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_ptr(dst, src) c89atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_ptr(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void*)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_ptr(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void*)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_8( ptr) c89atomic_test_and_set_explicit_8( ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_16(ptr) c89atomic_test_and_set_explicit_16(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_32(ptr) c89atomic_test_and_set_explicit_32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_64(ptr) c89atomic_test_and_set_explicit_64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_8( ptr) c89atomic_clear_explicit_8( ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_16(ptr) c89atomic_clear_explicit_16(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_32(ptr) c89atomic_clear_explicit_32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_64(ptr) c89atomic_clear_explicit_64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_store_8( dst, src) c89atomic_store_explicit_8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_16(dst, src) c89atomic_store_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_32(dst, src) c89atomic_store_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_64(dst, src) c89atomic_store_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_load_8( ptr) c89atomic_load_explicit_8( ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_16(ptr) c89atomic_load_explicit_16(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_32(ptr) c89atomic_load_explicit_32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_64(ptr) c89atomic_load_explicit_64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_8( dst, src) c89atomic_exchange_explicit_8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_16(dst, src) c89atomic_exchange_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_32(dst, src) c89atomic_exchange_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_64(dst, src) c89atomic_exchange_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_8( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_16(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_32(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_64(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_8( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_16( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_32( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_64( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_8( dst, src) c89atomic_fetch_add_explicit_8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_16(dst, src) c89atomic_fetch_add_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_32(dst, src) c89atomic_fetch_add_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_64(dst, src) c89atomic_fetch_add_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_8( dst, src) c89atomic_fetch_sub_explicit_8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_16(dst, src) c89atomic_fetch_sub_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_32(dst, src) c89atomic_fetch_sub_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_64(dst, src) c89atomic_fetch_sub_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_8( dst, src) c89atomic_fetch_or_explicit_8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_16(dst, src) c89atomic_fetch_or_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_32(dst, src) c89atomic_fetch_or_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_64(dst, src) c89atomic_fetch_or_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_8( dst, src) c89atomic_fetch_xor_explicit_8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_16(dst, src) c89atomic_fetch_xor_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_32(dst, src) c89atomic_fetch_xor_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_64(dst, src) c89atomic_fetch_xor_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_8( dst, src) c89atomic_fetch_and_explicit_8 (dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_16(dst, src) c89atomic_fetch_and_explicit_16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_32(dst, src) c89atomic_fetch_and_explicit_32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_64(dst, src) c89atomic_fetch_and_explicit_64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_explicit_i8( ptr, order) (c89atomic_int8 )c89atomic_test_and_set_explicit_8( (c89atomic_uint8* )ptr, order) +#define c89atomic_test_and_set_explicit_i16(ptr, order) (c89atomic_int16)c89atomic_test_and_set_explicit_16((c89atomic_uint16*)ptr, order) +#define c89atomic_test_and_set_explicit_i32(ptr, order) (c89atomic_int32)c89atomic_test_and_set_explicit_32((c89atomic_uint32*)ptr, order) +#define c89atomic_test_and_set_explicit_i64(ptr, order) (c89atomic_int64)c89atomic_test_and_set_explicit_64((c89atomic_uint64*)ptr, order) +#define c89atomic_clear_explicit_i8( ptr, order) c89atomic_clear_explicit_8( (c89atomic_uint8* )ptr, order) +#define c89atomic_clear_explicit_i16(ptr, order) c89atomic_clear_explicit_16((c89atomic_uint16*)ptr, order) +#define c89atomic_clear_explicit_i32(ptr, order) c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order) +#define c89atomic_clear_explicit_i64(ptr, order) c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order) +#define c89atomic_store_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_store_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_store_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_store_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_load_explicit_i8( ptr, order) (c89atomic_int8 )c89atomic_load_explicit_8( (c89atomic_uint8* )ptr, order) +#define c89atomic_load_explicit_i16(ptr, order) (c89atomic_int16)c89atomic_load_explicit_16((c89atomic_uint16*)ptr, order) +#define c89atomic_load_explicit_i32(ptr, order) (c89atomic_int32)c89atomic_load_explicit_32((c89atomic_uint32*)ptr, order) +#define c89atomic_load_explicit_i64(ptr, order) (c89atomic_int64)c89atomic_load_explicit_64((c89atomic_uint64*)ptr, order) +#define c89atomic_exchange_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_exchange_explicit_8 ((c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_exchange_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_exchange_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_exchange_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_exchange_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_exchange_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_exchange_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder) +#define c89atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder) +#define c89atomic_fetch_add_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_add_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_fetch_add_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_add_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_fetch_add_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_add_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_fetch_add_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_add_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_fetch_sub_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_sub_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_fetch_sub_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_sub_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_fetch_sub_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_sub_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_fetch_sub_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_sub_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_fetch_or_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_or_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_fetch_or_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_or_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_fetch_or_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_or_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_fetch_or_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_or_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_fetch_xor_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_xor_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_fetch_xor_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_xor_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_fetch_xor_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_xor_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_fetch_xor_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_xor_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_fetch_and_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_and_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_fetch_and_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_and_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_fetch_and_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_and_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_fetch_and_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_and_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_test_and_set_i8( ptr) c89atomic_test_and_set_explicit_i8( ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_i16(ptr) c89atomic_test_and_set_explicit_i16(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_i32(ptr) c89atomic_test_and_set_explicit_i32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_test_and_set_i64(ptr) c89atomic_test_and_set_explicit_i64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_i8( ptr) c89atomic_clear_explicit_i8( ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_i16(ptr) c89atomic_clear_explicit_i16(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_i32(ptr) c89atomic_clear_explicit_i32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_i64(ptr) c89atomic_clear_explicit_i64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_store_i8( dst, src) c89atomic_store_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_i16(dst, src) c89atomic_store_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_i32(dst, src) c89atomic_store_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_i64(dst, src) c89atomic_store_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_load_i8( ptr) c89atomic_load_explicit_i8( ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_i16(ptr) c89atomic_load_explicit_i16(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_i32(ptr) c89atomic_load_explicit_i32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_i64(ptr) c89atomic_load_explicit_i64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_i8( dst, src) c89atomic_exchange_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_i16(dst, src) c89atomic_exchange_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_i32(dst, src) c89atomic_exchange_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_i64(dst, src) c89atomic_exchange_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_i8( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_i16(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_i32(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_i64(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_i8( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_i16(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_i32(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_i64(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_i8( dst, src) c89atomic_fetch_add_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_i16(dst, src) c89atomic_fetch_add_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_i32(dst, src) c89atomic_fetch_add_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_i64(dst, src) c89atomic_fetch_add_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_i8( dst, src) c89atomic_fetch_sub_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_i16(dst, src) c89atomic_fetch_sub_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_i32(dst, src) c89atomic_fetch_sub_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_i64(dst, src) c89atomic_fetch_sub_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_i8( dst, src) c89atomic_fetch_or_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_i16(dst, src) c89atomic_fetch_or_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_i32(dst, src) c89atomic_fetch_or_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_i64(dst, src) c89atomic_fetch_or_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_i8( dst, src) c89atomic_fetch_xor_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_i16(dst, src) c89atomic_fetch_xor_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_i32(dst, src) c89atomic_fetch_xor_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_i64(dst, src) c89atomic_fetch_xor_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_i8( dst, src) c89atomic_fetch_and_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_i16(dst, src) c89atomic_fetch_and_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_i32(dst, src) c89atomic_fetch_and_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_i64(dst, src) c89atomic_fetch_and_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) typedef union { - ma_uint32 i; + c89atomic_uint32 i; float f; -} ma_atomic_if32; +} c89atomic_if32; typedef union { - ma_uint64 i; + c89atomic_uint64 i; double f; -} ma_atomic_if64; -#define ma_atomic_clear_explicit_f32(ptr, order) ma_atomic_clear_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_clear_explicit_f64(ptr, order) ma_atomic_clear_explicit_64((ma_uint64*)ptr, order) -static MA_INLINE void ma_atomic_store_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) +} c89atomic_if64; +#define c89atomic_clear_explicit_f32(ptr, order) c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order) +#define c89atomic_clear_explicit_f64(ptr, order) c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order) +static C89ATOMIC_INLINE void c89atomic_store_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) { - ma_atomic_if32 x; + c89atomic_if32 x; x.f = src; - ma_atomic_store_explicit_32((volatile ma_uint32*)dst, x.i, order); + c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); } -static MA_INLINE void ma_atomic_store_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) +static C89ATOMIC_INLINE void c89atomic_store_explicit_f64(volatile float* dst, float src, c89atomic_memory_order order) { - ma_atomic_if64 x; + c89atomic_if64 x; x.f = src; - ma_atomic_store_explicit_64((volatile ma_uint64*)dst, x.i, order); + c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); } -static MA_INLINE float ma_atomic_load_explicit_f32(volatile const float* ptr, ma_atomic_memory_order order) +static C89ATOMIC_INLINE float c89atomic_load_explicit_f32(volatile float* ptr, c89atomic_memory_order order) { - ma_atomic_if32 r; - r.i = ma_atomic_load_explicit_32((volatile const ma_uint32*)ptr, order); + c89atomic_if32 r; + r.i = c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order); return r.f; } -static MA_INLINE double ma_atomic_load_explicit_f64(volatile const double* ptr, ma_atomic_memory_order order) +static C89ATOMIC_INLINE double c89atomic_load_explicit_f64(volatile double* ptr, c89atomic_memory_order order) { - ma_atomic_if64 r; - r.i = ma_atomic_load_explicit_64((volatile const ma_uint64*)ptr, order); + c89atomic_if64 r; + r.i = c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order); return r.f; } -static MA_INLINE float ma_atomic_exchange_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) +static C89ATOMIC_INLINE float c89atomic_exchange_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) { - ma_atomic_if32 r; - ma_atomic_if32 x; + c89atomic_if32 r; + c89atomic_if32 x; x.f = src; - r.i = ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, x.i, order); + r.i = c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); return r.f; } -static MA_INLINE double ma_atomic_exchange_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) +static C89ATOMIC_INLINE double c89atomic_exchange_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order) { - ma_atomic_if64 r; - ma_atomic_if64 x; + c89atomic_if64 r; + c89atomic_if64 x; x.f = src; - r.i = ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, x.i, order); + r.i = c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); return r.f; } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) -{ - ma_atomic_if32 d; - d.f = desired; - return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); -} -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) -{ - ma_atomic_if64 d; - d.f = desired; - return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); -} -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) -{ - ma_atomic_if32 d; - d.f = desired; - return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); -} -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) -{ - ma_atomic_if64 d; - d.f = desired; - return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); -} -static MA_INLINE float ma_atomic_fetch_add_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) -{ - ma_atomic_if32 r; - ma_atomic_if32 x; - x.f = src; - r.i = ma_atomic_fetch_add_explicit_32((volatile ma_uint32*)dst, x.i, order); - return r.f; -} -static MA_INLINE double ma_atomic_fetch_add_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) -{ - ma_atomic_if64 r; - ma_atomic_if64 x; - x.f = src; - r.i = ma_atomic_fetch_add_explicit_64((volatile ma_uint64*)dst, x.i, order); - return r.f; -} -static MA_INLINE float ma_atomic_fetch_sub_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) -{ - ma_atomic_if32 r; - ma_atomic_if32 x; - x.f = src; - r.i = ma_atomic_fetch_sub_explicit_32((volatile ma_uint32*)dst, x.i, order); - return r.f; -} -static MA_INLINE double ma_atomic_fetch_sub_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) -{ - ma_atomic_if64 r; - ma_atomic_if64 x; - x.f = src; - r.i = ma_atomic_fetch_sub_explicit_64((volatile ma_uint64*)dst, x.i, order); - return r.f; -} -static MA_INLINE float ma_atomic_fetch_or_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) -{ - ma_atomic_if32 r; - ma_atomic_if32 x; - x.f = src; - r.i = ma_atomic_fetch_or_explicit_32((volatile ma_uint32*)dst, x.i, order); - return r.f; -} -static MA_INLINE double ma_atomic_fetch_or_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) -{ - ma_atomic_if64 r; - ma_atomic_if64 x; - x.f = src; - r.i = ma_atomic_fetch_or_explicit_64((volatile ma_uint64*)dst, x.i, order); - return r.f; -} -static MA_INLINE float ma_atomic_fetch_xor_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) -{ - ma_atomic_if32 r; - ma_atomic_if32 x; - x.f = src; - r.i = ma_atomic_fetch_xor_explicit_32((volatile ma_uint32*)dst, x.i, order); - return r.f; -} -static MA_INLINE double ma_atomic_fetch_xor_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) -{ - ma_atomic_if64 r; - ma_atomic_if64 x; - x.f = src; - r.i = ma_atomic_fetch_xor_explicit_64((volatile ma_uint64*)dst, x.i, order); - return r.f; -} -static MA_INLINE float ma_atomic_fetch_and_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) -{ - ma_atomic_if32 r; - ma_atomic_if32 x; - x.f = src; - r.i = ma_atomic_fetch_and_explicit_32((volatile ma_uint32*)dst, x.i, order); - return r.f; -} -static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) -{ - ma_atomic_if64 r; - ma_atomic_if64 x; - x.f = src; - r.i = ma_atomic_fetch_and_explicit_64((volatile ma_uint64*)dst, x.i, order); - return r.f; -} -#define ma_atomic_clear_f32(ptr) (float )ma_atomic_clear_explicit_f32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_f64(ptr) (double)ma_atomic_clear_explicit_f64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_f32(dst, src) ma_atomic_store_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_f64(dst, src) ma_atomic_store_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_f32(ptr) (float )ma_atomic_load_explicit_f32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_f64(ptr) (double)ma_atomic_load_explicit_f64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_f32(dst, src) (float )ma_atomic_exchange_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_f64(dst, src) (double)ma_atomic_exchange_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_f32(dst, src) ma_atomic_fetch_add_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_add_f64(dst, src) ma_atomic_fetch_add_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_f32(dst, src) ma_atomic_fetch_sub_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_sub_f64(dst, src) ma_atomic_fetch_sub_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_f32(dst, src) ma_atomic_fetch_or_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_or_f64(dst, src) ma_atomic_fetch_or_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_f32(dst, src) ma_atomic_fetch_xor_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_xor_f64(dst, src) ma_atomic_fetch_xor_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_f32(dst, src) ma_atomic_fetch_and_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_fetch_and_f64(dst, src) ma_atomic_fetch_and_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float desired) -{ - ma_atomic_if32 r; - ma_atomic_if32 e, d; - e.f = expected; - d.f = desired; - r.i = ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, e.i, d.i); - return r.f; -} -static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double desired) -{ - ma_atomic_if64 r; - ma_atomic_if64 e, d; - e.f = expected; - d.f = desired; - r.i = ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, e.i, d.i); - return r.f; -} -typedef ma_atomic_flag ma_atomic_spinlock; -static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) +#define c89atomic_clear_f32(ptr) (float )c89atomic_clear_explicit_f32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_clear_f64(ptr) (double)c89atomic_clear_explicit_f64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_store_f32(dst, src) c89atomic_store_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_store_f64(dst, src) c89atomic_store_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_load_f32(ptr) (float )c89atomic_load_explicit_f32(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_load_f64(ptr) (double)c89atomic_load_explicit_f64(ptr, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_f32(dst, src) (float )c89atomic_exchange_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_exchange_f64(dst, src) (double)c89atomic_exchange_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +typedef c89atomic_flag c89atomic_spinlock; +static C89ATOMIC_INLINE void c89atomic_spinlock_lock(volatile c89atomic_spinlock* pSpinlock) { for (;;) { - if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { + if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) { break; } - while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + while (c89atoimc_flag_load_explicit(pSpinlock, c89atomic_memory_order_relaxed) == 1) { } } } -static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) +static C89ATOMIC_INLINE void c89atomic_spinlock_unlock(volatile c89atomic_spinlock* pSpinlock) { - ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); + c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release); } -#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic pop -#endif #if defined(__cplusplus) } #endif #endif /* c89atomic.h end */ -#define MA_ATOMIC_SAFE_TYPE_IMPL(c89TypeExtension, type) \ - static MA_INLINE ma_##type ma_atomic_##type##_get(ma_atomic_##type* x) \ - { \ - return (ma_##type)ma_atomic_load_##c89TypeExtension(&x->value); \ - } \ - static MA_INLINE void ma_atomic_##type##_set(ma_atomic_##type* x, ma_##type value) \ - { \ - ma_atomic_store_##c89TypeExtension(&x->value, value); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_exchange(ma_atomic_##type* x, ma_##type value) \ - { \ - return (ma_##type)ma_atomic_exchange_##c89TypeExtension(&x->value, value); \ - } \ - static MA_INLINE ma_bool32 ma_atomic_##type##_compare_exchange(ma_atomic_##type* x, ma_##type* expected, ma_##type desired) \ - { \ - return ma_atomic_compare_exchange_weak_##c89TypeExtension(&x->value, expected, desired); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_fetch_add(ma_atomic_##type* x, ma_##type y) \ - { \ - return (ma_##type)ma_atomic_fetch_add_##c89TypeExtension(&x->value, y); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_fetch_sub(ma_atomic_##type* x, ma_##type y) \ - { \ - return (ma_##type)ma_atomic_fetch_sub_##c89TypeExtension(&x->value, y); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_fetch_or(ma_atomic_##type* x, ma_##type y) \ - { \ - return (ma_##type)ma_atomic_fetch_or_##c89TypeExtension(&x->value, y); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_fetch_xor(ma_atomic_##type* x, ma_##type y) \ - { \ - return (ma_##type)ma_atomic_fetch_xor_##c89TypeExtension(&x->value, y); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_fetch_and(ma_atomic_##type* x, ma_##type y) \ - { \ - return (ma_##type)ma_atomic_fetch_and_##c89TypeExtension(&x->value, y); \ - } \ - static MA_INLINE ma_##type ma_atomic_##type##_compare_and_swap(ma_atomic_##type* x, ma_##type expected, ma_##type desired) \ - { \ - return (ma_##type)ma_atomic_compare_and_swap_##c89TypeExtension(&x->value, expected, desired); \ - } \ -#define MA_ATOMIC_SAFE_TYPE_IMPL_PTR(type) \ - static MA_INLINE ma_##type* ma_atomic_ptr_##type##_get(ma_atomic_ptr_##type* x) \ - { \ - return ma_atomic_load_ptr((void**)&x->value); \ - } \ - static MA_INLINE void ma_atomic_ptr_##type##_set(ma_atomic_ptr_##type* x, ma_##type* value) \ - { \ - ma_atomic_store_ptr((void**)&x->value, (void*)value); \ - } \ - static MA_INLINE ma_##type* ma_atomic_ptr_##type##_exchange(ma_atomic_ptr_##type* x, ma_##type* value) \ - { \ - return ma_atomic_exchange_ptr((void**)&x->value, (void*)value); \ - } \ - static MA_INLINE ma_bool32 ma_atomic_ptr_##type##_compare_exchange(ma_atomic_ptr_##type* x, ma_##type** expected, ma_##type* desired) \ - { \ - return ma_atomic_compare_exchange_weak_ptr((void**)&x->value, (void*)expected, (void*)desired); \ - } \ - static MA_INLINE ma_##type* ma_atomic_ptr_##type##_compare_and_swap(ma_atomic_ptr_##type* x, ma_##type* expected, ma_##type* desired) \ - { \ - return (ma_##type*)ma_atomic_compare_and_swap_ptr((void**)&x->value, (void*)expected, (void*)desired); \ - } \ -MA_ATOMIC_SAFE_TYPE_IMPL(32, uint32) -MA_ATOMIC_SAFE_TYPE_IMPL(i32, int32) -MA_ATOMIC_SAFE_TYPE_IMPL(64, uint64) -MA_ATOMIC_SAFE_TYPE_IMPL(f32, float) -MA_ATOMIC_SAFE_TYPE_IMPL(32, bool32) +static void* ma__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_MALLOC(sz); +} -#if !defined(MA_NO_DEVICE_IO) -MA_ATOMIC_SAFE_TYPE_IMPL(i32, device_state) -#endif +static void* ma__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_REALLOC(p, sz); +} + +static void ma__free_default(void* p, void* pUserData) +{ + (void)pUserData; + MA_FREE(p); +} + + +static void* ma__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onMalloc != NULL) { + return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); + } + + /* Try using realloc(). */ + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + + return NULL; +} + +static void* ma__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); + } + + /* Try emulating realloc() in terms of malloc()/free(). */ + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + + if (p != NULL) { + MA_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static MA_INLINE void* ma__calloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +{ + void* p = ma__malloc_from_callbacks(sz, pAllocationCallbacks); + if (p != NULL) { + MA_ZERO_MEMORY(p, sz); + } + + return p; +} + +static void ma__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + +static ma_allocation_callbacks ma_allocation_callbacks_init_default(void) +{ + ma_allocation_callbacks callbacks; + callbacks.pUserData = NULL; + callbacks.onMalloc = ma__malloc_default; + callbacks.onRealloc = ma__realloc_default; + callbacks.onFree = ma__free_default; + + return callbacks; +} + +static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst, const ma_allocation_callbacks* pSrc) +{ + if (pDst == NULL) { + return MA_INVALID_ARGS; + } + + if (pSrc == NULL) { + *pDst = ma_allocation_callbacks_init_default(); + } else { + if (pSrc->pUserData == NULL && pSrc->onFree == NULL && pSrc->onMalloc == NULL && pSrc->onRealloc == NULL) { + *pDst = ma_allocation_callbacks_init_default(); + } else { + if (pSrc->onFree == NULL || (pSrc->onMalloc == NULL && pSrc->onRealloc == NULL)) { + return MA_INVALID_ARGS; /* Invalid allocation callbacks. */ + } else { + *pDst = *pSrc; + } + } + } + + return MA_SUCCESS; +} MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn) { - /* This is based on the calculation in ma_linear_resampler_get_expected_output_frame_count(). */ - ma_uint64 outputFrameCount; - ma_uint64 preliminaryInputFrameCountFromFrac; - ma_uint64 preliminaryInputFrameCount; - - if (sampleRateIn == 0 || sampleRateOut == 0 || frameCountIn == 0) { - return 0; - } + /* For robustness we're going to use a resampler object to calculate this since that already has a way of calculating this. */ + ma_result result; + ma_uint64 frameCountOut; + ma_resampler_config config; + ma_resampler resampler; if (sampleRateOut == sampleRateIn) { return frameCountIn; } - outputFrameCount = (frameCountIn * sampleRateOut) / sampleRateIn; - - preliminaryInputFrameCountFromFrac = (outputFrameCount * (sampleRateIn / sampleRateOut)) / sampleRateOut; - preliminaryInputFrameCount = (outputFrameCount * (sampleRateIn % sampleRateOut)) + preliminaryInputFrameCountFromFrac; - - if (preliminaryInputFrameCount <= frameCountIn) { - outputFrameCount += 1; + config = ma_resampler_config_init(ma_format_s16, 1, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear); + result = ma_resampler_init(&config, &resampler); + if (result != MA_SUCCESS) { + return 0; } - return outputFrameCount; + frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn); + + ma_resampler_uninit(&resampler); + return frameCountOut; } #ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE @@ -16098,7 +10174,7 @@ static ma_result ma_result_from_GetLastError(DWORD error) case ERROR_TOO_MANY_OPEN_FILES: return MA_TOO_MANY_OPEN_FILES; case ERROR_NOT_ENOUGH_MEMORY: return MA_OUT_OF_MEMORY; case ERROR_DISK_FULL: return MA_NO_SPACE; - case ERROR_HANDLE_EOF: return MA_AT_END; + case ERROR_HANDLE_EOF: return MA_END_OF_FILE; case ERROR_NEGATIVE_SEEK: return MA_BAD_SEEK; case ERROR_INVALID_PARAMETER: return MA_INVALID_ARGS; case ERROR_ACCESS_DENIED: return MA_ACCESS_DENIED; @@ -16117,6 +10193,16 @@ static ma_result ma_result_from_GetLastError(DWORD error) Threading *******************************************************************************/ +#ifndef MA_NO_THREADING +#ifdef MA_WIN32 + #define MA_THREADCALL WINAPI + typedef unsigned long ma_thread_result; +#else + #define MA_THREADCALL + typedef void* ma_thread_result; +#endif +typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData); + static MA_INLINE ma_result ma_spinlock_lock_ex(volatile ma_spinlock* pSpinlock, ma_bool32 yield) { if (pSpinlock == NULL) { @@ -16124,11 +10210,11 @@ static MA_INLINE ma_result ma_spinlock_lock_ex(volatile ma_spinlock* pSpinlock, } for (;;) { - if (ma_atomic_exchange_explicit_32(pSpinlock, 1, ma_atomic_memory_order_acquire) == 0) { + if (c89atomic_exchange_explicit_32(pSpinlock, 1, c89atomic_memory_order_acquire) == 0) { break; } - while (ma_atomic_load_explicit_32(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + while (c89atomic_load_explicit_32(pSpinlock, c89atomic_memory_order_relaxed) == 1) { if (yield) { ma_yield(); } @@ -16154,287 +10240,11 @@ MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock) return MA_INVALID_ARGS; } - ma_atomic_store_explicit_32(pSpinlock, 0, ma_atomic_memory_order_release); + c89atomic_store_explicit_32(pSpinlock, 0, c89atomic_memory_order_release); return MA_SUCCESS; } - -#ifndef MA_NO_THREADING -#if defined(MA_POSIX) - #define MA_THREADCALL - typedef void* ma_thread_result; -#elif defined(MA_WIN32) - #define MA_THREADCALL WINAPI - typedef unsigned long ma_thread_result; -#endif - -typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData); - -#ifdef MA_POSIX -static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData) -{ - int result; - pthread_attr_t* pAttr = NULL; - -#if !defined(__EMSCRIPTEN__) && !defined(__3DS__) - /* Try setting the thread priority. It's not critical if anything fails here. */ - pthread_attr_t attr; - if (pthread_attr_init(&attr) == 0) { - int scheduler = -1; - - /* We successfully initialized our attributes object so we can assign the pointer so it's passed into pthread_create(). */ - pAttr = &attr; - - /* We need to set the scheduler policy. Only do this if the OS supports pthread_attr_setschedpolicy() */ - #if !defined(MA_BEOS) - { - if (priority == ma_thread_priority_idle) { - #ifdef SCHED_IDLE - if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) { - scheduler = SCHED_IDLE; - } - #endif - } else if (priority == ma_thread_priority_realtime) { - #ifdef SCHED_FIFO - if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) { - scheduler = SCHED_FIFO; - } - #endif - #ifdef MA_LINUX - } else { - scheduler = sched_getscheduler(0); - #endif - } - } - #endif - - if (stackSize > 0) { - pthread_attr_setstacksize(&attr, stackSize); - } - - if (scheduler != -1) { - int priorityMin = sched_get_priority_min(scheduler); - int priorityMax = sched_get_priority_max(scheduler); - int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */ - - struct sched_param sched; - if (pthread_attr_getschedparam(&attr, &sched) == 0) { - if (priority == ma_thread_priority_idle) { - sched.sched_priority = priorityMin; - } else if (priority == ma_thread_priority_realtime) { - #if defined(MA_PTHREAD_REALTIME_THREAD_PRIORITY) - { - sched.sched_priority = MA_PTHREAD_REALTIME_THREAD_PRIORITY; - } - #else - { - sched.sched_priority = priorityMax; - } - #endif - } else { - sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ - } - - if (sched.sched_priority < priorityMin) { - sched.sched_priority = priorityMin; - } - if (sched.sched_priority > priorityMax) { - sched.sched_priority = priorityMax; - } - - /* I'm not treating a failure of setting the priority as a critical error so not aborting on failure here. */ - if (pthread_attr_setschedparam(&attr, &sched) == 0) { - #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) - { - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); - } - #endif - } - } - } - } -#else - /* It's the emscripten build. We'll have a few unused parameters. */ - (void)priority; - (void)stackSize; -#endif - - result = pthread_create((pthread_t*)pThread, pAttr, entryProc, pData); - - /* The thread attributes object is no longer required. */ - if (pAttr != NULL) { - pthread_attr_destroy(pAttr); - } - - if (result != 0) { - return ma_result_from_errno(result); - } - - return MA_SUCCESS; -} - -static void ma_thread_wait__posix(ma_thread* pThread) -{ - pthread_join((pthread_t)*pThread, NULL); -} - - -static ma_result ma_mutex_init__posix(ma_mutex* pMutex) -{ - int result; - - if (pMutex == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pMutex); - - result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL); - if (result != 0) { - return ma_result_from_errno(result); - } - - return MA_SUCCESS; -} - -static void ma_mutex_uninit__posix(ma_mutex* pMutex) -{ - pthread_mutex_destroy((pthread_mutex_t*)pMutex); -} - -static void ma_mutex_lock__posix(ma_mutex* pMutex) -{ - pthread_mutex_lock((pthread_mutex_t*)pMutex); -} - -static void ma_mutex_unlock__posix(ma_mutex* pMutex) -{ - pthread_mutex_unlock((pthread_mutex_t*)pMutex); -} - - -static ma_result ma_event_init__posix(ma_event* pEvent) -{ - int result; - - result = pthread_mutex_init((pthread_mutex_t*)&pEvent->lock, NULL); - if (result != 0) { - return ma_result_from_errno(result); - } - - result = pthread_cond_init((pthread_cond_t*)&pEvent->cond, NULL); - if (result != 0) { - pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock); - return ma_result_from_errno(result); - } - - pEvent->value = 0; - return MA_SUCCESS; -} - -static void ma_event_uninit__posix(ma_event* pEvent) -{ - pthread_cond_destroy((pthread_cond_t*)&pEvent->cond); - pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock); -} - -static ma_result ma_event_wait__posix(ma_event* pEvent) -{ - pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock); - { - while (pEvent->value == 0) { - pthread_cond_wait((pthread_cond_t*)&pEvent->cond, (pthread_mutex_t*)&pEvent->lock); - } - pEvent->value = 0; /* Auto-reset. */ - } - pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock); - - return MA_SUCCESS; -} - -static ma_result ma_event_signal__posix(ma_event* pEvent) -{ - pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock); - { - pEvent->value = 1; - pthread_cond_signal((pthread_cond_t*)&pEvent->cond); - } - pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock); - - return MA_SUCCESS; -} - - -static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore) -{ - int result; - - if (pSemaphore == NULL) { - return MA_INVALID_ARGS; - } - - pSemaphore->value = initialValue; - - result = pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock, NULL); - if (result != 0) { - return ma_result_from_errno(result); /* Failed to create mutex. */ - } - - result = pthread_cond_init((pthread_cond_t*)&pSemaphore->cond, NULL); - if (result != 0) { - pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock); - return ma_result_from_errno(result); /* Failed to create condition variable. */ - } - - return MA_SUCCESS; -} - -static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore) -{ - if (pSemaphore == NULL) { - return; - } - - pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond); - pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock); -} - -static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore) -{ - if (pSemaphore == NULL) { - return MA_INVALID_ARGS; - } - - pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock); - { - /* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */ - while (pSemaphore->value == 0) { - pthread_cond_wait((pthread_cond_t*)&pSemaphore->cond, (pthread_mutex_t*)&pSemaphore->lock); - } - - pSemaphore->value -= 1; - } - pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock); - - return MA_SUCCESS; -} - -static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore) -{ - if (pSemaphore == NULL) { - return MA_INVALID_ARGS; - } - - pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock); - { - pSemaphore->value += 1; - pthread_cond_signal((pthread_cond_t*)&pSemaphore->cond); - } - pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock); - - return MA_SUCCESS; -} -#elif defined(MA_WIN32) +#ifdef MA_WIN32 static int ma_thread_priority_to_win32(ma_thread_priority priority) { switch (priority) { @@ -16451,9 +10261,7 @@ static int ma_thread_priority_to_win32(ma_thread_priority priority) static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData) { - DWORD threadID; /* Not used. Only used for passing into CreateThread() so it doesn't fail on Windows 98. */ - - *pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, &threadID); + *pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL); if (*pThread == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -16472,7 +10280,7 @@ static void ma_thread_wait__win32(ma_thread* pThread) static ma_result ma_mutex_init__win32(ma_mutex* pMutex) { - *pMutex = CreateEventA(NULL, FALSE, TRUE, NULL); + *pMutex = CreateEventW(NULL, FALSE, TRUE, NULL); if (*pMutex == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -16498,7 +10306,7 @@ static void ma_mutex_unlock__win32(ma_mutex* pMutex) static ma_result ma_event_init__win32(ma_event* pEvent) { - *pEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + *pEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if (*pEvent == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -16576,103 +10384,285 @@ static ma_result ma_semaphore_release__win32(ma_semaphore* pSemaphore) } #endif -typedef struct + +#ifdef MA_POSIX +static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData) { - ma_thread_entry_proc entryProc; - void* pData; - ma_allocation_callbacks allocationCallbacks; -} ma_thread_proxy_data; + int result; + pthread_attr_t* pAttr = NULL; -static ma_thread_result MA_THREADCALL ma_thread_entry_proxy(void* pData) -{ - ma_thread_proxy_data* pProxyData = (ma_thread_proxy_data*)pData; - ma_thread_entry_proc entryProc; - void* pEntryProcData; - ma_thread_result result; +#if !defined(__EMSCRIPTEN__) + /* Try setting the thread priority. It's not critical if anything fails here. */ + pthread_attr_t attr; + if (pthread_attr_init(&attr) == 0) { + int scheduler = -1; + if (priority == ma_thread_priority_idle) { +#ifdef SCHED_IDLE + if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) { + scheduler = SCHED_IDLE; + } +#endif + } else if (priority == ma_thread_priority_realtime) { +#ifdef SCHED_FIFO + if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) { + scheduler = SCHED_FIFO; + } +#endif +#ifdef MA_LINUX + } else { + scheduler = sched_getscheduler(0); +#endif + } - #if defined(MA_ON_THREAD_ENTRY) - MA_ON_THREAD_ENTRY - #endif + if (stackSize > 0) { + pthread_attr_setstacksize(&attr, stackSize); + } - entryProc = pProxyData->entryProc; - pEntryProcData = pProxyData->pData; + if (scheduler != -1) { + int priorityMin = sched_get_priority_min(scheduler); + int priorityMax = sched_get_priority_max(scheduler); + int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */ - /* Free the proxy data before getting into the real thread entry proc. */ - ma_free(pProxyData, &pProxyData->allocationCallbacks); + struct sched_param sched; + if (pthread_attr_getschedparam(&attr, &sched) == 0) { + if (priority == ma_thread_priority_idle) { + sched.sched_priority = priorityMin; + } else if (priority == ma_thread_priority_realtime) { + sched.sched_priority = priorityMax; + } else { + sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ + if (sched.sched_priority < priorityMin) { + sched.sched_priority = priorityMin; + } + if (sched.sched_priority > priorityMax) { + sched.sched_priority = priorityMax; + } + } - result = entryProc(pEntryProcData); - - #if defined(MA_ON_THREAD_EXIT) - MA_ON_THREAD_EXIT - #endif - - return result; -} - -static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_result result; - ma_thread_proxy_data* pProxyData; - - if (pThread == NULL || entryProc == NULL) { - return MA_INVALID_ARGS; - } - - pProxyData = (ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData), pAllocationCallbacks); /* Will be freed by the proxy entry proc. */ - if (pProxyData == NULL) { - return MA_OUT_OF_MEMORY; - } - -#if defined(MA_THREAD_DEFAULT_STACK_SIZE) - if (stackSize == 0) { - stackSize = MA_THREAD_DEFAULT_STACK_SIZE; + if (pthread_attr_setschedparam(&attr, &sched) == 0) { + pAttr = &attr; + } + } + } } +#else + /* It's the emscripten build. We'll have a few unused parameters. */ + (void)priority; + (void)stackSize; #endif - pProxyData->entryProc = entryProc; - pProxyData->pData = pData; - ma_allocation_callbacks_init_copy(&pProxyData->allocationCallbacks, pAllocationCallbacks); + result = pthread_create(pThread, pAttr, entryProc, pData); -#if defined(MA_POSIX) - result = ma_thread_create__posix(pThread, priority, stackSize, ma_thread_entry_proxy, pProxyData); -#elif defined(MA_WIN32) - result = ma_thread_create__win32(pThread, priority, stackSize, ma_thread_entry_proxy, pProxyData); -#endif + /* The thread attributes object is no longer required. */ + if (pAttr != NULL) { + pthread_attr_destroy(pAttr); + } - if (result != MA_SUCCESS) { - ma_free(pProxyData, pAllocationCallbacks); - return result; + if (result != 0) { + return ma_result_from_errno(result); } return MA_SUCCESS; } +static void ma_thread_wait__posix(ma_thread* pThread) +{ + pthread_join(*pThread, NULL); + pthread_detach(*pThread); +} + + +static ma_result ma_mutex_init__posix(ma_mutex* pMutex) +{ + int result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL); + if (result != 0) { + return ma_result_from_errno(result); + } + + return MA_SUCCESS; +} + +static void ma_mutex_uninit__posix(ma_mutex* pMutex) +{ + pthread_mutex_destroy((pthread_mutex_t*)pMutex); +} + +static void ma_mutex_lock__posix(ma_mutex* pMutex) +{ + pthread_mutex_lock((pthread_mutex_t*)pMutex); +} + +static void ma_mutex_unlock__posix(ma_mutex* pMutex) +{ + pthread_mutex_unlock((pthread_mutex_t*)pMutex); +} + + +static ma_result ma_event_init__posix(ma_event* pEvent) +{ + int result; + + result = pthread_mutex_init(&pEvent->lock, NULL); + if (result != 0) { + return ma_result_from_errno(result); + } + + result = pthread_cond_init(&pEvent->cond, NULL); + if (result != 0) { + pthread_mutex_destroy(&pEvent->lock); + return ma_result_from_errno(result); + } + + pEvent->value = 0; + return MA_SUCCESS; +} + +static void ma_event_uninit__posix(ma_event* pEvent) +{ + pthread_cond_destroy(&pEvent->cond); + pthread_mutex_destroy(&pEvent->lock); +} + +static ma_result ma_event_wait__posix(ma_event* pEvent) +{ + pthread_mutex_lock(&pEvent->lock); + { + while (pEvent->value == 0) { + pthread_cond_wait(&pEvent->cond, &pEvent->lock); + } + pEvent->value = 0; /* Auto-reset. */ + } + pthread_mutex_unlock(&pEvent->lock); + + return MA_SUCCESS; +} + +static ma_result ma_event_signal__posix(ma_event* pEvent) +{ + pthread_mutex_lock(&pEvent->lock); + { + pEvent->value = 1; + pthread_cond_signal(&pEvent->cond); + } + pthread_mutex_unlock(&pEvent->lock); + + return MA_SUCCESS; +} + + +static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore) +{ + int result; + + if (pSemaphore == NULL) { + return MA_INVALID_ARGS; + } + + pSemaphore->value = initialValue; + + result = pthread_mutex_init(&pSemaphore->lock, NULL); + if (result != 0) { + return ma_result_from_errno(result); /* Failed to create mutex. */ + } + + result = pthread_cond_init(&pSemaphore->cond, NULL); + if (result != 0) { + pthread_mutex_destroy(&pSemaphore->lock); + return ma_result_from_errno(result); /* Failed to create condition variable. */ + } + + return MA_SUCCESS; +} + +static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + return; + } + + pthread_cond_destroy(&pSemaphore->cond); + pthread_mutex_destroy(&pSemaphore->lock); +} + +static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + return MA_INVALID_ARGS; + } + + pthread_mutex_lock(&pSemaphore->lock); + { + /* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */ + while (pSemaphore->value == 0) { + pthread_cond_wait(&pSemaphore->cond, &pSemaphore->lock); + } + + pSemaphore->value -= 1; + } + pthread_mutex_unlock(&pSemaphore->lock); + + return MA_SUCCESS; +} + +static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + return MA_INVALID_ARGS; + } + + pthread_mutex_lock(&pSemaphore->lock); + { + pSemaphore->value += 1; + pthread_cond_signal(&pSemaphore->cond); + } + pthread_mutex_unlock(&pSemaphore->lock); + + return MA_SUCCESS; +} +#endif + +static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData) +{ + if (pThread == NULL || entryProc == NULL) { + return MA_FALSE; + } + +#ifdef MA_WIN32 + return ma_thread_create__win32(pThread, priority, stackSize, entryProc, pData); +#endif +#ifdef MA_POSIX + return ma_thread_create__posix(pThread, priority, stackSize, entryProc, pData); +#endif +} + static void ma_thread_wait(ma_thread* pThread) { if (pThread == NULL) { return; } -#if defined(MA_POSIX) - ma_thread_wait__posix(pThread); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 ma_thread_wait__win32(pThread); #endif +#ifdef MA_POSIX + ma_thread_wait__posix(pThread); +#endif } MA_API ma_result ma_mutex_init(ma_mutex* pMutex) { if (pMutex == NULL) { - MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */ return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_mutex_init__posix(pMutex); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_mutex_init__win32(pMutex); #endif +#ifdef MA_POSIX + return ma_mutex_init__posix(pMutex); +#endif } MA_API void ma_mutex_uninit(ma_mutex* pMutex) @@ -16681,54 +10671,58 @@ MA_API void ma_mutex_uninit(ma_mutex* pMutex) return; } -#if defined(MA_POSIX) - ma_mutex_uninit__posix(pMutex); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 ma_mutex_uninit__win32(pMutex); #endif +#ifdef MA_POSIX + ma_mutex_uninit__posix(pMutex); +#endif } MA_API void ma_mutex_lock(ma_mutex* pMutex) { if (pMutex == NULL) { - MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */ return; } -#if defined(MA_POSIX) - ma_mutex_lock__posix(pMutex); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 ma_mutex_lock__win32(pMutex); #endif +#ifdef MA_POSIX + ma_mutex_lock__posix(pMutex); +#endif } MA_API void ma_mutex_unlock(ma_mutex* pMutex) { if (pMutex == NULL) { - MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */ return; - } +} -#if defined(MA_POSIX) - ma_mutex_unlock__posix(pMutex); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 ma_mutex_unlock__win32(pMutex); #endif +#ifdef MA_POSIX + ma_mutex_unlock__posix(pMutex); +#endif } MA_API ma_result ma_event_init(ma_event* pEvent) { if (pEvent == NULL) { - MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */ return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_event_init__posix(pEvent); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_event_init__win32(pEvent); #endif +#ifdef MA_POSIX + return ma_event_init__posix(pEvent); +#endif } #if 0 @@ -16743,14 +10737,14 @@ static ma_result ma_event_alloc_and_init(ma_event** ppEvent, ma_allocation_callb *ppEvent = NULL; - pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks); + pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/); if (pEvent == NULL) { return MA_OUT_OF_MEMORY; } result = ma_event_init(pEvent); if (result != MA_SUCCESS) { - ma_free(pEvent, pAllocationCallbacks); + ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/); return result; } @@ -16765,11 +10759,12 @@ MA_API void ma_event_uninit(ma_event* pEvent) return; } -#if defined(MA_POSIX) - ma_event_uninit__posix(pEvent); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 ma_event_uninit__win32(pEvent); #endif +#ifdef MA_POSIX + ma_event_uninit__posix(pEvent); +#endif } #if 0 @@ -16780,7 +10775,7 @@ static void ma_event_uninit_and_free(ma_event* pEvent, ma_allocation_callbacks* } ma_event_uninit(pEvent); - ma_free(pEvent, pAllocationCallbacks); + ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/); } #endif @@ -16791,11 +10786,12 @@ MA_API ma_result ma_event_wait(ma_event* pEvent) return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_event_wait__posix(pEvent); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_event_wait__win32(pEvent); #endif +#ifdef MA_POSIX + return ma_event_wait__posix(pEvent); +#endif } MA_API ma_result ma_event_signal(ma_event* pEvent) @@ -16805,11 +10801,12 @@ MA_API ma_result ma_event_signal(ma_event* pEvent) return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_event_signal__posix(pEvent); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_event_signal__win32(pEvent); #endif +#ifdef MA_POSIX + return ma_event_signal__posix(pEvent); +#endif } @@ -16820,11 +10817,12 @@ MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore) return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_semaphore_init__posix(initialValue, pSemaphore); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_semaphore_init__win32(initialValue, pSemaphore); #endif +#ifdef MA_POSIX + return ma_semaphore_init__posix(initialValue, pSemaphore); +#endif } MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore) @@ -16834,11 +10832,12 @@ MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore) return; } -#if defined(MA_POSIX) - ma_semaphore_uninit__posix(pSemaphore); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 ma_semaphore_uninit__win32(pSemaphore); #endif +#ifdef MA_POSIX + ma_semaphore_uninit__posix(pSemaphore); +#endif } MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore) @@ -16848,11 +10847,12 @@ MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore) return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_semaphore_wait__posix(pSemaphore); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_semaphore_wait__win32(pSemaphore); #endif +#ifdef MA_POSIX + return ma_semaphore_wait__posix(pSemaphore); +#endif } MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore) @@ -16862,11 +10862,12 @@ MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore) return MA_INVALID_ARGS; } -#if defined(MA_POSIX) - return ma_semaphore_release__posix(pSemaphore); -#elif defined(MA_WIN32) +#ifdef MA_WIN32 return ma_semaphore_release__win32(pSemaphore); #endif +#ifdef MA_POSIX + return ma_semaphore_release__posix(pSemaphore); +#endif } #else /* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */ @@ -16877,1140 +10878,6 @@ MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore) -#define MA_FENCE_COUNTER_MAX 0x7FFFFFFF - -MA_API ma_result ma_fence_init(ma_fence* pFence) -{ - if (pFence == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pFence); - pFence->counter = 0; - - #ifndef MA_NO_THREADING - { - ma_result result; - - result = ma_event_init(&pFence->e); - if (result != MA_SUCCESS) { - return result; - } - } - #endif - - return MA_SUCCESS; -} - -MA_API void ma_fence_uninit(ma_fence* pFence) -{ - if (pFence == NULL) { - return; - } - - #ifndef MA_NO_THREADING - { - ma_event_uninit(&pFence->e); - } - #endif - - MA_ZERO_OBJECT(pFence); -} - -MA_API ma_result ma_fence_acquire(ma_fence* pFence) -{ - if (pFence == NULL) { - return MA_INVALID_ARGS; - } - - for (;;) { - ma_uint32 oldCounter = ma_atomic_load_32(&pFence->counter); - ma_uint32 newCounter = oldCounter + 1; - - /* Make sure we're not about to exceed our maximum value. */ - if (newCounter > MA_FENCE_COUNTER_MAX) { - MA_ASSERT(MA_FALSE); - return MA_OUT_OF_RANGE; - } - - if (ma_atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) { - return MA_SUCCESS; - } else { - if (oldCounter == MA_FENCE_COUNTER_MAX) { - MA_ASSERT(MA_FALSE); - return MA_OUT_OF_RANGE; /* The other thread took the last available slot. Abort. */ - } - } - } - - /* Should never get here. */ - /*return MA_SUCCESS;*/ -} - -MA_API ma_result ma_fence_release(ma_fence* pFence) -{ - if (pFence == NULL) { - return MA_INVALID_ARGS; - } - - for (;;) { - ma_uint32 oldCounter = ma_atomic_load_32(&pFence->counter); - ma_uint32 newCounter = oldCounter - 1; - - if (oldCounter == 0) { - MA_ASSERT(MA_FALSE); - return MA_INVALID_OPERATION; /* Acquire/release mismatch. */ - } - - if (ma_atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) { - #ifndef MA_NO_THREADING - { - if (newCounter == 0) { - ma_event_signal(&pFence->e); /* <-- ma_fence_wait() will be waiting on this. */ - } - } - #endif - - return MA_SUCCESS; - } else { - if (oldCounter == 0) { - MA_ASSERT(MA_FALSE); - return MA_INVALID_OPERATION; /* Another thread has taken the 0 slot. Acquire/release mismatch. */ - } - } - } - - /* Should never get here. */ - /*return MA_SUCCESS;*/ -} - -MA_API ma_result ma_fence_wait(ma_fence* pFence) -{ - if (pFence == NULL) { - return MA_INVALID_ARGS; - } - - for (;;) { - ma_uint32 counter; - - counter = ma_atomic_load_32(&pFence->counter); - if (counter == 0) { - /* - Counter has hit zero. By the time we get here some other thread may have acquired the - fence again, but that is where the caller needs to take care with how they se the fence. - */ - return MA_SUCCESS; - } - - /* Getting here means the counter is > 0. We'll need to wait for something to happen. */ - #ifndef MA_NO_THREADING - { - ma_result result; - - result = ma_event_wait(&pFence->e); - if (result != MA_SUCCESS) { - return result; - } - } - #endif - } - - /* Should never get here. */ - /*return MA_INVALID_OPERATION;*/ -} - - -MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification) -{ - ma_async_notification_callbacks* pNotificationCallbacks = (ma_async_notification_callbacks*)pNotification; - - if (pNotification == NULL) { - return MA_INVALID_ARGS; - } - - if (pNotificationCallbacks->onSignal == NULL) { - return MA_NOT_IMPLEMENTED; - } - - pNotificationCallbacks->onSignal(pNotification); - return MA_INVALID_ARGS; -} - - -static void ma_async_notification_poll__on_signal(ma_async_notification* pNotification) -{ - ((ma_async_notification_poll*)pNotification)->signalled = MA_TRUE; -} - -MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll) -{ - if (pNotificationPoll == NULL) { - return MA_INVALID_ARGS; - } - - pNotificationPoll->cb.onSignal = ma_async_notification_poll__on_signal; - pNotificationPoll->signalled = MA_FALSE; - - return MA_SUCCESS; -} - -MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll) -{ - if (pNotificationPoll == NULL) { - return MA_FALSE; - } - - return pNotificationPoll->signalled; -} - - -static void ma_async_notification_event__on_signal(ma_async_notification* pNotification) -{ - ma_async_notification_event_signal((ma_async_notification_event*)pNotification); -} - -MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent) -{ - if (pNotificationEvent == NULL) { - return MA_INVALID_ARGS; - } - - pNotificationEvent->cb.onSignal = ma_async_notification_event__on_signal; - - #ifndef MA_NO_THREADING - { - ma_result result; - - result = ma_event_init(&pNotificationEvent->e); - if (result != MA_SUCCESS) { - return result; - } - - return MA_SUCCESS; - } - #else - { - return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ - } - #endif -} - -MA_API ma_result ma_async_notification_event_uninit(ma_async_notification_event* pNotificationEvent) -{ - if (pNotificationEvent == NULL) { - return MA_INVALID_ARGS; - } - - #ifndef MA_NO_THREADING - { - ma_event_uninit(&pNotificationEvent->e); - return MA_SUCCESS; - } - #else - { - return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ - } - #endif -} - -MA_API ma_result ma_async_notification_event_wait(ma_async_notification_event* pNotificationEvent) -{ - if (pNotificationEvent == NULL) { - return MA_INVALID_ARGS; - } - - #ifndef MA_NO_THREADING - { - return ma_event_wait(&pNotificationEvent->e); - } - #else - { - return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ - } - #endif -} - -MA_API ma_result ma_async_notification_event_signal(ma_async_notification_event* pNotificationEvent) -{ - if (pNotificationEvent == NULL) { - return MA_INVALID_ARGS; - } - - #ifndef MA_NO_THREADING - { - return ma_event_signal(&pNotificationEvent->e); - } - #else - { - return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ - } - #endif -} - - - -/************************************************************************************************************************************************************ - -Job Queue - -************************************************************************************************************************************************************/ -MA_API ma_slot_allocator_config ma_slot_allocator_config_init(ma_uint32 capacity) -{ - ma_slot_allocator_config config; - - MA_ZERO_OBJECT(&config); - config.capacity = capacity; - - return config; -} - - -static MA_INLINE ma_uint32 ma_slot_allocator_calculate_group_capacity(ma_uint32 slotCapacity) -{ - ma_uint32 cap = slotCapacity / 32; - if ((slotCapacity % 32) != 0) { - cap += 1; - } - - return cap; -} - -static MA_INLINE ma_uint32 ma_slot_allocator_group_capacity(const ma_slot_allocator* pAllocator) -{ - return ma_slot_allocator_calculate_group_capacity(pAllocator->capacity); -} - - -typedef struct -{ - size_t sizeInBytes; - size_t groupsOffset; - size_t slotsOffset; -} ma_slot_allocator_heap_layout; - -static ma_result ma_slot_allocator_get_heap_layout(const ma_slot_allocator_config* pConfig, ma_slot_allocator_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->capacity == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Groups. */ - pHeapLayout->groupsOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(ma_slot_allocator_calculate_group_capacity(pConfig->capacity) * sizeof(ma_slot_allocator_group)); - - /* Slots. */ - pHeapLayout->slotsOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(pConfig->capacity * sizeof(ma_uint32)); - - return MA_SUCCESS; -} - -MA_API ma_result ma_slot_allocator_get_heap_size(const ma_slot_allocator_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_slot_allocator_heap_layout layout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_slot_allocator_get_heap_layout(pConfig, &layout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = layout.sizeInBytes; - - return result; -} - -MA_API ma_result ma_slot_allocator_init_preallocated(const ma_slot_allocator_config* pConfig, void* pHeap, ma_slot_allocator* pAllocator) -{ - ma_result result; - ma_slot_allocator_heap_layout heapLayout; - - if (pAllocator == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pAllocator); - - if (pHeap == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_slot_allocator_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pAllocator->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pAllocator->pGroups = (ma_slot_allocator_group*)ma_offset_ptr(pHeap, heapLayout.groupsOffset); - pAllocator->pSlots = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.slotsOffset); - pAllocator->capacity = pConfig->capacity; - - return MA_SUCCESS; -} - -MA_API ma_result ma_slot_allocator_init(const ma_slot_allocator_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_slot_allocator* pAllocator) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_slot_allocator_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the size of the heap allocation. */ - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_slot_allocator_init_preallocated(pConfig, pHeap, pAllocator); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pAllocator->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_slot_allocator_uninit(ma_slot_allocator* pAllocator, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocator == NULL) { - return; - } - - if (pAllocator->_ownsHeap) { - ma_free(pAllocator->_pHeap, pAllocationCallbacks); - } -} - -MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint64* pSlot) -{ - ma_uint32 iAttempt; - const ma_uint32 maxAttempts = 2; /* The number of iterations to perform until returning MA_OUT_OF_MEMORY if no slots can be found. */ - - if (pAllocator == NULL || pSlot == NULL) { - return MA_INVALID_ARGS; - } - - for (iAttempt = 0; iAttempt < maxAttempts; iAttempt += 1) { - /* We need to acquire a suitable bitfield first. This is a bitfield that's got an available slot within it. */ - ma_uint32 iGroup; - for (iGroup = 0; iGroup < ma_slot_allocator_group_capacity(pAllocator); iGroup += 1) { - /* CAS */ - for (;;) { - ma_uint32 oldBitfield; - ma_uint32 newBitfield; - ma_uint32 bitOffset; - - oldBitfield = ma_atomic_load_32(&pAllocator->pGroups[iGroup].bitfield); /* <-- This copy must happen. The compiler must not optimize this away. */ - - /* Fast check to see if anything is available. */ - if (oldBitfield == 0xFFFFFFFF) { - break; /* No available bits in this bitfield. */ - } - - bitOffset = ma_ffs_32(~oldBitfield); - MA_ASSERT(bitOffset < 32); - - newBitfield = oldBitfield | (1 << bitOffset); - - if (ma_atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) { - ma_uint32 slotIndex; - - /* Increment the counter as soon as possible to have other threads report out-of-memory sooner than later. */ - ma_atomic_fetch_add_32(&pAllocator->count, 1); - - /* The slot index is required for constructing the output value. */ - slotIndex = (iGroup << 5) + bitOffset; /* iGroup << 5 = iGroup * 32 */ - if (slotIndex >= pAllocator->capacity) { - return MA_OUT_OF_MEMORY; - } - - /* Increment the reference count before constructing the output value. */ - pAllocator->pSlots[slotIndex] += 1; - - /* Construct the output value. */ - *pSlot = (((ma_uint64)pAllocator->pSlots[slotIndex] << 32) | slotIndex); - - return MA_SUCCESS; - } - } - } - - /* We weren't able to find a slot. If it's because we've reached our capacity we need to return MA_OUT_OF_MEMORY. Otherwise we need to do another iteration and try again. */ - if (pAllocator->count < pAllocator->capacity) { - ma_yield(); - } else { - return MA_OUT_OF_MEMORY; - } - } - - /* We couldn't find a slot within the maximum number of attempts. */ - return MA_OUT_OF_MEMORY; -} - -MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot) -{ - ma_uint32 iGroup; - ma_uint32 iBit; - - if (pAllocator == NULL) { - return MA_INVALID_ARGS; - } - - iGroup = (ma_uint32)((slot & 0xFFFFFFFF) >> 5); /* slot / 32 */ - iBit = (ma_uint32)((slot & 0xFFFFFFFF) & 31); /* slot % 32 */ - - if (iGroup >= ma_slot_allocator_group_capacity(pAllocator)) { - return MA_INVALID_ARGS; - } - - MA_ASSERT(iBit < 32); /* This must be true due to the logic we used to actually calculate it. */ - - while (ma_atomic_load_32(&pAllocator->count) > 0) { - /* CAS */ - ma_uint32 oldBitfield; - ma_uint32 newBitfield; - - oldBitfield = ma_atomic_load_32(&pAllocator->pGroups[iGroup].bitfield); /* <-- This copy must happen. The compiler must not optimize this away. */ - newBitfield = oldBitfield & ~(1 << iBit); - - /* Debugging for checking for double-frees. */ - #if defined(MA_DEBUG_OUTPUT) - { - if ((oldBitfield & (1 << iBit)) == 0) { - MA_ASSERT(MA_FALSE); /* Double free detected.*/ - } - } - #endif - - if (ma_atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) { - ma_atomic_fetch_sub_32(&pAllocator->count, 1); - return MA_SUCCESS; - } - } - - /* Getting here means there are no allocations available for freeing. */ - return MA_INVALID_OPERATION; -} - - -#define MA_JOB_ID_NONE ~((ma_uint64)0) -#define MA_JOB_SLOT_NONE (ma_uint16)(~0) - -static MA_INLINE ma_uint32 ma_job_extract_refcount(ma_uint64 toc) -{ - return (ma_uint32)(toc >> 32); -} - -static MA_INLINE ma_uint16 ma_job_extract_slot(ma_uint64 toc) -{ - return (ma_uint16)(toc & 0x0000FFFF); -} - -static MA_INLINE ma_uint16 ma_job_extract_code(ma_uint64 toc) -{ - return (ma_uint16)((toc & 0xFFFF0000) >> 16); -} - -static MA_INLINE ma_uint64 ma_job_toc_to_allocation(ma_uint64 toc) -{ - return ((ma_uint64)ma_job_extract_refcount(toc) << 32) | (ma_uint64)ma_job_extract_slot(toc); -} - -static MA_INLINE ma_uint64 ma_job_set_refcount(ma_uint64 toc, ma_uint32 refcount) -{ - /* Clear the reference count first. */ - toc = toc & ~((ma_uint64)0xFFFFFFFF << 32); - toc = toc | ((ma_uint64)refcount << 32); - - return toc; -} - - -MA_API ma_job ma_job_init(ma_uint16 code) -{ - ma_job job; - - MA_ZERO_OBJECT(&job); - job.toc.breakup.code = code; - job.toc.breakup.slot = MA_JOB_SLOT_NONE; /* Temp value. Will be allocated when posted to a queue. */ - job.next = MA_JOB_ID_NONE; - - return job; -} - - -static ma_result ma_job_process__noop(ma_job* pJob); -static ma_result ma_job_process__quit(ma_job* pJob); -static ma_result ma_job_process__custom(ma_job* pJob); -static ma_result ma_job_process__resource_manager__load_data_buffer_node(ma_job* pJob); -static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* pJob); -static ma_result ma_job_process__resource_manager__page_data_buffer_node(ma_job* pJob); -static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob); -static ma_result ma_job_process__resource_manager__free_data_buffer(ma_job* pJob); -static ma_result ma_job_process__resource_manager__load_data_stream(ma_job* pJob); -static ma_result ma_job_process__resource_manager__free_data_stream(ma_job* pJob); -static ma_result ma_job_process__resource_manager__page_data_stream(ma_job* pJob); -static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob); - -#if !defined(MA_NO_DEVICE_IO) -static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob); -#endif - -static ma_job_proc g_jobVTable[MA_JOB_TYPE_COUNT] = -{ - /* Miscellaneous. */ - ma_job_process__quit, /* MA_JOB_TYPE_QUIT */ - ma_job_process__custom, /* MA_JOB_TYPE_CUSTOM */ - - /* Resource Manager. */ - ma_job_process__resource_manager__load_data_buffer_node, /* MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE */ - ma_job_process__resource_manager__free_data_buffer_node, /* MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE */ - ma_job_process__resource_manager__page_data_buffer_node, /* MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE */ - ma_job_process__resource_manager__load_data_buffer, /* MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER */ - ma_job_process__resource_manager__free_data_buffer, /* MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER */ - ma_job_process__resource_manager__load_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM */ - ma_job_process__resource_manager__free_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM */ - ma_job_process__resource_manager__page_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM */ - ma_job_process__resource_manager__seek_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM */ - - /* Device. */ -#if !defined(MA_NO_DEVICE_IO) - ma_job_process__device__aaudio_reroute /* MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE */ -#endif -}; - -MA_API ma_result ma_job_process(ma_job* pJob) -{ - if (pJob == NULL) { - return MA_INVALID_ARGS; - } - - if (pJob->toc.breakup.code >= MA_JOB_TYPE_COUNT) { - return MA_INVALID_OPERATION; - } - - return g_jobVTable[pJob->toc.breakup.code](pJob); -} - -static ma_result ma_job_process__noop(ma_job* pJob) -{ - MA_ASSERT(pJob != NULL); - - /* No-op. */ - (void)pJob; - - return MA_SUCCESS; -} - -static ma_result ma_job_process__quit(ma_job* pJob) -{ - return ma_job_process__noop(pJob); -} - -static ma_result ma_job_process__custom(ma_job* pJob) -{ - MA_ASSERT(pJob != NULL); - - /* No-op if there's no callback. */ - if (pJob->data.custom.proc == NULL) { - return MA_SUCCESS; - } - - return pJob->data.custom.proc(pJob); -} - - - -MA_API ma_job_queue_config ma_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity) -{ - ma_job_queue_config config; - - config.flags = flags; - config.capacity = capacity; - - return config; -} - - -typedef struct -{ - size_t sizeInBytes; - size_t allocatorOffset; - size_t jobsOffset; -} ma_job_queue_heap_layout; - -static ma_result ma_job_queue_get_heap_layout(const ma_job_queue_config* pConfig, ma_job_queue_heap_layout* pHeapLayout) -{ - ma_result result; - - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->capacity == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Allocator. */ - { - ma_slot_allocator_config allocatorConfig; - size_t allocatorHeapSizeInBytes; - - allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity); - result = ma_slot_allocator_get_heap_size(&allocatorConfig, &allocatorHeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->allocatorOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += allocatorHeapSizeInBytes; - } - - /* Jobs. */ - pHeapLayout->jobsOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(pConfig->capacity * sizeof(ma_job)); - - return MA_SUCCESS; -} - -MA_API ma_result ma_job_queue_get_heap_size(const ma_job_queue_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_job_queue_heap_layout layout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_job_queue_get_heap_layout(pConfig, &layout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = layout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_job_queue_init_preallocated(const ma_job_queue_config* pConfig, void* pHeap, ma_job_queue* pQueue) -{ - ma_result result; - ma_job_queue_heap_layout heapLayout; - ma_slot_allocator_config allocatorConfig; - - if (pQueue == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pQueue); - - result = ma_job_queue_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pQueue->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pQueue->flags = pConfig->flags; - pQueue->capacity = pConfig->capacity; - pQueue->pJobs = (ma_job*)ma_offset_ptr(pHeap, heapLayout.jobsOffset); - - allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity); - result = ma_slot_allocator_init_preallocated(&allocatorConfig, ma_offset_ptr(pHeap, heapLayout.allocatorOffset), &pQueue->allocator); - if (result != MA_SUCCESS) { - return result; - } - - /* We need a semaphore if we're running in non-blocking mode. If threading is disabled we need to return an error. */ - if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { - #ifndef MA_NO_THREADING - { - ma_semaphore_init(0, &pQueue->sem); - } - #else - { - /* Threading is disabled and we've requested non-blocking mode. */ - return MA_INVALID_OPERATION; - } - #endif - } - - /* - Our queue needs to be initialized with a free standing node. This should always be slot 0. Required for the lock free algorithm. The first job in the queue is - just a dummy item for giving us the first item in the list which is stored in the "next" member. - */ - ma_slot_allocator_alloc(&pQueue->allocator, &pQueue->head); /* Will never fail. */ - pQueue->pJobs[ma_job_extract_slot(pQueue->head)].next = MA_JOB_ID_NONE; - pQueue->tail = pQueue->head; - - return MA_SUCCESS; -} - -MA_API ma_result ma_job_queue_init(const ma_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_job_queue* pQueue) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_job_queue_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_job_queue_init_preallocated(pConfig, pHeap, pQueue); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pQueue->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_job_queue_uninit(ma_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pQueue == NULL) { - return; - } - - /* All we need to do is uninitialize the semaphore. */ - if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { - #ifndef MA_NO_THREADING - { - ma_semaphore_uninit(&pQueue->sem); - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */ - } - #endif - } - - ma_slot_allocator_uninit(&pQueue->allocator, pAllocationCallbacks); - - if (pQueue->_ownsHeap) { - ma_free(pQueue->_pHeap, pAllocationCallbacks); - } -} - -static ma_bool32 ma_job_queue_cas(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) -{ - /* The new counter is taken from the expected value. */ - return ma_atomic_compare_and_swap_64(dst, expected, ma_job_set_refcount(desired, ma_job_extract_refcount(expected) + 1)) == expected; -} - -MA_API ma_result ma_job_queue_post(ma_job_queue* pQueue, const ma_job* pJob) -{ - /* - Lock free queue implementation based on the paper by Michael and Scott: Nonblocking Algorithms and Preemption-Safe Locking on Multiprogrammed Shared Memory Multiprocessors - */ - ma_result result; - ma_uint64 slot; - ma_uint64 tail; - ma_uint64 next; - - if (pQueue == NULL || pJob == NULL) { - return MA_INVALID_ARGS; - } - - /* We need a new slot. */ - result = ma_slot_allocator_alloc(&pQueue->allocator, &slot); - if (result != MA_SUCCESS) { - return result; /* Probably ran out of slots. If so, MA_OUT_OF_MEMORY will be returned. */ - } - - /* At this point we should have a slot to place the job. */ - MA_ASSERT(ma_job_extract_slot(slot) < pQueue->capacity); - - /* We need to put the job into memory before we do anything. */ - pQueue->pJobs[ma_job_extract_slot(slot)] = *pJob; - pQueue->pJobs[ma_job_extract_slot(slot)].toc.allocation = slot; /* This will overwrite the job code. */ - pQueue->pJobs[ma_job_extract_slot(slot)].toc.breakup.code = pJob->toc.breakup.code; /* The job code needs to be applied again because the line above overwrote it. */ - pQueue->pJobs[ma_job_extract_slot(slot)].next = MA_JOB_ID_NONE; /* Reset for safety. */ - - #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE - ma_spinlock_lock(&pQueue->lock); - #endif - { - /* The job is stored in memory so now we need to add it to our linked list. We only ever add items to the end of the list. */ - for (;;) { - tail = ma_atomic_load_64(&pQueue->tail); - next = ma_atomic_load_64(&pQueue->pJobs[ma_job_extract_slot(tail)].next); - - if (ma_job_toc_to_allocation(tail) == ma_job_toc_to_allocation(ma_atomic_load_64(&pQueue->tail))) { - if (ma_job_extract_slot(next) == 0xFFFF) { - if (ma_job_queue_cas(&pQueue->pJobs[ma_job_extract_slot(tail)].next, next, slot)) { - break; - } - } else { - ma_job_queue_cas(&pQueue->tail, tail, ma_job_extract_slot(next)); - } - } - } - ma_job_queue_cas(&pQueue->tail, tail, slot); - } - #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE - ma_spinlock_unlock(&pQueue->lock); - #endif - - - /* Signal the semaphore as the last step if we're using synchronous mode. */ - if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { - #ifndef MA_NO_THREADING - { - ma_semaphore_release(&pQueue->sem); - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */ - } - #endif - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) -{ - ma_uint64 head; - ma_uint64 tail; - ma_uint64 next; - - if (pQueue == NULL || pJob == NULL) { - return MA_INVALID_ARGS; - } - - /* If we're running in synchronous mode we'll need to wait on a semaphore. */ - if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { - #ifndef MA_NO_THREADING - { - ma_semaphore_wait(&pQueue->sem); - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */ - } - #endif - } - - #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE - ma_spinlock_lock(&pQueue->lock); - #endif - { - /* - BUG: In lock-free mode, multiple threads can be in this section of code. The "head" variable in the loop below - is stored. One thread can fall through to the freeing of this item while another is still using "head" for the - retrieval of the "next" variable. - - The slot allocator might need to make use of some reference counting to ensure it's only truly freed when - there are no more references to the item. This must be fixed before removing these locks. - */ - - /* Now we need to remove the root item from the list. */ - for (;;) { - head = ma_atomic_load_64(&pQueue->head); - tail = ma_atomic_load_64(&pQueue->tail); - next = ma_atomic_load_64(&pQueue->pJobs[ma_job_extract_slot(head)].next); - - if (ma_job_toc_to_allocation(head) == ma_job_toc_to_allocation(ma_atomic_load_64(&pQueue->head))) { - if (ma_job_extract_slot(head) == ma_job_extract_slot(tail)) { - if (ma_job_extract_slot(next) == 0xFFFF) { - #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE - ma_spinlock_unlock(&pQueue->lock); - #endif - return MA_NO_DATA_AVAILABLE; - } - ma_job_queue_cas(&pQueue->tail, tail, ma_job_extract_slot(next)); - } else { - *pJob = pQueue->pJobs[ma_job_extract_slot(next)]; - if (ma_job_queue_cas(&pQueue->head, head, ma_job_extract_slot(next))) { - break; - } - } - } - } - } - #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE - ma_spinlock_unlock(&pQueue->lock); - #endif - - ma_slot_allocator_free(&pQueue->allocator, head); - - /* - If it's a quit job make sure it's put back on the queue to ensure other threads have an opportunity to detect it and terminate naturally. We - could instead just leave it on the queue, but that would involve fiddling with the lock-free code above and I want to keep that as simple as - possible. - */ - if (pJob->toc.breakup.code == MA_JOB_TYPE_QUIT) { - ma_job_queue_post(pQueue, pJob); - return MA_CANCELLED; /* Return a cancelled status just in case the thread is checking return codes and not properly checking for a quit job. */ - } - - return MA_SUCCESS; -} - - - -/******************************************************************************* - -Dynamic Linking - -*******************************************************************************/ -#ifdef MA_POSIX - /* No need for dlfcn.h if we're not using runtime linking. */ - #ifndef MA_NO_RUNTIME_LINKING - #include - #endif -#endif - -MA_API ma_handle ma_dlopen(ma_log* pLog, const char* filename) -{ -#ifndef MA_NO_RUNTIME_LINKING - ma_handle handle; - - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); - - #ifdef MA_WIN32 - /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ - #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) - handle = (ma_handle)LoadLibraryA(filename); - #else - /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ - WCHAR filenameW[4096]; - if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { - handle = NULL; - } else { - handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); - } - #endif - #else - handle = (ma_handle)dlopen(filename, RTLD_NOW); - #endif - - /* - I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority - backend is a deliberate design choice. Instead I'm logging it as an informational message. - */ - if (handle == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); - } - - return handle; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)filename; - return NULL; -#endif -} - -MA_API void ma_dlclose(ma_log* pLog, ma_handle handle) -{ -#ifndef MA_NO_RUNTIME_LINKING - #ifdef MA_WIN32 - FreeLibrary((HMODULE)handle); - #else - /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ - #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) - { - dlclose((void*)handle); - } - #else - { - (void)handle; - } - #endif - #endif - - (void)pLog; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; -#endif -} - -MA_API ma_proc ma_dlsym(ma_log* pLog, ma_handle handle, const char* symbol) -{ -#ifndef MA_NO_RUNTIME_LINKING - ma_proc proc; - - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); - -#ifdef _WIN32 - proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); -#else -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" -#endif - proc = (ma_proc)dlsym((void*)handle, symbol); -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic pop -#endif -#endif - - if (proc == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); - } - - (void)pLog; /* It's possible for pContext to be unused. */ - return proc; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; - (void)symbol; - return NULL; -#endif -} - - - /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -18019,37 +10886,37 @@ DEVICE I/O ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ - -/* Disable run-time linking on certain backends and platforms. */ -#ifndef MA_NO_RUNTIME_LINKING - #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) - #define MA_NO_RUNTIME_LINKING - #endif -#endif - -#ifdef MA_APPLE - #include -#endif - #ifndef MA_NO_DEVICE_IO +#ifdef MA_WIN32 + #include + #include + #include +#endif -#if defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) +#if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) #include /* For mach_absolute_time() */ #endif #ifdef MA_POSIX #include #include - - /* No need for dlfcn.h if we're not using runtime linking. */ - #ifndef MA_NO_RUNTIME_LINKING - #include - #endif + #include #endif -/* This must be set to at least 26. */ -#ifndef MA_AAUDIO_MIN_ANDROID_SDK_VERSION -#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 27 +/* +Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When +using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing +compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply +disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am +not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere. +*/ +/*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/ + +/* Disable run-time linking on certain backends. */ +#ifndef MA_NO_RUNTIME_LINKING + #if defined(MA_EMSCRIPTEN) + #define MA_NO_RUNTIME_LINKING + #endif #endif @@ -18069,60 +10936,27 @@ MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, m } -typedef struct -{ - ma_backend backend; - const char* pName; -} ma_backend_info; - -static ma_backend_info gBackendInfo[] = /* Indexed by the backend enum. Must be in the order backends are declared in the ma_backend enum. */ -{ - {ma_backend_wasapi, "WASAPI"}, - {ma_backend_dsound, "DirectSound"}, - {ma_backend_winmm, "WinMM"}, - {ma_backend_coreaudio, "Core Audio"}, - {ma_backend_sndio, "sndio"}, - {ma_backend_audio4, "audio(4)"}, - {ma_backend_oss, "OSS"}, - {ma_backend_pulseaudio, "PulseAudio"}, - {ma_backend_alsa, "ALSA"}, - {ma_backend_jack, "JACK"}, - {ma_backend_aaudio, "AAudio"}, - {ma_backend_opensl, "OpenSL|ES"}, - {ma_backend_webaudio, "Web Audio"}, - {ma_backend_custom, "Custom"}, - {ma_backend_null, "Null"} -}; - MA_API const char* ma_get_backend_name(ma_backend backend) { - if (backend < 0 || backend >= (int)ma_countof(gBackendInfo)) { - return "Unknown"; + switch (backend) + { + case ma_backend_wasapi: return "WASAPI"; + case ma_backend_dsound: return "DirectSound"; + case ma_backend_winmm: return "WinMM"; + case ma_backend_coreaudio: return "Core Audio"; + case ma_backend_sndio: return "sndio"; + case ma_backend_audio4: return "audio(4)"; + case ma_backend_oss: return "OSS"; + case ma_backend_pulseaudio: return "PulseAudio"; + case ma_backend_alsa: return "ALSA"; + case ma_backend_jack: return "JACK"; + case ma_backend_aaudio: return "AAudio"; + case ma_backend_opensl: return "OpenSL|ES"; + case ma_backend_webaudio: return "Web Audio"; + case ma_backend_custom: return "Custom"; + case ma_backend_null: return "Null"; + default: return "Unknown"; } - - return gBackendInfo[backend].pName; -} - -MA_API ma_result ma_get_backend_from_name(const char* pBackendName, ma_backend* pBackend) -{ - size_t iBackend; - - if (pBackendName == NULL) { - return MA_INVALID_ARGS; - } - - for (iBackend = 0; iBackend < ma_countof(gBackendInfo); iBackend += 1) { - if (ma_strcmp(pBackendName, gBackendInfo[iBackend].pName) == 0) { - if (pBackend != NULL) { - *pBackend = gBackendInfo[iBackend].backend; - } - - return MA_SUCCESS; - } - } - - /* Getting here means the backend name is unknown. */ - return MA_INVALID_ARGS; } MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) @@ -18195,25 +11029,13 @@ MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) #endif case ma_backend_aaudio: #if defined(MA_HAS_AAUDIO) - #if defined(MA_ANDROID) - { - return ma_android_sdk_version() >= MA_AAUDIO_MIN_ANDROID_SDK_VERSION; - } - #else - return MA_FALSE; - #endif + return MA_TRUE; #else return MA_FALSE; #endif case ma_backend_opensl: #if defined(MA_HAS_OPENSL) - #if defined(MA_ANDROID) - { - return ma_android_sdk_version() >= 9; - } - #else - return MA_TRUE; - #endif + return MA_TRUE; #else return MA_FALSE; #endif @@ -18299,7 +11121,7 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend) -#if defined(MA_WIN32) +#ifdef MA_WIN32 /* WASAPI error codes. */ #define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001) #define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002) @@ -18459,115 +11281,203 @@ static ma_result ma_result_from_HRESULT(HRESULT hr) } } -/* PROPVARIANT */ -#define MA_VT_LPWSTR 31 -#define MA_VT_BLOB 65 - -#if defined(_MSC_VER) && !defined(__clang__) - #pragma warning(push) - #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */ - #if defined(__clang__) - #pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */ - #endif -#endif -typedef struct -{ - WORD vt; - WORD wReserved1; - WORD wReserved2; - WORD wReserved3; - union - { - struct - { - ULONG cbSize; - BYTE* pBlobData; - } blob; - WCHAR* pwszVal; - char pad[16]; /* Just to ensure the size of the struct matches the official version. */ - }; -} MA_PROPVARIANT; -#if defined(_MSC_VER) && !defined(__clang__) - #pragma warning(pop) -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) - #pragma GCC diagnostic pop -#endif - -typedef HRESULT (WINAPI * MA_PFN_CoInitialize)(void* pvReserved); -typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(void* pvReserved, DWORD dwCoInit); +typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); typedef void (WINAPI * MA_PFN_CoUninitialize)(void); -typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(const IID* rclsid, void* pUnkOuter, DWORD dwClsContext, const IID* riid, void* ppv); -typedef void (WINAPI * MA_PFN_CoTaskMemFree)(void* pv); -typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(MA_PROPVARIANT *pvar); -typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, WCHAR* lpsz, int cchMax); +typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); +typedef void (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv); +typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar); +typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax); -typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void); -typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void); +typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void); +typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void); -#if defined(MA_WIN32_DESKTOP) /* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */ -typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, const char* lpSubKey, DWORD ulOptions, DWORD samDesired, HKEY* phkResult); -typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); -typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, const char* lpValueName, DWORD* lpReserved, DWORD* lpType, BYTE* lpData, DWORD* lpcbData); -#endif /* MA_WIN32_DESKTOP */ - -MA_API size_t ma_strlen_WCHAR(const WCHAR* str) -{ - size_t len = 0; - while (str[len] != '\0') { - len += 1; - } - - return len; -} - -MA_API int ma_strcmp_WCHAR(const WCHAR *s1, const WCHAR *s2) -{ - while (*s1 != '\0' && *s1 == *s2) { - s1 += 1; - s2 += 1; - } - - return *s1 - *s2; -} - -MA_API int ma_strcpy_s_WCHAR(WCHAR* dst, size_t dstCap, const WCHAR* src) -{ - size_t i; - - if (dst == 0) { - return 22; - } - if (dstCap == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - for (i = 0; i < dstCap && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstCap) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return 34; -} -#endif /* MA_WIN32 */ +typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); +typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); +typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); +#endif #define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device" #define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device" +MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) +{ + switch (logLevel) + { + case MA_LOG_LEVEL_VERBOSE: return ""; + case MA_LOG_LEVEL_INFO: return "INFO"; + case MA_LOG_LEVEL_WARNING: return "WARNING"; + case MA_LOG_LEVEL_ERROR: return "ERROR"; + default: return "ERROR"; + } +} + +/* Posts a log message. */ +static void ma_post_log_message(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) +{ + if (pContext == NULL) { + if (pDevice != NULL) { + pContext = pDevice->pContext; + } + } + + /* All logs must be output when debug output is enabled. */ +#if defined(MA_DEBUG_OUTPUT) + printf("%s: %s\n", ma_log_level_to_string(logLevel), message); +#endif + + if (pContext == NULL) { + return; + } + +#if defined(MA_LOG_LEVEL) + if (logLevel <= MA_LOG_LEVEL) { + ma_log_proc onLog; + + onLog = pContext->logCallback; + if (onLog) { + onLog(pContext, pDevice, logLevel, message); + } + } +#endif +} + +/* +We need to emulate _vscprintf() for the VC6 build. This can be more efficient, but since it's only VC6, and it's just a +logging function, I'm happy to keep this simple. In the VC6 build we can implement this in terms of _vsnprintf(). +*/ +#if defined(_MSC_VER) && _MSC_VER < 1900 +int ma_vscprintf(const char* format, va_list args) +{ +#if _MSC_VER > 1200 + return _vscprintf(format, args); +#else + int result; + char* pTempBuffer = NULL; + size_t tempBufferCap = 1024; + + if (format == NULL) { + errno = EINVAL; + return -1; + } + + for (;;) { + char* pNewTempBuffer = (char*)ma_realloc(pTempBuffer, tempBufferCap, NULL); /* TODO: Add support for custom memory allocators? */ + if (pNewTempBuffer == NULL) { + ma_free(pTempBuffer, NULL); + errno = ENOMEM; + return -1; /* Out of memory. */ + } + + pTempBuffer = pNewTempBuffer; + + result = _vsnprintf(pTempBuffer, tempBufferCap, format, args); + ma_free(pTempBuffer, NULL); + + if (result != -1) { + break; /* Got it. */ + } + + /* Buffer wasn't big enough. Ideally it'd be nice to use an error code to know the reason for sure, but this is reliable enough. */ + tempBufferCap *= 2; + } + + return result; +#endif +} +#endif + +/* Posts a formatted log message. */ +static void ma_post_log_messagev(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, va_list args) +{ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + { + char pFormattedMessage[1024]; + vsnprintf(pFormattedMessage, sizeof(pFormattedMessage), pFormat, args); + ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage); + } +#else + { + /* + Without snprintf() we need to first measure the string and then heap allocate it. I'm only aware of Visual Studio having support for this without snprintf(), so we'll + need to restrict this branch to Visual Studio. For other compilers we need to just not support formatted logging because I don't want the security risk of overflowing + a fixed sized stack allocated buffer. + */ + #if defined(_MSC_VER) && _MSC_VER >= 1200 /* 1200 = VC6 */ + int formattedLen; + va_list args2; + + #if _MSC_VER >= 1800 + va_copy(args2, args); + #else + args2 = args; + #endif + formattedLen = ma_vscprintf(pFormat, args2); + va_end(args2); + + if (formattedLen > 0) { + char* pFormattedMessage = NULL; + ma_allocation_callbacks* pAllocationCallbacks = NULL; + + /* Make sure we have a context so we can allocate memory. */ + if (pContext == NULL) { + if (pDevice != NULL) { + pContext = pDevice->pContext; + } + } + + if (pContext != NULL) { + pAllocationCallbacks = &pContext->allocationCallbacks; + } + + pFormattedMessage = (char*)ma_malloc(formattedLen + 1, pAllocationCallbacks); + if (pFormattedMessage != NULL) { + /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ + #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ + vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args); + #else + vsprintf(pFormattedMessage, pFormat, args); + #endif + + ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage); + ma_free(pFormattedMessage, pAllocationCallbacks); + } + } + #else + /* Can't do anything because we don't have a safe way of to emulate vsnprintf() without a manual solution. */ + (void)pContext; + (void)pDevice; + (void)logLevel; + (void)pFormat; + (void)args; + #endif + } +#endif +} + +MA_API void ma_post_log_messagef(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, ...) +{ + va_list args; + va_start(args, pFormat); + { + ma_post_log_messagev(pContext, pDevice, logLevel, pFormat, args); + } + va_end(args); +} + +/* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */ +static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) +{ + ma_post_log_message(pContext, pDevice, logLevel, message); + return resultCode; +} + +static ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) +{ + return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode); +} /******************************************************************************* @@ -18575,7 +11485,7 @@ MA_API int ma_strcpy_s_WCHAR(WCHAR* dst, size_t dstCap, const WCHAR* src) Timing *******************************************************************************/ -#if defined(MA_WIN32) && !defined(MA_POSIX) +#ifdef MA_WIN32 static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ static void ma_timer_init(ma_timer* pTimer) { @@ -18598,7 +11508,7 @@ Timing return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart; } -#elif defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) +#elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) static ma_uint64 g_ma_TimerFrequency = 0; static void ma_timer_init(ma_timer* pTimer) { @@ -18627,7 +11537,7 @@ Timing return (emscripten_get_now() - pTimer->counterD) / 1000; /* Emscripten is in milliseconds. */ } #else - #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L + #if _POSIX_C_SOURCE >= 199309L #if defined(CLOCK_MONOTONIC) #define MA_CLOCK_ID CLOCK_MONOTONIC #else @@ -18681,6 +11591,103 @@ Timing #endif +/******************************************************************************* + +Dynamic Linking + +*******************************************************************************/ +MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename) +{ + ma_handle handle; + +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE + if (pContext != NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Loading library: ", filename); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message); + } +#endif + +#ifdef _WIN32 +#ifdef MA_WIN32_DESKTOP + handle = (ma_handle)LoadLibraryA(filename); +#else + /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ + WCHAR filenameW[4096]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { + handle = NULL; + } else { + handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); + } +#endif +#else + handle = (ma_handle)dlopen(filename, RTLD_NOW); +#endif + + /* + I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority + backend is a deliberate design choice. Instead I'm logging it as an informational message. + */ +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_INFO + if (handle == NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Failed to load library: ", filename); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, message); + } +#endif + + (void)pContext; /* It's possible for pContext to be unused. */ + return handle; +} + +MA_API void ma_dlclose(ma_context* pContext, ma_handle handle) +{ +#ifdef _WIN32 + FreeLibrary((HMODULE)handle); +#else + dlclose((void*)handle); +#endif + + (void)pContext; +} + +MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol) +{ + ma_proc proc; + +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE + if (pContext != NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Loading symbol: ", symbol); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message); + } +#endif + +#ifdef _WIN32 + proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); +#else +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" +#endif + proc = (ma_proc)dlsym((void*)handle, symbol); +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #pragma GCC diagnostic pop +#endif +#endif + +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_WARNING + if (handle == NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Failed to load symbol: ", symbol); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_WARNING, message); + } +#endif + + (void)pContext; /* It's possible for pContext to be unused. */ + return proc; +} + #if 0 static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn) @@ -18714,250 +11721,51 @@ static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn) #endif -static MA_INLINE unsigned int ma_device_disable_denormals(ma_device* pDevice) -{ - MA_ASSERT(pDevice != NULL); - - if (!pDevice->noDisableDenormals) { - return ma_disable_denormals(); - } else { - return 0; - } -} - -static MA_INLINE void ma_device_restore_denormals(ma_device* pDevice, unsigned int prevState) -{ - MA_ASSERT(pDevice != NULL); - - if (!pDevice->noDisableDenormals) { - ma_restore_denormals(prevState); - } else { - /* Do nothing. */ - (void)prevState; - } -} - -static ma_device_notification ma_device_notification_init(ma_device* pDevice, ma_device_notification_type type) -{ - ma_device_notification notification; - - MA_ZERO_OBJECT(¬ification); - notification.pDevice = pDevice; - notification.type = type; - - return notification; -} - -static void ma_device__on_notification(ma_device_notification notification) -{ - MA_ASSERT(notification.pDevice != NULL); - - if (notification.pDevice->onNotification != NULL) { - notification.pDevice->onNotification(¬ification); - } - - /* TEMP FOR COMPATIBILITY: If it's a stopped notification, fire the onStop callback as well. This is only for backwards compatibility and will be removed. */ - if (notification.pDevice->onStop != NULL && notification.type == ma_device_notification_type_stopped) { - notification.pDevice->onStop(notification.pDevice); - } -} - -static void ma_device__on_notification_started(ma_device* pDevice) -{ - ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_started)); -} - -static void ma_device__on_notification_stopped(ma_device* pDevice) -{ - ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_stopped)); -} - -/* Not all platforms support reroute notifications. */ -#if !defined(MA_EMSCRIPTEN) -static void ma_device__on_notification_rerouted(ma_device* pDevice) -{ - ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_rerouted)); -} -#endif - -#if defined(MA_EMSCRIPTEN) -#ifdef __cplusplus -extern "C" { -#endif -void EMSCRIPTEN_KEEPALIVE ma_device__on_notification_unlocked(ma_device* pDevice) -{ - ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_unlocked)); -} -#ifdef __cplusplus -} -#endif -#endif - - -static void ma_device__on_data_inner(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) -{ - MA_ASSERT(pDevice != NULL); - MA_ASSERT(pDevice->onData != NULL); - - if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) { - ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); - } - - pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount); -} - static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) -{ - MA_ASSERT(pDevice != NULL); - - /* Don't read more data from the client if we're in the process of stopping. */ - if (ma_device_get_state(pDevice) == ma_device_state_stopping) { - return; - } - - if (pDevice->noFixedSizedCallback) { - /* Fast path. Not using a fixed sized callback. Process directly from the specified buffers. */ - ma_device__on_data_inner(pDevice, pFramesOut, pFramesIn, frameCount); - } else { - /* Slow path. Using a fixed sized callback. Need to use the intermediary buffer. */ - ma_uint32 totalFramesProcessed = 0; - - while (totalFramesProcessed < frameCount) { - ma_uint32 totalFramesRemaining = frameCount - totalFramesProcessed; - ma_uint32 framesToProcessThisIteration = 0; - - if (pFramesIn != NULL) { - /* Capturing. Write to the intermediary buffer. If there's no room, fire the callback to empty it. */ - if (pDevice->capture.intermediaryBufferLen < pDevice->capture.intermediaryBufferCap) { - /* There's some room left in the intermediary buffer. Write to it without firing the callback. */ - framesToProcessThisIteration = totalFramesRemaining; - if (framesToProcessThisIteration > pDevice->capture.intermediaryBufferCap - pDevice->capture.intermediaryBufferLen) { - framesToProcessThisIteration = pDevice->capture.intermediaryBufferCap - pDevice->capture.intermediaryBufferLen; - } - - ma_copy_pcm_frames( - ma_offset_pcm_frames_ptr(pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferLen, pDevice->capture.format, pDevice->capture.channels), - ma_offset_pcm_frames_const_ptr(pFramesIn, totalFramesProcessed, pDevice->capture.format, pDevice->capture.channels), - framesToProcessThisIteration, - pDevice->capture.format, pDevice->capture.channels); - - pDevice->capture.intermediaryBufferLen += framesToProcessThisIteration; - } - - if (pDevice->capture.intermediaryBufferLen == pDevice->capture.intermediaryBufferCap) { - /* No room left in the intermediary buffer. Fire the data callback. */ - if (pDevice->type == ma_device_type_duplex) { - /* We'll do the duplex data callback later after we've processed the playback data. */ - } else { - ma_device__on_data_inner(pDevice, NULL, pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap); - - /* The intermediary buffer has just been drained. */ - pDevice->capture.intermediaryBufferLen = 0; - } - } - } - - if (pFramesOut != NULL) { - /* Playing back. Read from the intermediary buffer. If there's nothing in it, fire the callback to fill it. */ - if (pDevice->playback.intermediaryBufferLen > 0) { - /* There's some content in the intermediary buffer. Read from that without firing the callback. */ - if (pDevice->type == ma_device_type_duplex) { - /* The frames processed this iteration for a duplex device will always be based on the capture side. Leave it unmodified. */ - } else { - framesToProcessThisIteration = totalFramesRemaining; - if (framesToProcessThisIteration > pDevice->playback.intermediaryBufferLen) { - framesToProcessThisIteration = pDevice->playback.intermediaryBufferLen; - } - } - - ma_copy_pcm_frames( - ma_offset_pcm_frames_ptr(pFramesOut, totalFramesProcessed, pDevice->playback.format, pDevice->playback.channels), - ma_offset_pcm_frames_ptr(pDevice->playback.pIntermediaryBuffer, pDevice->playback.intermediaryBufferCap - pDevice->playback.intermediaryBufferLen, pDevice->playback.format, pDevice->playback.channels), - framesToProcessThisIteration, - pDevice->playback.format, pDevice->playback.channels); - - pDevice->playback.intermediaryBufferLen -= framesToProcessThisIteration; - } - - if (pDevice->playback.intermediaryBufferLen == 0) { - /* There's nothing in the intermediary buffer. Fire the data callback to fill it. */ - if (pDevice->type == ma_device_type_duplex) { - /* In duplex mode, the data callback will be fired later. Nothing to do here. */ - } else { - ma_device__on_data_inner(pDevice, pDevice->playback.pIntermediaryBuffer, NULL, pDevice->playback.intermediaryBufferCap); - - /* The intermediary buffer has just been filled. */ - pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap; - } - } - } - - /* If we're in duplex mode we might need to do a refill of the data. */ - if (pDevice->type == ma_device_type_duplex) { - if (pDevice->capture.intermediaryBufferLen == pDevice->capture.intermediaryBufferCap) { - ma_device__on_data_inner(pDevice, pDevice->playback.pIntermediaryBuffer, pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap); - - pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap; /* The playback buffer will have just been filled. */ - pDevice->capture.intermediaryBufferLen = 0; /* The intermediary buffer has just been drained. */ - } - } - - /* Make sure this is only incremented once in the duplex case. */ - totalFramesProcessed += framesToProcessThisIteration; - } - } -} - -static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) { float masterVolumeFactor; ma_device_get_master_volume(pDevice, &masterVolumeFactor); /* Use ma_device_get_master_volume() to ensure the volume is loaded atomically. */ if (pDevice->onData) { - unsigned int prevDenormalState = ma_device_disable_denormals(pDevice); - { - /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ - if (pFramesIn != NULL && masterVolumeFactor != 1) { - ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - ma_uint32 totalFramesProcessed = 0; - while (totalFramesProcessed < frameCount) { - ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed; - if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) { - framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture; - } - - ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor); - - ma_device__on_data(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration); - - totalFramesProcessed += framesToProcessThisIteration; - } - } else { - ma_device__on_data(pDevice, pFramesOut, pFramesIn, frameCount); - } - - /* Volume control and clipping for playback devices. */ - if (pFramesOut != NULL) { - if (masterVolumeFactor != 1) { - if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */ - ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor); - } - } - - if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) { - ma_clip_samples_f32((float*)pFramesOut, (const float*)pFramesOut, frameCount * pDevice->playback.channels); /* Intentionally specifying the same pointer for both input and output for in-place processing. */ - } - } - } - ma_device_restore_denormals(pDevice, prevDenormalState); - } else { - /* No data callback. Just silence the output. */ - if (pFramesOut != NULL) { + if (!pDevice->noPreZeroedOutputBuffer && pFramesOut != NULL) { ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); } + + /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ + if (pFramesIn != NULL && masterVolumeFactor < 1) { + ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint32 totalFramesProcessed = 0; + while (totalFramesProcessed < frameCount) { + ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed; + if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) { + framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture; + } + + ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor); + + pDevice->onData(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration); + + totalFramesProcessed += framesToProcessThisIteration; + } + } else { + pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount); + } + + /* Volume control and clipping for playback devices. */ + if (pFramesOut != NULL) { + if (masterVolumeFactor < 1) { + if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */ + ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor); + } + } + + if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) { + ma_clip_pcm_frames_f32((float*)pFramesOut, frameCount, pDevice->playback.channels); + } + } } } @@ -18971,97 +11779,58 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra MA_ASSERT(pFramesOut != NULL); if (pDevice->playback.converter.isPassthrough) { - ma_device__handle_data_callback(pDevice, pFramesOut, NULL, frameCount); + ma_device__on_data(pDevice, pFramesOut, NULL, frameCount); } else { ma_result result; ma_uint64 totalFramesReadOut; + ma_uint64 totalFramesReadIn; void* pRunningFramesOut; totalFramesReadOut = 0; + totalFramesReadIn = 0; pRunningFramesOut = pFramesOut; - /* - We run slightly different logic depending on whether or not we're using a heap-allocated - buffer for caching input data. This will be the case if the data converter does not have - the ability to retrieve the required input frame count for a given output frame count. - */ - if (pDevice->playback.pInputCache != NULL) { - while (totalFramesReadOut < frameCount) { - ma_uint64 framesToReadThisIterationIn; - ma_uint64 framesToReadThisIterationOut; + while (totalFramesReadOut < frameCount) { + ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In client format. */ + ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint64 framesToReadThisIterationIn; + ma_uint64 framesReadThisIterationIn; + ma_uint64 framesToReadThisIterationOut; + ma_uint64 framesReadThisIterationOut; + ma_uint64 requiredInputFrameCount; - /* If there's any data available in the cache, that needs to get processed first. */ - if (pDevice->playback.inputCacheRemaining > 0) { - framesToReadThisIterationOut = (frameCount - totalFramesReadOut); - framesToReadThisIterationIn = framesToReadThisIterationOut; - if (framesToReadThisIterationIn > pDevice->playback.inputCacheRemaining) { - framesToReadThisIterationIn = pDevice->playback.inputCacheRemaining; - } - - result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, ma_offset_pcm_frames_ptr(pDevice->playback.pInputCache, pDevice->playback.inputCacheConsumed, pDevice->playback.format, pDevice->playback.channels), &framesToReadThisIterationIn, pRunningFramesOut, &framesToReadThisIterationOut); - if (result != MA_SUCCESS) { - break; - } - - pDevice->playback.inputCacheConsumed += framesToReadThisIterationIn; - pDevice->playback.inputCacheRemaining -= framesToReadThisIterationIn; - - totalFramesReadOut += framesToReadThisIterationOut; - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesToReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); - - if (framesToReadThisIterationIn == 0 && framesToReadThisIterationOut == 0) { - break; /* We're done. */ - } - } - - /* Getting here means there's no data in the cache and we need to fill it up with data from the client. */ - if (pDevice->playback.inputCacheRemaining == 0) { - ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, NULL, (ma_uint32)pDevice->playback.inputCacheCap); - - pDevice->playback.inputCacheConsumed = 0; - pDevice->playback.inputCacheRemaining = pDevice->playback.inputCacheCap; - } + framesToReadThisIterationOut = (frameCount - totalFramesReadOut); + framesToReadThisIterationIn = framesToReadThisIterationOut; + if (framesToReadThisIterationIn > intermediaryBufferCap) { + framesToReadThisIterationIn = intermediaryBufferCap; } - } else { - while (totalFramesReadOut < frameCount) { - ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In client format. */ - ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - ma_uint64 framesToReadThisIterationIn; - ma_uint64 framesReadThisIterationIn; - ma_uint64 framesToReadThisIterationOut; - ma_uint64 framesReadThisIterationOut; - ma_uint64 requiredInputFrameCount; - framesToReadThisIterationOut = (frameCount - totalFramesReadOut); - framesToReadThisIterationIn = framesToReadThisIterationOut; - if (framesToReadThisIterationIn > intermediaryBufferCap) { - framesToReadThisIterationIn = intermediaryBufferCap; - } + requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut); + if (framesToReadThisIterationIn > requiredInputFrameCount) { + framesToReadThisIterationIn = requiredInputFrameCount; + } - ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut, &requiredInputFrameCount); - if (framesToReadThisIterationIn > requiredInputFrameCount) { - framesToReadThisIterationIn = requiredInputFrameCount; - } + if (framesToReadThisIterationIn > 0) { + ma_device__on_data(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); + totalFramesReadIn += framesToReadThisIterationIn; + } - ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); + /* + At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any + input frames, we still want to try processing frames because there may some output frames generated from cached input data. + */ + framesReadThisIterationIn = framesToReadThisIterationIn; + framesReadThisIterationOut = framesToReadThisIterationOut; + result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); + if (result != MA_SUCCESS) { + break; + } - /* - At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any - input frames, we still want to try processing frames because there may some output frames generated from cached input data. - */ - framesReadThisIterationIn = framesToReadThisIterationIn; - framesReadThisIterationOut = framesToReadThisIterationOut; - result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); - if (result != MA_SUCCESS) { - break; - } + totalFramesReadOut += framesReadThisIterationOut; + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); - totalFramesReadOut += framesReadThisIterationOut; - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); - - if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { - break; /* We're done. */ - } + if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { + break; /* We're done. */ } } } @@ -19075,7 +11844,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame MA_ASSERT(pFramesInDeviceFormat != NULL); if (pDevice->capture.converter.isPassthrough) { - ma_device__handle_data_callback(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat); + ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat); } else { ma_result result; ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; @@ -19084,7 +11853,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame ma_uint64 totalClientFramesProcessed = 0; const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat; - /* We just keep going until we've exhausted all of our input frames and cannot generate any more output frames. */ + /* We just keep going until we've exhaused all of our input frames and cannot generate any more output frames. */ for (;;) { ma_uint64 deviceFramesProcessedThisIteration; ma_uint64 clientFramesProcessedThisIteration; @@ -19098,16 +11867,13 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame } if (clientFramesProcessedThisIteration > 0) { - ma_device__handle_data_callback(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */ + ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */ } pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); totalDeviceFramesProcessed += deviceFramesProcessedThisIteration; totalClientFramesProcessed += clientFramesProcessedThisIteration; - /* This is just to silence a warning. I might want to use this variable later so leaving in place for now. */ - (void)totalClientFramesProcessed; - if (deviceFramesProcessedThisIteration == 0 && clientFramesProcessedThisIteration == 0) { break; /* We're done. */ } @@ -19136,7 +11902,7 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer."); + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result); break; } @@ -19154,9 +11920,9 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m break; } - result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat); /* Safe cast. */ + result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat, pFramesInClientFormat); /* Safe cast. */ if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer."); + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result); break; } @@ -19175,14 +11941,16 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB) { ma_result result; + ma_uint8 playbackFramesInExternalFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 totalFramesToReadFromClient; + ma_uint32 totalFramesReadFromClient; ma_uint32 totalFramesReadOut = 0; MA_ASSERT(pDevice != NULL); MA_ASSERT(frameCount > 0); MA_ASSERT(pFramesInInternalFormat != NULL); MA_ASSERT(pRB != NULL); - MA_ASSERT(pDevice->playback.pInputCache != NULL); /* Sitting in the ring buffer should be captured data from the capture callback in external format. If there's not enough data in there for @@ -19190,51 +11958,58 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, */ MA_ZERO_MEMORY(silentInputFrames, sizeof(silentInputFrames)); - while (totalFramesReadOut < frameCount && ma_device_is_started(pDevice)) { - /* - We should have a buffer allocated on the heap. Any playback frames still sitting in there - need to be sent to the internal device before we process any more data from the client. - */ - if (pDevice->playback.inputCacheRemaining > 0) { - ma_uint64 framesConvertedIn = pDevice->playback.inputCacheRemaining; - ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut); - ma_data_converter_process_pcm_frames(&pDevice->playback.converter, ma_offset_pcm_frames_ptr(pDevice->playback.pInputCache, pDevice->playback.inputCacheConsumed, pDevice->playback.format, pDevice->playback.channels), &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut); + /* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */ + totalFramesToReadFromClient = (ma_uint32)ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, frameCount); + totalFramesReadFromClient = 0; + while (totalFramesReadFromClient < totalFramesToReadFromClient && ma_device_is_started(pDevice)) { + ma_uint32 framesRemainingFromClient; + ma_uint32 framesToProcessFromClient; + ma_uint32 inputFrameCount; + void* pInputFrames; - pDevice->playback.inputCacheConsumed += framesConvertedIn; - pDevice->playback.inputCacheRemaining -= framesConvertedIn; - - totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */ - pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); + framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient); + framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + if (framesToProcessFromClient > framesRemainingFromClient) { + framesToProcessFromClient = framesRemainingFromClient; } - /* If there's no more data in the cache we'll need to fill it with some. */ - if (totalFramesReadOut < frameCount && pDevice->playback.inputCacheRemaining == 0) { - ma_uint32 inputFrameCount; - void* pInputFrames; - - inputFrameCount = (ma_uint32)pDevice->playback.inputCacheCap; - result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); - if (result == MA_SUCCESS) { - if (inputFrameCount > 0) { - ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount); - } else { - if (ma_pcm_rb_pointer_distance(pRB) == 0) { - break; /* Underrun. */ - } - } + /* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */ + inputFrameCount = framesToProcessFromClient; + result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); + if (result == MA_SUCCESS) { + if (inputFrameCount > 0) { + /* Use actual input frames. */ + ma_device__on_data(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount); } else { - /* No capture data available. Feed in silence. */ - inputFrameCount = (ma_uint32)ma_min(pDevice->playback.inputCacheCap, sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)); - ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, silentInputFrames, inputFrameCount); + if (ma_pcm_rb_pointer_distance(pRB) == 0) { + break; /* Underrun. */ + } } - pDevice->playback.inputCacheConsumed = 0; - pDevice->playback.inputCacheRemaining = inputFrameCount; - - result = ma_pcm_rb_commit_read(pRB, inputFrameCount); + /* We're done with the captured samples. */ + result = ma_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames); if (result != MA_SUCCESS) { - return result; /* Should never happen. */ + break; /* Don't know what to do here... Just abandon ship. */ } + } else { + /* Use silent input frames. */ + inputFrameCount = ma_min( + sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels), + sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels) + ); + + ma_device__on_data(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount); + } + + /* We have samples in external format so now we need to convert to internal format and output to the device. */ + { + ma_uint64 framesConvertedIn = inputFrameCount; + ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut); + ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackFramesInExternalFormat, &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut); + + totalFramesReadFromClient += (ma_uint32)framesConvertedIn; /* Safe cast. */ + totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */ + pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } } @@ -19242,17 +12017,17 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, } /* A helper for changing the state of the device. */ -static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state newState) +static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newState) { - ma_atomic_device_state_set(&pDevice->state, newState); + c89atomic_exchange_32(&pDevice->state, newState); } -#if defined(MA_WIN32) - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ +#ifdef MA_WIN32 + GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ + /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ #endif @@ -19272,6 +12047,7 @@ MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = bette static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType); + static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDeviceDescriptor) { if (pDeviceDescriptor == NULL) { @@ -19282,7 +12058,7 @@ static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDevi return MA_FALSE; } - if (pDeviceDescriptor->channels == 0 || pDeviceDescriptor->channels > MA_MAX_CHANNELS) { + if (pDeviceDescriptor->channels < MA_MIN_CHANNELS || pDeviceDescriptor->channels > MA_MAX_CHANNELS) { return MA_FALSE; } @@ -19324,7 +12100,7 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) /* NOTE: The device was started outside of this function, in the worker thread. */ - while (ma_device_get_state(pDevice) == ma_device_state_started && !exitLoop) { + while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) { switch (pDevice->type) { case ma_device_type_duplex: { @@ -19367,14 +12143,14 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) } /* - If we weren't able to generate any output frames it must mean we've exhausted all of our input. The only time this would not be the case is if capturedClientData was too small + If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE. */ if (capturedClientFramesToProcessThisIteration == 0) { break; } - ma_device__handle_data_callback(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/ + ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/ capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ @@ -19407,11 +12183,6 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) } } - /* Make sure we don't get stuck in the inner loop. */ - if (capturedDeviceFramesProcessed == 0) { - break; - } - totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed; } } break; @@ -19435,11 +12206,6 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) break; } - /* Make sure we don't get stuck in the inner loop. */ - if (framesProcessed == 0) { - break; - } - ma_device__send_frames_to_client(pDevice, framesProcessed, capturedDeviceData); framesReadThisPeriod += framesProcessed; @@ -19467,11 +12233,6 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) break; } - /* Make sure we don't get stuck in the inner loop. */ - if (framesProcessed == 0) { - break; - } - framesWrittenThisPeriod += framesProcessed; } } break; @@ -19570,7 +12331,7 @@ static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 oper /* The first thing to do is wait for an operation slot to become available. We only have a single slot for this, but we could extend this later - to support queuing of operations. + to support queing of operations. */ result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore); if (result != MA_SUCCESS) { @@ -19620,7 +12381,6 @@ static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enu ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1); - deviceInfo.isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */ cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } @@ -19629,7 +12389,6 @@ static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enu ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1); - deviceInfo.isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */ cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } @@ -19653,8 +12412,6 @@ static ma_result ma_context_get_device_info__null(ma_context* pContext, ma_devic ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1); } - pDeviceInfo->isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */ - /* Support everything on the null backend. */ pDeviceInfo->nativeDataFormats[0].format = ma_format_unknown; pDeviceInfo->nativeDataFormats[0].channels = 0; @@ -19704,7 +12461,7 @@ static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config pDescriptorCapture->sampleRate = (pDescriptorCapture->sampleRate != 0) ? pDescriptorCapture->sampleRate : MA_DEFAULT_SAMPLE_RATE; if (pDescriptorCapture->channelMap[0] == MA_CHANNEL_NONE) { - ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); + ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptorCapture->channels, pDescriptorCapture->channelMap); } pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile); @@ -19716,7 +12473,7 @@ static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config pDescriptorPlayback->sampleRate = (pDescriptorPlayback->sampleRate != 0) ? pDescriptorPlayback->sampleRate : MA_DEFAULT_SAMPLE_RATE; if (pDescriptorPlayback->channelMap[0] == MA_CHANNEL_NONE) { - ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorPlayback->channels); + ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); } pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); @@ -19741,7 +12498,7 @@ static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config return result; } - result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice, &pDevice->pContext->allocationCallbacks); + result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice); if (result != MA_SUCCESS) { return result; } @@ -19755,7 +12512,7 @@ static ma_result ma_device_start__null(ma_device* pDevice) ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL); - ma_atomic_bool32_set(&pDevice->null_device.isStarted, MA_TRUE); + c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE); return MA_SUCCESS; } @@ -19765,17 +12522,10 @@ static ma_result ma_device_stop__null(ma_device* pDevice) ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL); - ma_atomic_bool32_set(&pDevice->null_device.isStarted, MA_FALSE); + c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE); return MA_SUCCESS; } -static ma_bool32 ma_device_is_started__null(ma_device* pDevice) -{ - MA_ASSERT(pDevice != NULL); - - return ma_atomic_bool32_get(&pDevice->null_device.isStarted); -} - static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) { ma_result result = MA_SUCCESS; @@ -19786,7 +12536,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame *pFramesWritten = 0; } - wasStartedOnEntry = ma_device_is_started__null(pDevice); + wasStartedOnEntry = c89atomic_load_32(&pDevice->null_device.isStarted); /* Keep going until everything has been read. */ totalPCMFramesProcessed = 0; @@ -19812,7 +12562,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) { pDevice->null_device.currentPeriodFramesRemainingPlayback = 0; - if (!ma_device_is_started__null(pDevice) && !wasStartedOnEntry) { + if (!c89atomic_load_32(&pDevice->null_device.isStarted) && !wasStartedOnEntry) { result = ma_device_start__null(pDevice); if (result != MA_SUCCESS) { break; @@ -19832,7 +12582,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame ma_uint64 currentFrame; /* Stop waiting if the device has been stopped. */ - if (!ma_device_is_started__null(pDevice)) { + if (!c89atomic_load_32(&pDevice->null_device.isStarted)) { break; } @@ -19903,7 +12653,7 @@ static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_u ma_uint64 currentFrame; /* Stop waiting if the device has been stopped. */ - if (!ma_device_is_started__null(pDevice)) { + if (!c89atomic_load_32(&pDevice->null_device.isStarted)) { break; } @@ -19968,8 +12718,8 @@ WIN32 COMMON *******************************************************************************/ #if defined(MA_WIN32) -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((pContext->win32.CoInitializeEx) ? ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) : ((MA_PFN_CoInitialize)pContext->win32.CoInitialize)(pvReserved)) +#if defined(MA_WIN32_DESKTOP) + #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)() #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv) #define ma_CoTaskMemFree(pContext, pv) ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv) @@ -19986,34 +12736,19 @@ WIN32 COMMON typedef size_t DWORD_PTR; #endif -#if !defined(WAVE_FORMAT_1M08) -#define WAVE_FORMAT_1M08 0x00000001 -#define WAVE_FORMAT_1S08 0x00000002 -#define WAVE_FORMAT_1M16 0x00000004 -#define WAVE_FORMAT_1S16 0x00000008 -#define WAVE_FORMAT_2M08 0x00000010 -#define WAVE_FORMAT_2S08 0x00000020 -#define WAVE_FORMAT_2M16 0x00000040 -#define WAVE_FORMAT_2S16 0x00000080 -#define WAVE_FORMAT_4M08 0x00000100 -#define WAVE_FORMAT_4S08 0x00000200 -#define WAVE_FORMAT_4M16 0x00000400 -#define WAVE_FORMAT_4S16 0x00000800 -#endif - #if !defined(WAVE_FORMAT_44M08) -#define WAVE_FORMAT_44M08 0x00000100 -#define WAVE_FORMAT_44S08 0x00000200 -#define WAVE_FORMAT_44M16 0x00000400 -#define WAVE_FORMAT_44S16 0x00000800 -#define WAVE_FORMAT_48M08 0x00001000 -#define WAVE_FORMAT_48S08 0x00002000 -#define WAVE_FORMAT_48M16 0x00004000 -#define WAVE_FORMAT_48S16 0x00008000 -#define WAVE_FORMAT_96M08 0x00010000 -#define WAVE_FORMAT_96S08 0x00020000 -#define WAVE_FORMAT_96M16 0x00040000 -#define WAVE_FORMAT_96S16 0x00080000 +#define WAVE_FORMAT_44M08 0x00000100 +#define WAVE_FORMAT_44S08 0x00000200 +#define WAVE_FORMAT_44M16 0x00000400 +#define WAVE_FORMAT_44S16 0x00000800 +#define WAVE_FORMAT_48M08 0x00001000 +#define WAVE_FORMAT_48S08 0x00002000 +#define WAVE_FORMAT_48M16 0x00004000 +#define WAVE_FORMAT_48S16 0x00008000 +#define WAVE_FORMAT_96M08 0x00010000 +#define WAVE_FORMAT_96S08 0x00020000 +#define WAVE_FORMAT_96M16 0x00040000 +#define WAVE_FORMAT_96S16 0x00080000 #endif #ifndef SPEAKER_FRONT_LEFT @@ -20038,30 +12773,13 @@ typedef size_t DWORD_PTR; #endif /* -Implement our own version of MA_WAVEFORMATEXTENSIBLE so we can avoid a header. Be careful with this -because MA_WAVEFORMATEX has an extra two bytes over standard WAVEFORMATEX due to padding. The -standard version uses tight packing, but for compiler compatibility we're not doing that with ours. +The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We +define our own implementation in this case. */ +#if (defined(_MSC_VER) && !defined(_WAVEFORMATEXTENSIBLE_)) || defined(__DMC__) typedef struct { - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; -} MA_WAVEFORMATEX; - -typedef struct -{ - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; + WAVEFORMATEX Format; union { WORD wValidBitsPerSample; @@ -20070,18 +12788,13 @@ typedef struct } Samples; DWORD dwChannelMask; GUID SubFormat; -} MA_WAVEFORMATEXTENSIBLE; - - +} WAVEFORMATEXTENSIBLE; +#endif #ifndef WAVE_FORMAT_EXTENSIBLE #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif -#ifndef WAVE_FORMAT_PCM -#define WAVE_FORMAT_PCM 1 -#endif - #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif @@ -20157,9 +12870,11 @@ static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel* pChannelMap /* Converts a Win32-style channel mask to a miniaudio channel map. */ static void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel* pChannelMap) { - /* If the channel mask is set to 0, just assume a default Win32 channel map. */ - if (dwChannelMask == 0) { - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channels, channels); + if (channels == 1 && dwChannelMask == 0) { + pChannelMap[0] = MA_CHANNEL_MONO; + } else if (channels == 2 && dwChannelMask == 0) { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; } else { if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) { pChannelMap[0] = MA_CHANNEL_MONO; @@ -20195,21 +12910,21 @@ static MA_INLINE ma_bool32 ma_is_guid_null(const void* guid) return ma_is_guid_equal(guid, &nullguid); } -static ma_format ma_format_from_WAVEFORMATEX(const MA_WAVEFORMATEX* pWF) +static ma_format ma_format_from_WAVEFORMATEX(const WAVEFORMATEX* pWF) { MA_ASSERT(pWF != NULL); if (pWF->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - const MA_WAVEFORMATEXTENSIBLE* pWFEX = (const MA_WAVEFORMATEXTENSIBLE*)pWF; + const WAVEFORMATEXTENSIBLE* pWFEX = (const WAVEFORMATEXTENSIBLE*)pWF; if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_PCM)) { if (pWFEX->Samples.wValidBitsPerSample == 32) { return ma_format_s32; } if (pWFEX->Samples.wValidBitsPerSample == 24) { - if (pWFEX->wBitsPerSample == 32) { - return ma_format_s32; + if (pWFEX->Format.wBitsPerSample == 32) { + /*return ma_format_s24_32;*/ } - if (pWFEX->wBitsPerSample == 24) { + if (pWFEX->Format.wBitsPerSample == 24) { return ma_format_s24; } } @@ -20317,7 +13032,7 @@ typedef struct #endif /* Some compilers don't define PropVariantInit(). We just do this ourselves since it's just a memset(). */ -static MA_INLINE void ma_PropVariantInit(MA_PROPVARIANT* pProp) +static MA_INLINE void ma_PropVariantInit(PROPVARIANT* pProp) { MA_ZERO_OBJECT(pProp); } @@ -20327,7 +13042,7 @@ static const PROPERTYKEY MA_PKEY_Device_FriendlyName = {{0xA45C254E, static const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat = {{0xF19F064D, 0x82C, 0x4E27, {0xBC, 0x73, 0x68, 0x82, 0xA1, 0xBB, 0x8E, 0x4C}}, 0}; static const IID MA_IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; /* 00000000-0000-0000-C000-000000000046 */ -#if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) +#ifndef MA_WIN32_DESKTOP static const IID MA_IID_IAgileObject = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */ #endif @@ -20337,16 +13052,24 @@ static const IID MA_IID_IAudioClient3 = {0x7ED4EE07, static const IID MA_IID_IAudioRenderClient = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */ static const IID MA_IID_IAudioCaptureClient = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */ static const IID MA_IID_IMMNotificationClient = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */ -#if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) +#ifndef MA_WIN32_DESKTOP static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */ static const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; /* 2EEF81BE-33FA-4800-9670-1CD474972C3F */ static const IID MA_IID_IActivateAudioInterfaceCompletionHandler = {0x41D949AB, 0x9862, 0x444A, {0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB}}; /* 41D949AB-9862-444A-80F6-C261334DA5EB */ #endif -static const IID MA_CLSID_MMDeviceEnumerator = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}}; /* BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator) */ -static const IID MA_IID_IMMDeviceEnumerator = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}}; /* A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator) */ +static const IID MA_CLSID_MMDeviceEnumerator_Instance = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}}; /* BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator) */ +static const IID MA_IID_IMMDeviceEnumerator_Instance = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}}; /* A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator) */ +#ifdef __cplusplus +#define MA_CLSID_MMDeviceEnumerator MA_CLSID_MMDeviceEnumerator_Instance +#define MA_IID_IMMDeviceEnumerator MA_IID_IMMDeviceEnumerator_Instance +#else +#define MA_CLSID_MMDeviceEnumerator &MA_CLSID_MMDeviceEnumerator_Instance +#define MA_IID_IMMDeviceEnumerator &MA_IID_IMMDeviceEnumerator_Instance +#endif -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +typedef struct ma_IUnknown ma_IUnknown; +#ifdef MA_WIN32_DESKTOP #define MA_MM_DEVICE_STATE_ACTIVE 1 #define MA_MM_DEVICE_STATE_DISABLED 2 #define MA_MM_DEVICE_STATE_NOTPRESENT 4 @@ -20432,7 +13155,7 @@ static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const II static MA_INLINE ULONG ma_IUnknown_AddRef(ma_IUnknown* pThis) { return pThis->lpVtbl->AddRef(pThis); } static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) { return pThis->lpVtbl->Release(pThis); } -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP /* IMMNotificationClient */ typedef struct { @@ -20442,11 +13165,11 @@ static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) ULONG (STDMETHODCALLTYPE * Release) (ma_IMMNotificationClient* pThis); /* IMMNotificationClient */ - HRESULT (STDMETHODCALLTYPE * OnDeviceStateChanged) (ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID, DWORD dwNewState); - HRESULT (STDMETHODCALLTYPE * OnDeviceAdded) (ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID); - HRESULT (STDMETHODCALLTYPE * OnDeviceRemoved) (ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID); - HRESULT (STDMETHODCALLTYPE * OnDefaultDeviceChanged)(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, const WCHAR* pDefaultDeviceID); - HRESULT (STDMETHODCALLTYPE * OnPropertyValueChanged)(ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID, const PROPERTYKEY key); + HRESULT (STDMETHODCALLTYPE * OnDeviceStateChanged) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState); + HRESULT (STDMETHODCALLTYPE * OnDeviceAdded) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID); + HRESULT (STDMETHODCALLTYPE * OnDeviceRemoved) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID); + HRESULT (STDMETHODCALLTYPE * OnDefaultDeviceChanged)(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID); + HRESULT (STDMETHODCALLTYPE * OnPropertyValueChanged)(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key); } ma_IMMNotificationClientVtbl; /* IMMDeviceEnumerator */ @@ -20460,7 +13183,7 @@ static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) /* IMMDeviceEnumerator */ HRESULT (STDMETHODCALLTYPE * EnumAudioEndpoints) (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices); HRESULT (STDMETHODCALLTYPE * GetDefaultAudioEndpoint) (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint); - HRESULT (STDMETHODCALLTYPE * GetDevice) (ma_IMMDeviceEnumerator* pThis, const WCHAR* pID, ma_IMMDevice** ppDevice); + HRESULT (STDMETHODCALLTYPE * GetDevice) (ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice); HRESULT (STDMETHODCALLTYPE * RegisterEndpointNotificationCallback) (ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient); HRESULT (STDMETHODCALLTYPE * UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient); } ma_IMMDeviceEnumeratorVtbl; @@ -20473,7 +13196,7 @@ static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) static MA_INLINE ULONG ma_IMMDeviceEnumerator_Release(ma_IMMDeviceEnumerator* pThis) { return pThis->lpVtbl->Release(pThis); } static MA_INLINE HRESULT ma_IMMDeviceEnumerator_EnumAudioEndpoints(ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices) { return pThis->lpVtbl->EnumAudioEndpoints(pThis, dataFlow, dwStateMask, ppDevices); } static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint) { return pThis->lpVtbl->GetDefaultAudioEndpoint(pThis, dataFlow, role, ppEndpoint); } - static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator* pThis, const WCHAR* pID, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->GetDevice(pThis, pID, ppDevice); } + static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->GetDevice(pThis, pID, ppDevice); } static MA_INLINE HRESULT ma_IMMDeviceEnumerator_RegisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->RegisterEndpointNotificationCallback(pThis, pClient); } static MA_INLINE HRESULT ma_IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->UnregisterEndpointNotificationCallback(pThis, pClient); } @@ -20510,9 +13233,9 @@ static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDevice* pThis); /* IMMDevice */ - HRESULT (STDMETHODCALLTYPE * Activate) (ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, MA_PROPVARIANT* pActivationParams, void** ppInterface); + HRESULT (STDMETHODCALLTYPE * Activate) (ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface); HRESULT (STDMETHODCALLTYPE * OpenPropertyStore)(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties); - HRESULT (STDMETHODCALLTYPE * GetId) (ma_IMMDevice* pThis, WCHAR** pID); + HRESULT (STDMETHODCALLTYPE * GetId) (ma_IMMDevice* pThis, LPWSTR *pID); HRESULT (STDMETHODCALLTYPE * GetState) (ma_IMMDevice* pThis, DWORD *pState); } ma_IMMDeviceVtbl; struct ma_IMMDevice @@ -20522,9 +13245,9 @@ static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) static MA_INLINE HRESULT ma_IMMDevice_QueryInterface(ma_IMMDevice* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } static MA_INLINE ULONG ma_IMMDevice_AddRef(ma_IMMDevice* pThis) { return pThis->lpVtbl->AddRef(pThis); } static MA_INLINE ULONG ma_IMMDevice_Release(ma_IMMDevice* pThis) { return pThis->lpVtbl->Release(pThis); } - static MA_INLINE HRESULT ma_IMMDevice_Activate(ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, MA_PROPVARIANT* pActivationParams, void** ppInterface) { return pThis->lpVtbl->Activate(pThis, iid, dwClsCtx, pActivationParams, ppInterface); } + static MA_INLINE HRESULT ma_IMMDevice_Activate(ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface) { return pThis->lpVtbl->Activate(pThis, iid, dwClsCtx, pActivationParams, ppInterface); } static MA_INLINE HRESULT ma_IMMDevice_OpenPropertyStore(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties) { return pThis->lpVtbl->OpenPropertyStore(pThis, stgmAccess, ppProperties); } - static MA_INLINE HRESULT ma_IMMDevice_GetId(ma_IMMDevice* pThis, WCHAR** pID) { return pThis->lpVtbl->GetId(pThis, pID); } + static MA_INLINE HRESULT ma_IMMDevice_GetId(ma_IMMDevice* pThis, LPWSTR *pID) { return pThis->lpVtbl->GetId(pThis, pID); } static MA_INLINE HRESULT ma_IMMDevice_GetState(ma_IMMDevice* pThis, DWORD *pState) { return pThis->lpVtbl->GetState(pThis, pState); } #else /* IActivateAudioInterfaceAsyncOperation */ @@ -20559,8 +13282,8 @@ typedef struct /* IPropertyStore */ HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IPropertyStore* pThis, DWORD* pPropCount); HRESULT (STDMETHODCALLTYPE * GetAt) (ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey); - HRESULT (STDMETHODCALLTYPE * GetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, MA_PROPVARIANT* pPropVar); - HRESULT (STDMETHODCALLTYPE * SetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const MA_PROPVARIANT* const pPropVar); + HRESULT (STDMETHODCALLTYPE * GetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar); + HRESULT (STDMETHODCALLTYPE * SetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar); HRESULT (STDMETHODCALLTYPE * Commit) (ma_IPropertyStore* pThis); } ma_IPropertyStoreVtbl; struct ma_IPropertyStore @@ -20572,8 +13295,8 @@ static MA_INLINE ULONG ma_IPropertyStore_AddRef(ma_IPropertyStore* pThis) static MA_INLINE ULONG ma_IPropertyStore_Release(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Release(pThis); } static MA_INLINE HRESULT ma_IPropertyStore_GetCount(ma_IPropertyStore* pThis, DWORD* pPropCount) { return pThis->lpVtbl->GetCount(pThis, pPropCount); } static MA_INLINE HRESULT ma_IPropertyStore_GetAt(ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey) { return pThis->lpVtbl->GetAt(pThis, propIndex, pPropKey); } -static MA_INLINE HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, MA_PROPVARIANT* pPropVar) { return pThis->lpVtbl->GetValue(pThis, pKey, pPropVar); } -static MA_INLINE HRESULT ma_IPropertyStore_SetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const MA_PROPVARIANT* const pPropVar) { return pThis->lpVtbl->SetValue(pThis, pKey, pPropVar); } +static MA_INLINE HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar) { return pThis->lpVtbl->GetValue(pThis, pKey, pPropVar); } +static MA_INLINE HRESULT ma_IPropertyStore_SetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar) { return pThis->lpVtbl->SetValue(pThis, pKey, pPropVar); } static MA_INLINE HRESULT ma_IPropertyStore_Commit(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Commit(pThis); } @@ -20586,12 +13309,12 @@ typedef struct ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient* pThis); /* IAudioClient */ - HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); + HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames); HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency); HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames); - HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const MA_WAVEFORMATEX* pFormat, MA_WAVEFORMATEX** ppClosestMatch); - HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient* pThis, MA_WAVEFORMATEX** ppDeviceFormat); + HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch); + HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat); HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient* pThis); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient* pThis); @@ -20606,12 +13329,12 @@ struct ma_IAudioClient static MA_INLINE HRESULT ma_IAudioClient_QueryInterface(ma_IAudioClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } static MA_INLINE ULONG ma_IAudioClient_AddRef(ma_IAudioClient* pThis) { return pThis->lpVtbl->AddRef(pThis); } static MA_INLINE ULONG ma_IAudioClient_Release(ma_IAudioClient* pThis) { return pThis->lpVtbl->Release(pThis); } -static MA_INLINE HRESULT ma_IAudioClient_Initialize(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } +static MA_INLINE HRESULT ma_IAudioClient_Initialize(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } static MA_INLINE HRESULT ma_IAudioClient_GetBufferSize(ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); } static MA_INLINE HRESULT ma_IAudioClient_GetStreamLatency(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); } static MA_INLINE HRESULT ma_IAudioClient_GetCurrentPadding(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); } -static MA_INLINE HRESULT ma_IAudioClient_IsFormatSupported(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const MA_WAVEFORMATEX* pFormat, MA_WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } -static MA_INLINE HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient* pThis, MA_WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } +static MA_INLINE HRESULT ma_IAudioClient_IsFormatSupported(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } +static MA_INLINE HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } static MA_INLINE HRESULT ma_IAudioClient_GetDevicePeriod(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); } static MA_INLINE HRESULT ma_IAudioClient_Start(ma_IAudioClient* pThis) { return pThis->lpVtbl->Start(pThis); } static MA_INLINE HRESULT ma_IAudioClient_Stop(ma_IAudioClient* pThis) { return pThis->lpVtbl->Stop(pThis); } @@ -20628,12 +13351,12 @@ typedef struct ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient2* pThis); /* IAudioClient */ - HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); + HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames); HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency); HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames); - HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const MA_WAVEFORMATEX* pFormat, MA_WAVEFORMATEX** ppClosestMatch); - HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient2* pThis, MA_WAVEFORMATEX** ppDeviceFormat); + HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch); + HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat); HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient2* pThis); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient2* pThis); @@ -20644,7 +13367,7 @@ typedef struct /* IAudioClient2 */ HRESULT (STDMETHODCALLTYPE * IsOffloadCapable) (ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable); HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties); - HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient2* pThis, const MA_WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration); + HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration); } ma_IAudioClient2Vtbl; struct ma_IAudioClient2 { @@ -20653,12 +13376,12 @@ struct ma_IAudioClient2 static MA_INLINE HRESULT ma_IAudioClient2_QueryInterface(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } static MA_INLINE ULONG ma_IAudioClient2_AddRef(ma_IAudioClient2* pThis) { return pThis->lpVtbl->AddRef(pThis); } static MA_INLINE ULONG ma_IAudioClient2_Release(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Release(pThis); } -static MA_INLINE HRESULT ma_IAudioClient2_Initialize(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } +static MA_INLINE HRESULT ma_IAudioClient2_Initialize(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSize(ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); } static MA_INLINE HRESULT ma_IAudioClient2_GetStreamLatency(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); } static MA_INLINE HRESULT ma_IAudioClient2_GetCurrentPadding(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); } -static MA_INLINE HRESULT ma_IAudioClient2_IsFormatSupported(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const MA_WAVEFORMATEX* pFormat, MA_WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } -static MA_INLINE HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2* pThis, MA_WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } +static MA_INLINE HRESULT ma_IAudioClient2_IsFormatSupported(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } +static MA_INLINE HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } static MA_INLINE HRESULT ma_IAudioClient2_GetDevicePeriod(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); } static MA_INLINE HRESULT ma_IAudioClient2_Start(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Start(pThis); } static MA_INLINE HRESULT ma_IAudioClient2_Stop(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Stop(pThis); } @@ -20667,7 +13390,7 @@ static MA_INLINE HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2* pThis static MA_INLINE HRESULT ma_IAudioClient2_GetService(ma_IAudioClient2* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); } static MA_INLINE HRESULT ma_IAudioClient2_IsOffloadCapable(ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); } static MA_INLINE HRESULT ma_IAudioClient2_SetClientProperties(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties) { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); } -static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSizeLimits(ma_IAudioClient2* pThis, const MA_WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); } +static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSizeLimits(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); } /* IAudioClient3 */ @@ -20679,12 +13402,12 @@ typedef struct ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient3* pThis); /* IAudioClient */ - HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); + HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames); HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency); HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames); - HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const MA_WAVEFORMATEX* pFormat, MA_WAVEFORMATEX** ppClosestMatch); - HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient3* pThis, MA_WAVEFORMATEX** ppDeviceFormat); + HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch); + HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat); HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient3* pThis); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient3* pThis); @@ -20695,12 +13418,12 @@ typedef struct /* IAudioClient2 */ HRESULT (STDMETHODCALLTYPE * IsOffloadCapable) (ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable); HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties); - HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient3* pThis, const MA_WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration); + HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration); /* IAudioClient3 */ - HRESULT (STDMETHODCALLTYPE * GetSharedModeEnginePeriod) (ma_IAudioClient3* pThis, const MA_WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames); - HRESULT (STDMETHODCALLTYPE * GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3* pThis, MA_WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames); - HRESULT (STDMETHODCALLTYPE * InitializeSharedAudioStream) (ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); + HRESULT (STDMETHODCALLTYPE * GetSharedModeEnginePeriod) (ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames); + HRESULT (STDMETHODCALLTYPE * GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames); + HRESULT (STDMETHODCALLTYPE * InitializeSharedAudioStream) (ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); } ma_IAudioClient3Vtbl; struct ma_IAudioClient3 { @@ -20709,12 +13432,12 @@ struct ma_IAudioClient3 static MA_INLINE HRESULT ma_IAudioClient3_QueryInterface(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } static MA_INLINE ULONG ma_IAudioClient3_AddRef(ma_IAudioClient3* pThis) { return pThis->lpVtbl->AddRef(pThis); } static MA_INLINE ULONG ma_IAudioClient3_Release(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Release(pThis); } -static MA_INLINE HRESULT ma_IAudioClient3_Initialize(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } +static MA_INLINE HRESULT ma_IAudioClient3_Initialize(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSize(ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); } static MA_INLINE HRESULT ma_IAudioClient3_GetStreamLatency(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); } static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentPadding(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); } -static MA_INLINE HRESULT ma_IAudioClient3_IsFormatSupported(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const MA_WAVEFORMATEX* pFormat, MA_WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } -static MA_INLINE HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3* pThis, MA_WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } +static MA_INLINE HRESULT ma_IAudioClient3_IsFormatSupported(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } +static MA_INLINE HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } static MA_INLINE HRESULT ma_IAudioClient3_GetDevicePeriod(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); } static MA_INLINE HRESULT ma_IAudioClient3_Start(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Start(pThis); } static MA_INLINE HRESULT ma_IAudioClient3_Stop(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Stop(pThis); } @@ -20723,10 +13446,10 @@ static MA_INLINE HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3* pThis static MA_INLINE HRESULT ma_IAudioClient3_GetService(ma_IAudioClient3* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); } static MA_INLINE HRESULT ma_IAudioClient3_IsOffloadCapable(ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); } static MA_INLINE HRESULT ma_IAudioClient3_SetClientProperties(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties) { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); } -static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSizeLimits(ma_IAudioClient3* pThis, const MA_WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); } -static MA_INLINE HRESULT ma_IAudioClient3_GetSharedModeEnginePeriod(ma_IAudioClient3* pThis, const MA_WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames) { return pThis->lpVtbl->GetSharedModeEnginePeriod(pThis, pFormat, pDefaultPeriodInFrames, pFundamentalPeriodInFrames, pMinPeriodInFrames, pMaxPeriodInFrames); } -static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3* pThis, MA_WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames) { return pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis, ppFormat, pCurrentPeriodInFrames); } -static MA_INLINE HRESULT ma_IAudioClient3_InitializeSharedAudioStream(ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const MA_WAVEFORMATEX* pFormat, const GUID* pAudioSessionGUID) { return pThis->lpVtbl->InitializeSharedAudioStream(pThis, streamFlags, periodInFrames, pFormat, pAudioSessionGUID); } +static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSizeLimits(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); } +static MA_INLINE HRESULT ma_IAudioClient3_GetSharedModeEnginePeriod(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames) { return pThis->lpVtbl->GetSharedModeEnginePeriod(pThis, pFormat, pDefaultPeriodInFrames, pFundamentalPeriodInFrames, pMinPeriodInFrames, pMaxPeriodInFrames); } +static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames) { return pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis, ppFormat, pCurrentPeriodInFrames); } +static MA_INLINE HRESULT ma_IAudioClient3_InitializeSharedAudioStream(ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGUID) { return pThis->lpVtbl->InitializeSharedAudioStream(pThis, streamFlags, periodInFrames, pFormat, pAudioSessionGUID); } /* IAudioRenderClient */ @@ -20776,16 +13499,8 @@ static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); } static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket) { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); } -#if defined(MA_WIN32_UWP) -/* mmdevapi Functions */ -typedef HRESULT (WINAPI * MA_PFN_ActivateAudioInterfaceAsync)(const wchar_t* deviceInterfacePath, const IID* riid, MA_PROPVARIANT* activationParams, ma_IActivateAudioInterfaceCompletionHandler* completionHandler, ma_IActivateAudioInterfaceAsyncOperation** activationOperation); -#endif - -/* Avrt Functions */ -typedef HANDLE (WINAPI * MA_PFN_AvSetMmThreadCharacteristicsA)(const char* TaskName, DWORD* TaskIndex); -typedef BOOL (WINAPI * MA_PFN_AvRevertMmThreadCharacteristics)(HANDLE AvrtHandle); - -#if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) +#ifndef MA_WIN32_DESKTOP +#include typedef struct ma_completion_handler_uwp ma_completion_handler_uwp; typedef struct @@ -20801,7 +13516,7 @@ typedef struct struct ma_completion_handler_uwp { ma_completion_handler_uwp_vtbl* lpVtbl; - MA_ATOMIC(4, ma_uint32) counter; + MA_ATOMIC ma_uint32 counter; HANDLE hEvent; }; @@ -20824,12 +13539,12 @@ static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_com static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis) { - return (ULONG)ma_atomic_fetch_add_32(&pThis->counter, 1) + 1; + return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1; } static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp* pThis) { - ma_uint32 newRefCount = ma_atomic_fetch_sub_32(&pThis->counter, 1) - 1; + ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1; if (newRefCount == 0) { return 0; /* We don't free anything here because we never allocate the object on the heap. */ } @@ -20859,7 +13574,7 @@ static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHand pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance; pHandler->counter = 1; - pHandler->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + pHandler->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if (pHandler->hEvent == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -20876,12 +13591,12 @@ static void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler static void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler) { - WaitForSingleObject((HANDLE)pHandler->hEvent, INFINITE); + WaitForSingleObject(pHandler->hEvent, INFINITE); } #endif /* !MA_WIN32_DESKTOP */ /* We need a virtual table for our notification client object that's used for detecting changes to the default device. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject) { /* @@ -20901,12 +13616,12 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMN static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient* pThis) { - return (ULONG)ma_atomic_fetch_add_32(&pThis->counter, 1) + 1; + return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1; } static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificationClient* pThis) { - ma_uint32 newRefCount = ma_atomic_fetch_sub_32(&pThis->counter, 1) - 1; + ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1; if (newRefCount == 0) { return 0; /* We don't free anything here because we never allocate the object on the heap. */ } @@ -20914,14 +13629,15 @@ static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificati return (ULONG)newRefCount; } -static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID, DWORD dwNewState) +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState) { ma_bool32 isThisDevice = MA_FALSE; ma_bool32 isCapture = MA_FALSE; ma_bool32 isPlayback = MA_FALSE; + #ifdef MA_DEBUG_OUTPUT - /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)", (unsigned int)dwNewState);*/ + printf("IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)", (unsigned int)dwNewState); #endif /* @@ -20930,14 +13646,14 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(m */ if (pThis->pDevice->wasapi.allowCaptureAutoStreamRouting && (pThis->pDevice->type == ma_device_type_capture || pThis->pDevice->type == ma_device_type_duplex || pThis->pDevice->type == ma_device_type_loopback)) { isCapture = MA_TRUE; - if (ma_strcmp_WCHAR(pThis->pDevice->capture.id.wasapi, pDeviceID) == 0) { + if (wcscmp(pThis->pDevice->capture.id.wasapi, pDeviceID) == 0) { isThisDevice = MA_TRUE; } } if (pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting && (pThis->pDevice->type == ma_device_type_playback || pThis->pDevice->type == ma_device_type_duplex)) { isPlayback = MA_TRUE; - if (ma_strcmp_WCHAR(pThis->pDevice->playback.id.wasapi, pDeviceID) == 0) { + if (wcscmp(pThis->pDevice->playback.id.wasapi, pDeviceID) == 0) { isThisDevice = MA_TRUE; } } @@ -20955,7 +13671,7 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(m use this to determine whether or not we need to automatically start the device when it's plugged back in again. */ - if (ma_device_get_state(pThis->pDevice) == ma_device_state_started) { + if (ma_device_get_state(pThis->pDevice) == MA_STATE_STARTED) { if (isPlayback) { pThis->pDevice->wasapi.isDetachedPlayback = MA_TRUE; } @@ -20998,10 +13714,10 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(m return S_OK; } -static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID) +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID) { #ifdef MA_DEBUG_OUTPUT - /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/ + /*printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/ #endif /* We don't need to worry about this event for our purposes. */ @@ -21010,10 +13726,10 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNo return S_OK; } -static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID) +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID) { #ifdef MA_DEBUG_OUTPUT - /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/ + printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)"); #endif /* We don't need to worry about this event for our purposes. */ @@ -21022,31 +13738,35 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMM return S_OK; } -static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, const WCHAR* pDefaultDeviceID) +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID) { #ifdef MA_DEBUG_OUTPUT - /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)");*/ + printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)"); #endif - (void)role; - - /* We only care about devices with the same data flow as the current device. */ - if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) || - (pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture) || - (pThis->pDevice->type == ma_device_type_loopback && dataFlow != ma_eRender)) { - ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because dataFlow does match device type.\n"); + /* We only ever use the eConsole role in miniaudio. */ + if (role != ma_eConsole) { + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Stream rerouting: role != eConsole\n"); + #endif return S_OK; } - /* We need to consider dataFlow as ma_eCapture if device is ma_device_type_loopback */ - if (pThis->pDevice->type == ma_device_type_loopback) { - dataFlow = ma_eCapture; + /* We only care about devices with the same data flow and role as the current device. */ + if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) || + (pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture)) { + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Stream rerouting abandoned because dataFlow does match device type.\n"); + #endif + return S_OK; } /* Don't do automatic stream routing if we're not allowed. */ if ((dataFlow == ma_eRender && pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting == MA_FALSE) || (dataFlow == ma_eCapture && pThis->pDevice->wasapi.allowCaptureAutoStreamRouting == MA_FALSE)) { - ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because automatic stream routing has been disabled by the device config.\n"); + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Stream rerouting abandoned because automatic stream routing has been disabled by the device config.\n"); + #endif return S_OK; } @@ -21057,64 +13777,55 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged */ if ((dataFlow == ma_eRender && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) || (dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode == ma_share_mode_exclusive)) { - ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because the device shared mode is exclusive.\n"); + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Stream rerouting abandoned because the device shared mode is exclusive.\n"); + #endif return S_OK; } + /* Second attempt at device rerouting. We're going to retrieve the device's state at the time of the route change. We're then going to stop the device, reinitialize the device, and then start - it again if the state before stopping was ma_device_state_started. + it again if the state before stopping was MA_STATE_STARTED. */ { ma_uint32 previousState = ma_device_get_state(pThis->pDevice); ma_bool8 restartDevice = MA_FALSE; - if (previousState == ma_device_state_uninitialized || previousState == ma_device_state_starting) { - ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because the device is in the process of starting.\n"); - return S_OK; - } - - if (previousState == ma_device_state_started) { + if (previousState == MA_STATE_STARTED) { ma_device_stop(pThis->pDevice); restartDevice = MA_TRUE; } if (pDefaultDeviceID != NULL) { /* <-- The input device ID will be null if there's no other device available. */ - ma_mutex_lock(&pThis->pDevice->wasapi.rerouteLock); - { - if (dataFlow == ma_eRender) { - ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback); + if (dataFlow == ma_eRender) { + ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback); - if (pThis->pDevice->wasapi.isDetachedPlayback) { - pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE; - - if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedCapture) { - restartDevice = MA_FALSE; /* It's a duplex device and the capture side is detached. We cannot be restarting the device just yet. */ - } - else { - restartDevice = MA_TRUE; /* It's not a duplex device, or the capture side is also attached so we can go ahead and restart the device. */ - } + if (pThis->pDevice->wasapi.isDetachedPlayback) { + pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE; + + if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedCapture) { + restartDevice = MA_FALSE; /* It's a duplex device and the capture side is detached. We cannot be restarting the device just yet. */ + } else { + restartDevice = MA_TRUE; /* It's not a duplex device, or the capture side is also attached so we can go ahead and restart the device. */ } } - else { - ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture); + } else { + ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture); - if (pThis->pDevice->wasapi.isDetachedCapture) { - pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE; - - if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedPlayback) { - restartDevice = MA_FALSE; /* It's a duplex device and the playback side is detached. We cannot be restarting the device just yet. */ - } - else { - restartDevice = MA_TRUE; /* It's not a duplex device, or the playback side is also attached so we can go ahead and restart the device. */ - } + if (pThis->pDevice->wasapi.isDetachedCapture) { + pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE; + + if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedPlayback) { + restartDevice = MA_FALSE; /* It's a duplex device and the playback side is detached. We cannot be restarting the device just yet. */ + } else { + restartDevice = MA_TRUE; /* It's not a duplex device, or the playback side is also attached so we can go ahead and restart the device. */ } } } - ma_mutex_unlock(&pThis->pDevice->wasapi.rerouteLock); if (restartDevice) { ma_device_start(pThis->pDevice); @@ -21125,10 +13836,10 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged return S_OK; } -static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, const WCHAR* pDeviceID, const PROPERTYKEY key) +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key) { #ifdef MA_DEBUG_OUTPUT - /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/ + /*printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/ #endif (void)pThis; @@ -21149,20 +13860,7 @@ static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = { }; #endif /* MA_WIN32_DESKTOP */ -static const char* ma_to_usage_string__wasapi(ma_wasapi_usage usage) -{ - switch (usage) - { - case ma_wasapi_usage_default: return NULL; - case ma_wasapi_usage_games: return "Games"; - case ma_wasapi_usage_pro_audio: return "Pro Audio"; - default: break; - } - - return NULL; -} - -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP typedef ma_IMMDevice ma_WASAPIDeviceInterface; #else typedef ma_IUnknown ma_WASAPIDeviceInterface; @@ -21176,7 +13874,7 @@ typedef ma_IUnknown ma_WASAPIDeviceInterface; static ma_context_command__wasapi ma_context_init_command__wasapi(int code) { ma_context_command__wasapi cmd; - + MA_ZERO_OBJECT(&cmd); cmd.code = code; @@ -21221,7 +13919,7 @@ static ma_result ma_context_post_command__wasapi(ma_context* pContext, const ma_ /* Now that the command has been added, release the semaphore so ma_context_next_command__wasapi() can return. */ ma_semaphore_release(&pContext->wasapi.commandSem); } - ma_mutex_unlock(&pContext->wasapi.commandLock); + ma_mutex_unlock(&pContext->wasapi.commandLock); if (isUsingLocalEvent) { ma_event_wait(&localEvent); @@ -21247,7 +13945,7 @@ static ma_result ma_context_next_command__wasapi(ma_context* pContext, ma_contex pContext->wasapi.commandCount -= 1; } ma_mutex_unlock(&pContext->wasapi.commandLock); - } + } return result; } @@ -21275,15 +13973,15 @@ static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pU case MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI: { if (cmd.data.createAudioClient.deviceType == ma_device_type_playback) { - *cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioRenderClient, cmd.data.createAudioClient.ppAudioClientService)); + result = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioRenderClient, cmd.data.createAudioClient.ppAudioClientService)); } else { - *cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioCaptureClient, cmd.data.createAudioClient.ppAudioClientService)); + result = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioCaptureClient, cmd.data.createAudioClient.ppAudioClientService)); } } break; case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI: { - if (cmd.data.releaseAudioClient.deviceType == ma_device_type_playback) { + if (cmd.data.releaseAudioClient.deviceType == ma_device_type_playback) { if (cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback != NULL) { ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback); cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback = NULL; @@ -21320,19 +14018,18 @@ static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pU static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService) { ma_result result; - ma_result cmdResult; ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI); cmd.data.createAudioClient.deviceType = deviceType; cmd.data.createAudioClient.pAudioClient = (void*)pAudioClient; cmd.data.createAudioClient.ppAudioClientService = ppAudioClientService; - cmd.data.createAudioClient.pResult = &cmdResult; /* Declared locally, but won't be dereferenced after this function returns since execution of the command will wait here. */ - + cmd.data.createAudioClient.result = MA_SUCCESS; + result = ma_context_post_command__wasapi(pContext, &cmd); /* This will not return until the command has actually been run. */ if (result != MA_SUCCESS) { return result; } - return *cmd.data.createAudioClient.pResult; + return cmd.data.createAudioClient.result; } #if 0 /* Not used at the moment, but leaving here for future use. */ @@ -21353,7 +14050,7 @@ static ma_result ma_device_release_IAudioClient_service__wasapi(ma_device* pDevi #endif -static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const MA_WAVEFORMATEX* pWF, ma_share_mode shareMode, ma_device_info* pInfo) +static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_share_mode shareMode, ma_device_info* pInfo) { MA_ASSERT(pWF != NULL); MA_ASSERT(pInfo != NULL); @@ -21372,26 +14069,25 @@ static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const MA_ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pContext, /*ma_IMMDevice**/void* pMMDevice, ma_IAudioClient* pAudioClient, ma_device_info* pInfo) { HRESULT hr; - MA_WAVEFORMATEX* pWF = NULL; + WAVEFORMATEX* pWF = NULL; MA_ASSERT(pAudioClient != NULL); MA_ASSERT(pInfo != NULL); /* Shared Mode. We use GetMixFormat() here. */ - hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (MA_WAVEFORMATEX**)&pWF); + hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF); if (SUCCEEDED(hr)) { ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_shared, pInfo); } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.", ma_result_from_HRESULT(hr)); } /* - Exclusive Mode. We repeatedly call IsFormatSupported() here. This is not currently supported on + Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently supported on UWP. Failure to retrieve the exclusive mode format is not considered an error, so from here on out, MA_SUCCESS is guaranteed to be returned. */ - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + #ifdef MA_WIN32_DESKTOP { ma_IPropertyStore *pProperties; @@ -21401,12 +14097,12 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context */ hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties); if (SUCCEEDED(hr)) { - MA_PROPVARIANT var; + PROPVARIANT var; ma_PropVariantInit(&var); hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var); if (SUCCEEDED(hr)) { - pWF = (MA_WAVEFORMATEX*)var.blob.pBlobData; + pWF = (WAVEFORMATEX*)var.blob.pBlobData; /* In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format @@ -21421,9 +14117,9 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format. */ - ma_uint32 channels = pWF->nChannels; + ma_uint32 channels = pInfo->minChannels; ma_channel defaultChannelMap[MA_MAX_CHANNELS]; - MA_WAVEFORMATEXTENSIBLE wf; + WAVEFORMATEXTENSIBLE wf; ma_bool32 found; ma_uint32 iFormat; @@ -21432,12 +14128,12 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context channels = MA_MAX_CHANNELS; } - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, defaultChannelMap, ma_countof(defaultChannelMap), channels); + ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap); MA_ZERO_OBJECT(&wf); - wf.cbSize = sizeof(wf); - wf.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.nChannels = (WORD)channels; + wf.Format.cbSize = sizeof(wf); + wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wf.Format.nChannels = (WORD)channels; wf.dwChannelMask = ma_channel_map_to_channel_mask__win32(defaultChannelMap, channels); found = MA_FALSE; @@ -21445,10 +14141,10 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context ma_format format = g_maFormatPriorities[iFormat]; ma_uint32 iSampleRate; - wf.wBitsPerSample = (WORD)(ma_get_bytes_per_sample(format)*8); - wf.nBlockAlign = (WORD)(wf.nChannels * wf.wBitsPerSample / 8); - wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = /*(format == ma_format_s24_32) ? 24 :*/ wf.wBitsPerSample; + wf.Format.wBitsPerSample = (WORD)(ma_get_bytes_per_sample(format)*8); + wf.Format.nBlockAlign = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8); + wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; + wf.Samples.wValidBitsPerSample = /*(format == ma_format_s24_32) ? 24 :*/ wf.Format.wBitsPerSample; if (format == ma_format_f32) { wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } else { @@ -21456,11 +14152,11 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context } for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iSampleRate) { - wf.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate]; + wf.Format.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate]; - hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (MA_WAVEFORMATEX*)&wf, NULL); + hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL); if (SUCCEEDED(hr)) { - ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((MA_WAVEFORMATEX*)&wf, ma_share_mode_exclusive, pInfo); + ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, ma_share_mode_exclusive, pInfo); found = MA_TRUE; break; } @@ -21474,28 +14170,24 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context ma_PropVariantClear(pContext, &var); if (!found) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval."); + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval.", MA_FORMAT_NOT_SUPPORTED); } } } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval."); + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval.", ma_result_from_HRESULT(hr)); } ma_IPropertyStore_Release(pProperties); } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval."); + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval.", ma_result_from_HRESULT(hr)); } } - #else - { - (void)pMMDevice; /* Unused. */ - } #endif return MA_SUCCESS; } -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType) { if (deviceType == ma_device_type_playback) { @@ -21518,10 +14210,9 @@ static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pCont *ppDeviceEnumerator = NULL; /* Safety. */ - hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr)); } *ppDeviceEnumerator = pDeviceEnumerator; @@ -21529,11 +14220,11 @@ static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pCont return MA_SUCCESS; } -static WCHAR* ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType) +static LPWSTR ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType) { HRESULT hr; ma_IMMDevice* pMMDefaultDevice = NULL; - WCHAR* pDefaultDeviceID = NULL; + LPWSTR pDefaultDeviceID = NULL; ma_EDataFlow dataFlow; ma_ERole role; @@ -21565,11 +14256,11 @@ static WCHAR* ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi( return pDefaultDeviceID; } -static WCHAR* ma_context_get_default_device_id__wasapi(ma_context* pContext, ma_device_type deviceType) /* Free the returned pointer with ma_CoTaskMemFree() */ +static LPWSTR ma_context_get_default_device_id__wasapi(ma_context* pContext, ma_device_type deviceType) /* Free the returned pointer with ma_CoTaskMemFree() */ { ma_result result; ma_IMMDeviceEnumerator* pDeviceEnumerator; - WCHAR* pDefaultDeviceID = NULL; + LPWSTR pDefaultDeviceID = NULL; MA_ASSERT(pContext != NULL); @@ -21592,25 +14283,9 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); - /* - This weird COM init/uninit here is a hack to work around a crash when changing devices. What is happening is - WASAPI fires a callback from another thread when the device is changed. It's from that thread where this - function is getting called. What I'm suspecting is that the other thread is not initializing COM which in turn - results in CoCreateInstance() failing. - - The community has reported that this seems to fix the crash. There are future plans to move all WASAPI operation - over to a single thread to make everything safer, but in the meantime while we wait for that to come online I'm - happy enough to use this hack instead. - */ - ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); - { - hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - } - ma_CoUninitialize(pContext); - - if (FAILED(hr)) { /* <-- This is checking the call above to ma_CoCreateInstance(). */ - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); - return ma_result_from_HRESULT(hr); + hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + if (FAILED(hr)) { + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.", ma_result_from_HRESULT(hr)); } if (pDeviceID == NULL) { @@ -21621,8 +14296,7 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.\n"); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.", ma_result_from_HRESULT(hr)); } return MA_SUCCESS; @@ -21630,17 +14304,17 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device static ma_result ma_context_get_device_id_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_device_id* pDeviceID) { - WCHAR* pDeviceIDString; + LPWSTR pDeviceIDString; HRESULT hr; MA_ASSERT(pDeviceID != NULL); hr = ma_IMMDevice_GetId(pMMDevice, &pDeviceIDString); if (SUCCEEDED(hr)) { - size_t idlen = ma_strlen_WCHAR(pDeviceIDString); + size_t idlen = wcslen(pDeviceIDString); if (idlen+1 > ma_countof(pDeviceID->wasapi)) { ma_CoTaskMemFree(pContext, pDeviceIDString); - MA_ASSERT(MA_FALSE); /* NOTE: If this is triggered, please report it. It means the format of the ID must have changed and is too long to fit in our fixed sized buffer. */ + MA_ASSERT(MA_FALSE); /* NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer. */ return MA_ERROR; } @@ -21655,7 +14329,7 @@ static ma_result ma_context_get_device_id_from_MMDevice__wasapi(ma_context* pCon return MA_ERROR; } -static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, WCHAR* pDefaultDeviceID, ma_bool32 onlySimpleInfo, ma_device_info* pInfo) +static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, LPWSTR pDefaultDeviceID, ma_bool32 onlySimpleInfo, ma_device_info* pInfo) { ma_result result; HRESULT hr; @@ -21668,7 +14342,7 @@ static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pC result = ma_context_get_device_id_from_MMDevice__wasapi(pContext, pMMDevice, &pInfo->id); if (result == MA_SUCCESS) { if (pDefaultDeviceID != NULL) { - if (ma_strcmp_WCHAR(pInfo->id.wasapi, pDefaultDeviceID) == 0) { + if (wcscmp(pInfo->id.wasapi, pDefaultDeviceID) == 0) { pInfo->isDefault = MA_TRUE; } } @@ -21679,7 +14353,7 @@ static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pC ma_IPropertyStore *pProperties; hr = ma_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties); if (SUCCEEDED(hr)) { - MA_PROPVARIANT var; + PROPVARIANT var; ma_PropVariantInit(&var); hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &var); @@ -21702,8 +14376,7 @@ static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pC ma_IAudioClient_Release(pAudioClient); return result; } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.", ma_result_from_HRESULT(hr)); } } @@ -21716,7 +14389,7 @@ static ma_result ma_context_enumerate_devices_by_type__wasapi(ma_context* pConte UINT deviceCount; HRESULT hr; ma_uint32 iDevice; - WCHAR* pDefaultDeviceID = NULL; + LPWSTR pDefaultDeviceID = NULL; ma_IMMDeviceCollection* pDeviceCollection = NULL; MA_ASSERT(pContext != NULL); @@ -21730,8 +14403,7 @@ static ma_result ma_context_enumerate_devices_by_type__wasapi(ma_context* pConte if (SUCCEEDED(hr)) { hr = ma_IMMDeviceCollection_GetCount(pDeviceCollection, &deviceCount); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.\n"); - result = ma_result_from_HRESULT(hr); + result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.", ma_result_from_HRESULT(hr)); goto done; } @@ -21770,7 +14442,7 @@ done: return result; } -static ma_result ma_context_get_IAudioClient_Desktop__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, MA_PROPVARIANT* pActivationParams, ma_IAudioClient** ppAudioClient, ma_IMMDevice** ppMMDevice) +static ma_result ma_context_get_IAudioClient_Desktop__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_IMMDevice** ppMMDevice) { ma_result result; HRESULT hr; @@ -21784,7 +14456,7 @@ static ma_result ma_context_get_IAudioClient_Desktop__wasapi(ma_context* pContex return result; } - hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, pActivationParams, (void**)ppAudioClient); + hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)ppAudioClient); if (FAILED(hr)) { return ma_result_from_HRESULT(hr); } @@ -21792,12 +14464,12 @@ static ma_result ma_context_get_IAudioClient_Desktop__wasapi(ma_context* pContex return MA_SUCCESS; } #else -static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, MA_PROPVARIANT* pActivationParams, ma_IAudioClient** ppAudioClient, ma_IUnknown** ppActivatedInterface) +static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_IUnknown** ppActivatedInterface) { ma_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL; ma_completion_handler_uwp completionHandler; IID iid; - WCHAR* iidStr; + LPOLESTR iidStr; HRESULT hr; ma_result result; HRESULT activateResult; @@ -21807,43 +14479,42 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m MA_ASSERT(ppAudioClient != NULL); if (pDeviceID != NULL) { - iidStr = (WCHAR*)pDeviceID->wasapi; + MA_COPY_MEMORY(&iid, pDeviceID->wasapi, sizeof(iid)); } else { - if (deviceType == ma_device_type_capture) { - iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE; - } else { + if (deviceType == ma_device_type_playback) { iid = MA_IID_DEVINTERFACE_AUDIO_RENDER; + } else { + iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE; } + } - #if defined(__cplusplus) - hr = StringFromIID(iid, &iidStr); - #else - hr = StringFromIID(&iid, &iidStr); - #endif - if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.\n"); - return ma_result_from_HRESULT(hr); - } +#if defined(__cplusplus) + hr = StringFromIID(iid, &iidStr); +#else + hr = StringFromIID(&iid, &iidStr); +#endif + if (FAILED(hr)) { + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", ma_result_from_HRESULT(hr)); } result = ma_completion_handler_uwp_init(&completionHandler); if (result != MA_SUCCESS) { ma_CoTaskMemFree(pContext, iidStr); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().\n"); - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", result); } - hr = ((MA_PFN_ActivateAudioInterfaceAsync)pContext->wasapi.ActivateAudioInterfaceAsync)(iidStr, &MA_IID_IAudioClient, pActivationParams, (ma_IActivateAudioInterfaceCompletionHandler*)&completionHandler, (ma_IActivateAudioInterfaceAsyncOperation**)&pAsyncOp); +#if defined(__cplusplus) + hr = ActivateAudioInterfaceAsync(iidStr, MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp); +#else + hr = ActivateAudioInterfaceAsync(iidStr, &MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp); +#endif if (FAILED(hr)) { ma_completion_handler_uwp_uninit(&completionHandler); ma_CoTaskMemFree(pContext, iidStr); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.\n"); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", ma_result_from_HRESULT(hr)); } - if (pDeviceID == NULL) { - ma_CoTaskMemFree(pContext, iidStr); - } + ma_CoTaskMemFree(pContext, iidStr); /* Wait for the async operation for finish. */ ma_completion_handler_uwp_wait(&completionHandler); @@ -21853,15 +14524,13 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp); if (FAILED(hr) || FAILED(activateResult)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.\n"); - return FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult)); } /* Here is where we grab the IAudioClient interface. */ hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.\n"); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", ma_result_from_HRESULT(hr)); } if (ppActivatedInterface) { @@ -21874,121 +14543,27 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m } #endif - -/* https://docs.microsoft.com/en-us/windows/win32/api/audioclientactivationparams/ne-audioclientactivationparams-audioclient_activation_type */ -typedef enum +static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface) { - MA_AUDIOCLIENT_ACTIVATION_TYPE_DEFAULT, - MA_AUDIOCLIENT_ACTIVATION_TYPE_PROCESS_LOOPBACK -} MA_AUDIOCLIENT_ACTIVATION_TYPE; - -/* https://docs.microsoft.com/en-us/windows/win32/api/audioclientactivationparams/ne-audioclientactivationparams-process_loopback_mode */ -typedef enum -{ - MA_PROCESS_LOOPBACK_MODE_INCLUDE_TARGET_PROCESS_TREE, - MA_PROCESS_LOOPBACK_MODE_EXCLUDE_TARGET_PROCESS_TREE -} MA_PROCESS_LOOPBACK_MODE; - -/* https://docs.microsoft.com/en-us/windows/win32/api/audioclientactivationparams/ns-audioclientactivationparams-audioclient_process_loopback_params */ -typedef struct -{ - DWORD TargetProcessId; - MA_PROCESS_LOOPBACK_MODE ProcessLoopbackMode; -} MA_AUDIOCLIENT_PROCESS_LOOPBACK_PARAMS; - -#if defined(_MSC_VER) && !defined(__clang__) - #pragma warning(push) - #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */ - #if defined(__clang__) - #pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */ - #endif -#endif -/* https://docs.microsoft.com/en-us/windows/win32/api/audioclientactivationparams/ns-audioclientactivationparams-audioclient_activation_params */ -typedef struct -{ - MA_AUDIOCLIENT_ACTIVATION_TYPE ActivationType; - union - { - MA_AUDIOCLIENT_PROCESS_LOOPBACK_PARAMS ProcessLoopbackParams; - }; -} MA_AUDIOCLIENT_ACTIVATION_PARAMS; -#if defined(_MSC_VER) && !defined(__clang__) - #pragma warning(pop) -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) - #pragma GCC diagnostic pop -#endif - -#define MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK L"VAD\\Process_Loopback" - -static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_uint32 loopbackProcessID, ma_bool32 loopbackProcessExclude, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface) -{ - ma_result result; - ma_bool32 usingProcessLoopback = MA_FALSE; - MA_AUDIOCLIENT_ACTIVATION_PARAMS audioclientActivationParams; - MA_PROPVARIANT activationParams; - MA_PROPVARIANT* pActivationParams = NULL; - ma_device_id virtualDeviceID; - - /* Activation parameters specific to loopback mode. Note that process-specific loopback will only work when a default device ID is specified. */ - if (deviceType == ma_device_type_loopback && loopbackProcessID != 0 && pDeviceID == NULL) { - usingProcessLoopback = MA_TRUE; - } - - if (usingProcessLoopback) { - MA_ZERO_OBJECT(&audioclientActivationParams); - audioclientActivationParams.ActivationType = MA_AUDIOCLIENT_ACTIVATION_TYPE_PROCESS_LOOPBACK; - audioclientActivationParams.ProcessLoopbackParams.ProcessLoopbackMode = (loopbackProcessExclude) ? MA_PROCESS_LOOPBACK_MODE_EXCLUDE_TARGET_PROCESS_TREE : MA_PROCESS_LOOPBACK_MODE_INCLUDE_TARGET_PROCESS_TREE; - audioclientActivationParams.ProcessLoopbackParams.TargetProcessId = (DWORD)loopbackProcessID; - - ma_PropVariantInit(&activationParams); - activationParams.vt = MA_VT_BLOB; - activationParams.blob.cbSize = sizeof(audioclientActivationParams); - activationParams.blob.pBlobData = (BYTE*)&audioclientActivationParams; - pActivationParams = &activationParams; - - /* When requesting a specific device ID we need to use a special device ID. */ - MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ - pDeviceID = &virtualDeviceID; - } else { - pActivationParams = NULL; /* No activation parameters required. */ - } - -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - result = ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, pActivationParams, ppAudioClient, ppDeviceInterface); +#ifdef MA_WIN32_DESKTOP + return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface); #else - result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, pActivationParams, ppAudioClient, ppDeviceInterface); + return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface); #endif - - /* - If loopback mode was requested with a process ID and initialization failed, it could be because it's - trying to run on an older version of Windows where it's not supported. We need to let the caller - know about this with a log message. - */ - if (result != MA_SUCCESS) { - if (usingProcessLoopback) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Loopback mode requested to %s process ID %u, but initialization failed. Support for this feature begins with Windows 10 Build 20348. Confirm your version of Windows or consider not using process-specific loopback.\n", (loopbackProcessExclude) ? "exclude" : "include", loopbackProcessID); - } - } - - return result; } static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { /* Different enumeration for desktop and UWP. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP /* Desktop */ HRESULT hr; ma_IMMDeviceEnumerator* pDeviceEnumerator; - hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr)); } ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData); @@ -22032,10 +14607,10 @@ static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_e static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) { -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP ma_result result; ma_IMMDevice* pMMDevice = NULL; - WCHAR* pDefaultDeviceID = NULL; + LPWSTR pDefaultDeviceID = NULL; result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice); if (result != MA_SUCCESS) { @@ -22066,7 +14641,7 @@ static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_dev ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } - result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, NULL, &pAudioClient, NULL); + result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, &pAudioClient, NULL); if (result != MA_SUCCESS) { return result; } @@ -22084,35 +14659,17 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - { - if (pDevice->wasapi.pDeviceEnumerator) { - ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient); - ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator); - } - - ma_mutex_uninit(&pDevice->wasapi.rerouteLock); +#ifdef MA_WIN32_DESKTOP + if (pDevice->wasapi.pDeviceEnumerator) { + ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient); + ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator); } - #endif +#endif if (pDevice->wasapi.pRenderClient) { - if (pDevice->wasapi.pMappedBufferPlayback != NULL) { - ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); - pDevice->wasapi.pMappedBufferPlayback = NULL; - pDevice->wasapi.mappedBufferPlaybackCap = 0; - pDevice->wasapi.mappedBufferPlaybackLen = 0; - } - ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); } if (pDevice->wasapi.pCaptureClient) { - if (pDevice->wasapi.pMappedBufferCapture != NULL) { - ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - pDevice->wasapi.mappedBufferCaptureLen = 0; - } - ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); } @@ -22124,10 +14681,10 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice) } if (pDevice->wasapi.hEventPlayback) { - CloseHandle((HANDLE)pDevice->wasapi.hEventPlayback); + CloseHandle(pDevice->wasapi.hEventPlayback); } if (pDevice->wasapi.hEventCapture) { - CloseHandle((HANDLE)pDevice->wasapi.hEventCapture); + CloseHandle(pDevice->wasapi.hEventCapture); } return MA_SUCCESS; @@ -22149,8 +14706,6 @@ typedef struct ma_bool32 noAutoConvertSRC; ma_bool32 noDefaultQualitySRC; ma_bool32 noHardwareOffloading; - ma_uint32 loopbackProcessID; - ma_bool32 loopbackProcessExclude; /* Output. */ ma_IAudioClient* pAudioClient; @@ -22176,11 +14731,10 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device DWORD streamFlags = 0; MA_REFERENCE_TIME periodDurationInMicroseconds; ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE; - MA_WAVEFORMATEXTENSIBLE wf; + WAVEFORMATEXTENSIBLE wf; ma_WASAPIDeviceInterface* pDeviceInterface = NULL; ma_IAudioClient2* pAudioClient2; ma_uint32 nativeSampleRate; - ma_bool32 usingProcessLoopback = MA_FALSE; MA_ASSERT(pContext != NULL); MA_ASSERT(pData != NULL); @@ -22190,8 +14744,6 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device return MA_INVALID_ARGS; } - usingProcessLoopback = deviceType == ma_device_type_loopback && pData->loopbackProcessID != 0 && pDeviceID == NULL; - pData->pAudioClient = NULL; pData->pRenderClient = NULL; pData->pCaptureClient = NULL; @@ -22207,7 +14759,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device streamFlags |= MA_AUDCLNT_STREAMFLAGS_LOOPBACK; } - result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, pData->loopbackProcessID, pData->loopbackProcessExclude, &pData->pAudioClient, &pDeviceInterface); + result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pDeviceInterface); if (result != MA_SUCCESS) { goto done; } @@ -22236,19 +14788,19 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* Here is where we try to determine the best format to use with the device. If the client if wanting exclusive mode, first try finding the best format for that. If this fails, fall back to shared mode. */ result = MA_FORMAT_NOT_SUPPORTED; if (pData->shareMode == ma_share_mode_exclusive) { - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + #ifdef MA_WIN32_DESKTOP /* In exclusive mode on desktop we always use the backend's native format. */ ma_IPropertyStore* pStore = NULL; hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore); if (SUCCEEDED(hr)) { - MA_PROPVARIANT prop; + PROPVARIANT prop; ma_PropVariantInit(&prop); hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop); if (SUCCEEDED(hr)) { - MA_WAVEFORMATEX* pActualFormat = (MA_WAVEFORMATEX*)prop.blob.pBlobData; + WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData; hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL); if (SUCCEEDED(hr)) { - MA_COPY_MEMORY(&wf, pActualFormat, sizeof(MA_WAVEFORMATEXTENSIBLE)); + MA_COPY_MEMORY(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE)); } ma_PropVariantClear(pContext, &prop); @@ -22275,47 +14827,12 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device } } else { /* In shared mode we are always using the format reported by the operating system. */ - MA_WAVEFORMATEXTENSIBLE* pNativeFormat = NULL; - hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (MA_WAVEFORMATEX**)&pNativeFormat); + WAVEFORMATEXTENSIBLE* pNativeFormat = NULL; + hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (WAVEFORMATEX**)&pNativeFormat); if (hr != S_OK) { - /* When using process-specific loopback, GetMixFormat() seems to always fail. */ - if (usingProcessLoopback) { - wf.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - wf.nChannels = 2; - wf.nSamplesPerSec = 44100; - wf.wBitsPerSample = 32; - wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8; - wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; - wf.cbSize = sizeof(MA_WAVEFORMATEX); - - result = MA_SUCCESS; - } else { - result = MA_FORMAT_NOT_SUPPORTED; - } + result = MA_FORMAT_NOT_SUPPORTED; } else { - /* - I've seen cases where cbSize will be set to sizeof(WAVEFORMATEX) even though the structure itself - is given the format tag of WAVE_FORMAT_EXTENSIBLE. If the format tag is WAVE_FORMAT_EXTENSIBLE - want to make sure we copy the whole WAVEFORMATEXTENSIBLE structure. Otherwise we'll have to be - safe and only copy the WAVEFORMATEX part. - */ - if (pNativeFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - MA_COPY_MEMORY(&wf, pNativeFormat, sizeof(MA_WAVEFORMATEXTENSIBLE)); - } else { - /* I've seen a case where cbSize was set to 0. Assume sizeof(WAVEFORMATEX) in this case. */ - size_t cbSize = pNativeFormat->cbSize; - if (cbSize == 0) { - cbSize = sizeof(MA_WAVEFORMATEX); - } - - /* Make sure we don't copy more than the capacity of `wf`. */ - if (cbSize > sizeof(wf)) { - cbSize = sizeof(wf); - } - - MA_COPY_MEMORY(&wf, pNativeFormat, cbSize); - } - + MA_COPY_MEMORY(&wf, pNativeFormat, sizeof(wf)); result = MA_SUCCESS; } @@ -22334,13 +14851,13 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device Override the native sample rate with the one requested by the caller, but only if we're not using the default sample rate. We'll use WASAPI to perform the sample rate conversion. */ - nativeSampleRate = wf.nSamplesPerSec; + nativeSampleRate = wf.Format.nSamplesPerSec; if (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) { - wf.nSamplesPerSec = (pData->sampleRateIn != 0) ? pData->sampleRateIn : MA_DEFAULT_SAMPLE_RATE; - wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; + wf.Format.nSamplesPerSec = (pData->sampleRateIn != 0) ? pData->sampleRateIn : MA_DEFAULT_SAMPLE_RATE; + wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign; } - pData->formatOut = ma_format_from_WAVEFORMATEX((MA_WAVEFORMATEX*)&wf); + pData->formatOut = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)&wf); if (pData->formatOut == ma_format_unknown) { /* The format isn't supported. This is almost certainly because the exclusive mode format isn't supported by miniaudio. We need to return MA_SHARE_MODE_NOT_SUPPORTED @@ -22357,19 +14874,11 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device goto done; } - pData->channelsOut = wf.nChannels; - pData->sampleRateOut = wf.nSamplesPerSec; + pData->channelsOut = wf.Format.nChannels; + pData->sampleRateOut = wf.Format.nSamplesPerSec; - /* - Get the internal channel map based on the channel mask. There is a possibility that GetMixFormat() returns - a WAVEFORMATEX instead of a WAVEFORMATEXTENSIBLE, in which case the channel mask will be undefined. In this - case we'll just use the default channel map. - */ - if (wf.wFormatTag == WAVE_FORMAT_EXTENSIBLE || wf.cbSize >= sizeof(MA_WAVEFORMATEXTENSIBLE)) { - ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut); - } else { - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut); - } + /* Get the internal channel map based on the channel mask. */ + ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut); /* Period size. */ pData->periodsOut = (pData->periodsIn != 0) ? pData->periodsIn : MA_DEFAULT_PERIODS; @@ -22377,34 +14886,34 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device if (pData->periodSizeInFramesOut == 0) { if (pData->periodSizeInMillisecondsIn == 0) { if (pData->performanceProfile == ma_performance_profile_low_latency) { - pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, wf.nSamplesPerSec); + pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, wf.Format.nSamplesPerSec); } else { - pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, wf.nSamplesPerSec); + pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, wf.Format.nSamplesPerSec); } } else { - pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.nSamplesPerSec); + pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.Format.nSamplesPerSec); } } - periodDurationInMicroseconds = ((ma_uint64)pData->periodSizeInFramesOut * 1000 * 1000) / wf.nSamplesPerSec; + periodDurationInMicroseconds = ((ma_uint64)pData->periodSizeInFramesOut * 1000 * 1000) / wf.Format.nSamplesPerSec; /* Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode. */ if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) { - MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10; + MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * 10; /* - If the periodicity is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing + If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing it and trying it again. */ hr = E_FAIL; for (;;) { - hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (MA_WAVEFORMATEX*)&wf, NULL); + hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); if (hr == MA_AUDCLNT_E_INVALID_DEVICE_PERIOD) { if (bufferDuration > 500*10000) { break; } else { - if (bufferDuration == 0) { /* <-- Just a sanity check to prevent an infinite loop. Should never happen, but it makes me feel better. */ + if (bufferDuration == 0) { /* <-- Just a sanity check to prevent an infinit loop. Should never happen, but it makes me feel better. */ break; } @@ -22420,19 +14929,19 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device ma_uint32 bufferSizeInFrames; hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames); if (SUCCEEDED(hr)) { - bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.nSamplesPerSec * bufferSizeInFrames) + 0.5); + bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5); /* Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! */ ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient); - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + #ifdef MA_WIN32_DESKTOP hr = ma_IMMDevice_Activate(pDeviceInterface, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient); #else hr = ma_IUnknown_QueryInterface(pDeviceInterface, &MA_IID_IAudioClient, (void**)&pData->pAudioClient); #endif if (SUCCEEDED(hr)) { - hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (MA_WAVEFORMATEX*)&wf, NULL); + hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); } } } @@ -22461,72 +14970,79 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device any of these flags will result in HRESULT code 0x88890021. The other problem is that calling IAudioClient3_GetSharedModeEnginePeriod() with a sample rate different to that returned by IAudioClient_GetMixFormat() also results in an error. I'm therefore disabling low-latency shared mode with AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ - #ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE - { - if ((streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) == 0 || nativeSampleRate == wf.nSamplesPerSec) { - ma_IAudioClient3* pAudioClient3 = NULL; - hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient3, (void**)&pAudioClient3); +#ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE + if ((streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) == 0 || nativeSampleRate == wf.Format.nSamplesPerSec) { + ma_IAudioClient3* pAudioClient3 = NULL; + hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient3, (void**)&pAudioClient3); + if (SUCCEEDED(hr)) { + ma_uint32 defaultPeriodInFrames; + ma_uint32 fundamentalPeriodInFrames; + ma_uint32 minPeriodInFrames; + ma_uint32 maxPeriodInFrames; + hr = ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3, (WAVEFORMATEX*)&wf, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames); if (SUCCEEDED(hr)) { - ma_uint32 defaultPeriodInFrames; - ma_uint32 fundamentalPeriodInFrames; - ma_uint32 minPeriodInFrames; - ma_uint32 maxPeriodInFrames; - hr = ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3, (MA_WAVEFORMATEX*)&wf, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames); - if (SUCCEEDED(hr)) { - ma_uint32 desiredPeriodInFrames = pData->periodSizeInFramesOut; - ma_uint32 actualPeriodInFrames = desiredPeriodInFrames; + ma_uint32 desiredPeriodInFrames = pData->periodSizeInFramesOut; + ma_uint32 actualPeriodInFrames = desiredPeriodInFrames; - /* Make sure the period size is a multiple of fundamentalPeriodInFrames. */ - actualPeriodInFrames = actualPeriodInFrames / fundamentalPeriodInFrames; - actualPeriodInFrames = actualPeriodInFrames * fundamentalPeriodInFrames; + /* Make sure the period size is a multiple of fundamentalPeriodInFrames. */ + actualPeriodInFrames = actualPeriodInFrames / fundamentalPeriodInFrames; + actualPeriodInFrames = actualPeriodInFrames * fundamentalPeriodInFrames; - /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */ - actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames); + /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */ + actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " defaultPeriodInFrames=%d\n", defaultPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " minPeriodInFrames=%d\n", minPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " maxPeriodInFrames=%d\n", maxPeriodInFrames); + #if defined(MA_DEBUG_OUTPUT) + printf("[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames); + printf(" defaultPeriodInFrames=%d\n", defaultPeriodInFrames); + printf(" fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames); + printf(" minPeriodInFrames=%d\n", minPeriodInFrames); + printf(" maxPeriodInFrames=%d\n", maxPeriodInFrames); + #endif - /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */ - if (actualPeriodInFrames >= desiredPeriodInFrames) { - /* - MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY must not be in the stream flags. If either of these are specified, - IAudioClient3_InitializeSharedAudioStream() will fail. - */ - hr = ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3, streamFlags & ~(MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY), actualPeriodInFrames, (MA_WAVEFORMATEX*)&wf, NULL); - if (SUCCEEDED(hr)) { - wasInitializedUsingIAudioClient3 = MA_TRUE; - pData->periodSizeInFramesOut = actualPeriodInFrames; - - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut); - } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n"); - } + /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */ + if (actualPeriodInFrames >= desiredPeriodInFrames) { + /* + MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY must not be in the stream flags. If either of these are specified, + IAudioClient3_InitializeSharedAudioStream() will fail. + */ + hr = ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3, streamFlags & ~(MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY), actualPeriodInFrames, (WAVEFORMATEX*)&wf, NULL); + if (SUCCEEDED(hr)) { + wasInitializedUsingIAudioClient3 = MA_TRUE; + pData->periodSizeInFramesOut = actualPeriodInFrames; + #if defined(MA_DEBUG_OUTPUT) + printf("[WASAPI] Using IAudioClient3\n"); + printf(" periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut); + #endif } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Not using IAudioClient3 because the desired period size is larger than the maximum supported by IAudioClient3.\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n"); + #endif } } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[WASAPI] Not using IAudioClient3 because the desired period size is larger than the maximum supported by IAudioClient3.\n"); + #endif } - - ma_IAudioClient3_Release(pAudioClient3); - pAudioClient3 = NULL; + } else { + #if defined(MA_DEBUG_OUTPUT) + printf("[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n"); + #endif } + + ma_IAudioClient3_Release(pAudioClient3); + pAudioClient3 = NULL; } } - #else - { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Not using IAudioClient3 because MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE is enabled.\n"); - } - #endif +#else + #if defined(MA_DEBUG_OUTPUT) + printf("[WASAPI] Not using IAudioClient3 because MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE is enabled.\n"); + #endif +#endif /* If we don't have an IAudioClient3 then we need to use the normal initialization routine. */ if (!wasInitializedUsingIAudioClient3) { MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10; /* <-- Multiply by 10 for microseconds to 100-nanoseconds. */ - hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, 0, (const MA_WAVEFORMATEX*)&wf, NULL); + hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL); if (FAILED(hr)) { if (hr == E_ACCESSDENIED) { errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MA_ACCESS_DENIED; @@ -22542,28 +15058,19 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device } if (!wasInitializedUsingIAudioClient3) { - ma_uint32 bufferSizeInFrames = 0; + ma_uint32 bufferSizeInFrames; hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames); if (FAILED(hr)) { errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = ma_result_from_HRESULT(hr); goto done; } - /* - When using process loopback mode, retrieval of the buffer size seems to result in totally - incorrect values. In this case we'll just assume it's the same size as what we requested - when we initialized the client. - */ - if (usingProcessLoopback) { - bufferSizeInFrames = (ma_uint32)((periodDurationInMicroseconds * pData->periodsOut) * pData->sampleRateOut / 1000000); - } - pData->periodSizeInFramesOut = bufferSizeInFrames / pData->periodsOut; } pData->usingAudioClient3 = wasInitializedUsingIAudioClient3; - + if (deviceType == ma_device_type_playback) { result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pRenderClient); } else { @@ -22578,12 +15085,12 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* Grab the name of the device. */ - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + #ifdef MA_WIN32_DESKTOP { ma_IPropertyStore *pProperties; hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties); if (SUCCEEDED(hr)) { - MA_PROPVARIANT varName; + PROPVARIANT varName; ma_PropVariantInit(&varName); hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &varName); if (SUCCEEDED(hr)) { @@ -22601,7 +15108,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device stream routing so that IDs can be compared and we can determine which device has been detached and whether or not it matches with our ma_device. */ - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + #ifdef MA_WIN32_DESKTOP { /* Desktop */ ma_context_get_device_id_from_MMDevice__wasapi(pContext, pDeviceInterface, &pData->id); @@ -22615,7 +15122,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device done: /* Clean up. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP if (pDeviceInterface != NULL) { ma_IMMDevice_Release(pDeviceInterface); } @@ -22640,7 +15147,7 @@ done: } if (errorMsg != NULL && errorMsg[0] != '\0') { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "%s\n", errorMsg); + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, errorMsg, result); } return result; @@ -22717,8 +15224,6 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev data.noAutoConvertSRC = pDevice->wasapi.noAutoConvertSRC; data.noDefaultQualitySRC = pDevice->wasapi.noDefaultQualitySRC; data.noHardwareOffloading = pDevice->wasapi.noHardwareOffloading; - data.loopbackProcessID = pDevice->wasapi.loopbackProcessID; - data.loopbackProcessExclude = pDevice->wasapi.loopbackProcessExclude; result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, NULL, &data); if (result != MA_SUCCESS) { return result; @@ -22737,13 +15242,13 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev pDevice->capture.internalPeriods = data.periodsOut; ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName); - ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, (HANDLE)pDevice->wasapi.hEventCapture); + ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture); /* We must always have a valid ID. */ - ma_strcpy_s_WCHAR(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); + ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); } if (deviceType == ma_device_type_playback) { @@ -22758,13 +15263,13 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev pDevice->playback.internalPeriods = data.periodsOut; ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName); - ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, (HANDLE)pDevice->wasapi.hEventPlayback); + ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback); - /* We must always have a valid ID because rerouting will look at it. */ - ma_strcpy_s_WCHAR(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); + /* We must always have a valid ID. */ + ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); } return MA_SUCCESS; @@ -22774,7 +15279,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf { ma_result result = MA_SUCCESS; -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP HRESULT hr; ma_IMMDeviceEnumerator* pDeviceEnumerator; #endif @@ -22782,12 +15287,9 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf MA_ASSERT(pDevice != NULL); MA_ZERO_OBJECT(&pDevice->wasapi); - pDevice->wasapi.usage = pConfig->wasapi.usage; - pDevice->wasapi.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC; - pDevice->wasapi.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC; - pDevice->wasapi.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading; - pDevice->wasapi.loopbackProcessID = pConfig->wasapi.loopbackProcessID; - pDevice->wasapi.loopbackProcessExclude = pConfig->wasapi.loopbackProcessExclude; + pDevice->wasapi.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC; + pDevice->wasapi.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC; + pDevice->wasapi.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading; /* Exclusive mode is not allowed with loopback. */ if (pConfig->deviceType == ma_device_type_loopback && pConfig->playback.shareMode == ma_share_mode_exclusive) { @@ -22808,8 +15310,6 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf data.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC; data.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC; data.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading; - data.loopbackProcessID = pConfig->wasapi.loopbackProcessID; - data.loopbackProcessExclude = pConfig->wasapi.loopbackProcessExclude; result = ma_device_init_internal__wasapi(pDevice->pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture, pDescriptorCapture->pDeviceID, &data); if (result != MA_SUCCESS) { @@ -22827,7 +15327,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled, however, because we want to block until we actually have something for the first call to ma_device_read(). */ - pDevice->wasapi.hEventCapture = (ma_handle)CreateEventA(NULL, FALSE, FALSE, NULL); /* Auto reset, unsignaled by default. */ + pDevice->wasapi.hEventCapture = CreateEventW(NULL, FALSE, FALSE, NULL); /* Auto reset, unsignaled by default. */ if (pDevice->wasapi.hEventCapture == NULL) { result = ma_result_from_GetLastError(GetLastError()); @@ -22840,16 +15340,15 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf pDevice->wasapi.pAudioClientCapture = NULL; } - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.", result); } - ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, (HANDLE)pDevice->wasapi.hEventCapture); + ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture); /* We must always have a valid ID. */ - ma_strcpy_s_WCHAR(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); + ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); /* The descriptor needs to be updated with actual values. */ pDescriptorCapture->format = data.formatOut; @@ -22874,8 +15373,6 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf data.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC; data.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC; data.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading; - data.loopbackProcessID = pConfig->wasapi.loopbackProcessID; - data.loopbackProcessExclude = pConfig->wasapi.loopbackProcessExclude; result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data); if (result != MA_SUCCESS) { @@ -22889,7 +15386,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf pDevice->wasapi.pAudioClientCapture = NULL; } - CloseHandle((HANDLE)pDevice->wasapi.hEventCapture); + CloseHandle(pDevice->wasapi.hEventCapture); pDevice->wasapi.hEventCapture = NULL; } return result; @@ -22909,7 +15406,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf The playback event also needs to be initially set to a signaled state so that the first call to ma_device_write() is able to get passed WaitForMultipleObjects(). */ - pDevice->wasapi.hEventPlayback = (ma_handle)CreateEventA(NULL, FALSE, TRUE, NULL); /* Auto reset, signaled by default. */ + pDevice->wasapi.hEventPlayback = CreateEventW(NULL, FALSE, TRUE, NULL); /* Auto reset, signaled by default. */ if (pDevice->wasapi.hEventPlayback == NULL) { result = ma_result_from_GetLastError(GetLastError()); @@ -22923,7 +15420,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf pDevice->wasapi.pAudioClientCapture = NULL; } - CloseHandle((HANDLE)pDevice->wasapi.hEventCapture); + CloseHandle(pDevice->wasapi.hEventCapture); pDevice->wasapi.hEventCapture = NULL; } @@ -22936,16 +15433,15 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf pDevice->wasapi.pAudioClientPlayback = NULL; } - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.", result); } - ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, (HANDLE)pDevice->wasapi.hEventPlayback); + ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback); - /* We must always have a valid ID because rerouting will look at it. */ - ma_strcpy_s_WCHAR(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); + /* We must always have a valid ID. */ + ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); /* The descriptor needs to be updated with actual values. */ pDescriptorPlayback->format = data.formatOut; @@ -22961,9 +15457,9 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf we are connecting to the default device we want to do automatic stream routing when the device is disabled or unplugged. Otherwise we want to just stop the device outright and let the application handle it. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#ifdef MA_WIN32_DESKTOP if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) { - if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) && pConfig->capture.pDeviceID == NULL) { + if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) { pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE; } if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) { @@ -22971,13 +15467,10 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf } } - ma_mutex_init(&pDevice->wasapi.rerouteLock); - - hr = ma_CoCreateInstance(pDevice->pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { ma_device_uninit__wasapi(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr)); } pDevice->wasapi.notificationClient.lpVtbl = (void*)&g_maNotificationCientVtbl; @@ -22993,8 +15486,8 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf } #endif - ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); - ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); + c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); return MA_SUCCESS; } @@ -23038,16 +15531,16 @@ static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_ } if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { - *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback - paddingFramesCount; + *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback - paddingFramesCount; } else { *pFrameCount = paddingFramesCount; } } else { /* Exclusive mode. */ if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { - *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback; + *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback; } else { - *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesCapture; + *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesCapture; } } @@ -23063,183 +15556,40 @@ static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type de return MA_INVALID_ARGS; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== CHANGING DEVICE ===\n"); +#ifdef MA_DEBUG_OUTPUT + printf("=== CHANGING DEVICE ===\n"); +#endif result = ma_device_reinit__wasapi(pDevice, deviceType); if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WASAPI] Reinitializing device after route change failed.\n"); + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Reinitializing device after route change failed.\n"); + #endif return result; } ma_device__post_init_setup(pDevice, deviceType); - ma_device__on_notification_rerouted(pDevice); - - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== DEVICE CHANGED ===\n"); - - return MA_SUCCESS; -} - -static ma_result ma_device_start__wasapi_nolock(ma_device* pDevice) -{ - HRESULT hr; - - if (pDevice->pContext->wasapi.hAvrt) { - const char* pTaskName = ma_to_usage_string__wasapi(pDevice->wasapi.usage); - if (pTaskName) { - DWORD idx = 0; - pDevice->wasapi.hAvrtHandle = (ma_handle)((MA_PFN_AvSetMmThreadCharacteristicsA)pDevice->pContext->wasapi.AvSetMmThreadCharacteristicsA)(pTaskName, &idx); - } - } - - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { - hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); - if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device. HRESULT = %d.", (int)hr); - return ma_result_from_HRESULT(hr); - } - - ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_TRUE); - } - - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); - if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device. HRESULT = %d.", (int)hr); - return ma_result_from_HRESULT(hr); - } - - ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_TRUE); - } return MA_SUCCESS; } static ma_result ma_device_start__wasapi(ma_device* pDevice) { - ma_result result; - - MA_ASSERT(pDevice != NULL); - - /* Wait for any rerouting to finish before attempting to start the device. */ - ma_mutex_lock(&pDevice->wasapi.rerouteLock); - { - result = ma_device_start__wasapi_nolock(pDevice); - } - ma_mutex_unlock(&pDevice->wasapi.rerouteLock); - - return result; -} - -static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) -{ - ma_result result; HRESULT hr; MA_ASSERT(pDevice != NULL); - if (pDevice->wasapi.hAvrtHandle) { - ((MA_PFN_AvRevertMmThreadCharacteristics)pDevice->pContext->wasapi.AvRevertMmThreadcharacteristics)((HANDLE)pDevice->wasapi.hAvrtHandle); - pDevice->wasapi.hAvrtHandle = NULL; - } - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { - /* If we have a mapped buffer we need to release it. */ - if (pDevice->wasapi.pMappedBufferCapture != NULL) { - ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - pDevice->wasapi.mappedBufferCaptureLen = 0; - } - - hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device.", ma_result_from_HRESULT(hr)); } - /* The audio client needs to be reset otherwise restarting will fail. */ - hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); - if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device."); - return ma_result_from_HRESULT(hr); - } - - ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); + c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - if (pDevice->wasapi.pMappedBufferPlayback != NULL) { - ma_silence_pcm_frames( - ma_offset_pcm_frames_ptr(pDevice->wasapi.pMappedBufferPlayback, pDevice->wasapi.mappedBufferPlaybackLen, pDevice->playback.internalFormat, pDevice->playback.internalChannels), - pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen, - pDevice->playback.internalFormat, pDevice->playback.internalChannels - ); - ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); - pDevice->wasapi.pMappedBufferPlayback = NULL; - pDevice->wasapi.mappedBufferPlaybackCap = 0; - pDevice->wasapi.mappedBufferPlaybackLen = 0; - } - - /* - The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to - the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played. - */ - if (ma_atomic_bool32_get(&pDevice->wasapi.isStartedPlayback)) { - /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */ - DWORD waitTime = (pDevice->wasapi.actualBufferSizeInFramesPlayback * 1000) / pDevice->playback.internalSampleRate; - - if (pDevice->playback.shareMode == ma_share_mode_exclusive) { - WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); - } else { - ma_uint32 prevFramesAvailablePlayback = (ma_uint32)-1; - ma_uint32 framesAvailablePlayback; - for (;;) { - result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); - if (result != MA_SUCCESS) { - break; - } - - if (framesAvailablePlayback >= pDevice->wasapi.actualBufferSizeInFramesPlayback) { - break; - } - - /* - Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames - has not changed, get out of the loop. I don't think this should ever happen, but I think it's nice to have just in case. - */ - if (framesAvailablePlayback == prevFramesAvailablePlayback) { - break; - } - prevFramesAvailablePlayback = framesAvailablePlayback; - - ResetEvent((HANDLE)pDevice->wasapi.hEventPlayback); /* Manual reset. */ - WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); - } - } - } - - hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); - if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device."); - return ma_result_from_HRESULT(hr); - } - - /* The audio client needs to be reset otherwise restarting will fail. */ - { - ma_int32 retries = 5; - - while ((hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback)) == MA_AUDCLNT_E_BUFFER_OPERATION_PENDING && retries > 0) { - ma_sleep(10); - retries -= 1; - } - } - - if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device."); - return ma_result_from_HRESULT(hr); - } - - ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + /* No need to do anything for playback as that'll be started automatically in the data loop. */ } return MA_SUCCESS; @@ -23248,17 +15598,79 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) static ma_result ma_device_stop__wasapi(ma_device* pDevice) { ma_result result; + HRESULT hr; MA_ASSERT(pDevice != NULL); - /* Wait for any rerouting to finish before attempting to stop the device. */ - ma_mutex_lock(&pDevice->wasapi.rerouteLock); - { - result = ma_device_stop__wasapi_nolock(pDevice); - } - ma_mutex_unlock(&pDevice->wasapi.rerouteLock); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + if (FAILED(hr)) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.", ma_result_from_HRESULT(hr)); + } - return result; + /* The audio client needs to be reset otherwise restarting will fail. */ + hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + if (FAILED(hr)) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.", ma_result_from_HRESULT(hr)); + } + + c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + /* + The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to + the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played. + */ + if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { + /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */ + DWORD waitTime = pDevice->wasapi.actualPeriodSizeInFramesPlayback / pDevice->playback.internalSampleRate; + + if (pDevice->playback.shareMode == ma_share_mode_exclusive) { + WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime); + } else { + ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1; + ma_uint32 framesAvailablePlayback; + for (;;) { + result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); + if (result != MA_SUCCESS) { + break; + } + + if (framesAvailablePlayback >= pDevice->wasapi.actualPeriodSizeInFramesPlayback) { + break; + } + + /* + Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames + has not changed, get out of the loop. I don't think this should ever happen, but I think it's nice to have just in case. + */ + if (framesAvailablePlayback == prevFramesAvaialablePlayback) { + break; + } + prevFramesAvaialablePlayback = framesAvailablePlayback; + + WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime); + ResetEvent(pDevice->wasapi.hEventPlayback); /* Manual reset. */ + } + } + } + + hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + if (FAILED(hr)) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.", ma_result_from_HRESULT(hr)); + } + + /* The audio client needs to be reset otherwise restarting will fail. */ + hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + if (FAILED(hr)) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.", ma_result_from_HRESULT(hr)); + } + + c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + } + + return MA_SUCCESS; } @@ -23266,294 +15678,520 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) #define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000 #endif -static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) +static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) { - ma_result result = MA_SUCCESS; - ma_uint32 totalFramesProcessed = 0; + ma_result result; + HRESULT hr; + ma_bool32 exitLoop = MA_FALSE; + ma_uint32 framesWrittenToPlaybackDevice = 0; + ma_uint32 mappedDeviceBufferSizeInFramesCapture = 0; + ma_uint32 mappedDeviceBufferSizeInFramesPlayback = 0; + ma_uint32 mappedDeviceBufferFramesRemainingCapture = 0; + ma_uint32 mappedDeviceBufferFramesRemainingPlayback = 0; + BYTE* pMappedDeviceBufferCapture = NULL; + BYTE* pMappedDeviceBufferPlayback = NULL; + ma_uint32 bpfCaptureDevice = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + ma_uint32 bpfPlaybackDevice = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + ma_uint32 bpfCaptureClient = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 bpfPlaybackClient = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint8 inputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 inputDataInClientFormatCap = 0; + ma_uint8 outputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 outputDataInClientFormatCap = 0; + ma_uint32 outputDataInClientFormatCount = 0; + ma_uint32 outputDataInClientFormatConsumed = 0; + ma_uint32 periodSizeInFramesCapture = 0; - /* - When reading, we need to get a buffer and process all of it before releasing it. Because the - frame count (frameCount) can be different to the size of the buffer, we'll need to cache the - pointer to the buffer. - */ + MA_ASSERT(pDevice != NULL); - /* Keep running until we've processed the requested number of frames. */ - while (ma_device_get_state(pDevice) == ma_device_state_started && totalFramesProcessed < frameCount) { - ma_uint32 framesRemaining = frameCount - totalFramesProcessed; + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + periodSizeInFramesCapture = pDevice->capture.internalPeriodSizeInFrames; + inputDataInClientFormatCap = sizeof(inputDataInClientFormat) / bpfCaptureClient; + } - /* If we have a mapped data buffer, consume that first. */ - if (pDevice->wasapi.pMappedBufferCapture != NULL) { - /* We have a cached data pointer so consume that before grabbing another one from WASAPI. */ - ma_uint32 framesToProcessNow = framesRemaining; - if (framesToProcessNow > pDevice->wasapi.mappedBufferCaptureLen) { - framesToProcessNow = pDevice->wasapi.mappedBufferCaptureLen; - } + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + outputDataInClientFormatCap = sizeof(outputDataInClientFormat) / bpfPlaybackClient; + } - /* Now just copy the data over to the output buffer. */ - ma_copy_pcm_frames( - ma_offset_pcm_frames_ptr(pFrames, totalFramesProcessed, pDevice->capture.internalFormat, pDevice->capture.internalChannels), - ma_offset_pcm_frames_const_ptr(pDevice->wasapi.pMappedBufferCapture, pDevice->wasapi.mappedBufferCaptureCap - pDevice->wasapi.mappedBufferCaptureLen, pDevice->capture.internalFormat, pDevice->capture.internalChannels), - framesToProcessNow, - pDevice->capture.internalFormat, pDevice->capture.internalChannels - ); + while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) { + switch (pDevice->type) + { + case ma_device_type_duplex: + { + ma_uint32 framesAvailableCapture; + ma_uint32 framesAvailablePlayback; + DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */ - totalFramesProcessed += framesToProcessNow; - pDevice->wasapi.mappedBufferCaptureLen -= framesToProcessNow; + /* The process is to map the playback buffer and fill it as quickly as possible from input data. */ + if (pMappedDeviceBufferPlayback == NULL) { + result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); + if (result != MA_SUCCESS) { + return result; + } - /* If the data buffer has been fully consumed we need to release it. */ - if (pDevice->wasapi.mappedBufferCaptureLen == 0) { - ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - } - } else { - /* We don't have any cached data pointer, so grab another one. */ - HRESULT hr; - DWORD flags = 0; + /*printf("TRACE 1: framesAvailablePlayback=%d\n", framesAvailablePlayback);*/ - /* First just ask WASAPI for a data buffer. If it's not available, we'll wait for more. */ - hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL); - if (hr == S_OK) { - /* We got a data buffer. Continue to the next loop iteration which will then read from the mapped pointer. */ - pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap; - /* - There have been reports that indicate that at times the AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY is reported for every - call to IAudioCaptureClient_GetBuffer() above which results in spamming of the debug messages below. To partially - work around this, I'm only outputting these messages when MA_DEBUG_OUTPUT is explicitly defined. The better solution - would be to figure out why the flag is always getting reported. - */ - #if defined(MA_DEBUG_OUTPUT) - { - if (flags != 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags); - - if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=%d\n", pDevice->wasapi.mappedBufferCaptureCap); + /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */ + if (pDevice->playback.shareMode != ma_share_mode_exclusive) { + if (framesAvailablePlayback > pDevice->wasapi.periodSizeInFramesPlayback) { + framesAvailablePlayback = pDevice->wasapi.periodSizeInFramesPlayback; } } + + /* We're ready to map the playback device's buffer. We don't release this until it's been entirely filled. */ + hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + mappedDeviceBufferSizeInFramesPlayback = framesAvailablePlayback; + mappedDeviceBufferFramesRemainingPlayback = framesAvailablePlayback; } - #endif - /* Overrun detection. */ - if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { - /* Glitched. Probably due to an overrun. */ + if (mappedDeviceBufferFramesRemainingPlayback > 0) { + /* At this point we should have a buffer available for output. We need to keep writing input samples to it. */ + for (;;) { + /* Try grabbing some captured data if we haven't already got a mapped buffer. */ + if (pMappedDeviceBufferCapture == NULL) { + if (pDevice->capture.shareMode == ma_share_mode_shared) { + if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + return MA_ERROR; /* Wait failed. */ + } + } - /* - If we got an overrun it probably means we're straddling the end of the buffer. In normal capture - mode this is the fault of the client application because they're responsible for ensuring data is - processed fast enough. In duplex mode, however, the processing of audio is tied to the playback - device, so this can possibly be the result of a timing de-sync. - - In capture mode we're not going to do any kind of recovery because the real fix is for the client - application to process faster. In duplex mode, we'll treat this as a desync and reset the buffers - to prevent a never-ending sequence of glitches due to straddling the end of the buffer. - */ - if (pDevice->type == ma_device_type_duplex) { - /* - Experiment: - - If we empty out the *entire* buffer we may end up putting ourselves into an underrun position - which isn't really any better than the overrun we're probably in right now. Instead we'll just - empty out about half. - */ - ma_uint32 i; - ma_uint32 periodCount = (pDevice->wasapi.actualBufferSizeInFramesCapture / pDevice->wasapi.periodSizeInFramesCapture); - ma_uint32 iterationCount = periodCount / 2; - if ((periodCount % 2) > 0) { - iterationCount += 1; - } - - for (i = 0; i < iterationCount; i += 1) { - hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_ReleaseBuffer() failed with %ld.\n", hr); + result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture); + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; break; } - flags = 0; - hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL); - if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || FAILED(hr)) { - /* - The buffer has been completely emptied or an error occurred. In this case we'll need - to reset the state of the mapped buffer which will trigger the next iteration to get - a fresh buffer from WASAPI. - */ - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - pDevice->wasapi.mappedBufferCaptureLen = 0; + /*printf("TRACE 2: framesAvailableCapture=%d\n", framesAvailableCapture);*/ - if (hr == MA_AUDCLNT_S_BUFFER_EMPTY) { - if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied, and data discontinuity still reported.\n"); - } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied.\n"); + /* Wait for more if nothing is available. */ + if (framesAvailableCapture == 0) { + /* In exclusive mode we waited at the top. */ + if (pDevice->capture.shareMode != ma_share_mode_shared) { + if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + return MA_ERROR; /* Wait failed. */ } } - if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_GetBuffer() failed with %ld.\n", hr); + continue; + } + + /* Getting here means there's data available for writing to the output device. */ + mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture); + hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + + /* Overrun detection. */ + if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { + /* Glitched. Probably due to an overrun. */ + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); + #endif + + /* + Exeriment: If we get an overrun it probably means we're straddling the end of the buffer. In order to prevent a never-ending sequence of glitches let's experiment + by dropping every frame until we're left with only a single period. To do this we just keep retrieving and immediately releasing buffers until we're down to the + last period. + */ + if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) { + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Synchronizing capture stream. "); + #endif + do + { + hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); + if (FAILED(hr)) { + break; + } + + framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture; + + if (framesAvailableCapture > 0) { + mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture); + hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + } else { + pMappedDeviceBufferCapture = NULL; + mappedDeviceBufferSizeInFramesCapture = 0; + } + } while (framesAvailableCapture > periodSizeInFramesCapture); + #ifdef MA_DEBUG_OUTPUT + printf("framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); + #endif + } + } else { + #ifdef MA_DEBUG_OUTPUT + if (flagsCapture != 0) { + printf("[WASAPI] Capture Flags: %ld\n", flagsCapture); + } + #endif + } + + mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture; + } + + + /* At this point we should have both input and output data available. We now need to convert the data and post it to the client. */ + for (;;) { + BYTE* pRunningDeviceBufferCapture; + BYTE* pRunningDeviceBufferPlayback; + ma_uint32 framesToProcess; + ma_uint32 framesProcessed; + + pRunningDeviceBufferCapture = pMappedDeviceBufferCapture + ((mappedDeviceBufferSizeInFramesCapture - mappedDeviceBufferFramesRemainingCapture ) * bpfCaptureDevice); + pRunningDeviceBufferPlayback = pMappedDeviceBufferPlayback + ((mappedDeviceBufferSizeInFramesPlayback - mappedDeviceBufferFramesRemainingPlayback) * bpfPlaybackDevice); + + /* There may be some data sitting in the converter that needs to be processed first. Once this is exhaused, run the data callback again. */ + if (!pDevice->playback.converter.isPassthrough && outputDataInClientFormatConsumed < outputDataInClientFormatCount) { + ma_uint64 convertedFrameCountClient = (outputDataInClientFormatCount - outputDataInClientFormatConsumed); + ma_uint64 convertedFrameCountDevice = mappedDeviceBufferFramesRemainingPlayback; + void* pConvertedFramesClient = outputDataInClientFormat + (outputDataInClientFormatConsumed * bpfPlaybackClient); + void* pConvertedFramesDevice = pRunningDeviceBufferPlayback; + result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesClient, &convertedFrameCountClient, pConvertedFramesDevice, &convertedFrameCountDevice); + if (result != MA_SUCCESS) { + break; } - break; + outputDataInClientFormatConsumed += (ma_uint32)convertedFrameCountClient; /* Safe cast. */ + mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)convertedFrameCountDevice; /* Safe cast. */ + + if (mappedDeviceBufferFramesRemainingPlayback == 0) { + break; + } + } + + /* + Getting here means we need to fire the callback. If format conversion is unnecessary, we can optimize this by passing the pointers to the internal + buffers directly to the callback. + */ + if (pDevice->capture.converter.isPassthrough && pDevice->playback.converter.isPassthrough) { + /* Optimal path. We can pass mapped pointers directly to the callback. */ + framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback); + framesProcessed = framesToProcess; + + ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess); + + mappedDeviceBufferFramesRemainingCapture -= framesProcessed; + mappedDeviceBufferFramesRemainingPlayback -= framesProcessed; + + if (mappedDeviceBufferFramesRemainingCapture == 0) { + break; /* Exhausted input data. */ + } + if (mappedDeviceBufferFramesRemainingPlayback == 0) { + break; /* Exhausted output data. */ + } + } else if (pDevice->capture.converter.isPassthrough) { + /* The input buffer is a passthrough, but the playback buffer requires a conversion. */ + framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap); + framesProcessed = framesToProcess; + + ma_device__on_data(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess); + outputDataInClientFormatCount = framesProcessed; + outputDataInClientFormatConsumed = 0; + + mappedDeviceBufferFramesRemainingCapture -= framesProcessed; + if (mappedDeviceBufferFramesRemainingCapture == 0) { + break; /* Exhausted input data. */ + } + } else if (pDevice->playback.converter.isPassthrough) { + /* The input buffer requires conversion, the playback buffer is passthrough. */ + ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture; + ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, mappedDeviceBufferFramesRemainingPlayback); + + result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess); + if (result != MA_SUCCESS) { + break; + } + + if (capturedClientFramesToProcess == 0) { + break; + } + + ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); /* Safe cast. */ + + mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess; + mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess; + } else { + ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture; + ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, outputDataInClientFormatCap); + + result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess); + if (result != MA_SUCCESS) { + break; + } + + if (capturedClientFramesToProcess == 0) { + break; + } + + ma_device__on_data(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); + + mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess; + outputDataInClientFormatCount = (ma_uint32)capturedClientFramesToProcess; + outputDataInClientFormatConsumed = 0; } } - /* If at this point we have a valid buffer mapped, make sure the buffer length is set appropriately. */ - if (pDevice->wasapi.pMappedBufferCapture != NULL) { - pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap; + + /* If at this point we've run out of capture data we need to release the buffer. */ + if (mappedDeviceBufferFramesRemainingCapture == 0 && pMappedDeviceBufferCapture != NULL) { + hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + /*printf("TRACE: Released capture buffer\n");*/ + + pMappedDeviceBufferCapture = NULL; + mappedDeviceBufferFramesRemainingCapture = 0; + mappedDeviceBufferSizeInFramesCapture = 0; + } + + /* Get out of this loop if we're run out of room in the playback buffer. */ + if (mappedDeviceBufferFramesRemainingPlayback == 0) { + break; } } } - continue; - } else { - if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || hr == MA_AUDCLNT_E_BUFFER_ERROR) { + + /* If at this point we've run out of data we need to release the buffer. */ + if (mappedDeviceBufferFramesRemainingPlayback == 0 && pMappedDeviceBufferPlayback != NULL) { + hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + /*printf("TRACE: Released playback buffer\n");*/ + framesWrittenToPlaybackDevice += mappedDeviceBufferSizeInFramesPlayback; + + pMappedDeviceBufferPlayback = NULL; + mappedDeviceBufferFramesRemainingPlayback = 0; + mappedDeviceBufferSizeInFramesPlayback = 0; + } + + if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { + ma_uint32 startThreshold = pDevice->playback.internalPeriodSizeInFrames * 1; + + /* Prevent a deadlock. If we don't clamp against the actual buffer size we'll never end up starting the playback device which will result in a deadlock. */ + if (startThreshold > pDevice->wasapi.actualPeriodSizeInFramesPlayback) { + startThreshold = pDevice->wasapi.actualPeriodSizeInFramesPlayback; + } + + if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= startThreshold) { + hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + if (FAILED(hr)) { + ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr)); + } + + c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); + } + } + + /* Make sure the device has started before waiting. */ + if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + return MA_ERROR; /* Wait failed. */ + } + } break; + + + + case ma_device_type_capture: + case ma_device_type_loopback: + { + ma_uint32 framesAvailableCapture; + DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */ + + /* Wait for data to become available first. */ + if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + exitLoop = MA_TRUE; + break; /* Wait failed. */ + } + + /* See how many frames are available. Since we waited at the top, I don't think this should ever return 0. I'm checking for this anyway. */ + result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture); + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; + } + + if (framesAvailableCapture < pDevice->wasapi.periodSizeInFramesCapture) { + continue; /* Nothing available. Keep waiting. */ + } + + /* Map the data buffer in preparation for sending to the client. */ + mappedDeviceBufferSizeInFramesCapture = framesAvailableCapture; + hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + /* Overrun detection. */ + if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { + /* Glitched. Probably due to an overrun. */ + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); + #endif + /* - No data is available. We need to wait for more. There's two situations to consider - here. The first is normal capture mode. If this times out it probably means the - microphone isn't delivering data for whatever reason. In this case we'll just - abort the read and return whatever we were able to get. The other situations is - loopback mode, in which case a timeout probably just means the nothing is playing - through the speakers. + Exeriment: If we get an overrun it probably means we're straddling the end of the buffer. In order to prevent a never-ending sequence of glitches let's experiment + by dropping every frame until we're left with only a single period. To do this we just keep retrieving and immediately releasing buffers until we're down to the + last period. */ + if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) { + #ifdef MA_DEBUG_OUTPUT + printf("[WASAPI] Synchronizing capture stream. "); + #endif + do + { + hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); + if (FAILED(hr)) { + break; + } - /* Experiment: Use a shorter timeout for loopback mode. */ - DWORD timeoutInMilliseconds = MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS; - if (pDevice->type == ma_device_type_loopback) { - timeoutInMilliseconds = 10; + framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture; + + if (framesAvailableCapture > 0) { + mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture); + hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + } else { + pMappedDeviceBufferCapture = NULL; + mappedDeviceBufferSizeInFramesCapture = 0; + } + } while (framesAvailableCapture > periodSizeInFramesCapture); + #ifdef MA_DEBUG_OUTPUT + printf("framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); + #endif } - - if (WaitForSingleObject((HANDLE)pDevice->wasapi.hEventCapture, timeoutInMilliseconds) != WAIT_OBJECT_0) { - if (pDevice->type == ma_device_type_loopback) { - continue; /* Keep waiting in loopback mode. */ - } else { - result = MA_ERROR; - break; /* Wait failed. */ - } - } - - /* At this point we should be able to loop back to the start of the loop and try retrieving a data buffer again. */ } else { - /* An error occurred and we need to abort. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for reading from the device. HRESULT = %d. Stopping device.\n", (int)hr); - result = ma_result_from_HRESULT(hr); + #ifdef MA_DEBUG_OUTPUT + if (flagsCapture != 0) { + printf("[WASAPI] Capture Flags: %ld\n", flagsCapture); + } + #endif + } + + /* We should have a buffer at this point, but let's just do a sanity check anyway. */ + if (mappedDeviceBufferSizeInFramesCapture > 0 && pMappedDeviceBufferCapture != NULL) { + ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture); + + /* At this point we're done with the buffer. */ + hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); + pMappedDeviceBufferCapture = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */ + mappedDeviceBufferSizeInFramesCapture = 0; + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + } + } break; + + + + case ma_device_type_playback: + { + ma_uint32 framesAvailablePlayback; + + /* Check how much space is available. If this returns 0 we just keep waiting. */ + result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; break; } - } + + if (framesAvailablePlayback >= pDevice->wasapi.periodSizeInFramesPlayback) { + /* Map a the data buffer in preparation for the callback. */ + hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + /* We should have a buffer at this point. */ + ma_device__read_frames_from_client(pDevice, framesAvailablePlayback, pMappedDeviceBufferPlayback); + + /* At this point we're done writing to the device and we just need to release the buffer. */ + hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, 0); + pMappedDeviceBufferPlayback = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */ + mappedDeviceBufferSizeInFramesPlayback = 0; + + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + framesWrittenToPlaybackDevice += framesAvailablePlayback; + } + + if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { + hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + if (FAILED(hr)) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr)); + exitLoop = MA_TRUE; + break; + } + + c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); + } + + /* Make sure we don't wait on the event before we've started the device or we may end up deadlocking. */ + if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + exitLoop = MA_TRUE; + break; /* Wait failed. Probably timed out. */ + } + } break; + + default: return MA_INVALID_ARGS; } } - /* - If we were unable to process the entire requested frame count, but we still have a mapped buffer, - there's a good chance either an error occurred or the device was stopped mid-read. In this case - we'll need to make sure the buffer is released. - */ - if (totalFramesProcessed < frameCount && pDevice->wasapi.pMappedBufferCapture != NULL) { - ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - pDevice->wasapi.mappedBufferCaptureLen = 0; - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesProcessed; - } - - return result; -} - -static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) -{ - ma_result result = MA_SUCCESS; - ma_uint32 totalFramesProcessed = 0; - - /* Keep writing to the device until it's stopped or we've consumed all of our input. */ - while (ma_device_get_state(pDevice) == ma_device_state_started && totalFramesProcessed < frameCount) { - ma_uint32 framesRemaining = frameCount - totalFramesProcessed; - - /* - We're going to do this in a similar way to capture. We'll first check if the cached data pointer - is valid, and if so, read from that. Otherwise We will call IAudioRenderClient_GetBuffer() with - a requested buffer size equal to our actual period size. If it returns AUDCLNT_E_BUFFER_TOO_LARGE - it means we need to wait for some data to become available. - */ - if (pDevice->wasapi.pMappedBufferPlayback != NULL) { - /* We still have some space available in the mapped data buffer. Write to it. */ - ma_uint32 framesToProcessNow = framesRemaining; - if (framesToProcessNow > (pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen)) { - framesToProcessNow = (pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen); - } - - /* Now just copy the data over to the output buffer. */ - ma_copy_pcm_frames( - ma_offset_pcm_frames_ptr(pDevice->wasapi.pMappedBufferPlayback, pDevice->wasapi.mappedBufferPlaybackLen, pDevice->playback.internalFormat, pDevice->playback.internalChannels), - ma_offset_pcm_frames_const_ptr(pFrames, totalFramesProcessed, pDevice->playback.internalFormat, pDevice->playback.internalChannels), - framesToProcessNow, - pDevice->playback.internalFormat, pDevice->playback.internalChannels - ); - - totalFramesProcessed += framesToProcessNow; - pDevice->wasapi.mappedBufferPlaybackLen += framesToProcessNow; - - /* If the data buffer has been fully consumed we need to release it. */ - if (pDevice->wasapi.mappedBufferPlaybackLen == pDevice->wasapi.mappedBufferPlaybackCap) { - ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); - pDevice->wasapi.pMappedBufferPlayback = NULL; - pDevice->wasapi.mappedBufferPlaybackCap = 0; - pDevice->wasapi.mappedBufferPlaybackLen = 0; - - /* - In exclusive mode we need to wait here. Exclusive mode is weird because GetBuffer() never - seems to return AUDCLNT_E_BUFFER_TOO_LARGE, which is what we normally use to determine - whether or not we need to wait for more data. - */ - if (pDevice->playback.shareMode == ma_share_mode_exclusive) { - if (WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - result = MA_ERROR; - break; /* Wait failed. Probably timed out. */ - } - } - } - } else { - /* We don't have a mapped data buffer so we'll need to get one. */ - HRESULT hr; - ma_uint32 bufferSizeInFrames; - - /* Special rules for exclusive mode. */ - if (pDevice->playback.shareMode == ma_share_mode_exclusive) { - bufferSizeInFrames = pDevice->wasapi.actualBufferSizeInFramesPlayback; - } else { - bufferSizeInFrames = pDevice->wasapi.periodSizeInFramesPlayback; - } - - hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, bufferSizeInFrames, (BYTE**)&pDevice->wasapi.pMappedBufferPlayback); - if (hr == S_OK) { - /* We have data available. */ - pDevice->wasapi.mappedBufferPlaybackCap = bufferSizeInFrames; - pDevice->wasapi.mappedBufferPlaybackLen = 0; - } else { - if (hr == MA_AUDCLNT_E_BUFFER_TOO_LARGE || hr == MA_AUDCLNT_E_BUFFER_ERROR) { - /* Not enough data available. We need to wait for more. */ - if (WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - result = MA_ERROR; - break; /* Wait failed. Probably timed out. */ - } - } else { - /* Some error occurred. We'll need to abort. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device. HRESULT = %d. Stopping device.\n", (int)hr); - result = ma_result_from_HRESULT(hr); - break; - } - } + /* Here is where the device needs to be stopped. */ + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + /* Any mapped buffers need to be released. */ + if (pMappedDeviceBufferCapture != NULL) { + hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); } } - if (pFramesWritten != NULL) { - *pFramesWritten = totalFramesProcessed; + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + /* Any mapped buffers need to be released. */ + if (pMappedDeviceBufferPlayback != NULL) { + hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0); + } } - return result; + return MA_SUCCESS; } static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice) @@ -23574,32 +16212,19 @@ static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice) static ma_result ma_context_uninit__wasapi(ma_context* pContext) { - ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI); - MA_ASSERT(pContext != NULL); MA_ASSERT(pContext->backend == ma_backend_wasapi); + + if (pContext->wasapi.commandThread != NULL) { + ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI); + ma_context_post_command__wasapi(pContext, &cmd); + ma_thread_wait(&pContext->wasapi.commandThread); - ma_context_post_command__wasapi(pContext, &cmd); - ma_thread_wait(&pContext->wasapi.commandThread); - - if (pContext->wasapi.hAvrt) { - ma_dlclose(ma_context_get_log(pContext), pContext->wasapi.hAvrt); - pContext->wasapi.hAvrt = NULL; + /* Only after the thread has been terminated can we uninitialize the sync objects for the command thread. */ + ma_semaphore_uninit(&pContext->wasapi.commandSem); + ma_mutex_uninit(&pContext->wasapi.commandLock); } - #if defined(MA_WIN32_UWP) - { - if (pContext->wasapi.hMMDevapi) { - ma_dlclose(ma_context_get_log(pContext), pContext->wasapi.hMMDevapi); - pContext->wasapi.hMMDevapi = NULL; - } - } - #endif - - /* Only after the thread has been terminated can we uninitialize the sync objects for the command thread. */ - ma_semaphore_uninit(&pContext->wasapi.commandSem); - ma_mutex_uninit(&pContext->wasapi.commandLock); - return MA_SUCCESS; } @@ -23624,15 +16249,15 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ ma_PFNVerifyVersionInfoW _VerifyVersionInfoW; ma_PFNVerSetConditionMask _VerSetConditionMask; - kernel32DLL = ma_dlopen(ma_context_get_log(pContext), "kernel32.dll"); + kernel32DLL = ma_dlopen(pContext, "kernel32.dll"); if (kernel32DLL == NULL) { return MA_NO_BACKEND; } - _VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW )ma_dlsym(ma_context_get_log(pContext), kernel32DLL, "VerifyVersionInfoW"); - _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(ma_context_get_log(pContext), kernel32DLL, "VerSetConditionMask"); + _VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW )ma_dlsym(pContext, kernel32DLL, "VerifyVersionInfoW"); + _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(pContext, kernel32DLL, "VerSetConditionMask"); if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) { - ma_dlclose(ma_context_get_log(pContext), kernel32DLL); + ma_dlclose(pContext, kernel32DLL); return MA_NO_BACKEND; } @@ -23647,7 +16272,7 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ result = MA_NO_BACKEND; } - ma_dlclose(ma_context_get_log(pContext), kernel32DLL); + ma_dlclose(pContext, kernel32DLL); } #endif @@ -23657,39 +16282,6 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ MA_ZERO_OBJECT(&pContext->wasapi); - - #if defined(MA_WIN32_UWP) - { - /* Link to mmdevapi so we can get access to ActivateAudioInterfaceAsync(). */ - pContext->wasapi.hMMDevapi = ma_dlopen(ma_context_get_log(pContext), "mmdevapi.dll"); - if (pContext->wasapi.hMMDevapi) { - pContext->wasapi.ActivateAudioInterfaceAsync = ma_dlsym(ma_context_get_log(pContext), pContext->wasapi.hMMDevapi, "ActivateAudioInterfaceAsync"); - if (pContext->wasapi.ActivateAudioInterfaceAsync == NULL) { - ma_dlclose(ma_context_get_log(pContext), pContext->wasapi.hMMDevapi); - return MA_NO_BACKEND; /* ActivateAudioInterfaceAsync() could not be loaded. */ - } - } else { - return MA_NO_BACKEND; /* Failed to load mmdevapi.dll which is required for ActivateAudioInterfaceAsync() */ - } - } - #endif - - /* Optionally use the Avrt API to specify the audio thread's latency sensitivity requirements */ - pContext->wasapi.hAvrt = ma_dlopen(ma_context_get_log(pContext), "avrt.dll"); - if (pContext->wasapi.hAvrt) { - pContext->wasapi.AvSetMmThreadCharacteristicsA = ma_dlsym(ma_context_get_log(pContext), pContext->wasapi.hAvrt, "AvSetMmThreadCharacteristicsA"); - pContext->wasapi.AvRevertMmThreadcharacteristics = ma_dlsym(ma_context_get_log(pContext), pContext->wasapi.hAvrt, "AvRevertMmThreadCharacteristics"); - - /* If either function could not be found, disable use of avrt entirely. */ - if (!pContext->wasapi.AvSetMmThreadCharacteristicsA || !pContext->wasapi.AvRevertMmThreadcharacteristics) { - pContext->wasapi.AvSetMmThreadCharacteristicsA = NULL; - pContext->wasapi.AvRevertMmThreadcharacteristics = NULL; - ma_dlclose(ma_context_get_log(pContext), pContext->wasapi.hAvrt); - pContext->wasapi.hAvrt = NULL; - } - } - - /* Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread than the one that retrieved it with GetService(). This can result in a deadlock in two @@ -23727,7 +16319,7 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ return result; } - result = ma_thread_create(&pContext->wasapi.commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContext, &pContext->allocationCallbacks); + result = ma_thread_create(&pContext->wasapi.commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContext); if (result != MA_SUCCESS) { ma_semaphore_uninit(&pContext->wasapi.commandSem); ma_mutex_uninit(&pContext->wasapi.commandLock); @@ -23744,9 +16336,9 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ pCallbacks->onDeviceUninit = ma_device_uninit__wasapi; pCallbacks->onDeviceStart = ma_device_start__wasapi; pCallbacks->onDeviceStop = ma_device_stop__wasapi; - pCallbacks->onDeviceRead = ma_device_read__wasapi; - pCallbacks->onDeviceWrite = ma_device_write__wasapi; - pCallbacks->onDeviceDataLoop = NULL; + pCallbacks->onDeviceRead = NULL; /* Not used. Reading is done manually in the audio thread. */ + pCallbacks->onDeviceWrite = NULL; /* Not used. Writing is done manually in the audio thread. */ + pCallbacks->onDeviceDataLoop = ma_device_data_loop__wasapi; pCallbacks->onDeviceDataLoopWakeup = ma_device_data_loop_wakeup__wasapi; return MA_SUCCESS; @@ -23805,13 +16397,6 @@ DirectSound Backend #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020 -#define MA_DSBSTATUS_PLAYING 0x00000001 -#define MA_DSBSTATUS_BUFFERLOST 0x00000002 -#define MA_DSBSTATUS_LOOPING 0x00000004 -#define MA_DSBSTATUS_LOCHARDWARE 0x00000008 -#define MA_DSBSTATUS_LOCSOFTWARE 0x00000010 -#define MA_DSBSTATUS_TERMINATED 0x00000020 - #define MA_DSCBSTART_LOOPING 0x00000001 typedef struct @@ -23820,7 +16405,7 @@ typedef struct DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; - MA_WAVEFORMATEX* lpwfxFormat; + WAVEFORMATEX* lpwfxFormat; GUID guid3DAlgorithm; } MA_DSBUFFERDESC; @@ -23830,7 +16415,7 @@ typedef struct DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; - MA_WAVEFORMATEX* lpwfxFormat; + WAVEFORMATEX* lpwfxFormat; DWORD dwFXCount; void* lpDSCFXDesc; /* <-- miniaudio doesn't use this, so set to void*. */ } MA_DSCBUFFERDESC; @@ -23954,7 +16539,7 @@ typedef struct /* IDirectSoundBuffer */ HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps); HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor); - HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundBuffer* pThis, MA_WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten); + HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten); HRESULT (STDMETHODCALLTYPE * GetVolume) (ma_IDirectSoundBuffer* pThis, LONG* pVolume); HRESULT (STDMETHODCALLTYPE * GetPan) (ma_IDirectSoundBuffer* pThis, LONG* pPan); HRESULT (STDMETHODCALLTYPE * GetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD* pFrequency); @@ -23963,7 +16548,7 @@ typedef struct HRESULT (STDMETHODCALLTYPE * Lock) (ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags); HRESULT (STDMETHODCALLTYPE * Play) (ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags); HRESULT (STDMETHODCALLTYPE * SetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition); - HRESULT (STDMETHODCALLTYPE * SetFormat) (ma_IDirectSoundBuffer* pThis, const MA_WAVEFORMATEX* pFormat); + HRESULT (STDMETHODCALLTYPE * SetFormat) (ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat); HRESULT (STDMETHODCALLTYPE * SetVolume) (ma_IDirectSoundBuffer* pThis, LONG volume); HRESULT (STDMETHODCALLTYPE * SetPan) (ma_IDirectSoundBuffer* pThis, LONG pan); HRESULT (STDMETHODCALLTYPE * SetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD dwFrequency); @@ -23980,7 +16565,7 @@ static MA_INLINE ULONG ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer* pTh static MA_INLINE ULONG ma_IDirectSoundBuffer_Release(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Release(pThis); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCaps(ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSBufferCaps); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCurrentPlayCursor, pCurrentWriteCursor); } -static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer* pThis, MA_WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetVolume(ma_IDirectSoundBuffer* pThis, LONG* pVolume) { return pThis->lpVtbl->GetVolume(pThis, pVolume); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetPan(ma_IDirectSoundBuffer* pThis, LONG* pPan) { return pThis->lpVtbl->GetPan(pThis, pPan); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFrequency(ma_IDirectSoundBuffer* pThis, DWORD* pFrequency) { return pThis->lpVtbl->GetFrequency(pThis, pFrequency); } @@ -23989,7 +16574,7 @@ static MA_INLINE HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer* static MA_INLINE HRESULT ma_IDirectSoundBuffer_Lock(ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags) { return pThis->lpVtbl->Lock(pThis, dwOffset, dwBytes, ppAudioPtr1, pAudioBytes1, ppAudioPtr2, pAudioBytes2, dwFlags); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_Play(ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) { return pThis->lpVtbl->Play(pThis, dwReserved1, dwPriority, dwFlags); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition) { return pThis->lpVtbl->SetCurrentPosition(pThis, dwNewPosition); } -static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer* pThis, const MA_WAVEFORMATEX* pFormat) { return pThis->lpVtbl->SetFormat(pThis, pFormat); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat) { return pThis->lpVtbl->SetFormat(pThis, pFormat); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetVolume(ma_IDirectSoundBuffer* pThis, LONG volume) { return pThis->lpVtbl->SetVolume(pThis, volume); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetPan(ma_IDirectSoundBuffer* pThis, LONG pan) { return pThis->lpVtbl->SetPan(pThis, pan); } static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFrequency(ma_IDirectSoundBuffer* pThis, DWORD dwFrequency) { return pThis->lpVtbl->SetFrequency(pThis, dwFrequency); } @@ -24015,9 +16600,9 @@ struct ma_IDirectSoundCapture { ma_IDirectSoundCaptureVtbl* lpVtbl; }; -static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface (ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } -static MA_INLINE ULONG ma_IDirectSoundCapture_AddRef (ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->AddRef(pThis); } -static MA_INLINE ULONG ma_IDirectSoundCapture_Release (ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->Release(pThis); } +static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IDirectSoundCapture_AddRef(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->AddRef(pThis); } +static MA_INLINE ULONG ma_IDirectSoundCapture_Release(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->Release(pThis); } static MA_INLINE HRESULT ma_IDirectSoundCapture_CreateCaptureBuffer(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateCaptureBuffer(pThis, pDSCBufferDesc, ppDSCBuffer, pUnkOuter); } static MA_INLINE HRESULT ma_IDirectSoundCapture_GetCaps (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCCaps); } static MA_INLINE HRESULT ma_IDirectSoundCapture_Initialize (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); } @@ -24034,7 +16619,7 @@ typedef struct /* IDirectSoundCaptureBuffer */ HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps); HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition); - HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundCaptureBuffer* pThis, MA_WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten); + HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten); HRESULT (STDMETHODCALLTYPE * GetStatus) (ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus); HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc); HRESULT (STDMETHODCALLTYPE * Lock) (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags); @@ -24051,7 +16636,7 @@ static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCapt static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_Release(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->Release(pThis); } static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCaps(ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCBCaps); } static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCurrentPosition(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCapturePosition, pReadPosition); } -static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer* pThis, MA_WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); } +static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); } static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetStatus(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus) { return pThis->lpVtbl->GetStatus(pThis, pStatus); } static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Initialize(ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSoundCapture, pDSCBufferDesc); } static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Lock(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags) { return pThis->lpVtbl->Lock(pThis, dwOffset, dwBytes, ppAudioPtr1, pAudioBytes1, ppAudioPtr2, pAudioBytes2, dwFlags); } @@ -24081,11 +16666,11 @@ static MA_INLINE ULONG ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify* pT static MA_INLINE HRESULT ma_IDirectSoundNotify_SetNotificationPositions(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies) { return pThis->lpVtbl->SetNotificationPositions(pThis, dwPositionNotifies, pPositionNotifies); } -typedef BOOL (CALLBACK * ma_DSEnumCallbackAProc) (GUID* pDeviceGUID, const char* pDeviceDescription, const char* pModule, void* pContext); -typedef HRESULT (WINAPI * ma_DirectSoundCreateProc) (const GUID* pcGuidDevice, ma_IDirectSound** ppDS8, ma_IUnknown* pUnkOuter); -typedef HRESULT (WINAPI * ma_DirectSoundEnumerateAProc) (ma_DSEnumCallbackAProc pDSEnumCallback, void* pContext); -typedef HRESULT (WINAPI * ma_DirectSoundCaptureCreateProc) (const GUID* pcGuidDevice, ma_IDirectSoundCapture** ppDSC8, ma_IUnknown* pUnkOuter); -typedef HRESULT (WINAPI * ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback, void* pContext); +typedef BOOL (CALLBACK * ma_DSEnumCallbackAProc) (LPGUID pDeviceGUID, LPCSTR pDeviceDescription, LPCSTR pModule, LPVOID pContext); +typedef HRESULT (WINAPI * ma_DirectSoundCreateProc) (const GUID* pcGuidDevice, ma_IDirectSound** ppDS8, LPUNKNOWN pUnkOuter); +typedef HRESULT (WINAPI * ma_DirectSoundEnumerateAProc) (ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext); +typedef HRESULT (WINAPI * ma_DirectSoundCaptureCreateProc) (const GUID* pcGuidDevice, ma_IDirectSoundCapture** ppDSC8, LPUNKNOWN pUnkOuter); +typedef HRESULT (WINAPI * ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext); static ma_uint32 ma_get_best_sample_rate_within_range(ma_uint32 sampleRateMin, ma_uint32 sampleRateMax) { @@ -24176,23 +16761,18 @@ static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma pDirectSound = NULL; if (FAILED(((ma_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* The cooperative level must be set before doing anything else. */ - hWnd = (HWND)pContext->dsound.hWnd; - if (hWnd == 0) { - hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); - if (hWnd == 0) { - hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); - } + hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); + if (hWnd == NULL) { + hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); } hr = ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", ma_result_from_HRESULT(hr)); } *ppDirectSound = pDirectSound; @@ -24217,8 +16797,7 @@ static ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pCont hr = ((ma_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", ma_result_from_HRESULT(hr)); } *ppDirectSoundCapture = pDirectSoundCapture; @@ -24249,8 +16828,7 @@ static ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_c caps.dwSize = sizeof(caps); hr = ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.", ma_result_from_HRESULT(hr)); } if (pChannels) { @@ -24337,7 +16915,7 @@ typedef struct ma_bool32 terminated; } ma_context_enumerate_devices_callback_data__dsound; -static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(GUID* lpGuid, const char* lpcstrDescription, const char* lpcstrModule, void* lpContext) +static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) { ma_context_enumerate_devices_callback_data__dsound* pData = (ma_context_enumerate_devices_callback_data__dsound*)lpContext; ma_device_info deviceInfo; @@ -24360,7 +16938,7 @@ static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(GUID* lpGuid, /* Call the callback function, but make sure we stop enumerating if the callee requested so. */ MA_ASSERT(pData != NULL); - pData->terminated = (pData->callback(pData->pContext, pData->deviceType, &deviceInfo, pData->pUserData) == MA_FALSE); + pData->terminated = !pData->callback(pData->pContext, pData->deviceType, &deviceInfo, pData->pUserData); if (pData->terminated) { return FALSE; /* Stop enumeration. */ } else { @@ -24403,7 +16981,7 @@ typedef struct ma_bool32 found; } ma_context_get_device_info_callback_data__dsound; -static BOOL CALLBACK ma_context_get_device_info_callback__dsound(GUID* lpGuid, const char* lpcstrDescription, const char* lpcstrModule, void* lpContext) +static BOOL CALLBACK ma_context_get_device_info_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) { ma_context_get_device_info_callback_data__dsound* pData = (ma_context_get_device_info_callback_data__dsound*)lpContext; MA_ASSERT(pData != NULL); @@ -24485,8 +17063,7 @@ static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_dev caps.dwSize = sizeof(caps); hr = ma_IDirectSound_GetCaps(pDirectSound, &caps); if (FAILED(hr)) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device."); - return ma_result_from_HRESULT(hr); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr)); } @@ -24562,13 +17139,13 @@ static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_dev /* The format is always an integer format and is based on the bits per sample. */ if (bitsPerSample == 8) { - pDeviceInfo->nativeDataFormats[0].format = ma_format_u8; + pDeviceInfo->formats[0] = ma_format_u8; } else if (bitsPerSample == 16) { - pDeviceInfo->nativeDataFormats[0].format = ma_format_s16; + pDeviceInfo->formats[0] = ma_format_s16; } else if (bitsPerSample == 24) { - pDeviceInfo->nativeDataFormats[0].format = ma_format_s24; + pDeviceInfo->formats[0] = ma_format_s24; } else if (bitsPerSample == 32) { - pDeviceInfo->nativeDataFormats[0].format = ma_format_s32; + pDeviceInfo->formats[0] = ma_format_s32; } else { return MA_FORMAT_NOT_SUPPORTED; } @@ -24608,7 +17185,7 @@ static ma_result ma_device_uninit__dsound(ma_device* pDevice) return MA_SUCCESS; } -static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* pChannelMap, MA_WAVEFORMATEXTENSIBLE* pWF) +static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* pChannelMap, WAVEFORMATEXTENSIBLE* pWF) { GUID subformat; @@ -24645,14 +17222,14 @@ static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 c } MA_ZERO_OBJECT(pWF); - pWF->cbSize = sizeof(*pWF); - pWF->wFormatTag = WAVE_FORMAT_EXTENSIBLE; - pWF->nChannels = (WORD)channels; - pWF->nSamplesPerSec = (DWORD)sampleRate; - pWF->wBitsPerSample = (WORD)(ma_get_bytes_per_sample(format)*8); - pWF->nBlockAlign = (WORD)(pWF->nChannels * pWF->wBitsPerSample / 8); - pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec; - pWF->Samples.wValidBitsPerSample = pWF->wBitsPerSample; + pWF->Format.cbSize = sizeof(*pWF); + pWF->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + pWF->Format.nChannels = (WORD)channels; + pWF->Format.nSamplesPerSec = (DWORD)sampleRate; + pWF->Format.wBitsPerSample = (WORD)(ma_get_bytes_per_sample(format)*8); + pWF->Format.nBlockAlign = (WORD)(pWF->Format.nChannels * pWF->Format.wBitsPerSample / 8); + pWF->Format.nAvgBytesPerSec = pWF->Format.nBlockAlign * pWF->Format.nSamplesPerSec; + pWF->Samples.wValidBitsPerSample = pWF->Format.wBitsPerSample; pWF->dwChannelMask = ma_channel_map_to_channel_mask__win32(pChannelMap, channels); pWF->SubFormat = subformat; @@ -24661,11 +17238,8 @@ static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 c static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__dsound(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) { - /* - DirectSound has a minimum period size of 20ms. In practice, this doesn't seem to be enough for - reliable glitch-free processing so going to use 30ms instead. - */ - ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(30, nativeSampleRate); + /* DirectSound has a minimum period size of 20ms. */ + ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(20, nativeSampleRate); ma_uint32 periodSizeInFrames; periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile); @@ -24690,17 +17264,17 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf } /* - Unfortunately DirectSound uses different APIs and data structures for playback and capture devices. We need to initialize - the capture device first because we'll want to match its buffer size and period count on the playback side if we're using + Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices. We need to initialize + the capture device first because we'll want to match it's buffer size and period count on the playback side if we're using full-duplex mode. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { - MA_WAVEFORMATEXTENSIBLE wf; + WAVEFORMATEXTENSIBLE wf; MA_DSCBUFFERDESC descDS; ma_uint32 periodSizeInFrames; ma_uint32 periodCount; char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */ - MA_WAVEFORMATEXTENSIBLE* pActualFormat; + WAVEFORMATEXTENSIBLE* pActualFormat; result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &wf); if (result != MA_SUCCESS) { @@ -24713,49 +17287,47 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf return result; } - result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pDevice->pContext, (ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.nChannels, &wf.wBitsPerSample, &wf.nSamplesPerSec); + result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pDevice->pContext, (ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.Format.nChannels, &wf.Format.wBitsPerSample, &wf.Format.nSamplesPerSec); if (result != MA_SUCCESS) { ma_device_uninit__dsound(pDevice); return result; } - wf.nBlockAlign = (WORD)(wf.nChannels * wf.wBitsPerSample / 8); - wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.wBitsPerSample; + wf.Format.nBlockAlign = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8); + wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; + wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM; /* The size of the buffer must be a clean multiple of the period count. */ - periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorCapture, wf.nSamplesPerSec, pConfig->performanceProfile); + periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorCapture, wf.Format.nSamplesPerSec, pConfig->performanceProfile); periodCount = (pDescriptorCapture->periodCount > 0) ? pDescriptorCapture->periodCount : MA_DEFAULT_PERIODS; MA_ZERO_OBJECT(&descDS); descDS.dwSize = sizeof(descDS); descDS.dwFlags = 0; - descDS.dwBufferBytes = periodSizeInFrames * periodCount * wf.nBlockAlign; - descDS.lpwfxFormat = (MA_WAVEFORMATEX*)&wf; + descDS.dwBufferBytes = periodSizeInFrames * periodCount * wf.Format.nBlockAlign; + descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr)); } /* Get the _actual_ properties of the buffer. */ - pActualFormat = (MA_WAVEFORMATEXTENSIBLE*)rawdata; - hr = ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (MA_WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL); + pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; + hr = ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.", ma_result_from_HRESULT(hr)); } /* We can now start setting the output data formats. */ - pDescriptorCapture->format = ma_format_from_WAVEFORMATEX((MA_WAVEFORMATEX*)pActualFormat); - pDescriptorCapture->channels = pActualFormat->nChannels; - pDescriptorCapture->sampleRate = pActualFormat->nSamplesPerSec; + pDescriptorCapture->format = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat); + pDescriptorCapture->channels = pActualFormat->Format.nChannels; + pDescriptorCapture->sampleRate = pActualFormat->Format.nSamplesPerSec; /* Get the native channel map based on the channel mask. */ - if (pActualFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDescriptorCapture->channels, pDescriptorCapture->channelMap); } else { ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDescriptorCapture->channels, pDescriptorCapture->channelMap); @@ -24772,8 +17344,7 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr)); } } @@ -24783,16 +17354,14 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - MA_WAVEFORMATEXTENSIBLE wf; + WAVEFORMATEXTENSIBLE wf; MA_DSBUFFERDESC descDSPrimary; MA_DSCAPS caps; char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */ - MA_WAVEFORMATEXTENSIBLE* pActualFormat; + WAVEFORMATEXTENSIBLE* pActualFormat; ma_uint32 periodSizeInFrames; ma_uint32 periodCount; MA_DSBUFFERDESC descDS; - WORD nativeChannelCount; - DWORD nativeChannelMask = 0; result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &wf); if (result != MA_SUCCESS) { @@ -24811,8 +17380,7 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDSPrimary, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", ma_result_from_HRESULT(hr)); } @@ -24822,42 +17390,37 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSound_GetCaps((ma_IDirectSound*)pDevice->dsound.pPlayback, &caps); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device."); - return ma_result_from_HRESULT(hr); - } - - if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { - DWORD speakerConfig; - - /* It supports at least stereo, but could support more. */ - nativeChannelCount = 2; - - /* Look at the speaker configuration to get a better idea on the channel count. */ - if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) { - ma_get_channels_from_speaker_config__dsound(speakerConfig, &nativeChannelCount, &nativeChannelMask); - } - } else { - /* It does not support stereo, which means we are stuck with mono. */ - nativeChannelCount = 1; - nativeChannelMask = 0x00000001; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr)); } if (pDescriptorPlayback->channels == 0) { - wf.nChannels = nativeChannelCount; - wf.dwChannelMask = nativeChannelMask; + if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { + DWORD speakerConfig; + + /* It supports at least stereo, but could support more. */ + wf.Format.nChannels = 2; + + /* Look at the speaker configuration to get a better idea on the channel count. */ + if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) { + ma_get_channels_from_speaker_config__dsound(speakerConfig, &wf.Format.nChannels, &wf.dwChannelMask); + } + } else { + /* It does not support stereo, which means we are stuck with mono. */ + wf.Format.nChannels = 1; + } } if (pDescriptorPlayback->sampleRate == 0) { /* We base the sample rate on the values returned by GetCaps(). */ if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) { - wf.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate); + wf.Format.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate); } else { - wf.nSamplesPerSec = caps.dwMaxSecondarySampleRate; + wf.Format.nSamplesPerSec = caps.dwMaxSecondarySampleRate; } } - wf.nBlockAlign = (WORD)(wf.nChannels * wf.wBitsPerSample / 8); - wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; + wf.Format.nBlockAlign = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8); + wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; /* From MSDN: @@ -24866,46 +17429,27 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer and compare the result with the format that was requested with the SetFormat method. */ - hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (MA_WAVEFORMATEX*)&wf); + hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf); if (FAILED(hr)) { - /* - If setting of the format failed we'll try again with some fallback settings. On Windows 98 I have - observed that IEEE_FLOAT does not work. We'll therefore enforce PCM. I also had issues where a - sample rate of 48000 did not work correctly. Not sure if it was a driver issue or not, but will - use 44100 for the sample rate. - */ - wf.cbSize = 18; /* NOTE: Don't use sizeof(MA_WAVEFORMATEX) here because it's got an extra 2 bytes due to padding. */ - wf.wFormatTag = WAVE_FORMAT_PCM; - wf.wBitsPerSample = 16; - wf.nChannels = nativeChannelCount; - wf.nSamplesPerSec = 44100; - wf.nBlockAlign = wf.nChannels * (wf.wBitsPerSample / 8); - wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; - - hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (MA_WAVEFORMATEX*)&wf); - if (FAILED(hr)) { - ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer."); - return ma_result_from_HRESULT(hr); - } + ma_device_uninit__dsound(pDevice); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.", ma_result_from_HRESULT(hr)); } /* Get the _actual_ properties of the buffer. */ - pActualFormat = (MA_WAVEFORMATEXTENSIBLE*)rawdata; - hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (MA_WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL); + pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; + hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", ma_result_from_HRESULT(hr)); } /* We now have enough information to start setting some output properties. */ - pDescriptorPlayback->format = ma_format_from_WAVEFORMATEX((MA_WAVEFORMATEX*)pActualFormat); - pDescriptorPlayback->channels = pActualFormat->nChannels; - pDescriptorPlayback->sampleRate = pActualFormat->nSamplesPerSec; + pDescriptorPlayback->format = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat); + pDescriptorPlayback->channels = pActualFormat->Format.nChannels; + pDescriptorPlayback->sampleRate = pActualFormat->Format.nSamplesPerSec; /* Get the internal channel map based on the channel mask. */ - if (pActualFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); } else { ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); @@ -24934,12 +17478,11 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf descDS.dwSize = sizeof(descDS); descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2; descDS.dwBufferBytes = periodSizeInFrames * periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels); - descDS.lpwfxFormat = (MA_WAVEFORMATEX*)pActualFormat; + descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", ma_result_from_HRESULT(hr)); } /* DirectSound should give us a buffer exactly the size we asked for. */ @@ -24974,20 +17517,17 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ma_bool32 isPlaybackDeviceStarted = MA_FALSE; ma_uint32 framesWrittenToPlaybackDevice = 0; /* For knowing whether or not the playback device needs to be started. */ ma_uint32 waitTimeInMilliseconds = 1; - DWORD playbackBufferStatus = 0; MA_ASSERT(pDevice != NULL); /* The first thing to do is start the capture device. The playback device is only started after the first period is written. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - hr = ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING); - if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed."); - return ma_result_from_HRESULT(hr); + if (FAILED(ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING))) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); } } - while (ma_device_get_state(pDevice) == ma_device_state_started) { + while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { switch (pDevice->type) { case ma_device_type_duplex: @@ -25036,8 +17576,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); } @@ -25063,7 +17602,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess; mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess; - ma_device__handle_data_callback(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess); + ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess); /* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */ for (;;) { @@ -25091,7 +17630,9 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Play cursor has moved in front of the write cursor (same loop iteration). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #ifdef MA_DEBUG_OUTPUT + printf("[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #endif availableBytesPlayback = 0; } } else { @@ -25100,11 +17641,17 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #ifdef MA_DEBUG_OUTPUT + printf("[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #endif availableBytesPlayback = 0; } } + #ifdef MA_DEBUG_OUTPUT + /*printf("[DirectSound] (Duplex/Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/ + #endif + /* If there's no room available for writing we need to wait for more. */ if (availableBytesPlayback == 0) { /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */ @@ -25112,8 +17659,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); } isPlaybackDeviceStarted = MA_TRUE; } else { @@ -25135,8 +17681,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device."); - result = ma_result_from_HRESULT(hr); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); break; } @@ -25152,7 +17697,9 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) silentPaddingInBytes = lockSizeInBytesPlayback; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes); + #ifdef MA_DEBUG_OUTPUT + printf("[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes); + #endif } } @@ -25178,8 +17725,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device."); - result = ma_result_from_HRESULT(hr); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); break; } @@ -25198,8 +17744,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); } isPlaybackDeviceStarted = MA_TRUE; } @@ -25218,8 +17763,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) /* At this point we're done with the mapped portion of the capture buffer. */ hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); } prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture); } break; @@ -25262,6 +17806,11 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) } } + #ifdef MA_DEBUG_OUTPUT + /*printf("[DirectSound] (Capture) physicalCaptureCursorInBytes=%d, physicalReadCursorInBytes=%d\n", physicalCaptureCursorInBytes, physicalReadCursorInBytes);*/ + /*printf("[DirectSound] (Capture) lockOffsetInBytesCapture=%d, lockSizeInBytesCapture=%d\n", lockOffsetInBytesCapture, lockSizeInBytesCapture);*/ + #endif + if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) { ma_sleep(waitTimeInMilliseconds); continue; /* Nothing is available in the capture buffer. */ @@ -25269,20 +17818,20 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device."); - result = ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); } + #ifdef MA_DEBUG_OUTPUT if (lockSizeInBytesCapture != mappedSizeInBytesCapture) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture); + printf("[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture); } + #endif ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture); hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); } prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture; @@ -25303,20 +17852,6 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) break; } - hr = ma_IDirectSoundBuffer_GetStatus((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &playbackBufferStatus); - if (SUCCEEDED(hr) && (playbackBufferStatus & MA_DSBSTATUS_PLAYING) == 0 && isPlaybackDeviceStarted) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[DirectSound] Attempting to resume audio due to state: %d.", (int)playbackBufferStatus); - hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); - if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed after attempting to resume from state %d.", (int)playbackBufferStatus); - return ma_result_from_HRESULT(hr); - } - - isPlaybackDeviceStarted = MA_TRUE; - ma_sleep(waitTimeInMilliseconds); - continue; - } - if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; } @@ -25330,7 +17865,9 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #ifdef MA_DEBUG_OUTPUT + printf("[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #endif availableBytesPlayback = 0; } } else { @@ -25339,19 +17876,24 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #ifdef MA_DEBUG_OUTPUT + printf("[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + #endif availableBytesPlayback = 0; } } + #ifdef MA_DEBUG_OUTPUT + /*printf("[DirectSound] (Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/ + #endif + /* If there's no room available for writing we need to wait for more. */ if (availableBytesPlayback < pDevice->playback.internalPeriodSizeInFrames) { /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */ if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) { hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); } isPlaybackDeviceStarted = MA_TRUE; } else { @@ -25372,8 +17914,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device."); - result = ma_result_from_HRESULT(hr); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); break; } @@ -25382,8 +17923,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device."); - result = ma_result_from_HRESULT(hr); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); break; } @@ -25401,8 +17941,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) { hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); } isPlaybackDeviceStarted = MA_TRUE; } @@ -25421,8 +17960,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", ma_result_from_HRESULT(hr)); } } @@ -25470,8 +18008,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer); if (FAILED(hr)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed."); - return ma_result_from_HRESULT(hr); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", ma_result_from_HRESULT(hr)); } ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0); @@ -25485,7 +18022,7 @@ static ma_result ma_context_uninit__dsound(ma_context* pContext) MA_ASSERT(pContext != NULL); MA_ASSERT(pContext->backend == ma_backend_dsound); - ma_dlclose(ma_context_get_log(pContext), pContext->dsound.hDSoundDLL); + ma_dlclose(pContext, pContext->dsound.hDSoundDLL); return MA_SUCCESS; } @@ -25496,29 +18033,15 @@ static ma_result ma_context_init__dsound(ma_context* pContext, const ma_context_ (void)pConfig; - pContext->dsound.hDSoundDLL = ma_dlopen(ma_context_get_log(pContext), "dsound.dll"); + pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll"); if (pContext->dsound.hDSoundDLL == NULL) { return MA_API_NOT_FOUND; } - pContext->dsound.DirectSoundCreate = ma_dlsym(ma_context_get_log(pContext), pContext->dsound.hDSoundDLL, "DirectSoundCreate"); - pContext->dsound.DirectSoundEnumerateA = ma_dlsym(ma_context_get_log(pContext), pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA"); - pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(ma_context_get_log(pContext), pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); - pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(ma_context_get_log(pContext), pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA"); - - /* - We need to support all functions or nothing. DirectSound with Windows 95 seems to not work too - well in my testing. For example, it's missing DirectSoundCaptureEnumerateA(). This is a convenient - place to just disable the DirectSound backend for Windows 95. - */ - if (pContext->dsound.DirectSoundCreate == NULL || - pContext->dsound.DirectSoundEnumerateA == NULL || - pContext->dsound.DirectSoundCaptureCreate == NULL || - pContext->dsound.DirectSoundCaptureEnumerateA == NULL) { - return MA_API_NOT_FOUND; - } - - pContext->dsound.hWnd = pConfig->dsound.hWnd; + pContext->dsound.DirectSoundCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate"); + pContext->dsound.DirectSoundEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA"); + pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); + pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA"); pCallbacks->onContextInit = ma_context_init__dsound; pCallbacks->onContextUninit = ma_context_uninit__dsound; @@ -25546,75 +18069,16 @@ WinMM Backend #ifdef MA_HAS_WINMM /* -Some build configurations will exclude the WinMM API. An example is when WIN32_LEAN_AND_MEAN -is defined. We need to define the types and functions we need manually. +Some older compilers don't have WAVEOUTCAPS2A and WAVEINCAPS2A, so we'll need to write this ourselves. These structures +are exactly the same as the older ones but they have a few GUIDs for manufacturer/product/name identification. I'm keeping +the names the same as the Win32 library for consistency, but namespaced to avoid naming conflicts with the Win32 version. */ -#define MA_MMSYSERR_NOERROR 0 -#define MA_MMSYSERR_ERROR 1 -#define MA_MMSYSERR_BADDEVICEID 2 -#define MA_MMSYSERR_INVALHANDLE 5 -#define MA_MMSYSERR_NOMEM 7 -#define MA_MMSYSERR_INVALFLAG 10 -#define MA_MMSYSERR_INVALPARAM 11 -#define MA_MMSYSERR_HANDLEBUSY 12 - -#define MA_CALLBACK_EVENT 0x00050000 -#define MA_WAVE_ALLOWSYNC 0x0002 - -#define MA_WHDR_DONE 0x00000001 -#define MA_WHDR_PREPARED 0x00000002 -#define MA_WHDR_BEGINLOOP 0x00000004 -#define MA_WHDR_ENDLOOP 0x00000008 -#define MA_WHDR_INQUEUE 0x00000010 - -#define MA_MAXPNAMELEN 32 - -typedef void* MA_HWAVEIN; -typedef void* MA_HWAVEOUT; -typedef UINT MA_MMRESULT; -typedef UINT MA_MMVERSION; - typedef struct { WORD wMid; WORD wPid; - MA_MMVERSION vDriverVersion; - CHAR szPname[MA_MAXPNAMELEN]; - DWORD dwFormats; - WORD wChannels; - WORD wReserved1; -} MA_WAVEINCAPSA; - -typedef struct -{ - WORD wMid; - WORD wPid; - MA_MMVERSION vDriverVersion; - CHAR szPname[MA_MAXPNAMELEN]; - DWORD dwFormats; - WORD wChannels; - WORD wReserved1; - DWORD dwSupport; -} MA_WAVEOUTCAPSA; - -typedef struct tagWAVEHDR -{ - char* lpData; - DWORD dwBufferLength; - DWORD dwBytesRecorded; - DWORD_PTR dwUser; - DWORD dwFlags; - DWORD dwLoops; - struct tagWAVEHDR* lpNext; - DWORD_PTR reserved; -} MA_WAVEHDR; - -typedef struct -{ - WORD wMid; - WORD wPid; - MA_MMVERSION vDriverVersion; - CHAR szPname[MA_MAXPNAMELEN]; + MMVERSION vDriverVersion; + CHAR szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; WORD wReserved1; @@ -25623,13 +18087,12 @@ typedef struct GUID ProductGuid; GUID NameGuid; } MA_WAVEOUTCAPS2A; - typedef struct { WORD wMid; WORD wPid; - MA_MMVERSION vDriverVersion; - CHAR szPname[MA_MAXPNAMELEN]; + MMVERSION vDriverVersion; + CHAR szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; WORD wReserved1; @@ -25638,37 +18101,36 @@ typedef struct GUID NameGuid; } MA_WAVEINCAPS2A; -typedef UINT (WINAPI * MA_PFN_waveOutGetNumDevs)(void); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID, MA_WAVEOUTCAPSA* pwoc, UINT cbwoc); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutOpen)(MA_HWAVEOUT* phwo, UINT uDeviceID, const MA_WAVEFORMATEX* pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutClose)(MA_HWAVEOUT hwo); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutPrepareHeader)(MA_HWAVEOUT hwo, MA_WAVEHDR* pwh, UINT cbwh); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutUnprepareHeader)(MA_HWAVEOUT hwo, MA_WAVEHDR* pwh, UINT cbwh); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutWrite)(MA_HWAVEOUT hwo, MA_WAVEHDR* pwh, UINT cbwh); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveOutReset)(MA_HWAVEOUT hwo); -typedef UINT (WINAPI * MA_PFN_waveInGetNumDevs)(void); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID, MA_WAVEINCAPSA* pwic, UINT cbwic); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInOpen)(MA_HWAVEIN* phwi, UINT uDeviceID, const MA_WAVEFORMATEX* pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInClose)(MA_HWAVEIN hwi); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInPrepareHeader)(MA_HWAVEIN hwi, MA_WAVEHDR* pwh, UINT cbwh); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInUnprepareHeader)(MA_HWAVEIN hwi, MA_WAVEHDR* pwh, UINT cbwh); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInAddBuffer)(MA_HWAVEIN hwi, MA_WAVEHDR* pwh, UINT cbwh); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInStart)(MA_HWAVEIN hwi); -typedef MA_MMRESULT (WINAPI * MA_PFN_waveInReset)(MA_HWAVEIN hwi); +typedef UINT (WINAPI * MA_PFN_waveOutGetNumDevs)(void); +typedef MMRESULT (WINAPI * MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc); +typedef MMRESULT (WINAPI * MA_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); +typedef MMRESULT (WINAPI * MA_PFN_waveOutClose)(HWAVEOUT hwo); +typedef MMRESULT (WINAPI * MA_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MA_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MA_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MA_PFN_waveOutReset)(HWAVEOUT hwo); +typedef UINT (WINAPI * MA_PFN_waveInGetNumDevs)(void); +typedef MMRESULT (WINAPI * MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic); +typedef MMRESULT (WINAPI * MA_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); +typedef MMRESULT (WINAPI * MA_PFN_waveInClose)(HWAVEIN hwi); +typedef MMRESULT (WINAPI * MA_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MA_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MA_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MA_PFN_waveInStart)(HWAVEIN hwi); +typedef MMRESULT (WINAPI * MA_PFN_waveInReset)(HWAVEIN hwi); -static ma_result ma_result_from_MMRESULT(MA_MMRESULT resultMM) +static ma_result ma_result_from_MMRESULT(MMRESULT resultMM) { - switch (resultMM) - { - case MA_MMSYSERR_NOERROR: return MA_SUCCESS; - case MA_MMSYSERR_BADDEVICEID: return MA_INVALID_ARGS; - case MA_MMSYSERR_INVALHANDLE: return MA_INVALID_ARGS; - case MA_MMSYSERR_NOMEM: return MA_OUT_OF_MEMORY; - case MA_MMSYSERR_INVALFLAG: return MA_INVALID_ARGS; - case MA_MMSYSERR_INVALPARAM: return MA_INVALID_ARGS; - case MA_MMSYSERR_HANDLEBUSY: return MA_BUSY; - case MA_MMSYSERR_ERROR: return MA_ERROR; - default: return MA_ERROR; + switch (resultMM) { + case MMSYSERR_NOERROR: return MA_SUCCESS; + case MMSYSERR_BADDEVICEID: return MA_INVALID_ARGS; + case MMSYSERR_INVALHANDLE: return MA_INVALID_ARGS; + case MMSYSERR_NOMEM: return MA_OUT_OF_MEMORY; + case MMSYSERR_INVALFLAG: return MA_INVALID_ARGS; + case MMSYSERR_INVALPARAM: return MA_INVALID_ARGS; + case MMSYSERR_HANDLEBUSY: return MA_BUSY; + case MMSYSERR_ERROR: return MA_ERROR; + default: return MA_ERROR; } } @@ -25704,7 +18166,7 @@ we can do things generically and typesafely. Names are being kept the same for c */ typedef struct { - CHAR szPname[MA_MAXPNAMELEN]; + CHAR szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; GUID NameGuid; @@ -25790,7 +18252,7 @@ static ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WOR return MA_SUCCESS; } -static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, MA_WAVEFORMATEX* pWF) +static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, WAVEFORMATEX* pWF) { ma_result result; @@ -25842,12 +18304,12 @@ static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, - If the name GUID is not present in the registry we'll also need to stick to the original 31 characters. - I like consistency, so I want the returned device names to be consistent with those returned by WASAPI and DirectSound. The problem, however is that WASAPI and DirectSound use " ()" format (such as "Speakers (High Definition Audio)"), - but WinMM does not specify the component name. From my admittedly limited testing, I've notice the component name seems to + but WinMM does not specificy the component name. From my admittedly limited testing, I've notice the component name seems to usually fit within the 31 characters of the fixed sized buffer, so what I'm going to do is parse that string for the component name, and then concatenate the name from the registry. */ if (!ma_is_guid_null(&pCaps->NameGuid)) { - WCHAR guidStrW[256]; + wchar_t guidStrW[256]; if (((MA_PFN_StringFromGUID2)pContext->win32.StringFromGUID2)(&pCaps->NameGuid, guidStrW, ma_countof(guidStrW)) > 0) { char guidStr[256]; char keyStr[1024]; @@ -25861,10 +18323,10 @@ static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, if (((MA_PFN_RegOpenKeyExA)pContext->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE, keyStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { BYTE nameFromReg[512]; DWORD nameFromRegSize = sizeof(nameFromReg); - LONG resultWin32 = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (BYTE*)nameFromReg, (DWORD*)&nameFromRegSize); + result = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize); ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey); - if (resultWin32 == ERROR_SUCCESS) { + if (result == ERROR_SUCCESS) { /* We have the value from the registry, so now we need to construct the name string. */ char name[1024]; if (ma_strcpy_s(name, sizeof(name), pDeviceInfo->name) == 0) { @@ -25955,13 +18417,13 @@ static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_en /* Playback. */ playbackDeviceCount = ((MA_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)(); for (iPlaybackDevice = 0; iPlaybackDevice < playbackDeviceCount; ++iPlaybackDevice) { - MA_MMRESULT result; + MMRESULT result; MA_WAVEOUTCAPS2A caps; MA_ZERO_OBJECT(&caps); - result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iPlaybackDevice, (MA_WAVEOUTCAPSA*)&caps, sizeof(caps)); - if (result == MA_MMSYSERR_NOERROR) { + result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iPlaybackDevice, (WAVEOUTCAPSA*)&caps, sizeof(caps)); + if (result == MMSYSERR_NOERROR) { ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); @@ -25984,13 +18446,13 @@ static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_en /* Capture. */ captureDeviceCount = ((MA_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)(); for (iCaptureDevice = 0; iCaptureDevice < captureDeviceCount; ++iCaptureDevice) { - MA_MMRESULT result; + MMRESULT result; MA_WAVEINCAPS2A caps; MA_ZERO_OBJECT(&caps); - result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iCaptureDevice, (MA_WAVEINCAPSA*)&caps, sizeof(caps)); - if (result == MA_MMSYSERR_NOERROR) { + result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iCaptureDevice, (WAVEINCAPSA*)&caps, sizeof(caps)); + if (result == MMSYSERR_NOERROR) { ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); @@ -26032,23 +18494,23 @@ static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_devi } if (deviceType == ma_device_type_playback) { - MA_MMRESULT result; + MMRESULT result; MA_WAVEOUTCAPS2A caps; MA_ZERO_OBJECT(&caps); - result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (MA_WAVEOUTCAPSA*)&caps, sizeof(caps)); - if (result == MA_MMSYSERR_NOERROR) { + result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (WAVEOUTCAPSA*)&caps, sizeof(caps)); + if (result == MMSYSERR_NOERROR) { return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo); } } else { - MA_MMRESULT result; + MMRESULT result; MA_WAVEINCAPS2A caps; MA_ZERO_OBJECT(&caps); - result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (MA_WAVEINCAPSA*)&caps, sizeof(caps)); - if (result == MA_MMSYSERR_NOERROR) { + result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (WAVEINCAPSA*)&caps, sizeof(caps)); + if (result == MMSYSERR_NOERROR) { return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo); } } @@ -26062,17 +18524,17 @@ static ma_result ma_device_uninit__winmm(ma_device* pDevice) MA_ASSERT(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture); + ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture); CloseHandle((HANDLE)pDevice->winmm.hEventCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback); - ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback); + ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback); + ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback); CloseHandle((HANDLE)pDevice->winmm.hEventPlayback); } - ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */ @@ -26110,7 +18572,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi return MA_DEVICE_TYPE_NOT_SUPPORTED; } - /* No exclusive mode with WinMM. */ + /* No exlusive mode with WinMM. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; @@ -26125,19 +18587,19 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi /* The capture device needs to be initialized first. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { - MA_WAVEINCAPSA caps; - MA_WAVEFORMATEX wf; - MA_MMRESULT resultMM; + WAVEINCAPSA caps; + WAVEFORMATEX wf; + MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ - pDevice->winmm.hEventCapture = (ma_handle)CreateEventA(NULL, TRUE, TRUE, NULL); + pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventCapture == NULL) { - errorMsg = "[WinMM] Failed to create event for fragment enqueuing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError()); + errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; } /* The format should be based on the device's actual format. */ - if (((MA_PFN_waveInGetDevCapsA)pDevice->pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MA_MMSYSERR_NOERROR) { + if (((MA_PFN_waveInGetDevCapsA)pDevice->pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED; goto on_error; } @@ -26148,8 +18610,8 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi goto on_error; } - resultMM = ((MA_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((MA_HWAVEIN*)&pDevice->winmm.hDeviceCapture, winMMDeviceIDCapture, &wf, (DWORD_PTR)pDevice->winmm.hEventCapture, (DWORD_PTR)pDevice, MA_CALLBACK_EVENT | MA_WAVE_ALLOWSYNC); - if (resultMM != MA_MMSYSERR_NOERROR) { + resultMM = ((MA_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDeviceCapture, winMMDeviceIDCapture, &wf, (DWORD_PTR)pDevice->winmm.hEventCapture, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); + if (resultMM != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE; goto on_error; } @@ -26157,25 +18619,25 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi pDescriptorCapture->format = ma_format_from_WAVEFORMATEX(&wf); pDescriptorCapture->channels = wf.nChannels; pDescriptorCapture->sampleRate = wf.nSamplesPerSec; - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); + ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorCapture->channels, pDescriptorCapture->channelMap); pDescriptorCapture->periodCount = pDescriptorCapture->periodCount; pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - MA_WAVEOUTCAPSA caps; - MA_WAVEFORMATEX wf; - MA_MMRESULT resultMM; + WAVEOUTCAPSA caps; + WAVEFORMATEX wf; + MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ - pDevice->winmm.hEventPlayback = (ma_handle)CreateEventA(NULL, TRUE, TRUE, NULL); + pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventPlayback == NULL) { - errorMsg = "[WinMM] Failed to create event for fragment enqueuing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); + errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; } /* The format should be based on the device's actual format. */ - if (((MA_PFN_waveOutGetDevCapsA)pDevice->pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MA_MMSYSERR_NOERROR) { + if (((MA_PFN_waveOutGetDevCapsA)pDevice->pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED; goto on_error; } @@ -26186,8 +18648,8 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi goto on_error; } - resultMM = ((MA_PFN_waveOutOpen)pDevice->pContext->winmm.waveOutOpen)((MA_HWAVEOUT*)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, MA_CALLBACK_EVENT | MA_WAVE_ALLOWSYNC); - if (resultMM != MA_MMSYSERR_NOERROR) { + resultMM = ((MA_PFN_waveOutOpen)pDevice->pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); + if (resultMM != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE; goto on_error; } @@ -26195,7 +18657,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi pDescriptorPlayback->format = ma_format_from_WAVEFORMATEX(&wf); pDescriptorPlayback->channels = wf.nChannels; pDescriptorPlayback->sampleRate = wf.nSamplesPerSec; - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels); + ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); pDescriptorPlayback->periodCount = pDescriptorPlayback->periodCount; pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); } @@ -26207,13 +18669,13 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi */ heapSize = 0; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { - heapSize += sizeof(MA_WAVEHDR)*pDescriptorCapture->periodCount + (pDescriptorCapture->periodSizeInFrames * pDescriptorCapture->periodCount * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels)); + heapSize += sizeof(WAVEHDR)*pDescriptorCapture->periodCount + (pDescriptorCapture->periodSizeInFrames * pDescriptorCapture->periodCount * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels)); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - heapSize += sizeof(MA_WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels)); + heapSize += sizeof(WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels)); } - pDevice->winmm._pHeapData = (ma_uint8*)ma_calloc(heapSize, &pDevice->pContext->allocationCallbacks); + pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pDevice->pContext->allocationCallbacks); if (pDevice->winmm._pHeapData == NULL) { errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY; goto on_error; @@ -26226,27 +18688,27 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi if (pConfig->deviceType == ma_device_type_capture) { pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData; - pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount)); + pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount)); } else { pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData; - pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount)); + pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount)); } /* Prepare headers. */ for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) { ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->format, pDescriptorCapture->channels); - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData = (char*)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod)); - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes; - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags = 0L; - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops = 0L; - ((MA_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture, &((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(MA_WAVEHDR)); + ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod)); + ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes; + ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags = 0L; + ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops = 0L; + ((MA_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); /* - The user data of the MA_WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means + The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means it's unlocked and available for writing. A value of 1 means it's locked. */ - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0; + ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0; } } @@ -26255,27 +18717,27 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi if (pConfig->deviceType == ma_device_type_playback) { pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData; - pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(MA_WAVEHDR)*pDescriptorPlayback->periodCount); + pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDescriptorPlayback->periodCount); } else { - pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount)); - pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount)) + (pDescriptorCapture->periodSizeInFrames*pDescriptorCapture->periodCount*ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels)); + pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount)); + pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount)) + (pDescriptorCapture->periodSizeInFrames*pDescriptorCapture->periodCount*ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels)); } /* Prepare headers. */ for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) { ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->format, pDescriptorPlayback->channels); - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData = (char*)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod)); - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes; - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags = 0L; - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops = 0L; - ((MA_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback, &((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(MA_WAVEHDR)); + ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod)); + ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes; + ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags = 0L; + ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops = 0L; + ((MA_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR)); /* - The user data of the MA_WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means + The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means it's unlocked and available for writing. A value of 1 means it's locked. */ - ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0; + ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0; } } @@ -26286,31 +18748,26 @@ on_error: if (pDevice->winmm.pWAVEHDRCapture != NULL) { ma_uint32 iPeriod; for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) { - ((MA_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture, &((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(MA_WAVEHDR)); + ((MA_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); } } - ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture); + ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->winmm.pWAVEHDRCapture != NULL) { ma_uint32 iPeriod; for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) { - ((MA_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback, &((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(MA_WAVEHDR)); + ((MA_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR)); } } - ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback); + ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback); } - ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); - - if (errorMsg != NULL && errorMsg[0] != '\0') { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "%s", errorMsg); - } - - return errorCode; + ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode); } static ma_result ma_device_start__winmm(ma_device* pDevice) @@ -26318,21 +18775,20 @@ static ma_result ma_device_start__winmm(ma_device* pDevice) MA_ASSERT(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - MA_MMRESULT resultMM; - MA_WAVEHDR* pWAVEHDR; + MMRESULT resultMM; + WAVEHDR* pWAVEHDR; ma_uint32 iPeriod; - pWAVEHDR = (MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture; + pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture; /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */ ResetEvent((HANDLE)pDevice->winmm.hEventCapture); /* To start the device we attach all of the buffers and then start it. As the buffers are filled with data we will get notifications. */ for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { - resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture, &((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(MA_WAVEHDR)); - if (resultMM != MA_MMSYSERR_NOERROR) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture."); - return ma_result_from_MMRESULT(resultMM); + resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM)); } /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */ @@ -26340,10 +18796,9 @@ static ma_result ma_device_start__winmm(ma_device* pDevice) } /* Capture devices need to be explicitly started, unlike playback devices. */ - resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture); - if (resultMM != MA_MMSYSERR_NOERROR) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device."); - return ma_result_from_MMRESULT(resultMM); + resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture); + if (resultMM != MMSYSERR_NOERROR) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM)); } } @@ -26356,7 +18811,7 @@ static ma_result ma_device_start__winmm(ma_device* pDevice) static ma_result ma_device_stop__winmm(ma_device* pDevice) { - MA_MMRESULT resultMM; + MMRESULT resultMM; MA_ASSERT(pDevice != NULL); @@ -26365,22 +18820,22 @@ static ma_result ma_device_stop__winmm(ma_device* pDevice) return MA_INVALID_ARGS; } - resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture); - if (resultMM != MA_MMSYSERR_NOERROR) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset capture device."); + resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture); + if (resultMM != MMSYSERR_NOERROR) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset capture device.", ma_result_from_MMRESULT(resultMM)); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_uint32 iPeriod; - MA_WAVEHDR* pWAVEHDR; + WAVEHDR* pWAVEHDR; if (pDevice->winmm.hDevicePlayback == NULL) { return MA_INVALID_ARGS; } /* We need to drain the device. To do this we just loop over each header and if it's locked just wait for the event. */ - pWAVEHDR = (MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback; + pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback; for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; iPeriod += 1) { if (pWAVEHDR[iPeriod].dwUser == 1) { /* 1 = locked. */ if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) { @@ -26391,9 +18846,9 @@ static ma_result ma_device_stop__winmm(ma_device* pDevice) } } - resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback); - if (resultMM != MA_MMSYSERR_NOERROR) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset playback device."); + resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback); + if (resultMM != MMSYSERR_NOERROR) { + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM)); } } @@ -26403,9 +18858,9 @@ static ma_result ma_device_stop__winmm(ma_device* pDevice) static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) { ma_result result = MA_SUCCESS; - MA_MMRESULT resultMM; + MMRESULT resultMM; ma_uint32 totalFramesWritten; - MA_WAVEHDR* pWAVEHDR; + WAVEHDR* pWAVEHDR; MA_ASSERT(pDevice != NULL); MA_ASSERT(pPCMFrames != NULL); @@ -26414,7 +18869,7 @@ static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFram *pFramesWritten = 0; } - pWAVEHDR = (MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback; + pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback; /* Keep processing as much data as possible. */ totalFramesWritten = 0; @@ -26439,16 +18894,16 @@ static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFram /* If we've consumed the buffer entirely we need to write it out to the device. */ if (pDevice->winmm.headerFramesConsumedPlayback == (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf)) { pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 1; /* 1 = locked. */ - pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags &= ~MA_WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */ + pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */ /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */ ResetEvent((HANDLE)pDevice->winmm.hEventPlayback); /* The device will be started here. */ - resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((MA_HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(MA_WAVEHDR)); - if (resultMM != MA_MMSYSERR_NOERROR) { + resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { result = ma_result_from_MMRESULT(resultMM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed."); + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.", result); break; } @@ -26474,13 +18929,13 @@ static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFram } /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */ - if ((pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags & MA_WHDR_DONE) != 0) { + if ((pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags & WHDR_DONE) != 0) { pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 0; /* 0 = unlocked (make it available for writing). */ pDevice->winmm.headerFramesConsumedPlayback = 0; } /* If the device has been stopped we need to break. */ - if (ma_device_get_state(pDevice) != ma_device_state_started) { + if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { break; } } @@ -26495,9 +18950,9 @@ static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFram static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) { ma_result result = MA_SUCCESS; - MA_MMRESULT resultMM; + MMRESULT resultMM; ma_uint32 totalFramesRead; - MA_WAVEHDR* pWAVEHDR; + WAVEHDR* pWAVEHDR; MA_ASSERT(pDevice != NULL); MA_ASSERT(pPCMFrames != NULL); @@ -26506,7 +18961,7 @@ static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_ *pFramesRead = 0; } - pWAVEHDR = (MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture; + pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture; /* Keep processing as much data as possible. */ totalFramesRead = 0; @@ -26528,16 +18983,16 @@ static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_ /* If we've consumed the buffer entirely we need to add it back to the device. */ if (pDevice->winmm.headerFramesConsumedCapture == (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf)) { pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 1; /* 1 = locked. */ - pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags &= ~MA_WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */ + pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */ /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */ ResetEvent((HANDLE)pDevice->winmm.hEventCapture); /* The device will be started here. */ - resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((MA_HWAVEIN)pDevice->winmm.hDeviceCapture, &((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(MA_WAVEHDR)); - if (resultMM != MA_MMSYSERR_NOERROR) { + resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { result = ma_result_from_MMRESULT(resultMM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed."); + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.", result); break; } @@ -26563,13 +19018,13 @@ static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_ } /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */ - if ((pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags & MA_WHDR_DONE) != 0) { + if ((pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags & WHDR_DONE) != 0) { pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 0; /* 0 = unlocked (make it available for reading). */ pDevice->winmm.headerFramesConsumedCapture = 0; } /* If the device has been stopped we need to break. */ - if (ma_device_get_state(pDevice) != ma_device_state_started) { + if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { break; } } @@ -26586,7 +19041,7 @@ static ma_result ma_context_uninit__winmm(ma_context* pContext) MA_ASSERT(pContext != NULL); MA_ASSERT(pContext->backend == ma_backend_winmm); - ma_dlclose(ma_context_get_log(pContext), pContext->winmm.hWinMM); + ma_dlclose(pContext, pContext->winmm.hWinMM); return MA_SUCCESS; } @@ -26596,28 +19051,28 @@ static ma_result ma_context_init__winmm(ma_context* pContext, const ma_context_c (void)pConfig; - pContext->winmm.hWinMM = ma_dlopen(ma_context_get_log(pContext), "winmm.dll"); + pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll"); if (pContext->winmm.hWinMM == NULL) { return MA_NO_BACKEND; } - pContext->winmm.waveOutGetNumDevs = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutGetNumDevs"); - pContext->winmm.waveOutGetDevCapsA = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutGetDevCapsA"); - pContext->winmm.waveOutOpen = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutOpen"); - pContext->winmm.waveOutClose = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutClose"); - pContext->winmm.waveOutPrepareHeader = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutPrepareHeader"); - pContext->winmm.waveOutUnprepareHeader = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutUnprepareHeader"); - pContext->winmm.waveOutWrite = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutWrite"); - pContext->winmm.waveOutReset = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveOutReset"); - pContext->winmm.waveInGetNumDevs = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInGetNumDevs"); - pContext->winmm.waveInGetDevCapsA = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInGetDevCapsA"); - pContext->winmm.waveInOpen = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInOpen"); - pContext->winmm.waveInClose = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInClose"); - pContext->winmm.waveInPrepareHeader = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInPrepareHeader"); - pContext->winmm.waveInUnprepareHeader = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInUnprepareHeader"); - pContext->winmm.waveInAddBuffer = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInAddBuffer"); - pContext->winmm.waveInStart = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInStart"); - pContext->winmm.waveInReset = ma_dlsym(ma_context_get_log(pContext), pContext->winmm.hWinMM, "waveInReset"); + pContext->winmm.waveOutGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs"); + pContext->winmm.waveOutGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA"); + pContext->winmm.waveOutOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen"); + pContext->winmm.waveOutClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose"); + pContext->winmm.waveOutPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader"); + pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader"); + pContext->winmm.waveOutWrite = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite"); + pContext->winmm.waveOutReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset"); + pContext->winmm.waveInGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs"); + pContext->winmm.waveInGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA"); + pContext->winmm.waveInOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen"); + pContext->winmm.waveInClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose"); + pContext->winmm.waveInPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader"); + pContext->winmm.waveInUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader"); + pContext->winmm.waveInAddBuffer = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer"); + pContext->winmm.waveInStart = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart"); + pContext->winmm.waveInReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset"); pCallbacks->onContextInit = ma_context_init__winmm; pCallbacks->onContextUninit = ma_context_uninit__winmm; @@ -26645,9 +19100,6 @@ ALSA Backend ******************************************************************************/ #ifdef MA_HAS_ALSA -#include /* poll(), struct pollfd */ -#include /* eventfd() */ - #ifdef MA_NO_RUNTIME_LINKING /* asoundlib.h marks some functions with "inline" which isn't always supported. Need to emulate it. */ @@ -26906,7 +19358,6 @@ typedef int (* ma_snd_pcm_prepare_proc) ( typedef int (* ma_snd_pcm_start_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_drop_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_drain_proc) (ma_snd_pcm_t *pcm); -typedef int (* ma_snd_pcm_reset_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_device_name_hint_proc) (int card, const char *iface, void ***hints); typedef char * (* ma_snd_device_name_get_hint_proc) (const void *hint, const char *id); typedef int (* ma_snd_card_get_index_proc) (const char *name); @@ -26919,13 +19370,9 @@ typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_writei_proc) ( typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_proc) (ma_snd_pcm_t *pcm); typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_update_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_wait_proc) (ma_snd_pcm_t *pcm, int timeout); -typedef int (* ma_snd_pcm_nonblock_proc) (ma_snd_pcm_t *pcm, int nonblock); typedef int (* ma_snd_pcm_info_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_info_t* info); typedef size_t (* ma_snd_pcm_info_sizeof_proc) (void); typedef const char* (* ma_snd_pcm_info_get_name_proc) (const ma_snd_pcm_info_t* info); -typedef int (* ma_snd_pcm_poll_descriptors_proc) (ma_snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); -typedef int (* ma_snd_pcm_poll_descriptors_count_proc) (ma_snd_pcm_t *pcm); -typedef int (* ma_snd_pcm_poll_descriptors_revents_proc) (ma_snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); typedef int (* ma_snd_config_update_free_global_proc) (void); /* This array specifies each of the common devices that can be used for both playback and capture. */ @@ -27192,6 +19639,8 @@ static int ma_convert_device_name_to_hw_format__alsa(ma_context* pContext, char* return -2; /* Failed to retrieve the card index. */ } + /*printf("TESTING: CARD=%s,DEV=%s\n", card, dev); */ + /* Construction. */ dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':'; @@ -27285,14 +19734,13 @@ static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode s } if (!isDeviceOpen) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } else { /* We're trying to open a specific device. There's a few things to consider here: - miniaudio recognizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When + miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw"). */ @@ -27334,8 +19782,7 @@ static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode s } if (resultALSA < 0) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed."); - return ma_result_from_errno(-resultALSA); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.", ma_result_from_errno(-resultALSA)); } } @@ -27391,7 +19838,7 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu /* At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device - initialization time and is used as an indicator to try to use the most appropriate plugin depending on the + initialization time and is used as an indicator to try and use the most appropriate plugin depending on the device type and sharing mode. */ char* dst = hwid; @@ -27406,8 +19853,9 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu goto next_device; /* The device has already been enumerated. Move on to the next one. */ } else { /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */ + size_t oldCapacity = sizeof(*pUniqueIDs) * uniqueIDCount; size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1); - ma_device_id* pNewUniqueIDs = (ma_device_id*)ma_realloc(pUniqueIDs, newCapacity, &pContext->allocationCallbacks); + ma_device_id* pNewUniqueIDs = (ma_device_id*)ma__realloc_from_callbacks(pUniqueIDs, newCapacity, oldCapacity, &pContext->allocationCallbacks); if (pNewUniqueIDs == NULL) { goto next_device; /* Failed to allocate memory. */ } @@ -27472,11 +19920,10 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu /* Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback - again for the other device type in this case. We do this for known devices and where the IOID hint is NULL, which - means both Input and Output. + again for the other device type in this case. We do this for known devices. */ if (cbResult) { - if (ma_is_common_device_name__alsa(NAME) || IOID == NULL) { + if (ma_is_common_device_name__alsa(NAME)) { if (deviceType == ma_device_type_playback) { if (!ma_is_capture_device_blacklisted__alsa(NAME)) { cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); @@ -27505,7 +19952,7 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu } } - ma_free(pUniqueIDs, &pContext->allocationCallbacks); + ma__free_from_callbacks(pUniqueIDs, &pContext->allocationCallbacks); ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock); @@ -27570,7 +20017,7 @@ static void ma_context_iterate_rates_and_add_native_data_format__alsa(ma_context ((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &minSampleRate, &sampleRateDir); ((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &maxSampleRate, &sampleRateDir); - /* Make sure our sample rates are clamped to sane values. Stupid devices like "pulse" will reports rates like "1" which is ridiculous. */ + /* Make sure our sample rates are clamped to sane values. Stupid devices like "pulse" will reports rates like "1" which is ridiculus. */ minSampleRate = ma_clamp(minSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max); maxSampleRate = ma_clamp(maxSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max); @@ -27629,7 +20076,7 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic } /* We need to initialize a HW parameters object in order to know what formats are supported. */ - pHWParams = (ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks); + pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks); if (pHWParams == NULL) { ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); return MA_OUT_OF_MEMORY; @@ -27637,22 +20084,21 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams); if (resultALSA < 0) { - ma_free(pHWParams, &pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed."); - return ma_result_from_errno(-resultALSA); + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA)); } /* Some ALSA devices can support many permutations of formats, channels and rates. We only support a fixed number of permutations which means we need to employ some strategies to ensure the best - combinations are returned. An example is the "pulse" device which can do its own data conversion + combinations are returned. An example is the "pulse" device which can do it's own data conversion in software and as a result can support any combination of format, channels and rate. - We want to ensure that the first data formats are the best. We have a list of favored sample + We want to ensure the the first data formats are the best. We have a list of favored sample formats and sample rates, so these will be the basis of our iteration. */ - + /* Formats. We just iterate over our standard formats and test them, making sure we reset the configuration space each iteration. */ for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); iFormat += 1) { ma_format format = g_maFormatPriorities[iFormat]; @@ -27724,7 +20170,7 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic } } - ma_free(pHWParams, &pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); return MA_SUCCESS; @@ -27736,14 +20182,10 @@ static ma_result ma_device_uninit__alsa(ma_device* pDevice) if ((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); - close(pDevice->alsa.wakeupfdCapture); - ma_free(pDevice->alsa.pPollDescriptorsCapture, &pDevice->pContext->allocationCallbacks); } if ((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); - close(pDevice->alsa.wakeupfdPlayback); - ma_free(pDevice->alsa.pPollDescriptorsPlayback, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -27766,9 +20208,6 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic ma_snd_pcm_hw_params_t* pHWParams; ma_snd_pcm_sw_params_t* pSWParams; ma_snd_pcm_uframes_t bufferBoundary; - int pollDescriptorCount; - struct pollfd* pPollDescriptors; - int wakeupfd; MA_ASSERT(pConfig != NULL); MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should only be called for playback _or_ capture, never duplex. */ @@ -27794,26 +20233,23 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic /* Hardware parameters. */ - pHWParams = (ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_hw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); + pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_hw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); if (pHWParams == NULL) { - ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for hardware parameters."); return MA_OUT_OF_MEMORY; } resultALSA = ((ma_snd_pcm_hw_params_any_proc)pDevice->pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA)); } /* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */ isUsingMMap = MA_FALSE; #if 0 /* NOTE: MMAP mode temporarily disabled. */ if (deviceType != ma_device_type_capture) { /* <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it which means I can't test it... Contributions welcome. */ - if (!pConfig->alsa.noMMap) { + if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) { if (((ma_snd_pcm_hw_params_set_access_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) { pDevice->alsa.isUsingMMap = MA_TRUE; } @@ -27824,10 +20260,9 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic if (!isUsingMMap) { resultALSA = ((ma_snd_pcm_hw_params_set_access_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_RW_INTERLEAVED); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", ma_result_from_errno(-resultALSA)); } } @@ -27855,27 +20290,24 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic } if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats."); - return MA_FORMAT_NOT_SUPPORTED; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.", MA_FORMAT_NOT_SUPPORTED); } } resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", ma_result_from_errno(-resultALSA)); } internalFormat = ma_format_from_alsa(formatALSA); if (internalFormat == ma_format_unknown) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio."); - return MA_FORMAT_NOT_SUPPORTED; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); } } @@ -27888,10 +20320,9 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", ma_result_from_errno(-resultALSA)); } internalChannels = (ma_uint32)channels; @@ -27927,10 +20358,9 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", ma_result_from_errno(-resultALSA)); } internalSampleRate = (ma_uint32)sampleRate; @@ -27942,10 +20372,9 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", ma_result_from_errno(-resultALSA)); } internalPeriods = periods; @@ -27957,10 +20386,9 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", ma_result_from_errno(-resultALSA)); } internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods; @@ -27969,38 +20397,34 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic /* Apply hardware parameters. */ resultALSA = ((ma_snd_pcm_hw_params_proc)pDevice->pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams); if (resultALSA < 0) { - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", ma_result_from_errno(-resultALSA)); } - ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); pHWParams = NULL; /* Software parameters. */ - pSWParams = (ma_snd_pcm_sw_params_t*)ma_calloc(((ma_snd_pcm_sw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_sw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); + pSWParams = (ma_snd_pcm_sw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_sw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_sw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); if (pSWParams == NULL) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for software parameters."); return MA_OUT_OF_MEMORY; } resultALSA = ((ma_snd_pcm_sw_params_current_proc)pDevice->pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams); if (resultALSA < 0) { - ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", ma_result_from_errno(-resultALSA)); } resultALSA = ((ma_snd_pcm_sw_params_set_avail_min_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, ma_prev_power_of_2(internalPeriodSizeInFrames)); if (resultALSA < 0) { - ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", ma_result_from_errno(-resultALSA)); } resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pDevice->pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary); @@ -28008,6 +20432,8 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic bufferBoundary = internalPeriodSizeInFrames * internalPeriods; } + /*printf("TRACE: bufferBoundary=%ld\n", bufferBoundary);*/ + if (deviceType == ma_device_type_playback && !isUsingMMap) { /* Only playback devices in writei/readi mode need a start threshold. */ /* Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to @@ -28015,40 +20441,33 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic */ resultALSA = ((ma_snd_pcm_sw_params_set_start_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalPeriodSizeInFrames*2); if (resultALSA < 0) { - ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", ma_result_from_errno(-resultALSA)); } resultALSA = ((ma_snd_pcm_sw_params_set_stop_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary); if (resultALSA < 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */ - ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.", ma_result_from_errno(-resultALSA)); } } resultALSA = ((ma_snd_pcm_sw_params_proc)pDevice->pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams); if (resultALSA < 0) { - ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", ma_result_from_errno(-resultALSA)); } - ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); pSWParams = NULL; /* Grab the internal channel map. For now we're not going to bother trying to change the channel map and instead just do it ourselves. */ { - ma_snd_pcm_chmap_t* pChmap = NULL; - if (pDevice->pContext->alsa.snd_pcm_get_chmap != NULL) { - pChmap = ((ma_snd_pcm_get_chmap_proc)pDevice->pContext->alsa.snd_pcm_get_chmap)(pPCM); - } - + ma_snd_pcm_chmap_t* pChmap = ((ma_snd_pcm_get_chmap_proc)pDevice->pContext->alsa.snd_pcm_get_chmap)(pPCM); if (pChmap != NULL) { ma_uint32 iChannel; @@ -28068,7 +20487,7 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic ma_bool32 isValid = MA_TRUE; /* Fill with defaults. */ - ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); + ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); /* Overwrite first pChmap->channels channels. */ for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) { @@ -28088,7 +20507,7 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic /* If our channel map is invalid, fall back to defaults. */ if (!isValid) { - ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); + ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); } } @@ -28096,76 +20515,16 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic pChmap = NULL; } else { /* Could not retrieve the channel map. Fall back to a hard-coded assumption. */ - ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); + ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); } } - /* - We need to retrieve the poll descriptors so we can use poll() to wait for data to become - available for reading or writing. There's no well defined maximum for this so we're just going - to allocate this on the heap. - */ - pollDescriptorCount = ((ma_snd_pcm_poll_descriptors_count_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_count)(pPCM); - if (pollDescriptorCount <= 0) { - ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors count."); - return MA_ERROR; - } - - pPollDescriptors = (struct pollfd*)ma_malloc(sizeof(*pPollDescriptors) * (pollDescriptorCount + 1), &pDevice->pContext->allocationCallbacks); /* +1 because we want room for the wakeup descriptor. */ - if (pPollDescriptors == NULL) { - ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for poll descriptors."); - return MA_OUT_OF_MEMORY; - } - - /* - We need an eventfd to wakeup from poll() and avoid a deadlock in situations where the driver - never returns from writei() and readi(). This has been observed with the "pulse" device. - */ - wakeupfd = eventfd(0, 0); - if (wakeupfd < 0) { - ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks); - ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to create eventfd for poll wakeup."); - return ma_result_from_errno(errno); - } - - /* We'll place the wakeup fd at the start of the buffer. */ - pPollDescriptors[0].fd = wakeupfd; - pPollDescriptors[0].events = POLLIN; /* We only care about waiting to read from the wakeup file descriptor. */ - pPollDescriptors[0].revents = 0; - - /* We can now extract the PCM poll descriptors which we place after the wakeup descriptor. */ - pollDescriptorCount = ((ma_snd_pcm_poll_descriptors_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors)(pPCM, pPollDescriptors + 1, pollDescriptorCount); /* +1 because we want to place these descriptors after the wakeup descriptor. */ - if (pollDescriptorCount <= 0) { - close(wakeupfd); - ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks); - ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors."); - return MA_ERROR; - } - - if (deviceType == ma_device_type_capture) { - pDevice->alsa.pollDescriptorCountCapture = pollDescriptorCount; - pDevice->alsa.pPollDescriptorsCapture = pPollDescriptors; - pDevice->alsa.wakeupfdCapture = wakeupfd; - } else { - pDevice->alsa.pollDescriptorCountPlayback = pollDescriptorCount; - pDevice->alsa.pPollDescriptorsPlayback = pPollDescriptors; - pDevice->alsa.wakeupfdPlayback = wakeupfd; - } - - /* We're done. Prepare the device. */ resultALSA = ((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)(pPCM); if (resultALSA < 0) { - close(wakeupfd); - ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.", ma_result_from_errno(-resultALSA)); } @@ -28184,6 +20543,8 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; pDescriptor->periodCount = internalPeriods; + /*printf("format=%d; channels=%d; sampleRate=%d; periodSizeInFrames=%d; periodCount=%d\n", internalFormat, internalChannels, internalSampleRate, internalPeriodSizeInFrames, internalPeriods);*/ + return MA_SUCCESS; } @@ -28221,27 +20582,12 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device."); - return ma_result_from_errno(-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.", ma_result_from_errno(-resultALSA)); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* - When data is written to the device we wait for the device to get ready to receive data with poll(). In my testing - I have observed that poll() can sometimes block forever unless the device is started explicitly with snd_pcm_start() - or some data is written with snd_pcm_writei(). - - To resolve this I've decided to do an explicit start with snd_pcm_start(). The problem with this is that the device - is started without any data in the internal buffer which will result in an immediate underrun. If instead we were - to call into snd_pcm_writei() in an attempt to prevent the underrun, we would run the risk of a weird deadlock - issue as documented inside ma_device_write__alsa(). - */ - resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); - if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start playback device."); - return ma_result_from_errno(-resultALSA); - } + /* Don't need to do anything for playback because it'll be started automatically when enough data has been written. */ } return MA_SUCCESS; @@ -28249,139 +20595,34 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) static ma_result ma_device_stop__alsa(ma_device* pDevice) { - /* - The stop callback will get called on the worker thread after read/write__alsa() has returned. At this point there is - a small chance that our wakeupfd has not been cleared. We'll clear that out now if applicable. - */ - int resultPoll; - int resultRead; - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n"); - ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device successful.\n"); + ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); /* We need to prepare the device again, otherwise we won't be able to restart the device. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device...\n"); if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device failed.\n"); - } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n"); - } - - /* Clear the wakeupfd. */ - resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture, 1, 0); - if (resultPoll > 0) { - ma_uint64 t; - resultRead = read(((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture)[0].fd, &t, sizeof(t)); - if (resultRead != sizeof(t)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from capture wakeupfd. read() = %d\n", resultRead); - } + #ifdef MA_DEBUG_OUTPUT + printf("[ALSA] Failed to prepare capture device after stopping.\n"); + #endif } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device...\n"); - ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device successful.\n"); + ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); /* We need to prepare the device again, otherwise we won't be able to restart the device. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device...\n"); if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device failed.\n"); - } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.\n"); - } - - /* Clear the wakeupfd. */ - resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback, 1, 0); - if (resultPoll > 0) { - ma_uint64 t; - resultRead = read(((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback)[0].fd, &t, sizeof(t)); - if (resultRead != sizeof(t)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from playback wakeupfd. read() = %d\n", resultRead); - } + #ifdef MA_DEBUG_OUTPUT + printf("[ALSA] Failed to prepare playback device after stopping.\n"); + #endif } } return MA_SUCCESS; } -static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, struct pollfd* pPollDescriptors, int pollDescriptorCount, short requiredEvent) -{ - for (;;) { - unsigned short revents; - int resultALSA; - int resultPoll = poll(pPollDescriptors, pollDescriptorCount, -1); - if (resultPoll < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[ALSA] poll() failed.\n"); - - /* - There have been reports that poll() is returning an error randomly and that instead of - returning an error, simply trying again will work. I'm experimenting with adopting this - advice. - */ - continue; - /*return ma_result_from_errno(errno);*/ - } - - /* - Before checking the ALSA poll descriptor flag we need to check if the wakeup descriptor - has had it's POLLIN flag set. If so, we need to actually read the data and then exit the - function. The wakeup descriptor will be the first item in the descriptors buffer. - */ - if ((pPollDescriptors[0].revents & POLLIN) != 0) { - ma_uint64 t; - int resultRead = read(pPollDescriptors[0].fd, &t, sizeof(t)); /* <-- Important that we read here so that the next write() does not block. */ - if (resultRead < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] read() failed.\n"); - return ma_result_from_errno(errno); - } - - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] POLLIN set for wakeupfd\n"); - return MA_DEVICE_NOT_STARTED; - } - - /* - Getting here means that some data should be able to be read. We need to use ALSA to - translate the revents flags for us. - */ - resultALSA = ((ma_snd_pcm_poll_descriptors_revents_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_revents)(pPCM, pPollDescriptors + 1, pollDescriptorCount - 1, &revents); /* +1, -1 to ignore the wakeup descriptor. */ - if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed.\n"); - return ma_result_from_errno(-resultALSA); - } - - if ((revents & POLLERR) != 0) { - ma_snd_pcm_state_t state = ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM); - if (state == MA_SND_PCM_STATE_XRUN) { - /* The PCM is in a xrun state. This will be recovered from at a higher level. We can disregard this. */ - } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[ALSA] POLLERR detected. status = %d\n", ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM)); - } - } - - if ((revents & requiredEvent) == requiredEvent) { - break; /* We're done. Data available for reading or writing. */ - } - } - - return MA_SUCCESS; -} - -static ma_result ma_device_wait_read__alsa(ma_device* pDevice) -{ - return ma_device_wait__alsa(pDevice, (ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, (struct pollfd*)pDevice->alsa.pPollDescriptorsCapture, pDevice->alsa.pollDescriptorCountCapture + 1, POLLIN); /* +1 to account for the wakeup descriptor. */ -} - -static ma_result ma_device_wait_write__alsa(ma_device* pDevice) -{ - return ma_device_wait__alsa(pDevice, (ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, (struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback, pDevice->alsa.pollDescriptorCountPlayback + 1, POLLOUT); /* +1 to account for the wakeup descriptor. */ -} - static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead) { - ma_snd_pcm_sframes_t resultALSA = 0; + ma_snd_pcm_sframes_t resultALSA; MA_ASSERT(pDevice != NULL); MA_ASSERT(pFramesOut != NULL); @@ -28390,40 +20631,34 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u *pFramesRead = 0; } - while (ma_device_get_state(pDevice) == ma_device_state_started) { - ma_result result; - - /* The first thing to do is wait for data to become available for reading. This will return an error code if the device has been stopped. */ - result = ma_device_wait_read__alsa(pDevice); - if (result != MA_SUCCESS) { - return result; - } - - /* Getting here means we should have data available. */ + for (;;) { resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount); if (resultALSA >= 0) { break; /* Success. */ } else { if (resultALSA == -EAGAIN) { - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EGAIN (read)\n");*/ + /*printf("TRACE: EGAIN (read)\n");*/ continue; /* Try again. */ } else if (resultALSA == -EPIPE) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("TRACE: EPIPE (read)\n"); + #endif /* Overrun. Recover and try again. If this fails we need to return an error. */ resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE); if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun."); - return ma_result_from_errno((int)-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", ma_result_from_errno((int)-resultALSA)); } resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun."); - return ma_result_from_errno((int)-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA)); } - continue; /* Try reading again. */ + resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount); + if (resultALSA < 0) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to read data from the internal device.", ma_result_from_errno((int)-resultALSA)); + } } } } @@ -28437,7 +20672,7 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) { - ma_snd_pcm_sframes_t resultALSA = 0; + ma_snd_pcm_sframes_t resultALSA; MA_ASSERT(pDevice != NULL); MA_ASSERT(pFrames != NULL); @@ -28446,30 +20681,23 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, *pFramesWritten = 0; } - while (ma_device_get_state(pDevice) == ma_device_state_started) { - ma_result result; - - /* The first thing to do is wait for space to become available for writing. This will return an error code if the device has been stopped. */ - result = ma_device_wait_write__alsa(pDevice); - if (result != MA_SUCCESS) { - return result; - } - + for (;;) { resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount); if (resultALSA >= 0) { break; /* Success. */ } else { if (resultALSA == -EAGAIN) { - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EGAIN (write)\n");*/ + /*printf("TRACE: EGAIN (write)\n");*/ continue; /* Try again. */ } else if (resultALSA == -EPIPE) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("TRACE: EPIPE (write)\n"); + #endif /* Underrun. Recover and try again. If this fails we need to return an error. */ - resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE); /* MA_TRUE=silent (don't print anything on error). */ - if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun."); - return ma_result_from_errno((int)-resultALSA); + resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE); + if (resultALSA < 0) { /* MA_TRUE=silent (don't print anything on error). */ + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", ma_result_from_errno((int)-resultALSA)); } /* @@ -28481,11 +20709,13 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, */ resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); if (resultALSA < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun."); - return ma_result_from_errno((int)-resultALSA); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA)); } - continue; /* Try writing again. */ + resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount); + if (resultALSA < 0) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write data to device after underrun.", ma_result_from_errno((int)-resultALSA)); + } } } } @@ -28497,33 +20727,6 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, return MA_SUCCESS; } -static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice) -{ - ma_uint64 t = 1; - int resultWrite = 0; - - MA_ASSERT(pDevice != NULL); - - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up...\n"); - - /* Write to an eventfd to trigger a wakeup from poll() and abort any reading or writing. */ - if (pDevice->alsa.pPollDescriptorsCapture != NULL) { - resultWrite = write(pDevice->alsa.wakeupfdCapture, &t, sizeof(t)); - } - if (pDevice->alsa.pPollDescriptorsPlayback != NULL) { - resultWrite = write(pDevice->alsa.wakeupfdPlayback, &t, sizeof(t)); - } - - if (resultWrite < 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] write() failed.\n"); - return ma_result_from_errno(errno); - } - - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up completed successfully.\n"); - - return MA_SUCCESS; -} - static ma_result ma_context_uninit__alsa(ma_context* pContext) { MA_ASSERT(pContext != NULL); @@ -28533,7 +20736,7 @@ static ma_result ma_context_uninit__alsa(ma_context* pContext) ((ma_snd_config_update_free_global_proc)pContext->alsa.snd_config_update_free_global)(); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(ma_context_get_log(pContext), pContext->alsa.asoundSO); + ma_dlclose(pContext, pContext->alsa.asoundSO); #endif ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock); @@ -28543,7 +20746,6 @@ static ma_result ma_context_uninit__alsa(ma_context* pContext) static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) { - ma_result result; #ifndef MA_NO_RUNTIME_LINKING const char* libasoundNames[] = { "libasound.so.2", @@ -28552,83 +20754,80 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co size_t i; for (i = 0; i < ma_countof(libasoundNames); ++i) { - pContext->alsa.asoundSO = ma_dlopen(ma_context_get_log(pContext), libasoundNames[i]); + pContext->alsa.asoundSO = ma_dlopen(pContext, libasoundNames[i]); if (pContext->alsa.asoundSO != NULL) { break; } } if (pContext->alsa.asoundSO == NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to open shared object.\n"); +#ifdef MA_DEBUG_OUTPUT + printf("[ALSA] Failed to open shared object.\n"); +#endif return MA_NO_BACKEND; } - pContext->alsa.snd_pcm_open = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_open"); - pContext->alsa.snd_pcm_close = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_close"); - pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); - pContext->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); - pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); - pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); - pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); - pContext->alsa.snd_pcm_hw_params_set_channels = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels"); - pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); - pContext->alsa.snd_pcm_hw_params_set_channels_minmax = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_minmax"); - pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); - pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate"); - pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); - pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); - pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); - pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); - pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); - pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); - pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min"); - pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max"); - pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); - pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min"); - pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max"); - pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); - pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); - pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); - pContext->alsa.snd_pcm_hw_params_test_format = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_test_format"); - pContext->alsa.snd_pcm_hw_params_test_channels = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_test_channels"); - pContext->alsa.snd_pcm_hw_params_test_rate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params_test_rate"); - pContext->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_hw_params"); - pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); - pContext->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); - pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary"); - pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); - pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); - pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold"); - pContext->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_sw_params"); - pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); - pContext->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); - pContext->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_get_chmap"); - pContext->alsa.snd_pcm_state = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_state"); - pContext->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_prepare"); - pContext->alsa.snd_pcm_start = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_start"); - pContext->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_drop"); - pContext->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_drain"); - pContext->alsa.snd_pcm_reset = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_reset"); - pContext->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_device_name_hint"); - pContext->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_device_name_get_hint"); - pContext->alsa.snd_card_get_index = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_card_get_index"); - pContext->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_device_name_free_hint"); - pContext->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); - pContext->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); - pContext->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_recover"); - pContext->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_readi"); - pContext->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_writei"); - pContext->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_avail"); - pContext->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_avail_update"); - pContext->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_wait"); - pContext->alsa.snd_pcm_nonblock = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_nonblock"); - pContext->alsa.snd_pcm_info = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_info"); - pContext->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); - pContext->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_info_get_name"); - pContext->alsa.snd_pcm_poll_descriptors = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_poll_descriptors"); - pContext->alsa.snd_pcm_poll_descriptors_count = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_poll_descriptors_count"); - pContext->alsa.snd_pcm_poll_descriptors_revents = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_pcm_poll_descriptors_revents"); - pContext->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->alsa.asoundSO, "snd_config_update_free_global"); + pContext->alsa.snd_pcm_open = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_open"); + pContext->alsa.snd_pcm_close = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_close"); + pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); + pContext->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); + pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); + pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); + pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); + pContext->alsa.snd_pcm_hw_params_set_channels = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels"); + pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); + pContext->alsa.snd_pcm_hw_params_set_channels_minmax = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_minmax"); + pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); + pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate"); + pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); + pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); + pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); + pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); + pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); + pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); + pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min"); + pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max"); + pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); + pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min"); + pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max"); + pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); + pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); + pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); + pContext->alsa.snd_pcm_hw_params_test_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_format"); + pContext->alsa.snd_pcm_hw_params_test_channels = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_channels"); + pContext->alsa.snd_pcm_hw_params_test_rate = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_rate"); + pContext->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params"); + pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); + pContext->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); + pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary"); + pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); + pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); + pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold"); + pContext->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params"); + pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); + pContext->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); + pContext->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_get_chmap"); + pContext->alsa.snd_pcm_state = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_state"); + pContext->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_prepare"); + pContext->alsa.snd_pcm_start = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_start"); + pContext->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drop"); + pContext->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drain"); + pContext->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_hint"); + pContext->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_get_hint"); + pContext->alsa.snd_card_get_index = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_card_get_index"); + pContext->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_free_hint"); + pContext->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); + pContext->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); + pContext->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_recover"); + pContext->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_readi"); + pContext->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_writei"); + pContext->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail"); + pContext->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail_update"); + pContext->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_wait"); + pContext->alsa.snd_pcm_info = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info"); + pContext->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); + pContext->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_get_name"); + pContext->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_config_update_free_global"); #else /* The system below is just for type safety. */ ma_snd_pcm_open_proc _snd_pcm_open = snd_pcm_open; @@ -28676,7 +20875,6 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_start_proc _snd_pcm_start = snd_pcm_start; ma_snd_pcm_drop_proc _snd_pcm_drop = snd_pcm_drop; ma_snd_pcm_drain_proc _snd_pcm_drain = snd_pcm_drain; - ma_snd_pcm_reset_proc _snd_pcm_reset = snd_pcm_reset; ma_snd_device_name_hint_proc _snd_device_name_hint = snd_device_name_hint; ma_snd_device_name_get_hint_proc _snd_device_name_get_hint = snd_device_name_get_hint; ma_snd_card_get_index_proc _snd_card_get_index = snd_card_get_index; @@ -28689,13 +20887,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_avail_proc _snd_pcm_avail = snd_pcm_avail; ma_snd_pcm_avail_update_proc _snd_pcm_avail_update = snd_pcm_avail_update; ma_snd_pcm_wait_proc _snd_pcm_wait = snd_pcm_wait; - ma_snd_pcm_nonblock_proc _snd_pcm_nonblock = snd_pcm_nonblock; ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info; ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof; ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name; - ma_snd_pcm_poll_descriptors _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; - ma_snd_pcm_poll_descriptors_count _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; - ma_snd_pcm_poll_descriptors_revents _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global; pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open; @@ -28743,7 +20937,6 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.snd_pcm_start = (ma_proc)_snd_pcm_start; pContext->alsa.snd_pcm_drop = (ma_proc)_snd_pcm_drop; pContext->alsa.snd_pcm_drain = (ma_proc)_snd_pcm_drain; - pContext->alsa.snd_pcm_reset = (ma_proc)_snd_pcm_reset; pContext->alsa.snd_device_name_hint = (ma_proc)_snd_device_name_hint; pContext->alsa.snd_device_name_get_hint = (ma_proc)_snd_device_name_get_hint; pContext->alsa.snd_card_get_index = (ma_proc)_snd_card_get_index; @@ -28756,22 +20949,16 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.snd_pcm_avail = (ma_proc)_snd_pcm_avail; pContext->alsa.snd_pcm_avail_update = (ma_proc)_snd_pcm_avail_update; pContext->alsa.snd_pcm_wait = (ma_proc)_snd_pcm_wait; - pContext->alsa.snd_pcm_nonblock = (ma_proc)_snd_pcm_nonblock; pContext->alsa.snd_pcm_info = (ma_proc)_snd_pcm_info; pContext->alsa.snd_pcm_info_sizeof = (ma_proc)_snd_pcm_info_sizeof; pContext->alsa.snd_pcm_info_get_name = (ma_proc)_snd_pcm_info_get_name; - pContext->alsa.snd_pcm_poll_descriptors = (ma_proc)_snd_pcm_poll_descriptors; - pContext->alsa.snd_pcm_poll_descriptors_count = (ma_proc)_snd_pcm_poll_descriptors_count; - pContext->alsa.snd_pcm_poll_descriptors_revents = (ma_proc)_snd_pcm_poll_descriptors_revents; pContext->alsa.snd_config_update_free_global = (ma_proc)_snd_config_update_free_global; #endif pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration; - result = ma_mutex_init(&pContext->alsa.internalDeviceEnumLock); - if (result != MA_SUCCESS) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration."); - return result; + if (ma_mutex_init(&pContext->alsa.internalDeviceEnumLock) != MA_SUCCESS) { + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.", MA_ERROR); } pCallbacks->onContextInit = ma_context_init__alsa; @@ -28785,11 +20972,10 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pCallbacks->onDeviceRead = ma_device_read__alsa; pCallbacks->onDeviceWrite = ma_device_write__alsa; pCallbacks->onDeviceDataLoop = NULL; - pCallbacks->onDeviceDataLoopWakeup = ma_device_data_loop_wakeup__alsa; return MA_SUCCESS; } -#endif /* MA_HAS_ALSA */ +#endif /* ALSA */ @@ -28800,7 +20986,7 @@ PulseAudio Backend ******************************************************************************/ #ifdef MA_HAS_PULSEAUDIO /* -The PulseAudio API, along with Apple's Core Audio, is the worst of the mainstream audio APIs. This is a brief description of what's going on +The PulseAudio API, along with Apple's Core Audio, is the worst of the maintream audio APIs. This is a brief description of what's going on in the PulseAudio backend. I apologize if this gets a bit ranty for your liking - you might want to skip this discussion. PulseAudio has something they call the "Simple API", which unfortunately isn't suitable for miniaudio. I've not seen anywhere where it @@ -28815,7 +21001,7 @@ get fun, and I don't mean that in a good way... The problems start with the very name of the API - "asynchronous". Yes, this is an asynchronous oriented API which means your commands don't immediately take effect. You instead need to issue your commands, and then wait for them to complete. The waiting mechanism is -enabled through the use of a "main loop". In the asynchronous API you cannot get away from the main loop, and the main loop is where almost +enabled through the use of a "main loop". In the asychronous API you cannot get away from the main loop, and the main loop is where almost all of PulseAudio's problems stem from. When you first initialize PulseAudio you need an object referred to as "main loop". You can implement this yourself by defining your own @@ -28865,7 +21051,7 @@ because PulseAudio takes it literally, specifically the "can be". You would thin writing and reading data to and from the stream, and that would be right, except when it's not. When you initialize the stream, you can set a flag that tells PulseAudio to not start the stream automatically. This is required because miniaudio does not auto-start devices straight after initialization - you need to call `ma_device_start()` manually. The problem is that even when this flag is specified, -PulseAudio will immediately fire its write or read callback. This is *technically* correct (based on the wording in the documentation) +PulseAudio will immediately fire it's write or read callback. This is *technically* correct (based on the wording in the documentation) because indeed, data *can* be written at this point. The problem is that it's not *practical*. It makes sense that the write/read callback would be where a program will want to write or read data to or from the stream, but when it's called before the application has even requested that the stream be started, it's just not practical because the program probably isn't ready for any kind of data delivery at @@ -28873,7 +21059,7 @@ that point (it may still need to load files or whatnot). Instead, this callback stream be started which is how it works with literally *every* other callback-based audio API. Since miniaudio forbids firing of the data callback until the device has been started (as it should be with *all* callback based APIs), logic needs to be added to ensure miniaudio doesn't just blindly fire the application-defined data callback from within the PulseAudio callback before the stream has actually been -started. The device state is used for this - if the state is anything other than `ma_device_state_starting` or `ma_device_state_started`, the main data +started. The device state is used for this - if the state is anything other than `MA_STATE_STARTING` or `MA_STATE_STARTED`, the main data callback is not fired. This, unfortunately, is not the end of the problems with the PulseAudio write callback. Any normal callback based audio API will @@ -28939,7 +21125,6 @@ to check for type safety. We cannot do this when linking at run time because the #define MA_PA_ERR_ACCESS PA_ERR_ACCESS #define MA_PA_ERR_INVALID PA_ERR_INVALID #define MA_PA_ERR_NOENTITY PA_ERR_NOENTITY -#define MA_PA_ERR_NOTSUPPORTED PA_ERR_NOTSUPPORTED #define MA_PA_CHANNELS_MAX PA_CHANNELS_MAX #define MA_PA_RATE_MAX PA_RATE_MAX @@ -29135,14 +21320,12 @@ typedef pa_sink_info_cb_t ma_pa_sink_info_cb_t; typedef pa_source_info_cb_t ma_pa_source_info_cb_t; typedef pa_stream_success_cb_t ma_pa_stream_success_cb_t; typedef pa_stream_request_cb_t ma_pa_stream_request_cb_t; -typedef pa_stream_notify_cb_t ma_pa_stream_notify_cb_t; typedef pa_free_cb_t ma_pa_free_cb_t; #else #define MA_PA_OK 0 #define MA_PA_ERR_ACCESS 1 #define MA_PA_ERR_INVALID 2 #define MA_PA_ERR_NOENTITY 5 -#define MA_PA_ERR_NOTSUPPORTED 19 #define MA_PA_CHANNELS_MAX 32 #define MA_PA_RATE_MAX 384000 @@ -29416,7 +21599,6 @@ typedef void (* ma_pa_sink_info_cb_t) (ma_pa_context* c, const ma_pa_sink_in typedef void (* ma_pa_source_info_cb_t) (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata); typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata); typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata); -typedef void (* ma_pa_stream_notify_cb_t) (ma_pa_stream* s, void* userdata); typedef void (* ma_pa_free_cb_t) (void* p); #endif @@ -29468,9 +21650,6 @@ typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) ( typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); -typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); -typedef void (* ma_pa_stream_set_moved_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); -typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); @@ -29664,7 +21843,7 @@ static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position } #endif -static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP) +static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operation* pOP) { int resultPA; ma_pa_operation_state_t state; @@ -29678,7 +21857,7 @@ static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_ptr pMain break; /* Done. */ } - resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL); if (resultPA < 0) { return ma_result_from_pulse(resultPA); } @@ -29687,7 +21866,7 @@ static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_ptr pMain return MA_SUCCESS; } -static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP) +static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_pa_operation* pOP) { ma_result result; @@ -29695,29 +21874,28 @@ static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma return MA_INVALID_ARGS; } - result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP); + result = ma_wait_for_operation__pulse(pContext, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); return result; } -static ma_result ma_wait_for_pa_context_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr pPulseContext) +static ma_result ma_context_wait_for_pa_context_to_connect__pulse(ma_context* pContext) { int resultPA; ma_pa_context_state_t state; for (;;) { - state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pPulseContext); + state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pContext->pulse.pPulseContext); if (state == MA_PA_CONTEXT_READY) { break; /* Done. */ } if (state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context."); - return MA_ERROR; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.", MA_ERROR); } - resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL); if (resultPA < 0) { return ma_result_from_pulse(resultPA); } @@ -29727,23 +21905,22 @@ static ma_result ma_wait_for_pa_context_to_connect__pulse(ma_context* pContext, return MA_SUCCESS; } -static ma_result ma_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr pStream) +static ma_result ma_context_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_pa_stream* pStream) { int resultPA; ma_pa_stream_state_t state; for (;;) { - state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pStream); + state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)(pStream); if (state == MA_PA_STREAM_READY) { break; /* Done. */ } if (state == MA_PA_STREAM_FAILED || state == MA_PA_STREAM_TERMINATED) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream."); - return MA_ERROR; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream.", MA_ERROR); } - resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL); if (resultPA < 0) { return ma_result_from_pulse(resultPA); } @@ -29753,52 +21930,6 @@ static ma_result ma_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, m } -static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, const char* pApplicationName, const char* pServerName, ma_bool32 tryAutoSpawn, ma_ptr* ppMainLoop, ma_ptr* ppPulseContext) -{ - ma_result result; - ma_ptr pMainLoop; - ma_ptr pPulseContext; - - MA_ASSERT(ppMainLoop != NULL); - MA_ASSERT(ppPulseContext != NULL); - - /* The PulseAudio context maps well to miniaudio's notion of a context. The pa_context object will be initialized as part of the ma_context. */ - pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); - if (pMainLoop == NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop."); - return MA_FAILED_TO_INIT_BACKEND; - } - - pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pMainLoop), pApplicationName); - if (pPulseContext == NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context."); - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); - return MA_FAILED_TO_INIT_BACKEND; - } - - /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ - result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); - if (result != MA_SUCCESS) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context."); - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); - return result; - } - - /* Since ma_context_init() runs synchronously we need to wait for the PulseAudio context to connect before we return. */ - result = ma_wait_for_pa_context_to_connect__pulse(pContext, pMainLoop, pPulseContext); - if (result != MA_SUCCESS) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Waiting for connection failed."); - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); - return result; - } - - *ppMainLoop = pMainLoop; - *ppPulseContext = pPulseContext; - - return MA_SUCCESS; -} - - static void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_pa_sink_info* pInfoOut; @@ -29807,14 +21938,6 @@ static void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_ return; } - /* - There has been a report that indicates that pInfo can be null which results - in a null pointer dereference below. We'll check for this for safety. - */ - if (pInfo == NULL) { - return; - } - pInfoOut = (ma_pa_sink_info*)pUserData; MA_ASSERT(pInfoOut != NULL); @@ -29831,14 +21954,6 @@ static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const m return; } - /* - There has been a report that indicates that pInfo can be null which results - in a null pointer dereference below. We'll check for this for safety. - */ - if (pInfo == NULL) { - return; - } - pInfoOut = (ma_pa_source_info*)pUserData; MA_ASSERT(pInfoOut != NULL); @@ -29847,7 +21962,6 @@ static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const m (void)pPulseContext; /* Unused. */ } -#if 0 static void ma_device_sink_name_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_device* pDevice; @@ -29879,7 +21993,7 @@ static void ma_device_source_name_callback(ma_pa_context* pPulseContext, const m (void)pPulseContext; /* Unused. */ } -#endif + static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_sink_info* pSinkInfo) { @@ -29890,7 +22004,7 @@ static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const cha return MA_ERROR; } - return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); + return ma_wait_for_operation_and_unref__pulse(pContext, pOP); } static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_source_info* pSourceInfo) @@ -29902,7 +22016,7 @@ static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const c return MA_ERROR; } - return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); + return ma_wait_for_operation_and_unref__pulse(pContext, pOP);; } static ma_result ma_context_get_default_device_index__pulse(ma_context* pContext, ma_device_type deviceType, ma_uint32* pIndex) @@ -30046,7 +22160,7 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en goto done; } - result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP); + result = ma_wait_for_operation__pulse(pContext, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { @@ -30063,7 +22177,7 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en goto done; } - result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP); + result = ma_wait_for_operation__pulse(pContext, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { @@ -30162,29 +22276,22 @@ static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_devi ma_result result = MA_SUCCESS; ma_context_get_device_info_callback_data__pulse callbackData; ma_pa_operation* pOP = NULL; - const char* pDeviceName = NULL; MA_ASSERT(pContext != NULL); callbackData.pDeviceInfo = pDeviceInfo; callbackData.foundDevice = MA_FALSE; - if (pDeviceID != NULL) { - pDeviceName = pDeviceID->pulse; - } else { - pDeviceName = NULL; - } - result = ma_context_get_default_device_index__pulse(pContext, deviceType, &callbackData.defaultDeviceIndex); if (deviceType == ma_device_type_playback) { - pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceName, ma_context_get_device_info_sink_callback__pulse, &callbackData); + pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceID->pulse, ma_context_get_device_info_sink_callback__pulse, &callbackData); } else { - pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceName, ma_context_get_device_info_source_callback__pulse, &callbackData); + pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceID->pulse, ma_context_get_device_info_source_callback__pulse, &callbackData); } if (pOP != NULL) { - ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); + ma_wait_for_operation_and_unref__pulse(pContext, pOP); } else { result = MA_ERROR; goto done; @@ -30222,10 +22329,6 @@ static ma_result ma_device_uninit__pulse(ma_device* pDevice) ma_duplex_rb_uninit(&pDevice->duplexRB); } - ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext); - ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext); - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); - return MA_SUCCESS; } @@ -30241,22 +22344,20 @@ static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFra return attr; } -static ma_pa_stream* ma_device__pa_stream_new__pulse(ma_device* pDevice, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) +static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) { - static ma_atomic_uint32 g_StreamCounter = { 0 }; + static int g_StreamCounter = 0; char actualStreamName[256]; if (pStreamName != NULL) { ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1); } else { - const char* pBaseName = "miniaudio:"; - size_t baseNameLen = strlen(pBaseName); - ma_strcpy_s(actualStreamName, sizeof(actualStreamName), pBaseName); - ma_itoa_s((int)ma_atomic_uint32_get(&g_StreamCounter), actualStreamName + baseNameLen, sizeof(actualStreamName)-baseNameLen, 10); + ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:"); + ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10); /* 8 = strlen("miniaudio:") */ } - ma_atomic_uint32_fetch_add(&g_StreamCounter, 1); + g_StreamCounter += 1; - return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap); + return ((ma_pa_stream_new_proc)pContext->pulse.pa_stream_new)((ma_pa_context*)pContext->pulse.pPulseContext, actualStreamName, ss, cmap); } @@ -30264,28 +22365,18 @@ static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, vo { ma_device* pDevice = (ma_device*)pUserData; ma_uint32 bpf; - ma_uint32 deviceState; ma_uint64 frameCount; ma_uint64 framesProcessed; MA_ASSERT(pDevice != NULL); - /* - Don't do anything if the device isn't initialized yet. Yes, this can happen because PulseAudio - can fire this callback before the stream has even started. Ridiculous. - */ - deviceState = ma_device_get_state(pDevice); - if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) { - return; - } - bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); MA_ASSERT(bpf > 0); frameCount = byteCount / bpf; framesProcessed = 0; - while (ma_device_get_state(pDevice) == ma_device_state_started && framesProcessed < frameCount) { + while (ma_device_get_state(pDevice) == MA_STATE_STARTED && framesProcessed < frameCount) { const void* pMappedPCMFrames; size_t bytesMapped; ma_uint64 framesMapped; @@ -30301,7 +22392,9 @@ static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, vo ma_device_handle_backend_data_callback(pDevice, NULL, pMappedPCMFrames, framesMapped); } else { /* It's a hole. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] ma_device_on_read__pulse: Hole.\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[PulseAudio] ma_device_on_read__pulse: Hole.\n"); + #endif } pulseResult = ((ma_pa_stream_drop_proc)pDevice->pContext->pulse.pa_stream_drop)(pStream); @@ -30347,11 +22440,10 @@ static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stre framesMapped = bytesMapped / bpf; - if (deviceState == ma_device_state_started || deviceState == ma_device_state_starting) { /* Check for starting state just in case this is being used to do the initial fill. */ + if (deviceState == MA_STATE_STARTED) { ma_device_handle_backend_data_callback(pDevice, pMappedPCMFrames, NULL, framesMapped); } else { - /* Device is not started. Write silence. */ - ma_silence_pcm_frames(pMappedPCMFrames, framesMapped, pDevice->playback.format, pDevice->playback.channels); + /* Device is not started. Don't write anything to it. */ } pulseResult = ((ma_pa_stream_write_proc)pDevice->pContext->pulse.pa_stream_write)(pStream, pMappedPCMFrames, bytesMapped, NULL, 0, MA_PA_SEEK_RELATIVE); @@ -30362,7 +22454,7 @@ static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stre framesProcessed += framesMapped; } else { - result = MA_SUCCESS; /* No data available for writing. */ + result = MA_ERROR; /* No data available. Abort. */ goto done; } } else { @@ -30394,7 +22486,7 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v can fire this callback before the stream has even started. Ridiculous. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) { + if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) { return; } @@ -30409,7 +22501,7 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v /* Don't keep trying to process frames if the device isn't started. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) { + if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) { break; } @@ -30422,70 +22514,16 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v } } -static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData) -{ - ma_device* pDevice = (ma_device*)pUserData; - int suspended; - - (void)pStream; - - suspended = ((ma_pa_stream_is_suspended_proc)pDevice->pContext->pulse.pa_stream_is_suspended)(pStream); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. pa_stream_is_suspended() returned %d.\n", suspended); - - if (suspended < 0) { - return; - } - - if (suspended == 1) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n"); - ma_device__on_notification_stopped(pDevice); - } else { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n"); - ma_device__on_notification_started(pDevice); - } -} - -static void ma_device_on_rerouted__pulse(ma_pa_stream* pStream, void* pUserData) -{ - ma_device* pDevice = (ma_device*)pUserData; - - (void)pStream; - (void)pUserData; - - ma_device__on_notification_rerouted(pDevice); -} - -static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__pulse(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) -{ - /* - There have been reports from users where buffers of < ~20ms result glitches when running through - PipeWire. To work around this we're going to have to use a different default buffer size. - */ - const ma_uint32 defaultPeriodSizeInMilliseconds_LowLatency = 25; - const ma_uint32 defaultPeriodSizeInMilliseconds_Conservative = MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE; - - MA_ASSERT(nativeSampleRate != 0); - - if (pDescriptor->periodSizeInFrames == 0) { - if (pDescriptor->periodSizeInMilliseconds == 0) { - if (performanceProfile == ma_performance_profile_low_latency) { - return ma_calculate_buffer_size_in_frames_from_milliseconds(defaultPeriodSizeInMilliseconds_LowLatency, nativeSampleRate); - } else { - return ma_calculate_buffer_size_in_frames_from_milliseconds(defaultPeriodSizeInMilliseconds_Conservative, nativeSampleRate); - } - } else { - return ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate); - } - } else { - return pDescriptor->periodSizeInFrames; - } -} - static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { /* Notes for PulseAudio: + - We're always using native format/channels/rate regardless of whether or not PulseAudio + supports the format directly through their own data conversion system. I'm doing this to + reduce as much variability from the PulseAudio side as possible because it's seems to be + extremely unreliable at everything it does. + - When both the period size in frames and milliseconds are 0, we default to miniaudio's default buffer sizes rather than leaving it up to PulseAudio because I don't trust PulseAudio to give us any kind of reasonable latency by default. @@ -30507,8 +22545,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ma_pa_channel_map cmap; ma_pa_buffer_attr attr; const ma_pa_sample_spec* pActualSS = NULL; + const ma_pa_channel_map* pActualCMap = NULL; const ma_pa_buffer_attr* pActualAttr = NULL; - const ma_pa_channel_map* pActualChannelMap = NULL; ma_uint32 iChannel; ma_pa_stream_flags_t streamFlags; @@ -30539,74 +22577,33 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi if (pDescriptorCapture->pDeviceID != NULL) { devCapture = pDescriptorCapture->pDeviceID->pulse; } - + format = pDescriptorCapture->format; channels = pDescriptorCapture->channels; sampleRate = pDescriptorCapture->sampleRate; } - - - result = ma_init_pa_mainloop_and_pa_context__pulse(pDevice->pContext, pDevice->pContext->pulse.pApplicationName, pDevice->pContext->pulse.pServerName, MA_FALSE, &pDevice->pulse.pMainLoop, &pDevice->pulse.pPulseContext); - if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize PA mainloop and context for device.\n"); - return result; - } - if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { result = ma_context_get_source_info__pulse(pDevice->pContext, devCapture, &sourceInfo); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device."); + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.", result); goto on_error0; } ss = sourceInfo.sample_spec; cmap = sourceInfo.channel_map; - /* Use the requested channel count if we have one. */ - if (pDescriptorCapture->channels != 0) { - ss.channels = pDescriptorCapture->channels; - } - - /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); - - /* Use the requested sample rate if one was specified. */ - if (pDescriptorCapture->sampleRate != 0) { - ss.rate = pDescriptorCapture->sampleRate; - } - streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY; - - if (ma_format_from_pulse(ss.format) == ma_format_unknown) { - if (ma_is_little_endian()) { - ss.format = MA_PA_SAMPLE_FLOAT32LE; - } else { - ss.format = MA_PA_SAMPLE_FLOAT32BE; - } - streamFlags |= MA_PA_STREAM_FIX_FORMAT; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n"); - } - if (ss.rate == 0) { - ss.rate = MA_DEFAULT_SAMPLE_RATE; - streamFlags |= MA_PA_STREAM_FIX_RATE; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate); - } - if (ss.channels == 0) { - ss.channels = MA_DEFAULT_CHANNELS; - streamFlags |= MA_PA_STREAM_FIX_CHANNELS; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels); - } - /* We now have enough information to calculate our actual period size in frames. */ - pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorCapture, ss.rate, pConfig->performanceProfile); + pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, ss.rate, pConfig->performanceProfile); attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); + #ifdef MA_DEBUG_OUTPUT + printf("[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); + #endif - pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap); + pDevice->pulse.pStreamCapture = ma_context__pa_stream_new__pulse(pDevice->pContext, pConfig->pulse.pStreamNameCapture, &ss, &cmap); if (pDevice->pulse.pStreamCapture == NULL) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.\n"); - result = MA_ERROR; + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); goto on_error0; } @@ -30614,78 +22611,42 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi /* The callback needs to be set before connecting the stream. */ ((ma_pa_stream_set_read_callback_proc)pDevice->pContext->pulse.pa_stream_set_read_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_read__pulse, pDevice); - /* State callback for checking when the device has been corked. */ - ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_suspended__pulse, pDevice); - - /* Rerouting notification. */ - ((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_rerouted__pulse, pDevice); - /* Connect after we've got all of our internal state set up. */ + streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; if (devCapture != NULL) { streamFlags |= MA_PA_STREAM_DONT_MOVE; } error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); if (error != MA_PA_OK) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream."); - result = ma_result_from_pulse(error); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error)); goto on_error1; } - result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamCapture); + result = ma_context_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, (ma_pa_stream*)pDevice->pulse.pStreamCapture); if (result != MA_SUCCESS) { goto on_error2; } - /* Internal format. */ pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (pActualSS != NULL) { ss = *pActualSS; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate); - } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve capture sample spec.\n"); } pDescriptorCapture->format = ma_format_from_pulse(ss.format); pDescriptorCapture->channels = ss.channels; pDescriptorCapture->sampleRate = ss.rate; - if (pDescriptorCapture->format == ma_format_unknown || pDescriptorCapture->channels == 0 || pDescriptorCapture->sampleRate == 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Capture sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorCapture->format), pDescriptorCapture->channels, pDescriptorCapture->sampleRate); - result = MA_ERROR; - goto on_error4; - } - - /* Internal channel map. */ - pActualChannelMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); - if (pActualChannelMap == NULL) { - pActualChannelMap = &cmap; /* Fallback just in case. */ + pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + if (pActualCMap != NULL) { + cmap = *pActualCMap; } - /* - Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting - the channel map. To somewhat workaround this, I'm hacking in a hard coded channel map for mono - and stereo. In this case it should be safe to assume mono = MONO and stereo = LEFT/RIGHT. For - all other channel counts we need to just put up with whatever PipeWire reports and hope it gets - fixed sooner than later. I might remove this hack later. - */ - if (pDescriptorCapture->channels > 2) { - for (iChannel = 0; iChannel < pDescriptorCapture->channels; iChannel += 1) { - pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(pActualChannelMap->map[iChannel]); - } - } else { - /* Hack for mono and stereo. */ - if (pDescriptorCapture->channels == 1) { - pDescriptorCapture->channelMap[0] = MA_CHANNEL_MONO; - } else if (pDescriptorCapture->channels == 2) { - pDescriptorCapture->channelMap[0] = MA_CHANNEL_FRONT_LEFT; - pDescriptorCapture->channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } else { - MA_ASSERT(MA_FALSE); /* Should never hit this. */ - } + for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { + pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); } @@ -30695,102 +22656,66 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi attr = *pActualAttr; } - if (attr.fragsize > 0) { - pDescriptorCapture->periodCount = ma_max(attr.maxlength / attr.fragsize, 1); - } else { - pDescriptorCapture->periodCount = 1; - } - + pDescriptorCapture->periodCount = attr.maxlength / attr.fragsize; pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); + #ifdef MA_DEBUG_OUTPUT + printf("[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); + #endif + + + /* Name. */ + devCapture = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + if (devCapture != NULL) { + ma_pa_operation* pOP = ((ma_pa_context_get_source_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pContext->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice); + ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); + } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.\n"); + ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.", result); goto on_error2; } ss = sinkInfo.sample_spec; cmap = sinkInfo.channel_map; - /* Use the requested channel count if we have one. */ - if (pDescriptorPlayback->channels != 0) { - ss.channels = pDescriptorPlayback->channels; - } - - /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); - - - /* Use the requested sample rate if one was specified. */ - if (pDescriptorPlayback->sampleRate != 0) { - ss.rate = pDescriptorPlayback->sampleRate; - } - - streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY; - if (ma_format_from_pulse(ss.format) == ma_format_unknown) { - if (ma_is_little_endian()) { - ss.format = MA_PA_SAMPLE_FLOAT32LE; - } else { - ss.format = MA_PA_SAMPLE_FLOAT32BE; - } - streamFlags |= MA_PA_STREAM_FIX_FORMAT; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n"); - } - if (ss.rate == 0) { - ss.rate = MA_DEFAULT_SAMPLE_RATE; - streamFlags |= MA_PA_STREAM_FIX_RATE; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate); - } - if (ss.channels == 0) { - ss.channels = MA_DEFAULT_CHANNELS; - streamFlags |= MA_PA_STREAM_FIX_CHANNELS; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels); - } - /* We now have enough information to calculate the actual buffer size in frames. */ - pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorPlayback, ss.rate, pConfig->performanceProfile); + pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, ss.rate, pConfig->performanceProfile); attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss); + #ifdef MA_DEBUG_OUTPUT + printf("[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); + #endif - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); - - pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap); + pDevice->pulse.pStreamPlayback = ma_context__pa_stream_new__pulse(pDevice->pContext, pConfig->pulse.pStreamNamePlayback, &ss, &cmap); if (pDevice->pulse.pStreamPlayback == NULL) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.\n"); - result = MA_ERROR; + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); goto on_error2; } /* Note that this callback will be fired as soon as the stream is connected, even though it's started as corked. The callback needs to handle a - device state of ma_device_state_uninitialized. + device state of MA_STATE_UNINITIALIZED. */ ((ma_pa_stream_set_write_callback_proc)pDevice->pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice); - /* State callback for checking when the device has been corked. */ - ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_suspended__pulse, pDevice); - - /* Rerouting notification. */ - ((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_rerouted__pulse, pDevice); - /* Connect after we've got all of our internal state set up. */ + streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; if (devPlayback != NULL) { streamFlags |= MA_PA_STREAM_DONT_MOVE; } error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); if (error != MA_PA_OK) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream."); - result = ma_result_from_pulse(error); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error)); goto on_error3; } - result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamPlayback); + result = ma_context_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, (ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (result != MA_SUCCESS) { goto on_error3; } @@ -30800,49 +22725,20 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (pActualSS != NULL) { ss = *pActualSS; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate); - } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve playback sample spec.\n"); } pDescriptorPlayback->format = ma_format_from_pulse(ss.format); pDescriptorPlayback->channels = ss.channels; pDescriptorPlayback->sampleRate = ss.rate; - if (pDescriptorPlayback->format == ma_format_unknown || pDescriptorPlayback->channels == 0 || pDescriptorPlayback->sampleRate == 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Playback sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorPlayback->format), pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate); - result = MA_ERROR; - goto on_error4; - } - - /* Internal channel map. */ - pActualChannelMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); - if (pActualChannelMap == NULL) { - pActualChannelMap = &cmap; /* Fallback just in case. */ + pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + if (pActualCMap != NULL) { + cmap = *pActualCMap; } - /* - Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting - the channel map. To somewhat workaround this, I'm hacking in a hard coded channel map for mono - and stereo. In this case it should be safe to assume mono = MONO and stereo = LEFT/RIGHT. For - all other channel counts we need to just put up with whatever PipeWire reports and hope it gets - fixed sooner than later. I might remove this hack later. - */ - if (pDescriptorPlayback->channels > 2) { - for (iChannel = 0; iChannel < pDescriptorPlayback->channels; iChannel += 1) { - pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(pActualChannelMap->map[iChannel]); - } - } else { - /* Hack for mono and stereo. */ - if (pDescriptorPlayback->channels == 1) { - pDescriptorPlayback->channelMap[0] = MA_CHANNEL_MONO; - } else if (pDescriptorPlayback->channels == 2) { - pDescriptorPlayback->channelMap[0] = MA_CHANNEL_FRONT_LEFT; - pDescriptorPlayback->channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } else { - MA_ASSERT(MA_FALSE); /* Should never hit this. */ - } + for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { + pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); } @@ -30852,14 +22748,19 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi attr = *pActualAttr; } - if (attr.tlength > 0) { - pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1); - } else { - pDescriptorPlayback->periodCount = 1; - } - + pDescriptorPlayback->periodCount = attr.maxlength / attr.tlength; pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); + #ifdef MA_DEBUG_OUTPUT + printf("[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalPeriodSizeInFrames); + #endif + + + /* Name. */ + devPlayback = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + if (devPlayback != NULL) { + ma_pa_operation* pOP = ((ma_pa_context_get_sink_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pContext->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice); + ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); + } } @@ -30870,13 +22771,9 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi onDeviceDataLoop callback is NULL, which is not the case for PulseAudio. */ if (pConfig->deviceType == ma_device_type_duplex) { - ma_format rbFormat = (format != ma_format_unknown) ? format : pDescriptorCapture->format; - ma_uint32 rbChannels = (channels > 0) ? channels : pDescriptorCapture->channels; - ma_uint32 rbSampleRate = (sampleRate > 0) ? sampleRate : pDescriptorCapture->sampleRate; - - result = ma_duplex_rb_init(rbFormat, rbChannels, rbSampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB); + result = ma_duplex_rb_init(format, channels, sampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB); if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer. %s.\n", ma_result_description(result)); + result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer.", result); goto on_error4; } } @@ -30935,19 +22832,20 @@ static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_typ pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful); if (pOP == NULL) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE); } - result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP); + result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.", result); } if (!wasSuccessful) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to %s PulseAudio stream.", (cork) ? "stop" : "start"); - return MA_ERROR; + if (cork) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to stop PulseAudio stream.", MA_FAILED_TO_STOP_BACKEND_DEVICE); + } else { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to start PulseAudio stream.", MA_FAILED_TO_START_BACKEND_DEVICE); + } } return MA_SUCCESS; @@ -30967,12 +22865,11 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* - We need to fill some data before uncorking. Not doing this will result in the write callback - never getting fired. We're not going to abort if writing fails because I still want the device - to get uncorked. - */ - ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); /* No need to check the result here. Always want to fall through an uncork.*/ + /* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */ + result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); + if (result != MA_SUCCESS) { + return result; /* Failed to write data. Not sure what to do here... Just aborting. */ + } result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0); if (result != MA_SUCCESS) { @@ -30986,6 +22883,7 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) static ma_result ma_device_stop__pulse(ma_device* pDevice) { ma_result result; + ma_bool32 wasSuccessful; MA_ASSERT(pDevice != NULL); @@ -30997,16 +22895,9 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice) } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* - Ideally we would drain the device here, but there's been cases where PulseAudio seems to be - broken on some systems to the point where no audio processing seems to happen. When this - happens, draining never completes and we get stuck here. For now I'm disabling draining of - the device so we don't just freeze the application. - */ - #if 0 + /* The stream needs to be drained if it's a playback device. */ ma_pa_operation* pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful); - ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP); - #endif + ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1); if (result != MA_SUCCESS) { @@ -31029,8 +22920,8 @@ static ma_result ma_device_data_loop__pulse(ma_device* pDevice) All data is handled through callbacks. All we need to do is iterate over the main loop and let the callbacks deal with it. */ - while (ma_device_get_state(pDevice) == ma_device_state_started) { - resultPA = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL); + while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { + resultPA = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pContext->pulse.pMainLoop, 1, NULL); if (resultPA < 0) { break; } @@ -31044,7 +22935,7 @@ static ma_result ma_device_data_loop_wakeup__pulse(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - ((ma_pa_mainloop_wakeup_proc)pDevice->pContext->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); + ((ma_pa_mainloop_wakeup_proc)pDevice->pContext->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)pDevice->pContext->pulse.pMainLoop); return MA_SUCCESS; } @@ -31058,11 +22949,8 @@ static ma_result ma_context_uninit__pulse(ma_context* pContext) ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pContext->pulse.pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pContext->pulse.pMainLoop); - ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks); - ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks); - #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(ma_context_get_log(pContext), pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_SUCCESS; @@ -31079,7 +22967,7 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c size_t i; for (i = 0; i < ma_countof(libpulseNames); ++i) { - pContext->pulse.pulseSO = ma_dlopen(ma_context_get_log(pContext), libpulseNames[i]); + pContext->pulse.pulseSO = ma_dlopen(pContext, libpulseNames[i]); if (pContext->pulse.pulseSO != NULL) { break; } @@ -31089,67 +22977,64 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c return MA_NO_BACKEND; } - pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_mainloop_new"); - pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_mainloop_free"); - pContext->pulse.pa_mainloop_quit = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_mainloop_quit"); - pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_mainloop_get_api"); - pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_mainloop_iterate"); - pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_mainloop_wakeup"); - pContext->pulse.pa_threaded_mainloop_new = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_new"); - pContext->pulse.pa_threaded_mainloop_free = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_free"); - pContext->pulse.pa_threaded_mainloop_start = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_start"); - pContext->pulse.pa_threaded_mainloop_stop = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_stop"); - pContext->pulse.pa_threaded_mainloop_lock = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_lock"); - pContext->pulse.pa_threaded_mainloop_unlock = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_unlock"); - pContext->pulse.pa_threaded_mainloop_wait = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_wait"); - pContext->pulse.pa_threaded_mainloop_signal = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_signal"); - pContext->pulse.pa_threaded_mainloop_accept = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_accept"); - pContext->pulse.pa_threaded_mainloop_get_retval = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_get_retval"); - pContext->pulse.pa_threaded_mainloop_get_api = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_get_api"); - pContext->pulse.pa_threaded_mainloop_in_thread = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_in_thread"); - pContext->pulse.pa_threaded_mainloop_set_name = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_threaded_mainloop_set_name"); - pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_new"); - pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_unref"); - pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_connect"); - pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_disconnect"); - pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_set_state_callback"); - pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_get_state"); - pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_get_sink_info_list"); - pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_get_source_info_list"); - pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name"); - pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_context_get_source_info_by_name"); - pContext->pulse.pa_operation_unref = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_operation_unref"); - pContext->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_operation_get_state"); - pContext->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_channel_map_init_extend"); - pContext->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_channel_map_valid"); - pContext->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_channel_map_compatible"); - pContext->pulse.pa_stream_new = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_new"); - pContext->pulse.pa_stream_unref = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_unref"); - pContext->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_connect_playback"); - pContext->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_connect_record"); - pContext->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_disconnect"); - pContext->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_get_state"); - pContext->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_get_sample_spec"); - pContext->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_get_channel_map"); - pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_get_buffer_attr"); - pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_set_buffer_attr"); - pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_get_device_name"); - pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_set_write_callback"); - pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_set_read_callback"); - pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_set_suspended_callback"); - pContext->pulse.pa_stream_set_moved_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_set_moved_callback"); - pContext->pulse.pa_stream_is_suspended = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_is_suspended"); - pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_flush"); - pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_drain"); - pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_is_corked"); - pContext->pulse.pa_stream_cork = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_cork"); - pContext->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_trigger"); - pContext->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_begin_write"); - pContext->pulse.pa_stream_write = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_write"); - pContext->pulse.pa_stream_peek = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_peek"); - pContext->pulse.pa_stream_drop = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_drop"); - pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_writable_size"); - pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->pulse.pulseSO, "pa_stream_readable_size"); + pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new"); + pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free"); + pContext->pulse.pa_mainloop_quit = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_quit"); + pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api"); + pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate"); + pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup"); + pContext->pulse.pa_threaded_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_new"); + pContext->pulse.pa_threaded_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_free"); + pContext->pulse.pa_threaded_mainloop_start = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_start"); + pContext->pulse.pa_threaded_mainloop_stop = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_stop"); + pContext->pulse.pa_threaded_mainloop_lock = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_lock"); + pContext->pulse.pa_threaded_mainloop_unlock = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_unlock"); + pContext->pulse.pa_threaded_mainloop_wait = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_wait"); + pContext->pulse.pa_threaded_mainloop_signal = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_signal"); + pContext->pulse.pa_threaded_mainloop_accept = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_accept"); + pContext->pulse.pa_threaded_mainloop_get_retval = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_retval"); + pContext->pulse.pa_threaded_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_api"); + pContext->pulse.pa_threaded_mainloop_in_thread = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_in_thread"); + pContext->pulse.pa_threaded_mainloop_set_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_set_name"); + pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new"); + pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref"); + pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect"); + pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect"); + pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback"); + pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state"); + pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list"); + pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list"); + pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name"); + pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name"); + pContext->pulse.pa_operation_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_unref"); + pContext->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_get_state"); + pContext->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_init_extend"); + pContext->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_valid"); + pContext->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_compatible"); + pContext->pulse.pa_stream_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_new"); + pContext->pulse.pa_stream_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_unref"); + pContext->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_playback"); + pContext->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_record"); + pContext->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_disconnect"); + pContext->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_state"); + pContext->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_sample_spec"); + pContext->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_channel_map"); + pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_buffer_attr"); + pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_buffer_attr"); + pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name"); + pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback"); + pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback"); + pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush"); + pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain"); + pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked"); + pContext->pulse.pa_stream_cork = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_cork"); + pContext->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_trigger"); + pContext->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_begin_write"); + pContext->pulse.pa_stream_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_write"); + pContext->pulse.pa_stream_peek = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_peek"); + pContext->pulse.pa_stream_drop = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drop"); + pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size"); + pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size"); #else /* This strange assignment system is just for type safety. */ ma_pa_mainloop_new_proc _pa_mainloop_new = pa_mainloop_new; @@ -31199,9 +23084,6 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c ma_pa_stream_get_device_name_proc _pa_stream_get_device_name = pa_stream_get_device_name; ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback = pa_stream_set_write_callback; ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback = pa_stream_set_read_callback; - ma_pa_stream_set_suspended_callback_proc _pa_stream_set_suspended_callback = pa_stream_set_suspended_callback; - ma_pa_stream_set_moved_callback_proc _pa_stream_set_moved_callback = pa_stream_set_moved_callback; - ma_pa_stream_is_suspended_proc _pa_stream_is_suspended = pa_stream_is_suspended; ma_pa_stream_flush_proc _pa_stream_flush = pa_stream_flush; ma_pa_stream_drain_proc _pa_stream_drain = pa_stream_drain; ma_pa_stream_is_corked_proc _pa_stream_is_corked = pa_stream_is_corked; @@ -31261,9 +23143,6 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_get_device_name = (ma_proc)_pa_stream_get_device_name; pContext->pulse.pa_stream_set_write_callback = (ma_proc)_pa_stream_set_write_callback; pContext->pulse.pa_stream_set_read_callback = (ma_proc)_pa_stream_set_read_callback; - pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)_pa_stream_set_suspended_callback; - pContext->pulse.pa_stream_set_moved_callback = (ma_proc)_pa_stream_set_moved_callback; - pContext->pulse.pa_stream_is_suspended = (ma_proc)_pa_stream_is_suspended; pContext->pulse.pa_stream_flush = (ma_proc)_pa_stream_flush; pContext->pulse.pa_stream_drain = (ma_proc)_pa_stream_drain; pContext->pulse.pa_stream_is_corked = (ma_proc)_pa_stream_is_corked; @@ -31277,28 +23156,48 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_readable_size = (ma_proc)_pa_stream_readable_size; #endif - /* We need to make a copy of the application and server names so we can pass them to the pa_context of each device. */ - pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName, &pContext->allocationCallbacks); - if (pContext->pulse.pApplicationName == NULL && pConfig->pulse.pApplicationName != NULL) { - return MA_OUT_OF_MEMORY; - } - - pContext->pulse.pServerName = ma_copy_string(pConfig->pulse.pServerName, &pContext->allocationCallbacks); - if (pContext->pulse.pServerName == NULL && pConfig->pulse.pServerName != NULL) { - ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - - result = ma_init_pa_mainloop_and_pa_context__pulse(pContext, pConfig->pulse.pApplicationName, pConfig->pulse.pServerName, pConfig->pulse.tryAutoSpawn, &pContext->pulse.pMainLoop, &pContext->pulse.pPulseContext); - if (result != MA_SUCCESS) { - ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks); - ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks); + /* The PulseAudio context maps well to miniaudio's notion of a context. The pa_context object will be initialized as part of the ma_context. */ + pContext->pulse.pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); + if (pContext->pulse.pMainLoop == NULL) { + result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop.", MA_FAILED_TO_INIT_BACKEND); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(ma_context_get_log(pContext), pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return result; } + pContext->pulse.pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pContext->pulse.pMainLoop), pConfig->pulse.pApplicationName); + if (pContext->pulse.pPulseContext == NULL) { + result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context.", MA_FAILED_TO_INIT_BACKEND); + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop)); + #ifndef MA_NO_RUNTIME_LINKING + ma_dlclose(pContext, pContext->pulse.pulseSO); + #endif + return result; + } + + /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ + result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pContext->pulse.pPulseContext, pConfig->pulse.pServerName, (pConfig->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + if (result != MA_SUCCESS) { + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.", result); + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop)); + #ifndef MA_NO_RUNTIME_LINKING + ma_dlclose(pContext, pContext->pulse.pulseSO); + #endif + return result; + } + + /* Since ma_context_init() runs synchronously we need to wait for the PulseAudio context to connect before we return. */ + result = ma_context_wait_for_pa_context_to_connect__pulse(pContext); + if (result != MA_SUCCESS) { + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop)); + #ifndef MA_NO_RUNTIME_LINKING + ma_dlclose(pContext, pContext->pulse.pulseSO); + #endif + return result; + } + + /* With pa_mainloop we run a synchronous backend, but we implement our own main loop. */ pCallbacks->onContextInit = ma_context_init__pulse; pCallbacks->onContextUninit = ma_context_uninit__pulse; @@ -31463,8 +23362,7 @@ static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_devic /* The channel count and sample rate can only be determined by opening the device. */ result = ma_context_open_client__jack(pContext, &pClient); if (result != MA_SUCCESS) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client."); - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result); } pDeviceInfo->nativeDataFormats[0].sampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient); @@ -31473,8 +23371,7 @@ static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_devic ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ((deviceType == ma_device_type_playback) ? ma_JackPortIsInput : ma_JackPortIsOutput)); if (ppPorts == NULL) { ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } while (ppPorts[pDeviceInfo->nativeDataFormats[0].channels] != NULL) { @@ -31506,13 +23403,11 @@ static ma_result ma_device_uninit__jack(ma_device* pDevice) } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); - ma_free(pDevice->jack.ppPortsCapture, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); - ma_free(pDevice->jack.ppPortsPlayback, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -31534,12 +23429,12 @@ static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, vo if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { size_t newBufferSize = frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat)); - float* pNewBuffer = (float*)ma_calloc(newBufferSize, &pDevice->pContext->allocationCallbacks); + float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks); if (pNewBuffer == NULL) { return MA_OUT_OF_MEMORY; } - ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); pDevice->jack.pIntermediaryBufferCapture = pNewBuffer; pDevice->playback.internalPeriodSizeInFrames = frameCount; @@ -31547,12 +23442,12 @@ static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, vo if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { size_t newBufferSize = frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat)); - float* pNewBuffer = (float*)ma_calloc(newBufferSize, &pDevice->pContext->allocationCallbacks); + float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks); if (pNewBuffer == NULL) { return MA_OUT_OF_MEMORY; } - ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer; pDevice->playback.internalPeriodSizeInFrames = frameCount; @@ -31576,7 +23471,7 @@ static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { /* Channels need to be interleaved. */ for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { - const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.ppPortsCapture[iChannel], frameCount); + const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsCapture[iChannel], frameCount); if (pSrc != NULL) { float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel; ma_jack_nframes_t iFrame; @@ -31597,7 +23492,7 @@ static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* /* Channels need to be deinterleaved. */ for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { - float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.ppPortsPlayback[iChannel], frameCount); + float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[iChannel], frameCount); if (pDst != NULL) { const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel; ma_jack_nframes_t iFrame; @@ -31623,39 +23518,33 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config MA_ASSERT(pDevice != NULL); if (pConfig->deviceType == ma_device_type_loopback) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Loopback mode not supported."); return MA_DEVICE_TYPE_NOT_SUPPORTED; } /* Only supporting default devices with JACK. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->pDeviceID != NULL && pDescriptorPlayback->pDeviceID->jack != 0) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->pDeviceID != NULL && pDescriptorCapture->pDeviceID->jack != 0)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Only default devices are supported."); return MA_NO_DEVICE; } /* No exclusive mode with the JACK backend. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Exclusive mode not supported."); return MA_SHARE_MODE_NOT_SUPPORTED; } /* Open the client. */ result = ma_context_open_client__jack(pDevice->pContext, (ma_jack_client_t**)&pDevice->jack.pClient); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result); } /* Callbacks. */ if (((ma_jack_set_process_callback_proc)pDevice->pContext->jack.jack_set_process_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_process_callback, pDevice) != 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (((ma_jack_set_buffer_size_callback_proc)pDevice->pContext->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_buffer_size_callback, pDevice) != 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } ((ma_jack_on_shutdown_proc)pDevice->pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice); @@ -31665,42 +23554,31 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config periodSizeInFrames = ((ma_jack_get_buffer_size_proc)pDevice->pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient); if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { - ma_uint32 iPort; const char** ppPorts; pDescriptorCapture->format = ma_format_f32; pDescriptorCapture->channels = 0; pDescriptorCapture->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); + ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDescriptorCapture->channels, pDescriptorCapture->channelMap); ppPorts = ((ma_jack_get_ports_proc)pDevice->pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput); if (ppPorts == NULL) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } - /* Need to count the number of ports first so we can allocate some memory. */ while (ppPorts[pDescriptorCapture->channels] != NULL) { - pDescriptorCapture->channels += 1; - } - - pDevice->jack.ppPortsCapture = (ma_ptr*)ma_malloc(sizeof(*pDevice->jack.ppPortsCapture) * pDescriptorCapture->channels, &pDevice->pContext->allocationCallbacks); - if (pDevice->jack.ppPortsCapture == NULL) { - return MA_OUT_OF_MEMORY; - } - - for (iPort = 0; iPort < pDescriptorCapture->channels; iPort += 1) { char name[64]; ma_strcpy_s(name, sizeof(name), "capture"); - ma_itoa_s((int)iPort, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */ + ma_itoa_s((int)pDescriptorCapture->channels, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */ - pDevice->jack.ppPortsCapture[iPort] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0); - if (pDevice->jack.ppPortsCapture[iPort] == NULL) { + pDevice->jack.pPortsCapture[pDescriptorCapture->channels] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0); + if (pDevice->jack.pPortsCapture[pDescriptorCapture->channels] == NULL) { ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); ma_device_uninit__jack(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } + + pDescriptorCapture->channels += 1; } ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); @@ -31708,7 +23586,7 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config pDescriptorCapture->periodSizeInFrames = periodSizeInFrames; pDescriptorCapture->periodCount = 1; /* There's no notion of a period in JACK. Just set to 1. */ - pDevice->jack.pIntermediaryBufferCapture = (float*)ma_calloc(pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels), &pDevice->pContext->allocationCallbacks); + pDevice->jack.pIntermediaryBufferCapture = (float*)ma__calloc_from_callbacks(pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels), &pDevice->pContext->allocationCallbacks); if (pDevice->jack.pIntermediaryBufferCapture == NULL) { ma_device_uninit__jack(pDevice); return MA_OUT_OF_MEMORY; @@ -31716,43 +23594,31 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - ma_uint32 iPort; const char** ppPorts; pDescriptorPlayback->format = ma_format_f32; pDescriptorPlayback->channels = 0; pDescriptorPlayback->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels); + ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); ppPorts = ((ma_jack_get_ports_proc)pDevice->pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput); if (ppPorts == NULL) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } - /* Need to count the number of ports first so we can allocate some memory. */ while (ppPorts[pDescriptorPlayback->channels] != NULL) { - pDescriptorPlayback->channels += 1; - } - - pDevice->jack.ppPortsPlayback = (ma_ptr*)ma_malloc(sizeof(*pDevice->jack.ppPortsPlayback) * pDescriptorPlayback->channels, &pDevice->pContext->allocationCallbacks); - if (pDevice->jack.ppPortsPlayback == NULL) { - ma_free(pDevice->jack.ppPortsCapture, &pDevice->pContext->allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - - for (iPort = 0; iPort < pDescriptorPlayback->channels; iPort += 1) { char name[64]; ma_strcpy_s(name, sizeof(name), "playback"); - ma_itoa_s((int)iPort, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */ + ma_itoa_s((int)pDescriptorPlayback->channels, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */ - pDevice->jack.ppPortsPlayback[iPort] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0); - if (pDevice->jack.ppPortsPlayback[iPort] == NULL) { + pDevice->jack.pPortsPlayback[pDescriptorPlayback->channels] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0); + if (pDevice->jack.pPortsPlayback[pDescriptorPlayback->channels] == NULL) { ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); ma_device_uninit__jack(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } + + pDescriptorPlayback->channels += 1; } ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); @@ -31760,7 +23626,7 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames; pDescriptorPlayback->periodCount = 1; /* There's no notion of a period in JACK. Just set to 1. */ - pDevice->jack.pIntermediaryBufferPlayback = (float*)ma_calloc(pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels), &pDevice->pContext->allocationCallbacks); + pDevice->jack.pIntermediaryBufferPlayback = (float*)ma__calloc_from_callbacks(pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels), &pDevice->pContext->allocationCallbacks); if (pDevice->jack.pIntermediaryBufferPlayback == NULL) { ma_device_uninit__jack(pDevice); return MA_OUT_OF_MEMORY; @@ -31779,28 +23645,25 @@ static ma_result ma_device_start__jack(ma_device* pDevice) resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient); if (resultJACK != 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client."); - return MA_FAILED_TO_START_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.", MA_FAILED_TO_START_BACKEND_DEVICE); } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput); if (ppServerPorts == NULL) { ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR); } for (i = 0; ppServerPorts[i] != NULL; ++i) { const char* pServerPort = ppServerPorts[i]; - const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.ppPortsCapture[i]); + const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsCapture[i]); resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort); if (resultJACK != 0) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR); } } @@ -31811,20 +23674,18 @@ static ma_result ma_device_start__jack(ma_device* pDevice) const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput); if (ppServerPorts == NULL) { ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR); } for (i = 0; ppServerPorts[i] != NULL; ++i) { const char* pServerPort = ppServerPorts[i]; - const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.ppPortsPlayback[i]); + const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[i]); resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pClientPort, pServerPort); if (resultJACK != 0) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR); } } @@ -31837,13 +23698,16 @@ static ma_result ma_device_start__jack(ma_device* pDevice) static ma_result ma_device_stop__jack(ma_device* pDevice) { ma_context* pContext = pDevice->pContext; + ma_stop_proc onStop; if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.", MA_ERROR); } - ma_device__on_notification_stopped(pDevice); + onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); + } return MA_SUCCESS; } @@ -31858,7 +23722,7 @@ static ma_result ma_context_uninit__jack(ma_context* pContext) pContext->jack.pClientName = NULL; #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(ma_context_get_log(pContext), pContext->jack.jackSO); + ma_dlclose(pContext, pContext->jack.jackSO); #endif return MA_SUCCESS; @@ -31868,11 +23732,10 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co { #ifndef MA_NO_RUNTIME_LINKING const char* libjackNames[] = { -#if defined(MA_WIN32) +#ifdef MA_WIN32 "libjack.dll", "libjack64.dll" -#endif -#if defined(MA_UNIX) +#else "libjack.so", "libjack.so.0" #endif @@ -31880,7 +23743,7 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co size_t i; for (i = 0; i < ma_countof(libjackNames); ++i) { - pContext->jack.jackSO = ma_dlopen(ma_context_get_log(pContext), libjackNames[i]); + pContext->jack.jackSO = ma_dlopen(pContext, libjackNames[i]); if (pContext->jack.jackSO != NULL) { break; } @@ -31890,22 +23753,22 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co return MA_NO_BACKEND; } - pContext->jack.jack_client_open = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_client_open"); - pContext->jack.jack_client_close = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_client_close"); - pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_client_name_size"); - pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_set_process_callback"); - pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_set_buffer_size_callback"); - pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_on_shutdown"); - pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_get_sample_rate"); - pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_get_buffer_size"); - pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_get_ports"); - pContext->jack.jack_activate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_activate"); - pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_deactivate"); - pContext->jack.jack_connect = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_connect"); - pContext->jack.jack_port_register = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_port_register"); - pContext->jack.jack_port_name = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_port_name"); - pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_port_get_buffer"); - pContext->jack.jack_free = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->jack.jackSO, "jack_free"); + pContext->jack.jack_client_open = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open"); + pContext->jack.jack_client_close = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close"); + pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size"); + pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback"); + pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback"); + pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown"); + pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate"); + pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size"); + pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports"); + pContext->jack.jack_activate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate"); + pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate"); + pContext->jack.jack_connect = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect"); + pContext->jack.jack_port_register = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register"); + pContext->jack.jack_port_name = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name"); + pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer"); + pContext->jack.jack_free = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free"); #else /* This strange assignment system is here just to ensure type safety of miniaudio's function pointer @@ -31961,7 +23824,7 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co if (result != MA_SUCCESS) { ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(ma_context_get_log(pContext), pContext->jack.jackSO); + ma_dlclose(pContext, pContext->jack.jackSO); #endif return MA_NO_BACKEND; } @@ -31984,7 +23847,7 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* MA_HAS_JACK */ +#endif /* JACK */ @@ -32009,13 +23872,6 @@ References #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 #define MA_APPLE_WATCH #endif - #if __has_feature(objc_arc) - #define MA_BRIDGE_TRANSFER __bridge_transfer - #define MA_BRIDGE_RETAINED __bridge_retained - #else - #define MA_BRIDGE_TRANSFER - #define MA_BRIDGE_RETAINED - #endif #else #define MA_APPLE_DESKTOP #endif @@ -32075,7 +23931,7 @@ that supports this level of detail. There was some public domain sample code I s and AudioUnit APIs, but I couldn't see anything that gave low-level control over device selection and capabilities (the distinction between playback and capture in particular). Therefore, miniaudio is using the AudioObject API. -Most (all?) functions in the AudioObject API take a AudioObjectID as its input. This is the device identifier. When +Most (all?) functions in the AudioObject API take a AudioObjectID as it's input. This is the device identifier. When retrieving global information, such as the device list, you use kAudioObjectSystemObject. When retrieving device-specific data, you pass in the ID for that device. In order to retrieve device-specific IDs you need to enumerate over each of the devices. This is done using the AudioObjectGetPropertyDataSize() and AudioObjectGetPropertyData() APIs which seem to be @@ -32086,7 +23942,7 @@ structure with three variables and is used to identify which property you are ge which is basically the specific property that you're wanting to retrieve or set. The second is the "scope", which is typically set to kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeInput for input-specific properties and kAudioObjectPropertyScopeOutput for output-specific properties. The last is the "element" which is always set to -kAudioObjectPropertyElementMain in miniaudio's case. I don't know of any cases where this would be set to anything different. +kAudioObjectPropertyElementMaster in miniaudio's case. I don't know of any cases where this would be set to anything different. Back to the earlier issue of device retrieval, you first use the AudioObjectGetPropertyDataSize() API to retrieve the size of the raw data which is just a list of AudioDeviceID's. You use the kAudioObjectSystemObject AudioObjectID, and a property @@ -32095,18 +23951,6 @@ size, allocate a block of memory of that size and then call AudioObjectGetProper AudioDeviceID's so just do "dataSize/sizeof(AudioDeviceID)" to know the device count. */ -#if defined(MA_APPLE_MOBILE) -static void ma_device__on_notification_interruption_began(ma_device* pDevice) -{ - ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_began)); -} - -static void ma_device__on_notification_interruption_ended(ma_device* pDevice) -{ - ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_ended)); -} -#endif - static ma_result ma_result_from_OSStatus(OSStatus status) { switch (status) @@ -32366,22 +24210,22 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* case kAudioChannelLayoutTag_Binaural: case kAudioChannelLayoutTag_Ambisonic_B_Format: { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); + ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap); } break; case kAudioChannelLayoutTag_Octagonal: { pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; - } MA_FALLTHROUGH; /* Intentional fallthrough. */ + } /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Hexagonal: { pChannelMap[5] = MA_CHANNEL_BACK_CENTER; - } MA_FALLTHROUGH; /* Intentional fallthrough. */ + } /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Pentagonal: { pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - } MA_FALLTHROUGH; /* Intentional fallthrough. */ + } /* Intentional fallghrough. */ case kAudioChannelLayoutTag_Quadraphonic: { pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; @@ -32394,7 +24238,7 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* default: { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); + ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap); } break; } } @@ -32402,20 +24246,6 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* return MA_SUCCESS; } -#if (defined(MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0) || \ - (defined(__IPHONE_15_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_0) -#define AUDIO_OBJECT_PROPERTY_ELEMENT kAudioObjectPropertyElementMain -#else -/* kAudioObjectPropertyElementMaster is deprecated. */ -#define AUDIO_OBJECT_PROPERTY_ELEMENT kAudioObjectPropertyElementMaster -#endif - -/* kAudioDevicePropertyScope* were renamed to kAudioObjectPropertyScope* in 10.8. */ -#if !defined(MAC_OS_X_VERSION_10_8) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8) -#define kAudioObjectPropertyScopeInput kAudioDevicePropertyScopeInput -#define kAudioObjectPropertyScopeOutput kAudioDevicePropertyScopeOutput -#endif - static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */ { AudioObjectPropertyAddress propAddressDevices; @@ -32433,7 +24263,7 @@ static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt3 propAddressDevices.mSelector = kAudioHardwarePropertyDevices; propAddressDevices.mScope = kAudioObjectPropertyScopeGlobal; - propAddressDevices.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddressDevices.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize); if (status != noErr) { @@ -32467,7 +24297,7 @@ static ma_result ma_get_AudioObject_uid_as_CFStringRef(ma_context* pContext, Aud propAddress.mSelector = kAudioDevicePropertyDeviceUID; propAddress.mScope = kAudioObjectPropertyScopeGlobal; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; dataSize = sizeof(*pUID); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, pUID); @@ -32509,7 +24339,7 @@ static ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID obj propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; propAddress.mScope = kAudioObjectPropertyScopeGlobal; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; dataSize = sizeof(deviceName); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName); @@ -32538,21 +24368,21 @@ static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioOb /* To know whether or not a device is an input device we need ot look at the stream configuration. If it has an output channel it's a playback device. */ propAddress.mSelector = kAudioDevicePropertyStreamConfiguration; propAddress.mScope = scope; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { return MA_FALSE; } - pBufferList = (AudioBufferList*)ma_malloc(dataSize, &pContext->allocationCallbacks); + pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(dataSize, &pContext->allocationCallbacks); if (pBufferList == NULL) { return MA_FALSE; /* Out of memory. */ } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList); if (status != noErr) { - ma_free(pBufferList, &pContext->allocationCallbacks); + ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks); return MA_FALSE; } @@ -32561,7 +24391,7 @@ static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioOb isSupported = MA_TRUE; } - ma_free(pBufferList, &pContext->allocationCallbacks); + ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks); return isSupported; } @@ -32593,7 +24423,7 @@ static ma_result ma_get_AudioObject_stream_descriptions(ma_context* pContext, Au */ propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/ propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { @@ -32631,7 +24461,7 @@ static ma_result ma_get_AudioObject_channel_layout(ma_context* pContext, AudioOb propAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { @@ -32721,7 +24551,7 @@ static ma_result ma_get_AudioObject_sample_rates(ma_context* pContext, AudioObje propAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { @@ -32843,7 +24673,7 @@ static ma_result ma_get_AudioObject_closest_buffer_size_in_frames(ma_context* pC propAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; dataSize = sizeof(bufferSizeRange); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &bufferSizeRange); @@ -32881,7 +24711,7 @@ static ma_result ma_set_AudioObject_buffer_size_in_frames(ma_context* pContext, /* Try setting the size of the buffer... If this fails we just use whatever is currently set. */ propAddress.mSelector = kAudioDevicePropertyBufferFrameSize; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(chosenBufferSizeInFrames), &chosenBufferSizeInFrames); @@ -32910,7 +24740,7 @@ static ma_result ma_find_default_AudioObjectID(ma_context* pContext, ma_device_t *pDeviceObjectID = 0; propAddressDefaultDevice.mScope = kAudioObjectPropertyScopeGlobal; - propAddressDefaultDevice.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddressDefaultDevice.mElement = kAudioObjectPropertyElementMaster; if (deviceType == ma_device_type_playback) { propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultOutputDevice; } else { @@ -33005,7 +24835,7 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec desiredSampleRate = sampleRate; if (desiredSampleRate == 0) { - desiredSampleRate = (ma_uint32)pOrigFormat->mSampleRate; + desiredSampleRate = pOrigFormat->mSampleRate; } desiredChannelCount = channels; @@ -33029,9 +24859,9 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec hasSupportedFormat = MA_FALSE; for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) { - ma_format formatFromDescription; - ma_result formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &formatFromDescription); - if (formatResult == MA_SUCCESS && formatFromDescription != ma_format_unknown) { + ma_format format; + ma_result formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &format); + if (formatResult == MA_SUCCESS && format != ma_format_unknown) { hasSupportedFormat = MA_TRUE; bestDeviceFormatSoFar = pDeviceFormatDescriptions[iFormat].mFormat; break; @@ -33190,24 +25020,24 @@ static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit au return ma_result_from_OSStatus(status); } - pChannelLayout = (AudioChannelLayout*)ma_malloc(channelLayoutSize, &pContext->allocationCallbacks); + pChannelLayout = (AudioChannelLayout*)ma__malloc_from_callbacks(channelLayoutSize, &pContext->allocationCallbacks); if (pChannelLayout == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize); if (status != noErr) { - ma_free(pChannelLayout, &pContext->allocationCallbacks); + ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); return ma_result_from_OSStatus(status); } result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap); if (result != MA_SUCCESS) { - ma_free(pChannelLayout, &pContext->allocationCallbacks); + ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); return result; } - ma_free(pChannelLayout, &pContext->allocationCallbacks); + ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); return MA_SUCCESS; } #endif /* MA_APPLE_DESKTOP */ @@ -33333,7 +25163,7 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ if (deviceObjectID == defaultDeviceObjectID) { pDeviceInfo->isDefault = MA_TRUE; } - + /* There could be a large number of permutations here. Fortunately there is only a single channel count being reported which reduces this quite a bit. For sample rates we're only reporting those that are @@ -33343,19 +25173,19 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ sample rate. */ pDeviceInfo->nativeDataFormatCount = 0; - + /* Formats. */ { ma_format uniqueFormats[ma_format_count]; ma_uint32 uniqueFormatCount = 0; ma_uint32 channels; - + /* Channels. */ result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &channels); if (result != MA_SUCCESS) { return result; } - + /* Formats. */ result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions); if (result != MA_SUCCESS) { @@ -33382,21 +25212,21 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ break; } } - + /* If we've already handled this format just skip it. */ if (hasFormatBeenHandled) { continue; } - - uniqueFormats[uniqueFormatCount] = format; + uniqueFormatCount += 1; + /* Sample Rates */ result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges); if (result != MA_SUCCESS) { return result; } - + /* Annoyingly Core Audio reports a sample rate range. We just get all the standard rates that are between this range. @@ -33412,14 +25242,14 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = standardSampleRate; pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = 0; pDeviceInfo->nativeDataFormatCount += 1; - + if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) { break; /* No more room for any more formats. */ } } } } - + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) { @@ -33443,7 +25273,7 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ UInt32 propSize; /* We want to ensure we use a consistent device name to device enumeration. */ - if (pDeviceID != NULL && pDeviceID->coreaudio[0] != '\0') { + if (pDeviceID != NULL) { ma_bool32 found = MA_FALSE; if (deviceType == ma_device_type_playback) { NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs]; @@ -33513,12 +25343,12 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ /* Only a single format is being reported for iOS. */ pDeviceInfo->nativeDataFormatCount = 1; - + result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format); if (result != MA_SUCCESS) { return result; } - + pDeviceInfo->nativeDataFormats[0].channels = bestFormat.mChannelsPerFrame; /* @@ -33559,7 +25389,7 @@ static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInF allocationSize += sizeInFrames * ma_get_bytes_per_frame(format, channels); - pBufferList = (AudioBufferList*)ma_malloc(allocationSize, pAllocationCallbacks); + pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(allocationSize, pAllocationCallbacks); if (pBufferList == NULL) { return NULL; } @@ -33595,12 +25425,12 @@ static ma_result ma_device_realloc_AudioBufferList__coreaudio(ma_device* pDevice AudioBufferList* pNewAudioBufferList; pNewAudioBufferList = ma_allocate_AudioBufferList__coreaudio(sizeInFrames, format, channels, layout, &pDevice->pContext->allocationCallbacks); - if (pNewAudioBufferList == NULL) { + if (pNewAudioBufferList != NULL) { return MA_OUT_OF_MEMORY; } /* At this point we'll have a new AudioBufferList and we can free the old one. */ - ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); pDevice->coreaudio.pAudioBufferList = pNewAudioBufferList; pDevice->coreaudio.audioBufferCapInFrames = sizeInFrames; } @@ -33617,7 +25447,9 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl MA_ASSERT(pDevice != NULL); - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pBufferList->mNumberBuffers);*/ +#if defined(MA_DEBUG_OUTPUT) + printf("INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pBufferList->mNumberBuffers); +#endif /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */ layout = ma_stream_layout_interleaved; @@ -33635,7 +25467,9 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer); } - /*a_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);*/ + #if defined(MA_DEBUG_OUTPUT) + printf(" frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize); + #endif } else { /* This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's @@ -33643,12 +25477,15 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl output silence here. */ MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize); - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);*/ + + #if defined(MA_DEBUG_OUTPUT) + printf(" WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize); + #endif } } } else { /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */ - MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS); /* This should have been validated at initialization time. */ + MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS); /* This should heve been validated at initialization time. */ /* For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something @@ -33669,7 +25506,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl if (framesToRead > framesRemaining) { framesToRead = framesRemaining; } - + ma_device_handle_backend_data_callback(pDevice, tempBuffer, NULL, framesToRead); for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { @@ -33712,7 +25549,9 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla layout = ma_stream_layout_deinterleaved; } - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pRenderedBufferList->mNumberBuffers);*/ +#if defined(MA_DEBUG_OUTPUT) + printf("INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pRenderedBufferList->mNumberBuffers); +#endif /* There has been a situation reported where frame count passed into this function is greater than the capacity of @@ -33722,13 +25561,12 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla */ result = ma_device_realloc_AudioBufferList__coreaudio(pDevice, frameCount, pDevice->capture.internalFormat, pDevice->capture.internalChannels, layout); if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("Failed to allocate AudioBufferList for capture."); + #endif return noErr; } - pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList; - MA_ASSERT(pRenderedBufferList); - /* When you call AudioUnitRender(), Core Audio tries to be helpful by setting the mDataByteSize to the number of bytes that were actually rendered. The problem with this is that the next call can fail with -50 due to the size no longer @@ -33739,12 +25577,13 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla */ for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) { pRenderedBufferList->mBuffers[iBuffer].mDataByteSize = pDevice->coreaudio.audioBufferCapInFrames * ma_get_bytes_per_sample(pDevice->capture.internalFormat) * pRenderedBufferList->mBuffers[iBuffer].mNumberChannels; - /*printf("DEBUG: nDataByteSize = %d\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/ } status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList); if (status != noErr) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "ERROR: AudioUnitRender() failed with %d.\n", (int)status); + #if defined(MA_DEBUG_OUTPUT) + printf(" ERROR: AudioUnitRender() failed with %d\n", status); + #endif return status; } @@ -33752,7 +25591,10 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) { if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) { ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount); - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " mDataByteSize=%d.\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/ + + #if defined(MA_DEBUG_OUTPUT) + printf(" mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); + #endif } else { /* This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's @@ -33769,13 +25611,15 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla if (framesToSend > framesRemaining) { framesToSend = framesRemaining; } - + ma_device_handle_backend_data_callback(pDevice, NULL, silentBuffer, framesToSend); framesRemaining -= framesToSend; } - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/ + #if defined(MA_DEBUG_OUTPUT) + printf(" WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); + #endif } } } else { @@ -33825,29 +25669,30 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); - /* Don't do anything if it looks like we're just reinitializing due to a device switch. */ - if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) || - ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isSwitchingCaptureDevice)) { - return; - } - /* There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit) can try waiting on the same lock. I'm going to try working around this by not calling any Core Audio APIs in the callback when the device has been stopped or uninitialized. */ - if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) { - ma_device__on_notification_stopped(pDevice); + if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED || ma_device_get_state(pDevice) == MA_STATE_STOPPING || ma_device_get_state(pDevice) == MA_STATE_STOPPED) { + ma_stop_proc onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); + } + + ma_event_signal(&pDevice->coreaudio.stopEvent); } else { UInt32 isRunning; UInt32 isRunningSize = sizeof(isRunning); OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize); if (status != noErr) { - goto done; /* Don't really know what to do in this case... just ignore it, I suppose... */ + return; /* Don't really know what to do in this case... just ignore it, I suppose... */ } if (!isRunning) { + ma_stop_proc onStop; + /* The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider: @@ -33861,12 +25706,12 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio /* It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the - device to be seamless to the client (we don't want them receiving the stopped event and thinking that the device has stopped when it + device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it hasn't!). */ if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) || ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isSwitchingCaptureDevice)) { - goto done; + return; } /* @@ -33874,21 +25719,20 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most likely be successful in switching to the new device. - TODO: Try to predict if Core Audio will switch devices. If not, the stopped callback needs to be posted. + TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted. */ - goto done; + return; } /* Getting here means we need to stop the device. */ - ma_device__on_notification_stopped(pDevice); + onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); + } } } (void)propertyID; /* Unused. */ - -done: - /* Always signal the stop event. It's possible for the "else" case to get hit which can happen during an interruption. */ - ma_event_signal(&pDevice->coreaudio.stopEvent); } #if defined(MA_APPLE_DESKTOP) @@ -33939,7 +25783,7 @@ static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UIn ma_device__post_init_setup(pDevice, deviceType); /* Restart the device if required. If this fails we need to stop the device entirely. */ - if (ma_device_get_state(pDevice) == ma_device_state_started) { + if (ma_device_get_state(pDevice) == MA_STATE_STARTED) { OSStatus status; if (deviceType == ma_device_type_playback) { status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); @@ -33947,7 +25791,7 @@ static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UIn if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } - ma_device__set_state(pDevice, ma_device_state_stopped); + ma_device__set_state(pDevice, MA_STATE_STOPPED); } } else if (deviceType == ma_device_type_capture) { status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture); @@ -33955,12 +25799,10 @@ static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UIn if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); } - ma_device__set_state(pDevice, ma_device_state_stopped); + ma_device__set_state(pDevice, MA_STATE_STOPPED); } } } - - ma_device__on_notification_rerouted(pDevice); } } } @@ -33980,11 +25822,11 @@ static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContex ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio); { - /* Don't do anything if we've already initialized device tracking. */ + /* Don't do anything if we've already initializd device tracking. */ if (g_DeviceTrackingInitCounter_CoreAudio == 0) { AudioObjectPropertyAddress propAddress; propAddress.mScope = kAudioObjectPropertyScopeGlobal; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; ma_mutex_init(&g_DeviceTrackingMutex_CoreAudio); @@ -33994,8 +25836,8 @@ static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContex propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL); + g_DeviceTrackingInitCounter_CoreAudio += 1; } - g_DeviceTrackingInitCounter_CoreAudio += 1; } ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio); @@ -34008,13 +25850,12 @@ static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pCont ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio); { - if (g_DeviceTrackingInitCounter_CoreAudio > 0) - g_DeviceTrackingInitCounter_CoreAudio -= 1; + g_DeviceTrackingInitCounter_CoreAudio -= 1; if (g_DeviceTrackingInitCounter_CoreAudio == 0) { AudioObjectPropertyAddress propAddress; propAddress.mScope = kAudioObjectPropertyScopeGlobal; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL); @@ -34024,9 +25865,7 @@ static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pCont /* At this point there should be no tracked devices. If not there's an error somewhere. */ if (g_ppTrackedDevices_CoreAudio != NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active."); - ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio); - return MA_INVALID_OPERATION; + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.", MA_INVALID_OPERATION); } ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio); @@ -34045,15 +25884,17 @@ static ma_result ma_device__track__coreaudio(ma_device* pDevice) { /* Allocate memory if required. */ if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) { + ma_uint32 oldCap; ma_uint32 newCap; ma_device** ppNewDevices; + oldCap = g_TrackedDeviceCap_CoreAudio; newCap = g_TrackedDeviceCap_CoreAudio * 2; if (newCap == 0) { newCap = 1; } - ppNewDevices = (ma_device**)ma_realloc(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, &pDevice->pContext->allocationCallbacks); + ppNewDevices = (ma_device**)ma__realloc_from_callbacks(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, sizeof(*g_ppTrackedDevices_CoreAudio)*oldCap, &pDevice->pContext->allocationCallbacks); if (ppNewDevices == NULL) { ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio); return MA_OUT_OF_MEMORY; @@ -34090,7 +25931,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) /* If there's nothing else in the list we need to free memory. */ if (g_TrackedDeviceCount_CoreAudio == 0) { - ma_free(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks); g_ppTrackedDevices_CoreAudio = NULL; g_TrackedDeviceCap_CoreAudio = 0; } @@ -34106,71 +25947,30 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) #endif #if defined(MA_APPLE_MOBILE) -@interface ma_ios_notification_handler:NSObject { +@interface ma_router_change_handler:NSObject { ma_device* m_pDevice; } @end -@implementation ma_ios_notification_handler +@implementation ma_router_change_handler -(id)init:(ma_device*)pDevice { self = [super init]; m_pDevice = pDevice; - /* For route changes. */ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]]; - /* For interruptions. */ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; - return self; } -(void)dealloc { [self remove_handler]; - - #if defined(__has_feature) - #if !__has_feature(objc_arc) - [super dealloc]; - #endif - #endif } -(void)remove_handler { [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil]; -} - --(void)handle_interruption:(NSNotification*)pNotification -{ - NSInteger type = [[[pNotification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue]; - switch (type) - { - case AVAudioSessionInterruptionTypeBegan: - { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeBegan\n"); - - /* - Core Audio will have stopped the internal device automatically, but we need explicitly - stop it at a higher level to ensure miniaudio-specific state is updated for consistency. - */ - ma_device_stop(m_pDevice); - - /* - Fire the notification after the device has been stopped to ensure it's in the correct - state when the notification handler is invoked. - */ - ma_device__on_notification_interruption_began(m_pDevice); - } break; - - case AVAudioSessionInterruptionTypeEnded: - { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n"); - ma_device__on_notification_interruption_ended(m_pDevice); - } break; - } } -(void)handle_route_change:(NSNotification*)pNotification @@ -34182,45 +25982,79 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) { case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n"); + #endif } break; case AVAudioSessionRouteChangeReasonNewDeviceAvailable: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n"); + #endif } break; case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n"); + #endif } break; case AVAudioSessionRouteChangeReasonWakeFromSleep: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n"); + #endif } break; case AVAudioSessionRouteChangeReasonOverride: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n"); + #endif } break; case AVAudioSessionRouteChangeReasonCategoryChange: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n"); + #endif } break; case AVAudioSessionRouteChangeReasonUnknown: default: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n"); + #if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n"); + #endif } break; } - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels); +#if defined(MA_DEBUG_OUTPUT) + printf("[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels); +#endif - /* Let the application know about the route change. */ - ma_device__on_notification_rerouted(m_pDevice); + ma_uint32 previousState = ma_device_get_state(m_pDevice); + + if (previousState == MA_STATE_STARTED) { + ma_device_stop(m_pDevice); + } + + if (m_pDevice->type == ma_device_type_capture || m_pDevice->type == ma_device_type_duplex) { + m_pDevice->capture.internalChannels = (ma_uint32)pSession.inputNumberOfChannels; + m_pDevice->capture.internalSampleRate = (ma_uint32)pSession.sampleRate; + ma_device__post_init_setup(m_pDevice, ma_device_type_capture); + } + if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) { + m_pDevice->playback.internalChannels = (ma_uint32)pSession.outputNumberOfChannels; + m_pDevice->playback.internalSampleRate = (ma_uint32)pSession.sampleRate; + ma_device__post_init_setup(m_pDevice, ma_device_type_playback); + } + + if (previousState == MA_STATE_STARTED) { + ma_device_start(m_pDevice); + } } @end #endif @@ -34228,7 +26062,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) static ma_result ma_device_uninit__coreaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_uninitialized); + MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED); #if defined(MA_APPLE_DESKTOP) /* @@ -34238,9 +26072,9 @@ static ma_result ma_device_uninit__coreaudio(ma_device* pDevice) ma_device__untrack__coreaudio(pDevice); #endif #if defined(MA_APPLE_MOBILE) - if (pDevice->coreaudio.pNotificationHandler != NULL) { - ma_ios_notification_handler* pNotificationHandler = (MA_BRIDGE_TRANSFER ma_ios_notification_handler*)pDevice->coreaudio.pNotificationHandler; - [pNotificationHandler remove_handler]; + if (pDevice->coreaudio.pRouteChangeHandler != NULL) { + ma_router_change_handler* pRouteChangeHandler = (__bridge_transfer ma_router_change_handler*)pDevice->coreaudio.pRouteChangeHandler; + [pRouteChangeHandler remove_handler]; } #endif @@ -34252,7 +26086,7 @@ static ma_result ma_device_uninit__coreaudio(ma_device* pDevice) } if (pDevice->coreaudio.pAudioBufferList) { - ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -34292,14 +26126,16 @@ typedef struct static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */ { - ma_result result = MA_SUCCESS; + ma_result result; OSStatus status; UInt32 enableIOFlag; AudioStreamBasicDescription bestFormat; - ma_uint32 actualPeriodSizeInFrames; + UInt32 actualPeriodSizeInFrames; AURenderCallbackStruct callbackInfo; #if defined(MA_APPLE_DESKTOP) AudioObjectID deviceObjectID; +#else + UInt32 actualPeriodSizeInFramesSize = sizeof(actualPeriodSizeInFrames); #endif /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */ @@ -34448,7 +26284,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format. - Something that does seem to work, however, has been setting the nominal sample rate on the device object. The problem with + Something that does seem to work, however, has been setting the nominal sample rate on the deivce object. The problem with this, however, is that it actually changes the sample rate at the operating system level and not just the application. This could be intrusive to the user, however, so I don't think it's wise to make this the default. Instead I'm making this a configuration option. When the `coreaudio.allowNominalSampleRateChange` config option is set to true, changing the sample @@ -34465,7 +26301,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev propAddress.mSelector = kAudioDevicePropertyNominalSampleRate; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; - propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(sampleRateRange), &sampleRateRange); if (status != noErr) { @@ -34499,28 +26335,15 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev /* I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with AVAudioSession outputNumberOfChannels. I'm going to try using the AVAudioSession values instead. - - UPDATE 20/02/2025: - When testing on the simulator with an iPhone 15 and iOS 17 I get an error when initializing the audio - unit if set the input channels to pAudioSession.inputNumberOfChannels. What is happening is the channel - count returned from AudioUnitGetProperty() above is set to 2, but pAudioSession is reporting a channel - count of 1. When this happens, the call to AudioUnitSetProprty() below just down below will succeed, but - AudioUnitInitialize() further down will fail. The only solution I have come up with is to not set the - channel count to pAudioSession.inputNumberOfChannels. */ if (deviceType == ma_device_type_playback) { bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.outputNumberOfChannels; } - - #if 0 if (deviceType == ma_device_type_capture) { - /*printf("DEBUG: bestFormat.mChannelsPerFrame = %d; pAudioSession.inputNumberOfChannels = %d\n", (int)bestFormat.mChannelsPerFrame, (int)pAudioSession.inputNumberOfChannels);*/ bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.inputNumberOfChannels; } - #endif } - status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); @@ -34540,7 +26363,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev } pData->channelsOut = bestFormat.mChannelsPerFrame; - pData->sampleRateOut = (ma_uint32)bestFormat.mSampleRate; + pData->sampleRateOut = bestFormat.mSampleRate; } /* Clamp the channel count for safety. */ @@ -34566,12 +26389,12 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev } #else /* Fall back to default assumptions. */ - ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut); + ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut); #endif } #else /* TODO: Figure out how to get the channel map using AVAudioSession. */ - ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut); + ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut); #endif @@ -34597,16 +26420,13 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev } #else /* - On iOS, the size of the IO buffer needs to be specified in seconds and is a floating point - number. I don't trust any potential truncation errors due to converting from float to integer - so I'm going to explicitly set the actual period size to the next power of 2. + I don't know how to configure buffer sizes on iOS so for now we're not allowing it to be configured. Instead we're + just going to set it to the value of kAudioUnitProperty_MaximumFramesPerSlice. */ - @autoreleasepool { - AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; - MA_ASSERT(pAudioSession != NULL); - - [pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil]; - actualPeriodSizeInFrames = ma_next_power_of_2((ma_uint32)(pAudioSession.IOBufferDuration * pAudioSession.sampleRate)); + status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, &actualPeriodSizeInFramesSize); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); } #endif @@ -34671,7 +26491,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev /* Initialize the audio unit. */ status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit); if (status != noErr) { - ma_free(pData->pAudioBufferList, &pContext->allocationCallbacks); + ma__free_from_callbacks(pData->pAudioBufferList, &pContext->allocationCallbacks); pData->pAudioBufferList = NULL; ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); @@ -34718,7 +26538,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } if (pDevice->coreaudio.pAudioBufferList) { - ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); } } else if (deviceType == ma_device_type_playback) { data.formatIn = pDevice->playback.format; @@ -34751,7 +26571,6 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev if (deviceType == ma_device_type_capture) { #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID; - ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio); #endif pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit; pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList; @@ -34766,7 +26585,6 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev } else if (deviceType == ma_device_type_playback) { #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; - ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); #endif pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit; @@ -34844,10 +26662,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c pDescriptorCapture->periodCount = data.periodsOut; #if defined(MA_APPLE_DESKTOP) - ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio); - /* - If we are using the default device we'll need to listen for changes to the system's default device so we can seamlessly + If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. */ if (pConfig->capture.pDeviceID == NULL) { @@ -34884,7 +26700,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c if (pConfig->deviceType == ma_device_type_duplex) { ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); if (pDevice->coreaudio.pAudioBufferList) { - ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); } } return result; @@ -34908,10 +26724,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c pDescriptorPlayback->periodCount = data.periodsOut; #if defined(MA_APPLE_DESKTOP) - ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); - /* - If we are using the default device we'll need to listen for changes to the system's default device so we can seamlessly + If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. */ if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) { @@ -34920,7 +26734,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c #endif } - + /* When stopping the device, a callback is called on another thread. We need to wait for this callback @@ -34933,7 +26747,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c differently on non-Desktop Apple platforms. */ #if defined(MA_APPLE_MOBILE) - pDevice->coreaudio.pNotificationHandler = (MA_BRIDGE_RETAINED void*)[[ma_ios_notification_handler alloc] init:pDevice]; + pDevice->coreaudio.pRouteChangeHandler = (__bridge_retained void*)[[ma_router_change_handler alloc] init:pDevice]; #endif return MA_SUCCESS; @@ -34998,16 +26812,15 @@ static ma_result ma_context_uninit__coreaudio(ma_context* pContext) #if defined(MA_APPLE_MOBILE) if (!pContext->coreaudio.noAudioSessionDeactivate) { if (![[AVAudioSession sharedInstance] setActive:false error:nil]) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session."); - return MA_FAILED_TO_INIT_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session.", MA_FAILED_TO_INIT_BACKEND); } } #endif #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif #if !defined(MA_APPLE_MOBILE) @@ -35018,7 +26831,7 @@ static ma_result ma_context_uninit__coreaudio(ma_context* pContext) return MA_SUCCESS; } -#if defined(MA_APPLE_MOBILE) && defined(__IPHONE_12_0) +#if defined(MA_APPLE_MOBILE) static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_category category) { /* The "default" and "none" categories are treated different and should not be used as an input into this function. */ @@ -35075,47 +26888,41 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte } } else { if (pConfig->coreaudio.sessionCategory != ma_ios_session_category_none) { - #if defined(__IPHONE_12_0) if (![pAudioSession setCategory: ma_to_AVAudioSessionCategory(pConfig->coreaudio.sessionCategory) withOptions:options error:nil]) { return MA_INVALID_OPERATION; /* Failed to set session category. */ } - #else - /* Ignore the session category on version 11 and older, but post a warning. */ - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Session category only supported in iOS 12 and newer."); - #endif } } if (!pConfig->coreaudio.noAudioSessionActivate) { if (![pAudioSession setActive:true error:nil]) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to activate audio session."); - return MA_FAILED_TO_INIT_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to activate audio session.", MA_FAILED_TO_INIT_BACKEND); } } } #endif #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - pContext->coreaudio.hCoreFoundation = ma_dlopen(ma_context_get_log(pContext), "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"); + pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation"); if (pContext->coreaudio.hCoreFoundation == NULL) { return MA_API_NOT_FOUND; } - pContext->coreaudio.CFStringGetCString = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation, "CFStringGetCString"); - pContext->coreaudio.CFRelease = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation, "CFRelease"); + pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString"); + pContext->coreaudio.CFRelease = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFRelease"); - pContext->coreaudio.hCoreAudio = ma_dlopen(ma_context_get_log(pContext), "/System/Library/Frameworks/CoreAudio.framework/CoreAudio"); + pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio"); if (pContext->coreaudio.hCoreAudio == NULL) { - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } - pContext->coreaudio.AudioObjectGetPropertyData = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData"); - pContext->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize"); - pContext->coreaudio.AudioObjectSetPropertyData = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData"); - pContext->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener"); - pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener"); + pContext->coreaudio.AudioObjectGetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData"); + pContext->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize"); + pContext->coreaudio.AudioObjectSetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData"); + pContext->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener"); + pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener"); /* It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still @@ -35123,35 +26930,35 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to AudioToolbox. */ - pContext->coreaudio.hAudioUnit = ma_dlopen(ma_context_get_log(pContext), "/System/Library/Frameworks/AudioUnit.framework/AudioUnit"); + pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit"); if (pContext->coreaudio.hAudioUnit == NULL) { - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } - if (ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) { + if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) { /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */ - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit); - pContext->coreaudio.hAudioUnit = ma_dlopen(ma_context_get_log(pContext), "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox"); if (pContext->coreaudio.hAudioUnit == NULL) { - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } } - pContext->coreaudio.AudioComponentFindNext = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioComponentFindNext"); - pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose"); - pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew"); - pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart"); - pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop"); - pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener"); - pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo"); - pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty"); - pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty"); - pContext->coreaudio.AudioUnitInitialize = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioUnitInitialize"); - pContext->coreaudio.AudioUnitRender = ma_dlsym(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit, "AudioUnitRender"); + pContext->coreaudio.AudioComponentFindNext = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext"); + pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose"); + pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew"); + pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart"); + pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop"); + pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener"); + pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo"); + pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty"); + pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty"); + pContext->coreaudio.AudioUnitInitialize = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize"); + pContext->coreaudio.AudioUnitRender = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender"); #else pContext->coreaudio.CFStringGetCString = (ma_proc)CFStringGetCString; pContext->coreaudio.CFRelease = (ma_proc)CFRelease; @@ -35193,9 +27000,9 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc); if (pContext->coreaudio.component == NULL) { #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif return MA_FAILED_TO_INIT_BACKEND; } @@ -35205,16 +27012,16 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte result = ma_context__init_device_tracking__coreaudio(pContext); if (result != MA_SUCCESS) { #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hAudioUnit); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreAudio); - ma_dlclose(ma_context_get_log(pContext), pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif return result; } #endif pContext->coreaudio.noAudioSessionDeactivate = pConfig->coreaudio.noAudioSessionDeactivate; - + pCallbacks->onContextInit = ma_context_init__coreaudio; pCallbacks->onContextUninit = ma_context_uninit__coreaudio; pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__coreaudio; @@ -35229,7 +27036,7 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte return MA_SUCCESS; } -#endif /* MA_HAS_COREAUDIO */ +#endif /* Core Audio */ @@ -35721,7 +27528,7 @@ static ma_result ma_device_uninit__sndio(ma_device* pDevice) ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); } @@ -35750,7 +27557,7 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic MA_ASSERT(pDevice != NULL); if (deviceType == ma_device_type_capture) { - openFlags = MA_SIO_REC; + openFlags = MA_SIO_REC; } else { openFlags = MA_SIO_PLAY; } @@ -35767,15 +27574,13 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic handle = (ma_ptr)((ma_sio_open_proc)pDevice->pContext->sndio.sio_open)(pDeviceName, openFlags, 0); if (handle == NULL) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device."); - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* We need to retrieve the device caps to determine the most appropriate format to use. */ if (((ma_sio_getcap_proc)pDevice->pContext->sndio.sio_getcap)((struct ma_sio_hdl*)handle, &caps) == 0) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.", MA_ERROR); } /* @@ -35853,7 +27658,7 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic par.sig = 1; } break; } - + if (deviceType == ma_device_type_capture) { par.rchan = channels; } else { @@ -35869,14 +27674,12 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic if (((ma_sio_setpar_proc)pDevice->pContext->sndio.sio_setpar)((struct ma_sio_hdl*)handle, &par) == 0) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.", MA_FORMAT_NOT_SUPPORTED); } if (((ma_sio_getpar_proc)pDevice->pContext->sndio.sio_getpar)((struct ma_sio_hdl*)handle, &par) == 0) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size."); - return MA_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.", MA_FORMAT_NOT_SUPPORTED); } internalFormat = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb); @@ -35894,10 +27697,21 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic pDescriptor->format = internalFormat; pDescriptor->channels = internalChannels; pDescriptor->sampleRate = internalSampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_sndio, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), internalChannels); + ma_get_standard_channel_map(ma_standard_channel_map_sndio, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; pDescriptor->periodCount = internalPeriods; +#ifdef MA_DEBUG_OUTPUT + printf("DEVICE INFO\n"); + printf(" Format: %s\n", ma_get_format_name(internalFormat)); + printf(" Channels: %d\n", internalChannels); + printf(" Sample Rate: %d\n", internalSampleRate); + printf(" Period Size: %d\n", internalPeriodSizeInFrames); + printf(" Periods: %d\n", internalPeriods); + printf(" appbufsz: %d\n", par.appbufsz); + printf(" round: %d\n", par.round); +#endif + return MA_SUCCESS; } @@ -35978,8 +27792,7 @@ static ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFram result = ((ma_sio_write_proc)pDevice->pContext->sndio.sio_write)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (result == 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device."); - return MA_IO_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.", MA_IO_ERROR); } if (pFramesWritten != NULL) { @@ -35999,8 +27812,7 @@ static ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_ result = ((ma_sio_read_proc)pDevice->pContext->sndio.sio_read)((struct ma_sio_hdl*)pDevice->sndio.handleCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (result == 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device."); - return MA_IO_ERROR; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.", MA_IO_ERROR); } if (pFramesRead != NULL) { @@ -36028,7 +27840,7 @@ static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_c size_t i; for (i = 0; i < ma_countof(libsndioNames); ++i) { - pContext->sndio.sndioSO = ma_dlopen(ma_context_get_log(pContext), libsndioNames[i]); + pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]); if (pContext->sndio.sndioSO != NULL) { break; } @@ -36038,16 +27850,16 @@ static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_c return MA_NO_BACKEND; } - pContext->sndio.sio_open = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_open"); - pContext->sndio.sio_close = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_close"); - pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_setpar"); - pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_getpar"); - pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_getcap"); - pContext->sndio.sio_write = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_write"); - pContext->sndio.sio_read = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_read"); - pContext->sndio.sio_start = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_start"); - pContext->sndio.sio_stop = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_stop"); - pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->sndio.sndioSO, "sio_initpar"); + pContext->sndio.sio_open = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open"); + pContext->sndio.sio_close = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close"); + pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar"); + pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar"); + pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap"); + pContext->sndio.sio_write = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write"); + pContext->sndio.sio_read = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read"); + pContext->sndio.sio_start = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start"); + pContext->sndio.sio_stop = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop"); + pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar"); #else pContext->sndio.sio_open = sio_open; pContext->sndio.sio_close = sio_close; @@ -36076,7 +27888,7 @@ static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_c (void)pConfig; return MA_SUCCESS; } -#endif /* MA_HAS_SNDIO */ +#endif /* sndio */ @@ -36094,10 +27906,6 @@ audio(4) Backend #include #include -#ifdef __NetBSD__ -#include -#endif - #if defined(__OpenBSD__) #include #if defined(OpenBSD) && OpenBSD >= 201709 @@ -36317,15 +28125,9 @@ static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext ma_uint32 channels; ma_uint32 sampleRate; -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) - if (ioctl(fd, AUDIO_GETFORMAT, &fdInfo) < 0) { - return MA_ERROR; - } -#else if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { return MA_ERROR; } -#endif if (deviceType == ma_device_type_playback) { channels = fdInfo.play.channels; @@ -36518,13 +28320,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c "/dev/audio", "/dev/audio0" }; - const char* pDefaultDeviceCtlNames[] = { - "/dev/audioctl", - "/dev/audioctl0" - }; int fd; int fdFlags = 0; - size_t iDefaultDevice = (size_t)-1; ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; @@ -36543,11 +28340,11 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c } /*fdFlags |= O_NONBLOCK;*/ - /* Find the index of the default device as a start. We'll use this index later. Set it to (size_t)-1 otherwise. */ if (pDescriptor->pDeviceID == NULL) { /* Default device. */ - for (iDefaultDevice = 0; iDefaultDevice < ma_countof(pDefaultDeviceNames); ++iDefaultDevice) { - fd = open(pDefaultDeviceNames[iDefaultDevice], fdFlags, 0); + size_t iDevice; + for (iDevice = 0; iDevice < ma_countof(pDefaultDeviceNames); ++iDevice) { + fd = open(pDefaultDeviceNames[iDevice], fdFlags, 0); if (fd != -1) { break; } @@ -36555,27 +28352,15 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c } else { /* Specific device. */ fd = open(pDescriptor->pDeviceID->audio4, fdFlags, 0); - - for (iDefaultDevice = 0; iDefaultDevice < ma_countof(pDefaultDeviceNames); iDefaultDevice += 1) { - if (ma_strcmp(pDefaultDeviceNames[iDefaultDevice], pDescriptor->pDeviceID->audio4) == 0) { - break; - } - } - - if (iDefaultDevice == ma_countof(pDefaultDeviceNames)) { - iDefaultDevice = (size_t)-1; - } } if (fd == -1) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", ma_result_from_errno(errno)); } #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */ { audio_info_t fdInfo; - int fdInfoResult = -1; /* The documentation is a little bit unclear to me as to how it handles formats. It says the @@ -36595,32 +28380,6 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c */ AUDIO_INITINFO(&fdInfo); - /* - Get the default format from the audioctl file if we're asking for a default device. If we - retrieve it from /dev/audio it'll default to mono 8000Hz. - */ - if (iDefaultDevice != (size_t)-1) { - /* We're using a default device. Get the info from the /dev/audioctl file instead of /dev/audio. */ - int fdctl = open(pDefaultDeviceCtlNames[iDefaultDevice], fdFlags, 0); - if (fdctl != -1) { -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) - fdInfoResult = ioctl(fdctl, AUDIO_GETFORMAT, &fdInfo); -#else - fdInfoResult = ioctl(fdctl, AUDIO_GETINFO, &fdInfo); -#endif - close(fdctl); - } - } - - if (fdInfoResult == -1) { - /* We still don't have the default device info so just retrieve it from the main audio device. */ - if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { - close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed."); - return ma_result_from_errno(errno); - } - } - /* We get the driver to do as much of the data conversion as possible. */ if (deviceType == ma_device_type_capture) { fdInfo.mode = AUMODE_RECORD; @@ -36648,14 +28407,12 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED); } if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MA_FORMAT_NOT_SUPPORTED); } if (deviceType == ma_device_type_capture) { @@ -36670,8 +28427,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (internalFormat == ma_format_unknown) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable."); - return MA_FORMAT_NOT_SUPPORTED; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); } /* Buffer. */ @@ -36697,8 +28453,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c fdInfo.blocksize = internalPeriodSizeInBytes; if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED); } internalPeriods = fdInfo.hiwat; @@ -36712,8 +28467,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c /* We need to retrieve the format of the device so we can know the channel count and sample rate. Then we can calculate the buffer size. */ if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MA_FORMAT_NOT_SUPPORTED); } internalFormat = ma_format_from_swpar__audio4(&fdPar); @@ -36722,8 +28476,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (internalFormat == ma_format_unknown) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable."); - return MA_FORMAT_NOT_SUPPORTED; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); } /* Buffer. */ @@ -36743,14 +28496,12 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MA_FORMAT_NOT_SUPPORTED); } if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MA_FORMAT_NOT_SUPPORTED); } } @@ -36764,8 +28515,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (internalFormat == ma_format_unknown) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable."); - return MA_FORMAT_NOT_SUPPORTED; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); } if (deviceType == ma_device_type_capture) { @@ -36777,7 +28527,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c pDescriptor->format = internalFormat; pDescriptor->channels = internalChannels; pDescriptor->sampleRate = internalSampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), internalChannels); + ma_get_standard_channel_map(ma_standard_channel_map_sound4, internalChannels, pDescriptor->channelMap); pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; pDescriptor->periodCount = internalPeriods; @@ -36859,13 +28609,11 @@ static ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd) #if !defined(MA_AUDIO4_USE_NEW_API) if (ioctl(fd, AUDIO_FLUSH, 0) < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", ma_result_from_errno(errno)); } #else if (ioctl(fd, AUDIO_STOP, 0) < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", ma_result_from_errno(errno)); } #endif @@ -36913,8 +28661,7 @@ static ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFra result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (result < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", ma_result_from_errno(errno)); } if (pFramesWritten != NULL) { @@ -36934,8 +28681,7 @@ static ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (result < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", ma_result_from_errno(errno)); } if (pFramesRead != NULL) { @@ -36974,7 +28720,7 @@ static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_ return MA_SUCCESS; } -#endif /* MA_HAS_AUDIO4 */ +#endif /* audio4 */ /****************************************************************************** @@ -37050,8 +28796,7 @@ static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum fd = ma_open_temp_device__oss(); if (fd == -1) { - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration."); - return MA_NO_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND); } result = ioctl(fd, SNDCTL_SYSINFO, &si); @@ -37098,8 +28843,7 @@ static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum } } else { close(fd); - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration."); - return MA_NO_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND); } close(fd); @@ -37182,8 +28926,7 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device fdTemp = ma_open_temp_device__oss(); if (fdTemp == -1) { - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration."); - return MA_NO_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND); } result = ioctl(fdTemp, SNDCTL_SYSINFO, &si); @@ -37241,8 +28984,7 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device } } else { close(fdTemp); - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration."); - return MA_NO_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND); } @@ -37323,7 +29065,7 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf MA_ASSERT(pDevice != NULL); MA_ASSERT(pConfig != NULL); MA_ASSERT(deviceType != ma_device_type_duplex); - + pDeviceID = pDescriptor->pDeviceID; shareMode = pDescriptor->shareMode; ossFormat = ma_format_to_oss((pDescriptor->format != ma_format_unknown) ? pDescriptor->format : ma_format_s16); /* Use s16 by default because OSS doesn't like floating point. */ @@ -37332,12 +29074,11 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf result = ma_context_open_device__oss(pDevice->pContext, deviceType, pDeviceID, shareMode, &fd); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); } /* - The OSS documentation is very clear about the order we should be initializing the device's properties: + The OSS documantation is very clear about the order we should be initializing the device's properties: 1) Format 2) Channels 3) Sample rate. @@ -37347,24 +29088,21 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat); if (ossResult == -1) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.", MA_FORMAT_NOT_SUPPORTED); } /* Channels. */ ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels); if (ossResult == -1) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.", MA_FORMAT_NOT_SUPPORTED); } /* Sample Rate. */ ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate); if (ossResult == -1) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.", MA_FORMAT_NOT_SUPPORTED); } /* @@ -37398,8 +29136,7 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); if (ossResult == -1) { close(fd); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.", MA_FORMAT_NOT_SUPPORTED); } } @@ -37413,13 +29150,12 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf pDescriptor->format = ma_format_from_oss(ossFormat); pDescriptor->channels = ossChannels; pDescriptor->sampleRate = ossSampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); + ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDescriptor->channels, pDescriptor->channelMap); pDescriptor->periodCount = (ma_uint32)(ossFragment >> 16); pDescriptor->periodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format, pDescriptor->channels); if (pDescriptor->format == ma_format_unknown) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio."); - return MA_FORMAT_NOT_SUPPORTED; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); } return MA_SUCCESS; @@ -37439,16 +29175,14 @@ static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device."); - return result; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); } } @@ -37505,14 +29239,13 @@ static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames /* Don't do any processing if the device is stopped. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != ma_device_state_started && deviceState != ma_device_state_starting) { + if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) { return MA_SUCCESS; } resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (resultOSS < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno)); } if (pFramesWritten != NULL) { @@ -37533,14 +29266,13 @@ static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_ui /* Don't do any processing if the device is stopped. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != ma_device_state_started && deviceState != ma_device_state_starting) { + if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) { return MA_SUCCESS; } resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (resultOSS < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client."); - return ma_result_from_errno(errno); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno)); } if (pFramesRead != NULL) { @@ -37572,8 +29304,7 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con /* Try opening a temporary device first so we can get version information. This is closed at the end. */ fd = ma_open_temp_device__oss(); if (fd == -1) { - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties."); /* Looks liks OSS isn't installed, or there are no available devices. */ - return MA_NO_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.", MA_NO_BACKEND); /* Looks liks OSS isn't installed, or there are no available devices. */ } /* Grab the OSS version. */ @@ -37581,8 +29312,7 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con result = ioctl(fd, OSS_GETVERSION, &ossVersion); if (result == -1) { close(fd); - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version."); - return MA_NO_BACKEND; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.", MA_NO_BACKEND); } /* The file handle to temp device is no longer needed. Close ASAP. */ @@ -37605,10 +29335,7 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con return MA_SUCCESS; } -#endif /* MA_HAS_OSS */ - - - +#endif /* OSS */ /****************************************************************************** @@ -37618,9 +29345,7 @@ AAudio Backend ******************************************************************************/ #ifdef MA_HAS_AAUDIO -#ifdef MA_NO_RUNTIME_LINKING - #include -#endif +/*#include */ typedef int32_t ma_aaudio_result_t; typedef int32_t ma_aaudio_direction_t; @@ -37631,7 +29356,6 @@ typedef int32_t ma_aaudio_performance_mo typedef int32_t ma_aaudio_usage_t; typedef int32_t ma_aaudio_content_type_t; typedef int32_t ma_aaudio_input_preset_t; -typedef int32_t ma_aaudio_allowed_capture_policy_t; typedef int32_t ma_aaudio_data_callback_result_t; typedef struct ma_AAudioStreamBuilder_t* ma_AAudioStreamBuilder; typedef struct ma_AAudioStream_t* ma_AAudioStream; @@ -37706,11 +29430,6 @@ typedef struct ma_AAudioStream_t* ma_AAudioStream; #define MA_AAUDIO_INPUT_PRESET_UNPROCESSED 9 #define MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE 10 -/* Allowed Capture Policies */ -#define MA_AAUDIO_ALLOW_CAPTURE_BY_ALL 1 -#define MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM 2 -#define MA_AAUDIO_ALLOW_CAPTURE_BY_NONE 3 - /* Callback results. */ #define MA_AAUDIO_CALLBACK_RESULT_CONTINUE 0 #define MA_AAUDIO_CALLBACK_RESULT_STOP 1 @@ -37735,7 +29454,6 @@ typedef void (* MA_PFN_AAudioStreamBuilder_setPerformanceMod typedef void (* MA_PFN_AAudioStreamBuilder_setUsage) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_usage_t contentType); typedef void (* MA_PFN_AAudioStreamBuilder_setContentType) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_content_type_t contentType); typedef void (* MA_PFN_AAudioStreamBuilder_setInputPreset) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_input_preset_t inputPreset); -typedef void (* MA_PFN_AAudioStreamBuilder_setAllowedCapturePolicy) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_allowed_capture_policy_t policy); typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_openStream) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream); typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_close) (ma_AAudioStream* pStream); typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState) (ma_AAudioStream* pStream); @@ -37763,22 +29481,22 @@ static ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA) static ma_aaudio_usage_t ma_to_usage__aaudio(ma_aaudio_usage usage) { switch (usage) { - case ma_aaudio_usage_media: return MA_AAUDIO_USAGE_MEDIA; - case ma_aaudio_usage_voice_communication: return MA_AAUDIO_USAGE_VOICE_COMMUNICATION; - case ma_aaudio_usage_voice_communication_signalling: return MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; - case ma_aaudio_usage_alarm: return MA_AAUDIO_USAGE_ALARM; - case ma_aaudio_usage_notification: return MA_AAUDIO_USAGE_NOTIFICATION; - case ma_aaudio_usage_notification_ringtone: return MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE; - case ma_aaudio_usage_notification_event: return MA_AAUDIO_USAGE_NOTIFICATION_EVENT; - case ma_aaudio_usage_assistance_accessibility: return MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; - case ma_aaudio_usage_assistance_navigation_guidance: return MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; - case ma_aaudio_usage_assistance_sonification: return MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION; - case ma_aaudio_usage_game: return MA_AAUDIO_USAGE_GAME; - case ma_aaudio_usage_assitant: return MA_AAUDIO_USAGE_ASSISTANT; - case ma_aaudio_usage_emergency: return MA_AAUDIO_SYSTEM_USAGE_EMERGENCY; - case ma_aaudio_usage_safety: return MA_AAUDIO_SYSTEM_USAGE_SAFETY; - case ma_aaudio_usage_vehicle_status: return MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS; - case ma_aaudio_usage_announcement: return MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT; + case ma_aaudio_usage_announcement: return MA_AAUDIO_USAGE_MEDIA; + case ma_aaudio_usage_emergency: return MA_AAUDIO_USAGE_VOICE_COMMUNICATION; + case ma_aaudio_usage_safety: return MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + case ma_aaudio_usage_vehicle_status: return MA_AAUDIO_USAGE_ALARM; + case ma_aaudio_usage_alarm: return MA_AAUDIO_USAGE_NOTIFICATION; + case ma_aaudio_usage_assistance_accessibility: return MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE; + case ma_aaudio_usage_assistance_navigation_guidance: return MA_AAUDIO_USAGE_NOTIFICATION_EVENT; + case ma_aaudio_usage_assistance_sonification: return MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + case ma_aaudio_usage_assitant: return MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + case ma_aaudio_usage_game: return MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION; + case ma_aaudio_usage_media: return MA_AAUDIO_USAGE_GAME; + case ma_aaudio_usage_notification: return MA_AAUDIO_USAGE_ASSISTANT; + case ma_aaudio_usage_notification_event: return MA_AAUDIO_SYSTEM_USAGE_EMERGENCY; + case ma_aaudio_usage_notification_ringtone: return MA_AAUDIO_SYSTEM_USAGE_SAFETY; + case ma_aaudio_usage_voice_communication: return MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS; + case ma_aaudio_usage_voice_communication_signalling: return MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT; default: break; } @@ -37788,10 +29506,10 @@ static ma_aaudio_usage_t ma_to_usage__aaudio(ma_aaudio_usage usage) static ma_aaudio_content_type_t ma_to_content_type__aaudio(ma_aaudio_content_type contentType) { switch (contentType) { - case ma_aaudio_content_type_speech: return MA_AAUDIO_CONTENT_TYPE_SPEECH; - case ma_aaudio_content_type_music: return MA_AAUDIO_CONTENT_TYPE_MUSIC; case ma_aaudio_content_type_movie: return MA_AAUDIO_CONTENT_TYPE_MOVIE; + case ma_aaudio_content_type_music: return MA_AAUDIO_CONTENT_TYPE_MUSIC; case ma_aaudio_content_type_sonification: return MA_AAUDIO_CONTENT_TYPE_SONIFICATION; + case ma_aaudio_content_type_speech: return MA_AAUDIO_CONTENT_TYPE_SPEECH; default: break; } @@ -37803,9 +29521,9 @@ static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_prese switch (inputPreset) { case ma_aaudio_input_preset_generic: return MA_AAUDIO_INPUT_PRESET_GENERIC; case ma_aaudio_input_preset_camcorder: return MA_AAUDIO_INPUT_PRESET_CAMCORDER; + case ma_aaudio_input_preset_unprocessed: return MA_AAUDIO_INPUT_PRESET_UNPROCESSED; case ma_aaudio_input_preset_voice_recognition: return MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION; case ma_aaudio_input_preset_voice_communication: return MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION; - case ma_aaudio_input_preset_unprocessed: return MA_AAUDIO_INPUT_PRESET_UNPROCESSED; case ma_aaudio_input_preset_voice_performance: return MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE; default: break; } @@ -37813,46 +29531,25 @@ static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_prese return MA_AAUDIO_INPUT_PRESET_GENERIC; } -static ma_aaudio_allowed_capture_policy_t ma_to_allowed_capture_policy__aaudio(ma_aaudio_allowed_capture_policy allowedCapturePolicy) -{ - switch (allowedCapturePolicy) { - case ma_aaudio_allow_capture_by_all: return MA_AAUDIO_ALLOW_CAPTURE_BY_ALL; - case ma_aaudio_allow_capture_by_system: return MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM; - case ma_aaudio_allow_capture_by_none: return MA_AAUDIO_ALLOW_CAPTURE_BY_NONE; - default: break; - } - - return MA_AAUDIO_ALLOW_CAPTURE_BY_ALL; -} - static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUserData, ma_aaudio_result_t error) { - ma_result result; - ma_job job; ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); (void)error; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); + +#if defined(MA_DEBUG_OUTPUT) + printf("[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); +#endif + /* - When we get an error, we'll assume that the stream is in an erroneous state and needs to be restarted. From the documentation, - we cannot do this from the error callback. Therefore we are going to use an event thread for the AAudio backend to do this - cleanly and safely. + From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need + to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. */ - job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); - job.data.device.aaudio.reroute.pDevice = pDevice; - - if (pStream == pDevice->aaudio.pStreamCapture) { - job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; - } - else { - job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; - } - - result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); - if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); - return; + if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) { +#if defined(MA_DEBUG_OUTPUT) + printf("[AAudio] Device Disconnected.\n"); +#endif } } @@ -37861,9 +29558,7 @@ static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio( ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); - if (frameCount > 0) { - ma_device_handle_backend_data_callback(pDevice, NULL, pAudioData, (ma_uint32)frameCount); - } + ma_device_handle_backend_data_callback(pDevice, NULL, pAudioData, frameCount); (void)pStream; return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; @@ -37874,14 +29569,7 @@ static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); - /* - I've had a report that AAudio can sometimes post a frame count of 0. We need to check for that here - so we don't get any errors at a deeper level. I'm doing the same with the capture side for safety, - though I've not yet had any reports about that one. - */ - if (frameCount > 0) { - ma_device_handle_backend_data_callback(pDevice, pAudioData, NULL, (ma_uint32)frameCount); - } + ma_device_handle_backend_data_callback(pDevice, pAudioData, NULL, frameCount); (void)pStream; return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; @@ -37891,6 +29579,7 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* { ma_AAudioStreamBuilder* pBuilder; ma_aaudio_result_t resultAA; + ma_uint32 bufferCapacityInFrames; /* Safety. */ *ppBuilder = NULL; @@ -37916,35 +29605,33 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* ((MA_PFN_AAudioStreamBuilder_setSampleRate)pContext->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder, pDescriptor->sampleRate); } - if (pDescriptor->channels != 0) { - ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels); + if (deviceType == ma_device_type_capture) { + if (pDescriptor->channels != 0) { + ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels); + } + if (pDescriptor->format != ma_format_unknown) { + ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); + } + } else { + if (pDescriptor->channels != 0) { + ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels); + } + if (pDescriptor->format != ma_format_unknown) { + ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); + } } - if (pDescriptor->format != ma_format_unknown) { - ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); - } - - /* - There have been reports where setting the frames per data callback results in an error. - In particular, re-routing may inadvertently switch from low-latency mode, resulting in a less stable - stream from the legacy path (AudioStreamLegacy). To address this, we simply don't set the value. It - can still be set if it's explicitly requested via the aaudio.allowSetBufferCapacity variable in the - device config. + AAudio is annoying when it comes to it's buffer calculation stuff because it doesn't let you + retrieve the actual sample rate until after you've opened the stream. But you need to configure + the buffer capacity before you open the stream... :/ + + To solve, we're just going to assume MA_DEFAULT_SAMPLE_RATE (48000) and move on. */ - if ((!pConfig->aaudio.enableCompatibilityWorkarounds || ma_android_sdk_version() > 30) && pConfig->aaudio.allowSetBufferCapacity) { - /* - AAudio is annoying when it comes to its buffer calculation stuff because it doesn't let you - retrieve the actual sample rate until after you've opened the stream. But you need to configure - the buffer capacity before you open the stream... :/ + bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, pDescriptor->sampleRate, pConfig->performanceProfile) * pDescriptor->periodCount; - To solve, we're just going to assume MA_DEFAULT_SAMPLE_RATE (48000) and move on. - */ - ma_uint32 bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, pDescriptor->sampleRate, pConfig->performanceProfile) * pDescriptor->periodCount; - - ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames); - ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pDescriptor->periodCount); - } + ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames); + ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pDescriptor->periodCount); if (deviceType == ma_device_type_capture) { if (pConfig->aaudio.inputPreset != ma_aaudio_input_preset_default && pContext->aaudio.AAudioStreamBuilder_setInputPreset != NULL) { @@ -37961,20 +29648,12 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* ((MA_PFN_AAudioStreamBuilder_setContentType)pContext->aaudio.AAudioStreamBuilder_setContentType)(pBuilder, ma_to_content_type__aaudio(pConfig->aaudio.contentType)); } - if (pConfig->aaudio.allowedCapturePolicy != ma_aaudio_allow_capture_default && pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy != NULL) { - ((MA_PFN_AAudioStreamBuilder_setAllowedCapturePolicy)pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy)(pBuilder, ma_to_allowed_capture_policy__aaudio(pConfig->aaudio.allowedCapturePolicy)); - } - ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice); } - /* - If we set AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, we allow for MMAP (non-legacy path). - Since there's a mapping between miniaudio's performance profiles and AAudio's performance modes, let's use it. - Beware though, with a conservative performance profile, AAudio will indeed take the legacy path. - */ + /* Not sure how this affects things, but since there's a mapping between miniaudio's performance profiles and AAudio's performance modes, let go ahead and set it. */ ((MA_PFN_AAudioStreamBuilder_setPerformanceMode)pContext->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder, (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY : MA_AAUDIO_PERFORMANCE_MODE_NONE); - + /* We need to set an error callback to detect device changes. */ if (pDevice != NULL) { /* <-- pDevice should never be null if pDescriptor is not null, which is always the case if we hit this branch. Check anyway for safety. */ ((MA_PFN_AAudioStreamBuilder_setErrorCallback)pContext->aaudio.AAudioStreamBuilder_setErrorCallback)(pBuilder, ma_stream_error_callback__aaudio, (void*)pDevice); @@ -38008,9 +29687,6 @@ static ma_result ma_open_stream_basic__aaudio(ma_context* pContext, const ma_dev return result; } - /* Let's give AAudio a hint to avoid the legacy path (AudioStreamLegacy). */ - ((MA_PFN_AAudioStreamBuilder_setPerformanceMode)pContext->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder, MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); - return ma_open_stream_and_close_builder__aaudio(pContext, pBuilder, ppStream); } @@ -38019,9 +29695,8 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf ma_result result; ma_AAudioStreamBuilder* pBuilder; - MA_ASSERT(pDevice != NULL); - MA_ASSERT(pDescriptor != NULL); - MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */ + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pConfig->deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */ *ppStream = NULL; @@ -38035,10 +29710,6 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf static ma_result ma_close_stream__aaudio(ma_context* pContext, ma_AAudioStream* pStream) { - if (pStream == NULL) { - return MA_INVALID_ARGS; - } - return ma_result_from_aaudio(((MA_PFN_AAudioStream_close)pContext->aaudio.AAudioStream_close)(pStream)); } @@ -38165,36 +29836,20 @@ static ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_dev return MA_SUCCESS; } -static ma_result ma_close_streams__aaudio(ma_device* pDevice) -{ - MA_ASSERT(pDevice != NULL); - - /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); - pDevice->aaudio.pStreamCapture = NULL; - } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); - pDevice->aaudio.pStreamPlayback = NULL; - } - - return MA_SUCCESS; -} static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - /* Wait for any rerouting to finish before attempting to close the streams. */ - ma_mutex_lock(&pDevice->aaudio.rerouteLock); - { - ma_close_streams__aaudio(pDevice); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + pDevice->aaudio.pStreamCapture = NULL; } - ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - /* Destroy re-routing lock. */ - ma_mutex_uninit(&pDevice->aaudio.rerouteLock); + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); + pDevice->aaudio.pStreamPlayback = NULL; + } return MA_SUCCESS; } @@ -38225,9 +29880,9 @@ static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_dev /* For the channel map we need to be sure we don't overflow any buffers. */ if (pDescriptor->channels <= MA_MAX_CHANNELS) { - ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); /* <-- Cannot find info on channel order, so assuming a default. */ + ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptor->channels, pDescriptor->channelMap); /* <-- Cannot find info on channel order, so assuming a default. */ } else { - ma_channel_map_init_blank(pDescriptor->channelMap, MA_MAX_CHANNELS); /* Too many channels. Use a blank channel map. */ + ma_channel_map_init_blank(MA_MAX_CHANNELS, pDescriptor->channelMap); /* Too many channels. Use a blank channel map. */ } bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pDevice->pContext->aaudio.AAudioStream_getBufferCapacityInFrames)(pStream); @@ -38246,7 +29901,7 @@ static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_dev return MA_SUCCESS; } -static ma_result ma_device_init_streams__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { ma_result result; @@ -38256,11 +29911,11 @@ static ma_result ma_device_init_streams__aaudio(ma_device* pDevice, const ma_dev return MA_DEVICE_TYPE_NOT_SUPPORTED; } - pDevice->aaudio.usage = pConfig->aaudio.usage; - pDevice->aaudio.contentType = pConfig->aaudio.contentType; - pDevice->aaudio.inputPreset = pConfig->aaudio.inputPreset; - pDevice->aaudio.allowedCapturePolicy = pConfig->aaudio.allowedCapturePolicy; - pDevice->aaudio.noAutoStartAfterReroute = pConfig->aaudio.noAutoStartAfterReroute; + /* No exclusive mode with AAudio. */ + if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || + ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { + return MA_SHARE_MODE_NOT_SUPPORTED; + } if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture); @@ -38279,25 +29934,6 @@ static ma_result ma_device_init_streams__aaudio(ma_device* pDevice, const ma_dev return MA_SUCCESS; } -static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) -{ - ma_result result; - - MA_ASSERT(pDevice != NULL); - - result = ma_device_init_streams__aaudio(pDevice, pConfig, pDescriptorPlayback, pDescriptorCapture); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_mutex_init(&pDevice->aaudio.rerouteLock); - if (result != MA_SUCCESS) { - return result; - } - - return MA_SUCCESS; -} - static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream) { ma_aaudio_result_t resultAA; @@ -38305,16 +29941,12 @@ static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStr MA_ASSERT(pDevice != NULL); - if (pStream == NULL) { - return MA_INVALID_ARGS; - } - resultAA = ((MA_PFN_AAudioStream_requestStart)pDevice->pContext->aaudio.AAudioStream_requestStart)(pStream); if (resultAA != MA_AAUDIO_OK) { return ma_result_from_aaudio(resultAA); } - /* Do we actually need to wait for the device to transition into its started state? */ + /* Do we actually need to wait for the device to transition into it's started state? */ /* The device should be in either a starting or started state. If it's not set to started we need to wait for it to transition. It should go from starting to started. */ currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); @@ -38341,10 +29973,6 @@ static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStre MA_ASSERT(pDevice != NULL); - if (pStream == NULL) { - return MA_INVALID_ARGS; - } - /* From the AAudio documentation: @@ -38352,10 +29980,6 @@ static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStre This maps with miniaudio's requirement that device's be drained which means we don't need to implement any draining logic. */ - currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); - if (currentState == MA_AAUDIO_STREAM_STATE_DISCONNECTED) { - return MA_SUCCESS; /* The device is disconnected. Don't try stopping it. */ - } resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream); if (resultAA != MA_AAUDIO_OK) { @@ -38406,6 +30030,8 @@ static ma_result ma_device_start__aaudio(ma_device* pDevice) static ma_result ma_device_stop__aaudio(ma_device* pDevice) { + ma_stop_proc onStop; + MA_ASSERT(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { @@ -38422,146 +30048,10 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) } } - ma_device__on_notification_stopped(pDevice); - - return MA_SUCCESS; -} - -static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) -{ - ma_result result; - int32_t retries = 0; - - MA_ASSERT(pDevice != NULL); - - /* - TODO: Stop retrying if main thread is about to uninit device. - */ - ma_mutex_lock(&pDevice->aaudio.rerouteLock); - { -error_disconnected: - /* The first thing to do is close the streams. */ - ma_close_streams__aaudio(pDevice); - - /* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ - ma_device_config deviceConfig; - ma_device_descriptor descriptorPlayback; - ma_device_descriptor descriptorCapture; - - deviceConfig = ma_device_config_init(deviceType); - deviceConfig.playback.pDeviceID = NULL; /* Only doing rerouting with default devices. */ - deviceConfig.playback.shareMode = pDevice->playback.shareMode; - deviceConfig.playback.format = pDevice->playback.format; - deviceConfig.playback.channels = pDevice->playback.channels; - deviceConfig.capture.pDeviceID = NULL; /* Only doing rerouting with default devices. */ - deviceConfig.capture.shareMode = pDevice->capture.shareMode; - deviceConfig.capture.format = pDevice->capture.format; - deviceConfig.capture.channels = pDevice->capture.channels; - deviceConfig.sampleRate = pDevice->sampleRate; - deviceConfig.aaudio.usage = pDevice->aaudio.usage; - deviceConfig.aaudio.contentType = pDevice->aaudio.contentType; - deviceConfig.aaudio.inputPreset = pDevice->aaudio.inputPreset; - deviceConfig.aaudio.allowedCapturePolicy = pDevice->aaudio.allowedCapturePolicy; - deviceConfig.aaudio.noAutoStartAfterReroute = pDevice->aaudio.noAutoStartAfterReroute; - deviceConfig.periods = 1; - - /* Try to get an accurate period size. */ - if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { - deviceConfig.periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames; - } else { - deviceConfig.periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames; - } - - if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { - descriptorCapture.pDeviceID = deviceConfig.capture.pDeviceID; - descriptorCapture.shareMode = deviceConfig.capture.shareMode; - descriptorCapture.format = deviceConfig.capture.format; - descriptorCapture.channels = deviceConfig.capture.channels; - descriptorCapture.sampleRate = deviceConfig.sampleRate; - descriptorCapture.periodSizeInFrames = deviceConfig.periodSizeInFrames; - descriptorCapture.periodCount = deviceConfig.periods; - } - - if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { - descriptorPlayback.pDeviceID = deviceConfig.playback.pDeviceID; - descriptorPlayback.shareMode = deviceConfig.playback.shareMode; - descriptorPlayback.format = deviceConfig.playback.format; - descriptorPlayback.channels = deviceConfig.playback.channels; - descriptorPlayback.sampleRate = deviceConfig.sampleRate; - descriptorPlayback.periodSizeInFrames = deviceConfig.periodSizeInFrames; - descriptorPlayback.periodCount = deviceConfig.periods; - } - - result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); - if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); - goto done; - } - - result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); - if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); - ma_close_streams__aaudio(pDevice); - goto done; - } - - /* We'll only ever do this in response to a reroute. */ - ma_device__on_notification_rerouted(pDevice); - - /* If the device is started, start the streams. Maybe make this configurable? */ - if (ma_device_get_state(pDevice) == ma_device_state_started) { - if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { - result = ma_device_start__aaudio(pDevice); - if (result != MA_SUCCESS) { - /* We got disconnected! Retry a few times, until we find a connected device! */ - retries += 1; - if (retries <= 3) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries); - goto error_disconnected; - } - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); - goto done; - } - } else { - ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ - } - } - - result = MA_SUCCESS; + onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); } -done: - /* Re-routing done */ - ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - - return result; -} - -static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo) -{ - ma_AAudioStream* pStream = NULL; - - MA_ASSERT(pDevice != NULL); - MA_ASSERT(type != ma_device_type_duplex); - MA_ASSERT(pDeviceInfo != NULL); - - if (type == ma_device_type_capture) { - pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamCapture; - pDeviceInfo->id.aaudio = pDevice->capture.id.aaudio; - ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */ - } - if (type == ma_device_type_playback) { - pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback; - pDeviceInfo->id.aaudio = pDevice->playback.id.aaudio; - ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */ - } - - /* Safety. Should never happen. */ - if (pStream == NULL) { - return MA_INVALID_OPERATION; - } - - pDeviceInfo->nativeDataFormatCount = 0; - ma_context_add_native_data_format_from_AAudioStream__aaudio(pDevice->pContext, pStream, 0, pDeviceInfo); return MA_SUCCESS; } @@ -38572,9 +30062,7 @@ static ma_result ma_context_uninit__aaudio(ma_context* pContext) MA_ASSERT(pContext != NULL); MA_ASSERT(pContext->backend == ma_backend_aaudio); - ma_device_job_thread_uninit(&pContext->aaudio.jobThread, &pContext->allocationCallbacks); - - ma_dlclose(ma_context_get_log(pContext), pContext->aaudio.hAAudio); + ma_dlclose(pContext, pContext->aaudio.hAAudio); pContext->aaudio.hAAudio = NULL; return MA_SUCCESS; @@ -38582,14 +30070,13 @@ static ma_result ma_context_uninit__aaudio(ma_context* pContext) static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) { -#if !defined(MA_NO_RUNTIME_LINKING) size_t i; const char* libNames[] = { "libaaudio.so" }; for (i = 0; i < ma_countof(libNames); ++i) { - pContext->aaudio.hAAudio = ma_dlopen(ma_context_get_log(pContext), libNames[i]); + pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]); if (pContext->aaudio.hAAudio != NULL) { break; } @@ -38599,68 +30086,35 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ return MA_FAILED_TO_INIT_BACKEND; } - pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudio_createStreamBuilder"); - pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete"); - pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId"); - pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection"); - pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode"); - pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat"); - pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount"); - pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate"); - pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames"); - pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback"); - pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback"); - pContext->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback"); - pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode"); - pContext->aaudio.AAudioStreamBuilder_setUsage = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setUsage"); - pContext->aaudio.AAudioStreamBuilder_setContentType = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setContentType"); - pContext->aaudio.AAudioStreamBuilder_setInputPreset = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setInputPreset"); - pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_setAllowedCapturePolicy"); - pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream"); - pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_close"); - pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getState"); - pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange"); - pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getFormat"); - pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getChannelCount"); - pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getSampleRate"); - pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames"); - pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback"); - pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst"); - pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_requestStart"); - pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_requestStop"); -#else - pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)AAudio_createStreamBuilder; - pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)AAudioStreamBuilder_delete; - pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)AAudioStreamBuilder_setDeviceId; - pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)AAudioStreamBuilder_setDirection; - pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)AAudioStreamBuilder_setSharingMode; - pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)AAudioStreamBuilder_setFormat; - pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)AAudioStreamBuilder_setChannelCount; - pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)AAudioStreamBuilder_setSampleRate; - pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)AAudioStreamBuilder_setBufferCapacityInFrames; - pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)AAudioStreamBuilder_setFramesPerDataCallback; - pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)AAudioStreamBuilder_setDataCallback; - pContext->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)AAudioStreamBuilder_setErrorCallback; - pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)AAudioStreamBuilder_setPerformanceMode; - pContext->aaudio.AAudioStreamBuilder_setUsage = (ma_proc)AAudioStreamBuilder_setUsage; - pContext->aaudio.AAudioStreamBuilder_setContentType = (ma_proc)AAudioStreamBuilder_setContentType; - pContext->aaudio.AAudioStreamBuilder_setInputPreset = (ma_proc)AAudioStreamBuilder_setInputPreset; - #if defined(__ANDROID_API__) && __ANDROID_API__ >= 29 - pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy = (ma_proc)AAudioStreamBuilder_setAllowedCapturePolicy; - #endif - pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)AAudioStreamBuilder_openStream; - pContext->aaudio.AAudioStream_close = (ma_proc)AAudioStream_close; - pContext->aaudio.AAudioStream_getState = (ma_proc)AAudioStream_getState; - pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)AAudioStream_waitForStateChange; - pContext->aaudio.AAudioStream_getFormat = (ma_proc)AAudioStream_getFormat; - pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)AAudioStream_getChannelCount; - pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)AAudioStream_getSampleRate; - pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)AAudioStream_getBufferCapacityInFrames; - pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)AAudioStream_getFramesPerDataCallback; - pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)AAudioStream_getFramesPerBurst; - pContext->aaudio.AAudioStream_requestStart = (ma_proc)AAudioStream_requestStart; - pContext->aaudio.AAudioStream_requestStop = (ma_proc)AAudioStream_requestStop; -#endif + pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder"); + pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete"); + pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId"); + pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection"); + pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode"); + pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat"); + pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount"); + pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate"); + pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames"); + pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback"); + pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback"); + pContext->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback"); + pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode"); + pContext->aaudio.AAudioStreamBuilder_setUsage = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setUsage"); + pContext->aaudio.AAudioStreamBuilder_setContentType = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setContentType"); + pContext->aaudio.AAudioStreamBuilder_setInputPreset = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setInputPreset"); + pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream"); + pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close"); + pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState"); + pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange"); + pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat"); + pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount"); + pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate"); + pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames"); + pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback"); + pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst"); + pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart"); + pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop"); + pCallbacks->onContextInit = ma_context_init__aaudio; pCallbacks->onContextUninit = ma_context_uninit__aaudio; @@ -38673,59 +30127,10 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ pCallbacks->onDeviceRead = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceWrite = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceDataLoop = NULL; /* Not used because AAudio is asynchronous. */ - pCallbacks->onDeviceGetInfo = ma_device_get_info__aaudio; - - - /* We need a job thread so we can deal with rerouting. */ - { - ma_result result; - ma_device_job_thread_config jobThreadConfig; - - jobThreadConfig = ma_device_job_thread_config_init(); - - result = ma_device_job_thread_init(&jobThreadConfig, &pContext->allocationCallbacks, &pContext->aaudio.jobThread); - if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->aaudio.hAAudio); - pContext->aaudio.hAAudio = NULL; - return result; - } - } - (void)pConfig; return MA_SUCCESS; } - -static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) -{ - ma_result result; - ma_device* pDevice; - - MA_ASSERT(pJob != NULL); - - pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice; - MA_ASSERT(pDevice != NULL); - - /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ - result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); - if (result != MA_SUCCESS) { - /* - Getting here means we failed to reroute the device. The best thing I can think of here is to - just stop the device. - */ - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); - ma_device_stop(pDevice); - return result; - } - - return MA_SUCCESS; -} -#else -/* Getting here means there is no AAudio backend so we need a no-op job implementation. */ -static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) -{ - return ma_job_process__noop(pJob); -} #endif /* AAudio */ @@ -39052,7 +30457,6 @@ return_default_device:; if (cbResult) { ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); - deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT; ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } @@ -39061,7 +30465,6 @@ return_default_device:; if (cbResult) { ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); - deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT; ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } @@ -39160,12 +30563,10 @@ return_default_device: } } - /* ID and Name / Description */ + /* Name / Description */ if (deviceType == ma_device_type_playback) { - pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT; ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { - pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT; ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } @@ -39212,7 +30613,7 @@ static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBuff */ /* Don't do anything if the device is not started. */ - if (ma_device_get_state(pDevice) != ma_device_state_started) { + if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { return; } @@ -39246,7 +30647,7 @@ static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBuf (void)pBufferQueue; /* Don't do anything if the device is not started. */ - if (ma_device_get_state(pDevice) != ma_device_state_started) { + if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { return; } @@ -39283,7 +30684,7 @@ static ma_result ma_device_uninit__opensl(ma_device* pDevice) MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj); } - ma_free(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { @@ -39294,7 +30695,7 @@ static ma_result ma_device_uninit__opensl(ma_device* pDevice) MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj); } - ma_free(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma__free_from_callbacks(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -39331,8 +30732,8 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch #endif pDataFormat->numChannels = channels; - ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */ - pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format) * 8; + ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate) * 1000; /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */ + pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8; pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels); pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; @@ -39411,11 +30812,8 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf SLDataLocator_AndroidSimpleBufferQueue queue; SLresult resultSL; size_t bufferSizeInBytes; - SLInterfaceID itfIDs[2]; - const SLboolean itfIDsRequired[] = { - SL_BOOLEAN_TRUE, /* SL_IID_ANDROIDSIMPLEBUFFERQUEUE */ - SL_BOOLEAN_FALSE /* SL_IID_ANDROIDCONFIGURATION */ - }; + SLInterfaceID itfIDs1[1]; + const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; #endif MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to initialize a new device. */ @@ -39433,8 +30831,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf queues). */ #ifdef MA_ANDROID - itfIDs[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - itfIDs[1] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION; + itfIDs1[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE; /* No exclusive mode with OpenSL|ES. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || @@ -39459,7 +30856,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; - locatorDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; /* Must always use the default device with Android. */ + locatorDevice.deviceID = (pDescriptorCapture->pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pDescriptorCapture->pDeviceID->opensl; locatorDevice.device = NULL; source.pLocator = &locatorDevice; @@ -39470,28 +30867,27 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf sink.pLocator = &queue; sink.pFormat = (SLDataFormat_PCM*)&pcm; - resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); - if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) { + resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = 1; ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */ pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ - pcm.channelMask = 0; - resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); + pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); } if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.", ma_result_from_OpenSL(resultSL)); } /* Set the recording preset before realizing the player. */ if (pConfig->opensl.recordingPreset != ma_opensl_recording_preset_default) { - resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pRecorderConfig); + resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pRecorderConfig); if (resultSL == SL_RESULT_SUCCESS) { SLint32 recordingPreset = ma_to_recording_preset__opensl(pConfig->opensl.recordingPreset); resultSL = (*pRecorderConfig)->SetConfiguration(pRecorderConfig, SL_ANDROID_KEY_RECORDING_PRESET, &recordingPreset, sizeof(SLint32)); @@ -39504,29 +30900,25 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_RECORD, &pDevice->opensl.pAudioRecorder); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL)); } /* The internal format is determined by the "pcm" object. */ @@ -39537,11 +30929,10 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pDevice->opensl.currentBufferIndexCapture = 0; bufferSizeInBytes = pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * pDescriptorCapture->periodCount; - pDevice->opensl.pBufferCapture = (ma_uint8*)ma_calloc(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); + pDevice->opensl.pBufferCapture = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); if (pDevice->opensl.pBufferCapture == NULL) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer."); - return MA_OUT_OF_MEMORY; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY); } MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes); } @@ -39558,22 +30949,19 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL)); } /* Set the output device. */ @@ -39593,8 +30981,8 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf sink.pLocator = &outmixLocator; sink.pFormat = NULL; - resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); - if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) { + resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = 2; @@ -39602,13 +30990,12 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); + resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); } if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.", ma_result_from_OpenSL(resultSL)); } @@ -39627,29 +31014,25 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_PLAY, &pDevice->opensl.pAudioPlayer); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL)); } resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL)); } /* The internal format is determined by the "pcm" object. */ @@ -39660,11 +31043,10 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pDevice->opensl.currentBufferIndexPlayback = 0; bufferSizeInBytes = pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) * pDescriptorPlayback->periodCount; - pDevice->opensl.pBufferPlayback = (ma_uint8*)ma_calloc(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); + pDevice->opensl.pBufferPlayback = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); if (pDevice->opensl.pBufferPlayback == NULL) { ma_device_uninit__opensl(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer."); - return MA_OUT_OF_MEMORY; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY); } MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes); } @@ -39691,8 +31073,7 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING); if (resultSL != SL_RESULT_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.", ma_result_from_OpenSL(resultSL)); } periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); @@ -39700,8 +31081,7 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", ma_result_from_OpenSL(resultSL)); } } } @@ -39709,11 +31089,10 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING); if (resultSL != SL_RESULT_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.", ma_result_from_OpenSL(resultSL)); } - /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueue silent buffers. */ + /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueu silent buffers. */ if (pDevice->type == ma_device_type_duplex) { MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } else { @@ -39725,8 +31104,7 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pDevice->opensl.pBufferPlayback + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.", ma_result_from_OpenSL(resultSL)); } } } @@ -39771,6 +31149,7 @@ static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type devi static ma_result ma_device_stop__opensl(ma_device* pDevice) { SLresult resultSL; + ma_stop_proc onStop; MA_ASSERT(pDevice != NULL); @@ -39784,8 +31163,7 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice) resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); if (resultSL != SL_RESULT_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.", ma_result_from_OpenSL(resultSL)); } MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture); @@ -39796,15 +31174,17 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice) resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); if (resultSL != SL_RESULT_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device."); - return ma_result_from_OpenSL(resultSL); + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.", ma_result_from_OpenSL(resultSL)); } MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback); } /* Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. */ - ma_device__on_notification_stopped(pDevice); + onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); + } return MA_SUCCESS; } @@ -39834,9 +31214,9 @@ static ma_result ma_context_uninit__opensl(ma_context* pContext) static ma_result ma_dlsym_SLInterfaceID__opensl(ma_context* pContext, const char* pName, ma_handle* pHandle) { /* We need to return an error if the symbol cannot be found. This is important because there have been reports that some symbols do not exist. */ - ma_handle* p = (ma_handle*)ma_dlsym(ma_context_get_log(pContext), pContext->opensl.libOpenSLES, pName); + ma_handle* p = (ma_handle*)ma_dlsym(pContext, pContext->opensl.libOpenSLES, pName); if (p == NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol %s", pName); + ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol %s", pName); return MA_NO_BACKEND; } @@ -39892,63 +31272,63 @@ static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_ references to the symbols and will hopefully skip the checks. */ for (i = 0; i < ma_countof(libOpenSLESNames); i += 1) { - pContext->opensl.libOpenSLES = ma_dlopen(ma_context_get_log(pContext), libOpenSLESNames[i]); + pContext->opensl.libOpenSLES = ma_dlopen(pContext, libOpenSLESNames[i]); if (pContext->opensl.libOpenSLES != NULL) { break; } } if (pContext->opensl.libOpenSLES == NULL) { - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Could not find libOpenSLES.so"); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Could not find libOpenSLES.so"); return MA_NO_BACKEND; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ENGINE", &pContext->opensl.SL_IID_ENGINE); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_AUDIOIODEVICECAPABILITIES", &pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_RECORD", &pContext->opensl.SL_IID_RECORD); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_PLAY", &pContext->opensl.SL_IID_PLAY); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_OUTPUTMIX", &pContext->opensl.SL_IID_OUTPUTMIX); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDCONFIGURATION", &pContext->opensl.SL_IID_ANDROIDCONFIGURATION); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); return result; } - pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->opensl.libOpenSLES, "slCreateEngine"); + pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(pContext, pContext->opensl.libOpenSLES, "slCreateEngine"); if (pContext->opensl.slCreateEngine == NULL) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol slCreateEngine."); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol slCreateEngine."); return MA_NO_BACKEND; } #else @@ -39971,8 +31351,8 @@ static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_ ma_spinlock_unlock(&g_maOpenSLSpinlock); if (result != MA_SUCCESS) { - ma_dlclose(ma_context_get_log(pContext), pContext->opensl.libOpenSLES); - ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Failed to initialize OpenSL engine."); + ma_dlclose(pContext, pContext->opensl.libOpenSLES); + ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Failed to initialize OpenSL engine."); return result; } @@ -40001,33 +31381,6 @@ Web Audio Backend #ifdef MA_HAS_WEBAUDIO #include -#if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 32))) - #include - #define MA_SUPPORT_AUDIO_WORKLETS - - #if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 70))) - #define MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE - #endif -#endif - -/* -TODO: Version 0.12: Swap this logic around so that AudioWorklets are used by default. Add MA_NO_AUDIO_WORKLETS. -*/ -#if defined(MA_ENABLE_AUDIO_WORKLETS) && defined(MA_SUPPORT_AUDIO_WORKLETS) - #define MA_USE_AUDIO_WORKLETS -#endif - -/* The thread stack size must be a multiple of 16. */ -#ifndef MA_AUDIO_WORKLETS_THREAD_STACK_SIZE -#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 131072 -#endif - -#if defined(MA_USE_AUDIO_WORKLETS) -#define MA_WEBAUDIO_LATENCY_HINT_BALANCED "balanced" -#define MA_WEBAUDIO_LATENCY_HINT_INTERACTIVE "interactive" -#define MA_WEBAUDIO_LATENCY_HINT_PLAYBACK "playback" -#endif - static ma_bool32 ma_is_capture_supported__webaudio() { return EM_ASM_INT({ @@ -40038,16 +31391,6 @@ static ma_bool32 ma_is_capture_supported__webaudio() #ifdef __cplusplus extern "C" { #endif -void* EMSCRIPTEN_KEEPALIVE ma_malloc_emscripten(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) -{ - return ma_malloc(sz, pAllocationCallbacks); -} - -void EMSCRIPTEN_KEEPALIVE ma_free_emscripten(void* p, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_free(p, pAllocationCallbacks); -} - void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames) { ma_device_handle_backend_data_callback(pDevice, NULL, pFrames, (ma_uint32)frameCount); @@ -40138,78 +31481,69 @@ static ma_result ma_context_get_device_info__webaudio(ma_context* pContext, ma_d return MA_SUCCESS; } + +static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_type deviceType, int deviceIndex) +{ + MA_ASSERT(pDevice != NULL); + + EM_ASM({ + var device = miniaudio.get_device_by_index($0); + + /* Make sure all nodes are disconnected and marked for collection. */ + if (device.scriptNode !== undefined) { + device.scriptNode.onaudioprocess = function(e) {}; /* We want to reset the callback to ensure it doesn't get called after AudioContext.close() has returned. Shouldn't happen since we're disconnecting, but just to be safe... */ + device.scriptNode.disconnect(); + device.scriptNode = undefined; + } + if (device.streamNode !== undefined) { + device.streamNode.disconnect(); + device.streamNode = undefined; + } + + /* + Stop the device. I think there is a chance the callback could get fired after calling this, hence why we want + to clear the callback before closing. + */ + device.webaudio.close(); + device.webaudio = undefined; + + /* Can't forget to free the intermediary buffer. This is the buffer that's shared between JavaScript and C. */ + if (device.intermediaryBuffer !== undefined) { + Module._free(device.intermediaryBuffer); + device.intermediaryBuffer = undefined; + device.intermediaryBufferView = undefined; + device.intermediaryBufferSizeInBytes = undefined; + } + + /* Make sure the device is untracked so the slot can be reused later. */ + miniaudio.untrack_device_by_index($0); + }, deviceIndex, deviceType); +} + static ma_result ma_device_uninit__webaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - #if defined(MA_USE_AUDIO_WORKLETS) - { - EM_ASM({ - var device = window.miniaudio.get_device_by_index($0); - - if (device.streamNode !== undefined) { - device.streamNode.disconnect(); - device.streamNode = undefined; - } - - device.pDevice = undefined; - }, pDevice->webaudio.deviceIndex); - - emscripten_destroy_web_audio_node(pDevice->webaudio.audioWorklet); - emscripten_destroy_audio_context(pDevice->webaudio.audioContext); - ma_free(pDevice->webaudio.pStackBuffer, &pDevice->pContext->allocationCallbacks); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); } - #else - { - EM_ASM({ - var device = window.miniaudio.get_device_by_index($0); - /* Make sure all nodes are disconnected and marked for collection. */ - if (device.scriptNode !== undefined) { - device.scriptNode.onaudioprocess = function(e) {}; /* We want to reset the callback to ensure it doesn't get called after AudioContext.close() has returned. Shouldn't happen since we're disconnecting, but just to be safe... */ - device.scriptNode.disconnect(); - device.scriptNode = undefined; - } - - if (device.streamNode !== undefined) { - device.streamNode.disconnect(); - device.streamNode = undefined; - } - - /* - Stop the device. I think there is a chance the callback could get fired after calling this, hence why we want - to clear the callback before closing. - */ - device.webaudio.close(); - device.webaudio = undefined; - device.pDevice = undefined; - }, pDevice->webaudio.deviceIndex); + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback); } - #endif - - /* Clean up the device on the JS side. */ - EM_ASM({ - window.miniaudio.untrack_device_by_index($0); - }, pDevice->webaudio.deviceIndex); - - ma_free(pDevice->webaudio.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); return MA_SUCCESS; } -#if !defined(MA_USE_AUDIO_WORKLETS) static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__webaudio(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) { /* - There have been reports of the default buffer size being too small on some browsers. If we're using - the default buffer size, we'll make sure the period size is bigger than our standard defaults. + There have been reports of the default buffer size being too small on some browsers. There have been reports of the default buffer + size being too small on some browsers. If we're using default buffer size, we'll make sure the period size is a big biffer than our + standard defaults. */ ma_uint32 periodSizeInFrames; - if (nativeSampleRate == 0) { - nativeSampleRate = MA_DEFAULT_SAMPLE_RATE; - } - if (pDescriptor->periodSizeInFrames == 0) { if (pDescriptor->periodSizeInMilliseconds == 0) { if (performanceProfile == ma_performance_profile_low_latency) { @@ -40235,240 +31569,217 @@ static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__webaudio(co return periodSizeInFrames; } -#endif - -#if defined(MA_USE_AUDIO_WORKLETS) -typedef struct +static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType) { - ma_device* pDevice; - const ma_device_config* pConfig; - ma_device_descriptor* pDescriptorPlayback; - ma_device_descriptor* pDescriptorCapture; -} ma_audio_worklet_thread_initialized_data; + int deviceIndex; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_uint32 periodSizeInFrames; -static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const AudioSampleFrame* pInputs, int outputCount, AudioSampleFrame* pOutputs, int paramCount, const AudioParamFrame* pParams, void* pUserData) -{ - ma_device* pDevice = (ma_device*)pUserData; - ma_uint32 frameCount; + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pConfig != NULL); + MA_ASSERT(deviceType != ma_device_type_duplex); - (void)paramCount; - (void)pParams; - - /* - The Emscripten documentation says that it'll always be 128 frames being passed in. Hard coding it like that feels - like a very bad idea to me. Even if it's hard coded in the backend, the API and documentation should always refer - to variables instead of a hard coded number. In any case, will follow along for the time being. - - Unfortunately the audio data is not interleaved so we'll need to convert it before we give the data to miniaudio - for further processing. - */ - if (pDevice->type == ma_device_type_playback) { - frameCount = pDevice->playback.internalPeriodSizeInFrames; - } else { - frameCount = pDevice->capture.internalPeriodSizeInFrames; + if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) { + return MA_NO_DEVICE; } - if (ma_device_get_state(pDevice) != ma_device_state_started) { - /* Fill the output buffer with zero to avoid a noise sound */ - for (int i = 0; i < outputCount; i += 1) { - MA_ZERO_MEMORY(pOutputs[i].data, pOutputs[i].numberOfChannels * frameCount * sizeof(float)); + /* We're going to calculate some stuff in C just to simplify the JS code. */ + channels = (pDescriptor->channels > 0) ? pDescriptor->channels : MA_DEFAULT_CHANNELS; + sampleRate = (pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE; + periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptor, sampleRate, pConfig->performanceProfile); + + + /* We create the device on the JavaScript side and reference it using an index. We use this to make it possible to reference the device between JavaScript and C. */ + deviceIndex = EM_ASM_INT({ + var channels = $0; + var sampleRate = $1; + var bufferSize = $2; /* In PCM frames. */ + var isCapture = $3; + var pDevice = $4; + + if (typeof(miniaudio) === 'undefined') { + return -1; /* Context not initialized. */ } - return EM_TRUE; - } + var device = {}; - if (inputCount > 0) { - /* Input data needs to be interleaved before we hand it to the client. */ - for (ma_uint32 iChannel = 0; iChannel < pDevice->capture.internalChannels; iChannel += 1) { - for (ma_uint32 iFrame = 0; iFrame < frameCount; iFrame += 1) { - pDevice->webaudio.pIntermediaryBuffer[iFrame*pDevice->capture.internalChannels + iChannel] = pInputs[0].data[frameCount*iChannel + iFrame]; - } - } + /* The AudioContext must be created in a suspended state. */ + device.webaudio = new (window.AudioContext || window.webkitAudioContext)({sampleRate:sampleRate}); + device.webaudio.suspend(); + device.state = 1; /* MA_STATE_STOPPED */ - ma_device_process_pcm_frames_capture__webaudio(pDevice, frameCount, pDevice->webaudio.pIntermediaryBuffer); - } + /* + We need an intermediary buffer which we use for JavaScript and C interop. This buffer stores interleaved f32 PCM data. Because it's passed between + JavaScript and C it needs to be allocated and freed using Module._malloc() and Module._free(). + */ + device.intermediaryBufferSizeInBytes = channels * bufferSize * 4; + device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes); + device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes); - if (outputCount > 0) { - /* If it's a capture-only device, we'll need to output silence. */ - if (pDevice->type == ma_device_type_capture) { - MA_ZERO_MEMORY(pOutputs[0].data, frameCount * pDevice->playback.internalChannels * sizeof(float)); - } else { - ma_device_process_pcm_frames_playback__webaudio(pDevice, frameCount, pDevice->webaudio.pIntermediaryBuffer); + /* + Both playback and capture devices use a ScriptProcessorNode for performing per-sample operations. - /* We've read the data from the client. Now we need to deinterleave the buffer and output to the output buffer. */ - for (ma_uint32 iChannel = 0; iChannel < pDevice->playback.internalChannels; iChannel += 1) { - for (ma_uint32 iFrame = 0; iFrame < frameCount; iFrame += 1) { - pOutputs[0].data[frameCount*iChannel + iFrame] = pDevice->webaudio.pIntermediaryBuffer[iFrame*pDevice->playback.internalChannels + iChannel]; + ScriptProcessorNode is actually deprecated so this is likely to be temporary. The way this works for playback is very simple. You just set a callback + that's periodically fired, just like a normal audio callback function. But apparently this design is "flawed" and is now deprecated in favour of + something called AudioWorklets which _forces_ you to load a _separate_ .js file at run time... nice... Hopefully ScriptProcessorNode will continue to + work for years to come, but this may need to change to use AudioSourceBufferNode instead, which I think is what Emscripten uses for it's built-in SDL + implementation. I'll be avoiding that insane AudioWorklet API like the plague... + + For capture it is a bit unintuitive. We use the ScriptProccessorNode _only_ to get the raw PCM data. It is connected to an AudioContext just like the + playback case, however we just output silence to the AudioContext instead of passing any real data. It would make more sense to me to use the + MediaRecorder API, but unfortunately you need to specify a MIME time (Opus, Vorbis, etc.) for the binary blob that's returned to the client, but I've + been unable to figure out how to get this as raw PCM. The closest I can think is to use the MIME type for WAV files and just parse it, but I don't know + how well this would work. Although ScriptProccessorNode is deprecated, in practice it seems to have pretty good browser support so I'm leaving it like + this for now. If anyone knows how I could get raw PCM data using the MediaRecorder API please let me know! + */ + device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, channels, channels); + + if (isCapture) { + device.scriptNode.onaudioprocess = function(e) { + if (device.intermediaryBuffer === undefined) { + return; /* This means the device has been uninitialized. */ } - } - } - } - return EM_TRUE; -} + if(device.intermediaryBufferView.length == 0) { + /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */ + device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes); + } + /* Make sure silence it output to the AudioContext destination. Not doing this will cause sound to come out of the speakers! */ + for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { + e.outputBuffer.getChannelData(iChannel).fill(0.0); + } -static void ma_audio_worklet_processor_created__webaudio(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void* pUserData) -{ - ma_audio_worklet_thread_initialized_data* pParameters = (ma_audio_worklet_thread_initialized_data*)pUserData; - EmscriptenAudioWorkletNodeCreateOptions audioWorkletOptions; - int channels = 0; - size_t intermediaryBufferSizeInFrames; - int sampleRate; + /* There are some situations where we may want to send silence to the client. */ + var sendSilence = false; + if (device.streamNode === undefined) { + sendSilence = true; + } - if (success == EM_FALSE) { - pParameters->pDevice->webaudio.initResult = MA_ERROR; - ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); - return; - } + /* Sanity check. This will never happen, right? */ + if (e.inputBuffer.numberOfChannels != channels) { + console.log("Capture: Channel count mismatch. " + e.inputBufer.numberOfChannels + " != " + channels + ". Sending silence."); + sendSilence = true; + } - /* The next step is to initialize the audio worklet node. */ - MA_ZERO_OBJECT(&audioWorkletOptions); + /* This looped design guards against the situation where e.inputBuffer is a different size to the original buffer size. Should never happen in practice. */ + var totalFramesProcessed = 0; + while (totalFramesProcessed < e.inputBuffer.length) { + var framesRemaining = e.inputBuffer.length - totalFramesProcessed; + var framesToProcess = framesRemaining; + if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) { + framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4); + } - /* - The way channel counts work with Web Audio is confusing. As far as I can tell, there's no way to know the channel - count from MediaStreamAudioSourceNode (what we use for capture)? The only way to have control is to configure an - output channel count on the capture side. This is slightly confusing for capture mode because intuitively you - wouldn't actually connect an output to an input-only node, but this is what we'll have to do in order to have - proper control over the channel count. In the capture case, we'll have to output silence to its output node. - */ - if (pParameters->pConfig->deviceType == ma_device_type_capture) { - channels = (int)((pParameters->pDescriptorCapture->channels > 0) ? pParameters->pDescriptorCapture->channels : MA_DEFAULT_CHANNELS); - audioWorkletOptions.numberOfInputs = 1; - } else { - channels = (int)((pParameters->pDescriptorPlayback->channels > 0) ? pParameters->pDescriptorPlayback->channels : MA_DEFAULT_CHANNELS); + /* We need to do the reverse of the playback case. We need to interleave the input data and copy it into the intermediary buffer. Then we send it to the client. */ + if (sendSilence) { + device.intermediaryBufferView.fill(0.0); + } else { + for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) { + for (var iChannel = 0; iChannel < e.inputBuffer.numberOfChannels; ++iChannel) { + device.intermediaryBufferView[iFrame*channels + iChannel] = e.inputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame]; + } + } + } - if (pParameters->pConfig->deviceType == ma_device_type_duplex) { - audioWorkletOptions.numberOfInputs = 1; - } else { - audioWorkletOptions.numberOfInputs = 0; - } - } + /* Send data to the client from our intermediary buffer. */ + ccall("ma_device_process_pcm_frames_capture__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]); - audioWorkletOptions.numberOfOutputs = 1; - audioWorkletOptions.outputChannelCounts = &channels; - - - /* - Now that we know the channel count to use we can allocate the intermediary buffer. The - intermediary buffer is used for interleaving and deinterleaving. - */ - #if defined(MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE) - { - intermediaryBufferSizeInFrames = (size_t)emscripten_audio_context_quantum_size(audioContext); - } - #else - { - intermediaryBufferSizeInFrames = 128; - } - #endif - - pParameters->pDevice->webaudio.pIntermediaryBuffer = (float*)ma_malloc(intermediaryBufferSizeInFrames * (ma_uint32)channels * sizeof(float), &pParameters->pDevice->pContext->allocationCallbacks); - if (pParameters->pDevice->webaudio.pIntermediaryBuffer == NULL) { - pParameters->pDevice->webaudio.initResult = MA_OUT_OF_MEMORY; - ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); - return; - } - - pParameters->pDevice->webaudio.audioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "miniaudio", &audioWorkletOptions, &ma_audio_worklet_process_callback__webaudio, pParameters->pDevice); - - /* With the audio worklet initialized we can now attach it to the graph. */ - if (pParameters->pConfig->deviceType == ma_device_type_capture || pParameters->pConfig->deviceType == ma_device_type_duplex) { - ma_result attachmentResult = (ma_result)EM_ASM_INT({ - var getUserMediaResult = 0; - var audioWorklet = emscriptenGetAudioObject($0); - var audioContext = emscriptenGetAudioObject($1); + totalFramesProcessed += framesToProcess; + } + }; navigator.mediaDevices.getUserMedia({audio:true, video:false}) .then(function(stream) { - audioContext.streamNode = audioContext.createMediaStreamSource(stream); - audioContext.streamNode.connect(audioWorklet); - audioWorklet.connect(audioContext.destination); - getUserMediaResult = 0; /* 0 = MA_SUCCESS */ + device.streamNode = device.webaudio.createMediaStreamSource(stream); + device.streamNode.connect(device.scriptNode); + device.scriptNode.connect(device.webaudio.destination); }) .catch(function(error) { - console.log("navigator.mediaDevices.getUserMedia Failed: " + error); - getUserMediaResult = -1; /* -1 = MA_ERROR */ + /* I think this should output silence... */ + device.scriptNode.connect(device.webaudio.destination); }); + } else { + device.scriptNode.onaudioprocess = function(e) { + if (device.intermediaryBuffer === undefined) { + return; /* This means the device has been uninitialized. */ + } - return getUserMediaResult; - }, pParameters->pDevice->webaudio.audioWorklet, audioContext); + if(device.intermediaryBufferView.length == 0) { + /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */ + device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes); + } - if (attachmentResult != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pParameters->pDevice), MA_LOG_LEVEL_ERROR, "Web Audio: Failed to connect capture node."); - emscripten_destroy_web_audio_node(pParameters->pDevice->webaudio.audioWorklet); - pParameters->pDevice->webaudio.initResult = attachmentResult; - ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); - return; + var outputSilence = false; + + /* Sanity check. This will never happen, right? */ + if (e.outputBuffer.numberOfChannels != channels) { + console.log("Playback: Channel count mismatch. " + e.outputBufer.numberOfChannels + " != " + channels + ". Outputting silence."); + outputSilence = true; + return; + } + + /* This looped design guards against the situation where e.outputBuffer is a different size to the original buffer size. Should never happen in practice. */ + var totalFramesProcessed = 0; + while (totalFramesProcessed < e.outputBuffer.length) { + var framesRemaining = e.outputBuffer.length - totalFramesProcessed; + var framesToProcess = framesRemaining; + if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) { + framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4); + } + + /* Read data from the client into our intermediary buffer. */ + ccall("ma_device_process_pcm_frames_playback__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]); + + /* At this point we'll have data in our intermediary buffer which we now need to deinterleave and copy over to the output buffers. */ + if (outputSilence) { + for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { + e.outputBuffer.getChannelData(iChannel).fill(0.0); + } + } else { + for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { + for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) { + e.outputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame] = device.intermediaryBufferView[iFrame*channels + iChannel]; + } + } + } + + totalFramesProcessed += framesToProcess; + } + }; + + device.scriptNode.connect(device.webaudio.destination); } + + return miniaudio.track_device(device); + }, channels, sampleRate, periodSizeInFrames, deviceType == ma_device_type_capture, pDevice); + + if (deviceIndex < 0) { + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } - /* If it's playback only we can now attach the worklet node to the graph. This has already been done for the duplex case. */ - if (pParameters->pConfig->deviceType == ma_device_type_playback) { - ma_result attachmentResult = (ma_result)EM_ASM_INT({ - var audioWorklet = emscriptenGetAudioObject($0); - var audioContext = emscriptenGetAudioObject($1); - audioWorklet.connect(audioContext.destination); - return 0; /* 0 = MA_SUCCESS */ - }, pParameters->pDevice->webaudio.audioWorklet, audioContext); - - if (attachmentResult != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pParameters->pDevice), MA_LOG_LEVEL_ERROR, "Web Audio: Failed to connect playback node."); - pParameters->pDevice->webaudio.initResult = attachmentResult; - ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); - return; - } + if (deviceType == ma_device_type_capture) { + pDevice->webaudio.indexCapture = deviceIndex; + } else { + pDevice->webaudio.indexPlayback = deviceIndex; } - /* We need to update the descriptors so that they reflect the internal data format. Both capture and playback should be the same. */ - sampleRate = EM_ASM_INT({ return emscriptenGetAudioObject($0).sampleRate; }, audioContext); + pDescriptor->format = ma_format_f32; + pDescriptor->channels = channels; + ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDescriptor->channels, pDescriptor->channelMap); + pDescriptor->sampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); + pDescriptor->periodSizeInFrames = periodSizeInFrames; + pDescriptor->periodCount = 1; - if (pParameters->pDescriptorCapture != NULL) { - pParameters->pDescriptorCapture->format = ma_format_f32; - pParameters->pDescriptorCapture->channels = (ma_uint32)channels; - pParameters->pDescriptorCapture->sampleRate = (ma_uint32)sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pParameters->pDescriptorCapture->channelMap, ma_countof(pParameters->pDescriptorCapture->channelMap), pParameters->pDescriptorCapture->channels); - pParameters->pDescriptorCapture->periodSizeInFrames = intermediaryBufferSizeInFrames; - pParameters->pDescriptorCapture->periodCount = 1; - } - - if (pParameters->pDescriptorPlayback != NULL) { - pParameters->pDescriptorPlayback->format = ma_format_f32; - pParameters->pDescriptorPlayback->channels = (ma_uint32)channels; - pParameters->pDescriptorPlayback->sampleRate = (ma_uint32)sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pParameters->pDescriptorPlayback->channelMap, ma_countof(pParameters->pDescriptorPlayback->channelMap), pParameters->pDescriptorPlayback->channels); - pParameters->pDescriptorPlayback->periodSizeInFrames = intermediaryBufferSizeInFrames; - pParameters->pDescriptorPlayback->periodCount = 1; - } - - /* At this point we're done and we can return. */ - ma_log_postf(ma_device_get_log(pParameters->pDevice), MA_LOG_LEVEL_DEBUG, "AudioWorklets: Created worklet node: %d\n", pParameters->pDevice->webaudio.audioWorklet); - pParameters->pDevice->webaudio.initResult = MA_SUCCESS; - ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); + return MA_SUCCESS; } -static void ma_audio_worklet_thread_initialized__webaudio(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void* pUserData) -{ - ma_audio_worklet_thread_initialized_data* pParameters = (ma_audio_worklet_thread_initialized_data*)pUserData; - WebAudioWorkletProcessorCreateOptions workletProcessorOptions; - - MA_ASSERT(pParameters != NULL); - - if (success == EM_FALSE) { - pParameters->pDevice->webaudio.initResult = MA_ERROR; - return; - } - - MA_ZERO_OBJECT(&workletProcessorOptions); - workletProcessorOptions.name = "miniaudio"; /* I'm not entirely sure what to call this. Does this need to be globally unique, or does it need only be unique for a given AudioContext? */ - - emscripten_create_wasm_audio_worklet_processor_async(audioContext, &workletProcessorOptions, ma_audio_worklet_processor_created__webaudio, pParameters); -} -#endif - static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { + ma_result result; + if (pConfig->deviceType == ma_device_type_loopback) { return MA_DEVICE_TYPE_NOT_SUPPORTED; } @@ -40479,271 +31790,45 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co return MA_SHARE_MODE_NOT_SUPPORTED; } - /* - With AudioWorklets we'll have just a single AudioContext. I'm not sure why I'm not doing this for ScriptProcessorNode so - it might be worthwhile to look into that as well. - */ - #if defined(MA_USE_AUDIO_WORKLETS) - { - EmscriptenWebAudioCreateAttributes audioContextAttributes; - ma_audio_worklet_thread_initialized_data* pInitParameters; - void* pStackBuffer; - - if (pConfig->performanceProfile == ma_performance_profile_conservative) { - audioContextAttributes.latencyHint = MA_WEBAUDIO_LATENCY_HINT_PLAYBACK; - } else { - audioContextAttributes.latencyHint = MA_WEBAUDIO_LATENCY_HINT_INTERACTIVE; + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture); + if (result != MA_SUCCESS) { + return result; } - - /* - In my testing, Firefox does not seem to capture audio data properly if the sample rate is set - to anything other than 48K. This does not seem to be the case for other browsers. For this reason, - if the device type is anything other than playback, we'll leave the sample rate as-is and let the - browser pick the appropriate rate for us. - */ - if (pConfig->deviceType == ma_device_type_playback) { - audioContextAttributes.sampleRate = pDescriptorPlayback->sampleRate; - } else { - audioContextAttributes.sampleRate = 0; - } - - /* It's not clear if this can return an error. None of the tests in the Emscripten repository check for this, so neither am I for now. */ - pDevice->webaudio.audioContext = emscripten_create_audio_context(&audioContextAttributes); - - /* - With the context created we can now create the worklet. We can only have a single worklet per audio - context which means we'll need to craft this appropriately to handle duplex devices correctly. - */ - - /* - We now need to create a worker thread. This is a bit weird because we need to allocate our - own buffer for the thread's stack. The stack needs to be aligned to 16 bytes. I'm going to - allocate this on the heap to keep it simple. - */ - pStackBuffer = ma_aligned_malloc(MA_AUDIO_WORKLETS_THREAD_STACK_SIZE, 16, &pDevice->pContext->allocationCallbacks); - if (pStackBuffer == NULL) { - emscripten_destroy_audio_context(pDevice->webaudio.audioContext); - return MA_OUT_OF_MEMORY; - } - - /* Our thread initialization parameters need to be allocated on the heap so they don't go out of scope. */ - pInitParameters = (ma_audio_worklet_thread_initialized_data*)ma_malloc(sizeof(*pInitParameters), &pDevice->pContext->allocationCallbacks); - if (pInitParameters == NULL) { - ma_free(pStackBuffer, &pDevice->pContext->allocationCallbacks); - emscripten_destroy_audio_context(pDevice->webaudio.audioContext); - return MA_OUT_OF_MEMORY; - } - - pInitParameters->pDevice = pDevice; - pInitParameters->pConfig = pConfig; - pInitParameters->pDescriptorPlayback = pDescriptorPlayback; - pInitParameters->pDescriptorCapture = pDescriptorCapture; - - /* - We need to flag the device as not yet initialized so we can wait on it later. Unfortunately all of - the Emscripten WebAudio stuff is asynchronous. - */ - pDevice->webaudio.initResult = MA_BUSY; - { - emscripten_start_wasm_audio_worklet_thread_async(pDevice->webaudio.audioContext, pStackBuffer, MA_AUDIO_WORKLETS_THREAD_STACK_SIZE, ma_audio_worklet_thread_initialized__webaudio, pInitParameters); - } - while (pDevice->webaudio.initResult == MA_BUSY) { emscripten_sleep(1); } /* We must wait for initialization to complete. We're just spinning here. The emscripten_sleep() call is why we need to build with `-sASYNCIFY`. */ - - /* Initialization is now complete. Descriptors were updated when the worklet was initialized. */ - if (pDevice->webaudio.initResult != MA_SUCCESS) { - ma_free(pStackBuffer, &pDevice->pContext->allocationCallbacks); - emscripten_destroy_audio_context(pDevice->webaudio.audioContext); - return pDevice->webaudio.initResult; - } - - /* We need to add an entry to the miniaudio.devices list on the JS side so we can do some JS/C interop. */ - pDevice->webaudio.deviceIndex = EM_ASM_INT({ - return window.miniaudio.track_device({ - webaudio: emscriptenGetAudioObject($0), - state: 1, /* 1 = ma_device_state_stopped */ - pDevice: $1 - }); - }, pDevice->webaudio.audioContext, pDevice); - - return MA_SUCCESS; } - #else - { - /* ScriptProcessorNode. This path requires us to do almost everything in JS, but we'll do as much as we can in C. */ - ma_uint32 deviceIndex; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_uint32 periodSizeInFrames; - /* The channel count will depend on the device type. If it's a capture, use its, otherwise use the playback side. */ - if (pConfig->deviceType == ma_device_type_capture) { - channels = (pDescriptorCapture->channels > 0) ? pDescriptorCapture->channels : MA_DEFAULT_CHANNELS; - } else { - channels = (pDescriptorPlayback->channels > 0) ? pDescriptorPlayback->channels : MA_DEFAULT_CHANNELS; - } - - /* - When testing in Firefox, I've seen it where capture mode fails if the sample rate is changed to anything other than it's - native rate. For this reason we're leaving the sample rate untouched for capture devices. - */ - if (pConfig->deviceType == ma_device_type_playback) { - sampleRate = pDescriptorPlayback->sampleRate; - } else { - sampleRate = 0; /* Let the browser decide when capturing. */ - } - - /* The period size needs to be a power of 2. */ - if (pConfig->deviceType == ma_device_type_capture) { - periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptorCapture, sampleRate, pConfig->performanceProfile); - } else { - periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptorPlayback, sampleRate, pConfig->performanceProfile); - } - - /* We need an intermediary buffer for doing interleaving and deinterleaving. */ - pDevice->webaudio.pIntermediaryBuffer = (float*)ma_malloc(periodSizeInFrames * channels * sizeof(float), &pDevice->pContext->allocationCallbacks); - if (pDevice->webaudio.pIntermediaryBuffer == NULL) { - return MA_OUT_OF_MEMORY; - } - - deviceIndex = EM_ASM_INT({ - var deviceType = $0; - var channels = $1; - var sampleRate = $2; - var bufferSize = $3; - var pIntermediaryBuffer = $4; - var pDevice = $5; - - if (typeof(window.miniaudio) === 'undefined') { - return -1; /* Context not initialized. */ + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); + if (result != MA_SUCCESS) { + if (pConfig->deviceType == ma_device_type_duplex) { + ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); } - - var device = {}; - - /* First thing we need is an AudioContext. */ - var audioContextOptions = {}; - if (deviceType == window.miniaudio.device_type.playback && sampleRate != 0) { - audioContextOptions.sampleRate = sampleRate; - } - - device.webaudio = new (window.AudioContext || window.webkitAudioContext)(audioContextOptions); - device.webaudio.suspend(); /* The AudioContext must be created in a suspended state. */ - device.state = window.miniaudio.device_state.stopped; - - /* - We need to create a ScriptProcessorNode. The channel situation is the same as the AudioWorklet path in that we - need to specify an output and configure the channel count there. - */ - var channelCountIn = 0; - var channelCountOut = channels; - if (deviceType != window.miniaudio.device_type.playback) { - channelCountIn = channels; - } - - device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, channelCountIn, channelCountOut); - - /* The node processing callback. */ - device.scriptNode.onaudioprocess = function(e) { - if (device.intermediaryBufferView == null || device.intermediaryBufferView.length == 0) { - device.intermediaryBufferView = new Float32Array(HEAPF32.buffer, pIntermediaryBuffer, bufferSize * channels); - } - - /* Do the capture side first. */ - if (deviceType == window.miniaudio.device_type.capture || deviceType == window.miniaudio.device_type.duplex) { - /* The data must be interleaved before being processed miniaudio. */ - for (var iChannel = 0; iChannel < channels; iChannel += 1) { - var inputBuffer = e.inputBuffer.getChannelData(iChannel); - var intermediaryBuffer = device.intermediaryBufferView; - - for (var iFrame = 0; iFrame < bufferSize; iFrame += 1) { - intermediaryBuffer[iFrame*channels + iChannel] = inputBuffer[iFrame]; - } - } - - _ma_device_process_pcm_frames_capture__webaudio(pDevice, bufferSize, pIntermediaryBuffer); - } - - if (deviceType == window.miniaudio.device_type.playback || deviceType == window.miniaudio.device_type.duplex) { - _ma_device_process_pcm_frames_playback__webaudio(pDevice, bufferSize, pIntermediaryBuffer); - - for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { - var outputBuffer = e.outputBuffer.getChannelData(iChannel); - var intermediaryBuffer = device.intermediaryBufferView; - - for (var iFrame = 0; iFrame < bufferSize; iFrame += 1) { - outputBuffer[iFrame] = intermediaryBuffer[iFrame*channels + iChannel]; - } - } - } else { - /* It's a capture-only device. Make sure the output is silenced. */ - for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { - e.outputBuffer.getChannelData(iChannel).fill(0.0); - } - } - }; - - /* Now we need to connect our node to the graph. */ - if (deviceType == window.miniaudio.device_type.capture || deviceType == window.miniaudio.device_type.duplex) { - navigator.mediaDevices.getUserMedia({audio:true, video:false}) - .then(function(stream) { - device.streamNode = device.webaudio.createMediaStreamSource(stream); - device.streamNode.connect(device.scriptNode); - device.scriptNode.connect(device.webaudio.destination); - }) - .catch(function(error) { - console.log("Failed to get user media: " + error); - }); - } - - if (deviceType == window.miniaudio.device_type.playback) { - device.scriptNode.connect(device.webaudio.destination); - } - - device.pDevice = pDevice; - - return window.miniaudio.track_device(device); - }, pConfig->deviceType, channels, sampleRate, periodSizeInFrames, pDevice->webaudio.pIntermediaryBuffer, pDevice); - - if (deviceIndex < 0) { - return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + return result; } - - pDevice->webaudio.deviceIndex = deviceIndex; - - /* Grab the sample rate from the audio context directly. */ - sampleRate = (ma_uint32)EM_ASM_INT({ return window.miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); - - if (pDescriptorCapture != NULL) { - pDescriptorCapture->format = ma_format_f32; - pDescriptorCapture->channels = channels; - pDescriptorCapture->sampleRate = sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); - pDescriptorCapture->periodSizeInFrames = periodSizeInFrames; - pDescriptorCapture->periodCount = 1; - } - - if (pDescriptorPlayback != NULL) { - pDescriptorPlayback->format = ma_format_f32; - pDescriptorPlayback->channels = channels; - pDescriptorPlayback->sampleRate = sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels); - pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames; - pDescriptorPlayback->periodCount = 1; - } - - return MA_SUCCESS; } - #endif + + return MA_SUCCESS; } static ma_result ma_device_start__webaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - EM_ASM({ - var device = window.miniaudio.get_device_by_index($0); - device.webaudio.resume(); - device.state = window.miniaudio.device_state.started; - }, pDevice->webaudio.deviceIndex); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + EM_ASM({ + var device = miniaudio.get_device_by_index($0); + device.webaudio.resume(); + device.state = 2; /* MA_STATE_STARTED */ + }, pDevice->webaudio.indexCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + EM_ASM({ + var device = miniaudio.get_device_by_index($0); + device.webaudio.resume(); + device.state = 2; /* MA_STATE_STARTED */ + }, pDevice->webaudio.indexPlayback); + } return MA_SUCCESS; } @@ -40761,13 +31846,27 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) I read this to mean that "any current context processing blocks" are processed by suspend() - i.e. They they are drained. We therefore shouldn't need to do any kind of explicit draining. */ - EM_ASM({ - var device = window.miniaudio.get_device_by_index($0); - device.webaudio.suspend(); - device.state = window.miniaudio.device_state.stopped; - }, pDevice->webaudio.deviceIndex); - ma_device__on_notification_stopped(pDevice); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + EM_ASM({ + var device = miniaudio.get_device_by_index($0); + device.webaudio.suspend(); + device.state = 1; /* MA_STATE_STOPPED */ + }, pDevice->webaudio.indexCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + EM_ASM({ + var device = miniaudio.get_device_by_index($0); + device.webaudio.suspend(); + device.state = 1; /* MA_STATE_STOPPED */ + }, pDevice->webaudio.indexPlayback); + } + + ma_stop_proc onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); + } return MA_SUCCESS; } @@ -40777,21 +31876,8 @@ static ma_result ma_context_uninit__webaudio(ma_context* pContext) MA_ASSERT(pContext != NULL); MA_ASSERT(pContext->backend == ma_backend_webaudio); - (void)pContext; /* Unused. */ - - /* Remove the global miniaudio object from window if there are no more references to it. */ - EM_ASM({ - if (typeof(window.miniaudio) !== 'undefined') { - miniaudio.unlock_event_types.map(function(event_type) { - document.removeEventListener(event_type, miniaudio.unlock, true); - }); - - window.miniaudio.referenceCount -= 1; - if (window.miniaudio.referenceCount === 0) { - delete window.miniaudio; - } - } - }); + /* Nothing needs to be done here. */ + (void)pContext; return MA_SUCCESS; } @@ -40806,29 +31892,13 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex /* Here is where our global JavaScript object is initialized. */ resultFromJS = EM_ASM_INT({ - if (typeof window === 'undefined' || (window.AudioContext || window.webkitAudioContext) === undefined) { + if ((window.AudioContext || window.webkitAudioContext) === undefined) { return 0; /* Web Audio not supported. */ } - if (typeof(window.miniaudio) === 'undefined') { - window.miniaudio = { - referenceCount: 0 - }; - - /* Device types. */ - window.miniaudio.device_type = {}; - window.miniaudio.device_type.playback = $0; - window.miniaudio.device_type.capture = $1; - window.miniaudio.device_type.duplex = $2; - - /* Device states. */ - window.miniaudio.device_state = {}; - window.miniaudio.device_state.stopped = $3; - window.miniaudio.device_state.started = $4; - - /* Device cache for mapping devices to indexes for JavaScript/C interop. */ - let miniaudio = window.miniaudio; - miniaudio.devices = []; + if (typeof(miniaudio) === 'undefined') { + miniaudio = {}; + miniaudio.devices = []; /* Device cache for mapping devices to indexes for JavaScript/C interop. */ miniaudio.track_device = function(device) { /* Try inserting into a free slot first. */ @@ -40871,21 +31941,14 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex }; miniaudio.unlock_event_types = (function(){ - return ['touchend', 'click']; + return ['touchstart', 'touchend', 'click']; })(); miniaudio.unlock = function() { for(var i = 0; i < miniaudio.devices.length; ++i) { var device = miniaudio.devices[i]; - if (device != null && - device.webaudio != null && - device.state === miniaudio.device_state.started) { - - device.webaudio.resume().then(() => { - _ma_device__on_notification_unlocked(device.pDevice); - }, - (error) => {console.error("Failed to resume audiocontext", error); - }); + if (device != null && device.webaudio != null && device.state === 2 /* MA_STATE_STARTED */) { + device.webaudio.resume(); } } miniaudio.unlock_event_types.map(function(event_type) { @@ -40898,10 +31961,8 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex }); } - window.miniaudio.referenceCount += 1; - return 1; - }, ma_device_type_playback, ma_device_type_capture, ma_device_type_duplex, ma_device_state_stopped, ma_device_state_started); + }, 0); /* Must pass in a dummy argument for C99 compatibility. */ if (resultFromJS != 1) { return MA_FAILED_TO_INIT_BACKEND; @@ -40921,14 +31982,14 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex return MA_SUCCESS; } -#endif /* MA_HAS_WEBAUDIO */ +#endif /* Web Audio */ -static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint32 channels) +static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint32 channels) { /* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */ - if (pChannelMap != NULL && pChannelMap[0] != MA_CHANNEL_NONE) { + if (channelMap[0] != MA_CHANNEL_NONE) { ma_uint32 iChannel; if (channels == 0 || channels > MA_MAX_CHANNELS) { @@ -40939,7 +32000,7 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint for (iChannel = 0; iChannel < channels; ++iChannel) { ma_uint32 jChannel; for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) { - if (pChannelMap[iChannel] == pChannelMap[jChannel]) { + if (channelMap[iChannel] == channelMap[jChannel]) { return MA_FALSE; } } @@ -40950,29 +32011,13 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint } -static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext) -{ - MA_ASSERT(pContext != NULL); - - if (pContext->callbacks.onDeviceRead == NULL && pContext->callbacks.onDeviceWrite == NULL) { - if (pContext->callbacks.onDeviceDataLoop == NULL) { - return MA_TRUE; - } else { - return MA_FALSE; - } - } else { - return MA_FALSE; - } -} - - static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType) { ma_result result; MA_ASSERT(pDevice != NULL); - if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { if (pDevice->capture.format == ma_format_unknown) { pDevice->capture.format = pDevice->capture.internalFormat; } @@ -40985,9 +32030,9 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels); } else { if (pDevice->capture.channelMixMode == ma_channel_mix_mode_simple) { - ma_channel_map_init_blank(pDevice->capture.channelMap, pDevice->capture.channels); + ma_channel_map_init_blank(pDevice->capture.channels, pDevice->capture.channelMap); } else { - ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pDevice->capture.channels); + ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.channels, pDevice->capture.channelMap); } } } @@ -41006,16 +32051,16 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels); } else { if (pDevice->playback.channelMixMode == ma_channel_mix_mode_simple) { - ma_channel_map_init_blank(pDevice->playback.channelMap, pDevice->playback.channels); + ma_channel_map_init_blank(pDevice->playback.channels, pDevice->playback.channelMap); } else { - ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pDevice->playback.channels); + ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.channels, pDevice->playback.channelMap); } } } } if (pDevice->sampleRate == 0) { - if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { pDevice->sampleRate = pDevice->capture.internalSampleRate; } else { pDevice->sampleRate = pDevice->playback.internalSampleRate; @@ -41026,28 +32071,21 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { /* Converting from internal device format to client format. */ ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); - converterConfig.formatIn = pDevice->capture.internalFormat; - converterConfig.channelsIn = pDevice->capture.internalChannels; - converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; - converterConfig.pChannelMapIn = pDevice->capture.internalChannelMap; - converterConfig.formatOut = pDevice->capture.format; - converterConfig.channelsOut = pDevice->capture.channels; - converterConfig.sampleRateOut = pDevice->sampleRate; - converterConfig.pChannelMapOut = pDevice->capture.channelMap; - converterConfig.channelMixMode = pDevice->capture.channelMixMode; - converterConfig.calculateLFEFromSpatialChannels = pDevice->capture.calculateLFEFromSpatialChannels; - converterConfig.allowDynamicSampleRate = MA_FALSE; - converterConfig.resampling.algorithm = pDevice->resampling.algorithm; - converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; - converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable; - converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData; + converterConfig.formatIn = pDevice->capture.internalFormat; + converterConfig.channelsIn = pDevice->capture.internalChannels; + converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; + ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, ma_min(pDevice->capture.internalChannels, MA_MAX_CHANNELS)); + converterConfig.formatOut = pDevice->capture.format; + converterConfig.channelsOut = pDevice->capture.channels; + converterConfig.sampleRateOut = pDevice->sampleRate; + ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS)); + converterConfig.channelMixMode = pDevice->capture.channelMixMode; + converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; + converterConfig.resampling.algorithm = pDevice->resampling.algorithm; + converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; + converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality; - /* Make sure the old converter is uninitialized first. */ - if (ma_device_get_state(pDevice) != ma_device_state_uninitialized) { - ma_data_converter_uninit(&pDevice->capture.converter, &pDevice->pContext->allocationCallbacks); - } - - result = ma_data_converter_init(&converterConfig, &pDevice->pContext->allocationCallbacks, &pDevice->capture.converter); + result = ma_data_converter_init(&converterConfig, &pDevice->capture.converter); if (result != MA_SUCCESS) { return result; } @@ -41056,208 +32094,50 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { /* Converting from client format to device format. */ ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); - converterConfig.formatIn = pDevice->playback.format; - converterConfig.channelsIn = pDevice->playback.channels; - converterConfig.sampleRateIn = pDevice->sampleRate; - converterConfig.pChannelMapIn = pDevice->playback.channelMap; - converterConfig.formatOut = pDevice->playback.internalFormat; - converterConfig.channelsOut = pDevice->playback.internalChannels; - converterConfig.sampleRateOut = pDevice->playback.internalSampleRate; - converterConfig.pChannelMapOut = pDevice->playback.internalChannelMap; - converterConfig.channelMixMode = pDevice->playback.channelMixMode; - converterConfig.calculateLFEFromSpatialChannels = pDevice->playback.calculateLFEFromSpatialChannels; - converterConfig.allowDynamicSampleRate = MA_FALSE; - converterConfig.resampling.algorithm = pDevice->resampling.algorithm; - converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; - converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable; - converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData; + converterConfig.formatIn = pDevice->playback.format; + converterConfig.channelsIn = pDevice->playback.channels; + converterConfig.sampleRateIn = pDevice->sampleRate; + ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, ma_min(pDevice->playback.channels, MA_MAX_CHANNELS)); + converterConfig.formatOut = pDevice->playback.internalFormat; + converterConfig.channelsOut = pDevice->playback.internalChannels; + converterConfig.sampleRateOut = pDevice->playback.internalSampleRate; + ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS)); + converterConfig.channelMixMode = pDevice->playback.channelMixMode; + converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; + converterConfig.resampling.algorithm = pDevice->resampling.algorithm; + converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; + converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality; - /* Make sure the old converter is uninitialized first. */ - if (ma_device_get_state(pDevice) != ma_device_state_uninitialized) { - ma_data_converter_uninit(&pDevice->playback.converter, &pDevice->pContext->allocationCallbacks); - } - - result = ma_data_converter_init(&converterConfig, &pDevice->pContext->allocationCallbacks, &pDevice->playback.converter); + result = ma_data_converter_init(&converterConfig, &pDevice->playback.converter); if (result != MA_SUCCESS) { return result; } } - - /* - If the device is doing playback (ma_device_type_playback or ma_device_type_duplex), there's - a couple of situations where we'll need a heap allocated cache. - - The first is a duplex device for backends that use a callback for data delivery. The reason - this is needed is that the input stage needs to have a buffer to place the input data while it - waits for the playback stage, after which the miniaudio data callback will get fired. This is - not needed for backends that use a blocking API because miniaudio manages temporary buffers on - the stack to achieve this. - - The other situation is when the data converter does not have the ability to query the number - of input frames that are required in order to process a given number of output frames. When - performing data conversion, it's useful if miniaudio know exactly how many frames it needs - from the client in order to generate a given number of output frames. This way, only exactly - the number of frames are needed to be read from the client which means no cache is necessary. - On the other hand, if miniaudio doesn't know how many frames to read, it is forced to read - in fixed sized chunks and then cache any residual unused input frames, those of which will be - processed at a later stage. - */ - if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { - ma_uint64 unused; - - pDevice->playback.inputCacheConsumed = 0; - pDevice->playback.inputCacheRemaining = 0; - - if (pDevice->type == ma_device_type_duplex || /* Duplex. backend may decide to use ma_device_handle_backend_data_callback() which will require this cache. */ - ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, 1, &unused) != MA_SUCCESS) /* Data conversion required input frame calculation not supported. */ - { - /* We need a heap allocated cache. We want to size this based on the period size. */ - void* pNewInputCache; - ma_uint64 newInputCacheCap; - ma_uint64 newInputCacheSizeInBytes; - - newInputCacheCap = ma_calculate_frame_count_after_resampling(pDevice->playback.internalSampleRate, pDevice->sampleRate, pDevice->playback.internalPeriodSizeInFrames); - - newInputCacheSizeInBytes = newInputCacheCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - if (newInputCacheSizeInBytes > MA_SIZE_MAX) { - ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); - pDevice->playback.pInputCache = NULL; - pDevice->playback.inputCacheCap = 0; - return MA_OUT_OF_MEMORY; /* Allocation too big. Should never hit this, but makes the cast below safer for 32-bit builds. */ - } - - pNewInputCache = ma_realloc(pDevice->playback.pInputCache, (size_t)newInputCacheSizeInBytes, &pDevice->pContext->allocationCallbacks); - if (pNewInputCache == NULL) { - ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); - pDevice->playback.pInputCache = NULL; - pDevice->playback.inputCacheCap = 0; - return MA_OUT_OF_MEMORY; - } - - pDevice->playback.pInputCache = pNewInputCache; - pDevice->playback.inputCacheCap = newInputCacheCap; - } else { - /* Heap allocation not required. Make sure we clear out the old cache just in case this function was called in response to a route change. */ - ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); - pDevice->playback.pInputCache = NULL; - pDevice->playback.inputCacheCap = 0; - } - } - return MA_SUCCESS; } -MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pDescriptorPlayback, const ma_device_descriptor* pDescriptorCapture) -{ - ma_result result; - - if (pDevice == NULL) { - return MA_INVALID_ARGS; - } - - /* Capture. */ - if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { - if (ma_device_descriptor_is_valid(pDescriptorCapture) == MA_FALSE) { - return MA_INVALID_ARGS; - } - - pDevice->capture.internalFormat = pDescriptorCapture->format; - pDevice->capture.internalChannels = pDescriptorCapture->channels; - pDevice->capture.internalSampleRate = pDescriptorCapture->sampleRate; - MA_COPY_MEMORY(pDevice->capture.internalChannelMap, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap)); - pDevice->capture.internalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames; - pDevice->capture.internalPeriods = pDescriptorCapture->periodCount; - - if (pDevice->capture.internalPeriodSizeInFrames == 0) { - pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorCapture->periodSizeInMilliseconds, pDescriptorCapture->sampleRate); - } - } - - /* Playback. */ - if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { - if (ma_device_descriptor_is_valid(pDescriptorPlayback) == MA_FALSE) { - return MA_INVALID_ARGS; - } - - pDevice->playback.internalFormat = pDescriptorPlayback->format; - pDevice->playback.internalChannels = pDescriptorPlayback->channels; - pDevice->playback.internalSampleRate = pDescriptorPlayback->sampleRate; - MA_COPY_MEMORY(pDevice->playback.internalChannelMap, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); - pDevice->playback.internalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames; - pDevice->playback.internalPeriods = pDescriptorPlayback->periodCount; - - if (pDevice->playback.internalPeriodSizeInFrames == 0) { - pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorPlayback->periodSizeInMilliseconds, pDescriptorPlayback->sampleRate); - } - } - - /* - The name of the device can be retrieved from device info. This may be temporary and replaced with a `ma_device_get_info(pDevice, deviceType)` instead. - For loopback devices, we need to retrieve the name of the playback device. - */ - { - ma_device_info deviceInfo; - - if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { - result = ma_device_get_info(pDevice, ma_device_type_capture, &deviceInfo); - if (result == MA_SUCCESS) { - ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1); - } else { - /* We failed to retrieve the device info. Fall back to a default name. */ - if (pDescriptorCapture->pDeviceID == NULL) { - ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); - } else { - ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "Capture Device", (size_t)-1); - } - } - } - - if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { - result = ma_device_get_info(pDevice, ma_device_type_playback, &deviceInfo); - if (result == MA_SUCCESS) { - ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1); - } else { - /* We failed to retrieve the device info. Fall back to a default name. */ - if (pDescriptorPlayback->pDeviceID == NULL) { - ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); - } else { - ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "Playback Device", (size_t)-1); - } - } - } - } - - /* Update data conversion. */ - return ma_device__post_init_setup(pDevice, deviceType); /* TODO: Should probably rename ma_device__post_init_setup() to something better. */ -} - static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { ma_device* pDevice = (ma_device*)pData; -#ifdef MA_WIN32 - HRESULT CoInitializeResult; -#endif - MA_ASSERT(pDevice != NULL); #ifdef MA_WIN32 - CoInitializeResult = ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); + ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); #endif /* - When the device is being initialized its initial state is set to ma_device_state_uninitialized. Before returning from + When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker thread to signal an event to know when the worker thread is ready for action. */ - ma_device__set_state(pDevice, ma_device_state_stopped); + ma_device__set_state(pDevice, MA_STATE_STOPPED); ma_event_signal(&pDevice->stopEvent); for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */ - ma_result startResult; - ma_result stopResult; /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the stopped notification callback. */ + ma_stop_proc onStop; /* We wait on an event to know when something has requested that the device be started and the main loop entered. */ ma_event_wait(&pDevice->wakeupEvent); @@ -41266,7 +32146,7 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) pDevice->workResult = MA_SUCCESS; /* If the reason for the wake up is that we are terminating, just break from the loop. */ - if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { + if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) { break; } @@ -41275,31 +32155,20 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event in both the success and error case. It's important that the state of the device is set _before_ signaling the event. */ - MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_starting); + MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STARTING); /* If the device has a start callback, start it now. */ if (pDevice->pContext->callbacks.onDeviceStart != NULL) { - startResult = pDevice->pContext->callbacks.onDeviceStart(pDevice); - } else { - startResult = MA_SUCCESS; - } - - /* - If starting was not successful we'll need to loop back to the start and wait for something - to happen (pDevice->wakeupEvent). - */ - if (startResult != MA_SUCCESS) { - pDevice->workResult = startResult; - ma_event_signal(&pDevice->startEvent); /* <-- Always signal the start event so ma_device_start() can return as it'll be waiting on it. */ - continue; + ma_result result = pDevice->pContext->callbacks.onDeviceStart(pDevice); + if (result != MA_SUCCESS) { + pDevice->workResult = result; /* Failed to start the device. */ + } } /* Make sure the state is set appropriately. */ - ma_device__set_state(pDevice, ma_device_state_started); /* <-- Set this before signaling the event so that the state is always guaranteed to be good after ma_device_start() has returned. */ + ma_device__set_state(pDevice, MA_STATE_STARTED); ma_event_signal(&pDevice->startEvent); - ma_device__on_notification_started(pDevice); - if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) { pDevice->pContext->callbacks.onDeviceDataLoop(pDevice); } else { @@ -41307,36 +32176,39 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ma_device_audio_thread__default_read_write(pDevice); } - /* Getting here means we have broken from the main loop which happens the application has requested that device be stopped. */ - if (pDevice->pContext->callbacks.onDeviceStop != NULL) { - stopResult = pDevice->pContext->callbacks.onDeviceStop(pDevice); - } else { - stopResult = MA_SUCCESS; /* No stop callback with the backend. Just assume successful. */ + /* + Getting here means we have broken from the main loop which happens the application has requested that device be stopped. Note that this + may have actually already happened above if the device was lost and miniaudio has attempted to re-initialize the device. In this case we + don't want to be doing this a second time. + */ + if (ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED) { + if (pDevice->pContext->callbacks.onDeviceStop != NULL) { + pDevice->pContext->callbacks.onDeviceStop(pDevice); + } + } + + /* After the device has stopped, make sure an event is posted. */ + onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); } /* - After the device has stopped, make sure an event is posted. Don't post a stopped event if - stopping failed. This can happen on some backends when the underlying stream has been - stopped due to the device being physically unplugged or disabled via an OS setting. + A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. Note that + it's possible that the device has been uninitialized which means we need to _not_ change the status to stopped. We cannot go from an + uninitialized state to stopped state. */ - if (stopResult == MA_SUCCESS) { - ma_device__on_notification_stopped(pDevice); + if (ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED) { + ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_event_signal(&pDevice->stopEvent); } - - /* If we stopped because the device has been uninitialized, abort now. */ - if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { - break; - } - - /* A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. */ - ma_device__set_state(pDevice, ma_device_state_stopped); - ma_event_signal(&pDevice->stopEvent); } + /* Make sure we aren't continuously waiting on a stop event. */ + ma_event_signal(&pDevice->stopEvent); /* <-- Is this still needed? */ + #ifdef MA_WIN32 - if (CoInitializeResult == S_OK) { - ma_CoUninitialize(pDevice->pContext); - } + ma_CoUninitialize(pDevice->pContext); #endif return (ma_thread_result)0; @@ -41350,88 +32222,130 @@ static ma_bool32 ma_device__is_initialized(ma_device* pDevice) return MA_FALSE; } - return ma_device_get_state(pDevice) != ma_device_state_uninitialized; + return ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED; } #ifdef MA_WIN32 static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { - /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - if (pContext->win32.CoInitializeResult == S_OK) { - ma_CoUninitialize(pContext); - } - - #if defined(MA_WIN32_DESKTOP) - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); - #endif - - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); -#else - (void)pContext; -#endif + ma_CoUninitialize(pContext); + ma_dlclose(pContext, pContext->win32.hUser32DLL); + ma_dlclose(pContext, pContext->win32.hOle32DLL); + ma_dlclose(pContext, pContext->win32.hAdvapi32DLL); return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - #if defined(MA_WIN32_DESKTOP) - /* User32.dll */ - pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); - if (pContext->win32.hUser32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); - - - /* Advapi32.dll */ - pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); - if (pContext->win32.hAdvapi32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); - pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); - pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); - #endif - +#ifdef MA_WIN32_DESKTOP /* Ole32.dll */ - pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); + pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll"); if (pContext->win32.hOle32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); - pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); - pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); -#else - (void)pContext; /* Unused. */ + pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear"); + pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2"); + + + /* User32.dll */ + pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll"); + if (pContext->win32.hUser32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow"); + + + /* Advapi32.dll */ + pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll"); + if (pContext->win32.hAdvapi32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); + pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey"); + pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); #endif - pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); return MA_SUCCESS; } #else static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext) { +#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) + ma_dlclose(pContext, pContext->posix.pthreadSO); +#else (void)pContext; +#endif return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__nix(ma_context* pContext) { - (void)pContext; + /* pthread */ +#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) + const char* libpthreadFileNames[] = { + "libpthread.so", + "libpthread.so.0", + "libpthread.dylib" + }; + size_t i; + + for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { + pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]); + if (pContext->posix.pthreadSO != NULL) { + break; + } + } + + if (pContext->posix.pthreadSO == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create"); + pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join"); + pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init"); + pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy"); + pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock"); + pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock"); + pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init"); + pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy"); + pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait"); + pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal"); + pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init"); + pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy"); + pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy"); + pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam"); + pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam"); +#else + pContext->posix.pthread_create = (ma_proc)pthread_create; + pContext->posix.pthread_join = (ma_proc)pthread_join; + pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init; + pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy; + pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock; + pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock; + pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init; + pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy; + pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait; + pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal; + pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init; + pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy; +#if !defined(__EMSCRIPTEN__) + pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy; + pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam; + pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam; +#endif +#endif return MA_SUCCESS; } @@ -41462,156 +32376,23 @@ static ma_result ma_context_uninit_backend_apis(ma_context* pContext) } -/* The default capacity doesn't need to be too big. */ -#ifndef MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY -#define MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY 32 -#endif - -MA_API ma_device_job_thread_config ma_device_job_thread_config_init(void) +static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext) { - ma_device_job_thread_config config; + MA_ASSERT(pContext != NULL); - MA_ZERO_OBJECT(&config); - config.noThread = MA_FALSE; - config.jobQueueCapacity = MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY; - config.jobQueueFlags = 0; - - return config; -} - - -static ma_thread_result MA_THREADCALL ma_device_job_thread_entry(void* pUserData) -{ - ma_device_job_thread* pJobThread = (ma_device_job_thread*)pUserData; - MA_ASSERT(pJobThread != NULL); - - for (;;) { - ma_result result; - ma_job job; - - result = ma_device_job_thread_next(pJobThread, &job); - if (result != MA_SUCCESS) { - break; - } - - if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) { - break; - } - - ma_job_process(&job); - } - - return (ma_thread_result)0; -} - -MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_job_thread* pJobThread) -{ - ma_result result; - ma_job_queue_config jobQueueConfig; - - if (pJobThread == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pJobThread); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - - /* Initialize the job queue before the thread to ensure it's in a valid state. */ - jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity); - - result = ma_job_queue_init(&jobQueueConfig, pAllocationCallbacks, &pJobThread->jobQueue); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize job queue. */ - } - - - /* The thread needs to be initialized after the job queue to ensure the thread doesn't try to access it prematurely. */ - if (pConfig->noThread == MA_FALSE) { - result = ma_thread_create(&pJobThread->thread, ma_thread_priority_normal, 0, ma_device_job_thread_entry, pJobThread, pAllocationCallbacks); - if (result != MA_SUCCESS) { - ma_job_queue_uninit(&pJobThread->jobQueue, pAllocationCallbacks); - return result; /* Failed to create the job thread. */ - } - - pJobThread->_hasThread = MA_TRUE; - } else { - pJobThread->_hasThread = MA_FALSE; - } - - - return MA_SUCCESS; -} - -MA_API void ma_device_job_thread_uninit(ma_device_job_thread* pJobThread, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pJobThread == NULL) { - return; - } - - /* The first thing to do is post a quit message to the job queue. If we're using a thread we'll need to wait for it. */ - { - ma_job job = ma_job_init(MA_JOB_TYPE_QUIT); - ma_device_job_thread_post(pJobThread, &job); - } - - /* Wait for the thread to terminate naturally. */ - if (pJobThread->_hasThread) { - ma_thread_wait(&pJobThread->thread); - } - - /* At this point the thread should be terminated so we can safely uninitialize the job queue. */ - ma_job_queue_uninit(&pJobThread->jobQueue, pAllocationCallbacks); -} - -MA_API ma_result ma_device_job_thread_post(ma_device_job_thread* pJobThread, const ma_job* pJob) -{ - if (pJobThread == NULL || pJob == NULL) { - return MA_INVALID_ARGS; - } - - return ma_job_queue_post(&pJobThread->jobQueue, pJob); -} - -MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_job* pJob) -{ - if (pJob == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pJob); - - if (pJobThread == NULL) { - return MA_INVALID_ARGS; - } - - return ma_job_queue_next(&pJobThread->jobQueue, pJob); -} - - -MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id* pB) -{ - size_t i; - - if (pA == NULL || pB == NULL) { - return MA_FALSE; - } - - for (i = 0; i < sizeof(ma_device_id); i += 1) { - if (((const char*)pA)[i] != ((const char*)pB)[i]) { + if (pContext->callbacks.onDeviceRead == NULL && pContext->callbacks.onDeviceWrite == NULL) { + if (pContext->callbacks.onDeviceDataLoop == NULL) { + return MA_TRUE; + } else { return MA_FALSE; } + } else { + return MA_FALSE; } - - return MA_TRUE; } - -MA_API ma_context_config ma_context_config_init(void) +MA_API ma_context_config ma_context_config_init() { ma_context_config config; MA_ZERO_OBJECT(&config); @@ -41640,28 +32421,16 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC pConfig = &defaultConfig; } - /* Allocation callbacks need to come first because they'll be passed around to other areas. */ + pContext->logCallback = pConfig->logCallback; + pContext->threadPriority = pConfig->threadPriority; + pContext->threadStackSize = pConfig->threadStackSize; + pContext->pUserData = pConfig->pUserData; + result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &pConfig->allocationCallbacks); if (result != MA_SUCCESS) { return result; } - /* Get a lot set up first so we can start logging ASAP. */ - if (pConfig->pLog != NULL) { - pContext->pLog = pConfig->pLog; - } else { - result = ma_log_init(&pContext->allocationCallbacks, &pContext->log); - if (result == MA_SUCCESS) { - pContext->pLog = &pContext->log; - } else { - pContext->pLog = NULL; /* Logging is not available. */ - } - } - - pContext->threadPriority = pConfig->threadPriority; - pContext->threadStackSize = pConfig->threadStackSize; - pContext->pUserData = pConfig->pUserData; - /* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */ result = ma_context_init_backend_apis(pContext); if (result != MA_SUCCESS) { @@ -41752,17 +32521,13 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC #ifdef MA_HAS_AAUDIO case ma_backend_aaudio: { - if (ma_is_backend_enabled(backend)) { - pContext->callbacks.onContextInit = ma_context_init__aaudio; - } + pContext->callbacks.onContextInit = ma_context_init__aaudio; } break; #endif #ifdef MA_HAS_OPENSL case ma_backend_opensl: { - if (ma_is_backend_enabled(backend)) { - pContext->callbacks.onContextInit = ma_context_init__opensl; - } + pContext->callbacks.onContextInit = ma_context_init__opensl; } break; #endif #ifdef MA_HAS_WEBAUDIO @@ -41789,47 +32554,38 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC } if (pContext->callbacks.onContextInit != NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend)); + ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_VERBOSE, "Attempting to initialize %s backend...", ma_get_backend_name(backend)); result = pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks); } else { - /* Getting here means the onContextInit callback is not set which means the backend is not enabled. Special case for the custom backend. */ - if (backend != ma_backend_custom) { - result = MA_BACKEND_NOT_ENABLED; - } else { - #if !defined(MA_HAS_CUSTOM) - result = MA_BACKEND_NOT_ENABLED; - #else - result = MA_NO_BACKEND; - #endif - } + result = MA_NO_BACKEND; } /* If this iteration was successful, return. */ if (result == MA_SUCCESS) { result = ma_mutex_init(&pContext->deviceEnumLock); if (result != MA_SUCCESS) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.\n"); + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.", result); } result = ma_mutex_init(&pContext->deviceInfoLock); if (result != MA_SUCCESS) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n"); + ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.", result); } - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "System Architecture:\n"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " Endian: %s\n", ma_is_little_endian() ? "LE" : "BE"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " SSE2: %s\n", ma_has_sse2() ? "YES" : "NO"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " AVX2: %s\n", ma_has_avx2() ? "YES" : "NO"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " NEON: %s\n", ma_has_neon() ? "YES" : "NO"); + #ifdef MA_DEBUG_OUTPUT + { + printf("[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE"); + printf("[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO"); + printf("[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO"); + printf("[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO"); + printf("[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO"); + } + #endif pContext->backend = backend; return result; } else { - if (result == MA_BACKEND_NOT_ENABLED) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "%s backend is disabled.\n", ma_get_backend_name(backend)); - } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Failed to initialize %s backend.\n", ma_get_backend_name(backend)); - } + ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_VERBOSE, "Failed to initialize %s backend.", ma_get_backend_name(backend)); } } @@ -41850,32 +32606,18 @@ MA_API ma_result ma_context_uninit(ma_context* pContext) ma_mutex_uninit(&pContext->deviceEnumLock); ma_mutex_uninit(&pContext->deviceInfoLock); - ma_free(pContext->pDeviceInfos, &pContext->allocationCallbacks); + ma__free_from_callbacks(pContext->pDeviceInfos, &pContext->allocationCallbacks); ma_context_uninit_backend_apis(pContext); - if (pContext->pLog == &pContext->log) { - ma_log_uninit(&pContext->log); - } - return MA_SUCCESS; } -MA_API size_t ma_context_sizeof(void) +MA_API size_t ma_context_sizeof() { return sizeof(ma_context); } -MA_API ma_log* ma_context_get_log(ma_context* pContext) -{ - if (pContext == NULL) { - return NULL; - } - - return pContext->pLog; -} - - MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_result result; @@ -41913,8 +32655,9 @@ static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_ const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount; if (totalDeviceInfoCount >= pContext->deviceInfoCapacity) { - ma_uint32 newCapacity = pContext->deviceInfoCapacity + bufferExpansionCount; - ma_device_info* pNewInfos = (ma_device_info*)ma_realloc(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, &pContext->allocationCallbacks); + ma_uint32 oldCapacity = pContext->deviceInfoCapacity; + ma_uint32 newCapacity = oldCapacity + bufferExpansionCount; + ma_device_info* pNewInfos = (ma_device_info*)ma__realloc_from_callbacks(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, sizeof(*pContext->pDeviceInfos)*oldCapacity, &pContext->allocationCallbacks); if (pNewInfos == NULL) { return MA_FALSE; /* Out of memory. */ } @@ -41984,12 +32727,7 @@ MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** p /* Capture devices. */ if (ppCaptureDeviceInfos != NULL) { - *ppCaptureDeviceInfos = pContext->pDeviceInfos; - /* Capture devices come after playback devices. */ - if (pContext->playbackDeviceInfoCount > 0) { - /* Conditional, because NULL+0 is undefined behavior. */ - *ppCaptureDeviceInfos += pContext->playbackDeviceInfoCount; - } + *ppCaptureDeviceInfos = pContext->pDeviceInfos + pContext->playbackDeviceInfoCount; /* Capture devices come after playback devices. */ } if (pCaptureDeviceCount != NULL) { *pCaptureDeviceCount = pContext->captureDeviceInfoCount; @@ -42001,11 +32739,13 @@ MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** p return result; } -MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_result result; ma_device_info deviceInfo; + (void)shareMode; /* Unused. This parameter will be removed in version 0.11. */ + /* NOTE: Do not clear pDeviceInfo on entry. The reason is the pDeviceID may actually point to pDeviceInfo->id which will break things. */ if (pContext == NULL || pDeviceInfo == NULL) { return MA_INVALID_ARGS; @@ -42028,6 +32768,81 @@ MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type } ma_mutex_unlock(&pContext->deviceInfoLock); + /* + If the backend is using the new device info system, do a pass to fill out the old settings for backwards compatibility. This will be removed in + the future when all backends have implemented the new device info system. + */ + if (deviceInfo.nativeDataFormatCount > 0) { + ma_uint32 iNativeFormat; + ma_uint32 iSampleFormat; + + deviceInfo.minChannels = 0xFFFFFFFF; + deviceInfo.maxChannels = 0; + deviceInfo.minSampleRate = 0xFFFFFFFF; + deviceInfo.maxSampleRate = 0; + + for (iNativeFormat = 0; iNativeFormat < deviceInfo.nativeDataFormatCount; iNativeFormat += 1) { + /* Formats. */ + if (deviceInfo.nativeDataFormats[iNativeFormat].format == ma_format_unknown) { + /* All formats are supported. */ + deviceInfo.formats[0] = ma_format_u8; + deviceInfo.formats[1] = ma_format_s16; + deviceInfo.formats[2] = ma_format_s24; + deviceInfo.formats[3] = ma_format_s32; + deviceInfo.formats[4] = ma_format_f32; + deviceInfo.formatCount = 5; + } else { + /* Make sure the format isn't already in the list. If so, skip. */ + ma_bool32 alreadyExists = MA_FALSE; + for (iSampleFormat = 0; iSampleFormat < deviceInfo.formatCount; iSampleFormat += 1) { + if (deviceInfo.formats[iSampleFormat] == deviceInfo.nativeDataFormats[iNativeFormat].format) { + alreadyExists = MA_TRUE; + break; + } + } + + if (!alreadyExists) { + deviceInfo.formats[deviceInfo.formatCount++] = deviceInfo.nativeDataFormats[iNativeFormat].format; + } + } + + /* Channels. */ + if (deviceInfo.nativeDataFormats[iNativeFormat].channels == 0) { + /* All channels supported. */ + deviceInfo.minChannels = MA_MIN_CHANNELS; + deviceInfo.maxChannels = MA_MAX_CHANNELS; + } else { + if (deviceInfo.minChannels > deviceInfo.nativeDataFormats[iNativeFormat].channels) { + deviceInfo.minChannels = deviceInfo.nativeDataFormats[iNativeFormat].channels; + } + if (deviceInfo.maxChannels < deviceInfo.nativeDataFormats[iNativeFormat].channels) { + deviceInfo.maxChannels = deviceInfo.nativeDataFormats[iNativeFormat].channels; + } + } + + /* Sample rate. */ + if (deviceInfo.nativeDataFormats[iNativeFormat].sampleRate == 0) { + /* All sample rates supported. */ + deviceInfo.minSampleRate = (ma_uint32)ma_standard_sample_rate_min; + deviceInfo.maxSampleRate = (ma_uint32)ma_standard_sample_rate_max; + } else { + if (deviceInfo.minSampleRate > deviceInfo.nativeDataFormats[iNativeFormat].sampleRate) { + deviceInfo.minSampleRate = deviceInfo.nativeDataFormats[iNativeFormat].sampleRate; + } + if (deviceInfo.maxSampleRate < deviceInfo.nativeDataFormats[iNativeFormat].sampleRate) { + deviceInfo.maxSampleRate = deviceInfo.nativeDataFormats[iNativeFormat].sampleRate; + } + } + } + } + + + /* Clamp ranges. */ + deviceInfo.minChannels = ma_max(deviceInfo.minChannels, MA_MIN_CHANNELS); + deviceInfo.maxChannels = ma_min(deviceInfo.maxChannels, MA_MAX_CHANNELS); + deviceInfo.minSampleRate = ma_max(deviceInfo.minSampleRate, (ma_uint32)ma_standard_sample_rate_min); + deviceInfo.maxSampleRate = ma_min(deviceInfo.maxSampleRate, (ma_uint32)ma_standard_sample_rate_max); + *pDeviceInfo = deviceInfo; return result; } @@ -42047,7 +32862,11 @@ MA_API ma_device_config ma_device_config_init(ma_device_type deviceType) ma_device_config config; MA_ZERO_OBJECT(&config); config.deviceType = deviceType; - config.resampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate don't matter here. */ + + /* Resampling defaults. We must never use the Speex backend by default because it uses licensed third party code. */ + config.resampling.algorithm = ma_resample_algorithm_linear; + config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); + config.resampling.speex.quality = 3; return config; } @@ -42064,93 +32883,92 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } if (pDevice == NULL) { - return MA_INVALID_ARGS; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); } MA_ZERO_OBJECT(pDevice); if (pConfig == NULL) { - return MA_INVALID_ARGS; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pConfig == NULL).", MA_INVALID_ARGS); } + /* Check that we have our callbacks defined. */ if (pContext->callbacks.onDeviceInit == NULL) { return MA_INVALID_OPERATION; } + /* Basic config validation. */ + if (pConfig->deviceType != ma_device_type_playback && pConfig->deviceType != ma_device_type_capture && pConfig->deviceType != ma_device_type_duplex && pConfig->deviceType != ma_device_type_loopback) { + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Device type is invalid. Make sure the device type has been set in the config.", MA_INVALID_DEVICE_CONFIG); + } + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->capture.channels > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Capture channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG); } - - if (!ma__is_channel_map_valid(pConfig->capture.pChannelMap, pConfig->capture.channels)) { - return MA_INVALID_ARGS; + if (!ma__is_channel_map_valid(pConfig->capture.channelMap, pConfig->capture.channels)) { + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Capture channel map is invalid.", MA_INVALID_DEVICE_CONFIG); } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { if (pConfig->playback.channels > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Playback channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG); } - - if (!ma__is_channel_map_valid(pConfig->playback.pChannelMap, pConfig->playback.channels)) { - return MA_INVALID_ARGS; + if (!ma__is_channel_map_valid(pConfig->playback.channelMap, pConfig->playback.channels)) { + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Playback channel map is invalid.", MA_INVALID_DEVICE_CONFIG); } } pDevice->pContext = pContext; /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */ - pDevice->pUserData = pConfig->pUserData; - pDevice->onData = pConfig->dataCallback; - pDevice->onNotification = pConfig->notificationCallback; - pDevice->onStop = pConfig->stopCallback; + pDevice->pUserData = pConfig->pUserData; + pDevice->onData = pConfig->dataCallback; + pDevice->onStop = pConfig->stopCallback; + + if (((ma_uintptr)pDevice % sizeof(pDevice)) != 0) { + if (pContext->logCallback) { + pContext->logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported."); + } + } if (pConfig->playback.pDeviceID != NULL) { MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id)); - pDevice->playback.pID = &pDevice->playback.id; - } else { - pDevice->playback.pID = NULL; } if (pConfig->capture.pDeviceID != NULL) { MA_COPY_MEMORY(&pDevice->capture.id, pConfig->capture.pDeviceID, sizeof(pDevice->capture.id)); - pDevice->capture.pID = &pDevice->capture.id; - } else { - pDevice->capture.pID = NULL; } - pDevice->noPreSilencedOutputBuffer = pConfig->noPreSilencedOutputBuffer; - pDevice->noClip = pConfig->noClip; - pDevice->noDisableDenormals = pConfig->noDisableDenormals; - pDevice->noFixedSizedCallback = pConfig->noFixedSizedCallback; - ma_atomic_float_set(&pDevice->masterVolumeFactor, 1); + pDevice->noPreZeroedOutputBuffer = pConfig->noPreZeroedOutputBuffer; + pDevice->noClip = pConfig->noClip; + pDevice->masterVolumeFactor = 1; - pDevice->type = pConfig->deviceType; - pDevice->sampleRate = pConfig->sampleRate; - pDevice->resampling.algorithm = pConfig->resampling.algorithm; - pDevice->resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder; - pDevice->resampling.pBackendVTable = pConfig->resampling.pBackendVTable; - pDevice->resampling.pBackendUserData = pConfig->resampling.pBackendUserData; + pDevice->type = pConfig->deviceType; + pDevice->sampleRate = pConfig->sampleRate; + pDevice->resampling.algorithm = pConfig->resampling.algorithm; + pDevice->resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder; + pDevice->resampling.speex.quality = pConfig->resampling.speex.quality; - pDevice->capture.shareMode = pConfig->capture.shareMode; - pDevice->capture.format = pConfig->capture.format; - pDevice->capture.channels = pConfig->capture.channels; - ma_channel_map_copy_or_default(pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pConfig->capture.pChannelMap, pConfig->capture.channels); - pDevice->capture.channelMixMode = pConfig->capture.channelMixMode; - pDevice->capture.calculateLFEFromSpatialChannels = pConfig->capture.calculateLFEFromSpatialChannels; - - pDevice->playback.shareMode = pConfig->playback.shareMode; - pDevice->playback.format = pConfig->playback.format; - pDevice->playback.channels = pConfig->playback.channels; - ma_channel_map_copy_or_default(pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels); - pDevice->playback.channelMixMode = pConfig->playback.channelMixMode; - pDevice->playback.calculateLFEFromSpatialChannels = pConfig->playback.calculateLFEFromSpatialChannels; + pDevice->capture.shareMode = pConfig->capture.shareMode; + pDevice->capture.format = pConfig->capture.format; + pDevice->capture.channels = pConfig->capture.channels; + ma_channel_map_copy(pDevice->capture.channelMap, pConfig->capture.channelMap, pConfig->capture.channels); + pDevice->capture.channelMixMode = pConfig->capture.channelMixMode; + + pDevice->playback.shareMode = pConfig->playback.shareMode; + pDevice->playback.format = pConfig->playback.format; + pDevice->playback.channels = pConfig->playback.channels; + ma_channel_map_copy(pDevice->playback.channelMap, pConfig->playback.channelMap, pConfig->playback.channels); + pDevice->playback.channelMixMode = pConfig->playback.channelMixMode; + result = ma_mutex_init(&pDevice->startStopLock); if (result != MA_SUCCESS) { - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result); } /* @@ -42163,14 +32981,14 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC result = ma_event_init(&pDevice->wakeupEvent); if (result != MA_SUCCESS) { ma_mutex_uninit(&pDevice->startStopLock); - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result); } result = ma_event_init(&pDevice->startEvent); if (result != MA_SUCCESS) { ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->startStopLock); - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result); } result = ma_event_init(&pDevice->stopEvent); @@ -42178,7 +32996,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_event_uninit(&pDevice->startEvent); ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->startStopLock); - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result); } @@ -42188,7 +33006,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC descriptorPlayback.format = pConfig->playback.format; descriptorPlayback.channels = pConfig->playback.channels; descriptorPlayback.sampleRate = pConfig->sampleRate; - ma_channel_map_copy_or_default(descriptorPlayback.channelMap, ma_countof(descriptorPlayback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels); + ma_channel_map_copy(descriptorPlayback.channelMap, pConfig->playback.channelMap, pConfig->playback.channels); descriptorPlayback.periodSizeInFrames = pConfig->periodSizeInFrames; descriptorPlayback.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; descriptorPlayback.periodCount = pConfig->periods; @@ -42204,7 +33022,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC descriptorCapture.format = pConfig->capture.format; descriptorCapture.channels = pConfig->capture.channels; descriptorCapture.sampleRate = pConfig->sampleRate; - ma_channel_map_copy_or_default(descriptorCapture.channelMap, ma_countof(descriptorCapture.channelMap), pConfig->capture.pChannelMap, pConfig->capture.channels); + ma_channel_map_copy(descriptorCapture.channelMap, pConfig->capture.channelMap, pConfig->capture.channels); descriptorCapture.periodSizeInFrames = pConfig->periodSizeInFrames; descriptorCapture.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; descriptorCapture.periodCount = pConfig->periods; @@ -42222,7 +33040,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC return result; } -#if 0 + /* On output the descriptors will contain the *actual* data format of the device. We need this to know how to convert the data between the requested format and the internal format. @@ -42272,7 +33090,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_device_info deviceInfo; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { - result = ma_device_get_info(pDevice, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, &deviceInfo); + result = ma_context_get_device_info(pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, descriptorCapture.pDeviceID, descriptorCapture.shareMode, &deviceInfo); if (result == MA_SUCCESS) { ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1); } else { @@ -42286,7 +33104,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - result = ma_device_get_info(pDevice, ma_device_type_playback, &deviceInfo); + result = ma_context_get_device_info(pContext, ma_device_type_playback, descriptorPlayback.pDeviceID, descriptorPlayback.shareMode, &deviceInfo); if (result == MA_SUCCESS) { ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1); } else { @@ -42302,90 +33120,20 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_device__post_init_setup(pDevice, pConfig->deviceType); -#endif - - result = ma_device_post_init(pDevice, pConfig->deviceType, &descriptorPlayback, &descriptorCapture); - if (result != MA_SUCCESS) { - ma_device_uninit(pDevice); - return result; - } - - - /* - If we're using fixed sized callbacks we'll need to make use of an intermediary buffer. Needs to - be done after post_init_setup() because we'll need access to the sample rate. - */ - if (pConfig->noFixedSizedCallback == MA_FALSE) { - /* We're using a fixed sized data callback so we'll need an intermediary buffer. */ - ma_uint32 intermediaryBufferCap = pConfig->periodSizeInFrames; - if (intermediaryBufferCap == 0) { - intermediaryBufferCap = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pDevice->sampleRate); - } - - if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { - ma_uint32 intermediaryBufferSizeInBytes; - - pDevice->capture.intermediaryBufferLen = 0; - pDevice->capture.intermediaryBufferCap = intermediaryBufferCap; - if (pDevice->capture.intermediaryBufferCap == 0) { - pDevice->capture.intermediaryBufferCap = pDevice->capture.internalPeriodSizeInFrames; - } - - intermediaryBufferSizeInBytes = pDevice->capture.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - - pDevice->capture.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks); - if (pDevice->capture.pIntermediaryBuffer == NULL) { - ma_device_uninit(pDevice); - return MA_OUT_OF_MEMORY; - } - - /* Silence the buffer for safety. */ - ma_silence_pcm_frames(pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap, pDevice->capture.format, pDevice->capture.channels); - pDevice->capture.intermediaryBufferLen = pDevice->capture.intermediaryBufferCap; - } - - if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - ma_uint64 intermediaryBufferSizeInBytes; - - pDevice->playback.intermediaryBufferLen = 0; - if (pConfig->deviceType == ma_device_type_duplex) { - pDevice->playback.intermediaryBufferCap = pDevice->capture.intermediaryBufferCap; /* In duplex mode, make sure the intermediary buffer is always the same size as the capture side. */ - } else { - pDevice->playback.intermediaryBufferCap = intermediaryBufferCap; - if (pDevice->playback.intermediaryBufferCap == 0) { - pDevice->playback.intermediaryBufferCap = pDevice->playback.internalPeriodSizeInFrames; - } - } - - intermediaryBufferSizeInBytes = pDevice->playback.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - pDevice->playback.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks); - if (pDevice->playback.pIntermediaryBuffer == NULL) { - ma_device_uninit(pDevice); - return MA_OUT_OF_MEMORY; - } - - /* Silence the buffer for safety. */ - ma_silence_pcm_frames(pDevice->playback.pIntermediaryBuffer, pDevice->playback.intermediaryBufferCap, pDevice->playback.format, pDevice->playback.channels); - pDevice->playback.intermediaryBufferLen = 0; - } - } else { - /* Not using a fixed sized data callback so no need for an intermediary buffer. */ - } /* Some backends don't require the worker thread. */ if (!ma_context_is_backend_asynchronous(pContext)) { /* The worker thread. */ - result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice, &pContext->allocationCallbacks); + result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice); if (result != MA_SUCCESS) { ma_device_uninit(pDevice); - return result; + return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result); } - /* Wait for the worker thread to put the device into its stopped state for real. */ + /* Wait for the worker thread to put the device into it's stopped state for real. */ ma_event_wait(&pDevice->stopEvent); - MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); + MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED); } else { /* If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done @@ -42401,63 +33149,39 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } } - ma_device__set_state(pDevice, ma_device_state_stopped); + ma_device__set_state(pDevice, MA_STATE_STOPPED); } - /* Log device information. */ - { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { - char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; - ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Capture"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); - { - char channelMapStr[1024]; - ma_channel_map_to_string(pDevice->capture.internalChannelMap, pDevice->capture.internalChannels, channelMapStr, sizeof(channelMapStr)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}\n", channelMapStr); - - ma_channel_map_to_string(pDevice->capture.channelMap, pDevice->capture.channels, channelMapStr, sizeof(channelMapStr)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}\n", channelMapStr); - } - } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; - ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL); - - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Playback"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); - { - char channelMapStr[1024]; - ma_channel_map_to_string(pDevice->playback.channelMap, pDevice->playback.channels, channelMapStr, sizeof(channelMapStr)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}\n", channelMapStr); - - ma_channel_map_to_string(pDevice->playback.internalChannelMap, pDevice->playback.internalChannels, channelMapStr, sizeof(channelMapStr)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}\n", channelMapStr); - } - } + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "[%s]", ma_get_backend_name(pDevice->pContext->backend)); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " %s (%s)", pDevice->capture.name, "Capture"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Format: %s -> %s", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channels: %d -> %d", pDevice->capture.internalChannels, pDevice->capture.channels); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d", pDevice->capture.internalSampleRate, pDevice->sampleRate); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods)); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Conversion:"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Post Format Conversion: %s", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channel Routing: %s", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->capture.converter.hasResampler ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); + } + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " %s (%s)", pDevice->playback.name, "Playback"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Format: %s -> %s", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channels: %d -> %d", pDevice->playback.channels, pDevice->playback.internalChannels); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d", pDevice->sampleRate, pDevice->playback.internalSampleRate); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods)); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Conversion:"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Post Format Conversion: %s", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channel Routing: %s", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->playback.converter.hasResampler ? "YES" : "NO"); + ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); } - MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); + MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED); return MA_SUCCESS; } @@ -42484,7 +33208,8 @@ MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backen allocationCallbacks = ma_allocation_callbacks_init_default(); } - pContext = (ma_context*)ma_malloc(sizeof(*pContext), &allocationCallbacks); + + pContext = (ma_context*)ma__malloc_from_callbacks(sizeof(*pContext), &allocationCallbacks); if (pContext == NULL) { return MA_OUT_OF_MEMORY; } @@ -42503,33 +33228,6 @@ MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backen result = MA_NO_BACKEND; for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) { - /* - This is a hack for iOS. If the context config is null, there's a good chance the - `ma_device_init(NULL, &deviceConfig, pDevice);` pattern is being used. In this - case, set the session category based on the device type. - */ - #if defined(MA_APPLE_MOBILE) - ma_context_config contextConfig; - - if (pContextConfig == NULL) { - contextConfig = ma_context_config_init(); - switch (pConfig->deviceType) { - case ma_device_type_duplex: { - contextConfig.coreaudio.sessionCategory = ma_ios_session_category_play_and_record; - } break; - case ma_device_type_capture: { - contextConfig.coreaudio.sessionCategory = ma_ios_session_category_record; - } break; - case ma_device_type_playback: - default: { - contextConfig.coreaudio.sessionCategory = ma_ios_session_category_playback; - } break; - } - - pContextConfig = &contextConfig; - } - #endif - result = ma_context_init(&pBackendsToIterate[iBackend], 1, pContextConfig, pContext); if (result == MA_SUCCESS) { result = ma_device_init(pContext, pConfig, pDevice); @@ -42542,7 +33240,7 @@ MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backen } if (result != MA_SUCCESS) { - ma_free(pContext, &allocationCallbacks); + ma__free_from_callbacks(pContext, &allocationCallbacks); return result; } @@ -42556,26 +33254,13 @@ MA_API void ma_device_uninit(ma_device* pDevice) return; } - /* - It's possible for the miniaudio side of the device and the backend to not be in sync due to - system-level situations such as the computer being put into sleep mode and the backend not - notifying miniaudio of the fact the device has stopped. It's possible for this to result in a - deadlock due to miniaudio thinking the device is in a running state, when in fact it's not - running at all. For this reason I am no longer explicitly stopping the device. I don't think - this should affect anyone in practice since uninitializing the backend will naturally stop the - device anyway. - */ - #if 0 - { - /* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */ - if (ma_device_is_started(pDevice)) { - ma_device_stop(pDevice); - } + /* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */ + if (ma_device_is_started(pDevice)) { + ma_device_stop(pDevice); } - #endif /* Putting the device into an uninitialized state will make the worker thread return. */ - ma_device__set_state(pDevice, ma_device_state_uninitialized); + ma_device__set_state(pDevice, MA_STATE_UNINITIALIZED); /* Wake up the worker thread and wait for it to properly terminate. */ if (!ma_context_is_backend_asynchronous(pDevice->pContext)) { @@ -42599,154 +33284,38 @@ MA_API void ma_device_uninit(ma_device* pDevice) } } - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { - ma_data_converter_uninit(&pDevice->capture.converter, &pDevice->pContext->allocationCallbacks); - } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_data_converter_uninit(&pDevice->playback.converter, &pDevice->pContext->allocationCallbacks); - } - - if (pDevice->playback.pInputCache != NULL) { - ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); - } - - if (pDevice->capture.pIntermediaryBuffer != NULL) { - ma_free(pDevice->capture.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); - } - if (pDevice->playback.pIntermediaryBuffer != NULL) { - ma_free(pDevice->playback.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); - } - if (pDevice->isOwnerOfContext) { ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks; ma_context_uninit(pDevice->pContext); - ma_free(pDevice->pContext, &allocationCallbacks); + ma__free_from_callbacks(pDevice->pContext, &allocationCallbacks); } MA_ZERO_OBJECT(pDevice); } -MA_API ma_context* ma_device_get_context(ma_device* pDevice) -{ - if (pDevice == NULL) { - return NULL; - } - - return pDevice->pContext; -} - -MA_API ma_log* ma_device_get_log(ma_device* pDevice) -{ - return ma_context_get_log(ma_device_get_context(pDevice)); -} - -MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo) -{ - if (pDeviceInfo == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDeviceInfo); - - if (pDevice == NULL) { - return MA_INVALID_ARGS; - } - - /* If the onDeviceGetInfo() callback is set, use that. Otherwise we'll fall back to ma_context_get_device_info(). */ - if (pDevice->pContext->callbacks.onDeviceGetInfo != NULL) { - return pDevice->pContext->callbacks.onDeviceGetInfo(pDevice, type, pDeviceInfo); - } - - /* Getting here means onDeviceGetInfo is not implemented so we need to fall back to an alternative. */ - if (type == ma_device_type_playback) { - return ma_context_get_device_info(pDevice->pContext, type, pDevice->playback.pID, pDeviceInfo); - } else { - /* - Here we're getting the capture side, which is the branch we'll be entering for a loopback - device, since loopback is capturing. However, if the device is using the default device ID, - it won't get the correct information because it'll think we're asking for the default - capture device, where in fact for loopback we want the default *playback* device. We'll do - a bit of a hack here to make sure we get the correct info. - */ - if (pDevice->type == ma_device_type_loopback && pDevice->capture.pID == NULL) { - type = ma_device_type_playback; - } - - return ma_context_get_device_info(pDevice->pContext, type, pDevice->capture.pID, pDeviceInfo); - } -} - -MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator) -{ - ma_result result; - ma_device_info deviceInfo; - - if (pLengthNotIncludingNullTerminator != NULL) { - *pLengthNotIncludingNullTerminator = 0; - } - - if (pName != NULL && nameCap > 0) { - pName[0] = '\0'; - } - - result = ma_device_get_info(pDevice, type, &deviceInfo); - if (result != MA_SUCCESS) { - return result; - } - - if (pName != NULL) { - ma_strncpy_s(pName, nameCap, deviceInfo.name, (size_t)-1); - - /* - For safety, make sure the length is based on the truncated output string rather than the - source. Otherwise the caller might assume the output buffer contains more content than it - actually does. - */ - if (pLengthNotIncludingNullTerminator != NULL) { - *pLengthNotIncludingNullTerminator = strlen(pName); - } - } else { - /* Name not specified. Just report the length of the source string. */ - if (pLengthNotIncludingNullTerminator != NULL) { - *pLengthNotIncludingNullTerminator = strlen(deviceInfo.name); - } - } - - return MA_SUCCESS; -} - MA_API ma_result ma_device_start(ma_device* pDevice) { ma_result result; if (pDevice == NULL) { - return MA_INVALID_ARGS; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); } - if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { - return MA_INVALID_OPERATION; /* Not initialized. */ + if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); } - if (ma_device_get_state(pDevice) == ma_device_state_started) { - return MA_SUCCESS; /* Already started. */ + if (ma_device_get_state(pDevice) == MA_STATE_STARTED) { + return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_start() called when the device is already started.", MA_INVALID_OPERATION); /* Already started. Returning an error to let the application know because it probably means they're doing something wrong. */ } ma_mutex_lock(&pDevice->startStopLock); { - /* - We need to check again if the device is in a started state because it's possible for one thread to have started the device - while another was waiting on the mutex. - */ - if (ma_device_get_state(pDevice) == ma_device_state_started) { - ma_mutex_unlock(&pDevice->startStopLock); - return MA_SUCCESS; /* Already started. */ - } - /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */ - MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); + MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED); - ma_device__set_state(pDevice, ma_device_state_starting); + ma_device__set_state(pDevice, MA_STATE_STARTING); /* Asynchronous backends need to be handled differently. */ if (ma_context_is_backend_asynchronous(pDevice->pContext)) { @@ -42757,8 +33326,7 @@ MA_API ma_result ma_device_start(ma_device* pDevice) } if (result == MA_SUCCESS) { - ma_device__set_state(pDevice, ma_device_state_started); - ma_device__on_notification_started(pDevice); + ma_device__set_state(pDevice, MA_STATE_STARTED); } } else { /* @@ -42777,7 +33345,7 @@ MA_API ma_result ma_device_start(ma_device* pDevice) /* We changed the state from stopped to started, so if we failed, make sure we put the state back to stopped. */ if (result != MA_SUCCESS) { - ma_device__set_state(pDevice, ma_device_state_stopped); + ma_device__set_state(pDevice, MA_STATE_STOPPED); } } ma_mutex_unlock(&pDevice->startStopLock); @@ -42790,32 +33358,23 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) ma_result result; if (pDevice == NULL) { - return MA_INVALID_ARGS; + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); } - if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { - return MA_INVALID_OPERATION; /* Not initialized. */ + if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) { + return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); } - if (ma_device_get_state(pDevice) == ma_device_state_stopped) { - return MA_SUCCESS; /* Already stopped. */ + if (ma_device_get_state(pDevice) == MA_STATE_STOPPED) { + return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_stop() called when the device is already stopped.", MA_INVALID_OPERATION); /* Already stopped. Returning an error to let the application know because it probably means they're doing something wrong. */ } ma_mutex_lock(&pDevice->startStopLock); { - /* - We need to check again if the device is in a stopped state because it's possible for one thread to have stopped the device - while another was waiting on the mutex. - */ - if (ma_device_get_state(pDevice) == ma_device_state_stopped) { - ma_mutex_unlock(&pDevice->startStopLock); - return MA_SUCCESS; /* Already stopped. */ - } - /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */ - MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_started); + MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STARTED); - ma_device__set_state(pDevice, ma_device_state_stopping); + ma_device__set_state(pDevice, MA_STATE_STOPPING); /* Asynchronous backends need to be handled differently. */ if (ma_context_is_backend_asynchronous(pDevice->pContext)) { @@ -42826,15 +33385,15 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) result = MA_INVALID_OPERATION; } - ma_device__set_state(pDevice, ma_device_state_stopped); + ma_device__set_state(pDevice, MA_STATE_STOPPED); } else { /* Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If - the backend is implementing its own audio thread loop we'll need to wake it up if required. Note that we need to make + the backend is implementing it's own audio thread loop we'll need to wake it up if required. Note that we need to make sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super important though, so I'm asserting it here as well for extra safety in case we accidentally change something later. */ - MA_ASSERT(ma_device_get_state(pDevice) != ma_device_state_started); + MA_ASSERT(ma_device_get_state(pDevice) != MA_STATE_STARTED); if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) { pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice); @@ -42847,15 +33406,6 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) ma_event_wait(&pDevice->stopEvent); result = MA_SUCCESS; } - - /* - This is a safety measure to ensure the internal buffer has been cleared so any leftover - does not get played the next time the device starts. Ideally this should be drained by - the backend first. - */ - pDevice->playback.intermediaryBufferLen = 0; - pDevice->playback.inputCacheConsumed = 0; - pDevice->playback.inputCacheRemaining = 0; } ma_mutex_unlock(&pDevice->startStopLock); @@ -42864,16 +33414,16 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice) { - return ma_device_get_state(pDevice) == ma_device_state_started; + return ma_device_get_state(pDevice) == MA_STATE_STARTED; } -MA_API ma_device_state ma_device_get_state(const ma_device* pDevice) +MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice) { if (pDevice == NULL) { - return ma_device_state_uninitialized; + return MA_STATE_UNINITIALIZED; } - return ma_atomic_device_state_get((ma_atomic_device_state*)&pDevice->state); /* Naughty cast to get rid of a const warning. */ + return c89atomic_load_32((ma_uint32*)&pDevice->state); /* Naughty cast to get rid of a const warning. */ } MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) @@ -42882,11 +33432,11 @@ MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) return MA_INVALID_ARGS; } - if (volume < 0.0f) { + if (volume < 0.0f || volume > 1.0f) { return MA_INVALID_ARGS; } - ma_atomic_float_set(&pDevice->masterVolumeFactor, volume); + c89atomic_exchange_f32(&pDevice->masterVolumeFactor, volume); return MA_SUCCESS; } @@ -42902,21 +33452,21 @@ MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume) return MA_INVALID_ARGS; } - *pVolume = ma_atomic_float_get(&pDevice->masterVolumeFactor); + *pVolume = c89atomic_load_f32(&pDevice->masterVolumeFactor); return MA_SUCCESS; } -MA_API ma_result ma_device_set_master_volume_db(ma_device* pDevice, float gainDB) +MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB) { if (gainDB > 0) { return MA_INVALID_ARGS; } - return ma_device_set_master_volume(pDevice, ma_volume_db_to_linear(gainDB)); + return ma_device_set_master_volume(pDevice, ma_gain_db_to_factor(gainDB)); } -MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB) +MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB) { float factor; ma_result result; @@ -42931,7 +33481,7 @@ MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGain return result; } - *pGainDB = ma_volume_linear_to_db(factor); + *pGainDB = ma_factor_to_gain_db(factor); return MA_SUCCESS; } @@ -42947,15 +33497,6 @@ MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void return MA_INVALID_ARGS; } - /* - There is an assert deeper in the code that checks that frameCount > 0. Since this is a public facing - API we'll need to check for that here. I've had reports that AAudio can sometimes post a frame count - of 0. - */ - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - if (pDevice->type == ma_device_type_duplex) { if (pInput != NULL) { ma_device__handle_duplex_callback_capture(pDevice, frameCount, pInput, &pDevice->duplexRB.rb); @@ -43023,6 +33564,11 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_dev #endif /* MA_NO_DEVICE_IO */ +MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale) +{ + return ma_max(1, (ma_uint32)(baseBufferSize*scale)); +} + MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate) { /* Prevent a division by zero. */ @@ -43030,7 +33576,7 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 return 0; } - return (bufferSizeInFrames*1000 + (sampleRate - 1)) / sampleRate; + return bufferSizeInFrames*1000 / sampleRate; } MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) @@ -43076,89 +33622,13 @@ MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offse } -MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count) +MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount) { - ma_uint64 iSample; + ma_uint32 iSample; - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_u8(pSrc[iSample]); - } -} - -MA_API void ma_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count) -{ - ma_uint64 iSample; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_s16(pSrc[iSample]); - } -} - -MA_API void ma_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count) -{ - ma_uint64 iSample; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - for (iSample = 0; iSample < count; iSample += 1) { - ma_int64 s = ma_clip_s24(pSrc[iSample]); - pDst[iSample*3 + 0] = (ma_uint8)((s & 0x000000FF) >> 0); - pDst[iSample*3 + 1] = (ma_uint8)((s & 0x0000FF00) >> 8); - pDst[iSample*3 + 2] = (ma_uint8)((s & 0x00FF0000) >> 16); - } -} - -MA_API void ma_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count) -{ - ma_uint64 iSample; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_s32(pSrc[iSample]); - } -} - -MA_API void ma_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count) -{ - ma_uint64 iSample; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_f32(pSrc[iSample]); - } -} - -MA_API void ma_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels) -{ - ma_uint64 sampleCount; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - sampleCount = frameCount * channels; - - switch (format) { - case ma_format_u8: ma_clip_samples_u8( (ma_uint8*)pDst, (const ma_int16*)pSrc, sampleCount); break; - case ma_format_s16: ma_clip_samples_s16((ma_int16*)pDst, (const ma_int32*)pSrc, sampleCount); break; - case ma_format_s24: ma_clip_samples_s24((ma_uint8*)pDst, (const ma_int64*)pSrc, sampleCount); break; - case ma_format_s32: ma_clip_samples_s32((ma_int32*)pDst, (const ma_int64*)pSrc, sampleCount); break; - case ma_format_f32: ma_clip_samples_f32(( float*)pDst, (const float*)pSrc, sampleCount); break; - - /* Do nothing if we don't know the format. We're including these here to silence a compiler warning about enums not being handled by the switch. */ - case ma_format_unknown: - case ma_format_count: - break; + /* TODO: Research a branchless SSE implementation. */ + for (iSample = 0; iSample < sampleCount; iSample += 1) { + p[iSample] = ma_clip_f32(p[iSample]); } } @@ -43235,19 +33705,8 @@ MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* return; } - if (factor == 1) { - if (pSamplesOut == pSamplesIn) { - /* In place. No-op. */ - } else { - /* Just a copy. */ - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamplesOut[iSample] = pSamplesIn[iSample]; - } - } - } else { - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamplesOut[iSample] = pSamplesIn[iSample] * factor; - } + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamplesOut[iSample] = pSamplesIn[iSample] * factor; } } @@ -43276,265 +33735,85 @@ MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, f ma_copy_and_apply_volume_factor_f32(pSamples, pSamples, sampleCount, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pFramesOut, const ma_uint8* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_u8(pFramesOut, pFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_u8(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pFramesOut, const ma_int16* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_s16(pFramesOut, pFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_s16(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_s24(pFramesOut, pFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_s24(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pFramesOut, const ma_int32* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_s32(pFramesOut, pFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_s32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_f32(pFramesOut, pFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_f32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) { switch (format) { - case ma_format_u8: ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pFramesOut, (const ma_uint8*)pFramesIn, frameCount, channels, factor); return; - case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pFramesOut, (const ma_int16*)pFramesIn, frameCount, channels, factor); return; - case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24( pFramesOut, pFramesIn, frameCount, channels, factor); return; - case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pFramesOut, (const ma_int32*)pFramesIn, frameCount, channels, factor); return; - case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32( (float*)pFramesOut, (const float*)pFramesIn, frameCount, channels, factor); return; + case ma_format_u8: ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pPCMFramesOut, (const ma_uint8*)pPCMFramesIn, frameCount, channels, factor); return; + case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pPCMFramesOut, (const ma_int16*)pPCMFramesIn, frameCount, channels, factor); return; + case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24( pPCMFramesOut, pPCMFramesIn, frameCount, channels, factor); return; + case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pPCMFramesOut, (const ma_int32*)pPCMFramesIn, frameCount, channels, factor); return; + case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32( (float*)pPCMFramesOut, (const float*)pPCMFramesIn, frameCount, channels, factor); return; default: return; /* Do nothing. */ } } -MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_u8(pFrames, pFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_u8(pPCMFrames, pPCMFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_s16(pFrames, pFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_s16(pPCMFrames, pPCMFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_s24(pFrames, pFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_s24(pPCMFrames, pPCMFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_s32(pFrames, pFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_s32(pPCMFrames, pPCMFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_f32(pFrames, pFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_f32(pPCMFrames, pPCMFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames(void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames(void* pPCMFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames(pFramesOut, pFramesOut, frameCount, format, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames(pPCMFrames, pPCMFrames, frameCount, format, channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_per_channel_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float* pChannelGains) +MA_API float ma_factor_to_gain_db(float factor) { - ma_uint64 iFrame; - - if (channels == 2) { - /* TODO: Do an optimized implementation for stereo and mono. Can do a SIMD optimized implementation as well. */ - } - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - ma_uint32 iChannel; - for (iChannel = 0; iChannel < channels; iChannel += 1) { - pFramesOut[iFrame * channels + iChannel] = pFramesIn[iFrame * channels + iChannel] * pChannelGains[iChannel]; - } - } + return (float)(20*ma_log10f(factor)); } - - -static MA_INLINE ma_int16 ma_apply_volume_unclipped_u8(ma_int16 x, ma_int16 volume) +MA_API float ma_gain_db_to_factor(float gain) { - return (ma_int16)(((ma_int32)x * (ma_int32)volume) >> 8); + return (float)ma_powf(10, gain/20.0f); } -static MA_INLINE ma_int32 ma_apply_volume_unclipped_s16(ma_int32 x, ma_int16 volume) -{ - return (ma_int32)((x * volume) >> 8); -} - -static MA_INLINE ma_int64 ma_apply_volume_unclipped_s24(ma_int64 x, ma_int16 volume) -{ - return (ma_int64)((x * volume) >> 8); -} - -static MA_INLINE ma_int64 ma_apply_volume_unclipped_s32(ma_int64 x, ma_int16 volume) -{ - return (ma_int64)((x * volume) >> 8); -} - -static MA_INLINE float ma_apply_volume_unclipped_f32(float x, float volume) -{ - return x * volume; -} - - -MA_API void ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count, float volume) -{ - ma_uint64 iSample; - ma_int16 volumeFixed; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - volumeFixed = ma_float_to_fixed_16(volume); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_u8(ma_apply_volume_unclipped_u8(pSrc[iSample], volumeFixed)); - } -} - -MA_API void ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count, float volume) -{ - ma_uint64 iSample; - ma_int16 volumeFixed; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - volumeFixed = ma_float_to_fixed_16(volume); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_s16(ma_apply_volume_unclipped_s16(pSrc[iSample], volumeFixed)); - } -} - -MA_API void ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count, float volume) -{ - ma_uint64 iSample; - ma_int16 volumeFixed; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - volumeFixed = ma_float_to_fixed_16(volume); - - for (iSample = 0; iSample < count; iSample += 1) { - ma_int64 s = ma_clip_s24(ma_apply_volume_unclipped_s24(pSrc[iSample], volumeFixed)); - pDst[iSample*3 + 0] = (ma_uint8)((s & 0x000000FF) >> 0); - pDst[iSample*3 + 1] = (ma_uint8)((s & 0x0000FF00) >> 8); - pDst[iSample*3 + 2] = (ma_uint8)((s & 0x00FF0000) >> 16); - } -} - -MA_API void ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count, float volume) -{ - ma_uint64 iSample; - ma_int16 volumeFixed; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - volumeFixed = ma_float_to_fixed_16(volume); - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_s32(ma_apply_volume_unclipped_s32(pSrc[iSample], volumeFixed)); - } -} - -MA_API void ma_copy_and_apply_volume_and_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count, float volume) -{ - ma_uint64 iSample; - - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - /* For the f32 case we need to make sure this supports in-place processing where the input and output buffers are the same. */ - - for (iSample = 0; iSample < count; iSample += 1) { - pDst[iSample] = ma_clip_f32(ma_apply_volume_unclipped_f32(pSrc[iSample], volume)); - } -} - -MA_API void ma_copy_and_apply_volume_and_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float volume) -{ - MA_ASSERT(pDst != NULL); - MA_ASSERT(pSrc != NULL); - - if (volume == 1) { - ma_clip_pcm_frames(pDst, pSrc, frameCount, format, channels); /* Optimized case for volume = 1. */ - } else if (volume == 0) { - ma_silence_pcm_frames(pDst, frameCount, format, channels); /* Optimized case for volume = 0. */ - } else { - ma_uint64 sampleCount = frameCount * channels; - - switch (format) { - case ma_format_u8: ma_copy_and_apply_volume_and_clip_samples_u8( (ma_uint8*)pDst, (const ma_int16*)pSrc, sampleCount, volume); break; - case ma_format_s16: ma_copy_and_apply_volume_and_clip_samples_s16((ma_int16*)pDst, (const ma_int32*)pSrc, sampleCount, volume); break; - case ma_format_s24: ma_copy_and_apply_volume_and_clip_samples_s24((ma_uint8*)pDst, (const ma_int64*)pSrc, sampleCount, volume); break; - case ma_format_s32: ma_copy_and_apply_volume_and_clip_samples_s32((ma_int32*)pDst, (const ma_int64*)pSrc, sampleCount, volume); break; - case ma_format_f32: ma_copy_and_apply_volume_and_clip_samples_f32(( float*)pDst, (const float*)pSrc, sampleCount, volume); break; - - /* Do nothing if we don't know the format. We're including these here to silence a compiler warning about enums not being handled by the switch. */ - case ma_format_unknown: - case ma_format_count: - break; - } - } -} - - - -MA_API float ma_volume_linear_to_db(float factor) -{ - return 20*ma_log10f(factor); -} - -MA_API float ma_volume_db_to_linear(float gain) -{ - return ma_powf(10, gain/20.0f); -} - - -MA_API ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume) -{ - ma_uint64 iSample; - ma_uint64 sampleCount; - - if (pDst == NULL || pSrc == NULL || channels == 0) { - return MA_INVALID_ARGS; - } - - if (volume == 0) { - return MA_SUCCESS; /* No changes if the volume is 0. */ - } - - sampleCount = frameCount * channels; - - if (volume == 1) { - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pDst[iSample] += pSrc[iSample]; - } - } else { - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pDst[iSample] += ma_apply_volume_unclipped_f32(pSrc[iSample], volume); - } - } - - return MA_SUCCESS; -} - - /************************************************************************************************************************************************************** @@ -43565,6 +33844,33 @@ static MA_INLINE void ma_pcm_sample_s32_to_s24_no_scale(ma_int64 x, ma_uint8* s2 } +static MA_INLINE ma_uint8 ma_clip_u8(ma_int16 x) +{ + return (ma_uint8)(ma_clamp(x, -128, 127) + 128); +} + +static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x) +{ + return (ma_int16)ma_clamp(x, -32768, 32767); +} + +static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x) +{ + return (ma_int64)ma_clamp(x, -8388608, 8388607); +} + +static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x) +{ + /* This dance is to silence warnings with -std=c89. A good compiler should be able to optimize this away. */ + ma_int64 clipMin; + ma_int64 clipMax; + clipMin = -((ma_int64)2147483647 + 1); + clipMax = (ma_int64)2147483647; + + return (ma_int32)ma_clamp(x, clipMin, clipMax); +} + + /* u8 */ MA_API void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43600,6 +33906,12 @@ static MA_INLINE void ma_pcm_u8_to_s16__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_u8_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43612,11 +33924,15 @@ MA_API void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_u8_to_s16__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_u8_to_s16__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_u8_to_s16__neon(dst, src, count, ditherMode); } else @@ -43657,6 +33973,12 @@ static MA_INLINE void ma_pcm_u8_to_s24__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_u8_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43669,11 +33991,15 @@ MA_API void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_u8_to_s24__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_u8_to_s24__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_u8_to_s24__neon(dst, src, count, ditherMode); } else @@ -43712,6 +34038,12 @@ static MA_INLINE void ma_pcm_u8_to_s32__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_u8_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43724,11 +34056,15 @@ MA_API void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_u8_to_s32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_u8_to_s32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_u8_to_s32__neon(dst, src, count, ditherMode); } else @@ -43768,6 +34104,12 @@ static MA_INLINE void ma_pcm_u8_to_f32__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_u8_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43780,11 +34122,15 @@ MA_API void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_u8_to_f32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_u8_to_f32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_u8_to_f32__neon(dst, src, count, ditherMode); } else @@ -43920,6 +34266,12 @@ static MA_INLINE void ma_pcm_s16_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s16_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43932,11 +34284,15 @@ MA_API void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s16_to_u8__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s16_to_u8__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s16_to_u8__neon(dst, src, count, ditherMode); } else @@ -43981,6 +34337,12 @@ static MA_INLINE void ma_pcm_s16_to_s24__sse2(void* dst, const void* src, ma_uin ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s16_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43993,11 +34355,15 @@ MA_API void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s16_to_s24__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s16_to_s24__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s16_to_s24__neon(dst, src, count, ditherMode); } else @@ -44033,6 +34399,12 @@ static MA_INLINE void ma_pcm_s16_to_s32__sse2(void* dst, const void* src, ma_uin ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s16_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44045,11 +34417,15 @@ MA_API void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s16_to_s32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s16_to_s32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s16_to_s32__neon(dst, src, count, ditherMode); } else @@ -44097,6 +34473,12 @@ static MA_INLINE void ma_pcm_s16_to_f32__sse2(void* dst, const void* src, ma_uin ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s16_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44109,11 +34491,15 @@ MA_API void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s16_to_f32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s16_to_f32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s16_to_f32__neon(dst, src, count, ditherMode); } else @@ -44225,6 +34611,12 @@ static MA_INLINE void ma_pcm_s24_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s24_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44237,11 +34629,15 @@ MA_API void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s24_to_u8__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s24_to_u8__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s24_to_u8__neon(dst, src, count, ditherMode); } else @@ -44295,6 +34691,12 @@ static MA_INLINE void ma_pcm_s24_to_s16__sse2(void* dst, const void* src, ma_uin ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s24_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44307,11 +34709,15 @@ MA_API void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s24_to_s16__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s24_to_s16__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s24_to_s16__neon(dst, src, count, ditherMode); } else @@ -44355,6 +34761,12 @@ static MA_INLINE void ma_pcm_s24_to_s32__sse2(void* dst, const void* src, ma_uin ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s24_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44367,11 +34779,15 @@ MA_API void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s24_to_s32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s24_to_s32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s24_to_s32__neon(dst, src, count, ditherMode); } else @@ -44419,6 +34835,12 @@ static MA_INLINE void ma_pcm_s24_to_f32__sse2(void* dst, const void* src, ma_uin ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s24_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44431,11 +34853,15 @@ MA_API void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s24_to_f32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s24_to_f32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s24_to_f32__neon(dst, src, count, ditherMode); } else @@ -44555,6 +34981,12 @@ static MA_INLINE void ma_pcm_s32_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44567,11 +34999,15 @@ MA_API void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s32_to_u8__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s32_to_u8__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s32_to_u8__neon(dst, src, count, ditherMode); } else @@ -44625,6 +35061,12 @@ static MA_INLINE void ma_pcm_s32_to_s16__sse2(void* dst, const void* src, ma_uin ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44637,11 +35079,15 @@ MA_API void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s32_to_s16__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s32_to_s16__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s32_to_s16__neon(dst, src, count, ditherMode); } else @@ -44680,6 +35126,12 @@ static MA_INLINE void ma_pcm_s32_to_s24__sse2(void* dst, const void* src, ma_uin ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44692,11 +35144,15 @@ MA_API void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s32_to_s24__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s32_to_s24__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s32_to_s24__neon(dst, src, count, ditherMode); } else @@ -44750,6 +35206,12 @@ static MA_INLINE void ma_pcm_s32_to_f32__sse2(void* dst, const void* src, ma_uin ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_s32_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44762,11 +35224,15 @@ MA_API void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_s32_to_f32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_s32_to_f32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_s32_to_f32__neon(dst, src, count, ditherMode); } else @@ -44873,6 +35339,12 @@ static MA_INLINE void ma_pcm_f32_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_f32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -44885,11 +35357,15 @@ MA_API void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_f32_to_u8__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_f32_to_u8__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_f32_to_u8__neon(dst, src, count, ditherMode); } else @@ -45093,6 +35569,129 @@ static MA_INLINE void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uin } #endif /* SSE2 */ +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_f32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint64 i; + ma_uint64 i16; + ma_uint64 count16; + ma_int16* dst_s16; + const float* src_f32; + float ditherMin; + float ditherMax; + + /* Both the input and output buffers need to be aligned to 32 bytes. */ + if ((((ma_uintptr)dst & 31) != 0) || (((ma_uintptr)src & 31) != 0)) { + ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); + return; + } + + dst_s16 = (ma_int16*)dst; + src_f32 = (const float*)src; + + ditherMin = 0; + ditherMax = 0; + if (ditherMode != ma_dither_mode_none) { + ditherMin = 1.0f / -32768; + ditherMax = 1.0f / 32767; + } + + i = 0; + + /* AVX2. AVX2 allows us to output 16 s16's at a time which means our loop is unrolled 16 times. */ + count16 = count >> 4; + for (i16 = 0; i16 < count16; i16 += 1) { + __m256 d0; + __m256 d1; + __m256 x0; + __m256 x1; + __m256i i0; + __m256i i1; + __m256i p0; + __m256i p1; + __m256i r; + + if (ditherMode == ma_dither_mode_none) { + d0 = _mm256_set1_ps(0); + d1 = _mm256_set1_ps(0); + } else if (ditherMode == ma_dither_mode_rectangle) { + d0 = _mm256_set_ps( + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax) + ); + d1 = _mm256_set_ps( + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax), + ma_dither_f32_rectangle(ditherMin, ditherMax) + ); + } else { + d0 = _mm256_set_ps( + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax) + ); + d1 = _mm256_set_ps( + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax), + ma_dither_f32_triangle(ditherMin, ditherMax) + ); + } + + x0 = *((__m256*)(src_f32 + i) + 0); + x1 = *((__m256*)(src_f32 + i) + 1); + + x0 = _mm256_add_ps(x0, d0); + x1 = _mm256_add_ps(x1, d1); + + x0 = _mm256_mul_ps(x0, _mm256_set1_ps(32767.0f)); + x1 = _mm256_mul_ps(x1, _mm256_set1_ps(32767.0f)); + + /* Computing the final result is a little more complicated for AVX2 than SSE2. */ + i0 = _mm256_cvttps_epi32(x0); + i1 = _mm256_cvttps_epi32(x1); + p0 = _mm256_permute2x128_si256(i0, i1, 0 | 32); + p1 = _mm256_permute2x128_si256(i0, i1, 1 | 48); + r = _mm256_packs_epi32(p0, p1); + + _mm256_stream_si256(((__m256i*)(dst_s16 + i)), r); + + i += 16; + } + + + /* Leftover. */ + for (; i < count; i += 1) { + float x = src_f32[i]; + x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); + x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ + x = x * 32767.0f; /* -1..1 to -32767..32767 */ + + dst_s16[i] = (ma_int16)x; + } +} +#endif /* AVX2 */ + #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -45105,8 +35704,7 @@ static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uin float ditherMax; if (!ma_has_neon()) { - ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); - return; + return ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); } /* Both the input and output buffers need to be aligned to 16 bytes. */ @@ -45142,14 +35740,13 @@ static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uin d1 = vmovq_n_f32(0); } else if (ditherMode == ma_dither_mode_rectangle) { float d0v[4]; - float d1v[4]; - d0v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0 = vld1q_f32(d0v); + float d1v[4]; d1v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax); d1v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax); d1v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax); @@ -45157,14 +35754,13 @@ static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uin d1 = vld1q_f32(d1v); } else { float d0v[4]; - float d1v[4]; - d0v[0] = ma_dither_f32_triangle(ditherMin, ditherMax); d0v[1] = ma_dither_f32_triangle(ditherMin, ditherMax); d0v[2] = ma_dither_f32_triangle(ditherMin, ditherMax); d0v[3] = ma_dither_f32_triangle(ditherMin, ditherMax); d0 = vld1q_f32(d0v); + float d1v[4]; d1v[0] = ma_dither_f32_triangle(ditherMin, ditherMax); d1v[1] = ma_dither_f32_triangle(ditherMin, ditherMax); d1v[2] = ma_dither_f32_triangle(ditherMin, ditherMax); @@ -45207,11 +35803,15 @@ MA_API void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_f32_to_s16__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_f32_to_s16__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_f32_to_s16__neon(dst, src, count, ditherMode); } else @@ -45264,6 +35864,12 @@ static MA_INLINE void ma_pcm_f32_to_s24__sse2(void* dst, const void* src, ma_uin ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_f32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -45276,11 +35882,15 @@ MA_API void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_f32_to_s24__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_f32_to_s24__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_f32_to_s24__neon(dst, src, count, ditherMode); } else @@ -45329,6 +35939,12 @@ static MA_INLINE void ma_pcm_f32_to_s32__sse2(void* dst, const void* src, ma_uin ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); } #endif +#if defined(MA_SUPPORT_AVX2) +static MA_INLINE void ma_pcm_f32_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); +} +#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -45341,11 +35957,15 @@ MA_API void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode); #else - # if defined(MA_SUPPORT_SSE2) + # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 + if (ma_has_avx2()) { + ma_pcm_f32_to_s32__avx2(dst, src, count, ditherMode); + } else + #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 if (ma_has_sse2()) { ma_pcm_f32_to_s32__sse2(dst, src, count, ditherMode); } else - #elif defined(MA_SUPPORT_NEON) + #elif MA_PREFERRED_SIMD == MA_SIMD_NEON if (ma_has_neon()) { ma_pcm_f32_to_s32__neon(dst, src, count, ditherMode); } else @@ -45629,131 +36249,25 @@ MA_API ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channe return config; } - -typedef struct +MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ) { - size_t sizeInBytes; - size_t r1Offset; - size_t r2Offset; -} ma_biquad_heap_layout; - -static ma_result ma_biquad_get_heap_layout(const ma_biquad_config* pConfig, ma_biquad_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* R0 */ - pHeapLayout->r1Offset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; - - /* R1 */ - pHeapLayout->r2Offset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_biquad_get_heap_size(const ma_biquad_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_biquad_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_biquad_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_biquad_init_preallocated(const ma_biquad_config* pConfig, void* pHeap, ma_biquad* pBQ) -{ - ma_result result; - ma_biquad_heap_layout heapLayout; - if (pBQ == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pBQ); - result = ma_biquad_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - pBQ->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pBQ->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); - pBQ->pR2 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r2Offset); + if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; + } return ma_biquad_reinit(pConfig, pBQ); } -MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad* pBQ) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_biquad_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_biquad_init_preallocated(pConfig, pHeap, pBQ); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pBQ->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_biquad_uninit(ma_biquad* pBQ, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pBQ == NULL) { - return; - } - - if (pBQ->_ownsHeap) { - ma_free(pBQ->_pHeap, pAllocationCallbacks); - } -} - MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ) { if (pBQ == NULL || pConfig == NULL) { @@ -45801,23 +36315,6 @@ MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pB return MA_SUCCESS; } -MA_API ma_result ma_biquad_clear_cache(ma_biquad* pBQ) -{ - if (pBQ == NULL) { - return MA_INVALID_ARGS; - } - - if (pBQ->format == ma_format_f32) { - pBQ->pR1->f32 = 0; - pBQ->pR2->f32 = 0; - } else { - pBQ->pR1->s32 = 0; - pBQ->pR2->s32 = 0; - } - - return MA_SUCCESS; -} - static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX) { ma_uint32 c; @@ -45828,10 +36325,10 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed( const float a1 = pBQ->a1.f32; const float a2 = pBQ->a2.f32; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { - float r1 = pBQ->pR1[c].f32; - float r2 = pBQ->pR2[c].f32; + float r1 = pBQ->r1[c].f32; + float r2 = pBQ->r2[c].f32; float x = pX[c]; float y; @@ -45839,9 +36336,9 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed( r1 = b1*x - a1*y + r2; r2 = b2*x - a2*y; - pY[c] = y; - pBQ->pR1[c].f32 = r1; - pBQ->pR2[c].f32 = r2; + pY[c] = y; + pBQ->r1[c].f32 = r1; + pBQ->r2[c].f32 = r2; } } @@ -45860,10 +36357,10 @@ static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed( const ma_int32 a1 = pBQ->a1.s32; const ma_int32 a2 = pBQ->a2.s32; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { - ma_int32 r1 = pBQ->pR1[c].s32; - ma_int32 r2 = pBQ->pR2[c].s32; + ma_int32 r1 = pBQ->r1[c].s32; + ma_int32 r2 = pBQ->r2[c].s32; ma_int32 x = pX[c]; ma_int32 y; @@ -45871,9 +36368,9 @@ static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed( r1 = (b1*x - a1*y + r2); r2 = (b2*x - a2*y); - pY[c] = (ma_int16)ma_clamp(y, -32768, 32767); - pBQ->pR1[c].s32 = r1; - pBQ->pR2[c].s32 = r2; + pY[c] = (ma_int16)ma_clamp(y, -32768, 32767); + pBQ->r1[c].s32 = r1; + pBQ->r2[c].s32 = r2; } } @@ -45967,122 +36464,25 @@ MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, } -typedef struct +MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) { - size_t sizeInBytes; - size_t r1Offset; -} ma_lpf1_heap_layout; - -static ma_result ma_lpf1_get_heap_layout(const ma_lpf1_config* pConfig, ma_lpf1_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* R1 */ - pHeapLayout->r1Offset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_lpf1_get_heap_size(const ma_lpf1_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_lpf1_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_lpf1_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_lpf1_init_preallocated(const ma_lpf1_config* pConfig, void* pHeap, ma_lpf1* pLPF) -{ - ma_result result; - ma_lpf1_heap_layout heapLayout; - if (pLPF == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pLPF); - result = ma_lpf1_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - pLPF->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); + if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; + } return ma_lpf1_reinit(pConfig, pLPF); } -MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf1* pLPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_lpf1_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_lpf1_init_preallocated(pConfig, pHeap, pLPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pLPF->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_lpf1_uninit(ma_lpf1* pLPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pLPF == NULL) { - return; - } - - if (pLPF->_ownsHeap) { - ma_free(pLPF->_pHeap, pAllocationCallbacks); - } -} - MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) { double a; @@ -46109,7 +36509,7 @@ MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) pLPF->format = pConfig->format; pLPF->channels = pConfig->channels; - a = ma_expd(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate); + a = ma_exp(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate); if (pConfig->format == ma_format_f32) { pLPF->a.f32 = (float)a; } else { @@ -46119,21 +36519,6 @@ MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) return MA_SUCCESS; } -MA_API ma_result ma_lpf1_clear_cache(ma_lpf1* pLPF) -{ - if (pLPF == NULL) { - return MA_INVALID_ARGS; - } - - if (pLPF->format == ma_format_f32) { - pLPF->a.f32 = 0; - } else { - pLPF->a.s32 = 0; - } - - return MA_SUCCESS; -} - static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX) { ma_uint32 c; @@ -46141,16 +36526,16 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, co const float a = pLPF->a.f32; const float b = 1 - a; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { - float r1 = pLPF->pR1[c].f32; + float r1 = pLPF->r1[c].f32; float x = pX[c]; float y; y = b*x + a*r1; pY[c] = y; - pLPF->pR1[c].f32 = y; + pLPF->r1[c].f32 = y; } } @@ -46161,16 +36546,16 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int32 a = pLPF->a.s32; const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { - ma_int32 r1 = pLPF->pR1[c].s32; + ma_int32 r1 = pLPF->r1[c].s32; ma_int32 x = pX[c]; ma_int32 y; y = (b*x + a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT; - pY[c] = (ma_int16)y; - pLPF->pR1[c].s32 = (ma_int32)y; + pY[c] = (ma_int16)y; + pLPF->r1[c].s32 = (ma_int32)y; } } @@ -46233,8 +36618,8 @@ static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_confi q = pConfig->q; w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); + s = ma_sin(w); + c = ma_cos(w); a = s / (2*q); bqConfig.b0 = (1 - c) / 2; @@ -46250,15 +36635,7 @@ static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_confi return bqConfig; } -MA_API ma_result ma_lpf2_get_heap_size(const ma_lpf2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_lpf2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* pHeap, ma_lpf2* pLPF) +MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) { ma_result result; ma_biquad_config bqConfig; @@ -46274,7 +36651,7 @@ MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* } bqConfig = ma_lpf2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pLPF->bq); + result = ma_biquad_init(&bqConfig, &pLPF->bq); if (result != MA_SUCCESS) { return result; } @@ -46282,45 +36659,6 @@ MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* return MA_SUCCESS; } -MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf2* pLPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_lpf2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_lpf2_init_preallocated(pConfig, pHeap, pLPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pLPF->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_lpf2_uninit(ma_lpf2* pLPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pLPF == NULL) { - return; - } - - ma_biquad_uninit(&pLPF->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) { ma_result result; @@ -46339,17 +36677,6 @@ MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) return MA_SUCCESS; } -MA_API ma_result ma_lpf2_clear_cache(ma_lpf2* pLPF) -{ - if (pLPF == NULL) { - return MA_INVALID_ARGS; - } - - ma_biquad_clear_cache(&pLPF->bq); - - return MA_SUCCESS; -} - static MA_INLINE void ma_lpf2_process_pcm_frame_s16(ma_lpf2* pLPF, ma_int16* pFrameOut, const ma_int16* pFrameIn) { ma_biquad_process_pcm_frame_s16(&pLPF->bq, pFrameOut, pFrameIn); @@ -46393,24 +36720,7 @@ MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma return config; } - -typedef struct -{ - size_t sizeInBytes; - size_t lpf1Offset; - size_t lpf2Offset; /* Offset of the first second order filter. Subsequent filters will come straight after, and will each have the same heap size. */ -} ma_lpf_heap_layout; - -static void ma_lpf_calculate_sub_lpf_counts(ma_uint32 order, ma_uint32* pLPF1Count, ma_uint32* pLPF2Count) -{ - MA_ASSERT(pLPF1Count != NULL); - MA_ASSERT(pLPF2Count != NULL); - - *pLPF1Count = order % 2; - *pLPF2Count = order / 2; -} - -static ma_result ma_lpf_get_heap_layout(const ma_lpf_config* pConfig, ma_lpf_heap_layout* pHeapLayout) +static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* pLPF, ma_bool32 isNew) { ma_result result; ma_uint32 lpf1Count; @@ -46418,69 +36728,6 @@ static ma_result ma_lpf_get_heap_layout(const ma_lpf_config* pConfig, ma_lpf_hea ma_uint32 ilpf1; ma_uint32 ilpf2; - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - if (pConfig->order > MA_MAX_FILTER_ORDER) { - return MA_INVALID_ARGS; - } - - ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count); - - pHeapLayout->sizeInBytes = 0; - - /* LPF 1 */ - pHeapLayout->lpf1Offset = pHeapLayout->sizeInBytes; - for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) { - size_t lpf1HeapSizeInBytes; - ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); - - result = ma_lpf1_get_heap_size(&lpf1Config, &lpf1HeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += sizeof(ma_lpf1) + lpf1HeapSizeInBytes; - } - - /* LPF 2*/ - pHeapLayout->lpf2Offset = pHeapLayout->sizeInBytes; - for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) { - size_t lpf2HeapSizeInBytes; - ma_lpf2_config lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107); /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */ - - result = ma_lpf2_get_heap_size(&lpf2Config, &lpf2HeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += sizeof(ma_lpf2) + lpf2HeapSizeInBytes; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF, ma_bool32 isNew) -{ - ma_result result; - ma_uint32 lpf1Count; - ma_uint32 lpf2Count; - ma_uint32 ilpf1; - ma_uint32 ilpf2; - ma_lpf_heap_layout heapLayout; /* Only used if isNew is true. */ - if (pLPF == NULL || pConfig == NULL) { return MA_INVALID_ARGS; } @@ -46504,7 +36751,11 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHe return MA_INVALID_ARGS; } - ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count); + lpf1Count = pConfig->order % 2; + lpf2Count = pConfig->order / 2; + + MA_ASSERT(lpf1Count <= ma_countof(pLPF->lpf1)); + MA_ASSERT(lpf2Count <= ma_countof(pLPF->lpf2)); /* The filter order can't change between reinits. */ if (!isNew) { @@ -46513,42 +36764,16 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHe } } - if (isNew) { - result = ma_lpf_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pLPF->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pLPF->pLPF1 = (ma_lpf1*)ma_offset_ptr(pHeap, heapLayout.lpf1Offset); - pLPF->pLPF2 = (ma_lpf2*)ma_offset_ptr(pHeap, heapLayout.lpf2Offset); - } else { - MA_ZERO_OBJECT(&heapLayout); /* To silence a compiler warning. */ - } - for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) { ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); if (isNew) { - size_t lpf1HeapSizeInBytes; - - result = ma_lpf1_get_heap_size(&lpf1Config, &lpf1HeapSizeInBytes); - if (result == MA_SUCCESS) { - result = ma_lpf1_init_preallocated(&lpf1Config, ma_offset_ptr(pHeap, heapLayout.lpf1Offset + (sizeof(ma_lpf1) * lpf1Count) + (ilpf1 * lpf1HeapSizeInBytes)), &pLPF->pLPF1[ilpf1]); - } + result = ma_lpf1_init(&lpf1Config, &pLPF->lpf1[ilpf1]); } else { - result = ma_lpf1_reinit(&lpf1Config, &pLPF->pLPF1[ilpf1]); + result = ma_lpf1_reinit(&lpf1Config, &pLPF->lpf1[ilpf1]); } if (result != MA_SUCCESS) { - ma_uint32 jlpf1; - - for (jlpf1 = 0; jlpf1 < ilpf1; jlpf1 += 1) { - ma_lpf1_uninit(&pLPF->pLPF1[jlpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ - } - return result; } } @@ -46564,33 +36789,17 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHe } else { a = (1 + ilpf2*2) * (MA_PI_D/(pConfig->order*2)); /* Even order. */ } - q = 1 / (2*ma_cosd(a)); + q = 1 / (2*ma_cos(a)); lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q); if (isNew) { - size_t lpf2HeapSizeInBytes; - - result = ma_lpf2_get_heap_size(&lpf2Config, &lpf2HeapSizeInBytes); - if (result == MA_SUCCESS) { - result = ma_lpf2_init_preallocated(&lpf2Config, ma_offset_ptr(pHeap, heapLayout.lpf2Offset + (sizeof(ma_lpf2) * lpf2Count) + (ilpf2 * lpf2HeapSizeInBytes)), &pLPF->pLPF2[ilpf2]); - } + result = ma_lpf2_init(&lpf2Config, &pLPF->lpf2[ilpf2]); } else { - result = ma_lpf2_reinit(&lpf2Config, &pLPF->pLPF2[ilpf2]); + result = ma_lpf2_reinit(&lpf2Config, &pLPF->lpf2[ilpf2]); } if (result != MA_SUCCESS) { - ma_uint32 jlpf1; - ma_uint32 jlpf2; - - for (jlpf1 = 0; jlpf1 < lpf1Count; jlpf1 += 1) { - ma_lpf1_uninit(&pLPF->pLPF1[jlpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ - } - - for (jlpf2 = 0; jlpf2 < ilpf2; jlpf2 += 1) { - ma_lpf2_uninit(&pLPF->pLPF2[jlpf2], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ - } - return result; } } @@ -46604,28 +36813,7 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHe return MA_SUCCESS; } -MA_API ma_result ma_lpf_get_heap_size(const ma_lpf_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_lpf_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_lpf_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return result; -} - -MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF) +MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF) { if (pLPF == NULL) { return MA_INVALID_ARGS; @@ -46633,84 +36821,16 @@ MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pH MA_ZERO_OBJECT(pLPF); - return ma_lpf_reinit__internal(pConfig, pHeap, pLPF, /*isNew*/MA_TRUE); -} - -MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf* pLPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_lpf_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_lpf_init_preallocated(pConfig, pHeap, pLPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pLPF->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_lpf_uninit(ma_lpf* pLPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_uint32 ilpf1; - ma_uint32 ilpf2; - - if (pLPF == NULL) { - return; - } - - for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - ma_lpf1_uninit(&pLPF->pLPF1[ilpf1], pAllocationCallbacks); - } - - for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - ma_lpf2_uninit(&pLPF->pLPF2[ilpf2], pAllocationCallbacks); - } - - if (pLPF->_ownsHeap) { - ma_free(pLPF->_pHeap, pAllocationCallbacks); - } + return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_TRUE); } MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF) { - return ma_lpf_reinit__internal(pConfig, NULL, pLPF, /*isNew*/MA_FALSE); -} - -MA_API ma_result ma_lpf_clear_cache(ma_lpf* pLPF) -{ - ma_uint32 ilpf1; - ma_uint32 ilpf2; - - if (pLPF == NULL) { - return MA_INVALID_ARGS; - } - - for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - ma_lpf1_clear_cache(&pLPF->pLPF1[ilpf1]); - } - - for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - ma_lpf2_clear_cache(&pLPF->pLPF2[ilpf2]); - } - - return MA_SUCCESS; + return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_FALSE); } static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, const void* pX) @@ -46720,14 +36840,14 @@ static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, cons MA_ASSERT(pLPF->format == ma_format_f32); - MA_MOVE_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); + MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - ma_lpf1_process_pcm_frame_f32(&pLPF->pLPF1[ilpf1], pY, pY); + ma_lpf1_process_pcm_frame_f32(&pLPF->lpf1[ilpf1], pY, pY); } for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - ma_lpf2_process_pcm_frame_f32(&pLPF->pLPF2[ilpf2], pY, pY); + ma_lpf2_process_pcm_frame_f32(&pLPF->lpf2[ilpf2], pY, pY); } } @@ -46738,14 +36858,14 @@ static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, c MA_ASSERT(pLPF->format == ma_format_s16); - MA_MOVE_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); + MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - ma_lpf1_process_pcm_frame_s16(&pLPF->pLPF1[ilpf1], pY, pY); + ma_lpf1_process_pcm_frame_s16(&pLPF->lpf1[ilpf1], pY, pY); } for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - ma_lpf2_process_pcm_frame_s16(&pLPF->pLPF2[ilpf2], pY, pY); + ma_lpf2_process_pcm_frame_s16(&pLPF->lpf2[ilpf2], pY, pY); } } @@ -46762,14 +36882,14 @@ MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const /* Faster path for in-place. */ if (pFramesOut == pFramesIn) { for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - result = ma_lpf1_process_pcm_frames(&pLPF->pLPF1[ilpf1], pFramesOut, pFramesOut, frameCount); + result = ma_lpf1_process_pcm_frames(&pLPF->lpf1[ilpf1], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } } for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - result = ma_lpf2_process_pcm_frames(&pLPF->pLPF2[ilpf2], pFramesOut, pFramesOut, frameCount); + result = ma_lpf2_process_pcm_frames(&pLPF->lpf2[ilpf2], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } @@ -46855,120 +36975,23 @@ MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, } -typedef struct +MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) { - size_t sizeInBytes; - size_t r1Offset; -} ma_hpf1_heap_layout; + if (pHPF == NULL) { + return MA_INVALID_ARGS; + } -static ma_result ma_hpf1_get_heap_layout(const ma_hpf1_config* pConfig, ma_hpf1_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); + MA_ZERO_OBJECT(pHPF); if (pConfig == NULL) { return MA_INVALID_ARGS; } - if (pConfig->channels == 0) { + if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { return MA_INVALID_ARGS; } - pHeapLayout->sizeInBytes = 0; - - /* R1 */ - pHeapLayout->r1Offset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_hpf1_get_heap_size(const ma_hpf1_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_hpf1_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_hpf1_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_hpf1_init_preallocated(const ma_hpf1_config* pConfig, void* pHeap, ma_hpf1* pLPF) -{ - ma_result result; - ma_hpf1_heap_layout heapLayout; - - if (pLPF == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pLPF); - - result = ma_hpf1_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pLPF->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); - - return ma_hpf1_reinit(pConfig, pLPF); -} - -MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf1* pLPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_hpf1_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_hpf1_init_preallocated(pConfig, pHeap, pLPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pLPF->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_hpf1_uninit(ma_hpf1* pHPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pHPF == NULL) { - return; - } - - if (pHPF->_ownsHeap) { - ma_free(pHPF->_pHeap, pAllocationCallbacks); - } + return ma_hpf1_reinit(pConfig, pHPF); } MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) @@ -46997,7 +37020,7 @@ MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) pHPF->format = pConfig->format; pHPF->channels = pConfig->channels; - a = ma_expd(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate); + a = ma_exp(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate); if (pConfig->format == ma_format_f32) { pHPF->a.f32 = (float)a; } else { @@ -47014,16 +37037,16 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, co const float a = 1 - pHPF->a.f32; const float b = 1 - a; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { - float r1 = pHPF->pR1[c].f32; + float r1 = pHPF->r1[c].f32; float x = pX[c]; float y; y = b*x - a*r1; - pY[c] = y; - pHPF->pR1[c].f32 = y; + pY[c] = y; + pHPF->r1[c].f32 = y; } } @@ -47034,16 +37057,16 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32); const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { - ma_int32 r1 = pHPF->pR1[c].s32; + ma_int32 r1 = pHPF->r1[c].s32; ma_int32 x = pX[c]; ma_int32 y; y = (b*x - a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT; - pY[c] = (ma_int16)y; - pHPF->pR1[c].s32 = (ma_int32)y; + pY[c] = (ma_int16)y; + pHPF->r1[c].s32 = (ma_int32)y; } } @@ -47106,8 +37129,8 @@ static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_confi q = pConfig->q; w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); + s = ma_sin(w); + c = ma_cos(w); a = s / (2*q); bqConfig.b0 = (1 + c) / 2; @@ -47123,15 +37146,7 @@ static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_confi return bqConfig; } -MA_API ma_result ma_hpf2_get_heap_size(const ma_hpf2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_hpf2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* pHeap, ma_hpf2* pHPF) +MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF) { ma_result result; ma_biquad_config bqConfig; @@ -47147,7 +37162,7 @@ MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* } bqConfig = ma_hpf2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pHPF->bq); + result = ma_biquad_init(&bqConfig, &pHPF->bq); if (result != MA_SUCCESS) { return result; } @@ -47155,45 +37170,6 @@ MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* return MA_SUCCESS; } -MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf2* pHPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_hpf2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_hpf2_init_preallocated(pConfig, pHeap, pHPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pHPF->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_hpf2_uninit(ma_hpf2* pHPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pHPF == NULL) { - return; - } - - ma_biquad_uninit(&pHPF->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF) { ma_result result; @@ -47255,24 +37231,7 @@ MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma return config; } - -typedef struct -{ - size_t sizeInBytes; - size_t hpf1Offset; - size_t hpf2Offset; /* Offset of the first second order filter. Subsequent filters will come straight after, and will each have the same heap size. */ -} ma_hpf_heap_layout; - -static void ma_hpf_calculate_sub_hpf_counts(ma_uint32 order, ma_uint32* pHPF1Count, ma_uint32* pHPF2Count) -{ - MA_ASSERT(pHPF1Count != NULL); - MA_ASSERT(pHPF2Count != NULL); - - *pHPF1Count = order % 2; - *pHPF2Count = order / 2; -} - -static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_heap_layout* pHeapLayout) +static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* pHPF, ma_bool32 isNew) { ma_result result; ma_uint32 hpf1Count; @@ -47280,69 +37239,6 @@ static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_hea ma_uint32 ihpf1; ma_uint32 ihpf2; - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - if (pConfig->order > MA_MAX_FILTER_ORDER) { - return MA_INVALID_ARGS; - } - - ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count); - - pHeapLayout->sizeInBytes = 0; - - /* HPF 1 */ - pHeapLayout->hpf1Offset = pHeapLayout->sizeInBytes; - for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) { - size_t hpf1HeapSizeInBytes; - ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); - - result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += sizeof(ma_hpf1) + hpf1HeapSizeInBytes; - } - - /* HPF 2*/ - pHeapLayout->hpf2Offset = pHeapLayout->sizeInBytes; - for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) { - size_t hpf2HeapSizeInBytes; - ma_hpf2_config hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107); /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */ - - result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += sizeof(ma_hpf2) + hpf2HeapSizeInBytes; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pHPF, ma_bool32 isNew) -{ - ma_result result; - ma_uint32 hpf1Count; - ma_uint32 hpf2Count; - ma_uint32 ihpf1; - ma_uint32 ihpf2; - ma_hpf_heap_layout heapLayout; /* Only used if isNew is true. */ - if (pHPF == NULL || pConfig == NULL) { return MA_INVALID_ARGS; } @@ -47366,7 +37262,11 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe return MA_INVALID_ARGS; } - ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count); + hpf1Count = pConfig->order % 2; + hpf2Count = pConfig->order / 2; + + MA_ASSERT(hpf1Count <= ma_countof(pHPF->hpf1)); + MA_ASSERT(hpf2Count <= ma_countof(pHPF->hpf2)); /* The filter order can't change between reinits. */ if (!isNew) { @@ -47375,42 +37275,16 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe } } - if (isNew) { - result = ma_hpf_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pHPF->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pHPF->pHPF1 = (ma_hpf1*)ma_offset_ptr(pHeap, heapLayout.hpf1Offset); - pHPF->pHPF2 = (ma_hpf2*)ma_offset_ptr(pHeap, heapLayout.hpf2Offset); - } else { - MA_ZERO_OBJECT(&heapLayout); /* To silence a compiler warning. */ - } - for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) { ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); if (isNew) { - size_t hpf1HeapSizeInBytes; - - result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes); - if (result == MA_SUCCESS) { - result = ma_hpf1_init_preallocated(&hpf1Config, ma_offset_ptr(pHeap, heapLayout.hpf1Offset + (sizeof(ma_hpf1) * hpf1Count) + (ihpf1 * hpf1HeapSizeInBytes)), &pHPF->pHPF1[ihpf1]); - } + result = ma_hpf1_init(&hpf1Config, &pHPF->hpf1[ihpf1]); } else { - result = ma_hpf1_reinit(&hpf1Config, &pHPF->pHPF1[ihpf1]); + result = ma_hpf1_reinit(&hpf1Config, &pHPF->hpf1[ihpf1]); } if (result != MA_SUCCESS) { - ma_uint32 jhpf1; - - for (jhpf1 = 0; jhpf1 < ihpf1; jhpf1 += 1) { - ma_hpf1_uninit(&pHPF->pHPF1[jhpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ - } - return result; } } @@ -47426,33 +37300,17 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe } else { a = (1 + ihpf2*2) * (MA_PI_D/(pConfig->order*2)); /* Even order. */ } - q = 1 / (2*ma_cosd(a)); + q = 1 / (2*ma_cos(a)); hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q); if (isNew) { - size_t hpf2HeapSizeInBytes; - - result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes); - if (result == MA_SUCCESS) { - result = ma_hpf2_init_preallocated(&hpf2Config, ma_offset_ptr(pHeap, heapLayout.hpf2Offset + (sizeof(ma_hpf2) * hpf2Count) + (ihpf2 * hpf2HeapSizeInBytes)), &pHPF->pHPF2[ihpf2]); - } + result = ma_hpf2_init(&hpf2Config, &pHPF->hpf2[ihpf2]); } else { - result = ma_hpf2_reinit(&hpf2Config, &pHPF->pHPF2[ihpf2]); + result = ma_hpf2_reinit(&hpf2Config, &pHPF->hpf2[ihpf2]); } if (result != MA_SUCCESS) { - ma_uint32 jhpf1; - ma_uint32 jhpf2; - - for (jhpf1 = 0; jhpf1 < hpf1Count; jhpf1 += 1) { - ma_hpf1_uninit(&pHPF->pHPF1[jhpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ - } - - for (jhpf2 = 0; jhpf2 < ihpf2; jhpf2 += 1) { - ma_hpf2_uninit(&pHPF->pHPF2[jhpf2], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ - } - return result; } } @@ -47466,93 +37324,24 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe return MA_SUCCESS; } -MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes) +MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF) { - ma_result result; - ma_hpf_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_hpf_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return result; -} - -MA_API ma_result ma_hpf_init_preallocated(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pLPF) -{ - if (pLPF == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pLPF); - - return ma_hpf_reinit__internal(pConfig, pHeap, pLPF, /*isNew*/MA_TRUE); -} - -MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf* pHPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_hpf_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_hpf_init_preallocated(pConfig, pHeap, pHPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pHPF->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_hpf_uninit(ma_hpf* pHPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_uint32 ihpf1; - ma_uint32 ihpf2; - if (pHPF == NULL) { - return; + return MA_INVALID_ARGS; } - for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - ma_hpf1_uninit(&pHPF->pHPF1[ihpf1], pAllocationCallbacks); + MA_ZERO_OBJECT(pHPF); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - ma_hpf2_uninit(&pHPF->pHPF2[ihpf2], pAllocationCallbacks); - } - - if (pHPF->_ownsHeap) { - ma_free(pHPF->_pHeap, pAllocationCallbacks); - } + return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_TRUE); } MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF) { - return ma_hpf_reinit__internal(pConfig, NULL, pHPF, /*isNew*/MA_FALSE); + return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_FALSE); } MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) @@ -47568,14 +37357,14 @@ MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const /* Faster path for in-place. */ if (pFramesOut == pFramesIn) { for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - result = ma_hpf1_process_pcm_frames(&pHPF->pHPF1[ihpf1], pFramesOut, pFramesOut, frameCount); + result = ma_hpf1_process_pcm_frames(&pHPF->hpf1[ihpf1], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } } for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - result = ma_hpf2_process_pcm_frames(&pHPF->pHPF2[ihpf2], pFramesOut, pFramesOut, frameCount); + result = ma_hpf2_process_pcm_frames(&pHPF->hpf2[ihpf2], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } @@ -47594,11 +37383,11 @@ MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pHPF->format, pHPF->channels)); for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - ma_hpf1_process_pcm_frame_f32(&pHPF->pHPF1[ihpf1], pFramesOutF32, pFramesOutF32); + ma_hpf1_process_pcm_frame_f32(&pHPF->hpf1[ihpf1], pFramesOutF32, pFramesOutF32); } for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - ma_hpf2_process_pcm_frame_f32(&pHPF->pHPF2[ihpf2], pFramesOutF32, pFramesOutF32); + ma_hpf2_process_pcm_frame_f32(&pHPF->hpf2[ihpf2], pFramesOutF32, pFramesOutF32); } pFramesOutF32 += pHPF->channels; @@ -47612,11 +37401,11 @@ MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pHPF->format, pHPF->channels)); for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - ma_hpf1_process_pcm_frame_s16(&pHPF->pHPF1[ihpf1], pFramesOutS16, pFramesOutS16); + ma_hpf1_process_pcm_frame_s16(&pHPF->hpf1[ihpf1], pFramesOutS16, pFramesOutS16); } for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - ma_hpf2_process_pcm_frame_s16(&pHPF->pHPF2[ihpf2], pFramesOutS16, pFramesOutS16); + ma_hpf2_process_pcm_frame_s16(&pHPF->hpf2[ihpf2], pFramesOutS16, pFramesOutS16); } pFramesOutS16 += pHPF->channels; @@ -47679,8 +37468,8 @@ static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_confi q = pConfig->q; w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); + s = ma_sin(w); + c = ma_cos(w); a = s / (2*q); bqConfig.b0 = q * a; @@ -47696,15 +37485,7 @@ static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_confi return bqConfig; } -MA_API ma_result ma_bpf2_get_heap_size(const ma_bpf2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_bpf2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* pHeap, ma_bpf2* pBPF) +MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF) { ma_result result; ma_biquad_config bqConfig; @@ -47720,7 +37501,7 @@ MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* } bqConfig = ma_bpf2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pBPF->bq); + result = ma_biquad_init(&bqConfig, &pBPF->bq); if (result != MA_SUCCESS) { return result; } @@ -47728,45 +37509,6 @@ MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* return MA_SUCCESS; } -MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf2* pBPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_bpf2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_bpf2_init_preallocated(pConfig, pHeap, pBPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pBPF->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_bpf2_uninit(ma_bpf2* pBPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pBPF == NULL) { - return; - } - - ma_biquad_uninit(&pBPF->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF) { ma_result result; @@ -47828,67 +37570,12 @@ MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma return config; } - -typedef struct -{ - size_t sizeInBytes; - size_t bpf2Offset; -} ma_bpf_heap_layout; - -static ma_result ma_bpf_get_heap_layout(const ma_bpf_config* pConfig, ma_bpf_heap_layout* pHeapLayout) +static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* pBPF, ma_bool32 isNew) { ma_result result; ma_uint32 bpf2Count; ma_uint32 ibpf2; - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->order > MA_MAX_FILTER_ORDER) { - return MA_INVALID_ARGS; - } - - /* We must have an even number of order. */ - if ((pConfig->order & 0x1) != 0) { - return MA_INVALID_ARGS; - } - - bpf2Count = pConfig->order / 2; - - pHeapLayout->sizeInBytes = 0; - - /* BPF 2 */ - pHeapLayout->bpf2Offset = pHeapLayout->sizeInBytes; - for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) { - size_t bpf2HeapSizeInBytes; - ma_bpf2_config bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107); /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */ - - result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += sizeof(ma_bpf2) + bpf2HeapSizeInBytes; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF, ma_bool32 isNew) -{ - ma_result result; - ma_uint32 bpf2Count; - ma_uint32 ibpf2; - ma_bpf_heap_layout heapLayout; /* Only used if isNew is true. */ - if (pBPF == NULL || pConfig == NULL) { return MA_INVALID_ARGS; } @@ -47919,6 +37606,8 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHe bpf2Count = pConfig->order / 2; + MA_ASSERT(bpf2Count <= ma_countof(pBPF->bpf2)); + /* The filter order can't change between reinits. */ if (!isNew) { if (pBPF->bpf2Count != bpf2Count) { @@ -47926,20 +37615,6 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHe } } - if (isNew) { - result = ma_bpf_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pBPF->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pBPF->pBPF2 = (ma_bpf2*)ma_offset_ptr(pHeap, heapLayout.bpf2Offset); - } else { - MA_ZERO_OBJECT(&heapLayout); - } - for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) { ma_bpf2_config bpf2Config; double q; @@ -47950,14 +37625,9 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHe bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q); if (isNew) { - size_t bpf2HeapSizeInBytes; - - result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes); - if (result == MA_SUCCESS) { - result = ma_bpf2_init_preallocated(&bpf2Config, ma_offset_ptr(pHeap, heapLayout.bpf2Offset + (sizeof(ma_bpf2) * bpf2Count) + (ibpf2 * bpf2HeapSizeInBytes)), &pBPF->pBPF2[ibpf2]); - } + result = ma_bpf2_init(&bpf2Config, &pBPF->bpf2[ibpf2]); } else { - result = ma_bpf2_reinit(&bpf2Config, &pBPF->pBPF2[ibpf2]); + result = ma_bpf2_reinit(&bpf2Config, &pBPF->bpf2[ibpf2]); } if (result != MA_SUCCESS) { @@ -47972,29 +37642,7 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHe return MA_SUCCESS; } - -MA_API ma_result ma_bpf_get_heap_size(const ma_bpf_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_bpf_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_bpf_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF) +MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF) { if (pBPF == NULL) { return MA_INVALID_ARGS; @@ -48002,59 +37650,16 @@ MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pH MA_ZERO_OBJECT(pBPF); - return ma_bpf_reinit__internal(pConfig, pHeap, pBPF, /*isNew*/MA_TRUE); -} - -MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf* pBPF) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_bpf_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_bpf_init_preallocated(pConfig, pHeap, pBPF); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pBPF->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_bpf_uninit(ma_bpf* pBPF, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_uint32 ibpf2; - - if (pBPF == NULL) { - return; - } - - for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - ma_bpf2_uninit(&pBPF->pBPF2[ibpf2], pAllocationCallbacks); - } - - if (pBPF->_ownsHeap) { - ma_free(pBPF->_pHeap, pAllocationCallbacks); - } + return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_TRUE); } MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF) { - return ma_bpf_reinit__internal(pConfig, NULL, pBPF, /*isNew*/MA_FALSE); + return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_FALSE); } MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) @@ -48069,7 +37674,7 @@ MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const /* Faster path for in-place. */ if (pFramesOut == pFramesIn) { for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - result = ma_bpf2_process_pcm_frames(&pBPF->pBPF2[ibpf2], pFramesOut, pFramesOut, frameCount); + result = ma_bpf2_process_pcm_frames(&pBPF->bpf2[ibpf2], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } @@ -48088,7 +37693,7 @@ MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pBPF->format, pBPF->channels)); for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - ma_bpf2_process_pcm_frame_f32(&pBPF->pBPF2[ibpf2], pFramesOutF32, pFramesOutF32); + ma_bpf2_process_pcm_frame_f32(&pBPF->bpf2[ibpf2], pFramesOutF32, pFramesOutF32); } pFramesOutF32 += pBPF->channels; @@ -48102,7 +37707,7 @@ MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pBPF->format, pBPF->channels)); for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - ma_bpf2_process_pcm_frame_s16(&pBPF->pBPF2[ibpf2], pFramesOutS16, pFramesOutS16); + ma_bpf2_process_pcm_frame_s16(&pBPF->bpf2[ibpf2], pFramesOutS16, pFramesOutS16); } pFramesOutS16 += pBPF->channels; @@ -48164,8 +37769,8 @@ static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_c q = pConfig->q; w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); + s = ma_sin(w); + c = ma_cos(w); a = s / (2*q); bqConfig.b0 = 1; @@ -48181,15 +37786,7 @@ static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_c return bqConfig; } -MA_API ma_result ma_notch2_get_heap_size(const ma_notch2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_notch2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, void* pHeap, ma_notch2* pFilter) +MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -48205,7 +37802,7 @@ MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, vo } bqConfig = ma_notch2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + result = ma_biquad_init(&bqConfig, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -48213,45 +37810,6 @@ MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, vo return MA_SUCCESS; } -MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch2* pFilter) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_notch2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_notch2_init_preallocated(pConfig, pHeap, pFilter); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_notch2_uninit(ma_notch2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pFilter == NULL) { - return; - } - - ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter) { ma_result result; @@ -48339,10 +37897,10 @@ static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_con q = pConfig->q; w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); + s = ma_sin(w); + c = ma_cos(w); a = s / (2*q); - A = ma_powd(10, (pConfig->gainDB / 40)); + A = ma_pow(10, (pConfig->gainDB / 40)); bqConfig.b0 = 1 + (a * A); bqConfig.b1 = -2 * c; @@ -48357,15 +37915,7 @@ static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_con return bqConfig; } -MA_API ma_result ma_peak2_get_heap_size(const ma_peak2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_peak2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void* pHeap, ma_peak2* pFilter) +MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -48381,7 +37931,7 @@ MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void } bqConfig = ma_peak2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + result = ma_biquad_init(&bqConfig, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -48389,45 +37939,6 @@ MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void return MA_SUCCESS; } -MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak2* pFilter) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_peak2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_peak2_init_preallocated(pConfig, pHeap, pFilter); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_peak2_uninit(ma_peak2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pFilter == NULL) { - return; - } - - ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter) { ma_result result; @@ -48510,12 +38021,12 @@ static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshel MA_ASSERT(pConfig != NULL); w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); - A = ma_powd(10, (pConfig->gainDB / 40)); + s = ma_sin(w); + c = ma_cos(w); + A = ma_pow(10, (pConfig->gainDB / 40)); S = pConfig->shelfSlope; - a = s/2 * ma_sqrtd((A + 1/A) * (1/S - 1) + 2); - sqrtA = 2*ma_sqrtd(A)*a; + a = s/2 * ma_sqrt((A + 1/A) * (1/S - 1) + 2); + sqrtA = 2*ma_sqrt(A)*a; bqConfig.b0 = A * ((A + 1) - (A - 1)*c + sqrtA); bqConfig.b1 = 2 * A * ((A - 1) - (A + 1)*c); @@ -48530,15 +38041,7 @@ static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshel return bqConfig; } -MA_API ma_result ma_loshelf2_get_heap_size(const ma_loshelf2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_loshelf2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig, void* pHeap, ma_loshelf2* pFilter) +MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -48554,7 +38057,7 @@ MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig } bqConfig = ma_loshelf2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + result = ma_biquad_init(&bqConfig, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -48562,45 +38065,6 @@ MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig return MA_SUCCESS; } -MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf2* pFilter) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_loshelf2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_loshelf2_init_preallocated(pConfig, pHeap, pFilter); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_loshelf2_uninit(ma_loshelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pFilter == NULL) { - return; - } - - ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter) { ma_result result; @@ -48683,12 +38147,12 @@ static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishel MA_ASSERT(pConfig != NULL); w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate; - s = ma_sind(w); - c = ma_cosd(w); - A = ma_powd(10, (pConfig->gainDB / 40)); + s = ma_sin(w); + c = ma_cos(w); + A = ma_pow(10, (pConfig->gainDB / 40)); S = pConfig->shelfSlope; - a = s/2 * ma_sqrtd((A + 1/A) * (1/S - 1) + 2); - sqrtA = 2*ma_sqrtd(A)*a; + a = s/2 * ma_sqrt((A + 1/A) * (1/S - 1) + 2); + sqrtA = 2*ma_sqrt(A)*a; bqConfig.b0 = A * ((A + 1) + (A - 1)*c + sqrtA); bqConfig.b1 = -2 * A * ((A - 1) + (A + 1)*c); @@ -48703,15 +38167,7 @@ static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishel return bqConfig; } -MA_API ma_result ma_hishelf2_get_heap_size(const ma_hishelf2_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_biquad_config bqConfig; - bqConfig = ma_hishelf2__get_biquad_config(pConfig); - - return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); -} - -MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig, void* pHeap, ma_hishelf2* pFilter) +MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -48727,7 +38183,7 @@ MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig } bqConfig = ma_hishelf2__get_biquad_config(pConfig); - result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + result = ma_biquad_init(&bqConfig, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -48735,45 +38191,6 @@ MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig return MA_SUCCESS; } -MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf2* pFilter) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_hishelf2_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_hishelf2_init_preallocated(pConfig, pHeap, pFilter); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ - return MA_SUCCESS; -} - -MA_API void ma_hishelf2_uninit(ma_hishelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pFilter == NULL) { - return; - } - - ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ -} - MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter) { ma_result result; @@ -48822,2660 +38239,6 @@ MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter) -/* -Delay -*/ -MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay) -{ - ma_delay_config config; - - MA_ZERO_OBJECT(&config); - config.channels = channels; - config.sampleRate = sampleRate; - config.delayInFrames = delayInFrames; - config.delayStart = (decay == 0) ? MA_TRUE : MA_FALSE; /* Delay the start if it looks like we're not configuring an echo. */ - config.wet = 1; - config.dry = 1; - config.decay = decay; - - return config; -} - - -MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay) -{ - if (pDelay == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDelay); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->decay < 0 || pConfig->decay > 1) { - return MA_INVALID_ARGS; - } - - pDelay->config = *pConfig; - pDelay->bufferSizeInFrames = pConfig->delayInFrames; - pDelay->cursor = 0; - - pDelay->pBuffer = (float*)ma_malloc((size_t)(pDelay->bufferSizeInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->channels)), pAllocationCallbacks); - if (pDelay->pBuffer == NULL) { - return MA_OUT_OF_MEMORY; - } - - ma_silence_pcm_frames(pDelay->pBuffer, pDelay->bufferSizeInFrames, ma_format_f32, pConfig->channels); - - return MA_SUCCESS; -} - -MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pDelay == NULL) { - return; - } - - ma_free(pDelay->pBuffer, pAllocationCallbacks); -} - -MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) -{ - ma_uint32 iFrame; - ma_uint32 iChannel; - float* pFramesOutF32 = (float*)pFramesOut; - const float* pFramesInF32 = (const float*)pFramesIn; - - if (pDelay == NULL || pFramesOut == NULL || pFramesIn == NULL) { - return MA_INVALID_ARGS; - } - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pDelay->config.channels; iChannel += 1) { - ma_uint32 iBuffer = (pDelay->cursor * pDelay->config.channels) + iChannel; - - if (pDelay->config.delayStart) { - /* Delayed start. */ - - /* Read */ - pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet; - - /* Feedback */ - pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry); - } else { - /* Immediate start */ - - /* Feedback */ - pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry); - - /* Read */ - pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet; - } - } - - pDelay->cursor = (pDelay->cursor + 1) % pDelay->bufferSizeInFrames; - - pFramesOutF32 += pDelay->config.channels; - pFramesInF32 += pDelay->config.channels; - } - - return MA_SUCCESS; -} - -MA_API void ma_delay_set_wet(ma_delay* pDelay, float value) -{ - if (pDelay == NULL) { - return; - } - - pDelay->config.wet = value; -} - -MA_API float ma_delay_get_wet(const ma_delay* pDelay) -{ - if (pDelay == NULL) { - return 0; - } - - return pDelay->config.wet; -} - -MA_API void ma_delay_set_dry(ma_delay* pDelay, float value) -{ - if (pDelay == NULL) { - return; - } - - pDelay->config.dry = value; -} - -MA_API float ma_delay_get_dry(const ma_delay* pDelay) -{ - if (pDelay == NULL) { - return 0; - } - - return pDelay->config.dry; -} - -MA_API void ma_delay_set_decay(ma_delay* pDelay, float value) -{ - if (pDelay == NULL) { - return; - } - - pDelay->config.decay = value; -} - -MA_API float ma_delay_get_decay(const ma_delay* pDelay) -{ - if (pDelay == NULL) { - return 0; - } - - return pDelay->config.decay; -} - - -MA_API ma_gainer_config ma_gainer_config_init(ma_uint32 channels, ma_uint32 smoothTimeInFrames) -{ - ma_gainer_config config; - - MA_ZERO_OBJECT(&config); - config.channels = channels; - config.smoothTimeInFrames = smoothTimeInFrames; - - return config; -} - - -typedef struct -{ - size_t sizeInBytes; - size_t oldGainsOffset; - size_t newGainsOffset; -} ma_gainer_heap_layout; - -static ma_result ma_gainer_get_heap_layout(const ma_gainer_config* pConfig, ma_gainer_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Old gains. */ - pHeapLayout->oldGainsOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; - - /* New gains. */ - pHeapLayout->newGainsOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; - - /* Alignment. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - - -MA_API ma_result ma_gainer_get_heap_size(const ma_gainer_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_gainer_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_gainer_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - - -MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, void* pHeap, ma_gainer* pGainer) -{ - ma_result result; - ma_gainer_heap_layout heapLayout; - ma_uint32 iChannel; - - if (pGainer == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pGainer); - - if (pConfig == NULL || pHeap == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_gainer_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pGainer->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pGainer->pOldGains = (float*)ma_offset_ptr(pHeap, heapLayout.oldGainsOffset); - pGainer->pNewGains = (float*)ma_offset_ptr(pHeap, heapLayout.newGainsOffset); - pGainer->masterVolume = 1; - - pGainer->config = *pConfig; - pGainer->t = (ma_uint32)-1; /* No interpolation by default. */ - - for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { - pGainer->pOldGains[iChannel] = 1; - pGainer->pNewGains[iChannel] = 1; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_gainer_init(const ma_gainer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_gainer* pGainer) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_gainer_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the size of the heap allocation. */ - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_gainer_init_preallocated(pConfig, pHeap, pGainer); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pGainer->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pGainer == NULL) { - return; - } - - if (pGainer->_ownsHeap) { - ma_free(pGainer->_pHeap, pAllocationCallbacks); - } -} - -static float ma_gainer_calculate_current_gain(const ma_gainer* pGainer, ma_uint32 channel) -{ - float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames; - return ma_mix_f32_fast(pGainer->pOldGains[channel], pGainer->pNewGains[channel], a); -} - -static /*__attribute__((noinline))*/ ma_result ma_gainer_process_pcm_frames_internal(ma_gainer * pGainer, void* MA_RESTRICT pFramesOut, const void* MA_RESTRICT pFramesIn, ma_uint64 frameCount) -{ - ma_uint64 iFrame; - ma_uint32 iChannel; - ma_uint64 interpolatedFrameCount; - - MA_ASSERT(pGainer != NULL); - - /* - We don't necessarily need to apply a linear interpolation for the entire frameCount frames. When - linear interpolation is not needed we can do a simple volume adjustment which will be more - efficient than a lerp with an alpha value of 1. - - To do this, all we need to do is determine how many frames need to have a lerp applied. Then we - just process that number of frames with linear interpolation. After that we run on an optimized - path which just applies the new gains without a lerp. - */ - if (pGainer->t >= pGainer->config.smoothTimeInFrames) { - interpolatedFrameCount = 0; - } else { - interpolatedFrameCount = pGainer->t - pGainer->config.smoothTimeInFrames; - if (interpolatedFrameCount > frameCount) { - interpolatedFrameCount = frameCount; - } - } - - /* - Start off with our interpolated frames. When we do this, we'll adjust frameCount and our pointers - so that the fast path can work naturally without consideration of the interpolated path. - */ - if (interpolatedFrameCount > 0) { - /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ - if (pFramesOut != NULL && pFramesIn != NULL) { - /* - All we're really doing here is moving the old gains towards the new gains. We don't want to - be modifying the gains inside the ma_gainer object because that will break things. Instead - we can make a copy here on the stack. For extreme channel counts we can fall back to a slower - implementation which just uses a standard lerp. - */ - float* pFramesOutF32 = (float*)pFramesOut; - const float* pFramesInF32 = (const float*)pFramesIn; - float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames; - float d = 1.0f / pGainer->config.smoothTimeInFrames; - - if (pGainer->config.channels <= 32) { - float pRunningGain[32]; - float pRunningGainDelta[32]; /* Could this be heap-allocated as part of the ma_gainer object? */ - - /* Initialize the running gain. */ - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - float t = (pGainer->pNewGains[iChannel] - pGainer->pOldGains[iChannel]) * pGainer->masterVolume; - pRunningGainDelta[iChannel] = t * d; - pRunningGain[iChannel] = (pGainer->pOldGains[iChannel] * pGainer->masterVolume) + (t * a); - } - - iFrame = 0; - - /* Optimized paths for common channel counts. This is mostly just experimenting with some SIMD ideas. It's not necessarily final. */ - if (pGainer->config.channels == 2) { - #if defined(MA_SUPPORT_SSE2) - if (ma_has_sse2()) { - ma_uint64 unrolledLoopCount = interpolatedFrameCount >> 1; - - /* Expand some arrays so we can have a clean SIMD loop below. */ - __m128 runningGainDelta0 = _mm_set_ps(pRunningGainDelta[1], pRunningGainDelta[0], pRunningGainDelta[1], pRunningGainDelta[0]); - __m128 runningGain0 = _mm_set_ps(pRunningGain[1] + pRunningGainDelta[1], pRunningGain[0] + pRunningGainDelta[0], pRunningGain[1], pRunningGain[0]); - - for (; iFrame < unrolledLoopCount; iFrame += 1) { - _mm_storeu_ps(&pFramesOutF32[iFrame*4 + 0], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*4 + 0]), runningGain0)); - runningGain0 = _mm_add_ps(runningGain0, runningGainDelta0); - } - - iFrame = unrolledLoopCount << 1; - } else - #endif - { - /* - Two different scalar implementations here. Clang (and I assume GCC) will vectorize - both of these, but the bottom version results in a nicer vectorization with less - instructions emitted. The problem, however, is that the bottom version runs slower - when compiled with MSVC. The top version will be partially vectorized by MSVC. - */ - #if defined(_MSC_VER) && !defined(__clang__) - ma_uint64 unrolledLoopCount = interpolatedFrameCount >> 1; - - /* Expand some arrays so we can have a clean 4x SIMD operation in the loop. */ - pRunningGainDelta[2] = pRunningGainDelta[0]; - pRunningGainDelta[3] = pRunningGainDelta[1]; - pRunningGain[2] = pRunningGain[0] + pRunningGainDelta[0]; - pRunningGain[3] = pRunningGain[1] + pRunningGainDelta[1]; - - for (; iFrame < unrolledLoopCount; iFrame += 1) { - pFramesOutF32[iFrame*4 + 0] = pFramesInF32[iFrame*4 + 0] * pRunningGain[0]; - pFramesOutF32[iFrame*4 + 1] = pFramesInF32[iFrame*4 + 1] * pRunningGain[1]; - pFramesOutF32[iFrame*4 + 2] = pFramesInF32[iFrame*4 + 2] * pRunningGain[2]; - pFramesOutF32[iFrame*4 + 3] = pFramesInF32[iFrame*4 + 3] * pRunningGain[3]; - - /* Move the running gain forward towards the new gain. */ - pRunningGain[0] += pRunningGainDelta[0]; - pRunningGain[1] += pRunningGainDelta[1]; - pRunningGain[2] += pRunningGainDelta[2]; - pRunningGain[3] += pRunningGainDelta[3]; - } - - iFrame = unrolledLoopCount << 1; - #else - for (; iFrame < interpolatedFrameCount; iFrame += 1) { - for (iChannel = 0; iChannel < 2; iChannel += 1) { - pFramesOutF32[iFrame*2 + iChannel] = pFramesInF32[iFrame*2 + iChannel] * pRunningGain[iChannel]; - } - - for (iChannel = 0; iChannel < 2; iChannel += 1) { - pRunningGain[iChannel] += pRunningGainDelta[iChannel]; - } - } - #endif - } - } else if (pGainer->config.channels == 6) { - #if defined(MA_SUPPORT_SSE2) - if (ma_has_sse2()) { - /* - For 6 channels things are a bit more complicated because 6 isn't cleanly divisible by 4. We need to do 2 frames - at a time, meaning we'll be doing 12 samples in a group. Like the stereo case we'll need to expand some arrays - so we can do clean 4x SIMD operations. - */ - ma_uint64 unrolledLoopCount = interpolatedFrameCount >> 1; - - /* Expand some arrays so we can have a clean SIMD loop below. */ - __m128 runningGainDelta0 = _mm_set_ps(pRunningGainDelta[3], pRunningGainDelta[2], pRunningGainDelta[1], pRunningGainDelta[0]); - __m128 runningGainDelta1 = _mm_set_ps(pRunningGainDelta[1], pRunningGainDelta[0], pRunningGainDelta[5], pRunningGainDelta[4]); - __m128 runningGainDelta2 = _mm_set_ps(pRunningGainDelta[5], pRunningGainDelta[4], pRunningGainDelta[3], pRunningGainDelta[2]); - - __m128 runningGain0 = _mm_set_ps(pRunningGain[3], pRunningGain[2], pRunningGain[1], pRunningGain[0]); - __m128 runningGain1 = _mm_set_ps(pRunningGain[1] + pRunningGainDelta[1], pRunningGain[0] + pRunningGainDelta[0], pRunningGain[5], pRunningGain[4]); - __m128 runningGain2 = _mm_set_ps(pRunningGain[5] + pRunningGainDelta[5], pRunningGain[4] + pRunningGainDelta[4], pRunningGain[3] + pRunningGainDelta[3], pRunningGain[2] + pRunningGainDelta[2]); - - for (; iFrame < unrolledLoopCount; iFrame += 1) { - _mm_storeu_ps(&pFramesOutF32[iFrame*12 + 0], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12 + 0]), runningGain0)); - _mm_storeu_ps(&pFramesOutF32[iFrame*12 + 4], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12 + 4]), runningGain1)); - _mm_storeu_ps(&pFramesOutF32[iFrame*12 + 8], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12 + 8]), runningGain2)); - - runningGain0 = _mm_add_ps(runningGain0, runningGainDelta0); - runningGain1 = _mm_add_ps(runningGain1, runningGainDelta1); - runningGain2 = _mm_add_ps(runningGain2, runningGainDelta2); - } - - iFrame = unrolledLoopCount << 1; - } else - #endif - { - for (; iFrame < interpolatedFrameCount; iFrame += 1) { - for (iChannel = 0; iChannel < 6; iChannel += 1) { - pFramesOutF32[iFrame*6 + iChannel] = pFramesInF32[iFrame*6 + iChannel] * pRunningGain[iChannel]; - } - - /* Move the running gain forward towards the new gain. */ - for (iChannel = 0; iChannel < 6; iChannel += 1) { - pRunningGain[iChannel] += pRunningGainDelta[iChannel]; - } - } - } - } else if (pGainer->config.channels == 8) { - /* For 8 channels we can just go over frame by frame and do all eight channels as 2 separate 4x SIMD operations. */ - #if defined(MA_SUPPORT_SSE2) - if (ma_has_sse2()) { - __m128 runningGainDelta0 = _mm_loadu_ps(&pRunningGainDelta[0]); - __m128 runningGainDelta1 = _mm_loadu_ps(&pRunningGainDelta[4]); - __m128 runningGain0 = _mm_loadu_ps(&pRunningGain[0]); - __m128 runningGain1 = _mm_loadu_ps(&pRunningGain[4]); - - for (; iFrame < interpolatedFrameCount; iFrame += 1) { - _mm_storeu_ps(&pFramesOutF32[iFrame*8 + 0], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*8 + 0]), runningGain0)); - _mm_storeu_ps(&pFramesOutF32[iFrame*8 + 4], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*8 + 4]), runningGain1)); - - runningGain0 = _mm_add_ps(runningGain0, runningGainDelta0); - runningGain1 = _mm_add_ps(runningGain1, runningGainDelta1); - } - } else - #endif - { - /* This is crafted so that it auto-vectorizes when compiled with Clang. */ - for (; iFrame < interpolatedFrameCount; iFrame += 1) { - for (iChannel = 0; iChannel < 8; iChannel += 1) { - pFramesOutF32[iFrame*8 + iChannel] = pFramesInF32[iFrame*8 + iChannel] * pRunningGain[iChannel]; - } - - /* Move the running gain forward towards the new gain. */ - for (iChannel = 0; iChannel < 8; iChannel += 1) { - pRunningGain[iChannel] += pRunningGainDelta[iChannel]; - } - } - } - } - - for (; iFrame < interpolatedFrameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * pRunningGain[iChannel]; - pRunningGain[iChannel] += pRunningGainDelta[iChannel]; - } - } - } else { - /* Slower path for extreme channel counts where we can't fit enough on the stack. We could also move this to the heap as part of the ma_gainer object which might even be better since it'll only be updated when the gains actually change. */ - for (iFrame = 0; iFrame < interpolatedFrameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a) * pGainer->masterVolume; - } - - a += d; - } - } - } - - /* Make sure the timer is updated. */ - pGainer->t = (ma_uint32)ma_min(pGainer->t + interpolatedFrameCount, pGainer->config.smoothTimeInFrames); - - /* Adjust our arguments so the next part can work normally. */ - frameCount -= interpolatedFrameCount; - pFramesOut = ma_offset_ptr(pFramesOut, interpolatedFrameCount * sizeof(float)); - pFramesIn = ma_offset_ptr(pFramesIn, interpolatedFrameCount * sizeof(float)); - } - - /* All we need to do here is apply the new gains using an optimized path. */ - if (pFramesOut != NULL && pFramesIn != NULL) { - if (pGainer->config.channels <= 32) { - float gains[32]; - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - gains[iChannel] = pGainer->pNewGains[iChannel] * pGainer->masterVolume; - } - - ma_copy_and_apply_volume_factor_per_channel_f32((float*)pFramesOut, (const float*)pFramesIn, frameCount, pGainer->config.channels, gains); - } else { - /* Slow path. Too many channels to fit on the stack. Need to apply a master volume as a separate path. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - ((float*)pFramesOut)[iFrame*pGainer->config.channels + iChannel] = ((const float*)pFramesIn)[iFrame*pGainer->config.channels + iChannel] * pGainer->pNewGains[iChannel] * pGainer->masterVolume; - } - } - } - } - - /* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */ - if (pGainer->t == (ma_uint32)-1) { - pGainer->t = (ma_uint32)ma_min(pGainer->config.smoothTimeInFrames, frameCount); - } - -#if 0 - if (pGainer->t >= pGainer->config.smoothTimeInFrames) { - /* Fast path. No gain calculation required. */ - ma_copy_and_apply_volume_factor_per_channel_f32(pFramesOutF32, pFramesInF32, frameCount, pGainer->config.channels, pGainer->pNewGains); - ma_apply_volume_factor_f32(pFramesOutF32, frameCount * pGainer->config.channels, pGainer->masterVolume); - - /* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */ - if (pGainer->t == (ma_uint32)-1) { - pGainer->t = pGainer->config.smoothTimeInFrames; - } - } else { - /* Slow path. Need to interpolate the gain for each channel individually. */ - - /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ - if (pFramesOut != NULL && pFramesIn != NULL) { - float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames; - float d = 1.0f / pGainer->config.smoothTimeInFrames; - ma_uint32 channelCount = pGainer->config.channels; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < channelCount; iChannel += 1) { - pFramesOutF32[iChannel] = pFramesInF32[iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a) * pGainer->masterVolume; - } - - pFramesOutF32 += channelCount; - pFramesInF32 += channelCount; - - a += d; - if (a > 1) { - a = 1; - } - } - } - - pGainer->t = (ma_uint32)ma_min(pGainer->t + frameCount, pGainer->config.smoothTimeInFrames); - - #if 0 /* Reference implementation. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ - if (pFramesOut != NULL && pFramesIn != NULL) { - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - pFramesOutF32[iFrame * pGainer->config.channels + iChannel] = pFramesInF32[iFrame * pGainer->config.channels + iChannel] * ma_gainer_calculate_current_gain(pGainer, iChannel) * pGainer->masterVolume; - } - } - - /* Move interpolation time forward, but don't go beyond our smoothing time. */ - pGainer->t = ma_min(pGainer->t + 1, pGainer->config.smoothTimeInFrames); - } - #endif - } -#endif - - return MA_SUCCESS; -} - -MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) -{ - if (pGainer == NULL) { - return MA_INVALID_ARGS; - } - - /* - ma_gainer_process_pcm_frames_internal() marks pFramesOut and pFramesIn with MA_RESTRICT which - helps with auto-vectorization. - */ - return ma_gainer_process_pcm_frames_internal(pGainer, pFramesOut, pFramesIn, frameCount); -} - -static void ma_gainer_set_gain_by_index(ma_gainer* pGainer, float newGain, ma_uint32 iChannel) -{ - pGainer->pOldGains[iChannel] = ma_gainer_calculate_current_gain(pGainer, iChannel); - pGainer->pNewGains[iChannel] = newGain; -} - -static void ma_gainer_reset_smoothing_time(ma_gainer* pGainer) -{ - if (pGainer->t == (ma_uint32)-1) { - pGainer->t = pGainer->config.smoothTimeInFrames; /* No smoothing required for initial gains setting. */ - } else { - pGainer->t = 0; - } -} - -MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain) -{ - ma_uint32 iChannel; - - if (pGainer == NULL) { - return MA_INVALID_ARGS; - } - - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - ma_gainer_set_gain_by_index(pGainer, newGain, iChannel); - } - - /* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */ - ma_gainer_reset_smoothing_time(pGainer); - - return MA_SUCCESS; -} - -MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains) -{ - ma_uint32 iChannel; - - if (pGainer == NULL || pNewGains == NULL) { - return MA_INVALID_ARGS; - } - - for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - ma_gainer_set_gain_by_index(pGainer, pNewGains[iChannel], iChannel); - } - - /* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */ - ma_gainer_reset_smoothing_time(pGainer); - - return MA_SUCCESS; -} - -MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume) -{ - if (pGainer == NULL) { - return MA_INVALID_ARGS; - } - - pGainer->masterVolume = volume; - - return MA_SUCCESS; -} - -MA_API ma_result ma_gainer_get_master_volume(const ma_gainer* pGainer, float* pVolume) -{ - if (pGainer == NULL || pVolume == NULL) { - return MA_INVALID_ARGS; - } - - *pVolume = pGainer->masterVolume; - - return MA_SUCCESS; -} - - -MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels) -{ - ma_panner_config config; - - MA_ZERO_OBJECT(&config); - config.format = format; - config.channels = channels; - config.mode = ma_pan_mode_balance; /* Set to balancing mode by default because it's consistent with other audio engines and most likely what the caller is expecting. */ - config.pan = 0; - - return config; -} - - -MA_API ma_result ma_panner_init(const ma_panner_config* pConfig, ma_panner* pPanner) -{ - if (pPanner == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pPanner); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - pPanner->format = pConfig->format; - pPanner->channels = pConfig->channels; - pPanner->mode = pConfig->mode; - pPanner->pan = pConfig->pan; - - return MA_SUCCESS; -} - -static void ma_stereo_balance_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, float pan) -{ - ma_uint64 iFrame; - - if (pan > 0) { - float factor = 1.0f - pan; - if (pFramesOut == pFramesIn) { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0] * factor; - } - } else { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0] * factor; - pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1]; - } - } - } else { - float factor = 1.0f + pan; - if (pFramesOut == pFramesIn) { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1] * factor; - } - } else { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0]; - pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1] * factor; - } - } - } -} - -static void ma_stereo_balance_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, float pan) -{ - if (pan == 0) { - /* Fast path. No panning required. */ - if (pFramesOut == pFramesIn) { - /* No-op */ - } else { - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); - } - - return; - } - - switch (format) { - case ma_format_f32: ma_stereo_balance_pcm_frames_f32((float*)pFramesOut, (float*)pFramesIn, frameCount, pan); break; - - /* Unknown format. Just copy. */ - default: - { - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); - } break; - } -} - - -static void ma_stereo_pan_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, float pan) -{ - ma_uint64 iFrame; - - if (pan > 0) { - float factorL0 = 1.0f - pan; - float factorL1 = 0.0f + pan; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float sample0 = (pFramesIn[iFrame*2 + 0] * factorL0); - float sample1 = (pFramesIn[iFrame*2 + 0] * factorL1) + pFramesIn[iFrame*2 + 1]; - - pFramesOut[iFrame*2 + 0] = sample0; - pFramesOut[iFrame*2 + 1] = sample1; - } - } else { - float factorR0 = 0.0f - pan; - float factorR1 = 1.0f + pan; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float sample0 = pFramesIn[iFrame*2 + 0] + (pFramesIn[iFrame*2 + 1] * factorR0); - float sample1 = (pFramesIn[iFrame*2 + 1] * factorR1); - - pFramesOut[iFrame*2 + 0] = sample0; - pFramesOut[iFrame*2 + 1] = sample1; - } - } -} - -static void ma_stereo_pan_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, float pan) -{ - if (pan == 0) { - /* Fast path. No panning required. */ - if (pFramesOut == pFramesIn) { - /* No-op */ - } else { - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); - } - - return; - } - - switch (format) { - case ma_format_f32: ma_stereo_pan_pcm_frames_f32((float*)pFramesOut, (float*)pFramesIn, frameCount, pan); break; - - /* Unknown format. Just copy. */ - default: - { - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); - } break; - } -} - -MA_API ma_result ma_panner_process_pcm_frames(ma_panner* pPanner, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) -{ - if (pPanner == NULL || pFramesOut == NULL || pFramesIn == NULL) { - return MA_INVALID_ARGS; - } - - if (pPanner->channels == 2) { - /* Stereo case. For now assume channel 0 is left and channel right is 1, but should probably add support for a channel map. */ - if (pPanner->mode == ma_pan_mode_balance) { - ma_stereo_balance_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->pan); - } else { - ma_stereo_pan_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->pan); - } - } else { - if (pPanner->channels == 1) { - /* Panning has no effect on mono streams. */ - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->channels); - } else { - /* For now we're not going to support non-stereo set ups. Not sure how I want to handle this case just yet. */ - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->channels); - } - } - - return MA_SUCCESS; -} - -MA_API void ma_panner_set_mode(ma_panner* pPanner, ma_pan_mode mode) -{ - if (pPanner == NULL) { - return; - } - - pPanner->mode = mode; -} - -MA_API ma_pan_mode ma_panner_get_mode(const ma_panner* pPanner) -{ - if (pPanner == NULL) { - return ma_pan_mode_balance; - } - - return pPanner->mode; -} - -MA_API void ma_panner_set_pan(ma_panner* pPanner, float pan) -{ - if (pPanner == NULL) { - return; - } - - pPanner->pan = ma_clamp(pan, -1.0f, 1.0f); -} - -MA_API float ma_panner_get_pan(const ma_panner* pPanner) -{ - if (pPanner == NULL) { - return 0; - } - - return pPanner->pan; -} - - - - -MA_API ma_fader_config ma_fader_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate) -{ - ma_fader_config config; - - MA_ZERO_OBJECT(&config); - config.format = format; - config.channels = channels; - config.sampleRate = sampleRate; - - return config; -} - - -MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader) -{ - if (pFader == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pFader); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - /* Only f32 is supported for now. */ - if (pConfig->format != ma_format_f32) { - return MA_INVALID_ARGS; - } - - pFader->config = *pConfig; - pFader->volumeBeg = 1; - pFader->volumeEnd = 1; - pFader->lengthInFrames = 0; - pFader->cursorInFrames = 0; - - return MA_SUCCESS; -} - -MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) -{ - if (pFader == NULL) { - return MA_INVALID_ARGS; - } - - /* If the cursor is still negative we need to just copy the absolute number of those frames, but no more than frameCount. */ - if (pFader->cursorInFrames < 0) { - ma_uint64 absCursorInFrames = (ma_uint64)0 - pFader->cursorInFrames; - if (absCursorInFrames > frameCount) { - absCursorInFrames = frameCount; - } - - ma_copy_pcm_frames(pFramesOut, pFramesIn, absCursorInFrames, pFader->config.format, pFader->config.channels); - - pFader->cursorInFrames += absCursorInFrames; - frameCount -= absCursorInFrames; - pFramesOut = ma_offset_ptr(pFramesOut, ma_get_bytes_per_frame(pFader->config.format, pFader->config.channels)*absCursorInFrames); - pFramesIn = ma_offset_ptr(pFramesIn, ma_get_bytes_per_frame(pFader->config.format, pFader->config.channels)*absCursorInFrames); - } - - if (pFader->cursorInFrames >= 0) { - /* - For now we need to clamp frameCount so that the cursor never overflows 32-bits. This is required for - the conversion to a float which we use for the linear interpolation. This might be changed later. - */ - if (frameCount + pFader->cursorInFrames > UINT_MAX) { - frameCount = UINT_MAX - pFader->cursorInFrames; - } - - /* Optimized path if volumeBeg and volumeEnd are equal. */ - if (pFader->volumeBeg == pFader->volumeEnd) { - if (pFader->volumeBeg == 1) { - /* Straight copy. */ - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels); - } else { - /* Copy with volume. */ - ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels, pFader->volumeBeg); - } - } else { - /* Slower path. Volumes are different, so may need to do an interpolation. */ - if ((ma_uint64)pFader->cursorInFrames >= pFader->lengthInFrames) { - /* Fast path. We've gone past the end of the fade period so just apply the end volume to all samples. */ - ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels, pFader->volumeEnd); - } else { - /* Slow path. This is where we do the actual fading. */ - ma_uint64 iFrame; - ma_uint32 iChannel; - - /* For now we only support f32. Support for other formats might be added later. */ - if (pFader->config.format == ma_format_f32) { - const float* pFramesInF32 = (const float*)pFramesIn; - /* */ float* pFramesOutF32 = ( float*)pFramesOut; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float a = (ma_uint32)ma_min(pFader->cursorInFrames + iFrame, pFader->lengthInFrames) / (float)((ma_uint32)pFader->lengthInFrames); /* Safe cast due to the frameCount clamp at the top of this function. */ - float volume = ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, a); - - for (iChannel = 0; iChannel < pFader->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pFader->config.channels + iChannel] = pFramesInF32[iFrame*pFader->config.channels + iChannel] * volume; - } - } - } else { - return MA_NOT_IMPLEMENTED; - } - } - } - } - - pFader->cursorInFrames += frameCount; - - return MA_SUCCESS; -} - -MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) -{ - if (pFader == NULL) { - return; - } - - if (pFormat != NULL) { - *pFormat = pFader->config.format; - } - - if (pChannels != NULL) { - *pChannels = pFader->config.channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pFader->config.sampleRate; - } -} - -MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames) -{ - ma_fader_set_fade_ex(pFader, volumeBeg, volumeEnd, lengthInFrames, 0); -} - -MA_API void ma_fader_set_fade_ex(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames, ma_int64 startOffsetInFrames) -{ - if (pFader == NULL) { - return; - } - - /* If the volume is negative, use current volume. */ - if (volumeBeg < 0) { - volumeBeg = ma_fader_get_current_volume(pFader); - } - - /* - The length needs to be clamped to 32-bits due to how we convert it to a float for linear - interpolation reasons. I might change this requirement later, but for now it's not important. - */ - if (lengthInFrames > UINT_MAX) { - lengthInFrames = UINT_MAX; - } - - /* The start offset needs to be clamped to ensure it doesn't overflow a signed number. */ - if (startOffsetInFrames > INT_MAX) { - startOffsetInFrames = INT_MAX; - } - - pFader->volumeBeg = volumeBeg; - pFader->volumeEnd = volumeEnd; - pFader->lengthInFrames = lengthInFrames; - pFader->cursorInFrames = -startOffsetInFrames; -} - -MA_API float ma_fader_get_current_volume(const ma_fader* pFader) -{ - if (pFader == NULL) { - return 0.0f; - } - - /* Any frames prior to the start of the fade period will be at unfaded volume. */ - if (pFader->cursorInFrames < 0) { - return 1.0f; - } - - /* The current volume depends on the position of the cursor. */ - if (pFader->cursorInFrames == 0) { - return pFader->volumeBeg; - } else if ((ma_uint64)pFader->cursorInFrames >= pFader->lengthInFrames) { /* Safe case because the < 0 case was checked above. */ - return pFader->volumeEnd; - } else { - /* The cursor is somewhere inside the fading period. We can figure this out with a simple linear interpolation between volumeBeg and volumeEnd based on our cursor position. */ - return ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, (ma_uint32)pFader->cursorInFrames / (float)((ma_uint32)pFader->lengthInFrames)); /* Safe cast to uint32 because we clamp it in ma_fader_process_pcm_frames(). */ - } -} - - - - - -MA_API ma_vec3f ma_vec3f_init_3f(float x, float y, float z) -{ - ma_vec3f v; - - v.x = x; - v.y = y; - v.z = z; - - return v; -} - -MA_API ma_vec3f ma_vec3f_sub(ma_vec3f a, ma_vec3f b) -{ - return ma_vec3f_init_3f( - a.x - b.x, - a.y - b.y, - a.z - b.z - ); -} - -MA_API ma_vec3f ma_vec3f_neg(ma_vec3f a) -{ - return ma_vec3f_init_3f( - -a.x, - -a.y, - -a.z - ); -} - -MA_API float ma_vec3f_dot(ma_vec3f a, ma_vec3f b) -{ - return a.x*b.x + a.y*b.y + a.z*b.z; -} - -MA_API float ma_vec3f_len2(ma_vec3f v) -{ - return ma_vec3f_dot(v, v); -} - -MA_API float ma_vec3f_len(ma_vec3f v) -{ - return (float)ma_sqrtd(ma_vec3f_len2(v)); -} - - - -MA_API float ma_vec3f_dist(ma_vec3f a, ma_vec3f b) -{ - return ma_vec3f_len(ma_vec3f_sub(a, b)); -} - -MA_API ma_vec3f ma_vec3f_normalize(ma_vec3f v) -{ - float invLen; - float len2 = ma_vec3f_len2(v); - if (len2 == 0) { - return ma_vec3f_init_3f(0, 0, 0); - } - - invLen = ma_rsqrtf(len2); - v.x *= invLen; - v.y *= invLen; - v.z *= invLen; - - return v; -} - -MA_API ma_vec3f ma_vec3f_cross(ma_vec3f a, ma_vec3f b) -{ - return ma_vec3f_init_3f( - a.y*b.z - a.z*b.y, - a.z*b.x - a.x*b.z, - a.x*b.y - a.y*b.x - ); -} - - -MA_API void ma_atomic_vec3f_init(ma_atomic_vec3f* v, ma_vec3f value) -{ - v->v = value; - v->lock = 0; /* Important this is initialized to 0. */ -} - -MA_API void ma_atomic_vec3f_set(ma_atomic_vec3f* v, ma_vec3f value) -{ - ma_spinlock_lock(&v->lock); - { - v->v = value; - } - ma_spinlock_unlock(&v->lock); -} - -MA_API ma_vec3f ma_atomic_vec3f_get(ma_atomic_vec3f* v) -{ - ma_vec3f r; - - ma_spinlock_lock(&v->lock); - { - r = v->v; - } - ma_spinlock_unlock(&v->lock); - - return r; -} - - - -static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode); -static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition); - - -#ifndef MA_DEFAULT_SPEED_OF_SOUND -#define MA_DEFAULT_SPEED_OF_SOUND 343.3f -#endif - -/* -These vectors represent the direction that speakers are facing from the center point. They're used -for panning in the spatializer. Must be normalized. -*/ -static ma_vec3f g_maChannelDirections[MA_CHANNEL_POSITION_COUNT] = { - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_NONE */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_MONO */ - {-0.7071f, 0.0f, -0.7071f }, /* MA_CHANNEL_FRONT_LEFT */ - {+0.7071f, 0.0f, -0.7071f }, /* MA_CHANNEL_FRONT_RIGHT */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_FRONT_CENTER */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_LFE */ - {-0.7071f, 0.0f, +0.7071f }, /* MA_CHANNEL_BACK_LEFT */ - {+0.7071f, 0.0f, +0.7071f }, /* MA_CHANNEL_BACK_RIGHT */ - {-0.3162f, 0.0f, -0.9487f }, /* MA_CHANNEL_FRONT_LEFT_CENTER */ - {+0.3162f, 0.0f, -0.9487f }, /* MA_CHANNEL_FRONT_RIGHT_CENTER */ - { 0.0f, 0.0f, +1.0f }, /* MA_CHANNEL_BACK_CENTER */ - {-1.0f, 0.0f, 0.0f }, /* MA_CHANNEL_SIDE_LEFT */ - {+1.0f, 0.0f, 0.0f }, /* MA_CHANNEL_SIDE_RIGHT */ - { 0.0f, +1.0f, 0.0f }, /* MA_CHANNEL_TOP_CENTER */ - {-0.5774f, +0.5774f, -0.5774f }, /* MA_CHANNEL_TOP_FRONT_LEFT */ - { 0.0f, +0.7071f, -0.7071f }, /* MA_CHANNEL_TOP_FRONT_CENTER */ - {+0.5774f, +0.5774f, -0.5774f }, /* MA_CHANNEL_TOP_FRONT_RIGHT */ - {-0.5774f, +0.5774f, +0.5774f }, /* MA_CHANNEL_TOP_BACK_LEFT */ - { 0.0f, +0.7071f, +0.7071f }, /* MA_CHANNEL_TOP_BACK_CENTER */ - {+0.5774f, +0.5774f, +0.5774f }, /* MA_CHANNEL_TOP_BACK_RIGHT */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_0 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_1 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_2 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_3 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_4 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_5 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_6 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_7 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_8 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_9 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_10 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_11 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_12 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_13 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_14 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_15 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_16 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_17 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_18 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_19 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_20 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_21 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_22 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_23 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_24 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_25 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_26 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_27 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_28 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_29 */ - { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_30 */ - { 0.0f, 0.0f, -1.0f } /* MA_CHANNEL_AUX_31 */ -}; - -static ma_vec3f ma_get_channel_direction(ma_channel channel) -{ - if (channel >= MA_CHANNEL_POSITION_COUNT) { - return ma_vec3f_init_3f(0, 0, -1); - } else { - return g_maChannelDirections[channel]; - } -} - - - -static float ma_attenuation_inverse(float distance, float minDistance, float maxDistance, float rolloff) -{ - if (minDistance >= maxDistance) { - return 1; /* To avoid division by zero. Do not attenuate. */ - } - - return minDistance / (minDistance + rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance)); -} - -static float ma_attenuation_linear(float distance, float minDistance, float maxDistance, float rolloff) -{ - if (minDistance >= maxDistance) { - return 1; /* To avoid division by zero. Do not attenuate. */ - } - - return 1 - rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance) / (maxDistance - minDistance); -} - -static float ma_attenuation_exponential(float distance, float minDistance, float maxDistance, float rolloff) -{ - if (minDistance >= maxDistance) { - return 1; /* To avoid division by zero. Do not attenuate. */ - } - - return (float)ma_powd(ma_clamp(distance, minDistance, maxDistance) / minDistance, -rolloff); -} - - -/* -Doppler Effect calculation taken from the OpenAL spec, with two main differences: - - 1) The source to listener vector will have already been calculated at an earlier step so we can - just use that directly. We need only the position of the source relative to the origin. - - 2) We don't scale by a frequency because we actually just want the ratio which we'll plug straight - into the resampler directly. -*/ -static float ma_doppler_pitch(ma_vec3f relativePosition, ma_vec3f sourceVelocity, ma_vec3f listenVelocity, float speedOfSound, float dopplerFactor) -{ - float len; - float vls; - float vss; - - len = ma_vec3f_len(relativePosition); - - /* - There's a case where the position of the source will be right on top of the listener in which - case the length will be 0 and we'll end up with a division by zero. We can just return a ratio - of 1.0 in this case. This is not considered in the OpenAL spec, but is necessary. - */ - if (len == 0) { - return 1.0; - } - - vls = ma_vec3f_dot(relativePosition, listenVelocity) / len; - vss = ma_vec3f_dot(relativePosition, sourceVelocity) / len; - - vls = ma_min(vls, speedOfSound / dopplerFactor); - vss = ma_min(vss, speedOfSound / dopplerFactor); - - return (speedOfSound - dopplerFactor*vls) / (speedOfSound - dopplerFactor*vss); -} - - -static void ma_get_default_channel_map_for_spatializer(ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channelCount) -{ - /* - Special case for stereo. Want to default the left and right speakers to side left and side - right so that they're facing directly down the X axis rather than slightly forward. Not - doing this will result in sounds being quieter when behind the listener. This might - actually be good for some scenarios, but I don't think it's an appropriate default because - it can be a bit unexpected. - */ - if (channelCount == 2) { - pChannelMap[0] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[1] = MA_CHANNEL_SIDE_RIGHT; - } else { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); - } -} - - -MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uint32 channelsOut) -{ - ma_spatializer_listener_config config; - - MA_ZERO_OBJECT(&config); - config.channelsOut = channelsOut; - config.pChannelMapOut = NULL; - config.handedness = ma_handedness_right; - config.worldUp = ma_vec3f_init_3f(0, 1, 0); - config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */ - config.coneOuterAngleInRadians = 6.283185f; /* 360 degrees. */ - config.coneOuterGain = 0; - config.speedOfSound = 343.3f; /* Same as OpenAL. Used for doppler effect. */ - - return config; -} - - -typedef struct -{ - size_t sizeInBytes; - size_t channelMapOutOffset; -} ma_spatializer_listener_heap_layout; - -static ma_result ma_spatializer_listener_get_heap_layout(const ma_spatializer_listener_config* pConfig, ma_spatializer_listener_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channelsOut == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Channel map. We always need this, even for passthroughs. */ - pHeapLayout->channelMapOutOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(sizeof(*pConfig->pChannelMapOut) * pConfig->channelsOut); - - return MA_SUCCESS; -} - - -MA_API ma_result ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_spatializer_listener_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_spatializer_listener_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config* pConfig, void* pHeap, ma_spatializer_listener* pListener) -{ - ma_result result; - ma_spatializer_listener_heap_layout heapLayout; - - if (pListener == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pListener); - - result = ma_spatializer_listener_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pListener->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pListener->config = *pConfig; - ma_atomic_vec3f_init(&pListener->position, ma_vec3f_init_3f(0, 0, 0)); - ma_atomic_vec3f_init(&pListener->direction, ma_vec3f_init_3f(0, 0, -1)); - ma_atomic_vec3f_init(&pListener->velocity, ma_vec3f_init_3f(0, 0, 0)); - pListener->isEnabled = MA_TRUE; - - /* Swap the forward direction if we're left handed (it was initialized based on right handed). */ - if (pListener->config.handedness == ma_handedness_left) { - ma_vec3f negDir = ma_vec3f_neg(ma_spatializer_listener_get_direction(pListener)); - ma_spatializer_listener_set_direction(pListener, negDir.x, negDir.y, negDir.z); - } - - - /* We must always have a valid channel map. */ - pListener->config.pChannelMapOut = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapOutOffset); - - /* Use a slightly different default channel map for stereo. */ - if (pConfig->pChannelMapOut == NULL) { - ma_get_default_channel_map_for_spatializer(pListener->config.pChannelMapOut, pConfig->channelsOut, pConfig->channelsOut); - } else { - ma_channel_map_copy_or_default(pListener->config.pChannelMapOut, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelsOut); - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_spatializer_listener_init(const ma_spatializer_listener_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer_listener* pListener) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_spatializer_listener_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_spatializer_listener_init_preallocated(pConfig, pHeap, pListener); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pListener->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_spatializer_listener_uninit(ma_spatializer_listener* pListener, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pListener == NULL) { - return; - } - - if (pListener->_ownsHeap) { - ma_free(pListener->_pHeap, pAllocationCallbacks); - } -} - -MA_API ma_channel* ma_spatializer_listener_get_channel_map(ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return NULL; - } - - return pListener->config.pChannelMapOut; -} - -MA_API void ma_spatializer_listener_set_cone(ma_spatializer_listener* pListener, float innerAngleInRadians, float outerAngleInRadians, float outerGain) -{ - if (pListener == NULL) { - return; - } - - pListener->config.coneInnerAngleInRadians = innerAngleInRadians; - pListener->config.coneOuterAngleInRadians = outerAngleInRadians; - pListener->config.coneOuterGain = outerGain; -} - -MA_API void ma_spatializer_listener_get_cone(const ma_spatializer_listener* pListener, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) -{ - if (pListener == NULL) { - return; - } - - if (pInnerAngleInRadians != NULL) { - *pInnerAngleInRadians = pListener->config.coneInnerAngleInRadians; - } - - if (pOuterAngleInRadians != NULL) { - *pOuterAngleInRadians = pListener->config.coneOuterAngleInRadians; - } - - if (pOuterGain != NULL) { - *pOuterGain = pListener->config.coneOuterGain; - } -} - -MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListener, float x, float y, float z) -{ - if (pListener == NULL) { - return; - } - - ma_atomic_vec3f_set(&pListener->position, ma_vec3f_init_3f(x, y, z)); -} - -MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->position); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ -} - -MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z) -{ - if (pListener == NULL) { - return; - } - - ma_atomic_vec3f_set(&pListener->direction, ma_vec3f_init_3f(x, y, z)); -} - -MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return ma_vec3f_init_3f(0, 0, -1); - } - - return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->direction); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ -} - -MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z) -{ - if (pListener == NULL) { - return; - } - - ma_atomic_vec3f_set(&pListener->velocity, ma_vec3f_init_3f(x, y, z)); -} - -MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->velocity); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ -} - -MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound) -{ - if (pListener == NULL) { - return; - } - - pListener->config.speedOfSound = speedOfSound; -} - -MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return 0; - } - - return pListener->config.speedOfSound; -} - -MA_API void ma_spatializer_listener_set_world_up(ma_spatializer_listener* pListener, float x, float y, float z) -{ - if (pListener == NULL) { - return; - } - - pListener->config.worldUp = ma_vec3f_init_3f(x, y, z); -} - -MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return ma_vec3f_init_3f(0, 1, 0); - } - - return pListener->config.worldUp; -} - -MA_API void ma_spatializer_listener_set_enabled(ma_spatializer_listener* pListener, ma_bool32 isEnabled) -{ - if (pListener == NULL) { - return; - } - - pListener->isEnabled = isEnabled; -} - -MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener* pListener) -{ - if (pListener == NULL) { - return MA_FALSE; - } - - return pListener->isEnabled; -} - - - - -MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma_uint32 channelsOut) -{ - ma_spatializer_config config; - - MA_ZERO_OBJECT(&config); - config.channelsIn = channelsIn; - config.channelsOut = channelsOut; - config.pChannelMapIn = NULL; - config.attenuationModel = ma_attenuation_model_inverse; - config.positioning = ma_positioning_absolute; - config.handedness = ma_handedness_right; - config.minGain = 0; - config.maxGain = 1; - config.minDistance = 1; - config.maxDistance = MA_FLT_MAX; - config.rolloff = 1; - config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */ - config.coneOuterAngleInRadians = 6.283185f; /* 360 degrees. */ - config.coneOuterGain = 0.0f; - config.dopplerFactor = 1; - config.directionalAttenuationFactor = 1; - config.minSpatializationChannelGain = 0.2f; - config.gainSmoothTimeInFrames = 360; /* 7.5ms @ 48K. */ - - return config; -} - - -static ma_gainer_config ma_spatializer_gainer_config_init(const ma_spatializer_config* pConfig) -{ - MA_ASSERT(pConfig != NULL); - return ma_gainer_config_init(pConfig->channelsOut, pConfig->gainSmoothTimeInFrames); -} - -static ma_result ma_spatializer_validate_config(const ma_spatializer_config* pConfig) -{ - MA_ASSERT(pConfig != NULL); - - if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) { - return MA_INVALID_ARGS; - } - - return MA_SUCCESS; -} - -typedef struct -{ - size_t sizeInBytes; - size_t channelMapInOffset; - size_t newChannelGainsOffset; - size_t gainerOffset; -} ma_spatializer_heap_layout; - -static ma_result ma_spatializer_get_heap_layout(const ma_spatializer_config* pConfig, ma_spatializer_heap_layout* pHeapLayout) -{ - ma_result result; - - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_spatializer_validate_config(pConfig); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes = 0; - - /* Channel map. */ - pHeapLayout->channelMapInOffset = MA_SIZE_MAX; /* <-- MA_SIZE_MAX indicates no allocation necessary. */ - if (pConfig->pChannelMapIn != NULL) { - pHeapLayout->channelMapInOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(sizeof(*pConfig->pChannelMapIn) * pConfig->channelsIn); - } - - /* New channel gains for output. */ - pHeapLayout->newChannelGainsOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(sizeof(float) * pConfig->channelsOut); - - /* Gainer. */ - { - size_t gainerHeapSizeInBytes; - ma_gainer_config gainerConfig; - - gainerConfig = ma_spatializer_gainer_config_init(pConfig); - - result = ma_gainer_get_heap_size(&gainerConfig, &gainerHeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->gainerOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(gainerHeapSizeInBytes); - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_spatializer_get_heap_size(const ma_spatializer_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_spatializer_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; /* Safety. */ - - result = ma_spatializer_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - - -MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* pConfig, void* pHeap, ma_spatializer* pSpatializer) -{ - ma_result result; - ma_spatializer_heap_layout heapLayout; - ma_gainer_config gainerConfig; - - if (pSpatializer == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pSpatializer); - - if (pConfig == NULL || pHeap == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_spatializer_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pSpatializer->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pSpatializer->channelsIn = pConfig->channelsIn; - pSpatializer->channelsOut = pConfig->channelsOut; - pSpatializer->attenuationModel = pConfig->attenuationModel; - pSpatializer->positioning = pConfig->positioning; - pSpatializer->handedness = pConfig->handedness; - pSpatializer->minGain = pConfig->minGain; - pSpatializer->maxGain = pConfig->maxGain; - pSpatializer->minDistance = pConfig->minDistance; - pSpatializer->maxDistance = pConfig->maxDistance; - pSpatializer->rolloff = pConfig->rolloff; - pSpatializer->coneInnerAngleInRadians = pConfig->coneInnerAngleInRadians; - pSpatializer->coneOuterAngleInRadians = pConfig->coneOuterAngleInRadians; - pSpatializer->coneOuterGain = pConfig->coneOuterGain; - pSpatializer->dopplerFactor = pConfig->dopplerFactor; - pSpatializer->minSpatializationChannelGain = pConfig->minSpatializationChannelGain; - pSpatializer->directionalAttenuationFactor = pConfig->directionalAttenuationFactor; - pSpatializer->gainSmoothTimeInFrames = pConfig->gainSmoothTimeInFrames; - ma_atomic_vec3f_init(&pSpatializer->position, ma_vec3f_init_3f(0, 0, 0)); - ma_atomic_vec3f_init(&pSpatializer->direction, ma_vec3f_init_3f(0, 0, -1)); - ma_atomic_vec3f_init(&pSpatializer->velocity, ma_vec3f_init_3f(0, 0, 0)); - pSpatializer->dopplerPitch = 1; - - /* Swap the forward direction if we're left handed (it was initialized based on right handed). */ - if (pSpatializer->handedness == ma_handedness_left) { - ma_vec3f negDir = ma_vec3f_neg(ma_spatializer_get_direction(pSpatializer)); - ma_spatializer_set_direction(pSpatializer, negDir.x, negDir.y, negDir.z); - } - - /* Channel map. This will be on the heap. */ - if (pConfig->pChannelMapIn != NULL) { - pSpatializer->pChannelMapIn = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapInOffset); - ma_channel_map_copy_or_default(pSpatializer->pChannelMapIn, pSpatializer->channelsIn, pConfig->pChannelMapIn, pSpatializer->channelsIn); - } - - /* New channel gains for output channels. */ - pSpatializer->pNewChannelGainsOut = (float*)ma_offset_ptr(pHeap, heapLayout.newChannelGainsOffset); - - /* Gainer. */ - gainerConfig = ma_spatializer_gainer_config_init(pConfig); - - result = ma_gainer_init_preallocated(&gainerConfig, ma_offset_ptr(pHeap, heapLayout.gainerOffset), &pSpatializer->gainer); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the gainer. */ - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - /* We'll need a heap allocation to retrieve the size. */ - result = ma_spatializer_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_spatializer_init_preallocated(pConfig, pHeap, pSpatializer); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pSpatializer->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pSpatializer == NULL) { - return; - } - - ma_gainer_uninit(&pSpatializer->gainer, pAllocationCallbacks); - - if (pSpatializer->_ownsHeap) { - ma_free(pSpatializer->_pHeap, pAllocationCallbacks); - } -} - -static float ma_calculate_angular_gain(ma_vec3f dirA, ma_vec3f dirB, float coneInnerAngleInRadians, float coneOuterAngleInRadians, float coneOuterGain) -{ - /* - Angular attenuation. - - Unlike distance gain, the math for this is not specified by the OpenAL spec so we'll just go ahead and figure - this out for ourselves at the expense of possibly being inconsistent with other implementations. - - To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We - just need to get the direction from the source to the listener and then do a dot product against that and the - direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer - angles. If the dot product is greater than the outer angle, we just use coneOuterGain. If it's less than - the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain. - */ - if (coneInnerAngleInRadians < 6.283185f) { - float angularGain = 1; - float cutoffInner = (float)ma_cosd(coneInnerAngleInRadians*0.5f); - float cutoffOuter = (float)ma_cosd(coneOuterAngleInRadians*0.5f); - float d; - - d = ma_vec3f_dot(dirA, dirB); - - if (d > cutoffInner) { - /* It's inside the inner angle. */ - angularGain = 1; - } else { - /* It's outside the inner angle. */ - if (d > cutoffOuter) { - /* It's between the inner and outer angle. We need to linearly interpolate between 1 and coneOuterGain. */ - angularGain = ma_mix_f32(coneOuterGain, 1, (d - cutoffOuter) / (cutoffInner - cutoffOuter)); - } else { - /* It's outside the outer angle. */ - angularGain = coneOuterGain; - } - } - - /*printf("d = %f; cutoffInner = %f; cutoffOuter = %f; angularGain = %f\n", d, cutoffInner, cutoffOuter, angularGain);*/ - return angularGain; - } else { - /* Inner angle is 360 degrees so no need to do any attenuation. */ - return 1; - } -} - -MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) -{ - ma_channel* pChannelMapIn = pSpatializer->pChannelMapIn; - ma_channel* pChannelMapOut = pListener->config.pChannelMapOut; - - if (pSpatializer == NULL) { - return MA_INVALID_ARGS; - } - - /* If we're not spatializing we need to run an optimized path. */ - if (ma_atomic_load_i32(&pSpatializer->attenuationModel) == ma_attenuation_model_none) { - if (ma_spatializer_listener_is_enabled(pListener)) { - /* No attenuation is required, but we'll need to do some channel conversion. */ - if (pSpatializer->channelsIn == pSpatializer->channelsOut) { - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, ma_format_f32, pSpatializer->channelsIn); - } else { - ma_channel_map_apply_f32((float*)pFramesOut, pChannelMapOut, pSpatializer->channelsOut, (const float*)pFramesIn, pChannelMapIn, pSpatializer->channelsIn, frameCount, ma_channel_mix_mode_rectangular, ma_mono_expansion_mode_default); /* Safe casts to float* because f32 is the only supported format. */ - } - } else { - /* The listener is disabled. Output silence. */ - ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, pSpatializer->channelsOut); - } - - /* - We're not doing attenuation so don't bother with doppler for now. I'm not sure if this is - the correct thinking so might need to review this later. - */ - pSpatializer->dopplerPitch = 1; - } else { - /* - Let's first determine which listener the sound is closest to. Need to keep in mind that we - might not have a world or any listeners, in which case we just spatializer based on the - listener being positioned at the origin (0, 0, 0). - */ - ma_vec3f relativePosNormalized; - ma_vec3f relativePos; /* The position relative to the listener. */ - ma_vec3f relativeDir; /* The direction of the sound, relative to the listener. */ - ma_vec3f listenerVel; /* The velocity of the listener. For doppler pitch calculation. */ - float speedOfSound; - float distance = 0; - float gain = 1; - ma_uint32 iChannel; - const ma_uint32 channelsOut = pSpatializer->channelsOut; - const ma_uint32 channelsIn = pSpatializer->channelsIn; - float minDistance = ma_spatializer_get_min_distance(pSpatializer); - float maxDistance = ma_spatializer_get_max_distance(pSpatializer); - float rolloff = ma_spatializer_get_rolloff(pSpatializer); - float dopplerFactor = ma_spatializer_get_doppler_factor(pSpatializer); - - /* - We'll need the listener velocity for doppler pitch calculations. The speed of sound is - defined by the listener, so we'll grab that here too. - */ - if (pListener != NULL) { - listenerVel = ma_spatializer_listener_get_velocity(pListener); - speedOfSound = pListener->config.speedOfSound; - } else { - listenerVel = ma_vec3f_init_3f(0, 0, 0); - speedOfSound = MA_DEFAULT_SPEED_OF_SOUND; - } - - if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { - /* There's no listener or we're using relative positioning. */ - relativePos = ma_spatializer_get_position(pSpatializer); - relativeDir = ma_spatializer_get_direction(pSpatializer); - } else { - /* - We've found a listener and we're using absolute positioning. We need to transform the - sound's position and direction so that it's relative to listener. Later on we'll use - this for determining the factors to apply to each channel to apply the panning effect. - */ - ma_spatializer_get_relative_position_and_direction(pSpatializer, pListener, &relativePos, &relativeDir); - } - - distance = ma_vec3f_len(relativePos); - - /* We've gathered the data, so now we can apply some spatialization. */ - switch (ma_spatializer_get_attenuation_model(pSpatializer)) { - case ma_attenuation_model_inverse: - { - gain = ma_attenuation_inverse(distance, minDistance, maxDistance, rolloff); - } break; - case ma_attenuation_model_linear: - { - gain = ma_attenuation_linear(distance, minDistance, maxDistance, rolloff); - } break; - case ma_attenuation_model_exponential: - { - gain = ma_attenuation_exponential(distance, minDistance, maxDistance, rolloff); - } break; - case ma_attenuation_model_none: - default: - { - gain = 1; - } break; - } - - /* Normalize the position. */ - if (distance > 0.001f) { - float distanceInv = 1/distance; - relativePosNormalized = relativePos; - relativePosNormalized.x *= distanceInv; - relativePosNormalized.y *= distanceInv; - relativePosNormalized.z *= distanceInv; - } else { - distance = 0; - relativePosNormalized = ma_vec3f_init_3f(0, 0, 0); - } - - /* - Angular attenuation. - - Unlike distance gain, the math for this is not specified by the OpenAL spec so we'll just go ahead and figure - this out for ourselves at the expense of possibly being inconsistent with other implementations. - - To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We - just need to get the direction from the source to the listener and then do a dot product against that and the - direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer - angles. If the dot product is greater than the outer angle, we just use coneOuterGain. If it's less than - the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain. - */ - if (distance > 0) { - /* Source angular gain. */ - float spatializerConeInnerAngle; - float spatializerConeOuterAngle; - float spatializerConeOuterGain; - ma_spatializer_get_cone(pSpatializer, &spatializerConeInnerAngle, &spatializerConeOuterAngle, &spatializerConeOuterGain); - - gain *= ma_calculate_angular_gain(relativeDir, ma_vec3f_neg(relativePosNormalized), spatializerConeInnerAngle, spatializerConeOuterAngle, spatializerConeOuterGain); - - /* - We're supporting angular gain on the listener as well for those who want to reduce the volume of sounds that - are positioned behind the listener. On default settings, this will have no effect. - */ - if (pListener != NULL && pListener->config.coneInnerAngleInRadians < 6.283185f) { - ma_vec3f listenerDirection; - float listenerInnerAngle; - float listenerOuterAngle; - float listenerOuterGain; - - if (pListener->config.handedness == ma_handedness_right) { - listenerDirection = ma_vec3f_init_3f(0, 0, -1); - } else { - listenerDirection = ma_vec3f_init_3f(0, 0, +1); - } - - listenerInnerAngle = pListener->config.coneInnerAngleInRadians; - listenerOuterAngle = pListener->config.coneOuterAngleInRadians; - listenerOuterGain = pListener->config.coneOuterGain; - - gain *= ma_calculate_angular_gain(listenerDirection, relativePosNormalized, listenerInnerAngle, listenerOuterAngle, listenerOuterGain); - } - } else { - /* The sound is right on top of the listener. Don't do any angular attenuation. */ - } - - - /* Clamp the gain. */ - gain = ma_clamp(gain, ma_spatializer_get_min_gain(pSpatializer), ma_spatializer_get_max_gain(pSpatializer)); - - /* - The gain needs to be applied per-channel here. The spatialization code below will be changing the per-channel - gains which will then eventually be passed into the gainer which will deal with smoothing the gain transitions - to avoid harsh changes in gain. - */ - for (iChannel = 0; iChannel < channelsOut; iChannel += 1) { - pSpatializer->pNewChannelGainsOut[iChannel] = gain; - } - - /* - Convert to our output channel count. If the listener is disabled we just output silence here. We cannot ignore - the whole section of code here because we need to update some internal spatialization state. - */ - if (ma_spatializer_listener_is_enabled(pListener)) { - ma_channel_map_apply_f32((float*)pFramesOut, pChannelMapOut, channelsOut, (const float*)pFramesIn, pChannelMapIn, channelsIn, frameCount, ma_channel_mix_mode_rectangular, ma_mono_expansion_mode_default); - } else { - ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, pSpatializer->channelsOut); - } - - - /* - Panning. This is where we'll apply the gain and convert to the output channel count. We have an optimized path for - when we're converting to a mono stream. In that case we don't really need to do any panning - we just apply the - gain to the final output. - */ - /*printf("distance=%f; gain=%f\n", distance, gain);*/ - - /* We must have a valid channel map here to ensure we spatialize properly. */ - MA_ASSERT(pChannelMapOut != NULL); - - /* - We're not converting to mono so we'll want to apply some panning. This is where the feeling of something being - to the left, right, infront or behind the listener is calculated. I'm just using a basic model here. Note that - the code below is not based on any specific algorithm. I'm just implementing this off the top of my head and - seeing how it goes. There might be better ways to do this. - - To determine the direction of the sound relative to a speaker I'm using dot products. Each speaker is given a - direction. For example, the left channel in a stereo system will be -1 on the X axis and the right channel will - be +1 on the X axis. A dot product is performed against the direction vector of the channel and the normalized - position of the sound. - */ - - /* - Calculate our per-channel gains. We do this based on the normalized relative position of the sound and it's - relation to the direction of the channel. - */ - if (distance > 0) { - ma_vec3f unitPos = relativePos; - float distanceInv = 1/distance; - unitPos.x *= distanceInv; - unitPos.y *= distanceInv; - unitPos.z *= distanceInv; - - for (iChannel = 0; iChannel < channelsOut; iChannel += 1) { - ma_channel channelOut; - float d; - float dMin; - - channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannel); - if (ma_is_spatial_channel_position(channelOut)) { - d = ma_mix_f32_fast(1, ma_vec3f_dot(unitPos, ma_get_channel_direction(channelOut)), ma_spatializer_get_directional_attenuation_factor(pSpatializer)); - } else { - d = 1; /* It's not a spatial channel so there's no real notion of direction. */ - } - - /* - In my testing, if the panning effect is too aggressive it makes spatialization feel uncomfortable. - The "dMin" variable below is used to control the aggressiveness of the panning effect. When set to - 0, panning will be most extreme and any sounds that are positioned on the opposite side of the - speaker will be completely silent from that speaker. Not only does this feel uncomfortable, it - doesn't even remotely represent the real world at all because sounds that come from your right side - are still clearly audible from your left side. Setting "dMin" to 1 will result in no panning at - all, which is also not ideal. By setting it to something greater than 0, the spatialization effect - becomes much less dramatic and a lot more bearable. - - Summary: 0 = more extreme panning; 1 = no panning. - */ - dMin = pSpatializer->minSpatializationChannelGain; - - /* - At this point, "d" will be positive if the sound is on the same side as the channel and negative if - it's on the opposite side. It will be in the range of -1..1. There's two ways I can think of to - calculate a panning value. The first is to simply convert it to 0..1, however this has a problem - which I'm not entirely happy with. Considering a stereo system, when a sound is positioned right - in front of the listener it'll result in each speaker getting a gain of 0.5. I don't know if I like - the idea of having a scaling factor of 0.5 being applied to a sound when it's sitting right in front - of the listener. I would intuitively expect that to be played at full volume, or close to it. - - The second idea I think of is to only apply a reduction in gain when the sound is on the opposite - side of the speaker. That is, reduce the gain only when the dot product is negative. The problem - with this is that there will not be any attenuation as the sound sweeps around the 180 degrees - where the dot product is positive. The idea with this option is that you leave the gain at 1 when - the sound is being played on the same side as the speaker and then you just reduce the volume when - the sound is on the other side. - - The summarize, I think the first option should give a better sense of spatialization, but the second - option is better for preserving the sound's power. - - UPDATE: In my testing, I find the first option to sound better. You can feel the sense of space a - bit better, but you can also hear the reduction in volume when it's right in front. - */ - #if 1 - { - /* - Scale the dot product from -1..1 to 0..1. Will result in a sound directly in front losing power - by being played at 0.5 gain. - */ - d = (d + 1) * 0.5f; /* -1..1 to 0..1 */ - d = ma_max(d, dMin); - pSpatializer->pNewChannelGainsOut[iChannel] *= d; - } - #else - { - /* - Only reduce the volume of the sound if it's on the opposite side. This path keeps the volume more - consistent, but comes at the expense of a worse sense of space and positioning. - */ - if (d < 0) { - d += 1; /* Move into the positive range. */ - d = ma_max(d, dMin); - channelGainsOut[iChannel] *= d; - } - } - #endif - } - } else { - /* Assume the sound is right on top of us. Don't do any panning. */ - } - - /* Now we need to apply the volume to each channel. This needs to run through the gainer to ensure we get a smooth volume transition. */ - ma_gainer_set_gains(&pSpatializer->gainer, pSpatializer->pNewChannelGainsOut); - ma_gainer_process_pcm_frames(&pSpatializer->gainer, pFramesOut, pFramesOut, frameCount); - - /* - Before leaving we'll want to update our doppler pitch so that the caller can apply some - pitch shifting if they desire. Note that we need to negate the relative position here - because the doppler calculation needs to be source-to-listener, but ours is listener-to- - source. - */ - if (dopplerFactor > 0) { - pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_sub(ma_spatializer_listener_get_position(pListener), ma_spatializer_get_position(pSpatializer)), ma_spatializer_get_velocity(pSpatializer), listenerVel, speedOfSound, dopplerFactor); - } else { - pSpatializer->dopplerPitch = 1; - } - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer, float volume) -{ - if (pSpatializer == NULL) { - return MA_INVALID_ARGS; - } - - return ma_gainer_set_master_volume(&pSpatializer->gainer, volume); -} - -MA_API ma_result ma_spatializer_get_master_volume(const ma_spatializer* pSpatializer, float* pVolume) -{ - if (pSpatializer == NULL) { - return MA_INVALID_ARGS; - } - - return ma_gainer_get_master_volume(&pSpatializer->gainer, pVolume); -} - -MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return pSpatializer->channelsIn; -} - -MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return pSpatializer->channelsOut; -} - -MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_i32(&pSpatializer->attenuationModel, attenuationModel); -} - -MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return ma_attenuation_model_none; - } - - return (ma_attenuation_model)ma_atomic_load_i32(&pSpatializer->attenuationModel); -} - -MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_i32(&pSpatializer->positioning, positioning); -} - -MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return ma_positioning_absolute; - } - - return (ma_positioning)ma_atomic_load_i32(&pSpatializer->positioning); -} - -MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->rolloff, rolloff); -} - -MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return ma_atomic_load_f32(&pSpatializer->rolloff); -} - -MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->minGain, minGain); -} - -MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return ma_atomic_load_f32(&pSpatializer->minGain); -} - -MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->maxGain, maxGain); -} - -MA_API float ma_spatializer_get_max_gain(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return ma_atomic_load_f32(&pSpatializer->maxGain); -} - -MA_API void ma_spatializer_set_min_distance(ma_spatializer* pSpatializer, float minDistance) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->minDistance, minDistance); -} - -MA_API float ma_spatializer_get_min_distance(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return ma_atomic_load_f32(&pSpatializer->minDistance); -} - -MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float maxDistance) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->maxDistance, maxDistance); -} - -MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 0; - } - - return ma_atomic_load_f32(&pSpatializer->maxDistance); -} - -MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAngleInRadians, float outerAngleInRadians, float outerGain) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->coneInnerAngleInRadians, innerAngleInRadians); - ma_atomic_exchange_f32(&pSpatializer->coneOuterAngleInRadians, outerAngleInRadians); - ma_atomic_exchange_f32(&pSpatializer->coneOuterGain, outerGain); -} - -MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) -{ - if (pSpatializer == NULL) { - return; - } - - if (pInnerAngleInRadians != NULL) { - *pInnerAngleInRadians = ma_atomic_load_f32(&pSpatializer->coneInnerAngleInRadians); - } - - if (pOuterAngleInRadians != NULL) { - *pOuterAngleInRadians = ma_atomic_load_f32(&pSpatializer->coneOuterAngleInRadians); - } - - if (pOuterGain != NULL) { - *pOuterGain = ma_atomic_load_f32(&pSpatializer->coneOuterGain); - } -} - -MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->dopplerFactor, dopplerFactor); -} - -MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 1; - } - - return ma_atomic_load_f32(&pSpatializer->dopplerFactor); -} - -MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_exchange_f32(&pSpatializer->directionalAttenuationFactor, directionalAttenuationFactor); -} - -MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return 1; - } - - return ma_atomic_load_f32(&pSpatializer->directionalAttenuationFactor); -} - -MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_vec3f_set(&pSpatializer->position, ma_vec3f_init_3f(x, y, z)); -} - -MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->position); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ -} - -MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_vec3f_set(&pSpatializer->direction, ma_vec3f_init_3f(x, y, z)); -} - -MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return ma_vec3f_init_3f(0, 0, -1); - } - - return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->direction); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ -} - -MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z) -{ - if (pSpatializer == NULL) { - return; - } - - ma_atomic_vec3f_set(&pSpatializer->velocity, ma_vec3f_init_3f(x, y, z)); -} - -MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer) -{ - if (pSpatializer == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->velocity); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ -} - -MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir) -{ - if (pRelativePos != NULL) { - pRelativePos->x = 0; - pRelativePos->y = 0; - pRelativePos->z = 0; - } - - if (pRelativeDir != NULL) { - pRelativeDir->x = 0; - pRelativeDir->y = 0; - pRelativeDir->z = -1; - } - - if (pSpatializer == NULL) { - return; - } - - if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { - /* There's no listener or we're using relative positioning. */ - if (pRelativePos != NULL) { - *pRelativePos = ma_spatializer_get_position(pSpatializer); - } - if (pRelativeDir != NULL) { - *pRelativeDir = ma_spatializer_get_direction(pSpatializer); - } - } else { - ma_vec3f spatializerPosition; - ma_vec3f spatializerDirection; - ma_vec3f listenerPosition; - ma_vec3f listenerDirection; - ma_vec3f v; - ma_vec3f axisX; - ma_vec3f axisY; - ma_vec3f axisZ; - float m[4][4]; - - spatializerPosition = ma_spatializer_get_position(pSpatializer); - spatializerDirection = ma_spatializer_get_direction(pSpatializer); - listenerPosition = ma_spatializer_listener_get_position(pListener); - listenerDirection = ma_spatializer_listener_get_direction(pListener); - - /* - We need to calculate the right vector from our forward and up vectors. This is done with - a cross product. - */ - axisZ = ma_vec3f_normalize(listenerDirection); /* Normalization required here because we can't trust the caller. */ - axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */ - - /* - The calculation of axisX above can result in a zero-length vector if the listener is - looking straight up on the Y axis. We'll need to fall back to a +X in this case so that - the calculations below don't fall apart. This is where a quaternion based listener and - sound orientation would come in handy. - */ - if (ma_vec3f_len2(axisX) == 0) { - axisX = ma_vec3f_init_3f(1, 0, 0); - } - - axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */ - - /* - We need to swap the X axis if we're left handed because otherwise the cross product above - will have resulted in it pointing in the wrong direction (right handed was assumed in the - cross products above). - */ - if (pListener->config.handedness == ma_handedness_left) { - axisX = ma_vec3f_neg(axisX); - } - - /* Lookat. */ - m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, listenerPosition); - m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, listenerPosition); - m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), listenerPosition); - m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; - - /* - Multiply the lookat matrix by the spatializer position to transform it to listener - space. This allows calculations to work based on the sound being relative to the - origin which makes things simpler. - */ - if (pRelativePos != NULL) { - v = spatializerPosition; - pRelativePos->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1; - pRelativePos->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1; - pRelativePos->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1; - } - - /* - The direction of the sound needs to also be transformed so that it's relative to the - rotation of the listener. - */ - if (pRelativeDir != NULL) { - v = spatializerDirection; - pRelativeDir->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z; - pRelativeDir->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z; - pRelativeDir->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z; - } - } -} - - - - /************************************************************************************************************************************************************** Resampling @@ -51495,16 +38258,6 @@ MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format form return config; } - -typedef struct -{ - size_t sizeInBytes; - size_t x0Offset; - size_t x1Offset; - size_t lpfOffset; -} ma_linear_resampler_heap_layout; - - static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* pResampler, ma_uint32 oldSampleRateOut, ma_uint32 newSampleRateOut) { /* @@ -51523,7 +38276,7 @@ static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* p pResampler->inTimeFrac = pResampler->inTimeFrac % pResampler->config.sampleRateOut; } -static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, void* pHeap, ma_linear_resampler_heap_layout* pHeapLayout, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized) +static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized) { ma_result result; ma_uint32 gcf; @@ -51561,13 +38314,13 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder); /* - If the resampler is already initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames + If the resampler is alreay initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames getting cleared. Instead we re-initialize the filter which will maintain any cached frames. */ if (isResamplerAlreadyInitialized) { result = ma_lpf_reinit(&lpfConfig, &pResampler->lpf); } else { - result = ma_lpf_init_preallocated(&lpfConfig, ma_offset_ptr(pHeap, pHeapLayout->lpfOffset), &pResampler->lpf); + result = ma_lpf_init(&lpfConfig, &pResampler->lpf); } if (result != MA_SUCCESS) { @@ -51584,88 +38337,9 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes return MA_SUCCESS; } -static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_config* pConfig, ma_linear_resampler_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* x0 */ - pHeapLayout->x0Offset = pHeapLayout->sizeInBytes; - if (pConfig->format == ma_format_f32) { - pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; - } else { - pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels; - } - - /* x1 */ - pHeapLayout->x1Offset = pHeapLayout->sizeInBytes; - if (pConfig->format == ma_format_f32) { - pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; - } else { - pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels; - } - - /* LPF */ - pHeapLayout->lpfOffset = ma_align_64(pHeapLayout->sizeInBytes); - { - ma_result result; - size_t lpfHeapSizeInBytes; - ma_lpf_config lpfConfig = ma_lpf_config_init(pConfig->format, pConfig->channels, 1, 1, pConfig->lpfOrder); /* Sample rate and cutoff frequency do not matter. */ - - result = ma_lpf_get_heap_size(&lpfConfig, &lpfHeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += lpfHeapSizeInBytes; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_linear_resampler_get_heap_size(const ma_linear_resampler_config* pConfig, size_t* pHeapSizeInBytes) +MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler) { ma_result result; - ma_linear_resampler_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler_config* pConfig, void* pHeap, ma_linear_resampler* pResampler) -{ - ma_result result; - ma_linear_resampler_heap_layout heapLayout; if (pResampler == NULL) { return MA_INVALID_ARGS; @@ -51673,26 +38347,18 @@ MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler MA_ZERO_OBJECT(pResampler); - result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; } pResampler->config = *pConfig; - pResampler->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - if (pConfig->format == ma_format_f32) { - pResampler->x0.f32 = (float*)ma_offset_ptr(pHeap, heapLayout.x0Offset); - pResampler->x1.f32 = (float*)ma_offset_ptr(pHeap, heapLayout.x1Offset); - } else { - pResampler->x0.s16 = (ma_int16*)ma_offset_ptr(pHeap, heapLayout.x0Offset); - pResampler->x1.s16 = (ma_int16*)ma_offset_ptr(pHeap, heapLayout.x1Offset); - } - /* Setting the rate will set up the filter and time advances for us. */ - result = ma_linear_resampler_set_rate_internal(pResampler, pHeap, &heapLayout, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE); + result = ma_linear_resampler_set_rate_internal(pResampler, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE); if (result != MA_SUCCESS) { return result; } @@ -51703,47 +38369,11 @@ MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler return MA_SUCCESS; } -MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_linear_resampler_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_linear_resampler_init_preallocated(pConfig, pHeap, pResampler); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pResampler->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler) { if (pResampler == NULL) { return; } - - ma_lpf_uninit(&pResampler->lpf, pAllocationCallbacks); - - if (pResampler->_ownsHeap) { - ma_free(pResampler->_pHeap, pAllocationCallbacks); - } } static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift) @@ -51773,7 +38403,7 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift); pFrameOut[c] = s; @@ -51792,7 +38422,7 @@ static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResa a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a); pFrameOut[c] = s; @@ -51837,10 +38467,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear } } - /* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */ - if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) { - ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16); - } + /* Filter. */ + ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16); framesProcessedIn += 1; pResampler->inTimeInt -= 1; @@ -51926,10 +38554,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r MA_ASSERT(pResampler->inTimeInt == 0); ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16); - /* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */ - if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) { - ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pFramesOutS16, pFramesOutS16); - } + /* Filter. */ + ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pFramesOutS16, pFramesOutS16); pFramesOutS16 += pResampler->config.channels; } @@ -52001,10 +38627,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear } } - /* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */ - if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) { - ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32); - } + /* Filter. */ + ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32); framesProcessedIn += 1; pResampler->inTimeInt -= 1; @@ -52090,10 +38714,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r MA_ASSERT(pResampler->inTimeInt == 0); ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32); - /* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */ - if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) { - ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pFramesOutF32, pFramesOutF32); - } + /* Filter. */ + ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pFramesOutF32, pFramesOutF32); pFramesOutF32 += pResampler->config.channels; } @@ -52147,7 +38769,7 @@ MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pRe MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) { - return ma_linear_resampler_set_rate_internal(pResampler, NULL, NULL, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE); + return ma_linear_resampler_set_rate_internal(pResampler, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE); } MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut) @@ -52155,15 +38777,7 @@ MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResamp ma_uint32 n; ma_uint32 d; - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - if (ratioInOut <= 0) { - return MA_INVALID_ARGS; - } - - d = 1000000; + d = 1000; n = (ma_uint32)(ratioInOut * d); if (n == 0) { @@ -52175,6 +38789,67 @@ MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResamp return ma_linear_resampler_set_rate(pResampler, n, d); } + +MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount) +{ + ma_uint64 inputFrameCount; + + if (pResampler == NULL) { + return 0; + } + + if (outputFrameCount == 0) { + return 0; + } + + /* Any whole input frames are consumed before the first output frame is generated. */ + inputFrameCount = pResampler->inTimeInt; + outputFrameCount -= 1; + + /* The rest of the output frames can be calculated in constant time. */ + inputFrameCount += outputFrameCount * pResampler->inAdvanceInt; + inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut; + + return inputFrameCount; +} + +MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount) +{ + ma_uint64 outputFrameCount; + ma_uint64 preliminaryInputFrameCountFromFrac; + ma_uint64 preliminaryInputFrameCount; + + if (pResampler == NULL) { + return 0; + } + + /* + The first step is to get a preliminary output frame count. This will either be exactly equal to what we need, or less by 1. We need to + determine how many input frames will be consumed by this value. If it's greater than our original input frame count it means we won't + be able to generate an extra frame because we will have run out of input data. Otherwise we will have enough input for the generation + of an extra output frame. This add-by-one logic is necessary due to how the data loading logic works when processing frames. + */ + outputFrameCount = (inputFrameCount * pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn; + + /* + We need to determine how many *whole* input frames will have been processed to generate our preliminary output frame count. This is + used in the logic below to determine whether or not we need to add an extra output frame. + */ + preliminaryInputFrameCountFromFrac = (pResampler->inTimeFrac + outputFrameCount*pResampler->inAdvanceFrac) / pResampler->config.sampleRateOut; + preliminaryInputFrameCount = (pResampler->inTimeInt + outputFrameCount*pResampler->inAdvanceInt ) + preliminaryInputFrameCountFromFrac; + + /* + If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greather than + the amount of whole input frames we have available as input we need to *not* add an extra output frame as there won't be enough data + to actually process. Otherwise we need to add the extra output frame. + */ + if (preliminaryInputFrameCount <= inputFrameCount) { + outputFrameCount += 1; + } + + return outputFrameCount; +} + MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler) { if (pResampler == NULL) { @@ -52193,228 +38868,24 @@ MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resample return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn; } -MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) -{ - ma_uint64 inputFrameCount; - if (pInputFrameCount == NULL) { - return MA_INVALID_ARGS; +#if defined(ma_speex_resampler_h) +#define MA_HAS_SPEEX_RESAMPLER + +static ma_result ma_result_from_speex_err(int err) +{ + switch (err) + { + case RESAMPLER_ERR_SUCCESS: return MA_SUCCESS; + case RESAMPLER_ERR_ALLOC_FAILED: return MA_OUT_OF_MEMORY; + case RESAMPLER_ERR_BAD_STATE: return MA_ERROR; + case RESAMPLER_ERR_INVALID_ARG: return MA_INVALID_ARGS; + case RESAMPLER_ERR_PTR_OVERLAP: return MA_INVALID_ARGS; + case RESAMPLER_ERR_OVERFLOW: return MA_ERROR; + default: return MA_ERROR; } - - *pInputFrameCount = 0; - - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - if (outputFrameCount == 0) { - return MA_SUCCESS; - } - - /* Any whole input frames are consumed before the first output frame is generated. */ - inputFrameCount = pResampler->inTimeInt; - outputFrameCount -= 1; - - /* The rest of the output frames can be calculated in constant time. */ - inputFrameCount += outputFrameCount * pResampler->inAdvanceInt; - inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut; - - *pInputFrameCount = inputFrameCount; - - return MA_SUCCESS; } - -MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) -{ - ma_uint64 outputFrameCount; - ma_uint64 preliminaryInputFrameCountFromFrac; - ma_uint64 preliminaryInputFrameCount; - - if (pOutputFrameCount == NULL) { - return MA_INVALID_ARGS; - } - - *pOutputFrameCount = 0; - - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - /* - The first step is to get a preliminary output frame count. This will either be exactly equal to what we need, or less by 1. We need to - determine how many input frames will be consumed by this value. If it's greater than our original input frame count it means we won't - be able to generate an extra frame because we will have run out of input data. Otherwise we will have enough input for the generation - of an extra output frame. This add-by-one logic is necessary due to how the data loading logic works when processing frames. - */ - outputFrameCount = (inputFrameCount * pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn; - - /* - We need to determine how many *whole* input frames will have been processed to generate our preliminary output frame count. This is - used in the logic below to determine whether or not we need to add an extra output frame. - */ - preliminaryInputFrameCountFromFrac = (pResampler->inTimeFrac + outputFrameCount*pResampler->inAdvanceFrac) / pResampler->config.sampleRateOut; - preliminaryInputFrameCount = (pResampler->inTimeInt + outputFrameCount*pResampler->inAdvanceInt ) + preliminaryInputFrameCountFromFrac; - - /* - If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greater than - the amount of whole input frames we have available as input we need to *not* add an extra output frame as there won't be enough data - to actually process. Otherwise we need to add the extra output frame. - */ - if (preliminaryInputFrameCount <= inputFrameCount) { - outputFrameCount += 1; - } - - *pOutputFrameCount = outputFrameCount; - - return MA_SUCCESS; -} - -MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler) -{ - ma_uint32 iChannel; - - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - /* Timers need to be cleared back to zero. */ - pResampler->inTimeInt = 1; /* Set this to one to force an input sample to always be loaded for the first output frame. */ - pResampler->inTimeFrac = 0; - - /* Cached samples need to be cleared. */ - if (pResampler->config.format == ma_format_f32) { - for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { - pResampler->x0.f32[iChannel] = 0; - pResampler->x1.f32[iChannel] = 0; - } - } else { - for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { - pResampler->x0.s16[iChannel] = 0; - pResampler->x1.s16[iChannel] = 0; - } - } - - /* The low pass filter needs to have its cache reset. */ - ma_lpf_clear_cache(&pResampler->lpf); - - return MA_SUCCESS; -} - - - -/* Linear resampler backend vtable. */ -static ma_linear_resampler_config ma_resampling_backend_get_config__linear(const ma_resampler_config* pConfig) -{ - ma_linear_resampler_config linearConfig; - - linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut); - linearConfig.lpfOrder = pConfig->linear.lpfOrder; - - return linearConfig; -} - -static ma_result ma_resampling_backend_get_heap_size__linear(void* pUserData, const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_linear_resampler_config linearConfig; - - (void)pUserData; - - linearConfig = ma_resampling_backend_get_config__linear(pConfig); - - return ma_linear_resampler_get_heap_size(&linearConfig, pHeapSizeInBytes); -} - -static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_resampler_config* pConfig, void* pHeap, ma_resampling_backend** ppBackend) -{ - ma_resampler* pResampler = (ma_resampler*)pUserData; - ma_result result; - ma_linear_resampler_config linearConfig; - - (void)pUserData; - - linearConfig = ma_resampling_backend_get_config__linear(pConfig); - - result = ma_linear_resampler_init_preallocated(&linearConfig, pHeap, &pResampler->state.linear); - if (result != MA_SUCCESS) { - return result; - } - - *ppBackend = &pResampler->state.linear; - - return MA_SUCCESS; -} - -static void ma_resampling_backend_uninit__linear(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - (void)pUserData; - - ma_linear_resampler_uninit((ma_linear_resampler*)pBackend, pAllocationCallbacks); -} - -static ma_result ma_resampling_backend_process__linear(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) -{ - (void)pUserData; - - return ma_linear_resampler_process_pcm_frames((ma_linear_resampler*)pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); -} - -static ma_result ma_resampling_backend_set_rate__linear(void* pUserData, ma_resampling_backend* pBackend, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) -{ - (void)pUserData; - - return ma_linear_resampler_set_rate((ma_linear_resampler*)pBackend, sampleRateIn, sampleRateOut); -} - -static ma_uint64 ma_resampling_backend_get_input_latency__linear(void* pUserData, const ma_resampling_backend* pBackend) -{ - (void)pUserData; - - return ma_linear_resampler_get_input_latency((const ma_linear_resampler*)pBackend); -} - -static ma_uint64 ma_resampling_backend_get_output_latency__linear(void* pUserData, const ma_resampling_backend* pBackend) -{ - (void)pUserData; - - return ma_linear_resampler_get_output_latency((const ma_linear_resampler*)pBackend); -} - -static ma_result ma_resampling_backend_get_required_input_frame_count__linear(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) -{ - (void)pUserData; - - return ma_linear_resampler_get_required_input_frame_count((const ma_linear_resampler*)pBackend, outputFrameCount, pInputFrameCount); -} - -static ma_result ma_resampling_backend_get_expected_output_frame_count__linear(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) -{ - (void)pUserData; - - return ma_linear_resampler_get_expected_output_frame_count((const ma_linear_resampler*)pBackend, inputFrameCount, pOutputFrameCount); -} - -static ma_result ma_resampling_backend_reset__linear(void* pUserData, ma_resampling_backend* pBackend) -{ - (void)pUserData; - - return ma_linear_resampler_reset((ma_linear_resampler*)pBackend); -} - -static ma_resampling_backend_vtable g_ma_linear_resampler_vtable = -{ - ma_resampling_backend_get_heap_size__linear, - ma_resampling_backend_init__linear, - ma_resampling_backend_uninit__linear, - ma_resampling_backend_process__linear, - ma_resampling_backend_set_rate__linear, - ma_resampling_backend_get_input_latency__linear, - ma_resampling_backend_get_output_latency__linear, - ma_resampling_backend_get_required_input_frame_count__linear, - ma_resampling_backend_get_expected_output_frame_count__linear, - ma_resampling_backend_reset__linear -}; - - +#endif /* ma_speex_resampler_h */ MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm) { @@ -52429,74 +38900,15 @@ MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 /* Linear. */ config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); + config.linear.lpfNyquistFactor = 1; + + /* Speex. */ + config.speex.quality = 3; /* Cannot leave this as 0 as that is actually a valid value for Speex resampling quality. */ return config; } -static ma_result ma_resampler_get_vtable(const ma_resampler_config* pConfig, ma_resampler* pResampler, ma_resampling_backend_vtable** ppVTable, void** ppUserData) -{ - MA_ASSERT(pConfig != NULL); - MA_ASSERT(ppVTable != NULL); - MA_ASSERT(ppUserData != NULL); - - /* Safety. */ - *ppVTable = NULL; - *ppUserData = NULL; - - switch (pConfig->algorithm) - { - case ma_resample_algorithm_linear: - { - *ppVTable = &g_ma_linear_resampler_vtable; - *ppUserData = pResampler; - } break; - - case ma_resample_algorithm_custom: - { - *ppVTable = pConfig->pBackendVTable; - *ppUserData = pConfig->pBackendUserData; - } break; - - default: return MA_INVALID_ARGS; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_resampler_get_heap_size(const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_resampling_backend_vtable* pVTable; - void* pVTableUserData; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_resampler_get_vtable(pConfig, NULL, &pVTable, &pVTableUserData); - if (result != MA_SUCCESS) { - return result; - } - - if (pVTable == NULL || pVTable->onGetHeapSize == NULL) { - return MA_NOT_IMPLEMENTED; - } - - result = pVTable->onGetHeapSize(pVTableUserData, pConfig, pHeapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConfig, void* pHeap, ma_resampler* pResampler) +MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler) { ma_result result; @@ -52510,76 +38922,291 @@ MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConf return MA_INVALID_ARGS; } - pResampler->_pHeap = pHeap; - pResampler->format = pConfig->format; - pResampler->channels = pConfig->channels; - pResampler->sampleRateIn = pConfig->sampleRateIn; - pResampler->sampleRateOut = pConfig->sampleRateOut; - - result = ma_resampler_get_vtable(pConfig, pResampler, &pResampler->pBackendVTable, &pResampler->pBackendUserData); - if (result != MA_SUCCESS) { - return result; + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; } - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onInit == NULL) { - return MA_NOT_IMPLEMENTED; /* onInit not implemented. */ - } + pResampler->config = *pConfig; - result = pResampler->pBackendVTable->onInit(pResampler->pBackendUserData, pConfig, pHeap, &pResampler->pBackend); - if (result != MA_SUCCESS) { - return result; + switch (pConfig->algorithm) + { + case ma_resample_algorithm_linear: + { + ma_linear_resampler_config linearConfig; + linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut); + linearConfig.lpfOrder = pConfig->linear.lpfOrder; + linearConfig.lpfNyquistFactor = pConfig->linear.lpfNyquistFactor; + + result = ma_linear_resampler_init(&linearConfig, &pResampler->state.linear); + if (result != MA_SUCCESS) { + return result; + } + } break; + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + int speexErr; + pResampler->state.speex.pSpeexResamplerState = speex_resampler_init(pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->speex.quality, &speexErr); + if (pResampler->state.speex.pSpeexResamplerState == NULL) { + return ma_result_from_speex_err(speexErr); + } + #else + /* Speex resampler not available. */ + return MA_NO_BACKEND; + #endif + } break; + + default: return MA_INVALID_ARGS; } return MA_SUCCESS; } -MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resampler* pResampler) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_resampler_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_resampler_init_preallocated(pConfig, pHeap, pResampler); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pResampler->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API void ma_resampler_uninit(ma_resampler* pResampler) { if (pResampler == NULL) { return; } - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onUninit == NULL) { - return; + if (pResampler->config.algorithm == ma_resample_algorithm_linear) { + ma_linear_resampler_uninit(&pResampler->state.linear); } - pResampler->pBackendVTable->onUninit(pResampler->pBackendUserData, pResampler->pBackend, pAllocationCallbacks); - - if (pResampler->_ownsHeap) { - ma_free(pResampler->_pHeap, pAllocationCallbacks); +#if defined(MA_HAS_SPEEX_RESAMPLER) + if (pResampler->config.algorithm == ma_resample_algorithm_speex) { + speex_resampler_destroy((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState); } +#endif } +static ma_result ma_resampler_process_pcm_frames__read__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); +} + +#if defined(MA_HAS_SPEEX_RESAMPLER) +static ma_result ma_resampler_process_pcm_frames__read__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + int speexErr; + ma_uint64 frameCountOut; + ma_uint64 frameCountIn; + ma_uint64 framesProcessedOut; + ma_uint64 framesProcessedIn; + unsigned int framesPerIteration = UINT_MAX; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFramesOut != NULL); + MA_ASSERT(pFrameCountOut != NULL); + MA_ASSERT(pFrameCountIn != NULL); + + /* + Reading from the Speex resampler requires a bit of dancing around for a few reasons. The first thing is that it's frame counts + are in unsigned int's whereas ours is in ma_uint64. We therefore need to run the conversion in a loop. The other, more complicated + problem, is that we need to keep track of the input time, similar to what we do with the linear resampler. The reason we need to + do this is for ma_resampler_get_required_input_frame_count() and ma_resampler_get_expected_output_frame_count(). + */ + frameCountOut = *pFrameCountOut; + frameCountIn = *pFrameCountIn; + framesProcessedOut = 0; + framesProcessedIn = 0; + + while (framesProcessedOut < frameCountOut && framesProcessedIn < frameCountIn) { + unsigned int frameCountInThisIteration; + unsigned int frameCountOutThisIteration; + const void* pFramesInThisIteration; + void* pFramesOutThisIteration; + + frameCountInThisIteration = framesPerIteration; + if ((ma_uint64)frameCountInThisIteration > (frameCountIn - framesProcessedIn)) { + frameCountInThisIteration = (unsigned int)(frameCountIn - framesProcessedIn); + } + + frameCountOutThisIteration = framesPerIteration; + if ((ma_uint64)frameCountOutThisIteration > (frameCountOut - framesProcessedOut)) { + frameCountOutThisIteration = (unsigned int)(frameCountOut - framesProcessedOut); + } + + pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels)); + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels)); + + if (pResampler->config.format == ma_format_f32) { + speexErr = speex_resampler_process_interleaved_float((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const float*)pFramesInThisIteration, &frameCountInThisIteration, (float*)pFramesOutThisIteration, &frameCountOutThisIteration); + } else if (pResampler->config.format == ma_format_s16) { + speexErr = speex_resampler_process_interleaved_int((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const spx_int16_t*)pFramesInThisIteration, &frameCountInThisIteration, (spx_int16_t*)pFramesOutThisIteration, &frameCountOutThisIteration); + } else { + /* Format not supported. Should never get here. */ + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; + } + + if (speexErr != RESAMPLER_ERR_SUCCESS) { + return ma_result_from_speex_err(speexErr); + } + + framesProcessedIn += frameCountInThisIteration; + framesProcessedOut += frameCountOutThisIteration; + } + + *pFrameCountOut = framesProcessedOut; + *pFrameCountIn = framesProcessedIn; + + return MA_SUCCESS; +} +#endif + +static ma_result ma_resampler_process_pcm_frames__read(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFramesOut != NULL); + + /* pFramesOut is not NULL, which means we must have a capacity. */ + if (pFrameCountOut == NULL) { + return MA_INVALID_ARGS; + } + + /* It doesn't make sense to not have any input frames to process. */ + if (pFrameCountIn == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_resampler_process_pcm_frames__read__linear(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + return ma_resampler_process_pcm_frames__read__speex(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + #else + break; + #endif + } + + default: break; + } + + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return MA_INVALID_ARGS; +} + + +static ma_result ma_resampler_process_pcm_frames__seek__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) +{ + MA_ASSERT(pResampler != NULL); + + /* Seeking is supported natively by the linear resampler. */ + return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, NULL, pFrameCountOut); +} + +#if defined(MA_HAS_SPEEX_RESAMPLER) +static ma_result ma_resampler_process_pcm_frames__seek__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) +{ + /* The generic seek method is implemented in on top of ma_resampler_process_pcm_frames__read() by just processing into a dummy buffer. */ + float devnull[4096]; + ma_uint64 totalOutputFramesToProcess; + ma_uint64 totalOutputFramesProcessed; + ma_uint64 totalInputFramesProcessed; + ma_uint32 bpf; + ma_result result; + + MA_ASSERT(pResampler != NULL); + + totalOutputFramesProcessed = 0; + totalInputFramesProcessed = 0; + bpf = ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels); + + if (pFrameCountOut != NULL) { + /* Seek by output frames. */ + totalOutputFramesToProcess = *pFrameCountOut; + } else { + /* Seek by input frames. */ + MA_ASSERT(pFrameCountIn != NULL); + totalOutputFramesToProcess = ma_resampler_get_expected_output_frame_count(pResampler, *pFrameCountIn); + } + + if (pFramesIn != NULL) { + /* Process input data. */ + MA_ASSERT(pFrameCountIn != NULL); + while (totalOutputFramesProcessed < totalOutputFramesToProcess && totalInputFramesProcessed < *pFrameCountIn) { + ma_uint64 inputFramesToProcessThisIteration = (*pFrameCountIn - totalInputFramesProcessed); + ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed); + if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) { + outputFramesToProcessThisIteration = sizeof(devnull) / bpf; + } + + result = ma_resampler_process_pcm_frames__read(pResampler, ma_offset_ptr(pFramesIn, totalInputFramesProcessed*bpf), &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + totalOutputFramesProcessed += outputFramesToProcessThisIteration; + totalInputFramesProcessed += inputFramesToProcessThisIteration; + } + } else { + /* Don't process input data - just update timing and filter state as if zeroes were passed in. */ + while (totalOutputFramesProcessed < totalOutputFramesToProcess) { + ma_uint64 inputFramesToProcessThisIteration = 16384; + ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed); + if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) { + outputFramesToProcessThisIteration = sizeof(devnull) / bpf; + } + + result = ma_resampler_process_pcm_frames__read(pResampler, NULL, &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + totalOutputFramesProcessed += outputFramesToProcessThisIteration; + totalInputFramesProcessed += inputFramesToProcessThisIteration; + } + } + + + if (pFrameCountIn != NULL) { + *pFrameCountIn = totalInputFramesProcessed; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = totalOutputFramesProcessed; + } + + return MA_SUCCESS; +} +#endif + +static ma_result ma_resampler_process_pcm_frames__seek(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) +{ + MA_ASSERT(pResampler != NULL); + + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_resampler_process_pcm_frames__seek__linear(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); + } break; + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + return ma_resampler_process_pcm_frames__seek__speex(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); + #else + break; + #endif + }; + + default: break; + } + + /* Should never hit this. */ + MA_ASSERT(MA_FALSE); + return MA_INVALID_ARGS; +} + + MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) { if (pResampler == NULL) { @@ -52590,17 +39217,17 @@ MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const return MA_INVALID_ARGS; } - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onProcess == NULL) { - return MA_NOT_IMPLEMENTED; + if (pFramesOut != NULL) { + /* Reading. */ + return ma_resampler_process_pcm_frames__read(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + /* Seeking. */ + return ma_resampler_process_pcm_frames__seek(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); } - - return pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); } MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) { - ma_result result; - if (pResampler == NULL) { return MA_INVALID_ARGS; } @@ -52609,44 +39236,137 @@ MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampl return MA_INVALID_ARGS; } - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onSetRate == NULL) { - return MA_NOT_IMPLEMENTED; + pResampler->config.sampleRateIn = sampleRateIn; + pResampler->config.sampleRateOut = sampleRateOut; + + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_linear_resampler_set_rate(&pResampler->state.linear, sampleRateIn, sampleRateOut); + } break; + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + return ma_result_from_speex_err(speex_resampler_set_rate((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, sampleRateIn, sampleRateOut)); + #else + break; + #endif + }; + + default: break; } - result = pResampler->pBackendVTable->onSetRate(pResampler->pBackendUserData, pResampler->pBackend, sampleRateIn, sampleRateOut); - if (result != MA_SUCCESS) { - return result; - } - - pResampler->sampleRateIn = sampleRateIn; - pResampler->sampleRateOut = sampleRateOut; - - return MA_SUCCESS; + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; } MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio) { - ma_uint32 n; - ma_uint32 d; - if (pResampler == NULL) { return MA_INVALID_ARGS; } - if (ratio <= 0) { - return MA_INVALID_ARGS; + if (pResampler->config.algorithm == ma_resample_algorithm_linear) { + return ma_linear_resampler_set_rate_ratio(&pResampler->state.linear, ratio); + } else { + /* Getting here means the backend does not have native support for setting the rate as a ratio so we just do it generically. */ + ma_uint32 n; + ma_uint32 d; + + d = 1000; + n = (ma_uint32)(ratio * d); + + if (n == 0) { + return MA_INVALID_ARGS; /* Ratio too small. */ + } + + MA_ASSERT(n != 0); + + return ma_resampler_set_rate(pResampler, n, d); + } +} + +MA_API ma_uint64 ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount) +{ + if (pResampler == NULL) { + return 0; } - d = 1000; - n = (ma_uint32)(ratio * d); - - if (n == 0) { - return MA_INVALID_ARGS; /* Ratio too small. */ + if (outputFrameCount == 0) { + return 0; } - MA_ASSERT(n != 0); + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_linear_resampler_get_required_input_frame_count(&pResampler->state.linear, outputFrameCount); + } - return ma_resampler_set_rate(pResampler, n, d); + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + spx_uint64_t count; + int speexErr = ma_speex_resampler_get_required_input_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, outputFrameCount, &count); + if (speexErr != RESAMPLER_ERR_SUCCESS) { + return 0; + } + + return (ma_uint64)count; + #else + break; + #endif + } + + default: break; + } + + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return 0; +} + +MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount) +{ + if (pResampler == NULL) { + return 0; /* Invalid args. */ + } + + if (inputFrameCount == 0) { + return 0; + } + + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_linear_resampler_get_expected_output_frame_count(&pResampler->state.linear, inputFrameCount); + } + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + spx_uint64_t count; + int speexErr = ma_speex_resampler_get_expected_output_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, inputFrameCount, &count); + if (speexErr != RESAMPLER_ERR_SUCCESS) { + return 0; + } + + return (ma_uint64)count; + #else + break; + #endif + } + + default: break; + } + + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return 0; } MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler) @@ -52655,11 +39375,28 @@ MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler) return 0; } - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetInputLatency == NULL) { - return 0; + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_linear_resampler_get_input_latency(&pResampler->state.linear); + } + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + return (ma_uint64)ma_speex_resampler_get_input_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState); + #else + break; + #endif + } + + default: break; } - return pResampler->pBackendVTable->onGetInputLatency(pResampler->pBackendUserData, pResampler->pBackend); + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return 0; } MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler) @@ -52668,62 +39405,28 @@ MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler) return 0; } - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetOutputLatency == NULL) { - return 0; + switch (pResampler->config.algorithm) + { + case ma_resample_algorithm_linear: + { + return ma_linear_resampler_get_output_latency(&pResampler->state.linear); + } + + case ma_resample_algorithm_speex: + { + #if defined(MA_HAS_SPEEX_RESAMPLER) + return (ma_uint64)ma_speex_resampler_get_output_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState); + #else + break; + #endif + } + + default: break; } - return pResampler->pBackendVTable->onGetOutputLatency(pResampler->pBackendUserData, pResampler->pBackend); -} - -MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) -{ - if (pInputFrameCount == NULL) { - return MA_INVALID_ARGS; - } - - *pInputFrameCount = 0; - - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetRequiredInputFrameCount == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pResampler->pBackendVTable->onGetRequiredInputFrameCount(pResampler->pBackendUserData, pResampler->pBackend, outputFrameCount, pInputFrameCount); -} - -MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) -{ - if (pOutputFrameCount == NULL) { - return MA_INVALID_ARGS; - } - - *pOutputFrameCount = 0; - - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetExpectedOutputFrameCount == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pResampler->pBackendVTable->onGetExpectedOutputFrameCount(pResampler->pBackendUserData, pResampler->pBackend, inputFrameCount, pOutputFrameCount); -} - -MA_API ma_result ma_resampler_reset(ma_resampler* pResampler) -{ - if (pResampler == NULL) { - return MA_INVALID_ARGS; - } - - if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onReset == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pResampler->pBackendVTable->onReset(pResampler->pBackendUserData, pResampler->pBackend); + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return 0; } /************************************************************************************************************************************************************** @@ -52811,19 +39514,19 @@ static float ma_calculate_channel_position_rectangular_weight(ma_channel channel of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated. Imagine the front/left speaker as emitting audio from two planes - the front plane and the left plane. You can think of the front/left - speaker emitting half of its total volume from the front, and the other half from the left. Since part of its volume is being emitted + speaker emitting half of it's total volume from the front, and the other half from the left. Since part of it's volume is being emitted from the left side, and the side/left and back/left channels also emit audio from the left plane, one would expect that they would receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between the two speakers. Note that in the examples below I've added a top/front/left speaker as an example just to show how the math works across 3 spatial dimensions. The first thing to do is figure out how each speaker's volume is spread over each of plane: - - front/left: 2 planes (front and left) = 1/2 = half its total volume on each plane + - front/left: 2 planes (front and left) = 1/2 = half it's total volume on each plane - side/left: 1 plane (left only) = 1/1 = entire volume from left plane - - back/left: 2 planes (back and left) = 1/2 = half its total volume on each plane - - top/front/left: 3 planes (top, front and left) = 1/3 = one third its total volume on each plane + - back/left: 2 planes (back and left) = 1/2 = half it's total volume on each plane + - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane - The amount of volume each channel contributes to each of its planes is what controls how much it is willing to given and take to other + The amount of volume each channel contributes to each of it's planes is what controls how much it is willing to given and take to other channels on the same plane. The volume that is willing to the given by one channel is multiplied by the volume that is willing to be taken by the other to produce the final contribution. */ @@ -52844,13 +39547,17 @@ MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format fo { ma_channel_converter_config config; + /* Channel counts need to be clamped. */ + channelsIn = ma_min(channelsIn, ma_countof(config.channelMapIn)); + channelsOut = ma_min(channelsOut, ma_countof(config.channelMapOut)); + MA_ZERO_OBJECT(&config); - config.format = format; - config.channelsIn = channelsIn; - config.channelsOut = channelsOut; - config.pChannelMapIn = pChannelMapIn; - config.pChannelMapOut = pChannelMapOut; - config.mixingMode = mixingMode; + config.format = format; + config.channelsIn = channelsIn; + config.channelsOut = channelsOut; + ma_channel_map_copy_or_default(config.channelMapIn, pChannelMapIn, channelsIn); + ma_channel_map_copy_or_default(config.channelMapOut, pChannelMapOut, channelsOut); + config.mixingMode = mixingMode; return config; } @@ -52860,23 +39567,6 @@ static ma_int32 ma_channel_converter_float_to_fixed(float x) return (ma_int32)(x * (1< 0); - - for (iChannel = 0; iChannel < channels; ++iChannel) { - if (ma_is_spatial_channel_position(ma_channel_map_get_channel(pChannelMap, channels, iChannel))) { - spatialChannelCount++; - } - } - - return spatialChannelCount; -} - static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition) { int i; @@ -52885,10 +39575,6 @@ static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition) return MA_FALSE; } - if (channelPosition >= MA_CHANNEL_AUX_0 && channelPosition <= MA_CHANNEL_AUX_31) { - return MA_FALSE; - } - for (i = 0; i < 6; ++i) { /* Each side of a cube. */ if (g_maChannelPlaneRatios[channelPosition][i] != 0) { return MA_TRUE; @@ -52898,1084 +39584,320 @@ static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition) return MA_FALSE; } - -static ma_bool32 ma_channel_map_is_passthrough(const ma_channel* pChannelMapIn, ma_uint32 channelsIn, const ma_channel* pChannelMapOut, ma_uint32 channelsOut) -{ - if (channelsOut == channelsIn) { - return ma_channel_map_is_equal(pChannelMapOut, pChannelMapIn, channelsOut); - } else { - return MA_FALSE; /* Channel counts differ, so cannot be a passthrough. */ - } -} - -static ma_channel_conversion_path ma_channel_map_get_conversion_path(const ma_channel* pChannelMapIn, ma_uint32 channelsIn, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, ma_channel_mix_mode mode) -{ - if (ma_channel_map_is_passthrough(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut)) { - return ma_channel_conversion_path_passthrough; - } - - if (channelsOut == 1 && (pChannelMapOut == NULL || pChannelMapOut[0] == MA_CHANNEL_MONO)) { - return ma_channel_conversion_path_mono_out; - } - - if (channelsIn == 1 && (pChannelMapIn == NULL || pChannelMapIn[0] == MA_CHANNEL_MONO)) { - return ma_channel_conversion_path_mono_in; - } - - if (mode == ma_channel_mix_mode_custom_weights) { - return ma_channel_conversion_path_weights; - } - - /* - We can use a simple shuffle if both channel maps have the same channel count and all channel - positions are present in both. - */ - if (channelsIn == channelsOut) { - ma_uint32 iChannelIn; - ma_bool32 areAllChannelPositionsPresent = MA_TRUE; - for (iChannelIn = 0; iChannelIn < channelsIn; ++iChannelIn) { - ma_bool32 isInputChannelPositionInOutput = ma_channel_map_contains_channel_position(channelsOut, pChannelMapOut, ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn)); - if (!isInputChannelPositionInOutput) { - areAllChannelPositionsPresent = MA_FALSE; - break; - } - } - - if (areAllChannelPositionsPresent) { - return ma_channel_conversion_path_shuffle; - } - } - - /* Getting here means we'll need to use weights. */ - return ma_channel_conversion_path_weights; -} - - -static ma_result ma_channel_map_build_shuffle_table(const ma_channel* pChannelMapIn, ma_uint32 channelCountIn, const ma_channel* pChannelMapOut, ma_uint32 channelCountOut, ma_uint8* pShuffleTable) +MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, ma_channel_converter* pConverter) { ma_uint32 iChannelIn; ma_uint32 iChannelOut; - if (pShuffleTable == NULL || channelCountIn == 0 || channelCountOut == 0) { - return MA_INVALID_ARGS; - } - - /* - When building the shuffle table we just do a 1:1 mapping based on the first occurrence of a channel. If the - input channel has more than one occurrence of a channel position, the second one will be ignored. - */ - for (iChannelOut = 0; iChannelOut < channelCountOut; iChannelOut += 1) { - ma_channel channelOut; - - /* Default to MA_CHANNEL_INDEX_NULL so that if a mapping is not found it'll be set appropriately. */ - pShuffleTable[iChannelOut] = MA_CHANNEL_INDEX_NULL; - - channelOut = ma_channel_map_get_channel(pChannelMapOut, channelCountOut, iChannelOut); - for (iChannelIn = 0; iChannelIn < channelCountIn; iChannelIn += 1) { - ma_channel channelIn; - - channelIn = ma_channel_map_get_channel(pChannelMapIn, channelCountIn, iChannelIn); - if (channelOut == channelIn) { - pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn; - break; - } - - /* - Getting here means the channels don't exactly match, but we are going to support some - relaxed matching for practicality. If, for example, there are two stereo channel maps, - but one uses front left/right and the other uses side left/right, it makes logical - sense to just map these. The way we'll do it is we'll check if there is a logical - corresponding mapping, and if so, apply it, but we will *not* break from the loop, - thereby giving the loop a chance to find an exact match later which will take priority. - */ - switch (channelOut) - { - /* Left channels. */ - case MA_CHANNEL_FRONT_LEFT: - case MA_CHANNEL_SIDE_LEFT: - { - switch (channelIn) { - case MA_CHANNEL_FRONT_LEFT: - case MA_CHANNEL_SIDE_LEFT: - { - pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn; - } break; - } - } break; - - /* Right channels. */ - case MA_CHANNEL_FRONT_RIGHT: - case MA_CHANNEL_SIDE_RIGHT: - { - switch (channelIn) { - case MA_CHANNEL_FRONT_RIGHT: - case MA_CHANNEL_SIDE_RIGHT: - { - pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn; - } break; - } - } break; - - default: break; - } - } - } - - return MA_SUCCESS; -} - - -static void ma_channel_map_apply_shuffle_table_u8(ma_uint8* pFramesOut, ma_uint32 channelsOut, const ma_uint8* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) -{ - ma_uint64 iFrame; - ma_uint32 iChannelOut; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; - if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ - pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; - } else { - pFramesOut[iChannelOut] = 0; - } - } - - pFramesOut += channelsOut; - pFramesIn += channelsIn; - } -} - -static void ma_channel_map_apply_shuffle_table_s16(ma_int16* pFramesOut, ma_uint32 channelsOut, const ma_int16* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) -{ - ma_uint64 iFrame; - ma_uint32 iChannelOut; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; - if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ - pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; - } else { - pFramesOut[iChannelOut] = 0; - } - } - - pFramesOut += channelsOut; - pFramesIn += channelsIn; - } -} - -static void ma_channel_map_apply_shuffle_table_s24(ma_uint8* pFramesOut, ma_uint32 channelsOut, const ma_uint8* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) -{ - ma_uint64 iFrame; - ma_uint32 iChannelOut; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; - if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ - pFramesOut[iChannelOut*3 + 0] = pFramesIn[iChannelIn*3 + 0]; - pFramesOut[iChannelOut*3 + 1] = pFramesIn[iChannelIn*3 + 1]; - pFramesOut[iChannelOut*3 + 2] = pFramesIn[iChannelIn*3 + 2]; - } else { - pFramesOut[iChannelOut*3 + 0] = 0; - } pFramesOut[iChannelOut*3 + 1] = 0; - } pFramesOut[iChannelOut*3 + 2] = 0; - - pFramesOut += channelsOut*3; - pFramesIn += channelsIn*3; - } -} - -static void ma_channel_map_apply_shuffle_table_s32(ma_int32* pFramesOut, ma_uint32 channelsOut, const ma_int32* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) -{ - ma_uint64 iFrame; - ma_uint32 iChannelOut; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; - if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ - pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; - } else { - pFramesOut[iChannelOut] = 0; - } - } - - pFramesOut += channelsOut; - pFramesIn += channelsIn; - } -} - -static void ma_channel_map_apply_shuffle_table_f32(float* pFramesOut, ma_uint32 channelsOut, const float* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) -{ - ma_uint64 iFrame; - ma_uint32 iChannelOut; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; - if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ - pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; - } else { - pFramesOut[iChannelOut] = 0; - } - } - - pFramesOut += channelsOut; - pFramesIn += channelsIn; - } -} - -static ma_result ma_channel_map_apply_shuffle_table(void* pFramesOut, ma_uint32 channelsOut, const void* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable, ma_format format) -{ - if (pFramesOut == NULL || pFramesIn == NULL || channelsOut == 0 || pShuffleTable == NULL) { - return MA_INVALID_ARGS; - } - - switch (format) - { - case ma_format_u8: - { - ma_channel_map_apply_shuffle_table_u8((ma_uint8*)pFramesOut, channelsOut, (const ma_uint8*)pFramesIn, channelsIn, frameCount, pShuffleTable); - } break; - - case ma_format_s16: - { - ma_channel_map_apply_shuffle_table_s16((ma_int16*)pFramesOut, channelsOut, (const ma_int16*)pFramesIn, channelsIn, frameCount, pShuffleTable); - } break; - - case ma_format_s24: - { - ma_channel_map_apply_shuffle_table_s24((ma_uint8*)pFramesOut, channelsOut, (const ma_uint8*)pFramesIn, channelsIn, frameCount, pShuffleTable); - } break; - - case ma_format_s32: - { - ma_channel_map_apply_shuffle_table_s32((ma_int32*)pFramesOut, channelsOut, (const ma_int32*)pFramesIn, channelsIn, frameCount, pShuffleTable); - } break; - - case ma_format_f32: - { - ma_channel_map_apply_shuffle_table_f32((float*)pFramesOut, channelsOut, (const float*)pFramesIn, channelsIn, frameCount, pShuffleTable); - } break; - - default: return MA_INVALID_ARGS; /* Unknown format. */ - } - - return MA_SUCCESS; -} - -static ma_result ma_channel_map_apply_mono_out_f32(float* pFramesOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount) -{ - ma_uint64 iFrame; - ma_uint32 iChannelIn; - ma_uint32 accumulationCount; - - if (pFramesOut == NULL || pFramesIn == NULL || channelsIn == 0) { - return MA_INVALID_ARGS; - } - - /* In this case the output stream needs to be the average of all channels, ignoring NONE. */ - - /* A quick pre-processing step to get the accumulation counter since we're ignoring NONE channels. */ - accumulationCount = 0; - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - if (ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn) != MA_CHANNEL_NONE) { - accumulationCount += 1; - } - } - - if (accumulationCount > 0) { /* <-- Prevent a division by zero. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float accumulation = 0; - - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); - if (channelIn != MA_CHANNEL_NONE) { - accumulation += pFramesIn[iChannelIn]; - } - } - - pFramesOut[0] = accumulation / accumulationCount; - pFramesOut += 1; - pFramesIn += channelsIn; - } - } else { - ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, 1); - } - - return MA_SUCCESS; -} - -static ma_result ma_channel_map_apply_mono_in_f32(float* MA_RESTRICT pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* MA_RESTRICT pFramesIn, ma_uint64 frameCount, ma_mono_expansion_mode monoExpansionMode) -{ - ma_uint64 iFrame; - ma_uint32 iChannelOut; - - if (pFramesOut == NULL || channelsOut == 0 || pFramesIn == NULL) { - return MA_INVALID_ARGS; - } - - /* Note that the MA_CHANNEL_NONE channel must be ignored in all cases. */ - switch (monoExpansionMode) - { - case ma_mono_expansion_mode_average: - { - float weight; - ma_uint32 validChannelCount = 0; - - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut != MA_CHANNEL_NONE) { - validChannelCount += 1; - } - } - - weight = 1.0f / validChannelCount; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut != MA_CHANNEL_NONE) { - pFramesOut[iChannelOut] = pFramesIn[0] * weight; - } - } - - pFramesOut += channelsOut; - pFramesIn += 1; - } - } break; - - case ma_mono_expansion_mode_stereo_only: - { - if (channelsOut >= 2) { - ma_uint32 iChannelLeft = (ma_uint32)-1; - ma_uint32 iChannelRight = (ma_uint32)-1; - - /* - We first need to find our stereo channels. We prefer front-left and front-right, but - if they're not available, we'll also try side-left and side-right. If neither are - available we'll fall through to the default case below. - */ - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut == MA_CHANNEL_SIDE_LEFT) { - iChannelLeft = iChannelOut; - } - if (channelOut == MA_CHANNEL_SIDE_RIGHT) { - iChannelRight = iChannelOut; - } - } - - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut == MA_CHANNEL_FRONT_LEFT) { - iChannelLeft = iChannelOut; - } - if (channelOut == MA_CHANNEL_FRONT_RIGHT) { - iChannelRight = iChannelOut; - } - } - - - if (iChannelLeft != (ma_uint32)-1 && iChannelRight != (ma_uint32)-1) { - /* We found our stereo channels so we can duplicate the signal across those channels. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut != MA_CHANNEL_NONE) { - if (iChannelOut == iChannelLeft || iChannelOut == iChannelRight) { - pFramesOut[iChannelOut] = pFramesIn[0]; - } else { - pFramesOut[iChannelOut] = 0.0f; - } - } - } - - pFramesOut += channelsOut; - pFramesIn += 1; - } - - break; /* Get out of the switch. */ - } else { - /* Fallthrough. Does not have left and right channels. */ - goto default_handler; - } - } else { - /* Fallthrough. Does not have stereo channels. */ - goto default_handler; - } - }; /* Fallthrough. See comments above. */ - - case ma_mono_expansion_mode_duplicate: - default: - { - default_handler: - { - if (channelsOut <= MA_MAX_CHANNELS) { - ma_bool32 hasEmptyChannel = MA_FALSE; - ma_channel channelPositions[MA_MAX_CHANNELS]; - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - channelPositions[iChannelOut] = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelPositions[iChannelOut] == MA_CHANNEL_NONE) { - hasEmptyChannel = MA_TRUE; - } - } - - if (hasEmptyChannel == MA_FALSE) { - /* - Faster path when there's no MA_CHANNEL_NONE channel positions. This should hopefully - help the compiler with auto-vectorization.m - */ - if (channelsOut == 2) { - #if defined(MA_SUPPORT_SSE2) - if (ma_has_sse2()) { - /* We want to do two frames in each iteration. */ - ma_uint64 unrolledFrameCount = frameCount >> 1; - - for (iFrame = 0; iFrame < unrolledFrameCount; iFrame += 1) { - __m128 in0 = _mm_set1_ps(pFramesIn[iFrame*2 + 0]); - __m128 in1 = _mm_set1_ps(pFramesIn[iFrame*2 + 1]); - _mm_storeu_ps(&pFramesOut[iFrame*4 + 0], _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(0, 0, 0, 0))); - } - - /* Tail. */ - iFrame = unrolledFrameCount << 1; - goto generic_on_fastpath; - } else - #endif - { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < 2; iChannelOut += 1) { - pFramesOut[iFrame*2 + iChannelOut] = pFramesIn[iFrame]; - } - } - } - } else if (channelsOut == 6) { - #if defined(MA_SUPPORT_SSE2) - if (ma_has_sse2()) { - /* We want to do two frames in each iteration so we can have a multiple of 4 samples. */ - ma_uint64 unrolledFrameCount = frameCount >> 1; - - for (iFrame = 0; iFrame < unrolledFrameCount; iFrame += 1) { - __m128 in0 = _mm_set1_ps(pFramesIn[iFrame*2 + 0]); - __m128 in1 = _mm_set1_ps(pFramesIn[iFrame*2 + 1]); - - _mm_storeu_ps(&pFramesOut[iFrame*12 + 0], in0); - _mm_storeu_ps(&pFramesOut[iFrame*12 + 4], _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(0, 0, 0, 0))); - _mm_storeu_ps(&pFramesOut[iFrame*12 + 8], in1); - } - - /* Tail. */ - iFrame = unrolledFrameCount << 1; - goto generic_on_fastpath; - } else - #endif - { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < 6; iChannelOut += 1) { - pFramesOut[iFrame*6 + iChannelOut] = pFramesIn[iFrame]; - } - } - } - } else if (channelsOut == 8) { - #if defined(MA_SUPPORT_SSE2) - if (ma_has_sse2()) { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - __m128 in = _mm_set1_ps(pFramesIn[iFrame]); - _mm_storeu_ps(&pFramesOut[iFrame*8 + 0], in); - _mm_storeu_ps(&pFramesOut[iFrame*8 + 4], in); - } - } else - #endif - { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < 8; iChannelOut += 1) { - pFramesOut[iFrame*8 + iChannelOut] = pFramesIn[iFrame]; - } - } - } - } else { - iFrame = 0; - - #if defined(MA_SUPPORT_SSE2) /* For silencing a warning with non-x86 builds. */ - generic_on_fastpath: - #endif - { - for (; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - pFramesOut[iFrame*channelsOut + iChannelOut] = pFramesIn[iFrame]; - } - } - } - } - } else { - /* Slow path. Need to handle MA_CHANNEL_NONE. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - if (channelPositions[iChannelOut] != MA_CHANNEL_NONE) { - pFramesOut[iFrame*channelsOut + iChannelOut] = pFramesIn[iFrame]; - } - } - } - } - } else { - /* Slow path. Too many channels to store on the stack. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut != MA_CHANNEL_NONE) { - pFramesOut[iFrame*channelsOut + iChannelOut] = pFramesIn[iFrame]; - } - } - } - } - } - } break; - } - - return MA_SUCCESS; -} - -static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode) -{ - ma_channel_conversion_path conversionPath = ma_channel_map_get_conversion_path(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut, mode); - - /* Optimized Path: Passthrough */ - if (conversionPath == ma_channel_conversion_path_passthrough) { - ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, ma_format_f32, channelsOut); - return; - } - - /* Special Path: Mono Output. */ - if (conversionPath == ma_channel_conversion_path_mono_out) { - ma_channel_map_apply_mono_out_f32(pFramesOut, pFramesIn, pChannelMapIn, channelsIn, frameCount); - return; - } - - /* Special Path: Mono Input. */ - if (conversionPath == ma_channel_conversion_path_mono_in) { - ma_channel_map_apply_mono_in_f32(pFramesOut, pChannelMapOut, channelsOut, pFramesIn, frameCount, monoExpansionMode); - return; - } - - /* Getting here means we aren't running on an optimized conversion path. */ - if (channelsOut <= MA_MAX_CHANNELS) { - ma_result result; - - if (mode == ma_channel_mix_mode_simple) { - ma_channel shuffleTable[MA_MAX_CHANNELS]; - - result = ma_channel_map_build_shuffle_table(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut, shuffleTable); - if (result != MA_SUCCESS) { - return; - } - - result = ma_channel_map_apply_shuffle_table(pFramesOut, channelsOut, pFramesIn, channelsIn, frameCount, shuffleTable, ma_format_f32); - if (result != MA_SUCCESS) { - return; - } - } else { - ma_uint32 iFrame; - ma_uint32 iChannelOut; - ma_uint32 iChannelIn; - float weights[32][32]; /* Do not use MA_MAX_CHANNELS here! */ - - /* - If we have a small enough number of channels, pre-compute the weights. Otherwise we'll just need to - fall back to a slower path because otherwise we'll run out of stack space. - */ - if (channelsIn <= ma_countof(weights) && channelsOut <= ma_countof(weights)) { - /* Pre-compute weights. */ - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); - weights[iChannelOut][iChannelIn] = ma_calculate_channel_position_rectangular_weight(channelOut, channelIn); - } - } - - iFrame = 0; - - /* Experiment: Try an optimized unroll for some specific cases to see how it improves performance. RESULT: Good gains. */ - if (channelsOut == 8) { - /* Experiment 2: Expand the inner loop to see what kind of different it makes. RESULT: Small, but worthwhile gain. */ - if (channelsIn == 2) { - for (; iFrame < frameCount; iFrame += 1) { - float accumulation[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - accumulation[0] += pFramesIn[iFrame*2 + 0] * weights[0][0]; - accumulation[1] += pFramesIn[iFrame*2 + 0] * weights[1][0]; - accumulation[2] += pFramesIn[iFrame*2 + 0] * weights[2][0]; - accumulation[3] += pFramesIn[iFrame*2 + 0] * weights[3][0]; - accumulation[4] += pFramesIn[iFrame*2 + 0] * weights[4][0]; - accumulation[5] += pFramesIn[iFrame*2 + 0] * weights[5][0]; - accumulation[6] += pFramesIn[iFrame*2 + 0] * weights[6][0]; - accumulation[7] += pFramesIn[iFrame*2 + 0] * weights[7][0]; - - accumulation[0] += pFramesIn[iFrame*2 + 1] * weights[0][1]; - accumulation[1] += pFramesIn[iFrame*2 + 1] * weights[1][1]; - accumulation[2] += pFramesIn[iFrame*2 + 1] * weights[2][1]; - accumulation[3] += pFramesIn[iFrame*2 + 1] * weights[3][1]; - accumulation[4] += pFramesIn[iFrame*2 + 1] * weights[4][1]; - accumulation[5] += pFramesIn[iFrame*2 + 1] * weights[5][1]; - accumulation[6] += pFramesIn[iFrame*2 + 1] * weights[6][1]; - accumulation[7] += pFramesIn[iFrame*2 + 1] * weights[7][1]; - - pFramesOut[iFrame*8 + 0] = accumulation[0]; - pFramesOut[iFrame*8 + 1] = accumulation[1]; - pFramesOut[iFrame*8 + 2] = accumulation[2]; - pFramesOut[iFrame*8 + 3] = accumulation[3]; - pFramesOut[iFrame*8 + 4] = accumulation[4]; - pFramesOut[iFrame*8 + 5] = accumulation[5]; - pFramesOut[iFrame*8 + 6] = accumulation[6]; - pFramesOut[iFrame*8 + 7] = accumulation[7]; - } - } else { - /* When outputting to 8 channels, we can do everything in groups of two 4x SIMD operations. */ - for (; iFrame < frameCount; iFrame += 1) { - float accumulation[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - accumulation[0] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[0][iChannelIn]; - accumulation[1] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[1][iChannelIn]; - accumulation[2] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[2][iChannelIn]; - accumulation[3] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[3][iChannelIn]; - accumulation[4] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[4][iChannelIn]; - accumulation[5] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[5][iChannelIn]; - accumulation[6] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[6][iChannelIn]; - accumulation[7] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[7][iChannelIn]; - } - - pFramesOut[iFrame*8 + 0] = accumulation[0]; - pFramesOut[iFrame*8 + 1] = accumulation[1]; - pFramesOut[iFrame*8 + 2] = accumulation[2]; - pFramesOut[iFrame*8 + 3] = accumulation[3]; - pFramesOut[iFrame*8 + 4] = accumulation[4]; - pFramesOut[iFrame*8 + 5] = accumulation[5]; - pFramesOut[iFrame*8 + 6] = accumulation[6]; - pFramesOut[iFrame*8 + 7] = accumulation[7]; - } - } - } else if (channelsOut == 6) { - /* - When outputting to 6 channels we unfortunately don't have a nice multiple of 4 to do 4x SIMD operations. Instead we'll - expand our weights and do two frames at a time. - */ - for (; iFrame < frameCount; iFrame += 1) { - float accumulation[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - accumulation[0] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[0][iChannelIn]; - accumulation[1] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[1][iChannelIn]; - accumulation[2] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[2][iChannelIn]; - accumulation[3] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[3][iChannelIn]; - accumulation[4] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[4][iChannelIn]; - accumulation[5] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[5][iChannelIn]; - } - - pFramesOut[iFrame*6 + 0] = accumulation[0]; - pFramesOut[iFrame*6 + 1] = accumulation[1]; - pFramesOut[iFrame*6 + 2] = accumulation[2]; - pFramesOut[iFrame*6 + 3] = accumulation[3]; - pFramesOut[iFrame*6 + 4] = accumulation[4]; - pFramesOut[iFrame*6 + 5] = accumulation[5]; - } - } - - /* Leftover frames. */ - for (; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - float accumulation = 0; - - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - accumulation += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[iChannelOut][iChannelIn]; - } - - pFramesOut[iFrame*channelsOut + iChannelOut] = accumulation; - } - } - } else { - /* Cannot pre-compute weights because not enough room in stack-allocated buffer. */ - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - float accumulation = 0; - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - - for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); - accumulation += pFramesIn[iFrame*channelsIn + iChannelIn] * ma_calculate_channel_position_rectangular_weight(channelOut, channelIn); - } - - pFramesOut[iFrame*channelsOut + iChannelOut] = accumulation; - } - } - } - } - } else { - /* Fall back to silence. If you hit this, what are you doing with so many channels?! */ - ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, channelsOut); - } -} - - -typedef struct -{ - size_t sizeInBytes; - size_t channelMapInOffset; - size_t channelMapOutOffset; - size_t shuffleTableOffset; - size_t weightsOffset; -} ma_channel_converter_heap_layout; - -static ma_channel_conversion_path ma_channel_converter_config_get_conversion_path(const ma_channel_converter_config* pConfig) -{ - return ma_channel_map_get_conversion_path(pConfig->pChannelMapIn, pConfig->channelsIn, pConfig->pChannelMapOut, pConfig->channelsOut, pConfig->mixingMode); -} - -static ma_result ma_channel_converter_get_heap_layout(const ma_channel_converter_config* pConfig, ma_channel_converter_heap_layout* pHeapLayout) -{ - ma_channel_conversion_path conversionPath; - - MA_ASSERT(pHeapLayout != NULL); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) { - return MA_INVALID_ARGS; - } - - if (!ma_channel_map_is_valid(pConfig->pChannelMapIn, pConfig->channelsIn)) { - return MA_INVALID_ARGS; - } - - if (!ma_channel_map_is_valid(pConfig->pChannelMapOut, pConfig->channelsOut)) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Input channel map. Only need to allocate this if we have an input channel map (otherwise default channel map is assumed). */ - pHeapLayout->channelMapInOffset = pHeapLayout->sizeInBytes; - if (pConfig->pChannelMapIn != NULL) { - pHeapLayout->sizeInBytes += sizeof(ma_channel) * pConfig->channelsIn; - } - - /* Output channel map. Only need to allocate this if we have an output channel map (otherwise default channel map is assumed). */ - pHeapLayout->channelMapOutOffset = pHeapLayout->sizeInBytes; - if (pConfig->pChannelMapOut != NULL) { - pHeapLayout->sizeInBytes += sizeof(ma_channel) * pConfig->channelsOut; - } - - /* Alignment for the next section. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - /* Whether or not we use weights of a shuffle table depends on the channel map themselves and the algorithm we've chosen. */ - conversionPath = ma_channel_converter_config_get_conversion_path(pConfig); - - /* Shuffle table */ - pHeapLayout->shuffleTableOffset = pHeapLayout->sizeInBytes; - if (conversionPath == ma_channel_conversion_path_shuffle) { - pHeapLayout->sizeInBytes += sizeof(ma_uint8) * pConfig->channelsOut; - } - - /* Weights */ - pHeapLayout->weightsOffset = pHeapLayout->sizeInBytes; - if (conversionPath == ma_channel_conversion_path_weights) { - pHeapLayout->sizeInBytes += sizeof(float*) * pConfig->channelsIn; - pHeapLayout->sizeInBytes += sizeof(float ) * pConfig->channelsIn * pConfig->channelsOut; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_channel_converter_get_heap_size(const ma_channel_converter_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_channel_converter_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_channel_converter_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_converter_config* pConfig, void* pHeap, ma_channel_converter* pConverter) -{ - ma_result result; - ma_channel_converter_heap_layout heapLayout; - if (pConverter == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pConverter); - result = ma_channel_converter_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - pConverter->_pHeap = pHeap; - MA_ZERO_MEMORY(pConverter->_pHeap, heapLayout.sizeInBytes); + /* Basic validation for channel counts. */ + if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsIn > MA_MAX_CHANNELS || + pConfig->channelsOut < MA_MIN_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; + } + + if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) { + return MA_INVALID_ARGS; /* Invalid input channel map. */ + } + if (!ma_channel_map_valid(pConfig->channelsOut, pConfig->channelMapOut)) { + return MA_INVALID_ARGS; /* Invalid output channel map. */ + } pConverter->format = pConfig->format; pConverter->channelsIn = pConfig->channelsIn; pConverter->channelsOut = pConfig->channelsOut; + ma_channel_map_copy(pConverter->channelMapIn, pConfig->channelMapIn, pConfig->channelsIn); + ma_channel_map_copy(pConverter->channelMapOut, pConfig->channelMapOut, pConfig->channelsOut); pConverter->mixingMode = pConfig->mixingMode; - if (pConfig->pChannelMapIn != NULL) { - pConverter->pChannelMapIn = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapInOffset); - ma_channel_map_copy_or_default(pConverter->pChannelMapIn, pConfig->channelsIn, pConfig->pChannelMapIn, pConfig->channelsIn); - } else { - pConverter->pChannelMapIn = NULL; /* Use default channel map. */ - } - - if (pConfig->pChannelMapOut != NULL) { - pConverter->pChannelMapOut = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapOutOffset); - ma_channel_map_copy_or_default(pConverter->pChannelMapOut, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelsOut); - } else { - pConverter->pChannelMapOut = NULL; /* Use default channel map. */ - } - - pConverter->conversionPath = ma_channel_converter_config_get_conversion_path(pConfig); - - if (pConverter->conversionPath == ma_channel_conversion_path_shuffle) { - pConverter->pShuffleTable = (ma_uint8*)ma_offset_ptr(pHeap, heapLayout.shuffleTableOffset); - ma_channel_map_build_shuffle_table(pConverter->pChannelMapIn, pConverter->channelsIn, pConverter->pChannelMapOut, pConverter->channelsOut, pConverter->pShuffleTable); - } - - if (pConverter->conversionPath == ma_channel_conversion_path_weights) { - ma_uint32 iChannelIn; - ma_uint32 iChannelOut; - - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32 = (float** )ma_offset_ptr(pHeap, heapLayout.weightsOffset); - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { - pConverter->weights.f32[iChannelIn] = (float*)ma_offset_ptr(pHeap, heapLayout.weightsOffset + ((sizeof(float*) * pConverter->channelsIn) + (sizeof(float) * pConverter->channelsOut * iChannelIn))); - } - } else { - pConverter->weights.s16 = (ma_int32**)ma_offset_ptr(pHeap, heapLayout.weightsOffset); - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { - pConverter->weights.s16[iChannelIn] = (ma_int32*)ma_offset_ptr(pHeap, heapLayout.weightsOffset + ((sizeof(ma_int32*) * pConverter->channelsIn) + (sizeof(ma_int32) * pConverter->channelsOut * iChannelIn))); + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32[iChannelIn][iChannelOut] = pConfig->weights[iChannelIn][iChannelOut]; + } else { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(pConfig->weights[iChannelIn][iChannelOut]); } } + } - /* Silence our weights by default. */ - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) { - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = 0.0f; - } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = 0; + + + /* If the input and output channels and channel maps are the same we should use a passthrough. */ + if (pConverter->channelsIn == pConverter->channelsOut) { + if (ma_channel_map_equal(pConverter->channelsIn, pConverter->channelMapIn, pConverter->channelMapOut)) { + pConverter->isPassthrough = MA_TRUE; + } + if (ma_channel_map_blank(pConverter->channelsIn, pConverter->channelMapIn) || ma_channel_map_blank(pConverter->channelsOut, pConverter->channelMapOut)) { + pConverter->isPassthrough = MA_TRUE; + } + } + + + /* + We can use a simple case for expanding the mono channel. This will used when expanding a mono input into any output so long + as no LFE is present in the output. + */ + if (!pConverter->isPassthrough) { + if (pConverter->channelsIn == 1 && pConverter->channelMapIn[0] == MA_CHANNEL_MONO) { + /* Optimal case if no LFE is in the output channel map. */ + pConverter->isSimpleMonoExpansion = MA_TRUE; + if (ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, MA_CHANNEL_LFE)) { + pConverter->isSimpleMonoExpansion = MA_FALSE; + } + } + } + + /* Another optimized case is stereo to mono. */ + if (!pConverter->isPassthrough) { + if (pConverter->channelsOut == 1 && pConverter->channelMapOut[0] == MA_CHANNEL_MONO && pConverter->channelsIn == 2) { + /* Optimal case if no LFE is in the input channel map. */ + pConverter->isStereoToMono = MA_TRUE; + if (ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, MA_CHANNEL_LFE)) { + pConverter->isStereoToMono = MA_FALSE; + } + } + } + + + /* + Here is where we do a bit of pre-processing to know how each channel should be combined to make up the output. Rules: + + 1) If it's a passthrough, do nothing - it's just a simple memcpy(). + 2) If the channel counts are the same and every channel position in the input map is present in the output map, use a + simple shuffle. An example might be different 5.1 channel layouts. + 3) Otherwise channels are blended based on spatial locality. + */ + if (!pConverter->isPassthrough) { + if (pConverter->channelsIn == pConverter->channelsOut) { + ma_bool32 areAllChannelPositionsPresent = MA_TRUE; + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_bool32 isInputChannelPositionInOutput = MA_FALSE; + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) { + isInputChannelPositionInOutput = MA_TRUE; + break; + } + } + + if (!isInputChannelPositionInOutput) { + areAllChannelPositionsPresent = MA_FALSE; + break; + } + } + + if (areAllChannelPositionsPresent) { + pConverter->isSimpleShuffle = MA_TRUE; + + /* + All the router will be doing is rearranging channels which means all we need to do is use a shuffling table which is just + a mapping between the index of the input channel to the index of the output channel. + */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) { + pConverter->shuffleTable[iChannelIn] = (ma_uint8)iChannelOut; + break; + } + } } } } + } - /* - We now need to fill out our weights table. This is determined by the mixing mode. - */ - /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */ + /* + Here is where weights are calculated. Note that we calculate the weights at all times, even when using a passthrough and simple + shuffling. We use different algorithms for calculating weights depending on our mixing mode. + + In simple mode we don't do any blending (except for converting between mono, which is done in a later step). Instead we just + map 1:1 matching channels. In this mode, if no channels in the input channel map correspond to anything in the output channel + map, nothing will be heard! + */ + + /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; + + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; + + if (channelPosIn == channelPosOut) { + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32[iChannelIn][iChannelOut] = 1; + } else { + pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT); + } + } + } + } + + /* + The mono channel is accumulated on all other channels, except LFE. Make sure in this loop we exclude output mono channels since + they were handled in the pass above. + */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; + + if (channelPosIn == MA_CHANNEL_MONO) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; + + if (channelPosOut != MA_CHANNEL_NONE && channelPosOut != MA_CHANNEL_MONO && channelPosOut != MA_CHANNEL_LFE) { + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32[iChannelIn][iChannelOut] = 1; + } else { + pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT); + } + } + } + } + } + + /* The output mono channel is the average of all non-none, non-mono and non-lfe input channels. */ + { + ma_uint32 len = 0; for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn); + ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; + + if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) { + len += 1; + } + } + + if (len > 0) { + float monoWeight = 1.0f / len; for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = ma_channel_map_get_channel(pConverter->pChannelMapOut, pConverter->channelsOut, iChannelOut); + ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - if (channelPosIn == channelPosOut) { - float weight = 1; + if (channelPosOut == MA_CHANNEL_MONO) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = weight; - } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); + if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) { + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32[iChannelIn][iChannelOut] = monoWeight; + } else { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(monoWeight); + } + } } } } } + } - switch (pConverter->mixingMode) + + /* Input and output channels that are not present on the other side need to be blended in based on spatial locality. */ + switch (pConverter->mixingMode) + { + case ma_channel_mix_mode_rectangular: { - case ma_channel_mix_mode_custom_weights: - { - if (pConfig->ppWeights == NULL) { - return MA_INVALID_ARGS; /* Config specified a custom weights mixing mode, but no custom weights have been specified. */ - } + /* Unmapped input channels. */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) { - float weight = pConfig->ppWeights[iChannelIn][iChannelOut]; + if (ma_is_spatial_channel_position(channelPosIn)) { + if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, channelPosIn)) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = weight; - } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); - } - } - } - } break; + if (ma_is_spatial_channel_position(channelPosOut)) { + float weight = 0; + if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { + weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); + } - case ma_channel_mix_mode_simple: - { - /* - In simple mode, only set weights for channels that have exactly matching types, leave the rest at - zero. The 1:1 mappings have already been covered before this switch statement. - */ - } break; - - case ma_channel_mix_mode_rectangular: - default: - { - /* Unmapped input channels. */ - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn); - - if (ma_is_spatial_channel_position(channelPosIn)) { - if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->pChannelMapOut, channelPosIn)) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = ma_channel_map_get_channel(pConverter->pChannelMapOut, pConverter->channelsOut, iChannelOut); - - if (ma_is_spatial_channel_position(channelPosOut)) { - float weight = 0; - if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { - weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); + /* Only apply the weight if we haven't already got some contribution from the respective channels. */ + if (pConverter->format == ma_format_f32) { + if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { + pConverter->weights.f32[iChannelIn][iChannelOut] = weight; } - - /* Only apply the weight if we haven't already got some contribution from the respective channels. */ - if (pConverter->format == ma_format_f32) { - if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { - pConverter->weights.f32[iChannelIn][iChannelOut] = weight; - } - } else { - if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); - } + } else { + if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); } } } } } } + } - /* Unmapped output channels. */ - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = ma_channel_map_get_channel(pConverter->pChannelMapOut, pConverter->channelsOut, iChannelOut); + /* Unmapped output channels. */ + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - if (ma_is_spatial_channel_position(channelPosOut)) { - if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->pChannelMapIn, channelPosOut)) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn); + if (ma_is_spatial_channel_position(channelPosOut)) { + if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, channelPosOut)) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - if (ma_is_spatial_channel_position(channelPosIn)) { - float weight = 0; - if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { - weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); + if (ma_is_spatial_channel_position(channelPosIn)) { + float weight = 0; + if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { + weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); + } + + /* Only apply the weight if we haven't already got some contribution from the respective channels. */ + if (pConverter->format == ma_format_f32) { + if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { + pConverter->weights.f32[iChannelIn][iChannelOut] = weight; } - - /* Only apply the weight if we haven't already got some contribution from the respective channels. */ - if (pConverter->format == ma_format_f32) { - if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { - pConverter->weights.f32[iChannelIn][iChannelOut] = weight; - } - } else { - if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); - } + } else { + if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); } } } } } } + } + } break; - /* If LFE is in the output channel map but was not present in the input channel map, configure its weight now */ - if (pConfig->calculateLFEFromSpatialChannels) { - if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->pChannelMapIn, MA_CHANNEL_LFE)) { - ma_uint32 spatialChannelCount = ma_channel_map_get_spatial_channel_count(pConverter->pChannelMapIn, pConverter->channelsIn); - ma_uint32 iChannelOutLFE; - - if (spatialChannelCount > 0 && ma_channel_map_find_channel_position(pConverter->channelsOut, pConverter->pChannelMapOut, MA_CHANNEL_LFE, &iChannelOutLFE)) { - const float weightForLFE = 1.0f / spatialChannelCount; - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - const ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn); - if (ma_is_spatial_channel_position(channelPosIn)) { - if (pConverter->format == ma_format_f32) { - if (pConverter->weights.f32[iChannelIn][iChannelOutLFE] == 0) { - pConverter->weights.f32[iChannelIn][iChannelOutLFE] = weightForLFE; - } - } else { - if (pConverter->weights.s16[iChannelIn][iChannelOutLFE] == 0) { - pConverter->weights.s16[iChannelIn][iChannelOutLFE] = ma_channel_converter_float_to_fixed(weightForLFE); - } - } - } - } - } + case ma_channel_mix_mode_simple: + { + /* In simple mode, excess channels need to be silenced or dropped. */ + ma_uint32 iChannel; + for (iChannel = 0; iChannel < ma_min(pConverter->channelsIn, pConverter->channelsOut); iChannel += 1) { + if (pConverter->format == ma_format_f32) { + if (pConverter->weights.f32[iChannel][iChannel] == 0) { + pConverter->weights.f32[iChannel][iChannel] = 1; + } + } else { + if (pConverter->weights.s16[iChannel][iChannel] == 0) { + pConverter->weights.s16[iChannel][iChannel] = ma_channel_converter_float_to_fixed(1); } } - } break; - } + } + } break; + + case ma_channel_mix_mode_custom_weights: + default: + { + /* Fallthrough. */ + } break; } + return MA_SUCCESS; } -MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_channel_converter* pConverter) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_channel_converter_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_channel_converter_init_preallocated(pConfig, pHeap, pConverter); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pConverter->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter) { if (pConverter == NULL) { return; } - - if (pConverter->_ownsHeap) { - ma_free(pConverter->_pHeap, pAllocationCallbacks); - } } static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) @@ -53988,17 +39910,103 @@ static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel return MA_SUCCESS; } -static ma_result ma_channel_converter_process_pcm_frames__shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_channel_converter_process_pcm_frames__simple_shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { + ma_uint32 iFrame; + ma_uint32 iChannelIn; + MA_ASSERT(pConverter != NULL); MA_ASSERT(pFramesOut != NULL); MA_ASSERT(pFramesIn != NULL); MA_ASSERT(pConverter->channelsIn == pConverter->channelsOut); - return ma_channel_map_apply_shuffle_table(pFramesOut, pConverter->channelsOut, pFramesIn, pConverter->channelsIn, frameCount, pConverter->pShuffleTable, pConverter->format); + switch (pConverter->format) + { + case ma_format_u8: + { + /* */ ma_uint8* pFramesOutU8 = ( ma_uint8*)pFramesOut; + const ma_uint8* pFramesInU8 = (const ma_uint8*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + pFramesOutU8[pConverter->shuffleTable[iChannelIn]] = pFramesInU8[iChannelIn]; + } + + pFramesOutU8 += pConverter->channelsOut; + pFramesInU8 += pConverter->channelsIn; + } + } break; + + case ma_format_s16: + { + /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut; + const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + pFramesOutS16[pConverter->shuffleTable[iChannelIn]] = pFramesInS16[iChannelIn]; + } + + pFramesOutS16 += pConverter->channelsOut; + pFramesInS16 += pConverter->channelsIn; + } + } break; + + case ma_format_s24: + { + /* */ ma_uint8* pFramesOutS24 = ( ma_uint8*)pFramesOut; + const ma_uint8* pFramesInS24 = (const ma_uint8*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_uint32 iChannelOut = pConverter->shuffleTable[iChannelIn]; + pFramesOutS24[iChannelOut*3 + 0] = pFramesInS24[iChannelIn*3 + 0]; + pFramesOutS24[iChannelOut*3 + 1] = pFramesInS24[iChannelIn*3 + 1]; + pFramesOutS24[iChannelOut*3 + 2] = pFramesInS24[iChannelIn*3 + 2]; + } + + pFramesOutS24 += pConverter->channelsOut*3; + pFramesInS24 += pConverter->channelsIn*3; + } + } break; + + case ma_format_s32: + { + /* */ ma_int32* pFramesOutS32 = ( ma_int32*)pFramesOut; + const ma_int32* pFramesInS32 = (const ma_int32*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + pFramesOutS32[pConverter->shuffleTable[iChannelIn]] = pFramesInS32[iChannelIn]; + } + + pFramesOutS32 += pConverter->channelsOut; + pFramesInS32 += pConverter->channelsIn; + } + } break; + + case ma_format_f32: + { + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + pFramesOutF32[pConverter->shuffleTable[iChannelIn]] = pFramesInF32[iChannelIn]; + } + + pFramesOutF32 += pConverter->channelsOut; + pFramesInF32 += pConverter->channelsIn; + } + } break; + + default: return MA_INVALID_OPERATION; /* Unknown format. */ + } + + return MA_SUCCESS; } -static ma_result ma_channel_converter_process_pcm_frames__mono_in(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_channel_converter_process_pcm_frames__simple_mono_expansion(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { ma_uint64 iFrame; @@ -54098,14 +40106,14 @@ static ma_result ma_channel_converter_process_pcm_frames__mono_in(ma_channel_con return MA_SUCCESS; } -static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { ma_uint64 iFrame; - ma_uint32 iChannel; MA_ASSERT(pConverter != NULL); MA_ASSERT(pFramesOut != NULL); MA_ASSERT(pFramesIn != NULL); + MA_ASSERT(pConverter->channelsIn == 2); MA_ASSERT(pConverter->channelsOut == 1); switch (pConverter->format) @@ -54116,12 +40124,7 @@ static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_co const ma_uint8* pFramesInU8 = (const ma_uint8*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - ma_int32 t = 0; - for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { - t += ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*pConverter->channelsIn + iChannel]); - } - - pFramesOutU8[iFrame] = ma_clip_u8(t / pConverter->channelsOut); + pFramesOutU8[iFrame] = ma_clip_u8((ma_int16)((ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*2+0]) + ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*2+1])) / 2)); } } break; @@ -54131,12 +40134,7 @@ static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_co const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - ma_int32 t = 0; - for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { - t += pFramesInS16[iFrame*pConverter->channelsIn + iChannel]; - } - - pFramesOutS16[iFrame] = (ma_int16)(t / pConverter->channelsIn); + pFramesOutS16[iFrame] = (ma_int16)(((ma_int32)pFramesInS16[iFrame*2+0] + (ma_int32)pFramesInS16[iFrame*2+1]) / 2); } } break; @@ -54146,12 +40144,9 @@ static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_co const ma_uint8* pFramesInS24 = (const ma_uint8*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - ma_int64 t = 0; - for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { - t += ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*pConverter->channelsIn + iChannel)*3]); - } - - ma_pcm_sample_s32_to_s24_no_scale(t / pConverter->channelsIn, &pFramesOutS24[iFrame*3]); + ma_int64 s24_0 = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*2+0)*3]); + ma_int64 s24_1 = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*2+1)*3]); + ma_pcm_sample_s32_to_s24_no_scale((s24_0 + s24_1) / 2, &pFramesOutS24[iFrame*3]); } } break; @@ -54161,12 +40156,7 @@ static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_co const ma_int32* pFramesInS32 = (const ma_int32*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - ma_int64 t = 0; - for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { - t += pFramesInS32[iFrame*pConverter->channelsIn + iChannel]; - } - - pFramesOutS32[iFrame] = (ma_int32)(t / pConverter->channelsIn); + pFramesOutS32[iFrame] = (ma_int16)(((ma_int32)pFramesInS32[iFrame*2+0] + (ma_int32)pFramesInS32[iFrame*2+1]) / 2); } } break; @@ -54176,12 +40166,7 @@ static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_co const float* pFramesInF32 = (const float*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - float t = 0; - for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { - t += pFramesInF32[iFrame*pConverter->channelsIn + iChannel]; - } - - pFramesOutF32[iFrame] = t / pConverter->channelsIn; + pFramesOutF32[iFrame] = (pFramesInF32[iFrame*2+0] + pFramesInF32[iFrame*2+0]) * 0.5f; } } break; @@ -54312,59 +40297,40 @@ MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* p return MA_SUCCESS; } - switch (pConverter->conversionPath) - { - case ma_channel_conversion_path_passthrough: return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount); - case ma_channel_conversion_path_mono_out: return ma_channel_converter_process_pcm_frames__mono_out(pConverter, pFramesOut, pFramesIn, frameCount); - case ma_channel_conversion_path_mono_in: return ma_channel_converter_process_pcm_frames__mono_in(pConverter, pFramesOut, pFramesIn, frameCount); - case ma_channel_conversion_path_shuffle: return ma_channel_converter_process_pcm_frames__shuffle(pConverter, pFramesOut, pFramesIn, frameCount); - case ma_channel_conversion_path_weights: - default: - { - return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount); - } + if (pConverter->isPassthrough) { + return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount); + } else if (pConverter->isSimpleShuffle) { + return ma_channel_converter_process_pcm_frames__simple_shuffle(pConverter, pFramesOut, pFramesIn, frameCount); + } else if (pConverter->isSimpleMonoExpansion) { + return ma_channel_converter_process_pcm_frames__simple_mono_expansion(pConverter, pFramesOut, pFramesIn, frameCount); + } else if (pConverter->isStereoToMono) { + return ma_channel_converter_process_pcm_frames__stereo_to_mono(pConverter, pFramesOut, pFramesIn, frameCount); + } else { + return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount); } } -MA_API ma_result ma_channel_converter_get_input_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pConverter == NULL || pChannelMap == NULL) { - return MA_INVALID_ARGS; - } - - ma_channel_map_copy_or_default(pChannelMap, channelMapCap, pConverter->pChannelMapIn, pConverter->channelsIn); - - return MA_SUCCESS; -} - -MA_API ma_result ma_channel_converter_get_output_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pConverter == NULL || pChannelMap == NULL) { - return MA_INVALID_ARGS; - } - - ma_channel_map_copy_or_default(pChannelMap, channelMapCap, pConverter->pChannelMapOut, pConverter->channelsOut); - - return MA_SUCCESS; -} - /************************************************************************************************************************************************************** Data Conversion **************************************************************************************************************************************************************/ -MA_API ma_data_converter_config ma_data_converter_config_init_default(void) +MA_API ma_data_converter_config ma_data_converter_config_init_default() { ma_data_converter_config config; MA_ZERO_OBJECT(&config); config.ditherMode = ma_dither_mode_none; config.resampling.algorithm = ma_resample_algorithm_linear; - config.allowDynamicSampleRate = MA_FALSE; /* Disable dynamic sample rates by default because dynamic rate adjustments should be quite rare and it allows an optimization for cases when the in and out sample rates are the same. */ + config.resampling.allowDynamicSampleRate = MA_FALSE; /* Disable dynamic sample rates by default because dynamic rate adjustments should be quite rare and it allows an optimization for cases when the in and out sample rates are the same. */ /* Linear resampling defaults. */ config.resampling.linear.lpfOrder = 1; + config.resampling.linear.lpfNyquistFactor = 1; + + /* Speex resampling defaults. */ + config.resampling.speex.quality = 3; return config; } @@ -54374,169 +40340,18 @@ MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn ma_data_converter_config config = ma_data_converter_config_init_default(); config.formatIn = formatIn; config.formatOut = formatOut; - config.channelsIn = channelsIn; - config.channelsOut = channelsOut; + config.channelsIn = ma_min(channelsIn, MA_MAX_CHANNELS); + config.channelsOut = ma_min(channelsOut, MA_MAX_CHANNELS); config.sampleRateIn = sampleRateIn; config.sampleRateOut = sampleRateOut; return config; } - -typedef struct -{ - size_t sizeInBytes; - size_t channelConverterOffset; - size_t resamplerOffset; -} ma_data_converter_heap_layout; - -static ma_bool32 ma_data_converter_config_is_resampler_required(const ma_data_converter_config* pConfig) -{ - MA_ASSERT(pConfig != NULL); - - return pConfig->allowDynamicSampleRate || pConfig->sampleRateIn != pConfig->sampleRateOut; -} - -static ma_format ma_data_converter_config_get_mid_format(const ma_data_converter_config* pConfig) -{ - MA_ASSERT(pConfig != NULL); - - /* - We want to avoid as much data conversion as possible. The channel converter and linear - resampler both support s16 and f32 natively. We need to decide on the format to use for this - stage. We call this the mid format because it's used in the middle stage of the conversion - pipeline. If the output format is either s16 or f32 we use that one. If that is not the case it - will do the same thing for the input format. If it's neither we just use f32. If we are using a - custom resampling backend, we can only guarantee that f32 will be supported so we'll be forced - to use that if resampling is required. - */ - if (ma_data_converter_config_is_resampler_required(pConfig) && pConfig->resampling.algorithm != ma_resample_algorithm_linear) { - return ma_format_f32; /* <-- Force f32 since that is the only one we can guarantee will be supported by the resampler. */ - } else { - /* */ if (pConfig->formatOut == ma_format_s16 || pConfig->formatOut == ma_format_f32) { - return pConfig->formatOut; - } else if (pConfig->formatIn == ma_format_s16 || pConfig->formatIn == ma_format_f32) { - return pConfig->formatIn; - } else { - return ma_format_f32; - } - } -} - -static ma_channel_converter_config ma_channel_converter_config_init_from_data_converter_config(const ma_data_converter_config* pConfig) -{ - ma_channel_converter_config channelConverterConfig; - - MA_ASSERT(pConfig != NULL); - - channelConverterConfig = ma_channel_converter_config_init(ma_data_converter_config_get_mid_format(pConfig), pConfig->channelsIn, pConfig->pChannelMapIn, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelMixMode); - channelConverterConfig.ppWeights = pConfig->ppChannelWeights; - channelConverterConfig.calculateLFEFromSpatialChannels = pConfig->calculateLFEFromSpatialChannels; - - return channelConverterConfig; -} - -static ma_resampler_config ma_resampler_config_init_from_data_converter_config(const ma_data_converter_config* pConfig) -{ - ma_resampler_config resamplerConfig; - ma_uint32 resamplerChannels; - - MA_ASSERT(pConfig != NULL); - - /* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */ - if (pConfig->channelsIn < pConfig->channelsOut) { - resamplerChannels = pConfig->channelsIn; - } else { - resamplerChannels = pConfig->channelsOut; - } - - resamplerConfig = ma_resampler_config_init(ma_data_converter_config_get_mid_format(pConfig), resamplerChannels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->resampling.algorithm); - resamplerConfig.linear = pConfig->resampling.linear; - resamplerConfig.pBackendVTable = pConfig->resampling.pBackendVTable; - resamplerConfig.pBackendUserData = pConfig->resampling.pBackendUserData; - - return resamplerConfig; -} - -static ma_result ma_data_converter_get_heap_layout(const ma_data_converter_config* pConfig, ma_data_converter_heap_layout* pHeapLayout) +MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, ma_data_converter* pConverter) { ma_result result; - - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Channel converter. */ - pHeapLayout->channelConverterOffset = pHeapLayout->sizeInBytes; - { - size_t heapSizeInBytes; - ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig); - - result = ma_channel_converter_get_heap_size(&channelConverterConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += heapSizeInBytes; - } - - /* Resampler. */ - pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes; - if (ma_data_converter_config_is_resampler_required(pConfig)) { - size_t heapSizeInBytes; - ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig); - - result = ma_resampler_get_heap_size(&resamplerConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes += heapSizeInBytes; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_data_converter_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_data_converter_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter) -{ - ma_result result; - ma_data_converter_heap_layout heapLayout; ma_format midFormat; - ma_bool32 isResamplingRequired; if (pConverter == NULL) { return MA_INVALID_ARGS; @@ -54544,52 +40359,82 @@ MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_con MA_ZERO_OBJECT(pConverter); - result = ma_data_converter_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - pConverter->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + pConverter->config = *pConfig; - pConverter->formatIn = pConfig->formatIn; - pConverter->formatOut = pConfig->formatOut; - pConverter->channelsIn = pConfig->channelsIn; - pConverter->channelsOut = pConfig->channelsOut; - pConverter->sampleRateIn = pConfig->sampleRateIn; - pConverter->sampleRateOut = pConfig->sampleRateOut; - pConverter->ditherMode = pConfig->ditherMode; + /* Basic validation. */ + if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsOut < MA_MIN_CHANNELS || + pConfig->channelsIn > MA_MAX_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; + } /* - Determine if resampling is required. We need to do this so we can determine an appropriate - mid format to use. If resampling is required, the mid format must be ma_format_f32 since - that is the only one that is guaranteed to supported by custom resampling backends. + We want to avoid as much data conversion as possible. The channel converter and resampler both support s16 and f32 natively. We need to decide + on the format to use for this stage. We call this the mid format because it's used in the middle stage of the conversion pipeline. If the output + format is either s16 or f32 we use that one. If that is not the case it will do the same thing for the input format. If it's neither we just + use f32. */ - isResamplingRequired = ma_data_converter_config_is_resampler_required(pConfig); - midFormat = ma_data_converter_config_get_mid_format(pConfig); - + /* */ if (pConverter->config.formatOut == ma_format_s16 || pConverter->config.formatOut == ma_format_f32) { + midFormat = pConverter->config.formatOut; + } else if (pConverter->config.formatIn == ma_format_s16 || pConverter->config.formatIn == ma_format_f32) { + midFormat = pConverter->config.formatIn; + } else { + midFormat = ma_format_f32; + } /* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */ { - ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig); + ma_uint32 iChannelIn; + ma_uint32 iChannelOut; + ma_channel_converter_config channelConverterConfig; - result = ma_channel_converter_init_preallocated(&channelConverterConfig, ma_offset_ptr(pHeap, heapLayout.channelConverterOffset), &pConverter->channelConverter); + channelConverterConfig = ma_channel_converter_config_init(midFormat, pConverter->config.channelsIn, pConverter->config.channelMapIn, pConverter->config.channelsOut, pConverter->config.channelMapOut, pConverter->config.channelMixMode); + + /* Channel weights. */ + for (iChannelIn = 0; iChannelIn < pConverter->config.channelsIn; iChannelIn += 1) { + for (iChannelOut = 0; iChannelOut < pConverter->config.channelsOut; iChannelOut += 1) { + channelConverterConfig.weights[iChannelIn][iChannelOut] = pConverter->config.channelWeights[iChannelIn][iChannelOut]; + } + } + + result = ma_channel_converter_init(&channelConverterConfig, &pConverter->channelConverter); if (result != MA_SUCCESS) { return result; } /* If the channel converter is not a passthrough we need to enable it. Otherwise we can skip it. */ - if (pConverter->channelConverter.conversionPath != ma_channel_conversion_path_passthrough) { + if (pConverter->channelConverter.isPassthrough == MA_FALSE) { pConverter->hasChannelConverter = MA_TRUE; } } - /* Resampler. */ - if (isResamplingRequired) { - ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig); + /* Always enable dynamic sample rates if the input sample rate is different because we're always going to need a resampler in this case anyway. */ + if (pConverter->config.resampling.allowDynamicSampleRate == MA_FALSE) { + pConverter->config.resampling.allowDynamicSampleRate = pConverter->config.sampleRateIn != pConverter->config.sampleRateOut; + } - result = ma_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pConverter->resampler); + /* Resampler. */ + if (pConverter->config.resampling.allowDynamicSampleRate) { + ma_resampler_config resamplerConfig; + ma_uint32 resamplerChannels; + + /* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */ + if (pConverter->config.channelsIn < pConverter->config.channelsOut) { + resamplerChannels = pConverter->config.channelsIn; + } else { + resamplerChannels = pConverter->config.channelsOut; + } + + resamplerConfig = ma_resampler_config_init(midFormat, resamplerChannels, pConverter->config.sampleRateIn, pConverter->config.sampleRateOut, pConverter->config.resampling.algorithm); + resamplerConfig.linear.lpfOrder = pConverter->config.resampling.linear.lpfOrder; + resamplerConfig.linear.lpfNyquistFactor = pConverter->config.resampling.linear.lpfNyquistFactor; + resamplerConfig.speex.quality = pConverter->config.resampling.speex.quality; + + result = ma_resampler_init(&resamplerConfig, &pConverter->resampler); if (result != MA_SUCCESS) { return result; } @@ -54601,7 +40446,7 @@ MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_con /* We can simplify pre- and post-format conversion if we have neither channel conversion nor resampling. */ if (pConverter->hasChannelConverter == MA_FALSE && pConverter->hasResampler == MA_FALSE) { /* We have neither channel conversion nor resampling so we'll only need one of pre- or post-format conversion, or none if the input and output formats are the same. */ - if (pConverter->formatIn == pConverter->formatOut) { + if (pConverter->config.formatIn == pConverter->config.formatOut) { /* The formats are the same so we can just pass through. */ pConverter->hasPreFormatConversion = MA_FALSE; pConverter->hasPostFormatConversion = MA_FALSE; @@ -54612,10 +40457,10 @@ MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_con } } else { /* We have a channel converter and/or resampler so we'll need channel conversion based on the mid format. */ - if (pConverter->formatIn != midFormat) { - pConverter->hasPreFormatConversion = MA_TRUE; + if (pConverter->config.formatIn != midFormat) { + pConverter->hasPreFormatConversion = MA_TRUE; } - if (pConverter->formatOut != midFormat) { + if (pConverter->config.formatOut != midFormat) { pConverter->hasPostFormatConversion = MA_TRUE; } } @@ -54628,86 +40473,17 @@ MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_con pConverter->isPassthrough = MA_TRUE; } - - /* We now need to determine our execution path. */ - if (pConverter->isPassthrough) { - pConverter->executionPath = ma_data_converter_execution_path_passthrough; - } else { - if (pConverter->channelsIn < pConverter->channelsOut) { - /* Do resampling first, if necessary. */ - MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE); - - if (pConverter->hasResampler) { - pConverter->executionPath = ma_data_converter_execution_path_resample_first; - } else { - pConverter->executionPath = ma_data_converter_execution_path_channels_only; - } - } else { - /* Do channel conversion first, if necessary. */ - if (pConverter->hasChannelConverter) { - if (pConverter->hasResampler) { - pConverter->executionPath = ma_data_converter_execution_path_channels_first; - } else { - pConverter->executionPath = ma_data_converter_execution_path_channels_only; - } - } else { - /* Channel routing not required. */ - if (pConverter->hasResampler) { - pConverter->executionPath = ma_data_converter_execution_path_resample_only; - } else { - pConverter->executionPath = ma_data_converter_execution_path_format_only; - } - } - } - } - return MA_SUCCESS; } -MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_data_converter_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_data_converter_init_preallocated(pConfig, pHeap, pConverter); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pConverter->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API void ma_data_converter_uninit(ma_data_converter* pConverter) { if (pConverter == NULL) { return; } if (pConverter->hasResampler) { - ma_resampler_uninit(&pConverter->resampler, pAllocationCallbacks); - } - - ma_channel_converter_uninit(&pConverter->channelConverter, pAllocationCallbacks); - - if (pConverter->_ownsHeap) { - ma_free(pConverter->_pHeap, pAllocationCallbacks); + ma_resampler_uninit(&pConverter->resampler); } } @@ -54733,9 +40509,9 @@ static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_conve if (pFramesOut != NULL) { if (pFramesIn != NULL) { - ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } else { - ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } } @@ -54771,9 +40547,9 @@ static ma_result ma_data_converter_process_pcm_frames__format_only(ma_data_conve if (pFramesOut != NULL) { if (pFramesIn != NULL) { - ma_convert_pcm_frames_format(pFramesOut, pConverter->formatOut, pFramesIn, pConverter->formatIn, frameCount, pConverter->channelsIn, pConverter->ditherMode); + ma_convert_pcm_frames_format(pFramesOut, pConverter->config.formatOut, pFramesIn, pConverter->config.formatIn, frameCount, pConverter->config.channelsIn, pConverter->config.ditherMode); } else { - ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } } @@ -54813,20 +40589,20 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv while (framesProcessedOut < frameCountOut) { ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); + const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); const void* pFramesInThisIteration; /* */ void* pFramesOutThisIteration; ma_uint64 frameCountInThisIteration; ma_uint64 frameCountOutThisIteration; if (pFramesIn != NULL) { - pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); } else { pFramesInThisIteration = NULL; } if (pFramesOut != NULL) { - pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } else { pFramesOutThisIteration = NULL; } @@ -54834,7 +40610,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv /* Do a pre format conversion if necessary. */ if (pConverter->hasPreFormatConversion) { ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); + const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); frameCountInThisIteration = (frameCountIn - framesProcessedIn); if (frameCountInThisIteration > tempBufferInCap) { @@ -54848,7 +40624,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv } if (pFramesInThisIteration != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pFramesInThisIteration, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); } else { MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn)); } @@ -54889,7 +40665,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv /* If we are doing a post format conversion we need to do that now. */ if (pConverter->hasPostFormatConversion) { if (pFramesOutThisIteration != NULL) { - ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->formatOut, pTempBufferOut, pConverter->resampler.format, frameCountOutThisIteration, pConverter->resampler.channels, pConverter->ditherMode); + ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->resampler.config.channels, pConverter->config.ditherMode); } } @@ -54966,13 +40742,13 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con ma_uint64 frameCountThisIteration; if (pFramesIn != NULL) { - pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); } else { pFramesInThisIteration = NULL; } if (pFramesOut != NULL) { - pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } else { pFramesOutThisIteration = NULL; } @@ -54994,7 +40770,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con } if (pFramesInThisIteration != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->formatIn, frameCountThisIteration, pConverter->channelsIn, pConverter->ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); } else { MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn)); } @@ -55028,7 +40804,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con /* If we are doing a post format conversion we need to do that now. */ if (pConverter->hasPostFormatConversion) { if (pFramesOutThisIteration != NULL) { - ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->ditherMode); + ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode); } } @@ -55046,7 +40822,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con return MA_SUCCESS; } -static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) { ma_result result; ma_uint64 frameCountIn; @@ -55061,9 +40837,9 @@ static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_co ma_uint64 tempBufferOutCap; MA_ASSERT(pConverter != NULL); - MA_ASSERT(pConverter->resampler.format == pConverter->channelConverter.format); - MA_ASSERT(pConverter->resampler.channels == pConverter->channelConverter.channelsIn); - MA_ASSERT(pConverter->resampler.channels < pConverter->channelConverter.channelsOut); + MA_ASSERT(pConverter->resampler.config.format == pConverter->channelConverter.format); + MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsIn); + MA_ASSERT(pConverter->resampler.config.channels < pConverter->channelConverter.channelsOut); frameCountIn = 0; if (pFrameCountIn != NULL) { @@ -55078,8 +40854,8 @@ static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_co framesProcessedIn = 0; framesProcessedOut = 0; - tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); - tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); + tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); + tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut); while (framesProcessedOut < frameCountOut) { @@ -55091,10 +40867,10 @@ static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_co void* pChannelsBufferOut; if (pFramesIn != NULL) { - pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); } if (pFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } /* Run input data through the resampler and output it to the temporary buffer. */ @@ -55119,31 +40895,16 @@ static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_co } /* We need to ensure we don't try to process too many input frames that we run out of room in the output buffer. If this happens we'll end up glitching. */ - - /* - We need to try to predict how many input frames will be required for the resampler. If the - resampler can tell us, we'll use that. Otherwise we'll need to make a best guess. The further - off we are from this, the more wasted format conversions we'll end up doing. - */ - #if 1 { - ma_uint64 requiredInputFrameCount; - - result = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration, &requiredInputFrameCount); - if (result != MA_SUCCESS) { - /* Fall back to a best guess. */ - requiredInputFrameCount = (frameCountOutThisIteration * pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut; - } - + ma_uint64 requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration); if (frameCountInThisIteration > requiredInputFrameCount) { frameCountInThisIteration = requiredInputFrameCount; } } - #endif if (pConverter->hasPreFormatConversion) { if (pFramesIn != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pRunningFramesIn, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); pResampleBufferIn = pTempBufferIn; } else { pResampleBufferIn = NULL; @@ -55176,7 +40937,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_co /* Finally we do post format conversion. */ if (pConverter->hasPostFormatConversion) { - ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->ditherMode); + ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode); } } @@ -55217,9 +40978,9 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co ma_uint64 tempBufferOutCap; MA_ASSERT(pConverter != NULL); - MA_ASSERT(pConverter->resampler.format == pConverter->channelConverter.format); - MA_ASSERT(pConverter->resampler.channels == pConverter->channelConverter.channelsOut); - MA_ASSERT(pConverter->resampler.channels <= pConverter->channelConverter.channelsIn); + MA_ASSERT(pConverter->resampler.config.format == pConverter->channelConverter.format); + MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsOut); + MA_ASSERT(pConverter->resampler.config.channels < pConverter->channelConverter.channelsIn); frameCountIn = 0; if (pFrameCountIn != NULL) { @@ -55236,7 +40997,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn); tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut); - tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); + tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); while (framesProcessedOut < frameCountOut) { ma_uint64 frameCountInThisIteration; @@ -55247,67 +41008,22 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co void* pResampleBufferOut; if (pFramesIn != NULL) { - pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); } if (pFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); } - /* - Before doing any processing we need to determine how many frames we should try processing - this iteration, for both input and output. The resampler requires us to perform format and - channel conversion before passing any data into it. If we get our input count wrong, we'll - end up performing redundant pre-processing. This isn't the end of the world, but it does - result in some inefficiencies proportionate to how far our estimates are off. - - If the resampler has a means to calculate exactly how much we'll need, we'll use that. - Otherwise we'll make a best guess. In order to do this, we'll need to calculate the output - frame count first. - */ - frameCountOutThisIteration = (frameCountOut - framesProcessedOut); - if (frameCountOutThisIteration > tempBufferMidCap) { - frameCountOutThisIteration = tempBufferMidCap; - } - - if (pConverter->hasPostFormatConversion) { - if (frameCountOutThisIteration > tempBufferOutCap) { - frameCountOutThisIteration = tempBufferOutCap; - } - } - - /* Now that we have the output frame count we can determine the input frame count. */ + /* Run input data through the channel converter and output it to the temporary buffer. */ frameCountInThisIteration = (frameCountIn - framesProcessedIn); + if (pConverter->hasPreFormatConversion) { if (frameCountInThisIteration > tempBufferInCap) { frameCountInThisIteration = tempBufferInCap; } - } - if (frameCountInThisIteration > tempBufferMidCap) { - frameCountInThisIteration = tempBufferMidCap; - } - - #if 1 - { - ma_uint64 requiredInputFrameCount; - - result = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration, &requiredInputFrameCount); - if (result != MA_SUCCESS) { - /* Fall back to a best guess. */ - requiredInputFrameCount = (frameCountOutThisIteration * pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut; - } - - if (frameCountInThisIteration > requiredInputFrameCount) { - frameCountInThisIteration = requiredInputFrameCount; - } - } - #endif - - - /* Pre format conversion. */ - if (pConverter->hasPreFormatConversion) { if (pRunningFramesIn != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); pChannelsBufferIn = pTempBufferIn; } else { pChannelsBufferIn = NULL; @@ -55316,15 +41032,43 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co pChannelsBufferIn = pRunningFramesIn; } + /* + We can't convert more frames than will fit in the output buffer. We shouldn't actually need to do this check because the channel count is always reduced + in this case which means we should always have capacity, but I'm leaving it here just for safety for future maintenance. + */ + if (frameCountInThisIteration > tempBufferMidCap) { + frameCountInThisIteration = tempBufferMidCap; + } + + /* + Make sure we don't read any more input frames than we need to fill the output frame count. If we do this we will end up in a situation where we lose some + input samples and will end up glitching. + */ + frameCountOutThisIteration = (frameCountOut - framesProcessedOut); + if (frameCountOutThisIteration > tempBufferMidCap) { + frameCountOutThisIteration = tempBufferMidCap; + } + + if (pConverter->hasPostFormatConversion) { + ma_uint64 requiredInputFrameCount; + + if (frameCountOutThisIteration > tempBufferOutCap) { + frameCountOutThisIteration = tempBufferOutCap; + } + + requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration); + if (frameCountInThisIteration > requiredInputFrameCount) { + frameCountInThisIteration = requiredInputFrameCount; + } + } - /* Channel conversion. */ result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferMid, pChannelsBufferIn, frameCountInThisIteration); if (result != MA_SUCCESS) { return result; } - /* Resampling. */ + /* At this point we have converted the channels to the output channel count which we now need to resample. */ if (pConverter->hasPostFormatConversion) { pResampleBufferOut = pTempBufferOut; } else { @@ -55336,15 +41080,13 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co return result; } - - /* Post format conversion. */ + /* Finally we can do the post format conversion. */ if (pConverter->hasPostFormatConversion) { if (pRunningFramesOut != NULL) { - ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->formatOut, pResampleBufferOut, pConverter->resampler.format, frameCountOutThisIteration, pConverter->channelsOut, pConverter->ditherMode); + ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pResampleBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->config.channelsOut, pConverter->config.ditherMode); } } - framesProcessedIn += frameCountInThisIteration; framesProcessedOut += frameCountOutThisIteration; @@ -55372,15 +41114,46 @@ MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConver return MA_INVALID_ARGS; } - switch (pConverter->executionPath) - { - case ma_data_converter_execution_path_passthrough: return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - case ma_data_converter_execution_path_format_only: return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - case ma_data_converter_execution_path_channels_only: return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - case ma_data_converter_execution_path_resample_only: return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - case ma_data_converter_execution_path_resample_first: return ma_data_converter_process_pcm_frames__resample_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - case ma_data_converter_execution_path_channels_first: return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - default: return MA_INVALID_OPERATION; /* Should never hit this. */ + if (pConverter->isPassthrough) { + return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } + + /* + Here is where the real work is done. Getting here means we're not using a passthrough and we need to move the data through each of the relevant stages. The order + of our stages depends on the input and output channel count. If the input channels is less than the output channels we want to do sample rate conversion first so + that it has less work (resampling is the most expensive part of format conversion). + */ + if (pConverter->config.channelsIn < pConverter->config.channelsOut) { + /* Do resampling first, if necessary. */ + MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE); + + if (pConverter->hasResampler) { + /* Resampling first. */ + return ma_data_converter_process_pcm_frames__resampling_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + /* Resampling not required. */ + return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } + } else { + /* Do channel conversion first, if necessary. */ + if (pConverter->hasChannelConverter) { + if (pConverter->hasResampler) { + /* Channel routing first. */ + return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + /* Resampling not required. */ + return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } + } else { + /* Channel routing not required. */ + if (pConverter->hasResampler) { + /* Resampling only. */ + return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + /* No channel routing nor resampling required. Just format conversion. */ + return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } + } } } @@ -55410,6 +41183,32 @@ MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, return ma_resampler_set_rate_ratio(&pConverter->resampler, ratioInOut); } +MA_API ma_uint64 ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount) +{ + if (pConverter == NULL) { + return 0; + } + + if (pConverter->hasResampler) { + return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount); + } else { + return outputFrameCount; /* 1:1 */ + } +} + +MA_API ma_uint64 ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount) +{ + if (pConverter == NULL) { + return 0; + } + + if (pConverter->hasResampler) { + return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount); + } else { + return inputFrameCount; /* 1:1 */ + } +} + MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter) { if (pConverter == NULL) { @@ -55436,90 +41235,6 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* p return 0; /* No latency without a resampler. */ } -MA_API ma_result ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) -{ - if (pInputFrameCount == NULL) { - return MA_INVALID_ARGS; - } - - *pInputFrameCount = 0; - - if (pConverter == NULL) { - return MA_INVALID_ARGS; - } - - if (pConverter->hasResampler) { - return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount, pInputFrameCount); - } else { - *pInputFrameCount = outputFrameCount; /* 1:1 */ - return MA_SUCCESS; - } -} - -MA_API ma_result ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) -{ - if (pOutputFrameCount == NULL) { - return MA_INVALID_ARGS; - } - - *pOutputFrameCount = 0; - - if (pConverter == NULL) { - return MA_INVALID_ARGS; - } - - if (pConverter->hasResampler) { - return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount, pOutputFrameCount); - } else { - *pOutputFrameCount = inputFrameCount; /* 1:1 */ - return MA_SUCCESS; - } -} - -MA_API ma_result ma_data_converter_get_input_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pConverter == NULL || pChannelMap == NULL) { - return MA_INVALID_ARGS; - } - - if (pConverter->hasChannelConverter) { - ma_channel_converter_get_output_channel_map(&pConverter->channelConverter, pChannelMap, channelMapCap); - } else { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pConverter->channelsOut); - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_data_converter_get_output_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pConverter == NULL || pChannelMap == NULL) { - return MA_INVALID_ARGS; - } - - if (pConverter->hasChannelConverter) { - ma_channel_converter_get_input_channel_map(&pConverter->channelConverter, pChannelMap, channelMapCap); - } else { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pConverter->channelsIn); - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_data_converter_reset(ma_data_converter* pConverter) -{ - if (pConverter == NULL) { - return MA_INVALID_ARGS; - } - - /* There's nothing to do if we're not resampling. */ - if (pConverter->hasResampler == MA_FALSE) { - return MA_SUCCESS; - } - - return ma_resampler_reset(&pConverter->resampler); -} - /************************************************************************************************************************************************************** @@ -55527,22 +41242,7 @@ MA_API ma_result ma_data_converter_reset(ma_data_converter* pConverter) Channel Maps **************************************************************************************************************************************************************/ -static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex); - -MA_API ma_channel ma_channel_map_get_channel(const ma_channel* pChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex) -{ - if (pChannelMap == NULL) { - return ma_channel_map_init_standard_channel(ma_standard_channel_map_default, channelCount, channelIndex); - } else { - if (channelIndex >= channelCount) { - return MA_CHANNEL_NONE; - } - - return pChannelMap[channelIndex]; - } -} - -MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channels) +MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap) { if (pChannelMap == NULL) { return; @@ -55551,734 +41251,622 @@ MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channel MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels); } - -static ma_channel ma_channel_map_init_standard_channel_microsoft(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel* pChannelMap) { - if (channelCount == 0 || channelIndex >= channelCount) { - return MA_CHANNEL_NONE; - } - - /* This is the Microsoft channel map. Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */ - switch (channelCount) + /* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */ + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; } break; - case 3: /* No defined, but best guess. */ + case 3: /* Not defined, but best guess. */ { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - switch (channelIndex) { - #ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP - /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */ - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_BACK_CENTER; - #else - /* Quad. */ - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - #endif - } +#ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP + /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */ + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_CENTER; +#else + /* Quad. */ + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; +#endif } break; case 5: /* Not defined, but best guess. */ { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_LFE; - case 4: return MA_CHANNEL_SIDE_LEFT; - case 5: return MA_CHANNEL_SIDE_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[5] = MA_CHANNEL_SIDE_RIGHT; } break; case 7: /* Not defined, but best guess. */ { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_LFE; - case 4: return MA_CHANNEL_BACK_CENTER; - case 5: return MA_CHANNEL_SIDE_LEFT; - case 6: return MA_CHANNEL_SIDE_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_CENTER; + pChannelMap[5] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT; } break; case 8: default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_LFE; - case 4: return MA_CHANNEL_BACK_LEFT; - case 5: return MA_CHANNEL_BACK_RIGHT; - case 6: return MA_CHANNEL_SIDE_LEFT; - case 7: return MA_CHANNEL_SIDE_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_LEFT; + pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } - if (channelCount > 8) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 8; iChannel < channels; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } -static ma_channel ma_channel_map_init_standard_channel_alsa(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel* pChannelMap) { - switch (channelCount) + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - case 4: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - case 4: return MA_CHANNEL_FRONT_CENTER; - case 5: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; } break; case 7: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - case 4: return MA_CHANNEL_FRONT_CENTER; - case 5: return MA_CHANNEL_LFE; - case 6: return MA_CHANNEL_BACK_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + pChannelMap[6] = MA_CHANNEL_BACK_CENTER; } break; case 8: default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - case 4: return MA_CHANNEL_FRONT_CENTER; - case 5: return MA_CHANNEL_LFE; - case 6: return MA_CHANNEL_SIDE_LEFT; - case 7: return MA_CHANNEL_SIDE_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } - if (channelCount > 8) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 8; iChannel < channels; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } -static ma_channel ma_channel_map_init_standard_channel_rfc3551(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel* pChannelMap) { - switch (channelCount) + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_BACK_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_BACK_CENTER; } break; case 5: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: - default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_SIDE_LEFT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_FRONT_RIGHT; - case 4: return MA_CHANNEL_SIDE_RIGHT; - case 5: return MA_CHANNEL_BACK_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; } break; } - if (channelCount > 6) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6)); + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 6; iChannel < channels; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } -static ma_channel ma_channel_map_init_standard_channel_flac(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel* pChannelMap) { - switch (channelCount) + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_LFE; - case 4: return MA_CHANNEL_BACK_LEFT; - case 5: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_LEFT; + pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; } break; case 7: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_LFE; - case 4: return MA_CHANNEL_BACK_CENTER; - case 5: return MA_CHANNEL_SIDE_LEFT; - case 6: return MA_CHANNEL_SIDE_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_CENTER; + pChannelMap[5] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT; } break; case 8: default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_LFE; - case 4: return MA_CHANNEL_BACK_LEFT; - case 5: return MA_CHANNEL_BACK_RIGHT; - case 6: return MA_CHANNEL_SIDE_LEFT; - case 7: return MA_CHANNEL_SIDE_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_LEFT; + pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } - if (channelCount > 8) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 8; iChannel < channels; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } -static ma_channel ma_channel_map_init_standard_channel_vorbis(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel* pChannelMap) { - switch (channelCount) + /* In Vorbis' type 0 channel mapping, the first two channels are not always the standard left/right - it will have the center speaker where the right usually goes. Why?! */ + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; } break; case 4: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - case 5: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[5] = MA_CHANNEL_LFE; } break; case 7: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_SIDE_LEFT; - case 4: return MA_CHANNEL_SIDE_RIGHT; - case 5: return MA_CHANNEL_BACK_CENTER; - case 6: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; + pChannelMap[6] = MA_CHANNEL_LFE; } break; case 8: default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_SIDE_LEFT; - case 4: return MA_CHANNEL_SIDE_RIGHT; - case 5: return MA_CHANNEL_BACK_LEFT; - case 6: return MA_CHANNEL_BACK_RIGHT; - case 7: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[5] = MA_CHANNEL_BACK_LEFT; + pChannelMap[6] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[7] = MA_CHANNEL_LFE; } break; } - if (channelCount > 8) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 8; iChannel < channels; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } -static ma_channel ma_channel_map_init_standard_channel_sound4(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel* pChannelMap) { - switch (channelCount) + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_CENTER; } break; case 4: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_BACK_LEFT; - case 4: return MA_CHANNEL_BACK_RIGHT; - case 5: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; } break; case 7: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_SIDE_LEFT; - case 4: return MA_CHANNEL_SIDE_RIGHT; - case 5: return MA_CHANNEL_BACK_CENTER; - case 6: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; + pChannelMap[6] = MA_CHANNEL_LFE; } break; case 8: default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_CENTER; - case 2: return MA_CHANNEL_FRONT_RIGHT; - case 3: return MA_CHANNEL_SIDE_LEFT; - case 4: return MA_CHANNEL_SIDE_RIGHT; - case 5: return MA_CHANNEL_BACK_LEFT; - case 6: return MA_CHANNEL_BACK_RIGHT; - case 7: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } - if (channelCount > 8) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } -static ma_channel ma_channel_map_init_standard_channel_sndio(ma_uint32 channelCount, ma_uint32 channelIndex) +static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel* pChannelMap) { - switch (channelCount) + switch (channels) { - case 0: return MA_CHANNEL_NONE; - case 1: { - return MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; - case 3: /* No defined, but best guess. */ + case 3: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; - case 5: /* Not defined, but best guess. */ + case 5: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - case 4: return MA_CHANNEL_FRONT_CENTER; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: default: { - switch (channelIndex) { - case 0: return MA_CHANNEL_FRONT_LEFT; - case 1: return MA_CHANNEL_FRONT_RIGHT; - case 2: return MA_CHANNEL_BACK_LEFT; - case 3: return MA_CHANNEL_BACK_RIGHT; - case 4: return MA_CHANNEL_FRONT_CENTER; - case 5: return MA_CHANNEL_LFE; - } + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; } break; } - if (channelCount > 6) { - if (channelIndex < 32) { /* We have 32 AUX channels. */ - return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6)); + /* Remainder. */ + if (channels > 6) { + ma_uint32 iChannel; + for (iChannel = 6; iChannel < channels && iChannel < MA_MAX_CHANNELS; ++iChannel) { + if (iChannel < MA_MAX_CHANNELS) { + pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); + } else { + pChannelMap[iChannel] = MA_CHANNEL_NONE; + } } } - - /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ - return MA_CHANNEL_NONE; } - -static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex) +MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap) { - if (channelCount == 0 || channelIndex >= channelCount) { - return MA_CHANNEL_NONE; - } - switch (standardChannelMap) { case ma_standard_channel_map_alsa: { - return ma_channel_map_init_standard_channel_alsa(channelCount, channelIndex); + ma_get_standard_channel_map_alsa(channels, pChannelMap); } break; case ma_standard_channel_map_rfc3551: { - return ma_channel_map_init_standard_channel_rfc3551(channelCount, channelIndex); + ma_get_standard_channel_map_rfc3551(channels, pChannelMap); } break; case ma_standard_channel_map_flac: { - return ma_channel_map_init_standard_channel_flac(channelCount, channelIndex); + ma_get_standard_channel_map_flac(channels, pChannelMap); } break; case ma_standard_channel_map_vorbis: { - return ma_channel_map_init_standard_channel_vorbis(channelCount, channelIndex); + ma_get_standard_channel_map_vorbis(channels, pChannelMap); } break; case ma_standard_channel_map_sound4: { - return ma_channel_map_init_standard_channel_sound4(channelCount, channelIndex); + ma_get_standard_channel_map_sound4(channels, pChannelMap); } break; case ma_standard_channel_map_sndio: { - return ma_channel_map_init_standard_channel_sndio(channelCount, channelIndex); + ma_get_standard_channel_map_sndio(channels, pChannelMap); } break; case ma_standard_channel_map_microsoft: /* Also default. */ /*case ma_standard_channel_map_default;*/ default: { - return ma_channel_map_init_standard_channel_microsoft(channelCount, channelIndex); + ma_get_standard_channel_map_microsoft(channels, pChannelMap); } break; } } -MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels) -{ - ma_uint32 iChannel; - - if (pChannelMap == NULL || channelMapCap == 0 || channels == 0) { - return; - } - - for (iChannel = 0; iChannel < channels; iChannel += 1) { - if (channelMapCap == 0) { - break; /* Ran out of room. */ - } - - pChannelMap[0] = ma_channel_map_init_standard_channel(standardChannelMap, channels, iChannel); - pChannelMap += 1; - channelMapCap -= 1; - } -} - MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels) { if (pOut != NULL && pIn != NULL && channels > 0) { @@ -56286,7 +41874,7 @@ MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint } } -MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels) +MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels) { if (pOut == NULL || channels == 0) { return; @@ -56295,12 +41883,16 @@ MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCa if (pIn != NULL) { ma_channel_map_copy(pOut, pIn, channels); } else { - ma_channel_map_init_standard(ma_standard_channel_map_default, pOut, channelMapCapOut, channels); + ma_get_standard_channel_map(ma_standard_channel_map_default, channels, pOut); } } -MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels) +MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap) { + if (pChannelMap == NULL) { + return MA_FALSE; + } + /* A channel count of 0 is invalid. */ if (channels == 0) { return MA_FALSE; @@ -56310,7 +41902,7 @@ MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint3 if (channels > 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { - if (ma_channel_map_get_channel(pChannelMap, channels, iChannel) == MA_CHANNEL_MONO) { + if (pChannelMap[iChannel] == MA_CHANNEL_MONO) { return MA_FALSE; } } @@ -56319,7 +41911,7 @@ MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint3 return MA_TRUE; } -MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels) +MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB) { ma_uint32 iChannel; @@ -56328,7 +41920,7 @@ MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const m } for (iChannel = 0; iChannel < channels; ++iChannel) { - if (ma_channel_map_get_channel(pChannelMapA, channels, iChannel) != ma_channel_map_get_channel(pChannelMapB, channels, iChannel)) { + if (pChannelMapA[iChannel] != pChannelMapB[iChannel]) { return MA_FALSE; } } @@ -56336,15 +41928,10 @@ MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const m return MA_TRUE; } -MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels) +MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap) { ma_uint32 iChannel; - /* A null channel map is equivalent to the default channel map. */ - if (pChannelMap == NULL) { - return MA_FALSE; - } - for (iChannel = 0; iChannel < channels; ++iChannel) { if (pChannelMap[iChannel] != MA_CHANNEL_NONE) { return MA_FALSE; @@ -56355,128 +41942,18 @@ MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint3 } MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition) -{ - return ma_channel_map_find_channel_position(channels, pChannelMap, channelPosition, NULL); -} - -MA_API ma_bool32 ma_channel_map_find_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition, ma_uint32* pChannelIndex) { ma_uint32 iChannel; - if (pChannelIndex != NULL) { - *pChannelIndex = (ma_uint32)-1; - } - for (iChannel = 0; iChannel < channels; ++iChannel) { - if (ma_channel_map_get_channel(pChannelMap, channels, iChannel) == channelPosition) { - if (pChannelIndex != NULL) { - *pChannelIndex = iChannel; - } - + if (pChannelMap[iChannel] == channelPosition) { return MA_TRUE; } } - /* Getting here means the channel position was not found. */ return MA_FALSE; } -MA_API size_t ma_channel_map_to_string(const ma_channel* pChannelMap, ma_uint32 channels, char* pBufferOut, size_t bufferCap) -{ - size_t len; - ma_uint32 iChannel; - - len = 0; - - for (iChannel = 0; iChannel < channels; iChannel += 1) { - const char* pChannelStr = ma_channel_position_to_string(ma_channel_map_get_channel(pChannelMap, channels, iChannel)); - size_t channelStrLen = strlen(pChannelStr); - - /* Append the string if necessary. */ - if (pBufferOut != NULL && bufferCap > len + channelStrLen) { - MA_COPY_MEMORY(pBufferOut + len, pChannelStr, channelStrLen); - } - len += channelStrLen; - - /* Append a space if it's not the last item. */ - if (iChannel+1 < channels) { - if (pBufferOut != NULL && bufferCap > len + 1) { - pBufferOut[len] = ' '; - } - len += 1; - } - } - - /* Null terminate. Don't increment the length here. */ - if (pBufferOut != NULL && bufferCap > len + 1) { - pBufferOut[len] = '\0'; - } - - return len; -} - -MA_API const char* ma_channel_position_to_string(ma_channel channel) -{ - switch (channel) - { - case MA_CHANNEL_NONE : return "CHANNEL_NONE"; - case MA_CHANNEL_MONO : return "CHANNEL_MONO"; - case MA_CHANNEL_FRONT_LEFT : return "CHANNEL_FRONT_LEFT"; - case MA_CHANNEL_FRONT_RIGHT : return "CHANNEL_FRONT_RIGHT"; - case MA_CHANNEL_FRONT_CENTER : return "CHANNEL_FRONT_CENTER"; - case MA_CHANNEL_LFE : return "CHANNEL_LFE"; - case MA_CHANNEL_BACK_LEFT : return "CHANNEL_BACK_LEFT"; - case MA_CHANNEL_BACK_RIGHT : return "CHANNEL_BACK_RIGHT"; - case MA_CHANNEL_FRONT_LEFT_CENTER : return "CHANNEL_FRONT_LEFT_CENTER"; - case MA_CHANNEL_FRONT_RIGHT_CENTER: return "CHANNEL_FRONT_RIGHT_CENTER"; - case MA_CHANNEL_BACK_CENTER : return "CHANNEL_BACK_CENTER"; - case MA_CHANNEL_SIDE_LEFT : return "CHANNEL_SIDE_LEFT"; - case MA_CHANNEL_SIDE_RIGHT : return "CHANNEL_SIDE_RIGHT"; - case MA_CHANNEL_TOP_CENTER : return "CHANNEL_TOP_CENTER"; - case MA_CHANNEL_TOP_FRONT_LEFT : return "CHANNEL_TOP_FRONT_LEFT"; - case MA_CHANNEL_TOP_FRONT_CENTER : return "CHANNEL_TOP_FRONT_CENTER"; - case MA_CHANNEL_TOP_FRONT_RIGHT : return "CHANNEL_TOP_FRONT_RIGHT"; - case MA_CHANNEL_TOP_BACK_LEFT : return "CHANNEL_TOP_BACK_LEFT"; - case MA_CHANNEL_TOP_BACK_CENTER : return "CHANNEL_TOP_BACK_CENTER"; - case MA_CHANNEL_TOP_BACK_RIGHT : return "CHANNEL_TOP_BACK_RIGHT"; - case MA_CHANNEL_AUX_0 : return "CHANNEL_AUX_0"; - case MA_CHANNEL_AUX_1 : return "CHANNEL_AUX_1"; - case MA_CHANNEL_AUX_2 : return "CHANNEL_AUX_2"; - case MA_CHANNEL_AUX_3 : return "CHANNEL_AUX_3"; - case MA_CHANNEL_AUX_4 : return "CHANNEL_AUX_4"; - case MA_CHANNEL_AUX_5 : return "CHANNEL_AUX_5"; - case MA_CHANNEL_AUX_6 : return "CHANNEL_AUX_6"; - case MA_CHANNEL_AUX_7 : return "CHANNEL_AUX_7"; - case MA_CHANNEL_AUX_8 : return "CHANNEL_AUX_8"; - case MA_CHANNEL_AUX_9 : return "CHANNEL_AUX_9"; - case MA_CHANNEL_AUX_10 : return "CHANNEL_AUX_10"; - case MA_CHANNEL_AUX_11 : return "CHANNEL_AUX_11"; - case MA_CHANNEL_AUX_12 : return "CHANNEL_AUX_12"; - case MA_CHANNEL_AUX_13 : return "CHANNEL_AUX_13"; - case MA_CHANNEL_AUX_14 : return "CHANNEL_AUX_14"; - case MA_CHANNEL_AUX_15 : return "CHANNEL_AUX_15"; - case MA_CHANNEL_AUX_16 : return "CHANNEL_AUX_16"; - case MA_CHANNEL_AUX_17 : return "CHANNEL_AUX_17"; - case MA_CHANNEL_AUX_18 : return "CHANNEL_AUX_18"; - case MA_CHANNEL_AUX_19 : return "CHANNEL_AUX_19"; - case MA_CHANNEL_AUX_20 : return "CHANNEL_AUX_20"; - case MA_CHANNEL_AUX_21 : return "CHANNEL_AUX_21"; - case MA_CHANNEL_AUX_22 : return "CHANNEL_AUX_22"; - case MA_CHANNEL_AUX_23 : return "CHANNEL_AUX_23"; - case MA_CHANNEL_AUX_24 : return "CHANNEL_AUX_24"; - case MA_CHANNEL_AUX_25 : return "CHANNEL_AUX_25"; - case MA_CHANNEL_AUX_26 : return "CHANNEL_AUX_26"; - case MA_CHANNEL_AUX_27 : return "CHANNEL_AUX_27"; - case MA_CHANNEL_AUX_28 : return "CHANNEL_AUX_28"; - case MA_CHANNEL_AUX_29 : return "CHANNEL_AUX_29"; - case MA_CHANNEL_AUX_30 : return "CHANNEL_AUX_30"; - case MA_CHANNEL_AUX_31 : return "CHANNEL_AUX_31"; - default: break; - } - - return "UNKNOWN"; -} - /************************************************************************************************************************************************************** @@ -56489,6 +41966,8 @@ MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_forma ma_data_converter_config config; config = ma_data_converter_config_init(formatIn, formatOut, channelsIn, channelsOut, sampleRateIn, sampleRateOut); + ma_get_standard_channel_map(ma_standard_channel_map_default, channelsOut, config.channelMapOut); + ma_get_standard_channel_map(ma_standard_channel_map_default, channelsIn, config.channelMapIn); config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); return ma_convert_frames_ex(pOut, frameCountOut, pIn, frameCountIn, &config); @@ -56503,31 +41982,13 @@ MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const return 0; } - result = ma_data_converter_init(pConfig, NULL, &converter); + result = ma_data_converter_init(pConfig, &converter); if (result != MA_SUCCESS) { return 0; /* Failed to initialize the data converter. */ } if (pOut == NULL) { - result = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn, &frameCountOut); - if (result != MA_SUCCESS) { - if (result == MA_NOT_IMPLEMENTED) { - /* No way to calculate the number of frames, so we'll need to brute force it and loop. */ - frameCountOut = 0; - - while (frameCountIn > 0) { - ma_uint64 framesProcessedIn = frameCountIn; - ma_uint64 framesProcessedOut = 0xFFFFFFFF; - - result = ma_data_converter_process_pcm_frames(&converter, pIn, &framesProcessedIn, NULL, &framesProcessedOut); - if (result != MA_SUCCESS) { - break; - } - - frameCountIn -= framesProcessedIn; - } - } - } + frameCountOut = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn); } else { result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut); if (result != MA_SUCCESS) { @@ -56535,7 +41996,7 @@ MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const } } - ma_data_converter_uninit(&converter, NULL); + ma_data_converter_uninit(&converter); return frameCountOut; } @@ -56558,13 +42019,13 @@ static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffs static MA_INLINE void* ma_rb__get_read_ptr(ma_rb* pRB) { MA_ASSERT(pRB != NULL); - return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(ma_atomic_load_32(&pRB->encodedReadOffset))); + return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedReadOffset))); } static MA_INLINE void* ma_rb__get_write_ptr(ma_rb* pRB) { MA_ASSERT(pRB != NULL); - return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(ma_atomic_load_32(&pRB->encodedWriteOffset))); + return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedWriteOffset))); } static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag) @@ -56657,8 +42118,8 @@ MA_API void ma_rb_reset(ma_rb* pRB) return; } - ma_atomic_exchange_32(&pRB->encodedReadOffset, 0); - ma_atomic_exchange_32(&pRB->encodedWriteOffset, 0); + c89atomic_exchange_32(&pRB->encodedReadOffset, 0); + c89atomic_exchange_32(&pRB->encodedWriteOffset, 0); } MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut) @@ -56677,10 +42138,10 @@ MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppB } /* The returned buffer should never move ahead of the write pointer. */ - writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); - readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); /* @@ -56704,7 +42165,7 @@ MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppB return MA_SUCCESS; } -MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) +MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; @@ -56716,7 +42177,12 @@ MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) return MA_INVALID_ARGS; } - readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + /* Validate the buffer. */ + if (pBufferOut != ma_rb__get_read_ptr(pRB)) { + return MA_INVALID_ARGS; + } + + readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */ @@ -56732,8 +42198,7 @@ MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) newReadOffsetLoopFlag ^= 0x80000000; } - ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); - + c89atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes)); return MA_SUCCESS; } @@ -56753,10 +42218,10 @@ MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** pp } /* The returned buffer should never overtake the read buffer. */ - readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); - writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); /* @@ -56786,7 +42251,7 @@ MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** pp return MA_SUCCESS; } -MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) +MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut) { ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; @@ -56798,7 +42263,12 @@ MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) return MA_INVALID_ARGS; } - writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + /* Validate the buffer. */ + if (pBufferOut != ma_rb__get_write_ptr(pRB)) { + return MA_INVALID_ARGS; + } + + writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */ @@ -56814,8 +42284,7 @@ MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) newWriteOffsetLoopFlag ^= 0x80000000; } - ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); - + c89atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes)); return MA_SUCCESS; } @@ -56834,10 +42303,10 @@ MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes) return MA_INVALID_ARGS; } - readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); - writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); newReadOffsetLoopFlag = readOffsetLoopFlag; @@ -56859,7 +42328,7 @@ MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes) } } - ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); + c89atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); return MA_SUCCESS; } @@ -56878,10 +42347,10 @@ MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes) return MA_INVALID_ARGS; } - readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); - writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); newWriteOffsetLoopFlag = writeOffsetLoopFlag; @@ -56903,7 +42372,7 @@ MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes) } } - ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); + c89atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); return MA_SUCCESS; } @@ -56920,10 +42389,10 @@ MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB) return 0; } - readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); - writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); if (readOffsetLoopFlag == writeOffsetLoopFlag) { @@ -57000,95 +42469,6 @@ MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pB -static ma_result ma_pcm_rb_data_source__on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - /* Since there's no notion of an end, we don't ever want to return MA_AT_END here. But it is possible to return 0. */ - ma_pcm_rb* pRB = (ma_pcm_rb*)pDataSource; - ma_result result; - ma_uint64 totalFramesRead; - - MA_ASSERT(pRB != NULL); - - /* We need to run this in a loop since the ring buffer itself may loop. */ - totalFramesRead = 0; - while (totalFramesRead < frameCount) { - void* pMappedBuffer; - ma_uint32 mappedFrameCount; - ma_uint64 framesToRead = frameCount - totalFramesRead; - if (framesToRead > 0xFFFFFFFF) { - framesToRead = 0xFFFFFFFF; - } - - mappedFrameCount = (ma_uint32)framesToRead; - result = ma_pcm_rb_acquire_read(pRB, &mappedFrameCount, &pMappedBuffer); - if (result != MA_SUCCESS) { - break; - } - - if (mappedFrameCount == 0) { - break; /* <-- End of ring buffer. */ - } - - ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, pRB->format, pRB->channels), pMappedBuffer, mappedFrameCount, pRB->format, pRB->channels); - - result = ma_pcm_rb_commit_read(pRB, mappedFrameCount); - if (result != MA_SUCCESS) { - break; - } - - totalFramesRead += mappedFrameCount; - } - - /* - There is no notion of an "end" in a ring buffer. If we didn't have enough data to fill the requested frame - count we'll need to pad with silence. If we don't do this, totalFramesRead might equal 0 which will result - in the data source layer at a higher level translating this to MA_AT_END which is incorrect for a ring buffer. - */ - if (totalFramesRead < frameCount) { - ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, pRB->format, pRB->channels), (frameCount - totalFramesRead), pRB->format, pRB->channels); - totalFramesRead = frameCount; - } - - *pFramesRead = totalFramesRead; - return MA_SUCCESS; -} - -static ma_result ma_pcm_rb_data_source__on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_pcm_rb* pRB = (ma_pcm_rb*)pDataSource; - MA_ASSERT(pRB != NULL); - - if (pFormat != NULL) { - *pFormat = pRB->format; - } - - if (pChannels != NULL) { - *pChannels = pRB->channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pRB->sampleRate; - } - - /* Just assume the default channel map. */ - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pRB->channels); - } - - return MA_SUCCESS; -} - -static ma_data_source_vtable ma_gRBDataSourceVTable = -{ - ma_pcm_rb_data_source__on_read, - NULL, /* onSeek */ - ma_pcm_rb_data_source__on_get_data_format, - NULL, /* onGetCursor */ - NULL, /* onGetLength */ - NULL, /* onSetLooping */ - 0 -}; - static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB) { MA_ASSERT(pRB != NULL); @@ -57117,21 +42497,8 @@ MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint return result; } - pRB->format = format; - pRB->channels = channels; - pRB->sampleRate = 0; /* The sample rate is not passed in as a parameter. */ - - /* The PCM ring buffer is a data source. We need to get that set up as well. */ - { - ma_data_source_config dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &ma_gRBDataSourceVTable; - - result = ma_data_source_init(&dataSourceConfig, &pRB->ds); - if (result != MA_SUCCESS) { - ma_rb_uninit(&pRB->rb); - return result; - } - } + pRB->format = format; + pRB->channels = channels; return MA_SUCCESS; } @@ -57147,7 +42514,6 @@ MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB) return; } - ma_data_source_uninit(&pRB->ds); ma_rb_uninit(&pRB->rb); } @@ -57180,13 +42546,13 @@ MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames return MA_SUCCESS; } -MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames) +MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut) { if (pRB == NULL) { return MA_INVALID_ARGS; } - return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB)); + return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut); } MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut) @@ -57209,13 +42575,13 @@ MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrame return MA_SUCCESS; } -MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames) +MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut) { if (pRB == NULL) { return MA_INVALID_ARGS; } - return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB)); + return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut); } MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames) @@ -57299,42 +42665,6 @@ MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferInde return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer); } -MA_API ma_format ma_pcm_rb_get_format(const ma_pcm_rb* pRB) -{ - if (pRB == NULL) { - return ma_format_unknown; - } - - return pRB->format; -} - -MA_API ma_uint32 ma_pcm_rb_get_channels(const ma_pcm_rb* pRB) -{ - if (pRB == NULL) { - return 0; - } - - return pRB->channels; -} - -MA_API ma_uint32 ma_pcm_rb_get_sample_rate(const ma_pcm_rb* pRB) -{ - if (pRB == NULL) { - return 0; - } - - return pRB->sampleRate; -} - -MA_API void ma_pcm_rb_set_sample_rate(ma_pcm_rb* pRB, ma_uint32 sampleRate) -{ - if (pRB == NULL) { - return; - } - - pRB->sampleRate = sampleRate; -} - MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB) @@ -57392,7 +42722,7 @@ MA_API const char* ma_result_description(ma_result result) case MA_NOT_DIRECTORY: return "Not a directory"; case MA_IS_DIRECTORY: return "Is a directory"; case MA_DIRECTORY_NOT_EMPTY: return "Directory not empty"; - case MA_AT_END: return "At end"; + case MA_END_OF_FILE: return "End of file"; case MA_NO_SPACE: return "No space available"; case MA_BUSY: return "Device or resource busy"; case MA_IO_ERROR: return "Input/output error"; @@ -57428,6 +42758,7 @@ MA_API const char* ma_result_description(ma_result result) case MA_IN_PROGRESS: return "Operation in progress"; case MA_CANCELLED: return "Operation cancelled"; case MA_MEMORY_ALREADY_MAPPED: return "Memory already mapped"; + case MA_AT_END: return "Reached end of collection"; case MA_FORMAT_NOT_SUPPORTED: return "Format not supported"; case MA_DEVICE_TYPE_NOT_SUPPORTED: return "Device type not supported"; @@ -57452,33 +42783,19 @@ MA_API const char* ma_result_description(ma_result result) MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { - if (pAllocationCallbacks->onMalloc != NULL) { - return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); - } else { - return NULL; /* Do not fall back to the default implementation. */ - } + return ma__malloc_from_callbacks(sz, pAllocationCallbacks); } else { return ma__malloc_default(sz, NULL); } } -MA_API void* ma_calloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) -{ - void* p = ma_malloc(sz, pAllocationCallbacks); - if (p != NULL) { - MA_ZERO_MEMORY(p, sz); - } - - return p; -} - MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { if (pAllocationCallbacks->onRealloc != NULL) { return pAllocationCallbacks->onRealloc(p, sz, pAllocationCallbacks->pUserData); } else { - return NULL; /* Do not fall back to the default implementation. */ + return NULL; /* This requires a native implementation of realloc(). */ } } else { return ma__realloc_default(p, sz, NULL); @@ -57487,16 +42804,8 @@ MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllo MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) { - if (p == NULL) { - return; - } - if (pAllocationCallbacks != NULL) { - if (pAllocationCallbacks->onFree != NULL) { - pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); - } else { - return; /* Do no fall back to the default implementation. */ - } + ma__free_from_callbacks(p, pAllocationCallbacks); } else { ma__free_default(p, NULL); } @@ -57568,466 +42877,137 @@ MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format) -#define MA_DATA_SOURCE_DEFAULT_RANGE_BEG 0 -#define MA_DATA_SOURCE_DEFAULT_RANGE_END ~((ma_uint64)0) -#define MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG 0 -#define MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END ~((ma_uint64)0) - -MA_API ma_data_source_config ma_data_source_config_init(void) +MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop) { - ma_data_source_config config; - - MA_ZERO_OBJECT(&config); - - return config; -} - - -MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDataSourceBase); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->vtable == NULL) { - return MA_INVALID_ARGS; - } - - pDataSourceBase->vtable = pConfig->vtable; - pDataSourceBase->rangeBegInFrames = MA_DATA_SOURCE_DEFAULT_RANGE_BEG; - pDataSourceBase->rangeEndInFrames = MA_DATA_SOURCE_DEFAULT_RANGE_END; - pDataSourceBase->loopBegInFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG; - pDataSourceBase->loopEndInFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END; - pDataSourceBase->pCurrent = pDataSource; /* Always read from ourself by default. */ - pDataSourceBase->pNext = NULL; - pDataSourceBase->onGetNext = NULL; - - return MA_SUCCESS; -} - -MA_API void ma_data_source_uninit(ma_data_source* pDataSource) -{ - if (pDataSource == NULL) { - return; - } - - /* - This is placeholder in case we need this later. Data sources need to call this in their - uninitialization routine to ensure things work later on if something is added here. - */ -} - -static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_data_source** ppCurrentDataSource) -{ - ma_data_source_base* pCurrentDataSource = (ma_data_source_base*)pDataSource; - - MA_ASSERT(pDataSource != NULL); - MA_ASSERT(ppCurrentDataSource != NULL); - - if (pCurrentDataSource->pCurrent == NULL) { - /* - The current data source is NULL. If we're using this in the context of a chain we need to return NULL - here so that we don't end up looping. Otherwise we just return the data source itself. - */ - if (pCurrentDataSource->pNext != NULL || pCurrentDataSource->onGetNext != NULL) { - pCurrentDataSource = NULL; - } else { - pCurrentDataSource = (ma_data_source_base*)pDataSource; /* Not being used in a chain. Make sure we just always read from the data source itself at all times. */ - } - } else { - pCurrentDataSource = (ma_data_source_base*)pCurrentDataSource->pCurrent; - } - - *ppCurrentDataSource = pCurrentDataSource; - - return MA_SUCCESS; -} - -static ma_result ma_data_source_read_pcm_frames_from_backend(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - MA_ASSERT(pDataSourceBase != NULL); - MA_ASSERT(pDataSourceBase->vtable != NULL); - MA_ASSERT(pDataSourceBase->vtable->onRead != NULL); - MA_ASSERT(pFramesRead != NULL); - - if (pFramesOut != NULL) { - return pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, pFramesRead); - } else { - /* - No output buffer. Probably seeking forward. Read and discard. Can probably optimize this in terms of - onSeek and onGetCursor, but need to keep in mind that the data source may not implement these functions. - */ - ma_result result; - ma_uint64 framesRead; - ma_format format; - ma_uint32 channels; - ma_uint64 discardBufferCapInFrames; - ma_uint8 pDiscardBuffer[4096]; - - result = ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - discardBufferCapInFrames = sizeof(pDiscardBuffer) / ma_get_bytes_per_frame(format, channels); - - framesRead = 0; - while (framesRead < frameCount) { - ma_uint64 framesReadThisIteration = 0; - ma_uint64 framesToRead = frameCount - framesRead; - if (framesToRead > discardBufferCapInFrames) { - framesToRead = discardBufferCapInFrames; - } - - result = pDataSourceBase->vtable->onRead(pDataSourceBase, pDiscardBuffer, framesToRead, &framesReadThisIteration); - if (result != MA_SUCCESS) { - return result; - } - - framesRead += framesReadThisIteration; - } - - *pFramesRead = framesRead; - - return MA_SUCCESS; - } -} - -static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - ma_result result; - ma_uint64 framesRead = 0; - ma_bool32 loop = ma_data_source_is_looping(pDataSource); - - if (pDataSourceBase == NULL) { - return MA_AT_END; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - MA_ASSERT(pDataSourceBase->vtable != NULL); - - if ((pDataSourceBase->vtable->flags & MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) != 0 || (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE))) { - /* Either the data source is self-managing the range, or no range is set - just read like normal. The data source itself will tell us when the end is reached. */ - result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead); - } else { - /* Need to clamp to within the range. */ - ma_uint64 relativeCursor; - ma_uint64 absoluteCursor; - - result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &relativeCursor); - if (result != MA_SUCCESS) { - /* Failed to retrieve the cursor. Cannot read within a range or loop points. Just read like normal - this may happen for things like noise data sources where it doesn't really matter. */ - result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead); - } else { - ma_uint64 rangeBeg; - ma_uint64 rangeEnd; - - /* We have the cursor. We need to make sure we don't read beyond our range. */ - rangeBeg = pDataSourceBase->rangeBegInFrames; - rangeEnd = pDataSourceBase->rangeEndInFrames; - - absoluteCursor = rangeBeg + relativeCursor; - - /* If looping, make sure we're within range. */ - if (loop) { - if (pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) { - rangeEnd = ma_min(rangeEnd, pDataSourceBase->rangeBegInFrames + pDataSourceBase->loopEndInFrames); - } - } - - if (frameCount > (rangeEnd - absoluteCursor) && rangeEnd != ~((ma_uint64)0)) { - frameCount = (rangeEnd - absoluteCursor); - } - - /* - If the cursor is sitting on the end of the range the frame count will be set to 0 which can - result in MA_INVALID_ARGS. In this case, we don't want to try reading, but instead return - MA_AT_END so the higher level function can know about it. - */ - if (frameCount > 0) { - result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead); - } else { - result = MA_AT_END; /* The cursor is sitting on the end of the range which means we're at the end. */ - } - } - } - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - /* We need to make sure MA_AT_END is returned if we hit the end of the range. */ - if (result == MA_SUCCESS && framesRead == 0) { - result = MA_AT_END; - } - - return result; -} - -MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result = MA_SUCCESS; - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - ma_data_source_base* pCurrentDataSource; - void* pRunningFramesOut = pFramesOut; - ma_uint64 totalFramesProcessed = 0; - ma_format format; - ma_uint32 channels; - ma_uint32 emptyLoopCounter = 0; /* Keeps track of how many times 0 frames have been read. For infinite loop detection of sounds with no audio data. */ - ma_bool32 loop; + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; + /* Safety. */ if (pFramesRead != NULL) { *pFramesRead = 0; } - if (frameCount == 0) { + if (pCallbacks == NULL) { return MA_INVALID_ARGS; } - if (pDataSourceBase == NULL) { - return MA_INVALID_ARGS; + if (pCallbacks->onRead == NULL) { + return MA_NOT_IMPLEMENTED; } - loop = ma_data_source_is_looping(pDataSource); + /* A very small optimization for the non looping case. */ + if (loop == MA_FALSE) { + return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); + } else { + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + if (ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate) != MA_SUCCESS) { + return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); /* We don't have a way to retrieve the data format which means we don't know how to offset the output buffer. Just read as much as we can. */ + } else { + ma_result result = MA_SUCCESS; + ma_uint64 totalFramesProcessed; + void* pRunningFramesOut = pFramesOut; - /* - We need to know the data format so we can advance the output buffer as we read frames. If this - fails, chaining will not work and we'll just read as much as we can from the current source. - */ - if (ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0) != MA_SUCCESS) { - result = ma_data_source_resolve_current(pDataSource, (ma_data_source**)&pCurrentDataSource); - if (result != MA_SUCCESS) { - return result; - } + totalFramesProcessed = 0; + while (totalFramesProcessed < frameCount) { + ma_uint64 framesProcessed; + ma_uint64 framesRemaining = frameCount - totalFramesProcessed; - return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead); - } + result = pCallbacks->onRead(pDataSource, pRunningFramesOut, framesRemaining, &framesProcessed); + totalFramesProcessed += framesProcessed; - /* - Looping is a bit of a special case. When the `loop` argument is true, chaining will not work and - only the current data source will be read from. - */ - - /* Keep reading until we've read as many frames as possible. */ - while (totalFramesProcessed < frameCount) { - ma_uint64 framesProcessed; - ma_uint64 framesRemaining = frameCount - totalFramesProcessed; - - /* We need to resolve the data source that we'll actually be reading from. */ - result = ma_data_source_resolve_current(pDataSource, (ma_data_source**)&pCurrentDataSource); - if (result != MA_SUCCESS) { - break; - } - - if (pCurrentDataSource == NULL) { - break; - } - - result = ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pRunningFramesOut, framesRemaining, &framesProcessed); - totalFramesProcessed += framesProcessed; - - /* - If we encountered an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is - not necessarily considered an error. - */ - if (result != MA_SUCCESS && result != MA_AT_END) { - break; - } - - /* - We can determine if we've reached the end by checking if ma_data_source_read_pcm_frames_within_range() returned - MA_AT_END. To loop back to the start, all we need to do is seek back to the first frame. - */ - if (result == MA_AT_END) { - /* - The result needs to be reset back to MA_SUCCESS (from MA_AT_END) so that we don't - accidentally return MA_AT_END when data has been read in prior loop iterations. at the - end of this function, the result will be checked for MA_SUCCESS, and if the total - number of frames processed is 0, will be explicitly set to MA_AT_END. - */ - result = MA_SUCCESS; - - /* - We reached the end. If we're looping, we just loop back to the start of the current - data source. If we're not looping we need to check if we have another in the chain, and - if so, switch to it. - */ - if (loop) { - if (framesProcessed == 0) { - emptyLoopCounter += 1; - if (emptyLoopCounter > 1) { - break; /* Infinite loop detected. Get out. */ - } - } else { - emptyLoopCounter = 0; - } - - result = ma_data_source_seek_to_pcm_frame(pCurrentDataSource, pCurrentDataSource->loopBegInFrames); - if (result != MA_SUCCESS) { - break; /* Failed to loop. Abort. */ - } - - /* Don't return MA_AT_END for looping sounds. */ - result = MA_SUCCESS; - } else { - if (pCurrentDataSource->pNext != NULL) { - pDataSourceBase->pCurrent = pCurrentDataSource->pNext; - } else if (pCurrentDataSource->onGetNext != NULL) { - pDataSourceBase->pCurrent = pCurrentDataSource->onGetNext(pCurrentDataSource); - if (pDataSourceBase->pCurrent == NULL) { - break; /* Our callback did not return a next data source. We're done. */ - } - } else { - /* Reached the end of the chain. We're done. */ + /* + If we encounted an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is + not necessarily considered an error. + */ + if (result != MA_SUCCESS && result != MA_AT_END) { break; } - /* The next data source needs to be rewound to ensure data is read in looping scenarios. */ - result = ma_data_source_seek_to_pcm_frame(pDataSourceBase->pCurrent, 0); - if (result != MA_SUCCESS) { - break; + /* + We can determine if we've reached the end by checking the return value of the onRead() callback. If it's less than what we requested it means + we've reached the end. To loop back to the start, all we need to do is seek back to the first frame. + */ + if (framesProcessed < framesRemaining || result == MA_AT_END) { + if (ma_data_source_seek_to_pcm_frame(pDataSource, 0) != MA_SUCCESS) { + break; + } + } + + if (pRunningFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels)); } } - } - if (pRunningFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels)); + if (pFramesRead != NULL) { + *pFramesRead = totalFramesProcessed; + } + + return result; } } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesProcessed; - } - - MA_ASSERT(!(result == MA_AT_END && totalFramesProcessed > 0)); /* We should never be returning MA_AT_END if we read some data. */ - - if (result == MA_SUCCESS && totalFramesProcessed == 0) { - result = MA_AT_END; - } - - return result; } -MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked) +MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop) { - return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked); + return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked, loop); } MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSourceBase == NULL) { + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; + if (pCallbacks == NULL || pCallbacks->onSeek == NULL) { return MA_INVALID_ARGS; } - if (pDataSourceBase->vtable->onSeek == NULL) { - return MA_NOT_IMPLEMENTED; - } - - if (frameIndex > pDataSourceBase->rangeEndInFrames) { - return MA_INVALID_OPERATION; /* Trying to seek too far forward. */ - } - - MA_ASSERT(pDataSourceBase->vtable != NULL); - - return pDataSourceBase->vtable->onSeek(pDataSource, pDataSourceBase->rangeBegInFrames + frameIndex); + return pCallbacks->onSeek(pDataSource, frameIndex); } -MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked) +MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount) { - ma_uint64 frameCount; - ma_uint64 framesSeeked = 0; - ma_uint32 sampleRate; - ma_result result; - - if (pDataSource == NULL) { + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; + if (pCallbacks == NULL || pCallbacks->onMap == NULL) { return MA_INVALID_ARGS; } - result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - /* We need PCM frames instead of seconds */ - frameCount = (ma_uint64)(secondCount * sampleRate); - - result = ma_data_source_seek_pcm_frames(pDataSource, frameCount, &framesSeeked); - - /* VC6 doesn't support division between unsigned 64-bit integer and floating point number. Signed integer needed. This shouldn't affect anything in practice */ - *pSecondsSeeked = (ma_int64)framesSeeked / (float)sampleRate; - return result; + return pCallbacks->onMap(pDataSource, ppFramesOut, pFrameCount); } -MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds) +MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount) { - ma_uint64 frameIndex; - ma_uint32 sampleRate; - ma_result result; - - if (pDataSource == NULL) { + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; + if (pCallbacks == NULL || pCallbacks->onUnmap == NULL) { return MA_INVALID_ARGS; } - result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - /* We need PCM frames instead of seconds */ - frameIndex = (ma_uint64)(seekPointInSeconds * sampleRate); - - return ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex); + return pCallbacks->onUnmap(pDataSource, frameCount); } -MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_result result; ma_format format; ma_uint32 channels; ma_uint32 sampleRate; + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; - /* Initialize to defaults for safety just in case the data source does not implement this callback. */ if (pFormat != NULL) { *pFormat = ma_format_unknown; } + if (pChannels != NULL) { *pChannels = 0; } + if (pSampleRate != NULL) { *pSampleRate = 0; } - if (pChannelMap != NULL) { - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); - } - if (pDataSourceBase == NULL) { + if (pCallbacks == NULL || pCallbacks->onGetDataFormat == NULL) { return MA_INVALID_ARGS; } - MA_ASSERT(pDataSourceBase->vtable != NULL); - - if (pDataSourceBase->vtable->onGetDataFormat == NULL) { - return MA_NOT_IMPLEMENTED; - } - - result = pDataSourceBase->vtable->onGetDataFormat(pDataSource, &format, &channels, &sampleRate, pChannelMap, channelMapCap); + result = pCallbacks->onGetDataFormat(pDataSource, &format, &channels, &sampleRate); if (result != MA_SUCCESS) { return result; } @@ -58042,16 +43022,12 @@ MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_ *pSampleRate = sampleRate; } - /* Channel map was passed in directly to the callback. This is safe due to the channelMapCap parameter. */ - return MA_SUCCESS; } MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - ma_result result; - ma_uint64 cursor; + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; if (pCursor == NULL) { return MA_INVALID_ARGS; @@ -58059,34 +43035,20 @@ MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSo *pCursor = 0; - if (pDataSourceBase == NULL) { - return MA_SUCCESS; + if (pCallbacks == NULL) { + return MA_INVALID_ARGS; } - MA_ASSERT(pDataSourceBase->vtable != NULL); - - if (pDataSourceBase->vtable->onGetCursor == NULL) { + if (pCallbacks->onGetCursor == NULL) { return MA_NOT_IMPLEMENTED; } - result = pDataSourceBase->vtable->onGetCursor(pDataSourceBase, &cursor); - if (result != MA_SUCCESS) { - return result; - } - - /* The cursor needs to be made relative to the start of the range. */ - if (cursor < pDataSourceBase->rangeBegInFrames) { /* Safety check so we don't return some huge number. */ - *pCursor = 0; - } else { - *pCursor = cursor - pDataSourceBase->rangeBegInFrames; - } - - return MA_SUCCESS; + return pCallbacks->onGetCursor(pDataSource, pCursor); } MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; if (pLength == NULL) { return MA_INVALID_ARGS; @@ -58094,345 +43056,29 @@ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSo *pLength = 0; - if (pDataSourceBase == NULL) { + if (pCallbacks == NULL) { return MA_INVALID_ARGS; } - MA_ASSERT(pDataSourceBase->vtable != NULL); - - /* - If we have a range defined we'll use that to determine the length. This is one of rare times - where we'll actually trust the caller. If they've set the range, I think it's mostly safe to - assume they've set it based on some higher level knowledge of the structure of the sound bank. - */ - if (pDataSourceBase->rangeEndInFrames != ~((ma_uint64)0)) { - *pLength = pDataSourceBase->rangeEndInFrames - pDataSourceBase->rangeBegInFrames; - return MA_SUCCESS; - } - - /* - Getting here means a range is not defined so we'll need to get the data source itself to tell - us the length. - */ - if (pDataSourceBase->vtable->onGetLength == NULL) { + if (pCallbacks->onGetLength == NULL) { return MA_NOT_IMPLEMENTED; } - return pDataSourceBase->vtable->onGetLength(pDataSource, pLength); + return pCallbacks->onGetLength(pDataSource, pLength); } -MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor) -{ - ma_result result; - ma_uint64 cursorInPCMFrames; - ma_uint32 sampleRate; - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; - - result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursorInPCMFrames); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - /* VC6 does not support division of unsigned 64-bit integers with floating point numbers. Need to use a signed number. This shouldn't effect anything in practice. */ - *pCursor = (ma_int64)cursorInPCMFrames / (float)sampleRate; - - return MA_SUCCESS; -} - -MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength) -{ - ma_result result; - ma_uint64 lengthInPCMFrames; - ma_uint32 sampleRate; - - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; - - result = ma_data_source_get_length_in_pcm_frames(pDataSource, &lengthInPCMFrames); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - /* VC6 does not support division of unsigned 64-bit integers with floating point numbers. Need to use a signed number. This shouldn't effect anything in practice. */ - *pLength = (ma_int64)lengthInPCMFrames / (float)sampleRate; - - return MA_SUCCESS; -} - -MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - ma_atomic_exchange_32(&pDataSourceBase->isLooping, isLooping); - - MA_ASSERT(pDataSourceBase->vtable != NULL); - - /* If there's no callback for this just treat it as a successful no-op. */ - if (pDataSourceBase->vtable->onSetLooping == NULL) { - return MA_SUCCESS; - } - - return pDataSourceBase->vtable->onSetLooping(pDataSource, isLooping); -} - -MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source* pDataSource) -{ - const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_FALSE; - } - - return ma_atomic_load_32(&pDataSourceBase->isLooping); -} - -MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - ma_result result; - ma_uint64 relativeCursor; - ma_uint64 absoluteCursor; - ma_bool32 doSeekAdjustment = MA_FALSE; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if (rangeEndInFrames < rangeBegInFrames) { - return MA_INVALID_ARGS; /* The end of the range must come after the beginning. */ - } - - /* - We may need to adjust the position of the cursor to ensure it's clamped to the range. Grab it now - so we can calculate its absolute position before we change the range. - */ - result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &relativeCursor); - if (result == MA_SUCCESS) { - doSeekAdjustment = MA_TRUE; - absoluteCursor = relativeCursor + pDataSourceBase->rangeBegInFrames; - } else { - /* - We couldn't get the position of the cursor. It probably means the data source has no notion - of a cursor. We'll just leave it at position 0. Don't treat this as an error. - */ - doSeekAdjustment = MA_FALSE; - relativeCursor = 0; - absoluteCursor = 0; - } - - pDataSourceBase->rangeBegInFrames = rangeBegInFrames; - pDataSourceBase->rangeEndInFrames = rangeEndInFrames; - - /* - The commented out logic below was intended to maintain loop points in response to a change in the - range. However, this is not useful because it results in the sound breaking when you move the range - outside of the old loop points. I'm simplifying this by simply resetting the loop points. The - caller is expected to update their loop points if they change the range. - - In practice this should be mostly a non-issue because the majority of the time the range will be - set once right after initialization. - */ - pDataSourceBase->loopBegInFrames = 0; - pDataSourceBase->loopEndInFrames = ~((ma_uint64)0); - - - /* - Seek to within range. Note that our seek positions here are relative to the new range. We don't want - to do this if we failed to retrieve the cursor earlier on because it probably means the data source - has no notion of a cursor. In practice the seek would probably fail (which we silently ignore), but - I'm just not even going to attempt it. - */ - if (doSeekAdjustment) { - if (absoluteCursor < rangeBegInFrames) { - ma_data_source_seek_to_pcm_frame(pDataSource, 0); - } else if (absoluteCursor > rangeEndInFrames) { - ma_data_source_seek_to_pcm_frame(pDataSource, rangeEndInFrames - rangeBegInFrames); - } - } - - return MA_SUCCESS; -} - -MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames) -{ - const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; - - if (pRangeBegInFrames != NULL) { - *pRangeBegInFrames = 0; - } - if (pRangeEndInFrames != NULL) { - *pRangeEndInFrames = 0; - } - - if (pDataSource == NULL) { - return; - } - - if (pRangeBegInFrames != NULL) { - *pRangeBegInFrames = pDataSourceBase->rangeBegInFrames; - } - - if (pRangeEndInFrames != NULL) { - *pRangeEndInFrames = pDataSourceBase->rangeEndInFrames; - } -} - -MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if (loopEndInFrames < loopBegInFrames) { - return MA_INVALID_ARGS; /* The end of the loop point must come after the beginning. */ - } - - if (loopEndInFrames > pDataSourceBase->rangeEndInFrames && loopEndInFrames != ~((ma_uint64)0)) { - return MA_INVALID_ARGS; /* The end of the loop point must not go beyond the range. */ - } - - pDataSourceBase->loopBegInFrames = loopBegInFrames; - pDataSourceBase->loopEndInFrames = loopEndInFrames; - - /* The end cannot exceed the range. */ - if (pDataSourceBase->loopEndInFrames > (pDataSourceBase->rangeEndInFrames - pDataSourceBase->rangeBegInFrames) && pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) { - pDataSourceBase->loopEndInFrames = (pDataSourceBase->rangeEndInFrames - pDataSourceBase->rangeBegInFrames); - } - - return MA_SUCCESS; -} - -MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames) -{ - const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; - - if (pLoopBegInFrames != NULL) { - *pLoopBegInFrames = 0; - } - if (pLoopEndInFrames != NULL) { - *pLoopEndInFrames = 0; - } - - if (pDataSource == NULL) { - return; - } - - if (pLoopBegInFrames != NULL) { - *pLoopBegInFrames = pDataSourceBase->loopBegInFrames; - } - - if (pLoopEndInFrames != NULL) { - *pLoopEndInFrames = pDataSourceBase->loopEndInFrames; - } -} - -MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - pDataSourceBase->pCurrent = pCurrentDataSource; - - return MA_SUCCESS; -} - -MA_API ma_data_source* ma_data_source_get_current(const ma_data_source* pDataSource) -{ - const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return NULL; - } - - return pDataSourceBase->pCurrent; -} - -MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - pDataSourceBase->pNext = pNextDataSource; - - return MA_SUCCESS; -} - -MA_API ma_data_source* ma_data_source_get_next(const ma_data_source* pDataSource) -{ - const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return NULL; - } - - return pDataSourceBase->pNext; -} - -MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext) -{ - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - pDataSourceBase->onGetNext = onGetNext; - - return MA_SUCCESS; -} - -MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source* pDataSource) -{ - const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; - - if (pDataSource == NULL) { - return NULL; - } - - return pDataSourceBase->onGetNext; -} static ma_result ma_audio_buffer_ref__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource; - ma_uint64 framesRead = ma_audio_buffer_ref_read_pcm_frames(pAudioBufferRef, pFramesOut, frameCount, MA_FALSE); + ma_uint64 framesRead = ma_audio_buffer_ref_read_pcm_frames((ma_audio_buffer_ref*)pDataSource, pFramesOut, frameCount, MA_FALSE); if (pFramesRead != NULL) { *pFramesRead = framesRead; } - if (framesRead < frameCount || framesRead == 0) { + if (framesRead < frameCount) { return MA_AT_END; } @@ -58444,14 +43090,23 @@ static ma_result ma_audio_buffer_ref__data_source_on_seek(ma_data_source* pDataS return ma_audio_buffer_ref_seek_to_pcm_frame((ma_audio_buffer_ref*)pDataSource, frameIndex); } -static ma_result ma_audio_buffer_ref__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_result ma_audio_buffer_ref__data_source_on_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount) +{ + return ma_audio_buffer_ref_map((ma_audio_buffer_ref*)pDataSource, ppFramesOut, pFrameCount); +} + +static ma_result ma_audio_buffer_ref__data_source_on_unmap(ma_data_source* pDataSource, ma_uint64 frameCount) +{ + return ma_audio_buffer_ref_unmap((ma_audio_buffer_ref*)pDataSource, frameCount); +} + +static ma_result ma_audio_buffer_ref__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) { ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource; *pFormat = pAudioBufferRef->format; *pChannels = pAudioBufferRef->channels; - *pSampleRate = pAudioBufferRef->sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pAudioBufferRef->channels); + *pSampleRate = 0; /* There is no notion of a sample rate with audio buffers. */ return MA_SUCCESS; } @@ -58474,55 +43129,30 @@ static ma_result ma_audio_buffer_ref__data_source_on_get_length(ma_data_source* return MA_SUCCESS; } -static ma_data_source_vtable g_ma_audio_buffer_ref_data_source_vtable = -{ - ma_audio_buffer_ref__data_source_on_read, - ma_audio_buffer_ref__data_source_on_seek, - ma_audio_buffer_ref__data_source_on_get_data_format, - ma_audio_buffer_ref__data_source_on_get_cursor, - ma_audio_buffer_ref__data_source_on_get_length, - NULL, /* onSetLooping */ - 0 -}; - MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef) { - ma_result result; - ma_data_source_config dataSourceConfig; - if (pAudioBufferRef == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pAudioBufferRef); - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_audio_buffer_ref_data_source_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pAudioBufferRef->ds); - if (result != MA_SUCCESS) { - return result; - } - - pAudioBufferRef->format = format; - pAudioBufferRef->channels = channels; - pAudioBufferRef->sampleRate = 0; /* TODO: Version 0.12. Set this to sampleRate. */ - pAudioBufferRef->cursor = 0; - pAudioBufferRef->sizeInFrames = sizeInFrames; - pAudioBufferRef->pData = pData; + pAudioBufferRef->ds.onRead = ma_audio_buffer_ref__data_source_on_read; + pAudioBufferRef->ds.onSeek = ma_audio_buffer_ref__data_source_on_seek; + pAudioBufferRef->ds.onMap = ma_audio_buffer_ref__data_source_on_map; + pAudioBufferRef->ds.onUnmap = ma_audio_buffer_ref__data_source_on_unmap; + pAudioBufferRef->ds.onGetDataFormat = ma_audio_buffer_ref__data_source_on_get_data_format; + pAudioBufferRef->ds.onGetCursor = ma_audio_buffer_ref__data_source_on_get_cursor; + pAudioBufferRef->ds.onGetLength = ma_audio_buffer_ref__data_source_on_get_length; + pAudioBufferRef->format = format; + pAudioBufferRef->channels = channels; + pAudioBufferRef->cursor = 0; + pAudioBufferRef->sizeInFrames = sizeInFrames; + pAudioBufferRef->pData = pData; return MA_SUCCESS; } -MA_API void ma_audio_buffer_ref_uninit(ma_audio_buffer_ref* pAudioBufferRef) -{ - if (pAudioBufferRef == NULL) { - return; - } - - ma_data_source_uninit(&pAudioBufferRef->ds); -} - MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames) { if (pAudioBufferRef == NULL) { @@ -58559,7 +43189,7 @@ MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudio } if (pFramesOut != NULL) { - ma_copy_pcm_frames(ma_offset_ptr(pFramesOut, totalFramesRead * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), framesToRead, pAudioBufferRef->format, pAudioBufferRef->channels); + ma_copy_pcm_frames(pFramesOut, ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), framesToRead, pAudioBufferRef->format, pAudioBufferRef->channels); } totalFramesRead += framesToRead; @@ -58645,7 +43275,7 @@ MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, } } -MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef) +MA_API ma_result ma_audio_buffer_ref_at_end(ma_audio_buffer_ref* pAudioBufferRef) { if (pAudioBufferRef == NULL) { return MA_FALSE; @@ -58654,41 +43284,7 @@ MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBuf return pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames; } -MA_API ma_result ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; - - if (pAudioBufferRef == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = pAudioBufferRef->cursor; - - return MA_SUCCESS; -} - -MA_API ma_result ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; - - if (pAudioBufferRef == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = pAudioBufferRef->sizeInFrames; - - return MA_SUCCESS; -} - -MA_API ma_result ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames) +MA_API ma_result ma_audio_buffer_ref_get_available_frames(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames) { if (pAvailableFrames == NULL) { return MA_INVALID_ARGS; @@ -58717,11 +43313,10 @@ MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_u ma_audio_buffer_config config; MA_ZERO_OBJECT(&config); - config.format = format; - config.channels = channels; - config.sampleRate = 0; /* TODO: Version 0.12. Set this to sampleRate. */ + config.format = format; + config.channels = channels; config.sizeInFrames = sizeInFrames; - config.pData = pData; + config.pData = pData; ma_allocation_callbacks_init_copy(&config.allocationCallbacks, pAllocationCallbacks); return config; @@ -58749,10 +43344,7 @@ static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, if (result != MA_SUCCESS) { return result; } - - /* TODO: Version 0.12. Set this in ma_audio_buffer_ref_init() instead of here. */ - pAudioBuffer->ref.sampleRate = pConfig->sampleRate; - + ma_allocation_callbacks_init_copy(&pAudioBuffer->allocationCallbacks, &pConfig->allocationCallbacks); if (doCopy) { @@ -58764,7 +43356,7 @@ static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, return MA_OUT_OF_MEMORY; /* Too big. */ } - pData = ma_malloc((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks); /* Safe cast to size_t. */ + pData = ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks); /* Safe cast to size_t. */ if (pData == NULL) { return MA_OUT_OF_MEMORY; } @@ -58792,14 +43384,12 @@ static void ma_audio_buffer_uninit_ex(ma_audio_buffer* pAudioBuffer, ma_bool32 d } if (pAudioBuffer->ownsData && pAudioBuffer->ref.pData != &pAudioBuffer->_pExtraData[0]) { - ma_free((void*)pAudioBuffer->ref.pData, &pAudioBuffer->allocationCallbacks); /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */ + ma__free_from_callbacks((void*)pAudioBuffer->ref.pData, &pAudioBuffer->allocationCallbacks); /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */ } if (doFree) { - ma_free(pAudioBuffer, &pAudioBuffer->allocationCallbacks); + ma__free_from_callbacks(pAudioBuffer, &pAudioBuffer->allocationCallbacks); } - - ma_audio_buffer_ref_uninit(&pAudioBuffer->ref); } MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer) @@ -58837,7 +43427,7 @@ MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pC return MA_OUT_OF_MEMORY; /* Too big. */ } - pAudioBuffer = (ma_audio_buffer*)ma_malloc((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks); /* Safe cast to size_t. */ + pAudioBuffer = (ma_audio_buffer*)ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks); /* Safe cast to size_t. */ if (pAudioBuffer == NULL) { return MA_OUT_OF_MEMORY; } @@ -58852,7 +43442,7 @@ MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pC result = ma_audio_buffer_init_ex(&innerConfig, MA_FALSE, pAudioBuffer); if (result != MA_SUCCESS) { - ma_free(pAudioBuffer, &innerConfig.allocationCallbacks); + ma__free_from_callbacks(pAudioBuffer, &innerConfig.allocationCallbacks); return result; } @@ -58915,7 +43505,7 @@ MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 return ma_audio_buffer_ref_unmap(&pAudioBuffer->ref, frameCount); } -MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer) +MA_API ma_result ma_audio_buffer_at_end(ma_audio_buffer* pAudioBuffer) { if (pAudioBuffer == NULL) { return MA_FALSE; @@ -58924,25 +43514,7 @@ MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer) return ma_audio_buffer_ref_at_end(&pAudioBuffer->ref); } -MA_API ma_result ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pCursor) -{ - if (pAudioBuffer == NULL) { - return MA_INVALID_ARGS; - } - - return ma_audio_buffer_ref_get_cursor_in_pcm_frames(&pAudioBuffer->ref, pCursor); -} - -MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pLength) -{ - if (pAudioBuffer == NULL) { - return MA_INVALID_ARGS; - } - - return ma_audio_buffer_ref_get_length_in_pcm_frames(&pAudioBuffer->ref, pLength); -} - -MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames) +MA_API ma_result ma_audio_buffer_get_available_frames(ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames) { if (pAvailableFrames == NULL) { return MA_INVALID_ARGS; @@ -58959,392 +43531,6 @@ MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAu - - -MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData) -{ - if (pData == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pData); - - pData->format = format; - pData->channels = channels; - pData->pTail = &pData->head; - - return MA_SUCCESS; -} - -MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_paged_audio_buffer_page* pPage; - - if (pData == NULL) { - return; - } - - /* All pages need to be freed. */ - pPage = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pData->head.pNext); - while (pPage != NULL) { - ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPage->pNext); - - ma_free(pPage, pAllocationCallbacks); - pPage = pNext; - } -} - -MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData) -{ - if (pData == NULL) { - return NULL; - } - - return &pData->head; -} - -MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData) -{ - if (pData == NULL) { - return NULL; - } - - return pData->pTail; -} - -MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength) -{ - ma_paged_audio_buffer_page* pPage; - - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; - - if (pData == NULL) { - return MA_INVALID_ARGS; - } - - /* Calculate the length from the linked list. */ - for (pPage = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pData->head.pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPage->pNext)) { - *pLength += pPage->sizeInFrames; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage) -{ - ma_paged_audio_buffer_page* pPage; - ma_uint64 allocationSize; - - if (ppPage == NULL) { - return MA_INVALID_ARGS; - } - - *ppPage = NULL; - - if (pData == NULL) { - return MA_INVALID_ARGS; - } - - allocationSize = sizeof(*pPage) + (pageSizeInFrames * ma_get_bytes_per_frame(pData->format, pData->channels)); - if (allocationSize > MA_SIZE_MAX) { - return MA_OUT_OF_MEMORY; /* Too big. */ - } - - pPage = (ma_paged_audio_buffer_page*)ma_malloc((size_t)allocationSize, pAllocationCallbacks); /* Safe cast to size_t. */ - if (pPage == NULL) { - return MA_OUT_OF_MEMORY; - } - - pPage->pNext = NULL; - pPage->sizeInFrames = pageSizeInFrames; - - if (pInitialData != NULL) { - ma_copy_pcm_frames(pPage->pAudioData, pInitialData, pageSizeInFrames, pData->format, pData->channels); - } - - *ppPage = pPage; - - return MA_SUCCESS; -} - -MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pData == NULL || pPage == NULL) { - return MA_INVALID_ARGS; - } - - /* It's assumed the page is not attached to the list. */ - ma_free(pPage, pAllocationCallbacks); - - return MA_SUCCESS; -} - -MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage) -{ - if (pData == NULL || pPage == NULL) { - return MA_INVALID_ARGS; - } - - /* This function assumes the page has been filled with audio data by this point. As soon as we append, the page will be available for reading. */ - - /* First thing to do is update the tail. */ - for (;;) { - ma_paged_audio_buffer_page* pOldTail = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pData->pTail); - ma_paged_audio_buffer_page* pNewTail = pPage; - - if (ma_atomic_compare_exchange_weak_ptr((volatile void**)&pData->pTail, (void**)&pOldTail, pNewTail)) { - /* Here is where we append the page to the list. After this, the page is attached to the list and ready to be read from. */ - ma_atomic_exchange_ptr(&pOldTail->pNext, pPage); - break; /* Done. */ - } - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_result result; - ma_paged_audio_buffer_page* pPage; - - result = ma_paged_audio_buffer_data_allocate_page(pData, pageSizeInFrames, pInitialData, pAllocationCallbacks, &pPage); - if (result != MA_SUCCESS) { - return result; - } - - return ma_paged_audio_buffer_data_append_page(pData, pPage); /* <-- Should never fail. */ -} - - -MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData) -{ - ma_paged_audio_buffer_config config; - - MA_ZERO_OBJECT(&config); - config.pData = pData; - - return config; -} - - -static ma_result ma_paged_audio_buffer__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_paged_audio_buffer_read_pcm_frames((ma_paged_audio_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead); -} - -static ma_result ma_paged_audio_buffer__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) -{ - return ma_paged_audio_buffer_seek_to_pcm_frame((ma_paged_audio_buffer*)pDataSource, frameIndex); -} - -static ma_result ma_paged_audio_buffer__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_paged_audio_buffer* pPagedAudioBuffer = (ma_paged_audio_buffer*)pDataSource; - - *pFormat = pPagedAudioBuffer->pData->format; - *pChannels = pPagedAudioBuffer->pData->channels; - *pSampleRate = 0; /* There is no notion of a sample rate with audio buffers. */ - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pPagedAudioBuffer->pData->channels); - - return MA_SUCCESS; -} - -static ma_result ma_paged_audio_buffer__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_paged_audio_buffer_get_cursor_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pCursor); -} - -static ma_result ma_paged_audio_buffer__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_paged_audio_buffer_get_length_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pLength); -} - -static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable = -{ - ma_paged_audio_buffer__data_source_on_read, - ma_paged_audio_buffer__data_source_on_seek, - ma_paged_audio_buffer__data_source_on_get_data_format, - ma_paged_audio_buffer__data_source_on_get_cursor, - ma_paged_audio_buffer__data_source_on_get_length, - NULL, /* onSetLooping */ - 0 -}; - -MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer) -{ - ma_result result; - ma_data_source_config dataSourceConfig; - - if (pPagedAudioBuffer == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pPagedAudioBuffer); - - /* A config is required for the format and channel count. */ - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->pData == NULL) { - return MA_INVALID_ARGS; /* No underlying data specified. */ - } - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_paged_audio_buffer_data_source_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pPagedAudioBuffer->ds); - if (result != MA_SUCCESS) { - return result; - } - - pPagedAudioBuffer->pData = pConfig->pData; - pPagedAudioBuffer->pCurrent = ma_paged_audio_buffer_data_get_head(pConfig->pData); - pPagedAudioBuffer->relativeCursor = 0; - pPagedAudioBuffer->absoluteCursor = 0; - - return MA_SUCCESS; -} - -MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer) -{ - if (pPagedAudioBuffer == NULL) { - return; - } - - /* Nothing to do. The data needs to be deleted separately. */ -} - -MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result = MA_SUCCESS; - ma_uint64 totalFramesRead = 0; - ma_format format; - ma_uint32 channels; - - if (pPagedAudioBuffer == NULL) { - return MA_INVALID_ARGS; - } - - format = pPagedAudioBuffer->pData->format; - channels = pPagedAudioBuffer->pData->channels; - - while (totalFramesRead < frameCount) { - /* Read from the current page. The buffer should never be in a state where this is NULL. */ - ma_uint64 framesRemainingInCurrentPage; - ma_uint64 framesRemainingToRead = frameCount - totalFramesRead; - ma_uint64 framesToReadThisIteration; - - MA_ASSERT(pPagedAudioBuffer->pCurrent != NULL); - - framesRemainingInCurrentPage = pPagedAudioBuffer->pCurrent->sizeInFrames - pPagedAudioBuffer->relativeCursor; - - framesToReadThisIteration = ma_min(framesRemainingInCurrentPage, framesRemainingToRead); - ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), ma_offset_pcm_frames_ptr(pPagedAudioBuffer->pCurrent->pAudioData, pPagedAudioBuffer->relativeCursor, format, channels), framesToReadThisIteration, format, channels); - totalFramesRead += framesToReadThisIteration; - - pPagedAudioBuffer->absoluteCursor += framesToReadThisIteration; - pPagedAudioBuffer->relativeCursor += framesToReadThisIteration; - - /* Move to the next page if necessary. If there's no more pages, we need to return MA_AT_END. */ - MA_ASSERT(pPagedAudioBuffer->relativeCursor <= pPagedAudioBuffer->pCurrent->sizeInFrames); - - if (pPagedAudioBuffer->relativeCursor == pPagedAudioBuffer->pCurrent->sizeInFrames) { - /* We reached the end of the page. Need to move to the next. If there's no more pages, we're done. */ - ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPagedAudioBuffer->pCurrent->pNext); - if (pNext == NULL) { - result = MA_AT_END; - break; /* We've reached the end. */ - } else { - pPagedAudioBuffer->pCurrent = pNext; - pPagedAudioBuffer->relativeCursor = 0; - } - } - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - return result; -} - -MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex) -{ - if (pPagedAudioBuffer == NULL) { - return MA_INVALID_ARGS; - } - - if (frameIndex == pPagedAudioBuffer->absoluteCursor) { - return MA_SUCCESS; /* Nothing to do. */ - } - - if (frameIndex < pPagedAudioBuffer->absoluteCursor) { - /* Moving backwards. Need to move the cursor back to the start, and then move forward. */ - pPagedAudioBuffer->pCurrent = ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData); - pPagedAudioBuffer->absoluteCursor = 0; - pPagedAudioBuffer->relativeCursor = 0; - - /* Fall through to the forward seeking section below. */ - } - - if (frameIndex > pPagedAudioBuffer->absoluteCursor) { - /* Moving forward. */ - ma_paged_audio_buffer_page* pPage; - ma_uint64 runningCursor = 0; - - for (pPage = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData)->pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPage->pNext)) { - ma_uint64 pageRangeBeg = runningCursor; - ma_uint64 pageRangeEnd = pageRangeBeg + pPage->sizeInFrames; - - if (frameIndex >= pageRangeBeg) { - if (frameIndex < pageRangeEnd || (frameIndex == pageRangeEnd && pPage == (ma_paged_audio_buffer_page*)ma_atomic_load_ptr(ma_paged_audio_buffer_data_get_tail(pPagedAudioBuffer->pData)))) { /* A small edge case - allow seeking to the very end of the buffer. */ - /* We found the page. */ - pPagedAudioBuffer->pCurrent = pPage; - pPagedAudioBuffer->absoluteCursor = frameIndex; - pPagedAudioBuffer->relativeCursor = frameIndex - pageRangeBeg; - return MA_SUCCESS; - } - } - - runningCursor = pageRangeEnd; - } - - /* Getting here means we tried seeking too far forward. Don't change any state. */ - return MA_BAD_SEEK; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pPagedAudioBuffer == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = pPagedAudioBuffer->absoluteCursor; - - return MA_SUCCESS; -} - -MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength) -{ - return ma_paged_audio_buffer_data_get_length_in_pcm_frames(pPagedAudioBuffer->pData, pLength); -} - - - /************************************************************************************************************************************************************** VFS @@ -59410,8 +43596,6 @@ MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file) MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) { ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; - ma_result result; - size_t bytesRead = 0; if (pBytesRead != NULL) { *pBytesRead = 0; @@ -59425,17 +43609,7 @@ MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t return MA_NOT_IMPLEMENTED; } - result = pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, &bytesRead); - - if (pBytesRead != NULL) { - *pBytesRead = bytesRead; - } - - if (result == MA_SUCCESS && bytesRead == 0 && sizeInBytes > 0) { - result = MA_AT_END; - } - - return result; + return pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, pBytesRead); } MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) @@ -59515,36 +43689,83 @@ MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo } -#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) - #define MA_USE_WIN32_FILEIO -#endif - -#if defined(MA_USE_WIN32_FILEIO) -/* -We need to dynamically load SetFilePointer or SetFilePointerEx because older versions of Windows do -not have the Ex version. We therefore need to do some dynamic branching depending on what's available. - -We load these when we load our first file from the default VFS. It's left open for the life of the -program and is left to the OS to uninitialize when the program terminates. -*/ -typedef DWORD (__stdcall * ma_SetFilePointer_proc)(HANDLE hFile, LONG lDistanceToMove, LONG* lpDistanceToMoveHigh, DWORD dwMoveMethod); -typedef BOOL (__stdcall * ma_SetFilePointerEx_proc)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, LARGE_INTEGER* lpNewFilePointer, DWORD dwMoveMethod); - -static ma_handle hKernel32DLL = NULL; -static ma_SetFilePointer_proc ma_SetFilePointer = NULL; -static ma_SetFilePointerEx_proc ma_SetFilePointerEx = NULL; - -static void ma_win32_fileio_init(void) +static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePath, const wchar_t* pFilePathW, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks, ma_uint32 allocationType) { - if (hKernel32DLL == NULL) { - hKernel32DLL = ma_dlopen(NULL, "kernel32.dll"); - if (hKernel32DLL != NULL) { - ma_SetFilePointer = (ma_SetFilePointer_proc) ma_dlsym(NULL, hKernel32DLL, "SetFilePointer"); - ma_SetFilePointerEx = (ma_SetFilePointerEx_proc)ma_dlsym(NULL, hKernel32DLL, "SetFilePointerEx"); - } + ma_result result; + ma_vfs_file file; + ma_file_info info; + void* pData; + size_t bytesRead; + + (void)allocationType; + + if (ppData != NULL) { + *ppData = NULL; } + if (pSize != NULL) { + *pSize = 0; + } + + if (ppData == NULL) { + return MA_INVALID_ARGS; + } + + if (pFilePath != NULL) { + result = ma_vfs_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file); + } else { + result = ma_vfs_open_w(pVFS, pFilePathW, MA_OPEN_MODE_READ, &file); + } + if (result != MA_SUCCESS) { + return result; + } + + result = ma_vfs_info(pVFS, file, &info); + if (result != MA_SUCCESS) { + ma_vfs_close(pVFS, file); + return result; + } + + if (info.sizeInBytes > MA_SIZE_MAX) { + ma_vfs_close(pVFS, file); + return MA_TOO_BIG; + } + + pData = ma__malloc_from_callbacks((size_t)info.sizeInBytes, pAllocationCallbacks); /* Safe cast. */ + if (pData == NULL) { + ma_vfs_close(pVFS, file); + return result; + } + + result = ma_vfs_read(pVFS, file, pData, (size_t)info.sizeInBytes, &bytesRead); /* Safe cast. */ + ma_vfs_close(pVFS, file); + + if (result != MA_SUCCESS) { + ma__free_from_callbacks(pData, pAllocationCallbacks); + return result; + } + + if (pSize != NULL) { + *pSize = bytesRead; + } + + MA_ASSERT(ppData != NULL); + *ppData = pData; + + return MA_SUCCESS; } +MA_API ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, NULL, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/); +} + +MA_API ma_result ma_vfs_open_and_read_file_w(ma_vfs* pVFS, const wchar_t* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_vfs_open_and_read_file_ex(pVFS, NULL, pFilePath, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/); +} + + +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) static void ma_default_vfs__get_open_settings_win32(ma_uint32 openMode, DWORD* pDesiredAccess, DWORD* pShareMode, DWORD* pCreationDisposition) { *pDesiredAccess = 0; @@ -59576,9 +43797,6 @@ static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, (void)pVFS; - /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ - ma_win32_fileio_init(); - ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); hFile = CreateFileA(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); @@ -59599,9 +43817,6 @@ static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFile (void)pVFS; - /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ - ma_win32_fileio_init(); - ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); @@ -59648,7 +43863,6 @@ static ma_result ma_default_vfs_read__win32(ma_vfs* pVFS, ma_vfs_file file, void readResult = ReadFile((HANDLE)file, ma_offset_ptr(pDst, totalBytesRead), bytesToRead, &bytesRead, NULL); if (readResult == 1 && bytesRead == 0) { - result = MA_AT_END; break; /* EOF */ } @@ -59727,19 +43941,16 @@ static ma_result ma_default_vfs_seek__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i dwMoveMethod = FILE_BEGIN; } - if (ma_SetFilePointerEx != NULL) { - result = ma_SetFilePointerEx((HANDLE)file, liDistanceToMove, NULL, dwMoveMethod); - } else if (ma_SetFilePointer != NULL) { - /* No SetFilePointerEx() so restrict to 31 bits. */ - if (offset > 0x7FFFFFFF) { - return MA_OUT_OF_RANGE; - } - - result = ma_SetFilePointer((HANDLE)file, (LONG)liDistanceToMove.QuadPart, NULL, dwMoveMethod); - } else { - return MA_NOT_IMPLEMENTED; +#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__) + /* No SetFilePointerEx() so restrict to 31 bits. */ + if (origin > 0x7FFFFFFF) { + return MA_OUT_OF_RANGE; } + result = SetFilePointer((HANDLE)file, (LONG)liDistanceToMove.QuadPart, NULL, dwMoveMethod); +#else + result = SetFilePointerEx((HANDLE)file, liDistanceToMove, NULL, dwMoveMethod); +#endif if (result == 0) { return ma_result_from_GetLastError(GetLastError()); } @@ -59752,22 +43963,20 @@ static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i LARGE_INTEGER liZero; LARGE_INTEGER liTell; BOOL result; +#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__) + LONG tell; +#endif (void)pVFS; liZero.QuadPart = 0; - if (ma_SetFilePointerEx != NULL) { - result = ma_SetFilePointerEx((HANDLE)file, liZero, &liTell, FILE_CURRENT); - } else if (ma_SetFilePointer != NULL) { - LONG tell; - - result = ma_SetFilePointer((HANDLE)file, (LONG)liZero.QuadPart, &tell, FILE_CURRENT); - liTell.QuadPart = tell; - } else { - return MA_NOT_IMPLEMENTED; - } - +#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__) + result = SetFilePointer((HANDLE)file, (LONG)liZero.QuadPart, &tell, FILE_CURRENT); + liTell.QuadPart = tell; +#else + result = SetFilePointerEx((HANDLE)file, liZero, &liTell, FILE_CURRENT); +#endif if (result == 0) { return ma_result_from_GetLastError(GetLastError()); } @@ -59887,8 +44096,8 @@ static ma_result ma_default_vfs_read__stdio(ma_vfs* pVFS, ma_vfs_file file, void } if (result != sizeInBytes) { - if (result == 0 && feof((FILE*)file)) { - return MA_AT_END; + if (feof((FILE*)file)) { + return MA_END_OF_FILE; } else { return ma_result_from_errno(ferror((FILE*)file)); } @@ -59922,33 +44131,24 @@ static ma_result ma_default_vfs_write__stdio(ma_vfs* pVFS, ma_vfs_file file, con static ma_result ma_default_vfs_seek__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin) { int result; - int whence; MA_ASSERT(file != NULL); (void)pVFS; - if (origin == ma_seek_origin_start) { - whence = SEEK_SET; - } else if (origin == ma_seek_origin_end) { - whence = SEEK_END; - } else { - whence = SEEK_CUR; - } - #if defined(_WIN32) #if defined(_MSC_VER) && _MSC_VER > 1200 - result = _fseeki64((FILE*)file, offset, whence); + result = _fseeki64((FILE*)file, offset, origin); #else /* No _fseeki64() so restrict to 31 bits. */ - if (offset > 0x7FFFFFFF) { + if (origin > 0x7FFFFFFF) { return MA_OUT_OF_RANGE; } - result = fseek((FILE*)file, (int)offset, whence); + result = fseek((FILE*)file, (int)offset, origin); #endif #else - result = fseek((FILE*)file, (long int)offset, whence); + result = fseek((FILE*)file, (long int)offset, origin); #endif if (result != 0) { return MA_ERROR; @@ -60024,7 +44224,7 @@ static ma_result ma_default_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uin return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_open__win32(pVFS, pFilePath, openMode, pFile); #else return ma_default_vfs_open__stdio(pVFS, pFilePath, openMode, pFile); @@ -60043,7 +44243,7 @@ static ma_result ma_default_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, m return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_open_w__win32(pVFS, pFilePath, openMode, pFile); #else return ma_default_vfs_open_w__stdio(pVFS, pFilePath, openMode, pFile); @@ -60056,7 +44256,7 @@ static ma_result ma_default_vfs_close(ma_vfs* pVFS, ma_vfs_file file) return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_close__win32(pVFS, file); #else return ma_default_vfs_close__stdio(pVFS, file); @@ -60073,7 +44273,7 @@ static ma_result ma_default_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_read__win32(pVFS, file, pDst, sizeInBytes, pBytesRead); #else return ma_default_vfs_read__stdio(pVFS, file, pDst, sizeInBytes, pBytesRead); @@ -60090,7 +44290,7 @@ static ma_result ma_default_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_write__win32(pVFS, file, pSrc, sizeInBytes, pBytesWritten); #else return ma_default_vfs_write__stdio(pVFS, file, pSrc, sizeInBytes, pBytesWritten); @@ -60103,7 +44303,7 @@ static ma_result ma_default_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 of return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_seek__win32(pVFS, file, offset, origin); #else return ma_default_vfs_seek__stdio(pVFS, file, offset, origin); @@ -60122,7 +44322,7 @@ static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* p return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_tell__win32(pVFS, file, pCursor); #else return ma_default_vfs_tell__stdio(pVFS, file, pCursor); @@ -60141,7 +44341,7 @@ static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_inf return MA_INVALID_ARGS; } -#if defined(MA_USE_WIN32_FILEIO) +#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) return ma_default_vfs_info__win32(pVFS, file, pInfo); #else return ma_default_vfs_info__stdio(pVFS, file, pInfo); @@ -60243,81 +44443,6 @@ MA_API ma_result ma_vfs_or_default_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_ -static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePath, const wchar_t* pFilePathW, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_result result; - ma_vfs_file file; - ma_file_info info; - void* pData; - size_t bytesRead; - - if (ppData != NULL) { - *ppData = NULL; - } - if (pSize != NULL) { - *pSize = 0; - } - - if (ppData == NULL) { - return MA_INVALID_ARGS; - } - - if (pFilePath != NULL) { - result = ma_vfs_or_default_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file); - } else { - result = ma_vfs_or_default_open_w(pVFS, pFilePathW, MA_OPEN_MODE_READ, &file); - } - if (result != MA_SUCCESS) { - return result; - } - - result = ma_vfs_or_default_info(pVFS, file, &info); - if (result != MA_SUCCESS) { - ma_vfs_or_default_close(pVFS, file); - return result; - } - - if (info.sizeInBytes > MA_SIZE_MAX) { - ma_vfs_or_default_close(pVFS, file); - return MA_TOO_BIG; - } - - pData = ma_malloc((size_t)info.sizeInBytes, pAllocationCallbacks); /* Safe cast. */ - if (pData == NULL) { - ma_vfs_or_default_close(pVFS, file); - return result; - } - - result = ma_vfs_or_default_read(pVFS, file, pData, (size_t)info.sizeInBytes, &bytesRead); /* Safe cast. */ - ma_vfs_or_default_close(pVFS, file); - - if (result != MA_SUCCESS) { - ma_free(pData, pAllocationCallbacks); - return result; - } - - if (pSize != NULL) { - *pSize = bytesRead; - } - - MA_ASSERT(ppData != NULL); - *ppData = pData; - - return MA_SUCCESS; -} - -MA_API ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) -{ - return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, NULL, ppData, pSize, pAllocationCallbacks); -} - -MA_API ma_result ma_vfs_open_and_read_file_w(ma_vfs* pVFS, const wchar_t* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) -{ - return ma_vfs_open_and_read_file_ex(pVFS, NULL, pFilePath, ppData, pSize, pAllocationCallbacks); -} - - - /************************************************************************************************************************************************************** Decoding and Encoding Headers. These are auto-generated from a tool. @@ -60325,76 +44450,198 @@ Decoding and Encoding Headers. These are auto-generated from a tool. **************************************************************************************************************************************************************/ #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)) /* dr_wav_h begin */ -#ifndef ma_dr_wav_h -#define ma_dr_wav_h +#ifndef dr_wav_h +#define dr_wav_h #ifdef __cplusplus extern "C" { #endif -#define MA_DR_WAV_STRINGIFY(x) #x -#define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) -#define MA_DR_WAV_VERSION_MAJOR 0 -#define MA_DR_WAV_VERSION_MINOR 13 -#define MA_DR_WAV_VERSION_REVISION 18 -#define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) +#define DRWAV_STRINGIFY(x) #x +#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) +#define DRWAV_VERSION_MAJOR 0 +#define DRWAV_VERSION_MINOR 12 +#define DRWAV_VERSION_REVISION 19 +#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include -#define MA_DR_WAVE_FORMAT_PCM 0x1 -#define MA_DR_WAVE_FORMAT_ADPCM 0x2 -#define MA_DR_WAVE_FORMAT_IEEE_FLOAT 0x3 -#define MA_DR_WAVE_FORMAT_ALAW 0x6 -#define MA_DR_WAVE_FORMAT_MULAW 0x7 -#define MA_DR_WAVE_FORMAT_DVI_ADPCM 0x11 -#define MA_DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE -#define MA_DR_WAV_SEQUENTIAL 0x00000001 -#define MA_DR_WAV_WITH_METADATA 0x00000002 -MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision); -MA_API const char* ma_dr_wav_version_string(void); +typedef signed char drwav_int8; +typedef unsigned char drwav_uint8; +typedef signed short drwav_int16; +typedef unsigned short drwav_uint16; +typedef signed int drwav_int32; +typedef unsigned int drwav_uint32; +#if defined(_MSC_VER) + typedef signed __int64 drwav_int64; + typedef unsigned __int64 drwav_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drwav_int64; + typedef unsigned long long drwav_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + typedef drwav_uint64 drwav_uintptr; +#else + typedef drwav_uint32 drwav_uintptr; +#endif +typedef drwav_uint8 drwav_bool8; +typedef drwav_uint32 drwav_bool32; +#define DRWAV_TRUE 1 +#define DRWAV_FALSE 0 +#if !defined(DRWAV_API) + #if defined(DRWAV_DLL) + #if defined(_WIN32) + #define DRWAV_DLL_IMPORT __declspec(dllimport) + #define DRWAV_DLL_EXPORT __declspec(dllexport) + #define DRWAV_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRWAV_DLL_IMPORT __attribute__((visibility("default"))) + #define DRWAV_DLL_EXPORT __attribute__((visibility("default"))) + #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRWAV_DLL_IMPORT + #define DRWAV_DLL_EXPORT + #define DRWAV_DLL_PRIVATE static + #endif + #endif + #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) + #define DRWAV_API DRWAV_DLL_EXPORT + #else + #define DRWAV_API DRWAV_DLL_IMPORT + #endif + #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE + #else + #define DRWAV_API extern + #define DRWAV_PRIVATE static + #endif +#endif +typedef drwav_int32 drwav_result; +#define DRWAV_SUCCESS 0 +#define DRWAV_ERROR -1 +#define DRWAV_INVALID_ARGS -2 +#define DRWAV_INVALID_OPERATION -3 +#define DRWAV_OUT_OF_MEMORY -4 +#define DRWAV_OUT_OF_RANGE -5 +#define DRWAV_ACCESS_DENIED -6 +#define DRWAV_DOES_NOT_EXIST -7 +#define DRWAV_ALREADY_EXISTS -8 +#define DRWAV_TOO_MANY_OPEN_FILES -9 +#define DRWAV_INVALID_FILE -10 +#define DRWAV_TOO_BIG -11 +#define DRWAV_PATH_TOO_LONG -12 +#define DRWAV_NAME_TOO_LONG -13 +#define DRWAV_NOT_DIRECTORY -14 +#define DRWAV_IS_DIRECTORY -15 +#define DRWAV_DIRECTORY_NOT_EMPTY -16 +#define DRWAV_END_OF_FILE -17 +#define DRWAV_NO_SPACE -18 +#define DRWAV_BUSY -19 +#define DRWAV_IO_ERROR -20 +#define DRWAV_INTERRUPT -21 +#define DRWAV_UNAVAILABLE -22 +#define DRWAV_ALREADY_IN_USE -23 +#define DRWAV_BAD_ADDRESS -24 +#define DRWAV_BAD_SEEK -25 +#define DRWAV_BAD_PIPE -26 +#define DRWAV_DEADLOCK -27 +#define DRWAV_TOO_MANY_LINKS -28 +#define DRWAV_NOT_IMPLEMENTED -29 +#define DRWAV_NO_MESSAGE -30 +#define DRWAV_BAD_MESSAGE -31 +#define DRWAV_NO_DATA_AVAILABLE -32 +#define DRWAV_INVALID_DATA -33 +#define DRWAV_TIMEOUT -34 +#define DRWAV_NO_NETWORK -35 +#define DRWAV_NOT_UNIQUE -36 +#define DRWAV_NOT_SOCKET -37 +#define DRWAV_NO_ADDRESS -38 +#define DRWAV_BAD_PROTOCOL -39 +#define DRWAV_PROTOCOL_UNAVAILABLE -40 +#define DRWAV_PROTOCOL_NOT_SUPPORTED -41 +#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRWAV_SOCKET_NOT_SUPPORTED -44 +#define DRWAV_CONNECTION_RESET -45 +#define DRWAV_ALREADY_CONNECTED -46 +#define DRWAV_NOT_CONNECTED -47 +#define DRWAV_CONNECTION_REFUSED -48 +#define DRWAV_NO_HOST -49 +#define DRWAV_IN_PROGRESS -50 +#define DRWAV_CANCELLED -51 +#define DRWAV_MEMORY_ALREADY_MAPPED -52 +#define DRWAV_AT_END -53 +#define DR_WAVE_FORMAT_PCM 0x1 +#define DR_WAVE_FORMAT_ADPCM 0x2 +#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 +#define DR_WAVE_FORMAT_ALAW 0x6 +#define DR_WAVE_FORMAT_MULAW 0x7 +#define DR_WAVE_FORMAT_DVI_ADPCM 0x11 +#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE +#ifndef DRWAV_MAX_SMPL_LOOPS +#define DRWAV_MAX_SMPL_LOOPS 1 +#endif +#define DRWAV_SEQUENTIAL 0x00000001 +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision); +DRWAV_API const char* drwav_version_string(void); typedef enum { - ma_dr_wav_seek_origin_start, - ma_dr_wav_seek_origin_current -} ma_dr_wav_seek_origin; + drwav_seek_origin_start, + drwav_seek_origin_current +} drwav_seek_origin; typedef enum { - ma_dr_wav_container_riff, - ma_dr_wav_container_rifx, - ma_dr_wav_container_w64, - ma_dr_wav_container_rf64, - ma_dr_wav_container_aiff -} ma_dr_wav_container; + drwav_container_riff, + drwav_container_w64, + drwav_container_rf64 +} drwav_container; typedef struct { union { - ma_uint8 fourcc[4]; - ma_uint8 guid[16]; + drwav_uint8 fourcc[4]; + drwav_uint8 guid[16]; } id; - ma_uint64 sizeInBytes; + drwav_uint64 sizeInBytes; unsigned int paddingSize; -} ma_dr_wav_chunk_header; +} drwav_chunk_header; typedef struct { - ma_uint16 formatTag; - ma_uint16 channels; - ma_uint32 sampleRate; - ma_uint32 avgBytesPerSec; - ma_uint16 blockAlign; - ma_uint16 bitsPerSample; - ma_uint16 extendedSize; - ma_uint16 validBitsPerSample; - ma_uint32 channelMask; - ma_uint8 subFormat[16]; -} ma_dr_wav_fmt; -MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT); -typedef size_t (* ma_dr_wav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -typedef size_t (* ma_dr_wav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); -typedef ma_bool32 (* ma_dr_wav_seek_proc)(void* pUserData, int offset, ma_dr_wav_seek_origin origin); -typedef ma_uint64 (* ma_dr_wav_chunk_proc)(void* pChunkUserData, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_container container, const ma_dr_wav_fmt* pFMT); + drwav_uint16 formatTag; + drwav_uint16 channels; + drwav_uint32 sampleRate; + drwav_uint32 avgBytesPerSec; + drwav_uint16 blockAlign; + drwav_uint16 bitsPerSample; + drwav_uint16 extendedSize; + drwav_uint16 validBitsPerSample; + drwav_uint32 channelMask; + drwav_uint8 subFormat[16]; +} drwav_fmt; +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT); +typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); +typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); +typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); +typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT); typedef struct { - const ma_uint8* data; + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drwav_allocation_callbacks; +typedef struct +{ + const drwav_uint8* data; size_t dataSize; size_t currentReadPos; -} ma_dr_wav__memory_stream; +} drwav__memory_stream; typedef struct { void** ppData; @@ -60402,340 +44649,171 @@ typedef struct size_t dataSize; size_t dataCapacity; size_t currentWritePos; -} ma_dr_wav__memory_stream_write; +} drwav__memory_stream_write; typedef struct { - ma_dr_wav_container container; - ma_uint32 format; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_uint32 bitsPerSample; -} ma_dr_wav_data_format; -typedef enum -{ - ma_dr_wav_metadata_type_none = 0, - ma_dr_wav_metadata_type_unknown = 1 << 0, - ma_dr_wav_metadata_type_smpl = 1 << 1, - ma_dr_wav_metadata_type_inst = 1 << 2, - ma_dr_wav_metadata_type_cue = 1 << 3, - ma_dr_wav_metadata_type_acid = 1 << 4, - ma_dr_wav_metadata_type_bext = 1 << 5, - ma_dr_wav_metadata_type_list_label = 1 << 6, - ma_dr_wav_metadata_type_list_note = 1 << 7, - ma_dr_wav_metadata_type_list_labelled_cue_region = 1 << 8, - ma_dr_wav_metadata_type_list_info_software = 1 << 9, - ma_dr_wav_metadata_type_list_info_copyright = 1 << 10, - ma_dr_wav_metadata_type_list_info_title = 1 << 11, - ma_dr_wav_metadata_type_list_info_artist = 1 << 12, - ma_dr_wav_metadata_type_list_info_comment = 1 << 13, - ma_dr_wav_metadata_type_list_info_date = 1 << 14, - ma_dr_wav_metadata_type_list_info_genre = 1 << 15, - ma_dr_wav_metadata_type_list_info_album = 1 << 16, - ma_dr_wav_metadata_type_list_info_tracknumber = 1 << 17, - ma_dr_wav_metadata_type_list_all_info_strings = ma_dr_wav_metadata_type_list_info_software - | ma_dr_wav_metadata_type_list_info_copyright - | ma_dr_wav_metadata_type_list_info_title - | ma_dr_wav_metadata_type_list_info_artist - | ma_dr_wav_metadata_type_list_info_comment - | ma_dr_wav_metadata_type_list_info_date - | ma_dr_wav_metadata_type_list_info_genre - | ma_dr_wav_metadata_type_list_info_album - | ma_dr_wav_metadata_type_list_info_tracknumber, - ma_dr_wav_metadata_type_list_all_adtl = ma_dr_wav_metadata_type_list_label - | ma_dr_wav_metadata_type_list_note - | ma_dr_wav_metadata_type_list_labelled_cue_region, - ma_dr_wav_metadata_type_all = -2, - ma_dr_wav_metadata_type_all_including_unknown = -1 -} ma_dr_wav_metadata_type; -typedef enum -{ - ma_dr_wav_smpl_loop_type_forward = 0, - ma_dr_wav_smpl_loop_type_pingpong = 1, - ma_dr_wav_smpl_loop_type_backward = 2 -} ma_dr_wav_smpl_loop_type; + drwav_container container; + drwav_uint32 format; + drwav_uint32 channels; + drwav_uint32 sampleRate; + drwav_uint32 bitsPerSample; +} drwav_data_format; typedef struct { - ma_uint32 cuePointId; - ma_uint32 type; - ma_uint32 firstSampleByteOffset; - ma_uint32 lastSampleByteOffset; - ma_uint32 sampleFraction; - ma_uint32 playCount; -} ma_dr_wav_smpl_loop; + drwav_uint32 cuePointId; + drwav_uint32 type; + drwav_uint32 start; + drwav_uint32 end; + drwav_uint32 fraction; + drwav_uint32 playCount; +} drwav_smpl_loop; + typedef struct +{ + drwav_uint32 manufacturer; + drwav_uint32 product; + drwav_uint32 samplePeriod; + drwav_uint32 midiUnityNotes; + drwav_uint32 midiPitchFraction; + drwav_uint32 smpteFormat; + drwav_uint32 smpteOffset; + drwav_uint32 numSampleLoops; + drwav_uint32 samplerData; + drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS]; +} drwav_smpl; typedef struct { - ma_uint32 manufacturerId; - ma_uint32 productId; - ma_uint32 samplePeriodNanoseconds; - ma_uint32 midiUnityNote; - ma_uint32 midiPitchFraction; - ma_uint32 smpteFormat; - ma_uint32 smpteOffset; - ma_uint32 sampleLoopCount; - ma_uint32 samplerSpecificDataSizeInBytes; - ma_dr_wav_smpl_loop* pLoops; - ma_uint8* pSamplerSpecificData; -} ma_dr_wav_smpl; -typedef struct -{ - ma_int8 midiUnityNote; - ma_int8 fineTuneCents; - ma_int8 gainDecibels; - ma_int8 lowNote; - ma_int8 highNote; - ma_int8 lowVelocity; - ma_int8 highVelocity; -} ma_dr_wav_inst; -typedef struct -{ - ma_uint32 id; - ma_uint32 playOrderPosition; - ma_uint8 dataChunkId[4]; - ma_uint32 chunkStart; - ma_uint32 blockStart; - ma_uint32 sampleByteOffset; -} ma_dr_wav_cue_point; -typedef struct -{ - ma_uint32 cuePointCount; - ma_dr_wav_cue_point *pCuePoints; -} ma_dr_wav_cue; -typedef enum -{ - ma_dr_wav_acid_flag_one_shot = 1, - ma_dr_wav_acid_flag_root_note_set = 2, - ma_dr_wav_acid_flag_stretch = 4, - ma_dr_wav_acid_flag_disk_based = 8, - ma_dr_wav_acid_flag_acidizer = 16 -} ma_dr_wav_acid_flag; -typedef struct -{ - ma_uint32 flags; - ma_uint16 midiUnityNote; - ma_uint16 reserved1; - float reserved2; - ma_uint32 numBeats; - ma_uint16 meterDenominator; - ma_uint16 meterNumerator; - float tempo; -} ma_dr_wav_acid; -typedef struct -{ - ma_uint32 cuePointId; - ma_uint32 stringLength; - char* pString; -} ma_dr_wav_list_label_or_note; -typedef struct -{ - char* pDescription; - char* pOriginatorName; - char* pOriginatorReference; - char pOriginationDate[10]; - char pOriginationTime[8]; - ma_uint64 timeReference; - ma_uint16 version; - char* pCodingHistory; - ma_uint32 codingHistorySize; - ma_uint8* pUMID; - ma_uint16 loudnessValue; - ma_uint16 loudnessRange; - ma_uint16 maxTruePeakLevel; - ma_uint16 maxMomentaryLoudness; - ma_uint16 maxShortTermLoudness; -} ma_dr_wav_bext; -typedef struct -{ - ma_uint32 stringLength; - char* pString; -} ma_dr_wav_list_info_text; -typedef struct -{ - ma_uint32 cuePointId; - ma_uint32 sampleLength; - ma_uint8 purposeId[4]; - ma_uint16 country; - ma_uint16 language; - ma_uint16 dialect; - ma_uint16 codePage; - ma_uint32 stringLength; - char* pString; -} ma_dr_wav_list_labelled_cue_region; -typedef enum -{ - ma_dr_wav_metadata_location_invalid, - ma_dr_wav_metadata_location_top_level, - ma_dr_wav_metadata_location_inside_info_list, - ma_dr_wav_metadata_location_inside_adtl_list -} ma_dr_wav_metadata_location; -typedef struct -{ - ma_uint8 id[4]; - ma_dr_wav_metadata_location chunkLocation; - ma_uint32 dataSizeInBytes; - ma_uint8* pData; -} ma_dr_wav_unknown_metadata; -typedef struct -{ - ma_dr_wav_metadata_type type; - union - { - ma_dr_wav_cue cue; - ma_dr_wav_smpl smpl; - ma_dr_wav_acid acid; - ma_dr_wav_inst inst; - ma_dr_wav_bext bext; - ma_dr_wav_list_label_or_note labelOrNote; - ma_dr_wav_list_labelled_cue_region labelledCueRegion; - ma_dr_wav_list_info_text infoText; - ma_dr_wav_unknown_metadata unknown; - } data; -} ma_dr_wav_metadata; -typedef struct -{ - ma_dr_wav_read_proc onRead; - ma_dr_wav_write_proc onWrite; - ma_dr_wav_seek_proc onSeek; + drwav_read_proc onRead; + drwav_write_proc onWrite; + drwav_seek_proc onSeek; void* pUserData; - ma_allocation_callbacks allocationCallbacks; - ma_dr_wav_container container; - ma_dr_wav_fmt fmt; - ma_uint32 sampleRate; - ma_uint16 channels; - ma_uint16 bitsPerSample; - ma_uint16 translatedFormatTag; - ma_uint64 totalPCMFrameCount; - ma_uint64 dataChunkDataSize; - ma_uint64 dataChunkDataPos; - ma_uint64 bytesRemaining; - ma_uint64 readCursorInPCMFrames; - ma_uint64 dataChunkDataSizeTargetWrite; - ma_bool32 isSequentialWrite; - ma_dr_wav_metadata* pMetadata; - ma_uint32 metadataCount; - ma_dr_wav__memory_stream memoryStream; - ma_dr_wav__memory_stream_write memoryStreamWrite; + drwav_allocation_callbacks allocationCallbacks; + drwav_container container; + drwav_fmt fmt; + drwav_uint32 sampleRate; + drwav_uint16 channels; + drwav_uint16 bitsPerSample; + drwav_uint16 translatedFormatTag; + drwav_uint64 totalPCMFrameCount; + drwav_uint64 dataChunkDataSize; + drwav_uint64 dataChunkDataPos; + drwav_uint64 bytesRemaining; + drwav_uint64 dataChunkDataSizeTargetWrite; + drwav_bool32 isSequentialWrite; + drwav_smpl smpl; + drwav__memory_stream memoryStream; + drwav__memory_stream_write memoryStreamWrite; struct { - ma_uint32 bytesRemainingInBlock; - ma_uint16 predictor[2]; - ma_int32 delta[2]; - ma_int32 cachedFrames[4]; - ma_uint32 cachedFrameCount; - ma_int32 prevFrames[2][2]; + drwav_uint64 iCurrentPCMFrame; + } compressed; + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_uint16 predictor[2]; + drwav_int32 delta[2]; + drwav_int32 cachedFrames[4]; + drwav_uint32 cachedFrameCount; + drwav_int32 prevFrames[2][2]; } msadpcm; struct { - ma_uint32 bytesRemainingInBlock; - ma_int32 predictor[2]; - ma_int32 stepIndex[2]; - ma_int32 cachedFrames[16]; - ma_uint32 cachedFrameCount; + drwav_uint32 bytesRemainingInBlock; + drwav_int32 predictor[2]; + drwav_int32 stepIndex[2]; + drwav_int32 cachedFrames[16]; + drwav_uint32 cachedFrameCount; } ima; - struct - { - ma_bool8 isLE; - ma_bool8 isUnsigned; - } aiff; -} ma_dr_wav; -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_write_sequential(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_write_sequential_pcm_frames(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_write_with_metadata(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks, ma_dr_wav_metadata* pMetadata, ma_uint32 metadataCount); -MA_API ma_uint64 ma_dr_wav_target_write_size_bytes(const ma_dr_wav_data_format* pFormat, ma_uint64 totalFrameCount, ma_dr_wav_metadata* pMetadata, ma_uint32 metadataCount); -MA_API ma_dr_wav_metadata* ma_dr_wav_take_ownership_of_metadata(ma_dr_wav* pWav); -MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav); -MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToRead, void* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_le(ma_dr_wav* pWav, ma_uint64 framesToRead, void* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_be(ma_dr_wav* pWav, ma_uint64 framesToRead, void* pBufferOut); -MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFrameIndex); -MA_API ma_result ma_dr_wav_get_cursor_in_pcm_frames(ma_dr_wav* pWav, ma_uint64* pCursor); -MA_API ma_result ma_dr_wav_get_length_in_pcm_frames(ma_dr_wav* pWav, ma_uint64* pLength); -MA_API size_t ma_dr_wav_write_raw(ma_dr_wav* pWav, size_t bytesToWrite, const void* pData); -MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToWrite, const void* pData); -MA_API ma_uint64 ma_dr_wav_write_pcm_frames_le(ma_dr_wav* pWav, ma_uint64 framesToWrite, const void* pData); -MA_API ma_uint64 ma_dr_wav_write_pcm_frames_be(ma_dr_wav* pWav, ma_uint64 framesToWrite, const void* pData); -#ifndef MA_DR_WAV_NO_CONVERSION_API -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16le(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16be(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut); -MA_API void ma_dr_wav_u8_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s24_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s32_to_s16(ma_int16* pOut, const ma_int32* pIn, size_t sampleCount); -MA_API void ma_dr_wav_f32_to_s16(ma_int16* pOut, const float* pIn, size_t sampleCount); -MA_API void ma_dr_wav_f64_to_s16(ma_int16* pOut, const double* pIn, size_t sampleCount); -MA_API void ma_dr_wav_alaw_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_mulaw_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32le(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32be(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut); -MA_API void ma_dr_wav_u8_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s16_to_f32(float* pOut, const ma_int16* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s24_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s32_to_f32(float* pOut, const ma_int32* pIn, size_t sampleCount); -MA_API void ma_dr_wav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); -MA_API void ma_dr_wav_alaw_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_mulaw_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32le(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut); -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32be(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut); -MA_API void ma_dr_wav_u8_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s16_to_s32(ma_int32* pOut, const ma_int16* pIn, size_t sampleCount); -MA_API void ma_dr_wav_s24_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_f32_to_s32(ma_int32* pOut, const float* pIn, size_t sampleCount); -MA_API void ma_dr_wav_f64_to_s32(ma_int32* pOut, const double* pIn, size_t sampleCount); -MA_API void ma_dr_wav_alaw_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount); -MA_API void ma_dr_wav_mulaw_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount); +} drwav; +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); +DRWAV_API drwav_result drwav_uninit(drwav* pWav); +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex); +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +#ifndef DR_WAV_NO_CONVERSION_API +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); #endif -#ifndef MA_DR_WAV_NO_STDIO -MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_ex(ma_dr_wav* pWav, const char* filename, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_ex_w(ma_dr_wav* pWav, const wchar_t* filename, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_with_metadata(ma_dr_wav* pWav, const char* filename, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_with_metadata_w(ma_dr_wav* pWav, const wchar_t* filename, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_write(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential_pcm_frames(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_write_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential_pcm_frames_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_WAV_NO_STDIO +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); #endif -MA_API ma_bool32 ma_dr_wav_init_memory(ma_dr_wav* pWav, const void* data, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_memory_ex(ma_dr_wav* pWav, const void* data, size_t dataSize, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_memory_with_metadata(ma_dr_wav* pWav, const void* data, size_t dataSize, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_memory_write(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential_pcm_frames(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -#ifndef MA_DR_WAV_NO_CONVERSION_API -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -#ifndef MA_DR_WAV_NO_STDIO -MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_WAV_NO_CONVERSION_API +DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_WAV_NO_STDIO +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); #endif -MA_API ma_int16* ma_dr_wav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); #endif -MA_API void ma_dr_wav_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_uint16 ma_dr_wav_bytes_to_u16(const ma_uint8* data); -MA_API ma_int16 ma_dr_wav_bytes_to_s16(const ma_uint8* data); -MA_API ma_uint32 ma_dr_wav_bytes_to_u32(const ma_uint8* data); -MA_API ma_int32 ma_dr_wav_bytes_to_s32(const ma_uint8* data); -MA_API ma_uint64 ma_dr_wav_bytes_to_u64(const ma_uint8* data); -MA_API ma_int64 ma_dr_wav_bytes_to_s64(const ma_uint8* data); -MA_API float ma_dr_wav_bytes_to_f32(const ma_uint8* data); -MA_API ma_bool32 ma_dr_wav_guid_equal(const ma_uint8 a[16], const ma_uint8 b[16]); -MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b); +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data); +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data); +DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data); +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data); +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data); +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data); +DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]); +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #ifdef __cplusplus } #endif @@ -60745,284 +44823,358 @@ MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b); #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING) /* dr_flac_h begin */ -#ifndef ma_dr_flac_h -#define ma_dr_flac_h +#ifndef dr_flac_h +#define dr_flac_h #ifdef __cplusplus extern "C" { #endif -#define MA_DR_FLAC_STRINGIFY(x) #x -#define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) -#define MA_DR_FLAC_VERSION_MAJOR 0 -#define MA_DR_FLAC_VERSION_MINOR 12 -#define MA_DR_FLAC_VERSION_REVISION 43 -#define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) +#define DRFLAC_STRINGIFY(x) #x +#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) +#define DRFLAC_VERSION_MAJOR 0 +#define DRFLAC_VERSION_MINOR 12 +#define DRFLAC_VERSION_REVISION 29 +#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include +typedef signed char drflac_int8; +typedef unsigned char drflac_uint8; +typedef signed short drflac_int16; +typedef unsigned short drflac_uint16; +typedef signed int drflac_int32; +typedef unsigned int drflac_uint32; +#if defined(_MSC_VER) + typedef signed __int64 drflac_int64; + typedef unsigned __int64 drflac_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drflac_int64; + typedef unsigned long long drflac_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + typedef drflac_uint64 drflac_uintptr; +#else + typedef drflac_uint32 drflac_uintptr; +#endif +typedef drflac_uint8 drflac_bool8; +typedef drflac_uint32 drflac_bool32; +#define DRFLAC_TRUE 1 +#define DRFLAC_FALSE 0 +#if !defined(DRFLAC_API) + #if defined(DRFLAC_DLL) + #if defined(_WIN32) + #define DRFLAC_DLL_IMPORT __declspec(dllimport) + #define DRFLAC_DLL_EXPORT __declspec(dllexport) + #define DRFLAC_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRFLAC_DLL_IMPORT __attribute__((visibility("default"))) + #define DRFLAC_DLL_EXPORT __attribute__((visibility("default"))) + #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRFLAC_DLL_IMPORT + #define DRFLAC_DLL_EXPORT + #define DRFLAC_DLL_PRIVATE static + #endif + #endif + #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION) + #define DRFLAC_API DRFLAC_DLL_EXPORT + #else + #define DRFLAC_API DRFLAC_DLL_IMPORT + #endif + #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE + #else + #define DRFLAC_API extern + #define DRFLAC_PRIVATE static + #endif +#endif #if defined(_MSC_VER) && _MSC_VER >= 1700 - #define MA_DR_FLAC_DEPRECATED __declspec(deprecated) + #define DRFLAC_DEPRECATED __declspec(deprecated) #elif (defined(__GNUC__) && __GNUC__ >= 4) - #define MA_DR_FLAC_DEPRECATED __attribute__((deprecated)) + #define DRFLAC_DEPRECATED __attribute__((deprecated)) #elif defined(__has_feature) #if __has_feature(attribute_deprecated) - #define MA_DR_FLAC_DEPRECATED __attribute__((deprecated)) + #define DRFLAC_DEPRECATED __attribute__((deprecated)) #else - #define MA_DR_FLAC_DEPRECATED + #define DRFLAC_DEPRECATED #endif #else - #define MA_DR_FLAC_DEPRECATED + #define DRFLAC_DEPRECATED #endif -MA_API void ma_dr_flac_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision); -MA_API const char* ma_dr_flac_version_string(void); -#ifndef MA_DR_FLAC_BUFFER_SIZE -#define MA_DR_FLAC_BUFFER_SIZE 4096 +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision); +DRFLAC_API const char* drflac_version_string(void); +#ifndef DR_FLAC_BUFFER_SIZE +#define DR_FLAC_BUFFER_SIZE 4096 #endif -#ifdef MA_64BIT -typedef ma_uint64 ma_dr_flac_cache_t; +#if defined(_WIN64) || defined(_LP64) || defined(__LP64__) +#define DRFLAC_64BIT +#endif +#ifdef DRFLAC_64BIT +typedef drflac_uint64 drflac_cache_t; #else -typedef ma_uint32 ma_dr_flac_cache_t; +typedef drflac_uint32 drflac_cache_t; #endif -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO 0 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_PADDING 1 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_APPLICATION 2 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_CUESHEET 5 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_PICTURE 6 -#define MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID 127 -#define MA_DR_FLAC_PICTURE_TYPE_OTHER 0 -#define MA_DR_FLAC_PICTURE_TYPE_FILE_ICON 1 -#define MA_DR_FLAC_PICTURE_TYPE_OTHER_FILE_ICON 2 -#define MA_DR_FLAC_PICTURE_TYPE_COVER_FRONT 3 -#define MA_DR_FLAC_PICTURE_TYPE_COVER_BACK 4 -#define MA_DR_FLAC_PICTURE_TYPE_LEAFLET_PAGE 5 -#define MA_DR_FLAC_PICTURE_TYPE_MEDIA 6 -#define MA_DR_FLAC_PICTURE_TYPE_LEAD_ARTIST 7 -#define MA_DR_FLAC_PICTURE_TYPE_ARTIST 8 -#define MA_DR_FLAC_PICTURE_TYPE_CONDUCTOR 9 -#define MA_DR_FLAC_PICTURE_TYPE_BAND 10 -#define MA_DR_FLAC_PICTURE_TYPE_COMPOSER 11 -#define MA_DR_FLAC_PICTURE_TYPE_LYRICIST 12 -#define MA_DR_FLAC_PICTURE_TYPE_RECORDING_LOCATION 13 -#define MA_DR_FLAC_PICTURE_TYPE_DURING_RECORDING 14 -#define MA_DR_FLAC_PICTURE_TYPE_DURING_PERFORMANCE 15 -#define MA_DR_FLAC_PICTURE_TYPE_SCREEN_CAPTURE 16 -#define MA_DR_FLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17 -#define MA_DR_FLAC_PICTURE_TYPE_ILLUSTRATION 18 -#define MA_DR_FLAC_PICTURE_TYPE_BAND_LOGOTYPE 19 -#define MA_DR_FLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20 +#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0 +#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1 +#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2 +#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3 +#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4 +#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5 +#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6 +#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127 +#define DRFLAC_PICTURE_TYPE_OTHER 0 +#define DRFLAC_PICTURE_TYPE_FILE_ICON 1 +#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2 +#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3 +#define DRFLAC_PICTURE_TYPE_COVER_BACK 4 +#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5 +#define DRFLAC_PICTURE_TYPE_MEDIA 6 +#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7 +#define DRFLAC_PICTURE_TYPE_ARTIST 8 +#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9 +#define DRFLAC_PICTURE_TYPE_BAND 10 +#define DRFLAC_PICTURE_TYPE_COMPOSER 11 +#define DRFLAC_PICTURE_TYPE_LYRICIST 12 +#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13 +#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14 +#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15 +#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16 +#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17 +#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18 +#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19 +#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20 typedef enum { - ma_dr_flac_container_native, - ma_dr_flac_container_ogg, - ma_dr_flac_container_unknown -} ma_dr_flac_container; + drflac_container_native, + drflac_container_ogg, + drflac_container_unknown +} drflac_container; typedef enum { - ma_dr_flac_seek_origin_start, - ma_dr_flac_seek_origin_current -} ma_dr_flac_seek_origin; + drflac_seek_origin_start, + drflac_seek_origin_current +} drflac_seek_origin; +#pragma pack(2) typedef struct { - ma_uint64 firstPCMFrame; - ma_uint64 flacFrameOffset; - ma_uint16 pcmFrameCount; -} ma_dr_flac_seekpoint; + drflac_uint64 firstPCMFrame; + drflac_uint64 flacFrameOffset; + drflac_uint16 pcmFrameCount; +} drflac_seekpoint; +#pragma pack() typedef struct { - ma_uint16 minBlockSizeInPCMFrames; - ma_uint16 maxBlockSizeInPCMFrames; - ma_uint32 minFrameSizeInPCMFrames; - ma_uint32 maxFrameSizeInPCMFrames; - ma_uint32 sampleRate; - ma_uint8 channels; - ma_uint8 bitsPerSample; - ma_uint64 totalPCMFrameCount; - ma_uint8 md5[16]; -} ma_dr_flac_streaminfo; + drflac_uint16 minBlockSizeInPCMFrames; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint32 minFrameSizeInPCMFrames; + drflac_uint32 maxFrameSizeInPCMFrames; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalPCMFrameCount; + drflac_uint8 md5[16]; +} drflac_streaminfo; typedef struct { - ma_uint32 type; + drflac_uint32 type; const void* pRawData; - ma_uint32 rawDataSize; + drflac_uint32 rawDataSize; union { - ma_dr_flac_streaminfo streaminfo; + drflac_streaminfo streaminfo; struct { int unused; } padding; struct { - ma_uint32 id; + drflac_uint32 id; const void* pData; - ma_uint32 dataSize; + drflac_uint32 dataSize; } application; struct { - ma_uint32 seekpointCount; - const ma_dr_flac_seekpoint* pSeekpoints; + drflac_uint32 seekpointCount; + const drflac_seekpoint* pSeekpoints; } seektable; struct { - ma_uint32 vendorLength; + drflac_uint32 vendorLength; const char* vendor; - ma_uint32 commentCount; + drflac_uint32 commentCount; const void* pComments; } vorbis_comment; struct { char catalog[128]; - ma_uint64 leadInSampleCount; - ma_bool32 isCD; - ma_uint8 trackCount; + drflac_uint64 leadInSampleCount; + drflac_bool32 isCD; + drflac_uint8 trackCount; const void* pTrackData; } cuesheet; struct { - ma_uint32 type; - ma_uint32 mimeLength; + drflac_uint32 type; + drflac_uint32 mimeLength; const char* mime; - ma_uint32 descriptionLength; + drflac_uint32 descriptionLength; const char* description; - ma_uint32 width; - ma_uint32 height; - ma_uint32 colorDepth; - ma_uint32 indexColorCount; - ma_uint32 pictureDataSize; - const ma_uint8* pPictureData; + drflac_uint32 width; + drflac_uint32 height; + drflac_uint32 colorDepth; + drflac_uint32 indexColorCount; + drflac_uint32 pictureDataSize; + const drflac_uint8* pPictureData; } picture; } data; -} ma_dr_flac_metadata; -typedef size_t (* ma_dr_flac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -typedef ma_bool32 (* ma_dr_flac_seek_proc)(void* pUserData, int offset, ma_dr_flac_seek_origin origin); -typedef void (* ma_dr_flac_meta_proc)(void* pUserData, ma_dr_flac_metadata* pMetadata); +} drflac_metadata; +typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); +typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); +typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); typedef struct { - const ma_uint8* data; + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drflac_allocation_callbacks; +typedef struct +{ + const drflac_uint8* data; size_t dataSize; size_t currentReadPos; -} ma_dr_flac__memory_stream; +} drflac__memory_stream; typedef struct { - ma_dr_flac_read_proc onRead; - ma_dr_flac_seek_proc onSeek; + drflac_read_proc onRead; + drflac_seek_proc onSeek; void* pUserData; size_t unalignedByteCount; - ma_dr_flac_cache_t unalignedCache; - ma_uint32 nextL2Line; - ma_uint32 consumedBits; - ma_dr_flac_cache_t cacheL2[MA_DR_FLAC_BUFFER_SIZE/sizeof(ma_dr_flac_cache_t)]; - ma_dr_flac_cache_t cache; - ma_uint16 crc16; - ma_dr_flac_cache_t crc16Cache; - ma_uint32 crc16CacheIgnoredBytes; -} ma_dr_flac_bs; + drflac_cache_t unalignedCache; + drflac_uint32 nextL2Line; + drflac_uint32 consumedBits; + drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)]; + drflac_cache_t cache; + drflac_uint16 crc16; + drflac_cache_t crc16Cache; + drflac_uint32 crc16CacheIgnoredBytes; +} drflac_bs; typedef struct { - ma_uint8 subframeType; - ma_uint8 wastedBitsPerSample; - ma_uint8 lpcOrder; - ma_int32* pSamplesS32; -} ma_dr_flac_subframe; + drflac_uint8 subframeType; + drflac_uint8 wastedBitsPerSample; + drflac_uint8 lpcOrder; + drflac_int32* pSamplesS32; +} drflac_subframe; typedef struct { - ma_uint64 pcmFrameNumber; - ma_uint32 flacFrameNumber; - ma_uint32 sampleRate; - ma_uint16 blockSizeInPCMFrames; - ma_uint8 channelAssignment; - ma_uint8 bitsPerSample; - ma_uint8 crc8; -} ma_dr_flac_frame_header; + drflac_uint64 pcmFrameNumber; + drflac_uint32 flacFrameNumber; + drflac_uint32 sampleRate; + drflac_uint16 blockSizeInPCMFrames; + drflac_uint8 channelAssignment; + drflac_uint8 bitsPerSample; + drflac_uint8 crc8; +} drflac_frame_header; typedef struct { - ma_dr_flac_frame_header header; - ma_uint32 pcmFramesRemaining; - ma_dr_flac_subframe subframes[8]; -} ma_dr_flac_frame; + drflac_frame_header header; + drflac_uint32 pcmFramesRemaining; + drflac_subframe subframes[8]; +} drflac_frame; typedef struct { - ma_dr_flac_meta_proc onMeta; + drflac_meta_proc onMeta; void* pUserDataMD; - ma_allocation_callbacks allocationCallbacks; - ma_uint32 sampleRate; - ma_uint8 channels; - ma_uint8 bitsPerSample; - ma_uint16 maxBlockSizeInPCMFrames; - ma_uint64 totalPCMFrameCount; - ma_dr_flac_container container; - ma_uint32 seekpointCount; - ma_dr_flac_frame currentFLACFrame; - ma_uint64 currentPCMFrame; - ma_uint64 firstFLACFramePosInBytes; - ma_dr_flac__memory_stream memoryStream; - ma_int32* pDecodedSamples; - ma_dr_flac_seekpoint* pSeekpoints; + drflac_allocation_callbacks allocationCallbacks; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint64 totalPCMFrameCount; + drflac_container container; + drflac_uint32 seekpointCount; + drflac_frame currentFLACFrame; + drflac_uint64 currentPCMFrame; + drflac_uint64 firstFLACFramePosInBytes; + drflac__memory_stream memoryStream; + drflac_int32* pDecodedSamples; + drflac_seekpoint* pSeekpoints; void* _oggbs; - ma_bool32 _noSeekTableSeek : 1; - ma_bool32 _noBinarySearchSeek : 1; - ma_bool32 _noBruteForceSeek : 1; - ma_dr_flac_bs bs; - ma_uint8 pExtraData[1]; -} ma_dr_flac; -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API void ma_dr_flac_close(ma_dr_flac* pFlac); -MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut); -MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut); -MA_API ma_uint64 ma_dr_flac_read_pcm_frames_f32(ma_dr_flac* pFlac, ma_uint64 framesToRead, float* pBufferOut); -MA_API ma_bool32 ma_dr_flac_seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex); -#ifndef MA_DR_FLAC_NO_STDIO -MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_file_w(const wchar_t* pFileName, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata(const char* pFileName, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); + drflac_bool32 _noSeekTableSeek : 1; + drflac_bool32 _noBinarySearchSeek : 1; + drflac_bool32 _noBruteForceSeek : 1; + drflac_bs bs; + drflac_uint8 pExtraData[1]; +} drflac; +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API void drflac_close(drflac* pFlac); +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut); +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut); +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut); +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex); +#ifndef DR_FLAC_NO_STDIO +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); #endif -MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_t dataSize, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -#ifndef MA_DR_FLAC_NO_STDIO -MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_FLAC_NO_STDIO +DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); #endif -MA_API ma_int32* ma_dr_flac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API void ma_dr_flac_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks); typedef struct { - ma_uint32 countRemaining; + drflac_uint32 countRemaining; const char* pRunningData; -} ma_dr_flac_vorbis_comment_iterator; -MA_API void ma_dr_flac_init_vorbis_comment_iterator(ma_dr_flac_vorbis_comment_iterator* pIter, ma_uint32 commentCount, const void* pComments); -MA_API const char* ma_dr_flac_next_vorbis_comment(ma_dr_flac_vorbis_comment_iterator* pIter, ma_uint32* pCommentLengthOut); +} drflac_vorbis_comment_iterator; +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments); +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); typedef struct { - ma_uint32 countRemaining; + drflac_uint32 countRemaining; const char* pRunningData; -} ma_dr_flac_cuesheet_track_iterator; +} drflac_cuesheet_track_iterator; +#pragma pack(4) typedef struct { - ma_uint64 offset; - ma_uint8 index; - ma_uint8 reserved[3]; -} ma_dr_flac_cuesheet_track_index; + drflac_uint64 offset; + drflac_uint8 index; + drflac_uint8 reserved[3]; +} drflac_cuesheet_track_index; +#pragma pack() typedef struct { - ma_uint64 offset; - ma_uint8 trackNumber; + drflac_uint64 offset; + drflac_uint8 trackNumber; char ISRC[12]; - ma_bool8 isAudio; - ma_bool8 preEmphasis; - ma_uint8 indexCount; - const ma_dr_flac_cuesheet_track_index* pIndexPoints; -} ma_dr_flac_cuesheet_track; -MA_API void ma_dr_flac_init_cuesheet_track_iterator(ma_dr_flac_cuesheet_track_iterator* pIter, ma_uint32 trackCount, const void* pTrackData); -MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterator* pIter, ma_dr_flac_cuesheet_track* pCuesheetTrack); + drflac_bool8 isAudio; + drflac_bool8 preEmphasis; + drflac_uint8 indexCount; + const drflac_cuesheet_track_index* pIndexPoints; +} drflac_cuesheet_track; +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData); +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack); #ifdef __cplusplus } #endif @@ -61032,109 +45184,245 @@ MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterat #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) /* dr_mp3_h begin */ -#ifndef ma_dr_mp3_h -#define ma_dr_mp3_h +#ifndef dr_mp3_h +#define dr_mp3_h #ifdef __cplusplus extern "C" { #endif -#define MA_DR_MP3_STRINGIFY(x) #x -#define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) -#define MA_DR_MP3_VERSION_MAJOR 0 -#define MA_DR_MP3_VERSION_MINOR 6 -#define MA_DR_MP3_VERSION_REVISION 40 -#define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) +#define DRMP3_STRINGIFY(x) #x +#define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x) +#define DRMP3_VERSION_MAJOR 0 +#define DRMP3_VERSION_MINOR 6 +#define DRMP3_VERSION_REVISION 27 +#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #include -#define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 -#define MA_DR_MP3_MAX_SAMPLES_PER_FRAME (MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2) -MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision); -MA_API const char* ma_dr_mp3_version_string(void); +typedef signed char drmp3_int8; +typedef unsigned char drmp3_uint8; +typedef signed short drmp3_int16; +typedef unsigned short drmp3_uint16; +typedef signed int drmp3_int32; +typedef unsigned int drmp3_uint32; +#if defined(_MSC_VER) + typedef signed __int64 drmp3_int64; + typedef unsigned __int64 drmp3_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drmp3_int64; + typedef unsigned long long drmp3_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + typedef drmp3_uint64 drmp3_uintptr; +#else + typedef drmp3_uint32 drmp3_uintptr; +#endif +typedef drmp3_uint8 drmp3_bool8; +typedef drmp3_uint32 drmp3_bool32; +#define DRMP3_TRUE 1 +#define DRMP3_FALSE 0 +#if !defined(DRMP3_API) + #if defined(DRMP3_DLL) + #if defined(_WIN32) + #define DRMP3_DLL_IMPORT __declspec(dllimport) + #define DRMP3_DLL_EXPORT __declspec(dllexport) + #define DRMP3_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRMP3_DLL_IMPORT __attribute__((visibility("default"))) + #define DRMP3_DLL_EXPORT __attribute__((visibility("default"))) + #define DRMP3_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRMP3_DLL_IMPORT + #define DRMP3_DLL_EXPORT + #define DRMP3_DLL_PRIVATE static + #endif + #endif + #if defined(DR_MP3_IMPLEMENTATION) || defined(DRMP3_IMPLEMENTATION) + #define DRMP3_API DRMP3_DLL_EXPORT + #else + #define DRMP3_API DRMP3_DLL_IMPORT + #endif + #define DRMP3_PRIVATE DRMP3_DLL_PRIVATE + #else + #define DRMP3_API extern + #define DRMP3_PRIVATE static + #endif +#endif +typedef drmp3_int32 drmp3_result; +#define DRMP3_SUCCESS 0 +#define DRMP3_ERROR -1 +#define DRMP3_INVALID_ARGS -2 +#define DRMP3_INVALID_OPERATION -3 +#define DRMP3_OUT_OF_MEMORY -4 +#define DRMP3_OUT_OF_RANGE -5 +#define DRMP3_ACCESS_DENIED -6 +#define DRMP3_DOES_NOT_EXIST -7 +#define DRMP3_ALREADY_EXISTS -8 +#define DRMP3_TOO_MANY_OPEN_FILES -9 +#define DRMP3_INVALID_FILE -10 +#define DRMP3_TOO_BIG -11 +#define DRMP3_PATH_TOO_LONG -12 +#define DRMP3_NAME_TOO_LONG -13 +#define DRMP3_NOT_DIRECTORY -14 +#define DRMP3_IS_DIRECTORY -15 +#define DRMP3_DIRECTORY_NOT_EMPTY -16 +#define DRMP3_END_OF_FILE -17 +#define DRMP3_NO_SPACE -18 +#define DRMP3_BUSY -19 +#define DRMP3_IO_ERROR -20 +#define DRMP3_INTERRUPT -21 +#define DRMP3_UNAVAILABLE -22 +#define DRMP3_ALREADY_IN_USE -23 +#define DRMP3_BAD_ADDRESS -24 +#define DRMP3_BAD_SEEK -25 +#define DRMP3_BAD_PIPE -26 +#define DRMP3_DEADLOCK -27 +#define DRMP3_TOO_MANY_LINKS -28 +#define DRMP3_NOT_IMPLEMENTED -29 +#define DRMP3_NO_MESSAGE -30 +#define DRMP3_BAD_MESSAGE -31 +#define DRMP3_NO_DATA_AVAILABLE -32 +#define DRMP3_INVALID_DATA -33 +#define DRMP3_TIMEOUT -34 +#define DRMP3_NO_NETWORK -35 +#define DRMP3_NOT_UNIQUE -36 +#define DRMP3_NOT_SOCKET -37 +#define DRMP3_NO_ADDRESS -38 +#define DRMP3_BAD_PROTOCOL -39 +#define DRMP3_PROTOCOL_UNAVAILABLE -40 +#define DRMP3_PROTOCOL_NOT_SUPPORTED -41 +#define DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRMP3_SOCKET_NOT_SUPPORTED -44 +#define DRMP3_CONNECTION_RESET -45 +#define DRMP3_ALREADY_CONNECTED -46 +#define DRMP3_NOT_CONNECTED -47 +#define DRMP3_CONNECTION_REFUSED -48 +#define DRMP3_NO_HOST -49 +#define DRMP3_IN_PROGRESS -50 +#define DRMP3_CANCELLED -51 +#define DRMP3_MEMORY_ALREADY_MAPPED -52 +#define DRMP3_AT_END -53 +#define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 +#define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2) +#ifdef _MSC_VER + #define DRMP3_INLINE __forceinline +#elif defined(__GNUC__) + #if defined(__STRICT_ANSI__) + #define DRMP3_INLINE __inline__ __attribute__((always_inline)) + #else + #define DRMP3_INLINE inline __attribute__((always_inline)) + #endif +#elif defined(__WATCOMC__) + #define DRMP3_INLINE __inline +#else + #define DRMP3_INLINE +#endif +DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision); +DRMP3_API const char* drmp3_version_string(void); typedef struct { int frame_bytes, channels, hz, layer, bitrate_kbps; -} ma_dr_mp3dec_frame_info; +} drmp3dec_frame_info; typedef struct { float mdct_overlap[2][9*32], qmf_state[15*2*32]; int reserv, free_format_bytes; - ma_uint8 header[4], reserv_buf[511]; -} ma_dr_mp3dec; -MA_API void ma_dr_mp3dec_init(ma_dr_mp3dec *dec); -MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int mp3_bytes, void *pcm, ma_dr_mp3dec_frame_info *info); -MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples); + drmp3_uint8 header[4], reserv_buf[511]; +} drmp3dec; +DRMP3_API void drmp3dec_init(drmp3dec *dec); +DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info); +DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples); typedef enum { - ma_dr_mp3_seek_origin_start, - ma_dr_mp3_seek_origin_current -} ma_dr_mp3_seek_origin; + drmp3_seek_origin_start, + drmp3_seek_origin_current +} drmp3_seek_origin; typedef struct { - ma_uint64 seekPosInBytes; - ma_uint64 pcmFrameIndex; - ma_uint16 mp3FramesToDiscard; - ma_uint16 pcmFramesToDiscard; -} ma_dr_mp3_seek_point; -typedef size_t (* ma_dr_mp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -typedef ma_bool32 (* ma_dr_mp3_seek_proc)(void* pUserData, int offset, ma_dr_mp3_seek_origin origin); + drmp3_uint64 seekPosInBytes; + drmp3_uint64 pcmFrameIndex; + drmp3_uint16 mp3FramesToDiscard; + drmp3_uint16 pcmFramesToDiscard; +} drmp3_seek_point; +typedef size_t (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); +typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin); typedef struct { - ma_uint32 channels; - ma_uint32 sampleRate; -} ma_dr_mp3_config; -typedef struct -{ - ma_dr_mp3dec decoder; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_dr_mp3_read_proc onRead; - ma_dr_mp3_seek_proc onSeek; void* pUserData; - ma_allocation_callbacks allocationCallbacks; - ma_uint32 mp3FrameChannels; - ma_uint32 mp3FrameSampleRate; - ma_uint32 pcmFramesConsumedInMP3Frame; - ma_uint32 pcmFramesRemainingInMP3Frame; - ma_uint8 pcmFrames[sizeof(float)*MA_DR_MP3_MAX_SAMPLES_PER_FRAME]; - ma_uint64 currentPCMFrame; - ma_uint64 streamCursor; - ma_dr_mp3_seek_point* pSeekPoints; - ma_uint32 seekPointCount; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drmp3_allocation_callbacks; +typedef struct +{ + drmp3_uint32 channels; + drmp3_uint32 sampleRate; +} drmp3_config; +typedef struct +{ + drmp3dec decoder; + drmp3dec_frame_info frameInfo; + drmp3_uint32 channels; + drmp3_uint32 sampleRate; + drmp3_read_proc onRead; + drmp3_seek_proc onSeek; + void* pUserData; + drmp3_allocation_callbacks allocationCallbacks; + drmp3_uint32 mp3FrameChannels; + drmp3_uint32 mp3FrameSampleRate; + drmp3_uint32 pcmFramesConsumedInMP3Frame; + drmp3_uint32 pcmFramesRemainingInMP3Frame; + drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME]; + drmp3_uint64 currentPCMFrame; + drmp3_uint64 streamCursor; + drmp3_seek_point* pSeekPoints; + drmp3_uint32 seekPointCount; size_t dataSize; size_t dataCapacity; size_t dataConsumed; - ma_uint8* pData; - ma_bool32 atEnd : 1; + drmp3_uint8* pData; + drmp3_bool32 atEnd : 1; struct { - const ma_uint8* pData; + const drmp3_uint8* pData; size_t dataSize; size_t currentReadPos; } memory; -} ma_dr_mp3; -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); -#ifndef MA_DR_MP3_NO_STDIO -MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); +} drmp3; +DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_MP3_NO_STDIO +DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks); #endif -MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3); -MA_API ma_uint64 ma_dr_mp3_read_pcm_frames_f32(ma_dr_mp3* pMP3, ma_uint64 framesToRead, float* pBufferOut); -MA_API ma_uint64 ma_dr_mp3_read_pcm_frames_s16(ma_dr_mp3* pMP3, ma_uint64 framesToRead, ma_int16* pBufferOut); -MA_API ma_bool32 ma_dr_mp3_seek_to_pcm_frame(ma_dr_mp3* pMP3, ma_uint64 frameIndex); -MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3); -MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3); -MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint64* pMP3FrameCount, ma_uint64* pPCMFrameCount); -MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSeekPointCount, ma_dr_mp3_seek_point* pSeekPoints); -MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints); -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_mp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -#ifndef MA_DR_MP3_NO_STDIO -MA_API float* ma_dr_mp3_open_file_and_read_pcm_frames_f32(const char* filePath, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_file_and_read_pcm_frames_s16(const char* filePath, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +DRMP3_API void drmp3_uninit(drmp3* pMP3); +DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut); +DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut); +DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex); +DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3); +DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3); +DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount); +DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints); +DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints); +DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_MP3_NO_STDIO +DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks); #endif -MA_API void* ma_dr_mp3_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API void ma_dr_mp3_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); +DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks); +DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks); #ifdef __cplusplus } #endif @@ -61150,41 +45438,35 @@ Decoding **************************************************************************************************************************************************************/ #ifndef MA_NO_DECODING -static ma_result ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) +static size_t ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { - MA_ASSERT(pDecoder != NULL); + size_t bytesRead; - return pDecoder->onRead(pDecoder, pBufferOut, bytesToRead, pBytesRead); + MA_ASSERT(pDecoder != NULL); + MA_ASSERT(pBufferOut != NULL); + + bytesRead = pDecoder->onRead(pDecoder, pBufferOut, bytesToRead); + pDecoder->readPointerInBytes += bytesRead; + + return bytesRead; } -static ma_result ma_decoder_seek_bytes(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin) +static ma_bool32 ma_decoder_seek_bytes(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin) { + ma_bool32 wasSuccessful; + MA_ASSERT(pDecoder != NULL); - return pDecoder->onSeek(pDecoder, byteOffset, origin); -} - -static ma_result ma_decoder_tell_bytes(ma_decoder* pDecoder, ma_int64* pCursor) -{ - MA_ASSERT(pDecoder != NULL); - - if (pDecoder->onTell == NULL) { - return MA_NOT_IMPLEMENTED; + wasSuccessful = pDecoder->onSeek(pDecoder, byteOffset, origin); + if (wasSuccessful) { + if (origin == ma_seek_origin_start) { + pDecoder->readPointerInBytes = (ma_uint64)byteOffset; + } else { + pDecoder->readPointerInBytes += byteOffset; + } } - return pDecoder->onTell(pDecoder, pCursor); -} - - -MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat, ma_uint32 seekPointCount) -{ - ma_decoding_backend_config config; - - MA_ZERO_OBJECT(&config); - config.preferredFormat = preferredFormat; - config.seekPointCount = seekPointCount; - - return config; + return wasSuccessful; } @@ -61192,22 +45474,18 @@ MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint3 { ma_decoder_config config; MA_ZERO_OBJECT(&config); - config.format = outputFormat; - config.channels = outputChannels; - config.sampleRate = outputSampleRate; - config.resampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate doesn't matter here. */ - config.encodingFormat = ma_encoding_format_unknown; + config.format = outputFormat; + config.channels = ma_min(outputChannels, ma_countof(config.channelMap)); + config.sampleRate = outputSampleRate; + config.resampling.algorithm = ma_resample_algorithm_linear; + config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); + config.resampling.speex.quality = 3; /* Note that we are intentionally leaving the channel map empty here which will cause the default channel map to be used. */ return config; } -MA_API ma_decoder_config ma_decoder_config_init_default(void) -{ - return ma_decoder_config_init(ma_format_unknown, 0, 0); -} - MA_API ma_decoder_config ma_decoder_config_init_copy(const ma_decoder_config* pConfig) { ma_decoder_config config; @@ -61222,2358 +45500,447 @@ MA_API ma_decoder_config ma_decoder_config_init_copy(const ma_decoder_config* pC static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_decoder_config* pConfig) { - ma_result result; ma_data_converter_config converterConfig; - ma_format internalFormat; - ma_uint32 internalChannels; - ma_uint32 internalSampleRate; - ma_channel internalChannelMap[MA_MAX_CHANNELS]; MA_ASSERT(pDecoder != NULL); MA_ASSERT(pConfig != NULL); - result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, &internalSampleRate, internalChannelMap, ma_countof(internalChannelMap)); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the internal data format. */ - } - - /* Make sure we're not asking for too many channels. */ if (pConfig->channels > MA_MAX_CHANNELS) { return MA_INVALID_ARGS; } /* The internal channels should have already been validated at a higher level, but we'll do it again explicitly here for safety. */ - if (internalChannels > MA_MAX_CHANNELS) { + if (pDecoder->internalChannels > MA_MAX_CHANNELS) { return MA_INVALID_ARGS; } /* Output format. */ if (pConfig->format == ma_format_unknown) { - pDecoder->outputFormat = internalFormat; + pDecoder->outputFormat = pDecoder->internalFormat; } else { pDecoder->outputFormat = pConfig->format; } if (pConfig->channels == 0) { - pDecoder->outputChannels = internalChannels; + pDecoder->outputChannels = pDecoder->internalChannels; } else { pDecoder->outputChannels = pConfig->channels; } if (pConfig->sampleRate == 0) { - pDecoder->outputSampleRate = internalSampleRate; + pDecoder->outputSampleRate = pDecoder->internalSampleRate; } else { pDecoder->outputSampleRate = pConfig->sampleRate; } + if (ma_channel_map_blank(pDecoder->outputChannels, pConfig->channelMap)) { + ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->outputChannels, pDecoder->outputChannelMap); + } else { + MA_COPY_MEMORY(pDecoder->outputChannelMap, pConfig->channelMap, sizeof(pConfig->channelMap)); + } + + converterConfig = ma_data_converter_config_init( - internalFormat, pDecoder->outputFormat, - internalChannels, pDecoder->outputChannels, - internalSampleRate, pDecoder->outputSampleRate + pDecoder->internalFormat, pDecoder->outputFormat, + pDecoder->internalChannels, pDecoder->outputChannels, + pDecoder->internalSampleRate, pDecoder->outputSampleRate ); - converterConfig.pChannelMapIn = internalChannelMap; - converterConfig.pChannelMapOut = pConfig->pChannelMap; - converterConfig.channelMixMode = pConfig->channelMixMode; - converterConfig.ditherMode = pConfig->ditherMode; - converterConfig.allowDynamicSampleRate = MA_FALSE; /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */ - converterConfig.resampling = pConfig->resampling; + ma_channel_map_copy(converterConfig.channelMapIn, pDecoder->internalChannelMap, pDecoder->internalChannels); + ma_channel_map_copy(converterConfig.channelMapOut, pDecoder->outputChannelMap, pDecoder->outputChannels); + converterConfig.channelMixMode = pConfig->channelMixMode; + converterConfig.ditherMode = pConfig->ditherMode; + converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */ + converterConfig.resampling.algorithm = pConfig->resampling.algorithm; + converterConfig.resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder; + converterConfig.resampling.speex.quality = pConfig->resampling.speex.quality; - result = ma_data_converter_init(&converterConfig, &pDecoder->allocationCallbacks, &pDecoder->converter); - if (result != MA_SUCCESS) { - return result; - } - - /* - Now that we have the decoder we need to determine whether or not we need a heap-allocated cache. We'll - need this if the data converter does not support calculation of the required input frame count. To - determine support for this we'll just run a test. - */ - { - ma_uint64 unused; - - result = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, 1, &unused); - if (result != MA_SUCCESS) { - /* - We were unable to calculate the required input frame count which means we'll need to use - a heap-allocated cache. - */ - ma_uint64 inputCacheCapSizeInBytes; - - pDecoder->inputCacheCap = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(internalFormat, internalChannels); - - /* Not strictly necessary, but keeping here for safety in case we change the default value of pDecoder->inputCacheCap. */ - inputCacheCapSizeInBytes = pDecoder->inputCacheCap * ma_get_bytes_per_frame(internalFormat, internalChannels); - if (inputCacheCapSizeInBytes > MA_SIZE_MAX) { - ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - - pDecoder->pInputCache = ma_malloc((size_t)inputCacheCapSizeInBytes, &pDecoder->allocationCallbacks); /* Safe cast to size_t. */ - if (pDecoder->pInputCache == NULL) { - ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - } - } - - return MA_SUCCESS; + return ma_data_converter_init(&converterConfig, &pDecoder->converter); } - - -static ma_result ma_decoder_internal_on_read__custom(void* pUserData, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) -{ - ma_decoder* pDecoder = (ma_decoder*)pUserData; - MA_ASSERT(pDecoder != NULL); - - return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead, pBytesRead); -} - -static ma_result ma_decoder_internal_on_seek__custom(void* pUserData, ma_int64 offset, ma_seek_origin origin) -{ - ma_decoder* pDecoder = (ma_decoder*)pUserData; - MA_ASSERT(pDecoder != NULL); - - return ma_decoder_seek_bytes(pDecoder, offset, origin); -} - -static ma_result ma_decoder_internal_on_tell__custom(void* pUserData, ma_int64* pCursor) -{ - ma_decoder* pDecoder = (ma_decoder*)pUserData; - MA_ASSERT(pDecoder != NULL); - - return ma_decoder_tell_bytes(pDecoder, pCursor); -} - - -static ma_result ma_decoder_init_from_vtable__internal(const ma_decoding_backend_vtable* pVTable, void* pVTableUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result; - ma_decoding_backend_config backendConfig; - ma_data_source* pBackend; - - MA_ASSERT(pVTable != NULL); - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pVTable->onInit == NULL) { - return MA_NOT_IMPLEMENTED; - } - - backendConfig = ma_decoding_backend_config_init(pConfig->format, pConfig->seekPointCount); - - result = pVTable->onInit(pVTableUserData, ma_decoder_internal_on_read__custom, ma_decoder_internal_on_seek__custom, ma_decoder_internal_on_tell__custom, pDecoder, &backendConfig, &pDecoder->allocationCallbacks, &pBackend); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the backend from this vtable. */ - } - - /* Getting here means we were able to initialize the backend so we can now initialize the decoder. */ - pDecoder->pBackend = pBackend; - pDecoder->pBackendVTable = pVTable; - pDecoder->pBackendUserData = pConfig->pCustomBackendUserData; - - return MA_SUCCESS; -} - -static ma_result ma_decoder_init_from_file__internal(const ma_decoding_backend_vtable* pVTable, void* pVTableUserData, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result; - ma_decoding_backend_config backendConfig; - ma_data_source* pBackend; - - MA_ASSERT(pVTable != NULL); - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pVTable->onInitFile == NULL) { - return MA_NOT_IMPLEMENTED; - } - - backendConfig = ma_decoding_backend_config_init(pConfig->format, pConfig->seekPointCount); - - result = pVTable->onInitFile(pVTableUserData, pFilePath, &backendConfig, &pDecoder->allocationCallbacks, &pBackend); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the backend from this vtable. */ - } - - /* Getting here means we were able to initialize the backend so we can now initialize the decoder. */ - pDecoder->pBackend = pBackend; - pDecoder->pBackendVTable = pVTable; - pDecoder->pBackendUserData = pConfig->pCustomBackendUserData; - - return MA_SUCCESS; -} - -static ma_result ma_decoder_init_from_file_w__internal(const ma_decoding_backend_vtable* pVTable, void* pVTableUserData, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result; - ma_decoding_backend_config backendConfig; - ma_data_source* pBackend; - - MA_ASSERT(pVTable != NULL); - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pVTable->onInitFileW == NULL) { - return MA_NOT_IMPLEMENTED; - } - - backendConfig = ma_decoding_backend_config_init(pConfig->format, pConfig->seekPointCount); - - result = pVTable->onInitFileW(pVTableUserData, pFilePath, &backendConfig, &pDecoder->allocationCallbacks, &pBackend); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the backend from this vtable. */ - } - - /* Getting here means we were able to initialize the backend so we can now initialize the decoder. */ - pDecoder->pBackend = pBackend; - pDecoder->pBackendVTable = pVTable; - pDecoder->pBackendUserData = pConfig->pCustomBackendUserData; - - return MA_SUCCESS; -} - -static ma_result ma_decoder_init_from_memory__internal(const ma_decoding_backend_vtable* pVTable, void* pVTableUserData, const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result; - ma_decoding_backend_config backendConfig; - ma_data_source* pBackend; - - MA_ASSERT(pVTable != NULL); - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pVTable->onInitMemory == NULL) { - return MA_NOT_IMPLEMENTED; - } - - backendConfig = ma_decoding_backend_config_init(pConfig->format, pConfig->seekPointCount); - - result = pVTable->onInitMemory(pVTableUserData, pData, dataSize, &backendConfig, &pDecoder->allocationCallbacks, &pBackend); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the backend from this vtable. */ - } - - /* Getting here means we were able to initialize the backend so we can now initialize the decoder. */ - pDecoder->pBackend = pBackend; - pDecoder->pBackendVTable = pVTable; - pDecoder->pBackendUserData = pConfig->pCustomBackendUserData; - - return MA_SUCCESS; -} - - - -static ma_result ma_decoder_init_custom__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result = MA_NO_BACKEND; - size_t ivtable; - - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pConfig->ppCustomBackendVTables == NULL) { - return MA_NO_BACKEND; - } - - /* The order each backend is listed is what defines the priority. */ - for (ivtable = 0; ivtable < pConfig->customBackendCount; ivtable += 1) { - const ma_decoding_backend_vtable* pVTable = pConfig->ppCustomBackendVTables[ivtable]; - if (pVTable != NULL) { - result = ma_decoder_init_from_vtable__internal(pVTable, pConfig->pCustomBackendUserData, pConfig, pDecoder); - if (result == MA_SUCCESS) { - return MA_SUCCESS; - } else { - /* Initialization failed. Move on to the next one, but seek back to the start first so the next vtable starts from the first byte of the file. */ - result = ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start); - if (result != MA_SUCCESS) { - return result; /* Failed to seek back to the start. */ - } - } - } else { - /* No vtable. */ - } - } - - /* Getting here means we couldn't find a backend. */ - return MA_NO_BACKEND; -} - -static ma_result ma_decoder_init_custom_from_file__internal(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result = MA_NO_BACKEND; - size_t ivtable; - - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pConfig->ppCustomBackendVTables == NULL) { - return MA_NO_BACKEND; - } - - /* The order each backend is listed is what defines the priority. */ - for (ivtable = 0; ivtable < pConfig->customBackendCount; ivtable += 1) { - const ma_decoding_backend_vtable* pVTable = pConfig->ppCustomBackendVTables[ivtable]; - if (pVTable != NULL) { - result = ma_decoder_init_from_file__internal(pVTable, pConfig->pCustomBackendUserData, pFilePath, pConfig, pDecoder); - if (result == MA_SUCCESS) { - return MA_SUCCESS; - } - } else { - /* No vtable. */ - } - } - - /* Getting here means we couldn't find a backend. */ - return MA_NO_BACKEND; -} - -static ma_result ma_decoder_init_custom_from_file_w__internal(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result = MA_NO_BACKEND; - size_t ivtable; - - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pConfig->ppCustomBackendVTables == NULL) { - return MA_NO_BACKEND; - } - - /* The order each backend is listed is what defines the priority. */ - for (ivtable = 0; ivtable < pConfig->customBackendCount; ivtable += 1) { - const ma_decoding_backend_vtable* pVTable = pConfig->ppCustomBackendVTables[ivtable]; - if (pVTable != NULL) { - result = ma_decoder_init_from_file_w__internal(pVTable, pConfig->pCustomBackendUserData, pFilePath, pConfig, pDecoder); - if (result == MA_SUCCESS) { - return MA_SUCCESS; - } - } else { - /* No vtable. */ - } - } - - /* Getting here means we couldn't find a backend. */ - return MA_NO_BACKEND; -} - -static ma_result ma_decoder_init_custom_from_memory__internal(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result = MA_NO_BACKEND; - size_t ivtable; - - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDecoder != NULL); - - if (pConfig->ppCustomBackendVTables == NULL) { - return MA_NO_BACKEND; - } - - /* The order each backend is listed is what defines the priority. */ - for (ivtable = 0; ivtable < pConfig->customBackendCount; ivtable += 1) { - const ma_decoding_backend_vtable* pVTable = pConfig->ppCustomBackendVTables[ivtable]; - if (pVTable != NULL) { - result = ma_decoder_init_from_memory__internal(pVTable, pConfig->pCustomBackendUserData, pData, dataSize, pConfig, pDecoder); - if (result == MA_SUCCESS) { - return MA_SUCCESS; - } - } else { - /* No vtable. */ - } - } - - /* Getting here means we couldn't find a backend. */ - return MA_NO_BACKEND; -} - - /* WAV */ -#ifdef ma_dr_wav_h +#ifdef dr_wav_h #define MA_HAS_WAV -typedef struct +static size_t ma_decoder_internal_on_read__wav(void* pUserData, void* pBufferOut, size_t bytesToRead) { - ma_data_source_base ds; - ma_read_proc onRead; - ma_seek_proc onSeek; - ma_tell_proc onTell; - void* pReadSeekTellUserData; - ma_format format; /* Can be f32, s16 or s32. */ -#if !defined(MA_NO_WAV) - ma_dr_wav dr; -#endif -} ma_wav; + ma_decoder* pDecoder = (ma_decoder*)pUserData; + MA_ASSERT(pDecoder != NULL); -MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav); -MA_API ma_result ma_wav_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav); -MA_API ma_result ma_wav_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav); -MA_API ma_result ma_wav_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav); -MA_API void ma_wav_uninit(ma_wav* pWav, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_wav_seek_to_pcm_frame(ma_wav* pWav, ma_uint64 frameIndex); -MA_API ma_result ma_wav_get_data_format(ma_wav* pWav, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_wav_get_cursor_in_pcm_frames(ma_wav* pWav, ma_uint64* pCursor); -MA_API ma_result ma_wav_get_length_in_pcm_frames(ma_wav* pWav, ma_uint64* pLength); - - -static ma_result ma_wav_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_wav_read_pcm_frames((ma_wav*)pDataSource, pFramesOut, frameCount, pFramesRead); + return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead); } -static ma_result ma_wav_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +static drwav_bool32 ma_decoder_internal_on_seek__wav(void* pUserData, int offset, drwav_seek_origin origin) { - return ma_wav_seek_to_pcm_frame((ma_wav*)pDataSource, frameIndex); + ma_decoder* pDecoder = (ma_decoder*)pUserData; + MA_ASSERT(pDecoder != NULL); + + return ma_decoder_seek_bytes(pDecoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } -static ma_result ma_wav_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_uint64 ma_decoder_internal_on_read_pcm_frames__wav(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) { - return ma_wav_get_data_format((ma_wav*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} + drwav* pWav; -static ma_result ma_wav_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_wav_get_cursor_in_pcm_frames((ma_wav*)pDataSource, pCursor); -} - -static ma_result ma_wav_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_wav_get_length_in_pcm_frames((ma_wav*)pDataSource, pLength); -} - -static ma_data_source_vtable g_ma_wav_ds_vtable = -{ - ma_wav_ds_read, - ma_wav_ds_seek, - ma_wav_ds_get_data_format, - ma_wav_ds_get_cursor, - ma_wav_ds_get_length, - NULL, /* onSetLooping */ - 0 -}; - - -#if !defined(MA_NO_WAV) -static size_t ma_wav_dr_callback__read(void* pUserData, void* pBufferOut, size_t bytesToRead) -{ - ma_wav* pWav = (ma_wav*)pUserData; - ma_result result; - size_t bytesRead; + MA_ASSERT(pDecoder != NULL); + MA_ASSERT(pFramesOut != NULL); + pWav = (drwav*)pDecoder->pInternalDecoder; MA_ASSERT(pWav != NULL); - result = pWav->onRead(pWav->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); - (void)result; + switch (pDecoder->internalFormat) { + case ma_format_s16: return drwav_read_pcm_frames_s16(pWav, frameCount, (drwav_int16*)pFramesOut); + case ma_format_s32: return drwav_read_pcm_frames_s32(pWav, frameCount, (drwav_int32*)pFramesOut); + case ma_format_f32: return drwav_read_pcm_frames_f32(pWav, frameCount, (float*)pFramesOut); + default: break; + } - return bytesRead; + /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */ + MA_ASSERT(MA_FALSE); + return 0; } -static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav_seek_origin origin) +static ma_result ma_decoder_internal_on_seek_to_pcm_frame__wav(ma_decoder* pDecoder, ma_uint64 frameIndex) { - ma_wav* pWav = (ma_wav*)pUserData; - ma_result result; - ma_seek_origin maSeekOrigin; + drwav* pWav; + drwav_bool32 result; + pWav = (drwav*)pDecoder->pInternalDecoder; MA_ASSERT(pWav != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_wav_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; - } - - result = pWav->onSeek(pWav->pReadSeekTellUserData, offset, maSeekOrigin); - if (result != MA_SUCCESS) { - return MA_FALSE; - } - - return MA_TRUE; -} -#endif - -static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ma_wav* pWav) -{ - ma_result result; - ma_data_source_config dataSourceConfig; - - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pWav); - pWav->format = ma_format_unknown; /* Use closest match to source file by default. */ - - if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) { - pWav->format = pConfig->preferredFormat; + result = drwav_seek_to_pcm_frame(pWav, frameIndex); + if (result) { + return MA_SUCCESS; } else { - /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */ - } - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_wav_ds_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pWav->ds); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the base data source. */ + return MA_ERROR; } +} +static ma_result ma_decoder_internal_on_uninit__wav(ma_decoder* pDecoder) +{ + drwav_uninit((drwav*)pDecoder->pInternalDecoder); + ma__free_from_callbacks(pDecoder->pInternalDecoder, &pDecoder->allocationCallbacks); return MA_SUCCESS; } -static ma_result ma_wav_post_init(ma_wav* pWav) +static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__wav(ma_decoder* pDecoder) { - /* - If an explicit format was not specified, try picking the closest match based on the internal - format. The format needs to be supported by miniaudio. - */ - if (pWav->format == ma_format_unknown) { - switch (pWav->dr.translatedFormatTag) - { - case MA_DR_WAVE_FORMAT_PCM: - { - if (pWav->dr.bitsPerSample == 8) { - pWav->format = ma_format_u8; - } else if (pWav->dr.bitsPerSample == 16) { - pWav->format = ma_format_s16; - } else if (pWav->dr.bitsPerSample == 24) { - pWav->format = ma_format_s24; - } else if (pWav->dr.bitsPerSample == 32) { - pWav->format = ma_format_s32; - } - } break; - - case MA_DR_WAVE_FORMAT_IEEE_FLOAT: - { - if (pWav->dr.bitsPerSample == 32) { - pWav->format = ma_format_f32; - } - } break; - - default: break; - } - - /* Fall back to f32 if we couldn't find anything. */ - if (pWav->format == ma_format_unknown) { - pWav->format = ma_format_f32; - } - } - - return MA_SUCCESS; + return ((drwav*)pDecoder->pInternalDecoder)->totalPCMFrameCount; } -MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav) -{ - ma_result result; - - result = ma_wav_init_internal(pConfig, pWav); - if (result != MA_SUCCESS) { - return result; - } - - if (onRead == NULL || onSeek == NULL) { - return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */ - } - - pWav->onRead = onRead; - pWav->onSeek = onSeek; - pWav->onTell = onTell; - pWav->pReadSeekTellUserData = pReadSeekTellUserData; - - #if !defined(MA_NO_WAV) - { - ma_bool32 wavResult; - - wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, pWav, pAllocationCallbacks); - if (wavResult != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_wav_post_init(pWav); - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. */ - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav) -{ - ma_result result; - - result = ma_wav_init_internal(pConfig, pWav); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_WAV) - { - ma_bool32 wavResult; - - wavResult = ma_dr_wav_init_file(&pWav->dr, pFilePath, pAllocationCallbacks); - if (wavResult != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_wav_post_init(pWav); - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav) -{ - ma_result result; - - result = ma_wav_init_internal(pConfig, pWav); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_WAV) - { - ma_bool32 wavResult; - - wavResult = ma_dr_wav_init_file_w(&pWav->dr, pFilePath, pAllocationCallbacks); - if (wavResult != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_wav_post_init(pWav); - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav) -{ - ma_result result; - - result = ma_wav_init_internal(pConfig, pWav); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_WAV) - { - ma_bool32 wavResult; - - wavResult = ma_dr_wav_init_memory(&pWav->dr, pData, dataSize, pAllocationCallbacks); - if (wavResult != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_wav_post_init(pWav); - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. */ - (void)pData; - (void)dataSize; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API void ma_wav_uninit(ma_wav* pWav, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pWav == NULL) { - return; - } - - (void)pAllocationCallbacks; - - #if !defined(MA_NO_WAV) - { - ma_dr_wav_uninit(&pWav->dr); - } - #else - { - /* wav is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - } - #endif - - ma_data_source_uninit(&pWav->ds); -} - -MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_WAV) - { - /* We always use floating point format. */ - ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */ - ma_uint64 totalFramesRead = 0; - ma_format format; - - ma_wav_get_data_format(pWav, &format, NULL, NULL, NULL, 0); - - switch (format) - { - case ma_format_f32: - { - totalFramesRead = ma_dr_wav_read_pcm_frames_f32(&pWav->dr, frameCount, (float*)pFramesOut); - } break; - - case ma_format_s16: - { - totalFramesRead = ma_dr_wav_read_pcm_frames_s16(&pWav->dr, frameCount, (ma_int16*)pFramesOut); - } break; - - case ma_format_s32: - { - totalFramesRead = ma_dr_wav_read_pcm_frames_s32(&pWav->dr, frameCount, (ma_int32*)pFramesOut); - } break; - - /* Fallback to a raw read. */ - case ma_format_unknown: return MA_INVALID_OPERATION; /* <-- this should never be hit because initialization would just fall back to a supported format. */ - default: - { - totalFramesRead = ma_dr_wav_read_pcm_frames(&pWav->dr, frameCount, pFramesOut); - } break; - } - - /* In the future we'll update ma_dr_wav to return MA_AT_END for us. */ - if (totalFramesRead == 0) { - result = MA_AT_END; - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - if (result == MA_SUCCESS && totalFramesRead == 0) { - result = MA_AT_END; - } - - return result; - } - #else - { - /* wav is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)pFramesOut; - (void)frameCount; - (void)pFramesRead; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_seek_to_pcm_frame(ma_wav* pWav, ma_uint64 frameIndex) -{ - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_WAV) - { - ma_bool32 wavResult; - - wavResult = ma_dr_wav_seek_to_pcm_frame(&pWav->dr, frameIndex); - if (wavResult != MA_TRUE) { - return MA_ERROR; - } - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)frameIndex; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_get_data_format(ma_wav* pWav, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* Defaults for safety. */ - if (pFormat != NULL) { - *pFormat = ma_format_unknown; - } - if (pChannels != NULL) { - *pChannels = 0; - } - if (pSampleRate != NULL) { - *pSampleRate = 0; - } - if (pChannelMap != NULL) { - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); - } - - if (pWav == NULL) { - return MA_INVALID_OPERATION; - } - - if (pFormat != NULL) { - *pFormat = pWav->format; - } - - #if !defined(MA_NO_WAV) - { - if (pChannels != NULL) { - *pChannels = pWav->dr.channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pWav->dr.sampleRate; - } - - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channelMapCap, pWav->dr.channels); - } - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_get_cursor_in_pcm_frames(ma_wav* pWav, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_WAV) - { - ma_result wavResult = ma_dr_wav_get_cursor_in_pcm_frames(&pWav->dr, pCursor); - if (wavResult != MA_SUCCESS) { - return (ma_result)wavResult; /* ma_dr_wav result codes map to miniaudio's. */ - } - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_wav_get_length_in_pcm_frames(ma_wav* pWav, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; /* Safety. */ - - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_WAV) - { - ma_result wavResult = ma_dr_wav_get_length_in_pcm_frames(&pWav->dr, pLength); - if (wavResult != MA_SUCCESS) { - return (ma_result)wavResult; /* ma_dr_wav result codes map to miniaudio's. */ - } - - return MA_SUCCESS; - } - #else - { - /* wav is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - - -static ma_result ma_decoding_backend_init__wav(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_wav* pWav; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks); - if (pWav == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_wav_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pWav); - if (result != MA_SUCCESS) { - ma_free(pWav, pAllocationCallbacks); - return result; - } - - *ppBackend = pWav; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file__wav(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_wav* pWav; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks); - if (pWav == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_wav_init_file(pFilePath, pConfig, pAllocationCallbacks, pWav); - if (result != MA_SUCCESS) { - ma_free(pWav, pAllocationCallbacks); - return result; - } - - *ppBackend = pWav; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file_w__wav(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_wav* pWav; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks); - if (pWav == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_wav_init_file_w(pFilePath, pConfig, pAllocationCallbacks, pWav); - if (result != MA_SUCCESS) { - ma_free(pWav, pAllocationCallbacks); - return result; - } - - *ppBackend = pWav; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_memory__wav(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_wav* pWav; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks); - if (pWav == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_wav_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pWav); - if (result != MA_SUCCESS) { - ma_free(pWav, pAllocationCallbacks); - return result; - } - - *ppBackend = pWav; - - return MA_SUCCESS; -} - -static void ma_decoding_backend_uninit__wav(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_wav* pWav = (ma_wav*)pBackend; - - (void)pUserData; - - ma_wav_uninit(pWav, pAllocationCallbacks); - ma_free(pWav, pAllocationCallbacks); -} - -static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_wav = -{ - ma_decoding_backend_init__wav, - ma_decoding_backend_init_file__wav, - ma_decoding_backend_init_file_w__wav, - ma_decoding_backend_init_memory__wav, - ma_decoding_backend_uninit__wav -}; - static ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - return ma_decoder_init_from_vtable__internal(&g_ma_decoding_backend_vtable_wav, NULL, pConfig, pDecoder); -} + drwav* pWav; + drwav_allocation_callbacks allocationCallbacks; -static ma_result ma_decoder_init_wav_from_file__internal(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file__internal(&g_ma_decoding_backend_vtable_wav, NULL, pFilePath, pConfig, pDecoder); -} + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDecoder != NULL); -static ma_result ma_decoder_init_wav_from_file_w__internal(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file_w__internal(&g_ma_decoding_backend_vtable_wav, NULL, pFilePath, pConfig, pDecoder); -} + (void)pConfig; -static ma_result ma_decoder_init_wav_from_memory__internal(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_memory__internal(&g_ma_decoding_backend_vtable_wav, NULL, pData, dataSize, pConfig, pDecoder); + pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pDecoder->allocationCallbacks); + if (pWav == NULL) { + return MA_OUT_OF_MEMORY; + } + + allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData; + allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc; + allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc; + allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree; + + /* Try opening the decoder first. */ + if (!drwav_init(pWav, ma_decoder_internal_on_read__wav, ma_decoder_internal_on_seek__wav, pDecoder, &allocationCallbacks)) { + ma__free_from_callbacks(pWav, &pDecoder->allocationCallbacks); + return MA_ERROR; + } + + /* If we get here it means we successfully initialized the WAV decoder. We can now initialize the rest of the ma_decoder. */ + pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__wav; + pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__wav; + pDecoder->onUninit = ma_decoder_internal_on_uninit__wav; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__wav; + pDecoder->pInternalDecoder = pWav; + + /* Try to be as optimal as possible for the internal format. If miniaudio does not support a format we will fall back to f32. */ + pDecoder->internalFormat = ma_format_unknown; + switch (pWav->translatedFormatTag) { + case DR_WAVE_FORMAT_PCM: + { + if (pWav->bitsPerSample == 8) { + pDecoder->internalFormat = ma_format_s16; + } else if (pWav->bitsPerSample == 16) { + pDecoder->internalFormat = ma_format_s16; + } else if (pWav->bitsPerSample == 32) { + pDecoder->internalFormat = ma_format_s32; + } + } break; + + case DR_WAVE_FORMAT_IEEE_FLOAT: + { + if (pWav->bitsPerSample == 32) { + pDecoder->internalFormat = ma_format_f32; + } + } break; + + case DR_WAVE_FORMAT_ALAW: + case DR_WAVE_FORMAT_MULAW: + case DR_WAVE_FORMAT_ADPCM: + case DR_WAVE_FORMAT_DVI_ADPCM: + { + pDecoder->internalFormat = ma_format_s16; + } break; + } + + if (pDecoder->internalFormat == ma_format_unknown) { + pDecoder->internalFormat = ma_format_f32; + } + + pDecoder->internalChannels = pWav->channels; + pDecoder->internalSampleRate = pWav->sampleRate; + ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDecoder->internalChannels, pDecoder->internalChannelMap); + + return MA_SUCCESS; } -#endif /* ma_dr_wav_h */ +#endif /* dr_wav_h */ /* FLAC */ -#ifdef ma_dr_flac_h +#ifdef dr_flac_h #define MA_HAS_FLAC -typedef struct +static size_t ma_decoder_internal_on_read__flac(void* pUserData, void* pBufferOut, size_t bytesToRead) { - ma_data_source_base ds; - ma_read_proc onRead; - ma_seek_proc onSeek; - ma_tell_proc onTell; - void* pReadSeekTellUserData; - ma_format format; /* Can be f32, s16 or s32. */ -#if !defined(MA_NO_FLAC) - ma_dr_flac* dr; -#endif -} ma_flac; + ma_decoder* pDecoder = (ma_decoder*)pUserData; + MA_ASSERT(pDecoder != NULL); -MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac); -MA_API ma_result ma_flac_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac); -MA_API ma_result ma_flac_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac); -MA_API ma_result ma_flac_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac); -MA_API void ma_flac_uninit(ma_flac* pFlac, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_flac_read_pcm_frames(ma_flac* pFlac, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_flac_seek_to_pcm_frame(ma_flac* pFlac, ma_uint64 frameIndex); -MA_API ma_result ma_flac_get_data_format(ma_flac* pFlac, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_flac_get_cursor_in_pcm_frames(ma_flac* pFlac, ma_uint64* pCursor); -MA_API ma_result ma_flac_get_length_in_pcm_frames(ma_flac* pFlac, ma_uint64* pLength); - - -static ma_result ma_flac_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_flac_read_pcm_frames((ma_flac*)pDataSource, pFramesOut, frameCount, pFramesRead); + return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead); } -static ma_result ma_flac_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +static drflac_bool32 ma_decoder_internal_on_seek__flac(void* pUserData, int offset, drflac_seek_origin origin) { - return ma_flac_seek_to_pcm_frame((ma_flac*)pDataSource, frameIndex); + ma_decoder* pDecoder = (ma_decoder*)pUserData; + MA_ASSERT(pDecoder != NULL); + + return ma_decoder_seek_bytes(pDecoder, offset, (origin == drflac_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } -static ma_result ma_flac_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_uint64 ma_decoder_internal_on_read_pcm_frames__flac(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) { - return ma_flac_get_data_format((ma_flac*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} + drflac* pFlac; -static ma_result ma_flac_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_flac_get_cursor_in_pcm_frames((ma_flac*)pDataSource, pCursor); -} - -static ma_result ma_flac_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_flac_get_length_in_pcm_frames((ma_flac*)pDataSource, pLength); -} - -static ma_data_source_vtable g_ma_flac_ds_vtable = -{ - ma_flac_ds_read, - ma_flac_ds_seek, - ma_flac_ds_get_data_format, - ma_flac_ds_get_cursor, - ma_flac_ds_get_length, - NULL, /* onSetLooping */ - 0 -}; - - -#if !defined(MA_NO_FLAC) -static size_t ma_flac_dr_callback__read(void* pUserData, void* pBufferOut, size_t bytesToRead) -{ - ma_flac* pFlac = (ma_flac*)pUserData; - ma_result result; - size_t bytesRead; + MA_ASSERT(pDecoder != NULL); + MA_ASSERT(pFramesOut != NULL); + pFlac = (drflac*)pDecoder->pInternalDecoder; MA_ASSERT(pFlac != NULL); - result = pFlac->onRead(pFlac->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); - (void)result; + switch (pDecoder->internalFormat) { + case ma_format_s16: return drflac_read_pcm_frames_s16(pFlac, frameCount, (drflac_int16*)pFramesOut); + case ma_format_s32: return drflac_read_pcm_frames_s32(pFlac, frameCount, (drflac_int32*)pFramesOut); + case ma_format_f32: return drflac_read_pcm_frames_f32(pFlac, frameCount, (float*)pFramesOut); + default: break; + } - return bytesRead; + /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */ + MA_ASSERT(MA_FALSE); + return 0; } -static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_flac_seek_origin origin) +static ma_result ma_decoder_internal_on_seek_to_pcm_frame__flac(ma_decoder* pDecoder, ma_uint64 frameIndex) { - ma_flac* pFlac = (ma_flac*)pUserData; - ma_result result; - ma_seek_origin maSeekOrigin; + drflac* pFlac; + drflac_bool32 result; + pFlac = (drflac*)pDecoder->pInternalDecoder; MA_ASSERT(pFlac != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_flac_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; - } - - result = pFlac->onSeek(pFlac->pReadSeekTellUserData, offset, maSeekOrigin); - if (result != MA_SUCCESS) { - return MA_FALSE; - } - - return MA_TRUE; -} -#endif - -static ma_result ma_flac_init_internal(const ma_decoding_backend_config* pConfig, ma_flac* pFlac) -{ - ma_result result; - ma_data_source_config dataSourceConfig; - - if (pFlac == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pFlac); - pFlac->format = ma_format_f32; /* f32 by default. */ - - if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) { - pFlac->format = pConfig->preferredFormat; + result = drflac_seek_to_pcm_frame(pFlac, frameIndex); + if (result) { + return MA_SUCCESS; } else { - /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */ - } - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_flac_ds_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pFlac->ds); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the base data source. */ + return MA_ERROR; } +} +static ma_result ma_decoder_internal_on_uninit__flac(ma_decoder* pDecoder) +{ + drflac_close((drflac*)pDecoder->pInternalDecoder); return MA_SUCCESS; } -MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac) +static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__flac(ma_decoder* pDecoder) { - ma_result result; - - result = ma_flac_init_internal(pConfig, pFlac); - if (result != MA_SUCCESS) { - return result; - } - - if (onRead == NULL || onSeek == NULL) { - return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */ - } - - pFlac->onRead = onRead; - pFlac->onSeek = onSeek; - pFlac->onTell = onTell; - pFlac->pReadSeekTellUserData = pReadSeekTellUserData; - - #if !defined(MA_NO_FLAC) - { - pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, pFlac, pAllocationCallbacks); - if (pFlac->dr == NULL) { - return MA_INVALID_FILE; - } - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. */ - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif + return ((drflac*)pDecoder->pInternalDecoder)->totalPCMFrameCount; } -MA_API ma_result ma_flac_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac) -{ - ma_result result; - - result = ma_flac_init_internal(pConfig, pFlac); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_FLAC) - { - pFlac->dr = ma_dr_flac_open_file(pFilePath, pAllocationCallbacks); - if (pFlac->dr == NULL) { - return MA_INVALID_FILE; - } - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_flac_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac) -{ - ma_result result; - - result = ma_flac_init_internal(pConfig, pFlac); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_FLAC) - { - pFlac->dr = ma_dr_flac_open_file_w(pFilePath, pAllocationCallbacks); - if (pFlac->dr == NULL) { - return MA_INVALID_FILE; - } - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_flac_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac) -{ - ma_result result; - - result = ma_flac_init_internal(pConfig, pFlac); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_FLAC) - { - pFlac->dr = ma_dr_flac_open_memory(pData, dataSize, pAllocationCallbacks); - if (pFlac->dr == NULL) { - return MA_INVALID_FILE; - } - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. */ - (void)pData; - (void)dataSize; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API void ma_flac_uninit(ma_flac* pFlac, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pFlac == NULL) { - return; - } - - (void)pAllocationCallbacks; - - #if !defined(MA_NO_FLAC) - { - ma_dr_flac_close(pFlac->dr); - } - #else - { - /* flac is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - } - #endif - - ma_data_source_uninit(&pFlac->ds); -} - -MA_API ma_result ma_flac_read_pcm_frames(ma_flac* pFlac, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pFlac == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_FLAC) - { - /* We always use floating point format. */ - ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */ - ma_uint64 totalFramesRead = 0; - ma_format format; - - ma_flac_get_data_format(pFlac, &format, NULL, NULL, NULL, 0); - - switch (format) - { - case ma_format_f32: - { - totalFramesRead = ma_dr_flac_read_pcm_frames_f32(pFlac->dr, frameCount, (float*)pFramesOut); - } break; - - case ma_format_s16: - { - totalFramesRead = ma_dr_flac_read_pcm_frames_s16(pFlac->dr, frameCount, (ma_int16*)pFramesOut); - } break; - - case ma_format_s32: - { - totalFramesRead = ma_dr_flac_read_pcm_frames_s32(pFlac->dr, frameCount, (ma_int32*)pFramesOut); - } break; - - case ma_format_u8: - case ma_format_s24: - case ma_format_unknown: - default: - { - return MA_INVALID_OPERATION; - }; - } - - /* In the future we'll update ma_dr_flac to return MA_AT_END for us. */ - if (totalFramesRead == 0) { - result = MA_AT_END; - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - if (result == MA_SUCCESS && totalFramesRead == 0) { - result = MA_AT_END; - } - - return result; - } - #else - { - /* flac is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)pFramesOut; - (void)frameCount; - (void)pFramesRead; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_flac_seek_to_pcm_frame(ma_flac* pFlac, ma_uint64 frameIndex) -{ - if (pFlac == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_FLAC) - { - ma_bool32 flacResult; - - flacResult = ma_dr_flac_seek_to_pcm_frame(pFlac->dr, frameIndex); - if (flacResult != MA_TRUE) { - return MA_ERROR; - } - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)frameIndex; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_flac_get_data_format(ma_flac* pFlac, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* Defaults for safety. */ - if (pFormat != NULL) { - *pFormat = ma_format_unknown; - } - if (pChannels != NULL) { - *pChannels = 0; - } - if (pSampleRate != NULL) { - *pSampleRate = 0; - } - if (pChannelMap != NULL) { - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); - } - - if (pFlac == NULL) { - return MA_INVALID_OPERATION; - } - - if (pFormat != NULL) { - *pFormat = pFlac->format; - } - - #if !defined(MA_NO_FLAC) - { - if (pChannels != NULL) { - *pChannels = pFlac->dr->channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pFlac->dr->sampleRate; - } - - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channelMapCap, pFlac->dr->channels); - } - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_flac_get_cursor_in_pcm_frames(ma_flac* pFlac, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pFlac == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_FLAC) - { - *pCursor = pFlac->dr->currentPCMFrame; - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_flac_get_length_in_pcm_frames(ma_flac* pFlac, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; /* Safety. */ - - if (pFlac == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_FLAC) - { - *pLength = pFlac->dr->totalPCMFrameCount; - - return MA_SUCCESS; - } - #else - { - /* flac is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - - -static ma_result ma_decoding_backend_init__flac(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_flac* pFlac; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks); - if (pFlac == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_flac_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pFlac); - if (result != MA_SUCCESS) { - ma_free(pFlac, pAllocationCallbacks); - return result; - } - - *ppBackend = pFlac; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file__flac(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_flac* pFlac; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks); - if (pFlac == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_flac_init_file(pFilePath, pConfig, pAllocationCallbacks, pFlac); - if (result != MA_SUCCESS) { - ma_free(pFlac, pAllocationCallbacks); - return result; - } - - *ppBackend = pFlac; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file_w__flac(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_flac* pFlac; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks); - if (pFlac == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_flac_init_file_w(pFilePath, pConfig, pAllocationCallbacks, pFlac); - if (result != MA_SUCCESS) { - ma_free(pFlac, pAllocationCallbacks); - return result; - } - - *ppBackend = pFlac; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_memory__flac(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_flac* pFlac; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks); - if (pFlac == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_flac_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pFlac); - if (result != MA_SUCCESS) { - ma_free(pFlac, pAllocationCallbacks); - return result; - } - - *ppBackend = pFlac; - - return MA_SUCCESS; -} - -static void ma_decoding_backend_uninit__flac(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_flac* pFlac = (ma_flac*)pBackend; - - (void)pUserData; - - ma_flac_uninit(pFlac, pAllocationCallbacks); - ma_free(pFlac, pAllocationCallbacks); -} - -static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_flac = -{ - ma_decoding_backend_init__flac, - ma_decoding_backend_init_file__flac, - ma_decoding_backend_init_file_w__flac, - ma_decoding_backend_init_memory__flac, - ma_decoding_backend_uninit__flac -}; - static ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - return ma_decoder_init_from_vtable__internal(&g_ma_decoding_backend_vtable_flac, NULL, pConfig, pDecoder); -} + drflac* pFlac; + drflac_allocation_callbacks allocationCallbacks; -static ma_result ma_decoder_init_flac_from_file__internal(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file__internal(&g_ma_decoding_backend_vtable_flac, NULL, pFilePath, pConfig, pDecoder); -} + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDecoder != NULL); -static ma_result ma_decoder_init_flac_from_file_w__internal(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file_w__internal(&g_ma_decoding_backend_vtable_flac, NULL, pFilePath, pConfig, pDecoder); -} + allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData; + allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc; + allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc; + allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree; -static ma_result ma_decoder_init_flac_from_memory__internal(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_memory__internal(&g_ma_decoding_backend_vtable_flac, NULL, pData, dataSize, pConfig, pDecoder); + /* Try opening the decoder first. */ + pFlac = drflac_open(ma_decoder_internal_on_read__flac, ma_decoder_internal_on_seek__flac, pDecoder, &allocationCallbacks); + if (pFlac == NULL) { + return MA_ERROR; + } + + /* If we get here it means we successfully initialized the FLAC decoder. We can now initialize the rest of the ma_decoder. */ + pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__flac; + pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__flac; + pDecoder->onUninit = ma_decoder_internal_on_uninit__flac; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__flac; + pDecoder->pInternalDecoder = pFlac; + + /* + dr_flac supports reading as s32, s16 and f32. Try to do a one-to-one mapping if possible, but fall back to s32 if not. s32 is the "native" FLAC format + since it's the only one that's truly lossless. If the internal bits per sample is <= 16 we will decode to ma_format_s16 to keep it more efficient. + */ + if (pConfig->format == ma_format_unknown) { + if (pFlac->bitsPerSample <= 16) { + pDecoder->internalFormat = ma_format_s16; + } else { + pDecoder->internalFormat = ma_format_s32; + } + } else { + if (pConfig->format == ma_format_s16 || pConfig->format == ma_format_f32) { + pDecoder->internalFormat = pConfig->format; + } else { + pDecoder->internalFormat = ma_format_s32; /* s32 as the baseline to ensure no loss of precision for 24-bit encoded files. */ + } + } + + pDecoder->internalChannels = pFlac->channels; + pDecoder->internalSampleRate = pFlac->sampleRate; + ma_get_standard_channel_map(ma_standard_channel_map_flac, pDecoder->internalChannels, pDecoder->internalChannelMap); + + return MA_SUCCESS; } -#endif /* ma_dr_flac_h */ +#endif /* dr_flac_h */ /* MP3 */ -#ifdef ma_dr_mp3_h +#ifdef dr_mp3_h #define MA_HAS_MP3 -typedef struct +static size_t ma_decoder_internal_on_read__mp3(void* pUserData, void* pBufferOut, size_t bytesToRead) { - ma_data_source_base ds; - ma_read_proc onRead; - ma_seek_proc onSeek; - ma_tell_proc onTell; - void* pReadSeekTellUserData; - ma_format format; /* Can be f32 or s16. */ -#if !defined(MA_NO_MP3) - ma_dr_mp3 dr; - ma_uint32 seekPointCount; - ma_dr_mp3_seek_point* pSeekPoints; /* Only used if seek table generation is used. */ -#endif -} ma_mp3; + ma_decoder* pDecoder = (ma_decoder*)pUserData; + MA_ASSERT(pDecoder != NULL); -MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3); -MA_API ma_result ma_mp3_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3); -MA_API ma_result ma_mp3_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3); -MA_API ma_result ma_mp3_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3); -MA_API void ma_mp3_uninit(ma_mp3* pMP3, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_mp3_read_pcm_frames(ma_mp3* pMP3, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_mp3_seek_to_pcm_frame(ma_mp3* pMP3, ma_uint64 frameIndex); -MA_API ma_result ma_mp3_get_data_format(ma_mp3* pMP3, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_mp3_get_cursor_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pCursor); -MA_API ma_result ma_mp3_get_length_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pLength); - - -static ma_result ma_mp3_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_mp3_read_pcm_frames((ma_mp3*)pDataSource, pFramesOut, frameCount, pFramesRead); + return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead); } -static ma_result ma_mp3_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +static drmp3_bool32 ma_decoder_internal_on_seek__mp3(void* pUserData, int offset, drmp3_seek_origin origin) { - return ma_mp3_seek_to_pcm_frame((ma_mp3*)pDataSource, frameIndex); + ma_decoder* pDecoder = (ma_decoder*)pUserData; + MA_ASSERT(pDecoder != NULL); + + return ma_decoder_seek_bytes(pDecoder, offset, (origin == drmp3_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } -static ma_result ma_mp3_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_uint64 ma_decoder_internal_on_read_pcm_frames__mp3(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) { - return ma_mp3_get_data_format((ma_mp3*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} + drmp3* pMP3; -static ma_result ma_mp3_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_mp3_get_cursor_in_pcm_frames((ma_mp3*)pDataSource, pCursor); -} - -static ma_result ma_mp3_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_mp3_get_length_in_pcm_frames((ma_mp3*)pDataSource, pLength); -} - -static ma_data_source_vtable g_ma_mp3_ds_vtable = -{ - ma_mp3_ds_read, - ma_mp3_ds_seek, - ma_mp3_ds_get_data_format, - ma_mp3_ds_get_cursor, - ma_mp3_ds_get_length, - NULL, /* onSetLooping */ - 0 -}; - - -#if !defined(MA_NO_MP3) -static size_t ma_mp3_dr_callback__read(void* pUserData, void* pBufferOut, size_t bytesToRead) -{ - ma_mp3* pMP3 = (ma_mp3*)pUserData; - ma_result result; - size_t bytesRead; + MA_ASSERT(pDecoder != NULL); + MA_ASSERT(pFramesOut != NULL); + pMP3 = (drmp3*)pDecoder->pInternalDecoder; MA_ASSERT(pMP3 != NULL); - result = pMP3->onRead(pMP3->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); - (void)result; - - return bytesRead; +#if defined(DR_MP3_FLOAT_OUTPUT) + MA_ASSERT(pDecoder->internalFormat == ma_format_f32); + return drmp3_read_pcm_frames_f32(pMP3, frameCount, (float*)pFramesOut); +#else + MA_ASSERT(pDecoder->internalFormat == ma_format_s16); + return drmp3_read_pcm_frames_s16(pMP3, frameCount, (drmp3_int16*)pFramesOut); +#endif } -static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) +static ma_result ma_decoder_internal_on_seek_to_pcm_frame__mp3(ma_decoder* pDecoder, ma_uint64 frameIndex) { - ma_mp3* pMP3 = (ma_mp3*)pUserData; - ma_result result; - ma_seek_origin maSeekOrigin; + drmp3* pMP3; + drmp3_bool32 result; + pMP3 = (drmp3*)pDecoder->pInternalDecoder; MA_ASSERT(pMP3 != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_mp3_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; - } - - result = pMP3->onSeek(pMP3->pReadSeekTellUserData, offset, maSeekOrigin); - if (result != MA_SUCCESS) { - return MA_FALSE; - } - - return MA_TRUE; -} -#endif - -static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, ma_mp3* pMP3) -{ - ma_result result; - ma_data_source_config dataSourceConfig; - - if (pMP3 == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pMP3); - pMP3->format = ma_format_f32; /* f32 by default. */ - - if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16)) { - pMP3->format = pConfig->preferredFormat; + result = drmp3_seek_to_pcm_frame(pMP3, frameIndex); + if (result) { + return MA_SUCCESS; } else { - /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */ - } - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_mp3_ds_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pMP3->ds); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the base data source. */ - } - - return MA_SUCCESS; -} - -static ma_result ma_mp3_generate_seek_table(ma_mp3* pMP3, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_bool32 mp3Result; - ma_uint32 seekPointCount = 0; - ma_dr_mp3_seek_point* pSeekPoints = NULL; - - MA_ASSERT(pMP3 != NULL); - MA_ASSERT(pConfig != NULL); - - seekPointCount = pConfig->seekPointCount; - if (seekPointCount > 0) { - pSeekPoints = (ma_dr_mp3_seek_point*)ma_malloc(sizeof(*pMP3->pSeekPoints) * seekPointCount, pAllocationCallbacks); - if (pSeekPoints == NULL) { - return MA_OUT_OF_MEMORY; - } - } - - mp3Result = ma_dr_mp3_calculate_seek_points(&pMP3->dr, &seekPointCount, pSeekPoints); - if (mp3Result != MA_TRUE) { - ma_free(pSeekPoints, pAllocationCallbacks); return MA_ERROR; } +} - mp3Result = ma_dr_mp3_bind_seek_table(&pMP3->dr, seekPointCount, pSeekPoints); - if (mp3Result != MA_TRUE) { - ma_free(pSeekPoints, pAllocationCallbacks); - return MA_ERROR; - } - - pMP3->seekPointCount = seekPointCount; - pMP3->pSeekPoints = pSeekPoints; - +static ma_result ma_decoder_internal_on_uninit__mp3(ma_decoder* pDecoder) +{ + drmp3_uninit((drmp3*)pDecoder->pInternalDecoder); + ma__free_from_callbacks(pDecoder->pInternalDecoder, &pDecoder->allocationCallbacks); return MA_SUCCESS; } -static ma_result ma_mp3_post_init(ma_mp3* pMP3, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__mp3(ma_decoder* pDecoder) { - ma_result result; - - result = ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks); - if (result != MA_SUCCESS) { - return result; - } - - return MA_SUCCESS; + return drmp3_get_pcm_frame_count((drmp3*)pDecoder->pInternalDecoder); } -MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3) -{ - ma_result result; - - result = ma_mp3_init_internal(pConfig, pMP3); - if (result != MA_SUCCESS) { - return result; - } - - if (onRead == NULL || onSeek == NULL) { - return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */ - } - - pMP3->onRead = onRead; - pMP3->onSeek = onSeek; - pMP3->onTell = onTell; - pMP3->pReadSeekTellUserData = pReadSeekTellUserData; - - #if !defined(MA_NO_MP3) - { - ma_bool32 mp3Result; - - mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, pMP3, pAllocationCallbacks); - if (mp3Result != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_mp3_post_init(pMP3, pConfig, pAllocationCallbacks); - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. */ - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3) -{ - ma_result result; - - result = ma_mp3_init_internal(pConfig, pMP3); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_MP3) - { - ma_bool32 mp3Result; - - mp3Result = ma_dr_mp3_init_file(&pMP3->dr, pFilePath, pAllocationCallbacks); - if (mp3Result != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_mp3_post_init(pMP3, pConfig, pAllocationCallbacks); - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3) -{ - ma_result result; - - result = ma_mp3_init_internal(pConfig, pMP3); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_MP3) - { - ma_bool32 mp3Result; - - mp3Result = ma_dr_mp3_init_file_w(&pMP3->dr, pFilePath, pAllocationCallbacks); - if (mp3Result != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_mp3_post_init(pMP3, pConfig, pAllocationCallbacks); - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3) -{ - ma_result result; - - result = ma_mp3_init_internal(pConfig, pMP3); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_MP3) - { - ma_bool32 mp3Result; - - mp3Result = ma_dr_mp3_init_memory(&pMP3->dr, pData, dataSize, pAllocationCallbacks); - if (mp3Result != MA_TRUE) { - return MA_INVALID_FILE; - } - - ma_mp3_post_init(pMP3, pConfig, pAllocationCallbacks); - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. */ - (void)pData; - (void)dataSize; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API void ma_mp3_uninit(ma_mp3* pMP3, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pMP3 == NULL) { - return; - } - - #if !defined(MA_NO_MP3) - { - ma_dr_mp3_uninit(&pMP3->dr); - } - #else - { - /* mp3 is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - } - #endif - - /* Seek points need to be freed after the MP3 decoder has been uninitialized to ensure they're no longer being referenced. */ - ma_free(pMP3->pSeekPoints, pAllocationCallbacks); - - ma_data_source_uninit(&pMP3->ds); -} - -MA_API ma_result ma_mp3_read_pcm_frames(ma_mp3* pMP3, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pMP3 == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_MP3) - { - /* We always use floating point format. */ - ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */ - ma_uint64 totalFramesRead = 0; - ma_format format; - - ma_mp3_get_data_format(pMP3, &format, NULL, NULL, NULL, 0); - - switch (format) - { - case ma_format_f32: - { - totalFramesRead = ma_dr_mp3_read_pcm_frames_f32(&pMP3->dr, frameCount, (float*)pFramesOut); - } break; - - case ma_format_s16: - { - totalFramesRead = ma_dr_mp3_read_pcm_frames_s16(&pMP3->dr, frameCount, (ma_int16*)pFramesOut); - } break; - - case ma_format_u8: - case ma_format_s24: - case ma_format_s32: - case ma_format_unknown: - default: - { - return MA_INVALID_OPERATION; - }; - } - - /* In the future we'll update ma_dr_mp3 to return MA_AT_END for us. */ - if (totalFramesRead == 0) { - result = MA_AT_END; - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - return result; - } - #else - { - /* mp3 is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)pFramesOut; - (void)frameCount; - (void)pFramesRead; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_seek_to_pcm_frame(ma_mp3* pMP3, ma_uint64 frameIndex) -{ - if (pMP3 == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_MP3) - { - ma_bool32 mp3Result; - - mp3Result = ma_dr_mp3_seek_to_pcm_frame(&pMP3->dr, frameIndex); - if (mp3Result != MA_TRUE) { - return MA_ERROR; - } - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)frameIndex; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_get_data_format(ma_mp3* pMP3, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* Defaults for safety. */ - if (pFormat != NULL) { - *pFormat = ma_format_unknown; - } - if (pChannels != NULL) { - *pChannels = 0; - } - if (pSampleRate != NULL) { - *pSampleRate = 0; - } - if (pChannelMap != NULL) { - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); - } - - if (pMP3 == NULL) { - return MA_INVALID_OPERATION; - } - - if (pFormat != NULL) { - *pFormat = pMP3->format; - } - - #if !defined(MA_NO_MP3) - { - if (pChannels != NULL) { - *pChannels = pMP3->dr.channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pMP3->dr.sampleRate; - } - - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pMP3->dr.channels); - } - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_get_cursor_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pMP3 == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_MP3) - { - *pCursor = pMP3->dr.currentPCMFrame; - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_mp3_get_length_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; /* Safety. */ - - if (pMP3 == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_MP3) - { - *pLength = ma_dr_mp3_get_pcm_frame_count(&pMP3->dr); - - return MA_SUCCESS; - } - #else - { - /* mp3 is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - - -static ma_result ma_decoding_backend_init__mp3(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_mp3* pMP3; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks); - if (pMP3 == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_mp3_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pMP3); - if (result != MA_SUCCESS) { - ma_free(pMP3, pAllocationCallbacks); - return result; - } - - *ppBackend = pMP3; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file__mp3(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_mp3* pMP3; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks); - if (pMP3 == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_mp3_init_file(pFilePath, pConfig, pAllocationCallbacks, pMP3); - if (result != MA_SUCCESS) { - ma_free(pMP3, pAllocationCallbacks); - return result; - } - - *ppBackend = pMP3; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file_w__mp3(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_mp3* pMP3; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks); - if (pMP3 == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_mp3_init_file_w(pFilePath, pConfig, pAllocationCallbacks, pMP3); - if (result != MA_SUCCESS) { - ma_free(pMP3, pAllocationCallbacks); - return result; - } - - *ppBackend = pMP3; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_memory__mp3(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_mp3* pMP3; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks); - if (pMP3 == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_mp3_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pMP3); - if (result != MA_SUCCESS) { - ma_free(pMP3, pAllocationCallbacks); - return result; - } - - *ppBackend = pMP3; - - return MA_SUCCESS; -} - -static void ma_decoding_backend_uninit__mp3(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_mp3* pMP3 = (ma_mp3*)pBackend; - - (void)pUserData; - - ma_mp3_uninit(pMP3, pAllocationCallbacks); - ma_free(pMP3, pAllocationCallbacks); -} - -static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_mp3 = -{ - ma_decoding_backend_init__mp3, - ma_decoding_backend_init_file__mp3, - ma_decoding_backend_init_file_w__mp3, - ma_decoding_backend_init_memory__mp3, - ma_decoding_backend_uninit__mp3 -}; - static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - return ma_decoder_init_from_vtable__internal(&g_ma_decoding_backend_vtable_mp3, NULL, pConfig, pDecoder); -} + drmp3* pMP3; + drmp3_allocation_callbacks allocationCallbacks; -static ma_result ma_decoder_init_mp3_from_file__internal(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file__internal(&g_ma_decoding_backend_vtable_mp3, NULL, pFilePath, pConfig, pDecoder); -} + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDecoder != NULL); -static ma_result ma_decoder_init_mp3_from_file_w__internal(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file_w__internal(&g_ma_decoding_backend_vtable_mp3, NULL, pFilePath, pConfig, pDecoder); -} + (void)pConfig; -static ma_result ma_decoder_init_mp3_from_memory__internal(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_memory__internal(&g_ma_decoding_backend_vtable_mp3, NULL, pData, dataSize, pConfig, pDecoder); + pMP3 = (drmp3*)ma__malloc_from_callbacks(sizeof(*pMP3), &pDecoder->allocationCallbacks); + if (pMP3 == NULL) { + return MA_OUT_OF_MEMORY; + } + + allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData; + allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc; + allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc; + allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree; + + /* + Try opening the decoder first. We always use whatever dr_mp3 reports for channel count and sample rate. The format is determined by + the presence of DR_MP3_FLOAT_OUTPUT. + */ + if (!drmp3_init(pMP3, ma_decoder_internal_on_read__mp3, ma_decoder_internal_on_seek__mp3, pDecoder, &allocationCallbacks)) { + ma__free_from_callbacks(pMP3, &pDecoder->allocationCallbacks); + return MA_ERROR; + } + + /* If we get here it means we successfully initialized the MP3 decoder. We can now initialize the rest of the ma_decoder. */ + pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__mp3; + pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__mp3; + pDecoder->onUninit = ma_decoder_internal_on_uninit__mp3; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__mp3; + pDecoder->pInternalDecoder = pMP3; + + /* Internal format. */ +#if defined(DR_MP3_FLOAT_OUTPUT) + pDecoder->internalFormat = ma_format_f32; +#else + pDecoder->internalFormat = ma_format_s16; +#endif + pDecoder->internalChannels = pMP3->channels; + pDecoder->internalSampleRate = pMP3->sampleRate; + ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->internalChannels, pDecoder->internalChannelMap); + + return MA_SUCCESS; } -#endif /* ma_dr_mp3_h */ +#endif /* dr_mp3_h */ /* Vorbis */ #ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H @@ -63584,830 +45951,437 @@ static ma_result ma_decoder_init_mp3_from_memory__internal(const void* pData, si typedef struct { - ma_data_source_base ds; - ma_read_proc onRead; - ma_seek_proc onSeek; - ma_tell_proc onTell; - void* pReadSeekTellUserData; - ma_allocation_callbacks allocationCallbacks; /* Store the allocation callbacks within the structure because we may need to dynamically expand a buffer in ma_stbvorbis_read_pcm_frames() when using push mode. */ - ma_format format; /* Only f32 is allowed with stb_vorbis. */ - ma_uint32 channels; - ma_uint32 sampleRate; - ma_uint64 cursor; -#if !defined(MA_NO_VORBIS) - stb_vorbis* stb; - ma_bool32 usingPushMode; - struct - { - ma_uint8* pData; - size_t dataSize; - size_t dataCapacity; - size_t audioStartOffsetInBytes; - ma_uint32 framesConsumed; /* The number of frames consumed in ppPacketData. */ - ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */ - float** ppPacketData; - } push; -#endif -} ma_stbvorbis; + stb_vorbis* pInternalVorbis; + ma_uint8* pData; + size_t dataSize; + size_t dataCapacity; + ma_uint32 framesConsumed; /* The number of frames consumed in ppPacketData. */ + ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */ + float** ppPacketData; +} ma_vorbis_decoder; -MA_API ma_result ma_stbvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis); -MA_API ma_result ma_stbvorbis_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis); -MA_API ma_result ma_stbvorbis_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis); -MA_API void ma_stbvorbis_uninit(ma_stbvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_stbvorbis_seek_to_pcm_frame(ma_stbvorbis* pVorbis, ma_uint64 frameIndex); -MA_API ma_result ma_stbvorbis_get_data_format(ma_stbvorbis* pVorbis, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_stbvorbis_get_cursor_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pCursor); -MA_API ma_result ma_stbvorbis_get_length_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pLength); - - -static ma_result ma_stbvorbis_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +static ma_uint64 ma_vorbis_decoder_read_pcm_frames(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) { - return ma_stbvorbis_read_pcm_frames((ma_stbvorbis*)pDataSource, pFramesOut, frameCount, pFramesRead); -} + float* pFramesOutF; + ma_uint64 totalFramesRead; -static ma_result ma_stbvorbis_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) -{ - return ma_stbvorbis_seek_to_pcm_frame((ma_stbvorbis*)pDataSource, frameIndex); -} + MA_ASSERT(pVorbis != NULL); + MA_ASSERT(pDecoder != NULL); -static ma_result ma_stbvorbis_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - return ma_stbvorbis_get_data_format((ma_stbvorbis*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} + pFramesOutF = (float*)pFramesOut; -static ma_result ma_stbvorbis_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_stbvorbis_get_cursor_in_pcm_frames((ma_stbvorbis*)pDataSource, pCursor); -} + totalFramesRead = 0; + while (frameCount > 0) { + /* Read from the in-memory buffer first. */ + ma_uint32 framesToReadFromCache = (ma_uint32)ma_min(pVorbis->framesRemaining, frameCount); /* Safe cast because pVorbis->framesRemaining is 32-bit. */ -static ma_result ma_stbvorbis_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_stbvorbis_get_length_in_pcm_frames((ma_stbvorbis*)pDataSource, pLength); -} + if (pFramesOut != NULL) { + ma_uint64 iFrame; + for (iFrame = 0; iFrame < framesToReadFromCache; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pDecoder->internalChannels; ++iChannel) { + pFramesOutF[iChannel] = pVorbis->ppPacketData[iChannel][pVorbis->framesConsumed+iFrame]; + } + pFramesOutF += pDecoder->internalChannels; + } + } -static ma_data_source_vtable g_ma_stbvorbis_ds_vtable = -{ - ma_stbvorbis_ds_read, - ma_stbvorbis_ds_seek, - ma_stbvorbis_ds_get_data_format, - ma_stbvorbis_ds_get_cursor, - ma_stbvorbis_ds_get_length, - NULL, /* onSetLooping */ - 0 -}; + pVorbis->framesConsumed += framesToReadFromCache; + pVorbis->framesRemaining -= framesToReadFromCache; + frameCount -= framesToReadFromCache; + totalFramesRead += framesToReadFromCache; + if (frameCount == 0) { + break; + } -static ma_result ma_stbvorbis_init_internal(const ma_decoding_backend_config* pConfig, ma_stbvorbis* pVorbis) -{ - ma_result result; - ma_data_source_config dataSourceConfig; + MA_ASSERT(pVorbis->framesRemaining == 0); - (void)pConfig; + /* We've run out of cached frames, so decode the next packet and continue iteration. */ + do + { + int samplesRead; + int consumedDataSize; - if (pVorbis == NULL) { - return MA_INVALID_ARGS; + if (pVorbis->dataSize > INT_MAX) { + break; /* Too big. */ + } + + samplesRead = 0; + consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->pInternalVorbis, pVorbis->pData, (int)pVorbis->dataSize, NULL, (float***)&pVorbis->ppPacketData, &samplesRead); + if (consumedDataSize != 0) { + size_t leftoverDataSize = (pVorbis->dataSize - (size_t)consumedDataSize); + size_t i; + for (i = 0; i < leftoverDataSize; ++i) { + pVorbis->pData[i] = pVorbis->pData[i + consumedDataSize]; + } + + pVorbis->dataSize = leftoverDataSize; + pVorbis->framesConsumed = 0; + pVorbis->framesRemaining = samplesRead; + break; + } else { + /* Need more data. If there's any room in the existing buffer allocation fill that first. Otherwise expand. */ + size_t bytesRead; + if (pVorbis->dataCapacity == pVorbis->dataSize) { + /* No room. Expand. */ + size_t oldCap = pVorbis->dataCapacity; + size_t newCap = pVorbis->dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE; + ma_uint8* pNewData; + + pNewData = (ma_uint8*)ma__realloc_from_callbacks(pVorbis->pData, newCap, oldCap, &pDecoder->allocationCallbacks); + if (pNewData == NULL) { + return totalFramesRead; /* Out of memory. */ + } + + pVorbis->pData = pNewData; + pVorbis->dataCapacity = newCap; + } + + /* Fill in a chunk. */ + bytesRead = ma_decoder_read_bytes(pDecoder, pVorbis->pData + pVorbis->dataSize, (pVorbis->dataCapacity - pVorbis->dataSize)); + if (bytesRead == 0) { + return totalFramesRead; /* Error reading more data. */ + } + + pVorbis->dataSize += bytesRead; + } + } while (MA_TRUE); } - MA_ZERO_OBJECT(pVorbis); - pVorbis->format = ma_format_f32; /* Only supporting f32. */ - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_stbvorbis_ds_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pVorbis->ds); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the base data source. */ - } - - return MA_SUCCESS; + return totalFramesRead; } -#if !defined(MA_NO_VORBIS) -static ma_result ma_stbvorbis_post_init(ma_stbvorbis* pVorbis) +static ma_result ma_vorbis_decoder_seek_to_pcm_frame(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, ma_uint64 frameIndex) { - stb_vorbis_info info; + float buffer[4096]; MA_ASSERT(pVorbis != NULL); + MA_ASSERT(pDecoder != NULL); - info = stb_vorbis_get_info(pVorbis->stb); + /* + This is terribly inefficient because stb_vorbis does not have a good seeking solution with it's push API. Currently this just performs + a full decode right from the start of the stream. Later on I'll need to write a layer that goes through all of the Ogg pages until we + find the one containing the sample we need. Then we know exactly where to seek for stb_vorbis. - pVorbis->channels = info.channels; - pVorbis->sampleRate = info.sample_rate; + TODO: Use seeking logic documented for stb_vorbis_flush_pushdata(). + */ + if (!ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start)) { + return MA_ERROR; + } + + stb_vorbis_flush_pushdata(pVorbis->pInternalVorbis); + pVorbis->framesConsumed = 0; + pVorbis->framesRemaining = 0; + pVorbis->dataSize = 0; + + while (frameIndex > 0) { + ma_uint32 framesRead; + ma_uint32 framesToRead = ma_countof(buffer)/pDecoder->internalChannels; + if (framesToRead > frameIndex) { + framesToRead = (ma_uint32)frameIndex; + } + + framesRead = (ma_uint32)ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, buffer, framesToRead); + if (framesRead == 0) { + return MA_ERROR; + } + + frameIndex -= framesRead; + } return MA_SUCCESS; } -static ma_result ma_stbvorbis_init_internal_decoder_push(ma_stbvorbis* pVorbis) + +static ma_result ma_decoder_internal_on_seek_to_pcm_frame__vorbis(ma_decoder* pDecoder, ma_uint64 frameIndex) { - ma_result result; - stb_vorbis* stb; + ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder; + MA_ASSERT(pVorbis != NULL); + + return ma_vorbis_decoder_seek_to_pcm_frame(pVorbis, pDecoder, frameIndex); +} + +static ma_result ma_decoder_internal_on_uninit__vorbis(ma_decoder* pDecoder) +{ + ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder; + MA_ASSERT(pVorbis != NULL); + + stb_vorbis_close(pVorbis->pInternalVorbis); + ma__free_from_callbacks(pVorbis->pData, &pDecoder->allocationCallbacks); + ma__free_from_callbacks(pVorbis, &pDecoder->allocationCallbacks); + + return MA_SUCCESS; +} + +static ma_uint64 ma_decoder_internal_on_read_pcm_frames__vorbis(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) +{ + ma_vorbis_decoder* pVorbis; + + MA_ASSERT(pDecoder != NULL); + MA_ASSERT(pFramesOut != NULL); + MA_ASSERT(pDecoder->internalFormat == ma_format_f32); + + pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder; + MA_ASSERT(pVorbis != NULL); + + return ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, pFramesOut, frameCount); +} + +static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__vorbis(ma_decoder* pDecoder) +{ + /* No good way to do this with Vorbis. */ + (void)pDecoder; + return 0; +} + +static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + stb_vorbis* pInternalVorbis = NULL; size_t dataSize = 0; size_t dataCapacity = 0; - ma_uint8* pData = NULL; /* <-- Must be initialized to NULL. */ + ma_uint8* pData = NULL; + stb_vorbis_info vorbisInfo; + size_t vorbisDataSize; + ma_vorbis_decoder* pVorbis; - for (;;) { - int vorbisError; - int consumedDataSize; /* <-- Fill by stb_vorbis_open_pushdata(). */ - size_t bytesRead; + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDecoder != NULL); + + /* We grow the buffer in chunks. */ + do + { + /* Allocate memory for a new chunk. */ ma_uint8* pNewData; + size_t bytesRead; + int vorbisError = 0; + int consumedDataSize = 0; + size_t oldCapacity = dataCapacity; - /* Allocate memory for the new chunk. */ dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE; - pNewData = (ma_uint8*)ma_realloc(pData, dataCapacity, &pVorbis->allocationCallbacks); + pNewData = (ma_uint8*)ma__realloc_from_callbacks(pData, dataCapacity, oldCapacity, &pDecoder->allocationCallbacks); if (pNewData == NULL) { - ma_free(pData, &pVorbis->allocationCallbacks); + ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks); return MA_OUT_OF_MEMORY; } pData = pNewData; - /* Read in the next chunk. */ - result = pVorbis->onRead(pVorbis->pReadSeekTellUserData, ma_offset_ptr(pData, dataSize), (dataCapacity - dataSize), &bytesRead); + /* Fill in a chunk. */ + bytesRead = ma_decoder_read_bytes(pDecoder, pData + dataSize, (dataCapacity - dataSize)); + if (bytesRead == 0) { + return MA_ERROR; + } + dataSize += bytesRead; - - if (result != MA_SUCCESS) { - ma_free(pData, &pVorbis->allocationCallbacks); - return result; - } - - /* We have a maximum of 31 bits with stb_vorbis. */ if (dataSize > INT_MAX) { - ma_free(pData, &pVorbis->allocationCallbacks); - return MA_TOO_BIG; + return MA_ERROR; /* Too big. */ } - stb = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL); - if (stb != NULL) { + pInternalVorbis = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL); + if (pInternalVorbis != NULL) { /* - Successfully opened the Vorbis decoder. We might have some leftover unprocessed - data so we'll need to move that down to the front. + If we get here it means we were able to open the stb_vorbis decoder. There may be some leftover bytes in our buffer, so + we need to move those bytes down to the front of the buffer since they'll be needed for future decoding. */ - dataSize -= (size_t)consumedDataSize; /* Consume the data. */ - MA_MOVE_MEMORY(pData, ma_offset_ptr(pData, consumedDataSize), dataSize); + size_t leftoverDataSize = (dataSize - (size_t)consumedDataSize); + size_t i; + for (i = 0; i < leftoverDataSize; ++i) { + pData[i] = pData[i + consumedDataSize]; + } - /* - We need to track the start point so we can seek back to the start of the audio - data when seeking. - */ - pVorbis->push.audioStartOffsetInBytes = consumedDataSize; - - break; + dataSize = leftoverDataSize; + break; /* Success. */ } else { - /* Failed to open the decoder. */ if (vorbisError == VORBIS_need_more_data) { continue; } else { - ma_free(pData, &pVorbis->allocationCallbacks); return MA_ERROR; /* Failed to open the stb_vorbis decoder. */ } } + } while (MA_TRUE); + + + /* If we get here it means we successfully opened the Vorbis decoder. */ + vorbisInfo = stb_vorbis_get_info(pInternalVorbis); + + /* Don't allow more than MA_MAX_CHANNELS channels. */ + if (vorbisInfo.channels > MA_MAX_CHANNELS) { + stb_vorbis_close(pInternalVorbis); + ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks); + return MA_ERROR; /* Too many channels. */ } - MA_ASSERT(stb != NULL); - pVorbis->stb = stb; - pVorbis->push.pData = pData; - pVorbis->push.dataSize = dataSize; - pVorbis->push.dataCapacity = dataCapacity; - - return MA_SUCCESS; -} -#endif - -MA_API ma_result ma_stbvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis) -{ - ma_result result; - - result = ma_stbvorbis_init_internal(pConfig, pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - if (onRead == NULL || onSeek == NULL) { - return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */ - } - - pVorbis->onRead = onRead; - pVorbis->onSeek = onSeek; - pVorbis->onTell = onTell; - pVorbis->pReadSeekTellUserData = pReadSeekTellUserData; - ma_allocation_callbacks_init_copy(&pVorbis->allocationCallbacks, pAllocationCallbacks); - - #if !defined(MA_NO_VORBIS) - { - /* - stb_vorbis lacks a callback based API for its pulling API which means we're stuck with the - pushing API. In order for us to be able to successfully initialize the decoder we need to - supply it with enough data. We need to keep loading data until we have enough. - */ - result = ma_stbvorbis_init_internal_decoder_push(pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - pVorbis->usingPushMode = MA_TRUE; - - result = ma_stbvorbis_post_init(pVorbis); - if (result != MA_SUCCESS) { - stb_vorbis_close(pVorbis->stb); - ma_free(pVorbis->push.pData, pAllocationCallbacks); - return result; - } - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. */ - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_stbvorbis_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis) -{ - ma_result result; - - result = ma_stbvorbis_init_internal(pConfig, pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_VORBIS) - { - (void)pAllocationCallbacks; /* Don't know how to make use of this with stb_vorbis. */ - - /* We can use stb_vorbis' pull mode for file based streams. */ - pVorbis->stb = stb_vorbis_open_filename(pFilePath, NULL, NULL); - if (pVorbis->stb == NULL) { - return MA_INVALID_FILE; - } - - pVorbis->usingPushMode = MA_FALSE; - - result = ma_stbvorbis_post_init(pVorbis); - if (result != MA_SUCCESS) { - stb_vorbis_close(pVorbis->stb); - return result; - } - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. */ - (void)pFilePath; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_stbvorbis_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis) -{ - ma_result result; - - result = ma_stbvorbis_init_internal(pConfig, pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_VORBIS) - { - (void)pAllocationCallbacks; - - /* stb_vorbis uses an int as its size specifier, restricting it to 32-bit even on 64-bit systems. *sigh*. */ - if (dataSize > INT_MAX) { - return MA_TOO_BIG; - } - - pVorbis->stb = stb_vorbis_open_memory((const unsigned char*)pData, (int)dataSize, NULL, NULL); - if (pVorbis->stb == NULL) { - return MA_INVALID_FILE; - } - - pVorbis->usingPushMode = MA_FALSE; - - result = ma_stbvorbis_post_init(pVorbis); - if (result != MA_SUCCESS) { - stb_vorbis_close(pVorbis->stb); - return result; - } - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. */ - (void)pData; - (void)dataSize; - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API void ma_stbvorbis_uninit(ma_stbvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pVorbis == NULL) { - return; - } - - #if !defined(MA_NO_VORBIS) - { - stb_vorbis_close(pVorbis->stb); - - /* We'll have to clear some memory if we're using push mode. */ - if (pVorbis->usingPushMode) { - ma_free(pVorbis->push.pData, pAllocationCallbacks); - } - } - #else - { - /* vorbis is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - } - #endif - - ma_data_source_uninit(&pVorbis->ds); -} - -MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_VORBIS) - { - /* We always use floating point format. */ - ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */ - ma_uint64 totalFramesRead = 0; - ma_format format; - ma_uint32 channels; - - ma_stbvorbis_get_data_format(pVorbis, &format, &channels, NULL, NULL, 0); - - if (format == ma_format_f32) { - /* We read differently depending on whether or not we're using push mode. */ - if (pVorbis->usingPushMode) { - /* Push mode. This is the complex case. */ - float* pFramesOutF32 = (float*)pFramesOut; - - while (totalFramesRead < frameCount) { - /* The first thing to do is read from any already-cached frames. */ - ma_uint32 framesToReadFromCache = (ma_uint32)ma_min(pVorbis->push.framesRemaining, (frameCount - totalFramesRead)); /* Safe cast because pVorbis->framesRemaining is 32-bit. */ - - /* The output pointer can be null in which case we just treat it as a seek. */ - if (pFramesOut != NULL) { - ma_uint64 iFrame; - for (iFrame = 0; iFrame < framesToReadFromCache; iFrame += 1) { - ma_uint32 iChannel; - for (iChannel = 0; iChannel < pVorbis->channels; iChannel += 1) { - pFramesOutF32[iChannel] = pVorbis->push.ppPacketData[iChannel][pVorbis->push.framesConsumed + iFrame]; - } - - pFramesOutF32 += pVorbis->channels; - } - } - - /* Update pointers and counters. */ - pVorbis->push.framesConsumed += framesToReadFromCache; - pVorbis->push.framesRemaining -= framesToReadFromCache; - totalFramesRead += framesToReadFromCache; - - /* Don't bother reading any more frames right now if we've just finished loading. */ - if (totalFramesRead == frameCount) { - break; - } - - MA_ASSERT(pVorbis->push.framesRemaining == 0); - - /* Getting here means we've run out of cached frames. We'll need to load some more. */ - for (;;) { - int samplesRead = 0; - int consumedDataSize; - - /* We need to case dataSize to an int, so make sure we can do it safely. */ - if (pVorbis->push.dataSize > INT_MAX) { - break; /* Too big. */ - } - - consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->stb, pVorbis->push.pData, (int)pVorbis->push.dataSize, NULL, &pVorbis->push.ppPacketData, &samplesRead); - if (consumedDataSize != 0) { - /* Successfully decoded a Vorbis frame. Consume the data. */ - pVorbis->push.dataSize -= (size_t)consumedDataSize; - MA_MOVE_MEMORY(pVorbis->push.pData, ma_offset_ptr(pVorbis->push.pData, consumedDataSize), pVorbis->push.dataSize); - - pVorbis->push.framesConsumed = 0; - pVorbis->push.framesRemaining = samplesRead; - - break; - } else { - /* Not enough data. Read more. */ - size_t bytesRead; - - /* Expand the data buffer if necessary. */ - if (pVorbis->push.dataCapacity == pVorbis->push.dataSize) { - size_t newCap = pVorbis->push.dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE; - ma_uint8* pNewData; - - pNewData = (ma_uint8*)ma_realloc(pVorbis->push.pData, newCap, &pVorbis->allocationCallbacks); - if (pNewData == NULL) { - result = MA_OUT_OF_MEMORY; - break; - } - - pVorbis->push.pData = pNewData; - pVorbis->push.dataCapacity = newCap; - } - - /* We should have enough room to load some data. */ - result = pVorbis->onRead(pVorbis->pReadSeekTellUserData, ma_offset_ptr(pVorbis->push.pData, pVorbis->push.dataSize), (pVorbis->push.dataCapacity - pVorbis->push.dataSize), &bytesRead); - pVorbis->push.dataSize += bytesRead; - - if (result != MA_SUCCESS) { - break; /* Failed to read any data. Get out. */ - } - } - } - - /* If we don't have a success code at this point it means we've encountered an error or the end of the file has been reached (probably the latter). */ - if (result != MA_SUCCESS) { - break; - } - } - } else { - /* Pull mode. This is the simple case, but we still need to run in a loop because stb_vorbis loves using 32-bit instead of 64-bit. */ - while (totalFramesRead < frameCount) { - ma_uint64 framesRemaining = (frameCount - totalFramesRead); - int framesRead; - - if (framesRemaining > INT_MAX) { - framesRemaining = INT_MAX; - } - - framesRead = stb_vorbis_get_samples_float_interleaved(pVorbis->stb, channels, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)framesRemaining * channels); /* Safe cast. */ - totalFramesRead += framesRead; - - if (framesRead < (int)framesRemaining) { - break; /* Nothing left to read. Get out. */ - } - } - } - } else { - result = MA_INVALID_ARGS; - } - - pVorbis->cursor += totalFramesRead; - - if (totalFramesRead == 0) { - result = MA_AT_END; - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - if (result == MA_SUCCESS && totalFramesRead == 0) { - result = MA_AT_END; - } - - return result; - } - #else - { - /* vorbis is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)pFramesOut; - (void)frameCount; - (void)pFramesRead; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_stbvorbis_seek_to_pcm_frame(ma_stbvorbis* pVorbis, ma_uint64 frameIndex) -{ - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_VORBIS) - { - /* Different seeking methods depending on whether or not we're using push mode. */ - if (pVorbis->usingPushMode) { - /* Push mode. This is the complex case. */ - ma_result result; - float buffer[4096]; - - /* If we're seeking backwards, we need to seek back to the start and then brute-force forward. */ - if (frameIndex < pVorbis->cursor) { - if (frameIndex > 0x7FFFFFFF) { - return MA_INVALID_ARGS; /* Trying to seek beyond the 32-bit maximum of stb_vorbis. */ - } - - /* - This is wildly inefficient due to me having trouble getting sample exact seeking working - robustly with stb_vorbis_flush_pushdata(). The only way I can think to make this work - perfectly is to reinitialize the decoder. Note that we only enter this path when seeking - backwards. This will hopefully be removed once we get our own Vorbis decoder implemented. - */ - stb_vorbis_close(pVorbis->stb); - ma_free(pVorbis->push.pData, &pVorbis->allocationCallbacks); - - MA_ZERO_OBJECT(&pVorbis->push); - - /* Seek to the start of the file. */ - result = pVorbis->onSeek(pVorbis->pReadSeekTellUserData, 0, ma_seek_origin_start); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_stbvorbis_init_internal_decoder_push(pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - /* At this point we should be sitting on the first frame. */ - pVorbis->cursor = 0; - } - - /* We're just brute-forcing this for now. */ - while (pVorbis->cursor < frameIndex) { - ma_uint64 framesRead; - ma_uint64 framesToRead = ma_countof(buffer)/pVorbis->channels; - if (framesToRead > (frameIndex - pVorbis->cursor)) { - framesToRead = (frameIndex - pVorbis->cursor); - } - - result = ma_stbvorbis_read_pcm_frames(pVorbis, buffer, framesToRead, &framesRead); - if (result != MA_SUCCESS) { - return result; - } - } - } else { - /* Pull mode. This is the simple case. */ - int vorbisResult; - - if (frameIndex > UINT_MAX) { - return MA_INVALID_ARGS; /* Trying to seek beyond the 32-bit maximum of stb_vorbis. */ - } - - vorbisResult = stb_vorbis_seek(pVorbis->stb, (unsigned int)frameIndex); /* Safe cast. */ - if (vorbisResult == 0) { - return MA_ERROR; /* See failed. */ - } - - pVorbis->cursor = frameIndex; - } - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - - (void)frameIndex; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_stbvorbis_get_data_format(ma_stbvorbis* pVorbis, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* Defaults for safety. */ - if (pFormat != NULL) { - *pFormat = ma_format_unknown; - } - if (pChannels != NULL) { - *pChannels = 0; - } - if (pSampleRate != NULL) { - *pSampleRate = 0; - } - if (pChannelMap != NULL) { - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); - } - - if (pVorbis == NULL) { - return MA_INVALID_OPERATION; - } - - if (pFormat != NULL) { - *pFormat = pVorbis->format; - } - - #if !defined(MA_NO_VORBIS) - { - if (pChannels != NULL) { - *pChannels = pVorbis->channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pVorbis->sampleRate; - } - - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_vorbis, pChannelMap, channelMapCap, pVorbis->channels); - } - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_stbvorbis_get_cursor_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_VORBIS) - { - *pCursor = pVorbis->cursor; - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_stbvorbis_get_length_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; /* Safety. */ - - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_VORBIS) - { - if (pVorbis->usingPushMode) { - *pLength = 0; /* I don't know of a good way to determine this reliably with stb_vorbis and push mode. */ - } else { - *pLength = stb_vorbis_stream_length_in_samples(pVorbis->stb); - } - - return MA_SUCCESS; - } - #else - { - /* vorbis is disabled. Should never hit this since initialization would have failed. */ - MA_ASSERT(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - - -static ma_result ma_decoding_backend_init__stbvorbis(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_stbvorbis* pVorbis; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pVorbis = (ma_stbvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); + vorbisDataSize = sizeof(ma_vorbis_decoder) + sizeof(float)*vorbisInfo.max_frame_size; + pVorbis = (ma_vorbis_decoder*)ma__malloc_from_callbacks(vorbisDataSize, &pDecoder->allocationCallbacks); if (pVorbis == NULL) { + stb_vorbis_close(pInternalVorbis); + ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks); return MA_OUT_OF_MEMORY; } - result = ma_stbvorbis_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } + MA_ZERO_MEMORY(pVorbis, vorbisDataSize); + pVorbis->pInternalVorbis = pInternalVorbis; + pVorbis->pData = pData; + pVorbis->dataSize = dataSize; + pVorbis->dataCapacity = dataCapacity; - *ppBackend = pVorbis; + pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__vorbis; + pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__vorbis; + pDecoder->onUninit = ma_decoder_internal_on_uninit__vorbis; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__vorbis; + pDecoder->pInternalDecoder = pVorbis; + + /* The internal format is always f32. */ + pDecoder->internalFormat = ma_format_f32; + pDecoder->internalChannels = vorbisInfo.channels; + pDecoder->internalSampleRate = vorbisInfo.sample_rate; + ma_get_standard_channel_map(ma_standard_channel_map_vorbis, pDecoder->internalChannels, pDecoder->internalChannelMap); return MA_SUCCESS; } - -static ma_result ma_decoding_backend_init_file__stbvorbis(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_stbvorbis* pVorbis; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pVorbis = (ma_stbvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); - if (pVorbis == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_stbvorbis_init_file(pFilePath, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } - - *ppBackend = pVorbis; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_memory__stbvorbis(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_stbvorbis* pVorbis; - - (void)pUserData; /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */ - - /* For now we're just allocating the decoder backend on the heap. */ - pVorbis = (ma_stbvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); - if (pVorbis == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_stbvorbis_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } - - *ppBackend = pVorbis; - - return MA_SUCCESS; -} - -static void ma_decoding_backend_uninit__stbvorbis(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_stbvorbis* pVorbis = (ma_stbvorbis*)pBackend; - - (void)pUserData; - - ma_stbvorbis_uninit(pVorbis, pAllocationCallbacks); - ma_free(pVorbis, pAllocationCallbacks); -} - -static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_stbvorbis = -{ - ma_decoding_backend_init__stbvorbis, - ma_decoding_backend_init_file__stbvorbis, - NULL, /* onInitFileW() */ - ma_decoding_backend_init_memory__stbvorbis, - ma_decoding_backend_uninit__stbvorbis -}; - -static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_vtable__internal(&g_ma_decoding_backend_vtable_stbvorbis, NULL, pConfig, pDecoder); -} - -static ma_result ma_decoder_init_vorbis_from_file__internal(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file__internal(&g_ma_decoding_backend_vtable_stbvorbis, NULL, pFilePath, pConfig, pDecoder); -} - -static ma_result ma_decoder_init_vorbis_from_file_w__internal(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_file_w__internal(&g_ma_decoding_backend_vtable_stbvorbis, NULL, pFilePath, pConfig, pDecoder); -} - -static ma_result ma_decoder_init_vorbis_from_memory__internal(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_from_memory__internal(&g_ma_decoding_backend_vtable_stbvorbis, NULL, pData, dataSize, pConfig, pDecoder); -} #endif /* STB_VORBIS_INCLUDE_STB_VORBIS_H */ +/* Raw */ +static ma_uint64 ma_decoder_internal_on_read_pcm_frames__raw(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint32 bpf; + ma_uint64 totalFramesRead; + void* pRunningFramesOut; + MA_ASSERT(pDecoder != NULL); + + /* For raw decoding we just read directly from the decoder's callbacks. */ + bpf = ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels); + + totalFramesRead = 0; + pRunningFramesOut = pFramesOut; + + while (totalFramesRead < frameCount) { + ma_uint64 framesReadThisIteration; + ma_uint64 framesToReadThisIteration = (frameCount - totalFramesRead); + if (framesToReadThisIteration > 0x7FFFFFFF/bpf) { + framesToReadThisIteration = 0x7FFFFFFF/bpf; + } + + if (pFramesOut != NULL) { + framesReadThisIteration = ma_decoder_read_bytes(pDecoder, pRunningFramesOut, (size_t)framesToReadThisIteration * bpf) / bpf; /* Safe cast to size_t. */ + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIteration * bpf); + } else { + /* We'll first try seeking. If this fails it means the end was reached and we'll to do a read-and-discard slow path to get the exact amount. */ + if (ma_decoder_seek_bytes(pDecoder, (int)framesToReadThisIteration, ma_seek_origin_current)) { + framesReadThisIteration = framesToReadThisIteration; + } else { + /* Slow path. Need to fall back to a read-and-discard. This is required so we can get the exact number of remaining. */ + ma_uint8 buffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 bufferCap = sizeof(buffer) / bpf; + + framesReadThisIteration = 0; + while (framesReadThisIteration < framesToReadThisIteration) { + ma_uint64 framesReadNow; + ma_uint64 framesToReadNow = framesToReadThisIteration - framesReadThisIteration; + if (framesToReadNow > bufferCap) { + framesToReadNow = bufferCap; + } + + framesReadNow = ma_decoder_read_bytes(pDecoder, buffer, (size_t)(framesToReadNow * bpf)) / bpf; /* Safe cast. */ + framesReadThisIteration += framesReadNow; + + if (framesReadNow < framesToReadNow) { + break; /* The end has been reached. */ + } + } + } + } + + totalFramesRead += framesReadThisIteration; + + if (framesReadThisIteration < framesToReadThisIteration) { + break; /* Done. */ + } + } + + return totalFramesRead; +} + +static ma_result ma_decoder_internal_on_seek_to_pcm_frame__raw(ma_decoder* pDecoder, ma_uint64 frameIndex) +{ + ma_bool32 result = MA_FALSE; + ma_uint64 totalBytesToSeek; + + MA_ASSERT(pDecoder != NULL); + + if (pDecoder->onSeek == NULL) { + return MA_ERROR; + } + + /* The callback uses a 32 bit integer whereas we use a 64 bit unsigned integer. We just need to continuously seek until we're at the correct position. */ + totalBytesToSeek = frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels); + if (totalBytesToSeek < 0x7FFFFFFF) { + /* Simple case. */ + result = ma_decoder_seek_bytes(pDecoder, (int)(frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels)), ma_seek_origin_start); + } else { + /* Complex case. Start by doing a seek relative to the start. Then keep looping using offset seeking. */ + result = ma_decoder_seek_bytes(pDecoder, 0x7FFFFFFF, ma_seek_origin_start); + if (result == MA_TRUE) { + totalBytesToSeek -= 0x7FFFFFFF; + + while (totalBytesToSeek > 0) { + ma_uint64 bytesToSeekThisIteration = totalBytesToSeek; + if (bytesToSeekThisIteration > 0x7FFFFFFF) { + bytesToSeekThisIteration = 0x7FFFFFFF; + } + + result = ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_current); + if (result != MA_TRUE) { + break; + } + + totalBytesToSeek -= bytesToSeekThisIteration; + } + } + } + + if (result) { + return MA_SUCCESS; + } else { + return MA_ERROR; + } +} + +static ma_result ma_decoder_internal_on_uninit__raw(ma_decoder* pDecoder) +{ + (void)pDecoder; + return MA_SUCCESS; +} + +static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__raw(ma_decoder* pDecoder) +{ + (void)pDecoder; + return 0; +} + +static ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) +{ + MA_ASSERT(pConfigIn != NULL); + MA_ASSERT(pConfigOut != NULL); + MA_ASSERT(pDecoder != NULL); + + (void)pConfigOut; + + pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__raw; + pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__raw; + pDecoder->onUninit = ma_decoder_internal_on_uninit__raw; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__raw; + + /* Internal format. */ + pDecoder->internalFormat = pConfigIn->format; + pDecoder->internalChannels = pConfigIn->channels; + pDecoder->internalSampleRate = pConfigIn->sampleRate; + ma_channel_map_copy(pDecoder->internalChannelMap, pConfigIn->channelMap, pConfigIn->channels); + + return MA_SUCCESS; +} static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { @@ -64423,7 +46397,17 @@ static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* static ma_result ma_decoder__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - return ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount, pFramesRead); + ma_uint64 framesRead = ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount); + + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + if (framesRead < frameCount) { + return MA_AT_END; + } + + return MA_SUCCESS; } static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -64431,36 +46415,39 @@ static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma return ma_decoder_seek_to_pcm_frame((ma_decoder*)pDataSource, frameIndex); } -static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) { - return ma_decoder_get_data_format((ma_decoder*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); + ma_decoder* pDecoder = (ma_decoder*)pDataSource; + + *pFormat = pDecoder->outputFormat; + *pChannels = pDecoder->outputChannels; + *pSampleRate = pDecoder->outputSampleRate; + + return MA_SUCCESS; } -static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) +static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pLength) { - return ma_decoder_get_cursor_in_pcm_frames((ma_decoder*)pDataSource, pCursor); + ma_decoder* pDecoder = (ma_decoder*)pDataSource; + + return ma_decoder_get_cursor_in_pcm_frames(pDecoder, pLength); } static ma_result ma_decoder__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength) { - return ma_decoder_get_length_in_pcm_frames((ma_decoder*)pDataSource, pLength); + ma_decoder* pDecoder = (ma_decoder*)pDataSource; + + *pLength = ma_decoder_get_length_in_pcm_frames(pDecoder); + if (*pLength == 0) { + return MA_NOT_IMPLEMENTED; + } + + return MA_SUCCESS; } -static ma_data_source_vtable g_ma_decoder_data_source_vtable = -{ - ma_decoder__data_source_on_read, - ma_decoder__data_source_on_seek, - ma_decoder__data_source_on_get_data_format, - ma_decoder__data_source_on_get_cursor, - ma_decoder__data_source_on_get_length, - NULL, /* onSetLooping */ - 0 -}; - -static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, ma_decoder_tell_proc onTell, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result; - ma_data_source_config dataSourceConfig; MA_ASSERT(pConfig != NULL); @@ -64470,22 +46457,22 @@ static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_see MA_ZERO_OBJECT(pDecoder); - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_decoder_data_source_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pDecoder->ds); - if (result != MA_SUCCESS) { - return result; + if (onRead == NULL || onSeek == NULL) { + return MA_INVALID_ARGS; } + pDecoder->ds.onRead = ma_decoder__data_source_on_read; + pDecoder->ds.onSeek = ma_decoder__data_source_on_seek; + pDecoder->ds.onGetDataFormat = ma_decoder__data_source_on_get_data_format; + pDecoder->ds.onGetCursor = ma_decoder__data_source_on_get_cursor; + pDecoder->ds.onGetLength = ma_decoder__data_source_on_get_length; + pDecoder->onRead = onRead; pDecoder->onSeek = onSeek; - pDecoder->onTell = onTell; pDecoder->pUserData = pUserData; result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder); if (result != MA_SUCCESS) { - ma_data_source_uninit(&pDecoder->ds); return result; } @@ -64494,9 +46481,16 @@ static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_see static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - ma_result result; + ma_result result = MA_SUCCESS; - result = ma_decoder__init_data_converter(pDecoder, pConfig); + /* Basic validation in case the internal decoder supports different limits to miniaudio. */ + if (pDecoder->internalChannels < MA_MIN_CHANNELS || pDecoder->internalChannels > MA_MAX_CHANNELS) { + result = MA_INVALID_DATA; + } + + if (result == MA_SUCCESS) { + result = ma_decoder__init_data_converter(pDecoder, pConfig); + } /* If we failed post initialization we need to uninitialize the decoder before returning to prevent a memory leak. */ if (result != MA_SUCCESS) { @@ -64507,6 +46501,141 @@ static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decod return result; } +MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_WAV + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_wav__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)onRead; + (void)onSeek; + (void)pUserData; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_FLAC + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_flac__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)onRead; + (void)onSeek; + (void)pUserData; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_MP3 + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_mp3__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)onRead; + (void)onSeek; + (void)pUserData; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_VORBIS + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_vorbis__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)onRead; + (void)onSeek; + (void)pUserData; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) +{ + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfigOut); + + result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +} static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { @@ -64519,92 +46648,43 @@ static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decod (void)onRead; (void)onSeek; (void)pUserData; + (void)pConfig; + (void)pDecoder; + /* We use trial and error to open a decoder. */ - /* If we've specified a specific encoding type, try that first. */ - if (pConfig->encodingFormat != ma_encoding_format_unknown) { - #ifdef MA_HAS_WAV - if (pConfig->encodingFormat == ma_encoding_format_wav) { - result = ma_decoder_init_wav__internal(pConfig, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (pConfig->encodingFormat == ma_encoding_format_flac) { - result = ma_decoder_init_flac__internal(pConfig, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (pConfig->encodingFormat == ma_encoding_format_mp3) { - result = ma_decoder_init_mp3__internal(pConfig, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (pConfig->encodingFormat == ma_encoding_format_vorbis) { - result = ma_decoder_init_vorbis__internal(pConfig, pDecoder); - } - #endif - - /* If we weren't able to initialize the decoder, seek back to the start to give the next attempts a clean start. */ +#ifdef MA_HAS_WAV + if (result != MA_SUCCESS) { + result = ma_decoder_init_wav__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { onSeek(pDecoder, 0, ma_seek_origin_start); } } - +#endif +#ifdef MA_HAS_FLAC if (result != MA_SUCCESS) { - /* Getting here means we couldn't load a specific decoding backend based on the encoding format. */ - - /* - We use trial and error to open a decoder. We prioritize custom decoders so that if they - implement the same encoding format they take priority over the built-in decoders. - */ + result = ma_decoder_init_flac__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(pConfig, pDecoder); - if (result != MA_SUCCESS) { - onSeek(pDecoder, 0, ma_seek_origin_start); - } + onSeek(pDecoder, 0, ma_seek_origin_start); } - - /* - If we get to this point and we still haven't found a decoder, and the caller has requested a - specific encoding format, there's no hope for it. Abort. - */ - if (pConfig->encodingFormat != ma_encoding_format_unknown) { - return MA_NO_BACKEND; - } - - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS) { - result = ma_decoder_init_wav__internal(pConfig, pDecoder); - if (result != MA_SUCCESS) { - onSeek(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS) { - result = ma_decoder_init_flac__internal(pConfig, pDecoder); - if (result != MA_SUCCESS) { - onSeek(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS) { - result = ma_decoder_init_mp3__internal(pConfig, pDecoder); - if (result != MA_SUCCESS) { - onSeek(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_VORBIS - if (result != MA_SUCCESS) { - result = ma_decoder_init_vorbis__internal(pConfig, pDecoder); - if (result != MA_SUCCESS) { - onSeek(pDecoder, 0, ma_seek_origin_start); - } - } - #endif } +#endif +#ifdef MA_HAS_MP3 + if (result != MA_SUCCESS) { + result = ma_decoder_init_mp3__internal(pConfig, pDecoder); + if (result != MA_SUCCESS) { + onSeek(pDecoder, 0, ma_seek_origin_start); + } + } +#endif +#ifdef MA_HAS_VORBIS + if (result != MA_SUCCESS) { + result = ma_decoder_init_vorbis__internal(pConfig, pDecoder); + if (result != MA_SUCCESS) { + onSeek(pDecoder, 0, ma_seek_origin_start); + } + } +#endif if (result != MA_SUCCESS) { return result; @@ -64620,7 +46700,7 @@ MA_API ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_pr config = ma_decoder_config_init_copy(pConfig); - result = ma_decoder__preinit(onRead, onSeek, NULL, pUserData, &config, pDecoder); + result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } @@ -64629,93 +46709,54 @@ MA_API ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_pr } -static ma_result ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) +static size_t ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { size_t bytesRemaining; - MA_ASSERT(pDecoder->data.memory.dataSize >= pDecoder->data.memory.currentReadPos); + MA_ASSERT(pDecoder->backend.memory.dataSize >= pDecoder->backend.memory.currentReadPos); - if (pBytesRead != NULL) { - *pBytesRead = 0; - } - - bytesRemaining = pDecoder->data.memory.dataSize - pDecoder->data.memory.currentReadPos; + bytesRemaining = pDecoder->backend.memory.dataSize - pDecoder->backend.memory.currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } - if (bytesRemaining == 0) { - return MA_AT_END; - } - if (bytesToRead > 0) { - MA_COPY_MEMORY(pBufferOut, pDecoder->data.memory.pData + pDecoder->data.memory.currentReadPos, bytesToRead); - pDecoder->data.memory.currentReadPos += bytesToRead; + MA_COPY_MEMORY(pBufferOut, pDecoder->backend.memory.pData + pDecoder->backend.memory.currentReadPos, bytesToRead); + pDecoder->backend.memory.currentReadPos += bytesToRead; } - if (pBytesRead != NULL) { - *pBytesRead = bytesToRead; - } - - return MA_SUCCESS; + return bytesToRead; } -static ma_result ma_decoder__on_seek_memory(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin) +static ma_bool32 ma_decoder__on_seek_memory(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin) { - if (byteOffset > 0 && (ma_uint64)byteOffset > MA_SIZE_MAX) { - return MA_BAD_SEEK; - } - if (origin == ma_seek_origin_current) { if (byteOffset > 0) { - if (pDecoder->data.memory.currentReadPos + byteOffset > pDecoder->data.memory.dataSize) { - byteOffset = (ma_int64)(pDecoder->data.memory.dataSize - pDecoder->data.memory.currentReadPos); /* Trying to seek too far forward. */ + if (pDecoder->backend.memory.currentReadPos + byteOffset > pDecoder->backend.memory.dataSize) { + byteOffset = (int)(pDecoder->backend.memory.dataSize - pDecoder->backend.memory.currentReadPos); /* Trying to seek too far forward. */ } - - pDecoder->data.memory.currentReadPos += (size_t)byteOffset; } else { - if (pDecoder->data.memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(ma_int64)pDecoder->data.memory.currentReadPos; /* Trying to seek too far backwards. */ + if (pDecoder->backend.memory.currentReadPos < (size_t)-byteOffset) { + byteOffset = -(int)pDecoder->backend.memory.currentReadPos; /* Trying to seek too far backwards. */ } - - pDecoder->data.memory.currentReadPos -= (size_t)-byteOffset; } - } else { - if (origin == ma_seek_origin_end) { - if (byteOffset < 0) { - byteOffset = -byteOffset; - } - if (byteOffset > (ma_int64)pDecoder->data.memory.dataSize) { - pDecoder->data.memory.currentReadPos = 0; /* Trying to seek too far back. */ - } else { - pDecoder->data.memory.currentReadPos = pDecoder->data.memory.dataSize - (size_t)byteOffset; - } + /* This will never underflow thanks to the clamps above. */ + pDecoder->backend.memory.currentReadPos += byteOffset; + } else { + if ((ma_uint32)byteOffset <= pDecoder->backend.memory.dataSize) { + pDecoder->backend.memory.currentReadPos = byteOffset; } else { - if ((size_t)byteOffset <= pDecoder->data.memory.dataSize) { - pDecoder->data.memory.currentReadPos = (size_t)byteOffset; - } else { - pDecoder->data.memory.currentReadPos = pDecoder->data.memory.dataSize; /* Trying to seek too far forward. */ - } + pDecoder->backend.memory.currentReadPos = pDecoder->backend.memory.dataSize; /* Trying to seek too far forward. */ } } - return MA_SUCCESS; + return MA_TRUE; } -static ma_result ma_decoder__on_tell_memory(ma_decoder* pDecoder, ma_int64* pCursor) +static ma_result ma_decoder__preinit_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - MA_ASSERT(pDecoder != NULL); - MA_ASSERT(pCursor != NULL); - - *pCursor = (ma_int64)pDecoder->data.memory.currentReadPos; - - return MA_SUCCESS; -} - -static ma_result ma_decoder__preinit_memory_wrapper(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - ma_result result = ma_decoder__preinit(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, ma_decoder__on_tell_memory, NULL, pConfig, pDecoder); + ma_result result = ma_decoder__preinit(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } @@ -64724,9 +46765,9 @@ static ma_result ma_decoder__preinit_memory_wrapper(const void* pData, size_t da return MA_INVALID_ARGS; } - pDecoder->data.memory.pData = (const ma_uint8*)pData; - pDecoder->data.memory.dataSize = dataSize; - pDecoder->data.memory.currentReadPos = 0; + pDecoder->backend.memory.pData = (const ma_uint8*)pData; + pDecoder->backend.memory.dataSize = dataSize; + pDecoder->backend.memory.currentReadPos = 0; (void)pConfig; return MA_SUCCESS; @@ -64734,128 +46775,157 @@ static ma_result ma_decoder__preinit_memory_wrapper(const void* pData, size_t da MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - ma_result result; ma_decoder_config config; + ma_result result; - config = ma_decoder_config_init_copy(pConfig); + config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ - result = ma_decoder__preinit(NULL, NULL, NULL, NULL, &config, pDecoder); + result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } - if (pData == NULL || dataSize == 0) { - return MA_INVALID_ARGS; - } + return ma_decoder_init__internal(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, &config, pDecoder); +} - /* If the backend has support for loading from a file path we'll want to use that. If that all fails we'll fall back to the VFS path. */ - result = MA_NO_BACKEND; +MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_WAV + ma_decoder_config config; + ma_result result; - if (config.encodingFormat != ma_encoding_format_unknown) { - #ifdef MA_HAS_WAV - if (config.encodingFormat == ma_encoding_format_wav) { - result = ma_decoder_init_wav_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (config.encodingFormat == ma_encoding_format_flac) { - result = ma_decoder_init_flac_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (config.encodingFormat == ma_encoding_format_mp3) { - result = ma_decoder_init_mp3_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (config.encodingFormat == ma_encoding_format_vorbis) { - result = ma_decoder_init_vorbis_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - } + config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ + result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { - /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ - - /* - We use trial and error to open a decoder. We prioritize custom decoders so that if they - implement the same encoding format they take priority over the built-in decoders. - */ - result = ma_decoder_init_custom_from_memory__internal(pData, dataSize, &config, pDecoder); - - /* - If we get to this point and we still haven't found a decoder, and the caller has requested a - specific encoding format, there's no hope for it. Abort. - */ - if (result != MA_SUCCESS && config.encodingFormat != ma_encoding_format_unknown) { - return MA_NO_BACKEND; - } - - /* Use trial and error for stock decoders. */ - if (result != MA_SUCCESS) { - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS) { - result = ma_decoder_init_wav_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS) { - result = ma_decoder_init_flac_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS) { - result = ma_decoder_init_mp3_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (result != MA_SUCCESS) { - result = ma_decoder_init_vorbis_from_memory__internal(pData, dataSize, &config, pDecoder); - } - #endif - } + return result; } - /* - If at this point we still haven't successfully initialized the decoder it most likely means - the backend doesn't have an implementation for loading from a file path. We'll try using - miniaudio's built-in file IO for loading file. - */ - if (result == MA_SUCCESS) { - /* Initialization was successful. Finish up. */ - result = ma_decoder__postinit(&config, pDecoder); - if (result != MA_SUCCESS) { - /* - The backend was initialized successfully, but for some reason post-initialization failed. This is most likely - due to an out of memory error. We're going to abort with an error here and not try to recover. - */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, &pDecoder->pBackend, &pDecoder->allocationCallbacks); - } - - return result; - } - } else { - /* Probably no implementation for loading from a block of memory. Use miniaudio's abstraction instead. */ - result = ma_decoder__preinit_memory_wrapper(pData, dataSize, &config, pDecoder); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_decoder_init__internal(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, &config, pDecoder); - if (result != MA_SUCCESS) { - return result; - } + result = ma_decoder_init_wav__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; } - return MA_SUCCESS; + return ma_decoder__postinit(&config, pDecoder); +#else + (void)pData; + (void)dataSize; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_FLAC + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ + + result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_flac__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)pData; + (void)dataSize; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_MP3 + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ + + result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_mp3__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)pData; + (void)dataSize; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_VORBIS + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ + + result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_vorbis__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); +#else + (void)pData; + (void)dataSize; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) +{ + ma_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfigOut); /* Make sure the config is not NULL. */ + + result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(&config, pDecoder); } #if defined(MA_HAS_WAV) || \ defined(MA_HAS_MP3) || \ defined(MA_HAS_FLAC) || \ - defined(MA_HAS_VORBIS) + defined(MA_HAS_VORBIS) || \ + defined(MA_HAS_OPUS) #define MA_HAS_PATH_API #endif @@ -65030,26 +47100,30 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e -static ma_result ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) +static size_t ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { + size_t bytesRead; + MA_ASSERT(pDecoder != NULL); MA_ASSERT(pBufferOut != NULL); - return ma_vfs_or_default_read(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, pBufferOut, bytesToRead, pBytesRead); + ma_vfs_or_default_read(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file, pBufferOut, bytesToRead, &bytesRead); + + return bytesRead; } -static ma_result ma_decoder__on_seek_vfs(ma_decoder* pDecoder, ma_int64 offset, ma_seek_origin origin) +static ma_bool32 ma_decoder__on_seek_vfs(ma_decoder* pDecoder, int offset, ma_seek_origin origin) { + ma_result result; + MA_ASSERT(pDecoder != NULL); - return ma_vfs_or_default_seek(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, offset, origin); -} + result = ma_vfs_or_default_seek(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file, offset, origin); + if (result != MA_SUCCESS) { + return MA_FALSE; + } -static ma_result ma_decoder__on_tell_vfs(ma_decoder* pDecoder, ma_int64* pCursor) -{ - MA_ASSERT(pDecoder != NULL); - - return ma_vfs_or_default_tell(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, pCursor); + return MA_TRUE; } static ma_result ma_decoder__preinit_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) @@ -65057,7 +47131,7 @@ static ma_result ma_decoder__preinit_vfs(ma_vfs* pVFS, const char* pFilePath, co ma_result result; ma_vfs_file file; - result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, ma_decoder__on_tell_vfs, NULL, pConfig, pDecoder); + result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } @@ -65071,8 +47145,8 @@ static ma_result ma_decoder__preinit_vfs(ma_vfs* pVFS, const char* pFilePath, co return result; } - pDecoder->data.vfs.pVFS = pVFS; - pDecoder->data.vfs.file = file; + pDecoder->backend.vfs.pVFS = pVFS; + pDecoder->backend.vfs.file = file; return MA_SUCCESS; } @@ -65090,81 +47164,30 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const result = MA_NO_BACKEND; - if (config.encodingFormat != ma_encoding_format_unknown) { - #ifdef MA_HAS_WAV - if (config.encodingFormat == ma_encoding_format_wav) { - result = ma_decoder_init_wav__internal(&config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (config.encodingFormat == ma_encoding_format_flac) { - result = ma_decoder_init_flac__internal(&config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (config.encodingFormat == ma_encoding_format_mp3) { - result = ma_decoder_init_mp3__internal(&config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (config.encodingFormat == ma_encoding_format_vorbis) { - result = ma_decoder_init_vorbis__internal(&config, pDecoder); - } - #endif - - /* Make sure we seek back to the start if we didn't initialize a decoder successfully so the next attempts have a fresh start. */ +#ifdef MA_HAS_WAV + if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) { + result = ma_decoder_init_wav__internal(&config, pDecoder); if (result != MA_SUCCESS) { ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } } - - if (result != MA_SUCCESS) { - /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ - - /* - We use trial and error to open a decoder. We prioritize custom decoders so that if they - implement the same encoding format they take priority over the built-in decoders. - */ +#endif +#ifdef MA_HAS_FLAC + if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "flac")) { + result = ma_decoder_init_flac__internal(&config, pDecoder); if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } - - /* - If we get to this point and we still haven't found a decoder, and the caller has requested a - specific encoding format, there's no hope for it. Abort. - */ - if (config.encodingFormat != ma_encoding_format_unknown) { - return MA_NO_BACKEND; - } - - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) { - result = ma_decoder_init_wav__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "flac")) { - result = ma_decoder_init_flac__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "mp3")) { - result = ma_decoder_init_mp3__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } - } - #endif } +#endif +#ifdef MA_HAS_MP3 + if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "mp3")) { + result = ma_decoder_init_mp3__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); + } + } +#endif /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */ if (result != MA_SUCCESS) { @@ -65174,23 +47197,145 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const } if (result != MA_SUCCESS) { - if (pDecoder->data.vfs.file != NULL) { /* <-- Will be reset to NULL if ma_decoder_uninit() is called in one of the steps above which allows us to avoid a double close of the file. */ - ma_vfs_or_default_close(pVFS, pDecoder->data.vfs.file); - } - + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); return result; } return MA_SUCCESS; } +MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_WAV + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_wav__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_FLAC + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_flac__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_MP3 + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_mp3__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_VORBIS + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_vorbis__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + + static ma_result ma_decoder__preinit_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result; ma_vfs_file file; - result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, ma_decoder__on_tell_vfs, NULL, pConfig, pDecoder); + result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } @@ -65204,8 +47349,8 @@ static ma_result ma_decoder__preinit_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePat return result; } - pDecoder->data.vfs.pVFS = pVFS; - pDecoder->data.vfs.file = file; + pDecoder->backend.vfs.pVFS = pVFS; + pDecoder->backend.vfs.file = file; return MA_SUCCESS; } @@ -65223,81 +47368,30 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c result = MA_NO_BACKEND; - if (config.encodingFormat != ma_encoding_format_unknown) { - #ifdef MA_HAS_WAV - if (config.encodingFormat == ma_encoding_format_wav) { - result = ma_decoder_init_wav__internal(&config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (config.encodingFormat == ma_encoding_format_flac) { - result = ma_decoder_init_flac__internal(&config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (config.encodingFormat == ma_encoding_format_mp3) { - result = ma_decoder_init_mp3__internal(&config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (config.encodingFormat == ma_encoding_format_vorbis) { - result = ma_decoder_init_vorbis__internal(&config, pDecoder); - } - #endif - - /* Make sure we seek back to the start if we didn't initialize a decoder successfully so the next attempts have a fresh start. */ +#ifdef MA_HAS_WAV + if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) { + result = ma_decoder_init_wav__internal(&config, pDecoder); if (result != MA_SUCCESS) { ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } } - - if (result != MA_SUCCESS) { - /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ - - /* - We use trial and error to open a decoder. We prioritize custom decoders so that if they - implement the same encoding format they take priority over the built-in decoders. - */ +#endif +#ifdef MA_HAS_FLAC + if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"flac")) { + result = ma_decoder_init_flac__internal(&config, pDecoder); if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } - - /* - If we get to this point and we still haven't found a decoder, and the caller has requested a - specific encoding format, there's no hope for it. Abort. - */ - if (config.encodingFormat != ma_encoding_format_unknown) { - return MA_NO_BACKEND; - } - - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) { - result = ma_decoder_init_wav__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"flac")) { - result = ma_decoder_init_flac__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"mp3")) { - result = ma_decoder_init_mp3__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } - } - #endif } +#endif +#ifdef MA_HAS_MP3 + if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"mp3")) { + result = ma_decoder_init_mp3__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); + } + } +#endif /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */ if (result != MA_SUCCESS) { @@ -65307,312 +47401,189 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c } if (result != MA_SUCCESS) { - ma_vfs_or_default_close(pVFS, pDecoder->data.vfs.file); + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); return result; } return MA_SUCCESS; } - -static ma_result ma_decoder__preinit_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { +#ifdef MA_HAS_WAV ma_result result; + ma_decoder_config config; - result = ma_decoder__preinit(NULL, NULL, NULL, NULL, pConfig, pDecoder); + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder); if (result != MA_SUCCESS) { return result; } - if (pFilePath == NULL || pFilePath[0] == '\0') { - return MA_INVALID_ARGS; + result = ma_decoder_init_wav__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); } - return MA_SUCCESS; + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif } +MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_FLAC + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_flac__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_MP3 + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_mp3__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + +MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ +#ifdef MA_HAS_VORBIS + ma_result result; + ma_decoder_config config; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_init_vorbis__internal(&config, pDecoder); + if (result == MA_SUCCESS) { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file); + } + + return result; +#else + (void)pVFS; + (void)pFilePath; + (void)pConfig; + (void)pDecoder; + return MA_NO_BACKEND; +#endif +} + + + MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - ma_result result; - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - result = ma_decoder__preinit_file(pFilePath, &config, pDecoder); - if (result != MA_SUCCESS) { - return result; - } - - /* If the backend has support for loading from a file path we'll want to use that. If that all fails we'll fall back to the VFS path. */ - result = MA_NO_BACKEND; - - if (config.encodingFormat != ma_encoding_format_unknown) { - #ifdef MA_HAS_WAV - if (config.encodingFormat == ma_encoding_format_wav) { - result = ma_decoder_init_wav_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (config.encodingFormat == ma_encoding_format_flac) { - result = ma_decoder_init_flac_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (config.encodingFormat == ma_encoding_format_mp3) { - result = ma_decoder_init_mp3_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (config.encodingFormat == ma_encoding_format_vorbis) { - result = ma_decoder_init_vorbis_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - } - - if (result != MA_SUCCESS) { - /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ - - /* - We use trial and error to open a decoder. We prioritize custom decoders so that if they - implement the same encoding format they take priority over the built-in decoders. - */ - result = ma_decoder_init_custom_from_file__internal(pFilePath, &config, pDecoder); - - /* - If we get to this point and we still haven't found a decoder, and the caller has requested a - specific encoding format, there's no hope for it. Abort. - */ - if (result != MA_SUCCESS && config.encodingFormat != ma_encoding_format_unknown) { - return MA_NO_BACKEND; - } - - /* First try loading based on the file extension so we don't waste time opening and closing files. */ - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) { - result = ma_decoder_init_wav_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "flac")) { - result = ma_decoder_init_flac_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "mp3")) { - result = ma_decoder_init_mp3_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "ogg")) { - result = ma_decoder_init_vorbis_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - - /* - If we still haven't got a result just use trial and error. Custom decoders have already been attempted, so here we - need only iterate over our stock decoders. - */ - if (result != MA_SUCCESS) { - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS) { - result = ma_decoder_init_wav_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS) { - result = ma_decoder_init_flac_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS) { - result = ma_decoder_init_mp3_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (result != MA_SUCCESS) { - result = ma_decoder_init_vorbis_from_file__internal(pFilePath, &config, pDecoder); - } - #endif - } - } - - /* - If at this point we still haven't successfully initialized the decoder it most likely means - the backend doesn't have an implementation for loading from a file path. We'll try using - miniaudio's built-in file IO for loading file. - */ - if (result == MA_SUCCESS) { - /* Initialization was successful. Finish up. */ - result = ma_decoder__postinit(&config, pDecoder); - if (result != MA_SUCCESS) { - /* - The backend was initialized successfully, but for some reason post-initialization failed. This is most likely - due to an out of memory error. We're going to abort with an error here and not try to recover. - */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, &pDecoder->pBackend, &pDecoder->allocationCallbacks); - } - - return result; - } - } else { - /* Probably no implementation for loading from a file path. Use miniaudio's file IO instead. */ - result = ma_decoder_init_vfs(NULL, pFilePath, pConfig, pDecoder); - if (result != MA_SUCCESS) { - return result; - } - } - - return MA_SUCCESS; + return ma_decoder_init_vfs(NULL, pFilePath, pConfig, pDecoder); } -static ma_result ma_decoder__preinit_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - ma_result result; - - result = ma_decoder__preinit(NULL, NULL, NULL, NULL, pConfig, pDecoder); - if (result != MA_SUCCESS) { - return result; - } - - if (pFilePath == NULL || pFilePath[0] == '\0') { - return MA_INVALID_ARGS; - } - - return MA_SUCCESS; + return ma_decoder_init_vfs_wav(NULL, pFilePath, pConfig, pDecoder); } +MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_flac(NULL, pFilePath, pConfig, pDecoder); +} + +MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_mp3(NULL, pFilePath, pConfig, pDecoder); +} + +MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_vorbis(NULL, pFilePath, pConfig, pDecoder); +} + + + MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - ma_result result; - ma_decoder_config config; + return ma_decoder_init_vfs_w(NULL, pFilePath, pConfig, pDecoder); +} - config = ma_decoder_config_init_copy(pConfig); - result = ma_decoder__preinit_file_w(pFilePath, &config, pDecoder); - if (result != MA_SUCCESS) { - return result; - } +MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_wav_w(NULL, pFilePath, pConfig, pDecoder); +} - /* If the backend has support for loading from a file path we'll want to use that. If that all fails we'll fall back to the VFS path. */ - result = MA_NO_BACKEND; +MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_flac_w(NULL, pFilePath, pConfig, pDecoder); +} - if (config.encodingFormat != ma_encoding_format_unknown) { - #ifdef MA_HAS_WAV - if (config.encodingFormat == ma_encoding_format_wav) { - result = ma_decoder_init_wav_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (config.encodingFormat == ma_encoding_format_flac) { - result = ma_decoder_init_flac_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (config.encodingFormat == ma_encoding_format_mp3) { - result = ma_decoder_init_mp3_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (config.encodingFormat == ma_encoding_format_vorbis) { - result = ma_decoder_init_vorbis_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - } +MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_mp3_w(NULL, pFilePath, pConfig, pDecoder); +} - if (result != MA_SUCCESS) { - /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ - - /* - We use trial and error to open a decoder. We prioritize custom decoders so that if they - implement the same encoding format they take priority over the built-in decoders. - */ - result = ma_decoder_init_custom_from_file_w__internal(pFilePath, &config, pDecoder); - - /* - If we get to this point and we still haven't found a decoder, and the caller has requested a - specific encoding format, there's no hope for it. Abort. - */ - if (result != MA_SUCCESS && config.encodingFormat != ma_encoding_format_unknown) { - return MA_NO_BACKEND; - } - - /* First try loading based on the file extension so we don't waste time opening and closing files. */ - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) { - result = ma_decoder_init_wav_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"flac")) { - result = ma_decoder_init_flac_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"mp3")) { - result = ma_decoder_init_mp3_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"ogg")) { - result = ma_decoder_init_vorbis_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - - /* - If we still haven't got a result just use trial and error. Custom decoders have already been attempted, so here we - need only iterate over our stock decoders. - */ - if (result != MA_SUCCESS) { - #ifdef MA_HAS_WAV - if (result != MA_SUCCESS) { - result = ma_decoder_init_wav_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_FLAC - if (result != MA_SUCCESS) { - result = ma_decoder_init_flac_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_MP3 - if (result != MA_SUCCESS) { - result = ma_decoder_init_mp3_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - #ifdef MA_HAS_VORBIS - if (result != MA_SUCCESS) { - result = ma_decoder_init_vorbis_from_file_w__internal(pFilePath, &config, pDecoder); - } - #endif - } - } - - /* - If at this point we still haven't successfully initialized the decoder it most likely means - the backend doesn't have an implementation for loading from a file path. We'll try using - miniaudio's built-in file IO for loading file. - */ - if (result == MA_SUCCESS) { - /* Initialization was successful. Finish up. */ - result = ma_decoder__postinit(&config, pDecoder); - if (result != MA_SUCCESS) { - /* - The backend was initialized successfully, but for some reason post-initialization failed. This is most likely - due to an out of memory error. We're going to abort with an error here and not try to recover. - */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, &pDecoder->pBackend, &pDecoder->allocationCallbacks); - } - - return result; - } - } else { - /* Probably no implementation for loading from a file path. Use miniaudio's file IO instead. */ - result = ma_decoder_init_vfs_w(NULL, pFilePath, pConfig, pDecoder); - if (result != MA_SUCCESS) { - return result; - } - } - - return MA_SUCCESS; +MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + return ma_decoder_init_vfs_vorbis_w(NULL, pFilePath, pConfig, pDecoder); } MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder) @@ -65621,258 +47592,15 @@ MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder) return MA_INVALID_ARGS; } - if (pDecoder->pBackend != NULL) { - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, pDecoder->pBackend, &pDecoder->allocationCallbacks); - } + if (pDecoder->onUninit) { + pDecoder->onUninit(pDecoder); } if (pDecoder->onRead == ma_decoder__on_read_vfs) { - ma_vfs_or_default_close(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file); - pDecoder->data.vfs.file = NULL; + ma_vfs_or_default_close(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file); } - ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks); - ma_data_source_uninit(&pDecoder->ds); - - if (pDecoder->pInputCache != NULL) { - ma_free(pDecoder->pInputCache, &pDecoder->allocationCallbacks); - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result = MA_SUCCESS; - ma_uint64 totalFramesReadOut; - void* pRunningFramesOut; - - if (pFramesRead != NULL) { - *pFramesRead = 0; /* Safety. */ - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pDecoder == NULL) { - return MA_INVALID_ARGS; - } - - if (pDecoder->pBackend == NULL) { - return MA_INVALID_OPERATION; - } - - /* Fast path. */ - if (pDecoder->converter.isPassthrough) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pFramesOut, frameCount, &totalFramesReadOut); - } else { - /* - Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we - need to run through each sample because we need to ensure its internal cache is updated. - */ - if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut); - } else { - /* Slow path. Need to run everything through the data converter. */ - ma_format internalFormat; - ma_uint32 internalChannels; - - totalFramesReadOut = 0; - pRunningFramesOut = pFramesOut; - - result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, NULL, NULL, 0); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the internal format and channel count. */ - } - - /* - We run a different path depending on whether or not we are using a heap-allocated - intermediary buffer or not. If the data converter does not support the calculation of - the required number of input frames, we'll use the heap-allocated path. Otherwise we'll - use the stack-allocated path. - */ - if (pDecoder->pInputCache != NULL) { - /* We don't have a way of determining the required number of input frames, so need to persistently store input data in a cache. */ - while (totalFramesReadOut < frameCount) { - ma_uint64 framesToReadThisIterationIn; - ma_uint64 framesToReadThisIterationOut; - - /* If there's any data available in the cache, that needs to get processed first. */ - if (pDecoder->inputCacheRemaining > 0) { - framesToReadThisIterationOut = (frameCount - totalFramesReadOut); - framesToReadThisIterationIn = framesToReadThisIterationOut; - if (framesToReadThisIterationIn > pDecoder->inputCacheRemaining) { - framesToReadThisIterationIn = pDecoder->inputCacheRemaining; - } - - result = ma_data_converter_process_pcm_frames(&pDecoder->converter, ma_offset_pcm_frames_ptr(pDecoder->pInputCache, pDecoder->inputCacheConsumed, internalFormat, internalChannels), &framesToReadThisIterationIn, pRunningFramesOut, &framesToReadThisIterationOut); - if (result != MA_SUCCESS) { - break; - } - - pDecoder->inputCacheConsumed += framesToReadThisIterationIn; - pDecoder->inputCacheRemaining -= framesToReadThisIterationIn; - - totalFramesReadOut += framesToReadThisIterationOut; - - if (pRunningFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesToReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels)); - } - - if (framesToReadThisIterationIn == 0 && framesToReadThisIterationOut == 0) { - break; /* We're done. */ - } - } - - /* Getting here means there's no data in the cache and we need to fill it up from the data source. */ - if (pDecoder->inputCacheRemaining == 0) { - pDecoder->inputCacheConsumed = 0; - - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pDecoder->pInputCache, pDecoder->inputCacheCap, &pDecoder->inputCacheRemaining); - if (result != MA_SUCCESS) { - break; - } - } - } - } else { - /* We have a way of determining the required number of input frames so just use the stack. */ - while (totalFramesReadOut < frameCount) { - ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */ - ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(internalFormat, internalChannels); - ma_uint64 framesToReadThisIterationIn; - ma_uint64 framesReadThisIterationIn; - ma_uint64 framesToReadThisIterationOut; - ma_uint64 framesReadThisIterationOut; - ma_uint64 requiredInputFrameCount; - - framesToReadThisIterationOut = (frameCount - totalFramesReadOut); - framesToReadThisIterationIn = framesToReadThisIterationOut; - if (framesToReadThisIterationIn > intermediaryBufferCap) { - framesToReadThisIterationIn = intermediaryBufferCap; - } - - ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut, &requiredInputFrameCount); - if (framesToReadThisIterationIn > requiredInputFrameCount) { - framesToReadThisIterationIn = requiredInputFrameCount; - } - - if (requiredInputFrameCount > 0) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn); - - /* - Note here that even if we've reached the end, we don't want to abort because there might be more output frames needing to be - generated from cached input data, which might happen if resampling is being performed. - */ - if (result != MA_SUCCESS && result != MA_AT_END) { - break; - } - } else { - framesReadThisIterationIn = 0; - pIntermediaryBuffer[0] = 0; /* <-- This is just to silence a static analysis warning. */ - } - - /* - At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any - input frames, we still want to try processing frames because there may some output frames generated from cached input data. - */ - framesReadThisIterationOut = framesToReadThisIterationOut; - result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); - if (result != MA_SUCCESS) { - break; - } - - totalFramesReadOut += framesReadThisIterationOut; - - if (pRunningFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels)); - } - - if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { - break; /* We're done. */ - } - } - } - } - } - - pDecoder->readPointerInPCMFrames += totalFramesReadOut; - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesReadOut; - } - - if (result == MA_SUCCESS && totalFramesReadOut == 0) { - result = MA_AT_END; - } - - return result; -} - -MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex) -{ - if (pDecoder == NULL) { - return MA_INVALID_ARGS; - } - - if (pDecoder->pBackend != NULL) { - ma_result result; - ma_uint64 internalFrameIndex; - ma_uint32 internalSampleRate; - ma_uint64 currentFrameIndex; - - result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the internal sample rate. */ - } - - if (internalSampleRate == pDecoder->outputSampleRate) { - internalFrameIndex = frameIndex; - } else { - internalFrameIndex = ma_calculate_frame_count_after_resampling(internalSampleRate, pDecoder->outputSampleRate, frameIndex); - } - - /* Only seek if we're requesting a different frame to what we're currently sitting on. */ - ma_data_source_get_cursor_in_pcm_frames(pDecoder->pBackend, ¤tFrameIndex); - if (currentFrameIndex != internalFrameIndex) { - result = ma_data_source_seek_to_pcm_frame(pDecoder->pBackend, internalFrameIndex); - if (result == MA_SUCCESS) { - pDecoder->readPointerInPCMFrames = frameIndex; - } - - /* Reset the data converter so that any cached data in the resampler is cleared. */ - ma_data_converter_reset(&pDecoder->converter); - } - - return result; - } - - /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */ - return MA_INVALID_ARGS; -} - -MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pDecoder == NULL) { - return MA_INVALID_ARGS; - } - - if (pFormat != NULL) { - *pFormat = pDecoder->outputFormat; - } - - if (pChannels != NULL) { - *pChannels = pDecoder->outputChannels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pDecoder->outputSampleRate; - } - - if (pChannelMap != NULL) { - ma_data_converter_get_output_channel_map(&pDecoder->converter, pChannelMap, channelMapCap); - } + ma_data_converter_uninit(&pDecoder->converter); return MA_SUCCESS; } @@ -65894,48 +47622,139 @@ MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_ui return MA_SUCCESS; } -MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength) +MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder) { - if (pLength == NULL) { - return MA_INVALID_ARGS; + if (pDecoder == NULL) { + return 0; } - *pLength = 0; + if (pDecoder->onGetLengthInPCMFrames) { + ma_uint64 nativeLengthInPCMFrames = pDecoder->onGetLengthInPCMFrames(pDecoder); + if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) { + return nativeLengthInPCMFrames; + } else { + return ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, pDecoder->internalSampleRate, nativeLengthInPCMFrames); + } + } + return 0; +} + +MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) +{ + ma_result result; + ma_uint64 totalFramesReadOut; + ma_uint64 totalFramesReadIn; + void* pRunningFramesOut; + + if (pDecoder == NULL) { + return 0; + } + + if (pDecoder->onReadPCMFrames == NULL) { + return 0; + } + + /* Fast path. */ + if (pDecoder->converter.isPassthrough) { + totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, pFramesOut, frameCount); + } else { + /* + Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we + need to run through each sample because we need to ensure it's internal cache is updated. + */ + if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) { + totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, NULL, frameCount); /* All decoder backends must support passing in NULL for the output buffer. */ + } else { + /* Slow path. Need to run everything through the data converter. */ + totalFramesReadOut = 0; + totalFramesReadIn = 0; + pRunningFramesOut = pFramesOut; + + while (totalFramesReadOut < frameCount) { + ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */ + ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels); + ma_uint64 framesToReadThisIterationIn; + ma_uint64 framesReadThisIterationIn; + ma_uint64 framesToReadThisIterationOut; + ma_uint64 framesReadThisIterationOut; + ma_uint64 requiredInputFrameCount; + + framesToReadThisIterationOut = (frameCount - totalFramesReadOut); + framesToReadThisIterationIn = framesToReadThisIterationOut; + if (framesToReadThisIterationIn > intermediaryBufferCap) { + framesToReadThisIterationIn = intermediaryBufferCap; + } + + requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut); + if (framesToReadThisIterationIn > requiredInputFrameCount) { + framesToReadThisIterationIn = requiredInputFrameCount; + } + + if (requiredInputFrameCount > 0) { + framesReadThisIterationIn = pDecoder->onReadPCMFrames(pDecoder, pIntermediaryBuffer, framesToReadThisIterationIn); + totalFramesReadIn += framesReadThisIterationIn; + } else { + framesReadThisIterationIn = 0; + } + + /* + At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any + input frames, we still want to try processing frames because there may some output frames generated from cached input data. + */ + framesReadThisIterationOut = framesToReadThisIterationOut; + result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); + if (result != MA_SUCCESS) { + break; + } + + totalFramesReadOut += framesReadThisIterationOut; + + if (pRunningFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels)); + } + + if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { + break; /* We're done. */ + } + } + } + } + + pDecoder->readPointerInPCMFrames += totalFramesReadOut; + + return totalFramesReadOut; +} + +MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex) +{ if (pDecoder == NULL) { return MA_INVALID_ARGS; } - if (pDecoder->pBackend != NULL) { + if (pDecoder->onSeekToPCMFrame) { ma_result result; - ma_uint64 internalLengthInPCMFrames; - ma_uint32 internalSampleRate; - - result = ma_data_source_get_length_in_pcm_frames(pDecoder->pBackend, &internalLengthInPCMFrames); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the internal length. */ - } - - result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the internal sample rate. */ - } - - if (internalSampleRate == pDecoder->outputSampleRate) { - *pLength = internalLengthInPCMFrames; + ma_uint64 internalFrameIndex; + if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) { + internalFrameIndex = frameIndex; } else { - *pLength = ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, internalSampleRate, internalLengthInPCMFrames); + internalFrameIndex = ma_calculate_frame_count_after_resampling(pDecoder->internalSampleRate, pDecoder->outputSampleRate, frameIndex); } - return MA_SUCCESS; - } else { - return MA_NO_BACKEND; + result = pDecoder->onSeekToPCMFrame(pDecoder, internalFrameIndex); + if (result == MA_SUCCESS) { + pDecoder->readPointerInPCMFrames = frameIndex; + } + + return result; } + + /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */ + return MA_INVALID_ARGS; } MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames) { - ma_result result; ma_uint64 totalFrameCount; if (pAvailableFrames == NULL) { @@ -65948,9 +47767,9 @@ MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64 return MA_INVALID_ARGS; } - result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount); - if (result != MA_SUCCESS) { - return result; + totalFrameCount = ma_decoder_get_length_in_pcm_frames(pDecoder); + if (totalFrameCount == 0) { + return MA_NOT_IMPLEMENTED; } if (totalFrameCount <= pDecoder->readPointerInPCMFrames) { @@ -65959,13 +47778,12 @@ MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64 *pAvailableFrames = totalFrameCount - pDecoder->readPointerInPCMFrames; } - return MA_SUCCESS; + return MA_SUCCESS; /* No frames available. */ } static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) { - ma_result result; ma_uint64 totalFrameCount; ma_uint64 bpf; ma_uint64 dataCapInFrames; @@ -65986,19 +47804,21 @@ static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_dec /* Make room if there's not enough. */ if (totalFrameCount == dataCapInFrames) { void* pNewPCMFramesOut; + ma_uint64 oldDataCapInFrames = dataCapInFrames; ma_uint64 newDataCapInFrames = dataCapInFrames*2; if (newDataCapInFrames == 0) { newDataCapInFrames = 4096; } if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) { - ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); + ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks); return MA_TOO_BIG; } - pNewPCMFramesOut = (void*)ma_realloc(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), &pDecoder->allocationCallbacks); + + pNewPCMFramesOut = (void*)ma__realloc_from_callbacks(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), (size_t)(oldDataCapInFrames * bpf), &pDecoder->allocationCallbacks); if (pNewPCMFramesOut == NULL) { - ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); + ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks); return MA_OUT_OF_MEMORY; } @@ -66009,13 +47829,9 @@ static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_dec frameCountToTryReading = dataCapInFrames - totalFrameCount; MA_ASSERT(frameCountToTryReading > 0); - result = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading, &framesJustRead); + framesJustRead = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading); totalFrameCount += framesJustRead; - if (result != MA_SUCCESS) { - break; - } - if (framesJustRead < frameCountToTryReading) { break; } @@ -66023,15 +47839,16 @@ static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_dec if (pConfigOut != NULL) { - pConfigOut->format = pDecoder->outputFormat; - pConfigOut->channels = pDecoder->outputChannels; + pConfigOut->format = pDecoder->outputFormat; + pConfigOut->channels = pDecoder->outputChannels; pConfigOut->sampleRate = pDecoder->outputSampleRate; + ma_channel_map_copy(pConfigOut->channelMap, pDecoder->outputChannelMap, pDecoder->outputChannels); } if (ppPCMFramesOut != NULL) { *ppPCMFramesOut = pPCMFramesOut; } else { - ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); + ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks); } if (pFrameCountOut != NULL) { @@ -66107,50 +47924,40 @@ MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder static size_t ma_encoder__internal_on_write_wav(void* pUserData, const void* pData, size_t bytesToWrite) { ma_encoder* pEncoder = (ma_encoder*)pUserData; - size_t bytesWritten = 0; - MA_ASSERT(pEncoder != NULL); - pEncoder->onWrite(pEncoder, pData, bytesToWrite, &bytesWritten); - return bytesWritten; + return pEncoder->onWrite(pEncoder, pData, bytesToWrite); } -static ma_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, ma_dr_wav_seek_origin origin) +static drwav_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, drwav_seek_origin origin) { ma_encoder* pEncoder = (ma_encoder*)pUserData; - ma_result result; - MA_ASSERT(pEncoder != NULL); - result = pEncoder->onSeek(pEncoder, offset, (origin == ma_dr_wav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); - if (result != MA_SUCCESS) { - return MA_FALSE; - } else { - return MA_TRUE; - } + return pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder) { - ma_dr_wav_data_format wavFormat; - ma_allocation_callbacks allocationCallbacks; - ma_dr_wav* pWav; + drwav_data_format wavFormat; + drwav_allocation_callbacks allocationCallbacks; + drwav* pWav; MA_ASSERT(pEncoder != NULL); - pWav = (ma_dr_wav*)ma_malloc(sizeof(*pWav), &pEncoder->config.allocationCallbacks); + pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pEncoder->config.allocationCallbacks); if (pWav == NULL) { return MA_OUT_OF_MEMORY; } - wavFormat.container = ma_dr_wav_container_riff; + wavFormat.container = drwav_container_riff; wavFormat.channels = pEncoder->config.channels; wavFormat.sampleRate = pEncoder->config.sampleRate; wavFormat.bitsPerSample = ma_get_bytes_per_sample(pEncoder->config.format) * 8; if (pEncoder->config.format == ma_format_f32) { - wavFormat.format = MA_DR_WAVE_FORMAT_IEEE_FLOAT; + wavFormat.format = DR_WAVE_FORMAT_IEEE_FLOAT; } else { - wavFormat.format = MA_DR_WAVE_FORMAT_PCM; + wavFormat.format = DR_WAVE_FORMAT_PCM; } allocationCallbacks.pUserData = pEncoder->config.allocationCallbacks.pUserData; @@ -66158,7 +47965,7 @@ static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder) allocationCallbacks.onRealloc = pEncoder->config.allocationCallbacks.onRealloc; allocationCallbacks.onFree = pEncoder->config.allocationCallbacks.onFree; - if (!ma_dr_wav_init_write(pWav, &wavFormat, ma_encoder__internal_on_write_wav, ma_encoder__internal_on_seek_wav, pEncoder, &allocationCallbacks)) { + if (!drwav_init_write(pWav, &wavFormat, ma_encoder__internal_on_write_wav, ma_encoder__internal_on_seek_wav, pEncoder, &allocationCallbacks)) { return MA_ERROR; } @@ -66169,43 +47976,36 @@ static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder) static void ma_encoder__on_uninit_wav(ma_encoder* pEncoder) { - ma_dr_wav* pWav; + drwav* pWav; MA_ASSERT(pEncoder != NULL); - pWav = (ma_dr_wav*)pEncoder->pInternalEncoder; + pWav = (drwav*)pEncoder->pInternalEncoder; MA_ASSERT(pWav != NULL); - ma_dr_wav_uninit(pWav); - ma_free(pWav, &pEncoder->config.allocationCallbacks); + drwav_uninit(pWav); + ma__free_from_callbacks(pWav, &pEncoder->config.allocationCallbacks); } -static ma_result ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten) +static ma_uint64 ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount) { - ma_dr_wav* pWav; - ma_uint64 framesWritten; + drwav* pWav; MA_ASSERT(pEncoder != NULL); - pWav = (ma_dr_wav*)pEncoder->pInternalEncoder; + pWav = (drwav*)pEncoder->pInternalEncoder; MA_ASSERT(pWav != NULL); - framesWritten = ma_dr_wav_write_pcm_frames(pWav, frameCount, pFramesIn); - - if (pFramesWritten != NULL) { - *pFramesWritten = framesWritten; - } - - return MA_SUCCESS; + return drwav_write_pcm_frames(pWav, frameCount, pFramesIn); } #endif -MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) { ma_encoder_config config; MA_ZERO_OBJECT(&config); - config.encodingFormat = encodingFormat; + config.resourceFormat = resourceFormat; config.format = format; config.channels = channels; config.sampleRate = sampleRate; @@ -66256,9 +48056,9 @@ MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_enc pEncoder->onSeek = onSeek; pEncoder->pUserData = pUserData; - switch (pEncoder->config.encodingFormat) + switch (pEncoder->config.resourceFormat) { - case ma_encoding_format_wav: + case ma_resource_format_wav: { #if defined(MA_HAS_WAV) pEncoder->onInit = ma_encoder__on_init_wav; @@ -66278,85 +48078,64 @@ MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_enc /* Getting here means we should have our backend callbacks set up. */ if (result == MA_SUCCESS) { result = pEncoder->onInit(pEncoder); - } - - return result; -} - -static ma_result ma_encoder__on_write_vfs(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite, size_t* pBytesWritten) -{ - return ma_vfs_or_default_write(pEncoder->data.vfs.pVFS, pEncoder->data.vfs.file, pBufferIn, bytesToWrite, pBytesWritten); -} - -static ma_result ma_encoder__on_seek_vfs(ma_encoder* pEncoder, ma_int64 offset, ma_seek_origin origin) -{ - return ma_vfs_or_default_seek(pEncoder->data.vfs.pVFS, pEncoder->data.vfs.file, offset, origin); -} - -MA_API ma_result ma_encoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) -{ - ma_result result; - ma_vfs_file file; - - result = ma_encoder_preinit(pConfig, pEncoder); - if (result != MA_SUCCESS) { - return result; - } - - /* Now open the file. If this fails we don't need to uninitialize the encoder. */ - result = ma_vfs_or_default_open(pVFS, pFilePath, MA_OPEN_MODE_WRITE, &file); - if (result != MA_SUCCESS) { - return result; - } - - pEncoder->data.vfs.pVFS = pVFS; - pEncoder->data.vfs.file = file; - - result = ma_encoder_init__internal(ma_encoder__on_write_vfs, ma_encoder__on_seek_vfs, NULL, pEncoder); - if (result != MA_SUCCESS) { - ma_vfs_or_default_close(pVFS, file); - return result; + if (result != MA_SUCCESS) { + return result; + } } return MA_SUCCESS; } -MA_API ma_result ma_encoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) +MA_API size_t ma_encoder__on_write_stdio(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite) { - ma_result result; - ma_vfs_file file; + return fwrite(pBufferIn, 1, bytesToWrite, (FILE*)pEncoder->pFile); +} - result = ma_encoder_preinit(pConfig, pEncoder); - if (result != MA_SUCCESS) { - return result; - } - - /* Now open the file. If this fails we don't need to uninitialize the encoder. */ - result = ma_vfs_or_default_open_w(pVFS, pFilePath, MA_OPEN_MODE_WRITE, &file); - if (result != MA_SUCCESS) { - return result; - } - - pEncoder->data.vfs.pVFS = pVFS; - pEncoder->data.vfs.file = file; - - result = ma_encoder_init__internal(ma_encoder__on_write_vfs, ma_encoder__on_seek_vfs, NULL, pEncoder); - if (result != MA_SUCCESS) { - ma_vfs_or_default_close(pVFS, file); - return result; - } - - return MA_SUCCESS; +MA_API ma_bool32 ma_encoder__on_seek_stdio(ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin) +{ + return fseek((FILE*)pEncoder->pFile, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) { - return ma_encoder_init_vfs(NULL, pFilePath, pConfig, pEncoder); + ma_result result; + FILE* pFile; + + result = ma_encoder_preinit(pConfig, pEncoder); + if (result != MA_SUCCESS) { + return result; + } + + /* Now open the file. If this fails we don't need to uninitialize the encoder. */ + result = ma_fopen(&pFile, pFilePath, "wb"); + if (pFile == NULL) { + return result; + } + + pEncoder->pFile = pFile; + + return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder); } MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) { - return ma_encoder_init_vfs_w(NULL, pFilePath, pConfig, pEncoder); + ma_result result; + FILE* pFile; + + result = ma_encoder_preinit(pConfig, pEncoder); + if (result != MA_SUCCESS) { + return result; + } + + /* Now open the file. If this fails we don't need to uninitialize the encoder. */ + result = ma_wfopen(&pFile, pFilePath, L"wb", &pEncoder->config.allocationCallbacks); + if (pFile != NULL) { + return result; + } + + pEncoder->pFile = pFile; + + return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder); } MA_API ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder) @@ -66383,24 +48162,19 @@ MA_API void ma_encoder_uninit(ma_encoder* pEncoder) } /* If we have a file handle, close it. */ - if (pEncoder->onWrite == ma_encoder__on_write_vfs) { - ma_vfs_or_default_close(pEncoder->data.vfs.pVFS, pEncoder->data.vfs.file); - pEncoder->data.vfs.file = NULL; + if (pEncoder->onWrite == ma_encoder__on_write_stdio) { + fclose((FILE*)pEncoder->pFile); } } -MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten) +MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount) { - if (pFramesWritten != NULL) { - *pFramesWritten = 0; - } - if (pEncoder == NULL || pFramesIn == NULL) { - return MA_INVALID_ARGS; + return 0; } - return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount, pFramesWritten); + return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount); } #endif /* MA_NO_ENCODING */ @@ -66429,7 +48203,17 @@ MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 ch static ma_result ma_waveform__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - return ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount, pFramesRead); + ma_uint64 framesRead = ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount); + + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + if (framesRead < frameCount) { + return MA_AT_END; + } + + return MA_SUCCESS; } static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -66437,14 +48221,13 @@ static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, m return ma_waveform_seek_to_pcm_frame((ma_waveform*)pDataSource, frameIndex); } -static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) { ma_waveform* pWaveform = (ma_waveform*)pDataSource; *pFormat = pWaveform->config.format; *pChannels = pWaveform->config.channels; *pSampleRate = pWaveform->config.sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pWaveform->config.channels); return MA_SUCCESS; } @@ -66468,52 +48251,25 @@ static void ma_waveform__update_advance(ma_waveform* pWaveform) pWaveform->advance = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency); } -static ma_data_source_vtable g_ma_waveform_data_source_vtable = -{ - ma_waveform__data_source_on_read, - ma_waveform__data_source_on_seek, - ma_waveform__data_source_on_get_data_format, - ma_waveform__data_source_on_get_cursor, - NULL, /* onGetLength. There's no notion of a length in waveforms. */ - NULL, /* onSetLooping */ - 0 -}; - MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform) { - ma_result result; - ma_data_source_config dataSourceConfig; - if (pWaveform == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pWaveform); - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_waveform_data_source_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pWaveform->ds); - if (result != MA_SUCCESS) { - return result; - } - - pWaveform->config = *pConfig; - pWaveform->advance = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency); - pWaveform->time = 0; + pWaveform->ds.onRead = ma_waveform__data_source_on_read; + pWaveform->ds.onSeek = ma_waveform__data_source_on_seek; + pWaveform->ds.onGetDataFormat = ma_waveform__data_source_on_get_data_format; + pWaveform->ds.onGetCursor = ma_waveform__data_source_on_get_cursor; + pWaveform->ds.onGetLength = NULL; /* Intentionally set to NULL since there's no notion of a length in waveforms. */ + pWaveform->config = *pConfig; + pWaveform->advance = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency); + pWaveform->time = 0; return MA_SUCCESS; } -MA_API void ma_waveform_uninit(ma_waveform* pWaveform) -{ - if (pWaveform == NULL) { - return; - } - - ma_data_source_uninit(&pWaveform->ds); -} - MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude) { if (pWaveform == NULL) { @@ -66560,7 +48316,7 @@ MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 s static float ma_waveform_sine_f32(double time, double amplitude) { - return (float)(ma_sind(MA_TAU_D * time) * amplitude); + return (float)(ma_sin(MA_TAU_D * time) * amplitude); } static ma_int16 ma_waveform_sine_s16(double time, double amplitude) @@ -66568,12 +48324,12 @@ static ma_int16 ma_waveform_sine_s16(double time, double amplitude) return ma_pcm_sample_f32_to_s16(ma_waveform_sine_f32(time, amplitude)); } -static float ma_waveform_square_f32(double time, double dutyCycle, double amplitude) +static float ma_waveform_square_f32(double time, double amplitude) { double f = time - (ma_int64)time; double r; - if (f < dutyCycle) { + if (f < 0.5) { r = amplitude; } else { r = -amplitude; @@ -66582,9 +48338,9 @@ static float ma_waveform_square_f32(double time, double dutyCycle, double amplit return (float)r; } -static ma_int16 ma_waveform_square_s16(double time, double dutyCycle, double amplitude) +static ma_int16 ma_waveform_square_s16(double time, double amplitude) { - return ma_pcm_sample_f32_to_s16(ma_waveform_square_f32(time, dutyCycle, amplitude)); + return ma_pcm_sample_f32_to_s16(ma_waveform_square_f32(time, amplitude)); } static float ma_waveform_triangle_f32(double time, double amplitude) @@ -66659,7 +48415,7 @@ static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFra } } -static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, double dutyCycle, void* pFramesOut, ma_uint64 frameCount) +static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount) { ma_uint64 iFrame; ma_uint64 iChannel; @@ -66672,7 +48428,7 @@ static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, double d if (pWaveform->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float s = ma_waveform_square_f32(pWaveform->time, dutyCycle, pWaveform->config.amplitude); + float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.amplitude); pWaveform->time += pWaveform->advance; for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { @@ -66682,7 +48438,7 @@ static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, double d } else if (pWaveform->config.format == ma_format_s16) { ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - ma_int16 s = ma_waveform_square_s16(pWaveform->time, dutyCycle, pWaveform->config.amplitude); + ma_int16 s = ma_waveform_square_s16(pWaveform->time, pWaveform->config.amplitude); pWaveform->time += pWaveform->advance; for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { @@ -66691,7 +48447,7 @@ static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, double d } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float s = ma_waveform_square_f32(pWaveform->time, dutyCycle, pWaveform->config.amplitude); + float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.amplitude); pWaveform->time += pWaveform->advance; for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { @@ -66785,18 +48541,10 @@ static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* } } -MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount) { - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - if (pWaveform == NULL) { - return MA_INVALID_ARGS; + return 0; } if (pFramesOut != NULL) { @@ -66809,7 +48557,7 @@ MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFram case ma_waveform_type_square: { - ma_waveform_read_pcm_frames__square(pWaveform, 0.5, pFramesOut, frameCount); + ma_waveform_read_pcm_frames__square(pWaveform, pFramesOut, frameCount); } break; case ma_waveform_type_triangle: @@ -66822,17 +48570,13 @@ MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFram ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount); } break; - default: return MA_INVALID_OPERATION; /* Unknown waveform type. */ + default: return 0; } } else { pWaveform->time += pWaveform->advance * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */ } - if (pFramesRead != NULL) { - *pFramesRead = frameCount; - } - - return MA_SUCCESS; + return frameCount; } MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex) @@ -66846,142 +48590,6 @@ MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 return MA_SUCCESS; } -MA_API ma_pulsewave_config ma_pulsewave_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double dutyCycle, double amplitude, double frequency) -{ - ma_pulsewave_config config; - - MA_ZERO_OBJECT(&config); - config.format = format; - config.channels = channels; - config.sampleRate = sampleRate; - config.dutyCycle = dutyCycle; - config.amplitude = amplitude; - config.frequency = frequency; - - return config; -} - -MA_API ma_result ma_pulsewave_init(const ma_pulsewave_config* pConfig, ma_pulsewave* pWaveform) -{ - ma_result result; - ma_waveform_config config; - - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pWaveform); - - config = ma_waveform_config_init( - pConfig->format, - pConfig->channels, - pConfig->sampleRate, - ma_waveform_type_square, - pConfig->amplitude, - pConfig->frequency - ); - - result = ma_waveform_init(&config, &pWaveform->waveform); - ma_pulsewave_set_duty_cycle(pWaveform, pConfig->dutyCycle); - - return result; -} - -MA_API void ma_pulsewave_uninit(ma_pulsewave* pWaveform) -{ - if (pWaveform == NULL) { - return; - } - - ma_waveform_uninit(&pWaveform->waveform); -} - -MA_API ma_result ma_pulsewave_read_pcm_frames(ma_pulsewave* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - if (pFramesOut != NULL) { - ma_waveform_read_pcm_frames__square(&pWaveform->waveform, pWaveform->config.dutyCycle, pFramesOut, frameCount); - } else { - pWaveform->waveform.time += pWaveform->waveform.advance * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */ - } - - if (pFramesRead != NULL) { - *pFramesRead = frameCount; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_pulsewave_seek_to_pcm_frame(ma_pulsewave* pWaveform, ma_uint64 frameIndex) -{ - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - ma_waveform_seek_to_pcm_frame(&pWaveform->waveform, frameIndex); - - return MA_SUCCESS; -} - -MA_API ma_result ma_pulsewave_set_amplitude(ma_pulsewave* pWaveform, double amplitude) -{ - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - pWaveform->config.amplitude = amplitude; - ma_waveform_set_amplitude(&pWaveform->waveform, amplitude); - - return MA_SUCCESS; -} - -MA_API ma_result ma_pulsewave_set_frequency(ma_pulsewave* pWaveform, double frequency) -{ - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - pWaveform->config.frequency = frequency; - ma_waveform_set_frequency(&pWaveform->waveform, frequency); - - return MA_SUCCESS; -} - -MA_API ma_result ma_pulsewave_set_sample_rate(ma_pulsewave* pWaveform, ma_uint32 sampleRate) -{ - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - pWaveform->config.sampleRate = sampleRate; - ma_waveform_set_sample_rate(&pWaveform->waveform, sampleRate); - - return MA_SUCCESS; -} - -MA_API ma_result ma_pulsewave_set_duty_cycle(ma_pulsewave* pWaveform, double dutyCycle) -{ - if (pWaveform == NULL) { - return MA_INVALID_ARGS; - } - - pWaveform->config.dutyCycle = dutyCycle; - - return MA_SUCCESS; -} - - MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude) { @@ -67004,7 +48612,17 @@ MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels static ma_result ma_noise__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - return ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount, pFramesRead); + ma_uint64 framesRead = ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount); + + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + if (framesRead < frameCount) { + return MA_AT_END; + } + + return MA_SUCCESS; } static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -67015,162 +48633,51 @@ static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_u return MA_SUCCESS; } -static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) { ma_noise* pNoise = (ma_noise*)pDataSource; *pFormat = pNoise->config.format; *pChannels = pNoise->config.channels; *pSampleRate = 0; /* There is no notion of sample rate with noise generation. */ - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pNoise->config.channels); return MA_SUCCESS; } -static ma_data_source_vtable g_ma_noise_data_source_vtable = +MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) { - ma_noise__data_source_on_read, - ma_noise__data_source_on_seek, /* No-op for noise. */ - ma_noise__data_source_on_get_data_format, - NULL, /* onGetCursor. No notion of a cursor for noise. */ - NULL, /* onGetLength. No notion of a length for noise. */ - NULL, /* onSetLooping */ - 0 -}; - - -#ifndef MA_PINK_NOISE_BIN_SIZE -#define MA_PINK_NOISE_BIN_SIZE 16 -#endif - -typedef struct -{ - size_t sizeInBytes; - struct - { - size_t binOffset; - size_t accumulationOffset; - size_t counterOffset; - } pink; - struct - { - size_t accumulationOffset; - } brownian; -} ma_noise_heap_layout; - -static ma_result ma_noise_get_heap_layout(const ma_noise_config* pConfig, ma_noise_heap_layout* pHeapLayout) -{ - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels == 0) { - return MA_INVALID_ARGS; - } - - pHeapLayout->sizeInBytes = 0; - - /* Pink. */ - if (pConfig->type == ma_noise_type_pink) { - /* bin */ - pHeapLayout->pink.binOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(double*) * pConfig->channels; - pHeapLayout->sizeInBytes += sizeof(double ) * pConfig->channels * MA_PINK_NOISE_BIN_SIZE; - - /* accumulation */ - pHeapLayout->pink.accumulationOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels; - - /* counter */ - pHeapLayout->pink.counterOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(ma_uint32) * pConfig->channels; - } - - /* Brownian. */ - if (pConfig->type == ma_noise_type_brownian) { - /* accumulation */ - pHeapLayout->brownian.accumulationOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels; - } - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_noise_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_noise_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise) -{ - ma_result result; - ma_noise_heap_layout heapLayout; - ma_data_source_config dataSourceConfig; - ma_uint32 iChannel; - if (pNoise == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pNoise); - result = ma_noise_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; + if (pConfig == NULL) { + return MA_INVALID_ARGS; } - pNoise->_pHeap = pHeap; - MA_ZERO_MEMORY(pNoise->_pHeap, heapLayout.sizeInBytes); - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_noise_data_source_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pNoise->ds); - if (result != MA_SUCCESS) { - return result; + if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; } - pNoise->config = *pConfig; + pNoise->ds.onRead = ma_noise__data_source_on_read; + pNoise->ds.onSeek = ma_noise__data_source_on_seek; /* <-- No-op for noise. */ + pNoise->ds.onGetDataFormat = ma_noise__data_source_on_get_data_format; + pNoise->ds.onGetCursor = NULL; /* No notion of a cursor for noise. */ + pNoise->ds.onGetLength = NULL; /* No notion of a length for noise. */ + pNoise->config = *pConfig; ma_lcg_seed(&pNoise->lcg, pConfig->seed); if (pNoise->config.type == ma_noise_type_pink) { - pNoise->state.pink.bin = (double** )ma_offset_ptr(pHeap, heapLayout.pink.binOffset); - pNoise->state.pink.accumulation = (double* )ma_offset_ptr(pHeap, heapLayout.pink.accumulationOffset); - pNoise->state.pink.counter = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.pink.counterOffset); - + ma_uint32 iChannel; for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { - pNoise->state.pink.bin[iChannel] = (double*)ma_offset_ptr(pHeap, heapLayout.pink.binOffset + (sizeof(double*) * pConfig->channels) + (sizeof(double) * MA_PINK_NOISE_BIN_SIZE * iChannel)); pNoise->state.pink.accumulation[iChannel] = 0; pNoise->state.pink.counter[iChannel] = 1; } } if (pNoise->config.type == ma_noise_type_brownian) { - pNoise->state.brownian.accumulation = (double*)ma_offset_ptr(pHeap, heapLayout.brownian.accumulationOffset); - + ma_uint32 iChannel; for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { pNoise->state.brownian.accumulation[iChannel] = 0; } @@ -67179,49 +48686,6 @@ MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void return MA_SUCCESS; } -MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_noise_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_noise_init_preallocated(pConfig, pHeap, pNoise); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pNoise->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pNoise == NULL) { - return; - } - - ma_data_source_uninit(&pNoise->ds); - - if (pNoise->_ownsHeap) { - ma_free(pNoise->_pHeap, pAllocationCallbacks); - } -} - MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude) { if (pNoise == NULL) { @@ -67249,15 +48713,8 @@ MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type) return MA_INVALID_ARGS; } - /* - This function should never have been implemented in the first place. Changing the type dynamically is not - supported. Instead you need to uninitialize and reinitialize a fresh `ma_noise` object. This function - will be removed in version 0.12. - */ - MA_ASSERT(MA_FALSE); - (void)type; - - return MA_INVALID_OPERATION; + pNoise->config.type = type; + return MA_SUCCESS; } static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise) @@ -67275,7 +48732,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -67369,7 +48826,7 @@ static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel) double binNext; unsigned int ibin; - ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (MA_PINK_NOISE_BIN_SIZE - 1); + ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (ma_countof(pNoise->state.pink.bin[0]) - 1); binPrev = pNoise->state.pink.bin[iChannel][ibin]; binNext = ma_lcg_rand_f64(&pNoise->lcg); @@ -67394,7 +48851,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -67476,7 +48933,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; - MA_ASSUME(channels > 0); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -67534,10666 +48991,193 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, return frameCount; } -MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) { - ma_uint64 framesRead = 0; - - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - if (pNoise == NULL) { - return MA_INVALID_ARGS; + return 0; } /* The output buffer is allowed to be NULL. Since we aren't tracking cursors or anything we can just do nothing and pretend to be successful. */ if (pFramesOut == NULL) { - framesRead = frameCount; - } else { - switch (pNoise->config.type) { - case ma_noise_type_white: framesRead = ma_noise_read_pcm_frames__white (pNoise, pFramesOut, frameCount); break; - case ma_noise_type_pink: framesRead = ma_noise_read_pcm_frames__pink (pNoise, pFramesOut, frameCount); break; - case ma_noise_type_brownian: framesRead = ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount); break; - default: return MA_INVALID_OPERATION; /* Unknown noise type. */ - } + return frameCount; } - if (pFramesRead != NULL) { - *pFramesRead = framesRead; + if (pNoise->config.type == ma_noise_type_white) { + return ma_noise_read_pcm_frames__white(pNoise, pFramesOut, frameCount); } - return MA_SUCCESS; + if (pNoise->config.type == ma_noise_type_pink) { + return ma_noise_read_pcm_frames__pink(pNoise, pFramesOut, frameCount); + } + + if (pNoise->config.type == ma_noise_type_brownian) { + return ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount); + } + + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return 0; } #endif /* MA_NO_GENERATION */ -#ifndef MA_NO_RESOURCE_MANAGER -#ifndef MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS -#define MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS 1000 -#endif - -#ifndef MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY -#define MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY 1024 -#endif - -MA_API ma_resource_manager_pipeline_notifications ma_resource_manager_pipeline_notifications_init(void) -{ - ma_resource_manager_pipeline_notifications notifications; - - MA_ZERO_OBJECT(¬ifications); - - return notifications; -} - -static void ma_resource_manager_pipeline_notifications_signal_all_notifications(const ma_resource_manager_pipeline_notifications* pPipelineNotifications) -{ - if (pPipelineNotifications == NULL) { - return; - } - - if (pPipelineNotifications->init.pNotification) { ma_async_notification_signal(pPipelineNotifications->init.pNotification); } - if (pPipelineNotifications->done.pNotification) { ma_async_notification_signal(pPipelineNotifications->done.pNotification); } -} - -static void ma_resource_manager_pipeline_notifications_acquire_all_fences(const ma_resource_manager_pipeline_notifications* pPipelineNotifications) -{ - if (pPipelineNotifications == NULL) { - return; - } - - if (pPipelineNotifications->init.pFence != NULL) { ma_fence_acquire(pPipelineNotifications->init.pFence); } - if (pPipelineNotifications->done.pFence != NULL) { ma_fence_acquire(pPipelineNotifications->done.pFence); } -} - -static void ma_resource_manager_pipeline_notifications_release_all_fences(const ma_resource_manager_pipeline_notifications* pPipelineNotifications) -{ - if (pPipelineNotifications == NULL) { - return; - } - - if (pPipelineNotifications->init.pFence != NULL) { ma_fence_release(pPipelineNotifications->init.pFence); } - if (pPipelineNotifications->done.pFence != NULL) { ma_fence_release(pPipelineNotifications->done.pFence); } -} - - - -#ifndef MA_DEFAULT_HASH_SEED -#define MA_DEFAULT_HASH_SEED 42 -#endif - -/* MurmurHash3. Based on code from https://github.com/PeterScott/murmur3/blob/master/murmur3.c (public domain). */ -#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic push - #if __GNUC__ >= 7 - #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" - #endif -#endif - -static MA_INLINE ma_uint32 ma_rotl32(ma_uint32 x, ma_int8 r) -{ - return (x << r) | (x >> (32 - r)); -} - -static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i) -{ - ma_uint32 block; - - /* Try silencing a sanitization warning about unaligned access by doing a memcpy() instead of assignment. */ - MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block)); - - if (ma_is_little_endian()) { - return block; - } else { - return ma_swap_endian_uint32(block); - } -} - -static MA_INLINE ma_uint32 ma_hash_fmix32(ma_uint32 h) -{ - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -static ma_uint32 ma_hash_32(const void* key, int len, ma_uint32 seed) -{ - const ma_uint8* data = (const ma_uint8*)key; - const ma_uint32* blocks; - const ma_uint8* tail; - const int nblocks = len / 4; - ma_uint32 h1 = seed; - ma_uint32 c1 = 0xcc9e2d51; - ma_uint32 c2 = 0x1b873593; - ma_uint32 k1; - int i; - - blocks = (const ma_uint32 *)(data + nblocks*4); - - for(i = -nblocks; i; i++) { - k1 = ma_hash_getblock(blocks,i); - - k1 *= c1; - k1 = ma_rotl32(k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = ma_rotl32(h1, 13); - h1 = h1*5 + 0xe6546b64; - } - - - tail = (const ma_uint8*)(data + nblocks*4); - - k1 = 0; - switch(len & 3) { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0]; - k1 *= c1; k1 = ma_rotl32(k1, 15); k1 *= c2; h1 ^= k1; - }; - - - h1 ^= len; - h1 = ma_hash_fmix32(h1); - - return h1; -} - -#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic push -#endif -/* End MurmurHash3 */ - -static ma_uint32 ma_hash_string_32(const char* str) -{ - return ma_hash_32(str, (int)strlen(str), MA_DEFAULT_HASH_SEED); -} - -static ma_uint32 ma_hash_string_w_32(const wchar_t* str) -{ - return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); -} - - - - -/* -Basic BST Functions -*/ -static ma_result ma_resource_manager_data_buffer_node_search(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_resource_manager_data_buffer_node** ppDataBufferNode) -{ - ma_resource_manager_data_buffer_node* pCurrentNode; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(ppDataBufferNode != NULL); - - pCurrentNode = pResourceManager->pRootDataBufferNode; - while (pCurrentNode != NULL) { - if (hashedName32 == pCurrentNode->hashedName32) { - break; /* Found. */ - } else if (hashedName32 < pCurrentNode->hashedName32) { - pCurrentNode = pCurrentNode->pChildLo; - } else { - pCurrentNode = pCurrentNode->pChildHi; - } - } - - *ppDataBufferNode = pCurrentNode; - - if (pCurrentNode == NULL) { - return MA_DOES_NOT_EXIST; - } else { - return MA_SUCCESS; - } -} - -static ma_result ma_resource_manager_data_buffer_node_insert_point(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_resource_manager_data_buffer_node** ppInsertPoint) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager_data_buffer_node* pCurrentNode; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(ppInsertPoint != NULL); - - *ppInsertPoint = NULL; - - if (pResourceManager->pRootDataBufferNode == NULL) { - return MA_SUCCESS; /* No items. */ - } - - /* We need to find the node that will become the parent of the new node. If a node is found that already has the same hashed name we need to return MA_ALREADY_EXISTS. */ - pCurrentNode = pResourceManager->pRootDataBufferNode; - while (pCurrentNode != NULL) { - if (hashedName32 == pCurrentNode->hashedName32) { - result = MA_ALREADY_EXISTS; - break; - } else { - if (hashedName32 < pCurrentNode->hashedName32) { - if (pCurrentNode->pChildLo == NULL) { - result = MA_SUCCESS; - break; - } else { - pCurrentNode = pCurrentNode->pChildLo; - } - } else { - if (pCurrentNode->pChildHi == NULL) { - result = MA_SUCCESS; - break; - } else { - pCurrentNode = pCurrentNode->pChildHi; - } - } - } - } - - *ppInsertPoint = pCurrentNode; - return result; -} - -static ma_result ma_resource_manager_data_buffer_node_insert_at(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_resource_manager_data_buffer_node* pInsertPoint) -{ - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - - /* The key must have been set before calling this function. */ - MA_ASSERT(pDataBufferNode->hashedName32 != 0); - - if (pInsertPoint == NULL) { - /* It's the first node. */ - pResourceManager->pRootDataBufferNode = pDataBufferNode; - } else { - /* It's not the first node. It needs to be inserted. */ - if (pDataBufferNode->hashedName32 < pInsertPoint->hashedName32) { - MA_ASSERT(pInsertPoint->pChildLo == NULL); - pInsertPoint->pChildLo = pDataBufferNode; - } else { - MA_ASSERT(pInsertPoint->pChildHi == NULL); - pInsertPoint->pChildHi = pDataBufferNode; - } - } - - pDataBufferNode->pParent = pInsertPoint; - - return MA_SUCCESS; -} - -#if 0 /* Unused for now. */ -static ma_result ma_resource_manager_data_buffer_node_insert(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - ma_result result; - ma_resource_manager_data_buffer_node* pInsertPoint; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - - result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, pDataBufferNode->hashedName32, &pInsertPoint); - if (result != MA_SUCCESS) { - return MA_INVALID_ARGS; - } - - return ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint); -} -#endif - -static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_min(ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - ma_resource_manager_data_buffer_node* pCurrentNode; - - MA_ASSERT(pDataBufferNode != NULL); - - pCurrentNode = pDataBufferNode; - while (pCurrentNode->pChildLo != NULL) { - pCurrentNode = pCurrentNode->pChildLo; - } - - return pCurrentNode; -} - -static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_max(ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - ma_resource_manager_data_buffer_node* pCurrentNode; - - MA_ASSERT(pDataBufferNode != NULL); - - pCurrentNode = pDataBufferNode; - while (pCurrentNode->pChildHi != NULL) { - pCurrentNode = pCurrentNode->pChildHi; - } - - return pCurrentNode; -} - -static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_successor(ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - MA_ASSERT(pDataBufferNode != NULL); - MA_ASSERT(pDataBufferNode->pChildHi != NULL); - - return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi); -} - -static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - MA_ASSERT(pDataBufferNode != NULL); - MA_ASSERT(pDataBufferNode->pChildLo != NULL); - - return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo); -} - -static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - - if (pDataBufferNode->pChildLo == NULL) { - if (pDataBufferNode->pChildHi == NULL) { - /* Simple case - deleting a buffer with no children. */ - if (pDataBufferNode->pParent == NULL) { - MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode); /* There is only a single buffer in the tree which should be equal to the root node. */ - pResourceManager->pRootDataBufferNode = NULL; - } else { - if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { - pDataBufferNode->pParent->pChildLo = NULL; - } else { - pDataBufferNode->pParent->pChildHi = NULL; - } - } - } else { - /* Node has one child - pChildHi != NULL. */ - pDataBufferNode->pChildHi->pParent = pDataBufferNode->pParent; - - if (pDataBufferNode->pParent == NULL) { - MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode); - pResourceManager->pRootDataBufferNode = pDataBufferNode->pChildHi; - } else { - if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { - pDataBufferNode->pParent->pChildLo = pDataBufferNode->pChildHi; - } else { - pDataBufferNode->pParent->pChildHi = pDataBufferNode->pChildHi; - } - } - } - } else { - if (pDataBufferNode->pChildHi == NULL) { - /* Node has one child - pChildLo != NULL. */ - pDataBufferNode->pChildLo->pParent = pDataBufferNode->pParent; - - if (pDataBufferNode->pParent == NULL) { - MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode); - pResourceManager->pRootDataBufferNode = pDataBufferNode->pChildLo; - } else { - if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { - pDataBufferNode->pParent->pChildLo = pDataBufferNode->pChildLo; - } else { - pDataBufferNode->pParent->pChildHi = pDataBufferNode->pChildLo; - } - } - } else { - /* Complex case - deleting a node with two children. */ - ma_resource_manager_data_buffer_node* pReplacementDataBufferNode; - - /* For now we are just going to use the in-order successor as the replacement, but we may want to try to keep this balanced by switching between the two. */ - pReplacementDataBufferNode = ma_resource_manager_data_buffer_node_find_inorder_successor(pDataBufferNode); - MA_ASSERT(pReplacementDataBufferNode != NULL); - - /* - Now that we have our replacement node we can make the change. The simple way to do this would be to just exchange the values, and then remove the replacement - node, however we track specific nodes via pointers which means we can't just swap out the values. We need to instead just change the pointers around. The - replacement node should have at most 1 child. Therefore, we can detach it in terms of our simpler cases above. What we're essentially doing is detaching the - replacement node and reinserting it into the same position as the deleted node. - */ - MA_ASSERT(pReplacementDataBufferNode->pParent != NULL); /* The replacement node should never be the root which means it should always have a parent. */ - MA_ASSERT(pReplacementDataBufferNode->pChildLo == NULL); /* Because we used in-order successor. This would be pChildHi == NULL if we used in-order predecessor. */ - - if (pReplacementDataBufferNode->pChildHi == NULL) { - if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) { - pReplacementDataBufferNode->pParent->pChildLo = NULL; - } else { - pReplacementDataBufferNode->pParent->pChildHi = NULL; - } - } else { - pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode->pParent; - if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) { - pReplacementDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode->pChildHi; - } else { - pReplacementDataBufferNode->pParent->pChildHi = pReplacementDataBufferNode->pChildHi; - } - } - - - /* The replacement node has essentially been detached from the binary tree, so now we need to replace the old data buffer with it. The first thing to update is the parent */ - if (pDataBufferNode->pParent != NULL) { - if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { - pDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode; - } else { - pDataBufferNode->pParent->pChildHi = pReplacementDataBufferNode; - } - } - - /* Now need to update the replacement node's pointers. */ - pReplacementDataBufferNode->pParent = pDataBufferNode->pParent; - pReplacementDataBufferNode->pChildLo = pDataBufferNode->pChildLo; - pReplacementDataBufferNode->pChildHi = pDataBufferNode->pChildHi; - - /* Now the children of the replacement node need to have their parent pointers updated. */ - if (pReplacementDataBufferNode->pChildLo != NULL) { - pReplacementDataBufferNode->pChildLo->pParent = pReplacementDataBufferNode; - } - if (pReplacementDataBufferNode->pChildHi != NULL) { - pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode; - } - - /* Now the root node needs to be updated. */ - if (pResourceManager->pRootDataBufferNode == pDataBufferNode) { - pResourceManager->pRootDataBufferNode = pReplacementDataBufferNode; - } - } - } - - return MA_SUCCESS; -} - -#if 0 /* Unused for now. */ -static ma_result ma_resource_manager_data_buffer_node_remove_by_key(ma_resource_manager* pResourceManager, ma_uint32 hashedName32) -{ - ma_result result; - ma_resource_manager_data_buffer_node* pDataBufferNode; - - result = ma_resource_manager_data_buffer_search(pResourceManager, hashedName32, &pDataBufferNode); - if (result != MA_SUCCESS) { - return result; /* Could not find the data buffer. */ - } - - return ma_resource_manager_data_buffer_remove(pResourceManager, pDataBufferNode); -} -#endif - -static ma_resource_manager_data_supply_type ma_resource_manager_data_buffer_node_get_data_supply_type(ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - return (ma_resource_manager_data_supply_type)ma_atomic_load_i32(&pDataBufferNode->data.type); -} - -static void ma_resource_manager_data_buffer_node_set_data_supply_type(ma_resource_manager_data_buffer_node* pDataBufferNode, ma_resource_manager_data_supply_type supplyType) -{ - ma_atomic_exchange_i32(&pDataBufferNode->data.type, supplyType); -} - -static ma_result ma_resource_manager_data_buffer_node_increment_ref(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_uint32* pNewRefCount) -{ - ma_uint32 refCount; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - - (void)pResourceManager; - - refCount = ma_atomic_fetch_add_32(&pDataBufferNode->refCount, 1) + 1; - - if (pNewRefCount != NULL) { - *pNewRefCount = refCount; - } - - return MA_SUCCESS; -} - -static ma_result ma_resource_manager_data_buffer_node_decrement_ref(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_uint32* pNewRefCount) -{ - ma_uint32 refCount; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - - (void)pResourceManager; - - refCount = ma_atomic_fetch_sub_32(&pDataBufferNode->refCount, 1) - 1; - - if (pNewRefCount != NULL) { - *pNewRefCount = refCount; - } - - return MA_SUCCESS; -} - -static void ma_resource_manager_data_buffer_node_free(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - - if (pDataBufferNode->isDataOwnedByResourceManager) { - if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_encoded) { - ma_free((void*)pDataBufferNode->data.backend.encoded.pData, &pResourceManager->config.allocationCallbacks); - pDataBufferNode->data.backend.encoded.pData = NULL; - pDataBufferNode->data.backend.encoded.sizeInBytes = 0; - } else if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_decoded) { - ma_free((void*)pDataBufferNode->data.backend.decoded.pData, &pResourceManager->config.allocationCallbacks); - pDataBufferNode->data.backend.decoded.pData = NULL; - pDataBufferNode->data.backend.decoded.totalFrameCount = 0; - } else if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_decoded_paged) { - ma_paged_audio_buffer_data_uninit(&pDataBufferNode->data.backend.decodedPaged.data, &pResourceManager->config.allocationCallbacks); - } else { - /* Should never hit this if the node was successfully initialized. */ - MA_ASSERT(pDataBufferNode->result != MA_SUCCESS); - } - } - - /* The data buffer itself needs to be freed. */ - ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); -} - -static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - MA_ASSERT(pDataBufferNode != NULL); - - return (ma_result)ma_atomic_load_i32((ma_result*)&pDataBufferNode->result); /* Need a naughty const-cast here. */ -} - - -static ma_bool32 ma_resource_manager_is_threading_enabled(const ma_resource_manager* pResourceManager) -{ - MA_ASSERT(pResourceManager != NULL); - - return (pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) == 0; -} - - -typedef struct -{ - union - { - ma_async_notification_event e; - ma_async_notification_poll p; - } backend; /* Must be the first member. */ - ma_resource_manager* pResourceManager; -} ma_resource_manager_inline_notification; - -static ma_result ma_resource_manager_inline_notification_init(ma_resource_manager* pResourceManager, ma_resource_manager_inline_notification* pNotification) -{ - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pNotification != NULL); - - pNotification->pResourceManager = pResourceManager; - - if (ma_resource_manager_is_threading_enabled(pResourceManager)) { - return ma_async_notification_event_init(&pNotification->backend.e); - } else { - return ma_async_notification_poll_init(&pNotification->backend.p); - } -} - -static void ma_resource_manager_inline_notification_uninit(ma_resource_manager_inline_notification* pNotification) -{ - MA_ASSERT(pNotification != NULL); - - if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) { - ma_async_notification_event_uninit(&pNotification->backend.e); - } else { - /* No need to uninitialize a polling notification. */ - } -} - -static void ma_resource_manager_inline_notification_wait(ma_resource_manager_inline_notification* pNotification) -{ - MA_ASSERT(pNotification != NULL); - - if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) { - ma_async_notification_event_wait(&pNotification->backend.e); - } else { - while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) { - ma_result result = ma_resource_manager_process_next_job(pNotification->pResourceManager); - if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) { - break; - } - } - } -} - -static void ma_resource_manager_inline_notification_wait_and_uninit(ma_resource_manager_inline_notification* pNotification) -{ - ma_resource_manager_inline_notification_wait(pNotification); - ma_resource_manager_inline_notification_uninit(pNotification); -} - - -static void ma_resource_manager_data_buffer_bst_lock(ma_resource_manager* pResourceManager) -{ - MA_ASSERT(pResourceManager != NULL); - - if (ma_resource_manager_is_threading_enabled(pResourceManager)) { - #ifndef MA_NO_THREADING - { - ma_mutex_lock(&pResourceManager->dataBufferBSTLock); - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never hit this. */ - } - #endif - } else { - /* Threading not enabled. Do nothing. */ - } -} - -static void ma_resource_manager_data_buffer_bst_unlock(ma_resource_manager* pResourceManager) -{ - MA_ASSERT(pResourceManager != NULL); - - if (ma_resource_manager_is_threading_enabled(pResourceManager)) { - #ifndef MA_NO_THREADING - { - ma_mutex_unlock(&pResourceManager->dataBufferBSTLock); - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never hit this. */ - } - #endif - } else { - /* Threading not enabled. Do nothing. */ - } -} - -#ifndef MA_NO_THREADING -static ma_thread_result MA_THREADCALL ma_resource_manager_job_thread(void* pUserData) -{ - ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData; - MA_ASSERT(pResourceManager != NULL); - - for (;;) { - ma_result result; - ma_job job; - - result = ma_resource_manager_next_job(pResourceManager, &job); - if (result != MA_SUCCESS) { - break; - } - - /* Terminate if we got a quit message. */ - if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) { - break; - } - - ma_job_process(&job); - } - - return (ma_thread_result)0; -} -#endif - -MA_API ma_resource_manager_config ma_resource_manager_config_init(void) -{ - ma_resource_manager_config config; - - MA_ZERO_OBJECT(&config); - config.decodedFormat = ma_format_unknown; - config.decodedChannels = 0; - config.decodedSampleRate = 0; - config.jobThreadCount = 1; /* A single miniaudio-managed job thread by default. */ - config.jobQueueCapacity = MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY; - - /* Flags. */ - config.flags = 0; - #ifdef MA_NO_THREADING - { - /* Threading is disabled at compile time so disable threading at runtime as well by default. */ - config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; - config.jobThreadCount = 0; - } - #endif - - return config; -} - - -MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager) -{ - ma_result result; - ma_job_queue_config jobQueueConfig; - - if (pResourceManager == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pResourceManager); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - #ifndef MA_NO_THREADING - { - if (pConfig->jobThreadCount > ma_countof(pResourceManager->jobThreads)) { - return MA_INVALID_ARGS; /* Requesting too many job threads. */ - } - } - #endif - - pResourceManager->config = *pConfig; - ma_allocation_callbacks_init_copy(&pResourceManager->config.allocationCallbacks, &pConfig->allocationCallbacks); - - /* Get the log set up early so we can start using it as soon as possible. */ - if (pResourceManager->config.pLog == NULL) { - result = ma_log_init(&pResourceManager->config.allocationCallbacks, &pResourceManager->log); - if (result == MA_SUCCESS) { - pResourceManager->config.pLog = &pResourceManager->log; - } else { - pResourceManager->config.pLog = NULL; /* Logging is unavailable. */ - } - } - - if (pResourceManager->config.pVFS == NULL) { - result = ma_default_vfs_init(&pResourceManager->defaultVFS, &pResourceManager->config.allocationCallbacks); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the default file system. */ - } - - pResourceManager->config.pVFS = &pResourceManager->defaultVFS; - } - - /* If threading has been disabled at compile time, enforce it at run time as well. */ - #ifdef MA_NO_THREADING - { - pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; - } - #endif - - /* We need to force MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING if MA_RESOURCE_MANAGER_FLAG_NO_THREADING is set. */ - if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) { - pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; - - /* We cannot allow job threads when MA_RESOURCE_MANAGER_FLAG_NO_THREADING has been set. This is an invalid use case. */ - if (pResourceManager->config.jobThreadCount > 0) { - return MA_INVALID_ARGS; - } - } - - /* Job queue. */ - jobQueueConfig.capacity = pResourceManager->config.jobQueueCapacity; - jobQueueConfig.flags = 0; - if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING) != 0) { - if (pResourceManager->config.jobThreadCount > 0) { - return MA_INVALID_ARGS; /* Non-blocking mode is only valid for self-managed job threads. */ - } - - jobQueueConfig.flags |= MA_JOB_QUEUE_FLAG_NON_BLOCKING; - } - - result = ma_job_queue_init(&jobQueueConfig, &pResourceManager->config.allocationCallbacks, &pResourceManager->jobQueue); - if (result != MA_SUCCESS) { - return result; - } - - - /* Custom decoding backends. */ - if (pConfig->ppCustomDecodingBackendVTables != NULL && pConfig->customDecodingBackendCount > 0) { - size_t sizeInBytes = sizeof(*pResourceManager->config.ppCustomDecodingBackendVTables) * pConfig->customDecodingBackendCount; - ma_decoding_backend_vtable** ppCustomDecodingBackendVTables; - - ppCustomDecodingBackendVTables = (ma_decoding_backend_vtable**)ma_malloc(sizeInBytes, &pResourceManager->config.allocationCallbacks); - if (pResourceManager->config.ppCustomDecodingBackendVTables == NULL) { - ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - - MA_COPY_MEMORY(ppCustomDecodingBackendVTables, pConfig->ppCustomDecodingBackendVTables, sizeInBytes); - - pResourceManager->config.ppCustomDecodingBackendVTables = ppCustomDecodingBackendVTables; - pResourceManager->config.customDecodingBackendCount = pConfig->customDecodingBackendCount; - pResourceManager->config.pCustomDecodingBackendUserData = pConfig->pCustomDecodingBackendUserData; - } - - - - /* Here is where we initialize our threading stuff. We don't do this if we don't support threading. */ - if (ma_resource_manager_is_threading_enabled(pResourceManager)) { - #ifndef MA_NO_THREADING - { - ma_uint32 iJobThread; - - /* Data buffer lock. */ - result = ma_mutex_init(&pResourceManager->dataBufferBSTLock); - if (result != MA_SUCCESS) { - ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); - return result; - } - - /* Create the job threads last to ensure the threads has access to valid data. */ - for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) { - result = ma_thread_create(&pResourceManager->jobThreads[iJobThread], ma_thread_priority_normal, pResourceManager->config.jobThreadStackSize, ma_resource_manager_job_thread, pResourceManager, &pResourceManager->config.allocationCallbacks); - if (result != MA_SUCCESS) { - ma_mutex_uninit(&pResourceManager->dataBufferBSTLock); - ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); - return result; - } - } - } - #else - { - /* Threading is disabled at compile time. We should never get here because validation checks should have already been performed. */ - MA_ASSERT(MA_FALSE); - } - #endif - } - - return MA_SUCCESS; -} - - -static void ma_resource_manager_delete_all_data_buffer_nodes(ma_resource_manager* pResourceManager) -{ - MA_ASSERT(pResourceManager); - - /* If everything was done properly, there shouldn't be any active data buffers. */ - while (pResourceManager->pRootDataBufferNode != NULL) { - ma_resource_manager_data_buffer_node* pDataBufferNode = pResourceManager->pRootDataBufferNode; - ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); - - /* The data buffer has been removed from the BST, so now we need to free its data. */ - ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); - } -} - -MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager) -{ - if (pResourceManager == NULL) { - return; - } - - /* - Job threads need to be killed first. To do this we need to post a quit message to the message queue and then wait for the thread. The quit message will never be removed from the - queue which means it will never not be returned after being encountered for the first time which means all threads will eventually receive it. - */ - ma_resource_manager_post_job_quit(pResourceManager); - - /* Wait for every job to finish before continuing to ensure nothing is sill trying to access any of our objects below. */ - if (ma_resource_manager_is_threading_enabled(pResourceManager)) { - #ifndef MA_NO_THREADING - { - ma_uint32 iJobThread; - - for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) { - ma_thread_wait(&pResourceManager->jobThreads[iJobThread]); - } - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never hit this. */ - } - #endif - } - - /* At this point the thread should have returned and no other thread should be accessing our data. We can now delete all data buffers. */ - ma_resource_manager_delete_all_data_buffer_nodes(pResourceManager); - - /* The job queue is no longer needed. */ - ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); - - /* We're no longer doing anything with data buffers so the lock can now be uninitialized. */ - if (ma_resource_manager_is_threading_enabled(pResourceManager)) { - #ifndef MA_NO_THREADING - { - ma_mutex_uninit(&pResourceManager->dataBufferBSTLock); - } - #else - { - MA_ASSERT(MA_FALSE); /* Should never hit this. */ - } - #endif - } - - ma_free((ma_decoding_backend_vtable**)pResourceManager->config.ppCustomDecodingBackendVTables, &pResourceManager->config.allocationCallbacks); /* <-- Naughty const-cast, but this is safe. */ - - if (pResourceManager->config.pLog == &pResourceManager->log) { - ma_log_uninit(&pResourceManager->log); - } -} - -MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager) -{ - if (pResourceManager == NULL) { - return NULL; - } - - return pResourceManager->config.pLog; -} - - - -MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void) -{ - ma_resource_manager_data_source_config config; - - MA_ZERO_OBJECT(&config); - config.rangeBegInPCMFrames = MA_DATA_SOURCE_DEFAULT_RANGE_BEG; - config.rangeEndInPCMFrames = MA_DATA_SOURCE_DEFAULT_RANGE_END; - config.loopPointBegInPCMFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG; - config.loopPointEndInPCMFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END; - config.isLooping = MA_FALSE; - - return config; -} - - -static ma_decoder_config ma_resource_manager__init_decoder_config(ma_resource_manager* pResourceManager) -{ - ma_decoder_config config; - - config = ma_decoder_config_init(pResourceManager->config.decodedFormat, pResourceManager->config.decodedChannels, pResourceManager->config.decodedSampleRate); - config.allocationCallbacks = pResourceManager->config.allocationCallbacks; - config.ppCustomBackendVTables = pResourceManager->config.ppCustomDecodingBackendVTables; - config.customBackendCount = pResourceManager->config.customDecodingBackendCount; - config.pCustomBackendUserData = pResourceManager->config.pCustomDecodingBackendUserData; - - return config; -} - -static ma_result ma_resource_manager__init_decoder(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_decoder* pDecoder) -{ - ma_result result; - ma_decoder_config config; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pFilePath != NULL || pFilePathW != NULL); - MA_ASSERT(pDecoder != NULL); - - config = ma_resource_manager__init_decoder_config(pResourceManager); - - if (pFilePath != NULL) { - result = ma_decoder_init_vfs(pResourceManager->config.pVFS, pFilePath, &config, pDecoder); - if (result != MA_SUCCESS) { - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%s\". %s.\n", pFilePath, ma_result_description(result)); - return result; - } - } else { - result = ma_decoder_init_vfs_w(pResourceManager->config.pVFS, pFilePathW, &config, pDecoder); - if (result != MA_SUCCESS) { - #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%ls\". %s.\n", pFilePathW, ma_result_description(result)); - #endif - return result; - } - } - - return MA_SUCCESS; -} - -static ma_bool32 ma_resource_manager_data_buffer_has_connector(ma_resource_manager_data_buffer* pDataBuffer) -{ - return ma_atomic_bool32_get(&pDataBuffer->isConnectorInitialized); -} - -static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource_manager_data_buffer* pDataBuffer) -{ - if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE) { - return NULL; /* Connector not yet initialized. */ - } - - switch (pDataBuffer->pNode->data.type) - { - case ma_resource_manager_data_supply_type_encoded: return &pDataBuffer->connector.decoder; - case ma_resource_manager_data_supply_type_decoded: return &pDataBuffer->connector.buffer; - case ma_resource_manager_data_supply_type_decoded_paged: return &pDataBuffer->connector.pagedBuffer; - - case ma_resource_manager_data_supply_type_unknown: - default: - { - ma_log_postf(ma_resource_manager_get_log(pDataBuffer->pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to retrieve data buffer connector. Unknown data supply type.\n"); - return NULL; - }; - }; -} - -static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_manager_data_buffer* pDataBuffer, const ma_resource_manager_data_source_config* pConfig, ma_async_notification* pInitNotification, ma_fence* pInitFence) -{ - ma_result result; - - MA_ASSERT(pDataBuffer != NULL); - MA_ASSERT(pConfig != NULL); - MA_ASSERT(ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE); - - /* The underlying data buffer must be initialized before we'll be able to know how to initialize the backend. */ - result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode); - if (result != MA_SUCCESS && result != MA_BUSY) { - return result; /* The data buffer is in an erroneous state. */ - } - - /* - We need to initialize either a ma_decoder or an ma_audio_buffer depending on whether or not the backing data is encoded or decoded. These act as the - "instance" to the data and are used to form the connection between underlying data buffer and the data source. If the data buffer is decoded, we can use - an ma_audio_buffer. This enables us to use memory mapping when mixing which saves us a bit of data movement overhead. - */ - switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) - { - case ma_resource_manager_data_supply_type_encoded: /* Connector is a decoder. */ - { - ma_decoder_config config; - config = ma_resource_manager__init_decoder_config(pDataBuffer->pResourceManager); - result = ma_decoder_init_memory(pDataBuffer->pNode->data.backend.encoded.pData, pDataBuffer->pNode->data.backend.encoded.sizeInBytes, &config, &pDataBuffer->connector.decoder); - } break; - - case ma_resource_manager_data_supply_type_decoded: /* Connector is an audio buffer. */ - { - ma_audio_buffer_config config; - config = ma_audio_buffer_config_init(pDataBuffer->pNode->data.backend.decoded.format, pDataBuffer->pNode->data.backend.decoded.channels, pDataBuffer->pNode->data.backend.decoded.totalFrameCount, pDataBuffer->pNode->data.backend.decoded.pData, NULL); - result = ma_audio_buffer_init(&config, &pDataBuffer->connector.buffer); - } break; - - case ma_resource_manager_data_supply_type_decoded_paged: /* Connector is a paged audio buffer. */ - { - ma_paged_audio_buffer_config config; - config = ma_paged_audio_buffer_config_init(&pDataBuffer->pNode->data.backend.decodedPaged.data); - result = ma_paged_audio_buffer_init(&config, &pDataBuffer->connector.pagedBuffer); - } break; - - case ma_resource_manager_data_supply_type_unknown: - default: - { - /* Unknown data supply type. Should never happen. Need to post an error here. */ - return MA_INVALID_ARGS; - }; - } - - /* - Initialization of the connector is when we can fire the init notification. This will give the application access to - the format/channels/rate of the data source. - */ - if (result == MA_SUCCESS) { - /* - The resource manager supports the ability to set the range and loop settings via a config at - initialization time. This results in an case where the ranges could be set explicitly via - ma_data_source_set_*() before we get to this point here. If this happens, we'll end up - hitting a case where we just override those settings which results in what feels like a bug. - - To address this we only change the relevant properties if they're not equal to defaults. If - they're equal to defaults there's no need to change them anyway. If they're *not* set to the - default values, we can assume the user has set the range and loop settings via the config. If - they're doing their own calls to ma_data_source_set_*() in addition to setting them via the - config, that's entirely on the caller and any synchronization issue becomes their problem. - */ - if (pConfig->rangeBegInPCMFrames != MA_DATA_SOURCE_DEFAULT_RANGE_BEG || pConfig->rangeEndInPCMFrames != MA_DATA_SOURCE_DEFAULT_RANGE_END) { - ma_data_source_set_range_in_pcm_frames(pDataBuffer, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); - } - - if (pConfig->loopPointBegInPCMFrames != MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG || pConfig->loopPointEndInPCMFrames != MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END) { - ma_data_source_set_loop_point_in_pcm_frames(pDataBuffer, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); - } - - if (pConfig->isLooping != MA_FALSE) { - ma_data_source_set_looping(pDataBuffer, pConfig->isLooping); - } - - ma_atomic_bool32_set(&pDataBuffer->isConnectorInitialized, MA_TRUE); - - if (pInitNotification != NULL) { - ma_async_notification_signal(pInitNotification); - } - - if (pInitFence != NULL) { - ma_fence_release(pInitFence); - } - } - - /* At this point the backend should be initialized. We do *not* want to set pDataSource->result here - that needs to be done at a higher level to ensure it's done as the last step. */ - return result; -} - -static ma_result ma_resource_manager_data_buffer_uninit_connector(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer* pDataBuffer) -{ - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBuffer != NULL); - - (void)pResourceManager; - - switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) - { - case ma_resource_manager_data_supply_type_encoded: /* Connector is a decoder. */ - { - ma_decoder_uninit(&pDataBuffer->connector.decoder); - } break; - - case ma_resource_manager_data_supply_type_decoded: /* Connector is an audio buffer. */ - { - ma_audio_buffer_uninit(&pDataBuffer->connector.buffer); - } break; - - case ma_resource_manager_data_supply_type_decoded_paged: /* Connector is a paged audio buffer. */ - { - ma_paged_audio_buffer_uninit(&pDataBuffer->connector.pagedBuffer); - } break; - - case ma_resource_manager_data_supply_type_unknown: - default: - { - /* Unknown data supply type. Should never happen. Need to post an error here. */ - return MA_INVALID_ARGS; - }; - } - - return MA_SUCCESS; -} - -static ma_uint32 ma_resource_manager_data_buffer_node_next_execution_order(ma_resource_manager_data_buffer_node* pDataBufferNode) -{ - MA_ASSERT(pDataBufferNode != NULL); - return ma_atomic_fetch_add_32(&pDataBufferNode->executionCounter, 1); -} - -static ma_result ma_resource_manager_data_buffer_node_init_supply_encoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW) -{ - ma_result result; - size_t dataSizeInBytes; - void* pData; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - MA_ASSERT(pFilePath != NULL || pFilePathW != NULL); - - result = ma_vfs_open_and_read_file_ex(pResourceManager->config.pVFS, pFilePath, pFilePathW, &pData, &dataSizeInBytes, &pResourceManager->config.allocationCallbacks); - if (result != MA_SUCCESS) { - if (pFilePath != NULL) { - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%s\". %s.\n", pFilePath, ma_result_description(result)); - } else { - #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%ls\". %s.\n", pFilePathW, ma_result_description(result)); - #endif - } - - return result; - } - - pDataBufferNode->data.backend.encoded.pData = pData; - pDataBufferNode->data.backend.encoded.sizeInBytes = dataSizeInBytes; - ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_encoded); /* <-- Must be set last. */ - - return MA_SUCCESS; -} - -static ma_result ma_resource_manager_data_buffer_node_init_supply_decoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 flags, ma_decoder** ppDecoder) -{ - ma_result result = MA_SUCCESS; - ma_decoder* pDecoder; - ma_uint64 totalFrameCount; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - MA_ASSERT(ppDecoder != NULL); - MA_ASSERT(pFilePath != NULL || pFilePathW != NULL); - - *ppDecoder = NULL; /* For safety. */ - - pDecoder = (ma_decoder*)ma_malloc(sizeof(*pDecoder), &pResourceManager->config.allocationCallbacks); - if (pDecoder == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_resource_manager__init_decoder(pResourceManager, pFilePath, pFilePathW, pDecoder); - if (result != MA_SUCCESS) { - ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); - return result; - } - - /* - At this point we have the decoder and we now need to initialize the data supply. This will - be either a decoded buffer, or a decoded paged buffer. A regular buffer is just one big heap - allocated buffer, whereas a paged buffer is a linked list of paged-sized buffers. The latter - is used when the length of a sound is unknown until a full decode has been performed. - */ - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH) == 0) { - result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount); - if (result != MA_SUCCESS) { - return result; - } - } else { - totalFrameCount = 0; - } - - if (totalFrameCount > 0) { - /* It's a known length. The data supply is a regular decoded buffer. */ - ma_uint64 dataSizeInBytes; - void* pData; - - dataSizeInBytes = totalFrameCount * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels); - if (dataSizeInBytes > MA_SIZE_MAX) { - ma_decoder_uninit(pDecoder); - ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); - return MA_TOO_BIG; - } - - pData = ma_malloc((size_t)dataSizeInBytes, &pResourceManager->config.allocationCallbacks); - if (pData == NULL) { - ma_decoder_uninit(pDecoder); - ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - - /* The buffer needs to be initialized to silence in case the caller reads from it. */ - ma_silence_pcm_frames(pData, totalFrameCount, pDecoder->outputFormat, pDecoder->outputChannels); - - /* Data has been allocated and the data supply can now be initialized. */ - pDataBufferNode->data.backend.decoded.pData = pData; - pDataBufferNode->data.backend.decoded.totalFrameCount = totalFrameCount; - pDataBufferNode->data.backend.decoded.format = pDecoder->outputFormat; - pDataBufferNode->data.backend.decoded.channels = pDecoder->outputChannels; - pDataBufferNode->data.backend.decoded.sampleRate = pDecoder->outputSampleRate; - pDataBufferNode->data.backend.decoded.decodedFrameCount = 0; - ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_decoded); /* <-- Must be set last. */ - } else { - /* - It's an unknown length. The data supply is a paged decoded buffer. Setting this up is - actually easier than the non-paged decoded buffer because we just need to initialize - a ma_paged_audio_buffer object. - */ - result = ma_paged_audio_buffer_data_init(pDecoder->outputFormat, pDecoder->outputChannels, &pDataBufferNode->data.backend.decodedPaged.data); - if (result != MA_SUCCESS) { - ma_decoder_uninit(pDecoder); - ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); - return result; - } - - pDataBufferNode->data.backend.decodedPaged.sampleRate = pDecoder->outputSampleRate; - pDataBufferNode->data.backend.decodedPaged.decodedFrameCount = 0; - ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_decoded_paged); /* <-- Must be set last. */ - } - - *ppDecoder = pDecoder; - - return MA_SUCCESS; -} - -static ma_result ma_resource_manager_data_buffer_node_decode_next_page(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_decoder* pDecoder) -{ - ma_result result = MA_SUCCESS; - ma_uint64 pageSizeInFrames; - ma_uint64 framesToTryReading; - ma_uint64 framesRead; - - MA_ASSERT(pResourceManager != NULL); - MA_ASSERT(pDataBufferNode != NULL); - MA_ASSERT(pDecoder != NULL); - - /* We need to know the size of a page in frames to know how many frames to decode. */ - pageSizeInFrames = MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (pDecoder->outputSampleRate/1000); - framesToTryReading = pageSizeInFrames; - - /* - Here is where we do the decoding of the next page. We'll run a slightly different path depending - on whether or not we're using a flat or paged buffer because the allocation of the page differs - between the two. For a flat buffer it's an offset to an already-allocated buffer. For a paged - buffer, we need to allocate a new page and attach it to the linked list. - */ - switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode)) - { - case ma_resource_manager_data_supply_type_decoded: - { - /* The destination buffer is an offset to the existing buffer. Don't read more than we originally retrieved when we first initialized the decoder. */ - void* pDst; - ma_uint64 framesRemaining = pDataBufferNode->data.backend.decoded.totalFrameCount - pDataBufferNode->data.backend.decoded.decodedFrameCount; - if (framesToTryReading > framesRemaining) { - framesToTryReading = framesRemaining; - } - - if (framesToTryReading > 0) { - pDst = ma_offset_ptr( - pDataBufferNode->data.backend.decoded.pData, - pDataBufferNode->data.backend.decoded.decodedFrameCount * ma_get_bytes_per_frame(pDataBufferNode->data.backend.decoded.format, pDataBufferNode->data.backend.decoded.channels) - ); - MA_ASSERT(pDst != NULL); - - result = ma_decoder_read_pcm_frames(pDecoder, pDst, framesToTryReading, &framesRead); - if (framesRead > 0) { - pDataBufferNode->data.backend.decoded.decodedFrameCount += framesRead; - } - } else { - framesRead = 0; - } - } break; - - case ma_resource_manager_data_supply_type_decoded_paged: - { - /* The destination buffer is a freshly allocated page. */ - ma_paged_audio_buffer_page* pPage; - - result = ma_paged_audio_buffer_data_allocate_page(&pDataBufferNode->data.backend.decodedPaged.data, framesToTryReading, NULL, &pResourceManager->config.allocationCallbacks, &pPage); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_decoder_read_pcm_frames(pDecoder, pPage->pAudioData, framesToTryReading, &framesRead); - if (result == MA_SUCCESS && framesRead > 0) { - pPage->sizeInFrames = framesRead; - - result = ma_paged_audio_buffer_data_append_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage); - if (result == MA_SUCCESS) { - pDataBufferNode->data.backend.decodedPaged.decodedFrameCount += framesRead; - } else { - /* Failed to append the page. Just abort and set the status to MA_AT_END. */ - ma_paged_audio_buffer_data_free_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage, &pResourceManager->config.allocationCallbacks); - result = MA_AT_END; - } - } else { - /* No frames were read. Free the page and just set the status to MA_AT_END. */ - ma_paged_audio_buffer_data_free_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage, &pResourceManager->config.allocationCallbacks); - result = MA_AT_END; - } - } break; - - case ma_resource_manager_data_supply_type_encoded: - case ma_resource_manager_data_supply_type_unknown: - default: - { - /* Unexpected data supply type. */ - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Unexpected data supply type (%d) when decoding page.", ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode)); - return MA_ERROR; - }; - } - - if (result == MA_SUCCESS && framesRead == 0) { - result = MA_AT_END; - } - - return result; -} - -static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_inline_notification* pInitNotification, ma_resource_manager_data_buffer_node** ppDataBufferNode) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager_data_buffer_node* pDataBufferNode = NULL; - ma_resource_manager_data_buffer_node* pInsertPoint; - - if (ppDataBufferNode != NULL) { - *ppDataBufferNode = NULL; - } - - result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, hashedName32, &pInsertPoint); - if (result == MA_ALREADY_EXISTS) { - /* The node already exists. We just need to increment the reference count. */ - pDataBufferNode = pInsertPoint; - - result = ma_resource_manager_data_buffer_node_increment_ref(pResourceManager, pDataBufferNode, NULL); - if (result != MA_SUCCESS) { - return result; /* Should never happen. Failed to increment the reference count. */ - } - - result = MA_ALREADY_EXISTS; - goto done; - } else { - /* - The node does not already exist. We need to post a LOAD_DATA_BUFFER_NODE job here. This - needs to be done inside the critical section to ensure an uninitialization of the node - does not occur before initialization on another thread. - */ - pDataBufferNode = (ma_resource_manager_data_buffer_node*)ma_malloc(sizeof(*pDataBufferNode), &pResourceManager->config.allocationCallbacks); - if (pDataBufferNode == NULL) { - return MA_OUT_OF_MEMORY; - } - - MA_ZERO_OBJECT(pDataBufferNode); - pDataBufferNode->hashedName32 = hashedName32; - pDataBufferNode->refCount = 1; /* Always set to 1 by default (this is our first reference). */ - - if (pExistingData == NULL) { - pDataBufferNode->data.type = ma_resource_manager_data_supply_type_unknown; /* <-- We won't know this until we start decoding. */ - pDataBufferNode->result = MA_BUSY; /* Must be set to MA_BUSY before we leave the critical section, so might as well do it now. */ - pDataBufferNode->isDataOwnedByResourceManager = MA_TRUE; - } else { - pDataBufferNode->data = *pExistingData; - pDataBufferNode->result = MA_SUCCESS; /* Not loading asynchronously, so just set the status */ - pDataBufferNode->isDataOwnedByResourceManager = MA_FALSE; - } - - result = ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint); - if (result != MA_SUCCESS) { - ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); - return result; /* Should never happen. Failed to insert the data buffer into the BST. */ - } - - /* - Here is where we'll post the job, but only if we're loading asynchronously. If we're - loading synchronously we'll defer loading to a later stage, outside of the critical - section. - */ - if (pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) { - /* Loading asynchronously. Post the job. */ - ma_job job; - char* pFilePathCopy = NULL; - wchar_t* pFilePathWCopy = NULL; - - /* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */ - if (pFilePath != NULL) { - pFilePathCopy = ma_copy_string(pFilePath, &pResourceManager->config.allocationCallbacks); - } else { - pFilePathWCopy = ma_copy_string_w(pFilePathW, &pResourceManager->config.allocationCallbacks); - } - - if (pFilePathCopy == NULL && pFilePathWCopy == NULL) { - ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); - ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); - return MA_OUT_OF_MEMORY; - } - - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification); - } - - /* Acquire init and done fences before posting the job. These will be unacquired by the job thread. */ - if (pInitFence != NULL) { ma_fence_acquire(pInitFence); } - if (pDoneFence != NULL) { ma_fence_acquire(pDoneFence); } - - /* We now have everything we need to post the job to the job thread. */ - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE); - job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); - job.data.resourceManager.loadDataBufferNode.pResourceManager = pResourceManager; - job.data.resourceManager.loadDataBufferNode.pDataBufferNode = pDataBufferNode; - job.data.resourceManager.loadDataBufferNode.pFilePath = pFilePathCopy; - job.data.resourceManager.loadDataBufferNode.pFilePathW = pFilePathWCopy; - job.data.resourceManager.loadDataBufferNode.flags = flags; - job.data.resourceManager.loadDataBufferNode.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? pInitNotification : NULL; - job.data.resourceManager.loadDataBufferNode.pDoneNotification = NULL; - job.data.resourceManager.loadDataBufferNode.pInitFence = pInitFence; - job.data.resourceManager.loadDataBufferNode.pDoneFence = pDoneFence; - - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - result = ma_job_process(&job); - } else { - result = ma_resource_manager_post_job(pResourceManager, &job); - } - - if (result != MA_SUCCESS) { - /* Failed to post job. Probably ran out of memory. */ - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); - - /* - Fences were acquired before posting the job, but since the job was not able to - be posted, we need to make sure we release them so nothing gets stuck waiting. - */ - if (pInitFence != NULL) { ma_fence_release(pInitFence); } - if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } - - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_uninit(pInitNotification); - } else { - /* These will have been freed by the job thread, but with WAIT_INIT they will already have happened since the job has already been handled. */ - ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); - ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); - } - - ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); - ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); - - return result; - } - } - } - -done: - if (ppDataBufferNode != NULL) { - *ppDataBufferNode = pDataBufferNode; - } - - return result; -} - -static ma_result ma_resource_manager_data_buffer_node_acquire(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_data_buffer_node** ppDataBufferNode) -{ - ma_result result = MA_SUCCESS; - ma_bool32 nodeAlreadyExists = MA_FALSE; - ma_resource_manager_data_buffer_node* pDataBufferNode = NULL; - ma_resource_manager_inline_notification initNotification; /* Used when the WAIT_INIT flag is set. */ - - if (ppDataBufferNode != NULL) { - *ppDataBufferNode = NULL; /* Safety. */ - } - - if (pResourceManager == NULL || (pFilePath == NULL && pFilePathW == NULL && hashedName32 == 0)) { - return MA_INVALID_ARGS; - } - - /* If we're specifying existing data, it must be valid. */ - if (pExistingData != NULL && pExistingData->type == ma_resource_manager_data_supply_type_unknown) { - return MA_INVALID_ARGS; - } - - /* If we don't support threading, remove the ASYNC flag to make the rest of this a bit simpler. */ - if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { - flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC; - } - - if (hashedName32 == 0) { - if (pFilePath != NULL) { - hashedName32 = ma_hash_string_32(pFilePath); - } else { - hashedName32 = ma_hash_string_w_32(pFilePathW); - } - } - - /* - Here is where we either increment the node's reference count or allocate a new one and add it - to the BST. When allocating a new node, we need to make sure the LOAD_DATA_BUFFER_NODE job is - posted inside the critical section just in case the caller immediately uninitializes the node - as this will ensure the FREE_DATA_BUFFER_NODE job is given an execution order such that the - node is not uninitialized before initialization. - */ - ma_resource_manager_data_buffer_bst_lock(pResourceManager); - { - result = ma_resource_manager_data_buffer_node_acquire_critical_section(pResourceManager, pFilePath, pFilePathW, hashedName32, flags, pExistingData, pInitFence, pDoneFence, &initNotification, &pDataBufferNode); - } - ma_resource_manager_data_buffer_bst_unlock(pResourceManager); - - if (result == MA_ALREADY_EXISTS) { - nodeAlreadyExists = MA_TRUE; - result = MA_SUCCESS; - } else { - if (result != MA_SUCCESS) { - return result; - } - } - - /* - If we're loading synchronously, we'll need to load everything now. When loading asynchronously, - a job will have been posted inside the BST critical section so that an uninitialization can be - allocated an appropriate execution order thereby preventing it from being uninitialized before - the node is initialized by the decoding thread(s). - */ - if (nodeAlreadyExists == MA_FALSE) { /* Don't need to try loading anything if the node already exists. */ - if (pFilePath == NULL && pFilePathW == NULL) { - /* - If this path is hit, it means a buffer is being copied (i.e. initialized from only the - hashed name), but that node has been freed in the meantime, probably from some other - thread. This is an invalid operation. - */ - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Cloning data buffer node failed because the source node was released. The source node must remain valid until the cloning has completed.\n"); - result = MA_INVALID_OPERATION; - goto done; - } - - if (pDataBufferNode->isDataOwnedByResourceManager) { - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0) { - /* Loading synchronously. Load the sound in it's entirety here. */ - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) == 0) { - /* No decoding. This is the simple case - just store the file contents in memory. */ - result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pFilePath, pFilePathW); - if (result != MA_SUCCESS) { - goto done; - } - } else { - /* Decoding. We do this the same way as we do when loading asynchronously. */ - ma_decoder* pDecoder; - result = ma_resource_manager_data_buffer_node_init_supply_decoded(pResourceManager, pDataBufferNode, pFilePath, pFilePathW, flags, &pDecoder); - if (result != MA_SUCCESS) { - goto done; - } - - /* We have the decoder, now decode page by page just like we do when loading asynchronously. */ - for (;;) { - /* Decode next page. */ - result = ma_resource_manager_data_buffer_node_decode_next_page(pResourceManager, pDataBufferNode, pDecoder); - if (result != MA_SUCCESS) { - break; /* Will return MA_AT_END when the last page has been decoded. */ - } - } - - /* Reaching the end needs to be considered successful. */ - if (result == MA_AT_END) { - result = MA_SUCCESS; - } - - /* - At this point the data buffer is either fully decoded or some error occurred. Either - way, the decoder is no longer necessary. - */ - ma_decoder_uninit(pDecoder); - ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); - } - - /* Getting here means we were successful. Make sure the status of the node is updated accordingly. */ - ma_atomic_exchange_i32(&pDataBufferNode->result, result); - } else { - /* Loading asynchronously. We may need to wait for initialization. */ - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_wait(&initNotification); - } - } - } else { - /* The data is not managed by the resource manager so there's nothing else to do. */ - MA_ASSERT(pExistingData != NULL); - } - } - -done: - /* If we failed to initialize the data buffer we need to free it. */ - if (result != MA_SUCCESS) { - if (nodeAlreadyExists == MA_FALSE) { - ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); - ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); - } - } - - /* - The init notification needs to be uninitialized. This will be used if the node does not already - exist, and we've specified ASYNC | WAIT_INIT. - */ - if (nodeAlreadyExists == MA_FALSE && pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) { - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_uninit(&initNotification); - } - } - - if (ppDataBufferNode != NULL) { - *ppDataBufferNode = pDataBufferNode; - } - - return result; -} - -static ma_result ma_resource_manager_data_buffer_node_unacquire(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pName, const wchar_t* pNameW) -{ - ma_result result = MA_SUCCESS; - ma_uint32 refCount = 0xFFFFFFFF; /* The new reference count of the node after decrementing. Initialize to non-0 to be safe we don't fall into the freeing path. */ - ma_uint32 hashedName32 = 0; - - if (pResourceManager == NULL) { - return MA_INVALID_ARGS; - } - - if (pDataBufferNode == NULL) { - if (pName == NULL && pNameW == NULL) { - return MA_INVALID_ARGS; - } - - if (pName != NULL) { - hashedName32 = ma_hash_string_32(pName); - } else { - hashedName32 = ma_hash_string_w_32(pNameW); - } - } - - /* - The first thing to do is decrement the reference counter of the node. Then, if the reference - count is zero, we need to free the node. If the node is still in the process of loading, we'll - need to post a job to the job queue to free the node. Otherwise we'll just do it here. - */ - ma_resource_manager_data_buffer_bst_lock(pResourceManager); - { - /* Might need to find the node. Must be done inside the critical section. */ - if (pDataBufferNode == NULL) { - result = ma_resource_manager_data_buffer_node_search(pResourceManager, hashedName32, &pDataBufferNode); - if (result != MA_SUCCESS) { - goto stage2; /* Couldn't find the node. */ - } - } - - result = ma_resource_manager_data_buffer_node_decrement_ref(pResourceManager, pDataBufferNode, &refCount); - if (result != MA_SUCCESS) { - goto stage2; /* Should never happen. */ - } - - if (refCount == 0) { - result = ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); - if (result != MA_SUCCESS) { - goto stage2; /* An error occurred when trying to remove the data buffer. This should never happen. */ - } - } - } - ma_resource_manager_data_buffer_bst_unlock(pResourceManager); - -stage2: - if (result != MA_SUCCESS) { - return result; - } - - /* - Here is where we need to free the node. We don't want to do this inside the critical section - above because we want to keep that as small as possible for multi-threaded efficiency. - */ - if (refCount == 0) { - if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) { - /* The sound is still loading. We need to delay the freeing of the node to a safe time. */ - ma_job job; - - /* We need to mark the node as unavailable for the sake of the resource manager worker threads. */ - ma_atomic_exchange_i32(&pDataBufferNode->result, MA_UNAVAILABLE); - - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE); - job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); - job.data.resourceManager.freeDataBufferNode.pResourceManager = pResourceManager; - job.data.resourceManager.freeDataBufferNode.pDataBufferNode = pDataBufferNode; - - result = ma_resource_manager_post_job(pResourceManager, &job); - if (result != MA_SUCCESS) { - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); - return result; - } - - /* If we don't support threading, process the job queue here. */ - if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { - while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) { - result = ma_resource_manager_process_next_job(pResourceManager); - if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) { - result = MA_SUCCESS; - break; - } - } - } else { - /* Threading is enabled. The job queue will deal with the rest of the cleanup from here. */ - } - } else { - /* The sound isn't loading so we can just free the node here. */ - ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); - } - } - - return result; -} - - - -static ma_uint32 ma_resource_manager_data_buffer_next_execution_order(ma_resource_manager_data_buffer* pDataBuffer) -{ - MA_ASSERT(pDataBuffer != NULL); - return ma_atomic_fetch_add_32(&pDataBuffer->executionCounter, 1); -} - -static ma_result ma_resource_manager_data_buffer_cb__read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_resource_manager_data_buffer_read_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead); -} - -static ma_result ma_resource_manager_data_buffer_cb__seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) -{ - return ma_resource_manager_data_buffer_seek_to_pcm_frame((ma_resource_manager_data_buffer*)pDataSource, frameIndex); -} - -static ma_result ma_resource_manager_data_buffer_cb__get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - return ma_resource_manager_data_buffer_get_data_format((ma_resource_manager_data_buffer*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} - -static ma_result ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_resource_manager_data_buffer_get_cursor_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pCursor); -} - -static ma_result ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_resource_manager_data_buffer_get_length_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pLength); -} - -static ma_result ma_resource_manager_data_buffer_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) -{ - ma_resource_manager_data_buffer* pDataBuffer = (ma_resource_manager_data_buffer*)pDataSource; - MA_ASSERT(pDataBuffer != NULL); - - ma_atomic_exchange_32(&pDataBuffer->isLooping, isLooping); - - /* The looping state needs to be set on the connector as well or else looping won't work when we read audio data. */ - ma_data_source_set_looping(ma_resource_manager_data_buffer_get_connector(pDataBuffer), isLooping); - - return MA_SUCCESS; -} - -static ma_data_source_vtable g_ma_resource_manager_data_buffer_vtable = -{ - ma_resource_manager_data_buffer_cb__read_pcm_frames, - ma_resource_manager_data_buffer_cb__seek_to_pcm_frame, - ma_resource_manager_data_buffer_cb__get_data_format, - ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames, - ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames, - ma_resource_manager_data_buffer_cb__set_looping, - 0 -}; - -static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_uint32 hashedName32, ma_resource_manager_data_buffer* pDataBuffer) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager_data_buffer_node* pDataBufferNode; - ma_data_source_config dataSourceConfig; - ma_bool32 async; - ma_uint32 flags; - ma_resource_manager_pipeline_notifications notifications; - - if (pDataBuffer == NULL) { - if (pConfig != NULL && pConfig->pNotifications != NULL) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(pConfig->pNotifications); - } - - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDataBuffer); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->pNotifications != NULL) { - notifications = *pConfig->pNotifications; /* From here on out we should be referencing `notifications` instead of `pNotifications`. Set this to NULL to catch errors at testing time. */ - } else { - MA_ZERO_OBJECT(¬ifications); - } - - /* For safety, always remove the ASYNC flag if threading is disabled on the resource manager. */ - flags = pConfig->flags; - if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { - flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC; - } - - if (pConfig->isLooping) { - flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; - } - - async = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0; - - /* - Fences need to be acquired before doing anything. These must be acquired and released outside of - the node to ensure there's no holes where ma_fence_wait() could prematurely return before the - data buffer has completed initialization. - - When loading asynchronously, the node acquisition routine below will acquire the fences on this - thread and then release them on the async thread when the operation is complete. - - These fences are always released at the "done" tag at the end of this function. They'll be - acquired a second if loading asynchronously. This double acquisition system is just done to - simplify code maintenance. - */ - ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); - { - /* We first need to acquire a node. If ASYNC is not set, this will not return until the entire sound has been loaded. */ - result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode); - if (result != MA_SUCCESS) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - goto done; - } - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_resource_manager_data_buffer_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pDataBuffer->ds); - if (result != MA_SUCCESS) { - ma_resource_manager_data_buffer_node_unacquire(pResourceManager, pDataBufferNode, NULL, NULL); - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - goto done; - } - - pDataBuffer->pResourceManager = pResourceManager; - pDataBuffer->pNode = pDataBufferNode; - pDataBuffer->flags = flags; - pDataBuffer->result = MA_BUSY; /* Always default to MA_BUSY for safety. It'll be overwritten when loading completes or an error occurs. */ - - /* If we're loading asynchronously we need to post a job to the job queue to initialize the connector. */ - if (async == MA_FALSE || ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_SUCCESS) { - /* Loading synchronously or the data has already been fully loaded. We can just initialize the connector from here without a job. */ - result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pConfig, NULL, NULL); - ma_atomic_exchange_i32(&pDataBuffer->result, result); - - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - goto done; - } else { - /* The node's data supply isn't initialized yet. The caller has requested that we load asynchronously so we need to post a job to do this. */ - ma_job job; - ma_resource_manager_inline_notification initNotification; /* Used when the WAIT_INIT flag is set. */ - - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_init(pResourceManager, &initNotification); - } - - /* - The status of the data buffer needs to be set to MA_BUSY before posting the job so that the - worker thread is aware of its busy state. If the LOAD_DATA_BUFFER job sees a status other - than MA_BUSY, it'll assume an error and fall through to an early exit. - */ - ma_atomic_exchange_i32(&pDataBuffer->result, MA_BUSY); - - /* Acquire fences a second time. These will be released by the async thread. */ - ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); - - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER); - job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer); - job.data.resourceManager.loadDataBuffer.pDataBuffer = pDataBuffer; - job.data.resourceManager.loadDataBuffer.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? &initNotification : notifications.init.pNotification; - job.data.resourceManager.loadDataBuffer.pDoneNotification = notifications.done.pNotification; - job.data.resourceManager.loadDataBuffer.pInitFence = notifications.init.pFence; - job.data.resourceManager.loadDataBuffer.pDoneFence = notifications.done.pFence; - job.data.resourceManager.loadDataBuffer.rangeBegInPCMFrames = pConfig->rangeBegInPCMFrames; - job.data.resourceManager.loadDataBuffer.rangeEndInPCMFrames = pConfig->rangeEndInPCMFrames; - job.data.resourceManager.loadDataBuffer.loopPointBegInPCMFrames = pConfig->loopPointBegInPCMFrames; - job.data.resourceManager.loadDataBuffer.loopPointEndInPCMFrames = pConfig->loopPointEndInPCMFrames; - job.data.resourceManager.loadDataBuffer.isLooping = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING) != 0; - - /* If we need to wait for initialization to complete we can just process the job in place. */ - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - result = ma_job_process(&job); - } else { - result = ma_resource_manager_post_job(pResourceManager, &job); - } - - if (result != MA_SUCCESS) { - /* We failed to post the job. Most likely there isn't enough room in the queue's buffer. */ - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER job. %s.\n", ma_result_description(result)); - ma_atomic_exchange_i32(&pDataBuffer->result, result); - - /* Release the fences after the result has been set on the data buffer. */ - ma_resource_manager_pipeline_notifications_release_all_fences(¬ifications); - } else { - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_wait(&initNotification); - - if (notifications.init.pNotification != NULL) { - ma_async_notification_signal(notifications.init.pNotification); - } - - /* NOTE: Do not release the init fence here. It will have been done by the job. */ - - /* Make sure we return an error if initialization failed on the async thread. */ - result = ma_resource_manager_data_buffer_result(pDataBuffer); - if (result == MA_BUSY) { - result = MA_SUCCESS; - } - } - } - - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - ma_resource_manager_inline_notification_uninit(&initNotification); - } - } - - if (result != MA_SUCCESS) { - ma_resource_manager_data_buffer_node_unacquire(pResourceManager, pDataBufferNode, NULL, NULL); - goto done; - } - } -done: - if (result == MA_SUCCESS) { - if (pConfig->initialSeekPointInPCMFrames > 0) { - ma_resource_manager_data_buffer_seek_to_pcm_frame(pDataBuffer, pConfig->initialSeekPointInPCMFrames); - } - } - - ma_resource_manager_pipeline_notifications_release_all_fences(¬ifications); - - return result; -} - -MA_API ma_result ma_resource_manager_data_buffer_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_buffer* pDataBuffer) -{ - return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, pConfig, 0, pDataBuffer); -} - -MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer) -{ - ma_resource_manager_data_source_config config; - - config = ma_resource_manager_data_source_config_init(); - config.pFilePath = pFilePath; - config.flags = flags; - config.pNotifications = pNotifications; - - return ma_resource_manager_data_buffer_init_ex(pResourceManager, &config, pDataBuffer); -} - -MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer) -{ - ma_resource_manager_data_source_config config; - - config = ma_resource_manager_data_source_config_init(); - config.pFilePathW = pFilePath; - config.flags = flags; - config.pNotifications = pNotifications; - - return ma_resource_manager_data_buffer_init_ex(pResourceManager, &config, pDataBuffer); -} - -MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer) -{ - ma_resource_manager_data_source_config config; - - if (pExistingDataBuffer == NULL) { - return MA_INVALID_ARGS; - } - - MA_ASSERT(pExistingDataBuffer->pNode != NULL); /* <-- If you've triggered this, you've passed in an invalid existing data buffer. */ - - config = ma_resource_manager_data_source_config_init(); - config.flags = pExistingDataBuffer->flags; - - return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, &config, pExistingDataBuffer->pNode->hashedName32, pDataBuffer); -} - -static ma_result ma_resource_manager_data_buffer_uninit_internal(ma_resource_manager_data_buffer* pDataBuffer) -{ - MA_ASSERT(pDataBuffer != NULL); - - /* The connector should be uninitialized first. */ - ma_resource_manager_data_buffer_uninit_connector(pDataBuffer->pResourceManager, pDataBuffer); - - /* With the connector uninitialized we can unacquire the node. */ - ma_resource_manager_data_buffer_node_unacquire(pDataBuffer->pResourceManager, pDataBuffer->pNode, NULL, NULL); - - /* The base data source needs to be uninitialized as well. */ - ma_data_source_uninit(&pDataBuffer->ds); - - return MA_SUCCESS; -} - -MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer) -{ - ma_result result; - - if (pDataBuffer == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_buffer_result(pDataBuffer) == MA_SUCCESS) { - /* The data buffer can be deleted synchronously. */ - return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer); - } else { - /* - The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will - be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event - to get processed before returning. - */ - ma_resource_manager_inline_notification notification; - ma_job job; - - /* - We need to mark the node as unavailable so we don't try reading from it anymore, but also to - let the loading thread know that it needs to abort it's loading procedure. - */ - ma_atomic_exchange_i32(&pDataBuffer->result, MA_UNAVAILABLE); - - result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification); - if (result != MA_SUCCESS) { - return result; /* Failed to create the notification. This should rarely, if ever, happen. */ - } - - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER); - job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer); - job.data.resourceManager.freeDataBuffer.pDataBuffer = pDataBuffer; - job.data.resourceManager.freeDataBuffer.pDoneNotification = ¬ification; - job.data.resourceManager.freeDataBuffer.pDoneFence = NULL; - - result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job); - if (result != MA_SUCCESS) { - ma_resource_manager_inline_notification_uninit(¬ification); - return result; - } - - ma_resource_manager_inline_notification_wait_and_uninit(¬ification); - } - - return result; -} - -MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result = MA_SUCCESS; - ma_uint64 framesRead = 0; - ma_bool32 isDecodedBufferBusy = MA_FALSE; - - /* Safety. */ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - /* - We cannot be using the data buffer after it's been uninitialized. If you trigger this assert it means you're trying to read from the data buffer after - it's been uninitialized or is in the process of uninitializing. - */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - - /* If the node is not initialized we need to abort with a busy code. */ - if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE) { - return MA_BUSY; /* Still loading. */ - } - - /* - If we've got a seek scheduled we'll want to do that before reading. However, for paged buffers, there's - a chance that the sound hasn't yet been decoded up to the seek point will result in the seek failing. If - this happens, we need to keep the seek scheduled and return MA_BUSY. - */ - if (pDataBuffer->seekToCursorOnNextRead) { - pDataBuffer->seekToCursorOnNextRead = MA_FALSE; - - result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pDataBuffer->seekTargetInPCMFrames); - if (result != MA_SUCCESS) { - if (result == MA_BAD_SEEK && ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_decoded_paged) { - pDataBuffer->seekToCursorOnNextRead = MA_TRUE; /* Keep the seek scheduled. We just haven't loaded enough data yet to do the seek properly. */ - return MA_BUSY; - } - - return result; - } - } - - /* - For decoded buffers (not paged) we need to check beforehand how many frames we have available. We cannot - exceed this amount. We'll read as much as we can, and then return MA_BUSY. - */ - if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_decoded) { - ma_uint64 availableFrames; - - isDecodedBufferBusy = (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY); - - if (ma_resource_manager_data_buffer_get_available_frames(pDataBuffer, &availableFrames) == MA_SUCCESS) { - /* Don't try reading more than the available frame count if the data buffer node is still loading. */ - if (isDecodedBufferBusy) { - if (frameCount > availableFrames) { - frameCount = availableFrames; - - /* - If there's no frames available we want to set the status to MA_AT_END. The logic below - will check if the node is busy, and if so, change it to MA_BUSY. The reason we do this - is because we don't want to call `ma_data_source_read_pcm_frames()` if the frame count - is 0 because that'll result in a situation where it's possible MA_AT_END won't get - returned. - */ - if (frameCount == 0) { - result = MA_AT_END; - } - } else { - isDecodedBufferBusy = MA_FALSE; /* We have enough frames available in the buffer to avoid a MA_BUSY status. */ - } - } else { - /* - Getting here means the buffer has been fully loaded. We can just pass the frame count straight - into ma_data_source_read_pcm_frames() below and let ma_data_source handle it. - */ - } - } - } - - /* Don't attempt to read anything if we've got no frames available. */ - if (frameCount > 0) { - result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead); - } - - /* - If we returned MA_AT_END, but the node is still loading, we don't want to return that code or else the caller will interpret the sound - as at the end and terminate decoding. - */ - if (result == MA_AT_END) { - if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) { - result = MA_BUSY; - } - } - - if (isDecodedBufferBusy) { - result = MA_BUSY; - } - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - if (result == MA_SUCCESS && framesRead == 0) { - result = MA_AT_END; - } - - return result; -} - -MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex) -{ - ma_result result; - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - - /* If we haven't yet got a connector we need to abort. */ - if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE) { - pDataBuffer->seekTargetInPCMFrames = frameIndex; - pDataBuffer->seekToCursorOnNextRead = MA_TRUE; - return MA_BUSY; /* Still loading. */ - } - - result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), frameIndex); - if (result != MA_SUCCESS) { - return result; - } - - pDataBuffer->seekTargetInPCMFrames = ~(ma_uint64)0; /* <-- For identification purposes. */ - pDataBuffer->seekToCursorOnNextRead = MA_FALSE; - - return MA_SUCCESS; -} - -MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_manager_data_buffer* pDataBuffer, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - - switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) - { - case ma_resource_manager_data_supply_type_encoded: - { - return ma_data_source_get_data_format(&pDataBuffer->connector.decoder, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); - }; - - case ma_resource_manager_data_supply_type_decoded: - { - *pFormat = pDataBuffer->pNode->data.backend.decoded.format; - *pChannels = pDataBuffer->pNode->data.backend.decoded.channels; - *pSampleRate = pDataBuffer->pNode->data.backend.decoded.sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pDataBuffer->pNode->data.backend.decoded.channels); - return MA_SUCCESS; - }; - - case ma_resource_manager_data_supply_type_decoded_paged: - { - *pFormat = pDataBuffer->pNode->data.backend.decodedPaged.data.format; - *pChannels = pDataBuffer->pNode->data.backend.decodedPaged.data.channels; - *pSampleRate = pDataBuffer->pNode->data.backend.decodedPaged.sampleRate; - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pDataBuffer->pNode->data.backend.decoded.channels); - return MA_SUCCESS; - }; - - case ma_resource_manager_data_supply_type_unknown: - { - return MA_BUSY; /* Still loading. */ - }; - - default: - { - /* Unknown supply type. Should never hit this. */ - return MA_INVALID_ARGS; - } - } -} - -MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor) -{ - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - - if (pDataBuffer == NULL || pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; - - switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) - { - case ma_resource_manager_data_supply_type_encoded: - { - return ma_decoder_get_cursor_in_pcm_frames(&pDataBuffer->connector.decoder, pCursor); - }; - - case ma_resource_manager_data_supply_type_decoded: - { - return ma_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.buffer, pCursor); - }; - - case ma_resource_manager_data_supply_type_decoded_paged: - { - return ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, pCursor); - }; - - case ma_resource_manager_data_supply_type_unknown: - { - return MA_BUSY; - }; - - default: - { - return MA_INVALID_ARGS; - } - } -} - -MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength) -{ - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - - if (pDataBuffer == NULL || pLength == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { - return MA_BUSY; /* Still loading. */ - } - - return ma_data_source_get_length_in_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pLength); -} - -MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer) -{ - if (pDataBuffer == NULL) { - return MA_INVALID_ARGS; - } - - return (ma_result)ma_atomic_load_i32((ma_result*)&pDataBuffer->result); /* Need a naughty const-cast here. */ -} - -MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping) -{ - return ma_data_source_set_looping(pDataBuffer, isLooping); -} - -MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer) -{ - return ma_data_source_is_looping(pDataBuffer); -} - -MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames) -{ - if (pAvailableFrames == NULL) { - return MA_INVALID_ARGS; - } - - *pAvailableFrames = 0; - - if (pDataBuffer == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { - if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) { - return MA_BUSY; - } else { - return MA_INVALID_OPERATION; /* No connector. */ - } - } - - switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) - { - case ma_resource_manager_data_supply_type_encoded: - { - return ma_decoder_get_available_frames(&pDataBuffer->connector.decoder, pAvailableFrames); - }; - - case ma_resource_manager_data_supply_type_decoded: - { - return ma_audio_buffer_get_available_frames(&pDataBuffer->connector.buffer, pAvailableFrames); - }; - - case ma_resource_manager_data_supply_type_decoded_paged: - { - ma_uint64 cursor; - ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, &cursor); - - if (pDataBuffer->pNode->data.backend.decodedPaged.decodedFrameCount > cursor) { - *pAvailableFrames = pDataBuffer->pNode->data.backend.decodedPaged.decodedFrameCount - cursor; - } else { - *pAvailableFrames = 0; - } - - return MA_SUCCESS; - }; - - case ma_resource_manager_data_supply_type_unknown: - default: - { - /* Unknown supply type. Should never hit this. */ - return MA_INVALID_ARGS; - } - } -} - -MA_API ma_result ma_resource_manager_register_file(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags) -{ - return ma_resource_manager_data_buffer_node_acquire(pResourceManager, pFilePath, NULL, 0, flags, NULL, NULL, NULL, NULL); -} - -MA_API ma_result ma_resource_manager_register_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags) -{ - return ma_resource_manager_data_buffer_node_acquire(pResourceManager, NULL, pFilePath, 0, flags, NULL, NULL, NULL, NULL); -} - - -static ma_result ma_resource_manager_register_data(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, ma_resource_manager_data_supply* pExistingData) -{ - return ma_resource_manager_data_buffer_node_acquire(pResourceManager, pName, pNameW, 0, 0, pExistingData, NULL, NULL, NULL); -} - -static ma_result ma_resource_manager_register_decoded_data_internal(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) -{ - ma_resource_manager_data_supply data; - data.type = ma_resource_manager_data_supply_type_decoded; - data.backend.decoded.pData = pData; - data.backend.decoded.totalFrameCount = frameCount; - data.backend.decoded.format = format; - data.backend.decoded.channels = channels; - data.backend.decoded.sampleRate = sampleRate; - - return ma_resource_manager_register_data(pResourceManager, pName, pNameW, &data); -} - -MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) -{ - return ma_resource_manager_register_decoded_data_internal(pResourceManager, pName, NULL, pData, frameCount, format, channels, sampleRate); -} - -MA_API ma_result ma_resource_manager_register_decoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) -{ - return ma_resource_manager_register_decoded_data_internal(pResourceManager, NULL, pName, pData, frameCount, format, channels, sampleRate); -} - - -static ma_result ma_resource_manager_register_encoded_data_internal(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, const void* pData, size_t sizeInBytes) -{ - ma_resource_manager_data_supply data; - data.type = ma_resource_manager_data_supply_type_encoded; - data.backend.encoded.pData = pData; - data.backend.encoded.sizeInBytes = sizeInBytes; - - return ma_resource_manager_register_data(pResourceManager, pName, pNameW, &data); -} - -MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes) -{ - return ma_resource_manager_register_encoded_data_internal(pResourceManager, pName, NULL, pData, sizeInBytes); -} - -MA_API ma_result ma_resource_manager_register_encoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, size_t sizeInBytes) -{ - return ma_resource_manager_register_encoded_data_internal(pResourceManager, NULL, pName, pData, sizeInBytes); -} - - -MA_API ma_result ma_resource_manager_unregister_file(ma_resource_manager* pResourceManager, const char* pFilePath) -{ - return ma_resource_manager_unregister_data(pResourceManager, pFilePath); -} - -MA_API ma_result ma_resource_manager_unregister_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath) -{ - return ma_resource_manager_unregister_data_w(pResourceManager, pFilePath); -} - -MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName) -{ - return ma_resource_manager_data_buffer_node_unacquire(pResourceManager, NULL, pName, NULL); -} - -MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName) -{ - return ma_resource_manager_data_buffer_node_unacquire(pResourceManager, NULL, NULL, pName); -} - - -static ma_uint32 ma_resource_manager_data_stream_next_execution_order(ma_resource_manager_data_stream* pDataStream) -{ - MA_ASSERT(pDataStream != NULL); - return ma_atomic_fetch_add_32(&pDataStream->executionCounter, 1); -} - -static ma_bool32 ma_resource_manager_data_stream_is_decoder_at_end(const ma_resource_manager_data_stream* pDataStream) -{ - MA_ASSERT(pDataStream != NULL); - return ma_atomic_load_32((ma_bool32*)&pDataStream->isDecoderAtEnd); -} - -static ma_uint32 ma_resource_manager_data_stream_seek_counter(const ma_resource_manager_data_stream* pDataStream) -{ - MA_ASSERT(pDataStream != NULL); - return ma_atomic_load_32((ma_uint32*)&pDataStream->seekCounter); -} - - -static ma_result ma_resource_manager_data_stream_cb__read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_resource_manager_data_stream_read_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pFramesOut, frameCount, pFramesRead); -} - -static ma_result ma_resource_manager_data_stream_cb__seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) -{ - return ma_resource_manager_data_stream_seek_to_pcm_frame((ma_resource_manager_data_stream*)pDataSource, frameIndex); -} - -static ma_result ma_resource_manager_data_stream_cb__get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - return ma_resource_manager_data_stream_get_data_format((ma_resource_manager_data_stream*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} - -static ma_result ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_resource_manager_data_stream_get_cursor_in_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pCursor); -} - -static ma_result ma_resource_manager_data_stream_cb__get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_resource_manager_data_stream_get_length_in_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pLength); -} - -static ma_result ma_resource_manager_data_stream_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) -{ - ma_resource_manager_data_stream* pDataStream = (ma_resource_manager_data_stream*)pDataSource; - MA_ASSERT(pDataStream != NULL); - - ma_atomic_exchange_32(&pDataStream->isLooping, isLooping); - - return MA_SUCCESS; -} - -static ma_data_source_vtable g_ma_resource_manager_data_stream_vtable = -{ - ma_resource_manager_data_stream_cb__read_pcm_frames, - ma_resource_manager_data_stream_cb__seek_to_pcm_frame, - ma_resource_manager_data_stream_cb__get_data_format, - ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames, - ma_resource_manager_data_stream_cb__get_length_in_pcm_frames, - ma_resource_manager_data_stream_cb__set_looping, - 0 /*MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT*/ -}; - -static void ma_resource_manager_data_stream_set_absolute_cursor(ma_resource_manager_data_stream* pDataStream, ma_uint64 absoluteCursor) -{ - /* Loop if possible. */ - if (absoluteCursor > pDataStream->totalLengthInPCMFrames && pDataStream->totalLengthInPCMFrames > 0) { - absoluteCursor = absoluteCursor % pDataStream->totalLengthInPCMFrames; - } - - ma_atomic_exchange_64(&pDataStream->absoluteCursor, absoluteCursor); -} - -MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_stream* pDataStream) -{ - ma_result result; - ma_data_source_config dataSourceConfig; - char* pFilePathCopy = NULL; - wchar_t* pFilePathWCopy = NULL; - ma_job job; - ma_bool32 waitBeforeReturning = MA_FALSE; - ma_resource_manager_inline_notification waitNotification; - ma_resource_manager_pipeline_notifications notifications; - ma_uint32 flags; - - if (pDataStream == NULL) { - if (pConfig != NULL && pConfig->pNotifications != NULL) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(pConfig->pNotifications); - } - - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDataStream); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->pNotifications != NULL) { - notifications = *pConfig->pNotifications; /* From here on out, `notifications` should be used instead of `pNotifications`. Setting this to NULL to catch any errors at testing time. */ - } else { - MA_ZERO_OBJECT(¬ifications); - } - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_resource_manager_data_stream_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pDataStream->ds); - if (result != MA_SUCCESS) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - return result; - } - - flags = pConfig->flags; - if (pConfig->isLooping) { - flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; - } - - pDataStream->pResourceManager = pResourceManager; - pDataStream->flags = pConfig->flags; - pDataStream->result = MA_BUSY; - - ma_data_source_set_range_in_pcm_frames(pDataStream, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); - ma_data_source_set_loop_point_in_pcm_frames(pDataStream, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); - ma_data_source_set_looping(pDataStream, (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING) != 0); - - if (pResourceManager == NULL || (pConfig->pFilePath == NULL && pConfig->pFilePathW == NULL)) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - return MA_INVALID_ARGS; - } - - /* We want all access to the VFS and the internal decoder to happen on the job thread just to keep things easier to manage for the VFS. */ - - /* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */ - if (pConfig->pFilePath != NULL) { - pFilePathCopy = ma_copy_string(pConfig->pFilePath, &pResourceManager->config.allocationCallbacks); - } else { - pFilePathWCopy = ma_copy_string_w(pConfig->pFilePathW, &pResourceManager->config.allocationCallbacks); - } - - if (pFilePathCopy == NULL && pFilePathWCopy == NULL) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - return MA_OUT_OF_MEMORY; - } - - /* - We need to check for the presence of MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC. If it's not set, we need to wait before returning. Otherwise we - can return immediately. Likewise, we'll also check for MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT and do the same. - */ - if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0 || (pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { - waitBeforeReturning = MA_TRUE; - ma_resource_manager_inline_notification_init(pResourceManager, &waitNotification); - } - - ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); - - /* Set the absolute cursor to our initial seek position so retrieval of the cursor returns a good value. */ - ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, pConfig->initialSeekPointInPCMFrames); - - /* We now have everything we need to post the job. This is the last thing we need to do from here. The rest will be done by the job thread. */ - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM); - job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); - job.data.resourceManager.loadDataStream.pDataStream = pDataStream; - job.data.resourceManager.loadDataStream.pFilePath = pFilePathCopy; - job.data.resourceManager.loadDataStream.pFilePathW = pFilePathWCopy; - job.data.resourceManager.loadDataStream.initialSeekPoint = pConfig->initialSeekPointInPCMFrames; - job.data.resourceManager.loadDataStream.pInitNotification = (waitBeforeReturning == MA_TRUE) ? &waitNotification : notifications.init.pNotification; - job.data.resourceManager.loadDataStream.pInitFence = notifications.init.pFence; - result = ma_resource_manager_post_job(pResourceManager, &job); - if (result != MA_SUCCESS) { - ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); - ma_resource_manager_pipeline_notifications_release_all_fences(¬ifications); - - if (waitBeforeReturning) { - ma_resource_manager_inline_notification_uninit(&waitNotification); - } - - ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); - ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); - return result; - } - - /* Wait if needed. */ - if (waitBeforeReturning) { - ma_resource_manager_inline_notification_wait_and_uninit(&waitNotification); - - if (notifications.init.pNotification != NULL) { - ma_async_notification_signal(notifications.init.pNotification); - } - - /* - If there was an error during initialization make sure we return that result here. We don't want to do this - if we're not waiting because it will most likely be in a busy state. - */ - if (pDataStream->result != MA_SUCCESS) { - return pDataStream->result; - } - - /* NOTE: Do not release pInitFence here. That will be done by the job. */ - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream) -{ - ma_resource_manager_data_source_config config; - - config = ma_resource_manager_data_source_config_init(); - config.pFilePath = pFilePath; - config.flags = flags; - config.pNotifications = pNotifications; - - return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream); -} - -MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream) -{ - ma_resource_manager_data_source_config config; - - config = ma_resource_manager_data_source_config_init(); - config.pFilePathW = pFilePath; - config.flags = flags; - config.pNotifications = pNotifications; - - return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream); -} - -MA_API ma_result ma_resource_manager_data_stream_uninit(ma_resource_manager_data_stream* pDataStream) -{ - ma_resource_manager_inline_notification freeEvent; - ma_job job; - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - /* The first thing to do is set the result to unavailable. This will prevent future page decoding. */ - ma_atomic_exchange_i32(&pDataStream->result, MA_UNAVAILABLE); - - /* - We need to post a job to ensure we're not in the middle or decoding or anything. Because the object is owned by the caller, we'll need - to wait for it to complete before returning which means we need an event. - */ - ma_resource_manager_inline_notification_init(pDataStream->pResourceManager, &freeEvent); - - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM); - job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); - job.data.resourceManager.freeDataStream.pDataStream = pDataStream; - job.data.resourceManager.freeDataStream.pDoneNotification = &freeEvent; - job.data.resourceManager.freeDataStream.pDoneFence = NULL; - ma_resource_manager_post_job(pDataStream->pResourceManager, &job); - - /* We need to wait for the job to finish processing before we return. */ - ma_resource_manager_inline_notification_wait_and_uninit(&freeEvent); - - return MA_SUCCESS; -} - - -static ma_uint32 ma_resource_manager_data_stream_get_page_size_in_frames(ma_resource_manager_data_stream* pDataStream) -{ - MA_ASSERT(pDataStream != NULL); - MA_ASSERT(pDataStream->isDecoderInitialized == MA_TRUE); - - return MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (pDataStream->decoder.outputSampleRate/1000); -} - -static void* ma_resource_manager_data_stream_get_page_data_pointer(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex, ma_uint32 relativeCursor) -{ - MA_ASSERT(pDataStream != NULL); - MA_ASSERT(pDataStream->isDecoderInitialized == MA_TRUE); - MA_ASSERT(pageIndex == 0 || pageIndex == 1); - - return ma_offset_ptr(pDataStream->pPageData, ((ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * pageIndex) + relativeCursor) * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels)); -} - -static void ma_resource_manager_data_stream_fill_page(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex) -{ - ma_result result = MA_SUCCESS; - ma_uint64 pageSizeInFrames; - ma_uint64 totalFramesReadForThisPage = 0; - void* pPageData = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pageIndex, 0); - - pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); - - /* The decoder needs to inherit the stream's looping and range state. */ - { - ma_uint64 rangeBeg; - ma_uint64 rangeEnd; - ma_uint64 loopPointBeg; - ma_uint64 loopPointEnd; - - ma_data_source_set_looping(&pDataStream->decoder, ma_resource_manager_data_stream_is_looping(pDataStream)); - - ma_data_source_get_range_in_pcm_frames(pDataStream, &rangeBeg, &rangeEnd); - ma_data_source_set_range_in_pcm_frames(&pDataStream->decoder, rangeBeg, rangeEnd); - - ma_data_source_get_loop_point_in_pcm_frames(pDataStream, &loopPointBeg, &loopPointEnd); - ma_data_source_set_loop_point_in_pcm_frames(&pDataStream->decoder, loopPointBeg, loopPointEnd); - } - - /* Just read straight from the decoder. It will deal with ranges and looping for us. */ - result = ma_data_source_read_pcm_frames(&pDataStream->decoder, pPageData, pageSizeInFrames, &totalFramesReadForThisPage); - if (result == MA_AT_END || totalFramesReadForThisPage < pageSizeInFrames) { - ma_atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_TRUE); - } - - ma_atomic_exchange_32(&pDataStream->pageFrameCount[pageIndex], (ma_uint32)totalFramesReadForThisPage); - ma_atomic_exchange_32(&pDataStream->isPageValid[pageIndex], MA_TRUE); -} - -static void ma_resource_manager_data_stream_fill_pages(ma_resource_manager_data_stream* pDataStream) -{ - ma_uint32 iPage; - - MA_ASSERT(pDataStream != NULL); - - for (iPage = 0; iPage < 2; iPage += 1) { - ma_resource_manager_data_stream_fill_page(pDataStream, iPage); - } -} - - -static ma_result ma_resource_manager_data_stream_map(ma_resource_manager_data_stream* pDataStream, void** ppFramesOut, ma_uint64* pFrameCount) -{ - ma_uint64 framesAvailable; - ma_uint64 frameCount = 0; - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); - - if (pFrameCount != NULL) { - frameCount = *pFrameCount; - *pFrameCount = 0; - } - if (ppFramesOut != NULL) { - *ppFramesOut = NULL; - } - - if (pDataStream == NULL || ppFramesOut == NULL || pFrameCount == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { - return MA_INVALID_OPERATION; - } - - /* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */ - if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) { - return MA_BUSY; - } - - /* If the page we're on is invalid it means we've caught up to the job thread. */ - if (ma_atomic_load_32(&pDataStream->isPageValid[pDataStream->currentPageIndex]) == MA_FALSE) { - framesAvailable = 0; - } else { - /* - The page we're on is valid so we must have some frames available. We need to make sure that we don't overflow into the next page, even if it's valid. The reason is - that the unmap process will only post an update for one page at a time. Keeping mapping tied to page boundaries makes this simpler. - */ - ma_uint32 currentPageFrameCount = ma_atomic_load_32(&pDataStream->pageFrameCount[pDataStream->currentPageIndex]); - MA_ASSERT(currentPageFrameCount >= pDataStream->relativeCursor); - - framesAvailable = currentPageFrameCount - pDataStream->relativeCursor; - } - - /* If there's no frames available and the result is set to MA_AT_END we need to return MA_AT_END. */ - if (framesAvailable == 0) { - if (ma_resource_manager_data_stream_is_decoder_at_end(pDataStream)) { - return MA_AT_END; - } else { - return MA_BUSY; /* There are no frames available, but we're not marked as EOF so we might have caught up to the job thread. Need to return MA_BUSY and wait for more data. */ - } - } - - MA_ASSERT(framesAvailable > 0); - - if (frameCount > framesAvailable) { - frameCount = framesAvailable; - } - - *ppFramesOut = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pDataStream->currentPageIndex, pDataStream->relativeCursor); - *pFrameCount = frameCount; - - return MA_SUCCESS; -} - -static ma_result ma_resource_manager_data_stream_unmap(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameCount) -{ - ma_uint32 newRelativeCursor; - ma_uint32 pageSizeInFrames; - ma_job job; - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { - return MA_INVALID_OPERATION; - } - - /* The frame count should always fit inside a 32-bit integer. */ - if (frameCount > 0xFFFFFFFF) { - return MA_INVALID_ARGS; - } - - pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); - - /* The absolute cursor needs to be updated for ma_resource_manager_data_stream_get_cursor_in_pcm_frames(). */ - ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, ma_atomic_load_64(&pDataStream->absoluteCursor) + frameCount); - - /* Here is where we need to check if we need to load a new page, and if so, post a job to load it. */ - newRelativeCursor = pDataStream->relativeCursor + (ma_uint32)frameCount; - - /* If the new cursor has flowed over to the next page we need to mark the old one as invalid and post an event for it. */ - if (newRelativeCursor >= pageSizeInFrames) { - newRelativeCursor -= pageSizeInFrames; - - /* Here is where we post the job start decoding. */ - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM); - job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); - job.data.resourceManager.pageDataStream.pDataStream = pDataStream; - job.data.resourceManager.pageDataStream.pageIndex = pDataStream->currentPageIndex; - - /* The page needs to be marked as invalid so that the public API doesn't try reading from it. */ - ma_atomic_exchange_32(&pDataStream->isPageValid[pDataStream->currentPageIndex], MA_FALSE); - - /* Before posting the job we need to make sure we set some state. */ - pDataStream->relativeCursor = newRelativeCursor; - pDataStream->currentPageIndex = (pDataStream->currentPageIndex + 1) & 0x01; - return ma_resource_manager_post_job(pDataStream->pResourceManager, &job); - } else { - /* We haven't moved into a new page so we can just move the cursor forward. */ - pDataStream->relativeCursor = newRelativeCursor; - return MA_SUCCESS; - } -} - - -MA_API ma_result ma_resource_manager_data_stream_read_pcm_frames(ma_resource_manager_data_stream* pDataStream, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result = MA_SUCCESS; - ma_uint64 totalFramesProcessed; - ma_format format; - ma_uint32 channels; - - /* Safety. */ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { - return MA_INVALID_OPERATION; - } - - /* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */ - if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) { - return MA_BUSY; - } - - ma_resource_manager_data_stream_get_data_format(pDataStream, &format, &channels, NULL, NULL, 0); - - /* Reading is implemented in terms of map/unmap. We need to run this in a loop because mapping is clamped against page boundaries. */ - totalFramesProcessed = 0; - while (totalFramesProcessed < frameCount) { - void* pMappedFrames; - ma_uint64 mappedFrameCount; - - mappedFrameCount = frameCount - totalFramesProcessed; - result = ma_resource_manager_data_stream_map(pDataStream, &pMappedFrames, &mappedFrameCount); - if (result != MA_SUCCESS) { - break; - } - - /* Copy the mapped data to the output buffer if we have one. It's allowed for pFramesOut to be NULL in which case a relative forward seek is performed. */ - if (pFramesOut != NULL) { - ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesProcessed, format, channels), pMappedFrames, mappedFrameCount, format, channels); - } - - totalFramesProcessed += mappedFrameCount; - - result = ma_resource_manager_data_stream_unmap(pDataStream, mappedFrameCount); - if (result != MA_SUCCESS) { - break; /* This is really bad - will only get an error here if we failed to post a job to the queue for loading the next page. */ - } - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesProcessed; - } - - if (result == MA_SUCCESS && totalFramesProcessed == 0) { - result = MA_AT_END; - } - - return result; -} - -MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameIndex) -{ - ma_job job; - ma_result streamResult; - - streamResult = ma_resource_manager_data_stream_result(pDataStream); - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(streamResult != MA_UNAVAILABLE); - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - if (streamResult != MA_SUCCESS && streamResult != MA_BUSY) { - return MA_INVALID_OPERATION; - } - - /* If we're not already seeking and we're sitting on the same frame, just make this a no-op. */ - if (ma_atomic_load_32(&pDataStream->seekCounter) == 0) { - if (ma_atomic_load_64(&pDataStream->absoluteCursor) == frameIndex) { - return MA_SUCCESS; - } - } - - - /* Increment the seek counter first to indicate to read_paged_pcm_frames() and map_paged_pcm_frames() that we are in the middle of a seek and MA_BUSY should be returned. */ - ma_atomic_fetch_add_32(&pDataStream->seekCounter, 1); - - /* Update the absolute cursor so that ma_resource_manager_data_stream_get_cursor_in_pcm_frames() returns the new position. */ - ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, frameIndex); - - /* - We need to clear our currently loaded pages so that the stream starts playback from the new seek point as soon as possible. These are for the purpose of the public - API and will be ignored by the seek job. The seek job will operate on the assumption that both pages have been marked as invalid and the cursor is at the start of - the first page. - */ - pDataStream->relativeCursor = 0; - pDataStream->currentPageIndex = 0; - ma_atomic_exchange_32(&pDataStream->isPageValid[0], MA_FALSE); - ma_atomic_exchange_32(&pDataStream->isPageValid[1], MA_FALSE); - - /* Make sure the data stream is not marked as at the end or else if we seek in response to hitting the end, we won't be able to read any more data. */ - ma_atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_FALSE); - - /* - The public API is not allowed to touch the internal decoder so we need to use a job to perform the seek. When seeking, the job thread will assume both pages - are invalid and any content contained within them will be discarded and replaced with newly decoded data. - */ - job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM); - job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); - job.data.resourceManager.seekDataStream.pDataStream = pDataStream; - job.data.resourceManager.seekDataStream.frameIndex = frameIndex; - return ma_resource_manager_post_job(pDataStream->pResourceManager, &job); -} - -MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); - - if (pFormat != NULL) { - *pFormat = ma_format_unknown; - } - - if (pChannels != NULL) { - *pChannels = 0; - } - - if (pSampleRate != NULL) { - *pSampleRate = 0; - } - - if (pChannelMap != NULL) { - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); - } - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { - return MA_INVALID_OPERATION; - } - - /* - We're being a little bit naughty here and accessing the internal decoder from the public API. The output data format is constant, and we've defined this function - such that the application is responsible for ensuring it's not called while uninitializing so it should be safe. - */ - return ma_data_source_get_data_format(&pDataStream->decoder, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} - -MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pCursor) -{ - ma_result result; - - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - /* - If the stream is in an erroneous state we need to return an invalid operation. We can allow - this to be called when the data stream is in a busy state because the caller may have asked - for an initial seek position and it's convenient to return that as the cursor position. - */ - result = ma_resource_manager_data_stream_result(pDataStream); - if (result != MA_SUCCESS && result != MA_BUSY) { - return MA_INVALID_OPERATION; - } - - *pCursor = ma_atomic_load_64(&pDataStream->absoluteCursor); - - return MA_SUCCESS; -} - -MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength) -{ - ma_result streamResult; - - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; - - streamResult = ma_resource_manager_data_stream_result(pDataStream); - - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(streamResult != MA_UNAVAILABLE); - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - if (streamResult != MA_SUCCESS) { - return streamResult; - } - - /* - We most definitely do not want to be calling ma_decoder_get_length_in_pcm_frames() directly. Instead we want to use a cached value that we - calculated when we initialized it on the job thread. - */ - *pLength = pDataStream->totalLengthInPCMFrames; - if (*pLength == 0) { - return MA_NOT_IMPLEMENTED; /* Some decoders may not have a known length. */ - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream) -{ - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - return (ma_result)ma_atomic_load_i32(&pDataStream->result); -} - -MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping) -{ - return ma_data_source_set_looping(pDataStream, isLooping); -} - -MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream) -{ - if (pDataStream == NULL) { - return MA_FALSE; - } - - return ma_atomic_load_32((ma_bool32*)&pDataStream->isLooping); /* Naughty const-cast. Value won't change from here in practice (maybe from another thread). */ -} - -MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames) -{ - ma_uint32 pageIndex0; - ma_uint32 pageIndex1; - ma_uint32 relativeCursor; - ma_uint64 availableFrames; - - if (pAvailableFrames == NULL) { - return MA_INVALID_ARGS; - } - - *pAvailableFrames = 0; - - if (pDataStream == NULL) { - return MA_INVALID_ARGS; - } - - pageIndex0 = pDataStream->currentPageIndex; - pageIndex1 = (pDataStream->currentPageIndex + 1) & 0x01; - relativeCursor = pDataStream->relativeCursor; - - availableFrames = 0; - if (ma_atomic_load_32(&pDataStream->isPageValid[pageIndex0])) { - availableFrames += ma_atomic_load_32(&pDataStream->pageFrameCount[pageIndex0]) - relativeCursor; - if (ma_atomic_load_32(&pDataStream->isPageValid[pageIndex1])) { - availableFrames += ma_atomic_load_32(&pDataStream->pageFrameCount[pageIndex1]); - } - } - - *pAvailableFrames = availableFrames; - return MA_SUCCESS; -} - - -static ma_result ma_resource_manager_data_source_preinit(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDataSource); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pResourceManager == NULL) { - return MA_INVALID_ARGS; - } - - pDataSource->flags = pConfig->flags; - if (pConfig->isLooping) { - pDataSource->flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_resource_manager_data_source_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource) -{ - ma_result result; - - result = ma_resource_manager_data_source_preinit(pResourceManager, pConfig, pDataSource); - if (result != MA_SUCCESS) { - return result; - } - - /* The data source itself is just a data stream or a data buffer. */ - if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_init_ex(pResourceManager, pConfig, &pDataSource->backend.stream); - } else { - return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer); - } -} - -MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource) -{ - ma_resource_manager_data_source_config config; - - config = ma_resource_manager_data_source_config_init(); - config.pFilePath = pName; - config.flags = flags; - config.pNotifications = pNotifications; - - return ma_resource_manager_data_source_init_ex(pResourceManager, &config, pDataSource); -} - -MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource) -{ - ma_resource_manager_data_source_config config; - - config = ma_resource_manager_data_source_config_init(); - config.pFilePathW = pName; - config.flags = flags; - config.pNotifications = pNotifications; - - return ma_resource_manager_data_source_init_ex(pResourceManager, &config, pDataSource); -} - -MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource) -{ - ma_result result; - ma_resource_manager_data_source_config config; - - if (pExistingDataSource == NULL) { - return MA_INVALID_ARGS; - } - - config = ma_resource_manager_data_source_config_init(); - config.flags = pExistingDataSource->flags; - - result = ma_resource_manager_data_source_preinit(pResourceManager, &config, pDataSource); - if (result != MA_SUCCESS) { - return result; - } - - /* Copying can only be done from data buffers. Streams cannot be copied. */ - if ((pExistingDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return MA_INVALID_OPERATION; - } - - return ma_resource_manager_data_buffer_init_copy(pResourceManager, &pExistingDataSource->backend.buffer, &pDataSource->backend.buffer); -} - -MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - /* All we need to is uninitialize the underlying data buffer or data stream. */ - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_uninit(&pDataSource->backend.stream); - } else { - return ma_resource_manager_data_buffer_uninit(&pDataSource->backend.buffer); - } -} - -MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - /* Safety. */ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_read_pcm_frames(&pDataSource->backend.stream, pFramesOut, frameCount, pFramesRead); - } else { - return ma_resource_manager_data_buffer_read_pcm_frames(&pDataSource->backend.buffer, pFramesOut, frameCount, pFramesRead); - } -} - -MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_seek_to_pcm_frame(&pDataSource->backend.stream, frameIndex); - } else { - return ma_resource_manager_data_buffer_seek_to_pcm_frame(&pDataSource->backend.buffer, frameIndex); - } -} - -MA_API ma_result ma_resource_manager_data_source_map(ma_resource_manager_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_map(&pDataSource->backend.stream, ppFramesOut, pFrameCount); - } else { - return MA_NOT_IMPLEMENTED; /* Mapping not supported with data buffers. */ - } -} - -MA_API ma_result ma_resource_manager_data_source_unmap(ma_resource_manager_data_source* pDataSource, ma_uint64 frameCount) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_unmap(&pDataSource->backend.stream, frameCount); - } else { - return MA_NOT_IMPLEMENTED; /* Mapping not supported with data buffers. */ - } -} - -MA_API ma_result ma_resource_manager_data_source_get_data_format(ma_resource_manager_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_get_data_format(&pDataSource->backend.stream, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); - } else { - return ma_resource_manager_data_buffer_get_data_format(&pDataSource->backend.buffer, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); - } -} - -MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pCursor) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_get_cursor_in_pcm_frames(&pDataSource->backend.stream, pCursor); - } else { - return ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(&pDataSource->backend.buffer, pCursor); - } -} - -MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_get_length_in_pcm_frames(&pDataSource->backend.stream, pLength); - } else { - return ma_resource_manager_data_buffer_get_length_in_pcm_frames(&pDataSource->backend.buffer, pLength); - } -} - -MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_result(&pDataSource->backend.stream); - } else { - return ma_resource_manager_data_buffer_result(&pDataSource->backend.buffer); - } -} - -MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping) -{ - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_set_looping(&pDataSource->backend.stream, isLooping); - } else { - return ma_resource_manager_data_buffer_set_looping(&pDataSource->backend.buffer, isLooping); - } -} - -MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource) -{ - if (pDataSource == NULL) { - return MA_FALSE; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_is_looping(&pDataSource->backend.stream); - } else { - return ma_resource_manager_data_buffer_is_looping(&pDataSource->backend.buffer); - } -} - -MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames) -{ - if (pAvailableFrames == NULL) { - return MA_INVALID_ARGS; - } - - *pAvailableFrames = 0; - - if (pDataSource == NULL) { - return MA_INVALID_ARGS; - } - - if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_get_available_frames(&pDataSource->backend.stream, pAvailableFrames); - } else { - return ma_resource_manager_data_buffer_get_available_frames(&pDataSource->backend.buffer, pAvailableFrames); - } -} - - -MA_API ma_result ma_resource_manager_post_job(ma_resource_manager* pResourceManager, const ma_job* pJob) -{ - if (pResourceManager == NULL) { - return MA_INVALID_ARGS; - } - - return ma_job_queue_post(&pResourceManager->jobQueue, pJob); -} - -MA_API ma_result ma_resource_manager_post_job_quit(ma_resource_manager* pResourceManager) -{ - ma_job job = ma_job_init(MA_JOB_TYPE_QUIT); - return ma_resource_manager_post_job(pResourceManager, &job); -} - -MA_API ma_result ma_resource_manager_next_job(ma_resource_manager* pResourceManager, ma_job* pJob) -{ - if (pResourceManager == NULL) { - return MA_INVALID_ARGS; - } - - return ma_job_queue_next(&pResourceManager->jobQueue, pJob); -} - - -static ma_result ma_job_process__resource_manager__load_data_buffer_node(ma_job* pJob) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager* pResourceManager; - ma_resource_manager_data_buffer_node* pDataBufferNode; - - MA_ASSERT(pJob != NULL); - - pResourceManager = (ma_resource_manager*)pJob->data.resourceManager.loadDataBufferNode.pResourceManager; - MA_ASSERT(pResourceManager != NULL); - - pDataBufferNode = (ma_resource_manager_data_buffer_node*)pJob->data.resourceManager.loadDataBufferNode.pDataBufferNode; - MA_ASSERT(pDataBufferNode != NULL); - MA_ASSERT(pDataBufferNode->isDataOwnedByResourceManager == MA_TRUE); /* The data should always be owned by the resource manager. */ - - /* The data buffer is not getting deleted, but we may be getting executed out of order. If so, we need to push the job back onto the queue and return. */ - if (pJob->order != ma_atomic_load_32(&pDataBufferNode->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Attempting to execute out of order. Probably interleaved with a MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER job. */ - } - - /* First thing we need to do is check whether or not the data buffer is getting deleted. If so we just abort. */ - if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) != MA_BUSY) { - result = ma_resource_manager_data_buffer_node_result(pDataBufferNode); /* The data buffer may be getting deleted before it's even been loaded. */ - goto done; - } - - /* - We're ready to start loading. Essentially what we're doing here is initializing the data supply - of the node. Once this is complete, data buffers can have their connectors initialized which - will allow then to have audio data read from them. - - Note that when the data supply type has been moved away from "unknown", that is when other threads - will determine that the node is available for data delivery and the data buffer connectors can be - initialized. Therefore, it's important that it is set after the data supply has been initialized. - */ - if ((pJob->data.resourceManager.loadDataBufferNode.flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) != 0) { - /* - Decoding. This is the complex case because we're not going to be doing the entire decoding - process here. Instead it's going to be split of multiple jobs and loaded in pages. The - reason for this is to evenly distribute decoding time across multiple sounds, rather than - having one huge sound hog all the available processing resources. - - The first thing we do is initialize a decoder. This is allocated on the heap and is passed - around to the paging jobs. When the last paging job has completed it's processing, it'll - free the decoder for us. - - This job does not do any actual decoding. It instead just posts a PAGE_DATA_BUFFER_NODE job - which is where the actual decoding work will be done. However, once this job is complete, - the node will be in a state where data buffer connectors can be initialized. - */ - ma_decoder* pDecoder; /* <-- Free'd on the last page decode. */ - ma_job pageDataBufferNodeJob; - - /* Allocate the decoder by initializing a decoded data supply. */ - result = ma_resource_manager_data_buffer_node_init_supply_decoded(pResourceManager, pDataBufferNode, pJob->data.resourceManager.loadDataBufferNode.pFilePath, pJob->data.resourceManager.loadDataBufferNode.pFilePathW, pJob->data.resourceManager.loadDataBufferNode.flags, &pDecoder); - - /* - Don't ever propagate an MA_BUSY result code or else the resource manager will think the - node is just busy decoding rather than in an error state. This should never happen, but - including this logic for safety just in case. - */ - if (result == MA_BUSY) { - result = MA_ERROR; - } - - if (result != MA_SUCCESS) { - if (pJob->data.resourceManager.loadDataBufferNode.pFilePath != NULL) { - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%s\". %s.\n", pJob->data.resourceManager.loadDataBufferNode.pFilePath, ma_result_description(result)); - } else { - #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%ls\", %s.\n", pJob->data.resourceManager.loadDataBufferNode.pFilePathW, ma_result_description(result)); - #endif - } - - goto done; - } - - /* - At this point the node's data supply is initialized and other threads can start initializing - their data buffer connectors. However, no data will actually be available until we start to - actually decode it. To do this, we need to post a paging job which is where the decoding - work is done. - - Note that if an error occurred at an earlier point, this section will have been skipped. - */ - pageDataBufferNodeJob = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE); - pageDataBufferNodeJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); - pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pResourceManager = pResourceManager; - pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDataBufferNode = pDataBufferNode; - pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDecoder = pDecoder; - pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDoneNotification = pJob->data.resourceManager.loadDataBufferNode.pDoneNotification; - pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDoneFence = pJob->data.resourceManager.loadDataBufferNode.pDoneFence; - - /* The job has been set up so it can now be posted. */ - result = ma_resource_manager_post_job(pResourceManager, &pageDataBufferNodeJob); - - /* - When we get here, we want to make sure the result code is set to MA_BUSY. The reason for - this is that the result will be copied over to the node's internal result variable. In - this case, since the decoding is still in-progress, we need to make sure the result code - is set to MA_BUSY. - */ - if (result != MA_SUCCESS) { - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE job. %s\n", ma_result_description(result)); - ma_decoder_uninit(pDecoder); - ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); - } else { - result = MA_BUSY; - } - } else { - /* No decoding. This is the simple case. We need only read the file content into memory and we're done. */ - result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pJob->data.resourceManager.loadDataBufferNode.pFilePath, pJob->data.resourceManager.loadDataBufferNode.pFilePathW); - } - - -done: - /* File paths are no longer needed. */ - ma_free(pJob->data.resourceManager.loadDataBufferNode.pFilePath, &pResourceManager->config.allocationCallbacks); - ma_free(pJob->data.resourceManager.loadDataBufferNode.pFilePathW, &pResourceManager->config.allocationCallbacks); - - /* - We need to set the result to at the very end to ensure no other threads try reading the data before we've fully initialized the object. Other threads - are going to be inspecting this variable to determine whether or not they're ready to read data. We can only change the result if it's set to MA_BUSY - because otherwise we may be changing away from an error code which would be bad. An example is if the application creates a data buffer, but then - immediately deletes it before we've got to this point. In this case, pDataBuffer->result will be MA_UNAVAILABLE, and setting it to MA_SUCCESS or any - other error code would cause the buffer to look like it's in a state that it's not. - */ - ma_atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result); - - /* At this point initialization is complete and we can signal the notification if any. */ - if (pJob->data.resourceManager.loadDataBufferNode.pInitNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.loadDataBufferNode.pInitNotification); - } - if (pJob->data.resourceManager.loadDataBufferNode.pInitFence != NULL) { - ma_fence_release(pJob->data.resourceManager.loadDataBufferNode.pInitFence); - } - - /* If we have a success result it means we've fully loaded the buffer. This will happen in the non-decoding case. */ - if (result != MA_BUSY) { - if (pJob->data.resourceManager.loadDataBufferNode.pDoneNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.loadDataBufferNode.pDoneNotification); - } - if (pJob->data.resourceManager.loadDataBufferNode.pDoneFence != NULL) { - ma_fence_release(pJob->data.resourceManager.loadDataBufferNode.pDoneFence); - } - } - - /* Increment the node's execution pointer so that the next jobs can be processed. This is how we keep decoding of pages in-order. */ - ma_atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); - - /* A busy result should be considered successful from the point of view of the job system. */ - if (result == MA_BUSY) { - result = MA_SUCCESS; - } - - return result; -} - -static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* pJob) -{ - ma_resource_manager* pResourceManager; - ma_resource_manager_data_buffer_node* pDataBufferNode; - - MA_ASSERT(pJob != NULL); - - pResourceManager = (ma_resource_manager*)pJob->data.resourceManager.freeDataBufferNode.pResourceManager; - MA_ASSERT(pResourceManager != NULL); - - pDataBufferNode = (ma_resource_manager_data_buffer_node*)pJob->data.resourceManager.freeDataBufferNode.pDataBufferNode; - MA_ASSERT(pDataBufferNode != NULL); - - if (pJob->order != ma_atomic_load_32(&pDataBufferNode->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); - - /* The event needs to be signalled last. */ - if (pJob->data.resourceManager.freeDataBufferNode.pDoneNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.freeDataBufferNode.pDoneNotification); - } - - if (pJob->data.resourceManager.freeDataBufferNode.pDoneFence != NULL) { - ma_fence_release(pJob->data.resourceManager.freeDataBufferNode.pDoneFence); - } - - ma_atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); - return MA_SUCCESS; -} - -static ma_result ma_job_process__resource_manager__page_data_buffer_node(ma_job* pJob) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager* pResourceManager; - ma_resource_manager_data_buffer_node* pDataBufferNode; - - MA_ASSERT(pJob != NULL); - - pResourceManager = (ma_resource_manager*)pJob->data.resourceManager.pageDataBufferNode.pResourceManager; - MA_ASSERT(pResourceManager != NULL); - - pDataBufferNode = (ma_resource_manager_data_buffer_node*)pJob->data.resourceManager.pageDataBufferNode.pDataBufferNode; - MA_ASSERT(pDataBufferNode != NULL); - - if (pJob->order != ma_atomic_load_32(&pDataBufferNode->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - /* Don't do any more decoding if the data buffer has started the uninitialization process. */ - result = ma_resource_manager_data_buffer_node_result(pDataBufferNode); - if (result != MA_BUSY) { - goto done; - } - - /* We're ready to decode the next page. */ - result = ma_resource_manager_data_buffer_node_decode_next_page(pResourceManager, pDataBufferNode, (ma_decoder*)pJob->data.resourceManager.pageDataBufferNode.pDecoder); - - /* - If we have a success code by this point, we want to post another job. We're going to set the - result back to MA_BUSY to make it clear that there's still more to load. - */ - if (result == MA_SUCCESS) { - ma_job newJob; - newJob = *pJob; /* Everything is the same as the input job, except the execution order. */ - newJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); /* We need a fresh execution order. */ - - result = ma_resource_manager_post_job(pResourceManager, &newJob); - - /* Since the sound isn't yet fully decoded we want the status to be set to busy. */ - if (result == MA_SUCCESS) { - result = MA_BUSY; - } - } - -done: - /* If there's still more to decode the result will be set to MA_BUSY. Otherwise we can free the decoder. */ - if (result != MA_BUSY) { - ma_decoder_uninit((ma_decoder*)pJob->data.resourceManager.pageDataBufferNode.pDecoder); - ma_free(pJob->data.resourceManager.pageDataBufferNode.pDecoder, &pResourceManager->config.allocationCallbacks); - } - - /* If we reached the end we need to treat it as successful. */ - if (result == MA_AT_END) { - result = MA_SUCCESS; - } - - /* Make sure we set the result of node in case some error occurred. */ - ma_atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result); - - /* Signal the notification after setting the result in case the notification callback wants to inspect the result code. */ - if (result != MA_BUSY) { - if (pJob->data.resourceManager.pageDataBufferNode.pDoneNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.pageDataBufferNode.pDoneNotification); - } - - if (pJob->data.resourceManager.pageDataBufferNode.pDoneFence != NULL) { - ma_fence_release(pJob->data.resourceManager.pageDataBufferNode.pDoneFence); - } - } - - ma_atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); - return result; -} - - -static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager* pResourceManager; - ma_resource_manager_data_buffer* pDataBuffer; - ma_resource_manager_data_supply_type dataSupplyType = ma_resource_manager_data_supply_type_unknown; - ma_bool32 isConnectorInitialized = MA_FALSE; - - /* - All we're doing here is checking if the node has finished loading. If not, we just re-post the job - and keep waiting. Otherwise we increment the execution counter and set the buffer's result code. - */ - MA_ASSERT(pJob != NULL); - - pDataBuffer = (ma_resource_manager_data_buffer*)pJob->data.resourceManager.loadDataBuffer.pDataBuffer; - MA_ASSERT(pDataBuffer != NULL); - - pResourceManager = pDataBuffer->pResourceManager; - - if (pJob->order != ma_atomic_load_32(&pDataBuffer->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Attempting to execute out of order. Probably interleaved with a MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER job. */ - } - - /* - First thing we need to do is check whether or not the data buffer is getting deleted. If so we - just abort, but making sure we increment the execution pointer. - */ - result = ma_resource_manager_data_buffer_result(pDataBuffer); - if (result != MA_BUSY) { - goto done; /* <-- This will ensure the execution pointer is incremented. */ - } else { - result = MA_SUCCESS; /* <-- Make sure this is reset. */ - (void)result; /* <-- This is to suppress a static analysis diagnostic about "result" not being used. But for safety when I do future maintenance I don't want to delete that assignment. */ - } - - /* Try initializing the connector if we haven't already. */ - isConnectorInitialized = ma_resource_manager_data_buffer_has_connector(pDataBuffer); - if (isConnectorInitialized == MA_FALSE) { - dataSupplyType = ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode); - - if (dataSupplyType != ma_resource_manager_data_supply_type_unknown) { - /* We can now initialize the connector. If this fails, we need to abort. It's very rare for this to fail. */ - ma_resource_manager_data_source_config dataSourceConfig; /* For setting initial looping state and range. */ - dataSourceConfig = ma_resource_manager_data_source_config_init(); - dataSourceConfig.rangeBegInPCMFrames = pJob->data.resourceManager.loadDataBuffer.rangeBegInPCMFrames; - dataSourceConfig.rangeEndInPCMFrames = pJob->data.resourceManager.loadDataBuffer.rangeEndInPCMFrames; - dataSourceConfig.loopPointBegInPCMFrames = pJob->data.resourceManager.loadDataBuffer.loopPointBegInPCMFrames; - dataSourceConfig.loopPointEndInPCMFrames = pJob->data.resourceManager.loadDataBuffer.loopPointEndInPCMFrames; - dataSourceConfig.isLooping = pJob->data.resourceManager.loadDataBuffer.isLooping; - - result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, &dataSourceConfig, pJob->data.resourceManager.loadDataBuffer.pInitNotification, pJob->data.resourceManager.loadDataBuffer.pInitFence); - if (result != MA_SUCCESS) { - ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to initialize connector for data buffer. %s.\n", ma_result_description(result)); - goto done; - } - } else { - /* Don't have a known data supply type. Most likely the data buffer node is still loading, but it could be that an error occurred. */ - } - } else { - /* The connector is already initialized. Nothing to do here. */ - } - - /* - If the data node is still loading, we need to repost the job and *not* increment the execution - pointer (i.e. we need to not fall through to the "done" label). - - There is a hole between here and the where the data connector is initialized where the data - buffer node may have finished initializing. We need to check for this by checking the result of - the data buffer node and whether or not we had an unknown data supply type at the time of - trying to initialize the data connector. - */ - result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode); - if (result == MA_BUSY || (result == MA_SUCCESS && isConnectorInitialized == MA_FALSE && dataSupplyType == ma_resource_manager_data_supply_type_unknown)) { - return ma_resource_manager_post_job(pResourceManager, pJob); - } - -done: - /* Only move away from a busy code so that we don't trash any existing error codes. */ - ma_atomic_compare_and_swap_i32(&pDataBuffer->result, MA_BUSY, result); - - /* Only signal the other threads after the result has been set just for cleanliness sake. */ - if (pJob->data.resourceManager.loadDataBuffer.pDoneNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.loadDataBuffer.pDoneNotification); - } - if (pJob->data.resourceManager.loadDataBuffer.pDoneFence != NULL) { - ma_fence_release(pJob->data.resourceManager.loadDataBuffer.pDoneFence); - } - - /* - If at this point the data buffer has not had it's connector initialized, it means the - notification event was never signalled which means we need to signal it here. - */ - if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE && result != MA_SUCCESS) { - if (pJob->data.resourceManager.loadDataBuffer.pInitNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.loadDataBuffer.pInitNotification); - } - if (pJob->data.resourceManager.loadDataBuffer.pInitFence != NULL) { - ma_fence_release(pJob->data.resourceManager.loadDataBuffer.pInitFence); - } - } - - ma_atomic_fetch_add_32(&pDataBuffer->executionPointer, 1); - return result; -} - -static ma_result ma_job_process__resource_manager__free_data_buffer(ma_job* pJob) -{ - ma_resource_manager* pResourceManager; - ma_resource_manager_data_buffer* pDataBuffer; - - MA_ASSERT(pJob != NULL); - - pDataBuffer = (ma_resource_manager_data_buffer*)pJob->data.resourceManager.freeDataBuffer.pDataBuffer; - MA_ASSERT(pDataBuffer != NULL); - - pResourceManager = pDataBuffer->pResourceManager; - - if (pJob->order != ma_atomic_load_32(&pDataBuffer->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - ma_resource_manager_data_buffer_uninit_internal(pDataBuffer); - - /* The event needs to be signalled last. */ - if (pJob->data.resourceManager.freeDataBuffer.pDoneNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.freeDataBuffer.pDoneNotification); - } - - if (pJob->data.resourceManager.freeDataBuffer.pDoneFence != NULL) { - ma_fence_release(pJob->data.resourceManager.freeDataBuffer.pDoneFence); - } - - ma_atomic_fetch_add_32(&pDataBuffer->executionPointer, 1); - return MA_SUCCESS; -} - -static ma_result ma_job_process__resource_manager__load_data_stream(ma_job* pJob) -{ - ma_result result = MA_SUCCESS; - ma_decoder_config decoderConfig; - ma_uint32 pageBufferSizeInBytes; - ma_resource_manager* pResourceManager; - ma_resource_manager_data_stream* pDataStream; - - MA_ASSERT(pJob != NULL); - - pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.loadDataStream.pDataStream; - MA_ASSERT(pDataStream != NULL); - - pResourceManager = pDataStream->pResourceManager; - - if (pJob->order != ma_atomic_load_32(&pDataStream->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - if (ma_resource_manager_data_stream_result(pDataStream) != MA_BUSY) { - result = MA_INVALID_OPERATION; /* Most likely the data stream is being uninitialized. */ - goto done; - } - - /* We need to initialize the decoder first so we can determine the size of the pages. */ - decoderConfig = ma_resource_manager__init_decoder_config(pResourceManager); - - if (pJob->data.resourceManager.loadDataStream.pFilePath != NULL) { - result = ma_decoder_init_vfs(pResourceManager->config.pVFS, pJob->data.resourceManager.loadDataStream.pFilePath, &decoderConfig, &pDataStream->decoder); - } else { - result = ma_decoder_init_vfs_w(pResourceManager->config.pVFS, pJob->data.resourceManager.loadDataStream.pFilePathW, &decoderConfig, &pDataStream->decoder); - } - if (result != MA_SUCCESS) { - goto done; - } - - /* Retrieve the total length of the file before marking the decoder as loaded. */ - if ((pDataStream->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH) == 0) { - result = ma_decoder_get_length_in_pcm_frames(&pDataStream->decoder, &pDataStream->totalLengthInPCMFrames); - if (result != MA_SUCCESS) { - goto done; /* Failed to retrieve the length. */ - } - } else { - pDataStream->totalLengthInPCMFrames = 0; - } - - /* - Only mark the decoder as initialized when the length of the decoder has been retrieved because that can possibly require a scan over the whole file - and we don't want to have another thread trying to access the decoder while it's scanning. - */ - pDataStream->isDecoderInitialized = MA_TRUE; - - /* We have the decoder so we can now initialize our page buffer. */ - pageBufferSizeInBytes = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * 2 * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels); - - pDataStream->pPageData = ma_malloc(pageBufferSizeInBytes, &pResourceManager->config.allocationCallbacks); - if (pDataStream->pPageData == NULL) { - ma_decoder_uninit(&pDataStream->decoder); - result = MA_OUT_OF_MEMORY; - goto done; - } - - /* Seek to our initial seek point before filling the initial pages. */ - ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, pJob->data.resourceManager.loadDataStream.initialSeekPoint); - - /* We have our decoder and our page buffer, so now we need to fill our pages. */ - ma_resource_manager_data_stream_fill_pages(pDataStream); - - /* And now we're done. We want to make sure the result is MA_SUCCESS. */ - result = MA_SUCCESS; - -done: - ma_free(pJob->data.resourceManager.loadDataStream.pFilePath, &pResourceManager->config.allocationCallbacks); - ma_free(pJob->data.resourceManager.loadDataStream.pFilePathW, &pResourceManager->config.allocationCallbacks); - - /* We can only change the status away from MA_BUSY. If it's set to anything else it means an error has occurred somewhere or the uninitialization process has started (most likely). */ - ma_atomic_compare_and_swap_i32(&pDataStream->result, MA_BUSY, result); - - /* Only signal the other threads after the result has been set just for cleanliness sake. */ - if (pJob->data.resourceManager.loadDataStream.pInitNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.loadDataStream.pInitNotification); - } - if (pJob->data.resourceManager.loadDataStream.pInitFence != NULL) { - ma_fence_release(pJob->data.resourceManager.loadDataStream.pInitFence); - } - - ma_atomic_fetch_add_32(&pDataStream->executionPointer, 1); - return result; -} - -static ma_result ma_job_process__resource_manager__free_data_stream(ma_job* pJob) -{ - ma_resource_manager* pResourceManager; - ma_resource_manager_data_stream* pDataStream; - - MA_ASSERT(pJob != NULL); - - pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.freeDataStream.pDataStream; - MA_ASSERT(pDataStream != NULL); - - pResourceManager = pDataStream->pResourceManager; - - if (pJob->order != ma_atomic_load_32(&pDataStream->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - /* If our status is not MA_UNAVAILABLE we have a bug somewhere. */ - MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) == MA_UNAVAILABLE); - - if (pDataStream->isDecoderInitialized) { - ma_decoder_uninit(&pDataStream->decoder); - } - - if (pDataStream->pPageData != NULL) { - ma_free(pDataStream->pPageData, &pResourceManager->config.allocationCallbacks); - pDataStream->pPageData = NULL; /* Just in case... */ - } - - ma_data_source_uninit(&pDataStream->ds); - - /* The event needs to be signalled last. */ - if (pJob->data.resourceManager.freeDataStream.pDoneNotification != NULL) { - ma_async_notification_signal(pJob->data.resourceManager.freeDataStream.pDoneNotification); - } - if (pJob->data.resourceManager.freeDataStream.pDoneFence != NULL) { - ma_fence_release(pJob->data.resourceManager.freeDataStream.pDoneFence); - } - - /*ma_atomic_fetch_add_32(&pDataStream->executionPointer, 1);*/ - return MA_SUCCESS; -} - -static ma_result ma_job_process__resource_manager__page_data_stream(ma_job* pJob) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager* pResourceManager; - ma_resource_manager_data_stream* pDataStream; - - MA_ASSERT(pJob != NULL); - - pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.pageDataStream.pDataStream; - MA_ASSERT(pDataStream != NULL); - - pResourceManager = pDataStream->pResourceManager; - - if (pJob->order != ma_atomic_load_32(&pDataStream->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - /* For streams, the status should be MA_SUCCESS. */ - if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { - result = MA_INVALID_OPERATION; - goto done; - } - - ma_resource_manager_data_stream_fill_page(pDataStream, pJob->data.resourceManager.pageDataStream.pageIndex); - -done: - ma_atomic_fetch_add_32(&pDataStream->executionPointer, 1); - return result; -} - -static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob) -{ - ma_result result = MA_SUCCESS; - ma_resource_manager* pResourceManager; - ma_resource_manager_data_stream* pDataStream; - - MA_ASSERT(pJob != NULL); - - pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.seekDataStream.pDataStream; - MA_ASSERT(pDataStream != NULL); - - pResourceManager = pDataStream->pResourceManager; - - if (pJob->order != ma_atomic_load_32(&pDataStream->executionPointer)) { - return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ - } - - /* For streams the status should be MA_SUCCESS for this to do anything. */ - if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS || pDataStream->isDecoderInitialized == MA_FALSE) { - result = MA_INVALID_OPERATION; - goto done; - } - - /* - With seeking we just assume both pages are invalid and the relative frame cursor at position 0. This is basically exactly the same as loading, except - instead of initializing the decoder, we seek to a frame. - */ - ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, pJob->data.resourceManager.seekDataStream.frameIndex); - - /* After seeking we'll need to reload the pages. */ - ma_resource_manager_data_stream_fill_pages(pDataStream); - - /* We need to let the public API know that we're done seeking. */ - ma_atomic_fetch_sub_32(&pDataStream->seekCounter, 1); - -done: - ma_atomic_fetch_add_32(&pDataStream->executionPointer, 1); - return result; -} - -MA_API ma_result ma_resource_manager_process_job(ma_resource_manager* pResourceManager, ma_job* pJob) -{ - if (pResourceManager == NULL || pJob == NULL) { - return MA_INVALID_ARGS; - } - - return ma_job_process(pJob); -} - -MA_API ma_result ma_resource_manager_process_next_job(ma_resource_manager* pResourceManager) -{ - ma_result result; - ma_job job; - - if (pResourceManager == NULL) { - return MA_INVALID_ARGS; - } - - /* This will return MA_CANCELLED if the next job is a quit job. */ - result = ma_resource_manager_next_job(pResourceManager, &job); - if (result != MA_SUCCESS) { - return result; - } - - return ma_job_process(&job); -} -#else -/* We'll get here if the resource manager is being excluded from the build. We need to define the job processing callbacks as no-ops. */ -static ma_result ma_job_process__resource_manager__load_data_buffer_node(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__page_data_buffer_node(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__free_data_buffer(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__load_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__free_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__page_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } -static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } -#endif /* MA_NO_RESOURCE_MANAGER */ - - -#ifndef MA_NO_NODE_GRAPH - -static ma_stack* ma_stack_init(size_t sizeInBytes, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_stack* pStack; - - if (sizeInBytes == 0) { - return NULL; - } - - pStack = (ma_stack*)ma_malloc(sizeof(*pStack) - sizeof(pStack->_data) + sizeInBytes, pAllocationCallbacks); - if (pStack == NULL) { - return NULL; - } - - pStack->offset = 0; - pStack->sizeInBytes = sizeInBytes; - - return pStack; -} - -static void ma_stack_uninit(ma_stack* pStack, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pStack == NULL) { - return; - } - - ma_free(pStack, pAllocationCallbacks); -} - -static void* ma_stack_alloc(ma_stack* pStack, size_t sz) -{ - /* The size of the allocation is stored in the memory directly before the pointer. This needs to include padding to keep it aligned to ma_uintptr */ - void* p = (void*)((char*)pStack->_data + pStack->offset); - size_t* pSize = (size_t*)p; - - sz = (sz + (sizeof(ma_uintptr) - 1)) & ~(sizeof(ma_uintptr) - 1); /* Padding. */ - if (pStack->offset + sz + sizeof(size_t) > pStack->sizeInBytes) { - return NULL; /* Out of memory. */ - } - - pStack->offset += sz + sizeof(size_t); - - *pSize = sz; - return (void*)((char*)p + sizeof(size_t)); -} - -static void ma_stack_free(ma_stack* pStack, void* p) -{ - size_t* pSize; - - if (p == NULL) { - return; - } - - pSize = (size_t*)p - 1; - pStack->offset -= *pSize + sizeof(size_t); -} - - - -/* 10ms @ 48K = 480. Must never exceed 65535. */ -#ifndef MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS -#define MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS 480 -#endif - -#ifndef MA_DEFAULT_PREMIX_STACK_SIZE_PER_CHANNEL -#define MA_DEFAULT_PREMIX_STACK_SIZE_PER_CHANNEL 524288 -#endif - -static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime); - -MA_API void ma_debug_fill_pcm_frames_with_sine_wave(float* pFramesOut, ma_uint32 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) -{ - #ifndef MA_NO_GENERATION - { - ma_waveform_config waveformConfig; - ma_waveform waveform; - - waveformConfig = ma_waveform_config_init(format, channels, sampleRate, ma_waveform_type_sine, 1.0, 400); - ma_waveform_init(&waveformConfig, &waveform); - ma_waveform_read_pcm_frames(&waveform, pFramesOut, frameCount, NULL); - } - #else - { - (void)pFramesOut; - (void)frameCount; - (void)format; - (void)channels; - (void)sampleRate; - #if defined(MA_DEBUG_OUTPUT) - { - #if _MSC_VER - #pragma message ("ma_debug_fill_pcm_frames_with_sine_wave() will do nothing because MA_NO_GENERATION is enabled.") - #endif - } - #endif - } - #endif -} - - - -MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels) -{ - ma_node_graph_config config; - - MA_ZERO_OBJECT(&config); - config.channels = channels; - config.processingSizeInFrames = 0; - - return config; -} - - -static void ma_node_graph_set_is_reading(ma_node_graph* pNodeGraph, ma_bool32 isReading) -{ - MA_ASSERT(pNodeGraph != NULL); - ma_atomic_exchange_32(&pNodeGraph->isReading, isReading); -} - -#if 0 -static ma_bool32 ma_node_graph_is_reading(ma_node_graph* pNodeGraph) -{ - MA_ASSERT(pNodeGraph != NULL); - return ma_atomic_load_32(&pNodeGraph->isReading); -} -#endif - - -static void ma_node_graph_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_node_graph* pNodeGraph = (ma_node_graph*)pNode; - ma_uint64 framesRead; - - ma_node_graph_read_pcm_frames(pNodeGraph, ppFramesOut[0], *pFrameCountOut, &framesRead); - - *pFrameCountOut = (ma_uint32)framesRead; /* Safe cast. */ - - (void)ppFramesIn; - (void)pFrameCountIn; -} - -static ma_node_vtable g_node_graph_node_vtable = -{ - ma_node_graph_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 0, /* 0 input buses. */ - 1, /* 1 output bus. */ - 0 /* Flags. */ -}; - -static void ma_node_graph_endpoint_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - MA_ASSERT(pNode != NULL); - MA_ASSERT(ma_node_get_input_bus_count(pNode) == 1); - MA_ASSERT(ma_node_get_output_bus_count(pNode) == 1); - - /* Input channel count needs to be the same as the output channel count. */ - MA_ASSERT(ma_node_get_input_channels(pNode, 0) == ma_node_get_output_channels(pNode, 0)); - - /* We don't need to do anything here because it's a passthrough. */ - (void)pNode; - (void)ppFramesIn; - (void)pFrameCountIn; - (void)ppFramesOut; - (void)pFrameCountOut; - -#if 0 - /* The data has already been mixed. We just need to move it to the output buffer. */ - if (ppFramesIn != NULL) { - ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, ma_node_get_output_channels(pNode, 0)); - } -#endif -} - -static ma_node_vtable g_node_graph_endpoint_vtable = -{ - ma_node_graph_endpoint_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* 1 input bus. */ - 1, /* 1 output bus. */ - MA_NODE_FLAG_PASSTHROUGH /* Flags. The endpoint is a passthrough. */ -}; - -MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph) -{ - ma_result result; - ma_node_config baseConfig; - ma_node_config endpointConfig; - - if (pNodeGraph == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNodeGraph); - pNodeGraph->processingSizeInFrames = pConfig->processingSizeInFrames; - - /* Base node so we can use the node graph as a node into another graph. */ - baseConfig = ma_node_config_init(); - baseConfig.vtable = &g_node_graph_node_vtable; - baseConfig.pOutputChannels = &pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pNodeGraph->base); - if (result != MA_SUCCESS) { - return result; - } - - - /* Endpoint. */ - endpointConfig = ma_node_config_init(); - endpointConfig.vtable = &g_node_graph_endpoint_vtable; - endpointConfig.pInputChannels = &pConfig->channels; - endpointConfig.pOutputChannels = &pConfig->channels; - - result = ma_node_init(pNodeGraph, &endpointConfig, pAllocationCallbacks, &pNodeGraph->endpoint); - if (result != MA_SUCCESS) { - ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); - return result; - } - - - /* Processing cache. */ - if (pConfig->processingSizeInFrames > 0) { - pNodeGraph->pProcessingCache = (float*)ma_malloc(pConfig->processingSizeInFrames * pConfig->channels * sizeof(float), pAllocationCallbacks); - if (pNodeGraph->pProcessingCache == NULL) { - ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); - ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); - return MA_OUT_OF_MEMORY; - } - } - - - /* - We need a pre-mix stack. The size of this stack is configurable via the config. The default value depends on the channel count. - */ - { - size_t preMixStackSizeInBytes = pConfig->preMixStackSizeInBytes; - if (preMixStackSizeInBytes == 0) { - preMixStackSizeInBytes = pConfig->channels * MA_DEFAULT_PREMIX_STACK_SIZE_PER_CHANNEL; - } - - pNodeGraph->pPreMixStack = ma_stack_init(preMixStackSizeInBytes, pAllocationCallbacks); - if (pNodeGraph->pPreMixStack == NULL) { - ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); - ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); - if (pNodeGraph->pProcessingCache != NULL) { - ma_free(pNodeGraph->pProcessingCache, pAllocationCallbacks); - } - - return MA_OUT_OF_MEMORY; - } - } - - - return MA_SUCCESS; -} - -MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pNodeGraph == NULL) { - return; - } - - ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); - ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); - - if (pNodeGraph->pProcessingCache != NULL) { - ma_free(pNodeGraph->pProcessingCache, pAllocationCallbacks); - pNodeGraph->pProcessingCache = NULL; - } - - if (pNodeGraph->pPreMixStack != NULL) { - ma_stack_uninit(pNodeGraph->pPreMixStack, pAllocationCallbacks); - pNodeGraph->pPreMixStack = NULL; - } -} - -MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph) -{ - if (pNodeGraph == NULL) { - return NULL; - } - - return &pNodeGraph->endpoint; -} - -MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result = MA_SUCCESS; - ma_uint64 totalFramesRead; - ma_uint32 channels; - - if (pFramesRead != NULL) { - *pFramesRead = 0; /* Safety. */ - } - - if (pNodeGraph == NULL) { - return MA_INVALID_ARGS; - } - - channels = ma_node_get_output_channels(&pNodeGraph->endpoint, 0); - - - /* We'll be nice and try to do a full read of all frameCount frames. */ - totalFramesRead = 0; - while (totalFramesRead < frameCount) { - ma_uint32 framesJustRead; - ma_uint64 framesToRead; - float* pRunningFramesOut; - - framesToRead = frameCount - totalFramesRead; - if (framesToRead > 0xFFFFFFFF) { - framesToRead = 0xFFFFFFFF; - } - - pRunningFramesOut = (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels); - - /* If there's anything in the cache, consume that first. */ - if (pNodeGraph->processingCacheFramesRemaining > 0) { - ma_uint32 framesToReadFromCache; - - framesToReadFromCache = (ma_uint32)framesToRead; - if (framesToReadFromCache > pNodeGraph->processingCacheFramesRemaining) { - framesToReadFromCache = pNodeGraph->processingCacheFramesRemaining; - } - - MA_COPY_MEMORY(pRunningFramesOut, pNodeGraph->pProcessingCache, framesToReadFromCache * channels * sizeof(float)); - MA_MOVE_MEMORY(pNodeGraph->pProcessingCache, pNodeGraph->pProcessingCache + (framesToReadFromCache * channels), (pNodeGraph->processingCacheFramesRemaining - framesToReadFromCache) * channels * sizeof(float)); - pNodeGraph->processingCacheFramesRemaining -= framesToReadFromCache; - - totalFramesRead += framesToReadFromCache; - continue; - } else { - /* - If processingSizeInFrames is non-zero, we need to make sure we always read in chunks of that size. If the frame count is less than - that, we need to read into the cache and then continue on. - */ - float* pReadDst = pRunningFramesOut; - - if (pNodeGraph->processingSizeInFrames > 0) { - if (framesToRead < pNodeGraph->processingSizeInFrames) { - pReadDst = pNodeGraph->pProcessingCache; /* We need to read into the cache because otherwise we'll overflow the output buffer. */ - } - - framesToRead = pNodeGraph->processingSizeInFrames; - } - - ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE); - { - result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, pReadDst, (ma_uint32)framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint)); - } - ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE); - - /* - Do not increment the total frames read counter if we read into the cache. We use this to determine how many frames have - been written to the final output buffer. - */ - if (pReadDst == pNodeGraph->pProcessingCache) { - /* We read into the cache. */ - pNodeGraph->processingCacheFramesRemaining = framesJustRead; - } else { - /* We read straight into the output buffer. */ - totalFramesRead += framesJustRead; - } - - if (result != MA_SUCCESS) { - break; - } - - /* Abort if we weren't able to read any frames or else we risk getting stuck in a loop. */ - if (framesJustRead == 0) { - break; - } - } - } - - /* Let's go ahead and silence any leftover frames just for some added safety to ensure the caller doesn't try emitting garbage out of the speakers. */ - if (totalFramesRead < frameCount) { - ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (frameCount - totalFramesRead), ma_format_f32, channels); - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - return result; -} - -MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph) -{ - if (pNodeGraph == NULL) { - return 0; - } - - return ma_node_get_output_channels(&pNodeGraph->endpoint, 0); -} - -MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph) -{ - if (pNodeGraph == NULL) { - return 0; - } - - return ma_node_get_time(&pNodeGraph->endpoint); /* Global time is just the local time of the endpoint. */ -} - -MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime) -{ - if (pNodeGraph == NULL) { - return MA_INVALID_ARGS; - } - - return ma_node_set_time(&pNodeGraph->endpoint, globalTime); /* Global time is just the local time of the endpoint. */ -} - - -#define MA_NODE_OUTPUT_BUS_FLAG_HAS_READ 0x01 /* Whether or not this bus ready to read more data. Only used on nodes with multiple output buses. */ - -static ma_result ma_node_output_bus_init(ma_node* pNode, ma_uint32 outputBusIndex, ma_uint32 channels, ma_node_output_bus* pOutputBus) -{ - MA_ASSERT(pOutputBus != NULL); - MA_ASSERT(outputBusIndex < MA_MAX_NODE_BUS_COUNT); - MA_ASSERT(outputBusIndex < ma_node_get_output_bus_count(pNode)); - MA_ASSERT(channels < 256); - - MA_ZERO_OBJECT(pOutputBus); - - if (channels == 0) { - return MA_INVALID_ARGS; - } - - pOutputBus->pNode = pNode; - pOutputBus->outputBusIndex = (ma_uint8)outputBusIndex; - pOutputBus->channels = (ma_uint8)channels; - pOutputBus->flags = MA_NODE_OUTPUT_BUS_FLAG_HAS_READ; /* <-- Important that this flag is set by default. */ - pOutputBus->volume = 1; - - return MA_SUCCESS; -} - -static void ma_node_output_bus_lock(ma_node_output_bus* pOutputBus) -{ - ma_spinlock_lock(&pOutputBus->lock); -} - -static void ma_node_output_bus_unlock(ma_node_output_bus* pOutputBus) -{ - ma_spinlock_unlock(&pOutputBus->lock); -} - - -static ma_uint32 ma_node_output_bus_get_channels(const ma_node_output_bus* pOutputBus) -{ - return pOutputBus->channels; -} - - -static void ma_node_output_bus_set_has_read(ma_node_output_bus* pOutputBus, ma_bool32 hasRead) -{ - if (hasRead) { - ma_atomic_fetch_or_32(&pOutputBus->flags, MA_NODE_OUTPUT_BUS_FLAG_HAS_READ); - } else { - ma_atomic_fetch_and_32(&pOutputBus->flags, (ma_uint32)~MA_NODE_OUTPUT_BUS_FLAG_HAS_READ); - } -} - -static ma_bool32 ma_node_output_bus_has_read(ma_node_output_bus* pOutputBus) -{ - return (ma_atomic_load_32(&pOutputBus->flags) & MA_NODE_OUTPUT_BUS_FLAG_HAS_READ) != 0; -} - - -static void ma_node_output_bus_set_is_attached(ma_node_output_bus* pOutputBus, ma_bool32 isAttached) -{ - ma_atomic_exchange_32(&pOutputBus->isAttached, isAttached); -} - -static ma_bool32 ma_node_output_bus_is_attached(ma_node_output_bus* pOutputBus) -{ - return ma_atomic_load_32(&pOutputBus->isAttached); -} - - -static ma_result ma_node_output_bus_set_volume(ma_node_output_bus* pOutputBus, float volume) -{ - MA_ASSERT(pOutputBus != NULL); - - if (volume < 0.0f) { - volume = 0.0f; - } - - ma_atomic_exchange_f32(&pOutputBus->volume, volume); - - return MA_SUCCESS; -} - -static float ma_node_output_bus_get_volume(const ma_node_output_bus* pOutputBus) -{ - return ma_atomic_load_f32((float*)&pOutputBus->volume); -} - - -static ma_result ma_node_input_bus_init(ma_uint32 channels, ma_node_input_bus* pInputBus) -{ - MA_ASSERT(pInputBus != NULL); - MA_ASSERT(channels < 256); - - MA_ZERO_OBJECT(pInputBus); - - if (channels == 0) { - return MA_INVALID_ARGS; - } - - pInputBus->channels = (ma_uint8)channels; - - return MA_SUCCESS; -} - -static void ma_node_input_bus_lock(ma_node_input_bus* pInputBus) -{ - MA_ASSERT(pInputBus != NULL); - - ma_spinlock_lock(&pInputBus->lock); -} - -static void ma_node_input_bus_unlock(ma_node_input_bus* pInputBus) -{ - MA_ASSERT(pInputBus != NULL); - - ma_spinlock_unlock(&pInputBus->lock); -} - - -static void ma_node_input_bus_next_begin(ma_node_input_bus* pInputBus) -{ - ma_atomic_fetch_add_32(&pInputBus->nextCounter, 1); -} - -static void ma_node_input_bus_next_end(ma_node_input_bus* pInputBus) -{ - ma_atomic_fetch_sub_32(&pInputBus->nextCounter, 1); -} - -static ma_uint32 ma_node_input_bus_get_next_counter(ma_node_input_bus* pInputBus) -{ - return ma_atomic_load_32(&pInputBus->nextCounter); -} - - -static ma_uint32 ma_node_input_bus_get_channels(const ma_node_input_bus* pInputBus) -{ - return pInputBus->channels; -} - - -static void ma_node_input_bus_detach__no_output_bus_lock(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus) -{ - MA_ASSERT(pInputBus != NULL); - MA_ASSERT(pOutputBus != NULL); - - /* - Mark the output bus as detached first. This will prevent future iterations on the audio thread - from iterating this output bus. - */ - ma_node_output_bus_set_is_attached(pOutputBus, MA_FALSE); - - /* - We cannot use the output bus lock here since it'll be getting used at a higher level, but we do - still need to use the input bus lock since we'll be updating pointers on two different output - buses. The same rules apply here as the attaching case. Although we're using a lock here, we're - *not* using a lock when iterating over the list in the audio thread. We therefore need to craft - this in a way such that the iteration on the audio thread doesn't break. - - The first thing to do is swap out the "next" pointer of the previous output bus with the - new "next" output bus. This is the operation that matters for iteration on the audio thread. - After that, the previous pointer on the new "next" pointer needs to be updated, after which - point the linked list will be in a good state. - */ - ma_node_input_bus_lock(pInputBus); - { - ma_node_output_bus* pOldPrev = (ma_node_output_bus*)ma_atomic_load_ptr(&pOutputBus->pPrev); - ma_node_output_bus* pOldNext = (ma_node_output_bus*)ma_atomic_load_ptr(&pOutputBus->pNext); - - if (pOldPrev != NULL) { - ma_atomic_exchange_ptr(&pOldPrev->pNext, pOldNext); /* <-- This is where the output bus is detached from the list. */ - } - if (pOldNext != NULL) { - ma_atomic_exchange_ptr(&pOldNext->pPrev, pOldPrev); /* <-- This is required for detachment. */ - } - } - ma_node_input_bus_unlock(pInputBus); - - /* At this point the output bus is detached and the linked list is completely unaware of it. Reset some data for safety. */ - ma_atomic_exchange_ptr(&pOutputBus->pNext, NULL); /* Using atomic exchanges here, mainly for the benefit of analysis tools which don't always recognize spinlocks. */ - ma_atomic_exchange_ptr(&pOutputBus->pPrev, NULL); /* As above. */ - pOutputBus->pInputNode = NULL; - pOutputBus->inputNodeInputBusIndex = 0; - - - /* - For thread-safety reasons, we don't want to be returning from this straight away. We need to - wait for the audio thread to finish with the output bus. There's two things we need to wait - for. The first is the part that selects the next output bus in the list, and the other is the - part that reads from the output bus. Basically all we're doing is waiting for the input bus - to stop referencing the output bus. - - We're doing this part last because we want the section above to run while the audio thread - is finishing up with the output bus, just for efficiency reasons. We marked the output bus as - detached right at the top of this function which is going to prevent the audio thread from - iterating the output bus again. - */ - - /* Part 1: Wait for the current iteration to complete. */ - while (ma_node_input_bus_get_next_counter(pInputBus) > 0) { - ma_yield(); - } - - /* Part 2: Wait for any reads to complete. */ - while (ma_atomic_load_32(&pOutputBus->refCount) > 0) { - ma_yield(); - } - - /* - At this point we're done detaching and we can be guaranteed that the audio thread is not going - to attempt to reference this output bus again (until attached again). - */ -} - -#if 0 /* Not used at the moment, but leaving here in case I need it later. */ -static void ma_node_input_bus_detach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus) -{ - MA_ASSERT(pInputBus != NULL); - MA_ASSERT(pOutputBus != NULL); - - ma_node_output_bus_lock(pOutputBus); - { - ma_node_input_bus_detach__no_output_bus_lock(pInputBus, pOutputBus); - } - ma_node_output_bus_unlock(pOutputBus); -} -#endif - -static void ma_node_input_bus_attach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus, ma_node* pNewInputNode, ma_uint32 inputNodeInputBusIndex) -{ - MA_ASSERT(pInputBus != NULL); - MA_ASSERT(pOutputBus != NULL); - - ma_node_output_bus_lock(pOutputBus); - { - ma_node_output_bus* pOldInputNode = (ma_node_output_bus*)ma_atomic_load_ptr(&pOutputBus->pInputNode); - - /* Detach from any existing attachment first if necessary. */ - if (pOldInputNode != NULL) { - ma_node_input_bus_detach__no_output_bus_lock(pInputBus, pOutputBus); - } - - /* - At this point we can be sure the output bus is not attached to anything. The linked list in the - old input bus has been updated so that pOutputBus will not get iterated again. - */ - pOutputBus->pInputNode = pNewInputNode; /* No need for an atomic assignment here because modification of this variable always happens within a lock. */ - pOutputBus->inputNodeInputBusIndex = (ma_uint8)inputNodeInputBusIndex; - - /* - Now we need to attach the output bus to the linked list. This involves updating two pointers on - two different output buses so I'm going to go ahead and keep this simple and just use a lock. - There are ways to do this without a lock, but it's just too hard to maintain for its value. - - Although we're locking here, it's important to remember that we're *not* locking when iterating - and reading audio data since that'll be running on the audio thread. As a result we need to be - careful how we craft this so that we don't break iteration. What we're going to do is always - attach the new item so that it becomes the first item in the list. That way, as we're iterating - we won't break any links in the list and iteration will continue safely. The detaching case will - also be crafted in a way as to not break list iteration. It's important to remember to use - atomic exchanges here since no locking is happening on the audio thread during iteration. - */ - ma_node_input_bus_lock(pInputBus); - { - ma_node_output_bus* pNewPrev = &pInputBus->head; - ma_node_output_bus* pNewNext = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext); - - /* Update the local output bus. */ - ma_atomic_exchange_ptr(&pOutputBus->pPrev, pNewPrev); - ma_atomic_exchange_ptr(&pOutputBus->pNext, pNewNext); - - /* Update the other output buses to point back to the local output bus. */ - ma_atomic_exchange_ptr(&pInputBus->head.pNext, pOutputBus); /* <-- This is where the output bus is actually attached to the input bus. */ - - /* Do the previous pointer last. This is only used for detachment. */ - if (pNewNext != NULL) { - ma_atomic_exchange_ptr(&pNewNext->pPrev, pOutputBus); - } - } - ma_node_input_bus_unlock(pInputBus); - - /* - Mark the node as attached last. This is used to controlling whether or the output bus will be - iterated on the audio thread. Mainly required for detachment purposes. - */ - ma_node_output_bus_set_is_attached(pOutputBus, MA_TRUE); - } - ma_node_output_bus_unlock(pOutputBus); -} - -static ma_node_output_bus* ma_node_input_bus_next(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus) -{ - ma_node_output_bus* pNext; - - MA_ASSERT(pInputBus != NULL); - - if (pOutputBus == NULL) { - return NULL; - } - - ma_node_input_bus_next_begin(pInputBus); - { - pNext = pOutputBus; - for (;;) { - pNext = (ma_node_output_bus*)ma_atomic_load_ptr(&pNext->pNext); - if (pNext == NULL) { - break; /* Reached the end. */ - } - - if (ma_node_output_bus_is_attached(pNext) == MA_FALSE) { - continue; /* The node is not attached. Keep checking. */ - } - - /* The next node has been selected. */ - break; - } - - /* We need to increment the reference count of the selected node. */ - if (pNext != NULL) { - ma_atomic_fetch_add_32(&pNext->refCount, 1); - } - - /* The previous node is no longer being referenced. */ - ma_atomic_fetch_sub_32(&pOutputBus->refCount, 1); - } - ma_node_input_bus_next_end(pInputBus); - - return pNext; -} - -static ma_node_output_bus* ma_node_input_bus_first(ma_node_input_bus* pInputBus) -{ - return ma_node_input_bus_next(pInputBus, &pInputBus->head); -} - - - -static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_input_bus* pInputBus, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime) -{ - ma_result result = MA_SUCCESS; - ma_node_output_bus* pOutputBus; - ma_node_output_bus* pFirst; - ma_uint32 inputChannels; - ma_bool32 doesOutputBufferHaveContent = MA_FALSE; - - /* - This will be called from the audio thread which means we can't be doing any locking. Basically, - this function will not perform any locking, whereas attaching and detaching will, but crafted in - such a way that we don't need to perform any locking here. The important thing to remember is - to always iterate in a forward direction. - - In order to process any data we need to first read from all input buses. That's where this - function comes in. This iterates over each of the attachments and accumulates/mixes them. We - also convert the channels to the nodes output channel count before mixing. We want to do this - channel conversion so that the caller of this function can invoke the processing callback - without having to do it themselves. - - When we iterate over each of the attachments on the input bus, we need to read as much data as - we can from each of them so that we don't end up with holes between each of the attachments. To - do this, we need to read from each attachment in a loop and read as many frames as we can, up - to `frameCount`. - */ - MA_ASSERT(pInputNode != NULL); - MA_ASSERT(pFramesRead != NULL); /* pFramesRead is critical and must always be specified. On input it's undefined and on output it'll be set to the number of frames actually read. */ - - *pFramesRead = 0; /* Safety. */ - - inputChannels = ma_node_input_bus_get_channels(pInputBus); - - /* - We need to be careful with how we call ma_node_input_bus_first() and ma_node_input_bus_next(). They - are both critical to our lock-free thread-safety system. We can only call ma_node_input_bus_first() - once per iteration, however we have an optimization to checks whether or not it's the first item in - the list. We therefore need to store a pointer to the first item rather than repeatedly calling - ma_node_input_bus_first(). It's safe to keep hold of this pointer, so long as we don't dereference it - after calling ma_node_input_bus_next(), which we won't be. - */ - pFirst = ma_node_input_bus_first(pInputBus); - if (pFirst == NULL) { - return MA_SUCCESS; /* No attachments. Read nothing. */ - } - - for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) { - ma_uint32 framesProcessed = 0; - ma_bool32 isSilentOutput = MA_FALSE; - - MA_ASSERT(pOutputBus->pNode != NULL); - MA_ASSERT(((ma_node_base*)pOutputBus->pNode)->vtable != NULL); - - isSilentOutput = (((ma_node_base*)pOutputBus->pNode)->vtable->flags & MA_NODE_FLAG_SILENT_OUTPUT) != 0; - - if (pFramesOut != NULL) { - /* Read. */ - while (framesProcessed < frameCount) { - float* pRunningFramesOut; - ma_uint32 framesToRead; - ma_uint32 framesJustRead = 0; - - framesToRead = frameCount - framesProcessed; - pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(pFramesOut, framesProcessed, inputChannels); - - if (doesOutputBufferHaveContent == MA_FALSE) { - /* Fast path. First attachment. We just read straight into the output buffer (no mixing required). */ - result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pRunningFramesOut, framesToRead, &framesJustRead, globalTime + framesProcessed); - } else { - /* Slow path. Not the first attachment. Mixing required. */ - ma_uint32 preMixBufferCapInFrames = ((ma_node_base*)pInputNode)->cachedDataCapInFramesPerBus; - float* pPreMixBuffer = (float*)ma_stack_alloc(((ma_node_base*)pInputNode)->pNodeGraph->pPreMixStack, preMixBufferCapInFrames * inputChannels * sizeof(float)); - - if (pPreMixBuffer == NULL) { - /* - If you're hitting this assert it means you've got an unusually deep chain of nodes, you've got an excessively large processing - size, or you have a combination of both, and as a result have run out of stack space. You can increase this using the - preMixStackSizeInBytes variable in ma_node_graph_config. If you're using ma_engine, you can do it via the preMixStackSizeInBytes - variable in ma_engine_config. It defaults to 512KB per output channel. - */ - MA_ASSERT(MA_FALSE); - } else { - if (framesToRead > preMixBufferCapInFrames) { - framesToRead = preMixBufferCapInFrames; - } - - result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pPreMixBuffer, framesToRead, &framesJustRead, globalTime + framesProcessed); - if (result == MA_SUCCESS || result == MA_AT_END) { - if (isSilentOutput == MA_FALSE) { /* Don't mix if the node outputs silence. */ - ma_mix_pcm_frames_f32(pRunningFramesOut, pPreMixBuffer, framesJustRead, inputChannels, /*volume*/1); - } - } - - /* The pre-mix buffer is no longer required. */ - ma_stack_free(((ma_node_base*)pInputNode)->pNodeGraph->pPreMixStack, pPreMixBuffer); - pPreMixBuffer = NULL; - } - } - - framesProcessed += framesJustRead; - - /* If we reached the end or otherwise failed to read any data we need to finish up with this output node. */ - if (result != MA_SUCCESS) { - break; - } - - /* If we didn't read anything, abort so we don't get stuck in a loop. */ - if (framesJustRead == 0) { - break; - } - } - - /* If it's the first attachment we didn't do any mixing. Any leftover samples need to be silenced. */ - if (pOutputBus == pFirst && framesProcessed < frameCount) { - ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, framesProcessed, ma_format_f32, inputChannels), (frameCount - framesProcessed), ma_format_f32, inputChannels); - } - - if (isSilentOutput == MA_FALSE) { - doesOutputBufferHaveContent = MA_TRUE; - } - } else { - /* Seek. */ - ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, NULL, frameCount, &framesProcessed, globalTime); - } - } - - /* If we didn't output anything, output silence. */ - if (doesOutputBufferHaveContent == MA_FALSE && pFramesOut != NULL) { - ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, inputChannels); - } - - /* In this path we always "process" the entire amount. */ - *pFramesRead = frameCount; - - return result; -} - - -MA_API ma_node_config ma_node_config_init(void) -{ - ma_node_config config; - - MA_ZERO_OBJECT(&config); - config.initialState = ma_node_state_started; /* Nodes are started by default. */ - config.inputBusCount = MA_NODE_BUS_COUNT_UNKNOWN; - config.outputBusCount = MA_NODE_BUS_COUNT_UNKNOWN; - - return config; -} - -static ma_uint16 ma_node_config_get_cache_size_in_frames(const ma_node_config* pConfig, const ma_node_graph* pNodeGraph) -{ - ma_uint32 cacheSizeInFrames; - - (void)pConfig; - - if (pNodeGraph->processingSizeInFrames > 0) { - cacheSizeInFrames = pNodeGraph->processingSizeInFrames; - } else { - cacheSizeInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; - } - - if (cacheSizeInFrames > 0xFFFF) { - cacheSizeInFrames = 0xFFFF; - } - - return (ma_uint16)cacheSizeInFrames; -} - - - -static ma_result ma_node_detach_full(ma_node* pNode); - -static float* ma_node_get_cached_input_ptr(ma_node* pNode, ma_uint32 inputBusIndex) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_uint32 iInputBus; - float* pBasePtr; - - MA_ASSERT(pNodeBase != NULL); - - /* Input data is stored at the front of the buffer. */ - pBasePtr = pNodeBase->pCachedData; - for (iInputBus = 0; iInputBus < inputBusIndex; iInputBus += 1) { - pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iInputBus]); - } - - return pBasePtr; -} - -static float* ma_node_get_cached_output_ptr(ma_node* pNode, ma_uint32 outputBusIndex) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_uint32 iInputBus; - ma_uint32 iOutputBus; - float* pBasePtr; - - MA_ASSERT(pNodeBase != NULL); - - /* Cached output data starts after the input data. */ - pBasePtr = pNodeBase->pCachedData; - for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) { - pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iInputBus]); - } - - for (iOutputBus = 0; iOutputBus < outputBusIndex; iOutputBus += 1) { - pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iOutputBus]); - } - - return pBasePtr; -} - - -typedef struct -{ - size_t sizeInBytes; - size_t inputBusOffset; - size_t outputBusOffset; - size_t cachedDataOffset; - ma_uint32 inputBusCount; /* So it doesn't have to be calculated twice. */ - ma_uint32 outputBusCount; /* So it doesn't have to be calculated twice. */ -} ma_node_heap_layout; - -static ma_result ma_node_translate_bus_counts(const ma_node_config* pConfig, ma_uint32* pInputBusCount, ma_uint32* pOutputBusCount) -{ - ma_uint32 inputBusCount; - ma_uint32 outputBusCount; - - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pInputBusCount != NULL); - MA_ASSERT(pOutputBusCount != NULL); - - /* Bus counts are determined by the vtable, unless they're set to `MA_NODE_BUS_COUNT_UNKNWON`, in which case they're taken from the config. */ - if (pConfig->vtable->inputBusCount == MA_NODE_BUS_COUNT_UNKNOWN) { - inputBusCount = pConfig->inputBusCount; - } else { - inputBusCount = pConfig->vtable->inputBusCount; - - if (pConfig->inputBusCount != MA_NODE_BUS_COUNT_UNKNOWN && pConfig->inputBusCount != pConfig->vtable->inputBusCount) { - return MA_INVALID_ARGS; /* Invalid configuration. You must not specify a conflicting bus count between the node's config and the vtable. */ - } - } - - if (pConfig->vtable->outputBusCount == MA_NODE_BUS_COUNT_UNKNOWN) { - outputBusCount = pConfig->outputBusCount; - } else { - outputBusCount = pConfig->vtable->outputBusCount; - - if (pConfig->outputBusCount != MA_NODE_BUS_COUNT_UNKNOWN && pConfig->outputBusCount != pConfig->vtable->outputBusCount) { - return MA_INVALID_ARGS; /* Invalid configuration. You must not specify a conflicting bus count between the node's config and the vtable. */ - } - } - - /* Bus counts must be within limits. */ - if (inputBusCount > MA_MAX_NODE_BUS_COUNT || outputBusCount > MA_MAX_NODE_BUS_COUNT) { - return MA_INVALID_ARGS; - } - - - /* We must have channel counts for each bus. */ - if ((inputBusCount > 0 && pConfig->pInputChannels == NULL) || (outputBusCount > 0 && pConfig->pOutputChannels == NULL)) { - return MA_INVALID_ARGS; /* You must specify channel counts for each input and output bus. */ - } - - - /* Some special rules for passthrough nodes. */ - if ((pConfig->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { - if ((pConfig->vtable->inputBusCount != 0 && pConfig->vtable->inputBusCount != 1) || pConfig->vtable->outputBusCount != 1) { - return MA_INVALID_ARGS; /* Passthrough nodes must have exactly 1 output bus and either 0 or 1 input bus. */ - } - - if (pConfig->pInputChannels[0] != pConfig->pOutputChannels[0]) { - return MA_INVALID_ARGS; /* Passthrough nodes must have the same number of channels between input and output nodes. */ - } - } - - - *pInputBusCount = inputBusCount; - *pOutputBusCount = outputBusCount; - - return MA_SUCCESS; -} - -static ma_result ma_node_get_heap_layout(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, ma_node_heap_layout* pHeapLayout) -{ - ma_result result; - ma_uint32 inputBusCount; - ma_uint32 outputBusCount; - - MA_ASSERT(pHeapLayout != NULL); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL || pConfig->vtable == NULL || pConfig->vtable->onProcess == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_node_translate_bus_counts(pConfig, &inputBusCount, &outputBusCount); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->sizeInBytes = 0; - - /* Input buses. */ - if (inputBusCount > MA_MAX_NODE_LOCAL_BUS_COUNT) { - pHeapLayout->inputBusOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(sizeof(ma_node_input_bus) * inputBusCount); - } else { - pHeapLayout->inputBusOffset = MA_SIZE_MAX; /* MA_SIZE_MAX indicates that no heap allocation is required for the input bus. */ - } - - /* Output buses. */ - if (outputBusCount > MA_MAX_NODE_LOCAL_BUS_COUNT) { - pHeapLayout->outputBusOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(sizeof(ma_node_output_bus) * outputBusCount); - } else { - pHeapLayout->outputBusOffset = MA_SIZE_MAX; - } - - /* - Cached audio data. - - We need to allocate memory for caching both input and output data. We have an optimization - where no caching is necessary for specific conditions: - - - The node has 0 inputs and 1 output. - - When a node meets the above conditions, no cache is allocated. - - The size choice for this buffer is a little bit finicky. We don't want to be too wasteful by - allocating too much, but at the same time we want it be large enough so that enough frames can - be processed for each call to ma_node_read_pcm_frames() so that it keeps things efficient. For - now I'm going with 10ms @ 48K which is 480 frames per bus. This is configurable at compile - time. It might also be worth investigating whether or not this can be configured at run time. - */ - if (inputBusCount == 0 && outputBusCount == 1) { - /* Fast path. No cache needed. */ - pHeapLayout->cachedDataOffset = MA_SIZE_MAX; - } else { - /* Slow path. Cache needed. */ - size_t cachedDataSizeInBytes = 0; - ma_uint32 cacheCapInFrames; - ma_uint32 iBus; - - /* The capacity of the cache is based on our callback processing size. */ - cacheCapInFrames = ma_node_config_get_cache_size_in_frames(pConfig, pNodeGraph); - - for (iBus = 0; iBus < inputBusCount; iBus += 1) { - cachedDataSizeInBytes += cacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]); - } - - for (iBus = 0; iBus < outputBusCount; iBus += 1) { - cachedDataSizeInBytes += cacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]); - } - - pHeapLayout->cachedDataOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(cachedDataSizeInBytes); - } - - - /* - Not technically part of the heap, but we can output the input and output bus counts so we can - avoid a redundant call to ma_node_translate_bus_counts(). - */ - pHeapLayout->inputBusCount = inputBusCount; - pHeapLayout->outputBusCount = outputBusCount; - - /* Make sure allocation size is aligned. */ - pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); - - return MA_SUCCESS; -} - -MA_API ma_result ma_node_get_heap_size(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_node_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_node_get_heap_layout(pNodeGraph, pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_result result; - ma_node_heap_layout heapLayout; - ma_uint32 iInputBus; - ma_uint32 iOutputBus; - - if (pNodeBase == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNodeBase); - - result = ma_node_get_heap_layout(pNodeGraph, pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - pNodeBase->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pNodeBase->pNodeGraph = pNodeGraph; - pNodeBase->vtable = pConfig->vtable; - pNodeBase->state = pConfig->initialState; - pNodeBase->stateTimes[ma_node_state_started] = 0; - pNodeBase->stateTimes[ma_node_state_stopped] = (ma_uint64)(ma_int64)-1; /* Weird casting for VC6 compatibility. */ - pNodeBase->inputBusCount = heapLayout.inputBusCount; - pNodeBase->outputBusCount = heapLayout.outputBusCount; - - if (heapLayout.inputBusOffset != MA_SIZE_MAX) { - pNodeBase->pInputBuses = (ma_node_input_bus*)ma_offset_ptr(pHeap, heapLayout.inputBusOffset); - } else { - pNodeBase->pInputBuses = pNodeBase->_inputBuses; - } - - if (heapLayout.outputBusOffset != MA_SIZE_MAX) { - pNodeBase->pOutputBuses = (ma_node_output_bus*)ma_offset_ptr(pHeap, heapLayout.outputBusOffset); - } else { - pNodeBase->pOutputBuses = pNodeBase->_outputBuses; - } - - if (heapLayout.cachedDataOffset != MA_SIZE_MAX) { - pNodeBase->pCachedData = (float*)ma_offset_ptr(pHeap, heapLayout.cachedDataOffset); - pNodeBase->cachedDataCapInFramesPerBus = ma_node_config_get_cache_size_in_frames(pConfig, pNodeGraph); - } else { - pNodeBase->pCachedData = NULL; - } - - - /* We need to run an initialization step for each input and output bus. */ - for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) { - result = ma_node_input_bus_init(pConfig->pInputChannels[iInputBus], &pNodeBase->pInputBuses[iInputBus]); - if (result != MA_SUCCESS) { - return result; - } - } - - for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNodeBase); iOutputBus += 1) { - result = ma_node_output_bus_init(pNodeBase, iOutputBus, pConfig->pOutputChannels[iOutputBus], &pNodeBase->pOutputBuses[iOutputBus]); - if (result != MA_SUCCESS) { - return result; - } - } - - - /* The cached data needs to be initialized to silence (or a sine wave tone if we're debugging). */ - if (pNodeBase->pCachedData != NULL) { - ma_uint32 iBus; - - #if 1 /* Toggle this between 0 and 1 to turn debugging on or off. 1 = fill with a sine wave for debugging; 0 = fill with silence. */ - /* For safety we'll go ahead and default the buffer to silence. */ - for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) { - ma_silence_pcm_frames(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iBus])); - } - for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) { - ma_silence_pcm_frames(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iBus])); - } - #else - /* For debugging. Default to a sine wave. */ - for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) { - ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iBus]), 48000); - } - for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) { - ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iBus]), 48000); - } - #endif - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_node_get_heap_size(pNodeGraph, pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_node_init_preallocated(pNodeGraph, pConfig, pHeap, pNode); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - ((ma_node_base*)pNode)->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - - if (pNodeBase == NULL) { - return; - } - - /* - The first thing we need to do is fully detach the node. This will detach all inputs and - outputs. We need to do this first because it will sever the connection with the node graph and - allow us to complete uninitialization without needing to worry about thread-safety with the - audio thread. The detachment process will wait for any local processing of the node to finish. - */ - ma_node_detach_full(pNode); - - /* - At this point the node should be completely unreferenced by the node graph and we can finish up - the uninitialization process without needing to worry about thread-safety. - */ - if (pNodeBase->_ownsHeap) { - ma_free(pNodeBase->_pHeap, pAllocationCallbacks); - } -} - -MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode) -{ - if (pNode == NULL) { - return NULL; - } - - return ((const ma_node_base*)pNode)->pNodeGraph; -} - -MA_API ma_uint32 ma_node_get_input_bus_count(const ma_node* pNode) -{ - if (pNode == NULL) { - return 0; - } - - return ((ma_node_base*)pNode)->inputBusCount; -} - -MA_API ma_uint32 ma_node_get_output_bus_count(const ma_node* pNode) -{ - if (pNode == NULL) { - return 0; - } - - return ((ma_node_base*)pNode)->outputBusCount; -} - - -MA_API ma_uint32 ma_node_get_input_channels(const ma_node* pNode, ma_uint32 inputBusIndex) -{ - const ma_node_base* pNodeBase = (const ma_node_base*)pNode; - - if (pNode == NULL) { - return 0; - } - - if (inputBusIndex >= ma_node_get_input_bus_count(pNode)) { - return 0; /* Invalid bus index. */ - } - - return ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[inputBusIndex]); -} - -MA_API ma_uint32 ma_node_get_output_channels(const ma_node* pNode, ma_uint32 outputBusIndex) -{ - const ma_node_base* pNodeBase = (const ma_node_base*)pNode; - - if (pNode == NULL) { - return 0; - } - - if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { - return 0; /* Invalid bus index. */ - } - - return ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[outputBusIndex]); -} - - -static ma_result ma_node_detach_full(ma_node* pNode) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_uint32 iInputBus; - - if (pNodeBase == NULL) { - return MA_INVALID_ARGS; - } - - /* - Make sure the node is completely detached first. This will not return until the output bus is - guaranteed to no longer be referenced by the audio thread. - */ - ma_node_detach_all_output_buses(pNode); - - /* - At this point all output buses will have been detached from the graph and we can be guaranteed - that none of its input nodes will be getting processed by the graph. We can detach these - without needing to worry about the audio thread touching them. - */ - for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNode); iInputBus += 1) { - ma_node_input_bus* pInputBus; - ma_node_output_bus* pOutputBus; - - pInputBus = &pNodeBase->pInputBuses[iInputBus]; - - /* - This is important. We cannot be using ma_node_input_bus_first() or ma_node_input_bus_next(). Those - functions are specifically for the audio thread. We'll instead just manually iterate using standard - linked list logic. We don't need to worry about the audio thread referencing these because the step - above severed the connection to the graph. - */ - for (pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext)) { - ma_node_detach_output_bus(pOutputBus->pNode, pOutputBus->outputBusIndex); /* This won't do any waiting in practice and should be efficient. */ - } - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex) -{ - ma_result result = MA_SUCCESS; - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_node_base* pInputNodeBase; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { - return MA_INVALID_ARGS; /* Invalid output bus index. */ - } - - /* We need to lock the output bus because we need to inspect the input node and grab its input bus. */ - ma_node_output_bus_lock(&pNodeBase->pOutputBuses[outputBusIndex]); - { - pInputNodeBase = (ma_node_base*)pNodeBase->pOutputBuses[outputBusIndex].pInputNode; - if (pInputNodeBase != NULL) { - ma_node_input_bus_detach__no_output_bus_lock(&pInputNodeBase->pInputBuses[pNodeBase->pOutputBuses[outputBusIndex].inputNodeInputBusIndex], &pNodeBase->pOutputBuses[outputBusIndex]); - } - } - ma_node_output_bus_unlock(&pNodeBase->pOutputBuses[outputBusIndex]); - - return result; -} - -MA_API ma_result ma_node_detach_all_output_buses(ma_node* pNode) -{ - ma_uint32 iOutputBus; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNode); iOutputBus += 1) { - ma_node_detach_output_bus(pNode, iOutputBus); - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_node_attach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex, ma_node* pOtherNode, ma_uint32 otherNodeInputBusIndex) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_node_base* pOtherNodeBase = (ma_node_base*)pOtherNode; - - if (pNodeBase == NULL || pOtherNodeBase == NULL) { - return MA_INVALID_ARGS; - } - - if (pNodeBase == pOtherNodeBase) { - return MA_INVALID_OPERATION; /* Cannot attach a node to itself. */ - } - - if (outputBusIndex >= ma_node_get_output_bus_count(pNode) || otherNodeInputBusIndex >= ma_node_get_input_bus_count(pOtherNode)) { - return MA_INVALID_OPERATION; /* Invalid bus index. */ - } - - /* The output channel count of the output node must be the same as the input channel count of the input node. */ - if (ma_node_get_output_channels(pNode, outputBusIndex) != ma_node_get_input_channels(pOtherNode, otherNodeInputBusIndex)) { - return MA_INVALID_OPERATION; /* Channel count is incompatible. */ - } - - /* This will deal with detaching if the output bus is already attached to something. */ - ma_node_input_bus_attach(&pOtherNodeBase->pInputBuses[otherNodeInputBusIndex], &pNodeBase->pOutputBuses[outputBusIndex], pOtherNode, otherNodeInputBusIndex); - - return MA_SUCCESS; -} - -MA_API ma_result ma_node_set_output_bus_volume(ma_node* pNode, ma_uint32 outputBusIndex, float volume) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - - if (pNodeBase == NULL) { - return MA_INVALID_ARGS; - } - - if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { - return MA_INVALID_ARGS; /* Invalid bus index. */ - } - - return ma_node_output_bus_set_volume(&pNodeBase->pOutputBuses[outputBusIndex], volume); -} - -MA_API float ma_node_get_output_bus_volume(const ma_node* pNode, ma_uint32 outputBusIndex) -{ - const ma_node_base* pNodeBase = (const ma_node_base*)pNode; - - if (pNodeBase == NULL) { - return 0; - } - - if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { - return 0; /* Invalid bus index. */ - } - - return ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex]); -} - -MA_API ma_result ma_node_set_state(ma_node* pNode, ma_node_state state) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - - if (pNodeBase == NULL) { - return MA_INVALID_ARGS; - } - - ma_atomic_exchange_i32(&pNodeBase->state, state); - - return MA_SUCCESS; -} - -MA_API ma_node_state ma_node_get_state(const ma_node* pNode) -{ - const ma_node_base* pNodeBase = (const ma_node_base*)pNode; - - if (pNodeBase == NULL) { - return ma_node_state_stopped; - } - - return (ma_node_state)ma_atomic_load_i32(&pNodeBase->state); -} - -MA_API ma_result ma_node_set_state_time(ma_node* pNode, ma_node_state state, ma_uint64 globalTime) -{ - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - /* Validation check for safety since we'll be using this as an index into stateTimes[]. */ - if (state != ma_node_state_started && state != ma_node_state_stopped) { - return MA_INVALID_ARGS; - } - - ma_atomic_exchange_64(&((ma_node_base*)pNode)->stateTimes[state], globalTime); - - return MA_SUCCESS; -} - -MA_API ma_uint64 ma_node_get_state_time(const ma_node* pNode, ma_node_state state) -{ - if (pNode == NULL) { - return 0; - } - - /* Validation check for safety since we'll be using this as an index into stateTimes[]. */ - if (state != ma_node_state_started && state != ma_node_state_stopped) { - return 0; - } - - return ma_atomic_load_64(&((ma_node_base*)pNode)->stateTimes[state]); -} - -MA_API ma_node_state ma_node_get_state_by_time(const ma_node* pNode, ma_uint64 globalTime) -{ - if (pNode == NULL) { - return ma_node_state_stopped; - } - - return ma_node_get_state_by_time_range(pNode, globalTime, globalTime); -} - -MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_uint64 globalTimeBeg, ma_uint64 globalTimeEnd) -{ - ma_node_state state; - - if (pNode == NULL) { - return ma_node_state_stopped; - } - - state = ma_node_get_state(pNode); - - /* An explicitly stopped node is always stopped. */ - if (state == ma_node_state_stopped) { - return ma_node_state_stopped; - } - - /* - Getting here means the node is marked as started, but it may still not be truly started due to - its start time not having been reached yet. Also, the stop time may have also been reached in - which case it'll be considered stopped. - */ - if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeBeg) { - return ma_node_state_stopped; /* Start time has not yet been reached. */ - } - - if (ma_node_get_state_time(pNode, ma_node_state_stopped) <= globalTimeEnd) { - return ma_node_state_stopped; /* Stop time has been reached. */ - } - - /* Getting here means the node is marked as started and is within its start/stop times. */ - return ma_node_state_started; -} - -MA_API ma_uint64 ma_node_get_time(const ma_node* pNode) -{ - if (pNode == NULL) { - return 0; - } - - return ma_atomic_load_64(&((ma_node_base*)pNode)->localTime); -} - -MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime) -{ - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - ma_atomic_exchange_64(&((ma_node_base*)pNode)->localTime, localTime); - - return MA_SUCCESS; -} - - - -static void ma_node_process_pcm_frames_internal(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - - MA_ASSERT(pNode != NULL); - - if (pNodeBase->vtable->onProcess) { - pNodeBase->vtable->onProcess(pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut); - } -} - -static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_result result = MA_SUCCESS; - ma_uint32 iInputBus; - ma_uint32 iOutputBus; - ma_uint32 inputBusCount; - ma_uint32 outputBusCount; - ma_uint32 totalFramesRead = 0; - float* ppFramesIn[MA_MAX_NODE_BUS_COUNT]; - float* ppFramesOut[MA_MAX_NODE_BUS_COUNT]; - ma_uint64 globalTimeBeg; - ma_uint64 globalTimeEnd; - ma_uint64 startTime; - ma_uint64 stopTime; - ma_uint32 timeOffsetBeg; - ma_uint32 timeOffsetEnd; - ma_uint32 frameCountIn; - ma_uint32 frameCountOut; - - /* - pFramesRead is mandatory. It must be used to determine how many frames were read. It's normal and - expected that the number of frames read may be different to that requested. Therefore, the caller - must look at this value to correctly determine how many frames were read. - */ - MA_ASSERT(pFramesRead != NULL); /* <-- If you've triggered this assert, you're using this function wrong. You *must* use this variable and inspect it after the call returns. */ - if (pFramesRead == NULL) { - return MA_INVALID_ARGS; - } - - *pFramesRead = 0; /* Safety. */ - - if (pNodeBase == NULL) { - return MA_INVALID_ARGS; - } - - if (outputBusIndex >= ma_node_get_output_bus_count(pNodeBase)) { - return MA_INVALID_ARGS; /* Invalid output bus index. */ - } - - /* Don't do anything if we're in a stopped state. */ - if (ma_node_get_state_by_time_range(pNode, globalTime, globalTime + frameCount) != ma_node_state_started) { - return MA_SUCCESS; /* We're in a stopped state. This is not an error - we just need to not read anything. */ - } - - - globalTimeBeg = globalTime; - globalTimeEnd = globalTime + frameCount; - startTime = ma_node_get_state_time(pNode, ma_node_state_started); - stopTime = ma_node_get_state_time(pNode, ma_node_state_stopped); - - /* - At this point we know that we are inside our start/stop times. However, we may need to adjust - our frame count and output pointer to accommodate since we could be straddling the time period - that this function is getting called for. - - It's possible (and likely) that the start time does not line up with the output buffer. We - therefore need to offset it by a number of frames to accommodate. The same thing applies for - the stop time. - */ - timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(globalTimeEnd - startTime) : 0; - timeOffsetEnd = (globalTimeEnd > stopTime) ? (ma_uint32)(globalTimeEnd - stopTime) : 0; - - /* Trim based on the start offset. We need to silence the start of the buffer. */ - if (timeOffsetBeg > 0) { - ma_silence_pcm_frames(pFramesOut, timeOffsetBeg, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex)); - pFramesOut += timeOffsetBeg * ma_node_get_output_channels(pNode, outputBusIndex); - frameCount -= timeOffsetBeg; - } - - /* Trim based on the end offset. We don't need to silence the tail section because we'll just have a reduced value written to pFramesRead. */ - if (timeOffsetEnd > 0) { - frameCount -= timeOffsetEnd; - } - - - /* We run on different paths depending on the bus counts. */ - inputBusCount = ma_node_get_input_bus_count(pNode); - outputBusCount = ma_node_get_output_bus_count(pNode); - - /* - Run a simplified path when there are no inputs and one output. In this case there's nothing to - actually read and we can go straight to output. This is a very common scenario because the vast - majority of data source nodes will use this setup so this optimization I think is worthwhile. - */ - if (inputBusCount == 0 && outputBusCount == 1) { - /* Fast path. No need to read from input and no need for any caching. */ - frameCountIn = 0; - frameCountOut = frameCount; /* Just read as much as we can. The callback will return what was actually read. */ - - ppFramesOut[0] = pFramesOut; - - /* - If it's a passthrough we won't be expecting the callback to output anything, so we'll - need to pre-silence the output buffer. - */ - if ((pNodeBase->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { - ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex)); - } - - ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut); - totalFramesRead = frameCountOut; - } else { - /* Slow path. Need to read input data. */ - if ((pNodeBase->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { - /* - Fast path. We're running a passthrough. We need to read directly into the output buffer, but - still fire the callback so that event handling and trigger nodes can do their thing. Since - it's a passthrough there's no need for any kind of caching logic. - */ - MA_ASSERT(outputBusCount == inputBusCount); - MA_ASSERT(outputBusCount == 1); - MA_ASSERT(outputBusIndex == 0); - - /* We just read directly from input bus to output buffer, and then afterwards fire the callback. */ - ppFramesOut[0] = pFramesOut; - ppFramesIn[0] = ppFramesOut[0]; - - result = ma_node_input_bus_read_pcm_frames(pNodeBase, &pNodeBase->pInputBuses[0], ppFramesIn[0], frameCount, &totalFramesRead, globalTime); - if (result == MA_SUCCESS) { - /* Even though it's a passthrough, we still need to fire the callback. */ - frameCountIn = totalFramesRead; - frameCountOut = totalFramesRead; - - if (totalFramesRead > 0) { - ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Explicit cast to silence the warning. */ - } - - /* - A passthrough should never have modified the input and output frame counts. If you're - triggering these asserts you need to fix your processing callback. - */ - MA_ASSERT(frameCountIn == totalFramesRead); - MA_ASSERT(frameCountOut == totalFramesRead); - } - } else { - /* Slow path. Need to do caching. */ - ma_uint32 framesToProcessIn; - ma_uint32 framesToProcessOut; - ma_bool32 consumeNullInput = MA_FALSE; - - /* - We use frameCount as a basis for the number of frames to read since that's what's being - requested, however we still need to clamp it to whatever can fit in the cache. - - This will also be used as the basis for determining how many input frames to read. This is - not ideal because it can result in too many input frames being read which introduces latency. - To solve this, nodes can implement an optional callback called onGetRequiredInputFrameCount - which is used as hint to miniaudio as to how many input frames it needs to read at a time. This - callback is completely optional, and if it's not set, miniaudio will assume `frameCount`. - - This function will be called multiple times for each period of time, once for each output node. - We cannot read from each input node each time this function is called. Instead we need to check - whether or not this is first output bus to be read from for this time period, and if so, read - from our input data. - - To determine whether or not we're ready to read data, we check a flag. There will be one flag - for each output. When the flag is set, it means data has been read previously and that we're - ready to advance time forward for our input nodes by reading fresh data. - */ - framesToProcessOut = frameCount; - if (framesToProcessOut > pNodeBase->cachedDataCapInFramesPerBus) { - framesToProcessOut = pNodeBase->cachedDataCapInFramesPerBus; - } - - framesToProcessIn = frameCount; - if (pNodeBase->vtable->onGetRequiredInputFrameCount) { - pNodeBase->vtable->onGetRequiredInputFrameCount(pNode, framesToProcessOut, &framesToProcessIn); /* <-- It does not matter if this fails. */ - } - if (framesToProcessIn > pNodeBase->cachedDataCapInFramesPerBus) { - framesToProcessIn = pNodeBase->cachedDataCapInFramesPerBus; - } - - - MA_ASSERT(framesToProcessIn <= 0xFFFF); - MA_ASSERT(framesToProcessOut <= 0xFFFF); - - if (ma_node_output_bus_has_read(&pNodeBase->pOutputBuses[outputBusIndex])) { - /* Getting here means we need to do another round of processing. */ - pNodeBase->cachedFrameCountOut = 0; - - for (;;) { - frameCountOut = 0; - - /* - We need to prepare our output frame pointers for processing. In the same iteration we need - to mark every output bus as unread so that future calls to this function for different buses - for the current time period don't pull in data when they should instead be reading from cache. - */ - for (iOutputBus = 0; iOutputBus < outputBusCount; iOutputBus += 1) { - ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[iOutputBus], MA_FALSE); /* <-- This is what tells the next calls to this function for other output buses for this time period to read from cache instead of pulling in more data. */ - ppFramesOut[iOutputBus] = ma_node_get_cached_output_ptr(pNode, iOutputBus); - } - - /* We only need to read from input buses if there isn't already some data in the cache. */ - if (pNodeBase->cachedFrameCountIn == 0) { - ma_uint32 maxFramesReadIn = 0; - - /* Here is where we pull in data from the input buses. This is what will trigger an advance in time. */ - for (iInputBus = 0; iInputBus < inputBusCount; iInputBus += 1) { - ma_uint32 framesRead; - - /* The first thing to do is get the offset within our bulk allocation to store this input data. */ - ppFramesIn[iInputBus] = ma_node_get_cached_input_ptr(pNode, iInputBus); - - /* Once we've determined our destination pointer we can read. Note that we must inspect the number of frames read and fill any leftovers with silence for safety. */ - result = ma_node_input_bus_read_pcm_frames(pNodeBase, &pNodeBase->pInputBuses[iInputBus], ppFramesIn[iInputBus], framesToProcessIn, &framesRead, globalTime); - if (result != MA_SUCCESS) { - /* It doesn't really matter if we fail because we'll just fill with silence. */ - framesRead = 0; /* Just for safety, but I don't think it's really needed. */ - } - - /* TODO: Minor optimization opportunity here. If no frames were read and the buffer is already filled with silence, no need to re-silence it. */ - /* Any leftover frames need to silenced for safety. */ - if (framesRead < framesToProcessIn) { - ma_silence_pcm_frames(ppFramesIn[iInputBus] + (framesRead * ma_node_get_input_channels(pNodeBase, iInputBus)), (framesToProcessIn - framesRead), ma_format_f32, ma_node_get_input_channels(pNodeBase, iInputBus)); - } - - maxFramesReadIn = ma_max(maxFramesReadIn, framesRead); - } - - /* This was a fresh load of input data so reset our consumption counter. */ - pNodeBase->consumedFrameCountIn = 0; - - /* - We don't want to keep processing if there's nothing to process, so set the number of cached - input frames to the maximum number we read from each attachment (the lesser will be padded - with silence). If we didn't read anything, this will be set to 0 and the entire buffer will - have been assigned to silence. This being equal to 0 is an important property for us because - it allows us to detect when NULL can be passed into the processing callback for the input - buffer for the purpose of continuous processing. - */ - pNodeBase->cachedFrameCountIn = (ma_uint16)maxFramesReadIn; - } else { - /* We don't need to read anything, but we do need to prepare our input frame pointers. */ - for (iInputBus = 0; iInputBus < inputBusCount; iInputBus += 1) { - ppFramesIn[iInputBus] = ma_node_get_cached_input_ptr(pNode, iInputBus) + (pNodeBase->consumedFrameCountIn * ma_node_get_input_channels(pNodeBase, iInputBus)); - } - } - - /* - At this point we have our input data so now we need to do some processing. Sneaky little - optimization here - we can set the pointer to the output buffer for this output bus so - that the final copy into the output buffer is done directly by onProcess(). - */ - if (pFramesOut != NULL) { - ppFramesOut[outputBusIndex] = ma_offset_pcm_frames_ptr_f32(pFramesOut, pNodeBase->cachedFrameCountOut, ma_node_get_output_channels(pNode, outputBusIndex)); - } - - - /* Give the processing function the entire capacity of the output buffer. */ - frameCountOut = (framesToProcessOut - pNodeBase->cachedFrameCountOut); - - /* - We need to treat nodes with continuous processing a little differently. For these ones, - we always want to fire the callback with the requested number of frames, regardless of - pNodeBase->cachedFrameCountIn, which could be 0. Also, we want to check if we can pass - in NULL for the input buffer to the callback. - */ - if ((pNodeBase->vtable->flags & MA_NODE_FLAG_CONTINUOUS_PROCESSING) != 0) { - /* We're using continuous processing. Make sure we specify the whole frame count at all times. */ - frameCountIn = framesToProcessIn; /* Give the processing function as much input data as we've got in the buffer, including any silenced padding from short reads. */ - - if ((pNodeBase->vtable->flags & MA_NODE_FLAG_ALLOW_NULL_INPUT) != 0 && pNodeBase->consumedFrameCountIn == 0 && pNodeBase->cachedFrameCountIn == 0) { - consumeNullInput = MA_TRUE; - } else { - consumeNullInput = MA_FALSE; - } - - /* - Since we're using continuous processing we're always passing in a full frame count - regardless of how much input data was read. If this is greater than what we read as - input, we'll end up with an underflow. We instead need to make sure our cached frame - count is set to the number of frames we'll be passing to the data callback. Not - doing this will result in an underflow when we "consume" the cached data later on. - - Note that this check needs to be done after the "consumeNullInput" check above because - we use the property of cachedFrameCountIn being 0 to determine whether or not we - should be passing in a null pointer to the processing callback for when the node is - configured with MA_NODE_FLAG_ALLOW_NULL_INPUT. - */ - if (pNodeBase->cachedFrameCountIn < (ma_uint16)frameCountIn) { - pNodeBase->cachedFrameCountIn = (ma_uint16)frameCountIn; - } - } else { - frameCountIn = pNodeBase->cachedFrameCountIn; /* Give the processing function as much valid input data as we've got. */ - consumeNullInput = MA_FALSE; - } - - /* - Process data slightly differently depending on whether or not we're consuming NULL - input (checked just above). - */ - if (consumeNullInput) { - ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut); - } else { - /* - We want to skip processing if there's no input data, but we can only do that safely if - we know that there is no chance of any output frames being produced. If continuous - processing is being used, this won't be a problem because the input frame count will - always be non-0. However, if continuous processing is *not* enabled and input and output - data is processed at different rates, we still need to process that last input frame - because there could be a few excess output frames needing to be produced from cached - data. The `MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES` flag is used as the indicator for - determining whether or not we need to process the node even when there are no input - frames available right now. - */ - if (frameCountIn > 0 || (pNodeBase->vtable->flags & MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES) != 0) { - ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Explicit cast to silence the warning. */ - } else { - frameCountOut = 0; /* No data was processed. */ - } - } - - /* - Thanks to our sneaky optimization above we don't need to do any data copying directly into - the output buffer - the onProcess() callback just did that for us. We do, however, need to - apply the number of input and output frames that were processed. Note that due to continuous - processing above, we need to do explicit checks here. If we just consumed a NULL input - buffer it means that no actual input data was processed from the internal buffers and we - don't want to be modifying any counters. - */ - if (consumeNullInput == MA_FALSE) { - pNodeBase->consumedFrameCountIn += (ma_uint16)frameCountIn; - pNodeBase->cachedFrameCountIn -= (ma_uint16)frameCountIn; - } - - /* The cached output frame count is always equal to what we just read. */ - pNodeBase->cachedFrameCountOut += (ma_uint16)frameCountOut; - - /* If we couldn't process any data, we're done. The loop needs to be terminated here or else we'll get stuck in a loop. */ - if (pNodeBase->cachedFrameCountOut == framesToProcessOut || (frameCountOut == 0 && frameCountIn == 0)) { - break; - } - } - } else { - /* - We're not needing to read anything from the input buffer so just read directly from our - already-processed data. - */ - if (pFramesOut != NULL) { - ma_copy_pcm_frames(pFramesOut, ma_node_get_cached_output_ptr(pNodeBase, outputBusIndex), pNodeBase->cachedFrameCountOut, ma_format_f32, ma_node_get_output_channels(pNodeBase, outputBusIndex)); - } - } - - /* The number of frames read is always equal to the number of cached output frames. */ - totalFramesRead = pNodeBase->cachedFrameCountOut; - - /* Now that we've read the data, make sure our read flag is set. */ - ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[outputBusIndex], MA_TRUE); - } - } - - /* Apply volume, if necessary. */ - ma_apply_volume_factor_f32(pFramesOut, totalFramesRead * ma_node_get_output_channels(pNodeBase, outputBusIndex), ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex])); - - /* Advance our local time forward. */ - ma_atomic_fetch_add_64(&pNodeBase->localTime, (ma_uint64)totalFramesRead); - - *pFramesRead = totalFramesRead + timeOffsetBeg; /* Must include the silenced section at the start of the buffer. */ - return result; -} - - - - -/* Data source node. */ -MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource) -{ - ma_data_source_node_config config; - - MA_ZERO_OBJECT(&config); - config.nodeConfig = ma_node_config_init(); - config.pDataSource = pDataSource; - - return config; -} - - -static void ma_data_source_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_data_source_node* pDataSourceNode = (ma_data_source_node*)pNode; - ma_format format; - ma_uint32 channels; - ma_uint32 frameCount; - ma_uint64 framesRead = 0; - - MA_ASSERT(pDataSourceNode != NULL); - MA_ASSERT(pDataSourceNode->pDataSource != NULL); - MA_ASSERT(ma_node_get_input_bus_count(pDataSourceNode) == 0); - MA_ASSERT(ma_node_get_output_bus_count(pDataSourceNode) == 1); - - /* We don't want to read from ppFramesIn at all. Instead we read from the data source. */ - (void)ppFramesIn; - (void)pFrameCountIn; - - frameCount = *pFrameCountOut; - - /* miniaudio should never be calling this with a frame count of zero. */ - MA_ASSERT(frameCount > 0); - - if (ma_data_source_get_data_format(pDataSourceNode->pDataSource, &format, &channels, NULL, NULL, 0) == MA_SUCCESS) { /* <-- Don't care about sample rate here. */ - /* The node graph system requires samples be in floating point format. This is checked in ma_data_source_node_init(). */ - MA_ASSERT(format == ma_format_f32); - (void)format; /* Just to silence some static analysis tools. */ - - ma_data_source_read_pcm_frames(pDataSourceNode->pDataSource, ppFramesOut[0], frameCount, &framesRead); - } - - *pFrameCountOut = (ma_uint32)framesRead; -} - -static ma_node_vtable g_ma_data_source_node_vtable = -{ - ma_data_source_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 0, /* 0 input buses. */ - 1, /* 1 output bus. */ - 0 -}; - -MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode) -{ - ma_result result; - ma_format format; /* For validating the format, which must be ma_format_f32. */ - ma_uint32 channels; /* For specifying the channel count of the output bus. */ - ma_node_config baseConfig; - - if (pDataSourceNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDataSourceNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_data_source_get_data_format(pConfig->pDataSource, &format, &channels, NULL, NULL, 0); /* Don't care about sample rate. This will check pDataSource for NULL. */ - if (result != MA_SUCCESS) { - return result; - } - - MA_ASSERT(format == ma_format_f32); /* <-- If you've triggered this it means your data source is not outputting floating-point samples. You must configure your data source to use ma_format_f32. */ - if (format != ma_format_f32) { - return MA_INVALID_ARGS; /* Invalid format. */ - } - - /* The channel count is defined by the data source. If the caller has manually changed the channels we just ignore it. */ - baseConfig = pConfig->nodeConfig; - baseConfig.vtable = &g_ma_data_source_node_vtable; /* Explicitly set the vtable here to prevent callers from setting it incorrectly. */ - - /* - The channel count is defined by the data source. It is invalid for the caller to manually set - the channel counts in the config. `ma_data_source_node_config_init()` will have defaulted the - channel count pointer to NULL which is how it must remain. If you trigger any of these asserts - it means you're explicitly setting the channel count. Instead, configure the output channel - count of your data source to be the necessary channel count. - */ - if (baseConfig.pOutputChannels != NULL) { - return MA_INVALID_ARGS; - } - - baseConfig.pOutputChannels = &channels; - - result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDataSourceNode->base); - if (result != MA_SUCCESS) { - return result; - } - - pDataSourceNode->pDataSource = pConfig->pDataSource; - - return MA_SUCCESS; -} - -MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_node_uninit(&pDataSourceNode->base, pAllocationCallbacks); -} - -MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping) -{ - if (pDataSourceNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_data_source_set_looping(pDataSourceNode->pDataSource, isLooping); -} - -MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode) -{ - if (pDataSourceNode == NULL) { - return MA_FALSE; - } - - return ma_data_source_is_looping(pDataSourceNode->pDataSource); -} - - - -/* Splitter Node. */ -MA_API ma_splitter_node_config ma_splitter_node_config_init(ma_uint32 channels) -{ - ma_splitter_node_config config; - - MA_ZERO_OBJECT(&config); - config.nodeConfig = ma_node_config_init(); - config.channels = channels; - config.outputBusCount = 2; - - return config; -} - - -static void ma_splitter_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_node_base* pNodeBase = (ma_node_base*)pNode; - ma_uint32 iOutputBus; - ma_uint32 channels; - - MA_ASSERT(pNodeBase != NULL); - MA_ASSERT(ma_node_get_input_bus_count(pNodeBase) == 1); - - /* We don't need to consider the input frame count - it'll be the same as the output frame count and we process everything. */ - (void)pFrameCountIn; - - /* NOTE: This assumes the same number of channels for all inputs and outputs. This was checked in ma_splitter_node_init(). */ - channels = ma_node_get_input_channels(pNodeBase, 0); - - /* Splitting is just copying the first input bus and copying it over to each output bus. */ - for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNodeBase); iOutputBus += 1) { - ma_copy_pcm_frames(ppFramesOut[iOutputBus], ppFramesIn[0], *pFrameCountOut, ma_format_f32, channels); - } -} - -static ma_node_vtable g_ma_splitter_node_vtable = -{ - ma_splitter_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* 1 input bus. */ - MA_NODE_BUS_COUNT_UNKNOWN, /* The output bus count is specified on a per-node basis. */ - 0 -}; - -MA_API ma_result ma_splitter_node_init(ma_node_graph* pNodeGraph, const ma_splitter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_splitter_node* pSplitterNode) -{ - ma_result result; - ma_node_config baseConfig; - ma_uint32 pInputChannels[1]; - ma_uint32 pOutputChannels[MA_MAX_NODE_BUS_COUNT]; - ma_uint32 iOutputBus; - - if (pSplitterNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pSplitterNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->outputBusCount > MA_MAX_NODE_BUS_COUNT) { - return MA_INVALID_ARGS; /* Too many output buses. */ - } - - /* Splitters require the same number of channels between inputs and outputs. */ - pInputChannels[0] = pConfig->channels; - for (iOutputBus = 0; iOutputBus < pConfig->outputBusCount; iOutputBus += 1) { - pOutputChannels[iOutputBus] = pConfig->channels; - } - - baseConfig = pConfig->nodeConfig; - baseConfig.vtable = &g_ma_splitter_node_vtable; - baseConfig.pInputChannels = pInputChannels; - baseConfig.pOutputChannels = pOutputChannels; - baseConfig.outputBusCount = pConfig->outputBusCount; - - result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pSplitterNode->base); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the base node. */ - } - - return MA_SUCCESS; -} - -MA_API void ma_splitter_node_uninit(ma_splitter_node* pSplitterNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_node_uninit(pSplitterNode, pAllocationCallbacks); -} - - -/* -Biquad Node -*/ -MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2) -{ - ma_biquad_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.biquad = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2); - - return config; -} - -static void ma_biquad_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_biquad_process_pcm_frames(&pLPFNode->biquad, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_biquad_node_vtable = -{ - ma_biquad_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->biquad.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_biquad_init(&pConfig->biquad, pAllocationCallbacks, &pNode->biquad); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_biquad_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->biquad.channels; - baseNodeConfig.pOutputChannels = &pConfig->biquad.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode) -{ - ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; - - MA_ASSERT(pNode != NULL); - - return ma_biquad_reinit(pConfig, &pLPFNode->biquad); -} - -MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_biquad_uninit(&pLPFNode->biquad, pAllocationCallbacks); -} - - - -/* -Low Pass Filter Node -*/ -MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) -{ - ma_lpf_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.lpf = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); - - return config; -} - -static void ma_lpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_lpf_process_pcm_frames(&pLPFNode->lpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_lpf_node_vtable = -{ - ma_lpf_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->lpf.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_lpf_init(&pConfig->lpf, pAllocationCallbacks, &pNode->lpf); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_lpf_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->lpf.channels; - baseNodeConfig.pOutputChannels = &pConfig->lpf.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode) -{ - ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_lpf_reinit(pConfig, &pLPFNode->lpf); -} - -MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_lpf_uninit(&pLPFNode->lpf, pAllocationCallbacks); -} - - - -/* -High Pass Filter Node -*/ -MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) -{ - ma_hpf_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.hpf = ma_hpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); - - return config; -} - -static void ma_hpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_hpf_process_pcm_frames(&pHPFNode->hpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_hpf_node_vtable = -{ - ma_hpf_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->hpf.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_hpf_init(&pConfig->hpf, pAllocationCallbacks, &pNode->hpf); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_hpf_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->hpf.channels; - baseNodeConfig.pOutputChannels = &pConfig->hpf.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode) -{ - ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_hpf_reinit(pConfig, &pHPFNode->hpf); -} - -MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_hpf_uninit(&pHPFNode->hpf, pAllocationCallbacks); -} - - - - -/* -Band Pass Filter Node -*/ -MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) -{ - ma_bpf_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.bpf = ma_bpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); - - return config; -} - -static void ma_bpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_bpf_process_pcm_frames(&pBPFNode->bpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_bpf_node_vtable = -{ - ma_bpf_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->bpf.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_bpf_init(&pConfig->bpf, pAllocationCallbacks, &pNode->bpf); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_bpf_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->bpf.channels; - baseNodeConfig.pOutputChannels = &pConfig->bpf.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode) -{ - ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_bpf_reinit(pConfig, &pBPFNode->bpf); -} - -MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_bpf_uninit(&pBPFNode->bpf, pAllocationCallbacks); -} - - - -/* -Notching Filter Node -*/ -MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency) -{ - ma_notch_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.notch = ma_notch2_config_init(ma_format_f32, channels, sampleRate, q, frequency); - - return config; -} - -static void ma_notch_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_notch_node* pBPFNode = (ma_notch_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_notch2_process_pcm_frames(&pBPFNode->notch, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_notch_node_vtable = -{ - ma_notch_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->notch.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_notch2_init(&pConfig->notch, pAllocationCallbacks, &pNode->notch); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_notch_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->notch.channels; - baseNodeConfig.pOutputChannels = &pConfig->notch.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode) -{ - ma_notch_node* pNotchNode = (ma_notch_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_notch2_reinit(pConfig, &pNotchNode->notch); -} - -MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_notch_node* pNotchNode = (ma_notch_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_notch2_uninit(&pNotchNode->notch, pAllocationCallbacks); -} - - - -/* -Peaking Filter Node -*/ -MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) -{ - ma_peak_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.peak = ma_peak2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); - - return config; -} - -static void ma_peak_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_peak_node* pBPFNode = (ma_peak_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_peak2_process_pcm_frames(&pBPFNode->peak, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_peak_node_vtable = -{ - ma_peak_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->peak.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_peak2_init(&pConfig->peak, pAllocationCallbacks, &pNode->peak); - if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_peak_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->peak.channels; - baseNodeConfig.pOutputChannels = &pConfig->peak.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode) -{ - ma_peak_node* pPeakNode = (ma_peak_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_peak2_reinit(pConfig, &pPeakNode->peak); -} - -MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_peak_node* pPeakNode = (ma_peak_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_peak2_uninit(&pPeakNode->peak, pAllocationCallbacks); -} - - - -/* -Low Shelf Filter Node -*/ -MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) -{ - ma_loshelf_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.loshelf = ma_loshelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); - - return config; -} - -static void ma_loshelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_loshelf_node* pBPFNode = (ma_loshelf_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_loshelf2_process_pcm_frames(&pBPFNode->loshelf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_loshelf_node_vtable = -{ - ma_loshelf_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->loshelf.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_loshelf2_init(&pConfig->loshelf, pAllocationCallbacks, &pNode->loshelf); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_loshelf_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->loshelf.channels; - baseNodeConfig.pOutputChannels = &pConfig->loshelf.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode) -{ - ma_loshelf_node* pLoshelfNode = (ma_loshelf_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_loshelf2_reinit(pConfig, &pLoshelfNode->loshelf); -} - -MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_loshelf_node* pLoshelfNode = (ma_loshelf_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_loshelf2_uninit(&pLoshelfNode->loshelf, pAllocationCallbacks); -} - - - -/* -High Shelf Filter Node -*/ -MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) -{ - ma_hishelf_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.hishelf = ma_hishelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); - - return config; -} - -static void ma_hishelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_hishelf_node* pBPFNode = (ma_hishelf_node*)pNode; - - MA_ASSERT(pNode != NULL); - (void)pFrameCountIn; - - ma_hishelf2_process_pcm_frames(&pBPFNode->hishelf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_hishelf_node_vtable = -{ - ma_hishelf_node_process_pcm_frames, - NULL, /* onGetRequiredInputFrameCount */ - 1, /* One input. */ - 1, /* One output. */ - 0 /* Default flags. */ -}; - -MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode) -{ - ma_result result; - ma_node_config baseNodeConfig; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pNode); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->hishelf.format != ma_format_f32) { - return MA_INVALID_ARGS; /* The format must be f32. */ - } - - result = ma_hishelf2_init(&pConfig->hishelf, pAllocationCallbacks, &pNode->hishelf); - if (result != MA_SUCCESS) { - return result; - } - - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_hishelf_node_vtable; - baseNodeConfig.pInputChannels = &pConfig->hishelf.channels; - baseNodeConfig.pOutputChannels = &pConfig->hishelf.channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); - if (result != MA_SUCCESS) { - return result; - } - - return result; -} - -MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode) -{ - ma_hishelf_node* pHishelfNode = (ma_hishelf_node*)pNode; - - if (pNode == NULL) { - return MA_INVALID_ARGS; - } - - return ma_hishelf2_reinit(pConfig, &pHishelfNode->hishelf); -} - -MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_hishelf_node* pHishelfNode = (ma_hishelf_node*)pNode; - - if (pNode == NULL) { - return; - } - - ma_node_uninit(pNode, pAllocationCallbacks); - ma_hishelf2_uninit(&pHishelfNode->hishelf, pAllocationCallbacks); -} - - - - -MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay) -{ - ma_delay_node_config config; - - config.nodeConfig = ma_node_config_init(); - config.delay = ma_delay_config_init(channels, sampleRate, delayInFrames, decay); - - return config; -} - - -static void ma_delay_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_delay_node* pDelayNode = (ma_delay_node*)pNode; - - (void)pFrameCountIn; - - ma_delay_process_pcm_frames(&pDelayNode->delay, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); -} - -static ma_node_vtable g_ma_delay_node_vtable = -{ - ma_delay_node_process_pcm_frames, - NULL, - 1, /* 1 input channels. */ - 1, /* 1 output channel. */ - MA_NODE_FLAG_CONTINUOUS_PROCESSING /* Delay requires continuous processing to ensure the tail get's processed. */ -}; - -MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode) -{ - ma_result result; - ma_node_config baseConfig; - - if (pDelayNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pDelayNode); - - result = ma_delay_init(&pConfig->delay, pAllocationCallbacks, &pDelayNode->delay); - if (result != MA_SUCCESS) { - return result; - } - - baseConfig = pConfig->nodeConfig; - baseConfig.vtable = &g_ma_delay_node_vtable; - baseConfig.pInputChannels = &pConfig->delay.channels; - baseConfig.pOutputChannels = &pConfig->delay.channels; - - result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDelayNode->baseNode); - if (result != MA_SUCCESS) { - ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks); - return result; - } - - return result; -} - -MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pDelayNode == NULL) { - return; - } - - /* The base node is always uninitialized first. */ - ma_node_uninit(pDelayNode, pAllocationCallbacks); - ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks); -} - -MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value) -{ - if (pDelayNode == NULL) { - return; - } - - ma_delay_set_wet(&pDelayNode->delay, value); -} - -MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode) -{ - if (pDelayNode == NULL) { - return 0; - } - - return ma_delay_get_wet(&pDelayNode->delay); -} - -MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value) -{ - if (pDelayNode == NULL) { - return; - } - - ma_delay_set_dry(&pDelayNode->delay, value); -} - -MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode) -{ - if (pDelayNode == NULL) { - return 0; - } - - return ma_delay_get_dry(&pDelayNode->delay); -} - -MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value) -{ - if (pDelayNode == NULL) { - return; - } - - ma_delay_set_decay(&pDelayNode->delay, value); -} - -MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode) -{ - if (pDelayNode == NULL) { - return 0; - } - - return ma_delay_get_decay(&pDelayNode->delay); -} -#endif /* MA_NO_NODE_GRAPH */ - - -/* SECTION: miniaudio_engine.c */ -#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) -/************************************************************************************************************************************************************** - -Engine - -**************************************************************************************************************************************************************/ -#define MA_SEEK_TARGET_NONE (~(ma_uint64)0) - - -static void ma_sound_set_at_end(ma_sound* pSound, ma_bool32 atEnd) -{ - MA_ASSERT(pSound != NULL); - ma_atomic_exchange_32(&pSound->atEnd, atEnd); - - /* Fire any callbacks or events. */ - if (atEnd) { - if (pSound->endCallback != NULL) { - pSound->endCallback(pSound->pEndCallbackUserData, pSound); - } - } -} - -static ma_bool32 ma_sound_get_at_end(const ma_sound* pSound) -{ - MA_ASSERT(pSound != NULL); - return ma_atomic_load_32(&pSound->atEnd); -} - - -MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags) -{ - ma_engine_node_config config; - - MA_ZERO_OBJECT(&config); - config.pEngine = pEngine; - config.type = type; - config.isPitchDisabled = (flags & MA_SOUND_FLAG_NO_PITCH) != 0; - config.isSpatializationDisabled = (flags & MA_SOUND_FLAG_NO_SPATIALIZATION) != 0; - config.monoExpansionMode = pEngine->monoExpansionMode; - - return config; -} - - -static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode) -{ - ma_bool32 isUpdateRequired = MA_FALSE; - float newPitch; - - MA_ASSERT(pEngineNode != NULL); - - newPitch = ma_atomic_load_explicit_f32(&pEngineNode->pitch, ma_atomic_memory_order_acquire); - - if (pEngineNode->oldPitch != newPitch) { - pEngineNode->oldPitch = newPitch; - isUpdateRequired = MA_TRUE; - } - - if (pEngineNode->oldDopplerPitch != pEngineNode->spatializer.dopplerPitch) { - pEngineNode->oldDopplerPitch = pEngineNode->spatializer.dopplerPitch; - isUpdateRequired = MA_TRUE; - } - - if (isUpdateRequired) { - float basePitch = (float)pEngineNode->sampleRate / ma_engine_get_sample_rate(pEngineNode->pEngine); - ma_linear_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch); - } -} - -static ma_bool32 ma_engine_node_is_pitching_enabled(const ma_engine_node* pEngineNode) -{ - MA_ASSERT(pEngineNode != NULL); - - /* Don't try to be clever by skipping resampling in the pitch=1 case or else you'll glitch when moving away from 1. */ - return !ma_atomic_load_explicit_32(&pEngineNode->isPitchDisabled, ma_atomic_memory_order_acquire); -} - -static ma_bool32 ma_engine_node_is_spatialization_enabled(const ma_engine_node* pEngineNode) -{ - MA_ASSERT(pEngineNode != NULL); - - return !ma_atomic_load_explicit_32(&pEngineNode->isSpatializationDisabled, ma_atomic_memory_order_acquire); -} - -static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_node* pEngineNode, ma_uint64 outputFrameCount) -{ - ma_uint64 inputFrameCount = 0; - - if (ma_engine_node_is_pitching_enabled(pEngineNode)) { - ma_result result = ma_linear_resampler_get_required_input_frame_count(&pEngineNode->resampler, outputFrameCount, &inputFrameCount); - if (result != MA_SUCCESS) { - inputFrameCount = 0; - } - } else { - inputFrameCount = outputFrameCount; /* No resampling, so 1:1. */ - } - - return inputFrameCount; -} - -static ma_result ma_engine_node_set_volume(ma_engine_node* pEngineNode, float volume) -{ - if (pEngineNode == NULL) { - return MA_INVALID_ARGS; - } - - ma_atomic_float_set(&pEngineNode->volume, volume); - - /* If we're not smoothing we should bypass the volume gainer entirely. */ - if (pEngineNode->volumeSmoothTimeInPCMFrames == 0) { - /* We should always have an active spatializer because it can be enabled and disabled dynamically. We can just use that for holding our volume. */ - ma_spatializer_set_master_volume(&pEngineNode->spatializer, volume); - } else { - /* We're using volume smoothing, so apply the master volume to the gainer. */ - ma_gainer_set_gain(&pEngineNode->volumeGainer, volume); - } - - return MA_SUCCESS; -} - -static ma_result ma_engine_node_get_volume(const ma_engine_node* pEngineNode, float* pVolume) -{ - if (pVolume == NULL) { - return MA_INVALID_ARGS; - } - - *pVolume = 0.0f; - - if (pEngineNode == NULL) { - return MA_INVALID_ARGS; - } - - *pVolume = ma_atomic_float_get((ma_atomic_float*)&pEngineNode->volume); - - return MA_SUCCESS; -} - - -static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - ma_uint32 frameCountIn; - ma_uint32 frameCountOut; - ma_uint32 totalFramesProcessedIn; - ma_uint32 totalFramesProcessedOut; - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_bool32 isPitchingEnabled; - ma_bool32 isFadingEnabled; - ma_bool32 isSpatializationEnabled; - ma_bool32 isPanningEnabled; - ma_bool32 isVolumeSmoothingEnabled; - - frameCountIn = *pFrameCountIn; - frameCountOut = *pFrameCountOut; - - channelsIn = ma_spatializer_get_input_channels(&pEngineNode->spatializer); - channelsOut = ma_spatializer_get_output_channels(&pEngineNode->spatializer); - - totalFramesProcessedIn = 0; - totalFramesProcessedOut = 0; - - /* Update the fader if applicable. */ - { - ma_uint64 fadeLengthInFrames = ma_atomic_uint64_get(&pEngineNode->fadeSettings.fadeLengthInFrames); - if (fadeLengthInFrames != ~(ma_uint64)0) { - float fadeVolumeBeg = ma_atomic_float_get(&pEngineNode->fadeSettings.volumeBeg); - float fadeVolumeEnd = ma_atomic_float_get(&pEngineNode->fadeSettings.volumeEnd); - ma_int64 fadeStartOffsetInFrames = (ma_int64)ma_atomic_uint64_get(&pEngineNode->fadeSettings.absoluteGlobalTimeInFrames); - if (fadeStartOffsetInFrames == (ma_int64)(~(ma_uint64)0)) { - fadeStartOffsetInFrames = 0; - } else { - fadeStartOffsetInFrames -= ma_engine_get_time_in_pcm_frames(pEngineNode->pEngine); - } - - ma_fader_set_fade_ex(&pEngineNode->fader, fadeVolumeBeg, fadeVolumeEnd, fadeLengthInFrames, fadeStartOffsetInFrames); - - /* Reset the fade length so we don't erroneously apply it again. */ - ma_atomic_uint64_set(&pEngineNode->fadeSettings.fadeLengthInFrames, ~(ma_uint64)0); - } - } - - isPitchingEnabled = ma_engine_node_is_pitching_enabled(pEngineNode); - isFadingEnabled = pEngineNode->fader.volumeBeg != 1 || pEngineNode->fader.volumeEnd != 1; - isSpatializationEnabled = ma_engine_node_is_spatialization_enabled(pEngineNode); - isPanningEnabled = pEngineNode->panner.pan != 0 && channelsOut != 1; - isVolumeSmoothingEnabled = pEngineNode->volumeSmoothTimeInPCMFrames > 0; - - /* Keep going while we've still got data available for processing. */ - while (totalFramesProcessedOut < frameCountOut) { - /* - We need to process in a specific order. We always do resampling first because it's likely - we're going to be increasing the channel count after spatialization. Also, I want to do - fading based on the output sample rate. - - We'll first read into a buffer from the resampler. Then we'll do all processing that - operates on the on the input channel count. We'll then get the spatializer to output to - the output buffer and then do all effects from that point directly in the output buffer - in-place. - - Note that we're always running the resampler if pitching is enabled, even when the pitch - is 1. If we try to be clever and skip resampling when the pitch is 1, we'll get a glitch - when we move away from 1, back to 1, and then away from 1 again. We'll want to implement - any pitch=1 optimizations in the resampler itself. - - There's a small optimization here that we'll utilize since it might be a fairly common - case. When the input and output channel counts are the same, we'll read straight into the - output buffer from the resampler and do everything in-place. - */ - const float* pRunningFramesIn; - float* pRunningFramesOut; - float* pWorkingBuffer; /* This is the buffer that we'll be processing frames in. This is in input channels. */ - float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)]; - ma_uint32 tempCapInFrames = ma_countof(temp) / channelsIn; - ma_uint32 framesAvailableIn; - ma_uint32 framesAvailableOut; - ma_uint32 framesJustProcessedIn; - ma_uint32 framesJustProcessedOut; - ma_bool32 isWorkingBufferValid = MA_FALSE; - - framesAvailableIn = frameCountIn - totalFramesProcessedIn; - framesAvailableOut = frameCountOut - totalFramesProcessedOut; - - pRunningFramesIn = ma_offset_pcm_frames_const_ptr_f32(ppFramesIn[0], totalFramesProcessedIn, channelsIn); - pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesProcessedOut, channelsOut); - - if (channelsIn == channelsOut) { - /* Fast path. Channel counts are the same. No need for an intermediary input buffer. */ - pWorkingBuffer = pRunningFramesOut; - } else { - /* Slow path. Channel counts are different. Need to use an intermediary input buffer. */ - pWorkingBuffer = temp; - if (framesAvailableOut > tempCapInFrames) { - framesAvailableOut = tempCapInFrames; - } - } - - /* First is resampler. */ - if (isPitchingEnabled) { - ma_uint64 resampleFrameCountIn = framesAvailableIn; - ma_uint64 resampleFrameCountOut = framesAvailableOut; - - ma_linear_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut); - isWorkingBufferValid = MA_TRUE; - - framesJustProcessedIn = (ma_uint32)resampleFrameCountIn; - framesJustProcessedOut = (ma_uint32)resampleFrameCountOut; - } else { - framesJustProcessedIn = ma_min(framesAvailableIn, framesAvailableOut); - framesJustProcessedOut = framesJustProcessedIn; /* When no resampling is being performed, the number of output frames is the same as input frames. */ - } - - /* Fading. */ - if (isFadingEnabled) { - if (isWorkingBufferValid) { - ma_fader_process_pcm_frames(&pEngineNode->fader, pWorkingBuffer, pWorkingBuffer, framesJustProcessedOut); /* In-place processing. */ - } else { - ma_fader_process_pcm_frames(&pEngineNode->fader, pWorkingBuffer, pRunningFramesIn, framesJustProcessedOut); - isWorkingBufferValid = MA_TRUE; - } - } - - /* - If we're using smoothing, we won't be applying volume via the spatializer, but instead from a ma_gainer. In this case - we'll want to apply our volume now. - */ - if (isVolumeSmoothingEnabled) { - if (isWorkingBufferValid) { - ma_gainer_process_pcm_frames(&pEngineNode->volumeGainer, pWorkingBuffer, pWorkingBuffer, framesJustProcessedOut); - } else { - ma_gainer_process_pcm_frames(&pEngineNode->volumeGainer, pWorkingBuffer, pRunningFramesIn, framesJustProcessedOut); - isWorkingBufferValid = MA_TRUE; - } - } - - /* - If at this point we still haven't actually done anything with the working buffer we need - to just read straight from the input buffer. - */ - if (isWorkingBufferValid == MA_FALSE) { - pWorkingBuffer = (float*)pRunningFramesIn; /* Naughty const cast, but it's safe at this point because we won't ever be writing to it from this point out. */ - } - - /* Spatialization. */ - if (isSpatializationEnabled) { - ma_uint32 iListener; - - /* - When determining the listener to use, we first check to see if the sound is pinned to a - specific listener. If so, we use that. Otherwise we just use the closest listener. - */ - if (pEngineNode->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pEngineNode->pinnedListenerIndex < ma_engine_get_listener_count(pEngineNode->pEngine)) { - iListener = pEngineNode->pinnedListenerIndex; - } else { - ma_vec3f spatializerPosition = ma_spatializer_get_position(&pEngineNode->spatializer); - iListener = ma_engine_find_closest_listener(pEngineNode->pEngine, spatializerPosition.x, spatializerPosition.y, spatializerPosition.z); - } - - ma_spatializer_process_pcm_frames(&pEngineNode->spatializer, &pEngineNode->pEngine->listeners[iListener], pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut); - } else { - /* No spatialization, but we still need to do channel conversion and master volume. */ - float volume; - ma_engine_node_get_volume(pEngineNode, &volume); /* Should never fail. */ - - if (channelsIn == channelsOut) { - /* No channel conversion required. Just copy straight to the output buffer. */ - if (isVolumeSmoothingEnabled) { - /* Volume has already been applied. Just copy straight to the output buffer. */ - ma_copy_pcm_frames(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut * channelsOut, ma_format_f32, channelsOut); - } else { - /* Volume has not been applied yet. Copy and apply volume in the same pass. */ - ma_copy_and_apply_volume_factor_f32(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut * channelsOut, volume); - } - } else { - /* Channel conversion required. TODO: Add support for channel maps here. */ - ma_channel_map_apply_f32(pRunningFramesOut, NULL, channelsOut, pWorkingBuffer, NULL, channelsIn, framesJustProcessedOut, ma_channel_mix_mode_simple, pEngineNode->monoExpansionMode); - - /* If we're using smoothing, the volume will have already been applied. */ - if (!isVolumeSmoothingEnabled) { - ma_apply_volume_factor_f32(pRunningFramesOut, framesJustProcessedOut * channelsOut, volume); - } - } - } - - /* At this point we can guarantee that the output buffer contains valid data. We can process everything in place now. */ - - /* Panning. */ - if (isPanningEnabled) { - ma_panner_process_pcm_frames(&pEngineNode->panner, pRunningFramesOut, pRunningFramesOut, framesJustProcessedOut); /* In-place processing. */ - } - - /* We're done for this chunk. */ - totalFramesProcessedIn += framesJustProcessedIn; - totalFramesProcessedOut += framesJustProcessedOut; - - /* If we didn't process any output frames this iteration it means we've either run out of input data, or run out of room in the output buffer. */ - if (framesJustProcessedOut == 0) { - break; - } - } - - /* At this point we're done processing. */ - *pFrameCountIn = totalFramesProcessedIn; - *pFrameCountOut = totalFramesProcessedOut; -} - -static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - /* For sounds, we need to first read from the data source. Then we need to apply the engine effects (pan, pitch, fades, etc.). */ - ma_result result = MA_SUCCESS; - ma_sound* pSound = (ma_sound*)pNode; - ma_uint32 frameCount = *pFrameCountOut; - ma_uint32 totalFramesRead = 0; - ma_format dataSourceFormat; - ma_uint32 dataSourceChannels; - ma_uint8 temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint32 tempCapInFrames; - ma_uint64 seekTarget; - - /* This is a data source node which means no input buses. */ - (void)ppFramesIn; - (void)pFrameCountIn; - - /* If we're marked at the end we need to stop the sound and do nothing. */ - if (ma_sound_at_end(pSound)) { - ma_sound_stop(pSound); - *pFrameCountOut = 0; - return; - } - - /* If we're seeking, do so now before reading. */ - seekTarget = ma_atomic_load_64(&pSound->seekTarget); - if (seekTarget != MA_SEEK_TARGET_NONE) { - ma_data_source_seek_to_pcm_frame(pSound->pDataSource, seekTarget); - - /* Any time-dependant effects need to have their times updated. */ - ma_node_set_time(pSound, seekTarget); - - ma_atomic_exchange_64(&pSound->seekTarget, MA_SEEK_TARGET_NONE); - } - - /* - We want to update the pitch once. For sounds, this can be either at the start or at the end. If - we don't force this to only ever be updating once, we could end up in a situation where - retrieving the required input frame count ends up being different to what we actually retrieve. - What could happen is that the required input frame count is calculated, the pitch is update, - and then this processing function is called resulting in a different number of input frames - being processed. Do not call this in ma_engine_node_process_pcm_frames__general() or else - you'll hit the aforementioned bug. - */ - ma_engine_node_update_pitch_if_required(&pSound->engineNode); - - /* - For the convenience of the caller, we're doing to allow data sources to use non-floating-point formats and channel counts that differ - from the main engine. - */ - result = ma_data_source_get_data_format(pSound->pDataSource, &dataSourceFormat, &dataSourceChannels, NULL, NULL, 0); - if (result == MA_SUCCESS) { - tempCapInFrames = sizeof(temp) / ma_get_bytes_per_frame(dataSourceFormat, dataSourceChannels); - - /* Keep reading until we've read as much as was requested or we reach the end of the data source. */ - while (totalFramesRead < frameCount) { - ma_uint32 framesRemaining = frameCount - totalFramesRead; - ma_uint32 framesToRead; - ma_uint64 framesJustRead; - ma_uint32 frameCountIn; - ma_uint32 frameCountOut; - const float* pRunningFramesIn; - float* pRunningFramesOut; - - /* - The first thing we need to do is read into the temporary buffer. We can calculate exactly - how many input frames we'll need after resampling. - */ - framesToRead = (ma_uint32)ma_engine_node_get_required_input_frame_count(&pSound->engineNode, framesRemaining); - if (framesToRead > tempCapInFrames) { - framesToRead = tempCapInFrames; - } - - result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToRead, &framesJustRead); - - /* If we reached the end of the sound we'll want to mark it as at the end and stop it. This should never be returned for looping sounds. */ - if (result == MA_AT_END) { - ma_sound_set_at_end(pSound, MA_TRUE); /* This will be set to false in ma_sound_start(). */ - } - - pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_node_get_output_channels(pNode, 0)); - - frameCountIn = (ma_uint32)framesJustRead; - frameCountOut = framesRemaining; - - /* Convert if necessary. */ - if (dataSourceFormat == ma_format_f32) { - /* Fast path. No data conversion necessary. */ - pRunningFramesIn = (float*)temp; - ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut); - } else { - /* Slow path. Need to do sample format conversion to f32. If we give the f32 buffer the same count as the first temp buffer, we're guaranteed it'll be large enough. */ - float tempf32[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* Do not do `MA_DATA_CONVERTER_STACK_BUFFER_SIZE/sizeof(float)` here like we've done in other places. */ - ma_convert_pcm_frames_format(tempf32, ma_format_f32, temp, dataSourceFormat, framesJustRead, dataSourceChannels, ma_dither_mode_none); - - /* Now that we have our samples in f32 format we can process like normal. */ - pRunningFramesIn = tempf32; - ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut); - } - - /* We should have processed all of our input frames since we calculated the required number of input frames at the top. */ - MA_ASSERT(frameCountIn == framesJustRead); - totalFramesRead += (ma_uint32)frameCountOut; /* Safe cast. */ - - if (result != MA_SUCCESS || ma_sound_at_end(pSound)) { - break; /* Might have reached the end. */ - } - } - } - - *pFrameCountOut = totalFramesRead; -} - -static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) -{ - /* - Make sure the pitch is updated before trying to read anything. It's important that this is done - only once and not in ma_engine_node_process_pcm_frames__general(). The reason for this is that - ma_engine_node_process_pcm_frames__general() will call ma_engine_node_get_required_input_frame_count(), - and if another thread modifies the pitch just after that call it can result in a glitch due to - the input rate changing. - */ - ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); - - /* For groups, the input data has already been read and we just need to apply the effect. */ - ma_engine_node_process_pcm_frames__general((ma_engine_node*)pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut); -} - -static ma_result ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount) -{ - ma_uint64 inputFrameCount; - - MA_ASSERT(pInputFrameCount != NULL); - - /* Our pitch will affect this calculation. We need to update it. */ - ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); - - inputFrameCount = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount); - if (inputFrameCount > 0xFFFFFFFF) { - inputFrameCount = 0xFFFFFFFF; /* Will never happen because miniaudio will only ever process in relatively small chunks. */ - } - - *pInputFrameCount = (ma_uint32)inputFrameCount; - - return MA_SUCCESS; -} - - -static ma_node_vtable g_ma_engine_node_vtable__sound = -{ - ma_engine_node_process_pcm_frames__sound, - NULL, /* onGetRequiredInputFrameCount */ - 0, /* Sounds are data source nodes which means they have zero inputs (their input is drawn from the data source itself). */ - 1, /* Sounds have one output bus. */ - 0 /* Default flags. */ -}; - -static ma_node_vtable g_ma_engine_node_vtable__group = -{ - ma_engine_node_process_pcm_frames__group, - ma_engine_node_get_required_input_frame_count__group, - 1, /* Groups have one input bus. */ - 1, /* Groups have one output bus. */ - MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */ -}; - - - -static ma_node_config ma_engine_node_base_node_config_init(const ma_engine_node_config* pConfig) -{ - ma_node_config baseNodeConfig; - - if (pConfig->type == ma_engine_node_type_sound) { - /* Sound. */ - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_engine_node_vtable__sound; - baseNodeConfig.initialState = ma_node_state_stopped; /* Sounds are stopped by default. */ - } else { - /* Group. */ - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_engine_node_vtable__group; - baseNodeConfig.initialState = ma_node_state_started; /* Groups are started by default. */ - } - - return baseNodeConfig; -} - -static ma_spatializer_config ma_engine_node_spatializer_config_init(const ma_node_config* pBaseNodeConfig) -{ - return ma_spatializer_config_init(pBaseNodeConfig->pInputChannels[0], pBaseNodeConfig->pOutputChannels[0]); -} - -typedef struct -{ - size_t sizeInBytes; - size_t baseNodeOffset; - size_t resamplerOffset; - size_t spatializerOffset; - size_t gainerOffset; -} ma_engine_node_heap_layout; - -static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pConfig, ma_engine_node_heap_layout* pHeapLayout) -{ - ma_result result; - size_t tempHeapSize; - ma_node_config baseNodeConfig; - ma_linear_resampler_config resamplerConfig; - ma_spatializer_config spatializerConfig; - ma_gainer_config gainerConfig; - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_channel defaultStereoChannelMap[2] = {MA_CHANNEL_SIDE_LEFT, MA_CHANNEL_SIDE_RIGHT}; /* <-- Consistent with the default channel map of a stereo listener. Means channel conversion can run on a fast path. */ - - MA_ASSERT(pHeapLayout); - - MA_ZERO_OBJECT(pHeapLayout); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->pEngine == NULL) { - return MA_INVALID_ARGS; /* An engine must be specified. */ - } - - pHeapLayout->sizeInBytes = 0; - - channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); - channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); - - - /* Base node. */ - baseNodeConfig = ma_engine_node_base_node_config_init(pConfig); - baseNodeConfig.pInputChannels = &channelsIn; - baseNodeConfig.pOutputChannels = &channelsOut; - - result = ma_node_get_heap_size(ma_engine_get_node_graph(pConfig->pEngine), &baseNodeConfig, &tempHeapSize); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the size of the heap for the base node. */ - } - - pHeapLayout->baseNodeOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); - - - /* Resmapler. */ - resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, channelsIn, 1, 1); /* Input and output sample rates don't affect the calculation of the heap size. */ - resamplerConfig.lpfOrder = 0; - - result = ma_linear_resampler_get_heap_size(&resamplerConfig, &tempHeapSize); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the size of the heap for the resampler. */ - } - - pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); - - - /* Spatializer. */ - spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); - - if (spatializerConfig.channelsIn == 2) { - spatializerConfig.pChannelMapIn = defaultStereoChannelMap; - } - - result = ma_spatializer_get_heap_size(&spatializerConfig, &tempHeapSize); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the size of the heap for the spatializer. */ - } - - pHeapLayout->spatializerOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); - - - /* Gainer. Will not be used if we are not using smoothing. */ - if (pConfig->volumeSmoothTimeInPCMFrames > 0) { - gainerConfig = ma_gainer_config_init(channelsIn, pConfig->volumeSmoothTimeInPCMFrames); - - result = ma_gainer_get_heap_size(&gainerConfig, &tempHeapSize); - if (result != MA_SUCCESS) { - return result; - } - - pHeapLayout->gainerOffset = pHeapLayout->sizeInBytes; - pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); - } - - - return MA_SUCCESS; -} - -MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes) -{ - ma_result result; - ma_engine_node_heap_layout heapLayout; - - if (pHeapSizeInBytes == NULL) { - return MA_INVALID_ARGS; - } - - *pHeapSizeInBytes = 0; - - result = ma_engine_node_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - *pHeapSizeInBytes = heapLayout.sizeInBytes; - - return MA_SUCCESS; -} - -MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode) -{ - ma_result result; - ma_engine_node_heap_layout heapLayout; - ma_node_config baseNodeConfig; - ma_linear_resampler_config resamplerConfig; - ma_fader_config faderConfig; - ma_spatializer_config spatializerConfig; - ma_panner_config pannerConfig; - ma_gainer_config gainerConfig; - ma_uint32 channelsIn; - ma_uint32 channelsOut; - ma_channel defaultStereoChannelMap[2] = {MA_CHANNEL_SIDE_LEFT, MA_CHANNEL_SIDE_RIGHT}; /* <-- Consistent with the default channel map of a stereo listener. Means channel conversion can run on a fast path. */ - - if (pEngineNode == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pEngineNode); - - result = ma_engine_node_get_heap_layout(pConfig, &heapLayout); - if (result != MA_SUCCESS) { - return result; - } - - if (pConfig->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) { - return MA_INVALID_ARGS; /* Invalid listener. */ - } - - pEngineNode->_pHeap = pHeap; - MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - - pEngineNode->pEngine = pConfig->pEngine; - pEngineNode->sampleRate = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine); - pEngineNode->volumeSmoothTimeInPCMFrames = pConfig->volumeSmoothTimeInPCMFrames; - pEngineNode->monoExpansionMode = pConfig->monoExpansionMode; - ma_atomic_float_set(&pEngineNode->volume, 1); - pEngineNode->pitch = 1; - pEngineNode->oldPitch = 1; - pEngineNode->oldDopplerPitch = 1; - pEngineNode->isPitchDisabled = pConfig->isPitchDisabled; - pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled; - pEngineNode->pinnedListenerIndex = pConfig->pinnedListenerIndex; - ma_atomic_float_set(&pEngineNode->fadeSettings.volumeBeg, 1); - ma_atomic_float_set(&pEngineNode->fadeSettings.volumeEnd, 1); - ma_atomic_uint64_set(&pEngineNode->fadeSettings.fadeLengthInFrames, (~(ma_uint64)0)); - ma_atomic_uint64_set(&pEngineNode->fadeSettings.absoluteGlobalTimeInFrames, (~(ma_uint64)0)); /* <-- Indicates that the fade should start immediately. */ - - channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); - channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); - - /* - If the sample rate of the sound is different to the engine, make sure pitching is enabled so that the resampler - is activated. Not doing this will result in the sound not being resampled if MA_SOUND_FLAG_NO_PITCH is used. - */ - if (pEngineNode->sampleRate != ma_engine_get_sample_rate(pEngineNode->pEngine)) { - pEngineNode->isPitchDisabled = MA_FALSE; - } - - - /* Base node. */ - baseNodeConfig = ma_engine_node_base_node_config_init(pConfig); - baseNodeConfig.pInputChannels = &channelsIn; - baseNodeConfig.pOutputChannels = &channelsOut; - - result = ma_node_init_preallocated(&pConfig->pEngine->nodeGraph, &baseNodeConfig, ma_offset_ptr(pHeap, heapLayout.baseNodeOffset), &pEngineNode->baseNode); - if (result != MA_SUCCESS) { - goto error0; - } - - - /* - We can now initialize the effects we need in order to implement the engine node. There's a - defined order of operations here, mainly centered around when we convert our channels from the - data source's native channel count to the engine's channel count. As a rule, we want to do as - much computation as possible before spatialization because there's a chance that will increase - the channel count, thereby increasing the amount of work needing to be done to process. - */ - - /* We'll always do resampling first. */ - resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine)); - resamplerConfig.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ - - result = ma_linear_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pEngineNode->resampler); - if (result != MA_SUCCESS) { - goto error1; - } - - - /* After resampling will come the fader. */ - faderConfig = ma_fader_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], ma_engine_get_sample_rate(pEngineNode->pEngine)); - - result = ma_fader_init(&faderConfig, &pEngineNode->fader); - if (result != MA_SUCCESS) { - goto error2; - } - - - /* - Spatialization comes next. We spatialize based on the node's output channel count. It's up the caller to - ensure channels counts link up correctly in the node graph. - */ - spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); - spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames; - - if (spatializerConfig.channelsIn == 2) { - spatializerConfig.pChannelMapIn = defaultStereoChannelMap; - } - - result = ma_spatializer_init_preallocated(&spatializerConfig, ma_offset_ptr(pHeap, heapLayout.spatializerOffset), &pEngineNode->spatializer); - if (result != MA_SUCCESS) { - goto error2; - } - - - /* - After spatialization comes panning. We need to do this after spatialization because otherwise we wouldn't - be able to pan mono sounds. - */ - pannerConfig = ma_panner_config_init(ma_format_f32, baseNodeConfig.pOutputChannels[0]); - - result = ma_panner_init(&pannerConfig, &pEngineNode->panner); - if (result != MA_SUCCESS) { - goto error3; - } - - - /* We'll need a gainer for smoothing out volume changes if we have a non-zero smooth time. We apply this before converting to the output channel count. */ - if (pConfig->volumeSmoothTimeInPCMFrames > 0) { - gainerConfig = ma_gainer_config_init(channelsIn, pConfig->volumeSmoothTimeInPCMFrames); - - result = ma_gainer_init_preallocated(&gainerConfig, ma_offset_ptr(pHeap, heapLayout.gainerOffset), &pEngineNode->volumeGainer); - if (result != MA_SUCCESS) { - goto error3; - } - } - - - return MA_SUCCESS; - - /* No need for allocation callbacks here because we use a preallocated heap. */ -error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); -error2: ma_linear_resampler_uninit(&pEngineNode->resampler, NULL); -error1: ma_node_uninit(&pEngineNode->baseNode, NULL); -error0: return result; -} - -MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode) -{ - ma_result result; - size_t heapSizeInBytes; - void* pHeap; - - result = ma_engine_node_get_heap_size(pConfig, &heapSizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - if (heapSizeInBytes > 0) { - pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); - if (pHeap == NULL) { - return MA_OUT_OF_MEMORY; - } - } else { - pHeap = NULL; - } - - result = ma_engine_node_init_preallocated(pConfig, pHeap, pEngineNode); - if (result != MA_SUCCESS) { - ma_free(pHeap, pAllocationCallbacks); - return result; - } - - pEngineNode->_ownsHeap = MA_TRUE; - return MA_SUCCESS; -} - -MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks) -{ - /* - The base node always needs to be uninitialized first to ensure it's detached from the graph completely before we - destroy anything that might be in the middle of being used by the processing function. - */ - ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks); - - /* Now that the node has been uninitialized we can safely uninitialize the rest. */ - if (pEngineNode->volumeSmoothTimeInPCMFrames > 0) { - ma_gainer_uninit(&pEngineNode->volumeGainer, pAllocationCallbacks); - } - - ma_spatializer_uninit(&pEngineNode->spatializer, pAllocationCallbacks); - ma_linear_resampler_uninit(&pEngineNode->resampler, pAllocationCallbacks); - - /* Free the heap last. */ - if (pEngineNode->_ownsHeap) { - ma_free(pEngineNode->_pHeap, pAllocationCallbacks); - } -} - - -MA_API ma_sound_config ma_sound_config_init(void) -{ - return ma_sound_config_init_2(NULL); -} - -MA_API ma_sound_config ma_sound_config_init_2(ma_engine* pEngine) -{ - ma_sound_config config; - - MA_ZERO_OBJECT(&config); - - if (pEngine != NULL) { - config.monoExpansionMode = pEngine->monoExpansionMode; - } else { - config.monoExpansionMode = ma_mono_expansion_mode_default; - } - - config.rangeEndInPCMFrames = ~((ma_uint64)0); - config.loopPointEndInPCMFrames = ~((ma_uint64)0); - - return config; -} - -MA_API ma_sound_group_config ma_sound_group_config_init(void) -{ - return ma_sound_group_config_init_2(NULL); -} - -MA_API ma_sound_group_config ma_sound_group_config_init_2(ma_engine* pEngine) -{ - ma_sound_group_config config; - - MA_ZERO_OBJECT(&config); - - if (pEngine != NULL) { - config.monoExpansionMode = pEngine->monoExpansionMode; - } else { - config.monoExpansionMode = ma_mono_expansion_mode_default; - } - - return config; -} - - -MA_API ma_engine_config ma_engine_config_init(void) -{ - ma_engine_config config; - - MA_ZERO_OBJECT(&config); - config.listenerCount = 1; /* Always want at least one listener. */ - config.monoExpansionMode = ma_mono_expansion_mode_default; - - return config; -} - - -#if !defined(MA_NO_DEVICE_IO) -static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) -{ - ma_engine* pEngine = (ma_engine*)pDevice->pUserData; - - (void)pFramesIn; - - /* - Experiment: Try processing a resource manager job if we're on the Emscripten build. - - This serves two purposes: - - 1) It ensures jobs are actually processed at some point since we cannot guarantee that the - caller is doing the right thing and calling ma_resource_manager_process_next_job(); and - - 2) It's an attempt at working around an issue where processing jobs on the Emscripten main - loop doesn't work as well as it should. When trying to load sounds without the `DECODE` - flag or with the `ASYNC` flag, the sound data is just not able to be loaded in time - before the callback is processed. I think it's got something to do with the single- - threaded nature of Web, but I'm not entirely sure. - */ - #if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_EMSCRIPTEN) - { - if (pEngine->pResourceManager != NULL) { - if ((pEngine->pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) { - ma_resource_manager_process_next_job(pEngine->pResourceManager); - } - } - } - #endif - - ma_engine_read_pcm_frames(pEngine, pFramesOut, frameCount, NULL); -} - -static ma_uint32 ma_device__get_processing_size_in_frames(ma_device* pDevice) -{ - /* - The processing size is the period size. The device can have a fixed sized processing size, or - it can be decided by the backend in which case it can be variable. - */ - if (pDevice->playback.intermediaryBufferCap > 0) { - /* Using a fixed sized processing callback. */ - return pDevice->playback.intermediaryBufferCap; - } else { - /* Not using a fixed sized processing callback. Need to estimate the processing size based on the backend. */ - return pDevice->playback.internalPeriodSizeInFrames; - } -} -#endif - -MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine) -{ - ma_result result; - ma_node_graph_config nodeGraphConfig; - ma_engine_config engineConfig; - ma_spatializer_listener_config listenerConfig; - ma_uint32 iListener; - - if (pEngine == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pEngine); - - /* The config is allowed to be NULL in which case we use defaults for everything. */ - if (pConfig != NULL) { - engineConfig = *pConfig; - } else { - engineConfig = ma_engine_config_init(); - } - - pEngine->monoExpansionMode = engineConfig.monoExpansionMode; - pEngine->defaultVolumeSmoothTimeInPCMFrames = engineConfig.defaultVolumeSmoothTimeInPCMFrames; - pEngine->onProcess = engineConfig.onProcess; - pEngine->pProcessUserData = engineConfig.pProcessUserData; - ma_allocation_callbacks_init_copy(&pEngine->allocationCallbacks, &engineConfig.allocationCallbacks); - - #if !defined(MA_NO_RESOURCE_MANAGER) - { - pEngine->pResourceManager = engineConfig.pResourceManager; - } - #endif - - #if !defined(MA_NO_DEVICE_IO) - { - pEngine->pDevice = engineConfig.pDevice; - - /* If we don't have a device, we need one. */ - if (pEngine->pDevice == NULL && engineConfig.noDevice == MA_FALSE) { - ma_device_config deviceConfig; - - pEngine->pDevice = (ma_device*)ma_malloc(sizeof(*pEngine->pDevice), &pEngine->allocationCallbacks); - if (pEngine->pDevice == NULL) { - return MA_OUT_OF_MEMORY; - } - - deviceConfig = ma_device_config_init(ma_device_type_playback); - deviceConfig.playback.pDeviceID = engineConfig.pPlaybackDeviceID; - deviceConfig.playback.format = ma_format_f32; - deviceConfig.playback.channels = engineConfig.channels; - deviceConfig.sampleRate = engineConfig.sampleRate; - deviceConfig.dataCallback = (engineConfig.dataCallback != NULL) ? engineConfig.dataCallback : ma_engine_data_callback_internal; - deviceConfig.pUserData = pEngine; - deviceConfig.notificationCallback = engineConfig.notificationCallback; - deviceConfig.periodSizeInFrames = engineConfig.periodSizeInFrames; - deviceConfig.periodSizeInMilliseconds = engineConfig.periodSizeInMilliseconds; - deviceConfig.noPreSilencedOutputBuffer = MA_TRUE; /* We'll always be outputting to every frame in the callback so there's no need for a pre-silenced buffer. */ - deviceConfig.noClip = MA_TRUE; /* The engine will do clipping itself. */ - - if (engineConfig.pContext == NULL) { - ma_context_config contextConfig = ma_context_config_init(); - contextConfig.allocationCallbacks = pEngine->allocationCallbacks; - contextConfig.pLog = engineConfig.pLog; - - /* If the engine config does not specify a log, use the resource manager's if we have one. */ - #ifndef MA_NO_RESOURCE_MANAGER - { - if (contextConfig.pLog == NULL && engineConfig.pResourceManager != NULL) { - contextConfig.pLog = ma_resource_manager_get_log(engineConfig.pResourceManager); - } - } - #endif - - result = ma_device_init_ex(NULL, 0, &contextConfig, &deviceConfig, pEngine->pDevice); - } else { - result = ma_device_init(engineConfig.pContext, &deviceConfig, pEngine->pDevice); - } - - if (result != MA_SUCCESS) { - ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); - pEngine->pDevice = NULL; - return result; - } - - pEngine->ownsDevice = MA_TRUE; - } - - /* Update the channel count and sample rate of the engine config so we can reference it below. */ - if (pEngine->pDevice != NULL) { - engineConfig.channels = pEngine->pDevice->playback.channels; - engineConfig.sampleRate = pEngine->pDevice->sampleRate; - - /* - The processing size used by the engine is determined by engineConfig.periodSizeInFrames. We want - to make this equal to what the device is using for it's period size. If we don't do that, it's - possible that the node graph will split it's processing into multiple passes which can introduce - glitching. - */ - engineConfig.periodSizeInFrames = ma_device__get_processing_size_in_frames(pEngine->pDevice); - } - } - #endif - - if (engineConfig.channels == 0 || engineConfig.sampleRate == 0) { - return MA_INVALID_ARGS; - } - - pEngine->sampleRate = engineConfig.sampleRate; - - /* The engine always uses either the log that was passed into the config, or the context's log is available. */ - if (engineConfig.pLog != NULL) { - pEngine->pLog = engineConfig.pLog; - } else { - #if !defined(MA_NO_DEVICE_IO) - { - pEngine->pLog = ma_device_get_log(pEngine->pDevice); - } - #else - { - pEngine->pLog = NULL; - } - #endif - } - - - /* The engine is a node graph. This needs to be initialized after we have the device so we can determine the channel count. */ - nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels); - nodeGraphConfig.processingSizeInFrames = engineConfig.periodSizeInFrames; - nodeGraphConfig.preMixStackSizeInBytes = engineConfig.preMixStackSizeInBytes; - - result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph); - if (result != MA_SUCCESS) { - goto on_error_1; - } - - - /* We need at least one listener. */ - if (engineConfig.listenerCount == 0) { - engineConfig.listenerCount = 1; - } - - if (engineConfig.listenerCount > MA_ENGINE_MAX_LISTENERS) { - result = MA_INVALID_ARGS; /* Too many listeners. */ - goto on_error_1; - } - - for (iListener = 0; iListener < engineConfig.listenerCount; iListener += 1) { - listenerConfig = ma_spatializer_listener_config_init(ma_node_graph_get_channels(&pEngine->nodeGraph)); - - /* - If we're using a device, use the device's channel map for the listener. Otherwise just use - miniaudio's default channel map. - */ - #if !defined(MA_NO_DEVICE_IO) - { - if (pEngine->pDevice != NULL) { - /* - Temporarily disabled. There is a subtle bug here where front-left and front-right - will be used by the device's channel map, but this is not what we want to use for - spatialization. Instead we want to use side-left and side-right. I need to figure - out a better solution for this. For now, disabling the use of device channel maps. - */ - /*listenerConfig.pChannelMapOut = pEngine->pDevice->playback.channelMap;*/ - } - } - #endif - - result = ma_spatializer_listener_init(&listenerConfig, &pEngine->allocationCallbacks, &pEngine->listeners[iListener]); /* TODO: Change this to a pre-allocated heap. */ - if (result != MA_SUCCESS) { - goto on_error_2; - } - - pEngine->listenerCount += 1; - } - - - /* Gain smoothing for spatialized sounds. */ - pEngine->gainSmoothTimeInFrames = engineConfig.gainSmoothTimeInFrames; - if (pEngine->gainSmoothTimeInFrames == 0) { - ma_uint32 gainSmoothTimeInMilliseconds = engineConfig.gainSmoothTimeInMilliseconds; - if (gainSmoothTimeInMilliseconds == 0) { - gainSmoothTimeInMilliseconds = 8; - } - - pEngine->gainSmoothTimeInFrames = (gainSmoothTimeInMilliseconds * ma_engine_get_sample_rate(pEngine)) / 1000; /* 8ms by default. */ - } - - - /* We need a resource manager. */ - #ifndef MA_NO_RESOURCE_MANAGER - { - if (pEngine->pResourceManager == NULL) { - ma_resource_manager_config resourceManagerConfig; - - pEngine->pResourceManager = (ma_resource_manager*)ma_malloc(sizeof(*pEngine->pResourceManager), &pEngine->allocationCallbacks); - if (pEngine->pResourceManager == NULL) { - result = MA_OUT_OF_MEMORY; - goto on_error_2; - } - - resourceManagerConfig = ma_resource_manager_config_init(); - resourceManagerConfig.pLog = pEngine->pLog; /* Always use the engine's log for internally-managed resource managers. */ - resourceManagerConfig.decodedFormat = ma_format_f32; - resourceManagerConfig.decodedChannels = 0; /* Leave the decoded channel count as 0 so we can get good spatialization. */ - resourceManagerConfig.decodedSampleRate = ma_engine_get_sample_rate(pEngine); - ma_allocation_callbacks_init_copy(&resourceManagerConfig.allocationCallbacks, &pEngine->allocationCallbacks); - resourceManagerConfig.pVFS = engineConfig.pResourceManagerVFS; - - /* The Emscripten build cannot use threads unless it's targeting pthreads. */ - #if defined(MA_EMSCRIPTEN) && !defined(__EMSCRIPTEN_PTHREADS__) - { - resourceManagerConfig.jobThreadCount = 0; - resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; - } - #endif - - result = ma_resource_manager_init(&resourceManagerConfig, pEngine->pResourceManager); - if (result != MA_SUCCESS) { - goto on_error_3; - } - - pEngine->ownsResourceManager = MA_TRUE; - } - } - #endif - - /* Setup some stuff for inlined sounds. That is sounds played with ma_engine_play_sound(). */ - pEngine->inlinedSoundLock = 0; - pEngine->pInlinedSoundHead = NULL; - - /* Start the engine if required. This should always be the last step. */ - #if !defined(MA_NO_DEVICE_IO) - { - if (engineConfig.noAutoStart == MA_FALSE && pEngine->pDevice != NULL) { - result = ma_engine_start(pEngine); - if (result != MA_SUCCESS) { - goto on_error_4; /* Failed to start the engine. */ - } - } - } - #endif - - return MA_SUCCESS; - -#if !defined(MA_NO_DEVICE_IO) -on_error_4: -#endif -#if !defined(MA_NO_RESOURCE_MANAGER) -on_error_3: - if (pEngine->ownsResourceManager) { - ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks); - } -#endif /* MA_NO_RESOURCE_MANAGER */ -on_error_2: - for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { - ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks); - } - - ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks); -on_error_1: - #if !defined(MA_NO_DEVICE_IO) - { - if (pEngine->ownsDevice) { - ma_device_uninit(pEngine->pDevice); - ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); - } - } - #endif - - return result; -} - -MA_API void ma_engine_uninit(ma_engine* pEngine) -{ - ma_uint32 iListener; - - if (pEngine == NULL) { - return; - } - - /* The device must be uninitialized before the node graph to ensure the audio thread doesn't try accessing it. */ - #if !defined(MA_NO_DEVICE_IO) - { - if (pEngine->ownsDevice) { - ma_device_uninit(pEngine->pDevice); - ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); - } else { - if (pEngine->pDevice != NULL) { - ma_device_stop(pEngine->pDevice); - } - } - } - #endif - - /* - All inlined sounds need to be deleted. I'm going to use a lock here just to future proof in case - I want to do some kind of garbage collection later on. - */ - ma_spinlock_lock(&pEngine->inlinedSoundLock); - { - for (;;) { - ma_sound_inlined* pSoundToDelete = pEngine->pInlinedSoundHead; - if (pSoundToDelete == NULL) { - break; /* Done. */ - } - - pEngine->pInlinedSoundHead = pSoundToDelete->pNext; - - ma_sound_uninit(&pSoundToDelete->sound); - ma_free(pSoundToDelete, &pEngine->allocationCallbacks); - } - } - ma_spinlock_unlock(&pEngine->inlinedSoundLock); - - for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { - ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks); - } - - /* Make sure the node graph is uninitialized after the audio thread has been shutdown to prevent accessing of the node graph after being uninitialized. */ - ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks); - - /* Uninitialize the resource manager last to ensure we don't have a thread still trying to access it. */ -#ifndef MA_NO_RESOURCE_MANAGER - if (pEngine->ownsResourceManager) { - ma_resource_manager_uninit(pEngine->pResourceManager); - ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks); - } -#endif -} - -MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - ma_result result; - ma_uint64 framesRead = 0; - - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - result = ma_node_graph_read_pcm_frames(&pEngine->nodeGraph, pFramesOut, frameCount, &framesRead); - if (result != MA_SUCCESS) { - return result; - } - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - if (pEngine->onProcess) { - pEngine->onProcess(pEngine->pProcessUserData, (float*)pFramesOut, framesRead); /* Safe cast to float* because the engine always works on floating point samples. */ - } - - return MA_SUCCESS; -} - -MA_API ma_node_graph* ma_engine_get_node_graph(ma_engine* pEngine) -{ - if (pEngine == NULL) { - return NULL; - } - - return &pEngine->nodeGraph; -} - -#if !defined(MA_NO_RESOURCE_MANAGER) -MA_API ma_resource_manager* ma_engine_get_resource_manager(ma_engine* pEngine) -{ - if (pEngine == NULL) { - return NULL; - } - - #if !defined(MA_NO_RESOURCE_MANAGER) - { - return pEngine->pResourceManager; - } - #else - { - return NULL; - } - #endif -} -#endif - -MA_API ma_device* ma_engine_get_device(ma_engine* pEngine) -{ - if (pEngine == NULL) { - return NULL; - } - - #if !defined(MA_NO_DEVICE_IO) - { - return pEngine->pDevice; - } - #else - { - return NULL; - } - #endif -} - -MA_API ma_log* ma_engine_get_log(ma_engine* pEngine) -{ - if (pEngine == NULL) { - return NULL; - } - - if (pEngine->pLog != NULL) { - return pEngine->pLog; - } else { - #if !defined(MA_NO_DEVICE_IO) - { - return ma_device_get_log(ma_engine_get_device(pEngine)); - } - #else - { - return NULL; - } - #endif - } -} - -MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine) -{ - return ma_node_graph_get_endpoint(&pEngine->nodeGraph); -} - -MA_API ma_uint64 ma_engine_get_time_in_pcm_frames(const ma_engine* pEngine) -{ - return ma_node_graph_get_time(&pEngine->nodeGraph); -} - -MA_API ma_uint64 ma_engine_get_time_in_milliseconds(const ma_engine* pEngine) -{ - return ma_engine_get_time_in_pcm_frames(pEngine) * 1000 / ma_engine_get_sample_rate(pEngine); -} - -MA_API ma_result ma_engine_set_time_in_pcm_frames(ma_engine* pEngine, ma_uint64 globalTime) -{ - return ma_node_graph_set_time(&pEngine->nodeGraph, globalTime); -} - -MA_API ma_result ma_engine_set_time_in_milliseconds(ma_engine* pEngine, ma_uint64 globalTime) -{ - return ma_engine_set_time_in_pcm_frames(pEngine, globalTime * ma_engine_get_sample_rate(pEngine) / 1000); -} - -MA_API ma_uint64 ma_engine_get_time(const ma_engine* pEngine) -{ - return ma_engine_get_time_in_pcm_frames(pEngine); -} - -MA_API ma_result ma_engine_set_time(ma_engine* pEngine, ma_uint64 globalTime) -{ - return ma_engine_set_time_in_pcm_frames(pEngine, globalTime); -} - -MA_API ma_uint32 ma_engine_get_channels(const ma_engine* pEngine) -{ - return ma_node_graph_get_channels(&pEngine->nodeGraph); -} - -MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine) -{ - if (pEngine == NULL) { - return 0; - } - - return pEngine->sampleRate; -} - - -MA_API ma_result ma_engine_start(ma_engine* pEngine) -{ - ma_result result; - - if (pEngine == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_DEVICE_IO) - { - if (pEngine->pDevice != NULL) { - result = ma_device_start(pEngine->pDevice); - } else { - result = MA_INVALID_OPERATION; /* The engine is running without a device which means there's no real notion of "starting" the engine. */ - } - } - #else - { - result = MA_INVALID_OPERATION; /* Device IO is disabled, so there's no real notion of "starting" the engine. */ - } - #endif - - if (result != MA_SUCCESS) { - return result; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_engine_stop(ma_engine* pEngine) -{ - ma_result result; - - if (pEngine == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_DEVICE_IO) - { - if (pEngine->pDevice != NULL) { - result = ma_device_stop(pEngine->pDevice); - } else { - result = MA_INVALID_OPERATION; /* The engine is running without a device which means there's no real notion of "stopping" the engine. */ - } - } - #else - { - result = MA_INVALID_OPERATION; /* Device IO is disabled, so there's no real notion of "stopping" the engine. */ - } - #endif - - if (result != MA_SUCCESS) { - return result; - } - - return MA_SUCCESS; -} - -MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume) -{ - if (pEngine == NULL) { - return MA_INVALID_ARGS; - } - - return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, volume); -} - -MA_API float ma_engine_get_volume(ma_engine* pEngine) -{ - if (pEngine == NULL) { - return 0; - } - - return ma_node_get_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0); -} - -MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB) -{ - return ma_engine_set_volume(pEngine, ma_volume_db_to_linear(gainDB)); -} - -MA_API float ma_engine_get_gain_db(ma_engine* pEngine) -{ - return ma_volume_linear_to_db(ma_engine_get_volume(pEngine)); -} - - -MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine) -{ - if (pEngine == NULL) { - return 0; - } - - return pEngine->listenerCount; -} - -MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ) -{ - ma_uint32 iListener; - ma_uint32 iListenerClosest; - float closestLen2 = MA_FLT_MAX; - - if (pEngine == NULL || pEngine->listenerCount == 1) { - return 0; - } - - iListenerClosest = 0; - for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { - if (ma_engine_listener_is_enabled(pEngine, iListener)) { - float len2 = ma_vec3f_len2(ma_vec3f_sub(ma_spatializer_listener_get_position(&pEngine->listeners[iListener]), ma_vec3f_init_3f(absolutePosX, absolutePosY, absolutePosZ))); - if (closestLen2 > len2) { - closestLen2 = len2; - iListenerClosest = iListener; - } - } - } - - MA_ASSERT(iListenerClosest < 255); - return iListenerClosest; -} - -MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_set_position(&pEngine->listeners[listenerIndex], x, y, z); -} - -MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_spatializer_listener_get_position(&pEngine->listeners[listenerIndex]); -} - -MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_set_direction(&pEngine->listeners[listenerIndex], x, y, z); -} - -MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return ma_vec3f_init_3f(0, 0, -1); - } - - return ma_spatializer_listener_get_direction(&pEngine->listeners[listenerIndex]); -} - -MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_set_velocity(&pEngine->listeners[listenerIndex], x, y, z); -} - -MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_spatializer_listener_get_velocity(&pEngine->listeners[listenerIndex]); -} - -MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_set_cone(&pEngine->listeners[listenerIndex], innerAngleInRadians, outerAngleInRadians, outerGain); -} - -MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) -{ - if (pInnerAngleInRadians != NULL) { - *pInnerAngleInRadians = 0; - } - - if (pOuterAngleInRadians != NULL) { - *pOuterAngleInRadians = 0; - } - - if (pOuterGain != NULL) { - *pOuterGain = 0; - } - - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_get_cone(&pEngine->listeners[listenerIndex], pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); -} - -MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_set_world_up(&pEngine->listeners[listenerIndex], x, y, z); -} - -MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return ma_vec3f_init_3f(0, 1, 0); - } - - return ma_spatializer_listener_get_world_up(&pEngine->listeners[listenerIndex]); -} - -MA_API void ma_engine_listener_set_enabled(ma_engine* pEngine, ma_uint32 listenerIndex, ma_bool32 isEnabled) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return; - } - - ma_spatializer_listener_set_enabled(&pEngine->listeners[listenerIndex], isEnabled); -} - -MA_API ma_bool32 ma_engine_listener_is_enabled(const ma_engine* pEngine, ma_uint32 listenerIndex) -{ - if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { - return MA_FALSE; - } - - return ma_spatializer_listener_is_enabled(&pEngine->listeners[listenerIndex]); -} - - -#ifndef MA_NO_RESOURCE_MANAGER -MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex) -{ - ma_result result = MA_SUCCESS; - ma_sound_inlined* pSound = NULL; - ma_sound_inlined* pNextSound = NULL; - - if (pEngine == NULL || pFilePath == NULL) { - return MA_INVALID_ARGS; - } - - /* Attach to the endpoint node if nothing is specified. */ - if (pNode == NULL) { - pNode = ma_node_graph_get_endpoint(&pEngine->nodeGraph); - nodeInputBusIndex = 0; - } - - /* - We want to check if we can recycle an already-allocated inlined sound. Since this is just a - helper I'm not *too* concerned about performance here and I'm happy to use a lock to keep - the implementation simple. Maybe this can be optimized later if there's enough demand, but - if this function is being used it probably means the caller doesn't really care too much. - - What we do is check the atEnd flag. When this is true, we can recycle the sound. Otherwise - we just keep iterating. If we reach the end without finding a sound to recycle we just - allocate a new one. This doesn't scale well for a massive number of sounds being played - simultaneously as we don't ever actually free the sound objects. Some kind of garbage - collection routine might be valuable for this which I'll think about. - */ - ma_spinlock_lock(&pEngine->inlinedSoundLock); - { - ma_uint32 soundFlags = 0; - - for (pNextSound = pEngine->pInlinedSoundHead; pNextSound != NULL; pNextSound = pNextSound->pNext) { - if (ma_sound_at_end(&pNextSound->sound)) { - /* - The sound is at the end which means it's available for recycling. All we need to do - is uninitialize it and reinitialize it. All we're doing is recycling memory. - */ - pSound = pNextSound; - ma_atomic_fetch_sub_32(&pEngine->inlinedSoundCount, 1); - break; - } - } - - if (pSound != NULL) { - /* - We actually want to detach the sound from the list here. The reason is because we want the sound - to be in a consistent state at the non-recycled case to simplify the logic below. - */ - if (pEngine->pInlinedSoundHead == pSound) { - pEngine->pInlinedSoundHead = pSound->pNext; - } - - if (pSound->pPrev != NULL) { - pSound->pPrev->pNext = pSound->pNext; - } - if (pSound->pNext != NULL) { - pSound->pNext->pPrev = pSound->pPrev; - } - - /* Now the previous sound needs to be uninitialized. */ - ma_sound_uninit(&pNextSound->sound); - } else { - /* No sound available for recycling. Allocate one now. */ - pSound = (ma_sound_inlined*)ma_malloc(sizeof(*pSound), &pEngine->allocationCallbacks); - } - - if (pSound != NULL) { /* Safety check for the allocation above. */ - /* - At this point we should have memory allocated for the inlined sound. We just need - to initialize it like a normal sound now. - */ - soundFlags |= MA_SOUND_FLAG_ASYNC; /* For inlined sounds we don't want to be sitting around waiting for stuff to load so force an async load. */ - soundFlags |= MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT; /* We want specific control over where the sound is attached in the graph. We'll attach it manually just before playing the sound. */ - soundFlags |= MA_SOUND_FLAG_NO_PITCH; /* Pitching isn't usable with inlined sounds, so disable it to save on speed. */ - soundFlags |= MA_SOUND_FLAG_NO_SPATIALIZATION; /* Not currently doing spatialization with inlined sounds, but this might actually change later. For now disable spatialization. Will be removed if we ever add support for spatialization here. */ - - result = ma_sound_init_from_file(pEngine, pFilePath, soundFlags, NULL, NULL, &pSound->sound); - if (result == MA_SUCCESS) { - /* Now attach the sound to the graph. */ - result = ma_node_attach_output_bus(pSound, 0, pNode, nodeInputBusIndex); - if (result == MA_SUCCESS) { - /* At this point the sound should be loaded and we can go ahead and add it to the list. The new item becomes the new head. */ - pSound->pNext = pEngine->pInlinedSoundHead; - pSound->pPrev = NULL; - - pEngine->pInlinedSoundHead = pSound; /* <-- This is what attaches the sound to the list. */ - if (pSound->pNext != NULL) { - pSound->pNext->pPrev = pSound; - } - } else { - ma_free(pSound, &pEngine->allocationCallbacks); - } - } else { - ma_free(pSound, &pEngine->allocationCallbacks); - } - } else { - result = MA_OUT_OF_MEMORY; - } - } - ma_spinlock_unlock(&pEngine->inlinedSoundLock); - - if (result != MA_SUCCESS) { - return result; - } - - /* Finally we can start playing the sound. */ - result = ma_sound_start(&pSound->sound); - if (result != MA_SUCCESS) { - /* Failed to start the sound. We need to mark it for recycling and return an error. */ - ma_atomic_exchange_32(&pSound->sound.atEnd, MA_TRUE); - return result; - } - - ma_atomic_fetch_add_32(&pEngine->inlinedSoundCount, 1); - return result; -} - -MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup) -{ - return ma_engine_play_sound_ex(pEngine, pFilePath, pGroup, 0); -} -#endif - - -static ma_result ma_sound_preinit(ma_engine* pEngine, ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pSound); - pSound->seekTarget = MA_SEEK_TARGET_NONE; - - if (pEngine == NULL) { - return MA_INVALID_ARGS; - } - - return MA_SUCCESS; -} - -static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound) -{ - ma_result result; - ma_engine_node_config engineNodeConfig; - ma_engine_node_type type; /* Will be set to ma_engine_node_type_group if no data source is specified. */ - - /* Do not clear pSound to zero here - that's done at a higher level with ma_sound_preinit(). */ - MA_ASSERT(pEngine != NULL); - MA_ASSERT(pSound != NULL); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - pSound->pDataSource = pConfig->pDataSource; - - if (pConfig->pDataSource != NULL) { - type = ma_engine_node_type_sound; - } else { - type = ma_engine_node_type_group; - } - - /* - Sounds are engine nodes. Before we can initialize this we need to determine the channel count. - If we can't do this we need to abort. It's up to the caller to ensure they're using a data - source that provides this information upfront. - */ - engineNodeConfig = ma_engine_node_config_init(pEngine, type, pConfig->flags); - engineNodeConfig.channelsIn = pConfig->channelsIn; - engineNodeConfig.channelsOut = pConfig->channelsOut; - engineNodeConfig.volumeSmoothTimeInPCMFrames = pConfig->volumeSmoothTimeInPCMFrames; - engineNodeConfig.monoExpansionMode = pConfig->monoExpansionMode; - - if (engineNodeConfig.volumeSmoothTimeInPCMFrames == 0) { - engineNodeConfig.volumeSmoothTimeInPCMFrames = pEngine->defaultVolumeSmoothTimeInPCMFrames; - } - - /* If we're loading from a data source the input channel count needs to be the data source's native channel count. */ - if (pConfig->pDataSource != NULL) { - result = ma_data_source_get_data_format(pConfig->pDataSource, NULL, &engineNodeConfig.channelsIn, &engineNodeConfig.sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the channel count. */ - } - - if (engineNodeConfig.channelsIn == 0) { - return MA_INVALID_OPERATION; /* Invalid channel count. */ - } - - if (engineNodeConfig.channelsOut == MA_SOUND_SOURCE_CHANNEL_COUNT) { - engineNodeConfig.channelsOut = engineNodeConfig.channelsIn; - } - } - - - /* Getting here means we should have a valid channel count and we can initialize the engine node. */ - result = ma_engine_node_init(&engineNodeConfig, &pEngine->allocationCallbacks, &pSound->engineNode); - if (result != MA_SUCCESS) { - return result; - } - - /* If no attachment is specified, attach the sound straight to the endpoint. */ - if (pConfig->pInitialAttachment == NULL) { - /* No group. Attach straight to the endpoint by default, unless the caller has requested that it not. */ - if ((pConfig->flags & MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT) == 0) { - result = ma_node_attach_output_bus(pSound, 0, ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0); - } - } else { - /* An attachment is specified. Attach to it by default. The sound has only a single output bus, and the config will specify which input bus to attach to. */ - result = ma_node_attach_output_bus(pSound, 0, pConfig->pInitialAttachment, pConfig->initialAttachmentInputBusIndex); - } - - if (result != MA_SUCCESS) { - ma_engine_node_uninit(&pSound->engineNode, &pEngine->allocationCallbacks); - return result; - } - - - /* Apply initial range and looping state to the data source if applicable. */ - if (pConfig->rangeBegInPCMFrames != 0 || pConfig->rangeEndInPCMFrames != ~((ma_uint64)0)) { - ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); - } - - if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) { - ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); - } - - ma_sound_set_looping(pSound, pConfig->isLooping || ((pConfig->flags & MA_SOUND_FLAG_LOOPING) != 0)); - - return MA_SUCCESS; -} - -#ifndef MA_NO_RESOURCE_MANAGER -MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound) -{ - ma_result result = MA_SUCCESS; - ma_uint32 flags; - ma_sound_config config; - ma_resource_manager_pipeline_notifications notifications; - - /* - The engine requires knowledge of the channel count of the underlying data source before it can - initialize the sound. Therefore, we need to make the resource manager wait until initialization - of the underlying data source to be initialized so we can get access to the channel count. To - do this, the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT is forced. - - Because we're initializing the data source before the sound, there's a chance the notification - will get triggered before this function returns. This is OK, so long as the caller is aware of - it and can avoid accessing the sound from within the notification. - */ - flags = pConfig->flags | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT; - if (pConfig->isLooping) { - flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; - } - - pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks); - if (pSound->pResourceManagerDataSource == NULL) { - return MA_OUT_OF_MEMORY; - } - - /* Removed in 0.12. Set pDoneFence on the notifications. */ - notifications = pConfig->initNotifications; - if (pConfig->pDoneFence != NULL && notifications.done.pFence == NULL) { - notifications.done.pFence = pConfig->pDoneFence; - } - - /* - We must wrap everything around the fence if one was specified. This ensures ma_fence_wait() does - not return prematurely before the sound has finished initializing. - */ - if (notifications.done.pFence) { ma_fence_acquire(notifications.done.pFence); } - { - ma_resource_manager_data_source_config resourceManagerDataSourceConfig = ma_resource_manager_data_source_config_init(); - resourceManagerDataSourceConfig.pFilePath = pConfig->pFilePath; - resourceManagerDataSourceConfig.pFilePathW = pConfig->pFilePathW; - resourceManagerDataSourceConfig.flags = flags; - resourceManagerDataSourceConfig.pNotifications = ¬ifications; - resourceManagerDataSourceConfig.initialSeekPointInPCMFrames = pConfig->initialSeekPointInPCMFrames; - resourceManagerDataSourceConfig.rangeBegInPCMFrames = pConfig->rangeBegInPCMFrames; - resourceManagerDataSourceConfig.rangeEndInPCMFrames = pConfig->rangeEndInPCMFrames; - resourceManagerDataSourceConfig.loopPointBegInPCMFrames = pConfig->loopPointBegInPCMFrames; - resourceManagerDataSourceConfig.loopPointEndInPCMFrames = pConfig->loopPointEndInPCMFrames; - resourceManagerDataSourceConfig.isLooping = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING) != 0; - - result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); - if (result != MA_SUCCESS) { - goto done; - } - - pSound->ownsDataSource = MA_TRUE; /* <-- Important. Not setting this will result in the resource manager data source never getting uninitialized. */ - - /* We need to use a slightly customized version of the config so we'll need to make a copy. */ - config = *pConfig; - config.pFilePath = NULL; - config.pFilePathW = NULL; - config.pDataSource = pSound->pResourceManagerDataSource; - - result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound); - if (result != MA_SUCCESS) { - ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource); - ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); - MA_ZERO_OBJECT(pSound); - goto done; - } - } -done: - if (notifications.done.pFence) { ma_fence_release(notifications.done.pFence); } - return result; -} - -MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound) -{ - ma_sound_config config; - - if (pFilePath == NULL) { - return MA_INVALID_ARGS; - } - - config = ma_sound_config_init_2(pEngine); - config.pFilePath = pFilePath; - config.flags = flags; - config.pInitialAttachment = pGroup; - config.pDoneFence = pDoneFence; - - return ma_sound_init_ex(pEngine, &config, pSound); -} - -MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound) -{ - ma_sound_config config; - - if (pFilePath == NULL) { - return MA_INVALID_ARGS; - } - - config = ma_sound_config_init_2(pEngine); - config.pFilePathW = pFilePath; - config.flags = flags; - config.pInitialAttachment = pGroup; - config.pDoneFence = pDoneFence; - - return ma_sound_init_ex(pEngine, &config, pSound); -} - -MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound) -{ - ma_result result; - ma_sound_config config; - - result = ma_sound_preinit(pEngine, pSound); - if (result != MA_SUCCESS) { - return result; - } - - if (pExistingSound == NULL) { - return MA_INVALID_ARGS; - } - - /* Cloning only works for data buffers (not streams) that are loaded from the resource manager. */ - if (pExistingSound->pResourceManagerDataSource == NULL) { - return MA_INVALID_OPERATION; - } - - /* - We need to make a clone of the data source. If the data source is not a data buffer (i.e. a stream) - this will fail. - */ - pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks); - if (pSound->pResourceManagerDataSource == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_resource_manager_data_source_init_copy(pEngine->pResourceManager, pExistingSound->pResourceManagerDataSource, pSound->pResourceManagerDataSource); - if (result != MA_SUCCESS) { - ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); - return result; - } - - config = ma_sound_config_init_2(pEngine); - config.pDataSource = pSound->pResourceManagerDataSource; - config.flags = flags; - config.pInitialAttachment = pGroup; - config.monoExpansionMode = pExistingSound->engineNode.monoExpansionMode; - config.volumeSmoothTimeInPCMFrames = pExistingSound->engineNode.volumeSmoothTimeInPCMFrames; - - result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound); - if (result != MA_SUCCESS) { - ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource); - ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); - MA_ZERO_OBJECT(pSound); - return result; - } - - /* Make sure the sound is marked as the owner of the data source or else it will never get uninitialized. */ - pSound->ownsDataSource = MA_TRUE; - - return MA_SUCCESS; -} -#endif - -MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound) -{ - ma_sound_config config = ma_sound_config_init_2(pEngine); - config.pDataSource = pDataSource; - config.flags = flags; - config.pInitialAttachment = pGroup; - return ma_sound_init_ex(pEngine, &config, pSound); -} - -MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound) -{ - ma_result result; - - result = ma_sound_preinit(pEngine, pSound); - if (result != MA_SUCCESS) { - return result; - } - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - pSound->endCallback = pConfig->endCallback; - pSound->pEndCallbackUserData = pConfig->pEndCallbackUserData; - - /* We need to load the sound differently depending on whether or not we're loading from a file. */ -#ifndef MA_NO_RESOURCE_MANAGER - if (pConfig->pFilePath != NULL || pConfig->pFilePathW != NULL) { - return ma_sound_init_from_file_internal(pEngine, pConfig, pSound); - } else -#endif - { - /* - Getting here means we're not loading from a file. We may be loading from an already-initialized - data source, or none at all. If we aren't specifying any data source, we'll be initializing - the equivalent to a group. ma_data_source_init_from_data_source_internal() will deal with this - for us, so no special treatment required here. - */ - return ma_sound_init_from_data_source_internal(pEngine, pConfig, pSound); - } -} - -MA_API void ma_sound_uninit(ma_sound* pSound) -{ - if (pSound == NULL) { - return; - } - - /* - Always uninitialize the node first. This ensures it's detached from the graph and does not return until it has done - so which makes thread safety beyond this point trivial. - */ - ma_engine_node_uninit(&pSound->engineNode, &pSound->engineNode.pEngine->allocationCallbacks); - - /* Once the sound is detached from the group we can guarantee that it won't be referenced by the mixer thread which means it's safe for us to destroy the data source. */ -#ifndef MA_NO_RESOURCE_MANAGER - if (pSound->ownsDataSource) { - ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource); - ma_free(pSound->pResourceManagerDataSource, &pSound->engineNode.pEngine->allocationCallbacks); - pSound->pDataSource = NULL; - } -#else - MA_ASSERT(pSound->ownsDataSource == MA_FALSE); -#endif -} - -MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound) -{ - if (pSound == NULL) { - return NULL; - } - - return pSound->engineNode.pEngine; -} - -MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound) -{ - if (pSound == NULL) { - return NULL; - } - - return pSound->pDataSource; -} - -MA_API ma_result ma_sound_start(ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* If the sound is already playing, do nothing. */ - if (ma_sound_is_playing(pSound)) { - return MA_SUCCESS; - } - - /* If the sound is at the end it means we want to start from the start again. */ - if (ma_sound_at_end(pSound)) { - ma_result result = ma_data_source_seek_to_pcm_frame(pSound->pDataSource, 0); - if (result != MA_SUCCESS && result != MA_NOT_IMPLEMENTED) { - return result; /* Failed to seek back to the start. */ - } - - /* Make sure we clear the end indicator. */ - ma_atomic_exchange_32(&pSound->atEnd, MA_FALSE); - } - - /* Make sure the sound is started. If there's a start delay, the sound won't actually start until the start time is reached. */ - ma_node_set_state(pSound, ma_node_state_started); - - return MA_SUCCESS; -} - -MA_API ma_result ma_sound_stop(ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* This will stop the sound immediately. Use ma_sound_set_stop_time() to stop the sound at a specific time. */ - ma_node_set_state(pSound, ma_node_state_stopped); - - return MA_SUCCESS; -} - -MA_API ma_result ma_sound_stop_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 fadeLengthInFrames) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* Stopping with a fade out requires us to schedule the stop into the future by the fade length. */ - ma_sound_set_stop_time_with_fade_in_pcm_frames(pSound, ma_engine_get_time_in_pcm_frames(ma_sound_get_engine(pSound)) + fadeLengthInFrames, fadeLengthInFrames); - - return MA_SUCCESS; -} - -MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 fadeLengthInMilliseconds) -{ - ma_uint64 sampleRate; - - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); - - return ma_sound_stop_with_fade_in_pcm_frames(pSound, (fadeLengthInMilliseconds * sampleRate) / 1000); -} - -MA_API void ma_sound_set_volume(ma_sound* pSound, float volume) -{ - if (pSound == NULL) { - return; - } - - ma_engine_node_set_volume(&pSound->engineNode, volume); -} - -MA_API float ma_sound_get_volume(const ma_sound* pSound) -{ - float volume = 0; - - if (pSound == NULL) { - return 0; - } - - ma_engine_node_get_volume(&pSound->engineNode, &volume); - - return volume; -} - -MA_API void ma_sound_set_pan(ma_sound* pSound, float pan) -{ - if (pSound == NULL) { - return; - } - - ma_panner_set_pan(&pSound->engineNode.panner, pan); -} - -MA_API float ma_sound_get_pan(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_panner_get_pan(&pSound->engineNode.panner); -} - -MA_API void ma_sound_set_pan_mode(ma_sound* pSound, ma_pan_mode panMode) -{ - if (pSound == NULL) { - return; - } - - ma_panner_set_mode(&pSound->engineNode.panner, panMode); -} - -MA_API ma_pan_mode ma_sound_get_pan_mode(const ma_sound* pSound) -{ - if (pSound == NULL) { - return ma_pan_mode_balance; - } - - return ma_panner_get_mode(&pSound->engineNode.panner); -} - -MA_API void ma_sound_set_pitch(ma_sound* pSound, float pitch) -{ - if (pSound == NULL) { - return; - } - - if (pitch <= 0) { - return; - } - - ma_atomic_exchange_explicit_f32(&pSound->engineNode.pitch, pitch, ma_atomic_memory_order_release); -} - -MA_API float ma_sound_get_pitch(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_atomic_load_f32(&pSound->engineNode.pitch); /* Naughty const-cast for this. */ -} - -MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enabled) -{ - if (pSound == NULL) { - return; - } - - ma_atomic_exchange_explicit_32(&pSound->engineNode.isSpatializationDisabled, !enabled, ma_atomic_memory_order_release); -} - -MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_FALSE; - } - - return ma_engine_node_is_spatialization_enabled(&pSound->engineNode); -} - -MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex) -{ - if (pSound == NULL || listenerIndex >= ma_engine_get_listener_count(ma_sound_get_engine(pSound))) { - return; - } - - ma_atomic_exchange_explicit_32(&pSound->engineNode.pinnedListenerIndex, listenerIndex, ma_atomic_memory_order_release); -} - -MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_LISTENER_INDEX_CLOSEST; - } - - return ma_atomic_load_explicit_32(&pSound->engineNode.pinnedListenerIndex, ma_atomic_memory_order_acquire); -} - -MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound) -{ - ma_uint32 listenerIndex; - - if (pSound == NULL) { - return 0; - } - - listenerIndex = ma_sound_get_pinned_listener_index(pSound); - if (listenerIndex == MA_LISTENER_INDEX_CLOSEST) { - ma_vec3f position = ma_sound_get_position(pSound); - return ma_engine_find_closest_listener(ma_sound_get_engine(pSound), position.x, position.y, position.z); - } - - return listenerIndex; -} - -MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound) -{ - ma_vec3f relativePos; - ma_engine* pEngine; - - if (pSound == NULL) { - return ma_vec3f_init_3f(0, 0, -1); - } - - pEngine = ma_sound_get_engine(pSound); - if (pEngine == NULL) { - return ma_vec3f_init_3f(0, 0, -1); - } - - ma_spatializer_get_relative_position_and_direction(&pSound->engineNode.spatializer, &pEngine->listeners[ma_sound_get_listener_index(pSound)], &relativePos, NULL); - - return ma_vec3f_normalize(ma_vec3f_neg(relativePos)); -} - -MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_position(&pSound->engineNode.spatializer, x, y, z); -} - -MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound) -{ - if (pSound == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_spatializer_get_position(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_direction(&pSound->engineNode.spatializer, x, y, z); -} - -MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound) -{ - if (pSound == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_spatializer_get_direction(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_velocity(&pSound->engineNode.spatializer, x, y, z); -} - -MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound) -{ - if (pSound == NULL) { - return ma_vec3f_init_3f(0, 0, 0); - } - - return ma_spatializer_get_velocity(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_attenuation_model(&pSound->engineNode.spatializer, attenuationModel); -} - -MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound) -{ - if (pSound == NULL) { - return ma_attenuation_model_none; - } - - return ma_spatializer_get_attenuation_model(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_positioning(&pSound->engineNode.spatializer, positioning); -} - -MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound) -{ - if (pSound == NULL) { - return ma_positioning_absolute; - } - - return ma_spatializer_get_positioning(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_rolloff(&pSound->engineNode.spatializer, rolloff); -} - -MA_API float ma_sound_get_rolloff(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_spatializer_get_rolloff(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_min_gain(&pSound->engineNode.spatializer, minGain); -} - -MA_API float ma_sound_get_min_gain(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_spatializer_get_min_gain(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_max_gain(&pSound->engineNode.spatializer, maxGain); -} - -MA_API float ma_sound_get_max_gain(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_spatializer_get_max_gain(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_min_distance(ma_sound* pSound, float minDistance) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_min_distance(&pSound->engineNode.spatializer, minDistance); -} - -MA_API float ma_sound_get_min_distance(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_spatializer_get_min_distance(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_max_distance(ma_sound* pSound, float maxDistance) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_max_distance(&pSound->engineNode.spatializer, maxDistance); -} - -MA_API float ma_sound_get_max_distance(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_spatializer_get_max_distance(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float outerAngleInRadians, float outerGain) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_cone(&pSound->engineNode.spatializer, innerAngleInRadians, outerAngleInRadians, outerGain); -} - -MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) -{ - if (pInnerAngleInRadians != NULL) { - *pInnerAngleInRadians = 0; - } - - if (pOuterAngleInRadians != NULL) { - *pOuterAngleInRadians = 0; - } - - if (pOuterGain != NULL) { - *pOuterGain = 0; - } - - if (pSound == NULL) { - return; - } - - ma_spatializer_get_cone(&pSound->engineNode.spatializer, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); -} - -MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_doppler_factor(&pSound->engineNode.spatializer, dopplerFactor); -} - -MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_spatializer_get_doppler_factor(&pSound->engineNode.spatializer); -} - -MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor) -{ - if (pSound == NULL) { - return; - } - - ma_spatializer_set_directional_attenuation_factor(&pSound->engineNode.spatializer, directionalAttenuationFactor); -} - -MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 1; - } - - return ma_spatializer_get_directional_attenuation_factor(&pSound->engineNode.spatializer); -} - - -MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames) -{ - if (pSound == NULL) { - return; - } - - ma_sound_set_fade_start_in_pcm_frames(pSound, volumeBeg, volumeEnd, fadeLengthInFrames, (~(ma_uint64)0)); -} - -MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds) -{ - if (pSound == NULL) { - return; - } - - ma_sound_set_fade_in_pcm_frames(pSound, volumeBeg, volumeEnd, (fadeLengthInMilliseconds * pSound->engineNode.fader.config.sampleRate) / 1000); -} - -MA_API void ma_sound_set_fade_start_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames, ma_uint64 absoluteGlobalTimeInFrames) -{ - if (pSound == NULL) { - return; - } - - /* - We don't want to update the fader at this point because we need to use the engine's current time - to derive the fader's start offset. The timer is being updated on the audio thread so in order to - do this as accurately as possible we'll need to defer this to the audio thread. - */ - ma_atomic_float_set(&pSound->engineNode.fadeSettings.volumeBeg, volumeBeg); - ma_atomic_float_set(&pSound->engineNode.fadeSettings.volumeEnd, volumeEnd); - ma_atomic_uint64_set(&pSound->engineNode.fadeSettings.fadeLengthInFrames, fadeLengthInFrames); - ma_atomic_uint64_set(&pSound->engineNode.fadeSettings.absoluteGlobalTimeInFrames, absoluteGlobalTimeInFrames); -} - -MA_API void ma_sound_set_fade_start_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds, ma_uint64 absoluteGlobalTimeInMilliseconds) -{ - ma_uint32 sampleRate; - - if (pSound == NULL) { - return; - } - - sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); - - ma_sound_set_fade_start_in_pcm_frames(pSound, volumeBeg, volumeEnd, (fadeLengthInMilliseconds * sampleRate) / 1000, (absoluteGlobalTimeInMilliseconds * sampleRate) / 1000); -} - -MA_API float ma_sound_get_current_fade_volume(const ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - return ma_fader_get_current_volume(&pSound->engineNode.fader); -} - -MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames) -{ - if (pSound == NULL) { - return; - } - - ma_node_set_state_time(pSound, ma_node_state_started, absoluteGlobalTimeInFrames); -} - -MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds) -{ - if (pSound == NULL) { - return; - } - - ma_sound_set_start_time_in_pcm_frames(pSound, absoluteGlobalTimeInMilliseconds * ma_engine_get_sample_rate(ma_sound_get_engine(pSound)) / 1000); -} - -MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames) -{ - if (pSound == NULL) { - return; - } - - ma_sound_set_stop_time_with_fade_in_pcm_frames(pSound, absoluteGlobalTimeInFrames, 0); -} - -MA_API void ma_sound_set_stop_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds) -{ - if (pSound == NULL) { - return; - } - - ma_sound_set_stop_time_in_pcm_frames(pSound, absoluteGlobalTimeInMilliseconds * ma_engine_get_sample_rate(ma_sound_get_engine(pSound)) / 1000); -} - -MA_API void ma_sound_set_stop_time_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 stopAbsoluteGlobalTimeInFrames, ma_uint64 fadeLengthInFrames) -{ - if (pSound == NULL) { - return; - } - - if (fadeLengthInFrames > 0) { - if (fadeLengthInFrames > stopAbsoluteGlobalTimeInFrames) { - fadeLengthInFrames = stopAbsoluteGlobalTimeInFrames; - } - - ma_sound_set_fade_start_in_pcm_frames(pSound, -1, 0, fadeLengthInFrames, stopAbsoluteGlobalTimeInFrames - fadeLengthInFrames); - } - - ma_node_set_state_time(pSound, ma_node_state_stopped, stopAbsoluteGlobalTimeInFrames); -} - -MA_API void ma_sound_set_stop_time_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 stopAbsoluteGlobalTimeInMilliseconds, ma_uint64 fadeLengthInMilliseconds) -{ - ma_uint32 sampleRate; - - if (pSound == NULL) { - return; - } - - sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); - - ma_sound_set_stop_time_with_fade_in_pcm_frames(pSound, (stopAbsoluteGlobalTimeInMilliseconds * sampleRate) / 1000, (fadeLengthInMilliseconds * sampleRate) / 1000); -} - -MA_API ma_bool32 ma_sound_is_playing(const ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_FALSE; - } - - return ma_node_get_state_by_time(pSound, ma_engine_get_time_in_pcm_frames(ma_sound_get_engine(pSound))) == ma_node_state_started; -} - -MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - return ma_node_get_time(pSound); -} - -MA_API ma_uint64 ma_sound_get_time_in_milliseconds(const ma_sound* pSound) -{ - return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); -} - -MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) -{ - if (pSound == NULL) { - return; - } - - /* Looping is only a valid concept if the sound is backed by a data source. */ - if (pSound->pDataSource == NULL) { - return; - } - - /* The looping state needs to be applied to the data source in order for any looping to actually happen. */ - ma_data_source_set_looping(pSound->pDataSource, isLooping); -} - -MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_FALSE; - } - - /* There is no notion of looping for sounds that are not backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_FALSE; - } - - return ma_data_source_is_looping(pSound->pDataSource); -} - -MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound) -{ - if (pSound == NULL) { - return MA_FALSE; - } - - /* There is no notion of an end of a sound if it's not backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_FALSE; - } - - return ma_sound_get_at_end(pSound); -} - -MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* Seeking is only valid for sounds that are backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_INVALID_OPERATION; - } - - /* We can't be seeking while reading at the same time. We just set the seek target and get the mixing thread to do the actual seek. */ - ma_atomic_exchange_64(&pSound->seekTarget, frameIndex); - - return MA_SUCCESS; -} - -MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds) -{ - ma_uint64 frameIndex; - ma_uint32 sampleRate; - ma_result result; - - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - result = ma_sound_get_data_format(pSound, NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - /* We need PCM frames. We need to convert first */ - frameIndex = (ma_uint64)(seekPointInSeconds * sampleRate); - - return ma_sound_seek_to_pcm_frame(pSound, frameIndex); -} - -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* The data format is retrieved directly from the data source if the sound is backed by one. Otherwise we pull it from the node. */ - if (pSound->pDataSource == NULL) { - ma_uint32 channels; - - if (pFormat != NULL) { - *pFormat = ma_format_f32; - } - - channels = ma_node_get_input_channels(&pSound->engineNode, 0); - if (pChannels != NULL) { - *pChannels = channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pSound->engineNode.resampler.config.sampleRateIn; - } - - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channels); - } - - return MA_SUCCESS; - } else { - return ma_data_source_get_data_format(pSound->pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); - } -} - -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor) -{ - ma_uint64 seekTarget; - - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* The notion of a cursor is only valid for sounds that are backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_INVALID_OPERATION; - } - - seekTarget = ma_atomic_load_64(&pSound->seekTarget); - if (seekTarget != MA_SEEK_TARGET_NONE) { - *pCursor = seekTarget; - return MA_SUCCESS; - } else { - return ma_data_source_get_cursor_in_pcm_frames(pSound->pDataSource, pCursor); - } -} - -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* The notion of a sound length is only valid for sounds that are backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_INVALID_OPERATION; - } - - return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); -} - -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor) -{ - ma_result result; - ma_uint64 cursorInPCMFrames; - ma_uint32 sampleRate; - - if (pCursor != NULL) { - *pCursor = 0; - } - - result = ma_sound_get_cursor_in_pcm_frames(pSound, &cursorInPCMFrames); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_sound_get_data_format(pSound, NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return result; - } - - /* VC6 does not support division of unsigned 64-bit integers with floating point numbers. Need to use a signed number. This shouldn't effect anything in practice. */ - *pCursor = (ma_int64)cursorInPCMFrames / (float)sampleRate; - - return MA_SUCCESS; -} - -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* The notion of a sound length is only valid for sounds that are backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_INVALID_OPERATION; - } - - return ma_data_source_get_length_in_seconds(pSound->pDataSource, pLength); -} - -MA_API ma_result ma_sound_set_end_callback(ma_sound* pSound, ma_sound_end_proc callback, void* pUserData) -{ - if (pSound == NULL) { - return MA_INVALID_ARGS; - } - - /* The notion of an end is only valid for sounds that are backed by a data source. */ - if (pSound->pDataSource == NULL) { - return MA_INVALID_OPERATION; - } - - pSound->endCallback = callback; - pSound->pEndCallbackUserData = pUserData; - - return MA_SUCCESS; -} - - -MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup) -{ - ma_sound_group_config config = ma_sound_group_config_init_2(pEngine); - config.flags = flags; - config.pInitialAttachment = pParentGroup; - return ma_sound_group_init_ex(pEngine, &config, pGroup); -} - -MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup) -{ - ma_sound_config soundConfig; - - if (pGroup == NULL) { - return MA_INVALID_ARGS; - } - - MA_ZERO_OBJECT(pGroup); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - /* A sound group is just a sound without a data source. */ - soundConfig = *pConfig; - soundConfig.pFilePath = NULL; - soundConfig.pFilePathW = NULL; - soundConfig.pDataSource = NULL; - - /* - Groups need to have spatialization disabled by default because I think it'll be pretty rare - that programs will want to spatialize groups (but not unheard of). Certainly it feels like - disabling this by default feels like the right option. Spatialization can be enabled with a - call to ma_sound_group_set_spatialization_enabled(). - */ - soundConfig.flags |= MA_SOUND_FLAG_NO_SPATIALIZATION; - - return ma_sound_init_ex(pEngine, &soundConfig, pGroup); -} - -MA_API void ma_sound_group_uninit(ma_sound_group* pGroup) -{ - ma_sound_uninit(pGroup); -} - -MA_API ma_engine* ma_sound_group_get_engine(const ma_sound_group* pGroup) -{ - return ma_sound_get_engine(pGroup); -} - -MA_API ma_result ma_sound_group_start(ma_sound_group* pGroup) -{ - return ma_sound_start(pGroup); -} - -MA_API ma_result ma_sound_group_stop(ma_sound_group* pGroup) -{ - return ma_sound_stop(pGroup); -} - -MA_API void ma_sound_group_set_volume(ma_sound_group* pGroup, float volume) -{ - ma_sound_set_volume(pGroup, volume); -} - -MA_API float ma_sound_group_get_volume(const ma_sound_group* pGroup) -{ - return ma_sound_get_volume(pGroup); -} - -MA_API void ma_sound_group_set_pan(ma_sound_group* pGroup, float pan) -{ - ma_sound_set_pan(pGroup, pan); -} - -MA_API float ma_sound_group_get_pan(const ma_sound_group* pGroup) -{ - return ma_sound_get_pan(pGroup); -} - -MA_API void ma_sound_group_set_pan_mode(ma_sound_group* pGroup, ma_pan_mode panMode) -{ - ma_sound_set_pan_mode(pGroup, panMode); -} - -MA_API ma_pan_mode ma_sound_group_get_pan_mode(const ma_sound_group* pGroup) -{ - return ma_sound_get_pan_mode(pGroup); -} - -MA_API void ma_sound_group_set_pitch(ma_sound_group* pGroup, float pitch) -{ - ma_sound_set_pitch(pGroup, pitch); -} - -MA_API float ma_sound_group_get_pitch(const ma_sound_group* pGroup) -{ - return ma_sound_get_pitch(pGroup); -} - -MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma_bool32 enabled) -{ - ma_sound_set_spatialization_enabled(pGroup, enabled); -} - -MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup) -{ - return ma_sound_is_spatialization_enabled(pGroup); -} - -MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex) -{ - ma_sound_set_pinned_listener_index(pGroup, listenerIndex); -} - -MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup) -{ - return ma_sound_get_pinned_listener_index(pGroup); -} - -MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup) -{ - return ma_sound_get_listener_index(pGroup); -} - -MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup) -{ - return ma_sound_get_direction_to_listener(pGroup); -} - -MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z) -{ - ma_sound_set_position(pGroup, x, y, z); -} - -MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup) -{ - return ma_sound_get_position(pGroup); -} - -MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z) -{ - ma_sound_set_direction(pGroup, x, y, z); -} - -MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup) -{ - return ma_sound_get_direction(pGroup); -} - -MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z) -{ - ma_sound_set_velocity(pGroup, x, y, z); -} - -MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup) -{ - return ma_sound_get_velocity(pGroup); -} - -MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel) -{ - ma_sound_set_attenuation_model(pGroup, attenuationModel); -} - -MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup) -{ - return ma_sound_get_attenuation_model(pGroup); -} - -MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning) -{ - ma_sound_set_positioning(pGroup, positioning); -} - -MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup) -{ - return ma_sound_get_positioning(pGroup); -} - -MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff) -{ - ma_sound_set_rolloff(pGroup, rolloff); -} - -MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup) -{ - return ma_sound_get_rolloff(pGroup); -} - -MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain) -{ - ma_sound_set_min_gain(pGroup, minGain); -} - -MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup) -{ - return ma_sound_get_min_gain(pGroup); -} - -MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain) -{ - ma_sound_set_max_gain(pGroup, maxGain); -} - -MA_API float ma_sound_group_get_max_gain(const ma_sound_group* pGroup) -{ - return ma_sound_get_max_gain(pGroup); -} - -MA_API void ma_sound_group_set_min_distance(ma_sound_group* pGroup, float minDistance) -{ - ma_sound_set_min_distance(pGroup, minDistance); -} - -MA_API float ma_sound_group_get_min_distance(const ma_sound_group* pGroup) -{ - return ma_sound_get_min_distance(pGroup); -} - -MA_API void ma_sound_group_set_max_distance(ma_sound_group* pGroup, float maxDistance) -{ - ma_sound_set_max_distance(pGroup, maxDistance); -} - -MA_API float ma_sound_group_get_max_distance(const ma_sound_group* pGroup) -{ - return ma_sound_get_max_distance(pGroup); -} - -MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRadians, float outerAngleInRadians, float outerGain) -{ - ma_sound_set_cone(pGroup, innerAngleInRadians, outerAngleInRadians, outerGain); -} - -MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) -{ - ma_sound_get_cone(pGroup, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); -} - -MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor) -{ - ma_sound_set_doppler_factor(pGroup, dopplerFactor); -} - -MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup) -{ - return ma_sound_get_doppler_factor(pGroup); -} - -MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor) -{ - ma_sound_set_directional_attenuation_factor(pGroup, directionalAttenuationFactor); -} - -MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup) -{ - return ma_sound_get_directional_attenuation_factor(pGroup); -} - -MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames) -{ - ma_sound_set_fade_in_pcm_frames(pGroup, volumeBeg, volumeEnd, fadeLengthInFrames); -} - -MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds) -{ - ma_sound_set_fade_in_milliseconds(pGroup, volumeBeg, volumeEnd, fadeLengthInMilliseconds); -} - -MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup) -{ - return ma_sound_get_current_fade_volume(pGroup); -} - -MA_API void ma_sound_group_set_start_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames) -{ - ma_sound_set_start_time_in_pcm_frames(pGroup, absoluteGlobalTimeInFrames); -} - -MA_API void ma_sound_group_set_start_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds) -{ - ma_sound_set_start_time_in_milliseconds(pGroup, absoluteGlobalTimeInMilliseconds); -} - -MA_API void ma_sound_group_set_stop_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames) -{ - ma_sound_set_stop_time_in_pcm_frames(pGroup, absoluteGlobalTimeInFrames); -} - -MA_API void ma_sound_group_set_stop_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds) -{ - ma_sound_set_stop_time_in_milliseconds(pGroup, absoluteGlobalTimeInMilliseconds); -} - -MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup) -{ - return ma_sound_is_playing(pGroup); -} - -MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup) -{ - return ma_sound_get_time_in_pcm_frames(pGroup); -} -#endif /* MA_NO_ENGINE */ -/* END SECTION: miniaudio_engine.c */ - - - /************************************************************************************************************************************************************** *************************************************************************************************************************************************************** Auto Generated ============== -All code below is auto-generated from a tool. This mostly consists of decoding backend implementations such as ma_dr_wav, ma_dr_flac, etc. If you find a bug in the +All code below is auto-generated from a tool. This mostly consists of decoding backend implementations such as dr_wav, dr_flac, etc. If you find a bug in the code below please report the bug to the respective repository for the relevant project (probably dr_libs). *************************************************************************************************************************************************************** **************************************************************************************************************************************************************/ #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)) -#if !defined(MA_DR_WAV_IMPLEMENTATION) +#if !defined(DR_WAV_IMPLEMENTATION) && !defined(DRWAV_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */ /* dr_wav_c begin */ -#ifndef ma_dr_wav_c -#define ma_dr_wav_c -#ifdef __MRC__ -#pragma options opt off -#endif +#ifndef dr_wav_c +#define dr_wav_c #include #include #include -#ifndef MA_DR_WAV_NO_STDIO +#ifndef DR_WAV_NO_STDIO #include -#ifndef MA_DR_WAV_NO_WCHAR #include #endif -#endif -#ifndef MA_DR_WAV_ASSERT +#ifndef DRWAV_ASSERT #include -#define MA_DR_WAV_ASSERT(expression) assert(expression) +#define DRWAV_ASSERT(expression) assert(expression) #endif -#ifndef MA_DR_WAV_MALLOC -#define MA_DR_WAV_MALLOC(sz) malloc((sz)) +#ifndef DRWAV_MALLOC +#define DRWAV_MALLOC(sz) malloc((sz)) #endif -#ifndef MA_DR_WAV_REALLOC -#define MA_DR_WAV_REALLOC(p, sz) realloc((p), (sz)) +#ifndef DRWAV_REALLOC +#define DRWAV_REALLOC(p, sz) realloc((p), (sz)) #endif -#ifndef MA_DR_WAV_FREE -#define MA_DR_WAV_FREE(p) free((p)) +#ifndef DRWAV_FREE +#define DRWAV_FREE(p) free((p)) #endif -#ifndef MA_DR_WAV_COPY_MEMORY -#define MA_DR_WAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#ifndef DRWAV_COPY_MEMORY +#define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) #endif -#ifndef MA_DR_WAV_ZERO_MEMORY -#define MA_DR_WAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#ifndef DRWAV_ZERO_MEMORY +#define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif -#ifndef MA_DR_WAV_ZERO_OBJECT -#define MA_DR_WAV_ZERO_OBJECT(p) MA_DR_WAV_ZERO_MEMORY((p), sizeof(*p)) +#ifndef DRWAV_ZERO_OBJECT +#define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p)) +#endif +#define drwav_countof(x) (sizeof(x) / sizeof(x[0])) +#define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) +#define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) +#define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) +#define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) +#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 +#if defined(__x86_64__) || defined(_M_X64) + #define DRWAV_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRWAV_X86 +#elif defined(__arm__) || defined(_M_ARM) + #define DRWAV_ARM +#endif +#ifdef _MSC_VER + #define DRWAV_INLINE __forceinline +#elif defined(__GNUC__) + #if defined(__STRICT_ANSI__) + #define DRWAV_INLINE __inline__ __attribute__((always_inline)) + #else + #define DRWAV_INLINE inline __attribute__((always_inline)) + #endif +#elif defined(__WATCOMC__) + #define DRWAV_INLINE __inline +#else + #define DRWAV_INLINE +#endif +#if defined(SIZE_MAX) + #define DRWAV_SIZE_MAX SIZE_MAX +#else + #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) + #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRWAV_SIZE_MAX 0xFFFFFFFF + #endif #endif -#define ma_dr_wav_countof(x) (sizeof(x) / sizeof(x[0])) -#define ma_dr_wav_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) -#define ma_dr_wav_min(a, b) (((a) < (b)) ? (a) : (b)) -#define ma_dr_wav_max(a, b) (((a) > (b)) ? (a) : (b)) -#define ma_dr_wav_clamp(x, lo, hi) (ma_dr_wav_max((lo), ma_dr_wav_min((hi), (x)))) -#define ma_dr_wav_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset)) -#define MA_DR_WAV_MAX_SIMD_VECTOR_SIZE 32 -#define MA_DR_WAV_INT64_MIN ((ma_int64) ((ma_uint64)0x80000000 << 32)) -#define MA_DR_WAV_INT64_MAX ((ma_int64)(((ma_uint64)0x7FFFFFFF << 32) | 0xFFFFFFFF)) #if defined(_MSC_VER) && _MSC_VER >= 1400 - #define MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC - #define MA_DR_WAV_HAS_BYTESWAP32_INTRINSIC - #define MA_DR_WAV_HAS_BYTESWAP64_INTRINSIC + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC #elif defined(__clang__) #if defined(__has_builtin) #if __has_builtin(__builtin_bswap16) - #define MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC + #define DRWAV_HAS_BYTESWAP16_INTRINSIC #endif #if __has_builtin(__builtin_bswap32) - #define MA_DR_WAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP32_INTRINSIC #endif #if __has_builtin(__builtin_bswap64) - #define MA_DR_WAV_HAS_BYTESWAP64_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC #endif #endif #elif defined(__GNUC__) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define MA_DR_WAV_HAS_BYTESWAP32_INTRINSIC - #define MA_DR_WAV_HAS_BYTESWAP64_INTRINSIC + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC #endif #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #define MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC + #define DRWAV_HAS_BYTESWAP16_INTRINSIC #endif #endif -MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision) +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision) { if (pMajor) { - *pMajor = MA_DR_WAV_VERSION_MAJOR; + *pMajor = DRWAV_VERSION_MAJOR; } if (pMinor) { - *pMinor = MA_DR_WAV_VERSION_MINOR; + *pMinor = DRWAV_VERSION_MINOR; } if (pRevision) { - *pRevision = MA_DR_WAV_VERSION_REVISION; + *pRevision = DRWAV_VERSION_REVISION; } } -MA_API const char* ma_dr_wav_version_string(void) +DRWAV_API const char* drwav_version_string(void) { - return MA_DR_WAV_VERSION_STRING; + return DRWAV_VERSION_STRING; } -#ifndef MA_DR_WAV_MAX_SAMPLE_RATE -#define MA_DR_WAV_MAX_SAMPLE_RATE 384000 +#ifndef DRWAV_MAX_SAMPLE_RATE +#define DRWAV_MAX_SAMPLE_RATE 384000 #endif -#ifndef MA_DR_WAV_MAX_CHANNELS -#define MA_DR_WAV_MAX_CHANNELS 256 +#ifndef DRWAV_MAX_CHANNELS +#define DRWAV_MAX_CHANNELS 256 #endif -#ifndef MA_DR_WAV_MAX_BITS_PER_SAMPLE -#define MA_DR_WAV_MAX_BITS_PER_SAMPLE 64 +#ifndef DRWAV_MAX_BITS_PER_SAMPLE +#define DRWAV_MAX_BITS_PER_SAMPLE 64 #endif -static const ma_uint8 ma_dr_wavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; -static const ma_uint8 ma_dr_wavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; -static const ma_uint8 ma_dr_wavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; -static const ma_uint8 ma_dr_wavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; -static const ma_uint8 ma_dr_wavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; -static MA_INLINE int ma_dr_wav__is_little_endian(void) +static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; +static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; +static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; +static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; +static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; +static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; +static DRWAV_INLINE int drwav__is_little_endian(void) { -#if defined(MA_X86) || defined(MA_X64) - return MA_TRUE; +#if defined(DRWAV_X86) || defined(DRWAV_X64) + return DRWAV_TRUE; #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN - return MA_TRUE; + return DRWAV_TRUE; #else int n = 1; return (*(char*)&n) == 1; #endif } -static MA_INLINE void ma_dr_wav_bytes_to_guid(const ma_uint8* data, ma_uint8* guid) +static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) { int i; for (i = 0; i < 16; ++i) { guid[i] = data[i]; } } -static MA_INLINE ma_uint16 ma_dr_wav__bswap16(ma_uint16 n) +static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n) { -#ifdef MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC +#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC #if defined(_MSC_VER) return _byteswap_ushort(n); #elif defined(__GNUC__) || defined(__clang__) @@ -78206,16 +49190,16 @@ static MA_INLINE ma_uint16 ma_dr_wav__bswap16(ma_uint16 n) ((n & 0x00FF) << 8); #endif } -static MA_INLINE ma_uint32 ma_dr_wav__bswap32(ma_uint32 n) +static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n) { -#ifdef MA_DR_WAV_HAS_BYTESWAP32_INTRINSIC +#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC #if defined(_MSC_VER) return _byteswap_ulong(n); #elif defined(__GNUC__) || defined(__clang__) - #if defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(MA_64BIT) - ma_uint32 r; + #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT) + drwav_uint32 r; __asm__ __volatile__ ( - #if defined(MA_64BIT) + #if defined(DRWAV_64BIT) "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) #else "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) @@ -78235,9 +49219,9 @@ static MA_INLINE ma_uint32 ma_dr_wav__bswap32(ma_uint32 n) ((n & 0x000000FF) << 24); #endif } -static MA_INLINE ma_uint64 ma_dr_wav__bswap64(ma_uint64 n) +static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n) { -#ifdef MA_DR_WAV_HAS_BYTESWAP64_INTRINSIC +#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC #if defined(_MSC_VER) return _byteswap_uint64(n); #elif defined(__GNUC__) || defined(__clang__) @@ -78246,192 +49230,174 @@ static MA_INLINE ma_uint64 ma_dr_wav__bswap64(ma_uint64 n) #error "This compiler does not support the byte swap intrinsic." #endif #else - return ((n & ((ma_uint64)0xFF000000 << 32)) >> 56) | - ((n & ((ma_uint64)0x00FF0000 << 32)) >> 40) | - ((n & ((ma_uint64)0x0000FF00 << 32)) >> 24) | - ((n & ((ma_uint64)0x000000FF << 32)) >> 8) | - ((n & ((ma_uint64)0xFF000000 )) << 8) | - ((n & ((ma_uint64)0x00FF0000 )) << 24) | - ((n & ((ma_uint64)0x0000FF00 )) << 40) | - ((n & ((ma_uint64)0x000000FF )) << 56); + return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) | + ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) | + ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) | + ((n & ((drwav_uint64)0x000000FF << 32)) >> 8) | + ((n & ((drwav_uint64)0xFF000000 )) << 8) | + ((n & ((drwav_uint64)0x00FF0000 )) << 24) | + ((n & ((drwav_uint64)0x0000FF00 )) << 40) | + ((n & ((drwav_uint64)0x000000FF )) << 56); #endif } -static MA_INLINE ma_int16 ma_dr_wav__bswap_s16(ma_int16 n) +static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n) { - return (ma_int16)ma_dr_wav__bswap16((ma_uint16)n); + return (drwav_int16)drwav__bswap16((drwav_uint16)n); } -static MA_INLINE void ma_dr_wav__bswap_samples_s16(ma_int16* pSamples, ma_uint64 sampleCount) +static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount) { - ma_uint64 iSample; + drwav_uint64 iSample; for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamples[iSample] = ma_dr_wav__bswap_s16(pSamples[iSample]); + pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]); } } -static MA_INLINE void ma_dr_wav__bswap_s24(ma_uint8* p) +static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p) { - ma_uint8 t; + drwav_uint8 t; t = p[0]; p[0] = p[2]; p[2] = t; } -static MA_INLINE void ma_dr_wav__bswap_samples_s24(ma_uint8* pSamples, ma_uint64 sampleCount) +static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount) { - ma_uint64 iSample; + drwav_uint64 iSample; for (iSample = 0; iSample < sampleCount; iSample += 1) { - ma_uint8* pSample = pSamples + (iSample*3); - ma_dr_wav__bswap_s24(pSample); + drwav_uint8* pSample = pSamples + (iSample*3); + drwav__bswap_s24(pSample); } } -static MA_INLINE ma_int32 ma_dr_wav__bswap_s32(ma_int32 n) +static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n) { - return (ma_int32)ma_dr_wav__bswap32((ma_uint32)n); + return (drwav_int32)drwav__bswap32((drwav_uint32)n); } -static MA_INLINE void ma_dr_wav__bswap_samples_s32(ma_int32* pSamples, ma_uint64 sampleCount) +static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount) { - ma_uint64 iSample; + drwav_uint64 iSample; for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamples[iSample] = ma_dr_wav__bswap_s32(pSamples[iSample]); + pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]); } } -static MA_INLINE ma_int64 ma_dr_wav__bswap_s64(ma_int64 n) -{ - return (ma_int64)ma_dr_wav__bswap64((ma_uint64)n); -} -static MA_INLINE void ma_dr_wav__bswap_samples_s64(ma_int64* pSamples, ma_uint64 sampleCount) -{ - ma_uint64 iSample; - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamples[iSample] = ma_dr_wav__bswap_s64(pSamples[iSample]); - } -} -static MA_INLINE float ma_dr_wav__bswap_f32(float n) +static DRWAV_INLINE float drwav__bswap_f32(float n) { union { - ma_uint32 i; + drwav_uint32 i; float f; } x; x.f = n; - x.i = ma_dr_wav__bswap32(x.i); + x.i = drwav__bswap32(x.i); return x.f; } -static MA_INLINE void ma_dr_wav__bswap_samples_f32(float* pSamples, ma_uint64 sampleCount) +static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount) { - ma_uint64 iSample; + drwav_uint64 iSample; for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamples[iSample] = ma_dr_wav__bswap_f32(pSamples[iSample]); + pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]); } } -static MA_INLINE void ma_dr_wav__bswap_samples(void* pSamples, ma_uint64 sampleCount, ma_uint32 bytesPerSample) +static DRWAV_INLINE double drwav__bswap_f64(double n) +{ + union { + drwav_uint64 i; + double f; + } x; + x.f = n; + x.i = drwav__bswap64(x.i); + return x.f; +} +static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]); + } +} +static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) { switch (bytesPerSample) { - case 1: - { - } break; case 2: { - ma_dr_wav__bswap_samples_s16((ma_int16*)pSamples, sampleCount); + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); } break; case 3: { - ma_dr_wav__bswap_samples_s24((ma_uint8*)pSamples, sampleCount); + drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount); } break; case 4: { - ma_dr_wav__bswap_samples_s32((ma_int32*)pSamples, sampleCount); - } break; - case 8: - { - ma_dr_wav__bswap_samples_s64((ma_int64*)pSamples, sampleCount); + drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount); } break; default: { - MA_DR_WAV_ASSERT(MA_FALSE); + DRWAV_ASSERT(DRWAV_FALSE); } break; } } -MA_PRIVATE MA_INLINE ma_bool32 ma_dr_wav_is_container_be(ma_dr_wav_container container) +static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) { - if (container == ma_dr_wav_container_rifx || container == ma_dr_wav_container_aiff) { - return MA_TRUE; - } else { - return MA_FALSE; + switch (bytesPerSample) + { + #if 0 + case 2: + { + drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount); + } break; + #endif + case 4: + { + drwav__bswap_samples_f32((float*)pSamples, sampleCount); + } break; + case 8: + { + drwav__bswap_samples_f64((double*)pSamples, sampleCount); + } break; + default: + { + DRWAV_ASSERT(DRWAV_FALSE); + } break; } } -MA_PRIVATE MA_INLINE ma_uint16 ma_dr_wav_bytes_to_u16_le(const ma_uint8* data) +static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format) { - return ((ma_uint16)data[0] << 0) | ((ma_uint16)data[1] << 8); -} -MA_PRIVATE MA_INLINE ma_uint16 ma_dr_wav_bytes_to_u16_be(const ma_uint8* data) -{ - return ((ma_uint16)data[1] << 0) | ((ma_uint16)data[0] << 8); -} -MA_PRIVATE MA_INLINE ma_uint16 ma_dr_wav_bytes_to_u16_ex(const ma_uint8* data, ma_dr_wav_container container) -{ - if (ma_dr_wav_is_container_be(container)) { - return ma_dr_wav_bytes_to_u16_be(data); - } else { - return ma_dr_wav_bytes_to_u16_le(data); + switch (format) + { + case DR_WAVE_FORMAT_PCM: + { + drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample); + } break; + case DR_WAVE_FORMAT_IEEE_FLOAT: + { + drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample); + } break; + case DR_WAVE_FORMAT_ALAW: + case DR_WAVE_FORMAT_MULAW: + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; + case DR_WAVE_FORMAT_ADPCM: + case DR_WAVE_FORMAT_DVI_ADPCM: + default: + { + DRWAV_ASSERT(DRWAV_FALSE); + } break; } } -MA_PRIVATE MA_INLINE ma_uint32 ma_dr_wav_bytes_to_u32_le(const ma_uint8* data) -{ - return ((ma_uint32)data[0] << 0) | ((ma_uint32)data[1] << 8) | ((ma_uint32)data[2] << 16) | ((ma_uint32)data[3] << 24); -} -MA_PRIVATE MA_INLINE ma_uint32 ma_dr_wav_bytes_to_u32_be(const ma_uint8* data) -{ - return ((ma_uint32)data[3] << 0) | ((ma_uint32)data[2] << 8) | ((ma_uint32)data[1] << 16) | ((ma_uint32)data[0] << 24); -} -MA_PRIVATE MA_INLINE ma_uint32 ma_dr_wav_bytes_to_u32_ex(const ma_uint8* data, ma_dr_wav_container container) -{ - if (ma_dr_wav_is_container_be(container)) { - return ma_dr_wav_bytes_to_u32_be(data); - } else { - return ma_dr_wav_bytes_to_u32_le(data); - } -} -MA_PRIVATE ma_int64 ma_dr_wav_aiff_extented_to_s64(const ma_uint8* data) -{ - ma_uint32 exponent = ((ma_uint32)data[0] << 8) | data[1]; - ma_uint64 hi = ((ma_uint64)data[2] << 24) | ((ma_uint64)data[3] << 16) | ((ma_uint64)data[4] << 8) | ((ma_uint64)data[5] << 0); - ma_uint64 lo = ((ma_uint64)data[6] << 24) | ((ma_uint64)data[7] << 16) | ((ma_uint64)data[8] << 8) | ((ma_uint64)data[9] << 0); - ma_uint64 significand = (hi << 32) | lo; - int sign = exponent >> 15; - exponent &= 0x7FFF; - if (exponent == 0 && significand == 0) { - return 0; - } else if (exponent == 0x7FFF) { - return sign ? MA_DR_WAV_INT64_MIN : MA_DR_WAV_INT64_MAX; - } - exponent -= 16383; - if (exponent > 63) { - return sign ? MA_DR_WAV_INT64_MIN : MA_DR_WAV_INT64_MAX; - } else if (exponent < 1) { - return 0; - } - significand >>= (63 - exponent); - if (sign) { - return -(ma_int64)significand; - } else { - return (ma_int64)significand; - } -} -MA_PRIVATE void* ma_dr_wav__malloc_default(size_t sz, void* pUserData) +DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData) { (void)pUserData; - return MA_DR_WAV_MALLOC(sz); + return DRWAV_MALLOC(sz); } -MA_PRIVATE void* ma_dr_wav__realloc_default(void* p, size_t sz, void* pUserData) +DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData) { (void)pUserData; - return MA_DR_WAV_REALLOC(p, sz); + return DRWAV_REALLOC(p, sz); } -MA_PRIVATE void ma_dr_wav__free_default(void* p, void* pUserData) +DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData) { (void)pUserData; - MA_DR_WAV_FREE(p); + DRWAV_FREE(p); } -MA_PRIVATE void* ma_dr_wav__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks == NULL) { return NULL; @@ -78444,7 +49410,7 @@ MA_PRIVATE void* ma_dr_wav__malloc_from_callbacks(size_t sz, const ma_allocation } return NULL; } -MA_PRIVATE void* ma_dr_wav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks == NULL) { return NULL; @@ -78459,14 +49425,14 @@ MA_PRIVATE void* ma_dr_wav__realloc_from_callbacks(void* p, size_t szNew, size_t return NULL; } if (p != NULL) { - MA_DR_WAV_COPY_MEMORY(p2, p, szOld); + DRWAV_COPY_MEMORY(p2, p, szOld); pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } return p2; } return NULL; } -MA_PRIVATE void ma_dr_wav__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) { if (p == NULL || pAllocationCallbacks == NULL) { return; @@ -78475,1322 +49441,485 @@ MA_PRIVATE void ma_dr_wav__free_from_callbacks(void* p, const ma_allocation_call pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -MA_PRIVATE ma_allocation_callbacks ma_dr_wav_copy_allocation_callbacks_or_defaults(const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { return *pAllocationCallbacks; } else { - ma_allocation_callbacks allocationCallbacks; + drwav_allocation_callbacks allocationCallbacks; allocationCallbacks.pUserData = NULL; - allocationCallbacks.onMalloc = ma_dr_wav__malloc_default; - allocationCallbacks.onRealloc = ma_dr_wav__realloc_default; - allocationCallbacks.onFree = ma_dr_wav__free_default; + allocationCallbacks.onMalloc = drwav__malloc_default; + allocationCallbacks.onRealloc = drwav__realloc_default; + allocationCallbacks.onFree = drwav__free_default; return allocationCallbacks; } } -static MA_INLINE ma_bool32 ma_dr_wav__is_compressed_format_tag(ma_uint16 formatTag) +static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag) { return - formatTag == MA_DR_WAVE_FORMAT_ADPCM || - formatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM; + formatTag == DR_WAVE_FORMAT_ADPCM || + formatTag == DR_WAVE_FORMAT_DVI_ADPCM; } -MA_PRIVATE unsigned int ma_dr_wav__chunk_padding_size_riff(ma_uint64 chunkSize) +DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize) { return (unsigned int)(chunkSize % 2); } -MA_PRIVATE unsigned int ma_dr_wav__chunk_padding_size_w64(ma_uint64 chunkSize) +DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize) { return (unsigned int)(chunkSize % 8); } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 samplesToRead, ma_int16* pBufferOut); -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint64 samplesToRead, ma_int16* pBufferOut); -MA_PRIVATE ma_bool32 ma_dr_wav_init_write__internal(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount); -MA_PRIVATE ma_result ma_dr_wav__read_chunk_header(ma_dr_wav_read_proc onRead, void* pUserData, ma_dr_wav_container container, ma_uint64* pRunningBytesReadOut, ma_dr_wav_chunk_header* pHeaderOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); +DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut) { - if (container == ma_dr_wav_container_riff || container == ma_dr_wav_container_rifx || container == ma_dr_wav_container_rf64 || container == ma_dr_wav_container_aiff) { - ma_uint8 sizeInBytes[4]; + if (container == drwav_container_riff || container == drwav_container_rf64) { + drwav_uint8 sizeInBytes[4]; if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { - return MA_AT_END; + return DRWAV_AT_END; } if (onRead(pUserData, sizeInBytes, 4) != 4) { - return MA_INVALID_FILE; + return DRWAV_INVALID_FILE; } - pHeaderOut->sizeInBytes = ma_dr_wav_bytes_to_u32_ex(sizeInBytes, container); - pHeaderOut->paddingSize = ma_dr_wav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); + pHeaderOut->sizeInBytes = drwav_bytes_to_u32(sizeInBytes); + pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); *pRunningBytesReadOut += 8; - } else if (container == ma_dr_wav_container_w64) { - ma_uint8 sizeInBytes[8]; + } else { + drwav_uint8 sizeInBytes[8]; if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { - return MA_AT_END; + return DRWAV_AT_END; } if (onRead(pUserData, sizeInBytes, 8) != 8) { - return MA_INVALID_FILE; + return DRWAV_INVALID_FILE; } - pHeaderOut->sizeInBytes = ma_dr_wav_bytes_to_u64(sizeInBytes) - 24; - pHeaderOut->paddingSize = ma_dr_wav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); + pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24; + pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); *pRunningBytesReadOut += 24; - } else { - return MA_INVALID_FILE; } - return MA_SUCCESS; + return DRWAV_SUCCESS; } -MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) +DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) { - ma_uint64 bytesRemainingToSeek = offset; + drwav_uint64 bytesRemainingToSeek = offset; while (bytesRemainingToSeek > 0) { if (bytesRemainingToSeek > 0x7FFFFFFF) { - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; } bytesRemainingToSeek -= 0x7FFFFFFF; } else { - if (!onSeek(pUserData, (int)bytesRemainingToSeek, ma_dr_wav_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) { + return DRWAV_FALSE; } bytesRemainingToSeek = 0; } } - return MA_TRUE; + return DRWAV_TRUE; } -MA_PRIVATE ma_bool32 ma_dr_wav__seek_from_start(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) +DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_start); + return onSeek(pUserData, (int)offset, drwav_seek_origin_start); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_start)) { - return MA_FALSE; + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) { + return DRWAV_FALSE; } offset -= 0x7FFFFFFF; for (;;) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_current); + return onSeek(pUserData, (int)offset, drwav_seek_origin_current); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; } offset -= 0x7FFFFFFF; } } -MA_PRIVATE size_t ma_dr_wav__on_read(ma_dr_wav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, ma_uint64* pCursor) +DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) +{ + drwav_chunk_header header; + drwav_uint8 fmt[16]; + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav_fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) { + if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + } + if (container == drwav_container_riff || container == drwav_container_rf64) { + if (!drwav_fourcc_equal(header.id.fourcc, "fmt ")) { + return DRWAV_FALSE; + } + } else { + if (!drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT)) { + return DRWAV_FALSE; + } + } + if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += sizeof(fmt); + fmtOut->formatTag = drwav_bytes_to_u16(fmt + 0); + fmtOut->channels = drwav_bytes_to_u16(fmt + 2); + fmtOut->sampleRate = drwav_bytes_to_u32(fmt + 4); + fmtOut->avgBytesPerSec = drwav_bytes_to_u32(fmt + 8); + fmtOut->blockAlign = drwav_bytes_to_u16(fmt + 12); + fmtOut->bitsPerSample = drwav_bytes_to_u16(fmt + 14); + fmtOut->extendedSize = 0; + fmtOut->validBitsPerSample = 0; + fmtOut->channelMask = 0; + memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + if (header.sizeInBytes > 16) { + drwav_uint8 fmt_cbSize[2]; + int bytesReadSoFar = 0; + if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += sizeof(fmt_cbSize); + bytesReadSoFar = 18; + fmtOut->extendedSize = drwav_bytes_to_u16(fmt_cbSize); + if (fmtOut->extendedSize > 0) { + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + if (fmtOut->extendedSize != 22) { + return DRWAV_FALSE; + } + } + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + drwav_uint8 fmtext[22]; + if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { + return DRWAV_FALSE; + } + fmtOut->validBitsPerSample = drwav_bytes_to_u16(fmtext + 0); + fmtOut->channelMask = drwav_bytes_to_u32(fmtext + 2); + drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat); + } else { + if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + } + *pRunningBytesReadOut += fmtOut->extendedSize; + bytesReadSoFar += fmtOut->extendedSize; + } + if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar); + } + if (header.paddingSize > 0) { + if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.paddingSize; + } + return DRWAV_TRUE; +} +DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) { size_t bytesRead; - MA_DR_WAV_ASSERT(onRead != NULL); - MA_DR_WAV_ASSERT(pCursor != NULL); + DRWAV_ASSERT(onRead != NULL); + DRWAV_ASSERT(pCursor != NULL); bytesRead = onRead(pUserData, pBufferOut, bytesToRead); *pCursor += bytesRead; return bytesRead; } #if 0 -MA_PRIVATE ma_bool32 ma_dr_wav__on_seek(ma_dr_wav_seek_proc onSeek, void* pUserData, int offset, ma_dr_wav_seek_origin origin, ma_uint64* pCursor) +DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor) { - MA_DR_WAV_ASSERT(onSeek != NULL); - MA_DR_WAV_ASSERT(pCursor != NULL); + DRWAV_ASSERT(onSeek != NULL); + DRWAV_ASSERT(pCursor != NULL); if (!onSeek(pUserData, offset, origin)) { - return MA_FALSE; + return DRWAV_FALSE; } - if (origin == ma_dr_wav_seek_origin_start) { + if (origin == drwav_seek_origin_start) { *pCursor = offset; } else { *pCursor += offset; } - return MA_TRUE; + return DRWAV_TRUE; } #endif -#define MA_DR_WAV_SMPL_BYTES 36 -#define MA_DR_WAV_SMPL_LOOP_BYTES 24 -#define MA_DR_WAV_INST_BYTES 7 -#define MA_DR_WAV_ACID_BYTES 24 -#define MA_DR_WAV_CUE_BYTES 4 -#define MA_DR_WAV_BEXT_BYTES 602 -#define MA_DR_WAV_BEXT_DESCRIPTION_BYTES 256 -#define MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES 32 -#define MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES 32 -#define MA_DR_WAV_BEXT_RESERVED_BYTES 180 -#define MA_DR_WAV_BEXT_UMID_BYTES 64 -#define MA_DR_WAV_CUE_POINT_BYTES 24 -#define MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES 4 -#define MA_DR_WAV_LIST_LABELLED_TEXT_BYTES 20 -#define MA_DR_WAV_METADATA_ALIGNMENT 8 -typedef enum +DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { - ma_dr_wav__metadata_parser_stage_count, - ma_dr_wav__metadata_parser_stage_read -} ma_dr_wav__metadata_parser_stage; -typedef struct -{ - ma_dr_wav_read_proc onRead; - ma_dr_wav_seek_proc onSeek; - void *pReadSeekUserData; - ma_dr_wav__metadata_parser_stage stage; - ma_dr_wav_metadata *pMetadata; - ma_uint32 metadataCount; - ma_uint8 *pData; - ma_uint8 *pDataCursor; - ma_uint64 metadataCursor; - ma_uint64 extraCapacity; -} ma_dr_wav__metadata_parser; -MA_PRIVATE size_t ma_dr_wav__metadata_memory_capacity(ma_dr_wav__metadata_parser* pParser) -{ - ma_uint64 cap = sizeof(ma_dr_wav_metadata) * (ma_uint64)pParser->metadataCount + pParser->extraCapacity; - if (cap > MA_SIZE_MAX) { - return 0; - } - return (size_t)cap; -} -MA_PRIVATE ma_uint8* ma_dr_wav__metadata_get_memory(ma_dr_wav__metadata_parser* pParser, size_t size, size_t align) -{ - ma_uint8* pResult; - if (align) { - ma_uintptr modulo = (ma_uintptr)pParser->pDataCursor % align; - if (modulo != 0) { - pParser->pDataCursor += align - modulo; - } - } - pResult = pParser->pDataCursor; - MA_DR_WAV_ASSERT((pResult + size) <= (pParser->pData + ma_dr_wav__metadata_memory_capacity(pParser))); - pParser->pDataCursor += size; - return pResult; -} -MA_PRIVATE void ma_dr_wav__metadata_request_extra_memory_for_stage_2(ma_dr_wav__metadata_parser* pParser, size_t bytes, size_t align) -{ - size_t extra = bytes + (align ? (align - 1) : 0); - pParser->extraCapacity += extra; -} -MA_PRIVATE ma_result ma_dr_wav__metadata_alloc(ma_dr_wav__metadata_parser* pParser, ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) { - pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData); - pParser->pData = (ma_uint8*)pAllocationCallbacks->onMalloc(ma_dr_wav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData); - pParser->pDataCursor = pParser->pData; - if (pParser->pData == NULL) { - return MA_OUT_OF_MEMORY; - } - pParser->pMetadata = (ma_dr_wav_metadata*)ma_dr_wav__metadata_get_memory(pParser, sizeof(ma_dr_wav_metadata) * pParser->metadataCount, 1); - pParser->metadataCursor = 0; - } - return MA_SUCCESS; -} -MA_PRIVATE size_t ma_dr_wav__metadata_parser_read(ma_dr_wav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, ma_uint64* pCursor) -{ - if (pCursor != NULL) { - return ma_dr_wav__on_read(pParser->onRead, pParser->pReadSeekUserData, pBufferOut, bytesToRead, pCursor); - } else { - return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead); - } -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_smpl_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_metadata* pMetadata) -{ - ma_uint8 smplHeaderData[MA_DR_WAV_SMPL_BYTES]; - ma_uint64 totalBytesRead = 0; - size_t bytesJustRead; - if (pMetadata == NULL) { - return 0; - } - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - MA_DR_WAV_ASSERT(pChunkHeader != NULL); - if (pMetadata != NULL && bytesJustRead == sizeof(smplHeaderData)) { - ma_uint32 iSampleLoop; - pMetadata->type = ma_dr_wav_metadata_type_smpl; - pMetadata->data.smpl.manufacturerId = ma_dr_wav_bytes_to_u32(smplHeaderData + 0); - pMetadata->data.smpl.productId = ma_dr_wav_bytes_to_u32(smplHeaderData + 4); - pMetadata->data.smpl.samplePeriodNanoseconds = ma_dr_wav_bytes_to_u32(smplHeaderData + 8); - pMetadata->data.smpl.midiUnityNote = ma_dr_wav_bytes_to_u32(smplHeaderData + 12); - pMetadata->data.smpl.midiPitchFraction = ma_dr_wav_bytes_to_u32(smplHeaderData + 16); - pMetadata->data.smpl.smpteFormat = ma_dr_wav_bytes_to_u32(smplHeaderData + 20); - pMetadata->data.smpl.smpteOffset = ma_dr_wav_bytes_to_u32(smplHeaderData + 24); - pMetadata->data.smpl.sampleLoopCount = ma_dr_wav_bytes_to_u32(smplHeaderData + 28); - pMetadata->data.smpl.samplerSpecificDataSizeInBytes = ma_dr_wav_bytes_to_u32(smplHeaderData + 32); - if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - MA_DR_WAV_SMPL_BYTES) / MA_DR_WAV_SMPL_LOOP_BYTES) { - pMetadata->data.smpl.pLoops = (ma_dr_wav_smpl_loop*)ma_dr_wav__metadata_get_memory(pParser, sizeof(ma_dr_wav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, MA_DR_WAV_METADATA_ALIGNMENT); - for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { - ma_uint8 smplLoopData[MA_DR_WAV_SMPL_LOOP_BYTES]; - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); - if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); - } else { - break; - } - } - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - pMetadata->data.smpl.pSamplerSpecificData = ma_dr_wav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); - MA_DR_WAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); - ma_dr_wav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); - } - } - } - return totalBytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_cue_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_metadata* pMetadata) -{ - ma_uint8 cueHeaderSectionData[MA_DR_WAV_CUE_BYTES]; - ma_uint64 totalBytesRead = 0; - size_t bytesJustRead; - if (pMetadata == NULL) { - return 0; - } - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, cueHeaderSectionData, sizeof(cueHeaderSectionData), &totalBytesRead); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - if (bytesJustRead == sizeof(cueHeaderSectionData)) { - pMetadata->type = ma_dr_wav_metadata_type_cue; - pMetadata->data.cue.cuePointCount = ma_dr_wav_bytes_to_u32(cueHeaderSectionData); - if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - MA_DR_WAV_CUE_BYTES) / MA_DR_WAV_CUE_POINT_BYTES) { - pMetadata->data.cue.pCuePoints = (ma_dr_wav_cue_point*)ma_dr_wav__metadata_get_memory(pParser, sizeof(ma_dr_wav_cue_point) * pMetadata->data.cue.cuePointCount, MA_DR_WAV_METADATA_ALIGNMENT); - MA_DR_WAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - if (pMetadata->data.cue.cuePointCount > 0) { - ma_uint32 iCuePoint; - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - ma_uint8 cuePointData[MA_DR_WAV_CUE_POINT_BYTES]; - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); - if (bytesJustRead == sizeof(cuePointData)) { - pMetadata->data.cue.pCuePoints[iCuePoint].id = ma_dr_wav_bytes_to_u32(cuePointData + 0); - pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = ma_dr_wav_bytes_to_u32(cuePointData + 4); - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; - pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = ma_dr_wav_bytes_to_u32(cuePointData + 12); - pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = ma_dr_wav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); - } else { - break; - } - } - } - } - } - return totalBytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_inst_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, ma_dr_wav_metadata* pMetadata) -{ - ma_uint8 instData[MA_DR_WAV_INST_BYTES]; - ma_uint64 bytesRead; - if (pMetadata == NULL) { - return 0; - } - bytesRead = ma_dr_wav__metadata_parser_read(pParser, instData, sizeof(instData), NULL); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - if (bytesRead == sizeof(instData)) { - pMetadata->type = ma_dr_wav_metadata_type_inst; - pMetadata->data.inst.midiUnityNote = (ma_int8)instData[0]; - pMetadata->data.inst.fineTuneCents = (ma_int8)instData[1]; - pMetadata->data.inst.gainDecibels = (ma_int8)instData[2]; - pMetadata->data.inst.lowNote = (ma_int8)instData[3]; - pMetadata->data.inst.highNote = (ma_int8)instData[4]; - pMetadata->data.inst.lowVelocity = (ma_int8)instData[5]; - pMetadata->data.inst.highVelocity = (ma_int8)instData[6]; - } - return bytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_acid_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, ma_dr_wav_metadata* pMetadata) -{ - ma_uint8 acidData[MA_DR_WAV_ACID_BYTES]; - ma_uint64 bytesRead; - if (pMetadata == NULL) { - return 0; - } - bytesRead = ma_dr_wav__metadata_parser_read(pParser, acidData, sizeof(acidData), NULL); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - if (bytesRead == sizeof(acidData)) { - pMetadata->type = ma_dr_wav_metadata_type_acid; - pMetadata->data.acid.flags = ma_dr_wav_bytes_to_u32(acidData + 0); - pMetadata->data.acid.midiUnityNote = ma_dr_wav_bytes_to_u16(acidData + 4); - pMetadata->data.acid.reserved1 = ma_dr_wav_bytes_to_u16(acidData + 6); - pMetadata->data.acid.reserved2 = ma_dr_wav_bytes_to_f32(acidData + 8); - pMetadata->data.acid.numBeats = ma_dr_wav_bytes_to_u32(acidData + 12); - pMetadata->data.acid.meterDenominator = ma_dr_wav_bytes_to_u16(acidData + 16); - pMetadata->data.acid.meterNumerator = ma_dr_wav_bytes_to_u16(acidData + 18); - pMetadata->data.acid.tempo = ma_dr_wav_bytes_to_f32(acidData + 20); - } - return bytesRead; -} -MA_PRIVATE size_t ma_dr_wav__strlen(const char* str) -{ - size_t result = 0; - while (*str++) { - result += 1; - } - return result; -} -MA_PRIVATE size_t ma_dr_wav__strlen_clamped(const char* str, size_t maxToRead) -{ - size_t result = 0; - while (*str++ && result < maxToRead) { - result += 1; - } - return result; -} -MA_PRIVATE char* ma_dr_wav__metadata_copy_string(ma_dr_wav__metadata_parser* pParser, const char* str, size_t maxToRead) -{ - size_t len = ma_dr_wav__strlen_clamped(str, maxToRead); - if (len) { - char* result = (char*)ma_dr_wav__metadata_get_memory(pParser, len + 1, 1); - MA_DR_WAV_ASSERT(result != NULL); - MA_DR_WAV_COPY_MEMORY(result, str, len); - result[len] = '\0'; - return result; - } else { - return NULL; - } -} -typedef struct -{ - const void* pBuffer; - size_t sizeInBytes; - size_t cursor; -} ma_dr_wav_buffer_reader; -MA_PRIVATE ma_result ma_dr_wav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, ma_dr_wav_buffer_reader* pReader) -{ - MA_DR_WAV_ASSERT(pBuffer != NULL); - MA_DR_WAV_ASSERT(pReader != NULL); - MA_DR_WAV_ZERO_OBJECT(pReader); - pReader->pBuffer = pBuffer; - pReader->sizeInBytes = sizeInBytes; - pReader->cursor = 0; - return MA_SUCCESS; -} -MA_PRIVATE const void* ma_dr_wav_buffer_reader_ptr(const ma_dr_wav_buffer_reader* pReader) -{ - MA_DR_WAV_ASSERT(pReader != NULL); - return ma_dr_wav_offset_ptr(pReader->pBuffer, pReader->cursor); -} -MA_PRIVATE ma_result ma_dr_wav_buffer_reader_seek(ma_dr_wav_buffer_reader* pReader, size_t bytesToSeek) -{ - MA_DR_WAV_ASSERT(pReader != NULL); - if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) { - return MA_BAD_SEEK; - } - pReader->cursor += bytesToSeek; - return MA_SUCCESS; -} -MA_PRIVATE ma_result ma_dr_wav_buffer_reader_read(ma_dr_wav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead) -{ - ma_result result = MA_SUCCESS; - size_t bytesRemaining; - MA_DR_WAV_ASSERT(pReader != NULL); - if (pBytesRead != NULL) { - *pBytesRead = 0; - } - bytesRemaining = (pReader->sizeInBytes - pReader->cursor); - if (bytesToRead > bytesRemaining) { - bytesToRead = bytesRemaining; - } - if (pDst == NULL) { - result = ma_dr_wav_buffer_reader_seek(pReader, bytesToRead); - } else { - MA_DR_WAV_COPY_MEMORY(pDst, ma_dr_wav_buffer_reader_ptr(pReader), bytesToRead); - pReader->cursor += bytesToRead; - } - MA_DR_WAV_ASSERT(pReader->cursor <= pReader->sizeInBytes); - if (result == MA_SUCCESS) { - if (pBytesRead != NULL) { - *pBytesRead = bytesToRead; - } - } - return MA_SUCCESS; -} -MA_PRIVATE ma_result ma_dr_wav_buffer_reader_read_u16(ma_dr_wav_buffer_reader* pReader, ma_uint16* pDst) -{ - ma_result result; - size_t bytesRead; - ma_uint8 data[2]; - MA_DR_WAV_ASSERT(pReader != NULL); - MA_DR_WAV_ASSERT(pDst != NULL); - *pDst = 0; - result = ma_dr_wav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); - if (result != MA_SUCCESS || bytesRead != sizeof(*pDst)) { - return result; - } - *pDst = ma_dr_wav_bytes_to_u16(data); - return MA_SUCCESS; -} -MA_PRIVATE ma_result ma_dr_wav_buffer_reader_read_u32(ma_dr_wav_buffer_reader* pReader, ma_uint32* pDst) -{ - ma_result result; - size_t bytesRead; - ma_uint8 data[4]; - MA_DR_WAV_ASSERT(pReader != NULL); - MA_DR_WAV_ASSERT(pDst != NULL); - *pDst = 0; - result = ma_dr_wav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); - if (result != MA_SUCCESS || bytesRead != sizeof(*pDst)) { - return result; - } - *pDst = ma_dr_wav_bytes_to_u32(data); - return MA_SUCCESS; -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_bext_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, ma_dr_wav_metadata* pMetadata, ma_uint64 chunkSize) -{ - ma_uint8 bextData[MA_DR_WAV_BEXT_BYTES]; - size_t bytesRead = ma_dr_wav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - if (bytesRead == sizeof(bextData)) { - ma_dr_wav_buffer_reader reader; - ma_uint32 timeReferenceLow; - ma_uint32 timeReferenceHigh; - size_t extraBytes; - pMetadata->type = ma_dr_wav_metadata_type_bext; - if (ma_dr_wav_buffer_reader_init(bextData, bytesRead, &reader) == MA_SUCCESS) { - pMetadata->data.bext.pDescription = ma_dr_wav__metadata_copy_string(pParser, (const char*)ma_dr_wav_buffer_reader_ptr(&reader), MA_DR_WAV_BEXT_DESCRIPTION_BYTES); - ma_dr_wav_buffer_reader_seek(&reader, MA_DR_WAV_BEXT_DESCRIPTION_BYTES); - pMetadata->data.bext.pOriginatorName = ma_dr_wav__metadata_copy_string(pParser, (const char*)ma_dr_wav_buffer_reader_ptr(&reader), MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES); - ma_dr_wav_buffer_reader_seek(&reader, MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES); - pMetadata->data.bext.pOriginatorReference = ma_dr_wav__metadata_copy_string(pParser, (const char*)ma_dr_wav_buffer_reader_ptr(&reader), MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES); - ma_dr_wav_buffer_reader_seek(&reader, MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES); - ma_dr_wav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL); - ma_dr_wav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL); - ma_dr_wav_buffer_reader_read_u32(&reader, &timeReferenceLow); - ma_dr_wav_buffer_reader_read_u32(&reader, &timeReferenceHigh); - pMetadata->data.bext.timeReference = ((ma_uint64)timeReferenceHigh << 32) + timeReferenceLow; - ma_dr_wav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); - pMetadata->data.bext.pUMID = ma_dr_wav__metadata_get_memory(pParser, MA_DR_WAV_BEXT_UMID_BYTES, 1); - ma_dr_wav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, MA_DR_WAV_BEXT_UMID_BYTES, NULL); - ma_dr_wav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue); - ma_dr_wav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange); - ma_dr_wav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel); - ma_dr_wav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness); - ma_dr_wav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness); - MA_DR_WAV_ASSERT((ma_dr_wav_offset_ptr(ma_dr_wav_buffer_reader_ptr(&reader), MA_DR_WAV_BEXT_RESERVED_BYTES)) == (bextData + MA_DR_WAV_BEXT_BYTES)); - extraBytes = (size_t)(chunkSize - MA_DR_WAV_BEXT_BYTES); - if (extraBytes > 0) { - pMetadata->data.bext.pCodingHistory = (char*)ma_dr_wav__metadata_get_memory(pParser, extraBytes + 1, 1); - MA_DR_WAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - bytesRead += ma_dr_wav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (ma_uint32)ma_dr_wav__strlen(pMetadata->data.bext.pCodingHistory); - } else { - pMetadata->data.bext.pCodingHistory = NULL; - pMetadata->data.bext.codingHistorySize = 0; - } - } - } - return bytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_list_label_or_note_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, ma_dr_wav_metadata* pMetadata, ma_uint64 chunkSize, ma_dr_wav_metadata_type type) -{ - ma_uint8 cueIDBuffer[MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES]; - ma_uint64 totalBytesRead = 0; - size_t bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, cueIDBuffer, sizeof(cueIDBuffer), &totalBytesRead); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - if (bytesJustRead == sizeof(cueIDBuffer)) { - ma_uint32 sizeIncludingNullTerminator; - pMetadata->type = type; - pMetadata->data.labelOrNote.cuePointId = ma_dr_wav_bytes_to_u32(cueIDBuffer); - sizeIncludingNullTerminator = (ma_uint32)chunkSize - MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES; - if (sizeIncludingNullTerminator > 0) { - pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1; - pMetadata->data.labelOrNote.pString = (char*)ma_dr_wav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); - MA_DR_WAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - ma_dr_wav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); - } else { - pMetadata->data.labelOrNote.stringLength = 0; - pMetadata->data.labelOrNote.pString = NULL; - } - } - return totalBytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__read_list_labelled_cue_region_to_metadata_obj(ma_dr_wav__metadata_parser* pParser, ma_dr_wav_metadata* pMetadata, ma_uint64 chunkSize) -{ - ma_uint8 buffer[MA_DR_WAV_LIST_LABELLED_TEXT_BYTES]; - ma_uint64 totalBytesRead = 0; - size_t bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, buffer, sizeof(buffer), &totalBytesRead); - MA_DR_WAV_ASSERT(pParser->stage == ma_dr_wav__metadata_parser_stage_read); - if (bytesJustRead == sizeof(buffer)) { - ma_uint32 sizeIncludingNullTerminator; - pMetadata->type = ma_dr_wav_metadata_type_list_labelled_cue_region; - pMetadata->data.labelledCueRegion.cuePointId = ma_dr_wav_bytes_to_u32(buffer + 0); - pMetadata->data.labelledCueRegion.sampleLength = ma_dr_wav_bytes_to_u32(buffer + 4); - pMetadata->data.labelledCueRegion.purposeId[0] = buffer[8]; - pMetadata->data.labelledCueRegion.purposeId[1] = buffer[9]; - pMetadata->data.labelledCueRegion.purposeId[2] = buffer[10]; - pMetadata->data.labelledCueRegion.purposeId[3] = buffer[11]; - pMetadata->data.labelledCueRegion.country = ma_dr_wav_bytes_to_u16(buffer + 12); - pMetadata->data.labelledCueRegion.language = ma_dr_wav_bytes_to_u16(buffer + 14); - pMetadata->data.labelledCueRegion.dialect = ma_dr_wav_bytes_to_u16(buffer + 16); - pMetadata->data.labelledCueRegion.codePage = ma_dr_wav_bytes_to_u16(buffer + 18); - sizeIncludingNullTerminator = (ma_uint32)chunkSize - MA_DR_WAV_LIST_LABELLED_TEXT_BYTES; - if (sizeIncludingNullTerminator > 0) { - pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1; - pMetadata->data.labelledCueRegion.pString = (char*)ma_dr_wav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); - MA_DR_WAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - ma_dr_wav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); - } else { - pMetadata->data.labelledCueRegion.stringLength = 0; - pMetadata->data.labelledCueRegion.pString = NULL; - } - } - return totalBytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_info_text_chunk(ma_dr_wav__metadata_parser* pParser, ma_uint64 chunkSize, ma_dr_wav_metadata_type type) -{ - ma_uint64 bytesRead = 0; - ma_uint32 stringSizeWithNullTerminator = (ma_uint32)chunkSize; - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, stringSizeWithNullTerminator, 1); - } else { - ma_dr_wav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor]; - pMetadata->type = type; - if (stringSizeWithNullTerminator > 0) { - pMetadata->data.infoText.stringLength = stringSizeWithNullTerminator - 1; - pMetadata->data.infoText.pString = (char*)ma_dr_wav__metadata_get_memory(pParser, stringSizeWithNullTerminator, 1); - MA_DR_WAV_ASSERT(pMetadata->data.infoText.pString != NULL); - bytesRead = ma_dr_wav__metadata_parser_read(pParser, pMetadata->data.infoText.pString, (size_t)stringSizeWithNullTerminator, NULL); - if (bytesRead == chunkSize) { - pParser->metadataCursor += 1; - } else { - } - } else { - pMetadata->data.infoText.stringLength = 0; - pMetadata->data.infoText.pString = NULL; - pParser->metadataCursor += 1; - } - } - return bytesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_unknown_chunk(ma_dr_wav__metadata_parser* pParser, const ma_uint8* pChunkId, ma_uint64 chunkSize, ma_dr_wav_metadata_location location) -{ - ma_uint64 bytesRead = 0; - if (location == ma_dr_wav_metadata_location_invalid) { - return 0; - } - if (ma_dr_wav_fourcc_equal(pChunkId, "data") || ma_dr_wav_fourcc_equal(pChunkId, "fmt ") || ma_dr_wav_fourcc_equal(pChunkId, "fact")) { - return 0; - } - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)chunkSize, 1); - } else { - ma_dr_wav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor]; - pMetadata->type = ma_dr_wav_metadata_type_unknown; - pMetadata->data.unknown.chunkLocation = location; - pMetadata->data.unknown.id[0] = pChunkId[0]; - pMetadata->data.unknown.id[1] = pChunkId[1]; - pMetadata->data.unknown.id[2] = pChunkId[2]; - pMetadata->data.unknown.id[3] = pChunkId[3]; - pMetadata->data.unknown.dataSizeInBytes = (ma_uint32)chunkSize; - pMetadata->data.unknown.pData = (ma_uint8 *)ma_dr_wav__metadata_get_memory(pParser, (size_t)chunkSize, 1); - MA_DR_WAV_ASSERT(pMetadata->data.unknown.pData != NULL); - bytesRead = ma_dr_wav__metadata_parser_read(pParser, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes, NULL); - if (bytesRead == pMetadata->data.unknown.dataSizeInBytes) { - pParser->metadataCursor += 1; - } else { - } - } - return bytesRead; -} -MA_PRIVATE ma_bool32 ma_dr_wav__chunk_matches(ma_dr_wav_metadata_type allowedMetadataTypes, const ma_uint8* pChunkID, ma_dr_wav_metadata_type type, const char* pID) -{ - return (allowedMetadataTypes & type) && ma_dr_wav_fourcc_equal(pChunkID, pID); -} -MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parser* pParser, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_metadata_type allowedMetadataTypes) -{ - const ma_uint8 *pChunkID = pChunkHeader->id.fourcc; - ma_uint64 bytesRead = 0; - if (ma_dr_wav__chunk_matches(allowedMetadataTypes, pChunkID, ma_dr_wav_metadata_type_smpl, "smpl")) { - if (pChunkHeader->sizeInBytes >= MA_DR_WAV_SMPL_BYTES) { - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - ma_uint8 buffer[4]; - size_t bytesJustRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, 28, ma_dr_wav_seek_origin_current)) { - return bytesRead; - } - bytesRead += 28; - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - ma_uint32 loopCount = ma_dr_wav_bytes_to_u32(buffer); - ma_uint64 calculatedLoopCount; - calculatedLoopCount = (pChunkHeader->sizeInBytes - MA_DR_WAV_SMPL_BYTES) / MA_DR_WAV_SMPL_LOOP_BYTES; - if (calculatedLoopCount == loopCount) { - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - ma_uint32 samplerSpecificDataSizeInBytes = ma_dr_wav_bytes_to_u32(buffer); - pParser->metadataCount += 1; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(ma_dr_wav_smpl_loop) * loopCount, MA_DR_WAV_METADATA_ALIGNMENT); - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); - } - } else { - } - } - } else { - bytesRead = ma_dr_wav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, pChunkID, ma_dr_wav_metadata_type_inst, "inst")) { - if (pChunkHeader->sizeInBytes == MA_DR_WAV_INST_BYTES) { - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - } else { - bytesRead = ma_dr_wav__read_inst_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, pChunkID, ma_dr_wav_metadata_type_acid, "acid")) { - if (pChunkHeader->sizeInBytes == MA_DR_WAV_ACID_BYTES) { - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - } else { - bytesRead = ma_dr_wav__read_acid_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, pChunkID, ma_dr_wav_metadata_type_cue, "cue ")) { - if (pChunkHeader->sizeInBytes >= MA_DR_WAV_CUE_BYTES) { - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - size_t cueCount; - pParser->metadataCount += 1; - cueCount = (size_t)(pChunkHeader->sizeInBytes - MA_DR_WAV_CUE_BYTES) / MA_DR_WAV_CUE_POINT_BYTES; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(ma_dr_wav_cue_point) * cueCount, MA_DR_WAV_METADATA_ALIGNMENT); - } else { - bytesRead = ma_dr_wav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, pChunkID, ma_dr_wav_metadata_type_bext, "bext")) { - if (pChunkHeader->sizeInBytes >= MA_DR_WAV_BEXT_BYTES) { - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - char buffer[MA_DR_WAV_BEXT_DESCRIPTION_BYTES + 1]; - size_t allocSizeNeeded = MA_DR_WAV_BEXT_UMID_BYTES; - size_t bytesJustRead; - buffer[MA_DR_WAV_BEXT_DESCRIPTION_BYTES] = '\0'; - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, buffer, MA_DR_WAV_BEXT_DESCRIPTION_BYTES, &bytesRead); - if (bytesJustRead != MA_DR_WAV_BEXT_DESCRIPTION_BYTES) { - return bytesRead; - } - allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - buffer[MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0'; - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, buffer, MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead); - if (bytesJustRead != MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES) { - return bytesRead; - } - allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - buffer[MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES] = '\0'; - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, buffer, MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead); - if (bytesJustRead != MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES) { - return bytesRead; - } - allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); - pParser->metadataCount += 1; - } else { - bytesRead = ma_dr_wav__read_bext_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], pChunkHeader->sizeInBytes); - if (bytesRead == pChunkHeader->sizeInBytes) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav_fourcc_equal(pChunkID, "LIST") || ma_dr_wav_fourcc_equal(pChunkID, "list")) { - ma_dr_wav_metadata_location listType = ma_dr_wav_metadata_location_invalid; - while (bytesRead < pChunkHeader->sizeInBytes) { - ma_uint8 subchunkId[4]; - ma_uint8 subchunkSizeBuffer[4]; - ma_uint64 subchunkDataSize; - ma_uint64 subchunkBytesRead = 0; - ma_uint64 bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, subchunkId, sizeof(subchunkId), &bytesRead); - if (bytesJustRead != sizeof(subchunkId)) { - break; - } - if (ma_dr_wav_fourcc_equal(subchunkId, "adtl")) { - listType = ma_dr_wav_metadata_location_inside_adtl_list; - continue; - } else if (ma_dr_wav_fourcc_equal(subchunkId, "INFO")) { - listType = ma_dr_wav_metadata_location_inside_info_list; - continue; - } - bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, subchunkSizeBuffer, sizeof(subchunkSizeBuffer), &bytesRead); - if (bytesJustRead != sizeof(subchunkSizeBuffer)) { - break; - } - subchunkDataSize = ma_dr_wav_bytes_to_u32(subchunkSizeBuffer); - if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_label, "labl") || ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_note, "note")) { - if (subchunkDataSize >= MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES) { - ma_uint64 stringSizeWithNullTerm = subchunkDataSize - MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES; - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerm, 1); - } else { - subchunkBytesRead = ma_dr_wav__read_list_label_or_note_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize, ma_dr_wav_fourcc_equal(subchunkId, "labl") ? ma_dr_wav_metadata_type_list_label : ma_dr_wav_metadata_type_list_note); - if (subchunkBytesRead == subchunkDataSize) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_labelled_cue_region, "ltxt")) { - if (subchunkDataSize >= MA_DR_WAV_LIST_LABELLED_TEXT_BYTES) { - ma_uint64 stringSizeWithNullTerminator = subchunkDataSize - MA_DR_WAV_LIST_LABELLED_TEXT_BYTES; - if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { - pParser->metadataCount += 1; - ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerminator, 1); - } else { - subchunkBytesRead = ma_dr_wav__read_list_labelled_cue_region_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize); - if (subchunkBytesRead == subchunkDataSize) { - pParser->metadataCursor += 1; - } else { - } - } - } else { - } - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_software, "ISFT")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_software); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_copyright, "ICOP")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_copyright); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_title, "INAM")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_title); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_artist, "IART")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_artist); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_comment, "ICMT")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_comment); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_date, "ICRD")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_date); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_genre, "IGNR")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_genre); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_album, "IPRD")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_album); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_tracknumber, "ITRK")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_tracknumber); - } else if ((allowedMetadataTypes & ma_dr_wav_metadata_type_unknown) != 0) { - subchunkBytesRead = ma_dr_wav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); - } - bytesRead += subchunkBytesRead; - MA_DR_WAV_ASSERT(subchunkBytesRead <= subchunkDataSize); - if (subchunkBytesRead < subchunkDataSize) { - ma_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current)) { - break; - } - bytesRead += bytesToSeek; - } - if ((subchunkDataSize % 2) == 1) { - if (!pParser->onSeek(pParser->pReadSeekUserData, 1, ma_dr_wav_seek_origin_current)) { - break; - } - bytesRead += 1; - } - } - } else if ((allowedMetadataTypes & ma_dr_wav_metadata_type_unknown) != 0) { - bytesRead = ma_dr_wav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, ma_dr_wav_metadata_location_top_level); - } - return bytesRead; -} -MA_PRIVATE ma_uint32 ma_dr_wav_get_bytes_per_pcm_frame(ma_dr_wav* pWav) -{ - ma_uint32 bytesPerFrame; if ((pWav->bitsPerSample & 0x7) == 0) { - bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; } else { - bytesPerFrame = pWav->fmt.blockAlign; + return pWav->fmt.blockAlign; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_MULAW) { - if (bytesPerFrame != pWav->fmt.channels) { - return 0; - } - } - return bytesPerFrame; } -MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT) +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) { if (pFMT == NULL) { return 0; } - if (pFMT->formatTag != MA_DR_WAVE_FORMAT_EXTENSIBLE) { + if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) { return pFMT->formatTag; } else { - return ma_dr_wav_bytes_to_u16(pFMT->subFormat); + return drwav_bytes_to_u16(pFMT->subFormat); } } -MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pWav == NULL || onRead == NULL || onSeek == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - MA_DR_WAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); pWav->onRead = onRead; pWav->onSeek = onSeek; pWav->pUserData = pReadSeekUserData; - pWav->allocationCallbacks = ma_dr_wav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { - return MA_FALSE; + return DRWAV_FALSE; } - return MA_TRUE; + return DRWAV_TRUE; } -MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags) +DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) { - ma_result result; - ma_uint64 cursor; - ma_bool32 sequential; - ma_uint8 riff[4]; - ma_dr_wav_fmt fmt; + drwav_uint64 cursor; + drwav_bool32 sequential; + drwav_uint8 riff[4]; + drwav_fmt fmt; unsigned short translatedFormatTag; - ma_uint64 dataChunkSize = 0; - ma_uint64 sampleCountFromFactChunk = 0; - ma_uint64 metadataStartPos; - ma_dr_wav__metadata_parser metadataParser; - ma_bool8 isProcessingMetadata = MA_FALSE; - ma_bool8 foundChunk_fmt = MA_FALSE; - ma_bool8 foundChunk_data = MA_FALSE; - ma_bool8 isAIFCFormType = MA_FALSE; - ma_uint64 aiffFrameCount = 0; + drwav_bool32 foundDataChunk; + drwav_uint64 dataChunkSize = 0; + drwav_uint64 sampleCountFromFactChunk = 0; + drwav_uint64 chunkSize; cursor = 0; - sequential = (flags & MA_DR_WAV_SEQUENTIAL) != 0; - MA_DR_WAV_ZERO_OBJECT(&fmt); - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { - return MA_FALSE; + sequential = (flags & DRWAV_SEQUENTIAL) != 0; + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { + return DRWAV_FALSE; } - if (ma_dr_wav_fourcc_equal(riff, "RIFF")) { - pWav->container = ma_dr_wav_container_riff; - } else if (ma_dr_wav_fourcc_equal(riff, "RIFX")) { - pWav->container = ma_dr_wav_container_rifx; - } else if (ma_dr_wav_fourcc_equal(riff, "riff")) { + if (drwav_fourcc_equal(riff, "RIFF")) { + pWav->container = drwav_container_riff; + } else if (drwav_fourcc_equal(riff, "riff")) { int i; - ma_uint8 riff2[12]; - pWav->container = ma_dr_wav_container_w64; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { - return MA_FALSE; + drwav_uint8 riff2[12]; + pWav->container = drwav_container_w64; + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { + return DRWAV_FALSE; } for (i = 0; i < 12; ++i) { - if (riff2[i] != ma_dr_wavGUID_W64_RIFF[i+4]) { - return MA_FALSE; + if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { + return DRWAV_FALSE; } } - } else if (ma_dr_wav_fourcc_equal(riff, "RF64")) { - pWav->container = ma_dr_wav_container_rf64; - } else if (ma_dr_wav_fourcc_equal(riff, "FORM")) { - pWav->container = ma_dr_wav_container_aiff; + } else if (drwav_fourcc_equal(riff, "RF64")) { + pWav->container = drwav_container_rf64; } else { - return MA_FALSE; + return DRWAV_FALSE; } - if (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx || pWav->container == ma_dr_wav_container_rf64) { - ma_uint8 chunkSizeBytes[4]; - ma_uint8 wave[4]; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { - return MA_FALSE; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + drwav_uint8 chunkSizeBytes[4]; + drwav_uint8 wave[4]; + if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; } - if (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) { - if (ma_dr_wav_bytes_to_u32_ex(chunkSizeBytes, pWav->container) < 36) { - } - } else if (pWav->container == ma_dr_wav_container_rf64) { - if (ma_dr_wav_bytes_to_u32_le(chunkSizeBytes) != 0xFFFFFFFF) { - return MA_FALSE; + if (pWav->container == drwav_container_riff) { + if (drwav_bytes_to_u32(chunkSizeBytes) < 36) { + return DRWAV_FALSE; } } else { - return MA_FALSE; + if (drwav_bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) { + return DRWAV_FALSE; + } } - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { - return MA_FALSE; + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; } - if (!ma_dr_wav_fourcc_equal(wave, "WAVE")) { - return MA_FALSE; - } - } else if (pWav->container == ma_dr_wav_container_w64) { - ma_uint8 chunkSizeBytes[8]; - ma_uint8 wave[16]; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { - return MA_FALSE; - } - if (ma_dr_wav_bytes_to_u64(chunkSizeBytes) < 80) { - return MA_FALSE; - } - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { - return MA_FALSE; - } - if (!ma_dr_wav_guid_equal(wave, ma_dr_wavGUID_W64_WAVE)) { - return MA_FALSE; - } - } else if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint8 chunkSizeBytes[4]; - ma_uint8 aiff[4]; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { - return MA_FALSE; - } - if (ma_dr_wav_bytes_to_u32_be(chunkSizeBytes) < 18) { - return MA_FALSE; - } - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, aiff, sizeof(aiff), &cursor) != sizeof(aiff)) { - return MA_FALSE; - } - if (ma_dr_wav_fourcc_equal(aiff, "AIFF")) { - isAIFCFormType = MA_FALSE; - } else if (ma_dr_wav_fourcc_equal(aiff, "AIFC")) { - isAIFCFormType = MA_TRUE; - } else { - return MA_FALSE; + if (!drwav_fourcc_equal(wave, "WAVE")) { + return DRWAV_FALSE; } } else { - return MA_FALSE; - } - if (pWav->container == ma_dr_wav_container_rf64) { - ma_uint8 sizeBytes[8]; - ma_uint64 bytesRemainingInChunk; - ma_dr_wav_chunk_header header; - result = ma_dr_wav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); - if (result != MA_SUCCESS) { - return MA_FALSE; + drwav_uint8 chunkSizeBytes[8]; + drwav_uint8 wave[16]; + if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; } - if (!ma_dr_wav_fourcc_equal(header.id.fourcc, "ds64")) { - return MA_FALSE; + if (drwav_bytes_to_u64(chunkSizeBytes) < 80) { + return DRWAV_FALSE; + } + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; + } + if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) { + return DRWAV_FALSE; + } + } + if (pWav->container == drwav_container_rf64) { + drwav_uint8 sizeBytes[8]; + drwav_uint64 bytesRemainingInChunk; + drwav_chunk_header header; + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) { + return DRWAV_FALSE; } bytesRemainingInChunk = header.sizeInBytes + header.paddingSize; - if (!ma_dr_wav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) { - return MA_FALSE; + if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) { + return DRWAV_FALSE; } bytesRemainingInChunk -= 8; cursor += 8; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { - return MA_FALSE; + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; } bytesRemainingInChunk -= 8; - dataChunkSize = ma_dr_wav_bytes_to_u64(sizeBytes); - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { - return MA_FALSE; + dataChunkSize = drwav_bytes_to_u64(sizeBytes); + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; } bytesRemainingInChunk -= 8; - sampleCountFromFactChunk = ma_dr_wav_bytes_to_u64(sizeBytes); - if (!ma_dr_wav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) { - return MA_FALSE; + sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes); + if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) { + return DRWAV_FALSE; } cursor += bytesRemainingInChunk; } - metadataStartPos = cursor; - isProcessingMetadata = !sequential && ((flags & MA_DR_WAV_WITH_METADATA) != 0); - if (pWav->container != ma_dr_wav_container_riff && pWav->container != ma_dr_wav_container_rf64) { - isProcessingMetadata = MA_FALSE; + if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) { + return DRWAV_FALSE; } - MA_DR_WAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser)); - if (isProcessingMetadata) { - metadataParser.onRead = pWav->onRead; - metadataParser.onSeek = pWav->onSeek; - metadataParser.pReadSeekUserData = pWav->pUserData; - metadataParser.stage = ma_dr_wav__metadata_parser_stage_count; + if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) || + (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) || + (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) || + fmt.blockAlign == 0) { + return DRWAV_FALSE; } - for (;;) { - ma_dr_wav_chunk_header header; - ma_uint64 chunkSize; - result = ma_dr_wav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); - if (result != MA_SUCCESS) { - break; + translatedFormatTag = fmt.formatTag; + if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0); + } + foundDataChunk = DRWAV_FALSE; + for (;;) + { + drwav_chunk_header header; + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + if (!foundDataChunk) { + return DRWAV_FALSE; + } else { + break; + } + } + if (!sequential && onChunk != NULL) { + drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); + if (callbackBytesRead > 0) { + if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) { + return DRWAV_FALSE; + } + } + } + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; } chunkSize = header.sizeInBytes; - if (!sequential && onChunk != NULL) { - ma_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); - if (callbackBytesRead > 0) { - if (ma_dr_wav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav_fourcc_equal(header.id.fourcc, "data")) { + foundDataChunk = DRWAV_TRUE; + if (pWav->container != drwav_container_rf64) { + dataChunkSize = chunkSize; } } - } - if (((pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx || pWav->container == ma_dr_wav_container_rf64) && ma_dr_wav_fourcc_equal(header.id.fourcc, "fmt ")) || - ((pWav->container == ma_dr_wav_container_w64) && ma_dr_wav_guid_equal(header.id.guid, ma_dr_wavGUID_W64_FMT))) { - ma_uint8 fmtData[16]; - foundChunk_fmt = MA_TRUE; - if (pWav->onRead(pWav->pUserData, fmtData, sizeof(fmtData)) != sizeof(fmtData)) { - return MA_FALSE; - } - cursor += sizeof(fmtData); - fmt.formatTag = ma_dr_wav_bytes_to_u16_ex(fmtData + 0, pWav->container); - fmt.channels = ma_dr_wav_bytes_to_u16_ex(fmtData + 2, pWav->container); - fmt.sampleRate = ma_dr_wav_bytes_to_u32_ex(fmtData + 4, pWav->container); - fmt.avgBytesPerSec = ma_dr_wav_bytes_to_u32_ex(fmtData + 8, pWav->container); - fmt.blockAlign = ma_dr_wav_bytes_to_u16_ex(fmtData + 12, pWav->container); - fmt.bitsPerSample = ma_dr_wav_bytes_to_u16_ex(fmtData + 14, pWav->container); - fmt.extendedSize = 0; - fmt.validBitsPerSample = 0; - fmt.channelMask = 0; - MA_DR_WAV_ZERO_MEMORY(fmt.subFormat, sizeof(fmt.subFormat)); - if (header.sizeInBytes > 16) { - ma_uint8 fmt_cbSize[2]; - int bytesReadSoFar = 0; - if (pWav->onRead(pWav->pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { - return MA_FALSE; - } - cursor += sizeof(fmt_cbSize); - bytesReadSoFar = 18; - fmt.extendedSize = ma_dr_wav_bytes_to_u16_ex(fmt_cbSize, pWav->container); - if (fmt.extendedSize > 0) { - if (fmt.formatTag == MA_DR_WAVE_FORMAT_EXTENSIBLE) { - if (fmt.extendedSize != 22) { - return MA_FALSE; - } - } - if (fmt.formatTag == MA_DR_WAVE_FORMAT_EXTENSIBLE) { - ma_uint8 fmtext[22]; - if (pWav->onRead(pWav->pUserData, fmtext, fmt.extendedSize) != fmt.extendedSize) { - return MA_FALSE; - } - fmt.validBitsPerSample = ma_dr_wav_bytes_to_u16_ex(fmtext + 0, pWav->container); - fmt.channelMask = ma_dr_wav_bytes_to_u32_ex(fmtext + 2, pWav->container); - ma_dr_wav_bytes_to_guid(fmtext + 6, fmt.subFormat); - } else { - if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, ma_dr_wav_seek_origin_current) == MA_FALSE) { - return MA_FALSE; - } - } - cursor += fmt.extendedSize; - bytesReadSoFar += fmt.extendedSize; - } - if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), ma_dr_wav_seek_origin_current) == MA_FALSE) { - return MA_FALSE; - } - cursor += (header.sizeInBytes - bytesReadSoFar); - } - if (header.paddingSize > 0) { - if (ma_dr_wav__seek_forward(pWav->onSeek, header.paddingSize, pWav->pUserData) == MA_FALSE) { - break; - } - cursor += header.paddingSize; - } - continue; - } - if (((pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx || pWav->container == ma_dr_wav_container_rf64) && ma_dr_wav_fourcc_equal(header.id.fourcc, "data")) || - ((pWav->container == ma_dr_wav_container_w64) && ma_dr_wav_guid_equal(header.id.guid, ma_dr_wavGUID_W64_DATA))) { - foundChunk_data = MA_TRUE; - pWav->dataChunkDataPos = cursor; - if (pWav->container != ma_dr_wav_container_rf64) { + } else { + if (drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA)) { + foundDataChunk = DRWAV_TRUE; dataChunkSize = chunkSize; } - if (sequential || !isProcessingMetadata) { - break; - } else { - chunkSize += header.paddingSize; - if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { - break; - } - cursor += chunkSize; - continue; - } } - if (((pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx || pWav->container == ma_dr_wav_container_rf64) && ma_dr_wav_fourcc_equal(header.id.fourcc, "fact")) || - ((pWav->container == ma_dr_wav_container_w64) && ma_dr_wav_guid_equal(header.id.guid, ma_dr_wavGUID_W64_FACT))) { - if (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) { - ma_uint8 sampleCount[4]; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { - return MA_FALSE; + if (foundDataChunk && sequential) { + break; + } + if (pWav->container == drwav_container_riff) { + if (drwav_fourcc_equal(header.id.fourcc, "fact")) { + drwav_uint32 sampleCount; + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { + return DRWAV_FALSE; } chunkSize -= 4; - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { - sampleCountFromFactChunk = ma_dr_wav_bytes_to_u32_ex(sampleCount, pWav->container); + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + sampleCountFromFactChunk = sampleCount; } else { sampleCountFromFactChunk = 0; } - } else if (pWav->container == ma_dr_wav_container_w64) { - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { - return MA_FALSE; + } + } else if (pWav->container == drwav_container_w64) { + if (drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT)) { + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { + return DRWAV_FALSE; } chunkSize -= 8; - } else if (pWav->container == ma_dr_wav_container_rf64) { + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } } - chunkSize += header.paddingSize; - if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { - break; - } - cursor += chunkSize; - continue; + } else if (pWav->container == drwav_container_rf64) { } - if (pWav->container == ma_dr_wav_container_aiff && ma_dr_wav_fourcc_equal(header.id.fourcc, "COMM")) { - ma_uint8 commData[24]; - ma_uint32 commDataBytesToRead; - ma_uint16 channels; - ma_uint32 frameCount; - ma_uint16 sampleSizeInBits; - ma_int64 sampleRate; - ma_uint16 compressionFormat; - foundChunk_fmt = MA_TRUE; - if (isAIFCFormType) { - commDataBytesToRead = 24; - if (header.sizeInBytes < commDataBytesToRead) { - return MA_FALSE; - } - } else { - commDataBytesToRead = 18; - if (header.sizeInBytes != commDataBytesToRead) { - return MA_FALSE; - } - } - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, commData, commDataBytesToRead, &cursor) != commDataBytesToRead) { - return MA_FALSE; - } - channels = ma_dr_wav_bytes_to_u16_ex (commData + 0, pWav->container); - frameCount = ma_dr_wav_bytes_to_u32_ex (commData + 2, pWav->container); - sampleSizeInBits = ma_dr_wav_bytes_to_u16_ex (commData + 6, pWav->container); - sampleRate = ma_dr_wav_aiff_extented_to_s64(commData + 8); - if (sampleRate < 0 || sampleRate > 0xFFFFFFFF) { - return MA_FALSE; - } - if (isAIFCFormType) { - const ma_uint8* type = commData + 18; - if (ma_dr_wav_fourcc_equal(type, "NONE")) { - compressionFormat = MA_DR_WAVE_FORMAT_PCM; - } else if (ma_dr_wav_fourcc_equal(type, "raw ")) { - compressionFormat = MA_DR_WAVE_FORMAT_PCM; - if (sampleSizeInBits == 8) { - pWav->aiff.isUnsigned = MA_TRUE; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav_fourcc_equal(header.id.fourcc, "smpl")) { + drwav_uint8 smplHeaderData[36]; + if (chunkSize >= sizeof(smplHeaderData)) { + drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor); + chunkSize -= bytesJustRead; + if (bytesJustRead == sizeof(smplHeaderData)) { + drwav_uint32 iLoop; + pWav->smpl.manufacturer = drwav_bytes_to_u32(smplHeaderData+0); + pWav->smpl.product = drwav_bytes_to_u32(smplHeaderData+4); + pWav->smpl.samplePeriod = drwav_bytes_to_u32(smplHeaderData+8); + pWav->smpl.midiUnityNotes = drwav_bytes_to_u32(smplHeaderData+12); + pWav->smpl.midiPitchFraction = drwav_bytes_to_u32(smplHeaderData+16); + pWav->smpl.smpteFormat = drwav_bytes_to_u32(smplHeaderData+20); + pWav->smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData+24); + pWav->smpl.numSampleLoops = drwav_bytes_to_u32(smplHeaderData+28); + pWav->smpl.samplerData = drwav_bytes_to_u32(smplHeaderData+32); + for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { + drwav_uint8 smplLoopData[24]; + bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor); + chunkSize -= bytesJustRead; + if (bytesJustRead == sizeof(smplLoopData)) { + pWav->smpl.loops[iLoop].cuePointId = drwav_bytes_to_u32(smplLoopData+0); + pWav->smpl.loops[iLoop].type = drwav_bytes_to_u32(smplLoopData+4); + pWav->smpl.loops[iLoop].start = drwav_bytes_to_u32(smplLoopData+8); + pWav->smpl.loops[iLoop].end = drwav_bytes_to_u32(smplLoopData+12); + pWav->smpl.loops[iLoop].fraction = drwav_bytes_to_u32(smplLoopData+16); + pWav->smpl.loops[iLoop].playCount = drwav_bytes_to_u32(smplLoopData+20); + } else { + break; + } + } } - } else if (ma_dr_wav_fourcc_equal(type, "sowt")) { - compressionFormat = MA_DR_WAVE_FORMAT_PCM; - pWav->aiff.isLE = MA_TRUE; - } else if (ma_dr_wav_fourcc_equal(type, "fl32") || ma_dr_wav_fourcc_equal(type, "fl64") || ma_dr_wav_fourcc_equal(type, "FL32") || ma_dr_wav_fourcc_equal(type, "FL64")) { - compressionFormat = MA_DR_WAVE_FORMAT_IEEE_FLOAT; - } else if (ma_dr_wav_fourcc_equal(type, "alaw") || ma_dr_wav_fourcc_equal(type, "ALAW")) { - compressionFormat = MA_DR_WAVE_FORMAT_ALAW; - } else if (ma_dr_wav_fourcc_equal(type, "ulaw") || ma_dr_wav_fourcc_equal(type, "ULAW")) { - compressionFormat = MA_DR_WAVE_FORMAT_MULAW; - } else if (ma_dr_wav_fourcc_equal(type, "ima4")) { - compressionFormat = MA_DR_WAVE_FORMAT_DVI_ADPCM; - sampleSizeInBits = 4; - (void)compressionFormat; - (void)sampleSizeInBits; - return MA_FALSE; } else { - return MA_FALSE; - } - } else { - compressionFormat = MA_DR_WAVE_FORMAT_PCM; - } - aiffFrameCount = frameCount; - fmt.formatTag = compressionFormat; - fmt.channels = channels; - fmt.sampleRate = (ma_uint32)sampleRate; - fmt.bitsPerSample = sampleSizeInBits; - fmt.blockAlign = (ma_uint16)(fmt.channels * fmt.bitsPerSample / 8); - fmt.avgBytesPerSec = fmt.blockAlign * fmt.sampleRate; - if (fmt.blockAlign == 0 && compressionFormat == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - fmt.blockAlign = 34 * fmt.channels; - } - if (compressionFormat == MA_DR_WAVE_FORMAT_ALAW || compressionFormat == MA_DR_WAVE_FORMAT_MULAW) { - if (fmt.bitsPerSample > 8) { - fmt.bitsPerSample = 8; - fmt.blockAlign = fmt.channels; } } - fmt.bitsPerSample += (fmt.bitsPerSample & 7); - if (isAIFCFormType) { - if (ma_dr_wav__seek_forward(pWav->onSeek, (chunkSize - commDataBytesToRead), pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - cursor += (chunkSize - commDataBytesToRead); - } - continue; - } - if (pWav->container == ma_dr_wav_container_aiff && ma_dr_wav_fourcc_equal(header.id.fourcc, "SSND")) { - ma_uint8 offsetAndBlockSizeData[8]; - ma_uint32 offset; - foundChunk_data = MA_TRUE; - if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, offsetAndBlockSizeData, sizeof(offsetAndBlockSizeData), &cursor) != sizeof(offsetAndBlockSizeData)) { - return MA_FALSE; - } - offset = ma_dr_wav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); - if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - cursor += offset; - pWav->dataChunkDataPos = cursor; - dataChunkSize = chunkSize; - if (sequential || !isProcessingMetadata) { - break; - } else { - if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { - break; - } - cursor += chunkSize; - continue; - } - } - if (isProcessingMetadata) { - ma_dr_wav__metadata_process_chunk(&metadataParser, &header, ma_dr_wav_metadata_type_all_including_unknown); - if (ma_dr_wav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == MA_FALSE) { - break; + } else { + if (drwav_guid_equal(header.id.guid, drwavGUID_W64_SMPL)) { } } chunkSize += header.paddingSize; - if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { + if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) { break; } cursor += chunkSize; + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } } - if (!foundChunk_fmt || !foundChunk_data) { - return MA_FALSE; - } - if ((fmt.sampleRate == 0 || fmt.sampleRate > MA_DR_WAV_MAX_SAMPLE_RATE ) || - (fmt.channels == 0 || fmt.channels > MA_DR_WAV_MAX_CHANNELS ) || - (fmt.bitsPerSample == 0 || fmt.bitsPerSample > MA_DR_WAV_MAX_BITS_PER_SAMPLE) || - fmt.blockAlign == 0) { - return MA_FALSE; - } - translatedFormatTag = fmt.formatTag; - if (translatedFormatTag == MA_DR_WAVE_FORMAT_EXTENSIBLE) { - translatedFormatTag = ma_dr_wav_bytes_to_u16_ex(fmt.subFormat + 0, pWav->container); + if (!foundDataChunk) { + return DRWAV_FALSE; } if (!sequential) { - if (!ma_dr_wav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { - return MA_FALSE; + if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { + return DRWAV_FALSE; } cursor = pWav->dataChunkDataPos; } - if (isProcessingMetadata && metadataParser.metadataCount > 0) { - if (ma_dr_wav__seek_from_start(pWav->onSeek, metadataStartPos, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - result = ma_dr_wav__metadata_alloc(&metadataParser, &pWav->allocationCallbacks); - if (result != MA_SUCCESS) { - return MA_FALSE; - } - metadataParser.stage = ma_dr_wav__metadata_parser_stage_read; - for (;;) { - ma_dr_wav_chunk_header header; - ma_uint64 metadataBytesRead; - result = ma_dr_wav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); - if (result != MA_SUCCESS) { - break; - } - metadataBytesRead = ma_dr_wav__metadata_process_chunk(&metadataParser, &header, ma_dr_wav_metadata_type_all_including_unknown); - if (ma_dr_wav__seek_forward(pWav->onSeek, (header.sizeInBytes + header.paddingSize) - metadataBytesRead, pWav->pUserData) == MA_FALSE) { - ma_dr_wav_free(metadataParser.pMetadata, &pWav->allocationCallbacks); - return MA_FALSE; - } - } - pWav->pMetadata = metadataParser.pMetadata; - pWav->metadataCount = metadataParser.metadataCount; - } - if (dataChunkSize == 0xFFFFFFFF && (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) && pWav->isSequentialWrite == MA_FALSE) { - dataChunkSize = 0; - for (;;) { - ma_uint8 temp[4096]; - size_t bytesRead = pWav->onRead(pWav->pUserData, temp, sizeof(temp)); - dataChunkSize += bytesRead; - if (bytesRead < sizeof(temp)) { - break; - } - } - } - if (ma_dr_wav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == MA_FALSE) { - ma_dr_wav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return MA_FALSE; - } pWav->fmt = fmt; pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; @@ -79800,27 +49929,20 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->dataChunkDataSize = dataChunkSize; if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; - } else if (aiffFrameCount != 0) { - pWav->totalPCMFrameCount = aiffFrameCount; } else { - ma_uint32 bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - ma_dr_wav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return MA_FALSE; - } - pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame; - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { - ma_uint64 totalBlockHeaderSizeInBytes; - ma_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; if ((blockCount * fmt.blockAlign) < dataChunkSize) { blockCount += 1; } totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels); pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - ma_uint64 totalBlockHeaderSizeInBytes; - ma_uint64 blockCount = dataChunkSize / fmt.blockAlign; + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; if ((blockCount * fmt.blockAlign) < dataChunkSize) { blockCount += 1; } @@ -79829,843 +49951,913 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->totalPCMFrameCount += blockCount; } } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { if (pWav->channels > 2) { - ma_dr_wav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return MA_FALSE; + return DRWAV_FALSE; } } - if (ma_dr_wav_get_bytes_per_pcm_frame(pWav) == 0) { - ma_dr_wav_free(pWav->pMetadata, &pWav->allocationCallbacks); - return MA_FALSE; - } -#ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { - ma_uint64 blockCount = dataChunkSize / fmt.blockAlign; +#ifdef DR_WAV_LIBSNDFILE_COMPAT + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - ma_uint64 blockCount = dataChunkSize / fmt.blockAlign; + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels; } #endif - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); + return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { - return MA_FALSE; + if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; } - return ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); + return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); } -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { - return MA_FALSE; - } - return ma_dr_wav_init__internal(pWav, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA); -} -MA_API ma_dr_wav_metadata* ma_dr_wav_take_ownership_of_metadata(ma_dr_wav* pWav) -{ - ma_dr_wav_metadata *result = pWav->pMetadata; - pWav->pMetadata = NULL; - pWav->metadataCount = 0; - return result; -} -MA_PRIVATE size_t ma_dr_wav__write(ma_dr_wav* pWav, const void* pData, size_t dataSize) -{ - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->onWrite != NULL); - return pWav->onWrite(pWav->pUserData, pData, dataSize); -} -MA_PRIVATE size_t ma_dr_wav__write_byte(ma_dr_wav* pWav, ma_uint8 byte) -{ - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->onWrite != NULL); - return pWav->onWrite(pWav->pUserData, &byte, 1); -} -MA_PRIVATE size_t ma_dr_wav__write_u16ne_to_le(ma_dr_wav* pWav, ma_uint16 value) -{ - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->onWrite != NULL); - if (!ma_dr_wav__is_little_endian()) { - value = ma_dr_wav__bswap16(value); - } - return ma_dr_wav__write(pWav, &value, 2); -} -MA_PRIVATE size_t ma_dr_wav__write_u32ne_to_le(ma_dr_wav* pWav, ma_uint32 value) -{ - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->onWrite != NULL); - if (!ma_dr_wav__is_little_endian()) { - value = ma_dr_wav__bswap32(value); - } - return ma_dr_wav__write(pWav, &value, 4); -} -MA_PRIVATE size_t ma_dr_wav__write_u64ne_to_le(ma_dr_wav* pWav, ma_uint64 value) -{ - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->onWrite != NULL); - if (!ma_dr_wav__is_little_endian()) { - value = ma_dr_wav__bswap64(value); - } - return ma_dr_wav__write(pWav, &value, 8); -} -MA_PRIVATE size_t ma_dr_wav__write_f32ne_to_le(ma_dr_wav* pWav, float value) -{ - union { - ma_uint32 u32; - float f32; - } u; - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->onWrite != NULL); - u.f32 = value; - if (!ma_dr_wav__is_little_endian()) { - u.u32 = ma_dr_wav__bswap32(u.u32); - } - return ma_dr_wav__write(pWav, &u.u32, 4); -} -MA_PRIVATE size_t ma_dr_wav__write_or_count(ma_dr_wav* pWav, const void* pData, size_t dataSize) -{ - if (pWav == NULL) { - return dataSize; - } - return ma_dr_wav__write(pWav, pData, dataSize); -} -MA_PRIVATE size_t ma_dr_wav__write_or_count_byte(ma_dr_wav* pWav, ma_uint8 byte) -{ - if (pWav == NULL) { - return 1; - } - return ma_dr_wav__write_byte(pWav, byte); -} -MA_PRIVATE size_t ma_dr_wav__write_or_count_u16ne_to_le(ma_dr_wav* pWav, ma_uint16 value) -{ - if (pWav == NULL) { - return 2; - } - return ma_dr_wav__write_u16ne_to_le(pWav, value); -} -MA_PRIVATE size_t ma_dr_wav__write_or_count_u32ne_to_le(ma_dr_wav* pWav, ma_uint32 value) -{ - if (pWav == NULL) { - return 4; - } - return ma_dr_wav__write_u32ne_to_le(pWav, value); -} -#if 0 -MA_PRIVATE size_t ma_dr_wav__write_or_count_u64ne_to_le(ma_dr_wav* pWav, ma_uint64 value) -{ - if (pWav == NULL) { - return 8; - } - return ma_dr_wav__write_u64ne_to_le(pWav, value); -} -#endif -MA_PRIVATE size_t ma_dr_wav__write_or_count_f32ne_to_le(ma_dr_wav* pWav, float value) -{ - if (pWav == NULL) { - return 4; - } - return ma_dr_wav__write_f32ne_to_le(pWav, value); -} -MA_PRIVATE size_t ma_dr_wav__write_or_count_string_to_fixed_size_buf(ma_dr_wav* pWav, char* str, size_t bufFixedSize) -{ - size_t len; - if (pWav == NULL) { - return bufFixedSize; - } - len = ma_dr_wav__strlen_clamped(str, bufFixedSize); - ma_dr_wav__write_or_count(pWav, str, len); - if (len < bufFixedSize) { - size_t i; - for (i = 0; i < bufFixedSize - len; ++i) { - ma_dr_wav__write_byte(pWav, 0); - } - } - return bufFixedSize; -} -MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_metadata* pMetadatas, ma_uint32 metadataCount) -{ - size_t bytesWritten = 0; - ma_bool32 hasListAdtl = MA_FALSE; - ma_bool32 hasListInfo = MA_FALSE; - ma_uint32 iMetadata; - if (pMetadatas == NULL || metadataCount == 0) { - return 0; - } - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - ma_dr_wav_metadata* pMetadata = &pMetadatas[iMetadata]; - ma_uint32 chunkSize = 0; - if ((pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings) || (pMetadata->type == ma_dr_wav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_inside_info_list)) { - hasListInfo = MA_TRUE; - } - if ((pMetadata->type & ma_dr_wav_metadata_type_list_all_adtl) || (pMetadata->type == ma_dr_wav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_inside_adtl_list)) { - hasListAdtl = MA_TRUE; - } - switch (pMetadata->type) { - case ma_dr_wav_metadata_type_smpl: - { - ma_uint32 iLoop; - chunkSize = MA_DR_WAV_SMPL_BYTES + MA_DR_WAV_SMPL_LOOP_BYTES * pMetadata->data.smpl.sampleLoopCount + pMetadata->data.smpl.samplerSpecificDataSizeInBytes; - bytesWritten += ma_dr_wav__write_or_count(pWav, "smpl", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.manufacturerId); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.productId); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplePeriodNanoseconds); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiUnityNote); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiPitchFraction); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteFormat); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.sampleLoopCount); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplerSpecificDataSizeInBytes); - for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); - } - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes); - } - } break; - case ma_dr_wav_metadata_type_inst: - { - chunkSize = MA_DR_WAV_INST_BYTES; - bytesWritten += ma_dr_wav__write_or_count(pWav, "inst", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.midiUnityNote, 1); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.fineTuneCents, 1); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.gainDecibels, 1); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.lowNote, 1); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.highNote, 1); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.lowVelocity, 1); - bytesWritten += ma_dr_wav__write_or_count(pWav, &pMetadata->data.inst.highVelocity, 1); - } break; - case ma_dr_wav_metadata_type_cue: - { - ma_uint32 iCuePoint; - chunkSize = MA_DR_WAV_CUE_BYTES + MA_DR_WAV_CUE_POINT_BYTES * pMetadata->data.cue.cuePointCount; - bytesWritten += ma_dr_wav__write_or_count(pWav, "cue ", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.cuePointCount); - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].id); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); - } - } break; - case ma_dr_wav_metadata_type_acid: - { - chunkSize = MA_DR_WAV_ACID_BYTES; - bytesWritten += ma_dr_wav__write_or_count(pWav, "acid", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.flags); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.midiUnityNote); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.reserved1); - bytesWritten += ma_dr_wav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.reserved2); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.numBeats); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterDenominator); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterNumerator); - bytesWritten += ma_dr_wav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.tempo); - } break; - case ma_dr_wav_metadata_type_bext: - { - char reservedBuf[MA_DR_WAV_BEXT_RESERVED_BYTES]; - ma_uint32 timeReferenceLow; - ma_uint32 timeReferenceHigh; - chunkSize = MA_DR_WAV_BEXT_BYTES + pMetadata->data.bext.codingHistorySize; - bytesWritten += ma_dr_wav__write_or_count(pWav, "bext", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pDescription, MA_DR_WAV_BEXT_DESCRIPTION_BYTES); - bytesWritten += ma_dr_wav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorName, MA_DR_WAV_BEXT_ORIGINATOR_NAME_BYTES); - bytesWritten += ma_dr_wav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorReference, MA_DR_WAV_BEXT_ORIGINATOR_REF_BYTES); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate)); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime)); - timeReferenceLow = (ma_uint32)(pMetadata->data.bext.timeReference & 0xFFFFFFFF); - timeReferenceHigh = (ma_uint32)(pMetadata->data.bext.timeReference >> 32); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, timeReferenceLow); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, timeReferenceHigh); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.version); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.bext.pUMID, MA_DR_WAV_BEXT_UMID_BYTES); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessValue); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessRange); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxTruePeakLevel); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness); - MA_DR_WAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf)); - bytesWritten += ma_dr_wav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf)); - if (pMetadata->data.bext.codingHistorySize > 0) { - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize); - } - } break; - case ma_dr_wav_metadata_type_unknown: - { - if (pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_top_level) { - chunkSize = pMetadata->data.unknown.dataSizeInBytes; - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.unknown.id, 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes); - } - } break; - default: break; - } - if ((chunkSize % 2) != 0) { - bytesWritten += ma_dr_wav__write_or_count_byte(pWav, 0); - } - } - if (hasListInfo) { - ma_uint32 chunkSize = 4; - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - ma_dr_wav_metadata* pMetadata = &pMetadatas[iMetadata]; - if ((pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings)) { - chunkSize += 8; - chunkSize += pMetadata->data.infoText.stringLength + 1; - } else if (pMetadata->type == ma_dr_wav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_inside_info_list) { - chunkSize += 8; - chunkSize += pMetadata->data.unknown.dataSizeInBytes; - } - if ((chunkSize % 2) != 0) { - chunkSize += 1; - } - } - bytesWritten += ma_dr_wav__write_or_count(pWav, "LIST", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count(pWav, "INFO", 4); - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - ma_dr_wav_metadata* pMetadata = &pMetadatas[iMetadata]; - ma_uint32 subchunkSize = 0; - if (pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings) { - const char* pID = NULL; - switch (pMetadata->type) { - case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; - case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; - case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; - case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; - case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; - case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; - case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; - case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; - case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; - default: break; - } - MA_DR_WAV_ASSERT(pID != NULL); - if (pMetadata->data.infoText.stringLength) { - subchunkSize = pMetadata->data.infoText.stringLength + 1; - bytesWritten += ma_dr_wav__write_or_count(pWav, pID, 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.infoText.pString, pMetadata->data.infoText.stringLength); - bytesWritten += ma_dr_wav__write_or_count_byte(pWav, '\0'); - } - } else if (pMetadata->type == ma_dr_wav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_inside_info_list) { - if (pMetadata->data.unknown.dataSizeInBytes) { - subchunkSize = pMetadata->data.unknown.dataSizeInBytes; - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.unknown.id, 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.unknown.dataSizeInBytes); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize); - } - } - if ((subchunkSize % 2) != 0) { - bytesWritten += ma_dr_wav__write_or_count_byte(pWav, 0); - } - } - } - if (hasListAdtl) { - ma_uint32 chunkSize = 4; - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - ma_dr_wav_metadata* pMetadata = &pMetadatas[iMetadata]; - switch (pMetadata->type) - { - case ma_dr_wav_metadata_type_list_label: - case ma_dr_wav_metadata_type_list_note: - { - chunkSize += 8; - chunkSize += MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES; - if (pMetadata->data.labelOrNote.stringLength > 0) { - chunkSize += pMetadata->data.labelOrNote.stringLength + 1; - } - } break; - case ma_dr_wav_metadata_type_list_labelled_cue_region: - { - chunkSize += 8; - chunkSize += MA_DR_WAV_LIST_LABELLED_TEXT_BYTES; - if (pMetadata->data.labelledCueRegion.stringLength > 0) { - chunkSize += pMetadata->data.labelledCueRegion.stringLength + 1; - } - } break; - case ma_dr_wav_metadata_type_unknown: - { - if (pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_inside_adtl_list) { - chunkSize += 8; - chunkSize += pMetadata->data.unknown.dataSizeInBytes; - } - } break; - default: break; - } - if ((chunkSize % 2) != 0) { - chunkSize += 1; - } - } - bytesWritten += ma_dr_wav__write_or_count(pWav, "LIST", 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, chunkSize); - bytesWritten += ma_dr_wav__write_or_count(pWav, "adtl", 4); - for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) { - ma_dr_wav_metadata* pMetadata = &pMetadatas[iMetadata]; - ma_uint32 subchunkSize = 0; - switch (pMetadata->type) - { - case ma_dr_wav_metadata_type_list_label: - case ma_dr_wav_metadata_type_list_note: - { - if (pMetadata->data.labelOrNote.stringLength > 0) { - const char *pID = NULL; - if (pMetadata->type == ma_dr_wav_metadata_type_list_label) { - pID = "labl"; - } - else if (pMetadata->type == ma_dr_wav_metadata_type_list_note) { - pID = "note"; - } - MA_DR_WAV_ASSERT(pID != NULL); - MA_DR_WAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - subchunkSize = MA_DR_WAV_LIST_LABEL_OR_NOTE_BYTES; - bytesWritten += ma_dr_wav__write_or_count(pWav, pID, 4); - subchunkSize += pMetadata->data.labelOrNote.stringLength + 1; - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelOrNote.cuePointId); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.labelOrNote.pString, pMetadata->data.labelOrNote.stringLength); - bytesWritten += ma_dr_wav__write_or_count_byte(pWav, '\0'); - } - } break; - case ma_dr_wav_metadata_type_list_labelled_cue_region: - { - subchunkSize = MA_DR_WAV_LIST_LABELLED_TEXT_BYTES; - bytesWritten += ma_dr_wav__write_or_count(pWav, "ltxt", 4); - if (pMetadata->data.labelledCueRegion.stringLength > 0) { - subchunkSize += pMetadata->data.labelledCueRegion.stringLength + 1; - } - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.cuePointId); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.sampleLength); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.labelledCueRegion.purposeId, 4); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.country); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.language); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.dialect); - bytesWritten += ma_dr_wav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.codePage); - if (pMetadata->data.labelledCueRegion.stringLength > 0) { - MA_DR_WAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.labelledCueRegion.pString, pMetadata->data.labelledCueRegion.stringLength); - bytesWritten += ma_dr_wav__write_or_count_byte(pWav, '\0'); - } - } break; - case ma_dr_wav_metadata_type_unknown: - { - if (pMetadata->data.unknown.chunkLocation == ma_dr_wav_metadata_location_inside_adtl_list) { - subchunkSize = pMetadata->data.unknown.dataSizeInBytes; - MA_DR_WAV_ASSERT(pMetadata->data.unknown.pData != NULL); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.unknown.id, 4); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, subchunkSize); - bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize); - } - } break; - default: break; - } - if ((subchunkSize % 2) != 0) { - bytesWritten += ma_dr_wav__write_or_count_byte(pWav, 0); - } - } - } - MA_DR_WAV_ASSERT((bytesWritten % 2) == 0); - return bytesWritten; -} -MA_PRIVATE ma_uint32 ma_dr_wav__riff_chunk_size_riff(ma_uint64 dataChunkSize, ma_dr_wav_metadata* pMetadata, ma_uint32 metadataCount) -{ - ma_uint64 chunkSize = 4 + 24 + (ma_uint64)ma_dr_wav__write_or_count_metadata(NULL, pMetadata, metadataCount) + 8 + dataChunkSize + ma_dr_wav__chunk_padding_size_riff(dataChunkSize); + drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); if (chunkSize > 0xFFFFFFFFUL) { chunkSize = 0xFFFFFFFFUL; } - return (ma_uint32)chunkSize; + return (drwav_uint32)chunkSize; } -MA_PRIVATE ma_uint32 ma_dr_wav__data_chunk_size_riff(ma_uint64 dataChunkSize) +DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize) { if (dataChunkSize <= 0xFFFFFFFFUL) { - return (ma_uint32)dataChunkSize; + return (drwav_uint32)dataChunkSize; } else { return 0xFFFFFFFFUL; } } -MA_PRIVATE ma_uint64 ma_dr_wav__riff_chunk_size_w64(ma_uint64 dataChunkSize) +DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize) { - ma_uint64 dataSubchunkPaddingSize = ma_dr_wav__chunk_padding_size_w64(dataChunkSize); + drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize); return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; } -MA_PRIVATE ma_uint64 ma_dr_wav__data_chunk_size_w64(ma_uint64 dataChunkSize) +DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize) { return 24 + dataChunkSize; } -MA_PRIVATE ma_uint64 ma_dr_wav__riff_chunk_size_rf64(ma_uint64 dataChunkSize, ma_dr_wav_metadata *metadata, ma_uint32 numMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize) { - ma_uint64 chunkSize = 4 + 36 + 24 + (ma_uint64)ma_dr_wav__write_or_count_metadata(NULL, metadata, numMetadata) + 8 + dataChunkSize + ma_dr_wav__chunk_padding_size_riff(dataChunkSize); + drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); if (chunkSize > 0xFFFFFFFFUL) { chunkSize = 0xFFFFFFFFUL; } return chunkSize; } -MA_PRIVATE ma_uint64 ma_dr_wav__data_chunk_size_rf64(ma_uint64 dataChunkSize) +DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize) { return dataChunkSize; } -MA_PRIVATE ma_bool32 ma_dr_wav_preinit_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_bool32 isSequential, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + return pWav->onWrite(pWav->pUserData, pData, dataSize); +} +DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + if (!drwav__is_little_endian()) { + value = drwav__bswap16(value); + } + return drwav__write(pWav, &value, 2); +} +DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + if (!drwav__is_little_endian()) { + value = drwav__bswap32(value); + } + return drwav__write(pWav, &value, 4); +} +DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + if (!drwav__is_little_endian()) { + value = drwav__bswap64(value); + } + return drwav__write(pWav, &value, 8); +} +DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pWav == NULL || onWrite == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } if (!isSequential && onSeek == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - if (pFormat->format == MA_DR_WAVE_FORMAT_EXTENSIBLE) { - return MA_FALSE; + if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { + return DRWAV_FALSE; } - if (pFormat->format == MA_DR_WAVE_FORMAT_ADPCM || pFormat->format == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - return MA_FALSE; + if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) { + return DRWAV_FALSE; } - MA_DR_WAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); pWav->onWrite = onWrite; pWav->onSeek = onSeek; pWav->pUserData = pUserData; - pWav->allocationCallbacks = ma_dr_wav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { - return MA_FALSE; + return DRWAV_FALSE; } - pWav->fmt.formatTag = (ma_uint16)pFormat->format; - pWav->fmt.channels = (ma_uint16)pFormat->channels; + pWav->fmt.formatTag = (drwav_uint16)pFormat->format; + pWav->fmt.channels = (drwav_uint16)pFormat->channels; pWav->fmt.sampleRate = pFormat->sampleRate; - pWav->fmt.avgBytesPerSec = (ma_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8); - pWav->fmt.blockAlign = (ma_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8); - pWav->fmt.bitsPerSample = (ma_uint16)pFormat->bitsPerSample; + pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8); + pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8); + pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; pWav->fmt.extendedSize = 0; pWav->isSequentialWrite = isSequential; - return MA_TRUE; + return DRWAV_TRUE; } -MA_PRIVATE ma_bool32 ma_dr_wav_init_write__internal(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount) +DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) { size_t runningPos = 0; - ma_uint64 initialDataChunkSize = 0; - ma_uint64 chunkSizeFMT; + drwav_uint64 initialDataChunkSize = 0; + drwav_uint64 chunkSizeFMT; if (pWav->isSequentialWrite) { initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; - if (pFormat->container == ma_dr_wav_container_riff) { + if (pFormat->container == drwav_container_riff) { if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { - return MA_FALSE; + return DRWAV_FALSE; } } } pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; - if (pFormat->container == ma_dr_wav_container_riff) { - ma_uint32 chunkSizeRIFF = 28 + (ma_uint32)initialDataChunkSize; - runningPos += ma_dr_wav__write(pWav, "RIFF", 4); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, chunkSizeRIFF); - runningPos += ma_dr_wav__write(pWav, "WAVE", 4); - } else if (pFormat->container == ma_dr_wav_container_w64) { - ma_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; - runningPos += ma_dr_wav__write(pWav, ma_dr_wavGUID_W64_RIFF, 16); - runningPos += ma_dr_wav__write_u64ne_to_le(pWav, chunkSizeRIFF); - runningPos += ma_dr_wav__write(pWav, ma_dr_wavGUID_W64_WAVE, 16); - } else if (pFormat->container == ma_dr_wav_container_rf64) { - runningPos += ma_dr_wav__write(pWav, "RF64", 4); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, 0xFFFFFFFF); - runningPos += ma_dr_wav__write(pWav, "WAVE", 4); - } else { - return MA_FALSE; + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; + runningPos += drwav__write(pWav, "RIFF", 4); + runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF); + runningPos += drwav__write(pWav, "WAVE", 4); + } else if (pFormat->container == drwav_container_w64) { + drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; + runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF); + runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16); + } else if (pFormat->container == drwav_container_rf64) { + runningPos += drwav__write(pWav, "RF64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); + runningPos += drwav__write(pWav, "WAVE", 4); } - if (pFormat->container == ma_dr_wav_container_rf64) { - ma_uint32 initialds64ChunkSize = 28; - ma_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; - runningPos += ma_dr_wav__write(pWav, "ds64", 4); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, initialds64ChunkSize); - runningPos += ma_dr_wav__write_u64ne_to_le(pWav, initialRiffChunkSize); - runningPos += ma_dr_wav__write_u64ne_to_le(pWav, initialDataChunkSize); - runningPos += ma_dr_wav__write_u64ne_to_le(pWav, totalSampleCount); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, 0); + if (pFormat->container == drwav_container_rf64) { + drwav_uint32 initialds64ChunkSize = 28; + drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; + runningPos += drwav__write(pWav, "ds64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); + runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); + runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); + runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); + runningPos += drwav__write_u32ne_to_le(pWav, 0); } - if (pFormat->container == ma_dr_wav_container_riff || pFormat->container == ma_dr_wav_container_rf64) { + if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) { chunkSizeFMT = 16; - runningPos += ma_dr_wav__write(pWav, "fmt ", 4); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, (ma_uint32)chunkSizeFMT); - } else if (pFormat->container == ma_dr_wav_container_w64) { + runningPos += drwav__write(pWav, "fmt ", 4); + runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT); + } else if (pFormat->container == drwav_container_w64) { chunkSizeFMT = 40; - runningPos += ma_dr_wav__write(pWav, ma_dr_wavGUID_W64_FMT, 16); - runningPos += ma_dr_wav__write_u64ne_to_le(pWav, chunkSizeFMT); + runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT); } - runningPos += ma_dr_wav__write_u16ne_to_le(pWav, pWav->fmt.formatTag); - runningPos += ma_dr_wav__write_u16ne_to_le(pWav, pWav->fmt.channels); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec); - runningPos += ma_dr_wav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign); - runningPos += ma_dr_wav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample); - if (!pWav->isSequentialWrite && pWav->pMetadata != NULL && pWav->metadataCount > 0 && (pFormat->container == ma_dr_wav_container_riff || pFormat->container == ma_dr_wav_container_rf64)) { - runningPos += ma_dr_wav__write_or_count_metadata(pWav, pWav->pMetadata, pWav->metadataCount); - } - pWav->dataChunkDataPos = runningPos; - if (pFormat->container == ma_dr_wav_container_riff) { - ma_uint32 chunkSizeDATA = (ma_uint32)initialDataChunkSize; - runningPos += ma_dr_wav__write(pWav, "data", 4); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, chunkSizeDATA); - } else if (pFormat->container == ma_dr_wav_container_w64) { - ma_uint64 chunkSizeDATA = 24 + initialDataChunkSize; - runningPos += ma_dr_wav__write(pWav, ma_dr_wavGUID_W64_DATA, 16); - runningPos += ma_dr_wav__write_u64ne_to_le(pWav, chunkSizeDATA); - } else if (pFormat->container == ma_dr_wav_container_rf64) { - runningPos += ma_dr_wav__write(pWav, "data", 4); - runningPos += ma_dr_wav__write_u32ne_to_le(pWav, 0xFFFFFFFF); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels); + runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate); + runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample); + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize; + runningPos += drwav__write(pWav, "data", 4); + runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA); + } else if (pFormat->container == drwav_container_w64) { + drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; + runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA); + } else if (pFormat->container == drwav_container_rf64) { + runningPos += drwav__write(pWav, "data", 4); + runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); } pWav->container = pFormat->container; - pWav->channels = (ma_uint16)pFormat->channels; + pWav->channels = (drwav_uint16)pFormat->channels; pWav->sampleRate = pFormat->sampleRate; - pWav->bitsPerSample = (ma_uint16)pFormat->bitsPerSample; - pWav->translatedFormatTag = (ma_uint16)pFormat->format; + pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->translatedFormatTag = (drwav_uint16)pFormat->format; pWav->dataChunkDataPos = runningPos; - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_bool32 ma_dr_wav_init_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit_write(pWav, pFormat, MA_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { - return MA_FALSE; + if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; } - return ma_dr_wav_init_write__internal(pWav, pFormat, 0); + return drwav_init_write__internal(pWav, pFormat, 0); } -MA_API ma_bool32 ma_dr_wav_init_write_sequential(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit_write(pWav, pFormat, MA_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { - return MA_FALSE; + if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; } - return ma_dr_wav_init_write__internal(pWav, pFormat, totalSampleCount); + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); } -MA_API ma_bool32 ma_dr_wav_init_write_sequential_pcm_frames(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pFormat == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - return ma_dr_wav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks); + return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_write_with_metadata(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks, ma_dr_wav_metadata* pMetadata, ma_uint32 metadataCount) +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) { - if (!ma_dr_wav_preinit_write(pWav, pFormat, MA_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { - return MA_FALSE; - } - pWav->pMetadata = pMetadata; - pWav->metadataCount = metadataCount; - return ma_dr_wav_init_write__internal(pWav, pFormat, 0); -} -MA_API ma_uint64 ma_dr_wav_target_write_size_bytes(const ma_dr_wav_data_format* pFormat, ma_uint64 totalFrameCount, ma_dr_wav_metadata* pMetadata, ma_uint32 metadataCount) -{ - ma_uint64 targetDataSizeBytes = (ma_uint64)((ma_int64)totalFrameCount * pFormat->channels * pFormat->bitsPerSample/8.0); - ma_uint64 riffChunkSizeBytes; - ma_uint64 fileSizeBytes = 0; - if (pFormat->container == ma_dr_wav_container_riff) { - riffChunkSizeBytes = ma_dr_wav__riff_chunk_size_riff(targetDataSizeBytes, pMetadata, metadataCount); + drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0); + drwav_uint64 riffChunkSizeBytes; + drwav_uint64 fileSizeBytes = 0; + if (pFormat->container == drwav_container_riff) { + riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes); fileSizeBytes = (8 + riffChunkSizeBytes); - } else if (pFormat->container == ma_dr_wav_container_w64) { - riffChunkSizeBytes = ma_dr_wav__riff_chunk_size_w64(targetDataSizeBytes); + } else if (pFormat->container == drwav_container_w64) { + riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes); fileSizeBytes = riffChunkSizeBytes; - } else if (pFormat->container == ma_dr_wav_container_rf64) { - riffChunkSizeBytes = ma_dr_wav__riff_chunk_size_rf64(targetDataSizeBytes, pMetadata, metadataCount); + } else if (pFormat->container == drwav_container_rf64) { + riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes); fileSizeBytes = (8 + riffChunkSizeBytes); } return fileSizeBytes; } -#ifndef MA_DR_WAV_NO_STDIO -MA_PRIVATE size_t ma_dr_wav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) +#ifndef DR_WAV_NO_STDIO +#include +DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRWAV_SUCCESS; + #ifdef EPERM + case EPERM: return DRWAV_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRWAV_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRWAV_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRWAV_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRWAV_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRWAV_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRWAV_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRWAV_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRWAV_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRWAV_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRWAV_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRWAV_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRWAV_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRWAV_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRWAV_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRWAV_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRWAV_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRWAV_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRWAV_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRWAV_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRWAV_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRWAV_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRWAV_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRWAV_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRWAV_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRWAV_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRWAV_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRWAV_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRWAV_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRWAV_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRWAV_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRWAV_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRWAV_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRWAV_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRWAV_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRWAV_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRWAV_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRWAV_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRWAV_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRWAV_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRWAV_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRWAV_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRWAV_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRWAV_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRWAV_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRWAV_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRWAV_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRWAV_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRWAV_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRWAV_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRWAV_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRWAV_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRWAV_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRWAV_ERROR; + #endif + #ifdef EADV + case EADV: return DRWAV_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRWAV_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRWAV_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRWAV_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRWAV_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRWAV_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRWAV_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRWAV_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRWAV_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRWAV_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRWAV_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRWAV_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRWAV_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRWAV_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRWAV_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRWAV_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRWAV_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRWAV_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRWAV_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRWAV_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRWAV_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRWAV_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRWAV_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRWAV_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRWAV_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRWAV_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRWAV_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRWAV_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRWAV_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRWAV_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRWAV_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRWAV_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRWAV_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRWAV_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRWAV_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRWAV_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRWAV_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRWAV_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRWAV_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRWAV_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRWAV_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRWAV_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRWAV_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRWAV_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRWAV_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRWAV_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRWAV_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRWAV_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRWAV_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRWAV_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRWAV_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRWAV_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRWAV_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRWAV_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRWAV_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRWAV_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRWAV_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRWAV_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRWAV_ERROR; + #endif + default: return DRWAV_ERROR; + } +} +DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err; +#endif + if (ppFile != NULL) { + *ppFile = NULL; + } + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } +#if defined(_MSC_VER) && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drwav_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drwav_result result = drwav_result_from_errno(errno); + if (result == DRWAV_SUCCESS) { + result = DRWAV_ERROR; + } + return result; + } +#endif + return DRWAV_SUCCESS; +} +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRWAV_HAS_WFOPEN + #endif +#endif +DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; + } + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } +#if defined(DRWAV_HAS_WFOPEN) + { + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drwav_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drwav_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + DRWAV_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drwav_result_from_errno(errno); + } + pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRWAV_OUT_OF_MEMORY; + } + pFilePathTemp = pFilePath; + DRWAV_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + *ppFile = fopen(pFilePathMB, pOpenModeMB); + drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + if (*ppFile == NULL) { + return DRWAV_ERROR; + } +#endif + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) { return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); } -MA_PRIVATE size_t ma_dr_wav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) +DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) { return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); } -MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_stdio(void* pUserData, int offset, ma_dr_wav_seek_origin origin) +DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_wav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } -MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); + return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); } -MA_PRIVATE ma_bool32 ma_dr_wav_init_file__internal_FILE(ma_dr_wav* pWav, FILE* pFile, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_bool32 result; - result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); - if (result != MA_TRUE) { + drwav_bool32 result; + result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRWAV_TRUE) { fclose(pFile); return result; } - result = ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); - if (result != MA_TRUE) { + result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); + if (result != DRWAV_TRUE) { fclose(pFile); return result; } - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_bool32 ma_dr_wav_init_file_ex(ma_dr_wav* pWav, const char* filename, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; - if (ma_fopen(&pFile, filename, "rb") != MA_SUCCESS) { - return MA_FALSE; + if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; } - return ma_dr_wav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); + return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); } -#ifndef MA_DR_WAV_NO_WCHAR -MA_API ma_bool32 ma_dr_wav_init_file_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); + return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_file_ex_w(ma_dr_wav* pWav, const wchar_t* filename, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; - if (ma_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != MA_SUCCESS) { - return MA_FALSE; + if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; } - return ma_dr_wav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); + return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); } -#endif -MA_API ma_bool32 ma_dr_wav_init_file_with_metadata(ma_dr_wav* pWav, const char* filename, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { - FILE* pFile; - if (ma_fopen(&pFile, filename, "rb") != MA_SUCCESS) { - return MA_FALSE; - } - return ma_dr_wav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA, pAllocationCallbacks); -} -#ifndef MA_DR_WAV_NO_WCHAR -MA_API ma_bool32 ma_dr_wav_init_file_with_metadata_w(ma_dr_wav* pWav, const wchar_t* filename, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) -{ - FILE* pFile; - if (ma_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != MA_SUCCESS) { - return MA_FALSE; - } - return ma_dr_wav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA, pAllocationCallbacks); -} -#endif -MA_PRIVATE ma_bool32 ma_dr_wav_init_file_write__internal_FILE(ma_dr_wav* pWav, FILE* pFile, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_bool32 isSequential, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_bool32 result; - result = ma_dr_wav_preinit_write(pWav, pFormat, isSequential, ma_dr_wav__on_write_stdio, ma_dr_wav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); - if (result != MA_TRUE) { + drwav_bool32 result; + result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRWAV_TRUE) { fclose(pFile); return result; } - result = ma_dr_wav_init_write__internal(pWav, pFormat, totalSampleCount); - if (result != MA_TRUE) { + result = drwav_init_write__internal(pWav, pFormat, totalSampleCount); + if (result != DRWAV_TRUE) { fclose(pFile); return result; } - return MA_TRUE; + return DRWAV_TRUE; } -MA_PRIVATE ma_bool32 ma_dr_wav_init_file_write__internal(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_bool32 isSequential, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; - if (ma_fopen(&pFile, filename, "wb") != MA_SUCCESS) { - return MA_FALSE; + if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; } - return ma_dr_wav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); + return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); } -#ifndef MA_DR_WAV_NO_WCHAR -MA_PRIVATE ma_bool32 ma_dr_wav_init_file_write_w__internal(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_bool32 isSequential, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; - if (ma_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != MA_SUCCESS) { - return MA_FALSE; + if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; } - return ma_dr_wav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); + return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); } -#endif -MA_API ma_bool32 ma_dr_wav_init_file_write(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_file_write__internal(pWav, filename, pFormat, 0, MA_FALSE, pAllocationCallbacks); + return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, MA_TRUE, pAllocationCallbacks); + return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential_pcm_frames(ma_dr_wav* pWav, const char* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pFormat == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - return ma_dr_wav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); + return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } -#ifndef MA_DR_WAV_NO_WCHAR -MA_API ma_bool32 ma_dr_wav_init_file_write_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_file_write_w__internal(pWav, filename, pFormat, 0, MA_FALSE, pAllocationCallbacks); + return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, MA_TRUE, pAllocationCallbacks); + return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_file_write_sequential_pcm_frames_w(ma_dr_wav* pWav, const wchar_t* filename, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pFormat == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - return ma_dr_wav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); + return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } #endif -#endif -MA_PRIVATE size_t ma_dr_wav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { - ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + drwav* pWav = (drwav*)pUserData; size_t bytesRemaining; - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos); + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos); bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } if (bytesToRead > 0) { - MA_DR_WAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead); + DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead); pWav->memoryStream.currentReadPos += bytesToRead; } return bytesToRead; } -MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory(void* pUserData, int offset, ma_dr_wav_seek_origin origin) +DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) { - ma_dr_wav* pWav = (ma_dr_wav*)pUserData; - MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { + drwav* pWav = (drwav*)pUserData; + DRWAV_ASSERT(pWav != NULL); + if (origin == drwav_seek_origin_current) { if (offset > 0) { if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { - return MA_FALSE; + return DRWAV_FALSE; } } else { if (pWav->memoryStream.currentReadPos < (size_t)-offset) { - return MA_FALSE; + return DRWAV_FALSE; } } pWav->memoryStream.currentReadPos += offset; } else { - if ((ma_uint32)offset <= pWav->memoryStream.dataSize) { + if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) { pWav->memoryStream.currentReadPos = offset; } else { - return MA_FALSE; + return DRWAV_FALSE; } } - return MA_TRUE; + return DRWAV_TRUE; } -MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) +DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) { - ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + drwav* pWav = (drwav*)pUserData; size_t bytesRemaining; - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos; if (bytesRemaining < bytesToWrite) { void* pNewData; @@ -80673,14 +50865,14 @@ MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataI if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) { newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite; } - pNewData = ma_dr_wav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks); + pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks); if (pNewData == NULL) { return 0; } *pWav->memoryStreamWrite.ppData = pNewData; pWav->memoryStreamWrite.dataCapacity = newDataCapacity; } - MA_DR_WAV_COPY_MEMORY(((ma_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite); + DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite); pWav->memoryStreamWrite.currentWritePos += bytesToWrite; if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) { pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos; @@ -80688,11 +50880,11 @@ MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataI *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize; return bytesToWrite; } -MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory_write(void* pUserData, int offset, ma_dr_wav_seek_origin origin) +DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) { - ma_dr_wav* pWav = (ma_dr_wav*)pUserData; - MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { + drwav* pWav = (drwav*)pUserData; + DRWAV_ASSERT(pWav != NULL); + if (origin == drwav_seek_origin_current) { if (offset > 0) { if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); @@ -80704,156 +50896,133 @@ MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory_write(void* pUserData, int offset } pWav->memoryStreamWrite.currentWritePos += offset; } else { - if ((ma_uint32)offset <= pWav->memoryStreamWrite.dataSize) { + if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) { pWav->memoryStreamWrite.currentWritePos = offset; } else { pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; } } - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_bool32 ma_dr_wav_init_memory(ma_dr_wav* pWav, const void* data, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks); + return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_memory_ex(ma_dr_wav* pWav, const void* data, size_t dataSize, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { if (data == NULL || dataSize == 0) { - return MA_FALSE; + return DRWAV_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { - return MA_FALSE; + if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) { + return DRWAV_FALSE; } - pWav->memoryStream.data = (const ma_uint8*)data; + pWav->memoryStream.data = (const drwav_uint8*)data; pWav->memoryStream.dataSize = dataSize; pWav->memoryStream.currentReadPos = 0; - return ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); + return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); } -MA_API ma_bool32 ma_dr_wav_init_memory_with_metadata(ma_dr_wav* pWav, const void* data, size_t dataSize, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (data == NULL || dataSize == 0) { - return MA_FALSE; - } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { - return MA_FALSE; - } - pWav->memoryStream.data = (const ma_uint8*)data; - pWav->memoryStream.dataSize = dataSize; - pWav->memoryStream.currentReadPos = 0; - return ma_dr_wav_init__internal(pWav, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA); -} -MA_PRIVATE ma_bool32 ma_dr_wav_init_memory_write__internal(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_bool32 isSequential, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_PRIVATE drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { if (ppData == NULL || pDataSize == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } *ppData = NULL; *pDataSize = 0; - if (!ma_dr_wav_preinit_write(pWav, pFormat, isSequential, ma_dr_wav__on_write_memory, ma_dr_wav__on_seek_memory_write, pWav, pAllocationCallbacks)) { - return MA_FALSE; + if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) { + return DRWAV_FALSE; } pWav->memoryStreamWrite.ppData = ppData; pWav->memoryStreamWrite.pDataSize = pDataSize; pWav->memoryStreamWrite.dataSize = 0; pWav->memoryStreamWrite.dataCapacity = 0; pWav->memoryStreamWrite.currentWritePos = 0; - return ma_dr_wav_init_write__internal(pWav, pFormat, totalSampleCount); + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); } -MA_API ma_bool32 ma_dr_wav_init_memory_write(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, MA_FALSE, pAllocationCallbacks); + return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, MA_TRUE, pAllocationCallbacks); + return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential_pcm_frames(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pFormat == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - return ma_dr_wav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); + return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } -MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav) +DRWAV_API drwav_result drwav_uninit(drwav* pWav) { - ma_result result = MA_SUCCESS; + drwav_result result = DRWAV_SUCCESS; if (pWav == NULL) { - return MA_INVALID_ARGS; + return DRWAV_INVALID_ARGS; } if (pWav->onWrite != NULL) { - ma_uint32 paddingSize = 0; - if (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rf64) { - paddingSize = ma_dr_wav__chunk_padding_size_riff(pWav->dataChunkDataSize); + drwav_uint32 paddingSize = 0; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize); } else { - paddingSize = ma_dr_wav__chunk_padding_size_w64(pWav->dataChunkDataSize); + paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize); } if (paddingSize > 0) { - ma_uint64 paddingData = 0; - ma_dr_wav__write(pWav, &paddingData, paddingSize); + drwav_uint64 paddingData = 0; + drwav__write(pWav, &paddingData, paddingSize); } if (pWav->onSeek && !pWav->isSequentialWrite) { - if (pWav->container == ma_dr_wav_container_riff) { - if (pWav->onSeek(pWav->pUserData, 4, ma_dr_wav_seek_origin_start)) { - ma_uint32 riffChunkSize = ma_dr_wav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); - ma_dr_wav__write_u32ne_to_le(pWav, riffChunkSize); + if (pWav->container == drwav_container_riff) { + if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { + drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize); + drwav__write_u32ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, ma_dr_wav_seek_origin_start)) { - ma_uint32 dataChunkSize = ma_dr_wav__data_chunk_size_riff(pWav->dataChunkDataSize); - ma_dr_wav__write_u32ne_to_le(pWav, dataChunkSize); + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) { + drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize); + drwav__write_u32ne_to_le(pWav, dataChunkSize); } - } else if (pWav->container == ma_dr_wav_container_w64) { - if (pWav->onSeek(pWav->pUserData, 16, ma_dr_wav_seek_origin_start)) { - ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_w64(pWav->dataChunkDataSize); - ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); + } else if (pWav->container == drwav_container_w64) { + if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, ma_dr_wav_seek_origin_start)) { - ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_w64(pWav->dataChunkDataSize); - ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, dataChunkSize); } - } else if (pWav->container == ma_dr_wav_container_rf64) { + } else if (pWav->container == drwav_container_rf64) { int ds64BodyPos = 12 + 8; - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, ma_dr_wav_seek_origin_start)) { - ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); - ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, ma_dr_wav_seek_origin_start)) { - ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_rf64(pWav->dataChunkDataSize); - ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, dataChunkSize); } } } if (pWav->isSequentialWrite) { if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) { - result = MA_INVALID_FILE; + result = DRWAV_INVALID_FILE; } } - } else { - ma_dr_wav_free(pWav->pMetadata, &pWav->allocationCallbacks); } -#ifndef MA_DR_WAV_NO_STDIO - if (pWav->onRead == ma_dr_wav__on_read_stdio || pWav->onWrite == ma_dr_wav__on_write_stdio) { +#ifndef DR_WAV_NO_STDIO + if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { fclose((FILE*)pWav->pUserData); } #endif return result; } -MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBufferOut) +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { size_t bytesRead; - ma_uint32 bytesPerFrame; if (pWav == NULL || bytesToRead == 0) { return 0; } if (bytesToRead > pWav->bytesRemaining) { bytesToRead = (size_t)pWav->bytesRemaining; } - if (bytesToRead == 0) { - return 0; - } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; - } if (pBufferOut != NULL) { bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); } else { @@ -80863,13 +51032,13 @@ MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBuf if (bytesToSeek > 0x7FFFFFFF) { bytesToSeek = 0x7FFFFFFF; } - if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) { break; } bytesRead += bytesToSeek; } while (bytesRead < bytesToRead) { - ma_uint8 buffer[4096]; + drwav_uint8 buffer[4096]; size_t bytesSeeked; size_t bytesToSeek = (bytesToRead - bytesRead); if (bytesToSeek > sizeof(buffer)) { @@ -80882,202 +51051,140 @@ MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBuf } } } - pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; pWav->bytesRemaining -= bytesRead; return bytesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_le(ma_dr_wav* pWav, ma_uint64 framesToRead, void* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { - ma_uint32 bytesPerFrame; - ma_uint64 bytesToRead; - ma_uint64 framesRemainingInFile; + drwav_uint32 bytesPerFrame; + drwav_uint64 bytesToRead; if (pWav == NULL || framesToRead == 0) { return 0; } - if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { return 0; } - framesRemainingInFile = pWav->totalPCMFrameCount - pWav->readCursorInPCMFrames; - if (framesToRead > framesRemainingInFile) { - framesToRead = framesRemainingInFile; - } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } bytesToRead = framesToRead * bytesPerFrame; - if (bytesToRead > MA_SIZE_MAX) { - bytesToRead = (MA_SIZE_MAX / bytesPerFrame) * bytesPerFrame; + if (bytesToRead > DRWAV_SIZE_MAX) { + bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; } if (bytesToRead == 0) { return 0; } - return ma_dr_wav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame; + return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_be(ma_dr_wav* pWav, ma_uint64 framesToRead, void* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); if (pBufferOut != NULL) { - ma_uint32 bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; - } - ma_dr_wav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels); + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); } return framesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToRead, void* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { - ma_uint64 framesRead = 0; - if (ma_dr_wav_is_container_be(pWav->container)) { - if (pWav->container != ma_dr_wav_container_aiff || pWav->aiff.isLE == MA_FALSE) { - if (ma_dr_wav__is_little_endian()) { - framesRead = ma_dr_wav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); - } else { - framesRead = ma_dr_wav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); - } - goto post_process; - } - } - if (ma_dr_wav__is_little_endian()) { - framesRead = ma_dr_wav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + if (drwav__is_little_endian()) { + return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); } else { - framesRead = ma_dr_wav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); + return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); } - post_process: - { - if (pWav->container == ma_dr_wav_container_aiff && pWav->bitsPerSample == 8 && pWav->aiff.isUnsigned == MA_FALSE) { - if (pBufferOut != NULL) { - ma_uint64 iSample; - for (iSample = 0; iSample < framesRead * pWav->channels; iSample += 1) { - ((ma_uint8*)pBufferOut)[iSample] += 128; - } - } - } - } - return framesRead; } -MA_PRIVATE ma_bool32 ma_dr_wav_seek_to_first_pcm_frame(ma_dr_wav* pWav) +DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) { if (pWav->onWrite != NULL) { - return MA_FALSE; + return DRWAV_FALSE; } - if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, ma_dr_wav_seek_origin_start)) { - return MA_FALSE; + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { + return DRWAV_FALSE; } - if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { - MA_DR_WAV_ZERO_OBJECT(&pWav->msadpcm); - } else if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - MA_DR_WAV_ZERO_OBJECT(&pWav->ima); + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + pWav->compressed.iCurrentPCMFrame = 0; + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + DRWAV_ZERO_OBJECT(&pWav->msadpcm); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + DRWAV_ZERO_OBJECT(&pWav->ima); } else { - MA_DR_WAV_ASSERT(MA_FALSE); + DRWAV_ASSERT(DRWAV_FALSE); } } - pWav->readCursorInPCMFrames = 0; pWav->bytesRemaining = pWav->dataChunkDataSize; - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFrameIndex) +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex) { if (pWav == NULL || pWav->onSeek == NULL) { - return MA_FALSE; + return DRWAV_FALSE; } if (pWav->onWrite != NULL) { - return MA_FALSE; + return DRWAV_FALSE; } if (pWav->totalPCMFrameCount == 0) { - return MA_TRUE; + return DRWAV_TRUE; } - if (targetFrameIndex > pWav->totalPCMFrameCount) { - targetFrameIndex = pWav->totalPCMFrameCount; + if (targetFrameIndex >= pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount - 1; } - if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { - if (targetFrameIndex < pWav->readCursorInPCMFrames) { - if (!ma_dr_wav_seek_to_first_pcm_frame(pWav)) { - return MA_FALSE; + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) { + if (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; } } - if (targetFrameIndex > pWav->readCursorInPCMFrames) { - ma_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames; - ma_int16 devnull[2048]; + if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) { + drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame; + drwav_int16 devnull[2048]; while (offsetInFrames > 0) { - ma_uint64 framesRead = 0; - ma_uint64 framesToRead = offsetInFrames; - if (framesToRead > ma_dr_wav_countof(devnull)/pWav->channels) { - framesToRead = ma_dr_wav_countof(devnull)/pWav->channels; + drwav_uint64 framesRead = 0; + drwav_uint64 framesToRead = offsetInFrames; + if (framesToRead > drwav_countof(devnull)/pWav->channels) { + framesToRead = drwav_countof(devnull)/pWav->channels; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { - framesRead = ma_dr_wav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull); - } else if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - framesRead = ma_dr_wav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull); } else { - MA_DR_WAV_ASSERT(MA_FALSE); + DRWAV_ASSERT(DRWAV_FALSE); } if (framesRead != framesToRead) { - return MA_FALSE; + return DRWAV_FALSE; } offsetInFrames -= framesRead; } } } else { - ma_uint64 totalSizeInBytes; - ma_uint64 currentBytePos; - ma_uint64 targetBytePos; - ma_uint64 offset; - ma_uint32 bytesPerFrame; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return MA_FALSE; - } - totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame; + drwav_uint64 totalSizeInBytes; + drwav_uint64 currentBytePos; + drwav_uint64 targetBytePos; + drwav_uint64 offset; + totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - targetBytePos = targetFrameIndex * bytesPerFrame; + targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); if (currentBytePos < targetBytePos) { offset = (targetBytePos - currentBytePos); } else { - if (!ma_dr_wav_seek_to_first_pcm_frame(pWav)) { - return MA_FALSE; + if (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; } offset = targetBytePos; } while (offset > 0) { int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); - if (!pWav->onSeek(pWav->pUserData, offset32, ma_dr_wav_seek_origin_current)) { - return MA_FALSE; + if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { + return DRWAV_FALSE; } - pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; - pWav->bytesRemaining -= offset32; - offset -= offset32; + pWav->bytesRemaining -= offset32; + offset -= offset32; } } - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_result ma_dr_wav_get_cursor_in_pcm_frames(ma_dr_wav* pWav, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - *pCursor = 0; - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - *pCursor = pWav->readCursorInPCMFrames; - return MA_SUCCESS; -} -MA_API ma_result ma_dr_wav_get_length_in_pcm_frames(ma_dr_wav* pWav, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - *pLength = 0; - if (pWav == NULL) { - return MA_INVALID_ARGS; - } - *pLength = pWav->totalPCMFrameCount; - return MA_SUCCESS; -} -MA_API size_t ma_dr_wav_write_raw(ma_dr_wav* pWav, size_t bytesToWrite, const void* pData) +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) { size_t bytesWritten; if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { @@ -81087,26 +51194,26 @@ MA_API size_t ma_dr_wav_write_raw(ma_dr_wav* pWav, size_t bytesToWrite, const vo pWav->dataChunkDataSize += bytesWritten; return bytesWritten; } -MA_API ma_uint64 ma_dr_wav_write_pcm_frames_le(ma_dr_wav* pWav, ma_uint64 framesToWrite, const void* pData) +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) { - ma_uint64 bytesToWrite; - ma_uint64 bytesWritten; - const ma_uint8* pRunningData; + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + const drwav_uint8* pRunningData; if (pWav == NULL || framesToWrite == 0 || pData == NULL) { return 0; } bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); - if (bytesToWrite > MA_SIZE_MAX) { + if (bytesToWrite > DRWAV_SIZE_MAX) { return 0; } bytesWritten = 0; - pRunningData = (const ma_uint8*)pData; + pRunningData = (const drwav_uint8*)pData; while (bytesToWrite > 0) { size_t bytesJustWritten; - ma_uint64 bytesToWriteThisIteration; + drwav_uint64 bytesToWriteThisIteration; bytesToWriteThisIteration = bytesToWrite; - MA_DR_WAV_ASSERT(bytesToWriteThisIteration <= MA_SIZE_MAX); - bytesJustWritten = ma_dr_wav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); if (bytesJustWritten == 0) { break; } @@ -81116,39 +51223,36 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames_le(ma_dr_wav* pWav, ma_uint64 frames } return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; } -MA_API ma_uint64 ma_dr_wav_write_pcm_frames_be(ma_dr_wav* pWav, ma_uint64 framesToWrite, const void* pData) +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) { - ma_uint64 bytesToWrite; - ma_uint64 bytesWritten; - ma_uint32 bytesPerSample; - const ma_uint8* pRunningData; + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + drwav_uint32 bytesPerSample; + const drwav_uint8* pRunningData; if (pWav == NULL || framesToWrite == 0 || pData == NULL) { return 0; } bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); - if (bytesToWrite > MA_SIZE_MAX) { + if (bytesToWrite > DRWAV_SIZE_MAX) { return 0; } bytesWritten = 0; - pRunningData = (const ma_uint8*)pData; - bytesPerSample = ma_dr_wav_get_bytes_per_pcm_frame(pWav) / pWav->channels; - if (bytesPerSample == 0) { - return 0; - } + pRunningData = (const drwav_uint8*)pData; + bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; while (bytesToWrite > 0) { - ma_uint8 temp[4096]; - ma_uint32 sampleCount; + drwav_uint8 temp[4096]; + drwav_uint32 sampleCount; size_t bytesJustWritten; - ma_uint64 bytesToWriteThisIteration; + drwav_uint64 bytesToWriteThisIteration; bytesToWriteThisIteration = bytesToWrite; - MA_DR_WAV_ASSERT(bytesToWriteThisIteration <= MA_SIZE_MAX); + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); sampleCount = sizeof(temp)/bytesPerSample; - if (bytesToWriteThisIteration > ((ma_uint64)sampleCount)*bytesPerSample) { - bytesToWriteThisIteration = ((ma_uint64)sampleCount)*bytesPerSample; + if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) { + bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample; } - MA_DR_WAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); - ma_dr_wav__bswap_samples(temp, sampleCount, bytesPerSample); - bytesJustWritten = ma_dr_wav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); + DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); + drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag); + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); if (bytesJustWritten == 0) { break; } @@ -81158,79 +51262,67 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames_be(ma_dr_wav* pWav, ma_uint64 frames } return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; } -MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToWrite, const void* pData) +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) { - if (ma_dr_wav__is_little_endian()) { - return ma_dr_wav_write_pcm_frames_le(pWav, framesToWrite, pData); + if (drwav__is_little_endian()) { + return drwav_write_pcm_frames_le(pWav, framesToWrite, pData); } else { - return ma_dr_wav_write_pcm_frames_be(pWav, framesToWrite, pData); + return drwav_write_pcm_frames_be(pWav, framesToWrite, pData); } } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 totalFramesRead = 0; - static ma_int32 adaptationTable[] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 - }; - static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; - static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(framesToRead > 0); - while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { - MA_DR_WAV_ASSERT(framesToRead > 0); + drwav_uint64 totalFramesRead = 0; + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + DRWAV_ASSERT(framesToRead > 0); if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { if (pWav->channels == 1) { - ma_uint8 header[7]; + drwav_uint8 header[7]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalFramesRead; } pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); pWav->msadpcm.predictor[0] = header[0]; - pWav->msadpcm.delta[0] = ma_dr_wav_bytes_to_s16(header + 1); - pWav->msadpcm.prevFrames[0][1] = (ma_int32)ma_dr_wav_bytes_to_s16(header + 3); - pWav->msadpcm.prevFrames[0][0] = (ma_int32)ma_dr_wav_bytes_to_s16(header + 5); + pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 1); + pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 3); + pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 5); pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.cachedFrameCount = 2; - if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table)) { - return totalFramesRead; - } } else { - ma_uint8 header[14]; + drwav_uint8 header[14]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalFramesRead; } pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); pWav->msadpcm.predictor[0] = header[0]; pWav->msadpcm.predictor[1] = header[1]; - pWav->msadpcm.delta[0] = ma_dr_wav_bytes_to_s16(header + 2); - pWav->msadpcm.delta[1] = ma_dr_wav_bytes_to_s16(header + 4); - pWav->msadpcm.prevFrames[0][1] = (ma_int32)ma_dr_wav_bytes_to_s16(header + 6); - pWav->msadpcm.prevFrames[1][1] = (ma_int32)ma_dr_wav_bytes_to_s16(header + 8); - pWav->msadpcm.prevFrames[0][0] = (ma_int32)ma_dr_wav_bytes_to_s16(header + 10); - pWav->msadpcm.prevFrames[1][0] = (ma_int32)ma_dr_wav_bytes_to_s16(header + 12); + pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 2); + pWav->msadpcm.delta[1] = drwav_bytes_to_s16(header + 4); + pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 6); + pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav_bytes_to_s16(header + 8); + pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 10); + pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav_bytes_to_s16(header + 12); pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0]; pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0]; pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; pWav->msadpcm.cachedFrameCount = 2; - if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff2Table)) { - return totalFramesRead; - } } } - while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { if (pBufferOut != NULL) { - ma_uint32 iSample = 0; + drwav_uint32 iSample = 0; for (iSample = 0; iSample < pWav->channels; iSample += 1) { - pBufferOut[iSample] = (ma_int16)pWav->msadpcm.cachedFrames[(ma_dr_wav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample]; + pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample]; } pBufferOut += pWav->channels; } framesToRead -= 1; totalFramesRead += 1; - pWav->readCursorInPCMFrames += 1; + pWav->compressed.iCurrentPCMFrame += 1; pWav->msadpcm.cachedFrameCount -= 1; } if (framesToRead == 0) { @@ -81240,9 +51332,15 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ if (pWav->msadpcm.bytesRemainingInBlock == 0) { continue; } else { - ma_uint8 nibbles; - ma_int32 nibble0; - ma_int32 nibble1; + static drwav_int32 adaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + drwav_uint8 nibbles; + drwav_int32 nibble0; + drwav_int32 nibble1; if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { return totalFramesRead; } @@ -81250,11 +51348,11 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } if (pWav->channels == 1) { - ma_int32 newSample0; - ma_int32 newSample1; + drwav_int32 newSample0; + drwav_int32 newSample1; newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample0 += nibble0 * pWav->msadpcm.delta[0]; - newSample0 = ma_dr_wav_clamp(newSample0, -32768, 32767); + newSample0 = drwav_clamp(newSample0, -32768, 32767); pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; if (pWav->msadpcm.delta[0] < 16) { pWav->msadpcm.delta[0] = 16; @@ -81263,7 +51361,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.prevFrames[0][1] = newSample0; newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample1 += nibble1 * pWav->msadpcm.delta[0]; - newSample1 = ma_dr_wav_clamp(newSample1, -32768, 32767); + newSample1 = drwav_clamp(newSample1, -32768, 32767); pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8; if (pWav->msadpcm.delta[0] < 16) { pWav->msadpcm.delta[0] = 16; @@ -81274,11 +51372,11 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.cachedFrames[3] = newSample1; pWav->msadpcm.cachedFrameCount = 2; } else { - ma_int32 newSample0; - ma_int32 newSample1; + drwav_int32 newSample0; + drwav_int32 newSample1; newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample0 += nibble0 * pWav->msadpcm.delta[0]; - newSample0 = ma_dr_wav_clamp(newSample0, -32768, 32767); + newSample0 = drwav_clamp(newSample0, -32768, 32767); pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; if (pWav->msadpcm.delta[0] < 16) { pWav->msadpcm.delta[0] = 16; @@ -81287,7 +51385,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.prevFrames[0][1] = newSample0; newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; newSample1 += nibble1 * pWav->msadpcm.delta[1]; - newSample1 = ma_dr_wav_clamp(newSample1, -32768, 32767); + newSample1 = drwav_clamp(newSample1, -32768, 32767); pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8; if (pWav->msadpcm.delta[1] < 16) { pWav->msadpcm.delta[1] = 16; @@ -81303,15 +51401,15 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 totalFramesRead = 0; - ma_uint32 iChannel; - static ma_int32 indexTable[16] = { + drwav_uint64 totalFramesRead = 0; + drwav_uint32 iChannel; + static drwav_int32 indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; - static ma_int32 stepTable[89] = { + static drwav_int32 stepTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, @@ -81322,57 +51420,57 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(framesToRead > 0); - while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { - MA_DR_WAV_ASSERT(framesToRead > 0); + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + DRWAV_ASSERT(framesToRead > 0); if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { if (pWav->channels == 1) { - ma_uint8 header[4]; + drwav_uint8 header[4]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalFramesRead; } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); - if (header[2] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + if (header[2] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } - pWav->ima.predictor[0] = (ma_int16)ma_dr_wav_bytes_to_u16(header + 0); - pWav->ima.stepIndex[0] = ma_dr_wav_clamp(header[2], 0, (ma_int32)ma_dr_wav_countof(stepTable)-1); - pWav->ima.cachedFrames[ma_dr_wav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; + pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedFrameCount = 1; } else { - ma_uint8 header[8]; + drwav_uint8 header[8]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalFramesRead; } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); - if (header[2] >= ma_dr_wav_countof(stepTable) || header[6] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } - pWav->ima.predictor[0] = ma_dr_wav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = ma_dr_wav_clamp(header[2], 0, (ma_int32)ma_dr_wav_countof(stepTable)-1); - pWav->ima.predictor[1] = ma_dr_wav_bytes_to_s16(header + 4); - pWav->ima.stepIndex[1] = ma_dr_wav_clamp(header[6], 0, (ma_int32)ma_dr_wav_countof(stepTable)-1); - pWav->ima.cachedFrames[ma_dr_wav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; - pWav->ima.cachedFrames[ma_dr_wav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; + pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4); + pWav->ima.stepIndex[1] = header[6]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; pWav->ima.cachedFrameCount = 1; } } - while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { if (pBufferOut != NULL) { - ma_uint32 iSample; + drwav_uint32 iSample; for (iSample = 0; iSample < pWav->channels; iSample += 1) { - pBufferOut[iSample] = (ma_int16)pWav->ima.cachedFrames[(ma_dr_wav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample]; + pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample]; } pBufferOut += pWav->channels; } framesToRead -= 1; totalFramesRead += 1; - pWav->readCursorInPCMFrames += 1; + pWav->compressed.iCurrentPCMFrame += 1; pWav->ima.cachedFrameCount -= 1; } if (framesToRead == 0) { @@ -81384,27 +51482,27 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } else { pWav->ima.cachedFrameCount = 8; for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { - ma_uint32 iByte; - ma_uint8 nibbles[4]; + drwav_uint32 iByte; + drwav_uint8 nibbles[4]; if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { pWav->ima.cachedFrameCount = 0; return totalFramesRead; } pWav->ima.bytesRemainingInBlock -= 4; for (iByte = 0; iByte < 4; ++iByte) { - ma_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); - ma_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); - ma_int32 step = stepTable[pWav->ima.stepIndex[iChannel]]; - ma_int32 predictor = pWav->ima.predictor[iChannel]; - ma_int32 diff = step >> 3; + drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); + drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); + drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]]; + drwav_int32 predictor = pWav->ima.predictor[iChannel]; + drwav_int32 diff = step >> 3; if (nibble0 & 1) diff += step >> 2; if (nibble0 & 2) diff += step >> 1; if (nibble0 & 4) diff += step; if (nibble0 & 8) diff = -diff; - predictor = ma_dr_wav_clamp(predictor + diff, -32768, 32767); + predictor = drwav_clamp(predictor + diff, -32768, 32767); pWav->ima.predictor[iChannel] = predictor; - pWav->ima.stepIndex[iChannel] = ma_dr_wav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (ma_int32)ma_dr_wav_countof(stepTable)-1); - pWav->ima.cachedFrames[(ma_dr_wav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor; step = stepTable[pWav->ima.stepIndex[iChannel]]; predictor = pWav->ima.predictor[iChannel]; diff = step >> 3; @@ -81412,10 +51510,10 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint if (nibble1 & 2) diff += step >> 1; if (nibble1 & 4) diff += step; if (nibble1 & 8) diff = -diff; - predictor = ma_dr_wav_clamp(predictor + diff, -32768, 32767); + predictor = drwav_clamp(predictor + diff, -32768, 32767); pWav->ima.predictor[iChannel] = predictor; - pWav->ima.stepIndex[iChannel] = ma_dr_wav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (ma_int32)ma_dr_wav_countof(stepTable)-1); - pWav->ima.cachedFrames[(ma_dr_wav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor; } } } @@ -81423,8 +51521,8 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } return totalFramesRead; } -#ifndef MA_DR_WAV_NO_CONVERSION_API -static unsigned short g_ma_dr_wavAlawTable[256] = { +#ifndef DR_WAV_NO_CONVERSION_API +static unsigned short g_drwavAlawTable[256] = { 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, @@ -81442,7 +51540,7 @@ static unsigned short g_ma_dr_wavAlawTable[256] = { 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 }; -static unsigned short g_ma_dr_wavMulawTable[256] = { +static unsigned short g_drwavMulawTable[256] = { 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, @@ -81460,285 +51558,213 @@ static unsigned short g_ma_dr_wavMulawTable[256] = { 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 }; -static MA_INLINE ma_int16 ma_dr_wav__alaw_to_s16(ma_uint8 sampleIn) +static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) { - return (short)g_ma_dr_wavAlawTable[sampleIn]; + return (short)g_drwavAlawTable[sampleIn]; } -static MA_INLINE ma_int16 ma_dr_wav__mulaw_to_s16(ma_uint8 sampleIn) +static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) { - return (short)g_ma_dr_wavMulawTable[sampleIn]; + return (short)g_drwavMulawTable[sampleIn]; } -MA_PRIVATE void ma_dr_wav__pcm_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - size_t i; + unsigned int i; if (bytesPerSample == 1) { - ma_dr_wav_u8_to_s16(pOut, pIn, totalSampleCount); + drwav_u8_to_s16(pOut, pIn, totalSampleCount); return; } if (bytesPerSample == 2) { for (i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((const ma_int16*)pIn)[i]; + *pOut++ = ((const drwav_int16*)pIn)[i]; } return; } if (bytesPerSample == 3) { - ma_dr_wav_s24_to_s16(pOut, pIn, totalSampleCount); + drwav_s24_to_s16(pOut, pIn, totalSampleCount); return; } if (bytesPerSample == 4) { - ma_dr_wav_s32_to_s16(pOut, (const ma_int32*)pIn, totalSampleCount); + drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); return; } if (bytesPerSample > 8) { - MA_DR_WAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); return; } for (i = 0; i < totalSampleCount; ++i) { - ma_uint64 sample = 0; + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; unsigned int j; for (j = 0; j < bytesPerSample; j += 1) { - MA_DR_WAV_ASSERT(j < 8); - sample |= (ma_uint64)(pIn[j]) << shift; + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } pIn += j; - *pOut++ = (ma_int16)((ma_int64)sample >> 48); + *pOut++ = (drwav_int16)((drwav_int64)sample >> 48); } } -MA_PRIVATE void ma_dr_wav__ieee_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { if (bytesPerSample == 4) { - ma_dr_wav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); + drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); return; } else if (bytesPerSample == 8) { - ma_dr_wav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); + drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); return; } else { - MA_DR_WAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); return; } } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__pcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - if ((pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, pBufferOut); + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ieee(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; if (pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__alaw(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; if (pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); - #ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - pBufferOut += samplesRead; + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__mulaw(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; if (pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); - #ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - pBufferOut += samplesRead; + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { if (pWav == NULL || framesToRead == 0) { return 0; } if (pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } - if (framesToRead * pWav->channels * sizeof(ma_int16) > MA_SIZE_MAX) { - framesToRead = MA_SIZE_MAX / sizeof(ma_int16) / pWav->channels; + if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM) { - return ma_dr_wav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_IEEE_FLOAT) { - return ma_dr_wav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ALAW) { - return ma_dr_wav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_MULAW) { - return ma_dr_wav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { - return ma_dr_wav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - return ma_dr_wav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut); } return 0; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16le(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); - if (pBufferOut != NULL && ma_dr_wav__is_little_endian() == MA_FALSE) { - ma_dr_wav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); } return framesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16be(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); - if (pBufferOut != NULL && ma_dr_wav__is_little_endian() == MA_TRUE) { - ma_dr_wav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); } return framesRead; } -MA_API void ma_dr_wav_u8_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { int r; size_t i; @@ -81749,17 +51775,17 @@ MA_API void ma_dr_wav_u8_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t samp pOut[i] = (short)r; } } -MA_API void ma_dr_wav_s24_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { int r; size_t i; for (i = 0; i < sampleCount; ++i) { - int x = ((int)(((unsigned int)(((const ma_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const ma_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const ma_uint8*)pIn)[i*3+2])) << 24)) >> 8; + int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8; r = x >> 8; pOut[i] = (short)r; } } -MA_API void ma_dr_wav_s32_to_s16(ma_int16* pOut, const ma_int32* pIn, size_t sampleCount) +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) { int r; size_t i; @@ -81769,7 +51795,7 @@ MA_API void ma_dr_wav_s32_to_s16(ma_int16* pOut, const ma_int32* pIn, size_t sam pOut[i] = (short)r; } } -MA_API void ma_dr_wav_f32_to_s16(ma_int16* pOut, const float* pIn, size_t sampleCount) +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) { int r; size_t i; @@ -81783,7 +51809,7 @@ MA_API void ma_dr_wav_f32_to_s16(ma_int16* pOut, const float* pIn, size_t sample pOut[i] = (short)r; } } -MA_API void ma_dr_wav_f64_to_s16(ma_int16* pOut, const double* pIn, size_t sampleCount) +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) { int r; size_t i; @@ -81797,57 +51823,57 @@ MA_API void ma_dr_wav_f64_to_s16(ma_int16* pOut, const double* pIn, size_t sampl pOut[i] = (short)r; } } -MA_API void ma_dr_wav_alaw_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; for (i = 0; i < sampleCount; ++i) { - pOut[i] = ma_dr_wav__alaw_to_s16(pIn[i]); + pOut[i] = drwav__alaw_to_s16(pIn[i]); } } -MA_API void ma_dr_wav_mulaw_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; for (i = 0; i < sampleCount; ++i) { - pOut[i] = ma_dr_wav__mulaw_to_s16(pIn[i]); + pOut[i] = drwav__mulaw_to_s16(pIn[i]); } } -MA_PRIVATE void ma_dr_wav__pcm_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) +DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) { unsigned int i; if (bytesPerSample == 1) { - ma_dr_wav_u8_to_f32(pOut, pIn, sampleCount); + drwav_u8_to_f32(pOut, pIn, sampleCount); return; } if (bytesPerSample == 2) { - ma_dr_wav_s16_to_f32(pOut, (const ma_int16*)pIn, sampleCount); + drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); return; } if (bytesPerSample == 3) { - ma_dr_wav_s24_to_f32(pOut, pIn, sampleCount); + drwav_s24_to_f32(pOut, pIn, sampleCount); return; } if (bytesPerSample == 4) { - ma_dr_wav_s32_to_f32(pOut, (const ma_int32*)pIn, sampleCount); + drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount); return; } if (bytesPerSample > 8) { - MA_DR_WAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); return; } for (i = 0; i < sampleCount; ++i) { - ma_uint64 sample = 0; + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; unsigned int j; for (j = 0; j < bytesPerSample; j += 1) { - MA_DR_WAV_ASSERT(j < 8); - sample |= (ma_uint64)(pIn[j]) << shift; + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } pIn += j; - *pOut++ = (float)((ma_int64)sample / 9223372036854775807.0); + *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0); } } -MA_PRIVATE void ma_dr_wav__ieee_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) +DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) { if (bytesPerSample == 4) { unsigned int i; @@ -81856,246 +51882,187 @@ MA_PRIVATE void ma_dr_wav__ieee_to_f32(float* pOut, const ma_uint8* pIn, size_t } return; } else if (bytesPerSample == 8) { - ma_dr_wav_f64_to_f32(pOut, (const double*)pIn, sampleCount); + drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); return; } else { - MA_DR_WAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); return; } } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_f32__pcm(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_f32__msadpcm_ima(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) -{ - ma_uint64 totalFramesRead; - ma_int16 samples16[2048]; - totalFramesRead = 0; - while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, ma_dr_wav_countof(samples16)/pWav->channels); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); - if (framesRead == 0) { - break; - } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - ma_dr_wav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_f32__ieee(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, pBufferOut); - } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; - } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } - totalFramesRead = 0; + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_f32__alaw(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; - } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } - totalFramesRead = 0; + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); - #ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - pBufferOut += samplesRead; + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_f32__mulaw(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { return 0; } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); - #ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - pBufferOut += samplesRead; + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + totalFramesRead = 0; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + return totalFramesRead; +} +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + totalFramesRead = 0; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + return totalFramesRead; +} +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { if (pWav == NULL || framesToRead == 0) { return 0; } if (pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } - if (framesToRead * pWav->channels * sizeof(float) > MA_SIZE_MAX) { - framesToRead = MA_SIZE_MAX / sizeof(float) / pWav->channels; + if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM) { - return ma_dr_wav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - return ma_dr_wav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_IEEE_FLOAT) { - return ma_dr_wav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ALAW) { - return ma_dr_wav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_MULAW) { - return ma_dr_wav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); } return 0; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32le(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); - if (pBufferOut != NULL && ma_dr_wav__is_little_endian() == MA_FALSE) { - ma_dr_wav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); } return framesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32be(ma_dr_wav* pWav, ma_uint64 framesToRead, float* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); - if (pBufferOut != NULL && ma_dr_wav__is_little_endian() == MA_TRUE) { - ma_dr_wav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); } return framesRead; } -MA_API void ma_dr_wav_u8_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } -#ifdef MA_DR_WAV_LIBSNDFILE_COMPAT +#ifdef DR_WAV_LIBSNDFILE_COMPAT for (i = 0; i < sampleCount; ++i) { *pOut++ = (pIn[i] / 256.0f) * 2 - 1; } @@ -82108,7 +52075,7 @@ MA_API void ma_dr_wav_u8_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleC } #endif } -MA_API void ma_dr_wav_s16_to_f32(float* pOut, const ma_int16* pIn, size_t sampleCount) +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82118,7 +52085,7 @@ MA_API void ma_dr_wav_s16_to_f32(float* pOut, const ma_int16* pIn, size_t sample *pOut++ = pIn[i] * 0.000030517578125f; } } -MA_API void ma_dr_wav_s24_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82126,14 +52093,14 @@ MA_API void ma_dr_wav_s24_to_f32(float* pOut, const ma_uint8* pIn, size_t sample } for (i = 0; i < sampleCount; ++i) { double x; - ma_uint32 a = ((ma_uint32)(pIn[i*3+0]) << 8); - ma_uint32 b = ((ma_uint32)(pIn[i*3+1]) << 16); - ma_uint32 c = ((ma_uint32)(pIn[i*3+2]) << 24); - x = (double)((ma_int32)(a | b | c) >> 8); + drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) << 8); + drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16); + drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24); + x = (double)((drwav_int32)(a | b | c) >> 8); *pOut++ = (float)(x * 0.00000011920928955078125); } } -MA_API void ma_dr_wav_s32_to_f32(float* pOut, const ma_int32* pIn, size_t sampleCount) +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82143,7 +52110,7 @@ MA_API void ma_dr_wav_s32_to_f32(float* pOut, const ma_int32* pIn, size_t sample *pOut++ = (float)(pIn[i] / 2147483648.0); } } -MA_API void ma_dr_wav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82153,303 +52120,245 @@ MA_API void ma_dr_wav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCo *pOut++ = (float)pIn[i]; } } -MA_API void ma_dr_wav_alaw_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } for (i = 0; i < sampleCount; ++i) { - *pOut++ = ma_dr_wav__alaw_to_s16(pIn[i]) / 32768.0f; + *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; } } -MA_API void ma_dr_wav_mulaw_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } for (i = 0; i < sampleCount; ++i) { - *pOut++ = ma_dr_wav__mulaw_to_s16(pIn[i]) / 32768.0f; + *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; } } -MA_PRIVATE void ma_dr_wav__pcm_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { unsigned int i; if (bytesPerSample == 1) { - ma_dr_wav_u8_to_s32(pOut, pIn, totalSampleCount); + drwav_u8_to_s32(pOut, pIn, totalSampleCount); return; } if (bytesPerSample == 2) { - ma_dr_wav_s16_to_s32(pOut, (const ma_int16*)pIn, totalSampleCount); + drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); return; } if (bytesPerSample == 3) { - ma_dr_wav_s24_to_s32(pOut, pIn, totalSampleCount); + drwav_s24_to_s32(pOut, pIn, totalSampleCount); return; } if (bytesPerSample == 4) { for (i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((const ma_int32*)pIn)[i]; + *pOut++ = ((const drwav_int32*)pIn)[i]; } return; } if (bytesPerSample > 8) { - MA_DR_WAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); return; } for (i = 0; i < totalSampleCount; ++i) { - ma_uint64 sample = 0; + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; unsigned int j; for (j = 0; j < bytesPerSample; j += 1) { - MA_DR_WAV_ASSERT(j < 8); - sample |= (ma_uint64)(pIn[j]) << shift; + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } pIn += j; - *pOut++ = (ma_int32)((ma_int64)sample >> 32); + *pOut++ = (drwav_int32)((drwav_int64)sample >> 32); } } -MA_PRIVATE void ma_dr_wav__ieee_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { if (bytesPerSample == 4) { - ma_dr_wav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); + drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); return; } else if (bytesPerSample == 8) { - ma_dr_wav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); + drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); return; } else { - MA_DR_WAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); return; } } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s32__pcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, pBufferOut); + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s32__msadpcm_ima(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) -{ - ma_uint64 totalFramesRead = 0; - ma_int16 samples16[2048]; - while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, ma_dr_wav_countof(samples16)/pWav->channels); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); - if (framesRead == 0) { - break; - } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - ma_dr_wav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s32__ieee(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; - } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } - totalFramesRead = 0; + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s32__alaw(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame == 0) { - return 0; - } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } - totalFramesRead = 0; + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); - #ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - pBufferOut += samplesRead; + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s32__mulaw(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - ma_uint64 totalFramesRead; - ma_uint8 sampleData[4096] = {0}; - ma_uint32 bytesPerFrame; - ma_uint32 bytesPerSample; - ma_uint64 samplesRead; - bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - bytesPerSample = bytesPerFrame / pWav->channels; - if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { - return 0; - } totalFramesRead = 0; while (framesToRead > 0) { - ma_uint64 framesToReadThisIteration = ma_dr_wav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); if (framesRead == 0) { break; } - MA_DR_WAV_ASSERT(framesRead <= framesToReadThisIteration); - samplesRead = framesRead * pWav->channels; - if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { - MA_DR_WAV_ASSERT(MA_FALSE); - break; - } - ma_dr_wav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); - #ifdef MA_DR_WAV_LIBSNDFILE_COMPAT - { - if (pWav->container == ma_dr_wav_container_aiff) { - ma_uint64 iSample; - for (iSample = 0; iSample < samplesRead; iSample += 1) { - pBufferOut[iSample] = -pBufferOut[iSample]; - } - } - } - #endif - pBufferOut += samplesRead; + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + totalFramesRead = 0; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + return totalFramesRead; +} +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + totalFramesRead = 0; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + return totalFramesRead; +} +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { if (pWav == NULL || framesToRead == 0) { return 0; } if (pBufferOut == NULL) { - return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } - if (framesToRead * pWav->channels * sizeof(ma_int32) > MA_SIZE_MAX) { - framesToRead = MA_SIZE_MAX / sizeof(ma_int32) / pWav->channels; + if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels; } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM) { - return ma_dr_wav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { - return ma_dr_wav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_IEEE_FLOAT) { - return ma_dr_wav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ALAW) { - return ma_dr_wav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_MULAW) { - return ma_dr_wav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); } return 0; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32le(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); - if (pBufferOut != NULL && ma_dr_wav__is_little_endian() == MA_FALSE) { - ma_dr_wav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); } return framesRead; } -MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32be(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - ma_uint64 framesRead = ma_dr_wav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); - if (pBufferOut != NULL && ma_dr_wav__is_little_endian() == MA_TRUE) { - ma_dr_wav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); } return framesRead; } -MA_API void ma_dr_wav_u8_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82459,7 +52368,7 @@ MA_API void ma_dr_wav_u8_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t samp *pOut++ = ((int)pIn[i] - 128) << 24; } } -MA_API void ma_dr_wav_s16_to_s32(ma_int32* pOut, const ma_int16* pIn, size_t sampleCount) +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82469,7 +52378,7 @@ MA_API void ma_dr_wav_s16_to_s32(ma_int32* pOut, const ma_int16* pIn, size_t sam *pOut++ = pIn[i] << 16; } } -MA_API void ma_dr_wav_s24_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { @@ -82479,73 +52388,73 @@ MA_API void ma_dr_wav_s24_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sam unsigned int s0 = pIn[i*3 + 0]; unsigned int s1 = pIn[i*3 + 1]; unsigned int s2 = pIn[i*3 + 2]; - ma_int32 sample32 = (ma_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); + drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); *pOut++ = sample32; } } -MA_API void ma_dr_wav_f32_to_s32(ma_int32* pOut, const float* pIn, size_t sampleCount) +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } for (i = 0; i < sampleCount; ++i) { - *pOut++ = (ma_int32)(2147483648.0f * pIn[i]); + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); } } -MA_API void ma_dr_wav_f64_to_s32(ma_int32* pOut, const double* pIn, size_t sampleCount) +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } for (i = 0; i < sampleCount; ++i) { - *pOut++ = (ma_int32)(2147483648.0 * pIn[i]); + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); } } -MA_API void ma_dr_wav_alaw_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } for (i = 0; i < sampleCount; ++i) { - *pOut++ = ((ma_int32)ma_dr_wav__alaw_to_s16(pIn[i])) << 16; + *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; } } -MA_API void ma_dr_wav_mulaw_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { size_t i; if (pOut == NULL || pIn == NULL) { return; } for (i= 0; i < sampleCount; ++i) { - *pOut++ = ((ma_int32)ma_dr_wav__mulaw_to_s16(pIn[i])) << 16; + *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; } } -MA_PRIVATE ma_int16* ma_dr_wav__read_pcm_frames_and_close_s16(ma_dr_wav* pWav, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalFrameCount) +DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) { - ma_uint64 sampleDataSize; - ma_int16* pSampleData; - ma_uint64 framesRead; - MA_DR_WAV_ASSERT(pWav != NULL); - sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(ma_int16); - if (sampleDataSize > MA_SIZE_MAX) { - ma_dr_wav_uninit(pWav); + drwav_uint64 sampleDataSize; + drwav_int16* pSampleData; + drwav_uint64 framesRead; + DRWAV_ASSERT(pWav != NULL); + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); return NULL; } - pSampleData = (ma_int16*)ma_dr_wav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); + pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); if (pSampleData == NULL) { - ma_dr_wav_uninit(pWav); + drwav_uninit(pWav); return NULL; } - framesRead = ma_dr_wav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); if (framesRead != pWav->totalPCMFrameCount) { - ma_dr_wav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); - ma_dr_wav_uninit(pWav); + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); return NULL; } - ma_dr_wav_uninit(pWav); + drwav_uninit(pWav); if (sampleRate) { *sampleRate = pWav->sampleRate; } @@ -82557,29 +52466,29 @@ MA_PRIVATE ma_int16* ma_dr_wav__read_pcm_frames_and_close_s16(ma_dr_wav* pWav, u } return pSampleData; } -MA_PRIVATE float* ma_dr_wav__read_pcm_frames_and_close_f32(ma_dr_wav* pWav, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalFrameCount) +DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) { - ma_uint64 sampleDataSize; + drwav_uint64 sampleDataSize; float* pSampleData; - ma_uint64 framesRead; - MA_DR_WAV_ASSERT(pWav != NULL); + drwav_uint64 framesRead; + DRWAV_ASSERT(pWav != NULL); sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); - if (sampleDataSize > MA_SIZE_MAX) { - ma_dr_wav_uninit(pWav); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); return NULL; } - pSampleData = (float*)ma_dr_wav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); + pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); if (pSampleData == NULL) { - ma_dr_wav_uninit(pWav); + drwav_uninit(pWav); return NULL; } - framesRead = ma_dr_wav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); if (framesRead != pWav->totalPCMFrameCount) { - ma_dr_wav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); - ma_dr_wav_uninit(pWav); + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); return NULL; } - ma_dr_wav_uninit(pWav); + drwav_uninit(pWav); if (sampleRate) { *sampleRate = pWav->sampleRate; } @@ -82591,29 +52500,29 @@ MA_PRIVATE float* ma_dr_wav__read_pcm_frames_and_close_f32(ma_dr_wav* pWav, unsi } return pSampleData; } -MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalFrameCount) +DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) { - ma_uint64 sampleDataSize; - ma_int32* pSampleData; - ma_uint64 framesRead; - MA_DR_WAV_ASSERT(pWav != NULL); - sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(ma_int32); - if (sampleDataSize > MA_SIZE_MAX) { - ma_dr_wav_uninit(pWav); + drwav_uint64 sampleDataSize; + drwav_int32* pSampleData; + drwav_uint64 framesRead; + DRWAV_ASSERT(pWav != NULL); + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); return NULL; } - pSampleData = (ma_int32*)ma_dr_wav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); + pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); if (pSampleData == NULL) { - ma_dr_wav_uninit(pWav); + drwav_uninit(pWav); return NULL; } - framesRead = ma_dr_wav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); if (framesRead != pWav->totalPCMFrameCount) { - ma_dr_wav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); - ma_dr_wav_uninit(pWav); + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); return NULL; } - ma_dr_wav_uninit(pWav); + drwav_uninit(pWav); if (sampleRate) { *sampleRate = pWav->sampleRate; } @@ -82625,9 +52534,9 @@ MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, u } return pSampleData; } -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82637,14 +52546,14 @@ MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82654,14 +52563,14 @@ MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82671,15 +52580,15 @@ MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -#ifndef MA_DR_WAV_NO_STDIO -MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +#ifndef DR_WAV_NO_STDIO +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82689,14 +52598,14 @@ MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filenam if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_file(&wav, filename, pAllocationCallbacks)) { + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82706,14 +52615,14 @@ MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_file(&wav, filename, pAllocationCallbacks)) { + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82723,15 +52632,14 @@ MA_API ma_int32* ma_dr_wav_open_file_and_read_pcm_frames_s32(const char* filenam if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_file(&wav, filename, pAllocationCallbacks)) { + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -#ifndef MA_DR_WAV_NO_WCHAR -MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (sampleRateOut) { *sampleRateOut = 0; } @@ -82741,14 +52649,14 @@ MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16_w(const wchar_t* fi if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_file_w(&wav, filename, pAllocationCallbacks)) { + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (sampleRateOut) { *sampleRateOut = 0; } @@ -82758,14 +52666,14 @@ MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filen if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_file_w(&wav, filename, pAllocationCallbacks)) { + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (sampleRateOut) { *sampleRateOut = 0; } @@ -82775,16 +52683,15 @@ MA_API ma_int32* ma_dr_wav_open_file_and_read_pcm_frames_s32_w(const wchar_t* fi if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_file_w(&wav, filename, pAllocationCallbacks)) { + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } #endif -#endif -MA_API ma_int16* ma_dr_wav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82794,14 +52701,14 @@ MA_API ma_int16* ma_dr_wav_open_memory_and_read_pcm_frames_s16(const void* data, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82811,14 +52718,14 @@ MA_API float* ma_dr_wav_open_memory_and_read_pcm_frames_f32(const void* data, si if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { - ma_dr_wav wav; + drwav wav; if (channelsOut) { *channelsOut = 0; } @@ -82828,66 +52735,57 @@ MA_API ma_int32* ma_dr_wav_open_memory_and_read_pcm_frames_s32(const void* data, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { return NULL; } - return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } #endif -MA_API void ma_dr_wav_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { - ma_dr_wav__free_from_callbacks(p, pAllocationCallbacks); + drwav__free_from_callbacks(p, pAllocationCallbacks); } else { - ma_dr_wav__free_default(p, NULL); + drwav__free_default(p, NULL); } } -MA_API ma_uint16 ma_dr_wav_bytes_to_u16(const ma_uint8* data) +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data) { - return ((ma_uint16)data[0] << 0) | ((ma_uint16)data[1] << 8); + return (data[0] << 0) | (data[1] << 8); } -MA_API ma_int16 ma_dr_wav_bytes_to_s16(const ma_uint8* data) +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data) { - return (ma_int16)ma_dr_wav_bytes_to_u16(data); + return (short)drwav_bytes_to_u16(data); } -MA_API ma_uint32 ma_dr_wav_bytes_to_u32(const ma_uint8* data) +DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data) { - return ma_dr_wav_bytes_to_u32_le(data); + return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } -MA_API float ma_dr_wav_bytes_to_f32(const ma_uint8* data) +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data) { - union { - ma_uint32 u32; - float f32; - } value; - value.u32 = ma_dr_wav_bytes_to_u32(data); - return value.f32; + return (drwav_int32)drwav_bytes_to_u32(data); } -MA_API ma_int32 ma_dr_wav_bytes_to_s32(const ma_uint8* data) -{ - return (ma_int32)ma_dr_wav_bytes_to_u32(data); -} -MA_API ma_uint64 ma_dr_wav_bytes_to_u64(const ma_uint8* data) +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data) { return - ((ma_uint64)data[0] << 0) | ((ma_uint64)data[1] << 8) | ((ma_uint64)data[2] << 16) | ((ma_uint64)data[3] << 24) | - ((ma_uint64)data[4] << 32) | ((ma_uint64)data[5] << 40) | ((ma_uint64)data[6] << 48) | ((ma_uint64)data[7] << 56); + ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) | + ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56); } -MA_API ma_int64 ma_dr_wav_bytes_to_s64(const ma_uint8* data) +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data) { - return (ma_int64)ma_dr_wav_bytes_to_u64(data); + return (drwav_int64)drwav_bytes_to_u64(data); } -MA_API ma_bool32 ma_dr_wav_guid_equal(const ma_uint8 a[16], const ma_uint8 b[16]) +DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) { int i; for (i = 0; i < 16; i += 1) { if (a[i] != b[i]) { - return MA_FALSE; + return DRWAV_FALSE; } } - return MA_TRUE; + return DRWAV_TRUE; } -MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b) +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) { return a[0] == b[0] && @@ -82895,19 +52793,16 @@ MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b) a[2] == b[2] && a[3] == b[3]; } -#ifdef __MRC__ -#pragma options opt reset -#endif #endif /* dr_wav_c end */ -#endif /* MA_DR_WAV_IMPLEMENTATION */ +#endif /* DRWAV_IMPLEMENTATION */ #endif /* MA_NO_WAV */ #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING) -#if !defined(MA_DR_FLAC_IMPLEMENTATION) +#if !defined(DR_FLAC_IMPLEMENTATION) && !defined(DRFLAC_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */ /* dr_flac_c begin */ -#ifndef ma_dr_flac_c -#define ma_dr_flac_c +#ifndef dr_flac_c +#define dr_flac_c #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic push #if __GNUC__ >= 7 @@ -82928,60 +52823,87 @@ MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b) #endif #include #include -#if !defined(MA_DR_FLAC_NO_SIMD) - #if defined(MA_X64) || defined(MA_X86) +#ifdef _MSC_VER + #define DRFLAC_INLINE __forceinline +#elif defined(__GNUC__) + #if defined(__STRICT_ANSI__) + #define DRFLAC_INLINE __inline__ __attribute__((always_inline)) + #else + #define DRFLAC_INLINE inline __attribute__((always_inline)) + #endif +#elif defined(__WATCOMC__) + #define DRFLAC_INLINE __inline +#else + #define DRFLAC_INLINE +#endif +#if defined(__x86_64__) || defined(_M_X64) + #define DRFLAC_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRFLAC_X86 +#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64) + #define DRFLAC_ARM +#endif +#if !defined(DR_FLAC_NO_SIMD) + #if defined(DRFLAC_X64) || defined(DRFLAC_X86) #if defined(_MSC_VER) && !defined(__clang__) - #if _MSC_VER >= 1400 && !defined(MA_DR_FLAC_NO_SSE2) - #define MA_DR_FLAC_SUPPORT_SSE2 + #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2) + #define DRFLAC_SUPPORT_SSE2 #endif - #if _MSC_VER >= 1600 && !defined(MA_DR_FLAC_NO_SSE41) - #define MA_DR_FLAC_SUPPORT_SSE41 + #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) + #define DRFLAC_SUPPORT_SSE41 #endif #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) - #if defined(__SSE2__) && !defined(MA_DR_FLAC_NO_SSE2) - #define MA_DR_FLAC_SUPPORT_SSE2 + #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2) + #define DRFLAC_SUPPORT_SSE2 #endif - #if defined(__SSE4_1__) && !defined(MA_DR_FLAC_NO_SSE41) - #define MA_DR_FLAC_SUPPORT_SSE41 + #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41) + #define DRFLAC_SUPPORT_SSE41 #endif #endif #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) - #if !defined(MA_DR_FLAC_SUPPORT_SSE2) && !defined(MA_DR_FLAC_NO_SSE2) && __has_include() - #define MA_DR_FLAC_SUPPORT_SSE2 + #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include() + #define DRFLAC_SUPPORT_SSE2 #endif - #if !defined(MA_DR_FLAC_SUPPORT_SSE41) && !defined(MA_DR_FLAC_NO_SSE41) && __has_include() - #define MA_DR_FLAC_SUPPORT_SSE41 + #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include() + #define DRFLAC_SUPPORT_SSE41 #endif #endif - #if defined(MA_DR_FLAC_SUPPORT_SSE41) + #if defined(DRFLAC_SUPPORT_SSE41) #include - #elif defined(MA_DR_FLAC_SUPPORT_SSE2) + #elif defined(DRFLAC_SUPPORT_SSE2) #include #endif #endif - #if defined(MA_ARM) - #if !defined(MA_DR_FLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) - #define MA_DR_FLAC_SUPPORT_NEON + #if defined(DRFLAC_ARM) + #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + #define DRFLAC_SUPPORT_NEON + #endif + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include() + #define DRFLAC_SUPPORT_NEON + #endif + #endif + #if defined(DRFLAC_SUPPORT_NEON) #include #endif #endif #endif -#if !defined(MA_DR_FLAC_NO_SIMD) && (defined(MA_X86) || defined(MA_X64)) +#if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER >= 1400 #include - static void ma_dr_flac__cpuid(int info[4], int fid) + static void drflac__cpuid(int info[4], int fid) { __cpuid(info, fid); } #else - #define MA_DR_FLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif #else #if defined(__GNUC__) || defined(__clang__) - static void ma_dr_flac__cpuid(int info[4], int fid) + static void drflac__cpuid(int info[4], int fid) { - #if defined(MA_X86) && defined(__PIC__) + #if defined(DRFLAC_X86) && defined(__PIC__) __asm__ __volatile__ ( "xchg{l} {%%}ebx, %k1;" "cpuid;" @@ -82995,241 +52917,293 @@ MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b) #endif } #else - #define MA_DR_FLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif #endif #else - #define MA_DR_FLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif -static MA_INLINE ma_bool32 ma_dr_flac_has_sse2(void) +static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_DR_FLAC_NO_SSE2) - #if defined(MA_X64) - return MA_TRUE; +#if defined(DRFLAC_SUPPORT_SSE2) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2) + #if defined(DRFLAC_X64) + return DRFLAC_TRUE; #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) - return MA_TRUE; + return DRFLAC_TRUE; #else - #if defined(MA_DR_FLAC_NO_CPUID) - return MA_FALSE; + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; #else int info[4]; - ma_dr_flac__cpuid(info, 1); + drflac__cpuid(info, 1); return (info[3] & (1 << 26)) != 0; #endif #endif #else - return MA_FALSE; + return DRFLAC_FALSE; #endif #else - return MA_FALSE; + return DRFLAC_FALSE; #endif } -static MA_INLINE ma_bool32 ma_dr_flac_has_sse41(void) +static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) { -#if defined(MA_DR_FLAC_SUPPORT_SSE41) - #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_DR_FLAC_NO_SSE41) - #if defined(__SSE4_1__) || defined(__AVX__) - return MA_TRUE; +#if defined(DRFLAC_SUPPORT_SSE41) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41) + #if defined(DRFLAC_X64) + return DRFLAC_TRUE; + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__) + return DRFLAC_TRUE; #else - #if defined(MA_DR_FLAC_NO_CPUID) - return MA_FALSE; + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; #else int info[4]; - ma_dr_flac__cpuid(info, 1); + drflac__cpuid(info, 1); return (info[2] & (1 << 19)) != 0; #endif #endif #else - return MA_FALSE; + return DRFLAC_FALSE; #endif #else - return MA_FALSE; + return DRFLAC_FALSE; #endif } -#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(MA_X86) || defined(MA_X64)) && !defined(__clang__) - #define MA_DR_FLAC_HAS_LZCNT_INTRINSIC +#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__) + #define DRFLAC_HAS_LZCNT_INTRINSIC #elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) - #define MA_DR_FLAC_HAS_LZCNT_INTRINSIC + #define DRFLAC_HAS_LZCNT_INTRINSIC #elif defined(__clang__) #if defined(__has_builtin) #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) - #define MA_DR_FLAC_HAS_LZCNT_INTRINSIC + #define DRFLAC_HAS_LZCNT_INTRINSIC #endif #endif #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__) - #define MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC - #define MA_DR_FLAC_HAS_BYTESWAP32_INTRINSIC - #define MA_DR_FLAC_HAS_BYTESWAP64_INTRINSIC + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC #elif defined(__clang__) #if defined(__has_builtin) #if __has_builtin(__builtin_bswap16) - #define MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC #endif #if __has_builtin(__builtin_bswap32) - #define MA_DR_FLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC #endif #if __has_builtin(__builtin_bswap64) - #define MA_DR_FLAC_HAS_BYTESWAP64_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC #endif #endif #elif defined(__GNUC__) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define MA_DR_FLAC_HAS_BYTESWAP32_INTRINSIC - #define MA_DR_FLAC_HAS_BYTESWAP64_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC #endif #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #define MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC #endif #elif defined(__WATCOMC__) && defined(__386__) - #define MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC - #define MA_DR_FLAC_HAS_BYTESWAP32_INTRINSIC - #define MA_DR_FLAC_HAS_BYTESWAP64_INTRINSIC - extern __inline ma_uint16 _watcom_bswap16(ma_uint16); - extern __inline ma_uint32 _watcom_bswap32(ma_uint32); - extern __inline ma_uint64 _watcom_bswap64(ma_uint64); + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16); + extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32); + extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); #pragma aux _watcom_bswap16 = \ "xchg al, ah" \ - parm [ax] \ - value [ax] \ - modify nomemory; + parm [ax] \ + modify [ax]; #pragma aux _watcom_bswap32 = \ - "bswap eax" \ - parm [eax] \ - value [eax] \ - modify nomemory; + "bswap eax" \ + parm [eax] \ + modify [eax]; #pragma aux _watcom_bswap64 = \ "bswap eax" \ "bswap edx" \ "xchg eax,edx" \ parm [eax edx] \ - value [eax edx] \ - modify nomemory; + modify [eax edx]; #endif -#ifndef MA_DR_FLAC_ASSERT +#ifndef DRFLAC_ASSERT #include -#define MA_DR_FLAC_ASSERT(expression) assert(expression) +#define DRFLAC_ASSERT(expression) assert(expression) #endif -#ifndef MA_DR_FLAC_MALLOC -#define MA_DR_FLAC_MALLOC(sz) malloc((sz)) +#ifndef DRFLAC_MALLOC +#define DRFLAC_MALLOC(sz) malloc((sz)) #endif -#ifndef MA_DR_FLAC_REALLOC -#define MA_DR_FLAC_REALLOC(p, sz) realloc((p), (sz)) +#ifndef DRFLAC_REALLOC +#define DRFLAC_REALLOC(p, sz) realloc((p), (sz)) #endif -#ifndef MA_DR_FLAC_FREE -#define MA_DR_FLAC_FREE(p) free((p)) +#ifndef DRFLAC_FREE +#define DRFLAC_FREE(p) free((p)) #endif -#ifndef MA_DR_FLAC_COPY_MEMORY -#define MA_DR_FLAC_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#ifndef DRFLAC_COPY_MEMORY +#define DRFLAC_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) #endif -#ifndef MA_DR_FLAC_ZERO_MEMORY -#define MA_DR_FLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#ifndef DRFLAC_ZERO_MEMORY +#define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif -#ifndef MA_DR_FLAC_ZERO_OBJECT -#define MA_DR_FLAC_ZERO_OBJECT(p) MA_DR_FLAC_ZERO_MEMORY((p), sizeof(*(p))) +#ifndef DRFLAC_ZERO_OBJECT +#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p))) #endif -#define MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE 64 -#define MA_DR_FLAC_SUBFRAME_CONSTANT 0 -#define MA_DR_FLAC_SUBFRAME_VERBATIM 1 -#define MA_DR_FLAC_SUBFRAME_FIXED 8 -#define MA_DR_FLAC_SUBFRAME_LPC 32 -#define MA_DR_FLAC_SUBFRAME_RESERVED 255 -#define MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0 -#define MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1 -#define MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0 -#define MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8 -#define MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 -#define MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 -#define MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES 18 -#define MA_DR_FLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36 -#define MA_DR_FLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12 -#define ma_dr_flac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) -MA_API void ma_dr_flac_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision) +#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 +typedef drflac_int32 drflac_result; +#define DRFLAC_SUCCESS 0 +#define DRFLAC_ERROR -1 +#define DRFLAC_INVALID_ARGS -2 +#define DRFLAC_INVALID_OPERATION -3 +#define DRFLAC_OUT_OF_MEMORY -4 +#define DRFLAC_OUT_OF_RANGE -5 +#define DRFLAC_ACCESS_DENIED -6 +#define DRFLAC_DOES_NOT_EXIST -7 +#define DRFLAC_ALREADY_EXISTS -8 +#define DRFLAC_TOO_MANY_OPEN_FILES -9 +#define DRFLAC_INVALID_FILE -10 +#define DRFLAC_TOO_BIG -11 +#define DRFLAC_PATH_TOO_LONG -12 +#define DRFLAC_NAME_TOO_LONG -13 +#define DRFLAC_NOT_DIRECTORY -14 +#define DRFLAC_IS_DIRECTORY -15 +#define DRFLAC_DIRECTORY_NOT_EMPTY -16 +#define DRFLAC_END_OF_FILE -17 +#define DRFLAC_NO_SPACE -18 +#define DRFLAC_BUSY -19 +#define DRFLAC_IO_ERROR -20 +#define DRFLAC_INTERRUPT -21 +#define DRFLAC_UNAVAILABLE -22 +#define DRFLAC_ALREADY_IN_USE -23 +#define DRFLAC_BAD_ADDRESS -24 +#define DRFLAC_BAD_SEEK -25 +#define DRFLAC_BAD_PIPE -26 +#define DRFLAC_DEADLOCK -27 +#define DRFLAC_TOO_MANY_LINKS -28 +#define DRFLAC_NOT_IMPLEMENTED -29 +#define DRFLAC_NO_MESSAGE -30 +#define DRFLAC_BAD_MESSAGE -31 +#define DRFLAC_NO_DATA_AVAILABLE -32 +#define DRFLAC_INVALID_DATA -33 +#define DRFLAC_TIMEOUT -34 +#define DRFLAC_NO_NETWORK -35 +#define DRFLAC_NOT_UNIQUE -36 +#define DRFLAC_NOT_SOCKET -37 +#define DRFLAC_NO_ADDRESS -38 +#define DRFLAC_BAD_PROTOCOL -39 +#define DRFLAC_PROTOCOL_UNAVAILABLE -40 +#define DRFLAC_PROTOCOL_NOT_SUPPORTED -41 +#define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRFLAC_SOCKET_NOT_SUPPORTED -44 +#define DRFLAC_CONNECTION_RESET -45 +#define DRFLAC_ALREADY_CONNECTED -46 +#define DRFLAC_NOT_CONNECTED -47 +#define DRFLAC_CONNECTION_REFUSED -48 +#define DRFLAC_NO_HOST -49 +#define DRFLAC_IN_PROGRESS -50 +#define DRFLAC_CANCELLED -51 +#define DRFLAC_MEMORY_ALREADY_MAPPED -52 +#define DRFLAC_AT_END -53 +#define DRFLAC_CRC_MISMATCH -128 +#define DRFLAC_SUBFRAME_CONSTANT 0 +#define DRFLAC_SUBFRAME_VERBATIM 1 +#define DRFLAC_SUBFRAME_FIXED 8 +#define DRFLAC_SUBFRAME_LPC 32 +#define DRFLAC_SUBFRAME_RESERVED 255 +#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0 +#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1 +#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0 +#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8 +#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 +#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 +#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision) { if (pMajor) { - *pMajor = MA_DR_FLAC_VERSION_MAJOR; + *pMajor = DRFLAC_VERSION_MAJOR; } if (pMinor) { - *pMinor = MA_DR_FLAC_VERSION_MINOR; + *pMinor = DRFLAC_VERSION_MINOR; } if (pRevision) { - *pRevision = MA_DR_FLAC_VERSION_REVISION; + *pRevision = DRFLAC_VERSION_REVISION; } } -MA_API const char* ma_dr_flac_version_string(void) +DRFLAC_API const char* drflac_version_string(void) { - return MA_DR_FLAC_VERSION_STRING; + return DRFLAC_VERSION_STRING; } #if defined(__has_feature) #if __has_feature(thread_sanitizer) - #define MA_DR_FLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) + #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) #else - #define MA_DR_FLAC_NO_THREAD_SANITIZE + #define DRFLAC_NO_THREAD_SANITIZE #endif #else - #define MA_DR_FLAC_NO_THREAD_SANITIZE + #define DRFLAC_NO_THREAD_SANITIZE #endif -#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) -static ma_bool32 ma_dr_flac__gIsLZCNTSupported = MA_FALSE; +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; #endif -#ifndef MA_DR_FLAC_NO_CPUID -static ma_bool32 ma_dr_flac__gIsSSE2Supported = MA_FALSE; -static ma_bool32 ma_dr_flac__gIsSSE41Supported = MA_FALSE; -MA_DR_FLAC_NO_THREAD_SANITIZE static void ma_dr_flac__init_cpu_caps(void) +#ifndef DRFLAC_NO_CPUID +static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE; +static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE; +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) { - static ma_bool32 isCPUCapsInitialized = MA_FALSE; + static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE; if (!isCPUCapsInitialized) { -#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) int info[4] = {0}; - ma_dr_flac__cpuid(info, 0x80000001); - ma_dr_flac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; + drflac__cpuid(info, 0x80000001); + drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; #endif - ma_dr_flac__gIsSSE2Supported = ma_dr_flac_has_sse2(); - ma_dr_flac__gIsSSE41Supported = ma_dr_flac_has_sse41(); - isCPUCapsInitialized = MA_TRUE; + drflac__gIsSSE2Supported = drflac_has_sse2(); + drflac__gIsSSE41Supported = drflac_has_sse41(); + isCPUCapsInitialized = DRFLAC_TRUE; } } #else -static ma_bool32 ma_dr_flac__gIsNEONSupported = MA_FALSE; -static MA_INLINE ma_bool32 ma_dr_flac__has_neon(void) +static drflac_bool32 drflac__gIsNEONSupported = DRFLAC_FALSE; +static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void) { -#if defined(MA_DR_FLAC_SUPPORT_NEON) - #if defined(MA_ARM) && !defined(MA_DR_FLAC_NO_NEON) +#if defined(DRFLAC_SUPPORT_NEON) + #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON) #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) - return MA_TRUE; + return DRFLAC_TRUE; #else - return MA_FALSE; + return DRFLAC_FALSE; #endif #else - return MA_FALSE; + return DRFLAC_FALSE; #endif #else - return MA_FALSE; + return DRFLAC_FALSE; #endif } -MA_DR_FLAC_NO_THREAD_SANITIZE static void ma_dr_flac__init_cpu_caps(void) +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) { - ma_dr_flac__gIsNEONSupported = ma_dr_flac__has_neon(); -#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) && defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) - ma_dr_flac__gIsLZCNTSupported = MA_TRUE; + drflac__gIsNEONSupported = drflac__has_neon(); +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) + drflac__gIsLZCNTSupported = DRFLAC_TRUE; #endif } #endif -static MA_INLINE ma_bool32 ma_dr_flac__is_little_endian(void) +static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void) { -#if defined(MA_X86) || defined(MA_X64) - return MA_TRUE; +#if defined(DRFLAC_X86) || defined(DRFLAC_X64) + return DRFLAC_TRUE; #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN - return MA_TRUE; + return DRFLAC_TRUE; #else int n = 1; return (*(char*)&n) == 1; #endif } -static MA_INLINE ma_uint16 ma_dr_flac__swap_endian_uint16(ma_uint16 n) +static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) { -#ifdef MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC +#ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_ushort(n); #elif defined(__GNUC__) || defined(__clang__) @@ -83244,16 +53218,16 @@ static MA_INLINE ma_uint16 ma_dr_flac__swap_endian_uint16(ma_uint16 n) ((n & 0x00FF) << 8); #endif } -static MA_INLINE ma_uint32 ma_dr_flac__swap_endian_uint32(ma_uint32 n) +static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) { -#ifdef MA_DR_FLAC_HAS_BYTESWAP32_INTRINSIC +#ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_ulong(n); #elif defined(__GNUC__) || defined(__clang__) - #if defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(MA_64BIT) - ma_uint32 r; + #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT) + drflac_uint32 r; __asm__ __volatile__ ( - #if defined(MA_64BIT) + #if defined(DRFLAC_64BIT) "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) #else "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) @@ -83275,9 +53249,9 @@ static MA_INLINE ma_uint32 ma_dr_flac__swap_endian_uint32(ma_uint32 n) ((n & 0x000000FF) << 24); #endif } -static MA_INLINE ma_uint64 ma_dr_flac__swap_endian_uint64(ma_uint64 n) +static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) { -#ifdef MA_DR_FLAC_HAS_BYTESWAP64_INTRINSIC +#ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_uint64(n); #elif defined(__GNUC__) || defined(__clang__) @@ -83288,64 +53262,54 @@ static MA_INLINE ma_uint64 ma_dr_flac__swap_endian_uint64(ma_uint64 n) #error "This compiler does not support the byte swap intrinsic." #endif #else - return ((n & ((ma_uint64)0xFF000000 << 32)) >> 56) | - ((n & ((ma_uint64)0x00FF0000 << 32)) >> 40) | - ((n & ((ma_uint64)0x0000FF00 << 32)) >> 24) | - ((n & ((ma_uint64)0x000000FF << 32)) >> 8) | - ((n & ((ma_uint64)0xFF000000 )) << 8) | - ((n & ((ma_uint64)0x00FF0000 )) << 24) | - ((n & ((ma_uint64)0x0000FF00 )) << 40) | - ((n & ((ma_uint64)0x000000FF )) << 56); + return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) | + ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) | + ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) | + ((n & ((drflac_uint64)0x000000FF << 32)) >> 8) | + ((n & ((drflac_uint64)0xFF000000 )) << 8) | + ((n & ((drflac_uint64)0x00FF0000 )) << 24) | + ((n & ((drflac_uint64)0x0000FF00 )) << 40) | + ((n & ((drflac_uint64)0x000000FF )) << 56); #endif } -static MA_INLINE ma_uint16 ma_dr_flac__be2host_16(ma_uint16 n) +static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n) { - if (ma_dr_flac__is_little_endian()) { - return ma_dr_flac__swap_endian_uint16(n); + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint16(n); } return n; } -static MA_INLINE ma_uint32 ma_dr_flac__be2host_32(ma_uint32 n) +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) { - if (ma_dr_flac__is_little_endian()) { - return ma_dr_flac__swap_endian_uint32(n); + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint32(n); } return n; } -static MA_INLINE ma_uint32 ma_dr_flac__be2host_32_ptr_unaligned(const void* pData) +static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) { - const ma_uint8* pNum = (ma_uint8*)pData; - return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3); -} -static MA_INLINE ma_uint64 ma_dr_flac__be2host_64(ma_uint64 n) -{ - if (ma_dr_flac__is_little_endian()) { - return ma_dr_flac__swap_endian_uint64(n); + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint64(n); } return n; } -static MA_INLINE ma_uint32 ma_dr_flac__le2host_32(ma_uint32 n) +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) { - if (!ma_dr_flac__is_little_endian()) { - return ma_dr_flac__swap_endian_uint32(n); + if (!drflac__is_little_endian()) { + return drflac__swap_endian_uint32(n); } return n; } -static MA_INLINE ma_uint32 ma_dr_flac__le2host_32_ptr_unaligned(const void* pData) +static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) { - const ma_uint8* pNum = (ma_uint8*)pData; - return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24; -} -static MA_INLINE ma_uint32 ma_dr_flac__unsynchsafe_32(ma_uint32 n) -{ - ma_uint32 result = 0; + drflac_uint32 result = 0; result |= (n & 0x7F000000) >> 3; result |= (n & 0x007F0000) >> 2; result |= (n & 0x00007F00) >> 1; result |= (n & 0x0000007F) >> 0; return result; } -static ma_uint8 ma_dr_flac__crc8_table[] = { +static drflac_uint8 drflac__crc8_table[] = { 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, @@ -83363,7 +53327,7 @@ static ma_uint8 ma_dr_flac__crc8_table[] = { 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 }; -static ma_uint16 ma_dr_flac__crc16_table[] = { +static drflac_uint16 drflac__crc16_table[] = { 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, @@ -83397,22 +53361,22 @@ static ma_uint16 ma_dr_flac__crc16_table[] = { 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202 }; -static MA_INLINE ma_uint8 ma_dr_flac_crc8_byte(ma_uint8 crc, ma_uint8 data) +static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data) { - return ma_dr_flac__crc8_table[crc ^ data]; + return drflac__crc8_table[crc ^ data]; } -static MA_INLINE ma_uint8 ma_dr_flac_crc8(ma_uint8 crc, ma_uint32 data, ma_uint32 count) +static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count) { -#ifdef MA_DR_FLAC_NO_CRC +#ifdef DR_FLAC_NO_CRC (void)crc; (void)data; (void)count; return 0; #else #if 0 - ma_uint8 p = 0x07; + drflac_uint8 p = 0x07; for (int i = count-1; i >= 0; --i) { - ma_uint8 bit = (data & (1 << i)) >> i; + drflac_uint8 bit = (data & (1 << i)) >> i; if (crc & 0x80) { crc = ((crc << 1) | bit) ^ p; } else { @@ -83421,75 +53385,75 @@ static MA_INLINE ma_uint8 ma_dr_flac_crc8(ma_uint8 crc, ma_uint32 data, ma_uint3 } return crc; #else - ma_uint32 wholeBytes; - ma_uint32 leftoverBits; - ma_uint64 leftoverDataMask; - static ma_uint64 leftoverDataMaskTable[8] = { + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - MA_DR_FLAC_ASSERT(count <= 32); + DRFLAC_ASSERT(count <= 32); wholeBytes = count >> 3; leftoverBits = count - (wholeBytes*8); leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { - case 4: crc = ma_dr_flac_crc8_byte(crc, (ma_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); - case 3: crc = ma_dr_flac_crc8_byte(crc, (ma_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); - case 2: crc = ma_dr_flac_crc8_byte(crc, (ma_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); - case 1: crc = ma_dr_flac_crc8_byte(crc, (ma_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); - case 0: if (leftoverBits > 0) crc = (ma_uint8)((crc << leftoverBits) ^ ma_dr_flac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]); + case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]); } return crc; #endif #endif } -static MA_INLINE ma_uint16 ma_dr_flac_crc16_byte(ma_uint16 crc, ma_uint8 data) +static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data) { - return (crc << 8) ^ ma_dr_flac__crc16_table[(ma_uint8)(crc >> 8) ^ data]; + return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data]; } -static MA_INLINE ma_uint16 ma_dr_flac_crc16_cache(ma_uint16 crc, ma_dr_flac_cache_t data) +static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data) { -#ifdef MA_64BIT - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 56) & 0xFF)); - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 48) & 0xFF)); - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 40) & 0xFF)); - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 32) & 0xFF)); +#ifdef DRFLAC_64BIT + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); #endif - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 24) & 0xFF)); - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 16) & 0xFF)); - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 8) & 0xFF)); - crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 0) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); return crc; } -static MA_INLINE ma_uint16 ma_dr_flac_crc16_bytes(ma_uint16 crc, ma_dr_flac_cache_t data, ma_uint32 byteCount) +static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount) { switch (byteCount) { -#ifdef MA_64BIT - case 8: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 56) & 0xFF)); - case 7: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 48) & 0xFF)); - case 6: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 40) & 0xFF)); - case 5: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 32) & 0xFF)); +#ifdef DRFLAC_64BIT + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); #endif - case 4: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 24) & 0xFF)); - case 3: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 16) & 0xFF)); - case 2: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 8) & 0xFF)); - case 1: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data >> 0) & 0xFF)); + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); } return crc; } #if 0 -static MA_INLINE ma_uint16 ma_dr_flac_crc16__32bit(ma_uint16 crc, ma_uint32 data, ma_uint32 count) +static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count) { -#ifdef MA_DR_FLAC_NO_CRC +#ifdef DR_FLAC_NO_CRC (void)crc; (void)data; (void)count; return 0; #else #if 0 - ma_uint16 p = 0x8005; + drflac_uint16 p = 0x8005; for (int i = count-1; i >= 0; --i) { - ma_uint16 bit = (data & (1ULL << i)) >> i; + drflac_uint16 bit = (data & (1ULL << i)) >> i; if (r & 0x8000) { r = ((r << 1) | bit) ^ p; } else { @@ -83498,433 +53462,426 @@ static MA_INLINE ma_uint16 ma_dr_flac_crc16__32bit(ma_uint16 crc, ma_uint32 data } return crc; #else - ma_uint32 wholeBytes; - ma_uint32 leftoverBits; - ma_uint64 leftoverDataMask; - static ma_uint64 leftoverDataMaskTable[8] = { + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - MA_DR_FLAC_ASSERT(count <= 64); + DRFLAC_ASSERT(count <= 64); wholeBytes = count >> 3; leftoverBits = count & 7; leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { default: - case 4: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); - case 3: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); - case 2: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); - case 1: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); - case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ ma_dr_flac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; } return crc; #endif #endif } -static MA_INLINE ma_uint16 ma_dr_flac_crc16__64bit(ma_uint16 crc, ma_uint64 data, ma_uint32 count) +static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count) { -#ifdef MA_DR_FLAC_NO_CRC +#ifdef DR_FLAC_NO_CRC (void)crc; (void)data; (void)count; return 0; #else - ma_uint32 wholeBytes; - ma_uint32 leftoverBits; - ma_uint64 leftoverDataMask; - static ma_uint64 leftoverDataMaskTable[8] = { + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - MA_DR_FLAC_ASSERT(count <= 64); + DRFLAC_ASSERT(count <= 64); wholeBytes = count >> 3; leftoverBits = count & 7; leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { default: - case 8: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits))); - case 7: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits))); - case 6: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits))); - case 5: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits))); - case 4: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0xFF000000 ) << leftoverBits)) >> (24 + leftoverBits))); - case 3: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0x00FF0000 ) << leftoverBits)) >> (16 + leftoverBits))); - case 2: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0x0000FF00 ) << leftoverBits)) >> ( 8 + leftoverBits))); - case 1: crc = ma_dr_flac_crc16_byte(crc, (ma_uint8)((data & (((ma_uint64)0x000000FF ) << leftoverBits)) >> ( 0 + leftoverBits))); - case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ ma_dr_flac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits))); + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits))); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits))); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits))); + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 ) << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 ) << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 ) << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF ) << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; } return crc; #endif } -static MA_INLINE ma_uint16 ma_dr_flac_crc16(ma_uint16 crc, ma_dr_flac_cache_t data, ma_uint32 count) +static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count) { -#ifdef MA_64BIT - return ma_dr_flac_crc16__64bit(crc, data, count); +#ifdef DRFLAC_64BIT + return drflac_crc16__64bit(crc, data, count); #else - return ma_dr_flac_crc16__32bit(crc, data, count); + return drflac_crc16__32bit(crc, data, count); #endif } #endif -#ifdef MA_64BIT -#define ma_dr_flac__be2host__cache_line ma_dr_flac__be2host_64 +#ifdef DRFLAC_64BIT +#define drflac__be2host__cache_line drflac__be2host_64 #else -#define ma_dr_flac__be2host__cache_line ma_dr_flac__be2host_32 +#define drflac__be2host__cache_line drflac__be2host_32 #endif -#define MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) -#define MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) -#define MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) (MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits) -#define MA_DR_FLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~((~(ma_dr_flac_cache_t)0) >> (_bitCount))) -#define MA_DR_FLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) -#define MA_DR_FLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & MA_DR_FLAC_CACHE_L1_SELECTION_MASK(_bitCount)) -#define MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (MA_DR_FLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> MA_DR_FLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount))) -#define MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(MA_DR_FLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (MA_DR_FLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs)-1))) -#define MA_DR_FLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2)) -#define MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs) (MA_DR_FLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) -#define MA_DR_FLAC_CACHE_L2_LINES_REMAINING(bs) (MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) -#ifndef MA_DR_FLAC_NO_CRC -static MA_INLINE void ma_dr_flac__reset_crc16(ma_dr_flac_bs* bs) +#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) +#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) +#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits) +#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~((~(drflac_cache_t)0) >> (_bitCount))) +#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) +#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount))) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1))) +#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2)) +#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) +#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) +#ifndef DR_FLAC_NO_CRC +static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs) { bs->crc16 = 0; bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; } -static MA_INLINE void ma_dr_flac__update_crc16(ma_dr_flac_bs* bs) +static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs) { if (bs->crc16CacheIgnoredBytes == 0) { - bs->crc16 = ma_dr_flac_crc16_cache(bs->crc16, bs->crc16Cache); + bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache); } else { - bs->crc16 = ma_dr_flac_crc16_bytes(bs->crc16, bs->crc16Cache, MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); bs->crc16CacheIgnoredBytes = 0; } } -static MA_INLINE ma_uint16 ma_dr_flac__flush_crc16(ma_dr_flac_bs* bs) +static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) { - MA_DR_FLAC_ASSERT((MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); - if (MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { - ma_dr_flac__update_crc16(bs); + DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); + if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { + drflac__update_crc16(bs); } else { - bs->crc16 = ma_dr_flac_crc16_bytes(bs->crc16, bs->crc16Cache >> MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; } return bs->crc16; } #endif -static MA_INLINE ma_bool32 ma_dr_flac__reload_l1_cache_from_l2(ma_dr_flac_bs* bs) +static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) { size_t bytesRead; size_t alignedL1LineCount; - if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { bs->cache = bs->cacheL2[bs->nextL2Line++]; - return MA_TRUE; + return DRFLAC_TRUE; } if (bs->unalignedByteCount > 0) { - return MA_FALSE; + return DRFLAC_FALSE; } - bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, MA_DR_FLAC_CACHE_L2_SIZE_BYTES(bs)); + bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); bs->nextL2Line = 0; - if (bytesRead == MA_DR_FLAC_CACHE_L2_SIZE_BYTES(bs)) { + if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) { bs->cache = bs->cacheL2[bs->nextL2Line++]; - return MA_TRUE; + return DRFLAC_TRUE; } - alignedL1LineCount = bytesRead / MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs); - bs->unalignedByteCount = bytesRead - (alignedL1LineCount * MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs)); + alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); + bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs)); if (bs->unalignedByteCount > 0) { bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; } if (alignedL1LineCount > 0) { - size_t offset = MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; + size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; size_t i; for (i = alignedL1LineCount; i > 0; --i) { bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; } - bs->nextL2Line = (ma_uint32)offset; + bs->nextL2Line = (drflac_uint32)offset; bs->cache = bs->cacheL2[bs->nextL2Line++]; - return MA_TRUE; + return DRFLAC_TRUE; } else { - bs->nextL2Line = MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs); - return MA_FALSE; + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); + return DRFLAC_FALSE; } } -static ma_bool32 ma_dr_flac__reload_cache(ma_dr_flac_bs* bs) +static drflac_bool32 drflac__reload_cache(drflac_bs* bs) { size_t bytesRead; -#ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__update_crc16(bs); +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); #endif - if (ma_dr_flac__reload_l1_cache_from_l2(bs)) { - bs->cache = ma_dr_flac__be2host__cache_line(bs->cache); + if (drflac__reload_l1_cache_from_l2(bs)) { + bs->cache = drflac__be2host__cache_line(bs->cache); bs->consumedBits = 0; -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache; #endif - return MA_TRUE; + return DRFLAC_TRUE; } bytesRead = bs->unalignedByteCount; if (bytesRead == 0) { - bs->consumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); - return MA_FALSE; + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); + return DRFLAC_FALSE; } - MA_DR_FLAC_ASSERT(bytesRead < MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs)); - bs->consumedBits = (ma_uint32)(MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; - bs->cache = ma_dr_flac__be2host__cache_line(bs->unalignedCache); - bs->cache &= MA_DR_FLAC_CACHE_L1_SELECTION_MASK(MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)); + DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs)); + bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; + bs->cache = drflac__be2host__cache_line(bs->unalignedCache); + bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); bs->unalignedByteCount = 0; -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache >> bs->consumedBits; bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; #endif - return MA_TRUE; + return DRFLAC_TRUE; } -static void ma_dr_flac__reset_cache(ma_dr_flac_bs* bs) +static void drflac__reset_cache(drflac_bs* bs) { - bs->nextL2Line = MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs); - bs->consumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); bs->cache = 0; bs->unalignedByteCount = 0; bs->unalignedCache = 0; -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC bs->crc16Cache = 0; bs->crc16CacheIgnoredBytes = 0; #endif } -static MA_INLINE ma_bool32 ma_dr_flac__read_uint32(ma_dr_flac_bs* bs, unsigned int bitCount, ma_uint32* pResultOut) +static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut) { - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pResultOut != NULL); - MA_DR_FLAC_ASSERT(bitCount > 0); - MA_DR_FLAC_ASSERT(bitCount <= 32); - if (bs->consumedBits == MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs)) { - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResultOut != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 32); + if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } } - if (bitCount <= MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { -#ifdef MA_64BIT - *pResultOut = (ma_uint32)MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { +#ifdef DRFLAC_64BIT + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); bs->consumedBits += bitCount; bs->cache <<= bitCount; #else - if (bitCount < MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs)) { - *pResultOut = (ma_uint32)MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); bs->consumedBits += bitCount; bs->cache <<= bitCount; } else { - *pResultOut = (ma_uint32)bs->cache; - bs->consumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + *pResultOut = (drflac_uint32)bs->cache; + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); bs->cache = 0; } #endif - return MA_TRUE; + return DRFLAC_TRUE; } else { - ma_uint32 bitCountHi = MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs); - ma_uint32 bitCountLo = bitCount - bitCountHi; - ma_uint32 resultHi; - MA_DR_FLAC_ASSERT(bitCountHi > 0); - MA_DR_FLAC_ASSERT(bitCountHi < 32); - resultHi = (ma_uint32)MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; + drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); + drflac_uint32 bitCountLo = bitCount - bitCountHi; + drflac_uint32 resultHi; + DRFLAC_ASSERT(bitCountHi > 0); + DRFLAC_ASSERT(bitCountHi < 32); + resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } - if (bitCountLo > MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - return MA_FALSE; - } - *pResultOut = (resultHi << bitCountLo) | (ma_uint32)MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); + *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); bs->consumedBits += bitCountLo; bs->cache <<= bitCountLo; - return MA_TRUE; + return DRFLAC_TRUE; } } -static ma_bool32 ma_dr_flac__read_int32(ma_dr_flac_bs* bs, unsigned int bitCount, ma_int32* pResult) +static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult) { - ma_uint32 result; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pResult != NULL); - MA_DR_FLAC_ASSERT(bitCount > 0); - MA_DR_FLAC_ASSERT(bitCount <= 32); - if (!ma_dr_flac__read_uint32(bs, bitCount, &result)) { - return MA_FALSE; + drflac_uint32 result; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 32); + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; } if (bitCount < 32) { - ma_uint32 signbit; + drflac_uint32 signbit; signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; } - *pResult = (ma_int32)result; - return MA_TRUE; + *pResult = (drflac_int32)result; + return DRFLAC_TRUE; } -#ifdef MA_64BIT -static ma_bool32 ma_dr_flac__read_uint64(ma_dr_flac_bs* bs, unsigned int bitCount, ma_uint64* pResultOut) +#ifdef DRFLAC_64BIT +static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut) { - ma_uint32 resultHi; - ma_uint32 resultLo; - MA_DR_FLAC_ASSERT(bitCount <= 64); - MA_DR_FLAC_ASSERT(bitCount > 32); - if (!ma_dr_flac__read_uint32(bs, bitCount - 32, &resultHi)) { - return MA_FALSE; + drflac_uint32 resultHi; + drflac_uint32 resultLo; + DRFLAC_ASSERT(bitCount <= 64); + DRFLAC_ASSERT(bitCount > 32); + if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_uint32(bs, 32, &resultLo)) { - return MA_FALSE; + if (!drflac__read_uint32(bs, 32, &resultLo)) { + return DRFLAC_FALSE; } - *pResultOut = (((ma_uint64)resultHi) << 32) | ((ma_uint64)resultLo); - return MA_TRUE; + *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo); + return DRFLAC_TRUE; } #endif #if 0 -static ma_bool32 ma_dr_flac__read_int64(ma_dr_flac_bs* bs, unsigned int bitCount, ma_int64* pResultOut) +static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut) { - ma_uint64 result; - ma_uint64 signbit; - MA_DR_FLAC_ASSERT(bitCount <= 64); - if (!ma_dr_flac__read_uint64(bs, bitCount, &result)) { - return MA_FALSE; + drflac_uint64 result; + drflac_uint64 signbit; + DRFLAC_ASSERT(bitCount <= 64); + if (!drflac__read_uint64(bs, bitCount, &result)) { + return DRFLAC_FALSE; } signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; - *pResultOut = (ma_int64)result; - return MA_TRUE; + *pResultOut = (drflac_int64)result; + return DRFLAC_TRUE; } #endif -static ma_bool32 ma_dr_flac__read_uint16(ma_dr_flac_bs* bs, unsigned int bitCount, ma_uint16* pResult) +static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult) { - ma_uint32 result; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pResult != NULL); - MA_DR_FLAC_ASSERT(bitCount > 0); - MA_DR_FLAC_ASSERT(bitCount <= 16); - if (!ma_dr_flac__read_uint32(bs, bitCount, &result)) { - return MA_FALSE; + drflac_uint32 result; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 16); + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; } - *pResult = (ma_uint16)result; - return MA_TRUE; + *pResult = (drflac_uint16)result; + return DRFLAC_TRUE; } #if 0 -static ma_bool32 ma_dr_flac__read_int16(ma_dr_flac_bs* bs, unsigned int bitCount, ma_int16* pResult) +static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult) { - ma_int32 result; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pResult != NULL); - MA_DR_FLAC_ASSERT(bitCount > 0); - MA_DR_FLAC_ASSERT(bitCount <= 16); - if (!ma_dr_flac__read_int32(bs, bitCount, &result)) { - return MA_FALSE; + drflac_int32 result; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 16); + if (!drflac__read_int32(bs, bitCount, &result)) { + return DRFLAC_FALSE; } - *pResult = (ma_int16)result; - return MA_TRUE; + *pResult = (drflac_int16)result; + return DRFLAC_TRUE; } #endif -static ma_bool32 ma_dr_flac__read_uint8(ma_dr_flac_bs* bs, unsigned int bitCount, ma_uint8* pResult) +static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult) { - ma_uint32 result; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pResult != NULL); - MA_DR_FLAC_ASSERT(bitCount > 0); - MA_DR_FLAC_ASSERT(bitCount <= 8); - if (!ma_dr_flac__read_uint32(bs, bitCount, &result)) { - return MA_FALSE; + drflac_uint32 result; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 8); + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; } - *pResult = (ma_uint8)result; - return MA_TRUE; + *pResult = (drflac_uint8)result; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__read_int8(ma_dr_flac_bs* bs, unsigned int bitCount, ma_int8* pResult) +static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult) { - ma_int32 result; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pResult != NULL); - MA_DR_FLAC_ASSERT(bitCount > 0); - MA_DR_FLAC_ASSERT(bitCount <= 8); - if (!ma_dr_flac__read_int32(bs, bitCount, &result)) { - return MA_FALSE; + drflac_int32 result; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 8); + if (!drflac__read_int32(bs, bitCount, &result)) { + return DRFLAC_FALSE; } - *pResult = (ma_int8)result; - return MA_TRUE; + *pResult = (drflac_int8)result; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__seek_bits(ma_dr_flac_bs* bs, size_t bitsToSeek) +static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) { - if (bitsToSeek <= MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - bs->consumedBits += (ma_uint32)bitsToSeek; + if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + bs->consumedBits += (drflac_uint32)bitsToSeek; bs->cache <<= bitsToSeek; - return MA_TRUE; + return DRFLAC_TRUE; } else { - bitsToSeek -= MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs); - bs->consumedBits += MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs); + bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs); bs->cache = 0; -#ifdef MA_64BIT - while (bitsToSeek >= MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs)) { - ma_uint64 bin; - if (!ma_dr_flac__read_uint64(bs, MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { - return MA_FALSE; +#ifdef DRFLAC_64BIT + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint64 bin; + if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; } - bitsToSeek -= MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); } #else - while (bitsToSeek >= MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs)) { - ma_uint32 bin; - if (!ma_dr_flac__read_uint32(bs, MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { - return MA_FALSE; + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint32 bin; + if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; } - bitsToSeek -= MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); } #endif while (bitsToSeek >= 8) { - ma_uint8 bin; - if (!ma_dr_flac__read_uint8(bs, 8, &bin)) { - return MA_FALSE; + drflac_uint8 bin; + if (!drflac__read_uint8(bs, 8, &bin)) { + return DRFLAC_FALSE; } bitsToSeek -= 8; } if (bitsToSeek > 0) { - ma_uint8 bin; - if (!ma_dr_flac__read_uint8(bs, (ma_uint32)bitsToSeek, &bin)) { - return MA_FALSE; + drflac_uint8 bin; + if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) { + return DRFLAC_FALSE; } bitsToSeek = 0; } - MA_DR_FLAC_ASSERT(bitsToSeek == 0); - return MA_TRUE; + DRFLAC_ASSERT(bitsToSeek == 0); + return DRFLAC_TRUE; } } -static ma_bool32 ma_dr_flac__find_and_seek_to_next_sync_code(ma_dr_flac_bs* bs) +static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) { - MA_DR_FLAC_ASSERT(bs != NULL); - if (!ma_dr_flac__seek_bits(bs, MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { - return MA_FALSE; + DRFLAC_ASSERT(bs != NULL); + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; } for (;;) { - ma_uint8 hi; -#ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__reset_crc16(bs); + drflac_uint8 hi; +#ifndef DR_FLAC_NO_CRC + drflac__reset_crc16(bs); #endif - if (!ma_dr_flac__read_uint8(bs, 8, &hi)) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 8, &hi)) { + return DRFLAC_FALSE; } if (hi == 0xFF) { - ma_uint8 lo; - if (!ma_dr_flac__read_uint8(bs, 6, &lo)) { - return MA_FALSE; + drflac_uint8 lo; + if (!drflac__read_uint8(bs, 6, &lo)) { + return DRFLAC_FALSE; } if (lo == 0x3E) { - return MA_TRUE; + return DRFLAC_TRUE; } else { - if (!ma_dr_flac__seek_bits(bs, MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; } } } } } -#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) -#define MA_DR_FLAC_IMPLEMENT_CLZ_LZCNT +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +#define DRFLAC_IMPLEMENT_CLZ_LZCNT #endif -#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(MA_X64) || defined(MA_X86)) && !defined(__clang__) -#define MA_DR_FLAC_IMPLEMENT_CLZ_MSVC +#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__) +#define DRFLAC_IMPLEMENT_CLZ_MSVC #endif #if defined(__WATCOMC__) && defined(__386__) -#define MA_DR_FLAC_IMPLEMENT_CLZ_WATCOM +#define DRFLAC_IMPLEMENT_CLZ_WATCOM #endif -#ifdef __MRC__ -#include -#define MA_DR_FLAC_IMPLEMENT_CLZ_MRC -#endif -static MA_INLINE ma_uint32 ma_dr_flac__clz_software(ma_dr_flac_cache_t x) +static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { - ma_uint32 n; - static ma_uint32 clz_table_4[] = { + drflac_uint32 n; + static drflac_uint32 clz_table_4[] = { 0, 4, 3, 3, @@ -83936,11 +53893,11 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_software(ma_dr_flac_cache_t x) } n = clz_table_4[x >> (sizeof(x)*8 - 4)]; if (n == 0) { -#ifdef MA_64BIT - if ((x & ((ma_uint64)0xFFFFFFFF << 32)) == 0) { n = 32; x <<= 32; } - if ((x & ((ma_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; } - if ((x & ((ma_uint64)0xFF000000 << 32)) == 0) { n += 8; x <<= 8; } - if ((x & ((ma_uint64)0xF0000000 << 32)) == 0) { n += 4; x <<= 4; } +#ifdef DRFLAC_64BIT + if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n = 32; x <<= 32; } + if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; } + if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8; x <<= 8; } + if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4; x <<= 4; } #else if ((x & 0xFFFF0000) == 0) { n = 16; x <<= 16; } if ((x & 0xFF000000) == 0) { n += 8; x <<= 8; } @@ -83950,52 +53907,50 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_software(ma_dr_flac_cache_t x) } return n - 1; } -#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_LZCNT -static MA_INLINE ma_bool32 ma_dr_flac__is_lzcnt_supported(void) +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT +static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void) { -#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) && defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) - return MA_TRUE; -#elif defined(__MRC__) - return MA_TRUE; +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) + return DRFLAC_TRUE; #else - #ifdef MA_DR_FLAC_HAS_LZCNT_INTRINSIC - return ma_dr_flac__gIsLZCNTSupported; + #ifdef DRFLAC_HAS_LZCNT_INTRINSIC + return drflac__gIsLZCNTSupported; #else - return MA_FALSE; + return DRFLAC_FALSE; #endif #endif } -static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x) +static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) { #if defined(_MSC_VER) - #ifdef MA_64BIT - return (ma_uint32)__lzcnt64(x); + #ifdef DRFLAC_64BIT + return (drflac_uint32)__lzcnt64(x); #else - return (ma_uint32)__lzcnt(x); + return (drflac_uint32)__lzcnt(x); #endif #else #if defined(__GNUC__) || defined(__clang__) - #if defined(MA_X64) + #if defined(DRFLAC_X64) { - ma_uint64 r; + drflac_uint64 r; __asm__ __volatile__ ( "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" ); - return (ma_uint32)r; + return (drflac_uint32)r; } - #elif defined(MA_X86) + #elif defined(DRFLAC_X86) { - ma_uint32 r; + drflac_uint32 r; __asm__ __volatile__ ( "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" ); return r; } - #elif defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(MA_64BIT) + #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(DRFLAC_64BIT) { unsigned int r; __asm__ __volatile__ ( - #if defined(MA_64BIT) + #if defined(DRFLAC_64BIT) "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x) #else "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x) @@ -84007,10 +53962,10 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x) if (x == 0) { return sizeof(x)*8; } - #ifdef MA_64BIT - return (ma_uint32)__builtin_clzll((ma_uint64)x); + #ifdef DRFLAC_64BIT + return (drflac_uint32)__builtin_clzll((drflac_uint64)x); #else - return (ma_uint32)__builtin_clzl((ma_uint32)x); + return (drflac_uint32)__builtin_clzl((drflac_uint32)x); #endif #endif #else @@ -84019,15 +53974,15 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x) #endif } #endif -#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_MSVC +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC #include -static MA_INLINE ma_uint32 ma_dr_flac__clz_msvc(ma_dr_flac_cache_t x) +static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) { - ma_uint32 n; + drflac_uint32 n; if (x == 0) { return sizeof(x)*8; } -#ifdef MA_64BIT +#ifdef DRFLAC_64BIT _BitScanReverse64((unsigned long*)&n, x); #else _BitScanReverse((unsigned long*)&n, x); @@ -84035,120 +53990,98 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_msvc(ma_dr_flac_cache_t x) return sizeof(x)*8 - n - 1; } #endif -#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_WATCOM -static __inline ma_uint32 ma_dr_flac__clz_watcom (ma_uint32); -#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_WATCOM_LZCNT -#pragma aux ma_dr_flac__clz_watcom_lzcnt = \ - "db 0F3h, 0Fh, 0BDh, 0C0h" \ - parm [eax] \ - value [eax] \ - modify nomemory; -#else -#pragma aux ma_dr_flac__clz_watcom = \ +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM +static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#pragma aux drflac__clz_watcom = \ "bsr eax, eax" \ "xor eax, 31" \ parm [eax] nomemory \ value [eax] \ modify exact [eax] nomemory; #endif -#endif -static MA_INLINE ma_uint32 ma_dr_flac__clz(ma_dr_flac_cache_t x) +static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { -#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_LZCNT - if (ma_dr_flac__is_lzcnt_supported()) { - return ma_dr_flac__clz_lzcnt(x); +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT + if (drflac__is_lzcnt_supported()) { + return drflac__clz_lzcnt(x); } else #endif { -#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_MSVC - return ma_dr_flac__clz_msvc(x); -#elif defined(MA_DR_FLAC_IMPLEMENT_CLZ_WATCOM_LZCNT) - return ma_dr_flac__clz_watcom_lzcnt(x); -#elif defined(MA_DR_FLAC_IMPLEMENT_CLZ_WATCOM) - return (x == 0) ? sizeof(x)*8 : ma_dr_flac__clz_watcom(x); -#elif defined(__MRC__) - return __cntlzw(x); +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC + return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) + return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); #else - return ma_dr_flac__clz_software(x); + return drflac__clz_software(x); #endif } } -static MA_INLINE ma_bool32 ma_dr_flac__seek_past_next_set_bit(ma_dr_flac_bs* bs, unsigned int* pOffsetOut) +static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) { - ma_uint32 zeroCounter = 0; - ma_uint32 setBitOffsetPlus1; + drflac_uint32 zeroCounter = 0; + drflac_uint32 setBitOffsetPlus1; while (bs->cache == 0) { - zeroCounter += (ma_uint32)MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs); - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } } - if (bs->cache == 1) { - *pOffsetOut = zeroCounter + (ma_uint32)MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) - 1; - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; - } - return MA_TRUE; - } - setBitOffsetPlus1 = ma_dr_flac__clz(bs->cache); + setBitOffsetPlus1 = drflac__clz(bs->cache); setBitOffsetPlus1 += 1; - if (setBitOffsetPlus1 > MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - return MA_FALSE; - } bs->consumedBits += setBitOffsetPlus1; bs->cache <<= setBitOffsetPlus1; *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1; - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__seek_to_byte(ma_dr_flac_bs* bs, ma_uint64 offsetFromStart) +static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart) { - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(offsetFromStart > 0); + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(offsetFromStart > 0); if (offsetFromStart > 0x7FFFFFFF) { - ma_uint64 bytesRemaining = offsetFromStart; - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { - return MA_FALSE; + drflac_uint64 bytesRemaining = offsetFromStart; + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } bytesRemaining -= 0x7FFFFFFF; while (bytesRemaining > 0x7FFFFFFF) { - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } bytesRemaining -= 0x7FFFFFFF; } if (bytesRemaining > 0) { - if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } } } else { - if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, ma_dr_flac_seek_origin_start)) { - return MA_FALSE; + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } } - ma_dr_flac__reset_cache(bs); - return MA_TRUE; + drflac__reset_cache(bs); + return DRFLAC_TRUE; } -static ma_result ma_dr_flac__read_utf8_coded_number(ma_dr_flac_bs* bs, ma_uint64* pNumberOut, ma_uint8* pCRCOut) +static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut) { - ma_uint8 crc; - ma_uint64 result; - ma_uint8 utf8[7] = {0}; + drflac_uint8 crc; + drflac_uint64 result; + drflac_uint8 utf8[7] = {0}; int byteCount; int i; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pNumberOut != NULL); - MA_DR_FLAC_ASSERT(pCRCOut != NULL); + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pNumberOut != NULL); + DRFLAC_ASSERT(pCRCOut != NULL); crc = *pCRCOut; - if (!ma_dr_flac__read_uint8(bs, 8, utf8)) { + if (!drflac__read_uint8(bs, 8, utf8)) { *pNumberOut = 0; - return MA_AT_END; + return DRFLAC_AT_END; } - crc = ma_dr_flac_crc8(crc, utf8[0], 8); + crc = drflac_crc8(crc, utf8[0], 8); if ((utf8[0] & 0x80) == 0) { *pNumberOut = utf8[0]; *pCRCOut = crc; - return MA_SUCCESS; + return DRFLAC_SUCCESS; } if ((utf8[0] & 0xE0) == 0xC0) { byteCount = 2; @@ -84164,44 +54097,26 @@ static ma_result ma_dr_flac__read_utf8_coded_number(ma_dr_flac_bs* bs, ma_uint64 byteCount = 7; } else { *pNumberOut = 0; - return MA_CRC_MISMATCH; + return DRFLAC_CRC_MISMATCH; } - MA_DR_FLAC_ASSERT(byteCount > 1); - result = (ma_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); + DRFLAC_ASSERT(byteCount > 1); + result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); for (i = 1; i < byteCount; ++i) { - if (!ma_dr_flac__read_uint8(bs, 8, utf8 + i)) { + if (!drflac__read_uint8(bs, 8, utf8 + i)) { *pNumberOut = 0; - return MA_AT_END; + return DRFLAC_AT_END; } - crc = ma_dr_flac_crc8(crc, utf8[i], 8); + crc = drflac_crc8(crc, utf8[i], 8); result = (result << 6) | (utf8[i] & 0x3F); } *pNumberOut = result; *pCRCOut = crc; - return MA_SUCCESS; + return DRFLAC_SUCCESS; } -static MA_INLINE ma_uint32 ma_dr_flac__ilog2_u32(ma_uint32 x) +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { -#if 1 - ma_uint32 result = 0; - while (x > 0) { - result += 1; - x >>= 1; - } - return result; -#endif -} -static MA_INLINE ma_bool32 ma_dr_flac__use_64_bit_prediction(ma_uint32 bitsPerSample, ma_uint32 order, ma_uint32 precision) -{ - return bitsPerSample + precision + ma_dr_flac__ilog2_u32(order) > 32; -} -#if defined(__clang__) -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -static MA_INLINE ma_int32 ma_dr_flac__calculate_prediction_32(ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pDecodedSamples) -{ - ma_int32 prediction = 0; - MA_DR_FLAC_ASSERT(order <= 32); + drflac_int32 prediction = 0; + DRFLAC_ASSERT(order <= 32); switch (order) { case 32: prediction += coefficients[31] * pDecodedSamples[-32]; @@ -84237,188 +54152,188 @@ static MA_INLINE ma_int32 ma_dr_flac__calculate_prediction_32(ma_uint32 order, m case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2]; case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1]; } - return (ma_int32)(prediction >> shift); + return (drflac_int32)(prediction >> shift); } -static MA_INLINE ma_int32 ma_dr_flac__calculate_prediction_64(ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pDecodedSamples) +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - ma_int64 prediction; - MA_DR_FLAC_ASSERT(order <= 32); -#ifndef MA_64BIT + drflac_int64 prediction; + DRFLAC_ASSERT(order <= 32); +#ifndef DRFLAC_64BIT if (order == 8) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; - prediction += coefficients[6] * (ma_int64)pDecodedSamples[-7]; - prediction += coefficients[7] * (ma_int64)pDecodedSamples[-8]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; } else if (order == 7) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; - prediction += coefficients[6] * (ma_int64)pDecodedSamples[-7]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; } else if (order == 3) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; } else if (order == 6) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; } else if (order == 5) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; } else if (order == 4) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; } else if (order == 12) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; - prediction += coefficients[6] * (ma_int64)pDecodedSamples[-7]; - prediction += coefficients[7] * (ma_int64)pDecodedSamples[-8]; - prediction += coefficients[8] * (ma_int64)pDecodedSamples[-9]; - prediction += coefficients[9] * (ma_int64)pDecodedSamples[-10]; - prediction += coefficients[10] * (ma_int64)pDecodedSamples[-11]; - prediction += coefficients[11] * (ma_int64)pDecodedSamples[-12]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; } else if (order == 2) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; } else if (order == 1) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; } else if (order == 10) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; - prediction += coefficients[6] * (ma_int64)pDecodedSamples[-7]; - prediction += coefficients[7] * (ma_int64)pDecodedSamples[-8]; - prediction += coefficients[8] * (ma_int64)pDecodedSamples[-9]; - prediction += coefficients[9] * (ma_int64)pDecodedSamples[-10]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; } else if (order == 9) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; - prediction += coefficients[6] * (ma_int64)pDecodedSamples[-7]; - prediction += coefficients[7] * (ma_int64)pDecodedSamples[-8]; - prediction += coefficients[8] * (ma_int64)pDecodedSamples[-9]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; } else if (order == 11) { - prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; - prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; - prediction += coefficients[2] * (ma_int64)pDecodedSamples[-3]; - prediction += coefficients[3] * (ma_int64)pDecodedSamples[-4]; - prediction += coefficients[4] * (ma_int64)pDecodedSamples[-5]; - prediction += coefficients[5] * (ma_int64)pDecodedSamples[-6]; - prediction += coefficients[6] * (ma_int64)pDecodedSamples[-7]; - prediction += coefficients[7] * (ma_int64)pDecodedSamples[-8]; - prediction += coefficients[8] * (ma_int64)pDecodedSamples[-9]; - prediction += coefficients[9] * (ma_int64)pDecodedSamples[-10]; - prediction += coefficients[10] * (ma_int64)pDecodedSamples[-11]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; } else { int j; prediction = 0; for (j = 0; j < (int)order; ++j) { - prediction += coefficients[j] * (ma_int64)pDecodedSamples[-j-1]; + prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1]; } } #endif -#ifdef MA_64BIT +#ifdef DRFLAC_64BIT prediction = 0; switch (order) { - case 32: prediction += coefficients[31] * (ma_int64)pDecodedSamples[-32]; - case 31: prediction += coefficients[30] * (ma_int64)pDecodedSamples[-31]; - case 30: prediction += coefficients[29] * (ma_int64)pDecodedSamples[-30]; - case 29: prediction += coefficients[28] * (ma_int64)pDecodedSamples[-29]; - case 28: prediction += coefficients[27] * (ma_int64)pDecodedSamples[-28]; - case 27: prediction += coefficients[26] * (ma_int64)pDecodedSamples[-27]; - case 26: prediction += coefficients[25] * (ma_int64)pDecodedSamples[-26]; - case 25: prediction += coefficients[24] * (ma_int64)pDecodedSamples[-25]; - case 24: prediction += coefficients[23] * (ma_int64)pDecodedSamples[-24]; - case 23: prediction += coefficients[22] * (ma_int64)pDecodedSamples[-23]; - case 22: prediction += coefficients[21] * (ma_int64)pDecodedSamples[-22]; - case 21: prediction += coefficients[20] * (ma_int64)pDecodedSamples[-21]; - case 20: prediction += coefficients[19] * (ma_int64)pDecodedSamples[-20]; - case 19: prediction += coefficients[18] * (ma_int64)pDecodedSamples[-19]; - case 18: prediction += coefficients[17] * (ma_int64)pDecodedSamples[-18]; - case 17: prediction += coefficients[16] * (ma_int64)pDecodedSamples[-17]; - case 16: prediction += coefficients[15] * (ma_int64)pDecodedSamples[-16]; - case 15: prediction += coefficients[14] * (ma_int64)pDecodedSamples[-15]; - case 14: prediction += coefficients[13] * (ma_int64)pDecodedSamples[-14]; - case 13: prediction += coefficients[12] * (ma_int64)pDecodedSamples[-13]; - case 12: prediction += coefficients[11] * (ma_int64)pDecodedSamples[-12]; - case 11: prediction += coefficients[10] * (ma_int64)pDecodedSamples[-11]; - case 10: prediction += coefficients[ 9] * (ma_int64)pDecodedSamples[-10]; - case 9: prediction += coefficients[ 8] * (ma_int64)pDecodedSamples[- 9]; - case 8: prediction += coefficients[ 7] * (ma_int64)pDecodedSamples[- 8]; - case 7: prediction += coefficients[ 6] * (ma_int64)pDecodedSamples[- 7]; - case 6: prediction += coefficients[ 5] * (ma_int64)pDecodedSamples[- 6]; - case 5: prediction += coefficients[ 4] * (ma_int64)pDecodedSamples[- 5]; - case 4: prediction += coefficients[ 3] * (ma_int64)pDecodedSamples[- 4]; - case 3: prediction += coefficients[ 2] * (ma_int64)pDecodedSamples[- 3]; - case 2: prediction += coefficients[ 1] * (ma_int64)pDecodedSamples[- 2]; - case 1: prediction += coefficients[ 0] * (ma_int64)pDecodedSamples[- 1]; + case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1]; } #endif - return (ma_int32)(prediction >> shift); + return (drflac_int32)(prediction >> shift); } #if 0 -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__reference(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 riceParam, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - ma_uint32 i; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pSamplesOut != NULL); + drflac_uint32 i; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { - ma_uint32 zeroCounter = 0; + drflac_uint32 zeroCounter = 0; for (;;) { - ma_uint8 bit; - if (!ma_dr_flac__read_uint8(bs, 1, &bit)) { - return MA_FALSE; + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; } if (bit == 0) { zeroCounter += 1; @@ -84426,10 +54341,10 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__reference(ma_dr break; } } - ma_uint32 decodedRice; + drflac_uint32 decodedRice; if (riceParam > 0) { - if (!ma_dr_flac__read_uint32(bs, riceParam, &decodedRice)) { - return MA_FALSE; + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; } } else { decodedRice = 0; @@ -84440,24 +54355,24 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__reference(ma_dr } else { decodedRice = (decodedRice >> 1); } - if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - pSamplesOut[i] = decodedRice + ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + if (bitsPerSample+shift >= 32) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] = decodedRice + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); } } - return MA_TRUE; + return DRFLAC_TRUE; } #endif #if 0 -static ma_bool32 ma_dr_flac__read_rice_parts__reference(ma_dr_flac_bs* bs, ma_uint8 riceParam, ma_uint32* pZeroCounterOut, ma_uint32* pRiceParamPartOut) +static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { - ma_uint32 zeroCounter = 0; - ma_uint32 decodedRice; + drflac_uint32 zeroCounter = 0; + drflac_uint32 decodedRice; for (;;) { - ma_uint8 bit; - if (!ma_dr_flac__read_uint8(bs, 1, &bit)) { - return MA_FALSE; + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; } if (bit == 0) { zeroCounter += 1; @@ -84466,142 +54381,136 @@ static ma_bool32 ma_dr_flac__read_rice_parts__reference(ma_dr_flac_bs* bs, ma_ui } } if (riceParam > 0) { - if (!ma_dr_flac__read_uint32(bs, riceParam, &decodedRice)) { - return MA_FALSE; + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; } } else { decodedRice = 0; } *pZeroCounterOut = zeroCounter; *pRiceParamPartOut = decodedRice; - return MA_TRUE; + return DRFLAC_TRUE; } #endif #if 0 -static MA_INLINE ma_bool32 ma_dr_flac__read_rice_parts(ma_dr_flac_bs* bs, ma_uint8 riceParam, ma_uint32* pZeroCounterOut, ma_uint32* pRiceParamPartOut) +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { - ma_dr_flac_cache_t riceParamMask; - ma_uint32 zeroCounter; - ma_uint32 setBitOffsetPlus1; - ma_uint32 riceParamPart; - ma_uint32 riceLength; - MA_DR_FLAC_ASSERT(riceParam > 0); - riceParamMask = MA_DR_FLAC_CACHE_L1_SELECTION_MASK(riceParam); + drflac_cache_t riceParamMask; + drflac_uint32 zeroCounter; + drflac_uint32 setBitOffsetPlus1; + drflac_uint32 riceParamPart; + drflac_uint32 riceLength; + DRFLAC_ASSERT(riceParam > 0); + riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); zeroCounter = 0; while (bs->cache == 0) { - zeroCounter += (ma_uint32)MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs); - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } } - setBitOffsetPlus1 = ma_dr_flac__clz(bs->cache); + setBitOffsetPlus1 = drflac__clz(bs->cache); zeroCounter += setBitOffsetPlus1; setBitOffsetPlus1 += 1; riceLength = setBitOffsetPlus1 + riceParam; - if (riceLength < MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - riceParamPart = (ma_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> MA_DR_FLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); + if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); bs->consumedBits += riceLength; bs->cache <<= riceLength; } else { - ma_uint32 bitCountLo; - ma_dr_flac_cache_t resultHi; + drflac_uint32 bitCountLo; + drflac_cache_t resultHi; bs->consumedBits += riceLength; - bs->cache <<= setBitOffsetPlus1 & (MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs)-1); - bitCountLo = bs->consumedBits - MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); - resultHi = MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); - if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { -#ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__update_crc16(bs); + bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); + bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); #endif - bs->cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs->consumedBits = 0; -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache; #endif } else { - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; - } - if (bitCountLo > MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - return MA_FALSE; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } } - riceParamPart = (ma_uint32)(resultHi | MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); + riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); bs->consumedBits += bitCountLo; bs->cache <<= bitCountLo; } pZeroCounterOut[0] = zeroCounter; pRiceParamPartOut[0] = riceParamPart; - return MA_TRUE; + return DRFLAC_TRUE; } #endif -static MA_INLINE ma_bool32 ma_dr_flac__read_rice_parts_x1(ma_dr_flac_bs* bs, ma_uint8 riceParam, ma_uint32* pZeroCounterOut, ma_uint32* pRiceParamPartOut) +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { - ma_uint32 riceParamPlus1 = riceParam + 1; - ma_uint32 riceParamPlus1Shift = MA_DR_FLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); - ma_uint32 riceParamPlus1MaxConsumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; - ma_dr_flac_cache_t bs_cache = bs->cache; - ma_uint32 bs_consumedBits = bs->consumedBits; - ma_uint32 lzcount = ma_dr_flac__clz(bs_cache); + drflac_uint32 riceParamPlus1 = riceParam + 1; + drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + drflac_uint32 lzcount = drflac__clz(bs_cache); if (lzcount < sizeof(bs_cache)*8) { pZeroCounterOut[0] = lzcount; extract_rice_param_part: bs_cache <<= lzcount; bs_consumedBits += lzcount; if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { - pRiceParamPartOut[0] = (ma_uint32)(bs_cache >> riceParamPlus1Shift); + pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); bs_cache <<= riceParamPlus1; bs_consumedBits += riceParamPlus1; } else { - ma_uint32 riceParamPartHi; - ma_uint32 riceParamPartLo; - ma_uint32 riceParamPartLoBitCount; - riceParamPartHi = (ma_uint32)(bs_cache >> riceParamPlus1Shift); + drflac_uint32 riceParamPartHi; + drflac_uint32 riceParamPartLo; + drflac_uint32 riceParamPartLoBitCount; + riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; - MA_DR_FLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); - if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { - #ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__update_crc16(bs); + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); #endif - bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs_consumedBits = riceParamPartLoBitCount; - #ifndef MA_DR_FLAC_NO_CRC + #ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs_cache; #endif } else { - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; - } - if (riceParamPartLoBitCount > MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - return MA_FALSE; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } - riceParamPartLo = (ma_uint32)(bs_cache >> (MA_DR_FLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); + riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo; bs_cache <<= riceParamPartLoBitCount; } } else { - ma_uint32 zeroCounter = (ma_uint32)(MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); + drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); for (;;) { - if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { - #ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__update_crc16(bs); + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); #endif - bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs_consumedBits = 0; - #ifndef MA_DR_FLAC_NO_CRC + #ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs_cache; #endif } else { - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits; } - lzcount = ma_dr_flac__clz(bs_cache); + lzcount = drflac__clz(bs_cache); zeroCounter += lzcount; if (lzcount < sizeof(bs_cache)*8) { break; @@ -84612,15 +54521,15 @@ static MA_INLINE ma_bool32 ma_dr_flac__read_rice_parts_x1(ma_dr_flac_bs* bs, ma_ } bs->cache = bs_cache; bs->consumedBits = bs_consumedBits; - return MA_TRUE; + return DRFLAC_TRUE; } -static MA_INLINE ma_bool32 ma_dr_flac__seek_rice_parts(ma_dr_flac_bs* bs, ma_uint8 riceParam) +static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam) { - ma_uint32 riceParamPlus1 = riceParam + 1; - ma_uint32 riceParamPlus1MaxConsumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; - ma_dr_flac_cache_t bs_cache = bs->cache; - ma_uint32 bs_consumedBits = bs->consumedBits; - ma_uint32 lzcount = ma_dr_flac__clz(bs_cache); + drflac_uint32 riceParamPlus1 = riceParam + 1; + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + drflac_uint32 lzcount = drflac__clz(bs_cache); if (lzcount < sizeof(bs_cache)*8) { extract_rice_param_part: bs_cache <<= lzcount; @@ -84629,23 +54538,20 @@ static MA_INLINE ma_bool32 ma_dr_flac__seek_rice_parts(ma_dr_flac_bs* bs, ma_uin bs_cache <<= riceParamPlus1; bs_consumedBits += riceParamPlus1; } else { - ma_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; - MA_DR_FLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); - if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { - #ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__update_crc16(bs); + drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); #endif - bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs_consumedBits = riceParamPartLoBitCount; - #ifndef MA_DR_FLAC_NO_CRC + #ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs_cache; #endif } else { - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; - } - if (riceParamPartLoBitCount > MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { - return MA_FALSE; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; @@ -84654,23 +54560,23 @@ static MA_INLINE ma_bool32 ma_dr_flac__seek_rice_parts(ma_dr_flac_bs* bs, ma_uin } } else { for (;;) { - if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { - #ifndef MA_DR_FLAC_NO_CRC - ma_dr_flac__update_crc16(bs); + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); #endif - bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs_consumedBits = 0; - #ifndef MA_DR_FLAC_NO_CRC + #ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs_cache; #endif } else { - if (!ma_dr_flac__reload_cache(bs)) { - return MA_FALSE; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits; } - lzcount = ma_dr_flac__clz(bs_cache); + lzcount = drflac__clz(bs_cache); if (lzcount < sizeof(bs_cache)*8) { break; } @@ -84679,26 +54585,26 @@ static MA_INLINE ma_bool32 ma_dr_flac__seek_rice_parts(ma_dr_flac_bs* bs, ma_uin } bs->cache = bs_cache; bs->consumedBits = bs_consumedBits; - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__scalar_zeroorder(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 riceParam, ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorder(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - ma_uint32 zeroCountPart0; - ma_uint32 riceParamPart0; - ma_uint32 riceParamMask; - ma_uint32 i; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pSamplesOut != NULL); + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0; + drflac_uint32 riceParamPart0; + drflac_uint32 riceParamMask; + drflac_uint32 i; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); (void)bitsPerSample; (void)order; (void)shift; (void)coefficients; - riceParamMask = (ma_uint32)~((~0UL) << riceParam); + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); i = 0; while (i < count) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; } riceParamPart0 &= riceParamMask; riceParamPart0 |= (zeroCountPart0 << riceParam); @@ -84706,36 +54612,36 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__scalar_zeroorde pSamplesOut[i] = riceParamPart0; i += 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__scalar(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 riceParam, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - ma_uint32 zeroCountPart0 = 0; - ma_uint32 zeroCountPart1 = 0; - ma_uint32 zeroCountPart2 = 0; - ma_uint32 zeroCountPart3 = 0; - ma_uint32 riceParamPart0 = 0; - ma_uint32 riceParamPart1 = 0; - ma_uint32 riceParamPart2 = 0; - ma_uint32 riceParamPart3 = 0; - ma_uint32 riceParamMask; - const ma_int32* pSamplesOutEnd; - ma_uint32 i; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pSamplesOut != NULL); - if (lpcOrder == 0) { - return ma_dr_flac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0 = 0; + drflac_uint32 zeroCountPart1 = 0; + drflac_uint32 zeroCountPart2 = 0; + drflac_uint32 zeroCountPart3 = 0; + drflac_uint32 riceParamPart0 = 0; + drflac_uint32 riceParamPart1 = 0; + drflac_uint32 riceParamPart2 = 0; + drflac_uint32 riceParamPart3 = 0; + drflac_uint32 riceParamMask; + const drflac_int32* pSamplesOutEnd; + drflac_uint32 i; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + if (order == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } - riceParamMask = (ma_uint32)~((~0UL) << riceParam); + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); pSamplesOutEnd = pSamplesOut + (count & ~3); - if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + if (bitsPerSample+shift > 32) { while (pSamplesOut < pSamplesOutEnd) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; } riceParamPart0 &= riceParamMask; riceParamPart1 &= riceParamMask; @@ -84749,19 +54655,19 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__scalar(ma_dr_fl riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } } else { while (pSamplesOut < pSamplesOutEnd) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; } riceParamPart0 &= riceParamMask; riceParamPart1 &= riceParamMask; @@ -84775,33 +54681,33 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__scalar(ma_dr_fl riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } } i = (count & ~3); while (i < count) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; } riceParamPart0 &= riceParamMask; riceParamPart0 |= (zeroCountPart0 << riceParam); riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; - if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - pSamplesOut[0] = riceParamPart0 + ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + if (bitsPerSample+shift > 32) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); } else { - pSamplesOut[0] = riceParamPart0 + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); } i += 1; pSamplesOut += 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE __m128i ma_dr_flac__mm_packs_interleaved_epi32(__m128i a, __m128i b) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b) { __m128i r; r = _mm_packs_epi32(a, b); @@ -84811,42 +54717,42 @@ static MA_INLINE __m128i ma_dr_flac__mm_packs_interleaved_epi32(__m128i a, __m12 return r; } #endif -#if defined(MA_DR_FLAC_SUPPORT_SSE41) -static MA_INLINE __m128i ma_dr_flac__mm_not_si128(__m128i a) +#if defined(DRFLAC_SUPPORT_SSE41) +static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a) { return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())); } -static MA_INLINE __m128i ma_dr_flac__mm_hadd_epi32(__m128i x) +static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x) { __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))); __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2)); return _mm_add_epi32(x64, x32); } -static MA_INLINE __m128i ma_dr_flac__mm_hadd_epi64(__m128i x) +static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x) { return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))); } -static MA_INLINE __m128i ma_dr_flac__mm_srai_epi64(__m128i x, int count) +static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count) { __m128i lo = _mm_srli_epi64(x, count); __m128i hi = _mm_srai_epi32(x, count); hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0)); return _mm_or_si128(lo, hi); } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_32(ma_dr_flac_bs* bs, ma_uint32 count, ma_uint8 riceParam, ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { int i; - ma_uint32 riceParamMask; - ma_int32* pDecodedSamples = pSamplesOut; - ma_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); - ma_uint32 zeroCountParts0 = 0; - ma_uint32 zeroCountParts1 = 0; - ma_uint32 zeroCountParts2 = 0; - ma_uint32 zeroCountParts3 = 0; - ma_uint32 riceParamParts0 = 0; - ma_uint32 riceParamParts1 = 0; - ma_uint32 riceParamParts2 = 0; - ma_uint32 riceParamParts3 = 0; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts0 = 0; + drflac_uint32 zeroCountParts1 = 0; + drflac_uint32 zeroCountParts2 = 0; + drflac_uint32 zeroCountParts3 = 0; + drflac_uint32 riceParamParts0 = 0; + drflac_uint32 riceParamParts1 = 0; + drflac_uint32 riceParamParts2 = 0; + drflac_uint32 riceParamParts3 = 0; __m128i coefficients128_0; __m128i coefficients128_4; __m128i coefficients128_8; @@ -84854,8 +54760,8 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_32(ma_dr_ __m128i samples128_4; __m128i samples128_8; __m128i riceParamMask128; - const ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = (ma_uint32)~((~0UL) << riceParam); + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); riceParamMask128 = _mm_set1_epi32(riceParamMask); coefficients128_0 = _mm_setzero_si128(); coefficients128_4 = _mm_setzero_si128(); @@ -84909,39 +54815,39 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_32(ma_dr_ #else switch (order) { - case 12: ((ma_int32*)&coefficients128_8)[0] = coefficients[11]; ((ma_int32*)&samples128_8)[0] = pDecodedSamples[-12]; - case 11: ((ma_int32*)&coefficients128_8)[1] = coefficients[10]; ((ma_int32*)&samples128_8)[1] = pDecodedSamples[-11]; - case 10: ((ma_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((ma_int32*)&samples128_8)[2] = pDecodedSamples[-10]; - case 9: ((ma_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((ma_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; - case 8: ((ma_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((ma_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; - case 7: ((ma_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((ma_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; - case 6: ((ma_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((ma_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; - case 5: ((ma_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((ma_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; - case 4: ((ma_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((ma_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; - case 3: ((ma_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((ma_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; - case 2: ((ma_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((ma_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; - case 1: ((ma_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((ma_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; + case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12]; + case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11]; + case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10]; + case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; + case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; + case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; + case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; + case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; + case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; + case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; + case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; + case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; } #endif while (pDecodedSamples < pDecodedSamplesEnd) { __m128i prediction128; __m128i zeroCountPart128; __m128i riceParamPart128; - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { + return DRFLAC_FALSE; } zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); - riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(ma_dr_flac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01))); + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01))); if (order <= 4) { for (i = 0; i < 4; i += 1) { prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0); - prediction128 = ma_dr_flac__mm_hadd_epi32(prediction128); + prediction128 = drflac__mm_hadd_epi32(prediction128); prediction128 = _mm_srai_epi32(prediction128, shift); prediction128 = _mm_add_epi32(riceParamPart128, prediction128); samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); @@ -84951,7 +54857,7 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_32(ma_dr_ for (i = 0; i < 4; i += 1) { prediction128 = _mm_mullo_epi32(coefficients128_4, samples128_4); prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0)); - prediction128 = ma_dr_flac__mm_hadd_epi32(prediction128); + prediction128 = drflac__mm_hadd_epi32(prediction128); prediction128 = _mm_srai_epi32(prediction128, shift); prediction128 = _mm_add_epi32(riceParamPart128, prediction128); samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); @@ -84963,7 +54869,7 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_32(ma_dr_ prediction128 = _mm_mullo_epi32(coefficients128_8, samples128_8); prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4)); prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0)); - prediction128 = ma_dr_flac__mm_hadd_epi32(prediction128); + prediction128 = drflac__mm_hadd_epi32(prediction128); prediction128 = _mm_srai_epi32(prediction128, shift); prediction128 = _mm_add_epi32(riceParamPart128, prediction128); samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); @@ -84977,32 +54883,32 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_32(ma_dr_ } i = (count & ~3); while (i < (int)count) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; } riceParamParts0 &= riceParamMask; riceParamParts0 |= (zeroCountParts0 << riceParam); riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; - pDecodedSamples[0] = riceParamParts0 + ma_dr_flac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); i += 1; pDecodedSamples += 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_64(ma_dr_flac_bs* bs, ma_uint32 count, ma_uint8 riceParam, ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { int i; - ma_uint32 riceParamMask; - ma_int32* pDecodedSamples = pSamplesOut; - ma_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); - ma_uint32 zeroCountParts0 = 0; - ma_uint32 zeroCountParts1 = 0; - ma_uint32 zeroCountParts2 = 0; - ma_uint32 zeroCountParts3 = 0; - ma_uint32 riceParamParts0 = 0; - ma_uint32 riceParamParts1 = 0; - ma_uint32 riceParamParts2 = 0; - ma_uint32 riceParamParts3 = 0; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts0 = 0; + drflac_uint32 zeroCountParts1 = 0; + drflac_uint32 zeroCountParts2 = 0; + drflac_uint32 zeroCountParts3 = 0; + drflac_uint32 riceParamParts0 = 0; + drflac_uint32 riceParamParts1 = 0; + drflac_uint32 riceParamParts2 = 0; + drflac_uint32 riceParamParts3 = 0; __m128i coefficients128_0; __m128i coefficients128_4; __m128i coefficients128_8; @@ -85011,9 +54917,9 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_64(ma_dr_ __m128i samples128_8; __m128i prediction128; __m128i riceParamMask128; - const ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - MA_DR_FLAC_ASSERT(order <= 12); - riceParamMask = (ma_uint32)~((~0UL) << riceParam); + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + DRFLAC_ASSERT(order <= 12); + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); riceParamMask128 = _mm_set1_epi32(riceParamMask); prediction128 = _mm_setzero_si128(); coefficients128_0 = _mm_setzero_si128(); @@ -85068,34 +54974,34 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_64(ma_dr_ #else switch (order) { - case 12: ((ma_int32*)&coefficients128_8)[0] = coefficients[11]; ((ma_int32*)&samples128_8)[0] = pDecodedSamples[-12]; - case 11: ((ma_int32*)&coefficients128_8)[1] = coefficients[10]; ((ma_int32*)&samples128_8)[1] = pDecodedSamples[-11]; - case 10: ((ma_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((ma_int32*)&samples128_8)[2] = pDecodedSamples[-10]; - case 9: ((ma_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((ma_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; - case 8: ((ma_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((ma_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; - case 7: ((ma_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((ma_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; - case 6: ((ma_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((ma_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; - case 5: ((ma_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((ma_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; - case 4: ((ma_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((ma_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; - case 3: ((ma_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((ma_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; - case 2: ((ma_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((ma_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; - case 1: ((ma_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((ma_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; + case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12]; + case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11]; + case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10]; + case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; + case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; + case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; + case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; + case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; + case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; + case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; + case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; + case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; } #endif while (pDecodedSamples < pDecodedSamplesEnd) { __m128i zeroCountPart128; __m128i riceParamPart128; - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { + return DRFLAC_FALSE; } zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); - riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(ma_dr_flac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1))); + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1))); for (i = 0; i < 4; i += 1) { prediction128 = _mm_xor_si128(prediction128, prediction128); switch (order) @@ -85113,8 +55019,8 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_64(ma_dr_ case 2: case 1: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(3, 3, 2, 2)))); } - prediction128 = ma_dr_flac__mm_hadd_epi64(prediction128); - prediction128 = ma_dr_flac__mm_srai_epi64(prediction128, shift); + prediction128 = drflac__mm_hadd_epi64(prediction128); + prediction128 = drflac__mm_srai_epi64(prediction128, shift); prediction128 = _mm_add_epi32(riceParamPart128, prediction128); samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); @@ -85126,103 +55032,103 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41_64(ma_dr_ } i = (count & ~3); while (i < (int)count) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; } riceParamParts0 &= riceParamMask; riceParamParts0 |= (zeroCountParts0 << riceParam); riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; - pDecodedSamples[0] = riceParamParts0 + ma_dr_flac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); i += 1; pDecodedSamples += 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__sse41(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 riceParam, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pSamplesOut != NULL); - if (lpcOrder > 0 && lpcOrder <= 12) { - if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - return ma_dr_flac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + if (order > 0 && order <= 12) { + if (bitsPerSample+shift > 32) { + return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } else { - return ma_dr_flac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } } else { - return ma_dr_flac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac__vst2q_s32(ma_int32* p, int32x4x2_t x) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x) { vst1q_s32(p+0, x.val[0]); vst1q_s32(p+4, x.val[1]); } -static MA_INLINE void ma_dr_flac__vst2q_u32(ma_uint32* p, uint32x4x2_t x) +static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x) { vst1q_u32(p+0, x.val[0]); vst1q_u32(p+4, x.val[1]); } -static MA_INLINE void ma_dr_flac__vst2q_f32(float* p, float32x4x2_t x) +static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x) { vst1q_f32(p+0, x.val[0]); vst1q_f32(p+4, x.val[1]); } -static MA_INLINE void ma_dr_flac__vst2q_s16(ma_int16* p, int16x4x2_t x) +static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x) { vst1q_s16(p, vcombine_s16(x.val[0], x.val[1])); } -static MA_INLINE void ma_dr_flac__vst2q_u16(ma_uint16* p, uint16x4x2_t x) +static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x) { vst1q_u16(p, vcombine_u16(x.val[0], x.val[1])); } -static MA_INLINE int32x4_t ma_dr_flac__vdupq_n_s32x4(ma_int32 x3, ma_int32 x2, ma_int32 x1, ma_int32 x0) +static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0) { - ma_int32 x[4]; + drflac_int32 x[4]; x[3] = x3; x[2] = x2; x[1] = x1; x[0] = x0; return vld1q_s32(x); } -static MA_INLINE int32x4_t ma_dr_flac__valignrq_s32_1(int32x4_t a, int32x4_t b) +static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b) { return vextq_s32(b, a, 1); } -static MA_INLINE uint32x4_t ma_dr_flac__valignrq_u32_1(uint32x4_t a, uint32x4_t b) +static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b) { return vextq_u32(b, a, 1); } -static MA_INLINE int32x2_t ma_dr_flac__vhaddq_s32(int32x4_t x) +static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x) { int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x)); return vpadd_s32(r, r); } -static MA_INLINE int64x1_t ma_dr_flac__vhaddq_s64(int64x2_t x) +static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x) { return vadd_s64(vget_high_s64(x), vget_low_s64(x)); } -static MA_INLINE int32x4_t ma_dr_flac__vrevq_s32(int32x4_t x) +static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x) { return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x))); } -static MA_INLINE int32x4_t ma_dr_flac__vnotq_s32(int32x4_t x) +static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x) { return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF)); } -static MA_INLINE uint32x4_t ma_dr_flac__vnotq_u32(uint32x4_t x) +static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x) { return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF)); } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_32(ma_dr_flac_bs* bs, ma_uint32 count, ma_uint8 riceParam, ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { int i; - ma_uint32 riceParamMask; - ma_int32* pDecodedSamples = pSamplesOut; - ma_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); - ma_uint32 zeroCountParts[4]; - ma_uint32 riceParamParts[4]; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts[4]; + drflac_uint32 riceParamParts[4]; int32x4_t coefficients128_0; int32x4_t coefficients128_4; int32x4_t coefficients128_8; @@ -85233,16 +55139,16 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_32(ma_dr_f int32x4_t riceParam128; int32x2_t shift64; uint32x4_t one128; - const ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = (ma_uint32)~((~0UL) << riceParam); + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + riceParamMask = ~((~0UL) << riceParam); riceParamMask128 = vdupq_n_u32(riceParamMask); riceParam128 = vdupq_n_s32(riceParam); shift64 = vdup_n_s32(-shift); one128 = vdupq_n_u32(1); { int runningOrder = order; - ma_int32 tempC[4] = {0, 0, 0, 0}; - ma_int32 tempS[4] = {0, 0, 0, 0}; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; if (runningOrder >= 4) { coefficients128_0 = vld1q_s32(coefficients + 0); samples128_0 = vld1q_s32(pSamplesOut - 4); @@ -85285,58 +55191,58 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_32(ma_dr_f samples128_8 = vld1q_s32(tempS); runningOrder = 0; } - coefficients128_0 = ma_dr_flac__vrevq_s32(coefficients128_0); - coefficients128_4 = ma_dr_flac__vrevq_s32(coefficients128_4); - coefficients128_8 = ma_dr_flac__vrevq_s32(coefficients128_8); + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); } while (pDecodedSamples < pDecodedSamplesEnd) { int32x4_t prediction128; int32x2_t prediction64; uint32x4_t zeroCountPart128; uint32x4_t riceParamPart128; - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { + return DRFLAC_FALSE; } zeroCountPart128 = vld1q_u32(zeroCountParts); riceParamPart128 = vld1q_u32(riceParamParts); riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128); riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128)); - riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(ma_dr_flac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); if (order <= 4) { for (i = 0; i < 4; i += 1) { prediction128 = vmulq_s32(coefficients128_0, samples128_0); - prediction64 = ma_dr_flac__vhaddq_s32(prediction128); + prediction64 = drflac__vhaddq_s32(prediction128); prediction64 = vshl_s32(prediction64, shift64); prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); - samples128_0 = ma_dr_flac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); - riceParamPart128 = ma_dr_flac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); } } else if (order <= 8) { for (i = 0; i < 4; i += 1) { prediction128 = vmulq_s32(coefficients128_4, samples128_4); prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0); - prediction64 = ma_dr_flac__vhaddq_s32(prediction128); + prediction64 = drflac__vhaddq_s32(prediction128); prediction64 = vshl_s32(prediction64, shift64); prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); - samples128_4 = ma_dr_flac__valignrq_s32_1(samples128_0, samples128_4); - samples128_0 = ma_dr_flac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); - riceParamPart128 = ma_dr_flac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); } } else { for (i = 0; i < 4; i += 1) { prediction128 = vmulq_s32(coefficients128_8, samples128_8); prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4); prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0); - prediction64 = ma_dr_flac__vhaddq_s32(prediction128); + prediction64 = drflac__vhaddq_s32(prediction128); prediction64 = vshl_s32(prediction64, shift64); prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); - samples128_8 = ma_dr_flac__valignrq_s32_1(samples128_4, samples128_8); - samples128_4 = ma_dr_flac__valignrq_s32_1(samples128_0, samples128_4); - samples128_0 = ma_dr_flac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); - riceParamPart128 = ma_dr_flac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); } } vst1q_s32(pDecodedSamples, samples128_0); @@ -85344,26 +55250,26 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_32(ma_dr_f } i = (count & ~3); while (i < (int)count) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; } riceParamParts[0] &= riceParamMask; riceParamParts[0] |= (zeroCountParts[0] << riceParam); riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; - pDecodedSamples[0] = riceParamParts[0] + ma_dr_flac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); i += 1; pDecodedSamples += 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_64(ma_dr_flac_bs* bs, ma_uint32 count, ma_uint8 riceParam, ma_uint32 order, ma_int32 shift, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { int i; - ma_uint32 riceParamMask; - ma_int32* pDecodedSamples = pSamplesOut; - ma_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); - ma_uint32 zeroCountParts[4]; - ma_uint32 riceParamParts[4]; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts[4]; + drflac_uint32 riceParamParts[4]; int32x4_t coefficients128_0; int32x4_t coefficients128_4; int32x4_t coefficients128_8; @@ -85374,19 +55280,16 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_64(ma_dr_f int32x4_t riceParam128; int64x1_t shift64; uint32x4_t one128; - int64x2_t prediction128 = { 0 }; - uint32x4_t zeroCountPart128; - uint32x4_t riceParamPart128; - const ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = (ma_uint32)~((~0UL) << riceParam); + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + riceParamMask = ~((~0UL) << riceParam); riceParamMask128 = vdupq_n_u32(riceParamMask); riceParam128 = vdupq_n_s32(riceParam); shift64 = vdup_n_s64(-shift); one128 = vdupq_n_u32(1); { int runningOrder = order; - ma_int32 tempC[4] = {0, 0, 0, 0}; - ma_int32 tempS[4] = {0, 0, 0, 0}; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; if (runningOrder >= 4) { coefficients128_0 = vld1q_s32(coefficients + 0); samples128_0 = vld1q_s32(pSamplesOut - 4); @@ -85429,22 +55332,25 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_64(ma_dr_f samples128_8 = vld1q_s32(tempS); runningOrder = 0; } - coefficients128_0 = ma_dr_flac__vrevq_s32(coefficients128_0); - coefficients128_4 = ma_dr_flac__vrevq_s32(coefficients128_4); - coefficients128_8 = ma_dr_flac__vrevq_s32(coefficients128_8); + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); } while (pDecodedSamples < pDecodedSamplesEnd) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || - !ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { - return MA_FALSE; + int64x2_t prediction128; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { + return DRFLAC_FALSE; } zeroCountPart128 = vld1q_u32(zeroCountParts); riceParamPart128 = vld1q_u32(riceParamParts); riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128); riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128)); - riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(ma_dr_flac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); for (i = 0; i < 4; i += 1) { int64x1_t prediction64; prediction128 = veorq_s64(prediction128, prediction128); @@ -85463,156 +55369,153 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon_64(ma_dr_f case 2: case 1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0))); } - prediction64 = ma_dr_flac__vhaddq_s64(prediction128); + prediction64 = drflac__vhaddq_s64(prediction128); prediction64 = vshl_s64(prediction64, shift64); prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0))); - samples128_8 = ma_dr_flac__valignrq_s32_1(samples128_4, samples128_8); - samples128_4 = ma_dr_flac__valignrq_s32_1(samples128_0, samples128_4); - samples128_0 = ma_dr_flac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0); - riceParamPart128 = ma_dr_flac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); } vst1q_s32(pDecodedSamples, samples128_0); pDecodedSamples += 4; } i = (count & ~3); while (i < (int)count) { - if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { - return MA_FALSE; + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; } riceParamParts[0] &= riceParamMask; riceParamParts[0] |= (zeroCountParts[0] << riceParam); riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; - pDecodedSamples[0] = riceParamParts[0] + ma_dr_flac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); i += 1; pDecodedSamples += 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice__neon(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 riceParam, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(pSamplesOut != NULL); - if (lpcOrder > 0 && lpcOrder <= 12) { - if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - return ma_dr_flac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + if (order > 0 && order <= 12) { + if (bitsPerSample+shift > 32) { + return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } else { - return ma_dr_flac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); } } else { - return ma_dr_flac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } } #endif -static ma_bool32 ma_dr_flac__decode_samples_with_residual__rice(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 riceParam, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { -#if defined(MA_DR_FLAC_SUPPORT_SSE41) - if (ma_dr_flac__gIsSSE41Supported) { - return ma_dr_flac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); +#if defined(DRFLAC_SUPPORT_SSE41) + if (drflac__gIsSSE41Supported) { + return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported) { - return ma_dr_flac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported) { + return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); } else #endif { #if 0 - return ma_dr_flac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); #else - return ma_dr_flac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); #endif } } -static ma_bool32 ma_dr_flac__read_and_seek_residual__rice(ma_dr_flac_bs* bs, ma_uint32 count, ma_uint8 riceParam) +static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam) { - ma_uint32 i; - MA_DR_FLAC_ASSERT(bs != NULL); + drflac_uint32 i; + DRFLAC_ASSERT(bs != NULL); for (i = 0; i < count; ++i) { - if (!ma_dr_flac__seek_rice_parts(bs, riceParam)) { - return MA_FALSE; + if (!drflac__seek_rice_parts(bs, riceParam)) { + return DRFLAC_FALSE; } } - return MA_TRUE; + return DRFLAC_TRUE; } -#if defined(__clang__) -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -static ma_bool32 ma_dr_flac__decode_samples_with_residual__unencoded(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 count, ma_uint8 unencodedBitsPerSample, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - ma_uint32 i; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(unencodedBitsPerSample <= 31); - MA_DR_FLAC_ASSERT(pSamplesOut != NULL); + drflac_uint32 i; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(unencodedBitsPerSample <= 31); + DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { if (unencodedBitsPerSample > 0) { - if (!ma_dr_flac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { - return MA_FALSE; + if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { + return DRFLAC_FALSE; } } else { pSamplesOut[i] = 0; } - if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { - pSamplesOut[i] += ma_dr_flac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + if (bitsPerSample >= 24) { + pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] += ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); } } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples_with_residual(ma_dr_flac_bs* bs, ma_uint32 bitsPerSample, ma_uint32 blockSize, ma_uint32 lpcOrder, ma_int32 lpcShift, ma_uint32 lpcPrecision, const ma_int32* coefficients, ma_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - ma_uint8 residualMethod; - ma_uint8 partitionOrder; - ma_uint32 samplesInPartition; - ma_uint32 partitionsRemaining; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(blockSize != 0); - MA_DR_FLAC_ASSERT(pDecodedSamples != NULL); - if (!ma_dr_flac__read_uint8(bs, 2, &residualMethod)) { - return MA_FALSE; + drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + DRFLAC_ASSERT(pDecodedSamples != NULL); + if (!drflac__read_uint8(bs, 2, &residualMethod)) { + return DRFLAC_FALSE; } - if (residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - return MA_FALSE; + if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return DRFLAC_FALSE; } - pDecodedSamples += lpcOrder; - if (!ma_dr_flac__read_uint8(bs, 4, &partitionOrder)) { - return MA_FALSE; + pDecodedSamples += order; + if (!drflac__read_uint8(bs, 4, &partitionOrder)) { + return DRFLAC_FALSE; } if (partitionOrder > 8) { - return MA_FALSE; + return DRFLAC_FALSE; } - if ((blockSize / (1 << partitionOrder)) < lpcOrder) { - return MA_FALSE; + if ((blockSize / (1 << partitionOrder)) < order) { + return DRFLAC_FALSE; } - samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; partitionsRemaining = (1 << partitionOrder); for (;;) { - ma_uint8 riceParam = 0; - if (residualMethod == MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { - if (!ma_dr_flac__read_uint8(bs, 4, &riceParam)) { - return MA_FALSE; + drflac_uint8 riceParam = 0; + if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { + if (!drflac__read_uint8(bs, 4, &riceParam)) { + return DRFLAC_FALSE; } if (riceParam == 15) { riceParam = 0xFF; } - } else if (residualMethod == MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - if (!ma_dr_flac__read_uint8(bs, 5, &riceParam)) { - return MA_FALSE; + } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + if (!drflac__read_uint8(bs, 5, &riceParam)) { + return DRFLAC_FALSE; } if (riceParam == 31) { riceParam = 0xFF; } } if (riceParam != 0xFF) { - if (!ma_dr_flac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { - return MA_FALSE; + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; } } else { - ma_uint8 unencodedBitsPerSample = 0; - if (!ma_dr_flac__read_uint8(bs, 5, &unencodedBitsPerSample)) { - return MA_FALSE; + drflac_uint8 unencodedBitsPerSample = 0; + if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { - return MA_FALSE; + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; } } pDecodedSamples += samplesInPartition; @@ -85624,62 +55527,62 @@ static ma_bool32 ma_dr_flac__decode_samples_with_residual(ma_dr_flac_bs* bs, ma_ samplesInPartition = blockSize / (1 << partitionOrder); } } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__read_and_seek_residual(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 order) +static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order) { - ma_uint8 residualMethod; - ma_uint8 partitionOrder; - ma_uint32 samplesInPartition; - ma_uint32 partitionsRemaining; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(blockSize != 0); - if (!ma_dr_flac__read_uint8(bs, 2, &residualMethod)) { - return MA_FALSE; + drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + if (!drflac__read_uint8(bs, 2, &residualMethod)) { + return DRFLAC_FALSE; } - if (residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - return MA_FALSE; + if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_uint8(bs, 4, &partitionOrder)) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 4, &partitionOrder)) { + return DRFLAC_FALSE; } if (partitionOrder > 8) { - return MA_FALSE; + return DRFLAC_FALSE; } if ((blockSize / (1 << partitionOrder)) <= order) { - return MA_FALSE; + return DRFLAC_FALSE; } samplesInPartition = (blockSize / (1 << partitionOrder)) - order; partitionsRemaining = (1 << partitionOrder); for (;;) { - ma_uint8 riceParam = 0; - if (residualMethod == MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { - if (!ma_dr_flac__read_uint8(bs, 4, &riceParam)) { - return MA_FALSE; + drflac_uint8 riceParam = 0; + if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { + if (!drflac__read_uint8(bs, 4, &riceParam)) { + return DRFLAC_FALSE; } if (riceParam == 15) { riceParam = 0xFF; } - } else if (residualMethod == MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - if (!ma_dr_flac__read_uint8(bs, 5, &riceParam)) { - return MA_FALSE; + } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + if (!drflac__read_uint8(bs, 5, &riceParam)) { + return DRFLAC_FALSE; } if (riceParam == 31) { riceParam = 0xFF; } } if (riceParam != 0xFF) { - if (!ma_dr_flac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) { - return MA_FALSE; + if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) { + return DRFLAC_FALSE; } } else { - ma_uint8 unencodedBitsPerSample = 0; - if (!ma_dr_flac__read_uint8(bs, 5, &unencodedBitsPerSample)) { - return MA_FALSE; + drflac_uint8 unencodedBitsPerSample = 0; + if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) { + return DRFLAC_FALSE; } } if (partitionsRemaining == 1) { @@ -85688,36 +55591,36 @@ static ma_bool32 ma_dr_flac__read_and_seek_residual(ma_dr_flac_bs* bs, ma_uint32 partitionsRemaining -= 1; samplesInPartition = blockSize / (1 << partitionOrder); } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples__constant(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 subframeBitsPerSample, ma_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) { - ma_uint32 i; - ma_int32 sample; - if (!ma_dr_flac__read_int32(bs, subframeBitsPerSample, &sample)) { - return MA_FALSE; + drflac_uint32 i; + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; } for (i = 0; i < blockSize; ++i) { pDecodedSamples[i] = sample; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples__verbatim(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 subframeBitsPerSample, ma_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) { - ma_uint32 i; + drflac_uint32 i; for (i = 0; i < blockSize; ++i) { - ma_int32 sample; - if (!ma_dr_flac__read_int32(bs, subframeBitsPerSample, &sample)) { - return MA_FALSE; + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; } pDecodedSamples[i] = sample; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples__fixed(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 subframeBitsPerSample, ma_uint8 lpcOrder, ma_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { - ma_uint32 i; - static ma_int32 lpcCoefficientsTable[5][4] = { + drflac_uint32 i; + static drflac_int32 lpcCoefficientsTable[5][4] = { {0, 0, 0, 0}, {1, 0, 0, 0}, {2, -1, 0, 0}, @@ -85725,122 +55628,122 @@ static ma_bool32 ma_dr_flac__decode_samples__fixed(ma_dr_flac_bs* bs, ma_uint32 {4, -6, 4, -1} }; for (i = 0; i < lpcOrder; ++i) { - ma_int32 sample; - if (!ma_dr_flac__read_int32(bs, subframeBitsPerSample, &sample)) { - return MA_FALSE; + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; } pDecodedSamples[i] = sample; } - if (!ma_dr_flac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { - return MA_FALSE; + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + return DRFLAC_FALSE; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_samples__lpc(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 bitsPerSample, ma_uint8 lpcOrder, ma_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { - ma_uint8 i; - ma_uint8 lpcPrecision; - ma_int8 lpcShift; - ma_int32 coefficients[32]; + drflac_uint8 i; + drflac_uint8 lpcPrecision; + drflac_int8 lpcShift; + drflac_int32 coefficients[32]; for (i = 0; i < lpcOrder; ++i) { - ma_int32 sample; - if (!ma_dr_flac__read_int32(bs, bitsPerSample, &sample)) { - return MA_FALSE; + drflac_int32 sample; + if (!drflac__read_int32(bs, bitsPerSample, &sample)) { + return DRFLAC_FALSE; } pDecodedSamples[i] = sample; } - if (!ma_dr_flac__read_uint8(bs, 4, &lpcPrecision)) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { + return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return MA_FALSE; + return DRFLAC_FALSE; } lpcPrecision += 1; - if (!ma_dr_flac__read_int8(bs, 5, &lpcShift)) { - return MA_FALSE; + if (!drflac__read_int8(bs, 5, &lpcShift)) { + return DRFLAC_FALSE; } if (lpcShift < 0) { - return MA_FALSE; + return DRFLAC_FALSE; } - MA_DR_FLAC_ZERO_MEMORY(coefficients, sizeof(coefficients)); + DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients)); for (i = 0; i < lpcOrder; ++i) { - if (!ma_dr_flac__read_int32(bs, lpcPrecision, coefficients + i)) { - return MA_FALSE; + if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { + return DRFLAC_FALSE; } } - if (!ma_dr_flac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { - return MA_FALSE; + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__read_next_flac_frame_header(ma_dr_flac_bs* bs, ma_uint8 streaminfoBitsPerSample, ma_dr_flac_frame_header* header) +static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header) { - const ma_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; - const ma_uint8 bitsPerSampleTable[8] = {0, 8, 12, (ma_uint8)-1, 16, 20, 24, (ma_uint8)-1}; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(header != NULL); + const drflac_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; + const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(header != NULL); for (;;) { - ma_uint8 crc8 = 0xCE; - ma_uint8 reserved = 0; - ma_uint8 blockingStrategy = 0; - ma_uint8 blockSize = 0; - ma_uint8 sampleRate = 0; - ma_uint8 channelAssignment = 0; - ma_uint8 bitsPerSample = 0; - ma_bool32 isVariableBlockSize; - if (!ma_dr_flac__find_and_seek_to_next_sync_code(bs)) { - return MA_FALSE; + drflac_uint8 crc8 = 0xCE; + drflac_uint8 reserved = 0; + drflac_uint8 blockingStrategy = 0; + drflac_uint8 blockSize = 0; + drflac_uint8 sampleRate = 0; + drflac_uint8 channelAssignment = 0; + drflac_uint8 bitsPerSample = 0; + drflac_bool32 isVariableBlockSize; + if (!drflac__find_and_seek_to_next_sync_code(bs)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_uint8(bs, 1, &reserved)) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; } if (reserved == 1) { continue; } - crc8 = ma_dr_flac_crc8(crc8, reserved, 1); - if (!ma_dr_flac__read_uint8(bs, 1, &blockingStrategy)) { - return MA_FALSE; + crc8 = drflac_crc8(crc8, reserved, 1); + if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { + return DRFLAC_FALSE; } - crc8 = ma_dr_flac_crc8(crc8, blockingStrategy, 1); - if (!ma_dr_flac__read_uint8(bs, 4, &blockSize)) { - return MA_FALSE; + crc8 = drflac_crc8(crc8, blockingStrategy, 1); + if (!drflac__read_uint8(bs, 4, &blockSize)) { + return DRFLAC_FALSE; } if (blockSize == 0) { continue; } - crc8 = ma_dr_flac_crc8(crc8, blockSize, 4); - if (!ma_dr_flac__read_uint8(bs, 4, &sampleRate)) { - return MA_FALSE; + crc8 = drflac_crc8(crc8, blockSize, 4); + if (!drflac__read_uint8(bs, 4, &sampleRate)) { + return DRFLAC_FALSE; } - crc8 = ma_dr_flac_crc8(crc8, sampleRate, 4); - if (!ma_dr_flac__read_uint8(bs, 4, &channelAssignment)) { - return MA_FALSE; + crc8 = drflac_crc8(crc8, sampleRate, 4); + if (!drflac__read_uint8(bs, 4, &channelAssignment)) { + return DRFLAC_FALSE; } if (channelAssignment > 10) { continue; } - crc8 = ma_dr_flac_crc8(crc8, channelAssignment, 4); - if (!ma_dr_flac__read_uint8(bs, 3, &bitsPerSample)) { - return MA_FALSE; + crc8 = drflac_crc8(crc8, channelAssignment, 4); + if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { + return DRFLAC_FALSE; } if (bitsPerSample == 3 || bitsPerSample == 7) { continue; } - crc8 = ma_dr_flac_crc8(crc8, bitsPerSample, 3); - if (!ma_dr_flac__read_uint8(bs, 1, &reserved)) { - return MA_FALSE; + crc8 = drflac_crc8(crc8, bitsPerSample, 3); + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; } if (reserved == 1) { continue; } - crc8 = ma_dr_flac_crc8(crc8, reserved, 1); + crc8 = drflac_crc8(crc8, reserved, 1); isVariableBlockSize = blockingStrategy == 1; if (isVariableBlockSize) { - ma_uint64 pcmFrameNumber; - ma_result result = ma_dr_flac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8); - if (result != MA_SUCCESS) { - if (result == MA_AT_END) { - return MA_FALSE; + drflac_uint64 pcmFrameNumber; + drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_AT_END) { + return DRFLAC_FALSE; } else { continue; } @@ -85848,61 +55751,58 @@ static ma_bool32 ma_dr_flac__read_next_flac_frame_header(ma_dr_flac_bs* bs, ma_u header->flacFrameNumber = 0; header->pcmFrameNumber = pcmFrameNumber; } else { - ma_uint64 flacFrameNumber = 0; - ma_result result = ma_dr_flac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8); - if (result != MA_SUCCESS) { - if (result == MA_AT_END) { - return MA_FALSE; + drflac_uint64 flacFrameNumber = 0; + drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_AT_END) { + return DRFLAC_FALSE; } else { continue; } } - header->flacFrameNumber = (ma_uint32)flacFrameNumber; + header->flacFrameNumber = (drflac_uint32)flacFrameNumber; header->pcmFrameNumber = 0; } - MA_DR_FLAC_ASSERT(blockSize > 0); + DRFLAC_ASSERT(blockSize > 0); if (blockSize == 1) { header->blockSizeInPCMFrames = 192; } else if (blockSize <= 5) { - MA_DR_FLAC_ASSERT(blockSize >= 2); + DRFLAC_ASSERT(blockSize >= 2); header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2)); } else if (blockSize == 6) { - if (!ma_dr_flac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) { - return MA_FALSE; + if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) { + return DRFLAC_FALSE; } - crc8 = ma_dr_flac_crc8(crc8, header->blockSizeInPCMFrames, 8); + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8); header->blockSizeInPCMFrames += 1; } else if (blockSize == 7) { - if (!ma_dr_flac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) { - return MA_FALSE; - } - crc8 = ma_dr_flac_crc8(crc8, header->blockSizeInPCMFrames, 16); - if (header->blockSizeInPCMFrames == 0xFFFF) { - return MA_FALSE; + if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) { + return DRFLAC_FALSE; } + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16); header->blockSizeInPCMFrames += 1; } else { - MA_DR_FLAC_ASSERT(blockSize >= 8); + DRFLAC_ASSERT(blockSize >= 8); header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8)); } if (sampleRate <= 11) { header->sampleRate = sampleRateTable[sampleRate]; } else if (sampleRate == 12) { - if (!ma_dr_flac__read_uint32(bs, 8, &header->sampleRate)) { - return MA_FALSE; + if (!drflac__read_uint32(bs, 8, &header->sampleRate)) { + return DRFLAC_FALSE; } - crc8 = ma_dr_flac_crc8(crc8, header->sampleRate, 8); + crc8 = drflac_crc8(crc8, header->sampleRate, 8); header->sampleRate *= 1000; } else if (sampleRate == 13) { - if (!ma_dr_flac__read_uint32(bs, 16, &header->sampleRate)) { - return MA_FALSE; + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; } - crc8 = ma_dr_flac_crc8(crc8, header->sampleRate, 16); + crc8 = drflac_crc8(crc8, header->sampleRate, 16); } else if (sampleRate == 14) { - if (!ma_dr_flac__read_uint32(bs, 16, &header->sampleRate)) { - return MA_FALSE; + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; } - crc8 = ma_dr_flac_crc8(crc8, header->sampleRate, 16); + crc8 = drflac_crc8(crc8, header->sampleRate, 16); header->sampleRate *= 10; } else { continue; @@ -85912,291 +55812,281 @@ static ma_bool32 ma_dr_flac__read_next_flac_frame_header(ma_dr_flac_bs* bs, ma_u if (header->bitsPerSample == 0) { header->bitsPerSample = streaminfoBitsPerSample; } - if (header->bitsPerSample != streaminfoBitsPerSample) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 8, &header->crc8)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_uint8(bs, 8, &header->crc8)) { - return MA_FALSE; - } -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC if (header->crc8 != crc8) { continue; } #endif - return MA_TRUE; + return DRFLAC_TRUE; } } -static ma_bool32 ma_dr_flac__read_subframe_header(ma_dr_flac_bs* bs, ma_dr_flac_subframe* pSubframe) +static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe) { - ma_uint8 header; + drflac_uint8 header; int type; - if (!ma_dr_flac__read_uint8(bs, 8, &header)) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 8, &header)) { + return DRFLAC_FALSE; } if ((header & 0x80) != 0) { - return MA_FALSE; + return DRFLAC_FALSE; } - pSubframe->lpcOrder = 0; type = (header & 0x7E) >> 1; if (type == 0) { - pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_CONSTANT; + pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT; } else if (type == 1) { - pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_VERBATIM; + pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM; } else { if ((type & 0x20) != 0) { - pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_LPC; - pSubframe->lpcOrder = (ma_uint8)(type & 0x1F) + 1; + pSubframe->subframeType = DRFLAC_SUBFRAME_LPC; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1; } else if ((type & 0x08) != 0) { - pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_FIXED; - pSubframe->lpcOrder = (ma_uint8)(type & 0x07); + pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x07); if (pSubframe->lpcOrder > 4) { - pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_RESERVED; + pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; pSubframe->lpcOrder = 0; } } else { - pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_RESERVED; + pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; } } - if (pSubframe->subframeType == MA_DR_FLAC_SUBFRAME_RESERVED) { - return MA_FALSE; + if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) { + return DRFLAC_FALSE; } pSubframe->wastedBitsPerSample = 0; if ((header & 0x01) == 1) { unsigned int wastedBitsPerSample; - if (!ma_dr_flac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) { - return MA_FALSE; + if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) { + return DRFLAC_FALSE; } - pSubframe->wastedBitsPerSample = (ma_uint8)wastedBitsPerSample + 1; + pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_subframe(ma_dr_flac_bs* bs, ma_dr_flac_frame* frame, int subframeIndex, ma_int32* pDecodedSamplesOut) +static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut) { - ma_dr_flac_subframe* pSubframe; - ma_uint32 subframeBitsPerSample; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(frame != NULL); + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); pSubframe = frame->subframes + subframeIndex; - if (!ma_dr_flac__read_subframe_header(bs, pSubframe)) { - return MA_FALSE; + if (!drflac__read_subframe_header(bs, pSubframe)) { + return DRFLAC_FALSE; } subframeBitsPerSample = frame->header.bitsPerSample; - if ((frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { + if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { subframeBitsPerSample += 1; - } else if (frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { subframeBitsPerSample += 1; } - if (subframeBitsPerSample > 32) { - return MA_FALSE; - } if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { - return MA_FALSE; + return DRFLAC_FALSE; } subframeBitsPerSample -= pSubframe->wastedBitsPerSample; pSubframe->pSamplesS32 = pDecodedSamplesOut; - if (frame->header.blockSizeInPCMFrames < pSubframe->lpcOrder) { - return MA_FALSE; - } switch (pSubframe->subframeType) { - case MA_DR_FLAC_SUBFRAME_CONSTANT: + case DRFLAC_SUBFRAME_CONSTANT: { - ma_dr_flac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); } break; - case MA_DR_FLAC_SUBFRAME_VERBATIM: + case DRFLAC_SUBFRAME_VERBATIM: { - ma_dr_flac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); } break; - case MA_DR_FLAC_SUBFRAME_FIXED: + case DRFLAC_SUBFRAME_FIXED: { - ma_dr_flac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); } break; - case MA_DR_FLAC_SUBFRAME_LPC: + case DRFLAC_SUBFRAME_LPC: { - ma_dr_flac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); } break; - default: return MA_FALSE; + default: return DRFLAC_FALSE; } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__seek_subframe(ma_dr_flac_bs* bs, ma_dr_flac_frame* frame, int subframeIndex) +static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) { - ma_dr_flac_subframe* pSubframe; - ma_uint32 subframeBitsPerSample; - MA_DR_FLAC_ASSERT(bs != NULL); - MA_DR_FLAC_ASSERT(frame != NULL); + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); pSubframe = frame->subframes + subframeIndex; - if (!ma_dr_flac__read_subframe_header(bs, pSubframe)) { - return MA_FALSE; + if (!drflac__read_subframe_header(bs, pSubframe)) { + return DRFLAC_FALSE; } subframeBitsPerSample = frame->header.bitsPerSample; - if ((frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { + if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { subframeBitsPerSample += 1; - } else if (frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { subframeBitsPerSample += 1; } if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { - return MA_FALSE; + return DRFLAC_FALSE; } subframeBitsPerSample -= pSubframe->wastedBitsPerSample; pSubframe->pSamplesS32 = NULL; switch (pSubframe->subframeType) { - case MA_DR_FLAC_SUBFRAME_CONSTANT: + case DRFLAC_SUBFRAME_CONSTANT: { - if (!ma_dr_flac__seek_bits(bs, subframeBitsPerSample)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, subframeBitsPerSample)) { + return DRFLAC_FALSE; } } break; - case MA_DR_FLAC_SUBFRAME_VERBATIM: + case DRFLAC_SUBFRAME_VERBATIM: { unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample; - if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; } } break; - case MA_DR_FLAC_SUBFRAME_FIXED: + case DRFLAC_SUBFRAME_FIXED: { unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; - if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { - return MA_FALSE; + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return DRFLAC_FALSE; } } break; - case MA_DR_FLAC_SUBFRAME_LPC: + case DRFLAC_SUBFRAME_LPC: { - ma_uint8 lpcPrecision; + drflac_uint8 lpcPrecision; unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; - if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_uint8(bs, 4, &lpcPrecision)) { - return MA_FALSE; + if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { + return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return MA_FALSE; + return DRFLAC_FALSE; } lpcPrecision += 1; bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; - if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { - return MA_FALSE; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { - return MA_FALSE; + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return DRFLAC_FALSE; } } break; - default: return MA_FALSE; + default: return DRFLAC_FALSE; } - return MA_TRUE; + return DRFLAC_TRUE; } -static MA_INLINE ma_uint8 ma_dr_flac__get_channel_count_from_channel_assignment(ma_int8 channelAssignment) +static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment) { - ma_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; - MA_DR_FLAC_ASSERT(channelAssignment <= 10); + drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; + DRFLAC_ASSERT(channelAssignment <= 10); return lookup[channelAssignment]; } -static ma_result ma_dr_flac__decode_flac_frame(ma_dr_flac* pFlac) +static drflac_result drflac__decode_flac_frame(drflac* pFlac) { int channelCount; int i; - ma_uint8 paddingSizeInBits; - ma_uint16 desiredCRC16; -#ifndef MA_DR_FLAC_NO_CRC - ma_uint16 actualCRC16; + drflac_uint8 paddingSizeInBits; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; #endif - MA_DR_FLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes)); + DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes)); if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) { - return MA_ERROR; + return DRFLAC_ERROR; } - channelCount = ma_dr_flac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); if (channelCount != (int)pFlac->channels) { - return MA_ERROR; + return DRFLAC_ERROR; } for (i = 0; i < channelCount; ++i) { - if (!ma_dr_flac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) { - return MA_ERROR; + if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) { + return DRFLAC_ERROR; } } - paddingSizeInBits = (ma_uint8)(MA_DR_FLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7); + paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7); if (paddingSizeInBits > 0) { - ma_uint8 padding = 0; - if (!ma_dr_flac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { - return MA_AT_END; + drflac_uint8 padding = 0; + if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { + return DRFLAC_AT_END; } } -#ifndef MA_DR_FLAC_NO_CRC - actualCRC16 = ma_dr_flac__flush_crc16(&pFlac->bs); +#ifndef DR_FLAC_NO_CRC + actualCRC16 = drflac__flush_crc16(&pFlac->bs); #endif - if (!ma_dr_flac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { - return MA_AT_END; + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_AT_END; } -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC if (actualCRC16 != desiredCRC16) { - return MA_CRC_MISMATCH; + return DRFLAC_CRC_MISMATCH; } #endif pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; - return MA_SUCCESS; + return DRFLAC_SUCCESS; } -static ma_result ma_dr_flac__seek_flac_frame(ma_dr_flac* pFlac) +static drflac_result drflac__seek_flac_frame(drflac* pFlac) { int channelCount; int i; - ma_uint16 desiredCRC16; -#ifndef MA_DR_FLAC_NO_CRC - ma_uint16 actualCRC16; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; #endif - channelCount = ma_dr_flac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); for (i = 0; i < channelCount; ++i) { - if (!ma_dr_flac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) { - return MA_ERROR; + if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) { + return DRFLAC_ERROR; } } - if (!ma_dr_flac__seek_bits(&pFlac->bs, MA_DR_FLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { - return MA_ERROR; + if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { + return DRFLAC_ERROR; } -#ifndef MA_DR_FLAC_NO_CRC - actualCRC16 = ma_dr_flac__flush_crc16(&pFlac->bs); +#ifndef DR_FLAC_NO_CRC + actualCRC16 = drflac__flush_crc16(&pFlac->bs); #endif - if (!ma_dr_flac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { - return MA_AT_END; + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_AT_END; } -#ifndef MA_DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC if (actualCRC16 != desiredCRC16) { - return MA_CRC_MISMATCH; + return DRFLAC_CRC_MISMATCH; } #endif - return MA_SUCCESS; + return DRFLAC_SUCCESS; } -static ma_bool32 ma_dr_flac__read_and_decode_next_flac_frame(ma_dr_flac* pFlac) +static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac) { - MA_DR_FLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pFlac != NULL); for (;;) { - ma_result result; - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + drflac_result result; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } - result = ma_dr_flac__decode_flac_frame(pFlac); - if (result != MA_SUCCESS) { - if (result == MA_CRC_MISMATCH) { + result = drflac__decode_flac_frame(pFlac); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_CRC_MISMATCH) { continue; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } - return MA_TRUE; + return DRFLAC_TRUE; } } -static void ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(ma_dr_flac* pFlac, ma_uint64* pFirstPCMFrame, ma_uint64* pLastPCMFrame) +static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame) { - ma_uint64 firstPCMFrame; - ma_uint64 lastPCMFrame; - MA_DR_FLAC_ASSERT(pFlac != NULL); + drflac_uint64 firstPCMFrame; + drflac_uint64 lastPCMFrame; + DRFLAC_ASSERT(pFlac != NULL); firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber; if (firstPCMFrame == 0) { - firstPCMFrame = ((ma_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames; + firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames; } lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames; if (lastPCMFrame > 0) { @@ -86209,32 +56099,32 @@ static void ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(ma_dr_flac* pF *pLastPCMFrame = lastPCMFrame; } } -static ma_bool32 ma_dr_flac__seek_to_first_frame(ma_dr_flac* pFlac) +static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) { - ma_bool32 result; - MA_DR_FLAC_ASSERT(pFlac != NULL); - result = ma_dr_flac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes); - MA_DR_FLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + drflac_bool32 result; + DRFLAC_ASSERT(pFlac != NULL); + result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes); + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); pFlac->currentPCMFrame = 0; return result; } -static MA_INLINE ma_result ma_dr_flac__seek_to_next_flac_frame(ma_dr_flac* pFlac) +static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac) { - MA_DR_FLAC_ASSERT(pFlac != NULL); - return ma_dr_flac__seek_flac_frame(pFlac); + DRFLAC_ASSERT(pFlac != NULL); + return drflac__seek_flac_frame(pFlac); } -static ma_uint64 ma_dr_flac__seek_forward_by_pcm_frames(ma_dr_flac* pFlac, ma_uint64 pcmFramesToSeek) +static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek) { - ma_uint64 pcmFramesRead = 0; + drflac_uint64 pcmFramesRead = 0; while (pcmFramesToSeek > 0) { if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { - if (!ma_dr_flac__read_and_decode_next_flac_frame(pFlac)) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { break; } } else { if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) { pcmFramesRead += pcmFramesToSeek; - pFlac->currentFLACFrame.pcmFramesRemaining -= (ma_uint32)pcmFramesToSeek; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek; pcmFramesToSeek = 0; } else { pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining; @@ -86246,107 +56136,107 @@ static ma_uint64 ma_dr_flac__seek_forward_by_pcm_frames(ma_dr_flac* pFlac, ma_ui pFlac->currentPCMFrame += pcmFramesRead; return pcmFramesRead; } -static ma_bool32 ma_dr_flac__seek_to_pcm_frame__brute_force(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex) { - ma_bool32 isMidFrame = MA_FALSE; - ma_uint64 runningPCMFrameCount; - MA_DR_FLAC_ASSERT(pFlac != NULL); + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + DRFLAC_ASSERT(pFlac != NULL); if (pcmFrameIndex >= pFlac->currentPCMFrame) { runningPCMFrameCount = pFlac->currentPCMFrame; if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } else { - isMidFrame = MA_TRUE; + isMidFrame = DRFLAC_TRUE; } } else { runningPCMFrameCount = 0; - if (!ma_dr_flac__seek_to_first_frame(pFlac)) { - return MA_FALSE; + if (!drflac__seek_to_first_frame(pFlac)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } for (;;) { - ma_uint64 pcmFrameCountInThisFLACFrame; - ma_uint64 firstPCMFrameInFLACFrame = 0; - ma_uint64 lastPCMFrameInFLACFrame = 0; - ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + drflac_uint64 pcmFrameCountInThisFLACFrame; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { - ma_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; if (!isMidFrame) { - ma_result result = ma_dr_flac__decode_flac_frame(pFlac); - if (result == MA_SUCCESS) { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { goto next_iteration; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } } else { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; } } else { if (!isMidFrame) { - ma_result result = ma_dr_flac__seek_to_next_flac_frame(pFlac); - if (result == MA_SUCCESS) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { runningPCMFrameCount += pcmFrameCountInThisFLACFrame; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { goto next_iteration; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } } else { runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; pFlac->currentFLACFrame.pcmFramesRemaining = 0; - isMidFrame = MA_FALSE; + isMidFrame = DRFLAC_FALSE; } if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { - return MA_TRUE; + return DRFLAC_TRUE; } } next_iteration: - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } } -#if !defined(MA_DR_FLAC_NO_CRC) -#define MA_DR_FLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f -static ma_bool32 ma_dr_flac__seek_to_approximate_flac_frame_to_byte(ma_dr_flac* pFlac, ma_uint64 targetByte, ma_uint64 rangeLo, ma_uint64 rangeHi, ma_uint64* pLastSuccessfulSeekOffset) +#if !defined(DR_FLAC_NO_CRC) +#define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f +static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset) { - MA_DR_FLAC_ASSERT(pFlac != NULL); - MA_DR_FLAC_ASSERT(pLastSuccessfulSeekOffset != NULL); - MA_DR_FLAC_ASSERT(targetByte >= rangeLo); - MA_DR_FLAC_ASSERT(targetByte <= rangeHi); + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL); + DRFLAC_ASSERT(targetByte >= rangeLo); + DRFLAC_ASSERT(targetByte <= rangeHi); *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes; for (;;) { - ma_uint64 lastTargetByte = targetByte; - if (!ma_dr_flac__seek_to_byte(&pFlac->bs, targetByte)) { + drflac_uint64 lastTargetByte = targetByte; + if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) { if (targetByte == 0) { - ma_dr_flac__seek_to_first_frame(pFlac); - return MA_FALSE; + drflac__seek_to_first_frame(pFlac); + return DRFLAC_FALSE; } targetByte = rangeLo + ((rangeHi - rangeLo)/2); rangeHi = targetByte; } else { - MA_DR_FLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); #if 1 - if (!ma_dr_flac__read_and_decode_next_flac_frame(pFlac)) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { targetByte = rangeLo + ((rangeHi - rangeLo)/2); rangeHi = targetByte; } else { break; } #else - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { targetByte = rangeLo + ((rangeHi - rangeLo)/2); rangeHi = targetByte; } else { @@ -86355,48 +56245,48 @@ static ma_bool32 ma_dr_flac__seek_to_approximate_flac_frame_to_byte(ma_dr_flac* #endif } if(targetByte == lastTargetByte) { - return MA_FALSE; + return DRFLAC_FALSE; } } - ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); - MA_DR_FLAC_ASSERT(targetByte <= rangeHi); + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + DRFLAC_ASSERT(targetByte <= rangeHi); *pLastSuccessfulSeekOffset = targetByte; - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__decode_flac_frame_and_seek_forward_by_pcm_frames(ma_dr_flac* pFlac, ma_uint64 offset) +static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset) { #if 0 - if (ma_dr_flac__decode_flac_frame(pFlac) != MA_SUCCESS) { - if (ma_dr_flac__read_and_decode_next_flac_frame(pFlac) == MA_FALSE) { - return MA_FALSE; + if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) { + if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; } } #endif - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, offset) == offset; + return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset; } -static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search_internal(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex, ma_uint64 byteRangeLo, ma_uint64 byteRangeHi) +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi) { - ma_uint64 targetByte; - ma_uint64 pcmRangeLo = pFlac->totalPCMFrameCount; - ma_uint64 pcmRangeHi = 0; - ma_uint64 lastSuccessfulSeekOffset = (ma_uint64)-1; - ma_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo; - ma_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; - targetByte = byteRangeLo + (ma_uint64)(((ma_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * MA_DR_FLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO); + drflac_uint64 targetByte; + drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount; + drflac_uint64 pcmRangeHi = 0; + drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1; + drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO); if (targetByte > byteRangeHi) { targetByte = byteRangeHi; } for (;;) { - if (ma_dr_flac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) { - ma_uint64 newPCMRangeLo; - ma_uint64 newPCMRangeHi; - ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi); + if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) { + drflac_uint64 newPCMRangeLo; + drflac_uint64 newPCMRangeHi; + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi); if (pcmRangeLo == newPCMRangeLo) { - if (!ma_dr_flac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) { + if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) { break; } - if (ma_dr_flac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { - return MA_TRUE; + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; } else { break; } @@ -86404,13 +56294,13 @@ static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search_internal(ma_dr_fla pcmRangeLo = newPCMRangeLo; pcmRangeHi = newPCMRangeHi; if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) { - if (ma_dr_flac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) { - return MA_TRUE; + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) { + return DRFLAC_TRUE; } else { break; } } else { - const float approxCompressionRatio = (ma_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((ma_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f); + const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f); if (pcmRangeLo > pcmFrameIndex) { byteRangeHi = lastSuccessfulSeekOffset; if (byteRangeLo > byteRangeHi) { @@ -86422,8 +56312,8 @@ static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search_internal(ma_dr_fla } } else { if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) { - if (ma_dr_flac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { - return MA_TRUE; + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; } else { break; } @@ -86432,7 +56322,7 @@ static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search_internal(ma_dr_fla if (byteRangeHi < byteRangeLo) { byteRangeHi = byteRangeLo; } - targetByte = lastSuccessfulSeekOffset + (ma_uint64)(((ma_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio); + targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio); if (targetByte > byteRangeHi) { targetByte = byteRangeHi; } @@ -86446,37 +56336,34 @@ static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search_internal(ma_dr_fla break; } } - ma_dr_flac__seek_to_first_frame(pFlac); - return MA_FALSE; + drflac__seek_to_first_frame(pFlac); + return DRFLAC_FALSE; } -static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex) { - ma_uint64 byteRangeLo; - ma_uint64 byteRangeHi; - ma_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; - if (ma_dr_flac__seek_to_first_frame(pFlac) == MA_FALSE) { - return MA_FALSE; + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; } if (pcmFrameIndex < seekForwardThreshold) { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex; + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex; } byteRangeLo = pFlac->firstFLACFramePosInBytes; - byteRangeHi = pFlac->firstFLACFramePosInBytes + (ma_uint64)((ma_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); - return ma_dr_flac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi); + byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); + return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi); } #endif -static ma_bool32 ma_dr_flac__seek_to_pcm_frame__seek_table(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex) { - ma_uint32 iClosestSeekpoint = 0; - ma_bool32 isMidFrame = MA_FALSE; - ma_uint64 runningPCMFrameCount; - ma_uint32 iSeekpoint; - MA_DR_FLAC_ASSERT(pFlac != NULL); + drflac_uint32 iClosestSeekpoint = 0; + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + drflac_uint32 iSeekpoint; + DRFLAC_ASSERT(pFlac != NULL); if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { - return MA_FALSE; - } - if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { - return MA_FALSE; + return DRFLAC_FALSE; } for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { @@ -86485,31 +56372,31 @@ static ma_bool32 ma_dr_flac__seek_to_pcm_frame__seek_table(ma_dr_flac* pFlac, ma iClosestSeekpoint = iSeekpoint; } if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) { - return MA_FALSE; + return DRFLAC_FALSE; } if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) { - return MA_FALSE; + return DRFLAC_FALSE; } -#if !defined(MA_DR_FLAC_NO_CRC) +#if !defined(DR_FLAC_NO_CRC) if (pFlac->totalPCMFrameCount > 0) { - ma_uint64 byteRangeLo; - ma_uint64 byteRangeHi; - byteRangeHi = pFlac->firstFLACFramePosInBytes + (ma_uint64)((ma_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset; if (iClosestSeekpoint < pFlac->seekpointCount-1) { - ma_uint32 iNextSeekpoint = iClosestSeekpoint + 1; + drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1; if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) { - return MA_FALSE; + return DRFLAC_FALSE; } - if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((ma_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { + if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; } } - if (ma_dr_flac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { - if (ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); - if (ma_dr_flac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) { - return MA_TRUE; + if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) { + return DRFLAC_TRUE; } } } @@ -86518,173 +56405,173 @@ static ma_bool32 ma_dr_flac__seek_to_pcm_frame__seek_table(ma_dr_flac* pFlac, ma if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) { runningPCMFrameCount = pFlac->currentPCMFrame; if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } else { - isMidFrame = MA_TRUE; + isMidFrame = DRFLAC_TRUE; } } else { runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame; - if (!ma_dr_flac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { - return MA_FALSE; + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } for (;;) { - ma_uint64 pcmFrameCountInThisFLACFrame; - ma_uint64 firstPCMFrameInFLACFrame = 0; - ma_uint64 lastPCMFrameInFLACFrame = 0; - ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + drflac_uint64 pcmFrameCountInThisFLACFrame; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { - ma_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; if (!isMidFrame) { - ma_result result = ma_dr_flac__decode_flac_frame(pFlac); - if (result == MA_SUCCESS) { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { goto next_iteration; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } } else { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; } } else { if (!isMidFrame) { - ma_result result = ma_dr_flac__seek_to_next_flac_frame(pFlac); - if (result == MA_SUCCESS) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { runningPCMFrameCount += pcmFrameCountInThisFLACFrame; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { goto next_iteration; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } } else { runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; pFlac->currentFLACFrame.pcmFramesRemaining = 0; - isMidFrame = MA_FALSE; + isMidFrame = DRFLAC_FALSE; } if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { - return MA_TRUE; + return DRFLAC_TRUE; } } next_iteration: - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } } -#ifndef MA_DR_FLAC_NO_OGG +#ifndef DR_FLAC_NO_OGG typedef struct { - ma_uint8 capturePattern[4]; - ma_uint8 structureVersion; - ma_uint8 headerType; - ma_uint64 granulePosition; - ma_uint32 serialNumber; - ma_uint32 sequenceNumber; - ma_uint32 checksum; - ma_uint8 segmentCount; - ma_uint8 segmentTable[255]; -} ma_dr_flac_ogg_page_header; + drflac_uint8 capturePattern[4]; + drflac_uint8 structureVersion; + drflac_uint8 headerType; + drflac_uint64 granulePosition; + drflac_uint32 serialNumber; + drflac_uint32 sequenceNumber; + drflac_uint32 checksum; + drflac_uint8 segmentCount; + drflac_uint8 segmentTable[255]; +} drflac_ogg_page_header; #endif typedef struct { - ma_dr_flac_read_proc onRead; - ma_dr_flac_seek_proc onSeek; - ma_dr_flac_meta_proc onMeta; - ma_dr_flac_container container; + drflac_read_proc onRead; + drflac_seek_proc onSeek; + drflac_meta_proc onMeta; + drflac_container container; void* pUserData; void* pUserDataMD; - ma_uint32 sampleRate; - ma_uint8 channels; - ma_uint8 bitsPerSample; - ma_uint64 totalPCMFrameCount; - ma_uint16 maxBlockSizeInPCMFrames; - ma_uint64 runningFilePos; - ma_bool32 hasStreamInfoBlock; - ma_bool32 hasMetadataBlocks; - ma_dr_flac_bs bs; - ma_dr_flac_frame_header firstFrameHeader; -#ifndef MA_DR_FLAC_NO_OGG - ma_uint32 oggSerial; - ma_uint64 oggFirstBytePos; - ma_dr_flac_ogg_page_header oggBosHeader; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalPCMFrameCount; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint64 runningFilePos; + drflac_bool32 hasStreamInfoBlock; + drflac_bool32 hasMetadataBlocks; + drflac_bs bs; + drflac_frame_header firstFrameHeader; +#ifndef DR_FLAC_NO_OGG + drflac_uint32 oggSerial; + drflac_uint64 oggFirstBytePos; + drflac_ogg_page_header oggBosHeader; #endif -} ma_dr_flac_init_info; -static MA_INLINE void ma_dr_flac__decode_block_header(ma_uint32 blockHeader, ma_uint8* isLastBlock, ma_uint8* blockType, ma_uint32* blockSize) +} drflac_init_info; +static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) { - blockHeader = ma_dr_flac__be2host_32(blockHeader); - *isLastBlock = (ma_uint8)((blockHeader & 0x80000000UL) >> 31); - *blockType = (ma_uint8)((blockHeader & 0x7F000000UL) >> 24); + blockHeader = drflac__be2host_32(blockHeader); + *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31); + *blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24); *blockSize = (blockHeader & 0x00FFFFFFUL); } -static MA_INLINE ma_bool32 ma_dr_flac__read_and_decode_block_header(ma_dr_flac_read_proc onRead, void* pUserData, ma_uint8* isLastBlock, ma_uint8* blockType, ma_uint32* blockSize) +static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) { - ma_uint32 blockHeader; + drflac_uint32 blockHeader; *blockSize = 0; if (onRead(pUserData, &blockHeader, 4) != 4) { - return MA_FALSE; + return DRFLAC_FALSE; } - ma_dr_flac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize); - return MA_TRUE; + drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize); + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__read_streaminfo(ma_dr_flac_read_proc onRead, void* pUserData, ma_dr_flac_streaminfo* pStreamInfo) +static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) { - ma_uint32 blockSizes; - ma_uint64 frameSizes = 0; - ma_uint64 importantProps; - ma_uint8 md5[16]; + drflac_uint32 blockSizes; + drflac_uint64 frameSizes = 0; + drflac_uint64 importantProps; + drflac_uint8 md5[16]; if (onRead(pUserData, &blockSizes, 4) != 4) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, &frameSizes, 6) != 6) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, &importantProps, 8) != 8) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { - return MA_FALSE; + return DRFLAC_FALSE; } - blockSizes = ma_dr_flac__be2host_32(blockSizes); - frameSizes = ma_dr_flac__be2host_64(frameSizes); - importantProps = ma_dr_flac__be2host_64(importantProps); - pStreamInfo->minBlockSizeInPCMFrames = (ma_uint16)((blockSizes & 0xFFFF0000) >> 16); - pStreamInfo->maxBlockSizeInPCMFrames = (ma_uint16) (blockSizes & 0x0000FFFF); - pStreamInfo->minFrameSizeInPCMFrames = (ma_uint32)((frameSizes & (((ma_uint64)0x00FFFFFF << 16) << 24)) >> 40); - pStreamInfo->maxFrameSizeInPCMFrames = (ma_uint32)((frameSizes & (((ma_uint64)0x00FFFFFF << 16) << 0)) >> 16); - pStreamInfo->sampleRate = (ma_uint32)((importantProps & (((ma_uint64)0x000FFFFF << 16) << 28)) >> 44); - pStreamInfo->channels = (ma_uint8 )((importantProps & (((ma_uint64)0x0000000E << 16) << 24)) >> 41) + 1; - pStreamInfo->bitsPerSample = (ma_uint8 )((importantProps & (((ma_uint64)0x0000001F << 16) << 20)) >> 36) + 1; - pStreamInfo->totalPCMFrameCount = ((importantProps & ((((ma_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF))); - MA_DR_FLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5)); - return MA_TRUE; + blockSizes = drflac__be2host_32(blockSizes); + frameSizes = drflac__be2host_64(frameSizes); + importantProps = drflac__be2host_64(importantProps); + pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16); + pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF); + pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40); + pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 0)) >> 16); + pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44); + pStreamInfo->channels = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1; + pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1; + pStreamInfo->totalPCMFrameCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF))); + DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5)); + return DRFLAC_TRUE; } -static void* ma_dr_flac__malloc_default(size_t sz, void* pUserData) +static void* drflac__malloc_default(size_t sz, void* pUserData) { (void)pUserData; - return MA_DR_FLAC_MALLOC(sz); + return DRFLAC_MALLOC(sz); } -static void* ma_dr_flac__realloc_default(void* p, size_t sz, void* pUserData) +static void* drflac__realloc_default(void* p, size_t sz, void* pUserData) { (void)pUserData; - return MA_DR_FLAC_REALLOC(p, sz); + return DRFLAC_REALLOC(p, sz); } -static void ma_dr_flac__free_default(void* p, void* pUserData) +static void drflac__free_default(void* p, void* pUserData) { (void)pUserData; - MA_DR_FLAC_FREE(p); + DRFLAC_FREE(p); } -static void* ma_dr_flac__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks == NULL) { return NULL; @@ -86697,7 +56584,7 @@ static void* ma_dr_flac__malloc_from_callbacks(size_t sz, const ma_allocation_ca } return NULL; } -static void* ma_dr_flac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks) +static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks == NULL) { return NULL; @@ -86712,14 +56599,14 @@ static void* ma_dr_flac__realloc_from_callbacks(void* p, size_t szNew, size_t sz return NULL; } if (p != NULL) { - MA_DR_FLAC_COPY_MEMORY(p2, p, szOld); + DRFLAC_COPY_MEMORY(p2, p, szOld); pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } return p2; } return NULL; } -static void ma_dr_flac__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) { if (p == NULL || pAllocationCallbacks == NULL) { return; @@ -86728,18 +56615,18 @@ static void ma_dr_flac__free_from_callbacks(void* p, const ma_allocation_callbac pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) +static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize, drflac_allocation_callbacks* pAllocationCallbacks) { - ma_uint64 runningFilePos = 42; - ma_uint64 seektablePos = 0; - ma_uint32 seektableSize = 0; + drflac_uint64 runningFilePos = 42; + drflac_uint64 seektablePos = 0; + drflac_uint32 seektableSize = 0; for (;;) { - ma_dr_flac_metadata metadata; - ma_uint8 isLastBlock = 0; - ma_uint8 blockType = 0; - ma_uint32 blockSize; - if (ma_dr_flac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == MA_FALSE) { - return MA_FALSE; + drflac_metadata metadata; + drflac_uint8 isLastBlock = 0; + drflac_uint8 blockType; + drflac_uint32 blockSize; + if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) { + return DRFLAC_FALSE; } runningFilePos += 4; metadata.type = blockType; @@ -86747,285 +56634,249 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea metadata.rawDataSize = 0; switch (blockType) { - case MA_DR_FLAC_METADATA_BLOCK_TYPE_APPLICATION: + case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION: { if (blockSize < 4) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onMeta) { - void* pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - metadata.data.application.id = ma_dr_flac__be2host_32(*(ma_uint32*)pRawData); - metadata.data.application.pData = (const void*)((ma_uint8*)pRawData + sizeof(ma_uint32)); - metadata.data.application.dataSize = blockSize - sizeof(ma_uint32); + metadata.data.application.id = drflac__be2host_32(*(drflac_uint32*)pRawData); + metadata.data.application.pData = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32)); + metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32); onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; - case MA_DR_FLAC_METADATA_BLOCK_TYPE_SEEKTABLE: + case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE: { seektablePos = runningFilePos; seektableSize = blockSize; if (onMeta) { - ma_uint32 seekpointCount; - ma_uint32 iSeekpoint; + drflac_uint32 iSeekpoint; void* pRawData; - seekpointCount = blockSize/MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES; - pRawData = ma_dr_flac__malloc_from_callbacks(seekpointCount * sizeof(ma_dr_flac_seekpoint), pAllocationCallbacks); + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } - for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) { - ma_dr_flac_seekpoint* pSeekpoint = (ma_dr_flac_seekpoint*)pRawData + iSeekpoint; - if (onRead(pUserData, pSeekpoint, MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) != MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - pSeekpoint->firstPCMFrame = ma_dr_flac__be2host_64(pSeekpoint->firstPCMFrame); - pSeekpoint->flacFrameOffset = ma_dr_flac__be2host_64(pSeekpoint->flacFrameOffset); - pSeekpoint->pcmFrameCount = ma_dr_flac__be2host_16(pSeekpoint->pcmFrameCount); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - metadata.data.seektable.seekpointCount = seekpointCount; - metadata.data.seektable.pSeekpoints = (const ma_dr_flac_seekpoint*)pRawData; + metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint); + metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; + for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { + drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; + pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame); + pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset); + pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount); + } onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; - case MA_DR_FLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: + case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: { if (blockSize < 8) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onMeta) { void* pRawData; const char* pRunningData; const char* pRunningDataEnd; - ma_uint32 i; - pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + drflac_uint32 i; + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.vorbis_comment.vendorLength = ma_dr_flac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if ((pRunningDataEnd - pRunningData) - 4 < (ma_int64)metadata.data.vorbis_comment.vendorLength) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = ma_dr_flac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if ((pRunningDataEnd - pRunningData) / sizeof(ma_uint32) < metadata.data.vorbis_comment.commentCount) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.data.vorbis_comment.pComments = pRunningData; for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { - ma_uint32 commentLength; + drflac_uint32 commentLength; if (pRunningDataEnd - pRunningData < 4) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } - commentLength = ma_dr_flac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if (pRunningDataEnd - pRunningData < (ma_int64)commentLength) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } pRunningData += commentLength; } onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; - case MA_DR_FLAC_METADATA_BLOCK_TYPE_CUESHEET: + case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: { if (blockSize < 396) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onMeta) { void* pRawData; const char* pRunningData; const char* pRunningDataEnd; - size_t bufferSize; - ma_uint8 iTrack; - ma_uint8 iIndex; - void* pTrackData; - pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + drflac_uint8 iTrack; + drflac_uint8 iIndex; + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - MA_DR_FLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; - metadata.data.cuesheet.leadInSampleCount = ma_dr_flac__be2host_64(*(const ma_uint64*)pRunningData); pRunningData += 8; + DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; + metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259; metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; - metadata.data.cuesheet.pTrackData = NULL; - { - const char* pRunningDataSaved = pRunningData; - bufferSize = metadata.data.cuesheet.trackCount * MA_DR_FLAC_CUESHEET_TRACK_SIZE_IN_BYTES; - for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { - ma_uint8 indexCount; - ma_uint32 indexPointSize; - if (pRunningDataEnd - pRunningData < MA_DR_FLAC_CUESHEET_TRACK_SIZE_IN_BYTES) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - pRunningData += 35; - indexCount = pRunningData[0]; - pRunningData += 1; - bufferSize += indexCount * sizeof(ma_dr_flac_cuesheet_track_index); - indexPointSize = indexCount * MA_DR_FLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; - if (pRunningDataEnd - pRunningData < (ma_int64)indexPointSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - pRunningData += indexPointSize; + metadata.data.cuesheet.pTrackData = pRunningData; + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + drflac_uint32 indexPointSize; + if (pRunningDataEnd - pRunningData < 36) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + pRunningData += 35; + indexCount = pRunningData[0]; pRunningData += 1; + indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index); + if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + for (iIndex = 0; iIndex < indexCount; ++iIndex) { + drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData; + pRunningData += sizeof(drflac_cuesheet_track_index); + pTrack->offset = drflac__be2host_64(pTrack->offset); } - pRunningData = pRunningDataSaved; } - { - char* pRunningTrackData; - pTrackData = ma_dr_flac__malloc_from_callbacks(bufferSize, pAllocationCallbacks); - if (pTrackData == NULL) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - pRunningTrackData = (char*)pTrackData; - for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { - ma_uint8 indexCount; - MA_DR_FLAC_COPY_MEMORY(pRunningTrackData, pRunningData, MA_DR_FLAC_CUESHEET_TRACK_SIZE_IN_BYTES); - pRunningData += MA_DR_FLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; - pRunningTrackData += MA_DR_FLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; - indexCount = pRunningData[0]; - pRunningData += 1; - pRunningTrackData += 1; - for (iIndex = 0; iIndex < indexCount; ++iIndex) { - ma_dr_flac_cuesheet_track_index* pTrackIndex = (ma_dr_flac_cuesheet_track_index*)pRunningTrackData; - MA_DR_FLAC_COPY_MEMORY(pRunningTrackData, pRunningData, MA_DR_FLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES); - pRunningData += MA_DR_FLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; - pRunningTrackData += sizeof(ma_dr_flac_cuesheet_track_index); - pTrackIndex->offset = ma_dr_flac__be2host_64(pTrackIndex->offset); - } - } - metadata.data.cuesheet.pTrackData = pTrackData; - } - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - pRawData = NULL; onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pTrackData, pAllocationCallbacks); - pTrackData = NULL; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; - case MA_DR_FLAC_METADATA_BLOCK_TYPE_PICTURE: + case DRFLAC_METADATA_BLOCK_TYPE_PICTURE: { if (blockSize < 32) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onMeta) { void* pRawData; const char* pRunningData; const char* pRunningDataEnd; - pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.picture.type = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if ((pRunningDataEnd - pRunningData) - 24 < (ma_int64)metadata.data.picture.mimeLength) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if ((pRunningDataEnd - pRunningData) - 20 < (ma_int64)metadata.data.picture.descriptionLength) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; + metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } - metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; - metadata.data.picture.width = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.height = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.pPictureData = (const ma_uint8*)pRunningData; - if (pRunningDataEnd - pRunningData < (ma_int64)metadata.data.picture.pictureDataSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; + metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; + if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; - case MA_DR_FLAC_METADATA_BLOCK_TYPE_PADDING: + case DRFLAC_METADATA_BLOCK_TYPE_PADDING: { if (onMeta) { metadata.data.padding.unused = 0; - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { - isLastBlock = MA_TRUE; + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; } else { onMeta(pUserDataMD, &metadata); } } } break; - case MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID: + case DRFLAC_METADATA_BLOCK_TYPE_INVALID: { if (onMeta) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { - isLastBlock = MA_TRUE; + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; } } } break; default: { if (onMeta) { - void* pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; } if (onMeta == NULL && blockSize > 0) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { - isLastBlock = MA_TRUE; + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; } } runningFilePos += blockSize; @@ -87033,45 +56884,45 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea break; } } - *pSeektablePos = seektablePos; - *pSeekpointCount = seektableSize / MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES; - *pFirstFramePos = runningFilePos; - return MA_TRUE; + *pSeektablePos = seektablePos; + *pSeektableSize = seektableSize; + *pFirstFramePos = runningFilePos; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac__init_private__native(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_bool32 relaxed) +static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) { - ma_uint8 isLastBlock; - ma_uint8 blockType; - ma_uint32 blockSize; + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; (void)onSeek; - pInit->container = ma_dr_flac_container_native; - if (!ma_dr_flac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { - return MA_FALSE; + pInit->container = drflac_container_native; + if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { + return DRFLAC_FALSE; } - if (blockType != MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { if (!relaxed) { - return MA_FALSE; + return DRFLAC_FALSE; } else { - pInit->hasStreamInfoBlock = MA_FALSE; - pInit->hasMetadataBlocks = MA_FALSE; - if (!ma_dr_flac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { - return MA_FALSE; + pInit->hasStreamInfoBlock = DRFLAC_FALSE; + pInit->hasMetadataBlocks = DRFLAC_FALSE; + if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { + return DRFLAC_FALSE; } if (pInit->firstFrameHeader.bitsPerSample == 0) { - return MA_FALSE; + return DRFLAC_FALSE; } pInit->sampleRate = pInit->firstFrameHeader.sampleRate; - pInit->channels = ma_dr_flac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); + pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; pInit->maxBlockSizeInPCMFrames = 65535; - return MA_TRUE; + return DRFLAC_TRUE; } } else { - ma_dr_flac_streaminfo streaminfo; - if (!ma_dr_flac__read_streaminfo(onRead, pUserData, &streaminfo)) { - return MA_FALSE; + drflac_streaminfo streaminfo; + if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + return DRFLAC_FALSE; } - pInit->hasStreamInfoBlock = MA_TRUE; + pInit->hasStreamInfoBlock = DRFLAC_TRUE; pInit->sampleRate = streaminfo.sampleRate; pInit->channels = streaminfo.channels; pInit->bitsPerSample = streaminfo.bitsPerSample; @@ -87079,26 +56930,26 @@ static ma_bool32 ma_dr_flac__init_private__native(ma_dr_flac_init_info* pInit, m pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; pInit->hasMetadataBlocks = !isLastBlock; if (onMeta) { - ma_dr_flac_metadata metadata; - metadata.type = MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO; + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; metadata.pRawData = NULL; metadata.rawDataSize = 0; metadata.data.streaminfo = streaminfo; onMeta(pUserDataMD, &metadata); } - return MA_TRUE; + return DRFLAC_TRUE; } } -#ifndef MA_DR_FLAC_NO_OGG -#define MA_DR_FLAC_OGG_MAX_PAGE_SIZE 65307 -#define MA_DR_FLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 +#ifndef DR_FLAC_NO_OGG +#define DRFLAC_OGG_MAX_PAGE_SIZE 65307 +#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 typedef enum { - ma_dr_flac_ogg_recover_on_crc_mismatch, - ma_dr_flac_ogg_fail_on_crc_mismatch -} ma_dr_flac_ogg_crc_mismatch_recovery; -#ifndef MA_DR_FLAC_NO_CRC -static ma_uint32 ma_dr_flac__crc32_table[] = { + drflac_ogg_recover_on_crc_mismatch, + drflac_ogg_fail_on_crc_mismatch +} drflac_ogg_crc_mismatch_recovery; +#ifndef DR_FLAC_NO_CRC +static drflac_uint32 drflac__crc32_table[] = { 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L, @@ -87165,63 +57016,63 @@ static ma_uint32 ma_dr_flac__crc32_table[] = { 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L }; #endif -static MA_INLINE ma_uint32 ma_dr_flac_crc32_byte(ma_uint32 crc32, ma_uint8 data) +static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data) { -#ifndef MA_DR_FLAC_NO_CRC - return (crc32 << 8) ^ ma_dr_flac__crc32_table[(ma_uint8)((crc32 >> 24) & 0xFF) ^ data]; +#ifndef DR_FLAC_NO_CRC + return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data]; #else (void)data; return crc32; #endif } #if 0 -static MA_INLINE ma_uint32 ma_dr_flac_crc32_uint32(ma_uint32 crc32, ma_uint32 data) +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data) { - crc32 = ma_dr_flac_crc32_byte(crc32, (ma_uint8)((data >> 24) & 0xFF)); - crc32 = ma_dr_flac_crc32_byte(crc32, (ma_uint8)((data >> 16) & 0xFF)); - crc32 = ma_dr_flac_crc32_byte(crc32, (ma_uint8)((data >> 8) & 0xFF)); - crc32 = ma_dr_flac_crc32_byte(crc32, (ma_uint8)((data >> 0) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 8) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 0) & 0xFF)); return crc32; } -static MA_INLINE ma_uint32 ma_dr_flac_crc32_uint64(ma_uint32 crc32, ma_uint64 data) +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data) { - crc32 = ma_dr_flac_crc32_uint32(crc32, (ma_uint32)((data >> 32) & 0xFFFFFFFF)); - crc32 = ma_dr_flac_crc32_uint32(crc32, (ma_uint32)((data >> 0) & 0xFFFFFFFF)); + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF)); + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 0) & 0xFFFFFFFF)); return crc32; } #endif -static MA_INLINE ma_uint32 ma_dr_flac_crc32_buffer(ma_uint32 crc32, ma_uint8* pData, ma_uint32 dataSize) +static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize) { - ma_uint32 i; + drflac_uint32 i; for (i = 0; i < dataSize; ++i) { - crc32 = ma_dr_flac_crc32_byte(crc32, pData[i]); + crc32 = drflac_crc32_byte(crc32, pData[i]); } return crc32; } -static MA_INLINE ma_bool32 ma_dr_flac_ogg__is_capture_pattern(ma_uint8 pattern[4]) +static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4]) { return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S'; } -static MA_INLINE ma_uint32 ma_dr_flac_ogg__get_page_header_size(ma_dr_flac_ogg_page_header* pHeader) +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader) { return 27 + pHeader->segmentCount; } -static MA_INLINE ma_uint32 ma_dr_flac_ogg__get_page_body_size(ma_dr_flac_ogg_page_header* pHeader) +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) { - ma_uint32 pageBodySize = 0; + drflac_uint32 pageBodySize = 0; int i; for (i = 0; i < pHeader->segmentCount; ++i) { pageBodySize += pHeader->segmentTable[i]; } return pageBodySize; } -static ma_result ma_dr_flac_ogg__read_page_header_after_capture_pattern(ma_dr_flac_read_proc onRead, void* pUserData, ma_dr_flac_ogg_page_header* pHeader, ma_uint32* pBytesRead, ma_uint32* pCRC32) +static drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) { - ma_uint8 data[23]; - ma_uint32 i; - MA_DR_FLAC_ASSERT(*pCRC32 == MA_DR_FLAC_OGG_CAPTURE_PATTERN_CRC32); + drflac_uint8 data[23]; + drflac_uint32 i; + DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32); if (onRead(pUserData, data, 23) != 23) { - return MA_AT_END; + return DRFLAC_AT_END; } *pBytesRead += 23; pHeader->capturePattern[0] = 'O'; @@ -87230,44 +57081,44 @@ static ma_result ma_dr_flac_ogg__read_page_header_after_capture_pattern(ma_dr_fl pHeader->capturePattern[3] = 'S'; pHeader->structureVersion = data[0]; pHeader->headerType = data[1]; - MA_DR_FLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8); - MA_DR_FLAC_COPY_MEMORY(&pHeader->serialNumber, &data[10], 4); - MA_DR_FLAC_COPY_MEMORY(&pHeader->sequenceNumber, &data[14], 4); - MA_DR_FLAC_COPY_MEMORY(&pHeader->checksum, &data[18], 4); + DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8); + DRFLAC_COPY_MEMORY(&pHeader->serialNumber, &data[10], 4); + DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber, &data[14], 4); + DRFLAC_COPY_MEMORY(&pHeader->checksum, &data[18], 4); pHeader->segmentCount = data[22]; data[18] = 0; data[19] = 0; data[20] = 0; data[21] = 0; for (i = 0; i < 23; ++i) { - *pCRC32 = ma_dr_flac_crc32_byte(*pCRC32, data[i]); + *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]); } if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { - return MA_AT_END; + return DRFLAC_AT_END; } *pBytesRead += pHeader->segmentCount; for (i = 0; i < pHeader->segmentCount; ++i) { - *pCRC32 = ma_dr_flac_crc32_byte(*pCRC32, pHeader->segmentTable[i]); + *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]); } - return MA_SUCCESS; + return DRFLAC_SUCCESS; } -static ma_result ma_dr_flac_ogg__read_page_header(ma_dr_flac_read_proc onRead, void* pUserData, ma_dr_flac_ogg_page_header* pHeader, ma_uint32* pBytesRead, ma_uint32* pCRC32) +static drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) { - ma_uint8 id[4]; + drflac_uint8 id[4]; *pBytesRead = 0; if (onRead(pUserData, id, 4) != 4) { - return MA_AT_END; + return DRFLAC_AT_END; } *pBytesRead += 4; for (;;) { - if (ma_dr_flac_ogg__is_capture_pattern(id)) { - ma_result result; - *pCRC32 = MA_DR_FLAC_OGG_CAPTURE_PATTERN_CRC32; - result = ma_dr_flac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); - if (result == MA_SUCCESS) { - return MA_SUCCESS; + if (drflac_ogg__is_capture_pattern(id)) { + drflac_result result; + *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); + if (result == DRFLAC_SUCCESS) { + return DRFLAC_SUCCESS; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { continue; } else { return result; @@ -87278,7 +57129,7 @@ static ma_result ma_dr_flac_ogg__read_page_header(ma_dr_flac_read_proc onRead, v id[1] = id[2]; id[2] = id[3]; if (onRead(pUserData, &id[3], 1) != 1) { - return MA_AT_END; + return DRFLAC_AT_END; } *pBytesRead += 1; } @@ -87286,91 +57137,91 @@ static ma_result ma_dr_flac_ogg__read_page_header(ma_dr_flac_read_proc onRead, v } typedef struct { - ma_dr_flac_read_proc onRead; - ma_dr_flac_seek_proc onSeek; + drflac_read_proc onRead; + drflac_seek_proc onSeek; void* pUserData; - ma_uint64 currentBytePos; - ma_uint64 firstBytePos; - ma_uint32 serialNumber; - ma_dr_flac_ogg_page_header bosPageHeader; - ma_dr_flac_ogg_page_header currentPageHeader; - ma_uint32 bytesRemainingInPage; - ma_uint32 pageDataSize; - ma_uint8 pageData[MA_DR_FLAC_OGG_MAX_PAGE_SIZE]; -} ma_dr_flac_oggbs; -static size_t ma_dr_flac_oggbs__read_physical(ma_dr_flac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) + drflac_uint64 currentBytePos; + drflac_uint64 firstBytePos; + drflac_uint32 serialNumber; + drflac_ogg_page_header bosPageHeader; + drflac_ogg_page_header currentPageHeader; + drflac_uint32 bytesRemainingInPage; + drflac_uint32 pageDataSize; + drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE]; +} drflac_oggbs; +static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) { size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead); oggbs->currentBytePos += bytesActuallyRead; return bytesActuallyRead; } -static ma_bool32 ma_dr_flac_oggbs__seek_physical(ma_dr_flac_oggbs* oggbs, ma_uint64 offset, ma_dr_flac_seek_origin origin) +static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin) { - if (origin == ma_dr_flac_seek_origin_start) { + if (origin == drflac_seek_origin_start) { if (offset <= 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_start)) { - return MA_FALSE; + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } oggbs->currentBytePos = offset; - return MA_TRUE; + return DRFLAC_TRUE; } else { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { - return MA_FALSE; + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } oggbs->currentBytePos = offset; - return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, ma_dr_flac_seek_origin_current); + return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current); } } else { while (offset > 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } oggbs->currentBytePos += 0x7FFFFFFF; offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } oggbs->currentBytePos += offset; - return MA_TRUE; + return DRFLAC_TRUE; } } -static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr_flac_ogg_crc_mismatch_recovery recoveryMethod) +static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod) { - ma_dr_flac_ogg_page_header header; + drflac_ogg_page_header header; for (;;) { - ma_uint32 crc32 = 0; - ma_uint32 bytesRead; - ma_uint32 pageBodySize; -#ifndef MA_DR_FLAC_NO_CRC - ma_uint32 actualCRC32; + drflac_uint32 crc32 = 0; + drflac_uint32 bytesRead; + drflac_uint32 pageBodySize; +#ifndef DR_FLAC_NO_CRC + drflac_uint32 actualCRC32; #endif - if (ma_dr_flac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != MA_SUCCESS) { - return MA_FALSE; + if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; } oggbs->currentBytePos += bytesRead; - pageBodySize = ma_dr_flac_ogg__get_page_body_size(&header); - if (pageBodySize > MA_DR_FLAC_OGG_MAX_PAGE_SIZE) { + pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) { continue; } if (header.serialNumber != oggbs->serialNumber) { - if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } continue; } - if (ma_dr_flac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { - return MA_FALSE; + if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { + return DRFLAC_FALSE; } oggbs->pageDataSize = pageBodySize; -#ifndef MA_DR_FLAC_NO_CRC - actualCRC32 = ma_dr_flac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); +#ifndef DR_FLAC_NO_CRC + actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); if (actualCRC32 != header.checksum) { - if (recoveryMethod == ma_dr_flac_ogg_recover_on_crc_mismatch) { + if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) { continue; } else { - ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch); - return MA_FALSE; + drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch); + return DRFLAC_FALSE; } } #else @@ -87378,17 +57229,17 @@ static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr #endif oggbs->currentPageHeader = header; oggbs->bytesRemainingInPage = pageBodySize; - return MA_TRUE; + return DRFLAC_TRUE; } } #if 0 -static ma_uint8 ma_dr_flac_oggbs__get_current_segment_index(ma_dr_flac_oggbs* oggbs, ma_uint8* pBytesRemainingInSeg) +static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg) { - ma_uint32 bytesConsumedInPage = ma_dr_flac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage; - ma_uint8 iSeg = 0; - ma_uint32 iByte = 0; + drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage; + drflac_uint8 iSeg = 0; + drflac_uint32 iByte = 0; while (iByte < bytesConsumedInPage) { - ma_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; if (iByte + segmentSize > bytesConsumedInPage) { break; } else { @@ -87396,92 +57247,92 @@ static ma_uint8 ma_dr_flac_oggbs__get_current_segment_index(ma_dr_flac_oggbs* og iByte += segmentSize; } } - *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (ma_uint8)(bytesConsumedInPage - iByte); + *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte); return iSeg; } -static ma_bool32 ma_dr_flac_oggbs__seek_to_next_packet(ma_dr_flac_oggbs* oggbs) +static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) { for (;;) { - ma_bool32 atEndOfPage = MA_FALSE; - ma_uint8 bytesRemainingInSeg; - ma_uint8 iFirstSeg = ma_dr_flac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg); - ma_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg; - for (ma_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) { - ma_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + drflac_bool32 atEndOfPage = DRFLAC_FALSE; + drflac_uint8 bytesRemainingInSeg; + drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg); + drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg; + for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; if (segmentSize < 255) { if (iSeg == oggbs->currentPageHeader.segmentCount-1) { - atEndOfPage = MA_TRUE; + atEndOfPage = DRFLAC_TRUE; } break; } bytesToEndOfPacketOrPage += segmentSize; } - ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, ma_dr_flac_seek_origin_current); + drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; if (atEndOfPage) { - if (!ma_dr_flac_oggbs__goto_next_page(oggbs)) { - return MA_FALSE; + if (!drflac_oggbs__goto_next_page(oggbs)) { + return DRFLAC_FALSE; } if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { - return MA_TRUE; + return DRFLAC_TRUE; } } else { - return MA_TRUE; + return DRFLAC_TRUE; } } } -static ma_bool32 ma_dr_flac_oggbs__seek_to_next_frame(ma_dr_flac_oggbs* oggbs) +static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) { - return ma_dr_flac_oggbs__seek_to_next_packet(oggbs); + return drflac_oggbs__seek_to_next_packet(oggbs); } #endif -static size_t ma_dr_flac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) +static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) { - ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pUserData; - ma_uint8* pRunningBufferOut = (ma_uint8*)bufferOut; + drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; + drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut; size_t bytesRead = 0; - MA_DR_FLAC_ASSERT(oggbs != NULL); - MA_DR_FLAC_ASSERT(pRunningBufferOut != NULL); + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(pRunningBufferOut != NULL); while (bytesRead < bytesToRead) { size_t bytesRemainingToRead = bytesToRead - bytesRead; if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) { - MA_DR_FLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead); + DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead); bytesRead += bytesRemainingToRead; - oggbs->bytesRemainingInPage -= (ma_uint32)bytesRemainingToRead; + oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead; break; } if (oggbs->bytesRemainingInPage > 0) { - MA_DR_FLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage); + DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage); bytesRead += oggbs->bytesRemainingInPage; pRunningBufferOut += oggbs->bytesRemainingInPage; oggbs->bytesRemainingInPage = 0; } - MA_DR_FLAC_ASSERT(bytesRemainingToRead > 0); - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { + DRFLAC_ASSERT(bytesRemainingToRead > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { break; } } return bytesRead; } -static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac_seek_origin origin) +static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) { - ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pUserData; + drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; int bytesSeeked = 0; - MA_DR_FLAC_ASSERT(oggbs != NULL); - MA_DR_FLAC_ASSERT(offset >= 0); - if (origin == ma_dr_flac_seek_origin_start) { - if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, ma_dr_flac_seek_origin_start)) { - return MA_FALSE; + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(offset >= 0); + if (origin == drflac_seek_origin_start) { + if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { - return MA_FALSE; + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + return DRFLAC_FALSE; } - return ma_dr_flac__on_seek_ogg(pUserData, offset, ma_dr_flac_seek_origin_current); + return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current); } - MA_DR_FLAC_ASSERT(origin == ma_dr_flac_seek_origin_current); + DRFLAC_ASSERT(origin == drflac_seek_origin_current); while (bytesSeeked < offset) { int bytesRemainingToSeek = offset - bytesSeeked; - MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); + DRFLAC_ASSERT(bytesRemainingToSeek >= 0); if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { bytesSeeked += bytesRemainingToSeek; (void)bytesSeeked; @@ -87492,39 +57343,39 @@ static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac bytesSeeked += (int)oggbs->bytesRemainingInPage; oggbs->bytesRemainingInPage = 0; } - MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { - return MA_FALSE; + DRFLAC_ASSERT(bytesRemainingToSeek > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + return DRFLAC_FALSE; } } - return MA_TRUE; + return DRFLAC_TRUE; } -static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) { - ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; - ma_uint64 originalBytePos; - ma_uint64 runningGranulePosition; - ma_uint64 runningFrameBytePos; - ma_uint64 runningPCMFrameCount; - MA_DR_FLAC_ASSERT(oggbs != NULL); + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + drflac_uint64 originalBytePos; + drflac_uint64 runningGranulePosition; + drflac_uint64 runningFrameBytePos; + drflac_uint64 runningPCMFrameCount; + DRFLAC_ASSERT(oggbs != NULL); originalBytePos = oggbs->currentBytePos; - if (!ma_dr_flac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) { - return MA_FALSE; + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) { + return DRFLAC_FALSE; } oggbs->bytesRemainingInPage = 0; runningGranulePosition = 0; for (;;) { - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { - ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, ma_dr_flac_seek_origin_start); - return MA_FALSE; + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start); + return DRFLAC_FALSE; } - runningFrameBytePos = oggbs->currentBytePos - ma_dr_flac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; + runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) { break; } if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { if (oggbs->currentPageHeader.segmentTable[0] >= 2) { - ma_uint8 firstBytesInPage[2]; + drflac_uint8 firstBytesInPage[2]; firstBytesInPage[0] = oggbs->pageData[0]; firstBytesInPage[1] = oggbs->pageData[1]; if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { @@ -87534,120 +57385,120 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 } } } - if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, ma_dr_flac_seek_origin_start)) { - return MA_FALSE; + if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { - return MA_FALSE; + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + return DRFLAC_FALSE; } runningPCMFrameCount = runningGranulePosition; for (;;) { - ma_uint64 firstPCMFrameInFLACFrame = 0; - ma_uint64 lastPCMFrameInFLACFrame = 0; - ma_uint64 pcmFrameCountInThisFrame; - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - return MA_FALSE; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + drflac_uint64 pcmFrameCountInThisFrame; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } - ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) { - ma_result result = ma_dr_flac__decode_flac_frame(pFlac); - if (result == MA_SUCCESS) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { pFlac->currentPCMFrame = pcmFrameIndex; pFlac->currentFLACFrame.pcmFramesRemaining = 0; - return MA_TRUE; + return DRFLAC_TRUE; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) { - ma_result result = ma_dr_flac__decode_flac_frame(pFlac); - if (result == MA_SUCCESS) { - ma_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); if (pcmFramesToDecode == 0) { - return MA_TRUE; + return DRFLAC_TRUE; } pFlac->currentPCMFrame = runningPCMFrameCount; - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { continue; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } } else { - ma_result result = ma_dr_flac__seek_to_next_flac_frame(pFlac); - if (result == MA_SUCCESS) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { runningPCMFrameCount += pcmFrameCountInThisFrame; } else { - if (result == MA_CRC_MISMATCH) { + if (result == DRFLAC_CRC_MISMATCH) { continue; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } } } } -static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_bool32 relaxed) +static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) { - ma_dr_flac_ogg_page_header header; - ma_uint32 crc32 = MA_DR_FLAC_OGG_CAPTURE_PATTERN_CRC32; - ma_uint32 bytesRead = 0; + drflac_ogg_page_header header; + drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + drflac_uint32 bytesRead = 0; (void)relaxed; - pInit->container = ma_dr_flac_container_ogg; + pInit->container = drflac_container_ogg; pInit->oggFirstBytePos = 0; - if (ma_dr_flac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != MA_SUCCESS) { - return MA_FALSE; + if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; } pInit->runningFilePos += bytesRead; for (;;) { int pageBodySize; if ((header.headerType & 0x02) == 0) { - return MA_FALSE; + return DRFLAC_FALSE; } - pageBodySize = ma_dr_flac_ogg__get_page_body_size(&header); + pageBodySize = drflac_ogg__get_page_body_size(&header); if (pageBodySize == 51) { - ma_uint32 bytesRemainingInPage = pageBodySize; - ma_uint8 packetType; + drflac_uint32 bytesRemainingInPage = pageBodySize; + drflac_uint8 packetType; if (onRead(pUserData, &packetType, 1) != 1) { - return MA_FALSE; + return DRFLAC_FALSE; } bytesRemainingInPage -= 1; if (packetType == 0x7F) { - ma_uint8 sig[4]; + drflac_uint8 sig[4]; if (onRead(pUserData, sig, 4) != 4) { - return MA_FALSE; + return DRFLAC_FALSE; } bytesRemainingInPage -= 4; if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { - ma_uint8 mappingVersion[2]; + drflac_uint8 mappingVersion[2]; if (onRead(pUserData, mappingVersion, 2) != 2) { - return MA_FALSE; + return DRFLAC_FALSE; } if (mappingVersion[0] != 1) { - return MA_FALSE; + return DRFLAC_FALSE; } - if (!onSeek(pUserData, 2, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, 2, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } if (onRead(pUserData, sig, 4) != 4) { - return MA_FALSE; + return DRFLAC_FALSE; } if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') { - ma_dr_flac_streaminfo streaminfo; - ma_uint8 isLastBlock; - ma_uint8 blockType; - ma_uint32 blockSize; - if (!ma_dr_flac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { - return MA_FALSE; + drflac_streaminfo streaminfo; + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; + if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { + return DRFLAC_FALSE; } - if (blockType != MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { - return MA_FALSE; + if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + return DRFLAC_FALSE; } - if (ma_dr_flac__read_streaminfo(onRead, pUserData, &streaminfo)) { - pInit->hasStreamInfoBlock = MA_TRUE; + if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + pInit->hasStreamInfoBlock = DRFLAC_TRUE; pInit->sampleRate = streaminfo.sampleRate; pInit->channels = streaminfo.channels; pInit->bitsPerSample = streaminfo.bitsPerSample; @@ -87655,8 +57506,8 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; pInit->hasMetadataBlocks = !isLastBlock; if (onMeta) { - ma_dr_flac_metadata metadata; - metadata.type = MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO; + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; metadata.pRawData = NULL; metadata.rawDataSize = 0; metadata.data.streaminfo = streaminfo; @@ -87668,44 +57519,44 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d pInit->oggBosHeader = header; break; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } else { - return MA_FALSE; + return DRFLAC_FALSE; } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } } } else { - if (!onSeek(pUserData, pageBodySize, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } } pInit->runningFilePos += pageBodySize; - if (ma_dr_flac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != MA_SUCCESS) { - return MA_FALSE; + if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; } pInit->runningFilePos += bytesRead; } - pInit->hasMetadataBlocks = MA_TRUE; - return MA_TRUE; + pInit->hasMetadataBlocks = DRFLAC_TRUE; + return DRFLAC_TRUE; } #endif -static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) +static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD) { - ma_bool32 relaxed; - ma_uint8 id[4]; + drflac_bool32 relaxed; + drflac_uint8 id[4]; if (pInit == NULL || onRead == NULL || onSeek == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } - MA_DR_FLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); + DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); pInit->onRead = onRead; pInit->onSeek = onSeek; pInit->onMeta = onMeta; @@ -87715,29 +57566,29 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla pInit->bs.onRead = onRead; pInit->bs.onSeek = onSeek; pInit->bs.pUserData = pUserData; - ma_dr_flac__reset_cache(&pInit->bs); - relaxed = container != ma_dr_flac_container_unknown; + drflac__reset_cache(&pInit->bs); + relaxed = container != drflac_container_unknown; for (;;) { if (onRead(pUserData, id, 4) != 4) { - return MA_FALSE; + return DRFLAC_FALSE; } pInit->runningFilePos += 4; if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { - ma_uint8 header[6]; - ma_uint8 flags; - ma_uint32 headerSize; + drflac_uint8 header[6]; + drflac_uint8 flags; + drflac_uint32 headerSize; if (onRead(pUserData, header, 6) != 6) { - return MA_FALSE; + return DRFLAC_FALSE; } pInit->runningFilePos += 6; flags = header[1]; - MA_DR_FLAC_COPY_MEMORY(&headerSize, header+2, 4); - headerSize = ma_dr_flac__unsynchsafe_32(ma_dr_flac__be2host_32(headerSize)); + DRFLAC_COPY_MEMORY(&headerSize, header+2, 4); + headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize)); if (flags & 0x10) { headerSize += 10; } - if (!onSeek(pUserData, headerSize, ma_dr_flac_seek_origin_current)) { - return MA_FALSE; + if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; } pInit->runningFilePos += headerSize; } else { @@ -87745,56 +57596,56 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla } } if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') { - return ma_dr_flac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); } -#ifndef MA_DR_FLAC_NO_OGG +#ifndef DR_FLAC_NO_OGG if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') { - return ma_dr_flac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); } #endif if (relaxed) { - if (container == ma_dr_flac_container_native) { - return ma_dr_flac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + if (container == drflac_container_native) { + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); } -#ifndef MA_DR_FLAC_NO_OGG - if (container == ma_dr_flac_container_ogg) { - return ma_dr_flac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); +#ifndef DR_FLAC_NO_OGG + if (container == drflac_container_ogg) { + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); } #endif } - return MA_FALSE; + return DRFLAC_FALSE; } -static void ma_dr_flac__init_from_info(ma_dr_flac* pFlac, const ma_dr_flac_init_info* pInit) +static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit) { - MA_DR_FLAC_ASSERT(pFlac != NULL); - MA_DR_FLAC_ASSERT(pInit != NULL); - MA_DR_FLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac)); + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pInit != NULL); + DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac)); pFlac->bs = pInit->bs; pFlac->onMeta = pInit->onMeta; pFlac->pUserDataMD = pInit->pUserDataMD; pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames; pFlac->sampleRate = pInit->sampleRate; - pFlac->channels = (ma_uint8)pInit->channels; - pFlac->bitsPerSample = (ma_uint8)pInit->bitsPerSample; + pFlac->channels = (drflac_uint8)pInit->channels; + pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample; pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; pFlac->container = pInit->container; } -static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) +static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac_init_info init; - ma_uint32 allocationSize; - ma_uint32 wholeSIMDVectorCountPerChannel; - ma_uint32 decodedSamplesAllocationSize; -#ifndef MA_DR_FLAC_NO_OGG - ma_dr_flac_oggbs* pOggbs = NULL; + drflac_init_info init; + drflac_uint32 allocationSize; + drflac_uint32 wholeSIMDVectorCountPerChannel; + drflac_uint32 decodedSamplesAllocationSize; +#ifndef DR_FLAC_NO_OGG + drflac_oggbs oggbs; #endif - ma_uint64 firstFramePos; - ma_uint64 seektablePos; - ma_uint32 seekpointCount; - ma_allocation_callbacks allocationCallbacks; - ma_dr_flac* pFlac; - ma_dr_flac__init_cpu_caps(); - if (!ma_dr_flac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { + drflac_uint64 firstFramePos; + drflac_uint64 seektablePos; + drflac_uint32 seektableSize; + drflac_allocation_callbacks allocationCallbacks; + drflac* pFlac; + drflac__init_cpu_caps(); + if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { return NULL; } if (pAllocationCallbacks != NULL) { @@ -87804,84 +57655,74 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on } } else { allocationCallbacks.pUserData = NULL; - allocationCallbacks.onMalloc = ma_dr_flac__malloc_default; - allocationCallbacks.onRealloc = ma_dr_flac__realloc_default; - allocationCallbacks.onFree = ma_dr_flac__free_default; + allocationCallbacks.onMalloc = drflac__malloc_default; + allocationCallbacks.onRealloc = drflac__realloc_default; + allocationCallbacks.onFree = drflac__free_default; } - allocationSize = sizeof(ma_dr_flac); - if ((init.maxBlockSizeInPCMFrames % (MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE / sizeof(ma_int32))) == 0) { - wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE / sizeof(ma_int32))); + allocationSize = sizeof(drflac); + if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) { + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))); } else { - wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE / sizeof(ma_int32))) + 1; + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; } - decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE * init.channels; + decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; allocationSize += decodedSamplesAllocationSize; - allocationSize += MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE; -#ifndef MA_DR_FLAC_NO_OGG - if (init.container == ma_dr_flac_container_ogg) { - allocationSize += sizeof(ma_dr_flac_oggbs); - pOggbs = (ma_dr_flac_oggbs*)ma_dr_flac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks); - if (pOggbs == NULL) { - return NULL; - } - MA_DR_FLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); - pOggbs->onRead = onRead; - pOggbs->onSeek = onSeek; - pOggbs->pUserData = pUserData; - pOggbs->currentBytePos = init.oggFirstBytePos; - pOggbs->firstBytePos = init.oggFirstBytePos; - pOggbs->serialNumber = init.oggSerial; - pOggbs->bosPageHeader = init.oggBosHeader; - pOggbs->bytesRemainingInPage = 0; + allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + allocationSize += sizeof(drflac_oggbs); + } + DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs)); + if (init.container == drflac_container_ogg) { + oggbs.onRead = onRead; + oggbs.onSeek = onSeek; + oggbs.pUserData = pUserData; + oggbs.currentBytePos = init.oggFirstBytePos; + oggbs.firstBytePos = init.oggFirstBytePos; + oggbs.serialNumber = init.oggSerial; + oggbs.bosPageHeader = init.oggBosHeader; + oggbs.bytesRemainingInPage = 0; } #endif - firstFramePos = 42; - seektablePos = 0; - seekpointCount = 0; + firstFramePos = 42; + seektablePos = 0; + seektableSize = 0; if (init.hasMetadataBlocks) { - ma_dr_flac_read_proc onReadOverride = onRead; - ma_dr_flac_seek_proc onSeekOverride = onSeek; + drflac_read_proc onReadOverride = onRead; + drflac_seek_proc onSeekOverride = onSeek; void* pUserDataOverride = pUserData; -#ifndef MA_DR_FLAC_NO_OGG - if (init.container == ma_dr_flac_container_ogg) { - onReadOverride = ma_dr_flac__on_read_ogg; - onSeekOverride = ma_dr_flac__on_seek_ogg; - pUserDataOverride = (void*)pOggbs; +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + onReadOverride = drflac__on_read_ogg; + onSeekOverride = drflac__on_seek_ogg; + pUserDataOverride = (void*)&oggbs; } #endif - if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { - #ifndef MA_DR_FLAC_NO_OGG - ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); - #endif + if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) { return NULL; } - allocationSize += seekpointCount * sizeof(ma_dr_flac_seekpoint); + allocationSize += seektableSize; } - pFlac = (ma_dr_flac*)ma_dr_flac__malloc_from_callbacks(allocationSize, &allocationCallbacks); + pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks); if (pFlac == NULL) { - #ifndef MA_DR_FLAC_NO_OGG - ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); - #endif return NULL; } - ma_dr_flac__init_from_info(pFlac, &init); + drflac__init_from_info(pFlac, &init); pFlac->allocationCallbacks = allocationCallbacks; - pFlac->pDecodedSamples = (ma_int32*)ma_dr_flac_align((size_t)pFlac->pExtraData, MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE); -#ifndef MA_DR_FLAC_NO_OGG - if (init.container == ma_dr_flac_container_ogg) { - ma_dr_flac_oggbs* pInternalOggbs = (ma_dr_flac_oggbs*)((ma_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(ma_dr_flac_seekpoint))); - MA_DR_FLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs)); - ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); - pOggbs = NULL; - pFlac->bs.onRead = ma_dr_flac__on_read_ogg; - pFlac->bs.onSeek = ma_dr_flac__on_seek_ogg; + pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE); +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize); + *pInternalOggbs = oggbs; + pFlac->bs.onRead = drflac__on_read_ogg; + pFlac->bs.onSeek = drflac__on_seek_ogg; pFlac->bs.pUserData = (void*)pInternalOggbs; pFlac->_oggbs = (void*)pInternalOggbs; } #endif pFlac->firstFLACFramePosInBytes = firstFramePos; -#ifndef MA_DR_FLAC_NO_OGG - if (init.container == ma_dr_flac_container_ogg) +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { pFlac->pSeekpoints = NULL; pFlac->seekpointCount = 0; @@ -87890,25 +57731,24 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on #endif { if (seektablePos != 0) { - pFlac->seekpointCount = seekpointCount; - pFlac->pSeekpoints = (ma_dr_flac_seekpoint*)((ma_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); - MA_DR_FLAC_ASSERT(pFlac->bs.onSeek != NULL); - MA_DR_FLAC_ASSERT(pFlac->bs.onRead != NULL); - if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, ma_dr_flac_seek_origin_start)) { - ma_uint32 iSeekpoint; - for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { - if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) == MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) { - pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = ma_dr_flac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame); - pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = ma_dr_flac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset); - pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = ma_dr_flac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount); - } else { - pFlac->pSeekpoints = NULL; - pFlac->seekpointCount = 0; - break; + pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints); + pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); + DRFLAC_ASSERT(pFlac->bs.onSeek != NULL); + DRFLAC_ASSERT(pFlac->bs.onRead != NULL); + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) { + if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) { + drflac_uint32 iSeekpoint; + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame); + pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset); + pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount); } + } else { + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; } - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, ma_dr_flac_seek_origin_start)) { - ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } } else { @@ -87920,18 +57760,18 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on if (!init.hasStreamInfoBlock) { pFlac->currentFLACFrame.header = init.firstFrameHeader; for (;;) { - ma_result result = ma_dr_flac__decode_flac_frame(pFlac); - if (result == MA_SUCCESS) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { break; } else { - if (result == MA_CRC_MISMATCH) { - if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { - ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); + if (result == DRFLAC_CRC_MISMATCH) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } continue; } else { - ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); + drflac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } } @@ -87939,73 +57779,573 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on } return pFlac; } -#ifndef MA_DR_FLAC_NO_STDIO +#ifndef DR_FLAC_NO_STDIO #include -#ifndef MA_DR_FLAC_NO_WCHAR #include +#include +static drflac_result drflac_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRFLAC_SUCCESS; + #ifdef EPERM + case EPERM: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRFLAC_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRFLAC_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRFLAC_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRFLAC_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRFLAC_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRFLAC_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRFLAC_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRFLAC_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRFLAC_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRFLAC_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRFLAC_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRFLAC_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRFLAC_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRFLAC_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRFLAC_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRFLAC_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRFLAC_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRFLAC_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRFLAC_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRFLAC_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRFLAC_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRFLAC_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRFLAC_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRFLAC_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRFLAC_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRFLAC_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRFLAC_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRFLAC_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRFLAC_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRFLAC_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRFLAC_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRFLAC_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRFLAC_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRFLAC_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRFLAC_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRFLAC_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRFLAC_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRFLAC_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRFLAC_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRFLAC_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRFLAC_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRFLAC_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRFLAC_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRFLAC_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRFLAC_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRFLAC_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRFLAC_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRFLAC_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRFLAC_ERROR; + #endif + #ifdef EADV + case EADV: return DRFLAC_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRFLAC_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRFLAC_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRFLAC_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRFLAC_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRFLAC_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRFLAC_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRFLAC_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRFLAC_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRFLAC_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRFLAC_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRFLAC_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRFLAC_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRFLAC_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRFLAC_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRFLAC_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRFLAC_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRFLAC_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRFLAC_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRFLAC_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRFLAC_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRFLAC_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRFLAC_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRFLAC_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRFLAC_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRFLAC_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRFLAC_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRFLAC_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRFLAC_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRFLAC_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRFLAC_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRFLAC_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRFLAC_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRFLAC_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRFLAC_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRFLAC_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRFLAC_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRFLAC_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRFLAC_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRFLAC_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRFLAC_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRFLAC_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRFLAC_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRFLAC_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRFLAC_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRFLAC_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRFLAC_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRFLAC_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRFLAC_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRFLAC_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRFLAC_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRFLAC_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRFLAC_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRFLAC_ERROR; + #endif + default: return DRFLAC_ERROR; + } +} +static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err; #endif -static size_t ma_dr_flac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) + if (ppFile != NULL) { + *ppFile = NULL; + } + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } +#if defined(_MSC_VER) && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drflac_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drflac_result result = drflac_result_from_errno(errno); + if (result == DRFLAC_SUCCESS) { + result = DRFLAC_ERROR; + } + return result; + } +#endif + return DRFLAC_SUCCESS; +} +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRFLAC_HAS_WFOPEN + #endif +#endif +static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; + } + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } +#if defined(DRFLAC_HAS_WFOPEN) + { + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drflac_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drflac_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + DRFLAC_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drflac_result_from_errno(errno); + } + pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRFLAC_OUT_OF_MEMORY; + } + pFilePathTemp = pFilePath; + DRFLAC_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + *ppFile = fopen(pFilePathMB, pOpenModeMB); + drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + if (*ppFile == NULL) { + return DRFLAC_ERROR; + } +#endif + return DRFLAC_SUCCESS; +} +static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) { return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData); } -static ma_bool32 ma_dr_flac__on_seek_stdio(void* pUserData, int offset, ma_dr_flac_seek_origin origin) +static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) { - MA_DR_FLAC_ASSERT(offset >= 0); - return fseek((FILE*)pUserData, offset, (origin == ma_dr_flac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + DRFLAC_ASSERT(offset >= 0); + return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } -MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; FILE* pFile; - if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; } return pFlac; } -#ifndef MA_DR_FLAC_NO_WCHAR -MA_API ma_dr_flac* ma_dr_flac_open_file_w(const wchar_t* pFileName, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; FILE* pFile; - if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; } return pFlac; } -#endif -MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata(const char* pFileName, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; FILE* pFile; - if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; } return pFlac; } -#ifndef MA_DR_FLAC_NO_WCHAR -MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; FILE* pFile; - if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88013,62 +58353,61 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName return pFlac; } #endif -#endif -static size_t ma_dr_flac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) +static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) { - ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; size_t bytesRemaining; - MA_DR_FLAC_ASSERT(memoryStream != NULL); - MA_DR_FLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos); + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos); bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } if (bytesToRead > 0) { - MA_DR_FLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); + DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); memoryStream->currentReadPos += bytesToRead; } return bytesToRead; } -static ma_bool32 ma_dr_flac__on_seek_memory(void* pUserData, int offset, ma_dr_flac_seek_origin origin) +static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) { - ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; - MA_DR_FLAC_ASSERT(memoryStream != NULL); - MA_DR_FLAC_ASSERT(offset >= 0); - if (offset > (ma_int64)memoryStream->dataSize) { - return MA_FALSE; + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(offset >= 0); + if (offset > (drflac_int64)memoryStream->dataSize) { + return DRFLAC_FALSE; } - if (origin == ma_dr_flac_seek_origin_current) { + if (origin == drflac_seek_origin_current) { if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { memoryStream->currentReadPos += offset; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } else { - if ((ma_uint32)offset <= memoryStream->dataSize) { + if ((drflac_uint32)offset <= memoryStream->dataSize) { memoryStream->currentReadPos = offset; } else { - return MA_FALSE; + return DRFLAC_FALSE; } } - return MA_TRUE; + return DRFLAC_TRUE; } -MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac__memory_stream memoryStream; - ma_dr_flac* pFlac; - memoryStream.data = (const ma_uint8*)pData; + drflac__memory_stream memoryStream; + drflac* pFlac; + memoryStream.data = (const drflac_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, &memoryStream, pAllocationCallbacks); + pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } pFlac->memoryStream = memoryStream; -#ifndef MA_DR_FLAC_NO_OGG - if (pFlac->container == ma_dr_flac_container_ogg) +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) { - ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; oggbs->pUserData = &pFlac->memoryStream; } else @@ -88078,22 +58417,22 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, co } return pFlac; } -MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_t dataSize, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac__memory_stream memoryStream; - ma_dr_flac* pFlac; - memoryStream.data = (const ma_uint8*)pData; + drflac__memory_stream memoryStream; + drflac* pFlac; + memoryStream.data = (const drflac_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } pFlac->memoryStream = memoryStream; -#ifndef MA_DR_FLAC_NO_OGG - if (pFlac->container == ma_dr_flac_container_ogg) +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) { - ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; oggbs->pUserData = &pFlac->memoryStream; } else @@ -88103,104 +58442,104 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ } return pFlac; } -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); + return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); } -MA_API void ma_dr_flac_close(ma_dr_flac* pFlac) +DRFLAC_API void drflac_close(drflac* pFlac) { if (pFlac == NULL) { return; } -#ifndef MA_DR_FLAC_NO_STDIO - if (pFlac->bs.onRead == ma_dr_flac__on_read_stdio) { +#ifndef DR_FLAC_NO_STDIO + if (pFlac->bs.onRead == drflac__on_read_stdio) { fclose((FILE*)pFlac->bs.pUserData); } -#ifndef MA_DR_FLAC_NO_OGG - if (pFlac->container == ma_dr_flac_container_ogg) { - ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; - MA_DR_FLAC_ASSERT(pFlac->bs.onRead == ma_dr_flac__on_read_ogg); - if (oggbs->onRead == ma_dr_flac__on_read_stdio) { +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg); + if (oggbs->onRead == drflac__on_read_stdio) { fclose((FILE*)oggbs->pUserData); } } #endif #endif - ma_dr_flac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks); + drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks); } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCount; ++i) { - ma_uint32 left = (ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); - ma_uint32 side = (ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { - ma_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; - ma_uint32 right0 = left0 - side0; - ma_uint32 right1 = left1 - side1; - ma_uint32 right2 = left2 - side2; - ma_uint32 right3 = left3 - side3; - pOutputSamples[i*8+0] = (ma_int32)left0; - pOutputSamples[i*8+1] = (ma_int32)right0; - pOutputSamples[i*8+2] = (ma_int32)left1; - pOutputSamples[i*8+3] = (ma_int32)right1; - pOutputSamples[i*8+4] = (ma_int32)left2; - pOutputSamples[i*8+5] = (ma_int32)right2; - pOutputSamples[i*8+6] = (ma_int32)left3; - pOutputSamples[i*8+7] = (ma_int32)right3; + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + pOutputSamples[i*8+0] = (drflac_int32)left0; + pOutputSamples[i*8+1] = (drflac_int32)right0; + pOutputSamples[i*8+2] = (drflac_int32)left1; + pOutputSamples[i*8+3] = (drflac_int32)right1; + pOutputSamples[i*8+4] = (drflac_int32)left2; + pOutputSamples[i*8+5] = (drflac_int32)right2; + pOutputSamples[i*8+6] = (drflac_int32)left3; + pOutputSamples[i*8+7] = (drflac_int32)right3; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); for (i = 0; i < frameCount4; ++i) { __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); @@ -88209,26 +58548,26 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side__sse2(ma_ _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; int32x4_t shift0_4; int32x4_t shift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); shift0_4 = vdupq_n_s32(shift0); shift1_4 = vdupq_n_s32(shift1); for (i = 0; i < frameCount4; ++i) { @@ -88238,97 +58577,97 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side__neon(ma_ left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); right = vsubq_u32(left, side); - ma_dr_flac__vst2q_u32((ma_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_left_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCount; ++i) { - ma_uint32 side = (ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); - ma_uint32 right = (ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { - ma_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; - ma_uint32 left0 = right0 + side0; - ma_uint32 left1 = right1 + side1; - ma_uint32 left2 = right2 + side2; - ma_uint32 left3 = right3 + side3; - pOutputSamples[i*8+0] = (ma_int32)left0; - pOutputSamples[i*8+1] = (ma_int32)right0; - pOutputSamples[i*8+2] = (ma_int32)left1; - pOutputSamples[i*8+3] = (ma_int32)right1; - pOutputSamples[i*8+4] = (ma_int32)left2; - pOutputSamples[i*8+5] = (ma_int32)right2; - pOutputSamples[i*8+6] = (ma_int32)left3; - pOutputSamples[i*8+7] = (ma_int32)right3; + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + pOutputSamples[i*8+0] = (drflac_int32)left0; + pOutputSamples[i*8+1] = (drflac_int32)right0; + pOutputSamples[i*8+2] = (drflac_int32)left1; + pOutputSamples[i*8+3] = (drflac_int32)right1; + pOutputSamples[i*8+4] = (drflac_int32)left2; + pOutputSamples[i*8+5] = (drflac_int32)right2; + pOutputSamples[i*8+6] = (drflac_int32)left3; + pOutputSamples[i*8+7] = (drflac_int32)right3; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); for (i = 0; i < frameCount4; ++i) { __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); @@ -88337,26 +58676,26 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side__sse2(ma _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; int32x4_t shift0_4; int32x4_t shift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); shift0_4 = vdupq_n_s32(shift0); shift1_4 = vdupq_n_s32(shift1); for (i = 0; i < frameCount4; ++i) { @@ -88366,74 +58705,74 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side__neon(ma side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); left = vaddq_u32(right, side); - ma_dr_flac__vst2q_u32((ma_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left; - pOutputSamples[i*2+1] = (ma_int32)right; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_right_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - for (ma_uint64 i = 0; i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((ma_uint32)((ma_int32)(mid + side) >> 1) << unusedBitsPerSample); - pOutputSamples[i*2+1] = (ma_int32)((ma_uint32)((ma_int32)(mid - side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_int32 shift = unusedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; if (shift > 0) { shift -= 1; for (i = 0; i < frameCount4; ++i) { - ma_uint32 temp0L; - ma_uint32 temp1L; - ma_uint32 temp2L; - ma_uint32 temp3L; - ma_uint32 temp0R; - ma_uint32 temp1R; - ma_uint32 temp2R; - ma_uint32 temp3R; - ma_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid0 = (mid0 << 1) | (side0 & 0x01); mid1 = (mid1 << 1) | (side1 & 0x01); mid2 = (mid2 << 1) | (side2 & 0x01); @@ -88446,72 +58785,72 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__scalar(ma temp1R = (mid1 - side1) << shift; temp2R = (mid2 - side2) << shift; temp3R = (mid3 - side3) << shift; - pOutputSamples[i*8+0] = (ma_int32)temp0L; - pOutputSamples[i*8+1] = (ma_int32)temp0R; - pOutputSamples[i*8+2] = (ma_int32)temp1L; - pOutputSamples[i*8+3] = (ma_int32)temp1R; - pOutputSamples[i*8+4] = (ma_int32)temp2L; - pOutputSamples[i*8+5] = (ma_int32)temp2R; - pOutputSamples[i*8+6] = (ma_int32)temp3L; - pOutputSamples[i*8+7] = (ma_int32)temp3R; + pOutputSamples[i*8+0] = (drflac_int32)temp0L; + pOutputSamples[i*8+1] = (drflac_int32)temp0R; + pOutputSamples[i*8+2] = (drflac_int32)temp1L; + pOutputSamples[i*8+3] = (drflac_int32)temp1R; + pOutputSamples[i*8+4] = (drflac_int32)temp2L; + pOutputSamples[i*8+5] = (drflac_int32)temp2R; + pOutputSamples[i*8+6] = (drflac_int32)temp3L; + pOutputSamples[i*8+7] = (drflac_int32)temp3R; } } else { for (i = 0; i < frameCount4; ++i) { - ma_uint32 temp0L; - ma_uint32 temp1L; - ma_uint32 temp2L; - ma_uint32 temp3L; - ma_uint32 temp0R; - ma_uint32 temp1R; - ma_uint32 temp2R; - ma_uint32 temp3R; - ma_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid0 = (mid0 << 1) | (side0 & 0x01); mid1 = (mid1 << 1) | (side1 & 0x01); mid2 = (mid2 << 1) | (side2 & 0x01); mid3 = (mid3 << 1) | (side3 & 0x01); - temp0L = (ma_uint32)((ma_int32)(mid0 + side0) >> 1); - temp1L = (ma_uint32)((ma_int32)(mid1 + side1) >> 1); - temp2L = (ma_uint32)((ma_int32)(mid2 + side2) >> 1); - temp3L = (ma_uint32)((ma_int32)(mid3 + side3) >> 1); - temp0R = (ma_uint32)((ma_int32)(mid0 - side0) >> 1); - temp1R = (ma_uint32)((ma_int32)(mid1 - side1) >> 1); - temp2R = (ma_uint32)((ma_int32)(mid2 - side2) >> 1); - temp3R = (ma_uint32)((ma_int32)(mid3 - side3) >> 1); - pOutputSamples[i*8+0] = (ma_int32)temp0L; - pOutputSamples[i*8+1] = (ma_int32)temp0R; - pOutputSamples[i*8+2] = (ma_int32)temp1L; - pOutputSamples[i*8+3] = (ma_int32)temp1R; - pOutputSamples[i*8+4] = (ma_int32)temp2L; - pOutputSamples[i*8+5] = (ma_int32)temp2R; - pOutputSamples[i*8+6] = (ma_int32)temp3L; - pOutputSamples[i*8+7] = (ma_int32)temp3R; + temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1); + temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1); + temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1); + temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1); + temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1); + temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1); + temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1); + temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1); + pOutputSamples[i*8+0] = (drflac_int32)temp0L; + pOutputSamples[i*8+1] = (drflac_int32)temp0R; + pOutputSamples[i*8+2] = (drflac_int32)temp1L; + pOutputSamples[i*8+3] = (drflac_int32)temp1R; + pOutputSamples[i*8+4] = (drflac_int32)temp2L; + pOutputSamples[i*8+5] = (drflac_int32)temp2R; + pOutputSamples[i*8+6] = (drflac_int32)temp3L; + pOutputSamples[i*8+7] = (drflac_int32)temp3R; } } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((ma_uint32)((ma_int32)(mid + side) >> 1) << unusedBitsPerSample); - pOutputSamples[i*2+1] = (ma_int32)((ma_uint32)((ma_int32)(mid - side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_int32 shift = unusedBitsPerSample; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); if (shift == 0) { for (i = 0; i < frameCount4; ++i) { __m128i mid; @@ -88527,11 +58866,11 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__sse2(ma_d _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)(mid + side) >> 1; - pOutputSamples[i*2+1] = (ma_int32)(mid - side) >> 1; + pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; } } else { shift -= 1; @@ -88549,27 +58888,27 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__sse2(ma_d _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((mid + side) << shift); - pOutputSamples[i*2+1] = (ma_int32)((mid - side) << shift); + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); } } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_int32 shift = unusedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; int32x4_t wbpsShift0_4; int32x4_t wbpsShift1_4; uint32x4_t one4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); one4 = vdupq_n_u32(1); @@ -88584,14 +58923,14 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__neon(ma_d mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4)); left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); - ma_dr_flac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)(mid + side) >> 1; - pOutputSamples[i*2+1] = (ma_int32)(mid - side) >> 1; + pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; } } else { int32x4_t shift4; @@ -88607,86 +58946,86 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side__neon(ma_d mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4)); left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); - ma_dr_flac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((mid + side) << shift); - pOutputSamples[i*2+1] = (ma_int32)((mid - side) << shift); + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); } } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_mid_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - for (ma_uint64 i = 0; i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)((ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)); - pOutputSamples[i*2+1] = (ma_int32)((ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)); + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { - ma_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; - pOutputSamples[i*8+0] = (ma_int32)tempL0; - pOutputSamples[i*8+1] = (ma_int32)tempR0; - pOutputSamples[i*8+2] = (ma_int32)tempL1; - pOutputSamples[i*8+3] = (ma_int32)tempR1; - pOutputSamples[i*8+4] = (ma_int32)tempL2; - pOutputSamples[i*8+5] = (ma_int32)tempR2; - pOutputSamples[i*8+6] = (ma_int32)tempL3; - pOutputSamples[i*8+7] = (ma_int32)tempR3; + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + pOutputSamples[i*8+0] = (drflac_int32)tempL0; + pOutputSamples[i*8+1] = (drflac_int32)tempR0; + pOutputSamples[i*8+2] = (drflac_int32)tempL1; + pOutputSamples[i*8+3] = (drflac_int32)tempR1; + pOutputSamples[i*8+4] = (drflac_int32)tempL2; + pOutputSamples[i*8+5] = (drflac_int32)tempR2; + pOutputSamples[i*8+6] = (drflac_int32)tempL3; + pOutputSamples[i*8+7] = (drflac_int32)tempR3; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)(pInputSamples0U32[i] << shift0); - pOutputSamples[i*2+1] = (ma_int32)(pInputSamples1U32[i] << shift1); + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); @@ -88694,20 +59033,20 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo_ _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)(pInputSamples0U32[i] << shift0); - pOutputSamples[i*2+1] = (ma_int32)(pInputSamples1U32[i] << shift1); + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; int32x4_t shift4_0 = vdupq_n_s32(shift0); int32x4_t shift4_1 = vdupq_n_s32(shift1); for (i = 0; i < frameCount4; ++i) { @@ -88715,87 +59054,87 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo_ int32x4_t right; left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0)); right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1)); - ma_dr_flac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)(pInputSamples0U32[i] << shift0); - pOutputSamples[i*2+1] = (ma_int32)(pInputSamples1U32[i] << shift1); + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int32* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } -MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut) +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut) { - ma_uint64 framesRead; - ma_uint32 unusedBitsPerSample; + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; if (pFlac == NULL || framesToRead == 0) { return 0; } if (pBufferOut == NULL) { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, framesToRead); + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); } - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 32); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); unusedBitsPerSample = 32 - pFlac->bitsPerSample; framesRead = 0; while (framesToRead > 0) { if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { - if (!ma_dr_flac__read_and_decode_next_flac_frame(pFlac)) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { break; } } else { - unsigned int channelCount = ma_dr_flac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); - ma_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; - ma_uint64 frameCountThisIteration = framesToRead; + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; } if (channelCount == 2) { - const ma_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; - const ma_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; switch (pFlac->currentFLACFrame.header.channelAssignment) { - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { - ma_dr_flac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { - ma_dr_flac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: { - ma_dr_flac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: default: { - ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; } } else { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCountThisIteration; ++i) { unsigned int j; for (j = 0; j < channelCount; ++j) { - pBufferOut[(i*channelCount)+j] = (ma_int32)((ma_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); } } } @@ -88803,47 +59142,47 @@ MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 fra pBufferOut += frameCountThisIteration * channelCount; framesToRead -= frameCountThisIteration; pFlac->currentPCMFrame += frameCountThisIteration; - pFlac->currentFLACFrame.pcmFramesRemaining -= (ma_uint32)frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; } } return framesRead; } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCount; ++i) { - ma_uint32 left = (ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); - ma_uint32 side = (ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); - ma_uint32 right = left - side; + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { - ma_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; - ma_uint32 right0 = left0 - side0; - ma_uint32 right1 = left1 - side1; - ma_uint32 right2 = left2 - side2; - ma_uint32 right3 = left3 - side3; + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; left0 >>= 16; left1 >>= 16; left2 >>= 16; @@ -88852,66 +59191,66 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side__scalar(m right1 >>= 16; right2 >>= 16; right3 >>= 16; - pOutputSamples[i*8+0] = (ma_int16)left0; - pOutputSamples[i*8+1] = (ma_int16)right0; - pOutputSamples[i*8+2] = (ma_int16)left1; - pOutputSamples[i*8+3] = (ma_int16)right1; - pOutputSamples[i*8+4] = (ma_int16)left2; - pOutputSamples[i*8+5] = (ma_int16)right2; - pOutputSamples[i*8+6] = (ma_int16)left3; - pOutputSamples[i*8+7] = (ma_int16)right3; + pOutputSamples[i*8+0] = (drflac_int16)left0; + pOutputSamples[i*8+1] = (drflac_int16)right0; + pOutputSamples[i*8+2] = (drflac_int16)left1; + pOutputSamples[i*8+3] = (drflac_int16)right1; + pOutputSamples[i*8+4] = (drflac_int16)left2; + pOutputSamples[i*8+5] = (drflac_int16)right2; + pOutputSamples[i*8+6] = (drflac_int16)left3; + pOutputSamples[i*8+7] = (drflac_int16)right3; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); for (i = 0; i < frameCount4; ++i) { __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); __m128i right = _mm_sub_epi32(left, side); left = _mm_srai_epi32(left, 16); right = _mm_srai_epi32(right, 16); - _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), ma_dr_flac__mm_packs_interleaved_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; int32x4_t shift0_4; int32x4_t shift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); shift0_4 = vdupq_n_s32(shift0); shift1_4 = vdupq_n_s32(shift1); for (i = 0; i < frameCount4; ++i) { @@ -88923,74 +59262,74 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side__neon(ma_ right = vsubq_u32(left, side); left = vshrq_n_u32(left, 16); right = vshrq_n_u32(right, 16); - ma_dr_flac__vst2q_u16((ma_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_left_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCount; ++i) { - ma_uint32 side = (ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); - ma_uint32 right = (ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); - ma_uint32 left = right + side; + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { - ma_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; - ma_uint32 left0 = right0 + side0; - ma_uint32 left1 = right1 + side1; - ma_uint32 left2 = right2 + side2; - ma_uint32 left3 = right3 + side3; + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; left0 >>= 16; left1 >>= 16; left2 >>= 16; @@ -88999,66 +59338,66 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side__scalar( right1 >>= 16; right2 >>= 16; right3 >>= 16; - pOutputSamples[i*8+0] = (ma_int16)left0; - pOutputSamples[i*8+1] = (ma_int16)right0; - pOutputSamples[i*8+2] = (ma_int16)left1; - pOutputSamples[i*8+3] = (ma_int16)right1; - pOutputSamples[i*8+4] = (ma_int16)left2; - pOutputSamples[i*8+5] = (ma_int16)right2; - pOutputSamples[i*8+6] = (ma_int16)left3; - pOutputSamples[i*8+7] = (ma_int16)right3; + pOutputSamples[i*8+0] = (drflac_int16)left0; + pOutputSamples[i*8+1] = (drflac_int16)right0; + pOutputSamples[i*8+2] = (drflac_int16)left1; + pOutputSamples[i*8+3] = (drflac_int16)right1; + pOutputSamples[i*8+4] = (drflac_int16)left2; + pOutputSamples[i*8+5] = (drflac_int16)right2; + pOutputSamples[i*8+6] = (drflac_int16)left3; + pOutputSamples[i*8+7] = (drflac_int16)right3; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); for (i = 0; i < frameCount4; ++i) { __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); __m128i left = _mm_add_epi32(right, side); left = _mm_srai_epi32(left, 16); right = _mm_srai_epi32(right, 16); - _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), ma_dr_flac__mm_packs_interleaved_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; int32x4_t shift0_4; int32x4_t shift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); shift0_4 = vdupq_n_s32(shift0); shift1_4 = vdupq_n_s32(shift1); for (i = 0; i < frameCount4; ++i) { @@ -89070,76 +59409,76 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side__neon(ma left = vaddq_u32(right, side); left = vshrq_n_u32(left, 16); right = vshrq_n_u32(right, 16); - ma_dr_flac__vst2q_u16((ma_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; left >>= 16; right >>= 16; - pOutputSamples[i*2+0] = (ma_int16)left; - pOutputSamples[i*2+1] = (ma_int16)right; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_right_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - for (ma_uint64 i = 0; i < frameCount; ++i) { - ma_uint32 mid = (ma_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = (ma_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int16)(((ma_uint32)((ma_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); - pOutputSamples[i*2+1] = (ma_int16)(((ma_uint32)((ma_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift = unusedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; if (shift > 0) { shift -= 1; for (i = 0; i < frameCount4; ++i) { - ma_uint32 temp0L; - ma_uint32 temp1L; - ma_uint32 temp2L; - ma_uint32 temp3L; - ma_uint32 temp0R; - ma_uint32 temp1R; - ma_uint32 temp2R; - ma_uint32 temp3R; - ma_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid0 = (mid0 << 1) | (side0 & 0x01); mid1 = (mid1 << 1) | (side1 & 0x01); mid2 = (mid2 << 1) | (side2 & 0x01); @@ -89160,45 +59499,45 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__scalar(ma temp1R >>= 16; temp2R >>= 16; temp3R >>= 16; - pOutputSamples[i*8+0] = (ma_int16)temp0L; - pOutputSamples[i*8+1] = (ma_int16)temp0R; - pOutputSamples[i*8+2] = (ma_int16)temp1L; - pOutputSamples[i*8+3] = (ma_int16)temp1R; - pOutputSamples[i*8+4] = (ma_int16)temp2L; - pOutputSamples[i*8+5] = (ma_int16)temp2R; - pOutputSamples[i*8+6] = (ma_int16)temp3L; - pOutputSamples[i*8+7] = (ma_int16)temp3R; + pOutputSamples[i*8+0] = (drflac_int16)temp0L; + pOutputSamples[i*8+1] = (drflac_int16)temp0R; + pOutputSamples[i*8+2] = (drflac_int16)temp1L; + pOutputSamples[i*8+3] = (drflac_int16)temp1R; + pOutputSamples[i*8+4] = (drflac_int16)temp2L; + pOutputSamples[i*8+5] = (drflac_int16)temp2R; + pOutputSamples[i*8+6] = (drflac_int16)temp3L; + pOutputSamples[i*8+7] = (drflac_int16)temp3R; } } else { for (i = 0; i < frameCount4; ++i) { - ma_uint32 temp0L; - ma_uint32 temp1L; - ma_uint32 temp2L; - ma_uint32 temp3L; - ma_uint32 temp0R; - ma_uint32 temp1R; - ma_uint32 temp2R; - ma_uint32 temp3R; - ma_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid0 = (mid0 << 1) | (side0 & 0x01); mid1 = (mid1 << 1) | (side1 & 0x01); mid2 = (mid2 << 1) | (side2 & 0x01); mid3 = (mid3 << 1) | (side3 & 0x01); - temp0L = ((ma_int32)(mid0 + side0) >> 1); - temp1L = ((ma_int32)(mid1 + side1) >> 1); - temp2L = ((ma_int32)(mid2 + side2) >> 1); - temp3L = ((ma_int32)(mid3 + side3) >> 1); - temp0R = ((ma_int32)(mid0 - side0) >> 1); - temp1R = ((ma_int32)(mid1 - side1) >> 1); - temp2R = ((ma_int32)(mid2 - side2) >> 1); - temp3R = ((ma_int32)(mid3 - side3) >> 1); + temp0L = ((drflac_int32)(mid0 + side0) >> 1); + temp1L = ((drflac_int32)(mid1 + side1) >> 1); + temp2L = ((drflac_int32)(mid2 + side2) >> 1); + temp3L = ((drflac_int32)(mid3 + side3) >> 1); + temp0R = ((drflac_int32)(mid0 - side0) >> 1); + temp1R = ((drflac_int32)(mid1 - side1) >> 1); + temp2R = ((drflac_int32)(mid2 - side2) >> 1); + temp3R = ((drflac_int32)(mid3 - side3) >> 1); temp0L >>= 16; temp1L >>= 16; temp2L >>= 16; @@ -89207,33 +59546,33 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__scalar(ma temp1R >>= 16; temp2R >>= 16; temp3R >>= 16; - pOutputSamples[i*8+0] = (ma_int16)temp0L; - pOutputSamples[i*8+1] = (ma_int16)temp0R; - pOutputSamples[i*8+2] = (ma_int16)temp1L; - pOutputSamples[i*8+3] = (ma_int16)temp1R; - pOutputSamples[i*8+4] = (ma_int16)temp2L; - pOutputSamples[i*8+5] = (ma_int16)temp2R; - pOutputSamples[i*8+6] = (ma_int16)temp3L; - pOutputSamples[i*8+7] = (ma_int16)temp3R; + pOutputSamples[i*8+0] = (drflac_int16)temp0L; + pOutputSamples[i*8+1] = (drflac_int16)temp0R; + pOutputSamples[i*8+2] = (drflac_int16)temp1L; + pOutputSamples[i*8+3] = (drflac_int16)temp1R; + pOutputSamples[i*8+4] = (drflac_int16)temp2L; + pOutputSamples[i*8+5] = (drflac_int16)temp2R; + pOutputSamples[i*8+6] = (drflac_int16)temp3L; + pOutputSamples[i*8+7] = (drflac_int16)temp3R; } } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int16)(((ma_uint32)((ma_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); - pOutputSamples[i*2+1] = (ma_int16)(((ma_uint32)((ma_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift = unusedBitsPerSample; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); if (shift == 0) { for (i = 0; i < frameCount4; ++i) { __m128i mid; @@ -89247,14 +59586,14 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__sse2(ma_d right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); left = _mm_srai_epi32(left, 16); right = _mm_srai_epi32(right, 16); - _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), ma_dr_flac__mm_packs_interleaved_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int16)(((ma_int32)(mid + side) >> 1) >> 16); - pOutputSamples[i*2+1] = (ma_int16)(((ma_int32)(mid - side) >> 1) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); } } else { shift -= 1; @@ -89270,29 +59609,29 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__sse2(ma_d right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); left = _mm_srai_epi32(left, 16); right = _mm_srai_epi32(right, 16); - _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), ma_dr_flac__mm_packs_interleaved_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int16)(((mid + side) << shift) >> 16); - pOutputSamples[i*2+1] = (ma_int16)(((mid - side) << shift) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); } } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift = unusedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; int32x4_t wbpsShift0_4; int32x4_t wbpsShift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); if (shift == 0) { @@ -89308,14 +59647,14 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__neon(ma_d right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); left = vshrq_n_s32(left, 16); right = vshrq_n_s32(right, 16); - ma_dr_flac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int16)(((ma_int32)(mid + side) >> 1) >> 16); - pOutputSamples[i*2+1] = (ma_int16)(((ma_int32)(mid - side) >> 1) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); } } else { int32x4_t shift4; @@ -89333,63 +59672,63 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side__neon(ma_d right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); left = vshrq_n_s32(left, 16); right = vshrq_n_s32(right, 16); - ma_dr_flac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int16)(((mid + side) << shift) >> 16); - pOutputSamples[i*2+1] = (ma_int16)(((mid - side) << shift) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); } } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_mid_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - for (ma_uint64 i = 0; i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int16)((ma_int32)((ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16); - pOutputSamples[i*2+1] = (ma_int16)((ma_int32)((ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16); + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { - ma_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; tempL0 >>= 16; tempL1 >>= 16; tempL2 >>= 16; @@ -89398,51 +59737,51 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo_ tempR1 >>= 16; tempR2 >>= 16; tempR3 >>= 16; - pOutputSamples[i*8+0] = (ma_int16)tempL0; - pOutputSamples[i*8+1] = (ma_int16)tempR0; - pOutputSamples[i*8+2] = (ma_int16)tempL1; - pOutputSamples[i*8+3] = (ma_int16)tempR1; - pOutputSamples[i*8+4] = (ma_int16)tempL2; - pOutputSamples[i*8+5] = (ma_int16)tempR2; - pOutputSamples[i*8+6] = (ma_int16)tempL3; - pOutputSamples[i*8+7] = (ma_int16)tempR3; + pOutputSamples[i*8+0] = (drflac_int16)tempL0; + pOutputSamples[i*8+1] = (drflac_int16)tempR0; + pOutputSamples[i*8+2] = (drflac_int16)tempL1; + pOutputSamples[i*8+3] = (drflac_int16)tempR1; + pOutputSamples[i*8+4] = (drflac_int16)tempL2; + pOutputSamples[i*8+5] = (drflac_int16)tempR2; + pOutputSamples[i*8+6] = (drflac_int16)tempL3; + pOutputSamples[i*8+7] = (drflac_int16)tempR3; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int16)((pInputSamples0U32[i] << shift0) >> 16); - pOutputSamples[i*2+1] = (ma_int16)((pInputSamples1U32[i] << shift1) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; for (i = 0; i < frameCount4; ++i) { __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); left = _mm_srai_epi32(left, 16); right = _mm_srai_epi32(right, 16); - _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), ma_dr_flac__mm_packs_interleaved_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int16)((pInputSamples0U32[i] << shift0) >> 16); - pOutputSamples[i*2+1] = (ma_int16)((pInputSamples1U32[i] << shift1) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; int32x4_t shift0_4 = vdupq_n_s32(shift0); int32x4_t shift1_4 = vdupq_n_s32(shift1); for (i = 0; i < frameCount4; ++i) { @@ -89452,88 +59791,88 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo_ right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4)); left = vshrq_n_s32(left, 16); right = vshrq_n_s32(right, 16); - ma_dr_flac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int16)((pInputSamples0U32[i] << shift0) >> 16); - pOutputSamples[i*2+1] = (ma_int16)((pInputSamples1U32[i] << shift1) >> 16); + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, ma_int16* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } -MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut) { - ma_uint64 framesRead; - ma_uint32 unusedBitsPerSample; + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; if (pFlac == NULL || framesToRead == 0) { return 0; } if (pBufferOut == NULL) { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, framesToRead); + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); } - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 32); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); unusedBitsPerSample = 32 - pFlac->bitsPerSample; framesRead = 0; while (framesToRead > 0) { if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { - if (!ma_dr_flac__read_and_decode_next_flac_frame(pFlac)) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { break; } } else { - unsigned int channelCount = ma_dr_flac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); - ma_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; - ma_uint64 frameCountThisIteration = framesToRead; + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; } if (channelCount == 2) { - const ma_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; - const ma_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; switch (pFlac->currentFLACFrame.header.channelAssignment) { - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { - ma_dr_flac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { - ma_dr_flac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: { - ma_dr_flac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: default: { - ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; } } else { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCountThisIteration; ++i) { unsigned int j; for (j = 0; j < channelCount; ++j) { - ma_int32 sampleS32 = (ma_int32)((ma_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); - pBufferOut[(i*channelCount)+j] = (ma_int16)(sampleS32 >> 16); + drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16); } } } @@ -89541,74 +59880,74 @@ MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 fra pBufferOut += frameCountThisIteration * channelCount; framesToRead -= frameCountThisIteration; pFlac->currentPCMFrame += frameCountThisIteration; - pFlac->currentFLACFrame.pcmFramesRemaining -= (ma_uint32)frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; } } return framesRead; } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCount; ++i) { - ma_uint32 left = (ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); - ma_uint32 side = (ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (float)((ma_int32)left / 2147483648.0); - pOutputSamples[i*2+1] = (float)((ma_int32)right / 2147483648.0); + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; float factor = 1 / 2147483648.0; for (i = 0; i < frameCount4; ++i) { - ma_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; - ma_uint32 right0 = left0 - side0; - ma_uint32 right1 = left1 - side1; - ma_uint32 right2 = left2 - side2; - ma_uint32 right3 = left3 - side3; - pOutputSamples[i*8+0] = (ma_int32)left0 * factor; - pOutputSamples[i*8+1] = (ma_int32)right0 * factor; - pOutputSamples[i*8+2] = (ma_int32)left1 * factor; - pOutputSamples[i*8+3] = (ma_int32)right1 * factor; - pOutputSamples[i*8+4] = (ma_int32)left2 * factor; - pOutputSamples[i*8+5] = (ma_int32)right2 * factor; - pOutputSamples[i*8+6] = (ma_int32)left3 * factor; - pOutputSamples[i*8+7] = (ma_int32)right3 * factor; + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + pOutputSamples[i*8+0] = (drflac_int32)left0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)right0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)left1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)right1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)left2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)right2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)left3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)right3 * factor; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left * factor; - pOutputSamples[i*2+1] = (ma_int32)right * factor; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left * factor; + pOutputSamples[i*2+1] = (drflac_int32)right * factor; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; - ma_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; __m128 factor; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); factor = _mm_set1_ps(1.0f / 8388608.0f); for (i = 0; i < frameCount4; ++i) { __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); @@ -89620,27 +59959,27 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side__sse2(ma_ _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left / 8388608.0f; - pOutputSamples[i*2+1] = (ma_int32)right / 8388608.0f; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; - ma_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; float32x4_t factor4; int32x4_t shift0_4; int32x4_t shift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); factor4 = vdupq_n_f32(1.0f / 8388608.0f); shift0_4 = vdupq_n_s32(shift0); shift1_4 = vdupq_n_s32(shift1); @@ -89655,99 +59994,99 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side__neon(ma_ right = vsubq_u32(left, side); leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); - ma_dr_flac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 left = pInputSamples0U32[i] << shift0; - ma_uint32 side = pInputSamples1U32[i] << shift1; - ma_uint32 right = left - side; - pOutputSamples[i*2+0] = (ma_int32)left / 8388608.0f; - pOutputSamples[i*2+1] = (ma_int32)right / 8388608.0f; + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_left_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCount; ++i) { - ma_uint32 side = (ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); - ma_uint32 right = (ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (float)((ma_int32)left / 2147483648.0); - pOutputSamples[i*2+1] = (float)((ma_int32)right / 2147483648.0); + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; float factor = 1 / 2147483648.0; for (i = 0; i < frameCount4; ++i) { - ma_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; - ma_uint32 left0 = right0 + side0; - ma_uint32 left1 = right1 + side1; - ma_uint32 left2 = right2 + side2; - ma_uint32 left3 = right3 + side3; - pOutputSamples[i*8+0] = (ma_int32)left0 * factor; - pOutputSamples[i*8+1] = (ma_int32)right0 * factor; - pOutputSamples[i*8+2] = (ma_int32)left1 * factor; - pOutputSamples[i*8+3] = (ma_int32)right1 * factor; - pOutputSamples[i*8+4] = (ma_int32)left2 * factor; - pOutputSamples[i*8+5] = (ma_int32)right2 * factor; - pOutputSamples[i*8+6] = (ma_int32)left3 * factor; - pOutputSamples[i*8+7] = (ma_int32)right3 * factor; + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + pOutputSamples[i*8+0] = (drflac_int32)left0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)right0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)left1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)right1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)left2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)right2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)left3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)right3 * factor; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left * factor; - pOutputSamples[i*2+1] = (ma_int32)right * factor; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left * factor; + pOutputSamples[i*2+1] = (drflac_int32)right * factor; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; - ma_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; __m128 factor; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); factor = _mm_set1_ps(1.0f / 8388608.0f); for (i = 0; i < frameCount4; ++i) { __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); @@ -89759,27 +60098,27 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side__sse2(ma _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left / 8388608.0f; - pOutputSamples[i*2+1] = (ma_int32)right / 8388608.0f; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; - ma_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; float32x4_t factor4; int32x4_t shift0_4; int32x4_t shift1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); factor4 = vdupq_n_f32(1.0f / 8388608.0f); shift0_4 = vdupq_n_s32(shift0); shift1_4 = vdupq_n_s32(shift1); @@ -89794,75 +60133,75 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side__neon(ma left = vaddq_u32(right, side); leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); - ma_dr_flac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 side = pInputSamples0U32[i] << shift0; - ma_uint32 right = pInputSamples1U32[i] << shift1; - ma_uint32 left = right + side; - pOutputSamples[i*2+0] = (ma_int32)left / 8388608.0f; - pOutputSamples[i*2+1] = (ma_int32)right / 8388608.0f; + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_right_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - for (ma_uint64 i = 0; i < frameCount; ++i) { - ma_uint32 mid = (ma_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = (ma_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (float)((((ma_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); - pOutputSamples[i*2+1] = (float)((((ma_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift = unusedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; float factor = 1 / 2147483648.0; if (shift > 0) { shift -= 1; for (i = 0; i < frameCount4; ++i) { - ma_uint32 temp0L; - ma_uint32 temp1L; - ma_uint32 temp2L; - ma_uint32 temp3L; - ma_uint32 temp0R; - ma_uint32 temp1R; - ma_uint32 temp2R; - ma_uint32 temp3R; - ma_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid0 = (mid0 << 1) | (side0 & 0x01); mid1 = (mid1 << 1) | (side1 & 0x01); mid2 = (mid2 << 1) | (side2 & 0x01); @@ -89875,74 +60214,74 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__scalar(ma temp1R = (mid1 - side1) << shift; temp2R = (mid2 - side2) << shift; temp3R = (mid3 - side3) << shift; - pOutputSamples[i*8+0] = (ma_int32)temp0L * factor; - pOutputSamples[i*8+1] = (ma_int32)temp0R * factor; - pOutputSamples[i*8+2] = (ma_int32)temp1L * factor; - pOutputSamples[i*8+3] = (ma_int32)temp1R * factor; - pOutputSamples[i*8+4] = (ma_int32)temp2L * factor; - pOutputSamples[i*8+5] = (ma_int32)temp2R * factor; - pOutputSamples[i*8+6] = (ma_int32)temp3L * factor; - pOutputSamples[i*8+7] = (ma_int32)temp3R * factor; + pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor; + pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor; + pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor; + pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor; + pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor; + pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor; + pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor; + pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor; } } else { for (i = 0; i < frameCount4; ++i) { - ma_uint32 temp0L; - ma_uint32 temp1L; - ma_uint32 temp2L; - ma_uint32 temp3L; - ma_uint32 temp0R; - ma_uint32 temp1R; - ma_uint32 temp2R; - ma_uint32 temp3R; - ma_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; - ma_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid0 = (mid0 << 1) | (side0 & 0x01); mid1 = (mid1 << 1) | (side1 & 0x01); mid2 = (mid2 << 1) | (side2 & 0x01); mid3 = (mid3 << 1) | (side3 & 0x01); - temp0L = (ma_uint32)((ma_int32)(mid0 + side0) >> 1); - temp1L = (ma_uint32)((ma_int32)(mid1 + side1) >> 1); - temp2L = (ma_uint32)((ma_int32)(mid2 + side2) >> 1); - temp3L = (ma_uint32)((ma_int32)(mid3 + side3) >> 1); - temp0R = (ma_uint32)((ma_int32)(mid0 - side0) >> 1); - temp1R = (ma_uint32)((ma_int32)(mid1 - side1) >> 1); - temp2R = (ma_uint32)((ma_int32)(mid2 - side2) >> 1); - temp3R = (ma_uint32)((ma_int32)(mid3 - side3) >> 1); - pOutputSamples[i*8+0] = (ma_int32)temp0L * factor; - pOutputSamples[i*8+1] = (ma_int32)temp0R * factor; - pOutputSamples[i*8+2] = (ma_int32)temp1L * factor; - pOutputSamples[i*8+3] = (ma_int32)temp1R * factor; - pOutputSamples[i*8+4] = (ma_int32)temp2L * factor; - pOutputSamples[i*8+5] = (ma_int32)temp2R * factor; - pOutputSamples[i*8+6] = (ma_int32)temp3L * factor; - pOutputSamples[i*8+7] = (ma_int32)temp3R * factor; + temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1); + temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1); + temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1); + temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1); + temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1); + temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1); + temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1); + temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1); + pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor; + pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor; + pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor; + pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor; + pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor; + pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor; + pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor; + pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor; } } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((ma_uint32)((ma_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor; - pOutputSamples[i*2+1] = (ma_int32)((ma_uint32)((ma_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor; + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift = unusedBitsPerSample - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample - 8; float factor; __m128 factor128; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); factor = 1.0f / 8388608.0f; factor128 = _mm_set1_ps(factor); if (shift == 0) { @@ -89964,11 +60303,11 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__sse2(ma_d _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = ((ma_int32)(mid + side) >> 1) * factor; - pOutputSamples[i*2+1] = ((ma_int32)(mid - side) >> 1) * factor; + pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; } } else { shift -= 1; @@ -89990,29 +60329,29 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__sse2(ma_d _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((mid + side) << shift) * factor; - pOutputSamples[i*2+1] = (ma_int32)((mid - side) << shift) * factor; + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; } } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift = unusedBitsPerSample - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample - 8; float factor; float32x4_t factor4; int32x4_t shift4; int32x4_t wbps0_4; int32x4_t wbps1_4; - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); factor = 1.0f / 8388608.0f; factor4 = vdupq_n_f32(factor); wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); @@ -90030,14 +60369,14 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__neon(ma_d righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); - ma_dr_flac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = ((ma_int32)(mid + side) >> 1) * factor; - pOutputSamples[i*2+1] = ((ma_int32)(mid - side) >> 1) * factor; + pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; } } else { shift -= 1; @@ -90056,87 +60395,87 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side__neon(ma_d righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); - ma_dr_flac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - ma_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; mid = (mid << 1) | (side & 0x01); - pOutputSamples[i*2+0] = (ma_int32)((mid + side) << shift) * factor; - pOutputSamples[i*2+1] = (ma_int32)((mid - side) << shift) * factor; + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; } } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_mid_side(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } #if 0 -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__reference(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - for (ma_uint64 i = 0; i < frameCount; ++i) { - pOutputSamples[i*2+0] = (float)((ma_int32)((ma_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0); - pOutputSamples[i*2+1] = (float)((ma_int32)((ma_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0); + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0); } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__scalar(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; - ma_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; float factor = 1 / 2147483648.0; for (i = 0; i < frameCount4; ++i) { - ma_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; - ma_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; - ma_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; - ma_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; - ma_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; - ma_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; - ma_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; - ma_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; - pOutputSamples[i*8+0] = (ma_int32)tempL0 * factor; - pOutputSamples[i*8+1] = (ma_int32)tempR0 * factor; - pOutputSamples[i*8+2] = (ma_int32)tempL1 * factor; - pOutputSamples[i*8+3] = (ma_int32)tempR1 * factor; - pOutputSamples[i*8+4] = (ma_int32)tempL2 * factor; - pOutputSamples[i*8+5] = (ma_int32)tempR2 * factor; - pOutputSamples[i*8+6] = (ma_int32)tempL3 * factor; - pOutputSamples[i*8+7] = (ma_int32)tempR3 * factor; + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor; } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)(pInputSamples0U32[i] << shift0) * factor; - pOutputSamples[i*2+1] = (ma_int32)(pInputSamples1U32[i] << shift1) * factor; + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; } } -#if defined(MA_DR_FLAC_SUPPORT_SSE2) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__sse2(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; - ma_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; float factor = 1.0f / 8388608.0f; __m128 factor128 = _mm_set1_ps(factor); for (i = 0; i < frameCount4; ++i) { @@ -90152,20 +60491,20 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo_ _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)(pInputSamples0U32[i] << shift0) * factor; - pOutputSamples[i*2+1] = (ma_int32)(pInputSamples1U32[i] << shift1) * factor; + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; } } #endif -#if defined(MA_DR_FLAC_SUPPORT_NEON) -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__neon(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - ma_uint64 i; - ma_uint64 frameCount4 = frameCount >> 2; - const ma_uint32* pInputSamples0U32 = (const ma_uint32*)pInputSamples0; - const ma_uint32* pInputSamples1U32 = (const ma_uint32*)pInputSamples1; - ma_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; - ma_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; float factor = 1.0f / 8388608.0f; float32x4_t factor4 = vdupq_n_f32(factor); int32x4_t shift0_4 = vdupq_n_s32(shift0); @@ -90179,87 +60518,87 @@ static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo_ righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4)); leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); - ma_dr_flac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); } for (i = (frameCount4 << 2); i < frameCount; ++i) { - pOutputSamples[i*2+0] = (ma_int32)(pInputSamples0U32[i] << shift0) * factor; - pOutputSamples[i*2+1] = (ma_int32)(pInputSamples1U32[i] << shift1) * factor; + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; } } #endif -static MA_INLINE void ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo(ma_dr_flac* pFlac, ma_uint64 frameCount, ma_uint32 unusedBitsPerSample, const ma_int32* pInputSamples0, const ma_int32* pInputSamples1, float* pOutputSamples) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { -#if defined(MA_DR_FLAC_SUPPORT_SSE2) - if (ma_dr_flac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else -#elif defined(MA_DR_FLAC_SUPPORT_NEON) - if (ma_dr_flac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { - ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); } else #endif { #if 0 - ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else - ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #endif } } -MA_API ma_uint64 ma_dr_flac_read_pcm_frames_f32(ma_dr_flac* pFlac, ma_uint64 framesToRead, float* pBufferOut) +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut) { - ma_uint64 framesRead; - ma_uint32 unusedBitsPerSample; + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; if (pFlac == NULL || framesToRead == 0) { return 0; } if (pBufferOut == NULL) { - return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, framesToRead); + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); } - MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 32); + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); unusedBitsPerSample = 32 - pFlac->bitsPerSample; framesRead = 0; while (framesToRead > 0) { if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { - if (!ma_dr_flac__read_and_decode_next_flac_frame(pFlac)) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { break; } } else { - unsigned int channelCount = ma_dr_flac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); - ma_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; - ma_uint64 frameCountThisIteration = framesToRead; + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; } if (channelCount == 2) { - const ma_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; - const ma_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; switch (pFlac->currentFLACFrame.header.channelAssignment) { - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { - ma_dr_flac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { - ma_dr_flac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: { - ma_dr_flac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; - case MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: default: { - ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); } break; } } else { - ma_uint64 i; + drflac_uint64 i; for (i = 0; i < frameCountThisIteration; ++i) { unsigned int j; for (j = 0; j < channelCount; ++j) { - ma_int32 sampleS32 = (ma_int32)((ma_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0); } } @@ -90273,102 +60612,111 @@ MA_API ma_uint64 ma_dr_flac_read_pcm_frames_f32(ma_dr_flac* pFlac, ma_uint64 fra } return framesRead; } -MA_API ma_bool32 ma_dr_flac_seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) { if (pFlac == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } if (pFlac->currentPCMFrame == pcmFrameIndex) { - return MA_TRUE; + return DRFLAC_TRUE; } if (pFlac->firstFLACFramePosInBytes == 0) { - return MA_FALSE; + return DRFLAC_FALSE; } if (pcmFrameIndex == 0) { pFlac->currentPCMFrame = 0; - return ma_dr_flac__seek_to_first_frame(pFlac); + return drflac__seek_to_first_frame(pFlac); } else { - ma_bool32 wasSuccessful = MA_FALSE; - ma_uint64 originalPCMFrame = pFlac->currentPCMFrame; + drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; if (pcmFrameIndex > pFlac->totalPCMFrameCount) { pcmFrameIndex = pFlac->totalPCMFrameCount; } if (pcmFrameIndex > pFlac->currentPCMFrame) { - ma_uint32 offset = (ma_uint32)(pcmFrameIndex - pFlac->currentPCMFrame); + drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame); if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) { pFlac->currentFLACFrame.pcmFramesRemaining -= offset; pFlac->currentPCMFrame = pcmFrameIndex; - return MA_TRUE; + return DRFLAC_TRUE; } } else { - ma_uint32 offsetAbs = (ma_uint32)(pFlac->currentPCMFrame - pcmFrameIndex); - ma_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; - ma_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex); + drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining; if (currentFLACFramePCMFramesConsumed > offsetAbs) { pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs; pFlac->currentPCMFrame = pcmFrameIndex; - return MA_TRUE; + return DRFLAC_TRUE; } } -#ifndef MA_DR_FLAC_NO_OGG - if (pFlac->container == ma_dr_flac_container_ogg) +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) { - wasSuccessful = ma_dr_flac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex); + wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex); } else #endif { if (!pFlac->_noSeekTableSeek) { - wasSuccessful = ma_dr_flac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex); + wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex); } -#if !defined(MA_DR_FLAC_NO_CRC) +#if !defined(DR_FLAC_NO_CRC) if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) { - wasSuccessful = ma_dr_flac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex); + wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex); } #endif if (!wasSuccessful && !pFlac->_noBruteForceSeek) { - wasSuccessful = ma_dr_flac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); + wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); } } if (wasSuccessful) { pFlac->currentPCMFrame = pcmFrameIndex; } else { - if (ma_dr_flac_seek_to_pcm_frame(pFlac, originalPCMFrame) == MA_FALSE) { - ma_dr_flac_seek_to_pcm_frame(pFlac, 0); + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + drflac_seek_to_pcm_frame(pFlac, 0); } } return wasSuccessful; } } -#define MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \ -static type* ma_dr_flac__full_read_and_close_ ## extension (ma_dr_flac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut)\ +#if defined(SIZE_MAX) + #define DRFLAC_SIZE_MAX SIZE_MAX +#else + #if defined(DRFLAC_64BIT) + #define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRFLAC_SIZE_MAX 0xFFFFFFFF + #endif +#endif +#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \ +static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\ { \ type* pSampleData = NULL; \ - ma_uint64 totalPCMFrameCount; \ + drflac_uint64 totalPCMFrameCount; \ \ - MA_DR_FLAC_ASSERT(pFlac != NULL); \ + DRFLAC_ASSERT(pFlac != NULL); \ \ totalPCMFrameCount = pFlac->totalPCMFrameCount; \ \ if (totalPCMFrameCount == 0) { \ type buffer[4096]; \ - ma_uint64 pcmFramesRead; \ + drflac_uint64 pcmFramesRead; \ size_t sampleDataBufferSize = sizeof(buffer); \ \ - pSampleData = (type*)ma_dr_flac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ + pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ if (pSampleData == NULL) { \ goto on_error; \ } \ \ - while ((pcmFramesRead = (ma_uint64)ma_dr_flac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \ + while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \ if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \ type* pNewSampleData; \ size_t newSampleDataBufferSize; \ \ newSampleDataBufferSize = sampleDataBufferSize * 2; \ - pNewSampleData = (type*)ma_dr_flac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ + pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ if (pNewSampleData == NULL) { \ - ma_dr_flac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ + drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ goto on_error; \ } \ \ @@ -90376,43 +60724,43 @@ static type* ma_dr_flac__full_read_and_close_ ## extension (ma_dr_flac* pFlac, u pSampleData = pNewSampleData; \ } \ \ - MA_DR_FLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ + DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ totalPCMFrameCount += pcmFramesRead; \ } \ \ \ - MA_DR_FLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ + DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ } else { \ - ma_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ - if (dataSize > (ma_uint64)MA_SIZE_MAX) { \ + drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ + if (dataSize > DRFLAC_SIZE_MAX) { \ goto on_error; \ } \ \ - pSampleData = (type*)ma_dr_flac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); \ + pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); \ if (pSampleData == NULL) { \ goto on_error; \ } \ \ - totalPCMFrameCount = ma_dr_flac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \ + totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \ } \ \ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ if (channelsOut) *channelsOut = pFlac->channels; \ if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \ \ - ma_dr_flac_close(pFlac); \ + drflac_close(pFlac); \ return pSampleData; \ \ on_error: \ - ma_dr_flac_close(pFlac); \ + drflac_close(pFlac); \ return NULL; \ } -MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s32, ma_int32) -MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s16, ma_int16) -MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) +DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (channelsOut) { *channelsOut = 0; } @@ -90422,15 +60770,15 @@ MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); + return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (channelsOut) { *channelsOut = 0; } @@ -90440,15 +60788,15 @@ MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); + return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (channelsOut) { *channelsOut = 0; } @@ -90458,16 +60806,16 @@ MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRea if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); + return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -#ifndef MA_DR_FLAC_NO_STDIO -MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +#ifndef DR_FLAC_NO_STDIO +DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (sampleRate) { *sampleRate = 0; } @@ -90477,15 +60825,15 @@ MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filena if (totalPCMFrameCount) { *totalPCMFrameCount = 0; } - pFlac = ma_dr_flac_open_file(filename, pAllocationCallbacks); + pFlac = drflac_open_file(filename, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); } -MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (sampleRate) { *sampleRate = 0; } @@ -90495,15 +60843,15 @@ MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filena if (totalPCMFrameCount) { *totalPCMFrameCount = 0; } - pFlac = ma_dr_flac_open_file(filename, pAllocationCallbacks); + pFlac = drflac_open_file(filename, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); } -MA_API float* ma_dr_flac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (sampleRate) { *sampleRate = 0; } @@ -90513,16 +60861,16 @@ MA_API float* ma_dr_flac_open_file_and_read_pcm_frames_f32(const char* filename, if (totalPCMFrameCount) { *totalPCMFrameCount = 0; } - pFlac = ma_dr_flac_open_file(filename, pAllocationCallbacks); + pFlac = drflac_open_file(filename, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); } #endif -MA_API ma_int32* ma_dr_flac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (sampleRate) { *sampleRate = 0; } @@ -90532,15 +60880,15 @@ MA_API ma_int32* ma_dr_flac_open_memory_and_read_pcm_frames_s32(const void* data if (totalPCMFrameCount) { *totalPCMFrameCount = 0; } - pFlac = ma_dr_flac_open_memory(data, dataSize, pAllocationCallbacks); + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); } -MA_API ma_int16* ma_dr_flac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (sampleRate) { *sampleRate = 0; } @@ -90550,15 +60898,15 @@ MA_API ma_int16* ma_dr_flac_open_memory_and_read_pcm_frames_s16(const void* data if (totalPCMFrameCount) { *totalPCMFrameCount = 0; } - pFlac = ma_dr_flac_open_memory(data, dataSize, pAllocationCallbacks); + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); } -MA_API float* ma_dr_flac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) { - ma_dr_flac* pFlac; + drflac* pFlac; if (sampleRate) { *sampleRate = 0; } @@ -90568,21 +60916,21 @@ MA_API float* ma_dr_flac_open_memory_and_read_pcm_frames_f32(const void* data, s if (totalPCMFrameCount) { *totalPCMFrameCount = 0; } - pFlac = ma_dr_flac_open_memory(data, dataSize, pAllocationCallbacks); + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return ma_dr_flac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); } -MA_API void ma_dr_flac_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { - ma_dr_flac__free_from_callbacks(p, pAllocationCallbacks); + drflac__free_from_callbacks(p, pAllocationCallbacks); } else { - ma_dr_flac__free_default(p, NULL); + drflac__free_default(p, NULL); } } -MA_API void ma_dr_flac_init_vorbis_comment_iterator(ma_dr_flac_vorbis_comment_iterator* pIter, ma_uint32 commentCount, const void* pComments) +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments) { if (pIter == NULL) { return; @@ -90590,9 +60938,9 @@ MA_API void ma_dr_flac_init_vorbis_comment_iterator(ma_dr_flac_vorbis_comment_it pIter->countRemaining = commentCount; pIter->pRunningData = (const char*)pComments; } -MA_API const char* ma_dr_flac_next_vorbis_comment(ma_dr_flac_vorbis_comment_iterator* pIter, ma_uint32* pCommentLengthOut) +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) { - ma_int32 length; + drflac_int32 length; const char* pComment; if (pCommentLengthOut) { *pCommentLengthOut = 0; @@ -90600,7 +60948,7 @@ MA_API const char* ma_dr_flac_next_vorbis_comment(ma_dr_flac_vorbis_comment_iter if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { return NULL; } - length = ma_dr_flac__le2host_32_ptr_unaligned(pIter->pRunningData); + length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); pIter->pRunningData += 4; pComment = pIter->pRunningData; pIter->pRunningData += length; @@ -90610,7 +60958,7 @@ MA_API const char* ma_dr_flac_next_vorbis_comment(ma_dr_flac_vorbis_comment_iter } return pComment; } -MA_API void ma_dr_flac_init_cuesheet_track_iterator(ma_dr_flac_cuesheet_track_iterator* pIter, ma_uint32 trackCount, const void* pTrackData) +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData) { if (pIter == NULL) { return; @@ -90618,127 +60966,127 @@ MA_API void ma_dr_flac_init_cuesheet_track_iterator(ma_dr_flac_cuesheet_track_it pIter->countRemaining = trackCount; pIter->pRunningData = (const char*)pTrackData; } -MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterator* pIter, ma_dr_flac_cuesheet_track* pCuesheetTrack) +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack) { - ma_dr_flac_cuesheet_track cuesheetTrack; + drflac_cuesheet_track cuesheetTrack; const char* pRunningData; - ma_uint64 offsetHi; - ma_uint64 offsetLo; + drflac_uint64 offsetHi; + drflac_uint64 offsetLo; if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { - return MA_FALSE; + return DRFLAC_FALSE; } pRunningData = pIter->pRunningData; - offsetHi = ma_dr_flac__be2host_32(*(const ma_uint32*)pRunningData); pRunningData += 4; - offsetLo = ma_dr_flac__be2host_32(*(const ma_uint32*)pRunningData); pRunningData += 4; + offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; cuesheetTrack.offset = offsetLo | (offsetHi << 32); cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1; - MA_DR_FLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12; + DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12; cuesheetTrack.isAudio = (pRunningData[0] & 0x80) != 0; cuesheetTrack.preEmphasis = (pRunningData[0] & 0x40) != 0; pRunningData += 14; cuesheetTrack.indexCount = pRunningData[0]; pRunningData += 1; - cuesheetTrack.pIndexPoints = (const ma_dr_flac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(ma_dr_flac_cuesheet_track_index); + cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index); pIter->pRunningData = pRunningData; pIter->countRemaining -= 1; if (pCuesheetTrack) { *pCuesheetTrack = cuesheetTrack; } - return MA_TRUE; + return DRFLAC_TRUE; } #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic pop #endif #endif /* dr_flac_c end */ -#endif /* MA_DR_FLAC_IMPLEMENTATION */ +#endif /* DRFLAC_IMPLEMENTATION */ #endif /* MA_NO_FLAC */ #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) -#if !defined(MA_DR_MP3_IMPLEMENTATION) +#if !defined(DR_MP3_IMPLEMENTATION) && !defined(DRMP3_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */ /* dr_mp3_c begin */ -#ifndef ma_dr_mp3_c -#define ma_dr_mp3_c +#ifndef dr_mp3_c +#define dr_mp3_c #include #include #include -MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision) +DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision) { if (pMajor) { - *pMajor = MA_DR_MP3_VERSION_MAJOR; + *pMajor = DRMP3_VERSION_MAJOR; } if (pMinor) { - *pMinor = MA_DR_MP3_VERSION_MINOR; + *pMinor = DRMP3_VERSION_MINOR; } if (pRevision) { - *pRevision = MA_DR_MP3_VERSION_REVISION; + *pRevision = DRMP3_VERSION_REVISION; } } -MA_API const char* ma_dr_mp3_version_string(void) +DRMP3_API const char* drmp3_version_string(void) { - return MA_DR_MP3_VERSION_STRING; + return DRMP3_VERSION_STRING; } #if defined(__TINYC__) -#define MA_DR_MP3_NO_SIMD +#define DR_MP3_NO_SIMD #endif -#define MA_DR_MP3_OFFSET_PTR(p, offset) ((void*)((ma_uint8*)(p) + (offset))) -#define MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 -#ifndef MA_DR_MP3_MAX_FRAME_SYNC_MATCHES -#define MA_DR_MP3_MAX_FRAME_SYNC_MATCHES 10 +#define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset))) +#define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 +#ifndef DRMP3_MAX_FRAME_SYNC_MATCHES +#define DRMP3_MAX_FRAME_SYNC_MATCHES 10 #endif -#define MA_DR_MP3_MAX_L3_FRAME_PAYLOAD_BYTES MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE -#define MA_DR_MP3_MAX_BITRESERVOIR_BYTES 511 -#define MA_DR_MP3_SHORT_BLOCK_TYPE 2 -#define MA_DR_MP3_STOP_BLOCK_TYPE 3 -#define MA_DR_MP3_MODE_MONO 3 -#define MA_DR_MP3_MODE_JOINT_STEREO 1 -#define MA_DR_MP3_HDR_SIZE 4 -#define MA_DR_MP3_HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) -#define MA_DR_MP3_HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) -#define MA_DR_MP3_HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) -#define MA_DR_MP3_HDR_IS_CRC(h) (!((h[1]) & 1)) -#define MA_DR_MP3_HDR_TEST_PADDING(h) ((h[2]) & 0x2) -#define MA_DR_MP3_HDR_TEST_MPEG1(h) ((h[1]) & 0x8) -#define MA_DR_MP3_HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) -#define MA_DR_MP3_HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) -#define MA_DR_MP3_HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) -#define MA_DR_MP3_HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) -#define MA_DR_MP3_HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) -#define MA_DR_MP3_HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) -#define MA_DR_MP3_HDR_GET_BITRATE(h) ((h[2]) >> 4) -#define MA_DR_MP3_HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) -#define MA_DR_MP3_HDR_GET_MY_SAMPLE_RATE(h) (MA_DR_MP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) -#define MA_DR_MP3_HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) -#define MA_DR_MP3_HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) -#define MA_DR_MP3_BITS_DEQUANTIZER_OUT -1 -#define MA_DR_MP3_MAX_SCF (255 + MA_DR_MP3_BITS_DEQUANTIZER_OUT*4 - 210) -#define MA_DR_MP3_MAX_SCFI ((MA_DR_MP3_MAX_SCF + 3) & ~3) -#define MA_DR_MP3_MIN(a, b) ((a) > (b) ? (b) : (a)) -#define MA_DR_MP3_MAX(a, b) ((a) < (b) ? (b) : (a)) -#if !defined(MA_DR_MP3_NO_SIMD) -#if !defined(MA_DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) -#define MA_DR_MP3_ONLY_SIMD +#define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE +#define DRMP3_MAX_BITRESERVOIR_BYTES 511 +#define DRMP3_SHORT_BLOCK_TYPE 2 +#define DRMP3_STOP_BLOCK_TYPE 3 +#define DRMP3_MODE_MONO 3 +#define DRMP3_MODE_JOINT_STEREO 1 +#define DRMP3_HDR_SIZE 4 +#define DRMP3_HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) +#define DRMP3_HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) +#define DRMP3_HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) +#define DRMP3_HDR_IS_CRC(h) (!((h[1]) & 1)) +#define DRMP3_HDR_TEST_PADDING(h) ((h[2]) & 0x2) +#define DRMP3_HDR_TEST_MPEG1(h) ((h[1]) & 0x8) +#define DRMP3_HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) +#define DRMP3_HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) +#define DRMP3_HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) +#define DRMP3_HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) +#define DRMP3_HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) +#define DRMP3_HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) +#define DRMP3_HDR_GET_BITRATE(h) ((h[2]) >> 4) +#define DRMP3_HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) +#define DRMP3_HDR_GET_MY_SAMPLE_RATE(h) (DRMP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) +#define DRMP3_HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) +#define DRMP3_HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) +#define DRMP3_BITS_DEQUANTIZER_OUT -1 +#define DRMP3_MAX_SCF (255 + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210) +#define DRMP3_MAX_SCFI ((DRMP3_MAX_SCF + 3) & ~3) +#define DRMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define DRMP3_MAX(a, b) ((a) < (b) ? (b) : (a)) +#if !defined(DR_MP3_NO_SIMD) +#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) +#define DR_MP3_ONLY_SIMD #endif -#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__))) +#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) #if defined(_MSC_VER) #include #endif #include -#define MA_DR_MP3_HAVE_SSE 1 -#define MA_DR_MP3_HAVE_SIMD 1 -#define MA_DR_MP3_VSTORE _mm_storeu_ps -#define MA_DR_MP3_VLD _mm_loadu_ps -#define MA_DR_MP3_VSET _mm_set1_ps -#define MA_DR_MP3_VADD _mm_add_ps -#define MA_DR_MP3_VSUB _mm_sub_ps -#define MA_DR_MP3_VMUL _mm_mul_ps -#define MA_DR_MP3_VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) -#define MA_DR_MP3_VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) -#define MA_DR_MP3_VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) -#define MA_DR_MP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) -typedef __m128 ma_dr_mp3_f4; -#if defined(_MSC_VER) || defined(MA_DR_MP3_ONLY_SIMD) -#define ma_dr_mp3_cpuid __cpuid +#define DRMP3_HAVE_SSE 1 +#define DRMP3_HAVE_SIMD 1 +#define DRMP3_VSTORE _mm_storeu_ps +#define DRMP3_VLD _mm_loadu_ps +#define DRMP3_VSET _mm_set1_ps +#define DRMP3_VADD _mm_add_ps +#define DRMP3_VSUB _mm_sub_ps +#define DRMP3_VMUL _mm_mul_ps +#define DRMP3_VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) +#define DRMP3_VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) +#define DRMP3_VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) +#define DRMP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) +typedef __m128 drmp3_f4; +#if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD) +#define drmp3_cpuid __cpuid #else -static __inline__ __attribute__((always_inline)) void ma_dr_mp3_cpuid(int CPUInfo[], const int InfoType) +static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType) { #if defined(__PIC__) __asm__ __volatile__( @@ -90762,9 +61110,9 @@ static __inline__ __attribute__((always_inline)) void ma_dr_mp3_cpuid(int CPUInf #endif } #endif -static int ma_dr_mp3_have_simd(void) +static int drmp3_have_simd(void) { -#ifdef MA_DR_MP3_ONLY_SIMD +#ifdef DR_MP3_ONLY_SIMD return 1; #else static int g_have_simd; @@ -90776,10 +61124,10 @@ static int ma_dr_mp3_have_simd(void) #endif if (g_have_simd) goto end; - ma_dr_mp3_cpuid(CPUInfo, 0); + drmp3_cpuid(CPUInfo, 0); if (CPUInfo[0] > 0) { - ma_dr_mp3_cpuid(CPUInfo, 1); + drmp3_cpuid(CPUInfo, 1); g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; return g_have_simd - 1; } @@ -90787,110 +61135,87 @@ end: return g_have_simd - 1; #endif } -#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) #include -#define MA_DR_MP3_HAVE_SSE 0 -#define MA_DR_MP3_HAVE_SIMD 1 -#define MA_DR_MP3_VSTORE vst1q_f32 -#define MA_DR_MP3_VLD vld1q_f32 -#define MA_DR_MP3_VSET vmovq_n_f32 -#define MA_DR_MP3_VADD vaddq_f32 -#define MA_DR_MP3_VSUB vsubq_f32 -#define MA_DR_MP3_VMUL vmulq_f32 -#define MA_DR_MP3_VMAC(a, x, y) vmlaq_f32(a, x, y) -#define MA_DR_MP3_VMSB(a, x, y) vmlsq_f32(a, x, y) -#define MA_DR_MP3_VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) -#define MA_DR_MP3_VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) -typedef float32x4_t ma_dr_mp3_f4; -static int ma_dr_mp3_have_simd(void) +#define DRMP3_HAVE_SSE 0 +#define DRMP3_HAVE_SIMD 1 +#define DRMP3_VSTORE vst1q_f32 +#define DRMP3_VLD vld1q_f32 +#define DRMP3_VSET vmovq_n_f32 +#define DRMP3_VADD vaddq_f32 +#define DRMP3_VSUB vsubq_f32 +#define DRMP3_VMUL vmulq_f32 +#define DRMP3_VMAC(a, x, y) vmlaq_f32(a, x, y) +#define DRMP3_VMSB(a, x, y) vmlsq_f32(a, x, y) +#define DRMP3_VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) +#define DRMP3_VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) +typedef float32x4_t drmp3_f4; +static int drmp3_have_simd(void) { return 1; } #else -#define MA_DR_MP3_HAVE_SSE 0 -#define MA_DR_MP3_HAVE_SIMD 0 -#ifdef MA_DR_MP3_ONLY_SIMD -#error MA_DR_MP3_ONLY_SIMD used, but SSE/NEON not enabled +#define DRMP3_HAVE_SSE 0 +#define DRMP3_HAVE_SIMD 0 +#ifdef DR_MP3_ONLY_SIMD +#error DR_MP3_ONLY_SIMD used, but SSE/NEON not enabled #endif #endif #else -#define MA_DR_MP3_HAVE_SIMD 0 +#define DRMP3_HAVE_SIMD 0 #endif -#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) && !defined(__ARM_ARCH_6M__) -#define MA_DR_MP3_HAVE_ARMV6 1 -static __inline__ __attribute__((always_inline)) ma_int32 ma_dr_mp3_clip_int16_arm(ma_int32 a) +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) +#define DRMP3_HAVE_ARMV6 1 +static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(int32_t a) { - ma_int32 x = 0; + drmp3_int32 x = 0; __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); return x; } #else -#define MA_DR_MP3_HAVE_ARMV6 0 -#endif -#ifndef MA_DR_MP3_ASSERT -#include -#define MA_DR_MP3_ASSERT(expression) assert(expression) -#endif -#ifndef MA_DR_MP3_COPY_MEMORY -#define MA_DR_MP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) -#endif -#ifndef MA_DR_MP3_MOVE_MEMORY -#define MA_DR_MP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz)) -#endif -#ifndef MA_DR_MP3_ZERO_MEMORY -#define MA_DR_MP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) -#endif -#define MA_DR_MP3_ZERO_OBJECT(p) MA_DR_MP3_ZERO_MEMORY((p), sizeof(*(p))) -#ifndef MA_DR_MP3_MALLOC -#define MA_DR_MP3_MALLOC(sz) malloc((sz)) -#endif -#ifndef MA_DR_MP3_REALLOC -#define MA_DR_MP3_REALLOC(p, sz) realloc((p), (sz)) -#endif -#ifndef MA_DR_MP3_FREE -#define MA_DR_MP3_FREE(p) free((p)) +#define DRMP3_HAVE_ARMV6 0 #endif typedef struct { - const ma_uint8 *buf; + const drmp3_uint8 *buf; int pos, limit; -} ma_dr_mp3_bs; +} drmp3_bs; typedef struct { float scf[3*64]; - ma_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64]; -} ma_dr_mp3_L12_scale_info; + drmp3_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64]; +} drmp3_L12_scale_info; typedef struct { - ma_uint8 tab_offset, code_tab_width, band_count; -} ma_dr_mp3_L12_subband_alloc; + drmp3_uint8 tab_offset, code_tab_width, band_count; +} drmp3_L12_subband_alloc; typedef struct { - const ma_uint8 *sfbtab; - ma_uint16 part_23_length, big_values, scalefac_compress; - ma_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; - ma_uint8 table_select[3], region_count[3], subblock_gain[3]; - ma_uint8 preflag, scalefac_scale, count1_table, scfsi; -} ma_dr_mp3_L3_gr_info; + const drmp3_uint8 *sfbtab; + drmp3_uint16 part_23_length, big_values, scalefac_compress; + drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + drmp3_uint8 table_select[3], region_count[3], subblock_gain[3]; + drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi; +} drmp3_L3_gr_info; typedef struct { - ma_dr_mp3_bs bs; - ma_uint8 maindata[MA_DR_MP3_MAX_BITRESERVOIR_BYTES + MA_DR_MP3_MAX_L3_FRAME_PAYLOAD_BYTES]; - ma_dr_mp3_L3_gr_info gr_info[4]; + drmp3_bs bs; + drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES]; + drmp3_L3_gr_info gr_info[4]; float grbuf[2][576], scf[40], syn[18 + 15][2*32]; - ma_uint8 ist_pos[2][39]; -} ma_dr_mp3dec_scratch; -static void ma_dr_mp3_bs_init(ma_dr_mp3_bs *bs, const ma_uint8 *data, int bytes) + drmp3_uint8 ist_pos[2][39]; +} drmp3dec_scratch; +static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes) { bs->buf = data; bs->pos = 0; bs->limit = bytes*8; } -static ma_uint32 ma_dr_mp3_bs_get_bits(ma_dr_mp3_bs *bs, int n) +static drmp3_uint32 drmp3_bs_get_bits(drmp3_bs *bs, int n) { - ma_uint32 next, cache = 0, s = bs->pos & 7; + drmp3_uint32 next, cache = 0, s = bs->pos & 7; int shl = n + s; - const ma_uint8 *p = bs->buf + (bs->pos >> 3); + const drmp3_uint8 *p = bs->buf + (bs->pos >> 3); if ((bs->pos += n) > bs->limit) return 0; next = *p++ & (255 >> s); @@ -90901,72 +61226,72 @@ static ma_uint32 ma_dr_mp3_bs_get_bits(ma_dr_mp3_bs *bs, int n) } return cache | (next >> -shl); } -static int ma_dr_mp3_hdr_valid(const ma_uint8 *h) +static int drmp3_hdr_valid(const drmp3_uint8 *h) { return h[0] == 0xff && ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && - (MA_DR_MP3_HDR_GET_LAYER(h) != 0) && - (MA_DR_MP3_HDR_GET_BITRATE(h) != 15) && - (MA_DR_MP3_HDR_GET_SAMPLE_RATE(h) != 3); + (DRMP3_HDR_GET_LAYER(h) != 0) && + (DRMP3_HDR_GET_BITRATE(h) != 15) && + (DRMP3_HDR_GET_SAMPLE_RATE(h) != 3); } -static int ma_dr_mp3_hdr_compare(const ma_uint8 *h1, const ma_uint8 *h2) +static int drmp3_hdr_compare(const drmp3_uint8 *h1, const drmp3_uint8 *h2) { - return ma_dr_mp3_hdr_valid(h2) && + return drmp3_hdr_valid(h2) && ((h1[1] ^ h2[1]) & 0xFE) == 0 && ((h1[2] ^ h2[2]) & 0x0C) == 0 && - !(MA_DR_MP3_HDR_IS_FREE_FORMAT(h1) ^ MA_DR_MP3_HDR_IS_FREE_FORMAT(h2)); + !(DRMP3_HDR_IS_FREE_FORMAT(h1) ^ DRMP3_HDR_IS_FREE_FORMAT(h2)); } -static unsigned ma_dr_mp3_hdr_bitrate_kbps(const ma_uint8 *h) +static unsigned drmp3_hdr_bitrate_kbps(const drmp3_uint8 *h) { - static const ma_uint8 halfrate[2][3][15] = { + static const drmp3_uint8 halfrate[2][3][15] = { { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, }; - return 2*halfrate[!!MA_DR_MP3_HDR_TEST_MPEG1(h)][MA_DR_MP3_HDR_GET_LAYER(h) - 1][MA_DR_MP3_HDR_GET_BITRATE(h)]; + return 2*halfrate[!!DRMP3_HDR_TEST_MPEG1(h)][DRMP3_HDR_GET_LAYER(h) - 1][DRMP3_HDR_GET_BITRATE(h)]; } -static unsigned ma_dr_mp3_hdr_sample_rate_hz(const ma_uint8 *h) +static unsigned drmp3_hdr_sample_rate_hz(const drmp3_uint8 *h) { static const unsigned g_hz[3] = { 44100, 48000, 32000 }; - return g_hz[MA_DR_MP3_HDR_GET_SAMPLE_RATE(h)] >> (int)!MA_DR_MP3_HDR_TEST_MPEG1(h) >> (int)!MA_DR_MP3_HDR_TEST_NOT_MPEG25(h); + return g_hz[DRMP3_HDR_GET_SAMPLE_RATE(h)] >> (int)!DRMP3_HDR_TEST_MPEG1(h) >> (int)!DRMP3_HDR_TEST_NOT_MPEG25(h); } -static unsigned ma_dr_mp3_hdr_frame_samples(const ma_uint8 *h) +static unsigned drmp3_hdr_frame_samples(const drmp3_uint8 *h) { - return MA_DR_MP3_HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)MA_DR_MP3_HDR_IS_FRAME_576(h)); + return DRMP3_HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)DRMP3_HDR_IS_FRAME_576(h)); } -static int ma_dr_mp3_hdr_frame_bytes(const ma_uint8 *h, int free_format_size) +static int drmp3_hdr_frame_bytes(const drmp3_uint8 *h, int free_format_size) { - int frame_bytes = ma_dr_mp3_hdr_frame_samples(h)*ma_dr_mp3_hdr_bitrate_kbps(h)*125/ma_dr_mp3_hdr_sample_rate_hz(h); - if (MA_DR_MP3_HDR_IS_LAYER_1(h)) + int frame_bytes = drmp3_hdr_frame_samples(h)*drmp3_hdr_bitrate_kbps(h)*125/drmp3_hdr_sample_rate_hz(h); + if (DRMP3_HDR_IS_LAYER_1(h)) { frame_bytes &= ~3; } return frame_bytes ? frame_bytes : free_format_size; } -static int ma_dr_mp3_hdr_padding(const ma_uint8 *h) +static int drmp3_hdr_padding(const drmp3_uint8 *h) { - return MA_DR_MP3_HDR_TEST_PADDING(h) ? (MA_DR_MP3_HDR_IS_LAYER_1(h) ? 4 : 1) : 0; + return DRMP3_HDR_TEST_PADDING(h) ? (DRMP3_HDR_IS_LAYER_1(h) ? 4 : 1) : 0; } -#ifndef MA_DR_MP3_ONLY_MP3 -static const ma_dr_mp3_L12_subband_alloc *ma_dr_mp3_L12_subband_alloc_table(const ma_uint8 *hdr, ma_dr_mp3_L12_scale_info *sci) +#ifndef DR_MP3_ONLY_MP3 +static const drmp3_L12_subband_alloc *drmp3_L12_subband_alloc_table(const drmp3_uint8 *hdr, drmp3_L12_scale_info *sci) { - const ma_dr_mp3_L12_subband_alloc *alloc; - int mode = MA_DR_MP3_HDR_GET_STEREO_MODE(hdr); - int nbands, stereo_bands = (mode == MA_DR_MP3_MODE_MONO) ? 0 : (mode == MA_DR_MP3_MODE_JOINT_STEREO) ? (MA_DR_MP3_HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; - if (MA_DR_MP3_HDR_IS_LAYER_1(hdr)) + const drmp3_L12_subband_alloc *alloc; + int mode = DRMP3_HDR_GET_STEREO_MODE(hdr); + int nbands, stereo_bands = (mode == DRMP3_MODE_MONO) ? 0 : (mode == DRMP3_MODE_JOINT_STEREO) ? (DRMP3_HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; + if (DRMP3_HDR_IS_LAYER_1(hdr)) { - static const ma_dr_mp3_L12_subband_alloc g_alloc_L1[] = { { 76, 4, 32 } }; + static const drmp3_L12_subband_alloc g_alloc_L1[] = { { 76, 4, 32 } }; alloc = g_alloc_L1; nbands = 32; - } else if (!MA_DR_MP3_HDR_TEST_MPEG1(hdr)) + } else if (!DRMP3_HDR_TEST_MPEG1(hdr)) { - static const ma_dr_mp3_L12_subband_alloc g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; + static const drmp3_L12_subband_alloc g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; alloc = g_alloc_L2M2; nbands = 30; } else { - static const ma_dr_mp3_L12_subband_alloc g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; - int sample_rate_idx = MA_DR_MP3_HDR_GET_SAMPLE_RATE(hdr); - unsigned kbps = ma_dr_mp3_hdr_bitrate_kbps(hdr) >> (int)(mode != MA_DR_MP3_MODE_MONO); + static const drmp3_L12_subband_alloc g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; + int sample_rate_idx = DRMP3_HDR_GET_SAMPLE_RATE(hdr); + unsigned kbps = drmp3_hdr_bitrate_kbps(hdr) >> (int)(mode != DRMP3_MODE_MONO); if (!kbps) { kbps = 192; @@ -90975,7 +61300,7 @@ static const ma_dr_mp3_L12_subband_alloc *ma_dr_mp3_L12_subband_alloc_table(cons nbands = 27; if (kbps < 56) { - static const ma_dr_mp3_L12_subband_alloc g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; + static const drmp3_L12_subband_alloc g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; alloc = g_alloc_L2M1_lowrate; nbands = sample_rate_idx == 2 ? 12 : 8; } else if (kbps >= 96 && sample_rate_idx != 1) @@ -90983,15 +61308,15 @@ static const ma_dr_mp3_L12_subband_alloc *ma_dr_mp3_L12_subband_alloc_table(cons nbands = 30; } } - sci->total_bands = (ma_uint8)nbands; - sci->stereo_bands = (ma_uint8)MA_DR_MP3_MIN(stereo_bands, nbands); + sci->total_bands = (drmp3_uint8)nbands; + sci->stereo_bands = (drmp3_uint8)DRMP3_MIN(stereo_bands, nbands); return alloc; } -static void ma_dr_mp3_L12_read_scalefactors(ma_dr_mp3_bs *bs, ma_uint8 *pba, ma_uint8 *scfcod, int bands, float *scf) +static void drmp3_L12_read_scalefactors(drmp3_bs *bs, drmp3_uint8 *pba, drmp3_uint8 *scfcod, int bands, float *scf) { static const float g_deq_L12[18*3] = { -#define MA_DR_MP3_DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x - MA_DR_MP3_DQ(3),MA_DR_MP3_DQ(7),MA_DR_MP3_DQ(15),MA_DR_MP3_DQ(31),MA_DR_MP3_DQ(63),MA_DR_MP3_DQ(127),MA_DR_MP3_DQ(255),MA_DR_MP3_DQ(511),MA_DR_MP3_DQ(1023),MA_DR_MP3_DQ(2047),MA_DR_MP3_DQ(4095),MA_DR_MP3_DQ(8191),MA_DR_MP3_DQ(16383),MA_DR_MP3_DQ(32767),MA_DR_MP3_DQ(65535),MA_DR_MP3_DQ(3),MA_DR_MP3_DQ(5),MA_DR_MP3_DQ(9) +#define DRMP3_DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x + DRMP3_DQ(3),DRMP3_DQ(7),DRMP3_DQ(15),DRMP3_DQ(31),DRMP3_DQ(63),DRMP3_DQ(127),DRMP3_DQ(255),DRMP3_DQ(511),DRMP3_DQ(1023),DRMP3_DQ(2047),DRMP3_DQ(4095),DRMP3_DQ(8191),DRMP3_DQ(16383),DRMP3_DQ(32767),DRMP3_DQ(65535),DRMP3_DQ(3),DRMP3_DQ(5),DRMP3_DQ(9) }; int i, m; for (i = 0; i < bands; i++) @@ -91003,16 +61328,16 @@ static void ma_dr_mp3_L12_read_scalefactors(ma_dr_mp3_bs *bs, ma_uint8 *pba, ma_ { if (mask & m) { - int b = ma_dr_mp3_bs_get_bits(bs, 6); + int b = drmp3_bs_get_bits(bs, 6); s = g_deq_L12[ba*3 - 6 + b % 3]*(int)(1 << 21 >> b/3); } *scf++ = s; } } } -static void ma_dr_mp3_L12_read_scale_info(const ma_uint8 *hdr, ma_dr_mp3_bs *bs, ma_dr_mp3_L12_scale_info *sci) +static void drmp3_L12_read_scale_info(const drmp3_uint8 *hdr, drmp3_bs *bs, drmp3_L12_scale_info *sci) { - static const ma_uint8 g_bitalloc_code_tab[] = { + static const drmp3_uint8 g_bitalloc_code_tab[] = { 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16, 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16, 0,17,18, 3,19,4,5,16, @@ -91021,12 +61346,12 @@ static void ma_dr_mp3_L12_read_scale_info(const ma_uint8 *hdr, ma_dr_mp3_bs *bs, 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 }; - const ma_dr_mp3_L12_subband_alloc *subband_alloc = ma_dr_mp3_L12_subband_alloc_table(hdr, sci); + const drmp3_L12_subband_alloc *subband_alloc = drmp3_L12_subband_alloc_table(hdr, sci); int i, k = 0, ba_bits = 0; - const ma_uint8 *ba_code_tab = g_bitalloc_code_tab; + const drmp3_uint8 *ba_code_tab = g_bitalloc_code_tab; for (i = 0; i < sci->total_bands; i++) { - ma_uint8 ba; + drmp3_uint8 ba; if (i == k) { k += subband_alloc->band_count; @@ -91034,25 +61359,25 @@ static void ma_dr_mp3_L12_read_scale_info(const ma_uint8 *hdr, ma_dr_mp3_bs *bs, ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset; subband_alloc++; } - ba = ba_code_tab[ma_dr_mp3_bs_get_bits(bs, ba_bits)]; + ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)]; sci->bitalloc[2*i] = ba; if (i < sci->stereo_bands) { - ba = ba_code_tab[ma_dr_mp3_bs_get_bits(bs, ba_bits)]; + ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)]; } sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; } for (i = 0; i < 2*sci->total_bands; i++) { - sci->scfcod[i] = (ma_uint8)(sci->bitalloc[i] ? MA_DR_MP3_HDR_IS_LAYER_1(hdr) ? 2 : ma_dr_mp3_bs_get_bits(bs, 2) : 6); + sci->scfcod[i] = (drmp3_uint8)(sci->bitalloc[i] ? DRMP3_HDR_IS_LAYER_1(hdr) ? 2 : drmp3_bs_get_bits(bs, 2) : 6); } - ma_dr_mp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); + drmp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); for (i = sci->stereo_bands; i < sci->total_bands; i++) { sci->bitalloc[2*i + 1] = 0; } } -static int ma_dr_mp3_L12_dequantize_granule(float *grbuf, ma_dr_mp3_bs *bs, ma_dr_mp3_L12_scale_info *sci, int group_size) +static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_scale_info *sci, int group_size) { int i, j, k, choff = 576; for (j = 0; j < 4; j++) @@ -91068,12 +61393,12 @@ static int ma_dr_mp3_L12_dequantize_granule(float *grbuf, ma_dr_mp3_bs *bs, ma_d int half = (1 << (ba - 1)) - 1; for (k = 0; k < group_size; k++) { - dst[k] = (float)((int)ma_dr_mp3_bs_get_bits(bs, ba) - half); + dst[k] = (float)((int)drmp3_bs_get_bits(bs, ba) - half); } } else { unsigned mod = (2 << (ba - 17)) + 1; - unsigned code = ma_dr_mp3_bs_get_bits(bs, mod + 2 - (mod >> 3)); + unsigned code = drmp3_bs_get_bits(bs, mod + 2 - (mod >> 3)); for (k = 0; k < group_size; k++, code /= mod) { dst[k] = (float)((int)(code % mod - mod/2)); @@ -91086,10 +61411,10 @@ static int ma_dr_mp3_L12_dequantize_granule(float *grbuf, ma_dr_mp3_bs *bs, ma_d } return group_size*4; } -static void ma_dr_mp3_L12_apply_scf_384(ma_dr_mp3_L12_scale_info *sci, const float *scf, float *dst) +static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst) { int i, k; - MA_DR_MP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) { for (k = 0; k < 12; k++) @@ -91100,9 +61425,9 @@ static void ma_dr_mp3_L12_apply_scf_384(ma_dr_mp3_L12_scale_info *sci, const flo } } #endif -static int ma_dr_mp3_L3_read_side_info(ma_dr_mp3_bs *bs, ma_dr_mp3_L3_gr_info *gr, const ma_uint8 *hdr) +static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr) { - static const ma_uint8 g_scf_long[8][23] = { + static const drmp3_uint8 g_scf_long[8][23] = { { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 }, { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, @@ -91112,7 +61437,7 @@ static int ma_dr_mp3_L3_read_side_info(ma_dr_mp3_bs *bs, ma_dr_mp3_L3_gr_info *g { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 }, { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 } }; - static const ma_uint8 g_scf_short[8][40] = { + static const drmp3_uint8 g_scf_short[8][40] = { { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, @@ -91122,7 +61447,7 @@ static int ma_dr_mp3_L3_read_side_info(ma_dr_mp3_bs *bs, ma_dr_mp3_L3_gr_info *g { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } }; - static const ma_uint8 g_scf_mixed[8][40] = { + static const drmp3_uint8 g_scf_mixed[8][40] = { { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, @@ -91134,46 +61459,46 @@ static int ma_dr_mp3_L3_read_side_info(ma_dr_mp3_bs *bs, ma_dr_mp3_L3_gr_info *g }; unsigned tables, scfsi = 0; int main_data_begin, part_23_sum = 0; - int gr_count = MA_DR_MP3_HDR_IS_MONO(hdr) ? 1 : 2; - int sr_idx = MA_DR_MP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); - if (MA_DR_MP3_HDR_TEST_MPEG1(hdr)) + int gr_count = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2; + int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); + if (DRMP3_HDR_TEST_MPEG1(hdr)) { gr_count *= 2; - main_data_begin = ma_dr_mp3_bs_get_bits(bs, 9); - scfsi = ma_dr_mp3_bs_get_bits(bs, 7 + gr_count); + main_data_begin = drmp3_bs_get_bits(bs, 9); + scfsi = drmp3_bs_get_bits(bs, 7 + gr_count); } else { - main_data_begin = ma_dr_mp3_bs_get_bits(bs, 8 + gr_count) >> gr_count; + main_data_begin = drmp3_bs_get_bits(bs, 8 + gr_count) >> gr_count; } do { - if (MA_DR_MP3_HDR_IS_MONO(hdr)) + if (DRMP3_HDR_IS_MONO(hdr)) { scfsi <<= 4; } - gr->part_23_length = (ma_uint16)ma_dr_mp3_bs_get_bits(bs, 12); + gr->part_23_length = (drmp3_uint16)drmp3_bs_get_bits(bs, 12); part_23_sum += gr->part_23_length; - gr->big_values = (ma_uint16)ma_dr_mp3_bs_get_bits(bs, 9); + gr->big_values = (drmp3_uint16)drmp3_bs_get_bits(bs, 9); if (gr->big_values > 288) { return -1; } - gr->global_gain = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 8); - gr->scalefac_compress = (ma_uint16)ma_dr_mp3_bs_get_bits(bs, MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 4 : 9); + gr->global_gain = (drmp3_uint8)drmp3_bs_get_bits(bs, 8); + gr->scalefac_compress = (drmp3_uint16)drmp3_bs_get_bits(bs, DRMP3_HDR_TEST_MPEG1(hdr) ? 4 : 9); gr->sfbtab = g_scf_long[sr_idx]; gr->n_long_sfb = 22; gr->n_short_sfb = 0; - if (ma_dr_mp3_bs_get_bits(bs, 1)) + if (drmp3_bs_get_bits(bs, 1)) { - gr->block_type = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 2); + gr->block_type = (drmp3_uint8)drmp3_bs_get_bits(bs, 2); if (!gr->block_type) { return -1; } - gr->mixed_block_flag = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 1); + gr->mixed_block_flag = (drmp3_uint8)drmp3_bs_get_bits(bs, 1); gr->region_count[0] = 7; gr->region_count[1] = 255; - if (gr->block_type == MA_DR_MP3_SHORT_BLOCK_TYPE) + if (gr->block_type == DRMP3_SHORT_BLOCK_TYPE) { scfsi &= 0x0F0F; if (!gr->mixed_block_flag) @@ -91185,31 +61510,31 @@ static int ma_dr_mp3_L3_read_side_info(ma_dr_mp3_bs *bs, ma_dr_mp3_L3_gr_info *g } else { gr->sfbtab = g_scf_mixed[sr_idx]; - gr->n_long_sfb = MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 8 : 6; + gr->n_long_sfb = DRMP3_HDR_TEST_MPEG1(hdr) ? 8 : 6; gr->n_short_sfb = 30; } } - tables = ma_dr_mp3_bs_get_bits(bs, 10); + tables = drmp3_bs_get_bits(bs, 10); tables <<= 5; - gr->subblock_gain[0] = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 3); - gr->subblock_gain[1] = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 3); - gr->subblock_gain[2] = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 3); + gr->subblock_gain[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3); + gr->subblock_gain[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3); + gr->subblock_gain[2] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3); } else { gr->block_type = 0; gr->mixed_block_flag = 0; - tables = ma_dr_mp3_bs_get_bits(bs, 15); - gr->region_count[0] = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 4); - gr->region_count[1] = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 3); + tables = drmp3_bs_get_bits(bs, 15); + gr->region_count[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 4); + gr->region_count[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3); gr->region_count[2] = 255; } - gr->table_select[0] = (ma_uint8)(tables >> 10); - gr->table_select[1] = (ma_uint8)((tables >> 5) & 31); - gr->table_select[2] = (ma_uint8)((tables) & 31); - gr->preflag = (ma_uint8)(MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? ma_dr_mp3_bs_get_bits(bs, 1) : (gr->scalefac_compress >= 500)); - gr->scalefac_scale = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 1); - gr->count1_table = (ma_uint8)ma_dr_mp3_bs_get_bits(bs, 1); - gr->scfsi = (ma_uint8)((scfsi >> 12) & 15); + gr->table_select[0] = (drmp3_uint8)(tables >> 10); + gr->table_select[1] = (drmp3_uint8)((tables >> 5) & 31); + gr->table_select[2] = (drmp3_uint8)((tables) & 31); + gr->preflag = (drmp3_uint8)(DRMP3_HDR_TEST_MPEG1(hdr) ? drmp3_bs_get_bits(bs, 1) : (gr->scalefac_compress >= 500)); + gr->scalefac_scale = (drmp3_uint8)drmp3_bs_get_bits(bs, 1); + gr->count1_table = (drmp3_uint8)drmp3_bs_get_bits(bs, 1); + gr->scfsi = (drmp3_uint8)((scfsi >> 12) & 15); scfsi <<= 4; gr++; } while(--gr_count); @@ -91219,7 +61544,7 @@ static int ma_dr_mp3_L3_read_side_info(ma_dr_mp3_bs *bs, ma_dr_mp3_L3_gr_info *g } return main_data_begin; } -static void ma_dr_mp3_L3_read_scalefactors(ma_uint8 *scf, ma_uint8 *ist_pos, const ma_uint8 *scf_size, const ma_uint8 *scf_count, ma_dr_mp3_bs *bitbuf, int scfsi) +static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, const drmp3_uint8 *scf_size, const drmp3_uint8 *scf_count, drmp3_bs *bitbuf, int scfsi) { int i, k; for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) @@ -91227,22 +61552,22 @@ static void ma_dr_mp3_L3_read_scalefactors(ma_uint8 *scf, ma_uint8 *ist_pos, con int cnt = scf_count[i]; if (scfsi & 8) { - MA_DR_MP3_COPY_MEMORY(scf, ist_pos, cnt); + memcpy(scf, ist_pos, cnt); } else { int bits = scf_size[i]; if (!bits) { - MA_DR_MP3_ZERO_MEMORY(scf, cnt); - MA_DR_MP3_ZERO_MEMORY(ist_pos, cnt); + memset(scf, 0, cnt); + memset(ist_pos, 0, cnt); } else { int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; for (k = 0; k < cnt; k++) { - int s = ma_dr_mp3_bs_get_bits(bitbuf, bits); - ist_pos[k] = (ma_uint8)(s == max_scf ? -1 : s); - scf[k] = (ma_uint8)s; + int s = drmp3_bs_get_bits(bitbuf, bits); + ist_pos[k] = (drmp3_uint8)(s == max_scf ? -1 : s); + scf[k] = (drmp3_uint8)s; } } } @@ -91251,86 +61576,86 @@ static void ma_dr_mp3_L3_read_scalefactors(ma_uint8 *scf, ma_uint8 *ist_pos, con } scf[0] = scf[1] = scf[2] = 0; } -static float ma_dr_mp3_L3_ldexp_q2(float y, int exp_q2) +static float drmp3_L3_ldexp_q2(float y, int exp_q2) { static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f }; int e; do { - e = MA_DR_MP3_MIN(30*4, exp_q2); + e = DRMP3_MIN(30*4, exp_q2); y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2)); } while ((exp_q2 -= e) > 0); return y; } -static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_pos, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr, float *scf, int ch) +static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *ist_pos, drmp3_bs *bs, const drmp3_L3_gr_info *gr, float *scf, int ch) { - static const ma_uint8 g_scf_partitions[3][28] = { + static const drmp3_uint8 g_scf_partitions[3][28] = { { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 }, { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 }, { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 } }; - const ma_uint8 *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; - ma_uint8 scf_size[4], iscf[40]; + const drmp3_uint8 *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; + drmp3_uint8 scf_size[4], iscf[40]; int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; float gain; - if (MA_DR_MP3_HDR_TEST_MPEG1(hdr)) + if (DRMP3_HDR_TEST_MPEG1(hdr)) { - static const ma_uint8 g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; + static const drmp3_uint8 g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; int part = g_scfc_decode[gr->scalefac_compress]; - scf_size[1] = scf_size[0] = (ma_uint8)(part >> 2); - scf_size[3] = scf_size[2] = (ma_uint8)(part & 3); + scf_size[1] = scf_size[0] = (drmp3_uint8)(part >> 2); + scf_size[3] = scf_size[2] = (drmp3_uint8)(part & 3); } else { - static const ma_uint8 g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; - int k, modprod, sfc, ist = MA_DR_MP3_HDR_TEST_I_STEREO(hdr) && ch; + static const drmp3_uint8 g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; + int k, modprod, sfc, ist = DRMP3_HDR_TEST_I_STEREO(hdr) && ch; sfc = gr->scalefac_compress >> ist; for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) { for (modprod = 1, i = 3; i >= 0; i--) { - scf_size[i] = (ma_uint8)(sfc / modprod % g_mod[k + i]); + scf_size[i] = (drmp3_uint8)(sfc / modprod % g_mod[k + i]); modprod *= g_mod[k + i]; } } scf_partition += k; scfsi = -16; } - ma_dr_mp3_L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); + drmp3_L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); if (gr->n_short_sfb) { int sh = 3 - scf_shift; for (i = 0; i < gr->n_short_sfb; i += 3) { - iscf[gr->n_long_sfb + i + 0] = (ma_uint8)(iscf[gr->n_long_sfb + i + 0] + (gr->subblock_gain[0] << sh)); - iscf[gr->n_long_sfb + i + 1] = (ma_uint8)(iscf[gr->n_long_sfb + i + 1] + (gr->subblock_gain[1] << sh)); - iscf[gr->n_long_sfb + i + 2] = (ma_uint8)(iscf[gr->n_long_sfb + i + 2] + (gr->subblock_gain[2] << sh)); + iscf[gr->n_long_sfb + i + 0] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 0] + (gr->subblock_gain[0] << sh)); + iscf[gr->n_long_sfb + i + 1] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 1] + (gr->subblock_gain[1] << sh)); + iscf[gr->n_long_sfb + i + 2] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 2] + (gr->subblock_gain[2] << sh)); } } else if (gr->preflag) { - static const ma_uint8 g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; + static const drmp3_uint8 g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; for (i = 0; i < 10; i++) { - iscf[11 + i] = (ma_uint8)(iscf[11 + i] + g_preamp[i]); + iscf[11 + i] = (drmp3_uint8)(iscf[11 + i] + g_preamp[i]); } } - gain_exp = gr->global_gain + MA_DR_MP3_BITS_DEQUANTIZER_OUT*4 - 210 - (MA_DR_MP3_HDR_IS_MS_STEREO(hdr) ? 2 : 0); - gain = ma_dr_mp3_L3_ldexp_q2(1 << (MA_DR_MP3_MAX_SCFI/4), MA_DR_MP3_MAX_SCFI - gain_exp); + gain_exp = gr->global_gain + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210 - (DRMP3_HDR_IS_MS_STEREO(hdr) ? 2 : 0); + gain = drmp3_L3_ldexp_q2(1 << (DRMP3_MAX_SCFI/4), DRMP3_MAX_SCFI - gain_exp); for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++) { - scf[i] = ma_dr_mp3_L3_ldexp_q2(gain, iscf[i] << scf_shift); + scf[i] = drmp3_L3_ldexp_q2(gain, iscf[i] << scf_shift); } } -static const float g_ma_dr_mp3_pow43[129 + 16] = { +static const float g_drmp3_pow43[129 + 16] = { 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f }; -static float ma_dr_mp3_L3_pow_43(int x) +static float drmp3_L3_pow_43(int x) { float frac; int sign, mult = 256; if (x < 129) { - return g_ma_dr_mp3_pow43[16 + x]; + return g_drmp3_pow43[16 + x]; } if (x < 1024) { @@ -91339,11 +61664,11 @@ static float ma_dr_mp3_L3_pow_43(int x) } sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_ma_dr_mp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; + return g_drmp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } -static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) +static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { - static const ma_int16 tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + static const drmp3_int16 tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288, @@ -91359,61 +61684,61 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259, -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258, -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 }; - static const ma_uint8 tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205}; - static const ma_uint8 tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; - static const ma_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; - static const ma_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; -#define MA_DR_MP3_PEEK_BITS(n) (bs_cache >> (32 - (n))) -#define MA_DR_MP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } -#define MA_DR_MP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (ma_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } -#define MA_DR_MP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) + static const drmp3_uint8 tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205}; + static const drmp3_uint8 tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; + static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; + static const drmp3_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; +#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - n)) +#define DRMP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } +#define DRMP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } +#define DRMP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) float one = 0.0f; int ireg = 0, big_val_cnt = gr_info->big_values; - const ma_uint8 *sfb = gr_info->sfbtab; - const ma_uint8 *bs_next_ptr = bs->buf + bs->pos/8; - ma_uint32 bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); + const drmp3_uint8 *sfb = gr_info->sfbtab; + const drmp3_uint8 *bs_next_ptr = bs->buf + bs->pos/8; + drmp3_uint32 bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8; bs_next_ptr += 4; while (big_val_cnt > 0) { int tab_num = gr_info->table_select[ireg]; int sfb_cnt = gr_info->region_count[ireg++]; - const ma_int16 *codebook = tabs + tabindex[tab_num]; + const drmp3_int16 *codebook = tabs + tabindex[tab_num]; int linbits = g_linbits[tab_num]; if (linbits) { do { np = *sfb++ / 2; - pairs_to_decode = MA_DR_MP3_MIN(big_val_cnt, np); + pairs_to_decode = DRMP3_MIN(big_val_cnt, np); one = *scf++; do { int j, w = 5; - int leaf = codebook[MA_DR_MP3_PEEK_BITS(w)]; + int leaf = codebook[DRMP3_PEEK_BITS(w)]; while (leaf < 0) { - MA_DR_MP3_FLUSH_BITS(w); + DRMP3_FLUSH_BITS(w); w = leaf & 7; - leaf = codebook[MA_DR_MP3_PEEK_BITS(w) - (leaf >> 3)]; + leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; } - MA_DR_MP3_FLUSH_BITS(leaf >> 8); + DRMP3_FLUSH_BITS(leaf >> 8); for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; if (lsb == 15) { - lsb += MA_DR_MP3_PEEK_BITS(linbits); - MA_DR_MP3_FLUSH_BITS(linbits); - MA_DR_MP3_CHECK_BITS; - *dst = one*ma_dr_mp3_L3_pow_43(lsb)*((ma_int32)bs_cache < 0 ? -1: 1); + lsb += DRMP3_PEEK_BITS(linbits); + DRMP3_FLUSH_BITS(linbits); + DRMP3_CHECK_BITS; + *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1); } else { - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; } - MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); + DRMP3_FLUSH_BITS(lsb ? 1 : 0); } - MA_DR_MP3_CHECK_BITS; + DRMP3_CHECK_BITS; } while (--pairs_to_decode); } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); } else @@ -91421,73 +61746,66 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L do { np = *sfb++ / 2; - pairs_to_decode = MA_DR_MP3_MIN(big_val_cnt, np); + pairs_to_decode = DRMP3_MIN(big_val_cnt, np); one = *scf++; do { int j, w = 5; - int leaf = codebook[MA_DR_MP3_PEEK_BITS(w)]; + int leaf = codebook[DRMP3_PEEK_BITS(w)]; while (leaf < 0) { - MA_DR_MP3_FLUSH_BITS(w); + DRMP3_FLUSH_BITS(w); w = leaf & 7; - leaf = codebook[MA_DR_MP3_PEEK_BITS(w) - (leaf >> 3)]; + leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; } - MA_DR_MP3_FLUSH_BITS(leaf >> 8); + DRMP3_FLUSH_BITS(leaf >> 8); for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; - MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); + *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + DRMP3_FLUSH_BITS(lsb ? 1 : 0); } - MA_DR_MP3_CHECK_BITS; + DRMP3_CHECK_BITS; } while (--pairs_to_decode); } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); } } for (np = 1 - big_val_cnt;; dst += 4) { - const ma_uint8 *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; - int leaf = codebook_count1[MA_DR_MP3_PEEK_BITS(4)]; + const drmp3_uint8 *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; + int leaf = codebook_count1[DRMP3_PEEK_BITS(4)]; if (!(leaf & 8)) { leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))]; } - MA_DR_MP3_FLUSH_BITS(leaf & 7); - if (MA_DR_MP3_BSPOS > layer3gr_limit) + DRMP3_FLUSH_BITS(leaf & 7); + if (DRMP3_BSPOS > layer3gr_limit) { break; } -#define MA_DR_MP3_RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } -#define MA_DR_MP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((ma_int32)bs_cache < 0) ? -one : one; MA_DR_MP3_FLUSH_BITS(1) } - MA_DR_MP3_RELOAD_SCALEFACTOR; - MA_DR_MP3_DEQ_COUNT1(0); - MA_DR_MP3_DEQ_COUNT1(1); - MA_DR_MP3_RELOAD_SCALEFACTOR; - MA_DR_MP3_DEQ_COUNT1(2); - MA_DR_MP3_DEQ_COUNT1(3); - MA_DR_MP3_CHECK_BITS; +#define DRMP3_RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } +#define DRMP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((drmp3_int32)bs_cache < 0) ? -one : one; DRMP3_FLUSH_BITS(1) } + DRMP3_RELOAD_SCALEFACTOR; + DRMP3_DEQ_COUNT1(0); + DRMP3_DEQ_COUNT1(1); + DRMP3_RELOAD_SCALEFACTOR; + DRMP3_DEQ_COUNT1(2); + DRMP3_DEQ_COUNT1(3); + DRMP3_CHECK_BITS; } bs->pos = layer3gr_limit; } -static void ma_dr_mp3_L3_midside_stereo(float *left, int n) +static void drmp3_L3_midside_stereo(float *left, int n) { int i = 0; float *right = left + 576; -#if MA_DR_MP3_HAVE_SIMD - if (ma_dr_mp3_have_simd()) +#if DRMP3_HAVE_SIMD + if (drmp3_have_simd()) for (; i < n - 3; i += 4) { - for (; i < n - 3; i += 4) - { - ma_dr_mp3_f4 vl = MA_DR_MP3_VLD(left + i); - ma_dr_mp3_f4 vr = MA_DR_MP3_VLD(right + i); - MA_DR_MP3_VSTORE(left + i, MA_DR_MP3_VADD(vl, vr)); - MA_DR_MP3_VSTORE(right + i, MA_DR_MP3_VSUB(vl, vr)); - } -#ifdef __GNUC__ - if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0) - return; -#endif + drmp3_f4 vl = DRMP3_VLD(left + i); + drmp3_f4 vr = DRMP3_VLD(right + i); + DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); + DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); } #endif for (; i < n; i++) @@ -91498,7 +61816,7 @@ static void ma_dr_mp3_L3_midside_stereo(float *left, int n) right[i] = a - b; } } -static void ma_dr_mp3_L3_intensity_stereo_band(float *left, int n, float kl, float kr) +static void drmp3_L3_intensity_stereo_band(float *left, int n, float kl, float kr) { int i; for (i = 0; i < n; i++) @@ -91507,7 +61825,7 @@ static void ma_dr_mp3_L3_intensity_stereo_band(float *left, int n, float kl, flo left[i] = left[i]*kl; } } -static void ma_dr_mp3_L3_stereo_top_band(const float *right, const ma_uint8 *sfb, int nbands, int max_band[3]) +static void drmp3_L3_stereo_top_band(const float *right, const drmp3_uint8 *sfb, int nbands, int max_band[3]) { int i, k; max_band[0] = max_band[1] = max_band[2] = -1; @@ -91524,57 +61842,57 @@ static void ma_dr_mp3_L3_stereo_top_band(const float *right, const ma_uint8 *sfb right += sfb[i]; } } -static void ma_dr_mp3_L3_stereo_process(float *left, const ma_uint8 *ist_pos, const ma_uint8 *sfb, const ma_uint8 *hdr, int max_band[3], int mpeg2_sh) +static void drmp3_L3_stereo_process(float *left, const drmp3_uint8 *ist_pos, const drmp3_uint8 *sfb, const drmp3_uint8 *hdr, int max_band[3], int mpeg2_sh) { static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; - unsigned i, max_pos = MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 7 : 64; + unsigned i, max_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 7 : 64; for (i = 0; sfb[i]; i++) { unsigned ipos = ist_pos[i]; if ((int)i > max_band[i % 3] && ipos < max_pos) { - float kl, kr, s = MA_DR_MP3_HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; - if (MA_DR_MP3_HDR_TEST_MPEG1(hdr)) + float kl, kr, s = DRMP3_HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; + if (DRMP3_HDR_TEST_MPEG1(hdr)) { kl = g_pan[2*ipos]; kr = g_pan[2*ipos + 1]; } else { kl = 1; - kr = ma_dr_mp3_L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); + kr = drmp3_L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); if (ipos & 1) { kl = kr; kr = 1; } } - ma_dr_mp3_L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); - } else if (MA_DR_MP3_HDR_TEST_MS_STEREO(hdr)) + drmp3_L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); + } else if (DRMP3_HDR_TEST_MS_STEREO(hdr)) { - ma_dr_mp3_L3_midside_stereo(left, sfb[i]); + drmp3_L3_midside_stereo(left, sfb[i]); } left += sfb[i]; } } -static void ma_dr_mp3_L3_intensity_stereo(float *left, ma_uint8 *ist_pos, const ma_dr_mp3_L3_gr_info *gr, const ma_uint8 *hdr) +static void drmp3_L3_intensity_stereo(float *left, drmp3_uint8 *ist_pos, const drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr) { int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb; int i, max_blocks = gr->n_short_sfb ? 3 : 1; - ma_dr_mp3_L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); + drmp3_L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); if (gr->n_long_sfb) { - max_band[0] = max_band[1] = max_band[2] = MA_DR_MP3_MAX(MA_DR_MP3_MAX(max_band[0], max_band[1]), max_band[2]); + max_band[0] = max_band[1] = max_band[2] = DRMP3_MAX(DRMP3_MAX(max_band[0], max_band[1]), max_band[2]); } for (i = 0; i < max_blocks; i++) { - int default_pos = MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 3 : 0; + int default_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 3 : 0; int itop = n_sfb - max_blocks + i; int prev = itop - max_blocks; - ist_pos[itop] = (ma_uint8)(max_band[i] >= prev ? default_pos : ist_pos[prev]); + ist_pos[itop] = (drmp3_uint8)(max_band[i] >= prev ? default_pos : ist_pos[prev]); } - ma_dr_mp3_L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); + drmp3_L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); } -static void ma_dr_mp3_L3_reorder(float *grbuf, float *scratch, const ma_uint8 *sfb) +static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sfb) { int i, len; float *src = grbuf, *dst = scratch; @@ -91587,9 +61905,9 @@ static void ma_dr_mp3_L3_reorder(float *grbuf, float *scratch, const ma_uint8 *s *dst++ = src[2*len]; } } - MA_DR_MP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float)); + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); } -static void ma_dr_mp3_L3_antialias(float *grbuf, int nbands) +static void drmp3_L3_antialias(float *grbuf, int nbands) { static const float g_aa[2][8] = { {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f}, @@ -91598,20 +61916,20 @@ static void ma_dr_mp3_L3_antialias(float *grbuf, int nbands) for (; nbands > 0; nbands--, grbuf += 18) { int i = 0; -#if MA_DR_MP3_HAVE_SIMD - if (ma_dr_mp3_have_simd()) for (; i < 8; i += 4) +#if DRMP3_HAVE_SIMD + if (drmp3_have_simd()) for (; i < 8; i += 4) { - ma_dr_mp3_f4 vu = MA_DR_MP3_VLD(grbuf + 18 + i); - ma_dr_mp3_f4 vd = MA_DR_MP3_VLD(grbuf + 14 - i); - ma_dr_mp3_f4 vc0 = MA_DR_MP3_VLD(g_aa[0] + i); - ma_dr_mp3_f4 vc1 = MA_DR_MP3_VLD(g_aa[1] + i); - vd = MA_DR_MP3_VREV(vd); - MA_DR_MP3_VSTORE(grbuf + 18 + i, MA_DR_MP3_VSUB(MA_DR_MP3_VMUL(vu, vc0), MA_DR_MP3_VMUL(vd, vc1))); - vd = MA_DR_MP3_VADD(MA_DR_MP3_VMUL(vu, vc1), MA_DR_MP3_VMUL(vd, vc0)); - MA_DR_MP3_VSTORE(grbuf + 14 - i, MA_DR_MP3_VREV(vd)); + drmp3_f4 vu = DRMP3_VLD(grbuf + 18 + i); + drmp3_f4 vd = DRMP3_VLD(grbuf + 14 - i); + drmp3_f4 vc0 = DRMP3_VLD(g_aa[0] + i); + drmp3_f4 vc1 = DRMP3_VLD(g_aa[1] + i); + vd = DRMP3_VREV(vd); + DRMP3_VSTORE(grbuf + 18 + i, DRMP3_VSUB(DRMP3_VMUL(vu, vc0), DRMP3_VMUL(vd, vc1))); + vd = DRMP3_VADD(DRMP3_VMUL(vu, vc1), DRMP3_VMUL(vd, vc0)); + DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vd)); } #endif -#ifndef MA_DR_MP3_ONLY_SIMD +#ifndef DR_MP3_ONLY_SIMD for(; i < 8; i++) { float u = grbuf[18 + i]; @@ -91622,7 +61940,7 @@ static void ma_dr_mp3_L3_antialias(float *grbuf, int nbands) #endif } } -static void ma_dr_mp3_L3_dct3_9(float *y) +static void drmp3_L3_dct3_9(float *y) { float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4; s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8]; @@ -91655,7 +61973,7 @@ static void ma_dr_mp3_L3_dct3_9(float *y) y[7] = s2 - s1; y[8] = s4 + s7; } -static void ma_dr_mp3_L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) +static void drmp3_L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) { int i, j; static const float g_twid9[18] = { @@ -91673,28 +61991,28 @@ static void ma_dr_mp3_L3_imdct36(float *grbuf, float *overlap, const float *wind si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3]; co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]); } - ma_dr_mp3_L3_dct3_9(co); - ma_dr_mp3_L3_dct3_9(si); + drmp3_L3_dct3_9(co); + drmp3_L3_dct3_9(si); si[1] = -si[1]; si[3] = -si[3]; si[5] = -si[5]; si[7] = -si[7]; i = 0; -#if MA_DR_MP3_HAVE_SIMD - if (ma_dr_mp3_have_simd()) for (; i < 8; i += 4) +#if DRMP3_HAVE_SIMD + if (drmp3_have_simd()) for (; i < 8; i += 4) { - ma_dr_mp3_f4 vovl = MA_DR_MP3_VLD(overlap + i); - ma_dr_mp3_f4 vc = MA_DR_MP3_VLD(co + i); - ma_dr_mp3_f4 vs = MA_DR_MP3_VLD(si + i); - ma_dr_mp3_f4 vr0 = MA_DR_MP3_VLD(g_twid9 + i); - ma_dr_mp3_f4 vr1 = MA_DR_MP3_VLD(g_twid9 + 9 + i); - ma_dr_mp3_f4 vw0 = MA_DR_MP3_VLD(window + i); - ma_dr_mp3_f4 vw1 = MA_DR_MP3_VLD(window + 9 + i); - ma_dr_mp3_f4 vsum = MA_DR_MP3_VADD(MA_DR_MP3_VMUL(vc, vr1), MA_DR_MP3_VMUL(vs, vr0)); - MA_DR_MP3_VSTORE(overlap + i, MA_DR_MP3_VSUB(MA_DR_MP3_VMUL(vc, vr0), MA_DR_MP3_VMUL(vs, vr1))); - MA_DR_MP3_VSTORE(grbuf + i, MA_DR_MP3_VSUB(MA_DR_MP3_VMUL(vovl, vw0), MA_DR_MP3_VMUL(vsum, vw1))); - vsum = MA_DR_MP3_VADD(MA_DR_MP3_VMUL(vovl, vw1), MA_DR_MP3_VMUL(vsum, vw0)); - MA_DR_MP3_VSTORE(grbuf + 14 - i, MA_DR_MP3_VREV(vsum)); + drmp3_f4 vovl = DRMP3_VLD(overlap + i); + drmp3_f4 vc = DRMP3_VLD(co + i); + drmp3_f4 vs = DRMP3_VLD(si + i); + drmp3_f4 vr0 = DRMP3_VLD(g_twid9 + i); + drmp3_f4 vr1 = DRMP3_VLD(g_twid9 + 9 + i); + drmp3_f4 vw0 = DRMP3_VLD(window + i); + drmp3_f4 vw1 = DRMP3_VLD(window + 9 + i); + drmp3_f4 vsum = DRMP3_VADD(DRMP3_VMUL(vc, vr1), DRMP3_VMUL(vs, vr0)); + DRMP3_VSTORE(overlap + i, DRMP3_VSUB(DRMP3_VMUL(vc, vr0), DRMP3_VMUL(vs, vr1))); + DRMP3_VSTORE(grbuf + i, DRMP3_VSUB(DRMP3_VMUL(vovl, vw0), DRMP3_VMUL(vsum, vw1))); + vsum = DRMP3_VADD(DRMP3_VMUL(vovl, vw1), DRMP3_VMUL(vsum, vw0)); + DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vsum)); } #endif for (; i < 9; i++) @@ -91707,7 +62025,7 @@ static void ma_dr_mp3_L3_imdct36(float *grbuf, float *overlap, const float *wind } } } -static void ma_dr_mp3_L3_idct3(float x0, float x1, float x2, float *dst) +static void drmp3_L3_idct3(float x0, float x1, float x2, float *dst) { float m1 = x1*0.86602540f; float a1 = x0 - x2*0.5f; @@ -91715,13 +62033,13 @@ static void ma_dr_mp3_L3_idct3(float x0, float x1, float x2, float *dst) dst[0] = a1 + m1; dst[2] = a1 - m1; } -static void ma_dr_mp3_L3_imdct12(float *x, float *dst, float *overlap) +static void drmp3_L3_imdct12(float *x, float *dst, float *overlap) { static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f }; float co[3], si[3]; int i; - ma_dr_mp3_L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); - ma_dr_mp3_L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); + drmp3_L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); + drmp3_L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); si[1] = -si[1]; for (i = 0; i < 3; i++) { @@ -91732,26 +62050,26 @@ static void ma_dr_mp3_L3_imdct12(float *x, float *dst, float *overlap) dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i]; } } -static void ma_dr_mp3_L3_imdct_short(float *grbuf, float *overlap, int nbands) +static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands) { for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) { float tmp[18]; - MA_DR_MP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp)); - MA_DR_MP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float)); - ma_dr_mp3_L3_imdct12(tmp, grbuf + 6, overlap + 6); - ma_dr_mp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); - ma_dr_mp3_L3_imdct12(tmp + 2, overlap, overlap + 6); + memcpy(tmp, grbuf, sizeof(tmp)); + memcpy(grbuf, overlap, 6*sizeof(float)); + drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6); + drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); + drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6); } } -static void ma_dr_mp3_L3_change_sign(float *grbuf) +static void drmp3_L3_change_sign(float *grbuf) { int b, i; for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36) for (i = 1; i < 18; i += 2) grbuf[i] = -grbuf[i]; } -static void ma_dr_mp3_L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) +static void drmp3_L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) { static const float g_mdct_window[2][18] = { { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f }, @@ -91759,159 +62077,159 @@ static void ma_dr_mp3_L3_imdct_gr(float *grbuf, float *overlap, unsigned block_t }; if (n_long_bands) { - ma_dr_mp3_L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); + drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); grbuf += 18*n_long_bands; overlap += 9*n_long_bands; } - if (block_type == MA_DR_MP3_SHORT_BLOCK_TYPE) - ma_dr_mp3_L3_imdct_short(grbuf, overlap, 32 - n_long_bands); + if (block_type == DRMP3_SHORT_BLOCK_TYPE) + drmp3_L3_imdct_short(grbuf, overlap, 32 - n_long_bands); else - ma_dr_mp3_L3_imdct36(grbuf, overlap, g_mdct_window[block_type == MA_DR_MP3_STOP_BLOCK_TYPE], 32 - n_long_bands); + drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[block_type == DRMP3_STOP_BLOCK_TYPE], 32 - n_long_bands); } -static void ma_dr_mp3_L3_save_reservoir(ma_dr_mp3dec *h, ma_dr_mp3dec_scratch *s) +static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s) { int pos = (s->bs.pos + 7)/8u; int remains = s->bs.limit/8u - pos; - if (remains > MA_DR_MP3_MAX_BITRESERVOIR_BYTES) + if (remains > DRMP3_MAX_BITRESERVOIR_BYTES) { - pos += remains - MA_DR_MP3_MAX_BITRESERVOIR_BYTES; - remains = MA_DR_MP3_MAX_BITRESERVOIR_BYTES; + pos += remains - DRMP3_MAX_BITRESERVOIR_BYTES; + remains = DRMP3_MAX_BITRESERVOIR_BYTES; } if (remains > 0) { - MA_DR_MP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains); + memmove(h->reserv_buf, s->maindata + pos, remains); } h->reserv = remains; } -static int ma_dr_mp3_L3_restore_reservoir(ma_dr_mp3dec *h, ma_dr_mp3_bs *bs, ma_dr_mp3dec_scratch *s, int main_data_begin) +static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratch *s, int main_data_begin) { int frame_bytes = (bs->limit - bs->pos)/8; - int bytes_have = MA_DR_MP3_MIN(h->reserv, main_data_begin); - MA_DR_MP3_COPY_MEMORY(s->maindata, h->reserv_buf + MA_DR_MP3_MAX(0, h->reserv - main_data_begin), MA_DR_MP3_MIN(h->reserv, main_data_begin)); - MA_DR_MP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); - ma_dr_mp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); + int bytes_have = DRMP3_MIN(h->reserv, main_data_begin); + memcpy(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin)); + memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); return h->reserv >= main_data_begin; } -static void ma_dr_mp3_L3_decode(ma_dr_mp3dec *h, ma_dr_mp3dec_scratch *s, ma_dr_mp3_L3_gr_info *gr_info, int nch) +static void drmp3_L3_decode(drmp3dec *h, drmp3dec_scratch *s, drmp3_L3_gr_info *gr_info, int nch) { int ch; for (ch = 0; ch < nch; ch++) { int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length; - ma_dr_mp3_L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); - ma_dr_mp3_L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); + drmp3_L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); + drmp3_L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); } - if (MA_DR_MP3_HDR_TEST_I_STEREO(h->header)) + if (DRMP3_HDR_TEST_I_STEREO(h->header)) { - ma_dr_mp3_L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); - } else if (MA_DR_MP3_HDR_IS_MS_STEREO(h->header)) + drmp3_L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); + } else if (DRMP3_HDR_IS_MS_STEREO(h->header)) { - ma_dr_mp3_L3_midside_stereo(s->grbuf[0], 576); + drmp3_L3_midside_stereo(s->grbuf[0], 576); } for (ch = 0; ch < nch; ch++, gr_info++) { int aa_bands = 31; - int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(MA_DR_MP3_HDR_GET_MY_SAMPLE_RATE(h->header) == 2); + int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(DRMP3_HDR_GET_MY_SAMPLE_RATE(h->header) == 2); if (gr_info->n_short_sfb) { aa_bands = n_long_bands - 1; - ma_dr_mp3_L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); + drmp3_L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); } - ma_dr_mp3_L3_antialias(s->grbuf[ch], aa_bands); - ma_dr_mp3_L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); - ma_dr_mp3_L3_change_sign(s->grbuf[ch]); + drmp3_L3_antialias(s->grbuf[ch], aa_bands); + drmp3_L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); + drmp3_L3_change_sign(s->grbuf[ch]); } } -static void ma_dr_mp3d_DCT_II(float *grbuf, int n) +static void drmp3d_DCT_II(float *grbuf, int n) { static const float g_sec[24] = { 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f }; int i, k = 0; -#if MA_DR_MP3_HAVE_SIMD - if (ma_dr_mp3_have_simd()) for (; k < n; k += 4) +#if DRMP3_HAVE_SIMD + if (drmp3_have_simd()) for (; k < n; k += 4) { - ma_dr_mp3_f4 t[4][8], *x; + drmp3_f4 t[4][8], *x; float *y = grbuf + k; for (x = t[0], i = 0; i < 8; i++, x++) { - ma_dr_mp3_f4 x0 = MA_DR_MP3_VLD(&y[i*18]); - ma_dr_mp3_f4 x1 = MA_DR_MP3_VLD(&y[(15 - i)*18]); - ma_dr_mp3_f4 x2 = MA_DR_MP3_VLD(&y[(16 + i)*18]); - ma_dr_mp3_f4 x3 = MA_DR_MP3_VLD(&y[(31 - i)*18]); - ma_dr_mp3_f4 t0 = MA_DR_MP3_VADD(x0, x3); - ma_dr_mp3_f4 t1 = MA_DR_MP3_VADD(x1, x2); - ma_dr_mp3_f4 t2 = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(x1, x2), g_sec[3*i + 0]); - ma_dr_mp3_f4 t3 = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(x0, x3), g_sec[3*i + 1]); - x[0] = MA_DR_MP3_VADD(t0, t1); - x[8] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(t0, t1), g_sec[3*i + 2]); - x[16] = MA_DR_MP3_VADD(t3, t2); - x[24] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(t3, t2), g_sec[3*i + 2]); + drmp3_f4 x0 = DRMP3_VLD(&y[i*18]); + drmp3_f4 x1 = DRMP3_VLD(&y[(15 - i)*18]); + drmp3_f4 x2 = DRMP3_VLD(&y[(16 + i)*18]); + drmp3_f4 x3 = DRMP3_VLD(&y[(31 - i)*18]); + drmp3_f4 t0 = DRMP3_VADD(x0, x3); + drmp3_f4 t1 = DRMP3_VADD(x1, x2); + drmp3_f4 t2 = DRMP3_VMUL_S(DRMP3_VSUB(x1, x2), g_sec[3*i + 0]); + drmp3_f4 t3 = DRMP3_VMUL_S(DRMP3_VSUB(x0, x3), g_sec[3*i + 1]); + x[0] = DRMP3_VADD(t0, t1); + x[8] = DRMP3_VMUL_S(DRMP3_VSUB(t0, t1), g_sec[3*i + 2]); + x[16] = DRMP3_VADD(t3, t2); + x[24] = DRMP3_VMUL_S(DRMP3_VSUB(t3, t2), g_sec[3*i + 2]); } for (x = t[0], i = 0; i < 4; i++, x += 8) { - ma_dr_mp3_f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; - xt = MA_DR_MP3_VSUB(x0, x7); x0 = MA_DR_MP3_VADD(x0, x7); - x7 = MA_DR_MP3_VSUB(x1, x6); x1 = MA_DR_MP3_VADD(x1, x6); - x6 = MA_DR_MP3_VSUB(x2, x5); x2 = MA_DR_MP3_VADD(x2, x5); - x5 = MA_DR_MP3_VSUB(x3, x4); x3 = MA_DR_MP3_VADD(x3, x4); - x4 = MA_DR_MP3_VSUB(x0, x3); x0 = MA_DR_MP3_VADD(x0, x3); - x3 = MA_DR_MP3_VSUB(x1, x2); x1 = MA_DR_MP3_VADD(x1, x2); - x[0] = MA_DR_MP3_VADD(x0, x1); - x[4] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(x0, x1), 0.70710677f); - x5 = MA_DR_MP3_VADD(x5, x6); - x6 = MA_DR_MP3_VMUL_S(MA_DR_MP3_VADD(x6, x7), 0.70710677f); - x7 = MA_DR_MP3_VADD(x7, xt); - x3 = MA_DR_MP3_VMUL_S(MA_DR_MP3_VADD(x3, x4), 0.70710677f); - x5 = MA_DR_MP3_VSUB(x5, MA_DR_MP3_VMUL_S(x7, 0.198912367f)); - x7 = MA_DR_MP3_VADD(x7, MA_DR_MP3_VMUL_S(x5, 0.382683432f)); - x5 = MA_DR_MP3_VSUB(x5, MA_DR_MP3_VMUL_S(x7, 0.198912367f)); - x0 = MA_DR_MP3_VSUB(xt, x6); xt = MA_DR_MP3_VADD(xt, x6); - x[1] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VADD(xt, x7), 0.50979561f); - x[2] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VADD(x4, x3), 0.54119611f); - x[3] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(x0, x5), 0.60134488f); - x[5] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VADD(x0, x5), 0.89997619f); - x[6] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(x4, x3), 1.30656302f); - x[7] = MA_DR_MP3_VMUL_S(MA_DR_MP3_VSUB(xt, x7), 2.56291556f); + drmp3_f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = DRMP3_VSUB(x0, x7); x0 = DRMP3_VADD(x0, x7); + x7 = DRMP3_VSUB(x1, x6); x1 = DRMP3_VADD(x1, x6); + x6 = DRMP3_VSUB(x2, x5); x2 = DRMP3_VADD(x2, x5); + x5 = DRMP3_VSUB(x3, x4); x3 = DRMP3_VADD(x3, x4); + x4 = DRMP3_VSUB(x0, x3); x0 = DRMP3_VADD(x0, x3); + x3 = DRMP3_VSUB(x1, x2); x1 = DRMP3_VADD(x1, x2); + x[0] = DRMP3_VADD(x0, x1); + x[4] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x1), 0.70710677f); + x5 = DRMP3_VADD(x5, x6); + x6 = DRMP3_VMUL_S(DRMP3_VADD(x6, x7), 0.70710677f); + x7 = DRMP3_VADD(x7, xt); + x3 = DRMP3_VMUL_S(DRMP3_VADD(x3, x4), 0.70710677f); + x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f)); + x7 = DRMP3_VADD(x7, DRMP3_VMUL_S(x5, 0.382683432f)); + x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f)); + x0 = DRMP3_VSUB(xt, x6); xt = DRMP3_VADD(xt, x6); + x[1] = DRMP3_VMUL_S(DRMP3_VADD(xt, x7), 0.50979561f); + x[2] = DRMP3_VMUL_S(DRMP3_VADD(x4, x3), 0.54119611f); + x[3] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x5), 0.60134488f); + x[5] = DRMP3_VMUL_S(DRMP3_VADD(x0, x5), 0.89997619f); + x[6] = DRMP3_VMUL_S(DRMP3_VSUB(x4, x3), 1.30656302f); + x[7] = DRMP3_VMUL_S(DRMP3_VSUB(xt, x7), 2.56291556f); } if (k > n - 3) { -#if MA_DR_MP3_HAVE_SSE -#define MA_DR_MP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) +#if DRMP3_HAVE_SSE +#define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) #else -#define MA_DR_MP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[(i)*18], vget_low_f32(v)) +#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) #endif for (i = 0; i < 7; i++, y += 4*18) { - ma_dr_mp3_f4 s = MA_DR_MP3_VADD(t[3][i], t[3][i + 1]); - MA_DR_MP3_VSAVE2(0, t[0][i]); - MA_DR_MP3_VSAVE2(1, MA_DR_MP3_VADD(t[2][i], s)); - MA_DR_MP3_VSAVE2(2, MA_DR_MP3_VADD(t[1][i], t[1][i + 1])); - MA_DR_MP3_VSAVE2(3, MA_DR_MP3_VADD(t[2][1 + i], s)); + drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]); + DRMP3_VSAVE2(0, t[0][i]); + DRMP3_VSAVE2(1, DRMP3_VADD(t[2][i], s)); + DRMP3_VSAVE2(2, DRMP3_VADD(t[1][i], t[1][i + 1])); + DRMP3_VSAVE2(3, DRMP3_VADD(t[2][1 + i], s)); } - MA_DR_MP3_VSAVE2(0, t[0][7]); - MA_DR_MP3_VSAVE2(1, MA_DR_MP3_VADD(t[2][7], t[3][7])); - MA_DR_MP3_VSAVE2(2, t[1][7]); - MA_DR_MP3_VSAVE2(3, t[3][7]); + DRMP3_VSAVE2(0, t[0][7]); + DRMP3_VSAVE2(1, DRMP3_VADD(t[2][7], t[3][7])); + DRMP3_VSAVE2(2, t[1][7]); + DRMP3_VSAVE2(3, t[3][7]); } else { -#define MA_DR_MP3_VSAVE4(i, v) MA_DR_MP3_VSTORE(&y[(i)*18], v) +#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v) for (i = 0; i < 7; i++, y += 4*18) { - ma_dr_mp3_f4 s = MA_DR_MP3_VADD(t[3][i], t[3][i + 1]); - MA_DR_MP3_VSAVE4(0, t[0][i]); - MA_DR_MP3_VSAVE4(1, MA_DR_MP3_VADD(t[2][i], s)); - MA_DR_MP3_VSAVE4(2, MA_DR_MP3_VADD(t[1][i], t[1][i + 1])); - MA_DR_MP3_VSAVE4(3, MA_DR_MP3_VADD(t[2][1 + i], s)); + drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]); + DRMP3_VSAVE4(0, t[0][i]); + DRMP3_VSAVE4(1, DRMP3_VADD(t[2][i], s)); + DRMP3_VSAVE4(2, DRMP3_VADD(t[1][i], t[1][i + 1])); + DRMP3_VSAVE4(3, DRMP3_VADD(t[2][1 + i], s)); } - MA_DR_MP3_VSAVE4(0, t[0][7]); - MA_DR_MP3_VSAVE4(1, MA_DR_MP3_VADD(t[2][7], t[3][7])); - MA_DR_MP3_VSAVE4(2, t[1][7]); - MA_DR_MP3_VSAVE4(3, t[3][7]); + DRMP3_VSAVE4(0, t[0][7]); + DRMP3_VSAVE4(1, DRMP3_VADD(t[2][7], t[3][7])); + DRMP3_VSAVE4(2, t[1][7]); + DRMP3_VSAVE4(3, t[3][7]); } } else #endif -#ifdef MA_DR_MP3_ONLY_SIMD +#ifdef DR_MP3_ONLY_SIMD {} #else for (; k < n; k++) @@ -91972,31 +62290,31 @@ static void ma_dr_mp3d_DCT_II(float *grbuf, int n) } #endif } -#ifndef MA_DR_MP3_FLOAT_OUTPUT -typedef ma_int16 ma_dr_mp3d_sample_t; -static ma_int16 ma_dr_mp3d_scale_pcm(float sample) +#ifndef DR_MP3_FLOAT_OUTPUT +typedef drmp3_int16 drmp3d_sample_t; +static drmp3_int16 drmp3d_scale_pcm(float sample) { - ma_int16 s; -#if MA_DR_MP3_HAVE_ARMV6 - ma_int32 s32 = (ma_int32)(sample + .5f); + drmp3_int16 s; +#if DRMP3_HAVE_ARMV6 + drmp3_int32 s32 = (drmp3_int32)(sample + .5f); s32 -= (s32 < 0); - s = (ma_int16)ma_dr_mp3_clip_int16_arm(s32); + s = (drmp3_int16)drmp3_clip_int16_arm(s32); #else - if (sample >= 32766.5f) return (ma_int16) 32767; - if (sample <= -32767.5f) return (ma_int16)-32768; - s = (ma_int16)(sample + .5f); + if (sample >= 32766.5) return (drmp3_int16) 32767; + if (sample <= -32767.5) return (drmp3_int16)-32768; + s = (drmp3_int16)(sample + .5f); s -= (s < 0); #endif return s; } #else -typedef float ma_dr_mp3d_sample_t; -static float ma_dr_mp3d_scale_pcm(float sample) +typedef float drmp3d_sample_t; +static float drmp3d_scale_pcm(float sample) { return sample*(1.f/32768.f); } #endif -static void ma_dr_mp3d_synth_pair(ma_dr_mp3d_sample_t *pcm, int nch, const float *z) +static void drmp3d_synth_pair(drmp3d_sample_t *pcm, int nch, const float *z) { float a; a = (z[14*64] - z[ 0]) * 29; @@ -92007,7 +62325,7 @@ static void ma_dr_mp3d_synth_pair(ma_dr_mp3d_sample_t *pcm, int nch, const float a += (z[ 5*64] + z[ 9*64]) * 6574; a += (z[ 8*64] - z[ 6*64]) * 37489; a += z[ 7*64] * 75038; - pcm[0] = ma_dr_mp3d_scale_pcm(a); + pcm[0] = drmp3d_scale_pcm(a); z += 2; a = z[14*64] * 104; a += z[12*64] * 1567; @@ -92017,13 +62335,13 @@ static void ma_dr_mp3d_synth_pair(ma_dr_mp3d_sample_t *pcm, int nch, const float a += z[ 4*64] * -45; a += z[ 2*64] * 146; a += z[ 0*64] * -5; - pcm[16*nch] = ma_dr_mp3d_scale_pcm(a); + pcm[16*nch] = drmp3d_scale_pcm(a); } -static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, float *lins) +static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins) { int i; float *xr = xl + 576*(nch - 1); - ma_dr_mp3d_sample_t *dstr = dstl + (nch - 1); + drmp3d_sample_t *dstr = dstl + (nch - 1); static const float g_win[] = { -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856, @@ -92051,18 +62369,18 @@ static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, floa zlin[4*31 + 1] = xr[1 + 18*16]; zlin[4*31 + 2] = xl[1]; zlin[4*31 + 3] = xr[1]; - ma_dr_mp3d_synth_pair(dstr, nch, lins + 4*15 + 1); - ma_dr_mp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); - ma_dr_mp3d_synth_pair(dstl, nch, lins + 4*15); - ma_dr_mp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); -#if MA_DR_MP3_HAVE_SIMD - if (ma_dr_mp3_have_simd()) for (i = 14; i >= 0; i--) + drmp3d_synth_pair(dstr, nch, lins + 4*15 + 1); + drmp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); + drmp3d_synth_pair(dstl, nch, lins + 4*15); + drmp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); +#if DRMP3_HAVE_SIMD + if (drmp3_have_simd()) for (i = 14; i >= 0; i--) { -#define MA_DR_MP3_VLOAD(k) ma_dr_mp3_f4 w0 = MA_DR_MP3_VSET(*w++); ma_dr_mp3_f4 w1 = MA_DR_MP3_VSET(*w++); ma_dr_mp3_f4 vz = MA_DR_MP3_VLD(&zlin[4*i - 64*k]); ma_dr_mp3_f4 vy = MA_DR_MP3_VLD(&zlin[4*i - 64*(15 - k)]); -#define MA_DR_MP3_V0(k) { MA_DR_MP3_VLOAD(k) b = MA_DR_MP3_VADD(MA_DR_MP3_VMUL(vz, w1), MA_DR_MP3_VMUL(vy, w0)) ; a = MA_DR_MP3_VSUB(MA_DR_MP3_VMUL(vz, w0), MA_DR_MP3_VMUL(vy, w1)); } -#define MA_DR_MP3_V1(k) { MA_DR_MP3_VLOAD(k) b = MA_DR_MP3_VADD(b, MA_DR_MP3_VADD(MA_DR_MP3_VMUL(vz, w1), MA_DR_MP3_VMUL(vy, w0))); a = MA_DR_MP3_VADD(a, MA_DR_MP3_VSUB(MA_DR_MP3_VMUL(vz, w0), MA_DR_MP3_VMUL(vy, w1))); } -#define MA_DR_MP3_V2(k) { MA_DR_MP3_VLOAD(k) b = MA_DR_MP3_VADD(b, MA_DR_MP3_VADD(MA_DR_MP3_VMUL(vz, w1), MA_DR_MP3_VMUL(vy, w0))); a = MA_DR_MP3_VADD(a, MA_DR_MP3_VSUB(MA_DR_MP3_VMUL(vy, w1), MA_DR_MP3_VMUL(vz, w0))); } - ma_dr_mp3_f4 a, b; +#define DRMP3_VLOAD(k) drmp3_f4 w0 = DRMP3_VSET(*w++); drmp3_f4 w1 = DRMP3_VSET(*w++); drmp3_f4 vz = DRMP3_VLD(&zlin[4*i - 64*k]); drmp3_f4 vy = DRMP3_VLD(&zlin[4*i - 64*(15 - k)]); +#define DRMP3_V0(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0)) ; a = DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1)); } +#define DRMP3_V1(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1))); } +#define DRMP3_V2(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vy, w1), DRMP3_VMUL(vz, w0))); } + drmp3_f4 a, b; zlin[4*i] = xl[18*(31 - i)]; zlin[4*i + 1] = xr[18*(31 - i)]; zlin[4*i + 2] = xl[1 + 18*(31 - i)]; @@ -92071,28 +62389,28 @@ static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, floa zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)]; zlin[4*i - 64 + 2] = xl[18*(1 + i)]; zlin[4*i - 64 + 3] = xr[18*(1 + i)]; - MA_DR_MP3_V0(0) MA_DR_MP3_V2(1) MA_DR_MP3_V1(2) MA_DR_MP3_V2(3) MA_DR_MP3_V1(4) MA_DR_MP3_V2(5) MA_DR_MP3_V1(6) MA_DR_MP3_V2(7) + DRMP3_V0(0) DRMP3_V2(1) DRMP3_V1(2) DRMP3_V2(3) DRMP3_V1(4) DRMP3_V2(5) DRMP3_V1(6) DRMP3_V2(7) { -#ifndef MA_DR_MP3_FLOAT_OUTPUT -#if MA_DR_MP3_HAVE_SSE - static const ma_dr_mp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; - static const ma_dr_mp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; +#ifndef DR_MP3_FLOAT_OUTPUT +#if DRMP3_HAVE_SSE + static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); - dstr[(15 - i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 1); - dstr[(17 + i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 5); - dstl[(15 - i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 0); - dstl[(17 + i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 4); - dstr[(47 - i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 3); - dstr[(49 + i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 7); - dstl[(47 - i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 2); - dstl[(49 + i)*nch] = (ma_int16)_mm_extract_epi16(pcm8, 6); + dstr[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 1); + dstr[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 5); + dstl[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 0); + dstl[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 4); + dstr[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 3); + dstr[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 7); + dstl[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 2); + dstl[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 6); #else int16x4_t pcma, pcmb; - a = MA_DR_MP3_VADD(a, MA_DR_MP3_VSET(0.5f)); - b = MA_DR_MP3_VADD(b, MA_DR_MP3_VSET(0.5f)); - pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, MA_DR_MP3_VSET(0))))); - pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, MA_DR_MP3_VSET(0))))); + a = DRMP3_VADD(a, DRMP3_VSET(0.5f)); + b = DRMP3_VADD(b, DRMP3_VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0))))); vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1); vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1); vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0); @@ -92103,14 +62421,10 @@ static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, floa vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); #endif #else - #if MA_DR_MP3_HAVE_SSE - static const ma_dr_mp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; - #else - const ma_dr_mp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f); - #endif - a = MA_DR_MP3_VMUL(a, g_scale); - b = MA_DR_MP3_VMUL(b, g_scale); -#if MA_DR_MP3_HAVE_SSE + static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + a = DRMP3_VMUL(a, g_scale); + b = DRMP3_VMUL(b, g_scale); +#if DRMP3_HAVE_SSE _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); @@ -92133,15 +62447,15 @@ static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, floa } } else #endif -#ifdef MA_DR_MP3_ONLY_SIMD +#ifdef DR_MP3_ONLY_SIMD {} #else for (i = 14; i >= 0; i--) { -#define MA_DR_MP3_LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; -#define MA_DR_MP3_S0(k) { int j; MA_DR_MP3_LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } -#define MA_DR_MP3_S1(k) { int j; MA_DR_MP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } -#define MA_DR_MP3_S2(k) { int j; MA_DR_MP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } +#define DRMP3_LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; +#define DRMP3_S0(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } +#define DRMP3_S1(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } +#define DRMP3_S2(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } float a[4], b[4]; zlin[4*i] = xl[18*(31 - i)]; zlin[4*i + 1] = xr[18*(31 - i)]; @@ -92151,31 +62465,31 @@ static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, floa zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)]; zlin[4*(i - 16) + 2] = xl[18*(1 + i)]; zlin[4*(i - 16) + 3] = xr[18*(1 + i)]; - MA_DR_MP3_S0(0) MA_DR_MP3_S2(1) MA_DR_MP3_S1(2) MA_DR_MP3_S2(3) MA_DR_MP3_S1(4) MA_DR_MP3_S2(5) MA_DR_MP3_S1(6) MA_DR_MP3_S2(7) - dstr[(15 - i)*nch] = ma_dr_mp3d_scale_pcm(a[1]); - dstr[(17 + i)*nch] = ma_dr_mp3d_scale_pcm(b[1]); - dstl[(15 - i)*nch] = ma_dr_mp3d_scale_pcm(a[0]); - dstl[(17 + i)*nch] = ma_dr_mp3d_scale_pcm(b[0]); - dstr[(47 - i)*nch] = ma_dr_mp3d_scale_pcm(a[3]); - dstr[(49 + i)*nch] = ma_dr_mp3d_scale_pcm(b[3]); - dstl[(47 - i)*nch] = ma_dr_mp3d_scale_pcm(a[2]); - dstl[(49 + i)*nch] = ma_dr_mp3d_scale_pcm(b[2]); + DRMP3_S0(0) DRMP3_S2(1) DRMP3_S1(2) DRMP3_S2(3) DRMP3_S1(4) DRMP3_S2(5) DRMP3_S1(6) DRMP3_S2(7) + dstr[(15 - i)*nch] = drmp3d_scale_pcm(a[1]); + dstr[(17 + i)*nch] = drmp3d_scale_pcm(b[1]); + dstl[(15 - i)*nch] = drmp3d_scale_pcm(a[0]); + dstl[(17 + i)*nch] = drmp3d_scale_pcm(b[0]); + dstr[(47 - i)*nch] = drmp3d_scale_pcm(a[3]); + dstr[(49 + i)*nch] = drmp3d_scale_pcm(b[3]); + dstl[(47 - i)*nch] = drmp3d_scale_pcm(a[2]); + dstl[(49 + i)*nch] = drmp3d_scale_pcm(b[2]); } #endif } -static void ma_dr_mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, ma_dr_mp3d_sample_t *pcm, float *lins) +static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, drmp3d_sample_t *pcm, float *lins) { int i; for (i = 0; i < nch; i++) { - ma_dr_mp3d_DCT_II(grbuf + 576*i, nbands); + drmp3d_DCT_II(grbuf + 576*i, nbands); } - MA_DR_MP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64); + memcpy(lins, qmf_state, sizeof(float)*15*64); for (i = 0; i < nbands; i += 2) { - ma_dr_mp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); + drmp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); } -#ifndef MA_DR_MP3_NONSTANDARD_BUT_LOGICAL +#ifndef DR_MP3_NONSTANDARD_BUT_LOGICAL if (nch == 1) { for (i = 0; i < 15*64; i += 2) @@ -92185,38 +62499,38 @@ static void ma_dr_mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, } else #endif { - MA_DR_MP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64); + memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); } } -static int ma_dr_mp3d_match_frame(const ma_uint8 *hdr, int mp3_bytes, int frame_bytes) +static int drmp3d_match_frame(const drmp3_uint8 *hdr, int mp3_bytes, int frame_bytes) { int i, nmatch; - for (i = 0, nmatch = 0; nmatch < MA_DR_MP3_MAX_FRAME_SYNC_MATCHES; nmatch++) + for (i = 0, nmatch = 0; nmatch < DRMP3_MAX_FRAME_SYNC_MATCHES; nmatch++) { - i += ma_dr_mp3_hdr_frame_bytes(hdr + i, frame_bytes) + ma_dr_mp3_hdr_padding(hdr + i); - if (i + MA_DR_MP3_HDR_SIZE > mp3_bytes) + i += drmp3_hdr_frame_bytes(hdr + i, frame_bytes) + drmp3_hdr_padding(hdr + i); + if (i + DRMP3_HDR_SIZE > mp3_bytes) return nmatch > 0; - if (!ma_dr_mp3_hdr_compare(hdr, hdr + i)) + if (!drmp3_hdr_compare(hdr, hdr + i)) return 0; } return 1; } -static int ma_dr_mp3d_find_frame(const ma_uint8 *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) +static int drmp3d_find_frame(const drmp3_uint8 *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) { int i, k; - for (i = 0; i < mp3_bytes - MA_DR_MP3_HDR_SIZE; i++, mp3++) + for (i = 0; i < mp3_bytes - DRMP3_HDR_SIZE; i++, mp3++) { - if (ma_dr_mp3_hdr_valid(mp3)) + if (drmp3_hdr_valid(mp3)) { - int frame_bytes = ma_dr_mp3_hdr_frame_bytes(mp3, *free_format_bytes); - int frame_and_padding = frame_bytes + ma_dr_mp3_hdr_padding(mp3); - for (k = MA_DR_MP3_HDR_SIZE; !frame_bytes && k < MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - MA_DR_MP3_HDR_SIZE; k++) + int frame_bytes = drmp3_hdr_frame_bytes(mp3, *free_format_bytes); + int frame_and_padding = frame_bytes + drmp3_hdr_padding(mp3); + for (k = DRMP3_HDR_SIZE; !frame_bytes && k < DRMP3_MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - DRMP3_HDR_SIZE; k++) { - if (ma_dr_mp3_hdr_compare(mp3, mp3 + k)) + if (drmp3_hdr_compare(mp3, mp3 + k)) { - int fb = k - ma_dr_mp3_hdr_padding(mp3); - int nextfb = fb + ma_dr_mp3_hdr_padding(mp3 + k); - if (i + k + nextfb + MA_DR_MP3_HDR_SIZE > mp3_bytes || !ma_dr_mp3_hdr_compare(mp3, mp3 + k + nextfb)) + int fb = k - drmp3_hdr_padding(mp3); + int nextfb = fb + drmp3_hdr_padding(mp3 + k); + if (i + k + nextfb + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + k + nextfb)) continue; frame_and_padding = k; frame_bytes = fb; @@ -92224,7 +62538,7 @@ static int ma_dr_mp3d_find_frame(const ma_uint8 *mp3, int mp3_bytes, int *free_f } } if ((frame_bytes && i + frame_and_padding <= mp3_bytes && - ma_dr_mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || + drmp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || (!i && frame_and_padding == mp3_bytes)) { *ptr_frame_bytes = frame_and_padding; @@ -92236,28 +62550,28 @@ static int ma_dr_mp3d_find_frame(const ma_uint8 *mp3, int mp3_bytes, int *free_f *ptr_frame_bytes = 0; return mp3_bytes; } -MA_API void ma_dr_mp3dec_init(ma_dr_mp3dec *dec) +DRMP3_API void drmp3dec_init(drmp3dec *dec) { dec->header[0] = 0; } -MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int mp3_bytes, void *pcm, ma_dr_mp3dec_frame_info *info) +DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info) { int i = 0, igr, frame_size = 0, success = 1; - const ma_uint8 *hdr; - ma_dr_mp3_bs bs_frame[1]; - ma_dr_mp3dec_scratch scratch; - if (mp3_bytes > 4 && dec->header[0] == 0xff && ma_dr_mp3_hdr_compare(dec->header, mp3)) + const drmp3_uint8 *hdr; + drmp3_bs bs_frame[1]; + drmp3dec_scratch scratch; + if (mp3_bytes > 4 && dec->header[0] == 0xff && drmp3_hdr_compare(dec->header, mp3)) { - frame_size = ma_dr_mp3_hdr_frame_bytes(mp3, dec->free_format_bytes) + ma_dr_mp3_hdr_padding(mp3); - if (frame_size != mp3_bytes && (frame_size + MA_DR_MP3_HDR_SIZE > mp3_bytes || !ma_dr_mp3_hdr_compare(mp3, mp3 + frame_size))) + frame_size = drmp3_hdr_frame_bytes(mp3, dec->free_format_bytes) + drmp3_hdr_padding(mp3); + if (frame_size != mp3_bytes && (frame_size + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + frame_size))) { frame_size = 0; } } if (!frame_size) { - MA_DR_MP3_ZERO_MEMORY(dec, sizeof(ma_dr_mp3dec)); - i = ma_dr_mp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); + memset(dec, 0, sizeof(drmp3dec)); + i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); if (!frame_size || i + frame_size > mp3_bytes) { info->frame_bytes = i; @@ -92265,96 +62579,96 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int } } hdr = mp3 + i; - MA_DR_MP3_COPY_MEMORY(dec->header, hdr, MA_DR_MP3_HDR_SIZE); + memcpy(dec->header, hdr, DRMP3_HDR_SIZE); info->frame_bytes = i + frame_size; - info->channels = MA_DR_MP3_HDR_IS_MONO(hdr) ? 1 : 2; - info->hz = ma_dr_mp3_hdr_sample_rate_hz(hdr); - info->layer = 4 - MA_DR_MP3_HDR_GET_LAYER(hdr); - info->bitrate_kbps = ma_dr_mp3_hdr_bitrate_kbps(hdr); - ma_dr_mp3_bs_init(bs_frame, hdr + MA_DR_MP3_HDR_SIZE, frame_size - MA_DR_MP3_HDR_SIZE); - if (MA_DR_MP3_HDR_IS_CRC(hdr)) + info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2; + info->hz = drmp3_hdr_sample_rate_hz(hdr); + info->layer = 4 - DRMP3_HDR_GET_LAYER(hdr); + info->bitrate_kbps = drmp3_hdr_bitrate_kbps(hdr); + drmp3_bs_init(bs_frame, hdr + DRMP3_HDR_SIZE, frame_size - DRMP3_HDR_SIZE); + if (DRMP3_HDR_IS_CRC(hdr)) { - ma_dr_mp3_bs_get_bits(bs_frame, 16); + drmp3_bs_get_bits(bs_frame, 16); } if (info->layer == 3) { - int main_data_begin = ma_dr_mp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr); + int main_data_begin = drmp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr); if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) { - ma_dr_mp3dec_init(dec); + drmp3dec_init(dec); return 0; } - success = ma_dr_mp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); + success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); if (success && pcm != NULL) { - for (igr = 0; igr < (MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = MA_DR_MP3_OFFSET_PTR(pcm, sizeof(ma_dr_mp3d_sample_t)*576*info->channels)) + for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels)) { - MA_DR_MP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); - ma_dr_mp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); - ma_dr_mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (ma_dr_mp3d_sample_t*)pcm, scratch.syn[0]); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); + drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); } } - ma_dr_mp3_L3_save_reservoir(dec, &scratch); + drmp3_L3_save_reservoir(dec, &scratch); } else { -#ifdef MA_DR_MP3_ONLY_MP3 +#ifdef DR_MP3_ONLY_MP3 return 0; #else - ma_dr_mp3_L12_scale_info sci[1]; + drmp3_L12_scale_info sci[1]; if (pcm == NULL) { - return ma_dr_mp3_hdr_frame_samples(hdr); + return drmp3_hdr_frame_samples(hdr); } - ma_dr_mp3_L12_read_scale_info(hdr, bs_frame, sci); - MA_DR_MP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); + drmp3_L12_read_scale_info(hdr, bs_frame, sci); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); for (i = 0, igr = 0; igr < 3; igr++) { - if (12 == (i += ma_dr_mp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) + if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) { i = 0; - ma_dr_mp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); - ma_dr_mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (ma_dr_mp3d_sample_t*)pcm, scratch.syn[0]); - MA_DR_MP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); - pcm = MA_DR_MP3_OFFSET_PTR(pcm, sizeof(ma_dr_mp3d_sample_t)*384*info->channels); + drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); + drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels); } if (bs_frame->pos > bs_frame->limit) { - ma_dr_mp3dec_init(dec); + drmp3dec_init(dec); return 0; } } #endif } - return success*ma_dr_mp3_hdr_frame_samples(dec->header); + return success*drmp3_hdr_frame_samples(dec->header); } -MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples) +DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples) { size_t i = 0; -#if MA_DR_MP3_HAVE_SIMD +#if DRMP3_HAVE_SIMD size_t aligned_count = num_samples & ~7; for(; i < aligned_count; i+=8) { - ma_dr_mp3_f4 scale = MA_DR_MP3_VSET(32768.0f); - ma_dr_mp3_f4 a = MA_DR_MP3_VMUL(MA_DR_MP3_VLD(&in[i ]), scale); - ma_dr_mp3_f4 b = MA_DR_MP3_VMUL(MA_DR_MP3_VLD(&in[i+4]), scale); -#if MA_DR_MP3_HAVE_SSE - ma_dr_mp3_f4 s16max = MA_DR_MP3_VSET( 32767.0f); - ma_dr_mp3_f4 s16min = MA_DR_MP3_VSET(-32768.0f); + drmp3_f4 scale = DRMP3_VSET(32768.0f); + drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), scale); + drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), scale); +#if DRMP3_HAVE_SSE + drmp3_f4 s16max = DRMP3_VSET( 32767.0f); + drmp3_f4 s16min = DRMP3_VSET(-32768.0f); __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, s16max), s16min)), _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, s16max), s16min))); - out[i ] = (ma_int16)_mm_extract_epi16(pcm8, 0); - out[i+1] = (ma_int16)_mm_extract_epi16(pcm8, 1); - out[i+2] = (ma_int16)_mm_extract_epi16(pcm8, 2); - out[i+3] = (ma_int16)_mm_extract_epi16(pcm8, 3); - out[i+4] = (ma_int16)_mm_extract_epi16(pcm8, 4); - out[i+5] = (ma_int16)_mm_extract_epi16(pcm8, 5); - out[i+6] = (ma_int16)_mm_extract_epi16(pcm8, 6); - out[i+7] = (ma_int16)_mm_extract_epi16(pcm8, 7); + out[i ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0); + out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1); + out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2); + out[i+3] = (drmp3_int16)_mm_extract_epi16(pcm8, 3); + out[i+4] = (drmp3_int16)_mm_extract_epi16(pcm8, 4); + out[i+5] = (drmp3_int16)_mm_extract_epi16(pcm8, 5); + out[i+6] = (drmp3_int16)_mm_extract_epi16(pcm8, 6); + out[i+7] = (drmp3_int16)_mm_extract_epi16(pcm8, 7); #else int16x4_t pcma, pcmb; - a = MA_DR_MP3_VADD(a, MA_DR_MP3_VSET(0.5f)); - b = MA_DR_MP3_VADD(b, MA_DR_MP3_VSET(0.5f)); - pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, MA_DR_MP3_VSET(0))))); - pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, MA_DR_MP3_VSET(0))))); + a = DRMP3_VADD(a, DRMP3_VSET(0.5f)); + b = DRMP3_VADD(b, DRMP3_VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0))))); vst1_lane_s16(out+i , pcma, 0); vst1_lane_s16(out+i+1, pcma, 1); vst1_lane_s16(out+i+2, pcma, 2); @@ -92369,70 +62683,112 @@ MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_s for(; i < num_samples; i++) { float sample = in[i] * 32768.0f; - if (sample >= 32766.5f) - out[i] = (ma_int16) 32767; - else if (sample <= -32767.5f) - out[i] = (ma_int16)-32768; + if (sample >= 32766.5) + out[i] = (drmp3_int16) 32767; + else if (sample <= -32767.5) + out[i] = (drmp3_int16)-32768; else { - short s = (ma_int16)(sample + .5f); + short s = (drmp3_int16)(sample + .5f); s -= (s < 0); out[i] = s; } } } -#ifndef MA_DR_MP3_SEEK_LEADING_MP3_FRAMES -#define MA_DR_MP3_SEEK_LEADING_MP3_FRAMES 2 +#include +#if defined(SIZE_MAX) + #define DRMP3_SIZE_MAX SIZE_MAX +#else + #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) + #define DRMP3_SIZE_MAX ((drmp3_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRMP3_SIZE_MAX 0xFFFFFFFF + #endif #endif -#define MA_DR_MP3_MIN_DATA_CHUNK_SIZE 16384 -#ifndef MA_DR_MP3_DATA_CHUNK_SIZE -#define MA_DR_MP3_DATA_CHUNK_SIZE (MA_DR_MP3_MIN_DATA_CHUNK_SIZE*4) +#ifndef DRMP3_SEEK_LEADING_MP3_FRAMES +#define DRMP3_SEEK_LEADING_MP3_FRAMES 2 #endif -#define MA_DR_MP3_COUNTOF(x) (sizeof(x) / sizeof(x[0])) -#define MA_DR_MP3_CLAMP(x, lo, hi) (MA_DR_MP3_MAX(lo, MA_DR_MP3_MIN(x, hi))) -#ifndef MA_DR_MP3_PI_D -#define MA_DR_MP3_PI_D 3.14159265358979323846264 +#define DRMP3_MIN_DATA_CHUNK_SIZE 16384 +#ifndef DRMP3_DATA_CHUNK_SIZE +#define DRMP3_DATA_CHUNK_SIZE DRMP3_MIN_DATA_CHUNK_SIZE*4 #endif -#define MA_DR_MP3_DEFAULT_RESAMPLER_LPF_ORDER 2 -static MA_INLINE float ma_dr_mp3_mix_f32(float x, float y, float a) +#ifndef DRMP3_ASSERT +#include +#define DRMP3_ASSERT(expression) assert(expression) +#endif +#ifndef DRMP3_COPY_MEMORY +#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRMP3_ZERO_MEMORY +#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p))) +#ifndef DRMP3_MALLOC +#define DRMP3_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRMP3_REALLOC +#define DRMP3_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRMP3_FREE +#define DRMP3_FREE(p) free((p)) +#endif +#define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0])) +#define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi))) +#ifndef DRMP3_PI_D +#define DRMP3_PI_D 3.14159265358979323846264 +#endif +#define DRMP3_DEFAULT_RESAMPLER_LPF_ORDER 2 +static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a) { return x*(1-a) + y*a; } -static MA_INLINE float ma_dr_mp3_mix_f32_fast(float x, float y, float a) +static DRMP3_INLINE float drmp3_mix_f32_fast(float x, float y, float a) { float r0 = (y - x); float r1 = r0*a; return x + r1; } -static MA_INLINE ma_uint32 ma_dr_mp3_gcf_u32(ma_uint32 a, ma_uint32 b) +static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b) { for (;;) { if (b == 0) { break; } else { - ma_uint32 t = a; + drmp3_uint32 t = a; a = b; b = t % a; } } return a; } -static void* ma_dr_mp3__malloc_default(size_t sz, void* pUserData) +static DRMP3_INLINE double drmp3_sin(double x) +{ + return sin(x); +} +static DRMP3_INLINE double drmp3_exp(double x) +{ + return exp(x); +} +static DRMP3_INLINE double drmp3_cos(double x) +{ + return drmp3_sin((DRMP3_PI_D*0.5) - x); +} +static void* drmp3__malloc_default(size_t sz, void* pUserData) { (void)pUserData; - return MA_DR_MP3_MALLOC(sz); + return DRMP3_MALLOC(sz); } -static void* ma_dr_mp3__realloc_default(void* p, size_t sz, void* pUserData) +static void* drmp3__realloc_default(void* p, size_t sz, void* pUserData) { (void)pUserData; - return MA_DR_MP3_REALLOC(p, sz); + return DRMP3_REALLOC(p, sz); } -static void ma_dr_mp3__free_default(void* p, void* pUserData) +static void drmp3__free_default(void* p, void* pUserData) { (void)pUserData; - MA_DR_MP3_FREE(p); + DRMP3_FREE(p); } -static void* ma_dr_mp3__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +static void* drmp3__malloc_from_callbacks(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks == NULL) { return NULL; @@ -92445,7 +62801,7 @@ static void* ma_dr_mp3__malloc_from_callbacks(size_t sz, const ma_allocation_cal } return NULL; } -static void* ma_dr_mp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks) +static void* drmp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks == NULL) { return NULL; @@ -92460,14 +62816,14 @@ static void* ma_dr_mp3__realloc_from_callbacks(void* p, size_t szNew, size_t szO return NULL; } if (p != NULL) { - MA_DR_MP3_COPY_MEMORY(p2, p, szOld); + DRMP3_COPY_MEMORY(p2, p, szOld); pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } return p2; } return NULL; } -static void ma_dr_mp3__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +static void drmp3__free_from_callbacks(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (p == NULL || pAllocationCallbacks == NULL) { return; @@ -92476,114 +62832,111 @@ static void ma_dr_mp3__free_from_callbacks(void* p, const ma_allocation_callback pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -static ma_allocation_callbacks ma_dr_mp3_copy_allocation_callbacks_or_defaults(const ma_allocation_callbacks* pAllocationCallbacks) +static drmp3_allocation_callbacks drmp3_copy_allocation_callbacks_or_defaults(const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { return *pAllocationCallbacks; } else { - ma_allocation_callbacks allocationCallbacks; + drmp3_allocation_callbacks allocationCallbacks; allocationCallbacks.pUserData = NULL; - allocationCallbacks.onMalloc = ma_dr_mp3__malloc_default; - allocationCallbacks.onRealloc = ma_dr_mp3__realloc_default; - allocationCallbacks.onFree = ma_dr_mp3__free_default; + allocationCallbacks.onMalloc = drmp3__malloc_default; + allocationCallbacks.onRealloc = drmp3__realloc_default; + allocationCallbacks.onFree = drmp3__free_default; return allocationCallbacks; } } -static size_t ma_dr_mp3__on_read(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) +static size_t drmp3__on_read(drmp3* pMP3, void* pBufferOut, size_t bytesToRead) { size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); pMP3->streamCursor += bytesRead; return bytesRead; } -static ma_bool32 ma_dr_mp3__on_seek(ma_dr_mp3* pMP3, int offset, ma_dr_mp3_seek_origin origin) +static drmp3_bool32 drmp3__on_seek(drmp3* pMP3, int offset, drmp3_seek_origin origin) { - MA_DR_MP3_ASSERT(offset >= 0); + DRMP3_ASSERT(offset >= 0); if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { - return MA_FALSE; + return DRMP3_FALSE; } - if (origin == ma_dr_mp3_seek_origin_start) { - pMP3->streamCursor = (ma_uint64)offset; + if (origin == drmp3_seek_origin_start) { + pMP3->streamCursor = (drmp3_uint64)offset; } else { pMP3->streamCursor += offset; } - return MA_TRUE; + return DRMP3_TRUE; } -static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_mp3_seek_origin origin) +static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_seek_origin origin) { if (offset <= 0x7FFFFFFF) { - return ma_dr_mp3__on_seek(pMP3, (int)offset, origin); + return drmp3__on_seek(pMP3, (int)offset, origin); } - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_start)) { - return MA_FALSE; + if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) { + return DRMP3_FALSE; } offset -= 0x7FFFFFFF; while (offset > 0) { if (offset <= 0x7FFFFFFF) { - if (!ma_dr_mp3__on_seek(pMP3, (int)offset, ma_dr_mp3_seek_origin_current)) { - return MA_FALSE; + if (!drmp3__on_seek(pMP3, (int)offset, drmp3_seek_origin_current)) { + return DRMP3_FALSE; } offset = 0; } else { - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_current)) { - return MA_FALSE; + if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_current)) { + return DRMP3_FALSE; } offset -= 0x7FFFFFFF; } } - return MA_TRUE; + return DRMP3_TRUE; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sample_t* pPCMFrames) { - ma_uint32 pcmFramesRead = 0; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + drmp3_uint32 pcmFramesRead = 0; + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->onRead != NULL); if (pMP3->atEnd) { return 0; } for (;;) { - ma_dr_mp3dec_frame_info info; - if (pMP3->dataSize < MA_DR_MP3_MIN_DATA_CHUNK_SIZE) { + drmp3dec_frame_info info; + if (pMP3->dataSize < DRMP3_MIN_DATA_CHUNK_SIZE) { size_t bytesRead; if (pMP3->pData != NULL) { - MA_DR_MP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); } pMP3->dataConsumed = 0; - if (pMP3->dataCapacity < MA_DR_MP3_DATA_CHUNK_SIZE) { - ma_uint8* pNewData; + if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) { + drmp3_uint8* pNewData; size_t newDataCap; - newDataCap = MA_DR_MP3_DATA_CHUNK_SIZE; - pNewData = (ma_uint8*)ma_dr_mp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks); + newDataCap = DRMP3_DATA_CHUNK_SIZE; + pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks); if (pNewData == NULL) { return 0; } pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { if (pMP3->dataSize == 0) { - pMP3->atEnd = MA_TRUE; + pMP3->atEnd = DRMP3_TRUE; return 0; } } pMP3->dataSize += bytesRead; } if (pMP3->dataSize > INT_MAX) { - pMP3->atEnd = MA_TRUE; + pMP3->atEnd = DRMP3_TRUE; return 0; } - MA_DR_MP3_ASSERT(pMP3->pData != NULL); - MA_DR_MP3_ASSERT(pMP3->dataCapacity > 0); - if (pMP3->pData == NULL) { - return 0; - } - pcmFramesRead = ma_dr_mp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); + DRMP3_ASSERT(pMP3->pData != NULL); + DRMP3_ASSERT(pMP3->dataCapacity > 0); + pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); if (info.frame_bytes > 0) { pMP3->dataConsumed += (size_t)info.frame_bytes; pMP3->dataSize -= (size_t)info.frame_bytes; } if (pcmFramesRead > 0) { - pcmFramesRead = ma_dr_mp3_hdr_frame_samples(pMP3->decoder.header); + pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header); pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; @@ -92591,22 +62944,22 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d break; } else if (info.frame_bytes == 0) { size_t bytesRead; - MA_DR_MP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); pMP3->dataConsumed = 0; if (pMP3->dataCapacity == pMP3->dataSize) { - ma_uint8* pNewData; + drmp3_uint8* pNewData; size_t newDataCap; - newDataCap = pMP3->dataCapacity + MA_DR_MP3_DATA_CHUNK_SIZE; - pNewData = (ma_uint8*)ma_dr_mp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks); + newDataCap = pMP3->dataCapacity + DRMP3_DATA_CHUNK_SIZE; + pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks); if (pNewData == NULL) { return 0; } pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { - pMP3->atEnd = MA_TRUE; + pMP3->atEnd = DRMP3_TRUE; return 0; } pMP3->dataSize += bytesRead; @@ -92614,52 +62967,44 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d }; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sample_t* pPCMFrames) { - ma_uint32 pcmFramesRead = 0; - ma_dr_mp3dec_frame_info info; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->memory.pData != NULL); + drmp3_uint32 pcmFramesRead = 0; + drmp3dec_frame_info info; + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->memory.pData != NULL); if (pMP3->atEnd) { return 0; } - for (;;) { - pcmFramesRead = ma_dr_mp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info); - if (pcmFramesRead > 0) { - pcmFramesRead = ma_dr_mp3_hdr_frame_samples(pMP3->decoder.header); - pMP3->pcmFramesConsumedInMP3Frame = 0; - pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; - pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; - break; - } else if (info.frame_bytes > 0) { - pMP3->memory.currentReadPos += (size_t)info.frame_bytes; - } else { - break; - } + pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info); + if (pcmFramesRead > 0) { + pMP3->pcmFramesConsumedInMP3Frame = 0; + pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; + pMP3->mp3FrameChannels = info.channels; + pMP3->mp3FrameSampleRate = info.hz; } pMP3->memory.currentReadPos += (size_t)info.frame_bytes; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames) { if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { - return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); + return drmp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); } else { - return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); + return drmp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); } } -static ma_uint32 ma_dr_mp3_decode_next_frame(ma_dr_mp3* pMP3) +static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3) { - MA_DR_MP3_ASSERT(pMP3 != NULL); - return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames); + DRMP3_ASSERT(pMP3 != NULL); + return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames); } #if 0 -static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) +static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3) { - ma_uint32 pcmFrameCount; - MA_DR_MP3_ASSERT(pMP3 != NULL); - pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + drmp3_uint32 pcmFrameCount; + DRMP3_ASSERT(pMP3 != NULL); + pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL); if (pcmFrameCount == 0) { return 0; } @@ -92669,55 +63014,55 @@ static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) return pcmFrameCount; } #endif -static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks) { - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(onRead != NULL); - ma_dr_mp3dec_init(&pMP3->decoder); + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(onRead != NULL); + drmp3dec_init(&pMP3->decoder); pMP3->onRead = onRead; pMP3->onSeek = onSeek; pMP3->pUserData = pUserData; - pMP3->allocationCallbacks = ma_dr_mp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + pMP3->allocationCallbacks = drmp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { - return MA_FALSE; + return DRMP3_FALSE; } - if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { - ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); - return MA_FALSE; + if (!drmp3_decode_next_frame(pMP3)) { + drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); + return DRMP3_FALSE; } pMP3->channels = pMP3->mp3FrameChannels; pMP3->sampleRate = pMP3->mp3FrameSampleRate; - return MA_TRUE; + return DRMP3_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL || onRead == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } - MA_DR_MP3_ZERO_OBJECT(pMP3); - return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); + DRMP3_ZERO_OBJECT(pMP3); + return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); } -static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { - ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + drmp3* pMP3 = (drmp3*)pUserData; size_t bytesRemaining; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->memory.dataSize >= pMP3->memory.currentReadPos); + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->memory.dataSize >= pMP3->memory.currentReadPos); bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } if (bytesToRead > 0) { - MA_DR_MP3_COPY_MEMORY(pBufferOut, pMP3->memory.pData + pMP3->memory.currentReadPos, bytesToRead); + DRMP3_COPY_MEMORY(pBufferOut, pMP3->memory.pData + pMP3->memory.currentReadPos, bytesToRead); pMP3->memory.currentReadPos += bytesToRead; } return bytesToRead; } -static ma_bool32 ma_dr_mp3__on_seek_memory(void* pUserData, int byteOffset, ma_dr_mp3_seek_origin origin) +static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin) { - ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; - MA_DR_MP3_ASSERT(pMP3 != NULL); - if (origin == ma_dr_mp3_seek_origin_current) { + drmp3* pMP3 = (drmp3*)pUserData; + DRMP3_ASSERT(pMP3 != NULL); + if (origin == drmp3_seek_origin_current) { if (byteOffset > 0) { if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); @@ -92729,75 +63074,580 @@ static ma_bool32 ma_dr_mp3__on_seek_memory(void* pUserData, int byteOffset, ma_d } pMP3->memory.currentReadPos += byteOffset; } else { - if ((ma_uint32)byteOffset <= pMP3->memory.dataSize) { + if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) { pMP3->memory.currentReadPos = byteOffset; } else { pMP3->memory.currentReadPos = pMP3->memory.dataSize; } } - return MA_TRUE; + return DRMP3_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } - MA_DR_MP3_ZERO_OBJECT(pMP3); + DRMP3_ZERO_OBJECT(pMP3); if (pData == NULL || dataSize == 0) { - return MA_FALSE; + return DRMP3_FALSE; } - pMP3->memory.pData = (const ma_uint8*)pData; + pMP3->memory.pData = (const drmp3_uint8*)pData; pMP3->memory.dataSize = dataSize; pMP3->memory.currentReadPos = 0; - return ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, pMP3, pAllocationCallbacks); + return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pAllocationCallbacks); } -#ifndef MA_DR_MP3_NO_STDIO +#ifndef DR_MP3_NO_STDIO #include #include -static size_t ma_dr_mp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) +#include +static drmp3_result drmp3_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRMP3_SUCCESS; + #ifdef EPERM + case EPERM: return DRMP3_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRMP3_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRMP3_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRMP3_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRMP3_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRMP3_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRMP3_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRMP3_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRMP3_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRMP3_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRMP3_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRMP3_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRMP3_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRMP3_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRMP3_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRMP3_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRMP3_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRMP3_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRMP3_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRMP3_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRMP3_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRMP3_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRMP3_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRMP3_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRMP3_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRMP3_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRMP3_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRMP3_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRMP3_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRMP3_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRMP3_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRMP3_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRMP3_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRMP3_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRMP3_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRMP3_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRMP3_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRMP3_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return DRMP3_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRMP3_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRMP3_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRMP3_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRMP3_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRMP3_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRMP3_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRMP3_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRMP3_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRMP3_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRMP3_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRMP3_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRMP3_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRMP3_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRMP3_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRMP3_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRMP3_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRMP3_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRMP3_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRMP3_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRMP3_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRMP3_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRMP3_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRMP3_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRMP3_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRMP3_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRMP3_ERROR; + #endif + #ifdef EADV + case EADV: return DRMP3_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRMP3_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRMP3_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRMP3_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRMP3_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRMP3_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRMP3_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRMP3_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRMP3_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRMP3_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRMP3_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRMP3_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRMP3_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRMP3_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRMP3_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRMP3_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRMP3_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRMP3_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRMP3_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRMP3_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRMP3_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRMP3_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRMP3_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRMP3_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRMP3_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRMP3_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRMP3_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRMP3_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRMP3_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRMP3_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRMP3_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRMP3_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRMP3_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRMP3_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRMP3_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRMP3_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRMP3_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRMP3_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRMP3_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRMP3_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRMP3_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRMP3_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRMP3_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRMP3_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRMP3_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRMP3_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRMP3_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRMP3_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRMP3_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRMP3_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRMP3_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRMP3_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRMP3_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRMP3_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRMP3_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRMP3_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRMP3_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRMP3_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRMP3_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRMP3_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRMP3_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRMP3_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRMP3_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRMP3_ERROR; + #endif + default: return DRMP3_ERROR; + } +} +static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err; +#endif + if (ppFile != NULL) { + *ppFile = NULL; + } + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRMP3_INVALID_ARGS; + } +#if defined(_MSC_VER) && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drmp3_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drmp3_result result = drmp3_result_from_errno(errno); + if (result == DRMP3_SUCCESS) { + result = DRMP3_ERROR; + } + return result; + } +#endif + return DRMP3_SUCCESS; +} +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRMP3_HAS_WFOPEN + #endif +#endif +static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; + } + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRMP3_INVALID_ARGS; + } +#if defined(DRMP3_HAS_WFOPEN) + { + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drmp3_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drmp3_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + DRMP3_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drmp3_result_from_errno(errno); + } + pFilePathMB = (char*)drmp3__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRMP3_OUT_OF_MEMORY; + } + pFilePathTemp = pFilePath; + DRMP3_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + *ppFile = fopen(pFilePathMB, pOpenModeMB); + drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + if (*ppFile == NULL) { + return DRMP3_ERROR; + } +#endif + return DRMP3_SUCCESS; +} +static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) { return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); } -static ma_bool32 ma_dr_mp3__on_seek_stdio(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) +static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_mp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + return fseek((FILE*)pUserData, offset, (origin == drmp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } -MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_bool32 result; + drmp3_bool32 result; FILE* pFile; - if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { - return MA_FALSE; + if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) { + return DRMP3_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); - if (result != MA_TRUE) { + result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRMP3_TRUE) { fclose(pFile); return result; } - return MA_TRUE; + return DRMP3_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_bool32 result; + drmp3_bool32 result; FILE* pFile; - if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { - return MA_FALSE; + if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) { + return DRMP3_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); - if (result != MA_TRUE) { + result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRMP3_TRUE) { fclose(pFile); return result; } - return MA_TRUE; + return DRMP3_TRUE; } #endif -MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) +DRMP3_API void drmp3_uninit(drmp3* pMP3) { if (pMP3 == NULL) { return; } -#ifndef MA_DR_MP3_NO_STDIO - if (pMP3->onRead == ma_dr_mp3__on_read_stdio) { +#ifndef DR_MP3_NO_STDIO + if (pMP3->onRead == drmp3__on_read_stdio) { FILE* pFile = (FILE*)pMP3->pUserData; if (pFile != NULL) { fclose(pFile); @@ -92805,14 +63655,14 @@ MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) } } #endif - ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); + drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); } -#if defined(MA_DR_MP3_FLOAT_OUTPUT) -static void ma_dr_mp3_f32_to_s16(ma_int16* dst, const float* src, ma_uint64 sampleCount) +#if defined(DR_MP3_FLOAT_OUTPUT) +static void drmp3_f32_to_s16(drmp3_int16* dst, const float* src, drmp3_uint64 sampleCount) { - ma_uint64 i; - ma_uint64 i4; - ma_uint64 sampleCount4; + drmp3_uint64 i; + drmp3_uint64 i4; + drmp3_uint64 sampleCount4; i = 0; sampleCount4 = sampleCount >> 2; for (i4 = 0; i4 < sampleCount4; i4 += 1) { @@ -92828,24 +63678,24 @@ static void ma_dr_mp3_f32_to_s16(ma_int16* dst, const float* src, ma_uint64 samp x1 = x1 * 32767.0f; x2 = x2 * 32767.0f; x3 = x3 * 32767.0f; - dst[i+0] = (ma_int16)x0; - dst[i+1] = (ma_int16)x1; - dst[i+2] = (ma_int16)x2; - dst[i+3] = (ma_int16)x3; + dst[i+0] = (drmp3_int16)x0; + dst[i+1] = (drmp3_int16)x1; + dst[i+2] = (drmp3_int16)x2; + dst[i+3] = (drmp3_int16)x3; i += 4; } for (; i < sampleCount; i += 1) { float x = src[i]; x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); x = x * 32767.0f; - dst[i] = (ma_int16)x; + dst[i] = (drmp3_int16)x; } } #endif -#if !defined(MA_DR_MP3_FLOAT_OUTPUT) -static void ma_dr_mp3_s16_to_f32(float* dst, const ma_int16* src, ma_uint64 sampleCount) +#if !defined(DR_MP3_FLOAT_OUTPUT) +static void drmp3_s16_to_f32(float* dst, const drmp3_int16* src, drmp3_uint64 sampleCount) { - ma_uint64 i; + drmp3_uint64 i; for (i = 0; i < sampleCount; i += 1) { float x = (float)src[i]; x = x * 0.000030517578125f; @@ -92853,22 +63703,22 @@ static void ma_dr_mp3_s16_to_f32(float* dst, const ma_int16* src, ma_uint64 samp } } #endif -static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 framesToRead, void* pBufferOut) +static drmp3_uint64 drmp3_read_pcm_frames_raw(drmp3* pMP3, drmp3_uint64 framesToRead, void* pBufferOut) { - ma_uint64 totalFramesRead = 0; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + drmp3_uint64 totalFramesRead = 0; + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->onRead != NULL); while (framesToRead > 0) { - ma_uint32 framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + drmp3_uint32 framesToConsume = (drmp3_uint32)DRMP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); if (pBufferOut != NULL) { - #if defined(MA_DR_MP3_FLOAT_OUTPUT) - float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); - float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); + #if defined(DR_MP3_FLOAT_OUTPUT) + float* pFramesOutF32 = (float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); + float* pFramesInF32 = (float*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + DRMP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); #else - ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); - ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); + drmp3_int16* pFramesOutS16 = (drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalFramesRead * pMP3->channels); + drmp3_int16* pFramesInS16 = (drmp3_int16*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(drmp3_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + DRMP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(drmp3_int16) * framesToConsume * pMP3->channels); #endif } pMP3->currentPCMFrame += framesToConsume; @@ -92879,125 +63729,125 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames if (framesToRead == 0) { break; } - MA_DR_MP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); - if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { + DRMP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); + if (drmp3_decode_next_frame(pMP3) == 0) { break; } } return totalFramesRead; } -MA_API ma_uint64 ma_dr_mp3_read_pcm_frames_f32(ma_dr_mp3* pMP3, ma_uint64 framesToRead, float* pBufferOut) +DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut) { if (pMP3 == NULL || pMP3->onRead == NULL) { return 0; } -#if defined(MA_DR_MP3_FLOAT_OUTPUT) - return ma_dr_mp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut); +#if defined(DR_MP3_FLOAT_OUTPUT) + return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut); #else { - ma_int16 pTempS16[8192]; - ma_uint64 totalPCMFramesRead = 0; + drmp3_int16 pTempS16[8192]; + drmp3_uint64 totalPCMFramesRead = 0; while (totalPCMFramesRead < framesToRead) { - ma_uint64 framesJustRead; - ma_uint64 framesRemaining = framesToRead - totalPCMFramesRead; - ma_uint64 framesToReadNow = MA_DR_MP3_COUNTOF(pTempS16) / pMP3->channels; + drmp3_uint64 framesJustRead; + drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead; + drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempS16) / pMP3->channels; if (framesToReadNow > framesRemaining) { framesToReadNow = framesRemaining; } - framesJustRead = ma_dr_mp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempS16); + framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempS16); if (framesJustRead == 0) { break; } - ma_dr_mp3_s16_to_f32((float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels); + drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels); totalPCMFramesRead += framesJustRead; } return totalPCMFramesRead; } #endif } -MA_API ma_uint64 ma_dr_mp3_read_pcm_frames_s16(ma_dr_mp3* pMP3, ma_uint64 framesToRead, ma_int16* pBufferOut) +DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut) { if (pMP3 == NULL || pMP3->onRead == NULL) { return 0; } -#if !defined(MA_DR_MP3_FLOAT_OUTPUT) - return ma_dr_mp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut); +#if !defined(DR_MP3_FLOAT_OUTPUT) + return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut); #else { float pTempF32[4096]; - ma_uint64 totalPCMFramesRead = 0; + drmp3_uint64 totalPCMFramesRead = 0; while (totalPCMFramesRead < framesToRead) { - ma_uint64 framesJustRead; - ma_uint64 framesRemaining = framesToRead - totalPCMFramesRead; - ma_uint64 framesToReadNow = MA_DR_MP3_COUNTOF(pTempF32) / pMP3->channels; + drmp3_uint64 framesJustRead; + drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead; + drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempF32) / pMP3->channels; if (framesToReadNow > framesRemaining) { framesToReadNow = framesRemaining; } - framesJustRead = ma_dr_mp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempF32); + framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempF32); if (framesJustRead == 0) { break; } - ma_dr_mp3_f32_to_s16((ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalPCMFramesRead * pMP3->channels), pTempF32, framesJustRead * pMP3->channels); + drmp3_f32_to_s16((drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalPCMFramesRead * pMP3->channels), pTempF32, framesJustRead * pMP3->channels); totalPCMFramesRead += framesJustRead; } return totalPCMFramesRead; } #endif } -static void ma_dr_mp3_reset(ma_dr_mp3* pMP3) +static void drmp3_reset(drmp3* pMP3) { - MA_DR_MP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3 != NULL); pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = 0; pMP3->currentPCMFrame = 0; pMP3->dataSize = 0; - pMP3->atEnd = MA_FALSE; - ma_dr_mp3dec_init(&pMP3->decoder); + pMP3->atEnd = DRMP3_FALSE; + drmp3dec_init(&pMP3->decoder); } -static ma_bool32 ma_dr_mp3_seek_to_start_of_stream(ma_dr_mp3* pMP3) +static drmp3_bool32 drmp3_seek_to_start_of_stream(drmp3* pMP3) { - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->onSeek != NULL); - if (!ma_dr_mp3__on_seek(pMP3, 0, ma_dr_mp3_seek_origin_start)) { - return MA_FALSE; + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->onSeek != NULL); + if (!drmp3__on_seek(pMP3, 0, drmp3_seek_origin_start)) { + return DRMP3_FALSE; } - ma_dr_mp3_reset(pMP3); - return MA_TRUE; + drmp3_reset(pMP3); + return DRMP3_TRUE; } -static ma_bool32 ma_dr_mp3_seek_forward_by_pcm_frames__brute_force(ma_dr_mp3* pMP3, ma_uint64 frameOffset) +static drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_uint64 frameOffset) { - ma_uint64 framesRead; -#if defined(MA_DR_MP3_FLOAT_OUTPUT) - framesRead = ma_dr_mp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); + drmp3_uint64 framesRead; +#if defined(DR_MP3_FLOAT_OUTPUT) + framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); #else - framesRead = ma_dr_mp3_read_pcm_frames_s16(pMP3, frameOffset, NULL); + framesRead = drmp3_read_pcm_frames_s16(pMP3, frameOffset, NULL); #endif if (framesRead != frameOffset) { - return MA_FALSE; + return DRMP3_FALSE; } - return MA_TRUE; + return DRMP3_TRUE; } -static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__brute_force(ma_dr_mp3* pMP3, ma_uint64 frameIndex) +static drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 frameIndex) { - MA_DR_MP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3 != NULL); if (frameIndex == pMP3->currentPCMFrame) { - return MA_TRUE; + return DRMP3_TRUE; } if (frameIndex < pMP3->currentPCMFrame) { - if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { - return MA_FALSE; + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; } } - MA_DR_MP3_ASSERT(frameIndex >= pMP3->currentPCMFrame); - return ma_dr_mp3_seek_forward_by_pcm_frames__brute_force(pMP3, (frameIndex - pMP3->currentPCMFrame)); + DRMP3_ASSERT(frameIndex >= pMP3->currentPCMFrame); + return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, (frameIndex - pMP3->currentPCMFrame)); } -static ma_bool32 ma_dr_mp3_find_closest_seek_point(ma_dr_mp3* pMP3, ma_uint64 frameIndex, ma_uint32* pSeekPointIndex) +static drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_uint32* pSeekPointIndex) { - ma_uint32 iSeekPoint; - MA_DR_MP3_ASSERT(pSeekPointIndex != NULL); + drmp3_uint32 iSeekPoint; + DRMP3_ASSERT(pSeekPointIndex != NULL); *pSeekPointIndex = 0; if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) { - return MA_FALSE; + return DRMP3_FALSE; } for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) { if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) { @@ -93005,18 +63855,18 @@ static ma_bool32 ma_dr_mp3_find_closest_seek_point(ma_dr_mp3* pMP3, ma_uint64 fr } *pSeekPointIndex = iSeekPoint; } - return MA_TRUE; + return DRMP3_TRUE; } -static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uint64 frameIndex) +static drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frameIndex) { - ma_dr_mp3_seek_point seekPoint; - ma_uint32 priorSeekPointIndex; - ma_uint16 iMP3Frame; - ma_uint64 leftoverFrames; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->pSeekPoints != NULL); - MA_DR_MP3_ASSERT(pMP3->seekPointCount > 0); - if (ma_dr_mp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) { + drmp3_seek_point seekPoint; + drmp3_uint32 priorSeekPointIndex; + drmp3_uint16 iMP3Frame; + drmp3_uint64 leftoverFrames; + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->pSeekPoints != NULL); + DRMP3_ASSERT(pMP3->seekPointCount > 0); + if (drmp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) { seekPoint = pMP3->pSeekPoints[priorSeekPointIndex]; } else { seekPoint.seekPosInBytes = 0; @@ -93024,71 +63874,71 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin seekPoint.mp3FramesToDiscard = 0; seekPoint.pcmFramesToDiscard = 0; } - if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, ma_dr_mp3_seek_origin_start)) { - return MA_FALSE; + if (!drmp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, drmp3_seek_origin_start)) { + return DRMP3_FALSE; } - ma_dr_mp3_reset(pMP3); + drmp3_reset(pMP3); for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) { - ma_uint32 pcmFramesRead; - ma_dr_mp3d_sample_t* pPCMFrames; + drmp3_uint32 pcmFramesRead; + drmp3d_sample_t* pPCMFrames; pPCMFrames = NULL; if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { - pPCMFrames = (ma_dr_mp3d_sample_t*)pMP3->pcmFrames; + pPCMFrames = (drmp3d_sample_t*)pMP3->pcmFrames; } - pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames); + pcmFramesRead = drmp3_decode_next_frame_ex(pMP3, pPCMFrames); if (pcmFramesRead == 0) { - return MA_FALSE; + return DRMP3_FALSE; } } pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard; leftoverFrames = frameIndex - pMP3->currentPCMFrame; - return ma_dr_mp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames); + return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames); } -MA_API ma_bool32 ma_dr_mp3_seek_to_pcm_frame(ma_dr_mp3* pMP3, ma_uint64 frameIndex) +DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex) { if (pMP3 == NULL || pMP3->onSeek == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } if (frameIndex == 0) { - return ma_dr_mp3_seek_to_start_of_stream(pMP3); + return drmp3_seek_to_start_of_stream(pMP3); } if (pMP3->pSeekPoints != NULL && pMP3->seekPointCount > 0) { - return ma_dr_mp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex); + return drmp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex); } else { - return ma_dr_mp3_seek_to_pcm_frame__brute_force(pMP3, frameIndex); + return drmp3_seek_to_pcm_frame__brute_force(pMP3, frameIndex); } } -MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint64* pMP3FrameCount, ma_uint64* pPCMFrameCount) +DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount) { - ma_uint64 currentPCMFrame; - ma_uint64 totalPCMFrameCount; - ma_uint64 totalMP3FrameCount; + drmp3_uint64 currentPCMFrame; + drmp3_uint64 totalPCMFrameCount; + drmp3_uint64 totalMP3FrameCount; if (pMP3 == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } if (pMP3->onSeek == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } currentPCMFrame = pMP3->currentPCMFrame; - if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { - return MA_FALSE; + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; } totalPCMFrameCount = 0; totalMP3FrameCount = 0; for (;;) { - ma_uint32 pcmFramesInCurrentMP3Frame; - pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + drmp3_uint32 pcmFramesInCurrentMP3Frame; + pcmFramesInCurrentMP3Frame = drmp3_decode_next_frame_ex(pMP3, NULL); if (pcmFramesInCurrentMP3Frame == 0) { break; } totalPCMFrameCount += pcmFramesInCurrentMP3Frame; totalMP3FrameCount += 1; } - if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { - return MA_FALSE; + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; } - if (!ma_dr_mp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { - return MA_FALSE; + if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { + return DRMP3_FALSE; } if (pMP3FrameCount != NULL) { *pMP3FrameCount = totalMP3FrameCount; @@ -93096,89 +63946,89 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 if (pPCMFrameCount != NULL) { *pPCMFrameCount = totalPCMFrameCount; } - return MA_TRUE; + return DRMP3_TRUE; } -MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3) +DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3) { - ma_uint64 totalPCMFrameCount; - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + drmp3_uint64 totalPCMFrameCount; + if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { return 0; } return totalPCMFrameCount; } -MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3) +DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3) { - ma_uint64 totalMP3FrameCount; - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, NULL)) { + drmp3_uint64 totalMP3FrameCount; + if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, NULL)) { return 0; } return totalMP3FrameCount; } -static void ma_dr_mp3__accumulate_running_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint32 pcmFrameCountIn, ma_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart) +static void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFrameCountIn, drmp3_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart) { float srcRatio; float pcmFrameCountOutF; - ma_uint32 pcmFrameCountOut; + drmp3_uint32 pcmFrameCountOut; srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; - MA_DR_MP3_ASSERT(srcRatio > 0); + DRMP3_ASSERT(srcRatio > 0); pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio); - pcmFrameCountOut = (ma_uint32)pcmFrameCountOutF; + pcmFrameCountOut = (drmp3_uint32)pcmFrameCountOutF; *pRunningPCMFrameCountFractionalPart = pcmFrameCountOutF - pcmFrameCountOut; *pRunningPCMFrameCount += pcmFrameCountOut; } typedef struct { - ma_uint64 bytePos; - ma_uint64 pcmFrameIndex; -} ma_dr_mp3__seeking_mp3_frame_info; -MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSeekPointCount, ma_dr_mp3_seek_point* pSeekPoints) + drmp3_uint64 bytePos; + drmp3_uint64 pcmFrameIndex; +} drmp3__seeking_mp3_frame_info; +DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints) { - ma_uint32 seekPointCount; - ma_uint64 currentPCMFrame; - ma_uint64 totalMP3FrameCount; - ma_uint64 totalPCMFrameCount; + drmp3_uint32 seekPointCount; + drmp3_uint64 currentPCMFrame; + drmp3_uint64 totalMP3FrameCount; + drmp3_uint64 totalPCMFrameCount; if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } seekPointCount = *pSeekPointCount; if (seekPointCount == 0) { - return MA_FALSE; + return DRMP3_FALSE; } currentPCMFrame = pMP3->currentPCMFrame; - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) { - return MA_FALSE; + if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) { + return DRMP3_FALSE; } - if (totalMP3FrameCount < MA_DR_MP3_SEEK_LEADING_MP3_FRAMES+1) { + if (totalMP3FrameCount < DRMP3_SEEK_LEADING_MP3_FRAMES+1) { seekPointCount = 1; pSeekPoints[0].seekPosInBytes = 0; pSeekPoints[0].pcmFrameIndex = 0; pSeekPoints[0].mp3FramesToDiscard = 0; pSeekPoints[0].pcmFramesToDiscard = 0; } else { - ma_uint64 pcmFramesBetweenSeekPoints; - ma_dr_mp3__seeking_mp3_frame_info mp3FrameInfo[MA_DR_MP3_SEEK_LEADING_MP3_FRAMES+1]; - ma_uint64 runningPCMFrameCount = 0; + drmp3_uint64 pcmFramesBetweenSeekPoints; + drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1]; + drmp3_uint64 runningPCMFrameCount = 0; float runningPCMFrameCountFractionalPart = 0; - ma_uint64 nextTargetPCMFrame; - ma_uint32 iMP3Frame; - ma_uint32 iSeekPoint; + drmp3_uint64 nextTargetPCMFrame; + drmp3_uint32 iMP3Frame; + drmp3_uint32 iSeekPoint; if (seekPointCount > totalMP3FrameCount-1) { - seekPointCount = (ma_uint32)totalMP3FrameCount-1; + seekPointCount = (drmp3_uint32)totalMP3FrameCount-1; } pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1); - if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { - return MA_FALSE; + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; } - for (iMP3Frame = 0; iMP3Frame < MA_DR_MP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) { - ma_uint32 pcmFramesInCurrentMP3FrameIn; - MA_DR_MP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); + for (iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) { + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; + DRMP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { - return MA_FALSE; + return DRMP3_FALSE; } - ma_dr_mp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); + drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); } nextTargetPCMFrame = 0; for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) { @@ -93187,43 +64037,43 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe if (nextTargetPCMFrame < runningPCMFrameCount) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; - pSeekPoints[iSeekPoint].mp3FramesToDiscard = MA_DR_MP3_SEEK_LEADING_MP3_FRAMES; - pSeekPoints[iSeekPoint].pcmFramesToDiscard = (ma_uint16)(nextTargetPCMFrame - mp3FrameInfo[MA_DR_MP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex); + pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES; + pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex); break; } else { size_t i; - ma_uint32 pcmFramesInCurrentMP3FrameIn; - for (i = 0; i < MA_DR_MP3_COUNTOF(mp3FrameInfo)-1; ++i) { + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; + for (i = 0; i < DRMP3_COUNTOF(mp3FrameInfo)-1; ++i) { mp3FrameInfo[i] = mp3FrameInfo[i+1]; } - mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; - mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; + mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; - pSeekPoints[iSeekPoint].mp3FramesToDiscard = MA_DR_MP3_SEEK_LEADING_MP3_FRAMES; - pSeekPoints[iSeekPoint].pcmFramesToDiscard = (ma_uint16)(nextTargetPCMFrame - mp3FrameInfo[MA_DR_MP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex); + pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES; + pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex); break; } - ma_dr_mp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); + drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); } } } - if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { - return MA_FALSE; + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; } - if (!ma_dr_mp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { - return MA_FALSE; + if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { + return DRMP3_FALSE; } } *pSeekPointCount = seekPointCount; - return MA_TRUE; + return DRMP3_TRUE; } -MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints) +DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints) { if (pMP3 == NULL) { - return MA_FALSE; + return DRMP3_FALSE; } if (seekPointCount == 0 || pSeekPoints == NULL) { pMP3->seekPointCount = 0; @@ -93232,25 +64082,25 @@ MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointC pMP3->seekPointCount = seekPointCount; pMP3->pSeekPoints = pSeekPoints; } - return MA_TRUE; + return DRMP3_TRUE; } -static float* ma_dr_mp3__full_read_and_close_f32(ma_dr_mp3* pMP3, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount) +static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) { - ma_uint64 totalFramesRead = 0; - ma_uint64 framesCapacity = 0; + drmp3_uint64 totalFramesRead = 0; + drmp3_uint64 framesCapacity = 0; float* pFrames = NULL; float temp[4096]; - MA_DR_MP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3 != NULL); for (;;) { - ma_uint64 framesToReadRightNow = MA_DR_MP3_COUNTOF(temp) / pMP3->channels; - ma_uint64 framesJustRead = ma_dr_mp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp); + drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels; + drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp); if (framesJustRead == 0) { break; } if (framesCapacity < totalFramesRead + framesJustRead) { - ma_uint64 oldFramesBufferSize; - ma_uint64 newFramesBufferSize; - ma_uint64 newFramesCap; + drmp3_uint64 oldFramesBufferSize; + drmp3_uint64 newFramesBufferSize; + drmp3_uint64 newFramesCap; float* pNewFrames; newFramesCap = framesCapacity * 2; if (newFramesCap < totalFramesRead + framesJustRead) { @@ -93258,18 +64108,18 @@ static float* ma_dr_mp3__full_read_and_close_f32(ma_dr_mp3* pMP3, ma_dr_mp3_conf } oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float); newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float); - if (newFramesBufferSize > (ma_uint64)MA_SIZE_MAX) { + if (newFramesBufferSize > DRMP3_SIZE_MAX) { break; } - pNewFrames = (float*)ma_dr_mp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); + pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); if (pNewFrames == NULL) { - ma_dr_mp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); + drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); break; } pFrames = pNewFrames; framesCapacity = newFramesCap; } - MA_DR_MP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float))); + DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float))); totalFramesRead += framesJustRead; if (framesJustRead != framesToReadRightNow) { break; @@ -93279,48 +64129,48 @@ static float* ma_dr_mp3__full_read_and_close_f32(ma_dr_mp3* pMP3, ma_dr_mp3_conf pConfig->channels = pMP3->channels; pConfig->sampleRate = pMP3->sampleRate; } - ma_dr_mp3_uninit(pMP3); + drmp3_uninit(pMP3); if (pTotalFrameCount) { *pTotalFrameCount = totalFramesRead; } return pFrames; } -static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount) +static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) { - ma_uint64 totalFramesRead = 0; - ma_uint64 framesCapacity = 0; - ma_int16* pFrames = NULL; - ma_int16 temp[4096]; - MA_DR_MP3_ASSERT(pMP3 != NULL); + drmp3_uint64 totalFramesRead = 0; + drmp3_uint64 framesCapacity = 0; + drmp3_int16* pFrames = NULL; + drmp3_int16 temp[4096]; + DRMP3_ASSERT(pMP3 != NULL); for (;;) { - ma_uint64 framesToReadRightNow = MA_DR_MP3_COUNTOF(temp) / pMP3->channels; - ma_uint64 framesJustRead = ma_dr_mp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp); + drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels; + drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp); if (framesJustRead == 0) { break; } if (framesCapacity < totalFramesRead + framesJustRead) { - ma_uint64 newFramesBufferSize; - ma_uint64 oldFramesBufferSize; - ma_uint64 newFramesCap; - ma_int16* pNewFrames; + drmp3_uint64 newFramesBufferSize; + drmp3_uint64 oldFramesBufferSize; + drmp3_uint64 newFramesCap; + drmp3_int16* pNewFrames; newFramesCap = framesCapacity * 2; if (newFramesCap < totalFramesRead + framesJustRead) { newFramesCap = totalFramesRead + framesJustRead; } - oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(ma_int16); - newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(ma_int16); - if (newFramesBufferSize > (ma_uint64)MA_SIZE_MAX) { + oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16); + newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16); + if (newFramesBufferSize > DRMP3_SIZE_MAX) { break; } - pNewFrames = (ma_int16*)ma_dr_mp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); + pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); if (pNewFrames == NULL) { - ma_dr_mp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); + drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); break; } pFrames = pNewFrames; framesCapacity = newFramesCap; } - MA_DR_MP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(ma_int16))); + DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16))); totalFramesRead += framesJustRead; if (framesJustRead != framesToReadRightNow) { break; @@ -93330,81 +64180,81 @@ static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_c pConfig->channels = pMP3->channels; pConfig->sampleRate = pMP3->sampleRate; } - ma_dr_mp3_uninit(pMP3); + drmp3_uninit(pMP3); if (pTotalFrameCount) { *pTotalFrameCount = totalFramesRead; } return pFrames; } -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + drmp3 mp3; + if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + drmp3 mp3; + if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); } -MA_API float* ma_dr_mp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3 mp3; - if (!ma_dr_mp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { + drmp3 mp3; + if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { return NULL; } - return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3 mp3; - if (!ma_dr_mp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { + drmp3 mp3; + if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { return NULL; } - return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); } -#ifndef MA_DR_MP3_NO_STDIO -MA_API float* ma_dr_mp3_open_file_and_read_pcm_frames_f32(const char* filePath, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +#ifndef DR_MP3_NO_STDIO +DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3 mp3; - if (!ma_dr_mp3_init_file(&mp3, filePath, pAllocationCallbacks)) { + drmp3 mp3; + if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) { return NULL; } - return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_file_and_read_pcm_frames_s16(const char* filePath, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3 mp3; - if (!ma_dr_mp3_init_file(&mp3, filePath, pAllocationCallbacks)) { + drmp3 mp3; + if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) { return NULL; } - return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); } #endif -MA_API void* ma_dr_mp3_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { - return ma_dr_mp3__malloc_from_callbacks(sz, pAllocationCallbacks); + return drmp3__malloc_from_callbacks(sz, pAllocationCallbacks); } else { - return ma_dr_mp3__malloc_default(sz, NULL); + return drmp3__malloc_default(sz, NULL); } } -MA_API void ma_dr_mp3_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { - ma_dr_mp3__free_from_callbacks(p, pAllocationCallbacks); + drmp3__free_from_callbacks(p, pAllocationCallbacks); } else { - ma_dr_mp3__free_default(p, NULL); + drmp3__free_default(p, NULL); } } #endif /* dr_mp3_c end */ -#endif /* MA_DR_MP3_IMPLEMENTATION */ +#endif /* DRMP3_IMPLEMENTATION */ #endif /* MA_NO_MP3 */ @@ -93416,6 +64266,1033 @@ MA_API void ma_dr_mp3_free(void* p, const ma_allocation_callbacks* pAllocationCa #endif /* miniaudio_c */ #endif /* MINIAUDIO_IMPLEMENTATION */ +/* +RELEASE NOTES - VERSION 0.10.x +============================== +Version 0.10 includes major API changes and refactoring, mostly concerned with the data conversion system. Data conversion is performed internally to convert +audio data between the format requested when initializing the `ma_device` object and the format of the internal device used by the backend. The same applies +to the `ma_decoder` object. The previous design has several design flaws and missing features which necessitated a complete redesign. + + +Changes to Data Conversion +-------------------------- +The previous data conversion system used callbacks to deliver input data for conversion. This design works well in some specific situations, but in other +situations it has some major readability and maintenance issues. The decision was made to replace this with a more iterative approach where you just pass in a +pointer to the input data directly rather than dealing with a callback. + +The following are the data conversion APIs that have been removed and their replacements: + + - ma_format_converter -> ma_convert_pcm_frames_format() + - ma_channel_router -> ma_channel_converter + - ma_src -> ma_resampler + - ma_pcm_converter -> ma_data_converter + +The previous conversion APIs accepted a callback in their configs. There are no longer any callbacks to deal with. Instead you just pass the data into the +`*_process_pcm_frames()` function as a pointer to a buffer. + +The simplest aspect of data conversion is sample format conversion. To convert between two formats, just call `ma_convert_pcm_frames_format()`. Channel +conversion is also simple which you can do with `ma_channel_converter` via `ma_channel_converter_process_pcm_frames()`. + +Resampling is more complicated because the number of output frames that are processed is different to the number of input frames that are consumed. When you +call `ma_resampler_process_pcm_frames()` you need to pass in the number of input frames available for processing and the number of output frames you want to +output. Upon returning they will receive the number of input frames that were consumed and the number of output frames that were generated. + +The `ma_data_converter` API is a wrapper around format, channel and sample rate conversion and handles all of the data conversion you'll need which probably +makes it the best option if you need to do data conversion. + +In addition to changes to the API design, a few other changes have been made to the data conversion pipeline: + + - The sinc resampler has been removed. This was completely broken and never actually worked properly. + - The linear resampler now uses low-pass filtering to remove aliasing. The quality of the low-pass filter can be controlled via the resampler config with the + `lpfOrder` option, which has a maximum value of MA_MAX_FILTER_ORDER. + - Data conversion now supports s16 natively which runs through a fixed point pipeline. Previously everything needed to be converted to floating point before + processing, whereas now both s16 and f32 are natively supported. Other formats still require conversion to either s16 or f32 prior to processing, however + `ma_data_converter` will handle this for you. + + +Custom Memory Allocators +------------------------ +miniaudio has always supported macro level customization for memory allocation via MA_MALLOC, MA_REALLOC and MA_FREE, however some scenarios require more +flexibility by allowing a user data pointer to be passed to the custom allocation routines. Support for this has been added to version 0.10 via the +`ma_allocation_callbacks` structure. Anything making use of heap allocations has been updated to accept this new structure. + +The `ma_context_config` structure has been updated with a new member called `allocationCallbacks`. Leaving this set to it's defaults returned by +`ma_context_config_init()` will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. Likewise, The `ma_decoder_config` structure has been updated in the same +way, and leaving everything as-is after `ma_decoder_config_init()` will cause it to use the same defaults. + +The following APIs have been updated to take a pointer to a `ma_allocation_callbacks` object. Setting this parameter to NULL will cause it to use defaults. +Otherwise they will use the relevant callback in the structure. + + - ma_malloc() + - ma_realloc() + - ma_free() + - ma_aligned_malloc() + - ma_aligned_free() + - ma_rb_init() / ma_rb_init_ex() + - ma_pcm_rb_init() / ma_pcm_rb_init_ex() + +Note that you can continue to use MA_MALLOC, MA_REALLOC and MA_FREE as per normal. These will continue to be used by default if you do not specify custom +allocation callbacks. + + +Buffer and Period Configuration Changes +--------------------------------------- +The way in which the size of the internal buffer and periods are specified in the device configuration have changed. In previous versions, the config variables +`bufferSizeInFrames` and `bufferSizeInMilliseconds` defined the size of the entire buffer, with the size of a period being the size of this variable divided by +the period count. This became confusing because people would expect the value of `bufferSizeInFrames` or `bufferSizeInMilliseconds` to independantly determine +latency, when in fact it was that value divided by the period count that determined it. These variables have been removed and replaced with new ones called +`periodSizeInFrames` and `periodSizeInMilliseconds`. + +These new configuration variables work in the same way as their predecessors in that if one is set to 0, the other will be used, but the main difference is +that you now set these to you desired latency rather than the size of the entire buffer. The benefit of this is that it's much easier and less confusing to +configure latency. + +The following unused APIs have been removed: + + ma_get_default_buffer_size_in_milliseconds() + ma_get_default_buffer_size_in_frames() + +The following macros have been removed: + + MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY + MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE + + +Other API Changes +----------------- +Other less major API changes have also been made in version 0.10. + +`ma_device_set_stop_callback()` has been removed. If you require a stop callback, you must now set it via the device config just like the data callback. + +The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including +sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes a configuration +object called `ma_waveform_config` which defines the properties of the waveform. Use `ma_waveform_config_init()` to initialize a `ma_waveform_config` object. +Use `ma_waveform_read_pcm_frames()` in place of `ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`. + +`ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies +the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to +take a pointer to a `ma_data_converter_config` object to specify the input and output formats to convert between. This was done to make it more flexible, to +prevent the parameter list getting too long, and to prevent API breakage whenever a new conversion property is added. + +`ma_calculate_frame_count_after_src()` has been renamed to `ma_calculate_frame_count_after_resampling()` for consistency with the new `ma_resampler` API. + + +Filters +------- +The following filters have been added: + + |-------------|-------------------------------------------------------------------| + | API | Description | + |-------------|-------------------------------------------------------------------| + | ma_biquad | Biquad filter (transposed direct form 2) | + | ma_lpf1 | First order low-pass filter | + | ma_lpf2 | Second order low-pass filter | + | ma_lpf | High order low-pass filter (Butterworth) | + | ma_hpf1 | First order high-pass filter | + | ma_hpf2 | Second order high-pass filter | + | ma_hpf | High order high-pass filter (Butterworth) | + | ma_bpf2 | Second order band-pass filter | + | ma_bpf | High order band-pass filter | + | ma_peak2 | Second order peaking filter | + | ma_notch2 | Second order notching filter | + | ma_loshelf2 | Second order low shelf filter | + | ma_hishelf2 | Second order high shelf filter | + |-------------|-------------------------------------------------------------------| + +These filters all support 32-bit floating point and 16-bit signed integer formats natively. Other formats need to be converted beforehand. + + +Sine, Square, Triangle and Sawtooth Waveforms +--------------------------------------------- +Previously miniaudio supported only sine wave generation. This has now been generalized to support sine, square, triangle and sawtooth waveforms. The old +`ma_sine_wave` API has been removed and replaced with the `ma_waveform` API. Use `ma_waveform_config_init()` to initialize a config object, and then pass it +into `ma_waveform_init()`. Then use `ma_waveform_read_pcm_frames()` to read PCM data. + + +Noise Generation +---------------- +A noise generation API has been added. This is used via the `ma_noise` API. Currently white, pink and Brownian noise is supported. The `ma_noise` API is +similar to the waveform API. Use `ma_noise_config_init()` to initialize a config object, and then pass it into `ma_noise_init()` to initialize a `ma_noise` +object. Then use `ma_noise_read_pcm_frames()` to read PCM data. + + +Miscellaneous Changes +--------------------- +The MA_NO_STDIO option has been removed. This would disable file I/O APIs, however this has proven to be too hard to maintain for it's perceived value and was +therefore removed. + +Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report. + +The `ma_device` structure is no longer defined as being aligned to MA_SIMD_ALIGNMENT. This resulted in a possible crash when allocating a `ma_device` object on +the heap, but not aligning it to MA_SIMD_ALIGNMENT. This crash would happen due to the compiler seeing the alignment specified on the structure and assuming it +was always aligned as such and thinking it was safe to emit alignment-dependant SIMD instructions. Since miniaudio's philosophy is for things to just work, +this has been removed from all structures. + +Results codes have been overhauled. Unnecessary result codes have been removed, and some have been renumbered for organisation purposes. If you are are binding +maintainer you will need to update your result codes. Support has also been added for retrieving a human readable description of a given result code via the +`ma_result_description()` API. + +ALSA: The automatic format conversion, channel conversion and resampling performed by ALSA is now disabled by default as they were causing some compatibility +issues with certain devices and configurations. These can be individually enabled via the device config: + + ```c + deviceConfig.alsa.noAutoFormat = MA_TRUE; + deviceConfig.alsa.noAutoChannels = MA_TRUE; + deviceConfig.alsa.noAutoResample = MA_TRUE; + ``` +*/ + +/* +RELEASE NOTES - VERSION 0.9.x +============================= +Version 0.9 includes major API changes, centered mostly around full-duplex and the rebrand to "miniaudio". Before I go into detail about the major changes I +would like to apologize. I know it's annoying dealing with breaking API changes, but I think it's best to get these changes out of the way now while the +library is still relatively young and unknown. + +There's been a lot of refactoring with this release so there's a good chance a few bugs have been introduced. I apologize in advance for this. You may want to +hold off on upgrading for the short term if you're worried. If mini_al v0.8.14 works for you, and you don't need full-duplex support, you can avoid upgrading +(though you won't be getting future bug fixes). + + +Rebranding to "miniaudio" +------------------------- +The decision was made to rename mini_al to miniaudio. Don't worry, it's the same project. The reason for this is simple: + +1) Having the word "audio" in the title makes it immediately clear that the library is related to audio; and +2) I don't like the look of the underscore. + +This rebrand has necessitated a change in namespace from "mal" to "ma". I know this is annoying, and I apologize, but it's better to get this out of the road +now rather than later. Also, since there are necessary API changes for full-duplex support I think it's better to just get the namespace change over and done +with at the same time as the full-duplex changes. I'm hoping this will be the last of the major API changes. Fingers crossed! + +The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's your preference. + + +Full-Duplex Support +------------------- +The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes. + +1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted to avoid a third callback just + for full-duplex so the decision was made to break this API and unify the callbacks. Now, there is just one callback which is the same for all three modes + (playback, capture, duplex). The new callback looks like the following: + + void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + + This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In playback-only mode, pInput will be + null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer returned from the callback since it's not necessary for miniaudio + anymore. + +2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client to choose a different PCM format + for the playback and capture sides. The old ma_device_config object simply did not allow this and needed to change. With these changes you now specify the + device ID, format, channels, channel map and share mode on a per-playback and per-capture basis (see example below). The sample rate must be the same for + playback and capture. + + Since the device config API has changed I have also decided to take the opportunity to simplify device initialization. Now, the device ID, device type and + callback user data are set in the config. ma_device_init() is now simplified down to taking just the context, device config and a pointer to the device + object being initialized. The rationale for this change is that it just makes more sense to me that these are set as part of the config like everything + else. + + Example device initialization: + + ma_device_config config = ma_device_config_init(ma_device_type_duplex); // Or ma_device_type_playback or ma_device_type_capture. + config.playback.pDeviceID = &myPlaybackDeviceID; // Or NULL for the default playback device. + config.playback.format = ma_format_f32; + config.playback.channels = 2; + config.capture.pDeviceID = &myCaptureDeviceID; // Or NULL for the default capture device. + config.capture.format = ma_format_s16; + config.capture.channels = 1; + config.sampleRate = 44100; + config.dataCallback = data_callback; + config.pUserData = &myUserData; + + result = ma_device_init(&myContext, &config, &device); + if (result != MA_SUCCESS) { + ... handle error ... + } + + Note that the "onDataCallback" member of ma_device_config has been renamed to "dataCallback". Also, "onStopCallback" has been renamed to "stopCallback". + +This is the first pass for full-duplex and there is a known bug. You will hear crackling on the following backends when sample rate conversion is required for +the playback device: + - Core Audio + - JACK + - AAudio + - OpenSL + - WebAudio + +In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such thorough testing. If you +experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample program that reproduces the issue if possible). + + +Other API Changes +----------------- +In addition to the above, the following API changes have been made: + +- The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization. +- The onLogCallback member of ma_context_config has been renamed to "logCallback". +- The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) + - You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it. +- Some APIs have been renamed: + - mal_decoder_read() -> ma_decoder_read_pcm_frames() + - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame() + - mal_sine_wave_read() -> ma_sine_wave_read_f32() + - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex() +- Some APIs have been removed: + - mal_device_get_buffer_size_in_bytes() + - mal_device_set_recv_callback() + - mal_device_set_send_callback() + - mal_src_set_input_sample_rate() + - mal_src_set_output_sample_rate() +- Error codes have been rearranged. If you're a binding maintainer you will need to update. +- The ma_backend enums have been rearranged to priority order. The rationale for this is to simplify automatic backend selection and to make it easier to see + the priority. If you're a binding maintainer you will need to update. +- ma_dsp has been renamed to ma_pcm_converter. The rationale for this change is that I'm expecting "ma_dsp" to conflict with some future planned high-level + APIs. +- For functions that take a pointer/count combo, such as ma_decoder_read_pcm_frames(), the parameter order has changed so that the pointer comes before the + count. The rationale for this is to keep it consistent with things like memcpy(). + + +Miscellaneous Changes +--------------------- +The following miscellaneous changes have also been made. + +- The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the record, this is one of the nicest + audio APIs out there, just behind the BSD audio APIs). +- The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL. +- The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio was not explicitly + supported. These are no longer needed and have therefore been removed. +- Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an exclusive mode device, or an + error. The rationale for this change is to give the client more control over how to handle cases when the desired shared mode is unavailable. +- A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb" operates on PCM frames. +- The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but removes the attribution + requirement. The rationale for this is to support countries that don't recognize public domain. +*/ + +/* +REVISION HISTORY +================ +v0.10.33 - 2021-04-04 + - Core Audio: Fix a memory leak. + - Core Audio: Fix a bug where the performance profile is not being used by playback devices. + - JACK: Fix loading of 64-bit JACK on Windows. + - Fix a calculation error and add a safety check to the following APIs to prevent a division by zero: + - ma_calculate_buffer_size_in_milliseconds_from_frames() + - ma_calculate_buffer_size_in_frames_from_milliseconds() + - Fix compilation errors relating to c89atomic. + - Update FLAC decoder. + +v0.10.32 - 2021-02-23 + - WASAPI: Fix a deadlock in exclusive mode. + - WASAPI: No longer return an error from ma_context_get_device_info() when an exclusive mode format + cannot be retrieved. + - WASAPI: Attempt to fix some bugs with device uninitialization. + - PulseAudio: Yet another refactor, this time to remove the dependency on `pa_threaded_mainloop`. + - Web Audio: Fix a bug on Chrome and any other browser using the same engine. + - Web Audio: Automatically start the device on some user input if the device has been started. This + is to work around Google's policy of not starting audio if no user input has yet been performed. + - Fix a bug where thread handles are not being freed. + - Fix some static analysis warnings in FLAC, WAV and MP3 decoders. + - Fix a warning due to referencing _MSC_VER when it is undefined. + - Update to latest version of c89atomic. + - Internal refactoring to migrate over to the new backend callback system for the following backends: + - PulseAudio + - ALSA + - Core Audio + - AAudio + - OpenSL|ES + - OSS + - audio(4) + - sndio + +v0.10.31 - 2021-01-17 + - Make some functions const correct. + - Update ma_data_source_read_pcm_frames() to initialize pFramesRead to 0 for safety. + - Add the MA_ATOMIC annotation for use with variables that should be used atomically and remove unnecessary volatile qualifiers. + - Add support for enabling only specific backends at compile time. This is the reverse of the pre-existing system. With the new + system, all backends are first disabled with `MA_ENABLE_ONLY_SPECIFIC_BACKENDS`, which is then followed with `MA_ENABLE_*`. The + old system where you disable backends with `MA_NO_*` still exists and is still the default. + +v0.10.30 - 2021-01-10 + - Fix a crash in ma_audio_buffer_read_pcm_frames(). + - Update spinlock APIs to take a volatile parameter as input. + - Silence some unused parameter warnings. + - Fix a warning on GCC when compiling as C++. + +v0.10.29 - 2020-12-26 + - Fix some subtle multi-threading bugs on non-x86 platforms. + - Fix a bug resulting in superfluous memory allocations when enumerating devices. + - Core Audio: Fix a compilation error when compiling for iOS. + +v0.10.28 - 2020-12-16 + - Fix a crash when initializing a POSIX thread. + - OpenSL|ES: Respect the MA_NO_RUNTIME_LINKING option. + +v0.10.27 - 2020-12-04 + - Add support for dynamically configuring some properties of `ma_noise` objects post-initialization. + - Add support for configuring the channel mixing mode in the device config. + - Fix a bug with simple channel mixing mode (drop or silence excess channels). + - Fix some bugs with trying to access uninitialized variables. + - Fix some errors with stopping devices for synchronous backends where the backend's stop callback would get fired twice. + - Fix a bug in the decoder due to using an uninitialized variable. + - Fix some data race errors. + +v0.10.26 - 2020-11-24 + - WASAPI: Fix a bug where the exclusive mode format may not be retrieved correctly due to accessing freed memory. + - Fix a bug with ma_waveform where glitching occurs after changing frequency. + - Fix compilation with OpenWatcom. + - Fix compilation with TCC. + - Fix compilation with Digital Mars. + - Fix compilation warnings. + - Remove bitfields from public structures to aid in binding maintenance. + +v0.10.25 - 2020-11-15 + - PulseAudio: Fix a bug where the stop callback isn't fired. + - WebAudio: Fix an error that occurs when Emscripten increases the size of it's heap. + - Custom Backends: Change the onContextInit and onDeviceInit callbacks to take a parameter which is a pointer to the config that was + passed into ma_context_init() and ma_device_init(). This replaces the deviceType parameter of onDeviceInit. + - Fix compilation warnings on older versions of GCC. + +v0.10.24 - 2020-11-10 + - Fix a bug where initialization of a backend can fail due to some bad state being set from a prior failed attempt at initializing a + lower priority backend. + +v0.10.23 - 2020-11-09 + - AAudio: Add support for configuring a playback stream's usage. + - Fix a compilation error when all built-in asynchronous backends are disabled at compile time. + - Fix compilation errors when compiling as C++. + +v0.10.22 - 2020-11-08 + - Add support for custom backends. + - Add support for detecting default devices during device enumeration and with `ma_context_get_device_info()`. + - Refactor to the PulseAudio backend. This simplifies the implementation and fixes a capture bug. + - ALSA: Fix a bug in `ma_context_get_device_info()` where the PCM handle is left open in the event of an error. + - Core Audio: Further improvements to sample rate selection. + - Core Audio: Fix some bugs with capture mode. + - OpenSL: Add support for configuring stream types and recording presets. + - AAudio: Add support for configuring content types and input presets. + - Fix bugs in `ma_decoder_init_file*()` where the file handle is not closed after a decoding error. + - Fix some compilation warnings on GCC and Clang relating to the Speex resampler. + - Fix a compilation error for the Linux build when the ALSA and JACK backends are both disabled. + - Fix a compilation error for the BSD build. + - Fix some compilation errors on older versions of GCC. + - Add documentation for `MA_NO_RUNTIME_LINKING`. + +v0.10.21 - 2020-10-30 + - Add ma_is_backend_enabled() and ma_get_enabled_backends() for retrieving enabled backends at run-time. + - WASAPI: Fix a copy and paste bug relating to loopback mode. + - Core Audio: Fix a bug when using multiple contexts. + - Core Audio: Fix a compilation warning. + - Core Audio: Improvements to sample rate selection. + - Core Audio: Improvements to format/channels/rate selection when requesting defaults. + - Core Audio: Add notes regarding the Apple notarization process. + - Fix some bugs due to null pointer dereferences. + +v0.10.20 - 2020-10-06 + - Fix build errors with UWP. + - Minor documentation updates. + +v0.10.19 - 2020-09-22 + - WASAPI: Return an error when exclusive mode is requested, but the native format is not supported by miniaudio. + - Fix a bug where ma_decoder_seek_to_pcm_frames() never returns MA_SUCCESS even though it was successful. + - Store the sample rate in the `ma_lpf` and `ma_hpf` structures. + +v0.10.18 - 2020-08-30 + - Fix build errors with VC6. + - Fix a bug in channel converter for s32 format. + - Change channel converter configs to use the default channel map instead of a blank channel map when no channel map is specified when initializing the + config. This fixes an issue where the optimized mono expansion path would never get used. + - Use a more appropriate default format for FLAC decoders. This will now use ma_format_s16 when the FLAC is encoded as 16-bit. + - Update FLAC decoder. + - Update links to point to the new repository location (https://github.com/mackron/miniaudio). + +v0.10.17 - 2020-08-28 + - Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set. + - Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed. + - Fix compilation error on Android. + - Core Audio: Fix a bug with full-duplex mode. + - Add ma_decoder_get_cursor_in_pcm_frames(). + - Update WAV codec. + +v0.10.16 - 2020-08-14 + - WASAPI: Fix a potential crash due to using an uninitialized variable. + - OpenSL: Enable runtime linking. + - OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time. + - iOS: Improvements to device enumeration. + - Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL. + - Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work. + - Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled. + - Fix some compilation warnings when no decoders are enabled. + - Add ma_audio_buffer_get_available_frames(). + - Add ma_decoder_get_available_frames(). + - Add sample rate to ma_data_source_get_data_format(). + - Change volume APIs to take 64-bit frame counts. + - Updates to documentation. + +v0.10.15 - 2020-07-15 + - Fix a bug when converting bit-masked channel maps to miniaudio channel maps. This affects the WASAPI and OpenSL backends. + +v0.10.14 - 2020-07-14 + - Fix compilation errors on Android. + - Fix compilation errors with -march=armv6. + - Updates to the documentation. + +v0.10.13 - 2020-07-11 + - Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS. + - Fix compilation error on Emscripten. + - Silence some unused function warnings. + - Increase the default buffer size on the Web Audio backend. This fixes glitching issues on some browsers. + - Bring FLAC decoder up-to-date with dr_flac. + - Bring MP3 decoder up-to-date with dr_mp3. + +v0.10.12 - 2020-07-04 + - Fix compilation errors on the iOS build. + +v0.10.11 - 2020-06-28 + - Fix some bugs with device tracking on Core Audio. + - Updates to documentation. + +v0.10.10 - 2020-06-26 + - Add include guard for the implementation section. + - Mark ma_device_sink_info_callback() as static. + - Fix compilation errors with MA_NO_DECODING and MA_NO_ENCODING. + - Fix compilation errors with MA_NO_DEVICE_IO + +v0.10.9 - 2020-06-24 + - Amalgamation of dr_wav, dr_flac and dr_mp3. With this change, including the header section of these libraries before the implementation of miniaudio is no + longer required. Decoding of WAV, FLAC and MP3 should be supported seamlessly without any additional libraries. Decoders can be excluded from the build + with the following options: + - MA_NO_WAV + - MA_NO_FLAC + - MA_NO_MP3 + If you get errors about multiple definitions you need to either enable the options above, move the implementation of dr_wav, dr_flac and/or dr_mp3 to before + the implementation of miniaudio, or update dr_wav, dr_flac and/or dr_mp3. + - Changes to the internal atomics library. This has been replaced with c89atomic.h which is embedded within this file. + - Fix a bug when a decoding backend reports configurations outside the limits of miniaudio's decoder abstraction. + - Fix the UWP build. + - Fix the Core Audio build. + - Fix the -std=c89 build on GCC. + +v0.10.8 - 2020-06-22 + - Remove dependency on ma_context from mutexes. + - Change ma_data_source_read_pcm_frames() to return a result code and output the frames read as an output parameter. + - Change ma_data_source_seek_pcm_frames() to return a result code and output the frames seeked as an output parameter. + - Change ma_audio_buffer_unmap() to return MA_AT_END when the end has been reached. This should be considered successful. + - Change playback.pDeviceID and capture.pDeviceID to constant pointers in ma_device_config. + - Add support for initializing decoders from a virtual file system object. This is achieved via the ma_vfs API and allows the application to customize file + IO for the loading and reading of raw audio data. Passing in NULL for the VFS will use defaults. New APIs: + - ma_decoder_init_vfs() + - ma_decoder_init_vfs_wav() + - ma_decoder_init_vfs_flac() + - ma_decoder_init_vfs_mp3() + - ma_decoder_init_vfs_vorbis() + - ma_decoder_init_vfs_w() + - ma_decoder_init_vfs_wav_w() + - ma_decoder_init_vfs_flac_w() + - ma_decoder_init_vfs_mp3_w() + - ma_decoder_init_vfs_vorbis_w() + - Add support for memory mapping to ma_data_source. + - ma_data_source_map() + - ma_data_source_unmap() + - Add ma_offset_pcm_frames_ptr() and ma_offset_pcm_frames_const_ptr() which can be used for offsetting a pointer by a specified number of PCM frames. + - Add initial implementation of ma_yield() which is useful for spin locks which will be used in some upcoming work. + - Add documentation for log levels. + - The ma_event API has been made public in preparation for some uncoming work. + - Fix a bug in ma_decoder_seek_to_pcm_frame() where the internal sample rate is not being taken into account for determining the seek location. + - Fix some bugs with the linear resampler when dynamically changing the sample rate. + - Fix compilation errors with MA_NO_DEVICE_IO. + - Fix some warnings with GCC and -std=c89. + - Fix some formatting warnings with GCC and -Wall and -Wpedantic. + - Fix some warnings with VC6. + - Minor optimization to ma_copy_pcm_frames(). This is now a no-op when the input and output buffers are the same. + +v0.10.7 - 2020-05-25 + - Fix a compilation error in the C++ build. + - Silence a warning. + +v0.10.6 - 2020-05-24 + - Change ma_clip_samples_f32() and ma_clip_pcm_frames_f32() to take a 64-bit sample/frame count. + - Change ma_zero_pcm_frames() to clear to 128 for ma_format_u8. + - Add ma_silence_pcm_frames() which replaces ma_zero_pcm_frames(). ma_zero_pcm_frames() will be removed in version 0.11. + - Add support for u8, s24 and s32 formats to ma_channel_converter. + - Add compile-time and run-time version querying. + - MA_VERSION_MINOR + - MA_VERSION_MAJOR + - MA_VERSION_REVISION + - MA_VERSION_STRING + - ma_version() + - ma_version_string() + - Add ma_audio_buffer for reading raw audio data directly from memory. + - Fix a bug in shuffle mode in ma_channel_converter. + - Fix compilation errors in certain configurations for ALSA and PulseAudio. + - The data callback now initializes the output buffer to 128 when the playback sample format is ma_format_u8. + +v0.10.5 - 2020-05-05 + - Change ma_zero_pcm_frames() to take a 64-bit frame count. + - Add ma_copy_pcm_frames(). + - Add MA_NO_GENERATION build option to exclude the `ma_waveform` and `ma_noise` APIs from the build. + - Add support for formatted logging to the VC6 build. + - Fix a crash in the linear resampler when LPF order is 0. + - Fix compilation errors and warnings with older versions of Visual Studio. + - Minor documentation updates. + +v0.10.4 - 2020-04-12 + - Fix a data conversion bug when converting from the client format to the native device format. + +v0.10.3 - 2020-04-07 + - Bring up to date with breaking changes to dr_mp3. + - Remove MA_NO_STDIO. This was causing compilation errors and the maintenance cost versus practical benefit is no longer worthwhile. + - Fix a bug with data conversion where it was unnecessarily converting to s16 or f32 and then straight back to the original format. + - Fix compilation errors and warnings with Visual Studio 2005. + - ALSA: Disable ALSA's automatic data conversion by default and add configuration options to the device config: + - alsa.noAutoFormat + - alsa.noAutoChannels + - alsa.noAutoResample + - WASAPI: Add some overrun recovery for ma_device_type_capture devices. + +v0.10.2 - 2020-03-22 + - Decorate some APIs with MA_API which were missed in the previous version. + - Fix a bug in ma_linear_resampler_set_rate() and ma_linear_resampler_set_rate_ratio(). + +v0.10.1 - 2020-03-17 + - Add MA_API decoration. This can be customized by defining it before including miniaudio.h. + - Fix a bug where opening a file would return a success code when in fact it failed. + - Fix compilation errors with Visual Studio 6 and 2003. + - Fix warnings on macOS. + +v0.10.0 - 2020-03-07 + - API CHANGE: Refactor data conversion APIs + - ma_format_converter has been removed. Use ma_convert_pcm_frames_format() instead. + - ma_channel_router has been replaced with ma_channel_converter. + - ma_src has been replaced with ma_resampler + - ma_pcm_converter has been replaced with ma_data_converter + - API CHANGE: Add support for custom memory allocation callbacks. The following APIs have been updated to take an extra parameter for the allocation + callbacks: + - ma_malloc() + - ma_realloc() + - ma_free() + - ma_aligned_malloc() + - ma_aligned_free() + - ma_rb_init() / ma_rb_init_ex() + - ma_pcm_rb_init() / ma_pcm_rb_init_ex() + - API CHANGE: Simplify latency specification in device configurations. The bufferSizeInFrames and bufferSizeInMilliseconds parameters have been replaced with + periodSizeInFrames and periodSizeInMilliseconds respectively. The previous variables defined the size of the entire buffer, whereas the new ones define the + size of a period. The following APIs have been removed since they are no longer relevant: + - ma_get_default_buffer_size_in_milliseconds() + - ma_get_default_buffer_size_in_frames() + - API CHANGE: ma_device_set_stop_callback() has been removed. If you require a stop callback, you must now set it via the device config just like the data + callback. + - API CHANGE: The ma_sine_wave API has been replaced with ma_waveform. The following APIs have been removed: + - ma_sine_wave_init() + - ma_sine_wave_read_f32() + - ma_sine_wave_read_f32_ex() + - API CHANGE: ma_convert_frames() has been updated to take an extra parameter which is the size of the output buffer in PCM frames. Parameters have also been + reordered. + - API CHANGE: ma_convert_frames_ex() has been changed to take a pointer to a ma_data_converter_config object to specify the input and output formats to + convert between. + - API CHANGE: ma_calculate_frame_count_after_src() has been renamed to ma_calculate_frame_count_after_resampling(). + - Add support for the following filters: + - Biquad (ma_biquad) + - First order low-pass (ma_lpf1) + - Second order low-pass (ma_lpf2) + - Low-pass with configurable order (ma_lpf) + - First order high-pass (ma_hpf1) + - Second order high-pass (ma_hpf2) + - High-pass with configurable order (ma_hpf) + - Second order band-pass (ma_bpf2) + - Band-pass with configurable order (ma_bpf) + - Second order peaking EQ (ma_peak2) + - Second order notching (ma_notch2) + - Second order low shelf (ma_loshelf2) + - Second order high shelf (ma_hishelf2) + - Add waveform generation API (ma_waveform) with support for the following: + - Sine + - Square + - Triangle + - Sawtooth + - Add noise generation API (ma_noise) with support for the following: + - White + - Pink + - Brownian + - Add encoding API (ma_encoder). This only supports outputting to WAV files via dr_wav. + - Add ma_result_description() which is used to retrieve a human readable description of a given result code. + - Result codes have been changed. Binding maintainers will need to update their result code constants. + - More meaningful result codes are now returned when a file fails to open. + - Internal functions have all been made static where possible. + - Fix potential crash when ma_device object's are not aligned to MA_SIMD_ALIGNMENT. + - Fix a bug in ma_decoder_get_length_in_pcm_frames() where it was returning the length based on the internal sample rate rather than the output sample rate. + - Fix bugs in some backends where the device is not drained properly in ma_device_stop(). + - Improvements to documentation. + +v0.9.10 - 2020-01-15 + - Fix compilation errors due to #if/#endif mismatches. + - WASAPI: Fix a bug where automatic stream routing is being performed for devices that are initialized with an explicit device ID. + - iOS: Fix a crash on device uninitialization. + +v0.9.9 - 2020-01-09 + - Fix compilation errors with MinGW. + - Fix compilation errors when compiling on Apple platforms. + - WASAPI: Add support for disabling hardware offloading. + - WASAPI: Add support for disabling automatic stream routing. + - Core Audio: Fix bugs in the case where the internal device uses deinterleaved buffers. + - Core Audio: Add support for controlling the session category (AVAudioSessionCategory) and options (AVAudioSessionCategoryOptions). + - JACK: Fix bug where incorrect ports are connected. + +v0.9.8 - 2019-10-07 + - WASAPI: Fix a potential deadlock when starting a full-duplex device. + - WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC. + - Core Audio: Fix bugs with automatic stream routing. + - Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized + to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device + config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined. + - Add support for clipping samples after the data callback has returned. This only applies when the playback sample format is + configured as ma_format_f32. If you are doing clipping yourself, you can disable this overhead by setting noClip to true in + the device config. + - Add support for master volume control for devices. + - Use ma_device_set_master_volume() to set the volume to a factor between 0 and 1, where 0 is silence and 1 is full volume. + - Use ma_device_set_master_gain_db() to set the volume in decibels where 0 is full volume and < 0 reduces the volume. + - Fix warnings emitted by GCC when `__inline__` is undefined or defined as nothing. + +v0.9.7 - 2019-08-28 + - Add support for loopback mode (WASAPI only). + - To use this, set the device type to ma_device_type_loopback, and then fill out the capture section of the device config. + - If you need to capture from a specific output device, set the capture device ID to that of a playback device. + - Fix a crash when an error is posted in ma_device_init(). + - Fix a compilation error when compiling for ARM architectures. + - Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode. + - Fix memory leaks in the Core Audio backend. + - Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4), sndio and null backends. + +v0.9.6 - 2019-08-04 + - Add support for loading decoders using a wchar_t string for file paths. + - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning + and return MA_INVALID_OPERATION. The same applies for ma_device_stop(). + - Try fixing an issue with PulseAudio taking a long time to start playback. + - Fix a bug in ma_convert_frames() and ma_convert_frames_ex(). + - Fix memory leaks in the WASAPI backend. + - Fix a compilation error with Visual Studio 2010. + +v0.9.5 - 2019-05-21 + - Add logging to ma_dlopen() and ma_dlsym(). + - Add ma_decoder_get_length_in_pcm_frames(). + - Fix a bug with capture on the OpenSL|ES backend. + - Fix a bug with the ALSA backend where a device would not restart after being stopped. + +v0.9.4 - 2019-05-06 + - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and + Microsoft compilers back to VC6. Other compilers should also work, but have not been tested. + +v0.9.3 - 2019-04-19 + - Fix compiler errors on GCC when compiling with -std=c99. + +v0.9.2 - 2019-04-08 + - Add support for per-context user data. + - Fix a potential bug with context configs. + - Fix some bugs with PulseAudio. + +v0.9.1 - 2019-03-17 + - Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when + the device is running in passthrough mode (not doing any data conversion). + - Fix an issue where the data callback is getting called too frequently on the WASAPI and DirectSound backends. + - Fix error on the UWP build. + - Fix a build error on Apple platforms. + +v0.9 - 2019-03-06 + - Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma". + - API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly: + - The device type, device ID and user data pointer have moved from ma_device_init() to the config. + - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init(). + - ma_device_config_init() now takes only one parameter which is the device type. All other properties need + to be set on the returned object directly. + - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback" + and "stopCallback". + - The ID of the physical device is now split into two: one for the playback device and the other for the + capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID". + - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than + being separate for each. It now takes two pointers - one containing input data and the other output data. This + design in required for full-duplex. The return value is now void instead of the number of frames written. The + new callback looks like the following: + void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change, + ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The + new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The + "onLog" member of ma_context_config has been renamed to "logCallback". + - API CHANGE: Remove ma_device_get_buffer_size_in_bytes(). + - API CHANGE: Rename decoding APIs to "pcm_frames" convention. + - mal_decoder_read() -> ma_decoder_read_pcm_frames() + - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame() + - API CHANGE: Rename sine wave reading APIs to f32 convention. + - mal_sine_wave_read() -> ma_sine_wave_read_f32() + - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex() + - API CHANGE: Remove some deprecated APIs + - mal_device_set_recv_callback() + - mal_device_set_send_callback() + - mal_src_set_input_sample_rate() + - mal_src_set_output_sample_rate() + - API CHANGE: Add log level to the log callback. New signature: + - void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) + - API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're + a binding mainainer you will need to update your result code constants. + - API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you + will need to update. + - API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to + ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*. + - API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme. + - The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation + is too inefficient right now. This will hopefully be improved at a later date. + - Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable. + With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not + automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's + what they want. + - Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and + ma_pcm_rb operates on PCM frames. + - Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously + used for web support, will be removed in a future version. + - Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts + with Android 8. OpenSL|ES is used as a fallback for older versions of Android. + - Remove OpenAL and SDL backends. + - Fix a possible deadlock when rapidly stopping the device after it has started. + - Update documentation. + - Change licensing to a choice of public domain _or_ MIT-0 (No Attribution). + +v0.8.14 - 2018-12-16 + - Core Audio: Fix a bug where the device state is not set correctly after stopping. + - Add support for custom weights to the channel router. + - Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav. + +v0.8.13 - 2018-12-04 + - Core Audio: Fix a bug with channel mapping. + - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight. + +v0.8.12 - 2018-11-27 + - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2". + - Fix a linking error with ALSA. + - Fix a bug on iOS where the device name is not set correctly. + +v0.8.11 - 2018-11-21 + - iOS bug fixes. + - Minor tweaks to PulseAudio. + +v0.8.10 - 2018-10-21 + - Core Audio: Fix a hang when uninitializing a device. + - Fix a bug where an incorrect value is returned from mal_device_stop(). + +v0.8.9 - 2018-09-28 + - Fix a bug with the SDL backend where device initialization fails. + +v0.8.8 - 2018-09-14 + - Fix Linux build with the ALSA backend. + - Minor documentation fix. + +v0.8.7 - 2018-09-12 + - Fix a bug with UWP detection. + +v0.8.6 - 2018-08-26 + - Automatically switch the internal device when the default device is unplugged. Note that this is still in the + early stages and not all backends handle this the same way. As of this version, this will not detect a default + device switch when changed from the operating system's audio preferences (unless the backend itself handles + this automatically). This is not supported in exclusive mode. + - WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the + user switches the default device via the operating system's audio preferences, miniaudio will automatically switch + the internal device to the new default. This is not supported in exclusive mode. + - WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer. + - WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer. + - Add support for compiling the UWP build as C. + - mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this + when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0. + +v0.8.5 - 2018-08-12 + - Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in + frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0 + then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used. + - Add support for the audio(4) backend to OpenBSD. + - Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the + Raspberry Pi experience. + - Fix a bug where an incorrect number of samples is returned from sinc resampling. + - Add support for setting the value to be passed to internal calls to CoInitializeEx(). + - WASAPI and WinMM: Stop the device when it is unplugged. + +v0.8.4 - 2018-08-06 + - Add sndio backend for OpenBSD. + - Add audio(4) backend for NetBSD. + - Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD. + - Formats are now native-endian (were previously little-endian). + - Mark some APIs as deprecated: + - mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate(). + - mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate(). + - Fix a bug when capturing using the WASAPI backend. + - Fix some aliasing issues with resampling, specifically when increasing the sample rate. + - Fix warnings. + +v0.8.3 - 2018-07-15 + - Fix a crackling bug when resampling in capture mode. + - Core Audio: Fix a bug where capture does not work. + - ALSA: Fix a bug where the worker thread can get stuck in an infinite loop. + - PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable. + - JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable. + +v0.8.2 - 2018-07-07 + - Fix a bug on macOS with Core Audio where the internal callback is not called. + +v0.8.1 - 2018-07-06 + - Fix compilation errors and warnings. + +v0.8 - 2018-07-05 + - Changed MAL_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old + way is still supported for now, but you should update as it may be removed in the future. + - API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with + mal_context_get_devices(). An additional low-level device enumration API has been introduced called + mal_context_enumerate_devices() which uses a callback to report devices. + - API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add + mal_get_bytes_per_frame(). + - API CHANGE: Replace mal_device_config.preferExclusiveMode with mal_device_config.shareMode. + - This new config can be set to mal_share_mode_shared (default) or mal_share_mode_exclusive. + - API CHANGE: Remove excludeNullDevice from mal_context_config.alsa. + - API CHANGE: Rename MAL_MAX_SAMPLE_SIZE_IN_BYTES to MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES. + - API CHANGE: Change the default channel mapping to the standard Microsoft mapping. + - API CHANGE: Remove backend-specific result codes. + - API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.) + - Add support for Core Audio (Apple). + - Add support for PulseAudio. + - This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly + installed by default on many of the popular distros and offer's more seamless integration on + platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which + is extremely common), it's better to just use PulseAudio directly rather than going through the + "pulse" ALSA plugin (which is what the "default" ALSA device is likely set to). + - Add support for JACK. + - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no + longer required to build miniaudio. + - Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some + distributions of MinGW. + - Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some + distributions of MinGW. + - Add support for dithering to format conversion. + - Add support for configuring the priority of the worker thread. + - Add a sine wave generator. + - Improve efficiency of sample rate conversion. + - Introduce the notion of standard channel maps. Use mal_get_standard_channel_map(). + - Introduce the notion of default device configurations. A default config uses the same configuration + as the backend's internal device, and as such results in a pass-through data transmission pipeline. + - Add support for passing in NULL for the device config in mal_device_init(), which uses a default + config. This requires manually calling mal_device_set_send/recv_callback(). + - Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.) + - Make mal_device_init_ex() more robust. + - Make some APIs more const-correct. + - Fix errors with SDL detection on Apple platforms. + - Fix errors with OpenAL detection. + - Fix some memory leaks. + - Fix a bug with opening decoders from memory. + - Early work on SSE2, AVX2 and NEON optimizations. + - Miscellaneous bug fixes. + - Documentation updates. + +v0.7 - 2018-02-25 + - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts. + - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files. + - Allow opening of devices without a context. + - In this case the context is created and managed internally by the device. + - Change the default channel mapping to the same as that used by FLAC. + - Fix build errors with macOS. + +v0.6c - 2018-02-12 + - Fix build errors with BSD/OSS. + +v0.6b - 2018-02-03 + - Fix some warnings when compiling with Visual C++. + +v0.6a - 2018-01-26 + - Fix errors with channel mixing when increasing the channel count. + - Improvements to the build system for the OpenAL backend. + - Documentation fixes. + +v0.6 - 2017-12-08 + - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll + need to update. + - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. + - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. + - Add support for SDL and Emscripten. + - Simplify the build system further for when development packages for various backends are not installed. + With this change, when the compiler supports __has_include, backends without the relevant development + packages installed will be ignored. This fixes the build for old versions of MinGW. + - Fixes to the Android build. + - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of + audio data to a different format. + - Improvements to f32 -> u8/s16/s24/s32 conversion routines. + - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend. + - Fixes and improvements for Raspberry Pi. + - Warning fixes. + +v0.5 - 2017-11-11 + - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for + configuring the context. The works in the same kind of way as the device config. The rationale for this + change is to give applications better control over context-level properties, add support for backend- + specific configurations, and support extensibility without breaking the API. + - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for + anything anymore. + - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications + can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config + variable. + - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If + this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now + honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above) + which is by design. + - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable. + - ALSA: Fix a bug with channel mapping which causes an assertion to fail. + - Fix errors with enumeration when pInfo is set to NULL. + - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill. + +v0.4 - 2017-11-05 + - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to + mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic + messages at the context level. Previously this was only available at the device level. + - API CHANGE: The device config passed to mal_device_init() is now const. + - Added support for OSS which enables support on BSD platforms. + - Added support for WinMM (waveOut/waveIn). + - Added support for UWP (Universal Windows Platform) applications. Currently C++ only. + - Added support for exclusive mode for selected backends. Currently supported on WASAPI. + - POSIX builds no longer require explicit linking to libpthread (-lpthread). + - ALSA: Explicit linking to libasound (-lasound) is no longer required. + - ALSA: Latency improvements. + - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config. + - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the + alsa.preferPlugHW config. + - WASAPI is now the highest priority backend on Windows platforms. + - Fixed an error with sample rate conversion which was causing crackling when capturing. + - Improved error handling. + - Improved compiler support. + - Miscellaneous bug fixes. + +v0.3 - 2017-06-19 + - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for + enumerating and creating devices. Now, applications must first create a context, and then use that to + enumerate and create devices. The reason for this change is to ensure device enumeration and creation is + tied to the same backend. In addition, some backends are better suited to this design. + - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard + to test and maintain, and just generally unreliable. + - Added helper APIs for initializing mal_device_config objects. + - Null Backend: Fixed a crash when recording. + - Fixed build for UWP. + - Added support for f32 formats to the OpenSL|ES backend. + - Added initial implementation of the WASAPI backend. + - Added initial implementation of the OpenAL backend. + - Added support for low quality linear sample rate conversion. + - Added early support for basic channel mapping. + +v0.2 - 2016-10-28 + - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this + change is to ensure the logging callback has access to the user data during initialization. + - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale: + 1) The number of parameters is just getting too much. + 2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a + chance there will be support added for backend-specific properties. + - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the + added maintenance cost. + - DirectSound: Increased the default buffer size for capture devices. + - Added initial implementation of the OpenSL|ES backend. + +v0.1 - 2016-10-21 + - Initial versioned release. +*/ + /* This software is available as a choice of the following licenses. Choose @@ -93449,7 +65326,7 @@ For more information, please refer to =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== -Copyright 2025 David Reid +Copyright 2020 David Reid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/raylib/external/msf_gif.h b/raylib/external/msf_gif.h index bc2c6ed..348b1b1 100644 --- a/raylib/external/msf_gif.h +++ b/raylib/external/msf_gif.h @@ -13,31 +13,19 @@ USAGE EXAMPLE: int width = 480, height = 320, centisecondsPerFrame = 5, bitDepth = 16; MsfGifState gifState = {}; - // msf_gif_bgra_flag = true; //optionally, set this flag if your pixels are in BGRA format instead of RGBA - // msf_gif_alpha_threshold = 128; //optionally, enable transparency (see function documentation below for details) msf_gif_begin(&gifState, width, height); msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 1 msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 2 msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 3, etc... MsfGifResult result = msf_gif_end(&gifState); - if (result.data) { - FILE * fp = fopen("MyGif.gif", "wb"); - fwrite(result.data, result.dataSize, 1, fp); - fclose(fp); - } + FILE * fp = fopen("MyGif.gif", "wb"); + fwrite(result.data, result.dataSize, 1, fp); + fclose(fp); msf_gif_free(result); Detailed function documentation can be found in the header section below. -ERROR HANDLING: - - If memory allocation fails, the functions will signal the error via their return values. - If one function call fails, the library will free all of its allocations, - and all subsequent calls will safely no-op and return 0 until the next call to `msf_gif_begin()`. - Therefore, it's safe to check only the return value of `msf_gif_end()`. - - REPLACING MALLOC: This library uses malloc+realloc+free internally for memory allocation. @@ -51,20 +39,10 @@ REPLACING MALLOC: If your allocator needs a context pointer, you can set the `customAllocatorContext` field of the MsfGifState struct before calling msf_gif_begin(), and it will be passed to all subsequent allocator macro calls. - The maximum number of bytes the library will allocate to encode a single gif is bounded by the following formula: - `(2 * 1024 * 1024) + (width * height * 8) + ((1024 + width * height * 1.5) * 3 * frameCount)` - The peak heap memory usage in bytes, if using a general-purpose heap allocator, is bounded by the following formula: - `(2 * 1024 * 1024) + (width * height * 9.5) + 1024 + (16 * frameCount) + (2 * sizeOfResultingGif) - - See end of file for license information. */ -//version 2.2 - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// HEADER /// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//version 2.1 #ifndef MSF_GIF_H #define MSF_GIF_H @@ -85,24 +63,12 @@ typedef struct { //internal use int depth, count, rbits, gbits, bbits; } MsfCookedFrame; -typedef struct MsfGifBuffer { - struct MsfGifBuffer * next; - size_t size; - uint8_t data[1]; -} MsfGifBuffer; - -typedef size_t (* MsfGifFileWriteFunc) (const void * buffer, size_t size, size_t count, void * stream); typedef struct { - MsfGifFileWriteFunc fileWriteFunc; - void * fileWriteData; MsfCookedFrame previousFrame; - MsfCookedFrame currentFrame; - int16_t * lzwMem; - MsfGifBuffer * listHead; - MsfGifBuffer * listTail; + uint8_t * listHead; + uint8_t * listTail; int width, height; void * customAllocatorContext; - int framesSubmitted; //needed for transparency to work correctly (because we reach into the previous frame) } MsfGifState; #ifdef __cplusplus @@ -117,8 +83,7 @@ extern "C" { int msf_gif_begin(MsfGifState * handle, int width, int height); /** - * @param pixelData Pointer to raw framebuffer data. Rows must be contiguous in memory, in RGBA8 format - * (or BGRA8 if you have set `msf_gif_bgra_flag = true`). + * @param pixelData Pointer to raw framebuffer data. Rows must be contiguous in memory, in RGBA8 format. * Note: This function does NOT free `pixelData`. You must free it yourself afterwards. * @param centiSecondsPerFrame How many hundredths of a second this frame should be displayed for. * Note: This being specified in centiseconds is a limitation of the GIF format. @@ -146,35 +111,6 @@ MsfGifResult msf_gif_end(MsfGifState * handle); */ void msf_gif_free(MsfGifResult result); -//The gif format only supports 1-bit transparency, meaning a pixel will either be fully transparent or fully opaque. -//Pixels with an alpha value less than the alpha threshold will be treated as transparent. -//To enable exporting transparent gifs, set it to a value between 1 and 255 (inclusive) before calling msf_gif_frame(). -//Setting it to 0 causes the alpha channel to be ignored. Its initial value is 0. -extern int msf_gif_alpha_threshold; - -//Set `msf_gif_bgra_flag = true` before calling `msf_gif_frame()` if your pixels are in BGRA byte order instead of RBGA. -extern int msf_gif_bgra_flag; - - - -//TO-FILE FUNCTIONS -//These functions are equivalent to the ones above, but they write results to a file incrementally, -//instead of building a buffer in memory. This can result in lower memory usage when saving large gifs, -//because memory usage is bounded by only the size of a single frame, and is not dependent on the number of frames. -//There is currently no reason to use these unless you are on a memory-constrained platform. -//If in doubt about which API to use, for now you should use the normal (non-file) functions above. -//The signature of MsfGifFileWriteFunc matches fwrite for convenience, so that you can use the C file API like so: -// FILE * fp = fopen("MyGif.gif", "wb"); -// msf_gif_begin_to_file(&handle, width, height, (MsfGifFileWriteFunc) fwrite, (void *) fp); -// msf_gif_frame_to_file(...) -// msf_gif_end_to_file(&handle); -// fclose(fp); -//If you use a custom file write function, you must take care to return the same values that fwrite() would return. -//Note that all three functions will potentially write to the file. -int msf_gif_begin_to_file(MsfGifState * handle, int width, int height, MsfGifFileWriteFunc func, void * filePointer); -int msf_gif_frame_to_file(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes); -int msf_gif_end_to_file(MsfGifState * handle); //returns 0 on error and non-zero on success - #ifdef __cplusplus } #endif //__cplusplus @@ -189,6 +125,10 @@ int msf_gif_end_to_file(MsfGifState * handle); //returns 0 on error and non-zero #ifndef MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT #define MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT +#ifndef MSF_GIF_BUFFER_INIT_SIZE +#define MSF_GIF_BUFFER_INIT_SIZE 1024 * 1024 * 4 //4MB by default, you can increase this if you want to realloc less +#endif + //ensure the library user has either defined all of malloc/realloc/free, or none #if defined(MSF_GIF_MALLOC) && defined(MSF_GIF_REALLOC) && defined(MSF_GIF_FREE) //ok #elif !defined(MSF_GIF_MALLOC) && !defined(MSF_GIF_REALLOC) && !defined(MSF_GIF_FREE) //ok @@ -249,34 +189,28 @@ static inline int msf_imax(int a, int b) { return b < a? a : b; } #include #endif -int msf_gif_alpha_threshold = 0; -int msf_gif_bgra_flag = 0; - -static void msf_cook_frame(MsfCookedFrame * frame, uint8_t * raw, uint8_t * used, - int width, int height, int pitch, int depth) +static MsfCookedFrame msf_cook_frame(void * allocContext, uint8_t * raw, uint8_t * used, + int width, int height, int pitch, int depth) { MsfTimeFunc //bit depth for each channel - static const int rdepthsArray[17] = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5 }; - static const int gdepthsArray[17] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6 }; - static const int bdepthsArray[17] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5 }; - //this extra level of indirection looks unnecessary but we need to explicitly decay the arrays to pointers - //in order to be able to swap them because of C's annoying not-quite-pointers, not-quite-value-types stack arrays. - const int * rdepths = msf_gif_bgra_flag? bdepthsArray : rdepthsArray; - const int * gdepths = gdepthsArray; - const int * bdepths = msf_gif_bgra_flag? rdepthsArray : bdepthsArray; + const static int rdepths[17] = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5 }; + const static int gdepths[17] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6 }; + const static int bdepths[17] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5 }; - static const int ditherKernel[16] = { + const static int ditherKernel[16] = { 0 << 12, 8 << 12, 2 << 12, 10 << 12, 12 << 12, 4 << 12, 14 << 12, 6 << 12, 3 << 12, 11 << 12, 1 << 12, 9 << 12, 15 << 12, 7 << 12, 13 << 12, 5 << 12, }; - uint32_t * cooked = frame->pixels; + uint32_t * cooked = (uint32_t *) MSF_GIF_MALLOC(allocContext, width * height * sizeof(uint32_t)); + if (!cooked) { MsfCookedFrame blank = {0}; return blank; } + int count = 0; MsfTimeLoop("do") do { int rbits = rdepths[depth], gbits = gdepths[depth], bbits = bdepths[depth]; - int paletteSize = (1 << (rbits + gbits + bbits)) + 1; + int paletteSize = 1 << (rbits + gbits + bbits); memset(used, 0, paletteSize * sizeof(uint8_t)); //TODO: document what this math does and why it's correct @@ -296,6 +230,7 @@ static void msf_cook_frame(MsfCookedFrame * frame, uint8_t * raw, uint8_t * used #if (defined (__SSE2__) || defined (_M_X64) || _M_IX86_FP == 2) && !defined(MSF_GIF_NO_SSE2) __m128i k = _mm_loadu_si128((__m128i *) &ditherKernel[(y & 3) * 4]); __m128i k2 = _mm_or_si128(_mm_srli_epi32(k, rbits), _mm_slli_epi32(_mm_srli_epi32(k, bbits), 16)); + // MsfTimeLoop("SIMD") for (; x < width - 3; x += 4) { uint8_t * pixels = &raw[y * pitch + x * 4]; __m128i p = _mm_loadu_si128((__m128i *) pixels); @@ -311,30 +246,17 @@ static void msf_cook_frame(MsfCookedFrame * frame, uint8_t * raw, uint8_t * used __m128i g2 = _mm_adds_epu16(g1, _mm_srli_epi32(k, gbits)); __m128i g3 = _mm_and_si128(_mm_srli_epi32(g2, 16 - rbits - gbits), _mm_set1_epi32(gmask)); - __m128i out = _mm_or_si128(_mm_or_si128(r3, g3), b3); - - //mask in transparency based on threshold - //NOTE: we can theoretically do a sub instead of srli by doing an unsigned compare via bias - // to maybe save a TINY amount of throughput? but lol who cares maybe I'll do it later -m - __m128i invAlphaMask = _mm_cmplt_epi32(_mm_srli_epi32(p, 24), _mm_set1_epi32(msf_gif_alpha_threshold)); - out = _mm_or_si128(_mm_and_si128(invAlphaMask, _mm_set1_epi32(paletteSize - 1)), _mm_andnot_si128(invAlphaMask, out)); - //TODO: does storing this as a __m128i then reading it back as a uint32_t violate strict aliasing? uint32_t * c = &cooked[y * width + x]; + __m128i out = _mm_or_si128(_mm_or_si128(r3, g3), b3); _mm_storeu_si128((__m128i *) c, out); } #endif //scalar cleanup loop + // MsfTimeLoop("scalar") for (; x < width; ++x) { uint8_t * p = &raw[y * pitch + x * 4]; - - //transparent pixel if alpha is low - if (p[3] < msf_gif_alpha_threshold) { - cooked[y * width + x] = paletteSize - 1; - continue; - } - int dx = x & 3, dy = y & 3; int k = ditherKernel[dy * 4 + dx]; cooked[y * width + x] = @@ -345,25 +267,30 @@ static void msf_cook_frame(MsfCookedFrame * frame, uint8_t * raw, uint8_t * used } count = 0; - MsfTimeLoop("mark") for (int i = 0; i < width * height; ++i) { + MsfTimeLoop("mark and count") for (int i = 0; i < width * height; ++i) { used[cooked[i]] = 1; } - //count used colors, transparent is ignored - MsfTimeLoop("count") for (int j = 0; j < paletteSize - 1; ++j) { + //count used colors + MsfTimeLoop("count") for (int j = 0; j < paletteSize; ++j) { count += used[j]; } } while (count >= 256 && --depth); MsfCookedFrame ret = { cooked, depth, count, rdepths[depth], gdepths[depth], bdepths[depth] }; - *frame = ret; + return ret; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Frame Compression /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static inline void msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int len, uint32_t code) { +typedef struct { + uint8_t * next; + size_t size; +} MsfBufferHeader; + +static inline int msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int len, uint32_t code) { //insert new code into block buffer int idx = *blockBits / 8; int bit = *blockBits % 8; @@ -381,6 +308,8 @@ static inline void msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int (*writeHead)[0] = 255; memset((*writeHead) + 4, 0, 256); } + + return 1; } typedef struct { @@ -395,29 +324,30 @@ static inline void msf_lzw_reset(MsfStridedList * lzw, int tableSize, int stride lzw->stride = stride; } -static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int height, int centiSeconds, - MsfCookedFrame frame, MsfGifState * handle, uint8_t * used, int16_t * lzwMem) +static uint8_t * msf_compress_frame(void * allocContext, int width, int height, int centiSeconds, + MsfCookedFrame frame, MsfCookedFrame previous, uint8_t * used) { MsfTimeFunc //NOTE: we reserve enough memory for theoretical the worst case upfront because it's a reasonable amount, // and prevents us from ever having to check size or realloc during compression - int maxBufSize = offsetof(MsfGifBuffer, data) + 32 + 256 * 3 + width * height * 3 / 2; //headers + color table + data - MsfGifBuffer * buffer = (MsfGifBuffer *) MSF_GIF_MALLOC(allocContext, maxBufSize); - if (!buffer) { return NULL; } - uint8_t * writeHead = buffer->data; - MsfStridedList lzw = { lzwMem, 0, 0 }; + int maxBufSize = sizeof(MsfBufferHeader) + 32 + 256 * 3 + width * height * 3 / 2; //headers + color table + data + uint8_t * allocation = (uint8_t *) MSF_GIF_MALLOC(allocContext, maxBufSize); + if (!allocation) { return NULL; } + uint8_t * writeBase = allocation + sizeof(MsfBufferHeader); + uint8_t * writeHead = writeBase; + int lzwAllocSize = 4096 * (frame.count + 1) * sizeof(int16_t); + MsfStridedList lzw = { (int16_t *) MSF_GIF_MALLOC(allocContext, lzwAllocSize) }; + if (!lzw.data) { MSF_GIF_FREE(allocContext, allocation, maxBufSize); return NULL; } //allocate tlb int totalBits = frame.rbits + frame.gbits + frame.bbits; - int tlbSize = (1 << totalBits) + 1; - uint8_t tlb[(1 << 16) + 1]; //only 64k, so stack allocating is fine + int tlbSize = 1 << totalBits; + uint8_t tlb[1 << 16]; //only 64k, so stack allocating is fine //generate palette typedef struct { uint8_t r, g, b; } Color3; Color3 table[256] = { {0} }; int tableIdx = 1; //we start counting at 1 because 0 is the transparent color - //transparent is always last in the table - tlb[tlbSize-1] = 0; - MsfTimeLoop("table") for (int i = 0; i < tlbSize-1; ++i) { + MsfTimeLoop("table") for (int i = 0; i < tlbSize; ++i) { if (used[i]) { tlb[i] = tableIdx; int rmask = (1 << frame.rbits) - 1; @@ -433,32 +363,19 @@ static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int hei table[tableIdx].r = r | r >> frame.rbits | r >> (frame.rbits * 2) | r >> (frame.rbits * 3); table[tableIdx].g = g | g >> frame.gbits | g >> (frame.gbits * 2) | g >> (frame.gbits * 3); table[tableIdx].b = b | b >> frame.bbits | b >> (frame.bbits * 2) | b >> (frame.bbits * 3); - if (msf_gif_bgra_flag) { - uint8_t temp = table[tableIdx].r; - table[tableIdx].r = table[tableIdx].b; - table[tableIdx].b = temp; - } ++tableIdx; } } - int hasTransparentPixels = used[tlbSize-1]; //SPEC: "Because of some algorithmic constraints however, black & white images which have one color bit // must be indicated as having a code size of 2." int tableBits = msf_imax(2, msf_bit_log(tableIdx - 1)); int tableSize = 1 << tableBits; //NOTE: we don't just compare `depth` field here because it will be wrong for the first frame and we will segfault - MsfCookedFrame previous = handle->previousFrame; int hasSamePal = frame.rbits == previous.rbits && frame.gbits == previous.gbits && frame.bbits == previous.bbits; - int framesCompatible = hasSamePal && !hasTransparentPixels; //NOTE: because __attribute__((__packed__)) is annoyingly compiler-specific, we do this unreadable weirdness char headerBytes[19] = "\x21\xF9\x04\x05\0\0\0\0" "\x2C\0\0\0\0\0\0\0\0\x80"; - //NOTE: we need to check the frame number because if we reach into the buffer prior to the first frame, - // we'll just clobber the file header instead, which is a bug - if (hasTransparentPixels && handle->framesSubmitted > 0) { - handle->listTail->data[3] = 0x09; //set the previous frame's disposal to background, so transparency is possible - } memcpy(&headerBytes[4], ¢iSeconds, 2); memcpy(&headerBytes[13], &width, 2); memcpy(&headerBytes[15], &height, 2); @@ -480,10 +397,12 @@ static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int hei msf_lzw_reset(&lzw, tableSize, tableIdx); msf_put_code(&writeHead, &blockBits, msf_bit_log(lzw.len - 1), tableSize); - int lastCode = framesCompatible && frame.pixels[0] == previous.pixels[0]? 0 : tlb[frame.pixels[0]]; + int lastCode = hasSamePal && frame.pixels[0] == previous.pixels[0]? 0 : tlb[frame.pixels[0]]; MsfTimeLoop("compress") for (int i = 1; i < width * height; ++i) { //PERF: branching vs. branchless version of this line is observed to have no discernable impact on speed - int color = framesCompatible && frame.pixels[i] == previous.pixels[i]? 0 : tlb[frame.pixels[i]]; + int color = hasSamePal && frame.pixels[i] == previous.pixels[i]? 0 : tlb[frame.pixels[i]]; + //PERF: branchless version must use && otherwise it will segfault on frame 1, but it's well-predicted so OK + // int color = (!(hasSamePal && frame.pixels[i] == previous.pixels[i])) * tlb[frame.pixels[i]]; int code = (&lzw.data[lastCode * lzw.stride])[color]; if (code < 0) { //write to code stream @@ -505,6 +424,9 @@ static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int hei } } + MSF_GIF_FREE(allocContext, lzw.data, lzwAllocSize); + MSF_GIF_FREE(allocContext, previous.pixels, width * height * sizeof(uint32_t)); + //write code for leftover index buffer contents, then the end code msf_put_code(&writeHead, &blockBits, msf_imin(12, msf_bit_log(lzw.len - 1)), lastCode); msf_put_code(&writeHead, &blockBits, msf_imin(12, msf_bit_log(lzw.len)), tableSize + 1); @@ -517,72 +439,38 @@ static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int hei } *writeHead++ = 0; //terminating block - //fill in buffer header and shrink buffer to fit data - buffer->next = NULL; - buffer->size = writeHead - buffer->data; - MsfGifBuffer * moved = - (MsfGifBuffer *) MSF_GIF_REALLOC(allocContext, buffer, maxBufSize, offsetof(MsfGifBuffer, data) + buffer->size); - if (!moved) { MSF_GIF_FREE(allocContext, buffer, maxBufSize); return NULL; } + //filling in buffer header and shrink buffer to fit data + MsfBufferHeader * header = (MsfBufferHeader *) allocation; + header->next = NULL; + header->size = writeHead - writeBase; + uint8_t * moved = (uint8_t *) MSF_GIF_REALLOC(allocContext, allocation, maxBufSize, writeHead - allocation); + if (!moved) { MSF_GIF_FREE(allocContext, allocation, maxBufSize); return NULL; } return moved; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// To-memory API /// +/// Incremental API /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static const int lzwAllocSize = 4096 * 256 * sizeof(int16_t); - -//NOTE: by C standard library conventions, freeing NULL should be a no-op, -// but just in case the user's custom free doesn't follow that rule, we do null checks on our end as well. -static void msf_free_gif_state(MsfGifState * handle) { - if (handle->previousFrame.pixels) MSF_GIF_FREE(handle->customAllocatorContext, handle->previousFrame.pixels, - handle->width * handle->height * sizeof(uint32_t)); - if (handle->currentFrame.pixels) MSF_GIF_FREE(handle->customAllocatorContext, handle->currentFrame.pixels, - handle->width * handle->height * sizeof(uint32_t)); - if (handle->lzwMem) MSF_GIF_FREE(handle->customAllocatorContext, handle->lzwMem, lzwAllocSize); - for (MsfGifBuffer * node = handle->listHead; node;) { - MsfGifBuffer * next = node->next; //NOTE: we have to copy the `next` pointer BEFORE freeing the node holding it - MSF_GIF_FREE(handle->customAllocatorContext, node, offsetof(MsfGifBuffer, data) + node->size); - node = next; - } - handle->listHead = NULL; //this implicitly marks the handle as invalid until the next msf_gif_begin() call -} - int msf_gif_begin(MsfGifState * handle, int width, int height) { MsfTimeFunc - //NOTE: we cannot stomp the entire struct to zero because we must preserve `customAllocatorContext`. MsfCookedFrame empty = {0}; //god I hate MSVC... handle->previousFrame = empty; - handle->currentFrame = empty; handle->width = width; handle->height = height; - handle->framesSubmitted = 0; - - //allocate memory for LZW buffer - //NOTE: Unfortunately we can't just use stack memory for the LZW table because it's 2MB, - // which is more stack space than most operating systems give by default, - // and we can't realistically expect users to be willing to override that just to use our library, - // so we have to allocate this on the heap. - handle->lzwMem = (int16_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, lzwAllocSize); - handle->previousFrame.pixels = - (uint32_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, handle->width * handle->height * sizeof(uint32_t)); - handle->currentFrame.pixels = - (uint32_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, handle->width * handle->height * sizeof(uint32_t)); //setup header buffer header (lol) - handle->listHead = (MsfGifBuffer *) MSF_GIF_MALLOC(handle->customAllocatorContext, offsetof(MsfGifBuffer, data) + 32); - if (!handle->listHead || !handle->lzwMem || !handle->previousFrame.pixels || !handle->currentFrame.pixels) { - msf_free_gif_state(handle); - return 0; - } + handle->listHead = (uint8_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, sizeof(MsfBufferHeader) + 32); + if (!handle->listHead) { return 0; } handle->listTail = handle->listHead; - handle->listHead->next = NULL; - handle->listHead->size = 32; + MsfBufferHeader * header = (MsfBufferHeader *) handle->listHead; + header->next = NULL; + header->size = 32; //NOTE: because __attribute__((__packed__)) is annoyingly compiler-specific, we do this unreadable weirdness - char headerBytes[33] = "GIF89a\0\0\0\0\x70\0\0" "\x21\xFF\x0BNETSCAPE2.0\x03\x01\0\0\0"; + char headerBytes[33] = "GIF89a\0\0\0\0\x10\0\0" "\x21\xFF\x0BNETSCAPE2.0\x03\x01\0\0\0"; memcpy(&headerBytes[6], &width, 2); memcpy(&headerBytes[8], &height, 2); - memcpy(handle->listHead->data, headerBytes, 32); + memcpy(handle->listHead + sizeof(MsfBufferHeader), headerBytes, 32); return 1; } @@ -594,83 +482,86 @@ int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPer if (pitchInBytes == 0) pitchInBytes = handle->width * 4; if (pitchInBytes < 0) pixelData -= pitchInBytes * (handle->height - 1); - uint8_t used[(1 << 16) + 1]; //only 64k, so stack allocating is fine - msf_cook_frame(&handle->currentFrame, pixelData, used, handle->width, handle->height, pitchInBytes, - msf_imin(maxBitDepth, handle->previousFrame.depth + 160 / msf_imax(1, handle->previousFrame.count))); + uint8_t used[1 << 16]; //only 64k, so stack allocating is fine + MsfCookedFrame frame = + msf_cook_frame(handle->customAllocatorContext, pixelData, used, handle->width, handle->height, pitchInBytes, + msf_imin(maxBitDepth, handle->previousFrame.depth + 160 / msf_imax(1, handle->previousFrame.count))); + //TODO: de-duplicate cleanup code + if (!frame.pixels) { + MSF_GIF_FREE(handle->customAllocatorContext, + handle->previousFrame.pixels, handle->width * handle->height * sizeof(uint32_t)); + for (uint8_t * node = handle->listHead; node;) { + MsfBufferHeader * header = (MsfBufferHeader *) node; + node = header->next; + MSF_GIF_FREE(handle->customAllocatorContext, header, sizeof(MsfBufferHeader) + header->size); + } + handle->listHead = handle->listTail = NULL; + return 0; + } - MsfGifBuffer * buffer = msf_compress_frame(handle->customAllocatorContext, handle->width, handle->height, - centiSecondsPerFame, handle->currentFrame, handle, used, handle->lzwMem); - if (!buffer) { msf_free_gif_state(handle); return 0; } - handle->listTail->next = buffer; + uint8_t * buffer = msf_compress_frame(handle->customAllocatorContext, + handle->width, handle->height, centiSecondsPerFame, frame, handle->previousFrame, used); + ((MsfBufferHeader *) handle->listTail)->next = buffer; handle->listTail = buffer; + if (!buffer) { + MSF_GIF_FREE(handle->customAllocatorContext, frame.pixels, handle->width * handle->height * sizeof(uint32_t)); + MSF_GIF_FREE(handle->customAllocatorContext, + handle->previousFrame.pixels, handle->width * handle->height * sizeof(uint32_t)); + for (uint8_t * node = handle->listHead; node;) { + MsfBufferHeader * header = (MsfBufferHeader *) node; + node = header->next; + MSF_GIF_FREE(handle->customAllocatorContext, header, sizeof(MsfBufferHeader) + header->size); + } + handle->listHead = handle->listTail = NULL; + return 0; + } - //swap current and previous frames - MsfCookedFrame tmp = handle->previousFrame; - handle->previousFrame = handle->currentFrame; - handle->currentFrame = tmp; - - handle->framesSubmitted += 1; + handle->previousFrame = frame; return 1; } MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc if (!handle->listHead) { MsfGifResult empty = {0}; return empty; } + MSF_GIF_FREE(handle->customAllocatorContext, + handle->previousFrame.pixels, handle->width * handle->height * sizeof(uint32_t)); + //first pass: determine total size size_t total = 1; //1 byte for trailing marker - for (MsfGifBuffer * node = handle->listHead; node; node = node->next) { total += node->size; } + for (uint8_t * node = handle->listHead; node;) { + MsfBufferHeader * header = (MsfBufferHeader *) node; + node = header->next; + total += header->size; + } //second pass: write data uint8_t * buffer = (uint8_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, total); if (buffer) { uint8_t * writeHead = buffer; - for (MsfGifBuffer * node = handle->listHead; node; node = node->next) { - memcpy(writeHead, node->data, node->size); - writeHead += node->size; + for (uint8_t * node = handle->listHead; node;) { + MsfBufferHeader * header = (MsfBufferHeader *) node; + memcpy(writeHead, node + sizeof(MsfBufferHeader), header->size); + writeHead += header->size; + node = header->next; } *writeHead++ = 0x3B; } //third pass: free buffers - msf_free_gif_state(handle); + for (uint8_t * node = handle->listHead; node;) { + MsfBufferHeader * header = (MsfBufferHeader *) node; + node = header->next; + MSF_GIF_FREE(handle->customAllocatorContext, header, sizeof(MsfBufferHeader) + header->size); + } MsfGifResult ret = { buffer, total, total, handle->customAllocatorContext }; return ret; } -void msf_gif_free(MsfGifResult result) { MsfTimeFunc +void msf_gif_free(MsfGifResult result) { if (result.data) { MSF_GIF_FREE(result.contextPointer, result.data, result.allocSize); } } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// To-file API /// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int msf_gif_begin_to_file(MsfGifState * handle, int width, int height, MsfGifFileWriteFunc func, void * filePointer) { - handle->fileWriteFunc = func; - handle->fileWriteData = filePointer; - return msf_gif_begin(handle, width, height); -} - -int msf_gif_frame_to_file(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes) { - if (!msf_gif_frame(handle, pixelData, centiSecondsPerFame, maxBitDepth, pitchInBytes)) { return 0; } - - //NOTE: this is a somewhat hacky implementation which is not perfectly efficient, but it's good enough for now - MsfGifBuffer * head = handle->listHead; - if (!handle->fileWriteFunc(head->data, head->size, 1, handle->fileWriteData)) { msf_free_gif_state(handle); return 0; } - handle->listHead = head->next; - MSF_GIF_FREE(handle->customAllocatorContext, head, offsetof(MsfGifBuffer, data) + head->size); - return 1; -} - -int msf_gif_end_to_file(MsfGifState * handle) { - //NOTE: this is a somewhat hacky implementation which is not perfectly efficient, but it's good enough for now - MsfGifResult result = msf_gif_end(handle); - int ret = (int) handle->fileWriteFunc(result.data, result.dataSize, 1, handle->fileWriteData); - msf_gif_free(result); - return ret; -} - #endif //MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT #endif //MSF_GIF_IMPL @@ -679,7 +570,7 @@ int msf_gif_end_to_file(MsfGifState * handle) { This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License -Copyright (c) 2021 Miles Fogle +Copyright (c) 2020 Miles Fogle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to diff --git a/raylib/external/par_shapes.h b/raylib/external/par_shapes.h index d530913..8b65e38 100644 --- a/raylib/external/par_shapes.h +++ b/raylib/external/par_shapes.h @@ -21,7 +21,8 @@ // coordinates (one per vertex). That's it! If you need something fancier, // look elsewhere. // -// Distributed under the MIT License, see bottom of file. +// The MIT License +// Copyright (c) 2015 Philip Rideout #ifndef PAR_SHAPES_H #define PAR_SHAPES_H @@ -31,7 +32,8 @@ extern "C" { #endif #include -// Ray (@raysan5): Commented to avoid conflict with raylib bool + +// Ray: commented to avoid conflict with raylib bool /* #if !defined(_MSC_VER) # include @@ -39,9 +41,9 @@ extern "C" { # if _MSC_VER >= 1800 # include # else // stdbool.h missing prior to MSVC++ 12.0 (VS2013) -# define bool int -# define true 1 -# define false 0 +//# define bool int +//# define true 1 +//# define false 0 # endif #endif */ @@ -69,14 +71,6 @@ void par_shapes_free_mesh(par_shapes_mesh*); // both 1.0, but they can easily be changed with par_shapes_scale. par_shapes_mesh* par_shapes_create_cylinder(int slices, int stacks); -// Cone is similar to cylinder but the radius diminishes to zero as Z increases. -// Again, height and radius are 1.0, but can be changed with par_shapes_scale. -par_shapes_mesh* par_shapes_create_cone(int slices, int stacks); - -// Create a disk of radius 1.0 with texture coordinates and normals by squashing -// a cone flat on the Z=0 plane. -par_shapes_mesh* par_shapes_create_parametric_disk(int slices, int stacks); - // Create a donut that sits on the Z=0 plane with the specified inner radius. // The outer radius can be controlled with par_shapes_scale. par_shapes_mesh* par_shapes_create_torus(int slices, int stacks, float radius); @@ -178,17 +172,6 @@ par_shapes_mesh* par_shapes_weld(par_shapes_mesh const*, float epsilon, // Compute smooth normals by averaging adjacent facet normals. void par_shapes_compute_normals(par_shapes_mesh* m); -// Global Config --------------------------------------------------------------- - -void par_shapes_set_epsilon_welded_normals(float epsilon); -void par_shapes_set_epsilon_degenerate_sphere(float epsilon); - -// Advanced -------------------------------------------------------------------- - -void par_shapes__compute_welded_normals(par_shapes_mesh* m); -void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder, - int slices); - #ifndef PAR_PI #define PAR_PI (3.14159265359) #define PAR_MIN(a, b) (a > b ? b : a) @@ -222,15 +205,11 @@ void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder, #include #include -static float par_shapes__epsilon_welded_normals = 0.001; -static float par_shapes__epsilon_degenerate_sphere = 0.0001; - static void par_shapes__sphere(float const* uv, float* xyz, void*); static void par_shapes__hemisphere(float const* uv, float* xyz, void*); static void par_shapes__plane(float const* uv, float* xyz, void*); static void par_shapes__klein(float const* uv, float* xyz, void*); static void par_shapes__cylinder(float const* uv, float* xyz, void*); -static void par_shapes__cone(float const* uv, float* xyz, void*); static void par_shapes__torus(float const* uv, float* xyz, void*); static void par_shapes__trefoil(float const* uv, float* xyz, void*); @@ -319,12 +298,11 @@ static float par_shapes__sqrdist3(float const* a, float const* b) return dx * dx + dy * dy + dz * dz; } -void par_shapes__compute_welded_normals(par_shapes_mesh* m) +static void par_shapes__compute_welded_normals(par_shapes_mesh* m) { - const float epsilon = par_shapes__epsilon_welded_normals; m->normals = PAR_MALLOC(float, m->npoints * 3); PAR_SHAPES_T* weldmap = PAR_MALLOC(PAR_SHAPES_T, m->npoints); - par_shapes_mesh* welded = par_shapes_weld(m, epsilon, weldmap); + par_shapes_mesh* welded = par_shapes_weld(m, 0.01, weldmap); par_shapes_compute_normals(welded); float* pdst = m->normals; for (int i = 0; i < m->npoints; i++, pdst += 3) { @@ -347,24 +325,6 @@ par_shapes_mesh* par_shapes_create_cylinder(int slices, int stacks) stacks, 0); } -par_shapes_mesh* par_shapes_create_cone(int slices, int stacks) -{ - if (slices < 3 || stacks < 1) { - return 0; - } - return par_shapes_create_parametric(par_shapes__cone, slices, - stacks, 0); -} - -par_shapes_mesh* par_shapes_create_parametric_disk(int slices, int stacks) -{ - par_shapes_mesh* m = par_shapes_create_cone(slices, stacks); - if (m) { - par_shapes_scale(m, 1.0f, 1.0f, 0.0f); - } - return m; -} - par_shapes_mesh* par_shapes_create_parametric_sphere(int slices, int stacks) { if (slices < 3 || stacks < 3) { @@ -372,7 +332,7 @@ par_shapes_mesh* par_shapes_create_parametric_sphere(int slices, int stacks) } par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__sphere, slices, stacks, 0); - par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere); + par_shapes_remove_degenerate(m, 0.0001); return m; } @@ -383,7 +343,7 @@ par_shapes_mesh* par_shapes_create_hemisphere(int slices, int stacks) } par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__hemisphere, slices, stacks, 0); - par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere); + par_shapes_remove_degenerate(m, 0.0001); return m; } @@ -619,15 +579,6 @@ static void par_shapes__cylinder(float const* uv, float* xyz, void* userdata) xyz[2] = uv[0]; } -static void par_shapes__cone(float const* uv, float* xyz, void* userdata) -{ - float r = 1.0f - uv[0]; - float theta = uv[1] * 2 * PAR_PI; - xyz[0] = r * sinf(theta); - xyz[1] = r * cosf(theta); - xyz[2] = uv[0]; -} - static void par_shapes__torus(float const* uv, float* xyz, void* userdata) { float major = 1; @@ -669,14 +620,6 @@ static void par_shapes__trefoil(float const* uv, float* xyz, void* userdata) xyz[2] = z + d * ww[2] * sin(v); } -void par_shapes_set_epsilon_welded_normals(float epsilon) { - par_shapes__epsilon_welded_normals = epsilon; -} - -void par_shapes_set_epsilon_degenerate_sphere(float epsilon) { - par_shapes__epsilon_degenerate_sphere = epsilon; -} - void par_shapes_merge(par_shapes_mesh* dst, par_shapes_mesh const* src) { PAR_SHAPES_T offset = dst->npoints; @@ -801,15 +744,15 @@ void par_shapes_rotate(par_shapes_mesh* mesh, float radians, float const* axis) p[1] = y; p[2] = z; } - float* n = mesh->normals; - if (n) { - for (int i = 0; i < mesh->npoints; i++, n += 3) { - float x = col0[0] * n[0] + col1[0] * n[1] + col2[0] * n[2]; - float y = col0[1] * n[0] + col1[1] * n[1] + col2[1] * n[2]; - float z = col0[2] * n[0] + col1[2] * n[1] + col2[2] * n[2]; - n[0] = x; - n[1] = y; - n[2] = z; + p = mesh->normals; + if (p) { + for (int i = 0; i < mesh->npoints; i++, p += 3) { + float x = col0[0] * p[0] + col1[0] * p[1] + col2[0] * p[2]; + float y = col0[1] * p[0] + col1[1] * p[1] + col2[1] * p[2]; + float z = col0[2] * p[0] + col1[2] * p[1] + col2[2] * p[2]; + p[0] = x; + p[1] = y; + p[2] = z; } } } @@ -822,27 +765,6 @@ void par_shapes_scale(par_shapes_mesh* m, float x, float y, float z) *points++ *= y; *points++ *= z; } - float* n = m->normals; - if (n && !(x == y && y == z)) { - bool x_zero = x == 0; - bool y_zero = y == 0; - bool z_zero = z == 0; - if (!x_zero && !y_zero && !z_zero) { - x = 1.0f / x; - y = 1.0f / y; - z = 1.0f / z; - } else { - x = x_zero && !y_zero && !z_zero; - y = y_zero && !x_zero && !z_zero; - z = z_zero && !x_zero && !y_zero; - } - for (int i = 0; i < m->npoints; i++, n += 3) { - n[0] *= x; - n[1] *= y; - n[2] *= z; - par_shapes__normalize3(n); - } - } } void par_shapes_merge_and_free(par_shapes_mesh* dst, par_shapes_mesh* src) @@ -1130,7 +1052,7 @@ static par_shapes__rule* par_shapes__pick_rule(const char* name, total += rule->weight; } } - float r = (float) rand() / (float) RAND_MAX; + float r = (float) rand() / RAND_MAX; float t = 0; for (int i = 0; i < nrules; i++) { rule = rules + i; @@ -1176,8 +1098,8 @@ static par_shapes_mesh* par_shapes__apply_turtle(par_shapes_mesh* mesh, return m; } -void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder, - int slices) +static void par_shapes__connect(par_shapes_mesh* scene, + par_shapes_mesh* cylinder, int slices) { int stacks = 1; int npoints = (slices + 1) * (stacks + 1); @@ -1196,8 +1118,7 @@ void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder, // Create the new triangle list. int ntriangles = scene->ntriangles + 2 * slices * stacks; PAR_SHAPES_T* triangles = PAR_MALLOC(PAR_SHAPES_T, ntriangles * 3); - memcpy(triangles, scene->triangles, - sizeof(PAR_SHAPES_T) * scene->ntriangles * 3); + memcpy(triangles, scene->triangles, 2 * scene->ntriangles * 3); int v = scene->npoints - (slices + 1); PAR_SHAPES_T* face = triangles + scene->ntriangles * 3; for (int stack = 0; stack < stacks; stack++) { @@ -1233,7 +1154,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices, while (cmd) { char *arg = strtok(0, " "); if (!arg) { - puts("lsystem error: unexpected end of program."); + //puts("lsystem error: unexpected end of program."); break; } if (!strcmp(cmd, "rule")) { @@ -1287,6 +1208,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices, // For testing purposes, dump out the parsed program. #ifdef TEST_PARSE + /* for (int i = 0; i < nrules; i++) { par_shapes__rule rule = rules[i]; printf("rule %s.%d\n", rule.name, rule.weight); @@ -1295,6 +1217,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices, printf("\t%s %s\n", cmd.cmd, cmd.arg); } } + */ #endif // Instantiate the aggregated shape and the template shapes. @@ -1335,8 +1258,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices, par_shapes__command* cmd = rule->commands + (frame->pc++); #ifdef DUMP_TRACE - printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name, - frame->pc - 1, stackptr); + //printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name, frame->pc - 1, stackptr); #endif float value; @@ -1698,7 +1620,7 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize, PAR_SHAPES_T binvalue = *(bins + binindex); if (binvalue > 0) { if (nbins == 8) { - printf("Epsilon value is too large.\n"); + //printf("Epsilon value is too large.\n"); break; } nearby[nbins++] = binindex; @@ -1710,9 +1632,8 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize, // Check for colocated points in each nearby bin. for (int b = 0; b < nbins; b++) { int binindex = nearby[b]; - PAR_SHAPES_T binvalue = bins[binindex]; + PAR_SHAPES_T binvalue = *(bins + binindex); PAR_SHAPES_T nindex = binvalue - 1; - assert(nindex < mesh->npoints); while (true) { // If this isn't "self" and it's colocated, then weld it! @@ -1778,9 +1699,6 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize, PAR_SHAPES_T b = weldmap[tsrc[1]]; PAR_SHAPES_T c = weldmap[tsrc[2]]; if (a != b && a != c && b != c) { - assert(a < mesh->npoints); - assert(b < mesh->npoints); - assert(c < mesh->npoints); *tdst++ = a; *tdst++ = b; *tdst++ = c; @@ -2131,25 +2049,3 @@ void par_shapes_remove_degenerate(par_shapes_mesh* mesh, float mintriarea) #endif // PAR_SHAPES_IMPLEMENTATION #endif // PAR_SHAPES_H - -// par_shapes is distributed under the MIT license: -// -// Copyright (c) 2019 Philip Rideout -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. diff --git a/raylib/external/qoa.h b/raylib/external/qoa.h deleted file mode 100644 index f0f4421..0000000 --- a/raylib/external/qoa.h +++ /dev/null @@ -1,742 +0,0 @@ -/* - -Copyright (c) 2023, Dominic Szablewski - https://phoboslab.org -SPDX-License-Identifier: MIT - -QOA - The "Quite OK Audio" format for fast, lossy audio compression - - --- Data Format - -QOA encodes pulse-code modulated (PCM) audio data with up to 255 channels, -sample rates from 1 up to 16777215 hertz and a bit depth of 16 bits. - -The compression method employed in QOA is lossy; it discards some information -from the uncompressed PCM data. For many types of audio signals this compression -is "transparent", i.e. the difference from the original file is often not -audible. - -QOA encodes 20 samples of 16 bit PCM data into slices of 64 bits. A single -sample therefore requires 3.2 bits of storage space, resulting in a 5x -compression (16 / 3.2). - -A QOA file consists of an 8 byte file header, followed by a number of frames. -Each frame contains an 8 byte frame header, the current 16 byte en-/decoder -state per channel and 256 slices per channel. Each slice is 8 bytes wide and -encodes 20 samples of audio data. - -All values, including the slices, are big endian. The file layout is as follows: - -struct { - struct { - char magic[4]; // magic bytes "qoaf" - uint32_t samples; // samples per channel in this file - } file_header; - - struct { - struct { - uint8_t num_channels; // no. of channels - uint24_t samplerate; // samplerate in hz - uint16_t fsamples; // samples per channel in this frame - uint16_t fsize; // frame size (includes this header) - } frame_header; - - struct { - int16_t history[4]; // most recent last - int16_t weights[4]; // most recent last - } lms_state[num_channels]; - - qoa_slice_t slices[256][num_channels]; - - } frames[ceil(samples / (256 * 20))]; -} qoa_file_t; - -Each `qoa_slice_t` contains a quantized scalefactor `sf_quant` and 20 quantized -residuals `qrNN`: - -.- QOA_SLICE -- 64 bits, 20 samples --------------------------/ /------------. -| Byte[0] | Byte[1] | Byte[2] \ \ Byte[7] | -| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 / / 2 1 0 | -|------------+--------+--------+--------+---------+---------+-\ \--+---------| -| sf_quant | qr00 | qr01 | qr02 | qr03 | qr04 | / / | qr19 | -`-------------------------------------------------------------\ \------------` - -Each frame except the last must contain exactly 256 slices per channel. The last -frame may contain between 1 .. 256 (inclusive) slices per channel. The last -slice (for each channel) in the last frame may contain less than 20 samples; the -slice still must be 8 bytes wide, with the unused samples zeroed out. - -Channels are interleaved per slice. E.g. for 2 channel stereo: -slice[0] = L, slice[1] = R, slice[2] = L, slice[3] = R ... - -A valid QOA file or stream must have at least one frame. Each frame must contain -at least one channel and one sample with a samplerate between 1 .. 16777215 -(inclusive). - -If the total number of samples is not known by the encoder, the samples in the -file header may be set to 0x00000000 to indicate that the encoder is -"streaming". In a streaming context, the samplerate and number of channels may -differ from frame to frame. For static files (those with samples set to a -non-zero value), each frame must have the same number of channels and same -samplerate. - -Note that this implementation of QOA only handles files with a known total -number of samples. - -A decoder should support at least 8 channels. The channel layout for channel -counts 1 .. 8 is: - - 1. Mono - 2. L, R - 3. L, R, C - 4. FL, FR, B/SL, B/SR - 5. FL, FR, C, B/SL, B/SR - 6. FL, FR, C, LFE, B/SL, B/SR - 7. FL, FR, C, LFE, B, SL, SR - 8. FL, FR, C, LFE, BL, BR, SL, SR - -QOA predicts each audio sample based on the previously decoded ones using a -"Sign-Sign Least Mean Squares Filter" (LMS). This prediction plus the -dequantized residual forms the final output sample. - -*/ - - - -/* ----------------------------------------------------------------------------- - Header - Public functions */ - -#ifndef QOA_H -#define QOA_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define QOA_MIN_FILESIZE 16 -#define QOA_MAX_CHANNELS 8 - -#define QOA_SLICE_LEN 20 -#define QOA_SLICES_PER_FRAME 256 -#define QOA_FRAME_LEN (QOA_SLICES_PER_FRAME * QOA_SLICE_LEN) -#define QOA_LMS_LEN 4 -#define QOA_MAGIC 0x716f6166 /* 'qoaf' */ - -#define QOA_FRAME_SIZE(channels, slices) \ - (8 + QOA_LMS_LEN * 4 * channels + 8 * slices * channels) - -typedef struct { - int history[QOA_LMS_LEN]; - int weights[QOA_LMS_LEN]; -} qoa_lms_t; - -typedef struct { - unsigned int channels; - unsigned int samplerate; - unsigned int samples; - qoa_lms_t lms[QOA_MAX_CHANNELS]; - #ifdef QOA_RECORD_TOTAL_ERROR - double error; - #endif -} qoa_desc; - -unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes); -unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes); -void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len); - -unsigned int qoa_max_frame_size(qoa_desc *qoa); -unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa); -unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len); -short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file); - -#ifndef QOA_NO_STDIO - -int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa); -void *qoa_read(const char *filename, qoa_desc *qoa); - -#endif /* QOA_NO_STDIO */ - - -#ifdef __cplusplus -} -#endif -#endif /* QOA_H */ - - -/* ----------------------------------------------------------------------------- - Implementation */ - -#ifdef QOA_IMPLEMENTATION -#include - -#ifndef QOA_MALLOC - #define QOA_MALLOC(sz) malloc(sz) - #define QOA_FREE(p) free(p) -#endif - -typedef unsigned long long qoa_uint64_t; - - -/* The quant_tab provides an index into the dequant_tab for residuals in the -range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at -the higher end. Note that the residual zero is identical to the lowest positive -value. This is mostly fine, since the qoa_div() function always rounds away -from zero. */ - -static const int qoa_quant_tab[17] = { - 7, 7, 7, 5, 5, 3, 3, 1, /* -8..-1 */ - 0, /* 0 */ - 0, 2, 2, 4, 4, 6, 6, 6 /* 1.. 8 */ -}; - - -/* We have 16 different scalefactors. Like the quantized residuals these become -less accurate at the higher end. In theory, the highest scalefactor that we -would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we -rely on the LMS filter to predict samples accurately enough that a maximum -residual of one quarter of the 16 bit range is sufficient. I.e. with the -scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14. - -The scalefactor values are computed as: -scalefactor_tab[s] <- round(pow(s + 1, 2.75)) */ - -static const int qoa_scalefactor_tab[16] = { - 1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048 -}; - - -/* The reciprocal_tab maps each of the 16 scalefactors to their rounded -reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in -the encoder with just one multiplication instead of an expensive division. We -do this in .16 fixed point with integers, instead of floats. - -The reciprocal_tab is computed as: -reciprocal_tab[s] <- ((1<<16) + scalefactor_tab[s] - 1) / scalefactor_tab[s] */ - -static const int qoa_reciprocal_tab[16] = { - 65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32 -}; - - -/* The dequant_tab maps each of the scalefactors and quantized residuals to -their unscaled & dequantized version. - -Since qoa_div rounds away from the zero, the smallest entries are mapped to 3/4 -instead of 1. The dequant_tab assumes the following dequantized values for each -of the quant_tab indices and is computed as: -float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7}; -dequant_tab[s][q] <- round_ties_away_from_zero(scalefactor_tab[s] * dqt[q]) - -The rounding employed here is "to nearest, ties away from zero", i.e. positive -and negative values are treated symmetrically. -*/ - -static const int qoa_dequant_tab[16][8] = { - { 1, -1, 3, -3, 5, -5, 7, -7}, - { 5, -5, 18, -18, 32, -32, 49, -49}, - { 16, -16, 53, -53, 95, -95, 147, -147}, - { 34, -34, 113, -113, 203, -203, 315, -315}, - { 63, -63, 210, -210, 378, -378, 588, -588}, - { 104, -104, 345, -345, 621, -621, 966, -966}, - { 158, -158, 528, -528, 950, -950, 1477, -1477}, - { 228, -228, 760, -760, 1368, -1368, 2128, -2128}, - { 316, -316, 1053, -1053, 1895, -1895, 2947, -2947}, - { 422, -422, 1405, -1405, 2529, -2529, 3934, -3934}, - { 548, -548, 1828, -1828, 3290, -3290, 5117, -5117}, - { 696, -696, 2320, -2320, 4176, -4176, 6496, -6496}, - { 868, -868, 2893, -2893, 5207, -5207, 8099, -8099}, - {1064, -1064, 3548, -3548, 6386, -6386, 9933, -9933}, - {1286, -1286, 4288, -4288, 7718, -7718, 12005, -12005}, - {1536, -1536, 5120, -5120, 9216, -9216, 14336, -14336}, -}; - - -/* The Least Mean Squares Filter is the heart of QOA. It predicts the next -sample based on the previous 4 reconstructed samples. It does so by continuously -adjusting 4 weights based on the residual of the previous prediction. - -The next sample is predicted as the sum of (weight[i] * history[i]). - -The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or -subtracts the residual to each weight, based on the corresponding sample from -the history. This, surprisingly, is sufficient to get worthwhile predictions. - -This is all done with fixed point integers. Hence the right-shifts when updating -the weights and calculating the prediction. */ - -static int qoa_lms_predict(qoa_lms_t *lms) { - int prediction = 0; - for (int i = 0; i < QOA_LMS_LEN; i++) { - prediction += lms->weights[i] * lms->history[i]; - } - return prediction >> 13; -} - -static void qoa_lms_update(qoa_lms_t *lms, int sample, int residual) { - int delta = residual >> 4; - for (int i = 0; i < QOA_LMS_LEN; i++) { - lms->weights[i] += lms->history[i] < 0 ? -delta : delta; - } - - for (int i = 0; i < QOA_LMS_LEN-1; i++) { - lms->history[i] = lms->history[i+1]; - } - lms->history[QOA_LMS_LEN-1] = sample; -} - - -/* qoa_div() implements a rounding division, but avoids rounding to zero for -small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still -returns as 0, which is handled in the qoa_quant_tab[]. -qoa_div() takes an index into the .16 fixed point qoa_reciprocal_tab as an -argument, so it can do the division with a cheaper integer multiplication. */ - -static inline int qoa_div(int v, int scalefactor) { - int reciprocal = qoa_reciprocal_tab[scalefactor]; - int n = (v * reciprocal + (1 << 15)) >> 16; - n = n + ((v > 0) - (v < 0)) - ((n > 0) - (n < 0)); /* round away from 0 */ - return n; -} - -static inline int qoa_clamp(int v, int min, int max) { - if (v < min) { return min; } - if (v > max) { return max; } - return v; -} - -/* This specialized clamp function for the signed 16 bit range improves decode -performance quite a bit. The extra if() statement works nicely with the CPUs -branch prediction as this branch is rarely taken. */ - -static inline int qoa_clamp_s16(int v) { - if ((unsigned int)(v + 32768) > 65535) { - if (v < -32768) { return -32768; } - if (v > 32767) { return 32767; } - } - return v; -} - -static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) { - bytes += *p; - *p += 8; - return - ((qoa_uint64_t)(bytes[0]) << 56) | ((qoa_uint64_t)(bytes[1]) << 48) | - ((qoa_uint64_t)(bytes[2]) << 40) | ((qoa_uint64_t)(bytes[3]) << 32) | - ((qoa_uint64_t)(bytes[4]) << 24) | ((qoa_uint64_t)(bytes[5]) << 16) | - ((qoa_uint64_t)(bytes[6]) << 8) | ((qoa_uint64_t)(bytes[7]) << 0); -} - -static inline void qoa_write_u64(qoa_uint64_t v, unsigned char *bytes, unsigned int *p) { - bytes += *p; - *p += 8; - bytes[0] = (v >> 56) & 0xff; - bytes[1] = (v >> 48) & 0xff; - bytes[2] = (v >> 40) & 0xff; - bytes[3] = (v >> 32) & 0xff; - bytes[4] = (v >> 24) & 0xff; - bytes[5] = (v >> 16) & 0xff; - bytes[6] = (v >> 8) & 0xff; - bytes[7] = (v >> 0) & 0xff; -} - - -/* ----------------------------------------------------------------------------- - Encoder */ - -unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes) { - unsigned int p = 0; - qoa_write_u64(((qoa_uint64_t)QOA_MAGIC << 32) | qoa->samples, bytes, &p); - return p; -} - -unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes) { - unsigned int channels = qoa->channels; - - unsigned int p = 0; - unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; - unsigned int frame_size = QOA_FRAME_SIZE(channels, slices); - int prev_scalefactor[QOA_MAX_CHANNELS] = {0}; - - /* Write the frame header */ - qoa_write_u64(( - (qoa_uint64_t)qoa->channels << 56 | - (qoa_uint64_t)qoa->samplerate << 32 | - (qoa_uint64_t)frame_len << 16 | - (qoa_uint64_t)frame_size - ), bytes, &p); - - - for (unsigned int c = 0; c < channels; c++) { - /* Write the current LMS state */ - qoa_uint64_t weights = 0; - qoa_uint64_t history = 0; - for (int i = 0; i < QOA_LMS_LEN; i++) { - history = (history << 16) | (qoa->lms[c].history[i] & 0xffff); - weights = (weights << 16) | (qoa->lms[c].weights[i] & 0xffff); - } - qoa_write_u64(history, bytes, &p); - qoa_write_u64(weights, bytes, &p); - } - - /* We encode all samples with the channels interleaved on a slice level. - E.g. for stereo: (ch-0, slice 0), (ch 1, slice 0), (ch 0, slice 1), ...*/ - for (unsigned int sample_index = 0; sample_index < frame_len; sample_index += QOA_SLICE_LEN) { - - for (unsigned int c = 0; c < channels; c++) { - int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index); - int slice_start = sample_index * channels + c; - int slice_end = (sample_index + slice_len) * channels + c; - - /* Brute for search for the best scalefactor. Just go through all - 16 scalefactors, encode all samples for the current slice and - meassure the total squared error. */ - qoa_uint64_t best_rank = -1; - #ifdef QOA_RECORD_TOTAL_ERROR - qoa_uint64_t best_error = -1; - #endif - qoa_uint64_t best_slice = 0; - qoa_lms_t best_lms; - int best_scalefactor = 0; - - for (int sfi = 0; sfi < 16; sfi++) { - /* There is a strong correlation between the scalefactors of - neighboring slices. As an optimization, start testing - the best scalefactor of the previous slice first. */ - int scalefactor = (sfi + prev_scalefactor[c]) % 16; - - /* We have to reset the LMS state to the last known good one - before trying each scalefactor, as each pass updates the LMS - state when encoding. */ - qoa_lms_t lms = qoa->lms[c]; - qoa_uint64_t slice = scalefactor; - qoa_uint64_t current_rank = 0; - #ifdef QOA_RECORD_TOTAL_ERROR - qoa_uint64_t current_error = 0; - #endif - - for (int si = slice_start; si < slice_end; si += channels) { - int sample = sample_data[si]; - int predicted = qoa_lms_predict(&lms); - - int residual = sample - predicted; - int scaled = qoa_div(residual, scalefactor); - int clamped = qoa_clamp(scaled, -8, 8); - int quantized = qoa_quant_tab[clamped + 8]; - int dequantized = qoa_dequant_tab[scalefactor][quantized]; - int reconstructed = qoa_clamp_s16(predicted + dequantized); - - - /* If the weights have grown too large, we introduce a penalty - here. This prevents pops/clicks in certain problem cases */ - int weights_penalty = (( - lms.weights[0] * lms.weights[0] + - lms.weights[1] * lms.weights[1] + - lms.weights[2] * lms.weights[2] + - lms.weights[3] * lms.weights[3] - ) >> 18) - 0x8ff; - if (weights_penalty < 0) { - weights_penalty = 0; - } - - long long error = (sample - reconstructed); - qoa_uint64_t error_sq = error * error; - - current_rank += error_sq + weights_penalty * weights_penalty; - #ifdef QOA_RECORD_TOTAL_ERROR - current_error += error_sq; - #endif - if (current_rank > best_rank) { - break; - } - - qoa_lms_update(&lms, reconstructed, dequantized); - slice = (slice << 3) | quantized; - } - - if (current_rank < best_rank) { - best_rank = current_rank; - #ifdef QOA_RECORD_TOTAL_ERROR - best_error = current_error; - #endif - best_slice = slice; - best_lms = lms; - best_scalefactor = scalefactor; - } - } - - prev_scalefactor[c] = best_scalefactor; - - qoa->lms[c] = best_lms; - #ifdef QOA_RECORD_TOTAL_ERROR - qoa->error += best_error; - #endif - - /* If this slice was shorter than QOA_SLICE_LEN, we have to left- - shift all encoded data, to ensure the rightmost bits are the empty - ones. This should only happen in the last frame of a file as all - slices are completely filled otherwise. */ - best_slice <<= (QOA_SLICE_LEN - slice_len) * 3; - qoa_write_u64(best_slice, bytes, &p); - } - } - - return p; -} - -void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) { - if ( - qoa->samples == 0 || - qoa->samplerate == 0 || qoa->samplerate > 0xffffff || - qoa->channels == 0 || qoa->channels > QOA_MAX_CHANNELS - ) { - return NULL; - } - - /* Calculate the encoded size and allocate */ - unsigned int num_frames = (qoa->samples + QOA_FRAME_LEN-1) / QOA_FRAME_LEN; - unsigned int num_slices = (qoa->samples + QOA_SLICE_LEN-1) / QOA_SLICE_LEN; - unsigned int encoded_size = 8 + /* 8 byte file header */ - num_frames * 8 + /* 8 byte frame headers */ - num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */ - num_slices * 8 * qoa->channels; /* 8 byte slices */ - - unsigned char *bytes = QOA_MALLOC(encoded_size); - - for (unsigned int c = 0; c < qoa->channels; c++) { - /* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the - prediction of the first few ms of a file. */ - qoa->lms[c].weights[0] = 0; - qoa->lms[c].weights[1] = 0; - qoa->lms[c].weights[2] = -(1<<13); - qoa->lms[c].weights[3] = (1<<14); - - /* Explicitly set the history samples to 0, as we might have some - garbage in there. */ - for (int i = 0; i < QOA_LMS_LEN; i++) { - qoa->lms[c].history[i] = 0; - } - } - - - /* Encode the header and go through all frames */ - unsigned int p = qoa_encode_header(qoa, bytes); - #ifdef QOA_RECORD_TOTAL_ERROR - qoa->error = 0; - #endif - - int frame_len = QOA_FRAME_LEN; - for (unsigned int sample_index = 0; sample_index < qoa->samples; sample_index += frame_len) { - frame_len = qoa_clamp(QOA_FRAME_LEN, 0, qoa->samples - sample_index); - const short *frame_samples = sample_data + sample_index * qoa->channels; - unsigned int frame_size = qoa_encode_frame(frame_samples, qoa, frame_len, bytes + p); - p += frame_size; - } - - *out_len = p; - return bytes; -} - - - -/* ----------------------------------------------------------------------------- - Decoder */ - -unsigned int qoa_max_frame_size(qoa_desc *qoa) { - return QOA_FRAME_SIZE(qoa->channels, QOA_SLICES_PER_FRAME); -} - -unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa) { - unsigned int p = 0; - if (size < QOA_MIN_FILESIZE) { - return 0; - } - - - /* Read the file header, verify the magic number ('qoaf') and read the - total number of samples. */ - qoa_uint64_t file_header = qoa_read_u64(bytes, &p); - - if ((file_header >> 32) != QOA_MAGIC) { - return 0; - } - - qoa->samples = file_header & 0xffffffff; - if (!qoa->samples) { - return 0; - } - - /* Peek into the first frame header to get the number of channels and - the samplerate. */ - qoa_uint64_t frame_header = qoa_read_u64(bytes, &p); - qoa->channels = (frame_header >> 56) & 0x0000ff; - qoa->samplerate = (frame_header >> 32) & 0xffffff; - - if (qoa->channels == 0 || qoa->samples == 0 || qoa->samplerate == 0) { - return 0; - } - - return 8; -} - -unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len) { - unsigned int p = 0; - *frame_len = 0; - - if (size < 8 + QOA_LMS_LEN * 4 * qoa->channels) { - return 0; - } - - /* Read and verify the frame header */ - qoa_uint64_t frame_header = qoa_read_u64(bytes, &p); - unsigned int channels = (frame_header >> 56) & 0x0000ff; - unsigned int samplerate = (frame_header >> 32) & 0xffffff; - unsigned int samples = (frame_header >> 16) & 0x00ffff; - unsigned int frame_size = (frame_header ) & 0x00ffff; - - unsigned int data_size = frame_size - 8 - QOA_LMS_LEN * 4 * channels; - unsigned int num_slices = data_size / 8; - unsigned int max_total_samples = num_slices * QOA_SLICE_LEN; - - if ( - channels != qoa->channels || - samplerate != qoa->samplerate || - frame_size > size || - samples * channels > max_total_samples - ) { - return 0; - } - - - /* Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel */ - for (unsigned int c = 0; c < channels; c++) { - qoa_uint64_t history = qoa_read_u64(bytes, &p); - qoa_uint64_t weights = qoa_read_u64(bytes, &p); - for (int i = 0; i < QOA_LMS_LEN; i++) { - qoa->lms[c].history[i] = ((signed short)(history >> 48)); - history <<= 16; - qoa->lms[c].weights[i] = ((signed short)(weights >> 48)); - weights <<= 16; - } - } - - - /* Decode all slices for all channels in this frame */ - for (unsigned int sample_index = 0; sample_index < samples; sample_index += QOA_SLICE_LEN) { - for (unsigned int c = 0; c < channels; c++) { - qoa_uint64_t slice = qoa_read_u64(bytes, &p); - - int scalefactor = (slice >> 60) & 0xf; - slice <<= 4; - - int slice_start = sample_index * channels + c; - int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c; - - for (int si = slice_start; si < slice_end; si += channels) { - int predicted = qoa_lms_predict(&qoa->lms[c]); - int quantized = (slice >> 61) & 0x7; - int dequantized = qoa_dequant_tab[scalefactor][quantized]; - int reconstructed = qoa_clamp_s16(predicted + dequantized); - - sample_data[si] = reconstructed; - slice <<= 3; - - qoa_lms_update(&qoa->lms[c], reconstructed, dequantized); - } - } - } - - *frame_len = samples; - return p; -} - -short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) { - unsigned int p = qoa_decode_header(bytes, size, qoa); - if (!p) { - return NULL; - } - - /* Calculate the required size of the sample buffer and allocate */ - int total_samples = qoa->samples * qoa->channels; - short *sample_data = QOA_MALLOC(total_samples * sizeof(short)); - - unsigned int sample_index = 0; - unsigned int frame_len; - unsigned int frame_size; - - /* Decode all frames */ - do { - short *sample_ptr = sample_data + sample_index * qoa->channels; - frame_size = qoa_decode_frame(bytes + p, size - p, qoa, sample_ptr, &frame_len); - - p += frame_size; - sample_index += frame_len; - } while (frame_size && sample_index < qoa->samples); - - qoa->samples = sample_index; - return sample_data; -} - - - -/* ----------------------------------------------------------------------------- - File read/write convenience functions */ - -#ifndef QOA_NO_STDIO -#include - -int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa) { - FILE *f = fopen(filename, "wb"); - unsigned int size; - void *encoded; - - if (!f) { - return 0; - } - - encoded = qoa_encode(sample_data, qoa, &size); - if (!encoded) { - fclose(f); - return 0; - } - - fwrite(encoded, 1, size, f); - fclose(f); - - QOA_FREE(encoded); - return size; -} - -void *qoa_read(const char *filename, qoa_desc *qoa) { - FILE *f = fopen(filename, "rb"); - int size, bytes_read; - void *data; - short *sample_data; - - if (!f) { - return NULL; - } - - fseek(f, 0, SEEK_END); - size = ftell(f); - if (size <= 0) { - fclose(f); - return NULL; - } - fseek(f, 0, SEEK_SET); - - data = QOA_MALLOC(size); - if (!data) { - fclose(f); - return NULL; - } - - bytes_read = fread(data, 1, size, f); - fclose(f); - - sample_data = qoa_decode(data, bytes_read, qoa); - QOA_FREE(data); - return sample_data; -} - -#endif /* QOA_NO_STDIO */ -#endif /* QOA_IMPLEMENTATION */ diff --git a/raylib/external/qoaplay.c b/raylib/external/qoaplay.c deleted file mode 100644 index 039e279..0000000 --- a/raylib/external/qoaplay.c +++ /dev/null @@ -1,278 +0,0 @@ -/******************************************************************************************* -* -* qoaplay - QOA stream playing helper functions -* -* qoaplay is a tiny abstraction to read and decode a QOA file "on the fly". -* It reads and decodes one frame at a time with minimal memory requirements. -* qoaplay also provides some functions to seek to a specific frame. -* -* LICENSE: MIT License -* -* Copyright (c) 2023 Dominic Szablewski (@phoboslab), reviewed by Ramon Santamaria (@raysan5) -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -**********************************************************************************************/ - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// QOA streaming data descriptor -typedef struct { - qoa_desc info; // QOA descriptor data - - FILE *file; // QOA file to read, if NULL, using memory buffer -> file_data - unsigned char *file_data; // QOA file data on memory - unsigned int file_data_size; // QOA file data on memory size - unsigned int file_data_offset; // QOA file data on memory offset for next read - - unsigned int first_frame_pos; // First frame position (after QOA header, required for offset) - unsigned int sample_position; // Current streaming sample position - - unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding) - unsigned int buffer_len; // Buffer length to read samples for streaming - - short *sample_data; // Sample data decoded - unsigned int sample_data_len; // Sample data decoded length - unsigned int sample_data_pos; // Sample data decoded position - -} qoaplay_desc; - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -qoaplay_desc *qoaplay_open(const char *path); -qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size); -void qoaplay_close(qoaplay_desc *qoa_ctx); - -void qoaplay_rewind(qoaplay_desc *qoa_ctx); -void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame); -unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples); -unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx); -double qoaplay_get_duration(qoaplay_desc *qoa_ctx); -double qoaplay_get_time(qoaplay_desc *qoa_ctx); -int qoaplay_get_frame(qoaplay_desc *qoa_ctx); - -#if defined(__cplusplus) -} // Prevents name mangling of functions -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Open QOA file, keep FILE pointer to keep reading from file -qoaplay_desc *qoaplay_open(const char *path) -{ - FILE *file = fopen(path, "rb"); - if (!file) return NULL; - - // Read and decode the file header - unsigned char header[QOA_MIN_FILESIZE]; - int read = fread(header, QOA_MIN_FILESIZE, 1, file); - if (!read) return NULL; - - qoa_desc qoa; - unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); - if (!first_frame_pos) return NULL; - - // Rewind the file back to beginning of the first frame - fseek(file, first_frame_pos, SEEK_SET); - - // Allocate one chunk of memory for the qoaplay_desc struct - // + the sample data for one frame - // + a buffer to hold one frame of encoded data - unsigned int buffer_size = qoa_max_frame_size(&qoa); - unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2; - qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size); - memset(qoa_ctx, 0, sizeof(qoaplay_desc)); - - qoa_ctx->file = file; - qoa_ctx->file_data = NULL; - qoa_ctx->file_data_size = 0; - qoa_ctx->file_data_offset = 0; - qoa_ctx->first_frame_pos = first_frame_pos; - - // Setup data pointers to previously allocated data - qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); - qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); - - qoa_ctx->info.channels = qoa.channels; - qoa_ctx->info.samplerate = qoa.samplerate; - qoa_ctx->info.samples = qoa.samples; - - return qoa_ctx; -} - -// Open QOA file from memory, no FILE pointer required -qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size) -{ - // Read and decode the file header - unsigned char header[QOA_MIN_FILESIZE]; - memcpy(header, data, QOA_MIN_FILESIZE); - - qoa_desc qoa; - unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); - if (!first_frame_pos) return NULL; - - // Allocate one chunk of memory for the qoaplay_desc struct - // + the sample data for one frame - // + a buffer to hold one frame of encoded data - unsigned int buffer_size = qoa_max_frame_size(&qoa); - unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2; - qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size); - memset(qoa_ctx, 0, sizeof(qoaplay_desc)); - - qoa_ctx->file = NULL; - - // Keep a copy of file data provided to be managed internally - qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size); - memcpy(qoa_ctx->file_data, data, data_size); - qoa_ctx->file_data_size = data_size; - qoa_ctx->file_data_offset = 0; - qoa_ctx->first_frame_pos = first_frame_pos; - - // Setup data pointers to previously allocated data - qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); - qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); - - qoa_ctx->info.channels = qoa.channels; - qoa_ctx->info.samplerate = qoa.samplerate; - qoa_ctx->info.samples = qoa.samples; - - return qoa_ctx; -} - -// Close QOA file (if open) and free internal memory -void qoaplay_close(qoaplay_desc *qoa_ctx) -{ - if (qoa_ctx->file) fclose(qoa_ctx->file); - - if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0)) - { - QOA_FREE(qoa_ctx->file_data); - qoa_ctx->file_data_size = 0; - } - - QOA_FREE(qoa_ctx); -} - -// Decode one frame from QOA data -unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx) -{ - if (qoa_ctx->file) qoa_ctx->buffer_len = fread(qoa_ctx->buffer, 1, qoa_max_frame_size(&qoa_ctx->info), qoa_ctx->file); - else - { - qoa_ctx->buffer_len = qoa_max_frame_size(&qoa_ctx->info); - memcpy(qoa_ctx->buffer, qoa_ctx->file_data + qoa_ctx->file_data_offset, qoa_ctx->buffer_len); - qoa_ctx->file_data_offset += qoa_ctx->buffer_len; - } - - unsigned int frame_len; - qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len); - qoa_ctx->sample_data_pos = 0; - qoa_ctx->sample_data_len = frame_len; - - return frame_len; -} - -// Rewind QOA file or memory pointer to beginning -void qoaplay_rewind(qoaplay_desc *qoa_ctx) -{ - if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET); - else qoa_ctx->file_data_offset = 0; - - qoa_ctx->sample_position = 0; - qoa_ctx->sample_data_len = 0; - qoa_ctx->sample_data_pos = 0; -} - -// Decode required QOA frames -unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples) -{ - int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels; - int dst_index = 0; - - for (int i = 0; i < num_samples; i++) - { - // Do we have to decode more samples? - if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0) - { - if (!qoaplay_decode_frame(qoa_ctx)) - { - // Loop to the beginning - qoaplay_rewind(qoa_ctx); - qoaplay_decode_frame(qoa_ctx); - } - - src_index = 0; - } - - // Normalize to -1..1 floats and write to dest - for (int c = 0; c < qoa_ctx->info.channels; c++) - { - sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0; - } - - qoa_ctx->sample_data_pos++; - qoa_ctx->sample_position++; - } - - return num_samples; -} - -// Get QOA total time duration in seconds -double qoaplay_get_duration(qoaplay_desc *qoa_ctx) -{ - return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate; -} - -// Get QOA current time position in seconds -double qoaplay_get_time(qoaplay_desc *qoa_ctx) -{ - return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate; -} - -// Get QOA current audio frame -int qoaplay_get_frame(qoaplay_desc *qoa_ctx) -{ - return qoa_ctx->sample_position/QOA_FRAME_LEN; -} - -// Seek QOA audio frame -void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame) -{ - if (frame < 0) frame = 0; - - if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN; - - qoa_ctx->sample_position = frame*QOA_FRAME_LEN; - qoa_ctx->sample_data_len = 0; - qoa_ctx->sample_data_pos = 0; - - unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info); - - if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET); - else qoa_ctx->file_data_offset = offset; -} diff --git a/raylib/external/qoi.h b/raylib/external/qoi.h deleted file mode 100644 index f2800b0..0000000 --- a/raylib/external/qoi.h +++ /dev/null @@ -1,649 +0,0 @@ -/* - -Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org -SPDX-License-Identifier: MIT - - -QOI - The "Quite OK Image" format for fast, lossless image compression - --- About - -QOI encodes and decodes images in a lossless format. Compared to stb_image and -stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and -20% better compression. - - --- Synopsis - -// Define `QOI_IMPLEMENTATION` in *one* C/C++ file before including this -// library to create the implementation. - -#define QOI_IMPLEMENTATION -#include "qoi.h" - -// Encode and store an RGBA buffer to the file system. The qoi_desc describes -// the input pixel data. -qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){ - .width = 1920, - .height = 1080, - .channels = 4, - .colorspace = QOI_SRGB -}); - -// Load and decode a QOI image from the file system into a 32bbp RGBA buffer. -// The qoi_desc struct will be filled with the width, height, number of channels -// and colorspace read from the file header. -qoi_desc desc; -void *rgba_pixels = qoi_read("image.qoi", &desc, 4); - - - --- Documentation - -This library provides the following functions; -- qoi_read -- read and decode a QOI file -- qoi_decode -- decode the raw bytes of a QOI image from memory -- qoi_write -- encode and write a QOI file -- qoi_encode -- encode an rgba buffer into a QOI image in memory - -See the function declaration below for the signature and more information. - -If you don't want/need the qoi_read and qoi_write functions, you can define -QOI_NO_STDIO before including this library. - -This library uses malloc() and free(). To supply your own malloc implementation -you can define QOI_MALLOC and QOI_FREE before including this library. - -This library uses memset() to zero-initialize the index. To supply your own -implementation you can define QOI_ZEROARR before including this library. - - --- Data Format - -A QOI file has a 14 byte header, followed by any number of data "chunks" and an -8-byte end marker. - -struct qoi_header_t { - char magic[4]; // magic bytes "qoif" - uint32_t width; // image width in pixels (BE) - uint32_t height; // image height in pixels (BE) - uint8_t channels; // 3 = RGB, 4 = RGBA - uint8_t colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear -}; - -Images are encoded row by row, left to right, top to bottom. The decoder and -encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An -image is complete when all pixels specified by width * height have been covered. - -Pixels are encoded as - - a run of the previous pixel - - an index into an array of previously seen pixels - - a difference to the previous pixel value in r,g,b - - full r,g,b or r,g,b,a values - -The color channels are assumed to not be premultiplied with the alpha channel -("un-premultiplied alpha"). - -A running array[64] (zero-initialized) of previously seen pixel values is -maintained by the encoder and decoder. Each pixel that is seen by the encoder -and decoder is put into this array at the position formed by a hash function of -the color value. In the encoder, if the pixel value at the index matches the -current pixel, this index position is written to the stream as QOI_OP_INDEX. -The hash function for the index is: - - index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64 - -Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The -bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All -values encoded in these data bits have the most significant bit on the left. - -The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the -presence of an 8-bit tag first. - -The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte. - - -The possible chunks are: - - -.- QOI_OP_INDEX ----------. -| Byte[0] | -| 7 6 5 4 3 2 1 0 | -|-------+-----------------| -| 0 0 | index | -`-------------------------` -2-bit tag b00 -6-bit index into the color index array: 0..63 - -A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the -same index. QOI_OP_RUN should be used instead. - - -.- QOI_OP_DIFF -----------. -| Byte[0] | -| 7 6 5 4 3 2 1 0 | -|-------+-----+-----+-----| -| 0 1 | dr | dg | db | -`-------------------------` -2-bit tag b01 -2-bit red channel difference from the previous pixel between -2..1 -2-bit green channel difference from the previous pixel between -2..1 -2-bit blue channel difference from the previous pixel between -2..1 - -The difference to the current channel values are using a wraparound operation, -so "1 - 2" will result in 255, while "255 + 1" will result in 0. - -Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as -0 (b00). 1 is stored as 3 (b11). - -The alpha value remains unchanged from the previous pixel. - - -.- QOI_OP_LUMA -------------------------------------. -| Byte[0] | Byte[1] | -| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | -|-------+-----------------+-------------+-----------| -| 1 0 | green diff | dr - dg | db - dg | -`---------------------------------------------------` -2-bit tag b10 -6-bit green channel difference from the previous pixel -32..31 -4-bit red channel difference minus green channel difference -8..7 -4-bit blue channel difference minus green channel difference -8..7 - -The green channel is used to indicate the general direction of change and is -encoded in 6 bits. The red and blue channels (dr and db) base their diffs off -of the green channel difference and are encoded in 4 bits. I.e.: - dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g) - db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g) - -The difference to the current channel values are using a wraparound operation, -so "10 - 13" will result in 253, while "250 + 7" will result in 1. - -Values are stored as unsigned integers with a bias of 32 for the green channel -and a bias of 8 for the red and blue channel. - -The alpha value remains unchanged from the previous pixel. - - -.- QOI_OP_RUN ------------. -| Byte[0] | -| 7 6 5 4 3 2 1 0 | -|-------+-----------------| -| 1 1 | run | -`-------------------------` -2-bit tag b11 -6-bit run-length repeating the previous pixel: 1..62 - -The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64 -(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and -QOI_OP_RGBA tags. - - -.- QOI_OP_RGB ------------------------------------------. -| Byte[0] | Byte[1] | Byte[2] | Byte[3] | -| 7 6 5 4 3 2 1 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 | -|-------------------------+---------+---------+---------| -| 1 1 1 1 1 1 1 0 | red | green | blue | -`-------------------------------------------------------` -8-bit tag b11111110 -8-bit red channel value -8-bit green channel value -8-bit blue channel value - -The alpha value remains unchanged from the previous pixel. - - -.- QOI_OP_RGBA ---------------------------------------------------. -| Byte[0] | Byte[1] | Byte[2] | Byte[3] | Byte[4] | -| 7 6 5 4 3 2 1 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 | -|-------------------------+---------+---------+---------+---------| -| 1 1 1 1 1 1 1 1 | red | green | blue | alpha | -`-----------------------------------------------------------------` -8-bit tag b11111111 -8-bit red channel value -8-bit green channel value -8-bit blue channel value -8-bit alpha channel value - -*/ - - -/* ----------------------------------------------------------------------------- -Header - Public functions */ - -#ifndef QOI_H -#define QOI_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions. -It describes either the input format (for qoi_write and qoi_encode), or is -filled with the description read from the file header (for qoi_read and -qoi_decode). - -The colorspace in this qoi_desc is an enum where - 0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel - 1 = all channels are linear -You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely -informative. It will be saved to the file header, but does not affect -how chunks are en-/decoded. */ - -#define QOI_SRGB 0 -#define QOI_LINEAR 1 - -typedef struct { - unsigned int width; - unsigned int height; - unsigned char channels; - unsigned char colorspace; -} qoi_desc; - -#ifndef QOI_NO_STDIO - -/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file -system. The qoi_desc struct must be filled with the image width, height, -number of channels (3 = RGB, 4 = RGBA) and the colorspace. - -The function returns 0 on failure (invalid parameters, or fopen or malloc -failed) or the number of bytes written on success. */ - -int qoi_write(const char *filename, const void *data, const qoi_desc *desc); - - -/* Read and decode a QOI image from the file system. If channels is 0, the -number of channels from the file header is used. If channels is 3 or 4 the -output format will be forced into this number of channels. - -The function either returns NULL on failure (invalid data, or malloc or fopen -failed) or a pointer to the decoded pixels. On success, the qoi_desc struct -will be filled with the description from the file header. - -The returned pixel data should be free()d after use. */ - -void *qoi_read(const char *filename, qoi_desc *desc, int channels); - -#endif /* QOI_NO_STDIO */ - - -/* Encode raw RGB or RGBA pixels into a QOI image in memory. - -The function either returns NULL on failure (invalid parameters or malloc -failed) or a pointer to the encoded data on success. On success the out_len -is set to the size in bytes of the encoded data. - -The returned qoi data should be free()d after use. */ - -void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len); - - -/* Decode a QOI image from memory. - -The function either returns NULL on failure (invalid parameters or malloc -failed) or a pointer to the decoded pixels. On success, the qoi_desc struct -is filled with the description from the file header. - -The returned pixel data should be free()d after use. */ - -void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels); - - -#ifdef __cplusplus -} -#endif -#endif /* QOI_H */ - - -/* ----------------------------------------------------------------------------- -Implementation */ - -#ifdef QOI_IMPLEMENTATION -#include -#include - -#ifndef QOI_MALLOC - #define QOI_MALLOC(sz) malloc(sz) - #define QOI_FREE(p) free(p) -#endif -#ifndef QOI_ZEROARR - #define QOI_ZEROARR(a) memset((a),0,sizeof(a)) -#endif - -#define QOI_OP_INDEX 0x00 /* 00xxxxxx */ -#define QOI_OP_DIFF 0x40 /* 01xxxxxx */ -#define QOI_OP_LUMA 0x80 /* 10xxxxxx */ -#define QOI_OP_RUN 0xc0 /* 11xxxxxx */ -#define QOI_OP_RGB 0xfe /* 11111110 */ -#define QOI_OP_RGBA 0xff /* 11111111 */ - -#define QOI_MASK_2 0xc0 /* 11000000 */ - -#define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11) -#define QOI_MAGIC \ - (((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \ - ((unsigned int)'i') << 8 | ((unsigned int)'f')) -#define QOI_HEADER_SIZE 14 - -/* 2GB is the max file size that this implementation can safely handle. We guard -against anything larger than that, assuming the worst case with 5 bytes per -pixel, rounded down to a nice clean value. 400 million pixels ought to be -enough for anybody. */ -#define QOI_PIXELS_MAX ((unsigned int)400000000) - -typedef union { - struct { unsigned char r, g, b, a; } rgba; - unsigned int v; -} qoi_rgba_t; - -static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1}; - -static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) { - bytes[(*p)++] = (0xff000000 & v) >> 24; - bytes[(*p)++] = (0x00ff0000 & v) >> 16; - bytes[(*p)++] = (0x0000ff00 & v) >> 8; - bytes[(*p)++] = (0x000000ff & v); -} - -static unsigned int qoi_read_32(const unsigned char *bytes, int *p) { - unsigned int a = bytes[(*p)++]; - unsigned int b = bytes[(*p)++]; - unsigned int c = bytes[(*p)++]; - unsigned int d = bytes[(*p)++]; - return a << 24 | b << 16 | c << 8 | d; -} - -void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) { - int i, max_size, p, run; - int px_len, px_end, px_pos, channels; - unsigned char *bytes; - const unsigned char *pixels; - qoi_rgba_t index[64]; - qoi_rgba_t px, px_prev; - - if ( - data == NULL || out_len == NULL || desc == NULL || - desc->width == 0 || desc->height == 0 || - desc->channels < 3 || desc->channels > 4 || - desc->colorspace > 1 || - desc->height >= QOI_PIXELS_MAX / desc->width - ) { - return NULL; - } - - max_size = - desc->width * desc->height * (desc->channels + 1) + - QOI_HEADER_SIZE + sizeof(qoi_padding); - - p = 0; - bytes = (unsigned char *) QOI_MALLOC(max_size); - if (!bytes) { - return NULL; - } - - qoi_write_32(bytes, &p, QOI_MAGIC); - qoi_write_32(bytes, &p, desc->width); - qoi_write_32(bytes, &p, desc->height); - bytes[p++] = desc->channels; - bytes[p++] = desc->colorspace; - - - pixels = (const unsigned char *)data; - - QOI_ZEROARR(index); - - run = 0; - px_prev.rgba.r = 0; - px_prev.rgba.g = 0; - px_prev.rgba.b = 0; - px_prev.rgba.a = 255; - px = px_prev; - - px_len = desc->width * desc->height * desc->channels; - px_end = px_len - desc->channels; - channels = desc->channels; - - for (px_pos = 0; px_pos < px_len; px_pos += channels) { - px.rgba.r = pixels[px_pos + 0]; - px.rgba.g = pixels[px_pos + 1]; - px.rgba.b = pixels[px_pos + 2]; - - if (channels == 4) { - px.rgba.a = pixels[px_pos + 3]; - } - - if (px.v == px_prev.v) { - run++; - if (run == 62 || px_pos == px_end) { - bytes[p++] = QOI_OP_RUN | (run - 1); - run = 0; - } - } - else { - int index_pos; - - if (run > 0) { - bytes[p++] = QOI_OP_RUN | (run - 1); - run = 0; - } - - index_pos = QOI_COLOR_HASH(px) % 64; - - if (index[index_pos].v == px.v) { - bytes[p++] = QOI_OP_INDEX | index_pos; - } - else { - index[index_pos] = px; - - if (px.rgba.a == px_prev.rgba.a) { - signed char vr = px.rgba.r - px_prev.rgba.r; - signed char vg = px.rgba.g - px_prev.rgba.g; - signed char vb = px.rgba.b - px_prev.rgba.b; - - signed char vg_r = vr - vg; - signed char vg_b = vb - vg; - - if ( - vr > -3 && vr < 2 && - vg > -3 && vg < 2 && - vb > -3 && vb < 2 - ) { - bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2); - } - else if ( - vg_r > -9 && vg_r < 8 && - vg > -33 && vg < 32 && - vg_b > -9 && vg_b < 8 - ) { - bytes[p++] = QOI_OP_LUMA | (vg + 32); - bytes[p++] = (vg_r + 8) << 4 | (vg_b + 8); - } - else { - bytes[p++] = QOI_OP_RGB; - bytes[p++] = px.rgba.r; - bytes[p++] = px.rgba.g; - bytes[p++] = px.rgba.b; - } - } - else { - bytes[p++] = QOI_OP_RGBA; - bytes[p++] = px.rgba.r; - bytes[p++] = px.rgba.g; - bytes[p++] = px.rgba.b; - bytes[p++] = px.rgba.a; - } - } - } - px_prev = px; - } - - for (i = 0; i < (int)sizeof(qoi_padding); i++) { - bytes[p++] = qoi_padding[i]; - } - - *out_len = p; - return bytes; -} - -void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) { - const unsigned char *bytes; - unsigned int header_magic; - unsigned char *pixels; - qoi_rgba_t index[64]; - qoi_rgba_t px; - int px_len, chunks_len, px_pos; - int p = 0, run = 0; - - if ( - data == NULL || desc == NULL || - (channels != 0 && channels != 3 && channels != 4) || - size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding) - ) { - return NULL; - } - - bytes = (const unsigned char *)data; - - header_magic = qoi_read_32(bytes, &p); - desc->width = qoi_read_32(bytes, &p); - desc->height = qoi_read_32(bytes, &p); - desc->channels = bytes[p++]; - desc->colorspace = bytes[p++]; - - if ( - desc->width == 0 || desc->height == 0 || - desc->channels < 3 || desc->channels > 4 || - desc->colorspace > 1 || - header_magic != QOI_MAGIC || - desc->height >= QOI_PIXELS_MAX / desc->width - ) { - return NULL; - } - - if (channels == 0) { - channels = desc->channels; - } - - px_len = desc->width * desc->height * channels; - pixels = (unsigned char *) QOI_MALLOC(px_len); - if (!pixels) { - return NULL; - } - - QOI_ZEROARR(index); - px.rgba.r = 0; - px.rgba.g = 0; - px.rgba.b = 0; - px.rgba.a = 255; - - chunks_len = size - (int)sizeof(qoi_padding); - for (px_pos = 0; px_pos < px_len; px_pos += channels) { - if (run > 0) { - run--; - } - else if (p < chunks_len) { - int b1 = bytes[p++]; - - if (b1 == QOI_OP_RGB) { - px.rgba.r = bytes[p++]; - px.rgba.g = bytes[p++]; - px.rgba.b = bytes[p++]; - } - else if (b1 == QOI_OP_RGBA) { - px.rgba.r = bytes[p++]; - px.rgba.g = bytes[p++]; - px.rgba.b = bytes[p++]; - px.rgba.a = bytes[p++]; - } - else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) { - px = index[b1]; - } - else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) { - px.rgba.r += ((b1 >> 4) & 0x03) - 2; - px.rgba.g += ((b1 >> 2) & 0x03) - 2; - px.rgba.b += ( b1 & 0x03) - 2; - } - else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) { - int b2 = bytes[p++]; - int vg = (b1 & 0x3f) - 32; - px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f); - px.rgba.g += vg; - px.rgba.b += vg - 8 + (b2 & 0x0f); - } - else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) { - run = (b1 & 0x3f); - } - - index[QOI_COLOR_HASH(px) % 64] = px; - } - - pixels[px_pos + 0] = px.rgba.r; - pixels[px_pos + 1] = px.rgba.g; - pixels[px_pos + 2] = px.rgba.b; - - if (channels == 4) { - pixels[px_pos + 3] = px.rgba.a; - } - } - - return pixels; -} - -#ifndef QOI_NO_STDIO -#include - -int qoi_write(const char *filename, const void *data, const qoi_desc *desc) { - FILE *f = fopen(filename, "wb"); - int size, err; - void *encoded; - - if (!f) { - return 0; - } - - encoded = qoi_encode(data, desc, &size); - if (!encoded) { - fclose(f); - return 0; - } - - fwrite(encoded, 1, size, f); - fflush(f); - err = ferror(f); - fclose(f); - - QOI_FREE(encoded); - return err ? 0 : size; -} - -void *qoi_read(const char *filename, qoi_desc *desc, int channels) { - FILE *f = fopen(filename, "rb"); - int size, bytes_read; - void *pixels, *data; - - if (!f) { - return NULL; - } - - fseek(f, 0, SEEK_END); - size = ftell(f); - if (size <= 0 || fseek(f, 0, SEEK_SET) != 0) { - fclose(f); - return NULL; - } - - data = QOI_MALLOC(size); - if (!data) { - fclose(f); - return NULL; - } - - bytes_read = fread(data, 1, size, f); - fclose(f); - pixels = (bytes_read != size) ? NULL : qoi_decode(data, bytes_read, desc, channels); - QOI_FREE(data); - return pixels; -} - -#endif /* QOI_NO_STDIO */ -#endif /* QOI_IMPLEMENTATION */ diff --git a/raylib/external/rl_gputex.h b/raylib/external/rl_gputex.h deleted file mode 100644 index 4043a92..0000000 --- a/raylib/external/rl_gputex.h +++ /dev/null @@ -1,826 +0,0 @@ -/********************************************************************************************** -* -* rl_gputex v1.0 - GPU compressed textures loading and saving -* -* DESCRIPTION: -* -* Load GPU compressed image data from image files provided as memory data arrays, -* data is loaded compressed, ready to be loaded into GPU. -* -* Note that some file formats (DDS, PVR, KTX) also support uncompressed data storage. -* In those cases data is loaded uncompressed and format is returned. -* -* TODO: -* - Implement raylib function: rlGetGlTextureFormats(), required by rl_save_ktx_to_memory() -* - Review rl_load_ktx_from_memory() to support KTX v2.2 specs -* -* CONFIGURATION: -* -* #define RL_GPUTEX_SUPPORT_DDS -* #define RL_GPUTEX_SUPPORT_PKM -* #define RL_GPUTEX_SUPPORT_KTX -* #define RL_GPUTEX_SUPPORT_PVR -* #define RL_GPUTEX_SUPPORT_ASTC -* Define desired file formats to be supported -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#ifndef RL_GPUTEX_H -#define RL_GPUTEX_H - -#ifndef RLAPI - #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -// Load image data from memory data files -RLAPI void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips); -RLAPI void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips); -RLAPI void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips); -RLAPI void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips); -RLAPI void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips); - -RLAPI int rl_save_ktx_to_memory(const char *fileName, void *data, int width, int height, int format, int mipmaps); // Save image data as KTX file - -#if defined(__cplusplus) -} -#endif - -#endif // RL_GPUTEX_H - - -/*********************************************************************************** -* -* RL_GPUTEX IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RL_GPUTEX_IMPLEMENTATION) - -// Simple log system to avoid RPNG_LOG() calls if required -// NOTE: Avoiding those calls, also avoids const strings memory usage -#define RL_GPUTEX_SHOW_LOG_INFO -#if defined(RL_GPUTEX_SHOW_LOG_INFO) && !defined(LOG) -#define LOG(...) printf(__VA_ARGS__) -#else -#define LOG(...) -#endif - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -// Get pixel data size in bytes for certain pixel format -static int get_pixel_data_size(int width, int height, int format); - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- -#if defined(RL_GPUTEX_SUPPORT_DDS) -// Loading DDS from memory image data (compressed or uncompressed) -void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) -{ - void *image_data = NULL; // Image data pointer - int image_pixel_size = 0; // Image pixel size - - unsigned char *file_data_ptr = (unsigned char *)file_data; - - // Required extension: - // GL_EXT_texture_compression_s3tc - - // Supported tokens (defined by extensions) - // GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 - // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 - // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 - // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 - - #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII - #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII - #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII - - // DDS Pixel Format - typedef struct { - unsigned int size; - unsigned int flags; - unsigned int fourcc; - unsigned int rgb_bit_count; - unsigned int r_bit_mask; - unsigned int g_bit_mask; - unsigned int b_bit_mask; - unsigned int a_bit_mask; - } dds_pixel_format; - - // DDS Header (124 bytes) - typedef struct { - unsigned int size; - unsigned int flags; - unsigned int height; - unsigned int width; - unsigned int pitch_or_linear_size; - unsigned int depth; - unsigned int mipmap_count; - unsigned int reserved1[11]; - dds_pixel_format ddspf; - unsigned int caps; - unsigned int caps2; - unsigned int caps3; - unsigned int caps4; - unsigned int reserved2; - } dds_header; - - if (file_data_ptr != NULL) - { - // Verify the type of file - unsigned char *dds_header_id = file_data_ptr; - file_data_ptr += 4; - - if ((dds_header_id[0] != 'D') || (dds_header_id[1] != 'D') || (dds_header_id[2] != 'S') || (dds_header_id[3] != ' ')) - { - LOG("WARNING: IMAGE: DDS file data not valid"); - } - else - { - dds_header *header = (dds_header *)file_data_ptr; - - file_data_ptr += sizeof(dds_header); // Skip header - - *width = header->width; - *height = header->height; - - if (*width % 4 != 0) LOG("WARNING: IMAGE: DDS file width must be multiple of 4. Image will not display correctly"); - if (*height % 4 != 0) LOG("WARNING: IMAGE: DDS file height must be multiple of 4. Image will not display correctly"); - - image_pixel_size = header->width*header->height; - - if (header->mipmap_count == 0) *mips = 1; // Parameter not used - else *mips = header->mipmap_count; - - if (header->ddspf.rgb_bit_count == 16) // 16bit mode, no compressed - { - if (header->ddspf.flags == 0x40) // No alpha channel - { - int data_size = image_pixel_size*sizeof(unsigned short); - if (header->mipmap_count > 1) data_size = data_size + data_size / 3; - image_data = RL_MALLOC(data_size); - - memcpy(image_data, file_data_ptr, data_size); - - *format = PIXELFORMAT_UNCOMPRESSED_R5G6B5; - } - else if (header->ddspf.flags == 0x41) // With alpha channel - { - if (header->ddspf.a_bit_mask == 0x8000) // 1bit alpha - { - int data_size = image_pixel_size*sizeof(unsigned short); - if (header->mipmap_count > 1) data_size = data_size + data_size / 3; - image_data = RL_MALLOC(data_size); - - memcpy(image_data, file_data_ptr, data_size); - - unsigned char alpha = 0; - - // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1 - for (int i = 0; i < image_pixel_size; i++) - { - alpha = ((unsigned short *)image_data)[i] >> 15; - ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 1; - ((unsigned short *)image_data)[i] += alpha; - } - - *format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; - } - else if (header->ddspf.a_bit_mask == 0xf000) // 4bit alpha - { - int data_size = image_pixel_size*sizeof(unsigned short); - if (header->mipmap_count > 1) data_size = data_size + data_size / 3; - image_data = RL_MALLOC(data_size); - - memcpy(image_data, file_data_ptr, data_size); - - unsigned char alpha = 0; - - // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4 - for (int i = 0; i < image_pixel_size; i++) - { - alpha = ((unsigned short *)image_data)[i] >> 12; - ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 4; - ((unsigned short *)image_data)[i] += alpha; - } - - *format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; - } - } - } - else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed - { - int data_size = image_pixel_size*3*sizeof(unsigned char); - if (header->mipmap_count > 1) data_size = data_size + data_size / 3; - image_data = RL_MALLOC(data_size); - - memcpy(image_data, file_data_ptr, data_size); - - *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8; - } - else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed - { - int data_size = image_pixel_size*4*sizeof(unsigned char); - if (header->mipmap_count > 1) data_size = data_size + data_size / 3; - image_data = RL_MALLOC(data_size); - - memcpy(image_data, file_data_ptr, data_size); - - unsigned char blue = 0; - - // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment) - // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA - // So, we must realign B8G8R8A8 to R8G8B8A8 - for (int i = 0; i < image_pixel_size*4; i += 4) - { - blue = ((unsigned char *)image_data)[i]; - ((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2]; - ((unsigned char *)image_data)[i + 2] = blue; - } - - *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - } - else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed - { - int data_size = 0; - - // Calculate data size, including all mipmaps - if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size / 3; - else data_size = header->pitch_or_linear_size; - - image_data = RL_MALLOC(data_size*sizeof(unsigned char)); - - memcpy(image_data, file_data_ptr, data_size); - - switch (header->ddspf.fourcc) - { - case FOURCC_DXT1: - { - if (header->ddspf.flags == 0x04) *format = PIXELFORMAT_COMPRESSED_DXT1_RGB; - else *format = PIXELFORMAT_COMPRESSED_DXT1_RGBA; - } break; - case FOURCC_DXT3: *format = PIXELFORMAT_COMPRESSED_DXT3_RGBA; break; - case FOURCC_DXT5: *format = PIXELFORMAT_COMPRESSED_DXT5_RGBA; break; - default: break; - } - } - } - } - - return image_data; -} -#endif - -#if defined(RL_GPUTEX_SUPPORT_PKM) -// Loading PKM image data (ETC1/ETC2 compression) -// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps) -// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps) -void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) -{ - void *image_data = NULL; // Image data pointer - - unsigned char *file_data_ptr = (unsigned char *)file_data; - - // Required extensions: - // GL_OES_compressed_ETC1_RGB8_texture (ETC1) (OpenGL ES 2.0) - // GL_ARB_ES3_compatibility (ETC2/EAC) (OpenGL ES 3.0) - - // Supported tokens (defined by extensions) - // GL_ETC1_RGB8_OES 0x8D64 - // GL_COMPRESSED_RGB8_ETC2 0x9274 - // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 - - // PKM file (ETC1) Header (16 bytes) - typedef struct { - char id[4]; // "PKM " - char version[2]; // "10" or "20" - unsigned short format; // Data format (big-endian) (Check list below) - unsigned short width; // Texture width (big-endian) (orig_width rounded to multiple of 4) - unsigned short height; // Texture height (big-endian) (orig_height rounded to multiple of 4) - unsigned short orig_width; // Original width (big-endian) - unsigned short orig_height; // Original height (big-endian) - } pkm_header; - - // Formats list - // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used) - // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R - - // NOTE: The extended width and height are the widths rounded up to a multiple of 4. - // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels) - - if (file_data_ptr != NULL) - { - pkm_header *header = (pkm_header *)file_data_ptr; - - if ((header->id[0] != 'P') || (header->id[1] != 'K') || (header->id[2] != 'M') || (header->id[3] != ' ')) - { - LOG("WARNING: IMAGE: PKM file data not valid"); - } - else - { - file_data_ptr += sizeof(pkm_header); // Skip header - - // NOTE: format, width and height come as big-endian, data must be swapped to little-endian - header->format = ((header->format & 0x00FF) << 8) | ((header->format & 0xFF00) >> 8); - header->width = ((header->width & 0x00FF) << 8) | ((header->width & 0xFF00) >> 8); - header->height = ((header->height & 0x00FF) << 8) | ((header->height & 0xFF00) >> 8); - - *width = header->width; - *height = header->height; - *mips = 1; - - int bpp = 4; - if (header->format == 3) bpp = 8; - - int data_size = (*width)*(*height)*bpp/8; // Total data size in bytes - - image_data = RL_MALLOC(data_size*sizeof(unsigned char)); - - memcpy(image_data, file_data_ptr, data_size); - - if (header->format == 0) *format = PIXELFORMAT_COMPRESSED_ETC1_RGB; - else if (header->format == 1) *format = PIXELFORMAT_COMPRESSED_ETC2_RGB; - else if (header->format == 3) *format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; - } - } - - return image_data; -} -#endif - -#if defined(RL_GPUTEX_SUPPORT_KTX) -// Load KTX compressed image data (ETC1/ETC2 compression) -// TODO: Review KTX loading, many things changed! -void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) -{ - void *image_data = NULL; // Image data pointer - - unsigned char *file_data_ptr = (unsigned char *)file_data; - - // Required extensions: - // GL_OES_compressed_ETC1_RGB8_texture (ETC1) - // GL_ARB_ES3_compatibility (ETC2/EAC) - - // Supported tokens (defined by extensions) - // GL_ETC1_RGB8_OES 0x8D64 - // GL_COMPRESSED_RGB8_ETC2 0x9274 - // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 - - // KTX file Header (64 bytes) - // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ - // v2.0 - http://github.khronos.org/KTX-Specification/ - - // KTX 1.1 Header - // TODO: Support KTX 2.2 specs! - typedef struct { - char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" - unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 - unsigned int gl_type; // For compressed textures, glType must equal 0 - unsigned int gl_type_size; // For compressed texture data, usually 1 - unsigned int gl_format; // For compressed textures is 0 - unsigned int gl_internal_format; // Compressed internal format - unsigned int gl_base_internal_format; // Same as glFormat (RGB, RGBA, ALPHA...) - unsigned int width; // Texture image width in pixels - unsigned int height; // Texture image height in pixels - unsigned int depth; // For 2D textures is 0 - unsigned int elements; // Number of array elements, usually 0 - unsigned int faces; // Cubemap faces, for no-cubemap = 1 - unsigned int mipmap_levels; // Non-mipmapped textures = 1 - unsigned int key_value_data_size; // Used to encode any arbitrary data... - } ktx_header; - - // NOTE: Before start of every mipmap data block, we have: unsigned int data_size - - if (file_data_ptr != NULL) - { - ktx_header *header = (ktx_header *)file_data_ptr; - - if ((header->id[1] != 'K') || (header->id[2] != 'T') || (header->id[3] != 'X') || - (header->id[4] != ' ') || (header->id[5] != '1') || (header->id[6] != '1')) - { - LOG("WARNING: IMAGE: KTX file data not valid"); - } - else - { - file_data_ptr += sizeof(ktx_header); // Move file data pointer - - *width = header->width; - *height = header->height; - *mips = header->mipmap_levels; - - file_data_ptr += header->key_value_data_size; // Skip value data size - - int data_size = ((int *)file_data_ptr)[0]; - file_data_ptr += sizeof(int); - - image_data = RL_MALLOC(data_size*sizeof(unsigned char)); - - memcpy(image_data, file_data_ptr, data_size); - - if (header->gl_internal_format == 0x8D64) *format = PIXELFORMAT_COMPRESSED_ETC1_RGB; - else if (header->gl_internal_format == 0x9274) *format = PIXELFORMAT_COMPRESSED_ETC2_RGB; - else if (header->gl_internal_format == 0x9278) *format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; - - // TODO: Support uncompressed data formats? Right now it returns format = 0! - } - } - - return image_data; -} - -// Save image data as KTX file -// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018) -// TODO: Review KTX saving, many things changed! -int rl_save_ktx(const char *file_name, void *data, int width, int height, int format, int mipmaps) -{ - // KTX file Header (64 bytes) - // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ - // v2.0 - http://github.khronos.org/KTX-Specification/ - Final specs by 2021-04-18 - typedef struct { - char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n" - unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 - unsigned int gl_type; // For compressed textures, glType must equal 0 - unsigned int gl_type_size; // For compressed texture data, usually 1 - unsigned int gl_format; // For compressed textures is 0 - unsigned int gl_internal_format; // Compressed internal format - unsigned int gl_base_internal_format; // Same as glFormat (RGB, RGBA, ALPHA...) // KTX 2.0: UInt32 vkFormat - unsigned int width; // Texture image width in pixels - unsigned int height; // Texture image height in pixels - unsigned int depth; // For 2D textures is 0 - unsigned int elements; // Number of array elements, usually 0 - unsigned int faces; // Cubemap faces, for no-cubemap = 1 - unsigned int mipmap_levels; // Non-mipmapped textures = 1 - unsigned int key_value_data_size; // Used to encode any arbitrary data... // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0 - // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)... - // KTX 2.0 defines additional header elements... - } ktx_header; - - // Calculate file data_size required - int data_size = sizeof(ktx_header); - - for (int i = 0, w = width, h = height; i < mipmaps; i++) - { - data_size += get_pixel_data_size(w, h, format); - w /= 2; h /= 2; - } - - unsigned char *file_data = RL_CALLOC(data_size, 1); - unsigned char *file_data_ptr = file_data; - - ktx_header header = { 0 }; - - // KTX identifier (v1.1) - //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; - //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; - - const char ktx_identifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; - - // Get the image header - memcpy(header.id, ktx_identifier, 12); // KTX 1.1 signature - header.endianness = 0; - header.gl_type = 0; // Obtained from format - header.gl_type_size = 1; - header.gl_format = 0; // Obtained from format - header.gl_internal_format = 0; // Obtained from format - header.gl_base_internal_format = 0; - header.width = width; - header.height = height; - header.depth = 0; - header.elements = 0; - header.faces = 1; - header.mipmap_levels = mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats) - header.key_value_data_size = 0; // No extra data after the header - - rlGetGlTextureFormats(format, &header.gl_internal_format, &header.gl_format, &header.gl_type); // rlgl module function - header.gl_base_internal_format = header.gl_format; // KTX 1.1 only - - // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC - - if (header.gl_format == -1) LOG("WARNING: IMAGE: GL format not supported for KTX export (%i)", header.gl_format); - else - { - memcpy(file_data_ptr, &header, sizeof(ktx_header)); - file_data_ptr += sizeof(ktx_header); - - int temp_width = width; - int temp_height = height; - int data_offset = 0; - - // Save all mipmaps data - for (int i = 0; i < mipmaps; i++) - { - unsigned int data_size = get_pixel_data_size(temp_width, temp_height, format); - - memcpy(file_data_ptr, &data_size, sizeof(unsigned int)); - memcpy(file_data_ptr + 4, (unsigned char *)data + data_offset, data_size); - - temp_width /= 2; - temp_height /= 2; - data_offset += data_size; - file_data_ptr += (4 + data_size); - } - } - - // Save file data to file - int success = false; - FILE *file = fopen(file_name, "wb"); - - if (file != NULL) - { - unsigned int count = (unsigned int)fwrite(file_data, sizeof(unsigned char), data_size, file); - - if (count == 0) LOG("WARNING: FILEIO: [%s] Failed to write file", file_name); - else if (count != data_size) LOG("WARNING: FILEIO: [%s] File partially written", file_name); - else LOG("INFO: FILEIO: [%s] File saved successfully", file_name); - - int result = fclose(file); - if (result == 0) success = true; - } - else LOG("WARNING: FILEIO: [%s] Failed to open file", file_name); - - RL_FREE(file_data); // Free file data buffer - - // If all data has been written correctly to file, success = 1 - return success; -} -#endif - -#if defined(RL_GPUTEX_SUPPORT_PVR) -// Loading PVR image data (uncompressed or PVRT compression) -// NOTE: PVR v2 not supported, use PVR v3 instead -void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) -{ - void *image_data = NULL; // Image data pointer - - unsigned char *file_data_ptr = (unsigned char *)file_data; - - // Required extension: - // GL_IMG_texture_compression_pvrtc - - // Supported tokens (defined by extensions) - // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 - // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 - -#if 0 // Not used... - // PVR file v2 Header (52 bytes) - typedef struct { - unsigned int headerLength; - unsigned int height; - unsigned int width; - unsigned int numMipmaps; - unsigned int flags; - unsigned int dataLength; - unsigned int bpp; - unsigned int bitmaskRed; - unsigned int bitmaskGreen; - unsigned int bitmaskBlue; - unsigned int bitmaskAlpha; - unsigned int pvrTag; - unsigned int numSurfs; - } PVRHeaderV2; -#endif - - // PVR file v3 Header (52 bytes) - // NOTE: After it could be metadata (15 bytes?) - typedef struct { - char id[4]; - unsigned int flags; - unsigned char channels[4]; // pixelFormat high part - unsigned char channel_depth[4]; // pixelFormat low part - unsigned int color_space; - unsigned int channel_type; - unsigned int height; - unsigned int width; - unsigned int depth; - unsigned int num_surfaces; - unsigned int num_faces; - unsigned int num_mipmaps; - unsigned int metadata_size; - } pvr_header; - -#if 0 // Not used... - // Metadata (usually 15 bytes) - typedef struct { - unsigned int devFOURCC; - unsigned int key; - unsigned int data_size; // Not used? - unsigned char *data; // Not used? - } PVRMetadata; -#endif - - if (file_data_ptr != NULL) - { - // Check PVR image version - unsigned char pvr_version = file_data_ptr[0]; - - // Load different PVR data formats - if (pvr_version == 0x50) - { - pvr_header *header = (pvr_header *)file_data_ptr; - - if ((header->id[0] != 'P') || (header->id[1] != 'V') || (header->id[2] != 'R') || (header->id[3] != 3)) - { - LOG("WARNING: IMAGE: PVR file data not valid"); - } - else - { - file_data_ptr += sizeof(pvr_header); // Skip header - - *width = header->width; - *height = header->height; - *mips = header->num_mipmaps; - - // Check data format - if (((header->channels[0] == 'l') && (header->channels[1] == 0)) && (header->channel_depth[0] == 8)) *format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - else if (((header->channels[0] == 'l') && (header->channels[1] == 'a')) && ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8))) *format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; - else if ((header->channels[0] == 'r') && (header->channels[1] == 'g') && (header->channels[2] == 'b')) - { - if (header->channels[3] == 'a') - { - if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 5) && (header->channel_depth[2] == 5) && (header->channel_depth[3] == 1)) *format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; - else if ((header->channel_depth[0] == 4) && (header->channel_depth[1] == 4) && (header->channel_depth[2] == 4) && (header->channel_depth[3] == 4)) *format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; - else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8) && (header->channel_depth[3] == 8)) *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - } - else if (header->channels[3] == 0) - { - if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 6) && (header->channel_depth[2] == 5)) *format = PIXELFORMAT_UNCOMPRESSED_R5G6B5; - else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8)) *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8; - } - } - else if (header->channels[0] == 2) *format = PIXELFORMAT_COMPRESSED_PVRT_RGB; - else if (header->channels[0] == 3) *format = PIXELFORMAT_COMPRESSED_PVRT_RGBA; - - file_data_ptr += header->metadata_size; // Skip meta data header - - // Calculate data size (depends on format) - int bpp = 0; - switch (*format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; - case PIXELFORMAT_COMPRESSED_PVRT_RGB: - case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; - default: break; - } - - int data_size = (*width)*(*height)*bpp/8; // Total data size in bytes - image_data = RL_MALLOC(data_size*sizeof(unsigned char)); - - memcpy(image_data, file_data_ptr, data_size); - } - } - else if (pvr_version == 52) LOG("INFO: IMAGE: PVRv2 format not supported, update your files to PVRv3"); - } - - return image_data; -} -#endif - -#if defined(RL_GPUTEX_SUPPORT_ASTC) -// Load ASTC compressed image data (ASTC compression) -void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) -{ - void *image_data = NULL; // Image data pointer - - unsigned char *file_data_ptr = (unsigned char *)file_data; - - // Required extensions: - // GL_KHR_texture_compression_astc_hdr - // GL_KHR_texture_compression_astc_ldr - - // Supported tokens (defined by extensions) - // GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0 - // GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 - - // ASTC file Header (16 bytes) - typedef struct { - unsigned char id[4]; // Signature: 0x13 0xAB 0xA1 0x5C - unsigned char blockX; // Block X dimensions - unsigned char blockY; // Block Y dimensions - unsigned char blockZ; // Block Z dimensions (1 for 2D images) - unsigned char width[3]; // void *width in pixels (24bit value) - unsigned char height[3]; // void *height in pixels (24bit value) - unsigned char length[3]; // void *Z-size (1 for 2D images) - } astc_header; - - if (file_data_ptr != NULL) - { - astc_header *header = (astc_header *)file_data_ptr; - - if ((header->id[3] != 0x5c) || (header->id[2] != 0xa1) || (header->id[1] != 0xab) || (header->id[0] != 0x13)) - { - LOG("WARNING: IMAGE: ASTC file data not valid"); - } - else - { - file_data_ptr += sizeof(astc_header); // Skip header - - // NOTE: Assuming Little Endian (could it be wrong?) - *width = 0x00000000 | ((int)header->width[2] << 16) | ((int)header->width[1] << 8) | ((int)header->width[0]); - *height = 0x00000000 | ((int)header->height[2] << 16) | ((int)header->height[1] << 8) | ((int)header->height[0]); - *mips = 1; // NOTE: ASTC format only contains one mipmap level - - // NOTE: Each block is always stored in 128bit so we can calculate the bpp - int bpp = 128/(header->blockX*header->blockY); - - // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8 - if ((bpp == 8) || (bpp == 2)) - { - int data_size = (*width)*(*height)*bpp/8; // Data size in bytes - - image_data = RL_MALLOC(data_size*sizeof(unsigned char)); - - memcpy(image_data, file_data_ptr, data_size); - - if (bpp == 8) *format = PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA; - else if (bpp == 2) *format = PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA; - } - else LOG("WARNING: IMAGE: ASTC block size configuration not supported"); - } - } - - return image_data; -} -#endif - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Get pixel data size in bytes for certain pixel format -static int get_pixel_data_size(int width, int height, int format) -{ - int data_size = 0; // Size in bytes - int bpp = 0; // Bits per pixel - - switch (format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; - case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; - case PIXELFORMAT_COMPRESSED_DXT1_RGB: - case PIXELFORMAT_COMPRESSED_DXT1_RGBA: - case PIXELFORMAT_COMPRESSED_ETC1_RGB: - case PIXELFORMAT_COMPRESSED_ETC2_RGB: - case PIXELFORMAT_COMPRESSED_PVRT_RGB: - case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; - case PIXELFORMAT_COMPRESSED_DXT3_RGBA: - case PIXELFORMAT_COMPRESSED_DXT5_RGBA: - case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: - case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; - case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; - default: break; - } - - data_size = width*height*bpp/8; // Total data size in bytes - - // Most compressed formats works on 4x4 blocks, - // if texture is smaller, minimum dataSize is 8 or 16 - if ((width < 4) && (height < 4)) - { - if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) data_size = 8; - else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) data_size = 16; - } - - return data_size; -} -#endif // RL_GPUTEX_IMPLEMENTATION diff --git a/raylib/external/rprand.h b/raylib/external/rprand.h deleted file mode 100644 index ded6708..0000000 --- a/raylib/external/rprand.h +++ /dev/null @@ -1,311 +0,0 @@ -/********************************************************************************************** -* -* rprand v1.0 - A simple and easy-to-use pseudo-random numbers generator (PRNG) -* -* FEATURES: -* - Pseudo-random values generation, 32 bits: [0..4294967295] -* - Sequence generation avoiding duplicate values -* - Using standard and proven prng algorithm (Xoshiro128**) -* - State initialized with a separate generator (SplitMix64) -* -* LIMITATIONS: -* - No negative numbers, up to the user to manage them -* -* POSSIBLE IMPROVEMENTS: -* - Support 64 bits generation -* -* ADDITIONAL NOTES: -* This library implements two pseudo-random number generation algorithms: -* -* - Xoshiro128** : https://prng.di.unimi.it/xoshiro128starstar.c -* - SplitMix64 : https://prng.di.unimi.it/splitmix64.c -* -* SplitMix64 is used to initialize the Xoshiro128** state, from a provided seed -* -* It's suggested to use SplitMix64 to initialize the state of the generators starting from -* a 64-bit seed, as research has shown that initialization must be performed with a generator -* radically different in nature from the one initialized to avoid correlation on similar seeds. -* -* CONFIGURATION: -* #define RPRAND_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* DEPENDENCIES: none -* -* VERSIONS HISTORY: -* 1.0 (01-Jun-2023) First version -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2023 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#ifndef RPRAND_H -#define RPRAND_H - -#define RPRAND_VERSION "1.0" - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) - #if defined(BUILD_LIBTYPE_SHARED) - #define RPRAND __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) - #elif defined(USE_LIBTYPE_SHARED) - #define RPRAND __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) - #endif -#endif - -// Function specifiers definition -#ifndef RPRANDAPI - #define RPRANDAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// Allow custom memory allocators -#ifndef RPRAND_CALLOC - #define RPRAND_CALLOC(ptr,sz) calloc(ptr,sz) -#endif -#ifndef RPRAND_FREE - #define RPRAND_FREE(ptr) free(ptr) -#endif - -// Simple log system to avoid RPNG_LOG() calls if required -// NOTE: Avoiding those calls, also avoids const strings memory usage -#define RPRAND_SHOW_LOG_INFO -#if defined(RPNG_SHOW_LOG_INFO) - #define RPRAND_LOG(...) printf(__VA_ARGS__) -#else - #define RPRAND_LOG(...) -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -//... - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -RPRANDAPI void rprand_set_seed(unsigned long long seed); // Set rprand_state for Xoshiro128**, seed is 64bit -RPRANDAPI int rprand_get_value(int min, int max); // Get random value within a range, min and max included - -RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates -RPRANDAPI void rprand_unload_sequence(int *sequence); // Unload pseudo-random numbers sequence - -#ifdef __cplusplus -} -#endif - -#endif // RPRAND_H - -/*********************************************************************************** -* -* RPRAND IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RPRAND_IMPLEMENTATION) - -#include // Required for: calloc(), free(), abs() -#include // Required for data types: uint32_t, uint64_t - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static uint64_t rprand_seed = 0xAABBCCDD; // SplitMix64 default seed (aligned to rprand_state) -static uint32_t rprand_state[4] = { // Xoshiro128** state, initialized by SplitMix64 - 0x96ea83c1, - 0x218b21e5, - 0xaa91febd, - 0x976414d4 -}; - -//---------------------------------------------------------------------------------- -// Module internal functions declaration -//---------------------------------------------------------------------------------- -static uint32_t rprand_xoshiro(void); // Xoshiro128** generator (uses global rprand_state) -static uint64_t rprand_splitmix64(void); // SplitMix64 generator (uses seed to generate rprand_state) - -//---------------------------------------------------------------------------------- -// Module functions definition -//---------------------------------------------------------------------------------- -// Set rprand_state for Xoshiro128** -// NOTE: We use a custom generation algorithm using SplitMix64 -void rprand_set_seed(unsigned long long seed) -{ - rprand_seed = (uint64_t)seed; // Set SplitMix64 seed for further use - - // To generate the Xoshiro128** state, we use SplitMix64 generator first - // We generate 4 pseudo-random 64bit numbers that we combine using their LSB|MSB - rprand_state[0] = (uint32_t)(rprand_splitmix64() & 0xffffffff); - rprand_state[1] = (uint32_t)((rprand_splitmix64() & 0xffffffff00000000) >> 32); - rprand_state[2] = (uint32_t)(rprand_splitmix64() & 0xffffffff); - rprand_state[3] = (uint32_t)((rprand_splitmix64() & 0xffffffff00000000) >> 32); -} - -// Get random value within a range, min and max included -int rprand_get_value(int min, int max) -{ - int value = rprand_xoshiro()%(abs(max - min) + 1) + min; - - return value; -} - -// Load pseudo-random numbers sequence with no duplicates, min and max included -int *rprand_load_sequence(unsigned int count, int min, int max) -{ - int *sequence = NULL; - - if (count > (unsigned int)(abs(max - min) + 1)) - { - RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n"); - //count = (max - min); - return sequence; - } - - sequence = (int *)RPRAND_CALLOC(count, sizeof(int)); - - int value = 0; - bool value_is_dup = false; - - for (unsigned int i = 0; i < count;) - { - value = ((unsigned int)rprand_xoshiro()%(abs(max - min) + 1)) + min; - - for (unsigned int j = 0; j < i; j++) - { - if (sequence[j] == value) - { - value_is_dup = true; - break; - } - } - - if (!value_is_dup) - { - sequence[i] = value; - i++; - } - - value_is_dup = false; - } - - return sequence; -} - -// Unload pseudo-random numbers sequence -void rprand_unload_sequence(int *sequence) -{ - RPRAND_FREE(sequence); - sequence = NULL; -} - -//---------------------------------------------------------------------------------- -// Module internal functions definition -//---------------------------------------------------------------------------------- -static inline uint32_t rprand_rotate_left(const uint32_t x, int k) -{ - return (x << k) | (x >> (32 - k)); -} - -// Xoshiro128** generator info: -// -// Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) -// -// To the extent possible under law, the author has dedicated all copyright -// and related and neighboring rights to this software to the public domain -// worldwide. This software is distributed without any warranty. -// -// See . -// -// This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid -// generators. It has excellent speed, a state size (128 bits) that is -// large enough for mild parallelism, and it passes all tests we are aware -// of. -// -// Note that version 1.0 had mistakenly s[0] instead of s[1] as state -// word passed to the scrambler. -// -// For generating just single-precision (i.e., 32-bit) floating-point -// numbers, xoshiro128+ is even faster. -// -// The state must be seeded so that it is not everywhere zero. -// -uint32_t rprand_xoshiro(void) -{ - const uint32_t result = rprand_rotate_left(rprand_state[1]*5, 7)*9; - const uint32_t t = rprand_state[1] << 9; - - rprand_state[2] ^= rprand_state[0]; - rprand_state[3] ^= rprand_state[1]; - rprand_state[1] ^= rprand_state[2]; - rprand_state[0] ^= rprand_state[3]; - - rprand_state[2] ^= t; - - rprand_state[3] = rprand_rotate_left(rprand_state[3], 11); - - return result; -} - -// SplitMix64 generator info: -// -// Written in 2015 by Sebastiano Vigna (vigna@acm.org) -// -// To the extent possible under law, the author has dedicated all copyright -// and related and neighboring rights to this software to the public domain -// worldwide. This software is distributed without any warranty. -// -// See . -// -// -// This is a fixed-increment version of Java 8's SplittableRandom generator -// See http://dx.doi.org/10.1145/2714064.2660195 and -// http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html -// -// It is a very fast generator passing BigCrush, and it can be useful if -// for some reason you absolutely want 64 bits of state. -uint64_t rprand_splitmix64() -{ - uint64_t z = (rprand_seed += 0x9e3779b97f4a7c15); - z = (z ^ (z >> 30))*0xbf58476d1ce4e5b9; - z = (z ^ (z >> 27))*0x94d049bb133111eb; - return z ^ (z >> 31); -} - -#endif // RPRAND_IMPLEMENTATION \ No newline at end of file diff --git a/raylib/external/scripts/glfw-generate-wayland.sh b/raylib/external/scripts/glfw-generate-wayland.sh index 0619c4c..26cd10e 100755 --- a/raylib/external/scripts/glfw-generate-wayland.sh +++ b/raylib/external/scripts/glfw-generate-wayland.sh @@ -4,58 +4,37 @@ TMPDIR="/tmp" GLGLFW_PATH="`pwd`/../glfw/src" cd $TMPDIR -git clone --depth 1 https://gitlab.freedesktop.org/wayland/wayland.git -git clone --depth 1 https://gitlab.freedesktop.org/wayland/wayland-protocols.git - -cd $TMPDIR -cd wayland - -rm -f "$GLGLFW_PATH"/wayland-client-protocol.h -rm -f "$GLGLFW_PATH"/wayland-client-protocol-code.h - -wayland-scanner private-code ./protocol/wayland.xml "$GLGLFW_PATH"/wayland-client-protocol-code.h -wayland-scanner client-header ./protocol/wayland.xml "$GLGLFW_PATH"/wayland-client-protocol.h - -cd $TMPDIR +git clone https://github.com/wayland-project/wayland-protocols cd wayland-protocols -rm -f "$GLGLFW_PATH"/xdg-shell-client-protocol.h -rm -f "$GLGLFW_PATH"/xdg-shell-client-protocol-code.h -rm -f "$GLGLFW_PATH"/fractional-scale-v1-client-protocol.h -rm -f "$GLGLFW_PATH"/fractional-scale-v1-client-protocol-code.h -rm -f "$GLGLFW_PATH"/xdg-activation-v1-client-protocol.h -rm -f "$GLGLFW_PATH"/xdg-activation-v1-client-protocol-code.h -rm -f "$GLGLFW_PATH"/xdg-decoration-client-protocol.h -rm -f "$GLGLFW_PATH"/xdg-decoration-client-protocol-code.h -rm -f "$GLGLFW_PATH"/viewporter-client-protocol.h -rm -f "$GLGLFW_PATH"/viewporter-client-protocol-code.h -rm -f "$GLGLFW_PATH"/relative-pointer-unstable-v1-client-protocol.h -rm -f "$GLGLFW_PATH"/relative-pointer-unstable-v1-client-protocol-code.h -rm -f "$GLGLFW_PATH"/pointer-constraints-unstable-v1-client-protocol.h -rm -f "$GLGLFW_PATH"/pointer-constraints-unstable-v1-client-protocol-code.h -rm -f "$GLGLFW_PATH"/idle-inhibit-unstable-v1-client-protocol.h -rm -f "$GLGLFW_PATH"/idle-inhibit-unstable-v1-client-protocol-code.h +rm -f "$GLGLFW_PATH"/wayland-pointer-constraints-unstable-v1-client-protocol.{h,c} +rm -f "$GLGLFW_PATH"/wayland-relative-pointer-unstable-v1-client-protocol.{h,c} +rm -f "$GLGLFW_PATH"/wayland-idle-inhibit-unstable-v1-client-protocol.{h,c} +rm -f "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.{h,c} +rm -f "$GLGLFW_PATH"/wayland-xdg-decoration-client-protocol.{h,c} +rm -f "$GLGLFW_PATH"/wayland-viewporter-client-protocol.{h,c} -wayland-scanner private-code ./stable/xdg-shell/xdg-shell.xml "$GLGLFW_PATH"/xdg-shell-client-protocol-code.h -wayland-scanner client-header ./stable/xdg-shell/xdg-shell.xml "$GLGLFW_PATH"/xdg-shell-client-protocol.h +wayland-scanner code ./unstable/pointer-constraints/pointer-constraints-unstable-v1.xml "$GLGLFW_PATH"/wayland-pointer-constraints-unstable-v1-client-protocol.c +wayland-scanner client-header ./unstable/pointer-constraints/pointer-constraints-unstable-v1.xml "$GLGLFW_PATH"/wayland-pointer-constraints-unstable-v1-client-protocol.h -wayland-scanner private-code ./staging/fractional-scale/fractional-scale-v1.xml "$GLGLFW_PATH"/fractional-scale-v1-client-protocol-code.h -wayland-scanner client-header ./staging/fractional-scale/fractional-scale-v1.xml "$GLGLFW_PATH"/fractional-scale-v1-client-protocol.h +wayland-scanner code ./unstable/relative-pointer/relative-pointer-unstable-v1.xml "$GLGLFW_PATH"/wayland-relative-pointer-unstable-v1-client-protocol.c +wayland-scanner client-header ./unstable/relative-pointer/relative-pointer-unstable-v1.xml "$GLGLFW_PATH"/wayland-relative-pointer-unstable-v1-client-protocol.h -wayland-scanner private-code ./staging/xdg-activation/xdg-activation-v1.xml "$GLGLFW_PATH"/xdg-activation-v1-client-protocol-code.h -wayland-scanner client-header ./staging/xdg-activation/xdg-activation-v1.xml "$GLGLFW_PATH"/xdg-activation-v1-client-protocol.h +wayland-scanner code ./unstable/idle-inhibit/idle-inhibit-unstable-v1.xml "$GLGLFW_PATH"/wayland-idle-inhibit-unstable-v1-client-protocol.c +wayland-scanner client-header ./unstable/idle-inhibit/idle-inhibit-unstable-v1.xml "$GLGLFW_PATH"/wayland-idle-inhibit-unstable-v1-client-protocol.h -wayland-scanner private-code ./unstable/xdg-decoration/xdg-decoration-unstable-v1.xml "$GLGLFW_PATH"/xdg-decoration-unstable-v1-client-protocol-code.h -wayland-scanner client-header ./unstable/xdg-decoration/xdg-decoration-unstable-v1.xml "$GLGLFW_PATH"/xdg-decoration-unstable-v1-client-protocol.h +wayland-scanner code ./stable/xdg-shell/xdg-shell.xml "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.c +wayland-scanner client-header ./stable/xdg-shell/xdg-shell.xml "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.h -wayland-scanner private-code ./stable/viewporter/viewporter.xml "$GLGLFW_PATH"/viewporter-client-protocol-code.h -wayland-scanner client-header ./stable/viewporter/viewporter.xml "$GLGLFW_PATH"/viewporter-client-protocol.h +wayland-scanner code ./unstable/xdg-decoration/xdg-decoration-unstable-v1.xml "$GLGLFW_PATH"/wayland-xdg-decoration-client-protocol.c +wayland-scanner client-header ./unstable/xdg-decoration/xdg-decoration-unstable-v1.xml "$GLGLFW_PATH"/wayland-xdg-decoration-client-protocol.h -wayland-scanner private-code ./unstable/relative-pointer/relative-pointer-unstable-v1.xml "$GLGLFW_PATH"/relative-pointer-unstable-v1-client-protocol-code.h -wayland-scanner client-header ./unstable/relative-pointer/relative-pointer-unstable-v1.xml "$GLGLFW_PATH"/relative-pointer-unstable-v1-client-protocol.h +wayland-scanner code ./stable/viewporter/viewporter.xml "$GLGLFW_PATH"/wayland-viewporter-client-protocol.c +wayland-scanner client-header ./stable/viewporter/viewporter.xml "$GLGLFW_PATH"/wayland-viewporter-client-protocol.h -wayland-scanner private-code ./unstable/pointer-constraints/pointer-constraints-unstable-v1.xml "$GLGLFW_PATH"/pointer-constraints-unstable-v1-client-protocol-code.h -wayland-scanner client-header ./unstable/pointer-constraints/pointer-constraints-unstable-v1.xml "$GLGLFW_PATH"/pointer-constraints-unstable-v1-client-protocol.h - -wayland-scanner private-code ./unstable/idle-inhibit/idle-inhibit-unstable-v1.xml "$GLGLFW_PATH"/idle-inhibit-unstable-v1-client-protocol-code.h -wayland-scanner client-header ./unstable/idle-inhibit/idle-inhibit-unstable-v1.xml "$GLGLFW_PATH"/idle-inhibit-unstable-v1-client-protocol.h +# Patch for cgo +sed -i "s|types|wl_pc_types|g" "$GLGLFW_PATH"/wayland-pointer-constraints-unstable-v1-client-protocol.c +sed -i "s|types|wl_rp_types|g" "$GLGLFW_PATH"/wayland-relative-pointer-unstable-v1-client-protocol.c +sed -i "s|types|wl_ii_types|g" "$GLGLFW_PATH"/wayland-idle-inhibit-unstable-v1-client-protocol.c +sed -i "s|types|wl_xs_types|g" "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.c +sed -i "s|types|wl_v_types|g" "$GLGLFW_PATH"/wayland-viewporter-client-protocol.c diff --git a/raylib/external/sdefl.h b/raylib/external/sdefl.h index 36015b9..218e754 100644 --- a/raylib/external/sdefl.h +++ b/raylib/external/sdefl.h @@ -1,4 +1,5 @@ -/*# Small Deflate +/* +# Small Deflate `sdefl` is a small bare bone lossless compression library in ANSI C (ISO C90) which implements the Deflate (RFC 1951) compressed data format specification standard. It is mainly tuned to get as much speed and compression ratio from as little code @@ -32,16 +33,16 @@ this file implementation in *one* C or C++ file to prevent collisions. | Compressor name | Compression| Decompress.| Compr. size | Ratio | | ------------------------| -----------| -----------| ----------- | ----- | -| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 | -| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 | -| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 | +| sdefl 1.0 -0 | 127 MB/s | 233 MB/s | 40004116 | 39.88 | +| sdefl 1.0 -1 | 111 MB/s | 259 MB/s | 38940674 | 38.82 | +| sdefl 1.0 -5 | 45 MB/s | 275 MB/s | 36577183 | 36.46 | +| sdefl 1.0 -7 | 38 MB/s | 276 MB/s | 36523781 | 36.41 | | zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 | | zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 | | zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 | -| sdefl 1.0 -0 | 127 MB/s | 355 MB/s | 40004116 | 39.88 | -| sdefl 1.0 -1 | 111 MB/s | 413 MB/s | 38940674 | 38.82 | -| sdefl 1.0 -5 | 45 MB/s | 436 MB/s | 36577183 | 36.46 | -| sdefl 1.0 -7 | 38 MB/s | 432 MB/s | 36523781 | 36.41 | +| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 | +| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 | +| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 | | libdeflate 1.3 -1 | 147 MB/s | 667 MB/s | 39597378 | 39.60 | | libdeflate 1.3 -6 | 69 MB/s | 689 MB/s | 36648318 | 36.65 | | libdeflate 1.3 -9 | 13 MB/s | 672 MB/s | 35197141 | 35.20 | @@ -50,20 +51,20 @@ this file implementation in *one* C or C++ file to prevent collisions. ### Compression Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia): -| File | Original | `sdefl 0` | `sdefl 5` | `sdefl 7` | -| --------| -----------| -------------| ---------- | ------------| -| dickens | 10.192.446 | 4,260,187 | 3,845,261 | 3,833,657 | -| mozilla | 51.220.480 | 20,774,706 | 19,607,009 | 19,565,867 | -| mr | 9.970.564 | 3,860,531 | 3,673,460 | 3,665,627 | -| nci | 33.553.445 | 4,030,283 | 3,094,526 | 3,006,075 | -| ooffice | 6.152.192 | 3,320,063 | 3,186,373 | 3,183,815 | -| osdb | 10.085.684 | 3,919,646 | 3,649,510 | 3,649,477 | -| reymont | 6.627.202 | 2,263,378 | 1,857,588 | 1,827,237 | -| samba | 21.606.400 | 6,121,797 | 5,462,670 | 5,450,762 | -| sao | 7.251.944 | 5,612,421 | 5,485,380 | 5,481,765 | -| webster | 41.458.703 | 13,972,648 | 12,059,432 | 11,991,421 | -| xml | 5.345.280 | 886,620 | 674,009 | 662,141 | -| x-ray | 8.474.240 | 6,304,655 | 6,244,779 | 6,244,779 | +| File | Original | `sdefl 0` | `sdefl 5` | `sdefl 7` | +| :------ | ---------: | -----------------: | ---------: | ----------: | +| dickens | 10.192.446 | 4,260,187| 3,845,261| 3,833,657 | +| mozilla | 51.220.480 | 20,774,706 | 19,607,009 | 19,565,867 | +| mr | 9.970.564 | 3,860,531 | 3,673,460 | 3,665,627 | +| nci | 33.553.445 | 4,030,283 | 3,094,526 | 3,006,075 | +| ooffice | 6.152.192 | 3,320,063 | 3,186,373 | 3,183,815 | +| osdb | 10.085.684 | 3,919,646 | 3,649,510 | 3,649,477 | +| reymont | 6.627.202 | 2,263,378 | 1,857,588 | 1,827,237 | +| samba | 21.606.400 | 6,121,797 | 5,462,670 | 5,450,762 | +| sao | 7.251.944 | 5,612,421 | 5,485,380 | 5,481,765 | +| webster | 41.458.703 | 13,972,648 | 12,059,432 | 11,991,421 | +| xml | 5.345.280 | 886,620| 674,009 | 662,141 | +| x-ray | 8.474.240 | 6,304,655 | 6,244,779 | 6,244,779 | ## License ``` @@ -71,7 +72,7 @@ Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License -Copyright (c) 2020-2023 Micha Mettke +Copyright (c) 2020 Micha Mettke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to @@ -125,7 +126,7 @@ extern "C" { #define SDEFL_MIN_MATCH 4 #define SDEFL_BLK_MAX (256*1024) -#define SDEFL_SEQ_SIZ ((SDEFL_BLK_MAX+2)/3) +#define SDEFL_SEQ_SIZ ((SDEFL_BLK_MAX + SDEFL_MIN_MATCH)/SDEFL_MIN_MATCH) #define SDEFL_SYM_MAX (288) #define SDEFL_OFF_MAX (32) @@ -185,7 +186,6 @@ extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl); #define SDEFL_MAX_CODE_LEN (15) #define SDEFL_SYM_BITS (10u) #define SDEFL_SYM_MSK ((1u << SDEFL_SYM_BITS)-1u) -#define SDEFL_RAW_BLK_SIZE (65535) #define SDEFL_LIT_LEN_CODES (14) #define SDEFL_OFF_CODES (15) #define SDEFL_PRE_CODES (7) @@ -193,7 +193,6 @@ extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl); #define SDEFL_EOB (256) #define sdefl_npow2(n) (1 << (sdefl_ilog2((n)-1) + 1)) -#define sdefl_div_round_up(n,d) (((n)+((d)-1))/(d)) static int sdefl_ilog2(int n) { @@ -399,8 +398,8 @@ sdefl_precode(struct sdefl_symcnt *cnt, unsigned *freqs, unsigned *items, if (offlen[cnt->off - 1]) break; total = (unsigned)(cnt->lit + cnt->off); - memcpy(lens, litlen, sizeof(unsigned char) * (size_t)cnt->lit); - memcpy(lens + cnt->lit, offlen, sizeof(unsigned char) * (size_t)cnt->off); + memcpy(lens, litlen, sizeof(unsigned char) * cnt->lit); + memcpy(lens + cnt->lit, offlen, sizeof(unsigned char) * cnt->off); do { unsigned len = lens[run_start]; unsigned run_end = run_start; @@ -440,12 +439,12 @@ sdefl_precode(struct sdefl_symcnt *cnt, unsigned *freqs, unsigned *items, } while (run_start != total); cnt->items = (int)(at - items); } -struct sdefl_match_codest { +struct sdefl_match_codes { int ls, lc; int dc, dx; }; static void -sdefl_match_codes(struct sdefl_match_codest *cod, int dist, int len) { +sdefl_match_codes(struct sdefl_match_codes *cod, int dist, int len) { static const short dxmax[] = {0,6,12,24,48,96,192,384,768,1536,3072,6144,12288,24576}; static const unsigned char lslot[258+1] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, @@ -464,53 +463,11 @@ sdefl_match_codes(struct sdefl_match_codest *cod, int dist, int len) { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; - assert(len <= 258); - assert(dist <= 32768); cod->ls = lslot[len]; cod->lc = 257 + cod->ls; - assert(cod->lc <= 285); - cod->dx = sdefl_ilog2(sdefl_npow2(dist) >> 2); cod->dc = cod->dx ? ((cod->dx + 1) << 1) + (dist > dxmax[cod->dx]) : dist-1; } -enum sdefl_blk_type { - SDEFL_BLK_UCOMPR, - SDEFL_BLK_DYN -}; -static enum sdefl_blk_type -sdefl_blk_type(const struct sdefl *s, int blk_len, int pre_item_len, - const unsigned *pre_freq, const unsigned char *pre_len) { - static const unsigned char x_pre_bits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - static const unsigned char x_len_bits[] = {0,0,0,0,0,0,0,0, 1,1,1,1,2,2,2,2, - 3,3,3,3,4,4,4,4, 5,5,5,5,0}; - static const unsigned char x_off_bits[] = {0,0,0,0,1,1,2,2, 3,3,4,4,5,5,6,6, - 7,7,8,8,9,9,10,10, 11,11,12,12,13,13}; - - int dyn_cost = 0; - int fix_cost = 0; - int sym = 0; - - dyn_cost += 5 + 5 + 4 + (3 * pre_item_len); - for (sym = 0; sym < SDEFL_PRE_MAX; sym++) - dyn_cost += pre_freq[sym] * (x_pre_bits[sym] + pre_len[sym]); - for (sym = 0; sym < 256; sym++) - dyn_cost += s->freq.lit[sym] * s->cod.len.lit[sym]; - dyn_cost += s->cod.len.lit[SDEFL_EOB]; - for (sym = 257; sym < 286; sym++) - dyn_cost += s->freq.lit[sym] * (x_len_bits[sym - 257] + s->cod.len.lit[sym]); - for (sym = 0; sym < 30; sym++) - dyn_cost += s->freq.off[sym] * (x_off_bits[sym] + s->cod.len.off[sym]); - - fix_cost += 8*(5 * sdefl_div_round_up(blk_len, SDEFL_RAW_BLK_SIZE) + blk_len + 1 + 2); - return (dyn_cost < fix_cost) ? SDEFL_BLK_DYN : SDEFL_BLK_UCOMPR; -} -static void -sdefl_put16(unsigned char **dst, unsigned short x) { - unsigned char *val = *dst; - val[0] = (unsigned char)(x & 0xff); - val[1] = (unsigned char)(x >> 8); - *dst = val + 2; -} static void sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) { static const char lxn[] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; @@ -519,7 +476,7 @@ sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) { static const short dmin[] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257, 385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; - struct sdefl_match_codest cod; + struct sdefl_match_codes cod; sdefl_match_codes(&cod, dist, len); sdefl_put(dst, s, (int)s->cod.word.lit[cod.lc], s->cod.len.lit[cod.lc]); sdefl_put(dst, s, len - lmin[cod.ls], lxn[cod.ls]); @@ -528,8 +485,7 @@ sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) { } static void sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last, - const unsigned char *in, int blk_begin, int blk_end) { - int blk_len = blk_end - blk_begin; + const unsigned char *in) { int j, i = 0, item_cnt = 0; struct sdefl_symcnt symcnt = {0}; unsigned codes[SDEFL_PRE_MAX]; @@ -539,69 +495,41 @@ sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last, static const unsigned char perm[SDEFL_PRE_MAX] = {16,17,18,0,8,7,9,6,10,5,11, 4,12,3,13,2,14,1,15}; - /* calculate huffman codes */ + /* huffman codes */ s->freq.lit[SDEFL_EOB]++; sdefl_huff(s->cod.len.lit, s->cod.word.lit, s->freq.lit, SDEFL_SYM_MAX, SDEFL_LIT_LEN_CODES); sdefl_huff(s->cod.len.off, s->cod.word.off, s->freq.off, SDEFL_OFF_MAX, SDEFL_OFF_CODES); sdefl_precode(&symcnt, freqs, items, s->cod.len.lit, s->cod.len.off); sdefl_huff(lens, codes, freqs, SDEFL_PRE_MAX, SDEFL_PRE_CODES); for (item_cnt = SDEFL_PRE_MAX; item_cnt > 4; item_cnt--) { - if (lens[perm[item_cnt - 1]]){ - break; - } + if (lens[perm[item_cnt - 1]]) break; } - /* write block */ - switch (sdefl_blk_type(s, blk_len, item_cnt, freqs, lens)) { - case SDEFL_BLK_UCOMPR: { - /* uncompressed blocks */ - int n = sdefl_div_round_up(blk_len, SDEFL_RAW_BLK_SIZE); - for (i = 0; i < n; ++i) { - int fin = is_last && (i + 1 == n); - int amount = blk_len < SDEFL_RAW_BLK_SIZE ? blk_len : SDEFL_RAW_BLK_SIZE; - sdefl_put(dst, s, !!fin, 1); /* block */ - sdefl_put(dst, s, 0x00, 2); /* stored block */ - if (s->bitcnt) { - sdefl_put(dst, s, 0x00, 8 - s->bitcnt); + /* block header */ + sdefl_put(dst, s, is_last ? 0x01 : 0x00, 1); /* block */ + sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */ + sdefl_put(dst, s, symcnt.lit - 257, 5); + sdefl_put(dst, s, symcnt.off - 1, 5); + sdefl_put(dst, s, item_cnt - 4, 4); + for (i = 0; i < item_cnt; ++i) + sdefl_put(dst, s, lens[perm[i]], 3); + for (i = 0; i < symcnt.items; ++i) { + unsigned sym = items[i] & 0x1F; + sdefl_put(dst, s, (int)codes[sym], lens[sym]); + if (sym < 16) continue; + if (sym == 16) sdefl_put(dst, s, items[i] >> 5, 2); + else if(sym == 17) sdefl_put(dst, s, items[i] >> 5, 3); + else sdefl_put(dst, s, items[i] >> 5, 7); + } + /* block sequences */ + for (i = 0; i < s->seq_cnt; ++i) { + if (s->seq[i].off >= 0) + for (j = 0; j < s->seq[i].len; ++j) { + int c = in[s->seq[i].off + j]; + sdefl_put(dst, s, (int)s->cod.word.lit[c], s->cod.len.lit[c]); } - assert(s->bitcnt == 0); - sdefl_put16(dst, (unsigned short)amount); - sdefl_put16(dst, ~(unsigned short)amount); - memcpy(*dst, in + blk_begin + i * SDEFL_RAW_BLK_SIZE, amount); - *dst = *dst + amount; - blk_len -= amount; - } - } break; - case SDEFL_BLK_DYN: { - /* dynamic huffman block */ - sdefl_put(dst, s, !!is_last, 1); /* block */ - sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */ - sdefl_put(dst, s, symcnt.lit - 257, 5); - sdefl_put(dst, s, symcnt.off - 1, 5); - sdefl_put(dst, s, item_cnt - 4, 4); - for (i = 0; i < item_cnt; ++i) { - sdefl_put(dst, s, lens[perm[i]], 3); - } - for (i = 0; i < symcnt.items; ++i) { - unsigned sym = items[i] & 0x1F; - sdefl_put(dst, s, (int)codes[sym], lens[sym]); - if (sym < 16) continue; - if (sym == 16) sdefl_put(dst, s, items[i] >> 5, 2); - else if(sym == 17) sdefl_put(dst, s, items[i] >> 5, 3); - else sdefl_put(dst, s, items[i] >> 5, 7); - } - /* block sequences */ - for (i = 0; i < s->seq_cnt; ++i) { - if (s->seq[i].off >= 0) { - for (j = 0; j < s->seq[i].len; ++j) { - int c = in[s->seq[i].off + j]; - sdefl_put(dst, s, (int)s->cod.word.lit[c], s->cod.len.lit[c]); - } - } else { - sdefl_match(dst, s, -s->seq[i].off, s->seq[i].len); - } - } - sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]); - } break;} + else sdefl_match(dst, s, -s->seq[i].off, s->seq[i].len); + } + sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]); memset(&s->freq, 0, sizeof(s->freq)); s->seq_cnt = 0; } @@ -614,12 +542,8 @@ sdefl_seq(struct sdefl *s, int off, int len) { } static void sdefl_reg_match(struct sdefl *s, int off, int len) { - struct sdefl_match_codest cod; + struct sdefl_match_codes cod; sdefl_match_codes(&cod, off, len); - - assert(cod.lc < SDEFL_SYM_MAX); - assert(cod.dc < SDEFL_OFF_MAX); - s->freq.lit[cod.lc]++; s->freq.off[cod.dc]++; } @@ -628,35 +552,22 @@ struct sdefl_match { int len; }; static void -sdefl_fnd(struct sdefl_match *m, const struct sdefl *s, int chain_len, - int max_match, const unsigned char *in, int p, int e) { - int i = s->tbl[sdefl_hash32(in + p)]; - int limit = ((p - SDEFL_WIN_SIZ) < SDEFL_NIL) ? SDEFL_NIL : (p-SDEFL_WIN_SIZ); - - assert(p < e); - assert(p + max_match <= e); +sdefl_fnd(struct sdefl_match *m, const struct sdefl *s, + int chain_len, int max_match, const unsigned char *in, int p) { + int i = s->tbl[sdefl_hash32(&in[p])]; + int limit = ((p-SDEFL_WIN_SIZ) limit) { - assert(i + m->len < e); - assert(p + m->len < e); - assert(i + SDEFL_MIN_MATCH < e); - assert(p + SDEFL_MIN_MATCH < e); - - if (in[i + m->len] == in[p + m->len] && - (sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))) { + if (in[i+m->len] == in[p+m->len] && + (sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))){ int n = SDEFL_MIN_MATCH; - while (n < max_match && in[i + n] == in[p + n]) { - assert(i + n < e); - assert(p + n < e); - n++; - } + while (n < max_match && in[i+n] == in[p+n]) n++; if (n > m->len) { m->len = n, m->off = p - i; - if (n == max_match) - break; + if (n == max_match) break; } } if (!(--chain_len)) break; - i = s->prv[i & SDEFL_WIN_MSK]; + i = s->prv[i&SDEFL_WIN_MSK]; } } static int @@ -669,20 +580,18 @@ sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in, for (n = 0; n < SDEFL_HASH_SIZ; ++n) { s->tbl[n] = SDEFL_NIL; } - do {int blk_begin = i; - int blk_end = ((i + SDEFL_BLK_MAX) < in_len) ? (i + SDEFL_BLK_MAX) : in_len; + do {int blk_end = i + SDEFL_BLK_MAX < in_len ? i + SDEFL_BLK_MAX : in_len; while (i < blk_end) { struct sdefl_match m = {0}; - int left = blk_end - i; - int max_match = (left > SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH : left; + int max_match = ((in_len-i)>SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH:(in_len-i); int nice_match = pref[lvl] < max_match ? pref[lvl] : max_match; - int run = 1, inc = 1, run_inc = 0; + int run = 1, inc = 1, run_inc; if (max_match > SDEFL_MIN_MATCH) { - sdefl_fnd(&m, s, max_chain, max_match, in, i, in_len); + sdefl_fnd(&m, s, max_chain, max_match, in, i); } - if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len + 1 < nice_match){ + if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len < nice_match){ struct sdefl_match m2 = {0}; - sdefl_fnd(&m2, s, max_chain, m.len + 1, in, i + 1, in_len); + sdefl_fnd(&m2, s, max_chain, m.len+1, in, i+1); m.len = (m2.len > m.len) ? 0 : m.len; } if (m.len >= SDEFL_MIN_MATCH) { @@ -707,23 +616,20 @@ sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in, unsigned h = sdefl_hash32(&in[i]); s->prv[i&SDEFL_WIN_MSK] = s->tbl[h]; s->tbl[h] = i, i += inc; - assert(i <= blk_end); } } else { i += run_inc; - assert(i <= blk_end); } } if (litlen) { sdefl_seq(s, i - litlen, litlen); litlen = 0; } - sdefl_flush(&q, s, blk_end == in_len, in, blk_begin, blk_end); + sdefl_flush(&q, s, blk_end == in_len, in); } while (i < in_len); - if (s->bitcnt) { + + if (s->bitcnt) sdefl_put(&q, s, 0x00, 8 - s->bitcnt); - } - assert(s->bitcnt == 0); return (int)(q - out); } extern int @@ -783,8 +689,9 @@ zsdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) { } extern int sdefl_bound(int len) { - int max_blocks = 1 + sdefl_div_round_up(len, SDEFL_RAW_BLK_SIZE); - int bound = 5 * max_blocks + len + 1 + 4 + 8; - return bound; + int a = 128 + (len * 110) / 100; + int b = 128 + len + ((len / (31 * 1024)) + 1) * 5; + return (a > b) ? a : b; } #endif /* SDEFL_IMPLEMENTATION */ + diff --git a/raylib/external/sinfl.h b/raylib/external/sinfl.h index a749501..37c1aae 100644 --- a/raylib/external/sinfl.h +++ b/raylib/external/sinfl.h @@ -10,7 +10,7 @@ as needed to keep the implementation as concise as possible. - Dual license with either MIT or public domain - Small implementation - Deflate: 525 LoC - - Inflate: 500 LoC + - Inflate: 320 LoC - Webassembly: - Deflate ~3.7 KB (~2.2KB compressed) - Inflate ~3.6 KB (~2.2KB compressed) @@ -33,16 +33,16 @@ this file implementation in *one* C or C++ file to prevent collisions. | Compressor name | Compression| Decompress.| Compr. size | Ratio | | ------------------------| -----------| -----------| ----------- | ----- | -| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 | -| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 | -| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 | +| sdefl 1.0 -0 | 127 MB/s | 233 MB/s | 40004116 | 39.88 | +| sdefl 1.0 -1 | 111 MB/s | 259 MB/s | 38940674 | 38.82 | +| sdefl 1.0 -5 | 45 MB/s | 275 MB/s | 36577183 | 36.46 | +| sdefl 1.0 -7 | 38 MB/s | 276 MB/s | 36523781 | 36.41 | | zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 | | zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 | | zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 | -| sdefl 1.0 -0 | 127 MB/s | 355 MB/s | 40004116 | 39.88 | -| sdefl 1.0 -1 | 111 MB/s | 413 MB/s | 38940674 | 38.82 | -| sdefl 1.0 -5 | 45 MB/s | 436 MB/s | 36577183 | 36.46 | -| sdefl 1.0 -7 | 38 MB/s | 432 MB/s | 36523781 | 36.41 | +| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 | +| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 | +| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 | | libdeflate 1.3 -1 | 147 MB/s | 667 MB/s | 39597378 | 39.60 | | libdeflate 1.3 -6 | 69 MB/s | 689 MB/s | 36648318 | 36.65 | | libdeflate 1.3 -9 | 13 MB/s | 672 MB/s | 35197141 | 35.20 | @@ -51,20 +51,20 @@ this file implementation in *one* C or C++ file to prevent collisions. ### Compression Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia): -| File | Original | `sdefl 0` | `sdefl 5` | `sdefl 7` | -| --------| -----------| -------------| ---------- | ------------| -| dickens | 10.192.446 | 4,260,187 | 3,845,261 | 3,833,657 | -| mozilla | 51.220.480 | 20,774,706 | 19,607,009 | 19,565,867 | -| mr | 9.970.564 | 3,860,531 | 3,673,460 | 3,665,627 | -| nci | 33.553.445 | 4,030,283 | 3,094,526 | 3,006,075 | -| ooffice | 6.152.192 | 3,320,063 | 3,186,373 | 3,183,815 | -| osdb | 10.085.684 | 3,919,646 | 3,649,510 | 3,649,477 | -| reymont | 6.627.202 | 2,263,378 | 1,857,588 | 1,827,237 | -| samba | 21.606.400 | 6,121,797 | 5,462,670 | 5,450,762 | -| sao | 7.251.944 | 5,612,421 | 5,485,380 | 5,481,765 | -| webster | 41.458.703 | 13,972,648 | 12,059,432 | 11,991,421 | -| xml | 5.345.280 | 886,620 | 674,009 | 662,141 | -| x-ray | 8.474.240 | 6,304,655 | 6,244,779 | 6,244,779 | +| File | Original | `sdefl 0` | `sdefl 5` | `sdefl 7` | +| :------ | ---------: | -----------------: | ---------: | ----------: | +| dickens | 10.192.446 | 4,260,187| 3,845,261| 3,833,657 | +| mozilla | 51.220.480 | 20,774,706 | 19,607,009 | 19,565,867 | +| mr | 9.970.564 | 3,860,531 | 3,673,460 | 3,665,627 | +| nci | 33.553.445 | 4,030,283 | 3,094,526 | 3,006,075 | +| ooffice | 6.152.192 | 3,320,063 | 3,186,373 | 3,183,815 | +| osdb | 10.085.684 | 3,919,646 | 3,649,510 | 3,649,477 | +| reymont | 6.627.202 | 2,263,378 | 1,857,588 | 1,827,237 | +| samba | 21.606.400 | 6,121,797 | 5,462,670 | 5,450,762 | +| sao | 7.251.944 | 5,612,421 | 5,485,380 | 5,481,765 | +| webster | 41.458.703 | 13,972,648 | 12,059,432 | 11,991,421 | +| xml | 5.345.280 | 886,620| 674,009 | 662,141 | +| x-ray | 8.474.240 | 6,304,655 | 6,244,779 | 6,244,779 | ## License ``` @@ -72,7 +72,7 @@ Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License -Copyright (c) 2020-2023 Micha Mettke +Copyright (c) 2020 Micha Mettke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to @@ -121,16 +121,12 @@ extern "C" { #define SINFL_OFF_TBL_SIZE 402 struct sinfl { - const unsigned char *bitptr; - const unsigned char *bitend; // @raysan5: added - unsigned long long bitbuf; - int bitcnt; - + int bits, bitcnt; unsigned lits[SINFL_LIT_TBL_SIZE]; unsigned dsts[SINFL_OFF_TBL_SIZE]; }; -extern int sinflate(void *out, int cap, const void *in, int size); -extern int zsinflate(void *out, int cap, const void *in, int size); +extern int sinflate(void *out, const void *in, int size); +extern int zsinflate(void *out, const void *in, int size); #ifdef __cplusplus } @@ -141,117 +137,30 @@ extern int zsinflate(void *out, int cap, const void *in, int size); #ifdef SINFL_IMPLEMENTATION #include /* memcpy, memset */ -#include /* assert */ - -#if defined(__GNUC__) || defined(__clang__) -#define sinfl_likely(x) __builtin_expect((x),1) -#define sinfl_unlikely(x) __builtin_expect((x),0) -#else -#define sinfl_likely(x) (x) -#define sinfl_unlikely(x) (x) -#endif - -#ifndef SINFL_NO_SIMD -#if defined(__x86_64__) || defined(_WIN32) || defined(_WIN64) - #include - #define sinfl_char16 __m128i - #define sinfl_char16_ld(p) _mm_loadu_si128((const __m128i *)(void*)(p)) - #define sinfl_char16_str(d,v) _mm_storeu_si128((__m128i*)(void*)(d), v) - #define sinfl_char16_char(c) _mm_set1_epi8(c) -#elif defined(__arm__) || defined(__aarch64__) - #include - #define sinfl_char16 uint8x16_t - #define sinfl_char16_ld(p) vld1q_u8((const unsigned char*)(p)) - #define sinfl_char16_str(d,v) vst1q_u8((unsigned char*)(d), v) - #define sinfl_char16_char(c) vdupq_n_u8(c) -#else - #define SINFL_NO_SIMD -#endif -#endif static int sinfl_bsr(unsigned n) { #ifdef _MSC_VER - unsigned long uln = 0; - _BitScanReverse(&uln, n); - return (int)(uln); -#else // defined(__GNUC__) || defined(__clang__) || defined(__TINYC__) + _BitScanReverse(&n, n); + return n; +#elif defined(__GNUC__) || defined(__clang__) return 31 - __builtin_clz(n); #endif } -static unsigned long long -sinfl_read64(const void *p) { - unsigned long long n; - memcpy(&n, p, 8); - return n; -} -static void -sinfl_copy64(unsigned char **dst, unsigned char **src) { - //unsigned long long n; - //memcpy(&n, *src, 8); - //memcpy(*dst, &n, 8); - memcpy(*dst, *src, 8); // @raysan5 - *dst += 8, *src += 8; -} -static unsigned char* -sinfl_write64(unsigned char *dst, unsigned long long w) { - memcpy(dst, &w, 8); - return dst + 8; -} -#ifndef SINFL_NO_SIMD -static unsigned char* -sinfl_write128(unsigned char *dst, sinfl_char16 w) { - sinfl_char16_str(dst, w); - return dst + 8; -} -static void -sinfl_copy128(unsigned char **dst, unsigned char **src) { - sinfl_char16 n = sinfl_char16_ld(*src); - sinfl_char16_str(*dst, n); - *dst += 16, *src += 16; -} -#endif -static void -sinfl_refill(struct sinfl *s) { - if (s->bitend - s->bitptr >= 8) { - // @raysan5: original code, only those 3 lines - s->bitbuf |= sinfl_read64(s->bitptr) << s->bitcnt; - s->bitptr += (63 - s->bitcnt) >> 3; - s->bitcnt |= 56; /* bitcount in range [56,63] */ - } else { - // @raysan5: added this case when bits remaining < 8 - int bitswant = 63 - s->bitcnt; - int byteswant = bitswant >> 3; - int bytesuse = s->bitend - s->bitptr <= byteswant ? (int)(s->bitend - s->bitptr) : byteswant; - unsigned long long n = 0; - memcpy(&n, s->bitptr, bytesuse); - s->bitbuf |= n << s->bitcnt; - s->bitptr += bytesuse; - s->bitcnt += bytesuse << 3; +static int +sinfl_get(const unsigned char **src, const unsigned char *end, struct sinfl *s, + int n) { + const unsigned char *in = *src; + int v = s->bits & ((1 << n)-1); + s->bits >>= n; + s->bitcnt = s->bitcnt - n; + s->bitcnt = s->bitcnt < 0 ? 0 : s->bitcnt; + while (s->bitcnt < 16 && in < end) { + s->bits |= (*in++) << s->bitcnt; + s->bitcnt += 8; } -} -static int -sinfl_peek(struct sinfl *s, int cnt) { - //assert(cnt >= 0 && cnt <= 56); // @raysan5: commented to avoid crash on decompression - //assert(cnt <= s->bitcnt); - return s->bitbuf & ((1ull << cnt) - 1); -} -static void -sinfl_eat(struct sinfl *s, int cnt) { - //assert(cnt <= s->bitcnt); // @raysan5: commented - s->bitbuf >>= cnt; - s->bitcnt -= cnt; -} -static int -sinfl__get(struct sinfl *s, int cnt) { - int res = sinfl_peek(s, cnt); - sinfl_eat(s, cnt); - return res; -} -static int -sinfl_get(struct sinfl *s, int cnt) { - sinfl_refill(s); - return sinfl__get(s, cnt); + *src = in; + return v; } struct sinfl_gen { int len; @@ -300,7 +209,7 @@ sinfl_build_subtbl(struct sinfl_gen *gen, unsigned *tbl, int tbl_bits, while (1) { unsigned entry; int bit, stride, i; - /* start new sub-table */ + /* start new subtable */ if ((gen->word & ((1 << tbl_bits)-1)) != sub_prefix) { int used = 0; sub_prefix = gen->word & ((1 << tbl_bits)-1); @@ -314,7 +223,7 @@ sinfl_build_subtbl(struct sinfl_gen *gen, unsigned *tbl, int tbl_bits, tbl_end = sub_start + (1 << sub_bits); tbl[sub_prefix] = (sub_start << 16) | 0x10 | (sub_bits & 0xf); } - /* fill sub-table */ + /* fill subtable */ entry = (*gen->sorted << 16) | ((gen->len - tbl_bits) & 0xf); gen->sorted++; i = sub_start + (gen->word >> tbl_bits); @@ -367,21 +276,22 @@ sinfl_build(unsigned *tbl, unsigned char *lens, int tbl_bits, int maxlen, } } static int -sinfl_decode(struct sinfl *s, const unsigned *tbl, int bit_len) { - int idx = sinfl_peek(s, bit_len); +sinfl_decode(const unsigned char **in, const unsigned char *end, + struct sinfl *s, const unsigned *tbl, int bit_len) { + int idx = s->bits & ((1 << bit_len) - 1); unsigned key = tbl[idx]; if (key & 0x10) { /* sub-table lookup */ int len = key & 0x0f; - sinfl_eat(s, bit_len); - idx = sinfl_peek(s, len); + sinfl_get(in, end, s, bit_len); + idx = s->bits & ((1 << len)-1); key = tbl[((key >> 16) & 0xffff) + (unsigned)idx]; } - sinfl_eat(s, key & 0x0f); + sinfl_get(in, end, s, key & 0x0f); return (key >> 16) & 0x0fff; } static int -sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size) { +sinfl_decompress(unsigned char *out, const unsigned char *in, int size) { static const unsigned char order[] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; static const short dbase[30+2] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; @@ -392,23 +302,19 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size) static const unsigned char lbits[29+2] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4, 4,4,4,5,5,5,5,0,0,0}; - const unsigned char *oe = out + cap; const unsigned char *e = in + size, *o = out; enum sinfl_states {hdr,stored,fixed,dyn,blk}; enum sinfl_states state = hdr; struct sinfl s = {0}; int last = 0; - s.bitptr = in; - s.bitend = e; // @raysan5: added - while (1) { + sinfl_get(&in,e,&s,0); /* buffer input */ + while (in < e || s.bitcnt) { switch (state) { case hdr: { - /* block header */ - int type = 0; - sinfl_refill(&s); - last = sinfl__get(&s,1); - type = sinfl__get(&s,2); + int type = 0; /* block header */ + last = sinfl_get(&in,e,&s,1); + type = sinfl_get(&in,e,&s,2); switch (type) {default: return (int)(out-o); case 0x00: state = stored; break; @@ -416,22 +322,16 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size) case 0x02: state = dyn; break;} } break; case stored: { - /* uncompressed block */ - unsigned len, nlen; - sinfl__get(&s,s.bitcnt & 7); - len = (unsigned short)sinfl__get(&s,16); - nlen = (unsigned short)sinfl__get(&s,16); - s.bitptr -= s.bitcnt / 8; - s.bitbuf = s.bitcnt = 0; + int len; /* uncompressed block */ + sinfl_get(&in,e,&s,s.bitcnt & 7); + len = sinfl_get(&in,e,&s,16); + //int nlen = sinfl_get(&in,e,&s,16); + in -= 2; s.bitcnt = 0; - if ((unsigned short)len != (unsigned short)~nlen) + if (len > (e-in) || !len) return (int)(out-o); - if (len > (e - s.bitptr) || !len) - return (int)(out-o); - - memcpy(out, s.bitptr, (size_t)len); - s.bitptr += len, out += len; - if (last) return (int)(out-o); + memcpy(out, in, (size_t)len); + in += len, out += len; state = hdr; } break; case fixed: { @@ -449,142 +349,76 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size) state = blk; } break; case dyn: { - /* dynamic huffman codes */ - int n, i; - unsigned hlens[SINFL_PRE_TBL_SIZE]; - unsigned char nlens[19] = {0}, lens[288+32]; + /* dynamic huffman codes */ + int n, i; + unsigned hlens[SINFL_PRE_TBL_SIZE]; + unsigned char nlens[19] = {0}, lens[288+32]; + int nlit = 257 + sinfl_get(&in,e,&s,5); + int ndist = 1 + sinfl_get(&in,e,&s,5); + int nlen = 4 + sinfl_get(&in,e,&s,4); + for (n = 0; n < nlen; n++) + nlens[order[n]] = (unsigned char)sinfl_get(&in,e,&s,3); + sinfl_build(hlens, nlens, 7, 7, 19); - sinfl_refill(&s); - {int nlit = 257 + sinfl__get(&s,5); - int ndist = 1 + sinfl__get(&s,5); - int nlen = 4 + sinfl__get(&s,4); - for (n = 0; n < nlen; n++) - nlens[order[n]] = (unsigned char)sinfl_get(&s,3); - sinfl_build(hlens, nlens, 7, 7, 19); - - /* decode code lengths */ - for (n = 0; n < nlit + ndist;) { - int sym = 0; - sinfl_refill(&s); - sym = sinfl_decode(&s, hlens, 7); - switch (sym) {default: lens[n++] = (unsigned char)sym; break; - case 16: for (i=3+sinfl_get(&s,2);i;i--,n++) lens[n]=lens[n-1]; break; - case 17: for (i=3+sinfl_get(&s,3);i;i--,n++) lens[n]=0; break; - case 18: for (i=11+sinfl_get(&s,7);i;i--,n++) lens[n]=0; break;} - } - /* build lit/dist tables */ - sinfl_build(s.lits, lens, 10, 15, nlit); - sinfl_build(s.dsts, lens + nlit, 8, 15, ndist); - state = blk;} + /* decode code lengths */ + for (n = 0; n < nlit + ndist;) { + int sym = sinfl_decode(&in, e, &s, hlens, 7); + switch (sym) {default: lens[n++] = (unsigned char)sym; break; + case 16: for (i=3+sinfl_get(&in,e,&s,2);i;i--,n++) lens[n]=lens[n-1]; break; + case 17: for (i=3+sinfl_get(&in,e,&s,3);i;i--,n++) lens[n]=0; break; + case 18: for (i=11+sinfl_get(&in,e,&s,7);i;i--,n++) lens[n]=0; break;} + } + /* build lit/dist tables */ + sinfl_build(s.lits, lens, 10, 15, nlit); + sinfl_build(s.dsts, lens + nlit, 8, 15, ndist); + state = blk; } break; case blk: { /* decompress block */ - while (1) { - int sym; - sinfl_refill(&s); - sym = sinfl_decode(&s, s.lits, 10); - if (sym < 256) { - /* literal */ - if (sinfl_unlikely(out >= oe)) { - return (int)(out-o); - } - *out++ = (unsigned char)sym; - sym = sinfl_decode(&s, s.lits, 10); - if (sym < 256) { - *out++ = (unsigned char)sym; - continue; - } - } - if (sinfl_unlikely(sym == 256)) { - /* end of block */ - if (last) return (int)(out-o); - state = hdr; - break; - } - /* match */ - if (sym >= 286) { - /* length codes 286 and 287 must not appear in compressed data */ + int i, sym = sinfl_decode(&in, e, &s, s.lits, 10); + if (sym > 256) {sym -= 257; /* match symbol */ + {int len = sinfl_get(&in, e, &s, lbits[sym]) + lbase[sym]; + int dsym = sinfl_decode(&in, e, &s, s.dsts, 8); + int offs = sinfl_get(&in, e, &s, dbits[dsym]) + dbase[dsym]; + if (offs > (int)(out-o)) { return (int)(out-o); - } - sym -= 257; - {int len = sinfl__get(&s, lbits[sym]) + lbase[sym]; - int dsym = sinfl_decode(&s, s.dsts, 8); - int offs = sinfl__get(&s, dbits[dsym]) + dbase[dsym]; - unsigned char *dst = out, *src = out - offs; - if (sinfl_unlikely(offs > (int)(out-o))) { - return (int)(out-o); - } - out = out + len; - -#ifndef SINFL_NO_SIMD - if (sinfl_likely(oe - out >= 16 * 3)) { - if (offs >= 16) { - /* simd copy match */ - sinfl_copy128(&dst, &src); - sinfl_copy128(&dst, &src); - do sinfl_copy128(&dst, &src); - while (dst < out); - } else if (offs >= 8) { - /* word copy match */ - sinfl_copy64(&dst, &src); - sinfl_copy64(&dst, &src); - do sinfl_copy64(&dst, &src); - while (dst < out); - } else if (offs == 1) { - /* rle match copying */ - sinfl_char16 w = sinfl_char16_char(src[0]); - dst = sinfl_write128(dst, w); - dst = sinfl_write128(dst, w); - do dst = sinfl_write128(dst, w); - while (dst < out); - } else { - /* byte copy match */ - *dst++ = *src++; - *dst++ = *src++; - do *dst++ = *src++; - while (dst < out); + } else if (offs == 1) { + /* rle match copying */ + unsigned char c = *(out - offs); + unsigned long w = (c << 24) | (c << 16) | (c << 8) | c; + for (i = 0; i < len >> 2; ++i) { + memcpy(out, &w, 4); + out += 4; } - } -#else - if (sinfl_likely(oe - out >= 3 * 8 - 3)) { - if (offs >= 8) { - /* word copy match */ - sinfl_copy64(&dst, &src); - sinfl_copy64(&dst, &src); - do sinfl_copy64(&dst, &src); - while (dst < out); - } else if (offs == 1) { - /* rle match copying */ - unsigned int c = src[0]; - unsigned int hw = (c << 24u) | (c << 16u) | (c << 8u) | (unsigned)c; - unsigned long long w = (unsigned long long)hw << 32llu | hw; - dst = sinfl_write64(dst, w); - dst = sinfl_write64(dst, w); - do dst = sinfl_write64(dst, w); - while (dst < out); - } else { - /* byte copy match */ - *dst++ = *src++; - *dst++ = *src++; - do *dst++ = *src++; - while (dst < out); + len = len & 3; + } else if (offs >= 4) { + /* copy match */ + int wcnt = len >> 2; + for (i = 0; i < wcnt; ++i) { + unsigned long w = 0; + memcpy(&w, out - offs, 4); + memcpy(out, &w, 4); + out += 4; } + len = len & 3; } -#endif - else { - *dst++ = *src++; - *dst++ = *src++; - do *dst++ = *src++; - while (dst < out); - }} - } + for (i = 0; i < len; ++i) + {*out = *(out-offs), out++;} + } + } else if (sym == 256) { + /* end of block */ + if (last) return (int)(out-o); + state = hdr; + break; + /* literal */ + } else *out++ = (unsigned char)sym; } break;} } return (int)(out-o); } extern int -sinflate(void *out, int cap, const void *in, int size) { - return sinfl_decompress((unsigned char*)out, cap, (const unsigned char*)in, size); +sinflate(void *out, const void *in, int size) { + return sinfl_decompress((unsigned char*)out, (const unsigned char*)in, size); } static unsigned sinfl_adler32(unsigned adler32, const unsigned char *in, int in_len) { @@ -614,11 +448,11 @@ sinfl_adler32(unsigned adler32, const unsigned char *in, int in_len) { } return (unsigned)(s2 << 16) + (unsigned)s1; } extern int -zsinflate(void *out, int cap, const void *mem, int size) { +zsinflate(void *out, const void *mem, int size) { const unsigned char *in = (const unsigned char*)mem; if (size >= 6) { const unsigned char *eob = in + size - 4; - int n = sinfl_decompress((unsigned char*)out, cap, in + 2u, size); + int n = sinfl_decompress((unsigned char*)out, in + 2u, size); unsigned a = sinfl_adler32(1u, (unsigned char*)out, n); unsigned h = eob[0] << 24 | eob[1] << 16 | eob[2] << 8 | eob[3] << 0; return a == h ? n : -1; diff --git a/raylib/external/stb_image.h b/raylib/external/stb_image.h index 9eedabe..accef48 100644 --- a/raylib/external/stb_image.h +++ b/raylib/external/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,10 +48,6 @@ LICENSE RECENT REVISION HISTORY: - 2.30 (2024-05-31) avoid erroneous gcc warning - 2.29 (2023-05-xx) optimizations - 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff - 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically @@ -93,7 +89,7 @@ RECENT REVISION HISTORY: Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine Simon Breuss (16-bit PNM) + Arseny Kapoulkine John-Mark Allen Carmelo J Fdez-Aguera @@ -106,21 +102,19 @@ RECENT REVISION HISTORY: Thomas Ruf Ronny Chevalier github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Laurent Gomila Cort Stratton github:snagar Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Josh Tobin Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko github:mosra + Brad Weinberger Matvey Cherevko [reserved] Luca Sas Alexander Veselov Zack Middleton [reserved] Ryan C. Gordon [reserved] [reserved] DO NOT ADD YOUR NAME HERE - Jacko Dirks - To add your name to the credits, pick a random blank space in the middle and fill it. 80% of merge conflicts on stb PRs are due to people adding their name at the end of the credits. @@ -143,7 +137,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data); +// stbi_image_free(data) // // Standard parameters: // int *x -- outputs image width in pixels @@ -182,32 +176,6 @@ RECENT REVISION HISTORY: // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // -// To query the width, height and component count of an image without having to -// decode the full file, you can use the stbi_info family of functions: -// -// int x,y,n,ok; -// ok = stbi_info(filename, &x, &y, &n); -// // returns ok=1 and sets x, y, n if image is a supported format, -// // 0 otherwise. -// -// Note that stb_image pervasively uses ints in its public API for sizes, -// including sizes of memory buffers. This is now part of the API and thus -// hard to change without causing breakage. As a result, the various image -// loaders all have certain limits on image size; these differ somewhat -// by format but generally boil down to either just under 2GB or just under -// 1GB. When the decoded image would be larger than this, stb_image decoding -// will fail. -// -// Additionally, stb_image will reject image files that have any of their -// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, -// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, -// the only way to have an image with such dimensions load correctly -// is for it to have a rather extreme aspect ratio. Either way, the -// assumption here is that such larger images are likely to be malformed -// or malicious. If you do need to load an image with individual dimensions -// larger than that, and it still fits in the overall size limit, you can -// #define STBI_MAX_DIMENSIONS on your own to be something larger. -// // =========================================================================== // // UNICODE: @@ -313,10 +281,11 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// We optionally support converting iPhone-formatted PNGs (which store -// premultiplied BGRA) back to RGB, even though they're internally encoded -// differently. To enable this conversion, call -// stbi_convert_iphone_png_to_rgb(1). +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly @@ -520,8 +489,6 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // as above, but only applies to images loaded on the thread that calls the function // this function is only available if your compiler supports thread-local variables; // calling it will fail to link if your compiler doesn't -STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes @@ -638,7 +605,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #endif #endif -#if defined(_MSC_VER) || defined(__SYMBIAN32__) +#ifdef _MSC_VER typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -667,7 +634,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -781,12 +748,9 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -#ifdef _MSC_VER -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -#else +// assume GCC or Clang on ARM targets #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif -#endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name @@ -960,7 +924,6 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__pnm_is16(stbi__context *s); #endif static @@ -1035,7 +998,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && @@ -1058,7 +1021,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) return stbi__malloc(a*b*c + add); } -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; @@ -1066,23 +1029,6 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif -// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. -static int stbi__addints_valid(int a, int b) -{ - if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow - if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. - return a <= INT_MAX - b; -} - -// returns 1 if the product of two ints fits in a signed short, 0 on overflow. -static int stbi__mul2shorts_valid(int a, int b) -{ - if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow - if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid - if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN - return a >= SHRT_MIN / b; -} - // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -1141,8 +1087,9 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; - // test the formats with a very explicit header first (at least a FOURCC - // or distinctive magic number first) + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -1160,13 +1107,6 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif - - // then the formats that can end up attempting to load with just 1 or 2 - // bytes matching expectations; these are prone to false positives, so - // try them later - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif @@ -1322,12 +1262,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); @@ -1337,16 +1277,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) return 0; -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else @@ -1722,8 +1662,7 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - z += (stbi__uint32)stbi__get16le(s) << 16; - return z; + return z + (stbi__get16le(s) << 16); } #endif @@ -2005,12 +1944,9 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) { - for (j=0; j < count[i]; ++j) { + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) h->size[k++] = (stbi_uc) (i+1); - if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); - } - } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -2135,8 +2071,6 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - if(c < 0 || c >= 256) // symbol id out of bounds! - return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -2155,14 +2089,14 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing - sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB k = stbi_lrot(j->code_buffer, n); + if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & (sgn - 1)); + return k + (stbi__jbias[n] & ~sgn); } // get some unsigned bits @@ -2170,7 +2104,6 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -2182,7 +2115,6 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2214,16 +2146,14 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; - if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2237,7 +2167,6 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length - if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2274,14 +2203,12 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; - if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - data[0] = (short) (dc * (1 << j->succ_low)); + data[0] = (short) (dc << j->succ_low); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2315,11 +2242,10 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length - if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * (1 << shift)); + data[zig] = (short) ((r >> 8) << shift); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2337,7 +2263,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ } else { k += r; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + data[zig] = (short) (stbi__extend_receive(j,s) << shift); } } } while (k <= j->spec_end); @@ -3136,7 +3062,6 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } - if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3302,13 +3227,6 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } - // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios - // and I've never seen a non-corrupted JPEG file actually use them - for (i=0; i < s->img_n; ++i) { - if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); - if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); - } - // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; @@ -3386,28 +3304,6 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } -static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) -{ - // some JPEGs have junk at end, skip over it but if we find what looks - // like a valid marker, resume there - while (!stbi__at_eof(j->s)) { - stbi_uc x = stbi__get8(j->s); - while (x == 0xff) { // might be a marker - if (stbi__at_eof(j->s)) return STBI__MARKER_none; - x = stbi__get8(j->s); - if (x != 0x00 && x != 0xff) { - // not a stuffed zero or lead-in to another marker, looks - // like an actual marker, return it - return x; - } - // stuffed zero has x=0 now which ends the loop, meaning we go - // back to regular scan loop. - // repeated 0xff keeps trying to read the next byte of the marker. - } - } - return STBI__MARKER_none; -} - // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3424,22 +3320,25 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - j->marker = stbi__skip_jpeg_junk_at_end(j); + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } - m = stbi__get_marker(j); - if (STBI__RESTART(m)) - m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); - m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 1; - m = stbi__get_marker(j); + if (!stbi__process_marker(j, m)) return 0; } + m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3883,10 +3782,6 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp else decode_n = z->s->img_n; - // nothing to do if no components requested; check this now to avoid - // accessing uninitialized coutput[0] later - if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } - // resample and color-convert { int k; @@ -4029,8 +3924,6 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__errpuc("outofmem", "Out of memory"); - memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -4043,8 +3936,6 @@ static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__err("outofmem", "Out of memory"); - memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -4069,8 +3960,6 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - if (!j) return stbi__err("outofmem", "Out of memory"); - memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -4090,7 +3979,6 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) -#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) @@ -4100,8 +3988,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[STBI__ZNSYMS]; - stbi__uint16 value[STBI__ZNSYMS]; + stbi_uc size[288]; + stbi__uint16 value[288]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -4178,7 +4066,6 @@ typedef struct { stbi_uc *zbuffer, *zbuffer_end; int num_bits; - int hit_zeof_once; stbi__uint32 code_buffer; char *zout; @@ -4233,7 +4120,7 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; @@ -4245,20 +4132,9 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) int b,s; if (a->num_bits < 16) { if (stbi__zeof(a)) { - if (!a->hit_zeof_once) { - // This is the first time we hit eof, insert 16 extra padding btis - // to allow us to keep going; if we actually consume any of them - // though, that is invalid data. This is caught later. - a->hit_zeof_once = 1; - a->num_bits += 16; // add 16 implicit zero bits - } else { - // We already inserted our extra 16 padding bits and are again - // out, this stream is actually prematurely terminated. - return -1; - } - } else { - stbi__fill_bits(a); + return -1; /* report error for unexpected end of data. */ } + stbi__fill_bits(a); } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { @@ -4323,25 +4199,17 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) int len,dist; if (z == 256) { a->zout = zout; - if (a->hit_zeof_once && a->num_bits < 16) { - // The first time we hit zeof, we inserted 16 extra zero bits into our bit - // buffer so the decoder can just do its speculative decoding. But if we - // actually consumed any of those bits (which is the case when num_bits < 16), - // the stream actually read past the end so it is malformed. - return stbi__err("unexpected end","Corrupt PNG"); - } return 1; } - if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (len > a->zout_end - zout) { + if (zout + len > a->zout_end) { if (!stbi__zexpand(a, zout, len)) return 0; zout = a->zout; } @@ -4449,7 +4317,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +static const stbi_uc stbi__zdefault_length[288] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, @@ -4485,7 +4353,6 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) if (!stbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; - a->hit_zeof_once = 0; do { final = stbi__zreceive(a,1); type = stbi__zreceive(a,2); @@ -4496,7 +4363,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4641,8 +4508,9 @@ enum { STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, - // synthetic filter used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first }; static stbi_uc first_row_filter[5] = @@ -4651,56 +4519,29 @@ static stbi_uc first_row_filter[5] = STBI__F_sub, STBI__F_none, STBI__F_avg_first, - STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub + STBI__F_paeth_first }; static int stbi__paeth(int a, int b, int c) { - // This formulation looks very different from the reference in the PNG spec, but is - // actually equivalent and has favorable data dependencies and admits straightforward - // generation of branch-free code, which helps performance significantly. - int thresh = c*3 - (a + b); - int lo = a < b ? a : b; - int hi = a < b ? b : a; - int t0 = (hi <= thresh) ? lo : c; - int t1 = (thresh <= lo) ? hi : t0; - return t1; + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; } static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; -// adds an extra all-255 alpha channel -// dest == src is legal -// img_n must be 1 or 3 -static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) -{ - int i; - // must process data backwards since we allow dest==src - if (img_n == 1) { - for (i=x-1; i >= 0; --i) { - dest[i*2+1] = 255; - dest[i*2+0] = src[i]; - } - } else { - STBI_ASSERT(img_n == 3); - for (i=x-1; i >= 0; --i) { - dest[i*4+3] = 255; - dest[i*4+2] = src[i*3+2]; - dest[i*4+1] = src[i*3+1]; - dest[i*4+0] = src[i*3+0]; - } - } -} - // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { - int bytes = (depth == 16 ? 2 : 1); + int bytes = (depth == 16? 2 : 1); stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n*bytes; stbi__uint32 img_len, img_width_bytes; - stbi_uc *filter_buf; - int all_ok = 1; int k; int img_n = s->img_n; // copy it into a local for later @@ -4712,11 +4553,8 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); - // note: error exits here don't need to clean up a->out individually, - // stbi__do_png always does on error. if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); - if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); img_len = (img_width_bytes + 1) * y; // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, @@ -4724,136 +4562,188 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // so just check for raw_len < img_len always. if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - // Allocate two scan lines worth of filter workspace buffer. - filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); - if (!filter_buf) return stbi__err("outofmem", "Out of memory"); - - // Filtering for low-bit-depth images - if (depth < 8) { - filter_bytes = 1; - width = img_width_bytes; - } - for (j=0; j < y; ++j) { - // cur/prior filter buffers alternate - stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; - stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; - stbi_uc *dest = a->out + stride*j; - int nk = width * filter_bytes; + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; int filter = *raw++; - // check filter type - if (filter > 4) { - all_ok = stbi__err("invalid filter","Corrupt PNG"); - break; + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; - // perform actual filtering - switch (filter) { - case STBI__F_none: - memcpy(cur, raw, nk); - break; - case STBI__F_sub: - memcpy(cur, raw, filter_bytes); - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); - break; - case STBI__F_up: - for (k = 0; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + prior[k]); - break; - case STBI__F_avg: - for (k = 0; k < filter_bytes; ++k) - cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); - break; - case STBI__F_paeth: - for (k = 0; k < filter_bytes; ++k) - cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); - break; - case STBI__F_avg_first: - memcpy(cur, raw, filter_bytes); - for (k = filter_bytes; k < nk; ++k) - cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); - break; + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } } - raw += nk; - - // expand decoded bits in cur to dest, also adding an extra alpha channel if desired - if (depth < 8) { - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - stbi_uc *in = cur; - stbi_uc *out = dest; - stbi_uc inb = 0; - stbi__uint32 nsmp = x*img_n; - - // expand bits to bytes first - if (depth == 4) { - for (i=0; i < nsmp; ++i) { - if ((i & 1) == 0) inb = *in++; - *out++ = scale * (inb >> 4); - inb <<= 4; - } - } else if (depth == 2) { - for (i=0; i < nsmp; ++i) { - if ((i & 3) == 0) inb = *in++; - *out++ = scale * (inb >> 6); - inb <<= 2; - } - } else { - STBI_ASSERT(depth == 1); - for (i=0; i < nsmp; ++i) { - if ((i & 7) == 0) inb = *in++; - *out++ = scale * (inb >> 7); - inb <<= 1; - } - } - - // insert alpha=255 values if desired + if (depth == 8) { if (img_n != out_n) - stbi__create_png_alpha_expand8(dest, dest, x, img_n); - } else if (depth == 8) { - if (img_n == out_n) - memcpy(dest, cur, x*img_n); - else - stbi__create_png_alpha_expand8(dest, cur, x, img_n); + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; } else if (depth == 16) { - // convert the image data from big-endian to platform-native - stbi__uint16 *dest16 = (stbi__uint16*)dest; - stbi__uint32 nsmp = x*img_n; + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } - if (img_n == out_n) { - for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) - *dest16 = (cur[0] << 8) | cur[1]; - } else { - STBI_ASSERT(img_n+1 == out_n); - if (img_n == 1) { - for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { - dest16[0] = (cur[0] << 8) | cur[1]; - dest16[1] = 0xffff; - } - } else { - STBI_ASSERT(img_n == 3); - for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { - dest16[0] = (cur[0] << 8) | cur[1]; - dest16[1] = (cur[2] << 8) | cur[3]; - dest16[2] = (cur[4] << 8) | cur[5]; - dest16[3] = 0xffff; - } + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; } } } } - STBI_FREE(filter_buf); - if (!all_ok) return 0; + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } return 1; } @@ -4869,7 +4759,6 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4990,46 +4879,19 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load_global = 0; -static int stbi__de_iphone_flag_global = 0; +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag_global = flag_true_if_should_convert; + stbi__de_iphone_flag = flag_true_if_should_convert; } -#ifndef STBI_THREAD_LOCAL -#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global -#define stbi__de_iphone_flag stbi__de_iphone_flag_global -#else -static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; -static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; - -STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; - stbi__unpremultiply_on_load_set = 1; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_local = flag_true_if_should_convert; - stbi__de_iphone_flag_set = 1; -} - -#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ - ? stbi__unpremultiply_on_load_local \ - : stbi__unpremultiply_on_load_global) -#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ - ? stbi__de_iphone_flag_local \ - : stbi__de_iphone_flag_global) -#endif // STBI_THREAD_LOCAL - static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; @@ -5119,13 +4981,14 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS } - // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -5157,14 +5020,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; - // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. - if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { - for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning - tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { - for (k = 0; k < s->img_n && k < 3; ++k) - tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger } } break; @@ -5173,13 +5032,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { - // header scan definitely stops at first IDAT - if (pal_img_n) - s->img_n = pal_img_n; - return 1; - } - if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -5419,32 +5272,6 @@ typedef struct int extra_read; } stbi__bmp_data; -static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) -{ - // BI_BITFIELDS specifies masks explicitly, don't override - if (compress == 3) - return 1; - - if (compress == 0) { - if (info->bpp == 16) { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } else if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - // otherwise, use defaults, which is all-0 - info->mr = info->mg = info->mb = info->ma = 0; - } - return 1; - } - return 0; // error -} - static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; @@ -5472,8 +5299,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes - if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres @@ -5488,7 +5313,17 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - stbi__bmp_set_mask_defaults(info, compress); + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); @@ -5503,7 +5338,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) return stbi__errpuc("bad BMP", "bad BMP"); } } else { - // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); @@ -5511,8 +5345,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); - if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs - stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters @@ -5562,22 +5394,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - // accept some number of extra bytes after the header, but if the offset points either to before - // the header ends or implies a large amount of extra data, reject the file as malformed - int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); - int header_limit = 1024; // max we actually read is below 256 bytes currently. - int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. - if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { - return stbi__errpuc("bad header", "Corrupt BMP"); - } - // we established that bytes_read_so_far is positive and sensible. - // the first half of this test rejects offsets that are either too small positives, or - // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn - // ensures the number computed in the second half of the test can't overflow. - if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { - return stbi__errpuc("bad offset", "Corrupt BMP"); - } else { - stbi__skip(s, info.offset - bytes_read_so_far); + STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); + if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); } } @@ -6523,7 +6342,6 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6639,7 +6457,6 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); @@ -6949,17 +6766,6 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } -static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) -{ - STBI_FREE(g->out); - STBI_FREE(g->history); - STBI_FREE(g->background); - - if (out) STBI_FREE(out); - if (delays && *delays) STBI_FREE(*delays); - return stbi__errpuc("outofmem", "Out of memory"); -} - static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { @@ -6971,10 +6777,6 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int stride; int out_size = 0; int delays_size = 0; - - STBI_NOTUSED(out_size); - STBI_NOTUSED(delays_size); - memset(&g, 0, sizeof(g)); if (delays) { *delays = 0; @@ -6992,29 +6794,26 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (out) { void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (!tmp) - return stbi__load_gif_main_outofmem(&g, out, delays); + if (NULL == tmp) { + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + return stbi__errpuc("outofmem", "Out of memory"); + } else { out = (stbi_uc*) tmp; out_size = layers * stride; } if (delays) { - int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); - if (!new_delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - *delays = new_delays; + *delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); delays_size = layers * sizeof(int); } } else { out = (stbi_uc*)stbi__malloc( layers * stride ); - if (!out) - return stbi__load_gif_main_outofmem(&g, out, delays); out_size = layers * stride; if (delays) { *delays = (int*) stbi__malloc( layers * sizeof(int) ); - if (!*delays) - return stbi__load_gif_main_outofmem(&g, out, delays); delays_size = layers * sizeof(int); } } @@ -7265,12 +7064,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -7339,10 +7138,9 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) info.all_a = 255; p = stbi__bmp_parse_header(s, &info); - if (p == NULL) { - stbi__rewind( s ); + stbi__rewind( s ); + if (p == NULL) return 0; - } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { @@ -7408,8 +7206,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - STBI_NOTUSED(stbi__get32be(s)); - STBI_NOTUSED(stbi__get32be(s)); + (void) stbi__get32be(s); + (void) stbi__get32be(s); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -7488,6 +7286,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel #ifndef STBI_NO_PNM @@ -7508,8 +7307,7 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); - if (ri->bits_per_channel == 0) + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) return 0; if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); @@ -7519,22 +7317,15 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { - STBI_FREE(out); - return stbi__errpuc("bad PNM", "PNM file truncated"); - } + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); if (req_comp && req_comp != s->img_n) { - if (ri->bits_per_channel == 16) { - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); - } else { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - } + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7571,8 +7362,6 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); - if((value > 214748364) || (value == 214748364 && *c > '7')) - return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7603,29 +7392,17 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width - if(*x == 0) - return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height - if (*y == 0) - return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value - if (maxv > 65535) - return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); - else if (maxv > 255) - return 16; - else - return 8; -} -static int stbi__pnm_is16(stbi__context *s) -{ - if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) - return 1; - return 0; + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; } #endif @@ -7681,9 +7458,6 @@ static int stbi__is_16_main(stbi__context *s) if (stbi__psd_is16(s)) return 1; #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_is16(s)) return 1; - #endif return 0; } diff --git a/raylib/external/stb_image_resize.h b/raylib/external/stb_image_resize.h new file mode 100644 index 0000000..42a8efb --- /dev/null +++ b/raylib/external/stb_image_resize.h @@ -0,0 +1,2631 @@ +/* stb_image_resize - v0.96 - public domain image resizing + by Jorge L Rodriguez (@VinoBS) - 2014 + http://github.com/nothings/stb + + Written with emphasis on usability, portability, and efficiency. (No + SIMD or threads, so it be easily outperformed by libs that use those.) + Only scaling and translation is supported, no rotations or shears. + Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. + + COMPILING & LINKING + In one C/C++ file that #includes this file, do this: + #define STB_IMAGE_RESIZE_IMPLEMENTATION + before the #include. That will create the implementation in that file. + + QUICKSTART + stbir_resize_uint8( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, num_channels) + stbir_resize_float(...) + stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0) + stbir_resize_uint8_srgb_edgemode( + input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) + // WRAP/REFLECT/ZERO + + FULL API + See the "header file" section of the source for API documentation. + + ADDITIONAL DOCUMENTATION + + SRGB & FLOATING POINT REPRESENTATION + The sRGB functions presume IEEE floating point. If you do not have + IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use + a slower implementation. + + MEMORY ALLOCATION + The resize functions here perform a single memory allocation using + malloc. To control the memory allocation, before the #include that + triggers the implementation, do: + + #define STBIR_MALLOC(size,context) ... + #define STBIR_FREE(ptr,context) ... + + Each resize function makes exactly one call to malloc/free, so to use + temp memory, store the temp memory in the context and return that. + + ASSERT + Define STBIR_ASSERT(boolval) to override assert() and not use assert.h + + OPTIMIZATION + Define STBIR_SATURATE_INT to compute clamp values in-range using + integer operations instead of float operations. This may be faster + on some platforms. + + DEFAULT FILTERS + For functions which don't provide explicit control over what filters + to use, you can change the compile-time defaults with + + #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something + + See stbir_filter in the header-file section for the list of filters. + + NEW FILTERS + A number of 1D filter kernels are used. For a list of + supported filters see the stbir_filter enum. To add a new filter, + write a filter function and add it to stbir__filter_info_table. + + PROGRESS + For interactive use with slow resize operations, you can install + a progress-report callback: + + #define STBIR_PROGRESS_REPORT(val) some_func(val) + + The parameter val is a float which goes from 0 to 1 as progress is made. + + For example: + + static void my_progress_report(float progress); + #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) + + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "stb_image_resize.h" + + static void my_progress_report(float progress) + { + printf("Progress: %f%%\n", progress*100); + } + + MAX CHANNELS + If your image has more than 64 channels, define STBIR_MAX_CHANNELS + to the max you'll have. + + ALPHA CHANNEL + Most of the resizing functions provide the ability to control how + the alpha channel of an image is processed. The important things + to know about this: + + 1. The best mathematically-behaved version of alpha to use is + called "premultiplied alpha", in which the other color channels + have had the alpha value multiplied in. If you use premultiplied + alpha, linear filtering (such as image resampling done by this + library, or performed in texture units on GPUs) does the "right + thing". While premultiplied alpha is standard in the movie CGI + industry, it is still uncommon in the videogame/real-time world. + + If you linearly filter non-premultiplied alpha, strange effects + occur. (For example, the 50/50 average of 99% transparent bright green + and 1% transparent black produces 50% transparent dark green when + non-premultiplied, whereas premultiplied it produces 50% + transparent near-black. The former introduces green energy + that doesn't exist in the source image.) + + 2. Artists should not edit premultiplied-alpha images; artists + want non-premultiplied alpha images. Thus, art tools generally output + non-premultiplied alpha images. + + 3. You will get best results in most cases by converting images + to premultiplied alpha before processing them mathematically. + + 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the + resizer does not do anything special for the alpha channel; + it is resampled identically to other channels. This produces + the correct results for premultiplied-alpha images, but produces + less-than-ideal results for non-premultiplied-alpha images. + + 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, + then the resizer weights the contribution of input pixels + based on their alpha values, or, equivalently, it multiplies + the alpha value into the color channels, resamples, then divides + by the resultant alpha value. Input pixels which have alpha=0 do + not contribute at all to output pixels unless _all_ of the input + pixels affecting that output pixel have alpha=0, in which case + the result for that pixel is the same as it would be without + STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for + input images in integer formats. For input images in float format, + input pixels with alpha=0 have no effect, and output pixels + which have alpha=0 will be 0 in all channels. (For float images, + you can manually achieve the same result by adding a tiny epsilon + value to the alpha channel of every image, and then subtracting + or clamping it at the end.) + + 6. You can suppress the behavior described in #5 and make + all-0-alpha pixels have 0 in all channels by #defining + STBIR_NO_ALPHA_EPSILON. + + 7. You can separately control whether the alpha channel is + interpreted as linear or affected by the colorspace. By default + it is linear; you almost never want to apply the colorspace. + (For example, graphics hardware does not apply sRGB conversion + to the alpha channel.) + + CONTRIBUTORS + Jorge L Rodriguez: Implementation + Sean Barrett: API design, optimizations + Aras Pranckevicius: bugfix + Nathan Reed: warning fixes + + REVISIONS + 0.97 (2020-02-02) fixed warning + 0.96 (2019-03-04) fixed warnings + 0.95 (2017-07-23) fixed warnings + 0.94 (2017-03-18) fixed warnings + 0.93 (2017-03-03) fixed bug with certain combinations of heights + 0.92 (2017-01-02) fix integer overflow on large (>2GB) images + 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions + 0.90 (2014-09-17) first released version + + LICENSE + See end of file for license information. + + TODO + Don't decode all of the image data when only processing a partial tile + Don't use full-width decode buffers when only processing a partial tile + When processing wide images, break processing into tiles so data fits in L1 cache + Installable filters? + Resize that respects alpha test coverage + (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: + https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) +*/ + +#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H +#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H + +#ifdef _MSC_VER +typedef unsigned char stbir_uint8; +typedef unsigned short stbir_uint16; +typedef unsigned int stbir_uint32; +#else +#include +typedef uint8_t stbir_uint8; +typedef uint16_t stbir_uint16; +typedef uint32_t stbir_uint32; +#endif + +#ifndef STBIRDEF +#ifdef STB_IMAGE_RESIZE_STATIC +#define STBIRDEF static +#else +#ifdef __cplusplus +#define STBIRDEF extern "C" +#else +#define STBIRDEF extern +#endif +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Easy-to-use API: +// +// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) +// * input_w is input image width (x-axis), input_h is input image height (y-axis) +// * stride is the offset between successive rows of image data in memory, in bytes. you can +// specify 0 to mean packed continuously in memory +// * alpha channel is treated identically to other channels. +// * colorspace is linear or sRGB as specified by function name +// * returned result is 1 for success or 0 in case of an error. +// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. +// * Memory required grows approximately linearly with input and output size, but with +// discontinuities at input_w == output_w and input_h == output_h. +// * These functions use a "default" resampling filter defined at compile time. To change the filter, +// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE +// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + + +// The following functions interpret image data as gamma-corrected sRGB. +// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, +// or otherwise provide the index of the alpha channel. Flags value +// of 0 will probably do the right thing if you're not sure what +// the flags mean. + +#define STBIR_ALPHA_CHANNEL_NONE -1 + +// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will +// use alpha-weighted resampling (effectively premultiplying, resampling, +// then unpremultiplying). +#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) +// The specified alpha channel should be handled as gamma-corrected value even +// when doing sRGB operations. +#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags); + + +typedef enum +{ + STBIR_EDGE_CLAMP = 1, + STBIR_EDGE_REFLECT = 2, + STBIR_EDGE_WRAP = 3, + STBIR_EDGE_ZERO = 4, +} stbir_edge; + +// This function adds the ability to specify how requests to sample off the edge of the image are handled. +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode); + +////////////////////////////////////////////////////////////////////////////// +// +// Medium-complexity API +// +// This extends the easy-to-use API as follows: +// +// * Alpha-channel can be processed separately +// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE +// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) +// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) +// * Filter can be selected explicitly +// * uint16 image type +// * sRGB colorspace available for all types +// * context parameter for passing to STBIR_MALLOC + +typedef enum +{ + STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses + STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios + STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering + STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque + STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline + STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 +} stbir_filter; + +typedef enum +{ + STBIR_COLORSPACE_LINEAR, + STBIR_COLORSPACE_SRGB, + + STBIR_MAX_COLORSPACES, +} stbir_colorspace; + +// The following functions are all identical except for the type of the image data + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + + + +////////////////////////////////////////////////////////////////////////////// +// +// Full-complexity API +// +// This extends the medium API as follows: +// +// * uint32 image type +// * not typesafe +// * separate filter types for each axis +// * separate edge modes for each axis +// * can specify scale explicitly for subpixel correctness +// * can specify image source tile using texture coordinates + +typedef enum +{ + STBIR_TYPE_UINT8 , + STBIR_TYPE_UINT16, + STBIR_TYPE_UINT32, + STBIR_TYPE_FLOAT , + + STBIR_MAX_TYPES +} stbir_datatype; + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context); + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset); + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1); +// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H + + + + + +#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION + +#ifndef STBIR_ASSERT +#include +#define STBIR_ASSERT(x) assert(x) +#endif + +// For memset +#include + +#include + +#ifndef STBIR_MALLOC +#include +// use comma operator to evaluate c, to avoid "unused parameter" warnings +#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) +#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) +#endif + +#ifndef _MSC_VER +#ifdef __cplusplus +#define stbir__inline inline +#else +#define stbir__inline +#endif +#else +#define stbir__inline __forceinline +#endif + + +// should produce compiler error if size is wrong +typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBIR__NOTUSED(v) (void)(v) +#else +#define STBIR__NOTUSED(v) (void)sizeof(v) +#endif + +#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE +#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +#endif + +#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL +#endif + +#ifndef STBIR_PROGRESS_REPORT +#define STBIR_PROGRESS_REPORT(float_0_to_1) +#endif + +#ifndef STBIR_MAX_CHANNELS +#define STBIR_MAX_CHANNELS 64 +#endif + +#if STBIR_MAX_CHANNELS > 65536 +#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." +// because we store the indices in 16-bit variables +#endif + +// This value is added to alpha just before premultiplication to avoid +// zeroing out color values. It is equivalent to 2^-80. If you don't want +// that behavior (it may interfere if you have floating point images with +// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to +// disable it. +#ifndef STBIR_ALPHA_EPSILON +#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) +#endif + + + +#ifdef _MSC_VER +#define STBIR__UNUSED_PARAM(v) (void)(v) +#else +#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) +#endif + +// must match stbir_datatype +static unsigned char stbir__type_size[] = { + 1, // STBIR_TYPE_UINT8 + 2, // STBIR_TYPE_UINT16 + 4, // STBIR_TYPE_UINT32 + 4, // STBIR_TYPE_FLOAT +}; + +// Kernel function centered at 0 +typedef float (stbir__kernel_fn)(float x, float scale); +typedef float (stbir__support_fn)(float scale); + +typedef struct +{ + stbir__kernel_fn* kernel; + stbir__support_fn* support; +} stbir__filter_info; + +// When upsampling, the contributors are which source pixels contribute. +// When downsampling, the contributors are which destination pixels are contributed to. +typedef struct +{ + int n0; // First contributing pixel + int n1; // Last contributing pixel +} stbir__contributors; + +typedef struct +{ + const void* input_data; + int input_w; + int input_h; + int input_stride_bytes; + + void* output_data; + int output_w; + int output_h; + int output_stride_bytes; + + float s0, t0, s1, t1; + + float horizontal_shift; // Units: output pixels + float vertical_shift; // Units: output pixels + float horizontal_scale; + float vertical_scale; + + int channels; + int alpha_channel; + stbir_uint32 flags; + stbir_datatype type; + stbir_filter horizontal_filter; + stbir_filter vertical_filter; + stbir_edge edge_horizontal; + stbir_edge edge_vertical; + stbir_colorspace colorspace; + + stbir__contributors* horizontal_contributors; + float* horizontal_coefficients; + + stbir__contributors* vertical_contributors; + float* vertical_coefficients; + + int decode_buffer_pixels; + float* decode_buffer; + + float* horizontal_buffer; + + // cache these because ceil/floor are inexplicably showing up in profile + int horizontal_coefficient_width; + int vertical_coefficient_width; + int horizontal_filter_pixel_width; + int vertical_filter_pixel_width; + int horizontal_filter_pixel_margin; + int vertical_filter_pixel_margin; + int horizontal_num_contributors; + int vertical_num_contributors; + + int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) + int ring_buffer_num_entries; // Total number of entries in the ring buffer. + int ring_buffer_first_scanline; + int ring_buffer_last_scanline; + int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer + float* ring_buffer; + + float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. + + int horizontal_contributors_size; + int horizontal_coefficients_size; + int vertical_contributors_size; + int vertical_coefficients_size; + int decode_buffer_size; + int horizontal_buffer_size; + int ring_buffer_size; + int encode_buffer_size; +} stbir__info; + + +static const float stbir__max_uint8_as_float = 255.0f; +static const float stbir__max_uint16_as_float = 65535.0f; +static const double stbir__max_uint32_as_float = 4294967295.0; + + +static stbir__inline int stbir__min(int a, int b) +{ + return a < b ? a : b; +} + +static stbir__inline float stbir__saturate(float x) +{ + if (x < 0) + return 0; + + if (x > 1) + return 1; + + return x; +} + +#ifdef STBIR_SATURATE_INT +static stbir__inline stbir_uint8 stbir__saturate8(int x) +{ + if ((unsigned int) x <= 255) + return x; + + if (x < 0) + return 0; + + return 255; +} + +static stbir__inline stbir_uint16 stbir__saturate16(int x) +{ + if ((unsigned int) x <= 65535) + return x; + + if (x < 0) + return 0; + + return 65535; +} +#endif + +static float stbir__srgb_uchar_to_linear_float[256] = { + 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, + 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, + 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, + 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, + 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, + 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, + 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, + 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, + 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, + 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, + 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, + 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, + 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, + 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, + 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, + 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, + 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, + 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, + 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, + 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, + 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, + 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, + 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, + 0.982251f, 0.991102f, 1.0f +}; + +static float stbir__srgb_to_linear(float f) +{ + if (f <= 0.04045f) + return f / 12.92f; + else + return (float)pow((f + 0.055f) / 1.055f, 2.4f); +} + +static float stbir__linear_to_srgb(float f) +{ + if (f <= 0.0031308f) + return f * 12.92f; + else + return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; +} + +#ifndef STBIR_NON_IEEE_FLOAT +// From https://gist.github.com/rygorous/2203834 + +typedef union +{ + stbir_uint32 u; + float f; +} stbir__FP32; + +static const stbir_uint32 fp32_to_srgb8_tab4[104] = { + 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, + 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, + 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, + 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, + 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, + 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, + 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, + 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, + 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, + 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, + 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, + 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, + 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float in) +{ + static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps + static const stbir__FP32 minval = { (127-13) << 23 }; + stbir_uint32 tab,bias,scale,t; + stbir__FP32 f; + + // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. + // The tests are carefully written so that NaNs map to 0, same as in the reference + // implementation. + if (!(in > minval.f)) // written this way to catch NaNs + in = minval.f; + if (in > almostone.f) + in = almostone.f; + + // Do the table lookup and unpack bias, scale + f.f = in; + tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; + bias = (tab >> 16) << 9; + scale = tab & 0xffff; + + // Grab next-highest mantissa bits and perform linear interpolation + t = (f.u >> 12) & 0xff; + return (unsigned char) ((bias + scale*t) >> 16); +} + +#else +// sRGB transition values, scaled by 1<<28 +static int stbir__srgb_offset_to_linear_scaled[256] = +{ + 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, + 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, + 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, + 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, + 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, + 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, + 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, + 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, + 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, + 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, + 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, + 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, + 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, + 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, + 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, + 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, + 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, + 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, + 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, + 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, + 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, + 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, + 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, + 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, + 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, + 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, + 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, + 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, + 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, + 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, + 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, + 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float f) +{ + int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp + int v = 0; + int i; + + // Refine the guess with a short binary search. + i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + + return (stbir_uint8) v; +} +#endif + +static float stbir__filter_trapezoid(float x, float scale) +{ + float halfscale = scale / 2; + float t = 0.5f + halfscale; + STBIR_ASSERT(scale <= 1); + + x = (float)fabs(x); + + if (x >= t) + return 0; + else + { + float r = 0.5f - halfscale; + if (x <= r) + return 1; + else + return (t - x) / scale; + } +} + +static float stbir__support_trapezoid(float scale) +{ + STBIR_ASSERT(scale <= 1); + return 0.5f + scale / 2; +} + +static float stbir__filter_triangle(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x <= 1.0f) + return 1 - x; + else + return 0; +} + +static float stbir__filter_cubic(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (4 + x*x*(3*x - 6))/6; + else if (x < 2.0f) + return (8 + x*(-12 + x*(6 - x)))/6; + + return (0.0f); +} + +static float stbir__filter_catmullrom(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return 1 - x*x*(2.5f - 1.5f*x); + else if (x < 2.0f) + return 2 - x*(4 + x*(0.5f*x - 2.5f)); + + return (0.0f); +} + +static float stbir__filter_mitchell(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (16 + x*x*(21 * x - 36))/18; + else if (x < 2.0f) + return (32 + x*(-60 + x*(36 - 7*x)))/18; + + return (0.0f); +} + +static float stbir__support_zero(float s) +{ + STBIR__UNUSED_PARAM(s); + return 0; +} + +static float stbir__support_one(float s) +{ + STBIR__UNUSED_PARAM(s); + return 1; +} + +static float stbir__support_two(float s) +{ + STBIR__UNUSED_PARAM(s); + return 2; +} + +static stbir__filter_info stbir__filter_info_table[] = { + { NULL, stbir__support_zero }, + { stbir__filter_trapezoid, stbir__support_trapezoid }, + { stbir__filter_triangle, stbir__support_one }, + { stbir__filter_cubic, stbir__support_two }, + { stbir__filter_catmullrom, stbir__support_two }, + { stbir__filter_mitchell, stbir__support_two }, +}; + +stbir__inline static int stbir__use_upsampling(float ratio) +{ + return ratio > 1; +} + +stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->horizontal_scale); +} + +stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->vertical_scale); +} + +// This is the maximum number of input samples that can affect an output sample +// with the given filter +static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) +{ + STBIR_ASSERT(filter != 0); + STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); +} + +// This is how much to expand buffers to account for filters seeking outside +// the image boundaries. +static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) +{ + return stbir__get_filter_pixel_width(filter, scale) / 2; +} + +static int stbir__get_coefficient_width(stbir_filter filter, float scale) +{ + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); +} + +static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) +{ + if (stbir__use_upsampling(scale)) + return output_size; + else + return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); +} + +static int stbir__get_total_horizontal_coefficients(stbir__info* info) +{ + return info->horizontal_num_contributors + * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); +} + +static int stbir__get_total_vertical_coefficients(stbir__info* info) +{ + return info->vertical_num_contributors + * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); +} + +static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) +{ + return &contributors[n]; +} + +// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, +// if you change it here change it there too. +static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) +{ + int width = stbir__get_coefficient_width(filter, scale); + return &coefficients[width*n + c]; +} + +static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) +{ + switch (edge) + { + case STBIR_EDGE_ZERO: + return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later + + case STBIR_EDGE_CLAMP: + if (n < 0) + return 0; + + if (n >= max) + return max - 1; + + return n; // NOTREACHED + + case STBIR_EDGE_REFLECT: + { + if (n < 0) + { + if (n < max) + return -n; + else + return max - 1; + } + + if (n >= max) + { + int max2 = max * 2; + if (n >= max2) + return 0; + else + return max2 - n - 1; + } + + return n; // NOTREACHED + } + + case STBIR_EDGE_WRAP: + if (n >= 0) + return (n % max); + else + { + int m = (-n) % max; + + if (m != 0) + m = max - m; + + return (m); + } + // NOTREACHED + + default: + STBIR_ASSERT(!"Unimplemented edge type"); + return 0; + } +} + +stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) +{ + // avoid per-pixel switch + if (n >= 0 && n < max) + return n; + return stbir__edge_wrap_slow(edge, n, max); +} + +// What input pixels contribute to this output pixel? +static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) +{ + float out_pixel_center = (float)n + 0.5f; + float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; + float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; + + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; + + *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; + *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); + *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); +} + +// What output pixels does this input pixel contribute to? +static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) +{ + float in_pixel_center = (float)n + 0.5f; + float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; + float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; + + float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; + float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; + + *out_center_of_in = in_pixel_center * scale_ratio - out_shift; + *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); + *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); +} + +static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + float total_filter = 0; + float filter_scale; + + STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = in_first_pixel; + contributor->n1 = in_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + { + float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); + + // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) + if (i == 0 && !coefficient_group[i]) + { + contributor->n0 = ++in_first_pixel; + i--; + continue; + } + + total_filter += coefficient_group[i]; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); + + STBIR_ASSERT(total_filter > 0.9); + STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. + + // Make sure the sum of all coefficients is 1. + filter_scale = 1 / total_filter; + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + coefficient_group[i] *= filter_scale; + + for (i = in_last_pixel - in_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + + STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = out_first_pixel; + contributor->n1 = out_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= out_last_pixel - out_first_pixel; i++) + { + float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; + float x = out_pixel_center - out_center_of_in; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); + + for (i = out_last_pixel - out_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) +{ + int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); + int i, j; + int skip; + + for (i = 0; i < output_size; i++) + { + float scale; + float total = 0; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + { + float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); + total += coefficient; + } + else if (i < contributors[j].n0) + break; + } + + STBIR_ASSERT(total > 0.9f); + STBIR_ASSERT(total < 1.1f); + + scale = 1 / total; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; + else if (i < contributors[j].n0) + break; + } + } + + // Optimize: Skip zero coefficients and contributions outside of image bounds. + // Do this after normalizing because normalization depends on the n0/n1 values. + for (j = 0; j < num_contributors; j++) + { + int range, max, width; + + skip = 0; + while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) + skip++; + + contributors[j].n0 += skip; + + while (contributors[j].n0 < 0) + { + contributors[j].n0++; + skip++; + } + + range = contributors[j].n1 - contributors[j].n0 + 1; + max = stbir__min(num_coefficients, range); + + width = stbir__get_coefficient_width(filter, scale_ratio); + for (i = 0; i < max; i++) + { + if (i + skip >= width) + break; + + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); + } + + continue; + } + + // Using min to avoid writing into invalid pixels. + for (i = 0; i < num_contributors; i++) + contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); +} + +// Each scan line uses the same kernel values so we should calculate the kernel +// values once and then we can use them for every scan line. +static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) +{ + int n; + int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + + if (stbir__use_upsampling(scale_ratio)) + { + float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; + + // Looping through out pixels + for (n = 0; n < total_contributors; n++) + { + float in_center_of_out; // Center of the current out pixel in the in pixel space + int in_first_pixel, in_last_pixel; + + stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); + + stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + } + else + { + float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; + + // Looping through in pixels + for (n = 0; n < total_contributors; n++) + { + float out_center_of_in; // Center of the current out pixel in the in pixel space + int out_first_pixel, out_last_pixel; + int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); + + stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); + + stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + + stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); + } +} + +static float* stbir__get_decode_buffer(stbir__info* stbir_info) +{ + // The 0 index of the decode buffer starts after the margin. This makes + // it okay to use negative indexes on the decode buffer. + return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; +} + +#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace)) + +static void stbir__decode_scanline(stbir__info* stbir_info, int n) +{ + int c; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int input_w = stbir_info->input_w; + size_t input_stride_bytes = stbir_info->input_stride_bytes; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir_edge edge_horizontal = stbir_info->edge_horizontal; + stbir_edge edge_vertical = stbir_info->edge_vertical; + size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; + const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; + int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; + int decode = STBIR__DECODE(type, colorspace); + + int x = -stbir_info->horizontal_filter_pixel_margin; + + // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, + // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO + if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) + { + for (; x < max_x; x++) + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + return; + } + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; + } + + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) + { + int decode_pixel_index = x * channels; + + // If the alpha value is 0 it will clobber the color values. Make sure it's not. + float alpha = decode_buffer[decode_pixel_index + alpha_channel]; +#ifndef STBIR_NO_ALPHA_EPSILON + if (stbir_info->type != STBIR_TYPE_FLOAT) { + alpha += STBIR_ALPHA_EPSILON; + decode_buffer[decode_pixel_index + alpha_channel] = alpha; + } +#endif + for (c = 0; c < channels; c++) + { + if (c == alpha_channel) + continue; + + decode_buffer[decode_pixel_index + c] *= alpha; + } + } + } + + if (edge_horizontal == STBIR_EDGE_ZERO) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + for (x = input_w; x < max_x; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + } +} + +static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) +{ + return &ring_buffer[index * ring_buffer_length]; +} + +static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n) +{ + int ring_buffer_index; + float* ring_buffer; + + stbir_info->ring_buffer_last_scanline = n; + + if (stbir_info->ring_buffer_begin_index < 0) + { + ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; + stbir_info->ring_buffer_first_scanline = n; + } + else + { + ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; + STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); + } + + ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); + memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); + + return ring_buffer; +} + + +static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int output_w = stbir_info->output_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + + for (x = 0; x < output_w; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int out_pixel_index = x * channels; + int coefficient_group = coefficient_width * x; + int coefficient_counter = 0; + + STBIR_ASSERT(n1 >= n0); + STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + int c; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int input_w = stbir_info->input_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; + int max_x = input_w + filter_pixel_margin * 2; + + STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); + + switch (channels) { + case 1: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 1; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + } + break; + + case 2: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 2; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + } + break; + + case 3: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 3; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + } + break; + + case 4: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 4; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + } + break; + + default: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * channels; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int c; + int out_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + } + break; + } +} + +static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + // Now resample it into the ring buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + else + stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + + // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. +} + +static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); + + // Now resample it into the horizontal buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); + else + stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); + + // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. +} + +// Get the specified scan line from the ring buffer. +static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) +{ + int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; + return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); +} + + +static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) +{ + int x; + int n; + int num_nonalpha; + stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + float alpha = encode_buffer[pixel_index + alpha_channel]; + float reciprocal_alpha = alpha ? 1.0f / alpha : 0; + + // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb + for (n = 0; n < channels; n++) + if (n != alpha_channel) + encode_buffer[pixel_index + n] *= reciprocal_alpha; + + // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. + // Because we only add it for integer types, it will automatically be discarded on integer + // conversion, so we don't need to subtract it back out (which would be problematic for + // numeric precision reasons). + } + } + + // build a table of all channels that need colorspace correction, so + // we don't perform colorspace correction on channels that don't need it. + for (x = 0, num_nonalpha = 0; x < channels; ++x) + { + if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + { + nonalpha[num_nonalpha++] = (stbir_uint16)x; + } + } + + #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) + #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) + + #ifdef STBIR__SATURATE_INT + #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) + #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) + #else + #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) + #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) + #endif + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); + } + + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((float*)output_buffer)[index] = encode_buffer[index]; + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel]; + } + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } +} + +static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + void* output_data = stbir_info->output_data; + float* encode_buffer = stbir_info->encode_buffer; + int decode = STBIR__DECODE(type, colorspace); + int coefficient_width = stbir_info->vertical_coefficient_width; + int coefficient_counter; + int contributor = n; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + int n0,n1, output_row_start; + int coefficient_group = coefficient_width * contributor; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + output_row_start = n * stbir_info->output_stride_bytes; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + memset(encode_buffer, 0, output_w * sizeof(float) * channels); + + // I tried reblocking this for better cache usage of encode_buffer + // (using x_outer, k, x_inner), but it lost speed. -- stb + + coefficient_counter = 0; + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 1; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + } + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 2; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + } + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 3; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + } + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 4; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; + } + } + break; + default: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * channels; + int c; + for (c = 0; c < channels; c++) + encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; + } + } + break; + } + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); +} + +static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + float* horizontal_buffer = stbir_info->horizontal_buffer; + int coefficient_width = stbir_info->vertical_coefficient_width; + int contributor = n + stbir_info->vertical_filter_pixel_margin; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + int n0,n1; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (k = n0; k <= n1; k++) + { + int coefficient_index = k - n0; + int coefficient_group = coefficient_width * contributor; + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + + switch (channels) { + case 1: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 1; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 2; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 3; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 4; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * channels; + + int c; + for (c = 0; c < channels; c++) + ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__buffer_loop_upsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + for (y = 0; y < stbir_info->output_h; y++) + { + float in_center_of_out = 0; // Center of the current out scanline in the in scanline space + int in_first_scanline = 0, in_last_scanline = 0; + + stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); + + STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (in_first_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); + + while (in_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now all buffers should be ready to write a row of vertical sampling. + stbir__resample_vertical_upsample(stbir_info, y); + + STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); + } +} + +static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline) +{ + int output_stride_bytes = stbir_info->output_stride_bytes; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int output_w = stbir_info->output_w; + void* output_data = stbir_info->output_data; + int decode = STBIR__DECODE(type, colorspace); + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) + { + int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; + float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); + STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); + } + + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } +} + +static void stbir__buffer_loop_downsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + int output_h = stbir_info->output_h; + float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; + int pixel_margin = stbir_info->vertical_filter_pixel_margin; + int max_y = stbir_info->input_h + pixel_margin; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (y = -pixel_margin; y < max_y; y++) + { + float out_center_of_in; // Center of the current out scanline in the in scanline space + int out_first_scanline, out_last_scanline; + + stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); + + STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (out_last_scanline < 0 || out_first_scanline >= output_h) + continue; + + stbir__empty_ring_buffer(stbir_info, out_first_scanline); + + stbir__decode_and_resample_downsample(stbir_info, y); + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); + + while (out_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now the horizontal buffer is ready to write to all ring buffer rows. + stbir__resample_vertical_downsample(stbir_info, y); + } + + stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); +} + +static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) +{ + info->input_w = input_w; + info->input_h = input_h; + info->output_w = output_w; + info->output_h = output_h; + info->channels = channels; +} + +static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform) +{ + info->s0 = s0; + info->t0 = t0; + info->s1 = s1; + info->t1 = t1; + + if (transform) + { + info->horizontal_scale = transform[0]; + info->vertical_scale = transform[1]; + info->horizontal_shift = transform[2]; + info->vertical_shift = transform[3]; + } + else + { + info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); + info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); + + info->horizontal_shift = s0 * info->output_w / (s1 - s0); + info->vertical_shift = t0 * info->output_h / (t1 - t0); + } +} + +static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter) +{ + if (h_filter == 0) + h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + if (v_filter == 0) + v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + info->horizontal_filter = h_filter; + info->vertical_filter = v_filter; +} + +static stbir_uint32 stbir__calculate_memory(stbir__info *info) +{ + int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); + + info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); + info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); + + // One extra entry because floating point precision problems sometimes cause an extra to be necessary. + info->ring_buffer_num_entries = filter_height + 1; + + info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); + info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); + info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); + info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); + info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); + info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); + info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); + info->encode_buffer_size = info->output_w * info->channels * sizeof(float); + + STBIR_ASSERT(info->horizontal_filter != 0); + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + STBIR_ASSERT(info->vertical_filter != 0); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + + if (stbir__use_height_upsampling(info)) + // The horizontal buffer is for when we're downsampling the height and we + // can't output the result of sampling the decode buffer directly into the + // ring buffers. + info->horizontal_buffer_size = 0; + else + // The encode buffer is to retain precision in the height upsampling method + // and isn't used when height downsampling. + info->encode_buffer_size = 0; + + return info->horizontal_contributors_size + info->horizontal_coefficients_size + + info->vertical_contributors_size + info->vertical_coefficients_size + + info->decode_buffer_size + info->horizontal_buffer_size + + info->ring_buffer_size + info->encode_buffer_size; +} + +static int stbir__resize_allocated(stbir__info *info, + const void* input_data, int input_stride_in_bytes, + void* output_data, int output_stride_in_bytes, + int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, + void* tempmem, size_t tempmem_size_in_bytes) +{ + size_t memory_required = stbir__calculate_memory(info); + + int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; + int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; + +#ifdef STBIR_DEBUG_OVERWRITE_TEST +#define OVERWRITE_ARRAY_SIZE 8 + unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; + + size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; + memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); +#endif + + STBIR_ASSERT(info->channels >= 0); + STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); + + if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) + return 0; + + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + + if (alpha_channel < 0) + flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; + + if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { + STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); + } + + if (alpha_channel >= info->channels) + return 0; + + STBIR_ASSERT(tempmem); + + if (!tempmem) + return 0; + + STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); + + if (tempmem_size_in_bytes < memory_required) + return 0; + + memset(tempmem, 0, tempmem_size_in_bytes); + + info->input_data = input_data; + info->input_stride_bytes = width_stride_input; + + info->output_data = output_data; + info->output_stride_bytes = width_stride_output; + + info->alpha_channel = alpha_channel; + info->flags = flags; + info->type = type; + info->edge_horizontal = edge_horizontal; + info->edge_vertical = edge_vertical; + info->colorspace = colorspace; + + info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); + + info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); + info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; + +#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) + + info->horizontal_contributors = (stbir__contributors *) tempmem; + info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); + info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); + info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); + info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); + + if (stbir__use_height_upsampling(info)) + { + info->horizontal_buffer = NULL; + info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + else + { + info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); + info->encode_buffer = NULL; + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + +#undef STBIR__NEXT_MEMPTR + + // This signals that the ring buffer is empty + info->ring_buffer_begin_index = -1; + + stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); + stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); + + STBIR_PROGRESS_REPORT(0); + + if (stbir__use_height_upsampling(info)) + stbir__buffer_loop_upsample(info); + else + stbir__buffer_loop_downsample(info); + + STBIR_PROGRESS_REPORT(1); + +#ifdef STBIR_DEBUG_OVERWRITE_TEST + STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); +#endif + + return 1; +} + + +static int stbir__resize_arbitrary( + void *alloc_context, + const void* input_data, int input_w, int input_h, int input_stride_in_bytes, + void* output_data, int output_w, int output_h, int output_stride_in_bytes, + float s0, float t0, float s1, float t1, float *transform, + int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_filter h_filter, stbir_filter v_filter, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) +{ + stbir__info info; + int result; + size_t memory_required; + void* extra_memory; + + stbir__setup(&info, input_w, input_h, output_w, output_h, channels); + stbir__calculate_transform(&info, s0,t0,s1,t1,transform); + stbir__choose_filter(&info, h_filter, v_filter); + memory_required = stbir__calculate_memory(&info); + extra_memory = STBIR_MALLOC(memory_required, alloc_context); + + if (!extra_memory) + return 0; + + result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, + output_data, output_stride_in_bytes, + alpha_channel, flags, type, + edge_horizontal, edge_vertical, + colorspace, extra_memory, memory_required); + + STBIR_FREE(extra_memory, alloc_context); + + return result; +} + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset) +{ + float transform[4]; + transform[0] = x_scale; + transform[1] = y_scale; + transform[2] = x_offset; + transform[3] = y_offset; + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +#endif // STB_IMAGE_RESIZE_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/raylib/external/stb_image_resize2.h b/raylib/external/stb_image_resize2.h deleted file mode 100644 index 2f26274..0000000 --- a/raylib/external/stb_image_resize2.h +++ /dev/null @@ -1,10601 +0,0 @@ -/* stb_image_resize2 - v2.12 - public domain image resizing - - by Jeff Roberts (v2) and Jorge L Rodriguez - http://github.com/nothings/stb - - Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only - scaling and translation is supported, no rotations or shears. - - COMPILING & LINKING - In one C/C++ file that #includes this file, do this: - #define STB_IMAGE_RESIZE_IMPLEMENTATION - before the #include. That will create the implementation in that file. - - EASY API CALLS: - Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation, clamps to edge. - - stbir_resize_uint8_srgb( input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - pixel_layout_enum ) - - stbir_resize_uint8_linear( input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - pixel_layout_enum ) - - stbir_resize_float_linear( input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - pixel_layout_enum ) - - If you pass NULL or zero for the output_pixels, we will allocate the output buffer - for you and return it from the function (free with free() or STBIR_FREE). - As a special case, XX_stride_in_bytes of 0 means packed continuously in memory. - - API LEVELS - There are three levels of API - easy-to-use, medium-complexity and extended-complexity. - - See the "header file" section of the source for API documentation. - - ADDITIONAL DOCUMENTATION - - MEMORY ALLOCATION - By default, we use malloc and free for memory allocation. To override the - memory allocation, before the implementation #include, add a: - - #define STBIR_MALLOC(size,user_data) ... - #define STBIR_FREE(ptr,user_data) ... - - Each resize makes exactly one call to malloc/free (unless you use the - extended API where you can do one allocation for many resizes). Under - address sanitizer, we do separate allocations to find overread/writes. - - PERFORMANCE - This library was written with an emphasis on performance. When testing - stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with - STBIR_TYPE_UINT8 pixels and CLAMPed edges (which is what many other resize - libs do by default). Also, make sure SIMD is turned on of course (default - for 64-bit targets). Avoid WRAP edge mode if you want the fastest speed. - - This library also comes with profiling built-in. If you define STBIR_PROFILE, - you can use the advanced API and get low-level profiling information by - calling stbir_resize_extended_profile_info() or stbir_resize_split_profile_info() - after a resize. - - SIMD - Most of the routines have optimized SSE2, AVX, NEON and WASM versions. - - On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and - ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or - STBIR_NEON. For AVX and AVX2, we auto-select it by detecting the /arch:AVX - or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2 - support on by defining STBIR_SSE2, STBIR_AVX or STBIR_AVX2. - - On Linux, SSE2 and Neon is on by default for 64-bit x64 or ARM64. For 32-bit, - we select x86 SIMD mode by whether you have -msse2, -mavx or -mavx2 enabled - on the command line. For 32-bit ARM, you must pass -mfpu=neon-vfpv4 for both - clang and GCC, but GCC also requires an additional -mfp16-format=ieee to - automatically enable NEON. - - On x86 platforms, you can also define STBIR_FP16C to turn on FP16C instructions - for converting back and forth to half-floats. This is autoselected when we - are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses - the built-in half float hardware NEON instructions. - - You can also tell us to use multiply-add instructions with STBIR_USE_FMA. - Because x86 doesn't always have fma, we turn it off by default to maintain - determinism across all platforms. If you don't care about non-FMA determinism - and are willing to restrict yourself to more recent x86 CPUs (around the AVX - timeframe), then fma will give you around a 15% speedup. - - You can force off SIMD in all cases by defining STBIR_NO_SIMD. You can turn - off AVX or AVX2 specifically with STBIR_NO_AVX or STBIR_NO_AVX2. AVX is 10% - to 40% faster, and AVX2 is generally another 12%. - - ALPHA CHANNEL - Most of the resizing functions provide the ability to control how the alpha - channel of an image is processed. - - When alpha represents transparency, it is important that when combining - colors with filtering, the pixels should not be treated equally; they - should use a weighted average based on their alpha values. For example, - if a pixel is 1% opaque bright green and another pixel is 99% opaque - black and you average them, the average will be 50% opaque, but the - unweighted average and will be a middling green color, while the weighted - average will be nearly black. This means the unweighted version introduced - green energy that didn't exist in the source image. - - (If you want to know why this makes sense, you can work out the math for - the following: consider what happens if you alpha composite a source image - over a fixed color and then average the output, vs. if you average the - source image pixels and then composite that over the same fixed color. - Only the weighted average produces the same result as the ground truth - composite-then-average result.) - - Therefore, it is in general best to "alpha weight" the pixels when applying - filters to them. This essentially means multiplying the colors by the alpha - values before combining them, and then dividing by the alpha value at the - end. - - The computer graphics industry introduced a technique called "premultiplied - alpha" or "associated alpha" in which image colors are stored in image files - already multiplied by their alpha. This saves some math when compositing, - and also avoids the need to divide by the alpha at the end (which is quite - inefficient). However, while premultiplied alpha is common in the movie CGI - industry, it is not commonplace in other industries like videogames, and most - consumer file formats are generally expected to contain not-premultiplied - colors. For example, Photoshop saves PNG files "unpremultiplied", and web - browsers like Chrome and Firefox expect PNG images to be unpremultiplied. - - Note that there are three possibilities that might describe your image - and resize expectation: - - 1. images are not premultiplied, alpha weighting is desired - 2. images are not premultiplied, alpha weighting is not desired - 3. images are premultiplied - - Both case #2 and case #3 require the exact same math: no alpha weighting - should be applied or removed. Only case 1 requires extra math operations; - the other two cases can be handled identically. - - stb_image_resize expects case #1 by default, applying alpha weighting to - images, expecting the input images to be unpremultiplied. This is what the - COLOR+ALPHA buffer types tell the resizer to do. - - When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB, - STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are - non-premultiplied. In these cases, the resizer will alpha weight the colors - (effectively creating the premultiplied image), do the filtering, and then - convert back to non-premult on exit. - - When you use the pixel layouts STBIR_RGBA_PM, STBIR_RGBA_PM, STBIR_RGBA_PM, - STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels - ARE premultiplied. In this case, the resizer doesn't have to do the - premultipling - it can filter directly on the input. This about twice as - fast as the non-premultiplied case, so it's the right option if your data is - already setup correctly. - - When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are - telling us that there is no channel that represents transparency; it may be - RGB and some unrelated fourth channel that has been stored in the alpha - channel, but it is actually not alpha. No special processing will be - performed. - - The difference between the generic 4 or 2 channel layouts, and the - specialized _PM versions is with the _PM versions you are telling us that - the data *is* alpha, just don't premultiply it. That's important when - using SRGB pixel formats, we need to know where the alpha is, because - it is converted linearly (rather than with the SRGB converters). - - Because alpha weighting produces the same effect as premultiplying, you - even have the option with non-premultiplied inputs to let the resizer - produce a premultiplied output. Because the intially computed alpha-weighted - output image is effectively premultiplied, this is actually more performant - than the normal path which un-premultiplies the output image as a final step. - - Finally, when converting both in and out of non-premulitplied space (for - example, when using STBIR_RGBA), we go to somewhat heroic measures to - ensure that areas with zero alpha value pixels get something reasonable - in the RGB values. If you don't care about the RGB values of zero alpha - pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality() - function - this runs a premultiplied resize about 25% faster. That said, - when you really care about speed, using premultiplied pixels for both in - and out (STBIR_RGBA_PM, etc) much faster than both of these premultiplied - options. - - PIXEL LAYOUT CONVERSION - The resizer can convert from some pixel layouts to others. When using the - stbir_set_pixel_layouts(), you can, for example, specify STBIR_RGBA - on input, and STBIR_ARGB on output, and it will re-organize the channels - during the resize. Currently, you can only convert between two pixel - layouts with the same number of channels. - - DETERMINISM - We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc). - This requires compiling with fast-math off (using at least /fp:precise). - Also, you must turn off fp-contracting (which turns mult+adds into fmas)! - We attempt to do this with pragmas, but with Clang, you usually want to add - -ffp-contract=off to the command line as well. - - For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is, - if the scalar x87 unit gets used at all, we immediately lose determinism. - On Microsoft Visual Studio 2008 and earlier, from what we can tell there is - no way to be deterministic in 32-bit x86 (some x87 always leaks in, even - with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and - -fpmath=sse. - - Note that we will not be deterministic with float data containing NaNs - - the NaNs will propagate differently on different SIMD and platforms. - - If you turn on STBIR_USE_FMA, then we will be deterministic with other - fma targets, but we will differ from non-fma targets (this is unavoidable, - because a fma isn't simply an add with a mult - it also introduces a - rounding difference compared to non-fma instruction sequences. - - FLOAT PIXEL FORMAT RANGE - Any range of values can be used for the non-alpha float data that you pass - in (0 to 1, -1 to 1, whatever). However, if you are inputting float values - but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we - scale back properly. The alpha channel must also be 0 to 1 for any format - that does premultiplication prior to resizing. - - Note also that with float output, using filters with negative lobes, the - output filtered values might go slightly out of range. You can define - STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range - to clamp to on output, if that's important. - - MAX/MIN SCALE FACTORS - The input pixel resolutions are in integers, and we do the internal pointer - resolution in size_t sized integers. However, the scale ratio from input - resolution to output resolution is calculated in float form. This means - the effective possible scale ratio is limited to 24 bits (or 16 million - to 1). As you get close to the size of the float resolution (again, 16 - million pixels wide or high), you might start seeing float inaccuracy - issues in general in the pipeline. If you have to do extreme resizes, - you can usually do this is multiple stages (using float intermediate - buffers). - - FLIPPED IMAGES - Stride is just the delta from one scanline to the next. This means you can - use a negative stride to handle inverted images (point to the final - scanline and use a negative stride). You can invert the input or output, - using negative strides. - - DEFAULT FILTERS - For functions which don't provide explicit control over what filters to - use, you can change the compile-time defaults with: - - #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something - #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something - - See stbir_filter in the header-file section for the list of filters. - - NEW FILTERS - A number of 1D filter kernels are supplied. For a list of supported - filters, see the stbir_filter enum. You can install your own filters by - using the stbir_set_filter_callbacks function. - - PROGRESS - For interactive use with slow resize operations, you can use the the - scanline callbacks in the extended API. It would have to be a *very* large - image resample to need progress though - we're very fast. - - CEIL and FLOOR - In scalar mode, the only functions we use from math.h are ceilf and floorf, - but if you have your own versions, you can define the STBIR_CEILF(v) and - STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use - our own versions. - - ASSERT - Define STBIR_ASSERT(boolval) to override assert() and not use assert.h - - PORTING FROM VERSION 1 - The API has changed. You can continue to use the old version of stb_image_resize.h, - which is available in the "deprecated/" directory. - - If you're using the old simple-to-use API, porting is straightforward. - (For more advanced APIs, read the documentation.) - - stbir_resize_uint8(): - - call `stbir_resize_uint8_linear`, cast channel count to `stbir_pixel_layout` - - stbir_resize_float(): - - call `stbir_resize_float_linear`, cast channel count to `stbir_pixel_layout` - - stbir_resize_uint8_srgb(): - - function name is unchanged - - cast channel count to `stbir_pixel_layout` - - above is sufficient unless your image has alpha and it's not RGBA/BGRA - - in that case, follow the below instructions for stbir_resize_uint8_srgb_edgemode - - stbir_resize_uint8_srgb_edgemode() - - switch to the "medium complexity" API - - stbir_resize(), very similar API but a few more parameters: - - pixel_layout: cast channel count to `stbir_pixel_layout` - - data_type: STBIR_TYPE_UINT8_SRGB - - edge: unchanged (STBIR_EDGE_WRAP, etc.) - - filter: STBIR_FILTER_DEFAULT - - which channel is alpha is specified in stbir_pixel_layout, see enum for details - - FUTURE TODOS - * For polyphase integral filters, we just memcpy the coeffs to dupe - them, but we should indirect and use the same coeff memory. - * Add pixel layout conversions for sensible different channel counts - (maybe, 1->3/4, 3->4, 4->1, 3->1). - * For SIMD encode and decode scanline routines, do any pre-aligning - for bad input/output buffer alignments and pitch? - * For very wide scanlines, we should we do vertical strips to stay within - L2 cache. Maybe do chunks of 1K pixels at a time. There would be - some pixel reconversion, but probably dwarfed by things falling out - of cache. Probably also something possible with alternating between - scattering and gathering at high resize scales? - * Rewrite the coefficient generator to do many at once. - * AVX-512 vertical kernels - worried about downclocking here. - * Convert the reincludes to macros when we know they aren't changing. - * Experiment with pivoting the horizontal and always using the - vertical filters (which are faster, but perhaps not enough to overcome - the pivot cost and the extra memory touches). Need to buffer the whole - image so have to balance memory use. - * Most of our code is internally function pointers, should we compile - all the SIMD stuff always and dynamically dispatch? - - CONTRIBUTORS - Jeff Roberts: 2.0 implementation, optimizations, SIMD - Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer - Fabian Giesen: half float and srgb converters - Sean Barrett: API design, optimizations - Jorge L Rodriguez: Original 1.0 implementation - Aras Pranckevicius: bugfixes - Nathan Reed: warning fixes for 1.0 - - REVISIONS - 2.12 (2024-10-18) fix incorrect use of user_data with STBIR_FREE - 2.11 (2024-09-08) fix harmless asan warnings in 2-channel and 3-channel mode - with AVX-2, fix some weird scaling edge conditions with - point sample mode. - 2.10 (2024-07-27) fix the defines GCC and mingw for loop unroll control, - fix MSVC 32-bit arm half float routines. - 2.09 (2024-06-19) fix the defines for 32-bit ARM GCC builds (was selecting - hardware half floats). - 2.08 (2024-06-10) fix for RGB->BGR three channel flips and add SIMD (thanks - to Ryan Salsbury), fix for sub-rect resizes, use the - pragmas to control unrolling when they are available. - 2.07 (2024-05-24) fix for slow final split during threaded conversions of very - wide scanlines when downsampling (caused by extra input - converting), fix for wide scanline resamples with many - splits (int overflow), fix GCC warning. - 2.06 (2024-02-10) fix for identical width/height 3x or more down-scaling - undersampling a single row on rare resize ratios (about 1%). - 2.05 (2024-02-07) fix for 2 pixel to 1 pixel resizes with wrap (thanks Aras), - fix for output callback (thanks Julien Koenen). - 2.04 (2023-11-17) fix for rare AVX bug, shadowed symbol (thanks Nikola Smiljanic). - 2.03 (2023-11-01) ASAN and TSAN warnings fixed, minor tweaks. - 2.00 (2023-10-10) mostly new source: new api, optimizations, simd, vertical-first, etc - 2x-5x faster without simd, 4x-12x faster with simd, - in some cases, 20x to 40x faster esp resizing large to very small. - 0.96 (2019-03-04) fixed warnings - 0.95 (2017-07-23) fixed warnings - 0.94 (2017-03-18) fixed warnings - 0.93 (2017-03-03) fixed bug with certain combinations of heights - 0.92 (2017-01-02) fix integer overflow on large (>2GB) images - 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions - 0.90 (2014-09-17) first released version - - LICENSE - See end of file for license information. -*/ - -#if !defined(STB_IMAGE_RESIZE_DO_HORIZONTALS) && !defined(STB_IMAGE_RESIZE_DO_VERTICALS) && !defined(STB_IMAGE_RESIZE_DO_CODERS) // for internal re-includes - -#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE2_H -#define STBIR_INCLUDE_STB_IMAGE_RESIZE2_H - -#include -#ifdef _MSC_VER -typedef unsigned char stbir_uint8; -typedef unsigned short stbir_uint16; -typedef unsigned int stbir_uint32; -typedef unsigned __int64 stbir_uint64; -#else -#include -typedef uint8_t stbir_uint8; -typedef uint16_t stbir_uint16; -typedef uint32_t stbir_uint32; -typedef uint64_t stbir_uint64; -#endif - -#ifdef _M_IX86_FP -#if ( _M_IX86_FP >= 1 ) -#ifndef STBIR_SSE -#define STBIR_SSE -#endif -#endif -#endif - -#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2) - #ifndef STBIR_SSE2 - #define STBIR_SSE2 - #endif - #if defined(__AVX__) || defined(STBIR_AVX2) - #ifndef STBIR_AVX - #ifndef STBIR_NO_AVX - #define STBIR_AVX - #endif - #endif - #endif - #if defined(__AVX2__) || defined(STBIR_AVX2) - #ifndef STBIR_NO_AVX2 - #ifndef STBIR_AVX2 - #define STBIR_AVX2 - #endif - #if defined( _MSC_VER ) && !defined(__clang__) - #ifndef STBIR_FP16C // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -m16c - #define STBIR_FP16C - #endif - #endif - #endif - #endif - #ifdef __F16C__ - #ifndef STBIR_FP16C // turn on FP16C instructions if the define is set (for clang and gcc) - #define STBIR_FP16C - #endif - #endif -#endif - -#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || ((__ARM_NEON_FP & 4) != 0) || defined(__ARM_NEON__) -#ifndef STBIR_NEON -#define STBIR_NEON -#endif -#endif - -#if defined(_M_ARM) || defined(__arm__) -#ifdef STBIR_USE_FMA -#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC -#endif -#endif - -#if defined(__wasm__) && defined(__wasm_simd128__) -#ifndef STBIR_WASM -#define STBIR_WASM -#endif -#endif - -#ifndef STBIRDEF -#ifdef STB_IMAGE_RESIZE_STATIC -#define STBIRDEF static -#else -#ifdef __cplusplus -#define STBIRDEF extern "C" -#else -#define STBIRDEF extern -#endif -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -//// start "header file" /////////////////////////////////////////////////// -// -// Easy-to-use API: -// -// * stride is the offset between successive rows of image data -// in memory, in bytes. specify 0 for packed continuously in memory -// * colorspace is linear or sRGB as specified by function name -// * Uses the default filters -// * Uses edge mode clamped -// * returned result is 1 for success or 0 in case of an error. - - -// stbir_pixel_layout specifies: -// number of channels -// order of channels -// whether color is premultiplied by alpha -// for back compatibility, you can cast the old channel count to an stbir_pixel_layout -typedef enum -{ - STBIR_1CHANNEL = 1, - STBIR_2CHANNEL = 2, - STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping) - STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping) - STBIR_4CHANNEL = 5, - - STBIR_RGBA = 4, // alpha formats, where alpha is NOT premultiplied into color channels - STBIR_BGRA = 6, - STBIR_ARGB = 7, - STBIR_ABGR = 8, - STBIR_RA = 9, - STBIR_AR = 10, - - STBIR_RGBA_PM = 11, // alpha formats, where alpha is premultiplied into color channels - STBIR_BGRA_PM = 12, - STBIR_ARGB_PM = 13, - STBIR_ABGR_PM = 14, - STBIR_RA_PM = 15, - STBIR_AR_PM = 16, - - STBIR_RGBA_NO_AW = 11, // alpha formats, where NO alpha weighting is applied at all! - STBIR_BGRA_NO_AW = 12, // these are just synonyms for the _PM flags (which also do - STBIR_ARGB_NO_AW = 13, // no alpha weighting). These names just make it more clear - STBIR_ABGR_NO_AW = 14, // for some folks). - STBIR_RA_NO_AW = 15, - STBIR_AR_NO_AW = 16, - -} stbir_pixel_layout; - -//=============================================================== -// Simple-complexity API -// -// If output_pixels is NULL (0), then we will allocate the buffer and return it to you. -//-------------------------------- - -STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_type ); - -STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_type ); - -STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_type ); -//=============================================================== - -//=============================================================== -// Medium-complexity API -// -// This extends the easy-to-use API as follows: -// -// * Can specify the datatype - U8, U8_SRGB, U16, FLOAT, HALF_FLOAT -// * Edge wrap can selected explicitly -// * Filter can be selected explicitly -//-------------------------------- - -typedef enum -{ - STBIR_EDGE_CLAMP = 0, - STBIR_EDGE_REFLECT = 1, - STBIR_EDGE_WRAP = 2, // this edge mode is slower and uses more memory - STBIR_EDGE_ZERO = 3, -} stbir_edge; - -typedef enum -{ - STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses - STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios - STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering - STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque - STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline - STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 - STBIR_FILTER_POINT_SAMPLE = 6, // Simple point sampling - STBIR_FILTER_OTHER = 7, // User callback specified -} stbir_filter; - -typedef enum -{ - STBIR_TYPE_UINT8 = 0, - STBIR_TYPE_UINT8_SRGB = 1, - STBIR_TYPE_UINT8_SRGB_ALPHA = 2, // alpha channel, when present, should also be SRGB (this is very unusual) - STBIR_TYPE_UINT16 = 3, - STBIR_TYPE_FLOAT = 4, - STBIR_TYPE_HALF_FLOAT = 5 -} stbir_datatype; - -// medium api -STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout, stbir_datatype data_type, - stbir_edge edge, stbir_filter filter ); -//=============================================================== - - - -//=============================================================== -// Extended-complexity API -// -// This API exposes all resize functionality. -// -// * Separate filter types for each axis -// * Separate edge modes for each axis -// * Separate input and output data types -// * Can specify regions with subpixel correctness -// * Can specify alpha flags -// * Can specify a memory callback -// * Can specify a callback data type for pixel input and output -// * Can be threaded for a single resize -// * Can be used to resize many frames without recalculating the sampler info -// -// Use this API as follows: -// 1) Call the stbir_resize_init function on a local STBIR_RESIZE structure -// 2) Call any of the stbir_set functions -// 3) Optionally call stbir_build_samplers() if you are going to resample multiple times -// with the same input and output dimensions (like resizing video frames) -// 4) Resample by calling stbir_resize_extended(). -// 5) Call stbir_free_samplers() if you called stbir_build_samplers() -//-------------------------------- - - -// Types: - -// INPUT CALLBACK: this callback is used for input scanlines -typedef void const * stbir_input_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ); - -// OUTPUT CALLBACK: this callback is used for output scanlines -typedef void stbir_output_callback( void const * output_ptr, int num_pixels, int y, void * context ); - -// callbacks for user installed filters -typedef float stbir__kernel_callback( float x, float scale, void * user_data ); // centered at zero -typedef float stbir__support_callback( float scale, void * user_data ); - -// internal structure with precomputed scaling -typedef struct stbir__info stbir__info; - -typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override functions to set these values for future compatibility -{ - void * user_data; - void const * input_pixels; - int input_w, input_h; - double input_s0, input_t0, input_s1, input_t1; - stbir_input_callback * input_cb; - void * output_pixels; - int output_w, output_h; - int output_subx, output_suby, output_subw, output_subh; - stbir_output_callback * output_cb; - int input_stride_in_bytes; - int output_stride_in_bytes; - int splits; - int fast_alpha; - int needs_rebuild; - int called_alloc; - stbir_pixel_layout input_pixel_layout_public; - stbir_pixel_layout output_pixel_layout_public; - stbir_datatype input_data_type; - stbir_datatype output_data_type; - stbir_filter horizontal_filter, vertical_filter; - stbir_edge horizontal_edge, vertical_edge; - stbir__kernel_callback * horizontal_filter_kernel; stbir__support_callback * horizontal_filter_support; - stbir__kernel_callback * vertical_filter_kernel; stbir__support_callback * vertical_filter_support; - stbir__info * samplers; -} STBIR_RESIZE; - -// extended complexity api - - -// First off, you must ALWAYS call stbir_resize_init on your resize structure before any of the other calls! -STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, - const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, // stride can be zero - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero - stbir_pixel_layout pixel_layout, stbir_datatype data_type ); - -//=============================================================== -// You can update these parameters any time after resize_init and there is no cost -//-------------------------------- - -STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ); -STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ); // no callbacks by default -STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ); // pass back STBIR_RESIZE* by default -STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes ); - -//=============================================================== - - -//=============================================================== -// If you call any of these functions, you will trigger a sampler rebuild! -//-------------------------------- - -STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout ); // sets new buffer layouts -STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ); // CLAMP by default - -STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ); // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default -STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support ); - -STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets both sub-regions (full regions by default) -STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ); // sets input sub-region (full region by default) -STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets output sub-region (full region by default) - -// when inputting AND outputting non-premultiplied alpha pixels, we use a slower but higher quality technique -// that fills the zero alpha pixel's RGB values with something plausible. If you don't care about areas of -// zero alpha, you can call this function to get about a 25% speed improvement for STBIR_RGBA to STBIR_RGBA -// types of resizes. -STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality ); -//=============================================================== - - -//=============================================================== -// You can call build_samplers to prebuild all the internal data we need to resample. -// Then, if you call resize_extended many times with the same resize, you only pay the -// cost once. -// If you do call build_samplers, you MUST call free_samplers eventually. -//-------------------------------- - -// This builds the samplers and does one allocation -STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ); - -// You MUST call this, if you call stbir_build_samplers or stbir_build_samplers_with_splits -STBIRDEF void stbir_free_samplers( STBIR_RESIZE * resize ); -//=============================================================== - - -// And this is the main function to perform the resize synchronously on one thread. -STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ); - - -//=============================================================== -// Use these functions for multithreading. -// 1) You call stbir_build_samplers_with_splits first on the main thread -// 2) Then stbir_resize_with_split on each thread -// 3) stbir_free_samplers when done on the main thread -//-------------------------------- - -// This will build samplers for threading. -// You can pass in the number of threads you'd like to use (try_splits). -// It returns the number of splits (threads) that you can call it with. -/// It might be less if the image resize can't be split up that many ways. - -STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits ); - -// This function does a split of the resizing (you call this fuction for each -// split, on multiple threads). A split is a piece of the output resize pixel space. - -// Note that you MUST call stbir_build_samplers_with_splits before stbir_resize_extended_split! - -// Usually, you will always call stbir_resize_split with split_start as the thread_index -// and "1" for the split_count. -// But, if you have a weird situation where you MIGHT want 8 threads, but sometimes -// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the -// split_count each time to turn in into a 4 thread resize. (This is unusual). - -STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count ); -//=============================================================== - - -//=============================================================== -// Pixel Callbacks info: -//-------------------------------- - -// The input callback is super flexible - it calls you with the input address -// (based on the stride and base pointer), it gives you an optional_output -// pointer that you can fill, or you can just return your own pointer into -// your own data. -// -// You can also do conversion from non-supported data types if necessary - in -// this case, you ignore the input_ptr and just use the x and y parameters to -// calculate your own input_ptr based on the size of each non-supported pixel. -// (Something like the third example below.) -// -// You can also install just an input or just an output callback by setting the -// callback that you don't want to zero. -// -// First example, progress: (getting a callback that you can monitor the progress): -// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) -// { -// percentage_done = y / input_height; -// return input_ptr; // use buffer from call -// } -// -// Next example, copying: (copy from some other buffer or stream): -// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) -// { -// CopyOrStreamData( optional_output, other_data_src, num_pixels * pixel_width_in_bytes ); -// return optional_output; // return the optional buffer that we filled -// } -// -// Third example, input another buffer without copying: (zero-copy from other buffer): -// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) -// { -// void * pixels = ( (char*) other_image_base ) + ( y * other_image_stride ) + ( x * other_pixel_width_in_bytes ); -// return pixels; // return pointer to your data without copying -// } -// -// -// The output callback is considerably simpler - it just calls you so that you can dump -// out each scanline. You could even directly copy out to disk if you have a simple format -// like TGA or BMP. You can also convert to other output types here if you want. -// -// Simple example: -// void const * my_output( void * output_ptr, int num_pixels, int y, void * context ) -// { -// percentage_done = y / output_height; -// fwrite( output_ptr, pixel_width_in_bytes, num_pixels, output_file ); -// } -//=============================================================== - - - - -//=============================================================== -// optional built-in profiling API -//-------------------------------- - -#ifdef STBIR_PROFILE - -typedef struct STBIR_PROFILE_INFO -{ - stbir_uint64 total_clocks; - - // how many clocks spent (of total_clocks) in the various resize routines, along with a string description - // there are "resize_count" number of zones - stbir_uint64 clocks[ 8 ]; - char const ** descriptions; - - // count of clocks and descriptions - stbir_uint32 count; -} STBIR_PROFILE_INFO; - -// use after calling stbir_resize_extended (or stbir_build_samplers or stbir_build_samplers_with_splits) -STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize ); - -// use after calling stbir_resize_extended -STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize ); - -// use after calling stbir_resize_extended_split -STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize, int split_start, int split_num ); - -//=============================================================== - -#endif - - -//// end header file ///////////////////////////////////////////////////// -#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE2_H - -#if defined(STB_IMAGE_RESIZE_IMPLEMENTATION) || defined(STB_IMAGE_RESIZE2_IMPLEMENTATION) - -#ifndef STBIR_ASSERT -#include -#define STBIR_ASSERT(x) assert(x) -#endif - -#ifndef STBIR_MALLOC -#include -#define STBIR_MALLOC(size,user_data) ((void)(user_data), malloc(size)) -#define STBIR_FREE(ptr,user_data) ((void)(user_data), free(ptr)) -// (we used the comma operator to evaluate user_data, to avoid "unused parameter" warnings) -#endif - -#ifdef _MSC_VER - -#define stbir__inline __forceinline - -#else - -#define stbir__inline __inline__ - -// Clang address sanitizer -#if defined(__has_feature) - #if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer) - #ifndef STBIR__SEPARATE_ALLOCATIONS - #define STBIR__SEPARATE_ALLOCATIONS - #endif - #endif -#endif - -#endif - -// GCC and MSVC -#if defined(__SANITIZE_ADDRESS__) - #ifndef STBIR__SEPARATE_ALLOCATIONS - #define STBIR__SEPARATE_ALLOCATIONS - #endif -#endif - -// Always turn off automatic FMA use - use STBIR_USE_FMA if you want. -// Otherwise, this is a determinism disaster. -#ifndef STBIR_DONT_CHANGE_FP_CONTRACT // override in case you don't want this behavior -#if defined(_MSC_VER) && !defined(__clang__) -#if _MSC_VER > 1200 -#pragma fp_contract(off) -#endif -#elif defined(__GNUC__) && !defined(__clang__) -#pragma GCC optimize("fp-contract=off") -#else -#pragma STDC FP_CONTRACT OFF -#endif -#endif - -#ifdef _MSC_VER -#define STBIR__UNUSED(v) (void)(v) -#else -#define STBIR__UNUSED(v) (void)sizeof(v) -#endif - -#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) - - -#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE -#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM -#endif - -#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE -#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL -#endif - - -#ifndef STBIR__HEADER_FILENAME -#define STBIR__HEADER_FILENAME "stb_image_resize2.h" -#endif - -// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types -// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible -typedef enum -{ - STBIRI_1CHANNEL = 0, - STBIRI_2CHANNEL = 1, - STBIRI_RGB = 2, - STBIRI_BGR = 3, - STBIRI_4CHANNEL = 4, - - STBIRI_RGBA = 5, - STBIRI_BGRA = 6, - STBIRI_ARGB = 7, - STBIRI_ABGR = 8, - STBIRI_RA = 9, - STBIRI_AR = 10, - - STBIRI_RGBA_PM = 11, - STBIRI_BGRA_PM = 12, - STBIRI_ARGB_PM = 13, - STBIRI_ABGR_PM = 14, - STBIRI_RA_PM = 15, - STBIRI_AR_PM = 16, -} stbir_internal_pixel_layout; - -// define the public pixel layouts to not compile inside the implementation (to avoid accidental use) -#define STBIR_BGR bad_dont_use_in_implementation -#define STBIR_1CHANNEL STBIR_BGR -#define STBIR_2CHANNEL STBIR_BGR -#define STBIR_RGB STBIR_BGR -#define STBIR_RGBA STBIR_BGR -#define STBIR_4CHANNEL STBIR_BGR -#define STBIR_BGRA STBIR_BGR -#define STBIR_ARGB STBIR_BGR -#define STBIR_ABGR STBIR_BGR -#define STBIR_RA STBIR_BGR -#define STBIR_AR STBIR_BGR -#define STBIR_RGBA_PM STBIR_BGR -#define STBIR_BGRA_PM STBIR_BGR -#define STBIR_ARGB_PM STBIR_BGR -#define STBIR_ABGR_PM STBIR_BGR -#define STBIR_RA_PM STBIR_BGR -#define STBIR_AR_PM STBIR_BGR - -// must match stbir_datatype -static unsigned char stbir__type_size[] = { - 1,1,1,2,4,2 // STBIR_TYPE_UINT8,STBIR_TYPE_UINT8_SRGB,STBIR_TYPE_UINT8_SRGB_ALPHA,STBIR_TYPE_UINT16,STBIR_TYPE_FLOAT,STBIR_TYPE_HALF_FLOAT -}; - -// When gathering, the contributors are which source pixels contribute. -// When scattering, the contributors are which destination pixels are contributed to. -typedef struct -{ - int n0; // First contributing pixel - int n1; // Last contributing pixel -} stbir__contributors; - -typedef struct -{ - int lowest; // First sample index for whole filter - int highest; // Last sample index for whole filter - int widest; // widest single set of samples for an output -} stbir__filter_extent_info; - -typedef struct -{ - int n0; // First pixel of decode buffer to write to - int n1; // Last pixel of decode that will be written to - int pixel_offset_for_input; // Pixel offset into input_scanline -} stbir__span; - -typedef struct stbir__scale_info -{ - int input_full_size; - int output_sub_size; - float scale; - float inv_scale; - float pixel_shift; // starting shift in output pixel space (in pixels) - int scale_is_rational; - stbir_uint32 scale_numerator, scale_denominator; -} stbir__scale_info; - -typedef struct -{ - stbir__contributors * contributors; - float* coefficients; - stbir__contributors * gather_prescatter_contributors; - float * gather_prescatter_coefficients; - stbir__scale_info scale_info; - float support; - stbir_filter filter_enum; - stbir__kernel_callback * filter_kernel; - stbir__support_callback * filter_support; - stbir_edge edge; - int coefficient_width; - int filter_pixel_width; - int filter_pixel_margin; - int num_contributors; - int contributors_size; - int coefficients_size; - stbir__filter_extent_info extent_info; - int is_gather; // 0 = scatter, 1 = gather with scale >= 1, 2 = gather with scale < 1 - int gather_prescatter_num_contributors; - int gather_prescatter_coefficient_width; - int gather_prescatter_contributors_size; - int gather_prescatter_coefficients_size; -} stbir__sampler; - -typedef struct -{ - stbir__contributors conservative; - int edge_sizes[2]; // this can be less than filter_pixel_margin, if the filter and scaling falls off - stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP -} stbir__extents; - -typedef struct -{ -#ifdef STBIR_PROFILE - union - { - struct { stbir_uint64 total, looping, vertical, horizontal, decode, encode, alpha, unalpha; } named; - stbir_uint64 array[8]; - } profile; - stbir_uint64 * current_zone_excluded_ptr; -#endif - float* decode_buffer; - - int ring_buffer_first_scanline; - int ring_buffer_last_scanline; - int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer - int start_output_y, end_output_y; - int start_input_y, end_input_y; // used in scatter only - - #ifdef STBIR__SEPARATE_ALLOCATIONS - float** ring_buffers; // one pointer for each ring buffer - #else - float* ring_buffer; // one big buffer that we index into - #endif - - float* vertical_buffer; - - char no_cache_straddle[64]; -} stbir__per_split_info; - -typedef void stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input ); -typedef void stbir__alpha_weight_func( float * decode_buffer, int width_times_channels ); -typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, - stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ); -typedef void stbir__alpha_unweight_func(float * encode_buffer, int width_times_channels ); -typedef void stbir__encode_pixels_func( void * output, int width_times_channels, float const * encode ); - -struct stbir__info -{ -#ifdef STBIR_PROFILE - union - { - struct { stbir_uint64 total, build, alloc, horizontal, vertical, cleanup, pivot; } named; - stbir_uint64 array[7]; - } profile; - stbir_uint64 * current_zone_excluded_ptr; -#endif - stbir__sampler horizontal; - stbir__sampler vertical; - - void const * input_data; - void * output_data; - - int input_stride_bytes; - int output_stride_bytes; - int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) - int ring_buffer_num_entries; // Total number of entries in the ring buffer. - - stbir_datatype input_type; - stbir_datatype output_type; - - stbir_input_callback * in_pixels_cb; - void * user_data; - stbir_output_callback * out_pixels_cb; - - stbir__extents scanline_extents; - - void * alloced_mem; - stbir__per_split_info * split_info; // by default 1, but there will be N of these allocated based on the thread init you did - - stbir__decode_pixels_func * decode_pixels; - stbir__alpha_weight_func * alpha_weight; - stbir__horizontal_gather_channels_func * horizontal_gather_channels; - stbir__alpha_unweight_func * alpha_unweight; - stbir__encode_pixels_func * encode_pixels; - - int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated - int splits; // count of splits - - stbir_internal_pixel_layout input_pixel_layout_internal; - stbir_internal_pixel_layout output_pixel_layout_internal; - - int input_color_and_type; - int offset_x, offset_y; // offset within output_data - int vertical_first; - int channels; - int effective_channels; // same as channels, except on RGBA/ARGB (7), or XA/AX (3) - size_t alloced_total; -}; - - -#define stbir__max_uint8_as_float 255.0f -#define stbir__max_uint16_as_float 65535.0f -#define stbir__max_uint8_as_float_inverted (1.0f/255.0f) -#define stbir__max_uint16_as_float_inverted (1.0f/65535.0f) -#define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) - -// min/max friendly -#define STBIR_CLAMP(x, xmin, xmax) for(;;) { \ - if ( (x) < (xmin) ) (x) = (xmin); \ - if ( (x) > (xmax) ) (x) = (xmax); \ - break; \ -} - -static stbir__inline int stbir__min(int a, int b) -{ - return a < b ? a : b; -} - -static stbir__inline int stbir__max(int a, int b) -{ - return a > b ? a : b; -} - -static float stbir__srgb_uchar_to_linear_float[256] = { - 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, - 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, - 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, - 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, - 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, - 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, - 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, - 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, - 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, - 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, - 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, - 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, - 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, - 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, - 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, - 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, - 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, - 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, - 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, - 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, - 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, - 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, - 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, - 0.982251f, 0.991102f, 1.0f -}; - -typedef union -{ - unsigned int u; - float f; -} stbir__FP32; - -// From https://gist.github.com/rygorous/2203834 - -static const stbir_uint32 fp32_to_srgb8_tab4[104] = { - 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, - 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, - 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, - 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, - 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, - 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, - 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, - 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, - 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, - 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, - 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, - 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, - 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, -}; - -static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) -{ - static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps - static const stbir__FP32 minval = { (127-13) << 23 }; - stbir_uint32 tab,bias,scale,t; - stbir__FP32 f; - - // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. - // The tests are carefully written so that NaNs map to 0, same as in the reference - // implementation. - if (!(in > minval.f)) // written this way to catch NaNs - return 0; - if (in > almostone.f) - return 255; - - // Do the table lookup and unpack bias, scale - f.f = in; - tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; - bias = (tab >> 16) << 9; - scale = tab & 0xffff; - - // Grab next-highest mantissa bits and perform linear interpolation - t = (f.u >> 12) & 0xff; - return (unsigned char) ((bias + scale*t) >> 16); -} - -#ifndef STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT -#define STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT 32 // when downsampling and <= 32 scanlines of buffering, use gather. gather used down to 1/8th scaling for 25% win. -#endif - -#ifndef STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS -#define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split? -#endif - -// restrict pointers for the output pointers, other loop and unroll control -#if defined( _MSC_VER ) && !defined(__clang__) - #define STBIR_STREAMOUT_PTR( star ) star __restrict - #define STBIR_NO_UNROLL( ptr ) __assume(ptr) // this oddly keeps msvc from unrolling a loop - #if _MSC_VER >= 1900 - #define STBIR_NO_UNROLL_LOOP_START __pragma(loop( no_vector )) - #else - #define STBIR_NO_UNROLL_LOOP_START - #endif -#elif defined( __clang__ ) - #define STBIR_STREAMOUT_PTR( star ) star __restrict__ - #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) - #if ( __clang_major__ >= 4 ) || ( ( __clang_major__ >= 3 ) && ( __clang_minor__ >= 5 ) ) - #define STBIR_NO_UNROLL_LOOP_START _Pragma("clang loop unroll(disable)") _Pragma("clang loop vectorize(disable)") - #else - #define STBIR_NO_UNROLL_LOOP_START - #endif -#elif defined( __GNUC__ ) - #define STBIR_STREAMOUT_PTR( star ) star __restrict__ - #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) - #if __GNUC__ >= 14 - #define STBIR_NO_UNROLL_LOOP_START _Pragma("GCC unroll 0") _Pragma("GCC novector") - #else - #define STBIR_NO_UNROLL_LOOP_START - #endif - #define STBIR_NO_UNROLL_LOOP_START_INF_FOR -#else - #define STBIR_STREAMOUT_PTR( star ) star - #define STBIR_NO_UNROLL( ptr ) - #define STBIR_NO_UNROLL_LOOP_START -#endif - -#ifndef STBIR_NO_UNROLL_LOOP_START_INF_FOR -#define STBIR_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START -#endif - -#ifdef STBIR_NO_SIMD // force simd off for whatever reason - -// force simd off overrides everything else, so clear it all - -#ifdef STBIR_SSE2 -#undef STBIR_SSE2 -#endif - -#ifdef STBIR_AVX -#undef STBIR_AVX -#endif - -#ifdef STBIR_NEON -#undef STBIR_NEON -#endif - -#ifdef STBIR_AVX2 -#undef STBIR_AVX2 -#endif - -#ifdef STBIR_FP16C -#undef STBIR_FP16C -#endif - -#ifdef STBIR_WASM -#undef STBIR_WASM -#endif - -#ifdef STBIR_SIMD -#undef STBIR_SIMD -#endif - -#else // STBIR_SIMD - -#ifdef STBIR_SSE2 - #include - - #define stbir__simdf __m128 - #define stbir__simdi __m128i - - #define stbir_simdi_castf( reg ) _mm_castps_si128(reg) - #define stbir_simdf_casti( reg ) _mm_castsi128_ps(reg) - - #define stbir__simdf_load( reg, ptr ) (reg) = _mm_loadu_ps( (float const*)(ptr) ) - #define stbir__simdi_load( reg, ptr ) (reg) = _mm_loadu_si128 ( (stbir__simdi const*)(ptr) ) - #define stbir__simdf_load1( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf) - #define stbir__simdi_load1( out, ptr ) (out) = _mm_castps_si128( _mm_load_ss( (float const*)(ptr) )) - #define stbir__simdf_load1z( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values must be zero - #define stbir__simdf_frep4( fvar ) _mm_set_ps1( fvar ) - #define stbir__simdf_load1frep4( out, fvar ) (out) = _mm_set_ps1( fvar ) - #define stbir__simdf_load2( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values can be random (not denormal or nan for perf) - #define stbir__simdf_load2z( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values must be zero - #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = _mm_castpd_ps(_mm_loadh_pd( _mm_castps_pd(reg), (double*)(ptr) )) - - #define stbir__simdf_zeroP() _mm_setzero_ps() - #define stbir__simdf_zero( reg ) (reg) = _mm_setzero_ps() - - #define stbir__simdf_store( ptr, reg ) _mm_storeu_ps( (float*)(ptr), reg ) - #define stbir__simdf_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), reg ) - #define stbir__simdf_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), _mm_castps_si128(reg) ) - #define stbir__simdf_store2h( ptr, reg ) _mm_storeh_pd( (double*)(ptr), _mm_castps_pd(reg) ) - - #define stbir__simdi_store( ptr, reg ) _mm_storeu_si128( (__m128i*)(ptr), reg ) - #define stbir__simdi_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), _mm_castsi128_ps(reg) ) - #define stbir__simdi_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), (reg) ) - - #define stbir__prefetch( ptr ) _mm_prefetch((char*)(ptr), _MM_HINT_T0 ) - - #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \ - { \ - stbir__simdi zero = _mm_setzero_si128(); \ - out2 = _mm_unpacklo_epi8( ireg, zero ); \ - out3 = _mm_unpackhi_epi8( ireg, zero ); \ - out0 = _mm_unpacklo_epi16( out2, zero ); \ - out1 = _mm_unpackhi_epi16( out2, zero ); \ - out2 = _mm_unpacklo_epi16( out3, zero ); \ - out3 = _mm_unpackhi_epi16( out3, zero ); \ - } - -#define stbir__simdi_expand_u8_to_1u32(out,ireg) \ - { \ - stbir__simdi zero = _mm_setzero_si128(); \ - out = _mm_unpacklo_epi8( ireg, zero ); \ - out = _mm_unpacklo_epi16( out, zero ); \ - } - - #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \ - { \ - stbir__simdi zero = _mm_setzero_si128(); \ - out0 = _mm_unpacklo_epi16( ireg, zero ); \ - out1 = _mm_unpackhi_epi16( ireg, zero ); \ - } - - #define stbir__simdf_convert_float_to_i32( i, f ) (i) = _mm_cvttps_epi32(f) - #define stbir__simdf_convert_float_to_int( f ) _mm_cvtt_ss2si(f) - #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),_mm_setzero_ps())))) - #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))) - - #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i) - #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = _mm_cvtepi32_ps( ireg ) - #define stbir__simdf_add( out, reg0, reg1 ) (out) = _mm_add_ps( reg0, reg1 ) - #define stbir__simdf_mult( out, reg0, reg1 ) (out) = _mm_mul_ps( reg0, reg1 ) - #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = _mm_mul_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) ) - #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = _mm_mul_ss( reg, _mm_load_ss( (float const*)(ptr) ) ) - #define stbir__simdf_add_mem( out, reg, ptr ) (out) = _mm_add_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) ) - #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = _mm_add_ss( reg, _mm_load_ss( (float const*)(ptr) ) ) - - #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd - #include - #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_fmadd_ps( mul1, mul2, add ) - #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_fmadd_ss( mul1, mul2, add ) - #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ps( mul, _mm_loadu_ps( (float const*)(ptr) ), add ) - #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ss( mul, _mm_load_ss( (float const*)(ptr) ), add ) - #else - #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_add_ps( add, _mm_mul_ps( mul1, mul2 ) ) - #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_add_ss( add, _mm_mul_ss( mul1, mul2 ) ) - #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_add_ps( add, _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) ) - #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_add_ss( add, _mm_mul_ss( mul, _mm_load_ss( (float const*)(ptr) ) ) ) - #endif - - #define stbir__simdf_add1( out, reg0, reg1 ) (out) = _mm_add_ss( reg0, reg1 ) - #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = _mm_mul_ss( reg0, reg1 ) - - #define stbir__simdf_and( out, reg0, reg1 ) (out) = _mm_and_ps( reg0, reg1 ) - #define stbir__simdf_or( out, reg0, reg1 ) (out) = _mm_or_ps( reg0, reg1 ) - - #define stbir__simdf_min( out, reg0, reg1 ) (out) = _mm_min_ps( reg0, reg1 ) - #define stbir__simdf_max( out, reg0, reg1 ) (out) = _mm_max_ps( reg0, reg1 ) - #define stbir__simdf_min1( out, reg0, reg1 ) (out) = _mm_min_ss( reg0, reg1 ) - #define stbir__simdf_max1( out, reg0, reg1 ) (out) = _mm_max_ss( reg0, reg1 ) - - #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (3<<0) + (0<<2) + (1<<4) + (2<<6) ) ) - #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (2<<0) + (3<<2) + (0<<4) + (1<<6) ) ) - - static const stbir__simdf STBIR_zeroones = { 0.0f,1.0f,0.0f,1.0f }; - static const stbir__simdf STBIR_onezeros = { 1.0f,0.0f,1.0f,0.0f }; - #define stbir__simdf_aaa1( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movehl_ps( ones, alp ) ), (1<<0) + (1<<2) + (1<<4) + (2<<6) ) ) - #define stbir__simdf_1aaa( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movelh_ps( ones, alp ) ), (0<<0) + (2<<2) + (2<<4) + (2<<6) ) ) - #define stbir__simdf_a1a1( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_srli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_zeroones ) - #define stbir__simdf_1a1a( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_slli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_onezeros ) - - #define stbir__simdf_swiz( reg, one, two, three, four ) _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( reg ), (one<<0) + (two<<2) + (three<<4) + (four<<6) ) ) - - #define stbir__simdi_and( out, reg0, reg1 ) (out) = _mm_and_si128( reg0, reg1 ) - #define stbir__simdi_or( out, reg0, reg1 ) (out) = _mm_or_si128( reg0, reg1 ) - #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = _mm_madd_epi16( reg0, reg1 ) - - #define stbir__simdf_pack_to_8bytes(out,aa,bb) \ - { \ - stbir__simdf af,bf; \ - stbir__simdi a,b; \ - af = _mm_min_ps( aa, STBIR_max_uint8_as_float ); \ - bf = _mm_min_ps( bb, STBIR_max_uint8_as_float ); \ - af = _mm_max_ps( af, _mm_setzero_ps() ); \ - bf = _mm_max_ps( bf, _mm_setzero_ps() ); \ - a = _mm_cvttps_epi32( af ); \ - b = _mm_cvttps_epi32( bf ); \ - a = _mm_packs_epi32( a, b ); \ - out = _mm_packus_epi16( a, a ); \ - } - - #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \ - stbir__simdf_load( o0, (ptr) ); \ - stbir__simdf_load( o1, (ptr)+4 ); \ - stbir__simdf_load( o2, (ptr)+8 ); \ - stbir__simdf_load( o3, (ptr)+12 ); \ - { \ - __m128 tmp0, tmp1, tmp2, tmp3; \ - tmp0 = _mm_unpacklo_ps(o0, o1); \ - tmp2 = _mm_unpacklo_ps(o2, o3); \ - tmp1 = _mm_unpackhi_ps(o0, o1); \ - tmp3 = _mm_unpackhi_ps(o2, o3); \ - o0 = _mm_movelh_ps(tmp0, tmp2); \ - o1 = _mm_movehl_ps(tmp2, tmp0); \ - o2 = _mm_movelh_ps(tmp1, tmp3); \ - o3 = _mm_movehl_ps(tmp3, tmp1); \ - } - - #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \ - r0 = _mm_packs_epi32( r0, r1 ); \ - r2 = _mm_packs_epi32( r2, r3 ); \ - r1 = _mm_unpacklo_epi16( r0, r2 ); \ - r3 = _mm_unpackhi_epi16( r0, r2 ); \ - r0 = _mm_unpacklo_epi16( r1, r3 ); \ - r2 = _mm_unpackhi_epi16( r1, r3 ); \ - r0 = _mm_packus_epi16( r0, r2 ); \ - stbir__simdi_store( ptr, r0 ); \ - - #define stbir__simdi_32shr( out, reg, imm ) out = _mm_srli_epi32( reg, imm ) - - #if defined(_MSC_VER) && !defined(__clang__) - // msvc inits with 8 bytes - #define STBIR__CONST_32_TO_8( v ) (char)(unsigned char)((v)&255),(char)(unsigned char)(((v)>>8)&255),(char)(unsigned char)(((v)>>16)&255),(char)(unsigned char)(((v)>>24)&255) - #define STBIR__CONST_4_32i( v ) STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ) - #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) STBIR__CONST_32_TO_8( v0 ), STBIR__CONST_32_TO_8( v1 ), STBIR__CONST_32_TO_8( v2 ), STBIR__CONST_32_TO_8( v3 ) - #else - // everything else inits with long long's - #define STBIR__CONST_4_32i( v ) (long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v))),(long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v))) - #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) (long long)((((stbir_uint64)(stbir_uint32)(v1))<<32)|((stbir_uint64)(stbir_uint32)(v0))),(long long)((((stbir_uint64)(stbir_uint32)(v3))<<32)|((stbir_uint64)(stbir_uint32)(v2))) - #endif - - #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x } - #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { STBIR__CONST_4_32i(x) } - #define STBIR__CONSTF(var) (var) - #define STBIR__CONSTI(var) (var) - - #if defined(STBIR_AVX) || defined(__SSE4_1__) - #include - #define stbir__simdf_pack_to_8words(out,reg0,reg1) out = _mm_packus_epi32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())), _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps()))) - #else - STBIR__SIMDI_CONST(stbir__s32_32768, 32768); - STBIR__SIMDI_CONST(stbir__s16_32768, ((32768<<16)|32768)); - - #define stbir__simdf_pack_to_8words(out,reg0,reg1) \ - { \ - stbir__simdi tmp0,tmp1; \ - tmp0 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \ - tmp1 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \ - tmp0 = _mm_sub_epi32( tmp0, stbir__s32_32768 ); \ - tmp1 = _mm_sub_epi32( tmp1, stbir__s32_32768 ); \ - out = _mm_packs_epi32( tmp0, tmp1 ); \ - out = _mm_sub_epi16( out, stbir__s16_32768 ); \ - } - - #endif - - #define STBIR_SIMD - - // if we detect AVX, set the simd8 defines - #ifdef STBIR_AVX - #include - #define STBIR_SIMD8 - #define stbir__simdf8 __m256 - #define stbir__simdi8 __m256i - #define stbir__simdf8_load( out, ptr ) (out) = _mm256_loadu_ps( (float const *)(ptr) ) - #define stbir__simdi8_load( out, ptr ) (out) = _mm256_loadu_si256( (__m256i const *)(ptr) ) - #define stbir__simdf8_mult( out, a, b ) (out) = _mm256_mul_ps( (a), (b) ) - #define stbir__simdf8_store( ptr, out ) _mm256_storeu_ps( (float*)(ptr), out ) - #define stbir__simdi8_store( ptr, reg ) _mm256_storeu_si256( (__m256i*)(ptr), reg ) - #define stbir__simdf8_frep8( fval ) _mm256_set1_ps( fval ) - - #define stbir__simdf8_min( out, reg0, reg1 ) (out) = _mm256_min_ps( reg0, reg1 ) - #define stbir__simdf8_max( out, reg0, reg1 ) (out) = _mm256_max_ps( reg0, reg1 ) - - #define stbir__simdf8_add4halves( out, bot4, top8 ) (out) = _mm_add_ps( bot4, _mm256_extractf128_ps( top8, 1 ) ) - #define stbir__simdf8_mult_mem( out, reg, ptr ) (out) = _mm256_mul_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) ) - #define stbir__simdf8_add_mem( out, reg, ptr ) (out) = _mm256_add_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) ) - #define stbir__simdf8_add( out, a, b ) (out) = _mm256_add_ps( a, b ) - #define stbir__simdf8_load1b( out, ptr ) (out) = _mm256_broadcast_ss( ptr ) - #define stbir__simdf_load1rep4( out, ptr ) (out) = _mm_broadcast_ss( ptr ) // avx load instruction - - #define stbir__simdi8_convert_i32_to_float(out, ireg) (out) = _mm256_cvtepi32_ps( ireg ) - #define stbir__simdf8_convert_float_to_i32( i, f ) (i) = _mm256_cvttps_epi32(f) - - #define stbir__simdf8_bot4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (0<<0)+(2<<4) ) - #define stbir__simdf8_top4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (1<<0)+(3<<4) ) - - #define stbir__simdf8_gettop4( reg ) _mm256_extractf128_ps(reg,1) - - #ifdef STBIR_AVX2 - - #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \ - { \ - stbir__simdi8 a, zero =_mm256_setzero_si256();\ - a = _mm256_permute4x64_epi64( _mm256_unpacklo_epi8( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), zero ),(0<<0)+(2<<2)+(1<<4)+(3<<6)); \ - out0 = _mm256_unpacklo_epi16( a, zero ); \ - out1 = _mm256_unpackhi_epi16( a, zero ); \ - } - - #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \ - { \ - stbir__simdi8 t; \ - stbir__simdf8 af,bf; \ - stbir__simdi8 a,b; \ - af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \ - bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \ - af = _mm256_max_ps( af, _mm256_setzero_ps() ); \ - bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \ - a = _mm256_cvttps_epi32( af ); \ - b = _mm256_cvttps_epi32( bf ); \ - t = _mm256_permute4x64_epi64( _mm256_packs_epi32( a, b ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \ - out = _mm256_castsi256_si128( _mm256_permute4x64_epi64( _mm256_packus_epi16( t, t ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ) ); \ - } - - #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() ); - - #define stbir__simdf8_pack_to_16words(out,aa,bb) \ - { \ - stbir__simdf8 af,bf; \ - stbir__simdi8 a,b; \ - af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \ - bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \ - af = _mm256_max_ps( af, _mm256_setzero_ps() ); \ - bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \ - a = _mm256_cvttps_epi32( af ); \ - b = _mm256_cvttps_epi32( bf ); \ - (out) = _mm256_permute4x64_epi64( _mm256_packus_epi32(a, b), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \ - } - - #else - - #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \ - { \ - stbir__simdi a,zero = _mm_setzero_si128(); \ - a = _mm_unpacklo_epi8( ireg, zero ); \ - out0 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \ - a = _mm_unpackhi_epi8( ireg, zero ); \ - out1 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \ - } - - #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \ - { \ - stbir__simdi t; \ - stbir__simdf8 af,bf; \ - stbir__simdi8 a,b; \ - af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \ - bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \ - af = _mm256_max_ps( af, _mm256_setzero_ps() ); \ - bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \ - a = _mm256_cvttps_epi32( af ); \ - b = _mm256_cvttps_epi32( bf ); \ - out = _mm_packs_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \ - out = _mm_packus_epi16( out, out ); \ - t = _mm_packs_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \ - t = _mm_packus_epi16( t, t ); \ - out = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps(out), _mm_castsi128_ps(t), (0<<0)+(1<<2)+(0<<4)+(1<<6) ) ); \ - } - - #define stbir__simdi8_expand_u16_to_u32(out,ireg) \ - { \ - stbir__simdi a,b,zero = _mm_setzero_si128(); \ - a = _mm_unpacklo_epi16( ireg, zero ); \ - b = _mm_unpackhi_epi16( ireg, zero ); \ - out = _mm256_insertf128_si256( _mm256_castsi128_si256( a ), b, 1 ); \ - } - - #define stbir__simdf8_pack_to_16words(out,aa,bb) \ - { \ - stbir__simdi t0,t1; \ - stbir__simdf8 af,bf; \ - stbir__simdi8 a,b; \ - af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \ - bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \ - af = _mm256_max_ps( af, _mm256_setzero_ps() ); \ - bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \ - a = _mm256_cvttps_epi32( af ); \ - b = _mm256_cvttps_epi32( bf ); \ - t0 = _mm_packus_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \ - t1 = _mm_packus_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \ - out = _mm256_setr_m128i( t0, t1 ); \ - } - - #endif - - static __m256i stbir_00001111 = { STBIR__CONST_4d_32i( 0, 0, 0, 0 ), STBIR__CONST_4d_32i( 1, 1, 1, 1 ) }; - #define stbir__simdf8_0123to00001111( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00001111 ) - - static __m256i stbir_22223333 = { STBIR__CONST_4d_32i( 2, 2, 2, 2 ), STBIR__CONST_4d_32i( 3, 3, 3, 3 ) }; - #define stbir__simdf8_0123to22223333( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_22223333 ) - - #define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 ) - - #define stbir__simdf8_load4b( out, ptr ) (out) = _mm256_broadcast_ps( (__m128 const *)(ptr) ) - - static __m256i stbir_00112233 = { STBIR__CONST_4d_32i( 0, 0, 1, 1 ), STBIR__CONST_4d_32i( 2, 2, 3, 3 ) }; - #define stbir__simdf8_0123to00112233( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00112233 ) - #define stbir__simdf8_add4( out, a8, b ) (out) = _mm256_add_ps( a8, _mm256_castps128_ps256( b ) ) - - static __m256i stbir_load6 = { STBIR__CONST_4_32i( 0x80000000 ), STBIR__CONST_4d_32i( 0x80000000, 0x80000000, 0, 0 ) }; - #define stbir__simdf8_load6z( out, ptr ) (out) = _mm256_maskload_ps( ptr, stbir_load6 ) - - #define stbir__simdf8_0123to00000000( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(0<<4)+(0<<6) ) - #define stbir__simdf8_0123to11111111( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(1<<4)+(1<<6) ) - #define stbir__simdf8_0123to22222222( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(2<<2)+(2<<4)+(2<<6) ) - #define stbir__simdf8_0123to33333333( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(3<<2)+(3<<4)+(3<<6) ) - #define stbir__simdf8_0123to21032103( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(1<<2)+(0<<4)+(3<<6) ) - #define stbir__simdf8_0123to32103210( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(2<<2)+(1<<4)+(0<<6) ) - #define stbir__simdf8_0123to12301230( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(2<<2)+(3<<4)+(0<<6) ) - #define stbir__simdf8_0123to10321032( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(0<<2)+(3<<4)+(2<<6) ) - #define stbir__simdf8_0123to30123012( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(0<<2)+(1<<4)+(2<<6) ) - - #define stbir__simdf8_0123to11331133( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(3<<4)+(3<<6) ) - #define stbir__simdf8_0123to00220022( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(2<<4)+(2<<6) ) - - #define stbir__simdf8_aaa1( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(1<<1)+(1<<2)+(0<<3)+(1<<4)+(1<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (3<<0) + (3<<2) + (3<<4) + (0<<6) ) - #define stbir__simdf8_1aaa( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(1<<2)+(1<<3)+(0<<4)+(1<<5)+(1<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (0<<4) + (0<<6) ) - #define stbir__simdf8_a1a1( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(0<<1)+(1<<2)+(0<<3)+(1<<4)+(0<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) ) - #define stbir__simdf8_1a1a( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(0<<2)+(1<<3)+(0<<4)+(1<<5)+(0<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) ) - - #define stbir__simdf8_zero( reg ) (reg) = _mm256_setzero_ps() - - #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd - #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_fmadd_ps( mul1, mul2, add ) - #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ), add ) - #define stbir__simdf8_madd_mem4( out, add, mul, ptr )(out) = _mm256_fmadd_ps( _mm256_setr_m128( mul, _mm_setzero_ps() ), _mm256_setr_m128( _mm_loadu_ps( (float const*)(ptr) ), _mm_setzero_ps() ), add ) - #else - #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul1, mul2 ) ) - #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ) ) ) - #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_setr_m128( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ), _mm_setzero_ps() ) ) - #endif - #define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val ) - - #endif - - #ifdef STBIR_FLOORF - #undef STBIR_FLOORF - #endif - #define STBIR_FLOORF stbir_simd_floorf - static stbir__inline float stbir_simd_floorf(float x) // martins floorf - { - #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41) - __m128 t = _mm_set_ss(x); - return _mm_cvtss_f32( _mm_floor_ss(t, t) ); - #else - __m128 f = _mm_set_ss(x); - __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f)); - __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(f, t), _mm_set_ss(-1.0f))); - return _mm_cvtss_f32(r); - #endif - } - - #ifdef STBIR_CEILF - #undef STBIR_CEILF - #endif - #define STBIR_CEILF stbir_simd_ceilf - static stbir__inline float stbir_simd_ceilf(float x) // martins ceilf - { - #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41) - __m128 t = _mm_set_ss(x); - return _mm_cvtss_f32( _mm_ceil_ss(t, t) ); - #else - __m128 f = _mm_set_ss(x); - __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f)); - __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(t, f), _mm_set_ss(1.0f))); - return _mm_cvtss_f32(r); - #endif - } - -#elif defined(STBIR_NEON) - - #include - - #define stbir__simdf float32x4_t - #define stbir__simdi uint32x4_t - - #define stbir_simdi_castf( reg ) vreinterpretq_u32_f32(reg) - #define stbir_simdf_casti( reg ) vreinterpretq_f32_u32(reg) - - #define stbir__simdf_load( reg, ptr ) (reg) = vld1q_f32( (float const*)(ptr) ) - #define stbir__simdi_load( reg, ptr ) (reg) = vld1q_u32( (uint32_t const*)(ptr) ) - #define stbir__simdf_load1( out, ptr ) (out) = vld1q_dup_f32( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf) - #define stbir__simdi_load1( out, ptr ) (out) = vld1q_dup_u32( (uint32_t const*)(ptr) ) - #define stbir__simdf_load1z( out, ptr ) (out) = vld1q_lane_f32( (float const*)(ptr), vdupq_n_f32(0), 0 ) // top values must be zero - #define stbir__simdf_frep4( fvar ) vdupq_n_f32( fvar ) - #define stbir__simdf_load1frep4( out, fvar ) (out) = vdupq_n_f32( fvar ) - #define stbir__simdf_load2( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values can be random (not denormal or nan for perf) - #define stbir__simdf_load2z( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values must be zero - #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = vcombine_f32( vget_low_f32(reg), vld1_f32( (float const*)(ptr) ) ) - - #define stbir__simdf_zeroP() vdupq_n_f32(0) - #define stbir__simdf_zero( reg ) (reg) = vdupq_n_f32(0) - - #define stbir__simdf_store( ptr, reg ) vst1q_f32( (float*)(ptr), reg ) - #define stbir__simdf_store1( ptr, reg ) vst1q_lane_f32( (float*)(ptr), reg, 0) - #define stbir__simdf_store2( ptr, reg ) vst1_f32( (float*)(ptr), vget_low_f32(reg) ) - #define stbir__simdf_store2h( ptr, reg ) vst1_f32( (float*)(ptr), vget_high_f32(reg) ) - - #define stbir__simdi_store( ptr, reg ) vst1q_u32( (uint32_t*)(ptr), reg ) - #define stbir__simdi_store1( ptr, reg ) vst1q_lane_u32( (uint32_t*)(ptr), reg, 0 ) - #define stbir__simdi_store2( ptr, reg ) vst1_u32( (uint32_t*)(ptr), vget_low_u32(reg) ) - - #define stbir__prefetch( ptr ) - - #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \ - { \ - uint16x8_t l = vmovl_u8( vget_low_u8 ( vreinterpretq_u8_u32(ireg) ) ); \ - uint16x8_t h = vmovl_u8( vget_high_u8( vreinterpretq_u8_u32(ireg) ) ); \ - out0 = vmovl_u16( vget_low_u16 ( l ) ); \ - out1 = vmovl_u16( vget_high_u16( l ) ); \ - out2 = vmovl_u16( vget_low_u16 ( h ) ); \ - out3 = vmovl_u16( vget_high_u16( h ) ); \ - } - - #define stbir__simdi_expand_u8_to_1u32(out,ireg) \ - { \ - uint16x8_t tmp = vmovl_u8( vget_low_u8( vreinterpretq_u8_u32(ireg) ) ); \ - out = vmovl_u16( vget_low_u16( tmp ) ); \ - } - - #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \ - { \ - uint16x8_t tmp = vreinterpretq_u16_u32(ireg); \ - out0 = vmovl_u16( vget_low_u16 ( tmp ) ); \ - out1 = vmovl_u16( vget_high_u16( tmp ) ); \ - } - - #define stbir__simdf_convert_float_to_i32( i, f ) (i) = vreinterpretq_u32_s32( vcvtq_s32_f32(f) ) - #define stbir__simdf_convert_float_to_int( f ) vgetq_lane_s32(vcvtq_s32_f32(f), 0) - #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0) - #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),vdupq_n_f32(0))), 0)) - #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),vdupq_n_f32(0))), 0)) - #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = vcvtq_f32_s32( vreinterpretq_s32_u32(ireg) ) - #define stbir__simdf_add( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 ) - #define stbir__simdf_mult( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 ) - #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_f32( (float const*)(ptr) ) ) - #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) ) - #define stbir__simdf_add_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_f32( (float const*)(ptr) ) ) - #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) ) - - #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd (and also x64 no madd to arm madd) - #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 ) - #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 ) - #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_f32( (float const*)(ptr) ) ) - #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_dup_f32( (float const*)(ptr) ) ) - #else - #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) ) - #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) ) - #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_f32( (float const*)(ptr) ) ) ) - #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_dup_f32( (float const*)(ptr) ) ) ) - #endif - - #define stbir__simdf_add1( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 ) - #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 ) - - #define stbir__simdf_and( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vandq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) ) - #define stbir__simdf_or( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vorrq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) ) - - #define stbir__simdf_min( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 ) - #define stbir__simdf_max( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 ) - #define stbir__simdf_min1( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 ) - #define stbir__simdf_max1( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 ) - - #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 3 ) - #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 2 ) - - #define stbir__simdf_a1a1( out, alp, ones ) (out) = vzipq_f32(vuzpq_f32(alp, alp).val[1], ones).val[0] - #define stbir__simdf_1a1a( out, alp, ones ) (out) = vzipq_f32(ones, vuzpq_f32(alp, alp).val[0]).val[0] - - #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) - - #define stbir__simdf_aaa1( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3, ones, 3) - #define stbir__simdf_1aaa( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0, ones, 0) - - #if defined( _MSC_VER ) && !defined(__clang__) - #define stbir_make16(a,b,c,d) vcombine_u8( \ - vcreate_u8( (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \ - ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56)), \ - vcreate_u8( (4*c+0) | ((4*c+1)<<8) | ((4*c+2)<<16) | ((4*c+3)<<24) | \ - ((stbir_uint64)(4*d+0)<<32) | ((stbir_uint64)(4*d+1)<<40) | ((stbir_uint64)(4*d+2)<<48) | ((stbir_uint64)(4*d+3)<<56) ) ) - - static stbir__inline uint8x16x2_t stbir_make16x2(float32x4_t rega,float32x4_t regb) - { - uint8x16x2_t r = { vreinterpretq_u8_f32(rega), vreinterpretq_u8_f32(regb) }; - return r; - } - #else - #define stbir_make16(a,b,c,d) (uint8x16_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3,4*c+0,4*c+1,4*c+2,4*c+3,4*d+0,4*d+1,4*d+2,4*d+3} - #define stbir_make16x2(a,b) (uint8x16x2_t){{vreinterpretq_u8_f32(a),vreinterpretq_u8_f32(b)}} - #endif - - #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vqtbl1q_u8( vreinterpretq_u8_f32(reg), stbir_make16(one, two, three, four) ) ) - #define stbir__simdf_swiz2( rega, regb, one, two, three, four ) vreinterpretq_f32_u8( vqtbl2q_u8( stbir_make16x2(rega,regb), stbir_make16(one, two, three, four) ) ) - - #define stbir__simdi_16madd( out, reg0, reg1 ) \ - { \ - int16x8_t r0 = vreinterpretq_s16_u32(reg0); \ - int16x8_t r1 = vreinterpretq_s16_u32(reg1); \ - int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \ - int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \ - (out) = vreinterpretq_u32_s32( vpaddq_s32(tmp0, tmp1) ); \ - } - - #else - - #define stbir__simdf_aaa1( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3) - #define stbir__simdf_1aaa( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0) - - #if defined( _MSC_VER ) && !defined(__clang__) - static stbir__inline uint8x8x2_t stbir_make8x2(float32x4_t reg) - { - uint8x8x2_t r = { { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } }; - return r; - } - #define stbir_make8(a,b) vcreate_u8( \ - (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \ - ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56) ) - #else - #define stbir_make8x2(reg) (uint8x8x2_t){ { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } } - #define stbir_make8(a,b) (uint8x8_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3} - #endif - - #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vcombine_u8( \ - vtbl2_u8( stbir_make8x2( reg ), stbir_make8( one, two ) ), \ - vtbl2_u8( stbir_make8x2( reg ), stbir_make8( three, four ) ) ) ) - - #define stbir__simdi_16madd( out, reg0, reg1 ) \ - { \ - int16x8_t r0 = vreinterpretq_s16_u32(reg0); \ - int16x8_t r1 = vreinterpretq_s16_u32(reg1); \ - int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \ - int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \ - int32x2_t out0 = vpadd_s32( vget_low_s32(tmp0), vget_high_s32(tmp0) ); \ - int32x2_t out1 = vpadd_s32( vget_low_s32(tmp1), vget_high_s32(tmp1) ); \ - (out) = vreinterpretq_u32_s32( vcombine_s32(out0, out1) ); \ - } - - #endif - - #define stbir__simdi_and( out, reg0, reg1 ) (out) = vandq_u32( reg0, reg1 ) - #define stbir__simdi_or( out, reg0, reg1 ) (out) = vorrq_u32( reg0, reg1 ) - - #define stbir__simdf_pack_to_8bytes(out,aa,bb) \ - { \ - float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \ - float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \ - int16x4_t ai = vqmovn_s32( vcvtq_s32_f32( af ) ); \ - int16x4_t bi = vqmovn_s32( vcvtq_s32_f32( bf ) ); \ - uint8x8_t out8 = vqmovun_s16( vcombine_s16(ai, bi) ); \ - out = vreinterpretq_u32_u8( vcombine_u8(out8, out8) ); \ - } - - #define stbir__simdf_pack_to_8words(out,aa,bb) \ - { \ - float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \ - float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \ - int32x4_t ai = vcvtq_s32_f32( af ); \ - int32x4_t bi = vcvtq_s32_f32( bf ); \ - out = vreinterpretq_u32_u16( vcombine_u16(vqmovun_s32(ai), vqmovun_s32(bi)) ); \ - } - - #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \ - { \ - int16x4x2_t tmp0 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r0)), vqmovn_s32(vreinterpretq_s32_u32(r2)) ); \ - int16x4x2_t tmp1 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r1)), vqmovn_s32(vreinterpretq_s32_u32(r3)) ); \ - uint8x8x2_t out = \ - { { \ - vqmovun_s16( vcombine_s16(tmp0.val[0], tmp0.val[1]) ), \ - vqmovun_s16( vcombine_s16(tmp1.val[0], tmp1.val[1]) ), \ - } }; \ - vst2_u8(ptr, out); \ - } - - #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \ - { \ - float32x4x4_t tmp = vld4q_f32(ptr); \ - o0 = tmp.val[0]; \ - o1 = tmp.val[1]; \ - o2 = tmp.val[2]; \ - o3 = tmp.val[3]; \ - } - - #define stbir__simdi_32shr( out, reg, imm ) out = vshrq_n_u32( reg, imm ) - - #if defined( _MSC_VER ) && !defined(__clang__) - #define STBIR__SIMDF_CONST(var, x) __declspec(align(8)) float var[] = { x, x, x, x } - #define STBIR__SIMDI_CONST(var, x) __declspec(align(8)) uint32_t var[] = { x, x, x, x } - #define STBIR__CONSTF(var) (*(const float32x4_t*)var) - #define STBIR__CONSTI(var) (*(const uint32x4_t*)var) - #else - #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x } - #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x } - #define STBIR__CONSTF(var) (var) - #define STBIR__CONSTI(var) (var) - #endif - - #ifdef STBIR_FLOORF - #undef STBIR_FLOORF - #endif - #define STBIR_FLOORF stbir_simd_floorf - static stbir__inline float stbir_simd_floorf(float x) - { - #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) - return vget_lane_f32( vrndm_f32( vdup_n_f32(x) ), 0); - #else - float32x2_t f = vdup_n_f32(x); - float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f)); - uint32x2_t a = vclt_f32(f, t); - uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(-1.0f)); - float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b))); - return vget_lane_f32(r, 0); - #endif - } - - #ifdef STBIR_CEILF - #undef STBIR_CEILF - #endif - #define STBIR_CEILF stbir_simd_ceilf - static stbir__inline float stbir_simd_ceilf(float x) - { - #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) - return vget_lane_f32( vrndp_f32( vdup_n_f32(x) ), 0); - #else - float32x2_t f = vdup_n_f32(x); - float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f)); - uint32x2_t a = vclt_f32(t, f); - uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(1.0f)); - float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b))); - return vget_lane_f32(r, 0); - #endif - } - - #define STBIR_SIMD - -#elif defined(STBIR_WASM) - - #include - - #define stbir__simdf v128_t - #define stbir__simdi v128_t - - #define stbir_simdi_castf( reg ) (reg) - #define stbir_simdf_casti( reg ) (reg) - - #define stbir__simdf_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) ) - #define stbir__simdi_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) ) - #define stbir__simdf_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf) - #define stbir__simdi_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) ) - #define stbir__simdf_load1z( out, ptr ) (out) = wasm_v128_load32_zero( (void const*)(ptr) ) // top values must be zero - #define stbir__simdf_frep4( fvar ) wasm_f32x4_splat( fvar ) - #define stbir__simdf_load1frep4( out, fvar ) (out) = wasm_f32x4_splat( fvar ) - #define stbir__simdf_load2( out, ptr ) (out) = wasm_v128_load64_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf) - #define stbir__simdf_load2z( out, ptr ) (out) = wasm_v128_load64_zero( (void const*)(ptr) ) // top values must be zero - #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = wasm_v128_load64_lane( (void const*)(ptr), reg, 1 ) - - #define stbir__simdf_zeroP() wasm_f32x4_const_splat(0) - #define stbir__simdf_zero( reg ) (reg) = wasm_f32x4_const_splat(0) - - #define stbir__simdf_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg ) - #define stbir__simdf_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 ) - #define stbir__simdf_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 ) - #define stbir__simdf_store2h( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 1 ) - - #define stbir__simdi_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg ) - #define stbir__simdi_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 ) - #define stbir__simdi_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 ) - - #define stbir__prefetch( ptr ) - - #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \ - { \ - v128_t l = wasm_u16x8_extend_low_u8x16 ( ireg ); \ - v128_t h = wasm_u16x8_extend_high_u8x16( ireg ); \ - out0 = wasm_u32x4_extend_low_u16x8 ( l ); \ - out1 = wasm_u32x4_extend_high_u16x8( l ); \ - out2 = wasm_u32x4_extend_low_u16x8 ( h ); \ - out3 = wasm_u32x4_extend_high_u16x8( h ); \ - } - - #define stbir__simdi_expand_u8_to_1u32(out,ireg) \ - { \ - v128_t tmp = wasm_u16x8_extend_low_u8x16(ireg); \ - out = wasm_u32x4_extend_low_u16x8(tmp); \ - } - - #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \ - { \ - out0 = wasm_u32x4_extend_low_u16x8 ( ireg ); \ - out1 = wasm_u32x4_extend_high_u16x8( ireg ); \ - } - - #define stbir__simdf_convert_float_to_i32( i, f ) (i) = wasm_i32x4_trunc_sat_f32x4(f) - #define stbir__simdf_convert_float_to_int( f ) wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(f), 0) - #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0) - #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint8_as_float),wasm_f32x4_const_splat(0))), 0)) - #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint16_as_float),wasm_f32x4_const_splat(0))), 0)) - #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = wasm_f32x4_convert_i32x4(ireg) - #define stbir__simdf_add( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 ) - #define stbir__simdf_mult( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 ) - #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load( (void const*)(ptr) ) ) - #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load32_splat( (void const*)(ptr) ) ) - #define stbir__simdf_add_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load( (void const*)(ptr) ) ) - #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load32_splat( (void const*)(ptr) ) ) - - #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) ) - #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) ) - #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load( (void const*)(ptr) ) ) ) - #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load32_splat( (void const*)(ptr) ) ) ) - - #define stbir__simdf_add1( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 ) - #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 ) - - #define stbir__simdf_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 ) - #define stbir__simdf_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 ) - - #define stbir__simdf_min( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 ) - #define stbir__simdf_max( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 ) - #define stbir__simdf_min1( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 ) - #define stbir__simdf_max1( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 ) - - #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 3, 4, 5, -1 ) - #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 2, 3, 4, -1 ) - - #define stbir__simdf_aaa1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 3, 3, 3, 4) - #define stbir__simdf_1aaa(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 0, 0) - #define stbir__simdf_a1a1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 1, 4, 3, 4) - #define stbir__simdf_1a1a(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 4, 2) - - #define stbir__simdf_swiz( reg, one, two, three, four ) wasm_i32x4_shuffle(reg, reg, one, two, three, four) - - #define stbir__simdi_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 ) - #define stbir__simdi_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 ) - #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = wasm_i32x4_dot_i16x8( reg0, reg1 ) - - #define stbir__simdf_pack_to_8bytes(out,aa,bb) \ - { \ - v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \ - v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \ - v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \ - v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \ - v128_t out16 = wasm_i16x8_narrow_i32x4( ai, bi ); \ - out = wasm_u8x16_narrow_i16x8( out16, out16 ); \ - } - - #define stbir__simdf_pack_to_8words(out,aa,bb) \ - { \ - v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \ - v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \ - v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \ - v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \ - out = wasm_u16x8_narrow_i32x4( ai, bi ); \ - } - - #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \ - { \ - v128_t tmp0 = wasm_i16x8_narrow_i32x4(r0, r1); \ - v128_t tmp1 = wasm_i16x8_narrow_i32x4(r2, r3); \ - v128_t tmp = wasm_u8x16_narrow_i16x8(tmp0, tmp1); \ - tmp = wasm_i8x16_shuffle(tmp, tmp, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); \ - wasm_v128_store( (void*)(ptr), tmp); \ - } - - #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \ - { \ - v128_t t0 = wasm_v128_load( ptr ); \ - v128_t t1 = wasm_v128_load( ptr+4 ); \ - v128_t t2 = wasm_v128_load( ptr+8 ); \ - v128_t t3 = wasm_v128_load( ptr+12 ); \ - v128_t s0 = wasm_i32x4_shuffle(t0, t1, 0, 4, 2, 6); \ - v128_t s1 = wasm_i32x4_shuffle(t0, t1, 1, 5, 3, 7); \ - v128_t s2 = wasm_i32x4_shuffle(t2, t3, 0, 4, 2, 6); \ - v128_t s3 = wasm_i32x4_shuffle(t2, t3, 1, 5, 3, 7); \ - o0 = wasm_i32x4_shuffle(s0, s2, 0, 1, 4, 5); \ - o1 = wasm_i32x4_shuffle(s1, s3, 0, 1, 4, 5); \ - o2 = wasm_i32x4_shuffle(s0, s2, 2, 3, 6, 7); \ - o3 = wasm_i32x4_shuffle(s1, s3, 2, 3, 6, 7); \ - } - - #define stbir__simdi_32shr( out, reg, imm ) out = wasm_u32x4_shr( reg, imm ) - - typedef float stbir__f32x4 __attribute__((__vector_size__(16), __aligned__(16))); - #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = (v128_t)(stbir__f32x4){ x, x, x, x } - #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x } - #define STBIR__CONSTF(var) (var) - #define STBIR__CONSTI(var) (var) - - #ifdef STBIR_FLOORF - #undef STBIR_FLOORF - #endif - #define STBIR_FLOORF stbir_simd_floorf - static stbir__inline float stbir_simd_floorf(float x) - { - return wasm_f32x4_extract_lane( wasm_f32x4_floor( wasm_f32x4_splat(x) ), 0); - } - - #ifdef STBIR_CEILF - #undef STBIR_CEILF - #endif - #define STBIR_CEILF stbir_simd_ceilf - static stbir__inline float stbir_simd_ceilf(float x) - { - return wasm_f32x4_extract_lane( wasm_f32x4_ceil( wasm_f32x4_splat(x) ), 0); - } - - #define STBIR_SIMD - -#endif // SSE2/NEON/WASM - -#endif // NO SIMD - -#ifdef STBIR_SIMD8 - #define stbir__simdfX stbir__simdf8 - #define stbir__simdiX stbir__simdi8 - #define stbir__simdfX_load stbir__simdf8_load - #define stbir__simdiX_load stbir__simdi8_load - #define stbir__simdfX_mult stbir__simdf8_mult - #define stbir__simdfX_add_mem stbir__simdf8_add_mem - #define stbir__simdfX_madd_mem stbir__simdf8_madd_mem - #define stbir__simdfX_store stbir__simdf8_store - #define stbir__simdiX_store stbir__simdi8_store - #define stbir__simdf_frepX stbir__simdf8_frep8 - #define stbir__simdfX_madd stbir__simdf8_madd - #define stbir__simdfX_min stbir__simdf8_min - #define stbir__simdfX_max stbir__simdf8_max - #define stbir__simdfX_aaa1 stbir__simdf8_aaa1 - #define stbir__simdfX_1aaa stbir__simdf8_1aaa - #define stbir__simdfX_a1a1 stbir__simdf8_a1a1 - #define stbir__simdfX_1a1a stbir__simdf8_1a1a - #define stbir__simdfX_convert_float_to_i32 stbir__simdf8_convert_float_to_i32 - #define stbir__simdfX_pack_to_words stbir__simdf8_pack_to_16words - #define stbir__simdfX_zero stbir__simdf8_zero - #define STBIR_onesX STBIR_ones8 - #define STBIR_max_uint8_as_floatX STBIR_max_uint8_as_float8 - #define STBIR_max_uint16_as_floatX STBIR_max_uint16_as_float8 - #define STBIR_simd_point5X STBIR_simd_point58 - #define stbir__simdfX_float_count 8 - #define stbir__simdfX_0123to1230 stbir__simdf8_0123to12301230 - #define stbir__simdfX_0123to2103 stbir__simdf8_0123to21032103 - static const stbir__simdf8 STBIR_max_uint16_as_float_inverted8 = { stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted }; - static const stbir__simdf8 STBIR_max_uint8_as_float_inverted8 = { stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted }; - static const stbir__simdf8 STBIR_ones8 = { 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 }; - static const stbir__simdf8 STBIR_simd_point58 = { 0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5 }; - static const stbir__simdf8 STBIR_max_uint8_as_float8 = { stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float, stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float }; - static const stbir__simdf8 STBIR_max_uint16_as_float8 = { stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float, stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float }; -#else - #define stbir__simdfX stbir__simdf - #define stbir__simdiX stbir__simdi - #define stbir__simdfX_load stbir__simdf_load - #define stbir__simdiX_load stbir__simdi_load - #define stbir__simdfX_mult stbir__simdf_mult - #define stbir__simdfX_add_mem stbir__simdf_add_mem - #define stbir__simdfX_madd_mem stbir__simdf_madd_mem - #define stbir__simdfX_store stbir__simdf_store - #define stbir__simdiX_store stbir__simdi_store - #define stbir__simdf_frepX stbir__simdf_frep4 - #define stbir__simdfX_madd stbir__simdf_madd - #define stbir__simdfX_min stbir__simdf_min - #define stbir__simdfX_max stbir__simdf_max - #define stbir__simdfX_aaa1 stbir__simdf_aaa1 - #define stbir__simdfX_1aaa stbir__simdf_1aaa - #define stbir__simdfX_a1a1 stbir__simdf_a1a1 - #define stbir__simdfX_1a1a stbir__simdf_1a1a - #define stbir__simdfX_convert_float_to_i32 stbir__simdf_convert_float_to_i32 - #define stbir__simdfX_pack_to_words stbir__simdf_pack_to_8words - #define stbir__simdfX_zero stbir__simdf_zero - #define STBIR_onesX STBIR__CONSTF(STBIR_ones) - #define STBIR_simd_point5X STBIR__CONSTF(STBIR_simd_point5) - #define STBIR_max_uint8_as_floatX STBIR__CONSTF(STBIR_max_uint8_as_float) - #define STBIR_max_uint16_as_floatX STBIR__CONSTF(STBIR_max_uint16_as_float) - #define stbir__simdfX_float_count 4 - #define stbir__if_simdf8_cast_to_simdf4( val ) ( val ) - #define stbir__simdfX_0123to1230 stbir__simdf_0123to1230 - #define stbir__simdfX_0123to2103 stbir__simdf_0123to2103 -#endif - - -#if defined(STBIR_NEON) && !defined(_M_ARM) && !defined(__arm__) - - #if defined( _MSC_VER ) && !defined(__clang__) - typedef __int16 stbir__FP16; - #else - typedef float16_t stbir__FP16; - #endif - -#else // no NEON, or 32-bit ARM for MSVC - - typedef union stbir__FP16 - { - unsigned short u; - } stbir__FP16; - -#endif - -#if (!defined(STBIR_NEON) && !defined(STBIR_FP16C)) || (defined(STBIR_NEON) && defined(_M_ARM)) || (defined(STBIR_NEON) && defined(__arm__)) - - // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668 - - static stbir__inline float stbir__half_to_float( stbir__FP16 h ) - { - static const stbir__FP32 magic = { (254 - 15) << 23 }; - static const stbir__FP32 was_infnan = { (127 + 16) << 23 }; - stbir__FP32 o; - - o.u = (h.u & 0x7fff) << 13; // exponent/mantissa bits - o.f *= magic.f; // exponent adjust - if (o.f >= was_infnan.f) // make sure Inf/NaN survive - o.u |= 255 << 23; - o.u |= (h.u & 0x8000) << 16; // sign bit - return o.f; - } - - static stbir__inline stbir__FP16 stbir__float_to_half(float val) - { - stbir__FP32 f32infty = { 255 << 23 }; - stbir__FP32 f16max = { (127 + 16) << 23 }; - stbir__FP32 denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 }; - unsigned int sign_mask = 0x80000000u; - stbir__FP16 o = { 0 }; - stbir__FP32 f; - unsigned int sign; - - f.f = val; - sign = f.u & sign_mask; - f.u ^= sign; - - if (f.u >= f16max.u) // result is Inf or NaN (all exponent bits set) - o.u = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf - else // (De)normalized number or zero - { - if (f.u < (113 << 23)) // resulting FP16 is subnormal or zero - { - // use a magic value to align our 10 mantissa bits at the bottom of - // the float. as long as FP addition is round-to-nearest-even this - // just works. - f.f += denorm_magic.f; - // and one integer subtract of the bias later, we have our final float! - o.u = (unsigned short) ( f.u - denorm_magic.u ); - } - else - { - unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd - // update exponent, rounding bias part 1 - f.u = f.u + ((15u - 127) << 23) + 0xfff; - // rounding bias part 2 - f.u += mant_odd; - // take the bits! - o.u = (unsigned short) ( f.u >> 13 ); - } - } - - o.u |= sign >> 16; - return o; - } - -#endif - - -#if defined(STBIR_FP16C) - - #include - - static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) - { - _mm256_storeu_ps( (float*)output, _mm256_cvtph_ps( _mm_loadu_si128( (__m128i const* )input ) ) ); - } - - static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) - { - _mm_storeu_si128( (__m128i*)output, _mm256_cvtps_ph( _mm256_loadu_ps( input ), 0 ) ); - } - - static stbir__inline float stbir__half_to_float( stbir__FP16 h ) - { - return _mm_cvtss_f32( _mm_cvtph_ps( _mm_cvtsi32_si128( (int)h.u ) ) ); - } - - static stbir__inline stbir__FP16 stbir__float_to_half( float f ) - { - stbir__FP16 h; - h.u = (unsigned short) _mm_cvtsi128_si32( _mm_cvtps_ph( _mm_set_ss( f ), 0 ) ); - return h; - } - -#elif defined(STBIR_SSE2) - - // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668 - stbir__inline static void stbir__half_to_float_SIMD(float * output, void const * input) - { - static const STBIR__SIMDI_CONST(mask_nosign, 0x7fff); - static const STBIR__SIMDI_CONST(smallest_normal, 0x0400); - static const STBIR__SIMDI_CONST(infinity, 0x7c00); - static const STBIR__SIMDI_CONST(expadjust_normal, (127 - 15) << 23); - static const STBIR__SIMDI_CONST(magic_denorm, 113 << 23); - - __m128i i = _mm_loadu_si128 ( (__m128i const*)(input) ); - __m128i h = _mm_unpacklo_epi16 ( i, _mm_setzero_si128() ); - __m128i mnosign = STBIR__CONSTI(mask_nosign); - __m128i eadjust = STBIR__CONSTI(expadjust_normal); - __m128i smallest = STBIR__CONSTI(smallest_normal); - __m128i infty = STBIR__CONSTI(infinity); - __m128i expmant = _mm_and_si128(mnosign, h); - __m128i justsign = _mm_xor_si128(h, expmant); - __m128i b_notinfnan = _mm_cmpgt_epi32(infty, expmant); - __m128i b_isdenorm = _mm_cmpgt_epi32(smallest, expmant); - __m128i shifted = _mm_slli_epi32(expmant, 13); - __m128i adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust); - __m128i adjusted = _mm_add_epi32(eadjust, shifted); - __m128i den1 = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm)); - __m128i adjusted2 = _mm_add_epi32(adjusted, adj_infnan); - __m128 den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm); - __m128 adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm)); - __m128 adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2)); - __m128 adjusted5 = _mm_or_ps(adjusted3, adjusted4); - __m128i sign = _mm_slli_epi32(justsign, 16); - __m128 final = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign)); - stbir__simdf_store( output + 0, final ); - - h = _mm_unpackhi_epi16 ( i, _mm_setzero_si128() ); - expmant = _mm_and_si128(mnosign, h); - justsign = _mm_xor_si128(h, expmant); - b_notinfnan = _mm_cmpgt_epi32(infty, expmant); - b_isdenorm = _mm_cmpgt_epi32(smallest, expmant); - shifted = _mm_slli_epi32(expmant, 13); - adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust); - adjusted = _mm_add_epi32(eadjust, shifted); - den1 = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm)); - adjusted2 = _mm_add_epi32(adjusted, adj_infnan); - den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm); - adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm)); - adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2)); - adjusted5 = _mm_or_ps(adjusted3, adjusted4); - sign = _mm_slli_epi32(justsign, 16); - final = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign)); - stbir__simdf_store( output + 4, final ); - - // ~38 SSE2 ops for 8 values - } - - // Fabian's round-to-nearest-even float to half - // ~48 SSE2 ops for 8 output - stbir__inline static void stbir__float_to_half_SIMD(void * output, float const * input) - { - static const STBIR__SIMDI_CONST(mask_sign, 0x80000000u); - static const STBIR__SIMDI_CONST(c_f16max, (127 + 16) << 23); // all FP32 values >=this round to +inf - static const STBIR__SIMDI_CONST(c_nanbit, 0x200); - static const STBIR__SIMDI_CONST(c_infty_as_fp16, 0x7c00); - static const STBIR__SIMDI_CONST(c_min_normal, (127 - 14) << 23); // smallest FP32 that yields a normalized FP16 - static const STBIR__SIMDI_CONST(c_subnorm_magic, ((127 - 15) + (23 - 10) + 1) << 23); - static const STBIR__SIMDI_CONST(c_normal_bias, 0xfff - ((127 - 15) << 23)); // adjust exponent and add mantissa rounding - - __m128 f = _mm_loadu_ps(input); - __m128 msign = _mm_castsi128_ps(STBIR__CONSTI(mask_sign)); - __m128 justsign = _mm_and_ps(msign, f); - __m128 absf = _mm_xor_ps(f, justsign); - __m128i absf_int = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit) - __m128i f16max = STBIR__CONSTI(c_f16max); - __m128 b_isnan = _mm_cmpunord_ps(absf, absf); // is this a NaN? - __m128i b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special? - __m128i nanbit = _mm_and_si128(_mm_castps_si128(b_isnan), STBIR__CONSTI(c_nanbit)); - __m128i inf_or_nan = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials - - __m128i min_normal = STBIR__CONSTI(c_min_normal); - __m128i b_issub = _mm_cmpgt_epi32(min_normal, absf_int); - - // "result is subnormal" path - __m128 subnorm1 = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa - __m128i subnorm2 = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias - - // "result is normal" path - __m128i mantoddbit = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign - __m128i mantodd = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0 - - __m128i round1 = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias)); - __m128i round2 = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE) - __m128i normal = _mm_srli_epi32(round2, 13); // rounded result - - // combine the two non-specials - __m128i nonspecial = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal)); - - // merge in specials as well - __m128i joined = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan)); - - __m128i sign_shift = _mm_srai_epi32(_mm_castps_si128(justsign), 16); - __m128i final2, final= _mm_or_si128(joined, sign_shift); - - f = _mm_loadu_ps(input+4); - justsign = _mm_and_ps(msign, f); - absf = _mm_xor_ps(f, justsign); - absf_int = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit) - b_isnan = _mm_cmpunord_ps(absf, absf); // is this a NaN? - b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special? - nanbit = _mm_and_si128(_mm_castps_si128(b_isnan), c_nanbit); - inf_or_nan = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials - - b_issub = _mm_cmpgt_epi32(min_normal, absf_int); - - // "result is subnormal" path - subnorm1 = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa - subnorm2 = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias - - // "result is normal" path - mantoddbit = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign - mantodd = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0 - - round1 = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias)); - round2 = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE) - normal = _mm_srli_epi32(round2, 13); // rounded result - - // combine the two non-specials - nonspecial = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal)); - - // merge in specials as well - joined = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan)); - - sign_shift = _mm_srai_epi32(_mm_castps_si128(justsign), 16); - final2 = _mm_or_si128(joined, sign_shift); - final = _mm_packs_epi32(final, final2); - stbir__simdi_store( output,final ); - } - -#elif defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) // 64-bit ARM on MSVC (not clang) - - static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) - { - float16x4_t in0 = vld1_f16(input + 0); - float16x4_t in1 = vld1_f16(input + 4); - vst1q_f32(output + 0, vcvt_f32_f16(in0)); - vst1q_f32(output + 4, vcvt_f32_f16(in1)); - } - - static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) - { - float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0)); - float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4)); - vst1_f16(output+0, out0); - vst1_f16(output+4, out1); - } - - static stbir__inline float stbir__half_to_float( stbir__FP16 h ) - { - return vgetq_lane_f32(vcvt_f32_f16(vld1_dup_f16(&h)), 0); - } - - static stbir__inline stbir__FP16 stbir__float_to_half( float f ) - { - return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0]; - } - -#elif defined(STBIR_NEON) && ( defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) ) // 64-bit ARM - - static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) - { - float16x8_t in = vld1q_f16(input); - vst1q_f32(output + 0, vcvt_f32_f16(vget_low_f16(in))); - vst1q_f32(output + 4, vcvt_f32_f16(vget_high_f16(in))); - } - - static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) - { - float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0)); - float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4)); - vst1q_f16(output, vcombine_f16(out0, out1)); - } - - static stbir__inline float stbir__half_to_float( stbir__FP16 h ) - { - return vgetq_lane_f32(vcvt_f32_f16(vdup_n_f16(h)), 0); - } - - static stbir__inline stbir__FP16 stbir__float_to_half( float f ) - { - return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0); - } - -#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && (defined(_MSC_VER) || defined(_M_ARM) || defined(__arm__))) // WASM or 32-bit ARM on MSVC/clang - - static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) - { - for (int i=0; i<8; i++) - { - output[i] = stbir__half_to_float(input[i]); - } - } - static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) - { - for (int i=0; i<8; i++) - { - output[i] = stbir__float_to_half(input[i]); - } - } - -#endif - - -#ifdef STBIR_SIMD - -#define stbir__simdf_0123to3333( out, reg ) (out) = stbir__simdf_swiz( reg, 3,3,3,3 ) -#define stbir__simdf_0123to2222( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,2,2 ) -#define stbir__simdf_0123to1111( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,1,1 ) -#define stbir__simdf_0123to0000( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,0 ) -#define stbir__simdf_0123to0003( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,3 ) -#define stbir__simdf_0123to0001( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,1 ) -#define stbir__simdf_0123to1122( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,2,2 ) -#define stbir__simdf_0123to2333( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,3,3 ) -#define stbir__simdf_0123to0023( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,3 ) -#define stbir__simdf_0123to1230( out, reg ) (out) = stbir__simdf_swiz( reg, 1,2,3,0 ) -#define stbir__simdf_0123to2103( out, reg ) (out) = stbir__simdf_swiz( reg, 2,1,0,3 ) -#define stbir__simdf_0123to3210( out, reg ) (out) = stbir__simdf_swiz( reg, 3,2,1,0 ) -#define stbir__simdf_0123to2301( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,0,1 ) -#define stbir__simdf_0123to3012( out, reg ) (out) = stbir__simdf_swiz( reg, 3,0,1,2 ) -#define stbir__simdf_0123to0011( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,1,1 ) -#define stbir__simdf_0123to1100( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,0,0 ) -#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 ) -#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 ) -#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 ) -#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 ) - -typedef union stbir__simdi_u32 -{ - stbir_uint32 m128i_u32[4]; - int m128i_i32[4]; - stbir__simdi m128i_i128; -} stbir__simdi_u32; - -static const int STBIR_mask[9] = { 0,0,0,-1,-1,-1,0,0,0 }; - -static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float, stbir__max_uint8_as_float); -static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float, stbir__max_uint16_as_float); -static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float_inverted, stbir__max_uint8_as_float_inverted); -static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float_inverted, stbir__max_uint16_as_float_inverted); - -static const STBIR__SIMDF_CONST(STBIR_simd_point5, 0.5f); -static const STBIR__SIMDF_CONST(STBIR_ones, 1.0f); -static const STBIR__SIMDI_CONST(STBIR_almost_zero, (127 - 13) << 23); -static const STBIR__SIMDI_CONST(STBIR_almost_one, 0x3f7fffff); -static const STBIR__SIMDI_CONST(STBIR_mastissa_mask, 0xff); -static const STBIR__SIMDI_CONST(STBIR_topscale, 0x02000000); - -// Basically, in simd mode, we unroll the proper amount, and we don't want -// the non-simd remnant loops to be unroll because they only run a few times -// Adding this switch saves about 5K on clang which is Captain Unroll the 3rd. -#define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star ) -#define STBIR_SIMD_NO_UNROLL(ptr) STBIR_NO_UNROLL(ptr) -#define STBIR_SIMD_NO_UNROLL_LOOP_START STBIR_NO_UNROLL_LOOP_START -#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START_INF_FOR - -#ifdef STBIR_MEMCPY -#undef STBIR_MEMCPY -#endif -#define STBIR_MEMCPY stbir_simd_memcpy - -// override normal use of memcpy with much simpler copy (faster and smaller with our sized copies) -static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) -{ - char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest; - char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes; - ptrdiff_t ofs_to_src = (char*)src - (char*)dest; - - // check overlaps - STBIR_ASSERT( ( ( d >= ( (char*)src) + bytes ) ) || ( ( d + bytes ) <= (char*)src ) ); - - if ( bytes < (16*stbir__simdfX_float_count) ) - { - if ( bytes < 16 ) - { - if ( bytes ) - { - STBIR_SIMD_NO_UNROLL_LOOP_START - do - { - STBIR_SIMD_NO_UNROLL(d); - d[ 0 ] = d[ ofs_to_src ]; - ++d; - } while ( d < d_end ); - } - } - else - { - stbir__simdf x; - // do one unaligned to get us aligned for the stream out below - stbir__simdf_load( x, ( d + ofs_to_src ) ); - stbir__simdf_store( d, x ); - d = (char*)( ( ( (size_t)d ) + 16 ) & ~15 ); - - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - STBIR_SIMD_NO_UNROLL(d); - - if ( d > ( d_end - 16 ) ) - { - if ( d == d_end ) - return; - d = d_end - 16; - } - - stbir__simdf_load( x, ( d + ofs_to_src ) ); - stbir__simdf_store( d, x ); - d += 16; - } - } - } - else - { - stbir__simdfX x0,x1,x2,x3; - - // do one unaligned to get us aligned for the stream out below - stbir__simdfX_load( x0, ( d + ofs_to_src ) + 0*stbir__simdfX_float_count ); - stbir__simdfX_load( x1, ( d + ofs_to_src ) + 4*stbir__simdfX_float_count ); - stbir__simdfX_load( x2, ( d + ofs_to_src ) + 8*stbir__simdfX_float_count ); - stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count ); - stbir__simdfX_store( d + 0*stbir__simdfX_float_count, x0 ); - stbir__simdfX_store( d + 4*stbir__simdfX_float_count, x1 ); - stbir__simdfX_store( d + 8*stbir__simdfX_float_count, x2 ); - stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 ); - d = (char*)( ( ( (size_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) ); - - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - STBIR_SIMD_NO_UNROLL(d); - - if ( d > ( d_end - (16*stbir__simdfX_float_count) ) ) - { - if ( d == d_end ) - return; - d = d_end - (16*stbir__simdfX_float_count); - } - - stbir__simdfX_load( x0, ( d + ofs_to_src ) + 0*stbir__simdfX_float_count ); - stbir__simdfX_load( x1, ( d + ofs_to_src ) + 4*stbir__simdfX_float_count ); - stbir__simdfX_load( x2, ( d + ofs_to_src ) + 8*stbir__simdfX_float_count ); - stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count ); - stbir__simdfX_store( d + 0*stbir__simdfX_float_count, x0 ); - stbir__simdfX_store( d + 4*stbir__simdfX_float_count, x1 ); - stbir__simdfX_store( d + 8*stbir__simdfX_float_count, x2 ); - stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 ); - d += (16*stbir__simdfX_float_count); - } - } -} - -// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be -// a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to -// the diff between dest and src) -static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) -{ - char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src; - char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes; - ptrdiff_t ofs_to_dest = (char*)dest - (char*)src; - - if ( ofs_to_dest >= 16 ) // is the overlap more than 16 away? - { - char STBIR_SIMD_STREAMOUT_PTR( * ) s_end16 = ((char*) src) + (bytes&~15); - STBIR_SIMD_NO_UNROLL_LOOP_START - do - { - stbir__simdf x; - STBIR_SIMD_NO_UNROLL(sd); - stbir__simdf_load( x, sd ); - stbir__simdf_store( ( sd + ofs_to_dest ), x ); - sd += 16; - } while ( sd < s_end16 ); - - if ( sd == s_end ) - return; - } - - do - { - STBIR_SIMD_NO_UNROLL(sd); - *(int*)( sd + ofs_to_dest ) = *(int*) sd; - sd += 4; - } while ( sd < s_end ); -} - -#else // no SSE2 - -// when in scalar mode, we let unrolling happen, so this macro just does the __restrict -#define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star ) -#define STBIR_SIMD_NO_UNROLL(ptr) -#define STBIR_SIMD_NO_UNROLL_LOOP_START -#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - -#endif // SSE2 - - -#ifdef STBIR_PROFILE - -#ifndef STBIR_PROFILE_FUNC - -#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ ) - -#ifdef _MSC_VER - - STBIRDEF stbir_uint64 __rdtsc(); - #define STBIR_PROFILE_FUNC() __rdtsc() - -#else // non msvc - - static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() - { - stbir_uint32 lo, hi; - asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) ); - return ( ( (stbir_uint64) hi ) << 32 ) | ( (stbir_uint64) lo ); - } - -#endif // msvc - -#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) - -#if defined( _MSC_VER ) && !defined(__clang__) - - #define STBIR_PROFILE_FUNC() _ReadStatusReg(ARM64_CNTVCT) - -#else - - static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() - { - stbir_uint64 tsc; - asm volatile("mrs %0, cntvct_el0" : "=r" (tsc)); - return tsc; - } - -#endif - -#else // x64, arm - -#error Unknown platform for profiling. - -#endif // x64, arm - -#endif // STBIR_PROFILE_FUNC - -#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info -#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info - -#define STBIR_ONLY_PROFILE_BUILD_GET_INFO ,stbir__info * profile_info -#define STBIR_ONLY_PROFILE_BUILD_SET_INFO ,profile_info - -// super light-weight micro profiler -#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded; -#define STBIR_PROFILE_END_ll( info, wh ) wh##thiszonetime = STBIR_PROFILE_FUNC() - wh##thiszonetime; info->profile.named.wh += wh##thiszonetime - wh##current_zone_excluded; *wh##save_parent_excluded_ptr += wh##thiszonetime; info->current_zone_excluded_ptr = wh##save_parent_excluded_ptr; } -#define STBIR_PROFILE_FIRST_START_ll( info, wh ) { int i; info->current_zone_excluded_ptr = &info->profile.named.total; for(i=0;iprofile.array);i++) info->profile.array[i]=0; } STBIR_PROFILE_START_ll( info, wh ); -#define STBIR_PROFILE_CLEAR_EXTRAS_ll( info, num ) { int extra; for(extra=1;extra<(num);extra++) { int i; for(i=0;iprofile.array);i++) (info)[extra].profile.array[i]=0; } } - -// for thread data -#define STBIR_PROFILE_START( wh ) STBIR_PROFILE_START_ll( split_info, wh ) -#define STBIR_PROFILE_END( wh ) STBIR_PROFILE_END_ll( split_info, wh ) -#define STBIR_PROFILE_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( split_info, wh ) -#define STBIR_PROFILE_CLEAR_EXTRAS() STBIR_PROFILE_CLEAR_EXTRAS_ll( split_info, split_count ) - -// for build data -#define STBIR_PROFILE_BUILD_START( wh ) STBIR_PROFILE_START_ll( profile_info, wh ) -#define STBIR_PROFILE_BUILD_END( wh ) STBIR_PROFILE_END_ll( profile_info, wh ) -#define STBIR_PROFILE_BUILD_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( profile_info, wh ) -#define STBIR_PROFILE_BUILD_CLEAR( info ) { int i; for(i=0;iprofile.array);i++) info->profile.array[i]=0; } - -#else // no profile - -#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO -#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO - -#define STBIR_ONLY_PROFILE_BUILD_GET_INFO -#define STBIR_ONLY_PROFILE_BUILD_SET_INFO - -#define STBIR_PROFILE_START( wh ) -#define STBIR_PROFILE_END( wh ) -#define STBIR_PROFILE_FIRST_START( wh ) -#define STBIR_PROFILE_CLEAR_EXTRAS( ) - -#define STBIR_PROFILE_BUILD_START( wh ) -#define STBIR_PROFILE_BUILD_END( wh ) -#define STBIR_PROFILE_BUILD_FIRST_START( wh ) -#define STBIR_PROFILE_BUILD_CLEAR( info ) - -#endif // stbir_profile - -#ifndef STBIR_CEILF -#include -#if _MSC_VER <= 1200 // support VC6 for Sean -#define STBIR_CEILF(x) ((float)ceil((float)(x))) -#define STBIR_FLOORF(x) ((float)floor((float)(x))) -#else -#define STBIR_CEILF(x) ceilf(x) -#define STBIR_FLOORF(x) floorf(x) -#endif -#endif - -#ifndef STBIR_MEMCPY -// For memcpy -#include -#define STBIR_MEMCPY( dest, src, len ) memcpy( dest, src, len ) -#endif - -#ifndef STBIR_SIMD - -// memcpy that is specifically intentionally overlapping (src is smaller then dest, so can be -// a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to -// the diff between dest and src) -static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) -{ - char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src; - char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes; - ptrdiff_t ofs_to_dest = (char*)dest - (char*)src; - - if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away? - { - char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7); - STBIR_NO_UNROLL_LOOP_START - do - { - STBIR_NO_UNROLL(sd); - *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd; - sd += 8; - } while ( sd < s_end8 ); - - if ( sd == s_end ) - return; - } - - STBIR_NO_UNROLL_LOOP_START - do - { - STBIR_NO_UNROLL(sd); - *(int*)( sd + ofs_to_dest ) = *(int*) sd; - sd += 4; - } while ( sd < s_end ); -} - -#endif - -static float stbir__filter_trapezoid(float x, float scale, void * user_data) -{ - float halfscale = scale / 2; - float t = 0.5f + halfscale; - STBIR_ASSERT(scale <= 1); - STBIR__UNUSED(user_data); - - if ( x < 0.0f ) x = -x; - - if (x >= t) - return 0.0f; - else - { - float r = 0.5f - halfscale; - if (x <= r) - return 1.0f; - else - return (t - x) / scale; - } -} - -static float stbir__support_trapezoid(float scale, void * user_data) -{ - STBIR__UNUSED(user_data); - return 0.5f + scale / 2.0f; -} - -static float stbir__filter_triangle(float x, float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - - if ( x < 0.0f ) x = -x; - - if (x <= 1.0f) - return 1.0f - x; - else - return 0.0f; -} - -static float stbir__filter_point(float x, float s, void * user_data) -{ - STBIR__UNUSED(x); - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - - return 1.0f; -} - -static float stbir__filter_cubic(float x, float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - - if ( x < 0.0f ) x = -x; - - if (x < 1.0f) - return (4.0f + x*x*(3.0f*x - 6.0f))/6.0f; - else if (x < 2.0f) - return (8.0f + x*(-12.0f + x*(6.0f - x)))/6.0f; - - return (0.0f); -} - -static float stbir__filter_catmullrom(float x, float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - - if ( x < 0.0f ) x = -x; - - if (x < 1.0f) - return 1.0f - x*x*(2.5f - 1.5f*x); - else if (x < 2.0f) - return 2.0f - x*(4.0f + x*(0.5f*x - 2.5f)); - - return (0.0f); -} - -static float stbir__filter_mitchell(float x, float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - - if ( x < 0.0f ) x = -x; - - if (x < 1.0f) - return (16.0f + x*x*(21.0f * x - 36.0f))/18.0f; - else if (x < 2.0f) - return (32.0f + x*(-60.0f + x*(36.0f - 7.0f*x)))/18.0f; - - return (0.0f); -} - -static float stbir__support_zeropoint5(float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - return 0.5f; -} - -static float stbir__support_one(float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - return 1; -} - -static float stbir__support_two(float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - return 2; -} - -// This is the maximum number of input samples that can affect an output sample -// with the given filter from the output pixel's perspective -static int stbir__get_filter_pixel_width(stbir__support_callback * support, float scale, void * user_data) -{ - STBIR_ASSERT(support != 0); - - if ( scale >= ( 1.0f-stbir__small_float ) ) // upscale - return (int)STBIR_CEILF(support(1.0f/scale,user_data) * 2.0f); - else - return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale); -} - -// this is how many coefficents per run of the filter (which is different -// from the filter_pixel_width depending on if we are scattering or gathering) -static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, void * user_data) -{ - float scale = samp->scale_info.scale; - stbir__support_callback * support = samp->filter_support; - - switch( is_gather ) - { - case 1: - return (int)STBIR_CEILF(support(1.0f / scale, user_data) * 2.0f); - case 2: - return (int)STBIR_CEILF(support(scale, user_data) * 2.0f / scale); - case 0: - return (int)STBIR_CEILF(support(scale, user_data) * 2.0f); - default: - STBIR_ASSERT( (is_gather >= 0 ) && (is_gather <= 2 ) ); - return 0; - } -} - -static int stbir__get_contributors(stbir__sampler * samp, int is_gather) -{ - if (is_gather) - return samp->scale_info.output_sub_size; - else - return (samp->scale_info.input_full_size + samp->filter_pixel_margin * 2); -} - -static int stbir__edge_zero_full( int n, int max ) -{ - STBIR__UNUSED(n); - STBIR__UNUSED(max); - return 0; // NOTREACHED -} - -static int stbir__edge_clamp_full( int n, int max ) -{ - if (n < 0) - return 0; - - if (n >= max) - return max - 1; - - return n; // NOTREACHED -} - -static int stbir__edge_reflect_full( int n, int max ) -{ - if (n < 0) - { - if (n > -max) - return -n; - else - return max - 1; - } - - if (n >= max) - { - int max2 = max * 2; - if (n >= max2) - return 0; - else - return max2 - n - 1; - } - - return n; // NOTREACHED -} - -static int stbir__edge_wrap_full( int n, int max ) -{ - if (n >= 0) - return (n % max); - else - { - int m = (-n) % max; - - if (m != 0) - m = max - m; - - return (m); - } -} - -typedef int stbir__edge_wrap_func( int n, int max ); -static stbir__edge_wrap_func * stbir__edge_wrap_slow[] = -{ - stbir__edge_clamp_full, // STBIR_EDGE_CLAMP - stbir__edge_reflect_full, // STBIR_EDGE_REFLECT - stbir__edge_wrap_full, // STBIR_EDGE_WRAP - stbir__edge_zero_full, // STBIR_EDGE_ZERO -}; - -stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) -{ - // avoid per-pixel switch - if (n >= 0 && n < max) - return n; - return stbir__edge_wrap_slow[edge]( n, max ); -} - -#define STBIR__MERGE_RUNS_PIXEL_THRESHOLD 16 - -// get information on the extents of a sampler -static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline_extents ) -{ - int j, stop; - int left_margin, right_margin; - int min_n = 0x7fffffff, max_n = -0x7fffffff; - int min_left = 0x7fffffff, max_left = -0x7fffffff; - int min_right = 0x7fffffff, max_right = -0x7fffffff; - stbir_edge edge = samp->edge; - stbir__contributors* contributors = samp->contributors; - int output_sub_size = samp->scale_info.output_sub_size; - int input_full_size = samp->scale_info.input_full_size; - int filter_pixel_margin = samp->filter_pixel_margin; - - STBIR_ASSERT( samp->is_gather ); - - stop = output_sub_size; - for (j = 0; j < stop; j++ ) - { - STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 ); - if ( contributors[j].n0 < min_n ) - { - min_n = contributors[j].n0; - stop = j + filter_pixel_margin; // if we find a new min, only scan another filter width - if ( stop > output_sub_size ) stop = output_sub_size; - } - } - - stop = 0; - for (j = output_sub_size - 1; j >= stop; j-- ) - { - STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 ); - if ( contributors[j].n1 > max_n ) - { - max_n = contributors[j].n1; - stop = j - filter_pixel_margin; // if we find a new max, only scan another filter width - if (stop<0) stop = 0; - } - } - - STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n ); - STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n ); - - // now calculate how much into the margins we really read - left_margin = 0; - if ( min_n < 0 ) - { - left_margin = -min_n; - min_n = 0; - } - - right_margin = 0; - if ( max_n >= input_full_size ) - { - right_margin = max_n - input_full_size + 1; - max_n = input_full_size - 1; - } - - // index 1 is margin pixel extents (how many pixels we hang over the edge) - scanline_extents->edge_sizes[0] = left_margin; - scanline_extents->edge_sizes[1] = right_margin; - - // index 2 is pixels read from the input - scanline_extents->spans[0].n0 = min_n; - scanline_extents->spans[0].n1 = max_n; - scanline_extents->spans[0].pixel_offset_for_input = min_n; - - // default to no other input range - scanline_extents->spans[1].n0 = 0; - scanline_extents->spans[1].n1 = -1; - scanline_extents->spans[1].pixel_offset_for_input = 0; - - // don't have to do edge calc for zero clamp - if ( edge == STBIR_EDGE_ZERO ) - return; - - // convert margin pixels to the pixels within the input (min and max) - for( j = -left_margin ; j < 0 ; j++ ) - { - int p = stbir__edge_wrap( edge, j, input_full_size ); - if ( p < min_left ) - min_left = p; - if ( p > max_left ) - max_left = p; - } - - for( j = input_full_size ; j < (input_full_size + right_margin) ; j++ ) - { - int p = stbir__edge_wrap( edge, j, input_full_size ); - if ( p < min_right ) - min_right = p; - if ( p > max_right ) - max_right = p; - } - - // merge the left margin pixel region if it connects within 4 pixels of main pixel region - if ( min_left != 0x7fffffff ) - { - if ( ( ( min_left <= min_n ) && ( ( max_left + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) || - ( ( min_n <= min_left ) && ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_left ) ) ) - { - scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_left ); - scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_left ); - scanline_extents->spans[0].pixel_offset_for_input = min_n; - left_margin = 0; - } - } - - // merge the right margin pixel region if it connects within 4 pixels of main pixel region - if ( min_right != 0x7fffffff ) - { - if ( ( ( min_right <= min_n ) && ( ( max_right + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) || - ( ( min_n <= min_right ) && ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_right ) ) ) - { - scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_right ); - scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_right ); - scanline_extents->spans[0].pixel_offset_for_input = min_n; - right_margin = 0; - } - } - - STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n ); - STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n ); - - // you get two ranges when you have the WRAP edge mode and you are doing just the a piece of the resize - // so you need to get a second run of pixels from the opposite side of the scanline (which you - // wouldn't need except for WRAP) - - - // if we can't merge the min_left range, add it as a second range - if ( ( left_margin ) && ( min_left != 0x7fffffff ) ) - { - stbir__span * newspan = scanline_extents->spans + 1; - STBIR_ASSERT( right_margin == 0 ); - if ( min_left < scanline_extents->spans[0].n0 ) - { - scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0; - scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0; - scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1; - --newspan; - } - newspan->pixel_offset_for_input = min_left; - newspan->n0 = -left_margin; - newspan->n1 = ( max_left - min_left ) - left_margin; - scanline_extents->edge_sizes[0] = 0; // don't need to copy the left margin, since we are directly decoding into the margin - return; - } - - // if we can't merge the min_left range, add it as a second range - if ( ( right_margin ) && ( min_right != 0x7fffffff ) ) - { - stbir__span * newspan = scanline_extents->spans + 1; - if ( min_right < scanline_extents->spans[0].n0 ) - { - scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0; - scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0; - scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1; - --newspan; - } - newspan->pixel_offset_for_input = min_right; - newspan->n0 = scanline_extents->spans[1].n1 + 1; - newspan->n1 = scanline_extents->spans[1].n1 + 1 + ( max_right - min_right ); - scanline_extents->edge_sizes[1] = 0; // don't need to copy the right margin, since we are directly decoding into the margin - return; - } -} - -static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel, float out_pixel_center, float out_filter_radius, float inv_scale, float out_shift, int input_size, stbir_edge edge ) -{ - int first, last; - float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; - float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; - - float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale; - float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale; - - first = (int)(STBIR_FLOORF(in_pixel_influence_lowerbound + 0.5f)); - last = (int)(STBIR_FLOORF(in_pixel_influence_upperbound - 0.5f)); - if ( last < first ) last = first; // point sample mode can span a value *right* at 0.5, and cause these to cross - - if ( edge == STBIR_EDGE_WRAP ) - { - if ( first < -input_size ) - first = -input_size; - if ( last >= (input_size*2)) - last = (input_size*2) - 1; - } - - *first_pixel = first; - *last_pixel = last; -} - -static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float* coefficient_group, int coefficient_width, stbir_edge edge, void * user_data ) -{ - int n, end; - float inv_scale = scale_info->inv_scale; - float out_shift = scale_info->pixel_shift; - int input_size = scale_info->input_full_size; - int numerator = scale_info->scale_numerator; - int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) ); - - // Looping through out pixels - end = num_contributors; if ( polyphase ) end = numerator; - for (n = 0; n < end; n++) - { - int i; - int last_non_zero; - float out_pixel_center = (float)n + 0.5f; - float in_center_of_out = (out_pixel_center + out_shift) * inv_scale; - - int in_first_pixel, in_last_pixel; - - stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, out_pixel_center, out_filter_radius, inv_scale, out_shift, input_size, edge ); - - // make sure we never generate a range larger than our precalculated coeff width - // this only happens in point sample mode, but it's a good safe thing to do anyway - if ( ( in_last_pixel - in_first_pixel + 1 ) > coefficient_width ) - in_last_pixel = in_first_pixel + coefficient_width - 1; - - last_non_zero = -1; - for (i = 0; i <= in_last_pixel - in_first_pixel; i++) - { - float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; - float coeff = kernel(in_center_of_out - in_pixel_center, inv_scale, user_data); - - // kill denormals - if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) ) - { - if ( i == 0 ) // if we're at the front, just eat zero contributors - { - STBIR_ASSERT ( ( in_last_pixel - in_first_pixel ) != 0 ); // there should be at least one contrib - ++in_first_pixel; - i--; - continue; - } - coeff = 0; // make sure is fully zero (should keep denormals away) - } - else - last_non_zero = i; - - coefficient_group[i] = coeff; - } - - in_last_pixel = last_non_zero+in_first_pixel; // kills trailing zeros - contributors->n0 = in_first_pixel; - contributors->n1 = in_last_pixel; - - STBIR_ASSERT(contributors->n1 >= contributors->n0); - - ++contributors; - coefficient_group += coefficient_width; - } -} - -static void stbir__insert_coeff( stbir__contributors * contribs, float * coeffs, int new_pixel, float new_coeff, int max_width ) -{ - if ( new_pixel <= contribs->n1 ) // before the end - { - if ( new_pixel < contribs->n0 ) // before the front? - { - if ( ( contribs->n1 - new_pixel + 1 ) <= max_width ) - { - int j, o = contribs->n0 - new_pixel; - for ( j = contribs->n1 - contribs->n0 ; j <= 0 ; j-- ) - coeffs[ j + o ] = coeffs[ j ]; - for ( j = 1 ; j < o ; j-- ) - coeffs[ j ] = coeffs[ 0 ]; - coeffs[ 0 ] = new_coeff; - contribs->n0 = new_pixel; - } - } - else - { - coeffs[ new_pixel - contribs->n0 ] += new_coeff; - } - } - else - { - if ( ( new_pixel - contribs->n0 + 1 ) <= max_width ) - { - int j, e = new_pixel - contribs->n0; - for( j = ( contribs->n1 - contribs->n0 ) + 1 ; j < e ; j++ ) // clear in-betweens coeffs if there are any - coeffs[j] = 0; - - coeffs[ e ] = new_coeff; - contribs->n1 = new_pixel; - } - } -} - -static void stbir__calculate_out_pixel_range( int * first_pixel, int * last_pixel, float in_pixel_center, float in_pixels_radius, float scale, float out_shift, int out_size ) -{ - float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; - float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; - float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale - out_shift; - float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale - out_shift; - int out_first_pixel = (int)(STBIR_FLOORF(out_pixel_influence_lowerbound + 0.5f)); - int out_last_pixel = (int)(STBIR_FLOORF(out_pixel_influence_upperbound - 0.5f)); - - if ( out_first_pixel < 0 ) - out_first_pixel = 0; - if ( out_last_pixel >= out_size ) - out_last_pixel = out_size - 1; - *first_pixel = out_first_pixel; - *last_pixel = out_last_pixel; -} - -static void stbir__calculate_coefficients_for_gather_downsample( int start, int end, float in_pixels_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int coefficient_width, int num_contributors, stbir__contributors * contributors, float * coefficient_group, void * user_data ) -{ - int in_pixel; - int i; - int first_out_inited = -1; - float scale = scale_info->scale; - float out_shift = scale_info->pixel_shift; - int out_size = scale_info->output_sub_size; - int numerator = scale_info->scale_numerator; - int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < out_size ) ); - - STBIR__UNUSED(num_contributors); - - // Loop through the input pixels - for (in_pixel = start; in_pixel < end; in_pixel++) - { - float in_pixel_center = (float)in_pixel + 0.5f; - float out_center_of_in = in_pixel_center * scale - out_shift; - int out_first_pixel, out_last_pixel; - - stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, in_pixel_center, in_pixels_radius, scale, out_shift, out_size ); - - if ( out_first_pixel > out_last_pixel ) - continue; - - // clamp or exit if we are using polyphase filtering, and the limit is up - if ( polyphase ) - { - // when polyphase, you only have to do coeffs up to the numerator count - if ( out_first_pixel == numerator ) - break; - - // don't do any extra work, clamp last pixel at numerator too - if ( out_last_pixel >= numerator ) - out_last_pixel = numerator - 1; - } - - for (i = 0; i <= out_last_pixel - out_first_pixel; i++) - { - float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; - float x = out_pixel_center - out_center_of_in; - float coeff = kernel(x, scale, user_data) * scale; - - // kill the coeff if it's too small (avoid denormals) - if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) ) - coeff = 0.0f; - - { - int out = i + out_first_pixel; - float * coeffs = coefficient_group + out * coefficient_width; - stbir__contributors * contribs = contributors + out; - - // is this the first time this output pixel has been seen? Init it. - if ( out > first_out_inited ) - { - STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time - first_out_inited = out; - contribs->n0 = in_pixel; - contribs->n1 = in_pixel; - coeffs[0] = coeff; - } - else - { - // insert on end (always in order) - if ( coeffs[0] == 0.0f ) // if the first coefficent is zero, then zap it for this coeffs - { - STBIR_ASSERT( ( in_pixel - contribs->n0 ) == 1 ); // ensure that when we zap, we're at the 2nd pos - contribs->n0 = in_pixel; - } - contribs->n1 = in_pixel; - STBIR_ASSERT( ( in_pixel - contribs->n0 ) < coefficient_width ); - coeffs[in_pixel - contribs->n0] = coeff; - } - } - } - } -} - -#ifdef STBIR_RENORMALIZE_IN_FLOAT -#define STBIR_RENORM_TYPE float -#else -#define STBIR_RENORM_TYPE double -#endif - -static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter_extent_info* filter_info, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float * coefficient_group, int coefficient_width ) -{ - int input_size = scale_info->input_full_size; - int input_last_n1 = input_size - 1; - int n, end; - int lowest = 0x7fffffff; - int highest = -0x7fffffff; - int widest = -1; - int numerator = scale_info->scale_numerator; - int denominator = scale_info->scale_denominator; - int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) ); - float * coeffs; - stbir__contributors * contribs; - - // weight all the coeffs for each sample - coeffs = coefficient_group; - contribs = contributors; - end = num_contributors; if ( polyphase ) end = numerator; - for (n = 0; n < end; n++) - { - int i; - STBIR_RENORM_TYPE filter_scale, total_filter = 0; - int e; - - // add all contribs - e = contribs->n1 - contribs->n0; - for( i = 0 ; i <= e ; i++ ) - { - total_filter += (STBIR_RENORM_TYPE) coeffs[i]; - STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f ) ); // check for wonky weights - } - - // rescale - if ( ( total_filter < stbir__small_float ) && ( total_filter > -stbir__small_float ) ) - { - // all coeffs are extremely small, just zero it - contribs->n1 = contribs->n0; - coeffs[0] = 0.0f; - } - else - { - // if the total isn't 1.0, rescale everything - if ( ( total_filter < (1.0f-stbir__small_float) ) || ( total_filter > (1.0f+stbir__small_float) ) ) - { - filter_scale = ((STBIR_RENORM_TYPE)1.0) / total_filter; - - // scale them all - for (i = 0; i <= e; i++) - coeffs[i] = (float) ( coeffs[i] * filter_scale ); - } - } - ++contribs; - coeffs += coefficient_width; - } - - // if we have a rational for the scale, we can exploit the polyphaseness to not calculate - // most of the coefficients, so we copy them here - if ( polyphase ) - { - stbir__contributors * prev_contribs = contributors; - stbir__contributors * cur_contribs = contributors + numerator; - - for( n = numerator ; n < num_contributors ; n++ ) - { - cur_contribs->n0 = prev_contribs->n0 + denominator; - cur_contribs->n1 = prev_contribs->n1 + denominator; - ++cur_contribs; - ++prev_contribs; - } - stbir_overlapping_memcpy( coefficient_group + numerator * coefficient_width, coefficient_group, ( num_contributors - numerator ) * coefficient_width * sizeof( coeffs[ 0 ] ) ); - } - - coeffs = coefficient_group; - contribs = contributors; - - for (n = 0; n < num_contributors; n++) - { - int i; - - // in zero edge mode, just remove out of bounds contribs completely (since their weights are accounted for now) - if ( edge == STBIR_EDGE_ZERO ) - { - // shrink the right side if necessary - if ( contribs->n1 > input_last_n1 ) - contribs->n1 = input_last_n1; - - // shrink the left side - if ( contribs->n0 < 0 ) - { - int j, left, skips = 0; - - skips = -contribs->n0; - contribs->n0 = 0; - - // now move down the weights - left = contribs->n1 - contribs->n0 + 1; - if ( left > 0 ) - { - for( j = 0 ; j < left ; j++ ) - coeffs[ j ] = coeffs[ j + skips ]; - } - } - } - else if ( ( edge == STBIR_EDGE_CLAMP ) || ( edge == STBIR_EDGE_REFLECT ) ) - { - // for clamp and reflect, calculate the true inbounds position (based on edge type) and just add that to the existing weight - - // right hand side first - if ( contribs->n1 > input_last_n1 ) - { - int start = contribs->n0; - int endi = contribs->n1; - contribs->n1 = input_last_n1; - for( i = input_size; i <= endi; i++ ) - stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start], coefficient_width ); - } - - // now check left hand edge - if ( contribs->n0 < 0 ) - { - int save_n0; - float save_n0_coeff; - float * c = coeffs - ( contribs->n0 + 1 ); - - // reinsert the coeffs with it reflected or clamped (insert accumulates, if the coeffs exist) - for( i = -1 ; i > contribs->n0 ; i-- ) - stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), *c--, coefficient_width ); - save_n0 = contribs->n0; - save_n0_coeff = c[0]; // save it, since we didn't do the final one (i==n0), because there might be too many coeffs to hold (before we resize)! - - // now slide all the coeffs down (since we have accumulated them in the positive contribs) and reset the first contrib - contribs->n0 = 0; - for(i = 0 ; i <= contribs->n1 ; i++ ) - coeffs[i] = coeffs[i-save_n0]; - - // now that we have shrunk down the contribs, we insert the first one safely - stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( save_n0, input_size ), save_n0_coeff, coefficient_width ); - } - } - - if ( contribs->n0 <= contribs->n1 ) - { - int diff = contribs->n1 - contribs->n0 + 1; - while ( diff && ( coeffs[ diff-1 ] == 0.0f ) ) - --diff; - - contribs->n1 = contribs->n0 + diff - 1; - - if ( contribs->n0 <= contribs->n1 ) - { - if ( contribs->n0 < lowest ) - lowest = contribs->n0; - if ( contribs->n1 > highest ) - highest = contribs->n1; - if ( diff > widest ) - widest = diff; - } - - // re-zero out unused coefficients (if any) - for( i = diff ; i < coefficient_width ; i++ ) - coeffs[i] = 0.0f; - } - - ++contribs; - coeffs += coefficient_width; - } - filter_info->lowest = lowest; - filter_info->highest = highest; - filter_info->widest = widest; -} - -#undef STBIR_RENORM_TYPE - -static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row0, int row1 ) -{ - #define STBIR_MOVE_1( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint32*)(dest))[0] = ((stbir_uint32*)(src))[0]; } - #define STBIR_MOVE_2( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; } - #ifdef STBIR_SIMD - #define STBIR_MOVE_4( dest, src ) { stbir__simdf t; STBIR_NO_UNROLL(dest); stbir__simdf_load( t, src ); stbir__simdf_store( dest, t ); } - #else - #define STBIR_MOVE_4( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; ((stbir_uint64*)(dest))[1] = ((stbir_uint64*)(src))[1]; } - #endif - - int row_end = row1 + 1; - STBIR__UNUSED( row0 ); // only used in an assert - - if ( coefficient_width != widest ) - { - float * pc = coefficents; - float * coeffs = coefficents; - float * pc_end = coefficents + num_contributors * widest; - switch( widest ) - { - case 1: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_1( pc, coeffs ); - ++pc; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 2: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_2( pc, coeffs ); - pc += 2; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 3: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_2( pc, coeffs ); - STBIR_MOVE_1( pc+2, coeffs+2 ); - pc += 3; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 4: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - pc += 4; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 5: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_1( pc+4, coeffs+4 ); - pc += 5; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 6: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_2( pc+4, coeffs+4 ); - pc += 6; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 7: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_2( pc+4, coeffs+4 ); - STBIR_MOVE_1( pc+6, coeffs+6 ); - pc += 7; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 8: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_4( pc+4, coeffs+4 ); - pc += 8; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 9: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_4( pc+4, coeffs+4 ); - STBIR_MOVE_1( pc+8, coeffs+8 ); - pc += 9; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 10: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_4( pc+4, coeffs+4 ); - STBIR_MOVE_2( pc+8, coeffs+8 ); - pc += 10; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 11: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_4( pc+4, coeffs+4 ); - STBIR_MOVE_2( pc+8, coeffs+8 ); - STBIR_MOVE_1( pc+10, coeffs+10 ); - pc += 11; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - case 12: - STBIR_NO_UNROLL_LOOP_START - do { - STBIR_MOVE_4( pc, coeffs ); - STBIR_MOVE_4( pc+4, coeffs+4 ); - STBIR_MOVE_4( pc+8, coeffs+8 ); - pc += 12; - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - default: - STBIR_NO_UNROLL_LOOP_START - do { - float * copy_end = pc + widest - 4; - float * c = coeffs; - do { - STBIR_NO_UNROLL( pc ); - STBIR_MOVE_4( pc, c ); - pc += 4; - c += 4; - } while ( pc <= copy_end ); - copy_end += 4; - STBIR_NO_UNROLL_LOOP_START - while ( pc < copy_end ) - { - STBIR_MOVE_1( pc, c ); - ++pc; ++c; - } - coeffs += coefficient_width; - } while ( pc < pc_end ); - break; - } - } - - // some horizontal routines read one float off the end (which is then masked off), so put in a sentinal so we don't read an snan or denormal - coefficents[ widest * num_contributors ] = 8888.0f; - - // the minimum we might read for unrolled filters widths is 12. So, we need to - // make sure we never read outside the decode buffer, by possibly moving - // the sample area back into the scanline, and putting zeros weights first. - // we start on the right edge and check until we're well past the possible - // clip area (2*widest). - { - stbir__contributors * contribs = contributors + num_contributors - 1; - float * coeffs = coefficents + widest * ( num_contributors - 1 ); - - // go until no chance of clipping (this is usually less than 8 lops) - while ( ( contribs >= contributors ) && ( ( contribs->n0 + widest*2 ) >= row_end ) ) - { - // might we clip?? - if ( ( contribs->n0 + widest ) > row_end ) - { - int stop_range = widest; - - // if range is larger than 12, it will be handled by generic loops that can terminate on the exact length - // of this contrib n1, instead of a fixed widest amount - so calculate this - if ( widest > 12 ) - { - int mod; - - // how far will be read in the n_coeff loop (which depends on the widest count mod4); - mod = widest & 3; - stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; - - // the n_coeff loops do a minimum amount of coeffs, so factor that in! - if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod; - } - - // now see if we still clip with the refined range - if ( ( contribs->n0 + stop_range ) > row_end ) - { - int new_n0 = row_end - stop_range; - int num = contribs->n1 - contribs->n0 + 1; - int backup = contribs->n0 - new_n0; - float * from_co = coeffs + num - 1; - float * to_co = from_co + backup; - - STBIR_ASSERT( ( new_n0 >= row0 ) && ( new_n0 < contribs->n0 ) ); - - // move the coeffs over - while( num ) - { - *to_co-- = *from_co--; - --num; - } - // zero new positions - while ( to_co >= coeffs ) - *to_co-- = 0; - // set new start point - contribs->n0 = new_n0; - if ( widest > 12 ) - { - int mod; - - // how far will be read in the n_coeff loop (which depends on the widest count mod4); - mod = widest & 3; - stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; - - // the n_coeff loops do a minimum amount of coeffs, so factor that in! - if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod; - } - } - } - --contribs; - coeffs -= widest; - } - } - - return widest; - #undef STBIR_MOVE_1 - #undef STBIR_MOVE_2 - #undef STBIR_MOVE_4 -} - -static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * other_axis_for_pivot, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO ) -{ - int n; - float scale = samp->scale_info.scale; - stbir__kernel_callback * kernel = samp->filter_kernel; - stbir__support_callback * support = samp->filter_support; - float inv_scale = samp->scale_info.inv_scale; - int input_full_size = samp->scale_info.input_full_size; - int gather_num_contributors = samp->num_contributors; - stbir__contributors* gather_contributors = samp->contributors; - float * gather_coeffs = samp->coefficients; - int gather_coefficient_width = samp->coefficient_width; - - switch ( samp->is_gather ) - { - case 1: // gather upsample - { - float out_pixels_radius = support(inv_scale,user_data) * scale; - - stbir__calculate_coefficients_for_gather_upsample( out_pixels_radius, kernel, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width, samp->edge, user_data ); - - STBIR_PROFILE_BUILD_START( cleanup ); - stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width ); - STBIR_PROFILE_BUILD_END( cleanup ); - } - break; - - case 0: // scatter downsample (only on vertical) - case 2: // gather downsample - { - float in_pixels_radius = support(scale,user_data) * inv_scale; - int filter_pixel_margin = samp->filter_pixel_margin; - int input_end = input_full_size + filter_pixel_margin; - - // if this is a scatter, we do a downsample gather to get the coeffs, and then pivot after - if ( !samp->is_gather ) - { - // check if we are using the same gather downsample on the horizontal as this vertical, - // if so, then we don't have to generate them, we can just pivot from the horizontal. - if ( other_axis_for_pivot ) - { - gather_contributors = other_axis_for_pivot->contributors; - gather_coeffs = other_axis_for_pivot->coefficients; - gather_coefficient_width = other_axis_for_pivot->coefficient_width; - gather_num_contributors = other_axis_for_pivot->num_contributors; - samp->extent_info.lowest = other_axis_for_pivot->extent_info.lowest; - samp->extent_info.highest = other_axis_for_pivot->extent_info.highest; - samp->extent_info.widest = other_axis_for_pivot->extent_info.widest; - goto jump_right_to_pivot; - } - - gather_contributors = samp->gather_prescatter_contributors; - gather_coeffs = samp->gather_prescatter_coefficients; - gather_coefficient_width = samp->gather_prescatter_coefficient_width; - gather_num_contributors = samp->gather_prescatter_num_contributors; - } - - stbir__calculate_coefficients_for_gather_downsample( -filter_pixel_margin, input_end, in_pixels_radius, kernel, &samp->scale_info, gather_coefficient_width, gather_num_contributors, gather_contributors, gather_coeffs, user_data ); - - STBIR_PROFILE_BUILD_START( cleanup ); - stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width ); - STBIR_PROFILE_BUILD_END( cleanup ); - - if ( !samp->is_gather ) - { - // if this is a scatter (vertical only), then we need to pivot the coeffs - stbir__contributors * scatter_contributors; - int highest_set; - - jump_right_to_pivot: - - STBIR_PROFILE_BUILD_START( pivot ); - - highest_set = (-filter_pixel_margin) - 1; - for (n = 0; n < gather_num_contributors; n++) - { - int k; - int gn0 = gather_contributors->n0, gn1 = gather_contributors->n1; - int scatter_coefficient_width = samp->coefficient_width; - float * scatter_coeffs = samp->coefficients + ( gn0 + filter_pixel_margin ) * scatter_coefficient_width; - float * g_coeffs = gather_coeffs; - scatter_contributors = samp->contributors + ( gn0 + filter_pixel_margin ); - - for (k = gn0 ; k <= gn1 ; k++ ) - { - float gc = *g_coeffs++; - - // skip zero and denormals - must skip zeros to avoid adding coeffs beyond scatter_coefficient_width - // (which happens when pivoting from horizontal, which might have dummy zeros) - if ( ( ( gc >= stbir__small_float ) || ( gc <= -stbir__small_float ) ) ) - { - if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) ) - { - { - // if we are skipping over several contributors, we need to clear the skipped ones - stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1); - while ( clear_contributors < scatter_contributors ) - { - clear_contributors->n0 = 0; - clear_contributors->n1 = -1; - ++clear_contributors; - } - } - scatter_contributors->n0 = n; - scatter_contributors->n1 = n; - scatter_coeffs[0] = gc; - highest_set = k; - } - else - { - stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc, scatter_coefficient_width ); - } - STBIR_ASSERT( ( scatter_contributors->n1 - scatter_contributors->n0 + 1 ) <= scatter_coefficient_width ); - } - ++scatter_contributors; - scatter_coeffs += scatter_coefficient_width; - } - - ++gather_contributors; - gather_coeffs += gather_coefficient_width; - } - - // now clear any unset contribs - { - stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1); - stbir__contributors * end_contributors = samp->contributors + samp->num_contributors; - while ( clear_contributors < end_contributors ) - { - clear_contributors->n0 = 0; - clear_contributors->n1 = -1; - ++clear_contributors; - } - } - - STBIR_PROFILE_BUILD_END( pivot ); - } - } - break; - } -} - - -//======================================================================================================== -// scanline decoders and encoders - -#define stbir__coder_min_num 1 -#define STB_IMAGE_RESIZE_DO_CODERS -#include STBIR__HEADER_FILENAME - -#define stbir__decode_suffix BGRA -#define stbir__decode_swizzle -#define stbir__decode_order0 2 -#define stbir__decode_order1 1 -#define stbir__decode_order2 0 -#define stbir__decode_order3 3 -#define stbir__encode_order0 2 -#define stbir__encode_order1 1 -#define stbir__encode_order2 0 -#define stbir__encode_order3 3 -#define stbir__coder_min_num 4 -#define STB_IMAGE_RESIZE_DO_CODERS -#include STBIR__HEADER_FILENAME - -#define stbir__decode_suffix ARGB -#define stbir__decode_swizzle -#define stbir__decode_order0 1 -#define stbir__decode_order1 2 -#define stbir__decode_order2 3 -#define stbir__decode_order3 0 -#define stbir__encode_order0 3 -#define stbir__encode_order1 0 -#define stbir__encode_order2 1 -#define stbir__encode_order3 2 -#define stbir__coder_min_num 4 -#define STB_IMAGE_RESIZE_DO_CODERS -#include STBIR__HEADER_FILENAME - -#define stbir__decode_suffix ABGR -#define stbir__decode_swizzle -#define stbir__decode_order0 3 -#define stbir__decode_order1 2 -#define stbir__decode_order2 1 -#define stbir__decode_order3 0 -#define stbir__encode_order0 3 -#define stbir__encode_order1 2 -#define stbir__encode_order2 1 -#define stbir__encode_order3 0 -#define stbir__coder_min_num 4 -#define STB_IMAGE_RESIZE_DO_CODERS -#include STBIR__HEADER_FILENAME - -#define stbir__decode_suffix AR -#define stbir__decode_swizzle -#define stbir__decode_order0 1 -#define stbir__decode_order1 0 -#define stbir__decode_order2 3 -#define stbir__decode_order3 2 -#define stbir__encode_order0 1 -#define stbir__encode_order1 0 -#define stbir__encode_order2 3 -#define stbir__encode_order3 2 -#define stbir__coder_min_num 2 -#define STB_IMAGE_RESIZE_DO_CODERS -#include STBIR__HEADER_FILENAME - - -// fancy alpha means we expand to keep both premultipied and non-premultiplied color channels -static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_channels ) -{ - float STBIR_STREAMOUT_PTR(*) out = out_buffer; - float const * end_decode = out_buffer + ( width_times_channels / 4 ) * 7; // decode buffer aligned to end of out_buffer - float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels; - - // fancy alpha is stored internally as R G B A Rpm Gpm Bpm - - #ifdef STBIR_SIMD - - #ifdef STBIR_SIMD8 - decode += 16; - STBIR_NO_UNROLL_LOOP_START - while ( decode <= end_decode ) - { - stbir__simdf8 d0,d1,a0,a1,p0,p1; - STBIR_NO_UNROLL(decode); - stbir__simdf8_load( d0, decode-16 ); - stbir__simdf8_load( d1, decode-16+8 ); - stbir__simdf8_0123to33333333( a0, d0 ); - stbir__simdf8_0123to33333333( a1, d1 ); - stbir__simdf8_mult( p0, a0, d0 ); - stbir__simdf8_mult( p1, a1, d1 ); - stbir__simdf8_bot4s( a0, d0, p0 ); - stbir__simdf8_bot4s( a1, d1, p1 ); - stbir__simdf8_top4s( d0, d0, p0 ); - stbir__simdf8_top4s( d1, d1, p1 ); - stbir__simdf8_store ( out, a0 ); - stbir__simdf8_store ( out+7, d0 ); - stbir__simdf8_store ( out+14, a1 ); - stbir__simdf8_store ( out+21, d1 ); - decode += 16; - out += 28; - } - decode -= 16; - #else - decode += 8; - STBIR_NO_UNROLL_LOOP_START - while ( decode <= end_decode ) - { - stbir__simdf d0,a0,d1,a1,p0,p1; - STBIR_NO_UNROLL(decode); - stbir__simdf_load( d0, decode-8 ); - stbir__simdf_load( d1, decode-8+4 ); - stbir__simdf_0123to3333( a0, d0 ); - stbir__simdf_0123to3333( a1, d1 ); - stbir__simdf_mult( p0, a0, d0 ); - stbir__simdf_mult( p1, a1, d1 ); - stbir__simdf_store ( out, d0 ); - stbir__simdf_store ( out+4, p0 ); - stbir__simdf_store ( out+7, d1 ); - stbir__simdf_store ( out+7+4, p1 ); - decode += 8; - out += 14; - } - decode -= 8; - #endif - - // might be one last odd pixel - #ifdef STBIR_SIMD8 - STBIR_NO_UNROLL_LOOP_START - while ( decode < end_decode ) - #else - if ( decode < end_decode ) - #endif - { - stbir__simdf d,a,p; - STBIR_NO_UNROLL(decode); - stbir__simdf_load( d, decode ); - stbir__simdf_0123to3333( a, d ); - stbir__simdf_mult( p, a, d ); - stbir__simdf_store ( out, d ); - stbir__simdf_store ( out+4, p ); - decode += 4; - out += 7; - } - - #else - - while( decode < end_decode ) - { - float r = decode[0], g = decode[1], b = decode[2], alpha = decode[3]; - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = alpha; - out[4] = r * alpha; - out[5] = g * alpha; - out[6] = b * alpha; - out += 7; - decode += 4; - } - - #endif -} - -static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_channels ) -{ - float STBIR_STREAMOUT_PTR(*) out = out_buffer; - float const * end_decode = out_buffer + ( width_times_channels / 2 ) * 3; - float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels; - - // for fancy alpha, turns into: [X A Xpm][X A Xpm],etc - - #ifdef STBIR_SIMD - - decode += 8; - if ( decode <= end_decode ) - { - STBIR_NO_UNROLL_LOOP_START - do { - #ifdef STBIR_SIMD8 - stbir__simdf8 d0,a0,p0; - STBIR_NO_UNROLL(decode); - stbir__simdf8_load( d0, decode-8 ); - stbir__simdf8_0123to11331133( p0, d0 ); - stbir__simdf8_0123to00220022( a0, d0 ); - stbir__simdf8_mult( p0, p0, a0 ); - - stbir__simdf_store2( out, stbir__if_simdf8_cast_to_simdf4( d0 ) ); - stbir__simdf_store( out+2, stbir__if_simdf8_cast_to_simdf4( p0 ) ); - stbir__simdf_store2h( out+3, stbir__if_simdf8_cast_to_simdf4( d0 ) ); - - stbir__simdf_store2( out+6, stbir__simdf8_gettop4( d0 ) ); - stbir__simdf_store( out+8, stbir__simdf8_gettop4( p0 ) ); - stbir__simdf_store2h( out+9, stbir__simdf8_gettop4( d0 ) ); - #else - stbir__simdf d0,a0,d1,a1,p0,p1; - STBIR_NO_UNROLL(decode); - stbir__simdf_load( d0, decode-8 ); - stbir__simdf_load( d1, decode-8+4 ); - stbir__simdf_0123to1133( p0, d0 ); - stbir__simdf_0123to1133( p1, d1 ); - stbir__simdf_0123to0022( a0, d0 ); - stbir__simdf_0123to0022( a1, d1 ); - stbir__simdf_mult( p0, p0, a0 ); - stbir__simdf_mult( p1, p1, a1 ); - - stbir__simdf_store2( out, d0 ); - stbir__simdf_store( out+2, p0 ); - stbir__simdf_store2h( out+3, d0 ); - - stbir__simdf_store2( out+6, d1 ); - stbir__simdf_store( out+8, p1 ); - stbir__simdf_store2h( out+9, d1 ); - #endif - decode += 8; - out += 12; - } while ( decode <= end_decode ); - } - decode -= 8; - #endif - - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode < end_decode ) - { - float x = decode[0], y = decode[1]; - STBIR_SIMD_NO_UNROLL(decode); - out[0] = x; - out[1] = y; - out[2] = x * y; - out += 3; - decode += 2; - } -} - -static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_times_channels ) -{ - float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer; - float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer; - float const * end_output = encode_buffer + width_times_channels; - - // fancy RGBA is stored internally as R G B A Rpm Gpm Bpm - - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float alpha = input[3]; -#ifdef STBIR_SIMD - stbir__simdf i,ia; - STBIR_SIMD_NO_UNROLL(encode); - if ( alpha < stbir__small_float ) - { - stbir__simdf_load( i, input ); - stbir__simdf_store( encode, i ); - } - else - { - stbir__simdf_load1frep4( ia, 1.0f / alpha ); - stbir__simdf_load( i, input+4 ); - stbir__simdf_mult( i, i, ia ); - stbir__simdf_store( encode, i ); - encode[3] = alpha; - } -#else - if ( alpha < stbir__small_float ) - { - encode[0] = input[0]; - encode[1] = input[1]; - encode[2] = input[2]; - } - else - { - float ialpha = 1.0f / alpha; - encode[0] = input[4] * ialpha; - encode[1] = input[5] * ialpha; - encode[2] = input[6] * ialpha; - } - encode[3] = alpha; -#endif - - input += 7; - encode += 4; - } while ( encode < end_output ); -} - -// format: [X A Xpm][X A Xpm] etc -static void stbir__fancy_alpha_unweight_2ch( float * encode_buffer, int width_times_channels ) -{ - float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer; - float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer; - float const * end_output = encode_buffer + width_times_channels; - - do { - float alpha = input[1]; - encode[0] = input[0]; - if ( alpha >= stbir__small_float ) - encode[0] = input[2] / alpha; - encode[1] = alpha; - - input += 3; - encode += 2; - } while ( encode < end_output ); -} - -static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_times_channels ) -{ - float STBIR_STREAMOUT_PTR(*) decode = decode_buffer; - float const * end_decode = decode_buffer + width_times_channels; - - #ifdef STBIR_SIMD - { - decode += 2 * stbir__simdfX_float_count; - STBIR_NO_UNROLL_LOOP_START - while ( decode <= end_decode ) - { - stbir__simdfX d0,a0,d1,a1; - STBIR_NO_UNROLL(decode); - stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count ); - stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count ); - stbir__simdfX_aaa1( a0, d0, STBIR_onesX ); - stbir__simdfX_aaa1( a1, d1, STBIR_onesX ); - stbir__simdfX_mult( d0, d0, a0 ); - stbir__simdfX_mult( d1, d1, a1 ); - stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 ); - stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 ); - decode += 2 * stbir__simdfX_float_count; - } - decode -= 2 * stbir__simdfX_float_count; - - // few last pixels remnants - #ifdef STBIR_SIMD8 - STBIR_NO_UNROLL_LOOP_START - while ( decode < end_decode ) - #else - if ( decode < end_decode ) - #endif - { - stbir__simdf d,a; - stbir__simdf_load( d, decode ); - stbir__simdf_aaa1( a, d, STBIR__CONSTF(STBIR_ones) ); - stbir__simdf_mult( d, d, a ); - stbir__simdf_store ( decode, d ); - decode += 4; - } - } - - #else - - while( decode < end_decode ) - { - float alpha = decode[3]; - decode[0] *= alpha; - decode[1] *= alpha; - decode[2] *= alpha; - decode += 4; - } - - #endif -} - -static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_times_channels ) -{ - float STBIR_STREAMOUT_PTR(*) decode = decode_buffer; - float const * end_decode = decode_buffer + width_times_channels; - - #ifdef STBIR_SIMD - decode += 2 * stbir__simdfX_float_count; - STBIR_NO_UNROLL_LOOP_START - while ( decode <= end_decode ) - { - stbir__simdfX d0,a0,d1,a1; - STBIR_NO_UNROLL(decode); - stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count ); - stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count ); - stbir__simdfX_a1a1( a0, d0, STBIR_onesX ); - stbir__simdfX_a1a1( a1, d1, STBIR_onesX ); - stbir__simdfX_mult( d0, d0, a0 ); - stbir__simdfX_mult( d1, d1, a1 ); - stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 ); - stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 ); - decode += 2 * stbir__simdfX_float_count; - } - decode -= 2 * stbir__simdfX_float_count; - #endif - - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode < end_decode ) - { - float alpha = decode[1]; - STBIR_SIMD_NO_UNROLL(decode); - decode[0] *= alpha; - decode += 2; - } -} - -static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_times_channels ) -{ - float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer; - float const * end_output = encode_buffer + width_times_channels; - - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float alpha = encode[3]; - -#ifdef STBIR_SIMD - stbir__simdf i,ia; - STBIR_SIMD_NO_UNROLL(encode); - if ( alpha >= stbir__small_float ) - { - stbir__simdf_load1frep4( ia, 1.0f / alpha ); - stbir__simdf_load( i, encode ); - stbir__simdf_mult( i, i, ia ); - stbir__simdf_store( encode, i ); - encode[3] = alpha; - } -#else - if ( alpha >= stbir__small_float ) - { - float ialpha = 1.0f / alpha; - encode[0] *= ialpha; - encode[1] *= ialpha; - encode[2] *= ialpha; - } -#endif - encode += 4; - } while ( encode < end_output ); -} - -static void stbir__simple_alpha_unweight_2ch( float * encode_buffer, int width_times_channels ) -{ - float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer; - float const * end_output = encode_buffer + width_times_channels; - - do { - float alpha = encode[1]; - if ( alpha >= stbir__small_float ) - encode[0] /= alpha; - encode += 2; - } while ( encode < end_output ); -} - - -// only used in RGB->BGR or BGR->RGB -static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_channels ) -{ - float STBIR_STREAMOUT_PTR(*) decode = decode_buffer; - float const * end_decode = decode_buffer + width_times_channels; - -#ifdef STBIR_SIMD - #ifdef stbir__simdf_swiz2 // do we have two argument swizzles? - end_decode -= 12; - STBIR_NO_UNROLL_LOOP_START - while( decode <= end_decode ) - { - // on arm64 8 instructions, no overlapping stores - stbir__simdf a,b,c,na,nb; - STBIR_SIMD_NO_UNROLL(decode); - stbir__simdf_load( a, decode ); - stbir__simdf_load( b, decode+4 ); - stbir__simdf_load( c, decode+8 ); - - na = stbir__simdf_swiz2( a, b, 2, 1, 0, 5 ); - b = stbir__simdf_swiz2( a, b, 4, 3, 6, 7 ); - nb = stbir__simdf_swiz2( b, c, 0, 1, 4, 3 ); - c = stbir__simdf_swiz2( b, c, 2, 7, 6, 5 ); - - stbir__simdf_store( decode, na ); - stbir__simdf_store( decode+4, nb ); - stbir__simdf_store( decode+8, c ); - decode += 12; - } - end_decode += 12; - #else - end_decode -= 24; - STBIR_NO_UNROLL_LOOP_START - while( decode <= end_decode ) - { - // 26 instructions on x64 - stbir__simdf a,b,c,d,e,f,g; - float i21, i23; - STBIR_SIMD_NO_UNROLL(decode); - stbir__simdf_load( a, decode ); - stbir__simdf_load( b, decode+3 ); - stbir__simdf_load( c, decode+6 ); - stbir__simdf_load( d, decode+9 ); - stbir__simdf_load( e, decode+12 ); - stbir__simdf_load( f, decode+15 ); - stbir__simdf_load( g, decode+18 ); - - a = stbir__simdf_swiz( a, 2, 1, 0, 3 ); - b = stbir__simdf_swiz( b, 2, 1, 0, 3 ); - c = stbir__simdf_swiz( c, 2, 1, 0, 3 ); - d = stbir__simdf_swiz( d, 2, 1, 0, 3 ); - e = stbir__simdf_swiz( e, 2, 1, 0, 3 ); - f = stbir__simdf_swiz( f, 2, 1, 0, 3 ); - g = stbir__simdf_swiz( g, 2, 1, 0, 3 ); - - // stores overlap, need to be in order, - stbir__simdf_store( decode, a ); - i21 = decode[21]; - stbir__simdf_store( decode+3, b ); - i23 = decode[23]; - stbir__simdf_store( decode+6, c ); - stbir__simdf_store( decode+9, d ); - stbir__simdf_store( decode+12, e ); - stbir__simdf_store( decode+15, f ); - stbir__simdf_store( decode+18, g ); - decode[21] = i23; - decode[23] = i21; - decode += 24; - } - end_decode += 24; - #endif -#else - end_decode -= 12; - STBIR_NO_UNROLL_LOOP_START - while( decode <= end_decode ) - { - // 16 instructions - float t0,t1,t2,t3; - STBIR_NO_UNROLL(decode); - t0 = decode[0]; t1 = decode[3]; t2 = decode[6]; t3 = decode[9]; - decode[0] = decode[2]; decode[3] = decode[5]; decode[6] = decode[8]; decode[9] = decode[11]; - decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3; - decode += 12; - } - end_decode += 12; -#endif - - STBIR_NO_UNROLL_LOOP_START - while( decode < end_decode ) - { - float t = decode[0]; - STBIR_NO_UNROLL(decode); - decode[0] = decode[2]; - decode[2] = t; - decode += 3; - } -} - - - -static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float * output_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO ) -{ - int channels = stbir_info->channels; - int effective_channels = stbir_info->effective_channels; - int input_sample_in_bytes = stbir__type_size[stbir_info->input_type] * channels; - stbir_edge edge_horizontal = stbir_info->horizontal.edge; - stbir_edge edge_vertical = stbir_info->vertical.edge; - int row = stbir__edge_wrap(edge_vertical, n, stbir_info->vertical.scale_info.input_full_size); - const void* input_plane_data = ( (char *) stbir_info->input_data ) + (size_t)row * (size_t) stbir_info->input_stride_bytes; - stbir__span const * spans = stbir_info->scanline_extents.spans; - float* full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels; - - // if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed - STBIR_ASSERT( !(edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->vertical.scale_info.input_full_size)) ); - - do - { - float * decode_buffer; - void const * input_data; - float * end_decode; - int width_times_channels; - int width; - - if ( spans->n1 < spans->n0 ) - break; - - width = spans->n1 + 1 - spans->n0; - decode_buffer = full_decode_buffer + spans->n0 * effective_channels; - end_decode = full_decode_buffer + ( spans->n1 + 1 ) * effective_channels; - width_times_channels = width * channels; - - // read directly out of input plane by default - input_data = ( (char*)input_plane_data ) + spans->pixel_offset_for_input * input_sample_in_bytes; - - // if we have an input callback, call it to get the input data - if ( stbir_info->in_pixels_cb ) - { - // call the callback with a temp buffer (that they can choose to use or not). the temp is just right aligned memory in the decode_buffer itself - input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data ); - } - - STBIR_PROFILE_START( decode ); - // convert the pixels info the float decode_buffer, (we index from end_decode, so that when channelsdecode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data ); - STBIR_PROFILE_END( decode ); - - if (stbir_info->alpha_weight) - { - STBIR_PROFILE_START( alpha ); - stbir_info->alpha_weight( decode_buffer, width_times_channels ); - STBIR_PROFILE_END( alpha ); - } - - ++spans; - } while ( spans <= ( &stbir_info->scanline_extents.spans[1] ) ); - - // handle the edge_wrap filter (all other types are handled back out at the calculate_filter stage) - // basically the idea here is that if we have the whole scanline in memory, we don't redecode the - // wrapped edge pixels, and instead just memcpy them from the scanline into the edge positions - if ( ( edge_horizontal == STBIR_EDGE_WRAP ) && ( stbir_info->scanline_extents.edge_sizes[0] | stbir_info->scanline_extents.edge_sizes[1] ) ) - { - // this code only runs if we're in edge_wrap, and we're doing the entire scanline - int e, start_x[2]; - int input_full_size = stbir_info->horizontal.scale_info.input_full_size; - - start_x[0] = -stbir_info->scanline_extents.edge_sizes[0]; // left edge start x - start_x[1] = input_full_size; // right edge - - for( e = 0; e < 2 ; e++ ) - { - // do each margin - int margin = stbir_info->scanline_extents.edge_sizes[e]; - if ( margin ) - { - int x = start_x[e]; - float * marg = full_decode_buffer + x * effective_channels; - float const * src = full_decode_buffer + stbir__edge_wrap(edge_horizontal, x, input_full_size) * effective_channels; - STBIR_MEMCPY( marg, src, margin * effective_channels * sizeof(float) ); - } - } - } -} - - -//================= -// Do 1 channel horizontal routines - -#ifdef STBIR_SIMD - -#define stbir__1_coeff_only() \ - stbir__simdf tot,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1( c, hc ); \ - stbir__simdf_mult1_mem( tot, c, decode ); - -#define stbir__2_coeff_only() \ - stbir__simdf tot,c,d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2z( c, hc ); \ - stbir__simdf_load2( d, decode ); \ - stbir__simdf_mult( tot, c, d ); \ - stbir__simdf_0123to1230( c, tot ); \ - stbir__simdf_add1( tot, tot, c ); - -#define stbir__3_coeff_only() \ - stbir__simdf tot,c,t; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( c, hc ); \ - stbir__simdf_mult_mem( tot, c, decode ); \ - stbir__simdf_0123to1230( c, tot ); \ - stbir__simdf_0123to2301( t, tot ); \ - stbir__simdf_add1( tot, tot, c ); \ - stbir__simdf_add1( tot, tot, t ); - -#define stbir__store_output_tiny() \ - stbir__simdf_store1( output, tot ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 1; - -#define stbir__4_coeff_start() \ - stbir__simdf tot,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( c, hc ); \ - stbir__simdf_mult_mem( tot, c, decode ); \ - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( c, hc + (ofs) ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) ); - -#define stbir__1_coeff_remnant( ofs ) \ - { stbir__simdf d; \ - stbir__simdf_load1z( c, hc + (ofs) ); \ - stbir__simdf_load1( d, decode + (ofs) ); \ - stbir__simdf_madd( tot, tot, d, c ); } - -#define stbir__2_coeff_remnant( ofs ) \ - { stbir__simdf d; \ - stbir__simdf_load2z( c, hc+(ofs) ); \ - stbir__simdf_load2( d, decode+(ofs) ); \ - stbir__simdf_madd( tot, tot, d, c ); } - -#define stbir__3_coeff_setup() \ - stbir__simdf mask; \ - stbir__simdf_load( mask, STBIR_mask + 3 ); - -#define stbir__3_coeff_remnant( ofs ) \ - stbir__simdf_load( c, hc+(ofs) ); \ - stbir__simdf_and( c, c, mask ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) ); - -#define stbir__store_output() \ - stbir__simdf_0123to2301( c, tot ); \ - stbir__simdf_add( tot, tot, c ); \ - stbir__simdf_0123to1230( c, tot ); \ - stbir__simdf_add1( tot, tot, c ); \ - stbir__simdf_store1( output, tot ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 1; - -#else - -#define stbir__1_coeff_only() \ - float tot; \ - tot = decode[0]*hc[0]; - -#define stbir__2_coeff_only() \ - float tot; \ - tot = decode[0] * hc[0]; \ - tot += decode[1] * hc[1]; - -#define stbir__3_coeff_only() \ - float tot; \ - tot = decode[0] * hc[0]; \ - tot += decode[1] * hc[1]; \ - tot += decode[2] * hc[2]; - -#define stbir__store_output_tiny() \ - output[0] = tot; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 1; - -#define stbir__4_coeff_start() \ - float tot0,tot1,tot2,tot3; \ - tot0 = decode[0] * hc[0]; \ - tot1 = decode[1] * hc[1]; \ - tot2 = decode[2] * hc[2]; \ - tot3 = decode[3] * hc[3]; - -#define stbir__4_coeff_continue_from_4( ofs ) \ - tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ - tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ - tot2 += decode[2+(ofs)] * hc[2+(ofs)]; \ - tot3 += decode[3+(ofs)] * hc[3+(ofs)]; - -#define stbir__1_coeff_remnant( ofs ) \ - tot0 += decode[0+(ofs)] * hc[0+(ofs)]; - -#define stbir__2_coeff_remnant( ofs ) \ - tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ - tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ - -#define stbir__3_coeff_remnant( ofs ) \ - tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ - tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ - tot2 += decode[2+(ofs)] * hc[2+(ofs)]; - -#define stbir__store_output() \ - output[0] = (tot0+tot2)+(tot1+tot3); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 1; - -#endif - -#define STBIR__horizontal_channels 1 -#define STB_IMAGE_RESIZE_DO_HORIZONTALS -#include STBIR__HEADER_FILENAME - - -//================= -// Do 2 channel horizontal routines - -#ifdef STBIR_SIMD - -#define stbir__1_coeff_only() \ - stbir__simdf tot,c,d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1z( c, hc ); \ - stbir__simdf_0123to0011( c, c ); \ - stbir__simdf_load2( d, decode ); \ - stbir__simdf_mult( tot, d, c ); - -#define stbir__2_coeff_only() \ - stbir__simdf tot,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2( c, hc ); \ - stbir__simdf_0123to0011( c, c ); \ - stbir__simdf_mult_mem( tot, c, decode ); - -#define stbir__3_coeff_only() \ - stbir__simdf tot,c,cs,d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_mult_mem( tot, c, decode ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_load2z( d, decode+4 ); \ - stbir__simdf_madd( tot, tot, d, c ); - -#define stbir__store_output_tiny() \ - stbir__simdf_0123to2301( c, tot ); \ - stbir__simdf_add( tot, tot, c ); \ - stbir__simdf_store2( output, tot ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 2; - -#ifdef STBIR_SIMD8 - -#define stbir__4_coeff_start() \ - stbir__simdf8 tot0,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc ); \ - stbir__simdf8_0123to00112233( c, cs ); \ - stbir__simdf8_mult_mem( tot0, c, decode ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00112233( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); - -#define stbir__1_coeff_remnant( ofs ) \ - { stbir__simdf t,d; \ - stbir__simdf_load1z( t, hc + (ofs) ); \ - stbir__simdf_load2( d, decode + (ofs) * 2 ); \ - stbir__simdf_0123to0011( t, t ); \ - stbir__simdf_mult( t, t, d ); \ - stbir__simdf8_add4( tot0, tot0, t ); } - -#define stbir__2_coeff_remnant( ofs ) \ - { stbir__simdf t; \ - stbir__simdf_load2( t, hc + (ofs) ); \ - stbir__simdf_0123to0011( t, t ); \ - stbir__simdf_mult_mem( t, t, decode+(ofs)*2 ); \ - stbir__simdf8_add4( tot0, tot0, t ); } - -#define stbir__3_coeff_remnant( ofs ) \ - { stbir__simdf8 d; \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00112233( c, cs ); \ - stbir__simdf8_load6z( d, decode+(ofs)*2 ); \ - stbir__simdf8_madd( tot0, tot0, c, d ); } - -#define stbir__store_output() \ - { stbir__simdf t,d; \ - stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \ - stbir__simdf_0123to2301( d, t ); \ - stbir__simdf_add( t, t, d ); \ - stbir__simdf_store2( output, t ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 2; } - -#else - -#define stbir__4_coeff_start() \ - stbir__simdf tot0,tot1,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_0123to2233( c, cs ); \ - stbir__simdf_mult_mem( tot1, c, decode+4 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \ - stbir__simdf_0123to2233( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 ); - -#define stbir__1_coeff_remnant( ofs ) \ - { stbir__simdf d; \ - stbir__simdf_load1z( cs, hc + (ofs) ); \ - stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_load2( d, decode + (ofs) * 2 ); \ - stbir__simdf_madd( tot0, tot0, d, c ); } - -#define stbir__2_coeff_remnant( ofs ) \ - stbir__simdf_load2( cs, hc + (ofs) ); \ - stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); - -#define stbir__3_coeff_remnant( ofs ) \ - { stbir__simdf d; \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_load2z( d, decode + (ofs) * 2 + 4 ); \ - stbir__simdf_madd( tot1, tot1, d, c ); } - -#define stbir__store_output() \ - stbir__simdf_add( tot0, tot0, tot1 ); \ - stbir__simdf_0123to2301( c, tot0 ); \ - stbir__simdf_add( tot0, tot0, c ); \ - stbir__simdf_store2( output, tot0 ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 2; - -#endif - -#else - -#define stbir__1_coeff_only() \ - float tota,totb,c; \ - c = hc[0]; \ - tota = decode[0]*c; \ - totb = decode[1]*c; - -#define stbir__2_coeff_only() \ - float tota,totb,c; \ - c = hc[0]; \ - tota = decode[0]*c; \ - totb = decode[1]*c; \ - c = hc[1]; \ - tota += decode[2]*c; \ - totb += decode[3]*c; - -// this weird order of add matches the simd -#define stbir__3_coeff_only() \ - float tota,totb,c; \ - c = hc[0]; \ - tota = decode[0]*c; \ - totb = decode[1]*c; \ - c = hc[2]; \ - tota += decode[4]*c; \ - totb += decode[5]*c; \ - c = hc[1]; \ - tota += decode[2]*c; \ - totb += decode[3]*c; - -#define stbir__store_output_tiny() \ - output[0] = tota; \ - output[1] = totb; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 2; - -#define stbir__4_coeff_start() \ - float tota0,tota1,tota2,tota3,totb0,totb1,totb2,totb3,c; \ - c = hc[0]; \ - tota0 = decode[0]*c; \ - totb0 = decode[1]*c; \ - c = hc[1]; \ - tota1 = decode[2]*c; \ - totb1 = decode[3]*c; \ - c = hc[2]; \ - tota2 = decode[4]*c; \ - totb2 = decode[5]*c; \ - c = hc[3]; \ - tota3 = decode[6]*c; \ - totb3 = decode[7]*c; - -#define stbir__4_coeff_continue_from_4( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*2]*c; \ - totb0 += decode[1+(ofs)*2]*c; \ - c = hc[1+(ofs)]; \ - tota1 += decode[2+(ofs)*2]*c; \ - totb1 += decode[3+(ofs)*2]*c; \ - c = hc[2+(ofs)]; \ - tota2 += decode[4+(ofs)*2]*c; \ - totb2 += decode[5+(ofs)*2]*c; \ - c = hc[3+(ofs)]; \ - tota3 += decode[6+(ofs)*2]*c; \ - totb3 += decode[7+(ofs)*2]*c; - -#define stbir__1_coeff_remnant( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*2] * c; \ - totb0 += decode[1+(ofs)*2] * c; - -#define stbir__2_coeff_remnant( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*2] * c; \ - totb0 += decode[1+(ofs)*2] * c; \ - c = hc[1+(ofs)]; \ - tota1 += decode[2+(ofs)*2] * c; \ - totb1 += decode[3+(ofs)*2] * c; - -#define stbir__3_coeff_remnant( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*2] * c; \ - totb0 += decode[1+(ofs)*2] * c; \ - c = hc[1+(ofs)]; \ - tota1 += decode[2+(ofs)*2] * c; \ - totb1 += decode[3+(ofs)*2] * c; \ - c = hc[2+(ofs)]; \ - tota2 += decode[4+(ofs)*2] * c; \ - totb2 += decode[5+(ofs)*2] * c; - -#define stbir__store_output() \ - output[0] = (tota0+tota2)+(tota1+tota3); \ - output[1] = (totb0+totb2)+(totb1+totb3); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 2; - -#endif - -#define STBIR__horizontal_channels 2 -#define STB_IMAGE_RESIZE_DO_HORIZONTALS -#include STBIR__HEADER_FILENAME - - -//================= -// Do 3 channel horizontal routines - -#ifdef STBIR_SIMD - -#define stbir__1_coeff_only() \ - stbir__simdf tot,c,d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1z( c, hc ); \ - stbir__simdf_0123to0001( c, c ); \ - stbir__simdf_load( d, decode ); \ - stbir__simdf_mult( tot, d, c ); - -#define stbir__2_coeff_only() \ - stbir__simdf tot,c,cs,d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_load( d, decode ); \ - stbir__simdf_mult( tot, d, c ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_load( d, decode+3 ); \ - stbir__simdf_madd( tot, tot, d, c ); - -#define stbir__3_coeff_only() \ - stbir__simdf tot,c,d,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_load( d, decode ); \ - stbir__simdf_mult( tot, d, c ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_load( d, decode+3 ); \ - stbir__simdf_madd( tot, tot, d, c ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_load( d, decode+6 ); \ - stbir__simdf_madd( tot, tot, d, c ); - -#define stbir__store_output_tiny() \ - stbir__simdf_store2( output, tot ); \ - stbir__simdf_0123to2301( tot, tot ); \ - stbir__simdf_store1( output+2, tot ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 3; - -#ifdef STBIR_SIMD8 - -// we're loading from the XXXYYY decode by -1 to get the XXXYYY into different halves of the AVX reg fyi -#define stbir__4_coeff_start() \ - stbir__simdf8 tot0,tot1,c,cs; stbir__simdf t; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc ); \ - stbir__simdf8_0123to00001111( c, cs ); \ - stbir__simdf8_mult_mem( tot0, c, decode - 1 ); \ - stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00001111( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \ - stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 ); - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1rep4( t, hc + (ofs) ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 ); - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \ - stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); - - #define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00001111( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \ - stbir__simdf8_0123to2222( t, cs ); \ - stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 ); - -#define stbir__store_output() \ - stbir__simdf8_add( tot0, tot0, tot1 ); \ - stbir__simdf_0123to1230( t, stbir__if_simdf8_cast_to_simdf4( tot0 ) ); \ - stbir__simdf8_add4halves( t, t, tot0 ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 3; \ - if ( output < output_end ) \ - { \ - stbir__simdf_store( output-3, t ); \ - continue; \ - } \ - { stbir__simdf tt; stbir__simdf_0123to2301( tt, t ); \ - stbir__simdf_store2( output-3, t ); \ - stbir__simdf_store1( output+2-3, tt ); } \ - break; - - -#else - -#define stbir__4_coeff_start() \ - stbir__simdf tot0,tot1,tot2,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0001( c, cs ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_0123to1122( c, cs ); \ - stbir__simdf_mult_mem( tot1, c, decode+4 ); \ - stbir__simdf_0123to2333( c, cs ); \ - stbir__simdf_mult_mem( tot2, c, decode+8 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0001( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \ - stbir__simdf_0123to1122( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \ - stbir__simdf_0123to2333( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 ); - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1z( c, hc + (ofs) ); \ - stbir__simdf_0123to0001( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); - -#define stbir__2_coeff_remnant( ofs ) \ - { stbir__simdf d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2z( cs, hc + (ofs) ); \ - stbir__simdf_0123to0001( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \ - stbir__simdf_0123to1122( c, cs ); \ - stbir__simdf_load2z( d, decode+(ofs)*3+4 ); \ - stbir__simdf_madd( tot1, tot1, c, d ); } - -#define stbir__3_coeff_remnant( ofs ) \ - { stbir__simdf d; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0001( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \ - stbir__simdf_0123to1122( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_load1z( d, decode+(ofs)*3+8 ); \ - stbir__simdf_madd( tot2, tot2, c, d ); } - -#define stbir__store_output() \ - stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 ); \ - stbir__simdf_0123ABCDto23Ax( cs, tot1, tot2 ); \ - stbir__simdf_0123to1230( tot2, tot2 ); \ - stbir__simdf_add( tot0, tot0, cs ); \ - stbir__simdf_add( c, c, tot2 ); \ - stbir__simdf_add( tot0, tot0, c ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 3; \ - if ( output < output_end ) \ - { \ - stbir__simdf_store( output-3, tot0 ); \ - continue; \ - } \ - stbir__simdf_0123to2301( tot1, tot0 ); \ - stbir__simdf_store2( output-3, tot0 ); \ - stbir__simdf_store1( output+2-3, tot1 ); \ - break; - -#endif - -#else - -#define stbir__1_coeff_only() \ - float tot0, tot1, tot2, c; \ - c = hc[0]; \ - tot0 = decode[0]*c; \ - tot1 = decode[1]*c; \ - tot2 = decode[2]*c; - -#define stbir__2_coeff_only() \ - float tot0, tot1, tot2, c; \ - c = hc[0]; \ - tot0 = decode[0]*c; \ - tot1 = decode[1]*c; \ - tot2 = decode[2]*c; \ - c = hc[1]; \ - tot0 += decode[3]*c; \ - tot1 += decode[4]*c; \ - tot2 += decode[5]*c; - -#define stbir__3_coeff_only() \ - float tot0, tot1, tot2, c; \ - c = hc[0]; \ - tot0 = decode[0]*c; \ - tot1 = decode[1]*c; \ - tot2 = decode[2]*c; \ - c = hc[1]; \ - tot0 += decode[3]*c; \ - tot1 += decode[4]*c; \ - tot2 += decode[5]*c; \ - c = hc[2]; \ - tot0 += decode[6]*c; \ - tot1 += decode[7]*c; \ - tot2 += decode[8]*c; - -#define stbir__store_output_tiny() \ - output[0] = tot0; \ - output[1] = tot1; \ - output[2] = tot2; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 3; - -#define stbir__4_coeff_start() \ - float tota0,tota1,tota2,totb0,totb1,totb2,totc0,totc1,totc2,totd0,totd1,totd2,c; \ - c = hc[0]; \ - tota0 = decode[0]*c; \ - tota1 = decode[1]*c; \ - tota2 = decode[2]*c; \ - c = hc[1]; \ - totb0 = decode[3]*c; \ - totb1 = decode[4]*c; \ - totb2 = decode[5]*c; \ - c = hc[2]; \ - totc0 = decode[6]*c; \ - totc1 = decode[7]*c; \ - totc2 = decode[8]*c; \ - c = hc[3]; \ - totd0 = decode[9]*c; \ - totd1 = decode[10]*c; \ - totd2 = decode[11]*c; - -#define stbir__4_coeff_continue_from_4( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*3]*c; \ - tota1 += decode[1+(ofs)*3]*c; \ - tota2 += decode[2+(ofs)*3]*c; \ - c = hc[1+(ofs)]; \ - totb0 += decode[3+(ofs)*3]*c; \ - totb1 += decode[4+(ofs)*3]*c; \ - totb2 += decode[5+(ofs)*3]*c; \ - c = hc[2+(ofs)]; \ - totc0 += decode[6+(ofs)*3]*c; \ - totc1 += decode[7+(ofs)*3]*c; \ - totc2 += decode[8+(ofs)*3]*c; \ - c = hc[3+(ofs)]; \ - totd0 += decode[9+(ofs)*3]*c; \ - totd1 += decode[10+(ofs)*3]*c; \ - totd2 += decode[11+(ofs)*3]*c; - -#define stbir__1_coeff_remnant( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*3]*c; \ - tota1 += decode[1+(ofs)*3]*c; \ - tota2 += decode[2+(ofs)*3]*c; - -#define stbir__2_coeff_remnant( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*3]*c; \ - tota1 += decode[1+(ofs)*3]*c; \ - tota2 += decode[2+(ofs)*3]*c; \ - c = hc[1+(ofs)]; \ - totb0 += decode[3+(ofs)*3]*c; \ - totb1 += decode[4+(ofs)*3]*c; \ - totb2 += decode[5+(ofs)*3]*c; \ - -#define stbir__3_coeff_remnant( ofs ) \ - c = hc[0+(ofs)]; \ - tota0 += decode[0+(ofs)*3]*c; \ - tota1 += decode[1+(ofs)*3]*c; \ - tota2 += decode[2+(ofs)*3]*c; \ - c = hc[1+(ofs)]; \ - totb0 += decode[3+(ofs)*3]*c; \ - totb1 += decode[4+(ofs)*3]*c; \ - totb2 += decode[5+(ofs)*3]*c; \ - c = hc[2+(ofs)]; \ - totc0 += decode[6+(ofs)*3]*c; \ - totc1 += decode[7+(ofs)*3]*c; \ - totc2 += decode[8+(ofs)*3]*c; - -#define stbir__store_output() \ - output[0] = (tota0+totc0)+(totb0+totd0); \ - output[1] = (tota1+totc1)+(totb1+totd1); \ - output[2] = (tota2+totc2)+(totb2+totd2); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 3; - -#endif - -#define STBIR__horizontal_channels 3 -#define STB_IMAGE_RESIZE_DO_HORIZONTALS -#include STBIR__HEADER_FILENAME - -//================= -// Do 4 channel horizontal routines - -#ifdef STBIR_SIMD - -#define stbir__1_coeff_only() \ - stbir__simdf tot,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1( c, hc ); \ - stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_mult_mem( tot, c, decode ); - -#define stbir__2_coeff_only() \ - stbir__simdf tot,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_mult_mem( tot, c, decode ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+4 ); - -#define stbir__3_coeff_only() \ - stbir__simdf tot,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_mult_mem( tot, c, decode ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+4 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+8 ); - -#define stbir__store_output_tiny() \ - stbir__simdf_store( output, tot ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 4; - -#ifdef STBIR_SIMD8 - -#define stbir__4_coeff_start() \ - stbir__simdf8 tot0,c,cs; stbir__simdf t; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc ); \ - stbir__simdf8_0123to00001111( c, cs ); \ - stbir__simdf8_mult_mem( tot0, c, decode ); \ - stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00001111( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ - stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1rep4( t, hc + (ofs) ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 ); - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \ - stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); - - #define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00001111( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ - stbir__simdf8_0123to2222( t, cs ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 ); - -#define stbir__store_output() \ - stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \ - stbir__simdf_store( output, t ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 4; - -#else - -#define stbir__4_coeff_start() \ - stbir__simdf tot0,tot1,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_mult_mem( tot1, c, decode+4 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+8 ); \ - stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+12 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); \ - stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 ); - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1( c, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2( cs, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); - -#define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); - -#define stbir__store_output() \ - stbir__simdf_add( tot0, tot0, tot1 ); \ - stbir__simdf_store( output, tot0 ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 4; - -#endif - -#else - -#define stbir__1_coeff_only() \ - float p0,p1,p2,p3,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0]; \ - p0 = decode[0] * c; \ - p1 = decode[1] * c; \ - p2 = decode[2] * c; \ - p3 = decode[3] * c; - -#define stbir__2_coeff_only() \ - float p0,p1,p2,p3,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0]; \ - p0 = decode[0] * c; \ - p1 = decode[1] * c; \ - p2 = decode[2] * c; \ - p3 = decode[3] * c; \ - c = hc[1]; \ - p0 += decode[4] * c; \ - p1 += decode[5] * c; \ - p2 += decode[6] * c; \ - p3 += decode[7] * c; - -#define stbir__3_coeff_only() \ - float p0,p1,p2,p3,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0]; \ - p0 = decode[0] * c; \ - p1 = decode[1] * c; \ - p2 = decode[2] * c; \ - p3 = decode[3] * c; \ - c = hc[1]; \ - p0 += decode[4] * c; \ - p1 += decode[5] * c; \ - p2 += decode[6] * c; \ - p3 += decode[7] * c; \ - c = hc[2]; \ - p0 += decode[8] * c; \ - p1 += decode[9] * c; \ - p2 += decode[10] * c; \ - p3 += decode[11] * c; - -#define stbir__store_output_tiny() \ - output[0] = p0; \ - output[1] = p1; \ - output[2] = p2; \ - output[3] = p3; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 4; - -#define stbir__4_coeff_start() \ - float x0,x1,x2,x3,y0,y1,y2,y3,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0]; \ - x0 = decode[0] * c; \ - x1 = decode[1] * c; \ - x2 = decode[2] * c; \ - x3 = decode[3] * c; \ - c = hc[1]; \ - y0 = decode[4] * c; \ - y1 = decode[5] * c; \ - y2 = decode[6] * c; \ - y3 = decode[7] * c; \ - c = hc[2]; \ - x0 += decode[8] * c; \ - x1 += decode[9] * c; \ - x2 += decode[10] * c; \ - x3 += decode[11] * c; \ - c = hc[3]; \ - y0 += decode[12] * c; \ - y1 += decode[13] * c; \ - y2 += decode[14] * c; \ - y3 += decode[15] * c; - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*4] * c; \ - x1 += decode[1+(ofs)*4] * c; \ - x2 += decode[2+(ofs)*4] * c; \ - x3 += decode[3+(ofs)*4] * c; \ - c = hc[1+(ofs)]; \ - y0 += decode[4+(ofs)*4] * c; \ - y1 += decode[5+(ofs)*4] * c; \ - y2 += decode[6+(ofs)*4] * c; \ - y3 += decode[7+(ofs)*4] * c; \ - c = hc[2+(ofs)]; \ - x0 += decode[8+(ofs)*4] * c; \ - x1 += decode[9+(ofs)*4] * c; \ - x2 += decode[10+(ofs)*4] * c; \ - x3 += decode[11+(ofs)*4] * c; \ - c = hc[3+(ofs)]; \ - y0 += decode[12+(ofs)*4] * c; \ - y1 += decode[13+(ofs)*4] * c; \ - y2 += decode[14+(ofs)*4] * c; \ - y3 += decode[15+(ofs)*4] * c; - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*4] * c; \ - x1 += decode[1+(ofs)*4] * c; \ - x2 += decode[2+(ofs)*4] * c; \ - x3 += decode[3+(ofs)*4] * c; - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*4] * c; \ - x1 += decode[1+(ofs)*4] * c; \ - x2 += decode[2+(ofs)*4] * c; \ - x3 += decode[3+(ofs)*4] * c; \ - c = hc[1+(ofs)]; \ - y0 += decode[4+(ofs)*4] * c; \ - y1 += decode[5+(ofs)*4] * c; \ - y2 += decode[6+(ofs)*4] * c; \ - y3 += decode[7+(ofs)*4] * c; - -#define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*4] * c; \ - x1 += decode[1+(ofs)*4] * c; \ - x2 += decode[2+(ofs)*4] * c; \ - x3 += decode[3+(ofs)*4] * c; \ - c = hc[1+(ofs)]; \ - y0 += decode[4+(ofs)*4] * c; \ - y1 += decode[5+(ofs)*4] * c; \ - y2 += decode[6+(ofs)*4] * c; \ - y3 += decode[7+(ofs)*4] * c; \ - c = hc[2+(ofs)]; \ - x0 += decode[8+(ofs)*4] * c; \ - x1 += decode[9+(ofs)*4] * c; \ - x2 += decode[10+(ofs)*4] * c; \ - x3 += decode[11+(ofs)*4] * c; - -#define stbir__store_output() \ - output[0] = x0 + y0; \ - output[1] = x1 + y1; \ - output[2] = x2 + y2; \ - output[3] = x3 + y3; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 4; - -#endif - -#define STBIR__horizontal_channels 4 -#define STB_IMAGE_RESIZE_DO_HORIZONTALS -#include STBIR__HEADER_FILENAME - - - -//================= -// Do 7 channel horizontal routines - -#ifdef STBIR_SIMD - -#define stbir__1_coeff_only() \ - stbir__simdf tot0,tot1,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1( c, hc ); \ - stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_mult_mem( tot1, c, decode+3 ); - -#define stbir__2_coeff_only() \ - stbir__simdf tot0,tot1,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_mult_mem( tot1, c, decode+3 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c,decode+10 ); - -#define stbir__3_coeff_only() \ - stbir__simdf tot0,tot1,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_mult_mem( tot1, c, decode+3 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+10 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); - -#define stbir__store_output_tiny() \ - stbir__simdf_store( output+3, tot1 ); \ - stbir__simdf_store( output, tot0 ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 7; - -#ifdef STBIR_SIMD8 - -#define stbir__4_coeff_start() \ - stbir__simdf8 tot0,tot1,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc ); \ - stbir__simdf8_0123to00000000( c, cs ); \ - stbir__simdf8_mult_mem( tot0, c, decode ); \ - stbir__simdf8_0123to11111111( c, cs ); \ - stbir__simdf8_mult_mem( tot1, c, decode+7 ); \ - stbir__simdf8_0123to22222222( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+14 ); \ - stbir__simdf8_0123to33333333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00000000( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf8_0123to11111111( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); \ - stbir__simdf8_0123to22222222( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ - stbir__simdf8_0123to33333333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 ); - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load1b( c, hc + (ofs) ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load1b( c, hc + (ofs) ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf8_load1b( c, hc + (ofs)+1 ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); - -#define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf8_load4b( cs, hc + (ofs) ); \ - stbir__simdf8_0123to00000000( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf8_0123to11111111( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); \ - stbir__simdf8_0123to22222222( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); - -#define stbir__store_output() \ - stbir__simdf8_add( tot0, tot0, tot1 ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 7; \ - if ( output < output_end ) \ - { \ - stbir__simdf8_store( output-7, tot0 ); \ - continue; \ - } \ - stbir__simdf_store( output-7+3, stbir__simdf_swiz(stbir__simdf8_gettop4(tot0),0,0,1,2) ); \ - stbir__simdf_store( output-7, stbir__if_simdf8_cast_to_simdf4(tot0) ); \ - break; - -#else - -#define stbir__4_coeff_start() \ - stbir__simdf tot0,tot1,tot2,tot3,c,cs; \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_mult_mem( tot1, c, decode+3 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_mult_mem( tot2, c, decode+7 ); \ - stbir__simdf_mult_mem( tot3, c, decode+10 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); \ - stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+21 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+24 ); - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); \ - stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+21 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 ); - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load1( c, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \ - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load2( cs, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); - -#define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - stbir__simdf_load( cs, hc + (ofs) ); \ - stbir__simdf_0123to0000( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \ - stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); \ - stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); - -#define stbir__store_output() \ - stbir__simdf_add( tot0, tot0, tot2 ); \ - stbir__simdf_add( tot1, tot1, tot3 ); \ - stbir__simdf_store( output+3, tot1 ); \ - stbir__simdf_store( output, tot0 ); \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 7; - -#endif - -#else - -#define stbir__1_coeff_only() \ - float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \ - c = hc[0]; \ - tot0 = decode[0]*c; \ - tot1 = decode[1]*c; \ - tot2 = decode[2]*c; \ - tot3 = decode[3]*c; \ - tot4 = decode[4]*c; \ - tot5 = decode[5]*c; \ - tot6 = decode[6]*c; - -#define stbir__2_coeff_only() \ - float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \ - c = hc[0]; \ - tot0 = decode[0]*c; \ - tot1 = decode[1]*c; \ - tot2 = decode[2]*c; \ - tot3 = decode[3]*c; \ - tot4 = decode[4]*c; \ - tot5 = decode[5]*c; \ - tot6 = decode[6]*c; \ - c = hc[1]; \ - tot0 += decode[7]*c; \ - tot1 += decode[8]*c; \ - tot2 += decode[9]*c; \ - tot3 += decode[10]*c; \ - tot4 += decode[11]*c; \ - tot5 += decode[12]*c; \ - tot6 += decode[13]*c; \ - -#define stbir__3_coeff_only() \ - float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \ - c = hc[0]; \ - tot0 = decode[0]*c; \ - tot1 = decode[1]*c; \ - tot2 = decode[2]*c; \ - tot3 = decode[3]*c; \ - tot4 = decode[4]*c; \ - tot5 = decode[5]*c; \ - tot6 = decode[6]*c; \ - c = hc[1]; \ - tot0 += decode[7]*c; \ - tot1 += decode[8]*c; \ - tot2 += decode[9]*c; \ - tot3 += decode[10]*c; \ - tot4 += decode[11]*c; \ - tot5 += decode[12]*c; \ - tot6 += decode[13]*c; \ - c = hc[2]; \ - tot0 += decode[14]*c; \ - tot1 += decode[15]*c; \ - tot2 += decode[16]*c; \ - tot3 += decode[17]*c; \ - tot4 += decode[18]*c; \ - tot5 += decode[19]*c; \ - tot6 += decode[20]*c; \ - -#define stbir__store_output_tiny() \ - output[0] = tot0; \ - output[1] = tot1; \ - output[2] = tot2; \ - output[3] = tot3; \ - output[4] = tot4; \ - output[5] = tot5; \ - output[6] = tot6; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 7; - -#define stbir__4_coeff_start() \ - float x0,x1,x2,x3,x4,x5,x6,y0,y1,y2,y3,y4,y5,y6,c; \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0]; \ - x0 = decode[0] * c; \ - x1 = decode[1] * c; \ - x2 = decode[2] * c; \ - x3 = decode[3] * c; \ - x4 = decode[4] * c; \ - x5 = decode[5] * c; \ - x6 = decode[6] * c; \ - c = hc[1]; \ - y0 = decode[7] * c; \ - y1 = decode[8] * c; \ - y2 = decode[9] * c; \ - y3 = decode[10] * c; \ - y4 = decode[11] * c; \ - y5 = decode[12] * c; \ - y6 = decode[13] * c; \ - c = hc[2]; \ - x0 += decode[14] * c; \ - x1 += decode[15] * c; \ - x2 += decode[16] * c; \ - x3 += decode[17] * c; \ - x4 += decode[18] * c; \ - x5 += decode[19] * c; \ - x6 += decode[20] * c; \ - c = hc[3]; \ - y0 += decode[21] * c; \ - y1 += decode[22] * c; \ - y2 += decode[23] * c; \ - y3 += decode[24] * c; \ - y4 += decode[25] * c; \ - y5 += decode[26] * c; \ - y6 += decode[27] * c; - -#define stbir__4_coeff_continue_from_4( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*7] * c; \ - x1 += decode[1+(ofs)*7] * c; \ - x2 += decode[2+(ofs)*7] * c; \ - x3 += decode[3+(ofs)*7] * c; \ - x4 += decode[4+(ofs)*7] * c; \ - x5 += decode[5+(ofs)*7] * c; \ - x6 += decode[6+(ofs)*7] * c; \ - c = hc[1+(ofs)]; \ - y0 += decode[7+(ofs)*7] * c; \ - y1 += decode[8+(ofs)*7] * c; \ - y2 += decode[9+(ofs)*7] * c; \ - y3 += decode[10+(ofs)*7] * c; \ - y4 += decode[11+(ofs)*7] * c; \ - y5 += decode[12+(ofs)*7] * c; \ - y6 += decode[13+(ofs)*7] * c; \ - c = hc[2+(ofs)]; \ - x0 += decode[14+(ofs)*7] * c; \ - x1 += decode[15+(ofs)*7] * c; \ - x2 += decode[16+(ofs)*7] * c; \ - x3 += decode[17+(ofs)*7] * c; \ - x4 += decode[18+(ofs)*7] * c; \ - x5 += decode[19+(ofs)*7] * c; \ - x6 += decode[20+(ofs)*7] * c; \ - c = hc[3+(ofs)]; \ - y0 += decode[21+(ofs)*7] * c; \ - y1 += decode[22+(ofs)*7] * c; \ - y2 += decode[23+(ofs)*7] * c; \ - y3 += decode[24+(ofs)*7] * c; \ - y4 += decode[25+(ofs)*7] * c; \ - y5 += decode[26+(ofs)*7] * c; \ - y6 += decode[27+(ofs)*7] * c; - -#define stbir__1_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*7] * c; \ - x1 += decode[1+(ofs)*7] * c; \ - x2 += decode[2+(ofs)*7] * c; \ - x3 += decode[3+(ofs)*7] * c; \ - x4 += decode[4+(ofs)*7] * c; \ - x5 += decode[5+(ofs)*7] * c; \ - x6 += decode[6+(ofs)*7] * c; \ - -#define stbir__2_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*7] * c; \ - x1 += decode[1+(ofs)*7] * c; \ - x2 += decode[2+(ofs)*7] * c; \ - x3 += decode[3+(ofs)*7] * c; \ - x4 += decode[4+(ofs)*7] * c; \ - x5 += decode[5+(ofs)*7] * c; \ - x6 += decode[6+(ofs)*7] * c; \ - c = hc[1+(ofs)]; \ - y0 += decode[7+(ofs)*7] * c; \ - y1 += decode[8+(ofs)*7] * c; \ - y2 += decode[9+(ofs)*7] * c; \ - y3 += decode[10+(ofs)*7] * c; \ - y4 += decode[11+(ofs)*7] * c; \ - y5 += decode[12+(ofs)*7] * c; \ - y6 += decode[13+(ofs)*7] * c; \ - -#define stbir__3_coeff_remnant( ofs ) \ - STBIR_SIMD_NO_UNROLL(decode); \ - c = hc[0+(ofs)]; \ - x0 += decode[0+(ofs)*7] * c; \ - x1 += decode[1+(ofs)*7] * c; \ - x2 += decode[2+(ofs)*7] * c; \ - x3 += decode[3+(ofs)*7] * c; \ - x4 += decode[4+(ofs)*7] * c; \ - x5 += decode[5+(ofs)*7] * c; \ - x6 += decode[6+(ofs)*7] * c; \ - c = hc[1+(ofs)]; \ - y0 += decode[7+(ofs)*7] * c; \ - y1 += decode[8+(ofs)*7] * c; \ - y2 += decode[9+(ofs)*7] * c; \ - y3 += decode[10+(ofs)*7] * c; \ - y4 += decode[11+(ofs)*7] * c; \ - y5 += decode[12+(ofs)*7] * c; \ - y6 += decode[13+(ofs)*7] * c; \ - c = hc[2+(ofs)]; \ - x0 += decode[14+(ofs)*7] * c; \ - x1 += decode[15+(ofs)*7] * c; \ - x2 += decode[16+(ofs)*7] * c; \ - x3 += decode[17+(ofs)*7] * c; \ - x4 += decode[18+(ofs)*7] * c; \ - x5 += decode[19+(ofs)*7] * c; \ - x6 += decode[20+(ofs)*7] * c; \ - -#define stbir__store_output() \ - output[0] = x0 + y0; \ - output[1] = x1 + y1; \ - output[2] = x2 + y2; \ - output[3] = x3 + y3; \ - output[4] = x4 + y4; \ - output[5] = x5 + y5; \ - output[6] = x6 + y6; \ - horizontal_coefficients += coefficient_width; \ - ++horizontal_contributors; \ - output += 7; - -#endif - -#define STBIR__horizontal_channels 7 -#define STB_IMAGE_RESIZE_DO_HORIZONTALS -#include STBIR__HEADER_FILENAME - - -// include all of the vertical resamplers (both scatter and gather versions) - -#define STBIR__vertical_channels 1 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 1 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 2 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 2 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 3 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 3 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 4 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 4 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 5 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 5 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 6 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 6 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 7 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 7 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 8 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#include STBIR__HEADER_FILENAME - -#define STBIR__vertical_channels 8 -#define STB_IMAGE_RESIZE_DO_VERTICALS -#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#include STBIR__HEADER_FILENAME - -typedef void STBIR_VERTICAL_GATHERFUNC( float * output, float const * coeffs, float const ** inputs, float const * input0_end ); - -static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers[ 8 ] = -{ - stbir__vertical_gather_with_1_coeffs,stbir__vertical_gather_with_2_coeffs,stbir__vertical_gather_with_3_coeffs,stbir__vertical_gather_with_4_coeffs,stbir__vertical_gather_with_5_coeffs,stbir__vertical_gather_with_6_coeffs,stbir__vertical_gather_with_7_coeffs,stbir__vertical_gather_with_8_coeffs -}; - -static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers_continues[ 8 ] = -{ - stbir__vertical_gather_with_1_coeffs_cont,stbir__vertical_gather_with_2_coeffs_cont,stbir__vertical_gather_with_3_coeffs_cont,stbir__vertical_gather_with_4_coeffs_cont,stbir__vertical_gather_with_5_coeffs_cont,stbir__vertical_gather_with_6_coeffs_cont,stbir__vertical_gather_with_7_coeffs_cont,stbir__vertical_gather_with_8_coeffs_cont -}; - -typedef void STBIR_VERTICAL_SCATTERFUNC( float ** outputs, float const * coeffs, float const * input, float const * input_end ); - -static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_sets[ 8 ] = -{ - stbir__vertical_scatter_with_1_coeffs,stbir__vertical_scatter_with_2_coeffs,stbir__vertical_scatter_with_3_coeffs,stbir__vertical_scatter_with_4_coeffs,stbir__vertical_scatter_with_5_coeffs,stbir__vertical_scatter_with_6_coeffs,stbir__vertical_scatter_with_7_coeffs,stbir__vertical_scatter_with_8_coeffs -}; - -static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_blends[ 8 ] = -{ - stbir__vertical_scatter_with_1_coeffs_cont,stbir__vertical_scatter_with_2_coeffs_cont,stbir__vertical_scatter_with_3_coeffs_cont,stbir__vertical_scatter_with_4_coeffs_cont,stbir__vertical_scatter_with_5_coeffs_cont,stbir__vertical_scatter_with_6_coeffs_cont,stbir__vertical_scatter_with_7_coeffs_cont,stbir__vertical_scatter_with_8_coeffs_cont -}; - - -static void stbir__encode_scanline( stbir__info const * stbir_info, void *output_buffer_data, float * encode_buffer, int row STBIR_ONLY_PROFILE_GET_SPLIT_INFO ) -{ - int num_pixels = stbir_info->horizontal.scale_info.output_sub_size; - int channels = stbir_info->channels; - int width_times_channels = num_pixels * channels; - void * output_buffer; - - // un-alpha weight if we need to - if ( stbir_info->alpha_unweight ) - { - STBIR_PROFILE_START( unalpha ); - stbir_info->alpha_unweight( encode_buffer, width_times_channels ); - STBIR_PROFILE_END( unalpha ); - } - - // write directly into output by default - output_buffer = output_buffer_data; - - // if we have an output callback, we first convert the decode buffer in place (and then hand that to the callback) - if ( stbir_info->out_pixels_cb ) - output_buffer = encode_buffer; - - STBIR_PROFILE_START( encode ); - // convert into the output buffer - stbir_info->encode_pixels( output_buffer, width_times_channels, encode_buffer ); - STBIR_PROFILE_END( encode ); - - // if we have an output callback, call it to send the data - if ( stbir_info->out_pixels_cb ) - stbir_info->out_pixels_cb( output_buffer, num_pixels, row, stbir_info->user_data ); -} - - -// Get the ring buffer pointer for an index -static float* stbir__get_ring_buffer_entry(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int index ) -{ - STBIR_ASSERT( index < stbir_info->ring_buffer_num_entries ); - - #ifdef STBIR__SEPARATE_ALLOCATIONS - return split_info->ring_buffers[ index ]; - #else - return (float*) ( ( (char*) split_info->ring_buffer ) + ( index * stbir_info->ring_buffer_length_bytes ) ); - #endif -} - -// Get the specified scan line from the ring buffer -static float* stbir__get_ring_buffer_scanline(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int get_scanline) -{ - int ring_buffer_index = (split_info->ring_buffer_begin_index + (get_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; - return stbir__get_ring_buffer_entry( stbir_info, split_info, ring_buffer_index ); -} - -static void stbir__resample_horizontal_gather(stbir__info const * stbir_info, float* output_buffer, float const * input_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO ) -{ - float const * decode_buffer = input_buffer - ( stbir_info->scanline_extents.conservative.n0 * stbir_info->effective_channels ); - - STBIR_PROFILE_START( horizontal ); - if ( ( stbir_info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( stbir_info->horizontal.scale_info.scale == 1.0f ) ) - STBIR_MEMCPY( output_buffer, input_buffer, stbir_info->horizontal.scale_info.output_sub_size * sizeof( float ) * stbir_info->effective_channels ); - else - stbir_info->horizontal_gather_channels( output_buffer, stbir_info->horizontal.scale_info.output_sub_size, decode_buffer, stbir_info->horizontal.contributors, stbir_info->horizontal.coefficients, stbir_info->horizontal.coefficient_width ); - STBIR_PROFILE_END( horizontal ); -} - -static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n, int contrib_n0, int contrib_n1, float const * vertical_coefficients ) -{ - float* encode_buffer = split_info->vertical_buffer; - float* decode_buffer = split_info->decode_buffer; - int vertical_first = stbir_info->vertical_first; - int width = (vertical_first) ? ( stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1 ) : stbir_info->horizontal.scale_info.output_sub_size; - int width_times_channels = stbir_info->effective_channels * width; - - STBIR_ASSERT( stbir_info->vertical.is_gather ); - - // loop over the contributing scanlines and scale into the buffer - STBIR_PROFILE_START( vertical ); - { - int k = 0, total = contrib_n1 - contrib_n0 + 1; - STBIR_ASSERT( total > 0 ); - do { - float const * inputs[8]; - int i, cnt = total; if ( cnt > 8 ) cnt = 8; - for( i = 0 ; i < cnt ; i++ ) - inputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+contrib_n0 ); - - // call the N scanlines at a time function (up to 8 scanlines of blending at once) - ((k==0)?stbir__vertical_gathers:stbir__vertical_gathers_continues)[cnt-1]( (vertical_first) ? decode_buffer : encode_buffer, vertical_coefficients + k, inputs, inputs[0] + width_times_channels ); - k += cnt; - total -= cnt; - } while ( total ); - } - STBIR_PROFILE_END( vertical ); - - if ( vertical_first ) - { - // Now resample the gathered vertical data in the horizontal axis into the encode buffer - stbir__resample_horizontal_gather(stbir_info, encode_buffer, decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - } - - stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((size_t)n * (size_t)stbir_info->output_stride_bytes), - encode_buffer, n STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); -} - -static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n) -{ - int ring_buffer_index; - float* ring_buffer; - - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, n, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // update new end scanline - split_info->ring_buffer_last_scanline = n; - - // get ring buffer - ring_buffer_index = (split_info->ring_buffer_begin_index + (split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; - ring_buffer = stbir__get_ring_buffer_entry(stbir_info, split_info, ring_buffer_index); - - // Now resample it into the ring buffer. - stbir__resample_horizontal_gather( stbir_info, ring_buffer, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. -} - -static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count ) -{ - int y, start_output_y, end_output_y; - stbir__contributors* vertical_contributors = stbir_info->vertical.contributors; - float const * vertical_coefficients = stbir_info->vertical.coefficients; - - STBIR_ASSERT( stbir_info->vertical.is_gather ); - - start_output_y = split_info->start_output_y; - end_output_y = split_info[split_count-1].end_output_y; - - vertical_contributors += start_output_y; - vertical_coefficients += start_output_y * stbir_info->vertical.coefficient_width; - - // initialize the ring buffer for gathering - split_info->ring_buffer_begin_index = 0; - split_info->ring_buffer_first_scanline = vertical_contributors->n0; - split_info->ring_buffer_last_scanline = split_info->ring_buffer_first_scanline - 1; // means "empty" - - for (y = start_output_y; y < end_output_y; y++) - { - int in_first_scanline, in_last_scanline; - - in_first_scanline = vertical_contributors->n0; - in_last_scanline = vertical_contributors->n1; - - // make sure the indexing hasn't broken - STBIR_ASSERT( in_first_scanline >= split_info->ring_buffer_first_scanline ); - - // Load in new scanlines - while (in_last_scanline > split_info->ring_buffer_last_scanline) - { - STBIR_ASSERT( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) <= stbir_info->ring_buffer_num_entries ); - - // make sure there was room in the ring buffer when we add new scanlines - if ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries ) - { - split_info->ring_buffer_first_scanline++; - split_info->ring_buffer_begin_index++; - } - - if ( stbir_info->vertical_first ) - { - float * ring_buffer = stbir__get_ring_buffer_scanline( stbir_info, split_info, ++split_info->ring_buffer_last_scanline ); - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - } - else - { - stbir__decode_and_resample_for_vertical_gather_loop(stbir_info, split_info, split_info->ring_buffer_last_scanline + 1); - } - } - - // Now all buffers should be ready to write a row of vertical sampling, so do it. - stbir__resample_vertical_gather(stbir_info, split_info, y, in_first_scanline, in_last_scanline, vertical_coefficients ); - - ++vertical_contributors; - vertical_coefficients += stbir_info->vertical.coefficient_width; - } -} - -#define STBIR__FLOAT_EMPTY_MARKER 3.0e+38F -#define STBIR__FLOAT_BUFFER_IS_EMPTY(ptr) ((ptr)[0]==STBIR__FLOAT_EMPTY_MARKER) - -static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info) -{ - // evict a scanline out into the output buffer - float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index ); - - // dump the scanline out - stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // mark it as empty - ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER; - - // advance the first scanline - split_info->ring_buffer_first_scanline++; - if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries ) - split_info->ring_buffer_begin_index = 0; -} - -static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info) -{ - // evict a scanline out into the output buffer - - float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index ); - - // Now resample it into the buffer. - stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, ring_buffer_entry STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // dump the scanline out - stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // mark it as empty - ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER; - - // advance the first scanline - split_info->ring_buffer_first_scanline++; - if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries ) - split_info->ring_buffer_begin_index = 0; -} - -static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n0, int n1, float const * vertical_coefficients, float const * vertical_buffer, float const * vertical_buffer_end ) -{ - STBIR_ASSERT( !stbir_info->vertical.is_gather ); - - STBIR_PROFILE_START( vertical ); - { - int k = 0, total = n1 - n0 + 1; - STBIR_ASSERT( total > 0 ); - do { - float * outputs[8]; - int i, n = total; if ( n > 8 ) n = 8; - for( i = 0 ; i < n ; i++ ) - { - outputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+n0 ); - if ( ( i ) && ( STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[i] ) != STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ) ) ) // make sure runs are of the same type - { - n = i; - break; - } - } - // call the scatter to N scanlines at a time function (up to 8 scanlines of scattering at once) - ((STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ))?stbir__vertical_scatter_sets:stbir__vertical_scatter_blends)[n-1]( outputs, vertical_coefficients + k, vertical_buffer, vertical_buffer_end ); - k += n; - total -= n; - } while ( total ); - } - - STBIR_PROFILE_END( vertical ); -} - -typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info); - -static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count ) -{ - int y, start_output_y, end_output_y, start_input_y, end_input_y; - stbir__contributors* vertical_contributors = stbir_info->vertical.contributors; - float const * vertical_coefficients = stbir_info->vertical.coefficients; - stbir__handle_scanline_for_scatter_func * handle_scanline_for_scatter; - void * scanline_scatter_buffer; - void * scanline_scatter_buffer_end; - int on_first_input_y, last_input_y; - - STBIR_ASSERT( !stbir_info->vertical.is_gather ); - - start_output_y = split_info->start_output_y; - end_output_y = split_info[split_count-1].end_output_y; // may do multiple split counts - - start_input_y = split_info->start_input_y; - end_input_y = split_info[split_count-1].end_input_y; - - // adjust for starting offset start_input_y - y = start_input_y + stbir_info->vertical.filter_pixel_margin; - vertical_contributors += y ; - vertical_coefficients += stbir_info->vertical.coefficient_width * y; - - if ( stbir_info->vertical_first ) - { - handle_scanline_for_scatter = stbir__horizontal_resample_and_encode_first_scanline_from_scatter; - scanline_scatter_buffer = split_info->decode_buffer; - scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * (stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1); - } - else - { - handle_scanline_for_scatter = stbir__encode_first_scanline_from_scatter; - scanline_scatter_buffer = split_info->vertical_buffer; - scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * stbir_info->horizontal.scale_info.output_sub_size; - } - - // initialize the ring buffer for scattering - split_info->ring_buffer_first_scanline = start_output_y; - split_info->ring_buffer_last_scanline = -1; - split_info->ring_buffer_begin_index = -1; - - // mark all the buffers as empty to start - for( y = 0 ; y < stbir_info->ring_buffer_num_entries ; y++ ) - stbir__get_ring_buffer_entry( stbir_info, split_info, y )[0] = STBIR__FLOAT_EMPTY_MARKER; // only used on scatter - - // do the loop in input space - on_first_input_y = 1; last_input_y = start_input_y; - for (y = start_input_y ; y < end_input_y; y++) - { - int out_first_scanline, out_last_scanline; - - out_first_scanline = vertical_contributors->n0; - out_last_scanline = vertical_contributors->n1; - - STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); - - if ( ( out_last_scanline >= out_first_scanline ) && ( ( ( out_first_scanline >= start_output_y ) && ( out_first_scanline < end_output_y ) ) || ( ( out_last_scanline >= start_output_y ) && ( out_last_scanline < end_output_y ) ) ) ) - { - float const * vc = vertical_coefficients; - - // keep track of the range actually seen for the next resize - last_input_y = y; - if ( ( on_first_input_y ) && ( y > start_input_y ) ) - split_info->start_input_y = y; - on_first_input_y = 0; - - // clip the region - if ( out_first_scanline < start_output_y ) - { - vc += start_output_y - out_first_scanline; - out_first_scanline = start_output_y; - } - - if ( out_last_scanline >= end_output_y ) - out_last_scanline = end_output_y - 1; - - // if very first scanline, init the index - if (split_info->ring_buffer_begin_index < 0) - split_info->ring_buffer_begin_index = out_first_scanline - start_output_y; - - STBIR_ASSERT( split_info->ring_buffer_begin_index <= out_first_scanline ); - - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // When horizontal first, we resample horizontally into the vertical buffer before we scatter it out - if ( !stbir_info->vertical_first ) - stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - - // Now it's sitting in the buffer ready to be distributed into the ring buffers. - - // evict from the ringbuffer, if we need are full - if ( ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries ) && - ( out_last_scanline > split_info->ring_buffer_last_scanline ) ) - handle_scanline_for_scatter( stbir_info, split_info ); - - // Now the horizontal buffer is ready to write to all ring buffer rows, so do it. - stbir__resample_vertical_scatter(stbir_info, split_info, out_first_scanline, out_last_scanline, vc, (float*)scanline_scatter_buffer, (float*)scanline_scatter_buffer_end ); - - // update the end of the buffer - if ( out_last_scanline > split_info->ring_buffer_last_scanline ) - split_info->ring_buffer_last_scanline = out_last_scanline; - } - ++vertical_contributors; - vertical_coefficients += stbir_info->vertical.coefficient_width; - } - - // now evict the scanlines that are left over in the ring buffer - while ( split_info->ring_buffer_first_scanline < end_output_y ) - handle_scanline_for_scatter(stbir_info, split_info); - - // update the end_input_y if we do multiple resizes with the same data - ++last_input_y; - for( y = 0 ; y < split_count; y++ ) - if ( split_info[y].end_input_y > last_input_y ) - split_info[y].end_input_y = last_input_y; -} - - -static stbir__kernel_callback * stbir__builtin_kernels[] = { 0, stbir__filter_trapezoid, stbir__filter_triangle, stbir__filter_cubic, stbir__filter_catmullrom, stbir__filter_mitchell, stbir__filter_point }; -static stbir__support_callback * stbir__builtin_supports[] = { 0, stbir__support_trapezoid, stbir__support_one, stbir__support_two, stbir__support_two, stbir__support_two, stbir__support_zeropoint5 }; - -static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir__kernel_callback * kernel, stbir__support_callback * support, stbir_edge edge, stbir__scale_info * scale_info, int always_gather, void * user_data ) -{ - // set filter - if (filter == 0) - { - filter = STBIR_DEFAULT_FILTER_DOWNSAMPLE; // default to downsample - if (scale_info->scale >= ( 1.0f - stbir__small_float ) ) - { - if ( (scale_info->scale <= ( 1.0f + stbir__small_float ) ) && ( STBIR_CEILF(scale_info->pixel_shift) == scale_info->pixel_shift ) ) - filter = STBIR_FILTER_POINT_SAMPLE; - else - filter = STBIR_DEFAULT_FILTER_UPSAMPLE; - } - } - samp->filter_enum = filter; - - STBIR_ASSERT(samp->filter_enum != 0); - STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER); - samp->filter_kernel = stbir__builtin_kernels[ filter ]; - samp->filter_support = stbir__builtin_supports[ filter ]; - - if ( kernel && support ) - { - samp->filter_kernel = kernel; - samp->filter_support = support; - samp->filter_enum = STBIR_FILTER_OTHER; - } - - samp->edge = edge; - samp->filter_pixel_width = stbir__get_filter_pixel_width (samp->filter_support, scale_info->scale, user_data ); - // Gather is always better, but in extreme downsamples, you have to most or all of the data in memory - // For horizontal, we always have all the pixels, so we always use gather here (always_gather==1). - // For vertical, we use gather if scaling up (which means we will have samp->filter_pixel_width - // scanlines in memory at once). - samp->is_gather = 0; - if ( scale_info->scale >= ( 1.0f - stbir__small_float ) ) - samp->is_gather = 1; - else if ( ( always_gather ) || ( samp->filter_pixel_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ) ) - samp->is_gather = 2; - - // pre calculate stuff based on the above - samp->coefficient_width = stbir__get_coefficient_width(samp, samp->is_gather, user_data); - - // filter_pixel_width is the conservative size in pixels of input that affect an output pixel. - // In rare cases (only with 2 pix to 1 pix with the default filters), it's possible that the - // filter will extend before or after the scanline beyond just one extra entire copy of the - // scanline (we would hit the edge twice). We don't let you do that, so we clamp the total - // width to 3x the total of input pixel (once for the scanline, once for the left side - // overhang, and once for the right side). We only do this for edge mode, since the other - // modes can just re-edge clamp back in again. - if ( edge == STBIR_EDGE_WRAP ) - if ( samp->filter_pixel_width > ( scale_info->input_full_size * 3 ) ) - samp->filter_pixel_width = scale_info->input_full_size * 3; - - // This is how much to expand buffers to account for filters seeking outside - // the image boundaries. - samp->filter_pixel_margin = samp->filter_pixel_width / 2; - - // filter_pixel_margin is the amount that this filter can overhang on just one side of either - // end of the scanline (left or the right). Since we only allow you to overhang 1 scanline's - // worth of pixels, we clamp this one side of overhang to the input scanline size. Again, - // this clamping only happens in rare cases with the default filters (2 pix to 1 pix). - if ( edge == STBIR_EDGE_WRAP ) - if ( samp->filter_pixel_margin > scale_info->input_full_size ) - samp->filter_pixel_margin = scale_info->input_full_size; - - samp->num_contributors = stbir__get_contributors(samp, samp->is_gather); - - samp->contributors_size = samp->num_contributors * sizeof(stbir__contributors); - samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float); // extra sizeof(float) is padding - - samp->gather_prescatter_contributors = 0; - samp->gather_prescatter_coefficients = 0; - if ( samp->is_gather == 0 ) - { - samp->gather_prescatter_coefficient_width = samp->filter_pixel_width; - samp->gather_prescatter_num_contributors = stbir__get_contributors(samp, 2); - samp->gather_prescatter_contributors_size = samp->gather_prescatter_num_contributors * sizeof(stbir__contributors); - samp->gather_prescatter_coefficients_size = samp->gather_prescatter_num_contributors * samp->gather_prescatter_coefficient_width * sizeof(float); - } -} - -static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contributors * range, void * user_data ) -{ - float scale = samp->scale_info.scale; - float out_shift = samp->scale_info.pixel_shift; - stbir__support_callback * support = samp->filter_support; - int input_full_size = samp->scale_info.input_full_size; - stbir_edge edge = samp->edge; - float inv_scale = samp->scale_info.inv_scale; - - STBIR_ASSERT( samp->is_gather != 0 ); - - if ( samp->is_gather == 1 ) - { - int in_first_pixel, in_last_pixel; - float out_filter_radius = support(inv_scale, user_data) * scale; - - stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0.5, out_filter_radius, inv_scale, out_shift, input_full_size, edge ); - range->n0 = in_first_pixel; - stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, ( (float)(samp->scale_info.output_sub_size-1) ) + 0.5f, out_filter_radius, inv_scale, out_shift, input_full_size, edge ); - range->n1 = in_last_pixel; - } - else if ( samp->is_gather == 2 ) // downsample gather, refine - { - float in_pixels_radius = support(scale, user_data) * inv_scale; - int filter_pixel_margin = samp->filter_pixel_margin; - int output_sub_size = samp->scale_info.output_sub_size; - int input_end; - int n; - int in_first_pixel, in_last_pixel; - - // get a conservative area of the input range - stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0, 0, inv_scale, out_shift, input_full_size, edge ); - range->n0 = in_first_pixel; - stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, (float)output_sub_size, 0, inv_scale, out_shift, input_full_size, edge ); - range->n1 = in_last_pixel; - - // now go through the margin to the start of area to find bottom - n = range->n0 + 1; - input_end = -filter_pixel_margin; - while( n >= input_end ) - { - int out_first_pixel, out_last_pixel; - stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size ); - if ( out_first_pixel > out_last_pixel ) - break; - - if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) ) - range->n0 = n; - --n; - } - - // now go through the end of the area through the margin to find top - n = range->n1 - 1; - input_end = n + 1 + filter_pixel_margin; - while( n <= input_end ) - { - int out_first_pixel, out_last_pixel; - stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size ); - if ( out_first_pixel > out_last_pixel ) - break; - if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) ) - range->n1 = n; - ++n; - } - } - - if ( samp->edge == STBIR_EDGE_WRAP ) - { - // if we are wrapping, and we are very close to the image size (so the edges might merge), just use the scanline up to the edge - if ( ( range->n0 > 0 ) && ( range->n1 >= input_full_size ) ) - { - int marg = range->n1 - input_full_size + 1; - if ( ( marg + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= range->n0 ) - range->n0 = 0; - } - if ( ( range->n0 < 0 ) && ( range->n1 < (input_full_size-1) ) ) - { - int marg = -range->n0; - if ( ( input_full_size - marg - STBIR__MERGE_RUNS_PIXEL_THRESHOLD - 1 ) <= range->n1 ) - range->n1 = input_full_size - 1; - } - } - else - { - // for non-edge-wrap modes, we never read over the edge, so clamp - if ( range->n0 < 0 ) - range->n0 = 0; - if ( range->n1 >= input_full_size ) - range->n1 = input_full_size - 1; - } -} - -static void stbir__get_split_info( stbir__per_split_info* split_info, int splits, int output_height, int vertical_pixel_margin, int input_full_height ) -{ - int i, cur; - int left = output_height; - - cur = 0; - for( i = 0 ; i < splits ; i++ ) - { - int each; - split_info[i].start_output_y = cur; - each = left / ( splits - i ); - split_info[i].end_output_y = cur + each; - cur += each; - left -= each; - - // scatter range (updated to minimum as you run it) - split_info[i].start_input_y = -vertical_pixel_margin; - split_info[i].end_input_y = input_full_height + vertical_pixel_margin; - } -} - -static void stbir__free_internal_mem( stbir__info *info ) -{ - #define STBIR__FREE_AND_CLEAR( ptr ) { if ( ptr ) { void * p = (ptr); (ptr) = 0; STBIR_FREE( p, info->user_data); } } - - if ( info ) - { - #ifndef STBIR__SEPARATE_ALLOCATIONS - STBIR__FREE_AND_CLEAR( info->alloced_mem ); - #else - int i,j; - - if ( ( info->vertical.gather_prescatter_contributors ) && ( (void*)info->vertical.gather_prescatter_contributors != (void*)info->split_info[0].decode_buffer ) ) - { - STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_coefficients ); - STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_contributors ); - } - for( i = 0 ; i < info->splits ; i++ ) - { - for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ ) - { - #ifdef STBIR_SIMD8 - if ( info->effective_channels == 3 ) - --info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer - #endif - STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] ); - } - - #ifdef STBIR_SIMD8 - if ( info->effective_channels == 3 ) - --info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer - #endif - STBIR__FREE_AND_CLEAR( info->split_info[i].decode_buffer ); - STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers ); - STBIR__FREE_AND_CLEAR( info->split_info[i].vertical_buffer ); - } - STBIR__FREE_AND_CLEAR( info->split_info ); - if ( info->vertical.coefficients != info->horizontal.coefficients ) - { - STBIR__FREE_AND_CLEAR( info->vertical.coefficients ); - STBIR__FREE_AND_CLEAR( info->vertical.contributors ); - } - STBIR__FREE_AND_CLEAR( info->horizontal.coefficients ); - STBIR__FREE_AND_CLEAR( info->horizontal.contributors ); - STBIR__FREE_AND_CLEAR( info->alloced_mem ); - STBIR_FREE( info, info->user_data ); - #endif - } - - #undef STBIR__FREE_AND_CLEAR -} - -static int stbir__get_max_split( int splits, int height ) -{ - int i; - int max = 0; - - for( i = 0 ; i < splits ; i++ ) - { - int each = height / ( splits - i ); - if ( each > max ) - max = each; - height -= each; - } - return max; -} - -static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] = -{ - 0, stbir__horizontal_gather_1_channels_with_n_coeffs_funcs, stbir__horizontal_gather_2_channels_with_n_coeffs_funcs, stbir__horizontal_gather_3_channels_with_n_coeffs_funcs, stbir__horizontal_gather_4_channels_with_n_coeffs_funcs, 0,0, stbir__horizontal_gather_7_channels_with_n_coeffs_funcs -}; - -static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] = -{ - 0, stbir__horizontal_gather_1_channels_funcs, stbir__horizontal_gather_2_channels_funcs, stbir__horizontal_gather_3_channels_funcs, stbir__horizontal_gather_4_channels_funcs, 0,0, stbir__horizontal_gather_7_channels_funcs -}; - -// there are six resize classifications: 0 == vertical scatter, 1 == vertical gather < 1x scale, 2 == vertical gather 1x-2x scale, 4 == vertical gather < 3x scale, 4 == vertical gather > 3x scale, 5 == <=4 pixel height, 6 == <=4 pixel wide column -#define STBIR_RESIZE_CLASSIFICATIONS 8 - -static float stbir__compute_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4]= // 5 = 0=1chan, 1=2chan, 2=3chan, 3=4chan, 4=7chan -{ - { - { 1.00000f, 1.00000f, 0.31250f, 1.00000f }, - { 0.56250f, 0.59375f, 0.00000f, 0.96875f }, - { 1.00000f, 0.06250f, 0.00000f, 1.00000f }, - { 0.00000f, 0.09375f, 1.00000f, 1.00000f }, - { 1.00000f, 1.00000f, 1.00000f, 1.00000f }, - { 0.03125f, 0.12500f, 1.00000f, 1.00000f }, - { 0.06250f, 0.12500f, 0.00000f, 1.00000f }, - { 0.00000f, 1.00000f, 0.00000f, 0.03125f }, - }, { - { 0.00000f, 0.84375f, 0.00000f, 0.03125f }, - { 0.09375f, 0.93750f, 0.00000f, 0.78125f }, - { 0.87500f, 0.21875f, 0.00000f, 0.96875f }, - { 0.09375f, 0.09375f, 1.00000f, 1.00000f }, - { 1.00000f, 1.00000f, 1.00000f, 1.00000f }, - { 0.03125f, 0.12500f, 1.00000f, 1.00000f }, - { 0.06250f, 0.12500f, 0.00000f, 1.00000f }, - { 0.00000f, 1.00000f, 0.00000f, 0.53125f }, - }, { - { 0.00000f, 0.53125f, 0.00000f, 0.03125f }, - { 0.06250f, 0.96875f, 0.00000f, 0.53125f }, - { 0.87500f, 0.18750f, 0.00000f, 0.93750f }, - { 0.00000f, 0.09375f, 1.00000f, 1.00000f }, - { 1.00000f, 1.00000f, 1.00000f, 1.00000f }, - { 0.03125f, 0.12500f, 1.00000f, 1.00000f }, - { 0.06250f, 0.12500f, 0.00000f, 1.00000f }, - { 0.00000f, 1.00000f, 0.00000f, 0.56250f }, - }, { - { 0.00000f, 0.50000f, 0.00000f, 0.71875f }, - { 0.06250f, 0.84375f, 0.00000f, 0.87500f }, - { 1.00000f, 0.50000f, 0.50000f, 0.96875f }, - { 1.00000f, 0.09375f, 0.31250f, 0.50000f }, - { 1.00000f, 1.00000f, 1.00000f, 1.00000f }, - { 1.00000f, 0.03125f, 0.03125f, 0.53125f }, - { 0.18750f, 0.12500f, 0.00000f, 1.00000f }, - { 0.00000f, 1.00000f, 0.03125f, 0.18750f }, - }, { - { 0.00000f, 0.59375f, 0.00000f, 0.96875f }, - { 0.06250f, 0.81250f, 0.06250f, 0.59375f }, - { 0.75000f, 0.43750f, 0.12500f, 0.96875f }, - { 0.87500f, 0.06250f, 0.18750f, 0.43750f }, - { 1.00000f, 1.00000f, 1.00000f, 1.00000f }, - { 0.15625f, 0.12500f, 1.00000f, 1.00000f }, - { 0.06250f, 0.12500f, 0.00000f, 1.00000f }, - { 0.00000f, 1.00000f, 0.03125f, 0.34375f }, - } -}; - -// structure that allow us to query and override info for training the costs -typedef struct STBIR__V_FIRST_INFO -{ - double v_cost, h_cost; - int control_v_first; // 0 = no control, 1 = force hori, 2 = force vert - int v_first; - int v_resize_classification; - int is_gather; -} STBIR__V_FIRST_INFO; - -#ifdef STBIR__V_FIRST_INFO_BUFFER -static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0}; -#define STBIR__V_FIRST_INFO_POINTER &STBIR__V_FIRST_INFO_BUFFER -#else -#define STBIR__V_FIRST_INFO_POINTER 0 -#endif - -// Figure out whether to scale along the horizontal or vertical first. -// This only *super* important when you are scaling by a massively -// different amount in the vertical vs the horizontal (for example, if -// you are scaling by 2x in the width, and 0.5x in the height, then you -// want to do the vertical scale first, because it's around 3x faster -// in that order. -// -// In more normal circumstances, this makes a 20-40% differences, so -// it's good to get right, but not critical. The normal way that you -// decide which direction goes first is just figuring out which -// direction does more multiplies. But with modern CPUs with their -// fancy caches and SIMD and high IPC abilities, so there's just a lot -// more that goes into it. -// -// My handwavy sort of solution is to have an app that does a whole -// bunch of timing for both vertical and horizontal first modes, -// and then another app that can read lots of these timing files -// and try to search for the best weights to use. Dotimings.c -// is the app that does a bunch of timings, and vf_train.c is the -// app that solves for the best weights (and shows how well it -// does currently). - -static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info ) -{ - double v_cost, h_cost; - float * weights; - int vertical_first; - int v_classification; - - // categorize the resize into buckets - if ( ( vertical_output_size <= 4 ) || ( horizontal_output_size <= 4 ) ) - v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7; - else if ( vertical_scale <= 1.0f ) - v_classification = ( is_gather ) ? 1 : 0; - else if ( vertical_scale <= 2.0f) - v_classification = 2; - else if ( vertical_scale <= 3.0f) - v_classification = 3; - else if ( vertical_scale <= 4.0f) - v_classification = 5; - else - v_classification = 6; - - // use the right weights - weights = weights_table[ v_classification ]; - - // this is the costs when you don't take into account modern CPUs with high ipc and simd and caches - wish we had a better estimate - h_cost = (float)horizontal_filter_pixel_width * weights[0] + horizontal_scale * (float)vertical_filter_pixel_width * weights[1]; - v_cost = (float)vertical_filter_pixel_width * weights[2] + vertical_scale * (float)horizontal_filter_pixel_width * weights[3]; - - // use computation estimate to decide vertical first or not - vertical_first = ( v_cost <= h_cost ) ? 1 : 0; - - // save these, if requested - if ( info ) - { - info->h_cost = h_cost; - info->v_cost = v_cost; - info->v_resize_classification = v_classification; - info->v_first = vertical_first; - info->is_gather = is_gather; - } - - // and this allows us to override everything for testing (see dotiming.c) - if ( ( info ) && ( info->control_v_first ) ) - vertical_first = ( info->control_v_first == 2 ) ? 1 : 0; - - return vertical_first; -} - -// layout lookups - must match stbir_internal_pixel_layout -static unsigned char stbir__pixel_channels[] = { - 1,2,3,3,4, // 1ch, 2ch, rgb, bgr, 4ch - 4,4,4,4,2,2, // RGBA,BGRA,ARGB,ABGR,RA,AR - 4,4,4,4,2,2, // RGBA_PM,BGRA_PM,ARGB_PM,ABGR_PM,RA_PM,AR_PM -}; - -// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types -// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible -static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = { - STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA, - STBIRI_4CHANNEL, STBIRI_BGRA, STBIRI_ARGB, STBIRI_ABGR, STBIRI_RA, STBIRI_AR, - STBIRI_RGBA_PM, STBIRI_BGRA_PM, STBIRI_ARGB_PM, STBIRI_ABGR_PM, STBIRI_RA_PM, STBIRI_AR_PM, -}; - -static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sampler * horizontal, stbir__sampler * vertical, stbir__contributors * conservative, stbir_pixel_layout input_pixel_layout_public, stbir_pixel_layout output_pixel_layout_public, int splits, int new_x, int new_y, int fast_alpha, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO ) -{ - static char stbir_channel_count_index[8]={ 9,0,1,2, 3,9,9,4 }; - - stbir__info * info = 0; - void * alloced = 0; - size_t alloced_total = 0; - int vertical_first; - int decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size, alloc_ring_buffer_num_entries; - - int alpha_weighting_type = 0; // 0=none, 1=simple, 2=fancy - int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size ); - stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ]; - stbir_internal_pixel_layout output_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ output_pixel_layout_public ]; - int channels = stbir__pixel_channels[ input_pixel_layout ]; - int effective_channels = channels; - - // first figure out what type of alpha weighting to use (if any) - if ( ( horizontal->filter_enum != STBIR_FILTER_POINT_SAMPLE ) || ( vertical->filter_enum != STBIR_FILTER_POINT_SAMPLE ) ) // no alpha weighting on point sampling - { - if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) ) - { - if ( fast_alpha ) - { - alpha_weighting_type = 4; - } - else - { - static int fancy_alpha_effective_cnts[6] = { 7, 7, 7, 7, 3, 3 }; - alpha_weighting_type = 2; - effective_channels = fancy_alpha_effective_cnts[ input_pixel_layout - STBIRI_RGBA ]; - } - } - else if ( ( input_pixel_layout >= STBIRI_RGBA_PM ) && ( input_pixel_layout <= STBIRI_AR_PM ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) ) - { - // input premult, output non-premult - alpha_weighting_type = 3; - } - else if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA_PM ) && ( output_pixel_layout <= STBIRI_AR_PM ) ) - { - // input non-premult, output premult - alpha_weighting_type = 1; - } - } - - // channel in and out count must match currently - if ( channels != stbir__pixel_channels[ output_pixel_layout ] ) - return 0; - - // get vertical first - vertical_first = stbir__should_do_vertical_first( stbir__compute_weights[ (int)stbir_channel_count_index[ effective_channels ] ], horizontal->filter_pixel_width, horizontal->scale_info.scale, horizontal->scale_info.output_sub_size, vertical->filter_pixel_width, vertical->scale_info.scale, vertical->scale_info.output_sub_size, vertical->is_gather, STBIR__V_FIRST_INFO_POINTER ); - - // sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect) - decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float); // extra float for padding - -#if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8) - if ( effective_channels == 3 ) - decode_buffer_size += sizeof(float); // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations) -#endif - - ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding - - // if we do vertical first, the ring buffer holds a whole decoded line - if ( vertical_first ) - ring_buffer_length_bytes = ( decode_buffer_size + 15 ) & ~15; - - if ( ( ring_buffer_length_bytes & 4095 ) == 0 ) ring_buffer_length_bytes += 64*3; // avoid 4k alias - - // One extra entry because floating point precision problems sometimes cause an extra to be necessary. - alloc_ring_buffer_num_entries = vertical->filter_pixel_width + 1; - - // we never need more ring buffer entries than the scanlines we're outputting when in scatter mode - if ( ( !vertical->is_gather ) && ( alloc_ring_buffer_num_entries > conservative_split_output_size ) ) - alloc_ring_buffer_num_entries = conservative_split_output_size; - - ring_buffer_size = alloc_ring_buffer_num_entries * ring_buffer_length_bytes; - - // The vertical buffer is used differently, depending on whether we are scattering - // the vertical scanlines, or gathering them. - // If scattering, it's used at the temp buffer to accumulate each output. - // If gathering, it's just the output buffer. - vertical_buffer_size = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding - - // we make two passes through this loop, 1st to add everything up, 2nd to allocate and init - for(;;) - { - int i; - void * advance_mem = alloced; - int copy_horizontal = 0; - stbir__sampler * possibly_use_horizontal_for_pivot = 0; - -#ifdef STBIR__SEPARATE_ALLOCATIONS - #define STBIR__NEXT_PTR( ptr, size, ntype ) if ( alloced ) { void * p = STBIR_MALLOC( size, user_data); if ( p == 0 ) { stbir__free_internal_mem( info ); return 0; } (ptr) = (ntype*)p; } -#else - #define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size); -#endif - - STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info ); - - STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info ); - - if ( info ) - { - static stbir__alpha_weight_func * fancy_alpha_weights[6] = { stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_2ch, stbir__fancy_alpha_weight_2ch }; - static stbir__alpha_unweight_func * fancy_alpha_unweights[6] = { stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_2ch, stbir__fancy_alpha_unweight_2ch }; - static stbir__alpha_weight_func * simple_alpha_weights[6] = { stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_2ch, stbir__simple_alpha_weight_2ch }; - static stbir__alpha_unweight_func * simple_alpha_unweights[6] = { stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_2ch, stbir__simple_alpha_unweight_2ch }; - - // initialize info fields - info->alloced_mem = alloced; - info->alloced_total = alloced_total; - - info->channels = channels; - info->effective_channels = effective_channels; - - info->offset_x = new_x; - info->offset_y = new_y; - info->alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries; - info->ring_buffer_num_entries = 0; - info->ring_buffer_length_bytes = ring_buffer_length_bytes; - info->splits = splits; - info->vertical_first = vertical_first; - - info->input_pixel_layout_internal = input_pixel_layout; - info->output_pixel_layout_internal = output_pixel_layout; - - // setup alpha weight functions - info->alpha_weight = 0; - info->alpha_unweight = 0; - - // handle alpha weighting functions and overrides - if ( alpha_weighting_type == 2 ) - { - // high quality alpha multiplying on the way in, dividing on the way out - info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; - info->alpha_unweight = fancy_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; - } - else if ( alpha_weighting_type == 4 ) - { - // fast alpha multiplying on the way in, dividing on the way out - info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; - info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; - } - else if ( alpha_weighting_type == 1 ) - { - // fast alpha on the way in, leave in premultiplied form on way out - info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; - } - else if ( alpha_weighting_type == 3 ) - { - // incoming is premultiplied, fast alpha dividing on the way out - non-premultiplied output - info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; - } - - // handle 3-chan color flipping, using the alpha weight path - if ( ( ( input_pixel_layout == STBIRI_RGB ) && ( output_pixel_layout == STBIRI_BGR ) ) || - ( ( input_pixel_layout == STBIRI_BGR ) && ( output_pixel_layout == STBIRI_RGB ) ) ) - { - // do the flipping on the smaller of the two ends - if ( horizontal->scale_info.scale < 1.0f ) - info->alpha_unweight = stbir__simple_flip_3ch; - else - info->alpha_weight = stbir__simple_flip_3ch; - } - - } - - // get all the per-split buffers - for( i = 0 ; i < splits ; i++ ) - { - STBIR__NEXT_PTR( info->split_info[i].decode_buffer, decode_buffer_size, float ); - -#ifdef STBIR__SEPARATE_ALLOCATIONS - - #ifdef STBIR_SIMD8 - if ( ( info ) && ( effective_channels == 3 ) ) - ++info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer - #endif - - STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* ); - { - int j; - for( j = 0 ; j < alloc_ring_buffer_num_entries ; j++ ) - { - STBIR__NEXT_PTR( info->split_info[i].ring_buffers[j], ring_buffer_length_bytes, float ); - #ifdef STBIR_SIMD8 - if ( ( info ) && ( effective_channels == 3 ) ) - ++info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer - #endif - } - } -#else - STBIR__NEXT_PTR( info->split_info[i].ring_buffer, ring_buffer_size, float ); -#endif - STBIR__NEXT_PTR( info->split_info[i].vertical_buffer, vertical_buffer_size, float ); - } - - // alloc memory for to-be-pivoted coeffs (if necessary) - if ( vertical->is_gather == 0 ) - { - int both; - int temp_mem_amt; - - // when in vertical scatter mode, we first build the coefficients in gather mode, and then pivot after, - // that means we need two buffers, so we try to use the decode buffer and ring buffer for this. if that - // is too small, we just allocate extra memory to use as this temp. - - both = vertical->gather_prescatter_contributors_size + vertical->gather_prescatter_coefficients_size; - -#ifdef STBIR__SEPARATE_ALLOCATIONS - temp_mem_amt = decode_buffer_size; - - #ifdef STBIR_SIMD8 - if ( effective_channels == 3 ) - --temp_mem_amt; // avx in 3 channel mode needs one float at the start of the buffer - #endif -#else - temp_mem_amt = ( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * splits; -#endif - if ( temp_mem_amt >= both ) - { - if ( info ) - { - vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer; - vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size ); - } - } - else - { - // ring+decode memory is too small, so allocate temp memory - STBIR__NEXT_PTR( vertical->gather_prescatter_contributors, vertical->gather_prescatter_contributors_size, stbir__contributors ); - STBIR__NEXT_PTR( vertical->gather_prescatter_coefficients, vertical->gather_prescatter_coefficients_size, float ); - } - } - - STBIR__NEXT_PTR( horizontal->contributors, horizontal->contributors_size, stbir__contributors ); - STBIR__NEXT_PTR( horizontal->coefficients, horizontal->coefficients_size, float ); - - // are the two filters identical?? (happens a lot with mipmap generation) - if ( ( horizontal->filter_kernel == vertical->filter_kernel ) && ( horizontal->filter_support == vertical->filter_support ) && ( horizontal->edge == vertical->edge ) && ( horizontal->scale_info.output_sub_size == vertical->scale_info.output_sub_size ) ) - { - float diff_scale = horizontal->scale_info.scale - vertical->scale_info.scale; - float diff_shift = horizontal->scale_info.pixel_shift - vertical->scale_info.pixel_shift; - if ( diff_scale < 0.0f ) diff_scale = -diff_scale; - if ( diff_shift < 0.0f ) diff_shift = -diff_shift; - if ( ( diff_scale <= stbir__small_float ) && ( diff_shift <= stbir__small_float ) ) - { - if ( horizontal->is_gather == vertical->is_gather ) - { - copy_horizontal = 1; - goto no_vert_alloc; - } - // everything matches, but vertical is scatter, horizontal is gather, use horizontal coeffs for vertical pivot coeffs - possibly_use_horizontal_for_pivot = horizontal; - } - } - - STBIR__NEXT_PTR( vertical->contributors, vertical->contributors_size, stbir__contributors ); - STBIR__NEXT_PTR( vertical->coefficients, vertical->coefficients_size, float ); - - no_vert_alloc: - - if ( info ) - { - STBIR_PROFILE_BUILD_START( horizontal ); - - stbir__calculate_filters( horizontal, 0, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ); - - // setup the horizontal gather functions - // start with defaulting to the n_coeffs functions (specialized on channels and remnant leftover) - info->horizontal_gather_channels = stbir__horizontal_gather_n_coeffs_funcs[ effective_channels ][ horizontal->extent_info.widest & 3 ]; - // but if the number of coeffs <= 12, use another set of special cases. <=12 coeffs is any enlarging resize, or shrinking resize down to about 1/3 size - if ( horizontal->extent_info.widest <= 12 ) - info->horizontal_gather_channels = stbir__horizontal_gather_channels_funcs[ effective_channels ][ horizontal->extent_info.widest - 1 ]; - - info->scanline_extents.conservative.n0 = conservative->n0; - info->scanline_extents.conservative.n1 = conservative->n1; - - // get exact extents - stbir__get_extents( horizontal, &info->scanline_extents ); - - // pack the horizontal coeffs - horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n0, info->scanline_extents.conservative.n1 ); - - STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) ); - - STBIR_PROFILE_BUILD_END( horizontal ); - - if ( copy_horizontal ) - { - STBIR_MEMCPY( &info->vertical, horizontal, sizeof( stbir__sampler ) ); - } - else - { - STBIR_PROFILE_BUILD_START( vertical ); - - stbir__calculate_filters( vertical, possibly_use_horizontal_for_pivot, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ); - STBIR_MEMCPY( &info->vertical, vertical, sizeof( stbir__sampler ) ); - - STBIR_PROFILE_BUILD_END( vertical ); - } - - // setup the vertical split ranges - stbir__get_split_info( info->split_info, info->splits, info->vertical.scale_info.output_sub_size, info->vertical.filter_pixel_margin, info->vertical.scale_info.input_full_size ); - - // now we know precisely how many entries we need - info->ring_buffer_num_entries = info->vertical.extent_info.widest; - - // we never need more ring buffer entries than the scanlines we're outputting - if ( ( !info->vertical.is_gather ) && ( info->ring_buffer_num_entries > conservative_split_output_size ) ) - info->ring_buffer_num_entries = conservative_split_output_size; - STBIR_ASSERT( info->ring_buffer_num_entries <= info->alloc_ring_buffer_num_entries ); - - // a few of the horizontal gather functions read past the end of the decode (but mask it out), - // so put in normal values so no snans or denormals accidentally sneak in (also, in the ring - // buffer for vertical first) - for( i = 0 ; i < splits ; i++ ) - { - int t, ofs, start; - - ofs = decode_buffer_size / 4; - - #if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8) - if ( effective_channels == 3 ) - --ofs; // avx in 3 channel mode needs one float at the start of the buffer, so we snap back for clearing - #endif - - start = ofs - 4; - if ( start < 0 ) start = 0; - - for( t = start ; t < ofs; t++ ) - info->split_info[i].decode_buffer[ t ] = 9999.0f; - - if ( vertical_first ) - { - int j; - for( j = 0; j < info->ring_buffer_num_entries ; j++ ) - { - for( t = start ; t < ofs; t++ ) - stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ t ] = 9999.0f; - } - } - } - } - - #undef STBIR__NEXT_PTR - - - // is this the first time through loop? - if ( info == 0 ) - { - alloced_total = ( 15 + (size_t)advance_mem ); - alloced = STBIR_MALLOC( alloced_total, user_data ); - if ( alloced == 0 ) - return 0; - } - else - return info; // success - } -} - -static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count ) -{ - stbir__per_split_info * split_info = info->split_info + split_start; - - STBIR_PROFILE_CLEAR_EXTRAS(); - - STBIR_PROFILE_FIRST_START( looping ); - if (info->vertical.is_gather) - stbir__vertical_gather_loop( info, split_info, split_count ); - else - stbir__vertical_scatter_loop( info, split_info, split_count ); - STBIR_PROFILE_END( looping ); - - return 1; -} - -static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * resize ) -{ - static stbir__decode_pixels_func * decode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= - { - /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear, - }; - - static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= - { - { /* RGBA */ stbir__decode_uint8_srgb4_linearalpha, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear }, - { /* BGRA */ stbir__decode_uint8_srgb4_linearalpha_BGRA, stbir__decode_uint8_srgb_BGRA, 0, stbir__decode_float_linear_BGRA, stbir__decode_half_float_linear_BGRA }, - { /* ARGB */ stbir__decode_uint8_srgb4_linearalpha_ARGB, stbir__decode_uint8_srgb_ARGB, 0, stbir__decode_float_linear_ARGB, stbir__decode_half_float_linear_ARGB }, - { /* ABGR */ stbir__decode_uint8_srgb4_linearalpha_ABGR, stbir__decode_uint8_srgb_ABGR, 0, stbir__decode_float_linear_ABGR, stbir__decode_half_float_linear_ABGR }, - { /* RA */ stbir__decode_uint8_srgb2_linearalpha, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear }, - { /* AR */ stbir__decode_uint8_srgb2_linearalpha_AR, stbir__decode_uint8_srgb_AR, 0, stbir__decode_float_linear_AR, stbir__decode_half_float_linear_AR }, - }; - - static stbir__decode_pixels_func * decode_simple_scaled_or_not[2][2]= - { - { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear }, - }; - - static stbir__decode_pixels_func * decode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]= - { - { /* RGBA */ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear } }, - { /* BGRA */ { stbir__decode_uint8_linear_scaled_BGRA, stbir__decode_uint8_linear_BGRA }, { stbir__decode_uint16_linear_scaled_BGRA, stbir__decode_uint16_linear_BGRA } }, - { /* ARGB */ { stbir__decode_uint8_linear_scaled_ARGB, stbir__decode_uint8_linear_ARGB }, { stbir__decode_uint16_linear_scaled_ARGB, stbir__decode_uint16_linear_ARGB } }, - { /* ABGR */ { stbir__decode_uint8_linear_scaled_ABGR, stbir__decode_uint8_linear_ABGR }, { stbir__decode_uint16_linear_scaled_ABGR, stbir__decode_uint16_linear_ABGR } }, - { /* RA */ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear } }, - { /* AR */ { stbir__decode_uint8_linear_scaled_AR, stbir__decode_uint8_linear_AR }, { stbir__decode_uint16_linear_scaled_AR, stbir__decode_uint16_linear_AR } } - }; - - static stbir__encode_pixels_func * encode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= - { - /* 1ch-4ch */ stbir__encode_uint8_srgb, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear, - }; - - static stbir__encode_pixels_func * encode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= - { - { /* RGBA */ stbir__encode_uint8_srgb4_linearalpha, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear }, - { /* BGRA */ stbir__encode_uint8_srgb4_linearalpha_BGRA, stbir__encode_uint8_srgb_BGRA, 0, stbir__encode_float_linear_BGRA, stbir__encode_half_float_linear_BGRA }, - { /* ARGB */ stbir__encode_uint8_srgb4_linearalpha_ARGB, stbir__encode_uint8_srgb_ARGB, 0, stbir__encode_float_linear_ARGB, stbir__encode_half_float_linear_ARGB }, - { /* ABGR */ stbir__encode_uint8_srgb4_linearalpha_ABGR, stbir__encode_uint8_srgb_ABGR, 0, stbir__encode_float_linear_ABGR, stbir__encode_half_float_linear_ABGR }, - { /* RA */ stbir__encode_uint8_srgb2_linearalpha, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear }, - { /* AR */ stbir__encode_uint8_srgb2_linearalpha_AR, stbir__encode_uint8_srgb_AR, 0, stbir__encode_float_linear_AR, stbir__encode_half_float_linear_AR } - }; - - static stbir__encode_pixels_func * encode_simple_scaled_or_not[2][2]= - { - { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear }, - }; - - static stbir__encode_pixels_func * encode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]= - { - { /* RGBA */ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear } }, - { /* BGRA */ { stbir__encode_uint8_linear_scaled_BGRA, stbir__encode_uint8_linear_BGRA }, { stbir__encode_uint16_linear_scaled_BGRA, stbir__encode_uint16_linear_BGRA } }, - { /* ARGB */ { stbir__encode_uint8_linear_scaled_ARGB, stbir__encode_uint8_linear_ARGB }, { stbir__encode_uint16_linear_scaled_ARGB, stbir__encode_uint16_linear_ARGB } }, - { /* ABGR */ { stbir__encode_uint8_linear_scaled_ABGR, stbir__encode_uint8_linear_ABGR }, { stbir__encode_uint16_linear_scaled_ABGR, stbir__encode_uint16_linear_ABGR } }, - { /* RA */ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear } }, - { /* AR */ { stbir__encode_uint8_linear_scaled_AR, stbir__encode_uint8_linear_AR }, { stbir__encode_uint16_linear_scaled_AR, stbir__encode_uint16_linear_AR } } - }; - - stbir__decode_pixels_func * decode_pixels = 0; - stbir__encode_pixels_func * encode_pixels = 0; - stbir_datatype input_type, output_type; - - input_type = resize->input_data_type; - output_type = resize->output_data_type; - info->input_data = resize->input_pixels; - info->input_stride_bytes = resize->input_stride_in_bytes; - info->output_stride_bytes = resize->output_stride_in_bytes; - - // if we're completely point sampling, then we can turn off SRGB - if ( ( info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( info->vertical.filter_enum == STBIR_FILTER_POINT_SAMPLE ) ) - { - if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) && - ( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) ) - { - input_type = STBIR_TYPE_UINT8; - output_type = STBIR_TYPE_UINT8; - } - } - - // recalc the output and input strides - if ( info->input_stride_bytes == 0 ) - info->input_stride_bytes = info->channels * info->horizontal.scale_info.input_full_size * stbir__type_size[input_type]; - - if ( info->output_stride_bytes == 0 ) - info->output_stride_bytes = info->channels * info->horizontal.scale_info.output_sub_size * stbir__type_size[output_type]; - - // calc offset - info->output_data = ( (char*) resize->output_pixels ) + ( (size_t) info->offset_y * (size_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] ); - - info->in_pixels_cb = resize->input_cb; - info->user_data = resize->user_data; - info->out_pixels_cb = resize->output_cb; - - // setup the input format converters - if ( ( input_type == STBIR_TYPE_UINT8 ) || ( input_type == STBIR_TYPE_UINT16 ) ) - { - int non_scaled = 0; - - // check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16) - if ( ( !info->alpha_weight ) && ( !info->alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual) - if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) ) - non_scaled = 1; - - if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL ) - decode_pixels = decode_simple_scaled_or_not[ input_type == STBIR_TYPE_UINT16 ][ non_scaled ]; - else - decode_pixels = decode_alphas_scaled_or_not[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type == STBIR_TYPE_UINT16 ][ non_scaled ]; - } - else - { - if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL ) - decode_pixels = decode_simple[ input_type - STBIR_TYPE_UINT8_SRGB ]; - else - decode_pixels = decode_alphas[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type - STBIR_TYPE_UINT8_SRGB ]; - } - - // setup the output format converters - if ( ( output_type == STBIR_TYPE_UINT8 ) || ( output_type == STBIR_TYPE_UINT16 ) ) - { - int non_scaled = 0; - - // check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16) - if ( ( !info->alpha_weight ) && ( !info->alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual) - if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) ) - non_scaled = 1; - - if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL ) - encode_pixels = encode_simple_scaled_or_not[ output_type == STBIR_TYPE_UINT16 ][ non_scaled ]; - else - encode_pixels = encode_alphas_scaled_or_not[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type == STBIR_TYPE_UINT16 ][ non_scaled ]; - } - else - { - if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL ) - encode_pixels = encode_simple[ output_type - STBIR_TYPE_UINT8_SRGB ]; - else - encode_pixels = encode_alphas[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type - STBIR_TYPE_UINT8_SRGB ]; - } - - info->input_type = input_type; - info->output_type = output_type; - info->decode_pixels = decode_pixels; - info->encode_pixels = encode_pixels; -} - -static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, double * u1 ) -{ - double per, adj; - int over; - - // do left/top edge - if ( *outx < 0 ) - { - per = ( (double)*outx ) / ( (double)*outsubw ); // is negative - adj = per * ( *u1 - *u0 ); - *u0 -= adj; // increases u0 - *outx = 0; - } - - // do right/bot edge - over = outw - ( *outx + *outsubw ); - if ( over < 0 ) - { - per = ( (double)over ) / ( (double)*outsubw ); // is negative - adj = per * ( *u1 - *u0 ); - *u1 += adj; // decrease u1 - *outsubw = outw - *outx; - } -} - -// converts a double to a rational that has less than one float bit of error (returns 0 if unable to do so) -static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 *numer, stbir_uint32 *denom, int limit_denom ) // limit_denom (1) or limit numer (0) -{ - double err; - stbir_uint64 top, bot; - stbir_uint64 numer_last = 0; - stbir_uint64 denom_last = 1; - stbir_uint64 numer_estimate = 1; - stbir_uint64 denom_estimate = 0; - - // scale to past float error range - top = (stbir_uint64)( f * (double)(1 << 25) ); - bot = 1 << 25; - - // keep refining, but usually stops in a few loops - usually 5 for bad cases - for(;;) - { - stbir_uint64 est, temp; - - // hit limit, break out and do best full range estimate - if ( ( ( limit_denom ) ? denom_estimate : numer_estimate ) >= limit ) - break; - - // is the current error less than 1 bit of a float? if so, we're done - if ( denom_estimate ) - { - err = ( (double)numer_estimate / (double)denom_estimate ) - f; - if ( err < 0.0 ) err = -err; - if ( err < ( 1.0 / (double)(1<<24) ) ) - { - // yup, found it - *numer = (stbir_uint32) numer_estimate; - *denom = (stbir_uint32) denom_estimate; - return 1; - } - } - - // no more refinement bits left? break out and do full range estimate - if ( bot == 0 ) - break; - - // gcd the estimate bits - est = top / bot; - temp = top % bot; - top = bot; - bot = temp; - - // move remainders - temp = est * denom_estimate + denom_last; - denom_last = denom_estimate; - denom_estimate = temp; - - // move remainders - temp = est * numer_estimate + numer_last; - numer_last = numer_estimate; - numer_estimate = temp; - } - - // we didn't fine anything good enough for float, use a full range estimate - if ( limit_denom ) - { - numer_estimate= (stbir_uint64)( f * (double)limit + 0.5 ); - denom_estimate = limit; - } - else - { - numer_estimate = limit; - denom_estimate = (stbir_uint64)( ( (double)limit / f ) + 0.5 ); - } - - *numer = (stbir_uint32) numer_estimate; - *denom = (stbir_uint32) denom_estimate; - - err = ( denom_estimate ) ? ( ( (double)(stbir_uint32)numer_estimate / (double)(stbir_uint32)denom_estimate ) - f ) : 1.0; - if ( err < 0.0 ) err = -err; - return ( err < ( 1.0 / (double)(1<<24) ) ) ? 1 : 0; -} - -static int stbir__calculate_region_transform( stbir__scale_info * scale_info, int output_full_range, int * output_offset, int output_sub_range, int input_full_range, double input_s0, double input_s1 ) -{ - double output_range, input_range, output_s, input_s, ratio, scale; - - input_s = input_s1 - input_s0; - - // null area - if ( ( output_full_range == 0 ) || ( input_full_range == 0 ) || - ( output_sub_range == 0 ) || ( input_s <= stbir__small_float ) ) - return 0; - - // are either of the ranges completely out of bounds? - if ( ( *output_offset >= output_full_range ) || ( ( *output_offset + output_sub_range ) <= 0 ) || ( input_s0 >= (1.0f-stbir__small_float) ) || ( input_s1 <= stbir__small_float ) ) - return 0; - - output_range = (double)output_full_range; - input_range = (double)input_full_range; - - output_s = ( (double)output_sub_range) / output_range; - - // figure out the scaling to use - ratio = output_s / input_s; - - // save scale before clipping - scale = ( output_range / input_range ) * ratio; - scale_info->scale = (float)scale; - scale_info->inv_scale = (float)( 1.0 / scale ); - - // clip output area to left/right output edges (and adjust input area) - stbir__clip( output_offset, &output_sub_range, output_full_range, &input_s0, &input_s1 ); - - // recalc input area - input_s = input_s1 - input_s0; - - // after clipping do we have zero input area? - if ( input_s <= stbir__small_float ) - return 0; - - // calculate and store the starting source offsets in output pixel space - scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range ); - - scale_info->scale_is_rational = stbir__double_to_rational( scale, ( scale <= 1.0 ) ? output_full_range : input_full_range, &scale_info->scale_numerator, &scale_info->scale_denominator, ( scale >= 1.0 ) ); - - scale_info->input_full_size = input_full_range; - scale_info->output_sub_size = output_sub_range; - - return 1; -} - - -static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layout pixel_layout, stbir_datatype data_type ) -{ - resize->input_cb = 0; - resize->output_cb = 0; - resize->user_data = resize; - resize->samplers = 0; - resize->called_alloc = 0; - resize->horizontal_filter = STBIR_FILTER_DEFAULT; - resize->horizontal_filter_kernel = 0; resize->horizontal_filter_support = 0; - resize->vertical_filter = STBIR_FILTER_DEFAULT; - resize->vertical_filter_kernel = 0; resize->vertical_filter_support = 0; - resize->horizontal_edge = STBIR_EDGE_CLAMP; - resize->vertical_edge = STBIR_EDGE_CLAMP; - resize->input_s0 = 0; resize->input_t0 = 0; resize->input_s1 = 1; resize->input_t1 = 1; - resize->output_subx = 0; resize->output_suby = 0; resize->output_subw = resize->output_w; resize->output_subh = resize->output_h; - resize->input_data_type = data_type; - resize->output_data_type = data_type; - resize->input_pixel_layout_public = pixel_layout; - resize->output_pixel_layout_public = pixel_layout; - resize->needs_rebuild = 1; -} - -STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, - const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, // stride can be zero - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero - stbir_pixel_layout pixel_layout, stbir_datatype data_type ) -{ - resize->input_pixels = input_pixels; - resize->input_w = input_w; - resize->input_h = input_h; - resize->input_stride_in_bytes = input_stride_in_bytes; - resize->output_pixels = output_pixels; - resize->output_w = output_w; - resize->output_h = output_h; - resize->output_stride_in_bytes = output_stride_in_bytes; - resize->fast_alpha = 0; - - stbir__init_and_set_layout( resize, pixel_layout, data_type ); -} - -// You can update parameters any time after resize_init -STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ) // by default, datatype from resize_init -{ - resize->input_data_type = input_type; - resize->output_data_type = output_type; - if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) - stbir__update_info_from_resize( resize->samplers, resize ); -} - -STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ) // no callbacks by default -{ - resize->input_cb = input_cb; - resize->output_cb = output_cb; - - if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) - { - resize->samplers->in_pixels_cb = input_cb; - resize->samplers->out_pixels_cb = output_cb; - } -} - -STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ) // pass back STBIR_RESIZE* by default -{ - resize->user_data = user_data; - if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) - resize->samplers->user_data = user_data; -} - -STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes ) -{ - resize->input_pixels = input_pixels; - resize->input_stride_in_bytes = input_stride_in_bytes; - resize->output_pixels = output_pixels; - resize->output_stride_in_bytes = output_stride_in_bytes; - if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) - stbir__update_info_from_resize( resize->samplers, resize ); -} - - -STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ) // CLAMP by default -{ - resize->horizontal_edge = horizontal_edge; - resize->vertical_edge = vertical_edge; - resize->needs_rebuild = 1; - return 1; -} - -STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ) // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default -{ - resize->horizontal_filter = horizontal_filter; - resize->vertical_filter = vertical_filter; - resize->needs_rebuild = 1; - return 1; -} - -STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support ) -{ - resize->horizontal_filter_kernel = horizontal_filter; resize->horizontal_filter_support = horizontal_support; - resize->vertical_filter_kernel = vertical_filter; resize->vertical_filter_support = vertical_support; - resize->needs_rebuild = 1; - return 1; -} - -STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout ) // sets new pixel layouts -{ - resize->input_pixel_layout_public = input_pixel_layout; - resize->output_pixel_layout_public = output_pixel_layout; - resize->needs_rebuild = 1; - return 1; -} - - -STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality ) // sets alpha speed -{ - resize->fast_alpha = non_pma_alpha_speed_over_quality; - resize->needs_rebuild = 1; - return 1; -} - -STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ) // sets input region (full region by default) -{ - resize->input_s0 = s0; - resize->input_t0 = t0; - resize->input_s1 = s1; - resize->input_t1 = t1; - resize->needs_rebuild = 1; - - // are we inbounds? - if ( ( s1 < stbir__small_float ) || ( (s1-s0) < stbir__small_float ) || - ( t1 < stbir__small_float ) || ( (t1-t0) < stbir__small_float ) || - ( s0 > (1.0f-stbir__small_float) ) || - ( t0 > (1.0f-stbir__small_float) ) ) - return 0; - - return 1; -} - -STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ) // sets input region (full region by default) -{ - resize->output_subx = subx; - resize->output_suby = suby; - resize->output_subw = subw; - resize->output_subh = subh; - resize->needs_rebuild = 1; - - // are we inbounds? - if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) ) - return 0; - - return 1; -} - -STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ) // sets both regions (full regions by default) -{ - double s0, t0, s1, t1; - - s0 = ( (double)subx ) / ( (double)resize->output_w ); - t0 = ( (double)suby ) / ( (double)resize->output_h ); - s1 = ( (double)(subx+subw) ) / ( (double)resize->output_w ); - t1 = ( (double)(suby+subh) ) / ( (double)resize->output_h ); - - resize->input_s0 = s0; - resize->input_t0 = t0; - resize->input_s1 = s1; - resize->input_t1 = t1; - resize->output_subx = subx; - resize->output_suby = suby; - resize->output_subw = subw; - resize->output_subh = subh; - resize->needs_rebuild = 1; - - // are we inbounds? - if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) ) - return 0; - - return 1; -} - -static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) -{ - stbir__contributors conservative = { 0, 0 }; - stbir__sampler horizontal, vertical; - int new_output_subx, new_output_suby; - stbir__info * out_info; - #ifdef STBIR_PROFILE - stbir__info profile_infod; // used to contain building profile info before everything is allocated - stbir__info * profile_info = &profile_infod; - #endif - - // have we already built the samplers? - if ( resize->samplers ) - return 0; - - #define STBIR_RETURN_ERROR_AND_ASSERT( exp ) STBIR_ASSERT( !(exp) ); if (exp) return 0; - STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->horizontal_filter >= STBIR_FILTER_OTHER) - STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->vertical_filter >= STBIR_FILTER_OTHER) - #undef STBIR_RETURN_ERROR_AND_ASSERT - - if ( splits <= 0 ) - return 0; - - STBIR_PROFILE_BUILD_FIRST_START( build ); - - new_output_subx = resize->output_subx; - new_output_suby = resize->output_suby; - - // do horizontal clip and scale calcs - if ( !stbir__calculate_region_transform( &horizontal.scale_info, resize->output_w, &new_output_subx, resize->output_subw, resize->input_w, resize->input_s0, resize->input_s1 ) ) - return 0; - - // do vertical clip and scale calcs - if ( !stbir__calculate_region_transform( &vertical.scale_info, resize->output_h, &new_output_suby, resize->output_subh, resize->input_h, resize->input_t0, resize->input_t1 ) ) - return 0; - - // if nothing to do, just return - if ( ( horizontal.scale_info.output_sub_size == 0 ) || ( vertical.scale_info.output_sub_size == 0 ) ) - return 0; - - stbir__set_sampler(&horizontal, resize->horizontal_filter, resize->horizontal_filter_kernel, resize->horizontal_filter_support, resize->horizontal_edge, &horizontal.scale_info, 1, resize->user_data ); - stbir__get_conservative_extents( &horizontal, &conservative, resize->user_data ); - stbir__set_sampler(&vertical, resize->vertical_filter, resize->horizontal_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data ); - - if ( ( vertical.scale_info.output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice) - { - splits = vertical.scale_info.output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS; - if ( splits == 0 ) splits = 1; - } - - STBIR_PROFILE_BUILD_START( alloc ); - out_info = stbir__alloc_internal_mem_and_build_samplers( &horizontal, &vertical, &conservative, resize->input_pixel_layout_public, resize->output_pixel_layout_public, splits, new_output_subx, new_output_suby, resize->fast_alpha, resize->user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ); - STBIR_PROFILE_BUILD_END( alloc ); - STBIR_PROFILE_BUILD_END( build ); - - if ( out_info ) - { - resize->splits = splits; - resize->samplers = out_info; - resize->needs_rebuild = 0; - #ifdef STBIR_PROFILE - STBIR_MEMCPY( &out_info->profile, &profile_infod.profile, sizeof( out_info->profile ) ); - #endif - - // update anything that can be changed without recalcing samplers - stbir__update_info_from_resize( out_info, resize ); - - return splits; - } - - return 0; -} - -void stbir_free_samplers( STBIR_RESIZE * resize ) -{ - if ( resize->samplers ) - { - stbir__free_internal_mem( resize->samplers ); - resize->samplers = 0; - resize->called_alloc = 0; - } -} - -STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits ) -{ - if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) - { - if ( resize->samplers ) - stbir_free_samplers( resize ); - - resize->called_alloc = 1; - return stbir__perform_build( resize, splits ); - } - - STBIR_PROFILE_BUILD_CLEAR( resize->samplers ); - - return 1; -} - -STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ) -{ - return stbir_build_samplers_with_splits( resize, 1 ); -} - -STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) -{ - int result; - - if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) - { - int alloc_state = resize->called_alloc; // remember allocated state - - if ( resize->samplers ) - { - stbir__free_internal_mem( resize->samplers ); - resize->samplers = 0; - } - - if ( !stbir_build_samplers( resize ) ) - return 0; - - resize->called_alloc = alloc_state; - - // if build_samplers succeeded (above), but there are no samplers set, then - // the area to stretch into was zero pixels, so don't do anything and return - // success - if ( resize->samplers == 0 ) - return 1; - } - else - { - // didn't build anything - clear it - STBIR_PROFILE_BUILD_CLEAR( resize->samplers ); - } - - // do resize - result = stbir__perform_resize( resize->samplers, 0, resize->splits ); - - // if we alloced, then free - if ( !resize->called_alloc ) - { - stbir_free_samplers( resize ); - resize->samplers = 0; - } - - return result; -} - -STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count ) -{ - STBIR_ASSERT( resize->samplers ); - - // if we're just doing the whole thing, call full - if ( ( split_start == -1 ) || ( ( split_start == 0 ) && ( split_count == resize->splits ) ) ) - return stbir_resize_extended( resize ); - - // you **must** build samplers first when using split resize - if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) - return 0; - - if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) ) - return 0; - - // do resize - return stbir__perform_resize( resize->samplers, split_start, split_count ); -} - -static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * output_pixels, int type_size, int output_w, int output_h, int output_stride_in_bytes, stbir_internal_pixel_layout pixel_layout ) -{ - size_t size; - int pitch; - void * ptr; - - pitch = output_w * type_size * stbir__pixel_channels[ pixel_layout ]; - if ( pitch == 0 ) - return 0; - - if ( output_stride_in_bytes == 0 ) - output_stride_in_bytes = pitch; - - if ( output_stride_in_bytes < pitch ) - return 0; - - size = (size_t)output_stride_in_bytes * (size_t)output_h; - if ( size == 0 ) - return 0; - - *ret_ptr = 0; - *ret_pitch = output_stride_in_bytes; - - if ( output_pixels == 0 ) - { - ptr = STBIR_MALLOC( size, 0 ); - if ( ptr == 0 ) - return 0; - - *ret_ptr = ptr; - *ret_pitch = pitch; - } - - return 1; -} - - -STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout ) -{ - STBIR_RESIZE resize; - unsigned char * optr; - int opitch; - - if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) - return 0; - - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, - pixel_layout, STBIR_TYPE_UINT8 ); - - if ( !stbir_resize_extended( &resize ) ) - { - if ( optr ) - STBIR_FREE( optr, 0 ); - return 0; - } - - return (optr) ? optr : output_pixels; -} - -STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout ) -{ - STBIR_RESIZE resize; - unsigned char * optr; - int opitch; - - if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) - return 0; - - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, - pixel_layout, STBIR_TYPE_UINT8_SRGB ); - - if ( !stbir_resize_extended( &resize ) ) - { - if ( optr ) - STBIR_FREE( optr, 0 ); - return 0; - } - - return (optr) ? optr : output_pixels; -} - - -STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout ) -{ - STBIR_RESIZE resize; - float * optr; - int opitch; - - if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( float ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) - return 0; - - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, - pixel_layout, STBIR_TYPE_FLOAT ); - - if ( !stbir_resize_extended( &resize ) ) - { - if ( optr ) - STBIR_FREE( optr, 0 ); - return 0; - } - - return (optr) ? optr : output_pixels; -} - - -STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout, stbir_datatype data_type, - stbir_edge edge, stbir_filter filter ) -{ - STBIR_RESIZE resize; - float * optr; - int opitch; - - if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, stbir__type_size[data_type], output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) - return 0; - - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes, - pixel_layout, data_type ); - - resize.horizontal_edge = edge; - resize.vertical_edge = edge; - resize.horizontal_filter = filter; - resize.vertical_filter = filter; - - if ( !stbir_resize_extended( &resize ) ) - { - if ( optr ) - STBIR_FREE( optr, 0 ); - return 0; - } - - return (optr) ? optr : output_pixels; -} - -#ifdef STBIR_PROFILE - -STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize ) -{ - static char const * bdescriptions[6] = { "Building", "Allocating", "Horizontal sampler", "Vertical sampler", "Coefficient cleanup", "Coefficient piovot" } ; - stbir__info* samp = resize->samplers; - int i; - - typedef int testa[ (STBIR__ARRAY_SIZE( bdescriptions ) == (STBIR__ARRAY_SIZE( samp->profile.array )-1) )?1:-1]; - typedef int testb[ (sizeof( samp->profile.array ) == (sizeof(samp->profile.named)) )?1:-1]; - typedef int testc[ (sizeof( info->clocks ) >= (sizeof(samp->profile.named)) )?1:-1]; - - for( i = 0 ; i < STBIR__ARRAY_SIZE( bdescriptions ) ; i++) - info->clocks[i] = samp->profile.array[i+1]; - - info->total_clocks = samp->profile.named.total; - info->descriptions = bdescriptions; - info->count = STBIR__ARRAY_SIZE( bdescriptions ); -} - -STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize, int split_start, int split_count ) -{ - static char const * descriptions[7] = { "Looping", "Vertical sampling", "Horizontal sampling", "Scanline input", "Scanline output", "Alpha weighting", "Alpha unweighting" }; - stbir__per_split_info * split_info; - int s, i; - - typedef int testa[ (STBIR__ARRAY_SIZE( descriptions ) == (STBIR__ARRAY_SIZE( split_info->profile.array )-1) )?1:-1]; - typedef int testb[ (sizeof( split_info->profile.array ) == (sizeof(split_info->profile.named)) )?1:-1]; - typedef int testc[ (sizeof( info->clocks ) >= (sizeof(split_info->profile.named)) )?1:-1]; - - if ( split_start == -1 ) - { - split_start = 0; - split_count = resize->samplers->splits; - } - - if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) ) - { - info->total_clocks = 0; - info->descriptions = 0; - info->count = 0; - return; - } - - split_info = resize->samplers->split_info + split_start; - - // sum up the profile from all the splits - for( i = 0 ; i < STBIR__ARRAY_SIZE( descriptions ) ; i++ ) - { - stbir_uint64 sum = 0; - for( s = 0 ; s < split_count ; s++ ) - sum += split_info[s].profile.array[i+1]; - info->clocks[i] = sum; - } - - info->total_clocks = split_info->profile.named.total; - info->descriptions = descriptions; - info->count = STBIR__ARRAY_SIZE( descriptions ); -} - -STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize ) -{ - stbir_resize_split_profile_info( info, resize, -1, 0 ); -} - -#endif // STBIR_PROFILE - -#undef STBIR_BGR -#undef STBIR_1CHANNEL -#undef STBIR_2CHANNEL -#undef STBIR_RGB -#undef STBIR_RGBA -#undef STBIR_4CHANNEL -#undef STBIR_BGRA -#undef STBIR_ARGB -#undef STBIR_ABGR -#undef STBIR_RA -#undef STBIR_AR -#undef STBIR_RGBA_PM -#undef STBIR_BGRA_PM -#undef STBIR_ARGB_PM -#undef STBIR_ABGR_PM -#undef STBIR_RA_PM -#undef STBIR_AR_PM - -#endif // STB_IMAGE_RESIZE_IMPLEMENTATION - -#else // STB_IMAGE_RESIZE_HORIZONTALS&STB_IMAGE_RESIZE_DO_VERTICALS - -// we reinclude the header file to define all the horizontal functions -// specializing each function for the number of coeffs is 20-40% faster *OVERALL* - -// by including the header file again this way, we can still debug the functions - -#define STBIR_strs_join2( start, mid, end ) start##mid##end -#define STBIR_strs_join1( start, mid, end ) STBIR_strs_join2( start, mid, end ) - -#define STBIR_strs_join24( start, mid1, mid2, end ) start##mid1##mid2##end -#define STBIR_strs_join14( start, mid1, mid2, end ) STBIR_strs_join24( start, mid1, mid2, end ) - -#ifdef STB_IMAGE_RESIZE_DO_CODERS - -#ifdef stbir__decode_suffix -#define STBIR__CODER_NAME( name ) STBIR_strs_join1( name, _, stbir__decode_suffix ) -#else -#define STBIR__CODER_NAME( name ) name -#endif - -#ifdef stbir__decode_swizzle -#define stbir__decode_simdf8_flip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3),stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg) -#define stbir__decode_simdf4_flip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg) -#define stbir__encode_simdf8_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3),stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg) -#define stbir__encode_simdf4_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg) -#else -#define stbir__decode_order0 0 -#define stbir__decode_order1 1 -#define stbir__decode_order2 2 -#define stbir__decode_order3 3 -#define stbir__encode_order0 0 -#define stbir__encode_order1 1 -#define stbir__encode_order2 2 -#define stbir__encode_order3 3 -#define stbir__decode_simdf8_flip(reg) -#define stbir__decode_simdf4_flip(reg) -#define stbir__encode_simdf8_unflip(reg) -#define stbir__encode_simdf4_unflip(reg) -#endif - -#ifdef STBIR_SIMD8 -#define stbir__encode_simdfX_unflip stbir__encode_simdf8_unflip -#else -#define stbir__encode_simdfX_unflip stbir__encode_simdf4_unflip -#endif - -static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float * decode_end = (float*) decode + width_times_channels; - unsigned char const * input = (unsigned char const*)inputp; - - #ifdef STBIR_SIMD - unsigned char const * end_input_m16 = input + width_times_channels - 16; - if ( width_times_channels >= 16 ) - { - decode_end -= 16; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - #ifdef STBIR_SIMD8 - stbir__simdi i; stbir__simdi8 o0,o1; - stbir__simdf8 of0, of1; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi8_expand_u8_to_u32( o0, o1, i ); - stbir__simdi8_convert_i32_to_float( of0, o0 ); - stbir__simdi8_convert_i32_to_float( of1, o1 ); - stbir__simdf8_mult( of0, of0, STBIR_max_uint8_as_float_inverted8); - stbir__simdf8_mult( of1, of1, STBIR_max_uint8_as_float_inverted8); - stbir__decode_simdf8_flip( of0 ); - stbir__decode_simdf8_flip( of1 ); - stbir__simdf8_store( decode + 0, of0 ); - stbir__simdf8_store( decode + 8, of1 ); - #else - stbir__simdi i, o0, o1, o2, o3; - stbir__simdf of0, of1, of2, of3; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i); - stbir__simdi_convert_i32_to_float( of0, o0 ); - stbir__simdi_convert_i32_to_float( of1, o1 ); - stbir__simdi_convert_i32_to_float( of2, o2 ); - stbir__simdi_convert_i32_to_float( of3, o3 ); - stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) ); - stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) ); - stbir__simdf_mult( of2, of2, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) ); - stbir__simdf_mult( of3, of3, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) ); - stbir__decode_simdf4_flip( of0 ); - stbir__decode_simdf4_flip( of1 ); - stbir__decode_simdf4_flip( of2 ); - stbir__decode_simdf4_flip( of3 ); - stbir__simdf_store( decode + 0, of0 ); - stbir__simdf_store( decode + 4, of1 ); - stbir__simdf_store( decode + 8, of2 ); - stbir__simdf_store( decode + 12, of3 ); - #endif - decode += 16; - input += 16; - if ( decode <= decode_end ) - continue; - if ( decode == ( decode_end + 16 ) ) - break; - decode = decode_end; // backup and do last couple - input = end_input_m16; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode <= decode_end ) - { - STBIR_SIMD_NO_UNROLL(decode); - decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted; - decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted; - decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted; - decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint8_as_float_inverted; - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted; - #if stbir__coder_min_num >= 2 - decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted; - #endif - #if stbir__coder_min_num >= 3 - decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted; - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp; - unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels; - - #ifdef STBIR_SIMD - if ( width_times_channels >= stbir__simdfX_float_count*2 ) - { - float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; - end_output -= stbir__simdfX_float_count*2; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdfX e0, e1; - stbir__simdi i; - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode ); - stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode+stbir__simdfX_float_count ); - stbir__encode_simdfX_unflip( e0 ); - stbir__encode_simdfX_unflip( e1 ); - #ifdef STBIR_SIMD8 - stbir__simdf8_pack_to_16bytes( i, e0, e1 ); - stbir__simdi_store( output, i ); - #else - stbir__simdf_pack_to_8bytes( i, e0, e1 ); - stbir__simdi_store2( output, i ); - #endif - encode += stbir__simdfX_float_count*2; - output += stbir__simdfX_float_count*2; - if ( output <= end_output ) - continue; - if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m8; - } - return; - } - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - stbir__simdf e0; - stbir__simdi i0; - STBIR_NO_UNROLL(encode); - stbir__simdf_load( e0, encode ); - stbir__simdf_madd( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), e0 ); - stbir__encode_simdf4_unflip( e0 ); - stbir__simdf_pack_to_8bytes( i0, e0, e0 ); // only use first 4 - *(int*)(output-4) = stbir__simdi_to_int( i0 ); - output += 4; - encode += 4; - } - output -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - stbir__simdf e0; - STBIR_NO_UNROLL(encode); - stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_uint8( e0 ); - #if stbir__coder_min_num >= 2 - stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_uint8( e0 ); - #endif - #if stbir__coder_min_num >= 3 - stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_uint8( e0 ); - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif - - #else - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - while( output <= end_output ) - { - float f; - f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f; - f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f; - f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f; - f = encode[stbir__encode_order3] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f; - output += 4; - encode += 4; - } - output -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - float f; - STBIR_NO_UNROLL(encode); - f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f; - #if stbir__coder_min_num >= 2 - f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f; - #endif - #if stbir__coder_min_num >= 3 - f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f; - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif - #endif -} - -static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float * decode_end = (float*) decode + width_times_channels; - unsigned char const * input = (unsigned char const*)inputp; - - #ifdef STBIR_SIMD - unsigned char const * end_input_m16 = input + width_times_channels - 16; - if ( width_times_channels >= 16 ) - { - decode_end -= 16; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - #ifdef STBIR_SIMD8 - stbir__simdi i; stbir__simdi8 o0,o1; - stbir__simdf8 of0, of1; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi8_expand_u8_to_u32( o0, o1, i ); - stbir__simdi8_convert_i32_to_float( of0, o0 ); - stbir__simdi8_convert_i32_to_float( of1, o1 ); - stbir__decode_simdf8_flip( of0 ); - stbir__decode_simdf8_flip( of1 ); - stbir__simdf8_store( decode + 0, of0 ); - stbir__simdf8_store( decode + 8, of1 ); - #else - stbir__simdi i, o0, o1, o2, o3; - stbir__simdf of0, of1, of2, of3; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i); - stbir__simdi_convert_i32_to_float( of0, o0 ); - stbir__simdi_convert_i32_to_float( of1, o1 ); - stbir__simdi_convert_i32_to_float( of2, o2 ); - stbir__simdi_convert_i32_to_float( of3, o3 ); - stbir__decode_simdf4_flip( of0 ); - stbir__decode_simdf4_flip( of1 ); - stbir__decode_simdf4_flip( of2 ); - stbir__decode_simdf4_flip( of3 ); - stbir__simdf_store( decode + 0, of0 ); - stbir__simdf_store( decode + 4, of1 ); - stbir__simdf_store( decode + 8, of2 ); - stbir__simdf_store( decode + 12, of3 ); -#endif - decode += 16; - input += 16; - if ( decode <= decode_end ) - continue; - if ( decode == ( decode_end + 16 ) ) - break; - decode = decode_end; // backup and do last couple - input = end_input_m16; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode <= decode_end ) - { - STBIR_SIMD_NO_UNROLL(decode); - decode[0-4] = ((float)(input[stbir__decode_order0])); - decode[1-4] = ((float)(input[stbir__decode_order1])); - decode[2-4] = ((float)(input[stbir__decode_order2])); - decode[3-4] = ((float)(input[stbir__decode_order3])); - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = ((float)(input[stbir__decode_order0])); - #if stbir__coder_min_num >= 2 - decode[1] = ((float)(input[stbir__decode_order1])); - #endif - #if stbir__coder_min_num >= 3 - decode[2] = ((float)(input[stbir__decode_order2])); - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp; - unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels; - - #ifdef STBIR_SIMD - if ( width_times_channels >= stbir__simdfX_float_count*2 ) - { - float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; - end_output -= stbir__simdfX_float_count*2; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdfX e0, e1; - stbir__simdi i; - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode ); - stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count ); - stbir__encode_simdfX_unflip( e0 ); - stbir__encode_simdfX_unflip( e1 ); - #ifdef STBIR_SIMD8 - stbir__simdf8_pack_to_16bytes( i, e0, e1 ); - stbir__simdi_store( output, i ); - #else - stbir__simdf_pack_to_8bytes( i, e0, e1 ); - stbir__simdi_store2( output, i ); - #endif - encode += stbir__simdfX_float_count*2; - output += stbir__simdfX_float_count*2; - if ( output <= end_output ) - continue; - if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m8; - } - return; - } - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - stbir__simdf e0; - stbir__simdi i0; - STBIR_NO_UNROLL(encode); - stbir__simdf_load( e0, encode ); - stbir__simdf_add( e0, STBIR__CONSTF(STBIR_simd_point5), e0 ); - stbir__encode_simdf4_unflip( e0 ); - stbir__simdf_pack_to_8bytes( i0, e0, e0 ); // only use first 4 - *(int*)(output-4) = stbir__simdi_to_int( i0 ); - output += 4; - encode += 4; - } - output -= 4; - #endif - - #else - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - while( output <= end_output ) - { - float f; - f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f; - f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f; - f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f; - f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f; - output += 4; - encode += 4; - } - output -= 4; - #endif - - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - float f; - STBIR_NO_UNROLL(encode); - f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f; - #if stbir__coder_min_num >= 2 - f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f; - #endif - #if stbir__coder_min_num >= 3 - f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f; - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float const * decode_end = (float*) decode + width_times_channels; - unsigned char const * input = (unsigned char const *)inputp; - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - while( decode <= decode_end ) - { - decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ]; - decode[1-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ]; - decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ]; - decode[3-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order3 ] ]; - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ]; - #if stbir__coder_min_num >= 2 - decode[1] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ]; - #endif - #if stbir__coder_min_num >= 3 - decode[2] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ]; - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif -} - -#define stbir__min_max_shift20( i, f ) \ - stbir__simdf_max( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_zero )) ); \ - stbir__simdf_min( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_one )) ); \ - stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 ); - -#define stbir__scale_and_convert( i, f ) \ - stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \ - stbir__simdf_max( f, f, stbir__simdf_zeroP() ); \ - stbir__simdf_min( f, f, STBIR__CONSTF( STBIR_max_uint8_as_float ) ); \ - stbir__simdf_convert_float_to_i32( i, f ); - -#define stbir__linear_to_srgb_finish( i, f ) \ -{ \ - stbir__simdi temp; \ - stbir__simdi_32shr( temp, stbir_simdi_castf( f ), 12 ) ; \ - stbir__simdi_and( temp, temp, STBIR__CONSTI(STBIR_mastissa_mask) ); \ - stbir__simdi_or( temp, temp, STBIR__CONSTI(STBIR_topscale) ); \ - stbir__simdi_16madd( i, i, temp ); \ - stbir__simdi_32shr( i, i, 16 ); \ -} - -#define stbir__simdi_table_lookup2( v0,v1, table ) \ -{ \ - stbir__simdi_u32 temp0,temp1; \ - temp0.m128i_i128 = v0; \ - temp1.m128i_i128 = v1; \ - temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \ - temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \ - v0 = temp0.m128i_i128; \ - v1 = temp1.m128i_i128; \ -} - -#define stbir__simdi_table_lookup3( v0,v1,v2, table ) \ -{ \ - stbir__simdi_u32 temp0,temp1,temp2; \ - temp0.m128i_i128 = v0; \ - temp1.m128i_i128 = v1; \ - temp2.m128i_i128 = v2; \ - temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \ - temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \ - temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \ - v0 = temp0.m128i_i128; \ - v1 = temp1.m128i_i128; \ - v2 = temp2.m128i_i128; \ -} - -#define stbir__simdi_table_lookup4( v0,v1,v2,v3, table ) \ -{ \ - stbir__simdi_u32 temp0,temp1,temp2,temp3; \ - temp0.m128i_i128 = v0; \ - temp1.m128i_i128 = v1; \ - temp2.m128i_i128 = v2; \ - temp3.m128i_i128 = v3; \ - temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \ - temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \ - temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \ - temp3.m128i_u32[0] = table[temp3.m128i_i32[0]]; temp3.m128i_u32[1] = table[temp3.m128i_i32[1]]; temp3.m128i_u32[2] = table[temp3.m128i_i32[2]]; temp3.m128i_u32[3] = table[temp3.m128i_i32[3]]; \ - v0 = temp0.m128i_i128; \ - v1 = temp1.m128i_i128; \ - v2 = temp2.m128i_i128; \ - v3 = temp3.m128i_i128; \ -} - -static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp; - unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; - - #ifdef STBIR_SIMD - - if ( width_times_channels >= 16 ) - { - float const * end_encode_m16 = encode + width_times_channels - 16; - end_output -= 16; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; - STBIR_SIMD_NO_UNROLL(encode); - - stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); - - stbir__min_max_shift20( i0, f0 ); - stbir__min_max_shift20( i1, f1 ); - stbir__min_max_shift20( i2, f2 ); - stbir__min_max_shift20( i3, f3 ); - - stbir__simdi_table_lookup4( i0, i1, i2, i3, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); - - stbir__linear_to_srgb_finish( i0, f0 ); - stbir__linear_to_srgb_finish( i1, f1 ); - stbir__linear_to_srgb_finish( i2, f2 ); - stbir__linear_to_srgb_finish( i3, f3 ); - - stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) ); - - encode += 16; - output += 16; - if ( output <= end_output ) - continue; - if ( output == ( end_output + 16 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m16; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while ( output <= end_output ) - { - STBIR_SIMD_NO_UNROLL(encode); - - output[0-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] ); - output[1-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] ); - output[2-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] ); - output[3-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order3] ); - - output += 4; - encode += 4; - } - output -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - STBIR_NO_UNROLL(encode); - output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] ); - #if stbir__coder_min_num >= 2 - output[1] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] ); - #endif - #if stbir__coder_min_num >= 3 - output[2] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] ); - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif -} - -#if ( stbir__coder_min_num == 4 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) ) - -static void STBIR__CODER_NAME(stbir__decode_uint8_srgb4_linearalpha)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float const * decode_end = (float*) decode + width_times_channels; - unsigned char const * input = (unsigned char const *)inputp; - do { - decode[0] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ]; - decode[1] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order1] ]; - decode[2] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order2] ]; - decode[3] = ( (float) input[stbir__decode_order3] ) * stbir__max_uint8_as_float_inverted; - input += 4; - decode += 4; - } while( decode < decode_end ); -} - - -static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp; - unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; - - #ifdef STBIR_SIMD - - if ( width_times_channels >= 16 ) - { - float const * end_encode_m16 = encode + width_times_channels - 16; - end_output -= 16; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; - - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); - - stbir__min_max_shift20( i0, f0 ); - stbir__min_max_shift20( i1, f1 ); - stbir__min_max_shift20( i2, f2 ); - stbir__scale_and_convert( i3, f3 ); - - stbir__simdi_table_lookup3( i0, i1, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); - - stbir__linear_to_srgb_finish( i0, f0 ); - stbir__linear_to_srgb_finish( i1, f1 ); - stbir__linear_to_srgb_finish( i2, f2 ); - - stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) ); - - output += 16; - encode += 16; - - if ( output <= end_output ) - continue; - if ( output == ( end_output + 16 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m16; - } - return; - } - #endif - - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float f; - STBIR_SIMD_NO_UNROLL(encode); - - output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] ); - output[stbir__decode_order1] = stbir__linear_to_srgb_uchar( encode[1] ); - output[stbir__decode_order2] = stbir__linear_to_srgb_uchar( encode[2] ); - - f = encode[3] * stbir__max_uint8_as_float + 0.5f; - STBIR_CLAMP(f, 0, 255); - output[stbir__decode_order3] = (unsigned char) f; - - output += 4; - encode += 4; - } while( output < end_output ); -} - -#endif - -#if ( stbir__coder_min_num == 2 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) ) - -static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float const * decode_end = (float*) decode + width_times_channels; - unsigned char const * input = (unsigned char const *)inputp; - decode += 4; - while( decode <= decode_end ) - { - decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ]; - decode[1-4] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted; - decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0+2] ]; - decode[3-4] = ( (float) input[stbir__decode_order1+2] ) * stbir__max_uint8_as_float_inverted; - input += 4; - decode += 4; - } - decode -= 4; - if( decode < decode_end ) - { - decode[0] = stbir__srgb_uchar_to_linear_float[ stbir__decode_order0 ]; - decode[1] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted; - } -} - -static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp; - unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; - - #ifdef STBIR_SIMD - - if ( width_times_channels >= 16 ) - { - float const * end_encode_m16 = encode + width_times_channels - 16; - end_output -= 16; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; - - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); - - stbir__min_max_shift20( i0, f0 ); - stbir__scale_and_convert( i1, f1 ); - stbir__min_max_shift20( i2, f2 ); - stbir__scale_and_convert( i3, f3 ); - - stbir__simdi_table_lookup2( i0, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); - - stbir__linear_to_srgb_finish( i0, f0 ); - stbir__linear_to_srgb_finish( i2, f2 ); - - stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) ); - - output += 16; - encode += 16; - if ( output <= end_output ) - continue; - if ( output == ( end_output + 16 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m16; - } - return; - } - #endif - - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float f; - STBIR_SIMD_NO_UNROLL(encode); - - output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] ); - - f = encode[1] * stbir__max_uint8_as_float + 0.5f; - STBIR_CLAMP(f, 0, 255); - output[stbir__decode_order1] = (unsigned char) f; - - output += 2; - encode += 2; - } while( output < end_output ); -} - -#endif - -static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float * decode_end = (float*) decode + width_times_channels; - unsigned short const * input = (unsigned short const *)inputp; - - #ifdef STBIR_SIMD - unsigned short const * end_input_m8 = input + width_times_channels - 8; - if ( width_times_channels >= 8 ) - { - decode_end -= 8; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - #ifdef STBIR_SIMD8 - stbir__simdi i; stbir__simdi8 o; - stbir__simdf8 of; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi8_expand_u16_to_u32( o, i ); - stbir__simdi8_convert_i32_to_float( of, o ); - stbir__simdf8_mult( of, of, STBIR_max_uint16_as_float_inverted8); - stbir__decode_simdf8_flip( of ); - stbir__simdf8_store( decode + 0, of ); - #else - stbir__simdi i, o0, o1; - stbir__simdf of0, of1; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi_expand_u16_to_u32( o0,o1,i ); - stbir__simdi_convert_i32_to_float( of0, o0 ); - stbir__simdi_convert_i32_to_float( of1, o1 ); - stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted) ); - stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted)); - stbir__decode_simdf4_flip( of0 ); - stbir__decode_simdf4_flip( of1 ); - stbir__simdf_store( decode + 0, of0 ); - stbir__simdf_store( decode + 4, of1 ); - #endif - decode += 8; - input += 8; - if ( decode <= decode_end ) - continue; - if ( decode == ( decode_end + 8 ) ) - break; - decode = decode_end; // backup and do last couple - input = end_input_m8; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode <= decode_end ) - { - STBIR_SIMD_NO_UNROLL(decode); - decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted; - decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted; - decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted; - decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint16_as_float_inverted; - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted; - #if stbir__coder_min_num >= 2 - decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted; - #endif - #if stbir__coder_min_num >= 3 - decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted; - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif -} - - -static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp; - unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels; - - #ifdef STBIR_SIMD - { - if ( width_times_channels >= stbir__simdfX_float_count*2 ) - { - float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; - end_output -= stbir__simdfX_float_count*2; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdfX e0, e1; - stbir__simdiX i; - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode ); - stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode+stbir__simdfX_float_count ); - stbir__encode_simdfX_unflip( e0 ); - stbir__encode_simdfX_unflip( e1 ); - stbir__simdfX_pack_to_words( i, e0, e1 ); - stbir__simdiX_store( output, i ); - encode += stbir__simdfX_float_count*2; - output += stbir__simdfX_float_count*2; - if ( output <= end_output ) - continue; - if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m8; - } - return; - } - } - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - stbir__simdf e; - stbir__simdi i; - STBIR_NO_UNROLL(encode); - stbir__simdf_load( e, encode ); - stbir__simdf_madd( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), e ); - stbir__encode_simdf4_unflip( e ); - stbir__simdf_pack_to_8words( i, e, e ); // only use first 4 - stbir__simdi_store2( output-4, i ); - output += 4; - encode += 4; - } - output -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - stbir__simdf e; - STBIR_NO_UNROLL(encode); - stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_short( e ); - #if stbir__coder_min_num >= 2 - stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_short( e ); - #endif - #if stbir__coder_min_num >= 3 - stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_short( e ); - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif - - #else - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - float f; - STBIR_SIMD_NO_UNROLL(encode); - f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f; - f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f; - f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f; - f = encode[stbir__encode_order3] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f; - output += 4; - encode += 4; - } - output -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - float f; - STBIR_NO_UNROLL(encode); - f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f; - #if stbir__coder_min_num >= 2 - f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f; - #endif - #if stbir__coder_min_num >= 3 - f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f; - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif - #endif -} - -static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float * decode_end = (float*) decode + width_times_channels; - unsigned short const * input = (unsigned short const *)inputp; - - #ifdef STBIR_SIMD - unsigned short const * end_input_m8 = input + width_times_channels - 8; - if ( width_times_channels >= 8 ) - { - decode_end -= 8; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - #ifdef STBIR_SIMD8 - stbir__simdi i; stbir__simdi8 o; - stbir__simdf8 of; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi8_expand_u16_to_u32( o, i ); - stbir__simdi8_convert_i32_to_float( of, o ); - stbir__decode_simdf8_flip( of ); - stbir__simdf8_store( decode + 0, of ); - #else - stbir__simdi i, o0, o1; - stbir__simdf of0, of1; - STBIR_NO_UNROLL(decode); - stbir__simdi_load( i, input ); - stbir__simdi_expand_u16_to_u32( o0, o1, i ); - stbir__simdi_convert_i32_to_float( of0, o0 ); - stbir__simdi_convert_i32_to_float( of1, o1 ); - stbir__decode_simdf4_flip( of0 ); - stbir__decode_simdf4_flip( of1 ); - stbir__simdf_store( decode + 0, of0 ); - stbir__simdf_store( decode + 4, of1 ); - #endif - decode += 8; - input += 8; - if ( decode <= decode_end ) - continue; - if ( decode == ( decode_end + 8 ) ) - break; - decode = decode_end; // backup and do last couple - input = end_input_m8; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode <= decode_end ) - { - STBIR_SIMD_NO_UNROLL(decode); - decode[0-4] = ((float)(input[stbir__decode_order0])); - decode[1-4] = ((float)(input[stbir__decode_order1])); - decode[2-4] = ((float)(input[stbir__decode_order2])); - decode[3-4] = ((float)(input[stbir__decode_order3])); - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = ((float)(input[stbir__decode_order0])); - #if stbir__coder_min_num >= 2 - decode[1] = ((float)(input[stbir__decode_order1])); - #endif - #if stbir__coder_min_num >= 3 - decode[2] = ((float)(input[stbir__decode_order2])); - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int width_times_channels, float const * encode ) -{ - unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp; - unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels; - - #ifdef STBIR_SIMD - { - if ( width_times_channels >= stbir__simdfX_float_count*2 ) - { - float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; - end_output -= stbir__simdfX_float_count*2; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdfX e0, e1; - stbir__simdiX i; - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode ); - stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count ); - stbir__encode_simdfX_unflip( e0 ); - stbir__encode_simdfX_unflip( e1 ); - stbir__simdfX_pack_to_words( i, e0, e1 ); - stbir__simdiX_store( output, i ); - encode += stbir__simdfX_float_count*2; - output += stbir__simdfX_float_count*2; - if ( output <= end_output ) - continue; - if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m8; - } - return; - } - } - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - stbir__simdf e; - stbir__simdi i; - STBIR_NO_UNROLL(encode); - stbir__simdf_load( e, encode ); - stbir__simdf_add( e, STBIR__CONSTF(STBIR_simd_point5), e ); - stbir__encode_simdf4_unflip( e ); - stbir__simdf_pack_to_8words( i, e, e ); // only use first 4 - stbir__simdi_store2( output-4, i ); - output += 4; - encode += 4; - } - output -= 4; - #endif - - #else - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - float f; - STBIR_SIMD_NO_UNROLL(encode); - f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f; - f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f; - f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f; - f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f; - output += 4; - encode += 4; - } - output -= 4; - #endif - - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - float f; - STBIR_NO_UNROLL(encode); - f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f; - #if stbir__coder_min_num >= 2 - f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f; - #endif - #if stbir__coder_min_num >= 3 - f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f; - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, int width_times_channels, void const * inputp ) -{ - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float * decode_end = (float*) decode + width_times_channels; - stbir__FP16 const * input = (stbir__FP16 const *)inputp; - - #ifdef STBIR_SIMD - if ( width_times_channels >= 8 ) - { - stbir__FP16 const * end_input_m8 = input + width_times_channels - 8; - decode_end -= 8; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - STBIR_NO_UNROLL(decode); - - stbir__half_to_float_SIMD( decode, input ); - #ifdef stbir__decode_swizzle - #ifdef STBIR_SIMD8 - { - stbir__simdf8 of; - stbir__simdf8_load( of, decode ); - stbir__decode_simdf8_flip( of ); - stbir__simdf8_store( decode, of ); - } - #else - { - stbir__simdf of0,of1; - stbir__simdf_load( of0, decode ); - stbir__simdf_load( of1, decode+4 ); - stbir__decode_simdf4_flip( of0 ); - stbir__decode_simdf4_flip( of1 ); - stbir__simdf_store( decode, of0 ); - stbir__simdf_store( decode+4, of1 ); - } - #endif - #endif - decode += 8; - input += 8; - if ( decode <= decode_end ) - continue; - if ( decode == ( decode_end + 8 ) ) - break; - decode = decode_end; // backup and do last couple - input = end_input_m8; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode <= decode_end ) - { - STBIR_SIMD_NO_UNROLL(decode); - decode[0-4] = stbir__half_to_float(input[stbir__decode_order0]); - decode[1-4] = stbir__half_to_float(input[stbir__decode_order1]); - decode[2-4] = stbir__half_to_float(input[stbir__decode_order2]); - decode[3-4] = stbir__half_to_float(input[stbir__decode_order3]); - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = stbir__half_to_float(input[stbir__decode_order0]); - #if stbir__coder_min_num >= 2 - decode[1] = stbir__half_to_float(input[stbir__decode_order1]); - #endif - #if stbir__coder_min_num >= 3 - decode[2] = stbir__half_to_float(input[stbir__decode_order2]); - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp, int width_times_channels, float const * encode ) -{ - stbir__FP16 STBIR_SIMD_STREAMOUT_PTR( * ) output = (stbir__FP16*) outputp; - stbir__FP16 * end_output = ( (stbir__FP16*) output ) + width_times_channels; - - #ifdef STBIR_SIMD - if ( width_times_channels >= 8 ) - { - float const * end_encode_m8 = encode + width_times_channels - 8; - end_output -= 8; - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - STBIR_SIMD_NO_UNROLL(encode); - #ifdef stbir__decode_swizzle - #ifdef STBIR_SIMD8 - { - stbir__simdf8 of; - stbir__simdf8_load( of, encode ); - stbir__encode_simdf8_unflip( of ); - stbir__float_to_half_SIMD( output, (float*)&of ); - } - #else - { - stbir__simdf of[2]; - stbir__simdf_load( of[0], encode ); - stbir__simdf_load( of[1], encode+4 ); - stbir__encode_simdf4_unflip( of[0] ); - stbir__encode_simdf4_unflip( of[1] ); - stbir__float_to_half_SIMD( output, (float*)of ); - } - #endif - #else - stbir__float_to_half_SIMD( output, encode ); - #endif - encode += 8; - output += 8; - if ( output <= end_output ) - continue; - if ( output == ( end_output + 8 ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m8; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - STBIR_SIMD_NO_UNROLL(output); - output[0-4] = stbir__float_to_half(encode[stbir__encode_order0]); - output[1-4] = stbir__float_to_half(encode[stbir__encode_order1]); - output[2-4] = stbir__float_to_half(encode[stbir__encode_order2]); - output[3-4] = stbir__float_to_half(encode[stbir__encode_order3]); - output += 4; - encode += 4; - } - output -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - STBIR_NO_UNROLL(output); - output[0] = stbir__float_to_half(encode[stbir__encode_order0]); - #if stbir__coder_min_num >= 2 - output[1] = stbir__float_to_half(encode[stbir__encode_order1]); - #endif - #if stbir__coder_min_num >= 3 - output[2] = stbir__float_to_half(encode[stbir__encode_order2]); - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif -} - -static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int width_times_channels, void const * inputp ) -{ - #ifdef stbir__decode_swizzle - float STBIR_STREAMOUT_PTR( * ) decode = decodep; - float * decode_end = (float*) decode + width_times_channels; - float const * input = (float const *)inputp; - - #ifdef STBIR_SIMD - if ( width_times_channels >= 16 ) - { - float const * end_input_m16 = input + width_times_channels - 16; - decode_end -= 16; - STBIR_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - STBIR_NO_UNROLL(decode); - #ifdef stbir__decode_swizzle - #ifdef STBIR_SIMD8 - { - stbir__simdf8 of0,of1; - stbir__simdf8_load( of0, input ); - stbir__simdf8_load( of1, input+8 ); - stbir__decode_simdf8_flip( of0 ); - stbir__decode_simdf8_flip( of1 ); - stbir__simdf8_store( decode, of0 ); - stbir__simdf8_store( decode+8, of1 ); - } - #else - { - stbir__simdf of0,of1,of2,of3; - stbir__simdf_load( of0, input ); - stbir__simdf_load( of1, input+4 ); - stbir__simdf_load( of2, input+8 ); - stbir__simdf_load( of3, input+12 ); - stbir__decode_simdf4_flip( of0 ); - stbir__decode_simdf4_flip( of1 ); - stbir__decode_simdf4_flip( of2 ); - stbir__decode_simdf4_flip( of3 ); - stbir__simdf_store( decode, of0 ); - stbir__simdf_store( decode+4, of1 ); - stbir__simdf_store( decode+8, of2 ); - stbir__simdf_store( decode+12, of3 ); - } - #endif - #endif - decode += 16; - input += 16; - if ( decode <= decode_end ) - continue; - if ( decode == ( decode_end + 16 ) ) - break; - decode = decode_end; // backup and do last couple - input = end_input_m16; - } - return; - } - #endif - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - decode += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( decode <= decode_end ) - { - STBIR_SIMD_NO_UNROLL(decode); - decode[0-4] = input[stbir__decode_order0]; - decode[1-4] = input[stbir__decode_order1]; - decode[2-4] = input[stbir__decode_order2]; - decode[3-4] = input[stbir__decode_order3]; - decode += 4; - input += 4; - } - decode -= 4; - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( decode < decode_end ) - { - STBIR_NO_UNROLL(decode); - decode[0] = input[stbir__decode_order0]; - #if stbir__coder_min_num >= 2 - decode[1] = input[stbir__decode_order1]; - #endif - #if stbir__coder_min_num >= 3 - decode[2] = input[stbir__decode_order2]; - #endif - decode += stbir__coder_min_num; - input += stbir__coder_min_num; - } - #endif - - #else - - if ( (void*)decodep != inputp ) - STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) ); - - #endif -} - -static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int width_times_channels, float const * encode ) -{ - #if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LO_CLAMP) && !defined(stbir__decode_swizzle) - - if ( (void*)outputp != (void*) encode ) - STBIR_MEMCPY( outputp, encode, width_times_channels * sizeof( float ) ); - - #else - - float STBIR_SIMD_STREAMOUT_PTR( * ) output = (float*) outputp; - float * end_output = ( (float*) output ) + width_times_channels; - - #ifdef STBIR_FLOAT_HIGH_CLAMP - #define stbir_scalar_hi_clamp( v ) if ( v > STBIR_FLOAT_HIGH_CLAMP ) v = STBIR_FLOAT_HIGH_CLAMP; - #else - #define stbir_scalar_hi_clamp( v ) - #endif - #ifdef STBIR_FLOAT_LOW_CLAMP - #define stbir_scalar_lo_clamp( v ) if ( v < STBIR_FLOAT_LOW_CLAMP ) v = STBIR_FLOAT_LOW_CLAMP; - #else - #define stbir_scalar_lo_clamp( v ) - #endif - - #ifdef STBIR_SIMD - - #ifdef STBIR_FLOAT_HIGH_CLAMP - const stbir__simdfX high_clamp = stbir__simdf_frepX(STBIR_FLOAT_HIGH_CLAMP); - #endif - #ifdef STBIR_FLOAT_LOW_CLAMP - const stbir__simdfX low_clamp = stbir__simdf_frepX(STBIR_FLOAT_LOW_CLAMP); - #endif - - if ( width_times_channels >= ( stbir__simdfX_float_count * 2 ) ) - { - float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 ); - end_output -= ( stbir__simdfX_float_count * 2 ); - STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR - for(;;) - { - stbir__simdfX e0, e1; - STBIR_SIMD_NO_UNROLL(encode); - stbir__simdfX_load( e0, encode ); - stbir__simdfX_load( e1, encode+stbir__simdfX_float_count ); -#ifdef STBIR_FLOAT_HIGH_CLAMP - stbir__simdfX_min( e0, e0, high_clamp ); - stbir__simdfX_min( e1, e1, high_clamp ); -#endif -#ifdef STBIR_FLOAT_LOW_CLAMP - stbir__simdfX_max( e0, e0, low_clamp ); - stbir__simdfX_max( e1, e1, low_clamp ); -#endif - stbir__encode_simdfX_unflip( e0 ); - stbir__encode_simdfX_unflip( e1 ); - stbir__simdfX_store( output, e0 ); - stbir__simdfX_store( output+stbir__simdfX_float_count, e1 ); - encode += stbir__simdfX_float_count * 2; - output += stbir__simdfX_float_count * 2; - if ( output < end_output ) - continue; - if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) ) - break; - output = end_output; // backup and do last couple - encode = end_encode_m8; - } - return; - } - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - stbir__simdf e0; - STBIR_NO_UNROLL(encode); - stbir__simdf_load( e0, encode ); -#ifdef STBIR_FLOAT_HIGH_CLAMP - stbir__simdf_min( e0, e0, high_clamp ); -#endif -#ifdef STBIR_FLOAT_LOW_CLAMP - stbir__simdf_max( e0, e0, low_clamp ); -#endif - stbir__encode_simdf4_unflip( e0 ); - stbir__simdf_store( output-4, e0 ); - output += 4; - encode += 4; - } - output -= 4; - #endif - - #else - - // try to do blocks of 4 when you can - #if stbir__coder_min_num != 3 // doesn't divide cleanly by four - output += 4; - STBIR_SIMD_NO_UNROLL_LOOP_START - while( output <= end_output ) - { - float e; - STBIR_SIMD_NO_UNROLL(encode); - e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0-4] = e; - e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1-4] = e; - e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2-4] = e; - e = encode[ stbir__encode_order3 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[3-4] = e; - output += 4; - encode += 4; - } - output -= 4; - - #endif - - #endif - - // do the remnants - #if stbir__coder_min_num < 4 - STBIR_NO_UNROLL_LOOP_START - while( output < end_output ) - { - float e; - STBIR_NO_UNROLL(encode); - e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0] = e; - #if stbir__coder_min_num >= 2 - e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1] = e; - #endif - #if stbir__coder_min_num >= 3 - e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2] = e; - #endif - output += stbir__coder_min_num; - encode += stbir__coder_min_num; - } - #endif - - #endif -} - -#undef stbir__decode_suffix -#undef stbir__decode_simdf8_flip -#undef stbir__decode_simdf4_flip -#undef stbir__decode_order0 -#undef stbir__decode_order1 -#undef stbir__decode_order2 -#undef stbir__decode_order3 -#undef stbir__encode_order0 -#undef stbir__encode_order1 -#undef stbir__encode_order2 -#undef stbir__encode_order3 -#undef stbir__encode_simdf8_unflip -#undef stbir__encode_simdf4_unflip -#undef stbir__encode_simdfX_unflip -#undef STBIR__CODER_NAME -#undef stbir__coder_min_num -#undef stbir__decode_swizzle -#undef stbir_scalar_hi_clamp -#undef stbir_scalar_lo_clamp -#undef STB_IMAGE_RESIZE_DO_CODERS - -#elif defined( STB_IMAGE_RESIZE_DO_VERTICALS) - -#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#define STBIR_chans( start, end ) STBIR_strs_join14(start,STBIR__vertical_channels,end,_cont) -#else -#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__vertical_channels,end) -#endif - -#if STBIR__vertical_channels >= 1 -#define stbIF0( code ) code -#else -#define stbIF0( code ) -#endif -#if STBIR__vertical_channels >= 2 -#define stbIF1( code ) code -#else -#define stbIF1( code ) -#endif -#if STBIR__vertical_channels >= 3 -#define stbIF2( code ) code -#else -#define stbIF2( code ) -#endif -#if STBIR__vertical_channels >= 4 -#define stbIF3( code ) code -#else -#define stbIF3( code ) -#endif -#if STBIR__vertical_channels >= 5 -#define stbIF4( code ) code -#else -#define stbIF4( code ) -#endif -#if STBIR__vertical_channels >= 6 -#define stbIF5( code ) code -#else -#define stbIF5( code ) -#endif -#if STBIR__vertical_channels >= 7 -#define stbIF6( code ) code -#else -#define stbIF6( code ) -#endif -#if STBIR__vertical_channels >= 8 -#define stbIF7( code ) code -#else -#define stbIF7( code ) -#endif - -static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** outputs, float const * vertical_coefficients, float const * input, float const * input_end ) -{ - stbIF0( float STBIR_SIMD_STREAMOUT_PTR( * ) output0 = outputs[0]; float c0s = vertical_coefficients[0]; ) - stbIF1( float STBIR_SIMD_STREAMOUT_PTR( * ) output1 = outputs[1]; float c1s = vertical_coefficients[1]; ) - stbIF2( float STBIR_SIMD_STREAMOUT_PTR( * ) output2 = outputs[2]; float c2s = vertical_coefficients[2]; ) - stbIF3( float STBIR_SIMD_STREAMOUT_PTR( * ) output3 = outputs[3]; float c3s = vertical_coefficients[3]; ) - stbIF4( float STBIR_SIMD_STREAMOUT_PTR( * ) output4 = outputs[4]; float c4s = vertical_coefficients[4]; ) - stbIF5( float STBIR_SIMD_STREAMOUT_PTR( * ) output5 = outputs[5]; float c5s = vertical_coefficients[5]; ) - stbIF6( float STBIR_SIMD_STREAMOUT_PTR( * ) output6 = outputs[6]; float c6s = vertical_coefficients[6]; ) - stbIF7( float STBIR_SIMD_STREAMOUT_PTR( * ) output7 = outputs[7]; float c7s = vertical_coefficients[7]; ) - - #ifdef STBIR_SIMD - { - stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); ) - stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); ) - stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); ) - stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); ) - stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); ) - stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); ) - stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); ) - stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); ) - STBIR_SIMD_NO_UNROLL_LOOP_START - while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) ) - { - stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3; - STBIR_SIMD_NO_UNROLL(output0); - - stbir__simdfX_load( r0, input ); stbir__simdfX_load( r1, input+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input+(3*stbir__simdfX_float_count) ); - - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( stbir__simdfX_load( o0, output0 ); stbir__simdfX_load( o1, output0+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output0+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 ); - stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); ) - stbIF1( stbir__simdfX_load( o0, output1 ); stbir__simdfX_load( o1, output1+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output1+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 ); - stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); ) - stbIF2( stbir__simdfX_load( o0, output2 ); stbir__simdfX_load( o1, output2+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output2+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 ); - stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); ) - stbIF3( stbir__simdfX_load( o0, output3 ); stbir__simdfX_load( o1, output3+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output3+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 ); - stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); ) - stbIF4( stbir__simdfX_load( o0, output4 ); stbir__simdfX_load( o1, output4+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output4+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 ); - stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); ) - stbIF5( stbir__simdfX_load( o0, output5 ); stbir__simdfX_load( o1, output5+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output5+(2*stbir__simdfX_float_count)); stbir__simdfX_load( o3, output5+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 ); - stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); ) - stbIF6( stbir__simdfX_load( o0, output6 ); stbir__simdfX_load( o1, output6+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output6+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 ); - stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); ) - stbIF7( stbir__simdfX_load( o0, output7 ); stbir__simdfX_load( o1, output7+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output7+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 ); - stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); ) - #else - stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); - stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); ) - stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 ); - stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); ) - stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 ); - stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); ) - stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 ); - stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); ) - stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 ); - stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); ) - stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 ); - stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); ) - stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 ); - stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); ) - stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 ); - stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); ) - #endif - - input += (4*stbir__simdfX_float_count); - stbIF0( output0 += (4*stbir__simdfX_float_count); ) stbIF1( output1 += (4*stbir__simdfX_float_count); ) stbIF2( output2 += (4*stbir__simdfX_float_count); ) stbIF3( output3 += (4*stbir__simdfX_float_count); ) stbIF4( output4 += (4*stbir__simdfX_float_count); ) stbIF5( output5 += (4*stbir__simdfX_float_count); ) stbIF6( output6 += (4*stbir__simdfX_float_count); ) stbIF7( output7 += (4*stbir__simdfX_float_count); ) - } - STBIR_SIMD_NO_UNROLL_LOOP_START - while ( ( (char*)input_end - (char*) input ) >= 16 ) - { - stbir__simdf o0, r0; - STBIR_SIMD_NO_UNROLL(output0); - - stbir__simdf_load( r0, input ); - - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( stbir__simdf_load( o0, output0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); stbir__simdf_store( output0, o0 ); ) - stbIF1( stbir__simdf_load( o0, output1 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); stbir__simdf_store( output1, o0 ); ) - stbIF2( stbir__simdf_load( o0, output2 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); stbir__simdf_store( output2, o0 ); ) - stbIF3( stbir__simdf_load( o0, output3 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); stbir__simdf_store( output3, o0 ); ) - stbIF4( stbir__simdf_load( o0, output4 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); stbir__simdf_store( output4, o0 ); ) - stbIF5( stbir__simdf_load( o0, output5 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); stbir__simdf_store( output5, o0 ); ) - stbIF6( stbir__simdf_load( o0, output6 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); ) - stbIF7( stbir__simdf_load( o0, output7 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); ) - #else - stbIF0( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); stbir__simdf_store( output0, o0 ); ) - stbIF1( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); stbir__simdf_store( output1, o0 ); ) - stbIF2( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); stbir__simdf_store( output2, o0 ); ) - stbIF3( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); stbir__simdf_store( output3, o0 ); ) - stbIF4( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); stbir__simdf_store( output4, o0 ); ) - stbIF5( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); stbir__simdf_store( output5, o0 ); ) - stbIF6( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); ) - stbIF7( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); ) - #endif - - input += 4; - stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; ) - } - } - #else - STBIR_NO_UNROLL_LOOP_START - while ( ( (char*)input_end - (char*) input ) >= 16 ) - { - float r0, r1, r2, r3; - STBIR_NO_UNROLL(input); - - r0 = input[0], r1 = input[1], r2 = input[2], r3 = input[3]; - - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( output0[0] += ( r0 * c0s ); output0[1] += ( r1 * c0s ); output0[2] += ( r2 * c0s ); output0[3] += ( r3 * c0s ); ) - stbIF1( output1[0] += ( r0 * c1s ); output1[1] += ( r1 * c1s ); output1[2] += ( r2 * c1s ); output1[3] += ( r3 * c1s ); ) - stbIF2( output2[0] += ( r0 * c2s ); output2[1] += ( r1 * c2s ); output2[2] += ( r2 * c2s ); output2[3] += ( r3 * c2s ); ) - stbIF3( output3[0] += ( r0 * c3s ); output3[1] += ( r1 * c3s ); output3[2] += ( r2 * c3s ); output3[3] += ( r3 * c3s ); ) - stbIF4( output4[0] += ( r0 * c4s ); output4[1] += ( r1 * c4s ); output4[2] += ( r2 * c4s ); output4[3] += ( r3 * c4s ); ) - stbIF5( output5[0] += ( r0 * c5s ); output5[1] += ( r1 * c5s ); output5[2] += ( r2 * c5s ); output5[3] += ( r3 * c5s ); ) - stbIF6( output6[0] += ( r0 * c6s ); output6[1] += ( r1 * c6s ); output6[2] += ( r2 * c6s ); output6[3] += ( r3 * c6s ); ) - stbIF7( output7[0] += ( r0 * c7s ); output7[1] += ( r1 * c7s ); output7[2] += ( r2 * c7s ); output7[3] += ( r3 * c7s ); ) - #else - stbIF0( output0[0] = ( r0 * c0s ); output0[1] = ( r1 * c0s ); output0[2] = ( r2 * c0s ); output0[3] = ( r3 * c0s ); ) - stbIF1( output1[0] = ( r0 * c1s ); output1[1] = ( r1 * c1s ); output1[2] = ( r2 * c1s ); output1[3] = ( r3 * c1s ); ) - stbIF2( output2[0] = ( r0 * c2s ); output2[1] = ( r1 * c2s ); output2[2] = ( r2 * c2s ); output2[3] = ( r3 * c2s ); ) - stbIF3( output3[0] = ( r0 * c3s ); output3[1] = ( r1 * c3s ); output3[2] = ( r2 * c3s ); output3[3] = ( r3 * c3s ); ) - stbIF4( output4[0] = ( r0 * c4s ); output4[1] = ( r1 * c4s ); output4[2] = ( r2 * c4s ); output4[3] = ( r3 * c4s ); ) - stbIF5( output5[0] = ( r0 * c5s ); output5[1] = ( r1 * c5s ); output5[2] = ( r2 * c5s ); output5[3] = ( r3 * c5s ); ) - stbIF6( output6[0] = ( r0 * c6s ); output6[1] = ( r1 * c6s ); output6[2] = ( r2 * c6s ); output6[3] = ( r3 * c6s ); ) - stbIF7( output7[0] = ( r0 * c7s ); output7[1] = ( r1 * c7s ); output7[2] = ( r2 * c7s ); output7[3] = ( r3 * c7s ); ) - #endif - - input += 4; - stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; ) - } - #endif - STBIR_NO_UNROLL_LOOP_START - while ( input < input_end ) - { - float r = input[0]; - STBIR_NO_UNROLL(output0); - - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( output0[0] += ( r * c0s ); ) - stbIF1( output1[0] += ( r * c1s ); ) - stbIF2( output2[0] += ( r * c2s ); ) - stbIF3( output3[0] += ( r * c3s ); ) - stbIF4( output4[0] += ( r * c4s ); ) - stbIF5( output5[0] += ( r * c5s ); ) - stbIF6( output6[0] += ( r * c6s ); ) - stbIF7( output7[0] += ( r * c7s ); ) - #else - stbIF0( output0[0] = ( r * c0s ); ) - stbIF1( output1[0] = ( r * c1s ); ) - stbIF2( output2[0] = ( r * c2s ); ) - stbIF3( output3[0] = ( r * c3s ); ) - stbIF4( output4[0] = ( r * c4s ); ) - stbIF5( output5[0] = ( r * c5s ); ) - stbIF6( output6[0] = ( r * c6s ); ) - stbIF7( output7[0] = ( r * c7s ); ) - #endif - - ++input; - stbIF0( ++output0; ) stbIF1( ++output1; ) stbIF2( ++output2; ) stbIF3( ++output3; ) stbIF4( ++output4; ) stbIF5( ++output5; ) stbIF6( ++output6; ) stbIF7( ++output7; ) - } -} - -static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, float const * vertical_coefficients, float const ** inputs, float const * input0_end ) -{ - float STBIR_SIMD_STREAMOUT_PTR( * ) output = outputp; - - stbIF0( float const * input0 = inputs[0]; float c0s = vertical_coefficients[0]; ) - stbIF1( float const * input1 = inputs[1]; float c1s = vertical_coefficients[1]; ) - stbIF2( float const * input2 = inputs[2]; float c2s = vertical_coefficients[2]; ) - stbIF3( float const * input3 = inputs[3]; float c3s = vertical_coefficients[3]; ) - stbIF4( float const * input4 = inputs[4]; float c4s = vertical_coefficients[4]; ) - stbIF5( float const * input5 = inputs[5]; float c5s = vertical_coefficients[5]; ) - stbIF6( float const * input6 = inputs[6]; float c6s = vertical_coefficients[6]; ) - stbIF7( float const * input7 = inputs[7]; float c7s = vertical_coefficients[7]; ) - -#if ( STBIR__vertical_channels == 1 ) && !defined(STB_IMAGE_RESIZE_VERTICAL_CONTINUE) - // check single channel one weight - if ( ( c0s >= (1.0f-0.000001f) ) && ( c0s <= (1.0f+0.000001f) ) ) - { - STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 ); - return; - } -#endif - - #ifdef STBIR_SIMD - { - stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); ) - stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); ) - stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); ) - stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); ) - stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); ) - stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); ) - stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); ) - stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); ) - - STBIR_SIMD_NO_UNROLL_LOOP_START - while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) ) - { - stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3; - STBIR_SIMD_NO_UNROLL(output); - - // prefetch four loop iterations ahead (doesn't affect much for small resizes, but helps with big ones) - stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); ) - stbIF1( stbir__prefetch( input1 + (16*stbir__simdfX_float_count) ); ) - stbIF2( stbir__prefetch( input2 + (16*stbir__simdfX_float_count) ); ) - stbIF3( stbir__prefetch( input3 + (16*stbir__simdfX_float_count) ); ) - stbIF4( stbir__prefetch( input4 + (16*stbir__simdfX_float_count) ); ) - stbIF5( stbir__prefetch( input5 + (16*stbir__simdfX_float_count) ); ) - stbIF6( stbir__prefetch( input6 + (16*stbir__simdfX_float_count) ); ) - stbIF7( stbir__prefetch( input7 + (16*stbir__simdfX_float_count) ); ) - - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( stbir__simdfX_load( o0, output ); stbir__simdfX_load( o1, output+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output+(3*stbir__simdfX_float_count) ); - stbir__simdfX_load( r0, input0 ); stbir__simdfX_load( r1, input0+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input0+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 ); ) - #else - stbIF0( stbir__simdfX_load( r0, input0 ); stbir__simdfX_load( r1, input0+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input0+(3*stbir__simdfX_float_count) ); - stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); ) - #endif - - stbIF1( stbir__simdfX_load( r0, input1 ); stbir__simdfX_load( r1, input1+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input1+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 ); ) - stbIF2( stbir__simdfX_load( r0, input2 ); stbir__simdfX_load( r1, input2+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input2+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 ); ) - stbIF3( stbir__simdfX_load( r0, input3 ); stbir__simdfX_load( r1, input3+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input3+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 ); ) - stbIF4( stbir__simdfX_load( r0, input4 ); stbir__simdfX_load( r1, input4+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input4+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 ); ) - stbIF5( stbir__simdfX_load( r0, input5 ); stbir__simdfX_load( r1, input5+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input5+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input5+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 ); ) - stbIF6( stbir__simdfX_load( r0, input6 ); stbir__simdfX_load( r1, input6+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input6+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 ); ) - stbIF7( stbir__simdfX_load( r0, input7 ); stbir__simdfX_load( r1, input7+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input7+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 ); ) - - stbir__simdfX_store( output, o0 ); stbir__simdfX_store( output+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output+(3*stbir__simdfX_float_count), o3 ); - output += (4*stbir__simdfX_float_count); - stbIF0( input0 += (4*stbir__simdfX_float_count); ) stbIF1( input1 += (4*stbir__simdfX_float_count); ) stbIF2( input2 += (4*stbir__simdfX_float_count); ) stbIF3( input3 += (4*stbir__simdfX_float_count); ) stbIF4( input4 += (4*stbir__simdfX_float_count); ) stbIF5( input5 += (4*stbir__simdfX_float_count); ) stbIF6( input6 += (4*stbir__simdfX_float_count); ) stbIF7( input7 += (4*stbir__simdfX_float_count); ) - } - - STBIR_SIMD_NO_UNROLL_LOOP_START - while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) - { - stbir__simdf o0, r0; - STBIR_SIMD_NO_UNROLL(output); - - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( stbir__simdf_load( o0, output ); stbir__simdf_load( r0, input0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); ) - #else - stbIF0( stbir__simdf_load( r0, input0 ); stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); ) - #endif - stbIF1( stbir__simdf_load( r0, input1 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); ) - stbIF2( stbir__simdf_load( r0, input2 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); ) - stbIF3( stbir__simdf_load( r0, input3 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); ) - stbIF4( stbir__simdf_load( r0, input4 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); ) - stbIF5( stbir__simdf_load( r0, input5 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); ) - stbIF6( stbir__simdf_load( r0, input6 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); ) - stbIF7( stbir__simdf_load( r0, input7 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); ) - - stbir__simdf_store( output, o0 ); - output += 4; - stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; ) - } - } - #else - STBIR_NO_UNROLL_LOOP_START - while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) - { - float o0, o1, o2, o3; - STBIR_NO_UNROLL(output); - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( o0 = output[0] + input0[0] * c0s; o1 = output[1] + input0[1] * c0s; o2 = output[2] + input0[2] * c0s; o3 = output[3] + input0[3] * c0s; ) - #else - stbIF0( o0 = input0[0] * c0s; o1 = input0[1] * c0s; o2 = input0[2] * c0s; o3 = input0[3] * c0s; ) - #endif - stbIF1( o0 += input1[0] * c1s; o1 += input1[1] * c1s; o2 += input1[2] * c1s; o3 += input1[3] * c1s; ) - stbIF2( o0 += input2[0] * c2s; o1 += input2[1] * c2s; o2 += input2[2] * c2s; o3 += input2[3] * c2s; ) - stbIF3( o0 += input3[0] * c3s; o1 += input3[1] * c3s; o2 += input3[2] * c3s; o3 += input3[3] * c3s; ) - stbIF4( o0 += input4[0] * c4s; o1 += input4[1] * c4s; o2 += input4[2] * c4s; o3 += input4[3] * c4s; ) - stbIF5( o0 += input5[0] * c5s; o1 += input5[1] * c5s; o2 += input5[2] * c5s; o3 += input5[3] * c5s; ) - stbIF6( o0 += input6[0] * c6s; o1 += input6[1] * c6s; o2 += input6[2] * c6s; o3 += input6[3] * c6s; ) - stbIF7( o0 += input7[0] * c7s; o1 += input7[1] * c7s; o2 += input7[2] * c7s; o3 += input7[3] * c7s; ) - output[0] = o0; output[1] = o1; output[2] = o2; output[3] = o3; - output += 4; - stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; ) - } - #endif - STBIR_NO_UNROLL_LOOP_START - while ( input0 < input0_end ) - { - float o0; - STBIR_NO_UNROLL(output); - #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE - stbIF0( o0 = output[0] + input0[0] * c0s; ) - #else - stbIF0( o0 = input0[0] * c0s; ) - #endif - stbIF1( o0 += input1[0] * c1s; ) - stbIF2( o0 += input2[0] * c2s; ) - stbIF3( o0 += input3[0] * c3s; ) - stbIF4( o0 += input4[0] * c4s; ) - stbIF5( o0 += input5[0] * c5s; ) - stbIF6( o0 += input6[0] * c6s; ) - stbIF7( o0 += input7[0] * c7s; ) - output[0] = o0; - ++output; - stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; ) - } -} - -#undef stbIF0 -#undef stbIF1 -#undef stbIF2 -#undef stbIF3 -#undef stbIF4 -#undef stbIF5 -#undef stbIF6 -#undef stbIF7 -#undef STB_IMAGE_RESIZE_DO_VERTICALS -#undef STBIR__vertical_channels -#undef STB_IMAGE_RESIZE_DO_HORIZONTALS -#undef STBIR_strs_join24 -#undef STBIR_strs_join14 -#undef STBIR_chans -#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#undef STB_IMAGE_RESIZE_VERTICAL_CONTINUE -#endif - -#else // !STB_IMAGE_RESIZE_DO_VERTICALS - -#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__horizontal_channels,end) - -#ifndef stbir__2_coeff_only -#define stbir__2_coeff_only() \ - stbir__1_coeff_only(); \ - stbir__1_coeff_remnant(1); -#endif - -#ifndef stbir__2_coeff_remnant -#define stbir__2_coeff_remnant( ofs ) \ - stbir__1_coeff_remnant(ofs); \ - stbir__1_coeff_remnant((ofs)+1); -#endif - -#ifndef stbir__3_coeff_only -#define stbir__3_coeff_only() \ - stbir__2_coeff_only(); \ - stbir__1_coeff_remnant(2); -#endif - -#ifndef stbir__3_coeff_remnant -#define stbir__3_coeff_remnant( ofs ) \ - stbir__2_coeff_remnant(ofs); \ - stbir__1_coeff_remnant((ofs)+2); -#endif - -#ifndef stbir__3_coeff_setup -#define stbir__3_coeff_setup() -#endif - -#ifndef stbir__4_coeff_start -#define stbir__4_coeff_start() \ - stbir__2_coeff_only(); \ - stbir__2_coeff_remnant(2); -#endif - -#ifndef stbir__4_coeff_continue_from_4 -#define stbir__4_coeff_continue_from_4( ofs ) \ - stbir__2_coeff_remnant(ofs); \ - stbir__2_coeff_remnant((ofs)+2); -#endif - -#ifndef stbir__store_output_tiny -#define stbir__store_output_tiny stbir__store_output -#endif - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__1_coeff_only(); - stbir__store_output_tiny(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__2_coeff_only(); - stbir__store_output_tiny(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__3_coeff_only(); - stbir__store_output_tiny(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__1_coeff_remnant(4); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__2_coeff_remnant(4); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - stbir__3_coeff_setup(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - - stbir__4_coeff_start(); - stbir__3_coeff_remnant(4); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__4_coeff_continue_from_4(4); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__4_coeff_continue_from_4(4); - stbir__1_coeff_remnant(8); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__4_coeff_continue_from_4(4); - stbir__2_coeff_remnant(8); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - stbir__3_coeff_setup(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__4_coeff_continue_from_4(4); - stbir__3_coeff_remnant(8); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients; - stbir__4_coeff_start(); - stbir__4_coeff_continue_from_4(4); - stbir__4_coeff_continue_from_4(8); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2; - float const * hc = horizontal_coefficients; - - stbir__4_coeff_start(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - hc += 4; - decode += STBIR__horizontal_channels * 4; - stbir__4_coeff_continue_from_4( 0 ); - --n; - } while ( n > 0 ); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2; - float const * hc = horizontal_coefficients; - - stbir__4_coeff_start(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - hc += 4; - decode += STBIR__horizontal_channels * 4; - stbir__4_coeff_continue_from_4( 0 ); - --n; - } while ( n > 0 ); - stbir__1_coeff_remnant( 4 ); - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2; - float const * hc = horizontal_coefficients; - - stbir__4_coeff_start(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - hc += 4; - decode += STBIR__horizontal_channels * 4; - stbir__4_coeff_continue_from_4( 0 ); - --n; - } while ( n > 0 ); - stbir__2_coeff_remnant( 4 ); - - stbir__store_output(); - } while ( output < output_end ); -} - -static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ) -{ - float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; - float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; - stbir__3_coeff_setup(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2; - float const * hc = horizontal_coefficients; - - stbir__4_coeff_start(); - STBIR_SIMD_NO_UNROLL_LOOP_START - do { - hc += 4; - decode += STBIR__horizontal_channels * 4; - stbir__4_coeff_continue_from_4( 0 ); - --n; - } while ( n > 0 ); - stbir__3_coeff_remnant( 4 ); - - stbir__store_output(); - } while ( output < output_end ); -} - -static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_funcs)[4]= -{ - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3), -}; - -static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_funcs)[12]= -{ - STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff), - STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_3_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_7_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs), -}; - -#undef STBIR__horizontal_channels -#undef STB_IMAGE_RESIZE_DO_HORIZONTALS -#undef stbir__1_coeff_only -#undef stbir__1_coeff_remnant -#undef stbir__2_coeff_only -#undef stbir__2_coeff_remnant -#undef stbir__3_coeff_only -#undef stbir__3_coeff_remnant -#undef stbir__3_coeff_setup -#undef stbir__4_coeff_start -#undef stbir__4_coeff_continue_from_4 -#undef stbir__store_output -#undef stbir__store_output_tiny -#undef STBIR_chans - -#endif // HORIZONALS - -#undef STBIR_strs_join2 -#undef STBIR_strs_join1 - -#endif // STB_IMAGE_RESIZE_DO_HORIZONTALS/VERTICALS/CODERS - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/raylib/external/stb_image_write.h b/raylib/external/stb_image_write.h index e4b32ed..95943eb 100644 --- a/raylib/external/stb_image_write.h +++ b/raylib/external/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.16 - public domain - http://nothings.org/stb +/* stb_image_write - v1.15 - public domain - http://nothings.org/stb writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 no warranty implied; use at your own risk @@ -140,7 +140,6 @@ CREDITS: Ivan Tikhonov github:ignotion Adam Schackart - Andrew Kensler LICENSE @@ -167,9 +166,9 @@ LICENSE #endif #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations -STBIWDEF int stbi_write_tga_with_rle; -STBIWDEF int stbi_write_png_compression_level; -STBIWDEF int stbi_write_force_png_filter; +extern int stbi_write_tga_with_rle; +extern int stbi_write_png_compression_level; +extern int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO @@ -179,7 +178,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); -#ifdef STBIW_WINDOWS_UTF8 +#ifdef STBI_WINDOWS_UTF8 STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); #endif #endif @@ -286,7 +285,7 @@ static void stbi__stdio_write(void *context, void *data, int size) fwrite(data,1,size,(FILE*) context); } -#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) #ifdef __cplusplus #define STBIW_EXTERN extern "C" #else @@ -297,25 +296,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); } #endif static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) return 0; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else f = _wfopen(wFilename, wMode); #endif @@ -398,7 +397,7 @@ static void stbiw__putc(stbi__write_context *s, unsigned char c) static void stbiw__write1(stbi__write_context *s, unsigned char a) { - if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + if (s->buf_used + 1 > sizeof(s->buffer)) stbiw__write_flush(s); s->buffer[s->buf_used++] = a; } @@ -406,7 +405,7 @@ static void stbiw__write1(stbi__write_context *s, unsigned char a) static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { int n; - if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + if (s->buf_used + 3 > sizeof(s->buffer)) stbiw__write_flush(s); n = s->buf_used; s->buf_used = n+3; @@ -491,22 +490,11 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) { - if (comp != 4) { - // write RGB bitmap - int pad = (-x*3) & 3; - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header - } else { - // RGBA bitmaps need a v4 header - // use BI_BITFIELDS mode with 32bpp and alpha mask - // (straight BI_RGB with alpha mask doesn't work in most readers) - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, - "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", - 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header - 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header - } + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header } STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) @@ -634,8 +622,6 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) -#ifndef STBI_WRITE_NO_STDIO - static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; @@ -770,7 +756,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); -#ifdef __STDC_LIB_EXT1__ +#ifdef __STDC_WANT_SECURE_LIB__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); @@ -791,6 +777,7 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, return stbi_write_hdr_core(&s, x, y, comp, (float *) data); } +#ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { stbi__write_context s = { 0 }; @@ -981,23 +968,6 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i (void) stbiw__sbfree(hash_table[i]); STBIW_FREE(hash_table); - // store uncompressed instead if compression was worse - if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { - stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 - for (j = 0; j < data_len;) { - int blocklen = data_len - j; - if (blocklen > 32767) blocklen = 32767; - stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression - stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN - stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN - stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); - memcpy(out+stbiw__sbn(out), data+j, blocklen); - stbiw__sbn(out) += blocklen; - j += blocklen; - } - } - { // compute adler32 on input unsigned int s1=1, s2=0; @@ -1628,10 +1598,6 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history - 1.16 (2021-07-11) - make Deflate code emit uncompressed blocks when it would otherwise expand - support writing BMPs with alpha channel - 1.15 (2020-07-13) unknown 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1.13 1.12 @@ -1669,7 +1635,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const add HDR output fix monochrome BMP 0.95 (2014-08-17) - add monochrome TGA output + add monochrome TGA output 0.94 (2014-05-31) rename private functions to avoid conflicts with stb_image.h 0.93 (2014-05-27) diff --git a/raylib/external/stb_rect_pack.h b/raylib/external/stb_rect_pack.h index 6a633ce..5c848de 100644 --- a/raylib/external/stb_rect_pack.h +++ b/raylib/external/stb_rect_pack.h @@ -1,15 +1,9 @@ -// stb_rect_pack.h - v1.01 - public domain - rectangle packing +// stb_rect_pack.h - v1.00 - public domain - rectangle packing // Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. // Does not do rotation. // -// Before #including, -// -// #define STB_RECT_PACK_IMPLEMENTATION -// -// in the file that you want to have the implementation. -// // Not necessarily the awesomest packing method, but better than // the totally naive one in stb_truetype (which is primarily what // this is meant to replace). @@ -41,7 +35,6 @@ // // Version history: // -// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles // 0.99 (2019-02-07) warning fixes // 0.11 (2017-03-03) return packing success/fail result @@ -82,10 +75,11 @@ typedef struct stbrp_context stbrp_context; typedef struct stbrp_node stbrp_node; typedef struct stbrp_rect stbrp_rect; +#ifdef STBRP_LARGE_RECTS typedef int stbrp_coord; - -#define STBRP__MAXVAL 0x7fffffff -// Mostly for internal use, but this is the maximum supported coordinate value. +#else +typedef unsigned short stbrp_coord; +#endif STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); // Assign packed locations to rectangles. The rectangles are of type @@ -215,10 +209,8 @@ struct stbrp_context #ifdef _MSC_VER #define STBRP__NOTUSED(v) (void)(v) -#define STBRP__CDECL __cdecl #else #define STBRP__NOTUSED(v) (void)sizeof(v) -#define STBRP__CDECL #endif enum @@ -261,6 +253,9 @@ STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_ou STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) { int i; +#ifndef STBRP_LARGE_RECTS + STBRP_ASSERT(width <= 0xffff && height <= 0xffff); +#endif for (i=0; i < num_nodes-1; ++i) nodes[i].next = &nodes[i+1]; @@ -279,7 +274,11 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, context->extra[0].y = 0; context->extra[0].next = &context->extra[1]; context->extra[1].x = (stbrp_coord) width; +#ifdef STBRP_LARGE_RECTS context->extra[1].y = (1<<30); +#else + context->extra[1].y = 65535; +#endif context->extra[1].next = NULL; } @@ -521,7 +520,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i return res; } -static int STBRP__CDECL rect_height_compare(const void *a, const void *b) +static int rect_height_compare(const void *a, const void *b) { const stbrp_rect *p = (const stbrp_rect *) a; const stbrp_rect *q = (const stbrp_rect *) b; @@ -532,13 +531,19 @@ static int STBRP__CDECL rect_height_compare(const void *a, const void *b) return (p->w > q->w) ? -1 : (p->w < q->w); } -static int STBRP__CDECL rect_original_order(const void *a, const void *b) +static int rect_original_order(const void *a, const void *b) { const stbrp_rect *p = (const stbrp_rect *) a; const stbrp_rect *q = (const stbrp_rect *) b; return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); } +#ifdef STBRP_LARGE_RECTS +#define STBRP__MAXVAL 0xffffffff +#else +#define STBRP__MAXVAL 0xffff +#endif + STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) { int i, all_rects_packed = 1; diff --git a/raylib/external/stb_truetype.h b/raylib/external/stb_truetype.h index 491a854..935a6de 100644 --- a/raylib/external/stb_truetype.h +++ b/raylib/external/stb_truetype.h @@ -1,5 +1,5 @@ -// stb_truetype.h - v1.26 - public domain -// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// stb_truetype.h - v1.24 - public domain +// authored from 2009-2020 by Sean Barrett / RAD Game Tools // // ======================================================================= // @@ -53,13 +53,11 @@ // Johan Duparc Thomas Fields // Hou Qiming Derek Vinyard // Rob Loach Cort Stratton -// Kenney Phillis Jr. Brian Costabile -// Ken Voskuil (kaesve) Yakov Galka +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) // // VERSION HISTORY // -// 1.26 (2021-08-28) fix broken rasterizer -// 1.25 (2021-07-11) many fixes // 1.24 (2020-02-05) fix warning // 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) // 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined @@ -272,8 +270,8 @@ //// SAMPLE PROGRAMS //// // -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. -// See "tests/truetype_demo_win32.c" for a complete version. +// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless +// #if 0 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" @@ -299,8 +297,6 @@ void my_stbtt_initfont(void) void my_stbtt_print(float x, float y, char *text) { // assume orthographic projection with units = screen pixels, origin at top left - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, ftex); glBegin(GL_QUADS); @@ -308,10 +304,10 @@ void my_stbtt_print(float x, float y, char *text) if (*text >= 32 && *text < 128) { stbtt_aligned_quad q; stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); } ++text; } @@ -857,7 +853,6 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); // frees the data allocated above -STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); // fills svg with the character's SVG data. @@ -1544,12 +1539,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep search += 2; { - stbtt_uint16 offset, start, last; + stbtt_uint16 offset, start; stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - last = ttUSHORT(data + endCount + 2*item); - if (unicode_codepoint < start || unicode_codepoint > last) + if (unicode_codepoint < start) return 0; offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); @@ -1863,11 +1858,11 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s stbtt_vertex* v = &comp_verts[i]; stbtt_vertex_type x,y; x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(mtx[0]*x + mtx[2]*y + mtx[4]*m); - v->y = (stbtt_vertex_type)(mtx[1]*x + mtx[3]*y + mtx[5]*n); + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(mtx[0]*x + mtx[2]*y + mtx[4]*m); - v->cy = (stbtt_vertex_type)(mtx[1]*x + mtx[3]*y + mtx[5]*n); + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); } // Append vertices. tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); @@ -1876,7 +1871,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s if (comp_verts) STBTT_free(comp_verts, info->userdata); return 0; } - if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); if (vertices) STBTT_free(vertices, info->userdata); vertices = tmp; @@ -2139,7 +2134,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); has_subrs = 1; } - // FALLTHROUGH + // fallthrough case 0x1D: // callgsubr if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); v = (int) s[--sp]; @@ -2244,7 +2239,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st } break; default: - if (b0 != 255 && b0 != 28 && b0 < 32) + if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) return STBTT__CSERR("reserved operator"); // push immediate @@ -2356,7 +2351,7 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningent return length; } -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) { stbtt_uint8 *data = info->data + info->kern; stbtt_uint32 needle, straw; @@ -2386,225 +2381,243 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1 return 0; } -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) { - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); - switch (coverageFormat) { - case 1: { - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch(coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); - // Binary search. - stbtt_int32 l=0, r=glyphCount-1, m; - int straw, needle=glyph; - while (l <= r) { - stbtt_uint8 *glyphArray = coverageTable + 4; - stbtt_uint16 glyphID; - m = (l + r) >> 1; - glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - return m; + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } } - } - break; - } + } break; - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; - // Binary search. - stbtt_int32 l=0, r=rangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *rangeRecord; - m = (l + r) >> 1; - rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } } - } - break; - } + } break; - default: return -1; // unsupported - } + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } - return -1; + return -1; } static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) { - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); - switch (classDefFormat) - { - case 1: { - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch(classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) - return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - break; - } + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; + classDefTable = classDef1ValueArray + 2 * glyphCount; + } break; - // Binary search. - stbtt_int32 l=0, r=classRangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *classRangeRecord; - m = (l + r) >> 1; - classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } - break; - } + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; - default: - return -1; // Unsupported definition type, return an error. - } + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } - // "All glyphs not assigned to a class fall into class 0". (OpenType spec) - return 0; + classDefTable = classRangeRecords + 6 * classRangeCount; + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; } // Define to STBTT_assert(x) if you want to break on unimplemented formats. #define STBTT_GPOS_TODO_assert(x) -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) { - stbtt_uint16 lookupListOffset; - stbtt_uint8 *lookupList; - stbtt_uint16 lookupCount; - stbtt_uint8 *data; - stbtt_int32 i, sti; + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i; - if (!info->gpos) return 0; + if (!info->gpos) return 0; - data = info->data + info->gpos; + data = info->data + info->gpos; - if (ttUSHORT(data+0) != 1) return 0; // Major version 1 - if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 - lookupListOffset = ttUSHORT(data+8); - lookupList = data + lookupListOffset; - lookupCount = ttUSHORT(lookupList); + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); - for (i=0; i= pairSetCount) return 0; + needle=glyph2; + r=pairValueCount-1; + l=0; - needle=glyph2; - r=pairValueCount-1; - l=0; + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } break; - // Binary search. - while (l <= r) { - stbtt_uint16 secondGlyph; - stbtt_uint8 *pairValue; - m = (l + r) >> 1; - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; - secondGlyph = ttUSHORT(pairValue); - straw = secondGlyph; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); - return xAdvance; - } - } - } else - return 0; - break; - } + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - case 2: { - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); - stbtt_uint16 class1Count = ttUSHORT(table + 12); - stbtt_uint16 class2Count = ttUSHORT(table + 14); - stbtt_uint8 *class1Records, *class2Records; - stbtt_int16 xAdvance; + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + STBTT_assert(glyph1class < class1Count); + STBTT_assert(glyph2class < class2Count); - if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed - if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + // TODO: Support more formats. + STBTT_GPOS_TODO_assert(valueFormat1 == 4); + if (valueFormat1 != 4) return 0; + STBTT_GPOS_TODO_assert(valueFormat2 == 0); + if (valueFormat2 != 0) return 0; - class1Records = table + 16; - class2Records = class1Records + 2 * (glyph1class * class2Count); - xAdvance = ttSHORT(class2Records + 2 * glyph2class); - return xAdvance; - } else - return 0; - break; - } + if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { + stbtt_uint8 *class1Records = table + 16; + stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); + stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + break; + }; + } + } + break; + }; default: - return 0; // Unsupported position format - } - } - } + // TODO: Implement other stuff. + break; + } + } - return 0; + return 0; } STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) @@ -3062,23 +3075,6 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg } } -static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) -{ - STBTT_assert(top_width >= 0); - STBTT_assert(bottom_width >= 0); - return (top_width + bottom_width) / 2.0f * height; -} - -static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) -{ - return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); -} - -static float stbtt__sized_triangle_area(float height, float width) -{ - return height * width / 2; -} - static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) { float y_bottom = y_top+1; @@ -3133,13 +3129,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, float height; // simple case, only spans one pixel int x = (int) x_top; - height = (sy1 - sy0) * e->direction; + height = sy1 - sy0; STBTT_assert(x >= 0 && x < len); - scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); - scanline_fill[x] += height; // everything right of this pixel is filled + scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; + scanline_fill[x] += e->direction * height; // everything right of this pixel is filled } else { int x,x1,x2; - float y_crossing, y_final, step, sign, area; + float y_crossing, step, sign, area; // covers 2+ pixels if (x_top > x_bottom) { // flip scanline vertically; signed area is the same @@ -3152,79 +3148,29 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, dy = -dy; t = x0, x0 = xb, xb = t; } - STBTT_assert(dy >= 0); - STBTT_assert(dx >= 0); x1 = (int) x_top; x2 = (int) x_bottom; // compute intersection with y axis at x1+1 - y_crossing = y_top + dy * (x1+1 - x0); - - // compute intersection with y axis at x2 - y_final = y_top + dy * (x2 - x0); - - // x1 x_top x2 x_bottom - // y_top +------|-----+------------+------------+--------|---+------------+ - // | | | | | | - // | | | | | | - // sy0 | Txxxxx|............|............|............|............| - // y_crossing | *xxxxx.......|............|............|............| - // | | xxxxx..|............|............|............| - // | | /- xx*xxxx........|............|............| - // | | dy < | xxxxxx..|............|............| - // y_final | | \- | xx*xxx.........|............| - // sy1 | | | | xxxxxB...|............| - // | | | | | | - // | | | | | | - // y_bottom +------------+------------+------------+------------+------------+ - // - // goal is to measure the area covered by '.' in each pixel - - // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 - // @TODO: maybe test against sy1 rather than y_bottom? - if (y_crossing > y_bottom) - y_crossing = y_bottom; + y_crossing = (x1+1 - x0) * dy + y_top; sign = e->direction; - - // area of the rectangle covered from sy0..y_crossing + // area of the rectangle covered from y0..y_crossing area = sign * (y_crossing-sy0); + // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) + scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); - // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) - scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); - - // check if final y_crossing is blown up; no test case for this - if (y_final > y_bottom) { - y_final = y_bottom; - dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom - } - - // in second pixel, area covered by line segment found in first pixel - // is always a rectangle 1 wide * the height of that line segment; this - // is exactly what the variable 'area' stores. it also gets a contribution - // from the line segment within it. the THIRD pixel will get the first - // pixel's rectangle contribution, the second pixel's rectangle contribution, - // and its own contribution. the 'own contribution' is the same in every pixel except - // the leftmost and rightmost, a trapezoid that slides down in each pixel. - // the second pixel's contribution to the third pixel will be the - // rectangle 1 wide times the height change in the second pixel, which is dy. - - step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, - // which multiplied by 1-pixel-width is how much pixel area changes for each step in x - // so the area advances by 'step' every time - + step = sign * dy; for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; // area of trapezoid is 1*step/2 + scanline[x] += area + step/2; area += step; } - STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down - STBTT_assert(sy1 > y_final-0.01f); + y_crossing += dy * (x2 - (x1+1)); - // area covered in the last pixel is the rectangle from all the pixels to the left, - // plus the trapezoid filled by the line segment in this pixel all the way to the right edge - scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + STBTT_assert(STBTT_fabs(area) <= 1.01f); + + scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); - // the rest of the line is filled based on the total height of the line segment in this pixel scanline_fill[x2] += sign * (sy1-sy0); } } else { @@ -3232,9 +3178,6 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, // clipping logic. since this does not match the intended use // of this library, we use a different, very slow brute // force implementation - // note though that this does happen some of the time because - // x_top and x_bottom can be extrapolated at the top & bottom of - // the shape and actually lie outside the bounding box int x; for (x=0; x < len; ++x) { // cases: @@ -4471,14 +4414,15 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex float y_frac; int winding = 0; + orig[0] = x; + orig[1] = y; + // make sure y never passes through a vertex of the shape y_frac = (float) STBTT_fmod(y, 1.0f); if (y_frac < 0.01f) y += 0.01f; else if (y_frac > 0.99f) y -= 0.01f; - - orig[0] = x; orig[1] = y; // test a ray from (-infinity,y) to (x,y) @@ -4540,35 +4484,35 @@ static float stbtt__cuberoot( float x ) return (float) STBTT_pow( x,1.0f/3.0f); } -// x^3 + a*x^2 + b*x + c = 0 +// x^3 + c*x^2 + b*x + a = 0 static int stbtt__solve_cubic(float a, float b, float c, float* r) { - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative - float m = (float) STBTT_cos(v); + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); - return 3; + return 3; } } @@ -4604,8 +4548,6 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc scale_y = -scale_y; { - // distance from singular values (in the same units as the pixel grid) - const float eps = 1./1024, eps2 = eps*eps; int x,y,i,j; float *precompute; stbtt_vertex *verts; @@ -4618,15 +4560,15 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); - precompute[i] = (dist < eps) ? 0.0f : 1.0f / dist; + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; } else if (verts[i].type == STBTT_vcurve) { float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; float len2 = bx*bx + by*by; - if (len2 >= eps2) - precompute[i] = 1.0f / len2; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx*bx + by*by); else precompute[i] = 0.0f; } else @@ -4647,17 +4589,18 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc for (i=0; i < num_verts; ++i) { float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve + float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); - float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); + if (verts[i].type == STBTT_vline) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; // coarse culling against bbox //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) - dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; STBTT_assert(i != 0); if (dist < min_dist) { // check position along line @@ -4684,15 +4627,14 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc float ax = x1-x0, ay = y1-y0; float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; float mx = x0 - sx, my = y0 - sy; - float res[3] = {0.f,0.f,0.f}; - float px,py,t,it,dist2; + float res[3],px,py,t,it; float a_inv = precompute[i]; if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula float a = 3*(ax*bx + ay*by); float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); float c = mx*ax+my*ay; - if (STBTT_fabs(a) < eps2) { // if a is 0, it's linear - if (STBTT_fabs(b) >= eps2) { + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { res[num++] = -c/b; } } else { @@ -4712,10 +4654,6 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc float d = (mx*ax+my*ay) * a_inv; num = stbtt__solve_cubic(b, c, d, res); } - dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { t = res[0], it = 1.0f - t; px = it*it*x0 + 2*t*it*x1 + t*t*x2; @@ -4975,12 +4913,6 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const // FULL VERSION HISTORY // -// 1.25 (2021-07-11) many fixes -// 1.24 (2020-02-05) fix warning -// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) -// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined -// 1.21 (2019-02-25) fix warning -// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() // 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod // 1.18 (2018-01-29) add missing function // 1.17 (2017-07-23) make more arguments const; doc fix diff --git a/raylib/external/stb_vorbis.c b/raylib/external/stb_vorbis.h similarity index 68% rename from raylib/external/stb_vorbis.c rename to raylib/external/stb_vorbis.h index 3e5c250..c9ee5cc 100644 --- a/raylib/external/stb_vorbis.c +++ b/raylib/external/stb_vorbis.h @@ -1,4 +1,4 @@ -// Ogg Vorbis audio decoder - v1.22 - public domain +// Ogg Vorbis audio decoder - v1.14 - public domain // http://nothings.org/stb_vorbis/ // // Original version written by Sean Barrett in 2007. @@ -26,29 +26,18 @@ // Terje Mathisen Niklas Frykholm Andy Hill // Casey Muratori John Bolton Gargaj // Laurent Gomila Marc LeBlanc Ronny Chevalier -// Bernhard Wodo Evan Balster github:alxprd +// Bernhard Wodo Evan Balster alxprd@github // Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Phillip Bennefall Rohit Thiago Goulart -// github:manxorist Saga Musix github:infatum -// Timur Gagiev Maxwell Koo Peter Waller -// github:audinowho Dougall Johnson David Reid -// github:Clownacy Pedro J. Estebanez Remi Verschelde -// AnthoFoxo github:morlat Gabriel Ravier +// manxorist@github saga musix github:infatum +// Timur Gagiev BareRose // // Partial history: -// 1.22 - 2021-07-11 - various small fixes -// 1.21 - 2021-07-02 - fix bug for files with no comments -// 1.20 - 2020-07-11 - several small fixes -// 1.19 - 2020-02-05 - warnings -// 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. -// 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure) -// 1.16 - 2019-03-04 - fix warnings -// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found // 1.14 - 2018-02-11 - delete bogus dealloca usage // 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) // 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files -// 1.11 - 2017-07-23 - fix MinGW compilation -// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory +// 1.11 - 2017-07-23 - fix MinGW compilation +// 1.10 - 2017-03-03 - more robust seeking; fix negative stbv_ilog(); clear error in open_memory // 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version // 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame // 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const @@ -75,17 +64,28 @@ #define STB_VORBIS_INCLUDE_STB_VORBIS_H #if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) -#define STB_VORBIS_NO_STDIO 1 +#define STB_VORBIS_NO_STDIO #endif #ifndef STB_VORBIS_NO_STDIO #include #endif +// NOTE: Added to work with raylib on Android +#if defined(PLATFORM_ANDROID) + #include "utils.h" // Android fopen function map +#endif + #ifdef __cplusplus extern "C" { #endif +#ifdef STB_VORBIS_STATIC +#define STBVDEF static +#else +#define STBVDEF extern +#endif + /////////// THREAD SAFETY // Individual stb_vorbis* handles are not thread-safe; you cannot decode from @@ -101,8 +101,8 @@ extern "C" { // data in the file and how you set the compile flags for speed // vs. size. In my test files the maximal-size usage is ~150KB.) // -// You can modify the wrapper functions in the source (setup_malloc, -// setup_temp_malloc, temp_malloc) to change this behavior, or you +// You can modify the wrapper functions in the source (stbv_setup_malloc, +// stbv_setup_temp_malloc, temp_malloc) to change this behavior, or you // can use a simpler allocation model: you pass in a buffer from // which stb_vorbis will allocate _all_ its memory (including the // temp memory). "open" may fail with a VORBIS_outofmem if you @@ -138,36 +138,25 @@ typedef struct int max_frame_size; } stb_vorbis_info; -typedef struct -{ - char *vendor; - - int comment_list_length; - char **comment_list; -} stb_vorbis_comment; - // get general information about the file -extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); - -// get ogg comments -extern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f); +STBVDEF stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); // get the last error detected (clears it, too) -extern int stb_vorbis_get_error(stb_vorbis *f); +STBVDEF int stb_vorbis_get_error(stb_vorbis *f); // close an ogg vorbis file and free all memory in use -extern void stb_vorbis_close(stb_vorbis *f); +STBVDEF void stb_vorbis_close(stb_vorbis *f); // this function returns the offset (in samples) from the beginning of the // file that will be returned by the next decode, if it is known, or -1 // otherwise. after a flush_pushdata() call, this may take a while before // it becomes valid again. // NOT WORKING YET after a seek with PULLDATA API -extern int stb_vorbis_get_sample_offset(stb_vorbis *f); +STBVDEF int stb_vorbis_get_sample_offset(stb_vorbis *f); // returns the current seek point within the file, or offset from the beginning // of the memory buffer. In pushdata mode it returns 0. -extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); +STBVDEF unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); /////////// PUSHDATA API @@ -180,7 +169,7 @@ extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); // need to give it the same data again PLUS more. Note that the Vorbis // specification does not bound the size of an individual frame. -extern stb_vorbis *stb_vorbis_open_pushdata( +STBVDEF stb_vorbis *stb_vorbis_open_pushdata( const unsigned char * datablock, int datablock_length_in_bytes, int *datablock_memory_consumed_in_bytes, int *error, @@ -194,7 +183,7 @@ extern stb_vorbis *stb_vorbis_open_pushdata( // if returns NULL and *error is VORBIS_need_more_data, then the input block was // incomplete and you need to pass in a larger block from the start of the file -extern int stb_vorbis_decode_frame_pushdata( +STBVDEF int stb_vorbis_decode_frame_pushdata( stb_vorbis *f, const unsigned char *datablock, int datablock_length_in_bytes, int *channels, // place to write number of float * buffers @@ -223,14 +212,8 @@ extern int stb_vorbis_decode_frame_pushdata( // channel. In other words, (*output)[0][0] contains the first sample from // the first channel, and (*output)[1][0] contains the first sample from // the second channel. -// -// *output points into stb_vorbis's internal output buffer storage; these -// buffers are owned by stb_vorbis and application code should not free -// them or modify their contents. They are transient and will be overwritten -// once you ask for more data to get decoded, so be sure to grab any data -// you need before then. -extern void stb_vorbis_flush_pushdata(stb_vorbis *f); +STBVDEF void stb_vorbis_flush_pushdata(stb_vorbis *f); // inform stb_vorbis that your next datablock will not be contiguous with // previous ones (e.g. you've seeked in the data); future attempts to decode // frames will cause stb_vorbis to resynchronize (as noted above), and @@ -255,38 +238,38 @@ extern void stb_vorbis_flush_pushdata(stb_vorbis *f); // just want to go ahead and use pushdata.) #if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION) -extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output); +STBVDEF int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output); #endif -#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION) -extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output); +#ifndef STB_VORBIS_NO_INTEGER_CONVERSION +STBVDEF int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output); #endif // decode an entire file and output the data interleaved into a malloc()ed // buffer stored in *output. The return value is the number of samples // decoded, or -1 if the file could not be opened or was not an ogg vorbis file. // When you're done with it, just free() the pointer returned in *output. -extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, +STBVDEF stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from an ogg vorbis stream in memory (note // this must be the entire stream!). on failure, returns NULL and sets *error #ifndef STB_VORBIS_NO_STDIO -extern stb_vorbis * stb_vorbis_open_filename(const char *filename, +STBVDEF stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from a filename via fopen(). on failure, // returns NULL and sets *error (possibly to VORBIS_file_open_failure). -extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, +STBVDEF stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, int *error, const stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from an open FILE *, looking for a stream at // the _current_ seek point (ftell). on failure, returns NULL and sets *error. // note that stb_vorbis must "own" this stream; if you seek it in between -// calls to stb_vorbis, it will become confused. Moreover, if you attempt to +// calls to stb_vorbis, it will become confused. Morever, if you attempt to // perform stb_vorbis_seek_*() operations on this file, it will assume it // owns the _entire_ rest of the file after the start point. Use the next // function, stb_vorbis_open_file_section(), to limit it. -extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, +STBVDEF stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len); // create an ogg vorbis decoder from an open FILE *, looking for a stream at // the _current_ seek point (ftell); the stream will be of length 'len' bytes. @@ -295,8 +278,8 @@ extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_cl // confused. #endif -extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); -extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); +STBVDEF int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); +STBVDEF int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); // these functions seek in the Vorbis file to (approximately) 'sample_number'. // after calling seek_frame(), the next call to get_frame_*() will include // the specified sample. after calling stb_vorbis_seek(), the next call to @@ -304,14 +287,14 @@ extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); // do not need to seek to EXACTLY the target sample when using get_samples_*, // you can also use seek_frame(). -extern int stb_vorbis_seek_start(stb_vorbis *f); +STBVDEF int stb_vorbis_seek_start(stb_vorbis *f); // this function is equivalent to stb_vorbis_seek(f,0) -extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); -extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); +STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); +STBVDEF float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); // these functions return the total length of the vorbis stream -extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); +STBVDEF int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); // decode the next frame and return the number of samples. the number of // channels returned are stored in *channels (which can be NULL--it is always // the same as the number of channels reported by get_info). *output will @@ -322,8 +305,8 @@ extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***out // and stb_vorbis_get_samples_*(), since the latter calls the former. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION -extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); -extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); +STBVDEF int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); +STBVDEF int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); #endif // decode the next frame and return the number of *samples* per channel. // Note that for interleaved data, you pass in the number of shorts (the @@ -350,16 +333,16 @@ extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, shor // Note that this is not _good_ surround etc. mixing at all! It's just so // you get something useful. -extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); -extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); +STBVDEF int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); +STBVDEF int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); // gets num_samples samples, not necessarily on a frame boundary--this requires // buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES. // Returns the number of samples stored per channel; it may be less than requested // at the end of the file. If there are no more samples in the file, returns 0. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION -extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); -extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); +STBVDEF int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); +STBVDEF int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); #endif // gets num_samples samples, not necessarily on a frame boundary--this requires // buffering so you have to supply the buffers. Applies the coercion rules above @@ -402,8 +385,7 @@ enum STBVorbisError VORBIS_invalid_first_page, VORBIS_bad_packet_type, VORBIS_cant_find_last_page, - VORBIS_seek_failed, - VORBIS_ogg_skeleton_not_supported + VORBIS_seek_failed }; @@ -417,7 +399,7 @@ enum STBVorbisError // ////////////////////////////////////////////////////////////////////////////// -#ifndef STB_VORBIS_HEADER_ONLY +#ifdef STB_VORBIS_IMPLEMENTATION // global configuration settings (e.g. set these in the project/makefile), // or just set them in this file at the top (although ideally the first few @@ -446,7 +428,7 @@ enum STBVorbisError // STB_VORBIS_NO_FAST_SCALED_FLOAT // does not use a fast float-to-int trick to accelerate float-to-int on // most platforms which requires endianness be defined correctly. -//#define STB_VORBIS_NO_FAST_SCALED_FLOAT +// #define STB_VORBIS_NO_FAST_SCALED_FLOAT // STB_VORBIS_MAX_CHANNELS [number] @@ -588,7 +570,7 @@ enum STBVorbisError #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif - #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) + #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) || defined(__APPLE__) #include #endif #else // STB_VORBIS_NO_CRT @@ -611,7 +593,7 @@ enum STBVorbisError #endif #define __forceinline #ifndef alloca - #define alloca __builtin_alloca + #define alloca(s) __builtin_alloca(s) #endif #elif !defined(_MSC_VER) #if __GNUC__ @@ -632,34 +614,28 @@ enum STBVorbisError #if 0 #include -#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1]) +#define STBV_CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1]) #else -#define CHECK(f) ((void) 0) +#define STBV_CHECK(f) ((void) 0) #endif -#define MAX_BLOCKSIZE_LOG 13 // from specification -#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) +#define STBV_MAX_BLOCKSIZE_LOG 13 // from specification +#define STBV_MAX_BLOCKSIZE (1 << STBV_MAX_BLOCKSIZE_LOG) -typedef unsigned char uint8; -typedef signed char int8; -typedef unsigned short uint16; -typedef signed short int16; -typedef unsigned int uint32; -typedef signed int int32; +typedef unsigned char stbv_uint8; +typedef signed char stbv_int8; +typedef unsigned short stbv_uint16; +typedef signed short stbv_int16; +typedef unsigned int stbv_uint32; +typedef signed int stbv_int32; #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif -typedef float codetype; - -#ifdef _MSC_VER -#define STBV_NOTUSED(v) (void)(v) -#else -#define STBV_NOTUSED(v) (void)sizeof(v) -#endif +typedef float stbv_codetype; // @NOTE // @@ -674,113 +650,113 @@ typedef float codetype; // the sizes larger--nothing relies on silently truncating etc., nor the // order of variables. -#define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH) -#define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1) +#define STBV_FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH) +#define STBV_FAST_HUFFMAN_TABLE_MASK (STBV_FAST_HUFFMAN_TABLE_SIZE - 1) typedef struct { int dimensions, entries; - uint8 *codeword_lengths; + stbv_uint8 *codeword_lengths; float minimum_value; float delta_value; - uint8 value_bits; - uint8 lookup_type; - uint8 sequence_p; - uint8 sparse; - uint32 lookup_values; - codetype *multiplicands; - uint32 *codewords; + stbv_uint8 value_bits; + stbv_uint8 lookup_type; + stbv_uint8 sequence_p; + stbv_uint8 sparse; + stbv_uint32 lookup_values; + stbv_codetype *multiplicands; + stbv_uint32 *codewords; #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT - int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; + stbv_int16 fast_huffman[STBV_FAST_HUFFMAN_TABLE_SIZE]; #else - int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; + stbv_int32 fast_huffman[STBV_FAST_HUFFMAN_TABLE_SIZE]; #endif - uint32 *sorted_codewords; + stbv_uint32 *sorted_codewords; int *sorted_values; int sorted_entries; -} Codebook; +} StbvCodebook; typedef struct { - uint8 order; - uint16 rate; - uint16 bark_map_size; - uint8 amplitude_bits; - uint8 amplitude_offset; - uint8 number_of_books; - uint8 book_list[16]; // varies -} Floor0; + stbv_uint8 order; + stbv_uint16 rate; + stbv_uint16 bark_map_size; + stbv_uint8 amplitude_bits; + stbv_uint8 amplitude_offset; + stbv_uint8 number_of_books; + stbv_uint8 book_list[16]; // varies +} StbvFloor0; typedef struct { - uint8 partitions; - uint8 partition_class_list[32]; // varies - uint8 class_dimensions[16]; // varies - uint8 class_subclasses[16]; // varies - uint8 class_masterbooks[16]; // varies - int16 subclass_books[16][8]; // varies - uint16 Xlist[31*8+2]; // varies - uint8 sorted_order[31*8+2]; - uint8 neighbors[31*8+2][2]; - uint8 floor1_multiplier; - uint8 rangebits; + stbv_uint8 partitions; + stbv_uint8 partition_class_list[32]; // varies + stbv_uint8 class_dimensions[16]; // varies + stbv_uint8 class_subclasses[16]; // varies + stbv_uint8 class_masterbooks[16]; // varies + stbv_int16 subclass_books[16][8]; // varies + stbv_uint16 Xlist[31*8+2]; // varies + stbv_uint8 sorted_order[31*8+2]; + stbv_uint8 stbv_neighbors[31*8+2][2]; + stbv_uint8 floor1_multiplier; + stbv_uint8 rangebits; int values; -} Floor1; +} StbvFloor1; typedef union { - Floor0 floor0; - Floor1 floor1; -} Floor; + StbvFloor0 floor0; + StbvFloor1 floor1; +} StbvFloor; typedef struct { - uint32 begin, end; - uint32 part_size; - uint8 classifications; - uint8 classbook; - uint8 **classdata; - int16 (*residue_books)[8]; -} Residue; + stbv_uint32 begin, end; + stbv_uint32 part_size; + stbv_uint8 classifications; + stbv_uint8 classbook; + stbv_uint8 **classdata; + stbv_int16 (*residue_books)[8]; +} StbvResidue; typedef struct { - uint8 magnitude; - uint8 angle; - uint8 mux; -} MappingChannel; + stbv_uint8 magnitude; + stbv_uint8 angle; + stbv_uint8 mux; +} StbvMappingChannel; typedef struct { - uint16 coupling_steps; - MappingChannel *chan; - uint8 submaps; - uint8 submap_floor[15]; // varies - uint8 submap_residue[15]; // varies -} Mapping; + stbv_uint16 coupling_steps; + StbvMappingChannel *chan; + stbv_uint8 submaps; + stbv_uint8 submap_floor[15]; // varies + stbv_uint8 submap_residue[15]; // varies +} StbvMapping; typedef struct { - uint8 blockflag; - uint8 mapping; - uint16 windowtype; - uint16 transformtype; -} Mode; + stbv_uint8 blockflag; + stbv_uint8 mapping; + stbv_uint16 windowtype; + stbv_uint16 transformtype; +} StbvMode; typedef struct { - uint32 goal_crc; // expected crc if match + stbv_uint32 goal_crc; // expected crc if match int bytes_left; // bytes left in packet - uint32 crc_so_far; // running crc + stbv_uint32 crc_so_far; // running crc int bytes_done; // bytes processed in _current_ chunk - uint32 sample_loc; // granule pos encoded in page -} CRCscan; + stbv_uint32 sample_loc; // granule pos encoded in page +} StbvCRCscan; typedef struct { - uint32 page_start, page_end; - uint32 last_decoded_sample; -} ProbedPage; + stbv_uint32 page_start, page_end; + stbv_uint32 last_decoded_sample; +} StbvProbedPage; struct stb_vorbis { @@ -792,31 +768,24 @@ struct stb_vorbis unsigned int temp_memory_required; unsigned int setup_temp_memory_required; - char *vendor; - int comment_list_length; - char **comment_list; - // input config #ifndef STB_VORBIS_NO_STDIO FILE *f; - uint32 f_start; + stbv_uint32 f_start; int close_on_free; #endif - uint8 *stream; - uint8 *stream_start; - uint8 *stream_end; + stbv_uint8 *stream; + stbv_uint8 *stream_start; + stbv_uint8 *stream_end; - uint32 stream_len; + stbv_uint32 stream_len; - uint8 push_mode; + stbv_uint8 push_mode; - // the page to seek to when seeking to start, may be zero - uint32 first_audio_page_offset; + stbv_uint32 first_audio_page_offset; - // p_first is the page on which the first audio packet ends - // (but not necessarily the page on which it starts) - ProbedPage p_first, p_last; + StbvProbedPage p_first, p_last; // memory management stb_vorbis_alloc alloc; @@ -833,19 +802,19 @@ struct stb_vorbis int blocksize[2]; int blocksize_0, blocksize_1; int codebook_count; - Codebook *codebooks; + StbvCodebook *codebooks; int floor_count; - uint16 floor_types[64]; // varies - Floor *floor_config; + stbv_uint16 floor_types[64]; // varies + StbvFloor *floor_config; int residue_count; - uint16 residue_types[64]; // varies - Residue *residue_config; + stbv_uint16 residue_types[64]; // varies + StbvResidue *residue_config; int mapping_count; - Mapping *mapping; + StbvMapping *mapping; int mode_count; - Mode mode_config[64]; // varies + StbvMode mode_config[64]; // varies - uint32 total_samples; + stbv_uint32 total_samples; // decode buffer float *channel_buffers[STB_VORBIS_MAX_CHANNELS]; @@ -855,44 +824,44 @@ struct stb_vorbis int previous_length; #ifndef STB_VORBIS_NO_DEFER_FLOOR - int16 *finalY[STB_VORBIS_MAX_CHANNELS]; + stbv_int16 *finalY[STB_VORBIS_MAX_CHANNELS]; #else float *floor_buffers[STB_VORBIS_MAX_CHANNELS]; #endif - uint32 current_loc; // sample location of next frame to decode + stbv_uint32 current_loc; // sample location of next frame to decode int current_loc_valid; // per-blocksize precomputed data - + // twiddle factors float *A[2],*B[2],*C[2]; float *window[2]; - uint16 *bit_reverse[2]; + stbv_uint16 *stbv_bit_reverse[2]; // current page/packet/segment streaming info - uint32 serial; // stream serial number for verification + stbv_uint32 serial; // stream serial number for verification int last_page; int segment_count; - uint8 segments[255]; - uint8 page_flag; - uint8 bytes_in_seg; - uint8 first_decode; + stbv_uint8 segments[255]; + stbv_uint8 page_flag; + stbv_uint8 bytes_in_seg; + stbv_uint8 first_decode; int next_seg; int last_seg; // flag that we're on the last segment int last_seg_which; // what was the segment number of the last seg? - uint32 acc; + stbv_uint32 acc; int valid_bits; int packet_bytes; int end_seg_with_known_loc; - uint32 known_loc_for_packet; + stbv_uint32 known_loc_for_packet; int discard_samples_deferred; - uint32 samples_output; + stbv_uint32 samples_output; // push mode scanning int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching #ifndef STB_VORBIS_NO_PUSHDATA_API - CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; + StbvCRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; #endif // sample-access @@ -901,16 +870,16 @@ struct stb_vorbis }; #if defined(STB_VORBIS_NO_PUSHDATA_API) - #define IS_PUSH_MODE(f) FALSE + #define STBV_IS_PUSH_MODE(f) FALSE #elif defined(STB_VORBIS_NO_PULLDATA_API) - #define IS_PUSH_MODE(f) TRUE + #define STBV_IS_PUSH_MODE(f) TRUE #else - #define IS_PUSH_MODE(f) ((f)->push_mode) + #define STBV_IS_PUSH_MODE(f) ((f)->push_mode) #endif -typedef struct stb_vorbis vorb; +typedef struct stb_vorbis stbv_vorb; -static int error(vorb *f, enum STBVorbisError e) +static int stbv_error(stbv_vorb *f, enum STBVorbisError e) { f->error = e; if (!f->eof && e != VORBIS_need_more_data) { @@ -925,17 +894,17 @@ static int error(vorb *f, enum STBVorbisError e) // alloca(); otherwise, provide a temp buffer and it will // allocate out of those. -#define array_size_required(count,size) (count*(sizeof(void *)+(size))) +#define stbv_array_size_required(count,size) (count*(sizeof(void *)+(size))) -#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) -#define temp_free(f,p) (void)0 -#define temp_alloc_save(f) ((f)->temp_offset) -#define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) +#define stbv_temp_alloc(f,size) (f->alloc.alloc_buffer ? stbv_setup_temp_malloc(f,size) : alloca(size)) +#define stbv_temp_free(f,p) 0 +#define stbv_temp_alloc_save(f) ((f)->temp_offset) +#define stbv_temp_alloc_restore(f,p) ((f)->temp_offset = (p)) -#define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size) +#define stbv_temp_block_array(f,count,size) stbv_make_block_array(stbv_temp_alloc(f,stbv_array_size_required(count,size)), count, size) // given a sufficiently large block of memory, make an array of pointers to subblocks of it -static void *make_block_array(void *mem, int count, int size) +static void *stbv_make_block_array(void *mem, int count, int size) { int i; void ** p = (void **) mem; @@ -947,9 +916,9 @@ static void *make_block_array(void *mem, int count, int size) return p; } -static void *setup_malloc(vorb *f, int sz) +static void *stbv_setup_malloc(stbv_vorb *f, int sz) { - sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. + sz = (sz+3) & ~3; f->setup_memory_required += sz; if (f->alloc.alloc_buffer) { void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; @@ -960,15 +929,15 @@ static void *setup_malloc(vorb *f, int sz) return sz ? malloc(sz) : NULL; } -static void setup_free(vorb *f, void *p) +static void stbv_setup_free(stbv_vorb *f, void *p) { if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack free(p); } -static void *setup_temp_malloc(vorb *f, int sz) +static void *stbv_setup_temp_malloc(stbv_vorb *f, int sz) { - sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. + sz = (sz+3) & ~3; if (f->alloc.alloc_buffer) { if (f->temp_offset - sz < f->setup_offset) return NULL; f->temp_offset -= sz; @@ -977,37 +946,37 @@ static void *setup_temp_malloc(vorb *f, int sz) return malloc(sz); } -static void setup_temp_free(vorb *f, void *p, int sz) +static void stbv_setup_temp_free(stbv_vorb *f, void *p, int sz) { if (f->alloc.alloc_buffer) { - f->temp_offset += (sz+7)&~7; + f->temp_offset += (sz+3)&~3; return; } free(p); } -#define CRC32_POLY 0x04c11db7 // from spec +#define STBV_CRC32_POLY 0x04c11db7 // from spec -static uint32 crc_table[256]; -static void crc32_init(void) +static stbv_uint32 stbv_crc_table[256]; +static void stbv_crc32_init(void) { int i,j; - uint32 s; + stbv_uint32 s; for(i=0; i < 256; i++) { - for (s=(uint32) i << 24, j=0; j < 8; ++j) - s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0); - crc_table[i] = s; + for (s=(stbv_uint32) i << 24, j=0; j < 8; ++j) + s = (s << 1) ^ (s >= (1U<<31) ? STBV_CRC32_POLY : 0); + stbv_crc_table[i] = s; } } -static __forceinline uint32 crc32_update(uint32 crc, uint8 byte) +static __forceinline stbv_uint32 stbv_crc32_update(stbv_uint32 crc, stbv_uint8 byte) { - return (crc << 8) ^ crc_table[byte ^ (crc >> 24)]; + return (crc << 8) ^ stbv_crc_table[byte ^ (crc >> 24)]; } // used in setup, and for huffman that doesn't go fast path -static unsigned int bit_reverse(unsigned int n) +static unsigned int stbv_bit_reverse(unsigned int n) { n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); @@ -1016,7 +985,7 @@ static unsigned int bit_reverse(unsigned int n) return (n >> 16) | (n << 16); } -static float square(float x) +static float stbv_square(float x) { return x*x; } @@ -1024,7 +993,7 @@ static float square(float x) // this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3 // as required by the specification. fast(?) implementation from stb.h // @OPTIMIZE: called multiple times per-packet with "constants"; move to setup -static int ilog(int32 n) +static int stbv_ilog(stbv_int32 n) { static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; @@ -1054,14 +1023,14 @@ static int ilog(int32 n) // these functions are only called at setup, and only a few times // per file -static float float32_unpack(uint32 x) +static float stbv_float32_unpack(stbv_uint32 x) { // from the specification - uint32 mantissa = x & 0x1fffff; - uint32 sign = x & 0x80000000; - uint32 exp = (x & 0x7fe00000) >> 21; + stbv_uint32 mantissa = x & 0x1fffff; + stbv_uint32 sign = x & 0x80000000; + stbv_uint32 exp = (x & 0x7fe00000) >> 21; double res = sign ? -(double)mantissa : (double)mantissa; - return (float) ldexp((float)res, (int)exp-788); + return (float) ldexp((float)res, exp-788); } @@ -1072,7 +1041,7 @@ static float float32_unpack(uint32 x) // vorbis allows a huffman table with non-sorted lengths. This // requires a more sophisticated construction, since symbols in // order do not map to huffman codes "in order". -static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values) +static void stbv_add_entry(StbvCodebook *c, stbv_uint32 huff_code, int symbol, int count, int len, stbv_uint32 *values) { if (!c->sparse) { c->codewords [symbol] = huff_code; @@ -1083,18 +1052,17 @@ static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int } } -static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) +static int stbv_compute_codewords(StbvCodebook *c, stbv_uint8 *len, int n, stbv_uint32 *values) { int i,k,m=0; - uint32 available[32]; + stbv_uint32 available[32]; memset(available, 0, sizeof(available)); // find the first entry for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; if (k == n) { assert(c->sorted_entries == 0); return TRUE; } - assert(len[k] < 32); // no error return required, code reading lens checks this // add to the list - add_entry(c, 0, k, m++, len[k], values); + stbv_add_entry(c, 0, k, m++, len[k], values); // add all available leaves for (i=1; i <= len[k]; ++i) available[i] = 1U << (32-i); @@ -1103,10 +1071,9 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) // could probably be combined (except the initial code is 0, // and I use 0 in available[] to mean 'empty') for (i=k+1; i < n; ++i) { - uint32 res; + stbv_uint32 res; int z = len[i], y; if (z == NO_CODE) continue; - assert(z < 32); // no error return required, code reading lens checks this // find lowest available leaf (should always be earliest, // which is what the specification calls for) // note that this property, and the fact we can never have @@ -1116,10 +1083,12 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) while (z > 0 && !available[z]) --z; if (z == 0) { return FALSE; } res = available[z]; + assert(z >= 0 && z < 32); available[z] = 0; - add_entry(c, bit_reverse(res), i, m++, len[i], values); - // propagate availability up the tree + stbv_add_entry(c, stbv_bit_reverse(res), i, m++, len[i], values); + // propogate availability up the tree if (z != len[i]) { + assert(len[i] >= 0 && len[i] < 32); for (y=len[i]; y > z; --y) { assert(available[y] == 0); available[y] = res + (1 << (32-y)); @@ -1131,10 +1100,10 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) // accelerated huffman table allows fast O(1) match of all symbols // of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH -static void compute_accelerated_huffman(Codebook *c) +static void stbv_compute_accelerated_huffman(StbvCodebook *c) { int i, len; - for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i) + for (i=0; i < STBV_FAST_HUFFMAN_TABLE_SIZE; ++i) c->fast_huffman[i] = -1; len = c->sparse ? c->sorted_entries : c->entries; @@ -1143,9 +1112,9 @@ static void compute_accelerated_huffman(Codebook *c) #endif for (i=0; i < len; ++i) { if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) { - uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; + stbv_uint32 z = c->sparse ? stbv_bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; // set table entries for all bit combinations in the higher bits - while (z < FAST_HUFFMAN_TABLE_SIZE) { + while (z < STBV_FAST_HUFFMAN_TABLE_SIZE) { c->fast_huffman[z] = i; z += 1 << c->codeword_lengths[i]; } @@ -1159,14 +1128,14 @@ static void compute_accelerated_huffman(Codebook *c) #define STBV_CDECL #endif -static int STBV_CDECL uint32_compare(const void *p, const void *q) +static int STBV_CDECL stbv_uint32_compare(const void *p, const void *q) { - uint32 x = * (uint32 *) p; - uint32 y = * (uint32 *) q; + stbv_uint32 x = * (stbv_uint32 *) p; + stbv_uint32 y = * (stbv_uint32 *) q; return x < y ? -1 : x > y; } -static int include_in_sort(Codebook *c, uint8 len) +static int stbv_include_in_sort(StbvCodebook *c, stbv_uint8 len) { if (c->sparse) { assert(len != NO_CODE); return TRUE; } if (len == NO_CODE) return FALSE; @@ -1176,7 +1145,7 @@ static int include_in_sort(Codebook *c, uint8 len) // if the fast table above doesn't work, we want to binary // search them... need to reverse the bits -static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) +static void stbv_compute_sorted_huffman(StbvCodebook *c, stbv_uint8 *lengths, stbv_uint32 *values) { int i, len; // build a list of all the entries @@ -1186,15 +1155,15 @@ static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) if (!c->sparse) { int k = 0; for (i=0; i < c->entries; ++i) - if (include_in_sort(c, lengths[i])) - c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); + if (stbv_include_in_sort(c, lengths[i])) + c->sorted_codewords[k++] = stbv_bit_reverse(c->codewords[i]); assert(k == c->sorted_entries); } else { for (i=0; i < c->sorted_entries; ++i) - c->sorted_codewords[i] = bit_reverse(c->codewords[i]); + c->sorted_codewords[i] = stbv_bit_reverse(c->codewords[i]); } - qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare); + qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), stbv_uint32_compare); c->sorted_codewords[c->sorted_entries] = 0xffffffff; len = c->sparse ? c->sorted_entries : c->entries; @@ -1205,8 +1174,8 @@ static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) // #1 requires extra storage, #2 is slow, #3 can use binary search! for (i=0; i < len; ++i) { int huff_len = c->sparse ? lengths[values[i]] : lengths[i]; - if (include_in_sort(c,huff_len)) { - uint32 code = bit_reverse(c->codewords[i]); + if (stbv_include_in_sort(c,huff_len)) { + stbv_uint32 code = stbv_bit_reverse(c->codewords[i]); int x=0, n=c->sorted_entries; while (n > 1) { // invariant: sc[x] <= code < sc[x+n] @@ -1230,28 +1199,26 @@ static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) } // only run while parsing the header (3 times) -static int vorbis_validate(uint8 *data) +static int stbv_vorbis_validate(stbv_uint8 *data) { - static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; + static stbv_uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; return memcmp(data, vorbis, 6) == 0; } // called from setup only, once per code book // (formula implied by specification) -static int lookup1_values(int entries, int dim) +static int stbv_lookup1_values(int entries, int dim) { int r = (int) floor(exp((float) log((float) entries) / dim)); if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; ++r; // floor() to avoid _ftol() when non-CRT - if (pow((float) r+1, dim) <= entries) - return -1; - if ((int) floor(pow((float) r, dim)) > entries) - return -1; + assert(pow((float) r+1, dim) > entries); + assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above return r; } // called twice per file -static void compute_twiddle_factors(int n, float *A, float *B, float *C) +static void stbv_compute_twiddle_factors(int n, float *A, float *B, float *C) { int n4 = n >> 2, n8 = n >> 3; int k,k2; @@ -1268,39 +1235,39 @@ static void compute_twiddle_factors(int n, float *A, float *B, float *C) } } -static void compute_window(int n, float *window) +static void stbv_compute_window(int n, float *window) { int n2 = n >> 1, i; for (i=0; i < n2; ++i) - window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); + window[i] = (float) sin(0.5 * M_PI * stbv_square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); } -static void compute_bitreverse(int n, uint16 *rev) +static void stbv_compute_bitreverse(int n, stbv_uint16 *rev) { - int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + int ld = stbv_ilog(n) - 1; // stbv_ilog is off-by-one from normal definitions int i, n8 = n >> 3; for (i=0; i < n8; ++i) - rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2; + rev[i] = (stbv_bit_reverse(i) >> (32-ld+3)) << 2; } -static int init_blocksize(vorb *f, int b, int n) +static int stbv_init_blocksize(stbv_vorb *f, int b, int n) { int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3; - f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2); - f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2); - f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4); - if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem); - compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); - f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2); - if (!f->window[b]) return error(f, VORBIS_outofmem); - compute_window(n, f->window[b]); - f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8); - if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem); - compute_bitreverse(n, f->bit_reverse[b]); + f->A[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n2); + f->B[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n2); + f->C[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n4); + if (!f->A[b] || !f->B[b] || !f->C[b]) return stbv_error(f, VORBIS_outofmem); + stbv_compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); + f->window[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n2); + if (!f->window[b]) return stbv_error(f, VORBIS_outofmem); + stbv_compute_window(n, f->window[b]); + f->stbv_bit_reverse[b] = (stbv_uint16 *) stbv_setup_malloc(f, sizeof(stbv_uint16) * n8); + if (!f->stbv_bit_reverse[b]) return stbv_error(f, VORBIS_outofmem); + stbv_compute_bitreverse(n, f->stbv_bit_reverse[b]); return TRUE; } -static void neighbors(uint16 *x, int n, int *plow, int *phigh) +static void stbv_neighbors(stbv_uint16 *x, int n, int *plow, int *phigh) { int low = -1; int high = 65536; @@ -1314,13 +1281,13 @@ static void neighbors(uint16 *x, int n, int *plow, int *phigh) // this has been repurposed so y is now the original index instead of y typedef struct { - uint16 x,id; -} stbv__floor_ordering; + stbv_uint16 x,id; +} stbv_floor_ordering; -static int STBV_CDECL point_compare(const void *p, const void *q) +static int STBV_CDECL stbv_point_compare(const void *p, const void *q) { - stbv__floor_ordering *a = (stbv__floor_ordering *) p; - stbv__floor_ordering *b = (stbv__floor_ordering *) q; + stbv_floor_ordering *a = (stbv_floor_ordering *) p; + stbv_floor_ordering *b = (stbv_floor_ordering *) q; return a->x < b->x ? -1 : a->x > b->x; } @@ -1329,14 +1296,14 @@ static int STBV_CDECL point_compare(const void *p, const void *q) #if defined(STB_VORBIS_NO_STDIO) - #define USE_MEMORY(z) TRUE + #define STBV_USE_MEMORY(z) TRUE #else - #define USE_MEMORY(z) ((z)->stream) + #define STBV_USE_MEMORY(z) ((z)->stream) #endif -static uint8 get8(vorb *z) +static stbv_uint8 stbv_get8(stbv_vorb *z) { - if (USE_MEMORY(z)) { + if (STBV_USE_MEMORY(z)) { if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; } return *z->stream++; } @@ -1350,26 +1317,26 @@ static uint8 get8(vorb *z) #endif } -static uint32 get32(vorb *f) +static stbv_uint32 stbv_get32(stbv_vorb *f) { - uint32 x; - x = get8(f); - x += get8(f) << 8; - x += get8(f) << 16; - x += (uint32) get8(f) << 24; + stbv_uint32 x; + x = stbv_get8(f); + x += stbv_get8(f) << 8; + x += stbv_get8(f) << 16; + x += (stbv_uint32) stbv_get8(f) << 24; return x; } -static int getn(vorb *z, uint8 *data, int n) +static int stbv_getn(stbv_vorb *z, stbv_uint8 *data, int n) { - if (USE_MEMORY(z)) { + if (STBV_USE_MEMORY(z)) { if (z->stream+n > z->stream_end) { z->eof = 1; return 0; } memcpy(data, z->stream, n); z->stream += n; return 1; } - #ifndef STB_VORBIS_NO_STDIO + #ifndef STB_VORBIS_NO_STDIO if (fread(data, n, 1, z->f) == 1) return 1; else { @@ -1379,9 +1346,9 @@ static int getn(vorb *z, uint8 *data, int n) #endif } -static void skip(vorb *z, int n) +static void stbv_skip(stbv_vorb *z, int n) { - if (USE_MEMORY(z)) { + if (STBV_USE_MEMORY(z)) { z->stream += n; if (z->stream >= z->stream_end) z->eof = 1; return; @@ -1394,13 +1361,13 @@ static void skip(vorb *z, int n) #endif } -static int set_file_offset(stb_vorbis *f, unsigned int loc) +static int stbv_set_file_offset(stb_vorbis *f, unsigned int loc) { #ifndef STB_VORBIS_NO_PUSHDATA_API if (f->push_mode) return 0; #endif f->eof = 0; - if (USE_MEMORY(f)) { + if (STBV_USE_MEMORY(f)) { if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) { f->stream = f->stream_end; f->eof = 1; @@ -1426,47 +1393,44 @@ static int set_file_offset(stb_vorbis *f, unsigned int loc) } -static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; +static stbv_uint8 stbv_ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; -static int capture_pattern(vorb *f) +static int stbv_capture_pattern(stbv_vorb *f) { - if (0x4f != get8(f)) return FALSE; - if (0x67 != get8(f)) return FALSE; - if (0x67 != get8(f)) return FALSE; - if (0x53 != get8(f)) return FALSE; + if (0x4f != stbv_get8(f)) return FALSE; + if (0x67 != stbv_get8(f)) return FALSE; + if (0x67 != stbv_get8(f)) return FALSE; + if (0x53 != stbv_get8(f)) return FALSE; return TRUE; } -#define PAGEFLAG_continued_packet 1 -#define PAGEFLAG_first_page 2 -#define PAGEFLAG_last_page 4 +#define STBV_PAGEFLAG_continued_packet 1 +#define STBV_PAGEFLAG_first_page 2 +#define STBV_PAGEFLAG_last_page 4 -static int start_page_no_capturepattern(vorb *f) +static int stbv_start_page_no_capturepattern(stbv_vorb *f) { - uint32 loc0,loc1,n; - if (f->first_decode && !IS_PUSH_MODE(f)) { - f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4; - } + stbv_uint32 loc0,loc1,n; // stream structure version - if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); + if (0 != stbv_get8(f)) return stbv_error(f, VORBIS_invalid_stream_structure_version); // header flag - f->page_flag = get8(f); + f->page_flag = stbv_get8(f); // absolute granule position - loc0 = get32(f); - loc1 = get32(f); + loc0 = stbv_get32(f); + loc1 = stbv_get32(f); // @TODO: validate loc0,loc1 as valid positions? // stream serial number -- vorbis doesn't interleave, so discard - get32(f); - //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number); + stbv_get32(f); + //if (f->serial != stbv_get32(f)) return stbv_error(f, VORBIS_incorrect_stream_serial_number); // page sequence number - n = get32(f); + n = stbv_get32(f); f->last_page = n; // CRC32 - get32(f); + stbv_get32(f); // page_segments - f->segment_count = get8(f); - if (!getn(f, f->segments, f->segment_count)) - return error(f, VORBIS_unexpected_eof); + f->segment_count = stbv_get8(f); + if (!stbv_getn(f, f->segments, f->segment_count)) + return stbv_error(f, VORBIS_unexpected_eof); // assume we _don't_ know any the sample position of any segments f->end_seg_with_known_loc = -2; if (loc0 != ~0U || loc1 != ~0U) { @@ -1483,29 +1447,32 @@ static int start_page_no_capturepattern(vorb *f) } if (f->first_decode) { int i,len; + StbvProbedPage p; len = 0; for (i=0; i < f->segment_count; ++i) len += f->segments[i]; len += 27 + f->segment_count; - f->p_first.page_end = f->p_first.page_start + len; - f->p_first.last_decoded_sample = loc0; + p.page_start = f->first_audio_page_offset; + p.page_end = p.page_start + len; + p.last_decoded_sample = loc0; + f->p_first = p; } f->next_seg = 0; return TRUE; } -static int start_page(vorb *f) +static int stbv_start_page(stbv_vorb *f) { - if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern); - return start_page_no_capturepattern(f); + if (!stbv_capture_pattern(f)) return stbv_error(f, VORBIS_missing_capture_pattern); + return stbv_start_page_no_capturepattern(f); } -static int start_packet(vorb *f) +static int stbv_start_packet(stbv_vorb *f) { while (f->next_seg == -1) { - if (!start_page(f)) return FALSE; - if (f->page_flag & PAGEFLAG_continued_packet) - return error(f, VORBIS_continued_packet_flag_invalid); + if (!stbv_start_page(f)) return FALSE; + if (f->page_flag & STBV_PAGEFLAG_continued_packet) + return stbv_error(f, VORBIS_continued_packet_flag_invalid); } f->last_seg = FALSE; f->valid_bits = 0; @@ -1515,35 +1482,35 @@ static int start_packet(vorb *f) return TRUE; } -static int maybe_start_packet(vorb *f) +static int stbv_maybe_start_packet(stbv_vorb *f) { if (f->next_seg == -1) { - int x = get8(f); + int x = stbv_get8(f); if (f->eof) return FALSE; // EOF at page boundary is not an error! - if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern); - if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); - if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); - if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern); - if (!start_page_no_capturepattern(f)) return FALSE; - if (f->page_flag & PAGEFLAG_continued_packet) { + if (0x4f != x ) return stbv_error(f, VORBIS_missing_capture_pattern); + if (0x67 != stbv_get8(f)) return stbv_error(f, VORBIS_missing_capture_pattern); + if (0x67 != stbv_get8(f)) return stbv_error(f, VORBIS_missing_capture_pattern); + if (0x53 != stbv_get8(f)) return stbv_error(f, VORBIS_missing_capture_pattern); + if (!stbv_start_page_no_capturepattern(f)) return FALSE; + if (f->page_flag & STBV_PAGEFLAG_continued_packet) { // set up enough state that we can read this packet if we want, // e.g. during recovery f->last_seg = FALSE; f->bytes_in_seg = 0; - return error(f, VORBIS_continued_packet_flag_invalid); + return stbv_error(f, VORBIS_continued_packet_flag_invalid); } } - return start_packet(f); + return stbv_start_packet(f); } -static int next_segment(vorb *f) +static int stbv_next_segment(stbv_vorb *f) { int len; if (f->last_seg) return 0; if (f->next_seg == -1) { - f->last_seg_which = f->segment_count-1; // in case start_page fails - if (!start_page(f)) { f->last_seg = 1; return 0; } - if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid); + f->last_seg_which = f->segment_count-1; // in case stbv_start_page fails + if (!stbv_start_page(f)) { f->last_seg = 1; return 0; } + if (!(f->page_flag & STBV_PAGEFLAG_continued_packet)) return stbv_error(f, VORBIS_continued_packet_flag_invalid); } len = f->segments[f->next_seg++]; if (len < 255) { @@ -1557,70 +1524,59 @@ static int next_segment(vorb *f) return len; } -#define EOP (-1) -#define INVALID_BITS (-1) +#define STBV_EOP (-1) +#define STBV_INVALID_BITS (-1) -static int get8_packet_raw(vorb *f) +static int stbv_get8_packet_raw(stbv_vorb *f) { if (!f->bytes_in_seg) { // CLANG! - if (f->last_seg) return EOP; - else if (!next_segment(f)) return EOP; + if (f->last_seg) return STBV_EOP; + else if (!stbv_next_segment(f)) return STBV_EOP; } assert(f->bytes_in_seg > 0); --f->bytes_in_seg; ++f->packet_bytes; - return get8(f); + return stbv_get8(f); } -static int get8_packet(vorb *f) +static int stbv_get8_packet(stbv_vorb *f) { - int x = get8_packet_raw(f); + int x = stbv_get8_packet_raw(f); f->valid_bits = 0; return x; } -static int get32_packet(vorb *f) +static void stbv_flush_packet(stbv_vorb *f) { - uint32 x; - x = get8_packet(f); - x += get8_packet(f) << 8; - x += get8_packet(f) << 16; - x += (uint32) get8_packet(f) << 24; - return x; -} - -static void flush_packet(vorb *f) -{ - while (get8_packet_raw(f) != EOP); + while (stbv_get8_packet_raw(f) != STBV_EOP); } // @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important // as the huffman decoder? -static uint32 get_bits(vorb *f, int n) +static stbv_uint32 stbv_get_bits(stbv_vorb *f, int n) { - uint32 z; + stbv_uint32 z; if (f->valid_bits < 0) return 0; if (f->valid_bits < n) { if (n > 24) { // the accumulator technique below would not work correctly in this case - z = get_bits(f, 24); - z += get_bits(f, n-24) << 24; + z = stbv_get_bits(f, 24); + z += stbv_get_bits(f, n-24) << 24; return z; } if (f->valid_bits == 0) f->acc = 0; while (f->valid_bits < n) { - int z = get8_packet_raw(f); - if (z == EOP) { - f->valid_bits = INVALID_BITS; + int z = stbv_get8_packet_raw(f); + if (z == STBV_EOP) { + f->valid_bits = STBV_INVALID_BITS; return 0; } f->acc += z << f->valid_bits; f->valid_bits += 8; } } - - assert(f->valid_bits >= n); + if (f->valid_bits < 0) return 0; z = f->acc & ((1 << n)-1); f->acc >>= n; f->valid_bits -= n; @@ -1631,15 +1587,15 @@ static uint32 get_bits(vorb *f, int n) // expand the buffer to as many bits as possible without reading off end of packet // it might be nice to allow f->valid_bits and f->acc to be stored in registers, // e.g. cache them locally and decode locally -static __forceinline void prep_huffman(vorb *f) +static __forceinline void stbv_prep_huffman(stbv_vorb *f) { if (f->valid_bits <= 24) { if (f->valid_bits == 0) f->acc = 0; do { int z; if (f->last_seg && !f->bytes_in_seg) return; - z = get8_packet_raw(f); - if (z == EOP) return; + z = stbv_get8_packet_raw(f); + if (z == STBV_EOP) return; f->acc += (unsigned) z << f->valid_bits; f->valid_bits += 8; } while (f->valid_bits <= 24); @@ -1648,15 +1604,15 @@ static __forceinline void prep_huffman(vorb *f) enum { - VORBIS_packet_id = 1, - VORBIS_packet_comment = 3, - VORBIS_packet_setup = 5 + STBV_VORBIS_packet_id = 1, + STBV_VORBIS_packet_comment = 3, + STBV_VORBIS_packet_setup = 5 }; -static int codebook_decode_scalar_raw(vorb *f, Codebook *c) +static int stbv_codebook_decode_scalar_raw(stbv_vorb *f, StbvCodebook *c) { int i; - prep_huffman(f); + stbv_prep_huffman(f); if (c->codewords == NULL && c->sorted_codewords == NULL) return -1; @@ -1665,7 +1621,7 @@ static int codebook_decode_scalar_raw(vorb *f, Codebook *c) // sorted_codewords && c->entries > 8 if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { // binary search - uint32 code = bit_reverse(f->acc); + stbv_uint32 code = stbv_bit_reverse(f->acc); int x=0, n=c->sorted_entries, len; while (n > 1) { @@ -1707,17 +1663,17 @@ static int codebook_decode_scalar_raw(vorb *f, Codebook *c) } } - error(f, VORBIS_invalid_stream); + stbv_error(f, VORBIS_invalid_stream); f->valid_bits = 0; return -1; } #ifndef STB_VORBIS_NO_INLINE_DECODE -#define DECODE_RAW(var, f,c) \ +#define STBV_DECODE_RAW(var, f,c) \ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \ - prep_huffman(f); \ - var = f->acc & FAST_HUFFMAN_TABLE_MASK; \ + stbv_prep_huffman(f); \ + var = f->acc & STBV_FAST_HUFFMAN_TABLE_MASK; \ var = c->fast_huffman[var]; \ if (var >= 0) { \ int n = c->codeword_lengths[var]; \ @@ -1725,18 +1681,18 @@ static int codebook_decode_scalar_raw(vorb *f, Codebook *c) f->valid_bits -= n; \ if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \ } else { \ - var = codebook_decode_scalar_raw(f,c); \ + var = stbv_codebook_decode_scalar_raw(f,c); \ } #else -static int codebook_decode_scalar(vorb *f, Codebook *c) +static int stbv_codebook_decode_scalar(stbv_vorb *f, StbvCodebook *c) { int i; if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) - prep_huffman(f); + stbv_prep_huffman(f); // fast huffman table lookup - i = f->acc & FAST_HUFFMAN_TABLE_MASK; + i = f->acc & STBV_FAST_HUFFMAN_TABLE_MASK; i = c->fast_huffman[i]; if (i >= 0) { f->acc >>= c->codeword_lengths[i]; @@ -1744,21 +1700,21 @@ static int codebook_decode_scalar(vorb *f, Codebook *c) if (f->valid_bits < 0) { f->valid_bits = 0; return -1; } return i; } - return codebook_decode_scalar_raw(f,c); + return stbv_codebook_decode_scalar_raw(f,c); } -#define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c); +#define STBV_DECODE_RAW(var,f,c) var = stbv_codebook_decode_scalar(f,c); #endif -#define DECODE(var,f,c) \ - DECODE_RAW(var,f,c) \ +#define STBV_DECODE(var,f,c) \ + STBV_DECODE_RAW(var,f,c) \ if (c->sparse) var = c->sorted_values[var]; #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c) + #define DECODE_VQ(var,f,c) STBV_DECODE_RAW(var,f,c) #else - #define DECODE_VQ(var,f,c) DECODE(var,f,c) + #define DECODE_VQ(var,f,c) STBV_DECODE(var,f,c) #endif @@ -1766,45 +1722,45 @@ static int codebook_decode_scalar(vorb *f, Codebook *c) -// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case +// STBV_CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case // where we avoid one addition -#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) -#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) -#define CODEBOOK_ELEMENT_BASE(c) (0) +#define STBV_CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) +#define STBV_CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) +#define STBV_CODEBOOK_ELEMENT_BASE(c) (0) -static int codebook_decode_start(vorb *f, Codebook *c) +static int stbv_codebook_decode_start(stbv_vorb *f, StbvCodebook *c) { int z = -1; // type 0 is only legal in a scalar context if (c->lookup_type == 0) - error(f, VORBIS_invalid_stream); + stbv_error(f, VORBIS_invalid_stream); else { DECODE_VQ(z,f,c); if (c->sparse) assert(z < c->sorted_entries); - if (z < 0) { // check for EOP + if (z < 0) { // check for STBV_EOP if (!f->bytes_in_seg) if (f->last_seg) return z; - error(f, VORBIS_invalid_stream); + stbv_error(f, VORBIS_invalid_stream); } } return z; } -static int codebook_decode(vorb *f, Codebook *c, float *output, int len) +static int stbv_codebook_decode(stbv_vorb *f, StbvCodebook *c, float *output, int len) { - int i,z = codebook_decode_start(f,c); + int i,z = stbv_codebook_decode_start(f,c); if (z < 0) return FALSE; if (len > c->dimensions) len = c->dimensions; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { - float last = CODEBOOK_ELEMENT_BASE(c); + float last = STBV_CODEBOOK_ELEMENT_BASE(c); int div = 1; for (i=0; i < len; ++i) { int off = (z / div) % c->lookup_values; - float val = CODEBOOK_ELEMENT_FAST(c,off) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,off) + last; output[i] += val; if (c->sequence_p) last = val + c->minimum_value; div *= c->lookup_values; @@ -1815,26 +1771,26 @@ static int codebook_decode(vorb *f, Codebook *c, float *output, int len) z *= c->dimensions; if (c->sequence_p) { - float last = CODEBOOK_ELEMENT_BASE(c); + float last = STBV_CODEBOOK_ELEMENT_BASE(c); for (i=0; i < len; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; output[i] += val; last = val + c->minimum_value; } } else { - float last = CODEBOOK_ELEMENT_BASE(c); + float last = STBV_CODEBOOK_ELEMENT_BASE(c); for (i=0; i < len; ++i) { - output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last; + output[i] += STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; } } return TRUE; } -static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step) +static int stbv_codebook_decode_step(stbv_vorb *f, StbvCodebook *c, float *output, int len, int step) { - int i,z = codebook_decode_start(f,c); - float last = CODEBOOK_ELEMENT_BASE(c); + int i,z = stbv_codebook_decode_start(f,c); + float last = STBV_CODEBOOK_ELEMENT_BASE(c); if (z < 0) return FALSE; if (len > c->dimensions) len = c->dimensions; @@ -1843,7 +1799,7 @@ static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, in int div = 1; for (i=0; i < len; ++i) { int off = (z / div) % c->lookup_values; - float val = CODEBOOK_ELEMENT_FAST(c,off) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,off) + last; output[i*step] += val; if (c->sequence_p) last = val; div *= c->lookup_values; @@ -1854,7 +1810,7 @@ static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, in z *= c->dimensions; for (i=0; i < len; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; output[i*step] += val; if (c->sequence_p) last = val; } @@ -1862,17 +1818,17 @@ static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, in return TRUE; } -static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) +static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) { int c_inter = *c_inter_p; int p_inter = *p_inter_p; int i,z, effective = c->dimensions; // type 0 is only legal in a scalar context - if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); + if (c->lookup_type == 0) return stbv_error(f, VORBIS_invalid_stream); while (total_decode > 0) { - float last = CODEBOOK_ELEMENT_BASE(c); + float last = STBV_CODEBOOK_ELEMENT_BASE(c); DECODE_VQ(z,f,c); #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK assert(!c->sparse || z < c->sorted_entries); @@ -1880,7 +1836,7 @@ static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **out if (z < 0) { if (!f->bytes_in_seg) if (f->last_seg) return FALSE; - return error(f, VORBIS_invalid_stream); + return stbv_error(f, VORBIS_invalid_stream); } // if this will take us off the end of the buffers, stop short! @@ -1896,7 +1852,7 @@ static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **out int div = 1; for (i=0; i < effective; ++i) { int off = (z / div) % c->lookup_values; - float val = CODEBOOK_ELEMENT_FAST(c,off) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,off) + last; if (outputs[c_inter]) outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } @@ -1909,7 +1865,7 @@ static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **out z *= c->dimensions; if (c->sequence_p) { for (i=0; i < effective; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; if (outputs[c_inter]) outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } @@ -1917,7 +1873,7 @@ static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **out } } else { for (i=0; i < effective; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; if (outputs[c_inter]) outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } @@ -1932,7 +1888,7 @@ static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **out return TRUE; } -static int predict_point(int x, int x0, int x1, int y0, int y1) +static int stbv_predict_point(int x, int x0, int x1, int y0, int y1) { int dy = y1 - y0; int adx = x1 - x0; @@ -1943,71 +1899,71 @@ static int predict_point(int x, int x0, int x1, int y0, int y1) } // the following table is block-copied from the specification -static float inverse_db_table[256] = +static float stbv_inverse_db_table[256] = { - 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, - 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, - 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, - 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, - 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, - 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, - 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, - 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, - 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, - 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, - 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, - 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, - 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, - 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, - 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, - 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, - 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, - 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, - 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, - 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, - 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, - 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, - 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, - 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, - 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, - 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, - 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, - 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, - 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, - 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, - 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, - 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, - 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, - 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, - 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, - 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, - 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, - 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, - 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, - 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, - 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, - 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, - 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, - 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, - 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, - 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, - 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, - 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, - 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, - 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, - 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, - 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, - 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, - 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, - 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, - 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, - 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, - 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, - 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, - 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, - 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, - 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, - 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, + 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, + 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, + 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, + 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, + 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, + 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, + 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, + 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, + 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, + 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, + 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, + 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, + 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, + 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, + 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, + 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, + 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, + 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, + 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, + 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, + 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, + 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, + 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, + 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, + 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, + 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, + 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, + 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, + 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, + 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, + 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, + 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, + 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, + 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, + 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, + 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, + 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, + 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, + 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, + 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, + 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, + 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, + 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, + 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, + 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, + 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, + 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, + 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, + 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, + 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, + 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, + 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, + 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, + 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, + 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, + 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, + 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, + 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, + 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, + 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, + 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, + 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, + 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, 0.82788260f, 0.88168307f, 0.9389798f, 1.0f }; @@ -2020,18 +1976,18 @@ static float inverse_db_table[256] = // ... also, isn't the whole point of Bresenham's algorithm to NOT // have to divide in the setup? sigh. #ifndef STB_VORBIS_NO_DEFER_FLOOR -#define LINE_OP(a,b) a *= b +#define STBV_LINE_OP(a,b) a *= b #else -#define LINE_OP(a,b) a = b +#define STBV_LINE_OP(a,b) a = b #endif #ifdef STB_VORBIS_DIVIDE_TABLE -#define DIVTAB_NUMER 32 -#define DIVTAB_DENOM 64 -int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB +#define STBV_DIVTAB_NUMER 32 +#define STBV_DIVTAB_DENOM 64 +stbv_int8 stbv_integer_divide_table[STBV_DIVTAB_NUMER][STBV_DIVTAB_DENOM]; // 2KB #endif -static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n) +static __forceinline void stbv_draw_line(float *output, int x0, int y0, int x1, int y1, int n) { int dy = y1 - y0; int adx = x1 - x0; @@ -2042,12 +1998,12 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y int sy; #ifdef STB_VORBIS_DIVIDE_TABLE - if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) { + if (adx < STBV_DIVTAB_DENOM && ady < STBV_DIVTAB_NUMER) { if (dy < 0) { - base = -integer_divide_table[ady][adx]; + base = -stbv_integer_divide_table[ady][adx]; sy = base-1; } else { - base = integer_divide_table[ady][adx]; + base = stbv_integer_divide_table[ady][adx]; sy = base+1; } } else { @@ -2067,7 +2023,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y ady -= abs(base) * adx; if (x1 > n) x1 = n; if (x < x1) { - LINE_OP(output[x], inverse_db_table[y&255]); + STBV_LINE_OP(output[x], stbv_inverse_db_table[y]); for (++x; x < x1; ++x) { err += ady; if (err >= adx) { @@ -2075,22 +2031,22 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y y += sy; } else y += base; - LINE_OP(output[x], inverse_db_table[y&255]); + STBV_LINE_OP(output[x], stbv_inverse_db_table[y]); } } } -static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype) +static int stbv_residue_decode(stbv_vorb *f, StbvCodebook *book, float *target, int offset, int n, int rtype) { int k; if (rtype == 0) { int step = n / book->dimensions; for (k=0; k < step; ++k) - if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) + if (!stbv_codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) return FALSE; } else { for (k=0; k < n; ) { - if (!codebook_decode(f, book, target+offset, n-k)) + if (!stbv_codebook_decode(f, book, target+offset, n-k)) return FALSE; k += book->dimensions; offset += book->dimensions; @@ -2101,10 +2057,10 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in // n is 1/2 of the blocksize -- // specification: "Correct per-vector decode length is [n]/2" -static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) +static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, int n, int rn, stbv_uint8 *do_not_decode) { int i,j,pass; - Residue *r = f->residue_config + rn; + StbvResidue *r = f->residue_config + rn; int rtype = f->residue_types[rn]; int c = r->classbook; int classwords = f->codebooks[c].dimensions; @@ -2113,14 +2069,14 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size); int n_read = limit_r_end - limit_r_begin; int part_read = n_read / r->part_size; - int temp_alloc_point = temp_alloc_save(f); + int temp_alloc_point = stbv_temp_alloc_save(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); + stbv_uint8 ***part_classdata = (stbv_uint8 ***) stbv_temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); #else - int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); + int **classifications = (int **) stbv_temp_block_array(f,f->channels, part_read * sizeof(**classifications)); #endif - CHECK(f); + STBV_CHECK(f); for (i=0; i < ch; ++i) if (!do_not_decode[i]) @@ -2140,10 +2096,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int int z = r->begin + pcount*r->part_size; int c_inter = (z & 1), p_inter = z>>1; if (pass == 0) { - Codebook *c = f->codebooks+r->classbook; + StbvCodebook *c = f->codebooks+r->classbook; int q; - DECODE(q,f,c); - if (q == EOP) goto done; + STBV_DECODE(q,f,c); + if (q == STBV_EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else @@ -2162,13 +2118,13 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int #endif int b = r->residue_books[c][pass]; if (b >= 0) { - Codebook *book = f->codebooks + b; + StbvCodebook *book = f->codebooks + b; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK - if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; #else // saves 1% - if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; #endif } else { @@ -2181,15 +2137,15 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int ++class_set; #endif } - } else if (ch > 2) { + } else if (ch == 1) { while (pcount < part_read) { int z = r->begin + pcount*r->part_size; - int c_inter = z % ch, p_inter = z/ch; + int c_inter = 0, p_inter = z; if (pass == 0) { - Codebook *c = f->codebooks+r->classbook; + StbvCodebook *c = f->codebooks+r->classbook; int q; - DECODE(q,f,c); - if (q == EOP) goto done; + STBV_DECODE(q,f,c); + if (q == STBV_EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else @@ -2208,8 +2164,48 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int #endif int b = r->residue_books[c][pass]; if (b >= 0) { - Codebook *book = f->codebooks + b; - if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + StbvCodebook *book = f->codebooks + b; + if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + goto done; + } else { + z += r->part_size; + c_inter = 0; + p_inter = z; + } + } + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; + #endif + } + } else { + while (pcount < part_read) { + int z = r->begin + pcount*r->part_size; + int c_inter = z % ch, p_inter = z/ch; + if (pass == 0) { + StbvCodebook *c = f->codebooks+r->classbook; + int q; + STBV_DECODE(q,f,c); + if (q == STBV_EOP) goto done; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[0][class_set] = r->classdata[q]; + #else + for (i=classwords-1; i >= 0; --i) { + classifications[0][i+pcount] = q % r->classifications; + q /= r->classifications; + } + #endif + } + for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { + int z = r->begin + pcount*r->part_size; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[0][class_set][i]; + #else + int c = classifications[0][pcount]; + #endif + int b = r->residue_books[c][pass]; + if (b >= 0) { + StbvCodebook *book = f->codebooks + b; + if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; } else { z += r->part_size; @@ -2225,7 +2221,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int } goto done; } - CHECK(f); + STBV_CHECK(f); for (pass=0; pass < 8; ++pass) { int pcount = 0, class_set=0; @@ -2233,10 +2229,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int if (pass == 0) { for (j=0; j < ch; ++j) { if (!do_not_decode[j]) { - Codebook *c = f->codebooks+r->classbook; + StbvCodebook *c = f->codebooks+r->classbook; int temp; - DECODE(temp,f,c); - if (temp == EOP) goto done; + STBV_DECODE(temp,f,c); + if (temp == STBV_EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[j][class_set] = r->classdata[temp]; #else @@ -2261,8 +2257,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int float *target = residue_buffers[j]; int offset = r->begin + pcount * r->part_size; int n = r->part_size; - Codebook *book = f->codebooks + b; - if (!residue_decode(f, book, target, offset, n, rtype)) + StbvCodebook *book = f->codebooks + b; + if (!stbv_residue_decode(f, book, target, offset, n, rtype)) goto done; } } @@ -2274,13 +2270,13 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int } } done: - CHECK(f); + STBV_CHECK(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - temp_free(f,part_classdata); + stbv_temp_free(f,part_classdata); #else - temp_free(f,classifications); + stbv_temp_free(f,classifications); #endif - temp_alloc_restore(f,temp_alloc_point); + stbv_temp_alloc_restore(f,temp_alloc_point); } @@ -2309,7 +2305,7 @@ void inverse_mdct_slow(float *buffer, int n) } #elif 0 // same as above, but just barely able to run in real time on modern machines -void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) +void inverse_mdct_slow(float *buffer, int n, stbv_vorb *f, int blocktype) { float mcos[16384]; int i,j; @@ -2347,7 +2343,7 @@ void dct_iv_slow(float *buffer, int n) } } -void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) +void inverse_mdct_slow(float *buffer, int n, stbv_vorb *f, int blocktype) { int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4; float temp[4096]; @@ -2368,11 +2364,11 @@ void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) #if LIBVORBIS_MDCT // directly call the vorbis MDCT using an interface documented // by Jeff Roberts... useful for performance comparison -typedef struct +typedef struct { int n; int log2n; - + float *trig; int *bitrev; @@ -2385,13 +2381,13 @@ extern void mdct_backward(mdct_lookup *init, float *in, float *out); mdct_lookup M1,M2; -void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) +void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) { mdct_lookup *M; if (M1.n == n) M = &M1; else if (M2.n == n) M = &M2; else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; } - else { + else { if (M2.n) __asm int 3; mdct_init(&M2, n); M = &M2; @@ -2405,7 +2401,7 @@ void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) // the following were split out into separate functions while optimizing; // they could be pushed back up but eh. __forceinline showed no change; // they're probably already being inlined. -static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) +static void stbv_imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) { float *ee0 = e + i_off; float *ee2 = ee0 + k_off; @@ -2450,7 +2446,7 @@ static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float } } -static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) +static void stbv_imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) { int i; float k00_20, k01_21; @@ -2500,7 +2496,7 @@ static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float } } -static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) +static void stbv_imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) { int i; float A0 = A[0]; @@ -2551,7 +2547,7 @@ static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, floa } } -static __forceinline void iter_54(float *z) +static __forceinline void stbv_iter_54(float *z) { float k00,k11,k22,k33; float y0,y1,y2,y3; @@ -2583,7 +2579,7 @@ static __forceinline void iter_54(float *z) z[-7] = k11 + k22; // z1 - z5 - z2 + z6 } -static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) +static void stbv_imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) { int a_off = base_n >> 3; float A2 = A[0+a_off]; @@ -2592,47 +2588,48 @@ static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, while (z > base) { float k00,k11; - float l00,l11; - k00 = z[-0] - z[ -8]; - k11 = z[-1] - z[ -9]; - l00 = z[-2] - z[-10]; - l11 = z[-3] - z[-11]; - z[ -0] = z[-0] + z[ -8]; - z[ -1] = z[-1] + z[ -9]; - z[ -2] = z[-2] + z[-10]; - z[ -3] = z[-3] + z[-11]; - z[ -8] = k00; - z[ -9] = k11; - z[-10] = (l00+l11) * A2; - z[-11] = (l11-l00) * A2; + k00 = z[-0] - z[-8]; + k11 = z[-1] - z[-9]; + z[-0] = z[-0] + z[-8]; + z[-1] = z[-1] + z[-9]; + z[-8] = k00; + z[-9] = k11 ; - k00 = z[ -4] - z[-12]; + k00 = z[ -2] - z[-10]; + k11 = z[ -3] - z[-11]; + z[ -2] = z[ -2] + z[-10]; + z[ -3] = z[ -3] + z[-11]; + z[-10] = (k00+k11) * A2; + z[-11] = (k11-k00) * A2; + + k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation k11 = z[ -5] - z[-13]; - l00 = z[ -6] - z[-14]; - l11 = z[ -7] - z[-15]; z[ -4] = z[ -4] + z[-12]; z[ -5] = z[ -5] + z[-13]; + z[-12] = k11; + z[-13] = k00; + + k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation + k11 = z[ -7] - z[-15]; z[ -6] = z[ -6] + z[-14]; z[ -7] = z[ -7] + z[-15]; - z[-12] = k11; - z[-13] = -k00; - z[-14] = (l11-l00) * A2; - z[-15] = (l00+l11) * -A2; + z[-14] = (k00+k11) * A2; + z[-15] = (k00-k11) * A2; - iter_54(z); - iter_54(z-8); + stbv_iter_54(z); + stbv_iter_54(z-8); z -= 16; } } -static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) +static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) { int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; int ld; // @OPTIMIZE: reduce register pressure by using fewer variables? - int save_point = temp_alloc_save(f); - float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2)); + int save_point = stbv_temp_alloc_save(f); + float *buf2 = (float *) stbv_temp_alloc(f, n2 * sizeof(*buf2)); float *u=NULL,*v=NULL; // twiddle factors float *A = f->A[blocktype]; @@ -2653,7 +2650,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) // once I combined the passes. // so there's a missing 'times 2' here (for adding X to itself). - // this propagates through linearly to the end, where the numbers + // this propogates through linearly to the end, where the numbers // are 1/2 too small, and need to be compensated for. { @@ -2727,7 +2724,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) } // step 3 - ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + ld = stbv_ilog(n) - 1; // stbv_ilog is off-by-one from normal definitions // optimized step 3: @@ -2737,14 +2734,14 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) // switch between them halfway. // this is iteration 0 of step 3 - imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); - imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); + stbv_imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); + stbv_imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); // this is iteration 1 of step 3 - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); + stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); + stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); + stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); + stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); l=2; for (; l < (ld-3)>>1; ++l) { @@ -2752,7 +2749,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) int lim = 1 << (l+1); int i; for (i=0; i < lim; ++i) - imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); + stbv_imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); } for (; l < ld-6; ++l) { @@ -2763,7 +2760,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) float *A0 = A; i_off = n2-1; for (r=rlim; r > 0; --r) { - imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); + stbv_imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); A0 += k1*4; i_off -= 8; } @@ -2774,14 +2771,14 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) // the big win comes from getting rid of needless flops // due to the constants on pass 5 & 4 being all 1 and 0; // combining them to be simultaneous to improve cache made little difference - imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); + stbv_imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); // output is u // step 4, 5, and 6 // cannot be in-place because of step 5 { - uint16 *bitrev = f->bit_reverse[blocktype]; + stbv_uint16 *bitrev = f->stbv_bit_reverse[blocktype]; // weirdly, I'd have thought reading sequentially and writing // erratically would have been better than vice-versa, but in // fact that's not what my testing showed. (That is, with @@ -2803,7 +2800,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) d1[0] = u[k4+1]; d0[1] = u[k4+2]; d0[0] = u[k4+3]; - + d0 -= 4; d1 -= 4; bitrev += 2; @@ -2884,7 +2881,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) float p0,p1,p2,p3; p3 = e[6]*B[7] - e[7]*B[6]; - p2 = -e[6]*B[6] - e[7]*B[7]; + p2 = -e[6]*B[6] - e[7]*B[7]; d0[0] = p3; d1[3] = - p3; @@ -2892,7 +2889,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) d3[3] = p2; p1 = e[4]*B[5] - e[5]*B[4]; - p0 = -e[4]*B[4] - e[5]*B[5]; + p0 = -e[4]*B[4] - e[5]*B[5]; d0[1] = p1; d1[2] = - p1; @@ -2900,7 +2897,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) d3[2] = p0; p3 = e[2]*B[3] - e[3]*B[2]; - p2 = -e[2]*B[2] - e[3]*B[3]; + p2 = -e[2]*B[2] - e[3]*B[3]; d0[2] = p3; d1[1] = - p3; @@ -2908,7 +2905,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) d3[1] = p2; p1 = e[0]*B[1] - e[1]*B[0]; - p0 = -e[0]*B[0] - e[1]*B[1]; + p0 = -e[0]*B[0] - e[1]*B[1]; d0[3] = p1; d1[0] = - p1; @@ -2924,8 +2921,8 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) } } - temp_free(f,buf2); - temp_alloc_restore(f,save_point); + stbv_temp_free(f,buf2); + stbv_temp_alloc_restore(f,save_point); } #if 0 @@ -2976,7 +2973,7 @@ void inverse_mdct_naive(float *buffer, int n) w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4]; } // step 3 - ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + ld = stbv_ilog(n) - 1; // stbv_ilog is off-by-one from normal definitions for (l=0; l < ld-3; ++l) { int k0 = n >> (l+2), k1 = 1 << (l+3); int rlim = n >> (l+4), r4, r; @@ -2999,7 +2996,7 @@ void inverse_mdct_naive(float *buffer, int n) // step 4 for (i=0; i < n8; ++i) { - int j = bit_reverse(i) >> (32-ld+3); + int j = stbv_bit_reverse(i) >> (32-ld+3); assert(j < n8); if (i == j) { // paper bug: original code probably swapped in place; if copying, @@ -3056,34 +3053,34 @@ void inverse_mdct_naive(float *buffer, int n) } #endif -static float *get_window(vorb *f, int len) +static float *stbv_get_window(stbv_vorb *f, int len) { len <<= 1; if (len == f->blocksize_0) return f->window[0]; if (len == f->blocksize_1) return f->window[1]; + assert(0); return NULL; } #ifndef STB_VORBIS_NO_DEFER_FLOOR -typedef int16 YTYPE; +typedef stbv_int16 STBV_YTYPE; #else -typedef int YTYPE; +typedef int STBV_YTYPE; #endif -static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag) +static int stbv_do_floor(stbv_vorb *f, StbvMapping *map, int i, int n, float *target, STBV_YTYPE *finalY, stbv_uint8 *step2_flag) { int n2 = n >> 1; int s = map->chan[i].mux, floor; floor = map->submap_floor[s]; if (f->floor_types[floor] == 0) { - return error(f, VORBIS_invalid_stream); + return stbv_error(f, VORBIS_invalid_stream); } else { - Floor1 *g = &f->floor_config[floor].floor1; + StbvFloor1 *g = &f->floor_config[floor].floor1; int j,q; int lx = 0, ly = finalY[0] * g->floor1_multiplier; for (q=1; q < g->values; ++q) { j = g->sorted_order[q]; #ifndef STB_VORBIS_NO_DEFER_FLOOR - STBV_NOTUSED(step2_flag); if (finalY[j] >= 0) #else if (step2_flag[j]) @@ -3092,16 +3089,16 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f int hy = finalY[j] * g->floor1_multiplier; int hx = g->Xlist[j]; if (lx != hx) - draw_line(target, lx,ly, hx,hy, n2); - CHECK(f); + stbv_draw_line(target, lx,ly, hx,hy, n2); + STBV_CHECK(f); lx = hx, ly = hy; } } if (lx < n2) { - // optimization of: draw_line(target, lx,ly, n,ly, n2); + // optimization of: stbv_draw_line(target, lx,ly, n,ly, n2); for (j=lx; j < n2; ++j) - LINE_OP(target[j], inverse_db_table[ly]); - CHECK(f); + STBV_LINE_OP(target[j], stbv_inverse_db_table[ly]); + STBV_CHECK(f); } } return TRUE; @@ -3121,36 +3118,36 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f // has to be the same as frame N+1's left_end-left_start (which they are by // construction) -static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +static int stbv_vorbis_decode_initial(stbv_vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) { - Mode *m; + StbvMode *m; int i, n, prev, next, window_center; f->channel_buffer_start = f->channel_buffer_end = 0; retry: if (f->eof) return FALSE; - if (!maybe_start_packet(f)) + if (!stbv_maybe_start_packet(f)) return FALSE; // check packet type - if (get_bits(f,1) != 0) { - if (IS_PUSH_MODE(f)) - return error(f,VORBIS_bad_packet_type); - while (EOP != get8_packet(f)); + if (stbv_get_bits(f,1) != 0) { + if (STBV_IS_PUSH_MODE(f)) + return stbv_error(f,VORBIS_bad_packet_type); + while (STBV_EOP != stbv_get8_packet(f)); goto retry; } if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - i = get_bits(f, ilog(f->mode_count-1)); - if (i == EOP) return FALSE; + i = stbv_get_bits(f, stbv_ilog(f->mode_count-1)); + if (i == STBV_EOP) return FALSE; if (i >= f->mode_count) return FALSE; *mode = i; m = f->mode_config + i; if (m->blockflag) { n = f->blocksize_1; - prev = get_bits(f,1); - next = get_bits(f,1); + prev = stbv_get_bits(f,1); + next = stbv_get_bits(f,1); } else { prev = next = 0; n = f->blocksize_0; @@ -3177,41 +3174,40 @@ static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, in return TRUE; } -static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) +static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) { - Mapping *map; + StbvMapping *map; int i,j,k,n,n2; int zero_channel[256]; int really_zero_channel[256]; // WINDOWING - STBV_NOTUSED(left_end); n = f->blocksize[m->blockflag]; map = &f->mapping[m->mapping]; // FLOORS n2 = n >> 1; - CHECK(f); + STBV_CHECK(f); for (i=0; i < f->channels; ++i) { int s = map->chan[i].mux, floor; zero_channel[i] = FALSE; floor = map->submap_floor[s]; if (f->floor_types[floor] == 0) { - return error(f, VORBIS_invalid_stream); + return stbv_error(f, VORBIS_invalid_stream); } else { - Floor1 *g = &f->floor_config[floor].floor1; - if (get_bits(f, 1)) { + StbvFloor1 *g = &f->floor_config[floor].floor1; + if (stbv_get_bits(f, 1)) { short *finalY; - uint8 step2_flag[256]; + stbv_uint8 step2_flag[256]; static int range_list[4] = { 256, 128, 86, 64 }; int range = range_list[g->floor1_multiplier-1]; int offset = 2; finalY = f->finalY[i]; - finalY[0] = get_bits(f, ilog(range)-1); - finalY[1] = get_bits(f, ilog(range)-1); + finalY[0] = stbv_get_bits(f, stbv_ilog(range)-1); + finalY[1] = stbv_get_bits(f, stbv_ilog(range)-1); for (j=0; j < g->partitions; ++j) { int pclass = g->partition_class_list[j]; int cdim = g->class_dimensions[pclass]; @@ -3219,29 +3215,29 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int csub = (1 << cbits)-1; int cval = 0; if (cbits) { - Codebook *c = f->codebooks + g->class_masterbooks[pclass]; - DECODE(cval,f,c); + StbvCodebook *c = f->codebooks + g->class_masterbooks[pclass]; + STBV_DECODE(cval,f,c); } for (k=0; k < cdim; ++k) { int book = g->subclass_books[pclass][cval & csub]; cval = cval >> cbits; if (book >= 0) { int temp; - Codebook *c = f->codebooks + book; - DECODE(temp,f,c); + StbvCodebook *c = f->codebooks + book; + STBV_DECODE(temp,f,c); finalY[offset++] = temp; } else finalY[offset++] = 0; } } - if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec + if (f->valid_bits == STBV_INVALID_BITS) goto error; // behavior according to spec step2_flag[0] = step2_flag[1] = 1; for (j=2; j < g->values; ++j) { int low, high, pred, highroom, lowroom, room, val; - low = g->neighbors[j][0]; - high = g->neighbors[j][1]; - //neighbors(g->Xlist, j, &low, &high); - pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); + low = g->stbv_neighbors[j][0]; + high = g->stbv_neighbors[j][1]; + //stbv_neighbors(g->Xlist, j, &low, &high); + pred = stbv_predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); val = finalY[j]; highroom = range - pred; lowroom = pred; @@ -3269,7 +3265,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, } #ifdef STB_VORBIS_NO_DEFER_FLOOR - do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); + stbv_do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); #else // defer final floor computation until _after_ residue for (j=0; j < g->values; ++j) { @@ -3286,7 +3282,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, // at this point we've decoded the floor into buffer } } - CHECK(f); + STBV_CHECK(f); // at this point we've decoded all floors if (f->alloc.alloc_buffer) @@ -3299,12 +3295,12 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; } - CHECK(f); -// RESIDUE DECODE + STBV_CHECK(f); +// RESIDUE STBV_DECODE for (i=0; i < map->submaps; ++i) { float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; int r; - uint8 do_not_decode[256]; + stbv_uint8 do_not_decode[256]; int ch = 0; for (j=0; j < f->channels; ++j) { if (map->chan[j].mux == i) { @@ -3319,12 +3315,12 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, } } r = map->submap_residue[i]; - decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); + stbv_decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); } if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - CHECK(f); + STBV_CHECK(f); // INVERSE COUPLING for (i = map->coupling_steps-1; i >= 0; --i) { @@ -3347,7 +3343,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, a[j] = a2; } } - CHECK(f); + STBV_CHECK(f); // finish decoding the floors #ifndef STB_VORBIS_NO_DEFER_FLOOR @@ -3355,7 +3351,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, if (really_zero_channel[i]) { memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); } else { - do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); + stbv_do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); } } #else @@ -3370,21 +3366,21 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, #endif // INVERSE MDCT - CHECK(f); + STBV_CHECK(f); for (i=0; i < f->channels; ++i) - inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); - CHECK(f); + stbv_inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); + STBV_CHECK(f); // this shouldn't be necessary, unless we exited on an error // and want to flush to get to the next packet - flush_packet(f); + stbv_flush_packet(f); if (f->first_decode) { // assume we start so first non-discarded sample is sample 0 // this isn't to spec, but spec would require us to read ahead // and decode the size of all current frames--could be done, // but presumably it's not a commonly used feature - f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around) + f->current_loc = -n2; // start of first frame is positioned for discard // we might have to discard samples "from" the next frame too, // if we're lapping a large block then a small at the start? f->discard_samples_deferred = n - right_end; @@ -3412,8 +3408,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, // check if we have ogg information about the sample # for this packet if (f->last_seg_which == f->end_seg_with_known_loc) { // if we have a valid current loc, and this is final: - if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { - uint32 current_end = f->known_loc_for_packet; + if (f->current_loc_valid && (f->page_flag & STBV_PAGEFLAG_last_page)) { + stbv_uint32 current_end = f->known_loc_for_packet; // then let's infer the size of the (probably) short final frame if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc) { @@ -3441,19 +3437,19 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); *len = right_end; // ignore samples after the window goes to 0 - CHECK(f); + STBV_CHECK(f); return TRUE; } -static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right) +static int stbv_vorbis_decode_packet(stbv_vorb *f, int *len, int *p_left, int *p_right) { int mode, left_end, right_end; - if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; - return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); + if (!stbv_vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; + return stbv_vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); } -static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) +static int stbv_vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) { int prev,i,j; // we use right&left (the start of the right- and left-window sin()-regions) @@ -3467,8 +3463,7 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) // mixin from previous window if (f->previous_length) { int i,j, n = f->previous_length; - float *w = get_window(f, n); - if (w == NULL) return 0; + float *w = stbv_get_window(f, n); for (i=0; i < f->channels; ++i) { for (j=0; j < n; ++j) f->channel_buffers[i][left+j] = @@ -3506,28 +3501,28 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) return right - left; } -static int vorbis_pump_first_frame(stb_vorbis *f) +static int stbv_vorbis_pump_first_frame(stb_vorbis *f) { int len, right, left, res; - res = vorbis_decode_packet(f, &len, &left, &right); + res = stbv_vorbis_decode_packet(f, &len, &left, &right); if (res) - vorbis_finish_frame(f, len, left, right); + stbv_vorbis_finish_frame(f, len, left, right); return res; } #ifndef STB_VORBIS_NO_PUSHDATA_API -static int is_whole_packet_present(stb_vorbis *f) +static int stbv_is_whole_packet_present(stb_vorbis *f, int end_page) { // make sure that we have the packet available before continuing... // this requires a full ogg parse, but we know we can fetch from f->stream // instead of coding this out explicitly, we could save the current read state, - // read the next packet with get8() until end-of-packet, check f->eof, then + // read the next packet with stbv_get8() until end-of-packet, check f->eof, then // reset the state? but that would be slower, esp. since we'd have over 256 bytes // of state to restore (primarily the page segment table) int s = f->next_seg, first = TRUE; - uint8 *p = f->stream; + stbv_uint8 *p = f->stream; if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag for (; s < f->segment_count; ++s) { @@ -3536,166 +3531,112 @@ static int is_whole_packet_present(stb_vorbis *f) break; } // either this continues, or it ends it... + if (end_page) + if (s < f->segment_count-1) return stbv_error(f, VORBIS_invalid_stream); if (s == f->segment_count) s = -1; // set 'crosses page' flag - if (p > f->stream_end) return error(f, VORBIS_need_more_data); + if (p > f->stream_end) return stbv_error(f, VORBIS_need_more_data); first = FALSE; } for (; s == -1;) { - uint8 *q; + stbv_uint8 *q; int n; // check that we have the page header ready - if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data); + if (p + 26 >= f->stream_end) return stbv_error(f, VORBIS_need_more_data); // validate the page - if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream); - if (p[4] != 0) return error(f, VORBIS_invalid_stream); + if (memcmp(p, stbv_ogg_page_header, 4)) return stbv_error(f, VORBIS_invalid_stream); + if (p[4] != 0) return stbv_error(f, VORBIS_invalid_stream); if (first) { // the first segment must NOT have 'continued_packet', later ones MUST if (f->previous_length) - if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); + if ((p[5] & STBV_PAGEFLAG_continued_packet)) return stbv_error(f, VORBIS_invalid_stream); // if no previous length, we're resynching, so we can come in on a continued-packet, // which we'll just drop } else { - if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); + if (!(p[5] & STBV_PAGEFLAG_continued_packet)) return stbv_error(f, VORBIS_invalid_stream); } n = p[26]; // segment counts q = p+27; // q points to segment table p = q + n; // advance past header // make sure we've read the segment table - if (p > f->stream_end) return error(f, VORBIS_need_more_data); + if (p > f->stream_end) return stbv_error(f, VORBIS_need_more_data); for (s=0; s < n; ++s) { p += q[s]; if (q[s] < 255) break; } + if (end_page) + if (s < n-1) return stbv_error(f, VORBIS_invalid_stream); if (s == n) s = -1; // set 'crosses page' flag - if (p > f->stream_end) return error(f, VORBIS_need_more_data); + if (p > f->stream_end) return stbv_error(f, VORBIS_need_more_data); first = FALSE; } return TRUE; } #endif // !STB_VORBIS_NO_PUSHDATA_API -static int start_decoder(vorb *f) +static int stbv_start_decoder(stbv_vorb *f) { - uint8 header[6], x,y; + stbv_uint8 header[6], x,y; int len,i,j,k, max_submaps = 0; int longest_floorlist=0; // first page, first packet - f->first_decode = TRUE; - if (!start_page(f)) return FALSE; + if (!stbv_start_page(f)) return FALSE; // validate page flag - if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page); - if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page); - if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); + if (!(f->page_flag & STBV_PAGEFLAG_first_page)) return stbv_error(f, VORBIS_invalid_first_page); + if (f->page_flag & STBV_PAGEFLAG_last_page) return stbv_error(f, VORBIS_invalid_first_page); + if (f->page_flag & STBV_PAGEFLAG_continued_packet) return stbv_error(f, VORBIS_invalid_first_page); // check for expected packet length - if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); - if (f->segments[0] != 30) { - // check for the Ogg skeleton fishead identifying header to refine our error - if (f->segments[0] == 64 && - getn(f, header, 6) && - header[0] == 'f' && - header[1] == 'i' && - header[2] == 's' && - header[3] == 'h' && - header[4] == 'e' && - header[5] == 'a' && - get8(f) == 'd' && - get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported); - else - return error(f, VORBIS_invalid_first_page); - } - + if (f->segment_count != 1) return stbv_error(f, VORBIS_invalid_first_page); + if (f->segments[0] != 30) return stbv_error(f, VORBIS_invalid_first_page); // read packet // check packet header - if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); - if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof); - if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page); + if (stbv_get8(f) != STBV_VORBIS_packet_id) return stbv_error(f, VORBIS_invalid_first_page); + if (!stbv_getn(f, header, 6)) return stbv_error(f, VORBIS_unexpected_eof); + if (!stbv_vorbis_validate(header)) return stbv_error(f, VORBIS_invalid_first_page); // vorbis_version - if (get32(f) != 0) return error(f, VORBIS_invalid_first_page); - f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page); - if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels); - f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page); - get32(f); // bitrate_maximum - get32(f); // bitrate_nominal - get32(f); // bitrate_minimum - x = get8(f); + if (stbv_get32(f) != 0) return stbv_error(f, VORBIS_invalid_first_page); + f->channels = stbv_get8(f); if (!f->channels) return stbv_error(f, VORBIS_invalid_first_page); + if (f->channels > STB_VORBIS_MAX_CHANNELS) return stbv_error(f, VORBIS_too_many_channels); + f->sample_rate = stbv_get32(f); if (!f->sample_rate) return stbv_error(f, VORBIS_invalid_first_page); + stbv_get32(f); // bitrate_maximum + stbv_get32(f); // bitrate_nominal + stbv_get32(f); // bitrate_minimum + x = stbv_get8(f); { int log0,log1; log0 = x & 15; log1 = x >> 4; f->blocksize_0 = 1 << log0; f->blocksize_1 = 1 << log1; - if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); - if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); - if (log0 > log1) return error(f, VORBIS_invalid_setup); + if (log0 < 6 || log0 > 13) return stbv_error(f, VORBIS_invalid_setup); + if (log1 < 6 || log1 > 13) return stbv_error(f, VORBIS_invalid_setup); + if (log0 > log1) return stbv_error(f, VORBIS_invalid_setup); } // framing_flag - x = get8(f); - if (!(x & 1)) return error(f, VORBIS_invalid_first_page); + x = stbv_get8(f); + if (!(x & 1)) return stbv_error(f, VORBIS_invalid_first_page); // second packet! - if (!start_page(f)) return FALSE; - - if (!start_packet(f)) return FALSE; - - if (!next_segment(f)) return FALSE; - - if (get8_packet(f) != VORBIS_packet_comment) return error(f, VORBIS_invalid_setup); - for (i=0; i < 6; ++i) header[i] = get8_packet(f); - if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); - //file vendor - len = get32_packet(f); - f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1)); - if (f->vendor == NULL) return error(f, VORBIS_outofmem); - for(i=0; i < len; ++i) { - f->vendor[i] = get8_packet(f); - } - f->vendor[len] = (char)'\0'; - //user comments - f->comment_list_length = get32_packet(f); - f->comment_list = NULL; - if (f->comment_list_length > 0) - { - f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length)); - if (f->comment_list == NULL) return error(f, VORBIS_outofmem); - } - - for(i=0; i < f->comment_list_length; ++i) { - len = get32_packet(f); - f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1)); - if (f->comment_list[i] == NULL) return error(f, VORBIS_outofmem); - - for(j=0; j < len; ++j) { - f->comment_list[i][j] = get8_packet(f); - } - f->comment_list[i][len] = (char)'\0'; - } - - // framing_flag - x = get8_packet(f); - if (!(x & 1)) return error(f, VORBIS_invalid_setup); - - - skip(f, f->bytes_in_seg); - f->bytes_in_seg = 0; + if (!stbv_start_page(f)) return FALSE; + if (!stbv_start_packet(f)) return FALSE; do { - len = next_segment(f); - skip(f, len); + len = stbv_next_segment(f); + stbv_skip(f, len); f->bytes_in_seg = 0; } while (len); // third packet! - if (!start_packet(f)) return FALSE; + if (!stbv_start_packet(f)) return FALSE; #ifndef STB_VORBIS_NO_PUSHDATA_API - if (IS_PUSH_MODE(f)) { - if (!is_whole_packet_present(f)) { + if (STBV_IS_PUSH_MODE(f)) { + if (!stbv_is_whole_packet_present(f, TRUE)) { // convert error in ogg header to write type if (f->error == VORBIS_invalid_stream) f->error = VORBIS_invalid_setup; @@ -3704,65 +3645,64 @@ static int start_decoder(vorb *f) } #endif - crc32_init(); // always init it, to avoid multithread race conditions + stbv_crc32_init(); // always init it, to avoid multithread race conditions - if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup); - for (i=0; i < 6; ++i) header[i] = get8_packet(f); - if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); + if (stbv_get8_packet(f) != STBV_VORBIS_packet_setup) return stbv_error(f, VORBIS_invalid_setup); + for (i=0; i < 6; ++i) header[i] = stbv_get8_packet(f); + if (!stbv_vorbis_validate(header)) return stbv_error(f, VORBIS_invalid_setup); // codebooks - f->codebook_count = get_bits(f,8) + 1; - f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); - if (f->codebooks == NULL) return error(f, VORBIS_outofmem); + f->codebook_count = stbv_get_bits(f,8) + 1; + f->codebooks = (StbvCodebook *) stbv_setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); + if (f->codebooks == NULL) return stbv_error(f, VORBIS_outofmem); memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count); for (i=0; i < f->codebook_count; ++i) { - uint32 *values; + stbv_uint32 *values; int ordered, sorted_count; int total=0; - uint8 *lengths; - Codebook *c = f->codebooks+i; - CHECK(f); - x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); - x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); - x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); - x = get_bits(f, 8); - c->dimensions = (get_bits(f, 8)<<8) + x; - x = get_bits(f, 8); - y = get_bits(f, 8); - c->entries = (get_bits(f, 8)<<16) + (y<<8) + x; - ordered = get_bits(f,1); - c->sparse = ordered ? 0 : get_bits(f,1); + stbv_uint8 *lengths; + StbvCodebook *c = f->codebooks+i; + STBV_CHECK(f); + x = stbv_get_bits(f, 8); if (x != 0x42) return stbv_error(f, VORBIS_invalid_setup); + x = stbv_get_bits(f, 8); if (x != 0x43) return stbv_error(f, VORBIS_invalid_setup); + x = stbv_get_bits(f, 8); if (x != 0x56) return stbv_error(f, VORBIS_invalid_setup); + x = stbv_get_bits(f, 8); + c->dimensions = (stbv_get_bits(f, 8)<<8) + x; + x = stbv_get_bits(f, 8); + y = stbv_get_bits(f, 8); + c->entries = (stbv_get_bits(f, 8)<<16) + (y<<8) + x; + ordered = stbv_get_bits(f,1); + c->sparse = ordered ? 0 : stbv_get_bits(f,1); - if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup); + if (c->dimensions == 0 && c->entries != 0) return stbv_error(f, VORBIS_invalid_setup); if (c->sparse) - lengths = (uint8 *) setup_temp_malloc(f, c->entries); + lengths = (stbv_uint8 *) stbv_setup_temp_malloc(f, c->entries); else - lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); + lengths = c->codeword_lengths = (stbv_uint8 *) stbv_setup_malloc(f, c->entries); - if (!lengths) return error(f, VORBIS_outofmem); + if (!lengths) return stbv_error(f, VORBIS_outofmem); if (ordered) { int current_entry = 0; - int current_length = get_bits(f,5) + 1; + int current_length = stbv_get_bits(f,5) + 1; while (current_entry < c->entries) { int limit = c->entries - current_entry; - int n = get_bits(f, ilog(limit)); - if (current_length >= 32) return error(f, VORBIS_invalid_setup); - if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } + int n = stbv_get_bits(f, stbv_ilog(limit)); + if (current_entry + n > (int) c->entries) { return stbv_error(f, VORBIS_invalid_setup); } memset(lengths + current_entry, current_length, n); current_entry += n; ++current_length; } } else { for (j=0; j < c->entries; ++j) { - int present = c->sparse ? get_bits(f,1) : 1; + int present = c->sparse ? stbv_get_bits(f,1) : 1; if (present) { - lengths[j] = get_bits(f, 5) + 1; + lengths[j] = stbv_get_bits(f, 5) + 1; ++total; if (lengths[j] == 32) - return error(f, VORBIS_invalid_setup); + return stbv_error(f, VORBIS_invalid_setup); } else { lengths[j] = NO_CODE; } @@ -3774,10 +3714,10 @@ static int start_decoder(vorb *f) if (c->entries > (int) f->setup_temp_memory_required) f->setup_temp_memory_required = c->entries; - c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); - if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem); + c->codeword_lengths = (stbv_uint8 *) stbv_setup_malloc(f, c->entries); + if (c->codeword_lengths == NULL) return stbv_error(f, VORBIS_outofmem); memcpy(c->codeword_lengths, lengths, c->entries); - setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! + stbv_setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! lengths = c->codeword_lengths; c->sparse = 0; } @@ -3797,74 +3737,72 @@ static int start_decoder(vorb *f) c->sorted_entries = sorted_count; values = NULL; - CHECK(f); + STBV_CHECK(f); if (!c->sparse) { - c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); - if (!c->codewords) return error(f, VORBIS_outofmem); + c->codewords = (stbv_uint32 *) stbv_setup_malloc(f, sizeof(c->codewords[0]) * c->entries); + if (!c->codewords) return stbv_error(f, VORBIS_outofmem); } else { unsigned int size; if (c->sorted_entries) { - c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries); - if (!c->codeword_lengths) return error(f, VORBIS_outofmem); - c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); - if (!c->codewords) return error(f, VORBIS_outofmem); - values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); - if (!values) return error(f, VORBIS_outofmem); + c->codeword_lengths = (stbv_uint8 *) stbv_setup_malloc(f, c->sorted_entries); + if (!c->codeword_lengths) return stbv_error(f, VORBIS_outofmem); + c->codewords = (stbv_uint32 *) stbv_setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); + if (!c->codewords) return stbv_error(f, VORBIS_outofmem); + values = (stbv_uint32 *) stbv_setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); + if (!values) return stbv_error(f, VORBIS_outofmem); } size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries; if (size > f->setup_temp_memory_required) f->setup_temp_memory_required = size; } - if (!compute_codewords(c, lengths, c->entries, values)) { - if (c->sparse) setup_temp_free(f, values, 0); - return error(f, VORBIS_invalid_setup); + if (!stbv_compute_codewords(c, lengths, c->entries, values)) { + if (c->sparse) stbv_setup_temp_free(f, values, 0); + return stbv_error(f, VORBIS_invalid_setup); } if (c->sorted_entries) { // allocate an extra slot for sentinels - c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); - if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem); + c->sorted_codewords = (stbv_uint32 *) stbv_setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); + if (c->sorted_codewords == NULL) return stbv_error(f, VORBIS_outofmem); // allocate an extra slot at the front so that c->sorted_values[-1] is defined // so that we can catch that case without an extra if - c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); - if (c->sorted_values == NULL) return error(f, VORBIS_outofmem); + c->sorted_values = ( int *) stbv_setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); + if (c->sorted_values == NULL) return stbv_error(f, VORBIS_outofmem); ++c->sorted_values; c->sorted_values[-1] = -1; - compute_sorted_huffman(c, lengths, values); + stbv_compute_sorted_huffman(c, lengths, values); } if (c->sparse) { - setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); - setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); - setup_temp_free(f, lengths, c->entries); + stbv_setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); + stbv_setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); + stbv_setup_temp_free(f, lengths, c->entries); c->codewords = NULL; } - compute_accelerated_huffman(c); + stbv_compute_accelerated_huffman(c); - CHECK(f); - c->lookup_type = get_bits(f, 4); - if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); + STBV_CHECK(f); + c->lookup_type = stbv_get_bits(f, 4); + if (c->lookup_type > 2) return stbv_error(f, VORBIS_invalid_setup); if (c->lookup_type > 0) { - uint16 *mults; - c->minimum_value = float32_unpack(get_bits(f, 32)); - c->delta_value = float32_unpack(get_bits(f, 32)); - c->value_bits = get_bits(f, 4)+1; - c->sequence_p = get_bits(f,1); + stbv_uint16 *mults; + c->minimum_value = stbv_float32_unpack(stbv_get_bits(f, 32)); + c->delta_value = stbv_float32_unpack(stbv_get_bits(f, 32)); + c->value_bits = stbv_get_bits(f, 4)+1; + c->sequence_p = stbv_get_bits(f,1); if (c->lookup_type == 1) { - int values = lookup1_values(c->entries, c->dimensions); - if (values < 0) return error(f, VORBIS_invalid_setup); - c->lookup_values = (uint32) values; + c->lookup_values = stbv_lookup1_values(c->entries, c->dimensions); } else { c->lookup_values = c->entries * c->dimensions; } - if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup); - mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); - if (mults == NULL) return error(f, VORBIS_outofmem); + if (c->lookup_values == 0) return stbv_error(f, VORBIS_invalid_setup); + mults = (stbv_uint16 *) stbv_setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); + if (mults == NULL) return stbv_error(f, VORBIS_outofmem); for (j=0; j < (int) c->lookup_values; ++j) { - int q = get_bits(f, c->value_bits); - if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); } + int q = stbv_get_bits(f, c->value_bits); + if (q == STBV_EOP) { stbv_setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return stbv_error(f, VORBIS_invalid_setup); } mults[j] = q; } @@ -3874,25 +3812,26 @@ static int start_decoder(vorb *f) float last=0; // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop if (sparse) { - if (c->sorted_entries == 0) goto skip; - c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); + if (c->sorted_entries == 0) goto stbv_skip; + c->multiplicands = (stbv_codetype *) stbv_setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); } else - c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); - if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } + c->multiplicands = (stbv_codetype *) stbv_setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); + if (c->multiplicands == NULL) { stbv_setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return stbv_error(f, VORBIS_outofmem); } len = sparse ? c->sorted_entries : c->entries; for (j=0; j < len; ++j) { unsigned int z = sparse ? c->sorted_values[j] : j; unsigned int div=1; for (k=0; k < c->dimensions; ++k) { int off = (z / div) % c->lookup_values; - float val = mults[off]*c->delta_value + c->minimum_value + last; + float val = mults[off]; + val = mults[off]*c->delta_value + c->minimum_value + last; c->multiplicands[j*c->dimensions + k] = val; if (c->sequence_p) last = val; if (k+1 < c->dimensions) { if (div > UINT_MAX / (unsigned int) c->lookup_values) { - setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); - return error(f, VORBIS_invalid_setup); + stbv_setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); + return stbv_error(f, VORBIS_invalid_setup); } div *= c->lookup_values; } @@ -3904,9 +3843,9 @@ static int start_decoder(vorb *f) #endif { float last=0; - CHECK(f); - c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); - if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } + STBV_CHECK(f); + c->multiplicands = (stbv_codetype *) stbv_setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); + if (c->multiplicands == NULL) { stbv_setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return stbv_error(f, VORBIS_outofmem); } for (j=0; j < (int) c->lookup_values; ++j) { float val = mults[j] * c->delta_value + c->minimum_value + last; c->multiplicands[j] = val; @@ -3915,72 +3854,72 @@ static int start_decoder(vorb *f) } } #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - skip:; + stbv_skip:; #endif - setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values); + stbv_setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values); - CHECK(f); + STBV_CHECK(f); } - CHECK(f); + STBV_CHECK(f); } // time domain transfers (notused) - x = get_bits(f, 6) + 1; + x = stbv_get_bits(f, 6) + 1; for (i=0; i < x; ++i) { - uint32 z = get_bits(f, 16); - if (z != 0) return error(f, VORBIS_invalid_setup); + stbv_uint32 z = stbv_get_bits(f, 16); + if (z != 0) return stbv_error(f, VORBIS_invalid_setup); } // Floors - f->floor_count = get_bits(f, 6)+1; - f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); - if (f->floor_config == NULL) return error(f, VORBIS_outofmem); + f->floor_count = stbv_get_bits(f, 6)+1; + f->floor_config = (StbvFloor *) stbv_setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); + if (f->floor_config == NULL) return stbv_error(f, VORBIS_outofmem); for (i=0; i < f->floor_count; ++i) { - f->floor_types[i] = get_bits(f, 16); - if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup); + f->floor_types[i] = stbv_get_bits(f, 16); + if (f->floor_types[i] > 1) return stbv_error(f, VORBIS_invalid_setup); if (f->floor_types[i] == 0) { - Floor0 *g = &f->floor_config[i].floor0; - g->order = get_bits(f,8); - g->rate = get_bits(f,16); - g->bark_map_size = get_bits(f,16); - g->amplitude_bits = get_bits(f,6); - g->amplitude_offset = get_bits(f,8); - g->number_of_books = get_bits(f,4) + 1; + StbvFloor0 *g = &f->floor_config[i].floor0; + g->order = stbv_get_bits(f,8); + g->rate = stbv_get_bits(f,16); + g->bark_map_size = stbv_get_bits(f,16); + g->amplitude_bits = stbv_get_bits(f,6); + g->amplitude_offset = stbv_get_bits(f,8); + g->number_of_books = stbv_get_bits(f,4) + 1; for (j=0; j < g->number_of_books; ++j) - g->book_list[j] = get_bits(f,8); - return error(f, VORBIS_feature_not_supported); + g->book_list[j] = stbv_get_bits(f,8); + return stbv_error(f, VORBIS_feature_not_supported); } else { - stbv__floor_ordering p[31*8+2]; - Floor1 *g = &f->floor_config[i].floor1; - int max_class = -1; - g->partitions = get_bits(f, 5); + stbv_floor_ordering p[31*8+2]; + StbvFloor1 *g = &f->floor_config[i].floor1; + int max_class = -1; + g->partitions = stbv_get_bits(f, 5); for (j=0; j < g->partitions; ++j) { - g->partition_class_list[j] = get_bits(f, 4); + g->partition_class_list[j] = stbv_get_bits(f, 4); if (g->partition_class_list[j] > max_class) max_class = g->partition_class_list[j]; } for (j=0; j <= max_class; ++j) { - g->class_dimensions[j] = get_bits(f, 3)+1; - g->class_subclasses[j] = get_bits(f, 2); + g->class_dimensions[j] = stbv_get_bits(f, 3)+1; + g->class_subclasses[j] = stbv_get_bits(f, 2); if (g->class_subclasses[j]) { - g->class_masterbooks[j] = get_bits(f, 8); - if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + g->class_masterbooks[j] = stbv_get_bits(f, 8); + if (g->class_masterbooks[j] >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); } for (k=0; k < 1 << g->class_subclasses[j]; ++k) { - g->subclass_books[j][k] = (int16)get_bits(f,8)-1; - if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + g->subclass_books[j][k] = stbv_get_bits(f,8)-1; + if (g->subclass_books[j][k] >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); } } - g->floor1_multiplier = get_bits(f,2)+1; - g->rangebits = get_bits(f,4); + g->floor1_multiplier = stbv_get_bits(f,2)+1; + g->rangebits = stbv_get_bits(f,4); g->Xlist[0] = 0; g->Xlist[1] = 1 << g->rangebits; g->values = 2; for (j=0; j < g->partitions; ++j) { int c = g->partition_class_list[j]; for (k=0; k < g->class_dimensions[c]; ++k) { - g->Xlist[g->values] = get_bits(f, g->rangebits); + g->Xlist[g->values] = stbv_get_bits(f, g->rangebits); ++g->values; } } @@ -3989,18 +3928,15 @@ static int start_decoder(vorb *f) p[j].x = g->Xlist[j]; p[j].id = j; } - qsort(p, g->values, sizeof(p[0]), point_compare); - for (j=0; j < g->values-1; ++j) - if (p[j].x == p[j+1].x) - return error(f, VORBIS_invalid_setup); + qsort(p, g->values, sizeof(p[0]), stbv_point_compare); for (j=0; j < g->values; ++j) - g->sorted_order[j] = (uint8) p[j].id; - // precompute the neighbors + g->sorted_order[j] = (stbv_uint8) p[j].id; + // precompute the stbv_neighbors for (j=2; j < g->values; ++j) { - int low = 0,hi = 0; - neighbors(g->Xlist, j, &low,&hi); - g->neighbors[j][0] = low; - g->neighbors[j][1] = hi; + int low,hi; + stbv_neighbors(g->Xlist, j, &low,&hi); + g->stbv_neighbors[j][0] = low; + g->stbv_neighbors[j][1] = hi; } if (g->values > longest_floorlist) @@ -4008,37 +3944,37 @@ static int start_decoder(vorb *f) } } - // Residue - f->residue_count = get_bits(f, 6)+1; - f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); - if (f->residue_config == NULL) return error(f, VORBIS_outofmem); + // StbvResidue + f->residue_count = stbv_get_bits(f, 6)+1; + f->residue_config = (StbvResidue *) stbv_setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); + if (f->residue_config == NULL) return stbv_error(f, VORBIS_outofmem); memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0])); for (i=0; i < f->residue_count; ++i) { - uint8 residue_cascade[64]; - Residue *r = f->residue_config+i; - f->residue_types[i] = get_bits(f, 16); - if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); - r->begin = get_bits(f, 24); - r->end = get_bits(f, 24); - if (r->end < r->begin) return error(f, VORBIS_invalid_setup); - r->part_size = get_bits(f,24)+1; - r->classifications = get_bits(f,6)+1; - r->classbook = get_bits(f,8); - if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup); + stbv_uint8 residue_cascade[64]; + StbvResidue *r = f->residue_config+i; + f->residue_types[i] = stbv_get_bits(f, 16); + if (f->residue_types[i] > 2) return stbv_error(f, VORBIS_invalid_setup); + r->begin = stbv_get_bits(f, 24); + r->end = stbv_get_bits(f, 24); + if (r->end < r->begin) return stbv_error(f, VORBIS_invalid_setup); + r->part_size = stbv_get_bits(f,24)+1; + r->classifications = stbv_get_bits(f,6)+1; + r->classbook = stbv_get_bits(f,8); + if (r->classbook >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); for (j=0; j < r->classifications; ++j) { - uint8 high_bits=0; - uint8 low_bits=get_bits(f,3); - if (get_bits(f,1)) - high_bits = get_bits(f,5); + stbv_uint8 high_bits=0; + stbv_uint8 low_bits=stbv_get_bits(f,3); + if (stbv_get_bits(f,1)) + high_bits = stbv_get_bits(f,5); residue_cascade[j] = high_bits*8 + low_bits; } - r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); - if (r->residue_books == NULL) return error(f, VORBIS_outofmem); + r->residue_books = (short (*)[8]) stbv_setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); + if (r->residue_books == NULL) return stbv_error(f, VORBIS_outofmem); for (j=0; j < r->classifications; ++j) { for (k=0; k < 8; ++k) { if (residue_cascade[j] & (1 << k)) { - r->residue_books[j][k] = get_bits(f, 8); - if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + r->residue_books[j][k] = stbv_get_bits(f, 8); + if (r->residue_books[j][k] >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); } else { r->residue_books[j][k] = -1; } @@ -4046,14 +3982,14 @@ static int start_decoder(vorb *f) } // precompute the classifications[] array to avoid inner-loop mod/divide // call it 'classdata' since we already have r->classifications - r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); - if (!r->classdata) return error(f, VORBIS_outofmem); + r->classdata = (stbv_uint8 **) stbv_setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); + if (!r->classdata) return stbv_error(f, VORBIS_outofmem); memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); for (j=0; j < f->codebooks[r->classbook].entries; ++j) { int classwords = f->codebooks[r->classbook].dimensions; int temp = j; - r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); - if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem); + r->classdata[j] = (stbv_uint8 *) stbv_setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); + if (r->classdata[j] == NULL) return stbv_error(f, VORBIS_outofmem); for (k=classwords-1; k >= 0; --k) { r->classdata[j][k] = temp % r->classifications; temp /= r->classifications; @@ -4061,41 +3997,40 @@ static int start_decoder(vorb *f) } } - f->mapping_count = get_bits(f,6)+1; - f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); - if (f->mapping == NULL) return error(f, VORBIS_outofmem); + f->mapping_count = stbv_get_bits(f,6)+1; + f->mapping = (StbvMapping *) stbv_setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); + if (f->mapping == NULL) return stbv_error(f, VORBIS_outofmem); memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping)); for (i=0; i < f->mapping_count; ++i) { - Mapping *m = f->mapping + i; - int mapping_type = get_bits(f,16); - if (mapping_type != 0) return error(f, VORBIS_invalid_setup); - m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan)); - if (m->chan == NULL) return error(f, VORBIS_outofmem); - if (get_bits(f,1)) - m->submaps = get_bits(f,4)+1; + StbvMapping *m = f->mapping + i; + int mapping_type = stbv_get_bits(f,16); + if (mapping_type != 0) return stbv_error(f, VORBIS_invalid_setup); + m->chan = (StbvMappingChannel *) stbv_setup_malloc(f, f->channels * sizeof(*m->chan)); + if (m->chan == NULL) return stbv_error(f, VORBIS_outofmem); + if (stbv_get_bits(f,1)) + m->submaps = stbv_get_bits(f,4)+1; else m->submaps = 1; if (m->submaps > max_submaps) max_submaps = m->submaps; - if (get_bits(f,1)) { - m->coupling_steps = get_bits(f,8)+1; - if (m->coupling_steps > f->channels) return error(f, VORBIS_invalid_setup); + if (stbv_get_bits(f,1)) { + m->coupling_steps = stbv_get_bits(f,8)+1; for (k=0; k < m->coupling_steps; ++k) { - m->chan[k].magnitude = get_bits(f, ilog(f->channels-1)); - m->chan[k].angle = get_bits(f, ilog(f->channels-1)); - if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup); - if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup); - if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup); + m->chan[k].magnitude = stbv_get_bits(f, stbv_ilog(f->channels-1)); + m->chan[k].angle = stbv_get_bits(f, stbv_ilog(f->channels-1)); + if (m->chan[k].magnitude >= f->channels) return stbv_error(f, VORBIS_invalid_setup); + if (m->chan[k].angle >= f->channels) return stbv_error(f, VORBIS_invalid_setup); + if (m->chan[k].magnitude == m->chan[k].angle) return stbv_error(f, VORBIS_invalid_setup); } } else m->coupling_steps = 0; // reserved field - if (get_bits(f,2)) return error(f, VORBIS_invalid_setup); + if (stbv_get_bits(f,2)) return stbv_error(f, VORBIS_invalid_setup); if (m->submaps > 1) { for (j=0; j < f->channels; ++j) { - m->chan[j].mux = get_bits(f, 4); - if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup); + m->chan[j].mux = stbv_get_bits(f, 4); + if (m->chan[j].mux >= m->submaps) return stbv_error(f, VORBIS_invalid_setup); } } else // @SPECIFICATION: this case is missing from the spec @@ -4103,64 +4038,64 @@ static int start_decoder(vorb *f) m->chan[j].mux = 0; for (j=0; j < m->submaps; ++j) { - get_bits(f,8); // discard - m->submap_floor[j] = get_bits(f,8); - m->submap_residue[j] = get_bits(f,8); - if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup); - if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup); + stbv_get_bits(f,8); // discard + m->submap_floor[j] = stbv_get_bits(f,8); + m->submap_residue[j] = stbv_get_bits(f,8); + if (m->submap_floor[j] >= f->floor_count) return stbv_error(f, VORBIS_invalid_setup); + if (m->submap_residue[j] >= f->residue_count) return stbv_error(f, VORBIS_invalid_setup); } } // Modes - f->mode_count = get_bits(f, 6)+1; + f->mode_count = stbv_get_bits(f, 6)+1; for (i=0; i < f->mode_count; ++i) { - Mode *m = f->mode_config+i; - m->blockflag = get_bits(f,1); - m->windowtype = get_bits(f,16); - m->transformtype = get_bits(f,16); - m->mapping = get_bits(f,8); - if (m->windowtype != 0) return error(f, VORBIS_invalid_setup); - if (m->transformtype != 0) return error(f, VORBIS_invalid_setup); - if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup); + StbvMode *m = f->mode_config+i; + m->blockflag = stbv_get_bits(f,1); + m->windowtype = stbv_get_bits(f,16); + m->transformtype = stbv_get_bits(f,16); + m->mapping = stbv_get_bits(f,8); + if (m->windowtype != 0) return stbv_error(f, VORBIS_invalid_setup); + if (m->transformtype != 0) return stbv_error(f, VORBIS_invalid_setup); + if (m->mapping >= f->mapping_count) return stbv_error(f, VORBIS_invalid_setup); } - flush_packet(f); + stbv_flush_packet(f); f->previous_length = 0; for (i=0; i < f->channels; ++i) { - f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1); - f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); - f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); - if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); + f->channel_buffers[i] = (float *) stbv_setup_malloc(f, sizeof(float) * f->blocksize_1); + f->previous_window[i] = (float *) stbv_setup_malloc(f, sizeof(float) * f->blocksize_1/2); + f->finalY[i] = (stbv_int16 *) stbv_setup_malloc(f, sizeof(stbv_int16) * longest_floorlist); + if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return stbv_error(f, VORBIS_outofmem); memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1); #ifdef STB_VORBIS_NO_DEFER_FLOOR - f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); - if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); + f->floor_buffers[i] = (float *) stbv_setup_malloc(f, sizeof(float) * f->blocksize_1/2); + if (f->floor_buffers[i] == NULL) return stbv_error(f, VORBIS_outofmem); #endif } - if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE; - if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE; + if (!stbv_init_blocksize(f, 0, f->blocksize_0)) return FALSE; + if (!stbv_init_blocksize(f, 1, f->blocksize_1)) return FALSE; f->blocksize[0] = f->blocksize_0; f->blocksize[1] = f->blocksize_1; #ifdef STB_VORBIS_DIVIDE_TABLE - if (integer_divide_table[1][1]==0) - for (i=0; i < DIVTAB_NUMER; ++i) - for (j=1; j < DIVTAB_DENOM; ++j) - integer_divide_table[i][j] = i / j; + if (stbv_integer_divide_table[1][1]==0) + for (i=0; i < STBV_DIVTAB_NUMER; ++i) + for (j=1; j < STBV_DIVTAB_DENOM; ++j) + stbv_integer_divide_table[i][j] = i / j; #endif // compute how much temporary memory is needed // 1. { - uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); - uint32 classify_mem; + stbv_uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); + stbv_uint32 classify_mem; int i,max_part_read=0; for (i=0; i < f->residue_count; ++i) { - Residue *r = f->residue_config + i; + StbvResidue *r = f->residue_config + i; unsigned int actual_size = f->blocksize_1 / 2; unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size; unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size; @@ -4170,7 +4105,7 @@ static int start_decoder(vorb *f) max_part_read = part_read; } #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *)); + classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(stbv_uint8 *)); #else classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); #endif @@ -4182,105 +4117,89 @@ static int start_decoder(vorb *f) f->temp_memory_required = imdct_mem; } + f->first_decode = TRUE; if (f->alloc.alloc_buffer) { assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); // check if there's enough temp memory so we don't error later if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset) - return error(f, VORBIS_outofmem); + return stbv_error(f, VORBIS_outofmem); } - // @TODO: stb_vorbis_seek_start expects first_audio_page_offset to point to a page - // without PAGEFLAG_continued_packet, so this either points to the first page, or - // the page after the end of the headers. It might be cleaner to point to a page - // in the middle of the headers, when that's the page where the first audio packet - // starts, but we'd have to also correctly skip the end of any continued packet in - // stb_vorbis_seek_start. - if (f->next_seg == -1) { - f->first_audio_page_offset = stb_vorbis_get_file_offset(f); - } else { - f->first_audio_page_offset = 0; - } + f->first_audio_page_offset = stb_vorbis_get_file_offset(f); return TRUE; } -static void vorbis_deinit(stb_vorbis *p) +static void stbv_vorbis_deinit(stb_vorbis *p) { int i,j; - - setup_free(p, p->vendor); - for (i=0; i < p->comment_list_length; ++i) { - setup_free(p, p->comment_list[i]); - } - setup_free(p, p->comment_list); - if (p->residue_config) { for (i=0; i < p->residue_count; ++i) { - Residue *r = p->residue_config+i; + StbvResidue *r = p->residue_config+i; if (r->classdata) { for (j=0; j < p->codebooks[r->classbook].entries; ++j) - setup_free(p, r->classdata[j]); - setup_free(p, r->classdata); + stbv_setup_free(p, r->classdata[j]); + stbv_setup_free(p, r->classdata); } - setup_free(p, r->residue_books); + stbv_setup_free(p, r->residue_books); } } if (p->codebooks) { - CHECK(p); + STBV_CHECK(p); for (i=0; i < p->codebook_count; ++i) { - Codebook *c = p->codebooks + i; - setup_free(p, c->codeword_lengths); - setup_free(p, c->multiplicands); - setup_free(p, c->codewords); - setup_free(p, c->sorted_codewords); + StbvCodebook *c = p->codebooks + i; + stbv_setup_free(p, c->codeword_lengths); + stbv_setup_free(p, c->multiplicands); + stbv_setup_free(p, c->codewords); + stbv_setup_free(p, c->sorted_codewords); // c->sorted_values[-1] is the first entry in the array - setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); + stbv_setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); } - setup_free(p, p->codebooks); + stbv_setup_free(p, p->codebooks); } - setup_free(p, p->floor_config); - setup_free(p, p->residue_config); + stbv_setup_free(p, p->floor_config); + stbv_setup_free(p, p->residue_config); if (p->mapping) { for (i=0; i < p->mapping_count; ++i) - setup_free(p, p->mapping[i].chan); - setup_free(p, p->mapping); + stbv_setup_free(p, p->mapping[i].chan); + stbv_setup_free(p, p->mapping); } - CHECK(p); + STBV_CHECK(p); for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) { - setup_free(p, p->channel_buffers[i]); - setup_free(p, p->previous_window[i]); + stbv_setup_free(p, p->channel_buffers[i]); + stbv_setup_free(p, p->previous_window[i]); #ifdef STB_VORBIS_NO_DEFER_FLOOR - setup_free(p, p->floor_buffers[i]); + stbv_setup_free(p, p->floor_buffers[i]); #endif - setup_free(p, p->finalY[i]); + stbv_setup_free(p, p->finalY[i]); } for (i=0; i < 2; ++i) { - setup_free(p, p->A[i]); - setup_free(p, p->B[i]); - setup_free(p, p->C[i]); - setup_free(p, p->window[i]); - setup_free(p, p->bit_reverse[i]); + stbv_setup_free(p, p->A[i]); + stbv_setup_free(p, p->B[i]); + stbv_setup_free(p, p->C[i]); + stbv_setup_free(p, p->window[i]); + stbv_setup_free(p, p->stbv_bit_reverse[i]); } #ifndef STB_VORBIS_NO_STDIO if (p->close_on_free) fclose(p->f); #endif } -void stb_vorbis_close(stb_vorbis *p) +STBVDEF void stb_vorbis_close(stb_vorbis *p) { if (p == NULL) return; - vorbis_deinit(p); - setup_free(p,p); + stbv_vorbis_deinit(p); + stbv_setup_free(p,p); } -static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) +static void stbv_vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) { memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start if (z) { p->alloc = *z; - p->alloc.alloc_buffer_length_in_bytes &= ~7; + p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3; p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; } p->eof = 0; @@ -4294,7 +4213,7 @@ static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) #endif } -int stb_vorbis_get_sample_offset(stb_vorbis *f) +STBVDEF int stb_vorbis_get_sample_offset(stb_vorbis *f) { if (f->current_loc_valid) return f->current_loc; @@ -4302,7 +4221,7 @@ int stb_vorbis_get_sample_offset(stb_vorbis *f) return -1; } -stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) +STBVDEF stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) { stb_vorbis_info d; d.channels = f->channels; @@ -4314,31 +4233,22 @@ stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) return d; } -stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f) -{ - stb_vorbis_comment d; - d.vendor = f->vendor; - d.comment_list_length = f->comment_list_length; - d.comment_list = f->comment_list; - return d; -} - -int stb_vorbis_get_error(stb_vorbis *f) +STBVDEF int stb_vorbis_get_error(stb_vorbis *f) { int e = f->error; f->error = VORBIS__no_error; return e; } -static stb_vorbis * vorbis_alloc(stb_vorbis *f) +static stb_vorbis * stbv_vorbis_alloc(stb_vorbis *f) { - stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p)); + stb_vorbis *p = (stb_vorbis *) stbv_setup_malloc(f, sizeof(*p)); return p; } #ifndef STB_VORBIS_NO_PUSHDATA_API -void stb_vorbis_flush_pushdata(stb_vorbis *f) +STBVDEF void stb_vorbis_flush_pushdata(stb_vorbis *f) { f->previous_length = 0; f->page_crc_tests = 0; @@ -4350,7 +4260,7 @@ void stb_vorbis_flush_pushdata(stb_vorbis *f) f->channel_buffer_end = 0; } -static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) +static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, int data_len) { int i,n; for (i=0; i < f->page_crc_tests; ++i) @@ -4364,9 +4274,9 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) // one that straddles a boundary for (i=0; i < data_len; ++i) { if (data[i] == 0x4f) { - if (0==memcmp(data+i, ogg_page_header, 4)) { + if (0==memcmp(data+i, stbv_ogg_page_header, 4)) { int j,len; - uint32 crc; + stbv_uint32 crc; // make sure we have the whole page header if (i+26 >= data_len || i+27+data[i+26] >= data_len) { // only read up to this page start, so hopefully we'll @@ -4381,10 +4291,10 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) // scan everything up to the embedded crc (which we must 0) crc = 0; for (j=0; j < 22; ++j) - crc = crc32_update(crc, data[i+j]); + crc = stbv_crc32_update(crc, data[i+j]); // now process 4 0-bytes for ( ; j < 26; ++j) - crc = crc32_update(crc, 0); + crc = stbv_crc32_update(crc, 0); // len is the total number of bytes we need to scan n = f->page_crc_tests++; f->scan[n].bytes_left = len-j; @@ -4406,7 +4316,7 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) } for (i=0; i < f->page_crc_tests;) { - uint32 crc; + stbv_uint32 crc; int j; int n = f->scan[i].bytes_done; int m = f->scan[i].bytes_left; @@ -4414,7 +4324,7 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) // m is the bytes to scan in the current chunk crc = f->scan[i].crc_so_far; for (j=0; j < m; ++j) - crc = crc32_update(crc, data[n+j]); + crc = stbv_crc32_update(crc, data[n+j]); f->scan[i].bytes_left -= m; f->scan[i].crc_so_far = crc; if (f->scan[i].bytes_left == 0) { @@ -4441,9 +4351,9 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) } // return value: number of bytes we used -int stb_vorbis_decode_frame_pushdata( +STBVDEF int stb_vorbis_decode_frame_pushdata( stb_vorbis *f, // the file we're decoding - const uint8 *data, int data_len, // the memory available for decoding + const stbv_uint8 *data, int data_len, // the memory available for decoding int *channels, // place to write number of float * buffers float ***output, // place to write float ** array of float * buffers int *samples // place to write number of output samples @@ -4452,30 +4362,30 @@ int stb_vorbis_decode_frame_pushdata( int i; int len,right,left; - if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (!STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); if (f->page_crc_tests >= 0) { *samples = 0; - return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len); + return stbv_vorbis_search_for_page_pushdata(f, (stbv_uint8 *) data, data_len); } - f->stream = (uint8 *) data; - f->stream_end = (uint8 *) data + data_len; + f->stream = (stbv_uint8 *) data; + f->stream_end = (stbv_uint8 *) data + data_len; f->error = VORBIS__no_error; // check that we have the entire packet in memory - if (!is_whole_packet_present(f)) { + if (!stbv_is_whole_packet_present(f, FALSE)) { *samples = 0; return 0; } - if (!vorbis_decode_packet(f, &len, &left, &right)) { + if (!stbv_vorbis_decode_packet(f, &len, &left, &right)) { // save the actual error we encountered enum STBVorbisError error = f->error; if (error == VORBIS_bad_packet_type) { // flush and resynch f->error = VORBIS__no_error; - while (get8_packet(f) != EOP) + while (stbv_get8_packet(f) != STBV_EOP) if (f->eof) break; *samples = 0; return (int) (f->stream - data); @@ -4485,7 +4395,7 @@ int stb_vorbis_decode_frame_pushdata( // we may be resynching, in which case it's ok to hit one // of these; just discard the packet f->error = VORBIS__no_error; - while (get8_packet(f) != EOP) + while (stbv_get8_packet(f) != STBV_EOP) if (f->eof) break; *samples = 0; return (int) (f->stream - data); @@ -4501,7 +4411,7 @@ int stb_vorbis_decode_frame_pushdata( } // success! - len = vorbis_finish_frame(f, len, left, right); + len = stbv_vorbis_finish_frame(f, len, left, right); for (i=0; i < f->channels; ++i) f->outputs[i] = f->channel_buffers[i] + left; @@ -4511,43 +4421,42 @@ int stb_vorbis_decode_frame_pushdata( return (int) (f->stream - data); } -stb_vorbis *stb_vorbis_open_pushdata( +STBVDEF stb_vorbis *stb_vorbis_open_pushdata( const unsigned char *data, int data_len, // the memory available for decoding int *data_used, // only defined if result is not NULL int *error, const stb_vorbis_alloc *alloc) { stb_vorbis *f, p; - vorbis_init(&p, alloc); - p.stream = (uint8 *) data; - p.stream_end = (uint8 *) data + data_len; + stbv_vorbis_init(&p, alloc); + p.stream = (stbv_uint8 *) data; + p.stream_end = (stbv_uint8 *) data + data_len; p.push_mode = TRUE; - if (!start_decoder(&p)) { + if (!stbv_start_decoder(&p)) { if (p.eof) *error = VORBIS_need_more_data; else *error = p.error; - vorbis_deinit(&p); return NULL; } - f = vorbis_alloc(&p); + f = stbv_vorbis_alloc(&p); if (f) { *f = p; *data_used = (int) (f->stream - data); *error = 0; return f; } else { - vorbis_deinit(&p); + stbv_vorbis_deinit(&p); return NULL; } } #endif // STB_VORBIS_NO_PUSHDATA_API -unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) +STBVDEF unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) { #ifndef STB_VORBIS_NO_PUSHDATA_API if (f->push_mode) return 0; #endif - if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start); + if (STBV_USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start); #ifndef STB_VORBIS_NO_STDIO return (unsigned int) (ftell(f->f) - f->f_start); #endif @@ -4558,12 +4467,12 @@ unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) // DATA-PULLING API // -static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) +static stbv_uint32 stbv_vorbis_find_page(stb_vorbis *f, stbv_uint32 *end, stbv_uint32 *last) { for(;;) { int n; if (f->eof) return 0; - n = get8(f); + n = stbv_get8(f); if (n == 0x4f) { // page header candidate unsigned int retry_loc = stb_vorbis_get_file_offset(f); int i; @@ -4572,33 +4481,33 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) return 0; // check the rest of the header for (i=1; i < 4; ++i) - if (get8(f) != ogg_page_header[i]) + if (stbv_get8(f) != stbv_ogg_page_header[i]) break; if (f->eof) return 0; if (i == 4) { - uint8 header[27]; - uint32 i, crc, goal, len; + stbv_uint8 header[27]; + stbv_uint32 i, crc, goal, len; for (i=0; i < 4; ++i) - header[i] = ogg_page_header[i]; + header[i] = stbv_ogg_page_header[i]; for (; i < 27; ++i) - header[i] = get8(f); + header[i] = stbv_get8(f); if (f->eof) return 0; if (header[4] != 0) goto invalid; - goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24); + goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); for (i=22; i < 26; ++i) header[i] = 0; crc = 0; for (i=0; i < 27; ++i) - crc = crc32_update(crc, header[i]); + crc = stbv_crc32_update(crc, header[i]); len = 0; for (i=0; i < header[26]; ++i) { - int s = get8(f); - crc = crc32_update(crc, s); + int s = stbv_get8(f); + crc = stbv_crc32_update(crc, s); len += s; } if (len && f->eof) return 0; for (i=0; i < len; ++i) - crc = crc32_update(crc, get8(f)); + crc = stbv_crc32_update(crc, stbv_get8(f)); // finished parsing probable page if (crc == goal) { // we could now check that it's either got the last @@ -4617,19 +4526,19 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) else *last = 0; } - set_file_offset(f, retry_loc-1); + stbv_set_file_offset(f, retry_loc-1); return 1; } } invalid: // not a valid page, so rewind and look for next one - set_file_offset(f, retry_loc); + stbv_set_file_offset(f, retry_loc); } } } -#define SAMPLE_unknown 0xffffffff +#define STBV_SAMPLE_unknown 0xffffffff // seeking is implemented with a binary search, which narrows down the range to // 64K, before using a linear search (because finding the synchronization @@ -4640,19 +4549,19 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) // to try to bound either side of the binary search sensibly, while still // working in O(log n) time if they fail. -static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) +static int stbv_get_seek_page_info(stb_vorbis *f, StbvProbedPage *z) { - uint8 header[27], lacing[255]; + stbv_uint8 header[27], lacing[255]; int i,len; // record where the page starts z->page_start = stb_vorbis_get_file_offset(f); // parse the header - getn(f, header, 27); + stbv_getn(f, header, 27); if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S') return 0; - getn(f, lacing, header[26]); + stbv_getn(f, lacing, header[26]); // determine the length of the payload len = 0; @@ -4666,13 +4575,13 @@ static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24); // restore file state to where we were - set_file_offset(f, z->page_start); + stbv_set_file_offset(f, z->page_start); return 1; } -// rarely used function to seek back to the preceding page while finding the +// rarely used function to seek back to the preceeding page while finding the // start of a packet -static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) +static int stbv_go_to_page_before(stb_vorbis *f, unsigned int limit_offset) { unsigned int previous_safe, end; @@ -4682,12 +4591,12 @@ static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) else previous_safe = f->first_audio_page_offset; - set_file_offset(f, previous_safe); + stbv_set_file_offset(f, previous_safe); - while (vorbis_find_page(f, &end, NULL)) { + while (stbv_vorbis_find_page(f, &end, NULL)) { if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset) return 1; - set_file_offset(f, end); + stbv_set_file_offset(f, end); } return 0; @@ -4697,45 +4606,42 @@ static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) // the function succeeds, current_loc_valid will be true and current_loc will // be less than or equal to the provided sample number (the closer the // better). -static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) +static int stbv_seek_to_sample_coarse(stb_vorbis *f, stbv_uint32 sample_number) { - ProbedPage left, right, mid; + StbvProbedPage left, right, mid; int i, start_seg_with_known_loc, end_pos, page_start; - uint32 delta, stream_length, padding, last_sample_limit; - double offset = 0.0, bytes_per_sample = 0.0; + stbv_uint32 delta, stream_length, padding; + double offset, bytes_per_sample; int probe = 0; // find the last page and validate the target sample stream_length = stb_vorbis_stream_length_in_samples(f); - if (stream_length == 0) return error(f, VORBIS_seek_without_length); - if (sample_number > stream_length) return error(f, VORBIS_seek_invalid); + if (stream_length == 0) return stbv_error(f, VORBIS_seek_without_length); + if (sample_number > stream_length) return stbv_error(f, VORBIS_seek_invalid); // this is the maximum difference between the window-center (which is the // actual granule position value), and the right-start (which the spec // indicates should be the granule position (give or take one)). padding = ((f->blocksize_1 - f->blocksize_0) >> 2); if (sample_number < padding) - last_sample_limit = 0; + sample_number = 0; else - last_sample_limit = sample_number - padding; + sample_number -= padding; left = f->p_first; while (left.last_decoded_sample == ~0U) { // (untested) the first page does not have a 'last_decoded_sample' - set_file_offset(f, left.page_end); - if (!get_seek_page_info(f, &left)) goto error; + stbv_set_file_offset(f, left.page_end); + if (!stbv_get_seek_page_info(f, &left)) goto error; } right = f->p_last; assert(right.last_decoded_sample != ~0U); // starting from the start is handled differently - if (last_sample_limit <= left.last_decoded_sample) { - if (stb_vorbis_seek_start(f)) { - if (f->current_loc > sample_number) - return error(f, VORBIS_seek_failed); + if (sample_number <= left.last_decoded_sample) { + if (stb_vorbis_seek_start(f)) return 1; - } return 0; } @@ -4745,17 +4651,17 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) delta = right.page_start - left.page_end; if (delta <= 65536) { // there's only 64K left to search - handle it linearly - set_file_offset(f, left.page_end); + stbv_set_file_offset(f, left.page_end); } else { if (probe < 2) { if (probe == 0) { // first probe (interpolate) double data_bytes = right.page_end - left.page_start; bytes_per_sample = data_bytes / right.last_decoded_sample; - offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample); + offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample); } else { // second probe (try to bound the other side) - double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample; + double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample; if (error >= 0 && error < 8000) error = 8000; if (error < 0 && error > -8000) error = -8000; offset += error * 2; @@ -4767,43 +4673,41 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) if (offset > right.page_start - 65536) offset = right.page_start - 65536; - set_file_offset(f, (unsigned int) offset); + stbv_set_file_offset(f, (unsigned int) offset); } else { // binary search for large ranges (offset by 32K to ensure // we don't hit the right page) - set_file_offset(f, left.page_end + (delta / 2) - 32768); + stbv_set_file_offset(f, left.page_end + (delta / 2) - 32768); } - if (!vorbis_find_page(f, NULL, NULL)) goto error; + if (!stbv_vorbis_find_page(f, NULL, NULL)) goto error; } for (;;) { - if (!get_seek_page_info(f, &mid)) goto error; + if (!stbv_get_seek_page_info(f, &mid)) goto error; if (mid.last_decoded_sample != ~0U) break; // (untested) no frames end on this page - set_file_offset(f, mid.page_end); + stbv_set_file_offset(f, mid.page_end); assert(mid.page_start < right.page_start); } // if we've just found the last page again then we're in a tricky file, - // and we're close enough (if it wasn't an interpolation probe). - if (mid.page_start == right.page_start) { - if (probe >= 2 || delta <= 65536) - break; - } else { - if (last_sample_limit < mid.last_decoded_sample) - right = mid; - else - left = mid; - } + // and we're close enough. + if (mid.page_start == right.page_start) + break; + + if (sample_number < mid.last_decoded_sample) + right = mid; + else + left = mid; ++probe; } // seek back to start of the last packet page_start = left.page_start; - set_file_offset(f, page_start); - if (!start_page(f)) return error(f, VORBIS_seek_failed); + stbv_set_file_offset(f, page_start); + if (!stbv_start_page(f)) return stbv_error(f, VORBIS_seek_failed); end_pos = f->end_seg_with_known_loc; assert(end_pos >= 0); @@ -4814,15 +4718,15 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) start_seg_with_known_loc = i; - if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet)) + if (start_seg_with_known_loc > 0 || !(f->page_flag & STBV_PAGEFLAG_continued_packet)) break; // (untested) the final packet begins on an earlier page - if (!go_to_page_before(f, page_start)) + if (!stbv_go_to_page_before(f, page_start)) goto error; page_start = stb_vorbis_get_file_offset(f); - if (!start_page(f)) goto error; + if (!stbv_start_page(f)) goto error; end_pos = f->segment_count - 1; } @@ -4836,38 +4740,38 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) f->next_seg = start_seg_with_known_loc; for (i = 0; i < start_seg_with_known_loc; i++) - skip(f, f->segments[i]); + stbv_skip(f, f->segments[i]); // start decoding (optimizable - this frame is generally discarded) - if (!vorbis_pump_first_frame(f)) + if (!stbv_vorbis_pump_first_frame(f)) return 0; if (f->current_loc > sample_number) - return error(f, VORBIS_seek_failed); + return stbv_error(f, VORBIS_seek_failed); return 1; error: // try to restore the file to a valid state stb_vorbis_seek_start(f); - return error(f, VORBIS_seek_failed); + return stbv_error(f, VORBIS_seek_failed); } -// the same as vorbis_decode_initial, but without advancing -static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +// the same as stbv_vorbis_decode_initial, but without advancing +static int stbv_peek_decode_initial(stbv_vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) { int bits_read, bytes_read; - if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) + if (!stbv_vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) return 0; // either 1 or 2 bytes were read, figure out which so we can rewind - bits_read = 1 + ilog(f->mode_count-1); + bits_read = 1 + stbv_ilog(f->mode_count-1); if (f->mode_config[*mode].blockflag) bits_read += 2; bytes_read = (bits_read + 7) / 8; f->bytes_in_seg += bytes_read; f->packet_bytes -= bytes_read; - skip(f, -bytes_read); + stbv_skip(f, -bytes_read); if (f->next_seg == -1) f->next_seg = f->segment_count - 1; else @@ -4877,14 +4781,14 @@ static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int return 1; } -int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) +STBVDEF int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) { - uint32 max_frame_samples; + stbv_uint32 max_frame_samples; - if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); // fast page-level search - if (!seek_to_sample_coarse(f, sample_number)) + if (!stbv_seek_to_sample_coarse(f, sample_number)) return 0; assert(f->current_loc_valid); @@ -4894,36 +4798,36 @@ int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2; while (f->current_loc < sample_number) { int left_start, left_end, right_start, right_end, mode, frame_samples; - if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) - return error(f, VORBIS_seek_failed); + if (!stbv_peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) + return stbv_error(f, VORBIS_seek_failed); // calculate the number of samples returned by the next frame frame_samples = right_start - left_start; if (f->current_loc + frame_samples > sample_number) { return 1; // the next frame will contain the sample } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) { // there's a chance the frame after this could contain the sample - vorbis_pump_first_frame(f); + stbv_vorbis_pump_first_frame(f); } else { // this frame is too early to be relevant f->current_loc += frame_samples; f->previous_length = 0; - maybe_start_packet(f); - flush_packet(f); + stbv_maybe_start_packet(f); + stbv_flush_packet(f); } } - // the next frame should start with the sample - if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed); + // the next frame will start with the sample + assert(f->current_loc == sample_number); return 1; } -int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) +STBVDEF int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) { if (!stb_vorbis_seek_frame(f, sample_number)) return 0; if (sample_number != f->current_loc) { int n; - uint32 frame_start = f->current_loc; + stbv_uint32 frame_start = f->current_loc; stb_vorbis_get_frame_float(f, &n, NULL); assert(sample_number > frame_start); assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end); @@ -4933,25 +4837,25 @@ int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) return 1; } -int stb_vorbis_seek_start(stb_vorbis *f) +STBVDEF int stb_vorbis_seek_start(stb_vorbis *f) { - if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); } - set_file_offset(f, f->first_audio_page_offset); + if (STBV_IS_PUSH_MODE(f)) { return stbv_error(f, VORBIS_invalid_api_mixing); } + stbv_set_file_offset(f, f->first_audio_page_offset); f->previous_length = 0; f->first_decode = TRUE; f->next_seg = -1; - return vorbis_pump_first_frame(f); + return stbv_vorbis_pump_first_frame(f); } -unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) +STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) { unsigned int restore_offset, previous_safe; unsigned int end, last_page_loc; - if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); if (!f->total_samples) { unsigned int last; - uint32 lo,hi; + stbv_uint32 lo,hi; char header[6]; // first, store the current decode position so we can restore it @@ -4964,11 +4868,11 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) else previous_safe = f->first_audio_page_offset; - set_file_offset(f, previous_safe); + stbv_set_file_offset(f, previous_safe); // previous_safe is now our candidate 'earliest known place that seeking // to will lead to the final page' - if (!vorbis_find_page(f, &end, &last)) { + if (!stbv_vorbis_find_page(f, &end, &last)) { // if we can't find a page, we're hosed! f->error = VORBIS_cant_find_last_page; f->total_samples = 0xffffffff; @@ -4982,26 +4886,26 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) // this allows us to stop short of a 'file_section' end without // explicitly checking the length of the section while (!last) { - set_file_offset(f, end); - if (!vorbis_find_page(f, &end, &last)) { + stbv_set_file_offset(f, end); + if (!stbv_vorbis_find_page(f, &end, &last)) { // the last page we found didn't have the 'last page' flag // set. whoops! break; } - //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging + previous_safe = last_page_loc+1; last_page_loc = stb_vorbis_get_file_offset(f); } - set_file_offset(f, last_page_loc); + stbv_set_file_offset(f, last_page_loc); // parse the header - getn(f, (unsigned char *)header, 6); + stbv_getn(f, (unsigned char *)header, 6); // extract the absolute granule position - lo = get32(f); - hi = get32(f); + lo = stbv_get32(f); + hi = stbv_get32(f); if (lo == 0xffffffff && hi == 0xffffffff) { f->error = VORBIS_cant_find_last_page; - f->total_samples = SAMPLE_unknown; + f->total_samples = STBV_SAMPLE_unknown; goto done; } if (hi) @@ -5013,29 +4917,29 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) f->p_last.last_decoded_sample = lo; done: - set_file_offset(f, restore_offset); + stbv_set_file_offset(f, restore_offset); } - return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples; + return f->total_samples == STBV_SAMPLE_unknown ? 0 : f->total_samples; } -float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) +STBVDEF float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) { return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate; } -int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) +STBVDEF int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) { int len, right,left,i; - if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); - if (!vorbis_decode_packet(f, &len, &left, &right)) { + if (!stbv_vorbis_decode_packet(f, &len, &left, &right)) { f->channel_buffer_start = f->channel_buffer_end = 0; return 0; } - len = vorbis_finish_frame(f, len, left, right); + len = stbv_vorbis_finish_frame(f, len, left, right); for (i=0; i < f->channels; ++i) f->outputs[i] = f->channel_buffers[i] + left; @@ -5049,28 +4953,28 @@ int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) #ifndef STB_VORBIS_NO_STDIO -stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) +STBVDEF stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) { stb_vorbis *f, p; - vorbis_init(&p, alloc); + stbv_vorbis_init(&p, alloc); p.f = file; - p.f_start = (uint32) ftell(file); + p.f_start = (stbv_uint32) ftell(file); p.stream_len = length; p.close_on_free = close_on_free; - if (start_decoder(&p)) { - f = vorbis_alloc(&p); + if (stbv_start_decoder(&p)) { + f = stbv_vorbis_alloc(&p); if (f) { *f = p; - vorbis_pump_first_frame(f); + stbv_vorbis_pump_first_frame(f); return f; } } if (error) *error = p.error; - vorbis_deinit(&p); + stbv_vorbis_deinit(&p); return NULL; } -stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) +STBVDEF stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) { unsigned int len, start; start = (unsigned int) ftell(file); @@ -5080,67 +4984,58 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); } -stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) +STBVDEF stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) { - FILE *f; -#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) - if (0 != fopen_s(&f, filename, "rb")) - f = NULL; -#else - f = fopen(filename, "rb"); -#endif - if (f) + FILE *f = fopen(filename, "rb"); + if (f) return stb_vorbis_open_file(f, TRUE, error, alloc); if (error) *error = VORBIS_file_open_failure; return NULL; } #endif // STB_VORBIS_NO_STDIO -stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) +STBVDEF stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) { stb_vorbis *f, p; - if (!data) { - if (error) *error = VORBIS_unexpected_eof; - return NULL; - } - vorbis_init(&p, alloc); - p.stream = (uint8 *) data; - p.stream_end = (uint8 *) data + len; - p.stream_start = (uint8 *) p.stream; + if (data == NULL) return NULL; + stbv_vorbis_init(&p, alloc); + p.stream = (stbv_uint8 *) data; + p.stream_end = (stbv_uint8 *) data + len; + p.stream_start = (stbv_uint8 *) p.stream; p.stream_len = len; p.push_mode = FALSE; - if (start_decoder(&p)) { - f = vorbis_alloc(&p); + if (stbv_start_decoder(&p)) { + f = stbv_vorbis_alloc(&p); if (f) { *f = p; - vorbis_pump_first_frame(f); + stbv_vorbis_pump_first_frame(f); if (error) *error = VORBIS__no_error; return f; } } if (error) *error = p.error; - vorbis_deinit(&p); + stbv_vorbis_deinit(&p); return NULL; } #ifndef STB_VORBIS_NO_INTEGER_CONVERSION -#define PLAYBACK_MONO 1 -#define PLAYBACK_LEFT 2 -#define PLAYBACK_RIGHT 4 +#define STBV_PLAYBACK_MONO 1 +#define STBV_PLAYBACK_LEFT 2 +#define STBV_PLAYBACK_RIGHT 4 -#define L (PLAYBACK_LEFT | PLAYBACK_MONO) -#define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO) -#define R (PLAYBACK_RIGHT | PLAYBACK_MONO) +#define STBV_L (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_MONO) +#define STBV_C (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_RIGHT | STBV_PLAYBACK_MONO) +#define STBV_R (STBV_PLAYBACK_RIGHT | STBV_PLAYBACK_MONO) -static int8 channel_position[7][6] = +static stbv_int8 stbv_channel_position[7][6] = { { 0 }, - { C }, - { L, R }, - { L, C, R }, - { L, R, L, R }, - { L, C, R, L, R }, - { L, C, R, L, R, C }, + { STBV_C }, + { STBV_L, STBV_R }, + { STBV_L, STBV_C, STBV_R }, + { STBV_L, STBV_R, STBV_L, STBV_R }, + { STBV_L, STBV_C, STBV_R, STBV_L, STBV_R }, + { STBV_L, STBV_C, STBV_R, STBV_L, STBV_R, STBV_C }, }; @@ -5148,141 +5043,139 @@ static int8 channel_position[7][6] = typedef union { float f; int i; - } float_conv; + } stbv_float_conv; typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4]; - #define FASTDEF(x) float_conv x + #define STBV_FASTDEF(x) stbv_float_conv x // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round - #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) - #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) - #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s)) - #define check_endianness() + #define STBV_MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) + #define STBV_ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) + #define STBV_FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + STBV_MAGIC(s), temp.i - STBV_ADDEND(s)) + #define stbv_check_endianness() #else - #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) - #define check_endianness() - #define FASTDEF(x) + #define STBV_FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) + #define stbv_check_endianness() + #define STBV_FASTDEF(x) #endif -static void copy_samples(short *dest, float *src, int len) +static void stbv_copy_samples(short *dest, float *src, int len) { int i; - check_endianness(); + stbv_check_endianness(); for (i=0; i < len; ++i) { - FASTDEF(temp); - int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); + STBV_FASTDEF(temp); + int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; dest[i] = v; } } -static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) +static void stbv_compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) { - #define STB_BUFFER_SIZE 32 - float buffer[STB_BUFFER_SIZE]; - int i,j,o,n = STB_BUFFER_SIZE; - check_endianness(); - for (o = 0; o < len; o += STB_BUFFER_SIZE) { + #define BUFFER_SIZE 32 + float buffer[BUFFER_SIZE]; + int i,j,o,n = BUFFER_SIZE; + stbv_check_endianness(); + for (o = 0; o < len; o += BUFFER_SIZE) { memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { - if (channel_position[num_c][j] & mask) { + if (stbv_channel_position[num_c][j] & mask) { for (i=0; i < n; ++i) buffer[i] += data[j][d_offset+o+i]; } } for (i=0; i < n; ++i) { - FASTDEF(temp); - int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); + STBV_FASTDEF(temp); + int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; output[o+i] = v; } } - #undef STB_BUFFER_SIZE } -static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) +static void stbv_compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) { - #define STB_BUFFER_SIZE 32 - float buffer[STB_BUFFER_SIZE]; - int i,j,o,n = STB_BUFFER_SIZE >> 1; + #define BUFFER_SIZE 32 + float buffer[BUFFER_SIZE]; + int i,j,o,n = BUFFER_SIZE >> 1; // o is the offset in the source data - check_endianness(); - for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) { + stbv_check_endianness(); + for (o = 0; o < len; o += BUFFER_SIZE >> 1) { // o2 is the offset in the output data int o2 = o << 1; memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { - int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT); - if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) { + int m = stbv_channel_position[num_c][j] & (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_RIGHT); + if (m == (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_RIGHT)) { for (i=0; i < n; ++i) { buffer[i*2+0] += data[j][d_offset+o+i]; buffer[i*2+1] += data[j][d_offset+o+i]; } - } else if (m == PLAYBACK_LEFT) { + } else if (m == STBV_PLAYBACK_LEFT) { for (i=0; i < n; ++i) { buffer[i*2+0] += data[j][d_offset+o+i]; } - } else if (m == PLAYBACK_RIGHT) { + } else if (m == STBV_PLAYBACK_RIGHT) { for (i=0; i < n; ++i) { buffer[i*2+1] += data[j][d_offset+o+i]; } } } for (i=0; i < (n<<1); ++i) { - FASTDEF(temp); - int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); + STBV_FASTDEF(temp); + int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; output[o2+i] = v; } } - #undef STB_BUFFER_SIZE } -static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) +static void stbv_convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) { int i; if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { - static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} }; + static int channel_selector[3][2] = { {0}, {STBV_PLAYBACK_MONO}, {STBV_PLAYBACK_LEFT, STBV_PLAYBACK_RIGHT} }; for (i=0; i < buf_c; ++i) - compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); + stbv_compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); } else { int limit = buf_c < data_c ? buf_c : data_c; for (i=0; i < limit; ++i) - copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples); + stbv_copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples); for ( ; i < buf_c; ++i) memset(buffer[i]+b_offset, 0, sizeof(short) * samples); } } -int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) +STBVDEF int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) { - float **output = NULL; + float **output; int len = stb_vorbis_get_frame_float(f, NULL, &output); if (len > num_samples) len = num_samples; if (len) - convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); + stbv_convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); return len; } -static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) +static void stbv_convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) { int i; - check_endianness(); + stbv_check_endianness(); if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { assert(buf_c == 2); for (i=0; i < buf_c; ++i) - compute_stereo_samples(buffer, data_c, data, d_offset, len); + stbv_compute_stereo_samples(buffer, data_c, data, d_offset, len); } else { int limit = buf_c < data_c ? buf_c : data_c; int j; for (j=0; j < len; ++j) { for (i=0; i < limit; ++i) { - FASTDEF(temp); + STBV_FASTDEF(temp); float f = data[i][d_offset+j]; - int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); + int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; *buffer++ = v; @@ -5293,7 +5186,7 @@ static void convert_channels_short_interleaved(int buf_c, short *buffer, int dat } } -int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) +STBVDEF int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) { float **output; int len; @@ -5301,21 +5194,23 @@ int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buff len = stb_vorbis_get_frame_float(f, NULL, &output); if (len) { if (len*num_c > num_shorts) len = num_shorts / num_c; - convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); + stbv_convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); } return len; } -int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) +STBVDEF int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) { float **outputs; int len = num_shorts / channels; int n=0; + int z = f->channels; + if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; if (k) - convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); + stbv_convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); buffer += k*channels; n += k; f->channel_buffer_start += k; @@ -5325,15 +5220,17 @@ int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short return n; } -int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) +STBVDEF int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) { float **outputs; int n=0; + int z = f->channels; + if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; if (k) - convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); + stbv_convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); n += k; f->channel_buffer_start += k; if (n == len) break; @@ -5343,7 +5240,7 @@ int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, in } #ifndef STB_VORBIS_NO_STDIO -int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output) +STBVDEF int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output) { int data_len, offset, total, limit, error; short *data; @@ -5383,7 +5280,7 @@ int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_ } #endif // NO_STDIO -int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output) +STBVDEF int stb_vorbis_decode_memory(const stbv_uint8 *mem, int len, int *channels, int *sample_rate, short **output) { int data_len, offset, total, limit, error; short *data; @@ -5423,7 +5320,7 @@ int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *samp } #endif // STB_VORBIS_NO_INTEGER_CONVERSION -int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) +STBVDEF int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) { float **outputs; int len = num_floats / channels; @@ -5450,7 +5347,7 @@ int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float return n; } -int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) +STBVDEF int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) { float **outputs; int n=0; @@ -5478,20 +5375,14 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in #endif // STB_VORBIS_NO_PULLDATA_API /* Version history - 1.17 - 2019-07-08 - fix CVE-2019-13217, -13218, -13219, -13220, -13221, -13222, -13223 - found with Mayhem by ForAllSecure - 1.16 - 2019-03-04 - fix warnings - 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found - 1.14 - 2018-02-11 - delete bogus dealloca usage - 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files - 1.11 - 2017-07-23 - fix MinGW compilation - 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory + 1.11 - 2017-07-23 - fix MinGW compilation + 1.10 - 2017-03-03 - more robust seeking; fix negative stbv_ilog(); clear error in open_memory 1.09 - 2016-04-04 - back out 'avoid discarding last frame' fix from previous version 1.08 - 2016-04-02 - fixed multiple warnings; fix setup memory leaks; avoid discarding last frame of audio data 1.07 - 2015-01-16 - fixed some warnings, fix mingw, const-correct API - some more crash fixes when out of memory or with corrupt files + some more crash fixes when out of memory or with corrupt files 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) some crash fixes when out of memory or with corrupt files 1.05 - 2015-04-19 - don't define __forceinline if it's redundant @@ -5538,7 +5429,7 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in 0.90 - first public release */ -#endif // STB_VORBIS_HEADER_ONLY +#endif // STB_VORBIS_IMPLEMENTATION /* @@ -5547,38 +5438,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ */ diff --git a/raylib/external/tinyobj_loader_c.h b/raylib/external/tinyobj_loader_c.h index 55d595a..6bd63fc 100644 --- a/raylib/external/tinyobj_loader_c.h +++ b/raylib/external/tinyobj_loader_c.h @@ -746,7 +746,7 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, (*materials_out) = NULL; (*num_materials_out) = 0; - fp = fopen(filename, "rt"); + fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno); return TINYOBJ_ERROR_FILE_OPERATION; @@ -948,8 +948,6 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, /* @todo { unknown parameter } */ } - fclose(fp); - if (material.name) { /* Flush last material element */ materials = tinyobj_material_add(materials, num_materials, &material); @@ -1269,11 +1267,6 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, if (is_line_ending(buf, i, end_idx)) { line_infos[line_no].pos = prev_pos; line_infos[line_no].len = i - prev_pos; - -// ---- QUICK BUG FIX : https://github.com/raysan5/raylib/issues/3473 - if ( i > 0 && buf[i-1] == '\r' ) line_infos[line_no].len--; -// -------- - prev_pos = i + 1; line_no++; } diff --git a/raylib/external/vendor.go b/raylib/external/vendor.go deleted file mode 100644 index 0fb2a0f..0000000 --- a/raylib/external/vendor.go +++ /dev/null @@ -1,4 +0,0 @@ -//go:build required -// +build required - -package vendor diff --git a/raylib/external/vox_loader.h b/raylib/external/vox_loader.h deleted file mode 100644 index 0d328c0..0000000 --- a/raylib/external/vox_loader.h +++ /dev/null @@ -1,727 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) 2021 Johann Nadalutti. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - - vox_loader - v1.01 - no warranty implied; use at your own risk - - Do this: - #define VOX_LOADER_INCLUDE__H - before you include this file in* one* C or C++ file to create the implementation. - - // i.e. it should look like this: - #include ... - #include ... - #include ... - #define VOX_LOADER_INCLUDE__H - #include "vox_loader.h" - -revision history: - 1.00 (2021-09-03) first released version - 1.01 (2021-09-07) Support custom memory allocators - Removed Raylib dependencies - Changed Vox_LoadFileName to Vox_LoadFromMemory - 1.02 (2021-09-10) @raysan5: Reviewed some formating - 1.03 (2021-10-02) @catmanl: Reduce warnings on gcc - 1.04 (2021-10-17) @warzes: Fixing the error of loading VOX models - -*/ - -#ifndef VOX_LOADER_H -#define VOX_LOADER_H - -// Allow custom memory allocators -#ifndef VOX_MALLOC - #define VOX_MALLOC(sz) malloc(sz) -#endif -#ifndef VOX_CALLOC - #define VOX_CALLOC(n,sz) calloc(n,sz) -#endif -#ifndef VOX_REALLOC - #define VOX_REALLOC(n,sz) realloc(n,sz) -#endif -#ifndef VOX_FREE - #define VOX_FREE(p) free(p) -#endif - -#define VOX_SUCCESS (0) -#define VOX_ERROR_FILE_NOT_FOUND (-1) -#define VOX_ERROR_INVALID_FORMAT (-2) -#define VOX_ERROR_FILE_VERSION_NOT_MATCH (-3) - -// VoxColor, 4 components, R8G8B8A8 (32bit) -typedef struct { - unsigned char r, g, b, a; -} VoxColor; - -// VoxVector3, 3 components -typedef struct { - float x, y, z; -} VoxVector3; - -typedef struct { - VoxVector3* array; - int used, size; -} ArrayVector3; - -typedef struct { - VoxColor* array; - int used, size; -} ArrayColor; - -typedef struct { - unsigned short* array; - int used, size; -} ArrayUShort; - -// A chunk that contain voxels -typedef struct { - unsigned char* m_array; //If Sparse != null - int arraySize; //Size for m_array in bytes (DEBUG ONLY) -} CubeChunk3D; - -// Array for voxels -// Array is divised into chunks of CHUNKSIZE*CHUNKSIZE*CHUNKSIZE voxels size -typedef struct { - // Array size in voxels - int sizeX; - int sizeY; - int sizeZ; - - // Chunks size into array (array is divised into chunks) - int chunksSizeX; - int chunksSizeY; - int chunksSizeZ; - - // Chunks array - CubeChunk3D* m_arrayChunks; - int arrayChunksSize; // Size for m_arrayChunks in bytes (DEBUG ONLY) - - int ChunkFlattenOffset; - int chunksAllocated; - int chunksTotal; - - // Arrays for mesh build - ArrayVector3 vertices; - ArrayVector3 normals; - ArrayUShort indices; - ArrayColor colors; - - //Palette for voxels - VoxColor palette[256]; - -} VoxArray3D; - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -// Functions -int Vox_LoadFromMemory(unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray); -void Vox_FreeArrays(VoxArray3D* voxarray); - -#ifdef __cplusplus -} -#endif - -#endif // VOX_LOADER_H -//// end header file ///////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////// -// Implementation -///////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef VOX_LOADER_IMPLEMENTATION - -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////////// -// ArrayUShort helper -///////////////////////////////////////////////////////////////////////////////////////////// - -static void initArrayUShort(ArrayUShort* a, int initialSize) -{ - a->array = VOX_MALLOC(initialSize * sizeof(unsigned short)); - a->used = 0; - a->size = initialSize; -} - -static void insertArrayUShort(ArrayUShort* a, unsigned short element) -{ - if (a->used == a->size) - { - a->size *= 2; - a->array = VOX_REALLOC(a->array, a->size * sizeof(unsigned short)); - } - a->array[a->used++] = element; -} - -static void freeArrayUShort(ArrayUShort* a) -{ - VOX_FREE(a->array); - a->array = NULL; - a->used = a->size = 0; -} - - -///////////////////////////////////////////////////////////////////////////////////////////// -// ArrayVector3 helper -///////////////////////////////////////////////////////////////////////////////////////////// - -static void initArrayVector3(ArrayVector3* a, int initialSize) -{ - a->array = VOX_MALLOC(initialSize * sizeof(VoxVector3)); - a->used = 0; - a->size = initialSize; -} - -static void insertArrayVector3(ArrayVector3* a, VoxVector3 element) -{ - if (a->used == a->size) - { - a->size *= 2; - a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxVector3)); - } - a->array[a->used++] = element; -} - -static void freeArrayVector3(ArrayVector3* a) -{ - VOX_FREE(a->array); - a->array = NULL; - a->used = a->size = 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////// -// ArrayColor helper -///////////////////////////////////////////////////////////////////////////////////////////// - -static void initArrayColor(ArrayColor* a, int initialSize) -{ - a->array = VOX_MALLOC(initialSize * sizeof(VoxColor)); - a->used = 0; - a->size = initialSize; -} - -static void insertArrayColor(ArrayColor* a, VoxColor element) -{ - if (a->used == a->size) - { - a->size *= 2; - a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxColor)); - } - a->array[a->used++] = element; -} - -static void freeArrayColor(ArrayColor* a) -{ - VOX_FREE(a->array); - a->array = NULL; - a->used = a->size = 0; -} - - -///////////////////////////////////////////////////////////////////////////////////////////// -// Vox Loader -///////////////////////////////////////////////////////////////////////////////////////////// - -#define CHUNKSIZE 16 // chunk size (CHUNKSIZE*CHUNKSIZE*CHUNKSIZE) in voxels -#define CHUNKSIZE_OPSHIFT 4 // 1<<4=16 -> Warning depend of CHUNKSIZE -#define CHUNK_FLATTENOFFSET_OPSHIFT 8 // Warning depend of CHUNKSIZE - -// -// used right handed system and CCW face -// -// indexes for voxelcoords, per face orientation -// - -//# Y -//# | -//# o----X -//# / -//# Z 2------------3 -//# /| /| -//# 6------------7 | -//# | | | | -//# |0 ----------|- 1 -//# |/ |/ -//# 4------------5 - -// -// CCW -const int fv[6][4] = { - {0, 2, 6, 4 }, //-X - {5, 7, 3, 1 }, //+X - {0, 4, 5, 1 }, //-y - {6, 2, 3, 7 }, //+y - {1, 3, 2, 0 }, //-Z - {4, 6, 7, 5 } //+Z -}; - -const VoxVector3 SolidVertex[] = { - {0, 0, 0}, //0 - {1, 0, 0}, //1 - {0, 1, 0}, //2 - {1, 1, 0}, //3 - {0, 0, 1}, //4 - {1, 0, 1}, //5 - {0, 1, 1}, //6 - {1, 1, 1} //7 - }; - -const VoxVector3 FacesPerSideNormal[] = { - { -1, 0, 0 }, //-X - {1, 0, 0 }, //+X - {0,-1, 0}, //-Y - {0, 1, 0}, //+Y - {0, 0, -1}, //-Z - {0, 0, 1}, //+Z -}; - - -// Allocated VoxArray3D size -static void Vox_AllocArray(VoxArray3D* pvoxarray, int _sx, int _sy, int _sz) -{ - int sx = _sx + ((CHUNKSIZE - (_sx % CHUNKSIZE)) % CHUNKSIZE); - int sy = _sy + ((CHUNKSIZE - (_sy % CHUNKSIZE)) % CHUNKSIZE); - int sz = _sz + ((CHUNKSIZE - (_sz % CHUNKSIZE)) % CHUNKSIZE); - - int chx = sx >> CHUNKSIZE_OPSHIFT; //Chunks Count in X - int chy = sy >> CHUNKSIZE_OPSHIFT; //Chunks Count in Y - int chz = sz >> CHUNKSIZE_OPSHIFT; //Chunks Count in Z - - //VoxArray3D* parray = (VoxArray3D*)VOX_MALLOC(sizeof(VoxArray3D)); - pvoxarray->sizeX = sx; - pvoxarray->sizeY = sy; - pvoxarray->sizeZ = sz; - - pvoxarray->chunksSizeX = chx; - pvoxarray->chunksSizeY = chy; - pvoxarray->chunksSizeZ = chz; - - pvoxarray->ChunkFlattenOffset = (chy * chz); //m_arrayChunks[(x * (sy*sz)) + (z * sy) + y] - - // Alloc chunks array - int size = sizeof(CubeChunk3D) * chx * chy * chz; - pvoxarray->m_arrayChunks = VOX_MALLOC(size); - pvoxarray->arrayChunksSize = size; - - // Init chunks array - size = chx * chy * chz; - pvoxarray->chunksTotal = size; - pvoxarray->chunksAllocated = 0; - - for (int i = 0; i < size; i++) - { - pvoxarray->m_arrayChunks[i].m_array = 0; - pvoxarray->m_arrayChunks[i].arraySize = 0; - } -} - -// Set voxel ID from its position into VoxArray3D -static void Vox_SetVoxel(VoxArray3D* pvoxarray, int x, int y, int z, unsigned char id) -{ - // Get chunk from array pos - int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE; - int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE; - int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE; - int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY; - - //if (offset > voxarray->arrayChunksSize) - //{ - // TraceLog(LOG_ERROR, "Out of array"); - //} - - CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset]; - - // Set Chunk - chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE); - chY = y - (chY << CHUNKSIZE_OPSHIFT); //y - (by * CHUNKSIZE); - chZ = z - (chZ << CHUNKSIZE_OPSHIFT); //z - (bz * CHUNKSIZE); - - if (chunk->m_array == 0) - { - int size = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE; - chunk->m_array = VOX_MALLOC(size); - chunk->arraySize = size; - memset(chunk->m_array, 0, size); - - pvoxarray->chunksAllocated++; - } - - offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY; - - //if (offset > chunk->arraySize) - //{ - // TraceLog(LOG_ERROR, "Out of array"); - //} - - chunk->m_array[offset] = id; -} - -// Get voxel ID from its position into VoxArray3D -static unsigned char Vox_GetVoxel(VoxArray3D* pvoxarray, int x, int y, int z) -{ - if (x < 0 || y < 0 || z < 0) return 0; - - if (x >= pvoxarray->sizeX || y >= pvoxarray->sizeY || z >= pvoxarray->sizeZ) return 0; - - // Get chunk from array pos - int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE; - int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE; - int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE; - int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY; - - //if (offset > voxarray->arrayChunksSize) - //{ - // TraceLog(LOG_ERROR, "Out of array"); - //} - - CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset]; - - // Set Chunk - chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE); - chY = y - (chY << CHUNKSIZE_OPSHIFT); //y - (by * CHUNKSIZE); - chZ = z - (chZ << CHUNKSIZE_OPSHIFT); //z - (bz * CHUNKSIZE); - - if (chunk->m_array == 0) - { - return 0; - } - - offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY; - - //if (offset > chunk->arraySize) - //{ - // TraceLog(LOG_ERROR, "Out of array"); - //} - return chunk->m_array[offset]; - -} - -// Calc visibles faces from a voxel position -static unsigned char Vox_CalcFacesVisible(VoxArray3D* pvoxArray, int cx, int cy, int cz) -{ - unsigned char idXm1 = Vox_GetVoxel(pvoxArray, cx - 1, cy, cz); - unsigned char idXp1 = Vox_GetVoxel(pvoxArray, cx + 1, cy, cz); - - unsigned char idYm1 = Vox_GetVoxel(pvoxArray, cx, cy - 1, cz); - unsigned char idYp1 = Vox_GetVoxel(pvoxArray, cx, cy + 1, cz); - - unsigned char idZm1 = Vox_GetVoxel(pvoxArray, cx, cy, cz - 1); - unsigned char idZp1 = Vox_GetVoxel(pvoxArray, cx, cy, cz + 1); - - unsigned char byVFMask = 0; - - //#-x - if (idXm1 == 0) byVFMask |= (1 << 0); - - //#+x - if (idXp1 == 0) byVFMask |= (1 << 1); - - //#-y - if (idYm1 == 0) byVFMask |= (1 << 2); - - //#+y - if (idYp1 == 0) byVFMask |= (1 << 3); - - //#-z - if (idZm1 == 0) byVFMask |= (1 << 4); - - //#+z - if (idZp1 == 0) byVFMask |= (1 << 5); - - return byVFMask; -} - -// Get a vertex position from a voxel's corner -static VoxVector3 Vox_GetVertexPosition(int _wcx, int _wcy, int _wcz, int _nNumVertex) -{ - float scale = 0.25; - - VoxVector3 vtx = SolidVertex[_nNumVertex]; - vtx.x = (vtx.x + _wcx) * scale; - vtx.y = (vtx.y + _wcy) * scale; - vtx.z = (vtx.z + _wcz) * scale; - - return vtx; -} - -// Build a voxel vertices/colors/indices -static void Vox_Build_Voxel(VoxArray3D* pvoxArray, int x, int y, int z, int matID) -{ - unsigned char byVFMask = Vox_CalcFacesVisible(pvoxArray, x, y, z); - - if (byVFMask == 0) return; - - int i, j; - VoxVector3 vertComputed[8]; - int bVertexComputed[8]; - memset(vertComputed, 0, sizeof(vertComputed)); - memset(bVertexComputed, 0, sizeof(bVertexComputed)); - - //For each Cube's faces - for (i = 0; i < 6; i++) // 6 faces - { - if ((byVFMask & (1 << i)) != 0) //If face is visible - { - for (j = 0; j < 4; j++) // 4 corners - { - int nNumVertex = fv[i][j]; //Face,Corner - if (bVertexComputed[nNumVertex] == 0) //if never calc - { - bVertexComputed[nNumVertex] = 1; - vertComputed[nNumVertex] = Vox_GetVertexPosition(x, y, z, nNumVertex); - } - } - } - } - - //Add face - for (i = 0; i < 6; i++)// 6 faces - { - if ((byVFMask & (1 << i)) == 0) - continue; //Face invisible - - int v0 = fv[i][0]; //Face, Corner - int v1 = fv[i][1]; //Face, Corner - int v2 = fv[i][2]; //Face, Corner - int v3 = fv[i][3]; //Face, Corner - - //Arrays - int idx = pvoxArray->vertices.used; - insertArrayVector3(&pvoxArray->vertices, vertComputed[v0]); - insertArrayVector3(&pvoxArray->vertices, vertComputed[v1]); - insertArrayVector3(&pvoxArray->vertices, vertComputed[v2]); - insertArrayVector3(&pvoxArray->vertices, vertComputed[v3]); - - insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); - insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); - insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); - insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); - - VoxColor col = pvoxArray->palette[matID]; - - insertArrayColor(&pvoxArray->colors, col); - insertArrayColor(&pvoxArray->colors, col); - insertArrayColor(&pvoxArray->colors, col); - insertArrayColor(&pvoxArray->colors, col); - - - //v0 - v1 - v2, v0 - v2 - v3 - insertArrayUShort(&pvoxArray->indices, idx + 0); - insertArrayUShort(&pvoxArray->indices, idx + 2); - insertArrayUShort(&pvoxArray->indices, idx + 1); - - insertArrayUShort(&pvoxArray->indices, idx + 0); - insertArrayUShort(&pvoxArray->indices, idx + 3); - insertArrayUShort(&pvoxArray->indices, idx + 2); - } -} - -// MagicaVoxel *.vox file format Loader -int Vox_LoadFromMemory(unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray) -{ - ////////////////////////////////////////////////// - // Read VOX file - // 4 bytes: magic number ('V' 'O' 'X' 'space') - // 4 bytes: version number (current version is 150) - - // @raysan5: Reviewed (unsigned long) -> (unsigned int), possible issue with Ubuntu 18.04 64bit - - // @raysan5: reviewed signature loading - - unsigned char* fileData = pvoxData; - unsigned char* fileDataPtr = fileData; - unsigned char* endfileDataPtr = fileData + voxDataSize; - - if (strncmp((char*)fileDataPtr, "VOX ", 4) != 0) - { - return VOX_ERROR_INVALID_FORMAT; //"Not an MagicaVoxel File format" - } - - fileDataPtr += 4; - - // @raysan5: reviewed version loading - unsigned int version = 0; - version = ((unsigned int*)fileDataPtr)[0]; - fileDataPtr += 4; - - if (version != 150 && version != 200) - { - return VOX_ERROR_FILE_VERSION_NOT_MATCH; //"MagicaVoxel version doesn't match" - } - - - // header - //4 bytes: chunk id - //4 bytes: size of chunk contents (n) - //4 bytes: total size of children chunks(m) - - //// chunk content - //n bytes: chunk contents - - //// children chunks : m bytes - //{ child chunk 0 } - //{ child chunk 1 } - unsigned int sizeX, sizeY, sizeZ; - sizeX = sizeY = sizeZ = 0; - unsigned int numVoxels = 0; - - while (fileDataPtr < endfileDataPtr) - { - char szChunkName[5]; - memcpy(szChunkName, fileDataPtr, 4); - szChunkName[4] = 0; - fileDataPtr += 4; - - unsigned int chunkSize = *((unsigned int*)fileDataPtr); - fileDataPtr += sizeof(unsigned int); - - //unsigned long chunkTotalChildSize = *((unsigned long*)fileDataPtr); - fileDataPtr += sizeof(unsigned int); - - if (strcmp(szChunkName, "SIZE") == 0) - { - //(4 bytes x 3 : x, y, z ) - sizeX = *((unsigned int*)fileDataPtr); - fileDataPtr += sizeof(unsigned int); - - sizeY = *((unsigned int*)fileDataPtr); - fileDataPtr += sizeof(unsigned int); - - sizeZ = *((unsigned int*)fileDataPtr); - fileDataPtr += sizeof(unsigned int); - - //Alloc vox array - Vox_AllocArray(pvoxarray, sizeX, sizeZ, sizeY); //Reverse Y<>Z for left to right handed system - } - else if (strcmp(szChunkName, "XYZI") == 0) - { - unsigned char vx, vy, vz, vi; - - //(numVoxels : 4 bytes ) - //(each voxel: 1 byte x 4 : x, y, z, colorIndex ) x numVoxels - numVoxels = *((unsigned int*)fileDataPtr); - fileDataPtr += sizeof(unsigned int); - - while (numVoxels > 0) - { - vx = *((unsigned char*)fileDataPtr++); - vy = *((unsigned char*)fileDataPtr++); - vz = *((unsigned char*)fileDataPtr++); - vi = *((unsigned char*)fileDataPtr++); - - Vox_SetVoxel(pvoxarray, vx, vz, pvoxarray->sizeZ-vy-1, vi); //Reverse Y<>Z for left to right handed system - - numVoxels--; - } - } - else if (strcmp(szChunkName, "RGBA") == 0) - { - VoxColor col; - - //(each pixel: 1 byte x 4 : r, g, b, a ) x 256 - for (int i = 0; i < 256 - 1; i++) - { - col.r = *((unsigned char*)fileDataPtr++); - col.g = *((unsigned char*)fileDataPtr++); - col.b = *((unsigned char*)fileDataPtr++); - col.a = *((unsigned char*)fileDataPtr++); - - pvoxarray->palette[i + 1] = col; - } - - } - else - { - fileDataPtr += chunkSize; - } - } - - ////////////////////////////////////////////////////////// - // Building Mesh - // TODO compute globals indices array - - // Init Arrays - initArrayVector3(&pvoxarray->vertices, 3 * 1024); - initArrayVector3(&pvoxarray->normals, 3 * 1024); - initArrayUShort(&pvoxarray->indices, 3 * 1024); - initArrayColor(&pvoxarray->colors, 3 * 1024); - - // Create vertices and indices buffers - int x, y, z; - - for (x = 0; x <= pvoxarray->sizeX; x++) - { - for (z = 0; z <= pvoxarray->sizeZ; z++) - { - for (y = 0; y <= pvoxarray->sizeY; y++) - { - unsigned char matID = Vox_GetVoxel(pvoxarray, x, y, z); - if (matID != 0) - Vox_Build_Voxel(pvoxarray, x, y, z, matID); - } - } - } - - return VOX_SUCCESS; -} - -void Vox_FreeArrays(VoxArray3D* voxarray) -{ - // Free chunks - if (voxarray->m_arrayChunks != 0) - { - for (int i = 0; i < voxarray->chunksTotal; i++) - { - CubeChunk3D* chunk = &voxarray->m_arrayChunks[i]; - if (chunk->m_array != 0) - { - chunk->arraySize = 0; - VOX_FREE(chunk->m_array); - } - } - - VOX_FREE(voxarray->m_arrayChunks); - voxarray->m_arrayChunks = 0; - voxarray->arrayChunksSize = 0; - - voxarray->chunksSizeX = voxarray->chunksSizeY = voxarray->chunksSizeZ = 0; - voxarray->chunksTotal = 0; - voxarray->chunksAllocated = 0; - voxarray->ChunkFlattenOffset = 0; - voxarray->sizeX = voxarray->sizeY = voxarray->sizeZ = 0; - } - - // Free arrays - freeArrayVector3(&voxarray->vertices); - freeArrayUShort(&voxarray->indices); - freeArrayColor(&voxarray->colors); -} - -#endif //VOX_LOADER_IMPLEMENTATION diff --git a/raylib/external/win32_clipboard.h b/raylib/external/win32_clipboard.h deleted file mode 100644 index 8328564..0000000 --- a/raylib/external/win32_clipboard.h +++ /dev/null @@ -1,374 +0,0 @@ -#if !defined(_WIN32) -# error "This module is only made for Windows OS" -#endif - -#ifndef WIN32_CLIPBOARD_ -#define WIN32_CLIPBOARD_ -unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize); -#endif // WIN32_CLIPBOARD_ - -#ifdef WIN32_CLIPBOARD_IMPLEMENTATION -#include -#include -#include -#include - -// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h -// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. ) can cause problems is these are not defined. -#if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86) -#define _X86_ -#if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID) -#define _CHPE_X86_ARM64_ -#endif -#endif - -#if !defined(_AMD64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && (defined(_M_AMD64) || defined(_M_ARM64EC)) -#define _AMD64_ -#endif - -#if !defined(_ARM_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM) -#define _ARM_ -#endif - -#if !defined(_ARM64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64EC_) && defined(_M_ARM64) -#define _ARM64_ -#endif - -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM64EC) -#define _ARM64EC_ -#endif - -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_M68K) -#define _68K_ -#endif - -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_MPPC) -#define _MPPC_ -#endif - -#if !defined(_IA64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IA64) -#define _IA64_ -#endif - - -#define WIN32_LEAN_AND_MEAN -// #include -// #include -// #include -#include -// #include - -#ifndef WINAPI -#if defined(_ARM_) -#define WINAPI -#else -#define WINAPI __stdcall -#endif -#endif - -#ifndef WINAPI -#if defined(_ARM_) -#define WINAPI -#else -#define WINAPI __stdcall -#endif -#endif - -#ifndef WINBASEAPI -#ifndef _KERNEL32_ -#define WINBASEAPI DECLSPEC_IMPORT -#else -#define WINBASEAPI -#endif -#endif - -#ifndef WINUSERAPI -#ifndef _USER32_ -#define WINUSERAPI __declspec (dllimport) -#else -#define WINUSERAPI -#endif -#endif - -typedef int WINBOOL; - - - -// typedef HANDLE HGLOBAL; - -#ifndef HWND -#define HWND void* -#endif - - -#if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED) -WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); -WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); -WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); -WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); -WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); -WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); -WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext); -WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat, HANDLE hMem); -WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); -WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); -WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); -WINUSERAPI int WINAPI CountClipboardFormats(VOID); -WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); -WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format, LPSTR lpszFormatName, int cchMaxCount); -WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format, LPWSTR lpszFormatName, int cchMaxCount); -WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); -WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); -WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList, int cFormats); -WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); -#endif - -#ifndef HGLOBAL -#define HGLOBAL void* -#endif - -#if !defined(_WINBASE_) || !defined(WINBASE_ALREADY_INCLUDED) -WINBASEAPI SIZE_T WINAPI GlobalSize (HGLOBAL hMem); -WINBASEAPI LPVOID WINAPI GlobalLock (HGLOBAL hMem); -WINBASEAPI WINBOOL WINAPI GlobalUnlock (HGLOBAL hMem); -#endif - - -#if !defined(_WINGDI_) || !defined(WINGDI_ALREADY_INCLUDED) -#ifndef BITMAPINFOHEADER_ALREADY_DEFINED -#define BITMAPINFOHEADER_ALREADY_DEFINED -// Does this header need to be packed ? by the windowps header it doesnt seem to be -#pragma pack(push, 1) -typedef struct tagBITMAPINFOHEADER { - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; -} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; -#pragma pack(pop) -#endif - -#ifndef BITMAPFILEHEADER_ALREADY_DEFINED -#define BITMAPFILEHEADER_ALREADY_DEFINED -#pragma pack(push, 1) -typedef struct tagBITMAPFILEHEADER { - WORD bfType; - DWORD bfSize; - WORD bfReserved1; - WORD bfReserved2; - DWORD bfOffBits; -} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; -#pragma pack(pop) -#endif - -#ifndef RGBQUAD_ALREADY_DEFINED -#define RGBQUAD_ALREADY_DEFINED -typedef struct tagRGBQUAD { - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; - BYTE rgbReserved; -} RGBQUAD, *LPRGBQUAD; -#endif - - -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57 -#define BI_RGB 0x0000 -#define BI_RLE8 0x0001 -#define BI_RLE4 0x0002 -#define BI_BITFIELDS 0x0003 -#define BI_JPEG 0x0004 -#define BI_PNG 0x0005 -#define BI_CMYK 0x000B -#define BI_CMYKRLE8 0x000C -#define BI_CMYKRLE4 0x000D - -#endif - -// https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats -#define CF_DIB 8 - -// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor -// #define OCR_NORMAL 32512 // Normal select -// #define OCR_IBEAM 32513 // Text select -// #define OCR_WAIT 32514 // Busy -// #define OCR_CROSS 32515 // Precision select -// #define OCR_UP 32516 // Alternate select -// #define OCR_SIZENWSE 32642 // Diagonal resize 1 -// #define OCR_SIZENESW 32643 // Diagonal resize 2 -// #define OCR_SIZEWE 32644 // Horizontal resize -// #define OCR_SIZENS 32645 // Vertical resize -// #define OCR_SIZEALL 32646 // Move -// #define OCR_NO 32648 // Unavailable -// #define OCR_HAND 32649 // Link select -// #define OCR_APPSTARTING 32650 // - - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- - - -static BOOL OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries -static int GetPixelDataOffset(BITMAPINFOHEADER bih); - -unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize) -{ - HWND win = NULL; // Get from somewhere but is doesnt seem to matter - const char* msgString = ""; - int severity = LOG_INFO; - BYTE* bmpData = NULL; - if (!OpenClipboardRetrying(win)) { - severity = LOG_ERROR; - msgString = "Couldn't open clipboard"; - goto end; - } - - HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB); - if (!clipHandle) { - severity = LOG_ERROR; - msgString = "Clipboard data is not an Image"; - goto close; - } - - BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle); - if (!bmpInfoHeader) { - // Mapping from HGLOBAL to our local *address space* failed - severity = LOG_ERROR; - msgString = "Clipboard data failed to be locked"; - goto unlock; - } - - *width = bmpInfoHeader->biWidth; - *height = bmpInfoHeader->biHeight; - - SIZE_T clipDataSize = GlobalSize(clipHandle); - if (clipDataSize < sizeof(BITMAPINFOHEADER)) { - // Format CF_DIB needs space for BITMAPINFOHEADER struct. - msgString = "Clipboard has Malformed data"; - severity = LOG_ERROR; - goto unlock; - } - - // Denotes where the pixel data starts from the bmpInfoHeader pointer - int pixelOffset = GetPixelDataOffset(*bmpInfoHeader); - - //--------------------------------------------------------------------------------// - // - // The rest of the section is about create the bytes for a correct BMP file - // Then we copy the data and to a pointer - // - //--------------------------------------------------------------------------------// - - BITMAPFILEHEADER bmpFileHeader = {0}; - SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize; - *dataSize = bmpFileSize; - - bmpFileHeader.bfType = 0x4D42; //https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536 - - bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine - bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset; - - // - // Each process has a default heap provided by the system - // Memory objects allocated by GlobalAlloc and LocalAlloc are in private, - // committed pages with read/write access that cannot be accessed by other processes. - // - // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application - // that may cause heap corruption. We could create a FreeImage function - // - bmpData = malloc(sizeof(bmpFileHeader) + clipDataSize); - // First we add the header for a bmp file - memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader)); - // Then we add the header for the bmp itself + the pixel data - memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize); - msgString = "Clipboad image acquired successfully"; - - -unlock: - GlobalUnlock(clipHandle); -close: - CloseClipboard(); -end: - - TRACELOG(severity, msgString); - return bmpData; -} - -static BOOL OpenClipboardRetrying(HWND hWnd) -{ - static const int maxTries = 20; - static const int sleepTimeMS = 60; - for (int _ = 0; _ < maxTries; ++_) - { - // Might be being hold by another process - // Or yourself forgot to CloseClipboard - if (OpenClipboard(hWnd)) { - return true; - } - Sleep(sleepTimeMS); - } - return false; -} - -// Based off of researching microsoft docs and reponses from this question https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856 -// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader -// Get the byte offset where does the pixels data start (from a packed DIB) -static int GetPixelDataOffset(BITMAPINFOHEADER bih) -{ - int offset = 0; - const unsigned int rgbaSize = sizeof(RGBQUAD); - - // biSize Specifies the number of bytes required by the structure - // We expect to always be 40 because it should be packed - if (40 == bih.biSize && 40 == sizeof(BITMAPINFOHEADER)) - { - // - // biBitCount Specifies the number of bits per pixel. - // Might exist some bit masks *after* the header and *before* the pixel offset - // we're looking, but only if we have more than - // 8 bits per pixel, so we need to ajust for that - // - if (bih.biBitCount > 8) - { - // if bih.biCompression is RBG we should NOT offset more - - if (bih.biCompression == BI_BITFIELDS) - { - offset += 3 * rgbaSize; - } else if (bih.biCompression == 6 /* BI_ALPHABITFIELDS */) - { - // Not widely supported, but valid. - offset += 4 * rgbaSize; - } - } - } - - // - // biClrUsed Specifies the number of color indices in the color table that are actually used by the bitmap. - // If this value is zero, the bitmap uses the maximum number of colors - // corresponding to the value of the biBitCount member for the compression mode specified by biCompression. - // If biClrUsed is nonzero and the biBitCount member is less than 16 - // the biClrUsed member specifies the actual number of colors - // - if (bih.biClrUsed > 0) { - offset += bih.biClrUsed * rgbaSize; - } else { - if (bih.biBitCount < 16) - { - offset = offset + (rgbaSize << bih.biBitCount); - } - } - - return bih.biSize + offset; -} -#endif // WIN32_CLIPBOARD_IMPLEMENTATION -// EOF - diff --git a/raylib/rgestures.go b/raylib/gestures.go similarity index 89% rename from raylib/rgestures.go rename to raylib/gestures.go index 12b181f..b961000 100644 --- a/raylib/rgestures.go +++ b/raylib/gestures.go @@ -14,7 +14,7 @@ func SetGesturesEnabled(gestureFlags uint32) { // IsGestureDetected - Check if a gesture have been detected func IsGestureDetected(gesture Gestures) bool { - cgesture := (C.uint)(gesture) + cgesture := (C.int)(gesture) ret := C.IsGestureDetected(cgesture) v := bool(ret) return v @@ -27,6 +27,13 @@ func GetGestureDetected() Gestures { return v } +// GetTouchPointsCount - Get touch points count +func GetTouchPointsCount() int32 { + ret := C.GetTouchPointsCount() + v := (int32)(ret) + return v +} + // GetGestureHoldDuration - Get gesture hold time in milliseconds func GetGestureHoldDuration() float32 { ret := C.GetGestureHoldDuration() diff --git a/raylib/rgestures.h b/raylib/gestures.h similarity index 65% rename from raylib/rgestures.h rename to raylib/gestures.h index 1bf4e05..ece65b3 100644 --- a/raylib/rgestures.h +++ b/raylib/gestures.h @@ -1,16 +1,19 @@ /********************************************************************************************** * -* rgestures - Gestures system, gestures processing based on input events (touch/mouse) +* raylib.gestures - Gestures system, gestures processing based on input events (touch/mouse) +* +* NOTE: Memory footprint of this library is aproximately 128 bytes (global variables) * * CONFIGURATION: -* #define RGESTURES_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. * -* #define RGESTURES_STANDALONE -* If defined, the library can be used as standalone to process gesture events with -* no external dependencies. +* #define GESTURES_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define GESTURES_STANDALONE +* If defined, the library can be used as standalone to process gesture events with +* no external dependencies. * * CONTRIBUTORS: * Marc Palau: Initial implementation (2014) @@ -21,7 +24,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -40,8 +43,8 @@ * **********************************************************************************************/ -#ifndef RGESTURES_H -#define RGESTURES_H +#ifndef GESTURES_H +#define GESTURES_H #ifndef PI #define PI 3.14159265358979323846 @@ -50,62 +53,56 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#ifndef MAX_TOUCH_POINTS - #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported -#endif +//... //---------------------------------------------------------------------------------- // Types and Structures Definition -// NOTE: Below types are required for standalone usage +// NOTE: Below types are required for GESTURES_STANDALONE usage //---------------------------------------------------------------------------------- -// Boolean type -#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) - #include -#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) - typedef enum bool { false = 0, true = !false } bool; +#if defined(GESTURES_STANDALONE) + #ifndef __cplusplus + // Boolean type + typedef enum { false, true } bool; + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Gestures type + // NOTE: It could be used as flags to enable only some gestures + typedef enum { + GESTURE_NONE = 0, + GESTURE_TAP = 1, + GESTURE_DOUBLETAP = 2, + GESTURE_HOLD = 4, + GESTURE_DRAG = 8, + GESTURE_SWIPE_RIGHT = 16, + GESTURE_SWIPE_LEFT = 32, + GESTURE_SWIPE_UP = 64, + GESTURE_SWIPE_DOWN = 128, + GESTURE_PINCH_IN = 256, + GESTURE_PINCH_OUT = 512 + } Gestures; #endif -#if !defined(RL_VECTOR2_TYPE) -// Vector2 type -typedef struct Vector2 { - float x; - float y; -} Vector2; -#endif - -#if defined(RGESTURES_STANDALONE) -// Gestures type -// NOTE: It could be used as flags to enable only some gestures -typedef enum { - GESTURE_NONE = 0, - GESTURE_TAP = 1, - GESTURE_DOUBLETAP = 2, - GESTURE_HOLD = 4, - GESTURE_DRAG = 8, - GESTURE_SWIPE_RIGHT = 16, - GESTURE_SWIPE_LEFT = 32, - GESTURE_SWIPE_UP = 64, - GESTURE_SWIPE_DOWN = 128, - GESTURE_PINCH_IN = 256, - GESTURE_PINCH_OUT = 512 -} Gesture; -#endif - -typedef enum { - TOUCH_ACTION_UP = 0, - TOUCH_ACTION_DOWN, - TOUCH_ACTION_MOVE, - TOUCH_ACTION_CANCEL -} TouchAction; +typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; // Gesture event +// NOTE: MAX_TOUCH_POINTS fixed to 4 typedef struct { int touchAction; int pointCount; - int pointId[MAX_TOUCH_POINTS]; - Vector2 position[MAX_TOUCH_POINTS]; + int pointerId[4]; + Vector2 position[4]; } GestureEvent; +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -114,51 +111,39 @@ typedef struct { //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) -#if defined(RGESTURES_STANDALONE) -void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags +#if defined(GESTURES_STANDALONE) +void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags bool IsGestureDetected(int gesture); // Check if a gesture have been detected int GetGestureDetected(void); // Get latest detected gesture - -float GetGestureHoldDuration(void); // Get gesture hold time in seconds +int GetTouchPointsCount(void); // Get touch points count +float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle #endif -#if defined(__cplusplus) +#ifdef __cplusplus } #endif -#endif // RGESTURES_H +#endif // GESTURES_H /*********************************************************************************** * -* RGESTURES IMPLEMENTATION +* GESTURES IMPLEMENTATION * ************************************************************************************/ -#if defined(RGESTURES_IMPLEMENTATION) +#if defined(GESTURES_IMPLEMENTATION) -#if defined(RGESTURES_STANDALONE) #if defined(_WIN32) - #if defined(__cplusplus) - extern "C" { // Prevents name mangling of functions - #endif // Functions required to query time on Windows int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); - #if defined(__cplusplus) - } - #endif #elif defined(__linux__) #if _POSIX_C_SOURCE < 199309L #undef _POSIX_C_SOURCE @@ -173,17 +158,15 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang #include // Required for: clock_get_time() #include // Required for: mach_timespec_t #endif -#endif //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 0.2f // Swipe force, measured in normalized screen units/time +#define FORCE_TO_SWIPE 0.0005f // Swipe force, measured in normalized screen units/time #define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f) -#define DRAG_TIMEOUT 0.3f // Drag minimum time for web, measured in seconds #define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f) -#define TAP_TIMEOUT 0.3f // Tap minimum time, measured in seconds -#define PINCH_TIMEOUT 0.3f // Pinch minimum time, measured in seconds +#define TAP_TIMEOUT 300 // Tap minimum time, measured in milliseconds +#define PINCH_TIMEOUT 300 // Pinch minimum time, measured in milliseconds #define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f) //---------------------------------------------------------------------------------- @@ -204,13 +187,11 @@ typedef struct { Vector2 downDragPosition; // Touch drag position Vector2 moveDownPositionA; // First touch down position on move Vector2 moveDownPositionB; // Second touch down position on move - Vector2 previousPositionA; // Previous position A to compare for pinch gestures - Vector2 previousPositionB; // Previous position B to compare for pinch gestures - int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions) + int tapCounter; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions) } Touch; struct { bool resetRequired; // HOLD reset to get first touch point again - double timeDuration; // HOLD duration in seconds + double timeDuration; // HOLD duration in milliseconds } Hold; struct { Vector2 vector; // DRAG vector (between initial and current position) @@ -219,7 +200,8 @@ typedef struct { float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame) } Drag; struct { - double startTime; // SWIPE start time to calculate drag intensity + bool start; // SWIPE used to define when start measuring GESTURES.Swipe.timeDuration + double timeDuration; // SWIPE time to calculate drag intensity } Swipe; struct { Vector2 vector; // PINCH vector (between first and second touch points) @@ -233,29 +215,32 @@ typedef struct { //---------------------------------------------------------------------------------- static GesturesData GESTURES = { .Touch.firstId = -1, - .current = GESTURE_NONE, // No current gesture detected + .current = GESTURE_NONE, // No current gesture detected .enabledFlags = 0b0000001111111111 // All gestures supported by default }; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static float rgVector2Angle(Vector2 initialPosition, Vector2 finalPosition); -static float rgVector2Distance(Vector2 v1, Vector2 v2); -static double rgGetCurrentTime(void); +#if defined(GESTURES_STANDALONE) +// Some required math functions provided by raymath.h +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); +static float Vector2Distance(Vector2 v1, Vector2 v2); +#endif +static double GetCurrentTime(void); //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- -// Enable only desired gestures to be detected +// Enable only desired getures to be detected void SetGesturesEnabled(unsigned int flags) { GESTURES.enabledFlags = flags; } // Check if a gesture have been detected -bool IsGestureDetected(unsigned int gesture) +bool IsGestureDetected(int gesture) { if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true; else return false; @@ -267,14 +252,14 @@ void ProcessGestureEvent(GestureEvent event) // Reset required variables GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures() - if (GESTURES.Touch.pointCount == 1) // One touch point + if (GESTURES.Touch.pointCount < 2) { - if (event.touchAction == TOUCH_ACTION_DOWN) + if (event.touchAction == TOUCH_DOWN) { GESTURES.Touch.tapCounter++; // Tap counter // Detect GESTURE_DOUBLE_TAP - if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((rgGetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE)) + if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((GetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (Vector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE)) { GESTURES.current = GESTURE_DOUBLETAP; GESTURES.Touch.tapCounter = 0; @@ -289,31 +274,32 @@ void ProcessGestureEvent(GestureEvent event) GESTURES.Touch.downDragPosition = event.position[0]; GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA; - GESTURES.Touch.eventTime = rgGetCurrentTime(); + GESTURES.Touch.eventTime = GetCurrentTime(); - GESTURES.Swipe.startTime = rgGetCurrentTime(); + GESTURES.Touch.firstId = event.pointerId[0]; GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f }; } - else if (event.touchAction == TOUCH_ACTION_UP) + else if (event.touchAction == TOUCH_UP) { - // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases - if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0]; + if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0]; - // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen - GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); - GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime)); + // NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen + GESTURES.Drag.distance = Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); + GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((GetCurrentTime() - GESTURES.Swipe.timeDuration)); + + GESTURES.Swipe.start = false; // Detect GESTURE_SWIPE - if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG)) + if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.Touch.firstId == event.pointerId[0])) { // NOTE: Angle should be inverted in Y - GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); + GESTURES.Drag.angle = 360.0f - Vector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); - if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right - else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP; // Up - else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left - else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down + if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right + else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP; // Up + else if ((GESTURES.Drag.angle > 120) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left + else if ((GESTURES.Drag.angle > 210) && (GESTURES.Drag.angle < 300)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down else GESTURES.current = GESTURE_NONE; } else @@ -328,8 +314,16 @@ void ProcessGestureEvent(GestureEvent event) GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f }; GESTURES.Touch.pointCount = 0; } - else if (event.touchAction == TOUCH_ACTION_MOVE) + else if (event.touchAction == TOUCH_MOVE) { + if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.eventTime = GetCurrentTime(); + + if (!GESTURES.Swipe.start) + { + GESTURES.Swipe.timeDuration = GetCurrentTime(); + GESTURES.Swipe.start = true; + } + GESTURES.Touch.moveDownPositionA = event.position[0]; if (GESTURES.current == GESTURE_HOLD) @@ -339,9 +333,9 @@ void ProcessGestureEvent(GestureEvent event) GESTURES.Hold.resetRequired = false; // Detect GESTURE_DRAG - if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT) + if (Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG) { - GESTURES.Touch.eventTime = rgGetCurrentTime(); + GESTURES.Touch.eventTime = GetCurrentTime(); GESTURES.current = GESTURE_DRAG; } } @@ -350,27 +344,27 @@ void ProcessGestureEvent(GestureEvent event) GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y; } } - else if (GESTURES.Touch.pointCount == 2) // Two touch points + else // Two touch points { - if (event.touchAction == TOUCH_ACTION_DOWN) + if (event.touchAction == TOUCH_DOWN) { GESTURES.Touch.downPositionA = event.position[0]; GESTURES.Touch.downPositionB = event.position[1]; - GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA; - GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB; - - //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); + //GESTURES.Pinch.distance = Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x; GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y; GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); + GESTURES.Hold.timeDuration = GetCurrentTime(); } - else if (event.touchAction == TOUCH_ACTION_MOVE) + else if (event.touchAction == TOUCH_MOVE) { - GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); + GESTURES.Pinch.distance = Vector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); + + GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA; + GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB; GESTURES.Touch.moveDownPositionA = event.position[0]; GESTURES.Touch.moveDownPositionB = event.position[1]; @@ -378,21 +372,21 @@ void ProcessGestureEvent(GestureEvent event) GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x; GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y; - if ((rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH)) + if ((Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (Vector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH)) { - if ( rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN; + if ((Vector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN; else GESTURES.current = GESTURE_PINCH_OUT; } else { GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); + GESTURES.Hold.timeDuration = GetCurrentTime(); } // NOTE: Angle should be inverted in Y - GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); + GESTURES.Pinch.angle = 360.0f - Vector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); } - else if (event.touchAction == TOUCH_ACTION_UP) + else if (event.touchAction == TOUCH_UP) { GESTURES.Pinch.distance = 0.0f; GESTURES.Pinch.angle = 0.0f; @@ -402,10 +396,6 @@ void ProcessGestureEvent(GestureEvent event) GESTURES.current = GESTURE_NONE; } } - else if (GESTURES.Touch.pointCount > 2) // More than two touch points - { - // TODO: Process gesture events for more than two points - } } // Update gestures detected (must be called every frame) @@ -417,7 +407,14 @@ void UpdateGestures(void) if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2)) { GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); + GESTURES.Hold.timeDuration = GetCurrentTime(); + } + + if (((GetCurrentTime() - GESTURES.Touch.eventTime) > TAP_TIMEOUT) && (GESTURES.current == GESTURE_DRAG) && (GESTURES.Touch.pointCount < 2)) + { + GESTURES.current = GESTURE_HOLD; + GESTURES.Hold.timeDuration = GetCurrentTime(); + GESTURES.Hold.resetRequired = true; } // Detect GESTURE_NONE @@ -427,6 +424,14 @@ void UpdateGestures(void) } } +// Get number of touch points +int GetTouchPointsCount(void) +{ + // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called + + return GESTURES.Touch.pointCount; +} + // Get latest detected gesture int GetGestureDetected(void) { @@ -434,14 +439,14 @@ int GetGestureDetected(void) return (GESTURES.enabledFlags & GESTURES.current); } -// Hold time measured in seconds +// Hold time measured in ms float GetGestureHoldDuration(void) { // NOTE: time is calculated on current gesture HOLD double time = 0.0; - if (GESTURES.current == GESTURE_HOLD) time = rgGetCurrentTime() - GESTURES.Hold.timeDuration; + if (GESTURES.current == GESTURE_HOLD) time = GetCurrentTime() - GESTURES.Hold.timeDuration; return (float)time; } @@ -449,16 +454,16 @@ float GetGestureHoldDuration(void) // Get drag vector (between initial touch point to current) Vector2 GetGestureDragVector(void) { - // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE + // NOTE: drag vector is calculated on one touch points TOUCH_MOVE return GESTURES.Drag.vector; } // Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGestureDragAngle(void) { - // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP + // NOTE: drag angle is calculated on one touch points TOUCH_UP return GESTURES.Drag.angle; } @@ -466,16 +471,17 @@ float GetGestureDragAngle(void) // Get distance between two pinch points Vector2 GetGesturePinchVector(void) { - // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE + // NOTE: The position values used for GESTURES.Pinch.distance are not modified like the position values of [core.c]-->GetTouchPosition(int index) + // NOTE: pinch distance is calculated on two touch points TOUCH_MOVE return GESTURES.Pinch.vector; } -// Get angle between two pinch points -// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise +// Get angle beween two pinch points +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGesturePinchAngle(void) { - // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE + // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE return GESTURES.Pinch.angle; } @@ -483,8 +489,9 @@ float GetGesturePinchAngle(void) //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Get angle from two-points vector with X-axis -static float rgVector2Angle(Vector2 v1, Vector2 v2) +#if defined(GESTURES_STANDALONE) +// Returns angle from two-points vector with X-axis +static float Vector2Angle(Vector2 v1, Vector2 v2) { float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); @@ -494,7 +501,7 @@ static float rgVector2Angle(Vector2 v1, Vector2 v2) } // Calculate distance between two Vector2 -static float rgVector2Distance(Vector2 v1, Vector2 v2) +static float Vector2Distance(Vector2 v1, Vector2 v2) { float result; @@ -505,22 +512,20 @@ static float rgVector2Distance(Vector2 v1, Vector2 v2) return result; } +#endif -// Time measure returned are seconds -static double rgGetCurrentTime(void) +// Time measure returned are milliseconds +static double GetCurrentTime(void) { double time = 0; -#if !defined(RGESTURES_STANDALONE) - time = GetTime(); -#else #if defined(_WIN32) unsigned long long int clockFrequency, currentTime; - QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! + QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! QueryPerformanceCounter(¤tTime); - time = (double)currentTime/clockFrequency; // Time in seconds + time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds #endif #if defined(__linux__) @@ -529,7 +534,7 @@ static double rgGetCurrentTime(void) clock_gettime(CLOCK_MONOTONIC, &now); unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds - time = ((double)nowTime*1e-9); // Time in seconds + time = ((double)nowTime/1000000.0); // Time in miliseconds #endif #if defined(__APPLE__) @@ -545,11 +550,10 @@ static double rgGetCurrentTime(void) mach_port_deallocate(mach_task_self(), cclock); unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds - time = ((double)nowTime*1e-9); // Time in seconds -#endif + time = ((double)nowTime/1000000.0); // Time in miliseconds #endif return time; } -#endif // RGESTURES_IMPLEMENTATION +#endif // GESTURES_IMPLEMENTATION diff --git a/raylib/go.mod b/raylib/go.mod deleted file mode 100644 index fe16d16..0000000 --- a/raylib/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module git.terah.dev/UnrealXR/raylib-go/raylib - -go 1.21 - -require ( - github.com/ebitengine/purego v0.7.1 - golang.org/x/sys v0.20.0 -) - -require golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 diff --git a/raylib/go.sum b/raylib/go.sum deleted file mode 100644 index 2241fa5..0000000 --- a/raylib/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= -github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/raylib/miniaudio.c b/raylib/miniaudio.c new file mode 100644 index 0000000..54384c4 --- /dev/null +++ b/raylib/miniaudio.c @@ -0,0 +1,4 @@ +// The implementation of mini_al needs to #include windows.h which means it needs to go into +// it's own translation unit. Not doing this will cause conflicts with CloseWindow(), etc. +#define MAL_IMPLEMENTATION +#include "external/miniaudio.h" diff --git a/raylib/models.c b/raylib/models.c new file mode 100644 index 0000000..551ee7a --- /dev/null +++ b/raylib/models.c @@ -0,0 +1,4871 @@ +/********************************************************************************************** +* +* raylib.models - Basic functions to deal with 3d shapes and 3d models +* +* CONFIGURATION: +* +* #define SUPPORT_FILEFORMAT_OBJ +* #define SUPPORT_FILEFORMAT_MTL +* #define SUPPORT_FILEFORMAT_IQM +* #define SUPPORT_FILEFORMAT_GLTF +* Selected desired fileformats to be supported for model data loading. +* +* #define SUPPORT_MESH_GENERATION +* Support procedural mesh generation functions, uses external par_shapes.h library +* NOTE: Some generated meshes DO NOT include generated texture coordinates +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" // Declares module functions + +// Check if config flags have been externally provided on compilation line +#if !defined(EXTERNAL_CONFIG_FLAGS) + #include "config.h" // Defines module configuration flags +#endif + +#include "utils.h" // Required for: LoadFileData(), LoadFileText(), SaveFileText() + +#include // Required for: sprintf() +#include // Required for: malloc(), free() +#include // Required for: memcmp(), strlen() +#include // Required for: sinf(), cosf(), sqrtf(), fabsf() + +#if defined(_WIN32) + #include // Required for: _chdir() [Used in LoadOBJ()] + #define CHDIR _chdir +#else + #include // Required for: chdir() (POSIX) [Used in LoadOBJ()] + #define CHDIR chdir +#endif + +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 + +#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) + #define TINYOBJ_MALLOC RL_MALLOC + #define TINYOBJ_CALLOC RL_CALLOC + #define TINYOBJ_REALLOC RL_REALLOC + #define TINYOBJ_FREE RL_FREE + + #define TINYOBJ_LOADER_C_IMPLEMENTATION + #include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading +#endif + +#if defined(SUPPORT_FILEFORMAT_GLTF) + #define CGLTF_MALLOC RL_MALLOC + #define CGLTF_FREE RL_FREE + + #define CGLTF_IMPLEMENTATION + #include "external/cgltf.h" // glTF file format loading + #include "external/stb_image.h" // glTF texture images loading +#endif + +#if defined(SUPPORT_MESH_GENERATION) + #define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T))) + #define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1)) + #define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N))) + #define PAR_FREE RL_FREE + + #define PAR_SHAPES_IMPLEMENTATION + #include "external/par_shapes.h" // Shapes 3d parametric generation +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_FILEFORMAT_OBJ) +static Model LoadOBJ(const char *fileName); // Load OBJ mesh data +#endif +#if defined(SUPPORT_FILEFORMAT_IQM) +static Model LoadIQM(const char *fileName); // Load IQM mesh data +static ModelAnimation *LoadIQMModelAnimations(const char *fileName, int *animCount); // Load IQM animation data +#endif +#if defined(SUPPORT_FILEFORMAT_GLTF) +static Model LoadGLTF(const char *fileName); // Load GLTF mesh data +static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCount); // Load GLTF animation data +static void LoadGLTFModelIndices(Model* model, cgltf_accessor* indexAccessor, int primitiveIndex); +static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int primitiveIndex); +static void LoadGLTFBoneAttribute(Model* model, cgltf_accessor* jointsAccessor, const cgltf_data* data, int primitiveIndex); +static void LoadGLTFMaterial(Model* model, const char* fileName, const cgltf_data* data); +static void InitGLTFBones(Model* model, const cgltf_data* data); +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Draw a line in 3D world space +void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) +{ + // WARNING: Be careful with internal buffer vertex alignment + // when using RL_LINES or RL_TRIANGLES, data is aligned to fit + // lines-triangles-quads in the same indexed buffers!!! + rlCheckRenderBatchLimit(8); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex3f(startPos.x, startPos.y, startPos.z); + rlVertex3f(endPos.x, endPos.y, endPos.z); + rlEnd(); +} + +// Draw a point in 3D space, actually a small line +void DrawPoint3D(Vector3 position, Color color) +{ + rlCheckRenderBatchLimit(8); + + rlPushMatrix(); + rlTranslatef(position.x, position.y, position.z); + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex3f(0.0f, 0.0f, 0.0f); + rlVertex3f(0.0f, 0.0f, 0.1f); + rlEnd(); + rlPopMatrix(); +} + +// Draw a circle in 3D world space +void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) +{ + rlCheckRenderBatchLimit(2*36); + + rlPushMatrix(); + rlTranslatef(center.x, center.y, center.z); + rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); + + rlBegin(RL_LINES); + for (int i = 0; i < 360; i += 10) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f); + } + rlEnd(); + rlPopMatrix(); +} + +// Draw a color-filled triangle (vertex in counter-clockwise order!) +void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color) +{ + rlCheckRenderBatchLimit(3); + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex3f(v1.x, v1.y, v1.z); + rlVertex3f(v2.x, v2.y, v2.z); + rlVertex3f(v3.x, v3.y, v3.z); + rlEnd(); +} + +// Draw a triangle strip defined by points +void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color) +{ + if (pointsCount >= 3) + { + rlCheckRenderBatchLimit(3*(pointsCount - 2)); + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 2; i < pointsCount; i++) + { + if ((i%2) == 0) + { + rlVertex3f(points[i].x, points[i].y, points[i].z); + rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z); + rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z); + } + else + { + rlVertex3f(points[i].x, points[i].y, points[i].z); + rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z); + rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z); + } + } + rlEnd(); + } +} + +// Draw cube +// NOTE: Cube position is the center position +void DrawCube(Vector3 position, float width, float height, float length, Color color) +{ + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + + rlCheckRenderBatchLimit(36); + + rlPushMatrix(); + // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) + rlTranslatef(position.x, position.y, position.z); + //rlRotatef(45, 0, 1, 0); + //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + // Front face + rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left + rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right + rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left + + rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right + rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left + rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right + + // Back face + rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left + rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left + rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right + + rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right + rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right + rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left + + // Top face + rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left + rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left + rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right + + rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right + rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left + rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right + + // Bottom face + rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left + rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right + rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left + + rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right + rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right + rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left + + // Right face + rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right + rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right + rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left + + rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left + rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right + rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left + + // Left face + rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right + rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left + rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right + + rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left + rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left + rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right + rlEnd(); + rlPopMatrix(); +} + +// Draw cube (Vector version) +void DrawCubeV(Vector3 position, Vector3 size, Color color) +{ + DrawCube(position, size.x, size.y, size.z, color); +} + +// Draw cube wires +void DrawCubeWires(Vector3 position, float width, float height, float length, Color color) +{ + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + + rlCheckRenderBatchLimit(36); + + rlPushMatrix(); + rlTranslatef(position.x, position.y, position.z); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + // Front Face ----------------------------------------------------- + // Bottom Line + rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom Left + rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom Right + + // Left Line + rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom Right + rlVertex3f(x+width/2, y+height/2, z+length/2); // Top Right + + // Top Line + rlVertex3f(x+width/2, y+height/2, z+length/2); // Top Right + rlVertex3f(x-width/2, y+height/2, z+length/2); // Top Left + + // Right Line + rlVertex3f(x-width/2, y+height/2, z+length/2); // Top Left + rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom Left + + // Back Face ------------------------------------------------------ + // Bottom Line + rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom Left + rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom Right + + // Left Line + rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom Right + rlVertex3f(x+width/2, y+height/2, z-length/2); // Top Right + + // Top Line + rlVertex3f(x+width/2, y+height/2, z-length/2); // Top Right + rlVertex3f(x-width/2, y+height/2, z-length/2); // Top Left + + // Right Line + rlVertex3f(x-width/2, y+height/2, z-length/2); // Top Left + rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom Left + + // Top Face ------------------------------------------------------- + // Left Line + rlVertex3f(x-width/2, y+height/2, z+length/2); // Top Left Front + rlVertex3f(x-width/2, y+height/2, z-length/2); // Top Left Back + + // Right Line + rlVertex3f(x+width/2, y+height/2, z+length/2); // Top Right Front + rlVertex3f(x+width/2, y+height/2, z-length/2); // Top Right Back + + // Bottom Face --------------------------------------------------- + // Left Line + rlVertex3f(x-width/2, y-height/2, z+length/2); // Top Left Front + rlVertex3f(x-width/2, y-height/2, z-length/2); // Top Left Back + + // Right Line + rlVertex3f(x+width/2, y-height/2, z+length/2); // Top Right Front + rlVertex3f(x+width/2, y-height/2, z-length/2); // Top Right Back + rlEnd(); + rlPopMatrix(); +} + +// Draw cube wires (vector version) +void DrawCubeWiresV(Vector3 position, Vector3 size, Color color) +{ + DrawCubeWires(position, size.x, size.y, size.z, color); +} + +// Draw cube +// NOTE: Cube position is the center position +void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color) +{ + float x = position.x; + float y = position.y; + float z = position.z; + + rlCheckRenderBatchLimit(36); + + rlSetTexture(texture.id); + + //rlPushMatrix(); + // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) + //rlTranslatef(2.0f, 0.0f, 0.0f); + //rlRotatef(45, 0, 1, 0); + //rlScalef(2.0f, 2.0f, 2.0f); + + rlBegin(RL_QUADS); + rlColor4ub(color.r, color.g, color.b, color.a); + // Front Face + rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer + rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad + rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad + rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad + rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad + // Back Face + rlNormal3f(0.0f, 0.0f, - 1.0f); // Normal Pointing Away From Viewer + rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad + rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad + rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad + rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad + // Top Face + rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up + rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad + rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left Of The Texture and Quad + rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right Of The Texture and Quad + rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad + // Bottom Face + rlNormal3f(0.0f, - 1.0f, 0.0f); // Normal Pointing Down + rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Right Of The Texture and Quad + rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Left Of The Texture and Quad + rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad + rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad + // Right face + rlNormal3f(1.0f, 0.0f, 0.0f); // Normal Pointing Right + rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad + rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad + rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad + rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad + // Left Face + rlNormal3f( - 1.0f, 0.0f, 0.0f); // Normal Pointing Left + rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad + rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad + rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad + rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad + rlEnd(); + //rlPopMatrix(); + + rlSetTexture(0); +} + +// Draw sphere +void DrawSphere(Vector3 centerPos, float radius, Color color) +{ + DrawSphereEx(centerPos, radius, 16, 16, color); +} + +// Draw sphere with extended parameters +void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color) +{ + int numVertex = (rings + 2)*slices*6; + rlCheckRenderBatchLimit(numVertex); + + rlPushMatrix(); + // NOTE: Transformation is applied in inverse order (scale -> translate) + rlTranslatef(centerPos.x, centerPos.y, centerPos.z); + rlScalef(radius, radius, radius); + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 0; i < (rings + 2); i++) + { + for (int j = 0; j < slices; j++) + { + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); + + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); + } + } + rlEnd(); + rlPopMatrix(); +} + +// Draw sphere wires +void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color) +{ + int numVertex = (rings + 2)*slices*6; + rlCheckRenderBatchLimit(numVertex); + + rlPushMatrix(); + // NOTE: Transformation is applied in inverse order (scale -> translate) + rlTranslatef(centerPos.x, centerPos.y, centerPos.z); + rlScalef(radius, radius, radius); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 0; i < (rings + 2); i++) + { + for (int j = 0; j < slices; j++) + { + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); + + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); + + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); + rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), + sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), + cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); + } + } + rlEnd(); + rlPopMatrix(); +} + +// Draw a cylinder +// NOTE: It could be also used for pyramid and cone +void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) +{ + if (sides < 3) sides = 3; + + int numVertex = sides*6; + rlCheckRenderBatchLimit(numVertex); + + rlPushMatrix(); + rlTranslatef(position.x, position.y, position.z); + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + if (radiusTop > 0) + { + // Draw Body ------------------------------------------------------------------------------------- + for (int i = 0; i < 360; i += 360/sides) + { + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom); //Bottom Right + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); //Top Right + + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); //Top Left + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); //Top Right + } + + // Draw Cap -------------------------------------------------------------------------------------- + for (int i = 0; i < 360; i += 360/sides) + { + rlVertex3f(0, height, 0); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); + } + } + else + { + // Draw Cone ------------------------------------------------------------------------------------- + for (int i = 0; i < 360; i += 360/sides) + { + rlVertex3f(0, height, 0); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom); + } + } + + // Draw Base ----------------------------------------------------------------------------------------- + for (int i = 0; i < 360; i += 360/sides) + { + rlVertex3f(0, 0, 0); + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + } + rlEnd(); + rlPopMatrix(); +} + +// Draw a wired cylinder +// NOTE: It could be also used for pyramid and cone +void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) +{ + if (sides < 3) sides = 3; + + int numVertex = sides*8; + rlCheckRenderBatchLimit(numVertex); + + rlPushMatrix(); + rlTranslatef(position.x, position.y, position.z); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 0; i < 360; i += 360/sides) + { + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom); + + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); + + rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + } + rlEnd(); + rlPopMatrix(); +} + +// Draw a plane +void DrawPlane(Vector3 centerPos, Vector2 size, Color color) +{ + rlCheckRenderBatchLimit(4); + + // NOTE: Plane is always created on XZ ground + rlPushMatrix(); + rlTranslatef(centerPos.x, centerPos.y, centerPos.z); + rlScalef(size.x, 1.0f, size.y); + + rlBegin(RL_QUADS); + rlColor4ub(color.r, color.g, color.b, color.a); + rlNormal3f(0.0f, 1.0f, 0.0f); + + rlVertex3f(-0.5f, 0.0f, -0.5f); + rlVertex3f(-0.5f, 0.0f, 0.5f); + rlVertex3f(0.5f, 0.0f, 0.5f); + rlVertex3f(0.5f, 0.0f, -0.5f); + rlEnd(); + rlPopMatrix(); +} + +// Draw a ray line +void DrawRay(Ray ray, Color color) +{ + float scale = 10000; + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex3f(ray.position.x, ray.position.y, ray.position.z); + rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale); + rlEnd(); +} + +// Draw a grid centered at (0, 0, 0) +void DrawGrid(int slices, float spacing) +{ + int halfSlices = slices/2; + + rlCheckRenderBatchLimit((slices + 2)*4); + + rlBegin(RL_LINES); + for (int i = -halfSlices; i <= halfSlices; i++) + { + if (i == 0) + { + rlColor3f(0.5f, 0.5f, 0.5f); + rlColor3f(0.5f, 0.5f, 0.5f); + rlColor3f(0.5f, 0.5f, 0.5f); + rlColor3f(0.5f, 0.5f, 0.5f); + } + else + { + rlColor3f(0.75f, 0.75f, 0.75f); + rlColor3f(0.75f, 0.75f, 0.75f); + rlColor3f(0.75f, 0.75f, 0.75f); + rlColor3f(0.75f, 0.75f, 0.75f); + } + + rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing); + rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing); + + rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing); + rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing); + } + rlEnd(); +} + +// Load model from files (mesh and material) +Model LoadModel(const char *fileName) +{ + Model model = { 0 }; + +#if defined(SUPPORT_FILEFORMAT_OBJ) + if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName); +#endif +#if defined(SUPPORT_FILEFORMAT_IQM) + if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName); +#endif +#if defined(SUPPORT_FILEFORMAT_GLTF) + if (IsFileExtension(fileName, ".gltf;.glb")) model = LoadGLTF(fileName); +#endif + + // Make sure model transform is set to identity matrix! + model.transform = MatrixIdentity(); + + if (model.meshCount == 0) + { + model.meshCount = 1; + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); +#if defined(SUPPORT_MESH_GENERATION) + TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data, default to cube mesh", fileName); + model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f); +#else + TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data", fileName); +#endif + } + else + { + // Upload vertex data to GPU (static mesh) + for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false); + } + + if (model.materialCount == 0) + { + TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load material data, default to white material", fileName); + + model.materialCount = 1; + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); + model.materials[0] = LoadMaterialDefault(); + + if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); + } + + return model; +} + +// Load model from generated mesh +// WARNING: A shallow copy of mesh is generated, passed by value, +// as long as struct contains pointers to data and some values, we get a copy +// of mesh pointing to same data as original version... be careful! +Model LoadModelFromMesh(Mesh mesh) +{ + Model model = { 0 }; + + model.transform = MatrixIdentity(); + + model.meshCount = 1; + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); + model.meshes[0] = mesh; + + model.materialCount = 1; + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); + model.materials[0] = LoadMaterialDefault(); + + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); + model.meshMaterial[0] = 0; // First material index + + return model; +} + +// Unload model (meshes/materials) from memory (RAM and/or VRAM) +// NOTE: This function takes care of all model elements, for a detailed control +// over them, use UnloadMesh() and UnloadMaterial() +void UnloadModel(Model model) +{ + // Unload meshes + for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]); + + // Unload materials maps + // NOTE: As the user could be sharing shaders and textures between models, + // we don't unload the material but just free it's maps, + // the user is responsible for freeing models shaders and textures + for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); + + // Unload arrays + RL_FREE(model.meshes); + RL_FREE(model.materials); + RL_FREE(model.meshMaterial); + + // Unload animation data + RL_FREE(model.bones); + RL_FREE(model.bindPose); + + TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM"); +} + +// Unload model (but not meshes) from memory (RAM and/or VRAM) +void UnloadModelKeepMeshes(Model model) +{ + // Unload materials maps + // NOTE: As the user could be sharing shaders and textures between models, + // we don't unload the material but just free it's maps, + // the user is responsible for freeing models shaders and textures + for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); + + // Unload arrays + RL_FREE(model.meshes); + RL_FREE(model.materials); + RL_FREE(model.meshMaterial); + + // Unload animation data + RL_FREE(model.bones); + RL_FREE(model.bindPose); + + TRACELOG(LOG_INFO, "MODEL: Unloaded model (but not meshes) from RAM and VRAM"); +} + +// Upload vertex data into a VAO (if supported) and VBO +void UploadMesh(Mesh *mesh, bool dynamic) +{ + if (mesh->vaoId > 0) + { + // Check if mesh has already been loaded in GPU + TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId); + return; + } + + mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int)); + + mesh->vaoId = 0; // Vertex Array Object + mesh->vboId[0] = 0; // Vertex buffer: positions + mesh->vboId[1] = 0; // Vertex buffer: texcoords + mesh->vboId[2] = 0; // Vertex buffer: normals + mesh->vboId[3] = 0; // Vertex buffer: colors + mesh->vboId[4] = 0; // Vertex buffer: tangents + mesh->vboId[5] = 0; // Vertex buffer: texcoords2 + mesh->vboId[6] = 0; // Vertex buffer: indices + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + mesh->vaoId = rlLoadVertexArray(); + rlEnableVertexArray(mesh->vaoId); + + // NOTE: Attributes must be uploaded considering default locations points + + // Enable vertex attributes: position (shader-location = 0) + mesh->vboId[0] = rlLoadVertexBuffer(mesh->vertices, mesh->vertexCount*3*sizeof(float), dynamic); + rlSetVertexAttribute(0, 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(0); + + // Enable vertex attributes: texcoords (shader-location = 1) + mesh->vboId[1] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); + rlSetVertexAttribute(1, 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(1); + + if (mesh->normals != NULL) + { + // Enable vertex attributes: normals (shader-location = 2) + mesh->vboId[2] = rlLoadVertexBuffer(mesh->normals, mesh->vertexCount*3*sizeof(float), dynamic); + rlSetVertexAttribute(2, 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(2); + } + else + { + // Default color vertex attribute set to WHITE + float value[3] = { 1.0f, 1.0f, 1.0f }; + rlSetVertexAttributeDefault(2, value, SHADER_ATTRIB_VEC3, 3); + rlDisableVertexAttribute(2); + } + + if (mesh->colors != NULL) + { + // Enable vertex attribute: color (shader-location = 3) + mesh->vboId[3] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic); + rlSetVertexAttribute(3, 4, RL_UNSIGNED_BYTE, 1, 0, 0); + rlEnableVertexAttribute(3); + } + else + { + // Default color vertex attribute set to WHITE + float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + rlSetVertexAttributeDefault(3, value, SHADER_ATTRIB_VEC4, 4); + rlDisableVertexAttribute(3); + } + + if (mesh->tangents != NULL) + { + // Enable vertex attribute: tangent (shader-location = 4) + mesh->vboId[4] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic); + rlSetVertexAttribute(4, 4, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(4); + } + else + { + // Default tangents vertex attribute + float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + rlSetVertexAttributeDefault(4, value, SHADER_ATTRIB_VEC4, 4); + rlDisableVertexAttribute(4); + } + + if (mesh->texcoords2 != NULL) + { + // Enable vertex attribute: texcoord2 (shader-location = 5) + mesh->vboId[5] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic); + rlSetVertexAttribute(5, 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(5); + } + else + { + // Default texcoord2 vertex attribute + float value[2] = { 0.0f, 0.0f }; + rlSetVertexAttributeDefault(5, value, SHADER_ATTRIB_VEC2, 2); + rlDisableVertexAttribute(5); + } + + if (mesh->indices != NULL) + { + mesh->vboId[6] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic); + } + + if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId); + else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)"); + + rlDisableVertexArray(); +#endif +} + +// Update mesh vertex data in GPU for a specific buffer index +void UpdateMeshBuffer(Mesh mesh, int index, void *data, int dataSize, int offset) +{ + rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset); +} + +// Draw a 3d mesh with material and transform +void DrawMesh(Mesh mesh, Material material, Matrix transform) +{ + DrawMeshInstanced(mesh, material, &transform, 1); +} + +// Draw multiple mesh instances with material and different transforms +void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances) +{ +#if defined(GRAPHICS_API_OPENGL_11) + #define GL_VERTEX_ARRAY 0x8074 + #define GL_NORMAL_ARRAY 0x8075 + #define GL_COLOR_ARRAY 0x8076 + #define GL_TEXTURE_COORD_ARRAY 0x8078 + + rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id); + + rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices); + rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords); + rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals); + rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors); + + rlPushMatrix(); + rlMultMatrixf(MatrixToFloat(transforms[0])); + rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r, + material.maps[MATERIAL_MAP_DIFFUSE].color.g, + material.maps[MATERIAL_MAP_DIFFUSE].color.b, + material.maps[MATERIAL_MAP_DIFFUSE].color.a); + + if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices); + else rlDrawVertexArray(0, mesh.vertexCount); + rlPopMatrix(); + + rlDisableStatePointer(GL_VERTEX_ARRAY); + rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY); + rlDisableStatePointer(GL_NORMAL_ARRAY); + rlDisableStatePointer(GL_COLOR_ARRAY); + + rlDisableTexture(); +#endif + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Check instancing + bool instancing = false; + if (instances < 1) return; + else if (instances > 1) instancing = true; + float16 *instanceTransforms = NULL; + unsigned int instancesVboId = 0; + + // Bind shader program + rlEnableShader(material.shader.id); + + // Send required data to shader (matrices, values) + //----------------------------------------------------- + // Upload to shader material.colDiffuse + if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1) + { + float values[4] = { + (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f, + (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f, + (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f, + (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f + }; + + rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1); + } + + // Upload to shader material.colSpecular (if location available) + if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1) + { + float values[4] = { + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f, + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f, + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f, + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f + }; + + rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); + } + + // Get a copy of current matrices to work with, + // just in case stereo render is required and we need to modify them + // NOTE: At this point the modelview matrix just contains the view matrix (camera) + // That's because BeginMode3D() sets it and there is no model-drawing function + // that modifies it, all use rlPushMatrix() and rlPopMatrix() + Matrix matView = rlGetMatrixModelview(); + Matrix matModelView = matView; + Matrix matProjection = rlGetMatrixProjection(); + + // Upload view and projection matrices (if locations available) + if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView); + if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection); + + if (instancing) + { + // Create instances buffer + instanceTransforms = RL_MALLOC(instances*sizeof(float16)); + + // Fill buffer with instances transformations as float16 arrays + for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]); + + // Enable mesh VAO to attach new buffer + rlEnableVertexArray(mesh.vaoId); + + // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData(). + // It isn't clear which would be reliably faster in all cases and on all platforms, + // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems + // no faster, since we're transferring all the transform matrices anyway + instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false); + + // Instances transformation matrices are send to shader attribute location: SHADER_LOC_MATRIX_MODEL + for (unsigned int i = 0; i < 4; i++) + { + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 4, RL_FLOAT, 0, sizeof(Matrix), (void *)(i*sizeof(Vector4))); + rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 1); + } + + rlDisableVertexBuffer(); + rlDisableVertexArray(); + + // Accumulate internal matrix transform (push/pop) and view matrix + // NOTE: In this case, model instance transformation must be computed in the shader + matModelView = MatrixMultiply(rlGetMatrixTransform(), matView); + } + else + { + // Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL + if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transforms[0]); + + // Accumulate several transformations: + // matView: rlgl internal modelview matrix (actually, just view matrix) + // rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack + // transform: function parameter transformation + matModelView = MatrixMultiply(transforms[0], MatrixMultiply(rlGetMatrixTransform(), matView)); + } + + // Upload model normal matrix (if locations available) + if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModelView))); + //----------------------------------------------------- + + // Bind active texture maps (if available) + for (int i = 0; i < MAX_MATERIAL_MAPS; i++) + { + if (material.maps[i].texture.id > 0) + { + // Select current shader texture slot + rlActiveTextureSlot(i); + + // Enable texture for active slot + if ((i == MATERIAL_MAP_IRRADIANCE) || + (i == MATERIAL_MAP_PREFILTER) || + (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id); + else rlEnableTexture(material.maps[i].texture.id); + + rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1); + } + } + + // Try binding vertex array objects (VAO) + // or use VBOs if not possible + if (!rlEnableVertexArray(mesh.vaoId)) + { + // Bind mesh VBO data: vertex position (shader-location = 0) + rlEnableVertexBuffer(mesh.vboId[0]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); + + rlEnableVertexBuffer(mesh.vboId[0]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); + + // Bind mesh VBO data: vertex texcoords (shader-location = 1) + rlEnableVertexBuffer(mesh.vboId[1]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); + + if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) + { + // Bind mesh VBO data: vertex normals (shader-location = 2) + rlEnableVertexBuffer(mesh.vboId[2]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); + } + + // Bind mesh VBO data: vertex colors (shader-location = 3, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) + { + if (mesh.vboId[3] != 0) + { + rlEnableVertexBuffer(mesh.vboId[3]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); + } + else + { + // Set default value for unused attribute + // NOTE: Required when using default shader and no VAO support + float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC2, 4); + rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); + } + } + + // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) + { + rlEnableVertexBuffer(mesh.vboId[4]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); + } + + // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) + { + rlEnableVertexBuffer(mesh.vboId[5]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); + } + + if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); + } + + int eyesCount = 1; + if (rlIsStereoRenderEnabled()) eyesCount = 2; + + for (int eye = 0; eye < eyesCount; eye++) + { + // Calculate model-view-projection matrix (MVP) + Matrix matMVP = MatrixIdentity(); + if (eyesCount == 1) matMVP = MatrixMultiply(matModelView, matProjection); + else + { + // Setup current eye viewport (half screen width) + rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight()); + matMVP = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye)); + } + + // Send combined model-view-projection matrix to shader + rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matMVP); + + if (instancing) // Draw mesh instanced + { + if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances); + else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances); + } + else // Draw mesh + { + if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0); + else rlDrawVertexArray(0, mesh.vertexCount); + } + } + + // Unbind all binded texture maps + for (int i = 0; i < MAX_MATERIAL_MAPS; i++) + { + // Select current shader texture slot + rlActiveTextureSlot(i); + + // Disable texture for active slot + if ((i == MATERIAL_MAP_IRRADIANCE) || + (i == MATERIAL_MAP_PREFILTER) || + (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); + else rlDisableTexture(); + } + + // Disable all possible vertex array objects (or VBOs) + rlDisableVertexArray(); + rlDisableVertexBuffer(); + rlDisableVertexBufferElement(); + + // Disable shader program + rlDisableShader(); + + if (instancing) + { + // Remove instance transforms buffer + rlUnloadVertexBuffer(instancesVboId); + RL_FREE(instanceTransforms); + } + else + { + // Restore rlgl internal modelview and projection matrices + rlSetMatrixModelview(matView); + rlSetMatrixProjection(matProjection); + } +#endif +} + +// Unload mesh from memory (RAM and VRAM) +void UnloadMesh(Mesh mesh) +{ + // Unload rlgl mesh vboId data + rlUnloadVertexArray(mesh.vaoId); + + for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]); + RL_FREE(mesh.vboId); + + RL_FREE(mesh.vertices); + RL_FREE(mesh.texcoords); + RL_FREE(mesh.normals); + RL_FREE(mesh.colors); + RL_FREE(mesh.tangents); + RL_FREE(mesh.texcoords2); + RL_FREE(mesh.indices); + + RL_FREE(mesh.animVertices); + RL_FREE(mesh.animNormals); + RL_FREE(mesh.boneWeights); + RL_FREE(mesh.boneIds); +} + +// Export mesh data to file +bool ExportMesh(Mesh mesh, const char *fileName) +{ + bool success = false; + + if (IsFileExtension(fileName, ".obj")) + { + // Estimated data size, it should be enough... + int dataSize = mesh.vertexCount/3* (int)strlen("v 0000.00f 0000.00f 0000.00f") + + mesh.vertexCount/2* (int)strlen("vt 0.000f 0.00f") + + mesh.vertexCount/3* (int)strlen("vn 0.000f 0.00f 0.00f") + + mesh.triangleCount/3* (int)strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000"); + + // NOTE: Text data buffer size is estimated considering mesh data size + char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char)); + + int bytesCount = 0; + bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n"); + bytesCount += sprintf(txtData + bytesCount, "# // //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // feedback and support: ray[at]raylib.com //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n"); + bytesCount += sprintf(txtData + bytesCount, "# // //\n"); + bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); + bytesCount += sprintf(txtData + bytesCount, "# Vertex Count: %i\n", mesh.vertexCount); + bytesCount += sprintf(txtData + bytesCount, "# Triangle Count: %i\n\n", mesh.triangleCount); + + bytesCount += sprintf(txtData + bytesCount, "g mesh\n"); + + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) + { + bytesCount += sprintf(txtData + bytesCount, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); + } + + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2) + { + bytesCount += sprintf(txtData + bytesCount, "vt %.3f %.3f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); + } + + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) + { + bytesCount += sprintf(txtData + bytesCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); + } + + for (int i = 0; i < mesh.triangleCount; i += 3) + { + bytesCount += sprintf(txtData + bytesCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2); + } + + bytesCount += sprintf(txtData + bytesCount, "\n"); + + // NOTE: Text data length exported is determined by '\0' (NULL) character + success = SaveFileText(fileName, txtData); + + RL_FREE(txtData); + } + else if (IsFileExtension(fileName, ".raw")) + { + // TODO: Support additional file formats to export mesh vertex data + } + + return success; +} + + +// Load materials from model file +Material *LoadMaterials(const char *fileName, int *materialCount) +{ + Material *materials = NULL; + unsigned int count = 0; + + // TODO: Support IQM and GLTF for materials parsing + +#if defined(SUPPORT_FILEFORMAT_MTL) + if (IsFileExtension(fileName, ".mtl")) + { + tinyobj_material_t *mats = NULL; + + int result = tinyobj_parse_mtl_file(&mats, &count, fileName); + if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName); + + // TODO: Process materials to return + + tinyobj_materials_free(mats, count); + } +#else + TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName); +#endif + + // Set materials shader to default (DIFFUSE, SPECULAR, NORMAL) + if (materials != NULL) + { + for (unsigned int i = 0; i < count; i++) materials[i].shader = rlGetShaderDefault(); + } + + *materialCount = count; + return materials; +} + +// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +Material LoadMaterialDefault(void) +{ + Material material = { 0 }; + material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap)); + + material.shader = rlGetShaderDefault(); + material.maps[MATERIAL_MAP_DIFFUSE].texture = rlGetTextureDefault(); // White texture (1x1 pixel) + //material.maps[MATERIAL_MAP_NORMAL].texture; // NOTE: By default, not set + //material.maps[MATERIAL_MAP_SPECULAR].texture; // NOTE: By default, not set + + material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE; // Diffuse color + material.maps[MATERIAL_MAP_SPECULAR].color = WHITE; // Specular color + + return material; +} + +// Unload material from memory +void UnloadMaterial(Material material) +{ + // Unload material shader (avoid unloading default shader, managed by raylib) + if (material.shader.id != rlGetShaderDefault().id) UnloadShader(material.shader); + + // Unload loaded texture maps (avoid unloading default texture, managed by raylib) + for (int i = 0; i < MAX_MATERIAL_MAPS; i++) + { + if (material.maps[i].texture.id != rlGetTextureDefault().id) rlUnloadTexture(material.maps[i].texture.id); + } + + RL_FREE(material.maps); +} + +// Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) +// NOTE: Previous texture should be manually unloaded +void SetMaterialTexture(Material *material, int mapType, Texture2D texture) +{ + material->maps[mapType].texture = texture; +} + +// Set the material for a mesh +void SetModelMeshMaterial(Model *model, int meshId, int materialId) +{ + if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count"); + else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count"); + else model->meshMaterial[meshId] = materialId; +} + +// Load model animations from file +ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount) +{ + ModelAnimation *animations = NULL; + +#if defined(SUPPORT_FILEFORMAT_IQM) + if (IsFileExtension(fileName, ".iqm")) animations = LoadIQMModelAnimations(fileName, animCount); +#endif +#if defined(SUPPORT_FILEFORMAT_GLTF) + if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadGLTFModelAnimations(fileName, animCount); +#endif + + return animations; +} + +// Update model animated vertex data (positions and normals) for a given frame +// NOTE: Updated data is uploaded to GPU +void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) +{ + if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL)) + { + if (frame >= anim.frameCount) frame = frame%anim.frameCount; + + for (int m = 0; m < model.meshCount; m++) + { + Vector3 animVertex = { 0 }; + Vector3 animNormal = { 0 }; + + Vector3 inTranslation = { 0 }; + Quaternion inRotation = { 0 }; + //Vector3 inScale = { 0 }; // Not used... + + Vector3 outTranslation = { 0 }; + Quaternion outRotation = { 0 }; + Vector3 outScale = { 0 }; + + int vCounter = 0; + int boneCounter = 0; + int boneId = 0; + float boneWeight = 0.0; + + for (int i = 0; i < model.meshes[m].vertexCount; i++) + { + model.meshes[m].animVertices[vCounter] = 0; + model.meshes[m].animVertices[vCounter + 1] = 0; + model.meshes[m].animVertices[vCounter + 2] = 0; + + model.meshes[m].animNormals[vCounter] = 0; + model.meshes[m].animNormals[vCounter + 1] = 0; + model.meshes[m].animNormals[vCounter + 2] = 0; + + for (int j = 0; j < 4; j++) + { + boneId = model.meshes[m].boneIds[boneCounter]; + boneWeight = model.meshes[m].boneWeights[boneCounter]; + inTranslation = model.bindPose[boneId].translation; + inRotation = model.bindPose[boneId].rotation; + //inScale = model.bindPose[boneId].scale; + outTranslation = anim.framePoses[frame][boneId].translation; + outRotation = anim.framePoses[frame][boneId].rotation; + outScale = anim.framePoses[frame][boneId].scale; + + // Vertices processing + // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position) + animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] }; + animVertex = Vector3Multiply(animVertex, outScale); + animVertex = Vector3Subtract(animVertex, inTranslation); + animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); + animVertex = Vector3Add(animVertex, outTranslation); + model.meshes[m].animVertices[vCounter] += animVertex.x * boneWeight; + model.meshes[m].animVertices[vCounter + 1] += animVertex.y * boneWeight; + model.meshes[m].animVertices[vCounter + 2] += animVertex.z * boneWeight; + + // Normals processing + // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) + if (model.meshes[m].normals != NULL) + { + animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] }; + animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); + model.meshes[m].animNormals[vCounter] += animNormal.x * boneWeight; + model.meshes[m].animNormals[vCounter + 1] += animNormal.y * boneWeight; + model.meshes[m].animNormals[vCounter + 2] += animNormal.z * boneWeight; + } + boneCounter += 1; + } + vCounter += 3; + } + + // Upload new vertex data to GPU for model drawing + rlUpdateVertexBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float), 0); // Update vertex position + rlUpdateVertexBuffer(model.meshes[m].vboId[2], model.meshes[m].animNormals, model.meshes[m].vertexCount*3*sizeof(float), 0); // Update vertex normals + } + } +} + +// Unload animation array data +void UnloadModelAnimations(ModelAnimation* animations, unsigned int count) +{ + for (unsigned int i = 0; i < count; i++) UnloadModelAnimation(animations[i]); + RL_FREE(animations); +} + +// Unload animation data +void UnloadModelAnimation(ModelAnimation anim) +{ + for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]); + + RL_FREE(anim.bones); + RL_FREE(anim.framePoses); +} + +// Check model animation skeleton match +// NOTE: Only number of bones and parent connections are checked +bool IsModelAnimationValid(Model model, ModelAnimation anim) +{ + int result = true; + + if (model.boneCount != anim.boneCount) result = false; + else + { + for (int i = 0; i < model.boneCount; i++) + { + if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; } + } + } + + return result; +} + +#if defined(SUPPORT_MESH_GENERATION) +// Generate polygonal mesh +Mesh GenMeshPoly(int sides, float radius) +{ + Mesh mesh = { 0 }; + + if (sides < 3) return mesh; + + int vertexCount = sides*3; + + // Vertices definition + Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); + + float d = 0.0f, dStep = 360.0f/sides; + for (int v = 0; v < vertexCount; v += 3) + { + vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f }; + vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius }; + vertices[v + 2] = (Vector3){sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius }; + d += dStep; + } + + // Normals definition + Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); + for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; + + // TexCoords definition + Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2)); + for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f }; + + mesh.vertexCount = vertexCount; + mesh.triangleCount = sides; + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + + // Mesh vertices position array + for (int i = 0; i < mesh.vertexCount; i++) + { + mesh.vertices[3*i] = vertices[i].x; + mesh.vertices[3*i + 1] = vertices[i].y; + mesh.vertices[3*i + 2] = vertices[i].z; + } + + // Mesh texcoords array + for (int i = 0; i < mesh.vertexCount; i++) + { + mesh.texcoords[2*i] = texcoords[i].x; + mesh.texcoords[2*i + 1] = texcoords[i].y; + } + + // Mesh normals array + for (int i = 0; i < mesh.vertexCount; i++) + { + mesh.normals[3*i] = normals[i].x; + mesh.normals[3*i + 1] = normals[i].y; + mesh.normals[3*i + 2] = normals[i].z; + } + + RL_FREE(vertices); + RL_FREE(normals); + RL_FREE(texcoords); + + // Upload vertex data to GPU (static mesh) + // NOTE: mesh.vboId array is allocated inside UploadMesh() + UploadMesh(&mesh, false); + + return mesh; +} + +// Generate plane mesh (with subdivisions) +Mesh GenMeshPlane(float width, float length, int resX, int resZ) +{ + Mesh mesh = { 0 }; + +#define CUSTOM_MESH_GEN_PLANE +#if defined(CUSTOM_MESH_GEN_PLANE) + resX++; + resZ++; + + // Vertices definition + int vertexCount = resX*resZ; // vertices get reused for the faces + + Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); + for (int z = 0; z < resZ; z++) + { + // [-length/2, length/2] + float zPos = ((float)z/(resZ - 1) - 0.5f)*length; + for (int x = 0; x < resX; x++) + { + // [-width/2, width/2] + float xPos = ((float)x/(resX - 1) - 0.5f)*width; + vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos }; + } + } + + // Normals definition + Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); + for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; + + // TexCoords definition + Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2)); + for (int v = 0; v < resZ; v++) + { + for (int u = 0; u < resX; u++) + { + texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) }; + } + } + + // Triangles definition (indices) + int numFaces = (resX - 1)*(resZ - 1); + int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int)); + int t = 0; + for (int face = 0; face < numFaces; face++) + { + // Retrieve lower left corner from face ind + int i = face % (resX - 1) + (face/(resZ - 1)*resX); + + triangles[t++] = i + resX; + triangles[t++] = i + 1; + triangles[t++] = i; + + triangles[t++] = i + resX; + triangles[t++] = i + resX + 1; + triangles[t++] = i + 1; + } + + mesh.vertexCount = vertexCount; + mesh.triangleCount = numFaces*2; + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short)); + + // Mesh vertices position array + for (int i = 0; i < mesh.vertexCount; i++) + { + mesh.vertices[3*i] = vertices[i].x; + mesh.vertices[3*i + 1] = vertices[i].y; + mesh.vertices[3*i + 2] = vertices[i].z; + } + + // Mesh texcoords array + for (int i = 0; i < mesh.vertexCount; i++) + { + mesh.texcoords[2*i] = texcoords[i].x; + mesh.texcoords[2*i + 1] = texcoords[i].y; + } + + // Mesh normals array + for (int i = 0; i < mesh.vertexCount; i++) + { + mesh.normals[3*i] = normals[i].x; + mesh.normals[3*i + 1] = normals[i].y; + mesh.normals[3*i + 2] = normals[i].z; + } + + // Mesh indices array initialization + for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i]; + + RL_FREE(vertices); + RL_FREE(normals); + RL_FREE(texcoords); + RL_FREE(triangles); + +#else // Use par_shapes library to generate plane mesh + + par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!! + par_shapes_scale(plane, width, length, 1.0f); + par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 }); + par_shapes_translate(plane, -width/2, 0.0f, length/2); + + mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = plane->ntriangles*3; + mesh.triangleCount = plane->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = plane->points[plane->triangles[k]*3]; + mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2]; + + mesh.normals[k*3] = plane->normals[plane->triangles[k]*3]; + mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(plane); +#endif + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + + return mesh; +} + +// Generated cuboid mesh +Mesh GenMeshCube(float width, float height, float length) +{ + Mesh mesh = { 0 }; + +#define CUSTOM_MESH_GEN_CUBE +#if defined(CUSTOM_MESH_GEN_CUBE) + float vertices[] = { + -width/2, -height/2, length/2, + width/2, -height/2, length/2, + width/2, height/2, length/2, + -width/2, height/2, length/2, + -width/2, -height/2, -length/2, + -width/2, height/2, -length/2, + width/2, height/2, -length/2, + width/2, -height/2, -length/2, + -width/2, height/2, -length/2, + -width/2, height/2, length/2, + width/2, height/2, length/2, + width/2, height/2, -length/2, + -width/2, -height/2, -length/2, + width/2, -height/2, -length/2, + width/2, -height/2, length/2, + -width/2, -height/2, length/2, + width/2, -height/2, -length/2, + width/2, height/2, -length/2, + width/2, height/2, length/2, + width/2, -height/2, length/2, + -width/2, -height/2, -length/2, + -width/2, -height/2, length/2, + -width/2, height/2, length/2, + -width/2, height/2, -length/2 + }; + + float texcoords[] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f + }; + + float normals[] = { + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f,-1.0f, + 0.0f, 0.0f,-1.0f, + 0.0f, 0.0f,-1.0f, + 0.0f, 0.0f,-1.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f,-1.0f, 0.0f, + 0.0f,-1.0f, 0.0f, + 0.0f,-1.0f, 0.0f, + 0.0f,-1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f + }; + + mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float)); + memcpy(mesh.vertices, vertices, 24*3*sizeof(float)); + + mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float)); + memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float)); + + mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float)); + memcpy(mesh.normals, normals, 24*3*sizeof(float)); + + mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short)); + + int k = 0; + + // Indices can be initialized right now + for (int i = 0; i < 36; i+=6) + { + mesh.indices[i] = 4*k; + mesh.indices[i+1] = 4*k+1; + mesh.indices[i+2] = 4*k+2; + mesh.indices[i+3] = 4*k; + mesh.indices[i+4] = 4*k+2; + mesh.indices[i+5] = 4*k+3; + + k++; + } + + mesh.vertexCount = 24; + mesh.triangleCount = 12; + +#else // Use par_shapes library to generate cube mesh +/* +// Platonic solids: +par_shapes_mesh* par_shapes_create_tetrahedron(); // 4 sides polyhedron (pyramid) +par_shapes_mesh* par_shapes_create_cube(); // 6 sides polyhedron (cube) +par_shapes_mesh* par_shapes_create_octahedron(); // 8 sides polyhedron (dyamond) +par_shapes_mesh* par_shapes_create_dodecahedron(); // 12 sides polyhedron +par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron +*/ + // Platonic solid generation: cube (6 sides) + // NOTE: No normals/texcoords generated by default + par_shapes_mesh *cube = par_shapes_create_cube(); + cube->tcoords = PAR_MALLOC(float, 2*cube->npoints); + for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f; + par_shapes_scale(cube, width, height, length); + par_shapes_translate(cube, -width/2, 0.0f, -length/2); + par_shapes_compute_normals(cube); + + mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = cube->ntriangles*3; + mesh.triangleCount = cube->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = cube->points[cube->triangles[k]*3]; + mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2]; + + mesh.normals[k*3] = cube->normals[cube->triangles[k]*3]; + mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(cube); +#endif + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + + return mesh; +} + +// Generate sphere mesh (standard sphere) +Mesh GenMeshSphere(float radius, int rings, int slices) +{ + Mesh mesh = { 0 }; + + if ((rings >= 3) && (slices >= 3)) + { + par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings); + par_shapes_scale(sphere, radius, radius, radius); + // NOTE: Soft normals are computed internally + + mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = sphere->ntriangles*3; + mesh.triangleCount = sphere->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; + mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; + + mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; + mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(sphere); + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + } + else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere"); + + return mesh; +} + +// Generate hemi-sphere mesh (half sphere, no bottom cap) +Mesh GenMeshHemiSphere(float radius, int rings, int slices) +{ + Mesh mesh = { 0 }; + + if ((rings >= 3) && (slices >= 3)) + { + if (radius < 0.0f) radius = 0.0f; + + par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings); + par_shapes_scale(sphere, radius, radius, radius); + // NOTE: Soft normals are computed internally + + mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = sphere->ntriangles*3; + mesh.triangleCount = sphere->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; + mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; + + mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; + mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(sphere); + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + } + else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere"); + + return mesh; +} + +// Generate cylinder mesh +Mesh GenMeshCylinder(float radius, float height, int slices) +{ + Mesh mesh = { 0 }; + + if (slices >= 3) + { + // Instance a cylinder that sits on the Z=0 plane using the given tessellation + // levels across the UV domain. Think of "slices" like a number of pizza + // slices, and "stacks" like a number of stacked rings. + // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale + par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8); + par_shapes_scale(cylinder, radius, radius, height); + par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 }); + par_shapes_rotate(cylinder, PI/2.0f, (float[]){ 0, 1, 0 }); + + // Generate an orientable disk shape (top cap) + par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 }); + capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints); + for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f; + par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 }); + par_shapes_translate(capTop, 0, height, 0); + + // Generate an orientable disk shape (bottom cap) + par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 }); + capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints); + for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f; + par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 }); + + par_shapes_merge_and_free(cylinder, capTop); + par_shapes_merge_and_free(cylinder, capBottom); + + mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = cylinder->ntriangles*3; + mesh.triangleCount = cylinder->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3]; + mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2]; + + mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3]; + mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(cylinder); + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + } + else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder"); + + return mesh; +} + +// Generate torus mesh +Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) +{ + Mesh mesh = { 0 }; + + if ((sides >= 3) && (radSeg >= 3)) + { + if (radius > 1.0f) radius = 1.0f; + else if (radius < 0.1f) radius = 0.1f; + + // Create a donut that sits on the Z=0 plane with the specified inner radius + // The outer radius can be controlled with par_shapes_scale + par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius); + par_shapes_scale(torus, size/2, size/2, size/2); + + mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = torus->ntriangles*3; + mesh.triangleCount = torus->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = torus->points[torus->triangles[k]*3]; + mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2]; + + mesh.normals[k*3] = torus->normals[torus->triangles[k]*3]; + mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(torus); + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + } + else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus"); + + return mesh; +} + +// Generate trefoil knot mesh +Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) +{ + Mesh mesh = { 0 }; + + if ((sides >= 3) && (radSeg >= 3)) + { + if (radius > 3.0f) radius = 3.0f; + else if (radius < 0.5f) radius = 0.5f; + + par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius); + par_shapes_scale(knot, size, size, size); + + mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float)); + + mesh.vertexCount = knot->ntriangles*3; + mesh.triangleCount = knot->ntriangles; + + for (int k = 0; k < mesh.vertexCount; k++) + { + mesh.vertices[k*3] = knot->points[knot->triangles[k]*3]; + mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1]; + mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2]; + + mesh.normals[k*3] = knot->normals[knot->triangles[k]*3]; + mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1]; + mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2]; + + mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2]; + mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1]; + } + + par_shapes_free_mesh(knot); + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + } + else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot"); + + return mesh; +} + +// Generate a mesh from heightmap +// NOTE: Vertex data is uploaded to GPU +Mesh GenMeshHeightmap(Image heightmap, Vector3 size) +{ + #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) + + Mesh mesh = { 0 }; + + int mapX = heightmap.width; + int mapZ = heightmap.height; + + Color *pixels = LoadImageColors(heightmap); + + // NOTE: One vertex per pixel + mesh.triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels + + mesh.vertexCount = mesh.triangleCount*3; + + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.colors = NULL; + + int vCounter = 0; // Used to count vertices float by float + int tcCounter = 0; // Used to count texcoords float by float + int nCounter = 0; // Used to count normals float by float + + int trisCounter = 0; + + Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ }; + + Vector3 vA = { 0 }; + Vector3 vB = { 0 }; + Vector3 vC = { 0 }; + Vector3 vN = { 0 }; + + for (int z = 0; z < mapZ-1; z++) + { + for (int x = 0; x < mapX-1; x++) + { + // Fill vertices array with data + //---------------------------------------------------------- + + // one triangle - 3 vertex + mesh.vertices[vCounter] = (float)x*scaleFactor.x; + mesh.vertices[vCounter + 1] = (float)GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z; + + mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x; + mesh.vertices[vCounter + 4] = (float)GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z; + + mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x; + mesh.vertices[vCounter + 7] = (float)GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z; + + // another triangle - 3 vertex + mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6]; + mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7]; + mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8]; + + mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3]; + mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4]; + mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5]; + + mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x; + mesh.vertices[vCounter + 16] = (float)GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z; + vCounter += 18; // 6 vertex, 18 floats + + // Fill texcoords array with data + //-------------------------------------------------------------- + mesh.texcoords[tcCounter] = (float)x/(mapX - 1); + mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1); + + mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1); + mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1); + + mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1); + mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1); + + mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4]; + mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5]; + + mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2]; + mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3]; + + mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1); + mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1); + tcCounter += 12; // 6 texcoords, 12 floats + + // Fill normals array with data + //-------------------------------------------------------------- + for (int i = 0; i < 18; i += 9) + { + vA.x = mesh.vertices[nCounter + i]; + vA.y = mesh.vertices[nCounter + i + 1]; + vA.z = mesh.vertices[nCounter + i + 2]; + + vB.x = mesh.vertices[nCounter + i + 3]; + vB.y = mesh.vertices[nCounter + i + 4]; + vB.z = mesh.vertices[nCounter + i + 5]; + + vC.x = mesh.vertices[nCounter + i + 6]; + vC.y = mesh.vertices[nCounter + i + 7]; + vC.z = mesh.vertices[nCounter + i + 8]; + + vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA))); + + mesh.normals[nCounter + i] = vN.x; + mesh.normals[nCounter + i + 1] = vN.y; + mesh.normals[nCounter + i + 2] = vN.z; + + mesh.normals[nCounter + i + 3] = vN.x; + mesh.normals[nCounter + i + 4] = vN.y; + mesh.normals[nCounter + i + 5] = vN.z; + + mesh.normals[nCounter + i + 6] = vN.x; + mesh.normals[nCounter + i + 7] = vN.y; + mesh.normals[nCounter + i + 8] = vN.z; + } + + nCounter += 18; // 6 vertex, 18 floats + trisCounter += 2; + } + } + + UnloadImageColors(pixels); // Unload pixels color data + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + + return mesh; +} + +// Generate a cubes mesh from pixel data +// NOTE: Vertex data is uploaded to GPU +Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) +{ + #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) + + Mesh mesh = { 0 }; + + Color *pixels = LoadImageColors(cubicmap); + + int mapWidth = cubicmap.width; + int mapHeight = cubicmap.height; + + // NOTE: Max possible number of triangles numCubes*(12 triangles by cube) + int maxTriangles = cubicmap.width*cubicmap.height*12; + + int vCounter = 0; // Used to count vertices + int tcCounter = 0; // Used to count texcoords + int nCounter = 0; // Used to count normals + + float w = cubeSize.x; + float h = cubeSize.z; + float h2 = cubeSize.y; + + Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3)); + Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2)); + Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3)); + + // Define the 6 normals of the cube, we will combine them accordingly later... + Vector3 n1 = { 1.0f, 0.0f, 0.0f }; + Vector3 n2 = { -1.0f, 0.0f, 0.0f }; + Vector3 n3 = { 0.0f, 1.0f, 0.0f }; + Vector3 n4 = { 0.0f, -1.0f, 0.0f }; + Vector3 n5 = { 0.0f, 0.0f, -1.0f }; + Vector3 n6 = { 0.0f, 0.0f, 1.0f }; + + // NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6) + typedef struct RectangleF { + float x; + float y; + float width; + float height; + } RectangleF; + + RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f }; + RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f }; + RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f }; + RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f }; + RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f }; + RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f }; + + for (int z = 0; z < mapHeight; ++z) + { + for (int x = 0; x < mapWidth; ++x) + { + // Define the 8 vertex of the cube, we will combine them accordingly later... + Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) }; + Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) }; + Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) }; + Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) }; + Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) }; + Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) }; + Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) }; + Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) }; + + // We check pixel color to be WHITE -> draw full cube + if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE)) + { + // Define triangles and checking collateral cubes + //------------------------------------------------ + + // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4) + // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside + mapVertices[vCounter] = v1; + mapVertices[vCounter + 1] = v2; + mapVertices[vCounter + 2] = v3; + mapVertices[vCounter + 3] = v1; + mapVertices[vCounter + 4] = v3; + mapVertices[vCounter + 5] = v4; + vCounter += 6; + + mapNormals[nCounter] = n3; + mapNormals[nCounter + 1] = n3; + mapNormals[nCounter + 2] = n3; + mapNormals[nCounter + 3] = n3; + mapNormals[nCounter + 4] = n3; + mapNormals[nCounter + 5] = n3; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; + mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; + mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y }; + tcCounter += 6; + + // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8) + mapVertices[vCounter] = v6; + mapVertices[vCounter + 1] = v8; + mapVertices[vCounter + 2] = v7; + mapVertices[vCounter + 3] = v6; + mapVertices[vCounter + 4] = v5; + mapVertices[vCounter + 5] = v8; + vCounter += 6; + + mapNormals[nCounter] = n4; + mapNormals[nCounter + 1] = n4; + mapNormals[nCounter + 2] = n4; + mapNormals[nCounter + 3] = n4; + mapNormals[nCounter + 4] = n4; + mapNormals[nCounter + 5] = n4; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height }; + mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y }; + mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; + tcCounter += 6; + + // Checking cube on bottom of current cube + if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1)) + { + // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8 + // NOTE: Collateral occluded faces are not generated + mapVertices[vCounter] = v2; + mapVertices[vCounter + 1] = v7; + mapVertices[vCounter + 2] = v3; + mapVertices[vCounter + 3] = v3; + mapVertices[vCounter + 4] = v7; + mapVertices[vCounter + 5] = v8; + vCounter += 6; + + mapNormals[nCounter] = n6; + mapNormals[nCounter + 1] = n6; + mapNormals[nCounter + 2] = n6; + mapNormals[nCounter + 3] = n6; + mapNormals[nCounter + 4] = n6; + mapNormals[nCounter + 5] = n6; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y }; + mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height }; + mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height }; + tcCounter += 6; + } + + // Checking cube on top of current cube + if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0)) + { + // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5 + // NOTE: Collateral occluded faces are not generated + mapVertices[vCounter] = v1; + mapVertices[vCounter + 1] = v5; + mapVertices[vCounter + 2] = v6; + mapVertices[vCounter + 3] = v1; + mapVertices[vCounter + 4] = v4; + mapVertices[vCounter + 5] = v5; + vCounter += 6; + + mapNormals[nCounter] = n5; + mapNormals[nCounter + 1] = n5; + mapNormals[nCounter + 2] = n5; + mapNormals[nCounter + 3] = n5; + mapNormals[nCounter + 4] = n5; + mapNormals[nCounter + 5] = n5; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height }; + mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y }; + mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height }; + tcCounter += 6; + } + + // Checking cube on right of current cube + if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1)) + { + // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5 + // NOTE: Collateral occluded faces are not generated + mapVertices[vCounter] = v3; + mapVertices[vCounter + 1] = v8; + mapVertices[vCounter + 2] = v4; + mapVertices[vCounter + 3] = v4; + mapVertices[vCounter + 4] = v8; + mapVertices[vCounter + 5] = v5; + vCounter += 6; + + mapNormals[nCounter] = n1; + mapNormals[nCounter + 1] = n1; + mapNormals[nCounter + 2] = n1; + mapNormals[nCounter + 3] = n1; + mapNormals[nCounter + 4] = n1; + mapNormals[nCounter + 5] = n1; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y }; + mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height }; + mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height }; + tcCounter += 6; + } + + // Checking cube on left of current cube + if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0)) + { + // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7 + // NOTE: Collateral occluded faces are not generated + mapVertices[vCounter] = v1; + mapVertices[vCounter + 1] = v7; + mapVertices[vCounter + 2] = v2; + mapVertices[vCounter + 3] = v1; + mapVertices[vCounter + 4] = v6; + mapVertices[vCounter + 5] = v7; + vCounter += 6; + + mapNormals[nCounter] = n2; + mapNormals[nCounter + 1] = n2; + mapNormals[nCounter + 2] = n2; + mapNormals[nCounter + 3] = n2; + mapNormals[nCounter + 4] = n2; + mapNormals[nCounter + 5] = n2; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y }; + mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height }; + mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height }; + tcCounter += 6; + } + } + // We check pixel color to be BLACK, we will only draw floor and roof + else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK)) + { + // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4) + mapVertices[vCounter] = v1; + mapVertices[vCounter + 1] = v3; + mapVertices[vCounter + 2] = v2; + mapVertices[vCounter + 3] = v1; + mapVertices[vCounter + 4] = v4; + mapVertices[vCounter + 5] = v3; + vCounter += 6; + + mapNormals[nCounter] = n4; + mapNormals[nCounter + 1] = n4; + mapNormals[nCounter + 2] = n4; + mapNormals[nCounter + 3] = n4; + mapNormals[nCounter + 4] = n4; + mapNormals[nCounter + 5] = n4; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height }; + mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y }; + mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; + tcCounter += 6; + + // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8) + mapVertices[vCounter] = v6; + mapVertices[vCounter + 1] = v7; + mapVertices[vCounter + 2] = v8; + mapVertices[vCounter + 3] = v6; + mapVertices[vCounter + 4] = v8; + mapVertices[vCounter + 5] = v5; + vCounter += 6; + + mapNormals[nCounter] = n3; + mapNormals[nCounter + 1] = n3; + mapNormals[nCounter + 2] = n3; + mapNormals[nCounter + 3] = n3; + mapNormals[nCounter + 4] = n3; + mapNormals[nCounter + 5] = n3; + nCounter += 6; + + mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; + mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height }; + mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; + mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; + mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; + mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y }; + tcCounter += 6; + } + } + } + + // Move data from mapVertices temp arays to vertices float array + mesh.vertexCount = vCounter; + mesh.triangleCount = vCounter/3; + + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.colors = NULL; + + int fCounter = 0; + + // Move vertices data + for (int i = 0; i < vCounter; i++) + { + mesh.vertices[fCounter] = mapVertices[i].x; + mesh.vertices[fCounter + 1] = mapVertices[i].y; + mesh.vertices[fCounter + 2] = mapVertices[i].z; + fCounter += 3; + } + + fCounter = 0; + + // Move normals data + for (int i = 0; i < nCounter; i++) + { + mesh.normals[fCounter] = mapNormals[i].x; + mesh.normals[fCounter + 1] = mapNormals[i].y; + mesh.normals[fCounter + 2] = mapNormals[i].z; + fCounter += 3; + } + + fCounter = 0; + + // Move texcoords data + for (int i = 0; i < tcCounter; i++) + { + mesh.texcoords[fCounter] = mapTexcoords[i].x; + mesh.texcoords[fCounter + 1] = mapTexcoords[i].y; + fCounter += 2; + } + + RL_FREE(mapVertices); + RL_FREE(mapNormals); + RL_FREE(mapTexcoords); + + UnloadImageColors(pixels); // Unload pixels color data + + // Upload vertex data to GPU (static mesh) + UploadMesh(&mesh, false); + + return mesh; +} +#endif // SUPPORT_MESH_GENERATION + +// Compute mesh bounding box limits +// NOTE: minVertex and maxVertex should be transformed by model transform matrix +BoundingBox GetMeshBoundingBox(Mesh mesh) +{ + // Get min and max vertex to construct bounds (AABB) + Vector3 minVertex = { 0 }; + Vector3 maxVertex = { 0 }; + + if (mesh.vertices != NULL) + { + minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; + maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; + + for (int i = 1; i < mesh.vertexCount; i++) + { + minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); + maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); + } + } + + // Create the bounding box + BoundingBox box = { 0 }; + box.min = minVertex; + box.max = maxVertex; + + return box; +} + +// Compute mesh tangents +// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates +// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html +void MeshTangents(Mesh *mesh) +{ + if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float)); + else TRACELOG(LOG_WARNING, "MESH: Tangents data already available, re-writting"); + + Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3)); + Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3)); + + for (int i = 0; i < mesh->vertexCount; i += 3) + { + // Get triangle vertices + Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] }; + Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] }; + Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] }; + + // Get triangle texcoords + Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] }; + Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] }; + Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] }; + + float x1 = v2.x - v1.x; + float y1 = v2.y - v1.y; + float z1 = v2.z - v1.z; + float x2 = v3.x - v1.x; + float y2 = v3.y - v1.y; + float z2 = v3.z - v1.z; + + float s1 = uv2.x - uv1.x; + float t1 = uv2.y - uv1.y; + float s2 = uv3.x - uv1.x; + float t2 = uv3.y - uv1.y; + + float div = s1*t2 - s2*t1; + float r = (div == 0.0f)? 0.0f : 1.0f/div; + + Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; + Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; + + tan1[i + 0] = sdir; + tan1[i + 1] = sdir; + tan1[i + 2] = sdir; + + tan2[i + 0] = tdir; + tan2[i + 1] = tdir; + tan2[i + 2] = tdir; + } + + // Compute tangents considering normals + for (int i = 0; i < mesh->vertexCount; ++i) + { + Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] }; + Vector3 tangent = tan1[i]; + + // TODO: Review, not sure if tangent computation is right, just used reference proposed maths... + #if defined(COMPUTE_TANGENTS_METHOD_01) + Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent))); + tmp = Vector3Normalize(tmp); + mesh->tangents[i*4 + 0] = tmp.x; + mesh->tangents[i*4 + 1] = tmp.y; + mesh->tangents[i*4 + 2] = tmp.z; + mesh->tangents[i*4 + 3] = 1.0f; + #else + Vector3OrthoNormalize(&normal, &tangent); + mesh->tangents[i*4 + 0] = tangent.x; + mesh->tangents[i*4 + 1] = tangent.y; + mesh->tangents[i*4 + 2] = tangent.z; + mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f; + #endif + } + + RL_FREE(tan1); + RL_FREE(tan2); + + // Load a new tangent attributes buffer + mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false); + + TRACELOG(LOG_INFO, "MESH: Tangents data computed for provided mesh"); +} + +// Compute mesh binormals (aka bitangent) +void MeshBinormals(Mesh *mesh) +{ + for (int i = 0; i < mesh->vertexCount; i++) + { + //Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] }; + //Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] }; + //Vector3 binormal = Vector3Scale(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]); + + // TODO: Register computed binormal in mesh->binormal? + } +} + +// Draw a model (with texture if set) +void DrawModel(Model model, Vector3 position, float scale, Color tint) +{ + Vector3 vScale = { scale, scale, scale }; + Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f }; + + DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); +} + +// Draw a model with extended parameters +void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) +{ + // Calculate transformation matrix from function parameters + // Get transform matrix (rotation -> scale -> translation) + Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); + Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); + Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); + + Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + + // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) + model.transform = MatrixMultiply(model.transform, matTransform); + + for (int i = 0; i < model.meshCount; i++) + { + Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color; + + Color colorTint = WHITE; + colorTint.r = (unsigned char)((((float)color.r/255.0)*((float)tint.r/255.0))*255.0f); + colorTint.g = (unsigned char)((((float)color.g/255.0)*((float)tint.g/255.0))*255.0f); + colorTint.b = (unsigned char)((((float)color.b/255.0)*((float)tint.b/255.0))*255.0f); + colorTint.a = (unsigned char)((((float)color.a/255.0)*((float)tint.a/255.0))*255.0f); + + model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint; + DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform); + model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color; + } +} + +// Draw a model wires (with texture if set) +void DrawModelWires(Model model, Vector3 position, float scale, Color tint) +{ + rlEnableWireMode(); + + DrawModel(model, position, scale, tint); + + rlDisableWireMode(); +} + +// Draw a model wires (with texture if set) with extended parameters +void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) +{ + rlEnableWireMode(); + + DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); + + rlDisableWireMode(); +} + +// Draw a billboard +void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint) +{ + Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height }; + + DrawBillboardRec(camera, texture, source, position, (Vector2){ size, size }, tint); +} + +// Draw a billboard (part of a texture defined by a rectangle) +void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint) +{ + DrawBillboardPro(camera, texture, source, position, size, Vector2Zero(), 0.0f, tint); +} + +void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Vector2 origin, float rotation, Color tint) +{ + // NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width + Vector2 sizeRatio = { size.y, size.x*(float)source.height/source.width }; + + Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + + Vector3 right = { matView.m0, matView.m4, matView.m8 }; + //Vector3 up = { matView.m1, matView.m5, matView.m9 }; + + // NOTE: Billboard locked on axis-Y + Vector3 up = { 0.0f, 1.0f, 0.0f }; + + Vector3 rightScaled = Vector3Scale(right, sizeRatio.x/2); + Vector3 upScaled = Vector3Scale(up, sizeRatio.y/2); + + Vector3 p1 = Vector3Add(rightScaled, upScaled); + Vector3 p2 = Vector3Subtract(rightScaled, upScaled); + + Vector3 topLeft = Vector3Scale(p2, -1); + Vector3 topRight = p1; + Vector3 bottomRight = p2; + Vector3 bottomLeft = Vector3Scale(p1, -1); + + if (rotation != 0.0f) + { + float sinRotation = sinf(rotation*DEG2RAD); + float cosRotation = cosf(rotation*DEG2RAD); + + // NOTE: (-1, 1) is the range where origin.x, origin.y is inside the texture + float rotateAboutX = sizeRatio.x*origin.x/2; + float rotateAboutY = sizeRatio.y*origin.y/2; + + float xtvalue, ytvalue; + float rotatedX, rotatedY; + + xtvalue = Vector3DotProduct(right, topLeft) - rotateAboutX; // Project points to x and y coordinates on the billboard plane + ytvalue = Vector3DotProduct(up, topLeft) - rotateAboutY; + rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX; // Rotate about the point origin + rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY; + topLeft = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX)); // Translate back to cartesian coordinates + + xtvalue = Vector3DotProduct(right, topRight) - rotateAboutX; + ytvalue = Vector3DotProduct(up, topRight) - rotateAboutY; + rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX; + rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY; + topRight = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX)); + + xtvalue = Vector3DotProduct(right, bottomRight) - rotateAboutX; + ytvalue = Vector3DotProduct(up, bottomRight) - rotateAboutY; + rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX; + rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY; + bottomRight = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX)); + + xtvalue = Vector3DotProduct(right, bottomLeft)-rotateAboutX; + ytvalue = Vector3DotProduct(up, bottomLeft)-rotateAboutY; + rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX; + rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY; + bottomLeft = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX)); + } + + // Translate points to the draw center (position) + topLeft = Vector3Add(topLeft, position); + topRight = Vector3Add(topRight, position); + bottomRight = Vector3Add(bottomRight, position); + bottomLeft = Vector3Add(bottomLeft, position); + + rlCheckRenderBatchLimit(4); + + rlSetTexture(texture.id); + + rlBegin(RL_QUADS); + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + + // Bottom-left corner for texture and quad + rlTexCoord2f((float)source.x/texture.width, (float)source.y/texture.height); + rlVertex3f(topLeft.x, topLeft.y, topLeft.z); + + // Top-left corner for texture and quad + rlTexCoord2f((float)source.x/texture.width, (float)(source.y + source.height)/texture.height); + rlVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + + // Top-right corner for texture and quad + rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height); + rlVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + + // Bottom-right corner for texture and quad + rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)source.y/texture.height); + rlVertex3f(topRight.x, topRight.y, topRight.z); + rlEnd(); + + rlSetTexture(0); +} + +// Draw a bounding box with wires +void DrawBoundingBox(BoundingBox box, Color color) +{ + Vector3 size = { 0 }; + + size.x = fabsf(box.max.x - box.min.x); + size.y = fabsf(box.max.y - box.min.y); + size.z = fabsf(box.max.z - box.min.z); + + Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f }; + + DrawCubeWires(center, size.x, size.y, size.z, color); +} + +// Detect collision between two spheres +bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2) +{ + bool collision = false; + + // Simple way to check for collision, just checking distance between two points + // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution + /* + float dx = center1.x - center2.x; // X distance between centers + float dy = center1.y - center2.y; // Y distance between centers + float dz = center1.z - center2.z; // Z distance between centers + + float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers + + if (distance <= (radius1 + radius2)) collision = true; + */ + + // Check for distances squared to avoid sqrtf() + if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true; + + return collision; +} + +// Detect collision between two boxes +// NOTE: Boxes are defined by two points minimum and maximum +bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2) +{ + bool collision = true; + + if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x)) + { + if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false; + if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false; + } + else collision = false; + + return collision; +} + +// Detect collision between box and sphere +bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius) +{ + bool collision = false; + + float dmin = 0; + + if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2); + else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2); + + if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2); + else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2); + + if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2); + else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2); + + if (dmin <= (radius*radius)) collision = true; + + return collision; +} + +// Detect collision between ray and sphere +bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius) +{ + bool collision = false; + + Vector3 raySpherePos = Vector3Subtract(center, ray.position); + float distance = Vector3Length(raySpherePos); + float vector = Vector3DotProduct(raySpherePos, ray.direction); + float d = radius*radius - (distance*distance - vector*vector); + + if (d >= 0.0f) collision = true; + + return collision; +} + +// Detect collision between ray and sphere with extended parameters and collision point detection +bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint) +{ + bool collision = false; + + Vector3 raySpherePos = Vector3Subtract(center, ray.position); + float distance = Vector3Length(raySpherePos); + float vector = Vector3DotProduct(raySpherePos, ray.direction); + float d = radius*radius - (distance*distance - vector*vector); + + if (d >= 0.0f) collision = true; + + // Check if ray origin is inside the sphere to calculate the correct collision point + float collisionDistance = 0; + + if (distance < radius) collisionDistance = vector + sqrtf(d); + else collisionDistance = vector - sqrtf(d); + + // Calculate collision point + Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance)); + + collisionPoint->x = cPoint.x; + collisionPoint->y = cPoint.y; + collisionPoint->z = cPoint.z; + + return collision; +} + +// Detect collision between ray and bounding box +bool CheckCollisionRayBox(Ray ray, BoundingBox box) +{ + bool collision = false; + + float t[8] = { 0 }; + t[0] = (box.min.x - ray.position.x)/ray.direction.x; + t[1] = (box.max.x - ray.position.x)/ray.direction.x; + t[2] = (box.min.y - ray.position.y)/ray.direction.y; + t[3] = (box.max.y - ray.position.y)/ray.direction.y; + t[4] = (box.min.z - ray.position.z)/ray.direction.z; + t[5] = (box.max.z - ray.position.z)/ray.direction.z; + t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5])); + t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5])); + + collision = !(t[7] < 0 || t[6] > t[7]); + + return collision; +} +// Get collision info between ray and mesh +RayHitInfo GetCollisionRayMesh(Ray ray, Mesh mesh, Matrix transform) +{ + RayHitInfo result = { 0 }; + + // Check if mesh vertex data on CPU for testing + if (mesh.vertices != NULL) + { + int triangleCount = mesh.triangleCount; + + // Test against all triangles in mesh + for (int i = 0; i < triangleCount; i++) + { + Vector3 a, b, c; + Vector3* vertdata = (Vector3*)mesh.vertices; + + if (mesh.indices) + { + a = vertdata[mesh.indices[i*3 + 0]]; + b = vertdata[mesh.indices[i*3 + 1]]; + c = vertdata[mesh.indices[i*3 + 2]]; + } + else + { + a = vertdata[i*3 + 0]; + b = vertdata[i*3 + 1]; + c = vertdata[i*3 + 2]; + } + + a = Vector3Transform(a, transform); + b = Vector3Transform(b, transform); + c = Vector3Transform(c, transform); + + RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); + + if (triHitInfo.hit) + { + // Save the closest hit triangle + if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo; + } + } + } + return result; +} + +// Get collision info between ray and model +RayHitInfo GetCollisionRayModel(Ray ray, Model model) +{ + RayHitInfo result = { 0 }; + + for (int m = 0; m < model.meshCount; m++) + { + RayHitInfo meshHitInfo = GetCollisionRayMesh(ray, model.meshes[m], model.transform); + + if (meshHitInfo.hit) + { + // Save the closest hit mesh + if ((!result.hit) || (result.distance > meshHitInfo.distance)) result = meshHitInfo; + } + } + + return result; +} + +// Get collision info between ray and triangle +// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm +RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) +{ + #define EPSILON 0.000001 // A small number + + Vector3 edge1, edge2; + Vector3 p, q, tv; + float det, invDet, u, v, t; + RayHitInfo result = {0}; + + // Find vectors for two edges sharing V1 + edge1 = Vector3Subtract(p2, p1); + edge2 = Vector3Subtract(p3, p1); + + // Begin calculating determinant - also used to calculate u parameter + p = Vector3CrossProduct(ray.direction, edge2); + + // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle + det = Vector3DotProduct(edge1, p); + + // Avoid culling! + if ((det > -EPSILON) && (det < EPSILON)) return result; + + invDet = 1.0f/det; + + // Calculate distance from V1 to ray origin + tv = Vector3Subtract(ray.position, p1); + + // Calculate u parameter and test bound + u = Vector3DotProduct(tv, p)*invDet; + + // The intersection lies outside of the triangle + if ((u < 0.0f) || (u > 1.0f)) return result; + + // Prepare to test v parameter + q = Vector3CrossProduct(tv, edge1); + + // Calculate V parameter and test bound + v = Vector3DotProduct(ray.direction, q)*invDet; + + // The intersection lies outside of the triangle + if ((v < 0.0f) || ((u + v) > 1.0f)) return result; + + t = Vector3DotProduct(edge2, q)*invDet; + + if (t > EPSILON) + { + // Ray hit, get hit point and normal + result.hit = true; + result.distance = t; + result.hit = true; + result.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2)); + result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, t)); + } + + return result; +} + +// Get collision info between ray and ground plane (Y-normal plane) +RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) +{ + #define EPSILON 0.000001 // A small number + + RayHitInfo result = { 0 }; + + if (fabsf(ray.direction.y) > EPSILON) + { + float distance = (ray.position.y - groundHeight)/-ray.direction.y; + + if (distance >= 0.0) + { + result.hit = true; + result.distance = distance; + result.normal = (Vector3){ 0.0, 1.0, 0.0 }; + result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, distance)); + result.position.y = groundHeight; + } + } + + return result; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +#if defined(SUPPORT_FILEFORMAT_OBJ) +// Load OBJ mesh data +static Model LoadOBJ(const char *fileName) +{ + Model model = { 0 }; + + tinyobj_attrib_t attrib = { 0 }; + tinyobj_shape_t *meshes = NULL; + unsigned int meshCount = 0; + + tinyobj_material_t *materials = NULL; + unsigned int materialCount = 0; + + char *fileText = LoadFileText(fileName); + + if (fileText != NULL) + { + unsigned int dataSize = (unsigned int)strlen(fileText); + char currentDir[1024] = { 0 }; + strcpy(currentDir, GetWorkingDirectory()); + const char *workingDir = GetDirectoryPath(fileName); + if (CHDIR(workingDir) != 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir); + } + + unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; + int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileText, dataSize, flags); + + if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName); + else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount); + + model.meshCount = materialCount; + + // Init model materials array + if (materialCount > 0) + { + model.materialCount = materialCount; + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); + TraceLog(LOG_INFO, "MODEL: model has %i material meshes", materialCount); + } + else + { + model.meshCount = 1; + TraceLog(LOG_INFO, "MODEL: No materials, putting all meshes in a default material"); + } + + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); + + // count the faces for each material + int *matFaces = RL_CALLOC(meshCount, sizeof(int)); + + for (unsigned int mi = 0; mi < meshCount; mi++) + { + for (unsigned int fi = 0; fi < meshes[mi].length; fi++) + { + int idx = attrib.material_ids[meshes[mi].face_offset + fi]; + if (idx == -1) idx = 0; // for no material face (which could be the whole model) + matFaces[idx]++; + } + } + + //-------------------------------------- + // create the material meshes + + // running counts / indexes for each material mesh as we are + // building them at the same time + int *vCount = RL_CALLOC(model.meshCount, sizeof(int)); + int *vtCount = RL_CALLOC(model.meshCount, sizeof(int)); + int *vnCount = RL_CALLOC(model.meshCount, sizeof(int)); + int *faceCount = RL_CALLOC(model.meshCount, sizeof(int)); + + // allocate space for each of the material meshes + for (int mi = 0; mi < model.meshCount; mi++) + { + model.meshes[mi].vertexCount = matFaces[mi]*3; + model.meshes[mi].triangleCount = matFaces[mi]; + model.meshes[mi].vertices = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float)); + model.meshes[mi].texcoords = (float *)RL_CALLOC(model.meshes[mi].vertexCount*2, sizeof(float)); + model.meshes[mi].normals = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float)); + model.meshMaterial[mi] = mi; + } + + // scan through the combined sub meshes and pick out each material mesh + for (unsigned int af = 0; af < attrib.num_faces; af++) + { + int mm = attrib.material_ids[af]; // mesh material for this face + if (mm == -1) { mm = 0; } // no material object.. + + // Get indices for the face + tinyobj_vertex_index_t idx0 = attrib.faces[3*af + 0]; + tinyobj_vertex_index_t idx1 = attrib.faces[3*af + 1]; + tinyobj_vertex_index_t idx2 = attrib.faces[3*af + 2]; + + // Fill vertices buffer (float) using vertex index of the face + for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx0.v_idx*3 + v]; } vCount[mm] +=3; + for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount[mm] +=3; + for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx2.v_idx*3 + v]; } vCount[mm] +=3; + + if (attrib.num_texcoords > 0) + { + // Fill texcoords buffer (float) using vertex index of the face + // NOTE: Y-coordinate must be flipped upside-down to account for + // raylib's upside down textures... + model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx0.vt_idx*2 + 0]; + model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1]; vtCount[mm] += 2; + model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx1.vt_idx*2 + 0]; + model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; vtCount[mm] += 2; + model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx2.vt_idx*2 + 0]; + model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount[mm] += 2; + } + + if (attrib.num_normals > 0) + { + // Fill normals buffer (float) using vertex index of the face + for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx0.vn_idx*3 + v]; } vnCount[mm] +=3; + for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx1.vn_idx*3 + v]; } vnCount[mm] +=3; + for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx2.vn_idx*3 + v]; } vnCount[mm] +=3; + } + } + + // Init model materials + for (unsigned int m = 0; m < materialCount; m++) + { + // Init material to default + // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE + model.materials[m] = LoadMaterialDefault(); + + model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = rlGetTextureDefault(); // Get default texture, in case no texture is defined + + if (materials[m].diffuse_texname != NULL) model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd + else model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = rlGetTextureDefault(); + + model.materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2]*255.0f), 255 }; //float diffuse[3]; + model.materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; + + if (materials[m].specular_texname != NULL) model.materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks + model.materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2]*255.0f), 255 }; //float specular[3]; + model.materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; + + if (materials[m].bump_texname != NULL) model.materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump + model.materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; + model.materials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; + + model.materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2]*255.0f), 255 }; //float emission[3]; + + if (materials[m].displacement_texname != NULL) model.materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp + } + + tinyobj_attrib_free(&attrib); + tinyobj_shapes_free(meshes, meshCount); + tinyobj_materials_free(materials, materialCount); + + UnloadFileText(fileText); + + RL_FREE(matFaces); + RL_FREE(vCount); + RL_FREE(vtCount); + RL_FREE(vnCount); + RL_FREE(faceCount); + + if (CHDIR(currentDir) != 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir); + } + } + + return model; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_IQM) +// Load IQM mesh data +static Model LoadIQM(const char *fileName) +{ + #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number + #define IQM_VERSION 2 // only IQM version 2 supported + + #define BONE_NAME_LENGTH 32 // BoneInfo name string length + #define MESH_NAME_LENGTH 32 // Mesh name string length + #define MATERIAL_NAME_LENGTH 32 // Material name string length + + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); + unsigned char *fileDataPtr = fileData; + + // IQM file structs + //----------------------------------------------------------------------------------- + typedef struct IQMHeader { + char magic[16]; + unsigned int version; + unsigned int filesize; + unsigned int flags; + unsigned int num_text, ofs_text; + unsigned int num_meshes, ofs_meshes; + unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; + unsigned int num_triangles, ofs_triangles, ofs_adjacency; + unsigned int num_joints, ofs_joints; + unsigned int num_poses, ofs_poses; + unsigned int num_anims, ofs_anims; + unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds; + unsigned int num_comment, ofs_comment; + unsigned int num_extensions, ofs_extensions; + } IQMHeader; + + typedef struct IQMMesh { + unsigned int name; + unsigned int material; + unsigned int first_vertex, num_vertexes; + unsigned int first_triangle, num_triangles; + } IQMMesh; + + typedef struct IQMTriangle { + unsigned int vertex[3]; + } IQMTriangle; + + typedef struct IQMJoint { + unsigned int name; + int parent; + float translate[3], rotate[4], scale[3]; + } IQMJoint; + + typedef struct IQMVertexArray { + unsigned int type; + unsigned int flags; + unsigned int format; + unsigned int size; + unsigned int offset; + } IQMVertexArray; + + // NOTE: Below IQM structures are not used but listed for reference + /* + typedef struct IQMAdjacency { + unsigned int triangle[3]; + } IQMAdjacency; + + typedef struct IQMPose { + int parent; + unsigned int mask; + float channeloffset[10]; + float channelscale[10]; + } IQMPose; + + typedef struct IQMAnim { + unsigned int name; + unsigned int first_frame, num_frames; + float framerate; + unsigned int flags; + } IQMAnim; + + typedef struct IQMBounds { + float bbmin[3], bbmax[3]; + float xyradius, radius; + } IQMBounds; + */ + //----------------------------------------------------------------------------------- + + // IQM vertex data types + enum { + IQM_POSITION = 0, + IQM_TEXCOORD = 1, + IQM_NORMAL = 2, + IQM_TANGENT = 3, // NOTE: Tangents unused by default + IQM_BLENDINDEXES = 4, + IQM_BLENDWEIGHTS = 5, + IQM_COLOR = 6, // NOTE: Vertex colors unused by default + IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default + }; + + Model model = { 0 }; + + IQMMesh *imesh = NULL; + IQMTriangle *tri = NULL; + IQMVertexArray *va = NULL; + IQMJoint *ijoint = NULL; + + float *vertex = NULL; + float *normal = NULL; + float *text = NULL; + char *blendi = NULL; + unsigned char *blendw = NULL; + + // In case file can not be read, return an empty model + if (fileDataPtr == NULL) return model; + + // Read IQM header + IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr; + + if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); + return model; + } + + if (iqmHeader->version != IQM_VERSION) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); + return model; + } + + //fileDataPtr += sizeof(IQMHeader); // Move file data pointer + + // Meshes data processing + imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh)); + //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET); + //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile); + memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh)); + + model.meshCount = iqmHeader->num_meshes; + model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); + + model.materialCount = model.meshCount; + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); + + char name[MESH_NAME_LENGTH] = { 0 }; + char material[MATERIAL_NAME_LENGTH] = { 0 }; + + for (int i = 0; i < model.meshCount; i++) + { + //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET); + //fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); + memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char)); + + //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET); + //fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile); + memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char)); + + model.materials[i] = LoadMaterialDefault(); + + TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material); + + model.meshes[i].vertexCount = imesh[i].num_vertexes; + + model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions + model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals + model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords + + model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported! + model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported! + + model.meshes[i].triangleCount = imesh[i].num_triangles; + model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short)); + + // Animated verted data, what we actually process for rendering + // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning) + model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); + model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); + } + + // Triangles data processing + tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle)); + //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET); + //fread(tri, iqmHeader->num_triangles*sizeof(IQMTriangle), 1, iqmFile); + memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle)); + + for (int m = 0; m < model.meshCount; m++) + { + int tcounter = 0; + + for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++) + { + // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order, + // expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes + // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default + model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex; + model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex; + model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex; + tcounter += 3; + } + } + + // Vertex arrays data processing + va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); + //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET); + //fread(va, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile); + memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); + + for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++) + { + switch (va[i].type) + { + case IQM_POSITION: + { + vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile); + memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float)); + + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) + { + int vCounter = 0; + for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++) + { + model.meshes[m].vertices[vCounter] = vertex[i]; + model.meshes[m].animVertices[vCounter] = vertex[i]; + vCounter++; + } + } + } break; + case IQM_NORMAL: + { + normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile); + memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float)); + + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) + { + int vCounter = 0; + for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++) + { + model.meshes[m].normals[vCounter] = normal[i]; + model.meshes[m].animNormals[vCounter] = normal[i]; + vCounter++; + } + } + } break; + case IQM_TEXCOORD: + { + text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile); + memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float)); + + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) + { + int vCounter = 0; + for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++) + { + model.meshes[m].texcoords[vCounter] = text[i]; + vCounter++; + } + } + } break; + case IQM_BLENDINDEXES: + { + blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile); + memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char)); + + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) + { + int boneCounter = 0; + for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) + { + model.meshes[m].boneIds[boneCounter] = blendi[i]; + boneCounter++; + } + } + } break; + case IQM_BLENDWEIGHTS: + { + blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile); + memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char)); + + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) + { + int boneCounter = 0; + for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) + { + model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f; + boneCounter++; + } + } + } break; + } + } + + // Bones (joints) data processing + ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint)); + //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET); + //fread(ijoint, iqmHeader->num_joints*sizeof(IQMJoint), 1, iqmFile); + memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint)); + + model.boneCount = iqmHeader->num_joints; + model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo)); + model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform)); + + for (unsigned int i = 0; i < iqmHeader->num_joints; i++) + { + // Bones + model.bones[i].parent = ijoint[i].parent; + //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET); + //fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile); + memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char)); + + // Bind pose (base pose) + model.bindPose[i].translation.x = ijoint[i].translate[0]; + model.bindPose[i].translation.y = ijoint[i].translate[1]; + model.bindPose[i].translation.z = ijoint[i].translate[2]; + + model.bindPose[i].rotation.x = ijoint[i].rotate[0]; + model.bindPose[i].rotation.y = ijoint[i].rotate[1]; + model.bindPose[i].rotation.z = ijoint[i].rotate[2]; + model.bindPose[i].rotation.w = ijoint[i].rotate[3]; + + model.bindPose[i].scale.x = ijoint[i].scale[0]; + model.bindPose[i].scale.y = ijoint[i].scale[1]; + model.bindPose[i].scale.z = ijoint[i].scale[2]; + } + + // Build bind pose from parent joints + for (int i = 0; i < model.boneCount; i++) + { + if (model.bones[i].parent >= 0) + { + model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation); + model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation); + model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation); + model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale); + } + } + + RL_FREE(fileData); + + RL_FREE(imesh); + RL_FREE(tri); + RL_FREE(va); + RL_FREE(vertex); + RL_FREE(normal); + RL_FREE(text); + RL_FREE(blendi); + RL_FREE(blendw); + RL_FREE(ijoint); + + return model; +} + +// Load IQM animation data +static ModelAnimation* LoadIQMModelAnimations(const char* fileName, int* animCount) +{ +#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number +#define IQM_VERSION 2 // only IQM version 2 supported + + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); + unsigned char *fileDataPtr = fileData; + + typedef struct IQMHeader { + char magic[16]; + unsigned int version; + unsigned int filesize; + unsigned int flags; + unsigned int num_text, ofs_text; + unsigned int num_meshes, ofs_meshes; + unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; + unsigned int num_triangles, ofs_triangles, ofs_adjacency; + unsigned int num_joints, ofs_joints; + unsigned int num_poses, ofs_poses; + unsigned int num_anims, ofs_anims; + unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds; + unsigned int num_comment, ofs_comment; + unsigned int num_extensions, ofs_extensions; + } IQMHeader; + + typedef struct IQMPose { + int parent; + unsigned int mask; + float channeloffset[10]; + float channelscale[10]; + } IQMPose; + + typedef struct IQMAnim { + unsigned int name; + unsigned int first_frame, num_frames; + float framerate; + unsigned int flags; + } IQMAnim; + + // In case file can not be read, return an empty model + if (fileDataPtr == NULL) return NULL; + + // Read IQM header + IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr; + + if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); + return NULL; + } + + if (iqmHeader->version != IQM_VERSION) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); + return NULL; + } + + // Get bones data + IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose)); + //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET); + //fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile); + memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose)); + + // Get animations data + *animCount = iqmHeader->num_anims; + IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim)); + //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET); + //fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile); + memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim)); + + ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation)); + + // frameposes + unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); + //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET); + //fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile); + memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); + + for (unsigned int a = 0; a < iqmHeader->num_anims; a++) + { + animations[a].frameCount = anim[a].num_frames; + animations[a].boneCount = iqmHeader->num_poses; + animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo)); + animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *)); + // animations[a].framerate = anim.framerate; // TODO: Use framerate? + + for (unsigned int j = 0; j < iqmHeader->num_poses; j++) + { + strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); + animations[a].bones[j].parent = poses[j].parent; + } + + for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform)); + + int dcounter = anim[a].first_frame*iqmHeader->num_framechannels; + + for (unsigned int frame = 0; frame < anim[a].num_frames; frame++) + { + for (unsigned int i = 0; i < iqmHeader->num_poses; i++) + { + animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0]; + + if (poses[i].mask & 0x01) + { + animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0]; + dcounter++; + } + + animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1]; + + if (poses[i].mask & 0x02) + { + animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1]; + dcounter++; + } + + animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2]; + + if (poses[i].mask & 0x04) + { + animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3]; + + if (poses[i].mask & 0x08) + { + animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4]; + + if (poses[i].mask & 0x10) + { + animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5]; + + if (poses[i].mask & 0x20) + { + animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6]; + + if (poses[i].mask & 0x40) + { + animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6]; + dcounter++; + } + + animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7]; + + if (poses[i].mask & 0x80) + { + animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7]; + dcounter++; + } + + animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8]; + + if (poses[i].mask & 0x100) + { + animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8]; + dcounter++; + } + + animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9]; + + if (poses[i].mask & 0x200) + { + animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation); + } + } + + // Build frameposes + for (unsigned int frame = 0; frame < anim[a].num_frames; frame++) + { + for (int i = 0; i < animations[a].boneCount; i++) + { + if (animations[a].bones[i].parent >= 0) + { + animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation); + animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation); + animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation); + animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale); + } + } + } + } + + RL_FREE(fileData); + + RL_FREE(framedata); + RL_FREE(poses); + RL_FREE(anim); + + return animations; +} + +#endif + +#if defined(SUPPORT_FILEFORMAT_GLTF) + +static const unsigned char base64Table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51 +}; + +static int GetSizeBase64(char *input) +{ + int size = 0; + + for (int i = 0; input[4*i] != 0; i++) + { + if (input[4*i + 3] == '=') + { + if (input[4*i + 2] == '=') size += 1; + else size += 2; + } + else size += 3; + } + + return size; +} + +static unsigned char *DecodeBase64(char *input, int *size) +{ + *size = GetSizeBase64(input); + + unsigned char *buf = (unsigned char *)RL_MALLOC(*size); + for (int i = 0; i < *size/3; i++) + { + unsigned char a = base64Table[(int)input[4*i]]; + unsigned char b = base64Table[(int)input[4*i + 1]]; + unsigned char c = base64Table[(int)input[4*i + 2]]; + unsigned char d = base64Table[(int)input[4*i + 3]]; + + buf[3*i] = (a << 2) | (b >> 4); + buf[3*i + 1] = (b << 4) | (c >> 2); + buf[3*i + 2] = (c << 6) | d; + } + + if (*size%3 == 1) + { + int n = *size/3; + unsigned char a = base64Table[(int)input[4*n]]; + unsigned char b = base64Table[(int)input[4*n + 1]]; + buf[*size - 1] = (a << 2) | (b >> 4); + } + else if (*size%3 == 2) + { + int n = *size/3; + unsigned char a = base64Table[(int)input[4*n]]; + unsigned char b = base64Table[(int)input[4*n + 1]]; + unsigned char c = base64Table[(int)input[4*n + 2]]; + buf[*size - 2] = (a << 2) | (b >> 4); + buf[*size - 1] = (b << 4) | (c >> 2); + } + return buf; +} + +// Load texture from cgltf_image +static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Color tint) +{ + Image rimage = { 0 }; + + if (image->uri) + { + if ((strlen(image->uri) > 5) && + (image->uri[0] == 'd') && + (image->uri[1] == 'a') && + (image->uri[2] == 't') && + (image->uri[3] == 'a') && + (image->uri[4] == ':')) + { + // Data URI + // Format: data:;base64, + + // Find the comma + int i = 0; + while ((image->uri[i] != ',') && (image->uri[i] != 0)) i++; + + if (image->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image"); + else + { + int size = 0; + unsigned char *data = DecodeBase64(image->uri + i + 1, &size); + + int width, height; + unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4); + RL_FREE(data); + + rimage.data = raw; + rimage.width = width; + rimage.height = height; + rimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + rimage.mipmaps = 1; + + // TODO: Tint shouldn't be applied here! + ImageColorTint(&rimage, tint); + } + } + else + { + rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri)); + + // TODO: Tint shouldn't be applied here! + ImageColorTint(&rimage, tint); + } + } + else if (image->buffer_view) + { + unsigned char *data = RL_MALLOC(image->buffer_view->size); + int n = (int)image->buffer_view->offset; + int stride = (int)image->buffer_view->stride ? (int)image->buffer_view->stride : 1; + + for (unsigned int i = 0; i < image->buffer_view->size; i++) + { + data[i] = ((unsigned char *)image->buffer_view->buffer->data)[n]; + n += stride; + } + + int width, height; + unsigned char *raw = stbi_load_from_memory(data, (int)image->buffer_view->size, &width, &height, NULL, 4); + RL_FREE(data); + + rimage.data = raw; + rimage.width = width; + rimage.height = height; + rimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + rimage.mipmaps = 1; + + // TODO: Tint shouldn't be applied here! + ImageColorTint(&rimage, tint); + } + else rimage = GenImageColor(1, 1, tint); + + return rimage; +} + + +static bool GLTFReadValue(cgltf_accessor* acc, unsigned int index, void *variable, unsigned int elements, unsigned int size) +{ + if (acc->count == 2) + { + if (index > 1) return false; + + memcpy(variable, index == 0 ? acc->min : acc->max, elements*size); + return true; + } + + unsigned int stride = size*elements; + memset(variable, 0, stride); + + if (acc->buffer_view == NULL || acc->buffer_view->buffer == NULL || acc->buffer_view->buffer->data == NULL) return false; + + void* readPosition = ((char *)acc->buffer_view->buffer->data) + (index*stride) + acc->buffer_view->offset + acc->offset; + memcpy(variable, readPosition, stride); + return true; +} + +// LoadGLTF loads in model data from given filename, supporting both .gltf and .glb +static Model LoadGLTF(const char *fileName) +{ + /*********************************************************************************** + + Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend) and Hristo Stamenov(@object71) + + Features: + - Supports .gltf and .glb files + - Supports embedded (base64) or external textures + - Loads all raylib supported material textures, values and colors + - Supports multiple mesh per model and multiple primitives per model + + Some restrictions (not exhaustive): + - Triangle-only meshes + - Not supported node hierarchies or transforms + - Only supports unsigned short indices (no byte/unsigned int) + - Only supports float for texture coordinates (no byte/unsigned short) + + *************************************************************************************/ + + Model model = { 0 }; + + // glTF file loading + unsigned int dataSize = 0; + unsigned char *fileData = LoadFileData(fileName, &dataSize); + + if (fileData == NULL) return model; + + // glTF data loading + cgltf_options options = { 0 }; + cgltf_data *data = NULL; + cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); + + if (result == cgltf_result_success) + { + TRACELOG(LOG_INFO, "MODEL: [%s] glTF meshes (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count); + TRACELOG(LOG_INFO, "MODEL: [%s] glTF materials (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->materials_count); + + // Read data buffers + result = cgltf_load_buffers(&options, data, fileName); + if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName); + + int primitivesCount = 0; + + for (unsigned int i = 0; i < data->meshes_count; i++) + primitivesCount += (int)data->meshes[i].primitives_count; + + // Process glTF data and map to model + model.meshCount = primitivesCount; + model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); + model.materialCount = (int)data->materials_count + 1; + model.materials = RL_MALLOC(model.materialCount*sizeof(Material)); + model.meshMaterial = RL_MALLOC(model.meshCount*sizeof(int)); + model.boneCount = (int)data->nodes_count; + model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo)); + model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform)); + + InitGLTFBones(&model, data); + LoadGLTFMaterial(&model, fileName, data); + + int primitiveIndex = 0; + + for (unsigned int i = 0; i < data->meshes_count; i++) + { + for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++) + { + for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++) + { + if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) + { + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + model.meshes[primitiveIndex].vertexCount = (int)acc->count; + int bufferSize = model.meshes[primitiveIndex].vertexCount*3*sizeof(float); + model.meshes[primitiveIndex].vertices = RL_MALLOC(bufferSize); + model.meshes[primitiveIndex].animVertices = RL_MALLOC(bufferSize); + + if (acc->component_type == cgltf_component_type_r_32f) + { + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, model.meshes[primitiveIndex].vertices + (a*3), 3, sizeof(float)); + } + } + else if (acc->component_type == cgltf_component_type_r_32u) + { + int readValue[3]; + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, readValue, 3, sizeof(int)); + model.meshes[primitiveIndex].vertices[(a*3) + 0] = (float)readValue[0]; + model.meshes[primitiveIndex].vertices[(a*3) + 1] = (float)readValue[1]; + model.meshes[primitiveIndex].vertices[(a*3) + 2] = (float)readValue[2]; + } + } + else + { + // TODO: Support normalized unsigned byte/unsigned short vertices + TRACELOG(LOG_WARNING, "MODEL: [%s] glTF vertices must be float or int", fileName); + } + + memcpy(model.meshes[primitiveIndex].animVertices, model.meshes[primitiveIndex].vertices, bufferSize); + } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal) + { + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + + int bufferSize = (int)(acc->count*3*sizeof(float)); + model.meshes[primitiveIndex].normals = RL_MALLOC(bufferSize); + model.meshes[primitiveIndex].animNormals = RL_MALLOC(bufferSize); + + if (acc->component_type == cgltf_component_type_r_32f) + { + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, model.meshes[primitiveIndex].normals + (a*3), 3, sizeof(float)); + } + } + else if (acc->component_type == cgltf_component_type_r_32u) + { + int readValue[3]; + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, readValue, 3, sizeof(int)); + model.meshes[primitiveIndex].normals[(a*3) + 0] = (float)readValue[0]; + model.meshes[primitiveIndex].normals[(a*3) + 1] = (float)readValue[1]; + model.meshes[primitiveIndex].normals[(a*3) + 2] = (float)readValue[2]; + } + } + else + { + // TODO: Support normalized unsigned byte/unsigned short normals + TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName); + } + + memcpy(model.meshes[primitiveIndex].animNormals, model.meshes[primitiveIndex].normals, bufferSize); + } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) + { + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + + if (acc->component_type == cgltf_component_type_r_32f) + { + model.meshes[primitiveIndex].texcoords = RL_MALLOC(acc->count*2*sizeof(float)); + + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, model.meshes[primitiveIndex].texcoords + (a*2), 2, sizeof(float)); + } + } + else + { + // TODO: Support normalized unsigned byte/unsigned short texture coordinates + TRACELOG(LOG_WARNING, "MODEL: [%s] glTF texture coordinates must be float", fileName); + } + } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_joints) + { + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + LoadGLTFBoneAttribute(&model, acc, data, primitiveIndex); + } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_weights) + { + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + + model.meshes[primitiveIndex].boneWeights = RL_MALLOC(acc->count*4*sizeof(float)); + + if (acc->component_type == cgltf_component_type_r_32f) + { + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, model.meshes[primitiveIndex].boneWeights + (a*4), 4, sizeof(float)); + } + } + else if (acc->component_type == cgltf_component_type_r_32u) + { + unsigned int readValue[4]; + for (unsigned int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned int)); + model.meshes[primitiveIndex].boneWeights[(a*4) + 0] = (float)readValue[0]; + model.meshes[primitiveIndex].boneWeights[(a*4) + 1] = (float)readValue[1]; + model.meshes[primitiveIndex].boneWeights[(a*4) + 2] = (float)readValue[2]; + model.meshes[primitiveIndex].boneWeights[(a*4) + 3] = (float)readValue[3]; + } + } + else + { + // TODO: Support normalized unsigned byte/unsigned short weights + TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName); + } + } + } + + cgltf_accessor *acc = data->meshes[i].primitives[p].indices; + LoadGLTFModelIndices(&model, acc, primitiveIndex); + + if (data->meshes[i].primitives[p].material) + { + // Compute the offset + model.meshMaterial[primitiveIndex] = (int)(data->meshes[i].primitives[p].material - data->materials); + } + else + { + model.meshMaterial[primitiveIndex] = model.materialCount - 1; + } + + BindGLTFPrimitiveToBones(&model, data, primitiveIndex); + + primitiveIndex++; + } + + } + + cgltf_free(data); + } + else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName); + + RL_FREE(fileData); + + return model; +} + +static void InitGLTFBones(Model* model, const cgltf_data* data) +{ + for (unsigned int j = 0; j < data->nodes_count; j++) + { + strcpy(model->bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name); + model->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1; + } + + for (unsigned int i = 0; i < data->nodes_count; i++) + { + if (data->nodes[i].has_translation) memcpy(&model->bindPose[i].translation, data->nodes[i].translation, 3*sizeof(float)); + else model->bindPose[i].translation = Vector3Zero(); + + if (data->nodes[i].has_rotation) memcpy(&model->bindPose[i].rotation, data->nodes[i].rotation, 4*sizeof(float)); + else model->bindPose[i].rotation = QuaternionIdentity(); + + model->bindPose[i].rotation = QuaternionNormalize(model->bindPose[i].rotation); + + if (data->nodes[i].has_scale) memcpy(&model->bindPose[i].scale, data->nodes[i].scale, 3*sizeof(float)); + else model->bindPose[i].scale = Vector3One(); + } + + { + bool* completedBones = RL_CALLOC(model->boneCount, sizeof(bool)); + int numberCompletedBones = 0; + + while (numberCompletedBones < model->boneCount) { + for (int i = 0; i < model->boneCount; i++) + { + if (completedBones[i]) continue; + + if (model->bones[i].parent < 0) { + completedBones[i] = true; + numberCompletedBones++; + continue; + } + + if (!completedBones[model->bones[i].parent]) continue; + + Transform* currentTransform = &model->bindPose[i]; + BoneInfo* currentBone = &model->bones[i]; + int root = currentBone->parent; + if (root >= model->boneCount) + root = 0; + Transform* parentTransform = &model->bindPose[root]; + + currentTransform->rotation = QuaternionMultiply(parentTransform->rotation, currentTransform->rotation); + currentTransform->translation = Vector3RotateByQuaternion(currentTransform->translation, parentTransform->rotation); + currentTransform->translation = Vector3Add(currentTransform->translation, parentTransform->translation); + currentTransform->scale = Vector3Multiply(currentTransform->scale, parentTransform->scale); + completedBones[i] = true; + numberCompletedBones++; + } + } + + RL_FREE(completedBones); + } +} + +static void LoadGLTFMaterial(Model* model, const char* fileName, const cgltf_data* data) +{ + for (int i = 0; i < model->materialCount - 1; i++) + { + model->materials[i] = LoadMaterialDefault(); + Color tint = (Color){ 255, 255, 255, 255 }; + const char *texPath = GetDirectoryPath(fileName); + + // Ensure material follows raylib support for PBR (metallic/roughness flow) + if (data->materials[i].has_pbr_metallic_roughness) + { + tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255); + tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255); + tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255); + tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255); + + model->materials[i].maps[MATERIAL_MAP_ALBEDO].color = tint; + + if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture) + { + Image albedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint); + model->materials[i].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(albedo); + UnloadImage(albedo); + } + + tint = WHITE; // Set tint to white after it's been used by Albedo + + if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture) + { + Image metallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint); + model->materials[i].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(metallicRoughness); + + float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor; + model->materials[i].maps[MATERIAL_MAP_ROUGHNESS].value = roughness; + + float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor; + model->materials[i].maps[MATERIAL_MAP_METALNESS].value = metallic; + + UnloadImage(metallicRoughness); + } + + if (data->materials[i].normal_texture.texture) + { + Image normalImage = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint); + model->materials[i].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(normalImage); + UnloadImage(normalImage); + } + + if (data->materials[i].occlusion_texture.texture) + { + Image occulsionImage = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint); + model->materials[i].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(occulsionImage); + UnloadImage(occulsionImage); + } + + if (data->materials[i].emissive_texture.texture) + { + Image emissiveImage = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath, tint); + model->materials[i].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(emissiveImage); + tint.r = (unsigned char)(data->materials[i].emissive_factor[0]*255); + tint.g = (unsigned char)(data->materials[i].emissive_factor[1]*255); + tint.b = (unsigned char)(data->materials[i].emissive_factor[2]*255); + model->materials[i].maps[MATERIAL_MAP_EMISSION].color = tint; + UnloadImage(emissiveImage); + } + } + } + + model->materials[model->materialCount - 1] = LoadMaterialDefault(); +} + +static void LoadGLTFBoneAttribute(Model* model, cgltf_accessor* jointsAccessor, const cgltf_data* data, int primitiveIndex) +{ + if (jointsAccessor->component_type == cgltf_component_type_r_16u) + { + model->meshes[primitiveIndex].boneIds = RL_MALLOC(jointsAccessor->count*4*sizeof(int)); + short* bones = RL_MALLOC(jointsAccessor->count*4*sizeof(short)); + + for (unsigned int a = 0; a < jointsAccessor->count; a++) + { + GLTFReadValue(jointsAccessor, a, bones + (a*4), 4, sizeof(short)); + } + + for (unsigned int a = 0; a < jointsAccessor->count*4; a++) + { + cgltf_node* skinJoint = data->skins->joints[bones[a]]; + + for (unsigned int k = 0; k < data->nodes_count; k++) + { + if (&(data->nodes[k]) == skinJoint) + { + model->meshes[primitiveIndex].boneIds[a] = k; + break; + } + } + } + RL_FREE(bones); + } + else if (jointsAccessor->component_type == cgltf_component_type_r_8u) + { + model->meshes[primitiveIndex].boneIds = RL_MALLOC(jointsAccessor->count*4*sizeof(int)); + unsigned char* bones = RL_MALLOC(jointsAccessor->count*4*sizeof(unsigned char)); + + for (unsigned int a = 0; a < jointsAccessor->count; a++) + { + GLTFReadValue(jointsAccessor, a, bones + (a*4), 4, sizeof(unsigned char)); + } + + for (unsigned int a = 0; a < jointsAccessor->count*4; a++) + { + cgltf_node* skinJoint = data->skins->joints[bones[a]]; + + for (unsigned int k = 0; k < data->nodes_count; k++) + { + if (&(data->nodes[k]) == skinJoint) + { + model->meshes[primitiveIndex].boneIds[a] = k; + break; + } + } + } + RL_FREE(bones); + } + else + { + // TODO: Support other size of bone index? + TRACELOG(LOG_WARNING, "MODEL: glTF bones in unexpected format"); + } +} + +static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int primitiveIndex) +{ + if (model->meshes[primitiveIndex].boneIds == NULL && data->nodes_count > 0) + { + for (unsigned int nodeId = 0; nodeId < data->nodes_count; nodeId++) + { + if (data->nodes[nodeId].mesh == &(data->meshes[primitiveIndex])) + { + model->meshes[primitiveIndex].boneIds = RL_CALLOC(4*model->meshes[primitiveIndex].vertexCount, sizeof(int)); + model->meshes[primitiveIndex].boneWeights = RL_CALLOC(4*model->meshes[primitiveIndex].vertexCount, sizeof(float)); + + for (int b = 0; b < 4*model->meshes[primitiveIndex].vertexCount; b++) + { + if (b%4 == 0) + { + model->meshes[primitiveIndex].boneIds[b] = nodeId; + model->meshes[primitiveIndex].boneWeights[b] = 1.0f; + } + else + { + model->meshes[primitiveIndex].boneIds[b] = 0; + model->meshes[primitiveIndex].boneWeights[b] = 0.0f; + } + + } + + Vector3 boundVertex = { 0 }; + Vector3 boundNormal = { 0 }; + + Vector3 outTranslation = { 0 }; + Quaternion outRotation = { 0 }; + Vector3 outScale = { 0 }; + + int vCounter = 0; + int boneCounter = 0; + int boneId = 0; + + for (int i = 0; i < model->meshes[primitiveIndex].vertexCount; i++) + { + boneId = model->meshes[primitiveIndex].boneIds[boneCounter]; + outTranslation = model->bindPose[boneId].translation; + outRotation = model->bindPose[boneId].rotation; + outScale = model->bindPose[boneId].scale; + + // Vertices processing + boundVertex = (Vector3){ model->meshes[primitiveIndex].vertices[vCounter], model->meshes[primitiveIndex].vertices[vCounter + 1], model->meshes[primitiveIndex].vertices[vCounter + 2] }; + boundVertex = Vector3Multiply(boundVertex, outScale); + boundVertex = Vector3RotateByQuaternion(boundVertex, outRotation); + boundVertex = Vector3Add(boundVertex, outTranslation); + model->meshes[primitiveIndex].vertices[vCounter] = boundVertex.x; + model->meshes[primitiveIndex].vertices[vCounter + 1] = boundVertex.y; + model->meshes[primitiveIndex].vertices[vCounter + 2] = boundVertex.z; + + // Normals processing + if (model->meshes[primitiveIndex].normals != NULL) + { + boundNormal = (Vector3){ model->meshes[primitiveIndex].normals[vCounter], model->meshes[primitiveIndex].normals[vCounter + 1], model->meshes[primitiveIndex].normals[vCounter + 2] }; + boundNormal = Vector3RotateByQuaternion(boundNormal, outRotation); + model->meshes[primitiveIndex].normals[vCounter] = boundNormal.x; + model->meshes[primitiveIndex].normals[vCounter + 1] = boundNormal.y; + model->meshes[primitiveIndex].normals[vCounter + 2] = boundNormal.z; + } + + vCounter += 3; + boneCounter += 4; + } + } + } + } +} + +static void LoadGLTFModelIndices(Model* model, cgltf_accessor* indexAccessor, int primitiveIndex) +{ + if (indexAccessor) + { + if (indexAccessor->component_type == cgltf_component_type_r_16u || indexAccessor->component_type == cgltf_component_type_r_16) + { + model->meshes[primitiveIndex].triangleCount = (int)indexAccessor->count/3; + model->meshes[primitiveIndex].indices = RL_MALLOC(model->meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short)); + + unsigned short readValue = 0; + for (unsigned int a = 0; a < indexAccessor->count; a++) + { + GLTFReadValue(indexAccessor, a, &readValue, 1, sizeof(short)); + model->meshes[primitiveIndex].indices[a] = readValue; + } + } + else if (indexAccessor->component_type == cgltf_component_type_r_8u || indexAccessor->component_type == cgltf_component_type_r_8) + { + model->meshes[primitiveIndex].triangleCount = (int)indexAccessor->count/3; + model->meshes[primitiveIndex].indices = RL_MALLOC(model->meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short)); + + unsigned char readValue = 0; + for (unsigned int a = 0; a < indexAccessor->count; a++) + { + GLTFReadValue(indexAccessor, a, &readValue, 1, sizeof(char)); + model->meshes[primitiveIndex].indices[a] = (unsigned short)readValue; + } + } + else if (indexAccessor->component_type == cgltf_component_type_r_32u) + { + model->meshes[primitiveIndex].triangleCount = (int)indexAccessor->count/3; + model->meshes[primitiveIndex].indices = RL_MALLOC(model->meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short)); + + unsigned int readValue; + for (unsigned int a = 0; a < indexAccessor->count; a++) + { + GLTFReadValue(indexAccessor, a, &readValue, 1, sizeof(unsigned int)); + model->meshes[primitiveIndex].indices[a] = (unsigned short)readValue; + } + } + } + else + { + // Unindexed mesh + model->meshes[primitiveIndex].triangleCount = model->meshes[primitiveIndex].vertexCount/3; + } +} + +// LoadGLTF loads in animation data from given filename +static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCount) +{ + /*********************************************************************************** + + Function implemented by Hristo Stamenov (@object71) + + Features: + - Supports .gltf and .glb files + + Some restrictions (not exhaustive): + - ... + + *************************************************************************************/ + + // glTF file loading + unsigned int dataSize = 0; + unsigned char *fileData = LoadFileData(fileName, &dataSize); + + ModelAnimation *animations = NULL; + + if (fileData == NULL) return animations; + + // glTF data loading + cgltf_options options = { 0 }; + cgltf_data *data = NULL; + cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); + + if (result == cgltf_result_success) + { + TRACELOG(LOG_INFO, "MODEL: [%s] glTF animations (%s) count: %i", fileName, (data->file_type == 2)? "glb" : + "gltf", data->animations_count); + + result = cgltf_load_buffers(&options, data, fileName); + if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName); + animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); + *animCount = (int)data->animations_count; + + for (unsigned int a = 0; a < data->animations_count; a++) + { + // gltf animation consists of the following structures: + // - nodes - bones + // - channels - single transformation type on a single bone + // - node - bone + // - transformation type (path) - translation, rotation, scale + // - sampler - animation samples + // - input - points in time this transformation happens + // - output - the transformation amount at the given input points in time + // - interpolation - the type of interpolation to use between the frames + + cgltf_animation *animation = data->animations + a; + + ModelAnimation *output = animations + a; + + // 30 frames sampled per second + const float timeStep = (1.0f/30.0f); + float animationDuration = 0.0f; + + // Getting the max animation time to consider for animation duration + for (unsigned int i = 0; i < animation->channels_count; i++) + { + cgltf_animation_channel* channel = animation->channels + i; + int frameCounts = (int)channel->sampler->input->count; + float lastFrameTime = 0.0f; + + if (GLTFReadValue(channel->sampler->input, frameCounts - 1, &lastFrameTime, 1, sizeof(float))) + { + animationDuration = fmaxf(lastFrameTime, animationDuration); + } + } + + output->frameCount = (int)(animationDuration / timeStep); + output->boneCount = (int)data->nodes_count; + output->bones = RL_MALLOC(output->boneCount*sizeof(BoneInfo)); + output->framePoses = RL_MALLOC(output->frameCount*sizeof(Transform *)); + // output->framerate = // TODO: Use framerate instead of const timestep + + // Name and parent bones + for (unsigned int j = 0; j < output->boneCount; j++) + { + strcpy(output->bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name); + output->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1; + } + + // Allocate data for frames + // Initiate with zero bone translations + for (int frame = 0; frame < output->frameCount; frame++) + { + output->framePoses[frame] = RL_MALLOC(output->boneCount*sizeof(Transform)); + + for (unsigned int i = 0; i < output->boneCount; i++) + { + output->framePoses[frame][i].translation = Vector3Zero(); + output->framePoses[frame][i].rotation = QuaternionIdentity(); + output->framePoses[frame][i].rotation = QuaternionNormalize(output->framePoses[frame][i].rotation); + output->framePoses[frame][i].scale = Vector3One(); + } + } + + // for each single transformation type on single bone + for (unsigned int channelId = 0; channelId < animation->channels_count; channelId++) + { + cgltf_animation_channel* channel = animation->channels + channelId; + cgltf_animation_sampler* sampler = channel->sampler; + + int boneId = (int)(channel->target_node - data->nodes); + + for (int frame = 0; frame < output->frameCount; frame++) + { + bool shouldSkipFurtherTransformation = true; + int outputMin = 0; + int outputMax = 0; + float frameTime = frame*timeStep; + float lerpPercent = 0.0f; + + // For this transformation: + // getting between which input values the current frame time position + // and also what is the percent to use in the linear interpolation later + for (unsigned int j = 0; j < sampler->input->count; j++) + { + float inputFrameTime; + if (GLTFReadValue(sampler->input, j, &inputFrameTime, 1, sizeof(float))) + { + if (frameTime < inputFrameTime) + { + shouldSkipFurtherTransformation = false; + outputMin = (j == 0) ? 0 : j - 1; + outputMax = j; + + float previousInputTime = 0.0f; + if (GLTFReadValue(sampler->input, outputMin, &previousInputTime, 1, sizeof(float))) + { + if ((inputFrameTime - previousInputTime) != 0) + { + lerpPercent = (frameTime - previousInputTime)/(inputFrameTime - previousInputTime); + } + } + + break; + } + } + else break; + } + + // If the current transformation has no information for the current frame time point + if (shouldSkipFurtherTransformation) continue; + + if (channel->target_path == cgltf_animation_path_type_translation) + { + Vector3 translationStart; + Vector3 translationEnd; + + bool success = GLTFReadValue(sampler->output, outputMin, &translationStart, 3, sizeof(float)); + success = GLTFReadValue(sampler->output, outputMax, &translationEnd, 3, sizeof(float)) || success; + + if (success) output->framePoses[frame][boneId].translation = Vector3Lerp(translationStart, translationEnd, lerpPercent); + } + if (channel->target_path == cgltf_animation_path_type_rotation) + { + Quaternion rotationStart; + Quaternion rotationEnd; + + bool success = GLTFReadValue(sampler->output, outputMin, &rotationStart, 4, sizeof(float)); + success = GLTFReadValue(sampler->output, outputMax, &rotationEnd, 4, sizeof(float)) || success; + + if (success) + { + output->framePoses[frame][boneId].rotation = QuaternionLerp(rotationStart, rotationEnd, lerpPercent); + output->framePoses[frame][boneId].rotation = QuaternionNormalize(output->framePoses[frame][boneId].rotation); + } + } + if (channel->target_path == cgltf_animation_path_type_scale) + { + Vector3 scaleStart; + Vector3 scaleEnd; + + bool success = GLTFReadValue(sampler->output, outputMin, &scaleStart, 3, sizeof(float)); + success = GLTFReadValue(sampler->output, outputMax, &scaleEnd, 3, sizeof(float)) || success; + + if (success) output->framePoses[frame][boneId].scale = Vector3Lerp(scaleStart, scaleEnd, lerpPercent); + } + } + } + + // Build frameposes + for (int frame = 0; frame < output->frameCount; frame++) + { + bool *completedBones = RL_CALLOC(output->boneCount, sizeof(bool)); + int numberCompletedBones = 0; + + while (numberCompletedBones < output->boneCount) + { + for (int i = 0; i < output->boneCount; i++) + { + if (completedBones[i]) continue; + + if (output->bones[i].parent < 0) + { + completedBones[i] = true; + numberCompletedBones++; + continue; + } + + if (!completedBones[output->bones[i].parent]) continue; + + output->framePoses[frame][i].rotation = QuaternionMultiply(output->framePoses[frame][output->bones[i].parent].rotation, output->framePoses[frame][i].rotation); + output->framePoses[frame][i].translation = Vector3RotateByQuaternion(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].rotation); + output->framePoses[frame][i].translation = Vector3Add(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].translation); + output->framePoses[frame][i].scale = Vector3Multiply(output->framePoses[frame][i].scale, output->framePoses[frame][output->bones[i].parent].scale); + completedBones[i] = true; + numberCompletedBones++; + } + } + + RL_FREE(completedBones); + } + + } + + cgltf_free(data); + } + else TRACELOG(LOG_WARNING, ": [%s] Failed to load glTF data", fileName); + + RL_FREE(fileData); + + return animations; +} + +#endif diff --git a/raylib/rmodels.go b/raylib/models.go similarity index 50% rename from raylib/rmodels.go rename to raylib/models.go index fc58860..fb04702 100644 --- a/raylib/rmodels.go +++ b/raylib/models.go @@ -5,243 +5,147 @@ package rl #include */ import "C" - -import ( - "image/color" - "unsafe" -) - -// newMeshFromPointer - Returns new Mesh from pointer -func newMeshFromPointer(ptr unsafe.Pointer) Mesh { - return *(*Mesh)(ptr) -} +import "unsafe" // cptr returns C pointer func (m *Mesh) cptr() *C.Mesh { return (*C.Mesh)(unsafe.Pointer(m)) } -// newMaterialFromPointer - Returns new Material from pointer -func newMaterialFromPointer(ptr unsafe.Pointer) Material { - return *(*Material)(ptr) -} - // cptr returns C pointer func (m *Material) cptr() *C.Material { return (*C.Material)(unsafe.Pointer(m)) } -// newModelFromPointer - Returns new Model from pointer -func newModelFromPointer(ptr unsafe.Pointer) Model { - return *(*Model)(ptr) -} - // cptr returns C pointer func (m *Model) cptr() *C.Model { return (*C.Model)(unsafe.Pointer(m)) } -// newRayFromPointer - Returns new Ray from pointer -func newRayFromPointer(ptr unsafe.Pointer) Ray { - return *(*Ray)(ptr) -} - // cptr returns C pointer func (r *Ray) cptr() *C.Ray { return (*C.Ray)(unsafe.Pointer(r)) } -// newModelAnimationFromPointer - Returns new ModelAnimation from pointer -func newModelAnimationFromPointer(ptr unsafe.Pointer) ModelAnimation { - return *(*ModelAnimation)(ptr) -} - -// cptr returns C pointer -func (r *ModelAnimation) cptr() *C.ModelAnimation { - return (*C.ModelAnimation)(unsafe.Pointer(r)) -} - -// newRayCollisionFromPointer - Returns new RayCollision from pointer -func newRayCollisionFromPointer(ptr unsafe.Pointer) RayCollision { - return *(*RayCollision)(ptr) -} - // DrawLine3D - Draw a line in 3D world space -func DrawLine3D(startPos Vector3, endPos Vector3, col color.RGBA) { +func DrawLine3D(startPos Vector3, endPos Vector3, color Color) { cstartPos := startPos.cptr() cendPos := endPos.cptr() - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawLine3D(*cstartPos, *cendPos, *ccolor) } -// DrawPoint3D - Draw a point in 3D space, actually a small line -func DrawPoint3D(position Vector3, col color.RGBA) { - cposition := position.cptr() - ccolor := colorCptr(col) - C.DrawPoint3D(*cposition, *ccolor) -} - // DrawCircle3D - Draw a circle in 3D world space -func DrawCircle3D(center Vector3, radius float32, rotationAxis Vector3, rotationAngle float32, col color.RGBA) { +func DrawCircle3D(center Vector3, radius float32, rotationAxis Vector3, rotationAngle float32, color Color) { ccenter := center.cptr() cradius := (C.float)(radius) crotationAxis := rotationAxis.cptr() crotationAngle := (C.float)(rotationAngle) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawCircle3D(*ccenter, cradius, *crotationAxis, crotationAngle, *ccolor) } -// DrawTriangle3D - Draw a color-filled triangle (vertex in counter-clockwise order!) -func DrawTriangle3D(v1 Vector3, v2 Vector3, v3 Vector3, col color.RGBA) { - cv1 := v1.cptr() - cv2 := v2.cptr() - cv3 := v3.cptr() - ccolor := colorCptr(col) - C.DrawTriangle3D(*cv1, *cv2, *cv3, *ccolor) -} - // DrawCube - Draw cube -func DrawCube(position Vector3, width float32, height float32, length float32, col color.RGBA) { +func DrawCube(position Vector3, width float32, height float32, length float32, color Color) { cposition := position.cptr() cwidth := (C.float)(width) cheight := (C.float)(height) clength := (C.float)(length) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawCube(*cposition, cwidth, cheight, clength, *ccolor) } // DrawCubeV - Draw cube (Vector version) -func DrawCubeV(position Vector3, size Vector3, col color.RGBA) { +func DrawCubeV(position Vector3, size Vector3, color Color) { cposition := position.cptr() csize := size.cptr() - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawCubeV(*cposition, *csize, *ccolor) } // DrawCubeWires - Draw cube wires -func DrawCubeWires(position Vector3, width float32, height float32, length float32, col color.RGBA) { +func DrawCubeWires(position Vector3, width float32, height float32, length float32, color Color) { cposition := position.cptr() cwidth := (C.float)(width) cheight := (C.float)(height) clength := (C.float)(length) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawCubeWires(*cposition, cwidth, cheight, clength, *ccolor) } -// DrawCubeWiresV - Draw cube wires (Vector version) -func DrawCubeWiresV(position Vector3, size Vector3, col color.RGBA) { +// DrawCubeTexture - Draw cube textured +func DrawCubeTexture(texture Texture2D, position Vector3, width float32, height float32, length float32, color Color) { + ctexture := texture.cptr() cposition := position.cptr() - csize := size.cptr() - ccolor := colorCptr(col) - C.DrawCubeWiresV(*cposition, *csize, *ccolor) + cwidth := (C.float)(width) + cheight := (C.float)(height) + clength := (C.float)(length) + ccolor := color.cptr() + C.DrawCubeTexture(*ctexture, *cposition, cwidth, cheight, clength, *ccolor) } // DrawSphere - Draw sphere -func DrawSphere(centerPos Vector3, radius float32, col color.RGBA) { +func DrawSphere(centerPos Vector3, radius float32, color Color) { ccenterPos := centerPos.cptr() cradius := (C.float)(radius) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawSphere(*ccenterPos, cradius, *ccolor) } // DrawSphereEx - Draw sphere with extended parameters -func DrawSphereEx(centerPos Vector3, radius float32, rings int32, slices int32, col color.RGBA) { +func DrawSphereEx(centerPos Vector3, radius float32, rings int32, slices int32, color Color) { ccenterPos := centerPos.cptr() cradius := (C.float)(radius) crings := (C.int)(rings) cslices := (C.int)(slices) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawSphereEx(*ccenterPos, cradius, crings, cslices, *ccolor) } // DrawSphereWires - Draw sphere wires -func DrawSphereWires(centerPos Vector3, radius float32, rings int32, slices int32, col color.RGBA) { +func DrawSphereWires(centerPos Vector3, radius float32, rings int32, slices int32, color Color) { ccenterPos := centerPos.cptr() cradius := (C.float)(radius) crings := (C.int)(rings) cslices := (C.int)(slices) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawSphereWires(*ccenterPos, cradius, crings, cslices, *ccolor) } // DrawCylinder - Draw a cylinder/cone -func DrawCylinder(position Vector3, radiusTop float32, radiusBottom float32, height float32, slices int32, col color.RGBA) { +func DrawCylinder(position Vector3, radiusTop float32, radiusBottom float32, height float32, slices int32, color Color) { cposition := position.cptr() cradiusTop := (C.float)(radiusTop) cradiusBottom := (C.float)(radiusBottom) cheight := (C.float)(height) cslices := (C.int)(slices) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawCylinder(*cposition, cradiusTop, cradiusBottom, cheight, cslices, *ccolor) } -// DrawCylinderEx - Draw a cylinder with base at startPos and top at endPos -func DrawCylinderEx(startPos Vector3, endPos Vector3, startRadius float32, endRadius float32, sides int32, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - cstartRadius := (C.float)(startRadius) - cendRadius := (C.float)(endRadius) - csides := (C.int)(sides) - ccolor := colorCptr(col) - C.DrawCylinderEx(*cstartPos, *cendPos, cstartRadius, cendRadius, csides, *ccolor) -} - // DrawCylinderWires - Draw a cylinder/cone wires -func DrawCylinderWires(position Vector3, radiusTop float32, radiusBottom float32, height float32, slices int32, col color.RGBA) { +func DrawCylinderWires(position Vector3, radiusTop float32, radiusBottom float32, height float32, slices int32, color Color) { cposition := position.cptr() cradiusTop := (C.float)(radiusTop) cradiusBottom := (C.float)(radiusBottom) cheight := (C.float)(height) cslices := (C.int)(slices) - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawCylinderWires(*cposition, cradiusTop, cradiusBottom, cheight, cslices, *ccolor) } -// DrawCylinderWiresEx - Draw a cylinder wires with base at startPos and top at endPos -func DrawCylinderWiresEx(startPos Vector3, endPos Vector3, startRadius float32, endRadius float32, sides int32, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - cstartRadius := (C.float)(startRadius) - cendRadius := (C.float)(endRadius) - csides := (C.int)(sides) - ccolor := colorCptr(col) - C.DrawCylinderWiresEx(*cstartPos, *cendPos, cstartRadius, cendRadius, csides, *ccolor) -} - -// DrawCapsule - Draw a capsule with the center of its sphere caps at startPos and endPos -func DrawCapsule(startPos, endPos Vector3, radius float32, slices, rings int32, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - cradius := (C.float)(radius) - cslices := (C.int)(slices) - crings := (C.int)(rings) - ccolor := colorCptr(col) - C.DrawCapsule(*cstartPos, *cendPos, cradius, cslices, crings, *ccolor) -} - -// DrawCapsuleWires - Draw capsule wireframe with the center of its sphere caps at startPos and endPos -func DrawCapsuleWires(startPos, endPos Vector3, radius float32, slices, rings int32, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - cradius := (C.float)(radius) - cslices := (C.int)(slices) - crings := (C.int)(rings) - ccolor := colorCptr(col) - C.DrawCapsuleWires(*cstartPos, *cendPos, cradius, cslices, crings, *ccolor) -} - // DrawPlane - Draw a plane XZ -func DrawPlane(centerPos Vector3, size Vector2, col color.RGBA) { +func DrawPlane(centerPos Vector3, size Vector2, color Color) { ccenterPos := centerPos.cptr() csize := size.cptr() - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawPlane(*ccenterPos, *csize, *ccolor) } // DrawRay - Draw a ray line -func DrawRay(ray Ray, col color.RGBA) { +func DrawRay(ray Ray, color Color) { cray := ray.cptr() - ccolor := colorCptr(col) + ccolor := color.cptr() C.DrawRay(*cray, *ccolor) } @@ -269,146 +173,16 @@ func LoadModelFromMesh(data Mesh) Model { return v } -// IsModelValid - Check if a model is valid (loaded in GPU, VAO/VBOs) -func IsModelValid(model Model) bool { - cmodel := model.cptr() - ret := C.IsModelValid(*cmodel) - v := bool(ret) - return v -} - // UnloadModel - Unload model from memory (RAM and/or VRAM) func UnloadModel(model Model) { cmodel := model.cptr() C.UnloadModel(*cmodel) } -// GetModelBoundingBox - Compute model bounding box limits (considers all meshes -func GetModelBoundingBox(model Model) BoundingBox { - cmodel := model.cptr() - ret := C.GetModelBoundingBox(*cmodel) - v := newBoundingBoxFromPointer(unsafe.Pointer(&ret)) - return v -} - -// DrawModel - Draw a model (with texture if set) -func DrawModel(model Model, position Vector3, scale float32, tint color.RGBA) { - cmodel := model.cptr() - cposition := position.cptr() - cscale := (C.float)(scale) - ctint := colorCptr(tint) - C.DrawModel(*cmodel, *cposition, cscale, *ctint) -} - -// DrawModelEx - Draw a model with extended parameters -func DrawModelEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint color.RGBA) { - cmodel := model.cptr() - cposition := position.cptr() - crotationAxis := rotationAxis.cptr() - crotationAngle := (C.float)(rotationAngle) - cscale := scale.cptr() - ctint := colorCptr(tint) - C.DrawModelEx(*cmodel, *cposition, *crotationAxis, crotationAngle, *cscale, *ctint) -} - -// DrawModelWires - Draw a model wires (with texture if set) -func DrawModelWires(model Model, position Vector3, scale float32, tint color.RGBA) { - cmodel := model.cptr() - cposition := position.cptr() - cscale := (C.float)(scale) - ctint := colorCptr(tint) - C.DrawModelWires(*cmodel, *cposition, cscale, *ctint) -} - -// DrawModelWiresEx - Draw a model wires (with texture if set) with extended parameters -func DrawModelWiresEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint color.RGBA) { - cmodel := model.cptr() - cposition := position.cptr() - crotationAxis := rotationAxis.cptr() - crotationAngle := (C.float)(rotationAngle) - cscale := scale.cptr() - ctint := colorCptr(tint) - C.DrawModelWiresEx(*cmodel, *cposition, *crotationAxis, crotationAngle, *cscale, *ctint) -} - -// DrawModelPoints - Draw a model as points -func DrawModelPoints(model Model, position Vector3, scale float32, tint color.RGBA) { - cmodel := model.cptr() - cposition := position.cptr() - cscale := (C.float)(scale) - ctint := colorCptr(tint) - C.DrawModelPoints(*cmodel, *cposition, cscale, *ctint) -} - -// DrawModelPointsEx - Draw a model as points with extended parameters -func DrawModelPointsEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint color.RGBA) { - cmodel := model.cptr() - cposition := position.cptr() - crotationAxis := rotationAxis.cptr() - crotationAngle := (C.float)(rotationAngle) - cscale := scale.cptr() - ctint := colorCptr(tint) - C.DrawModelPointsEx(*cmodel, *cposition, *crotationAxis, crotationAngle, *cscale, *ctint) -} - -// DrawBoundingBox - Draw bounding box (wires) -func DrawBoundingBox(box BoundingBox, col color.RGBA) { - cbox := box.cptr() - ccolor := colorCptr(col) - C.DrawBoundingBox(*cbox, *ccolor) -} - -// DrawBillboard - Draw a billboard texture -func DrawBillboard(camera Camera, texture Texture2D, center Vector3, scale float32, tint color.RGBA) { - ccamera := camera.cptr() - ctexture := texture.cptr() - ccenter := center.cptr() - cscale := (C.float)(scale) - ctint := colorCptr(tint) - C.DrawBillboard(*ccamera, *ctexture, *ccenter, cscale, *ctint) -} - -// DrawBillboardRec - Draw a billboard texture defined by sourceRec -func DrawBillboardRec(camera Camera, texture Texture2D, sourceRec Rectangle, center Vector3, size Vector2, tint color.RGBA) { - ccamera := camera.cptr() - ctexture := texture.cptr() - csourceRec := sourceRec.cptr() - ccenter := center.cptr() - csize := size.cptr() - ctint := colorCptr(tint) - C.DrawBillboardRec(*ccamera, *ctexture, *csourceRec, *ccenter, *csize, *ctint) -} - -// DrawBillboardPro - Draw a billboard texture with pro parameters -func DrawBillboardPro(camera Camera, texture Texture2D, sourceRec Rectangle, position Vector3, up Vector3, size Vector2, origin Vector2, rotation float32, tint Color) { - ccamera := camera.cptr() - ctexture := texture.cptr() - csourceRec := sourceRec.cptr() - cposition := position.cptr() - cup := up.cptr() - csize := size.cptr() - corigin := origin.cptr() - crotation := (C.float)(rotation) - ctint := colorCptr(tint) - C.DrawBillboardPro(*ccamera, *ctexture, *csourceRec, *cposition, *cup, *csize, *corigin, crotation, *ctint) -} - -// UpdateMeshBuffer - Update mesh vertex data in GPU for a specific buffer index -func UpdateMeshBuffer(mesh Mesh, index int, data []byte, offset int) { - cindex := (C.int)(index) - coffset := (C.int)(offset) - cdataSize := (C.int)(len(data)) - C.UpdateMeshBuffer(*mesh.cptr(), cindex, unsafe.Pointer(&data[0]), cdataSize, coffset) -} - -// DrawMesh - Draw a single mesh -func DrawMesh(mesh Mesh, material Material, transform Matrix) { - C.DrawMesh(*mesh.cptr(), *material.cptr(), *transform.cptr()) -} - -// DrawMeshInstanced - Draw mesh with instanced rendering -func DrawMeshInstanced(mesh Mesh, material Material, transforms []Matrix, instances int) { - C.DrawMeshInstanced(*mesh.cptr(), *material.cptr(), transforms[0].cptr(), C.int(instances)) +// UnloadMesh - Unload mesh from memory (RAM and/or VRAM) +func UnloadMesh(mesh *Mesh) { + cmesh := mesh.cptr() + C.UnloadMesh(*cmesh) } // ExportMesh - Export mesh as an OBJ file @@ -419,24 +193,6 @@ func ExportMesh(mesh Mesh, fileName string) { C.ExportMesh(*cmesh, cfileName) } -// GetMeshBoundingBox - Compute mesh bounding box limits -func GetMeshBoundingBox(mesh Mesh) BoundingBox { - cmesh := mesh.cptr() - ret := C.GetMeshBoundingBox(*cmesh) - v := newBoundingBoxFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshPoly - Generate polygonal mesh -func GenMeshPoly(sides int, radius float32) Mesh { - csides := (C.int)(sides) - cradius := (C.float)(radius) - - ret := C.GenMeshPoly(csides, cradius) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - // GenMeshPlane - Generate plane mesh (with subdivisions) func GenMeshPlane(width, length float32, resX, resZ int) Mesh { cwidth := (C.float)(width) @@ -493,17 +249,6 @@ func GenMeshCylinder(radius, height float32, slices int) Mesh { return v } -// GenMeshCone - Generate cone/pyramid mesh -func GenMeshCone(radius, height float32, slices int) Mesh { - cradius := (C.float)(radius) - cheight := (C.float)(height) - cslices := (C.int)(slices) - - ret := C.GenMeshCone(cradius, cheight, cslices) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - // GenMeshTorus - Generate torus mesh func GenMeshTorus(radius, size float32, radSeg, sides int) Mesh { cradius := (C.float)(radius) @@ -549,12 +294,12 @@ func GenMeshCubicmap(cubicmap Image, size Vector3) Mesh { } // LoadMaterials - Load material data (.MTL) -func LoadMaterials(fileName string) []Material { +func LoadMaterials(fileName string) Material { cfileName := C.CString(fileName) defer C.free(unsafe.Pointer(cfileName)) ccount := C.int(0) ret := C.LoadMaterials(cfileName, &ccount) - v := (*[1 << 24]Material)(unsafe.Pointer(ret))[:int(ccount)] + v := newMaterialFromPointer(unsafe.Pointer(&ret)) return v } @@ -565,14 +310,6 @@ func LoadMaterialDefault() Material { return v } -// IsMaterialValid - Check if a material is valid (shader assigned, map textures loaded in GPU) -func IsMaterialValid(material Material) bool { - cmaterial := material.cptr() - ret := C.IsMaterialValid(*cmaterial) - v := bool(ret) - return v -} - // UnloadMaterial - Unload material textures from VRAM func UnloadMaterial(material Material) { cmaterial := material.cptr() @@ -595,49 +332,79 @@ func SetModelMeshMaterial(model *Model, meshId int32, materialId int32) { C.SetModelMeshMaterial(cmodel, cmeshId, cmaterialId) } -// LoadModelAnimations - Load model animations from file -func LoadModelAnimations(fileName string) []ModelAnimation { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ccount := C.int(0) - ret := C.LoadModelAnimations(cfileName, &ccount) - v := (*[1 << 24]ModelAnimation)(unsafe.Pointer(ret))[:int(ccount)] - return v -} - -// UpdateModelAnimation - Update model animation pose (CPU) -func UpdateModelAnimation(model Model, anim ModelAnimation, frame int32) { +// DrawModel - Draw a model (with texture if set) +func DrawModel(model Model, position Vector3, scale float32, tint Color) { cmodel := model.cptr() - canim := anim.cptr() - cframe := (C.int)(frame) - C.UpdateModelAnimation(*cmodel, *canim, cframe) + cposition := position.cptr() + cscale := (C.float)(scale) + ctint := tint.cptr() + C.DrawModel(*cmodel, *cposition, cscale, *ctint) } -// UpdateModelAnimationBones - Update model animation mesh bone matrices (GPU skinning) -func UpdateModelAnimationBones(model Model, anim ModelAnimation, frame int32) { +// DrawModelEx - Draw a model with extended parameters +func DrawModelEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint Color) { cmodel := model.cptr() - canim := anim.cptr() - cframe := (C.int)(frame) - C.UpdateModelAnimationBones(*cmodel, *canim, cframe) + cposition := position.cptr() + crotationAxis := rotationAxis.cptr() + crotationAngle := (C.float)(rotationAngle) + cscale := scale.cptr() + ctint := tint.cptr() + C.DrawModelEx(*cmodel, *cposition, *crotationAxis, crotationAngle, *cscale, *ctint) } -// UnloadModelAnimation - Unload animation data -func UnloadModelAnimation(anim ModelAnimation) { - canim := anim.cptr() - C.UnloadModelAnimation(*canim) -} - -// UnloadModelAnimations - Unload animation array data -func UnloadModelAnimations(animations []ModelAnimation) { - C.UnloadModelAnimations((*C.ModelAnimation)(unsafe.Pointer(&animations[0])), (C.int)(len(animations))) -} - -// IsModelAnimationValid - Check model animation skeleton match -func IsModelAnimationValid(model Model, anim ModelAnimation) bool { +// DrawModelWires - Draw a model wires (with texture if set) +func DrawModelWires(model Model, position Vector3, scale float32, tint Color) { cmodel := model.cptr() - canim := anim.cptr() - ret := C.IsModelAnimationValid(*cmodel, *canim) - v := bool(ret) + cposition := position.cptr() + cscale := (C.float)(scale) + ctint := tint.cptr() + C.DrawModelWires(*cmodel, *cposition, cscale, *ctint) +} + +// DrawModelWiresEx - Draw a model wires (with texture if set) with extended parameters +func DrawModelWiresEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint Color) { + cmodel := model.cptr() + cposition := position.cptr() + crotationAxis := rotationAxis.cptr() + crotationAngle := (C.float)(rotationAngle) + cscale := scale.cptr() + ctint := tint.cptr() + C.DrawModelWiresEx(*cmodel, *cposition, *crotationAxis, crotationAngle, *cscale, *ctint) +} + +// DrawBoundingBox - Draw bounding box (wires) +func DrawBoundingBox(box BoundingBox, color Color) { + cbox := box.cptr() + ccolor := color.cptr() + C.DrawBoundingBox(*cbox, *ccolor) +} + +// DrawBillboard - Draw a billboard texture +func DrawBillboard(camera Camera, texture Texture2D, center Vector3, size float32, tint Color) { + ccamera := camera.cptr() + ctexture := texture.cptr() + ccenter := center.cptr() + csize := (C.float)(size) + ctint := tint.cptr() + C.DrawBillboard(*ccamera, *ctexture, *ccenter, csize, *ctint) +} + +// DrawBillboardRec - Draw a billboard texture defined by sourceRec +func DrawBillboardRec(camera Camera, texture Texture2D, sourceRec Rectangle, center Vector3, size Vector2, tint Color) { + ccamera := camera.cptr() + ctexture := texture.cptr() + csourceRec := sourceRec.cptr() + ccenter := center.cptr() + csize := size.cptr() + ctint := tint.cptr() + C.DrawBillboardRec(*ccamera, *ctexture, *csourceRec, *ccenter, *csize, *ctint) +} + +// GetMeshBoundingBox - Compute mesh bounding box limits +func GetMeshBoundingBox(mesh Mesh) BoundingBox { + cmesh := mesh.cptr() + ret := C.GetMeshBoundingBox(*cmesh) + v := newBoundingBoxFromPointer(unsafe.Pointer(&ret)) return v } @@ -671,54 +438,32 @@ func CheckCollisionBoxSphere(box BoundingBox, centerSphere Vector3, radiusSphere return v } -// GetRayCollisionSphere - Get collision info between ray and sphere -func GetRayCollisionSphere(ray Ray, center Vector3, radius float32) RayCollision { +// CheckCollisionRaySphere - Detect collision between ray and sphere +func CheckCollisionRaySphere(ray Ray, spherePosition Vector3, sphereRadius float32) bool { cray := ray.cptr() - ccenter := center.cptr() - cradius := (C.float)(radius) - ret := C.GetRayCollisionSphere(*cray, *ccenter, cradius) - v := newRayCollisionFromPointer(unsafe.Pointer(&ret)) + cspherePosition := spherePosition.cptr() + csphereRadius := (C.float)(sphereRadius) + ret := C.CheckCollisionRaySphere(*cray, *cspherePosition, csphereRadius) + v := bool(ret) return v } -// GetRayCollisionBox - Get collision info between ray and box -func GetRayCollisionBox(ray Ray, box BoundingBox) RayCollision { +// CheckCollisionRaySphereEx - Detect collision between ray and sphere with extended parameters and collision point detection +func CheckCollisionRaySphereEx(ray Ray, spherePosition Vector3, sphereRadius float32, collisionPoint Vector3) bool { + cray := ray.cptr() + cspherePosition := spherePosition.cptr() + csphereRadius := (C.float)(sphereRadius) + ccollisionPoint := collisionPoint.cptr() + ret := C.CheckCollisionRaySphereEx(*cray, *cspherePosition, csphereRadius, ccollisionPoint) + v := bool(ret) + return v +} + +// CheckCollisionRayBox - Detect collision between ray and box +func CheckCollisionRayBox(ray Ray, box BoundingBox) bool { cray := ray.cptr() cbox := box.cptr() - ret := C.GetRayCollisionBox(*cray, *cbox) - v := newRayCollisionFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetRayCollisionMesh - Get collision info between ray and mesh -func GetRayCollisionMesh(ray Ray, mesh Mesh, transform Matrix) RayCollision { - cray := ray.cptr() - cmesh := mesh.cptr() - ctransform := transform.cptr() - ret := C.GetRayCollisionMesh(*cray, *cmesh, *ctransform) - v := newRayCollisionFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetRayCollisionTriangle - Get collision info between ray and triangle -func GetRayCollisionTriangle(ray Ray, p1, p2, p3 Vector3) RayCollision { - cray := ray.cptr() - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - ret := C.GetRayCollisionTriangle(*cray, *cp1, *cp2, *cp3) - v := newRayCollisionFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetRayCollisionQuad - Get collision info between ray and quad -func GetRayCollisionQuad(ray Ray, p1, p2, p3, p4 Vector3) RayCollision { - cray := ray.cptr() - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - ret := C.GetRayCollisionQuad(*cray, *cp1, *cp2, *cp3, *cp4) - v := newRayCollisionFromPointer(unsafe.Pointer(&ret)) + ret := C.CheckCollisionRayBox(*cray, *cbox) + v := bool(ret) return v } diff --git a/raylib/platform_android.c b/raylib/platform_android.c new file mode 100644 index 0000000..1e5574b --- /dev/null +++ b/raylib/platform_android.c @@ -0,0 +1,12 @@ +// +build android + +#include "_cgo_export.h" + +struct android_app *GetAndroidApp(); + +void android_init() { + struct android_app *app; + app = GetAndroidApp(); + asset_manager = app->activity->assetManager; + internal_storage_path = app->activity->internalDataPath; +} diff --git a/raylib/platform_android.go b/raylib/platform_android.go index ecde316..47d7762 100644 --- a/raylib/platform_android.go +++ b/raylib/platform_android.go @@ -1,4 +1,3 @@ -//go:build android // +build android package rl @@ -9,17 +8,10 @@ package rl #include #include -extern struct android_app* GetAndroidApp(); +extern void android_init(); -static AAssetManager* GetAssetManager() { - struct android_app* app = GetAndroidApp(); - return app->activity->assetManager; -} - -static const char* GetInternalStoragePath() { - struct android_app* app = GetAndroidApp(); - return app->activity->internalDataPath; -} +AAssetManager* asset_manager; +const char* internal_storage_path; */ import "C" @@ -40,6 +32,7 @@ func InitWindow(width int32, height int32, title string) { defer C.free(unsafe.Pointer(ctitle)) C.InitWindow(cwidth, cheight, ctitle) + C.android_init() } // SetCallbackFunc - Sets callback function @@ -89,13 +82,13 @@ func IsFileDropped() bool { return false } -// LoadDroppedFiles - Load dropped filepaths -func LoadDroppedFiles() (files []string) { +// GetDroppedFiles - Retrieve dropped files into window +func GetDroppedFiles(count *int32) (files []string) { return } -// UnloadDroppedFiles - Unload dropped filepaths -func UnloadDroppedFiles() { +// ClearDroppedFiles - Clear dropped files paths buffer +func ClearDroppedFiles() { return } @@ -104,7 +97,7 @@ func OpenAsset(name string) (Asset, error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) - a := &asset{C.AAssetManager_open(C.GetAssetManager(), cname, C.AASSET_MODE_UNKNOWN)} + a := &asset{C.AAssetManager_open(C.asset_manager, cname, C.AASSET_MODE_UNKNOWN)} if a.ptr == nil { return nil, fmt.Errorf("asset file could not be opened") @@ -122,7 +115,6 @@ func (a *asset) Read(p []byte) (n int, err error) { if n == 0 && len(p) > 0 { return 0, io.EOF } - return n, nil } @@ -131,16 +123,10 @@ func (a *asset) Seek(offset int64, whence int) (int64, error) { if off == -1 { return 0, fmt.Errorf("bad result for offset=%d, whence=%d", offset, whence) } - return int64(off), nil } func (a *asset) Close() error { C.AAsset_close(a.ptr) - return nil } - -func getInternalStoragePath() string { - return C.GoString(C.GetInternalStoragePath()) -} diff --git a/raylib/platform_desktop.go b/raylib/platform_desktop.go index 91634fb..0074ba0 100644 --- a/raylib/platform_desktop.go +++ b/raylib/platform_desktop.go @@ -1,5 +1,4 @@ -//go:build !rgfw && !sdl && !sdl3 && !drm && !android -// +build !rgfw,!sdl,!sdl3,!drm,!android +// +build !rpi,!drm,!android package rl @@ -27,6 +26,7 @@ func InitWindow(width int32, height int32, title string) { // SetCallbackFunc - Sets callback function func SetCallbackFunc(func()) { + return } // ShowCursor - Shows cursor @@ -43,7 +43,6 @@ func HideCursor() { func IsCursorHidden() bool { ret := C.IsCursorHidden() v := bool(ret) - return v } @@ -51,7 +50,6 @@ func IsCursorHidden() bool { func IsCursorOnScreen() bool { ret := C.IsCursorOnScreen() v := bool(ret) - return v } @@ -69,17 +67,16 @@ func DisableCursor() { func IsFileDropped() bool { ret := C.IsFileDropped() v := bool(ret) - return v } -// LoadDroppedFiles - Load dropped filepaths -func LoadDroppedFiles() []string { - ret := C.LoadDroppedFiles() - defer C.UnloadDroppedFiles(ret) +// GetDroppedFiles - Retrieve dropped files into window +func GetDroppedFiles(count *int32) []string { + ccount := (*C.int)(unsafe.Pointer(count)) + ret := C.GetDroppedFiles(ccount) - tmpslice := (*[1 << 24]*C.char)(unsafe.Pointer(ret.paths))[:ret.count:ret.count] - gostrings := make([]string, ret.count) + tmpslice := (*[1 << 24]*C.char)(unsafe.Pointer(ret))[:*count:*count] + gostrings := make([]string, *count) for i, s := range tmpslice { gostrings[i] = C.GoString(s) } @@ -87,8 +84,9 @@ func LoadDroppedFiles() []string { return gostrings } -// UnloadDroppedFiles - Unload dropped filepaths -func UnloadDroppedFiles() { +// ClearDroppedFiles - Clear dropped files paths buffer +func ClearDroppedFiles() { + C.ClearDroppedFiles() } // OpenAsset - Open asset @@ -97,6 +95,5 @@ func OpenAsset(name string) (Asset, error) { if err != nil { return nil, err } - return f, nil } diff --git a/raylib/platform_desktop_sdl.go b/raylib/platform_desktop_sdl.go deleted file mode 100644 index 82cf7ad..0000000 --- a/raylib/platform_desktop_sdl.go +++ /dev/null @@ -1,105 +0,0 @@ -//go:build (sdl || sdl3) && !rgfw && !drm && !android -// +build sdl sdl3 -// +build !rgfw -// +build !drm -// +build !android - -package rl - -/* -#include "raylib.h" -#include -*/ -import "C" - -import ( - "os" - "unsafe" -) - -// InitWindow - Initialize Window and OpenGL Graphics -func InitWindow(width int32, height int32, title string) { - cwidth := (C.int)(width) - cheight := (C.int)(height) - - ctitle := C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) - - C.InitWindow(cwidth, cheight, ctitle) -} - -// SetCallbackFunc - Sets callback function -func SetCallbackFunc(func()) { -} - -// ShowCursor - Shows cursor -func ShowCursor() { - C.ShowCursor() -} - -// HideCursor - Hides cursor -func HideCursor() { - C.HideCursor() -} - -// IsCursorHidden - Returns true if cursor is not visible -func IsCursorHidden() bool { - ret := C.IsCursorHidden() - v := bool(ret) - - return v -} - -// IsCursorOnScreen - Check if cursor is on the current screen. -func IsCursorOnScreen() bool { - ret := C.IsCursorOnScreen() - v := bool(ret) - - return v -} - -// EnableCursor - Enables cursor -func EnableCursor() { - C.EnableCursor() -} - -// DisableCursor - Disables cursor -func DisableCursor() { - C.DisableCursor() -} - -// IsFileDropped - Check if a file have been dropped into window -func IsFileDropped() bool { - ret := C.IsFileDropped() - v := bool(ret) - - return v -} - -// LoadDroppedFiles - Load dropped filepaths -func LoadDroppedFiles() []string { - ret := C.LoadDroppedFiles() - defer C.UnloadDroppedFiles(ret) - - tmpslice := (*[1 << 24]*C.char)(unsafe.Pointer(ret.paths))[:ret.count:ret.count] - gostrings := make([]string, ret.count) - for i, s := range tmpslice { - gostrings[i] = C.GoString(s) - } - - return gostrings -} - -// UnloadDroppedFiles - Unload dropped filepaths -func UnloadDroppedFiles() { -} - -// OpenAsset - Open asset -func OpenAsset(name string) (Asset, error) { - f, err := os.Open(name) - if err != nil { - return nil, err - } - - return f, nil -} diff --git a/raylib/platform_drm.go b/raylib/platform_drm.go index fa036d5..22ddcee 100644 --- a/raylib/platform_drm.go +++ b/raylib/platform_drm.go @@ -1,5 +1,4 @@ -//go:build linux && drm && !rgfw && !sdl && !sdl3 && !android -// +build linux,drm,!rgfw,!sdl,!sdl3,!android +// +build linux,drm,!rpi,!android package rl @@ -69,13 +68,13 @@ func IsFileDropped() bool { return false } -// LoadDroppedFiles - Load dropped filepaths -func LoadDroppedFiles() (files []string) { +// GetDroppedFiles - Retrieve dropped files into window +func GetDroppedFiles(count *int32) (files []string) { return } -// UnloadDroppedFiles - Unload dropped filepaths -func UnloadDroppedFiles() { +// ClearDroppedFiles - Clear dropped files paths buffer +func ClearDroppedFiles() { return } diff --git a/raylib/platform_desktop_rgfw.go b/raylib/platform_rpi.go similarity index 69% rename from raylib/platform_desktop_rgfw.go rename to raylib/platform_rpi.go index ba77eec..853b6b5 100644 --- a/raylib/platform_desktop_rgfw.go +++ b/raylib/platform_rpi.go @@ -1,5 +1,4 @@ -//go:build rgfw && !sdl && !sdl3 && !drm && !android -// +build rgfw,!sdl,!sdl3,!drm,!android +// +build linux,rpi,!drm,!android package rl @@ -27,6 +26,7 @@ func InitWindow(width int32, height int32, title string) { // SetCallbackFunc - Sets callback function func SetCallbackFunc(func()) { + return } // ShowCursor - Shows cursor @@ -43,7 +43,6 @@ func HideCursor() { func IsCursorHidden() bool { ret := C.IsCursorHidden() v := bool(ret) - return v } @@ -51,7 +50,6 @@ func IsCursorHidden() bool { func IsCursorOnScreen() bool { ret := C.IsCursorOnScreen() v := bool(ret) - return v } @@ -67,28 +65,17 @@ func DisableCursor() { // IsFileDropped - Check if a file have been dropped into window func IsFileDropped() bool { - ret := C.IsFileDropped() - v := bool(ret) - - return v + return false } -// LoadDroppedFiles - Load dropped filepaths -func LoadDroppedFiles() []string { - ret := C.LoadDroppedFiles() - defer C.UnloadDroppedFiles(ret) - - tmpslice := (*[1 << 24]*C.char)(unsafe.Pointer(ret.paths))[:ret.count:ret.count] - gostrings := make([]string, ret.count) - for i, s := range tmpslice { - gostrings[i] = C.GoString(s) - } - - return gostrings +// GetDroppedFiles - Retrieve dropped files into window +func GetDroppedFiles(count *int32) (files []string) { + return } -// UnloadDroppedFiles - Unload dropped filepaths -func UnloadDroppedFiles() { +// ClearDroppedFiles - Clear dropped files paths buffer +func ClearDroppedFiles() { + return } // OpenAsset - Open asset @@ -97,6 +84,5 @@ func OpenAsset(name string) (Asset, error) { if err != nil { return nil, err } - return f, nil } diff --git a/raylib/platforms/drm-lease-v1.c b/raylib/platforms/drm-lease-v1.c deleted file mode 100644 index 5f75126..0000000 --- a/raylib/platforms/drm-lease-v1.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * Copyright © 2018 NXP - * Copyright © 2019 Status Research & Development GmbH. - * Copyright © 2021 Xaver Hugl - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include "wayland-util.h" - -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - -extern const struct wl_interface wp_drm_lease_connector_v1_interface; -extern const struct wl_interface wp_drm_lease_request_v1_interface; -extern const struct wl_interface wp_drm_lease_v1_interface; - -static const struct wl_interface *drm_lease_v1_types[] = { - NULL, - &wp_drm_lease_request_v1_interface, - &wp_drm_lease_connector_v1_interface, - &wp_drm_lease_connector_v1_interface, - &wp_drm_lease_v1_interface, -}; - -static const struct wl_message wp_drm_lease_device_v1_requests[] = { - { "create_lease_request", "n", drm_lease_v1_types + 1 }, - { "release", "", drm_lease_v1_types + 0 }, -}; - -static const struct wl_message wp_drm_lease_device_v1_events[] = { - { "drm_fd", "h", drm_lease_v1_types + 0 }, - { "connector", "n", drm_lease_v1_types + 2 }, - { "done", "", drm_lease_v1_types + 0 }, - { "released", "", drm_lease_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wp_drm_lease_device_v1_interface = { - "wp_drm_lease_device_v1", 1, - 2, wp_drm_lease_device_v1_requests, - 4, wp_drm_lease_device_v1_events, -}; - -static const struct wl_message wp_drm_lease_connector_v1_requests[] = { - { "destroy", "", drm_lease_v1_types + 0 }, -}; - -static const struct wl_message wp_drm_lease_connector_v1_events[] = { - { "name", "s", drm_lease_v1_types + 0 }, - { "description", "s", drm_lease_v1_types + 0 }, - { "connector_id", "u", drm_lease_v1_types + 0 }, - { "done", "", drm_lease_v1_types + 0 }, - { "withdrawn", "", drm_lease_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wp_drm_lease_connector_v1_interface = { - "wp_drm_lease_connector_v1", 1, - 1, wp_drm_lease_connector_v1_requests, - 5, wp_drm_lease_connector_v1_events, -}; - -static const struct wl_message wp_drm_lease_request_v1_requests[] = { - { "request_connector", "o", drm_lease_v1_types + 3 }, - { "submit", "n", drm_lease_v1_types + 4 }, -}; - -WL_PRIVATE const struct wl_interface wp_drm_lease_request_v1_interface = { - "wp_drm_lease_request_v1", 1, - 2, wp_drm_lease_request_v1_requests, - 0, NULL, -}; - -static const struct wl_message wp_drm_lease_v1_requests[] = { - { "destroy", "", drm_lease_v1_types + 0 }, -}; - -static const struct wl_message wp_drm_lease_v1_events[] = { - { "lease_fd", "h", drm_lease_v1_types + 0 }, - { "finished", "", drm_lease_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wp_drm_lease_v1_interface = { - "wp_drm_lease_v1", 1, - 1, wp_drm_lease_v1_requests, - 2, wp_drm_lease_v1_events, -}; - diff --git a/raylib/platforms/drm-lease-v1.h b/raylib/platforms/drm-lease-v1.h deleted file mode 100644 index ef24934..0000000 --- a/raylib/platforms/drm-lease-v1.h +++ /dev/null @@ -1,743 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef DRM_LEASE_V1_CLIENT_PROTOCOL_H -#define DRM_LEASE_V1_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_drm_lease_v1 The drm_lease_v1 protocol - * @section page_ifaces_drm_lease_v1 Interfaces - * - @subpage page_iface_wp_drm_lease_device_v1 - lease device - * - @subpage page_iface_wp_drm_lease_connector_v1 - a leasable DRM connector - * - @subpage page_iface_wp_drm_lease_request_v1 - DRM lease request - * - @subpage page_iface_wp_drm_lease_v1 - a DRM lease - * @section page_copyright_drm_lease_v1 Copyright - *
- *
- * Copyright © 2018 NXP
- * Copyright © 2019 Status Research & Development GmbH.
- * Copyright © 2021 Xaver Hugl
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- * 
- */ -struct wp_drm_lease_connector_v1; -struct wp_drm_lease_device_v1; -struct wp_drm_lease_request_v1; -struct wp_drm_lease_v1; - -#ifndef WP_DRM_LEASE_DEVICE_V1_INTERFACE -#define WP_DRM_LEASE_DEVICE_V1_INTERFACE -/** - * @page page_iface_wp_drm_lease_device_v1 wp_drm_lease_device_v1 - * @section page_iface_wp_drm_lease_device_v1_desc Description - * - * This protocol is used by Wayland compositors which act as Direct - * Rendering Manager (DRM) masters to lease DRM resources to Wayland - * clients. - * - * The compositor will advertise one wp_drm_lease_device_v1 global for each - * DRM node. Some time after a client binds to the wp_drm_lease_device_v1 - * global, the compositor will send a drm_fd event followed by zero, one or - * more connector events. After all currently available connectors have been - * sent, the compositor will send a wp_drm_lease_device_v1.done event. - * - * When the list of connectors available for lease changes the compositor - * will send wp_drm_lease_device_v1.connector events for added connectors and - * wp_drm_lease_connector_v1.withdrawn events for removed connectors, - * followed by a wp_drm_lease_device_v1.done event. - * - * The compositor will indicate when a device is gone by removing the global - * via a wl_registry.global_remove event. Upon receiving this event, the - * client should destroy any matching wp_drm_lease_device_v1 object. - * - * To destroy a wp_drm_lease_device_v1 object, the client must first issue - * a release request. Upon receiving this request, the compositor will - * immediately send a released event and destroy the object. The client must - * continue to process and discard drm_fd and connector events until it - * receives the released event. Upon receiving the released event, the - * client can safely cleanup any client-side resources. - * - * Warning! The protocol described in this file is currently in the testing - * phase. Backward compatible changes may be added together with the - * corresponding interface version bump. Backward incompatible changes can - * only be done by creating a new major version of the extension. - * @section page_iface_wp_drm_lease_device_v1_api API - * See @ref iface_wp_drm_lease_device_v1. - */ -/** - * @defgroup iface_wp_drm_lease_device_v1 The wp_drm_lease_device_v1 interface - * - * This protocol is used by Wayland compositors which act as Direct - * Rendering Manager (DRM) masters to lease DRM resources to Wayland - * clients. - * - * The compositor will advertise one wp_drm_lease_device_v1 global for each - * DRM node. Some time after a client binds to the wp_drm_lease_device_v1 - * global, the compositor will send a drm_fd event followed by zero, one or - * more connector events. After all currently available connectors have been - * sent, the compositor will send a wp_drm_lease_device_v1.done event. - * - * When the list of connectors available for lease changes the compositor - * will send wp_drm_lease_device_v1.connector events for added connectors and - * wp_drm_lease_connector_v1.withdrawn events for removed connectors, - * followed by a wp_drm_lease_device_v1.done event. - * - * The compositor will indicate when a device is gone by removing the global - * via a wl_registry.global_remove event. Upon receiving this event, the - * client should destroy any matching wp_drm_lease_device_v1 object. - * - * To destroy a wp_drm_lease_device_v1 object, the client must first issue - * a release request. Upon receiving this request, the compositor will - * immediately send a released event and destroy the object. The client must - * continue to process and discard drm_fd and connector events until it - * receives the released event. Upon receiving the released event, the - * client can safely cleanup any client-side resources. - * - * Warning! The protocol described in this file is currently in the testing - * phase. Backward compatible changes may be added together with the - * corresponding interface version bump. Backward incompatible changes can - * only be done by creating a new major version of the extension. - */ -extern const struct wl_interface wp_drm_lease_device_v1_interface; -#endif -#ifndef WP_DRM_LEASE_CONNECTOR_V1_INTERFACE -#define WP_DRM_LEASE_CONNECTOR_V1_INTERFACE -/** - * @page page_iface_wp_drm_lease_connector_v1 wp_drm_lease_connector_v1 - * @section page_iface_wp_drm_lease_connector_v1_desc Description - * - * Represents a DRM connector which is available for lease. These objects are - * created via wp_drm_lease_device_v1.connector events, and should be passed - * to lease requests via wp_drm_lease_request_v1.request_connector. - * Immediately after the wp_drm_lease_connector_v1 object is created the - * compositor will send a name, a description, a connector_id and a done - * event. When the description is updated the compositor will send a - * description event followed by a done event. - * @section page_iface_wp_drm_lease_connector_v1_api API - * See @ref iface_wp_drm_lease_connector_v1. - */ -/** - * @defgroup iface_wp_drm_lease_connector_v1 The wp_drm_lease_connector_v1 interface - * - * Represents a DRM connector which is available for lease. These objects are - * created via wp_drm_lease_device_v1.connector events, and should be passed - * to lease requests via wp_drm_lease_request_v1.request_connector. - * Immediately after the wp_drm_lease_connector_v1 object is created the - * compositor will send a name, a description, a connector_id and a done - * event. When the description is updated the compositor will send a - * description event followed by a done event. - */ -extern const struct wl_interface wp_drm_lease_connector_v1_interface; -#endif -#ifndef WP_DRM_LEASE_REQUEST_V1_INTERFACE -#define WP_DRM_LEASE_REQUEST_V1_INTERFACE -/** - * @page page_iface_wp_drm_lease_request_v1 wp_drm_lease_request_v1 - * @section page_iface_wp_drm_lease_request_v1_desc Description - * - * A client that wishes to lease DRM resources will attach the list of - * connectors advertised with wp_drm_lease_device_v1.connector that they - * wish to lease, then use wp_drm_lease_request_v1.submit to submit the - * request. - * @section page_iface_wp_drm_lease_request_v1_api API - * See @ref iface_wp_drm_lease_request_v1. - */ -/** - * @defgroup iface_wp_drm_lease_request_v1 The wp_drm_lease_request_v1 interface - * - * A client that wishes to lease DRM resources will attach the list of - * connectors advertised with wp_drm_lease_device_v1.connector that they - * wish to lease, then use wp_drm_lease_request_v1.submit to submit the - * request. - */ -extern const struct wl_interface wp_drm_lease_request_v1_interface; -#endif -#ifndef WP_DRM_LEASE_V1_INTERFACE -#define WP_DRM_LEASE_V1_INTERFACE -/** - * @page page_iface_wp_drm_lease_v1 wp_drm_lease_v1 - * @section page_iface_wp_drm_lease_v1_desc Description - * - * A DRM lease object is used to transfer the DRM file descriptor to the - * client and manage the lifetime of the lease. - * - * Some time after the wp_drm_lease_v1 object is created, the compositor - * will reply with the lease request's result. If the lease request is - * granted, the compositor will send a lease_fd event. If the lease request - * is denied, the compositor will send a finished event without a lease_fd - * event. - * @section page_iface_wp_drm_lease_v1_api API - * See @ref iface_wp_drm_lease_v1. - */ -/** - * @defgroup iface_wp_drm_lease_v1 The wp_drm_lease_v1 interface - * - * A DRM lease object is used to transfer the DRM file descriptor to the - * client and manage the lifetime of the lease. - * - * Some time after the wp_drm_lease_v1 object is created, the compositor - * will reply with the lease request's result. If the lease request is - * granted, the compositor will send a lease_fd event. If the lease request - * is denied, the compositor will send a finished event without a lease_fd - * event. - */ -extern const struct wl_interface wp_drm_lease_v1_interface; -#endif - -/** - * @ingroup iface_wp_drm_lease_device_v1 - * @struct wp_drm_lease_device_v1_listener - */ -struct wp_drm_lease_device_v1_listener { - /** - * open a non-master fd for this DRM node - * - * The compositor will send this event when the - * wp_drm_lease_device_v1 global is bound, although there are no - * guarantees as to how long this takes - the compositor might need - * to wait until regaining DRM master. The included fd is a - * non-master DRM file descriptor opened for this device and the - * compositor must not authenticate it. The purpose of this event - * is to give the client the ability to query DRM and discover - * information which may help them pick the appropriate DRM device - * or select the appropriate connectors therein. - * @param fd DRM file descriptor - */ - void (*drm_fd)(void *data, - struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, - int32_t fd); - /** - * advertise connectors available for leases - * - * The compositor will use this event to advertise connectors - * available for lease by clients. This object may be passed into a - * lease request to indicate the client would like to lease that - * connector, see wp_drm_lease_request_v1.request_connector for - * details. While the compositor will make a best effort to not - * send disconnected connectors, no guarantees can be made. - * - * The compositor must send the drm_fd event before sending - * connectors. After the drm_fd event it will send all available - * connectors but may send additional connectors at any time. - */ - void (*connector)(void *data, - struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, - struct wp_drm_lease_connector_v1 *id); - /** - * signals grouping of connectors - * - * The compositor will send this event to indicate that it has - * sent all currently available connectors after the client binds - * to the global or when it updates the connector list, for example - * on hotplug, drm master change or when a leased connector becomes - * available again. It will similarly send this event to group - * wp_drm_lease_connector_v1.withdrawn events of connectors of this - * device. - */ - void (*done)(void *data, - struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1); - /** - * the compositor has finished using the device - * - * This event is sent in response to the release request and - * indicates that the compositor is done sending connector events. - * The compositor will destroy this object immediately after - * sending the event and it will become invalid. The client should - * release any resources associated with this device after - * receiving this event. - */ - void (*released)(void *data, - struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1); -}; - -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -static inline int -wp_drm_lease_device_v1_add_listener(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, - const struct wp_drm_lease_device_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wp_drm_lease_device_v1, - (void (**)(void)) listener, data); -} - -#define WP_DRM_LEASE_DEVICE_V1_CREATE_LEASE_REQUEST 0 -#define WP_DRM_LEASE_DEVICE_V1_RELEASE 1 - -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -#define WP_DRM_LEASE_DEVICE_V1_DRM_FD_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -#define WP_DRM_LEASE_DEVICE_V1_CONNECTOR_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -#define WP_DRM_LEASE_DEVICE_V1_DONE_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -#define WP_DRM_LEASE_DEVICE_V1_RELEASED_SINCE_VERSION 1 - -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -#define WP_DRM_LEASE_DEVICE_V1_CREATE_LEASE_REQUEST_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_device_v1 - */ -#define WP_DRM_LEASE_DEVICE_V1_RELEASE_SINCE_VERSION 1 - -/** @ingroup iface_wp_drm_lease_device_v1 */ -static inline void -wp_drm_lease_device_v1_set_user_data(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_device_v1, user_data); -} - -/** @ingroup iface_wp_drm_lease_device_v1 */ -static inline void * -wp_drm_lease_device_v1_get_user_data(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_device_v1); -} - -static inline uint32_t -wp_drm_lease_device_v1_get_version(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_device_v1); -} - -/** @ingroup iface_wp_drm_lease_device_v1 */ -static inline void -wp_drm_lease_device_v1_destroy(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) -{ - wl_proxy_destroy((struct wl_proxy *) wp_drm_lease_device_v1); -} - -/** - * @ingroup iface_wp_drm_lease_device_v1 - * - * Creates a lease request object. - * - * See the documentation for wp_drm_lease_request_v1 for details. - */ -static inline struct wp_drm_lease_request_v1 * -wp_drm_lease_device_v1_create_lease_request(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_device_v1, - WP_DRM_LEASE_DEVICE_V1_CREATE_LEASE_REQUEST, &wp_drm_lease_request_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_device_v1), 0, NULL); - - return (struct wp_drm_lease_request_v1 *) id; -} - -/** - * @ingroup iface_wp_drm_lease_device_v1 - * - * Indicates the client no longer wishes to use this object. In response - * the compositor will immediately send the released event and destroy - * this object. It can however not guarantee that the client won't receive - * connector events before the released event. The client must not send any - * requests after this one, doing so will raise a wl_display error. - * Existing connectors, lease request and leases will not be affected. - */ -static inline void -wp_drm_lease_device_v1_release(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_device_v1, - WP_DRM_LEASE_DEVICE_V1_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_device_v1), 0); -} - -/** - * @ingroup iface_wp_drm_lease_connector_v1 - * @struct wp_drm_lease_connector_v1_listener - */ -struct wp_drm_lease_connector_v1_listener { - /** - * name - * - * The compositor sends this event once the connector is created - * to indicate the name of this connector. This will not change for - * the duration of the Wayland session, but is not guaranteed to be - * consistent between sessions. - * - * If the compositor supports wl_output version 4 and this - * connector corresponds to a wl_output, the compositor should use - * the same name as for the wl_output. - * @param name connector name - */ - void (*name)(void *data, - struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, - const char *name); - /** - * description - * - * The compositor sends this event once the connector is created - * to provide a human-readable description for this connector, - * which may be presented to the user. The compositor may send this - * event multiple times over the lifetime of this object to reflect - * changes in the description. - * @param description connector description - */ - void (*description)(void *data, - struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, - const char *description); - /** - * connector_id - * - * The compositor sends this event once the connector is created - * to indicate the DRM object ID which represents the underlying - * connector that is being offered. Note that the final lease may - * include additional object IDs, such as CRTCs and planes. - * @param connector_id DRM connector ID - */ - void (*connector_id)(void *data, - struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, - uint32_t connector_id); - /** - * all properties have been sent - * - * This event is sent after all properties of a connector have - * been sent. This allows changes to the properties to be seen as - * atomic even if they happen via multiple events. - */ - void (*done)(void *data, - struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1); - /** - * lease offer withdrawn - * - * Sent to indicate that the compositor will no longer honor - * requests for DRM leases which include this connector. The client - * may still issue a lease request including this connector, but - * the compositor will send wp_drm_lease_v1.finished without - * issuing a lease fd. Compositors are encouraged to send this - * event when they lose access to connector, for example when the - * connector is hot-unplugged, when the connector gets leased to a - * client or when the compositor loses DRM master. - * - * If a client holds a lease for the connector, the status of the - * lease remains the same. The client should destroy the object - * after receiving this event. - */ - void (*withdrawn)(void *data, - struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1); -}; - -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -static inline int -wp_drm_lease_connector_v1_add_listener(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, - const struct wp_drm_lease_connector_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wp_drm_lease_connector_v1, - (void (**)(void)) listener, data); -} - -#define WP_DRM_LEASE_CONNECTOR_V1_DESTROY 0 - -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -#define WP_DRM_LEASE_CONNECTOR_V1_NAME_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -#define WP_DRM_LEASE_CONNECTOR_V1_DESCRIPTION_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -#define WP_DRM_LEASE_CONNECTOR_V1_CONNECTOR_ID_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -#define WP_DRM_LEASE_CONNECTOR_V1_DONE_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -#define WP_DRM_LEASE_CONNECTOR_V1_WITHDRAWN_SINCE_VERSION 1 - -/** - * @ingroup iface_wp_drm_lease_connector_v1 - */ -#define WP_DRM_LEASE_CONNECTOR_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_wp_drm_lease_connector_v1 */ -static inline void -wp_drm_lease_connector_v1_set_user_data(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_connector_v1, user_data); -} - -/** @ingroup iface_wp_drm_lease_connector_v1 */ -static inline void * -wp_drm_lease_connector_v1_get_user_data(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_connector_v1); -} - -static inline uint32_t -wp_drm_lease_connector_v1_get_version(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_connector_v1); -} - -/** - * @ingroup iface_wp_drm_lease_connector_v1 - * - * The client may send this request to indicate that it will not use this - * connector. Clients are encouraged to send this after receiving the - * "withdrawn" event so that the server can release the resources - * associated with this connector offer. Neither existing lease requests - * nor leases will be affected. - */ -static inline void -wp_drm_lease_connector_v1_destroy(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_connector_v1, - WP_DRM_LEASE_CONNECTOR_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_connector_v1), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WP_DRM_LEASE_REQUEST_V1_ERROR_ENUM -#define WP_DRM_LEASE_REQUEST_V1_ERROR_ENUM -enum wp_drm_lease_request_v1_error { - /** - * requested a connector from a different lease device - */ - WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE = 0, - /** - * requested a connector twice - */ - WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR = 1, - /** - * requested a lease without requesting a connector - */ - WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE = 2, -}; -#endif /* WP_DRM_LEASE_REQUEST_V1_ERROR_ENUM */ - -#define WP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR 0 -#define WP_DRM_LEASE_REQUEST_V1_SUBMIT 1 - - -/** - * @ingroup iface_wp_drm_lease_request_v1 - */ -#define WP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_request_v1 - */ -#define WP_DRM_LEASE_REQUEST_V1_SUBMIT_SINCE_VERSION 1 - -/** @ingroup iface_wp_drm_lease_request_v1 */ -static inline void -wp_drm_lease_request_v1_set_user_data(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_request_v1, user_data); -} - -/** @ingroup iface_wp_drm_lease_request_v1 */ -static inline void * -wp_drm_lease_request_v1_get_user_data(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_request_v1); -} - -static inline uint32_t -wp_drm_lease_request_v1_get_version(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_request_v1); -} - -/** @ingroup iface_wp_drm_lease_request_v1 */ -static inline void -wp_drm_lease_request_v1_destroy(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) -{ - wl_proxy_destroy((struct wl_proxy *) wp_drm_lease_request_v1); -} - -/** - * @ingroup iface_wp_drm_lease_request_v1 - * - * Indicates that the client would like to lease the given connector. - * This is only used as a suggestion, the compositor may choose to - * include any resources in the lease it issues, or change the set of - * leased resources at any time. Compositors are however encouraged to - * include the requested connector and other resources necessary - * to drive the connected output in the lease. - * - * Requesting a connector that was created from a different lease device - * than this lease request raises the wrong_device error. Requesting a - * connector twice will raise the duplicate_connector error. - */ -static inline void -wp_drm_lease_request_v1_request_connector(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1, struct wp_drm_lease_connector_v1 *connector) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_request_v1, - WP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_request_v1), 0, connector); -} - -/** - * @ingroup iface_wp_drm_lease_request_v1 - * - * Submits the lease request and creates a new wp_drm_lease_v1 object. - * After calling submit the compositor will immediately destroy this - * object, issuing any more requests will cause a wl_display error. - * The compositor doesn't make any guarantees about the events of the - * lease object, clients cannot expect an immediate response. - * Not requesting any connectors before submitting the lease request - * will raise the empty_lease error. - */ -static inline struct wp_drm_lease_v1 * -wp_drm_lease_request_v1_submit(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_request_v1, - WP_DRM_LEASE_REQUEST_V1_SUBMIT, &wp_drm_lease_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_request_v1), WL_MARSHAL_FLAG_DESTROY, NULL); - - return (struct wp_drm_lease_v1 *) id; -} - -/** - * @ingroup iface_wp_drm_lease_v1 - * @struct wp_drm_lease_v1_listener - */ -struct wp_drm_lease_v1_listener { - /** - * shares the DRM file descriptor - * - * This event returns a file descriptor suitable for use with - * DRM-related ioctls. The client should use drmModeGetLease to - * enumerate the DRM objects which have been leased to them. The - * compositor guarantees it will not use the leased DRM objects - * itself until it sends the finished event. If the compositor - * cannot or will not grant a lease for the requested connectors, - * it will not send this event, instead sending the finished event. - * - * The compositor will send this event at most once during this - * objects lifetime. - * @param leased_fd leased DRM file descriptor - */ - void (*lease_fd)(void *data, - struct wp_drm_lease_v1 *wp_drm_lease_v1, - int32_t leased_fd); - /** - * sent when the lease has been revoked - * - * The compositor uses this event to either reject a lease - * request, or if it previously sent a lease_fd, to notify the - * client that the lease has been revoked. If the client requires a - * new lease, they should destroy this object and submit a new - * lease request. The compositor will send no further events for - * this object after sending the finish event. Compositors should - * revoke the lease when any of the leased resources become - * unavailable, namely when a hot-unplug occurs or when the - * compositor loses DRM master. Compositors may advertise the - * connector for leasing again, if the resource is available, by - * sending the connector event through the wp_drm_lease_device_v1 - * interface. - */ - void (*finished)(void *data, - struct wp_drm_lease_v1 *wp_drm_lease_v1); -}; - -/** - * @ingroup iface_wp_drm_lease_v1 - */ -static inline int -wp_drm_lease_v1_add_listener(struct wp_drm_lease_v1 *wp_drm_lease_v1, - const struct wp_drm_lease_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wp_drm_lease_v1, - (void (**)(void)) listener, data); -} - -#define WP_DRM_LEASE_V1_DESTROY 0 - -/** - * @ingroup iface_wp_drm_lease_v1 - */ -#define WP_DRM_LEASE_V1_LEASE_FD_SINCE_VERSION 1 -/** - * @ingroup iface_wp_drm_lease_v1 - */ -#define WP_DRM_LEASE_V1_FINISHED_SINCE_VERSION 1 - -/** - * @ingroup iface_wp_drm_lease_v1 - */ -#define WP_DRM_LEASE_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_wp_drm_lease_v1 */ -static inline void -wp_drm_lease_v1_set_user_data(struct wp_drm_lease_v1 *wp_drm_lease_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_v1, user_data); -} - -/** @ingroup iface_wp_drm_lease_v1 */ -static inline void * -wp_drm_lease_v1_get_user_data(struct wp_drm_lease_v1 *wp_drm_lease_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_v1); -} - -static inline uint32_t -wp_drm_lease_v1_get_version(struct wp_drm_lease_v1 *wp_drm_lease_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_v1); -} - -/** - * @ingroup iface_wp_drm_lease_v1 - * - * The client should send this to indicate that it no longer wishes to use - * this lease. The compositor should use drmModeRevokeLease on the - * appropriate file descriptor, if necessary. - * - * Upon destruction, the compositor should advertise the connector for - * leasing again by sending the connector event through the - * wp_drm_lease_device_v1 interface. - */ -static inline void -wp_drm_lease_v1_destroy(struct wp_drm_lease_v1 *wp_drm_lease_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_v1, - WP_DRM_LEASE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_v1), WL_MARSHAL_FLAG_DESTROY); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/raylib/platforms/drm-lease-v1.xml b/raylib/platforms/drm-lease-v1.xml deleted file mode 100644 index 1fca538..0000000 --- a/raylib/platforms/drm-lease-v1.xml +++ /dev/null @@ -1,317 +0,0 @@ - - - - Copyright © 2018 NXP - Copyright © 2019 Status Research & Development GmbH. - Copyright © 2021 Xaver Hugl - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - - - - This protocol is used by Wayland compositors which act as Direct - Rendering Manager (DRM) masters to lease DRM resources to Wayland - clients. - - The compositor will advertise one wp_drm_lease_device_v1 global for each - DRM node. Some time after a client binds to the wp_drm_lease_device_v1 - global, the compositor will send a drm_fd event followed by zero, one or - more connector events. After all currently available connectors have been - sent, the compositor will send a wp_drm_lease_device_v1.done event. - - When the list of connectors available for lease changes the compositor - will send wp_drm_lease_device_v1.connector events for added connectors and - wp_drm_lease_connector_v1.withdrawn events for removed connectors, - followed by a wp_drm_lease_device_v1.done event. - - The compositor will indicate when a device is gone by removing the global - via a wl_registry.global_remove event. Upon receiving this event, the - client should destroy any matching wp_drm_lease_device_v1 object. - - To destroy a wp_drm_lease_device_v1 object, the client must first issue - a release request. Upon receiving this request, the compositor will - immediately send a released event and destroy the object. The client must - continue to process and discard drm_fd and connector events until it - receives the released event. Upon receiving the released event, the - client can safely cleanup any client-side resources. - - Warning! The protocol described in this file is currently in the testing - phase. Backward compatible changes may be added together with the - corresponding interface version bump. Backward incompatible changes can - only be done by creating a new major version of the extension. - - - - - Creates a lease request object. - - See the documentation for wp_drm_lease_request_v1 for details. - - - - - - - Indicates the client no longer wishes to use this object. In response - the compositor will immediately send the released event and destroy - this object. It can however not guarantee that the client won't receive - connector events before the released event. The client must not send any - requests after this one, doing so will raise a wl_display error. - Existing connectors, lease request and leases will not be affected. - - - - - - The compositor will send this event when the wp_drm_lease_device_v1 - global is bound, although there are no guarantees as to how long this - takes - the compositor might need to wait until regaining DRM master. - The included fd is a non-master DRM file descriptor opened for this - device and the compositor must not authenticate it. - The purpose of this event is to give the client the ability to - query DRM and discover information which may help them pick the - appropriate DRM device or select the appropriate connectors therein. - - - - - - - The compositor will use this event to advertise connectors available for - lease by clients. This object may be passed into a lease request to - indicate the client would like to lease that connector, see - wp_drm_lease_request_v1.request_connector for details. While the - compositor will make a best effort to not send disconnected connectors, - no guarantees can be made. - - The compositor must send the drm_fd event before sending connectors. - After the drm_fd event it will send all available connectors but may - send additional connectors at any time. - - - - - - - The compositor will send this event to indicate that it has sent all - currently available connectors after the client binds to the global or - when it updates the connector list, for example on hotplug, drm master - change or when a leased connector becomes available again. It will - similarly send this event to group wp_drm_lease_connector_v1.withdrawn - events of connectors of this device. - - - - - - This event is sent in response to the release request and indicates - that the compositor is done sending connector events. - The compositor will destroy this object immediately after sending the - event and it will become invalid. The client should release any - resources associated with this device after receiving this event. - - - - - - - Represents a DRM connector which is available for lease. These objects are - created via wp_drm_lease_device_v1.connector events, and should be passed - to lease requests via wp_drm_lease_request_v1.request_connector. - Immediately after the wp_drm_lease_connector_v1 object is created the - compositor will send a name, a description, a connector_id and a done - event. When the description is updated the compositor will send a - description event followed by a done event. - - - - - The compositor sends this event once the connector is created to - indicate the name of this connector. This will not change for the - duration of the Wayland session, but is not guaranteed to be consistent - between sessions. - - If the compositor supports wl_output version 4 and this connector - corresponds to a wl_output, the compositor should use the same name as - for the wl_output. - - - - - - - The compositor sends this event once the connector is created to provide - a human-readable description for this connector, which may be presented - to the user. The compositor may send this event multiple times over the - lifetime of this object to reflect changes in the description. - - - - - - - The compositor sends this event once the connector is created to - indicate the DRM object ID which represents the underlying connector - that is being offered. Note that the final lease may include additional - object IDs, such as CRTCs and planes. - - - - - - - This event is sent after all properties of a connector have been sent. - This allows changes to the properties to be seen as atomic even if they - happen via multiple events. - - - - - - Sent to indicate that the compositor will no longer honor requests for - DRM leases which include this connector. The client may still issue a - lease request including this connector, but the compositor will send - wp_drm_lease_v1.finished without issuing a lease fd. Compositors are - encouraged to send this event when they lose access to connector, for - example when the connector is hot-unplugged, when the connector gets - leased to a client or when the compositor loses DRM master. - - If a client holds a lease for the connector, the status of the lease - remains the same. The client should destroy the object after receiving - this event. - - - - - - The client may send this request to indicate that it will not use this - connector. Clients are encouraged to send this after receiving the - "withdrawn" event so that the server can release the resources - associated with this connector offer. Neither existing lease requests - nor leases will be affected. - - - - - - - A client that wishes to lease DRM resources will attach the list of - connectors advertised with wp_drm_lease_device_v1.connector that they - wish to lease, then use wp_drm_lease_request_v1.submit to submit the - request. - - - - - - - - - - - Indicates that the client would like to lease the given connector. - This is only used as a suggestion, the compositor may choose to - include any resources in the lease it issues, or change the set of - leased resources at any time. Compositors are however encouraged to - include the requested connector and other resources necessary - to drive the connected output in the lease. - - Requesting a connector that was created from a different lease device - than this lease request raises the wrong_device error. Requesting a - connector twice will raise the duplicate_connector error. - - - - - - - Submits the lease request and creates a new wp_drm_lease_v1 object. - After calling submit the compositor will immediately destroy this - object, issuing any more requests will cause a wl_display error. - The compositor doesn't make any guarantees about the events of the - lease object, clients cannot expect an immediate response. - Not requesting any connectors before submitting the lease request - will raise the empty_lease error. - - - - - - - - A DRM lease object is used to transfer the DRM file descriptor to the - client and manage the lifetime of the lease. - - Some time after the wp_drm_lease_v1 object is created, the compositor - will reply with the lease request's result. If the lease request is - granted, the compositor will send a lease_fd event. If the lease request - is denied, the compositor will send a finished event without a lease_fd - event. - - - - - This event returns a file descriptor suitable for use with DRM-related - ioctls. The client should use drmModeGetLease to enumerate the DRM - objects which have been leased to them. The compositor guarantees it - will not use the leased DRM objects itself until it sends the finished - event. If the compositor cannot or will not grant a lease for the - requested connectors, it will not send this event, instead sending the - finished event. - - The compositor will send this event at most once during this objects - lifetime. - - - - - - - The compositor uses this event to either reject a lease request, or if - it previously sent a lease_fd, to notify the client that the lease has - been revoked. If the client requires a new lease, they should destroy - this object and submit a new lease request. The compositor will send - no further events for this object after sending the finish event. - Compositors should revoke the lease when any of the leased resources - become unavailable, namely when a hot-unplug occurs or when the - compositor loses DRM master. Compositors may advertise the connector - for leasing again, if the resource is available, by sending the - connector event through the wp_drm_lease_device_v1 interface. - - - - - - The client should send this to indicate that it no longer wishes to use - this lease. The compositor should use drmModeRevokeLease on the - appropriate file descriptor, if necessary. - - Upon destruction, the compositor should advertise the connector for - leasing again by sending the connector event through the - wp_drm_lease_device_v1 interface. - - - - diff --git a/raylib/platforms/rcore_android.c b/raylib/platforms/rcore_android.c deleted file mode 100644 index b41f8a1..0000000 --- a/raylib/platforms/rcore_android.c +++ /dev/null @@ -1,1414 +0,0 @@ -/********************************************************************************************** -* -* rcore_android - Functions to manage window, graphics device and inputs -* -* PLATFORM: ANDROID -* - Android (ARM, ARM64) -* -* LIMITATIONS: -* - Limitation 01 -* - Limitation 02 -* -* POSSIBLE IMPROVEMENTS: -* - Improvement 01 -* - Improvement 02 -* -* ADDITIONAL NOTES: -* - TRACELOG() function is located in raylib [utils] module -* -* CONFIGURATION: -* #define RCORE_PLATFORM_CUSTOM_FLAG -* Custom flag for rcore on target platform -not used- -* -* DEPENDENCIES: -* - Android NDK: Provides C API to access Android functionality -* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#include // Required for: android_app struct and activity management -#include // Required for: AWINDOW_FLAG_FULLSCREEN definition and others -//#include // Required for: Android sensors functions (accelerometer, gyroscope, light...) -#include // Required for: JNIEnv and JavaVM [Used in OpenURL()] - -#include // Native platform windowing system interface - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef struct { - // Application data - struct android_app *app; // Android activity - struct android_poll_source *source; // Android events polling source - bool appEnabled; // Flag to detect if app is active ** = true - bool contextRebindRequired; // Used to know context rebind required - - // Display data - EGLDisplay device; // Native display device (physical screen connection) - EGLSurface surface; // Surface to draw on, framebuffers (connected to context) - EGLContext context; // Graphic context, mode in which drawing can be done - EGLConfig config; // Graphic config -} PlatformData; - -typedef struct { - // Store data for both Hover and Touch events - // Used to ignore Hover events which are interpreted as Touch events - int32_t pointCount; // Number of touch points active - int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers - Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen - - int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points -} TouchRaw; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context -extern bool isGpuReady; // Flag to note GPU has been initialized successfully -static PlatformData platform = { 0 }; // Platform specific data - -//---------------------------------------------------------------------------------- -// Local Variables Definition -//---------------------------------------------------------------------------------- -#define KEYCODE_MAP_SIZE 162 -static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = { - KEY_NULL, // AKEYCODE_UNKNOWN - 0, // AKEYCODE_SOFT_LEFT - 0, // AKEYCODE_SOFT_RIGHT - 0, // AKEYCODE_HOME - KEY_BACK, // AKEYCODE_BACK - 0, // AKEYCODE_CALL - 0, // AKEYCODE_ENDCALL - KEY_ZERO, // AKEYCODE_0 - KEY_ONE, // AKEYCODE_1 - KEY_TWO, // AKEYCODE_2 - KEY_THREE, // AKEYCODE_3 - KEY_FOUR, // AKEYCODE_4 - KEY_FIVE, // AKEYCODE_5 - KEY_SIX, // AKEYCODE_6 - KEY_SEVEN, // AKEYCODE_7 - KEY_EIGHT, // AKEYCODE_8 - KEY_NINE, // AKEYCODE_9 - 0, // AKEYCODE_STAR - 0, // AKEYCODE_POUND - KEY_UP, // AKEYCODE_DPAD_UP - KEY_DOWN, // AKEYCODE_DPAD_DOWN - KEY_LEFT, // AKEYCODE_DPAD_LEFT - KEY_RIGHT, // AKEYCODE_DPAD_RIGHT - 0, // AKEYCODE_DPAD_CENTER - KEY_VOLUME_UP, // AKEYCODE_VOLUME_UP - KEY_VOLUME_DOWN, // AKEYCODE_VOLUME_DOWN - 0, // AKEYCODE_POWER - 0, // AKEYCODE_CAMERA - 0, // AKEYCODE_CLEAR - KEY_A, // AKEYCODE_A - KEY_B, // AKEYCODE_B - KEY_C, // AKEYCODE_C - KEY_D, // AKEYCODE_D - KEY_E, // AKEYCODE_E - KEY_F, // AKEYCODE_F - KEY_G, // AKEYCODE_G - KEY_H, // AKEYCODE_H - KEY_I, // AKEYCODE_I - KEY_J, // AKEYCODE_J - KEY_K, // AKEYCODE_K - KEY_L, // AKEYCODE_L - KEY_M, // AKEYCODE_M - KEY_N, // AKEYCODE_N - KEY_O, // AKEYCODE_O - KEY_P, // AKEYCODE_P - KEY_Q, // AKEYCODE_Q - KEY_R, // AKEYCODE_R - KEY_S, // AKEYCODE_S - KEY_T, // AKEYCODE_T - KEY_U, // AKEYCODE_U - KEY_V, // AKEYCODE_V - KEY_W, // AKEYCODE_W - KEY_X, // AKEYCODE_X - KEY_Y, // AKEYCODE_Y - KEY_Z, // AKEYCODE_Z - KEY_COMMA, // AKEYCODE_COMMA - KEY_PERIOD, // AKEYCODE_PERIOD - KEY_LEFT_ALT, // AKEYCODE_ALT_LEFT - KEY_RIGHT_ALT, // AKEYCODE_ALT_RIGHT - KEY_LEFT_SHIFT, // AKEYCODE_SHIFT_LEFT - KEY_RIGHT_SHIFT, // AKEYCODE_SHIFT_RIGHT - KEY_TAB, // AKEYCODE_TAB - KEY_SPACE, // AKEYCODE_SPACE - 0, // AKEYCODE_SYM - 0, // AKEYCODE_EXPLORER - 0, // AKEYCODE_ENVELOPE - KEY_ENTER, // AKEYCODE_ENTER - KEY_BACKSPACE, // AKEYCODE_DEL - KEY_GRAVE, // AKEYCODE_GRAVE - KEY_MINUS, // AKEYCODE_MINUS - KEY_EQUAL, // AKEYCODE_EQUALS - KEY_LEFT_BRACKET, // AKEYCODE_LEFT_BRACKET - KEY_RIGHT_BRACKET, // AKEYCODE_RIGHT_BRACKET - KEY_BACKSLASH, // AKEYCODE_BACKSLASH - KEY_SEMICOLON, // AKEYCODE_SEMICOLON - KEY_APOSTROPHE, // AKEYCODE_APOSTROPHE - KEY_SLASH, // AKEYCODE_SLASH - 0, // AKEYCODE_AT - 0, // AKEYCODE_NUM - 0, // AKEYCODE_HEADSETHOOK - 0, // AKEYCODE_FOCUS - 0, // AKEYCODE_PLUS - KEY_MENU, // AKEYCODE_MENU - 0, // AKEYCODE_NOTIFICATION - 0, // AKEYCODE_SEARCH - 0, // AKEYCODE_MEDIA_PLAY_PAUSE - 0, // AKEYCODE_MEDIA_STOP - 0, // AKEYCODE_MEDIA_NEXT - 0, // AKEYCODE_MEDIA_PREVIOUS - 0, // AKEYCODE_MEDIA_REWIND - 0, // AKEYCODE_MEDIA_FAST_FORWARD - 0, // AKEYCODE_MUTE - KEY_PAGE_UP, // AKEYCODE_PAGE_UP - KEY_PAGE_DOWN, // AKEYCODE_PAGE_DOWN - 0, // AKEYCODE_PICTSYMBOLS - 0, // AKEYCODE_SWITCH_CHARSET - 0, // AKEYCODE_BUTTON_A - 0, // AKEYCODE_BUTTON_B - 0, // AKEYCODE_BUTTON_C - 0, // AKEYCODE_BUTTON_X - 0, // AKEYCODE_BUTTON_Y - 0, // AKEYCODE_BUTTON_Z - 0, // AKEYCODE_BUTTON_L1 - 0, // AKEYCODE_BUTTON_R1 - 0, // AKEYCODE_BUTTON_L2 - 0, // AKEYCODE_BUTTON_R2 - 0, // AKEYCODE_BUTTON_THUMBL - 0, // AKEYCODE_BUTTON_THUMBR - 0, // AKEYCODE_BUTTON_START - 0, // AKEYCODE_BUTTON_SELECT - 0, // AKEYCODE_BUTTON_MODE - KEY_ESCAPE, // AKEYCODE_ESCAPE - KEY_DELETE, // AKEYCODE_FORWARD_DELL - KEY_LEFT_CONTROL, // AKEYCODE_CTRL_LEFT - KEY_RIGHT_CONTROL, // AKEYCODE_CTRL_RIGHT - KEY_CAPS_LOCK, // AKEYCODE_CAPS_LOCK - KEY_SCROLL_LOCK, // AKEYCODE_SCROLL_LOCK - KEY_LEFT_SUPER, // AKEYCODE_META_LEFT - KEY_RIGHT_SUPER, // AKEYCODE_META_RIGHT - 0, // AKEYCODE_FUNCTION - KEY_PRINT_SCREEN, // AKEYCODE_SYSRQ - KEY_PAUSE, // AKEYCODE_BREAK - KEY_HOME, // AKEYCODE_MOVE_HOME - KEY_END, // AKEYCODE_MOVE_END - KEY_INSERT, // AKEYCODE_INSERT - 0, // AKEYCODE_FORWARD - 0, // AKEYCODE_MEDIA_PLAY - 0, // AKEYCODE_MEDIA_PAUSE - 0, // AKEYCODE_MEDIA_CLOSE - 0, // AKEYCODE_MEDIA_EJECT - 0, // AKEYCODE_MEDIA_RECORD - KEY_F1, // AKEYCODE_F1 - KEY_F2, // AKEYCODE_F2 - KEY_F3, // AKEYCODE_F3 - KEY_F4, // AKEYCODE_F4 - KEY_F5, // AKEYCODE_F5 - KEY_F6, // AKEYCODE_F6 - KEY_F7, // AKEYCODE_F7 - KEY_F8, // AKEYCODE_F8 - KEY_F9, // AKEYCODE_F9 - KEY_F10, // AKEYCODE_F10 - KEY_F11, // AKEYCODE_F11 - KEY_F12, // AKEYCODE_F12 - KEY_NUM_LOCK, // AKEYCODE_NUM_LOCK - KEY_KP_0, // AKEYCODE_NUMPAD_0 - KEY_KP_1, // AKEYCODE_NUMPAD_1 - KEY_KP_2, // AKEYCODE_NUMPAD_2 - KEY_KP_3, // AKEYCODE_NUMPAD_3 - KEY_KP_4, // AKEYCODE_NUMPAD_4 - KEY_KP_5, // AKEYCODE_NUMPAD_5 - KEY_KP_6, // AKEYCODE_NUMPAD_6 - KEY_KP_7, // AKEYCODE_NUMPAD_7 - KEY_KP_8, // AKEYCODE_NUMPAD_8 - KEY_KP_9, // AKEYCODE_NUMPAD_9 - KEY_KP_DIVIDE, // AKEYCODE_NUMPAD_DIVIDE - KEY_KP_MULTIPLY, // AKEYCODE_NUMPAD_MULTIPLY - KEY_KP_SUBTRACT, // AKEYCODE_NUMPAD_SUBTRACT - KEY_KP_ADD, // AKEYCODE_NUMPAD_ADD - KEY_KP_DECIMAL, // AKEYCODE_NUMPAD_DOT - 0, // AKEYCODE_NUMPAD_COMMA - KEY_KP_ENTER, // AKEYCODE_NUMPAD_ENTER - KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS -}; - -static TouchRaw touchRaw = { 0 }; - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -int InitPlatform(void); // Initialize platform (graphics, inputs and more) -void ClosePlatform(void); // Close platform - -static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands -static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs -static GamepadButton AndroidTranslateGamepadButton(int button); // Map Android gamepad button to raylib gamepad button - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -// NOTE: Functions declaration is provided by raylib.h - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Application -//---------------------------------------------------------------------------------- - -// To allow easier porting to android, we allow the user to define a -// main function which we call from android_main, defined by ourselves -//extern int main(int argc, char *argv[]); -extern void android_run(); - -// Android main function -void android_main(struct android_app *app) -{ - char arg0[] = "raylib"; // NOTE: argv[] are mutable - platform.app = app; - - (void)android_run(); - // NOTE: Return from main is ignored - //(void)main(1, (char *[]) { arg0, NULL }); - - // Request to end the native activity - ANativeActivity_finish(app->activity); - - // Android ALooper_pollOnce() variables - int pollResult = 0; - int pollEvents = 0; - - // Waiting for application events before complete finishing - while (!app->destroyRequested) - { - // Poll all events until we reach return value TIMEOUT, meaning no events left to process - while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void **)&platform.source)) > ALOOPER_POLL_TIMEOUT) - { - if (platform.source != NULL) platform.source->process(app, platform.source); - } - } -} - -// NOTE: Add this to header (if apps really need it) -struct android_app *GetAndroidApp(void) -{ - return platform.app; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Window and Graphics Device -//---------------------------------------------------------------------------------- - -// Check if application should close -bool WindowShouldClose(void) -{ - if (CORE.Window.ready) return CORE.Window.shouldClose; - else return true; -} - -// Toggle fullscreen mode -void ToggleFullscreen(void) -{ - TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform"); -} - -// Toggle borderless windowed mode -void ToggleBorderlessWindowed(void) -{ - TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform"); -} - -// Set window state: maximized, if resizable -void MaximizeWindow(void) -{ - TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform"); -} - -// Set window state: minimized -void MinimizeWindow(void) -{ - TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform"); -} - -// Restore window from being minimized/maximized -void RestoreWindow(void) -{ - TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform"); -} - -// Set window configuration state using flags -void SetWindowState(unsigned int flags) -{ - TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform"); -} - -// Clear window configuration state flags -void ClearWindowState(unsigned int flags) -{ - TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform"); -} - -// Set icon for window -void SetWindowIcon(Image image) -{ - TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform"); -} - -// Set icon for window -void SetWindowIcons(Image *images, int count) -{ - TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); -} - -// Set title for window -void SetWindowTitle(const char *title) -{ - CORE.Window.title = title; -} - -// Set window position on screen (windowed mode) -void SetWindowPosition(int x, int y) -{ - TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform"); -} - -// Set monitor for the current window -void SetWindowMonitor(int monitor) -{ - TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform"); -} - -// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMinSize(int width, int height) -{ - CORE.Window.screenMin.width = width; - CORE.Window.screenMin.height = height; -} - -// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMaxSize(int width, int height) -{ - CORE.Window.screenMax.width = width; - CORE.Window.screenMax.height = height; -} - -// Set window dimensions -void SetWindowSize(int width, int height) -{ - TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform"); -} - -// Set window opacity, value opacity is between 0.0 and 1.0 -void SetWindowOpacity(float opacity) -{ - TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); -} - -// Set window focused -void SetWindowFocused(void) -{ - TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform"); -} - -// Get native window handle -void *GetWindowHandle(void) -{ - TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform"); - return NULL; -} - -// Get number of monitors -int GetMonitorCount(void) -{ - TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform"); - return 1; -} - -// Get current monitor where window is placed -int GetCurrentMonitor(void) -{ - TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform"); - return 0; -} - -// Get selected monitor position -Vector2 GetMonitorPosition(int monitor) -{ - TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform"); - return (Vector2){ 0, 0 }; -} - -// Get selected monitor width (currently used by monitor) -int GetMonitorWidth(int monitor) -{ - TRACELOG(LOG_WARNING, "GetMonitorWidth() not implemented on target platform"); - return 0; -} - -// Get selected monitor height (currently used by monitor) -int GetMonitorHeight(int monitor) -{ - TRACELOG(LOG_WARNING, "GetMonitorHeight() not implemented on target platform"); - return 0; -} - -// Get selected monitor physical width in millimetres -// NOTE: It seems to return a slightly underestimated value on some devices -int GetMonitorPhysicalWidth(int monitor) -{ - int widthPixels = ANativeWindow_getWidth(platform.app->window); - float dpi = AConfiguration_getDensity(platform.app->config); - return (widthPixels/dpi)*25.4f; -} - -// Get selected monitor physical height in millimetres -// NOTE: It seems to return a slightly underestimated value on some devices -int GetMonitorPhysicalHeight(int monitor) -{ - int heightPixels = ANativeWindow_getHeight(platform.app->window); - float dpi = AConfiguration_getDensity(platform.app->config); - return (heightPixels/dpi)*25.4f; -} - -// Get selected monitor refresh rate -int GetMonitorRefreshRate(int monitor) -{ - TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform"); - return 0; -} - -// Get the human-readable, UTF-8 encoded name of the selected monitor -const char *GetMonitorName(int monitor) -{ - TRACELOG(LOG_WARNING, "GetMonitorName() not implemented on target platform"); - return ""; -} - -// Get window position XY on monitor -Vector2 GetWindowPosition(void) -{ - TRACELOG(LOG_WARNING, "GetWindowPosition() not implemented on target platform"); - return (Vector2){ 0, 0 }; -} - -// Get window scale DPI factor for current monitor -Vector2 GetWindowScaleDPI(void) -{ - int density = AConfiguration_getDensity(platform.app->config); - float scale = (float)density/160; - return (Vector2){ scale, scale }; -} - -// Set clipboard text content -void SetClipboardText(const char *text) -{ - TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform"); -} - -// Get clipboard text content -// NOTE: returned string is allocated and freed by GLFW -const char *GetClipboardText(void) -{ - TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform"); - return NULL; -} - -// Get clipboard image -Image GetClipboardImage(void) -{ - Image image = { 0 }; - - TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); - - return image; -} - -// Show mouse cursor -void ShowCursor(void) -{ - CORE.Input.Mouse.cursorHidden = false; -} - -// Hides mouse cursor -void HideCursor(void) -{ - CORE.Input.Mouse.cursorHidden = true; -} - -// Enables cursor (unlock cursor) -void EnableCursor(void) -{ - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - - CORE.Input.Mouse.cursorHidden = false; -} - -// Disables cursor (lock cursor) -void DisableCursor(void) -{ - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - - CORE.Input.Mouse.cursorHidden = true; -} - -// Swap back buffer with front buffer (screen drawing) -void SwapScreenBuffer(void) -{ - eglSwapBuffers(platform.device, platform.surface); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Misc -//---------------------------------------------------------------------------------- - -// Get elapsed time measure in seconds since InitTimer() -double GetTime(void) -{ - double time = 0.0; - struct timespec ts = { 0 }; - clock_gettime(CLOCK_MONOTONIC, &ts); - unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; - - time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() - - return time; -} - -// Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 -void OpenURL(const char *url) -{ - // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else - { - JNIEnv *env = NULL; - JavaVM *vm = platform.app->activity->vm; - (*vm)->AttachCurrentThread(vm, &env, NULL); - - jstring urlString = (*env)->NewStringUTF(env, url); - jclass uriClass = (*env)->FindClass(env, "android/net/Uri"); - jmethodID uriParse = (*env)->GetStaticMethodID(env, uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;"); - jobject uri = (*env)->CallStaticObjectMethod(env, uriClass, uriParse, urlString); - - jclass intentClass = (*env)->FindClass(env, "android/content/Intent"); - jfieldID actionViewId = (*env)->GetStaticFieldID(env, intentClass, "ACTION_VIEW", "Ljava/lang/String;"); - jobject actionView = (*env)->GetStaticObjectField(env, intentClass, actionViewId); - jmethodID newIntent = (*env)->GetMethodID(env, intentClass, "", "(Ljava/lang/String;Landroid/net/Uri;)V"); - jobject intent = (*env)->AllocObject(env, intentClass); - - (*env)->CallVoidMethod(env, intent, newIntent, actionView, uri); - jclass activityClass = (*env)->FindClass(env, "android/app/Activity"); - jmethodID startActivity = (*env)->GetMethodID(env, activityClass, "startActivity", "(Landroid/content/Intent;)V"); - (*env)->CallVoidMethod(env, platform.app->activity->clazz, startActivity, intent); - - (*vm)->DetachCurrentThread(vm); - } -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Inputs -//---------------------------------------------------------------------------------- - -// Set internal gamepad mappings -int SetGamepadMappings(const char *mappings) -{ - TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform"); - return 0; -} - -// Set gamepad vibration -void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) -{ - TRACELOG(LOG_WARNING, "SetGamepadVibration() not implemented on target platform"); -} - -// Set mouse position XY -void SetMousePosition(int x, int y) -{ - CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; -} - -// Set mouse cursor -void SetMouseCursor(int cursor) -{ - TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); -} - -// Get physical key name. -const char *GetKeyName(int key) -{ - TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform"); - return ""; -} - -// Register all input events -void PollInputEvents(void) -{ -#if defined(SUPPORT_GESTURES_SYSTEM) - // NOTE: Gestures update must be called every frame to reset gestures correctly - // because ProcessGestureEvent() is just called on an event, not every frame - UpdateGestures(); -#endif - - // Reset keys/chars pressed registered - CORE.Input.Keyboard.keyPressedQueueCount = 0; - CORE.Input.Keyboard.charPressedQueueCount = 0; - // Reset key repeats - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - - // Reset last gamepad button/axis registered state - CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN - //CORE.Input.Gamepad.axisCount = 0; - - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (CORE.Input.Gamepad.ready[i]) // Check if gamepad is available - { - // Register previous gamepad states - for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) - CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; - } - } - - // Register previous touch states - for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; - - // Reset touch positions - //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; - - // Register previous keys states - // NOTE: Android supports up to 260 keys - for (int i = 0; i < 260; i++) - { - CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Android ALooper_pollOnce() variables - int pollResult = 0; - int pollEvents = 0; - - // Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll - // NOTE: Activity is paused if not enabled (platform.appEnabled) - while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)) - { - // Process this event - if (platform.source != NULL) platform.source->process(platform.app, platform.source); - - // NOTE: Allow closing the window in case a configuration change happened. - // The android_main function should be allowed to return to its caller in order for the - // Android OS to relaunch the activity. - if (platform.app->destroyRequested != 0) - { - CORE.Window.shouldClose = true; - } - } -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- - -// Initialize platform: graphics, inputs and more -int InitPlatform(void) -{ - // Initialize display basic configuration - //---------------------------------------------------------------------------- - CORE.Window.currentFbo.width = CORE.Window.screen.width; - CORE.Window.currentFbo.height = CORE.Window.screen.height; - - // Set desired windows flags before initializing anything - ANativeActivity_setWindowFlags(platform.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER - - int orientation = AConfiguration_getOrientation(platform.app->config); - - if (orientation == ACONFIGURATION_ORIENTATION_PORT) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as portrait"); - else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as landscape"); - - // TODO: Automatic orientation doesn't seem to work - if (CORE.Window.screen.width <= CORE.Window.screen.height) - { - AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_PORT); - TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait"); - } - else - { - AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_LAND); - TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape"); - } - - //AConfiguration_getDensity(platform.app->config); - //AConfiguration_getKeyboard(platform.app->config); - //AConfiguration_getScreenSize(platform.app->config); - //AConfiguration_getScreenLong(platform.app->config); - - // Set some default window flags - CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false - CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false - CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true - CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false - //---------------------------------------------------------------------------- - - // Initialize App command system - // NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()... - //---------------------------------------------------------------------------- - platform.app->onAppCmd = AndroidCommandCallback; - //---------------------------------------------------------------------------- - - // Initialize input events system - //---------------------------------------------------------------------------- - platform.app->onInputEvent = AndroidInputCallback; - //---------------------------------------------------------------------------- - - // Initialize storage system - //---------------------------------------------------------------------------- - InitAssetManager(platform.app->activity->assetManager, platform.app->activity->internalDataPath); // Initialize assets manager - - CORE.Storage.basePath = platform.app->activity->internalDataPath; // Define base path for storage - //---------------------------------------------------------------------------- - - TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Initialized successfully"); - - // Android ALooper_pollOnce() variables - int pollResult = 0; - int pollEvents = 0; - - // Wait for window to be initialized (display and context) - while (!CORE.Window.ready) - { - // Process events until we reach TIMEOUT, which indicates no more events queued. - while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)) - { - // Process this event - if (platform.source != NULL) platform.source->process(platform.app, platform.source); - - // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle. - //if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true; - } - } - - for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1; - - return 0; -} - -// Close platform -void ClosePlatform(void) -{ - // Close surface, context and display - if (platform.device != EGL_NO_DISPLAY) - { - eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (platform.surface != EGL_NO_SURFACE) - { - eglDestroySurface(platform.device, platform.surface); - platform.surface = EGL_NO_SURFACE; - } - - if (platform.context != EGL_NO_CONTEXT) - { - eglDestroyContext(platform.device, platform.context); - platform.context = EGL_NO_CONTEXT; - } - - eglTerminate(platform.device); - platform.device = EGL_NO_DISPLAY; - } - - // NOTE: Reset global state in case the activity is being relaunched. - if (platform.app->destroyRequested != 0) { - CORE = (CoreData){0}; - platform = (PlatformData){0}; - } -} - -// Initialize display device and framebuffer -// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size -// If width or height are 0, default display size will be used for framebuffer size -// NOTE: returns false in case graphic device could not be created -static int InitGraphicsDevice(void) -{ - CORE.Window.fullscreen = true; - CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - - EGLint samples = 0; - EGLint sampleBuffer = 0; - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - samples = 4; - sampleBuffer = 1; - TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); - } - - const EGLint framebufferAttribs[] = { - EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support - EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) - EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) - EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) - //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) - EGL_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!) - //EGL_STENCIL_SIZE, 8, // Stencil buffer size - EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA - EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) - EGL_NONE - }; - - const EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - EGLint numConfigs = 0; - - // Get an EGL device connection - platform.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (platform.device == EGL_NO_DISPLAY) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); - return -1; - } - - // Initialize the EGL device connection - if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE) - { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); - return -1; - } - - // Get an appropriate EGL framebuffer configuration - eglChooseConfig(platform.device, framebufferAttribs, &platform.config, 1, &numConfigs); - - // Set rendering API - eglBindAPI(EGL_OPENGL_ES_API); - - // Create an EGL rendering context - platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs); - if (platform.context == EGL_NO_CONTEXT) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); - return -1; - } - - // Create an EGL window surface - //--------------------------------------------------------------------------------- - EGLint displayFormat = 0; - - // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry() - // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID - eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat); - - // At this point we need to manage render size vs screen size - // NOTE: This function use and modify global module variables: - // -> CORE.Window.screen.width/CORE.Window.screen.height - // -> CORE.Window.render.width/CORE.Window.render.height - // -> CORE.Window.screenScale - SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - - ANativeWindow_setBuffersGeometry(platform.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); - //ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size - - platform.surface = eglCreateWindowSurface(platform.device, platform.config, platform.app->window, NULL); - - // There must be at least one frame displayed before the buffers are swapped - //eglSwapInterval(platform.device, 1); - - if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface"); - return -1; - } - else - { - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.currentFbo.width = CORE.Window.render.width; - CORE.Window.currentFbo.height = CORE.Window.render.height; - - TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); - TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); - TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); - TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); - } - - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - rlLoadExtensions(eglGetProcAddress); - - CORE.Window.ready = true; - - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow(); - - return 0; -} - -// ANDROID: Process activity lifecycle commands -static void AndroidCommandCallback(struct android_app *app, int32_t cmd) -{ - switch (cmd) - { - case APP_CMD_START: - { - //rendering = true; - } break; - case APP_CMD_RESUME: break; - case APP_CMD_INIT_WINDOW: - { - if (app->window != NULL) - { - if (platform.contextRebindRequired) - { - // Reset screen scaling to full display size - EGLint displayFormat = 0; - eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat); - - // Adding renderOffset here feels rather hackish, but the viewport scaling is wrong after the - // context rebinding if the screen is scaled unless offsets are added. There's probably a more - // appropriate way to fix this - ANativeWindow_setBuffersGeometry(app->window, - CORE.Window.render.width + CORE.Window.renderOffset.x, - CORE.Window.render.height + CORE.Window.renderOffset.y, - displayFormat); - - // Recreate display surface and re-attach OpenGL context - platform.surface = eglCreateWindowSurface(platform.device, platform.config, app->window, NULL); - eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context); - - platform.contextRebindRequired = false; - } - else - { - CORE.Window.display.width = ANativeWindow_getWidth(platform.app->window); - CORE.Window.display.height = ANativeWindow_getHeight(platform.app->window); - - // Initialize graphics device (display device and OpenGL context) - InitGraphicsDevice(); - - // Initialize OpenGL context (states and resources) - // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl - rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); - isGpuReady = true; - - // Setup default viewport - // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height - SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); - - // Initialize hi-res timer - InitTimer(); - - #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT) - // Load default font - // WARNING: External function: Module required: rtext - LoadFontDefault(); - #if defined(SUPPORT_MODULE_RSHAPES) - // Set font white rectangle for shapes drawing, so shapes and text can be batched together - // WARNING: rshapes module is required, if not available, default internal white rectangle is used - Rectangle rec = GetFontDefault().recs[95]; - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering - SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 }); - } - else - { - // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding - SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); - } - #endif - #else - #if defined(SUPPORT_MODULE_RSHAPES) - // Set default texture and rectangle to be used for shapes drawing - // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 - Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes - #endif - #endif - - // Initialize random seed - SetRandomSeed((unsigned int)time(NULL)); - - // TODO: GPU assets reload in case of lost focus (lost context) - // NOTE: This problem has been solved just unbinding and rebinding context from display - /* - if (assetsReloadRequired) - { - for (int i = 0; i < assetCount; i++) - { - // TODO: Unload old asset if required - - // Load texture again to pointed texture - (*textureAsset + i) = LoadTexture(assetPath[i]); - } - } - */ - } - } - } break; - case APP_CMD_GAINED_FOCUS: - { - platform.appEnabled = true; - CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; - //ResumeMusicStream(); - } break; - case APP_CMD_PAUSE: break; - case APP_CMD_LOST_FOCUS: - { - platform.appEnabled = false; - CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; - //PauseMusicStream(); - } break; - case APP_CMD_TERM_WINDOW: - { - // Detach OpenGL context and destroy display surface - // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming. - // NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...) - // NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :( - if (platform.device != EGL_NO_DISPLAY) - { - eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (platform.surface != EGL_NO_SURFACE) - { - eglDestroySurface(platform.device, platform.surface); - platform.surface = EGL_NO_SURFACE; - } - - platform.contextRebindRequired = true; - } - // If 'platform.device' is already set to 'EGL_NO_DISPLAY' - // this means that the user has already called 'CloseWindow()' - - } break; - case APP_CMD_SAVE_STATE: break; - case APP_CMD_STOP: break; - case APP_CMD_DESTROY: break; - case APP_CMD_CONFIG_CHANGED: - { - //AConfiguration_fromAssetManager(platform.app->config, platform.app->activity->assetManager); - //print_cur_config(platform.app); - - // Check screen orientation here! - } break; - default: break; - } -} - -// ANDROID: Map Android gamepad button to raylib gamepad button -static GamepadButton AndroidTranslateGamepadButton(int button) -{ - switch (button) - { - case AKEYCODE_BUTTON_A: return GAMEPAD_BUTTON_RIGHT_FACE_DOWN; - case AKEYCODE_BUTTON_B: return GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; - case AKEYCODE_BUTTON_X: return GAMEPAD_BUTTON_RIGHT_FACE_LEFT; - case AKEYCODE_BUTTON_Y: return GAMEPAD_BUTTON_RIGHT_FACE_UP; - case AKEYCODE_BUTTON_L1: return GAMEPAD_BUTTON_LEFT_TRIGGER_1; - case AKEYCODE_BUTTON_R1: return GAMEPAD_BUTTON_RIGHT_TRIGGER_1; - case AKEYCODE_BUTTON_L2: return GAMEPAD_BUTTON_LEFT_TRIGGER_2; - case AKEYCODE_BUTTON_R2: return GAMEPAD_BUTTON_RIGHT_TRIGGER_2; - case AKEYCODE_BUTTON_THUMBL: return GAMEPAD_BUTTON_LEFT_THUMB; - case AKEYCODE_BUTTON_THUMBR: return GAMEPAD_BUTTON_RIGHT_THUMB; - case AKEYCODE_BUTTON_START: return GAMEPAD_BUTTON_MIDDLE_RIGHT; - case AKEYCODE_BUTTON_SELECT: return GAMEPAD_BUTTON_MIDDLE_LEFT; - case AKEYCODE_BUTTON_MODE: return GAMEPAD_BUTTON_MIDDLE; - // On some (most?) gamepads dpad events are reported as axis motion instead - case AKEYCODE_DPAD_DOWN: return GAMEPAD_BUTTON_LEFT_FACE_DOWN; - case AKEYCODE_DPAD_RIGHT: return GAMEPAD_BUTTON_LEFT_FACE_RIGHT; - case AKEYCODE_DPAD_LEFT: return GAMEPAD_BUTTON_LEFT_FACE_LEFT; - case AKEYCODE_DPAD_UP: return GAMEPAD_BUTTON_LEFT_FACE_UP; - default: return GAMEPAD_BUTTON_UNKNOWN; - } -} - -// ANDROID: Get input events -static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) -{ - // If additional inputs are required check: - // https://developer.android.com/ndk/reference/group/input - // https://developer.android.com/training/game-controllers/controller-input - - int type = AInputEvent_getType(event); - int source = AInputEvent_getSource(event); - - if (type == AINPUT_EVENT_TYPE_MOTION) - { - if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) || - ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD)) - { - // For now we'll assume a single gamepad which we "detect" on its input event - CORE.Input.Gamepad.ready[0] = true; - - CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_X] = AMotionEvent_getAxisValue( - event, AMOTION_EVENT_AXIS_X, 0); - CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_Y] = AMotionEvent_getAxisValue( - event, AMOTION_EVENT_AXIS_Y, 0); - CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_X] = AMotionEvent_getAxisValue( - event, AMOTION_EVENT_AXIS_Z, 0); - CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_Y] = AMotionEvent_getAxisValue( - event, AMOTION_EVENT_AXIS_RZ, 0); - CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_TRIGGER] = AMotionEvent_getAxisValue( - event, AMOTION_EVENT_AXIS_BRAKE, 0)*2.0f - 1.0f; - CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_TRIGGER] = AMotionEvent_getAxisValue( - event, AMOTION_EVENT_AXIS_GAS, 0)*2.0f - 1.0f; - - // dpad is reported as an axis on android - float dpadX = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_X, 0); - float dpadY = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_Y, 0); - - if (dpadX == 1.0f) - { - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_RIGHT] = 1; - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_LEFT] = 0; - } - else if (dpadX == -1.0f) - { - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_RIGHT] = 0; - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_LEFT] = 1; - } - else - { - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_RIGHT] = 0; - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_LEFT] = 0; - } - - if (dpadY == 1.0f) - { - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_DOWN] = 1; - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_UP] = 0; - } - else if (dpadY == -1.0f) - { - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_DOWN] = 0; - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_UP] = 1; - } - else - { - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_DOWN] = 0; - CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_UP] = 0; - } - - return 1; // Handled gamepad axis motion - } - } - else if (type == AINPUT_EVENT_TYPE_KEY) - { - int32_t keycode = AKeyEvent_getKeyCode(event); - //int32_t AKeyEvent_getMetaState(event); - - // Handle gamepad button presses and releases - if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) || - ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD)) - { - // For now we'll assume a single gamepad which we "detect" on its input event - CORE.Input.Gamepad.ready[0] = true; - - GamepadButton button = AndroidTranslateGamepadButton(keycode); - - if (button == GAMEPAD_BUTTON_UNKNOWN) return 1; - - if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) - { - CORE.Input.Gamepad.currentButtonState[0][button] = 1; - } - else CORE.Input.Gamepad.currentButtonState[0][button] = 0; // Key up - - return 1; // Handled gamepad button - } - - KeyboardKey key = ((keycode > 0) && (keycode < KEYCODE_MAP_SIZE))? mapKeycode[keycode] : KEY_NULL; - if (key != KEY_NULL) - { - // Save current key and its state - // NOTE: Android key action is 0 for down and 1 for up - if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) - { - CORE.Input.Keyboard.currentKeyState[key] = 1; // Key down - - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; - else CORE.Input.Keyboard.currentKeyState[key] = 0; // Key up - } - - if (keycode == AKEYCODE_POWER) - { - // Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS - // Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS - // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected. - // NOTE: AndroidManifest.xml must have - // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour - return 0; - } - else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU)) - { - // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS! - return 1; - } - else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN)) - { - // Set default OS behaviour - return 0; - } - - return 0; - } - - // Register touch points count - touchRaw.pointCount = AMotionEvent_getPointerCount(event); - - for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++) - { - // Register touch points id - touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i); - - // Register touch points position - touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) }; - - // Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height - float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width; - float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height; - touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2; - touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2; - } - - int32_t action = AMotionEvent_getAction(event); - unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; - int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - - if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER) - { - // The new pointer is hover - // So add it to hoverPoints - for (int i = 0; i < MAX_TOUCH_POINTS; i++) - { - if (touchRaw.hoverPoints[i] == -1) - { - touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex]; - break; - } - } - } - - if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)) - { - // One of the touchpoints is released, remove it from touch point arrays - if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT) - { - // If the touchPoint is hover, remove it from hoverPoints - for (int i = 0; i < MAX_TOUCH_POINTS; i++) - { - if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex]) - { - touchRaw.hoverPoints[i] = -1; - break; - } - } - } - for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++) - { - touchRaw.pointId[i] = touchRaw.pointId[i+1]; - touchRaw.position[i] = touchRaw.position[i+1]; - } - touchRaw.pointCount--; - } - - int pointCount = 0; - for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++) - { - // If the touchPoint is hover, Ignore it - bool hover = false; - for (int j = 0; j < MAX_TOUCH_POINTS; j++) - { - // Check if the touchPoint is in hoverPointers - if (touchRaw.hoverPoints[j] == touchRaw.pointId[i]) - { - hover = true; - break; - } - } - if (hover) continue; - - CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i]; - CORE.Input.Touch.position[pointCount] = touchRaw.position[i]; - pointCount++; - } - CORE.Input.Touch.pointCount = pointCount; - -#if defined(SUPPORT_GESTURES_SYSTEM) - GestureEvent gestureEvent = { 0 }; - - gestureEvent.pointCount = CORE.Input.Touch.pointCount; - - // Register touch actions - if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_ACTION_DOWN; - else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_ACTION_UP; - else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE; - else if (flags == AMOTION_EVENT_ACTION_CANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL; - - for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++) - { - gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i]; - gestureEvent.position[i] = CORE.Input.Touch.position[i]; - gestureEvent.position[i].x /= (float)GetScreenWidth(); - gestureEvent.position[i].y /= (float)GetScreenHeight(); - } - - // Gesture data is sent to gestures system for processing - ProcessGestureEvent(gestureEvent); -#endif - - // When all touchpoints are tapped and released really quickly, this event is generated - if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0; - - if (CORE.Input.Touch.pointCount > 0) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1; - else CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0; - - // Stores the previous position of touch[0] only while it's active to calculate the delta. - if (flags == AMOTION_EVENT_ACTION_MOVE) - { - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - } - else - { - CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0]; - } - - // Map touch[0] as mouse input for convenience - CORE.Input.Mouse.currentPosition = CORE.Input.Touch.position[0]; - CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f }; - - return 0; -} - -// EOF diff --git a/raylib/platforms/rcore_desktop_glfw.c b/raylib/platforms/rcore_desktop_glfw.c deleted file mode 100644 index 9bbd655..0000000 --- a/raylib/platforms/rcore_desktop_glfw.c +++ /dev/null @@ -1,1994 +0,0 @@ -/********************************************************************************************** -* -* rcore_desktop_glfw - Functions to manage window, graphics device and inputs -* -* PLATFORM: DESKTOP: GLFW -* - Windows (Win32, Win64) -* - Linux (X11/Wayland desktop mode) -* - FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop) -* - OSX/macOS (x64, arm64) -* -* LIMITATIONS: -* - Limitation 01 -* - Limitation 02 -* -* POSSIBLE IMPROVEMENTS: -* - Improvement 01 -* - Improvement 02 -* -* ADDITIONAL NOTES: -* - TRACELOG() function is located in raylib [utils] module -* -* CONFIGURATION: -* #define RCORE_PLATFORM_CUSTOM_FLAG -* Custom flag for rcore on target platform -not used- -* -* DEPENDENCIES: -* - rglfw: Manage graphic device, OpenGL context and inputs (Windows, Linux, OSX, FreeBSD...) -* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 - // NOTE: Already provided by rlgl implementation (on glad.h) -#include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management - // NOTE: GLFW3 already includes gl.h (OpenGL) headers - -// Support retrieving native window handlers -#if defined(_WIN32) - typedef void *PVOID; - typedef PVOID HANDLE; - #include "../external/win32_clipboard.h" - typedef HANDLE HWND; - #define GLFW_EXPOSE_NATIVE_WIN32 - #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h - #include "GLFW/glfw3native.h" - - #if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) - // NOTE: Those functions require linking with winmm library - //#pragma warning(disable: 4273) - __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); - //#pragma warning(default: 4273) - #endif -#endif -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) - #include // Required for: timespec, nanosleep(), select() - POSIX - - //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type - //#define GLFW_EXPOSE_NATIVE_WAYLAND - #include "GLFW/glfw3native.h" // Required for: glfwGetX11Window() -#endif -#if defined(__APPLE__) - #include // Required for: usleep() - - //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition - void *glfwGetCocoaWindow(GLFWwindow* handle); - #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow() -#endif - -#include // Required for: size_t - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef struct { - GLFWwindow *handle; // GLFW window handle (graphic device) -} PlatformData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context - -static PlatformData platform = { 0 }; // Platform specific data - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -int InitPlatform(void); // Initialize platform (graphics, inputs and more) -void ClosePlatform(void); // Close platform - -// Error callback event -static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error - -// Window callbacks events -static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized -static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved -static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored -static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized -static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus -static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window -static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale - -// Input callbacks events -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed -static void CharCallback(GLFWwindow *window, unsigned int codepoint); // GLFW3 Char Callback, runs on key pressed (get codepoint value) -static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed -static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move -static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel -static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area -static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback - -// Wrappers used by glfwInitAllocator -static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro -static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro -static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -// NOTE: Functions declaration is provided by raylib.h - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Window and Graphics Device -//---------------------------------------------------------------------------------- - -// Check if application should close -// NOTE: By default, if KEY_ESCAPE pressed or window close icon clicked -bool WindowShouldClose(void) -{ - if (CORE.Window.ready) return CORE.Window.shouldClose; - else return true; -} - -// Toggle fullscreen mode -void ToggleFullscreen(void) -{ - if (!CORE.Window.fullscreen) - { - // Store previous window position (in case we exit fullscreen) - CORE.Window.previousPosition = CORE.Window.position; - - int monitorCount = 0; - int monitorIndex = GetCurrentMonitor(); - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - // Use current monitor, so we correctly get the display the window is on - GLFWmonitor *monitor = (monitorIndex < monitorCount)? monitors[monitorIndex] : NULL; - - if (monitor == NULL) - { - TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor"); - - CORE.Window.fullscreen = false; - CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - - glfwSetWindowMonitor(platform.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); - } - else - { - CORE.Window.fullscreen = true; - CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - - glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); - } - - } - else - { - CORE.Window.fullscreen = false; - CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - - glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); - - // we update the window position right away - CORE.Window.position.x = CORE.Window.previousPosition.x; - CORE.Window.position.y = CORE.Window.previousPosition.y; - } - - // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) - // NOTE: V-Sync can be enabled by graphic driver configuration - if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1); -} - -// Toggle borderless windowed mode -void ToggleBorderlessWindowed(void) -{ - // Leave fullscreen before attempting to set borderless windowed mode - bool wasOnFullscreen = false; - if (CORE.Window.fullscreen) - { - // fullscreen already saves the previous position so it does not need to be set here again - ToggleFullscreen(); - wasOnFullscreen = true; - } - - const int monitor = GetCurrentMonitor(); - int monitorCount; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); - - if (mode) - { - if (!IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE)) - { - // Store screen position and size - // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here - if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position; - CORE.Window.previousScreen = CORE.Window.screen; - - // Set undecorated flag - glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE); - CORE.Window.flags |= FLAG_WINDOW_UNDECORATED; - - // Get monitor position and size - int monitorPosX = 0; - int monitorPosY = 0; - glfwGetMonitorPos(monitors[monitor], &monitorPosX, &monitorPosY); - const int monitorWidth = mode->width; - const int monitorHeight = mode->height; - - // Set screen position and size - glfwSetWindowPos(platform.handle, monitorPosX, monitorPosY); - glfwSetWindowSize(platform.handle, monitorWidth, monitorHeight); - - // Refocus window - glfwFocusWindow(platform.handle); - - CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE; - } - else - { - // Remove undecorated flag - glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); - CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED; - - // Return previous screen size and position - // NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly - glfwSetWindowSize(platform.handle, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height); - glfwSetWindowPos(platform.handle, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y); - - // Refocus window - glfwFocusWindow(platform.handle); - - CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE; - - CORE.Window.position.x = CORE.Window.previousPosition.x; - CORE.Window.position.y = CORE.Window.previousPosition.y; - } - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); -} - -// Set window state: maximized, if resizable -void MaximizeWindow(void) -{ - if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) - { - glfwMaximizeWindow(platform.handle); - CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; - } -} - -// Set window state: minimized -void MinimizeWindow(void) -{ - // NOTE: Following function launches callback that sets appropriate flag! - glfwIconifyWindow(platform.handle); -} - -// Restore window from being minimized/maximized -void RestoreWindow(void) -{ - if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) - { - // Restores the specified window if it was previously iconified (minimized) or maximized - glfwRestoreWindow(platform.handle); - CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; - CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; - } -} - -// Set window configuration state using flags -void SetWindowState(unsigned int flags) -{ - if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead"); - - // Check previous state and requested state to apply required changes - // NOTE: In most cases the functions already change the flags internally - - // State change: FLAG_VSYNC_HINT - if (((CORE.Window.flags & FLAG_VSYNC_HINT) != (flags & FLAG_VSYNC_HINT)) && ((flags & FLAG_VSYNC_HINT) > 0)) - { - glfwSwapInterval(1); - CORE.Window.flags |= FLAG_VSYNC_HINT; - } - - // State change: FLAG_BORDERLESS_WINDOWED_MODE - // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running - if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) != (flags & FLAG_BORDERLESS_WINDOWED_MODE)) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)) - { - ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_FULLSCREEN_MODE - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE) && ((flags & FLAG_FULLSCREEN_MODE) > 0)) - { - ToggleFullscreen(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_WINDOW_RESIZABLE - if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_TRUE); - CORE.Window.flags |= FLAG_WINDOW_RESIZABLE; - } - - // State change: FLAG_WINDOW_UNDECORATED - if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) != (flags & FLAG_WINDOW_UNDECORATED)) && (flags & FLAG_WINDOW_UNDECORATED)) - { - glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE); - CORE.Window.flags |= FLAG_WINDOW_UNDECORATED; - } - - // State change: FLAG_WINDOW_HIDDEN - if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) != (flags & FLAG_WINDOW_HIDDEN)) && ((flags & FLAG_WINDOW_HIDDEN) > 0)) - { - glfwHideWindow(platform.handle); - CORE.Window.flags |= FLAG_WINDOW_HIDDEN; - } - - // State change: FLAG_WINDOW_MINIMIZED - if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) != (flags & FLAG_WINDOW_MINIMIZED)) && ((flags & FLAG_WINDOW_MINIMIZED) > 0)) - { - //GLFW_ICONIFIED - MinimizeWindow(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_WINDOW_MAXIMIZED - if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0)) - { - //GLFW_MAXIMIZED - MaximizeWindow(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_WINDOW_UNFOCUSED - if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) != (flags & FLAG_WINDOW_UNFOCUSED)) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_FALSE); - CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; - } - - // State change: FLAG_WINDOW_TOPMOST - if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) != (flags & FLAG_WINDOW_TOPMOST)) && ((flags & FLAG_WINDOW_TOPMOST) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE); - CORE.Window.flags |= FLAG_WINDOW_TOPMOST; - } - - // State change: FLAG_WINDOW_ALWAYS_RUN - if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) != (flags & FLAG_WINDOW_ALWAYS_RUN)) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)) - { - CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN; - } - - // The following states can not be changed after window creation - - // State change: FLAG_WINDOW_TRANSPARENT - if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) - { - TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); - } - - // State change: FLAG_WINDOW_HIGHDPI - if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) - { - TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); - } - - // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH - if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) != (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); - CORE.Window.flags |= FLAG_WINDOW_MOUSE_PASSTHROUGH; - } - - // State change: FLAG_MSAA_4X_HINT - if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0)) - { - TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization"); - } - - // State change: FLAG_INTERLACED_HINT - if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0)) - { - TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); - } -} - -// Clear window configuration state flags -void ClearWindowState(unsigned int flags) -{ - // Check previous state and requested state to apply required changes - // NOTE: In most cases the functions already change the flags internally - - // State change: FLAG_VSYNC_HINT - if (((CORE.Window.flags & FLAG_VSYNC_HINT) > 0) && ((flags & FLAG_VSYNC_HINT) > 0)) - { - glfwSwapInterval(0); - CORE.Window.flags &= ~FLAG_VSYNC_HINT; - } - - // State change: FLAG_BORDERLESS_WINDOWED_MODE - // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running - if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)) - { - ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_FULLSCREEN_MODE - if (((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) && ((flags & FLAG_FULLSCREEN_MODE) > 0)) - { - ToggleFullscreen(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_WINDOW_RESIZABLE - if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_FALSE); - CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE; - } - - // State change: FLAG_WINDOW_HIDDEN - if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) && ((flags & FLAG_WINDOW_HIDDEN) > 0)) - { - glfwShowWindow(platform.handle); - CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; - } - - // State change: FLAG_WINDOW_MINIMIZED - if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((flags & FLAG_WINDOW_MINIMIZED) > 0)) - { - RestoreWindow(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_WINDOW_MAXIMIZED - if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0)) - { - RestoreWindow(); // NOTE: Window state flag updated inside function - } - - // State change: FLAG_WINDOW_UNDECORATED - if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) && ((flags & FLAG_WINDOW_UNDECORATED) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); - CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED; - } - - // State change: FLAG_WINDOW_UNFOCUSED - if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_TRUE); - CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; - } - - // State change: FLAG_WINDOW_TOPMOST - if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) && ((flags & FLAG_WINDOW_TOPMOST) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE); - CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST; - } - - // State change: FLAG_WINDOW_ALWAYS_RUN - if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) > 0) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)) - { - CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN; - } - - // The following states can not be changed after window creation - - // State change: FLAG_WINDOW_TRANSPARENT - if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) - { - TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); - } - - // State change: FLAG_WINDOW_HIGHDPI - if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) - { - TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); - } - - // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH - if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)) - { - glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE); - CORE.Window.flags &= ~FLAG_WINDOW_MOUSE_PASSTHROUGH; - } - - // State change: FLAG_MSAA_4X_HINT - if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0)) - { - TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization"); - } - - // State change: FLAG_INTERLACED_HINT - if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0)) - { - TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); - } -} - -// Set icon for window -// NOTE 1: Image must be in RGBA format, 8bit per channel -// NOTE 2: Image is scaled by the OS for all required sizes -void SetWindowIcon(Image image) -{ - if (image.data == NULL) - { - // Revert to the default window icon, pass in an empty image array - glfwSetWindowIcon(platform.handle, 0, NULL); - } - else - { - if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) - { - GLFWimage icon[1] = { 0 }; - - icon[0].width = image.width; - icon[0].height = image.height; - icon[0].pixels = (unsigned char *)image.data; - - // NOTE 1: We only support one image icon - // NOTE 2: The specified image data is copied before this function returns - glfwSetWindowIcon(platform.handle, 1, icon); - } - else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); - } -} - -// Set icon for window, multiple images -// NOTE 1: Images must be in RGBA format, 8bit per channel -// NOTE 2: The multiple images are used depending on provided sizes -// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16 -void SetWindowIcons(Image *images, int count) -{ - if ((images == NULL) || (count <= 0)) - { - // Revert to the default window icon, pass in an empty image array - glfwSetWindowIcon(platform.handle, 0, NULL); - } - else - { - int valid = 0; - GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage)); - - for (int i = 0; i < count; i++) - { - if (images[i].format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) - { - icons[valid].width = images[i].width; - icons[valid].height = images[i].height; - icons[valid].pixels = (unsigned char *)images[i].data; - - valid++; - } - else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); - } - // NOTE: Images data is copied internally before this function returns - glfwSetWindowIcon(platform.handle, valid, icons); - - RL_FREE(icons); - } -} - -// Set title for window -void SetWindowTitle(const char *title) -{ - CORE.Window.title = title; - glfwSetWindowTitle(platform.handle, title); -} - -// Set window position on screen (windowed mode) -void SetWindowPosition(int x, int y) -{ - // Update CORE.Window.position as well - CORE.Window.position.x = x; - CORE.Window.position.y = y; - glfwSetWindowPos(platform.handle, x, y); -} - -// Set monitor for the current window -void SetWindowMonitor(int monitor) -{ - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - if (CORE.Window.fullscreen) - { - TRACELOG(LOG_INFO, "GLFW: Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); - - const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); - glfwSetWindowMonitor(platform.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate); - } - else - { - TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); - - // Here the render width has to be used again in case high dpi flag is enabled - const int screenWidth = CORE.Window.render.width; - const int screenHeight = CORE.Window.render.height; - int monitorWorkareaX = 0; - int monitorWorkareaY = 0; - int monitorWorkareaWidth = 0; - int monitorWorkareaHeight = 0; - glfwGetMonitorWorkarea(monitors[monitor], &monitorWorkareaX, &monitorWorkareaY, &monitorWorkareaWidth, &monitorWorkareaHeight); - - // If the screen size is larger than the monitor workarea, anchor it on the top left corner, otherwise, center it - if ((screenWidth >= monitorWorkareaWidth) || (screenHeight >= monitorWorkareaHeight)) glfwSetWindowPos(platform.handle, monitorWorkareaX, monitorWorkareaY); - else - { - const int x = monitorWorkareaX + (monitorWorkareaWidth/2) - (screenWidth/2); - const int y = monitorWorkareaY + (monitorWorkareaHeight/2) - (screenHeight/2); - glfwSetWindowPos(platform.handle, x, y); - } - } - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); -} - -// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMinSize(int width, int height) -{ - CORE.Window.screenMin.width = width; - CORE.Window.screenMin.height = height; - - int minWidth = (CORE.Window.screenMin.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.width; - int minHeight = (CORE.Window.screenMin.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.height; - int maxWidth = (CORE.Window.screenMax.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.width; - int maxHeight = (CORE.Window.screenMax.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.height; - - glfwSetWindowSizeLimits(platform.handle, minWidth, minHeight, maxWidth, maxHeight); -} - -// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMaxSize(int width, int height) -{ - CORE.Window.screenMax.width = width; - CORE.Window.screenMax.height = height; - - int minWidth = (CORE.Window.screenMin.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.width; - int minHeight = (CORE.Window.screenMin.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMin.height; - int maxWidth = (CORE.Window.screenMax.width == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.width; - int maxHeight = (CORE.Window.screenMax.height == 0)? GLFW_DONT_CARE : (int)CORE.Window.screenMax.height; - - glfwSetWindowSizeLimits(platform.handle, minWidth, minHeight, maxWidth, maxHeight); -} - -// Set window dimensions -void SetWindowSize(int width, int height) -{ - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - - glfwSetWindowSize(platform.handle, width, height); -} - -// Set window opacity, value opacity is between 0.0 and 1.0 -void SetWindowOpacity(float opacity) -{ - if (opacity >= 1.0f) opacity = 1.0f; - else if (opacity <= 0.0f) opacity = 0.0f; - glfwSetWindowOpacity(platform.handle, opacity); -} - -// Set window focused -void SetWindowFocused(void) -{ - glfwFocusWindow(platform.handle); -} - -// Get native window handle -void *GetWindowHandle(void) -{ -#if defined(_WIN32) - // NOTE: Returned handle is: void *HWND (windows.h) - return glfwGetWin32Window(platform.handle); -#endif -#if defined(__linux__) - // NOTE: Returned handle is: unsigned long Window (X.h) - // typedef unsigned long XID; - // typedef XID Window; - //unsigned long id = (unsigned long)glfwGetX11Window(platform.handle); - //return NULL; // TODO: Find a way to return value... cast to void *? - return (void *)platform.handle; -#endif -#if defined(__APPLE__) - // NOTE: Returned handle is: (objc_object *) - return (void *)glfwGetCocoaWindow(platform.handle); -#endif - - return NULL; -} - -// Get number of monitors -int GetMonitorCount(void) -{ - int monitorCount = 0; - - glfwGetMonitors(&monitorCount); - - return monitorCount; -} - -// Get current monitor where window is placed -int GetCurrentMonitor(void) -{ - int index = 0; - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - GLFWmonitor *monitor = NULL; - - if (monitorCount >= 1) - { - if (IsWindowFullscreen()) - { - // Get the handle of the monitor that the specified window is in full screen on - monitor = glfwGetWindowMonitor(platform.handle); - - for (int i = 0; i < monitorCount; i++) - { - if (monitors[i] == monitor) - { - index = i; - break; - } - } - } - else - { - // In case the window is between two monitors, we use below logic - // to try to detect the "current monitor" for that window, note that - // this is probably an overengineered solution for a very side case - // trying to match SDL behaviour - - int closestDist = 0x7FFFFFFF; - - // Window center position - int wcx = 0; - int wcy = 0; - - glfwGetWindowPos(platform.handle, &wcx, &wcy); - wcx += (int)CORE.Window.screen.width/2; - wcy += (int)CORE.Window.screen.height/2; - - for (int i = 0; i < monitorCount; i++) - { - // Monitor top-left position - int mx = 0; - int my = 0; - - monitor = monitors[i]; - glfwGetMonitorPos(monitor, &mx, &my); - const GLFWvidmode *mode = glfwGetVideoMode(monitor); - - if (mode) - { - const int right = mx + mode->width - 1; - const int bottom = my + mode->height - 1; - - if ((wcx >= mx) && - (wcx <= right) && - (wcy >= my) && - (wcy <= bottom)) - { - index = i; - break; - } - - int xclosest = wcx; - if (wcx < mx) xclosest = mx; - else if (wcx > right) xclosest = right; - - int yclosest = wcy; - if (wcy < my) yclosest = my; - else if (wcy > bottom) yclosest = bottom; - - int dx = wcx - xclosest; - int dy = wcy - yclosest; - int dist = (dx*dx) + (dy*dy); - if (dist < closestDist) - { - index = i; - closestDist = dist; - } - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); - } - } - } - - return index; -} - -// Get selected monitor position -Vector2 GetMonitorPosition(int monitor) -{ - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - int x, y; - glfwGetMonitorPos(monitors[monitor], &x, &y); - - return (Vector2){ (float)x, (float)y }; - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - return (Vector2){ 0, 0 }; -} - -// Get selected monitor width (currently used by monitor) -int GetMonitorWidth(int monitor) -{ - int width = 0; - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); - - if (mode) width = mode->width; - else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - - return width; -} - -// Get selected monitor height (currently used by monitor) -int GetMonitorHeight(int monitor) -{ - int height = 0; - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); - - if (mode) height = mode->height; - else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - - return height; -} - -// Get selected monitor physical width in millimetres -int GetMonitorPhysicalWidth(int monitor) -{ - int width = 0; - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) glfwGetMonitorPhysicalSize(monitors[monitor], &width, NULL); - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - - return width; -} - -// Get selected monitor physical height in millimetres -int GetMonitorPhysicalHeight(int monitor) -{ - int height = 0; - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) glfwGetMonitorPhysicalSize(monitors[monitor], NULL, &height); - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - - return height; -} - -// Get selected monitor refresh rate -int GetMonitorRefreshRate(int monitor) -{ - int refresh = 0; - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - const GLFWvidmode *vidmode = glfwGetVideoMode(monitors[monitor]); - refresh = vidmode->refreshRate; - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - - return refresh; -} - -// Get the human-readable, UTF-8 encoded name of the selected monitor -const char *GetMonitorName(int monitor) -{ - int monitorCount = 0; - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - return glfwGetMonitorName(monitors[monitor]); - } - else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); - return ""; -} - -// Get window position XY on monitor -Vector2 GetWindowPosition(void) -{ - int x = 0; - int y = 0; - - glfwGetWindowPos(platform.handle, &x, &y); - - return (Vector2){ (float)x, (float)y }; -} - -// Get window scale DPI factor for current monitor -Vector2 GetWindowScaleDPI(void) -{ - Vector2 scale = {0}; - glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y); - return scale; -} - -// Set clipboard text content -void SetClipboardText(const char *text) -{ - glfwSetClipboardString(platform.handle, text); -} - -// Get clipboard text content -// NOTE: returned string is allocated and freed by GLFW -const char *GetClipboardText(void) -{ - return glfwGetClipboardString(platform.handle); -} - -// Get clipboard image -Image GetClipboardImage(void) -{ - Image image = { 0 }; - -#if defined(SUPPORT_CLIPBOARD_IMAGE) -#if defined(_WIN32) - unsigned long long int dataSize = 0; - void *fileData = NULL; - int width = 0; - int height = 0; - - fileData = (void*)Win32GetClipboardImageData(&width, &height, &dataSize); - - if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data."); - else image = LoadImageFromMemory(".bmp", fileData, (int)dataSize); -#else - TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); -#endif -#endif // SUPPORT_CLIPBOARD_IMAGE - - return image; -} - -// Show mouse cursor -void ShowCursor(void) -{ - glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - CORE.Input.Mouse.cursorHidden = false; -} - -// Hides mouse cursor -void HideCursor(void) -{ - glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - CORE.Input.Mouse.cursorHidden = true; -} - -// Enables cursor (unlock cursor) -void EnableCursor(void) -{ - glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - - if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE); - - CORE.Input.Mouse.cursorHidden = false; -} - -// Disables cursor (lock cursor) -void DisableCursor(void) -{ - // Reset mouse position within the window area before disabling cursor - SetMousePosition(CORE.Window.screen.width, CORE.Window.screen.height); - - glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - - if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); - - CORE.Input.Mouse.cursorHidden = true; -} - -// Swap back buffer with front buffer (screen drawing) -void SwapScreenBuffer(void) -{ - glfwSwapBuffers(platform.handle); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Misc -//---------------------------------------------------------------------------------- - -// Get elapsed time measure in seconds since InitTimer() -double GetTime(void) -{ - double time = glfwGetTime(); // Elapsed time since glfwInit() - return time; -} - -// Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 -void OpenURL(const char *url) -{ - // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else - { - char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); -#if defined(_WIN32) - sprintf(cmd, "explorer \"%s\"", url); -#endif -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) - sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser -#endif -#if defined(__APPLE__) - sprintf(cmd, "open '%s'", url); -#endif - int result = system(cmd); - if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created"); - RL_FREE(cmd); - } -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Inputs -//---------------------------------------------------------------------------------- - -// Set internal gamepad mappings -int SetGamepadMappings(const char *mappings) -{ - return glfwUpdateGamepadMappings(mappings); -} - -// Set gamepad vibration -void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) -{ - TRACELOG(LOG_WARNING, "SetGamepadVibration() not available on target platform"); -} - -// Set mouse position XY -void SetMousePosition(int x, int y) -{ - CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - - // NOTE: emscripten not implemented - glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); -} - -// Set mouse cursor -void SetMouseCursor(int cursor) -{ - CORE.Input.Mouse.cursor = cursor; - if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(platform.handle, NULL); - else - { - // NOTE: We are relating internal GLFW enum values to our MouseCursor enum values - glfwSetCursor(platform.handle, glfwCreateStandardCursor(0x00036000 + cursor)); - } -} - -// Get physical key name. -const char *GetKeyName(int key) -{ - return glfwGetKeyName(key, glfwGetKeyScancode(key)); -} - -// Register all input events -void PollInputEvents(void) -{ -#if defined(SUPPORT_GESTURES_SYSTEM) - // NOTE: Gestures update must be called every frame to reset gestures correctly - // because ProcessGestureEvent() is just called on an event, not every frame - UpdateGestures(); -#endif - - // Reset keys/chars pressed registered - CORE.Input.Keyboard.keyPressedQueueCount = 0; - CORE.Input.Keyboard.charPressedQueueCount = 0; - - // Reset last gamepad button/axis registered state - CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN - //CORE.Input.Gamepad.axisCount = 0; - - // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback) - - // Register previous keys states - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Register previous mouse states - for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; - - // Register previous mouse wheel state - CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; - CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f }; - - // Register previous mouse position - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - - // Register previous touch states - for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; - - // Reset touch positions - //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; - - // Map touch position to mouse position for convenience - // WARNING: If the target desktop device supports touch screen, this behaviour should be reviewed! - // TODO: GLFW does not support multi-touch input just yet - // https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch - // https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - - // Check if gamepads are ready - // NOTE: We do it here in case of disconnection - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (glfwJoystickPresent(i)) CORE.Input.Gamepad.ready[i] = true; - else CORE.Input.Gamepad.ready[i] = false; - } - - // Register gamepads buttons events - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (CORE.Input.Gamepad.ready[i]) // Check if gamepad is available - { - // Register previous gamepad states - for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; - - // Get current gamepad state - // NOTE: There is no callback available, so we get it manually - GLFWgamepadstate state = { 0 }; - glfwGetGamepadState(i, &state); // This remapps all gamepads so they have their buttons mapped like an xbox controller - - const unsigned char *buttons = state.buttons; - - for (int k = 0; (buttons != NULL) && (k < MAX_GAMEPAD_BUTTONS); k++) - { - int button = -1; // GamepadButton enum values assigned - - switch (k) - { - case GLFW_GAMEPAD_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; - case GLFW_GAMEPAD_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; - case GLFW_GAMEPAD_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break; - case GLFW_GAMEPAD_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break; - - case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break; - case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break; - - case GLFW_GAMEPAD_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break; - case GLFW_GAMEPAD_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break; - case GLFW_GAMEPAD_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break; - - case GLFW_GAMEPAD_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break; - case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break; - case GLFW_GAMEPAD_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break; - case GLFW_GAMEPAD_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break; - - case GLFW_GAMEPAD_BUTTON_LEFT_THUMB: button = GAMEPAD_BUTTON_LEFT_THUMB; break; - case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB: button = GAMEPAD_BUTTON_RIGHT_THUMB; break; - default: break; - } - - if (button != -1) // Check for valid button - { - if (buttons[k] == GLFW_PRESS) - { - CORE.Input.Gamepad.currentButtonState[i][button] = 1; - CORE.Input.Gamepad.lastButtonPressed = button; - } - else CORE.Input.Gamepad.currentButtonState[i][button] = 0; - } - } - - // Get current state of axes - const float *axes = state.axes; - - for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++) - { - CORE.Input.Gamepad.axisState[i][k] = axes[k]; - } - - // Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes) - if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f) - { - CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1; - CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_LEFT_TRIGGER_2; - } - else CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 0; - if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1f) - { - CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = 1; - CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_RIGHT_TRIGGER_2; - } - else CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = 0; - - CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1; - } - } - - CORE.Window.resizedLastFrame = false; - - if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN))) - { - glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) - CORE.Time.previous = GetTime(); - } - else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state - - CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle); - - // Reset close status for next frame - glfwSetWindowShouldClose(platform.handle, GLFW_FALSE); -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- - -static void SetDimensionsFromMonitor(GLFWmonitor *monitor) -{ - const GLFWvidmode *mode = glfwGetVideoMode(monitor); - - // Default display resolution to that of the current mode - CORE.Window.display.width = mode->width; - CORE.Window.display.height = mode->height; - - // Set screen width/height to the display width/height if they are 0 - if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; - if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; -} - -// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform() -// We need to provide these because GLFWallocator expects function pointers with specific signatures. -// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch. -// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator -static void *AllocateWrapper(size_t size, void *user) -{ - (void)user; - return RL_MALLOC(size); -} -static void *ReallocateWrapper(void *block, size_t size, void *user) -{ - (void)user; - return RL_REALLOC(block, size); -} -static void DeallocateWrapper(void *block, void *user) -{ - (void)user; - RL_FREE(block); -} - -// Initialize platform: graphics, inputs and more -int InitPlatform(void) -{ - glfwSetErrorCallback(ErrorCallback); - - const GLFWallocator allocator = { - .allocate = AllocateWrapper, - .deallocate = DeallocateWrapper, - .reallocate = ReallocateWrapper, - .user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data - }; - - glfwInitAllocator(&allocator); - -#if defined(__APPLE__) - glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE); -#endif - // Initialize GLFW internal global state - int result = glfwInit(); - if (result == GLFW_FALSE) { TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW"); return -1; } - - // Initialize graphic device: display/window and graphic context - //---------------------------------------------------------------------------- - glfwDefaultWindowHints(); // Set default windows hints - //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits - //glfwWindowHint(GLFW_GREEN_BITS, 8); // Framebuffer green color component bits - //glfwWindowHint(GLFW_BLUE_BITS, 8); // Framebuffer blue color component bits - //glfwWindowHint(GLFW_ALPHA_BITS, 8); // Framebuffer alpha color component bits - //glfwWindowHint(GLFW_DEPTH_BITS, 24); // Depthbuffer bits - //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window - //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API - //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers - - // Disable GlFW auto iconify behaviour - // Auto Iconify automatically minimizes (iconifies) the window if the window loses focus - // additionally auto iconify restores the hardware resolution of the monitor if the window that loses focus is a fullscreen window - glfwWindowHint(GLFW_AUTO_ICONIFY, 0); - - // Check window creation flags - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; - - if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window - else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden - - if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window - else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window - - if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window - else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable - - // Disable FLAG_WINDOW_MINIMIZED, not supported on initialization - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; - - // Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; - - if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE); - else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); - - if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); - else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); - - // NOTE: Some GLFW flags are not supported on HTML5 - if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer - else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer - - // HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and - // was enabled by default. Disabling it gets back the old behavior. A - // complete fix will require removing a lot of CORE.Window.render - // manipulation code. - glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); - - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) - { - // Resize window content area based on the monitor content scale. - // NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11. - // On platforms like macOS the resolution of the framebuffer is changed independently of the window size. - glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on -#if defined(__APPLE__) - glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); -#endif - } - else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); - - // Mouse passthrough - if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); - else glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE); - - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - // NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs - TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); - glfwWindowHint(GLFW_SAMPLES, 4); // Tries to enable multisampling x4 (MSAA), default is 0 - } - - // NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version - // with backward compatibility to older OpenGL versions. - // For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context. - - // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_21) - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // Choose OpenGL major version (just hint) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // Choose OpenGL minor version (just hint) - } - else if (rlGetVersion() == RL_OPENGL_33) - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above! - // Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE -#if defined(__APPLE__) - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // OSX Requires forward compatibility -#else - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Forward Compatibility Hint: Only 3.3 and above! -#endif - //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context - } - else if (rlGetVersion() == RL_OPENGL_43) - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Choose OpenGL major version (just hint) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Enable OpenGL Debug Context -#endif - } - else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); - } - else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); - } - - // NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions. - // Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn. - // The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience. - // REF: https://github.com/raysan5/raylib/issues/1554 - glfwSetJoystickCallback(NULL); - - GLFWmonitor *monitor = NULL; - if (CORE.Window.fullscreen) - { - // According to glfwCreateWindow(), if the user does not have a choice, fullscreen applications - // should default to the primary monitor. - - monitor = glfwGetPrimaryMonitor(); - if (!monitor) - { - TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor"); - return -1; - } - - SetDimensionsFromMonitor(monitor); - - // Remember center for switching from fullscreen to window - if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) - { - // If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed. - // Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11. - CORE.Window.position.x = CORE.Window.display.width/4; - CORE.Window.position.y = CORE.Window.display.height/4; - } - else - { - CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2; - CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2; - } - - if (CORE.Window.position.x < 0) CORE.Window.position.x = 0; - if (CORE.Window.position.y < 0) CORE.Window.position.y = 0; - - // Obtain recommended CORE.Window.display.width/CORE.Window.display.height from a valid videomode for the monitor - int count = 0; - const GLFWvidmode *modes = glfwGetVideoModes(monitor, &count); - - // Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height - for (int i = 0; i < count; i++) - { - if ((unsigned int)modes[i].width >= CORE.Window.screen.width) - { - if ((unsigned int)modes[i].height >= CORE.Window.screen.height) - { - CORE.Window.display.width = modes[i].width; - CORE.Window.display.height = modes[i].height; - break; - } - } - } - - TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - - // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, - // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3), - // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched - // by the sides to fit all monitor space... - - // Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight - // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset) - // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale - // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed... - // HighDPI monitors are properly considered in a following similar function: SetupViewport() - SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - - platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", monitor, NULL); - if (!platform.handle) - { - glfwTerminate(); - TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); - return -1; - } - - // NOTE: Full-screen change, not working properly... - //glfwSetWindowMonitor(platform.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); - } - else - { - // No-fullscreen window creation - bool requestWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 0); - - // Default to at least one pixel in size, as creation with a zero dimension is not allowed. - int creationWidth = CORE.Window.screen.width != 0 ? CORE.Window.screen.width : 1; - int creationHeight = CORE.Window.screen.height != 0 ? CORE.Window.screen.height : 1; - - platform.handle = glfwCreateWindow(creationWidth, creationHeight, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); - if (!platform.handle) - { - glfwTerminate(); - TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); - return -1; - } - - // After the window was created, determine the monitor that the window manager assigned. - // Derive display sizes, and, if possible, window size in case it was zero at beginning. - - int monitorCount = 0; - int monitorIndex = GetCurrentMonitor(); - GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if (monitorIndex < monitorCount) - { - monitor = monitors[monitorIndex]; - SetDimensionsFromMonitor(monitor); - - if (requestWindowedFullscreen) glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height); - } - else - { - // The monitor for the window-manager-created window can not be determined, so it can not be centered. - glfwTerminate(); - TRACELOG(LOG_WARNING, "GLFW: Failed to determine Monitor to center Window"); - return -1; - } - - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - } - - glfwMakeContextCurrent(platform.handle); - result = glfwGetError(NULL); - - // Check context activation - if ((result != GLFW_NO_WINDOW_CONTEXT) && (result != GLFW_PLATFORM_ERROR)) - { - CORE.Window.ready = true; - - glfwSwapInterval(0); // No V-Sync by default - - // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) - // NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need - // to be activated on web platforms since VSync is enforced there. - if (CORE.Window.flags & FLAG_VSYNC_HINT) - { - // WARNING: It seems to hit a critical render path in Intel HD Graphics - glfwSwapInterval(1); - TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC"); - } - - int fbWidth = CORE.Window.screen.width; - int fbHeight = CORE.Window.screen.height; - - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) - { - // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling. - // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); - #if !defined(__APPLE__) - glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight); - - // Screen scaling matrix is required in case desired screen area is different from display area - CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); - - // Mouse input scaling for the new screen size - SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight); - #endif - } - - CORE.Window.render.width = fbWidth; - CORE.Window.render.height = fbHeight; - CORE.Window.currentFbo.width = fbWidth; - CORE.Window.currentFbo.height = fbHeight; - - TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); - TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); - TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); - TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); - } - else - { - TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device"); - return -1; - } - - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow(); - - // If graphic device is no properly initialized, we end program - if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; } - else - { - // Try to center window on screen but avoiding window-bar outside of screen - int monitorX = 0; - int monitorY = 0; - int monitorWidth = 0; - int monitorHeight = 0; - glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight); - - // Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled. - int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2; - int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2; - if (posX < monitorX) posX = monitorX; - if (posY < monitorY) posY = monitorY; - SetWindowPosition(posX, posY); - - // Update CORE.Window.position here so it is correct from the start - CORE.Window.position.x = posX; - CORE.Window.position.y = posY; - } - - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - rlLoadExtensions(glfwGetProcAddress); - //---------------------------------------------------------------------------- - - // Initialize input events callbacks - //---------------------------------------------------------------------------- - // Set window callback events - glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! - glfwSetWindowPosCallback(platform.handle, WindowPosCallback); - glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback); - glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); - glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); - glfwSetDropCallback(platform.handle, WindowDropCallback); - - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) - { - glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback); - } - - // Set input callback events - glfwSetKeyCallback(platform.handle, KeyCallback); - glfwSetCharCallback(platform.handle, CharCallback); - glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback); - glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes - glfwSetScrollCallback(platform.handle, MouseScrollCallback); - glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback); - glfwSetJoystickCallback(JoystickCallback); - - glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM) - - // Retrieve gamepad names - for (int i = 0; i < MAX_GAMEPADS; i++) - { - // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH, - // we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1) - if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1); - } - //---------------------------------------------------------------------------- - - // Initialize timming system - //---------------------------------------------------------------------------- - InitTimer(); - //---------------------------------------------------------------------------- - - // Initialize storage system - //---------------------------------------------------------------------------- - CORE.Storage.basePath = GetWorkingDirectory(); - //---------------------------------------------------------------------------- - -#if defined(__NetBSD__) - // Workaround for NetBSD - char *glfwPlatform = "X11"; -#else - char *glfwPlatform = ""; - switch (glfwGetPlatform()) - { - case GLFW_PLATFORM_WIN32: glfwPlatform = "Win32"; break; - case GLFW_PLATFORM_COCOA: glfwPlatform = "Cocoa"; break; - case GLFW_PLATFORM_WAYLAND: glfwPlatform = "Wayland"; break; - case GLFW_PLATFORM_X11: glfwPlatform = "X11"; break; - case GLFW_PLATFORM_NULL: glfwPlatform = "Null"; break; - default: break; - } -#endif - - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (GLFW - %s): Initialized successfully", glfwPlatform); - - return 0; -} - -// Close platform -void ClosePlatform(void) -{ - glfwDestroyWindow(platform.handle); - glfwTerminate(); - -#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) - timeEndPeriod(1); // Restore time period -#endif -} - -// GLFW3 Error Callback, runs on GLFW3 error -static void ErrorCallback(int error, const char *description) -{ - TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description); -} - -// GLFW3 WindowSize Callback, runs when window is resizedLastFrame -// NOTE: Window resizing not enabled by default, use SetConfigFlags() -static void WindowSizeCallback(GLFWwindow *window, int width, int height) -{ - // WARNING: On window minimization, callback is called, - // but we don't want to change internal screen values, it breaks things - if ((width == 0) || (height == 0)) return; - - // Reset viewport and projection matrix for new size - SetupViewport(width, height); - - CORE.Window.currentFbo.width = width; - CORE.Window.currentFbo.height = height; - CORE.Window.resizedLastFrame = true; - - if (IsWindowFullscreen()) return; - - // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) - { - width = (int)(width/GetWindowScaleDPI().x); - height = (int)(height/GetWindowScaleDPI().y); - } - - // Set render size - CORE.Window.render.width = width; - CORE.Window.render.height = height; - - // Set current screen size - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - - // WARNING: If using a render texture, it is not scaled to new size -} -static void WindowPosCallback(GLFWwindow* window, int x, int y) -{ - // Set current window position - CORE.Window.position.x = x; - CORE.Window.position.y = y; -} -static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) -{ - CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f); -} - -// GLFW3 WindowIconify Callback, runs when window is minimized/restored -static void WindowIconifyCallback(GLFWwindow *window, int iconified) -{ - if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified - else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored -} - -// GLFW3 WindowMaximize Callback, runs when window is maximized/restored -static void WindowMaximizeCallback(GLFWwindow *window, int maximized) -{ - if (maximized) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized - else CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored -} - -// GLFW3 WindowFocus Callback, runs when window get/lose focus -static void WindowFocusCallback(GLFWwindow *window, int focused) -{ - if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused - else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus -} - -// GLFW3 Window Drop Callback, runs when drop files into window -static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) -{ - if (count > 0) - { - // In case previous dropped filepaths have not been freed, we free them - if (CORE.Window.dropFileCount > 0) - { - for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); - - RL_FREE(CORE.Window.dropFilepaths); - - CORE.Window.dropFileCount = 0; - CORE.Window.dropFilepaths = NULL; - } - - // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy - CORE.Window.dropFileCount = count; - CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); - - for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) - { - CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[i], paths[i]); - } - } -} - -// GLFW3 Keyboard Callback, runs on key pressed -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) -{ - if (key < 0) return; // Security check, macOS fn key generates -1 - - // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 - // to work properly with our implementation (IsKeyDown/IsKeyUp checks) - if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; - else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; - else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; - - // WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys - if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) || - ((key == KEY_NUM_LOCK) && ((mods & GLFW_MOD_NUM_LOCK) > 0))) CORE.Input.Keyboard.currentKeyState[key] = 1; - - // Check if there is space available in the key queue - if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) - { - // Add character to the queue - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - - // Check the exit key to set close window - if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE); -} - -// GLFW3 Char Callback, get unicode codepoint value -static void CharCallback(GLFWwindow *window, unsigned int codepoint) -{ - //TRACELOG(LOG_DEBUG, "Char Callback: Codepoint: %i", codepoint); - - // NOTE: Registers any key down considering OS keyboard layout but - // does not detect action events, those should be managed by user... - // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 - // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char - - // Check if there is space available in the queue - if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) - { - // Add character to the queue - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint; - CORE.Input.Keyboard.charPressedQueueCount++; - } -} - -// GLFW3 Mouse Button Callback, runs on mouse button pressed -static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) -{ - // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, - // but future releases may add more actions (i.e. GLFW_REPEAT) - CORE.Input.Mouse.currentButtonState[button] = action; - CORE.Input.Touch.currentTouchState[button] = action; - -#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent = { 0 }; - - // Register touch actions - if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN; - else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP; - - // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback() - - // Assign a pointer ID - gestureEvent.pointId[0] = 0; - - // Register touch points count - gestureEvent.pointCount = 1; - - // Register touch points position, only one point registered - gestureEvent.position[0] = GetMousePosition(); - - // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures-system for processing - ProcessGestureEvent(gestureEvent); -#endif -} - -// GLFW3 Cursor Position Callback, runs on mouse move -static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) -{ - CORE.Input.Mouse.currentPosition.x = (float)x; - CORE.Input.Mouse.currentPosition.y = (float)y; - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - -#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent = { 0 }; - - gestureEvent.touchAction = TOUCH_ACTION_MOVE; - - // Assign a pointer ID - gestureEvent.pointId[0] = 0; - - // Register touch points count - gestureEvent.pointCount = 1; - - // Register touch points position, only one point registered - gestureEvent.position[0] = CORE.Input.Touch.position[0]; - - // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures-system for processing - ProcessGestureEvent(gestureEvent); -#endif -} - -// GLFW3 Scrolling Callback, runs on mouse wheel -static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) -{ - CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; -} - -// GLFW3 CursorEnter Callback, when cursor enters the window -static void CursorEnterCallback(GLFWwindow *window, int enter) -{ - if (enter) CORE.Input.Mouse.cursorOnScreen = true; - else CORE.Input.Mouse.cursorOnScreen = false; -} - -// GLFW3 Joystick Connected/Disconnected Callback -static void JoystickCallback(int jid, int event) -{ - if (event == GLFW_CONNECTED) - { - // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH, - // we can get a not-NULL terminated string, so, we clean destination and only copy up to -1 - memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH); - strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1); - } - else if (event == GLFW_DISCONNECTED) - { - memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH); - } -} - -#ifdef _WIN32 -# define WIN32_CLIPBOARD_IMPLEMENTATION -# include "../external/win32_clipboard.h" -#endif -// EOF diff --git a/raylib/platforms/rcore_desktop_rgfw.c b/raylib/platforms/rcore_desktop_rgfw.c deleted file mode 100644 index a1694af..0000000 --- a/raylib/platforms/rcore_desktop_rgfw.c +++ /dev/null @@ -1,1425 +0,0 @@ -/********************************************************************************************** -* -* rcore_desktop_rgfw - Functions to manage window, graphics device and inputs -* -* PLATFORM: RGFW -* - Windows (Win32, Win64) -* - Linux (X11/Wayland desktop mode) -* - MacOS (Cocoa) -* - HTML5 (Emscripten) -* - Others (untested) -* -* LIMITATIONS: -* - TODO -* -* POSSIBLE IMPROVEMENTS: -* - TODO -* -* ADDITIONAL NOTES: -* - TRACELOG() function is located in raylib [utils] module -* -* CONFIGURATION: -* #define RCORE_PLATFORM_RGFW -* Custom flag for rcore on target platform RGFW -* -* DEPENDENCIES: -* - RGFW.h (main library): Windowing and inputs management -* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5), Colleague Riley and contributors -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */ -#include "raylib.h" -#include "../rcore.c" -#endif - -#if defined(PLATFORM_WEB_RGFW) -#define RGFW_NO_GL_HEADER -#endif - -#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(PLATFORM_WEB_RGFW) - #define RGFW_OPENGL_ES2 -#endif - -void ShowCursor(void); -void CloseWindow(void); - -#if defined(__linux__) - #define _INPUT_EVENT_CODES_H -#endif - -#if defined(__unix__) || defined(__linux__) - #define _XTYPEDEF_FONT -#endif - -#define RGFW_IMPLEMENTATION - -#if defined(_WIN32) || defined(_WIN64) - #define WIN32_LEAN_AND_MEAN - #define Rectangle rectangle_win32 - #define CloseWindow CloseWindow_win32 - #define ShowCursor __imp_ShowCursor - #define _APISETSTRING_ - - #undef MAX_PATH - - __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); -#endif - -#if defined(__APPLE__) - #define Point NSPOINT - #define Size NSSIZE -#endif - -#define RGFW_ALLOC RL_MALLOC -#define RGFW_FREE RL_FREE -#define RGFW_CALLOC RL_CALLOC - -#include "../external/RGFW.h" - -#if defined(_WIN32) || defined(_WIN64) - #undef DrawText - #undef ShowCursor - #undef CloseWindow - #undef Rectangle - - #undef MAX_PATH - #define MAX_PATH 1025 -#endif - -#if defined(__APPLE__) - #undef Point - #undef Size -#endif - -#include -#include // Required for: strcmp() - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef struct { - RGFW_window *window; // Native display device (physical screen connection) - RGFW_monitor mon; -} PlatformData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context - -static PlatformData platform = { 0 }; // Platform specific - -static bool RGFW_disableCursor = false; - -static const unsigned short keyMappingRGFW[] = { - [RGFW_keyNULL] = KEY_NULL, - [RGFW_return] = KEY_ENTER, - [RGFW_return] = KEY_ENTER, - [RGFW_apostrophe] = KEY_APOSTROPHE, - [RGFW_comma] = KEY_COMMA, - [RGFW_minus] = KEY_MINUS, - [RGFW_period] = KEY_PERIOD, - [RGFW_slash] = KEY_SLASH, - [RGFW_escape] = KEY_ESCAPE, - [RGFW_F1] = KEY_F1, - [RGFW_F2] = KEY_F2, - [RGFW_F3] = KEY_F3, - [RGFW_F4] = KEY_F4, - [RGFW_F5] = KEY_F5, - [RGFW_F6] = KEY_F6, - [RGFW_F7] = KEY_F7, - [RGFW_F8] = KEY_F8, - [RGFW_F9] = KEY_F9, - [RGFW_F10] = KEY_F10, - [RGFW_F11] = KEY_F11, - [RGFW_F12] = KEY_F12, - [RGFW_backtick] = KEY_GRAVE, - [RGFW_0] = KEY_ZERO, - [RGFW_1] = KEY_ONE, - [RGFW_2] = KEY_TWO, - [RGFW_3] = KEY_THREE, - [RGFW_4] = KEY_FOUR, - [RGFW_5] = KEY_FIVE, - [RGFW_6] = KEY_SIX, - [RGFW_7] = KEY_SEVEN, - [RGFW_8] = KEY_EIGHT, - [RGFW_9] = KEY_NINE, - [RGFW_equals] = KEY_EQUAL, - [RGFW_backSpace] = KEY_BACKSPACE, - [RGFW_tab] = KEY_TAB, - [RGFW_capsLock] = KEY_CAPS_LOCK, - [RGFW_shiftL] = KEY_LEFT_SHIFT, - [RGFW_controlL] = KEY_LEFT_CONTROL, - [RGFW_altL] = KEY_LEFT_ALT, - [RGFW_superL] = KEY_LEFT_SUPER, - #ifndef RGFW_MACOS - [RGFW_shiftR] = KEY_RIGHT_SHIFT, - [RGFW_controlR] = KEY_RIGHT_CONTROL, - [RGFW_altR] = KEY_RIGHT_ALT, - [RGFW_superR] = KEY_RIGHT_SUPER, - #endif - [RGFW_space] = KEY_SPACE, - - [RGFW_a] = KEY_A, - [RGFW_b] = KEY_B, - [RGFW_c] = KEY_C, - [RGFW_d] = KEY_D, - [RGFW_e] = KEY_E, - [RGFW_f] = KEY_F, - [RGFW_g] = KEY_G, - [RGFW_h] = KEY_H, - [RGFW_i] = KEY_I, - [RGFW_j] = KEY_J, - [RGFW_k] = KEY_K, - [RGFW_l] = KEY_L, - [RGFW_m] = KEY_M, - [RGFW_n] = KEY_N, - [RGFW_o] = KEY_O, - [RGFW_p] = KEY_P, - [RGFW_q] = KEY_Q, - [RGFW_r] = KEY_R, - [RGFW_s] = KEY_S, - [RGFW_t] = KEY_T, - [RGFW_u] = KEY_U, - [RGFW_v] = KEY_V, - [RGFW_w] = KEY_W, - [RGFW_x] = KEY_X, - [RGFW_y] = KEY_Y, - [RGFW_z] = KEY_Z, - [RGFW_bracket] = KEY_LEFT_BRACKET, - [RGFW_backSlash] = KEY_BACKSLASH, - [RGFW_closeBracket] = KEY_RIGHT_BRACKET, - [RGFW_semicolon] = KEY_SEMICOLON, - [RGFW_insert] = KEY_INSERT, - [RGFW_home] = KEY_HOME, - [RGFW_pageUp] = KEY_PAGE_UP, - [RGFW_delete] = KEY_DELETE, - [RGFW_end] = KEY_END, - [RGFW_pageDown] = KEY_PAGE_DOWN, - [RGFW_right] = KEY_RIGHT, - [RGFW_left] = KEY_LEFT, - [RGFW_down] = KEY_DOWN, - [RGFW_up] = KEY_UP, - [RGFW_numLock] = KEY_NUM_LOCK, - [RGFW_KP_Slash] = KEY_KP_DIVIDE, - [RGFW_multiply] = KEY_KP_MULTIPLY, - [RGFW_KP_Minus] = KEY_KP_SUBTRACT, - [RGFW_KP_Return] = KEY_KP_ENTER, - [RGFW_KP_1] = KEY_KP_1, - [RGFW_KP_2] = KEY_KP_2, - [RGFW_KP_3] = KEY_KP_3, - [RGFW_KP_4] = KEY_KP_4, - [RGFW_KP_5] = KEY_KP_5, - [RGFW_KP_6] = KEY_KP_6, - [RGFW_KP_7] = KEY_KP_7, - [RGFW_KP_8] = KEY_KP_8, - [RGFW_KP_9] = KEY_KP_9, - [RGFW_KP_0] = KEY_KP_0, - [RGFW_KP_Period] = KEY_KP_DECIMAL, - [RGFW_scrollLock] = KEY_SCROLL_LOCK, -}; - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -int InitPlatform(void); // Initialize platform (graphics, inputs and more) -bool InitGraphicsDevice(void); // Initialize graphics device - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -// NOTE: Functions declaration is provided by raylib.h - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Window and Graphics Device -//---------------------------------------------------------------------------------- - -// Check if application should close -bool WindowShouldClose(void) -{ - if (CORE.Window.shouldClose == false) - CORE.Window.shouldClose = RGFW_window_shouldClose(platform.window); - if (CORE.Window.ready) return CORE.Window.shouldClose; - else return true; -} - -// Toggle fullscreen mode -void ToggleFullscreen(void) -{ - if (!CORE.Window.fullscreen) - { - // Store previous window position (in case we exit fullscreen) - CORE.Window.previousPosition = CORE.Window.position; - CORE.Window.previousScreen = CORE.Window.screen; - - platform.mon = RGFW_window_getMonitor(platform.window); - CORE.Window.fullscreen = true; - CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - - RGFW_monitor_scaleToWindow(platform.mon, platform.window); - RGFW_window_setFullscreen(platform.window, 1); - } - else - { - CORE.Window.fullscreen = false; - CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - - if (platform.mon.mode.area.w) - { - RGFW_monitor monitor = RGFW_window_getMonitor(platform.window); - RGFW_monitor_requestMode(monitor, platform.mon.mode, RGFW_monitorScale); - - platform.mon.mode.area.w = 0; - } - - // we update the window position right away - CORE.Window.position = CORE.Window.previousPosition; - RGFW_window_setFullscreen(platform.window, 0); - RGFW_window_move(platform.window, RGFW_POINT(CORE.Window.position.x, CORE.Window.position.y)); - RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height)); - } - - // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) - // NOTE: V-Sync can be enabled by graphic driver configuration - if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1); -} - -// Toggle borderless windowed mode -void ToggleBorderlessWindowed(void) -{ - if (CORE.Window.fullscreen) - { - CORE.Window.previousPosition = CORE.Window.position; - CORE.Window.previousScreen = CORE.Window.screen; - - RGFW_window_setBorder(platform.window, 0); - - RGFW_monitor mon = RGFW_window_getMonitor(platform.window); - RGFW_window_resize(platform.window, mon.mode.area); - } - else - { - RGFW_window_setBorder(platform.window, 1); - - CORE.Window.position = CORE.Window.previousPosition; - RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height)); - } - - CORE.Window.fullscreen = !CORE.Window.fullscreen; -} - -// Set window state: maximized, if resizable -void MaximizeWindow(void) -{ - RGFW_window_maximize(platform.window); -} - -// Set window state: minimized -void MinimizeWindow(void) -{ - RGFW_window_minimize(platform.window); -} - -// Restore window from being minimized/maximized -void RestoreWindow(void) -{ - if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window); - - RGFW_window_restore(platform.window); -} - -// Set window configuration state using flags -void SetWindowState(unsigned int flags) -{ - if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead"); - - CORE.Window.flags |= flags; - - if (flags & FLAG_VSYNC_HINT) - { - RGFW_window_swapInterval(platform.window, 1); - } - if (flags & FLAG_FULLSCREEN_MODE) - { - if (!CORE.Window.fullscreen) ToggleFullscreen(); - } - if (flags & FLAG_WINDOW_RESIZABLE) - { - RGFW_window_setMaxSize(platform.window, RGFW_AREA(0, 0)); - RGFW_window_setMinSize(platform.window, RGFW_AREA(0, 0)); - } - if (flags & FLAG_WINDOW_UNDECORATED) - { - RGFW_window_setBorder(platform.window, 0); - } - if (flags & FLAG_WINDOW_HIDDEN) - { - RGFW_window_hide(platform.window); - } - if (flags & FLAG_WINDOW_MINIMIZED) - { - RGFW_window_minimize(platform.window); - } - if (flags & FLAG_WINDOW_MAXIMIZED) - { - RGFW_window_maximize(platform.window); - } - if (flags & FLAG_WINDOW_UNFOCUSED) - { - CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; - platform.window->_flags &= ~RGFW_windowFocusOnShow; - RGFW_window_setFlags(platform.window, platform.window->_flags); - } - if (flags & FLAG_WINDOW_TOPMOST) - { - RGFW_window_setFloating(platform.window, RGFW_TRUE); - } - if (flags & FLAG_WINDOW_ALWAYS_RUN) - { - CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN; - } - if (flags & FLAG_WINDOW_TRANSPARENT) - { - TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); - } - if (flags & FLAG_WINDOW_HIGHDPI) - { - TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); - } - if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) - { - RGFW_window_setMousePassthrough(platform.window, 1); - } - if (flags & FLAG_BORDERLESS_WINDOWED_MODE) - { - ToggleBorderlessWindowed(); - } - if (flags & FLAG_MSAA_4X_HINT) - { - RGFW_setGLHint(RGFW_glSamples, 4); - } - if (flags & FLAG_INTERLACED_HINT) - { - TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); - } -} - -// Clear window configuration state flags -void ClearWindowState(unsigned int flags) -{ - CORE.Window.flags &= ~flags; - - if (flags & FLAG_VSYNC_HINT) - { - RGFW_window_swapInterval(platform.window, 0); - } - if (flags & FLAG_FULLSCREEN_MODE) - { - if (CORE.Window.fullscreen) ToggleFullscreen(); - } - if (flags & FLAG_WINDOW_RESIZABLE) - { - RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); - RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); - } - if (flags & FLAG_WINDOW_UNDECORATED) - { - RGFW_window_setBorder(platform.window, 1); - } - if (flags & FLAG_WINDOW_HIDDEN) - { - if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window); - - RGFW_window_show(platform.window); - } - if (flags & FLAG_WINDOW_MINIMIZED) - { - if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window); - - RGFW_window_restore(platform.window); - } - if (flags & FLAG_WINDOW_MAXIMIZED) - { - if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window); - - RGFW_window_restore(platform.window); - } - if (flags & FLAG_WINDOW_UNFOCUSED) - { - RGFW_window_setFlags(platform.window, platform.window->_flags | RGFW_windowFocusOnShow); - CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; - } - if (flags & FLAG_WINDOW_TOPMOST) - { - RGFW_window_setFloating(platform.window, RGFW_FALSE); - } - if (flags & FLAG_WINDOW_ALWAYS_RUN) - { - CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN; - } - if (flags & FLAG_WINDOW_TRANSPARENT) - { - TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); - } - if (flags & FLAG_WINDOW_HIGHDPI) - { - TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); - } - if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) - { - RGFW_window_setMousePassthrough(platform.window, 0); - } - if (flags & FLAG_BORDERLESS_WINDOWED_MODE) - { - if (CORE.Window.fullscreen) ToggleBorderlessWindowed(); - } - if (flags & FLAG_MSAA_4X_HINT) - { - RGFW_setGLHint(RGFW_glSamples, 0); - } - if (flags & FLAG_INTERLACED_HINT) - { - TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); - } -} - -int RGFW_formatToChannels(int format) -{ - switch (format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - case PIXELFORMAT_UNCOMPRESSED_R16: // 16 bpp (1 channel - half float) - case PIXELFORMAT_UNCOMPRESSED_R32: // 32 bpp (1 channel - float) - return 1; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: // 8*2 bpp (2 channels) - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: // 16 bpp - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // 24 bpp - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: // 16 bpp (1 bit alpha) - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: // 16 bpp (4 bit alpha) - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: // 32 bpp - return 2; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: // 32*3 bpp (3 channels - float) - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: // 16*3 bpp (3 channels - half float) - case PIXELFORMAT_COMPRESSED_DXT1_RGB: // 4 bpp (no alpha) - case PIXELFORMAT_COMPRESSED_ETC1_RGB: // 4 bpp - case PIXELFORMAT_COMPRESSED_ETC2_RGB: // 4 bpp - case PIXELFORMAT_COMPRESSED_PVRT_RGB: // 4 bpp - return 3; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: // 32*4 bpp (4 channels - float) - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: // 16*4 bpp (4 channels - half float) - case PIXELFORMAT_COMPRESSED_DXT1_RGBA: // 4 bpp (1 bit alpha) - case PIXELFORMAT_COMPRESSED_DXT3_RGBA: // 8 bpp - case PIXELFORMAT_COMPRESSED_DXT5_RGBA: // 8 bpp - case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: // 8 bpp - case PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 4 bpp - case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 8 bpp - case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 2 bpp - return 4; - default: return 4; - } -} - -// Set icon for window -void SetWindowIcon(Image image) -{ - RGFW_window_setIcon(platform.window, image.data, RGFW_AREA(image.width, image.height), RGFW_formatToChannels(image.format)); -} - -// Set icon for window -void SetWindowIcons(Image *images, int count) -{ - if ((images == NULL) || (count <= 0)) - { - RGFW_window_setIcon(platform.window, NULL, RGFW_AREA(0, 0), 0); - } - else - { - Image *bigIcon = NULL; - Image *smallIcon = NULL; - - for (int i = 0; i < count; i++) - { - if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i]; - if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i]; - } - - if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow); - if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar); - } -} - -// Set title for window -void SetWindowTitle(const char *title) -{ - RGFW_window_setName(platform.window, (char *)title); - CORE.Window.title = title; -} - -// Set window position on screen (windowed mode) -void SetWindowPosition(int x, int y) -{ - RGFW_window_move(platform.window, RGFW_POINT(x, y)); -} - -// Set monitor for the current window -void SetWindowMonitor(int monitor) -{ - RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]); -} - -// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMinSize(int width, int height) -{ - RGFW_window_setMinSize(platform.window, RGFW_AREA(width, height)); - CORE.Window.screenMin.width = width; - CORE.Window.screenMin.height = height; -} - -// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMaxSize(int width, int height) -{ - RGFW_window_setMaxSize(platform.window, RGFW_AREA(width, height)); - CORE.Window.screenMax.width = width; - CORE.Window.screenMax.height = height; -} - -// Set window dimensions -void SetWindowSize(int width, int height) -{ - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - - RGFW_window_resize(platform.window, RGFW_AREA(width, height)); -} - -// Set window opacity, value opacity is between 0.0 and 1.0 -void SetWindowOpacity(float opacity) -{ - RGFW_window_setOpacity(platform.window, opacity); -} - -// Set window focused -void SetWindowFocused(void) -{ - RGFW_window_focus(platform.window); -} - -// Get native window handle -void *GetWindowHandle(void) -{ - if (platform.window == NULL) return NULL; -#ifdef RGFW_WASM - return (void *)platform.window->src.ctx; -#else - return (void *)platform.window->src.window; -#endif -} - -// Get number of monitors -int GetMonitorCount(void) -{ - #define MAX_MONITORS_SUPPORTED 6 - - int count = MAX_MONITORS_SUPPORTED; - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - for (int i = 0; i < 6; i++) - { - if (!mons[i].x && !mons[i].y && !mons[i].mode.area.w && mons[i].mode.area.h) - { - count = i; - break; - } - } - - return count; -} - -// Get current monitor where window is placed -int GetCurrentMonitor(void) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - RGFW_monitor mon = { 0 }; - - if (platform.window) mon = RGFW_window_getMonitor(platform.window); - else mon = RGFW_getPrimaryMonitor(); - - for (int i = 0; i < 6; i++) - { - if ((mons[i].x == mon.x) && (mons[i].y == mon.y)) return i; - } - - return 0; -} - -// Get selected monitor position -Vector2 GetMonitorPosition(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y }; -} - -// Get selected monitor width (currently used by monitor) -int GetMonitorWidth(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return mons[monitor].mode.area.w; -} - -// Get selected monitor height (currently used by monitor) -int GetMonitorHeight(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return mons[monitor].mode.area.h; -} - -// Get selected monitor physical width in millimetres -int GetMonitorPhysicalWidth(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return mons[monitor].physW; -} - -// Get selected monitor physical height in millimetres -int GetMonitorPhysicalHeight(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return (int)mons[monitor].physH; -} - -// Get selected monitor refresh rate -int GetMonitorRefreshRate(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return (int)mons[monitor].mode.refreshRate; -} - -// Get the human-readable, UTF-8 encoded name of the selected monitor -const char *GetMonitorName(int monitor) -{ - RGFW_monitor *mons = RGFW_getMonitors(NULL); - - return mons[monitor].name; -} - -// Get window position XY on monitor -Vector2 GetWindowPosition(void) -{ - if (platform.window == NULL) return (Vector2){ 0.0f, 0.0f }; - return (Vector2){ (float)platform.window->r.x, (float)platform.window->r.y }; -} - -// Get window scale DPI factor for current monitor -Vector2 GetWindowScaleDPI(void) -{ - RGFW_monitor monitor = { 0 }; - - if (platform.window) monitor = RGFW_window_getMonitor(platform.window); - else monitor = RGFW_getPrimaryMonitor(); - - return (Vector2){ monitor.scaleX, monitor.scaleX }; -} - -// Set clipboard text content -void SetClipboardText(const char *text) -{ - RGFW_writeClipboard(text, strlen(text)); -} - -// Get clipboard text content -// NOTE: returned string is allocated and freed by RGFW -const char *GetClipboardText(void) -{ - return RGFW_readClipboard(NULL); -} - -#if defined(SUPPORT_CLIPBOARD_IMAGE) -#if defined(_WIN32) - #define WIN32_CLIPBOARD_IMPLEMENTATION - #define WINUSER_ALREADY_INCLUDED - #define WINBASE_ALREADY_INCLUDED - #define WINGDI_ALREADY_INCLUDED - #include "../external/win32_clipboard.h" -#endif -#endif - -// Get clipboard image -Image GetClipboardImage(void) -{ - Image image = { 0 }; - unsigned long long int dataSize = 0; - void *fileData = NULL; - -#if defined(SUPPORT_CLIPBOARD_IMAGE) -#if defined(_WIN32) - int width = 0; - int height = 0; - fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize); - - if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data"); - else image = LoadImageFromMemory(".bmp", fileData, dataSize); -#else - TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS"); -#endif -#endif // SUPPORT_CLIPBOARD_IMAGE - - return image; -} - -// Show mouse cursor -void ShowCursor(void) -{ - RGFW_window_showMouse(platform.window, true); - CORE.Input.Mouse.cursorHidden = false; -} - -// Hides mouse cursor -void HideCursor(void) -{ - RGFW_window_showMouse(platform.window, false); - CORE.Input.Mouse.cursorHidden = true; -} - -// Enables cursor (unlock cursor) -void EnableCursor(void) -{ - RGFW_disableCursor = false; - RGFW_window_mouseUnhold(platform.window); - - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - RGFW_window_showMouse(platform.window, true); - CORE.Input.Mouse.cursorHidden = false; -} - -// Disables cursor (lock cursor) -void DisableCursor(void) -{ - RGFW_disableCursor = true; - RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0)); - HideCursor(); -} - -// Swap back buffer with front buffer (screen drawing) -void SwapScreenBuffer(void) -{ - RGFW_window_swapBuffers(platform.window); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Misc -//---------------------------------------------------------------------------------- - -// Get elapsed time measure in seconds since InitTimer() -double GetTime(void) -{ - return RGFW_getTime(); -} - -// Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 -void OpenURL(const char *url) -{ - // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else - { - // TODO: Open URL implementation - } -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Inputs -//---------------------------------------------------------------------------------- - -// Set internal gamepad mappings -int SetGamepadMappings(const char *mappings) -{ - TRACELOG(LOG_WARNING, "SetGamepadMappings() unsupported on target platform"); - return 0; -} - -// Set gamepad vibration -void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) -{ - TRACELOG(LOG_WARNING, "SetGamepadVibration() unsupported on target platform"); -} - -// Set mouse position XY -void SetMousePosition(int x, int y) -{ - RGFW_window_moveMouse(platform.window, RGFW_POINT(x, y)); - CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; -} - -// Set mouse cursor -void SetMouseCursor(int cursor) -{ - RGFW_window_setMouseStandard(platform.window, cursor); -} - -// Get physical key name. -const char *GetKeyName(int key) -{ - TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform"); - - return ""; -} - -static KeyboardKey ConvertScancodeToKey(u32 keycode); - -int RGFW_gpConvTable[18] = { - [RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP, - [RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, - [RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN, - [RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT, - [RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, - [RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1, - [RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, - [RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2, - [RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT, - [RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE, - [RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT, - [RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP, - [RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT, - [RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN, - [RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT, - [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB, - [RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB, -}; - -// Register all input events -void PollInputEvents(void) -{ -#if defined(SUPPORT_GESTURES_SYSTEM) - // NOTE: Gestures update must be called every frame to reset gestures correctly - // because ProcessGestureEvent() is just called on an event, not every frame - UpdateGestures(); -#endif - - // Reset keys/chars pressed registered - CORE.Input.Keyboard.keyPressedQueueCount = 0; - CORE.Input.Keyboard.charPressedQueueCount = 0; - - // Reset mouse wheel - CORE.Input.Mouse.currentWheelMove.x = 0; - CORE.Input.Mouse.currentWheelMove.y = 0; - - // Register previous mouse position - - // Reset last gamepad button/axis registered state - for (int i = 0; (i < 4) && (i < MAX_GAMEPADS); i++) - { - // Check if gamepad is available - if (CORE.Input.Gamepad.ready[i]) - { - // Register previous gamepad button states - for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) - { - CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; - } - } - } - - // Register previous touch states - for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; - - // Map touch position to mouse position for convenience - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - - int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE - bool realTouch = false; // Flag to differentiate real touch gestures from mouse ones - - // Register previous keys states - // NOTE: Android supports up to 260 keys - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Register previous mouse states - for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; - - // Poll input events for current platform - //----------------------------------------------------------------------------- - CORE.Window.resizedLastFrame = false; - - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - if (platform.window->_flags & RGFW_HOLD_MOUSE) - { - CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; - CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f }; - } - else - { - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - } - - if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN))) - { - RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state - CORE.Time.previous = GetTime(); - } - - while (RGFW_window_checkEvent(platform.window)) - { - RGFW_event *event = &platform.window->event; - // All input events can be processed after polling - - switch (event->type) - { - case RGFW_mouseEnter: CORE.Input.Mouse.cursorOnScreen = true; break; - case RGFW_mouseLeave: CORE.Input.Mouse.cursorOnScreen = false; break; - case RGFW_quit: - event->type = 0; - CORE.Window.shouldClose = true; - return; - case RGFW_DND: // Dropped file - { - for (int i = 0; i < event->droppedFilesCount; i++) - { - if (CORE.Window.dropFileCount == 0) - { - // When a new file is dropped, we reserve a fixed number of slots for all possible dropped files - // at the moment we limit the number of drops at once to 1024 files but this behaviour should probably be reviewed - // TODO: Pointers should probably be reallocated for any new file added... - CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *)); - - CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]); - - CORE.Window.dropFileCount++; - } - else if (CORE.Window.dropFileCount < 1024) - { - CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]); - - CORE.Window.dropFileCount++; - } - else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!"); - } - } break; - - // Window events are also polled (Minimized, maximized, close...) - case RGFW_windowResized: - { - SetupViewport(platform.window->r.w, platform.window->r.h); - - // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) - { - CORE.Window.screen.width = (int)(platform.window->r.w / GetWindowScaleDPI().x); - CORE.Window.screen.height = (int)(platform.window->r.h / GetWindowScaleDPI().y); - } - else - { - CORE.Window.screen.width = platform.window->r.w; - CORE.Window.screen.height = platform.window->r.h; - } - - CORE.Window.currentFbo.width = platform.window->r.w; - CORE.Window.currentFbo.height = platform.window->r.h; - CORE.Window.resizedLastFrame = true; - } break; - case RGFW_windowMaximized: - { - CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized - } break; - case RGFW_windowMinimized: - { - CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified - } break; - case RGFW_windowRestored: - { - if (RGFW_window_isMaximized(platform.window)) - CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored - if (RGFW_window_isMinimized(platform.window)) - CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored - } break; - case RGFW_windowMoved: - { - CORE.Window.position.x = platform.window->r.x; - CORE.Window.position.y = platform.window->r.x; - } break; - - // Keyboard events - case RGFW_keyPressed: - { - KeyboardKey key = ConvertScancodeToKey(event->key); - if (key != KEY_NULL) - { - // If key was up, add it to the key pressed queue - if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)) - { - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - - CORE.Input.Keyboard.currentKeyState[key] = 1; - } - - // TODO: Put exitKey verification outside the switch? - if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) - { - CORE.Window.shouldClose = true; - } - - // NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int) - // Check if there is space available in the queue - if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) - { - // Add character (codepoint) to the queue - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = event->keyChar; - CORE.Input.Keyboard.charPressedQueueCount++; - } - } break; - case RGFW_keyReleased: - { - KeyboardKey key = ConvertScancodeToKey(event->key); - if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0; - } break; - - // Check mouse events - case RGFW_mouseButtonPressed: - { - if ((event->button == RGFW_mouseScrollUp) || (event->button == RGFW_mouseScrollDown)) - { - CORE.Input.Mouse.currentWheelMove.y = event->scroll; - break; - } - else CORE.Input.Mouse.currentWheelMove.y = 0; - - int btn = event->button; - if (btn == RGFW_mouseLeft) btn = 1; - else if (btn == RGFW_mouseRight) btn = 2; - else if (btn == RGFW_mouseMiddle) btn = 3; - - CORE.Input.Mouse.currentButtonState[btn - 1] = 1; - CORE.Input.Touch.currentTouchState[btn - 1] = 1; - - touchAction = 1; - } break; - case RGFW_mouseButtonReleased: - { - if ((event->button == RGFW_mouseScrollUp) || (event->button == RGFW_mouseScrollDown)) - { - CORE.Input.Mouse.currentWheelMove.y = event->scroll; - break; - } - else CORE.Input.Mouse.currentWheelMove.y = 0; - - int btn = event->button; - if (btn == RGFW_mouseLeft) btn = 1; - else if (btn == RGFW_mouseRight) btn = 2; - else if (btn == RGFW_mouseMiddle) btn = 3; - - CORE.Input.Mouse.currentButtonState[btn - 1] = 0; - CORE.Input.Touch.currentTouchState[btn - 1] = 0; - - touchAction = 0; - } break; - case RGFW_mousePosChanged: - { - if (platform.window->_flags & RGFW_HOLD_MOUSE) - { - CORE.Input.Mouse.currentPosition.x += (float)event->vector.x; - CORE.Input.Mouse.currentPosition.y += (float)event->vector.y; - } - else - { - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - CORE.Input.Mouse.currentPosition.x = (float)event->point.x; - CORE.Input.Mouse.currentPosition.y = (float)event->point.y; - } - - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - touchAction = 2; - } break; - case RGFW_gamepadConnected: - { - CORE.Input.Gamepad.ready[platform.window->event.gamepad] = true; - CORE.Input.Gamepad.axisCount[platform.window->event.gamepad] = platform.window->event.axisesCount; - CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; - CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; - - strcpy(CORE.Input.Gamepad.name[platform.window->event.gamepad], RGFW_getGamepadName(platform.window, platform.window->event.gamepad)); - } break; - case RGFW_gamepadDisconnected: - { - CORE.Input.Gamepad.ready[platform.window->event.gamepad] = false; - } break; - case RGFW_gamepadButtonPressed: - { - int button = RGFW_gpConvTable[event->button]; - - if (button >= 0) - { - CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = 1; - CORE.Input.Gamepad.lastButtonPressed = button; - } - } break; - case RGFW_gamepadButtonReleased: - { - int button = RGFW_gpConvTable[event->button]; - - CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = 0; - if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; - } break; - case RGFW_gamepadAxisMove: - { - int axis = -1; - float value = 0; - - switch(event->whichAxis) - { - case 0: - { - CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_X] = event->axis[0].x / 100.0f; - CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_Y] = event->axis[0].y / 100.0f; - } break; - case 1: - { - CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_X] = event->axis[1].x / 100.0f; - CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_Y] = event->axis[1].y / 100.0f; - } break; - case 2: axis = GAMEPAD_AXIS_LEFT_TRIGGER; - case 3: - { - if (axis == -1) axis = GAMEPAD_AXIS_RIGHT_TRIGGER; - - int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2; - int pressed = (value > 0.1f); - CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed; - - if (pressed) CORE.Input.Gamepad.lastButtonPressed = button; - else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; - } - default: break; - } - } break; - default: break; - } - -#if defined(SUPPORT_GESTURES_SYSTEM) - if (touchAction > -1) - { - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent = { 0 }; - - // Register touch actions - gestureEvent.touchAction = touchAction; - - // Assign a pointer ID - gestureEvent.pointId[0] = 0; - - // Register touch points count - gestureEvent.pointCount = 1; - - // Register touch points position, only one point registered - if (touchAction == 2 || realTouch) gestureEvent.position[0] = CORE.Input.Touch.position[0]; - else gestureEvent.position[0] = GetMousePosition(); - - // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures-system for processing - ProcessGestureEvent(gestureEvent); - - touchAction = -1; - } -#endif - } - //----------------------------------------------------------------------------- -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- - -// Initialize platform: graphics, inputs and more -int InitPlatform(void) -{ - // Initialize RGFW internal global state, only required systems - unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND; - - // Check window creation flags - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) - { - CORE.Window.fullscreen = true; - flags |= RGFW_windowFullscreen; - } - - if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) - { - CORE.Window.fullscreen = true; - flags |= RGFW_windowedFullscreen; - } - - if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= RGFW_windowNoBorder; - if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) flags |= RGFW_windowNoResize; - if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= RGFW_windowTransparent; - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) flags |= RGFW_windowFullscreen; - if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) flags |= RGFW_windowHide; - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= RGFW_windowMaximize; - - // NOTE: Some OpenGL context attributes must be set before window creation - // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_21) - { - RGFW_setGLHint(RGFW_glMajor, 2); - RGFW_setGLHint(RGFW_glMinor, 1); - } - else if (rlGetVersion() == RL_OPENGL_33) - { - RGFW_setGLHint(RGFW_glMajor, 3); - RGFW_setGLHint(RGFW_glMinor, 3); - } - else if (rlGetVersion() == RL_OPENGL_43) - { - RGFW_setGLHint(RGFW_glMajor, 4); - RGFW_setGLHint(RGFW_glMinor, 3); - } - - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLHint(RGFW_glSamples, 4); - - if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) flags |= RGFW_windowFocusOnShow | RGFW_windowFocus; - - platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags); - platform.mon.mode.area.w = 0; - - if (platform.window != NULL) - { - // NOTE: RGFW's exit key is distinct from raylib's exit key (which can - // be set with SetExitKey()) and defaults to Escape - platform.window->exitKey = RGFW_keyNULL; - } - -#ifndef PLATFORM_WEB_RGFW - RGFW_area screenSize = RGFW_getScreenSize(); - CORE.Window.display.width = screenSize.w; - CORE.Window.display.height = screenSize.h; -#else - CORE.Window.display.width = CORE.Window.screen.width; - CORE.Window.display.height = CORE.Window.screen.height; -#endif - // TODO: Is this needed by raylib now? - // If so, rcore_desktop_sdl should be updated too - //SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - - if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1); - RGFW_window_makeCurrent(platform.window); - - // Check surface and context activation - if (platform.window != NULL) - { - CORE.Window.ready = true; - - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.currentFbo.width = CORE.Window.render.width; - CORE.Window.currentFbo.height = CORE.Window.render.height; - } - else - { - TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device"); - return -1; - } - //---------------------------------------------------------------------------- - - // If everything work as expected, we can continue - CORE.Window.position.x = platform.window->r.x; - CORE.Window.position.y = platform.window->r.y; - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.currentFbo.width = CORE.Window.render.width; - CORE.Window.currentFbo.height = CORE.Window.render.height; - - TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); - TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); - TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); - TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); - - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - //---------------------------------------------------------------------------- - rlLoadExtensions((void *)RGFW_getProcAddress); - //---------------------------------------------------------------------------- - - // Initialize timing system - //---------------------------------------------------------------------------- - InitTimer(); - //---------------------------------------------------------------------------- - - // Initialize storage system - //---------------------------------------------------------------------------- - CORE.Storage.basePath = GetWorkingDirectory(); - //---------------------------------------------------------------------------- - -#if defined(RGFW_WAYLAND) - if (RGFW_useWaylandBool) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully"); - else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully"); -#elif defined(RGFW_X11) - #if defined(__APPLE__) - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (MacOS)): Initialized successfully"); - #else - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully"); - #endif -#elif defined (RGFW_WINDOWS) - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully"); -#elif defined(RGFW_WASM) - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully"); -#elif defined(RGFW_MACOS) - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully"); -#endif - - return 0; -} - -// Close platform -void ClosePlatform(void) -{ - RGFW_window_close(platform.window); -} - -// Keycode mapping -static KeyboardKey ConvertScancodeToKey(u32 keycode) -{ - if (keycode > sizeof(keyMappingRGFW)/sizeof(unsigned short)) return 0; - - return keyMappingRGFW[keycode]; -} diff --git a/raylib/platforms/rcore_desktop_sdl.c b/raylib/platforms/rcore_desktop_sdl.c deleted file mode 100644 index 6af1cb6..0000000 --- a/raylib/platforms/rcore_desktop_sdl.c +++ /dev/null @@ -1,2096 +0,0 @@ -/********************************************************************************************** -* -* rcore_desktop_sdl - Functions to manage window, graphics device and inputs -* -* PLATFORM: DESKTOP: SDL -* - Windows (Win32, Win64) -* - Linux (X11/Wayland desktop mode) -* - Others (not tested) -* -* LIMITATIONS: -* - Limitation 01 -* - Limitation 02 -* -* POSSIBLE IMPROVEMENTS: -* - Improvement 01 -* - Improvement 02 -* -* ADDITIONAL NOTES: -* - TRACELOG() function is located in raylib [utils] module -* -* CONFIGURATION: -* #define RCORE_PLATFORM_CUSTOM_FLAG -* Custom flag for rcore on target platform -not used- -* -* DEPENDENCIES: -* - SDL 2 or SDL 3 (main library): Windowing and inputs management -* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - - -#ifndef SDL_ENABLE_OLD_NAMES - #define SDL_ENABLE_OLD_NAMES // Just in case we're on SDL3, we need some in-between compatibily -#endif -#include "SDL.h" // SDL base library (window/rendered, input, timing... functionality) - -#if defined(GRAPHICS_API_OPENGL_ES2) - // It seems it does not need to be included to work - //#include "SDL_opengles2.h" -#else - #include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef MAX_CLIPBOARD_BUFFER_LENGTH - #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText() -#endif - -#if ((defined(SDL_MAJOR_VERSION) && (SDL_MAJOR_VERSION == 3)) && (defined(SDL_MINOR_VERSION) && (SDL_MINOR_VERSION >= 1))) - #ifndef PLATFORM_DESKTOP_SDL3 - #define PLATFORM_DESKTOP_SDL3 - #endif -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef struct { - SDL_Window *window; - SDL_GLContext glContext; - - SDL_GameController *gamepad[MAX_GAMEPADS]; - SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids - SDL_Cursor *cursor; - bool cursorRelative; -} PlatformData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context - -static PlatformData platform = { 0 }; // Platform specific data - -//---------------------------------------------------------------------------------- -// Local Variables Definition -//---------------------------------------------------------------------------------- -#define SCANCODE_MAPPED_NUM 232 -static const KeyboardKey mapScancodeToKey[SCANCODE_MAPPED_NUM] = { - KEY_NULL, // SDL_SCANCODE_UNKNOWN - 0, - 0, - 0, - KEY_A, // SDL_SCANCODE_A - KEY_B, // SDL_SCANCODE_B - KEY_C, // SDL_SCANCODE_C - KEY_D, // SDL_SCANCODE_D - KEY_E, // SDL_SCANCODE_E - KEY_F, // SDL_SCANCODE_F - KEY_G, // SDL_SCANCODE_G - KEY_H, // SDL_SCANCODE_H - KEY_I, // SDL_SCANCODE_I - KEY_J, // SDL_SCANCODE_J - KEY_K, // SDL_SCANCODE_K - KEY_L, // SDL_SCANCODE_L - KEY_M, // SDL_SCANCODE_M - KEY_N, // SDL_SCANCODE_N - KEY_O, // SDL_SCANCODE_O - KEY_P, // SDL_SCANCODE_P - KEY_Q, // SDL_SCANCODE_Q - KEY_R, // SDL_SCANCODE_R - KEY_S, // SDL_SCANCODE_S - KEY_T, // SDL_SCANCODE_T - KEY_U, // SDL_SCANCODE_U - KEY_V, // SDL_SCANCODE_V - KEY_W, // SDL_SCANCODE_W - KEY_X, // SDL_SCANCODE_X - KEY_Y, // SDL_SCANCODE_Y - KEY_Z, // SDL_SCANCODE_Z - KEY_ONE, // SDL_SCANCODE_1 - KEY_TWO, // SDL_SCANCODE_2 - KEY_THREE, // SDL_SCANCODE_3 - KEY_FOUR, // SDL_SCANCODE_4 - KEY_FIVE, // SDL_SCANCODE_5 - KEY_SIX, // SDL_SCANCODE_6 - KEY_SEVEN, // SDL_SCANCODE_7 - KEY_EIGHT, // SDL_SCANCODE_8 - KEY_NINE, // SDL_SCANCODE_9 - KEY_ZERO, // SDL_SCANCODE_0 - KEY_ENTER, // SDL_SCANCODE_RETURN - KEY_ESCAPE, // SDL_SCANCODE_ESCAPE - KEY_BACKSPACE, // SDL_SCANCODE_BACKSPACE - KEY_TAB, // SDL_SCANCODE_TAB - KEY_SPACE, // SDL_SCANCODE_SPACE - KEY_MINUS, // SDL_SCANCODE_MINUS - KEY_EQUAL, // SDL_SCANCODE_EQUALS - KEY_LEFT_BRACKET, // SDL_SCANCODE_LEFTBRACKET - KEY_RIGHT_BRACKET, // SDL_SCANCODE_RIGHTBRACKET - KEY_BACKSLASH, // SDL_SCANCODE_BACKSLASH - 0, // SDL_SCANCODE_NONUSHASH - KEY_SEMICOLON, // SDL_SCANCODE_SEMICOLON - KEY_APOSTROPHE, // SDL_SCANCODE_APOSTROPHE - KEY_GRAVE, // SDL_SCANCODE_GRAVE - KEY_COMMA, // SDL_SCANCODE_COMMA - KEY_PERIOD, // SDL_SCANCODE_PERIOD - KEY_SLASH, // SDL_SCANCODE_SLASH - KEY_CAPS_LOCK, // SDL_SCANCODE_CAPSLOCK - KEY_F1, // SDL_SCANCODE_F1 - KEY_F2, // SDL_SCANCODE_F2 - KEY_F3, // SDL_SCANCODE_F3 - KEY_F4, // SDL_SCANCODE_F4 - KEY_F5, // SDL_SCANCODE_F5 - KEY_F6, // SDL_SCANCODE_F6 - KEY_F7, // SDL_SCANCODE_F7 - KEY_F8, // SDL_SCANCODE_F8 - KEY_F9, // SDL_SCANCODE_F9 - KEY_F10, // SDL_SCANCODE_F10 - KEY_F11, // SDL_SCANCODE_F11 - KEY_F12, // SDL_SCANCODE_F12 - KEY_PRINT_SCREEN, // SDL_SCANCODE_PRINTSCREEN - KEY_SCROLL_LOCK, // SDL_SCANCODE_SCROLLLOCK - KEY_PAUSE, // SDL_SCANCODE_PAUSE - KEY_INSERT, // SDL_SCANCODE_INSERT - KEY_HOME, // SDL_SCANCODE_HOME - KEY_PAGE_UP, // SDL_SCANCODE_PAGEUP - KEY_DELETE, // SDL_SCANCODE_DELETE - KEY_END, // SDL_SCANCODE_END - KEY_PAGE_DOWN, // SDL_SCANCODE_PAGEDOWN - KEY_RIGHT, // SDL_SCANCODE_RIGHT - KEY_LEFT, // SDL_SCANCODE_LEFT - KEY_DOWN, // SDL_SCANCODE_DOWN - KEY_UP, // SDL_SCANCODE_UP - KEY_NUM_LOCK, // SDL_SCANCODE_NUMLOCKCLEAR - KEY_KP_DIVIDE, // SDL_SCANCODE_KP_DIVIDE - KEY_KP_MULTIPLY, // SDL_SCANCODE_KP_MULTIPLY - KEY_KP_SUBTRACT, // SDL_SCANCODE_KP_MINUS - KEY_KP_ADD, // SDL_SCANCODE_KP_PLUS - KEY_KP_ENTER, // SDL_SCANCODE_KP_ENTER - KEY_KP_1, // SDL_SCANCODE_KP_1 - KEY_KP_2, // SDL_SCANCODE_KP_2 - KEY_KP_3, // SDL_SCANCODE_KP_3 - KEY_KP_4, // SDL_SCANCODE_KP_4 - KEY_KP_5, // SDL_SCANCODE_KP_5 - KEY_KP_6, // SDL_SCANCODE_KP_6 - KEY_KP_7, // SDL_SCANCODE_KP_7 - KEY_KP_8, // SDL_SCANCODE_KP_8 - KEY_KP_9, // SDL_SCANCODE_KP_9 - KEY_KP_0, // SDL_SCANCODE_KP_0 - KEY_KP_DECIMAL, // SDL_SCANCODE_KP_PERIOD - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - KEY_LEFT_CONTROL, //SDL_SCANCODE_LCTRL - KEY_LEFT_SHIFT, //SDL_SCANCODE_LSHIFT - KEY_LEFT_ALT, //SDL_SCANCODE_LALT - KEY_LEFT_SUPER, //SDL_SCANCODE_LGUI - KEY_RIGHT_CONTROL, //SDL_SCANCODE_RCTRL - KEY_RIGHT_SHIFT, //SDL_SCANCODE_RSHIFT - KEY_RIGHT_ALT, //SDL_SCANCODE_RALT - KEY_RIGHT_SUPER //SDL_SCANCODE_RGUI -}; - -static const int CursorsLUT[] = { - SDL_SYSTEM_CURSOR_ARROW, // 0 MOUSE_CURSOR_DEFAULT - SDL_SYSTEM_CURSOR_ARROW, // 1 MOUSE_CURSOR_ARROW - SDL_SYSTEM_CURSOR_IBEAM, // 2 MOUSE_CURSOR_IBEAM - SDL_SYSTEM_CURSOR_CROSSHAIR, // 3 MOUSE_CURSOR_CROSSHAIR - SDL_SYSTEM_CURSOR_HAND, // 4 MOUSE_CURSOR_POINTING_HAND - SDL_SYSTEM_CURSOR_SIZEWE, // 5 MOUSE_CURSOR_RESIZE_EW - SDL_SYSTEM_CURSOR_SIZENS, // 6 MOUSE_CURSOR_RESIZE_NS - SDL_SYSTEM_CURSOR_SIZENWSE, // 7 MOUSE_CURSOR_RESIZE_NWSE - SDL_SYSTEM_CURSOR_SIZENESW, // 8 MOUSE_CURSOR_RESIZE_NESW - SDL_SYSTEM_CURSOR_SIZEALL, // 9 MOUSE_CURSOR_RESIZE_ALL - SDL_SYSTEM_CURSOR_NO // 10 MOUSE_CURSOR_NOT_ALLOWED - //SDL_SYSTEM_CURSOR_WAIT, // No equivalent implemented on MouseCursor enum on raylib.h - //SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h -}; - - -// SDL3 Migration Layer made to avoid `ifdefs` inside functions when we can. -#if defined(PLATFORM_DESKTOP_SDL3) - -// SDL3 Migration: -// SDL_WINDOW_FULLSCREEN_DESKTOP has been removed, -// and you can call SDL_GetWindowFullscreenMode() -// to see whether an exclusive fullscreen mode will be used -// or the borderless fullscreen desktop mode will be used -#define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN - -#define SDL_IGNORE false -#define SDL_DISABLE false -#define SDL_ENABLE true - -// SDL3 Migration: SDL_INIT_TIMER - no longer needed before calling SDL_AddTimer() -#define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|) - -// SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag. -#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|) - -// SDL3 Migration: Renamed -// IMPORTANT: Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852 -#define SDL_DROPFILE SDL_EVENT_DROP_FILE - -// SDL2 implementation for SDL3 function -const char *SDL_GameControllerNameForIndex(int joystickIndex) -{ - // NOTE: SDL3 uses the IDs itself (SDL_JoystickID) instead of SDL2 joystick_index - const char *name = NULL; - int numJoysticks = 0; - SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); - - if (joysticks) - { - if (joystickIndex < numJoysticks) - { - SDL_JoystickID instance_id = joysticks[joystickIndex]; - name = SDL_GetGamepadNameForID(instance_id); - } - - SDL_free(joysticks); - } - - return name; -} - -int SDL_GetNumVideoDisplays(void) -{ - int monitorCount = 0; - SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount); - - // Safe because If `mem` is NULL, SDL_free does nothing - SDL_free(displays); - - return monitorCount; -} - -// SLD3 Migration: To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE` -// representing the *processing state* of the event before this function makes any changes to it -Uint8 SDL_EventState(Uint32 type, int state) -{ - Uint8 stateBefore = SDL_EventEnabled(type); - - switch (state) - { - case SDL_DISABLE: SDL_SetEventEnabled(type, false); break; - case SDL_ENABLE: SDL_SetEventEnabled(type, true); break; - default: TRACELOG(LOG_WARNING, "Event sate: unknow type"); - } - - return stateBefore; -} - -void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode) -{ - const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID); - - if (currMode == NULL) TRACELOG(LOG_WARNING, "No current display mode"); - else *mode = *currMode; -} - -// SDL3 Migration: Renamed -#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_Adapter - -SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) -{ - return SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask)); -} - -// SDL3 Migration: -// SDL_GetDisplayDPI() - -// not reliable across platforms, approximately replaced by multiplying -// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms. -// returns 0 on success or a negative error code on failure -int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi) -{ - float dpi = SDL_GetWindowDisplayScale(platform.window)*96.0; - - if (ddpi != NULL) *ddpi = dpi; - if (hdpi != NULL) *hdpi = dpi; - if (vdpi != NULL) *vdpi = dpi; - - return 0; -} - -SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format) -{ - return SDL_CreateSurface(width, height, format); -} - -SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) -{ - return SDL_CreateSurfaceFrom(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask), pixels, pitch); -} - -SDL_Surface *SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 format) -{ - return SDL_CreateSurfaceFrom(width, height, format, pixels, pitch); -} - -int SDL_NumJoysticks(void) -{ - int numJoysticks; - SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); - SDL_free(joysticks); - return numJoysticks; -} - -// SDL_SetRelativeMouseMode -// returns 0 on success or a negative error code on failure -// If relative mode is not supported, this returns -1. -int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled) -{ - // SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled) - // \returns true on success or false on failure; call SDL_GetError() for more - if (SDL_SetWindowRelativeMouseMode(platform.window, enabled)) - { - return 0; // success - } - else - { - return -1; // failure - } -} - -#define SDL_SetRelativeMouseMode SDL_SetRelativeMouseMode_Adapter - -bool SDL_GetRelativeMouseMode_Adapter(void) -{ - return SDL_GetWindowRelativeMouseMode(platform.window); -} - -#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_Adapter - -int SDL_GetNumTouchFingers(SDL_TouchID touchID) -{ - // SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count) - int count = 0; - SDL_Finger **fingers = SDL_GetTouchFingers(touchID, &count); - SDL_free(fingers); - return count; -} - -#else // We're on SDL2 - -// Since SDL2 doesn't have this function we leave a stub -// SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3) -void *SDL_GetClipboardData(const char *mime_type, size_t *size) -{ - TRACELOG(LOG_WARNING, "Getting clipboard data that is not text is only available in SDL3"); - - // We could possibly implement it ourselves in this case for some easier platforms - return NULL; -} - -#endif // PLATFORM_DESKTOP_SDL3 - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -int InitPlatform(void); // Initialize platform (graphics, inputs and more) -void ClosePlatform(void); // Close platform - -static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -// NOTE: Functions declaration is provided by raylib.h - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Window and Graphics Device -//---------------------------------------------------------------------------------- - -// Check if application should close -bool WindowShouldClose(void) -{ - if (CORE.Window.ready) return CORE.Window.shouldClose; - else return true; -} - -// Toggle fullscreen mode -void ToggleFullscreen(void) -{ - const int monitor = SDL_GetWindowDisplayIndex(platform.window); - const int monitorCount = SDL_GetNumVideoDisplays(); - -#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure - if ((monitor > 0) && (monitor <= monitorCount)) -#else - if ((monitor >= 0) && (monitor < monitorCount)) -#endif - { - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) - { - SDL_SetWindowFullscreen(platform.window, 0); - CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - CORE.Window.fullscreen = false; - } - else - { - SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN); - CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - CORE.Window.fullscreen = true; - } - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); -} - -// Toggle borderless windowed mode -void ToggleBorderlessWindowed(void) -{ - const int monitor = SDL_GetWindowDisplayIndex(platform.window); - const int monitorCount = SDL_GetNumVideoDisplays(); - -#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure - if ((monitor > 0) && (monitor <= monitorCount)) -#else - if ((monitor >= 0) && (monitor < monitorCount)) -#endif - { - if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) - { - SDL_SetWindowFullscreen(platform.window, 0); - CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE; - } - else - { - SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP); - CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE; - } - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); -} - -// Set window state: maximized, if resizable -void MaximizeWindow(void) -{ - SDL_MaximizeWindow(platform.window); - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; -} - -// Set window state: minimized -void MinimizeWindow(void) -{ - SDL_MinimizeWindow(platform.window); - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; -} - -// Restore window from being minimized/maximized -void RestoreWindow(void) -{ - SDL_RestoreWindow(platform.window); - // CORE.Window.flags will be removed on PollInputEvents() -} - -// Set window configuration state using flags -void SetWindowState(unsigned int flags) -{ - if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead"); - - CORE.Window.flags |= flags; - - if (flags & FLAG_VSYNC_HINT) - { - SDL_GL_SetSwapInterval(1); - } - if (flags & FLAG_FULLSCREEN_MODE) - { - const int monitor = SDL_GetWindowDisplayIndex(platform.window); - const int monitorCount = SDL_GetNumVideoDisplays(); - - #if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure - if ((monitor > 0) && (monitor <= monitorCount)) - #else - if ((monitor >= 0) && (monitor < monitorCount)) - #endif - { - SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN); - CORE.Window.fullscreen = true; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - } - if (flags & FLAG_WINDOW_RESIZABLE) - { - SDL_SetWindowResizable(platform.window, SDL_TRUE); - } - if (flags & FLAG_WINDOW_UNDECORATED) - { - SDL_SetWindowBordered(platform.window, SDL_FALSE); - } - if (flags & FLAG_WINDOW_HIDDEN) - { - SDL_HideWindow(platform.window); - } - if (flags & FLAG_WINDOW_MINIMIZED) - { - SDL_MinimizeWindow(platform.window); - } - if (flags & FLAG_WINDOW_MAXIMIZED) - { - SDL_MaximizeWindow(platform.window); - } - if (flags & FLAG_WINDOW_UNFOCUSED) - { - // NOTE: To be able to implement this part it seems that we should - // do it ourselves, via `Windows.h`, `X11/Xlib.h` or even `Cocoa.h` - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_WINDOW_TOPMOST) - { - SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE); - } - if (flags & FLAG_WINDOW_ALWAYS_RUN) - { - CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN; - } - if (flags & FLAG_WINDOW_TRANSPARENT) - { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_WINDOW_HIGHDPI) - { - // NOTE: Such a function does not seem to exist - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) - { - //SDL_SetWindowGrab(platform.window, SDL_FALSE); - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_BORDERLESS_WINDOWED_MODE) - { - const int monitor = SDL_GetWindowDisplayIndex(platform.window); - const int monitorCount = SDL_GetNumVideoDisplays(); - - #if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure - if ((monitor > 0) && (monitor <= monitorCount)) - #else - if ((monitor >= 0) && (monitor < monitorCount)) - #endif - { - SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP); - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - } - if (flags & FLAG_MSAA_4X_HINT) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable multisampling buffers - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); // Enable multisampling - } - if (flags & FLAG_INTERLACED_HINT) - { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL"); - } -} - -// Clear window configuration state flags -void ClearWindowState(unsigned int flags) -{ - CORE.Window.flags &= ~flags; - - if (flags & FLAG_VSYNC_HINT) - { - SDL_GL_SetSwapInterval(0); - } - if (flags & FLAG_FULLSCREEN_MODE) - { - SDL_SetWindowFullscreen(platform.window, 0); - CORE.Window.fullscreen = false; - } - if (flags & FLAG_WINDOW_RESIZABLE) - { - SDL_SetWindowResizable(platform.window, SDL_FALSE); - } - if (flags & FLAG_WINDOW_UNDECORATED) - { - SDL_SetWindowBordered(platform.window, SDL_TRUE); - } - if (flags & FLAG_WINDOW_HIDDEN) - { - SDL_ShowWindow(platform.window); - } - if (flags & FLAG_WINDOW_MINIMIZED) - { - SDL_RestoreWindow(platform.window); - } - if (flags & FLAG_WINDOW_MAXIMIZED) - { - SDL_RestoreWindow(platform.window); - } - if (flags & FLAG_WINDOW_UNFOCUSED) - { - //SDL_RaiseWindow(platform.window); - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_WINDOW_TOPMOST) - { - SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE); - } - if (flags & FLAG_WINDOW_ALWAYS_RUN) - { - CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN; - } - if (flags & FLAG_WINDOW_TRANSPARENT) - { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_WINDOW_HIGHDPI) - { - // NOTE: There also doesn't seem to be a feature to disable high DPI once enabled - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) - { - //SDL_SetWindowGrab(platform.window, SDL_TRUE); - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL"); - } - if (flags & FLAG_BORDERLESS_WINDOWED_MODE) - { - SDL_SetWindowFullscreen(platform.window, 0); - } - if (flags & FLAG_MSAA_4X_HINT) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); // Disable multisampling buffers - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); // Disable multisampling - } - if (flags & FLAG_INTERLACED_HINT) - { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL"); - } -} - -// Set icon for window -void SetWindowIcon(Image image) -{ - SDL_Surface *iconSurface = NULL; - - unsigned int rmask = 0, gmask = 0, bmask = 0, amask = 0; - int depth = 0; // Depth in bits - int pitch = 0; // Pixel spacing (pitch) in bytes - - switch (image.format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - { - rmask = 0xFF, gmask = 0; - bmask = 0, amask = 0; - depth = 8, pitch = image.width; - } break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - { - rmask = 0xFF, gmask = 0xFF00; - bmask = 0, amask = 0; - depth = 16, pitch = image.width*2; - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: - { - rmask = 0xF800, gmask = 0x07E0; - bmask = 0x001F, amask = 0; - depth = 16, pitch = image.width*2; - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: - { - // WARNING: SDL2 could be using BGR but SDL3 RGB - rmask = 0xFF0000, gmask = 0x00FF00; - bmask = 0x0000FF, amask = 0; - depth = 24, pitch = image.width*3; - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - { - rmask = 0xF800, gmask = 0x07C0; - bmask = 0x003E, amask = 0x0001; - depth = 16, pitch = image.width*2; - } break; - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - { - rmask = 0xF000, gmask = 0x0F00; - bmask = 0x00F0, amask = 0x000F; - depth = 16, pitch = image.width*2; - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - { - rmask = 0xFF000000, gmask = 0x00FF0000; - bmask = 0x0000FF00, amask = 0x000000FF; - depth = 32, pitch = image.width*4; - } break; - case PIXELFORMAT_UNCOMPRESSED_R32: - { - rmask = 0xFFFFFFFF, gmask = 0; - bmask = 0, amask = 0; - depth = 32, pitch = image.width*4; - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: - { - rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF; - bmask = 0xFFFFFFFF, amask = 0; - depth = 96, pitch = image.width*12; - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - { - rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF; - bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF; - depth = 128, pitch = image.width*16; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - rmask = 0xFFFF, gmask = 0; - bmask = 0, amask = 0; - depth = 16, pitch = image.width*2; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - rmask = 0xFFFF, gmask = 0xFFFF; - bmask = 0xFFFF, amask = 0; - depth = 48, pitch = image.width*6; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - rmask = 0xFFFF, gmask = 0xFFFF; - bmask = 0xFFFF, amask = 0xFFFF; - depth = 64, pitch = image.width*8; - } break; - default: return; // Compressed formats are not supported - } - - iconSurface = SDL_CreateRGBSurfaceFrom( image.data, image.width, image.height, depth, pitch, rmask, gmask, bmask, amask ); - - if (iconSurface) - { - SDL_SetWindowIcon(platform.window, iconSurface); - SDL_FreeSurface(iconSurface); - } -} - -// Set icon for window -void SetWindowIcons(Image *images, int count) -{ - TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); -} - -// Set title for window -void SetWindowTitle(const char *title) -{ - SDL_SetWindowTitle(platform.window, title); - - CORE.Window.title = title; -} - -// Set window position on screen (windowed mode) -void SetWindowPosition(int x, int y) -{ - SDL_SetWindowPosition(platform.window, x, y); - - CORE.Window.position.x = x; - CORE.Window.position.y = y; -} - -// Set monitor for the current window -void SetWindowMonitor(int monitor) -{ - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - // NOTE: - // 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3, - // see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba - // 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again. - const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false; - - const int screenWidth = CORE.Window.screen.width; - const int screenHeight = CORE.Window.screen.height; - SDL_Rect usableBounds; - - #if defined(PLATFORM_DESKTOP_SDL3) // Different style for success checking - if (SDL_GetDisplayUsableBounds(monitor, &usableBounds)) - #else - if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0) - #endif - { - if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen. - - // If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it - if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h)) - { - // NOTE: - // 1. There's a known issue where if the window larger than the target display bounds, - // when moving the windows to that display, the window could be clipped back - // ending up positioned partly outside the target display. - // 2. The workaround for that is, previously to moving the window, - // setting the window size to the target display size, so they match. - // 3. It wasn't done here because we can't assume changing the window size automatically - // is acceptable behavior by the user. - SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y); - CORE.Window.position.x = usableBounds.x; - CORE.Window.position.y = usableBounds.y; - } - else - { - const int x = usableBounds.x + (usableBounds.w/2) - (screenWidth/2); - const int y = usableBounds.y + (usableBounds.h/2) - (screenHeight/2); - SDL_SetWindowPosition(platform.window, x, y); - CORE.Window.position.x = x; - CORE.Window.position.y = y; - } - - if (wasFullscreen == 1) ToggleFullscreen(); // Re-enter fullscreen - } - else TRACELOG(LOG_WARNING, "SDL: Failed to get selected display usable bounds"); - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); -} - -// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMinSize(int width, int height) -{ - SDL_SetWindowMinimumSize(platform.window, width, height); - - CORE.Window.screenMin.width = width; - CORE.Window.screenMin.height = height; -} - -// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMaxSize(int width, int height) -{ - SDL_SetWindowMaximumSize(platform.window, width, height); - - CORE.Window.screenMax.width = width; - CORE.Window.screenMax.height = height; -} - -// Set window dimensions -void SetWindowSize(int width, int height) -{ - SDL_SetWindowSize(platform.window, width, height); - - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; -} - -// Set window opacity, value opacity is between 0.0 and 1.0 -void SetWindowOpacity(float opacity) -{ - if (opacity >= 1.0f) opacity = 1.0f; - else if (opacity <= 0.0f) opacity = 0.0f; - - SDL_SetWindowOpacity(platform.window, opacity); -} - -// Set window focused -void SetWindowFocused(void) -{ - SDL_RaiseWindow(platform.window); -} - -// Get native window handle -void *GetWindowHandle(void) -{ - return (void *)platform.window; -} - -// Get number of monitors -int GetMonitorCount(void) -{ - int monitorCount = 0; - - monitorCount = SDL_GetNumVideoDisplays(); - - return monitorCount; -} - -// Get current monitor where window is placed -int GetCurrentMonitor(void) -{ - int currentMonitor = 0; - - // Be aware that this returns an ID in SDL3 and a Index in SDL2 - currentMonitor = SDL_GetWindowDisplayIndex(platform.window); - - return currentMonitor; -} - -// Get selected monitor position -Vector2 GetMonitorPosition(int monitor) -{ - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - SDL_Rect displayBounds; - - #if defined(PLATFORM_DESKTOP_SDL3) - if (SDL_GetDisplayUsableBounds(monitor, &displayBounds)) - #else - if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0) - #endif - { - return (Vector2){ (float)displayBounds.x, (float)displayBounds.y }; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to get selected display usable bounds"); - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - return (Vector2){ 0.0f, 0.0f }; -} - -// Get selected monitor width (currently used by monitor) -int GetMonitorWidth(int monitor) -{ - int width = 0; - - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - SDL_DisplayMode mode; - SDL_GetCurrentDisplayMode(monitor, &mode); - width = mode.w; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - - return width; -} - -// Get selected monitor height (currently used by monitor) -int GetMonitorHeight(int monitor) -{ - int height = 0; - - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - SDL_DisplayMode mode; - SDL_GetCurrentDisplayMode(monitor, &mode); - height = mode.h; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - - return height; -} - -// Get selected monitor physical width in millimetres -int GetMonitorPhysicalWidth(int monitor) -{ - int width = 0; - - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - float ddpi = 0.0f; - SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL); - SDL_DisplayMode mode; - SDL_GetCurrentDisplayMode(monitor, &mode); - // Calculate size on inches, then convert to millimeter - if (ddpi > 0.0f) width = (mode.w/ddpi)*25.4f; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - - return width; -} - -// Get selected monitor physical height in millimetres -int GetMonitorPhysicalHeight(int monitor) -{ - int height = 0; - - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - float ddpi = 0.0f; - SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL); - SDL_DisplayMode mode; - SDL_GetCurrentDisplayMode(monitor, &mode); - // Calculate size on inches, then convert to millimeter - if (ddpi > 0.0f) height = (mode.h/ddpi)*25.4f; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - - return height; -} - -// Get selected monitor refresh rate -int GetMonitorRefreshRate(int monitor) -{ - int refresh = 0; - - const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) - { - SDL_DisplayMode mode; - SDL_GetCurrentDisplayMode(monitor, &mode); - refresh = mode.refresh_rate; - } - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - - return refresh; -} - -// Get the human-readable, UTF-8 encoded name of the selected monitor -const char *GetMonitorName(int monitor) -{ - const int monitorCount = SDL_GetNumVideoDisplays(); - - if ((monitor >= 0) && (monitor < monitorCount)) return SDL_GetDisplayName(monitor); - else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); - - return ""; -} - -// Get window position XY on monitor -Vector2 GetWindowPosition(void) -{ - int x = 0; - int y = 0; - - SDL_GetWindowPosition(platform.window, &x, &y); - - return (Vector2){ (float)x, (float)y }; -} - -// Get window scale DPI factor for current monitor -Vector2 GetWindowScaleDPI(void) -{ - Vector2 scale = { 1.0f, 1.0f }; - -#ifndef PLATFORM_DESKTOP_SDL3 - // NOTE: SDL_GetWindowDisplayScale was only added on SDL3 - // see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale - // TODO: Implement the window scale factor calculation manually. - TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); -#else - scale.x = SDL_GetWindowDisplayScale(platform.window); - scale.y = scale.x; - TRACELOG(LOG_INFO, "WindowScaleDPI is %f", scale.x); -#endif - - return scale; -} - -// Set clipboard text content -void SetClipboardText(const char *text) -{ - SDL_SetClipboardText(text); -} - -// Get clipboard text content -const char *GetClipboardText(void) -{ - static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 }; - - char *clipboard = SDL_GetClipboardText(); - - int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard); - if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH) - { - char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4; - sprintf(truncate, "..."); - } - - SDL_free(clipboard); - - return buffer; -} - -// Get clipboard image -Image GetClipboardImage(void) -{ - Image image = { 0 }; - -#if defined(SUPPORT_CLIPBOARD_IMAGE) - // Let's hope compiler put these arrays in static memory - const char *imageFormats[] = { - "image/bmp", - "image/png", - "image/jpg", - "image/tiff", - }; - const char *imageExtensions[] = { - ".bmp", - ".png", - ".jpg", - ".tiff", - }; - - size_t dataSize = 0; - void *fileData = NULL; - - for (int i = 0; i < SDL_arraysize(imageFormats); ++i) - { - // NOTE: This pointer should be free with SDL_free() at some point - fileData = SDL_GetClipboardData(imageFormats[i], &dataSize); - - if (fileData) - { - image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize); - if (IsImageValid(image)) - { - TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", imageExtensions[i]); - return image; - } - } - } - - if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. Error: %s", SDL_GetError()); -#endif - - return image; -} - -// Show mouse cursor -void ShowCursor(void) -{ -#if defined(PLATFORM_DESKTOP_SDL3) - SDL_ShowCursor(); -#else - SDL_ShowCursor(SDL_ENABLE); -#endif - CORE.Input.Mouse.cursorHidden = false; -} - -// Hides mouse cursor -void HideCursor(void) -{ -#if defined(PLATFORM_DESKTOP_SDL3) - SDL_HideCursor(); -#else - SDL_ShowCursor(SDL_DISABLE); -#endif - CORE.Input.Mouse.cursorHidden = true; -} - -// Enables cursor (unlock cursor) -void EnableCursor(void) -{ - SDL_SetRelativeMouseMode(SDL_FALSE); - -#if defined(PLATFORM_DESKTOP_SDL3) - // SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible() - SDL_ShowCursor(); -#else - SDL_ShowCursor(SDL_ENABLE); -#endif - - platform.cursorRelative = false; - CORE.Input.Mouse.cursorHidden = false; -} - -// Disables cursor (lock cursor) -void DisableCursor(void) -{ - SDL_SetRelativeMouseMode(SDL_TRUE); - - platform.cursorRelative = true; - CORE.Input.Mouse.cursorHidden = true; -} - -// Swap back buffer with front buffer (screen drawing) -void SwapScreenBuffer(void) -{ - SDL_GL_SwapWindow(platform.window); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Misc -//---------------------------------------------------------------------------------- - -// Get elapsed time measure in seconds -double GetTime(void) -{ - unsigned int ms = SDL_GetTicks(); // Elapsed time in milliseconds since SDL_Init() - double time = (double)ms/1000; - return time; -} - -// Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 -void OpenURL(const char *url) -{ - // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else SDL_OpenURL(url); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Inputs -//---------------------------------------------------------------------------------- - -// Set internal gamepad mappings -int SetGamepadMappings(const char *mappings) -{ - return SDL_GameControllerAddMapping(mappings); -} - -// Set gamepad vibration -void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) -{ - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (duration > 0.0f)) - { - if (leftMotor < 0.0f) leftMotor = 0.0f; - if (leftMotor > 1.0f) leftMotor = 1.0f; - if (rightMotor < 0.0f) rightMotor = 0.0f; - if (rightMotor > 1.0f) rightMotor = 1.0f; - if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME; - - SDL_GameControllerRumble(platform.gamepad[gamepad], (Uint16)(leftMotor*65535.0f), (Uint16)(rightMotor*65535.0f), (Uint32)(duration*1000.0f)); - } -} - -// Set mouse position XY -void SetMousePosition(int x, int y) -{ - SDL_WarpMouseInWindow(platform.window, x, y); - - CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; -} - -// Set mouse cursor -void SetMouseCursor(int cursor) -{ - platform.cursor = SDL_CreateSystemCursor(CursorsLUT[cursor]); - SDL_SetCursor(platform.cursor); - - CORE.Input.Mouse.cursor = cursor; -} - -// Get physical key name. -const char *GetKeyName(int key) -{ - return SDL_GetKeyName(key); -} - -static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event) -{ -#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 - int count = 0; - SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count); - CORE.Input.Touch.pointCount = count; - - for (int i = 0; i < CORE.Input.Touch.pointCount; i++) - { - SDL_Finger *finger = fingers[i]; - CORE.Input.Touch.pointId[i] = finger->id; - CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; - CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; - CORE.Input.Touch.currentTouchState[i] = 1; - } - - SDL_free(fingers); - -#else // SDL2 - - CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId); - - for (int i = 0; i < CORE.Input.Touch.pointCount; i++) - { - SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i); - CORE.Input.Touch.pointId[i] = finger->id; - CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; - CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; - CORE.Input.Touch.currentTouchState[i] = 1; - } -#endif - - for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0; -} - -// Register all input events -void PollInputEvents(void) -{ -#if defined(SUPPORT_GESTURES_SYSTEM) - // NOTE: Gestures update must be called every frame to reset gestures correctly - // because ProcessGestureEvent() is just called on an event, not every frame - UpdateGestures(); -#endif - - // Reset keys/chars pressed registered - CORE.Input.Keyboard.keyPressedQueueCount = 0; - CORE.Input.Keyboard.charPressedQueueCount = 0; - - // Reset mouse wheel - CORE.Input.Mouse.currentWheelMove.x = 0; - CORE.Input.Mouse.currentWheelMove.y = 0; - - // Register previous mouse position - if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f }; - else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - - // Reset last gamepad button/axis registered state - for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++) - { - // Check if gamepad is available - if (CORE.Input.Gamepad.ready[i]) - { - // Register previous gamepad button states - for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) - { - CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; - } - } - } - - // Register previous touch states - for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; - - // Map touch position to mouse position for convenience - if (CORE.Input.Touch.pointCount == 0) CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - - int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE - bool realTouch = false; // Flag to differentiate real touch gestures from mouse ones - - // Register previous keys states - // NOTE: Android supports up to 260 keys - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Register previous mouse states - for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; - - // Poll input events for current platform - //----------------------------------------------------------------------------- - /* - // WARNING: Indexes into this array are obtained by using SDL_Scancode values, not SDL_Keycode values - const Uint8 *keys = SDL_GetKeyboardState(NULL); - for (int i = 0; i < 256; ++i) - { - CORE.Input.Keyboard.currentKeyState[i] = keys[i]; - //if (keys[i]) TRACELOG(LOG_WARNING, "Pressed key: %i", i); - } - */ - - CORE.Window.resizedLastFrame = false; - - if ((CORE.Window.eventWaiting) || (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0))) - { - SDL_WaitEvent(NULL); - CORE.Time.previous = GetTime(); - } - - SDL_Event event = { 0 }; - while (SDL_PollEvent(&event) != 0) - { - // All input events can be processed after polling - switch (event.type) - { - case SDL_QUIT: CORE.Window.shouldClose = true; break; - - case SDL_DROPFILE: // Dropped file - { - if (CORE.Window.dropFileCount == 0) - { - // When a new file is dropped, we reserve a fixed number of slots for all possible dropped files - // at the moment we limit the number of drops at once to 1024 files but this behaviour should probably be reviewed - // TODO: Pointers should probably be reallocated for any new file added... - CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *)); - - CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - - #if defined(PLATFORM_DESKTOP_SDL3) - // const char *data; /**< The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events */ - // Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE, and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events, you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed. - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data); - #else - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file); - SDL_free(event.drop.file); - #endif - - CORE.Window.dropFileCount++; - } - else if (CORE.Window.dropFileCount < 1024) - { - CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - - #if defined(PLATFORM_DESKTOP_SDL3) - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data); - #else - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file); - SDL_free(event.drop.file); - #endif - - CORE.Window.dropFileCount++; - } - else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!"); - - } break; - - // Window events are also polled (Minimized, maximized, close...) - - #ifndef PLATFORM_DESKTOP_SDL3 - // SDL3 states: - // The SDL_WINDOWEVENT_* events have been moved to top level events, - // and SDL_WINDOWEVENT has been removed. - // In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT - // and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event. - case SDL_WINDOWEVENT: - { - switch (event.window.event) - { - #endif - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - { - const int width = event.window.data1; - const int height = event.window.data2; - SetupViewport(width, height); - // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) - { - CORE.Window.screen.width = (int)(width / GetWindowScaleDPI().x); - CORE.Window.screen.height = (int)(height / GetWindowScaleDPI().y); - } - else - { - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - } - CORE.Window.currentFbo.width = width; - CORE.Window.currentFbo.height = height; - CORE.Window.resizedLastFrame = true; - - #ifndef PLATFORM_DESKTOP_SDL3 - // Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms) to remove the FLAG_WINDOW_MAXIMIZED accordingly - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) - { - int borderTop = 0; - int borderLeft = 0; - int borderBottom = 0; - int borderRight = 0; - SDL_GetWindowBordersSize(platform.window, &borderTop, &borderLeft, &borderBottom, &borderRight); - SDL_Rect usableBounds; - SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(platform.window), &usableBounds); - - if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; - } - #endif - } break; - - case SDL_WINDOWEVENT_ENTER: - { - CORE.Input.Mouse.cursorOnScreen = true; - } break; - case SDL_WINDOWEVENT_LEAVE: - { - CORE.Input.Mouse.cursorOnScreen = false; - } break; - - case SDL_WINDOWEVENT_MINIMIZED: - { - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; - } break; - case SDL_WINDOWEVENT_MAXIMIZED: - { - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; - } break; - case SDL_WINDOWEVENT_RESTORED: - { - if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MINIMIZED) == 0) - { - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; - } - - #ifdef PLATFORM_DESKTOP_SDL3 - if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MAXIMIZED) == 0) - { - if ((CORE.Window.flags & SDL_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~SDL_WINDOW_MAXIMIZED; - } - #endif - } break; - - case SDL_WINDOWEVENT_HIDDEN: - { - if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; - } break; - case SDL_WINDOWEVENT_SHOWN: - { - if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; - } break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - { - if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; - } break; - case SDL_WINDOWEVENT_FOCUS_LOST: - { - if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0) CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; - } break; - - #ifndef PLATFORM_DESKTOP_SDL3 - default: break; - } - } break; - #endif - - // Keyboard events - case SDL_KEYDOWN: - { - #if defined(PLATFORM_DESKTOP_SDL3) - // SDL3 Migration: The following structures have been removed: * SDL_Keysym - KeyboardKey key = ConvertScancodeToKey(event.key.scancode); - #else - KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode); - #endif - - if (key != KEY_NULL) - { - // If key was up, add it to the key pressed queue - if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)) - { - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - - CORE.Input.Keyboard.currentKeyState[key] = 1; - } - - if (event.key.repeat) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; - - // TODO: Put exitKey verification outside the switch? - if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) - { - CORE.Window.shouldClose = true; - } - } break; - - case SDL_KEYUP: - { - - #if defined(PLATFORM_DESKTOP_SDL3) - KeyboardKey key = ConvertScancodeToKey(event.key.scancode); - #else - KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode); - #endif - if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0; - } break; - - case SDL_TEXTINPUT: - { - // NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int) - - int codepointSize = 0; - - // Check if there is space available in the queue - if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) - { - // Add character (codepoint) to the queue - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize); - CORE.Input.Keyboard.charPressedQueueCount++; - } - } break; - - // Check mouse events - case SDL_MOUSEBUTTONDOWN: - { - // NOTE: SDL2 mouse button order is LEFT, MIDDLE, RIGHT, but raylib uses LEFT, RIGHT, MIDDLE like GLFW - // The following conditions align SDL with raylib.h MouseButton enum order - int btn = event.button.button - 1; - if (btn == 2) btn = 1; - else if (btn == 1) btn = 2; - - CORE.Input.Mouse.currentButtonState[btn] = 1; - CORE.Input.Touch.currentTouchState[btn] = 1; - - touchAction = 1; - } break; - case SDL_MOUSEBUTTONUP: - { - // NOTE: SDL2 mouse button order is LEFT, MIDDLE, RIGHT, but raylib uses LEFT, RIGHT, MIDDLE like GLFW - // The following conditions align SDL with raylib.h MouseButton enum order - int btn = event.button.button - 1; - if (btn == 2) btn = 1; - else if (btn == 1) btn = 2; - - CORE.Input.Mouse.currentButtonState[btn] = 0; - CORE.Input.Touch.currentTouchState[btn] = 0; - - touchAction = 0; - } break; - case SDL_MOUSEWHEEL: - { - CORE.Input.Mouse.currentWheelMove.x = (float)event.wheel.x; - CORE.Input.Mouse.currentWheelMove.y = (float)event.wheel.y; - } break; - case SDL_MOUSEMOTION: - { - if (platform.cursorRelative) - { - CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel; - CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel; - CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; - } - else - { - CORE.Input.Mouse.currentPosition.x = (float)event.motion.x; - CORE.Input.Mouse.currentPosition.y = (float)event.motion.y; - } - - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - touchAction = 2; - } break; - - case SDL_FINGERDOWN: - { - UpdateTouchPointsSDL(event.tfinger); - touchAction = 1; - realTouch = true; - } break; - case SDL_FINGERUP: - { - UpdateTouchPointsSDL(event.tfinger); - touchAction = 0; - realTouch = true; - } break; - case SDL_FINGERMOTION: - { - UpdateTouchPointsSDL(event.tfinger); - touchAction = 2; - realTouch = true; - } break; - - // Check gamepad events - case SDL_JOYDEVICEADDED: - { - int jid = event.jdevice.which; // Joystick device index - - if (CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS)) - { - platform.gamepad[jid] = SDL_GameControllerOpen(jid); - platform.gamepadId[jid] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid])); - - if (platform.gamepad[jid]) - { - CORE.Input.Gamepad.ready[jid] = true; - CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid])); - CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; - CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; - memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH); - strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), MAX_GAMEPAD_NAME_LENGTH - 1); - } - else - { - TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); - } - } - } break; - case SDL_JOYDEVICEREMOVED: - { - int jid = event.jdevice.which; // Joystick instance id - - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (platform.gamepadId[i] == jid) - { - SDL_GameControllerClose(platform.gamepad[i]); - CORE.Input.Gamepad.ready[i] = false; - memset(CORE.Input.Gamepad.name[i], 0, MAX_GAMEPAD_NAME_LENGTH); - platform.gamepadId[i] = -1; - break; - } - } - } break; - case SDL_CONTROLLERBUTTONDOWN: - { - int button = -1; - - switch (event.jbutton.button) - { - case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; - case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; - case SDL_CONTROLLER_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break; - case SDL_CONTROLLER_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break; - - case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break; - case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break; - - case SDL_CONTROLLER_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break; - case SDL_CONTROLLER_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break; - case SDL_CONTROLLER_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break; - - case SDL_CONTROLLER_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break; - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break; - - case SDL_CONTROLLER_BUTTON_LEFTSTICK: button = GAMEPAD_BUTTON_LEFT_THUMB; break; - case SDL_CONTROLLER_BUTTON_RIGHTSTICK: button = GAMEPAD_BUTTON_RIGHT_THUMB; break; - default: break; - } - - if (button >= 0) - { - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (platform.gamepadId[i] == event.jbutton.which) - { - CORE.Input.Gamepad.currentButtonState[i][button] = 1; - CORE.Input.Gamepad.lastButtonPressed = button; - break; - } - } - } - } break; - case SDL_CONTROLLERBUTTONUP: - { - int button = -1; - - switch (event.jbutton.button) - { - case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; - case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; - case SDL_CONTROLLER_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break; - case SDL_CONTROLLER_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break; - - case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break; - case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break; - - case SDL_CONTROLLER_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break; - case SDL_CONTROLLER_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break; - case SDL_CONTROLLER_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break; - - case SDL_CONTROLLER_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break; - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break; - - case SDL_CONTROLLER_BUTTON_LEFTSTICK: button = GAMEPAD_BUTTON_LEFT_THUMB; break; - case SDL_CONTROLLER_BUTTON_RIGHTSTICK: button = GAMEPAD_BUTTON_RIGHT_THUMB; break; - default: break; - } - - if (button >= 0) - { - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (platform.gamepadId[i] == event.jbutton.which) - { - CORE.Input.Gamepad.currentButtonState[i][button] = 0; - if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; - break; - } - } - } - } break; - case SDL_CONTROLLERAXISMOTION: - { - int axis = -1; - - switch (event.jaxis.axis) - { - case SDL_CONTROLLER_AXIS_LEFTX: axis = GAMEPAD_AXIS_LEFT_X; break; - case SDL_CONTROLLER_AXIS_LEFTY: axis = GAMEPAD_AXIS_LEFT_Y; break; - case SDL_CONTROLLER_AXIS_RIGHTX: axis = GAMEPAD_AXIS_RIGHT_X; break; - case SDL_CONTROLLER_AXIS_RIGHTY: axis = GAMEPAD_AXIS_RIGHT_Y; break; - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: axis = GAMEPAD_AXIS_LEFT_TRIGGER; break; - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: axis = GAMEPAD_AXIS_RIGHT_TRIGGER; break; - default: break; - } - - if (axis >= 0) - { - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (platform.gamepadId[i] == event.jaxis.which) - { - // SDL axis value range is -32768 to 32767, we normalize it to raylib's -1.0 to 1.0f range - float value = event.jaxis.value/(float)32767; - CORE.Input.Gamepad.axisState[i][axis] = value; - - // Register button state for triggers in addition to their axes - if ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER)) - { - int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2; - int pressed = (value > 0.1f); - CORE.Input.Gamepad.currentButtonState[i][button] = pressed; - if (pressed) CORE.Input.Gamepad.lastButtonPressed = button; - else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; - } - break; - } - } - } - } break; - default: break; - } - -#if defined(SUPPORT_GESTURES_SYSTEM) - if (touchAction > -1) - { - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent = { 0 }; - - // Register touch actions - gestureEvent.touchAction = touchAction; - - // Assign a pointer ID - gestureEvent.pointId[0] = 0; - - // Register touch points count - gestureEvent.pointCount = 1; - - // Register touch points position, only one point registered - if (touchAction == 2 || realTouch) gestureEvent.position[0] = CORE.Input.Touch.position[0]; - else gestureEvent.position[0] = GetMousePosition(); - - // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures-system for processing - ProcessGestureEvent(gestureEvent); - - touchAction = -1; - } -#endif - } - //----------------------------------------------------------------------------- -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- - -// Initialize platform: graphics, inputs and more -int InitPlatform(void) -{ - // Initialize SDL internal global state, only required systems - // NOTE: Not all systems need to be initialized, SDL_INIT_AUDIO is not required, managed by miniaudio - int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER); - if (result < 0) { TRACELOG(LOG_WARNING, "SDL: Failed to initialize SDL"); return -1; } - - // Initialize graphic device: display/window and graphic context - //---------------------------------------------------------------------------- - unsigned int flags = 0; - flags |= SDL_WINDOW_SHOWN; - flags |= SDL_WINDOW_OPENGL; - flags |= SDL_WINDOW_INPUT_FOCUS; - flags |= SDL_WINDOW_MOUSE_FOCUS; - flags |= SDL_WINDOW_MOUSE_CAPTURE; // Window has mouse captured - - // Check window creation flags - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) - { - CORE.Window.fullscreen = true; - flags |= SDL_WINDOW_FULLSCREEN; - } - - //if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) flags |= SDL_WINDOW_HIDDEN; - if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= SDL_WINDOW_BORDERLESS; - if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) flags |= SDL_WINDOW_RESIZABLE; - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) flags |= SDL_WINDOW_MINIMIZED; - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= SDL_WINDOW_MAXIMIZED; - - if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) - { - flags &= ~SDL_WINDOW_INPUT_FOCUS; - flags &= ~SDL_WINDOW_MOUSE_FOCUS; - } - - if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) flags |= SDL_WINDOW_ALWAYS_ON_TOP; - if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) flags &= ~SDL_WINDOW_MOUSE_CAPTURE; - - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) flags |= SDL_WINDOW_ALLOW_HIGHDPI; - - //if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= SDL_WINDOW_TRANSPARENT; // Alternative: SDL_GL_ALPHA_SIZE = 8 - - //if ((CORE.Window.flags & FLAG_FULLSCREEN_DESKTOP) > 0) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - - // NOTE: Some OpenGL context attributes must be set before window creation - - // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_21) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - } - else if (rlGetVersion() == RL_OPENGL_33) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - } - else if (rlGetVersion() == RL_OPENGL_43) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context -#endif - } - else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - } - else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - } - - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); - } - - // Init window -#if defined(PLATFORM_DESKTOP_SDL3) - platform.window = SDL_CreateWindow(CORE.Window.title, CORE.Window.screen.width, CORE.Window.screen.height, flags); -#else - platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags); -#endif - - // Init OpenGL context - platform.glContext = SDL_GL_CreateContext(platform.window); - - // Check window and glContext have been initialized successfully - if ((platform.window != NULL) && (platform.glContext != NULL)) - { - CORE.Window.ready = true; - - SDL_DisplayMode displayMode = { 0 }; - SDL_GetCurrentDisplayMode(GetCurrentMonitor(), &displayMode); - - CORE.Window.display.width = displayMode.w; - CORE.Window.display.height = displayMode.h; - - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.currentFbo.width = CORE.Window.render.width; - CORE.Window.currentFbo.height = CORE.Window.render.height; - - TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); - TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); - TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); - TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); - - if (CORE.Window.flags & FLAG_VSYNC_HINT) SDL_GL_SetSwapInterval(1); - else SDL_GL_SetSwapInterval(0); - } - else - { - TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device"); - return -1; - } - - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - rlLoadExtensions(SDL_GL_GetProcAddress); - //---------------------------------------------------------------------------- - - // Initialize input events system - //---------------------------------------------------------------------------- - // Initialize gamepads - for (int i = 0; i < MAX_GAMEPADS; i++) - { - platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero - } - - for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++) - { - platform.gamepad[i] = SDL_GameControllerOpen(i); - platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i])); - - if (platform.gamepad[i]) - { - CORE.Input.Gamepad.ready[i] = true; - CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i])); - CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; - CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; - strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1); - CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0'; - } - else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); - } - - // Disable mouse events being interpreted as touch events - // NOTE: This is wanted because there are SDL_FINGER* events available which provide unique data - // Due to the way PollInputEvents() and rgestures.h are currently implemented, setting this won't break SUPPORT_MOUSE_GESTURES - SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); - - SDL_EventState(SDL_DROPFILE, SDL_ENABLE); - //---------------------------------------------------------------------------- - - // Initialize timing system - //---------------------------------------------------------------------------- - // NOTE: No need to call InitTimer(), let SDL manage it internally - CORE.Time.previous = GetTime(); // Get time as double - - #if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) - SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); // SDL equivalent of timeBeginPeriod() and timeEndPeriod() - #endif - //---------------------------------------------------------------------------- - - // Initialize storage system - //---------------------------------------------------------------------------- - // Define base path for storage - CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory(); - //---------------------------------------------------------------------------- - -#if defined(PLATFORM_DESKTOP_SDL3) - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully"); -#else - TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL2): Initialized successfully"); -#endif - - return 0; -} - -// Close platform -void ClosePlatform(void) -{ - SDL_FreeCursor(platform.cursor); // Free cursor - SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context - SDL_DestroyWindow(platform.window); - SDL_Quit(); // Deinitialize SDL internal global state -} - -// Scancode to keycode mapping -static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode) -{ - if ((sdlScancode >= 0) && (sdlScancode < SCANCODE_MAPPED_NUM)) - { - return mapScancodeToKey[sdlScancode]; - } - - return KEY_NULL; // No equivalent key in Raylib -} -// EOF diff --git a/raylib/platforms/rcore_drm.c b/raylib/platforms/rcore_drm.c deleted file mode 100644 index 20d676e..0000000 --- a/raylib/platforms/rcore_drm.c +++ /dev/null @@ -1,2258 +0,0 @@ -/********************************************************************************************** -* -* rcore_drm - Functions to manage window, graphics device and inputs -* -* PLATFORM: DRM -* - Raspberry Pi 0-5 (DRM/KMS) -* - Linux DRM subsystem (KMS mode) -* -* LIMITATIONS: -* - Most of the window/monitor functions are not implemented (not required) -* -* POSSIBLE IMPROVEMENTS: -* - Improvement 01 -* - Improvement 02 -* -* ADDITIONAL NOTES: -* - TRACELOG() function is located in raylib [utils] module -* -* CONFIGURATION: -* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only) -* Reconfigure standard input to receive key inputs, works with SSH connection. -* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other -* running processes orblocking the device if not restored properly. Use with care. -* #define ENABLE_WAYLAND_DRM_LEASING -* Instead of acquiring DRM exclusively, this leases a DRM instance from the currently running -* Wayland compositor. This requires the screen to have the non-desktop property, which is set -* through EDIDs. X11 is not supported, but it may be in the future. -* See: -* https://learn.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension -* -* DEPENDENCIES: -* - DRM and GLM: System libraries for display initialization and configuration -* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) -* - wayland-client: Needed for DRM leasing. Only used if ENABLE_WAYLAND_DRM_LEASING is set. -* - drm-lease-v1: Generated Wayland code for the DRM leasing extension. Only used if -* ENABLE_WAYLAND_DRM_LEASING is set. -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#include // POSIX file control definitions - open(), creat(), fcntl() -#include // POSIX standard function definitions - read(), close(), STDIN_FILENO -#include // POSIX terminal control definitions - tcgetattr(), tcsetattr() -#include // POSIX threads management (inputs reading) -#include // POSIX directory browsing - -#include // Required for: ioctl() - UNIX System call for device-specific input/output operations -#include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition -#include // Linux: Keycodes constants definition (KEY_A, ...) -#include // Linux: Joystick support library - -// WARNING: Both 'linux/input.h' and 'raylib.h' define KEY_F12 -// To avoid conflict with the capturing code in rcore.c we undefine the macro KEY_F12, -// so the enum KEY_F12 from raylib is used -#undef KEY_F12 - -#include // Generic Buffer Management (native platform for EGL on DRM) -#include // Direct Rendering Manager user-level library interface -#include // Direct Rendering Manager mode setting (KMS) interface - -#include "EGL/egl.h" // Native platform windowing system interface -#include "EGL/eglext.h" // EGL extensions - -#if defined(ENABLE_WAYLAND_DRM_LEASING) - #include "wayland-client.h" // Wayland client. Used to do DRM leasing. - // DRM leasing protocol that's used - #include "drm-lease-v1.c" - #include "drm-lease-v1.h" -#endif - -#ifndef EGL_OPENGL_ES3_BIT - #define EGL_OPENGL_ES3_BIT 0x40 -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event number - -#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events - -// So actually the biggest key is KEY_CNT but we only really map the keys up to -// KEY_ALS_TOGGLE -#define KEYMAP_SIZE KEY_ALS_TOGGLE - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef unsigned int uint; - -typedef struct { - // Display data - int fd; // File descriptor for /dev/dri/... - drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector - drmModeCrtc *crtc; // CRT Controller - int modeIndex; // Index of the used mode of connector->modes - struct gbm_device *gbmDevice; // GBM device - struct gbm_surface *gbmSurface; // GBM surface - struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping) - uint32_t prevFB; // Previous GBM framebufer (during frame swapping) - - EGLDisplay device; // Native display device (physical screen connection) - EGLSurface surface; // Surface to draw on, framebuffers (connected to context) - EGLContext context; // Graphic context, mode in which drawing can be done - EGLConfig config; // Graphic config - - // Keyboard data - int defaultKeyboardMode; // Default keyboard mode - bool eventKeyboardMode; // Keyboard in event mode - int defaultFileFlags; // Default IO file flags - struct termios defaultSettings; // Default keyboard settings - int keyboardFd; // File descriptor for the evdev keyboard - - // Mouse data - Vector2 eventWheelMove; // Registers the event mouse wheel variation - // NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update - char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab - bool cursorRelative; // Relative cursor mode - int mouseFd; // File descriptor for the evdev mouse/touch/gestures - Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) - int touchSlot; // Hold the touch slot number of the currently being sent multitouch block - - // Gamepad data - int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor - int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes - int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one - int gamepadCount; // The number of gamepads registered - - #if defined(ENABLE_WAYLAND_DRM_LEASING) - bool usingDRMLeasing; // True if we are using DRM leasing - #endif -} PlatformData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context - -static PlatformData platform = { 0 }; // Platform specific data - -//---------------------------------------------------------------------------------- -// Local Variables Definition -//---------------------------------------------------------------------------------- - -// NOTE: The complete evdev EV_KEY list can be found at /usr/include/linux/input-event-codes.h -// TODO: Complete the LUT with all unicode decimal values -// TODO: Replace this with a keymap from the X11 to get the correct regional map for the keyboard: -// Currently non US keyboards will have the wrong mapping for some keys -// NOTE: Replacing this with the keymap from X11 would probably be useless, as people use the drm -// backend to *avoid* X11 -static const int evkeyToUnicodeLUT[] = { - 0, 27, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 8, 0, 113, 119, 101, 114, - 116, 121, 117, 105, 111, 112, 0, 0, 13, 0, 97, 115, 100, 102, 103, 104, 106, 107, 108, 59, - 39, 96, 0, 92, 122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 32 - // LUT currently incomplete, just mapped the most essential keys -}; - -// This is the map used to map any keycode returned from linux to a raylib code from 'raylib.h' -// NOTE: Use short here to save a little memory -static const short linuxToRaylibMap[KEYMAP_SIZE] = { - // We don't map those with designated initialization, because we would getting - // into loads of naming conflicts - 0, 256, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 48, 45, 61, 259, 258, - 81, 87, 69, 82, 84, 89, 85, 73, - 79, 80, 91, 93, 257, 341, 65, 83, - 68, 70, 71, 72, 74, 75, 76, 59, - 39, 96, 340, 92, 90, 88, 67, 86, - 66, 78, 77, 44, 46, 47, 344, 332, - 342, 32, 280, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 282, 281, 327, - 328, 329, 333, 324, 325, 326, 334, 321, - 322, 323, 320, 330, 0, 85, 86, 300, - 301, 89, 90, 91, 92, 93, 94, 95, - 335, 345, 331, 283, 346, 101, 268, 265, - 266, 263, 262, 269, 264, 267, 260, 261, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 347, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 0, 0, 0, 0, - 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, - 248, 0, 0, 0, 0, 0, 0, 0, - - // Gamepads are mapped according to: - // https://www.kernel.org/doc/html/next/input/gamepad.html - // Those mappings are standardized, but that doesn't mean people follow - // the standards, so this is more of an approximation - [BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP, - [BTN_DPAD_RIGHT] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT, - [BTN_DPAD_DOWN] = GAMEPAD_BUTTON_LEFT_FACE_DOWN, - [BTN_DPAD_LEFT] = GAMEPAD_BUTTON_LEFT_FACE_LEFT, - [BTN_Y] = GAMEPAD_BUTTON_RIGHT_FACE_UP, - [BTN_B] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, - [BTN_A] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN, - [BTN_X] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT, - [BTN_TL] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, - [BTN_TL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, - [BTN_TR] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1, - [BTN_TR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2, - [BTN_SELECT] = GAMEPAD_BUTTON_MIDDLE_LEFT, - [BTN_MODE] = GAMEPAD_BUTTON_MIDDLE, - [BTN_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT, - [BTN_THUMBL] = GAMEPAD_BUTTON_LEFT_THUMB, - [BTN_THUMBR] = GAMEPAD_BUTTON_RIGHT_THUMB, -}; - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -int InitPlatform(void); // Initialize platform (graphics, inputs and more) -void ClosePlatform(void); // Close platform - -#if defined(SUPPORT_SSH_KEYBOARD_RPI) -static void InitKeyboard(void); // Initialize raw keyboard system -static void RestoreKeyboard(void); // Restore keyboard system -static void ProcessKeyboard(void); // Process keyboard events -#endif - -static void InitEvdevInput(void); // Initialize evdev inputs -static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate -static void PollKeyboardEvents(void); // Process evdev keyboard events -static void PollGamepadEvents(void); // Process evdev gamepad events -static void PollMouseEvents(void); // Process evdev mouse events - -static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list -static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list -static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -// NOTE: Functions declaration is provided by raylib.h - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Window and Graphics Device -//---------------------------------------------------------------------------------- - -// Check if application should close -// NOTE: By default, if KEY_ESCAPE pressed -bool WindowShouldClose(void) -{ - if (CORE.Window.ready) return CORE.Window.shouldClose; - else return true; -} - -// Toggle fullscreen mode -void ToggleFullscreen(void) -{ - TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform"); -} - -// Toggle borderless windowed mode -void ToggleBorderlessWindowed(void) -{ - TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform"); -} - -// Set window state: maximized, if resizable -void MaximizeWindow(void) -{ - TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform"); -} - -// Set window state: minimized -void MinimizeWindow(void) -{ - TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform"); -} - -// Restore window from being minimized/maximized -void RestoreWindow(void) -{ - TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform"); -} - -// Set window configuration state using flags -void SetWindowState(unsigned int flags) -{ - TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform"); -} - -// Clear window configuration state flags -void ClearWindowState(unsigned int flags) -{ - TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform"); -} - -// Set icon for window -void SetWindowIcon(Image image) -{ - TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform"); -} - -// Set icon for window -void SetWindowIcons(Image *images, int count) -{ - TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); -} - -// Set title for window -void SetWindowTitle(const char *title) -{ - CORE.Window.title = title; -} - -// Set window position on screen (windowed mode) -void SetWindowPosition(int x, int y) -{ - TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform"); -} - -// Set monitor for the current window -void SetWindowMonitor(int monitor) -{ - TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform"); -} - -// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMinSize(int width, int height) -{ - CORE.Window.screenMin.width = width; - CORE.Window.screenMin.height = height; -} - -// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMaxSize(int width, int height) -{ - CORE.Window.screenMax.width = width; - CORE.Window.screenMax.height = height; -} - -// Set window dimensions -void SetWindowSize(int width, int height) -{ - TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform"); -} - -// Set window opacity, value opacity is between 0.0 and 1.0 -void SetWindowOpacity(float opacity) -{ - TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); -} - -// Set window focused -void SetWindowFocused(void) -{ - TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform"); -} - -// Get native window handle -void *GetWindowHandle(void) -{ - TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform"); - return NULL; -} - -// Get number of monitors -int GetMonitorCount(void) -{ - TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform"); - return 1; -} - -// Get current monitor where window is placed -int GetCurrentMonitor(void) -{ - TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform"); - return 0; -} - -// Get selected monitor position -Vector2 GetMonitorPosition(int monitor) -{ - TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform"); - return (Vector2){ 0, 0 }; -} - -// Get selected monitor width (currently used by monitor) -int GetMonitorWidth(int monitor) -{ - int width = 0; - - if (monitor != 0) - { - TRACELOG(LOG_WARNING, "GetMonitorWidth() implemented for first monitor only"); - } - else if ((platform.connector) && (platform.modeIndex >= 0)) - { - width = platform.connector->modes[platform.modeIndex].hdisplay; - } - - return width; -} - -// Get selected monitor height (currently used by monitor) -int GetMonitorHeight(int monitor) -{ - int height = 0; - - if (monitor != 0) - { - TRACELOG(LOG_WARNING, "GetMonitorHeight() implemented for first monitor only"); - } - else if ((platform.connector) && (platform.modeIndex >= 0)) - { - height = platform.connector->modes[platform.modeIndex].vdisplay; - } - - return height; -} - -// Get selected monitor physical width in millimetres -int GetMonitorPhysicalWidth(int monitor) -{ - int physicalWidth = 0; - - if (monitor != 0) - { - TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() implemented for first monitor only"); - } - else if ((platform.connector) && (platform.modeIndex >= 0)) - { - physicalWidth = platform.connector->mmWidth; - } - - return physicalWidth; -} - -// Get selected monitor physical height in millimetres -int GetMonitorPhysicalHeight(int monitor) -{ - int physicalHeight = 0; - - if (monitor != 0) - { - TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() implemented for first monitor only"); - } - else if ((platform.connector) && (platform.modeIndex >= 0)) - { - physicalHeight = platform.connector->mmHeight; - } - - return physicalHeight; -} - -// Get selected monitor refresh rate -int GetMonitorRefreshRate(int monitor) -{ - int refresh = 0; - - if ((platform.connector) && (platform.modeIndex >= 0)) - { - refresh = platform.connector->modes[platform.modeIndex].vrefresh; - } - - return refresh; -} - -// Get the human-readable, UTF-8 encoded name of the selected monitor -const char *GetMonitorName(int monitor) -{ - const char *name = ""; - - if (monitor != 0) - { - TRACELOG(LOG_WARNING, "GetMonitorName() implemented for first monitor only"); - } - else if ((platform.connector) && (platform.modeIndex >= 0)) - { - name = platform.connector->modes[platform.modeIndex].name; - } - - return name; -} - -// Get window position XY on monitor -Vector2 GetWindowPosition(void) -{ - return (Vector2){ 0, 0 }; -} - -// Get window scale DPI factor for current monitor -Vector2 GetWindowScaleDPI(void) -{ - return (Vector2){ 1.0f, 1.0f }; -} - -// Set clipboard text content -void SetClipboardText(const char *text) -{ - TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform"); -} - -// Get clipboard text content -// NOTE: returned string is allocated and freed by GLFW -const char *GetClipboardText(void) -{ - TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform"); - return NULL; -} - -// Get clipboard image -Image GetClipboardImage(void) -{ - Image image = { 0 }; - - TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); - - return image; -} - -// Show mouse cursor -void ShowCursor(void) -{ - CORE.Input.Mouse.cursorHidden = false; -} - -// Hides mouse cursor -void HideCursor(void) -{ - CORE.Input.Mouse.cursorHidden = true; -} - -// Enables cursor (unlock cursor) -void EnableCursor(void) -{ - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - - platform.cursorRelative = false; - CORE.Input.Mouse.cursorHidden = false; -} - -// Disables cursor (lock cursor) -void DisableCursor(void) -{ - // Set cursor position in the middle - SetMousePosition(0, 0); - - platform.cursorRelative = true; - CORE.Input.Mouse.cursorHidden = true; -} - -// Swap back buffer with front buffer (screen drawing) -void SwapScreenBuffer(void) -{ - eglSwapBuffers(platform.device, platform.surface); - - if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); - - struct gbm_bo *bo = gbm_surface_lock_front_buffer(platform.gbmSurface); - if (!bo) TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer"); - - uint32_t fb = 0; - int result = drmModeAddFB(platform.fd, platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb); - if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result); - - result = drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, fb, 0, 0, &platform.connector->connector_id, 1, &platform.connector->modes[platform.modeIndex]); - if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result); - - if (platform.prevFB) - { - result = drmModeRmFB(platform.fd, platform.prevFB); - if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result); - } - - platform.prevFB = fb; - - if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); - - platform.prevBO = bo; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Misc -//---------------------------------------------------------------------------------- - -// Get elapsed time measure in seconds since InitTimer() -double GetTime(void) -{ - double time = 0.0; - struct timespec ts = { 0 }; - clock_gettime(CLOCK_MONOTONIC, &ts); - unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; - - time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() - - return time; -} - -// Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 -void OpenURL(const char *url) -{ - TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform"); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Inputs -//---------------------------------------------------------------------------------- - -// Set internal gamepad mappings -int SetGamepadMappings(const char *mappings) -{ - TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform"); - return 0; -} - -// Set gamepad vibration -void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) -{ - TRACELOG(LOG_WARNING, "SetGamepadVibration() not implemented on target platform"); -} - -// Set mouse position XY -void SetMousePosition(int x, int y) -{ - CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; -} - -// Set mouse cursor -void SetMouseCursor(int cursor) -{ - TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); -} - -// Get physical key name. -const char *GetKeyName(int key) -{ - TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform"); - return ""; -} - -// Register all input events -void PollInputEvents(void) -{ -#if defined(SUPPORT_GESTURES_SYSTEM) - // NOTE: Gestures update must be called every frame to reset gestures correctly - // because ProcessGestureEvent() is just called on an event, not every frame - UpdateGestures(); -#endif - - // Reset keys/chars pressed registered - CORE.Input.Keyboard.keyPressedQueueCount = 0; - CORE.Input.Keyboard.charPressedQueueCount = 0; - - // Reset last gamepad button/axis registered state - CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN - //CORE.Input.Gamepad.axisCount = 0; - - // Register previous keys states - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - PollKeyboardEvents(); - -#if defined(SUPPORT_SSH_KEYBOARD_RPI) - // NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here. - // stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console - if (!platform.eventKeyboardMode) ProcessKeyboard(); -#endif - - // Check exit key - if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true; - - // Register previous mouse position - if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f }; - else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - - // Register previous mouse states - CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; - CORE.Input.Mouse.currentWheelMove = platform.eventWheelMove; - platform.eventWheelMove = (Vector2){ 0.0f, 0.0f }; - - for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) - { - CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; - CORE.Input.Mouse.currentButtonState[i] = platform.currentButtonStateEvdev[i]; - CORE.Input.Touch.currentTouchState[i] = platform.currentButtonStateEvdev[i]; - } - - // Register gamepads buttons events - PollGamepadEvents(); - - // Register previous touch states - for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; - - // Reset touch positions - //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; - - // Map touch position to mouse position for convenience - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - - // Handle the mouse/touch/gestures events: - PollMouseEvents(); -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- - -#if defined(ENABLE_WAYLAND_DRM_LEASING) - // Wayland state for DRM leasing - struct wayland_state { - struct wp_drm_lease_device_v1 *lease_device; - struct wp_drm_lease_connector_v1 *lease_connector; - }; - - // Called when we get a potential DRM lease - void lease_handler(void *data, struct wp_drm_lease_v1 *wp_drm_lease_v1, int32_t leased_fd) - { - int *fd = data; - *fd = leased_fd; - } - - void lease_remove_handler(void *data, struct wp_drm_lease_v1 *wp_drm_lease_v1) - { - // Do nothing - } - - static const struct wp_drm_lease_v1_listener lease_listener = { - .lease_fd = lease_handler, - .finished = lease_remove_handler, - }; - - // Called when we get a potential DRM lease - static void lease_device_fd_handler(void *data, struct wp_drm_lease_device_v1 *lease_device, int fd) - { - close(fd); - } - - // Called when we get a lease connector - static void lease_device_connector_handler(void *data, struct wp_drm_lease_device_v1 *lease_device, struct wp_drm_lease_connector_v1 *conn) - { - struct wayland_state *state = data; - - if (!state->lease_connector) { - state->lease_connector = conn; - } - } - - static void lease_device_on_done(void *data, struct wp_drm_lease_device_v1 *lease_device) - { - // Do nothing - } - - static void lease_device_on_release(void *data, struct wp_drm_lease_device_v1 *lease_device) - { - // Do nothing - } - - static const struct wp_drm_lease_device_v1_listener lease_manager_listener = { - .drm_fd = lease_device_fd_handler, - .connector = lease_device_connector_handler, - .done = lease_device_on_done, - .released = lease_device_on_release, - }; - - // Listen for protocol list/dump - static void registry_handler(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) - { - struct wayland_state *state = data; - - if (strcmp(interface, "wp_drm_lease_device_v1") == 0) { - state->lease_device = wl_registry_bind(registry, name, &wp_drm_lease_device_v1_interface, version); - wp_drm_lease_device_v1_add_listener(state->lease_device, &lease_manager_listener, state); - } - } - - // Listen for remove event - static void registry_remove_handler(void *data, struct wl_registry *registry, uint32_t name) - { - // Do nothing - } - - static const struct wl_registry_listener registry_listener = { - .global = registry_handler, - .global_remove = registry_remove_handler, - }; - - // Get the DRM device's file descriptor via DRM leasing. Seperate function due to readability concerns - int GetDRMFDViaWaylandLeasing(void) - { - int fd = -1; - - // Connect to the potentially running Wayland instance - struct wayland_state state = { 0 }; - struct wl_display *display = wl_display_connect(NULL); - - if (!display) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to connect to Wayland server for DRM leasing! Is Wayland running? Cannot do DRM leasing"); - return -1; - } - - // Check the Wayland registry to determine if the DRM leasing protocol (wp_drm_lease_device_v1) is supported. If so, get the lease device and connector. - struct wl_registry *registry = wl_display_get_registry(display); - wl_registry_add_listener(registry, ®istry_listener, &state); - wl_display_dispatch(display); - wl_display_roundtrip(display); - - if (!state.lease_device) { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to acquire leasing device"); - return -1; - } - - if (!state.lease_connector) { - TRACELOG(LOG_WARNING, "DISPLAY: No connectors offered for lease"); - return -1; - } - - struct wp_drm_lease_request_v1 *req = wp_drm_lease_device_v1_create_lease_request(state.lease_device); - wp_drm_lease_request_v1_request_connector(req, state.lease_connector); - - struct wp_drm_lease_v1 *lease = wp_drm_lease_request_v1_submit(req); - wp_drm_lease_v1_add_listener(lease, &lease_listener, &fd); - wl_display_dispatch(display); - wl_display_roundtrip(display); - - if (fd < 0) { - TRACELOG(LOG_WARNING, "DISPLAY: DRM file descriptor is not set. Cannot use DRM leased value"); - return -1; - } - - return fd; - } -#endif - -// Get the DRM device's file descriptor -int GetDRMFD(void) -{ - int fd; - - #if defined(ENABLE_WAYLAND_DRM_LEASING) - TRACELOG(LOG_INFO, "DISPLAY: Attempting Wayland DRM leasing"); - fd = GetDRMFDViaWaylandLeasing(); - - if (fd != -1) - { - TRACELOG(LOG_INFO, "DISPLAY: Leased DRM device opened successfully"); - platform.usingDRMLeasing = true; - return fd; - } - #endif - - #if defined(DEFAULT_GRAPHIC_DEVICE_DRM) - fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); - - if (fd != -1) - { - TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully"); - return fd; - } - #else - TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card"); - fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) - - if (fd != -1) - { - TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully"); - return fd; - } - - if (drmModeGetResources(fd) == NULL) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1"); - fd = open("/dev/dri/card1", O_RDWR); // Other Embedded - - if (fd != -1) - { - TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully"); - return fd; - } - } - - if (drmModeGetResources(fd) == NULL) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0"); - fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) - - if (fd != -1) - { - TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully"); - return fd; - } - } - #endif - - return fd; -} - -// Initialize platform: graphics, inputs and more -int InitPlatform(void) -{ - platform.fd = GetDRMFD(); - platform.connector = NULL; - platform.modeIndex = -1; - platform.crtc = NULL; - platform.gbmDevice = NULL; - platform.gbmSurface = NULL; - platform.prevBO = NULL; - platform.prevFB = 0; - - // Initialize graphic device: display/window and graphic context - //---------------------------------------------------------------------------- - CORE.Window.fullscreen = true; - CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - - if (platform.fd == -1) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card"); - return -1; - } - - drmModeRes *res = drmModeGetResources(platform.fd); - if (!res) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources"); - return -1; - } - - TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors); - - for (size_t i = 0; i < res->count_connectors; i++) - { - TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i); - - drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]); - TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); - - // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected. - // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output. - #if defined(ENABLE_WAYLAND_DRM_LEASING) - if (platform.usingDRMLeasing) - { - if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION))) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); - platform.connector = con; - break; - } - else - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); - drmModeFreeConnector(con); - } - } - else - { - if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); - platform.connector = con; - break; - } - else - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); - drmModeFreeConnector(con); - } - } - #else - if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); - platform.connector = con; - break; - } - else - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); - drmModeFreeConnector(con); - } - #endif - } - - if (!platform.connector) - { - TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found"); - drmModeFreeResources(res); - return -1; - } - - #if defined(ENABLE_WAYLAND_DRM_LEASING) - drmModeEncoder *enc = NULL; - - if (platform.usingDRMLeasing) - { - drmModeResPtr drm_resources = drmModeGetResources(platform.fd); - - if (!drm_resources) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM resources"); - drmModeFreeResources(res); - return -1; - } - - if (res->count_crtcs == 0) - { - TRACELOG(LOG_WARNING, "DISPLAY: No CRTCs found for display"); - } - - for (size_t i = 0; i < res->count_crtcs; ++i) - { - platform.crtc = drmModeGetCrtc(platform.fd, res->crtcs[i]); - - if (!platform.crtc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); - drmModeFreeResources(drm_resources); - drmModeFreeResources(res); - return -1; - } - } - - if (!platform.crtc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); - drmModeFreeResources(drm_resources); - drmModeFreeResources(res); - return -1; - } - } - else - { - enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); - if (!enc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); - drmModeFreeResources(res); - return -1; - } - - platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id); - if (!platform.crtc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); - drmModeFreeEncoder(enc); - drmModeFreeResources(res); - return -1; - } - } - #else - drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); - if (!enc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); - drmModeFreeResources(res); - return -1; - } - - platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id); - if (!platform.crtc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); - drmModeFreeEncoder(enc); - drmModeFreeResources(res); - return -1; - } - #endif - - // If InitWindow should use the current mode find it in the connector's mode list - if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0)) - { - TRACELOG(LOG_TRACE, "DISPLAY: Selecting DRM connector mode for current used mode..."); - - platform.modeIndex = FindMatchingConnectorMode(platform.connector, &platform.crtc->mode); - - if (platform.modeIndex < 0) - { - TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found"); - #if defined(ENABLE_WAYLAND_DRM_LEASING) - if (!platform.usingDRMLeasing) drmModeFreeEncoder(enc); - #else - drmModeFreeEncoder(enc); - #endif - drmModeFreeResources(res); - return -1; - } - - CORE.Window.screen.width = CORE.Window.display.width; - CORE.Window.screen.height = CORE.Window.display.height; - } - - const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT; - const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60; - - // Try to find an exact matching mode - platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); - - // If nothing found, try to find a nearly matching mode - if (platform.modeIndex < 0) platform.modeIndex = FindNearestConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); - - // If nothing found, try to find an exactly matching mode including interlaced - if (platform.modeIndex < 0) platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); - - // If nothing found, try to find a nearly matching mode including interlaced - if (platform.modeIndex < 0) platform.modeIndex = FindNearestConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); - - // If nothing found, there is no suitable mode - if (platform.modeIndex < 0) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode"); - #if defined(ENABLE_WAYLAND_DRM_LEASING) - if (!platform.usingDRMLeasing) drmModeFreeEncoder(enc); - #else - drmModeFreeEncoder(enc); - #endif - drmModeFreeResources(res); - return -1; - } - - CORE.Window.display.width = platform.connector->modes[platform.modeIndex].hdisplay; - CORE.Window.display.height = platform.connector->modes[platform.modeIndex].vdisplay; - - TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name, - platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay, - (platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p', - platform.connector->modes[platform.modeIndex].vrefresh); - - // Use the width and height of the surface for render - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - - #if defined(ENABLE_WAYLAND_DRM_LEASING) - if (!platform.usingDRMLeasing) - { - drmModeFreeEncoder(enc); - enc = NULL; - } - #else - drmModeFreeEncoder(enc); - enc = NULL; - #endif - - drmModeFreeResources(res); - res = NULL; - - platform.gbmDevice = gbm_create_device(platform.fd); - if (!platform.gbmDevice) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM device"); - return -1; - } - - platform.gbmSurface = gbm_surface_create(platform.gbmDevice, platform.connector->modes[platform.modeIndex].hdisplay, - platform.connector->modes[platform.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!platform.gbmSurface) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM surface"); - return -1; - } - - EGLint samples = 0; - EGLint sampleBuffer = 0; - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - samples = 4; - sampleBuffer = 1; - TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); - } - - const EGLint framebufferAttribs[] = - { - EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! - EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) - EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) - EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) - EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer) - //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) - EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) - //EGL_STENCIL_SIZE, 8, // Stencil buffer size - EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA - EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) - EGL_NONE - }; - - const EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - EGLint numConfigs = 0; - - // Get an EGL device connection - platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice); - if (platform.device == EGL_NO_DISPLAY) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); - return -1; - } - - // Initialize the EGL device connection - if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE) - { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); - return -1; - } - - if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError()); - return -1; - } - - TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs); - - EGLConfig *configs = (EGLConfig *)RL_CALLOC(numConfigs, sizeof(*configs)); - if (!configs) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs"); - return -1; - } - - EGLint matchingNumConfigs = 0; - if (!eglChooseConfig(platform.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError()); - free(configs); - return -1; - } - - TRACELOG(LOG_TRACE, "DISPLAY: EGL matching configs available: %d", matchingNumConfigs); - - // find the EGL config that matches the previously setup GBM format - int found = 0; - for (EGLint i = 0; i < matchingNumConfigs; ++i) - { - EGLint id = 0; - if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config attribute: 0x%x", eglGetError()); - continue; - } - - if (GBM_FORMAT_ARGB8888 == id) - { - TRACELOG(LOG_TRACE, "DISPLAY: Using EGL config: %d", i); - platform.config = configs[i]; - found = 1; - break; - } - } - - RL_FREE(configs); - - if (!found) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable EGL config"); - return -1; - } - - // Set rendering API - eglBindAPI(EGL_OPENGL_ES_API); - - // Create an EGL rendering context - platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs); - if (platform.context == EGL_NO_CONTEXT) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); - return -1; - } - - // Create an EGL window surface - platform.surface = eglCreateWindowSurface(platform.device, platform.config, (EGLNativeWindowType)platform.gbmSurface, NULL); - if (EGL_NO_SURFACE == platform.surface) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError()); - return -1; - } - - // At this point we need to manage render size vs screen size - // NOTE: This function use and modify global module variables: - // -> CORE.Window.screen.width/CORE.Window.screen.height - // -> CORE.Window.render.width/CORE.Window.render.height - // -> CORE.Window.screenScale - SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - - // There must be at least one frame displayed before the buffers are swapped - //eglSwapInterval(platform.device, 1); - - EGLBoolean result = eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context); - - // Check surface and context activation - if (result != EGL_FALSE) - { - CORE.Window.ready = true; - - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.currentFbo.width = CORE.Window.render.width; - CORE.Window.currentFbo.height = CORE.Window.render.height; - - TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); - TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); - TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); - TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); - } - else - { - TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device"); - return -1; - } - - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow(); - - // If graphic device is no properly initialized, we end program - if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; } - else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2); - - // Set some default window flags - CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false - CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false - CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true - CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false - - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - rlLoadExtensions(eglGetProcAddress); - //---------------------------------------------------------------------------- - - // Initialize timming system - //---------------------------------------------------------------------------- - // NOTE: timming system must be initialized before the input events system - InitTimer(); - //---------------------------------------------------------------------------- - - // Initialize input events system - //---------------------------------------------------------------------------- - InitEvdevInput(); // Evdev inputs initialization - -#if defined(SUPPORT_SSH_KEYBOARD_RPI) - InitKeyboard(); // Keyboard init (stdin) -#endif - //---------------------------------------------------------------------------- - - // Initialize storage system - //---------------------------------------------------------------------------- - CORE.Storage.basePath = GetWorkingDirectory(); - //---------------------------------------------------------------------------- - - TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized successfully"); - - return 0; -} - -// Close platform -void ClosePlatform(void) -{ - if (platform.prevFB) - { - drmModeRmFB(platform.fd, platform.prevFB); - platform.prevFB = 0; - } - - if (platform.prevBO) - { - gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); - platform.prevBO = NULL; - } - - if (platform.gbmSurface) - { - gbm_surface_destroy(platform.gbmSurface); - platform.gbmSurface = NULL; - } - - if (platform.gbmDevice) - { - gbm_device_destroy(platform.gbmDevice); - platform.gbmDevice = NULL; - } - - if (platform.crtc) - { - if (platform.connector) - { - drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, platform.crtc->buffer_id, - platform.crtc->x, platform.crtc->y, &platform.connector->connector_id, 1, &platform.crtc->mode); - drmModeFreeConnector(platform.connector); - platform.connector = NULL; - } - - drmModeFreeCrtc(platform.crtc); - platform.crtc = NULL; - } - - if (platform.fd != -1) - { - close(platform.fd); - platform.fd = -1; - } - - // Close surface, context and display - if (platform.device != EGL_NO_DISPLAY) - { - if (platform.surface != EGL_NO_SURFACE) - { - eglDestroySurface(platform.device, platform.surface); - platform.surface = EGL_NO_SURFACE; - } - - if (platform.context != EGL_NO_CONTEXT) - { - eglDestroyContext(platform.device, platform.context); - platform.context = EGL_NO_CONTEXT; - } - - eglTerminate(platform.device); - platform.device = EGL_NO_DISPLAY; - } - - CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called - - // Close the evdev devices - - if (platform.mouseFd != -1) - { - close(platform.mouseFd); - platform.mouseFd = -1; - } - - for (int i = 0; i < platform.gamepadCount; i++) - { - close(platform.gamepadStreamFd[i]); - platform.gamepadStreamFd[i] = -1; - } - - if (platform.keyboardFd != -1) - { - close(platform.keyboardFd); - platform.keyboardFd = -1; - } -} - -#if defined(SUPPORT_SSH_KEYBOARD_RPI) -// Initialize Keyboard system (using standard input) -static void InitKeyboard(void) -{ - // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor, - // Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE - - // Save terminal keyboard settings - tcgetattr(STDIN_FILENO, &platform.defaultSettings); - - // Reconfigure terminal with new settings - struct termios keyboardNewSettings = { 0 }; - keyboardNewSettings = platform.defaultSettings; - - // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing - // NOTE: ISIG controls if ^C and ^Z generate break signals or not - keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG); - //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF); - keyboardNewSettings.c_cc[VMIN] = 1; - keyboardNewSettings.c_cc[VTIME] = 0; - - // Set new keyboard settings (change occurs immediately) - tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings); - - // Save old keyboard mode to restore it at the end - platform.defaultFileFlags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags - fcntl(STDIN_FILENO, F_SETFL, platform.defaultFileFlags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified - - // NOTE: If ioctl() returns -1, it means the call failed for some reason (error code set in errno) - int result = ioctl(STDIN_FILENO, KDGKBMODE, &platform.defaultKeyboardMode); - - // In case of failure, it could mean a remote keyboard is used (SSH) - if (result < 0) TRACELOG(LOG_WARNING, "DRM: Failed to change keyboard mode, an SSH keyboard is probably used"); - else - { - // Reconfigure keyboard mode to get: - // - scancodes (K_RAW) - // - keycodes (K_MEDIUMRAW) - // - ASCII chars (K_XLATE) - // - UNICODE chars (K_UNICODE) - ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE); // ASCII chars - } - - // Register keyboard restore when program finishes - atexit(RestoreKeyboard); -} - -// Restore default keyboard input -static void RestoreKeyboard(void) -{ - // Reset to default keyboard settings - tcsetattr(STDIN_FILENO, TCSANOW, &platform.defaultSettings); - - // Reconfigure keyboard to default mode - fcntl(STDIN_FILENO, F_SETFL, platform.defaultFileFlags); - ioctl(STDIN_FILENO, KDSKBMODE, platform.defaultKeyboardMode); -} - -// Process keyboard inputs -static void ProcessKeyboard(void) -{ - #define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read - - // Keyboard input polling (fill keys[256] array with status) - int bufferByteCount = 0; // Bytes available on the buffer - char keysBuffer[MAX_KEYBUFFER_SIZE] = { 0 }; // Max keys to be read at a time - - // Read availables keycodes from stdin - bufferByteCount = read(STDIN_FILENO, keysBuffer, MAX_KEYBUFFER_SIZE); // POSIX system call - - // Reset pressed keys array (it will be filled below) - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.currentKeyState[i] = 0; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Fill all read bytes (looking for keys) - for (int i = 0; i < bufferByteCount; i++) - { - // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code! - // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42 - if (keysBuffer[i] == 0x1b) - { - // Check if ESCAPE key has been pressed to stop program - if (bufferByteCount == 1) CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] = 1; - else - { - if (keysBuffer[i + 1] == 0x5b) // Special function key - { - if ((keysBuffer[i + 2] == 0x5b) || (keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) - { - // Process special function keys (F1 - F12) - switch (keysBuffer[i + 3]) - { - case 0x41: CORE.Input.Keyboard.currentKeyState[290] = 1; break; // raylib KEY_F1 - case 0x42: CORE.Input.Keyboard.currentKeyState[291] = 1; break; // raylib KEY_F2 - case 0x43: CORE.Input.Keyboard.currentKeyState[292] = 1; break; // raylib KEY_F3 - case 0x44: CORE.Input.Keyboard.currentKeyState[293] = 1; break; // raylib KEY_F4 - case 0x45: CORE.Input.Keyboard.currentKeyState[294] = 1; break; // raylib KEY_F5 - case 0x37: CORE.Input.Keyboard.currentKeyState[295] = 1; break; // raylib KEY_F6 - case 0x38: CORE.Input.Keyboard.currentKeyState[296] = 1; break; // raylib KEY_F7 - case 0x39: CORE.Input.Keyboard.currentKeyState[297] = 1; break; // raylib KEY_F8 - case 0x30: CORE.Input.Keyboard.currentKeyState[298] = 1; break; // raylib KEY_F9 - case 0x31: CORE.Input.Keyboard.currentKeyState[299] = 1; break; // raylib KEY_F10 - case 0x33: CORE.Input.Keyboard.currentKeyState[300] = 1; break; // raylib KEY_F11 - case 0x34: CORE.Input.Keyboard.currentKeyState[301] = 1; break; // raylib KEY_F12 - default: break; - } - - if (keysBuffer[i + 2] == 0x5b) i += 4; - else if ((keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) i += 5; - } - else - { - switch (keysBuffer[i + 2]) - { - case 0x41: CORE.Input.Keyboard.currentKeyState[265] = 1; break; // raylib KEY_UP - case 0x42: CORE.Input.Keyboard.currentKeyState[264] = 1; break; // raylib KEY_DOWN - case 0x43: CORE.Input.Keyboard.currentKeyState[262] = 1; break; // raylib KEY_RIGHT - case 0x44: CORE.Input.Keyboard.currentKeyState[263] = 1; break; // raylib KEY_LEFT - default: break; - } - - i += 3; // Jump to next key - } - - // NOTE: Some keys are not directly keymapped (CTRL, ALT, SHIFT) - } - } - } - else if (keysBuffer[i] == 0x0a) // raylib KEY_ENTER (don't mix with KEY_*) - { - CORE.Input.Keyboard.currentKeyState[257] = 1; - - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 257; // Add keys pressed into queue - CORE.Input.Keyboard.keyPressedQueueCount++; - } - else if (keysBuffer[i] == 0x7f) // raylib KEY_BACKSPACE - { - CORE.Input.Keyboard.currentKeyState[259] = 1; - - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 257; // Add keys pressed into queue - CORE.Input.Keyboard.keyPressedQueueCount++; - } - else - { - // Translate lowercase a-z letters to A-Z - if ((keysBuffer[i] >= 97) && (keysBuffer[i] <= 122)) - { - CORE.Input.Keyboard.currentKeyState[(int)keysBuffer[i] - 32] = 1; - } - else CORE.Input.Keyboard.currentKeyState[(int)keysBuffer[i]] = 1; - - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keysBuffer[i]; // Add keys pressed into queue - CORE.Input.Keyboard.keyPressedQueueCount++; - } - } -} -#endif // SUPPORT_SSH_KEYBOARD_RPI - -// Initialise user input from evdev(/dev/input/event) -// this means mouse, keyboard or gamepad devices -static void InitEvdevInput(void) -{ - #if !defined(DISABLE_EVDEV_INPUT) - char path[MAX_FILEPATH_LENGTH] = { 0 }; - DIR *directory = NULL; - struct dirent *entity = NULL; - - // Initialise keyboard file descriptor - platform.keyboardFd = -1; - platform.mouseFd = -1; - - // Reset variables - for (int i = 0; i < MAX_TOUCH_POINTS; ++i) - { - CORE.Input.Touch.position[i].x = -1; - CORE.Input.Touch.position[i].y = -1; - } - - // Reset keyboard key state - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.currentKeyState[i] = 0; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Open the linux directory of "/dev/input" - directory = opendir(DEFAULT_EVDEV_PATH); - - if (directory) - { - while ((entity = readdir(directory)) != NULL) - { - if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*" - (strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*" - { - sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name); - ConfigureEvdevDevice(path); // Configure the device if appropriate - } - } - - closedir(directory); - } - else TRACELOG(LOG_WARNING, "INPUT: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH); - #else - TRACELOG(LOG_INFO, "INPUT: Not doing evdev input configuration as it's disabled"); - platform.keyboardFd = -1; - platform.mouseFd = -1; - #endif -} - -// Identifies a input device and configures it for use if appropriate -static void ConfigureEvdevDevice(char *device) -{ - #define BITS_PER_LONG (8*sizeof(long)) - #define NBITS(x) ((((x) - 1)/BITS_PER_LONG) + 1) - #define OFF(x) ((x)%BITS_PER_LONG) - #define BIT(x) (1UL<> OFF(bit)) & 1) - - unsigned long evBits[NBITS(EV_MAX)] = { 0 }; - unsigned long absBits[NBITS(ABS_MAX)] = { 0 }; - unsigned long relBits[NBITS(REL_MAX)] = { 0 }; - unsigned long keyBits[NBITS(KEY_MAX)] = { 0 }; - - // Open the device - int fd = open(device, O_RDONLY | O_NONBLOCK); - if (fd < 0) - { - TRACELOG(LOG_WARNING, "SYSTEM: Failed to open input device: %s", device); - return; - } - - // At this point we have a connection to the device, but we don't yet know what the device is. - // It could be many things, even as simple as a power button... - //------------------------------------------------------------------------------------------------------- - - // Identify the device - //------------------------------------------------------------------------------------------------------- - struct { - bool exist; - struct input_absinfo info; - } absinfo[ABS_CNT] = { 0 }; - - // These flags aren't really a one of - // Some devices could have properties we assosciate with keyboards as well as properties - // we assosciate with mice - bool isKeyboard = false; - bool isMouse = false; - bool isTouch = false; - bool isGamepad = false; - - int absAxisCount = 0; - - ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); - ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits); - - if (TEST_BIT(evBits, EV_ABS)) - { - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits); - - // If the device has an X an Y axis it's either a touch device, a special mouse or a gamepad - bool hasAbsXY = TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y); - - if (hasAbsXY) - { - absAxisCount += 2; - - absinfo[ABS_X].exist = true; - absinfo[ABS_Y].exist = true; - - ioctl(fd, EVIOCGABS(ABS_X), &absinfo[ABS_X].info); - ioctl(fd, EVIOCGABS(ABS_Y), &absinfo[ABS_Y].info); - } - - // If it has any of these buttons it's a touch device - if (hasAbsXY && - (TEST_BIT(keyBits, BTN_STYLUS) || - TEST_BIT(keyBits, BTN_TOOL_PEN) || - TEST_BIT(keyBits, BTN_TOOL_FINGER) || - TEST_BIT(keyBits, BTN_TOUCH))) isTouch = true; - - // Absolute mice should really only exist with VMWare, but it shouldn't - // matter if we support them - else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true; - - // If any of the common joystick axes are present, we assume it's a gamepad - else - { - for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++) - { - if (TEST_BIT(absBits, axis)) - { - absinfo[axis].exist = true; - isGamepad = true; - absAxisCount++; - - ioctl(fd, EVIOCGABS(axis), &absinfo[axis].info); - } - } - } - - // If the device has multitouch axes, it's a touch device - if (TEST_BIT(absBits, ABS_MT_POSITION_X) && - TEST_BIT(absBits, ABS_MT_POSITION_Y)) isTouch = true; - } - - if (TEST_BIT(evBits, EV_REL)) - { - ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits); - - // If it has any of the gamepad or touch features we tested so far, it's not a mouse - if (!isTouch && - !isGamepad && - TEST_BIT(relBits, REL_X) && - TEST_BIT(relBits, REL_Y) && - TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true; - } - - if (TEST_BIT(evBits, EV_KEY)) - { - // The first 32 keys as defined in input-event-codes.h are pretty much - // exclusive to keyboards, so we can test them using a mask - // Leave out the first bit to not test KEY_RESERVED - const unsigned long mask = 0xFFFFFFFE; - if ((keyBits[0] & mask) == mask) isKeyboard = true; - - // If we find any of the common gamepad buttons we assume it's a gamepad - else - { - for (int button = BTN_JOYSTICK; button < BTN_DIGI; ++button) - { - if (TEST_BIT(keyBits, button)) isGamepad = true; - } - - for (int button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40; button++) - { - if (TEST_BIT(keyBits, button)) isGamepad = true; - } - } - } - - const char *deviceKindStr = "unknown"; - if (isMouse || isTouch) - { - deviceKindStr = "mouse"; - if (platform.mouseFd != -1) close(platform.mouseFd); - platform.mouseFd = fd; - - if (absAxisCount > 0) - { - platform.absRange.x = absinfo[ABS_X].info.minimum; - platform.absRange.width = absinfo[ABS_X].info.maximum - absinfo[ABS_X].info.minimum; - - platform.absRange.y = absinfo[ABS_Y].info.minimum; - platform.absRange.height = absinfo[ABS_Y].info.maximum - absinfo[ABS_Y].info.minimum; - } - } - else if (isGamepad && !isMouse && !isKeyboard && (platform.gamepadCount < MAX_GAMEPADS)) - { - deviceKindStr = "gamepad"; - int index = platform.gamepadCount++; - - platform.gamepadStreamFd[index] = fd; - CORE.Input.Gamepad.ready[index] = true; - - ioctl(platform.gamepadStreamFd[index], EVIOCGNAME(64), &CORE.Input.Gamepad.name[index]); - CORE.Input.Gamepad.axisCount[index] = absAxisCount; - - if (absAxisCount > 0) - { - // TODO / NOTE - // So gamepad axes (as in the actual linux joydev.c) are just simply enumerated - // and (at least for some input drivers like xpat) it's convention to use - // ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the - // shoulder buttons - // If these are now enumerated you get LJOY_X, LJOY_Y, LEFT_SHOULDERB, RJOY_X, ... - // That means they don't match the GamepadAxis enum - // This could be fixed - int axisIndex = 0; - for (int axis = ABS_X; axis < ABS_PRESSURE; axis++) - { - if (absinfo[axis].exist) - { - platform.gamepadAbsAxisRange[index][axisIndex][0] = absinfo[axisIndex].info.minimum; - platform.gamepadAbsAxisRange[index][axisIndex][1] = absinfo[axisIndex].info.maximum - absinfo[axisIndex].info.minimum; - - platform.gamepadAbsAxisMap[index][axis] = axisIndex; - axisIndex++; - } - } - } - } - else if (isKeyboard && (platform.keyboardFd == -1)) - { - deviceKindStr = "keyboard"; - platform.keyboardFd = fd; - } - else - { - close(fd); - return; - } - - TRACELOG(LOG_INFO, "INPUT: Initialized input device %s as %s", device, deviceKindStr); -} - -// Poll and process evdev keyboard events -static void PollKeyboardEvents(void) -{ - int fd = platform.keyboardFd; - if (fd == -1) return; - - struct input_event event = { 0 }; - int keycode = -1; - - // Try to read data from the keyboard and only continue if successful - while (read(fd, &event, sizeof(event)) == (int)sizeof(event)) - { - // Check if the event is a key event - if (event.type != EV_KEY) continue; - -#if defined(SUPPORT_SSH_KEYBOARD_RPI) - // If the event was a key, we know a working keyboard is connected, so disable the SSH keyboard - platform.eventKeyboardMode = true; -#endif - - // Keyboard keys appear for codes 1 to 255, ignore everthing else - if ((event.code >= 1) && (event.code <= 255)) - { - - // Lookup the scancode in the keymap to get a keycode - keycode = linuxToRaylibMap[event.code]; - - // Make sure we got a valid keycode - if ((keycode > 0) && (keycode < MAX_KEYBOARD_KEYS)) - { - - // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt - // Event interface: 'value' is the value the event carries. Either a relative change for EV_REL, - // absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat - CORE.Input.Keyboard.currentKeyState[keycode] = (event.value >= 1); - CORE.Input.Keyboard.keyRepeatInFrame[keycode] = (event.value == 2); - - // If the key is pressed add it to the queues - if (event.value == 1) - { - if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) - { - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - - if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) - { - // TODO/FIXME: This is not actually converting to unicode properly because it's not taking things like shift into account - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = evkeyToUnicodeLUT[event.code]; - CORE.Input.Keyboard.charPressedQueueCount++; - } - } - - TRACELOG(LOG_DEBUG, "INPUT: KEY_%s Keycode(linux): %4i KeyCode(raylib): %4i", (event.value == 0)? "UP " : "DOWN", event.code, keycode); - } - } - } -} - -// Poll gamepad input events -static void PollGamepadEvents(void) -{ - // Read gamepad event - struct input_event event = { 0 }; - - for (int i = 0; i < platform.gamepadCount; i++) - { - if (!CORE.Input.Gamepad.ready[i]) continue; - - // Register previous gamepad states - for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; - - while (read(platform.gamepadStreamFd[i], &event, sizeof(event)) == (int)sizeof(event)) - { - if (event.type == EV_KEY) - { - if (event.code < KEYMAP_SIZE) - { - short keycodeRaylib = linuxToRaylibMap[event.code]; - - TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: KEY_%s Keycode(linux): %4i Keycode(raylib): %4i", i, (event.value == 0)? "UP" : "DOWN", event.code, keycodeRaylib); - - if ((keycodeRaylib != 0) && (keycodeRaylib < MAX_GAMEPAD_BUTTONS)) - { - // 1 - button pressed, 0 - button released - CORE.Input.Gamepad.currentButtonState[i][keycodeRaylib] = event.value; - - CORE.Input.Gamepad.lastButtonPressed = (event.value == 1)? keycodeRaylib : GAMEPAD_BUTTON_UNKNOWN; - } - } - } - else if (event.type == EV_ABS) - { - if (event.code < ABS_CNT) - { - int axisRaylib = platform.gamepadAbsAxisMap[i][event.code]; - - TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value); - - if (axisRaylib < MAX_GAMEPAD_AXES) - { - int min = platform.gamepadAbsAxisRange[i][event.code][0]; - int range = platform.gamepadAbsAxisRange[i][event.code][1]; - - // NOTE: Scaling of event.value to get values between -1..1 - CORE.Input.Gamepad.axisState[i][axisRaylib] = (2*(float)(event.value - min)/range) - 1; - } - } - } - } - } -} - -// Poll mouse input events -static void PollMouseEvents(void) -{ - int fd = platform.mouseFd; - if (fd == -1) return; - - struct input_event event = { 0 }; - int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE - - // Try to read data from the mouse/touch/gesture and only continue if successful - while (read(fd, &event, sizeof(event)) == (int)sizeof(event)) - { - // Relative movement parsing - if (event.type == EV_REL) - { - if (event.code == REL_X) - { - if (platform.cursorRelative) - { - CORE.Input.Mouse.currentPosition.x = event.value; - CORE.Input.Mouse.previousPosition.x = 0.0f; - } - else CORE.Input.Mouse.currentPosition.x += event.value; - - CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x; - touchAction = 2; // TOUCH_ACTION_MOVE - } - - if (event.code == REL_Y) - { - if (platform.cursorRelative) - { - CORE.Input.Mouse.currentPosition.y = event.value; - CORE.Input.Mouse.previousPosition.y = 0.0f; - } - else CORE.Input.Mouse.currentPosition.y += event.value; - - CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y; - touchAction = 2; // TOUCH_ACTION_MOVE - } - - if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value; - } - - // Absolute movement parsing - if (event.type == EV_ABS) - { - // Basic movement - if (event.code == ABS_X) - { - CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange - CORE.Input.Touch.position[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange - - touchAction = 2; // TOUCH_ACTION_MOVE - } - - if (event.code == ABS_Y) - { - CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange - CORE.Input.Touch.position[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange - - touchAction = 2; // TOUCH_ACTION_MOVE - } - - // Multitouch movement - if (event.code == ABS_MT_SLOT) platform.touchSlot = event.value; // Remember the slot number for the folowing events - - if (event.code == ABS_MT_POSITION_X) - { - if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange - } - - if (event.code == ABS_MT_POSITION_Y) - { - if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange - } - - if (event.code == ABS_MT_TRACKING_ID) - { - if ((event.value < 0) && (platform.touchSlot < MAX_TOUCH_POINTS)) - { - // Touch has ended for this point - CORE.Input.Touch.position[platform.touchSlot].x = -1; - CORE.Input.Touch.position[platform.touchSlot].y = -1; - } - } - - // Touchscreen tap - if (event.code == ABS_PRESSURE) - { - int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT]; - - if (!event.value && previousMouseLeftButtonState) - { - platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0; - touchAction = 0; // TOUCH_ACTION_UP - } - - if (event.value && !previousMouseLeftButtonState) - { - platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1; - touchAction = 1; // TOUCH_ACTION_DOWN - } - } - - } - - // Button parsing - if (event.type == EV_KEY) - { - // Mouse button parsing - if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT)) - { - platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value; - - if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN - else touchAction = 0; // TOUCH_ACTION_UP - } - - if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value; - if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value; - if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value; - if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value; - if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value; - if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value; - } - - // Screen confinement - if (!CORE.Input.Mouse.cursorHidden) - { - if (CORE.Input.Mouse.currentPosition.x < 0) CORE.Input.Mouse.currentPosition.x = 0; - if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x; - - if (CORE.Input.Mouse.currentPosition.y < 0) CORE.Input.Mouse.currentPosition.y = 0; - if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y; - } - - // Update touch point count - CORE.Input.Touch.pointCount = 0; - for (int i = 0; i < MAX_TOUCH_POINTS; i++) - { - if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++; - } - -#if defined(SUPPORT_GESTURES_SYSTEM) - if (touchAction > -1) - { - GestureEvent gestureEvent = { 0 }; - - gestureEvent.touchAction = touchAction; - gestureEvent.pointCount = CORE.Input.Touch.pointCount; - - for (int i = 0; i < MAX_TOUCH_POINTS; i++) - { - gestureEvent.pointId[i] = i; - gestureEvent.position[i] = CORE.Input.Touch.position[i]; - } - - ProcessGestureEvent(gestureEvent); - - touchAction = -1; - } -#endif - } -} - -// Search matching DRM mode in connector's mode list -static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode) -{ - if (NULL == connector) return -1; - if (NULL == mode) return -1; - - // safe bitwise comparison of two modes - #define BINCMP(a, b) memcmp((a), (b), (sizeof(a) < sizeof(b))? sizeof(a) : sizeof(b)) - - for (size_t i = 0; i < connector->count_modes; i++) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay, - connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive"); - - if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i; - } - - return -1; - - #undef BINCMP -} - -// Search exactly matching DRM connector mode in connector's list -static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced) -{ - TRACELOG(LOG_TRACE, "DISPLAY: Searching exact connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s", width, height, fps, allowInterlaced? "yes" : "no"); - - if (NULL == connector) return -1; - - for (int i = 0; i < platform.connector->count_modes; i++) - { - const drmModeModeInfo *const mode = &platform.connector->modes[i]; - - TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive"); - - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced) continue; - - if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i; - } - - TRACELOG(LOG_TRACE, "DISPLAY: No DRM exact matching mode found"); - return -1; -} - -// Search the nearest matching DRM connector mode in connector's list -static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced) -{ - TRACELOG(LOG_TRACE, "DISPLAY: Searching nearest connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s", width, height, fps, allowInterlaced? "yes" : "no"); - - if (NULL == connector) return -1; - - int nearestIndex = -1; - for (int i = 0; i < platform.connector->count_modes; i++) - { - const drmModeModeInfo *const mode = &platform.connector->modes[i]; - - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, - (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive"); - - if ((mode->hdisplay < width) || (mode->vdisplay < height)) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode is too small"); - continue; - } - - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode"); - continue; - } - - if (nearestIndex < 0) - { - nearestIndex = i; - continue; - } - - const int widthDiff = abs(mode->hdisplay - width); - const int heightDiff = abs(mode->vdisplay - height); - const int fpsDiff = abs(mode->vrefresh - fps); - - const int nearestWidthDiff = abs(platform.connector->modes[nearestIndex].hdisplay - width); - const int nearestHeightDiff = abs(platform.connector->modes[nearestIndex].vdisplay - height); - const int nearestFpsDiff = abs(platform.connector->modes[nearestIndex].vrefresh - fps); - - if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) nearestIndex = i; - } - - return nearestIndex; -} - -// EOF diff --git a/raylib/platforms/vendor.go b/raylib/platforms/vendor.go deleted file mode 100644 index 0fb2a0f..0000000 --- a/raylib/platforms/vendor.go +++ /dev/null @@ -1,4 +0,0 @@ -//go:build required -// +build required - -package vendor diff --git a/raylib/purego_windows.go b/raylib/purego_windows.go deleted file mode 100644 index 35cb0ed..0000000 --- a/raylib/purego_windows.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build !cgo && windows -// +build !cgo,windows - -package rl - -import ( - "fmt" - "syscall" - "unsafe" - - "github.com/ebitengine/purego" - "golang.org/x/sys/windows" -) - -const ( - libname = "raylib.dll" - requiredVersion = "5.5" -) - -var wvsprintfA uintptr - -func init() { - handle, err := windows.LoadLibrary("user32.dll") - if err == nil { - wvsprintfA, _ = windows.GetProcAddress(handle, "wvsprintfA") - } -} - -// loadLibrary loads the raylib dll and panics on error -func loadLibrary() uintptr { - handle, err := windows.LoadLibrary(libname) - if err != nil { - panic(fmt.Errorf("cannot load library %s: %w", libname, err)) - } - - proc, err := windows.GetProcAddress(handle, "raylib_version") - if err != nil { - panic(err) - } - - version := windows.BytePtrToString(**(***byte)(unsafe.Pointer(&proc))) - if version != requiredVersion { - panic(fmt.Errorf("version %s of %s doesn't match the required version %s", version, libname, requiredVersion)) - } - - return uintptr(handle) -} - -func traceLogCallbackWrapper(fn TraceLogCallbackFun) uintptr { - return purego.NewCallback(func(logLevel int32, text *byte, args unsafe.Pointer) uintptr { - if wvsprintfA != 0 { - var buffer [1024]byte // Max size is 1024 (see https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wvsprintfa) - _, _, errno := syscall.SyscallN(wvsprintfA, uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(text)), uintptr(args)) - if errno == 0 { - text = &buffer[0] - } - } - fn(int(logLevel), windows.BytePtrToString(text)) - return 0 - }) -} diff --git a/raylib/raudio.c b/raylib/raudio.c index 0faf3ad..408dfb5 100644 --- a/raylib/raudio.c +++ b/raylib/raudio.c @@ -1,9 +1,8 @@ -//go:build !noaudio // +build !noaudio /********************************************************************************************** * -* raudio v1.1 - A simple and easy-to-use audio library based on miniaudio +* raudio v1.0 - A simple and easy-to-use audio library based on miniaudio * * FEATURES: * - Manage audio device (init/close) @@ -14,27 +13,23 @@ * - Play/Stop/Pause/Resume loaded audio * * CONFIGURATION: -* #define SUPPORT_MODULE_RAUDIO -* raudio module is included in the build * -* #define RAUDIO_STANDALONE -* Define to use the module as standalone library (independently of raylib). -* Required types and functions are defined in the same module. +* #define RAUDIO_STANDALONE +* Define to use the module as standalone library (independently of raylib). +* Required types and functions are defined in the same module. * -* #define SUPPORT_FILEFORMAT_WAV -* #define SUPPORT_FILEFORMAT_OGG -* #define SUPPORT_FILEFORMAT_MP3 -* #define SUPPORT_FILEFORMAT_QOA -* #define SUPPORT_FILEFORMAT_FLAC -* #define SUPPORT_FILEFORMAT_XM -* #define SUPPORT_FILEFORMAT_MOD -* Selected desired fileformats to be supported for loading. Some of those formats are -* supported by default, to remove support, just comment unrequired #define in this module +* #define SUPPORT_FILEFORMAT_WAV +* #define SUPPORT_FILEFORMAT_OGG +* #define SUPPORT_FILEFORMAT_XM +* #define SUPPORT_FILEFORMAT_MOD +* #define SUPPORT_FILEFORMAT_FLAC +* #define SUPPORT_FILEFORMAT_MP3 +* Selected desired fileformats to be supported for loading. Some of those formats are +* supported by default, to remove support, just comment unrequired #define in this module * * DEPENDENCIES: -* miniaudio.h - Audio device management lib (https://github.com/mackron/miniaudio) +* miniaudio.h - Audio device management lib (https://github.com/dr-soft/miniaudio) * stb_vorbis.h - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) -* dr_wav.h - WAV audio files loading (http://github.com/mackron/dr_libs) * dr_mp3.h - MP3 audio file loading (https://github.com/mackron/dr_libs) * dr_flac.h - FLAC audio file loading (https://github.com/mackron/dr_libs) * jar_xm.h - XM module file loading @@ -44,7 +39,7 @@ * David Reid (github: @mackron) (Nov. 2017): * - Complete port to miniaudio library * -* Joshua Reisenauer (github: @kd7tck) (2015): +* Joshua Reisenauer (github: @kd7tck) (2015) * - XM audio module support (jar_xm) * - MOD audio module support (jar_mod) * - Mixing channels support @@ -53,7 +48,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -74,18 +69,17 @@ #if defined(RAUDIO_STANDALONE) #include "raudio.h" + #include // Required for: va_list, va_start(), vfprintf(), va_end() #else #include "raylib.h" // Declares module functions - // Check if config flags have been externally provided on compilation line - #if !defined(EXTERNAL_CONFIG_FLAGS) - #include "config.h" // Defines module configuration flags - #endif +// Check if config flags have been externally provided on compilation line +#if !defined(EXTERNAL_CONFIG_FLAGS) + #include "config.h" // Defines module configuration flags +#endif #include "utils.h" // Required for: fopen() Android mapping #endif -#if defined(SUPPORT_MODULE_RAUDIO) - #if defined(_WIN32) // To avoid conflicting windows.h symbols with raylib, some flags are defined // WARNING: Those flags avoid inclusion of some Win32 headers that could be required @@ -136,7 +130,7 @@ // Type required before windows.h inclusion typedef struct tagMSG *LPMSG; -#include // Windows functionality (miniaudio) +#include // Type required by some unused function... typedef struct tagBITMAPINFOHEADER { @@ -153,9 +147,9 @@ typedef struct tagBITMAPINFOHEADER { DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; -#include // Component Object Model (COM) header -#include // Windows Multimedia, defines some WAVE structs -#include // Windows Multimedia, used by Windows GDI, defines DIBINDEX macro +#include +#include +#include // Some required types defined for MSVC/TinyC compiler #if defined(_MSC_VER) || defined(__TINYC__) @@ -170,43 +164,59 @@ typedef struct tagBITMAPINFOHEADER { #define MA_NO_WAV #define MA_NO_FLAC #define MA_NO_MP3 -#define MA_NO_RESOURCE_MANAGER -#define MA_NO_NODE_GRAPH -#define MA_NO_ENGINE -#define MA_NO_GENERATION - -// Threading model: Default: [0] COINIT_MULTITHREADED: COM calls objects on any thread (free threading) -#define MA_COINIT_VALUE 2 // [2] COINIT_APARTMENTTHREADED: Each object has its own thread (apartment model) - #define MINIAUDIO_IMPLEMENTATION //#define MA_DEBUG_OUTPUT -#include "external/miniaudio.h" // Audio device initialization and management +#include "external/miniaudio.h" // miniaudio library #undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro #include // Required for: malloc(), free() #include // Required for: FILE, fopen(), fclose(), fread() -#include // Required for: strcmp() [Used in IsFileExtension(), LoadWaveFromMemory(), LoadMusicStreamFromMemory()] #if defined(RAUDIO_STANDALONE) - #ifndef TRACELOG - #define TRACELOG(level, ...) printf(__VA_ARGS__) + #include // Required for: strcmp() [Used in IsFileExtension()] + + #if !defined(TRACELOG) + #define TRACELOG(level, ...) (void)0 #endif // Allow custom memory allocators #ifndef RL_MALLOC - #define RL_MALLOC(sz) malloc(sz) + #define RL_MALLOC(sz) malloc(sz) #endif #ifndef RL_CALLOC - #define RL_CALLOC(n,sz) calloc(n,sz) + #define RL_CALLOC(n,sz) calloc(n,sz) #endif #ifndef RL_REALLOC - #define RL_REALLOC(ptr,sz) realloc(ptr,sz) + #define RL_REALLOC(ptr,sz) realloc(ptr,sz) #endif #ifndef RL_FREE - #define RL_FREE(ptr) free(ptr) + #define RL_FREE(ptr) free(ptr) #endif #endif +#if defined(SUPPORT_FILEFORMAT_OGG) + // TODO: Remap malloc()/free() calls to RL_MALLOC/RL_FREE + + #define STB_VORBIS_IMPLEMENTATION + #include "external/stb_vorbis.h" // OGG loading functions +#endif + +#if defined(SUPPORT_FILEFORMAT_XM) + #define JARXM_MALLOC RL_MALLOC + #define JARXM_FREE RL_FREE + + #define JAR_XM_IMPLEMENTATION + #include "external/jar_xm.h" // XM loading functions +#endif + +#if defined(SUPPORT_FILEFORMAT_MOD) + #define JARMOD_MALLOC RL_MALLOC + #define JARMOD_FREE RL_FREE + + #define JAR_MOD_IMPLEMENTATION + #include "external/jar_mod.h" // MOD loading functions +#endif + #if defined(SUPPORT_FILEFORMAT_WAV) #define DRWAV_MALLOC RL_MALLOC #define DRWAV_REALLOC RL_REALLOC @@ -216,11 +226,6 @@ typedef struct tagBITMAPINFOHEADER { #include "external/dr_wav.h" // WAV loading functions #endif -#if defined(SUPPORT_FILEFORMAT_OGG) - // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE - #include "external/stb_vorbis.c" // OGG loading functions -#endif - #if defined(SUPPORT_FILEFORMAT_MP3) #define DRMP3_MALLOC RL_MALLOC #define DRMP3_REALLOC RL_REALLOC @@ -230,26 +235,6 @@ typedef struct tagBITMAPINFOHEADER { #include "external/dr_mp3.h" // MP3 loading functions #endif -#if defined(SUPPORT_FILEFORMAT_QOA) - #define QOA_MALLOC RL_MALLOC - #define QOA_FREE RL_FREE - - #if defined(_MSC_VER) // Disable some MSVC warning - #pragma warning(push) - #pragma warning(disable : 4018) - #pragma warning(disable : 4267) - #pragma warning(disable : 4244) - #endif - - #define QOA_IMPLEMENTATION - #include "external/qoa.h" // QOA loading and saving functions - #include "external/qoaplay.c" // QOA stream playing helper functions - - #if defined(_MSC_VER) - #pragma warning(pop) // Disable MSVC warning suppression - #endif -#endif - #if defined(SUPPORT_FILEFORMAT_FLAC) #define DRFLAC_MALLOC RL_MALLOC #define DRFLAC_REALLOC RL_REALLOC @@ -260,29 +245,8 @@ typedef struct tagBITMAPINFOHEADER { #include "external/dr_flac.h" // FLAC loading functions #endif -#if defined(SUPPORT_FILEFORMAT_XM) - #define JARXM_MALLOC RL_MALLOC - #define JARXM_FREE RL_FREE - - #if defined(_MSC_VER) // Disable some MSVC warning - #pragma warning(push) - #pragma warning(disable : 4244) - #endif - - #define JAR_XM_IMPLEMENTATION - #include "external/jar_xm.h" // XM loading functions - - #if defined(_MSC_VER) - #pragma warning(pop) // Disable MSVC warning suppression - #endif -#endif - -#if defined(SUPPORT_FILEFORMAT_MOD) - #define JARMOD_MALLOC RL_MALLOC - #define JARMOD_FREE RL_FREE - - #define JAR_MOD_IMPLEMENTATION - #include "external/jar_mod.h" // MOD loading functions +#if defined(_MSC_VER) + #undef bool #endif //---------------------------------------------------------------------------------- @@ -294,73 +258,71 @@ typedef struct tagBITMAPINFOHEADER { #ifndef AUDIO_DEVICE_CHANNELS #define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo #endif -#ifndef AUDIO_DEVICE_SAMPLE_RATE - #define AUDIO_DEVICE_SAMPLE_RATE 0 // Device output sample rate -#endif +#ifndef AUDIO_DEVICE_SAMPLE_RATE + #define AUDIO_DEVICE_SAMPLE_RATE 0 // Device output channels: stereo +#endif #ifndef MAX_AUDIO_BUFFER_POOL_CHANNELS #define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Audio pool channels #endif +#ifndef DEFAULT_AUDIO_BUFFER_SIZE + #define DEFAULT_AUDIO_BUFFER_SIZE 4096 // Default audio buffer size +#endif + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#if defined(RAUDIO_STANDALONE) -// Trace log level -// NOTE: Organized by priority level -typedef enum { - LOG_ALL = 0, // Display all logs - LOG_TRACE, // Trace logging, intended for internal use only - LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds - LOG_INFO, // Info logging, used for program execution info - LOG_WARNING, // Warning logging, used on recoverable failures - LOG_ERROR, // Error logging, used on unrecoverable failures - LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) - LOG_NONE // Disable logging -} TraceLogLevel; -#endif // Music context type // NOTE: Depends on data structure provided by the library // in charge of reading the different file types typedef enum { - MUSIC_AUDIO_NONE = 0, // No audio context loaded - MUSIC_AUDIO_WAV, // WAV audio context - MUSIC_AUDIO_OGG, // OGG audio context - MUSIC_AUDIO_FLAC, // FLAC audio context - MUSIC_AUDIO_MP3, // MP3 audio context - MUSIC_AUDIO_QOA, // QOA audio context - MUSIC_MODULE_XM, // XM module audio context - MUSIC_MODULE_MOD // MOD module audio context + MUSIC_AUDIO_NONE = 0, + MUSIC_AUDIO_WAV, + MUSIC_AUDIO_OGG, + MUSIC_AUDIO_FLAC, + MUSIC_AUDIO_MP3, + MUSIC_MODULE_XM, + MUSIC_MODULE_MOD } MusicContextType; +#if defined(RAUDIO_STANDALONE) +typedef enum { + LOG_ALL, + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARNING, + LOG_ERROR, + LOG_FATAL, + LOG_NONE +} TraceLogLevel; +#endif + // NOTE: Different logic is used when feeding data to the playback device -// depending on whether data is streamed (Music vs Sound) +// depending on whether or not data is streamed (Music vs Sound) typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; -// Audio buffer struct +// Audio buffer structure struct rAudioBuffer { ma_data_converter converter; // Audio data converter - AudioCallback callback; // Audio buffer callback for buffer filling on audio threads - rAudioProcessor *processor; // Audio processor - float volume; // Audio buffer volume float pitch; // Audio buffer pitch - float pan; // Audio buffer pan (0.0f to 1.0f) bool playing; // Audio buffer state: AUDIO_PLAYING bool paused; // Audio buffer state: AUDIO_PAUSED - bool looping; // Audio buffer looping, default to true for AudioStreams + bool looping; // Audio buffer looping, always true for AudioStreams int usage; // Audio buffer usage mode: STATIC or STREAM bool isSubBufferProcessed[2]; // SubBuffer processed (virtual double buffer) unsigned int sizeInFrames; // Total buffer size in frames unsigned int frameCursorPos; // Frame cursor position - unsigned int framesProcessed; // Total frames processed in this buffer (required for play timing) + unsigned int totalFramesProcessed; // Total frames processed in this buffer (required for play timing) unsigned char *data; // Data buffer, on music stream keeps filling @@ -368,14 +330,6 @@ struct rAudioBuffer { rAudioBuffer *prev; // Previous audio buffer on the list }; -// Audio processor struct -// NOTE: Useful to apply effects to an AudioBuffer -struct rAudioProcessor { - AudioCallback process; // Processor callback function - rAudioProcessor *next; // Next audio processor on the list - rAudioProcessor *prev; // Previous audio processor on the list -}; - #define AudioBuffer rAudioBuffer // HACK: To avoid CoreAudio (macOS) symbol collision // Audio data context @@ -385,15 +339,17 @@ typedef struct AudioData { ma_device device; // miniaudio device ma_mutex lock; // miniaudio mutex lock bool isReady; // Check if audio device is ready - size_t pcmBufferSize; // Pre-allocated buffer size - void *pcmBuffer; // Pre-allocated buffer to read audio data from file/memory } System; struct { AudioBuffer *first; // Pointer to first AudioBuffer in the list AudioBuffer *last; // Pointer to last AudioBuffer in the list int defaultSize; // Default audio buffer size for audio streams } Buffer; - rAudioProcessor *mixedProcessor; + struct { + unsigned int poolCounter; // AudioBuffer pointers pool counter + AudioBuffer *pool[MAX_AUDIO_BUFFER_POOL_CHANNELS]; // Multichannel AudioBuffer pointers pool + unsigned int channels[MAX_AUDIO_BUFFER_POOL_CHANNELS]; // AudioBuffer pool channels + } MultiChannel; } AudioData; //---------------------------------------------------------------------------------- @@ -405,34 +361,38 @@ static AudioData AUDIO = { // Global AUDIO context // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a // standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough // In case of music-stalls, just increase this number - .Buffer.defaultSize = 0, - .mixedProcessor = NULL + .Buffer.defaultSize = 0 }; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static void OnLog(void *pUserData, ma_uint32 level, const char *pMessage); - -// Reads audio data from an AudioBuffer object in internal/device formats -static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount); -static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount); - +static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message); static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount); -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer); +static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, float localVolume); -static bool IsAudioBufferPlayingInLockedState(AudioBuffer *buffer); -static void StopAudioBufferInLockedState(AudioBuffer *buffer); -static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount); +#if defined(SUPPORT_FILEFORMAT_WAV) +static Wave LoadWAV(const unsigned char *fileData, unsigned int fileSize); // Load WAV file +static int SaveWAV(Wave wave, const char *fileName); // Save wave data as WAV file +#endif +#if defined(SUPPORT_FILEFORMAT_OGG) +static Wave LoadOGG(const unsigned char *fileData, unsigned int fileSize); // Load OGG file +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) +static Wave LoadFLAC(const unsigned char *fileData, unsigned int fileSize); // Load FLAC file +#endif +#if defined(SUPPORT_FILEFORMAT_MP3) +static Wave LoadMP3(const unsigned char *fileData, unsigned int fileSize); // Load MP3 file +#endif #if defined(RAUDIO_STANDALONE) static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension static const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes the dot: .png) -static const char *GetFileName(const char *filePath); // Get pointer to filename for a path string -static const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) +static bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal +static const char *TextToLower(const char *text); // Get lower case version of provided string -static unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) -static bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write) +static unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read) +static bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write) static bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated #endif @@ -450,10 +410,9 @@ void PauseAudioBuffer(AudioBuffer *buffer); void ResumeAudioBuffer(AudioBuffer *buffer); void SetAudioBufferVolume(AudioBuffer *buffer, float volume); void SetAudioBufferPitch(AudioBuffer *buffer, float pitch); -void SetAudioBufferPan(AudioBuffer *buffer, float pan); void TrackAudioBuffer(AudioBuffer *buffer); void UntrackAudioBuffer(AudioBuffer *buffer); - +int GetAudioStreamBufferSizeDefault(); //---------------------------------------------------------------------------------- // Module Functions Definition - Audio Device initialization and Closing @@ -461,9 +420,11 @@ void UntrackAudioBuffer(AudioBuffer *buffer); // Initialize audio device void InitAudioDevice(void) { + // TODO: Load AUDIO context memory dynamically? + // Init audio context ma_context_config ctxConfig = ma_context_config_init(); - ma_log_callback_init(OnLog, NULL); + ctxConfig.logCallback = OnLog; ma_result result = ma_context_init(NULL, 0, &ctxConfig, &AUDIO.System.context); if (result != MA_SUCCESS) @@ -473,12 +434,12 @@ void InitAudioDevice(void) } // Init audio device - // NOTE: Using the default device. Format is floating point because it simplifies mixing + // NOTE: Using the default device. Format is floating point because it simplifies mixing. ma_device_config config = ma_device_config_init(ma_device_type_playback); - config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device + config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device. config.playback.format = AUDIO_DEVICE_FORMAT; config.playback.channels = AUDIO_DEVICE_CHANNELS; - config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device + config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device. config.capture.format = ma_format_s16; config.capture.channels = 1; config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE; @@ -493,18 +454,8 @@ void InitAudioDevice(void) return; } - // Mixing happens on a separate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may - // want to look at something a bit smarter later on to keep everything real-time, if that's necessary - if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS) - { - TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing"); - ma_device_uninit(&AUDIO.System.device); - ma_context_uninit(&AUDIO.System.context); - return; - } - // Keep the device running the whole time. May want to consider doing something a bit smarter and only have the device running - // while there's at least one sound being played + // while there's at least one sound being played. result = ma_device_start(&AUDIO.System.device); if (result != MA_SUCCESS) { @@ -514,8 +465,26 @@ void InitAudioDevice(void) return; } + // Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may + // want to look at something a bit smarter later on to keep everything real-time, if that's necessary. + if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS) + { + TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing"); + ma_device_uninit(&AUDIO.System.device); + ma_context_uninit(&AUDIO.System.context); + return; + } + + // Init dummy audio buffers pool for multichannel sound playing + for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) + { + // WARNING: An empty audioBuffer is created (data = 0) + // AudioBuffer data just points to loaded sound data + AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC); + } + TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully"); - TRACELOG(LOG_INFO, " > Backend: miniaudio | %s", ma_get_backend_name(AUDIO.System.context.backend)); + TRACELOG(LOG_INFO, " > Backend: miniaudio / %s", ma_get_backend_name(AUDIO.System.context.backend)); TRACELOG(LOG_INFO, " > Format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat)); TRACELOG(LOG_INFO, " > Channels: %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels); TRACELOG(LOG_INFO, " > Sample rate: %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate); @@ -529,14 +498,25 @@ void CloseAudioDevice(void) { if (AUDIO.System.isReady) { + // Unload dummy audio buffers pool + // WARNING: They can be pointing to already unloaded data + for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) + { + //UnloadAudioBuffer(AUDIO.MultiChannel.pool[i]); + if (AUDIO.MultiChannel.pool[i] != NULL) + { + ma_data_converter_uninit(&AUDIO.MultiChannel.pool[i]->converter); + UntrackAudioBuffer(AUDIO.MultiChannel.pool[i]); + //RL_FREE(buffer->data); // Already unloaded by UnloadSound() + RL_FREE(AUDIO.MultiChannel.pool[i]); + } + } + ma_mutex_uninit(&AUDIO.System.lock); ma_device_uninit(&AUDIO.System.device); ma_context_uninit(&AUDIO.System.context); AUDIO.System.isReady = false; - RL_FREE(AUDIO.System.pcmBuffer); - AUDIO.System.pcmBuffer = NULL; - AUDIO.System.pcmBufferSize = 0; TRACELOG(LOG_INFO, "AUDIO: Device closed successfully"); } @@ -555,14 +535,6 @@ void SetMasterVolume(float volume) ma_device_set_master_volume(&AUDIO.System.device, volume); } -// Get master volume (listener) -float GetMasterVolume(void) -{ - float volume = 0.0f; - ma_device_get_master_volume(&AUDIO.System.device, &volume); - return volume; -} - //---------------------------------------------------------------------------------- // Module Functions Definition - Audio Buffer management //---------------------------------------------------------------------------------- @@ -582,9 +554,9 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam // Audio data runs through a format converter ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO.System.device.sampleRate); - converterConfig.allowDynamicSampleRate = true; + converterConfig.resampling.allowDynamicSampleRate = true; // Required for pitch shifting - ma_result result = ma_data_converter_init(&converterConfig, NULL, &audioBuffer->converter); + ma_result result = ma_data_converter_init(&converterConfig, &audioBuffer->converter); if (result != MA_SUCCESS) { @@ -596,18 +568,11 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam // Init audio buffer values audioBuffer->volume = 1.0f; audioBuffer->pitch = 1.0f; - audioBuffer->pan = 0.5f; - - audioBuffer->callback = NULL; - audioBuffer->processor = NULL; - audioBuffer->playing = false; audioBuffer->paused = false; audioBuffer->looping = false; - audioBuffer->usage = usage; audioBuffer->frameCursorPos = 0; - audioBuffer->framesProcessed = 0; audioBuffer->sizeInFrames = sizeInFrames; // Buffers should be marked as processed by default so that a call to @@ -626,80 +591,69 @@ void UnloadAudioBuffer(AudioBuffer *buffer) { if (buffer != NULL) { + ma_data_converter_uninit(&buffer->converter); UntrackAudioBuffer(buffer); - ma_data_converter_uninit(&buffer->converter, NULL); RL_FREE(buffer->data); RL_FREE(buffer); } } -// Check if an audio buffer is playing from a program state without lock +// Check if an audio buffer is playing bool IsAudioBufferPlaying(AudioBuffer *buffer) { bool result = false; - ma_mutex_lock(&AUDIO.System.lock); - result = IsAudioBufferPlayingInLockedState(buffer); - ma_mutex_unlock(&AUDIO.System.lock); + + if (buffer != NULL) result = (buffer->playing && !buffer->paused); + return result; } // Play an audio buffer -// NOTE: Buffer is restarted to the start -// Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained +// NOTE: Buffer is restarted to the start. +// Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained. void PlayAudioBuffer(AudioBuffer *buffer) { if (buffer != NULL) { - ma_mutex_lock(&AUDIO.System.lock); buffer->playing = true; buffer->paused = false; buffer->frameCursorPos = 0; - buffer->framesProcessed = 0; - buffer->isSubBufferProcessed[0] = true; - buffer->isSubBufferProcessed[1] = true; - ma_mutex_unlock(&AUDIO.System.lock); } } -// Stop an audio buffer from a program state without lock +// Stop an audio buffer void StopAudioBuffer(AudioBuffer *buffer) { - ma_mutex_lock(&AUDIO.System.lock); - StopAudioBufferInLockedState(buffer); - ma_mutex_unlock(&AUDIO.System.lock); + if (buffer != NULL) + { + if (IsAudioBufferPlaying(buffer)) + { + buffer->playing = false; + buffer->paused = false; + buffer->frameCursorPos = 0; + buffer->totalFramesProcessed = 0; + buffer->isSubBufferProcessed[0] = true; + buffer->isSubBufferProcessed[1] = true; + } + } } // Pause an audio buffer void PauseAudioBuffer(AudioBuffer *buffer) { - if (buffer != NULL) - { - ma_mutex_lock(&AUDIO.System.lock); - buffer->paused = true; - ma_mutex_unlock(&AUDIO.System.lock); - } + if (buffer != NULL) buffer->paused = true; } // Resume an audio buffer void ResumeAudioBuffer(AudioBuffer *buffer) { - if (buffer != NULL) - { - ma_mutex_lock(&AUDIO.System.lock); - buffer->paused = false; - ma_mutex_unlock(&AUDIO.System.lock); - } + if (buffer != NULL) buffer->paused = false; } // Set volume for an audio buffer void SetAudioBufferVolume(AudioBuffer *buffer, float volume) { - if (buffer != NULL) - { - ma_mutex_lock(&AUDIO.System.lock); - buffer->volume = volume; - ma_mutex_unlock(&AUDIO.System.lock); - } + if (buffer != NULL) buffer->volume = volume; } // Set pitch for an audio buffer @@ -707,30 +661,14 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch) { if ((buffer != NULL) && (pitch > 0.0f)) { - ma_mutex_lock(&AUDIO.System.lock); - // Pitching is just an adjustment of the sample rate + // Pitching is just an adjustment of the sample rate. // Note that this changes the duration of the sound: // - higher pitches will make the sound faster // - lower pitches make it slower - ma_uint32 outputSampleRate = (ma_uint32)((float)buffer->converter.sampleRateOut/pitch); - ma_data_converter_set_rate(&buffer->converter, buffer->converter.sampleRateIn, outputSampleRate); + ma_uint32 outputSampleRate = (ma_uint32)((float)buffer->converter.config.sampleRateOut/pitch); + ma_data_converter_set_rate(&buffer->converter, buffer->converter.config.sampleRateIn, outputSampleRate); buffer->pitch = pitch; - ma_mutex_unlock(&AUDIO.System.lock); - } -} - -// Set pan for an audio buffer -void SetAudioBufferPan(AudioBuffer *buffer, float pan) -{ - if (pan < 0.0f) pan = 0.0f; - else if (pan > 1.0f) pan = 1.0f; - - if (buffer != NULL) - { - ma_mutex_lock(&AUDIO.System.lock); - buffer->pan = pan; - ma_mutex_unlock(&AUDIO.System.lock); } } @@ -778,141 +716,46 @@ Wave LoadWave(const char *fileName) Wave wave = { 0 }; // Loading file to memory - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); - // Loading wave from memory data - if (fileData != NULL) wave = LoadWaveFromMemory(GetFileExtension(fileName), fileData, dataSize); + if (fileData != NULL) + { + // Loading wave from memory data + wave = LoadWaveFromMemory(GetFileExtension(fileName), fileData, fileSize); - UnloadFileData(fileData); + RL_FREE(fileData); + } return wave; } // Load wave from memory buffer, fileType refers to extension: i.e. ".wav" -// WARNING: File extension must be provided in lower-case Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize) { Wave wave = { 0 }; + char fileExtLower[16] = { 0 }; + strcpy(fileExtLower, TextToLower(fileType)); + if (false) { } #if defined(SUPPORT_FILEFORMAT_WAV) - else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0)) - { - drwav wav = { 0 }; - bool success = drwav_init_memory(&wav, fileData, dataSize, NULL); - - if (success) - { - wave.frameCount = (unsigned int)wav.totalPCMFrameCount; - wave.sampleRate = wav.sampleRate; - wave.sampleSize = 16; - wave.channels = wav.channels; - wave.data = (short *)RL_MALLOC((size_t)wave.frameCount*wave.channels*sizeof(short)); - - // NOTE: We are forcing conversion to 16bit sample size on reading - drwav_read_pcm_frames_s16(&wav, wave.frameCount, wave.data); - } - else TRACELOG(LOG_WARNING, "WAVE: Failed to load WAV data"); - - drwav_uninit(&wav); - } + else if (TextIsEqual(fileExtLower, ".wav")) wave = LoadWAV(fileData, dataSize); #endif #if defined(SUPPORT_FILEFORMAT_OGG) - else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0)) - { - stb_vorbis *oggData = stb_vorbis_open_memory((unsigned char *)fileData, dataSize, NULL, NULL); - - if (oggData != NULL) - { - stb_vorbis_info info = stb_vorbis_get_info(oggData); - - wave.sampleRate = info.sample_rate; - wave.sampleSize = 16; // By default, ogg data is 16 bit per sample (short) - wave.channels = info.channels; - wave.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples(oggData); // NOTE: It returns frames! - wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short)); - - // NOTE: Get the number of samples to process (be careful! we ask for number of shorts, not bytes!) - stb_vorbis_get_samples_short_interleaved(oggData, info.channels, (short *)wave.data, wave.frameCount*wave.channels); - stb_vorbis_close(oggData); - } - else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data"); - } -#endif -#if defined(SUPPORT_FILEFORMAT_MP3) - else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0)) - { - drmp3_config config = { 0 }; - unsigned long long int totalFrameCount = 0; - - // NOTE: We are forcing conversion to 32bit float sample size on reading - wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, dataSize, &config, &totalFrameCount, NULL); - wave.sampleSize = 32; - - if (wave.data != NULL) - { - wave.channels = config.channels; - wave.sampleRate = config.sampleRate; - wave.frameCount = (int)totalFrameCount; - } - else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data"); - - } -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - else if ((strcmp(fileType, ".qoa") == 0) || (strcmp(fileType, ".QOA") == 0)) - { - qoa_desc qoa = { 0 }; - - // NOTE: Returned sample data is always 16 bit? - wave.data = qoa_decode(fileData, dataSize, &qoa); - wave.sampleSize = 16; - - if (wave.data != NULL) - { - wave.channels = qoa.channels; - wave.sampleRate = qoa.samplerate; - wave.frameCount = qoa.samples; - } - else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data"); - - } + else if (TextIsEqual(fileExtLower, ".ogg")) wave = LoadOGG(fileData, dataSize); #endif #if defined(SUPPORT_FILEFORMAT_FLAC) - else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0)) - { - unsigned long long int totalFrameCount = 0; - - // NOTE: We are forcing conversion to 16bit sample size on reading - wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL); - wave.sampleSize = 16; - - if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; - else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data"); - } + else if (TextIsEqual(fileExtLower, ".flac")) wave = LoadFLAC(fileData, dataSize); #endif - else TRACELOG(LOG_WARNING, "WAVE: Data format not supported"); - - TRACELOG(LOG_INFO, "WAVE: Data loaded successfully (%i Hz, %i bit, %i channels)", wave.sampleRate, wave.sampleSize, wave.channels); +#if defined(SUPPORT_FILEFORMAT_MP3) + else if (TextIsEqual(fileExtLower, ".mp3")) wave = LoadMP3(fileData, dataSize); +#endif + else TRACELOG(LOG_WARNING, "WAVE: File format not supported"); return wave; } -// Checks if wave data is valid (data loaded and parameters) -bool IsWaveValid(Wave wave) -{ - bool result = false; - - if ((wave.data != NULL) && // Validate wave data available - (wave.frameCount > 0) && // Validate frame count - (wave.sampleRate > 0) && // Validate sample rate is supported - (wave.sampleSize > 0) && // Validate sample size is supported - (wave.channels > 0)) result = true; // Validate number of channels supported - - return result; -} - // Load sound from file // NOTE: The entire file is loaded to memory to be played (no-streaming) Sound LoadSound(const char *fileName) @@ -934,17 +777,17 @@ Sound LoadSoundFromWave(Wave wave) if (wave.data != NULL) { - // When using miniaudio we need to do our own mixing + // When using miniaudio we need to do our own mixing. // To simplify this we need convert the format of each sound to be consistent with // the format used to open the playback AUDIO.System.device. We can do this two ways: // - // 1) Convert the whole sound in one go at load time (here) - // 2) Convert the audio data in chunks at mixing time + // 1) Convert the whole sound in one go at load time (here). + // 2) Convert the audio data in chunks at mixing time. // - // First option has been selected, format conversion is done on the loading stage - // The downside is that it uses more memory if the original sound is u8 or s16 - ma_format formatIn = ((wave.sampleSize == 8)? ma_format_u8 : ((wave.sampleSize == 16)? ma_format_s16 : ma_format_f32)); - ma_uint32 frameCountIn = wave.frameCount; + // First option has been selected, format conversion is done on the loading stage. + // The downside is that it uses more memory if the original sound is u8 or s16. + ma_format formatIn = ((wave.sampleSize == 8)? ma_format_u8 : ((wave.sampleSize == 16)? ma_format_s16 : ma_format_f32)); + ma_uint32 frameCountIn = wave.sampleCount/wave.channels; ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, NULL, frameCountIn, formatIn, wave.channels, wave.sampleRate); if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed to get frame count for format conversion"); @@ -959,7 +802,7 @@ Sound LoadSoundFromWave(Wave wave) frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate); if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed format conversion"); - sound.frameCount = frameCount; + sound.sampleCount = frameCount*AUDIO_DEVICE_CHANNELS; sound.stream.sampleRate = AUDIO.System.device.sampleRate; sound.stream.sampleSize = 32; sound.stream.channels = AUDIO_DEVICE_CHANNELS; @@ -969,84 +812,31 @@ Sound LoadSoundFromWave(Wave wave) return sound; } -// Clone sound from existing sound data, clone does not own wave data -// NOTE: Wave data must be unallocated manually and will be shared across all clones -Sound LoadSoundAlias(Sound source) -{ - Sound sound = { 0 }; - - if (source.stream.buffer->data != NULL) - { - AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC); - - if (audioBuffer == NULL) - { - TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer"); - return sound; // Early return to avoid dereferencing the audioBuffer null pointer - } - - audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames; - audioBuffer->volume = source.stream.buffer->volume; - audioBuffer->data = source.stream.buffer->data; - - sound.frameCount = source.frameCount; - sound.stream.sampleRate = AUDIO.System.device.sampleRate; - sound.stream.sampleSize = 32; - sound.stream.channels = AUDIO_DEVICE_CHANNELS; - sound.stream.buffer = audioBuffer; - } - - return sound; -} - - -// Checks if a sound is valid (data loaded and buffers initialized) -bool IsSoundValid(Sound sound) -{ - bool result = false; - - if ((sound.frameCount > 0) && // Validate frame count - (sound.stream.buffer != NULL) && // Validate stream buffer - (sound.stream.sampleRate > 0) && // Validate sample rate is supported - (sound.stream.sampleSize > 0) && // Validate sample size is supported - (sound.stream.channels > 0)) result = true; // Validate number of channels supported - - return result; -} - // Unload wave data void UnloadWave(Wave wave) { - RL_FREE(wave.data); - //TRACELOG(LOG_INFO, "WAVE: Unloaded wave data from RAM"); + if (wave.data != NULL) RL_FREE(wave.data); + + TRACELOG(LOG_INFO, "WAVE: Unloaded wave data from RAM"); } // Unload sound void UnloadSound(Sound sound) { UnloadAudioBuffer(sound.stream.buffer); - //TRACELOG(LOG_INFO, "SOUND: Unloaded sound data from RAM"); -} -void UnloadSoundAlias(Sound alias) -{ - // Untrack and unload just the sound buffer, not the sample data, it is shared with the source for the alias - if (alias.stream.buffer != NULL) - { - UntrackAudioBuffer(alias.stream.buffer); - ma_data_converter_uninit(&alias.stream.buffer->converter, NULL); - RL_FREE(alias.stream.buffer); - } + TRACELOG(LOG_INFO, "WAVE: Unloaded sound data from RAM"); } // Update sound buffer with new data -void UpdateSound(Sound sound, const void *data, int frameCount) +void UpdateSound(Sound sound, const void *data, int samplesCount) { if (sound.stream.buffer != NULL) { StopAudioBuffer(sound.stream.buffer); - memcpy(sound.stream.buffer->data, data, frameCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.formatIn, sound.stream.buffer->converter.channelsIn)); + // TODO: May want to lock/unlock this since this data buffer is read at mixing time + memcpy(sound.stream.buffer->data, data, samplesCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.config.formatIn, sound.stream.buffer->converter.config.channelsIn)); } } @@ -1057,49 +847,13 @@ bool ExportWave(Wave wave, const char *fileName) if (false) { } #if defined(SUPPORT_FILEFORMAT_WAV) - else if (IsFileExtension(fileName, ".wav")) - { - drwav wav = { 0 }; - drwav_data_format format = { 0 }; - format.container = drwav_container_riff; - if (wave.sampleSize == 32) format.format = DR_WAVE_FORMAT_IEEE_FLOAT; - else format.format = DR_WAVE_FORMAT_PCM; - format.channels = wave.channels; - format.sampleRate = wave.sampleRate; - format.bitsPerSample = wave.sampleSize; - - void *fileData = NULL; - size_t fileDataSize = 0; - success = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); - if (success) success = (int)drwav_write_pcm_frames(&wav, wave.frameCount, wave.data); - drwav_result result = drwav_uninit(&wav); - - if (result == DRWAV_SUCCESS) success = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize); - - drwav_free(fileData, NULL); - } -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - else if (IsFileExtension(fileName, ".qoa")) - { - if (wave.sampleSize == 16) - { - qoa_desc qoa = { 0 }; - qoa.channels = wave.channels; - qoa.samplerate = wave.sampleRate; - qoa.samples = wave.frameCount; - - int bytesWritten = qoa_write(fileName, wave.data, &qoa); - if (bytesWritten > 0) success = true; - } - else TRACELOG(LOG_WARNING, "AUDIO: Wave data must be 16 bit per sample for QOA format export"); - } + else if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName); #endif else if (IsFileExtension(fileName, ".raw")) { // Export raw sample data (without header) // NOTE: It's up to the user to track wave parameters - success = SaveFileData(fileName, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8); + success = SaveFileData(fileName, wave.data, wave.sampleCount*wave.sampleSize/8); } if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName); @@ -1117,61 +871,49 @@ bool ExportWaveAsCode(Wave wave, const char *fileName) #define TEXT_BYTES_PER_LINE 20 #endif - int waveDataSize = wave.frameCount*wave.channels*wave.sampleSize/8; + int waveDataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; // NOTE: Text data buffer size is estimated considering wave data size in bytes - // and requiring 12 char bytes for every byte; the actual size varies, but - // the longest possible char being appended is "%.4ff,\n ", which is 12 bytes. - char *txtData = (char *)RL_CALLOC(waveDataSize*12 + 2000, sizeof(char)); + // and requiring 6 char bytes for every byte: "0x00, " + char *txtData = (char *)RL_CALLOC(6*waveDataSize + 2000, sizeof(char)); - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "\n//////////////////////////////////////////////////////////////////////////////////\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// WaveAsCode exporter v1.1 - Wave data exported as an array of bytes //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); - byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n"); + int bytesCount = 0; + bytesCount += sprintf(txtData + bytesCount, "\n//////////////////////////////////////////////////////////////////////////////////\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); + bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "//////////////////////////////////////////////////////////////////////////////////\n\n"); - // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; +#if !defined(RAUDIO_STANDALONE) + // Get file name from path and convert variable name to uppercase strcpy(varFileName, GetFileNameWithoutExt(fileName)); for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; } +#else + strcpy(varFileName, fileName); +#endif - // Add wave information - byteCount += sprintf(txtData + byteCount, "// Wave data information\n"); - byteCount += sprintf(txtData + byteCount, "#define %s_FRAME_COUNT %u\n", varFileName, wave.frameCount); - byteCount += sprintf(txtData + byteCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate); - byteCount += sprintf(txtData + byteCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize); - byteCount += sprintf(txtData + byteCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels); + bytesCount += sprintf(txtData + bytesCount, "// Wave data information\n"); + bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount); + bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate); + bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize); + bytesCount += sprintf(txtData + bytesCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels); - // Write wave data as an array of values - // Wave data is exported as byte array for 8/16bit and float array for 32bit float data - // NOTE: Frame data exported is channel-interlaced: frame01[sampleChannel1, sampleChannel2, ...], frame02[], frame03[] - if (wave.sampleSize == 32) - { - byteCount += sprintf(txtData + byteCount, "static float %s_DATA[%i] = {\n", varFileName, waveDataSize/4); - for (int i = 1; i < waveDataSize/4; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.4ff,\n " : "%.4ff, "), ((float *)wave.data)[i - 1]); - byteCount += sprintf(txtData + byteCount, "%.4ff };\n", ((float *)wave.data)[waveDataSize/4 - 1]); - } - else - { - byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize); - for (int i = 1; i < waveDataSize; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n " : "0x%x, "), ((unsigned char *)wave.data)[i - 1]); - byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]); - } + // Write byte data as hexadecimal text + bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize); + for (int i = 0; i < waveDataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]); + bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]); // NOTE: Text data length exported is determined by '\0' (NULL) character success = SaveFileText(fileName, txtData); RL_FREE(txtData); - if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave as code exported successfully", fileName); - else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave as code", fileName); - return success; } @@ -1181,6 +923,85 @@ void PlaySound(Sound sound) PlayAudioBuffer(sound.stream.buffer); } +// Play a sound in the multichannel buffer pool +void PlaySoundMulti(Sound sound) +{ + int index = -1; + unsigned int oldAge = 0; + int oldIndex = -1; + + // find the first non playing pool entry + for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) + { + if (AUDIO.MultiChannel.channels[i] > oldAge) + { + oldAge = AUDIO.MultiChannel.channels[i]; + oldIndex = i; + } + + if (!IsAudioBufferPlaying(AUDIO.MultiChannel.pool[i])) + { + index = i; + break; + } + } + + // If no none playing pool members can be index choose the oldest + if (index == -1) + { + TRACELOG(LOG_WARNING, "SOUND: Buffer pool is already full, count: %i", AUDIO.MultiChannel.poolCounter); + + if (oldIndex == -1) + { + // Shouldn't be able to get here... but just in case something odd happens! + TRACELOG(LOG_WARNING, "SOUND: Buffer pool could not determine oldest buffer not playing sound"); + return; + } + + index = oldIndex; + + // Just in case... + StopAudioBuffer(AUDIO.MultiChannel.pool[index]); + } + + // Experimentally mutex lock doesn't seem to be needed this makes sense + // as pool[index] isn't playing and the only stuff we're copying + // shouldn't be changing... + + AUDIO.MultiChannel.channels[index] = AUDIO.MultiChannel.poolCounter; + AUDIO.MultiChannel.poolCounter++; + + AUDIO.MultiChannel.pool[index]->volume = sound.stream.buffer->volume; + AUDIO.MultiChannel.pool[index]->pitch = sound.stream.buffer->pitch; + AUDIO.MultiChannel.pool[index]->looping = sound.stream.buffer->looping; + AUDIO.MultiChannel.pool[index]->usage = sound.stream.buffer->usage; + AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false; + AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[1] = false; + AUDIO.MultiChannel.pool[index]->sizeInFrames = sound.stream.buffer->sizeInFrames; + AUDIO.MultiChannel.pool[index]->data = sound.stream.buffer->data; + + PlayAudioBuffer(AUDIO.MultiChannel.pool[index]); +} + +// Stop any sound played with PlaySoundMulti() +void StopSoundMulti(void) +{ + for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) StopAudioBuffer(AUDIO.MultiChannel.pool[i]); +} + +// Get number of sounds playing in the multichannel buffer pool +int GetSoundsPlaying(void) +{ + int counter = 0; + + for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) + { + if (IsAudioBufferPlaying(AUDIO.MultiChannel.pool[i])) counter++; + } + + return counter; +} + // Pause a sound void PauseSound(Sound sound) { @@ -1202,11 +1023,7 @@ void StopSound(Sound sound) // Check if a sound is playing bool IsSoundPlaying(Sound sound) { - bool result = false; - - if (IsAudioBufferPlaying(sound.stream.buffer)) result = true; - - return result; + return IsAudioBufferPlaying(sound.stream.buffer); } // Set volume for a sound @@ -1221,21 +1038,15 @@ void SetSoundPitch(Sound sound, float pitch) SetAudioBufferPitch(sound.stream.buffer, pitch); } -// Set pan for a sound -void SetSoundPan(Sound sound, float pan) -{ - SetAudioBufferPan(sound.stream.buffer, pan); -} - // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { ma_format formatIn = ((wave->sampleSize == 8)? ma_format_u8 : ((wave->sampleSize == 16)? ma_format_s16 : ma_format_f32)); ma_format formatOut = ((sampleSize == 8)? ma_format_u8 : ((sampleSize == 16)? ma_format_s16 : ma_format_f32)); - ma_uint32 frameCountIn = wave->frameCount; - ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, formatOut, channels, sampleRate, NULL, frameCountIn, formatIn, wave->channels, wave->sampleRate); + ma_uint32 frameCountIn = wave->sampleCount/wave->channels; + ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, formatOut, channels, sampleRate, NULL, frameCountIn, formatIn, wave->channels, wave->sampleRate); if (frameCount == 0) { TRACELOG(LOG_WARNING, "WAVE: Failed to get frame count for format conversion"); @@ -1247,16 +1058,14 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate); if (frameCount == 0) { - RL_FREE(wave->data); TRACELOG(LOG_WARNING, "WAVE: Failed format conversion"); return; } - wave->frameCount = frameCount; + wave->sampleCount = frameCount*channels; wave->sampleSize = sampleSize; wave->sampleRate = sampleRate; wave->channels = channels; - RL_FREE(wave->data); wave->data = data; } @@ -1266,14 +1075,14 @@ Wave WaveCopy(Wave wave) { Wave newWave = { 0 }; - newWave.data = RL_MALLOC(wave.frameCount*wave.channels*wave.sampleSize/8); + newWave.data = RL_MALLOC(wave.sampleCount*wave.sampleSize/8); if (newWave.data != NULL) { // NOTE: Size must be provided in bytes - memcpy(newWave.data, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8); + memcpy(newWave.data, wave.data, wave.sampleCount*wave.sampleSize/8); - newWave.frameCount = wave.frameCount; + newWave.sampleCount = wave.sampleCount; newWave.sampleRate = wave.sampleRate; newWave.sampleSize = wave.sampleSize; newWave.channels = wave.channels; @@ -1282,21 +1091,21 @@ Wave WaveCopy(Wave wave) return newWave; } -// Crop a wave to defined frames range +// Crop a wave to defined samples range // NOTE: Security check in case of out-of-range -void WaveCrop(Wave *wave, int initFrame, int finalFrame) +void WaveCrop(Wave *wave, int initSample, int finalSample) { - if ((initFrame >= 0) && (initFrame < finalFrame) && ((unsigned int)finalFrame <= wave->frameCount)) + if ((initSample >= 0) && (initSample < finalSample) && + (finalSample > 0) && ((unsigned int)finalSample < wave->sampleCount)) { - int frameCount = finalFrame - initFrame; + int sampleCount = finalSample - initSample; - void *data = RL_MALLOC(frameCount*wave->channels*wave->sampleSize/8); + void *data = RL_MALLOC(sampleCount*wave->sampleSize/8); - memcpy(data, (unsigned char *)wave->data + (initFrame*wave->channels*wave->sampleSize/8), frameCount*wave->channels*wave->sampleSize/8); + memcpy(data, (unsigned char *)wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->sampleSize/8); RL_FREE(wave->data); wave->data = data; - wave->frameCount = (unsigned int)frameCount; } else TRACELOG(LOG_WARNING, "WAVE: Crop range out of bounds"); } @@ -1306,14 +1115,14 @@ void WaveCrop(Wave *wave, int initFrame, int finalFrame) // NOTE 2: Sample data allocated should be freed with UnloadWaveSamples() float *LoadWaveSamples(Wave wave) { - float *samples = (float *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(float)); + float *samples = (float *)RL_MALLOC(wave.sampleCount*sizeof(float)); // NOTE: sampleCount is the total number of interlaced samples (including channels) - for (unsigned int i = 0; i < wave.frameCount*wave.channels; i++) + for (unsigned int i = 0; i < wave.sampleCount; i++) { - if (wave.sampleSize == 8) samples[i] = (float)(((unsigned char *)wave.data)[i] - 128)/128.0f; - else if (wave.sampleSize == 16) samples[i] = (float)(((short *)wave.data)[i])/32768.0f; + if (wave.sampleSize == 8) samples[i] = (float)(((unsigned char *)wave.data)[i] - 127)/256.0f; + else if (wave.sampleSize == 16) samples[i] = (float)(((short *)wave.data)[i])/32767.0f; else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i]; } @@ -1327,7 +1136,7 @@ void UnloadWaveSamples(float *samples) } //---------------------------------------------------------------------------------- -// Module Functions Definition - Music loading and stream playing +// Module Functions Definition - Music loading and stream playing (.OGG) //---------------------------------------------------------------------------------- // Load music stream from file @@ -1340,113 +1149,78 @@ Music LoadMusicStream(const char *fileName) #if defined(SUPPORT_FILEFORMAT_WAV) else if (IsFileExtension(fileName, ".wav")) { - drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav)); + drwav *ctxWav = RL_CALLOC(1, sizeof(drwav)); bool success = drwav_init_file(ctxWav, fileName, NULL); + music.ctxType = MUSIC_AUDIO_WAV; + music.ctxData = ctxWav; + if (success) { - music.ctxType = MUSIC_AUDIO_WAV; - music.ctxData = ctxWav; int sampleSize = ctxWav->bitsPerSample; if (ctxWav->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream() - music.stream = LoadAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels); - music.frameCount = (unsigned int)ctxWav->totalPCMFrameCount; + music.stream = InitAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels); + music.sampleCount = (unsigned int)ctxWav->totalPCMFrameCount*ctxWav->channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else - { - RL_FREE(ctxWav); - } } #endif #if defined(SUPPORT_FILEFORMAT_OGG) else if (IsFileExtension(fileName, ".ogg")) { // Open ogg audio stream - stb_vorbis *ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL); + music.ctxType = MUSIC_AUDIO_OGG; + music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); - if (ctxOgg != NULL) + if (music.ctxData != NULL) { - music.ctxType = MUSIC_AUDIO_OGG; - music.ctxData = ctxOgg; stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info // OGG bit rate defaults to 16 bit, it's enough for compressed format - music.stream = LoadAudioStream(info.sample_rate, 16, info.channels); + music.stream = InitAudioStream(info.sample_rate, 16, info.channels); // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels - music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData); + music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else + } +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + else if (IsFileExtension(fileName, ".flac")) + { + music.ctxType = MUSIC_AUDIO_FLAC; + music.ctxData = drflac_open_file(fileName, NULL); + + if (music.ctxData != NULL) { - stb_vorbis_close(ctxOgg); + drflac *ctxFlac = (drflac *)music.ctxData; + + music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); + music.sampleCount = (unsigned int)ctxFlac->totalPCMFrameCount*ctxFlac->channels; + music.looping = true; // Looping enabled by default + musicLoaded = true; } } #endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (IsFileExtension(fileName, ".mp3")) { - drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3)); + drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3)); int result = drmp3_init_file(ctxMp3, fileName, NULL); + music.ctxType = MUSIC_AUDIO_MP3; + music.ctxData = ctxMp3; + if (result > 0) { - music.ctxType = MUSIC_AUDIO_MP3; - music.ctxData = ctxMp3; - music.stream = LoadAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); - music.frameCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3); + music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); + music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else - { - RL_FREE(ctxMp3); - } - } -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - else if (IsFileExtension(fileName, ".qoa")) - { - qoaplay_desc *ctxQoa = qoaplay_open(fileName); - - if (ctxQoa != NULL) - { - music.ctxType = MUSIC_AUDIO_QOA; - music.ctxData = ctxQoa; - // NOTE: We are loading samples are 32bit float normalized data, so, - // we configure the output audio stream to also use float 32bit - music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels); - music.frameCount = ctxQoa->info.samples; - music.looping = true; // Looping enabled by default - musicLoaded = true; - } - else{} //No uninit required - } -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (IsFileExtension(fileName, ".flac")) - { - drflac *ctxFlac = drflac_open_file(fileName, NULL); - - if (ctxFlac != NULL) - { - music.ctxType = MUSIC_AUDIO_FLAC; - music.ctxData = ctxFlac; - int sampleSize = ctxFlac->bitsPerSample; - if (ctxFlac->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream() - music.stream = LoadAudioStream(ctxFlac->sampleRate, sampleSize, ctxFlac->channels); - music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; - music.looping = true; // Looping enabled by default - musicLoaded = true; - } - else - { - drflac_free(ctxFlac, NULL); - } } #endif #if defined(SUPPORT_FILEFORMAT_XM) @@ -1455,242 +1229,221 @@ Music LoadMusicStream(const char *fileName) jar_xm_context_t *ctxXm = NULL; int result = jar_xm_create_context_from_file(&ctxXm, AUDIO.System.device.sampleRate, fileName); + music.ctxType = MUSIC_MODULE_XM; + music.ctxData = ctxXm; + if (result == 0) // XM AUDIO.System.context created successfully { - music.ctxType = MUSIC_MODULE_XM; - music.ctxData = ctxXm; jar_xm_set_max_loop_count(ctxXm, 0); // Set infinite number of loops unsigned int bits = 32; - if (AUDIO_DEVICE_FORMAT == ma_format_s16) bits = 16; - else if (AUDIO_DEVICE_FORMAT == ma_format_u8) bits = 8; + if (AUDIO_DEVICE_FORMAT == ma_format_s16) + bits = 16; + else if (AUDIO_DEVICE_FORMAT == ma_format_u8) + bits = 8; // NOTE: Only stereo is supported for XM - music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, bits, AUDIO_DEVICE_CHANNELS); - music.frameCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm); // NOTE: Always 2 channels (stereo) + music.stream = InitAudioStream(AUDIO.System.device.sampleRate, bits, AUDIO_DEVICE_CHANNELS); + music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2; // 2 channels music.looping = true; // Looping enabled by default - jar_xm_reset(ctxXm); // Make sure we start at the beginning of the song + jar_xm_reset(ctxXm); // make sure we start at the beginning of the song musicLoaded = true; } - else - { - jar_xm_free_context(ctxXm); - } } #endif #if defined(SUPPORT_FILEFORMAT_MOD) else if (IsFileExtension(fileName, ".mod")) { - jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_CALLOC(1, sizeof(jar_mod_context_t)); + jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t)); jar_mod_init(ctxMod); int result = jar_mod_load_file(ctxMod, fileName); + music.ctxType = MUSIC_MODULE_MOD; + music.ctxData = ctxMod; + if (result > 0) { - music.ctxType = MUSIC_MODULE_MOD; - music.ctxData = ctxMod; // NOTE: Only stereo is supported for MOD - music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, 16, AUDIO_DEVICE_CHANNELS); - music.frameCount = (unsigned int)jar_mod_max_samples(ctxMod); // NOTE: Always 2 channels (stereo) + music.stream = InitAudioStream(AUDIO.System.device.sampleRate, 16, AUDIO_DEVICE_CHANNELS); + music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2; // 2 channels music.looping = true; // Looping enabled by default musicLoaded = true; } - else - { - jar_mod_unload(ctxMod); - RL_FREE(ctxMod); - } } #endif - else TRACELOG(LOG_WARNING, "STREAM: [%s] File format not supported", fileName); + else TRACELOG(LOG_WARNING, "STREAM: [%s] Fileformat not supported", fileName); if (!musicLoaded) { + if (false) { } + #if defined(SUPPORT_FILEFORMAT_WAV) + else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData); + #endif + #if defined(SUPPORT_FILEFORMAT_OGG) + else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); + #endif + #if defined(SUPPORT_FILEFORMAT_FLAC) + else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); + #endif + #if defined(SUPPORT_FILEFORMAT_MP3) + else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } + #endif + #if defined(SUPPORT_FILEFORMAT_XM) + else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); + #endif + #if defined(SUPPORT_FILEFORMAT_MOD) + else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); } + #endif + + music.ctxData = NULL; TRACELOG(LOG_WARNING, "FILEIO: [%s] Music file could not be opened", fileName); } else { // Show some music stream info - TRACELOG(LOG_INFO, "FILEIO: [%s] Music file loaded successfully", fileName); + TRACELOG(LOG_INFO, "FILEIO: [%s] Music file successfully loaded:", fileName); + TRACELOG(LOG_INFO, " > Total samples: %i", music.sampleCount); TRACELOG(LOG_INFO, " > Sample rate: %i Hz", music.stream.sampleRate); TRACELOG(LOG_INFO, " > Sample size: %i bits", music.stream.sampleSize); TRACELOG(LOG_INFO, " > Channels: %i (%s)", music.stream.channels, (music.stream.channels == 1)? "Mono" : (music.stream.channels == 2)? "Stereo" : "Multi"); - TRACELOG(LOG_INFO, " > Total frames: %i", music.frameCount); } return music; } -// Load music stream from memory buffer, fileType refers to extension: i.e. ".wav" -// WARNING: File extension must be provided in lower-case -Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize) +// extension including period ".mod" +Music LoadMusicStreamFromMemory(const char *fileType, unsigned char* data, int dataSize) { Music music = { 0 }; bool musicLoaded = false; + char fileExtLower[16] = { 0 }; + strcpy(fileExtLower, TextToLower(fileType)); + if (false) { } #if defined(SUPPORT_FILEFORMAT_WAV) - else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0)) + else if (TextIsEqual(fileExtLower, ".wav")) { - drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav)); + drwav *ctxWav = RL_CALLOC(1, sizeof(drwav)); - bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL); + bool success = drwav_init_memory(ctxWav, (const void*)data, dataSize, NULL); + + music.ctxType = MUSIC_AUDIO_WAV; + music.ctxData = ctxWav; if (success) { - music.ctxType = MUSIC_AUDIO_WAV; - music.ctxData = ctxWav; int sampleSize = ctxWav->bitsPerSample; if (ctxWav->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream() - music.stream = LoadAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels); - music.frameCount = (unsigned int)ctxWav->totalPCMFrameCount; + music.stream = InitAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels); + music.sampleCount = (unsigned int)ctxWav->totalPCMFrameCount*ctxWav->channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else { - drwav_uninit(ctxWav); - RL_FREE(ctxWav); - } } #endif -#if defined(SUPPORT_FILEFORMAT_OGG) - else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0)) +#if defined(SUPPORT_FILEFORMAT_FLAC) + else if (TextIsEqual(fileExtLower, ".flac")) { - // Open ogg audio stream - stb_vorbis *ctxOgg = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL); + music.ctxType = MUSIC_AUDIO_FLAC; + music.ctxData = drflac_open_memory((const void*)data, dataSize, NULL); - if (ctxOgg != NULL) + if (music.ctxData != NULL) { - music.ctxType = MUSIC_AUDIO_OGG; - music.ctxData = ctxOgg; - stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info + drflac *ctxFlac = (drflac *)music.ctxData; - // OGG bit rate defaults to 16 bit, it's enough for compressed format - music.stream = LoadAudioStream(info.sample_rate, 16, info.channels); - - // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels - music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData); + music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); + music.sampleCount = (unsigned int)ctxFlac->totalPCMFrameCount*ctxFlac->channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else - { - stb_vorbis_close(ctxOgg); - } } #endif #if defined(SUPPORT_FILEFORMAT_MP3) - else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0)) + else if (TextIsEqual(fileExtLower, ".mp3")) { - drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3)); + drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3)); int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL); + music.ctxType = MUSIC_AUDIO_MP3; + music.ctxData = ctxMp3; + if (success) { - music.ctxType = MUSIC_AUDIO_MP3; - music.ctxData = ctxMp3; - music.stream = LoadAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); - music.frameCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3); + music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); + music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else - { - drmp3_uninit(ctxMp3); - RL_FREE(ctxMp3); - } } #endif -#if defined(SUPPORT_FILEFORMAT_QOA) - else if ((strcmp(fileType, ".qoa") == 0) || (strcmp(fileType, ".QOA") == 0)) +#if defined(SUPPORT_FILEFORMAT_OGG) + else if (TextIsEqual(fileExtLower, ".ogg")) { - qoaplay_desc *ctxQoa = NULL; - if ((data != NULL) && (dataSize > 0)) - { - ctxQoa = qoaplay_open_memory(data, dataSize); - } + // Open ogg audio stream + music.ctxType = MUSIC_AUDIO_OGG; + //music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); + music.ctxData = stb_vorbis_open_memory((const unsigned char*)data, dataSize, NULL, NULL); - if (ctxQoa != NULL) + if (music.ctxData != NULL) { - music.ctxType = MUSIC_AUDIO_QOA; - music.ctxData = ctxQoa; - // NOTE: We are loading samples are 32bit float normalized data, so, - // we configure the output audio stream to also use float 32bit - music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels); - music.frameCount = ctxQoa->info.samples; + stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info + + // OGG bit rate defaults to 16 bit, it's enough for compressed format + music.stream = InitAudioStream(info.sample_rate, 16, info.channels); + + // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels + music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels; music.looping = true; // Looping enabled by default musicLoaded = true; } - else{} //No uninit required - } -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0)) - { - drflac *ctxFlac = drflac_open_memory((const void*)data, dataSize, NULL); - - if (ctxFlac != NULL) - { - music.ctxType = MUSIC_AUDIO_FLAC; - music.ctxData = ctxFlac; - int sampleSize = ctxFlac->bitsPerSample; - if (ctxFlac->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream() - music.stream = LoadAudioStream(ctxFlac->sampleRate, sampleSize, ctxFlac->channels); - music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; - music.looping = true; // Looping enabled by default - musicLoaded = true; - } - else - { - drflac_free(ctxFlac, NULL); - } } #endif #if defined(SUPPORT_FILEFORMAT_XM) - else if ((strcmp(fileType, ".xm") == 0) || (strcmp(fileType, ".XM") == 0)) + else if (TextIsEqual(fileExtLower, ".xm")) { jar_xm_context_t *ctxXm = NULL; - int result = jar_xm_create_context_safe(&ctxXm, (const char *)data, dataSize, AUDIO.System.device.sampleRate); + int result = jar_xm_create_context_safe(&ctxXm, (const char*)data, dataSize, AUDIO.System.device.sampleRate); if (result == 0) // XM AUDIO.System.context created successfully { music.ctxType = MUSIC_MODULE_XM; - music.ctxData = ctxXm; jar_xm_set_max_loop_count(ctxXm, 0); // Set infinite number of loops unsigned int bits = 32; - if (AUDIO_DEVICE_FORMAT == ma_format_s16) bits = 16; - else if (AUDIO_DEVICE_FORMAT == ma_format_u8) bits = 8; + if (AUDIO_DEVICE_FORMAT == ma_format_s16) + bits = 16; + else if (AUDIO_DEVICE_FORMAT == ma_format_u8) + bits = 8; // NOTE: Only stereo is supported for XM - music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, bits, 2); - music.frameCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm); // NOTE: Always 2 channels (stereo) + music.stream = InitAudioStream(AUDIO.System.device.sampleRate, bits, 2); + music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2; // 2 channels music.looping = true; // Looping enabled by default - jar_xm_reset(ctxXm); // Make sure we start at the beginning of the song + jar_xm_reset(ctxXm); // make sure we start at the beginning of the song + music.ctxData = ctxXm; musicLoaded = true; } - else - { - jar_xm_free_context(ctxXm); - } } #endif #if defined(SUPPORT_FILEFORMAT_MOD) - else if ((strcmp(fileType, ".mod") == 0) || (strcmp(fileType, ".MOD") == 0)) + else if (TextIsEqual(fileExtLower, ".mod")) { - jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_MALLOC(sizeof(jar_mod_context_t)); + jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t)); int result = 0; jar_mod_init(ctxMod); - // Copy data to allocated memory for default UnloadMusicStream - unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize); + // copy data to allocated memory for default UnloadMusicStream + unsigned char *newData = RL_MALLOC(dataSize); int it = dataSize/sizeof(unsigned char); - for (int i = 0; i < it; i++) newData[i] = data[i]; + for (int i = 0; i < it; i++){ + newData[i] = data[i]; + } // Memory loaded version for jar_mod_load_file() - if (dataSize && (dataSize < 32*1024*1024)) + if (dataSize && dataSize < 32*1024*1024) { ctxMod->modfilesize = dataSize; ctxMod->modfile = newData; @@ -1700,54 +1453,62 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, if (result > 0) { music.ctxType = MUSIC_MODULE_MOD; - music.ctxData = ctxMod; // NOTE: Only stereo is supported for MOD - music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, 16, 2); - music.frameCount = (unsigned int)jar_mod_max_samples(ctxMod); // NOTE: Always 2 channels (stereo) + music.stream = InitAudioStream(AUDIO.System.device.sampleRate, 16, 2); + music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2; // 2 channels music.looping = true; // Looping enabled by default musicLoaded = true; - } - else - { - jar_mod_unload(ctxMod); - RL_FREE(ctxMod); + + music.ctxData = ctxMod; + musicLoaded = true; } } #endif - else TRACELOG(LOG_WARNING, "STREAM: Data format not supported"); + else TRACELOG(LOG_WARNING, "STREAM: [%s] Fileformat not supported", fileType); if (!musicLoaded) { - TRACELOG(LOG_WARNING, "FILEIO: Music data could not be loaded"); + if (false) { } + #if defined(SUPPORT_FILEFORMAT_WAV) + else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData); + #endif + #if defined(SUPPORT_FILEFORMAT_FLAC) + else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); + #endif + #if defined(SUPPORT_FILEFORMAT_MP3) + else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } + #endif + #if defined(SUPPORT_FILEFORMAT_OGG) + else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); + #endif + #if defined(SUPPORT_FILEFORMAT_XM) + else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); + #endif + #if defined(SUPPORT_FILEFORMAT_MOD) + else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); } + #endif + + music.ctxData = NULL; + TRACELOG(LOG_WARNING, "FILEIO: [%s] Music memory could not be opened", fileType); } else { // Show some music stream info - TRACELOG(LOG_INFO, "FILEIO: Music data loaded successfully"); + TRACELOG(LOG_INFO, "FILEIO: [%s] Music memory successfully loaded:", fileType); + TRACELOG(LOG_INFO, " > Total samples: %i", music.sampleCount); TRACELOG(LOG_INFO, " > Sample rate: %i Hz", music.stream.sampleRate); TRACELOG(LOG_INFO, " > Sample size: %i bits", music.stream.sampleSize); TRACELOG(LOG_INFO, " > Channels: %i (%s)", music.stream.channels, (music.stream.channels == 1)? "Mono" : (music.stream.channels == 2)? "Stereo" : "Multi"); - TRACELOG(LOG_INFO, " > Total frames: %i", music.frameCount); } return music; } -// Checks if a music stream is valid (context and buffers initialized) -bool IsMusicValid(Music music) -{ - return ((music.ctxData != NULL) && // Validate context loaded - (music.frameCount > 0) && // Validate audio frame count - (music.stream.sampleRate > 0) && // Validate sample rate is supported - (music.stream.sampleSize > 0) && // Validate sample size is supported - (music.stream.channels > 0)); // Validate number of channels supported -} - // Unload music stream void UnloadMusicStream(Music music) { - UnloadAudioStream(music.stream); + CloseAudioStream(music.stream); if (music.ctxData != NULL) { @@ -1758,15 +1519,12 @@ void UnloadMusicStream(Music music) #if defined(SUPPORT_FILEFORMAT_OGG) else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); #endif -#if defined(SUPPORT_FILEFORMAT_MP3) - else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - else if (music.ctxType == MUSIC_AUDIO_QOA) qoaplay_close((qoaplay_desc *)music.ctxData); -#endif #if defined(SUPPORT_FILEFORMAT_FLAC) else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); #endif +#if defined(SUPPORT_FILEFORMAT_MP3) + else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } +#endif #if defined(SUPPORT_FILEFORMAT_XM) else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); #endif @@ -1776,10 +1534,19 @@ void UnloadMusicStream(Music music) } } -// Start music playing (open stream) from beginning +// Start music playing (open stream) void PlayMusicStream(Music music) { - PlayAudioStream(music.stream); + if (music.stream.buffer != NULL) + { + // For music streams, we need to make sure we maintain the frame cursor position + // This is a hack for this section of code in UpdateMusicStream() + // NOTE: In case window is minimized, music stream is stopped, just make sure to + // play again on window restore: if (IsMusicStreamPlaying(music)) PlayMusicStream(music); + ma_uint32 frameCursorPos = music.stream.buffer->frameCursorPos; + PlayAudioStream(music.stream); // WARNING: This resets the cursor position. + music.stream.buffer->frameCursorPos = frameCursorPos; + } } // Pause music playing @@ -1802,19 +1569,16 @@ void StopMusicStream(Music music) switch (music.ctxType) { #if defined(SUPPORT_FILEFORMAT_WAV) - case MUSIC_AUDIO_WAV: drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); break; + case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, 0); break; #endif #if defined(SUPPORT_FILEFORMAT_OGG) case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break; #endif -#if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break; -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: qoaplay_rewind((qoaplay_desc *)music.ctxData); break; -#endif #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break; + case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, 0); break; +#endif +#if defined(SUPPORT_FILEFORMAT_MP3) + case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, 0); break; #endif #if defined(SUPPORT_FILEFORMAT_XM) case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break; @@ -1826,175 +1590,90 @@ void StopMusicStream(Music music) } } -// Seek music to a certain position (in seconds) -void SeekMusicStream(Music music, float position) -{ - // Seeking is not supported in module formats - if ((music.ctxType == MUSIC_MODULE_XM) || (music.ctxType == MUSIC_MODULE_MOD)) return; - - unsigned int positionInFrames = (unsigned int)(position*music.stream.sampleRate); - - switch (music.ctxType) - { -#if defined(SUPPORT_FILEFORMAT_WAV) - case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, positionInFrames); break; -#endif -#if defined(SUPPORT_FILEFORMAT_OGG) - case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break; -#endif -#if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break; -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: - { - int qoaFrame = positionInFrames/QOA_FRAME_LEN; - qoaplay_seek_frame((qoaplay_desc *)music.ctxData, qoaFrame); // Seeks to QOA frame, not PCM frame - - // We need to compute QOA frame number and update positionInFrames - positionInFrames = ((qoaplay_desc *)music.ctxData)->sample_position; - } break; -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break; -#endif - default: break; - } - - ma_mutex_lock(&AUDIO.System.lock); - music.stream.buffer->framesProcessed = positionInFrames; - music.stream.buffer->isSubBufferProcessed[0] = true; - music.stream.buffer->isSubBufferProcessed[1] = true; - ma_mutex_unlock(&AUDIO.System.lock); -} - // Update (re-fill) music buffers if data already processed void UpdateMusicStream(Music music) { if (music.stream.buffer == NULL) return; - ma_mutex_lock(&AUDIO.System.lock); +#if defined(SUPPORT_FILEFORMAT_XM) + if (music.ctxType == MUSIC_MODULE_XM) jar_xm_set_max_loop_count(music.ctxData, music.looping ? 0 : 1); +#endif + + bool streamEnding = false; unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2; - // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in - int frameSize = music.stream.channels*music.stream.sampleSize/8; - unsigned int pcmSize = subBufferSizeInFrames*frameSize; + // NOTE: Using dynamic allocation because it could require more than 16KB + void *pcm = RL_CALLOC(subBufferSizeInFrames*music.stream.channels*music.stream.sampleSize/8, 1); - if (AUDIO.System.pcmBufferSize < pcmSize) + int samplesCount = 0; // Total size of data streamed in L+R samples for xm floats, individual L or R for ogg shorts + + // TODO: Get the sampleLeft using totalFramesProcessed... but first, get total frames processed correctly... + //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; + int sampleLeft = music.sampleCount - (music.stream.buffer->totalFramesProcessed*music.stream.channels); + + if (music.ctxType == MUSIC_MODULE_XM && music.looping) sampleLeft = subBufferSizeInFrames*4; + + while (IsAudioStreamProcessed(music.stream)) { - RL_FREE(AUDIO.System.pcmBuffer); - AUDIO.System.pcmBuffer = RL_CALLOC(1, pcmSize); - AUDIO.System.pcmBufferSize = pcmSize; - } - - // Check both sub-buffers to check if they require refilling - for (int i = 0; i < 2; i++) - { - if (!music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer - - unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed; // Frames left to be processed - unsigned int framesToStream = 0; // Total frames to be streamed - - if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames; - else framesToStream = framesLeft; - - int frameCountStillNeeded = framesToStream; - int frameCountReadTotal = 0; + if ((sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels; + else samplesCount = sampleLeft; switch (music.ctxType) { #if defined(SUPPORT_FILEFORMAT_WAV) case MUSIC_AUDIO_WAV: { - if (music.stream.sampleSize == 16) - { - while (true) - { - int frameCountRead = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); - } - } - else if (music.stream.sampleSize == 32) - { - while (true) - { - int frameCountRead = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); - } - } + // NOTE: Returns the number of samples to process (not required) + if (music.stream.sampleSize == 16) drwav_read_pcm_frames_s16((drwav *)music.ctxData, samplesCount/music.stream.channels, (short *)pcm); + else if (music.stream.sampleSize == 32) drwav_read_pcm_frames_f32((drwav *)music.ctxData, samplesCount/music.stream.channels, (float *)pcm); + } break; #endif #if defined(SUPPORT_FILEFORMAT_OGG) case MUSIC_AUDIO_OGG: { - while (true) - { - int frameCountRead = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded*music.stream.channels); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else stb_vorbis_seek_start((stb_vorbis *)music.ctxData); - } - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: - { - while (true) - { - int frameCountRead = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); - } - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: - { - unsigned int frameCountRead = qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream); - frameCountReadTotal += frameCountRead; - /* - while (true) - { - int frameCountRead = (int)qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else qoaplay_rewind((qoaplay_desc *)music.ctxData); - } - */ + // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) + stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)pcm, samplesCount); + } break; #endif #if defined(SUPPORT_FILEFORMAT_FLAC) case MUSIC_AUDIO_FLAC: { - while (true) - { - int frameCountRead = (int)drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drflac__seek_to_first_frame((drflac *)music.ctxData); - } + // NOTE: Returns the number of samples to process (not required) + drflac_read_pcm_frames_s16((drflac *)music.ctxData, samplesCount, (short *)pcm); + + } break; + #endif + #if defined(SUPPORT_FILEFORMAT_MP3) + case MUSIC_AUDIO_MP3: + { + // NOTE: samplesCount, actually refers to framesCount and returns the number of frames processed + drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, samplesCount/music.stream.channels, (float *)pcm); + } break; #endif #if defined(SUPPORT_FILEFORMAT_XM) case MUSIC_MODULE_XM: { - // NOTE: Internally we consider 2 channels generation, so sampleCount/2 - if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream); - else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream); - else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcmBuffer, framesToStream); - //jar_xm_reset((jar_xm_context_t *)music.ctxData); + switch (AUDIO_DEVICE_FORMAT) + { + case ma_format_f32: + // NOTE: Internally this function considers 2 channels generation, so samplesCount/2 + jar_xm_generate_samples((jar_xm_context_t*)music.ctxData, (float*)pcm, samplesCount / 2); + break; + + case ma_format_s16: + // NOTE: Internally this function considers 2 channels generation, so samplesCount/2 + jar_xm_generate_samples_16bit((jar_xm_context_t*)music.ctxData, (short*)pcm, samplesCount / 2); + break; + + case ma_format_u8: + // NOTE: Internally this function considers 2 channels generation, so samplesCount/2 + jar_xm_generate_samples_8bit((jar_xm_context_t*)music.ctxData, (char*)pcm, samplesCount / 2); + break; + } } break; #endif @@ -2002,31 +1681,43 @@ void UpdateMusicStream(Music music) case MUSIC_MODULE_MOD: { // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2 - jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream, 0); - //jar_mod_seek_start((jar_mod_context_t *)music.ctxData); - + jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)pcm, samplesCount/2, 0); } break; #endif default: break; } - UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream); + UpdateAudioStream(music.stream, pcm, samplesCount); - music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount; - - if (framesLeft <= subBufferSizeInFrames) + if ((music.ctxType == MUSIC_MODULE_XM) || music.ctxType == MUSIC_MODULE_MOD) { - if (!music.looping) - { - ma_mutex_unlock(&AUDIO.System.lock); - // Streaming is ending, we filled latest frames from input - StopMusicStream(music); - return; - } + if (samplesCount > 1) sampleLeft -= samplesCount/2; + else sampleLeft -= samplesCount; + } + else sampleLeft -= samplesCount; + + if (sampleLeft <= 0) + { + streamEnding = true; + break; } } - ma_mutex_unlock(&AUDIO.System.lock); + // Free allocated pcm data + RL_FREE(pcm); + + // Reset audio stream for looping + if (streamEnding) + { + StopMusicStream(music); // Stop music (and reset) + if (music.looping) PlayMusicStream(music); // Play again + } + else + { + // NOTE: In case window is minimized, music stream is stopped, + // just make sure to play again on window restore + if (IsMusicStreamPlaying(music)) PlayMusicStream(music); + } } // Check if any music is playing @@ -2047,18 +1738,12 @@ void SetMusicPitch(Music music, float pitch) SetAudioBufferPitch(music.stream.buffer, pitch); } -// Set pan for a music -void SetMusicPan(Music music, float pan) -{ - SetAudioBufferPan(music.stream.buffer, pan); -} - // Get music time length (in seconds) float GetMusicTimeLength(Music music) { float totalSeconds = 0.0f; - totalSeconds = (float)music.frameCount/music.stream.sampleRate; + totalSeconds = (float)music.sampleCount/(music.stream.sampleRate*music.stream.channels); return totalSeconds; } @@ -2066,39 +1751,29 @@ float GetMusicTimeLength(Music music) // Get current music time played (in seconds) float GetMusicTimePlayed(Music music) { +#if defined(SUPPORT_FILEFORMAT_XM) + if (music.ctxType == MUSIC_MODULE_XM) + { + uint64_t samples = 0; + jar_xm_get_position(music.ctxData, NULL, NULL, NULL, &samples); + samples = samples % (music.sampleCount); + + return (float)(samples)/(music.stream.sampleRate*music.stream.channels); + } +#endif float secondsPlayed = 0.0f; if (music.stream.buffer != NULL) { -#if defined(SUPPORT_FILEFORMAT_XM) - if (music.ctxType == MUSIC_MODULE_XM) - { - uint64_t framesPlayed = 0; - - jar_xm_get_position(music.ctxData, NULL, NULL, NULL, &framesPlayed); - secondsPlayed = (float)framesPlayed/music.stream.sampleRate; - } - else -#endif - { - ma_mutex_lock(&AUDIO.System.lock); - //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; - int framesProcessed = (int)music.stream.buffer->framesProcessed; - int subBufferSize = (int)music.stream.buffer->sizeInFrames/2; - int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize; - int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize; - int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize; - int framesPlayed = (framesProcessed - framesInFirstBuffer - framesInSecondBuffer + framesSentToMix)%(int)music.frameCount; - if (framesPlayed < 0) framesPlayed += music.frameCount; - secondsPlayed = (float)framesPlayed/music.stream.sampleRate; - ma_mutex_unlock(&AUDIO.System.lock); - } + //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; + unsigned int samplesPlayed = music.stream.buffer->totalFramesProcessed*music.stream.channels; + secondsPlayed = (float)samplesPlayed/(music.stream.sampleRate*music.stream.channels); } return secondsPlayed; } -// Load audio stream (to stream audio pcm data) -AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) +// Init audio stream (to stream audio pcm data) +AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) { AudioStream stream = { 0 }; @@ -2110,13 +1785,7 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // The size of a streaming buffer must be at least double the size of a period unsigned int periodSize = AUDIO.System.device.playback.internalPeriodSizeInFrames; - - // If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate at the device bit size/rate - int deviceBitsPerSample = AUDIO.System.device.playback.format; - if (deviceBitsPerSample > 4) deviceBitsPerSample = 4; - deviceBitsPerSample *= AUDIO.System.device.playback.channels; - - unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0) ? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize; + unsigned int subBufferSize = GetAudioStreamBufferSizeDefault(); if (subBufferSize < periodSize) subBufferSize = periodSize; @@ -2133,17 +1802,8 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un return stream; } -// Checks if an audio stream is valid (buffers initialized) -bool IsAudioStreamValid(AudioStream stream) -{ - return ((stream.buffer != NULL) && // Validate stream buffer - (stream.sampleRate > 0) && // Validate sample rate is supported - (stream.sampleSize > 0) && // Validate sample size is supported - (stream.channels > 0)); // Validate number of channels supported -} - -// Unload audio stream and free memory -void UnloadAudioStream(AudioStream stream) +// Close audio stream and free memory +void CloseAudioStream(AudioStream stream) { UnloadAudioBuffer(stream.buffer); @@ -2151,13 +1811,57 @@ void UnloadAudioStream(AudioStream stream) } // Update audio stream buffers with data -// NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue -// NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed() -void UpdateAudioStream(AudioStream stream, const void *data, int frameCount) +// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue +// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioStreamProcessed() +void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) { - ma_mutex_lock(&AUDIO.System.lock); - UpdateAudioStreamInLockedState(stream, data, frameCount); - ma_mutex_unlock(&AUDIO.System.lock); + if (stream.buffer != NULL) + { + if (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1]) + { + ma_uint32 subBufferToUpdate = 0; + + if (stream.buffer->isSubBufferProcessed[0] && stream.buffer->isSubBufferProcessed[1]) + { + // Both buffers are available for updating. + // Update the first one and make sure the cursor is moved back to the front. + subBufferToUpdate = 0; + stream.buffer->frameCursorPos = 0; + } + else + { + // Just update whichever sub-buffer is processed. + subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1; + } + + ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2; + unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); + + // TODO: Get total frames processed on this buffer... DOES NOT WORK. + stream.buffer->totalFramesProcessed += subBufferSizeInFrames; + + // Does this API expect a whole buffer to be updated in one go? + // Assuming so, but if not will need to change this logic. + if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels) + { + ma_uint32 framesToWrite = subBufferSizeInFrames; + + if (framesToWrite > ((ma_uint32)samplesCount/stream.channels)) framesToWrite = (ma_uint32)samplesCount/stream.channels; + + ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); + memcpy(subBuffer, data, bytesToWrite); + + // Any leftover frames should be filled with zeros. + ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; + + if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); + + stream.buffer->isSubBufferProcessed[subBufferToUpdate] = false; + } + else TRACELOG(LOG_WARNING, "STREAM: Attempting to write too many frames to buffer"); + } + else TRACELOG(LOG_WARNING, "STREAM: Buffer not available for updating"); + } } // Check if any audio stream buffers requires refill @@ -2165,11 +1869,7 @@ bool IsAudioStreamProcessed(AudioStream stream) { if (stream.buffer == NULL) return false; - bool result = false; - ma_mutex_lock(&AUDIO.System.lock); - result = stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1]; - ma_mutex_unlock(&AUDIO.System.lock); - return result; + return (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1]); } // Play audio stream @@ -2190,7 +1890,7 @@ void ResumeAudioStream(AudioStream stream) ResumeAudioBuffer(stream.buffer); } -// Check if audio stream is playing +// Check if audio stream is playing. bool IsAudioStreamPlaying(AudioStream stream) { return IsAudioBufferPlaying(stream.buffer); @@ -2214,170 +1914,49 @@ void SetAudioStreamPitch(AudioStream stream, float pitch) SetAudioBufferPitch(stream.buffer, pitch); } -// Set pan for audio stream -void SetAudioStreamPan(AudioStream stream, float pan) -{ - SetAudioBufferPan(stream.buffer, pan); -} - // Default size for new audio streams void SetAudioStreamBufferSizeDefault(int size) { AUDIO.Buffer.defaultSize = size; } -// Audio thread callback to request new data -void SetAudioStreamCallback(AudioStream stream, AudioCallback callback) +int GetAudioStreamBufferSizeDefault() { - if (stream.buffer != NULL) - { - ma_mutex_lock(&AUDIO.System.lock); - stream.buffer->callback = callback; - ma_mutex_unlock(&AUDIO.System.lock); - } + // if the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate + if (AUDIO.Buffer.defaultSize == 0) + AUDIO.Buffer.defaultSize = AUDIO.System.device.sampleRate/30; + + return AUDIO.Buffer.defaultSize; } -// Add processor to audio stream. Contrary to buffers, the order of processors is important -// The new processor must be added at the end. As there aren't supposed to be a lot of processors attached to -// a given stream, we iterate through the list to find the end. That way we don't need a pointer to the last element -void AttachAudioStreamProcessor(AudioStream stream, AudioCallback process) -{ - ma_mutex_lock(&AUDIO.System.lock); - - rAudioProcessor *processor = (rAudioProcessor *)RL_CALLOC(1, sizeof(rAudioProcessor)); - processor->process = process; - - rAudioProcessor *last = stream.buffer->processor; - - while (last && last->next) - { - last = last->next; - } - if (last) - { - processor->prev = last; - last->next = processor; - } - else stream.buffer->processor = processor; - - ma_mutex_unlock(&AUDIO.System.lock); -} - -// Remove processor from audio stream -void DetachAudioStreamProcessor(AudioStream stream, AudioCallback process) -{ - ma_mutex_lock(&AUDIO.System.lock); - - rAudioProcessor *processor = stream.buffer->processor; - - while (processor) - { - rAudioProcessor *next = processor->next; - rAudioProcessor *prev = processor->prev; - - if (processor->process == process) - { - if (stream.buffer->processor == processor) stream.buffer->processor = next; - if (prev) prev->next = next; - if (next) next->prev = prev; - - RL_FREE(processor); - } - - processor = next; - } - - ma_mutex_unlock(&AUDIO.System.lock); -} - -// Add processor to audio pipeline. Order of processors is important -// Works the same way as {Attach,Detach}AudioStreamProcessor() functions, except -// these two work on the already mixed output just before sending it to the sound hardware -void AttachAudioMixedProcessor(AudioCallback process) -{ - ma_mutex_lock(&AUDIO.System.lock); - - rAudioProcessor *processor = (rAudioProcessor *)RL_CALLOC(1, sizeof(rAudioProcessor)); - processor->process = process; - - rAudioProcessor *last = AUDIO.mixedProcessor; - - while (last && last->next) - { - last = last->next; - } - if (last) - { - processor->prev = last; - last->next = processor; - } - else AUDIO.mixedProcessor = processor; - - ma_mutex_unlock(&AUDIO.System.lock); -} - -// Remove processor from audio pipeline -void DetachAudioMixedProcessor(AudioCallback process) -{ - ma_mutex_lock(&AUDIO.System.lock); - - rAudioProcessor *processor = AUDIO.mixedProcessor; - - while (processor) - { - rAudioProcessor *next = processor->next; - rAudioProcessor *prev = processor->prev; - - if (processor->process == process) - { - if (AUDIO.mixedProcessor == processor) AUDIO.mixedProcessor = next; - if (prev) prev->next = next; - if (next) next->prev = prev; - - RL_FREE(processor); - } - - processor = next; - } - - ma_mutex_unlock(&AUDIO.System.lock); -} - - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- // Log callback function -static void OnLog(void *pUserData, ma_uint32 level, const char *pMessage) +static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message) { - TRACELOG(LOG_WARNING, "miniaudio: %s", pMessage); // All log messages from miniaudio are errors + (void)pContext; + (void)pDevice; + + TRACELOG(LOG_WARNING, "miniaudio: %s", message); // All log messages from miniaudio are errors } -// Reads audio data from an AudioBuffer object in internal format +// Reads audio data from an AudioBuffer object in internal format. static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount) { - // Using audio buffer callback - if (audioBuffer->callback) - { - audioBuffer->callback(framesOut, frameCount); - audioBuffer->framesProcessed += frameCount; - - return frameCount; - } - ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames; ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames; if (currentSubBufferIndex > 1) return 0; - // Another thread can update the processed state of buffers, so + // Another thread can update the processed state of buffers so // we just take a copy here to try and avoid potential synchronization problems - bool isSubBufferProcessed[2] = { 0 }; + bool isSubBufferProcessed[2]; isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1]; - ma_uint32 frameSizeInBytes = ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn); + ma_uint32 frameSizeInBytes = ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn); // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0 ma_uint32 framesRead = 0; @@ -2385,7 +1964,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, { // We break from this loop differently depending on the buffer's usage // - For static buffers, we simply fill as much data as we can - // - For streaming buffers we only fill half of the buffer that are processed + // - For streaming buffers we only fill the halves of the buffer that are processed // Unprocessed halves must keep their audio data in-tact if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { @@ -2428,7 +2007,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, // We need to break from this loop if we're not looping if (!audioBuffer->looping) { - StopAudioBufferInLockedState(audioBuffer); + StopAudioBuffer(audioBuffer); break; } } @@ -2442,56 +2021,60 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, // For static buffers we can fill the remaining frames with silence for safety, but we don't want // to report those frames as "read". The reason for this is that the caller uses the return value - // to know whether a non-looping sound has finished playback + // to know whether or not a non-looping sound has finished playback. if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining; } return framesRead; } -// Reads audio data from an AudioBuffer object in device format, returned data will be in a format appropriate for mixing +// Reads audio data from an AudioBuffer object in device format. Returned data will be in a format appropriate for mixing. static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount) { // What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which // should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important // detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output - // frames. This can be achieved with ma_data_converter_get_required_input_frame_count() - ma_uint8 inputBuffer[4096] = { 0 }; - ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn); + // frames. This can be achieved with ma_data_converter_get_required_input_frame_count(). + ma_uint8 inputBuffer[4096]; + ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn); ma_uint32 totalOutputFramesProcessed = 0; while (totalOutputFramesProcessed < frameCount) { ma_uint64 outputFramesToProcessThisIteration = frameCount - totalOutputFramesProcessed; - ma_uint64 inputFramesToProcessThisIteration = 0; - (void)ma_data_converter_get_required_input_frame_count(&audioBuffer->converter, outputFramesToProcessThisIteration, &inputFramesToProcessThisIteration); + ma_uint64 inputFramesToProcessThisIteration = ma_data_converter_get_required_input_frame_count(&audioBuffer->converter, outputFramesToProcessThisIteration); if (inputFramesToProcessThisIteration > inputBufferFrameCap) { inputFramesToProcessThisIteration = inputBufferFrameCap; } - float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.channelsOut); + float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.config.channelsOut); - // At this point we can convert the data to our mixing format - ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration); + /* At this point we can convert the data to our mixing format. */ + ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration); /* Safe cast. */ ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration; ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration); - totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; // Safe cast + totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; /* Safe cast. */ - if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration) break; // Ran out of input data + if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration) + { + break; /* Ran out of input data. */ + } - // This should never be hit, but added here for safety - // Ensures we get out of the loop when no input nor output frames are processed - if ((inputFramesProcessedThisIteration == 0) && (outputFramesProcessedThisIteration == 0)) break; + /* This should never be hit, but will add it here for safety. Ensures we get out of the loop when no input nor output frames are processed. */ + if (inputFramesProcessedThisIteration == 0 && outputFramesProcessedThisIteration == 0) + { + break; + } } return totalOutputFramesProcessed; } + // Sending audio data to device callback function -// This function will be called when miniaudio needs more data // NOTE: All the mixing takes place here static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount) { @@ -2520,7 +2103,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const while (framesToRead > 0) { - float tempBuffer[1024] = { 0 }; // Frames for stereo + float tempBuffer[1024]; // 512 frames for stereo ma_uint32 framesToReadRightNow = framesToRead; if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS) @@ -2532,17 +2115,9 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const if (framesJustRead > 0) { float *framesOut = (float *)pFramesOut + (framesRead*AUDIO.System.device.playback.channels); - float *framesIn = tempBuffer; + float *framesIn = tempBuffer; - // Apply processors chain if defined - rAudioProcessor *processor = audioBuffer->processor; - while (processor) - { - processor->process(framesIn, framesJustRead); - processor = processor->next; - } - - MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer); + MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); framesToRead -= framesJustRead; framesRead += framesJustRead; @@ -2559,7 +2134,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const { if (!audioBuffer->looping) { - StopAudioBufferInLockedState(audioBuffer); + StopAudioBuffer(audioBuffer); break; } else @@ -2579,135 +2154,168 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const } } - rAudioProcessor *processor = AUDIO.mixedProcessor; - while (processor) - { - processor->process(pFramesOut, frameCount); - processor = processor->next; - } - ma_mutex_unlock(&AUDIO.System.lock); } -// Main mixing function, pretty simple in this project, just an accumulation -// NOTE: framesOut is both an input and an output, it is initially filled with zeros outside of this function -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer) +// This is the main mixing function. Mixing is pretty simple in this project - it's just an accumulation. +// NOTE: framesOut is both an input and an output. It will be initially filled with zeros outside of this function. +static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, float localVolume) { - const float localVolume = buffer->volume; - const ma_uint32 channels = AUDIO.System.device.playback.channels; - - if (channels == 2) // We consider panning + for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - const float left = buffer->pan; - const float right = 1.0f - left; - - // Fast sine approximation in [0..1] for pan law: y = 0.5f*x*(3 - x*x); - const float levels[2] = { localVolume*0.5f*left*(3.0f - left*left), localVolume*0.5f*right*(3.0f - right*right) }; - - float *frameOut = framesOut; - const float *frameIn = framesIn; - - for (ma_uint32 frame = 0; frame < frameCount; frame++) + for (ma_uint32 iChannel = 0; iChannel < AUDIO.System.device.playback.channels; ++iChannel) { - frameOut[0] += (frameIn[0]*levels[0]); - frameOut[1] += (frameIn[1]*levels[1]); + float *frameOut = framesOut + (iFrame*AUDIO.System.device.playback.channels); + const float *frameIn = framesIn + (iFrame*AUDIO.System.device.playback.channels); - frameOut += 2; - frameIn += 2; - } - } - else // We do not consider panning - { - for (ma_uint32 frame = 0; frame < frameCount; frame++) - { - for (ma_uint32 c = 0; c < channels; c++) - { - float *frameOut = framesOut + (frame*channels); - const float *frameIn = framesIn + (frame*channels); - - // Output accumulates input multiplied by volume to provided output (usually 0) - frameOut[c] += (frameIn[c]*localVolume); - } + frameOut[iChannel] += (frameIn[iChannel]*localVolume); } } } -// Check if an audio buffer is playing, assuming the audio system mutex has been locked -static bool IsAudioBufferPlayingInLockedState(AudioBuffer *buffer) +#if defined(SUPPORT_FILEFORMAT_WAV) +// Load WAV file data into Wave structure +// NOTE: Using dr_wav library +static Wave LoadWAV(const unsigned char *fileData, unsigned int fileSize) { - bool result = false; + Wave wave = { 0 }; + drwav wav = { 0 }; - if (buffer != NULL) result = (buffer->playing && !buffer->paused); + bool success = drwav_init_memory(&wav, fileData, fileSize, NULL); - return result; -} - -// Stop an audio buffer, assuming the audio system mutex has been locked -static void StopAudioBufferInLockedState(AudioBuffer *buffer) -{ - if (buffer != NULL) + if (success) { - if (IsAudioBufferPlayingInLockedState(buffer)) - { - buffer->playing = false; - buffer->paused = false; - buffer->frameCursorPos = 0; - buffer->framesProcessed = 0; - buffer->isSubBufferProcessed[0] = true; - buffer->isSubBufferProcessed[1] = true; - } + wave.sampleCount = (unsigned int)wav.totalPCMFrameCount*wav.channels; + wave.sampleRate = wav.sampleRate; + wave.sampleSize = 16; // NOTE: We are forcing conversion to 16bit + wave.channels = wav.channels; + wave.data = (short *)RL_MALLOC(wave.sampleCount*sizeof(short)); + drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data); } + else TRACELOG(LOG_WARNING, "WAVE: Failed to load WAV data"); + + drwav_uninit(&wav); + + return wave; } -// Update audio stream, assuming the audio system mutex has been locked -static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount) +// Save wave data as WAV file +// NOTE: Using dr_wav library +static int SaveWAV(Wave wave, const char *fileName) { - if (stream.buffer != NULL) - { - if (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1]) - { - ma_uint32 subBufferToUpdate = 0; + int success = false; - if (stream.buffer->isSubBufferProcessed[0] && stream.buffer->isSubBufferProcessed[1]) - { - // Both buffers are available for updating - // Update the first one and make sure the cursor is moved back to the front - subBufferToUpdate = 0; - stream.buffer->frameCursorPos = 0; - } - else - { - // Just update whichever sub-buffer is processed - subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1; - } + drwav wav = { 0 }; + drwav_data_format format = { 0 }; + format.container = drwav_container_riff; + format.format = DR_WAVE_FORMAT_PCM; + format.channels = wave.channels; + format.sampleRate = wave.sampleRate; + format.bitsPerSample = wave.sampleSize; - ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2; - unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); + void *fileData = NULL; + size_t fileDataSize = 0; + success = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); + if (success) success = (int)drwav_write_pcm_frames(&wav, wave.sampleCount/wave.channels, wave.data); + drwav_result result = drwav_uninit(&wav); - // Total frames processed in buffer is always the complete size, filled with 0 if required - stream.buffer->framesProcessed += subBufferSizeInFrames; + if (result == DRWAV_SUCCESS) success = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize); - // Does this API expect a whole buffer to be updated in one go? - // Assuming so, but if not will need to change this logic - if (subBufferSizeInFrames >= (ma_uint32)frameCount) - { - ma_uint32 framesToWrite = (ma_uint32)frameCount; + drwav_free(fileData, NULL); - ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); - memcpy(subBuffer, data, bytesToWrite); - - // Any leftover frames should be filled with zeros - ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; - - if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); - - stream.buffer->isSubBufferProcessed[subBufferToUpdate] = false; - } - else TRACELOG(LOG_WARNING, "STREAM: Attempting to write too many frames to buffer"); - } - else TRACELOG(LOG_WARNING, "STREAM: Buffer not available for updating"); - } + return success; } +#endif + +#if defined(SUPPORT_FILEFORMAT_OGG) +// Load OGG file data into Wave structure +// NOTE: Using stb_vorbis library +static Wave LoadOGG(const unsigned char *fileData, unsigned int fileSize) +{ + Wave wave = { 0 }; + + stb_vorbis *oggData = stb_vorbis_open_memory((unsigned char *)fileData, fileSize, NULL, NULL); + + if (oggData != NULL) + { + stb_vorbis_info info = stb_vorbis_get_info(oggData); + + wave.sampleRate = info.sample_rate; + wave.sampleSize = 16; // 16 bit per sample (short) + wave.channels = info.channels; + wave.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples(oggData)*info.channels; // Independent by channel + + float totalSeconds = stb_vorbis_stream_length_in_seconds(oggData); + if (totalSeconds > 10) TRACELOG(LOG_WARNING, "WAVE: OGG audio length larger than 10 seconds (%f sec.), that's a big file in memory, consider music streaming", totalSeconds); + + wave.data = (short *)RL_MALLOC(wave.sampleCount*sizeof(short)); + + // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) + stb_vorbis_get_samples_short_interleaved(oggData, info.channels, (short *)wave.data, wave.sampleCount); + TRACELOG(LOG_INFO, "WAVE: OGG data loaded successfully (%i Hz, %i bit, %s)", wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); + + stb_vorbis_close(oggData); + } + else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data"); + + return wave; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_FLAC) +// Load FLAC file data into Wave structure +// NOTE: Using dr_flac library +static Wave LoadFLAC(const unsigned char *fileData, unsigned int fileSize) +{ + Wave wave = { 0 }; + + // Decode the entire FLAC file in one go + unsigned long long int totalFrameCount = 0; + wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, fileSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL); + + if (wave.data != NULL) + { + wave.sampleCount = (unsigned int)totalFrameCount*wave.channels; + wave.sampleSize = 16; + + TRACELOG(LOG_INFO, "WAVE: FLAC data loaded successfully (%i Hz, %i bit, %s)", wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); + } + else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data"); + + return wave; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_MP3) +// Load MP3 file data into Wave structure +// NOTE: Using dr_mp3 library +static Wave LoadMP3(const unsigned char *fileData, unsigned int fileSize) +{ + Wave wave = { 0 }; + drmp3_config config = { 0 }; + + // Decode the entire MP3 file in one go + unsigned long long int totalFrameCount = 0; + wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, fileSize, &config, &totalFrameCount, NULL); + + if (wave.data != NULL) + { + wave.channels = config.channels; + wave.sampleRate = config.sampleRate; + wave.sampleCount = (int)totalFrameCount*wave.channels; + wave.sampleSize = 32; + + // NOTE: Only support up to 2 channels (mono, stereo) + // TODO: Really? + if (wave.channels > 2) TRACELOG(LOG_WARNING, "WAVE: MP3 channels number (%i) not supported", wave.channels); + + TRACELOG(LOG_INFO, "WAVE: MP3 file loaded successfully (%i Hz, %i bit, %s)", wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); + } + else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data"); + + return wave; +} +#endif // Some required functions for audio standalone module version #if defined(RAUDIO_STANDALONE) @@ -2735,55 +2343,43 @@ static const char *GetFileExtension(const char *fileName) return dot; } -// String pointer reverse break: returns right-most occurrence of charset in s -static const char *strprbrk(const char *s, const char *charset) +// Check if two text string are equal +// REQUIRES: strcmp() +static bool TextIsEqual(const char *text1, const char *text2) { - const char *latestMatch = NULL; - for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { } - return latestMatch; + bool result = false; + + if (strcmp(text1, text2) == 0) result = true; + + return result; } -// Get pointer to filename for a path string -static const char *GetFileName(const char *filePath) +// Get lower case version of provided string +// REQUIRES: tolower() +static const char *TextToLower(const char *text) { - const char *fileName = NULL; - if (filePath != NULL) fileName = strprbrk(filePath, "\\/"); + #define MAX_TEXT_BUFFER_LENGTH 1024 + + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - if (!fileName) return filePath; - - return fileName + 1; -} - -// Get filename string without extension (uses static string) -static const char *GetFileNameWithoutExt(const char *filePath) -{ - #define MAX_FILENAMEWITHOUTEXT_LENGTH 256 - - static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 }; - memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH); - - if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension - - int size = (int)strlen(fileName); // Get size in bytes - - for (int i = 0; (i < size) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++) + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) { - if (fileName[i] == '.') + if (text[i] != '\0') { - // NOTE: We break on first '.' found - fileName[i] = '\0'; - break; + buffer[i] = (char)tolower(text[i]); + //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32; } + else { buffer[i] = '\0'; break; } } - return fileName; + return buffer; } // Load data from file into a buffer -static unsigned char *LoadFileData(const char *fileName, int *dataSize) +static unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead) { unsigned char *data = NULL; - *dataSize = 0; + *bytesRead = 0; if (fileName != NULL) { @@ -2803,7 +2399,7 @@ static unsigned char *LoadFileData(const char *fileName, int *dataSize) // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file); - *dataSize = count; + *bytesRead = count; if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName); else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName); @@ -2820,7 +2416,7 @@ static unsigned char *LoadFileData(const char *fileName, int *dataSize) } // Save data to file from buffer -static bool SaveFileData(const char *fileName, void *data, int dataSize) +static bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite) { if (fileName != NULL) { @@ -2828,27 +2424,17 @@ static bool SaveFileData(const char *fileName, void *data, int dataSize) if (file != NULL) { - unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), dataSize, file); + unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file); if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName); - else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName); + else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName); else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName); fclose(file); } - else - { - TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); - return false; - } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); } - else - { - TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); - return false; - } - - return true; + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); } // Save text data to file (write), string must be '\0' terminated @@ -2867,22 +2453,10 @@ static bool SaveFileText(const char *fileName, char *text) fclose(file); } - else - { - TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); - return false; - } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); } - else - { - TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); - return false; - } - - return true; + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); } #endif #undef AudioBuffer - -#endif // SUPPORT_MODULE_RAUDIO diff --git a/raylib/raudio.go b/raylib/raudio.go index 129a71e..162d27c 100644 --- a/raylib/raudio.go +++ b/raylib/raudio.go @@ -1,131 +1,31 @@ -//go:build !noaudio // +build !noaudio package rl /* +//#include "external/stb_vorbis.c" + #include "raylib.h" #include - -extern void internalAudioStreamCallbackGo(void *, int); - -static void audioStreamWrapperCallback(void *data, unsigned int frames) { - internalAudioStreamCallbackGo(data, frames); -} - -static void setAudioStreamCallbackWrapper(AudioStream stream) { - SetAudioStreamCallback(stream, audioStreamWrapperCallback); -} - -extern void internalAudioMixedProcessorGo(void *, int); - -static void audioMixedProcessorCallback(void *data, unsigned int frames) { - internalAudioMixedProcessorGo(data, frames); -} - -static void setAudioMixedProcessorCallbackWrapper() { - AttachAudioMixedProcessor(audioMixedProcessorCallback); -} - -static void unsetAudioMixedProcessorCallbackWrapper() { - DetachAudioMixedProcessor(audioMixedProcessorCallback); -} */ import "C" -import ( - "reflect" - "sync" - "unsafe" -) - -var ( - internalAudioStreamCallback AudioCallback - audioMixedProcessorsMutex = sync.RWMutex{} - audioMixedProcessors = []AudioCallback{} -) - -// SetAudioStreamCallback - Audio thread callback to request new data -func SetAudioStreamCallback(stream AudioStream, callback AudioCallback) { - internalAudioStreamCallback = callback - C.setAudioStreamCallbackWrapper(*stream.cptr()) -} - -//export internalAudioStreamCallbackGo -func internalAudioStreamCallbackGo(data unsafe.Pointer, frames C.int) { - if internalAudioStreamCallback != nil { - internalAudioStreamCallback(unsafe.Slice((*float32)(data), frames), int(frames)) - } -} - -func AttachAudioMixedProcessor(callback AudioCallback) { - audioMixedProcessorsMutex.Lock() - defer audioMixedProcessorsMutex.Unlock() - - if len(audioMixedProcessors) == 0 { - C.setAudioMixedProcessorCallbackWrapper() - } - - audioMixedProcessors = append(audioMixedProcessors, callback) -} - -func DetachAudioMixedProcessor(callback AudioCallback) { - audioMixedProcessorsMutex.Lock() - defer audioMixedProcessorsMutex.Unlock() - - callbackPtr := reflect.ValueOf(callback).Pointer() - for i := len(audioMixedProcessors) - 1; i >= 0; i-- { - if reflect.ValueOf(audioMixedProcessors[i]).Pointer() == callbackPtr { - audioMixedProcessors = append(audioMixedProcessors[:i], audioMixedProcessors[i+1:]...) - break - } - } - - if len(audioMixedProcessors) == 0 { - C.unsetAudioMixedProcessorCallbackWrapper() - } -} - -//export internalAudioMixedProcessorGo -func internalAudioMixedProcessorGo(data unsafe.Pointer, frames C.int) { - for _, callback := range audioMixedProcessors { - callback(unsafe.Slice((*float32)(data), frames), int(frames)) - } -} - -// newWaveFromPointer - Returns new Wave from pointer -func newWaveFromPointer(ptr unsafe.Pointer) Wave { - return *(*Wave)(ptr) -} +import "unsafe" +import "reflect" // cptr returns C pointer func (w *Wave) cptr() *C.Wave { return (*C.Wave)(unsafe.Pointer(w)) } -// newSoundFromPointer - Returns new Sound from pointer -func newSoundFromPointer(ptr unsafe.Pointer) Sound { - return *(*Sound)(ptr) -} - func (s *Sound) cptr() *C.Sound { return (*C.Sound)(unsafe.Pointer(s)) } -// newAudioStreamFromPointer - Returns new AudioStream from pointer -func newAudioStreamFromPointer(ptr unsafe.Pointer) AudioStream { - return *(*AudioStream)(ptr) -} - // cptr returns C pointer func (a *AudioStream) cptr() *C.AudioStream { return (*C.AudioStream)(unsafe.Pointer(a)) } -// newMusicFromPointer - Returns new Music from pointer -func newMusicFromPointer(ptr unsafe.Pointer) Music { - return *(*Music)(ptr) -} - // InitAudioDevice - Initialize audio device and context func InitAudioDevice() { C.InitAudioDevice() @@ -149,13 +49,6 @@ func SetMasterVolume(volume float32) { C.SetMasterVolume(cvolume) } -// GetMasterVolume - Set master volume (listener) -func GetMasterVolume() float32 { - ret := C.GetMasterVolume() - v := float32(ret) - return v -} - // LoadWave - Load wave data from file into RAM func LoadWave(fileName string) Wave { cfileName := C.CString(fileName) @@ -176,14 +69,6 @@ func LoadWaveFromMemory(fileType string, fileData []byte, dataSize int32) Wave { return v } -// IsWaveValid - Checks if wave data is valid (data loaded and parameters) -func IsWaveValid(wave Wave) bool { - cwave := wave.cptr() - ret := C.IsWaveValid(*cwave) - v := bool(ret) - return v -} - // LoadSound - Load sound to memory func LoadSound(fileName string) Sound { cfileName := C.CString(fileName) @@ -201,22 +86,6 @@ func LoadSoundFromWave(wave Wave) Sound { return v } -// LoadSoundAlias - Create a new sound that shares the same sample data as the source sound, does not own the sound data -func LoadSoundAlias(source Sound) Sound { - csound := source.cptr() - ret := C.LoadSoundAlias(*csound) - v := newSoundFromPointer(unsafe.Pointer(&ret)) - return v -} - -// IsSoundValid - Checks if a sound is valid (data loaded and buffers initialized) -func IsSoundValid(sound Sound) bool { - csound := sound.cptr() - ret := C.IsSoundValid(*csound) - v := bool(ret) - return v -} - // UpdateSound - Update sound buffer with new data func UpdateSound(sound Sound, data []byte, samplesCount int32) { csound := sound.cptr() @@ -237,12 +106,6 @@ func UnloadSound(sound Sound) { C.UnloadSound(*csound) } -// UnloadSoundAlias - Unload a sound alias (does not deallocate sample data) -func UnloadSoundAlias(sound Sound) { - csound := sound.cptr() - C.UnloadSoundAlias(*csound) -} - // ExportWave - Export wave data to file func ExportWave(wave Wave, fileName string) { cwave := wave.cptr() @@ -257,12 +120,6 @@ func PlaySound(sound Sound) { C.PlaySound(*csound) } -// StopSound - Stop playing a sound -func StopSound(sound Sound) { - csound := sound.cptr() - C.StopSound(*csound) -} - // PauseSound - Pause a sound func PauseSound(sound Sound) { csound := sound.cptr() @@ -275,6 +132,12 @@ func ResumeSound(sound Sound) { C.ResumeSound(*csound) } +// StopSound - Stop playing a sound +func StopSound(sound Sound) { + csound := sound.cptr() + C.StopSound(*csound) +} + // IsSoundPlaying - Check if a sound is currently playing func IsSoundPlaying(sound Sound) bool { csound := sound.cptr() @@ -297,15 +160,8 @@ func SetSoundPitch(sound Sound, pitch float32) { C.SetSoundPitch(*csound, cpitch) } -// SetSoundPan - Set pan for a sound (0.5 is center) -func SetSoundPan(sound Sound, pan float32) { - csound := sound.cptr() - cpan := (C.float)(pan) - C.SetSoundPan(*csound, cpan) -} - // WaveFormat - Convert wave data to desired format -func WaveFormat(wave *Wave, sampleRate int32, sampleSize int32, channels int32) { +func WaveFormat(wave Wave, sampleRate int32, sampleSize int32, channels int32) { cwave := wave.cptr() csampleRate := (C.int)(sampleRate) csampleSize := (C.int)(sampleSize) @@ -321,25 +177,26 @@ func WaveCopy(wave Wave) Wave { return v } -// WaveCrop - Crop a wave to defined frames range -func WaveCrop(wave *Wave, initFrame int32, finalFrame int32) { +// WaveCrop - Crop a wave to defined samples range +func WaveCrop(wave Wave, initSample int32, finalSample int32) { cwave := wave.cptr() - cinitFrame := (C.int)(initFrame) - cfinalFrame := (C.int)(finalFrame) - C.WaveCrop(cwave, cinitFrame, cfinalFrame) + cinitSample := (C.int)(initSample) + cfinalSample := (C.int)(finalSample) + C.WaveCrop(cwave, cinitSample, cfinalSample) } // LoadWaveSamples - Get samples data from wave as a floats array func LoadWaveSamples(wave Wave) []float32 { + var data []float32 cwave := wave.cptr() ret := C.LoadWaveSamples(*cwave) - v := unsafe.Slice((*float32)(unsafe.Pointer(ret)), wave.FrameCount) - return v -} -// UnloadWaveSamples - Unload samples data loaded with LoadWaveSamples() -func UnloadWaveSamples(samples []float32) { - C.UnloadWaveSamples((*C.float)(unsafe.Pointer(&samples[0]))) + sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&data))) + sliceHeader.Cap = int(wave.SampleCount) + sliceHeader.Len = int(wave.SampleCount) + sliceHeader.Data = uintptr(unsafe.Pointer(ret)) + + return data } // LoadMusicStream - Load music stream from file @@ -362,14 +219,6 @@ func LoadMusicStreamFromMemory(fileType string, fileData []byte, dataSize int32) return v } -// IsMusicValid - Checks if a music stream is valid (context and buffers initialized) -func IsMusicValid(music Music) bool { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - ret := C.IsMusicValid(cmusic) - v := bool(ret) - return v -} - // UnloadMusicStream - Unload music stream func UnloadMusicStream(music Music) { cmusic := *(*C.Music)(unsafe.Pointer(&music)) @@ -382,14 +231,6 @@ func PlayMusicStream(music Music) { C.PlayMusicStream(cmusic) } -// IsMusicStreamPlaying - Check if music is playing -func IsMusicStreamPlaying(music Music) bool { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - ret := C.IsMusicStreamPlaying(cmusic) - v := bool(ret) - return v -} - // UpdateMusicStream - Updates buffers for music streaming func UpdateMusicStream(music Music) { cmusic := *(*C.Music)(unsafe.Pointer(&music)) @@ -414,11 +255,12 @@ func ResumeMusicStream(music Music) { C.ResumeMusicStream(cmusic) } -// SeekMusicStream - Seek music to a position (in seconds) -func SeekMusicStream(music Music, position float32) { +// IsMusicStreamPlaying - Check if music is playing +func IsMusicStreamPlaying(music Music) bool { cmusic := *(*C.Music)(unsafe.Pointer(&music)) - cposition := (C.float)(position) - C.SeekMusicStream(cmusic, cposition) + ret := C.IsMusicStreamPlaying(cmusic) + v := bool(ret) + return v } // SetMusicVolume - Set volume for music (1.0 is max level) @@ -435,13 +277,6 @@ func SetMusicPitch(music Music, pitch float32) { C.SetMusicPitch(cmusic, cpitch) } -// SetMusicPan - Set pan for a music (0.5 is center) -func SetMusicPan(music Music, pan float32) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - cpan := (C.float)(pan) - C.SetMusicPan(cmusic, cpan) -} - // GetMusicTimeLength - Get music time length (in seconds) func GetMusicTimeLength(music Music) float32 { cmusic := *(*C.Music)(unsafe.Pointer(&music)) @@ -458,38 +293,30 @@ func GetMusicTimePlayed(music Music) float32 { return v } -// LoadAudioStream - Load audio stream (to stream raw audio pcm data) -func LoadAudioStream(sampleRate uint32, sampleSize uint32, channels uint32) AudioStream { +// InitAudioStream - Init audio stream (to stream raw audio pcm data) +func InitAudioStream(sampleRate uint32, sampleSize uint32, channels uint32) AudioStream { csampleRate := (C.uint)(sampleRate) csampleSize := (C.uint)(sampleSize) cchannels := (C.uint)(channels) - ret := C.LoadAudioStream(csampleRate, csampleSize, cchannels) + ret := C.InitAudioStream(csampleRate, csampleSize, cchannels) v := newAudioStreamFromPointer(unsafe.Pointer(&ret)) return v } -// IsAudioStreamValid - Checks if an audio stream is valid (buffers initialized) -func IsAudioStreamValid(stream AudioStream) bool { - cstream := stream.cptr() - ret := C.IsAudioStreamValid(*cstream) - v := bool(ret) - return v -} - -// UnloadAudioStream - Unload audio stream and free memory -func UnloadAudioStream(stream AudioStream) { - cstream := stream.cptr() - C.UnloadAudioStream(*cstream) -} - // UpdateAudioStream - Update audio stream buffers with data -func UpdateAudioStream(stream AudioStream, data []float32) { +func UpdateAudioStream(stream AudioStream, data []float32, samplesCount int32) { cstream := stream.cptr() cdata := unsafe.Pointer(&data[0]) - csamplesCount := (C.int)(len(data)) + csamplesCount := (C.int)(samplesCount) C.UpdateAudioStream(*cstream, cdata, csamplesCount) } +// CloseAudioStream - Close audio stream and free memory +func CloseAudioStream(stream AudioStream) { + cstream := stream.cptr() + C.CloseAudioStream(*cstream) +} + // IsAudioStreamProcessed - Check if any audio stream buffers requires refill func IsAudioStreamProcessed(stream AudioStream) bool { cstream := stream.cptr() @@ -516,43 +343,26 @@ func ResumeAudioStream(stream AudioStream) { C.ResumeAudioStream(*cstream) } -// IsAudioStreamPlaying - Check if audio stream is playing -func IsAudioStreamPlaying(stream AudioStream) bool { - cstream := stream.cptr() - ret := C.IsAudioStreamPlaying(*cstream) - v := bool(ret) - return v -} - // StopAudioStream - Stop audio stream func StopAudioStream(stream AudioStream) { cstream := stream.cptr() C.StopAudioStream(*cstream) } -// SetAudioStreamVolume - Set volume for audio stream (1.0 is max level) -func SetAudioStreamVolume(stream AudioStream, volume float32) { - cstream := stream.cptr() - cvolume := (C.float)(volume) - C.SetAudioStreamVolume(*cstream, cvolume) +// PlaySoundMulti - Play a sound (using multichannel buffer pool) +func PlaySoundMulti(sound Sound) { + csound := sound.cptr() + C.PlaySoundMulti(*csound) } -// SetAudioStreamPitch - Set pitch for audio stream (1.0 is base level) -func SetAudioStreamPitch(stream AudioStream, pitch float32) { - cstream := stream.cptr() - cpitch := (C.float)(pitch) - C.SetAudioStreamPitch(*cstream, cpitch) +// GetSoundsPlaying - Get number of sounds playing in the multichannel +func GetSoundsPlaying() int { + ret := C.GetSoundsPlaying() + v := int(ret) + return v } -// SetAudioStreamPan - Set pan for audio stream (0.5 is centered) -func SetAudioStreamPan(stream AudioStream, pan float32) { - cstream := stream.cptr() - cpan := (C.float)(pan) - C.SetAudioStreamPan(*cstream, cpan) -} - -// SetAudioStreamBufferSizeDefault - Default size for new audio streams -func SetAudioStreamBufferSizeDefault(size int32) { - csize := (C.int)(size) - C.SetAudioStreamBufferSizeDefault(csize) +// StopSoundMulti - Stop any sound playing (using multichannel buffer pool) +func StopSoundMulti() { + C.StopSoundMulti() } diff --git a/raylib/raudio.h b/raylib/raudio.h new file mode 100644 index 0000000..a38c695 --- /dev/null +++ b/raylib/raudio.h @@ -0,0 +1,200 @@ +/********************************************************************************************** +* +* raudio v1.0 - A simple and easy-to-use audio library based on miniaudio +* +* FEATURES: +* - Manage audio device (init/close) +* - Load and unload audio files +* - Format wave data (sample rate, size, channels) +* - Play/Stop/Pause/Resume loaded audio +* - Manage mixing channels +* - Manage raw audio context +* +* DEPENDENCIES: +* miniaudio.h - Audio device management lib (https://github.com/dr-soft/miniaudio) +* stb_vorbis.h - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) +* dr_mp3.h - MP3 audio file loading (https://github.com/mackron/dr_libs) +* dr_flac.h - FLAC audio file loading (https://github.com/mackron/dr_libs) +* jar_xm.h - XM module file loading +* jar_mod.h - MOD audio file loading +* +* CONTRIBUTORS: +* David Reid (github: @mackron) (Nov. 2017): +* - Complete port to miniaudio library +* +* Joshua Reisenauer (github: @kd7tck) (2015) +* - XM audio module support (jar_xm) +* - MOD audio module support (jar_mod) +* - Mixing channels support +* - Raw audio context support +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAUDIO_H +#define RAUDIO_H + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Allow custom memory allocators +#ifndef RL_MALLOC + #define RL_MALLOC(sz) malloc(sz) +#endif +#ifndef RL_CALLOC + #define RL_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RL_FREE + #define RL_FREE(p) free(p) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#ifndef __cplusplus +// Boolean type + #if !defined(_STDBOOL_H) + typedef enum { false, true } bool; + #define _STDBOOL_H + #endif +#endif + +// Wave type, defines audio wave data +typedef struct Wave { + unsigned int sampleCount; // Total number of samples + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + void *data; // Buffer data pointer +} Wave; + +typedef struct rAudioBuffer rAudioBuffer; + +// Audio stream type +// NOTE: Useful to create custom audio streams not bound to a specific file +typedef struct AudioStream { + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + + rAudioBuffer *buffer; // Pointer to internal data used by the audio system +} AudioStream; + +// Sound source type +typedef struct Sound { + unsigned int sampleCount; // Total number of samples + AudioStream stream; // Audio stream +} Sound; + +// Music stream type (audio file streaming from memory) +// NOTE: Anything longer than ~10 seconds should be streamed +typedef struct Music { + int ctxType; // Type of music context (audio filetype) + void *ctxData; // Audio context data, depends on type + + bool looping; // Music looping enable + unsigned int sampleCount; // Total number of samples + + AudioStream stream; // Audio stream +} Music; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +// Audio device management functions +void InitAudioDevice(void); // Initialize audio device and context +void CloseAudioDevice(void); // Close the audio device and context +bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully +void SetMasterVolume(float volume); // Set master volume (listener) + +// Wave/Sound loading/unloading functions +Wave LoadWave(const char *fileName); // Load wave data from file +Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. ".wav" +Sound LoadSound(const char *fileName); // Load sound from file +Sound LoadSoundFromWave(Wave wave); // Load sound from wave data +void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data +void UnloadWave(Wave wave); // Unload wave data +void UnloadSound(Sound sound); // Unload sound +bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success +bool ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h), returns true on success + +// Wave/Sound management functions +void PlaySound(Sound sound); // Play a sound +void StopSound(Sound sound); // Stop playing a sound +void PauseSound(Sound sound); // Pause a sound +void ResumeSound(Sound sound); // Resume a paused sound +void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool) +void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool) +int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel +bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing +void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) +void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) +void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +Wave WaveCopy(Wave wave); // Copy a wave to a new wave +void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range +float *LoadWaveSamples(Wave wave); // Load samples data from wave as a floats array +void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples() + +// Music management functions +Music LoadMusicStream(const char *fileName); // Load music stream from file +Music LoadMusicStreamFromMemory(const char *fileType, unsigned char* data, int dataSize); // Load music stream from data +void UnloadMusicStream(Music music); // Unload music stream +void PlayMusicStream(Music music); // Start music playing +bool IsMusicStreamPlaying(Music music); // Check if music is playing +void UpdateMusicStream(Music music); // Updates buffers for music streaming +void StopMusicStream(Music music); // Stop music playing +void PauseMusicStream(Music music); // Pause music playing +void ResumeMusicStream(Music music); // Resume playing paused music +void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +float GetMusicTimeLength(Music music); // Get music time length (in seconds) +float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) + +// AudioStream management functions +AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) +void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data +void CloseAudioStream(AudioStream stream); // Close audio stream and free memory +bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +void PlayAudioStream(AudioStream stream); // Play audio stream +void PauseAudioStream(AudioStream stream); // Pause audio stream +void ResumeAudioStream(AudioStream stream); // Resume audio stream +bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing +void StopAudioStream(AudioStream stream); // Stop audio stream +void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) +void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) +void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams + +#ifdef __cplusplus +} +#endif + +#endif // RAUDIO_H diff --git a/raylib/raylib.go b/raylib/raylib.go index 0cd3126..a5b8087 100644 --- a/raylib/raylib.go +++ b/raylib/raylib.go @@ -1,15 +1,47 @@ /* -Package raylib - Go bindings for raylib, a simple and easy-to-use library to enjoy videogames programming. +Package raylib - Go bindings for raylib, a simple and easy-to-use library to learn videogames programming. raylib is highly inspired by Borland BGI graphics lib and by XNA framework. + raylib could be useful for prototyping, tools development, graphic applications, embedded systems and education. NOTE for ADVENTURERS: raylib is a programming library to learn videogames programming; no fancy interface, no visual helpers, no auto-debugging... just coding in the most pure spartan-programmers way. + +Example: + + package main + + import "github.com/gen2brain/raylib-go/raylib" + + func main() { + rl.InitWindow(800, 450, "raylib [core] example - basic window") + + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LightGray) + + rl.EndDrawing() + } + + rl.CloseWindow() + } + + */ package rl +/* +#include "raylib.h" +#include +*/ +import "C" import ( - "image/color" + "image" "io" "runtime" "unsafe" @@ -23,7 +55,7 @@ func init() { // Wave type, defines audio wave data type Wave struct { // Number of samples - FrameCount uint32 + SampleCount uint32 // Frequency (samples per second) SampleRate uint32 // Bit depth (bits per sample): 8, 16, 32 (24 not supported) @@ -31,43 +63,52 @@ type Wave struct { // Number of channels (1-mono, 2-stereo) Channels uint32 // Buffer data pointer - Data unsafe.Pointer + data unsafe.Pointer } // NewWave - Returns new Wave func NewWave(sampleCount, sampleRate, sampleSize, channels uint32, data []byte) Wave { d := unsafe.Pointer(&data[0]) - return Wave{sampleCount, sampleRate, sampleSize, channels, d} } -// AudioCallback function. -type AudioCallback func(data []float32, frames int) +// newWaveFromPointer - Returns new Wave from pointer +func newWaveFromPointer(ptr unsafe.Pointer) Wave { + return *(*Wave)(ptr) +} // Sound source type type Sound struct { - Stream AudioStream - FrameCount uint32 - _ [4]byte + Stream AudioStream + SampleCount uint32 + _ [4]byte +} + +// newSoundFromPointer - Returns new Sound from pointer +func newSoundFromPointer(ptr unsafe.Pointer) Sound { + return *(*Sound)(ptr) } // Music type (file streaming from memory) // NOTE: Anything longer than ~10 seconds should be streamed type Music struct { - Stream AudioStream - FrameCount uint32 - Looping bool - CtxType int32 - CtxData unsafe.Pointer + Stream AudioStream + SampleCount uint32 + Looping bool + CtxType int32 + CtxData unsafe.Pointer +} + +// newMusicFromPointer - Returns new Music from pointer +func newMusicFromPointer(ptr unsafe.Pointer) Music { + return *(*Music)(ptr) } // AudioStream type // NOTE: Useful to create custom audio streams not bound to a specific file type AudioStream struct { // Buffer - Buffer *AudioBuffer - // Processor - Processor *AudioProcessor + Buffer *C.rAudioBuffer // Frequency (samples per second) SampleRate uint32 // Bit depth (bits per sample): 8, 16, 32 (24 not supported) @@ -77,113 +118,9 @@ type AudioStream struct { _ [4]byte } -type maDataConverter struct { - FormatIn uint32 - FormatOut uint32 - ChannelsIn uint32 - ChannelsOut uint32 - SampleRateIn uint32 - SampleRateOut uint32 - DitherMode uint32 - ExecutionPath uint32 - ChannelConverter maChannelConverter - Resampler maResampler - HasPreFormatConversion uint8 - HasPostFormatConversion uint8 - HasChannelConverter uint8 - HasResampler uint8 - IsPassthrough uint8 - X_ownsHeap uint8 - X_pHeap *byte -} - -type maChannelConverter struct { - Format uint32 - ChannelsIn uint32 - ChannelsOut uint32 - MixingMode uint32 - ConversionPath uint32 - PChannelMapIn *uint8 - PChannelMapOut *uint8 - PShuffleTable *uint8 - Weights [8]byte - X_pHeap *byte - X_ownsHeap uint32 - Pad_cgo_0 [4]byte -} - -type maResampler struct { - PBackend *byte - PBackendVTable *maResamplingBackendVtable - PBackendUserData *byte - Format uint32 - Channels uint32 - SampleRateIn uint32 - SampleRateOut uint32 - State [136]byte - X_pHeap *byte - X_ownsHeap uint32 - Pad_cgo_0 [4]byte -} - -type maResamplingBackendVtable struct { - OnGetHeapSize *[0]byte - OnInit *[0]byte - OnUninit *[0]byte - OnProcess *[0]byte - OnSetRate *[0]byte - OnGetInputLatency *[0]byte - OnGetOutputLatency *[0]byte - OnGetRequiredInputFrameCount *[0]byte - OnGetExpectedOutputFrameCount *[0]byte - OnReset *[0]byte -} - -type AudioBuffer struct { - Converter maDataConverter - Callback *[0]byte - Processor *AudioProcessor - Volume float32 - Pitch float32 - Pan float32 - Playing bool - Paused bool - Looping bool - Usage int32 - IsSubBufferProcessed [2]bool - SizeInFrames uint32 - FrameCursorPos uint32 - FramesProcessed uint32 - Data *uint8 - Next *AudioBuffer - Prev *AudioBuffer -} - -type AudioProcessor struct { - Process *[0]byte - Next *AudioProcessor - Prev *AudioProcessor -} - -// AutomationEvent - Automation event -type AutomationEvent struct { - Frame uint32 - Type uint32 - Params [4]int32 -} - -// AutomationEventList - Automation event list -type AutomationEventList struct { - Capacity uint32 - Count uint32 - // Events array (c array) - // - // Use AutomationEventList.GetEvents instead (go slice) - Events *AutomationEvent -} - -func (a *AutomationEventList) GetEvents() []AutomationEvent { - return unsafe.Slice(a.Events, a.Count) +// newAudioStreamFromPointer - Returns new AudioStream from pointer +func newAudioStreamFromPointer(ptr unsafe.Pointer) AudioStream { + return *(*AudioStream)(ptr) } // CameraMode type @@ -207,6 +144,22 @@ const ( CameraOrthographic ) +// ShaderUniformDataType type +type ShaderUniformDataType int32 + +// ShaderUniformDataType enumeration +const ( + ShaderUniformFloat ShaderUniformDataType = iota + ShaderUniformVec2 + ShaderUniformVec3 + ShaderUniformVec4 + ShaderUniformInt + ShaderUniformIvec2 + ShaderUniformIvec3 + ShaderUniformIvec4 + ShaderUniformSampler2d +) + // Some basic Defines const ( Pi = 3.1415927 @@ -216,40 +169,33 @@ const ( // Raylib Config Flags // Set to try enabling V-Sync on GPU - FlagVsyncHint = 0x00000040 + FlagVsyncHint = C.FLAG_VSYNC_HINT // Set to run program in fullscreen - FlagFullscreenMode = 0x00000002 + FlagFullscreenMode = C.FLAG_FULLSCREEN_MODE // Set to allow resizable window - FlagWindowResizable = 0x00000004 + FlagWindowResizable = C.FLAG_WINDOW_RESIZABLE // Set to disable window decoration (frame and buttons) - FlagWindowUndecorated = 0x00000008 + FlagWindowUndecorated = C.FLAG_WINDOW_UNDECORATED // Set to hide window - FlagWindowHidden = 0x00000080 + FlagWindowHidden = C.FLAG_WINDOW_HIDDEN // Set to minimize window (iconify) - FlagWindowMinimized = 0x00000200 + FlagWindowMinimized = C.FLAG_WINDOW_MINIMIZED // Set to maximize window (expanded to monitor) - FlagWindowMaximized = 0x00000400 + FlagWindowMaximized = C.FLAG_WINDOW_MAXIMIZED // Set to window non focused - FlagWindowUnfocused = 0x00000800 + FlagWindowUnfocused = C.FLAG_WINDOW_UNFOCUSED // Set to window always on top - FlagWindowTopmost = 0x00001000 + FlagWindowTopmost = C.FLAG_WINDOW_TOPMOST // Set to allow windows running while minimized - FlagWindowAlwaysRun = 0x00000100 + FlagWindowAlwaysRun = C.FLAG_WINDOW_ALWAYS_RUN // Set to allow transparent window - FlagWindowTransparent = 0x00000010 + FlagWindowTransparent = C.FLAG_WINDOW_TRANSPARENT // Set to support HighDPI - FlagWindowHighdpi = 0x00002000 - // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED - FlagWindowMousePassthrough = 0x00004000 - // Set to run program in borderless windowed mode - FlagBorderlessWindowedMode = 0x00008000 + FlagWindowHighdpi = C.FLAG_WINDOW_HIGHDPI // Set to try enabling MSAA 4X - FlagMsaa4xHint = 0x00000020 + FlagMsaa4xHint = C.FLAG_MSAA_4X_HINT // Set to try enabling interlaced video format (for V3D) - FlagInterlacedHint = 0x00010000 - - // KeyNull is used for no key pressed - KeyNull = 0 + FlagInterlacedHint = C.FLAG_INTERLACED_HINT // Keyboard Function Keys KeySpace = 32 @@ -364,75 +310,99 @@ const ( // Android keys KeyBack = 4 - KeyMenu = 5 + KeyMenu = 82 KeyVolumeUp = 24 KeyVolumeDown = 25 - MouseLeftButton = MouseButtonLeft - MouseRightButton = MouseButtonRight - MouseMiddleButton = MouseButtonMiddle -) + // Mouse Buttons + MouseLeftButton = 0 + MouseRightButton = 1 + MouseMiddleButton = 2 -type MouseButton int32 + // Touch points registered + MaxTouchPoints = 2 -// Mouse Buttons -const ( - MouseButtonLeft MouseButton = iota - MouseButtonRight - MouseButtonMiddle - MouseButtonSide - MouseButtonExtra - MouseButtonForward - MouseButtonBack -) + // Gamepad Number + GamepadPlayer1 = 0 + GamepadPlayer2 = 1 + GamepadPlayer3 = 2 + GamepadPlayer4 = 3 -// Mouse cursor -type MouseCursor = int32 + // Gamepad Buttons/Axis -const ( - MouseCursorDefault MouseCursor = iota // Default pointer shape - MouseCursorArrow // Arrow shape - MouseCursorIBeam // Text writing cursor shape - MouseCursorCrosshair // Cross shape - MouseCursorPointingHand // Pointing hand cursor - MouseCursorResizeEW // Horizontal resize/move arrow shape - MouseCursorResizeNS // Vertical resize/move arrow shape - MouseCursorResizeNWSE // Top-left to bottom-right diagonal resize/move arrow shape - MouseCursorResizeNESW // The top-right to bottom-left diagonal resize/move arrow shape - MouseCursorResizeAll // The omni-directional resize/move cursor shape - MouseCursorNotAllowed // The operation-not-allowed shape -) + // PS3 USB Controller Buttons + GamepadPs3ButtonTriangle = 0 + GamepadPs3ButtonCircle = 1 + GamepadPs3ButtonCross = 2 + GamepadPs3ButtonSquare = 3 + GamepadPs3ButtonL1 = 6 + GamepadPs3ButtonR1 = 7 + GamepadPs3ButtonL2 = 4 + GamepadPs3ButtonR2 = 5 + GamepadPs3ButtonStart = 8 + GamepadPs3ButtonSelect = 9 + GamepadPs3ButtonUp = 24 + GamepadPs3ButtonRight = 25 + GamepadPs3ButtonDown = 26 + GamepadPs3ButtonLeft = 27 + GamepadPs3ButtonPs = 12 -// Gamepad Buttons -const ( - GamepadButtonUnknown = iota // Unknown button, just for error checking - GamepadButtonLeftFaceUp // Gamepad left DPAD up button - GamepadButtonLeftFaceRight // Gamepad left DPAD right button - GamepadButtonLeftFaceDown // Gamepad left DPAD down button - GamepadButtonLeftFaceLeft // Gamepad left DPAD left button - GamepadButtonRightFaceUp // Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) - GamepadButtonRightFaceRight // Gamepad right button right (i.e. PS3: Circle, Xbox: B) - GamepadButtonRightFaceDown // Gamepad right button down (i.e. PS3: Cross, Xbox: A) - GamepadButtonRightFaceLeft // Gamepad right button left (i.e. PS3: Square, Xbox: X) - GamepadButtonLeftTrigger1 // Gamepad top/back trigger left (first), it could be a trailing button - GamepadButtonLeftTrigger2 // Gamepad top/back trigger left (second), it could be a trailing button - GamepadButtonRightTrigger1 // Gamepad top/back trigger right (first), it could be a trailing button - GamepadButtonRightTrigger2 // Gamepad top/back trigger right (second), it could be a trailing button - GamepadButtonMiddleLeft // Gamepad center buttons, left one (i.e. PS3: Select) - GamepadButtonMiddle // Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) - GamepadButtonMiddleRight // Gamepad center buttons, right one (i.e. PS3: Start) - GamepadButtonLeftThumb // Gamepad joystick pressed button left - GamepadButtonRightThumb // Gamepad joystick pressed button right -) + // PS3 USB Controller Axis + GamepadPs3AxisLeftX = 0 + GamepadPs3AxisLeftY = 1 + GamepadPs3AxisRightX = 2 + GamepadPs3AxisRightY = 5 + // [1..-1] (pressure-level) + GamepadPs3AxisL2 = 3 + // [1..-1] (pressure-level) + GamepadPs3AxisR2 = 4 -// Gamepad Axis -const ( - GamepadAxisLeftX = iota // Gamepad left stick X axis - GamepadAxisLeftY // Gamepad left stick Y axis - GamepadAxisRightX // Gamepad right stick X axis - GamepadAxisRightY // Gamepad right stick Y axis - GamepadAxisLeftTrigger // Gamepad back trigger left, pressure level: [1..-1] - GamepadAxisRightTrigger // Gamepad back trigger right, pressure level: [1..-1] + // Xbox360 USB Controller Buttons + GamepadXboxButtonA = 0 + GamepadXboxButtonB = 1 + GamepadXboxButtonX = 2 + GamepadXboxButtonY = 3 + GamepadXboxButtonLb = 4 + GamepadXboxButtonRb = 5 + GamepadXboxButtonSelect = 6 + GamepadXboxButtonStart = 7 + GamepadXboxButtonUp = 10 + GamepadXboxButtonRight = 11 + GamepadXboxButtonDown = 12 + GamepadXboxButtonLeft = 13 + GamepadXboxButtonHome = 8 + + // Android Gamepad Controller (SNES CLASSIC) + GamepadAndroidDpadUp = 19 + GamepadAndroidDpadDown = 20 + GamepadAndroidDpadLeft = 21 + GamepadAndroidDpadRight = 22 + GamepadAndroidDpadCenter = 23 + + GamepadAndroidButtonA = 96 + GamepadAndroidButtonB = 97 + GamepadAndroidButtonC = 98 + GamepadAndroidButtonX = 99 + GamepadAndroidButtonY = 100 + GamepadAndroidButtonZ = 101 + GamepadAndroidButtonL1 = 102 + GamepadAndroidButtonR1 = 103 + GamepadAndroidButtonL2 = 104 + GamepadAndroidButtonR2 = 105 + + // Xbox360 USB Controller Axis + // [-1..1] (left->right) + GamepadXboxAxisLeftX = 0 + // [1..-1] (up->down) + GamepadXboxAxisLeftY = 1 + // [-1..1] (left->right) + GamepadXboxAxisRightX = 2 + // [1..-1] (up->down) + GamepadXboxAxisRightY = 3 + // [-1..1] (pressure-level) + GamepadXboxAxisLt = 4 + // [-1..1] (pressure-level) + GamepadXboxAxisRt = 5 ) // Some Basic Colors @@ -503,6 +473,11 @@ func NewVector2(x, y float32) Vector2 { return Vector2{x, y} } +// newVector2FromPointer - Returns new Vector2 from pointer +func newVector2FromPointer(ptr unsafe.Pointer) Vector2 { + return *(*Vector2)(ptr) +} + // Vector3 type type Vector3 struct { X float32 @@ -511,8 +486,13 @@ type Vector3 struct { } // NewVector3 - Returns new Vector3 -func NewVector3(x, y, z float32) Vector3 { - return Vector3{x, y, z} +func NewVector3(X, Y, Z float32) Vector3 { + return Vector3{X, Y, Z} +} + +// newVector3FromPointer - Returns new Vector3 from pointer +func newVector3FromPointer(ptr unsafe.Pointer) Vector3 { + return *(*Vector3)(ptr) } // Vector4 type @@ -524,8 +504,13 @@ type Vector4 struct { } // NewVector4 - Returns new Vector4 -func NewVector4(x, y, z, w float32) Vector4 { - return Vector4{x, y, z, w} +func NewVector4(X, Y, Z, W float32) Vector4 { + return Vector4{X, Y, Z, W} +} + +// newVector4FromPointer - Returns new Vector4 from pointer +func newVector4FromPointer(ptr unsafe.Pointer) Vector4 { + return *(*Vector4)(ptr) } // Matrix type (OpenGL style 4x4 - right handed, column major) @@ -541,6 +526,11 @@ func NewMatrix(m0, m4, m8, m12, m1, m5, m9, m13, m2, m6, m10, m14, m3, m7, m11, return Matrix{m0, m4, m8, m12, m1, m5, m9, m13, m2, m6, m10, m14, m3, m7, m11, m15} } +// newMatrixFromPointer - Returns new Matrix from pointer +func newMatrixFromPointer(ptr unsafe.Pointer) Matrix { + return *(*Matrix)(ptr) +} + // Mat2 type (used for polygon shape rotation matrix) type Mat2 struct { M00 float32 @@ -554,8 +544,13 @@ func NewMat2(m0, m1, m10, m11 float32) Mat2 { return Mat2{m0, m1, m10, m11} } -// Quaternion, 4 components (Vector4 alias) -type Quaternion = Vector4 +// Quaternion type +type Quaternion struct { + X float32 + Y float32 + Z float32 + W float32 +} // NewQuaternion - Returns new Quaternion func NewQuaternion(x, y, z, w float32) Quaternion { @@ -563,12 +558,21 @@ func NewQuaternion(x, y, z, w float32) Quaternion { } // Color type, RGBA (32bit) -// TODO remove later, keep type for now to not break code -type Color = color.RGBA +type Color struct { + R uint8 + G uint8 + B uint8 + A uint8 +} // NewColor - Returns new Color -func NewColor(r, g, b, a uint8) color.RGBA { - return color.RGBA{r, g, b, a} +func NewColor(r, g, b, a uint8) Color { + return Color{r, g, b, a} +} + +// newColorFromPointer - Returns new Color from pointer +func newColorFromPointer(ptr unsafe.Pointer) Color { + return *(*Color)(ptr) } // Rectangle type @@ -584,6 +588,11 @@ func NewRectangle(x, y, width, height float32) Rectangle { return Rectangle{x, y, width, height} } +// newRectangleFromPointer - Returns new Rectangle from pointer +func newRectangleFromPointer(ptr unsafe.Pointer) Rectangle { + return *(*Rectangle)(ptr) +} + // ToInt32 converts rectangle to int32 variant func (r *Rectangle) ToInt32() RectangleInt32 { rect := RectangleInt32{} @@ -636,6 +645,11 @@ func NewCamera3D(pos, target, up Vector3, fovy float32, ct CameraProjection) Cam return Camera3D{pos, target, up, fovy, ct} } +// newCamera3DFromPointer - Returns new Camera3D from pointer +func newCamera3DFromPointer(ptr unsafe.Pointer) Camera3D { + return *(*Camera3D)(ptr) +} + // Camera2D type, defines a 2d camera type Camera2D struct { // Camera offset (displacement from target) @@ -653,6 +667,11 @@ func NewCamera2D(offset, target Vector2, rotation, zoom float32) Camera2D { return Camera2D{offset, target, rotation, zoom} } +// newCamera2DFromPointer - Returns new Camera2D from pointer +func newCamera2DFromPointer(ptr unsafe.Pointer) Camera2D { + return *(*Camera2D)(ptr) +} + // BoundingBox type type BoundingBox struct { // Minimum vertex box-corner @@ -666,6 +685,11 @@ func NewBoundingBox(min, max Vector3) BoundingBox { return BoundingBox{min, max} } +// newBoundingBoxFromPointer - Returns new BoundingBox from pointer +func newBoundingBoxFromPointer(ptr unsafe.Pointer) BoundingBox { + return *(*BoundingBox)(ptr) +} + // Asset file type Asset interface { io.ReadSeeker @@ -693,71 +717,35 @@ const ( // Shader location point type const ( - ShaderLocVertexPosition = iota - ShaderLocVertexTexcoord01 - ShaderLocVertexTexcoord02 - ShaderLocVertexNormal - ShaderLocVertexTangent - ShaderLocVertexColor - ShaderLocMatrixMvp - ShaderLocMatrixView - ShaderLocMatrixProjection - ShaderLocMatrixModel - ShaderLocMatrixNormal - ShaderLocVectorView - ShaderLocColorDiffuse - ShaderLocColorSpecular - ShaderLocColorAmbient - ShaderLocMapAlbedo - ShaderLocMapMetalness - ShaderLocMapNormal - ShaderLocMapRoughness - ShaderLocMapOcclusion - ShaderLocMapEmission - ShaderLocMapHeight - ShaderLocMapCubemap - ShaderLocMapIrradiance - ShaderLocMapPrefilter - ShaderLocMapBrdf - - ShaderLocMapDiffuse = ShaderLocMapAlbedo - ShaderLocMapSpecular = ShaderLocMapMetalness + LocVertexPosition = iota + LocVertexTexcoord01 + LocVertexTexcoord02 + LocVertexNormal + LocVertexTangent + LocVertexColor + LocMatrixMvp + LocMatrixView + LocMatrixProjection + LocMatrixModel + LocMatrixNormal + LocVectorView + LocColorDiffuse + LocColorSpecular + LocColorAmbient + LocMapAlbedo + LocMapMetalness + LocMapNormal + LocMapRoughness + LocMapOcclusion + LocMapEmission + LocMapHeight + LocMapCubemap + LocMapIrradiance + LocMapPrefilter + LocMapBrdf ) -// ShaderUniformDataType type -type ShaderUniformDataType int32 - -// ShaderUniformDataType enumeration -const ( - // Shader uniform type: float - ShaderUniformFloat ShaderUniformDataType = iota - // Shader uniform type: vec2 (2 float) - ShaderUniformVec2 - // Shader uniform type: vec3 (3 float) - ShaderUniformVec3 - // Shader uniform type: vec4 (4 float) - ShaderUniformVec4 - // Shader uniform type: int - ShaderUniformInt - // Shader uniform type: ivec2 (2 int) - ShaderUniformIvec2 - // Shader uniform type: ivec2 (3 int) - ShaderUniformIvec3 - // Shader uniform type: ivec2 (4 int) - ShaderUniformIvec4 - // Shader uniform type: unsigned int - ShaderUniformUint - // Shader uniform type: uivec2 (2 unsigned int) - ShaderUniformUivec2 - // Shader uniform type: uivec3 (3 unsigned int) - ShaderUniformUivec3 - // Shader uniform type: uivec4 (4 unsigned int) - ShaderUniformUivec4 - // Shader uniform type: sampler2d - ShaderUniformSampler2d -) - -// Material map index +// Material map type const ( MapAlbedo = iota MapMetalness @@ -770,10 +758,14 @@ const ( MapCubemap MapIrradiance MapPrefilter - MapBrdf +) - MapDiffuse = MapAlbedo - MapSpecular = MapMetalness +// Material map type +const ( + MapDiffuse = MapAlbedo + MapSpecular = MapMetalness + LocMapDiffuse = LocMapAlbedo + LocMapSpecular = LocMapMetalness ) // Shader and material limits @@ -812,16 +804,17 @@ type Mesh struct { BoneIds *int32 // BoneWeights BoneWeights *float32 - // Bones animated transformation matrices - BoneMatrices *Matrix - // Number of bones - BoneCount int32 // OpenGL Vertex Array Object id VaoID uint32 // OpenGL Vertex Buffer Objects id (7 types of vertex data) VboID *uint32 } +// newMeshFromPointer - Returns new Mesh from pointer +func newMeshFromPointer(ptr unsafe.Pointer) Mesh { + return *(*Mesh)(ptr) +} + // Material type type Material struct { // Shader @@ -832,9 +825,9 @@ type Material struct { Params [4]float32 } -// GetMap - Get pointer to MaterialMap by map type -func (mt Material) GetMap(index int32) *MaterialMap { - return (*MaterialMap)(unsafe.Pointer(uintptr(unsafe.Pointer(mt.Maps)) + uintptr(index)*unsafe.Sizeof(MaterialMap{}))) +// newMaterialFromPointer - Returns new Material from pointer +func newMaterialFromPointer(ptr unsafe.Pointer) Material { + return *(*Material)(ptr) } // MaterialMap type @@ -842,68 +835,36 @@ type MaterialMap struct { // Texture Texture Texture2D // Color - Color color.RGBA + Color Color // Value Value float32 } -// Model is struct of model, meshes, materials and animation data type Model struct { // Local transform matrix - Transform Matrix - // Number of meshes - MeshCount int32 - // Number of materials + Transform Matrix + MeshCount int32 MaterialCount int32 - // Meshes array (c array) - // - // Use Model.GetMeshes instead (go slice) - Meshes *Mesh - // Materials array (c array) - // - // Use Model.GetMaterials instead (go slice) - Materials *Material - // Mesh material number - MeshMaterial *int32 - // Number of bones - BoneCount int32 - // Bones information (skeleton) (c array) - // - // Use Model.GetBones instead (go slice) - Bones *BoneInfo - // Bones base transformation (pose) (c array) - // - // Use Model.GetBindPose instead (go slice) - BindPose *Transform + Meshes *Mesh + Materials *Material + MeshMaterial *int32 + BoneCount int32 + Bones *BoneInfo + BindPose *Transform } -// GetMeshes returns the meshes of a model as go slice -func (m Model) GetMeshes() []Mesh { - return unsafe.Slice(m.Meshes, m.MeshCount) +// newModelFromPointer - Returns new Model from pointer +func newModelFromPointer(ptr unsafe.Pointer) Model { + return *(*Model)(ptr) } -// GetMaterials returns the materials of a model as go slice -func (m Model) GetMaterials() []Material { - return unsafe.Slice(m.Materials, m.MaterialCount) -} - -// GetBones returns the bones information (skeleton) of a model as go slice -func (m Model) GetBones() []BoneInfo { - return unsafe.Slice(m.Bones, m.BoneCount) -} - -// GetBindPose returns the bones base transformation of a model as go slice -func (m Model) GetBindPose() []Transform { - return unsafe.Slice(m.BindPose, m.BoneCount) -} - -// BoneInfo type +// BoneInfo type. type BoneInfo struct { Name [32]int8 Parent int32 } -// Transform type +// Transform type. type Transform struct { Translation Vector3 Rotation Vector4 @@ -923,48 +884,9 @@ func NewRay(position, direction Vector3) Ray { return Ray{position, direction} } -// ModelAnimation type -type ModelAnimation struct { - BoneCount int32 - FrameCount int32 - Bones *BoneInfo - FramePoses **Transform - Name [32]uint8 -} - -// GetBones returns the bones information (skeleton) of a ModelAnimation as go slice -func (m ModelAnimation) GetBones() []BoneInfo { - return unsafe.Slice(m.Bones, m.BoneCount) -} - -// GetFramePose returns the Transform for a specific bone at a specific frame -func (m ModelAnimation) GetFramePose(frame, bone int) Transform { - framePoses := unsafe.Slice(m.FramePoses, m.FrameCount) - return unsafe.Slice(framePoses[frame], m.BoneCount)[bone] -} - -// GetName returns the ModelAnimation's name as go string -func (m ModelAnimation) GetName() string { - var end int - for end = range m.Name { - if m.Name[end] == 0 { - break - } - } - return string(m.Name[:end]) -} - -// RayCollision type - ray hit information -type RayCollision struct { - Hit bool - Distance float32 - Point Vector3 - Normal Vector3 -} - -// NewRayCollision - Returns new RayCollision -func NewRayCollision(hit bool, distance float32, point, normal Vector3) RayCollision { - return RayCollision{hit, distance, point, normal} +// newRayFromPointer - Returns new Ray from pointer +func newRayFromPointer(ptr unsafe.Pointer) Ray { + return *(*Ray)(ptr) } // BlendMode type @@ -972,14 +894,12 @@ type BlendMode int32 // Color blending modes (pre-defined) const ( - BlendAlpha BlendMode = iota // Blend textures considering alpha (default) - BlendAdditive // Blend textures adding colors - BlendMultiplied // Blend textures multiplying colors - BlendAddColors // Blend textures adding colors (alternative) - BlendSubtractColors // Blend textures subtracting colors (alternative) - BlendAlphaPremultiply // Blend premultiplied textures considering alpha - BlendCustom // Blend textures using custom src/dst factors - BlendCustomSeparate // Blend textures using custom rgb/alpha separate src/dst factors + BlendAlpha BlendMode = iota // Blend textures considering alpha (default) + BlendAdditive // Blend textures adding colors + BlendMultiplied // Blend textures multiplying colors + BlendAddColors // Blend textures adding colors (alternative) + BlendSubtractColors // Blend textures subtracting colors (alternative) + BlendCustom // Blend textures using custom src/dst factors (use SetBlendModeCustom()) ) // Shader type (generic shader) @@ -995,18 +915,13 @@ func NewShader(id uint32, locs *int32) Shader { return Shader{id, locs} } -// GetLocation - Get shader value's location -func (sh Shader) GetLocation(index int32) int32 { - return *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(sh.Locs)) + uintptr(index*4))) +// newShaderFromPointer - Returns new Shader from pointer +func newShaderFromPointer(ptr unsafe.Pointer) Shader { + return *(*Shader)(ptr) } -// UpdateLocation - Update shader value's location -func (sh Shader) UpdateLocation(index int32, loc int32) { - *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(sh.Locs)) + uintptr(index*4))) = loc -} - -// GlyphInfo - Font character info -type GlyphInfo struct { +// CharInfo - Font character info +type CharInfo struct { // Character value (Unicode) Value int32 // Character offset X when drawing @@ -1019,9 +934,14 @@ type GlyphInfo struct { Image Image } -// NewGlyphInfo - Returns new CharInfo -func NewGlyphInfo(value int32, offsetX, offsetY, advanceX int32, image Image) GlyphInfo { - return GlyphInfo{value, offsetX, offsetY, advanceX, image} +// NewCharInfo - Returns new CharInfo +func NewCharInfo(value int32, offsetX, offsetY, advanceX int32, image Image) CharInfo { + return CharInfo{value, offsetX, offsetY, advanceX, image} +} + +// newCharInfoFromPointer - Returns new CharInfo from pointer +func newCharInfoFromPointer(ptr unsafe.Pointer) CharInfo { + return *(*CharInfo)(ptr) } // Font type, includes texture and charSet array data @@ -1037,15 +957,13 @@ type Font struct { // Characters rectangles in texture Recs *Rectangle // Characters info data - Chars *GlyphInfo + Chars *CharInfo } -// Font type, defines generation method -const ( - FontDefault = iota // Default font generation, anti-aliased - FontBitmap // Bitmap font generation, no anti-aliasing - FontSdf // SDF font generation, requires external shader -) +// newFontFromPointer - Returns new Font from pointer +func newFontFromPointer(ptr unsafe.Pointer) Font { + return *(*Font)(ptr) +} // PixelFormat - Texture format type PixelFormat int32 @@ -1129,20 +1047,11 @@ const ( WrapMirrorClamp ) -// Cubemap layouts -const ( - CubemapLayoutAutoDetect = iota // Automatically detect layout type - CubemapLayoutLineVertical // Layout is defined by a vertical line with faces - CubemapLayoutLineHorizontal // Layout is defined by a horizontal line with faces - CubemapLayoutCrossThreeByFour // Layout is defined by a 3x4 cross with cubemap faces - CubemapLayoutCrossFourByThree // Layout is defined by a 4x3 cross with cubemap faces -) - // Image type, bpp always RGBA (32bit) // NOTE: Data stored in CPU memory (RAM) type Image struct { - // Image raw Data - Data unsafe.Pointer + // Image raw data + data unsafe.Pointer // Image base width Width int32 // Image base height @@ -1156,10 +1065,39 @@ type Image struct { // NewImage - Returns new Image func NewImage(data []byte, width, height, mipmaps int32, format PixelFormat) *Image { d := unsafe.Pointer(&data[0]) - return &Image{d, width, height, mipmaps, format} } +// newImageFromPointer - Returns new Image from pointer +func newImageFromPointer(ptr unsafe.Pointer) *Image { + return (*Image)(ptr) +} + +// NewImageFromImage - Returns new Image from Go image.Image +func NewImageFromImage(img image.Image) *Image { + size := img.Bounds().Size() + + cx := (C.int)(size.X) + cy := (C.int)(size.Y) + ccolor := White.cptr() + ret := C.GenImageColor(cx, cy, *ccolor) + + for y := 0; y < size.Y; y++ { + for x := 0; x < size.X; x++ { + color := img.At(x, y) + r, g, b, a := color.RGBA() + rcolor := NewColor(uint8(r), uint8(g), uint8(b), uint8(a)) + ccolor = rcolor.cptr() + + cx = (C.int)(x) + cy = (C.int)(y) + C.ImageDrawPixel(&ret, cx, cy, *ccolor) + } + } + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + // Texture2D type, bpp always RGBA (32bit) // NOTE: Data stored in GPU memory type Texture2D struct { @@ -1180,6 +1118,11 @@ func NewTexture2D(id uint32, width, height, mipmaps int32, format PixelFormat) T return Texture2D{id, width, height, mipmaps, format} } +// newTexture2DFromPointer - Returns new Texture2D from pointer +func newTexture2DFromPointer(ptr unsafe.Pointer) Texture2D { + return *(*Texture2D)(ptr) +} + // RenderTexture2D type, for texture rendering type RenderTexture2D struct { // Render texture (fbo) id @@ -1195,73 +1138,21 @@ func NewRenderTexture2D(id uint32, texture, depth Texture2D) RenderTexture2D { return RenderTexture2D{id, texture, depth} } -// TraceLogCallbackFun - function that will recive the trace log messages -type TraceLogCallbackFun func(int, string) +// newRenderTexture2DFromPointer - Returns new RenderTexture2D from pointer +func newRenderTexture2DFromPointer(ptr unsafe.Pointer) RenderTexture2D { + return *(*RenderTexture2D)(ptr) +} -// TraceLogLevel parameter of trace log message -type TraceLogLevel int - -// Trace log level -// NOTE: Organized by priority level +// Log message types const ( - // Display all logs - LogAll TraceLogLevel = iota - // Trace logging, intended for internal use only + LogAll = iota LogTrace - // Debug logging, used for internal debugging, it should be disabled on release builds LogDebug - // Info logging, used for program execution info LogInfo - // Warning logging, used on recoverable failures LogWarning - // Error logging, used on unrecoverable failures LogError - // Fatal logging, used to abort program: exit(EXIT_FAILURE) LogFatal - // Disable logging LogNone ) -// N-patch layout -type NPatchLayout int32 - -const ( - NPatchNinePatch NPatchLayout = iota // Npatch layout: 3x3 tiles - NPatchThreePatchVertical // Npatch layout: 1x3 tiles - NPatchThreePatchHorizontal // Npatch layout: 3x1 tiles -) - -// NPatchInfo type, n-patch layout info -type NPatchInfo struct { - Source Rectangle // Texture source rectangle - Left int32 // Left border offset - Top int32 // Top border offset - Right int32 // Right border offset - Bottom int32 // Bottom border offset - Layout NPatchLayout // Layout of the n-patch: 3x3, 1x3 or 3x1 -} - -// VrStereoConfig, VR stereo rendering configuration for simulator -type VrStereoConfig struct { - Projection [2]Matrix // VR projection matrices (per eye) - ViewOffset [2]Matrix // VR view offset matrices (per eye) - LeftLensCenter [2]float32 // VR left lens center - RightLensCenter [2]float32 // VR right lens center - LeftScreenCenter [2]float32 // VR left screen center - RightScreenCenter [2]float32 // VR right screen center - Scale [2]float32 // VR distortion scale - ScaleIn [2]float32 // VR distortion scale in -} - -// VrDeviceInfo, Head-Mounted-Display device parameters -type VrDeviceInfo struct { - HResolution int32 // Horizontal resolution in pixels - VResolution int32 // Vertical resolution in pixels - HScreenSize float32 // Horizontal size in meters - VScreenSize float32 // Vertical size in meters - EyeToScreenDistance float32 // Distance between eye and display in meters - LensSeparationDistance float32 // Lens separation distance in meters - InterpupillaryDistance float32 // IPD (distance between pupils) in meters - LensDistortionValues [4]float32 // Lens distortion constant parameters - ChromaAbCorrection [4]float32 // Chromatic aberration correction parameters -} +var logTypeFlags = LogInfo | LogWarning | LogError diff --git a/raylib/raylib.h b/raylib/raylib.h index f42ab40..0394315 100644 --- a/raylib/raylib.h +++ b/raylib/raylib.h @@ -1,61 +1,55 @@ /********************************************************************************************** * -* raylib v5.6-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) +* raylib - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) * * FEATURES: * - NO external dependencies, all required libraries included with raylib * - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly, -* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5. +* MacOS, Haiku, UWP, Android, Raspberry Pi, HTML5. * - Written in plain C code (C99) in PascalCase/camelCase notation -* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile) +* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile) * - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] -* - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts) +* - Multiple Fonts formats supported (TTF, XNA fonts, AngelCode fonts) * - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) * - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * - Flexible Materials system, supporting classic maps and PBR maps -* - Animated 3D models supported (skeletal bones animation) (IQM, M3D, GLTF) +* - Animated 3D models supported (skeletal bones animation) (IQM, glTF) * - Shaders support, including Model shaders and Postprocessing shaders * - Powerful math module for Vector, Matrix and Quaternion operations: [raymath] -* - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, QOA, XM, MOD) +* - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, XM, MOD) * - VR stereo rendering with configurable HMD device parameters * - Bindings to multiple programming languages available! * * NOTES: -* - One default Font is loaded on InitWindow()->LoadFontDefault() [core, text] -* - One default Texture2D is loaded on rlglInit(), 1x1 white pixel R8G8B8A8 [rlgl] (OpenGL 3.3 or ES2) -* - One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2) -* - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2) +* One default Font is loaded on InitWindow()->LoadFontDefault() [core, text] +* One default Texture2D is loaded on rlglInit() [rlgl] (OpenGL 3.3 or ES2) +* One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2) +* One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2) * * DEPENDENCIES (included): -* [rcore][GLFW] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input -* [rcore][RGFW] rgfw (ColleagueRiley - github.com/ColleagueRiley/RGFW) for window/context management and input -* [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading -* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management +* [core] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input (PLATFORM_DESKTOP) +* [rlgl] glad (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading (PLATFORM_DESKTOP) +* [raudio] miniaudio (David Reid - github.com/dr-soft/miniaudio) for audio device/context management * * OPTIONAL DEPENDENCIES (included): -* [rcore] msf_gif (Miles Fogle) for GIF recording -* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm -* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm -* [rcore] rprand (Ramon Snatamaria) for pseudo-random numbers generation -* [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image manage -* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) -* [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG) -* [rtextures] stb_image_resize2 (Sean Barret) for image resizing algorithms -* [rtextures] stb_perlin (Sean Barret) for Perlin Noise image generation -* [rtext] stb_truetype (Sean Barret) for ttf fonts loading -* [rtext] stb_rect_pack (Sean Barret) for rectangles packing -* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation -* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL) -* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF) -* [rmodels] m3d (bzt) for models loading (M3D, https://bztsrc.gitlab.io/model3d) -* [rmodels] vox_loader (Johann Nadalutti) for models loading (VOX) +* [core] msf_gif (Miles Fogle) for GIF recording +* [core] sinfl (Micha Mettke) for DEFLATE decompression algorythm +* [core] sdefl (Micha Mettke) for DEFLATE compression algorythm +* [textures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) +* [textures] stb_image_write (Sean Barret) for image writting (BMP, TGA, PNG, JPG) +* [textures] stb_image_resize (Sean Barret) for image resizing algorithms +* [textures] stb_perlin (Sean Barret) for Perlin noise image generation +* [text] stb_truetype (Sean Barret) for ttf fonts loading +* [text] stb_rect_pack (Sean Barret) for rectangles packing +* [models] par_shapes (Philip Rideout) for parametric 3d shapes generation +* [models] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL) +* [models] cgltf (Johannes Kuhlmann) for models loading (glTF) * [raudio] dr_wav (David Reid) for WAV audio file loading * [raudio] dr_flac (David Reid) for FLAC audio file loading * [raudio] dr_mp3 (David Reid) for MP3 audio file loading * [raudio] stb_vorbis (Sean Barret) for OGG audio loading * [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading * [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading -* [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio manage * * * LICENSE: zlib/libpng @@ -63,7 +57,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -87,31 +81,19 @@ #include // Required for: va_list - Only used by TraceLogCallback -#define RAYLIB_VERSION_MAJOR 5 -#define RAYLIB_VERSION_MINOR 6 -#define RAYLIB_VERSION_PATCH 0 -#define RAYLIB_VERSION "5.6-dev" +#define RAYLIB_VERSION "3.8-dev" -// Function specifiers in case library is build/used as a shared library -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -// NOTE: visibility("default") attribute makes symbols "visible" when compiled with -fvisibility=hidden #if defined(_WIN32) - #if defined(__TINYC__) - #define __declspec(x) __attribute__((x)) - #endif + // Microsoft attibutes to tell compiler that symbols are imported/exported from a .dll #if defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll) #elif defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) + #else + #define RLAPI // We are building or using raylib as a static library #endif #else - #if defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __attribute__((visibility("default"))) // We are building as a Unix shared library (.so/.dylib) - #endif -#endif - -#ifndef RLAPI - #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) + #define RLAPI // We are building or using raylib as a static library (or Linux shared library) #endif //---------------------------------------------------------------------------------- @@ -120,15 +102,11 @@ #ifndef PI #define PI 3.14159265358979323846f #endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif + +#define DEG2RAD (PI/180.0f) +#define RAD2DEG (180.0f/PI) // Allow custom memory allocators -// NOTE: Require recompiling raylib sources #ifndef RL_MALLOC #define RL_MALLOC(sz) malloc(sz) #endif @@ -143,33 +121,13 @@ #endif // NOTE: MSVC C++ compiler does not support compound literals (C99 feature) -// Plain structures in C++ (without constructors) can be initialized with { } -// This is called aggregate initialization (C++11 feature) +// Plain structures in C++ (without constructors) can be initialized from { } initializers. #if defined(__cplusplus) #define CLITERAL(type) type #else #define CLITERAL(type) (type) #endif -// Some compilers (mostly macos clang) default to C++98, -// where aggregate initialization can't be used -// So, give a more clear error stating how to fix this -#if !defined(_MSC_VER) && (defined(__cplusplus) && __cplusplus < 201103L) - #error "C++11 or later is required. Add -std=c++11" -#endif - -// NOTE: We set some defines with some data types declared by raylib -// Other modules (raymath, rlgl) also require some of those types, so, -// to be able to use those other modules as standalone (not depending on raylib) -// this defines are very useful for internal check and avoid type (re)definitions -#define RL_COLOR_TYPE -#define RL_RECTANGLE_TYPE -#define RL_VECTOR2_TYPE -#define RL_VECTOR3_TYPE -#define RL_VECTOR4_TYPE -#define RL_QUATERNION_TYPE -#define RL_MATRIX_TYPE - // Some Basic Colors // NOTE: Custom raylib color palette for amazing visuals on WHITE background #define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray @@ -200,66 +158,77 @@ #define MAGENTA CLITERAL(Color){ 255, 0, 255, 255 } // Magenta #define RAYWHITE CLITERAL(Color){ 245, 245, 245, 255 } // My own White (raylib logo) +// Temporal hacks to avoid breaking old codebases using +// deprecated raylib implementation or definitions +#define FormatText TextFormat +#define LoadText LoadFileText +#define GetExtension GetFileExtension +#define GetImageData LoadImageColors +#define FILTER_POINT TEXTURE_FILTER_POINT +#define FILTER_BILINEAR TEXTURE_FILTER_BILINEAR +#define MAP_DIFFUSE MATERIAL_MAP_DIFFUSE +#define UNCOMPRESSED_R8G8B8A8 PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 + //---------------------------------------------------------------------------------- // Structures Definition //---------------------------------------------------------------------------------- // Boolean type -#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L #include #elif !defined(__cplusplus) && !defined(bool) - typedef enum bool { false = 0, true = !false } bool; - #define RL_BOOL_TYPE + typedef enum { false, true } bool; #endif -// Vector2, 2 components +// Vector2 type typedef struct Vector2 { - float x; // Vector x component - float y; // Vector y component + float x; + float y; } Vector2; -// Vector3, 3 components +// Vector3 type typedef struct Vector3 { - float x; // Vector x component - float y; // Vector y component - float z; // Vector z component + float x; + float y; + float z; } Vector3; -// Vector4, 4 components +// Vector4 type typedef struct Vector4 { - float x; // Vector x component - float y; // Vector y component - float z; // Vector z component - float w; // Vector w component + float x; + float y; + float z; + float w; } Vector4; -// Quaternion, 4 components (Vector4 alias) +// Quaternion type, same as Vector4 typedef Vector4 Quaternion; -// Matrix, 4x4 components, column major, OpenGL style, right-handed +// Matrix type (OpenGL style 4x4 - right handed, column major) typedef struct Matrix { - float m0, m4, m8, m12; // Matrix first row (4 components) - float m1, m5, m9, m13; // Matrix second row (4 components) - float m2, m6, m10, m14; // Matrix third row (4 components) - float m3, m7, m11, m15; // Matrix fourth row (4 components) + float m0, m4, m8, m12; + float m1, m5, m9, m13; + float m2, m6, m10, m14; + float m3, m7, m11, m15; } Matrix; -// Color, 4 components, R8G8B8A8 (32bit) +// Color type, RGBA (32bit) typedef struct Color { - unsigned char r; // Color red value - unsigned char g; // Color green value - unsigned char b; // Color blue value - unsigned char a; // Color alpha value + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; } Color; -// Rectangle, 4 components +// Rectangle type typedef struct Rectangle { - float x; // Rectangle top-left corner position x - float y; // Rectangle top-left corner position y - float width; // Rectangle width - float height; // Rectangle height + float x; + float y; + float width; + float height; } Rectangle; -// Image, pixel data stored in CPU memory (RAM) +// Image type, bpp always RGBA (32bit) +// NOTE: Data stored in CPU memory (RAM) typedef struct Image { void *data; // Image raw data int width; // Image base width @@ -268,7 +237,8 @@ typedef struct Image { int format; // Data format (PixelFormat type) } Image; -// Texture, tex data stored in GPU memory (VRAM) +// Texture type +// NOTE: Data stored in GPU memory typedef struct Texture { unsigned int id; // OpenGL texture id int width; // Texture base width @@ -277,23 +247,23 @@ typedef struct Texture { int format; // Data format (PixelFormat type) } Texture; -// Texture2D, same as Texture +// Texture2D type, same as Texture typedef Texture Texture2D; -// TextureCubemap, same as Texture +// TextureCubemap type, actually, same as Texture typedef Texture TextureCubemap; -// RenderTexture, fbo for texture rendering +// RenderTexture type, for texture rendering typedef struct RenderTexture { unsigned int id; // OpenGL framebuffer object id Texture texture; // Color buffer attachment texture Texture depth; // Depth buffer attachment texture } RenderTexture; -// RenderTexture2D, same as RenderTexture +// RenderTexture2D type, same as RenderTexture typedef RenderTexture RenderTexture2D; -// NPatchInfo, n-patch layout info +// N-Patch layout info typedef struct NPatchInfo { Rectangle source; // Texture source rectangle int left; // Left border offset @@ -303,37 +273,39 @@ typedef struct NPatchInfo { int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 } NPatchInfo; -// GlyphInfo, font characters glyphs info -typedef struct GlyphInfo { +// Font character info +typedef struct CharInfo { int value; // Character value (Unicode) int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X Image image; // Character image data -} GlyphInfo; +} CharInfo; -// Font, font texture and GlyphInfo array data +// Font type, includes texture and charSet array data typedef struct Font { int baseSize; // Base size (default chars height) - int glyphCount; // Number of glyph characters - int glyphPadding; // Padding around the glyph characters - Texture2D texture; // Texture atlas containing the glyphs - Rectangle *recs; // Rectangles in texture for the glyphs - GlyphInfo *glyphs; // Glyphs info data + int charsCount; // Number of characters + int charsPadding; // Padding around the chars + Texture2D texture; // Characters texture atlas + Rectangle *recs; // Characters rectangles in texture + CharInfo *chars; // Characters info data } Font; -// Camera, defines position/orientation in 3d space +#define SpriteFont Font // SpriteFont type fallback, defaults to Font + +// Camera type, defines a camera position/orientation in 3d space typedef struct Camera3D { Vector3 position; // Camera position Vector3 target; // Camera target it looks-at Vector3 up; // Camera up vector (rotation over its axis) - float fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic + float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } Camera3D; typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D -// Camera2D, defines position/orientation in 2d space +// Camera2D type, defines a 2d camera typedef struct Camera2D { Vector2 offset; // Camera offset (displacement from target) Vector2 target; // Camera target (rotation and zoom origin) @@ -341,67 +313,66 @@ typedef struct Camera2D { float zoom; // Camera zoom (scaling), should be 1.0f by default } Camera2D; -// Mesh, vertex data and vao/vbo +// Vertex data definning a mesh +// NOTE: Data stored in CPU memory (and GPU) typedef struct Mesh { int vertexCount; // Number of vertices stored in arrays int triangleCount; // Number of triangles stored (indexed or not) - // Vertex attributes data + // Default vertex data float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - float *texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) + float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5) float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) - unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - unsigned short *indices; // Vertex indices (in case vertex data comes indexed) + unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + unsigned short *indices;// Vertex indices (in case vertex data comes indexed) // Animation vertex data float *animVertices; // Animated vertex positions (after bones transformations) float *animNormals; // Animated normals (after bones transformations) - unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6) - float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) - Matrix *boneMatrices; // Bones animated transformation matrices - int boneCount; // Number of bones + int *boneIds; // Vertex bone ids, up to 4 bones influence by vertex (skinning) + float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) // OpenGL identifiers unsigned int vaoId; // OpenGL Vertex Array Object id unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data) } Mesh; -// Shader +// Shader type (generic) typedef struct Shader { unsigned int id; // Shader program id - int *locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) + int *locs; // Shader locations array (MAX_SHADER_LOCATIONS) } Shader; -// MaterialMap +// Material texture map typedef struct MaterialMap { Texture2D texture; // Material map texture Color color; // Material map color float value; // Material map value } MaterialMap; -// Material, includes shader and maps +// Material type (generic) typedef struct Material { Shader shader; // Material shader MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS) float params[4]; // Material generic parameters (if required) } Material; -// Transform, vertex transformation data +// Transformation properties typedef struct Transform { Vector3 translation; // Translation Quaternion rotation; // Rotation Vector3 scale; // Scale } Transform; -// Bone, skeletal animation bone +// Bone information typedef struct BoneInfo { char name[32]; // Bone name int parent; // Bone parent } BoneInfo; -// Model, meshes, materials and animation data +// Model type typedef struct Model { Matrix transform; // Local transform matrix @@ -417,81 +388,79 @@ typedef struct Model { Transform *bindPose; // Bones base transformation (pose) } Model; -// ModelAnimation +// Model animation typedef struct ModelAnimation { int boneCount; // Number of bones int frameCount; // Number of animation frames BoneInfo *bones; // Bones information (skeleton) Transform **framePoses; // Poses array by frame - char name[32]; // Animation name } ModelAnimation; -// Ray, ray for raycasting +// Ray type (useful for raycast) typedef struct Ray { Vector3 position; // Ray position (origin) - Vector3 direction; // Ray direction (normalized) + Vector3 direction; // Ray direction } Ray; -// RayCollision, ray hit information -typedef struct RayCollision { +// Raycast hit information +typedef struct RayHitInfo { bool hit; // Did the ray hit something? - float distance; // Distance to the nearest hit - Vector3 point; // Point of the nearest hit + float distance; // Distance to nearest hit + Vector3 position; // Position of nearest hit Vector3 normal; // Surface normal of hit -} RayCollision; +} RayHitInfo; -// BoundingBox +// Bounding box type typedef struct BoundingBox { Vector3 min; // Minimum vertex box-corner Vector3 max; // Maximum vertex box-corner } BoundingBox; -// Wave, audio wave data +// Wave type, defines audio wave data typedef struct Wave { - unsigned int frameCount; // Total number of frames (considering channels) - unsigned int sampleRate; // Frequency (samples per second) - unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) - unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) - void *data; // Buffer data pointer + unsigned int sampleCount; // Total number of samples (considering channels!) + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + void *data; // Buffer data pointer } Wave; -// Opaque structs declaration -// NOTE: Actual structs are defined internally in raudio module typedef struct rAudioBuffer rAudioBuffer; -typedef struct rAudioProcessor rAudioProcessor; -// AudioStream, custom audio stream +// Audio stream type +// NOTE: Useful to create custom audio streams not bound to a specific file typedef struct AudioStream { - rAudioBuffer *buffer; // Pointer to internal data used by the audio system - rAudioProcessor *processor; // Pointer to internal data processor, useful for audio effects + rAudioBuffer *buffer; // Pointer to internal data used by the audio system - unsigned int sampleRate; // Frequency (samples per second) - unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) - unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) } AudioStream; -// Sound +// Sound source type typedef struct Sound { - AudioStream stream; // Audio stream - unsigned int frameCount; // Total number of frames (considering channels) + AudioStream stream; // Audio stream + unsigned int sampleCount; // Total number of samples } Sound; -// Music, audio stream, anything longer than ~10 seconds should be streamed +// Music stream type (audio file streaming from memory) +// NOTE: Anything longer than ~10 seconds should be streamed typedef struct Music { - AudioStream stream; // Audio stream - unsigned int frameCount; // Total number of frames (considering channels) - bool looping; // Music looping enable + AudioStream stream; // Audio stream + unsigned int sampleCount; // Total number of samples + bool looping; // Music looping enable - int ctxType; // Type of music context (audio filetype) - void *ctxData; // Audio context data, depends on type + int ctxType; // Type of music context (audio filetype) + void *ctxData; // Audio context data, depends on type } Music; -// VrDeviceInfo, Head-Mounted-Display device parameters +// Head-Mounted-Display device parameters typedef struct VrDeviceInfo { int hResolution; // Horizontal resolution in pixels int vResolution; // Vertical resolution in pixels float hScreenSize; // Horizontal size in meters float vScreenSize; // Vertical size in meters + float vScreenCenter; // Screen center in meters float eyeToScreenDistance; // Distance between eye and display in meters float lensSeparationDistance; // Lens separation distance in meters float interpupillaryDistance; // IPD (distance between pupils) in meters @@ -499,7 +468,7 @@ typedef struct VrDeviceInfo { float chromaAbCorrection[4]; // Chromatic aberration correction parameters } VrDeviceInfo; -// VrStereoConfig, VR stereo rendering configuration for simulator +// VR Stereo rendering configuration for simulator typedef struct VrStereoConfig { Matrix projection[2]; // VR projection matrices (per eye) Matrix viewOffset[2]; // VR view offset matrices (per eye) @@ -511,27 +480,6 @@ typedef struct VrStereoConfig { float scaleIn[2]; // VR distortion scale in } VrStereoConfig; -// File path list -typedef struct FilePathList { - unsigned int capacity; // Filepaths max entries - unsigned int count; // Filepaths entries count - char **paths; // Filepaths entries -} FilePathList; - -// Automation event -typedef struct AutomationEvent { - unsigned int frame; // Event frame - unsigned int type; // Event type (AutomationEventType) - int params[4]; // Event parameters (if required) -} AutomationEvent; - -// Automation event list -typedef struct AutomationEventList { - unsigned int capacity; // Events max entries (MAX_AUTOMATION_EVENTS) - unsigned int count; // Events entries count - AutomationEvent *events; // Events entries -} AutomationEventList; - //---------------------------------------------------------------------------------- // Enumerators Definition //---------------------------------------------------------------------------------- @@ -551,22 +499,19 @@ typedef enum { FLAG_WINDOW_ALWAYS_RUN = 0x00000100, // Set to allow windows running while minimized FLAG_WINDOW_TRANSPARENT = 0x00000010, // Set to allow transparent framebuffer FLAG_WINDOW_HIGHDPI = 0x00002000, // Set to support HighDPI - FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED - FLAG_BORDERLESS_WINDOWED_MODE = 0x00008000, // Set to run program in borderless windowed mode FLAG_MSAA_4X_HINT = 0x00000020, // Set to try enabling MSAA 4X FLAG_INTERLACED_HINT = 0x00010000 // Set to try enabling interlaced video format (for V3D) } ConfigFlags; // Trace log level -// NOTE: Organized by priority level typedef enum { LOG_ALL = 0, // Display all logs - LOG_TRACE, // Trace logging, intended for internal use only - LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds - LOG_INFO, // Info logging, used for program execution info - LOG_WARNING, // Warning logging, used on recoverable failures - LOG_ERROR, // Error logging, used on unrecoverable failures - LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARNING, + LOG_ERROR, + LOG_FATAL, LOG_NONE // Disable logging } TraceLogLevel; @@ -574,120 +519,122 @@ typedef enum { // NOTE: Use GetKeyPressed() to allow redefining // required keys for alternative layouts typedef enum { - KEY_NULL = 0, // Key: NULL, used for no key pressed + KEY_NULL = 0, // Alphanumeric keys - KEY_APOSTROPHE = 39, // Key: ' - KEY_COMMA = 44, // Key: , - KEY_MINUS = 45, // Key: - - KEY_PERIOD = 46, // Key: . - KEY_SLASH = 47, // Key: / - KEY_ZERO = 48, // Key: 0 - KEY_ONE = 49, // Key: 1 - KEY_TWO = 50, // Key: 2 - KEY_THREE = 51, // Key: 3 - KEY_FOUR = 52, // Key: 4 - KEY_FIVE = 53, // Key: 5 - KEY_SIX = 54, // Key: 6 - KEY_SEVEN = 55, // Key: 7 - KEY_EIGHT = 56, // Key: 8 - KEY_NINE = 57, // Key: 9 - KEY_SEMICOLON = 59, // Key: ; - KEY_EQUAL = 61, // Key: = - KEY_A = 65, // Key: A | a - KEY_B = 66, // Key: B | b - KEY_C = 67, // Key: C | c - KEY_D = 68, // Key: D | d - KEY_E = 69, // Key: E | e - KEY_F = 70, // Key: F | f - KEY_G = 71, // Key: G | g - KEY_H = 72, // Key: H | h - KEY_I = 73, // Key: I | i - KEY_J = 74, // Key: J | j - KEY_K = 75, // Key: K | k - KEY_L = 76, // Key: L | l - KEY_M = 77, // Key: M | m - KEY_N = 78, // Key: N | n - KEY_O = 79, // Key: O | o - KEY_P = 80, // Key: P | p - KEY_Q = 81, // Key: Q | q - KEY_R = 82, // Key: R | r - KEY_S = 83, // Key: S | s - KEY_T = 84, // Key: T | t - KEY_U = 85, // Key: U | u - KEY_V = 86, // Key: V | v - KEY_W = 87, // Key: W | w - KEY_X = 88, // Key: X | x - KEY_Y = 89, // Key: Y | y - KEY_Z = 90, // Key: Z | z - KEY_LEFT_BRACKET = 91, // Key: [ - KEY_BACKSLASH = 92, // Key: '\' - KEY_RIGHT_BRACKET = 93, // Key: ] - KEY_GRAVE = 96, // Key: ` + KEY_APOSTROPHE = 39, + KEY_COMMA = 44, + KEY_MINUS = 45, + KEY_PERIOD = 46, + KEY_SLASH = 47, + KEY_ZERO = 48, + KEY_ONE = 49, + KEY_TWO = 50, + KEY_THREE = 51, + KEY_FOUR = 52, + KEY_FIVE = 53, + KEY_SIX = 54, + KEY_SEVEN = 55, + KEY_EIGHT = 56, + KEY_NINE = 57, + KEY_SEMICOLON = 59, + KEY_EQUAL = 61, + KEY_A = 65, + KEY_B = 66, + KEY_C = 67, + KEY_D = 68, + KEY_E = 69, + KEY_F = 70, + KEY_G = 71, + KEY_H = 72, + KEY_I = 73, + KEY_J = 74, + KEY_K = 75, + KEY_L = 76, + KEY_M = 77, + KEY_N = 78, + KEY_O = 79, + KEY_P = 80, + KEY_Q = 81, + KEY_R = 82, + KEY_S = 83, + KEY_T = 84, + KEY_U = 85, + KEY_V = 86, + KEY_W = 87, + KEY_X = 88, + KEY_Y = 89, + KEY_Z = 90, + // Function keys - KEY_SPACE = 32, // Key: Space - KEY_ESCAPE = 256, // Key: Esc - KEY_ENTER = 257, // Key: Enter - KEY_TAB = 258, // Key: Tab - KEY_BACKSPACE = 259, // Key: Backspace - KEY_INSERT = 260, // Key: Ins - KEY_DELETE = 261, // Key: Del - KEY_RIGHT = 262, // Key: Cursor right - KEY_LEFT = 263, // Key: Cursor left - KEY_DOWN = 264, // Key: Cursor down - KEY_UP = 265, // Key: Cursor up - KEY_PAGE_UP = 266, // Key: Page up - KEY_PAGE_DOWN = 267, // Key: Page down - KEY_HOME = 268, // Key: Home - KEY_END = 269, // Key: End - KEY_CAPS_LOCK = 280, // Key: Caps lock - KEY_SCROLL_LOCK = 281, // Key: Scroll down - KEY_NUM_LOCK = 282, // Key: Num lock - KEY_PRINT_SCREEN = 283, // Key: Print screen - KEY_PAUSE = 284, // Key: Pause - KEY_F1 = 290, // Key: F1 - KEY_F2 = 291, // Key: F2 - KEY_F3 = 292, // Key: F3 - KEY_F4 = 293, // Key: F4 - KEY_F5 = 294, // Key: F5 - KEY_F6 = 295, // Key: F6 - KEY_F7 = 296, // Key: F7 - KEY_F8 = 297, // Key: F8 - KEY_F9 = 298, // Key: F9 - KEY_F10 = 299, // Key: F10 - KEY_F11 = 300, // Key: F11 - KEY_F12 = 301, // Key: F12 - KEY_LEFT_SHIFT = 340, // Key: Shift left - KEY_LEFT_CONTROL = 341, // Key: Control left - KEY_LEFT_ALT = 342, // Key: Alt left - KEY_LEFT_SUPER = 343, // Key: Super left - KEY_RIGHT_SHIFT = 344, // Key: Shift right - KEY_RIGHT_CONTROL = 345, // Key: Control right - KEY_RIGHT_ALT = 346, // Key: Alt right - KEY_RIGHT_SUPER = 347, // Key: Super right - KEY_KB_MENU = 348, // Key: KB menu + KEY_SPACE = 32, + KEY_ESCAPE = 256, + KEY_ENTER = 257, + KEY_TAB = 258, + KEY_BACKSPACE = 259, + KEY_INSERT = 260, + KEY_DELETE = 261, + KEY_RIGHT = 262, + KEY_LEFT = 263, + KEY_DOWN = 264, + KEY_UP = 265, + KEY_PAGE_UP = 266, + KEY_PAGE_DOWN = 267, + KEY_HOME = 268, + KEY_END = 269, + KEY_CAPS_LOCK = 280, + KEY_SCROLL_LOCK = 281, + KEY_NUM_LOCK = 282, + KEY_PRINT_SCREEN = 283, + KEY_PAUSE = 284, + KEY_F1 = 290, + KEY_F2 = 291, + KEY_F3 = 292, + KEY_F4 = 293, + KEY_F5 = 294, + KEY_F6 = 295, + KEY_F7 = 296, + KEY_F8 = 297, + KEY_F9 = 298, + KEY_F10 = 299, + KEY_F11 = 300, + KEY_F12 = 301, + KEY_LEFT_SHIFT = 340, + KEY_LEFT_CONTROL = 341, + KEY_LEFT_ALT = 342, + KEY_LEFT_SUPER = 343, + KEY_RIGHT_SHIFT = 344, + KEY_RIGHT_CONTROL = 345, + KEY_RIGHT_ALT = 346, + KEY_RIGHT_SUPER = 347, + KEY_KB_MENU = 348, + KEY_LEFT_BRACKET = 91, + KEY_BACKSLASH = 92, + KEY_RIGHT_BRACKET = 93, + KEY_GRAVE = 96, + // Keypad keys - KEY_KP_0 = 320, // Key: Keypad 0 - KEY_KP_1 = 321, // Key: Keypad 1 - KEY_KP_2 = 322, // Key: Keypad 2 - KEY_KP_3 = 323, // Key: Keypad 3 - KEY_KP_4 = 324, // Key: Keypad 4 - KEY_KP_5 = 325, // Key: Keypad 5 - KEY_KP_6 = 326, // Key: Keypad 6 - KEY_KP_7 = 327, // Key: Keypad 7 - KEY_KP_8 = 328, // Key: Keypad 8 - KEY_KP_9 = 329, // Key: Keypad 9 - KEY_KP_DECIMAL = 330, // Key: Keypad . - KEY_KP_DIVIDE = 331, // Key: Keypad / - KEY_KP_MULTIPLY = 332, // Key: Keypad * - KEY_KP_SUBTRACT = 333, // Key: Keypad - - KEY_KP_ADD = 334, // Key: Keypad + - KEY_KP_ENTER = 335, // Key: Keypad Enter - KEY_KP_EQUAL = 336, // Key: Keypad = + KEY_KP_0 = 320, + KEY_KP_1 = 321, + KEY_KP_2 = 322, + KEY_KP_3 = 323, + KEY_KP_4 = 324, + KEY_KP_5 = 325, + KEY_KP_6 = 326, + KEY_KP_7 = 327, + KEY_KP_8 = 328, + KEY_KP_9 = 329, + KEY_KP_DECIMAL = 330, + KEY_KP_DIVIDE = 331, + KEY_KP_MULTIPLY = 332, + KEY_KP_SUBTRACT = 333, + KEY_KP_ADD = 334, + KEY_KP_ENTER = 335, + KEY_KP_EQUAL = 336, // Android key buttons - KEY_BACK = 4, // Key: Android back button - KEY_MENU = 5, // Key: Android menu button - KEY_VOLUME_UP = 24, // Key: Android volume up button - KEY_VOLUME_DOWN = 25 // Key: Android volume down button + KEY_BACK = 4, + KEY_MENU = 82, + KEY_VOLUME_UP = 24, + KEY_VOLUME_DOWN = 25 } KeyboardKey; // Add backwards compatibility support for deprecated names @@ -697,75 +644,95 @@ typedef enum { // Mouse buttons typedef enum { - MOUSE_BUTTON_LEFT = 0, // Mouse button left - MOUSE_BUTTON_RIGHT = 1, // Mouse button right - MOUSE_BUTTON_MIDDLE = 2, // Mouse button middle (pressed wheel) - MOUSE_BUTTON_SIDE = 3, // Mouse button side (advanced mouse device) - MOUSE_BUTTON_EXTRA = 4, // Mouse button extra (advanced mouse device) - MOUSE_BUTTON_FORWARD = 5, // Mouse button forward (advanced mouse device) - MOUSE_BUTTON_BACK = 6, // Mouse button back (advanced mouse device) + MOUSE_BUTTON_LEFT = 0, + MOUSE_BUTTON_RIGHT = 1, + MOUSE_BUTTON_MIDDLE = 2, + MOUSE_BUTTON_SIDE = 3, + MOUSE_BUTTON_EXTRA = 4, + MOUSE_BUTTON_FORWARD = 5, + MOUSE_BUTTON_BACK = 6, + MOUSE_BUTTON_MAX = 7 } MouseButton; // Mouse cursor typedef enum { - MOUSE_CURSOR_DEFAULT = 0, // Default pointer shape - MOUSE_CURSOR_ARROW = 1, // Arrow shape - MOUSE_CURSOR_IBEAM = 2, // Text writing cursor shape - MOUSE_CURSOR_CROSSHAIR = 3, // Cross shape - MOUSE_CURSOR_POINTING_HAND = 4, // Pointing hand cursor - MOUSE_CURSOR_RESIZE_EW = 5, // Horizontal resize/move arrow shape - MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape - MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape + MOUSE_CURSOR_DEFAULT = 0, + MOUSE_CURSOR_ARROW = 1, + MOUSE_CURSOR_IBEAM = 2, + MOUSE_CURSOR_CROSSHAIR = 3, + MOUSE_CURSOR_POINTING_HAND = 4, + MOUSE_CURSOR_RESIZE_EW = 5, // The horizontal resize/move arrow shape + MOUSE_CURSOR_RESIZE_NS = 6, // The vertical resize/move arrow shape + MOUSE_CURSOR_RESIZE_NWSE = 7, // The top-left to bottom-right diagonal resize/move arrow shape MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape - MOUSE_CURSOR_RESIZE_ALL = 9, // The omnidirectional resize/move cursor shape + MOUSE_CURSOR_RESIZE_ALL = 9, // The omni-directional resize/move cursor shape MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape } MouseCursor; // Gamepad buttons typedef enum { - GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, just for error checking - GAMEPAD_BUTTON_LEFT_FACE_UP, // Gamepad left DPAD up button - GAMEPAD_BUTTON_LEFT_FACE_RIGHT, // Gamepad left DPAD right button - GAMEPAD_BUTTON_LEFT_FACE_DOWN, // Gamepad left DPAD down button - GAMEPAD_BUTTON_LEFT_FACE_LEFT, // Gamepad left DPAD left button - GAMEPAD_BUTTON_RIGHT_FACE_UP, // Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) - GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, // Gamepad right button right (i.e. PS3: Circle, Xbox: B) - GAMEPAD_BUTTON_RIGHT_FACE_DOWN, // Gamepad right button down (i.e. PS3: Cross, Xbox: A) - GAMEPAD_BUTTON_RIGHT_FACE_LEFT, // Gamepad right button left (i.e. PS3: Square, Xbox: X) - GAMEPAD_BUTTON_LEFT_TRIGGER_1, // Gamepad top/back trigger left (first), it could be a trailing button - GAMEPAD_BUTTON_LEFT_TRIGGER_2, // Gamepad top/back trigger left (second), it could be a trailing button - GAMEPAD_BUTTON_RIGHT_TRIGGER_1, // Gamepad top/back trigger right (first), it could be a trailing button - GAMEPAD_BUTTON_RIGHT_TRIGGER_2, // Gamepad top/back trigger right (second), it could be a trailing button - GAMEPAD_BUTTON_MIDDLE_LEFT, // Gamepad center buttons, left one (i.e. PS3: Select) - GAMEPAD_BUTTON_MIDDLE, // Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) - GAMEPAD_BUTTON_MIDDLE_RIGHT, // Gamepad center buttons, right one (i.e. PS3: Start) - GAMEPAD_BUTTON_LEFT_THUMB, // Gamepad joystick pressed button left - GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right + // This is here just for error checking + GAMEPAD_BUTTON_UNKNOWN = 0, + + // This is normally a DPAD + GAMEPAD_BUTTON_LEFT_FACE_UP, + GAMEPAD_BUTTON_LEFT_FACE_RIGHT, + GAMEPAD_BUTTON_LEFT_FACE_DOWN, + GAMEPAD_BUTTON_LEFT_FACE_LEFT, + + // This normally corresponds with PlayStation and Xbox controllers + // XBOX: [Y,X,A,B] + // PS3: [Triangle,Square,Cross,Circle] + // No support for 6 button controllers though.. + GAMEPAD_BUTTON_RIGHT_FACE_UP, + GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, + GAMEPAD_BUTTON_RIGHT_FACE_DOWN, + GAMEPAD_BUTTON_RIGHT_FACE_LEFT, + + // Triggers + GAMEPAD_BUTTON_LEFT_TRIGGER_1, + GAMEPAD_BUTTON_LEFT_TRIGGER_2, + GAMEPAD_BUTTON_RIGHT_TRIGGER_1, + GAMEPAD_BUTTON_RIGHT_TRIGGER_2, + + // These are buttons in the center of the gamepad + GAMEPAD_BUTTON_MIDDLE_LEFT, // PS3 Select + GAMEPAD_BUTTON_MIDDLE, // PS Button/XBOX Button + GAMEPAD_BUTTON_MIDDLE_RIGHT, // PS3 Start + + // These are the joystick press in buttons + GAMEPAD_BUTTON_LEFT_THUMB, + GAMEPAD_BUTTON_RIGHT_THUMB } GamepadButton; -// Gamepad axes +// Gamepad axis typedef enum { - GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis - GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis - GAMEPAD_AXIS_RIGHT_X = 2, // Gamepad right stick X axis - GAMEPAD_AXIS_RIGHT_Y = 3, // Gamepad right stick Y axis - GAMEPAD_AXIS_LEFT_TRIGGER = 4, // Gamepad back trigger left, pressure level: [1..-1] - GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // Gamepad back trigger right, pressure level: [1..-1] + // Left stick + GAMEPAD_AXIS_LEFT_X = 0, + GAMEPAD_AXIS_LEFT_Y = 1, + + // Right stick + GAMEPAD_AXIS_RIGHT_X = 2, + GAMEPAD_AXIS_RIGHT_Y = 3, + + // Pressure levels for the back triggers + GAMEPAD_AXIS_LEFT_TRIGGER = 4, // [1..-1] (pressure-level) + GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // [1..-1] (pressure-level) } GamepadAxis; // Material map index typedef enum { - MATERIAL_MAP_ALBEDO = 0, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) - MATERIAL_MAP_METALNESS, // Metalness material (same as: MATERIAL_MAP_SPECULAR) - MATERIAL_MAP_NORMAL, // Normal material - MATERIAL_MAP_ROUGHNESS, // Roughness material - MATERIAL_MAP_OCCLUSION, // Ambient occlusion material - MATERIAL_MAP_EMISSION, // Emission material - MATERIAL_MAP_HEIGHT, // Heightmap material - MATERIAL_MAP_CUBEMAP, // Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - MATERIAL_MAP_IRRADIANCE, // Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - MATERIAL_MAP_PREFILTER, // Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - MATERIAL_MAP_BRDF // Brdf material + MATERIAL_MAP_ALBEDO = 0, // MATERIAL_MAP_DIFFUSE + MATERIAL_MAP_METALNESS = 1, // MATERIAL_MAP_SPECULAR + MATERIAL_MAP_NORMAL = 2, + MATERIAL_MAP_ROUGHNESS = 3, + MATERIAL_MAP_OCCLUSION, + MATERIAL_MAP_EMISSION, + MATERIAL_MAP_HEIGHT, + MATERIAL_MAP_BRDG, + MATERIAL_MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP + MATERIAL_MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP + MATERIAL_MAP_PREFILTER // NOTE: Uses GL_TEXTURE_CUBE_MAP } MaterialMapIndex; #define MATERIAL_MAP_DIFFUSE MATERIAL_MAP_ALBEDO @@ -773,36 +740,32 @@ typedef enum { // Shader location index typedef enum { - SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position - SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 - SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 - SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal - SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent - SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color - SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection - SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) - SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection - SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) - SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal - SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view - SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color - SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color - SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color - SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE) - SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR) - SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal - SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness - SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion - SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission - SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height - SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap - SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance - SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter - SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf - SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds - SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights - SHADER_LOC_BONE_MATRICES, // Shader location: array of matrices uniform: boneMatrices - SHADER_LOC_VERTEX_INSTANCE_TX // Shader location: vertex attribute: instanceTransform + SHADER_LOC_VERTEX_POSITION = 0, + SHADER_LOC_VERTEX_TEXCOORD01, + SHADER_LOC_VERTEX_TEXCOORD02, + SHADER_LOC_VERTEX_NORMAL, + SHADER_LOC_VERTEX_TANGENT, + SHADER_LOC_VERTEX_COLOR, + SHADER_LOC_MATRIX_MVP, + SHADER_LOC_MATRIX_VIEW, + SHADER_LOC_MATRIX_PROJECTION, + SHADER_LOC_MATRIX_MODEL, + SHADER_LOC_MATRIX_NORMAL, + SHADER_LOC_VECTOR_VIEW, + SHADER_LOC_COLOR_DIFFUSE, + SHADER_LOC_COLOR_SPECULAR, + SHADER_LOC_COLOR_AMBIENT, + SHADER_LOC_MAP_ALBEDO, // SHADER_LOC_MAP_DIFFUSE + SHADER_LOC_MAP_METALNESS, // SHADER_LOC_MAP_SPECULAR + SHADER_LOC_MAP_NORMAL, + SHADER_LOC_MAP_ROUGHNESS, + SHADER_LOC_MAP_OCCLUSION, + SHADER_LOC_MAP_EMISSION, + SHADER_LOC_MAP_HEIGHT, + SHADER_LOC_MAP_CUBEMAP, + SHADER_LOC_MAP_IRRADIANCE, + SHADER_LOC_MAP_PREFILTER, + SHADER_LOC_MAP_BRDF } ShaderLocationIndex; #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO @@ -810,63 +773,48 @@ typedef enum { // Shader uniform data type typedef enum { - SHADER_UNIFORM_FLOAT = 0, // Shader uniform type: float - SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) - SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) - SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) - SHADER_UNIFORM_INT, // Shader uniform type: int - SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) - SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) - SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) - SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int - SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) - SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) - SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) - SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d + SHADER_UNIFORM_FLOAT = 0, + SHADER_UNIFORM_VEC2, + SHADER_UNIFORM_VEC3, + SHADER_UNIFORM_VEC4, + SHADER_UNIFORM_INT, + SHADER_UNIFORM_IVEC2, + SHADER_UNIFORM_IVEC3, + SHADER_UNIFORM_IVEC4, + SHADER_UNIFORM_SAMPLER2D } ShaderUniformDataType; -// Shader attribute data types -typedef enum { - SHADER_ATTRIB_FLOAT = 0, // Shader attribute type: float - SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) - SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) - SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) -} ShaderAttributeDataType; - // Pixel formats // NOTE: Support depends on OpenGL version and platform typedef enum { - PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp - PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp - PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp - PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) - PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) - PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) - PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp - PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp + PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp + PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp } PixelFormat; // Texture parameters: filter mode // NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 2: Filter is accordingly set for minification and magnification typedef enum { - TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation + TEXTURE_FILTER_POINT = 0, // No filter, just pixel aproximation TEXTURE_FILTER_BILINEAR, // Linear filtering TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x @@ -876,69 +824,68 @@ typedef enum { // Texture parameters: wrap mode typedef enum { - TEXTURE_WRAP_REPEAT = 0, // Repeats texture in tiled mode - TEXTURE_WRAP_CLAMP, // Clamps texture to edge pixel in tiled mode - TEXTURE_WRAP_MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode - TEXTURE_WRAP_MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode + TEXTURE_WRAP_REPEAT = 0, // Repeats texture in tiled mode + TEXTURE_WRAP_CLAMP, // Clamps texture to edge pixel in tiled mode + TEXTURE_WRAP_MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode + TEXTURE_WRAP_MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode } TextureWrap; // Cubemap layouts typedef enum { - CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type - CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces - CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces - CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces - CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE // Layout is defined by a 4x3 cross with cubemap faces + CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type + CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces + CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces + CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces + CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces + CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirectangular map) } CubemapLayout; // Font type, defines generation method typedef enum { - FONT_DEFAULT = 0, // Default font generation, anti-aliased - FONT_BITMAP, // Bitmap font generation, no anti-aliasing - FONT_SDF // SDF font generation, requires external shader + FONT_DEFAULT = 0, // Default font generation, anti-aliased + FONT_BITMAP, // Bitmap font generation, no anti-aliasing + FONT_SDF // SDF font generation, requires external shader } FontType; // Color blending modes (pre-defined) typedef enum { - BLEND_ALPHA = 0, // Blend textures considering alpha (default) - BLEND_ADDITIVE, // Blend textures adding colors - BLEND_MULTIPLIED, // Blend textures multiplying colors - BLEND_ADD_COLORS, // Blend textures adding colors (alternative) - BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) - BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha - BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) - BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate()) + BLEND_ALPHA = 0, // Blend textures considering alpha (default) + BLEND_ADDITIVE, // Blend textures adding colors + BLEND_MULTIPLIED, // Blend textures multiplying colors + BLEND_ADD_COLORS, // Blend textures adding colors (alternative) + BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + BLEND_CUSTOM // Belnd textures using custom src/dst factors (use rlSetBlendMode()) } BlendMode; -// Gesture -// NOTE: Provided as bit-wise flags to enable only desired gestures +// Gestures +// NOTE: It could be used as flags to enable only some gestures typedef enum { - GESTURE_NONE = 0, // No gesture - GESTURE_TAP = 1, // Tap gesture - GESTURE_DOUBLETAP = 2, // Double tap gesture - GESTURE_HOLD = 4, // Hold gesture - GESTURE_DRAG = 8, // Drag gesture - GESTURE_SWIPE_RIGHT = 16, // Swipe right gesture - GESTURE_SWIPE_LEFT = 32, // Swipe left gesture - GESTURE_SWIPE_UP = 64, // Swipe up gesture - GESTURE_SWIPE_DOWN = 128, // Swipe down gesture - GESTURE_PINCH_IN = 256, // Pinch in gesture - GESTURE_PINCH_OUT = 512 // Pinch out gesture -} Gesture; + GESTURE_NONE = 0, + GESTURE_TAP = 1, + GESTURE_DOUBLETAP = 2, + GESTURE_HOLD = 4, + GESTURE_DRAG = 8, + GESTURE_SWIPE_RIGHT = 16, + GESTURE_SWIPE_LEFT = 32, + GESTURE_SWIPE_UP = 64, + GESTURE_SWIPE_DOWN = 128, + GESTURE_PINCH_IN = 256, + GESTURE_PINCH_OUT = 512 +} Gestures; // Camera system modes typedef enum { - CAMERA_CUSTOM = 0, // Camera custom, controlled by user (UpdateCamera() does nothing) - CAMERA_FREE, // Camera free mode - CAMERA_ORBITAL, // Camera orbital, around target, zoom supported - CAMERA_FIRST_PERSON, // Camera first person - CAMERA_THIRD_PERSON // Camera third person + CAMERA_CUSTOM = 0, + CAMERA_FREE, + CAMERA_ORBITAL, + CAMERA_FIRST_PERSON, + CAMERA_THIRD_PERSON } CameraMode; // Camera projection typedef enum { - CAMERA_PERSPECTIVE = 0, // Perspective projection - CAMERA_ORTHOGRAPHIC // Orthographic projection + CAMERA_PERSPECTIVE = 0, + CAMERA_ORTHOGRAPHIC } CameraProjection; // N-patch layout @@ -949,12 +896,17 @@ typedef enum { } NPatchLayout; // Callbacks to hook some internal functions -// WARNING: These callbacks are intended for advanced users +// WARNING: This callbacks are intended for advance users typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages -typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data -typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data -typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data -typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data +typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data +typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data +typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data +typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data + + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif //------------------------------------------------------------------------------------ // Global Variables Definition @@ -965,60 +917,46 @@ typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - // Window-related functions RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context +RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI void CloseWindow(void); // Close window and unload OpenGL context -RLAPI bool WindowShouldClose(void); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen -RLAPI bool IsWindowHidden(void); // Check if window is currently hidden -RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized -RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized -RLAPI bool IsWindowFocused(void); // Check if window is currently focused +RLAPI bool IsWindowHidden(void); // Check if window is currently hidden (only PLATFORM_DESKTOP) +RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized (only PLATFORM_DESKTOP) +RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized (only PLATFORM_DESKTOP) +RLAPI bool IsWindowFocused(void); // Check if window is currently focused (only PLATFORM_DESKTOP) RLAPI bool IsWindowResized(void); // Check if window has been resized last frame RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags -RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed, resizes monitor to match window resolution -RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed, resizes window to match monitor resolution -RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable -RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable -RLAPI void RestoreWindow(void); // Restore window from being minimized/maximized -RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit) -RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit) -RLAPI void SetWindowTitle(const char *title); // Set title for window -RLAPI void SetWindowPosition(int x, int y); // Set window position on screen -RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window +RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) +RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) +RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) +RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) +RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) +RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP) +RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) +RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode) RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) -RLAPI void SetWindowMaxSize(int width, int height); // Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) RLAPI void SetWindowSize(int width, int height); // Set window dimensions -RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] -RLAPI void SetWindowFocused(void); // Set window focused RLAPI void *GetWindowHandle(void); // Get native window handle RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height -RLAPI int GetRenderWidth(void); // Get current render width (it considers HiDPI) -RLAPI int GetRenderHeight(void); // Get current render height (it considers HiDPI) RLAPI int GetMonitorCount(void); // Get number of connected monitors -RLAPI int GetCurrentMonitor(void); // Get current monitor where window is placed +RLAPI int GetCurrentMonitor(void); // Get current connected monitor RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position -RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (current video mode used by monitor) -RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (current video mode used by monitor) +RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (max available by monitor) +RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (max available by monitor) RLAPI int GetMonitorPhysicalWidth(int monitor); // Get specified monitor physical width in millimetres RLAPI int GetMonitorPhysicalHeight(int monitor); // Get specified monitor physical height in millimetres RLAPI int GetMonitorRefreshRate(int monitor); // Get specified monitor refresh rate RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor RLAPI Vector2 GetWindowScaleDPI(void); // Get window scale DPI factor -RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the specified monitor +RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor RLAPI void SetClipboardText(const char *text); // Set clipboard text content RLAPI const char *GetClipboardText(void); // Get clipboard text content -RLAPI Image GetClipboardImage(void); // Get clipboard image content -RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling -RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling // Cursor-related functions RLAPI void ShowCursor(void); // Shows cursor @@ -1040,7 +978,7 @@ RLAPI void BeginTextureMode(RenderTexture2D target); // Begin drawi RLAPI void EndTextureMode(void); // Ends drawing to render texture RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) -RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied, subtract, custom) +RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) RLAPI void EndScissorMode(void); // End scissor mode @@ -1055,61 +993,42 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s // NOTE: Shader functionality is not available on OpenGL 1.1 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations -RLAPI bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU) RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) -RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d) +RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value for texture (sampler2d) RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) // Screen-space-related functions -#define GetMouseRay GetScreenToWorldRay // Compatibility hack for previous raylib versions -RLAPI Ray GetScreenToWorldRay(Vector2 position, Camera camera); // Get a ray trace from screen position (i.e mouse) -RLAPI Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height); // Get a ray trace from screen position (i.e mouse) in a viewport -RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get the screen space position for a 3d world space position -RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position -RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the screen space position for a 2d camera world space position -RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get the world space position for a 2d camera screen space position -RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix) -RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix +RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position +RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) +RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Returns camera 2d transform matrix +RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position +RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Returns size position for a 3d world space position +RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Returns the screen space position for a 2d camera world space position +RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Returns the world space position for a 2d camera screen space position // Timing-related functions RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) -RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time) -RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow() -RLAPI int GetFPS(void); // Get current FPS - -// Custom frame control functions -// NOTE: Those functions are intended for advanced users that want full control over the frame processing -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() -// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL -RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) -RLAPI void PollInputEvents(void); // Register all input events -RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution) - -// Random values generation functions -RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator -RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) -RLAPI int *LoadRandomSequence(unsigned int count, int min, int max); // Load random values sequence, no values repeated -RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence +RLAPI int GetFPS(void); // Returns current FPS +RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn (delta time) +RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow() // Misc. functions +RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format) RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS) -RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) -// NOTE: Following functions implemented in module [utils] -//------------------------------------------------------------------ -RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) +RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR) RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level -RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator -RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator +RLAPI void *MemAlloc(int size); // Internal memory allocator +RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator RLAPI void MemFree(void *ptr); // Internal memory free // Set custom callbacks -// WARNING: Callbacks setup is intended for advanced users +// WARNING: Callbacks setup is intended for advance users RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver @@ -1117,126 +1036,106 @@ RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver // Files management functions -RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) +RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read) RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() -RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success -RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success +RLAPI bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write), returns true on success RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() -RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success -//------------------------------------------------------------------ - -// File system functions +RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success RLAPI bool FileExists(const char *fileName); // Check if file exists RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists -RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (including point: .png, .wav) -RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) -RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') +RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension (including point: .png, .wav) +RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: ".png") RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) -RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) -RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success +RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed) +RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory) RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success -RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory -RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS -RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths -RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result -RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window -RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths -RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths +RLAPI char **GetDroppedFiles(int *count); // Get dropped files names (memory should be freed) +RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory) RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) -// Compression/Encoding functionality -RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() -RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() -RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree() -RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree() -RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code -RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) -RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) +RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength); // Compress data (DEFLATE algorithm) +RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorithm) -// Automation events functionality -RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS -RLAPI void UnloadAutomationEventList(AutomationEventList list); // Unload automation events list from file -RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName); // Export automation events list as text file -RLAPI void SetAutomationEventList(AutomationEventList *list); // Set automation event list to record to -RLAPI void SetAutomationEventBaseFrame(int frame); // Set automation event internal base frame to start recording -RLAPI void StartAutomationEventRecording(void); // Start recording automation events (AutomationEventList must be set) -RLAPI void StopAutomationEventRecording(void); // Stop recording automation events -RLAPI void PlayAutomationEvent(AutomationEvent event); // Play a recorded automation event +// Persistent storage management +RLAPI bool SaveStorageValue(unsigned int position, int value); // Save integer value to storage file (to defined position), returns true on success +RLAPI int LoadStorageValue(unsigned int position); // Load integer value from storage file (from defined position) + +RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ // Input-related functions: keyboard -RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once -RLAPI bool IsKeyPressedRepeat(int key); // Check if a key has been pressed again -RLAPI bool IsKeyDown(int key); // Check if a key is being pressed -RLAPI bool IsKeyReleased(int key); // Check if a key has been released once -RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed -RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty -RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty -RLAPI const char *GetKeyName(int key); // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) +RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once +RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed +RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once +RLAPI bool IsKeyUp(int key); // Detect if a key is NOT being pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) +RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued +RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued // Input-related functions: gamepads -RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available -RLAPI const char *GetGamepadName(int gamepad); // Get gamepad internal name id -RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if a gamepad button has been pressed once -RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a gamepad button is being pressed -RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once -RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed +RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +RLAPI bool IsGamepadName(int gamepad, const char *name); // Check gamepad name (if available) +RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id +RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once +RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed +RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once +RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed -RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad -RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis +RLAPI int GetGamepadAxisCount(int gamepad); // Return gamepad axis count for a gamepad +RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB) -RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds) // Input-related functions: mouse -RLAPI bool IsMouseButtonPressed(int button); // Check if a mouse button has been pressed once -RLAPI bool IsMouseButtonDown(int button); // Check if a mouse button is being pressed -RLAPI bool IsMouseButtonReleased(int button); // Check if a mouse button has been released once -RLAPI bool IsMouseButtonUp(int button); // Check if a mouse button is NOT being pressed -RLAPI int GetMouseX(void); // Get mouse position X -RLAPI int GetMouseY(void); // Get mouse position Y -RLAPI Vector2 GetMousePosition(void); // Get mouse position XY -RLAPI Vector2 GetMouseDelta(void); // Get mouse delta between frames +RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once +RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed +RLAPI bool IsMouseButtonReleased(int button); // Detect if a mouse button has been released once +RLAPI bool IsMouseButtonUp(int button); // Detect if a mouse button is NOT being pressed +RLAPI int GetMouseX(void); // Returns mouse position X +RLAPI int GetMouseY(void); // Returns mouse position Y +RLAPI Vector2 GetMousePosition(void); // Returns mouse position XY RLAPI void SetMousePosition(int x, int y); // Set mouse position XY RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling -RLAPI float GetMouseWheelMove(void); // Get mouse wheel movement for X or Y, whichever is larger -RLAPI Vector2 GetMouseWheelMoveV(void); // Get mouse wheel movement for both X and Y +RLAPI float GetMouseWheelMove(void); // Returns mouse wheel movement Y RLAPI void SetMouseCursor(int cursor); // Set mouse cursor // Input-related functions: touch -RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size) -RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size) -RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size) -RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index -RLAPI int GetTouchPointCount(void); // Get number of touch points +RLAPI int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) +RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) +RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) //------------------------------------------------------------------------------------ -// Gestures and Touch Handling Functions (Module: rgestures) +// Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ -RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags -RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected -RLAPI int GetGestureDetected(void); // Get latest detected gesture -RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds -RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector -RLAPI float GetGestureDragAngle(void); // Get gesture drag angle -RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta -RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle +RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags +RLAPI bool IsGestureDetected(int gesture); // Check if a gesture have been detected +RLAPI int GetGestureDetected(void); // Get latest detected gesture +RLAPI int GetTouchPointsCount(void); // Get touch points count +RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds +RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector +RLAPI float GetGestureDragAngle(void); // Get gesture drag angle +RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta +RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle //------------------------------------------------------------------------------------ -// Camera System Functions (Module: rcamera) +// Camera System Functions (Module: camera) //------------------------------------------------------------------------------------ -RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode -RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation +RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) +RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode + +RLAPI void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) +RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) +RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera) +RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) @@ -1244,80 +1143,53 @@ RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, f // Set texture and rectangle to be used on shapes drawing // NOTE: It can be useful when using basic shapes and one single font, // defining a font char white rectangle would allow drawing everything in a single draw call -RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing -RLAPI Texture2D GetShapesTexture(void); // Get texture that is used for shapes drawing -RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing +RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing // Basic shapes drawing functions -RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care] -RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] +RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel +RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line -RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) -RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) -RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines) -RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation +RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (Vector version) +RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness +RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line using cubic-bezier curves in-out +RLAPI void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color); //Draw line using quadratic bezier curves with a control point +RLAPI void DrawLineStrip(Vector2 *points, int pointsCount, Color color); // Draw lines sequence RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline -RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer); // Draw a gradient-filled circle +RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline -RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version) RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse -RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version) RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline -RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version) RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters -RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle -RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle -RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors +RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle +RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle +RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges -RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle lines with rounded edges -RLAPI void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline +RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!) -RLAPI void DrawTriangleFan(const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points (first vertex is the center) -RLAPI void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points +RLAPI void DrawTriangleFan(Vector2 *points, int pointsCount, Color color); // Draw a triangle fan defined by points (first vertex is the center) +RLAPI void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color); // Draw a triangle strip defined by points RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters -// Splines drawing functions -RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Linear, minimum 2 points -RLAPI void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: B-Spline, minimum 4 points -RLAPI void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Catmull-Rom, minimum 4 points -RLAPI void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] -RLAPI void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] -RLAPI void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color); // Draw spline segment: Linear, 2 points -RLAPI void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: B-Spline, 4 points -RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: Catmull-Rom, 4 points -RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point -RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points - -// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] -RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear -RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline -RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom -RLAPI Vector2 GetSplinePointBezierQuad(Vector2 p1, Vector2 c2, Vector2 p3, float t); // Get (evaluate) spline point: Quadratic Bezier -RLAPI Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t); // Get (evaluate) spline point: Cubic Bezier - // Basic shapes collision detection functions RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle -RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); // Check if circle collides with a line created betweeen two points [p1] and [p2] RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle -RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] -RLAPI bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount); // Check if point is within a polygon described by array of vertices RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision @@ -1326,35 +1198,28 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); //------------------------------------------------------------------------------------ // Image loading functions -// NOTE: These functions do not require GPU access +// NOTE: This functions do not require GPU access RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) -RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer -RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' -RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data -RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot) -RLAPI bool IsImageValid(Image image); // Check if an image is valid (data and parameters) +RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. ".png" RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success -RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success // Image generation functions RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color -RLAPI Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end); // Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient +RLAPI Image GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient +RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient -RLAPI Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer); // Generate image: square gradient RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise -RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells -RLAPI Image GenImageText(int width, int height, const char *text); // Generate image: grayscale image from text data +RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells // Image manipulation functions RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece -RLAPI Image ImageFromChannel(Image image, int selectedChannel); // Create an image from a selected channel of another image (GRAYSCALE) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format @@ -1364,16 +1229,13 @@ RLAPI void ImageAlphaCrop(Image *image, float threshold); RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel -RLAPI void ImageBlurGaussian(Image *image, int blurSize); // Apply Gaussian blur using a box blur approximation -RLAPI void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize); // Apply custom square convolution kernel to image RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm) -RLAPI void ImageResizeNN(Image *image, int newWidth, int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) -RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color +RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color RLAPI void ImageMipmaps(Image *image); // Compute all mipmap levels for a provided image RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally -RLAPI void ImageRotate(Image *image, int degrees); // Rotate image by input angle in degrees (-359 to 359) RLAPI void ImageRotateCW(Image *image); // Rotate image clockwise 90deg RLAPI void ImageRotateCCW(Image *image); // Rotate image counter-clockwise 90deg RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint @@ -1383,11 +1245,10 @@ RLAPI void ImageColorContrast(Image *image, float contrast); RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color RLAPI Color *LoadImageColors(Image image); // Load color data from image as a Color array (RGBA - 32bit) -RLAPI Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount); // Load colors palette from image as a Color array (RGBA - 32bit) +RLAPI Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorsCount); // Load colors palette from image as a Color array (RGBA - 32bit) RLAPI void UnloadImageColors(Color *colors); // Unload color data loaded with LoadImageColors() RLAPI void UnloadImagePalette(Color *colors); // Unload colors palette loaded with LoadImagePalette() RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle -RLAPI Color GetImageColor(Image image, int x, int y); // Get image pixel color at (x, y) position // Image drawing functions // NOTE: Image software-rendering functions (CPU) @@ -1396,20 +1257,12 @@ RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version) RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image RLAPI void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color); // Draw line within an image (Vector version) -RLAPI void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color); // Draw a line defining thickness within an image -RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image -RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version) -RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image -RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color); // Draw circle outline within an image (Vector version) +RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle within an image +RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw circle within an image (Vector version) RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version) RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image -RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image -RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image -RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image -RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center) -RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source) RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination) RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination) @@ -1420,12 +1273,12 @@ RLAPI Texture2D LoadTexture(const char *fileName); RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) -RLAPI bool IsTextureValid(Texture2D texture); // Check if a texture is valid (loaded in GPU) RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) -RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data +RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image +RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot) // Texture configuration functions RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture @@ -1437,24 +1290,22 @@ RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters -RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely +RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters +RLAPI void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. +RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters +RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely +RLAPI void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointsCount, Color tint); // Draw a textured polygon // Color/pixel related functions -RLAPI bool ColorIsEqual(Color col1, Color col2); // Check if two colors are equal -RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f -RLAPI int ColorToInt(Color color); // Get hexadecimal value for a Color (0xRRGGBBAA) -RLAPI Vector4 ColorNormalize(Color color); // Get Color normalized as float [0..1] -RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1] -RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] -RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] -RLAPI Color ColorTint(Color color, Color tint); // Get color multiplied with another color -RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f -RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f -RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f -RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint -RLAPI Color ColorLerp(Color color1, Color color2, float factor); // Get color lerp interpolation between two colors, factor [0.0f..1.0f] -RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value +RLAPI Color Fade(Color color, float alpha); // Returns color with alpha applied, alpha goes from 0.0f to 1.0f +RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color +RLAPI Vector4 ColorNormalize(Color color); // Returns Color normalized as float [0..1] +RLAPI Color ColorFromNormalized(Vector4 normalized); // Returns Color from normalized values [0..1] +RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color, hue [0..360], saturation/value [0..1] +RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Returns a Color from HSV values, hue [0..360], saturation/value [0..1] +RLAPI Color ColorAlpha(Color color, float alpha); // Returns color with alpha applied, alpha goes from 0.0f to 1.0f +RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Returns src alpha-blended into dst color with tint +RLAPI Color GetColor(int hexValue); // Get Color structure from hexadecimal value RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format @@ -1466,65 +1317,51 @@ RLAPI int GetPixelDataSize(int width, int height, int format); // G // Font loading/unloading functions RLAPI Font GetFontDefault(void); // Get the default Font RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height +RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // Load font from file with extended parameters RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) -RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' -RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked) -RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use -RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info -RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) -RLAPI void UnloadFont(Font font); // Unload font from GPU memory (VRAM) -RLAPI bool ExportFontAsCode(Font font, const char *fileName); // Export font as code file, returns true on success +RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount); // Load font from memory buffer, fileType refers to extension: i.e. ".ttf" +RLAPI CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use +RLAPI Image GenImageFontAtlas(const CharInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info +RLAPI void UnloadFontData(CharInfo *chars, int charsCount); // Unload font chars info data (RAM) +RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions RLAPI void DrawFPS(int posX, int posY); // Draw current FPS RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters -RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) -RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) -RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint) +RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters +RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits +RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection +RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) -// Text font info functions -RLAPI void SetTextLineSpacing(int spacing); // Set vertical line spacing when drawing with line-breaks +// Text misc. functions RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found -RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found -RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found +RLAPI int GetGlyphIndex(Font font, int codepoint); // Get index position for a unicode character on font -// Text codepoints management functions (unicode characters) -RLAPI char *LoadUTF8(const int *codepoints, int length); // Load UTF-8 text encoded from codepoints array -RLAPI void UnloadUTF8(char *text); // Unload UTF-8 text encoded from codepoints array -RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter -RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory -RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string -RLAPI int GetCodepoint(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) - -// Text strings management functions (no UTF-8 strings, only byte chars) -// WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use -// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree() +// Text strings management functions (no utf8 strings, only byte chars) +// NOTE: Some strings allocate memory internally for returned strings, just be careful! RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending -RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style) +RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style) RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string -RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) -RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) -RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter -RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings +RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (memory must be freed!) +RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (memory must be freed!) +RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter +RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string -RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string -RLAPI char *TextToLower(const char *text); // Get lower case version of provided string -RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string -RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string -RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string +RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string +RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string +RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string +RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported) +RLAPI char *TextToUtf8(int *codepoints, int length); // Encode text codepoint into utf8 text (memory must be freed!) -RLAPI int TextToInteger(const char *text); // Get integer value from text -RLAPI float TextToFloat(const char *text); // Get float value from text +// UTF8 text strings management functions +RLAPI int *GetCodepoints(const char *text, int *count); // Get all codepoints in a string, codepoints count returned by parameters +RLAPI int GetCodepointsCount(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string +RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed); // Returns next codepoint in a UTF8 encoded string; 0x3f('?') is returned on failure +RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode codepoint into utf8 text (char array length returned as parameter) //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) @@ -1535,20 +1372,17 @@ RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) -RLAPI void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color); // Draw a triangle strip defined by points +RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color); // Draw a triangle strip defined by points RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version) +RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone -RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires -RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos -RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos -RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) @@ -1557,35 +1391,33 @@ RLAPI void DrawGrid(int slices, float spacing); // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ -// Model management functions +// Model loading/unloading functions RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials) RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) -RLAPI bool IsModelValid(Model model); // Check if a model is valid (loaded in GPU, VAO/VBOs) RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) -RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) +RLAPI void UnloadModelKeepMeshes(Model model); // Unload model (but not meshes) from memory (RAM and/or VRAM) -// Model drawing functions -RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters -RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) -RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points -RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters -RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) -RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source -RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation - -// Mesh management functions +// Mesh loading/unloading functions RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids -RLAPI void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset); // Update mesh vertex data in GPU for a specific buffer index -RLAPI void UnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU +RLAPI void UpdateMeshBuffer(Mesh mesh, int index, void *data, int dataSize, int offset); // Update mesh vertex data in GPU for a specific buffer index RLAPI void DrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform -RLAPI void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms -RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits -RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents +RLAPI void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms +RLAPI void UnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU RLAPI bool ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file, returns true on success -RLAPI bool ExportMeshAsCode(Mesh mesh, const char *fileName); // Export mesh as code file (.h) defining multiple arrays of vertex attributes + +// Material loading/unloading functions +RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file +RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) +RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) +RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh + +// Model animations loading/unloading functions +RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animsCount); // Load model animations from file +RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose +RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data +RLAPI void UnloadModelAnimations(ModelAnimation* animations, unsigned int count); // Unload animation array data +RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match // Mesh generation functions RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh @@ -1594,62 +1426,56 @@ RLAPI Mesh GenMeshCube(float width, float height, float length); RLAPI Mesh GenMeshSphere(float radius, int rings, int slices); // Generate sphere mesh (standard sphere) RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices); // Generate half-sphere mesh (no bottom cap) RLAPI Mesh GenMeshCylinder(float radius, float height, int slices); // Generate cylinder mesh -RLAPI Mesh GenMeshCone(float radius, float height, int slices); // Generate cone/pyramid mesh RLAPI Mesh GenMeshTorus(float radius, float size, int radSeg, int sides); // Generate torus mesh RLAPI Mesh GenMeshKnot(float radius, float size, int radSeg, int sides); // Generate trefoil knot mesh RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); // Generate heightmap mesh from image data RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data -// Material loading/unloading functions -RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file -RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -RLAPI bool IsMaterialValid(Material material); // Check if a material is valid (shader assigned, map textures loaded in GPU) -RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) -RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) -RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh +// Mesh manipulation functions +RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits +RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents +RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals -// Model animations loading/unloading functions -RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file -RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose (CPU) -RLAPI void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (GPU skinning) -RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data -RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data -RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match +// Model drawing functions +RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) +RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters +RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) +RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) +RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source +RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation // Collision detection functions -RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres -RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Check collision between two bounding boxes -RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere -RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere -RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box -RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh -RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle -RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad +RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Detect collision between two spheres +RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes +RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Detect collision between box and sphere +RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius); // Detect collision between ray and sphere +RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point +RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box +RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh +RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model model); // Get collision info between ray and model +RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle +RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane) //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ -typedef void (*AudioCallback)(void *bufferData, unsigned int frames); // Audio device management functions RLAPI void InitAudioDevice(void); // Initialize audio device and context RLAPI void CloseAudioDevice(void); // Close the audio device and context RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully RLAPI void SetMasterVolume(float volume); // Set master volume (listener) -RLAPI float GetMasterVolume(void); // Get master volume (listener) // Wave/Sound loading/unloading functions RLAPI Wave LoadWave(const char *fileName); // Load wave data from file -RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' -RLAPI bool IsWaveValid(Wave wave); // Checks if wave data is valid (data loaded and parameters) +RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. ".wav" RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data -RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data -RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized) -RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data +RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound -RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data) RLAPI bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success RLAPI bool ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h), returns true on success @@ -1658,20 +1484,21 @@ RLAPI void PlaySound(Sound sound); // Play a RLAPI void StopSound(Sound sound); // Stop playing a sound RLAPI void PauseSound(Sound sound); // Pause a sound RLAPI void ResumeSound(Sound sound); // Resume a paused sound +RLAPI void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool) +RLAPI void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool) +RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) -RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center) +RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave -RLAPI void WaveCrop(Wave *wave, int initFrame, int finalFrame); // Crop a wave to defined frames range -RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format -RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a 32bit float data array +RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range +RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a floats array RLAPI void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples() // Music management functions RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file -RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data -RLAPI bool IsMusicValid(Music music); // Checks if a music stream is valid (context and buffers initialized) +RLAPI Music LoadMusicStreamFromMemory(const char *fileType, unsigned char* data, int dataSize); // Load music stream from data RLAPI void UnloadMusicStream(Music music); // Unload music stream RLAPI void PlayMusicStream(Music music); // Start music playing RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing @@ -1679,18 +1506,15 @@ RLAPI void UpdateMusicStream(Music music); // Updates RLAPI void StopMusicStream(Music music); // Stop music playing RLAPI void PauseMusicStream(Music music); // Pause music playing RLAPI void ResumeMusicStream(Music music); // Resume playing paused music -RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) // AudioStream management functions -RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) -RLAPI bool IsAudioStreamValid(AudioStream stream); // Checks if an audio stream is valid (buffers initialized) -RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory -RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data +RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) +RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data +RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream @@ -1699,15 +1523,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) -RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 is centered) RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams -RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data - -RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) -RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream - -RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) -RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline #if defined(__cplusplus) } diff --git a/raylib/raylib_purego.go b/raylib/raylib_purego.go deleted file mode 100644 index 70e8b61..0000000 --- a/raylib/raylib_purego.go +++ /dev/null @@ -1,3984 +0,0 @@ -//go:build !cgo && windows -// +build !cgo,windows - -package rl - -import ( - "fmt" - "image" - "image/color" - "os" - "reflect" - "unsafe" - - "github.com/ebitengine/purego" - "golang.org/x/sys/windows" -) - -var ( - // raylibDll is the pointer to the shared library - raylibDll uintptr - - // audioCallbacks is needed to have a reference between Go functions (keys) created by the user - // and C function pointers (values) created by purego.NewCallback - audioCallbacks map[uintptr]uintptr -) - -var initWindow func(width int32, height int32, title string) -var closeWindow func() -var windowShouldClose func() bool -var isWindowReady func() bool -var isWindowFullscreen func() bool -var isWindowHidden func() bool -var isWindowMinimized func() bool -var isWindowMaximized func() bool -var isWindowFocused func() bool -var isWindowResized func() bool -var isWindowState func(flag uint32) bool -var setWindowState func(flags uint32) -var clearWindowState func(flags uint32) -var toggleFullscreen func() -var toggleBorderlessWindowed func() -var maximizeWindow func() -var minimizeWindow func() -var restoreWindow func() -var setWindowIcon func(image uintptr) -var setWindowIcons func(images uintptr, count int32) -var setWindowTitle func(title string) -var setWindowPosition func(x int32, y int32) -var setWindowMonitor func(monitor int32) -var setWindowMinSize func(width int32, height int32) -var setWindowMaxSize func(width int32, height int32) -var setWindowSize func(width int32, height int32) -var setWindowOpacity func(opacity float32) -var setWindowFocused func() -var getWindowHandle func() unsafe.Pointer -var getScreenWidth func() int32 -var getScreenHeight func() int32 -var getRenderWidth func() int32 -var getRenderHeight func() int32 -var getMonitorCount func() int32 -var getCurrentMonitor func() int32 -var getMonitorPosition func(monitor int32) uintptr -var getMonitorWidth func(monitor int32) int32 -var getMonitorHeight func(monitor int32) int32 -var getMonitorPhysicalWidth func(monitor int32) int32 -var getMonitorPhysicalHeight func(monitor int32) int32 -var getMonitorRefreshRate func(monitor int32) int32 -var getWindowPosition func() uintptr -var getWindowScaleDPI func() uintptr -var getMonitorName func(monitor int32) string -var setClipboardText func(text string) -var getClipboardText func() string -var getClipboardImage func(img uintptr) -var enableEventWaiting func() -var disableEventWaiting func() -var showCursor func() -var hideCursor func() -var isCursorHidden func() bool -var enableCursor func() -var disableCursor func() -var isCursorOnScreen func() bool -var clearBackground func(col uintptr) -var beginDrawing func() -var endDrawing func() -var beginMode2D func(camera uintptr) -var endMode2D func() -var beginMode3D func(camera uintptr) -var endMode3D func() -var beginTextureMode func(target uintptr) -var endTextureMode func() -var beginShaderMode func(shader uintptr) -var endShaderMode func() -var beginBlendMode func(mode int32) -var endBlendMode func() -var beginScissorMode func(x int32, y int32, width int32, height int32) -var endScissorMode func() -var beginVrStereoMode func(config uintptr) -var endVrStereoMode func() -var loadVrStereoConfig func(config uintptr, device uintptr) -var unloadVrStereoConfig func(config uintptr) -var loadShader func(shader uintptr, vsFileName uintptr, fsFileName uintptr) -var loadShaderFromMemory func(shader uintptr, vsCode uintptr, fsCode uintptr) -var isShaderValid func(shader uintptr) bool -var getShaderLocation func(shader uintptr, uniformName string) int32 -var getShaderLocationAttrib func(shader uintptr, attribName string) int32 -var setShaderValue func(shader uintptr, locIndex int32, value []float32, uniformType int32) -var setShaderValueV func(shader uintptr, locIndex int32, value []float32, uniformType int32, count int32) -var setShaderValueMatrix func(shader uintptr, locIndex int32, mat uintptr) -var setShaderValueTexture func(shader uintptr, locIndex int32, texture uintptr) -var unloadShader func(shader uintptr) -var getScreenToWorldRay func(ray uintptr, position uintptr, camera uintptr) -var getScreenToWorldRayEx func(ray uintptr, position uintptr, camera uintptr, width, height int32) -var getCameraMatrix func(mat uintptr, camera uintptr) -var getCameraMatrix2D func(mat uintptr, camera uintptr) -var getWorldToScreen func(position uintptr, camera uintptr) uintptr -var getScreenToWorld2D func(position uintptr, camera uintptr) uintptr -var getWorldToScreenEx func(position uintptr, camera uintptr, width int32, height int32) uintptr -var getWorldToScreen2D func(position uintptr, camera uintptr) uintptr -var setTargetFPS func(fps int32) -var getFrameTime func() float32 -var getTime func() float64 -var getFPS func() int32 -var swapScreenBuffer func() -var pollInputEvents func() -var waitTime func(seconds float64) -var setRandomSeed func(seed uint32) -var getRandomValue func(minimum int32, maximum int32) int32 -var loadRandomSequence func(count uint32, minimum int32, maximum int32) *int32 -var unloadRandomSequence func(sequence *int32) -var takeScreenshot func(fileName string) -var setConfigFlags func(flags uint32) -var openURL func(url string) -var traceLog func(logLevel int32, text string) -var setTraceLogLevel func(logLevel int32) -var memAlloc func(size uint32) unsafe.Pointer -var memRealloc func(ptr unsafe.Pointer, size uint32) unsafe.Pointer -var memFree func(ptr unsafe.Pointer) -var setTraceLogCallback func(callback uintptr) -var isFileDropped func() bool -var loadDroppedFiles func(files uintptr) -var unloadDroppedFiles func(files uintptr) -var loadAutomationEventList func(automationEventList uintptr, fileName string) uintptr -var unloadAutomationEventList func(list uintptr) -var exportAutomationEventList func(list uintptr, fileName string) bool -var setAutomationEventList func(list uintptr) -var setAutomationEventBaseFrame func(frame int32) -var startAutomationEventRecording func() -var stopAutomationEventRecording func() -var playAutomationEvent func(event uintptr) -var isKeyPressed func(key int32) bool -var isKeyPressedRepeat func(key int32) bool -var isKeyDown func(key int32) bool -var isKeyReleased func(key int32) bool -var isKeyUp func(key int32) bool -var getKeyPressed func() int32 -var getCharPressed func() int32 -var setExitKey func(key int32) -var isGamepadAvailable func(gamepad int32) bool -var getGamepadName func(gamepad int32) string -var isGamepadButtonPressed func(gamepad int32, button int32) bool -var isGamepadButtonDown func(gamepad int32, button int32) bool -var isGamepadButtonReleased func(gamepad int32, button int32) bool -var isGamepadButtonUp func(gamepad int32, button int32) bool -var getGamepadButtonPressed func() int32 -var getGamepadAxisCount func(gamepad int32) int32 -var getGamepadAxisMovement func(gamepad int32, axis int32) float32 -var setGamepadMappings func(mappings string) int32 -var setGamepadVibration func(gamepad int32, leftMotor, rightMotor, duration float32) -var isMouseButtonPressed func(button int32) bool -var isMouseButtonDown func(button int32) bool -var isMouseButtonReleased func(button int32) bool -var isMouseButtonUp func(button int32) bool -var getMouseX func() int32 -var getMouseY func() int32 -var getMousePosition func() uintptr -var getMouseDelta func() uintptr -var setMousePosition func(x int32, y int32) -var setMouseOffset func(offsetX int32, offsetY int32) -var setMouseScale func(scaleX float32, scaleY float32) -var getMouseWheelMove func() float32 -var getMouseWheelMoveV func() uintptr -var setMouseCursor func(cursor int32) -var getTouchX func() int32 -var getTouchY func() int32 -var getTouchPosition func(index int32) uintptr -var getTouchPointId func(index int32) int32 -var getTouchPointCount func() int32 -var setGesturesEnabled func(flags uint32) -var isGestureDetected func(gesture uint32) bool -var getGestureDetected func() int32 -var getGestureHoldDuration func() float32 -var getGestureDragVector func() uintptr -var getGestureDragAngle func() float32 -var getGesturePinchVector func() uintptr -var getGesturePinchAngle func() float32 -var setShapesTexture func(texture uintptr, source uintptr) -var getShapesTexture func(texture uintptr) -var getShapesTextureRectangle func(rec uintptr) -var drawPixel func(posX int32, posY int32, col uintptr) -var drawPixelV func(position uintptr, col uintptr) -var drawLine func(startPosX int32, startPosY int32, endPosX int32, endPosY int32, col uintptr) -var drawLineV func(startPos uintptr, endPos uintptr, col uintptr) -var drawLineEx func(startPos uintptr, endPos uintptr, thick float32, col uintptr) -var drawLineStrip func(points *Vector2, pointCount int32, col uintptr) -var drawLineBezier func(startPos uintptr, endPos uintptr, thick float32, col uintptr) -var drawCircle func(centerX int32, centerY int32, radius float32, col uintptr) -var drawCircleSector func(center uintptr, radius float32, startAngle float32, endAngle float32, segments int32, col uintptr) -var drawCircleSectorLines func(center uintptr, radius float32, startAngle float32, endAngle float32, segments int32, col uintptr) -var drawCircleGradient func(centerX int32, centerY int32, radius float32, inner uintptr, outer uintptr) -var drawCircleV func(center uintptr, radius float32, col uintptr) -var drawCircleLines func(centerX int32, centerY int32, radius float32, col uintptr) -var drawCircleLinesV func(center uintptr, radius float32, col uintptr) -var drawEllipse func(centerX int32, centerY int32, radiusH float32, radiusV float32, col uintptr) -var drawEllipseLines func(centerX int32, centerY int32, radiusH float32, radiusV float32, col uintptr) -var drawRing func(center uintptr, innerRadius float32, outerRadius float32, startAngle float32, endAngle float32, segments int32, col uintptr) -var drawRingLines func(center uintptr, innerRadius float32, outerRadius float32, startAngle float32, endAngle float32, segments int32, col uintptr) -var drawRectangle func(posX int32, posY int32, width int32, height int32, col uintptr) -var drawRectangleV func(position uintptr, size uintptr, col uintptr) -var drawRectangleRec func(rec uintptr, col uintptr) -var drawRectanglePro func(rec uintptr, origin uintptr, rotation float32, col uintptr) -var drawRectangleGradientV func(posX int32, posY int32, width int32, height int32, top uintptr, bottom uintptr) -var drawRectangleGradientH func(posX int32, posY int32, width int32, height int32, left uintptr, right uintptr) -var drawRectangleGradientEx func(rec uintptr, topLeft uintptr, bottomLeft uintptr, topRight uintptr, bottomRight uintptr) -var drawRectangleLines func(posX int32, posY int32, width int32, height int32, col uintptr) -var drawRectangleLinesEx func(rec uintptr, lineThick float32, col uintptr) -var drawRectangleRounded func(rec uintptr, roundness float32, segments int32, col uintptr) -var drawRectangleRoundedLines func(rec uintptr, roundness float32, segments int32, col uintptr) -var drawRectangleRoundedLinesEx func(rec uintptr, roundness float32, segments int32, lineThick float32, col uintptr) -var drawTriangle func(v1 uintptr, v2 uintptr, v3 uintptr, col uintptr) -var drawTriangleLines func(v1 uintptr, v2 uintptr, v3 uintptr, col uintptr) -var drawTriangleFan func(points *Vector2, pointCount int32, col uintptr) -var drawTriangleStrip func(points *Vector2, pointCount int32, col uintptr) -var drawPoly func(center uintptr, sides int32, radius float32, rotation float32, col uintptr) -var drawPolyLines func(center uintptr, sides int32, radius float32, rotation float32, col uintptr) -var drawPolyLinesEx func(center uintptr, sides int32, radius float32, rotation float32, lineThick float32, col uintptr) -var drawSplineLinear func(points *Vector2, pointCount int32, thick float32, col uintptr) -var drawSplineBasis func(points *Vector2, pointCount int32, thick float32, col uintptr) -var drawSplineCatmullRom func(points *Vector2, pointCount int32, thick float32, col uintptr) -var drawSplineBezierQuadratic func(points *Vector2, pointCount int32, thick float32, col uintptr) -var drawSplineBezierCubic func(points *Vector2, pointCount int32, thick float32, col uintptr) -var drawSplineSegmentLinear func(p1 uintptr, p2 uintptr, thick float32, col uintptr) -var drawSplineSegmentBasis func(p1 uintptr, p2 uintptr, p3 uintptr, p4 uintptr, thick float32, col uintptr) -var drawSplineSegmentCatmullRom func(p1 uintptr, p2 uintptr, p3 uintptr, p4 uintptr, thick float32, col uintptr) -var drawSplineSegmentBezierQuadratic func(p1 uintptr, c2 uintptr, p3 uintptr, thick float32, col uintptr) -var drawSplineSegmentBezierCubic func(p1 uintptr, c2 uintptr, c3 uintptr, p4 uintptr, thick float32, col uintptr) -var getSplinePointLinear func(startPos uintptr, endPos uintptr, t float32) uintptr -var getSplinePointBasis func(p1 uintptr, p2 uintptr, p3 uintptr, p4 uintptr, t float32) uintptr -var getSplinePointCatmullRom func(p1 uintptr, p2 uintptr, p3 uintptr, p4 uintptr, t float32) uintptr -var getSplinePointBezierQuad func(p1 uintptr, c2 uintptr, p3 uintptr, t float32) uintptr -var getSplinePointBezierCubic func(p1 uintptr, c2 uintptr, c3 uintptr, p4 uintptr, t float32) uintptr -var checkCollisionRecs func(rec1 uintptr, rec2 uintptr) bool -var checkCollisionCircles func(center1 uintptr, radius1 float32, center2 uintptr, radius2 float32) bool -var checkCollisionCircleRec func(center uintptr, radius float32, rec uintptr) bool -var checkCollisionCircleLine func(center uintptr, radius float32, p1, p2 uintptr) bool -var checkCollisionPointRec func(point uintptr, rec uintptr) bool -var checkCollisionPointCircle func(point uintptr, center uintptr, radius float32) bool -var checkCollisionPointTriangle func(point uintptr, p1 uintptr, p2 uintptr, p3 uintptr) bool -var checkCollisionPointPoly func(point uintptr, points *Vector2, pointCount int32) bool -var checkCollisionLines func(startPos1 uintptr, endPos1 uintptr, startPos2 uintptr, endPos2 uintptr, collisionPoint *Vector2) bool -var checkCollisionPointLine func(point uintptr, p1 uintptr, p2 uintptr, threshold int32) bool -var getCollisionRec func(rec uintptr, rec1 uintptr, rec2 uintptr) -var loadImage func(img uintptr, fileName string) -var loadImageRaw func(img uintptr, fileName string, width int32, height int32, format int32, headerSize int32) -var loadImageAnim func(img uintptr, fileName string, frames *int32) -var loadImageAnimFromMemory func(img uintptr, fileType string, fileData []byte, dataSize int32, frames *int32) -var loadImageFromMemory func(img uintptr, fileType string, fileData []byte, dataSize int32) -var loadImageFromTexture func(img uintptr, texture uintptr) -var loadImageFromScreen func(img uintptr) -var isImageValid func(image uintptr) bool -var unloadImage func(image uintptr) -var exportImage func(image uintptr, fileName string) bool -var exportImageToMemory func(image uintptr, fileType string, fileSize *int32) *byte -var genImageColor func(image uintptr, width int32, height int32, col uintptr) -var genImageGradientLinear func(image uintptr, width int32, height int32, direction int32, start uintptr, end uintptr) -var genImageGradientRadial func(image uintptr, width int32, height int32, density float32, inner uintptr, outer uintptr) -var genImageGradientSquare func(image uintptr, width int32, height int32, density float32, inner uintptr, outer uintptr) -var genImageChecked func(image uintptr, width int32, height int32, checksX int32, checksY int32, col1 uintptr, col2 uintptr) -var genImageWhiteNoise func(image uintptr, width int32, height int32, factor float32) -var genImagePerlinNoise func(image uintptr, width int32, height int32, offsetX int32, offsetY int32, scale float32) -var genImageCellular func(image uintptr, width int32, height int32, tileSize int32) -var genImageText func(image uintptr, width int32, height int32, text string) -var imageCopy func(retImage uintptr, image uintptr) -var imageFromImage func(retImage uintptr, image uintptr, rec uintptr) -var imageFromChannel func(retImage uintptr, image uintptr, selectedChannel int32) -var imageText func(retImage uintptr, text string, fontSize int32, col uintptr) -var imageTextEx func(retImage uintptr, font uintptr, text string, fontSize float32, spacing float32, tint uintptr) -var imageFormat func(image *Image, newFormat int32) -var imageToPOT func(image *Image, fill uintptr) -var imageCrop func(image *Image, crop uintptr) -var imageAlphaCrop func(image *Image, threshold float32) -var imageAlphaClear func(image *Image, col uintptr, threshold float32) -var imageAlphaMask func(image *Image, alphaMask uintptr) -var imageAlphaPremultiply func(image *Image) -var imageBlurGaussian func(image *Image, blurSize int32) -var imageKernelConvolution func(image *Image, kernel []float32, kernelSize int32) -var imageResize func(image *Image, newWidth int32, newHeight int32) -var imageResizeNN func(image *Image, newWidth int32, newHeight int32) -var imageResizeCanvas func(image *Image, newWidth int32, newHeight int32, offsetX int32, offsetY int32, fill uintptr) -var imageMipmaps func(image *Image) -var imageDither func(image *Image, rBpp int32, gBpp int32, bBpp int32, aBpp int32) -var imageFlipVertical func(image *Image) -var imageFlipHorizontal func(image *Image) -var imageRotate func(image *Image, degrees int32) -var imageRotateCW func(image *Image) -var imageRotateCCW func(image *Image) -var imageColorTint func(image *Image, col uintptr) -var imageColorInvert func(image *Image) -var imageColorGrayscale func(image *Image) -var imageColorContrast func(image *Image, contrast float32) -var imageColorBrightness func(image *Image, brightness int32) -var imageColorReplace func(image *Image, col uintptr, replace uintptr) -var loadImageColors func(image uintptr) *color.RGBA -var loadImagePalette func(image uintptr, maxPaletteSize int32, colorCount *int32) *color.RGBA -var unloadImageColors func(colors *color.RGBA) -var unloadImagePalette func(colors *color.RGBA) -var getImageAlphaBorder func(rec uintptr, image uintptr, threshold float32) -var getImageColor func(image uintptr, x int32, y int32) uintptr -var imageClearBackground func(dst *Image, col uintptr) -var imageDrawPixel func(dst *Image, posX int32, posY int32, col uintptr) -var imageDrawPixelV func(dst *Image, position uintptr, col uintptr) -var imageDrawLine func(dst *Image, startPosX int32, startPosY int32, endPosX int32, endPosY int32, col uintptr) -var imageDrawLineV func(dst *Image, start uintptr, end uintptr, col uintptr) -var imageDrawLineEx func(dst *Image, start uintptr, end uintptr, thick int32, col uintptr) -var imageDrawCircle func(dst *Image, centerX int32, centerY int32, radius int32, col uintptr) -var imageDrawCircleV func(dst *Image, center uintptr, radius int32, col uintptr) -var imageDrawCircleLines func(dst *Image, centerX int32, centerY int32, radius int32, col uintptr) -var imageDrawCircleLinesV func(dst *Image, center uintptr, radius int32, col uintptr) -var imageDrawRectangle func(dst *Image, posX int32, posY int32, width int32, height int32, col uintptr) -var imageDrawRectangleV func(dst *Image, position uintptr, size uintptr, col uintptr) -var imageDrawRectangleRec func(dst *Image, rec uintptr, col uintptr) -var imageDrawRectangleLines func(dst *Image, rec uintptr, thick int32, col uintptr) -var imageDrawTriangle func(dst *Image, v1, v2, v3 uintptr, col uintptr) -var imageDrawTriangleEx func(dst *Image, v1, v2, v3 uintptr, c1, c2, c3 uintptr) -var imageDrawTriangleLines func(dst *Image, v1, v2, v3 uintptr, col uintptr) -var imageDrawTriangleFan func(dst *Image, points *Vector2, pointCount int32, col uintptr) -var imageDrawTriangleStrip func(dst *Image, points *Vector2, pointCount int32, col uintptr) -var imageDraw func(dst *Image, src uintptr, srcRec uintptr, dstRec uintptr, tint uintptr) -var imageDrawText func(dst *Image, text string, posX int32, posY int32, fontSize int32, col uintptr) -var imageDrawTextEx func(dst *Image, font uintptr, text string, position uintptr, fontSize float32, spacing float32, tint uintptr) -var loadTexture func(texture uintptr, fileName string) -var loadTextureFromImage func(texture uintptr, image uintptr) -var loadTextureCubemap func(texture uintptr, image uintptr, layout int32) -var loadRenderTexture func(texture uintptr, width int32, height int32) -var isTextureValid func(texture uintptr) bool -var unloadTexture func(texture uintptr) -var isRenderTextureValid func(target uintptr) bool -var unloadRenderTexture func(target uintptr) -var updateTexture func(texture uintptr, pixels *color.RGBA) -var updateTextureRec func(texture uintptr, rec uintptr, pixels *color.RGBA) -var genTextureMipmaps func(texture *Texture2D) -var setTextureFilter func(texture uintptr, filter int32) -var setTextureWrap func(texture uintptr, wrap int32) -var drawTexture func(texture uintptr, posX int32, posY int32, tint uintptr) -var drawTextureV func(texture uintptr, position uintptr, tint uintptr) -var drawTextureEx func(texture uintptr, position uintptr, rotation float32, scale float32, tint uintptr) -var drawTextureRec func(texture uintptr, source uintptr, position uintptr, tint uintptr) -var drawTexturePro func(texture uintptr, source uintptr, dest uintptr, origin uintptr, rotation float32, tint uintptr) -var drawTextureNPatch func(texture uintptr, nPatchInfo uintptr, dest uintptr, origin uintptr, rotation float32, tint uintptr) -var fade func(col uintptr, alpha float32) uintptr -var colorToInt func(col uintptr) int32 -var colorNormalize func(vector4 uintptr, col uintptr) -var colorFromNormalized func(normalized uintptr) uintptr -var colorToHSV func(vector3 uintptr, col uintptr) -var colorFromHSV func(hue float32, saturation float32, value float32) uintptr -var colorTint func(col uintptr, tint uintptr) uintptr -var colorBrightness func(col uintptr, factor float32) uintptr -var colorContrast func(col uintptr, contrast float32) uintptr -var colorAlpha func(col uintptr, alpha float32) uintptr -var colorAlphaBlend func(dst uintptr, src uintptr, tint uintptr) uintptr -var colorLerp func(col1, col2 uintptr, factor float32) uintptr -var getColor func(hexValue uint32) uintptr -var getPixelColor func(srcPtr unsafe.Pointer, format int32) uintptr -var setPixelColor func(dstPtr unsafe.Pointer, col uintptr, format int32) -var getPixelDataSize func(width int32, height int32, format int32) int32 -var getFontDefault func(font uintptr) -var loadFont func(font uintptr, fileName string) -var loadFontEx func(font uintptr, fileName string, fontSize int32, codepoints []int32, codepointCount int32) -var loadFontFromImage func(font uintptr, image uintptr, key uintptr, firstChar int32) -var loadFontFromMemory func(font uintptr, fileType string, fileData []byte, dataSize int32, fontSize int32, codepoints []int32, codepointCount int32) -var isFontValid func(font uintptr) bool -var loadFontData func(fileData []byte, dataSize int32, fontSize int32, codepoints []int32, codepointCount int32, _type int32) *GlyphInfo -var genImageFontAtlas func(image uintptr, glyphs *GlyphInfo, glyphRecs []*Rectangle, glyphCount int32, fontSize int32, padding int32, packMethod int32) -var unloadFontData func(glyphs *GlyphInfo, glyphCount int32) -var unloadFont func(font uintptr) -var drawFPS func(posX int32, posY int32) -var drawText func(text string, posX int32, posY int32, fontSize int32, col uintptr) -var drawTextEx func(font uintptr, text string, position uintptr, fontSize float32, spacing float32, tint uintptr) -var drawTextPro func(font uintptr, text string, position uintptr, origin uintptr, rotation float32, fontSize float32, spacing float32, tint uintptr) -var drawTextCodepoint func(font uintptr, codepoint int32, position uintptr, fontSize float32, tint uintptr) -var drawTextCodepoints func(font uintptr, codepoints []int32, codepointCount int32, position uintptr, fontSize float32, spacing float32, tint uintptr) -var setTextLineSpacing func(spacing int32) -var measureText func(text string, fontSize int32) int32 -var measureTextEx func(font uintptr, text string, fontSize float32, spacing float32) uintptr -var getGlyphIndex func(font uintptr, codepoint int32) int32 -var getGlyphInfo func(glyphInfo uintptr, font uintptr, codepoint int32) -var getGlyphAtlasRec func(rec uintptr, font uintptr, codepoint int32) -var drawLine3D func(startPos uintptr, endPos uintptr, col uintptr) -var drawPoint3D func(position uintptr, col uintptr) -var drawCircle3D func(center uintptr, radius float32, rotationAxis uintptr, rotationAngle float32, col uintptr) -var drawTriangle3D func(v1 uintptr, v2 uintptr, v3 uintptr, col uintptr) -var drawTriangleStrip3D func(points *Vector3, pointCount int32, col uintptr) -var drawCube func(position uintptr, width float32, height float32, length float32, col uintptr) -var drawCubeV func(position uintptr, size uintptr, col uintptr) -var drawCubeWires func(position uintptr, width float32, height float32, length float32, col uintptr) -var drawCubeWiresV func(position uintptr, size uintptr, col uintptr) -var drawSphere func(centerPos uintptr, radius float32, col uintptr) -var drawSphereEx func(centerPos uintptr, radius float32, rings int32, slices int32, col uintptr) -var drawSphereWires func(centerPos uintptr, radius float32, rings int32, slices int32, col uintptr) -var drawCylinder func(position uintptr, radiusTop float32, radiusBottom float32, height float32, slices int32, col uintptr) -var drawCylinderEx func(startPos uintptr, endPos uintptr, startRadius float32, endRadius float32, sides int32, col uintptr) -var drawCylinderWires func(position uintptr, radiusTop float32, radiusBottom float32, height float32, slices int32, col uintptr) -var drawCylinderWiresEx func(startPos uintptr, endPos uintptr, startRadius float32, endRadius float32, sides int32, col uintptr) -var drawCapsule func(startPos uintptr, endPos uintptr, radius float32, slices int32, rings int32, col uintptr) -var drawCapsuleWires func(startPos uintptr, endPos uintptr, radius float32, slices int32, rings int32, col uintptr) -var drawPlane func(centerPos uintptr, size uintptr, col uintptr) -var drawRay func(ray uintptr, col uintptr) -var drawGrid func(slices int32, spacing float32) -var loadModel func(model uintptr, fileName string) -var loadModelFromMesh func(model uintptr, mesh uintptr) -var isModelValid func(model uintptr) bool -var unloadModel func(model uintptr) -var getModelBoundingBox func(boundingBox uintptr, model uintptr) -var drawModel func(model uintptr, position uintptr, scale float32, tint uintptr) -var drawModelEx func(model uintptr, position uintptr, rotationAxis uintptr, rotationAngle float32, scale uintptr, tint uintptr) -var drawModelWires func(model uintptr, position uintptr, scale float32, tint uintptr) -var drawModelWiresEx func(model uintptr, position uintptr, rotationAxis uintptr, rotationAngle float32, scale uintptr, tint uintptr) -var drawModelPoints func(model uintptr, position uintptr, scale float32, tint uintptr) -var drawModelPointsEx func(model uintptr, position uintptr, rotationAxis uintptr, rotationAngle float32, scale uintptr, tint uintptr) -var drawBoundingBox func(box uintptr, col uintptr) -var drawBillboard func(camera uintptr, texture uintptr, position uintptr, scale float32, tint uintptr) -var drawBillboardRec func(camera uintptr, texture uintptr, source uintptr, position uintptr, size uintptr, tint uintptr) -var drawBillboardPro func(camera uintptr, texture uintptr, source uintptr, position uintptr, up uintptr, size uintptr, origin uintptr, rotation float32, tint uintptr) -var uploadMesh func(mesh *Mesh, dynamic bool) -var updateMeshBuffer func(mesh uintptr, index int32, data []byte, dataSize int32, offset int32) -var unloadMesh func(mesh uintptr) -var drawMesh func(mesh uintptr, material uintptr, transform uintptr) -var drawMeshInstanced func(mesh uintptr, material uintptr, transforms []Matrix, instances int32) -var exportMesh func(mesh uintptr, fileName string) bool -var getMeshBoundingBox func(boundingBox uintptr, mesh uintptr) -var genMeshTangents func(mesh *Mesh) -var genMeshPoly func(mesh uintptr, sides int32, radius float32) -var genMeshPlane func(mesh uintptr, width float32, length float32, resX int32, resZ int32) -var genMeshCube func(mesh uintptr, width float32, height float32, length float32) -var genMeshSphere func(mesh uintptr, radius float32, rings int32, slices int32) -var genMeshHemiSphere func(mesh uintptr, radius float32, rings int32, slices int32) -var genMeshCylinder func(mesh uintptr, radius float32, height float32, slices int32) -var genMeshCone func(mesh uintptr, radius float32, height float32, slices int32) -var genMeshTorus func(mesh uintptr, radius float32, size float32, radSeg int32, sides int32) -var genMeshKnot func(mesh uintptr, radius float32, size float32, radSeg int32, sides int32) -var genMeshHeightmap func(mesh uintptr, heightmap uintptr, size uintptr) -var genMeshCubicmap func(mesh uintptr, cubicmap uintptr, cubeSize uintptr) -var loadMaterials func(fileName string, materialCount *int32) *Material -var loadMaterialDefault func(material uintptr) -var isMaterialValid func(material uintptr) bool -var unloadMaterial func(material uintptr) -var setMaterialTexture func(material *Material, mapType int32, texture uintptr) -var setModelMeshMaterial func(model *Model, meshId int32, materialId int32) -var loadModelAnimations func(fileName string, animCount *int32) *ModelAnimation -var updateModelAnimation func(model uintptr, anim uintptr, frame int32) -var updateModelAnimationBones func(model uintptr, anim uintptr, frame int32) -var unloadModelAnimation func(anim uintptr) -var unloadModelAnimations func(animations *ModelAnimation, animCount int32) -var isModelAnimationValid func(model uintptr, anim uintptr) bool -var checkCollisionSpheres func(center1 uintptr, radius1 float32, center2 uintptr, radius2 float32) bool -var checkCollisionBoxes func(box1 uintptr, box2 uintptr) bool -var checkCollisionBoxSphere func(box uintptr, center uintptr, radius float32) bool -var getRayCollisionSphere func(rayCollision uintptr, ray uintptr, center uintptr, radius float32) -var getRayCollisionBox func(rayCollision uintptr, ray uintptr, box uintptr) -var getRayCollisionMesh func(rayCollision uintptr, ray uintptr, mesh uintptr, transform uintptr) -var getRayCollisionTriangle func(rayCollision uintptr, ray uintptr, p1 uintptr, p2 uintptr, p3 uintptr) -var getRayCollisionQuad func(rayCollision uintptr, ray uintptr, p1 uintptr, p2 uintptr, p3 uintptr, p4 uintptr) -var initAudioDevice func() -var closeAudioDevice func() -var isAudioDeviceReady func() bool -var setMasterVolume func(volume float32) -var getMasterVolume func() float32 -var loadWave func(wave uintptr, fileName string) -var loadWaveFromMemory func(wave uintptr, fileType string, fileData []byte, dataSize int32) -var isWaveValid func(wave uintptr) bool -var loadSound func(sound uintptr, fileName string) -var loadSoundFromWave func(sound uintptr, wave uintptr) -var loadSoundAlias func(sound uintptr, source uintptr) -var isSoundValid func(sound uintptr) bool -var updateSound func(sound uintptr, data []byte, sampleCount int32) -var unloadWave func(wave uintptr) -var unloadSound func(sound uintptr) -var unloadSoundAlias func(alias uintptr) -var exportWave func(wave uintptr, fileName string) bool -var playSound func(sound uintptr) -var stopSound func(sound uintptr) -var pauseSound func(sound uintptr) -var resumeSound func(sound uintptr) -var isSoundPlaying func(sound uintptr) bool -var setSoundVolume func(sound uintptr, volume float32) -var setSoundPitch func(sound uintptr, pitch float32) -var setSoundPan func(sound uintptr, pan float32) -var waveCopy func(copy uintptr, wave uintptr) -var waveCrop func(wave *Wave, initFrame int32, finalFrame int32) -var waveFormat func(wave *Wave, sampleRate int32, sampleSize int32, channels int32) -var loadWaveSamples func(wave uintptr) *float32 -var unloadWaveSamples func(samples []float32) -var loadMusicStream func(music uintptr, fileName string) -var loadMusicStreamFromMemory func(sound uintptr, fileType string, data []byte, dataSize int32) -var isMusicValid func(music uintptr) bool -var unloadMusicStream func(music uintptr) -var playMusicStream func(music uintptr) -var isMusicStreamPlaying func(music uintptr) bool -var updateMusicStream func(music uintptr) -var stopMusicStream func(music uintptr) -var pauseMusicStream func(music uintptr) -var resumeMusicStream func(music uintptr) -var seekMusicStream func(music uintptr, position float32) -var setMusicVolume func(music uintptr, volume float32) -var setMusicPitch func(music uintptr, pitch float32) -var setMusicPan func(music uintptr, pan float32) -var getMusicTimeLength func(music uintptr) float32 -var getMusicTimePlayed func(music uintptr) float32 -var loadAudioStream func(audioStream uintptr, sampleRate uint32, sampleSize uint32, channels uint32) -var isAudioStreamValid func(stream uintptr) bool -var unloadAudioStream func(stream uintptr) -var updateAudioStream func(stream uintptr, data []float32, frameCount int32) -var isAudioStreamProcessed func(stream uintptr) bool -var playAudioStream func(stream uintptr) -var pauseAudioStream func(stream uintptr) -var resumeAudioStream func(stream uintptr) -var isAudioStreamPlaying func(stream uintptr) bool -var stopAudioStream func(stream uintptr) -var setAudioStreamVolume func(stream uintptr, volume float32) -var setAudioStreamPitch func(stream uintptr, pitch float32) -var setAudioStreamPan func(stream uintptr, pan float32) -var setAudioStreamBufferSizeDefault func(size int32) -var setAudioStreamCallback func(stream uintptr, callback uintptr) -var attachAudioStreamProcessor func(stream uintptr, processor uintptr) -var detachAudioStreamProcessor func(stream uintptr, processor uintptr) -var attachAudioMixedProcessor func(processor uintptr) -var detachAudioMixedProcessor func(processor uintptr) - -func init() { - raylibDll = loadLibrary() - audioCallbacks = make(map[uintptr]uintptr) - - initRlglPurego() - - purego.RegisterLibFunc(&initWindow, raylibDll, "InitWindow") - purego.RegisterLibFunc(&closeWindow, raylibDll, "CloseWindow") - purego.RegisterLibFunc(&windowShouldClose, raylibDll, "WindowShouldClose") - purego.RegisterLibFunc(&isWindowReady, raylibDll, "IsWindowReady") - purego.RegisterLibFunc(&isWindowFullscreen, raylibDll, "IsWindowFullscreen") - purego.RegisterLibFunc(&isWindowHidden, raylibDll, "IsWindowHidden") - purego.RegisterLibFunc(&isWindowMinimized, raylibDll, "IsWindowMinimized") - purego.RegisterLibFunc(&isWindowMaximized, raylibDll, "IsWindowMaximized") - purego.RegisterLibFunc(&isWindowFocused, raylibDll, "IsWindowFocused") - purego.RegisterLibFunc(&isWindowResized, raylibDll, "IsWindowResized") - purego.RegisterLibFunc(&isWindowState, raylibDll, "IsWindowState") - purego.RegisterLibFunc(&setWindowState, raylibDll, "SetWindowState") - purego.RegisterLibFunc(&clearWindowState, raylibDll, "ClearWindowState") - purego.RegisterLibFunc(&toggleFullscreen, raylibDll, "ToggleFullscreen") - purego.RegisterLibFunc(&toggleBorderlessWindowed, raylibDll, "ToggleBorderlessWindowed") - purego.RegisterLibFunc(&maximizeWindow, raylibDll, "MaximizeWindow") - purego.RegisterLibFunc(&minimizeWindow, raylibDll, "MinimizeWindow") - purego.RegisterLibFunc(&restoreWindow, raylibDll, "RestoreWindow") - purego.RegisterLibFunc(&setWindowIcon, raylibDll, "SetWindowIcon") - purego.RegisterLibFunc(&setWindowIcons, raylibDll, "SetWindowIcons") - purego.RegisterLibFunc(&setWindowTitle, raylibDll, "SetWindowTitle") - purego.RegisterLibFunc(&setWindowPosition, raylibDll, "SetWindowPosition") - purego.RegisterLibFunc(&setWindowMonitor, raylibDll, "SetWindowMonitor") - purego.RegisterLibFunc(&setWindowMinSize, raylibDll, "SetWindowMinSize") - purego.RegisterLibFunc(&setWindowMaxSize, raylibDll, "SetWindowMaxSize") - purego.RegisterLibFunc(&setWindowSize, raylibDll, "SetWindowSize") - purego.RegisterLibFunc(&setWindowOpacity, raylibDll, "SetWindowOpacity") - purego.RegisterLibFunc(&setWindowFocused, raylibDll, "SetWindowFocused") - purego.RegisterLibFunc(&getWindowHandle, raylibDll, "GetWindowHandle") - purego.RegisterLibFunc(&getScreenWidth, raylibDll, "GetScreenWidth") - purego.RegisterLibFunc(&getScreenHeight, raylibDll, "GetScreenHeight") - purego.RegisterLibFunc(&getRenderWidth, raylibDll, "GetRenderWidth") - purego.RegisterLibFunc(&getRenderHeight, raylibDll, "GetRenderHeight") - purego.RegisterLibFunc(&getMonitorCount, raylibDll, "GetMonitorCount") - purego.RegisterLibFunc(&getCurrentMonitor, raylibDll, "GetCurrentMonitor") - purego.RegisterLibFunc(&getMonitorPosition, raylibDll, "GetMonitorPosition") - purego.RegisterLibFunc(&getMonitorWidth, raylibDll, "GetMonitorWidth") - purego.RegisterLibFunc(&getMonitorHeight, raylibDll, "GetMonitorHeight") - purego.RegisterLibFunc(&getMonitorPhysicalWidth, raylibDll, "GetMonitorPhysicalWidth") - purego.RegisterLibFunc(&getMonitorPhysicalHeight, raylibDll, "GetMonitorPhysicalHeight") - purego.RegisterLibFunc(&getMonitorRefreshRate, raylibDll, "GetMonitorRefreshRate") - purego.RegisterLibFunc(&getWindowPosition, raylibDll, "GetWindowPosition") - purego.RegisterLibFunc(&getWindowScaleDPI, raylibDll, "GetWindowScaleDPI") - purego.RegisterLibFunc(&getMonitorName, raylibDll, "GetMonitorName") - purego.RegisterLibFunc(&setClipboardText, raylibDll, "SetClipboardText") - purego.RegisterLibFunc(&getClipboardText, raylibDll, "GetClipboardText") - purego.RegisterLibFunc(&getClipboardImage, raylibDll, "GetClipboardImage") - purego.RegisterLibFunc(&enableEventWaiting, raylibDll, "EnableEventWaiting") - purego.RegisterLibFunc(&disableEventWaiting, raylibDll, "DisableEventWaiting") - purego.RegisterLibFunc(&showCursor, raylibDll, "ShowCursor") - purego.RegisterLibFunc(&hideCursor, raylibDll, "HideCursor") - purego.RegisterLibFunc(&isCursorHidden, raylibDll, "IsCursorHidden") - purego.RegisterLibFunc(&enableCursor, raylibDll, "EnableCursor") - purego.RegisterLibFunc(&disableCursor, raylibDll, "DisableCursor") - purego.RegisterLibFunc(&isCursorOnScreen, raylibDll, "IsCursorOnScreen") - purego.RegisterLibFunc(&clearBackground, raylibDll, "ClearBackground") - purego.RegisterLibFunc(&beginDrawing, raylibDll, "BeginDrawing") - purego.RegisterLibFunc(&endDrawing, raylibDll, "EndDrawing") - purego.RegisterLibFunc(&beginMode2D, raylibDll, "BeginMode2D") - purego.RegisterLibFunc(&endMode2D, raylibDll, "EndMode2D") - purego.RegisterLibFunc(&beginMode3D, raylibDll, "BeginMode3D") - purego.RegisterLibFunc(&endMode3D, raylibDll, "EndMode3D") - purego.RegisterLibFunc(&beginTextureMode, raylibDll, "BeginTextureMode") - purego.RegisterLibFunc(&endTextureMode, raylibDll, "EndTextureMode") - purego.RegisterLibFunc(&beginShaderMode, raylibDll, "BeginShaderMode") - purego.RegisterLibFunc(&endShaderMode, raylibDll, "EndShaderMode") - purego.RegisterLibFunc(&beginBlendMode, raylibDll, "BeginBlendMode") - purego.RegisterLibFunc(&endBlendMode, raylibDll, "EndBlendMode") - purego.RegisterLibFunc(&beginScissorMode, raylibDll, "BeginScissorMode") - purego.RegisterLibFunc(&endScissorMode, raylibDll, "EndScissorMode") - purego.RegisterLibFunc(&beginVrStereoMode, raylibDll, "BeginVrStereoMode") - purego.RegisterLibFunc(&endVrStereoMode, raylibDll, "EndVrStereoMode") - purego.RegisterLibFunc(&loadVrStereoConfig, raylibDll, "LoadVrStereoConfig") - purego.RegisterLibFunc(&unloadVrStereoConfig, raylibDll, "UnloadVrStereoConfig") - purego.RegisterLibFunc(&loadShader, raylibDll, "LoadShader") - purego.RegisterLibFunc(&loadShaderFromMemory, raylibDll, "LoadShaderFromMemory") - purego.RegisterLibFunc(&isShaderValid, raylibDll, "IsShaderValid") - purego.RegisterLibFunc(&getShaderLocation, raylibDll, "GetShaderLocation") - purego.RegisterLibFunc(&getShaderLocationAttrib, raylibDll, "GetShaderLocationAttrib") - purego.RegisterLibFunc(&setShaderValue, raylibDll, "SetShaderValue") - purego.RegisterLibFunc(&setShaderValueV, raylibDll, "SetShaderValueV") - purego.RegisterLibFunc(&setShaderValueMatrix, raylibDll, "SetShaderValueMatrix") - purego.RegisterLibFunc(&setShaderValueTexture, raylibDll, "SetShaderValueTexture") - purego.RegisterLibFunc(&unloadShader, raylibDll, "UnloadShader") - purego.RegisterLibFunc(&getScreenToWorldRay, raylibDll, "GetScreenToWorldRay") - purego.RegisterLibFunc(&getScreenToWorldRayEx, raylibDll, "GetScreenToWorldRayEx") - purego.RegisterLibFunc(&getCameraMatrix, raylibDll, "GetCameraMatrix") - purego.RegisterLibFunc(&getCameraMatrix2D, raylibDll, "GetCameraMatrix2D") - purego.RegisterLibFunc(&getWorldToScreen, raylibDll, "GetWorldToScreen") - purego.RegisterLibFunc(&getScreenToWorld2D, raylibDll, "GetScreenToWorld2D") - purego.RegisterLibFunc(&getWorldToScreenEx, raylibDll, "GetWorldToScreenEx") - purego.RegisterLibFunc(&getWorldToScreen2D, raylibDll, "GetWorldToScreen2D") - purego.RegisterLibFunc(&setTargetFPS, raylibDll, "SetTargetFPS") - purego.RegisterLibFunc(&getFrameTime, raylibDll, "GetFrameTime") - purego.RegisterLibFunc(&getTime, raylibDll, "GetTime") - purego.RegisterLibFunc(&getFPS, raylibDll, "GetFPS") - purego.RegisterLibFunc(&swapScreenBuffer, raylibDll, "SwapScreenBuffer") - purego.RegisterLibFunc(&pollInputEvents, raylibDll, "PollInputEvents") - purego.RegisterLibFunc(&waitTime, raylibDll, "WaitTime") - purego.RegisterLibFunc(&setRandomSeed, raylibDll, "SetRandomSeed") - purego.RegisterLibFunc(&getRandomValue, raylibDll, "GetRandomValue") - purego.RegisterLibFunc(&loadRandomSequence, raylibDll, "LoadRandomSequence") - purego.RegisterLibFunc(&unloadRandomSequence, raylibDll, "UnloadRandomSequence") - purego.RegisterLibFunc(&takeScreenshot, raylibDll, "TakeScreenshot") - purego.RegisterLibFunc(&setConfigFlags, raylibDll, "SetConfigFlags") - purego.RegisterLibFunc(&openURL, raylibDll, "OpenURL") - purego.RegisterLibFunc(&traceLog, raylibDll, "TraceLog") - purego.RegisterLibFunc(&setTraceLogLevel, raylibDll, "SetTraceLogLevel") - purego.RegisterLibFunc(&memAlloc, raylibDll, "MemAlloc") - purego.RegisterLibFunc(&memRealloc, raylibDll, "MemRealloc") - purego.RegisterLibFunc(&memFree, raylibDll, "MemFree") - purego.RegisterLibFunc(&setTraceLogCallback, raylibDll, "SetTraceLogCallback") - purego.RegisterLibFunc(&isFileDropped, raylibDll, "IsFileDropped") - purego.RegisterLibFunc(&loadDroppedFiles, raylibDll, "LoadDroppedFiles") - purego.RegisterLibFunc(&unloadDroppedFiles, raylibDll, "UnloadDroppedFiles") - purego.RegisterLibFunc(&loadAutomationEventList, raylibDll, "LoadAutomationEventList") - purego.RegisterLibFunc(&unloadAutomationEventList, raylibDll, "UnloadAutomationEventList") - purego.RegisterLibFunc(&exportAutomationEventList, raylibDll, "ExportAutomationEventList") - purego.RegisterLibFunc(&setAutomationEventList, raylibDll, "SetAutomationEventList") - purego.RegisterLibFunc(&setAutomationEventBaseFrame, raylibDll, "SetAutomationEventBaseFrame") - purego.RegisterLibFunc(&startAutomationEventRecording, raylibDll, "StartAutomationEventRecording") - purego.RegisterLibFunc(&stopAutomationEventRecording, raylibDll, "StopAutomationEventRecording") - purego.RegisterLibFunc(&playAutomationEvent, raylibDll, "PlayAutomationEvent") - purego.RegisterLibFunc(&isKeyPressed, raylibDll, "IsKeyPressed") - purego.RegisterLibFunc(&isKeyPressedRepeat, raylibDll, "IsKeyPressedRepeat") - purego.RegisterLibFunc(&isKeyDown, raylibDll, "IsKeyDown") - purego.RegisterLibFunc(&isKeyReleased, raylibDll, "IsKeyReleased") - purego.RegisterLibFunc(&isKeyUp, raylibDll, "IsKeyUp") - purego.RegisterLibFunc(&getKeyPressed, raylibDll, "GetKeyPressed") - purego.RegisterLibFunc(&getCharPressed, raylibDll, "GetCharPressed") - purego.RegisterLibFunc(&setExitKey, raylibDll, "SetExitKey") - purego.RegisterLibFunc(&isGamepadAvailable, raylibDll, "IsGamepadAvailable") - purego.RegisterLibFunc(&getGamepadName, raylibDll, "GetGamepadName") - purego.RegisterLibFunc(&isGamepadButtonPressed, raylibDll, "IsGamepadButtonPressed") - purego.RegisterLibFunc(&isGamepadButtonDown, raylibDll, "IsGamepadButtonDown") - purego.RegisterLibFunc(&isGamepadButtonReleased, raylibDll, "IsGamepadButtonReleased") - purego.RegisterLibFunc(&isGamepadButtonUp, raylibDll, "IsGamepadButtonUp") - purego.RegisterLibFunc(&getGamepadButtonPressed, raylibDll, "GetGamepadButtonPressed") - purego.RegisterLibFunc(&getGamepadAxisCount, raylibDll, "GetGamepadAxisCount") - purego.RegisterLibFunc(&getGamepadAxisMovement, raylibDll, "GetGamepadAxisMovement") - purego.RegisterLibFunc(&setGamepadMappings, raylibDll, "SetGamepadMappings") - purego.RegisterLibFunc(&setGamepadVibration, raylibDll, "SetGamepadVibration") - purego.RegisterLibFunc(&isMouseButtonPressed, raylibDll, "IsMouseButtonPressed") - purego.RegisterLibFunc(&isMouseButtonDown, raylibDll, "IsMouseButtonDown") - purego.RegisterLibFunc(&isMouseButtonReleased, raylibDll, "IsMouseButtonReleased") - purego.RegisterLibFunc(&isMouseButtonUp, raylibDll, "IsMouseButtonUp") - purego.RegisterLibFunc(&getMouseX, raylibDll, "GetMouseX") - purego.RegisterLibFunc(&getMouseY, raylibDll, "GetMouseY") - purego.RegisterLibFunc(&getMousePosition, raylibDll, "GetMousePosition") - purego.RegisterLibFunc(&getMouseDelta, raylibDll, "GetMouseDelta") - purego.RegisterLibFunc(&setMousePosition, raylibDll, "SetMousePosition") - purego.RegisterLibFunc(&setMouseOffset, raylibDll, "SetMouseOffset") - purego.RegisterLibFunc(&setMouseScale, raylibDll, "SetMouseScale") - purego.RegisterLibFunc(&getMouseWheelMove, raylibDll, "GetMouseWheelMove") - purego.RegisterLibFunc(&getMouseWheelMoveV, raylibDll, "GetMouseWheelMoveV") - purego.RegisterLibFunc(&setMouseCursor, raylibDll, "SetMouseCursor") - purego.RegisterLibFunc(&getTouchX, raylibDll, "GetTouchX") - purego.RegisterLibFunc(&getTouchY, raylibDll, "GetTouchY") - purego.RegisterLibFunc(&getTouchPosition, raylibDll, "GetTouchPosition") - purego.RegisterLibFunc(&getTouchPointId, raylibDll, "GetTouchPointId") - purego.RegisterLibFunc(&getTouchPointCount, raylibDll, "GetTouchPointCount") - purego.RegisterLibFunc(&setGesturesEnabled, raylibDll, "SetGesturesEnabled") - purego.RegisterLibFunc(&isGestureDetected, raylibDll, "IsGestureDetected") - purego.RegisterLibFunc(&getGestureDetected, raylibDll, "GetGestureDetected") - purego.RegisterLibFunc(&getGestureHoldDuration, raylibDll, "GetGestureHoldDuration") - purego.RegisterLibFunc(&getGestureDragVector, raylibDll, "GetGestureDragVector") - purego.RegisterLibFunc(&getGestureDragAngle, raylibDll, "GetGestureDragAngle") - purego.RegisterLibFunc(&getGesturePinchVector, raylibDll, "GetGesturePinchVector") - purego.RegisterLibFunc(&getGesturePinchAngle, raylibDll, "GetGesturePinchAngle") - purego.RegisterLibFunc(&setShapesTexture, raylibDll, "SetShapesTexture") - purego.RegisterLibFunc(&getShapesTexture, raylibDll, "GetShapesTexture") - purego.RegisterLibFunc(&getShapesTextureRectangle, raylibDll, "GetShapesTextureRectangle") - purego.RegisterLibFunc(&drawPixel, raylibDll, "DrawPixel") - purego.RegisterLibFunc(&drawPixelV, raylibDll, "DrawPixelV") - purego.RegisterLibFunc(&drawLine, raylibDll, "DrawLine") - purego.RegisterLibFunc(&drawLineV, raylibDll, "DrawLineV") - purego.RegisterLibFunc(&drawLineEx, raylibDll, "DrawLineEx") - purego.RegisterLibFunc(&drawLineStrip, raylibDll, "DrawLineStrip") - purego.RegisterLibFunc(&drawLineBezier, raylibDll, "DrawLineBezier") - purego.RegisterLibFunc(&drawCircle, raylibDll, "DrawCircle") - purego.RegisterLibFunc(&drawCircleSector, raylibDll, "DrawCircleSector") - purego.RegisterLibFunc(&drawCircleSectorLines, raylibDll, "DrawCircleSectorLines") - purego.RegisterLibFunc(&drawCircleGradient, raylibDll, "DrawCircleGradient") - purego.RegisterLibFunc(&drawCircleV, raylibDll, "DrawCircleV") - purego.RegisterLibFunc(&drawCircleLines, raylibDll, "DrawCircleLines") - purego.RegisterLibFunc(&drawCircleLinesV, raylibDll, "DrawCircleLinesV") - purego.RegisterLibFunc(&drawEllipse, raylibDll, "DrawEllipse") - purego.RegisterLibFunc(&drawEllipseLines, raylibDll, "DrawEllipseLines") - purego.RegisterLibFunc(&drawRing, raylibDll, "DrawRing") - purego.RegisterLibFunc(&drawRingLines, raylibDll, "DrawRingLines") - purego.RegisterLibFunc(&drawRectangle, raylibDll, "DrawRectangle") - purego.RegisterLibFunc(&drawRectangleV, raylibDll, "DrawRectangleV") - purego.RegisterLibFunc(&drawRectangleRec, raylibDll, "DrawRectangleRec") - purego.RegisterLibFunc(&drawRectanglePro, raylibDll, "DrawRectanglePro") - purego.RegisterLibFunc(&drawRectangleGradientV, raylibDll, "DrawRectangleGradientV") - purego.RegisterLibFunc(&drawRectangleGradientH, raylibDll, "DrawRectangleGradientH") - purego.RegisterLibFunc(&drawRectangleGradientEx, raylibDll, "DrawRectangleGradientEx") - purego.RegisterLibFunc(&drawRectangleLines, raylibDll, "DrawRectangleLines") - purego.RegisterLibFunc(&drawRectangleLinesEx, raylibDll, "DrawRectangleLinesEx") - purego.RegisterLibFunc(&drawRectangleRounded, raylibDll, "DrawRectangleRounded") - purego.RegisterLibFunc(&drawRectangleRoundedLines, raylibDll, "DrawRectangleRoundedLines") - purego.RegisterLibFunc(&drawRectangleRoundedLinesEx, raylibDll, "DrawRectangleRoundedLinesEx") - purego.RegisterLibFunc(&drawTriangle, raylibDll, "DrawTriangle") - purego.RegisterLibFunc(&drawTriangleLines, raylibDll, "DrawTriangleLines") - purego.RegisterLibFunc(&drawTriangleFan, raylibDll, "DrawTriangleFan") - purego.RegisterLibFunc(&drawTriangleStrip, raylibDll, "DrawTriangleStrip") - purego.RegisterLibFunc(&drawPoly, raylibDll, "DrawPoly") - purego.RegisterLibFunc(&drawPolyLines, raylibDll, "DrawPolyLines") - purego.RegisterLibFunc(&drawPolyLinesEx, raylibDll, "DrawPolyLinesEx") - purego.RegisterLibFunc(&drawSplineLinear, raylibDll, "DrawSplineLinear") - purego.RegisterLibFunc(&drawSplineBasis, raylibDll, "DrawSplineBasis") - purego.RegisterLibFunc(&drawSplineCatmullRom, raylibDll, "DrawSplineCatmullRom") - purego.RegisterLibFunc(&drawSplineBezierQuadratic, raylibDll, "DrawSplineBezierQuadratic") - purego.RegisterLibFunc(&drawSplineBezierCubic, raylibDll, "DrawSplineBezierCubic") - purego.RegisterLibFunc(&drawSplineSegmentLinear, raylibDll, "DrawSplineSegmentLinear") - purego.RegisterLibFunc(&drawSplineSegmentBasis, raylibDll, "DrawSplineSegmentBasis") - purego.RegisterLibFunc(&drawSplineSegmentCatmullRom, raylibDll, "DrawSplineSegmentCatmullRom") - purego.RegisterLibFunc(&drawSplineSegmentBezierQuadratic, raylibDll, "DrawSplineSegmentBezierQuadratic") - purego.RegisterLibFunc(&drawSplineSegmentBezierCubic, raylibDll, "DrawSplineSegmentBezierCubic") - purego.RegisterLibFunc(&getSplinePointLinear, raylibDll, "GetSplinePointLinear") - purego.RegisterLibFunc(&getSplinePointBasis, raylibDll, "GetSplinePointBasis") - purego.RegisterLibFunc(&getSplinePointCatmullRom, raylibDll, "GetSplinePointCatmullRom") - purego.RegisterLibFunc(&getSplinePointBezierQuad, raylibDll, "GetSplinePointBezierQuad") - purego.RegisterLibFunc(&getSplinePointBezierCubic, raylibDll, "GetSplinePointBezierCubic") - purego.RegisterLibFunc(&checkCollisionRecs, raylibDll, "CheckCollisionRecs") - purego.RegisterLibFunc(&checkCollisionCircles, raylibDll, "CheckCollisionCircles") - purego.RegisterLibFunc(&checkCollisionCircleRec, raylibDll, "CheckCollisionCircleRec") - purego.RegisterLibFunc(&checkCollisionCircleLine, raylibDll, "CheckCollisionCircleLine") - purego.RegisterLibFunc(&checkCollisionPointRec, raylibDll, "CheckCollisionPointRec") - purego.RegisterLibFunc(&checkCollisionPointCircle, raylibDll, "CheckCollisionPointCircle") - purego.RegisterLibFunc(&checkCollisionPointTriangle, raylibDll, "CheckCollisionPointTriangle") - purego.RegisterLibFunc(&checkCollisionPointPoly, raylibDll, "CheckCollisionPointPoly") - purego.RegisterLibFunc(&checkCollisionLines, raylibDll, "CheckCollisionLines") - purego.RegisterLibFunc(&checkCollisionPointLine, raylibDll, "CheckCollisionPointLine") - purego.RegisterLibFunc(&getCollisionRec, raylibDll, "GetCollisionRec") - purego.RegisterLibFunc(&loadImage, raylibDll, "LoadImage") - purego.RegisterLibFunc(&loadImageRaw, raylibDll, "LoadImageRaw") - purego.RegisterLibFunc(&loadImageAnim, raylibDll, "LoadImageAnim") - purego.RegisterLibFunc(&loadImageAnimFromMemory, raylibDll, "LoadImageAnimFromMemory") - purego.RegisterLibFunc(&loadImageFromMemory, raylibDll, "LoadImageFromMemory") - purego.RegisterLibFunc(&loadImageFromTexture, raylibDll, "LoadImageFromTexture") - purego.RegisterLibFunc(&loadImageFromScreen, raylibDll, "LoadImageFromScreen") - purego.RegisterLibFunc(&isImageValid, raylibDll, "IsImageValid") - purego.RegisterLibFunc(&unloadImage, raylibDll, "UnloadImage") - purego.RegisterLibFunc(&exportImage, raylibDll, "ExportImage") - purego.RegisterLibFunc(&exportImageToMemory, raylibDll, "ExportImageToMemory") - purego.RegisterLibFunc(&genImageColor, raylibDll, "GenImageColor") - purego.RegisterLibFunc(&genImageGradientLinear, raylibDll, "GenImageGradientLinear") - purego.RegisterLibFunc(&genImageGradientRadial, raylibDll, "GenImageGradientRadial") - purego.RegisterLibFunc(&genImageGradientSquare, raylibDll, "GenImageGradientSquare") - purego.RegisterLibFunc(&genImageChecked, raylibDll, "GenImageChecked") - purego.RegisterLibFunc(&genImageWhiteNoise, raylibDll, "GenImageWhiteNoise") - purego.RegisterLibFunc(&genImagePerlinNoise, raylibDll, "GenImagePerlinNoise") - purego.RegisterLibFunc(&genImageCellular, raylibDll, "GenImageCellular") - purego.RegisterLibFunc(&genImageText, raylibDll, "GenImageText") - purego.RegisterLibFunc(&imageCopy, raylibDll, "ImageCopy") - purego.RegisterLibFunc(&imageFromImage, raylibDll, "ImageFromImage") - purego.RegisterLibFunc(&imageFromChannel, raylibDll, "ImageFromChannel") - purego.RegisterLibFunc(&imageText, raylibDll, "ImageText") - purego.RegisterLibFunc(&imageTextEx, raylibDll, "ImageTextEx") - purego.RegisterLibFunc(&imageFormat, raylibDll, "ImageFormat") - purego.RegisterLibFunc(&imageToPOT, raylibDll, "ImageToPOT") - purego.RegisterLibFunc(&imageCrop, raylibDll, "ImageCrop") - purego.RegisterLibFunc(&imageAlphaCrop, raylibDll, "ImageAlphaCrop") - purego.RegisterLibFunc(&imageAlphaClear, raylibDll, "ImageAlphaClear") - purego.RegisterLibFunc(&imageAlphaMask, raylibDll, "ImageAlphaMask") - purego.RegisterLibFunc(&imageAlphaPremultiply, raylibDll, "ImageAlphaPremultiply") - purego.RegisterLibFunc(&imageBlurGaussian, raylibDll, "ImageBlurGaussian") - purego.RegisterLibFunc(&imageKernelConvolution, raylibDll, "ImageKernelConvolution") - purego.RegisterLibFunc(&imageResize, raylibDll, "ImageResize") - purego.RegisterLibFunc(&imageResizeNN, raylibDll, "ImageResizeNN") - purego.RegisterLibFunc(&imageResizeCanvas, raylibDll, "ImageResizeCanvas") - purego.RegisterLibFunc(&imageMipmaps, raylibDll, "ImageMipmaps") - purego.RegisterLibFunc(&imageDither, raylibDll, "ImageDither") - purego.RegisterLibFunc(&imageFlipVertical, raylibDll, "ImageFlipVertical") - purego.RegisterLibFunc(&imageFlipHorizontal, raylibDll, "ImageFlipHorizontal") - purego.RegisterLibFunc(&imageRotate, raylibDll, "ImageRotate") - purego.RegisterLibFunc(&imageRotateCW, raylibDll, "ImageRotateCW") - purego.RegisterLibFunc(&imageRotateCCW, raylibDll, "ImageRotateCCW") - purego.RegisterLibFunc(&imageColorTint, raylibDll, "ImageColorTint") - purego.RegisterLibFunc(&imageColorInvert, raylibDll, "ImageColorInvert") - purego.RegisterLibFunc(&imageColorGrayscale, raylibDll, "ImageColorGrayscale") - purego.RegisterLibFunc(&imageColorContrast, raylibDll, "ImageColorContrast") - purego.RegisterLibFunc(&imageColorBrightness, raylibDll, "ImageColorBrightness") - purego.RegisterLibFunc(&imageColorReplace, raylibDll, "ImageColorReplace") - purego.RegisterLibFunc(&loadImageColors, raylibDll, "LoadImageColors") - purego.RegisterLibFunc(&loadImagePalette, raylibDll, "LoadImagePalette") - purego.RegisterLibFunc(&unloadImageColors, raylibDll, "UnloadImageColors") - purego.RegisterLibFunc(&unloadImagePalette, raylibDll, "UnloadImagePalette") - purego.RegisterLibFunc(&getImageAlphaBorder, raylibDll, "GetImageAlphaBorder") - purego.RegisterLibFunc(&getImageColor, raylibDll, "GetImageColor") - purego.RegisterLibFunc(&imageClearBackground, raylibDll, "ImageClearBackground") - purego.RegisterLibFunc(&imageDrawPixel, raylibDll, "ImageDrawPixel") - purego.RegisterLibFunc(&imageDrawPixelV, raylibDll, "ImageDrawPixelV") - purego.RegisterLibFunc(&imageDrawLine, raylibDll, "ImageDrawLine") - purego.RegisterLibFunc(&imageDrawLineV, raylibDll, "ImageDrawLineV") - purego.RegisterLibFunc(&imageDrawLineEx, raylibDll, "ImageDrawLineEx") - purego.RegisterLibFunc(&imageDrawCircle, raylibDll, "ImageDrawCircle") - purego.RegisterLibFunc(&imageDrawCircleV, raylibDll, "ImageDrawCircleV") - purego.RegisterLibFunc(&imageDrawCircleLines, raylibDll, "ImageDrawCircleLines") - purego.RegisterLibFunc(&imageDrawCircleLinesV, raylibDll, "ImageDrawCircleLinesV") - purego.RegisterLibFunc(&imageDrawRectangle, raylibDll, "ImageDrawRectangle") - purego.RegisterLibFunc(&imageDrawRectangleV, raylibDll, "ImageDrawRectangleV") - purego.RegisterLibFunc(&imageDrawRectangleRec, raylibDll, "ImageDrawRectangleRec") - purego.RegisterLibFunc(&imageDrawRectangleLines, raylibDll, "ImageDrawRectangleLines") - purego.RegisterLibFunc(&imageDrawTriangle, raylibDll, "ImageDrawTriangle") - purego.RegisterLibFunc(&imageDrawTriangleEx, raylibDll, "ImageDrawTriangleEx") - purego.RegisterLibFunc(&imageDrawTriangleLines, raylibDll, "ImageDrawTriangleLines") - purego.RegisterLibFunc(&imageDrawTriangleFan, raylibDll, "ImageDrawTriangleFan") - purego.RegisterLibFunc(&imageDrawTriangleStrip, raylibDll, "ImageDrawTriangleStrip") - purego.RegisterLibFunc(&imageDraw, raylibDll, "ImageDraw") - purego.RegisterLibFunc(&imageDrawText, raylibDll, "ImageDrawText") - purego.RegisterLibFunc(&imageDrawTextEx, raylibDll, "ImageDrawTextEx") - purego.RegisterLibFunc(&loadTexture, raylibDll, "LoadTexture") - purego.RegisterLibFunc(&loadTextureFromImage, raylibDll, "LoadTextureFromImage") - purego.RegisterLibFunc(&loadTextureCubemap, raylibDll, "LoadTextureCubemap") - purego.RegisterLibFunc(&loadRenderTexture, raylibDll, "LoadRenderTexture") - purego.RegisterLibFunc(&isTextureValid, raylibDll, "IsTextureValid") - purego.RegisterLibFunc(&unloadTexture, raylibDll, "UnloadTexture") - purego.RegisterLibFunc(&isRenderTextureValid, raylibDll, "IsRenderTextureValid") - purego.RegisterLibFunc(&unloadRenderTexture, raylibDll, "UnloadRenderTexture") - purego.RegisterLibFunc(&updateTexture, raylibDll, "UpdateTexture") - purego.RegisterLibFunc(&updateTextureRec, raylibDll, "UpdateTextureRec") - purego.RegisterLibFunc(&genTextureMipmaps, raylibDll, "GenTextureMipmaps") - purego.RegisterLibFunc(&setTextureFilter, raylibDll, "SetTextureFilter") - purego.RegisterLibFunc(&setTextureWrap, raylibDll, "SetTextureWrap") - purego.RegisterLibFunc(&drawTexture, raylibDll, "DrawTexture") - purego.RegisterLibFunc(&drawTextureV, raylibDll, "DrawTextureV") - purego.RegisterLibFunc(&drawTextureEx, raylibDll, "DrawTextureEx") - purego.RegisterLibFunc(&drawTextureRec, raylibDll, "DrawTextureRec") - purego.RegisterLibFunc(&drawTexturePro, raylibDll, "DrawTexturePro") - purego.RegisterLibFunc(&drawTextureNPatch, raylibDll, "DrawTextureNPatch") - purego.RegisterLibFunc(&fade, raylibDll, "Fade") - purego.RegisterLibFunc(&colorToInt, raylibDll, "ColorToInt") - purego.RegisterLibFunc(&colorNormalize, raylibDll, "ColorNormalize") - purego.RegisterLibFunc(&colorFromNormalized, raylibDll, "ColorFromNormalized") - purego.RegisterLibFunc(&colorToHSV, raylibDll, "ColorToHSV") - purego.RegisterLibFunc(&colorFromHSV, raylibDll, "ColorFromHSV") - purego.RegisterLibFunc(&colorTint, raylibDll, "ColorTint") - purego.RegisterLibFunc(&colorBrightness, raylibDll, "ColorBrightness") - purego.RegisterLibFunc(&colorContrast, raylibDll, "ColorContrast") - purego.RegisterLibFunc(&colorAlpha, raylibDll, "ColorAlpha") - purego.RegisterLibFunc(&colorAlphaBlend, raylibDll, "ColorAlphaBlend") - purego.RegisterLibFunc(&colorLerp, raylibDll, "ColorLerp") - purego.RegisterLibFunc(&getColor, raylibDll, "GetColor") - purego.RegisterLibFunc(&getPixelColor, raylibDll, "GetPixelColor") - purego.RegisterLibFunc(&setPixelColor, raylibDll, "SetPixelColor") - purego.RegisterLibFunc(&getPixelDataSize, raylibDll, "GetPixelDataSize") - purego.RegisterLibFunc(&getFontDefault, raylibDll, "GetFontDefault") - purego.RegisterLibFunc(&loadFont, raylibDll, "LoadFont") - purego.RegisterLibFunc(&loadFontEx, raylibDll, "LoadFontEx") - purego.RegisterLibFunc(&loadFontFromImage, raylibDll, "LoadFontFromImage") - purego.RegisterLibFunc(&loadFontFromMemory, raylibDll, "LoadFontFromMemory") - purego.RegisterLibFunc(&isFontValid, raylibDll, "IsFontValid") - purego.RegisterLibFunc(&loadFontData, raylibDll, "LoadFontData") - purego.RegisterLibFunc(&genImageFontAtlas, raylibDll, "GenImageFontAtlas") - purego.RegisterLibFunc(&unloadFontData, raylibDll, "UnloadFontData") - purego.RegisterLibFunc(&unloadFont, raylibDll, "UnloadFont") - purego.RegisterLibFunc(&drawFPS, raylibDll, "DrawFPS") - purego.RegisterLibFunc(&drawText, raylibDll, "DrawText") - purego.RegisterLibFunc(&drawTextEx, raylibDll, "DrawTextEx") - purego.RegisterLibFunc(&drawTextPro, raylibDll, "DrawTextPro") - purego.RegisterLibFunc(&drawTextCodepoint, raylibDll, "DrawTextCodepoint") - purego.RegisterLibFunc(&drawTextCodepoints, raylibDll, "DrawTextCodepoints") - purego.RegisterLibFunc(&setTextLineSpacing, raylibDll, "SetTextLineSpacing") - purego.RegisterLibFunc(&measureText, raylibDll, "MeasureText") - purego.RegisterLibFunc(&measureTextEx, raylibDll, "MeasureTextEx") - purego.RegisterLibFunc(&getGlyphIndex, raylibDll, "GetGlyphIndex") - purego.RegisterLibFunc(&getGlyphInfo, raylibDll, "GetGlyphInfo") - purego.RegisterLibFunc(&getGlyphAtlasRec, raylibDll, "GetGlyphAtlasRec") - purego.RegisterLibFunc(&drawLine3D, raylibDll, "DrawLine3D") - purego.RegisterLibFunc(&drawPoint3D, raylibDll, "DrawPoint3D") - purego.RegisterLibFunc(&drawCircle3D, raylibDll, "DrawCircle3D") - purego.RegisterLibFunc(&drawTriangle3D, raylibDll, "DrawTriangle3D") - purego.RegisterLibFunc(&drawTriangleStrip3D, raylibDll, "DrawTriangleStrip3D") - purego.RegisterLibFunc(&drawCube, raylibDll, "DrawCube") - purego.RegisterLibFunc(&drawCubeV, raylibDll, "DrawCubeV") - purego.RegisterLibFunc(&drawCubeWires, raylibDll, "DrawCubeWires") - purego.RegisterLibFunc(&drawCubeWiresV, raylibDll, "DrawCubeWiresV") - purego.RegisterLibFunc(&drawSphere, raylibDll, "DrawSphere") - purego.RegisterLibFunc(&drawSphereEx, raylibDll, "DrawSphereEx") - purego.RegisterLibFunc(&drawSphereWires, raylibDll, "DrawSphereWires") - purego.RegisterLibFunc(&drawCylinder, raylibDll, "DrawCylinder") - purego.RegisterLibFunc(&drawCylinderEx, raylibDll, "DrawCylinderEx") - purego.RegisterLibFunc(&drawCylinderWires, raylibDll, "DrawCylinderWires") - purego.RegisterLibFunc(&drawCylinderWiresEx, raylibDll, "DrawCylinderWiresEx") - purego.RegisterLibFunc(&drawCapsule, raylibDll, "DrawCapsule") - purego.RegisterLibFunc(&drawCapsuleWires, raylibDll, "DrawCapsuleWires") - purego.RegisterLibFunc(&drawPlane, raylibDll, "DrawPlane") - purego.RegisterLibFunc(&drawRay, raylibDll, "DrawRay") - purego.RegisterLibFunc(&drawGrid, raylibDll, "DrawGrid") - purego.RegisterLibFunc(&loadModel, raylibDll, "LoadModel") - purego.RegisterLibFunc(&loadModelFromMesh, raylibDll, "LoadModelFromMesh") - purego.RegisterLibFunc(&isModelValid, raylibDll, "IsModelValid") - purego.RegisterLibFunc(&unloadModel, raylibDll, "UnloadModel") - purego.RegisterLibFunc(&getModelBoundingBox, raylibDll, "GetModelBoundingBox") - purego.RegisterLibFunc(&drawModel, raylibDll, "DrawModel") - purego.RegisterLibFunc(&drawModelEx, raylibDll, "DrawModelEx") - purego.RegisterLibFunc(&drawModelWires, raylibDll, "DrawModelWires") - purego.RegisterLibFunc(&drawModelWiresEx, raylibDll, "DrawModelWiresEx") - purego.RegisterLibFunc(&drawModelPoints, raylibDll, "DrawModelPoints") - purego.RegisterLibFunc(&drawModelPointsEx, raylibDll, "DrawModelPointsEx") - purego.RegisterLibFunc(&drawBoundingBox, raylibDll, "DrawBoundingBox") - purego.RegisterLibFunc(&drawBillboard, raylibDll, "DrawBillboard") - purego.RegisterLibFunc(&drawBillboardRec, raylibDll, "DrawBillboardRec") - purego.RegisterLibFunc(&drawBillboardPro, raylibDll, "DrawBillboardPro") - purego.RegisterLibFunc(&uploadMesh, raylibDll, "UploadMesh") - purego.RegisterLibFunc(&updateMeshBuffer, raylibDll, "UpdateMeshBuffer") - purego.RegisterLibFunc(&unloadMesh, raylibDll, "UnloadMesh") - purego.RegisterLibFunc(&drawMesh, raylibDll, "DrawMesh") - purego.RegisterLibFunc(&drawMeshInstanced, raylibDll, "DrawMeshInstanced") - purego.RegisterLibFunc(&exportMesh, raylibDll, "ExportMesh") - purego.RegisterLibFunc(&getMeshBoundingBox, raylibDll, "GetMeshBoundingBox") - purego.RegisterLibFunc(&genMeshTangents, raylibDll, "GenMeshTangents") - purego.RegisterLibFunc(&genMeshPoly, raylibDll, "GenMeshPoly") - purego.RegisterLibFunc(&genMeshPlane, raylibDll, "GenMeshPlane") - purego.RegisterLibFunc(&genMeshCube, raylibDll, "GenMeshCube") - purego.RegisterLibFunc(&genMeshSphere, raylibDll, "GenMeshSphere") - purego.RegisterLibFunc(&genMeshHemiSphere, raylibDll, "GenMeshHemiSphere") - purego.RegisterLibFunc(&genMeshCylinder, raylibDll, "GenMeshCylinder") - purego.RegisterLibFunc(&genMeshCone, raylibDll, "GenMeshCone") - purego.RegisterLibFunc(&genMeshTorus, raylibDll, "GenMeshTorus") - purego.RegisterLibFunc(&genMeshKnot, raylibDll, "GenMeshKnot") - purego.RegisterLibFunc(&genMeshHeightmap, raylibDll, "GenMeshHeightmap") - purego.RegisterLibFunc(&genMeshCubicmap, raylibDll, "GenMeshCubicmap") - purego.RegisterLibFunc(&loadMaterials, raylibDll, "LoadMaterials") - purego.RegisterLibFunc(&loadMaterialDefault, raylibDll, "LoadMaterialDefault") - purego.RegisterLibFunc(&isMaterialValid, raylibDll, "IsMaterialValid") - purego.RegisterLibFunc(&unloadMaterial, raylibDll, "UnloadMaterial") - purego.RegisterLibFunc(&setMaterialTexture, raylibDll, "SetMaterialTexture") - purego.RegisterLibFunc(&setModelMeshMaterial, raylibDll, "SetModelMeshMaterial") - purego.RegisterLibFunc(&loadModelAnimations, raylibDll, "LoadModelAnimations") - purego.RegisterLibFunc(&updateModelAnimation, raylibDll, "UpdateModelAnimation") - purego.RegisterLibFunc(&updateModelAnimationBones, raylibDll, "UpdateModelAnimationBones") - purego.RegisterLibFunc(&unloadModelAnimation, raylibDll, "UnloadModelAnimation") - purego.RegisterLibFunc(&unloadModelAnimations, raylibDll, "UnloadModelAnimations") - purego.RegisterLibFunc(&isModelAnimationValid, raylibDll, "IsModelAnimationValid") - purego.RegisterLibFunc(&checkCollisionSpheres, raylibDll, "CheckCollisionSpheres") - purego.RegisterLibFunc(&checkCollisionBoxes, raylibDll, "CheckCollisionBoxes") - purego.RegisterLibFunc(&checkCollisionBoxSphere, raylibDll, "CheckCollisionBoxSphere") - purego.RegisterLibFunc(&getRayCollisionSphere, raylibDll, "GetRayCollisionSphere") - purego.RegisterLibFunc(&getRayCollisionBox, raylibDll, "GetRayCollisionBox") - purego.RegisterLibFunc(&getRayCollisionMesh, raylibDll, "GetRayCollisionMesh") - purego.RegisterLibFunc(&getRayCollisionTriangle, raylibDll, "GetRayCollisionTriangle") - purego.RegisterLibFunc(&getRayCollisionQuad, raylibDll, "GetRayCollisionQuad") - purego.RegisterLibFunc(&initAudioDevice, raylibDll, "InitAudioDevice") - purego.RegisterLibFunc(&closeAudioDevice, raylibDll, "CloseAudioDevice") - purego.RegisterLibFunc(&isAudioDeviceReady, raylibDll, "IsAudioDeviceReady") - purego.RegisterLibFunc(&setMasterVolume, raylibDll, "SetMasterVolume") - purego.RegisterLibFunc(&getMasterVolume, raylibDll, "GetMasterVolume") - purego.RegisterLibFunc(&loadWave, raylibDll, "LoadWave") - purego.RegisterLibFunc(&loadWaveFromMemory, raylibDll, "LoadWaveFromMemory") - purego.RegisterLibFunc(&isWaveValid, raylibDll, "IsWaveValid") - purego.RegisterLibFunc(&loadSound, raylibDll, "LoadSound") - purego.RegisterLibFunc(&loadSoundFromWave, raylibDll, "LoadSoundFromWave") - purego.RegisterLibFunc(&loadSoundAlias, raylibDll, "LoadSoundAlias") - purego.RegisterLibFunc(&isSoundValid, raylibDll, "IsSoundValid") - purego.RegisterLibFunc(&updateSound, raylibDll, "UpdateSound") - purego.RegisterLibFunc(&unloadWave, raylibDll, "UnloadWave") - purego.RegisterLibFunc(&unloadSound, raylibDll, "UnloadSound") - purego.RegisterLibFunc(&unloadSoundAlias, raylibDll, "UnloadSoundAlias") - purego.RegisterLibFunc(&exportWave, raylibDll, "ExportWave") - purego.RegisterLibFunc(&playSound, raylibDll, "PlaySound") - purego.RegisterLibFunc(&stopSound, raylibDll, "StopSound") - purego.RegisterLibFunc(&pauseSound, raylibDll, "PauseSound") - purego.RegisterLibFunc(&resumeSound, raylibDll, "ResumeSound") - purego.RegisterLibFunc(&isSoundPlaying, raylibDll, "IsSoundPlaying") - purego.RegisterLibFunc(&setSoundVolume, raylibDll, "SetSoundVolume") - purego.RegisterLibFunc(&setSoundPitch, raylibDll, "SetSoundPitch") - purego.RegisterLibFunc(&setSoundPan, raylibDll, "SetSoundPan") - purego.RegisterLibFunc(&waveCopy, raylibDll, "WaveCopy") - purego.RegisterLibFunc(&waveCrop, raylibDll, "WaveCrop") - purego.RegisterLibFunc(&waveFormat, raylibDll, "WaveFormat") - purego.RegisterLibFunc(&loadWaveSamples, raylibDll, "LoadWaveSamples") - purego.RegisterLibFunc(&unloadWaveSamples, raylibDll, "UnloadWaveSamples") - purego.RegisterLibFunc(&loadMusicStream, raylibDll, "LoadMusicStream") - purego.RegisterLibFunc(&loadMusicStreamFromMemory, raylibDll, "LoadMusicStreamFromMemory") - purego.RegisterLibFunc(&isMusicValid, raylibDll, "IsMusicValid") - purego.RegisterLibFunc(&unloadMusicStream, raylibDll, "UnloadMusicStream") - purego.RegisterLibFunc(&playMusicStream, raylibDll, "PlayMusicStream") - purego.RegisterLibFunc(&isMusicStreamPlaying, raylibDll, "IsMusicStreamPlaying") - purego.RegisterLibFunc(&updateMusicStream, raylibDll, "UpdateMusicStream") - purego.RegisterLibFunc(&stopMusicStream, raylibDll, "StopMusicStream") - purego.RegisterLibFunc(&pauseMusicStream, raylibDll, "PauseMusicStream") - purego.RegisterLibFunc(&resumeMusicStream, raylibDll, "ResumeMusicStream") - purego.RegisterLibFunc(&seekMusicStream, raylibDll, "SeekMusicStream") - purego.RegisterLibFunc(&setMusicVolume, raylibDll, "SetMusicVolume") - purego.RegisterLibFunc(&setMusicPitch, raylibDll, "SetMusicPitch") - purego.RegisterLibFunc(&setMusicPan, raylibDll, "SetMusicPan") - purego.RegisterLibFunc(&getMusicTimeLength, raylibDll, "GetMusicTimeLength") - purego.RegisterLibFunc(&getMusicTimePlayed, raylibDll, "GetMusicTimePlayed") - purego.RegisterLibFunc(&loadAudioStream, raylibDll, "LoadAudioStream") - purego.RegisterLibFunc(&isAudioStreamValid, raylibDll, "IsAudioStreamValid") - purego.RegisterLibFunc(&unloadAudioStream, raylibDll, "UnloadAudioStream") - purego.RegisterLibFunc(&updateAudioStream, raylibDll, "UpdateAudioStream") - purego.RegisterLibFunc(&isAudioStreamProcessed, raylibDll, "IsAudioStreamProcessed") - purego.RegisterLibFunc(&playAudioStream, raylibDll, "PlayAudioStream") - purego.RegisterLibFunc(&pauseAudioStream, raylibDll, "PauseAudioStream") - purego.RegisterLibFunc(&resumeAudioStream, raylibDll, "ResumeAudioStream") - purego.RegisterLibFunc(&isAudioStreamPlaying, raylibDll, "IsAudioStreamPlaying") - purego.RegisterLibFunc(&stopAudioStream, raylibDll, "StopAudioStream") - purego.RegisterLibFunc(&setAudioStreamVolume, raylibDll, "SetAudioStreamVolume") - purego.RegisterLibFunc(&setAudioStreamPitch, raylibDll, "SetAudioStreamPitch") - purego.RegisterLibFunc(&setAudioStreamPan, raylibDll, "SetAudioStreamPan") - purego.RegisterLibFunc(&setAudioStreamBufferSizeDefault, raylibDll, "SetAudioStreamBufferSizeDefault") - purego.RegisterLibFunc(&setAudioStreamCallback, raylibDll, "SetAudioStreamCallback") - purego.RegisterLibFunc(&attachAudioStreamProcessor, raylibDll, "AttachAudioStreamProcessor") - purego.RegisterLibFunc(&detachAudioStreamProcessor, raylibDll, "DetachAudioStreamProcessor") - purego.RegisterLibFunc(&attachAudioMixedProcessor, raylibDll, "AttachAudioMixedProcessor") - purego.RegisterLibFunc(&detachAudioMixedProcessor, raylibDll, "DetachAudioMixedProcessor") -} - -// InitWindow - Initialize window and OpenGL context -func InitWindow(width int32, height int32, title string) { - initWindow(width, height, title) -} - -// CloseWindow - Close window and unload OpenGL context -func CloseWindow() { - closeWindow() -} - -// WindowShouldClose - Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) -func WindowShouldClose() bool { - return windowShouldClose() -} - -// IsWindowReady - Check if window has been initialized successfully -func IsWindowReady() bool { - return isWindowReady() -} - -// IsWindowFullscreen - Check if window is currently fullscreen -func IsWindowFullscreen() bool { - return isWindowFullscreen() -} - -// IsWindowHidden - Check if window is currently hidden (only PLATFORM_DESKTOP) -func IsWindowHidden() bool { - return isWindowHidden() -} - -// IsWindowMinimized - Check if window is currently minimized (only PLATFORM_DESKTOP) -func IsWindowMinimized() bool { - return isWindowMinimized() -} - -// IsWindowMaximized - Check if window is currently maximized (only PLATFORM_DESKTOP) -func IsWindowMaximized() bool { - return isWindowMaximized() -} - -// IsWindowFocused - Check if window is currently focused (only PLATFORM_DESKTOP) -func IsWindowFocused() bool { - return isWindowFocused() -} - -// IsWindowResized - Check if window has been resized last frame -func IsWindowResized() bool { - return isWindowResized() -} - -// IsWindowState - Check if one specific window flag is enabled -func IsWindowState(flag uint32) bool { - return isWindowState(flag) -} - -// SetWindowState - Set window configuration state using flags (only PLATFORM_DESKTOP) -func SetWindowState(flags uint32) { - setWindowState(flags) -} - -// ClearWindowState - Clear window configuration state flags -func ClearWindowState(flags uint32) { - clearWindowState(flags) -} - -// ToggleFullscreen - Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) -func ToggleFullscreen() { - toggleFullscreen() -} - -// ToggleBorderlessWindowed - Toggle window state: borderless windowed (only PLATFORM_DESKTOP) -func ToggleBorderlessWindowed() { - toggleBorderlessWindowed() -} - -// MaximizeWindow - Set window state: maximized, if resizable (only PLATFORM_DESKTOP) -func MaximizeWindow() { - maximizeWindow() -} - -// MinimizeWindow - Set window state: minimized, if resizable (only PLATFORM_DESKTOP) -func MinimizeWindow() { - minimizeWindow() -} - -// RestoreWindow - Set window state: not minimized/maximized (only PLATFORM_DESKTOP) -func RestoreWindow() { - restoreWindow() -} - -// SetWindowIcon - Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) -func SetWindowIcon(image Image) { - setWindowIcon(uintptr(unsafe.Pointer(&image))) -} - -// SetWindowIcons - Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) -func SetWindowIcons(images []Image, count int32) { - setWindowIcons(uintptr(unsafe.Pointer(&images[0])), int32(len(images))) -} - -// SetWindowTitle - Set title for window (only PLATFORM_DESKTOP and PLATFORM_WEB) -func SetWindowTitle(title string) { - setWindowTitle(title) -} - -// SetWindowPosition - Set window position on screen (only PLATFORM_DESKTOP) -func SetWindowPosition(x int, y int) { - setWindowPosition(int32(x), int32(y)) -} - -// SetWindowMonitor - Set monitor for the current window -func SetWindowMonitor(monitor int) { - setWindowMonitor(int32(monitor)) -} - -// SetWindowMinSize - Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) -func SetWindowMinSize(width int, height int) { - setWindowMinSize(int32(width), int32(height)) -} - -// SetWindowMaxSize - Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) -func SetWindowMaxSize(width int, height int) { - setWindowMaxSize(int32(width), int32(height)) -} - -// SetWindowSize - Set window dimensions -func SetWindowSize(width int, height int) { - setWindowSize(int32(width), int32(height)) -} - -// SetWindowOpacity - Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) -func SetWindowOpacity(opacity float32) { - setWindowOpacity(opacity) -} - -// SetWindowFocused - Set window focused (only PLATFORM_DESKTOP) -func SetWindowFocused() { - setWindowFocused() -} - -// GetWindowHandle - Get native window handle -func GetWindowHandle() unsafe.Pointer { - return getWindowHandle() -} - -// GetScreenWidth - Get current screen width -func GetScreenWidth() int { - return int(getScreenWidth()) -} - -// GetScreenHeight - Get current screen height -func GetScreenHeight() int { - return int(getScreenHeight()) -} - -// GetRenderWidth - Get current render width (it considers HiDPI) -func GetRenderWidth() int { - return int(getRenderWidth()) -} - -// GetRenderHeight - Get current render height (it considers HiDPI) -func GetRenderHeight() int { - return int(getRenderHeight()) -} - -// GetMonitorCount - Get number of connected monitors -func GetMonitorCount() int { - return int(getMonitorCount()) -} - -// GetCurrentMonitor - Get current monitor where window is placed -func GetCurrentMonitor() int { - return int(getCurrentMonitor()) -} - -// GetMonitorPosition - Get specified monitor position -func GetMonitorPosition(monitor int) Vector2 { - ret := getMonitorPosition(int32(monitor)) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetMonitorWidth - Get specified monitor width (current video mode used by monitor) -func GetMonitorWidth(monitor int) int { - return int(getMonitorWidth(int32(monitor))) -} - -// GetMonitorHeight - Get specified monitor height (current video mode used by monitor) -func GetMonitorHeight(monitor int) int { - return int(getMonitorHeight(int32(monitor))) -} - -// GetMonitorPhysicalWidth - Get specified monitor physical width in millimetres -func GetMonitorPhysicalWidth(monitor int) int { - return int(getMonitorPhysicalWidth(int32(monitor))) -} - -// GetMonitorPhysicalHeight - Get specified monitor physical height in millimetres -func GetMonitorPhysicalHeight(monitor int) int { - return int(getMonitorPhysicalHeight(int32(monitor))) -} - -// GetMonitorRefreshRate - Get specified monitor refresh rate -func GetMonitorRefreshRate(monitor int) int { - return int(getMonitorRefreshRate(int32(monitor))) -} - -// GetWindowPosition - Get window position XY on monitor -func GetWindowPosition() Vector2 { - ret := getWindowPosition() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetWindowScaleDPI - Get window scale DPI factor -func GetWindowScaleDPI() Vector2 { - ret := getWindowScaleDPI() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetMonitorName - Get the human-readable, UTF-8 encoded name of the specified monitor -func GetMonitorName(monitor int) string { - return getMonitorName(int32(monitor)) -} - -// SetClipboardText - Set clipboard text content -func SetClipboardText(text string) { - setClipboardText(text) -} - -// GetClipboardText - Get clipboard text content -func GetClipboardText() string { - return getClipboardText() -} - -// GetClipboardImage - Get clipboard image content -// -// Only works with SDL3 backend or Windows with RGFW/GLFW -func GetClipboardImage() Image { - var img Image - getClipboardImage(uintptr(unsafe.Pointer(&img))) - return img -} - -// EnableEventWaiting - Enable waiting for events on EndDrawing(), no automatic event polling -func EnableEventWaiting() { - enableEventWaiting() -} - -// DisableEventWaiting - Disable waiting for events on EndDrawing(), automatic events polling -func DisableEventWaiting() { - disableEventWaiting() -} - -// ShowCursor - Shows cursor -func ShowCursor() { - showCursor() -} - -// HideCursor - Hides cursor -func HideCursor() { - hideCursor() -} - -// IsCursorHidden - Check if cursor is not visible -func IsCursorHidden() bool { - return isCursorHidden() -} - -// EnableCursor - Enables cursor (unlock cursor) -func EnableCursor() { - enableCursor() -} - -// DisableCursor - Disables cursor (lock cursor) -func DisableCursor() { - disableCursor() -} - -// IsCursorOnScreen - Check if cursor is on the screen -func IsCursorOnScreen() bool { - return isCursorOnScreen() -} - -// ClearBackground - Set background color (framebuffer clear color) -func ClearBackground(col color.RGBA) { - clearBackground(*(*uintptr)(unsafe.Pointer(&col))) -} - -// BeginDrawing - Setup canvas (framebuffer) to start drawing -func BeginDrawing() { - beginDrawing() -} - -// EndDrawing - End canvas drawing and swap buffers (double buffering) -func EndDrawing() { - endDrawing() -} - -// BeginMode2D - Begin 2D mode with custom camera (2D) -func BeginMode2D(camera Camera2D) { - beginMode2D(uintptr(unsafe.Pointer(&camera))) -} - -// EndMode2D - Ends 2D mode with custom camera -func EndMode2D() { - endMode2D() -} - -// BeginMode3D - Begin 3D mode with custom camera (3D) -func BeginMode3D(camera Camera3D) { - beginMode3D(uintptr(unsafe.Pointer(&camera))) -} - -// EndMode3D - Ends 3D mode and returns to default 2D orthographic mode -func EndMode3D() { - endMode3D() -} - -// BeginTextureMode - Begin drawing to render texture -func BeginTextureMode(target RenderTexture2D) { - beginTextureMode(uintptr(unsafe.Pointer(&target))) -} - -// EndTextureMode - Ends drawing to render texture -func EndTextureMode() { - endTextureMode() -} - -// BeginShaderMode - Begin custom shader drawing -func BeginShaderMode(shader Shader) { - beginShaderMode(uintptr(unsafe.Pointer(&shader))) -} - -// EndShaderMode - End custom shader drawing (use default shader) -func EndShaderMode() { - endShaderMode() -} - -// BeginBlendMode - Begin blending mode (alpha, additive, multiplied, subtract, custom) -func BeginBlendMode(mode BlendMode) { - beginBlendMode(int32(mode)) -} - -// EndBlendMode - End blending mode (reset to default: alpha blending) -func EndBlendMode() { - endBlendMode() -} - -// BeginScissorMode - Begin scissor mode (define screen area for following drawing) -func BeginScissorMode(x int32, y int32, width int32, height int32) { - beginScissorMode(x, y, width, height) -} - -// EndScissorMode - End scissor mode -func EndScissorMode() { - endScissorMode() -} - -// BeginVrStereoMode - Begin stereo rendering (requires VR simulator) -func BeginVrStereoMode(config VrStereoConfig) { - beginVrStereoMode(uintptr(unsafe.Pointer(&config))) -} - -// EndVrStereoMode - End stereo rendering (requires VR simulator) -func EndVrStereoMode() { - endVrStereoMode() -} - -// LoadVrStereoConfig - Load VR stereo config for VR simulator device parameters -func LoadVrStereoConfig(device VrDeviceInfo) VrStereoConfig { - var config VrStereoConfig - loadVrStereoConfig(uintptr(unsafe.Pointer(&config)), uintptr(unsafe.Pointer(&device))) - return config -} - -// UnloadVrStereoConfig - Unload VR stereo config -func UnloadVrStereoConfig(config VrStereoConfig) { - unloadVrStereoConfig(uintptr(unsafe.Pointer(&config))) -} - -// LoadShader - Load shader from files and bind default locations -func LoadShader(vsFileName string, fsFileName string) Shader { - var shader Shader - var cvsFileName, cfsFileName *byte - if vsFileName != "" { - var err error - cvsFileName, err = windows.BytePtrFromString(vsFileName) - if err != nil { - panic(err) - } - } - if fsFileName != "" { - var err error - cfsFileName, err = windows.BytePtrFromString(fsFileName) - if err != nil { - panic(err) - } - } - loadShader(uintptr(unsafe.Pointer(&shader)), uintptr(unsafe.Pointer(cvsFileName)), uintptr(unsafe.Pointer(cfsFileName))) - return shader -} - -// LoadShaderFromMemory - Load shader from code strings and bind default locations -func LoadShaderFromMemory(vsCode string, fsCode string) Shader { - var shader Shader - var cvsCode, cfsCode *byte - if vsCode != "" { - var err error - cvsCode, err = windows.BytePtrFromString(vsCode) - if err != nil { - panic(err) - } - } - if fsCode != "" { - var err error - cfsCode, err = windows.BytePtrFromString(fsCode) - if err != nil { - panic(err) - } - } - loadShaderFromMemory(uintptr(unsafe.Pointer(&shader)), uintptr(unsafe.Pointer(cvsCode)), uintptr(unsafe.Pointer(cfsCode))) - return shader -} - -// IsShaderValid - Check if a shader is valid (loaded on GPU) -func IsShaderValid(shader Shader) bool { - return isShaderValid(uintptr(unsafe.Pointer(&shader))) -} - -// GetShaderLocation - Get shader uniform location -func GetShaderLocation(shader Shader, uniformName string) int32 { - return getShaderLocation(uintptr(unsafe.Pointer(&shader)), uniformName) -} - -// GetShaderLocationAttrib - Get shader attribute location -func GetShaderLocationAttrib(shader Shader, attribName string) int32 { - return getShaderLocationAttrib(uintptr(unsafe.Pointer(&shader)), attribName) -} - -// SetShaderValue - Set shader uniform value -func SetShaderValue(shader Shader, locIndex int32, value []float32, uniformType ShaderUniformDataType) { - setShaderValue(uintptr(unsafe.Pointer(&shader)), locIndex, value, int32(uniformType)) -} - -// SetShaderValueV - Set shader uniform value vector -func SetShaderValueV(shader Shader, locIndex int32, value []float32, uniformType ShaderUniformDataType, count int32) { - setShaderValueV(uintptr(unsafe.Pointer(&shader)), locIndex, value, int32(uniformType), count) -} - -// SetShaderValueMatrix - Set shader uniform value (matrix 4x4) -func SetShaderValueMatrix(shader Shader, locIndex int32, mat Matrix) { - setShaderValueMatrix(uintptr(unsafe.Pointer(&shader)), locIndex, uintptr(unsafe.Pointer(&mat))) -} - -// SetShaderValueTexture - Set shader uniform value for texture (sampler2d) -func SetShaderValueTexture(shader Shader, locIndex int32, texture Texture2D) { - setShaderValueTexture(uintptr(unsafe.Pointer(&shader)), locIndex, uintptr(unsafe.Pointer(&texture))) -} - -// UnloadShader - Unload shader from GPU memory (VRAM) -func UnloadShader(shader Shader) { - unloadShader(uintptr(unsafe.Pointer(&shader))) -} - -// GetMouseRay - Get a ray trace from mouse position -// -// Deprecated: Use [GetScreenToWorldRay] instead. -func GetMouseRay(mousePosition Vector2, camera Camera) Ray { - return GetScreenToWorldRay(mousePosition, camera) -} - -// GetScreenToWorldRay - Get a ray trace from screen position (i.e mouse) -func GetScreenToWorldRay(position Vector2, camera Camera) Ray { - var ray Ray - getScreenToWorldRay(uintptr(unsafe.Pointer(&ray)), *(*uintptr)(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&camera))) - return ray -} - -// GetScreenToWorldRayEx - Get a ray trace from screen position (i.e mouse) in a viewport -func GetScreenToWorldRayEx(position Vector2, camera Camera, width, height int32) Ray { - var ray Ray - getScreenToWorldRayEx(uintptr(unsafe.Pointer(&ray)), *(*uintptr)(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&camera)), width, height) - return ray -} - -// GetCameraMatrix - Get camera transform matrix (view matrix) -func GetCameraMatrix(camera Camera) Matrix { - var mat Matrix - getCameraMatrix(uintptr(unsafe.Pointer(&mat)), uintptr(unsafe.Pointer(&camera))) - return mat -} - -// GetCameraMatrix2D - Get camera 2d transform matrix -func GetCameraMatrix2D(camera Camera2D) Matrix { - var mat Matrix - getCameraMatrix2D(uintptr(unsafe.Pointer(&mat)), uintptr(unsafe.Pointer(&camera))) - return mat -} - -// GetWorldToScreen - Get the screen space position for a 3d world space position -func GetWorldToScreen(position Vector3, camera Camera) Vector2 { - ret := getWorldToScreen(uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&camera))) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetScreenToWorld2D - Get the world space position for a 2d camera screen space position -func GetScreenToWorld2D(position Vector2, camera Camera2D) Vector2 { - ret := getScreenToWorld2D(*(*uintptr)(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&camera))) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetWorldToScreenEx - Get size position for a 3d world space position -func GetWorldToScreenEx(position Vector3, camera Camera, width int32, height int32) Vector2 { - ret := getWorldToScreenEx(uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&camera)), width, height) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetWorldToScreen2D - Get the screen space position for a 2d camera world space position -func GetWorldToScreen2D(position Vector2, camera Camera2D) Vector2 { - ret := getWorldToScreen2D(*(*uintptr)(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&camera))) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// SetTargetFPS - Set target FPS (maximum) -func SetTargetFPS(fps int32) { - setTargetFPS(fps) -} - -// GetFrameTime - Get time in seconds for last frame drawn (delta time) -func GetFrameTime() float32 { - return getFrameTime() -} - -// GetTime - Get elapsed time in seconds since InitWindow() -func GetTime() float64 { - return getTime() -} - -// GetFPS - Get current FPS -func GetFPS() int32 { - return getFPS() -} - -// Custom frame control functions -// NOTE: SwapScreenBuffer and PollInputEvents are intended for advanced users that want full control over the frame processing -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() -// To avoid that behaviour and control frame processes manually you must recompile raylib with SUPPORT_CUSTOM_FRAME_CONTROL enabled in config.h - -// SwapScreenBuffer - Swap back buffer with front buffer (screen drawing) -func SwapScreenBuffer() { - swapScreenBuffer() -} - -// PollInputEvents - Register all input events -func PollInputEvents() { - pollInputEvents() -} - -// WaitTime - Wait for some time (halt program execution) -func WaitTime(seconds float64) { - waitTime(seconds) -} - -// SetRandomSeed - Set the seed for the random number generator -// -// Note: You can use go's math/rand package instead -func SetRandomSeed(seed uint32) { - setRandomSeed(seed) -} - -// GetRandomValue - Get a random value between min and max (both included) -// -// Note: You can use go's math/rand package instead -func GetRandomValue(minimum int32, maximum int32) int32 { - return getRandomValue(minimum, maximum) -} - -// LoadRandomSequence - Load random values sequence, no values repeated -// -// Note: Use UnloadRandomSequence if you don't need the sequence any more. You can use go's math/rand.Perm function instead. -func LoadRandomSequence(count uint32, minimum int32, maximum int32) []int32 { - ret := loadRandomSequence(count, minimum, maximum) - return unsafe.Slice(ret, 10) -} - -// UnloadRandomSequence - Unload random values sequence -func UnloadRandomSequence(sequence []int32) { - unloadRandomSequence(unsafe.SliceData(sequence)) -} - -// TakeScreenshot - Takes a screenshot of current screen (filename extension defines format) -func TakeScreenshot(fileName string) { - takeScreenshot(fileName) -} - -// SetConfigFlags - Setup init configuration flags (view FLAGS) -func SetConfigFlags(flags uint32) { - setConfigFlags(flags) -} - -// OpenURL - Open URL with default system browser (if available) -func OpenURL(url string) { - openURL(url) -} - -// TraceLog - Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) -func TraceLog(logLevel TraceLogLevel, text string, args ...any) { - traceLog(int32(logLevel), fmt.Sprintf(text, args...)) -} - -// SetTraceLogLevel - Set the current threshold (minimum) log level -func SetTraceLogLevel(logLevel TraceLogLevel) { - setTraceLogLevel(int32(logLevel)) -} - -// MemAlloc - Internal memory allocator -func MemAlloc(size uint32) unsafe.Pointer { - return memAlloc(size) -} - -// MemRealloc - Internal memory reallocator -func MemRealloc(ptr unsafe.Pointer, size uint32) unsafe.Pointer { - return memRealloc(ptr, size) -} - -// MemFree - Internal memory free -func MemFree(ptr unsafe.Pointer) { - memFree(ptr) -} - -// SetTraceLogCallback - Set custom trace log -func SetTraceLogCallback(fn TraceLogCallbackFun) { - setTraceLogCallback(traceLogCallbackWrapper(fn)) -} - -// IsFileDropped - Check if a file has been dropped into window -func IsFileDropped() bool { - return isFileDropped() -} - -// LoadDroppedFiles - Load dropped filepaths -func LoadDroppedFiles() []string { - var filePathList = struct { - capacity uint32 - count uint32 - paths **byte - }{} - loadDroppedFiles(uintptr(unsafe.Pointer(&filePathList))) - defer unloadDroppedFiles(uintptr(unsafe.Pointer(&filePathList))) - - tmpslice := (*[1 << 24]*byte)(unsafe.Pointer(filePathList.paths))[:filePathList.count:filePathList.count] - - gostrings := make([]string, filePathList.count) - for i, s := range tmpslice { - gostrings[i] = func(p *byte) string { - if p == nil || *p == 0 { - return "" - } - - n := 0 - for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ { - ptr = unsafe.Pointer(uintptr(ptr) + 1) - } - - return string(unsafe.Slice(p, n)) - }(s) - } - - return gostrings -} - -// UnloadDroppedFiles - Unload dropped filepaths -func UnloadDroppedFiles() {} - -// LoadAutomationEventList - Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS -func LoadAutomationEventList(fileName string) AutomationEventList { - var automationEventList AutomationEventList - loadAutomationEventList(uintptr(unsafe.Pointer(&automationEventList)), fileName) - return automationEventList -} - -// UnloadAutomationEventList - Unload automation events list from file -func UnloadAutomationEventList(list *AutomationEventList) { - unloadAutomationEventList(uintptr(unsafe.Pointer(&list))) -} - -// ExportAutomationEventList - Export automation events list as text file -func ExportAutomationEventList(list AutomationEventList, fileName string) bool { - return exportAutomationEventList(uintptr(unsafe.Pointer(&list)), fileName) -} - -// SetAutomationEventList - Set automation event list to record to -func SetAutomationEventList(list *AutomationEventList) { - setAutomationEventList(uintptr(unsafe.Pointer(&list))) -} - -// SetAutomationEventBaseFrame - Set automation event internal base frame to start recording -func SetAutomationEventBaseFrame(frame int) { - setAutomationEventBaseFrame(int32(frame)) -} - -// StartAutomationEventRecording - Start recording automation events (AutomationEventList must be set) -func StartAutomationEventRecording() { - startAutomationEventRecording() -} - -// StopAutomationEventRecording - Stop recording automation events -func StopAutomationEventRecording() { - stopAutomationEventRecording() -} - -// PlayAutomationEvent - Play a recorded automation event -func PlayAutomationEvent(event AutomationEvent) { - playAutomationEvent(uintptr(unsafe.Pointer(&event))) -} - -// IsKeyPressed - Check if a key has been pressed once -func IsKeyPressed(key int32) bool { - return isKeyPressed(key) -} - -// IsKeyPressedRepeat - Check if a key has been pressed again (Only PLATFORM_DESKTOP) -func IsKeyPressedRepeat(key int32) bool { - return isKeyPressedRepeat(key) -} - -// IsKeyDown - Check if a key is being pressed -func IsKeyDown(key int32) bool { - return isKeyDown(key) -} - -// IsKeyReleased - Check if a key has been released once -func IsKeyReleased(key int32) bool { - return isKeyReleased(key) -} - -// IsKeyUp - Check if a key is NOT being pressed -func IsKeyUp(key int32) bool { - return isKeyUp(key) -} - -// GetKeyPressed - Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty -func GetKeyPressed() int32 { - return getKeyPressed() -} - -// GetCharPressed - Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty -func GetCharPressed() int32 { - return getCharPressed() -} - -// SetExitKey - Set a custom key to exit program (default is ESC) -func SetExitKey(key int32) { - setExitKey(key) -} - -// IsGamepadAvailable - Check if a gamepad is available -func IsGamepadAvailable(gamepad int32) bool { - return isGamepadAvailable(gamepad) -} - -// GetGamepadName - Get gamepad internal name id -func GetGamepadName(gamepad int32) string { - return getGamepadName(gamepad) -} - -// IsGamepadButtonPressed - Check if a gamepad button has been pressed once -func IsGamepadButtonPressed(gamepad int32, button int32) bool { - return isGamepadButtonPressed(gamepad, button) -} - -// IsGamepadButtonDown - Check if a gamepad button is being pressed -func IsGamepadButtonDown(gamepad int32, button int32) bool { - return isGamepadButtonDown(gamepad, button) -} - -// IsGamepadButtonReleased - Check if a gamepad button has been released once -func IsGamepadButtonReleased(gamepad int32, button int32) bool { - return isGamepadButtonReleased(gamepad, button) -} - -// IsGamepadButtonUp - Check if a gamepad button is NOT being pressed -func IsGamepadButtonUp(gamepad int32, button int32) bool { - return isGamepadButtonUp(gamepad, button) -} - -// GetGamepadButtonPressed - Get the last gamepad button pressed -func GetGamepadButtonPressed() int32 { - return getGamepadButtonPressed() -} - -// GetGamepadAxisCount - Get gamepad axis count for a gamepad -func GetGamepadAxisCount(gamepad int32) int32 { - return getGamepadAxisCount(gamepad) -} - -// GetGamepadAxisMovement - Get axis movement value for a gamepad axis -func GetGamepadAxisMovement(gamepad int32, axis int32) float32 { - return getGamepadAxisMovement(gamepad, axis) -} - -// SetGamepadMappings - Set internal gamepad mappings (SDL_GameControllerDB) -func SetGamepadMappings(mappings string) int32 { - return setGamepadMappings(mappings) -} - -// SetGamepadVibration - Set gamepad vibration for both motors (duration in seconds) -func SetGamepadVibration(gamepad int32, leftMotor, rightMotor, duration float32) { - setGamepadVibration(gamepad, leftMotor, rightMotor, duration) -} - -// IsMouseButtonPressed - Check if a mouse button has been pressed once -func IsMouseButtonPressed(button MouseButton) bool { - return isMouseButtonPressed(int32(button)) -} - -// IsMouseButtonDown - Check if a mouse button is being pressed -func IsMouseButtonDown(button MouseButton) bool { - return isMouseButtonDown(int32(button)) -} - -// IsMouseButtonReleased - Check if a mouse button has been released once -func IsMouseButtonReleased(button MouseButton) bool { - return isMouseButtonReleased(int32(button)) -} - -// IsMouseButtonUp - Check if a mouse button is NOT being pressed -func IsMouseButtonUp(button MouseButton) bool { - return isMouseButtonUp(int32(button)) -} - -// GetMouseX - Get mouse position X -func GetMouseX() int32 { - return getMouseX() -} - -// GetMouseY - Get mouse position Y -func GetMouseY() int32 { - return getMouseY() -} - -// GetMousePosition - Get mouse position XY -func GetMousePosition() Vector2 { - ret := getMousePosition() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetMouseDelta - Get mouse delta between frames -func GetMouseDelta() Vector2 { - ret := getMouseDelta() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// SetMousePosition - Set mouse position XY -func SetMousePosition(x int32, y int32) { - setMousePosition(x, y) -} - -// SetMouseOffset - Set mouse offset -func SetMouseOffset(offsetX int32, offsetY int32) { - setMouseOffset(offsetX, offsetY) -} - -// SetMouseScale - Set mouse scaling -func SetMouseScale(scaleX float32, scaleY float32) { - setMouseScale(scaleX, scaleY) -} - -// GetMouseWheelMove - Get mouse wheel movement for X or Y, whichever is larger -func GetMouseWheelMove() float32 { - return getMouseWheelMove() -} - -// GetMouseWheelMoveV - Get mouse wheel movement for both X and Y -func GetMouseWheelMoveV() Vector2 { - ret := getMouseWheelMoveV() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// SetMouseCursor - Set mouse cursor -func SetMouseCursor(cursor int32) { - setMouseCursor(cursor) -} - -// GetTouchX - Get touch position X for touch point 0 (relative to screen size) -func GetTouchX() int32 { - return getTouchX() -} - -// GetTouchY - Get touch position Y for touch point 0 (relative to screen size) -func GetTouchY() int32 { - return getTouchY() -} - -// GetTouchPosition - Get touch position XY for a touch point index (relative to screen size) -func GetTouchPosition(index int32) Vector2 { - ret := getTouchPosition(index) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetTouchPointId - Get touch point identifier for given index -func GetTouchPointId(index int32) int32 { - return getTouchPointId(index) -} - -// GetTouchPointCount - Get number of touch points -func GetTouchPointCount() int32 { - return getTouchPointCount() -} - -// SetGesturesEnabled - Enable a set of gestures using flags -func SetGesturesEnabled(flags uint32) { - setGesturesEnabled(flags) -} - -// IsGestureDetected - Check if a gesture have been detected -func IsGestureDetected(gesture Gestures) bool { - return isGestureDetected(uint32(gesture)) -} - -// GetGestureDetected - Get latest detected gesture -func GetGestureDetected() Gestures { - return Gestures(getGestureDetected()) -} - -// GetGestureHoldDuration - Get gesture hold time in milliseconds -func GetGestureHoldDuration() float32 { - return getGestureHoldDuration() -} - -// GetGestureDragVector - Get gesture drag vector -func GetGestureDragVector() Vector2 { - ret := getGestureDragVector() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetGestureDragAngle - Get gesture drag angle -func GetGestureDragAngle() float32 { - return getGestureDragAngle() -} - -// GetGesturePinchVector - Get gesture pinch delta -func GetGesturePinchVector() Vector2 { - ret := getGesturePinchVector() - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetGesturePinchAngle - Get gesture pinch angle -func GetGesturePinchAngle() float32 { - return getGesturePinchAngle() -} - -// SetShapesTexture - Set texture and rectangle to be used on shapes drawing -func SetShapesTexture(texture Texture2D, source Rectangle) { - setShapesTexture(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&source))) -} - -// GetShapesTexture - Get texture that is used for shapes drawing -func GetShapesTexture() Texture2D { - var texture Texture2D - getShapesTexture(uintptr(unsafe.Pointer(&texture))) - return texture -} - -// GetShapesTextureRectangle - Get texture source rectangle that is used for shapes drawing -func GetShapesTextureRectangle() Rectangle { - var rec Rectangle - getShapesTextureRectangle(uintptr(unsafe.Pointer(&rec))) - return rec -} - -// DrawPixel - Draw a pixel -func DrawPixel(posX int32, posY int32, col color.RGBA) { - drawPixel(posX, posY, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawPixelV - Draw a pixel (Vector version) -func DrawPixelV(position Vector2, col color.RGBA) { - drawPixelV(*(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawLine - Draw a line -func DrawLine(startPosX int32, startPosY int32, endPosX int32, endPosY int32, col color.RGBA) { - drawLine(startPosX, startPosY, endPosX, endPosY, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawLineV - Draw a line (using gl lines) -func DrawLineV(startPos Vector2, endPos Vector2, col color.RGBA) { - drawLineV(*(*uintptr)(unsafe.Pointer(&startPos)), *(*uintptr)(unsafe.Pointer(&endPos)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawLineEx - Draw a line (using triangles/quads) -func DrawLineEx(startPos Vector2, endPos Vector2, thick float32, col color.RGBA) { - drawLineEx(*(*uintptr)(unsafe.Pointer(&startPos)), *(*uintptr)(unsafe.Pointer(&endPos)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawLineStrip - Draw lines sequence (using gl lines) -func DrawLineStrip(points []Vector2, col color.RGBA) { - pointCount := int32(len(points)) - drawLineStrip((unsafe.SliceData(points)), pointCount, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawLineBezier - Draw line segment cubic-bezier in-out interpolation -func DrawLineBezier(startPos Vector2, endPos Vector2, thick float32, col color.RGBA) { - drawLineBezier(*(*uintptr)(unsafe.Pointer(&startPos)), *(*uintptr)(unsafe.Pointer(&endPos)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircle - Draw a color-filled circle -func DrawCircle(centerX int32, centerY int32, radius float32, col color.RGBA) { - drawCircle(centerX, centerY, radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircleSector - Draw a piece of a circle -func DrawCircleSector(center Vector2, radius float32, startAngle float32, endAngle float32, segments int32, col color.RGBA) { - drawCircleSector(*(*uintptr)(unsafe.Pointer(¢er)), radius, startAngle, endAngle, segments, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircleSectorLines - Draw circle sector outline -func DrawCircleSectorLines(center Vector2, radius float32, startAngle float32, endAngle float32, segments int32, col color.RGBA) { - drawCircleSectorLines(*(*uintptr)(unsafe.Pointer(¢er)), radius, startAngle, endAngle, segments, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircleGradient - Draw a gradient-filled circle -func DrawCircleGradient(centerX int32, centerY int32, radius float32, inner color.RGBA, outer color.RGBA) { - drawCircleGradient(centerX, centerY, radius, *(*uintptr)(unsafe.Pointer(&inner)), *(*uintptr)(unsafe.Pointer(&outer))) -} - -// DrawCircleV - Draw a color-filled circle (Vector version) -func DrawCircleV(center Vector2, radius float32, col color.RGBA) { - drawCircleV(*(*uintptr)(unsafe.Pointer(¢er)), radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircleLines - Draw circle outline -func DrawCircleLines(centerX int32, centerY int32, radius float32, col color.RGBA) { - drawCircleLines(centerX, centerY, radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircleLinesV - Draw circle outline (Vector version) -func DrawCircleLinesV(center Vector2, radius float32, col color.RGBA) { - drawCircleLinesV(*(*uintptr)(unsafe.Pointer(¢er)), radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawEllipse - Draw ellipse -func DrawEllipse(centerX int32, centerY int32, radiusH float32, radiusV float32, col color.RGBA) { - drawEllipse(centerX, centerY, radiusH, radiusV, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawEllipseLines - Draw ellipse outline -func DrawEllipseLines(centerX int32, centerY int32, radiusH float32, radiusV float32, col color.RGBA) { - drawEllipseLines(centerX, centerY, radiusH, radiusV, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRing - Draw ring -func DrawRing(center Vector2, innerRadius float32, outerRadius float32, startAngle float32, endAngle float32, segments int32, col color.RGBA) { - drawRing(*(*uintptr)(unsafe.Pointer(¢er)), innerRadius, outerRadius, startAngle, endAngle, segments, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRingLines - Draw ring outline -func DrawRingLines(center Vector2, innerRadius float32, outerRadius float32, startAngle float32, endAngle float32, segments int32, col color.RGBA) { - drawRingLines(*(*uintptr)(unsafe.Pointer(¢er)), innerRadius, outerRadius, startAngle, endAngle, segments, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangle - Draw a color-filled rectangle -func DrawRectangle(posX int32, posY int32, width int32, height int32, col color.RGBA) { - drawRectangle(posX, posY, width, height, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleV - Draw a color-filled rectangle (Vector version) -func DrawRectangleV(position Vector2, size Vector2, col color.RGBA) { - drawRectangleV(*(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleRec - Draw a color-filled rectangle -func DrawRectangleRec(rec Rectangle, col color.RGBA) { - drawRectangleRec(uintptr(unsafe.Pointer(&rec)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectanglePro - Draw a color-filled rectangle with pro parameters -func DrawRectanglePro(rec Rectangle, origin Vector2, rotation float32, col color.RGBA) { - drawRectanglePro(uintptr(unsafe.Pointer(&rec)), *(*uintptr)(unsafe.Pointer(&origin)), rotation, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleGradientV - Draw a vertical-gradient-filled rectangle -func DrawRectangleGradientV(posX int32, posY int32, width int32, height int32, top color.RGBA, bottom color.RGBA) { - drawRectangleGradientV(posX, posY, width, height, *(*uintptr)(unsafe.Pointer(&top)), *(*uintptr)(unsafe.Pointer(&bottom))) -} - -// DrawRectangleGradientH - Draw a horizontal-gradient-filled rectangle -func DrawRectangleGradientH(posX int32, posY int32, width int32, height int32, left color.RGBA, right color.RGBA) { - drawRectangleGradientH(posX, posY, width, height, *(*uintptr)(unsafe.Pointer(&left)), *(*uintptr)(unsafe.Pointer(&right))) -} - -// DrawRectangleGradientEx - Draw a gradient-filled rectangle with custom vertex colors -func DrawRectangleGradientEx(rec Rectangle, topLeft color.RGBA, bottomLeft color.RGBA, topRight color.RGBA, bottomRight color.RGBA) { - drawRectangleGradientEx(uintptr(unsafe.Pointer(&rec)), *(*uintptr)(unsafe.Pointer(&topLeft)), *(*uintptr)(unsafe.Pointer(&bottomLeft)), *(*uintptr)(unsafe.Pointer(&topRight)), *(*uintptr)(unsafe.Pointer(&bottomRight))) -} - -// DrawRectangleLines - Draw rectangle outline -func DrawRectangleLines(posX int32, posY int32, width int32, height int32, col color.RGBA) { - drawRectangleLines(posX, posY, width, height, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleLinesEx - Draw rectangle outline with extended parameters -func DrawRectangleLinesEx(rec Rectangle, lineThick float32, col color.RGBA) { - drawRectangleLinesEx(uintptr(unsafe.Pointer(&rec)), lineThick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleRounded - Draw rectangle with rounded edges -func DrawRectangleRounded(rec Rectangle, roundness float32, segments int32, col color.RGBA) { - drawRectangleRounded(uintptr(unsafe.Pointer(&rec)), roundness, segments, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleRoundedLines - Draw rectangle lines with rounded edges -func DrawRectangleRoundedLines(rec Rectangle, roundness float32, segments int32, col color.RGBA) { - drawRectangleRoundedLines(uintptr(unsafe.Pointer(&rec)), roundness, segments, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRectangleRoundedLinesEx - Draw rectangle with rounded edges outline -func DrawRectangleRoundedLinesEx(rec Rectangle, roundness float32, segments int32, lineThick float32, col color.RGBA) { - drawRectangleRoundedLinesEx(uintptr(unsafe.Pointer(&rec)), roundness, segments, lineThick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTriangle - Draw a color-filled triangle (vertex in counter-clockwise order!) -func DrawTriangle(v1 Vector2, v2 Vector2, v3 Vector2, col color.RGBA) { - drawTriangle(*(*uintptr)(unsafe.Pointer(&v1)), *(*uintptr)(unsafe.Pointer(&v2)), *(*uintptr)(unsafe.Pointer(&v3)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTriangleLines - Draw triangle outline (vertex in counter-clockwise order!) -func DrawTriangleLines(v1 Vector2, v2 Vector2, v3 Vector2, col color.RGBA) { - drawTriangleLines(*(*uintptr)(unsafe.Pointer(&v1)), *(*uintptr)(unsafe.Pointer(&v2)), *(*uintptr)(unsafe.Pointer(&v3)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTriangleFan - Draw a triangle fan defined by points (first vertex is the center) -func DrawTriangleFan(points []Vector2, col color.RGBA) { - pointCount := int32(len(points)) - drawTriangleFan(unsafe.SliceData(points), pointCount, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTriangleStrip - Draw a triangle strip defined by points -func DrawTriangleStrip(points []Vector2, col color.RGBA) { - pointCount := int32(len(points)) - drawTriangleStrip(unsafe.SliceData(points), pointCount, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawPoly - Draw a regular polygon (Vector version) -func DrawPoly(center Vector2, sides int32, radius float32, rotation float32, col color.RGBA) { - drawPoly(*(*uintptr)(unsafe.Pointer(¢er)), sides, radius, rotation, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawPolyLines - Draw a polygon outline of n sides -func DrawPolyLines(center Vector2, sides int32, radius float32, rotation float32, col color.RGBA) { - drawPolyLines(*(*uintptr)(unsafe.Pointer(¢er)), sides, radius, rotation, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawPolyLinesEx - Draw a polygon outline of n sides with extended parameters -func DrawPolyLinesEx(center Vector2, sides int32, radius float32, rotation float32, lineThick float32, col color.RGBA) { - drawPolyLinesEx(*(*uintptr)(unsafe.Pointer(¢er)), sides, radius, rotation, lineThick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineLinear - Draw spline: Linear, minimum 2 points -func DrawSplineLinear(points []Vector2, thick float32, col color.RGBA) { - pointCount := int32(len(points)) - drawSplineLinear(unsafe.SliceData(points), pointCount, thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineBasis - Draw spline: B-Spline, minimum 4 points -func DrawSplineBasis(points []Vector2, thick float32, col color.RGBA) { - pointCount := int32(len(points)) - drawSplineBasis(unsafe.SliceData(points), pointCount, thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineCatmullRom - Draw spline: Catmull-Rom, minimum 4 points -func DrawSplineCatmullRom(points []Vector2, thick float32, col color.RGBA) { - pointCount := int32(len(points)) - drawSplineCatmullRom(unsafe.SliceData(points), pointCount, thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineBezierQuadratic - Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] -func DrawSplineBezierQuadratic(points []Vector2, thick float32, col color.RGBA) { - pointCount := int32(len(points)) - drawSplineBezierQuadratic(unsafe.SliceData(points), pointCount, thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineBezierCubic - Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] -func DrawSplineBezierCubic(points []Vector2, thick float32, col color.RGBA) { - pointCount := int32(len(points)) - drawSplineBezierCubic(unsafe.SliceData(points), pointCount, thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineSegmentLinear - Draw spline segment: Linear, 2 points -func DrawSplineSegmentLinear(p1 Vector2, p2 Vector2, thick float32, col color.RGBA) { - drawSplineSegmentLinear(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineSegmentBasis - Draw spline segment: B-Spline, 4 points -func DrawSplineSegmentBasis(p1 Vector2, p2 Vector2, p3 Vector2, p4 Vector2, thick float32, col color.RGBA) { - drawSplineSegmentBasis(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), *(*uintptr)(unsafe.Pointer(&p3)), *(*uintptr)(unsafe.Pointer(&p4)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineSegmentCatmullRom - Draw spline segment: Catmull-Rom, 4 points -func DrawSplineSegmentCatmullRom(p1 Vector2, p2 Vector2, p3 Vector2, p4 Vector2, thick float32, col color.RGBA) { - drawSplineSegmentCatmullRom(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), *(*uintptr)(unsafe.Pointer(&p3)), *(*uintptr)(unsafe.Pointer(&p4)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineSegmentBezierQuadratic - Draw spline segment: Quadratic Bezier, 2 points, 1 control point -func DrawSplineSegmentBezierQuadratic(p1 Vector2, c2 Vector2, p3 Vector2, thick float32, col color.RGBA) { - drawSplineSegmentBezierQuadratic(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&c2)), *(*uintptr)(unsafe.Pointer(&p3)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSplineSegmentBezierCubic - Draw spline segment: Cubic Bezier, 2 points, 2 control points -func DrawSplineSegmentBezierCubic(p1 Vector2, c2 Vector2, c3 Vector2, p4 Vector2, thick float32, col color.RGBA) { - drawSplineSegmentBezierCubic(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&c2)), *(*uintptr)(unsafe.Pointer(&c3)), *(*uintptr)(unsafe.Pointer(&p4)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// GetSplinePointLinear - Get (evaluate) spline point: Linear -func GetSplinePointLinear(startPos Vector2, endPos Vector2, t float32) Vector2 { - ret := getSplinePointLinear(*(*uintptr)(unsafe.Pointer(&startPos)), *(*uintptr)(unsafe.Pointer(&endPos)), t) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetSplinePointBasis - Get (evaluate) spline point: B-Spline -func GetSplinePointBasis(p1 Vector2, p2 Vector2, p3 Vector2, p4 Vector2, t float32) Vector2 { - ret := getSplinePointBasis(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), *(*uintptr)(unsafe.Pointer(&p3)), *(*uintptr)(unsafe.Pointer(&p4)), t) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetSplinePointCatmullRom - Get (evaluate) spline point: Catmull-Rom -func GetSplinePointCatmullRom(p1 Vector2, p2 Vector2, p3 Vector2, p4 Vector2, t float32) Vector2 { - ret := getSplinePointCatmullRom(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), *(*uintptr)(unsafe.Pointer(&p3)), *(*uintptr)(unsafe.Pointer(&p4)), t) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetSplinePointBezierQuad - Get (evaluate) spline point: Quadratic Bezier -func GetSplinePointBezierQuad(p1 Vector2, c2 Vector2, p3 Vector2, t float32) Vector2 { - ret := getSplinePointBezierQuad(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&c2)), *(*uintptr)(unsafe.Pointer(&p3)), t) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetSplinePointBezierCubic - Get (evaluate) spline point: Cubic Bezier -func GetSplinePointBezierCubic(p1 Vector2, c2 Vector2, c3 Vector2, p4 Vector2, t float32) Vector2 { - ret := getSplinePointBezierCubic(*(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&c2)), *(*uintptr)(unsafe.Pointer(&c3)), *(*uintptr)(unsafe.Pointer(&p4)), t) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// CheckCollisionRecs - Check collision between two rectangles -func CheckCollisionRecs(rec1 Rectangle, rec2 Rectangle) bool { - return checkCollisionRecs(uintptr(unsafe.Pointer(&rec1)), uintptr(unsafe.Pointer(&rec2))) -} - -// CheckCollisionCircles - Check collision between two circles -func CheckCollisionCircles(center1 Vector2, radius1 float32, center2 Vector2, radius2 float32) bool { - return checkCollisionCircles(*(*uintptr)(unsafe.Pointer(¢er1)), radius1, *(*uintptr)(unsafe.Pointer(¢er2)), radius2) -} - -// CheckCollisionCircleRec - Check collision between circle and rectangle -func CheckCollisionCircleRec(center Vector2, radius float32, rec Rectangle) bool { - return checkCollisionCircleRec(*(*uintptr)(unsafe.Pointer(¢er)), radius, uintptr(unsafe.Pointer(&rec))) -} - -// CheckCollisionCircleLine - Check if circle collides with a line created betweeen two points [p1] and [p2] -func CheckCollisionCircleLine(center Vector2, radius float32, p1, p2 Vector2) bool { - return checkCollisionCircleLine(*(*uintptr)(unsafe.Pointer(¢er)), radius, *(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2))) -} - -// CheckCollisionPointRec - Check if point is inside rectangle -func CheckCollisionPointRec(point Vector2, rec Rectangle) bool { - return checkCollisionPointRec(*(*uintptr)(unsafe.Pointer(&point)), uintptr(unsafe.Pointer(&rec))) -} - -// CheckCollisionPointCircle - Check if point is inside circle -func CheckCollisionPointCircle(point Vector2, center Vector2, radius float32) bool { - return checkCollisionPointCircle(*(*uintptr)(unsafe.Pointer(&point)), *(*uintptr)(unsafe.Pointer(¢er)), radius) -} - -// CheckCollisionPointTriangle - Check if point is inside a triangle -func CheckCollisionPointTriangle(point Vector2, p1 Vector2, p2 Vector2, p3 Vector2) bool { - return checkCollisionPointTriangle(*(*uintptr)(unsafe.Pointer(&point)), *(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), *(*uintptr)(unsafe.Pointer(&p3))) -} - -// CheckCollisionPointPoly - Check if point is within a polygon described by array of vertices -func CheckCollisionPointPoly(point Vector2, points []Vector2) bool { - pointCount := int32(len(points)) - return checkCollisionPointPoly(*(*uintptr)(unsafe.Pointer(&point)), unsafe.SliceData(points), pointCount) -} - -// CheckCollisionLines - Check the collision between two lines defined by two points each, returns collision point by reference -func CheckCollisionLines(startPos1 Vector2, endPos1 Vector2, startPos2 Vector2, endPos2 Vector2, collisionPoint *Vector2) bool { - return checkCollisionLines(*(*uintptr)(unsafe.Pointer(&startPos1)), *(*uintptr)(unsafe.Pointer(&endPos1)), *(*uintptr)(unsafe.Pointer(&startPos2)), *(*uintptr)(unsafe.Pointer(&endPos2)), collisionPoint) -} - -// CheckCollisionPointLine - Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] -func CheckCollisionPointLine(point Vector2, p1 Vector2, p2 Vector2, threshold int32) bool { - return checkCollisionPointLine(*(*uintptr)(unsafe.Pointer(&point)), *(*uintptr)(unsafe.Pointer(&p1)), *(*uintptr)(unsafe.Pointer(&p2)), threshold) -} - -// GetCollisionRec - Get collision rectangle for two rectangles collision -func GetCollisionRec(rec1 Rectangle, rec2 Rectangle) Rectangle { - var rec Rectangle - getCollisionRec(uintptr(unsafe.Pointer(&rec)), uintptr(unsafe.Pointer(&rec1)), uintptr(unsafe.Pointer(&rec2))) - return rec -} - -// LoadImage - Load image from file into CPU memory (RAM) -func LoadImage(fileName string) *Image { - var img Image - loadImage(uintptr(unsafe.Pointer(&img)), fileName) - return &img -} - -// LoadImageRaw - Load image from RAW file data -func LoadImageRaw(fileName string, width int32, height int32, format PixelFormat, headerSize int32) *Image { - var img Image - loadImageRaw(uintptr(unsafe.Pointer(&img)), fileName, width, height, int32(format), headerSize) - return &img -} - -// LoadImageAnim - Load image sequence from file (frames appended to image.data) -func LoadImageAnim(fileName string, frames *int32) *Image { - var img Image - loadImageAnim(uintptr(unsafe.Pointer(&img)), fileName, frames) - return &img -} - -// LoadImageAnimFromMemory - Load image sequence from memory buffer -func LoadImageAnimFromMemory(fileType string, fileData []byte, dataSize int32, frames *int32) *Image { - var img Image - loadImageAnimFromMemory(uintptr(unsafe.Pointer(&img)), fileType, fileData, dataSize, frames) - return &img -} - -// LoadImageFromMemory - Load image from memory buffer, fileType refers to extension: i.e. '.png' -func LoadImageFromMemory(fileType string, fileData []byte, dataSize int32) *Image { - var img Image - loadImageFromMemory(uintptr(unsafe.Pointer(&img)), fileType, fileData, dataSize) - return &img -} - -// LoadImageFromTexture - Load image from GPU texture data -func LoadImageFromTexture(texture Texture2D) *Image { - var img Image - loadImageFromTexture(uintptr(unsafe.Pointer(&img)), uintptr(unsafe.Pointer(&texture))) - return &img -} - -// LoadImageFromScreen - Load image from screen buffer and (screenshot) -func LoadImageFromScreen() *Image { - var img Image - loadImageFromScreen(uintptr(unsafe.Pointer(&img))) - return &img -} - -// IsImageValid - Check if an image is valid (data and parameters) -func IsImageValid(image *Image) bool { - return isImageValid(uintptr(unsafe.Pointer(image))) -} - -// UnloadImage - Unload image from CPU memory (RAM) -func UnloadImage(image *Image) { - unloadImage(uintptr(unsafe.Pointer(image))) -} - -// ExportImage - Export image data to file, returns true on success -func ExportImage(image Image, fileName string) bool { - return exportImage(uintptr(unsafe.Pointer(&image)), fileName) -} - -// ExportImageToMemory - Export image to memory buffer -func ExportImageToMemory(image Image, fileType string) []byte { - var fileSize int32 - ret := exportImageToMemory(uintptr(unsafe.Pointer(&image)), fileType, &fileSize) - return unsafe.Slice(ret, fileSize) -} - -// GenImageColor - Generate image: plain color -func GenImageColor(width int, height int, col color.RGBA) *Image { - var image Image - genImageColor(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), *(*uintptr)(unsafe.Pointer(&col))) - return &image -} - -// GenImageGradientLinear - Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient -func GenImageGradientLinear(width int, height int, direction int, start color.RGBA, end color.RGBA) *Image { - var image Image - genImageGradientLinear(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), int32(direction), *(*uintptr)(unsafe.Pointer(&start)), *(*uintptr)(unsafe.Pointer(&end))) - return &image -} - -// GenImageGradientRadial - Generate image: radial gradient -func GenImageGradientRadial(width int, height int, density float32, inner color.RGBA, outer color.RGBA) *Image { - var image Image - genImageGradientRadial(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), density, *(*uintptr)(unsafe.Pointer(&inner)), *(*uintptr)(unsafe.Pointer(&outer))) - return &image -} - -// GenImageGradientSquare - Generate image: square gradient -func GenImageGradientSquare(width int, height int, density float32, inner color.RGBA, outer color.RGBA) *Image { - var image Image - genImageGradientSquare(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), density, *(*uintptr)(unsafe.Pointer(&inner)), *(*uintptr)(unsafe.Pointer(&outer))) - return &image -} - -// GenImageChecked - Generate image: checked -func GenImageChecked(width int, height int, checksX int, checksY int, col1 color.RGBA, col2 color.RGBA) *Image { - var image Image - genImageChecked(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), int32(checksX), int32(checksY), *(*uintptr)(unsafe.Pointer(&col1)), *(*uintptr)(unsafe.Pointer(&col2))) - return &image -} - -// GenImageWhiteNoise - Generate image: white noise -func GenImageWhiteNoise(width int, height int, factor float32) *Image { - var image Image - genImageWhiteNoise(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), factor) - return &image -} - -// GenImagePerlinNoise - Generate image: perlin noise -func GenImagePerlinNoise(width int, height int, offsetX int32, offsetY int32, scale float32) *Image { - var image Image - genImagePerlinNoise(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), offsetX, offsetY, scale) - return &image -} - -// GenImageCellular - Generate image: cellular algorithm, bigger tileSize means bigger cells -func GenImageCellular(width int, height int, tileSize int) *Image { - var image Image - genImageCellular(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), int32(tileSize)) - return &image -} - -// GenImageText - Generate image: grayscale image from text data -func GenImageText(width int, height int, text string) Image { - var image Image - genImageText(uintptr(unsafe.Pointer(&image)), int32(width), int32(height), text) - return image -} - -// ImageCopy - Create an image duplicate (useful for transformations) -func ImageCopy(image *Image) *Image { - var retImage Image - imageCopy(uintptr(unsafe.Pointer(&retImage)), uintptr(unsafe.Pointer(image))) - return &retImage -} - -// ImageFromImage - Create an image from another image piece -func ImageFromImage(image Image, rec Rectangle) Image { - var retImage Image - imageFromImage(uintptr(unsafe.Pointer(&retImage)), uintptr(unsafe.Pointer(&image)), uintptr(unsafe.Pointer(&rec))) - return retImage -} - -// ImageFromChannel - Create an image from a selected channel of another image (GRAYSCALE) -func ImageFromChannel(image Image, selectedChannel int32) Image { - var retImage Image - imageFromChannel(uintptr(unsafe.Pointer(&retImage)), uintptr(unsafe.Pointer(&image)), selectedChannel) - return retImage -} - -// ImageText - Create an image from text (default font) -func ImageText(text string, fontSize int32, col color.RGBA) Image { - var retImage Image - imageText(uintptr(unsafe.Pointer(&retImage)), text, fontSize, *(*uintptr)(unsafe.Pointer(&col))) - return retImage -} - -// ImageTextEx - Create an image from text (custom sprite font) -func ImageTextEx(font Font, text string, fontSize float32, spacing float32, tint color.RGBA) Image { - var retImage Image - imageTextEx(uintptr(unsafe.Pointer(&retImage)), uintptr(unsafe.Pointer(&font)), text, fontSize, spacing, *(*uintptr)(unsafe.Pointer(&tint))) - return retImage -} - -// ImageFormat - Convert image data to desired format -func ImageFormat(image *Image, newFormat PixelFormat) { - imageFormat(image, int32(newFormat)) -} - -// ImageToPOT - Convert image to POT (power-of-two) -func ImageToPOT(image *Image, fill color.RGBA) { - imageToPOT(image, *(*uintptr)(unsafe.Pointer(&fill))) -} - -// ImageCrop - Crop an image to a defined rectangle -func ImageCrop(image *Image, crop Rectangle) { - imageCrop(image, uintptr(unsafe.Pointer(&crop))) -} - -// ImageAlphaCrop - Crop image depending on alpha value -func ImageAlphaCrop(image *Image, threshold float32) { - imageAlphaCrop(image, threshold) -} - -// ImageAlphaClear - Clear alpha channel to desired color -func ImageAlphaClear(image *Image, col color.RGBA, threshold float32) { - imageAlphaClear(image, *(*uintptr)(unsafe.Pointer(&col)), threshold) -} - -// ImageAlphaMask - Apply alpha mask to image -func ImageAlphaMask(image *Image, alphaMask *Image) { - imageAlphaMask(image, uintptr(unsafe.Pointer(alphaMask))) -} - -// ImageAlphaPremultiply - Premultiply alpha channel -func ImageAlphaPremultiply(image *Image) { - imageAlphaPremultiply(image) -} - -// ImageBlurGaussian - Apply Gaussian blur using a box blur approximation -func ImageBlurGaussian(image *Image, blurSize int32) { - imageBlurGaussian(image, blurSize) -} - -// ImageKernelConvolution - Apply custom square convolution kernel to image -func ImageKernelConvolution(image *Image, kernel []float32) { - imageKernelConvolution(image, kernel, int32(len(kernel))) -} - -// ImageResize - Resize image (Bicubic scaling algorithm) -func ImageResize(image *Image, newWidth int32, newHeight int32) { - imageResize(image, newWidth, newHeight) -} - -// ImageResizeNN - Resize image (Nearest-Neighbor scaling algorithm) -func ImageResizeNN(image *Image, newWidth int32, newHeight int32) { - imageResizeNN(image, newWidth, newHeight) -} - -// ImageResizeCanvas - Resize canvas and fill with color -func ImageResizeCanvas(image *Image, newWidth int32, newHeight int32, offsetX int32, offsetY int32, fill color.RGBA) { - imageResizeCanvas(image, newWidth, newHeight, offsetX, offsetY, *(*uintptr)(unsafe.Pointer(&fill))) -} - -// ImageMipmaps - Compute all mipmap levels for a provided image -func ImageMipmaps(image *Image) { - imageMipmaps(image) -} - -// ImageDither - Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -func ImageDither(image *Image, rBpp int32, gBpp int32, bBpp int32, aBpp int32) { - imageDither(image, rBpp, gBpp, bBpp, aBpp) -} - -// ImageFlipVertical - Flip image vertically -func ImageFlipVertical(image *Image) { - imageFlipVertical(image) -} - -// ImageFlipHorizontal - Flip image horizontally -func ImageFlipHorizontal(image *Image) { - imageFlipHorizontal(image) -} - -// ImageRotate - Rotate image by input angle in degrees (-359 to 359) -func ImageRotate(image *Image, degrees int32) { - imageRotate(image, degrees) -} - -// ImageRotateCW - Rotate image clockwise 90deg -func ImageRotateCW(image *Image) { - imageRotateCW(image) -} - -// ImageRotateCCW - Rotate image counter-clockwise 90deg -func ImageRotateCCW(image *Image) { - imageRotateCCW(image) -} - -// ImageColorTint - Modify image color: tint -func ImageColorTint(image *Image, col color.RGBA) { - imageColorTint(image, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageColorInvert - Modify image color: invert -func ImageColorInvert(image *Image) { - imageColorInvert(image) -} - -// ImageColorGrayscale - Modify image color: grayscale -func ImageColorGrayscale(image *Image) { - imageColorGrayscale(image) -} - -// ImageColorContrast - Modify image color: contrast (-100 to 100) -func ImageColorContrast(image *Image, contrast float32) { - imageColorContrast(image, contrast) -} - -// ImageColorBrightness - Modify image color: brightness (-255 to 255) -func ImageColorBrightness(image *Image, brightness int32) { - imageColorBrightness(image, brightness) -} - -// ImageColorReplace - Modify image color: replace color -func ImageColorReplace(image *Image, col color.RGBA, replace color.RGBA) { - imageColorReplace(image, *(*uintptr)(unsafe.Pointer(&col)), *(*uintptr)(unsafe.Pointer(&replace))) -} - -// LoadImageColors - Load color data from image as a Color array (RGBA - 32bit) -// -// NOTE: Memory allocated should be freed using UnloadImageColors() -func LoadImageColors(image *Image) []color.RGBA { - ret := loadImageColors(uintptr(unsafe.Pointer(image))) - return unsafe.Slice(ret, image.Width*image.Height) -} - -// LoadImagePalette - Load colors palette from image as a Color array (RGBA - 32bit) -// -// NOTE: Memory allocated should be freed using UnloadImagePalette() -func LoadImagePalette(image Image, maxPaletteSize int32) []color.RGBA { - var colorCount int32 - ret := loadImagePalette(uintptr(unsafe.Pointer(&image)), maxPaletteSize, &colorCount) - return unsafe.Slice(ret, colorCount) -} - -// UnloadImageColors - Unload color data loaded with LoadImageColors() -func UnloadImageColors(colors []color.RGBA) { - unloadImageColors(unsafe.SliceData(colors)) -} - -// UnloadImagePalette - Unload colors palette loaded with LoadImagePalette() -func UnloadImagePalette(colors []color.RGBA) { - unloadImagePalette(unsafe.SliceData(colors)) -} - -// GetImageAlphaBorder - Get image alpha border rectangle -func GetImageAlphaBorder(image Image, threshold float32) Rectangle { - var rec Rectangle - getImageAlphaBorder(uintptr(unsafe.Pointer(&rec)), uintptr(unsafe.Pointer(&image)), threshold) - return rec -} - -// GetImageColor - Get image pixel color at (x, y) position -func GetImageColor(image Image, x int32, y int32) color.RGBA { - ret := getImageColor(uintptr(unsafe.Pointer(&image)), x, y) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ImageClearBackground - Clear image background with given color -func ImageClearBackground(dst *Image, col color.RGBA) { - imageClearBackground(dst, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawPixel - Draw pixel within an image -func ImageDrawPixel(dst *Image, posX int32, posY int32, col color.RGBA) { - imageDrawPixel(dst, posX, posY, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawPixelV - Draw pixel within an image (Vector version) -func ImageDrawPixelV(dst *Image, position Vector2, col color.RGBA) { - imageDrawPixelV(dst, *(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawLine - Draw line within an image -func ImageDrawLine(dst *Image, startPosX int32, startPosY int32, endPosX int32, endPosY int32, col color.RGBA) { - imageDrawLine(dst, startPosX, startPosY, endPosX, endPosY, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawLineV - Draw line within an image (Vector version) -func ImageDrawLineV(dst *Image, start, end Vector2, col color.RGBA) { - imageDrawLineV(dst, *(*uintptr)(unsafe.Pointer(&start)), *(*uintptr)(unsafe.Pointer(&end)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawLineEx - Draw a line defining thickness within an image -func ImageDrawLineEx(dst *Image, start, end Vector2, thick int32, col color.RGBA) { - imageDrawLineEx(dst, *(*uintptr)(unsafe.Pointer(&start)), *(*uintptr)(unsafe.Pointer(&end)), thick, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawCircle - Draw a filled circle within an image -func ImageDrawCircle(dst *Image, centerX int32, centerY int32, radius int32, col color.RGBA) { - imageDrawCircle(dst, centerX, centerY, radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawCircleV - Draw a filled circle within an image (Vector version) -func ImageDrawCircleV(dst *Image, center Vector2, radius int32, col color.RGBA) { - imageDrawCircleV(dst, *(*uintptr)(unsafe.Pointer(¢er)), radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawCircleLines - Draw circle outline within an image -func ImageDrawCircleLines(dst *Image, centerX int32, centerY int32, radius int32, col color.RGBA) { - imageDrawCircleLines(dst, centerX, centerY, radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawCircleLinesV - Draw circle outline within an image (Vector version) -func ImageDrawCircleLinesV(dst *Image, center Vector2, radius int32, col color.RGBA) { - imageDrawCircleLinesV(dst, *(*uintptr)(unsafe.Pointer(¢er)), radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawRectangle - Draw rectangle within an image -func ImageDrawRectangle(dst *Image, posX int32, posY int32, width int32, height int32, col color.RGBA) { - imageDrawRectangle(dst, posX, posY, width, height, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawRectangleV - Draw rectangle within an image (Vector version) -func ImageDrawRectangleV(dst *Image, position Vector2, size Vector2, col color.RGBA) { - imageDrawRectangleV(dst, *(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawRectangleRec - Draw rectangle within an image -func ImageDrawRectangleRec(dst *Image, rec Rectangle, col color.RGBA) { - imageDrawRectangleRec(dst, uintptr(unsafe.Pointer(&rec)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawRectangleLines - Draw rectangle lines within an image -func ImageDrawRectangleLines(dst *Image, rec Rectangle, thick int, col color.RGBA) { - imageDrawRectangleLines(dst, uintptr(unsafe.Pointer(&rec)), int32(thick), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawTriangle - Draw triangle within an image -func ImageDrawTriangle(dst *Image, v1, v2, v3 Vector2, col color.RGBA) { - imageDrawTriangle(dst, *(*uintptr)(unsafe.Pointer(&v1)), *(*uintptr)(unsafe.Pointer(&v2)), *(*uintptr)(unsafe.Pointer(&v3)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawTriangleEx - Draw triangle with interpolated colors within an image -func ImageDrawTriangleEx(dst *Image, v1, v2, v3 Vector2, c1, c2, c3 color.RGBA) { - imageDrawTriangleEx(dst, *(*uintptr)(unsafe.Pointer(&v1)), *(*uintptr)(unsafe.Pointer(&v2)), *(*uintptr)(unsafe.Pointer(&v3)), *(*uintptr)(unsafe.Pointer(&c1)), *(*uintptr)(unsafe.Pointer(&c2)), *(*uintptr)(unsafe.Pointer(&c3))) -} - -// ImageDrawTriangleLines - Draw triangle outline within an image -func ImageDrawTriangleLines(dst *Image, v1, v2, v3 Vector2, col color.RGBA) { - imageDrawTriangleLines(dst, *(*uintptr)(unsafe.Pointer(&v1)), *(*uintptr)(unsafe.Pointer(&v2)), *(*uintptr)(unsafe.Pointer(&v3)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawTriangleFan - Draw a triangle fan defined by points within an image (first vertex is the center) -func ImageDrawTriangleFan(dst *Image, points []Vector2, col color.RGBA) { - pointCount := int32(len(points)) - imageDrawTriangleFan(dst, (unsafe.SliceData(points)), pointCount, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDrawTriangleStrip - Draw a triangle strip defined by points within an image -func ImageDrawTriangleStrip(dst *Image, points []Vector2, col color.RGBA) { - pointCount := int32(len(points)) - imageDrawTriangleStrip(dst, (unsafe.SliceData(points)), pointCount, *(*uintptr)(unsafe.Pointer(&col))) -} - -// ImageDraw - Draw a source image within a destination image (tint applied to source) -func ImageDraw(dst *Image, src *Image, srcRec Rectangle, dstRec Rectangle, tint color.RGBA) { - imageDraw(dst, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(&srcRec)), uintptr(unsafe.Pointer(&dstRec)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// ImageDrawText - Draw text (using default font) within an image (destination) -func ImageDrawText(dst *Image, posX int32, posY int32, text string, fontSize int32, col color.RGBA) { - imageDrawText(dst, text, posX, posY, fontSize, *(*uintptr)(unsafe.Pointer(&col))) - -} - -// ImageDrawTextEx - Draw text (custom sprite font) within an image (destination) -func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontSize float32, spacing float32, tint color.RGBA) { - imageDrawTextEx(dst, uintptr(unsafe.Pointer(&font)), text, *(*uintptr)(unsafe.Pointer(&position)), fontSize, spacing, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// LoadTexture - Load texture from file into GPU memory (VRAM) -func LoadTexture(fileName string) Texture2D { - var texture Texture2D - loadTexture(uintptr(unsafe.Pointer(&texture)), fileName) - return texture -} - -// LoadTextureFromImage - Load texture from image data -func LoadTextureFromImage(image *Image) Texture2D { - var texture Texture2D - loadTextureFromImage(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(image))) - return texture -} - -// LoadTextureCubemap - Load cubemap from image, multiple image cubemap layouts supported -func LoadTextureCubemap(image *Image, layout int32) Texture2D { - var texture Texture2D - loadTextureCubemap(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(image)), layout) - return texture -} - -// LoadRenderTexture - Load texture for rendering (framebuffer) -func LoadRenderTexture(width int32, height int32) RenderTexture2D { - var texture RenderTexture2D - loadRenderTexture(uintptr(unsafe.Pointer(&texture)), width, height) - return texture -} - -// IsTextureValid - Check if a texture is valid (loaded in GPU) -func IsTextureValid(texture Texture2D) bool { - return isTextureValid(uintptr(unsafe.Pointer(&texture))) -} - -// UnloadTexture - Unload texture from GPU memory (VRAM) -func UnloadTexture(texture Texture2D) { - unloadTexture(uintptr(unsafe.Pointer(&texture))) -} - -// IsRenderTextureValid - Check if a render texture is valid (loaded in GPU) -func IsRenderTextureValid(target RenderTexture2D) bool { - return isRenderTextureValid(uintptr(unsafe.Pointer(&target))) -} - -// UnloadRenderTexture - Unload render texture from GPU memory (VRAM) -func UnloadRenderTexture(target RenderTexture2D) { - unloadRenderTexture(uintptr(unsafe.Pointer(&target))) -} - -// UpdateTexture - Update GPU texture with new data -func UpdateTexture(texture Texture2D, pixels []color.RGBA) { - updateTexture(uintptr(unsafe.Pointer(&texture)), unsafe.SliceData(pixels)) -} - -// UpdateTextureRec - Update GPU texture rectangle with new data -func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []color.RGBA) { - updateTextureRec(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&rec)), unsafe.SliceData(pixels)) -} - -// GenTextureMipmaps - Generate GPU mipmaps for a texture -func GenTextureMipmaps(texture *Texture2D) { - genTextureMipmaps(texture) -} - -// SetTextureFilter - Set texture scaling filter mode -func SetTextureFilter(texture Texture2D, filter TextureFilterMode) { - setTextureFilter(uintptr(unsafe.Pointer(&texture)), int32(filter)) -} - -// SetTextureWrap - Set texture wrapping mode -func SetTextureWrap(texture Texture2D, wrap TextureWrapMode) { - setTextureWrap(uintptr(unsafe.Pointer(&texture)), int32(wrap)) -} - -// DrawTexture - Draw a Texture2D -func DrawTexture(texture Texture2D, posX int32, posY int32, tint color.RGBA) { - drawTexture(uintptr(unsafe.Pointer(&texture)), posX, posY, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextureV - Draw a Texture2D with position defined as Vector2 -func DrawTextureV(texture Texture2D, position Vector2, tint color.RGBA) { - drawTextureV(uintptr(unsafe.Pointer(&texture)), *(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextureEx - Draw a Texture2D with extended parameters -func DrawTextureEx(texture Texture2D, position Vector2, rotation float32, scale float32, tint color.RGBA) { - drawTextureEx(uintptr(unsafe.Pointer(&texture)), *(*uintptr)(unsafe.Pointer(&position)), rotation, scale, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextureRec - Draw a part of a texture defined by a rectangle -func DrawTextureRec(texture Texture2D, source Rectangle, position Vector2, tint color.RGBA) { - drawTextureRec(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&source)), *(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTexturePro - Draw a part of a texture defined by a rectangle with 'pro' parameters -func DrawTexturePro(texture Texture2D, source Rectangle, dest Rectangle, origin Vector2, rotation float32, tint color.RGBA) { - drawTexturePro(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&source)), uintptr(unsafe.Pointer(&dest)), *(*uintptr)(unsafe.Pointer(&origin)), rotation, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextureNPatch - Draws a texture (or part of it) that stretches or shrinks nicely -func DrawTextureNPatch(texture Texture2D, nPatchInfo NPatchInfo, dest Rectangle, origin Vector2, rotation float32, tint color.RGBA) { - drawTextureNPatch(uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&nPatchInfo)), uintptr(unsafe.Pointer(&dest)), *(*uintptr)(unsafe.Pointer(&origin)), rotation, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// Fade - Get color with alpha applied, alpha goes from 0.0f to 1.0f -func Fade(col color.RGBA, alpha float32) color.RGBA { - ret := fade(*(*uintptr)(unsafe.Pointer(&col)), alpha) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorToInt - Get hexadecimal value for a Color (0xRRGGBBAA) -func ColorToInt(col color.RGBA) int32 { - return colorToInt(*(*uintptr)(unsafe.Pointer(&col))) -} - -// ColorNormalize - Get Color normalized as float [0..1] -func ColorNormalize(col color.RGBA) Vector4 { - var vector4 Vector4 - colorNormalize(uintptr(unsafe.Pointer(&vector4)), *(*uintptr)(unsafe.Pointer(&col))) - return vector4 -} - -// ColorFromNormalized - Get Color from normalized values [0..1] -func ColorFromNormalized(normalized Vector4) color.RGBA { - ret := colorFromNormalized(uintptr(unsafe.Pointer(&normalized))) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorToHSV - Get HSV values for a Color, hue [0..360], saturation/value [0..1] -func ColorToHSV(col color.RGBA) Vector3 { - var vector3 Vector3 - colorToHSV(uintptr(unsafe.Pointer(&vector3)), *(*uintptr)(unsafe.Pointer(&col))) - return vector3 -} - -// ColorFromHSV - Get a Color from HSV values, hue [0..360], saturation/value [0..1] -func ColorFromHSV(hue float32, saturation float32, value float32) color.RGBA { - ret := colorFromHSV(hue, saturation, value) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorTint - Get color multiplied with another color -func ColorTint(col color.RGBA, tint color.RGBA) color.RGBA { - ret := colorTint(*(*uintptr)(unsafe.Pointer(&col)), *(*uintptr)(unsafe.Pointer(&tint))) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorBrightness - Get color with brightness correction, brightness factor goes from -1.0f to 1.0f -func ColorBrightness(col color.RGBA, factor float32) color.RGBA { - ret := colorBrightness(*(*uintptr)(unsafe.Pointer(&col)), factor) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorContrast - Get color with contrast correction, contrast values between -1.0f and 1.0f -func ColorContrast(col color.RGBA, contrast float32) color.RGBA { - ret := colorContrast(*(*uintptr)(unsafe.Pointer(&col)), contrast) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorAlpha - Get color with alpha applied, alpha goes from 0.0f to 1.0f -func ColorAlpha(col color.RGBA, alpha float32) color.RGBA { - ret := colorAlpha(*(*uintptr)(unsafe.Pointer(&col)), alpha) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorAlphaBlend - Get src alpha-blended into dst color with tint -func ColorAlphaBlend(dst color.RGBA, src color.RGBA, tint color.RGBA) color.RGBA { - ret := colorAlphaBlend(*(*uintptr)(unsafe.Pointer(&dst)), *(*uintptr)(unsafe.Pointer(&src)), *(*uintptr)(unsafe.Pointer(&tint))) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// ColorLerp - Get color lerp interpolation between two colors, factor [0.0f..1.0f] -func ColorLerp(col1, col2 color.RGBA, factor float32) color.RGBA { - ret := colorLerp(*(*uintptr)(unsafe.Pointer(&col1)), *(*uintptr)(unsafe.Pointer(&col2)), factor) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// GetColor - Get Color structure from hexadecimal value -func GetColor(hexValue uint) color.RGBA { - ret := getColor(uint32(hexValue)) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// GetPixelColor - Get Color from a source pixel pointer of certain format -func GetPixelColor(srcPtr unsafe.Pointer, format int32) color.RGBA { - ret := getPixelColor(srcPtr, format) - return *(*color.RGBA)(unsafe.Pointer(&ret)) -} - -// SetPixelColor - Set color formatted into destination pixel pointer -func SetPixelColor(dstPtr unsafe.Pointer, col color.RGBA, format int32) { - setPixelColor(dstPtr, *(*uintptr)(unsafe.Pointer(&col)), format) -} - -// GetPixelDataSize - Get pixel data size in bytes for certain format -func GetPixelDataSize(width int32, height int32, format int32) int32 { - return getPixelDataSize(width, height, format) -} - -// GetFontDefault - Get the default Font -func GetFontDefault() Font { - var font Font - getFontDefault(uintptr(unsafe.Pointer(&font))) - return font -} - -// LoadFont - Load font from file into GPU memory (VRAM) -func LoadFont(fileName string) Font { - var font Font - loadFont(uintptr(unsafe.Pointer(&font)), fileName) - return font -} - -// LoadFontEx - Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont -func LoadFontEx(fileName string, fontSize int32, codepoints []rune, runesNumber ...int32) Font { - var font Font - codepointCount := int32(len(codepoints)) - if len(runesNumber) > 0 { - codepointCount = int32(runesNumber[0]) - } - loadFontEx(uintptr(unsafe.Pointer(&font)), fileName, fontSize, codepoints, codepointCount) - return font -} - -// LoadFontFromImage - Load font from Image (XNA style) -func LoadFontFromImage(image Image, key color.RGBA, firstChar rune) Font { - var font Font - loadFontFromImage(uintptr(unsafe.Pointer(&font)), uintptr(unsafe.Pointer(&image)), *(*uintptr)(unsafe.Pointer(&key)), firstChar) - return font -} - -// LoadFontFromMemory - Load font from memory buffer, fileType refers to extension: i.e. '.ttf' -func LoadFontFromMemory(fileType string, fileData []byte, fontSize int32, codepoints []rune) Font { - var font Font - dataSize := int32(len(fileData)) - codepointCount := int32(len(codepoints)) - loadFontFromMemory(uintptr(unsafe.Pointer(&font)), fileType, fileData, dataSize, fontSize, codepoints, codepointCount) - return font -} - -// IsFontValid - Check if a font is valid (font data loaded, WARNING: GPU texture not checked) -func IsFontValid(font Font) bool { - return isFontValid(uintptr(unsafe.Pointer(&font))) -} - -// LoadFontData - Load font data for further use -func LoadFontData(fileData []byte, fontSize int32, codepoints []rune, codepointCount, typ int32) []GlyphInfo { - dataSize := int32(len(fileData)) - // In case no chars count provided, default to 95 - if codepointCount <= 0 { - codepointCount = 95 - } - ret := loadFontData(fileData, dataSize, fontSize, codepoints, codepointCount, typ) - return unsafe.Slice(ret, codepointCount) -} - -// GenImageFontAtlas - Generate image font atlas using chars info -func GenImageFontAtlas(glyphs []GlyphInfo, glyphRecs []*Rectangle, fontSize int32, padding int32, packMethod int32) Image { - var image Image - glyphCount := int32(len(glyphs)) - genImageFontAtlas(uintptr(unsafe.Pointer(&image)), unsafe.SliceData(glyphs), glyphRecs, glyphCount, fontSize, padding, packMethod) - return image -} - -// UnloadFontData - Unload font chars info data (RAM) -func UnloadFontData(glyphs []GlyphInfo) { - glyphCount := int32(len(glyphs)) - unloadFontData(unsafe.SliceData(glyphs), glyphCount) -} - -// UnloadFont - Unload font from GPU memory (VRAM) -func UnloadFont(font Font) { - unloadFont(uintptr(unsafe.Pointer(&font))) -} - -// DrawFPS - Draw current FPS -func DrawFPS(posX int32, posY int32) { - drawFPS(posX, posY) -} - -// DrawText - Draw text (using default font) -func DrawText(text string, posX int32, posY int32, fontSize int32, col color.RGBA) { - drawText(text, posX, posY, fontSize, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTextEx - Draw text using font and additional parameters -func DrawTextEx(font Font, text string, position Vector2, fontSize float32, spacing float32, tint color.RGBA) { - drawTextEx(uintptr(unsafe.Pointer(&font)), text, *(*uintptr)(unsafe.Pointer(&position)), fontSize, spacing, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextPro - Draw text using Font and pro parameters (rotation) -func DrawTextPro(font Font, text string, position Vector2, origin Vector2, rotation float32, fontSize float32, spacing float32, tint color.RGBA) { - drawTextPro(uintptr(unsafe.Pointer(&font)), text, *(*uintptr)(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&origin)), rotation, fontSize, spacing, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextCodepoint - Draw one character (codepoint) -func DrawTextCodepoint(font Font, codepoint rune, position Vector2, fontSize float32, tint color.RGBA) { - drawTextCodepoint(uintptr(unsafe.Pointer(&font)), codepoint, *(*uintptr)(unsafe.Pointer(&position)), fontSize, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawTextCodepoints - Draw multiple character (codepoint) -func DrawTextCodepoints(font Font, codepoints []rune, position Vector2, fontSize float32, spacing float32, tint color.RGBA) { - codepointCount := int32(len(codepoints)) - drawTextCodepoints(uintptr(unsafe.Pointer(&font)), codepoints, codepointCount, *(*uintptr)(unsafe.Pointer(&position)), fontSize, spacing, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// SetTextLineSpacing - Set vertical line spacing when drawing with line-breaks -func SetTextLineSpacing(spacing int) { - setTextLineSpacing(int32(spacing)) -} - -// MeasureText - Measure string width for default font -func MeasureText(text string, fontSize int32) int32 { - return measureText(text, fontSize) -} - -// MeasureTextEx - Measure string size for Font -func MeasureTextEx(font Font, text string, fontSize float32, spacing float32) Vector2 { - ret := measureTextEx(uintptr(unsafe.Pointer(&font)), text, fontSize, spacing) - return *(*Vector2)(unsafe.Pointer(&ret)) -} - -// GetGlyphIndex - Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found -func GetGlyphIndex(font Font, codepoint rune) int32 { - return getGlyphIndex(uintptr(unsafe.Pointer(&font)), codepoint) -} - -// GetGlyphInfo - Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found -func GetGlyphInfo(font Font, codepoint rune) GlyphInfo { - var glyphInfo GlyphInfo - getGlyphInfo(uintptr(unsafe.Pointer(&glyphInfo)), uintptr(unsafe.Pointer(&font)), codepoint) - return glyphInfo -} - -// GetGlyphAtlasRec - Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found -func GetGlyphAtlasRec(font Font, codepoint rune) Rectangle { - var rec Rectangle - getGlyphAtlasRec(uintptr(unsafe.Pointer(&rec)), uintptr(unsafe.Pointer(&font)), codepoint) - return rec -} - -// DrawLine3D - Draw a line in 3D world space -func DrawLine3D(startPos Vector3, endPos Vector3, col color.RGBA) { - drawLine3D(uintptr(unsafe.Pointer(&startPos)), uintptr(unsafe.Pointer(&endPos)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawPoint3D - Draw a point in 3D space, actually a small line -func DrawPoint3D(position Vector3, col color.RGBA) { - drawPoint3D(uintptr(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCircle3D - Draw a circle in 3D world space -func DrawCircle3D(center Vector3, radius float32, rotationAxis Vector3, rotationAngle float32, col color.RGBA) { - drawCircle3D(uintptr(unsafe.Pointer(¢er)), radius, uintptr(unsafe.Pointer(&rotationAxis)), rotationAngle, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTriangle3D - Draw a color-filled triangle (vertex in counter-clockwise order!) -func DrawTriangle3D(v1 Vector3, v2 Vector3, v3 Vector3, col color.RGBA) { - drawTriangle3D(uintptr(unsafe.Pointer(&v1)), uintptr(unsafe.Pointer(&v2)), uintptr(unsafe.Pointer(&v3)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawTriangleStrip3D - Draw a triangle strip defined by points -func DrawTriangleStrip3D(points []Vector3, col color.RGBA) { - pointCount := int32(len(points)) - drawTriangleStrip3D(unsafe.SliceData(points), pointCount, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCube - Draw cube -func DrawCube(position Vector3, width float32, height float32, length float32, col color.RGBA) { - drawCube(uintptr(unsafe.Pointer(&position)), width, height, length, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCubeV - Draw cube (Vector version) -func DrawCubeV(position Vector3, size Vector3, col color.RGBA) { - drawCubeV(uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCubeWires - Draw cube wires -func DrawCubeWires(position Vector3, width float32, height float32, length float32, col color.RGBA) { - drawCubeWires(uintptr(unsafe.Pointer(&position)), width, height, length, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCubeWiresV - Draw cube wires (Vector version) -func DrawCubeWiresV(position Vector3, size Vector3, col color.RGBA) { - drawCubeWiresV(uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSphere - Draw sphere -func DrawSphere(centerPos Vector3, radius float32, col color.RGBA) { - drawSphere(uintptr(unsafe.Pointer(¢erPos)), radius, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSphereEx - Draw sphere with extended parameters -func DrawSphereEx(centerPos Vector3, radius float32, rings int32, slices int32, col color.RGBA) { - drawSphereEx(uintptr(unsafe.Pointer(¢erPos)), radius, rings, slices, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawSphereWires - Draw sphere wires -func DrawSphereWires(centerPos Vector3, radius float32, rings int32, slices int32, col color.RGBA) { - drawSphereWires(uintptr(unsafe.Pointer(¢erPos)), radius, rings, slices, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCylinder - Draw a cylinder/cone -func DrawCylinder(position Vector3, radiusTop float32, radiusBottom float32, height float32, slices int32, col color.RGBA) { - drawCylinder(uintptr(unsafe.Pointer(&position)), radiusTop, radiusBottom, height, slices, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCylinderEx - Draw a cylinder with base at startPos and top at endPos -func DrawCylinderEx(startPos Vector3, endPos Vector3, startRadius float32, endRadius float32, sides int32, col color.RGBA) { - drawCylinderEx(uintptr(unsafe.Pointer(&startPos)), uintptr(unsafe.Pointer(&endPos)), startRadius, endRadius, sides, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCylinderWires - Draw a cylinder/cone wires -func DrawCylinderWires(position Vector3, radiusTop float32, radiusBottom float32, height float32, slices int32, col color.RGBA) { - drawCylinderWires(uintptr(unsafe.Pointer(&position)), radiusTop, radiusBottom, height, slices, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCylinderWiresEx - Draw a cylinder wires with base at startPos and top at endPos -func DrawCylinderWiresEx(startPos Vector3, endPos Vector3, startRadius float32, endRadius float32, sides int32, col color.RGBA) { - drawCylinderWiresEx(uintptr(unsafe.Pointer(&startPos)), uintptr(unsafe.Pointer(&endPos)), startRadius, endRadius, sides, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCapsule - Draw a capsule with the center of its sphere caps at startPos and endPos -func DrawCapsule(startPos Vector3, endPos Vector3, radius float32, slices int32, rings int32, col color.RGBA) { - drawCapsule(uintptr(unsafe.Pointer(&startPos)), uintptr(unsafe.Pointer(&endPos)), radius, slices, rings, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawCapsuleWires - Draw capsule wireframe with the center of its sphere caps at startPos and endPos -func DrawCapsuleWires(startPos Vector3, endPos Vector3, radius float32, slices int32, rings int32, col color.RGBA) { - drawCapsuleWires(uintptr(unsafe.Pointer(&startPos)), uintptr(unsafe.Pointer(&endPos)), radius, slices, rings, *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawPlane - Draw a plane XZ -func DrawPlane(centerPos Vector3, size Vector2, col color.RGBA) { - drawPlane(uintptr(unsafe.Pointer(¢erPos)), *(*uintptr)(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawRay - Draw a ray line -func DrawRay(ray Ray, col color.RGBA) { - drawRay(uintptr(unsafe.Pointer(&ray)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawGrid - Draw a grid (centered at (0, 0, 0)) -func DrawGrid(slices int32, spacing float32) { - drawGrid(slices, spacing) -} - -// LoadModel - Load model from files (meshes and materials) -func LoadModel(fileName string) Model { - var model Model - loadModel(uintptr(unsafe.Pointer(&model)), fileName) - return model -} - -// LoadModelFromMesh - Load model from generated mesh (default material) -func LoadModelFromMesh(mesh Mesh) Model { - var model Model - loadModelFromMesh(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&mesh))) - return model -} - -// IsModelValid - Check if a model is valid (loaded in GPU, VAO/VBOs) -func IsModelValid(model Model) bool { - return isModelValid(uintptr(unsafe.Pointer(&model))) -} - -// UnloadModel - Unload model (including meshes) from memory (RAM and/or VRAM) -func UnloadModel(model Model) { - unloadModel(uintptr(unsafe.Pointer(&model))) -} - -// GetModelBoundingBox - Compute model bounding box limits (considers all meshes) -func GetModelBoundingBox(model Model) BoundingBox { - var boundingBox BoundingBox - getModelBoundingBox(uintptr(unsafe.Pointer(&boundingBox)), uintptr(unsafe.Pointer(&model))) - return boundingBox -} - -// DrawModel - Draw a model (with texture if set) -func DrawModel(model Model, position Vector3, scale float32, tint color.RGBA) { - drawModel(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&position)), scale, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawModelEx - Draw a model with extended parameters -func DrawModelEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint color.RGBA) { - drawModelEx(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&rotationAxis)), rotationAngle, uintptr(unsafe.Pointer(&scale)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawModelWires - Draw a model wires (with texture if set) -func DrawModelWires(model Model, position Vector3, scale float32, tint color.RGBA) { - drawModelWires(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&position)), scale, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawModelWiresEx - Draw a model wires (with texture if set) with extended parameters -func DrawModelWiresEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint color.RGBA) { - drawModelWiresEx(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&rotationAxis)), rotationAngle, uintptr(unsafe.Pointer(&scale)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawModelPoints - Draw a model as points -func DrawModelPoints(model Model, position Vector3, scale float32, tint color.RGBA) { - drawModelPoints(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&position)), scale, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawModelPointsEx - Draw a model as points with extended parameters -func DrawModelPointsEx(model Model, position Vector3, rotationAxis Vector3, rotationAngle float32, scale Vector3, tint color.RGBA) { - drawModelPointsEx(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&rotationAxis)), rotationAngle, uintptr(unsafe.Pointer(&scale)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawBoundingBox - Draw bounding box (wires) -func DrawBoundingBox(box BoundingBox, col color.RGBA) { - drawBoundingBox(uintptr(unsafe.Pointer(&box)), *(*uintptr)(unsafe.Pointer(&col))) -} - -// DrawBillboard - Draw a billboard texture -func DrawBillboard(camera Camera, texture Texture2D, position Vector3, scale float32, tint color.RGBA) { - drawBillboard(uintptr(unsafe.Pointer(&camera)), uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&position)), scale, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawBillboardRec - Draw a billboard texture defined by source -func DrawBillboardRec(camera Camera, texture Texture2D, source Rectangle, position Vector3, size Vector2, tint color.RGBA) { - drawBillboardRec(uintptr(unsafe.Pointer(&camera)), uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&source)), uintptr(unsafe.Pointer(&position)), *(*uintptr)(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&tint))) -} - -// DrawBillboardPro - Draw a billboard texture defined by source and rotation -func DrawBillboardPro(camera Camera, texture Texture2D, source Rectangle, position Vector3, up Vector3, size Vector2, origin Vector2, rotation float32, tint color.RGBA) { - drawBillboardPro(uintptr(unsafe.Pointer(&camera)), uintptr(unsafe.Pointer(&texture)), uintptr(unsafe.Pointer(&source)), uintptr(unsafe.Pointer(&position)), uintptr(unsafe.Pointer(&up)), *(*uintptr)(unsafe.Pointer(&size)), *(*uintptr)(unsafe.Pointer(&origin)), rotation, *(*uintptr)(unsafe.Pointer(&tint))) -} - -// UploadMesh - Upload mesh vertex data in GPU and provide VAO/VBO ids -func UploadMesh(mesh *Mesh, dynamic bool) { - uploadMesh(mesh, dynamic) -} - -// UpdateMeshBuffer - Update mesh vertex data in GPU for a specific buffer index -func UpdateMeshBuffer(mesh Mesh, index int32, data []byte, offset int) { - dataSize := int32(len(data)) - updateMeshBuffer(uintptr(unsafe.Pointer(&mesh)), index, data, dataSize, int32(offset)) -} - -// UnloadMesh - Unload mesh data from CPU and GPU -func UnloadMesh(mesh *Mesh) { - unloadMesh(uintptr(unsafe.Pointer(mesh))) -} - -// DrawMesh - Draw a 3d mesh with material and transform -func DrawMesh(mesh Mesh, material Material, transform Matrix) { - drawMesh(uintptr(unsafe.Pointer(&mesh)), uintptr(unsafe.Pointer(&material)), uintptr(unsafe.Pointer(&transform))) -} - -// DrawMeshInstanced - Draw multiple mesh instances with material and different transforms -func DrawMeshInstanced(mesh Mesh, material Material, transforms []Matrix, instances int32) { - drawMeshInstanced(uintptr(unsafe.Pointer(&mesh)), uintptr(unsafe.Pointer(&material)), transforms, instances) -} - -// ExportMesh - Export mesh data to file, returns true on success -func ExportMesh(mesh Mesh, fileName string) bool { - return exportMesh(uintptr(unsafe.Pointer(&mesh)), fileName) -} - -// GetMeshBoundingBox - Compute mesh bounding box limits -func GetMeshBoundingBox(mesh Mesh) BoundingBox { - var boundingBox BoundingBox - getMeshBoundingBox(uintptr(unsafe.Pointer(&boundingBox)), uintptr(unsafe.Pointer(&mesh))) - return boundingBox -} - -// GenMeshTangents - Compute mesh tangents -func GenMeshTangents(mesh *Mesh) { - genMeshTangents(mesh) -} - -// GenMeshPoly - Generate polygonal mesh -func GenMeshPoly(sides int, radius float32) Mesh { - var mesh Mesh - genMeshPoly(uintptr(unsafe.Pointer(&mesh)), int32(sides), radius) - return mesh -} - -// GenMeshPlane - Generate plane mesh (with subdivisions) -func GenMeshPlane(width float32, length float32, resX int, resZ int) Mesh { - var mesh Mesh - genMeshPlane(uintptr(unsafe.Pointer(&mesh)), width, length, int32(resX), int32(resZ)) - return mesh -} - -// GenMeshCube - Generate cuboid mesh -func GenMeshCube(width float32, height float32, length float32) Mesh { - var mesh Mesh - genMeshCube(uintptr(unsafe.Pointer(&mesh)), width, height, length) - return mesh -} - -// GenMeshSphere - Generate sphere mesh (standard sphere) -func GenMeshSphere(radius float32, rings int, slices int) Mesh { - var mesh Mesh - genMeshSphere(uintptr(unsafe.Pointer(&mesh)), radius, int32(rings), int32(slices)) - return mesh -} - -// GenMeshHemiSphere - Generate half-sphere mesh (no bottom cap) -func GenMeshHemiSphere(radius float32, rings int, slices int) Mesh { - var mesh Mesh - genMeshHemiSphere(uintptr(unsafe.Pointer(&mesh)), radius, int32(rings), int32(slices)) - return mesh -} - -// GenMeshCylinder - Generate cylinder mesh -func GenMeshCylinder(radius float32, height float32, slices int) Mesh { - var mesh Mesh - genMeshCylinder(uintptr(unsafe.Pointer(&mesh)), radius, height, int32(slices)) - return mesh -} - -// GenMeshCone - Generate cone/pyramid mesh -func GenMeshCone(radius float32, height float32, slices int) Mesh { - var mesh Mesh - genMeshCone(uintptr(unsafe.Pointer(&mesh)), radius, height, int32(slices)) - return mesh -} - -// GenMeshTorus - Generate torus mesh -func GenMeshTorus(radius float32, size float32, radSeg int, sides int) Mesh { - var mesh Mesh - genMeshTorus(uintptr(unsafe.Pointer(&mesh)), radius, size, int32(radSeg), int32(sides)) - return mesh -} - -// GenMeshKnot - Generate trefoil knot mesh -func GenMeshKnot(radius float32, size float32, radSeg int, sides int) Mesh { - var mesh Mesh - genMeshKnot(uintptr(unsafe.Pointer(&mesh)), radius, size, int32(radSeg), int32(sides)) - return mesh -} - -// GenMeshHeightmap - Generate heightmap mesh from image data -func GenMeshHeightmap(heightmap Image, size Vector3) Mesh { - var mesh Mesh - genMeshHeightmap(uintptr(unsafe.Pointer(&mesh)), uintptr(unsafe.Pointer(&heightmap)), uintptr(unsafe.Pointer(&size))) - return mesh -} - -// GenMeshCubicmap - Generate cubes-based map mesh from image data -func GenMeshCubicmap(cubicmap Image, cubeSize Vector3) Mesh { - var mesh Mesh - genMeshCubicmap(uintptr(unsafe.Pointer(&mesh)), uintptr(unsafe.Pointer(&cubicmap)), uintptr(unsafe.Pointer(&cubeSize))) - return mesh -} - -// LoadMaterials - Load materials from model file -func LoadMaterials(fileName string) []Material { - var materialCount int32 - ret := loadMaterials(fileName, &materialCount) - return unsafe.Slice(ret, materialCount) -} - -// LoadMaterialDefault - Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -func LoadMaterialDefault() Material { - var material Material - loadMaterialDefault(uintptr(unsafe.Pointer(&material))) - return material -} - -// IsMaterialValid - Check if a material is valid (shader assigned, map textures loaded in GPU) -func IsMaterialValid(material Material) bool { - return isMaterialValid(uintptr(unsafe.Pointer(&material))) -} - -// UnloadMaterial - Unload material from GPU memory (VRAM) -func UnloadMaterial(material Material) { - unloadMaterial(uintptr(unsafe.Pointer(&material))) -} - -// SetMaterialTexture - Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) -func SetMaterialTexture(material *Material, mapType int32, texture Texture2D) { - setMaterialTexture(material, mapType, uintptr(unsafe.Pointer(&texture))) -} - -// SetModelMeshMaterial - Set material for a mesh -func SetModelMeshMaterial(model *Model, meshId int32, materialId int32) { - setModelMeshMaterial(model, meshId, materialId) -} - -// LoadModelAnimations - Load model animations from file -func LoadModelAnimations(fileName string) []ModelAnimation { - var animCount int32 - ret := loadModelAnimations(fileName, &animCount) - return unsafe.Slice(ret, animCount) -} - -// UpdateModelAnimation - Update model animation pose (CPU) -func UpdateModelAnimation(model Model, anim ModelAnimation, frame int32) { - updateModelAnimation(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&anim)), frame) -} - -// UpdateModelAnimationBones - Update model animation mesh bone matrices (GPU skinning) -func UpdateModelAnimationBones(model Model, anim ModelAnimation, frame int32) { - updateModelAnimationBones(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&anim)), frame) -} - -// UnloadModelAnimation - Unload animation data -func UnloadModelAnimation(anim ModelAnimation) { - unloadModelAnimation(uintptr(unsafe.Pointer(&anim))) -} - -// UnloadModelAnimations - Unload animation array data -func UnloadModelAnimations(animations []ModelAnimation) { - animCount := int32(len(animations)) - unloadModelAnimations(unsafe.SliceData(animations), animCount) -} - -// IsModelAnimationValid - Check model animation skeleton match -func IsModelAnimationValid(model Model, anim ModelAnimation) bool { - return isModelAnimationValid(uintptr(unsafe.Pointer(&model)), uintptr(unsafe.Pointer(&anim))) -} - -// CheckCollisionSpheres - Check collision between two spheres -func CheckCollisionSpheres(center1 Vector3, radius1 float32, center2 Vector3, radius2 float32) bool { - return checkCollisionSpheres(uintptr(unsafe.Pointer(¢er1)), radius1, uintptr(unsafe.Pointer(¢er2)), radius2) -} - -// CheckCollisionBoxes - Check collision between two bounding boxes -func CheckCollisionBoxes(box1 BoundingBox, box2 BoundingBox) bool { - return checkCollisionBoxes(uintptr(unsafe.Pointer(&box1)), uintptr(unsafe.Pointer(&box2))) -} - -// CheckCollisionBoxSphere - Check collision between box and sphere -func CheckCollisionBoxSphere(box BoundingBox, center Vector3, radius float32) bool { - return checkCollisionBoxSphere(uintptr(unsafe.Pointer(&box)), uintptr(unsafe.Pointer(¢er)), radius) -} - -// GetRayCollisionSphere - Get collision info between ray and sphere -func GetRayCollisionSphere(ray Ray, center Vector3, radius float32) RayCollision { - var rayCollision RayCollision - getRayCollisionSphere(uintptr(unsafe.Pointer(&rayCollision)), uintptr(unsafe.Pointer(&ray)), uintptr(unsafe.Pointer(¢er)), radius) - return rayCollision -} - -// GetRayCollisionBox - Get collision info between ray and box -func GetRayCollisionBox(ray Ray, box BoundingBox) RayCollision { - var rayCollision RayCollision - getRayCollisionBox(uintptr(unsafe.Pointer(&rayCollision)), uintptr(unsafe.Pointer(&ray)), uintptr(unsafe.Pointer(&box))) - return rayCollision -} - -// GetRayCollisionMesh - Get collision info between ray and mesh -func GetRayCollisionMesh(ray Ray, mesh Mesh, transform Matrix) RayCollision { - var rayCollision RayCollision - getRayCollisionMesh(uintptr(unsafe.Pointer(&rayCollision)), uintptr(unsafe.Pointer(&ray)), uintptr(unsafe.Pointer(&mesh)), uintptr(unsafe.Pointer(&transform))) - return rayCollision -} - -// GetRayCollisionTriangle - Get collision info between ray and triangle -func GetRayCollisionTriangle(ray Ray, p1 Vector3, p2 Vector3, p3 Vector3) RayCollision { - var rayCollision RayCollision - getRayCollisionTriangle(uintptr(unsafe.Pointer(&rayCollision)), uintptr(unsafe.Pointer(&ray)), uintptr(unsafe.Pointer(&p1)), uintptr(unsafe.Pointer(&p2)), uintptr(unsafe.Pointer(&p3))) - return rayCollision -} - -// GetRayCollisionQuad - Get collision info between ray and quad -func GetRayCollisionQuad(ray Ray, p1 Vector3, p2 Vector3, p3 Vector3, p4 Vector3) RayCollision { - var rayCollision RayCollision - getRayCollisionQuad(uintptr(unsafe.Pointer(&rayCollision)), uintptr(unsafe.Pointer(&ray)), uintptr(unsafe.Pointer(&p1)), uintptr(unsafe.Pointer(&p2)), uintptr(unsafe.Pointer(&p3)), uintptr(unsafe.Pointer(&p4))) - return rayCollision -} - -// InitAudioDevice - Initialize audio device and context -func InitAudioDevice() { - initAudioDevice() -} - -// CloseAudioDevice - Close the audio device and context -func CloseAudioDevice() { - closeAudioDevice() -} - -// IsAudioDeviceReady - Check if audio device has been initialized successfully -func IsAudioDeviceReady() bool { - return isAudioDeviceReady() -} - -// SetMasterVolume - Set master volume (listener) -func SetMasterVolume(volume float32) { - setMasterVolume(volume) -} - -// GetMasterVolume - Get master volume (listener) -func GetMasterVolume() float32 { - return getMasterVolume() -} - -// LoadWave - Load wave data from file -func LoadWave(fileName string) Wave { - var wave Wave - loadWave(uintptr(unsafe.Pointer(&wave)), fileName) - return wave -} - -// LoadWaveFromMemory - Load wave from memory buffer, fileType refers to extension: i.e. '.wav' -func LoadWaveFromMemory(fileType string, fileData []byte, dataSize int32) Wave { - var wave Wave - loadWaveFromMemory(uintptr(unsafe.Pointer(&wave)), fileType, fileData, dataSize) - return wave -} - -// IsWaveValid - Checks if wave data is valid (data loaded and parameters) -func IsWaveValid(wave Wave) bool { - return isWaveValid(uintptr(unsafe.Pointer(&wave))) -} - -// LoadSound - Load sound from file -func LoadSound(fileName string) Sound { - var sound Sound - loadSound(uintptr(unsafe.Pointer(&sound)), fileName) - return sound -} - -// LoadSoundFromWave - Load sound from wave data -func LoadSoundFromWave(wave Wave) Sound { - var sound Sound - loadSoundFromWave(uintptr(unsafe.Pointer(&sound)), uintptr(unsafe.Pointer(&wave))) - return sound -} - -// LoadSoundAlias - Create a new sound that shares the same sample data as the source sound, does not own the sound data -func LoadSoundAlias(source Sound) Sound { - var sound Sound - loadSoundAlias(uintptr(unsafe.Pointer(&sound)), uintptr(unsafe.Pointer(&source))) - return sound -} - -// IsSoundValid - Checks if a sound is valid (data loaded and buffers initialized) -func IsSoundValid(sound Sound) bool { - return isSoundValid(uintptr(unsafe.Pointer(&sound))) -} - -// UpdateSound - Update sound buffer with new data -func UpdateSound(sound Sound, data []byte, sampleCount int32) { - updateSound(uintptr(unsafe.Pointer(&sound)), data, sampleCount) -} - -// UnloadWave - Unload wave data -func UnloadWave(wave Wave) { - unloadWave(uintptr(unsafe.Pointer(&wave))) -} - -// UnloadSound - Unload sound -func UnloadSound(sound Sound) { - unloadSound(uintptr(unsafe.Pointer(&sound))) -} - -// UnloadSoundAlias - Unload a sound alias (does not deallocate sample data) -func UnloadSoundAlias(alias Sound) { - unloadSoundAlias(uintptr(unsafe.Pointer(&alias))) -} - -// ExportWave - Export wave data to file, returns true on success -func ExportWave(wave Wave, fileName string) bool { - return exportWave(uintptr(unsafe.Pointer(&wave)), fileName) -} - -// PlaySound - Play a sound -func PlaySound(sound Sound) { - playSound(uintptr(unsafe.Pointer(&sound))) -} - -// StopSound - Stop playing a sound -func StopSound(sound Sound) { - stopSound(uintptr(unsafe.Pointer(&sound))) -} - -// PauseSound - Pause a sound -func PauseSound(sound Sound) { - pauseSound(uintptr(unsafe.Pointer(&sound))) -} - -// ResumeSound - Resume a paused sound -func ResumeSound(sound Sound) { - resumeSound(uintptr(unsafe.Pointer(&sound))) -} - -// IsSoundPlaying - Check if a sound is currently playing -func IsSoundPlaying(sound Sound) bool { - return isSoundPlaying(uintptr(unsafe.Pointer(&sound))) -} - -// SetSoundVolume - Set volume for a sound (1.0 is max level) -func SetSoundVolume(sound Sound, volume float32) { - setSoundVolume(uintptr(unsafe.Pointer(&sound)), volume) -} - -// SetSoundPitch - Set pitch for a sound (1.0 is base level) -func SetSoundPitch(sound Sound, pitch float32) { - setSoundPitch(uintptr(unsafe.Pointer(&sound)), pitch) -} - -// SetSoundPan - Set pan for a sound (0.5 is center) -func SetSoundPan(sound Sound, pan float32) { - setSoundPan(uintptr(unsafe.Pointer(&sound)), pan) -} - -// WaveCopy - Copy a wave to a new wave -func WaveCopy(wave Wave) Wave { - var copy Wave - waveCopy(uintptr(unsafe.Pointer(©)), uintptr(unsafe.Pointer(&wave))) - return copy -} - -// WaveCrop - Crop a wave to defined frames range -func WaveCrop(wave *Wave, initFrame int32, finalFrame int32) { - waveCrop(wave, initFrame, finalFrame) -} - -// WaveFormat - Convert wave data to desired format -func WaveFormat(wave *Wave, sampleRate int32, sampleSize int32, channels int32) { - waveFormat(wave, sampleRate, sampleRate, channels) -} - -// LoadWaveSamples - Load samples data from wave as a 32bit float data array -func LoadWaveSamples(wave Wave) []float32 { - ret := loadWaveSamples(uintptr(unsafe.Pointer(&wave))) - return unsafe.Slice(ret, wave.FrameCount*wave.Channels) -} - -// UnloadWaveSamples - Unload samples data loaded with LoadWaveSamples() -func UnloadWaveSamples(samples []float32) { - unloadWaveSamples(samples) -} - -// LoadMusicStream - Load music stream from file -func LoadMusicStream(fileName string) Music { - var music Music - loadMusicStream(uintptr(unsafe.Pointer(&music)), fileName) - return music -} - -// LoadMusicStreamFromMemory - Load music stream from data -func LoadMusicStreamFromMemory(fileType string, data []byte, dataSize int32) Music { - var music Music - loadMusicStreamFromMemory(uintptr(unsafe.Pointer(&music)), fileType, data, dataSize) - return music -} - -// IsMusicValid - Checks if a music stream is valid (context and buffers initialized) -func IsMusicValid(music Music) bool { - return isMusicValid(uintptr(unsafe.Pointer(&music))) -} - -// UnloadMusicStream - Unload music stream -func UnloadMusicStream(music Music) { - unloadMusicStream(uintptr(unsafe.Pointer(&music))) -} - -// PlayMusicStream - Start music playing -func PlayMusicStream(music Music) { - playMusicStream(uintptr(unsafe.Pointer(&music))) -} - -// IsMusicStreamPlaying - Check if music is playing -func IsMusicStreamPlaying(music Music) bool { - return isMusicStreamPlaying(uintptr(unsafe.Pointer(&music))) -} - -// UpdateMusicStream - Updates buffers for music streaming -func UpdateMusicStream(music Music) { - updateMusicStream(uintptr(unsafe.Pointer(&music))) -} - -// StopMusicStream - Stop music playing -func StopMusicStream(music Music) { - stopMusicStream(uintptr(unsafe.Pointer(&music))) -} - -// PauseMusicStream - Pause music playing -func PauseMusicStream(music Music) { - pauseMusicStream(uintptr(unsafe.Pointer(&music))) -} - -// ResumeMusicStream - Resume playing paused music -func ResumeMusicStream(music Music) { - resumeMusicStream(uintptr(unsafe.Pointer(&music))) -} - -// SeekMusicStream - Seek music to a position (in seconds) -func SeekMusicStream(music Music, position float32) { - seekMusicStream(uintptr(unsafe.Pointer(&music)), position) -} - -// SetMusicVolume - Set volume for music (1.0 is max level) -func SetMusicVolume(music Music, volume float32) { - setMusicVolume(uintptr(unsafe.Pointer(&music)), volume) -} - -// SetMusicPitch - Set pitch for a music (1.0 is base level) -func SetMusicPitch(music Music, pitch float32) { - setMusicPitch(uintptr(unsafe.Pointer(&music)), pitch) -} - -// SetMusicPan - Set pan for a music (0.5 is center) -func SetMusicPan(music Music, pan float32) { - setMusicPan(uintptr(unsafe.Pointer(&music)), pan) -} - -// GetMusicTimeLength - Get music time length (in seconds) -func GetMusicTimeLength(music Music) float32 { - return getMusicTimeLength(uintptr(unsafe.Pointer(&music))) -} - -// GetMusicTimePlayed - Get current music time played (in seconds) -func GetMusicTimePlayed(music Music) float32 { - return getMusicTimePlayed(uintptr(unsafe.Pointer(&music))) -} - -// LoadAudioStream - Load audio stream (to stream raw audio pcm data) -func LoadAudioStream(sampleRate uint32, sampleSize uint32, channels uint32) AudioStream { - var audioStream AudioStream - loadAudioStream(uintptr(unsafe.Pointer(&audioStream)), sampleRate, sampleSize, channels) - return audioStream -} - -// IsAudioStreamValid - Checks if an audio stream is valid (buffers initialized) -func IsAudioStreamValid(stream AudioStream) bool { - return isAudioStreamValid(uintptr(unsafe.Pointer(&stream))) -} - -// UnloadAudioStream - Unload audio stream and free memory -func UnloadAudioStream(stream AudioStream) { - unloadAudioStream(uintptr(unsafe.Pointer(&stream))) -} - -// UpdateAudioStream - Update audio stream buffers with data -func UpdateAudioStream(stream AudioStream, data []float32) { - frameCount := int32(len(data)) - updateAudioStream(uintptr(unsafe.Pointer(&stream)), data, frameCount) -} - -// IsAudioStreamProcessed - Check if any audio stream buffers requires refill -func IsAudioStreamProcessed(stream AudioStream) bool { - return isAudioStreamProcessed(uintptr(unsafe.Pointer(&stream))) -} - -// PlayAudioStream - Play audio stream -func PlayAudioStream(stream AudioStream) { - playAudioStream(uintptr(unsafe.Pointer(&stream))) -} - -// PauseAudioStream - Pause audio stream -func PauseAudioStream(stream AudioStream) { - pauseAudioStream(uintptr(unsafe.Pointer(&stream))) -} - -// ResumeAudioStream - Resume audio stream -func ResumeAudioStream(stream AudioStream) { - resumeAudioStream(uintptr(unsafe.Pointer(&stream))) -} - -// IsAudioStreamPlaying - Check if audio stream is playing -func IsAudioStreamPlaying(stream AudioStream) bool { - return isAudioStreamPlaying(uintptr(unsafe.Pointer(&stream))) -} - -// StopAudioStream - Stop audio stream -func StopAudioStream(stream AudioStream) { - stopAudioStream(uintptr(unsafe.Pointer(&stream))) -} - -// SetAudioStreamVolume - Set volume for audio stream (1.0 is max level) -func SetAudioStreamVolume(stream AudioStream, volume float32) { - setAudioStreamVolume(uintptr(unsafe.Pointer(&stream)), volume) -} - -// SetAudioStreamPitch - Set pitch for audio stream (1.0 is base level) -func SetAudioStreamPitch(stream AudioStream, pitch float32) { - setAudioStreamPitch(uintptr(unsafe.Pointer(&stream)), pitch) -} - -// SetAudioStreamPan - Set pan for audio stream (0.5 is centered) -func SetAudioStreamPan(stream AudioStream, pan float32) { - setAudioStreamPan(uintptr(unsafe.Pointer(&stream)), pan) -} - -// SetAudioStreamBufferSizeDefault - Default size for new audio streams -func SetAudioStreamBufferSizeDefault(size int32) { - setAudioStreamBufferSizeDefault(size) -} - -// SetAudioStreamCallback - Audio thread callback to request new data -func SetAudioStreamCallback(stream AudioStream, callback AudioCallback) { - fn := purego.NewCallback(func(bufferData unsafe.Pointer, frames int32) uintptr { - callback(unsafe.Slice((*float32)(bufferData), frames), int(frames)) - return 0 - }) - setAudioStreamCallback(uintptr(unsafe.Pointer(&stream)), fn) -} - -// AttachAudioStreamProcessor - Attach audio stream processor to stream, receives the samples as s -func AttachAudioStreamProcessor(stream AudioStream, processor AudioCallback) { - fn := purego.NewCallback(func(bufferData unsafe.Pointer, frames int32) uintptr { - processor(unsafe.Slice((*float32)(bufferData), frames), int(frames)) - return 0 - }) - ptr := uintptr(reflect.ValueOf(processor).UnsafePointer()) - audioCallbacks[ptr] = fn - attachAudioStreamProcessor(uintptr(unsafe.Pointer(&stream)), fn) -} - -// DetachAudioStreamProcessor - Detach audio stream processor from stream -func DetachAudioStreamProcessor(stream AudioStream, processor AudioCallback) { - ptr := uintptr(reflect.ValueOf(processor).UnsafePointer()) - fn := audioCallbacks[ptr] - detachAudioStreamProcessor(uintptr(unsafe.Pointer(&stream)), fn) -} - -// AttachAudioMixedProcessor - Attach audio stream processor to the entire audio pipeline, receives the samples as s -func AttachAudioMixedProcessor(processor AudioCallback) { - fn := purego.NewCallback(func(bufferData unsafe.Pointer, frames int32) uintptr { - processor(unsafe.Slice((*float32)(bufferData), frames), int(frames)) - return 0 - }) - ptr := uintptr(reflect.ValueOf(processor).UnsafePointer()) - audioCallbacks[ptr] = fn - attachAudioMixedProcessor(fn) -} - -// DetachAudioMixedProcessor - Detach audio stream processor from the entire audio pipeline -func DetachAudioMixedProcessor(processor AudioCallback) { - ptr := uintptr(reflect.ValueOf(processor).UnsafePointer()) - fn := audioCallbacks[ptr] - detachAudioMixedProcessor(fn) -} - -// SetCallbackFunc - Sets callback function -func SetCallbackFunc(func()) { -} - -// NewImageFromImage - Returns new Image from Go image.Image -func NewImageFromImage(img image.Image) *Image { - size := img.Bounds().Size() - - ret := GenImageColor(size.X, size.Y, White) - - for y := 0; y < size.Y; y++ { - for x := 0; x < size.X; x++ { - col := img.At(x, y) - r, g, b, a := col.RGBA() - rcolor := NewColor(uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8)) - ImageDrawPixel(ret, int32(x), int32(y), rcolor) - } - } - - return ret -} - -// ToImage converts a Image to Go image.Image -func (i *Image) ToImage() image.Image { - img := image.NewRGBA(image.Rect(0, 0, int(i.Width), int(i.Height))) - - // Get pixel data from image (RGBA 32bit) - ret := LoadImageColors(i) - pixels := (*[1 << 24]uint8)(unsafe.Pointer(unsafe.SliceData(ret)))[0 : i.Width*i.Height*4] - - img.Pix = pixels - - return img -} - -// OpenAsset - Open asset -func OpenAsset(name string) (Asset, error) { - f, err := os.Open(name) - if err != nil { - return nil, err - } - return f, nil -} - -// HomeDir - Returns user home directory -// NOTE: On Android this returns internal data path and must be called after InitWindow -func HomeDir() string { - if homeDir, err := os.UserHomeDir(); err == nil { - return homeDir - } - return "" -} diff --git a/raylib/raymath.go b/raylib/raymath.go index e0aefc6..b211063 100644 --- a/raylib/raymath.go +++ b/raylib/raymath.go @@ -4,47 +4,6 @@ import ( "math" ) -// Clamp - Clamp float value -func Clamp(value, min, max float32) float32 { - var res float32 - if value < min { - res = min - } else { - res = value - } - - if res > max { - return max - } - - return res -} - -// Lerp - Calculate linear interpolation between two floats -func Lerp(start, end, amount float32) float32 { - return start + amount*(end-start) -} - -// Normalize - Normalize input value within input range -func Normalize(value, start, end float32) float32 { - return (value - start) / (end - start) -} - -// Remap - Remap input value within input range to output range -func Remap(value, inputStart, inputEnd, outputStart, outputEnd float32) float32 { - return (value-inputStart)/(inputEnd-inputStart)*(outputEnd-outputStart) + outputStart -} - -// Wrap - Wrap input value from min to max -func Wrap(value, min, max float32) float32 { - return float32(float64(value) - float64(max-min)*math.Floor(float64((value-min)/(max-min)))) -} - -// FloatEquals - Check whether two given floats are almost equal -func FloatEquals(x, y float32) bool { - return (math.Abs(float64(x-y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(x)), math.Abs(float64(y))))) -} - // Vector2Zero - Vector with components value 0.0 func Vector2Zero() Vector2 { return NewVector2(0.0, 0.0) @@ -60,31 +19,16 @@ func Vector2Add(v1, v2 Vector2) Vector2 { return NewVector2(v1.X+v2.X, v1.Y+v2.Y) } -// Vector2AddValue - Add vector and float value -func Vector2AddValue(v Vector2, add float32) Vector2 { - return NewVector2(v.X+add, v.Y+add) -} - // Vector2Subtract - Subtract two vectors (v1 - v2) func Vector2Subtract(v1, v2 Vector2) Vector2 { return NewVector2(v1.X-v2.X, v1.Y-v2.Y) } -// Vector2SubtractValue - Subtract vector by float value -func Vector2SubtractValue(v Vector2, sub float32) Vector2 { - return NewVector2(v.X-sub, v.Y-sub) -} - // Vector2Length - Calculate vector length func Vector2Length(v Vector2) float32 { return float32(math.Sqrt(float64((v.X * v.X) + (v.Y * v.Y)))) } -// Vector2LengthSqr - Calculate vector square length -func Vector2LengthSqr(v Vector2) float32 { - return v.X*v.X + v.Y*v.Y -} - // Vector2DotProduct - Calculate two vectors dot product func Vector2DotProduct(v1, v2 Vector2) float32 { return v1.X*v2.X + v1.Y*v2.Y @@ -95,22 +39,15 @@ func Vector2Distance(v1, v2 Vector2) float32 { return float32(math.Sqrt(float64((v1.X-v2.X)*(v1.X-v2.X) + (v1.Y-v2.Y)*(v1.Y-v2.Y)))) } -// Vector2DistanceSqr - Calculate square distance between two vectors -func Vector2DistanceSqr(v1 Vector2, v2 Vector2) float32 { - return (v1.X-v2.X)*(v1.X-v2.X) + (v1.Y-v2.Y)*(v1.Y-v2.Y) -} - -// Vector2Angle - Calculate angle from two vectors in radians +// Vector2Angle - Calculate angle between two vectors in X-axis func Vector2Angle(v1, v2 Vector2) float32 { - result := math.Atan2(float64(v2.Y), float64(v2.X)) - math.Atan2(float64(v1.Y), float64(v1.X)) + angle := float32(math.Atan2(float64(v2.Y-v1.Y), float64(v2.X-v1.X)) * (180.0 / float64(Pi))) - return float32(result) -} + if angle < 0 { + angle += 360.0 + } -// Vector2LineAngle - Calculate angle defined by a two vectors line -// NOTE: Parameters need to be normalized. Current implementation should be aligned with glm::angle -func Vector2LineAngle(start Vector2, end Vector2) float32 { - return float32(-math.Atan2(float64(end.Y-start.Y), float64(end.X-start.X))) + return angle } // Vector2Scale - Scale vector (multiply by value) @@ -129,30 +66,13 @@ func Vector2Negate(v Vector2) Vector2 { } // Vector2Divide - Divide vector by vector -func Vector2Divide(v1, v2 Vector2) Vector2 { +func Vector2DivideV(v1, v2 Vector2) Vector2 { return NewVector2(v1.X/v2.X, v1.Y/v2.Y) } // Vector2Normalize - Normalize provided vector func Vector2Normalize(v Vector2) Vector2 { - if l := Vector2Length(v); l > 0 { - return Vector2Scale(v, 1/l) - } - return v -} - -// Vector2Transform - Transforms a Vector2 by a given Matrix -func Vector2Transform(v Vector2, mat Matrix) Vector2 { - var result = Vector2{} - - var x = v.X - var y = v.Y - var z float32 - - result.X = mat.M0*x + mat.M4*y + mat.M8*z + mat.M12 - result.Y = mat.M1*x + mat.M5*y + mat.M9*z + mat.M13 - - return result + return Vector2Scale(v, 1/Vector2Length(v)) } // Vector2Lerp - Calculate linear interpolation between two vectors @@ -160,94 +80,6 @@ func Vector2Lerp(v1, v2 Vector2, amount float32) Vector2 { return NewVector2(v1.X+amount*(v2.X-v1.X), v1.Y+amount*(v2.Y-v1.Y)) } -// Vector2Reflect - Calculate reflected vector to normal -func Vector2Reflect(v Vector2, normal Vector2) Vector2 { - var result = Vector2{} - - dotProduct := v.X*normal.X + v.Y*normal.Y // Dot product - - result.X = v.X - 2.0*normal.X*dotProduct - result.Y = v.Y - 2.0*normal.Y*dotProduct - - return result -} - -// Vector2Rotate - Rotate vector by angle -func Vector2Rotate(v Vector2, angle float32) Vector2 { - var result = Vector2{} - - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) - - result.X = v.X*cosres - v.Y*sinres - result.Y = v.X*sinres + v.Y*cosres - - return result -} - -// Vector2MoveTowards - Move Vector towards target -func Vector2MoveTowards(v Vector2, target Vector2, maxDistance float32) Vector2 { - var result = Vector2{} - - dx := target.X - v.X - dy := target.Y - v.Y - value := dx*dx + dy*dy - - if value == 0 || maxDistance >= 0 && value <= maxDistance*maxDistance { - return target - } - - dist := float32(math.Sqrt(float64(value))) - - result.X = v.X + dx/dist*maxDistance - result.Y = v.Y + dy/dist*maxDistance - - return result -} - -// Vector2Invert - Invert the given vector -func Vector2Invert(v Vector2) Vector2 { - return NewVector2(1.0/v.X, 1.0/v.Y) -} - -// Vector2Clamp - Clamp the components of the vector between min and max values specified by the given vectors -func Vector2Clamp(v Vector2, min Vector2, max Vector2) Vector2 { - var result = Vector2{} - - result.X = float32(math.Min(float64(max.X), math.Max(float64(min.X), float64(v.X)))) - result.Y = float32(math.Min(float64(max.Y), math.Max(float64(min.Y), float64(v.Y)))) - - return result -} - -// Vector2ClampValue - Clamp the magnitude of the vector between two min and max values -func Vector2ClampValue(v Vector2, min float32, max float32) Vector2 { - var result = v - - length := v.X*v.X + v.Y*v.Y - if length > 0.0 { - length = float32(math.Sqrt(float64(length))) - - if length < min { - scale := min / length - result.X = v.X * scale - result.Y = v.Y * scale - } else if length > max { - scale := max / length - result.X = v.X * scale - result.Y = v.Y * scale - } - } - - return result -} - -// Vector2Equals - Check whether two given vectors are almost equal -func Vector2Equals(p Vector2, q Vector2) bool { - return (math.Abs(float64(p.X-q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y-q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y))))) -} - // Vector2CrossProduct - Calculate two vectors cross product func Vector2CrossProduct(v1, v2 Vector2) float32 { return v1.X*v2.Y - v1.Y*v2.X @@ -263,6 +95,35 @@ func Vector2LenSqr(vector Vector2) float32 { return vector.X*vector.X + vector.Y*vector.Y } +// Mat2Radians - Creates a matrix 2x2 from a given radians value +func Mat2Radians(radians float32) Mat2 { + c := float32(math.Cos(float64(radians))) + s := float32(math.Sin(float64(radians))) + + return NewMat2(c, -s, s, c) +} + +// Mat2Set - Set values from radians to a created matrix 2x2 +func Mat2Set(matrix *Mat2, radians float32) { + cos := float32(math.Cos(float64(radians))) + sin := float32(math.Sin(float64(radians))) + + matrix.M00 = cos + matrix.M01 = -sin + matrix.M10 = sin + matrix.M11 = cos +} + +// Mat2Transpose - Returns the transpose of a given matrix 2x2 +func Mat2Transpose(matrix Mat2) Mat2 { + return NewMat2(matrix.M00, matrix.M10, matrix.M01, matrix.M11) +} + +// Mat2MultiplyVector2 - Multiplies a vector by a matrix 2x2 +func Mat2MultiplyVector2(matrix Mat2, vector Vector2) Vector2 { + return NewVector2(matrix.M00*vector.X+matrix.M01*vector.Y, matrix.M10*vector.X+matrix.M11*vector.Y) +} + // Vector3Zero - Vector with components value 0.0 func Vector3Zero() Vector3 { return NewVector3(0.0, 0.0, 0.0) @@ -278,28 +139,19 @@ func Vector3Add(v1, v2 Vector3) Vector3 { return NewVector3(v1.X+v2.X, v1.Y+v2.Y, v1.Z+v2.Z) } -// Vector3AddValue - Add vector and float value -func Vector3AddValue(v Vector3, add float32) Vector3 { - return NewVector3(v.X+add, v.Y+add, v.Z+add) +// Vector3Multiply - Multiply vector by scalar +func Vector3Multiply(v Vector3, scalar float32) Vector3 { + result := Vector3{} + + result.X = v.X * scalar + result.Y = v.Y * scalar + result.Z = v.Z * scalar + + return result } -// Vector3Subtract - Subtract two vectors -func Vector3Subtract(v1, v2 Vector3) Vector3 { - return NewVector3(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z) -} - -// Vector3SubtractValue - Subtract vector by float value -func Vector3SubtractValue(v Vector3, sub float32) Vector3 { - return NewVector3(v.X-sub, v.Y-sub, v.Z-sub) -} - -// Vector3Scale - Scale provided vector -func Vector3Scale(v Vector3, scale float32) Vector3 { - return NewVector3(v.X*scale, v.Y*scale, v.Z*scale) -} - -// Vector3Multiply - Multiply vector by vector -func Vector3Multiply(v1, v2 Vector3) Vector3 { +// Vector3MultiplyV - Multiply vector by vector +func Vector3MultiplyV(v1, v2 Vector3) Vector3 { result := Vector3{} result.X = v1.X * v2.X @@ -309,6 +161,11 @@ func Vector3Multiply(v1, v2 Vector3) Vector3 { return result } +// Vector3Subtract - Subtract two vectors +func Vector3Subtract(v1, v2 Vector3) Vector3 { + return NewVector3(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z) +} + // Vector3CrossProduct - Calculate two vectors cross product func Vector3CrossProduct(v1, v2 Vector3) Vector3 { result := Vector3{} @@ -322,6 +179,8 @@ func Vector3CrossProduct(v1, v2 Vector3) Vector3 { // Vector3Perpendicular - Calculate one vector perpendicular vector func Vector3Perpendicular(v Vector3) Vector3 { + result := Vector3{} + min := math.Abs(float64(v.X)) cardinalAxis := NewVector3(1.0, 0.0, 0.0) @@ -334,7 +193,7 @@ func Vector3Perpendicular(v Vector3) Vector3 { cardinalAxis = NewVector3(0.0, 0.0, 1.0) } - result := Vector3CrossProduct(v, cardinalAxis) + result = Vector3CrossProduct(v, cardinalAxis) return result } @@ -344,11 +203,6 @@ func Vector3Length(v Vector3) float32 { return float32(math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z))) } -// Vector3LengthSqr - Calculate vector square length -func Vector3LengthSqr(v Vector3) float32 { - return v.X*v.X + v.Y*v.Y + v.Z*v.Z -} - // Vector3DotProduct - Calculate two vectors dot product func Vector3DotProduct(v1, v2 Vector3) float32 { return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z @@ -363,28 +217,9 @@ func Vector3Distance(v1, v2 Vector3) float32 { return float32(math.Sqrt(float64(dx*dx + dy*dy + dz*dz))) } -// Vector3DistanceSqr - Calculate square distance between two vectors -func Vector3DistanceSqr(v1 Vector3, v2 Vector3) float32 { - var result float32 - - dx := v2.X - v1.X - dy := v2.Y - v1.Y - dz := v2.Z - v1.Z - result = dx*dx + dy*dy + dz*dz - - return result -} - -// Vector3Angle - Calculate angle between two vectors -func Vector3Angle(v1 Vector3, v2 Vector3) float32 { - var result float32 - - cross := Vector3{X: v1.Y*v2.Z - v1.Z*v2.Y, Y: v1.Z*v2.X - v1.X*v2.Z, Z: v1.X*v2.Y - v1.Y*v2.X} - length := float32(math.Sqrt(float64(cross.X*cross.X + cross.Y*cross.Y + cross.Z*cross.Z))) - dot := v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z - result = float32(math.Atan2(float64(length), float64(dot))) - - return result +// Vector3Scale - Scale provided vector +func Vector3Scale(v Vector3, scale float32) Vector3 { + return NewVector3(v.X*scale, v.Y*scale, v.Z*scale) } // Vector3Negate - Negate provided vector (invert direction) @@ -392,11 +227,6 @@ func Vector3Negate(v Vector3) Vector3 { return NewVector3(-v.X, -v.Y, -v.Z) } -// Vector3Divide - Divide vector by vector -func Vector3Divide(v1 Vector3, v2 Vector3) Vector3 { - return NewVector3(v1.X/v2.X, v1.Y/v2.Y, v1.Z/v2.Z) -} - // Vector3Normalize - Normalize provided vector func Vector3Normalize(v Vector3) Vector3 { result := v @@ -418,51 +248,6 @@ func Vector3Normalize(v Vector3) Vector3 { return result } -// Vector3Project - Calculate the projection of the vector v1 on to v2 -func Vector3Project(v1, v2 Vector3) Vector3 { - result := Vector3{} - - v1dv2 := (v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z) - v2dv2 := (v2.X*v2.X + v2.Y*v2.Y + v2.Z*v2.Z) - - mag := v1dv2 / v2dv2 - - result.X = v2.X * mag - result.Y = v2.Y * mag - result.Z = v2.Z * mag - - return result -} - -// Vector3Reject - Calculate the rejection of the vector v1 on to v2 -func Vector3Reject(v1, v2 Vector3) Vector3 { - result := Vector3{} - - v1dv2 := (v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z) - v2dv2 := (v2.X*v2.X + v2.Y*v2.Y + v2.Z*v2.Z) - - mag := v1dv2 / v2dv2 - - result.X = v1.X - (v2.X * mag) - result.Y = v1.Y - (v2.Y * mag) - result.Z = v1.Z - (v2.Z * mag) - - return result -} - -// Vector3OrthoNormalize - Orthonormalize provided vectors -// Makes vectors normalized and orthogonal to each other -// Gram-Schmidt function implementation -func Vector3OrthoNormalize(v1, v2 *Vector3) { - Vector3Normalize(*v1) - - vn1 := Vector3CrossProduct(*v1, *v2) - Vector3Normalize(vn1) - - vn2 := Vector3CrossProduct(vn1, *v1) - *v2 = vn2 -} - // Vector3Transform - Transforms a Vector3 by a given Matrix func Vector3Transform(v Vector3, mat Matrix) Vector3 { result := Vector3{} @@ -478,70 +263,6 @@ func Vector3Transform(v Vector3, mat Matrix) Vector3 { return result } -// Vector3RotateByQuaternion - Transform a vector by quaternion rotation -func Vector3RotateByQuaternion(v Vector3, q Quaternion) Vector3 { - var result Vector3 - - result.X = v.X*(q.X*q.X+q.W*q.W-q.Y*q.Y-q.Z*q.Z) + v.Y*(2*q.X*q.Y-2*q.W*q.Z) + v.Z*(2*q.X*q.Z+2*q.W*q.Y) - result.Y = v.X*(2*q.W*q.Z+2*q.X*q.Y) + v.Y*(q.W*q.W-q.X*q.X+q.Y*q.Y-q.Z*q.Z) + v.Z*(-2*q.W*q.X+2*q.Y*q.Z) - result.Z = v.X*(-2*q.W*q.Y+2*q.X*q.Z) + v.Y*(2*q.W*q.X+2*q.Y*q.Z) + v.Z*(q.W*q.W-q.X*q.X-q.Y*q.Y+q.Z*q.Z) - - return result -} - -// Vector3RotateByAxisAngle - Rotates a vector around an axis -func Vector3RotateByAxisAngle(v Vector3, axis Vector3, angle float32) Vector3 { - // Using Euler-Rodrigues Formula - // Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula - - result := v - - // Vector3Normalize(axis); - length := float32(math.Sqrt(float64(axis.X*axis.X + axis.Y*axis.Y + axis.Z*axis.Z))) - if length == 0.0 { - length = 1.0 - } - ilength := 1.0 / length - axis.X *= ilength - axis.Y *= ilength - axis.Z *= ilength - - angle /= 2.0 - a := float32(math.Sin(float64(angle))) - b := axis.X * a - c := axis.Y * a - d := axis.Z * a - a = float32(math.Cos(float64(angle))) - w := NewVector3(b, c, d) - - // Vector3CrossProduct(w, v) - wv := NewVector3(w.Y*v.Z-w.Z*v.Y, w.Z*v.X-w.X*v.Z, w.X*v.Y-w.Y*v.X) - - // Vector3CrossProduct(w, wv) - wwv := NewVector3(w.Y*wv.Z-w.Z*wv.Y, w.Z*wv.X-w.X*wv.Z, w.X*wv.Y-w.Y*wv.X) - - // Vector3Scale(wv, 2*a) - a *= 2 - wv.X *= a - wv.Y *= a - wv.Z *= a - - // Vector3Scale(wwv, 2) - wwv.X *= 2 - wwv.Y *= 2 - wwv.Z *= 2 - - result.X += wv.X - result.Y += wv.Y - result.Z += wv.Z - - result.X += wwv.X - result.Y += wwv.Y - result.Z += wwv.Z - - return result -} - // Vector3Lerp - Calculate linear interpolation between two vectors func Vector3Lerp(v1, v2 Vector3, amount float32) Vector3 { result := Vector3{} @@ -614,211 +335,6 @@ func Vector3Barycenter(p, a, b, c Vector3) Vector3 { return result } -// Vector3Unproject - Projects a Vector3 from screen space into object space -// NOTE: We are avoiding calling other raymath functions despite available -func Vector3Unproject(source Vector3, projection Matrix, view Matrix) Vector3 { - var result = Vector3{} - - // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it - var matViewProj = Matrix{ // MatrixMultiply(view, projection); - M0: view.M0*projection.M0 + view.M1*projection.M4 + view.M2*projection.M8 + view.M3*projection.M12, - M4: view.M0*projection.M1 + view.M1*projection.M5 + view.M2*projection.M9 + view.M3*projection.M13, - M8: view.M0*projection.M2 + view.M1*projection.M6 + view.M2*projection.M10 + view.M3*projection.M14, - M12: view.M0*projection.M3 + view.M1*projection.M7 + view.M2*projection.M11 + view.M3*projection.M15, - M1: view.M4*projection.M0 + view.M5*projection.M4 + view.M6*projection.M8 + view.M7*projection.M12, - M5: view.M4*projection.M1 + view.M5*projection.M5 + view.M6*projection.M9 + view.M7*projection.M13, - M9: view.M4*projection.M2 + view.M5*projection.M6 + view.M6*projection.M10 + view.M7*projection.M14, - M13: view.M4*projection.M3 + view.M5*projection.M7 + view.M6*projection.M11 + view.M7*projection.M15, - M2: view.M8*projection.M0 + view.M9*projection.M4 + view.M10*projection.M8 + view.M11*projection.M12, - M6: view.M8*projection.M1 + view.M9*projection.M5 + view.M10*projection.M9 + view.M11*projection.M13, - M10: view.M8*projection.M2 + view.M9*projection.M6 + view.M10*projection.M10 + view.M11*projection.M14, - M14: view.M8*projection.M3 + view.M9*projection.M7 + view.M10*projection.M11 + view.M11*projection.M15, - M3: view.M12*projection.M0 + view.M13*projection.M4 + view.M14*projection.M8 + view.M15*projection.M12, - M7: view.M12*projection.M1 + view.M13*projection.M5 + view.M14*projection.M9 + view.M15*projection.M13, - M11: view.M12*projection.M2 + view.M13*projection.M6 + view.M14*projection.M10 + view.M15*projection.M14, - M15: view.M12*projection.M3 + view.M13*projection.M7 + view.M14*projection.M11 + view.M15*projection.M15} - - // Calculate inverted matrix -> MatrixInvert(matViewProj); - // Cache the matrix values (speed optimization) - var a00 = matViewProj.M0 - var a01 = matViewProj.M1 - var a02 = matViewProj.M2 - var a03 = matViewProj.M3 - var a10 = matViewProj.M4 - var a11 = matViewProj.M5 - var a12 = matViewProj.M6 - var a13 = matViewProj.M7 - var a20 = matViewProj.M8 - var a21 = matViewProj.M9 - var a22 = matViewProj.M10 - var a23 = matViewProj.M11 - var a30 = matViewProj.M12 - var a31 = matViewProj.M13 - var a32 = matViewProj.M14 - var a33 = matViewProj.M15 - - var b00 = a00*a11 - a01*a10 - var b01 = a00*a12 - a02*a10 - var b02 = a00*a13 - a03*a10 - var b03 = a01*a12 - a02*a11 - var b04 = a01*a13 - a03*a11 - var b05 = a02*a13 - a03*a12 - var b06 = a20*a31 - a21*a30 - var b07 = a20*a32 - a22*a30 - var b08 = a20*a33 - a23*a30 - var b09 = a21*a32 - a22*a31 - var b10 = a21*a33 - a23*a31 - var b11 = a22*a33 - a23*a32 - - // Calculate the invert determinant (inlined to avoid double-caching) - var invDet = 1.0 / (b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06) - - var matViewProjInv = Matrix{ - M0: (a11*b11 - a12*b10 + a13*b09) * invDet, - M4: (-a01*b11 + a02*b10 - a03*b09) * invDet, - M8: (a31*b05 - a32*b04 + a33*b03) * invDet, - M12: (-a21*b05 + a22*b04 - a23*b03) * invDet, - M1: (-a10*b11 + a12*b08 - a13*b07) * invDet, - M5: (a00*b11 - a02*b08 + a03*b07) * invDet, - M9: (-a30*b05 + a32*b02 - a33*b01) * invDet, - M13: (a20*b05 - a22*b02 + a23*b01) * invDet, - M2: (a10*b10 - a11*b08 + a13*b06) * invDet, - M6: (-a00*b10 + a01*b08 - a03*b06) * invDet, - M10: (a30*b04 - a31*b02 + a33*b00) * invDet, - M14: (-a20*b04 + a21*b02 - a23*b00) * invDet, - M3: (-a10*b09 + a11*b07 - a12*b06) * invDet, - M7: (a00*b09 - a01*b07 + a02*b06) * invDet, - M11: (-a30*b03 + a31*b01 - a32*b00) * invDet, - M15: (a20*b03 - a21*b01 + a22*b00) * invDet} - - // Create quaternion from source point - var quat = Quaternion{X: source.X, Y: source.Y, Z: source.Z, W: 1.0} - - // Multiply quat point by unprojecte matrix - var qtransformed = Quaternion{ // QuaternionTransform(quat, matViewProjInv) - X: matViewProjInv.M0*quat.X + matViewProjInv.M4*quat.Y + matViewProjInv.M8*quat.Z + matViewProjInv.M12*quat.W, - Y: matViewProjInv.M1*quat.X + matViewProjInv.M5*quat.Y + matViewProjInv.M9*quat.Z + matViewProjInv.M13*quat.W, - Z: matViewProjInv.M2*quat.X + matViewProjInv.M6*quat.Y + matViewProjInv.M10*quat.Z + matViewProjInv.M14*quat.W, - W: matViewProjInv.M3*quat.X + matViewProjInv.M7*quat.Y + matViewProjInv.M11*quat.Z + matViewProjInv.M15*quat.W} - - // Normalized world points in vectors - result.X = qtransformed.X / qtransformed.W - result.Y = qtransformed.Y / qtransformed.W - result.Z = qtransformed.Z / qtransformed.W - - return result -} - -// Vector3ToFloatV - Get Vector3 as float array -func Vector3ToFloatV(v Vector3) [3]float32 { - var result [3]float32 - - result[0] = v.X - result[1] = v.Y - result[2] = v.Z - - return result -} - -// Vector3Invert - Invert the given vector -func Vector3Invert(v Vector3) Vector3 { - return NewVector3(1.0/v.X, 1.0/v.Y, 1.0/v.Z) -} - -// Vector3Clamp - Clamp the components of the vector between min and max values specified by the given vectors -func Vector3Clamp(v Vector3, min Vector3, max Vector3) Vector3 { - var result = Vector3{} - - result.X = float32(math.Min(float64(max.X), math.Max(float64(min.X), float64(v.X)))) - result.Y = float32(math.Min(float64(max.Y), math.Max(float64(min.Y), float64(v.Y)))) - result.Z = float32(math.Min(float64(max.Z), math.Max(float64(min.Z), float64(v.Z)))) - - return result -} - -// Vector3ClampValue - Clamp the magnitude of the vector between two values -func Vector3ClampValue(v Vector3, min float32, max float32) Vector3 { - var result = v - - length := v.X*v.X + v.Y*v.Y + v.Z*v.Z - if length > 0.0 { - length = float32(math.Sqrt(float64(length))) - - if length < min { - scale := min / length - result.X = v.X * scale - result.Y = v.Y * scale - result.Z = v.Z * scale - } else if length > max { - scale := max / length - result.X = v.X * scale - result.Y = v.Y * scale - result.Z = v.Z * scale - } - } - - return result -} - -// Vector3Equals - Check whether two given vectors are almost equal -func Vector3Equals(p Vector3, q Vector3) bool { - return (math.Abs(float64(p.X-q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y-q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && - math.Abs(float64(p.Z-q.Z)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z))))) -} - -// Vector3Refract - Compute the direction of a refracted ray -// -// v: normalized direction of the incoming ray -// n: normalized normal vector of the interface of two optical media -// r: ratio of the refractive index of the medium from where the ray comes to the refractive index of the medium on the other side of the surface -func Vector3Refract(v Vector3, n Vector3, r float32) Vector3 { - var result = Vector3{} - - dot := v.X*n.X + v.Y*n.Y + v.Z*n.Z - d := 1.0 - r*r*(1.0-dot*dot) - - if d >= 0.0 { - d = float32(math.Sqrt(float64(d))) - v.X = r*v.X - (r*dot+d)*n.X - v.Y = r*v.Y - (r*dot+d)*n.Y - v.Z = r*v.Z - (r*dot+d)*n.Z - - result = v - } - - return result -} - -// Mat2Radians - Creates a matrix 2x2 from a given radians value -func Mat2Radians(radians float32) Mat2 { - c := float32(math.Cos(float64(radians))) - s := float32(math.Sin(float64(radians))) - - return NewMat2(c, -s, s, c) -} - -// Mat2Set - Set values from radians to a created matrix 2x2 -func Mat2Set(matrix *Mat2, radians float32) { - cos := float32(math.Cos(float64(radians))) - sin := float32(math.Sin(float64(radians))) - - matrix.M00 = cos - matrix.M01 = -sin - matrix.M10 = sin - matrix.M11 = cos -} - -// Mat2Transpose - Returns the transpose of a given matrix 2x2 -func Mat2Transpose(matrix Mat2) Mat2 { - return NewMat2(matrix.M00, matrix.M10, matrix.M01, matrix.M11) -} - -// Mat2MultiplyVector2 - Multiplies a vector by a matrix 2x2 -func Mat2MultiplyVector2(matrix Mat2, vector Vector2) Vector2 { - return NewVector2(matrix.M00*vector.X+matrix.M01*vector.Y, matrix.M10*vector.X+matrix.M11*vector.Y) -} - // MatrixDeterminant - Compute matrix determinant func MatrixDeterminant(mat Matrix) float32 { var result float32 @@ -936,15 +452,6 @@ func MatrixInvert(mat Matrix) Matrix { return result } -// MatrixIdentity - Returns identity matrix -func MatrixIdentity() Matrix { - return NewMatrix( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0) -} - // MatrixNormalize - Normalize provided matrix func MatrixNormalize(mat Matrix) Matrix { var result Matrix @@ -971,6 +478,15 @@ func MatrixNormalize(mat Matrix) Matrix { return result } +// MatrixIdentity - Returns identity matrix +func MatrixIdentity() Matrix { + return NewMatrix( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0) +} + // MatrixAdd - Add two matrices func MatrixAdd(left, right Matrix) Matrix { result := MatrixIdentity() @@ -1019,30 +535,6 @@ func MatrixSubtract(left, right Matrix) Matrix { return result } -// MatrixMultiply - Returns two matrix multiplication -func MatrixMultiply(left, right Matrix) Matrix { - var result Matrix - - result.M0 = left.M0*right.M0 + left.M1*right.M4 + left.M2*right.M8 + left.M3*right.M12 - result.M1 = left.M0*right.M1 + left.M1*right.M5 + left.M2*right.M9 + left.M3*right.M13 - result.M2 = left.M0*right.M2 + left.M1*right.M6 + left.M2*right.M10 + left.M3*right.M14 - result.M3 = left.M0*right.M3 + left.M1*right.M7 + left.M2*right.M11 + left.M3*right.M15 - result.M4 = left.M4*right.M0 + left.M5*right.M4 + left.M6*right.M8 + left.M7*right.M12 - result.M5 = left.M4*right.M1 + left.M5*right.M5 + left.M6*right.M9 + left.M7*right.M13 - result.M6 = left.M4*right.M2 + left.M5*right.M6 + left.M6*right.M10 + left.M7*right.M14 - result.M7 = left.M4*right.M3 + left.M5*right.M7 + left.M6*right.M11 + left.M7*right.M15 - result.M8 = left.M8*right.M0 + left.M9*right.M4 + left.M10*right.M8 + left.M11*right.M12 - result.M9 = left.M8*right.M1 + left.M9*right.M5 + left.M10*right.M9 + left.M11*right.M13 - result.M10 = left.M8*right.M2 + left.M9*right.M6 + left.M10*right.M10 + left.M11*right.M14 - result.M11 = left.M8*right.M3 + left.M9*right.M7 + left.M10*right.M11 + left.M11*right.M15 - result.M12 = left.M12*right.M0 + left.M13*right.M4 + left.M14*right.M8 + left.M15*right.M12 - result.M13 = left.M12*right.M1 + left.M13*right.M5 + left.M14*right.M9 + left.M15*right.M13 - result.M14 = left.M12*right.M2 + left.M13*right.M6 + left.M14*right.M10 + left.M15*right.M14 - result.M15 = left.M12*right.M3 + left.M13*right.M7 + left.M14*right.M11 + left.M15*right.M15 - - return result -} - // MatrixTranslate - Returns translation matrix func MatrixTranslate(x, y, z float32) Matrix { return NewMatrix( @@ -1166,67 +658,6 @@ func MatrixRotateZ(angle float32) Matrix { return result } -// MatrixRotateXYZ - Get xyz-rotation matrix (angles in radians) -func MatrixRotateXYZ(ang Vector3) Matrix { - result := MatrixIdentity() - - cosz := float32(math.Cos(float64(-ang.Z))) - sinz := float32(math.Sin(float64(-ang.Z))) - cosy := float32(math.Cos(float64(-ang.Y))) - siny := float32(math.Sin(float64(-ang.Y))) - cosx := float32(math.Cos(float64(-ang.X))) - sinx := float32(math.Sin(float64(-ang.X))) - - result.M0 = cosz * cosy - result.M4 = (cosz * siny * sinx) - (sinz * cosx) - result.M8 = (cosz * siny * cosx) + (sinz * sinx) - - result.M1 = sinz * cosy - result.M5 = (sinz * siny * sinx) + (cosz * cosx) - result.M9 = (sinz * siny * cosx) - (cosz * sinx) - - result.M2 = -siny - result.M6 = cosy * sinx - result.M10 = cosy * cosx - - return result -} - -// MatrixRotateZYX - Get zyx-rotation matrix -// NOTE: Angle must be provided in radians -func MatrixRotateZYX(angle Vector3) Matrix { - var result = Matrix{} - - var cz = float32(math.Cos(float64(angle.Z))) - var sz = float32(math.Sin(float64(angle.Z))) - var cy = float32(math.Cos(float64(angle.Y))) - var sy = float32(math.Sin(float64(angle.Y))) - var cx = float32(math.Cos(float64(angle.X))) - var sx = float32(math.Sin(float64(angle.X))) - - result.M0 = cz * cy - result.M4 = cz*sy*sx - cx*sz - result.M8 = sz*sx + cz*cx*sy - result.M12 = float32(0) - - result.M1 = cy * sz - result.M5 = cz*cx + sz*sy*sx - result.M9 = cx*sz*sy - cz*sx - result.M13 = float32(0) - - result.M2 = -sy - result.M6 = cy * sx - result.M10 = cy * cx - result.M14 = float32(0) - - result.M3 = float32(0) - result.M7 = float32(0) - result.M11 = float32(0) - result.M15 = float32(1) - - return result -} - // MatrixScale - Returns scaling matrix func MatrixScale(x, y, z float32) Matrix { result := NewMatrix( @@ -1238,6 +669,30 @@ func MatrixScale(x, y, z float32) Matrix { return result } +// MatrixMultiply - Returns two matrix multiplication +func MatrixMultiply(left, right Matrix) Matrix { + var result Matrix + + result.M0 = right.M0*left.M0 + right.M1*left.M4 + right.M2*left.M8 + right.M3*left.M12 + result.M1 = right.M0*left.M1 + right.M1*left.M5 + right.M2*left.M9 + right.M3*left.M13 + result.M2 = right.M0*left.M2 + right.M1*left.M6 + right.M2*left.M10 + right.M3*left.M14 + result.M3 = right.M0*left.M3 + right.M1*left.M7 + right.M2*left.M11 + right.M3*left.M15 + result.M4 = right.M4*left.M0 + right.M5*left.M4 + right.M6*left.M8 + right.M7*left.M12 + result.M5 = right.M4*left.M1 + right.M5*left.M5 + right.M6*left.M9 + right.M7*left.M13 + result.M6 = right.M4*left.M2 + right.M5*left.M6 + right.M6*left.M10 + right.M7*left.M14 + result.M7 = right.M4*left.M3 + right.M5*left.M7 + right.M6*left.M11 + right.M7*left.M15 + result.M8 = right.M8*left.M0 + right.M9*left.M4 + right.M10*left.M8 + right.M11*left.M12 + result.M9 = right.M8*left.M1 + right.M9*left.M5 + right.M10*left.M9 + right.M11*left.M13 + result.M10 = right.M8*left.M2 + right.M9*left.M6 + right.M10*left.M10 + right.M11*left.M14 + result.M11 = right.M8*left.M3 + right.M9*left.M7 + right.M10*left.M11 + right.M11*left.M15 + result.M12 = right.M12*left.M0 + right.M13*left.M4 + right.M14*left.M8 + right.M15*left.M12 + result.M13 = right.M12*left.M1 + right.M13*left.M5 + right.M14*left.M9 + right.M15*left.M13 + result.M14 = right.M12*left.M2 + right.M13*left.M6 + right.M14*left.M10 + right.M15*left.M14 + result.M15 = right.M12*left.M3 + right.M13*left.M7 + right.M14*left.M11 + right.M15*left.M15 + + return result +} + // MatrixFrustum - Returns perspective projection matrix func MatrixFrustum(left, right, bottom, top, near, far float32) Matrix { var result Matrix @@ -1336,71 +791,6 @@ func MatrixLookAt(eye, target, up Vector3) Matrix { return result } -// MatrixToFloatV - Get float array of matrix data -func MatrixToFloatV(mat Matrix) [16]float32 { - var result [16]float32 - - result[0] = mat.M0 - result[1] = mat.M1 - result[2] = mat.M2 - result[3] = mat.M3 - result[4] = mat.M4 - result[5] = mat.M5 - result[6] = mat.M6 - result[7] = mat.M7 - result[8] = mat.M8 - result[9] = mat.M9 - result[10] = mat.M10 - result[11] = mat.M11 - result[12] = mat.M12 - result[13] = mat.M13 - result[14] = mat.M14 - result[15] = mat.M15 - - return result -} - -// MatrixToFloat - Converts Matrix to float32 slice -func MatrixToFloat(mat Matrix) []float32 { - data := MatrixToFloatV(mat) - return data[:] -} - -// QuaternionAdd - Add two quaternions -func QuaternionAdd(q1 Quaternion, q2 Quaternion) Quaternion { - var result = Quaternion{X: q1.X + q2.X, Y: q1.Y + q2.Y, Z: q1.Z + q2.Z, W: q1.W + q2.W} - - return result -} - -// QuaternionAddValue - Add quaternion and float value -func QuaternionAddValue(q Quaternion, add float32) Quaternion { - var result = Quaternion{X: q.X + add, Y: q.Y + add, Z: q.Z + add, W: q.W + add} - - return result -} - -// QuaternionSubtract - Subtract two quaternions -func QuaternionSubtract(q1 Quaternion, q2 Quaternion) Quaternion { - var result = Quaternion{X: q1.X - q2.X, Y: q1.Y - q2.Y, Z: q1.Z - q2.Z, W: q1.W - q2.W} - - return result -} - -// QuaternionSubtractValue - Subtract quaternion and float value -func QuaternionSubtractValue(q Quaternion, sub float32) Quaternion { - var result = Quaternion{X: q.X - sub, Y: q.Y - sub, Z: q.Z - sub, W: q.W - sub} - - return result -} - -// QuaternionIdentity - Get identity quaternion -func QuaternionIdentity() Quaternion { - var result = Quaternion{W: 1.0} - - return result -} - // QuaternionLength - Compute the length of a quaternion func QuaternionLength(quat Quaternion) float32 { return float32(math.Sqrt(float64(quat.X*quat.X + quat.Y*quat.Y + quat.Z*quat.Z + quat.W*quat.W))) @@ -1408,17 +798,23 @@ func QuaternionLength(quat Quaternion) float32 { // QuaternionNormalize - Normalize provided quaternion func QuaternionNormalize(q Quaternion) Quaternion { - result := q + var result Quaternion - length := QuaternionLength(q) + var length, ilength float32 - if length != 0.0 { - result.X /= length - result.Y /= length - result.Z /= length - result.W /= length + length = QuaternionLength(q) + + if length == 0.0 { + length = 1.0 } + ilength = 1.0 / length + + result.X *= ilength + result.Y *= ilength + result.Z *= ilength + result.W *= ilength + return result } @@ -1462,63 +858,6 @@ func QuaternionMultiply(q1, q2 Quaternion) Quaternion { return result } -// QuaternionScale - Scale quaternion by float value -func QuaternionScale(q Quaternion, mul float32) Quaternion { - var result = Quaternion{} - - result.X = q.X * mul - result.Y = q.Y * mul - result.Z = q.Z * mul - result.W = q.W * mul - - return result -} - -// QuaternionDivide - Divide two quaternions -func QuaternionDivide(q1 Quaternion, q2 Quaternion) Quaternion { - var result = Quaternion{X: q1.X / q2.X, Y: q1.Y / q2.Y, Z: q1.Z / q2.Z, W: q1.W / q2.W} - - return result -} - -// QuaternionLerp - Calculate linear interpolation between two quaternions -func QuaternionLerp(q1 Quaternion, q2 Quaternion, amount float32) Quaternion { - var result = Quaternion{} - - result.X = q1.X + amount*(q2.X-q1.X) - result.Y = q1.Y + amount*(q2.Y-q1.Y) - result.Z = q1.Z + amount*(q2.Z-q1.Z) - result.W = q1.W + amount*(q2.W-q1.W) - - return result -} - -// QuaternionNlerp - Calculate slerp-optimized interpolation between two quaternions -func QuaternionNlerp(q1 Quaternion, q2 Quaternion, amount float32) Quaternion { - var result = Quaternion{} - - // QuaternionLerp(q1, q2, amount) - result.X = q1.X + amount*(q2.X-q1.X) - result.Y = q1.Y + amount*(q2.Y-q1.Y) - result.Z = q1.Z + amount*(q2.Z-q1.Z) - result.W = q1.W + amount*(q2.W-q1.W) - - // QuaternionNormalize(q); - q := result - length := float32(math.Sqrt(float64(q.X*q.X + q.Y*q.Y + q.Z*q.Z + q.W*q.W))) - if length == 0.0 { - length = 1.0 - } - ilength := 1.0 / length - - result.X = q.X * ilength - result.Y = q.Y * ilength - result.Z = q.Z * ilength - result.W = q.W * ilength - - return result -} - // QuaternionSlerp - Calculates spherical linear interpolation between two quaternions func QuaternionSlerp(q1, q2 Quaternion, amount float32) Quaternion { var result Quaternion @@ -1550,35 +889,6 @@ func QuaternionSlerp(q1, q2 Quaternion, amount float32) Quaternion { return result } -// QuaternionFromVector3ToVector3 - Calculate quaternion based on the rotation from one vector to another -func QuaternionFromVector3ToVector3(from Vector3, to Vector3) Quaternion { - var result = Quaternion{} - - cos2Theta := from.X*to.X + from.Y*to.Y + from.Z*to.Z // Vector3DotProduct(from, to) - cross := Vector3{X: from.Y*to.Z - from.Z*to.Y, Y: from.Z*to.X - from.X*to.Z, Z: from.X*to.Y - from.Y*to.X} // Vector3CrossProduct(from, to) - - result.X = cross.X - result.Y = cross.Y - result.Z = cross.Z - result.W = 1.0 + cos2Theta - - // QuaternionNormalize(q); - // NOTE: Normalize to essentially nlerp the original and identity to 0.5 - q := result - length := float32(math.Sqrt(float64(q.X*q.X + q.Y*q.Y + q.Z*q.Z + q.W*q.W))) - if length == 0.0 { - length = 1.0 - } - ilength := 1.0 / length - - result.X = q.X * ilength - result.Y = q.Y * ilength - result.Z = q.Z * ilength - result.W = q.W * ilength - - return result -} - // QuaternionFromMatrix - Returns a quaternion for a given rotation matrix func QuaternionFromMatrix(matrix Matrix) Quaternion { var result Quaternion @@ -1721,49 +1031,6 @@ func QuaternionToAxisAngle(q Quaternion, outAxis *Vector3, outAngle *float32) { *outAngle = resAngle } -// QuaternionFromEuler - Get the quaternion equivalent to Euler angles -// NOTE: Rotation order is ZYX -func QuaternionFromEuler(pitch, yaw, roll float32) Quaternion { - var result Quaternion - - x0 := float32(math.Cos(float64(pitch * 0.5))) - x1 := float32(math.Sin(float64(pitch * 0.5))) - y0 := float32(math.Cos(float64(yaw * 0.5))) - y1 := float32(math.Sin(float64(yaw * 0.5))) - z0 := float32(math.Cos(float64(roll * 0.5))) - z1 := float32(math.Sin(float64(roll * 0.5))) - - result.X = x1*y0*z0 - x0*y1*z1 - result.Y = x0*y1*z0 + x1*y0*z1 - result.Z = x0*y0*z1 - x1*y1*z0 - result.W = x0*y0*z0 + x1*y1*z1 - - return result -} - -// QuaternionToEuler - Get the Euler angles equivalent to quaternion (roll, pitch, yaw) -// NOTE: Angles are returned in a Vector3 struct in radians -func QuaternionToEuler(q Quaternion) Vector3 { - var result Vector3 - - // Roll (x-axis rotation) - x0 := 2.0 * (q.W*q.X + q.Y*q.Z) - x1 := 1.0 - 2.0*(q.X*q.X+q.Y*q.Y) - result.X = float32(math.Atan2(float64(x0), float64(x1))) - - // Pitch (y-axis rotation) - y0 := 2.0 * (q.W*q.Y - q.Z*q.X) - y0 = Clamp(y0, -1.0, 1.0) - result.Y = float32(math.Asin(float64(y0))) - - // Yaw (z-axis rotation) - z0 := 2.0 * (q.W*q.Z + q.X*q.Y) - z1 := 1.0 - 2.0*(q.Y*q.Y+q.Z*q.Z) - result.Z = float32(math.Atan2(float64(z0), float64(z1))) - - return result -} - // QuaternionTransform - Transform a quaternion given a transformation matrix func QuaternionTransform(q Quaternion, mat Matrix) Quaternion { var result Quaternion @@ -1781,67 +1048,18 @@ func QuaternionTransform(q Quaternion, mat Matrix) Quaternion { return result } -// QuaternionEquals - Check whether two given quaternions are almost equal -func QuaternionEquals(p, q Quaternion) bool { - return (math.Abs(float64(p.X-q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y-q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && - math.Abs(float64(p.Z-q.Z)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z)))) && - math.Abs(float64(p.W-q.W)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.W)), math.Abs(float64(q.W)))) || - math.Abs(float64(p.X+q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y+q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && - math.Abs(float64(p.Z+q.Z)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z)))) && - math.Abs(float64(p.W+q.W)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.W)), math.Abs(float64(q.W))))) -} - -// MatrixDecompose - Decompose a transformation matrix into its rotational, translational and scaling components -func MatrixDecompose(mat Matrix, translation *Vector3, rotation *Quaternion, scale *Vector3) { - // Extract translation. - translation.X = mat.M12 - translation.Y = mat.M13 - translation.Z = mat.M14 - - // Extract upper-left for determinant computation - a := mat.M0 - b := mat.M4 - c := mat.M8 - d := mat.M1 - e := mat.M5 - f := mat.M9 - g := mat.M2 - h := mat.M6 - i := mat.M10 - A := e*i - f*h - B := f*g - d*i - C := d*h - e*g - - // Extract scale - det := a*A + b*B + c*C - abc := NewVector3(a, b, c) - def := NewVector3(d, e, f) - ghi := NewVector3(g, h, i) - - scalex := Vector3Length(abc) - scaley := Vector3Length(def) - scalez := Vector3Length(ghi) - s := NewVector3(scalex, scaley, scalez) - - if det < 0 { - s = Vector3Negate(s) - } - - *scale = s - - // Remove scale from the matrix if it is not close to zero - clone := mat - if !FloatEquals(det, 0) { - clone.M0 /= s.X - clone.M5 /= s.Y - clone.M10 /= s.Z - - // Extract rotation - *rotation = QuaternionFromMatrix(clone) +// Clamp - Clamp float value +func Clamp(value, min, max float32) float32 { + var res float32 + if value < min { + res = min } else { - // Set to identity if close to zero - *rotation = QuaternionIdentity() + res = value } + + if res > max { + return max + } + + return res } diff --git a/raylib/raymath.h b/raylib/raymath.h index a531b3a..e396d5a 100644 --- a/raylib/raymath.h +++ b/raylib/raymath.h @@ -1,38 +1,26 @@ /********************************************************************************************** * -* raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions -* -* CONVENTIONS: -* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all -* math operations performed by the library consider the structure as it was column-major -* It is like transposed versions of the matrices are used for all the maths -* It benefits some functions making them cache-friendly and also avoids matrix -* transpositions sometimes required by OpenGL -* Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3] -* - Functions are always self-contained, no function use another raymath function inside, -* required code is directly re-implemented inside -* - Functions input parameters are always received by value (2 unavoidable exceptions) -* - Functions use always a "result" variable for return (except C++ operators) -* - Functions are always defined inline -* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) -* - No compound literals used to make sure libray is compatible with C++ +* raymath v1.2 - Math functions to work with Vector3, Matrix and Quaternions * * CONFIGURATION: -* #define RAYMATH_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. * -* #define RAYMATH_STATIC_INLINE -* Define static inline functions code, so #include header suffices for use. -* This may use up lots of memory. +* #define RAYMATH_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define RAYMATH_HEADER_ONLY +* Define static inline functions code, so #include header suffices for use. +* This may use up lots of memory. +* +* #define RAYMATH_STANDALONE +* Avoid raylib.h header inclusion in this file. +* Vector3 and Matrix data types are defined internally in raymath module. * -* #define RAYMATH_DISABLE_CPP_OPERATORS -* Disables C++ operator overloads for raymath types. * * LICENSE: zlib/libpng * -* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -54,32 +42,35 @@ #ifndef RAYMATH_H #define RAYMATH_H -#if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_STATIC_INLINE) - #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory" +//#define RAYMATH_STANDALONE // NOTE: To use raymath as standalone lib, just uncomment this line +//#define RAYMATH_HEADER_ONLY // NOTE: To compile functions as static inline, uncomment this line + +#ifndef RAYMATH_STANDALONE + #include "raylib.h" // Required for structs: Vector3, Matrix +#endif + +#if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_HEADER_ONLY) + #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_HEADER_ONLY is contradictory" #endif -// Function specifiers definition #if defined(RAYMATH_IMPLEMENTATION) #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) - #define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll) - #elif defined(BUILD_LIBTYPE_SHARED) - #define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib) + #define RMDEF __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll). #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) + #define RMDEF __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) #else - #define RMAPI extern inline // Provide external definition + #define RMDEF extern inline // Provide external definition #endif -#elif defined(RAYMATH_STATIC_INLINE) - #define RMAPI static inline // Functions may be inlined, no external out-of-line definition +#elif defined(RAYMATH_HEADER_ONLY) + #define RMDEF static inline // Functions may be inlined, no external out-of-line definition #else #if defined(__TINYC__) - #define RMAPI static inline // plain inline not supported by tinycc (See issue #435) + #define RMDEF static inline // plain inline not supported by tinycc (See issue #435) #else - #define RMAPI inline // Functions may be inlined or external definition used + #define RMDEF inline // Functions may be inlined or external definition used #endif #endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -87,10 +78,6 @@ #define PI 3.14159265358979323846f #endif -#ifndef EPSILON - #define EPSILON 0.000001f -#endif - #ifndef DEG2RAD #define DEG2RAD (PI/180.0f) #endif @@ -99,12 +86,12 @@ #define RAD2DEG (180.0f/PI) #endif -// Get float vector for Matrix +// Return float vector for Matrix #ifndef MatrixToFloat #define MatrixToFloat(mat) (MatrixToFloatV(mat).v) #endif -// Get float vector for Vector3 +// Return float vector for Vector3 #ifndef Vector3ToFloat #define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v) #endif @@ -112,120 +99,74 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#if !defined(RL_VECTOR2_TYPE) -// Vector2 type -typedef struct Vector2 { - float x; - float y; -} Vector2; -#define RL_VECTOR2_TYPE -#endif -#if !defined(RL_VECTOR3_TYPE) -// Vector3 type -typedef struct Vector3 { - float x; - float y; - float z; -} Vector3; -#define RL_VECTOR3_TYPE -#endif +#if defined(RAYMATH_STANDALONE) + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; -#if !defined(RL_VECTOR4_TYPE) -// Vector4 type -typedef struct Vector4 { - float x; - float y; - float z; - float w; -} Vector4; -#define RL_VECTOR4_TYPE -#endif + // Vector3 type + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; -#if !defined(RL_QUATERNION_TYPE) -// Quaternion type -typedef Vector4 Quaternion; -#define RL_QUATERNION_TYPE -#endif + // Vector4 type + typedef struct Vector4 { + float x; + float y; + float z; + float w; + } Vector4; -#if !defined(RL_MATRIX_TYPE) -// Matrix type (OpenGL style 4x4 - right handed, column major) -typedef struct Matrix { - float m0, m4, m8, m12; // Matrix first row (4 components) - float m1, m5, m9, m13; // Matrix second row (4 components) - float m2, m6, m10, m14; // Matrix third row (4 components) - float m3, m7, m11, m15; // Matrix fourth row (4 components) -} Matrix; -#define RL_MATRIX_TYPE + // Quaternion type + typedef Vector4 Quaternion; + + // Matrix type (OpenGL style 4x4 - right handed, column major) + typedef struct Matrix { + float m0, m4, m8, m12; + float m1, m5, m9, m13; + float m2, m6, m10, m14; + float m3, m7, m11, m15; + } Matrix; #endif // NOTE: Helper types to be used instead of array return types for *ToFloat functions -typedef struct float3 { - float v[3]; -} float3; +typedef struct float3 { float v[3]; } float3; +typedef struct float16 { float v[16]; } float16; -typedef struct float16 { - float v[16]; -} float16; - -#include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf() +#include // Required for: sinf(), cosf(), sqrtf(), tan(), fabs() //---------------------------------------------------------------------------------- // Module Functions Definition - Utils math //---------------------------------------------------------------------------------- // Clamp float value -RMAPI float Clamp(float value, float min, float max) +RMDEF float Clamp(float value, float min, float max) { - float result = (value < min)? min : value; - - if (result > max) result = max; - - return result; + const float res = value < min ? min : value; + return res > max ? max : res; } // Calculate linear interpolation between two floats -RMAPI float Lerp(float start, float end, float amount) +RMDEF float Lerp(float start, float end, float amount) { - float result = start + amount*(end - start); - - return result; + return start + amount*(end - start); } // Normalize input value within input range -RMAPI float Normalize(float value, float start, float end) +RMDEF float Normalize(float value, float start, float end) { - float result = (value - start)/(end - start); - - return result; + return (value - start)/(end - start); } // Remap input value within input range to output range -RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) +RMDEF float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) { - float result = (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart; - - return result; -} - -// Wrap input value from min to max -RMAPI float Wrap(float value, float min, float max) -{ - float result = value - (max - min)*floorf((value - min)/(max - min)); - - return result; -} - -// Check whether two given floats are almost equal -RMAPI int FloatEquals(float x, float y) -{ -#if !defined(EPSILON) - #define EPSILON 0.000001f -#endif - - int result = (fabsf(x - y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y)))); - - return result; + return (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart; } //---------------------------------------------------------------------------------- @@ -233,194 +174,120 @@ RMAPI int FloatEquals(float x, float y) //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMAPI Vector2 Vector2Zero(void) +RMDEF Vector2 Vector2Zero(void) { Vector2 result = { 0.0f, 0.0f }; - return result; } // Vector with components value 1.0f -RMAPI Vector2 Vector2One(void) +RMDEF Vector2 Vector2One(void) { Vector2 result = { 1.0f, 1.0f }; - return result; } // Add two vectors (v1 + v2) -RMAPI Vector2 Vector2Add(Vector2 v1, Vector2 v2) +RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2) { Vector2 result = { v1.x + v2.x, v1.y + v2.y }; - return result; } // Add vector and float value -RMAPI Vector2 Vector2AddValue(Vector2 v, float add) +RMDEF Vector2 Vector2AddValue(Vector2 v, float add) { Vector2 result = { v.x + add, v.y + add }; - return result; } // Subtract two vectors (v1 - v2) -RMAPI Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) +RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) { Vector2 result = { v1.x - v2.x, v1.y - v2.y }; - return result; } // Subtract vector by float value -RMAPI Vector2 Vector2SubtractValue(Vector2 v, float sub) +RMDEF Vector2 Vector2SubtractValue(Vector2 v, float sub) { Vector2 result = { v.x - sub, v.y - sub }; - return result; } // Calculate vector length -RMAPI float Vector2Length(Vector2 v) +RMDEF float Vector2Length(Vector2 v) { float result = sqrtf((v.x*v.x) + (v.y*v.y)); - return result; } // Calculate vector square length -RMAPI float Vector2LengthSqr(Vector2 v) +RMDEF float Vector2LengthSqr(Vector2 v) { float result = (v.x*v.x) + (v.y*v.y); - return result; } // Calculate two vectors dot product -RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2) +RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2) { float result = (v1.x*v2.x + v1.y*v2.y); - - return result; -} - -// Calculate two vectors cross product -RMAPI float Vector2CrossProduct(Vector2 v1, Vector2 v2) -{ - float result = (v1.x*v2.y - v1.y*v2.x); - return result; } // Calculate distance between two vectors -RMAPI float Vector2Distance(Vector2 v1, Vector2 v2) +RMDEF float Vector2Distance(Vector2 v1, Vector2 v2) { float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); - return result; } -// Calculate square distance between two vectors -RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) +// Calculate angle from two vectors in X-axis +RMDEF float Vector2Angle(Vector2 v1, Vector2 v2) { - float result = ((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); - - return result; -} - -// Calculate the signed angle from v1 to v2, relative to the origin (0, 0) -// NOTE: Coordinate system convention: positive X right, positive Y down, -// positive angles appear clockwise, and negative angles appear counterclockwise -RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) -{ - float result = 0.0f; - - float dot = v1.x*v2.x + v1.y*v2.y; - float det = v1.x*v2.y - v1.y*v2.x; - - result = atan2f(det, dot); - - return result; -} - -// Calculate angle defined by a two vectors line -// NOTE: Parameters need to be normalized -// Current implementation should be aligned with glm::angle -RMAPI float Vector2LineAngle(Vector2 start, Vector2 end) -{ - float result = 0.0f; - - // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior - result = -atan2f(end.y - start.y, end.x - start.x); - + float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); + if (result < 0) result += 360.0f; return result; } // Scale vector (multiply by value) -RMAPI Vector2 Vector2Scale(Vector2 v, float scale) +RMDEF Vector2 Vector2Scale(Vector2 v, float scale) { Vector2 result = { v.x*scale, v.y*scale }; - return result; } // Multiply vector by vector -RMAPI Vector2 Vector2Multiply(Vector2 v1, Vector2 v2) +RMDEF Vector2 Vector2Multiply(Vector2 v1, Vector2 v2) { Vector2 result = { v1.x*v2.x, v1.y*v2.y }; - return result; } // Negate vector -RMAPI Vector2 Vector2Negate(Vector2 v) +RMDEF Vector2 Vector2Negate(Vector2 v) { Vector2 result = { -v.x, -v.y }; - return result; } // Divide vector by vector -RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2) +RMDEF Vector2 Vector2Divide(Vector2 v1, Vector2 v2) { Vector2 result = { v1.x/v2.x, v1.y/v2.y }; - return result; } // Normalize provided vector -RMAPI Vector2 Vector2Normalize(Vector2 v) +RMDEF Vector2 Vector2Normalize(Vector2 v) { - Vector2 result = { 0 }; - float length = sqrtf((v.x*v.x) + (v.y*v.y)); - - if (length > 0) - { - float ilength = 1.0f/length; - result.x = v.x*ilength; - result.y = v.y*ilength; - } - - return result; -} - -// Transforms a Vector2 by a given Matrix -RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat) -{ - Vector2 result = { 0 }; - - float x = v.x; - float y = v.y; - float z = 0; - - result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; - result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; - + Vector2 result = Vector2Scale(v, 1/Vector2Length(v)); return result; } // Calculate linear interpolation between two vectors -RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) +RMDEF Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) { Vector2 result = { 0 }; @@ -431,11 +298,11 @@ RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) } // Calculate reflected vector to normal -RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal) +RMDEF Vector2 Vector2Reflect(Vector2 v, Vector2 normal) { Vector2 result = { 0 }; - float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product + float dotProduct = Vector2DotProduct(v, normal); result.x = v.x - (2.0f*normal.x)*dotProduct; result.y = v.y - (2.0f*normal.y)*dotProduct; @@ -443,52 +310,23 @@ RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal) return result; } -// Get min value for each pair of components -RMAPI Vector2 Vector2Min(Vector2 v1, Vector2 v2) +// Rotate Vector by float in Degrees. +RMDEF Vector2 Vector2Rotate(Vector2 v, float degs) { - Vector2 result = { 0 }; - - result.x = fminf(v1.x, v2.x); - result.y = fminf(v1.y, v2.y); - - return result; -} - -// Get max value for each pair of components -RMAPI Vector2 Vector2Max(Vector2 v1, Vector2 v2) -{ - Vector2 result = { 0 }; - - result.x = fmaxf(v1.x, v2.x); - result.y = fmaxf(v1.y, v2.y); - - return result; -} - -// Rotate vector by angle -RMAPI Vector2 Vector2Rotate(Vector2 v, float angle) -{ - Vector2 result = { 0 }; - - float cosres = cosf(angle); - float sinres = sinf(angle); - - result.x = v.x*cosres - v.y*sinres; - result.y = v.x*sinres + v.y*cosres; - + float rads = degs*DEG2RAD; + Vector2 result = {v.x*cosf(rads) - v.y*sinf(rads) , v.x*sinf(rads) + v.y*cosf(rads) }; return result; } // Move Vector towards target -RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance) +RMDEF Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance) { Vector2 result = { 0 }; - float dx = target.x - v.x; float dy = target.y - v.y; float value = (dx*dx) + (dy*dy); - if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; + if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) result = target; float dist = sqrtf(value); @@ -498,323 +336,157 @@ RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance) return result; } -// Invert the given vector -RMAPI Vector2 Vector2Invert(Vector2 v) -{ - Vector2 result = { 1.0f/v.x, 1.0f/v.y }; - - return result; -} - -// Clamp the components of the vector between -// min and max values specified by the given vectors -RMAPI Vector2 Vector2Clamp(Vector2 v, Vector2 min, Vector2 max) -{ - Vector2 result = { 0 }; - - result.x = fminf(max.x, fmaxf(min.x, v.x)); - result.y = fminf(max.y, fmaxf(min.y, v.y)); - - return result; -} - -// Clamp the magnitude of the vector between two min and max values -RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max) -{ - Vector2 result = v; - - float length = (v.x*v.x) + (v.y*v.y); - if (length > 0.0f) - { - length = sqrtf(length); - - float scale = 1; // By default, 1 as the neutral element. - if (length < min) - { - scale = min/length; - } - else if (length > max) - { - scale = max/length; - } - - result.x = v.x*scale; - result.y = v.y*scale; - } - - return result; -} - -// Check whether two given vectors are almost equal -RMAPI int Vector2Equals(Vector2 p, Vector2 q) -{ -#if !defined(EPSILON) - #define EPSILON 0.000001f -#endif - - int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && - ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))); - - return result; -} - -// Compute the direction of a refracted ray -// v: normalized direction of the incoming ray -// n: normalized normal vector of the interface of two optical media -// r: ratio of the refractive index of the medium from where the ray comes -// to the refractive index of the medium on the other side of the surface -RMAPI Vector2 Vector2Refract(Vector2 v, Vector2 n, float r) -{ - Vector2 result = { 0 }; - - float dot = v.x*n.x + v.y*n.y; - float d = 1.0f - r*r*(1.0f - dot*dot); - - if (d >= 0.0f) - { - d = sqrtf(d); - v.x = r*v.x - (r*dot + d)*n.x; - v.y = r*v.y - (r*dot + d)*n.y; - - result = v; - } - - return result; -} - - //---------------------------------------------------------------------------------- // Module Functions Definition - Vector3 math //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMAPI Vector3 Vector3Zero(void) +RMDEF Vector3 Vector3Zero(void) { Vector3 result = { 0.0f, 0.0f, 0.0f }; - return result; } // Vector with components value 1.0f -RMAPI Vector3 Vector3One(void) +RMDEF Vector3 Vector3One(void) { Vector3 result = { 1.0f, 1.0f, 1.0f }; - return result; } // Add two vectors -RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2) +RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2) { Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; - return result; } // Add vector and float value -RMAPI Vector3 Vector3AddValue(Vector3 v, float add) +RMDEF Vector3 Vector3AddValue(Vector3 v, float add) { Vector3 result = { v.x + add, v.y + add, v.z + add }; - return result; } // Subtract two vectors -RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) +RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) { Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; - return result; } // Subtract vector by float value -RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub) +RMDEF Vector3 Vector3SubtractValue(Vector3 v, float sub) { Vector3 result = { v.x - sub, v.y - sub, v.z - sub }; - return result; } // Multiply vector by scalar -RMAPI Vector3 Vector3Scale(Vector3 v, float scalar) +RMDEF Vector3 Vector3Scale(Vector3 v, float scalar) { Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar }; - return result; } // Multiply vector by vector -RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2) +RMDEF Vector3 Vector3Multiply(Vector3 v1, Vector3 v2) { Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z }; - return result; } // Calculate two vectors cross product -RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2) +RMDEF Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2) { Vector3 result = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; - return result; } // Calculate one vector perpendicular vector -RMAPI Vector3 Vector3Perpendicular(Vector3 v) +RMDEF Vector3 Vector3Perpendicular(Vector3 v) { Vector3 result = { 0 }; - float min = fabsf(v.x); + float min = (float) fabs(v.x); Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f}; - if (fabsf(v.y) < min) + if (fabs(v.y) < min) { - min = fabsf(v.y); + min = (float) fabs(v.y); Vector3 tmp = {0.0f, 1.0f, 0.0f}; cardinalAxis = tmp; } - if (fabsf(v.z) < min) + if (fabs(v.z) < min) { Vector3 tmp = {0.0f, 0.0f, 1.0f}; cardinalAxis = tmp; } - // Cross product between vectors - result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y; - result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z; - result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x; + result = Vector3CrossProduct(v, cardinalAxis); return result; } // Calculate vector length -RMAPI float Vector3Length(const Vector3 v) +RMDEF float Vector3Length(const Vector3 v) { float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); - return result; } // Calculate vector square length -RMAPI float Vector3LengthSqr(const Vector3 v) +RMDEF float Vector3LengthSqr(const Vector3 v) { float result = v.x*v.x + v.y*v.y + v.z*v.z; - return result; } // Calculate two vectors dot product -RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2) +RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2) { float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); - return result; } // Calculate distance between two vectors -RMAPI float Vector3Distance(Vector3 v1, Vector3 v2) +RMDEF float Vector3Distance(Vector3 v1, Vector3 v2) { - float result = 0.0f; - float dx = v2.x - v1.x; float dy = v2.y - v1.y; float dz = v2.z - v1.z; - result = sqrtf(dx*dx + dy*dy + dz*dz); - - return result; -} - -// Calculate square distance between two vectors -RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2) -{ - float result = 0.0f; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - result = dx*dx + dy*dy + dz*dz; - - return result; -} - -// Calculate angle between two vectors -RMAPI float Vector3Angle(Vector3 v1, Vector3 v2) -{ - float result = 0.0f; - - Vector3 cross = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; - float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z); - float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); - result = atan2f(len, dot); - + float result = sqrtf(dx*dx + dy*dy + dz*dz); return result; } // Negate provided vector (invert direction) -RMAPI Vector3 Vector3Negate(Vector3 v) +RMDEF Vector3 Vector3Negate(Vector3 v) { Vector3 result = { -v.x, -v.y, -v.z }; - return result; } // Divide vector by vector -RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2) +RMDEF Vector3 Vector3Divide(Vector3 v1, Vector3 v2) { Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z }; - return result; } // Normalize provided vector -RMAPI Vector3 Vector3Normalize(Vector3 v) +RMDEF Vector3 Vector3Normalize(Vector3 v) { Vector3 result = v; - float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); - if (length != 0.0f) - { - float ilength = 1.0f/length; + float length, ilength; + length = Vector3Length(v); + if (length == 0.0f) length = 1.0f; + ilength = 1.0f/length; - result.x *= ilength; - result.y *= ilength; - result.z *= ilength; - } - - return result; -} - -//Calculate the projection of the vector v1 on to v2 -RMAPI Vector3 Vector3Project(Vector3 v1, Vector3 v2) -{ - Vector3 result = { 0 }; - - float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); - float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z); - - float mag = v1dv2/v2dv2; - - result.x = v2.x*mag; - result.y = v2.y*mag; - result.z = v2.z*mag; - - return result; -} - -//Calculate the rejection of the vector v1 on to v2 -RMAPI Vector3 Vector3Reject(Vector3 v1, Vector3 v2) -{ - Vector3 result = { 0 }; - - float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); - float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z); - - float mag = v1dv2/v2dv2; - - result.x = v1.x - (v2.x*mag); - result.y = v1.y - (v2.y*mag); - result.z = v1.z - (v2.z*mag); + result.x *= ilength; + result.y *= ilength; + result.z *= ilength; return result; } @@ -822,43 +494,18 @@ RMAPI Vector3 Vector3Reject(Vector3 v1, Vector3 v2) // Orthonormalize provided vectors // Makes vectors normalized and orthogonal to each other // Gram-Schmidt function implementation -RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) +RMDEF void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) { - float length = 0.0f; - float ilength = 0.0f; - - // Vector3Normalize(*v1); - Vector3 v = *v1; - length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); - if (length == 0.0f) length = 1.0f; - ilength = 1.0f/length; - v1->x *= ilength; - v1->y *= ilength; - v1->z *= ilength; - - // Vector3CrossProduct(*v1, *v2) - Vector3 vn1 = { v1->y*v2->z - v1->z*v2->y, v1->z*v2->x - v1->x*v2->z, v1->x*v2->y - v1->y*v2->x }; - - // Vector3Normalize(vn1); - v = vn1; - length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); - if (length == 0.0f) length = 1.0f; - ilength = 1.0f/length; - vn1.x *= ilength; - vn1.y *= ilength; - vn1.z *= ilength; - - // Vector3CrossProduct(vn1, *v1) - Vector3 vn2 = { vn1.y*v1->z - vn1.z*v1->y, vn1.z*v1->x - vn1.x*v1->z, vn1.x*v1->y - vn1.y*v1->x }; - - *v2 = vn2; + *v1 = Vector3Normalize(*v1); + Vector3 vn = Vector3CrossProduct(*v1, *v2); + vn = Vector3Normalize(vn); + *v2 = Vector3CrossProduct(vn, *v1); } // Transforms a Vector3 by a given Matrix -RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat) +RMDEF Vector3 Vector3Transform(Vector3 v, Matrix mat) { Vector3 result = { 0 }; - float x = v.x; float y = v.y; float z = v.z; @@ -871,7 +518,7 @@ RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat) } // Transform a vector by quaternion rotation -RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) +RMDEF Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) { Vector3 result = { 0 }; @@ -882,81 +529,8 @@ RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) return result; } -// Rotates a vector around an axis -RMAPI Vector3 Vector3RotateByAxisAngle(Vector3 v, Vector3 axis, float angle) -{ - // Using Euler-Rodrigues Formula - // Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula - - Vector3 result = v; - - // Vector3Normalize(axis); - float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); - if (length == 0.0f) length = 1.0f; - float ilength = 1.0f/length; - axis.x *= ilength; - axis.y *= ilength; - axis.z *= ilength; - - angle /= 2.0f; - float a = sinf(angle); - float b = axis.x*a; - float c = axis.y*a; - float d = axis.z*a; - a = cosf(angle); - Vector3 w = { b, c, d }; - - // Vector3CrossProduct(w, v) - Vector3 wv = { w.y*v.z - w.z*v.y, w.z*v.x - w.x*v.z, w.x*v.y - w.y*v.x }; - - // Vector3CrossProduct(w, wv) - Vector3 wwv = { w.y*wv.z - w.z*wv.y, w.z*wv.x - w.x*wv.z, w.x*wv.y - w.y*wv.x }; - - // Vector3Scale(wv, 2*a) - a *= 2; - wv.x *= a; - wv.y *= a; - wv.z *= a; - - // Vector3Scale(wwv, 2) - wwv.x *= 2; - wwv.y *= 2; - wwv.z *= 2; - - result.x += wv.x; - result.y += wv.y; - result.z += wv.z; - - result.x += wwv.x; - result.y += wwv.y; - result.z += wwv.z; - - return result; -} - -// Move Vector towards target -RMAPI Vector3 Vector3MoveTowards(Vector3 v, Vector3 target, float maxDistance) -{ - Vector3 result = { 0 }; - - float dx = target.x - v.x; - float dy = target.y - v.y; - float dz = target.z - v.z; - float value = (dx*dx) + (dy*dy) + (dz*dz); - - if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; - - float dist = sqrtf(value); - - result.x = v.x + dx/dist*maxDistance; - result.y = v.y + dy/dist*maxDistance; - result.z = v.z + dz/dist*maxDistance; - - return result; -} - // Calculate linear interpolation between two vectors -RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) +RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) { Vector3 result = { 0 }; @@ -967,32 +541,16 @@ RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) return result; } -// Calculate cubic hermite interpolation between two vectors and their tangents -// as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic -RMAPI Vector3 Vector3CubicHermite(Vector3 v1, Vector3 tangent1, Vector3 v2, Vector3 tangent2, float amount) -{ - Vector3 result = { 0 }; - - float amountPow2 = amount*amount; - float amountPow3 = amount*amount*amount; - - result.x = (2*amountPow3 - 3*amountPow2 + 1)*v1.x + (amountPow3 - 2*amountPow2 + amount)*tangent1.x + (-2*amountPow3 + 3*amountPow2)*v2.x + (amountPow3 - amountPow2)*tangent2.x; - result.y = (2*amountPow3 - 3*amountPow2 + 1)*v1.y + (amountPow3 - 2*amountPow2 + amount)*tangent1.y + (-2*amountPow3 + 3*amountPow2)*v2.y + (amountPow3 - amountPow2)*tangent2.y; - result.z = (2*amountPow3 - 3*amountPow2 + 1)*v1.z + (amountPow3 - 2*amountPow2 + amount)*tangent1.z + (-2*amountPow3 + 3*amountPow2)*v2.z + (amountPow3 - amountPow2)*tangent2.z; - - return result; -} - // Calculate reflected vector to normal -RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal) +RMDEF Vector3 Vector3Reflect(Vector3 v, Vector3 normal) { - Vector3 result = { 0 }; - // I is the original vector // N is the normal of the incident plane - // R = I - (2*N*(DotProduct[I, N])) + // R = I - (2*N*( DotProduct[ I,N] )) - float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z); + Vector3 result = { 0 }; + + float dotProduct = Vector3DotProduct(v, normal); result.x = v.x - (2.0f*normal.x)*dotProduct; result.y = v.y - (2.0f*normal.y)*dotProduct; @@ -1001,8 +559,8 @@ RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal) return result; } -// Get min value for each pair of components -RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2) +// Return min value for each pair of components +RMDEF Vector3 Vector3Min(Vector3 v1, Vector3 v2) { Vector3 result = { 0 }; @@ -1013,8 +571,8 @@ RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2) return result; } -// Get max value for each pair of components -RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2) +// Return max value for each pair of components +RMDEF Vector3 Vector3Max(Vector3 v1, Vector3 v2) { Vector3 result = { 0 }; @@ -1027,21 +585,23 @@ RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2) // Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c) // NOTE: Assumes P is on the plane of the triangle -RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) +RMDEF Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) { - Vector3 result = { 0 }; + //Vector v0 = b - a, v1 = c - a, v2 = p - a; - Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z }; // Vector3Subtract(b, a) - Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z }; // Vector3Subtract(c, a) - Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z }; // Vector3Subtract(p, a) - float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z); // Vector3DotProduct(v0, v0) - float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z); // Vector3DotProduct(v0, v1) - float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); // Vector3DotProduct(v1, v1) - float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z); // Vector3DotProduct(v2, v0) - float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z); // Vector3DotProduct(v2, v1) + Vector3 v0 = Vector3Subtract(b, a); + Vector3 v1 = Vector3Subtract(c, a); + Vector3 v2 = Vector3Subtract(p, a); + float d00 = Vector3DotProduct(v0, v0); + float d01 = Vector3DotProduct(v0, v1); + float d11 = Vector3DotProduct(v1, v1); + float d20 = Vector3DotProduct(v2, v0); + float d21 = Vector3DotProduct(v2, v1); float denom = d00*d11 - d01*d01; + Vector3 result = { 0 }; + result.y = (d11*d20 - d01*d21)/denom; result.z = (d00*d21 - d01*d20)/denom; result.x = 1.0f - (result.z + result.y); @@ -1049,92 +609,8 @@ RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) return result; } -// Projects a Vector3 from screen space into object space -// NOTE: We are avoiding calling other raymath functions despite available -RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) -{ - Vector3 result = { 0 }; - - // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it - Matrix matViewProj = { // MatrixMultiply(view, projection); - view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, - view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, - view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14, - view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15, - view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12, - view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13, - view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14, - view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15, - view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12, - view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13, - view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14, - view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15, - view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12, - view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13, - view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14, - view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 }; - - // Calculate inverted matrix -> MatrixInvert(matViewProj); - // Cache the matrix values (speed optimization) - float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3; - float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7; - float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11; - float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15; - - float b00 = a00*a11 - a01*a10; - float b01 = a00*a12 - a02*a10; - float b02 = a00*a13 - a03*a10; - float b03 = a01*a12 - a02*a11; - float b04 = a01*a13 - a03*a11; - float b05 = a02*a13 - a03*a12; - float b06 = a20*a31 - a21*a30; - float b07 = a20*a32 - a22*a30; - float b08 = a20*a33 - a23*a30; - float b09 = a21*a32 - a22*a31; - float b10 = a21*a33 - a23*a31; - float b11 = a22*a33 - a23*a32; - - // Calculate the invert determinant (inlined to avoid double-caching) - float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); - - Matrix matViewProjInv = { - (a11*b11 - a12*b10 + a13*b09)*invDet, - (-a01*b11 + a02*b10 - a03*b09)*invDet, - (a31*b05 - a32*b04 + a33*b03)*invDet, - (-a21*b05 + a22*b04 - a23*b03)*invDet, - (-a10*b11 + a12*b08 - a13*b07)*invDet, - (a00*b11 - a02*b08 + a03*b07)*invDet, - (-a30*b05 + a32*b02 - a33*b01)*invDet, - (a20*b05 - a22*b02 + a23*b01)*invDet, - (a10*b10 - a11*b08 + a13*b06)*invDet, - (-a00*b10 + a01*b08 - a03*b06)*invDet, - (a30*b04 - a31*b02 + a33*b00)*invDet, - (-a20*b04 + a21*b02 - a23*b00)*invDet, - (-a10*b09 + a11*b07 - a12*b06)*invDet, - (a00*b09 - a01*b07 + a02*b06)*invDet, - (-a30*b03 + a31*b01 - a32*b00)*invDet, - (a20*b03 - a21*b01 + a22*b00)*invDet }; - - // Create quaternion from source point - Quaternion quat = { source.x, source.y, source.z, 1.0f }; - - // Multiply quat point by unprojecte matrix - Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv) - matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w, - matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w, - matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w, - matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w }; - - // Normalized world points in vectors - result.x = qtransformed.x/qtransformed.w; - result.y = qtransformed.y/qtransformed.w; - result.z = qtransformed.z/qtransformed.w; - - return result; -} - -// Get Vector3 as float array -RMAPI float3 Vector3ToFloatV(Vector3 v) +// Returns Vector3 as float array +RMDEF float3 Vector3ToFloatV(Vector3 v) { float3 buffer = { 0 }; @@ -1145,372 +621,38 @@ RMAPI float3 Vector3ToFloatV(Vector3 v) return buffer; } -// Invert the given vector -RMAPI Vector3 Vector3Invert(Vector3 v) -{ - Vector3 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z }; - - return result; -} - -// Clamp the components of the vector between -// min and max values specified by the given vectors -RMAPI Vector3 Vector3Clamp(Vector3 v, Vector3 min, Vector3 max) -{ - Vector3 result = { 0 }; - - result.x = fminf(max.x, fmaxf(min.x, v.x)); - result.y = fminf(max.y, fmaxf(min.y, v.y)); - result.z = fminf(max.z, fmaxf(min.z, v.z)); - - return result; -} - -// Clamp the magnitude of the vector between two values -RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max) -{ - Vector3 result = v; - - float length = (v.x*v.x) + (v.y*v.y) + (v.z*v.z); - if (length > 0.0f) - { - length = sqrtf(length); - - float scale = 1; // By default, 1 as the neutral element. - if (length < min) - { - scale = min/length; - } - else if (length > max) - { - scale = max/length; - } - - result.x = v.x*scale; - result.y = v.y*scale; - result.z = v.z*scale; - } - - return result; -} - -// Check whether two given vectors are almost equal -RMAPI int Vector3Equals(Vector3 p, Vector3 q) -{ -#if !defined(EPSILON) - #define EPSILON 0.000001f -#endif - - int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && - ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && - ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))); - - return result; -} - -// Compute the direction of a refracted ray -// v: normalized direction of the incoming ray -// n: normalized normal vector of the interface of two optical media -// r: ratio of the refractive index of the medium from where the ray comes -// to the refractive index of the medium on the other side of the surface -RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r) -{ - Vector3 result = { 0 }; - - float dot = v.x*n.x + v.y*n.y + v.z*n.z; - float d = 1.0f - r*r*(1.0f - dot*dot); - - if (d >= 0.0f) - { - d = sqrtf(d); - v.x = r*v.x - (r*dot + d)*n.x; - v.y = r*v.y - (r*dot + d)*n.y; - v.z = r*v.z - (r*dot + d)*n.z; - - result = v; - } - - return result; -} - - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Vector4 math -//---------------------------------------------------------------------------------- - -RMAPI Vector4 Vector4Zero(void) -{ - Vector4 result = { 0.0f, 0.0f, 0.0f, 0.0f }; - return result; -} - -RMAPI Vector4 Vector4One(void) -{ - Vector4 result = { 1.0f, 1.0f, 1.0f, 1.0f }; - return result; -} - -RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2) -{ - Vector4 result = { - v1.x + v2.x, - v1.y + v2.y, - v1.z + v2.z, - v1.w + v2.w - }; - return result; -} - -RMAPI Vector4 Vector4AddValue(Vector4 v, float add) -{ - Vector4 result = { - v.x + add, - v.y + add, - v.z + add, - v.w + add - }; - return result; -} - -RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2) -{ - Vector4 result = { - v1.x - v2.x, - v1.y - v2.y, - v1.z - v2.z, - v1.w - v2.w - }; - return result; -} - -RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add) -{ - Vector4 result = { - v.x - add, - v.y - add, - v.z - add, - v.w - add - }; - return result; -} - -RMAPI float Vector4Length(Vector4 v) -{ - float result = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w)); - return result; -} - -RMAPI float Vector4LengthSqr(Vector4 v) -{ - float result = (v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w); - return result; -} - -RMAPI float Vector4DotProduct(Vector4 v1, Vector4 v2) -{ - float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w); - return result; -} - -// Calculate distance between two vectors -RMAPI float Vector4Distance(Vector4 v1, Vector4 v2) -{ - float result = sqrtf( - (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + - (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w)); - return result; -} - -// Calculate square distance between two vectors -RMAPI float Vector4DistanceSqr(Vector4 v1, Vector4 v2) -{ - float result = - (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + - (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w); - - return result; -} - -RMAPI Vector4 Vector4Scale(Vector4 v, float scale) -{ - Vector4 result = { v.x*scale, v.y*scale, v.z*scale, v.w*scale }; - return result; -} - -// Multiply vector by vector -RMAPI Vector4 Vector4Multiply(Vector4 v1, Vector4 v2) -{ - Vector4 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z, v1.w*v2.w }; - return result; -} - -// Negate vector -RMAPI Vector4 Vector4Negate(Vector4 v) -{ - Vector4 result = { -v.x, -v.y, -v.z, -v.w }; - return result; -} - -// Divide vector by vector -RMAPI Vector4 Vector4Divide(Vector4 v1, Vector4 v2) -{ - Vector4 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z, v1.w/v2.w }; - return result; -} - -// Normalize provided vector -RMAPI Vector4 Vector4Normalize(Vector4 v) -{ - Vector4 result = { 0 }; - float length = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w)); - - if (length > 0) - { - float ilength = 1.0f/length; - result.x = v.x*ilength; - result.y = v.y*ilength; - result.z = v.z*ilength; - result.w = v.w*ilength; - } - - return result; -} - -// Get min value for each pair of components -RMAPI Vector4 Vector4Min(Vector4 v1, Vector4 v2) -{ - Vector4 result = { 0 }; - - result.x = fminf(v1.x, v2.x); - result.y = fminf(v1.y, v2.y); - result.z = fminf(v1.z, v2.z); - result.w = fminf(v1.w, v2.w); - - return result; -} - -// Get max value for each pair of components -RMAPI Vector4 Vector4Max(Vector4 v1, Vector4 v2) -{ - Vector4 result = { 0 }; - - result.x = fmaxf(v1.x, v2.x); - result.y = fmaxf(v1.y, v2.y); - result.z = fmaxf(v1.z, v2.z); - result.w = fmaxf(v1.w, v2.w); - - return result; -} - -// Calculate linear interpolation between two vectors -RMAPI Vector4 Vector4Lerp(Vector4 v1, Vector4 v2, float amount) -{ - Vector4 result = { 0 }; - - result.x = v1.x + amount*(v2.x - v1.x); - result.y = v1.y + amount*(v2.y - v1.y); - result.z = v1.z + amount*(v2.z - v1.z); - result.w = v1.w + amount*(v2.w - v1.w); - - return result; -} - -// Move Vector towards target -RMAPI Vector4 Vector4MoveTowards(Vector4 v, Vector4 target, float maxDistance) -{ - Vector4 result = { 0 }; - - float dx = target.x - v.x; - float dy = target.y - v.y; - float dz = target.z - v.z; - float dw = target.w - v.w; - float value = (dx*dx) + (dy*dy) + (dz*dz) + (dw*dw); - - if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; - - float dist = sqrtf(value); - - result.x = v.x + dx/dist*maxDistance; - result.y = v.y + dy/dist*maxDistance; - result.z = v.z + dz/dist*maxDistance; - result.w = v.w + dw/dist*maxDistance; - - return result; -} - -// Invert the given vector -RMAPI Vector4 Vector4Invert(Vector4 v) -{ - Vector4 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z, 1.0f/v.w }; - return result; -} - -// Check whether two given vectors are almost equal -RMAPI int Vector4Equals(Vector4 p, Vector4 q) -{ -#if !defined(EPSILON) - #define EPSILON 0.000001f -#endif - - int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && - ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && - ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && - ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w))))); - return result; -} - - //---------------------------------------------------------------------------------- // Module Functions Definition - Matrix math //---------------------------------------------------------------------------------- // Compute matrix determinant -RMAPI float MatrixDeterminant(Matrix mat) +RMDEF float MatrixDeterminant(Matrix mat) { - float result = 0.0f; -/* // Cache the matrix values (speed optimization) float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; - // NOTE: It takes 72 multiplication to calculate 4x4 matrix determinant - result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + - a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + - a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + - a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + - a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + - a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; -*/ - // Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion), - // previous operation can be simplified to 40 multiplications, decreasing matrix - // size from 4x4 to 2x2 using minors - - // Cache the matrix values (speed optimization) - float m0 = mat.m0, m1 = mat.m1, m2 = mat.m2, m3 = mat.m3; - float m4 = mat.m4, m5 = mat.m5, m6 = mat.m6, m7 = mat.m7; - float m8 = mat.m8, m9 = mat.m9, m10 = mat.m10, m11 = mat.m11; - float m12 = mat.m12, m13 = mat.m13, m14 = mat.m14, m15 = mat.m15; - - result = (m0*((m5*(m10*m15 - m11*m14) - m9*(m6*m15 - m7*m14) + m13*(m6*m11 - m7*m10))) - - m4*((m1*(m10*m15 - m11*m14) - m9*(m2*m15 - m3*m14) + m13*(m2*m11 - m3*m10))) + - m8*((m1*(m6*m15 - m7*m14) - m5*(m2*m15 - m3*m14) + m13*(m2*m7 - m3*m6))) - - m12*((m1*(m6*m11 - m7*m10) - m5*(m2*m11 - m3*m10) + m9*(m2*m7 - m3*m6)))); + float result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + + a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + + a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + + a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + + a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + + a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; return result; } -// Get the trace of the matrix (sum of the values along the diagonal) -RMAPI float MatrixTrace(Matrix mat) +// Returns the trace of the matrix (sum of the values along the diagonal) +RMDEF float MatrixTrace(Matrix mat) { float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15); - return result; } // Transposes provided matrix -RMAPI Matrix MatrixTranspose(Matrix mat) +RMDEF Matrix MatrixTranspose(Matrix mat) { Matrix result = { 0 }; @@ -1535,7 +677,7 @@ RMAPI Matrix MatrixTranspose(Matrix mat) } // Invert provided matrix -RMAPI Matrix MatrixInvert(Matrix mat) +RMDEF Matrix MatrixInvert(Matrix mat) { Matrix result = { 0 }; @@ -1581,8 +723,35 @@ RMAPI Matrix MatrixInvert(Matrix mat) return result; } -// Get identity matrix -RMAPI Matrix MatrixIdentity(void) +// Normalize provided matrix +RMDEF Matrix MatrixNormalize(Matrix mat) +{ + Matrix result = { 0 }; + + float det = MatrixDeterminant(mat); + + result.m0 = mat.m0/det; + result.m1 = mat.m1/det; + result.m2 = mat.m2/det; + result.m3 = mat.m3/det; + result.m4 = mat.m4/det; + result.m5 = mat.m5/det; + result.m6 = mat.m6/det; + result.m7 = mat.m7/det; + result.m8 = mat.m8/det; + result.m9 = mat.m9/det; + result.m10 = mat.m10/det; + result.m11 = mat.m11/det; + result.m12 = mat.m12/det; + result.m13 = mat.m13/det; + result.m14 = mat.m14/det; + result.m15 = mat.m15/det; + + return result; +} + +// Returns identity matrix +RMDEF Matrix MatrixIdentity(void) { Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -1593,9 +762,9 @@ RMAPI Matrix MatrixIdentity(void) } // Add two matrices -RMAPI Matrix MatrixAdd(Matrix left, Matrix right) +RMDEF Matrix MatrixAdd(Matrix left, Matrix right) { - Matrix result = { 0 }; + Matrix result = MatrixIdentity(); result.m0 = left.m0 + right.m0; result.m1 = left.m1 + right.m1; @@ -1618,9 +787,9 @@ RMAPI Matrix MatrixAdd(Matrix left, Matrix right) } // Subtract two matrices (left - right) -RMAPI Matrix MatrixSubtract(Matrix left, Matrix right) +RMDEF Matrix MatrixSubtract(Matrix left, Matrix right) { - Matrix result = { 0 }; + Matrix result = MatrixIdentity(); result.m0 = left.m0 - right.m0; result.m1 = left.m1 - right.m1; @@ -1642,9 +811,9 @@ RMAPI Matrix MatrixSubtract(Matrix left, Matrix right) return result; } -// Get two matrix multiplication +// Returns two matrix multiplication // NOTE: When multiplying matrices... the order matters! -RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) +RMDEF Matrix MatrixMultiply(Matrix left, Matrix right) { Matrix result = { 0 }; @@ -1668,8 +837,8 @@ RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) return result; } -// Get translation matrix -RMAPI Matrix MatrixTranslate(float x, float y, float z) +// Returns translation matrix +RMDEF Matrix MatrixTranslate(float x, float y, float z) { Matrix result = { 1.0f, 0.0f, 0.0f, x, 0.0f, 1.0f, 0.0f, y, @@ -1681,7 +850,7 @@ RMAPI Matrix MatrixTranslate(float x, float y, float z) // Create rotation matrix from axis and angle // NOTE: Angle should be provided in radians -RMAPI Matrix MatrixRotate(Vector3 axis, float angle) +RMDEF Matrix MatrixRotate(Vector3 axis, float angle) { Matrix result = { 0 }; @@ -1691,28 +860,28 @@ RMAPI Matrix MatrixRotate(Vector3 axis, float angle) if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) { - float ilength = 1.0f/sqrtf(lengthSquared); - x *= ilength; - y *= ilength; - z *= ilength; + float inverseLength = 1.0f/sqrtf(lengthSquared); + x *= inverseLength; + y *= inverseLength; + z *= inverseLength; } float sinres = sinf(angle); float cosres = cosf(angle); float t = 1.0f - cosres; - result.m0 = x*x*t + cosres; - result.m1 = y*x*t + z*sinres; - result.m2 = z*x*t - y*sinres; - result.m3 = 0.0f; + result.m0 = x*x*t + cosres; + result.m1 = y*x*t + z*sinres; + result.m2 = z*x*t - y*sinres; + result.m3 = 0.0f; - result.m4 = x*y*t - z*sinres; - result.m5 = y*y*t + cosres; - result.m6 = z*y*t + x*sinres; - result.m7 = 0.0f; + result.m4 = x*y*t - z*sinres; + result.m5 = y*y*t + cosres; + result.m6 = z*y*t + x*sinres; + result.m7 = 0.0f; - result.m8 = x*z*t + y*sinres; - result.m9 = y*z*t - x*sinres; + result.m8 = x*z*t + y*sinres; + result.m9 = y*z*t - x*sinres; result.m10 = z*z*t + cosres; result.m11 = 0.0f; @@ -1724,136 +893,119 @@ RMAPI Matrix MatrixRotate(Vector3 axis, float angle) return result; } -// Get x-rotation matrix -// NOTE: Angle must be provided in radians -RMAPI Matrix MatrixRotateX(float angle) +// Returns x-rotation matrix (angle in radians) +RMDEF Matrix MatrixRotateX(float angle) { - Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + Matrix result = MatrixIdentity(); float cosres = cosf(angle); float sinres = sinf(angle); result.m5 = cosres; - result.m6 = sinres; - result.m9 = -sinres; + result.m6 = -sinres; + result.m9 = sinres; result.m10 = cosres; return result; } -// Get y-rotation matrix -// NOTE: Angle must be provided in radians -RMAPI Matrix MatrixRotateY(float angle) +// Returns y-rotation matrix (angle in radians) +RMDEF Matrix MatrixRotateY(float angle) { - Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + Matrix result = MatrixIdentity(); float cosres = cosf(angle); float sinres = sinf(angle); result.m0 = cosres; - result.m2 = -sinres; - result.m8 = sinres; + result.m2 = sinres; + result.m8 = -sinres; result.m10 = cosres; return result; } -// Get z-rotation matrix -// NOTE: Angle must be provided in radians -RMAPI Matrix MatrixRotateZ(float angle) +// Returns z-rotation matrix (angle in radians) +RMDEF Matrix MatrixRotateZ(float angle) { - Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + Matrix result = MatrixIdentity(); float cosres = cosf(angle); float sinres = sinf(angle); result.m0 = cosres; - result.m1 = sinres; - result.m4 = -sinres; + result.m1 = -sinres; + result.m4 = sinres; result.m5 = cosres; return result; } -// Get xyz-rotation matrix -// NOTE: Angle must be provided in radians -RMAPI Matrix MatrixRotateXYZ(Vector3 angle) +// Returns xyz-rotation matrix (angles in radians) +RMDEF Matrix MatrixRotateXYZ(Vector3 ang) { - Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + Matrix result = MatrixIdentity(); - float cosz = cosf(-angle.z); - float sinz = sinf(-angle.z); - float cosy = cosf(-angle.y); - float siny = sinf(-angle.y); - float cosx = cosf(-angle.x); - float sinx = sinf(-angle.x); + float cosz = cosf(-ang.z); + float sinz = sinf(-ang.z); + float cosy = cosf(-ang.y); + float siny = sinf(-ang.y); + float cosx = cosf(-ang.x); + float sinx = sinf(-ang.x); result.m0 = cosz*cosy; - result.m1 = (cosz*siny*sinx) - (sinz*cosx); - result.m2 = (cosz*siny*cosx) + (sinz*sinx); + result.m4 = (cosz*siny*sinx) - (sinz*cosx); + result.m8 = (cosz*siny*cosx) + (sinz*sinx); - result.m4 = sinz*cosy; + result.m1 = sinz*cosy; result.m5 = (sinz*siny*sinx) + (cosz*cosx); - result.m6 = (sinz*siny*cosx) - (cosz*sinx); + result.m9 = (sinz*siny*cosx) - (cosz*sinx); - result.m8 = -siny; - result.m9 = cosy*sinx; + result.m2 = -siny; + result.m6 = cosy*sinx; result.m10= cosy*cosx; return result; } -// Get zyx-rotation matrix -// NOTE: Angle must be provided in radians -RMAPI Matrix MatrixRotateZYX(Vector3 angle) +// Returns zyx-rotation matrix (angles in radians) +RMDEF Matrix MatrixRotateZYX(Vector3 ang) { Matrix result = { 0 }; - float cz = cosf(angle.z); - float sz = sinf(angle.z); - float cy = cosf(angle.y); - float sy = sinf(angle.y); - float cx = cosf(angle.x); - float sx = sinf(angle.x); + float cz = cosf(ang.z); + float sz = sinf(ang.z); + float cy = cosf(ang.y); + float sy = sinf(ang.y); + float cx = cosf(ang.x); + float sx = sinf(ang.x); result.m0 = cz*cy; - result.m4 = cz*sy*sx - cx*sz; - result.m8 = sz*sx + cz*cx*sy; - result.m12 = 0; - - result.m1 = cy*sz; - result.m5 = cz*cx + sz*sy*sx; - result.m9 = cx*sz*sy - cz*sx; - result.m13 = 0; - - result.m2 = -sy; - result.m6 = cy*sx; - result.m10 = cy*cx; - result.m14 = 0; - + result.m1 = cz*sy*sx - cx*sz; + result.m2 = sz*sx + cz*cx*sy; result.m3 = 0; + + result.m4 = cy*sz; + result.m5 = cz*cx + sz*sy*sx; + result.m6 = cx*sz*sy - cz*sx; result.m7 = 0; + + result.m8 = -sy; + result.m9 = cy*sx; + result.m10 = cy*cx; result.m11 = 0; + + result.m12 = 0; + result.m13 = 0; + result.m14 = 0; result.m15 = 1; return result; } -// Get scaling matrix -RMAPI Matrix MatrixScale(float x, float y, float z) +// Returns scaling matrix +RMDEF Matrix MatrixScale(float x, float y, float z) { Matrix result = { x, 0.0f, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, @@ -1863,73 +1015,57 @@ RMAPI Matrix MatrixScale(float x, float y, float z) return result; } -// Get perspective projection matrix -RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double nearPlane, double farPlane) +// Returns perspective projection matrix +RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far) { Matrix result = { 0 }; float rl = (float)(right - left); float tb = (float)(top - bottom); - float fn = (float)(farPlane - nearPlane); + float fn = (float)(far - near); - result.m0 = ((float)nearPlane*2.0f)/rl; + result.m0 = ((float) near*2.0f)/rl; result.m1 = 0.0f; result.m2 = 0.0f; result.m3 = 0.0f; result.m4 = 0.0f; - result.m5 = ((float)nearPlane*2.0f)/tb; + result.m5 = ((float) near*2.0f)/tb; result.m6 = 0.0f; result.m7 = 0.0f; result.m8 = ((float)right + (float)left)/rl; result.m9 = ((float)top + (float)bottom)/tb; - result.m10 = -((float)farPlane + (float)nearPlane)/fn; + result.m10 = -((float)far + (float)near)/fn; result.m11 = -1.0f; result.m12 = 0.0f; result.m13 = 0.0f; - result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; + result.m14 = -((float)far*(float)near*2.0f)/fn; result.m15 = 0.0f; return result; } -// Get perspective projection matrix -// NOTE: Fovy angle must be provided in radians -RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane) +// Returns perspective projection matrix +// NOTE: Angle should be provided in radians +RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far) { - Matrix result = { 0 }; - - double top = nearPlane*tan(fovY*0.5); - double bottom = -top; + double top = near*tan(fovy*0.5); double right = top*aspect; - double left = -right; - - // MatrixFrustum(-right, right, -top, top, near, far); - float rl = (float)(right - left); - float tb = (float)(top - bottom); - float fn = (float)(farPlane - nearPlane); - - result.m0 = ((float)nearPlane*2.0f)/rl; - result.m5 = ((float)nearPlane*2.0f)/tb; - result.m8 = ((float)right + (float)left)/rl; - result.m9 = ((float)top + (float)bottom)/tb; - result.m10 = -((float)farPlane + (float)nearPlane)/fn; - result.m11 = -1.0f; - result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; + Matrix result = MatrixFrustum(-right, right, -top, top, near, far); return result; } -// Get orthographic projection matrix -RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane) +// Returns orthographic projection matrix +RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far) { Matrix result = { 0 }; float rl = (float)(right - left); float tb = (float)(top - bottom); - float fn = (float)(farPlane - nearPlane); + float fn = (float)(far - near); result.m0 = 2.0f/rl; result.m1 = 0.0f; @@ -1945,90 +1081,66 @@ RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, d result.m11 = 0.0f; result.m12 = -((float)left + (float)right)/rl; result.m13 = -((float)top + (float)bottom)/tb; - result.m14 = -((float)farPlane + (float)nearPlane)/fn; + result.m14 = -((float)far + (float)near)/fn; result.m15 = 1.0f; return result; } -// Get camera look-at matrix (view matrix) -RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) +// Returns camera look-at matrix (view matrix) +RMDEF Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) { Matrix result = { 0 }; - float length = 0.0f; - float ilength = 0.0f; + Vector3 z = Vector3Subtract(eye, target); + z = Vector3Normalize(z); + Vector3 x = Vector3CrossProduct(up, z); + x = Vector3Normalize(x); + Vector3 y = Vector3CrossProduct(z, x); - // Vector3Subtract(eye, target) - Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z }; - - // Vector3Normalize(vz) - Vector3 v = vz; - length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); - if (length == 0.0f) length = 1.0f; - ilength = 1.0f/length; - vz.x *= ilength; - vz.y *= ilength; - vz.z *= ilength; - - // Vector3CrossProduct(up, vz) - Vector3 vx = { up.y*vz.z - up.z*vz.y, up.z*vz.x - up.x*vz.z, up.x*vz.y - up.y*vz.x }; - - // Vector3Normalize(x) - v = vx; - length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); - if (length == 0.0f) length = 1.0f; - ilength = 1.0f/length; - vx.x *= ilength; - vx.y *= ilength; - vx.z *= ilength; - - // Vector3CrossProduct(vz, vx) - Vector3 vy = { vz.y*vx.z - vz.z*vx.y, vz.z*vx.x - vz.x*vx.z, vz.x*vx.y - vz.y*vx.x }; - - result.m0 = vx.x; - result.m1 = vy.x; - result.m2 = vz.x; + result.m0 = x.x; + result.m1 = y.x; + result.m2 = z.x; result.m3 = 0.0f; - result.m4 = vx.y; - result.m5 = vy.y; - result.m6 = vz.y; + result.m4 = x.y; + result.m5 = y.y; + result.m6 = z.y; result.m7 = 0.0f; - result.m8 = vx.z; - result.m9 = vy.z; - result.m10 = vz.z; + result.m8 = x.z; + result.m9 = y.z; + result.m10 = z.z; result.m11 = 0.0f; - result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z); // Vector3DotProduct(vx, eye) - result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z); // Vector3DotProduct(vy, eye) - result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z); // Vector3DotProduct(vz, eye) + result.m12 = -Vector3DotProduct(x, eye); + result.m13 = -Vector3DotProduct(y, eye); + result.m14 = -Vector3DotProduct(z, eye); result.m15 = 1.0f; return result; } -// Get float array of matrix data -RMAPI float16 MatrixToFloatV(Matrix mat) +// Returns float array of matrix data +RMDEF float16 MatrixToFloatV(Matrix mat) { - float16 result = { 0 }; + float16 buffer = { 0 }; - result.v[0] = mat.m0; - result.v[1] = mat.m1; - result.v[2] = mat.m2; - result.v[3] = mat.m3; - result.v[4] = mat.m4; - result.v[5] = mat.m5; - result.v[6] = mat.m6; - result.v[7] = mat.m7; - result.v[8] = mat.m8; - result.v[9] = mat.m9; - result.v[10] = mat.m10; - result.v[11] = mat.m11; - result.v[12] = mat.m12; - result.v[13] = mat.m13; - result.v[14] = mat.m14; - result.v[15] = mat.m15; + buffer.v[0] = mat.m0; + buffer.v[1] = mat.m1; + buffer.v[2] = mat.m2; + buffer.v[3] = mat.m3; + buffer.v[4] = mat.m4; + buffer.v[5] = mat.m5; + buffer.v[6] = mat.m6; + buffer.v[7] = mat.m7; + buffer.v[8] = mat.m8; + buffer.v[9] = mat.m9; + buffer.v[10] = mat.m10; + buffer.v[11] = mat.m11; + buffer.v[12] = mat.m12; + buffer.v[13] = mat.m13; + buffer.v[14] = mat.m14; + buffer.v[15] = mat.m15; - return result; + return buffer; } //---------------------------------------------------------------------------------- @@ -2036,61 +1148,56 @@ RMAPI float16 MatrixToFloatV(Matrix mat) //---------------------------------------------------------------------------------- // Add two quaternions -RMAPI Quaternion QuaternionAdd(Quaternion q1, Quaternion q2) +RMDEF Quaternion QuaternionAdd(Quaternion q1, Quaternion q2) { Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w}; - return result; } // Add quaternion and float value -RMAPI Quaternion QuaternionAddValue(Quaternion q, float add) +RMDEF Quaternion QuaternionAddValue(Quaternion q, float add) { Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add}; - return result; } // Subtract two quaternions -RMAPI Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2) +RMDEF Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2) { Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w}; - return result; } // Subtract quaternion and float value -RMAPI Quaternion QuaternionSubtractValue(Quaternion q, float sub) +RMDEF Quaternion QuaternionSubtractValue(Quaternion q, float sub) { Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub}; - return result; } -// Get identity quaternion -RMAPI Quaternion QuaternionIdentity(void) +// Returns identity quaternion +RMDEF Quaternion QuaternionIdentity(void) { Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; - return result; } // Computes the length of a quaternion -RMAPI float QuaternionLength(Quaternion q) +RMDEF float QuaternionLength(Quaternion q) { float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - return result; } // Normalize provided quaternion -RMAPI Quaternion QuaternionNormalize(Quaternion q) +RMDEF Quaternion QuaternionNormalize(Quaternion q) { Quaternion result = { 0 }; - float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + float length, ilength; + length = QuaternionLength(q); if (length == 0.0f) length = 1.0f; - float ilength = 1.0f/length; + ilength = 1.0f/length; result.x = q.x*ilength; result.y = q.y*ilength; @@ -2101,27 +1208,27 @@ RMAPI Quaternion QuaternionNormalize(Quaternion q) } // Invert provided quaternion -RMAPI Quaternion QuaternionInvert(Quaternion q) +RMDEF Quaternion QuaternionInvert(Quaternion q) { Quaternion result = q; + float length = QuaternionLength(q); + float lengthSq = length*length; - float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; - - if (lengthSq != 0.0f) + if (lengthSq != 0.0) { - float invLength = 1.0f/lengthSq; + float i = 1.0f/lengthSq; - result.x *= -invLength; - result.y *= -invLength; - result.z *= -invLength; - result.w *= invLength; + result.x *= -i; + result.y *= -i; + result.z *= -i; + result.w *= i; } return result; } // Calculate two quaternion multiplication -RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) +RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) { Quaternion result = { 0 }; @@ -2137,28 +1244,29 @@ RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) } // Scale quaternion by float value -RMAPI Quaternion QuaternionScale(Quaternion q, float mul) +RMDEF Quaternion QuaternionScale(Quaternion q, float mul) { Quaternion result = { 0 }; - result.x = q.x*mul; - result.y = q.y*mul; - result.z = q.z*mul; - result.w = q.w*mul; + float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w; + + result.x = qax*mul + qaw*mul + qay*mul - qaz*mul; + result.y = qay*mul + qaw*mul + qaz*mul - qax*mul; + result.z = qaz*mul + qaw*mul + qax*mul - qay*mul; + result.w = qaw*mul - qax*mul - qay*mul - qaz*mul; return result; } // Divide two quaternions -RMAPI Quaternion QuaternionDivide(Quaternion q1, Quaternion q2) +RMDEF Quaternion QuaternionDivide(Quaternion q1, Quaternion q2) { Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w }; - return result; } // Calculate linear interpolation between two quaternions -RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) +RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) { Quaternion result = { 0 }; @@ -2171,40 +1279,20 @@ RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) } // Calculate slerp-optimized interpolation between two quaternions -RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) +RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) { - Quaternion result = { 0 }; - - // QuaternionLerp(q1, q2, amount) - result.x = q1.x + amount*(q2.x - q1.x); - result.y = q1.y + amount*(q2.y - q1.y); - result.z = q1.z + amount*(q2.z - q1.z); - result.w = q1.w + amount*(q2.w - q1.w); - - // QuaternionNormalize(q); - Quaternion q = result; - float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - if (length == 0.0f) length = 1.0f; - float ilength = 1.0f/length; - - result.x = q.x*ilength; - result.y = q.y*ilength; - result.z = q.z*ilength; - result.w = q.w*ilength; + Quaternion result = QuaternionLerp(q1, q2, amount); + result = QuaternionNormalize(result); return result; } // Calculates spherical linear interpolation between two quaternions -RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) +RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) { Quaternion result = { 0 }; -#if !defined(EPSILON) - #define EPSILON 0.000001f -#endif - - float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; + float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; if (cosHalfTheta < 0) { @@ -2212,14 +1300,14 @@ RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) cosHalfTheta = -cosHalfTheta; } - if (fabsf(cosHalfTheta) >= 1.0f) result = q1; + if (fabs(cosHalfTheta) >= 1.0f) result = q1; else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount); else { float halfTheta = acosf(cosHalfTheta); float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta); - if (fabsf(sinHalfTheta) < EPSILON) + if (fabs(sinHalfTheta) < 0.001f) { result.x = (q1.x*0.5f + q2.x*0.5f); result.y = (q1.y*0.5f + q2.y*0.5f); @@ -2241,223 +1329,122 @@ RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) return result; } -// Calculate quaternion cubic spline interpolation using Cubic Hermite Spline algorithm -// as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic -RMAPI Quaternion QuaternionCubicHermiteSpline(Quaternion q1, Quaternion outTangent1, Quaternion q2, Quaternion inTangent2, float t) +// Calculate quaternion based on the rotation from one vector to another +RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) { - float t2 = t*t; - float t3 = t2*t; - float h00 = 2*t3 - 3*t2 + 1; - float h10 = t3 - 2*t2 + t; - float h01 = -2*t3 + 3*t2; - float h11 = t3 - t2; - - Quaternion p0 = QuaternionScale(q1, h00); - Quaternion m0 = QuaternionScale(outTangent1, h10); - Quaternion p1 = QuaternionScale(q2, h01); - Quaternion m1 = QuaternionScale(inTangent2, h11); - Quaternion result = { 0 }; - result = QuaternionAdd(p0, m0); - result = QuaternionAdd(result, p1); - result = QuaternionAdd(result, m1); + float cos2Theta = Vector3DotProduct(from, to); + Vector3 cross = Vector3CrossProduct(from, to); + + result.x = cross.x; + result.y = cross.y; + result.z = cross.z; + result.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity() + + // Normalize to essentially nlerp the original and identity to 0.5 + result = QuaternionNormalize(result); + + // Above lines are equivalent to: + //Quaternion result = QuaternionNlerp(q, QuaternionIdentity(), 0.5f); + + return result; +} + +// Returns a quaternion for a given rotation matrix +RMDEF Quaternion QuaternionFromMatrix(Matrix mat) +{ + Quaternion result = { 0 }; + + if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10)) + { + float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2; + + result.x = 0.25f*s; + result.y = (mat.m4 + mat.m1)/s; + result.z = (mat.m2 + mat.m8)/s; + result.w = (mat.m9 - mat.m6)/s; + } + else if (mat.m5 > mat.m10) + { + float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2; + result.x = (mat.m4 + mat.m1)/s; + result.y = 0.25f*s; + result.z = (mat.m9 + mat.m6)/s; + result.w = (mat.m2 - mat.m8)/s; + } + else + { + float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2; + result.x = (mat.m2 + mat.m8)/s; + result.y = (mat.m9 + mat.m6)/s; + result.z = 0.25f*s; + result.w = (mat.m4 - mat.m1)/s; + } + + return result; +} + +// Returns a matrix for a given quaternion +RMDEF Matrix QuaternionToMatrix(Quaternion q) +{ + Matrix result = MatrixIdentity(); + + float a2 = 2*(q.x*q.x), b2=2*(q.y*q.y), c2=2*(q.z*q.z); //, d2=2*(q.w*q.w); + + float ab = 2*(q.x*q.y), ac=2*(q.x*q.z), bc=2*(q.y*q.z); + float ad = 2*(q.x*q.w), bd=2*(q.y*q.w), cd=2*(q.z*q.w); + + result.m0 = 1 - b2 - c2; + result.m1 = ab - cd; + result.m2 = ac + bd; + + result.m4 = ab + cd; + result.m5 = 1 - a2 - c2; + result.m6 = bc - ad; + + result.m8 = ac - bd; + result.m9 = bc + ad; + result.m10 = 1 - a2 - b2; + + return result; +} + +// Returns rotation quaternion for an angle and axis +// NOTE: angle must be provided in radians +RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle) +{ + Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; + + if (Vector3Length(axis) != 0.0f) + + angle *= 0.5f; + + axis = Vector3Normalize(axis); + + float sinres = sinf(angle); + float cosres = cosf(angle); + + result.x = axis.x*sinres; + result.y = axis.y*sinres; + result.z = axis.z*sinres; + result.w = cosres; + result = QuaternionNormalize(result); return result; } -// Calculate quaternion based on the rotation from one vector to another -RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) +// Returns the rotation angle and axis for a given quaternion +RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) { - Quaternion result = { 0 }; - - float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) - Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to) - - result.x = cross.x; - result.y = cross.y; - result.z = cross.z; - result.w = 1.0f + cos2Theta; - - // QuaternionNormalize(q); - // NOTE: Normalize to essentially nlerp the original and identity to 0.5 - Quaternion q = result; - float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - if (length == 0.0f) length = 1.0f; - float ilength = 1.0f/length; - - result.x = q.x*ilength; - result.y = q.y*ilength; - result.z = q.z*ilength; - result.w = q.w*ilength; - - return result; -} - -// Get a quaternion for a given rotation matrix -RMAPI Quaternion QuaternionFromMatrix(Matrix mat) -{ - Quaternion result = { 0 }; - - float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10; - float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10; - float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10; - float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5; - - int biggestIndex = 0; - float fourBiggestSquaredMinus1 = fourWSquaredMinus1; - if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) - { - fourBiggestSquaredMinus1 = fourXSquaredMinus1; - biggestIndex = 1; - } - - if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) - { - fourBiggestSquaredMinus1 = fourYSquaredMinus1; - biggestIndex = 2; - } - - if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) - { - fourBiggestSquaredMinus1 = fourZSquaredMinus1; - biggestIndex = 3; - } - - float biggestVal = sqrtf(fourBiggestSquaredMinus1 + 1.0f)*0.5f; - float mult = 0.25f/biggestVal; - - switch (biggestIndex) - { - case 0: - result.w = biggestVal; - result.x = (mat.m6 - mat.m9)*mult; - result.y = (mat.m8 - mat.m2)*mult; - result.z = (mat.m1 - mat.m4)*mult; - break; - case 1: - result.x = biggestVal; - result.w = (mat.m6 - mat.m9)*mult; - result.y = (mat.m1 + mat.m4)*mult; - result.z = (mat.m8 + mat.m2)*mult; - break; - case 2: - result.y = biggestVal; - result.w = (mat.m8 - mat.m2)*mult; - result.x = (mat.m1 + mat.m4)*mult; - result.z = (mat.m6 + mat.m9)*mult; - break; - case 3: - result.z = biggestVal; - result.w = (mat.m1 - mat.m4)*mult; - result.x = (mat.m8 + mat.m2)*mult; - result.y = (mat.m6 + mat.m9)*mult; - break; - } - - return result; -} - -// Get a matrix for a given quaternion -RMAPI Matrix QuaternionToMatrix(Quaternion q) -{ - Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() - - float a2 = q.x*q.x; - float b2 = q.y*q.y; - float c2 = q.z*q.z; - float ac = q.x*q.z; - float ab = q.x*q.y; - float bc = q.y*q.z; - float ad = q.w*q.x; - float bd = q.w*q.y; - float cd = q.w*q.z; - - result.m0 = 1 - 2*(b2 + c2); - result.m1 = 2*(ab + cd); - result.m2 = 2*(ac - bd); - - result.m4 = 2*(ab - cd); - result.m5 = 1 - 2*(a2 + c2); - result.m6 = 2*(bc + ad); - - result.m8 = 2*(ac + bd); - result.m9 = 2*(bc - ad); - result.m10 = 1 - 2*(a2 + b2); - - return result; -} - -// Get rotation quaternion for an angle and axis -// NOTE: Angle must be provided in radians -RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle) -{ - Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; - - float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); - - if (axisLength != 0.0f) - { - angle *= 0.5f; - - float length = 0.0f; - float ilength = 0.0f; - - // Vector3Normalize(axis) - length = axisLength; - if (length == 0.0f) length = 1.0f; - ilength = 1.0f/length; - axis.x *= ilength; - axis.y *= ilength; - axis.z *= ilength; - - float sinres = sinf(angle); - float cosres = cosf(angle); - - result.x = axis.x*sinres; - result.y = axis.y*sinres; - result.z = axis.z*sinres; - result.w = cosres; - - // QuaternionNormalize(q); - Quaternion q = result; - length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - if (length == 0.0f) length = 1.0f; - ilength = 1.0f/length; - result.x = q.x*ilength; - result.y = q.y*ilength; - result.z = q.z*ilength; - result.w = q.w*ilength; - } - - return result; -} - -// Get the rotation angle and axis for a given quaternion -RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) -{ - if (fabsf(q.w) > 1.0f) - { - // QuaternionNormalize(q); - float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - if (length == 0.0f) length = 1.0f; - float ilength = 1.0f/length; - - q.x = q.x*ilength; - q.y = q.y*ilength; - q.z = q.z*ilength; - q.w = q.w*ilength; - } + if (fabs(q.w) > 1.0f) q = QuaternionNormalize(q); Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; float resAngle = 2.0f*acosf(q.w); float den = sqrtf(1.0f - q.w*q.w); - if (den > EPSILON) + if (den > 0.0001f) { resAxis.x = q.x/den; resAxis.y = q.y/den; @@ -2474,11 +1461,11 @@ RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle *outAngle = resAngle; } -// Get the quaternion equivalent to Euler angles +// Returns the quaternion equivalent to Euler angles // NOTE: Rotation order is ZYX -RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) +RMDEF Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) { - Quaternion result = { 0 }; + Quaternion q = { 0 }; float x0 = cosf(pitch*0.5f); float x1 = sinf(pitch*0.5f); @@ -2487,41 +1474,41 @@ RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) float z0 = cosf(roll*0.5f); float z1 = sinf(roll*0.5f); - result.x = x1*y0*z0 - x0*y1*z1; - result.y = x0*y1*z0 + x1*y0*z1; - result.z = x0*y0*z1 - x1*y1*z0; - result.w = x0*y0*z0 + x1*y1*z1; + q.x = x1*y0*z0 - x0*y1*z1; + q.y = x0*y1*z0 + x1*y0*z1; + q.z = x0*y0*z1 - x1*y1*z0; + q.w = x0*y0*z0 + x1*y1*z1; - return result; + return q; } -// Get the Euler angles equivalent to quaternion (roll, pitch, yaw) -// NOTE: Angles are returned in a Vector3 struct in radians -RMAPI Vector3 QuaternionToEuler(Quaternion q) +// Return the Euler angles equivalent to quaternion (roll, pitch, yaw) +// NOTE: Angles are returned in a Vector3 struct in degrees +RMDEF Vector3 QuaternionToEuler(Quaternion q) { Vector3 result = { 0 }; - // Roll (x-axis rotation) + // roll (x-axis rotation) float x0 = 2.0f*(q.w*q.x + q.y*q.z); float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y); - result.x = atan2f(x0, x1); + result.x = atan2f(x0, x1)*RAD2DEG; - // Pitch (y-axis rotation) + // pitch (y-axis rotation) float y0 = 2.0f*(q.w*q.y - q.z*q.x); y0 = y0 > 1.0f ? 1.0f : y0; y0 = y0 < -1.0f ? -1.0f : y0; - result.y = asinf(y0); + result.y = asinf(y0)*RAD2DEG; - // Yaw (z-axis rotation) + // yaw (z-axis rotation) float z0 = 2.0f*(q.w*q.z + q.x*q.y); float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z); - result.z = atan2f(z0, z1); + result.z = atan2f(z0, z1)*RAD2DEG; return result; } // Transform a quaternion given a transformation matrix -RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat) +RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat) { Quaternion result = { 0 }; @@ -2533,434 +1520,27 @@ RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat) return result; } -// Check whether two given quaternions are almost equal -RMAPI int QuaternionEquals(Quaternion p, Quaternion q) +// Projects a Vector3 from screen space into object space +RMDEF Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) { -#if !defined(EPSILON) - #define EPSILON 0.000001f -#endif + Vector3 result = { 0.0f, 0.0f, 0.0f }; - int result = (((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && - ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && - ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && - ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))) || - (((fabsf(p.x + q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && - ((fabsf(p.y + q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && - ((fabsf(p.z + q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && - ((fabsf(p.w + q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))); + // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it + Matrix matViewProj = MatrixMultiply(view, projection); + matViewProj = MatrixInvert(matViewProj); + + // Create quaternion from source point + Quaternion quat = { source.x, source.y, source.z, 1.0f }; + + // Multiply quat point by unproject matrix + quat = QuaternionTransform(quat, matViewProj); + + // Normalized world points in vectors + result.x = quat.x/quat.w; + result.y = quat.y/quat.w; + result.z = quat.z/quat.w; return result; } -// Decompose a transformation matrix into its rotational, translational and scaling components -RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) -{ - // Extract translation. - translation->x = mat.m12; - translation->y = mat.m13; - translation->z = mat.m14; - - // Extract upper-left for determinant computation - const float a = mat.m0; - const float b = mat.m4; - const float c = mat.m8; - const float d = mat.m1; - const float e = mat.m5; - const float f = mat.m9; - const float g = mat.m2; - const float h = mat.m6; - const float i = mat.m10; - const float A = e*i - f*h; - const float B = f*g - d*i; - const float C = d*h - e*g; - - // Extract scale - const float det = a*A + b*B + c*C; - Vector3 abc = { a, b, c }; - Vector3 def = { d, e, f }; - Vector3 ghi = { g, h, i }; - - float scalex = Vector3Length(abc); - float scaley = Vector3Length(def); - float scalez = Vector3Length(ghi); - Vector3 s = { scalex, scaley, scalez }; - - if (det < 0) s = Vector3Negate(s); - - *scale = s; - - // Remove scale from the matrix if it is not close to zero - Matrix clone = mat; - if (!FloatEquals(det, 0)) - { - clone.m0 /= s.x; - clone.m4 /= s.x; - clone.m8 /= s.x; - clone.m1 /= s.y; - clone.m5 /= s.y; - clone.m9 /= s.y; - clone.m2 /= s.z; - clone.m6 /= s.z; - clone.m10 /= s.z; - - // Extract rotation - *rotation = QuaternionFromMatrix(clone); - } - else - { - // Set to identity if close to zero - *rotation = QuaternionIdentity(); - } -} - -#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS) - -// Optional C++ math operators -//------------------------------------------------------------------------------- - -// Vector2 operators -static constexpr Vector2 Vector2Zeros = { 0, 0 }; -static constexpr Vector2 Vector2Ones = { 1, 1 }; -static constexpr Vector2 Vector2UnitX = { 1, 0 }; -static constexpr Vector2 Vector2UnitY = { 0, 1 }; - -inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs) -{ - return Vector2Add(lhs, rhs); -} - -inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs) -{ - lhs = Vector2Add(lhs, rhs); - return lhs; -} - -inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs) -{ - return Vector2Subtract(lhs, rhs); -} - -inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs) -{ - lhs = Vector2Subtract(lhs, rhs); - return lhs; -} - -inline Vector2 operator * (const Vector2& lhs, const float& rhs) -{ - return Vector2Scale(lhs, rhs); -} - -inline const Vector2& operator *= (Vector2& lhs, const float& rhs) -{ - lhs = Vector2Scale(lhs, rhs); - return lhs; -} - -inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs) -{ - return Vector2Multiply(lhs, rhs); -} - -inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs) -{ - lhs = Vector2Multiply(lhs, rhs); - return lhs; -} - -inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs) -{ - return Vector2Transform(lhs, rhs); -} - -inline const Vector2& operator *= (Vector2& lhs, const Matrix& rhs) -{ - lhs = Vector2Transform(lhs, rhs); - return lhs; -} - -inline Vector2 operator / (const Vector2& lhs, const float& rhs) -{ - return Vector2Scale(lhs, 1.0f/rhs); -} - -inline const Vector2& operator /= (Vector2& lhs, const float& rhs) -{ - lhs = Vector2Scale(lhs, 1.0f/rhs); - return lhs; -} - -inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs) -{ - return Vector2Divide(lhs, rhs); -} - -inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs) -{ - lhs = Vector2Divide(lhs, rhs); - return lhs; -} - -inline bool operator == (const Vector2& lhs, const Vector2& rhs) -{ - return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y); -} - -inline bool operator != (const Vector2& lhs, const Vector2& rhs) -{ - return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y); -} - -// Vector3 operators -static constexpr Vector3 Vector3Zeros = { 0, 0, 0 }; -static constexpr Vector3 Vector3Ones = { 1, 1, 1 }; -static constexpr Vector3 Vector3UnitX = { 1, 0, 0 }; -static constexpr Vector3 Vector3UnitY = { 0, 1, 0 }; -static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 }; - -inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs) -{ - return Vector3Add(lhs, rhs); -} - -inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs) -{ - lhs = Vector3Add(lhs, rhs); - return lhs; -} - -inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs) -{ - return Vector3Subtract(lhs, rhs); -} - -inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs) -{ - lhs = Vector3Subtract(lhs, rhs); - return lhs; -} - -inline Vector3 operator * (const Vector3& lhs, const float& rhs) -{ - return Vector3Scale(lhs, rhs); -} - -inline const Vector3& operator *= (Vector3& lhs, const float& rhs) -{ - lhs = Vector3Scale(lhs, rhs); - return lhs; -} - -inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs) -{ - return Vector3Multiply(lhs, rhs); -} - -inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs) -{ - lhs = Vector3Multiply(lhs, rhs); - return lhs; -} - -inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs) -{ - return Vector3Transform(lhs, rhs); -} - -inline const Vector3& operator *= (Vector3& lhs, const Matrix& rhs) -{ - lhs = Vector3Transform(lhs, rhs); - return lhs; -} - -inline Vector3 operator / (const Vector3& lhs, const float& rhs) -{ - return Vector3Scale(lhs, 1.0f/rhs); -} - -inline const Vector3& operator /= (Vector3& lhs, const float& rhs) -{ - lhs = Vector3Scale(lhs, 1.0f/rhs); - return lhs; -} - -inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs) -{ - return Vector3Divide(lhs, rhs); -} - -inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs) -{ - lhs = Vector3Divide(lhs, rhs); - return lhs; -} - -inline bool operator == (const Vector3& lhs, const Vector3& rhs) -{ - return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z); -} - -inline bool operator != (const Vector3& lhs, const Vector3& rhs) -{ - return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z); -} - -// Vector4 operators -static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 }; -static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 }; -static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 }; -static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 }; -static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 }; -static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 }; - -inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs) -{ - return Vector4Add(lhs, rhs); -} - -inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs) -{ - lhs = Vector4Add(lhs, rhs); - return lhs; -} - -inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs) -{ - return Vector4Subtract(lhs, rhs); -} - -inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs) -{ - lhs = Vector4Subtract(lhs, rhs); - return lhs; -} - -inline Vector4 operator * (const Vector4& lhs, const float& rhs) -{ - return Vector4Scale(lhs, rhs); -} - -inline const Vector4& operator *= (Vector4& lhs, const float& rhs) -{ - lhs = Vector4Scale(lhs, rhs); - return lhs; -} - -inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs) -{ - return Vector4Multiply(lhs, rhs); -} - -inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs) -{ - lhs = Vector4Multiply(lhs, rhs); - return lhs; -} - -inline Vector4 operator / (const Vector4& lhs, const float& rhs) -{ - return Vector4Scale(lhs, 1.0f/rhs); -} - -inline const Vector4& operator /= (Vector4& lhs, const float& rhs) -{ - lhs = Vector4Scale(lhs, 1.0f/rhs); - return lhs; -} - -inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs) -{ - return Vector4Divide(lhs, rhs); -} - -inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs) -{ - lhs = Vector4Divide(lhs, rhs); - return lhs; -} - -inline bool operator == (const Vector4& lhs, const Vector4& rhs) -{ - return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w); -} - -inline bool operator != (const Vector4& lhs, const Vector4& rhs) -{ - return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w); -} - -// Quaternion operators -static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 }; -static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 }; -static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 }; - -inline Quaternion operator + (const Quaternion& lhs, const float& rhs) -{ - return QuaternionAddValue(lhs, rhs); -} - -inline const Quaternion& operator += (Quaternion& lhs, const float& rhs) -{ - lhs = QuaternionAddValue(lhs, rhs); - return lhs; -} - -inline Quaternion operator - (const Quaternion& lhs, const float& rhs) -{ - return QuaternionSubtractValue(lhs, rhs); -} - -inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs) -{ - lhs = QuaternionSubtractValue(lhs, rhs); - return lhs; -} - -inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs) -{ - return QuaternionTransform(lhs, rhs); -} - -inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) -{ - lhs = QuaternionTransform(lhs, rhs); - return lhs; -} - -// Matrix operators -inline Matrix operator + (const Matrix& lhs, const Matrix& rhs) -{ - return MatrixAdd(lhs, rhs); -} - -inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs) -{ - lhs = MatrixAdd(lhs, rhs); - return lhs; -} - -inline Matrix operator - (const Matrix& lhs, const Matrix& rhs) -{ - return MatrixSubtract(lhs, rhs); -} - -inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs) -{ - lhs = MatrixSubtract(lhs, rhs); - return lhs; -} - -inline Matrix operator * (const Matrix& lhs, const Matrix& rhs) -{ - return MatrixMultiply(lhs, rhs); -} - -inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs) -{ - lhs = MatrixMultiply(lhs, rhs); - return lhs; -} -//------------------------------------------------------------------------------- -#endif // C++ operators - #endif // RAYMATH_H diff --git a/raylib/rcamera.go b/raylib/rcamera.go deleted file mode 100644 index d0df645..0000000 --- a/raylib/rcamera.go +++ /dev/null @@ -1,350 +0,0 @@ -package rl - -// GetCameraForward - Returns the cameras forward vector (normalized) -func GetCameraForward(camera *Camera) Vector3 { - return Vector3Normalize(Vector3Subtract(camera.Target, camera.Position)) -} - -// GetCameraUp - Returns the cameras up vector (normalized) -// Note: The up vector might not be perpendicular to the forward vector -func GetCameraUp(camera *Camera) Vector3 { - return Vector3Normalize(camera.Up) -} - -// GetCameraRight - Returns the cameras right vector (normalized) -func GetCameraRight(camera *Camera) Vector3 { - forward := GetCameraForward(camera) - up := GetCameraUp(camera) - - return Vector3CrossProduct(forward, up) -} - -// CameraMoveForward - Moves the camera in its forward direction -func CameraMoveForward(camera *Camera, distance float32, moveInWorldPlane uint8) { - forward := GetCameraForward(camera) - - if moveInWorldPlane != 0 { - // Project vector onto world plane - forward.Y = float32(0) - forward = Vector3Normalize(forward) - } - - // Scale by distance - forward = Vector3Scale(forward, distance) - - // Move position and target - camera.Position = Vector3Add(camera.Position, forward) - camera.Target = Vector3Add(camera.Target, forward) -} - -// CameraMoveUp - Moves the camera in its up direction -func CameraMoveUp(camera *Camera, distance float32) { - up := GetCameraUp(camera) - - // Scale by distance - up = Vector3Scale(up, distance) - - // Move position and target - camera.Position = Vector3Add(camera.Position, up) - camera.Target = Vector3Add(camera.Target, up) -} - -// CameraMoveRight - Moves the camera target in its current right direction -func CameraMoveRight(camera *Camera, distance float32, moveInWorldPlane uint8) { - right := GetCameraRight(camera) - - if moveInWorldPlane != 0 { - // Project vector onto world plane - right.Y = float32(0) - right = Vector3Normalize(right) - } - - // Scale by distance - right = Vector3Scale(right, distance) - - // Move position and target - camera.Position = Vector3Add(camera.Position, right) - camera.Target = Vector3Add(camera.Target, right) -} - -// CameraMoveToTarget - Moves the camera position closer/farther to/from the camera target -func CameraMoveToTarget(camera *Camera, delta float32) { - distance := Vector3Distance(camera.Position, camera.Target) - - // Apply delta - distance = distance + delta - - // Distance must be greater than 0 - if distance <= float32(0) { - distance = 0.001 - } - - // Set new distance by moving the position along the forward vector - forward := GetCameraForward(camera) - camera.Position = Vector3Add(camera.Target, Vector3Scale(forward, -distance)) -} - -// CameraYaw - Rotates the camera around its up vector -// Yaw is "looking left and right" -// If rotateAroundTarget is false, the camera rotates around its position -// Note: angle must be provided in radians -func CameraYaw(camera *Camera, angle float32, rotateAroundTarget uint8) { - // Rotation axis - var up = GetCameraUp(camera) - - // View vector - var targetPosition = Vector3Subtract(camera.Target, camera.Position) - - // Rotate view vector around up axis - targetPosition = Vector3RotateByAxisAngle(targetPosition, up, angle) - - if rotateAroundTarget != 0 { - // Move position relative to target - camera.Position = Vector3Subtract(camera.Target, targetPosition) - } else { - // Move target relative to position - camera.Target = Vector3Add(camera.Position, targetPosition) - } -} - -// CameraPitch - Rotates the camera around its right vector, pitch is "looking up and down" -// - lockView prevents camera overrotation (aka "somersaults") -// - rotateAroundTarget defines if rotation is around target or around its position -// - rotateUp rotates the up direction as well (typically only useful in CAMERA_FREE) -// -// NOTE: angle must be provided in radians -func CameraPitch(camera *Camera, angle float32, lockView uint8, rotateAroundTarget uint8, rotateUp uint8) { - // Up direction - var up = GetCameraUp(camera) - - // View vector - var targetPosition = Vector3Subtract(camera.Target, camera.Position) - - if lockView != 0 { - // In these camera modes we clamp the Pitch angle - // to allow only viewing straight up or down. - - // Clamp view up - maxAngleUp := Vector3Angle(up, targetPosition) - maxAngleUp = maxAngleUp - 0.001 // avoid numerical errors - if angle > maxAngleUp { - angle = maxAngleUp - } - - // Clamp view down - maxAngleDown := Vector3Angle(Vector3Negate(up), targetPosition) - maxAngleDown = maxAngleDown * -1.0 // downwards angle is negative - maxAngleDown = maxAngleDown + 0.001 // avoid numerical errors - if angle < maxAngleDown { - angle = maxAngleDown - } - } - - // Rotation axis - var right = GetCameraRight(camera) - - // Rotate view vector around right axis - targetPosition = Vector3RotateByAxisAngle(targetPosition, right, angle) - - if rotateAroundTarget != 0 { - // Move position relative to target - camera.Position = Vector3Subtract(camera.Target, targetPosition) - } else { - // Move target relative to position - camera.Target = Vector3Add(camera.Position, targetPosition) - } - - if rotateUp != 0 { - // Rotate up direction around right axis - camera.Up = Vector3RotateByAxisAngle(camera.Up, right, angle) - } -} - -// CameraRoll - Rotates the camera around its forward vector -// Roll is "turning your head sideways to the left or right" -// Note: angle must be provided in radians -func CameraRoll(camera *Camera, angle float32) { - // Rotation axis - var forward = GetCameraForward(camera) - - // Rotate up direction around forward axis - camera.Up = Vector3RotateByAxisAngle(camera.Up, forward, angle) -} - -// GetCameraViewMatrix - Returns the camera view matrix -func GetCameraViewMatrix(camera *Camera) Matrix { - return MatrixLookAt(camera.Position, camera.Target, camera.Up) -} - -// GetCameraProjectionMatrix - Returns the camera projection matrix -func GetCameraProjectionMatrix(camera *Camera, aspect float32) Matrix { - if camera.Projection == CameraPerspective { - return MatrixPerspective(camera.Fovy*(Pi/180.0), aspect, 0.01, 1000.0) - } else if camera.Projection == CameraOrthographic { - top := camera.Fovy / 2.0 - right := top * aspect - - return MatrixOrtho(-right, right, -top, top, 0.01, 1000.0) - } - - return MatrixIdentity() -} - -// UpdateCamera - Update camera position for selected mode -// Camera mode: CameraFree, CameraFirstPerson, CameraThirdPerson, CameraOrbital or Custom -func UpdateCamera(camera *Camera, mode CameraMode) { - var mousePositionDelta = GetMouseDelta() - - moveInWorldPlaneBool := mode == CameraFirstPerson || mode == CameraThirdPerson - var moveInWorldPlane uint8 - if moveInWorldPlaneBool { - moveInWorldPlane = 1 - } - - rotateAroundTargetBool := mode == CameraThirdPerson || mode == CameraOrbital - var rotateAroundTarget uint8 - if rotateAroundTargetBool { - rotateAroundTarget = 1 - } - - lockViewBool := mode == CameraFirstPerson || mode == CameraThirdPerson || mode == CameraOrbital - var lockView uint8 - if lockViewBool { - lockView = 1 - } - - var rotateUp uint8 - - if mode == CameraOrbital { - // Orbital can just orbit - var rotation = MatrixRotate(GetCameraUp(camera), 0.5*GetFrameTime()) - var view = Vector3Subtract(camera.Position, camera.Target) - view = Vector3Transform(view, rotation) - camera.Position = Vector3Add(camera.Target, view) - } else { - // Camera rotation - if IsKeyDown(KeyDown) { - CameraPitch(camera, -0.03, lockView, rotateAroundTarget, rotateUp) - } - if IsKeyDown(KeyUp) { - CameraPitch(camera, 0.03, lockView, rotateAroundTarget, rotateUp) - } - if IsKeyDown(KeyRight) { - CameraYaw(camera, -0.03, rotateAroundTarget) - } - if IsKeyDown(KeyLeft) { - CameraYaw(camera, 0.03, rotateAroundTarget) - } - if IsKeyDown(KeyQ) { - CameraRoll(camera, -0.03) - } - if IsKeyDown(KeyE) { - CameraRoll(camera, 0.03) - } - - // Camera movement - if !(IsGamepadAvailable(0)) { - // Camera pan (for CameraFree) - if mode == CameraFree && IsMouseButtonDown(MouseMiddleButton) { - var mouseDelta = GetMouseDelta() - if mouseDelta.X > 0.0 { - CameraMoveRight(camera, 0.2, moveInWorldPlane) - } - if mouseDelta.X < 0.0 { - CameraMoveRight(camera, -0.2, moveInWorldPlane) - } - if mouseDelta.Y > 0.0 { - CameraMoveUp(camera, -0.2) - } - if mouseDelta.Y < 0.0 { - CameraMoveUp(camera, 0.2) - } - } else { - // Mouse support - CameraYaw(camera, -mousePositionDelta.X*0.003, rotateAroundTarget) - CameraPitch(camera, -mousePositionDelta.Y*0.003, lockView, rotateAroundTarget, rotateUp) - } - - // Keyboard support - if IsKeyDown(KeyW) { - CameraMoveForward(camera, 0.09, moveInWorldPlane) - } - if IsKeyDown(KeyA) { - CameraMoveRight(camera, -0.09, moveInWorldPlane) - } - if IsKeyDown(KeyS) { - CameraMoveForward(camera, -0.09, moveInWorldPlane) - } - if IsKeyDown(KeyD) { - CameraMoveRight(camera, 0.09, moveInWorldPlane) - } - } else { - // Gamepad controller support - CameraYaw(camera, -(GetGamepadAxisMovement(0, GamepadAxisRightX)*float32(2))*0.003, rotateAroundTarget) - CameraPitch(camera, -(GetGamepadAxisMovement(0, GamepadAxisRightY)*float32(2))*0.003, lockView, rotateAroundTarget, rotateUp) - - if GetGamepadAxisMovement(0, GamepadAxisLeftY) <= -0.25 { - CameraMoveForward(camera, 0.09, moveInWorldPlane) - } - if GetGamepadAxisMovement(0, GamepadAxisLeftX) <= -0.25 { - CameraMoveRight(camera, -0.09, moveInWorldPlane) - } - if GetGamepadAxisMovement(0, GamepadAxisLeftY) >= 0.25 { - CameraMoveForward(camera, -0.09, moveInWorldPlane) - } - if GetGamepadAxisMovement(0, GamepadAxisLeftX) >= 0.25 { - CameraMoveRight(camera, 0.09, moveInWorldPlane) - } - } - - if mode == CameraFree { - if IsKeyDown(KeySpace) { - CameraMoveUp(camera, 0.09) - } - if IsKeyDown(KeyLeftControl) { - CameraMoveUp(camera, -0.09) - } - } - } - - if mode == CameraThirdPerson || mode == CameraOrbital || mode == CameraFree { - // Zoom target distance - CameraMoveToTarget(camera, -GetMouseWheelMove()) - if IsKeyPressed(KeyKpSubtract) { - CameraMoveToTarget(camera, 2.0) - } - if IsKeyPressed(KeyKpAdd) { - CameraMoveToTarget(camera, -2.0) - } - } -} - -// UpdateCameraPro - Update camera movement, movement/rotation values should be provided by user -func UpdateCameraPro(camera *Camera, movement Vector3, rotation Vector3, zoom float32) { - // Required values - // movement.X - Move forward/backward - // movement.Y - Move right/left - // movement.Z - Move up/down - // rotation.X - yaw - // rotation.Y - pitch - // rotation.Z - roll - // zoom - Move towards target - - lockView := uint8(1) - rotateAroundTarget := uint8(0) - rotateUp := uint8(0) - moveInWorldPlane := uint8(1) - - // Camera rotation - CameraPitch(camera, -rotation.Y*(Pi/180.0), lockView, rotateAroundTarget, rotateUp) - CameraYaw(camera, -rotation.X*(Pi/180.0), rotateAroundTarget) - CameraRoll(camera, rotation.Z*(Pi/180.0)) - - // Camera movement - CameraMoveForward(camera, movement.X, moveInWorldPlane) - CameraMoveRight(camera, movement.Y, moveInWorldPlane) - CameraMoveUp(camera, movement.Z) - - // Zoom target distance - CameraMoveToTarget(camera, zoom) -} diff --git a/raylib/rcamera.h b/raylib/rcamera.h deleted file mode 100644 index a598e11..0000000 --- a/raylib/rcamera.h +++ /dev/null @@ -1,555 +0,0 @@ -/******************************************************************************************* -* -* rcamera - Basic camera system with support for multiple camera modes -* -* CONFIGURATION: -* #define RCAMERA_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* #define RCAMERA_STANDALONE -* If defined, the library can be used as standalone as a camera system but some -* functions must be redefined to manage inputs accordingly. -* -* CONTRIBUTORS: -* Ramon Santamaria: Supervision, review, update and maintenance -* Christoph Wagner: Complete redesign, using raymath (2022) -* Marc Palau: Initial implementation (2014) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2022-2025 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#ifndef RCAMERA_H -#define RCAMERA_H - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// Function specifiers definition - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) -#if defined(BUILD_LIBTYPE_SHARED) -#if defined(__TINYC__) -#define __declspec(x) __attribute__((x)) -#endif -#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) -#elif defined(USE_LIBTYPE_SHARED) -#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) -#endif -#endif - -#ifndef RLAPI - #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -#if defined(RCAMERA_STANDALONE) - #define CAMERA_CULL_DISTANCE_NEAR 0.01 - #define CAMERA_CULL_DISTANCE_FAR 1000.0 -#else - #define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR - #define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for standalone usage -//---------------------------------------------------------------------------------- -#if defined(RCAMERA_STANDALONE) - // Vector2, 2 components - typedef struct Vector2 { - float x; // Vector x component - float y; // Vector y component - } Vector2; - - // Vector3, 3 components - typedef struct Vector3 { - float x; // Vector x component - float y; // Vector y component - float z; // Vector z component - } Vector3; - - // Matrix, 4x4 components, column major, OpenGL style, right-handed - typedef struct Matrix { - float m0, m4, m8, m12; // Matrix first row (4 components) - float m1, m5, m9, m13; // Matrix second row (4 components) - float m2, m6, m10, m14; // Matrix third row (4 components) - float m3, m7, m11, m15; // Matrix fourth row (4 components) - } Matrix; - - // Camera type, defines a camera position/orientation in 3d space - typedef struct Camera3D { - Vector3 position; // Camera position - Vector3 target; // Camera target it looks-at - Vector3 up; // Camera up vector (rotation over its axis) - float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - int projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC - } Camera3D; - - typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D - - // Camera projection - typedef enum { - CAMERA_PERSPECTIVE = 0, // Perspective projection - CAMERA_ORTHOGRAPHIC // Orthographic projection - } CameraProjection; - - // Camera system modes - typedef enum { - CAMERA_CUSTOM = 0, // Camera custom, controlled by user (UpdateCamera() does nothing) - CAMERA_FREE, // Camera free mode - CAMERA_ORBITAL, // Camera orbital, around target, zoom supported - CAMERA_FIRST_PERSON, // Camera first person - CAMERA_THIRD_PERSON // Camera third person - } CameraMode; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -RLAPI Vector3 GetCameraForward(Camera *camera); -RLAPI Vector3 GetCameraUp(Camera *camera); -RLAPI Vector3 GetCameraRight(Camera *camera); - -// Camera movement -RLAPI void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane); -RLAPI void CameraMoveUp(Camera *camera, float distance); -RLAPI void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane); -RLAPI void CameraMoveToTarget(Camera *camera, float delta); - -// Camera rotation -RLAPI void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget); -RLAPI void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); -RLAPI void CameraRoll(Camera *camera, float angle); - -RLAPI Matrix GetCameraViewMatrix(Camera *camera); -RLAPI Matrix GetCameraProjectionMatrix(Camera *camera, float aspect); - -#if defined(__cplusplus) -} -#endif - -#endif // RCAMERA_H - -/*********************************************************************************** -* -* CAMERA IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RCAMERA_IMPLEMENTATION) - -#include "raymath.h" // Required for vector maths: - // Vector3Add() - // Vector3Subtract() - // Vector3Scale() - // Vector3Normalize() - // Vector3Distance() - // Vector3CrossProduct() - // Vector3RotateByAxisAngle() - // Vector3Angle() - // Vector3Negate() - // MatrixLookAt() - // MatrixPerspective() - // MatrixOrtho() - // MatrixIdentity() - -// raylib required functionality: - // GetMouseDelta() - // GetMouseWheelMove() - // IsKeyDown() - // IsKeyPressed() - // GetFrameTime() - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define CAMERA_MOVE_SPEED 5.4f // Units per second -#define CAMERA_ROTATION_SPEED 0.03f -#define CAMERA_PAN_SPEED 0.2f - -// Camera mouse movement sensitivity -#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f - -// Camera orbital speed in CAMERA_ORBITAL mode -#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- -// Returns the cameras forward vector (normalized) -Vector3 GetCameraForward(Camera *camera) -{ - return Vector3Normalize(Vector3Subtract(camera->target, camera->position)); -} - -// Returns the cameras up vector (normalized) -// Note: The up vector might not be perpendicular to the forward vector -Vector3 GetCameraUp(Camera *camera) -{ - return Vector3Normalize(camera->up); -} - -// Returns the cameras right vector (normalized) -Vector3 GetCameraRight(Camera *camera) -{ - Vector3 forward = GetCameraForward(camera); - Vector3 up = GetCameraUp(camera); - - return Vector3Normalize(Vector3CrossProduct(forward, up)); -} - -// Moves the camera in its forward direction -void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane) -{ - Vector3 forward = GetCameraForward(camera); - - if (moveInWorldPlane) - { - // Project vector onto world plane - forward.y = 0; - forward = Vector3Normalize(forward); - } - - // Scale by distance - forward = Vector3Scale(forward, distance); - - // Move position and target - camera->position = Vector3Add(camera->position, forward); - camera->target = Vector3Add(camera->target, forward); -} - -// Moves the camera in its up direction -void CameraMoveUp(Camera *camera, float distance) -{ - Vector3 up = GetCameraUp(camera); - - // Scale by distance - up = Vector3Scale(up, distance); - - // Move position and target - camera->position = Vector3Add(camera->position, up); - camera->target = Vector3Add(camera->target, up); -} - -// Moves the camera target in its current right direction -void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane) -{ - Vector3 right = GetCameraRight(camera); - - if (moveInWorldPlane) - { - // Project vector onto world plane - right.y = 0; - right = Vector3Normalize(right); - } - - // Scale by distance - right = Vector3Scale(right, distance); - - // Move position and target - camera->position = Vector3Add(camera->position, right); - camera->target = Vector3Add(camera->target, right); -} - -// Moves the camera position closer/farther to/from the camera target -void CameraMoveToTarget(Camera *camera, float delta) -{ - float distance = Vector3Distance(camera->position, camera->target); - - // Apply delta - distance += delta; - - // Distance must be greater than 0 - if (distance <= 0) distance = 0.001f; - - // Set new distance by moving the position along the forward vector - Vector3 forward = GetCameraForward(camera); - camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance)); -} - -// Rotates the camera around its up vector -// Yaw is "looking left and right" -// If rotateAroundTarget is false, the camera rotates around its position -// Note: angle must be provided in radians -void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget) -{ - // Rotation axis - Vector3 up = GetCameraUp(camera); - - // View vector - Vector3 targetPosition = Vector3Subtract(camera->target, camera->position); - - // Rotate view vector around up axis - targetPosition = Vector3RotateByAxisAngle(targetPosition, up, angle); - - if (rotateAroundTarget) - { - // Move position relative to target - camera->position = Vector3Subtract(camera->target, targetPosition); - } - else // rotate around camera.position - { - // Move target relative to position - camera->target = Vector3Add(camera->position, targetPosition); - } -} - -// Rotates the camera around its right vector, pitch is "looking up and down" -// - lockView prevents camera overrotation (aka "somersaults") -// - rotateAroundTarget defines if rotation is around target or around its position -// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) -// NOTE: angle must be provided in radians -void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) -{ - // Up direction - Vector3 up = GetCameraUp(camera); - - // View vector - Vector3 targetPosition = Vector3Subtract(camera->target, camera->position); - - if (lockView) - { - // In these camera modes we clamp the Pitch angle - // to allow only viewing straight up or down. - - // Clamp view up - float maxAngleUp = Vector3Angle(up, targetPosition); - maxAngleUp -= 0.001f; // avoid numerical errors - if (angle > maxAngleUp) angle = maxAngleUp; - - // Clamp view down - float maxAngleDown = Vector3Angle(Vector3Negate(up), targetPosition); - maxAngleDown *= -1.0f; // downwards angle is negative - maxAngleDown += 0.001f; // avoid numerical errors - if (angle < maxAngleDown) angle = maxAngleDown; - } - - // Rotation axis - Vector3 right = GetCameraRight(camera); - - // Rotate view vector around right axis - targetPosition = Vector3RotateByAxisAngle(targetPosition, right, angle); - - if (rotateAroundTarget) - { - // Move position relative to target - camera->position = Vector3Subtract(camera->target, targetPosition); - } - else // rotate around camera.position - { - // Move target relative to position - camera->target = Vector3Add(camera->position, targetPosition); - } - - if (rotateUp) - { - // Rotate up direction around right axis - camera->up = Vector3RotateByAxisAngle(camera->up, right, angle); - } -} - -// Rotates the camera around its forward vector -// Roll is "turning your head sideways to the left or right" -// Note: angle must be provided in radians -void CameraRoll(Camera *camera, float angle) -{ - // Rotation axis - Vector3 forward = GetCameraForward(camera); - - // Rotate up direction around forward axis - camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle); -} - -// Returns the camera view matrix -Matrix GetCameraViewMatrix(Camera *camera) -{ - return MatrixLookAt(camera->position, camera->target, camera->up); -} - -// Returns the camera projection matrix -Matrix GetCameraProjectionMatrix(Camera *camera, float aspect) -{ - if (camera->projection == CAMERA_PERSPECTIVE) - { - return MatrixPerspective(camera->fovy*DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); - } - else if (camera->projection == CAMERA_ORTHOGRAPHIC) - { - double top = camera->fovy/2.0; - double right = top*aspect; - - return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); - } - - return MatrixIdentity(); -} - -#if !defined(RCAMERA_STANDALONE) -// Update camera position for selected mode -// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM -void UpdateCamera(Camera *camera, int mode) -{ - Vector2 mousePositionDelta = GetMouseDelta(); - - bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)); - bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); - bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); - bool rotateUp = false; - - // Camera speeds based on frame time - float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime(); - float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime(); - float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime(); - float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime(); - - if (mode == CAMERA_CUSTOM) {} - else if (mode == CAMERA_ORBITAL) - { - // Orbital can just orbit - Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed); - Vector3 view = Vector3Subtract(camera->position, camera->target); - view = Vector3Transform(view, rotation); - camera->position = Vector3Add(camera->target, view); - } - else - { - // Camera rotation - if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp); - if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp); - if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget); - if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget); - if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed); - if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed); - - // Camera movement - // Camera pan (for CAMERA_FREE) - if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE))) - { - const Vector2 mouseDelta = GetMouseDelta(); - if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane); - if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane); - if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed); - if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed); - } - else - { - // Mouse support - CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); - CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); - } - - // Keyboard support - if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane); - if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane); - if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane); - if (IsKeyDown(KEY_D)) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane); - - // Gamepad movement - if (IsGamepadAvailable(0)) - { - // Gamepad controller support - CameraYaw(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); - CameraPitch(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); - - if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) <= -0.25f) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane); - if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) <= -0.25f) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane); - if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) >= 0.25f) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane); - if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) >= 0.25f) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane); - } - - if (mode == CAMERA_FREE) - { - if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, cameraMoveSpeed); - if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -cameraMoveSpeed); - } - } - - if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL) || (mode == CAMERA_FREE)) - { - // Zoom target distance - CameraMoveToTarget(camera, -GetMouseWheelMove()); - if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); - if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); - } -} -#endif // !RCAMERA_STANDALONE - -// Update camera movement, movement/rotation values should be provided by user -void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom) -{ - // Required values - // movement.x - Move forward/backward - // movement.y - Move right/left - // movement.z - Move up/down - // rotation.x - yaw - // rotation.y - pitch - // rotation.z - roll - // zoom - Move towards target - - bool lockView = true; - bool rotateAroundTarget = false; - bool rotateUp = false; - bool moveInWorldPlane = true; - - // Camera rotation - CameraPitch(camera, -rotation.y*DEG2RAD, lockView, rotateAroundTarget, rotateUp); - CameraYaw(camera, -rotation.x*DEG2RAD, rotateAroundTarget); - CameraRoll(camera, rotation.z*DEG2RAD); - - // Camera movement - CameraMoveForward(camera, movement.x, moveInWorldPlane); - CameraMoveRight(camera, movement.y, moveInWorldPlane); - CameraMoveUp(camera, movement.z); - - // Zoom target distance - CameraMoveToTarget(camera, zoom); -} - -#endif // RCAMERA_IMPLEMENTATION diff --git a/raylib/rcore.c b/raylib/rcore.c deleted file mode 100644 index f8b061a..0000000 --- a/raylib/rcore.c +++ /dev/null @@ -1,4134 +0,0 @@ -/********************************************************************************************** -* -* rcore - Window/display management, Graphic device/context management and input management -* -* PLATFORMS SUPPORTED: -* > PLATFORM_DESKTOP_GLFW (GLFW backend): -* - Windows (Win32, Win64) -* - Linux (X11/Wayland desktop mode) -* - macOS/OSX (x64, arm64) -* - FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop) -* > PLATFORM_DESKTOP_SDL (SDL backend): -* - Windows (Win32, Win64) -* - Linux (X11/Wayland desktop mode) -* - Others (not tested) -* > PLATFORM_DESKTOP_RGFW (RGFW backend): -* - Windows (Win32, Win64) -* - Linux (X11/Wayland desktop mode) -* - macOS/OSX (x64, arm64) -* - Others (not tested) -* > PLATFORM_WEB_RGFW: -* - HTML5 (WebAssembly) -* > PLATFORM_WEB: -* - HTML5 (WebAssembly) -* > PLATFORM_DRM: -* - Raspberry Pi 0-5 (DRM/KMS) -* - Linux DRM subsystem (KMS mode) -* > PLATFORM_ANDROID: -* - Android (ARM, ARM64) -* -* CONFIGURATION: -* #define SUPPORT_DEFAULT_FONT (default) -* Default font is loaded on window initialization to be available for the user to render simple text. -* NOTE: If enabled, uses external module functions to load default raylib font (module: text) -* -* #define SUPPORT_CAMERA_SYSTEM -* Camera module is included (rcamera.h) and multiple predefined cameras are available: -* free, 1st/3rd person, orbital, custom -* -* #define SUPPORT_GESTURES_SYSTEM -* Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag -* -* #define SUPPORT_MOUSE_GESTURES -* Mouse gestures are directly mapped like touches and processed by gestures system. -* -* #define SUPPORT_BUSY_WAIT_LOOP -* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used -* -* #define SUPPORT_PARTIALBUSY_WAIT_LOOP -* Use a partial-busy wait loop, in this case frame sleeps for most of the time and runs a busy-wait-loop at the end -* -* #define SUPPORT_SCREEN_CAPTURE -* Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() -* -* #define SUPPORT_GIF_RECORDING -* Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() -* -* #define SUPPORT_COMPRESSION_API -* Support CompressData() and DecompressData() functions, those functions use zlib implementation -* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module -* for linkage -* -* #define SUPPORT_AUTOMATION_EVENTS -* Support automatic events recording and playing, useful for automated testing systems or AI based game playing -* -* DEPENDENCIES: -* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion) -* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) -* gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -//---------------------------------------------------------------------------------- -// Feature Test Macros required for this module -//---------------------------------------------------------------------------------- -#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_XOPEN_SOURCE < 500) - #undef _XOPEN_SOURCE - #define _XOPEN_SOURCE 500 // Required for: readlink if compiled with c99 without gnu ext. -#endif - -#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_POSIX_C_SOURCE < 199309L) - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext. -#endif - -#include "raylib.h" // Declares module functions - -// Check if config flags have been externally provided on compilation line -#if !defined(EXTERNAL_CONFIG_FLAGS) - #include "config.h" // Defines module configuration flags -#endif - -#include "utils.h" // Required for: TRACELOG() macros - -#include // Required for: srand(), rand(), atexit() -#include // Required for: sprintf() [Used in OpenURL()] -#include // Required for: strrchr(), strcmp(), strlen(), memset() -#include // Required for: time() [Used in InitTimer()] -#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] - -#define RLGL_IMPLEMENTATION -#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 - -#define RAYMATH_IMPLEMENTATION -#include "raymath.h" // Vector2, Vector3, Quaternion and Matrix functionality - -#if defined(SUPPORT_GESTURES_SYSTEM) - #define RGESTURES_IMPLEMENTATION - #include "rgestures.h" // Gestures detection functionality -#endif - -#if defined(SUPPORT_CAMERA_SYSTEM) - #define RCAMERA_IMPLEMENTATION - #include "rcamera.h" // Camera system functionality -#endif - -#if defined(SUPPORT_GIF_RECORDING) - #define MSF_GIF_MALLOC(contextPointer, newSize) RL_MALLOC(newSize) - #define MSF_GIF_REALLOC(contextPointer, oldMemory, oldSize, newSize) RL_REALLOC(oldMemory, newSize) - #define MSF_GIF_FREE(contextPointer, oldMemory, oldSize) RL_FREE(oldMemory) - - #define MSF_GIF_IMPL - #include "external/msf_gif.h" // GIF recording functionality -#endif - -#if defined(SUPPORT_COMPRESSION_API) - #define SINFL_IMPLEMENTATION - #define SINFL_NO_SIMD - #include "external/sinfl.h" // Deflate (RFC 1951) decompressor - - #define SDEFL_IMPLEMENTATION - #include "external/sdefl.h" // Deflate (RFC 1951) compressor -#endif - -#if defined(SUPPORT_RPRAND_GENERATOR) - #define RPRAND_IMPLEMENTATION - #include "external/rprand.h" -#endif - -#if defined(__linux__) && !defined(_GNU_SOURCE) - #define _GNU_SOURCE -#endif - -// Platform specific defines to handle GetApplicationDirectory() -#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW)) - #ifndef MAX_PATH - #define MAX_PATH 1025 - #endif -struct HINSTANCE__; -__declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize); -__declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize); -__declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); -__declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); -__declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); -#elif defined(__linux__) - #include -#elif defined(__FreeBSD__) - #include - #include - #include -#elif defined(__APPLE__) - #include - #include -#endif // OSs - -#define _CRT_INTERNAL_NONSTDC_NAMES 1 -#include // Required for: stat(), S_ISREG [Used in GetFileModTime(), IsFilePath()] - -#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) - #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif - -#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) - #define DIRENT_MALLOC RL_MALLOC - #define DIRENT_FREE RL_FREE - - #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()] -#else - #include // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()] -#endif - -#if defined(_WIN32) - #include // Required for: _access() [Used in FileExists()] - #include // Required for: _getch(), _chdir(), _mkdir() - #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() - #define CHDIR _chdir - #define MKDIR(dir) _mkdir(dir) -#else - #include // Required for: getch(), chdir(), mkdir(), access() - #define GETCWD getcwd - #define CHDIR chdir - #define MKDIR(dir) mkdir(dir, 0777) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef MAX_FILEPATH_CAPACITY - #define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath -#endif -#ifndef MAX_FILEPATH_LENGTH - #if defined(_WIN32) - #define MAX_FILEPATH_LENGTH 256 // On Win32, MAX_PATH = 260 (limits.h) but Windows 10, Version 1607 enables long paths... - #else - #define MAX_FILEPATH_LENGTH 4096 // On Linux, PATH_MAX = 4096 by default (limits.h) - #endif -#endif - -#ifndef MAX_KEYBOARD_KEYS - #define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported -#endif -#ifndef MAX_MOUSE_BUTTONS - #define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported -#endif -#ifndef MAX_GAMEPADS - #define MAX_GAMEPADS 4 // Maximum number of gamepads supported -#endif -#ifndef MAX_GAMEPAD_NAME_LENGTH - #define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters in a gamepad name (byte size) -#endif -#ifndef MAX_GAMEPAD_AXES - #define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad) -#endif -#ifndef MAX_GAMEPAD_BUTTONS - #define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) -#endif -#ifndef MAX_GAMEPAD_VIBRATION_TIME - #define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds -#endif -#ifndef MAX_TOUCH_POINTS - #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported -#endif -#ifndef MAX_KEY_PRESSED_QUEUE - #define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue -#endif -#ifndef MAX_CHAR_PRESSED_QUEUE - #define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue -#endif - -#ifndef MAX_DECOMPRESSION_SIZE - #define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB -#endif - -#ifndef MAX_AUTOMATION_EVENTS - #define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record -#endif - -#ifndef DIRECTORY_FILTER_TAG - #define DIRECTORY_FILTER_TAG "DIR" // Name tag used to request directory inclusion on directory scan -#endif // NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx() - -// Flags operation macros -#define FLAG_SET(n, f) ((n) |= (f)) -#define FLAG_CLEAR(n, f) ((n) &= ~(f)) -#define FLAG_TOGGLE(n, f) ((n) ^= (f)) -#define FLAG_CHECK(n, f) ((n) & (f)) - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef struct { int x; int y; } Point; -typedef struct { unsigned int width; unsigned int height; } Size; - -// Core global state context data -typedef struct CoreData { - struct { - const char *title; // Window text title const pointer - unsigned int flags; // Configuration flags (bit based), keeps window state - bool ready; // Check if window has been initialized successfully - bool fullscreen; // Check if fullscreen mode is enabled - bool shouldClose; // Check if window set for closing - bool resizedLastFrame; // Check if window has been resized last frame - bool eventWaiting; // Wait for events before ending frame - bool usingFbo; // Using FBO (RenderTexture) for rendering instead of default framebuffer - - Point position; // Window position (required on fullscreen toggle) - Point previousPosition; // Window previous position (required on borderless windowed toggle) - Size display; // Display width and height (monitor, device-screen, LCD, ...) - Size screen; // Screen width and height (used render area) - Size previousScreen; // Screen previous width and height (required on borderless windowed toggle) - Size currentFbo; // Current render width and height (depends on active fbo) - Size render; // Framebuffer width and height (render area, including black bars if required) - Point renderOffset; // Offset from render area (must be divided by 2) - Size screenMin; // Screen minimum width and height (for resizable window) - Size screenMax; // Screen maximum width and height (for resizable window) - Matrix screenScale; // Matrix to scale screen (framebuffer rendering) - - char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW) - unsigned int dropFileCount; // Count dropped files strings - - } Window; - struct { - const char *basePath; // Base path for data storage - - } Storage; - struct { - struct { - int exitKey; // Default exit key - char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state - char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state - - // NOTE: Since key press logic involves comparing prev vs cur key state, we need to handle key repeats specially - char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame - - int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue - int keyPressedQueueCount; // Input keys queue count - - int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode) - int charPressedQueueCount; // Input characters queue count - - } Keyboard; - struct { - Vector2 offset; // Mouse offset - Vector2 scale; // Mouse scaling - Vector2 currentPosition; // Mouse position on screen - Vector2 previousPosition; // Previous mouse position - - int cursor; // Tracks current mouse cursor - bool cursorHidden; // Track if cursor is hidden - bool cursorOnScreen; // Tracks if cursor is inside client area - - char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state - char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state - Vector2 currentWheelMove; // Registers current mouse wheel variation - Vector2 previousWheelMove; // Registers previous mouse wheel variation - - } Mouse; - struct { - int pointCount; // Number of touch points active - int pointId[MAX_TOUCH_POINTS]; // Point identifiers - Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen - char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state - char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state - - } Touch; - struct { - int lastButtonPressed; // Register last gamepad button pressed - int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axes - bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready - char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH]; // Gamepad name holder - char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state - char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state - float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state - - } Gamepad; - } Input; - struct { - double current; // Current time measure - double previous; // Previous time measure - double update; // Time measure for frame update - double draw; // Time measure for frame draw - double frame; // Time measure for one frame - double target; // Desired time for one frame, if 0 not applied - unsigned long long int base; // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM) - unsigned int frameCounter; // Frame counter - - } Time; -} CoreData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings - -CoreData CORE = { 0 }; // Global CORE state context - -// Flag to note GPU acceleration is available, -// referenced from other modules to support GPU data loading -// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading -bool isGpuReady = false; - -#if defined(SUPPORT_SCREEN_CAPTURE) -static int screenshotCounter = 0; // Screenshots counter -#endif - -#if defined(SUPPORT_GIF_RECORDING) -static unsigned int gifFrameCounter = 0; // GIF frames counter -static bool gifRecording = false; // GIF recording state -static MsfGifState gifState = { 0 }; // MSGIF context state -#endif - -#if defined(SUPPORT_AUTOMATION_EVENTS) -// Automation events type -typedef enum AutomationEventType { - EVENT_NONE = 0, - // Input events - INPUT_KEY_UP, // param[0]: key - INPUT_KEY_DOWN, // param[0]: key - INPUT_KEY_PRESSED, // param[0]: key - INPUT_KEY_RELEASED, // param[0]: key - INPUT_MOUSE_BUTTON_UP, // param[0]: button - INPUT_MOUSE_BUTTON_DOWN, // param[0]: button - INPUT_MOUSE_POSITION, // param[0]: x, param[1]: y - INPUT_MOUSE_WHEEL_MOTION, // param[0]: x delta, param[1]: y delta - INPUT_GAMEPAD_CONNECT, // param[0]: gamepad - INPUT_GAMEPAD_DISCONNECT, // param[0]: gamepad - INPUT_GAMEPAD_BUTTON_UP, // param[0]: button - INPUT_GAMEPAD_BUTTON_DOWN, // param[0]: button - INPUT_GAMEPAD_AXIS_MOTION, // param[0]: axis, param[1]: delta - INPUT_TOUCH_UP, // param[0]: id - INPUT_TOUCH_DOWN, // param[0]: id - INPUT_TOUCH_POSITION, // param[0]: x, param[1]: y - INPUT_GESTURE, // param[0]: gesture - // Window events - WINDOW_CLOSE, // no params - WINDOW_MAXIMIZE, // no params - WINDOW_MINIMIZE, // no params - WINDOW_RESIZE, // param[0]: width, param[1]: height - // Custom events - ACTION_TAKE_SCREENSHOT, // no params - ACTION_SETTARGETFPS // param[0]: fps -} AutomationEventType; - -// Event type to config events flags -// TODO: Not used at the moment -typedef enum { - EVENT_INPUT_KEYBOARD = 0, - EVENT_INPUT_MOUSE = 1, - EVENT_INPUT_GAMEPAD = 2, - EVENT_INPUT_TOUCH = 4, - EVENT_INPUT_GESTURE = 8, - EVENT_WINDOW = 16, - EVENT_CUSTOM = 32 -} EventType; - -// Event type name strings, required for export -static const char *autoEventTypeName[] = { - "EVENT_NONE", - "INPUT_KEY_UP", - "INPUT_KEY_DOWN", - "INPUT_KEY_PRESSED", - "INPUT_KEY_RELEASED", - "INPUT_MOUSE_BUTTON_UP", - "INPUT_MOUSE_BUTTON_DOWN", - "INPUT_MOUSE_POSITION", - "INPUT_MOUSE_WHEEL_MOTION", - "INPUT_GAMEPAD_CONNECT", - "INPUT_GAMEPAD_DISCONNECT", - "INPUT_GAMEPAD_BUTTON_UP", - "INPUT_GAMEPAD_BUTTON_DOWN", - "INPUT_GAMEPAD_AXIS_MOTION", - "INPUT_TOUCH_UP", - "INPUT_TOUCH_DOWN", - "INPUT_TOUCH_POSITION", - "INPUT_GESTURE", - "WINDOW_CLOSE", - "WINDOW_MAXIMIZE", - "WINDOW_MINIMIZE", - "WINDOW_RESIZE", - "ACTION_TAKE_SCREENSHOT", - "ACTION_SETTARGETFPS" -}; - -/* -// Automation event (24 bytes) -// NOTE: Opaque struct, internal to raylib -struct AutomationEvent { - unsigned int frame; // Event frame - unsigned int type; // Event type (AutomationEventType) - int params[4]; // Event parameters (if required) -}; -*/ - -static AutomationEventList *currentEventList = NULL; // Current automation events list, set by user, keep internal pointer -static bool automationEventRecording = false; // Recording automation events flag -//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing -#endif -//----------------------------------------------------------------------------------- - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -// NOTE: Those functions are common for all platforms! -//---------------------------------------------------------------------------------- - -#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT) -extern void LoadFontDefault(void); // [Module: text] Loads default font on InitWindow() -extern void UnloadFontDefault(void); // [Module: text] Unloads default font from GPU memory -#endif - -extern int InitPlatform(void); // Initialize platform (graphics, inputs and more) -extern void ClosePlatform(void); // Close platform - -static void InitTimer(void); // Initialize timer, hi-resolution if available (required by InitPlatform()) -static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform()) -static void SetupViewport(int width, int height); // Set viewport for a provided width and height - -static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories in a base path -static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories recursively from a base path - -#if defined(SUPPORT_AUTOMATION_EVENTS) -static void RecordAutomationEvent(void); // Record frame events (to internal events array) -#endif - -#if defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW) -// NOTE: We declare Sleep() function symbol to avoid including windows.h (kernel32.lib linkage required) -__declspec(dllimport) void __stdcall Sleep(unsigned long msTimeout); // Required for: WaitTime() -#endif - -#if !defined(SUPPORT_MODULE_RTEXT) -const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -#endif // !SUPPORT_MODULE_RTEXT - -#if defined(PLATFORM_DESKTOP) - #define PLATFORM_DESKTOP_GLFW -#endif - -// We're using '#pragma message' because '#warning' is not adopted by MSVC -#if defined(SUPPORT_CLIPBOARD_IMAGE) - #if !defined(SUPPORT_MODULE_RTEXTURES) - #pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly") - #endif - - // It's nice to have support Bitmap on Linux as well, but not as necessary as Windows - #if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32) - #pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows") - #endif - - // From what I've tested applications on Wayland saves images on clipboard as PNG - #if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32) - #pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG") - #endif - - // Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined - // #if !defined(STBI_REQUIRED) - // #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard" - // #endif - -#endif // SUPPORT_CLIPBOARD_IMAGE - -// Include platform-specific submodules -#if defined(PLATFORM_DESKTOP_GLFW) - #include "platforms/rcore_desktop_glfw.c" -#elif defined(PLATFORM_DESKTOP_SDL) - #include "platforms/rcore_desktop_sdl.c" -#elif (defined(PLATFORM_DESKTOP_RGFW) || defined(PLATFORM_WEB_RGFW)) - #include "platforms/rcore_desktop_rgfw.c" -#elif defined(PLATFORM_WEB) - #include "platforms/rcore_web.c" -#elif defined(PLATFORM_DRM) - #include "platforms/rcore_drm.c" -#elif defined(PLATFORM_ANDROID) - #include "platforms/rcore_android.c" -#else - // TODO: Include your custom platform backend! - // i.e software rendering backend or console backend! -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Window and Graphics Device -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//bool WindowShouldClose(void) -//void ToggleFullscreen(void) -//void ToggleBorderlessWindowed(void) -//void MaximizeWindow(void) -//void MinimizeWindow(void) -//void RestoreWindow(void) - -//void SetWindowState(unsigned int flags) -//void ClearWindowState(unsigned int flags) - -//void SetWindowIcon(Image image) -//void SetWindowIcons(Image *images, int count) -//void SetWindowTitle(const char *title) -//void SetWindowPosition(int x, int y) -//void SetWindowMonitor(int monitor) -//void SetWindowMinSize(int width, int height) -//void SetWindowMaxSize(int width, int height) -//void SetWindowSize(int width, int height) -//void SetWindowOpacity(float opacity) -//void SetWindowFocused(void) -//void *GetWindowHandle(void) -//Vector2 GetWindowPosition(void) -//Vector2 GetWindowScaleDPI(void) - -//int GetMonitorCount(void) -//int GetCurrentMonitor(void) -//int GetMonitorWidth(int monitor) -//int GetMonitorHeight(int monitor) -//int GetMonitorPhysicalWidth(int monitor) -//int GetMonitorPhysicalHeight(int monitor) -//int GetMonitorRefreshRate(int monitor) -//Vector2 GetMonitorPosition(int monitor) -//const char *GetMonitorName(int monitor) - -//void SetClipboardText(const char *text) -//const char *GetClipboardText(void) - -//void ShowCursor(void) -//void HideCursor(void) -//void EnableCursor(void) -//void DisableCursor(void) - -// Initialize window and OpenGL context -void InitWindow(int width, int height, const char *title) -{ - TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION); - -#if defined(PLATFORM_DESKTOP_GLFW) - TRACELOG(LOG_INFO, "Platform backend: DESKTOP (GLFW)"); -#elif defined(PLATFORM_DESKTOP_SDL) - TRACELOG(LOG_INFO, "Platform backend: DESKTOP (SDL)"); -#elif defined(PLATFORM_DESKTOP_RGFW) - TRACELOG(LOG_INFO, "Platform backend: DESKTOP (RGFW)"); -#elif defined(PLATFORM_WEB_RGFW) - TRACELOG(LOG_INFO, "Platform backend: WEB (RGFW) (HTML5)"); -#elif defined(PLATFORM_WEB) - TRACELOG(LOG_INFO, "Platform backend: WEB (HTML5)"); -#elif defined(PLATFORM_DRM) - TRACELOG(LOG_INFO, "Platform backend: NATIVE DRM"); -#elif defined(PLATFORM_ANDROID) - TRACELOG(LOG_INFO, "Platform backend: ANDROID"); -#else - // TODO: Include your custom platform backend! - // i.e software rendering backend or console backend! - TRACELOG(LOG_INFO, "Platform backend: CUSTOM"); -#endif - - TRACELOG(LOG_INFO, "Supported raylib modules:"); - TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)"); - TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)"); -#if defined(SUPPORT_MODULE_RSHAPES) - TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)"); -#else - TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)"); -#endif -#if defined(SUPPORT_MODULE_RTEXTURES) - TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)"); -#else - TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)"); -#endif -#if defined(SUPPORT_MODULE_RTEXT) - TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)"); -#else - TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)"); -#endif -#if defined(SUPPORT_MODULE_RMODELS) - TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)"); -#else - TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)"); -#endif -#if defined(SUPPORT_MODULE_RAUDIO) - TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)"); -#else - TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)"); -#endif - - // Initialize window data - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - CORE.Window.eventWaiting = false; - CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default - if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title; - - // Initialize global input state - memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0 - CORE.Input.Keyboard.exitKey = KEY_ESCAPE; - CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; - CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW; - CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN; - - // Initialize platform - //-------------------------------------------------------------- - int result = InitPlatform(); - - if (result != 0) - { - TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize Platform"); - return; - } - //-------------------------------------------------------------- - - // Initialize rlgl default data (buffers and shaders) - // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl - rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); - isGpuReady = true; // Flag to note GPU has been initialized successfully - - // Setup default viewport - SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); - -#if defined(SUPPORT_MODULE_RTEXT) - #if defined(SUPPORT_DEFAULT_FONT) - // Load default font - // WARNING: External function: Module required: rtext - LoadFontDefault(); - #if defined(SUPPORT_MODULE_RSHAPES) - // Set font white rectangle for shapes drawing, so shapes and text can be batched together - // WARNING: rshapes module is required, if not available, default internal white rectangle is used - Rectangle rec = GetFontDefault().recs[95]; - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering - SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 }); - } - else - { - // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding - SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); - } - #endif - #endif -#else - #if defined(SUPPORT_MODULE_RSHAPES) - // Set default texture and rectangle to be used for shapes drawing - // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 - Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes - #endif -#endif - - CORE.Time.frameCounter = 0; - CORE.Window.shouldClose = false; - - // Initialize random seed - SetRandomSeed((unsigned int)time(NULL)); - - TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory()); -} - -// Close window and unload OpenGL context -void CloseWindow(void) -{ -#if defined(SUPPORT_GIF_RECORDING) - if (gifRecording) - { - MsfGifResult result = msf_gif_end(&gifState); - msf_gif_free(result); - gifRecording = false; - } -#endif - -#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT) - UnloadFontDefault(); // WARNING: Module required: rtext -#endif - - rlglClose(); // De-init rlgl - - // De-initialize platform - //-------------------------------------------------------------- - ClosePlatform(); - //-------------------------------------------------------------- - - CORE.Window.ready = false; - TRACELOG(LOG_INFO, "Window closed successfully"); -} - -// Check if window has been initialized successfully -bool IsWindowReady(void) -{ - return CORE.Window.ready; -} - -// Check if window is currently fullscreen -bool IsWindowFullscreen(void) -{ - return CORE.Window.fullscreen; -} - -// Check if window is currently hidden -bool IsWindowHidden(void) -{ - return ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0); -} - -// Check if window has been minimized -bool IsWindowMinimized(void) -{ - return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0); -} - -// Check if window has been maximized -bool IsWindowMaximized(void) -{ - return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0); -} - -// Check if window has the focus -bool IsWindowFocused(void) -{ - return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0); -} - -// Check if window has been resizedLastFrame -bool IsWindowResized(void) -{ - return CORE.Window.resizedLastFrame; -} - -// Check if one specific window flag is enabled -bool IsWindowState(unsigned int flag) -{ - return ((CORE.Window.flags & flag) > 0); -} - -// Get current screen width -int GetScreenWidth(void) -{ - return CORE.Window.screen.width; -} - -// Get current screen height -int GetScreenHeight(void) -{ - return CORE.Window.screen.height; -} - -// Get current render width which is equal to screen width*dpi scale -int GetRenderWidth(void) -{ - int width = 0; -#if defined(__APPLE__) - Vector2 scale = GetWindowScaleDPI(); - width = (int)((float)CORE.Window.render.width*scale.x); -#else - width = CORE.Window.render.width; -#endif - return width; -} - -// Get current screen height which is equal to screen height*dpi scale -int GetRenderHeight(void) -{ - int height = 0; -#if defined(__APPLE__) - Vector2 scale = GetWindowScaleDPI(); - height = (int)((float)CORE.Window.render.height*scale.y); -#else - height = CORE.Window.render.height; -#endif - return height; -} - -// Enable waiting for events on EndDrawing(), no automatic event polling -void EnableEventWaiting(void) -{ - CORE.Window.eventWaiting = true; -} - -// Disable waiting for events on EndDrawing(), automatic events polling -void DisableEventWaiting(void) -{ - CORE.Window.eventWaiting = false; -} - -// Check if cursor is not visible -bool IsCursorHidden(void) -{ - return CORE.Input.Mouse.cursorHidden; -} - -// Check if cursor is on the current screen -bool IsCursorOnScreen(void) -{ - return CORE.Input.Mouse.cursorOnScreen; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Screen Drawing -//---------------------------------------------------------------------------------- - -// Set background color (framebuffer clear color) -void ClearBackground(Color color) -{ - rlClearColor(color.r, color.g, color.b, color.a); // Set clear color - rlClearScreenBuffers(); // Clear current framebuffers -} - -// Setup canvas (framebuffer) to start drawing -void BeginDrawing(void) -{ - // WARNING: Previously to BeginDrawing() other render textures drawing could happen, - // consequently the measure for update vs draw is not accurate (only the total frame time is accurate) - - CORE.Time.current = GetTime(); // Number of elapsed seconds since InitTimer() - CORE.Time.update = CORE.Time.current - CORE.Time.previous; - CORE.Time.previous = CORE.Time.current; - - rlLoadIdentity(); // Reset current matrix (modelview) - rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling - - //rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1 - // NOTE: Not required with OpenGL 3.3+ -} - -// End canvas drawing and swap buffers (double buffering) -void EndDrawing(void) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - -#if defined(SUPPORT_GIF_RECORDING) - // Draw record indicator - if (gifRecording) - { - #ifndef GIF_RECORD_FRAMERATE - #define GIF_RECORD_FRAMERATE 10 - #endif - gifFrameCounter += (unsigned int)(GetFrameTime()*1000); - - // NOTE: We record one gif frame depending on the desired gif framerate - if (gifFrameCounter > 1000/GIF_RECORD_FRAMERATE) - { - // Get image data for the current frame (from backbuffer) - // NOTE: This process is quite slow... :( - Vector2 scale = GetWindowScaleDPI(); - unsigned char *screenData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); - - #ifndef GIF_RECORD_BITRATE - #define GIF_RECORD_BITRATE 16 - #endif - - // Add the frame to the gif recording, given how many frames have passed in centiseconds - msf_gif_frame(&gifState, screenData, gifFrameCounter/10, GIF_RECORD_BITRATE, (int)((float)CORE.Window.render.width*scale.x)*4); - gifFrameCounter -= 1000/GIF_RECORD_FRAMERATE; - - RL_FREE(screenData); // Free image data - } - - #if defined(SUPPORT_MODULE_RSHAPES) && defined(SUPPORT_MODULE_RTEXT) - // Display the recording indicator every half-second - if ((int)(GetTime()/0.5)%2 == 1) - { - DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON); // WARNING: Module required: rshapes - DrawText("GIF RECORDING", 50, CORE.Window.screen.height - 25, 10, RED); // WARNING: Module required: rtext - } - #endif - - rlDrawRenderBatchActive(); // Update and draw internal render batch - } -#endif - -#if defined(SUPPORT_AUTOMATION_EVENTS) - if (automationEventRecording) RecordAutomationEvent(); // Event recording -#endif - -#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL) - SwapScreenBuffer(); // Copy back buffer to front buffer (screen) - - // Frame time control system - CORE.Time.current = GetTime(); - CORE.Time.draw = CORE.Time.current - CORE.Time.previous; - CORE.Time.previous = CORE.Time.current; - - CORE.Time.frame = CORE.Time.update + CORE.Time.draw; - - // Wait for some milliseconds... - if (CORE.Time.frame < CORE.Time.target) - { - WaitTime(CORE.Time.target - CORE.Time.frame); - - CORE.Time.current = GetTime(); - double waitTime = CORE.Time.current - CORE.Time.previous; - CORE.Time.previous = CORE.Time.current; - - CORE.Time.frame += waitTime; // Total frame time: update + draw + wait - } - - PollInputEvents(); // Poll user events (before next frame update) -#endif - -#if defined(SUPPORT_SCREEN_CAPTURE) - if (IsKeyPressed(KEY_F12)) - { -#if defined(SUPPORT_GIF_RECORDING) - if (IsKeyDown(KEY_LEFT_CONTROL)) - { - if (gifRecording) - { - gifRecording = false; - - MsfGifResult result = msf_gif_end(&gifState); - - SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize); - msf_gif_free(result); - - TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); - } - else - { - gifRecording = true; - gifFrameCounter = 0; - - Vector2 scale = GetWindowScaleDPI(); - msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); - screenshotCounter++; - - TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); - } - } - else -#endif // SUPPORT_GIF_RECORDING - { - TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); - screenshotCounter++; - } - } -#endif // SUPPORT_SCREEN_CAPTURE - - CORE.Time.frameCounter++; -} - -// Initialize 2D mode with custom camera (2D) -void BeginMode2D(Camera2D camera) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlLoadIdentity(); // Reset current matrix (modelview) - - // Apply 2d camera transformation to modelview - rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera))); -} - -// Ends 2D mode with custom camera -void EndMode2D(void) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlLoadIdentity(); // Reset current matrix (modelview) - - if (rlGetActiveFramebuffer() == 0) rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required -} - -// Initializes 3D mode with custom camera (3D) -void BeginMode3D(Camera camera) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlMatrixMode(RL_PROJECTION); // Switch to projection matrix - rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection - rlLoadIdentity(); // Reset current matrix (projection) - - float aspect = (float)CORE.Window.currentFbo.width/(float)CORE.Window.currentFbo.height; - - // NOTE: zNear and zFar values are important when computing depth buffer values - if (camera.projection == CAMERA_PERSPECTIVE) - { - // Setup perspective projection - double top = rlGetCullDistanceNear()*tan(camera.fovy*0.5*DEG2RAD); - double right = top*aspect; - - rlFrustum(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); - } - else if (camera.projection == CAMERA_ORTHOGRAPHIC) - { - // Setup orthographic projection - double top = camera.fovy/2.0; - double right = top*aspect; - - rlOrtho(-right, right, -top,top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); - } - - rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix - rlLoadIdentity(); // Reset current matrix (modelview) - - // Setup Camera view - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - rlMultMatrixf(MatrixToFloat(matView)); // Multiply modelview matrix by view matrix (camera) - - rlEnableDepthTest(); // Enable DEPTH_TEST for 3D -} - -// Ends 3D mode and returns to default 2D orthographic mode -void EndMode3D(void) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlMatrixMode(RL_PROJECTION); // Switch to projection matrix - rlPopMatrix(); // Restore previous matrix (projection) from matrix stack - - rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix - rlLoadIdentity(); // Reset current matrix (modelview) - - if (rlGetActiveFramebuffer() == 0) rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required - - rlDisableDepthTest(); // Disable DEPTH_TEST for 2D -} - -// Initializes render texture for drawing -void BeginTextureMode(RenderTexture2D target) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlEnableFramebuffer(target.id); // Enable render target - - // Set viewport and RLGL internal framebuffer size - rlViewport(0, 0, target.texture.width, target.texture.height); - rlSetFramebufferWidth(target.texture.width); - rlSetFramebufferHeight(target.texture.height); - - rlMatrixMode(RL_PROJECTION); // Switch to projection matrix - rlLoadIdentity(); // Reset current matrix (projection) - - // Set orthographic projection to current framebuffer size - // NOTE: Configured top-left corner as (0, 0) - rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f); - - rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix - rlLoadIdentity(); // Reset current matrix (modelview) - - //rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?) - - // Setup current width/height for proper aspect ratio - // calculation when using BeginTextureMode() - CORE.Window.currentFbo.width = target.texture.width; - CORE.Window.currentFbo.height = target.texture.height; - CORE.Window.usingFbo = true; -} - -// Ends drawing to render texture -void EndTextureMode(void) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlDisableFramebuffer(); // Disable render target (fbo) - - // Set viewport to default framebuffer size - SetupViewport(CORE.Window.render.width, CORE.Window.render.height); - - // Go back to the modelview state from BeginDrawing since we are back to the default FBO - rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix - rlLoadIdentity(); // Reset current matrix (modelview) - rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required - - // Reset current fbo to screen size - CORE.Window.currentFbo.width = CORE.Window.render.width; - CORE.Window.currentFbo.height = CORE.Window.render.height; - CORE.Window.usingFbo = false; -} - -// Begin custom shader mode -void BeginShaderMode(Shader shader) -{ - rlSetShader(shader.id, shader.locs); -} - -// End custom shader mode (returns to default shader) -void EndShaderMode(void) -{ - rlSetShader(rlGetShaderIdDefault(), rlGetShaderLocsDefault()); -} - -// Begin blending mode (alpha, additive, multiplied, subtract, custom) -// NOTE: Blend modes supported are enumerated in BlendMode enum -void BeginBlendMode(int mode) -{ - rlSetBlendMode(mode); -} - -// End blending mode (reset to default: alpha blending) -void EndBlendMode(void) -{ - rlSetBlendMode(BLEND_ALPHA); -} - -// Begin scissor mode (define screen area for following drawing) -// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left -void BeginScissorMode(int x, int y, int width, int height) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlEnableScissorTest(); - -#if defined(__APPLE__) - if (!CORE.Window.usingFbo) - { - Vector2 scale = GetWindowScaleDPI(); - rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y)); - } -#else - if (!CORE.Window.usingFbo && ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)) - { - Vector2 scale = GetWindowScaleDPI(); - rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y)); - } -#endif - else - { - rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height); - } -} - -// End scissor mode -void EndScissorMode(void) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - rlDisableScissorTest(); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: VR Stereo Rendering -//---------------------------------------------------------------------------------- - -// Begin VR drawing configuration -void BeginVrStereoMode(VrStereoConfig config) -{ - rlEnableStereoRender(); - - // Set stereo render matrices - rlSetMatrixProjectionStereo(config.projection[0], config.projection[1]); - rlSetMatrixViewOffsetStereo(config.viewOffset[0], config.viewOffset[1]); -} - -// End VR drawing process (and desktop mirror) -void EndVrStereoMode(void) -{ - rlDisableStereoRender(); -} - -// Load VR stereo config for VR simulator device parameters -VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device) -{ - VrStereoConfig config = { 0 }; - - if (rlGetVersion() != RL_OPENGL_11) - { - // Compute aspect ratio - float aspect = ((float)device.hResolution*0.5f)/(float)device.vResolution; - - // Compute lens parameters - float lensShift = (device.hScreenSize*0.25f - device.lensSeparationDistance*0.5f)/device.hScreenSize; - config.leftLensCenter[0] = 0.25f + lensShift; - config.leftLensCenter[1] = 0.5f; - config.rightLensCenter[0] = 0.75f - lensShift; - config.rightLensCenter[1] = 0.5f; - config.leftScreenCenter[0] = 0.25f; - config.leftScreenCenter[1] = 0.5f; - config.rightScreenCenter[0] = 0.75f; - config.rightScreenCenter[1] = 0.5f; - - // Compute distortion scale parameters - // NOTE: To get lens max radius, lensShift must be normalized to [-1..1] - float lensRadius = fabsf(-1.0f - 4.0f*lensShift); - float lensRadiusSq = lensRadius*lensRadius; - float distortionScale = device.lensDistortionValues[0] + - device.lensDistortionValues[1]*lensRadiusSq + - device.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq + - device.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq; - - float normScreenWidth = 0.5f; - float normScreenHeight = 1.0f; - config.scaleIn[0] = 2.0f/normScreenWidth; - config.scaleIn[1] = 2.0f/normScreenHeight/aspect; - config.scale[0] = normScreenWidth*0.5f/distortionScale; - config.scale[1] = normScreenHeight*0.5f*aspect/distortionScale; - - // Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance) - // ...but with lens distortion it is increased (see Oculus SDK Documentation) - float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance); // Really need distortionScale? - // float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance); - - // Compute camera projection matrices - float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] - Matrix proj = MatrixPerspective(fovy, aspect, rlGetCullDistanceNear(), rlGetCullDistanceFar()); - - config.projection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)); - config.projection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f)); - - // Compute camera transformation matrices - // NOTE: Camera movement might seem more natural if we model the head - // Our axis of rotation is the base of our head, so we might want to add - // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions - config.viewOffset[0] = MatrixTranslate(device.interpupillaryDistance*0.5f, 0.075f, 0.045f); - config.viewOffset[1] = MatrixTranslate(-device.interpupillaryDistance*0.5f, 0.075f, 0.045f); - - // Compute eyes Viewports - /* - config.eyeViewportRight[0] = 0; - config.eyeViewportRight[1] = 0; - config.eyeViewportRight[2] = device.hResolution/2; - config.eyeViewportRight[3] = device.vResolution; - - config.eyeViewportLeft[0] = device.hResolution/2; - config.eyeViewportLeft[1] = 0; - config.eyeViewportLeft[2] = device.hResolution/2; - config.eyeViewportLeft[3] = device.vResolution; - */ - } - else TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1"); - - return config; -} - -// Unload VR stereo config properties -void UnloadVrStereoConfig(VrStereoConfig config) -{ - TRACELOG(LOG_INFO, "UnloadVrStereoConfig not implemented in rcore.c"); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Shaders Management -//---------------------------------------------------------------------------------- - -// Load shader from files and bind default locations -// NOTE: If shader string is NULL, using default vertex/fragment shaders -Shader LoadShader(const char *vsFileName, const char *fsFileName) -{ - Shader shader = { 0 }; - - char *vShaderStr = NULL; - char *fShaderStr = NULL; - - if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName); - if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName); - - if ((vShaderStr == NULL) && (fShaderStr == NULL)) TraceLog(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader"); - - shader = LoadShaderFromMemory(vShaderStr, fShaderStr); - - UnloadFileText(vShaderStr); - UnloadFileText(fShaderStr); - - return shader; -} - -// Load shader from code strings and bind default locations -Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) -{ - Shader shader = { 0 }; - - shader.id = rlLoadShaderCode(vsCode, fsCode); - - if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault(); - else if (shader.id > 0) - { - // After custom shader loading, we TRY to set default location names - // Default shader attribute locations have been binded before linking: - // vertex position location = 0 - // vertex texcoord location = 1 - // vertex normal location = 2 - // vertex color location = 3 - // vertex tangent location = 4 - // vertex texcoord2 location = 5 - // vertex boneIds location = 6 - // vertex boneWeights location = 7 - - // NOTE: If any location is not found, loc point becomes -1 - - shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); - - // All locations reset to -1 (no location) - for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; - - // Get handles to GLSL input attribute locations - shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); - shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); - shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); - shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); - shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); - shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); - shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); - shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); - shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX); - - // Get handles to GLSL uniform locations (vertex shader) - shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP); - shader.locs[SHADER_LOC_MATRIX_VIEW] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW); - shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION); - shader.locs[SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL); - shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL); - shader.locs[SHADER_LOC_BONE_MATRICES] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES); - - // Get handles to GLSL uniform locations (fragment shader) - shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR); - shader.locs[SHADER_LOC_MAP_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0); // SHADER_LOC_MAP_ALBEDO - shader.locs[SHADER_LOC_MAP_SPECULAR] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1); // SHADER_LOC_MAP_METALNESS - shader.locs[SHADER_LOC_MAP_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2); - } - - return shader; -} - -// Check if a shader is valid (loaded on GPU) -bool IsShaderValid(Shader shader) -{ - return ((shader.id > 0) && // Validate shader id (GPU loaded successfully) - (shader.locs != NULL)); // Validate memory has been allocated for default shader locations - - // The following locations are tried to be set automatically (locs[i] >= 0), - // any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION - // NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones - - // Vertex shader attribute locations (default) - // shader.locs[SHADER_LOC_VERTEX_POSITION] // Set by default internal shader - // shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] // Set by default internal shader - // shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] - // shader.locs[SHADER_LOC_VERTEX_NORMAL] - // shader.locs[SHADER_LOC_VERTEX_TANGENT] - // shader.locs[SHADER_LOC_VERTEX_COLOR] // Set by default internal shader - - // Vertex shader uniform locations (default) - // shader.locs[SHADER_LOC_MATRIX_MVP] // Set by default internal shader - // shader.locs[SHADER_LOC_MATRIX_VIEW] - // shader.locs[SHADER_LOC_MATRIX_PROJECTION] - // shader.locs[SHADER_LOC_MATRIX_MODEL] - // shader.locs[SHADER_LOC_MATRIX_NORMAL] - - // Fragment shader uniform locations (default) - // shader.locs[SHADER_LOC_COLOR_DIFFUSE] // Set by default internal shader - // shader.locs[SHADER_LOC_MAP_DIFFUSE] // Set by default internal shader - // shader.locs[SHADER_LOC_MAP_SPECULAR] - // shader.locs[SHADER_LOC_MAP_NORMAL] -} - -// Unload shader from GPU memory (VRAM) -void UnloadShader(Shader shader) -{ - if (shader.id != rlGetShaderIdDefault()) - { - rlUnloadShaderProgram(shader.id); - - // NOTE: If shader loading failed, it should be 0 - RL_FREE(shader.locs); - } -} - -// Get shader uniform location -int GetShaderLocation(Shader shader, const char *uniformName) -{ - return rlGetLocationUniform(shader.id, uniformName); -} - -// Get shader attribute location -int GetShaderLocationAttrib(Shader shader, const char *attribName) -{ - return rlGetLocationAttrib(shader.id, attribName); -} - -// Set shader uniform value -void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType) -{ - SetShaderValueV(shader, locIndex, value, uniformType, 1); -} - -// Set shader uniform value vector -void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count) -{ - if (locIndex > -1) - { - rlEnableShader(shader.id); - rlSetUniform(locIndex, value, uniformType, count); - //rlDisableShader(); // Avoid resetting current shader program, in case other uniforms are set - } -} - -// Set shader uniform value (matrix 4x4) -void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat) -{ - if (locIndex > -1) - { - rlEnableShader(shader.id); - rlSetUniformMatrix(locIndex, mat); - //rlDisableShader(); - } -} - -// Set shader uniform value for texture -void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture) -{ - if (locIndex > -1) - { - rlEnableShader(shader.id); - rlSetUniformSampler(locIndex, texture.id); - //rlDisableShader(); - } -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Screen-space Queries -//---------------------------------------------------------------------------------- - -// Get a ray trace from screen position (i.e mouse) -Ray GetScreenToWorldRay(Vector2 position, Camera camera) -{ - Ray ray = GetScreenToWorldRayEx(position, camera, GetScreenWidth(), GetScreenHeight()); - - return ray; -} - -// Get a ray trace from the screen position (i.e mouse) within a specific section of the screen -Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height) -{ - Ray ray = { 0 }; - - // Calculate normalized device coordinates - // NOTE: y value is negative - float x = (2.0f*position.x)/(float)width - 1.0f; - float y = 1.0f - (2.0f*position.y)/(float)height; - float z = 1.0f; - - // Store values in a vector - Vector3 deviceCoords = { x, y, z }; - - // Calculate view matrix from camera look at - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - - Matrix matProj = MatrixIdentity(); - - if (camera.projection == CAMERA_PERSPECTIVE) - { - // Calculate projection matrix from perspective - matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar()); - } - else if (camera.projection == CAMERA_ORTHOGRAPHIC) - { - double aspect = (double)width/(double)height; - double top = camera.fovy/2.0; - double right = top*aspect; - - // Calculate projection matrix from orthographic - matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0); - } - - // Unproject far/near points - Vector3 nearPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); - Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); - - // Unproject the mouse cursor in the near plane - // We need this as the source position because orthographic projects, - // compared to perspective doesn't have a convergence point, - // meaning that the "eye" of the camera is more like a plane than a point - Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); - - // Calculate normalized direction vector - Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint)); - - if (camera.projection == CAMERA_PERSPECTIVE) ray.position = camera.position; - else if (camera.projection == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos; - - // Apply calculated vectors to ray - ray.direction = direction; - - return ray; -} - -// Get transform matrix for camera -Matrix GetCameraMatrix(Camera camera) -{ - Matrix mat = MatrixLookAt(camera.position, camera.target, camera.up); - - return mat; -} - -// Get camera 2d transform matrix -Matrix GetCameraMatrix2D(Camera2D camera) -{ - Matrix matTransform = { 0 }; - // The camera in world-space is set by - // 1. Move it to target - // 2. Rotate by -rotation and scale by (1/zoom) - // When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller), - // not for the camera getting bigger, hence the invert. Same deal with rotation - // 3. Move it by (-offset); - // Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera) - // we need to do it into opposite direction (inverse transform) - - // Having camera transform in world-space, inverse of it gives the modelview transform - // Since (A*B*C)' = C'*B'*A', the modelview is - // 1. Move to offset - // 2. Rotate and Scale - // 3. Move by -target - Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); - Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); - Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); - Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f); - - matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); - - return matTransform; -} - -// Get the screen space position from a 3d world space position -Vector2 GetWorldToScreen(Vector3 position, Camera camera) -{ - Vector2 screenPosition = GetWorldToScreenEx(position, camera, GetScreenWidth(), GetScreenHeight()); - - return screenPosition; -} - -// Get size position for a 3d world space position (useful for texture drawing) -Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height) -{ - // Calculate projection matrix (from perspective instead of frustum - Matrix matProj = MatrixIdentity(); - - if (camera.projection == CAMERA_PERSPECTIVE) - { - // Calculate projection matrix from perspective - matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar()); - } - else if (camera.projection == CAMERA_ORTHOGRAPHIC) - { - double aspect = (double)width/(double)height; - double top = camera.fovy/2.0; - double right = top*aspect; - - // Calculate projection matrix from orthographic - matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); - } - - // Calculate view matrix from camera look at (and transpose it) - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - - // TODO: Why not use Vector3Transform(Vector3 v, Matrix mat)? - - // Convert world position vector to quaternion - Quaternion worldPos = { position.x, position.y, position.z, 1.0f }; - - // Transform world position to view - worldPos = QuaternionTransform(worldPos, matView); - - // Transform result to projection (clip space position) - worldPos = QuaternionTransform(worldPos, matProj); - - // Calculate normalized device coordinates (inverted y) - Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w }; - - // Calculate 2d screen position vector - Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)width, (ndcPos.y + 1.0f)/2.0f*(float)height }; - - return screenPosition; -} - -// Get the screen space position for a 2d camera world space position -Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera) -{ - Matrix matCamera = GetCameraMatrix2D(camera); - Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera); - - return (Vector2){ transform.x, transform.y }; -} - -// Get the world space position for a 2d camera screen space position -Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera) -{ - Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera)); - Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera); - - return (Vector2){ transform.x, transform.y }; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Timming -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//double GetTime(void) - -// Set target FPS (maximum) -void SetTargetFPS(int fps) -{ - if (fps < 1) CORE.Time.target = 0.0; - else CORE.Time.target = 1.0/(double)fps; - - TRACELOG(LOG_INFO, "TIMER: Target time per frame: %02.03f milliseconds", (float)CORE.Time.target*1000.0f); -} - -// Get current FPS -// NOTE: We calculate an average framerate -int GetFPS(void) -{ - int fps = 0; - -#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL) - #define FPS_CAPTURE_FRAMES_COUNT 30 // 30 captures - #define FPS_AVERAGE_TIME_SECONDS 0.5f // 500 milliseconds - #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT) - - static int index = 0; - static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 }; - static float average = 0, last = 0; - float fpsFrame = GetFrameTime(); - - // if we reset the window, reset the FPS info - if (CORE.Time.frameCounter == 0) - { - average = 0; - last = 0; - index = 0; - - for (int i = 0; i < FPS_CAPTURE_FRAMES_COUNT; i++) history[i] = 0; - } - - if (fpsFrame == 0) return 0; - - if ((GetTime() - last) > FPS_STEP) - { - last = (float)GetTime(); - index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT; - average -= history[index]; - history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT; - average += history[index]; - } - - fps = (int)roundf(1.0f/average); -#endif - - return fps; -} - -// Get time in seconds for last frame drawn (delta time) -float GetFrameTime(void) -{ - return (float)CORE.Time.frame; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Custom frame control -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//void SwapScreenBuffer(void); -//void PollInputEvents(void); - -// Wait for some time (stop program execution) -// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could -// take longer than expected... for that reason we use the busy wait loop -// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected -// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32! -void WaitTime(double seconds) -{ - if (seconds < 0) return; // Security check - -#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) - double destinationTime = GetTime() + seconds; -#endif - -#if defined(SUPPORT_BUSY_WAIT_LOOP) - while (GetTime() < destinationTime) { } -#else - #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) - double sleepSeconds = seconds - seconds*0.05; // NOTE: We reserve a percentage of the time for busy waiting - #else - double sleepSeconds = seconds; - #endif - - // System halt functions - #if defined(_WIN32) - Sleep((unsigned long)(sleepSeconds*1000.0)); - #endif - #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) - struct timespec req = { 0 }; - time_t sec = sleepSeconds; - long nsec = (sleepSeconds - sec)*1000000000L; - req.tv_sec = sec; - req.tv_nsec = nsec; - - // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated - while (nanosleep(&req, &req) == -1) continue; - #endif - #if defined(__APPLE__) - usleep(sleepSeconds*1000000.0); - #endif - - #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) - while (GetTime() < destinationTime) { } - #endif -#endif -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Misc -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//void OpenURL(const char *url) - -// Set the seed for the random number generator -void SetRandomSeed(unsigned int seed) -{ -#if defined(SUPPORT_RPRAND_GENERATOR) - rprand_set_seed(seed); -#else - srand(seed); -#endif -} - -// Get a random value between min and max included -int GetRandomValue(int min, int max) -{ - int value = 0; - - if (min > max) - { - int tmp = max; - max = min; - min = tmp; - } - -#if defined(SUPPORT_RPRAND_GENERATOR) - value = rprand_get_value(min, max); -#else - // WARNING: Ranges higher than RAND_MAX will return invalid results - // More specifically, if (max - min) > INT_MAX there will be an overflow, - // and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold - // NOTE: Depending on the library it can be as low as 32767 - if ((unsigned int)(max - min) > (unsigned int)RAND_MAX) - { - TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX); - } - - value = (rand()%(abs(max - min) + 1) + min); -#endif - return value; -} - -// Load random values sequence, no values repeated, min and max included -int *LoadRandomSequence(unsigned int count, int min, int max) -{ - int *values = NULL; - -#if defined(SUPPORT_RPRAND_GENERATOR) - values = rprand_load_sequence(count, min, max); -#else - if (count > ((unsigned int)abs(max - min) + 1)) return values; // Security check - - values = (int *)RL_CALLOC(count, sizeof(int)); - - int value = 0; - bool dupValue = false; - - for (int i = 0; i < (int)count;) - { - value = (rand()%(abs(max - min) + 1) + min); - dupValue = false; - - for (int j = 0; j < i; j++) - { - if (values[j] == value) - { - dupValue = true; - break; - } - } - - if (!dupValue) - { - values[i] = value; - i++; - } - } -#endif - return values; -} - -// Unload random values sequence -void UnloadRandomSequence(int *sequence) -{ -#if defined(SUPPORT_RPRAND_GENERATOR) - rprand_unload_sequence(sequence); -#else - RL_FREE(sequence); -#endif -} - -// Takes a screenshot of current screen -// NOTE: Provided fileName should not contain paths, saving to working directory -void TakeScreenshot(const char *fileName) -{ -#if defined(SUPPORT_MODULE_RTEXTURES) - // Security check to (partially) avoid malicious code - if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; } - - // Apply a scale if we are doing HIGHDPI auto-scaling - Vector2 scale = { 1.0f, 1.0f }; - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI(); - - unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); - Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - - char path[512] = { 0 }; - strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName)); - - ExportImage(image, path); // WARNING: Module required: rtextures - RL_FREE(imgData); - - if (FileExists(path)) TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path); - else TRACELOG(LOG_WARNING, "SYSTEM: [%s] Screenshot could not be saved", path); -#else - TRACELOG(LOG_WARNING,"IMAGE: ExportImage() requires module: rtextures"); -#endif -} - -// Setup window configuration flags (view FLAGS) -// NOTE: This function is expected to be called before window creation, -// because it sets up some flags for the window creation process -// To configure window states after creation, just use SetWindowState() -void SetConfigFlags(unsigned int flags) -{ - if (CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetConfigFlags called after window initialization, Use \"SetWindowState\" to set flags instead"); - - // Selected flags are set but not evaluated at this point, - // flag evaluation happens at InitWindow() or SetWindowState() - CORE.Window.flags |= flags; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: File system -//---------------------------------------------------------------------------------- - -// Check if the file exists -bool FileExists(const char *fileName) -{ - bool result = false; - -#if defined(_WIN32) - if (_access(fileName, 0) != -1) result = true; -#else - if (access(fileName, F_OK) != -1) result = true; -#endif - - // NOTE: Alternatively, stat() can be used instead of access() - //#include - //struct stat statbuf; - //if (stat(filename, &statbuf) == 0) result = true; - - return result; -} - -// Check file extension -// NOTE: Extensions checking is not case-sensitive -bool IsFileExtension(const char *fileName, const char *ext) -{ - #define MAX_FILE_EXTENSION_LENGTH 16 - - bool result = false; - const char *fileExt = GetFileExtension(fileName); - - if (fileExt != NULL) - { -#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_TEXT_MANIPULATION) - int extCount = 0; - char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext - - char fileExtLower[MAX_FILE_EXTENSION_LENGTH + 1] = { 0 }; - strncpy(fileExtLower, TextToLower(fileExt), MAX_FILE_EXTENSION_LENGTH); // WARNING: Module required: rtext - - for (int i = 0; i < extCount; i++) - { - if (strcmp(fileExtLower, TextToLower(checkExts[i])) == 0) - { - result = true; - break; - } - } -#else - if (strcmp(fileExt, ext) == 0) result = true; -#endif - } - - return result; -} - -// Check if a directory path exists -bool DirectoryExists(const char *dirPath) -{ - bool result = false; - DIR *dir = opendir(dirPath); - - if (dir != NULL) - { - result = true; - closedir(dir); - } - - return result; -} - -// Get file length in bytes -// NOTE: GetFileSize() conflicts with windows.h -int GetFileLength(const char *fileName) -{ - int size = 0; - - // NOTE: On Unix-like systems, it can by used the POSIX system call: stat(), - // but depending on the platform that call could not be available - //struct stat result = { 0 }; - //stat(fileName, &result); - //return result.st_size; - - FILE *file = fopen(fileName, "rb"); - - if (file != NULL) - { - fseek(file, 0L, SEEK_END); - long int fileSize = ftell(file); - - // Check for size overflow (INT_MAX) - if (fileSize > 2147483647) TRACELOG(LOG_WARNING, "[%s] File size overflows expected limit, do not use GetFileLength()", fileName); - else size = (int)fileSize; - - fclose(file); - } - - return size; -} - -// Get pointer to extension for a filename string (includes the dot: .png) -const char *GetFileExtension(const char *fileName) -{ - const char *dot = strrchr(fileName, '.'); - - if (!dot || dot == fileName) return NULL; - - return dot; -} - -// String pointer reverse break: returns right-most occurrence of charset in s -static const char *strprbrk(const char *s, const char *charset) -{ - const char *latestMatch = NULL; - - for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { } - - return latestMatch; -} - -// Get pointer to filename for a path string -const char *GetFileName(const char *filePath) -{ - const char *fileName = NULL; - - if (filePath != NULL) fileName = strprbrk(filePath, "\\/"); - - if (fileName == NULL) return filePath; - - return fileName + 1; -} - -// Get filename string without extension (uses static string) -const char *GetFileNameWithoutExt(const char *filePath) -{ - #define MAX_FILENAME_LENGTH 256 - - static char fileName[MAX_FILENAME_LENGTH] = { 0 }; - memset(fileName, 0, MAX_FILENAME_LENGTH); - - if (filePath != NULL) - { - strcpy(fileName, GetFileName(filePath)); // Get filename.ext without path - int size = (int)strlen(fileName); // Get size in bytes - - for (int i = size; i > 0; i--) // Reverse search '.' - { - if (fileName[i] == '.') - { - // NOTE: We break on first '.' found - fileName[i] = '\0'; - break; - } - } - } - - return fileName; -} - -// Get directory for a given filePath -const char *GetDirectoryPath(const char *filePath) -{ - /* - // NOTE: Directory separator is different in Windows and other platforms, - // fortunately, Windows also support the '/' separator, that's the one should be used - #if defined(_WIN32) - char separator = '\\'; - #else - char separator = '/'; - #endif - */ - const char *lastSlash = NULL; - static char dirPath[MAX_FILEPATH_LENGTH] = { 0 }; - memset(dirPath, 0, MAX_FILEPATH_LENGTH); - - // In case provided path does not contain a root drive letter (C:\, D:\) nor leading path separator (\, /), - // we add the current directory path to dirPath - if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/')) - { - // For security, we set starting path to current directory, - // obtained path will be concatenated to this - dirPath[0] = '.'; - dirPath[1] = '/'; - } - - lastSlash = strprbrk(filePath, "\\/"); - if (lastSlash) - { - if (lastSlash == filePath) - { - // The last and only slash is the leading one: path is in a root directory - dirPath[0] = filePath[0]; - dirPath[1] = '\0'; - } - else - { - // NOTE: Be careful, strncpy() is not safe, it does not care about '\0' - char *dirPathPtr = dirPath; - if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/')) dirPathPtr += 2; // Skip drive letter, "C:" - memcpy(dirPathPtr, filePath, strlen(filePath) - (strlen(lastSlash) - 1)); - dirPath[strlen(filePath) - strlen(lastSlash) + (((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/'))? 2 : 0)] = '\0'; // Add '\0' manually - } - } - - return dirPath; -} - -// Get previous directory path for a given path -const char *GetPrevDirectoryPath(const char *dirPath) -{ - static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 }; - memset(prevDirPath, 0, MAX_FILEPATH_LENGTH); - int pathLen = (int)strlen(dirPath); - - if (pathLen <= 3) strcpy(prevDirPath, dirPath); - - for (int i = (pathLen - 1); (i >= 0) && (pathLen > 3); i--) - { - if ((dirPath[i] == '\\') || (dirPath[i] == '/')) - { - // Check for root: "C:\" or "/" - if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++; - - strncpy(prevDirPath, dirPath, i); - break; - } - } - - return prevDirPath; -} - -// Get current working directory -const char *GetWorkingDirectory(void) -{ - static char currentDir[MAX_FILEPATH_LENGTH] = { 0 }; - memset(currentDir, 0, MAX_FILEPATH_LENGTH); - - char *path = GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1); - - return path; -} - -const char *GetApplicationDirectory(void) -{ - static char appDir[MAX_FILEPATH_LENGTH] = { 0 }; - memset(appDir, 0, MAX_FILEPATH_LENGTH); - -#if defined(_WIN32) - int len = 0; -#if defined(UNICODE) - unsigned short widePath[MAX_PATH]; - len = GetModuleFileNameW(NULL, widePath, MAX_PATH); - len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL); -#else - len = GetModuleFileNameA(NULL, appDir, MAX_PATH); -#endif - if (len > 0) - { - for (int i = len; i >= 0; --i) - { - if (appDir[i] == '\\') - { - appDir[i + 1] = '\0'; - break; - } - } - } - else - { - appDir[0] = '.'; - appDir[1] = '\\'; - } - -#elif defined(__linux__) - unsigned int size = sizeof(appDir); - ssize_t len = readlink("/proc/self/exe", appDir, size); - - if (len > 0) - { - for (int i = len; i >= 0; --i) - { - if (appDir[i] == '/') - { - appDir[i + 1] = '\0'; - break; - } - } - } - else - { - appDir[0] = '.'; - appDir[1] = '/'; - } -#elif defined(__APPLE__) - uint32_t size = sizeof(appDir); - - if (_NSGetExecutablePath(appDir, &size) == 0) - { - int len = strlen(appDir); - for (int i = len; i >= 0; --i) - { - if (appDir[i] == '/') - { - appDir[i + 1] = '\0'; - break; - } - } - } - else - { - appDir[0] = '.'; - appDir[1] = '/'; - } -#elif defined(__FreeBSD__) - size_t size = sizeof(appDir); - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; - - if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0) - { - int len = strlen(appDir); - for (int i = len; i >= 0; --i) - { - if (appDir[i] == '/') - { - appDir[i + 1] = '\0'; - break; - } - } - } - else - { - appDir[0] = '.'; - appDir[1] = '/'; - } - -#endif - - return appDir; -} - -// Load directory filepaths -// NOTE: Base path is prepended to the scanned filepaths -// WARNING: Directory is scanned twice, first time to get files count -// No recursive scanning is done! -FilePathList LoadDirectoryFiles(const char *dirPath) -{ - FilePathList files = { 0 }; - unsigned int fileCounter = 0; - - struct dirent *entity; - DIR *dir = opendir(dirPath); - - if (dir != NULL) // It's a directory - { - // SCAN 1: Count files - while ((entity = readdir(dir)) != NULL) - { - // NOTE: We skip '.' (current dir) and '..' (parent dir) filepaths - if ((strcmp(entity->d_name, ".") != 0) && (strcmp(entity->d_name, "..") != 0)) fileCounter++; - } - - // Memory allocation for dirFileCount - files.capacity = fileCounter; - files.paths = (char **)RL_MALLOC(files.capacity*sizeof(char *)); - for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char)); - - closedir(dir); - - // SCAN 2: Read filepaths - // NOTE: Directory paths are also registered - ScanDirectoryFiles(dirPath, &files, NULL); - - // Security check: read files.count should match fileCounter - if (files.count != files.capacity) TRACELOG(LOG_WARNING, "FILEIO: Read files count do not match capacity allocated"); - } - else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file... - - return files; -} - -// Load directory filepaths with extension filtering and recursive directory scan -// NOTE: On recursive loading we do not pre-scan for file count, we use MAX_FILEPATH_CAPACITY -FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs) -{ - FilePathList files = { 0 }; - - files.capacity = MAX_FILEPATH_CAPACITY; - files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *)); - for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - - // WARNING: basePath is always prepended to scanned paths - if (scanSubdirs) ScanDirectoryFilesRecursively(basePath, &files, filter); - else ScanDirectoryFiles(basePath, &files, filter); - - return files; -} - -// Unload directory filepaths -// WARNING: files.count is not reseted to 0 after unloading -void UnloadDirectoryFiles(FilePathList files) -{ - if (files.paths != NULL) - { - for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]); - - RL_FREE(files.paths); - } -} - -// Create directories (including full path requested), returns 0 on success -int MakeDirectory(const char *dirPath) -{ - if ((dirPath == NULL) || (dirPath[0] == '\0')) return 1; // Path is not valid - if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid) - - // Copy path string to avoid modifying original - int len = (int)strlen(dirPath) + 1; - char *pathcpy = (char *)RL_CALLOC(len, 1); - memcpy(pathcpy, dirPath, len); - - // Iterate over pathcpy, create each subdirectory as needed - for (int i = 0; (i < len) && (pathcpy[i] != '\0'); i++) - { - if (pathcpy[i] == ':') i++; - else - { - if ((pathcpy[i] == '\\') || (pathcpy[i] == '/')) - { - pathcpy[i] = '\0'; - if (!DirectoryExists(pathcpy)) MKDIR(pathcpy); - pathcpy[i] = '/'; - } - } - } - - // Create final directory - if (!DirectoryExists(pathcpy)) MKDIR(pathcpy); - - RL_FREE(pathcpy); - - return 0; -} - -// Change working directory, returns true on success -bool ChangeDirectory(const char *dir) -{ - bool result = CHDIR(dir); - - if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir); - else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dir); - - return (result == 0); -} - -// Check if a given path point to a file -bool IsPathFile(const char *path) -{ - struct stat result = { 0 }; - stat(path, &result); - - return S_ISREG(result.st_mode); -} - -// Check if fileName is valid for the platform/OS -bool IsFileNameValid(const char *fileName) -{ - bool valid = true; - - if ((fileName != NULL) && (fileName[0] != '\0')) - { - int length = (int)strlen(fileName); - bool allPeriods = true; - - for (int i = 0; i < length; i++) - { - // Check invalid characters - if ((fileName[i] == '<') || - (fileName[i] == '>') || - (fileName[i] == ':') || - (fileName[i] == '\"') || - (fileName[i] == '/') || - (fileName[i] == '\\') || - (fileName[i] == '|') || - (fileName[i] == '?') || - (fileName[i] == '*')) { valid = false; break; } - - // Check non-glyph characters - if ((unsigned char)fileName[i] < 32) { valid = false; break; } - - // TODO: Check trailing periods/spaces? - - // Check if filename is not all periods - if (fileName[i] != '.') allPeriods = false; - } - - if (allPeriods) valid = false; - -/* - if (valid) - { - // Check invalid DOS names - if (length >= 3) - { - if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'N')) || // CON - ((fileName[0] == 'P') && (fileName[1] == 'R') && (fileName[2] == 'N')) || // PRN - ((fileName[0] == 'A') && (fileName[1] == 'U') && (fileName[2] == 'X')) || // AUX - ((fileName[0] == 'N') && (fileName[1] == 'U') && (fileName[2] == 'L'))) valid = false; // NUL - } - - if (length >= 4) - { - if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'M') && ((fileName[3] >= '0') && (fileName[3] <= '9'))) || // COM0-9 - ((fileName[0] == 'L') && (fileName[1] == 'P') && (fileName[2] == 'T') && ((fileName[3] >= '0') && (fileName[3] <= '9')))) valid = false; // LPT0-9 - } - } -*/ - } - - return valid; -} - -// Check if a file has been dropped into window -bool IsFileDropped(void) -{ - bool result = false; - - if (CORE.Window.dropFileCount > 0) result = true; - - return result; -} - -// Load dropped filepaths -FilePathList LoadDroppedFiles(void) -{ - FilePathList files = { 0 }; - - files.count = CORE.Window.dropFileCount; - files.paths = CORE.Window.dropFilepaths; - - return files; -} - -// Unload dropped filepaths -void UnloadDroppedFiles(FilePathList files) -{ - // WARNING: files pointers are the same as internal ones - - if (files.count > 0) - { - for (unsigned int i = 0; i < files.count; i++) RL_FREE(files.paths[i]); - - RL_FREE(files.paths); - - CORE.Window.dropFileCount = 0; - CORE.Window.dropFilepaths = NULL; - } -} - -// Get file modification time (last write time) -long GetFileModTime(const char *fileName) -{ - struct stat result = { 0 }; - long modTime = 0; - - if (stat(fileName, &result) == 0) - { - time_t mod = result.st_mtime; - - modTime = (long)mod; - } - - return modTime; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Compression and Encoding -//---------------------------------------------------------------------------------- - -// Compress data (DEFLATE algorithm) -unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize) -{ - #define COMPRESSION_QUALITY_DEFLATE 8 - - unsigned char *compData = NULL; - -#if defined(SUPPORT_COMPRESSION_API) - // Compress data and generate a valid DEFLATE stream - struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB - int bounds = sdefl_bound(dataSize); - compData = (unsigned char *)RL_CALLOC(bounds, 1); - - *compDataSize = sdeflate(sdefl, compData, data, dataSize, COMPRESSION_QUALITY_DEFLATE); // Compression level 8, same as stbiw - RL_FREE(sdefl); - - TRACELOG(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize); -#endif - - return compData; -} - -// Decompress data (DEFLATE algorithm) -unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize) -{ - unsigned char *data = NULL; - -#if defined(SUPPORT_COMPRESSION_API) - // Decompress data from a valid DEFLATE stream - data = (unsigned char *)RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1); - int length = sinflate(data, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize); - - // WARNING: RL_REALLOC can make (and leave) data copies in memory, be careful with sensitive compressed data! - // TODO: Use a different approach, create another buffer, copy data manually to it and wipe original buffer memory - unsigned char *temp = (unsigned char *)RL_REALLOC(data, length); - - if (temp != NULL) data = temp; - else TRACELOG(LOG_WARNING, "SYSTEM: Failed to re-allocate required decompression memory"); - - *dataSize = length; - - TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, *dataSize); -#endif - - return data; -} - -// Encode data to Base64 string -// NOTE: Returned string includes NULL terminator, considered on outputSize -char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize) -{ - // Base64 conversion table from RFC 4648 [0..63] - // NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sixtets" (6bit characters) - static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - // Compute expected size and padding - int paddedSize = dataSize; - while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes - int estimatedOutputSize = 4*(paddedSize/3); - int padding = paddedSize - dataSize; - - // Adding null terminator to string - estimatedOutputSize += 1; - - // Load some memory to store encoded string - char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1); - if (encodedData == NULL) return NULL; - - int outputCount = 0; - for (int i = 0; i < dataSize;) - { - unsigned int octetA = 0; - unsigned int octetB = 0; - unsigned int octetC = 0; - unsigned int octetPack = 0; - - octetA = data[i]; // Generates 2 sextets - octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets - octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets - - octetPack = (octetA << 16) | (octetB << 8) | octetC; - - encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]); - encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]); - encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]); - encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]); - outputCount += 4; - i += 3; - } - - // Add required padding bytes - for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '='; - - // Add null terminator to string - encodedData[outputCount] = '\0'; - outputCount++; - - if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation"); - - *outputSize = estimatedOutputSize; - return encodedData; -} - -// Decode Base64 string (expected NULL terminated) -unsigned char *DecodeDataBase64(const char *text, int *outputSize) -{ - // Base64 decode table - // NOTE: Following ASCII order [0..255] assigning the expected sixtet value to - // every character in the corresponding ASCII position - static const unsigned char base64DecodeTable[256] = { - ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7, - ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, - ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, - ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, - ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41, - ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, - ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, - ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63 - }; - - // Compute expected size and padding - int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings! - int ending = dataSize - 1; - int padding = 0; - while (text[ending] == '=') { padding++; ending--; } - int estimatedOutputSize = 3*(dataSize/4) - padding; - int maxOutputSize = 3*(dataSize/4); - - // Load some memory to store decoded data - // NOTE: Allocated enough size to include padding - unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1); - if (decodedData == NULL) return NULL; - - int outputCount = 0; - for (int i = 0; i < dataSize;) - { - // Every 4 sixtets must generate 3 octets - unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]]; - unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]]; - unsigned int sixtetC = ((unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0; - unsigned int sixtetD = ((unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0; - - unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD; - - decodedData[outputCount + 0] = (octetPack >> 16) & 0xff; - decodedData[outputCount + 1] = (octetPack >> 8) & 0xff; - decodedData[outputCount + 2] = octetPack & 0xff; - outputCount += 3; - i += 4; - } - - if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation"); - - *outputSize = estimatedOutputSize; - return decodedData; -} - -// Compute CRC32 hash code -unsigned int ComputeCRC32(unsigned char *data, int dataSize) -{ - static unsigned int crcTable[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - - unsigned int crc = ~0u; - - for (int i = 0; i < dataSize; i++) crc = (crc >> 8) ^ crcTable[data[i] ^ (crc & 0xff)]; - - return ~crc; -} - -// Compute MD5 hash code -// NOTE: Returns a static int[4] array (16 bytes) -unsigned int *ComputeMD5(unsigned char *data, int dataSize) -{ - #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) - - static unsigned int hash[4] = { 0 }; // Hash to be returned - - // WARNING: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating - - // NOTE: r specifies the per-round shift amounts - unsigned int r[] = { - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 - }; - - // Using binary integer part of the sines of integers (in radians) as constants - unsigned int k[] = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - - hash[0] = 0x67452301; - hash[1] = 0xefcdab89; - hash[2] = 0x98badcfe; - hash[3] = 0x10325476; - - // Pre-processing: adding a single 1 bit - // Append '1' bit to message - // NOTE: The input bytes are considered as bits strings, - // where the first bit is the most significant bit of the byte - - // Pre-processing: padding with zeros - // Append '0' bit until message length in bit 448 (mod 512) - // Append length mod (2 pow 64) to message - - int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8; - - unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes - memcpy(msg, data, dataSize); - msg[dataSize] = 128; // Write the '1' bit - - unsigned int bitsLen = 8*dataSize; - memcpy(msg + newDataSize, &bitsLen, 4); // Append the len in bits at the end of the buffer - - // Process the message in successive 512-bit chunks for each 512-bit chunk of message - for (int offset = 0; offset < newDataSize; offset += (512/8)) - { - // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 - unsigned int *w = (unsigned int *)(msg + offset); - - // Initialize hash value for this chunk - unsigned int a = hash[0]; - unsigned int b = hash[1]; - unsigned int c = hash[2]; - unsigned int d = hash[3]; - - for (int i = 0; i < 64; i++) - { - unsigned int f = 0; - unsigned int g = 0; - - if (i < 16) - { - f = (b & c) | ((~b) & d); - g = i; - } - else if (i < 32) - { - f = (d & b) | ((~d) & c); - g = (5*i + 1)%16; - } - else if (i < 48) - { - f = b ^ c ^ d; - g = (3*i + 5)%16; - } - else - { - f = c ^ (b | (~d)); - g = (7*i)%16; - } - - unsigned int temp = d; - d = c; - c = b; - b = b + ROTATE_LEFT((a + f + k[i] + w[g]), r[i]); - a = temp; - } - - // Add chunk's hash to result so far - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; - } - - RL_FREE(msg); - - return hash; -} - -// Compute SHA-1 hash code -// NOTE: Returns a static int[5] array (20 bytes) -unsigned int *ComputeSHA1(unsigned char *data, int dataSize) -{ - #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) - - static unsigned int hash[5] = { 0 }; // Hash to be returned - - // Initialize hash values - hash[0] = 0x67452301; - hash[1] = 0xEFCDAB89; - hash[2] = 0x98BADCFE; - hash[3] = 0x10325476; - hash[4] = 0xC3D2E1F0; - - // Pre-processing: adding a single 1 bit - // Append '1' bit to message - // NOTE: The input bytes are considered as bits strings, - // where the first bit is the most significant bit of the byte - - // Pre-processing: padding with zeros - // Append '0' bit until message length in bit 448 (mod 512) - // Append length mod (2 pow 64) to message - - int newDataSize = ((((dataSize + 8)/64) + 1)*64); - - unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits - memcpy(msg, data, dataSize); - msg[dataSize] = 128; // Write the '1' bit - - unsigned int bitsLen = 8*dataSize; - msg[newDataSize-1] = bitsLen; - - // Process the message in successive 512-bit chunks - for (int offset = 0; offset < newDataSize; offset += (512/8)) - { - // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 - unsigned int w[80] = {0}; - for (int i = 0; i < 16; i++) - { - w[i] = (msg[offset + (i*4) + 0] << 24) | - (msg[offset + (i*4) + 1] << 16) | - (msg[offset + (i*4) + 2] << 8) | - (msg[offset + (i*4) + 3]); - } - - // Message schedule: extend the sixteen 32-bit words into eighty 32-bit words: - for (int i = 16; i < 80; i++) w[i] = ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1); - - // Initialize hash value for this chunk - unsigned int a = hash[0]; - unsigned int b = hash[1]; - unsigned int c = hash[2]; - unsigned int d = hash[3]; - unsigned int e = hash[4]; - - for (int i = 0; i < 80; i++) - { - unsigned int f = 0; - unsigned int k = 0; - - if (i < 20) - { - f = (b & c) | ((~b) & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - - unsigned int temp = ROTATE_LEFT(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = ROTATE_LEFT(b, 30); - b = a; - a = temp; - } - - // Add this chunk's hash to result so far - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; - hash[4] += e; - } - - free(msg); - - return hash; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Automation Events Recording and Playing -//---------------------------------------------------------------------------------- - -// Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS -AutomationEventList LoadAutomationEventList(const char *fileName) -{ - AutomationEventList list = { 0 }; - - // Allocate and empty automation event list, ready to record new events - list.events = (AutomationEvent *)RL_CALLOC(MAX_AUTOMATION_EVENTS, sizeof(AutomationEvent)); - list.capacity = MAX_AUTOMATION_EVENTS; - -#if defined(SUPPORT_AUTOMATION_EVENTS) - if (fileName == NULL) TRACELOG(LOG_INFO, "AUTOMATION: New empty events list loaded successfully"); - else - { - // Load automation events file (binary) - /* - //int dataSize = 0; - //unsigned char *data = LoadFileData(fileName, &dataSize); - - FILE *raeFile = fopen(fileName, "rb"); - unsigned char fileId[4] = { 0 }; - - fread(fileId, 1, 4, raeFile); - - if ((fileId[0] == 'r') && (fileId[1] == 'A') && (fileId[2] == 'E') && (fileId[1] == ' ')) - { - fread(&eventCount, sizeof(int), 1, raeFile); - TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount); - fread(events, sizeof(AutomationEvent), eventCount, raeFile); - } - - fclose(raeFile); - */ - - // Load events file (text) - //unsigned char *buffer = LoadFileText(fileName); - FILE *raeFile = fopen(fileName, "rt"); - - if (raeFile != NULL) - { - unsigned int counter = 0; - char buffer[256] = { 0 }; - char eventDesc[64] = { 0 }; - - fgets(buffer, 256, raeFile); - - while (!feof(raeFile)) - { - switch (buffer[0]) - { - case 'c': sscanf(buffer, "c %i", &list.count); break; - case 'e': - { - sscanf(buffer, "e %d %d %d %d %d %d %[^\n]s", &list.events[counter].frame, &list.events[counter].type, - &list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc); - - counter++; - } break; - default: break; - } - - fgets(buffer, 256, raeFile); - } - - if (counter != list.count) - { - TRACELOG(LOG_WARNING, "AUTOMATION: Events read from file [%i] do not mach event count specified [%i]", counter, list.count); - list.count = counter; - } - - fclose(raeFile); - - TRACELOG(LOG_INFO, "AUTOMATION: Events file loaded successfully"); - } - - TRACELOG(LOG_INFO, "AUTOMATION: Events loaded from file: %i", list.count); - } -#endif - return list; -} - -// Unload automation events list from file -void UnloadAutomationEventList(AutomationEventList list) -{ -#if defined(SUPPORT_AUTOMATION_EVENTS) - RL_FREE(list.events); -#endif -} - -// Export automation events list as text file -bool ExportAutomationEventList(AutomationEventList list, const char *fileName) -{ - bool success = false; - -#if defined(SUPPORT_AUTOMATION_EVENTS) - // Export events as binary file - // TODO: Save to memory buffer and SaveFileData() - /* - unsigned char fileId[4] = "rAE "; - FILE *raeFile = fopen(fileName, "wb"); - fwrite(fileId, sizeof(unsigned char), 4, raeFile); - fwrite(&eventCount, sizeof(int), 1, raeFile); - fwrite(events, sizeof(AutomationEvent), eventCount, raeFile); - fclose(raeFile); - */ - - // Export events as text - // TODO: Save to memory buffer and SaveFileText() - char *txtData = (char *)RL_CALLOC(256*list.count + 2048, sizeof(char)); // 256 characters per line plus some header - - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "#\n"); - byteCount += sprintf(txtData + byteCount, "# Automation events exporter v1.0 - raylib automation events list\n"); - byteCount += sprintf(txtData + byteCount, "#\n"); - byteCount += sprintf(txtData + byteCount, "# c \n"); - byteCount += sprintf(txtData + byteCount, "# e // \n"); - byteCount += sprintf(txtData + byteCount, "#\n"); - byteCount += sprintf(txtData + byteCount, "# more info and bugs-report: github.com/raysan5/raylib\n"); - byteCount += sprintf(txtData + byteCount, "# feedback and support: ray[at]raylib.com\n"); - byteCount += sprintf(txtData + byteCount, "#\n"); - byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)\n"); - byteCount += sprintf(txtData + byteCount, "#\n\n"); - - // Add events data - byteCount += sprintf(txtData + byteCount, "c %i\n", list.count); - for (unsigned int i = 0; i < list.count; i++) - { - byteCount += snprintf(txtData + byteCount, 256, "e %i %i %i %i %i %i // Event: %s\n", list.events[i].frame, list.events[i].type, - list.events[i].params[0], list.events[i].params[1], list.events[i].params[2], list.events[i].params[3], autoEventTypeName[list.events[i].type]); - } - - // NOTE: Text data size exported is determined by '\0' (NULL) character - success = SaveFileText(fileName, txtData); - - RL_FREE(txtData); -#endif - - return success; -} - -// Setup automation event list to record to -void SetAutomationEventList(AutomationEventList *list) -{ -#if defined(SUPPORT_AUTOMATION_EVENTS) - currentEventList = list; -#endif -} - -// Set automation event internal base frame to start recording -void SetAutomationEventBaseFrame(int frame) -{ - CORE.Time.frameCounter = frame; -} - -// Start recording automation events (AutomationEventList must be set) -void StartAutomationEventRecording(void) -{ -#if defined(SUPPORT_AUTOMATION_EVENTS) - automationEventRecording = true; -#endif -} - -// Stop recording automation events -void StopAutomationEventRecording(void) -{ -#if defined(SUPPORT_AUTOMATION_EVENTS) - automationEventRecording = false; -#endif -} - -// Play a recorded automation event -void PlayAutomationEvent(AutomationEvent event) -{ -#if defined(SUPPORT_AUTOMATION_EVENTS) - // WARNING: When should event be played? After/before/replace PollInputEvents()? -> Up to the user! - - if (!automationEventRecording) // TODO: Allow recording events while playing? - { - switch (event.type) - { - // Input event - case INPUT_KEY_UP: CORE.Input.Keyboard.currentKeyState[event.params[0]] = false; break; // param[0]: key - case INPUT_KEY_DOWN: { // param[0]: key - CORE.Input.Keyboard.currentKeyState[event.params[0]] = true; - - if (CORE.Input.Keyboard.previousKeyState[event.params[0]] == false) - { - if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) - { - // Add character to the queue - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = event.params[0]; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - } - } break; - case INPUT_MOUSE_BUTTON_UP: CORE.Input.Mouse.currentButtonState[event.params[0]] = false; break; // param[0]: key - case INPUT_MOUSE_BUTTON_DOWN: CORE.Input.Mouse.currentButtonState[event.params[0]] = true; break; // param[0]: key - case INPUT_MOUSE_POSITION: // param[0]: x, param[1]: y - { - CORE.Input.Mouse.currentPosition.x = (float)event.params[0]; - CORE.Input.Mouse.currentPosition.y = (float)event.params[1]; - } break; - case INPUT_MOUSE_WHEEL_MOTION: // param[0]: x delta, param[1]: y delta - { - CORE.Input.Mouse.currentWheelMove.x = (float)event.params[0]; - CORE.Input.Mouse.currentWheelMove.y = (float)event.params[1]; - } break; - case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[event.params[0]] = false; break; // param[0]: id - case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[event.params[0]] = true; break; // param[0]: id - case INPUT_TOUCH_POSITION: // param[0]: id, param[1]: x, param[2]: y - { - CORE.Input.Touch.position[event.params[0]].x = (float)event.params[1]; - CORE.Input.Touch.position[event.params[0]].y = (float)event.params[2]; - } break; - case INPUT_GAMEPAD_CONNECT: CORE.Input.Gamepad.ready[event.params[0]] = true; break; // param[0]: gamepad - case INPUT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[event.params[0]] = false; break; // param[0]: gamepad - case INPUT_GAMEPAD_BUTTON_UP: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = false; break; // param[0]: gamepad, param[1]: button - case INPUT_GAMEPAD_BUTTON_DOWN: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = true; break; // param[0]: gamepad, param[1]: button - case INPUT_GAMEPAD_AXIS_MOTION: // param[0]: gamepad, param[1]: axis, param[2]: delta - { - CORE.Input.Gamepad.axisState[event.params[0]][event.params[1]] = ((float)event.params[2]/32768.0f); - } break; - #if defined(SUPPORT_GESTURES_SYSTEM) - case INPUT_GESTURE: GESTURES.current = event.params[0]; break; // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current - #endif - // Window event - case WINDOW_CLOSE: CORE.Window.shouldClose = true; break; - case WINDOW_MAXIMIZE: MaximizeWindow(); break; - case WINDOW_MINIMIZE: MinimizeWindow(); break; - case WINDOW_RESIZE: SetWindowSize(event.params[0], event.params[1]); break; - - // Custom event - #if defined(SUPPORT_SCREEN_CAPTURE) - case ACTION_TAKE_SCREENSHOT: - { - TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); - screenshotCounter++; - } break; - #endif - case ACTION_SETTARGETFPS: SetTargetFPS(event.params[0]); break; - default: break; - } - - TRACELOG(LOG_INFO, "AUTOMATION PLAY: Frame: %i | Event type: %i | Event parameters: %i, %i, %i", event.frame, event.type, event.params[0], event.params[1], event.params[2]); - } -#endif -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Input Handling: Keyboard -//---------------------------------------------------------------------------------- - -// Check if a key has been pressed once -bool IsKeyPressed(int key) -{ - - bool pressed = false; - - if ((key > 0) && (key < MAX_KEYBOARD_KEYS)) - { - if ((CORE.Input.Keyboard.previousKeyState[key] == 0) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true; - } - - return pressed; -} - -// Check if a key has been pressed again -bool IsKeyPressedRepeat(int key) -{ - bool repeat = false; - - if ((key > 0) && (key < MAX_KEYBOARD_KEYS)) - { - if (CORE.Input.Keyboard.keyRepeatInFrame[key] == 1) repeat = true; - } - - return repeat; -} - -// Check if a key is being pressed (key held down) -bool IsKeyDown(int key) -{ - bool down = false; - - if ((key > 0) && (key < MAX_KEYBOARD_KEYS)) - { - if (CORE.Input.Keyboard.currentKeyState[key] == 1) down = true; - } - - return down; -} - -// Check if a key has been released once -bool IsKeyReleased(int key) -{ - bool released = false; - - if ((key > 0) && (key < MAX_KEYBOARD_KEYS)) - { - if ((CORE.Input.Keyboard.previousKeyState[key] == 1) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true; - } - - return released; -} - -// Check if a key is NOT being pressed (key not held down) -bool IsKeyUp(int key) -{ - bool up = false; - - if ((key > 0) && (key < MAX_KEYBOARD_KEYS)) - { - if (CORE.Input.Keyboard.currentKeyState[key] == 0) up = true; - } - - return up; -} - -// Get the last key pressed -int GetKeyPressed(void) -{ - int value = 0; - - if (CORE.Input.Keyboard.keyPressedQueueCount > 0) - { - // Get character from the queue head - value = CORE.Input.Keyboard.keyPressedQueue[0]; - - // Shift elements 1 step toward the head - for (int i = 0; i < (CORE.Input.Keyboard.keyPressedQueueCount - 1); i++) - CORE.Input.Keyboard.keyPressedQueue[i] = CORE.Input.Keyboard.keyPressedQueue[i + 1]; - - // Reset last character in the queue - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount - 1] = 0; - CORE.Input.Keyboard.keyPressedQueueCount--; - } - - return value; -} - -// Get the last char pressed -int GetCharPressed(void) -{ - int value = 0; - - if (CORE.Input.Keyboard.charPressedQueueCount > 0) - { - // Get character from the queue head - value = CORE.Input.Keyboard.charPressedQueue[0]; - - // Shift elements 1 step toward the head - for (int i = 0; i < (CORE.Input.Keyboard.charPressedQueueCount - 1); i++) - CORE.Input.Keyboard.charPressedQueue[i] = CORE.Input.Keyboard.charPressedQueue[i + 1]; - - // Reset last character in the queue - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount - 1] = 0; - CORE.Input.Keyboard.charPressedQueueCount--; - } - - return value; -} - -// Set a custom key to exit program -// NOTE: default exitKey is set to ESCAPE -void SetExitKey(int key) -{ - CORE.Input.Keyboard.exitKey = key; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Input Handling: Gamepad -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//int SetGamepadMappings(const char *mappings) - -// Check if a gamepad is available -bool IsGamepadAvailable(int gamepad) -{ - bool result = false; - - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true; - - return result; -} - -// Get gamepad internal name id -const char *GetGamepadName(int gamepad) -{ - return CORE.Input.Gamepad.name[gamepad]; -} - -// Check if a gamepad button has been pressed once -bool IsGamepadButtonPressed(int gamepad, int button) -{ - bool pressed = false; - - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true; - - return pressed; -} - -// Check if a gamepad button is being pressed -bool IsGamepadButtonDown(int gamepad, int button) -{ - bool down = false; - - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) down = true; - - return down; -} - -// Check if a gamepad button has NOT been pressed once -bool IsGamepadButtonReleased(int gamepad, int button) -{ - bool released = false; - - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true; - - return released; -} - -// Check if a gamepad button is NOT being pressed -bool IsGamepadButtonUp(int gamepad, int button) -{ - bool up = false; - - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) up = true; - - return up; -} - -// Get the last gamepad button pressed -int GetGamepadButtonPressed(void) -{ - return CORE.Input.Gamepad.lastButtonPressed; -} - -// Get gamepad axis count -int GetGamepadAxisCount(int gamepad) -{ - return CORE.Input.Gamepad.axisCount[gamepad]; -} - -// Get axis movement vector for a gamepad -float GetGamepadAxisMovement(int gamepad, int axis) -{ - float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f; - - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES)) - { - float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]); - - if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis]; - } - - return value; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Input Handling: Mouse -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//void SetMousePosition(int x, int y) -//void SetMouseCursor(int cursor) - -// Check if a mouse button has been pressed once -bool IsMouseButtonPressed(int button) -{ - bool pressed = false; - - if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true; - - // Map touches to mouse buttons checking - if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true; - - return pressed; -} - -// Check if a mouse button is being pressed -bool IsMouseButtonDown(int button) -{ - bool down = false; - - if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true; - - // NOTE: Touches are considered like mouse buttons - if (CORE.Input.Touch.currentTouchState[button] == 1) down = true; - - return down; -} - -// Check if a mouse button has been released once -bool IsMouseButtonReleased(int button) -{ - bool released = false; - - if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true; - - // Map touches to mouse buttons checking - if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true; - - return released; -} - -// Check if a mouse button is NOT being pressed -bool IsMouseButtonUp(int button) -{ - bool up = false; - - if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true; - - // NOTE: Touches are considered like mouse buttons - if (CORE.Input.Touch.currentTouchState[button] == 0) up = true; - - return up; -} - -// Get mouse position X -int GetMouseX(void) -{ - int mouseX = (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x); - return mouseX; -} - -// Get mouse position Y -int GetMouseY(void) -{ - int mouseY = (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y); - return mouseY; -} - -// Get mouse position XY -Vector2 GetMousePosition(void) -{ - Vector2 position = { 0 }; - - position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x; - position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y; - - return position; -} - -// Get mouse delta between frames -Vector2 GetMouseDelta(void) -{ - Vector2 delta = { 0 }; - - delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x; - delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y; - - return delta; -} - -// Set mouse offset -// NOTE: Useful when rendering to different size targets -void SetMouseOffset(int offsetX, int offsetY) -{ - CORE.Input.Mouse.offset = (Vector2){ (float)offsetX, (float)offsetY }; -} - -// Set mouse scaling -// NOTE: Useful when rendering to different size targets -void SetMouseScale(float scaleX, float scaleY) -{ - CORE.Input.Mouse.scale = (Vector2){ scaleX, scaleY }; -} - -// Get mouse wheel movement Y -float GetMouseWheelMove(void) -{ - float result = 0.0f; - - if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x; - else result = (float)CORE.Input.Mouse.currentWheelMove.y; - - return result; -} - -// Get mouse wheel movement X/Y as a vector -Vector2 GetMouseWheelMoveV(void) -{ - Vector2 result = { 0 }; - - result = CORE.Input.Mouse.currentWheelMove; - - return result; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition: Input Handling: Touch -//---------------------------------------------------------------------------------- - -// Get touch position X for touch point 0 (relative to screen size) -int GetTouchX(void) -{ - int touchX = (int)CORE.Input.Touch.position[0].x; - return touchX; -} - -// Get touch position Y for touch point 0 (relative to screen size) -int GetTouchY(void) -{ - int touchY = (int)CORE.Input.Touch.position[0].y; - return touchY; -} - -// Get touch position XY for a touch point index (relative to screen size) -// TODO: Touch position should be scaled depending on display size and render size -Vector2 GetTouchPosition(int index) -{ - Vector2 position = { -1.0f, -1.0f }; - - if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index]; - else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); - - return position; -} - -// Get touch point identifier for given index -int GetTouchPointId(int index) -{ - int id = -1; - - if (index < MAX_TOUCH_POINTS) id = CORE.Input.Touch.pointId[index]; - - return id; -} - -// Get number of touch points -int GetTouchPointCount(void) -{ - return CORE.Input.Touch.pointCount; -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- - -// NOTE: Functions with a platform-specific implementation on rcore_.c -//int InitPlatform(void) -//void ClosePlatform(void) - -// Initialize hi-resolution timer -void InitTimer(void) -{ - // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions - // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often - // High resolutions can also prevent the CPU power management system from entering power-saving modes - // Setting a higher resolution does not improve the accuracy of the high-resolution performance counter -#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_DESKTOP_SDL) - timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms) -#endif - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) - struct timespec now = { 0 }; - - if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success - { - CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; - } - else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available"); -#endif - - CORE.Time.previous = GetTime(); // Get time as double -} - -// Set viewport for a provided width and height -void SetupViewport(int width, int height) -{ - CORE.Window.render.width = width; - CORE.Window.render.height = height; - - // Set viewport width and height - // NOTE: We consider render size (scaled) and offset in case black bars are required and - // render area does not match full display area (this situation is only applicable on fullscreen mode) -#if defined(__APPLE__) - Vector2 scale = GetWindowScaleDPI(); - rlViewport(CORE.Window.renderOffset.x/2*scale.x, CORE.Window.renderOffset.y/2*scale.y, (CORE.Window.render.width)*scale.x, (CORE.Window.render.height)*scale.y); -#else - rlViewport(CORE.Window.renderOffset.x/2, CORE.Window.renderOffset.y/2, CORE.Window.render.width, CORE.Window.render.height); -#endif - - rlMatrixMode(RL_PROJECTION); // Switch to projection matrix - rlLoadIdentity(); // Reset current matrix (projection) - - // Set orthographic projection to current framebuffer size - // NOTE: Configured top-left corner as (0, 0) - rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, 0.0f, 1.0f); - - rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix - rlLoadIdentity(); // Reset current matrix (modelview) -} - -// Compute framebuffer size relative to screen size and display size -// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified -void SetupFramebuffer(int width, int height) -{ - // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var) - if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height); - - // Downscaling to fit display with border-bars - float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width; - float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height; - - if (widthRatio <= heightRatio) - { - CORE.Window.render.width = CORE.Window.display.width; - CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio); - CORE.Window.renderOffset.x = 0; - CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height); - } - else - { - CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio); - CORE.Window.render.height = CORE.Window.display.height; - CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width); - CORE.Window.renderOffset.y = 0; - } - - // Screen scaling required - float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width; - CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f); - - // NOTE: We render to full display resolution! - // We just need to calculate above parameters for downscale matrix and offsets - CORE.Window.render.width = CORE.Window.display.width; - CORE.Window.render.height = CORE.Window.display.height; - - TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height); - } - else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height)) - { - // Required screen size is smaller than display size - TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height); - - if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0)) - { - CORE.Window.screen.width = CORE.Window.display.width; - CORE.Window.screen.height = CORE.Window.display.height; - } - - // Upscaling to fit display with border-bars - float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height; - float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height; - - if (displayRatio <= screenRatio) - { - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio); - CORE.Window.renderOffset.x = 0; - CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height); - } - else - { - CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio); - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width); - CORE.Window.renderOffset.y = 0; - } - } - else - { - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - CORE.Window.renderOffset.x = 0; - CORE.Window.renderOffset.y = 0; - } -} - -// Scan all files and directories in a base path -// WARNING: files.paths[] must be previously allocated and -// contain enough space to store all required paths -static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter) -{ - static char path[MAX_FILEPATH_LENGTH] = { 0 }; - memset(path, 0, MAX_FILEPATH_LENGTH); - - struct dirent *dp = NULL; - DIR *dir = opendir(basePath); - - if (dir != NULL) - { - while ((dp = readdir(dir)) != NULL) - { - if ((strcmp(dp->d_name, ".") != 0) && - (strcmp(dp->d_name, "..") != 0)) - { - #if defined(_WIN32) - int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name); - #else - int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name); - #endif - - if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH)) - { - TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath); - } - else if (filter != NULL) - { - if (IsPathFile(path)) - { - if (IsFileExtension(path, filter)) - { - strcpy(files->paths[files->count], path); - files->count++; - } - } - else - { - if (strstr(filter, DIRECTORY_FILTER_TAG) != NULL) - { - strcpy(files->paths[files->count], path); - files->count++; - } - } - } - else - { - strcpy(files->paths[files->count], path); - files->count++; - } - } - } - - closedir(dir); - } - else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); -} - -// Scan all files and directories recursively from a base path -static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter) -{ - static char path[MAX_FILEPATH_LENGTH] = { 0 }; - memset(path, 0, MAX_FILEPATH_LENGTH); - - struct dirent *dp = NULL; - DIR *dir = opendir(basePath); - - if (dir != NULL) - { - while (((dp = readdir(dir)) != NULL) && (files->count < files->capacity)) - { - if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0)) - { - // Construct new path from our base path - #if defined(_WIN32) - int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name); - #else - int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name); - #endif - - if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH)) - { - TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath); - } - else if (IsPathFile(path)) - { - if (filter != NULL) - { - if (IsFileExtension(path, filter)) - { - strcpy(files->paths[files->count], path); - files->count++; - } - } - else - { - strcpy(files->paths[files->count], path); - files->count++; - } - - if (files->count >= files->capacity) - { - TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity); - break; - } - } - else - { - if ((filter != NULL) && (strstr(filter, DIRECTORY_FILTER_TAG) != NULL)) - { - strcpy(files->paths[files->count], path); - files->count++; - } - - if (files->count >= files->capacity) - { - TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity); - break; - } - - ScanDirectoryFilesRecursively(path, files, filter); - } - } - } - - closedir(dir); - } - else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); -} - -#if defined(SUPPORT_AUTOMATION_EVENTS) -// Automation event recording -// NOTE: Recording is by default done at EndDrawing(), before PollInputEvents() -static void RecordAutomationEvent(void) -{ - // Checking events in current frame and save them into currentEventList - // TODO: How important is the current frame? Could it be modified? - - if (currentEventList->count == currentEventList->capacity) return; // Security check - - // Keyboard input events recording - //------------------------------------------------------------------------------------- - for (int key = 0; key < MAX_KEYBOARD_KEYS; key++) - { - // Event type: INPUT_KEY_UP (only saved once) - if (CORE.Input.Keyboard.previousKeyState[key] && !CORE.Input.Keyboard.currentKeyState[key]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_KEY_UP; - currentEventList->events[currentEventList->count].params[0] = key; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - - // Event type: INPUT_KEY_DOWN - if (CORE.Input.Keyboard.currentKeyState[key]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_KEY_DOWN; - currentEventList->events[currentEventList->count].params[0] = key; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - //------------------------------------------------------------------------------------- - - // Mouse input currentEventList->events recording - //------------------------------------------------------------------------------------- - for (int button = 0; button < MAX_MOUSE_BUTTONS; button++) - { - // Event type: INPUT_MOUSE_BUTTON_UP - if (CORE.Input.Mouse.previousButtonState[button] && !CORE.Input.Mouse.currentButtonState[button]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_UP; - currentEventList->events[currentEventList->count].params[0] = button; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - - // Event type: INPUT_MOUSE_BUTTON_DOWN - if (CORE.Input.Mouse.currentButtonState[button]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_DOWN; - currentEventList->events[currentEventList->count].params[0] = button; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - - // Event type: INPUT_MOUSE_POSITION (only saved if changed) - if (((int)CORE.Input.Mouse.currentPosition.x != (int)CORE.Input.Mouse.previousPosition.x) || - ((int)CORE.Input.Mouse.currentPosition.y != (int)CORE.Input.Mouse.previousPosition.y)) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_MOUSE_POSITION; - currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentPosition.x; - currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentPosition.y; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - - // Event type: INPUT_MOUSE_WHEEL_MOTION - if (((int)CORE.Input.Mouse.currentWheelMove.x != (int)CORE.Input.Mouse.previousWheelMove.x) || - ((int)CORE.Input.Mouse.currentWheelMove.y != (int)CORE.Input.Mouse.previousWheelMove.y)) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_MOUSE_WHEEL_MOTION; - currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x; - currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_WHEEL_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - //------------------------------------------------------------------------------------- - - // Touch input currentEventList->events recording - //------------------------------------------------------------------------------------- - for (int id = 0; id < MAX_TOUCH_POINTS; id++) - { - // Event type: INPUT_TOUCH_UP - if (CORE.Input.Touch.previousTouchState[id] && !CORE.Input.Touch.currentTouchState[id]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_TOUCH_UP; - currentEventList->events[currentEventList->count].params[0] = id; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - - // Event type: INPUT_TOUCH_DOWN - if (CORE.Input.Touch.currentTouchState[id]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_TOUCH_DOWN; - currentEventList->events[currentEventList->count].params[0] = id; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - - // Event type: INPUT_TOUCH_POSITION - // TODO: It requires the id! - /* - if (((int)CORE.Input.Touch.currentPosition[id].x != (int)CORE.Input.Touch.previousPosition[id].x) || - ((int)CORE.Input.Touch.currentPosition[id].y != (int)CORE.Input.Touch.previousPosition[id].y)) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_TOUCH_POSITION; - currentEventList->events[currentEventList->count].params[0] = id; - currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Touch.currentPosition[id].x; - currentEventList->events[currentEventList->count].params[2] = (int)CORE.Input.Touch.currentPosition[id].y; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - */ - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - //------------------------------------------------------------------------------------- - - // Gamepad input currentEventList->events recording - //------------------------------------------------------------------------------------- - for (int gamepad = 0; gamepad < MAX_GAMEPADS; gamepad++) - { - // Event type: INPUT_GAMEPAD_CONNECT - /* - if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) && - (CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to ready - { - // TODO: Save gamepad connect event - } - */ - - // Event type: INPUT_GAMEPAD_DISCONNECT - /* - if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) && - (!CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to not-ready - { - // TODO: Save gamepad disconnect event - } - */ - - for (int button = 0; button < MAX_GAMEPAD_BUTTONS; button++) - { - // Event type: INPUT_GAMEPAD_BUTTON_UP - if (CORE.Input.Gamepad.previousButtonState[gamepad][button] && !CORE.Input.Gamepad.currentButtonState[gamepad][button]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_UP; - currentEventList->events[currentEventList->count].params[0] = gamepad; - currentEventList->events[currentEventList->count].params[1] = button; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - - // Event type: INPUT_GAMEPAD_BUTTON_DOWN - if (CORE.Input.Gamepad.currentButtonState[gamepad][button]) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_DOWN; - currentEventList->events[currentEventList->count].params[0] = gamepad; - currentEventList->events[currentEventList->count].params[1] = button; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - - for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++) - { - // Event type: INPUT_GAMEPAD_AXIS_MOTION - float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f; - if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement) - { - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_AXIS_MOTION; - currentEventList->events[currentEventList->count].params[0] = gamepad; - currentEventList->events[currentEventList->count].params[1] = axis; - currentEventList->events[currentEventList->count].params[2] = (int)(CORE.Input.Gamepad.axisState[gamepad][axis]*32768.0f); - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_AXIS_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - } - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - } - //------------------------------------------------------------------------------------- - -#if defined(SUPPORT_GESTURES_SYSTEM) - // Gestures input currentEventList->events recording - //------------------------------------------------------------------------------------- - if (GESTURES.current != GESTURE_NONE) - { - // Event type: INPUT_GESTURE - currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; - currentEventList->events[currentEventList->count].type = INPUT_GESTURE; - currentEventList->events[currentEventList->count].params[0] = GESTURES.current; - currentEventList->events[currentEventList->count].params[1] = 0; - currentEventList->events[currentEventList->count].params[2] = 0; - - TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GESTURE | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]); - currentEventList->count++; - - if (currentEventList->count == currentEventList->capacity) return; // Security check - } - //------------------------------------------------------------------------------------- -#endif -} -#endif - -#if !defined(SUPPORT_MODULE_RTEXT) -// Formatting of text with variables to 'embed' -// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times -const char *TextFormat(const char *text, ...) -{ -#ifndef MAX_TEXTFORMAT_BUFFERS - #define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting -#endif -#ifndef MAX_TEXT_BUFFER_LENGTH - #define MAX_TEXT_BUFFER_LENGTH 1024 // Maximum size of static text buffer -#endif - - // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations - static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 }; - static int index = 0; - - char *currentBuffer = buffers[index]; - memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using - - va_list args; - va_start(args, text); - int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); - va_end(args); - - // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured - if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) - { - // Inserting "..." at the end of the string to mark as truncated - char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" - sprintf(truncBuffer, "..."); - } - - index += 1; // Move to next buffer for next function call - if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; - - return currentBuffer; -} - -#endif // !SUPPORT_MODULE_RTEXT diff --git a/raylib/rlgl.go b/raylib/rlgl.go index cc24f30..716367a 100644 --- a/raylib/rlgl.go +++ b/raylib/rlgl.go @@ -1,177 +1,160 @@ package rl -const ( - // Texture parameters (equivalent to OpenGL defines) - TextureWrapS = 0x2802 // GL_TEXTURE_WRAP_S - TextureWrapT = 0x2803 // GL_TEXTURE_WRAP_T - TextureMagFilter = 0x2800 // GL_TEXTURE_MAG_FILTER - TextureMinFilter = 0x2801 // GL_TEXTURE_MIN_FILTER +/* +#include "raylib.h" +#include "rlgl.h" +#include +*/ +import "C" +import "unsafe" +import "reflect" - TextureFilterNearest = 0x2600 // GL_NEAREST - TextureFilterLinear = 0x2601 // GL_LINEAR - TextureFilterMipNearest = 0x2700 // GL_NEAREST_MIPMAP_NEAREST - TextureFilterNearestMipLinear = 0x2702 // GL_NEAREST_MIPMAP_LINEAR - TextureFilterLinearMipNearest = 0x2701 // GL_LINEAR_MIPMAP_NEAREST - TextureFilterMipLinear = 0x2703 // GL_LINEAR_MIPMAP_LINEAR - TextureFilterAnisotropic = 0x3000 // Anisotropic filter (custom identifier) - TextureMipmapBiasRatio = 0x4000 // Texture mipmap bias, percentage ratio (custom identifier) - - TextureWrapRepeat = 0x2901 // GL_REPEAT - TextureWrapClamp = 0x812F // GL_CLAMP_TO_EDGE - TextureWrapMirrorRepeat = 0x8370 // GL_MIRRORED_REPEAT - TextureWrapMirrorClamp = 0x8742 // GL_MIRROR_CLAMP_EXT - - // Matrix modes (equivalent to OpenGL) - Modelview = 0x1700 // GL_MODELVIEW - Projection = 0x1701 // GL_PROJECTION - Texture = 0x1702 // GL_TEXTURE - - // Primitive assembly draw modes - Lines = 0x0001 // GL_LINES - Triangles = 0x0004 // GL_TRIANGLES - Quads = 0x0007 // GL_QUADS - - // GL equivalent data types - UnsignedByte = 0x1401 // GL_UNSIGNED_BYTE - Float = 0x1406 // GL_FLOAT - - // Buffer usage hint - StreamDraw = 0x88E0 // GL_STREAM_DRAW - StreamRead = 0x88E1 // GL_STREAM_READ - StreamCopy = 0x88E2 // GL_STREAM_COPY - StaticDraw = 0x88E4 // GL_STATIC_DRAW - StaticRead = 0x88E5 // GL_STATIC_READ - StaticCopy = 0x88E6 // GL_STATIC_COPY - DynamicDraw = 0x88E8 // GL_DYNAMIC_DRAW - DynamicRead = 0x88E9 // GL_DYNAMIC_READ - DynamicCopy = 0x88EA // GL_DYNAMIC_COPY - - // GL Shader type - FragmentShader = 0x8B30 // GL_FRAGMENT_SHADER - VertexShader = 0x8B31 // GL_VERTEX_SHADER - ComputeShader = 0x91B9 // GL_COMPUTE_SHADER - - // GL blending factors - Zero = 0 // GL_ZERO - One = 1 // GL_ONE - SrcColor = 0x0300 // GL_SRC_COLOR - OneMinusSrcColor = 0x0301 // GL_ONE_MINUS_SRC_COLOR - SrcAlpha = 0x0302 // GL_SRC_ALPHA - OneMinusSrcAlpha = 0x0303 // GL_ONE_MINUS_SRC_ALPHA - DstAlpha = 0x0304 // GL_DST_ALPHA - OneMinusDstAlpha = 0x0305 // GL_ONE_MINUS_DST_ALPHA - DstColor = 0x0306 // GL_DST_COLOR - OneMinusDstColor = 0x0307 // GL_ONE_MINUS_DST_COLOR - SrcAlphaSaturate = 0x0308 // GL_SRC_ALPHA_SATURATE - ConstantColor = 0x8001 // GL_CONSTANT_COLOR - OneMinusConstantColor = 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR - ConstantAlpha = 0x8003 // GL_CONSTANT_ALPHA - OneMinusConstantAlpha = 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA - - // GL blending functions/equations - FuncAdd = 0x8006 // GL_FUNC_ADD - Min = 0x8007 // GL_MIN - Max = 0x8008 // GL_MAX - FuncSubtract = 0x800A // GL_FUNC_SUBTRACT - FuncReverseSubtract = 0x800B // GL_FUNC_REVERSE_SUBTRACT - BlendEquation = 0x8009 // GL_BLEND_EQUATION - BlendEquationRgb = BlendEquation // GL_BLEND_EQUATION_RGB (Same as BLEND_EQUATION) - BlendEquationAlpha = 0x883D // GL_BLEND_EQUATION_ALPHA - BlendDstRgb = 0x80C8 // GL_BLEND_DST_RGB - BlendSrcRgb = 0x80C9 // GL_BLEND_SRC_RGB - BlendDstAlpha = 0x80CA // GL_BLEND_DST_ALPHA - BlendSrcAlpha = 0x80CB // GL_BLEND_SRC_ALPHA - BlendColor = 0x8005 // GL_BLEND_COLOR - - ReadFramebuffer = 0x8CA8 // GL_READ_FRAMEBUFFER - DrawFramebuffer = 0x8CA9 // GL_DRAW_FRAMEBUFFER -) - -// VertexBuffer - Dynamic vertex buffers (position + texcoords + colors + indices arrays) -type VertexBuffer struct { - ElementCount int32 // Number of elements in the buffer (QUADS) - Vertices *float32 // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) - Texcoords *float32 // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - Normals *float32 // Vertex normal (XYZ - 3 components per vertex) (shader-location = 2) - Colors *uint8 // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - Indices *uint32 // Vertex indices (in case vertex data comes indexed) (6 indices per quad) - VaoId uint32 // OpenGL Vertex Array Object id - VboId [5]uint32 // OpenGL Vertex Buffer Objects id (5 types of vertex data) +// cptr returns C pointer +func (s *Shader) cptr() *C.Shader { + return (*C.Shader)(unsafe.Pointer(s)) } -// DrawCall - Draw call type -// NOTE: Only texture changes register a new draw, other state-change-related elements are not -// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any -// of those state-change happens (this is done in core module) -type DrawCall struct { - Mode int32 - VertexCount int32 - VertexAlignment int32 - TextureId uint32 +// LoadShader - Load a custom shader and bind default locations +func LoadShader(vsFileName string, fsFileName string) Shader { + cvsFileName := C.CString(vsFileName) + defer C.free(unsafe.Pointer(cvsFileName)) + + cfsFileName := C.CString(fsFileName) + defer C.free(unsafe.Pointer(cfsFileName)) + + var v Shader + if vsFileName == "" { + ret := C.LoadShader(nil, cfsFileName) + v = newShaderFromPointer(unsafe.Pointer(&ret)) + } else { + ret := C.LoadShader(cvsFileName, cfsFileName) + v = newShaderFromPointer(unsafe.Pointer(&ret)) + } + + return v } -// RenderBatch type -type RenderBatch struct { - BufferCount int32 - CurrentBuffer int32 - VertexBuffer *VertexBuffer - Draws *DrawCall - DrawCounter int32 - DurrentDepth float32 +// LoadShaderFromMemory - Load shader from code strings and bind default locations +func LoadShaderFromMemory(vsCode string, fsCode string) Shader { + cvsCode := C.CString(vsCode) + defer C.free(unsafe.Pointer(cvsCode)) + + cfsCode := C.CString(fsCode) + defer C.free(unsafe.Pointer(cfsCode)) + + ret := C.LoadShaderFromMemory(cvsCode, cfsCode) + v := newShaderFromPointer(unsafe.Pointer(&ret)) + + return v } -// OpenGL version -const ( - Opengl11 int32 = 1 - Opengl21 int32 = 2 - Opengl33 int32 = 3 - Opengl43 int32 = 4 - OpenglEs20 int32 = 5 -) +// UnloadShader - Unload a custom shader from memory +func UnloadShader(shader Shader) { + cshader := shader.cptr() + C.UnloadShader(*cshader) +} -// GlVersion type -type GlVersion = int32 +// GetShaderDefault - Get default shader +func GetShaderDefault() Shader { + ret := C.rlGetShaderDefault() + v := newShaderFromPointer(unsafe.Pointer(&ret)) + return v +} -// Shader attribute data types -const ( - ShaderAttribFloat int32 = 0 - ShaderAttribVec2 int32 = 1 - ShaderAttribVec3 int32 = 2 - ShaderAttribVec4 int32 = 3 -) +// GetTextureDefault - Get default texture +func GetTextureDefault() *Texture2D { + ret := C.rlGetTextureDefault() + v := newTexture2DFromPointer(unsafe.Pointer(&ret)) + return &v +} -// ShaderAttributeDataType type -type ShaderAttributeDataType = int32 +// GetShaderLocation - Get shader uniform location +func GetShaderLocation(shader Shader, uniformName string) int32 { + cshader := shader.cptr() + cuniformName := C.CString(uniformName) + defer C.free(unsafe.Pointer(cuniformName)) -// Framebuffer attachment type -// NOTE: By default up to 8 color channels defined but it can be more -const ( - AttachmentColorChannel0 int32 = 0 - AttachmentColorChannel1 int32 = 1 - AttachmentColorChannel2 int32 = 2 - AttachmentColorChannel3 int32 = 3 - AttachmentColorChannel4 int32 = 4 - AttachmentColorChannel5 int32 = 5 - AttachmentColorChannel6 int32 = 6 - AttachmentColorChannel7 int32 = 7 - AttachmentDepth int32 = 100 - AttachmentStencil int32 = 200 -) + ret := C.GetShaderLocation(*cshader, cuniformName) + v := (int32)(ret) + return v +} -// FramebufferAttachType type -type FramebufferAttachType = int32 +// GetShaderLocationAttrib - Get shader attribute location +func GetShaderLocationAttrib(shader Shader, attribName string) int32 { + cshader := shader.cptr() + cuniformName := C.CString(attribName) + defer C.free(unsafe.Pointer(cuniformName)) -// Framebuffer texture attachment type -const ( - AttachmentCubemapPositiveX int32 = 0 - AttachmentCubemapNegativeX int32 = 1 - AttachmentCubemapPositiveY int32 = 2 - AttachmentCubemapNegativeY int32 = 3 - AttachmentCubemapPositiveZ int32 = 4 - AttachmentCubemapNegativeZ int32 = 5 - AttachmentTexture2d int32 = 100 - AttachmentRenderbuffer int32 = 200 -) + ret := C.GetShaderLocationAttrib(*cshader, cuniformName) + v := (int32)(ret) + return v +} -// FramebufferAttachTextureType type -type FramebufferAttachTextureType = int32 +// SetShaderValue - Set shader uniform value (float) +func SetShaderValue(shader Shader, locIndex int32, value []float32, uniformType ShaderUniformDataType) { + cshader := shader.cptr() + clocIndex := (C.int)(locIndex) + cvalue := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&value)).Data) + cuniformType := (C.int)(uniformType) + C.SetShaderValue(*cshader, clocIndex, cvalue, cuniformType) +} + +// SetShaderValueV - Set shader uniform value (float) +func SetShaderValueV(shader Shader, locIndex int32, value []float32, uniformType ShaderUniformDataType, count int32) { + cshader := shader.cptr() + clocIndex := (C.int)(locIndex) + cvalue := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&value)).Data) + cuniformType := (C.int)(uniformType) + ccount := (C.int)(count) + C.SetShaderValueV(*cshader, clocIndex, cvalue, cuniformType, ccount) +} + +// SetShaderValueMatrix - Set shader uniform value (matrix 4x4) +func SetShaderValueMatrix(shader Shader, locIndex int32, mat Matrix) { + cshader := shader.cptr() + clocIndex := (C.int)(locIndex) + cmat := mat.cptr() + C.SetShaderValueMatrix(*cshader, clocIndex, *cmat) +} + +// SetShaderValueTexture - Set shader uniform value for texture (sampler2d) +func SetShaderValueTexture(shader Shader, locIndex int32, texture Texture2D) { + cshader := shader.cptr() + clocIndex := (C.int)(locIndex) + ctexture := texture.cptr() + C.SetShaderValueTexture(*cshader, clocIndex, *ctexture) +} + +// SetMatrixProjection - Set a custom projection matrix (replaces internal projection matrix) +func SetMatrixProjection(proj Matrix) { + cproj := proj.cptr() + C.rlSetMatrixProjection(*cproj) +} + +// SetMatrixModelview - Set a custom modelview matrix (replaces internal modelview matrix) +func SetMatrixModelview(view Matrix) { + cview := view.cptr() + C.rlSetMatrixModelview(*cview) +} + +// BeginShaderMode - Begin custom shader drawing +func BeginShaderMode(shader Shader) { + cshader := shader.cptr() + C.BeginShaderMode(*cshader) +} + +// EndShaderMode - End custom shader drawing (use default shader) +func EndShaderMode() { + C.EndShaderMode() +} + +// BeginBlendMode - Begin blending mode (alpha, additive, multiplied) +func BeginBlendMode(mode BlendMode) { + cmode := (C.int)(mode) + C.BeginBlendMode(cmode) +} + +// EndBlendMode - End blending mode (reset to default: alpha blending) +func EndBlendMode() { + C.EndBlendMode() +} diff --git a/raylib/rlgl.h b/raylib/rlgl.h index c39d096..a40c804 100644 --- a/raylib/rlgl.h +++ b/raylib/rlgl.h @@ -1,94 +1,44 @@ /********************************************************************************************** * -* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API +* rlgl v3.7 - raylib OpenGL abstraction layer * -* DESCRIPTION: -* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0, ES 3.0) -* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) +* rlgl is a wrapper for multiple OpenGL versions (1.1, 2.1, 3.3 Core, ES 2.0) to +* pseudo-OpenGL 1.1 style functions (rlVertex, rlTranslate, rlRotate...). * -* ADDITIONAL NOTES: -* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are -* initialized on rlglInit() to accumulate vertex data -* -* When an internal state change is required all the stored vertex data is rendered in batch, -* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch -* -* Some resources are also loaded for convenience, here the complete list: -* - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data -* - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8 -* - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs) -* -* Internal buffer (and resources) must be manually unloaded calling rlglClose() +* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal +* VBO buffers (and VAOs if available). It requires calling 3 functions: +* rlglInit() - Initialize internal buffers and auxiliary resources +* rlglClose() - De-initialize internal buffers data and other auxiliar resources * * CONFIGURATION: -* #define GRAPHICS_API_OPENGL_11 -* #define GRAPHICS_API_OPENGL_21 -* #define GRAPHICS_API_OPENGL_33 -* #define GRAPHICS_API_OPENGL_43 -* #define GRAPHICS_API_OPENGL_ES2 -* #define GRAPHICS_API_OPENGL_ES3 -* Use selected OpenGL graphics backend, should be supported by platform -* Those preprocessor defines are only used on rlgl module, if OpenGL version is -* required by any other module, use rlGetVersion() to check it * -* #define RLGL_IMPLEMENTATION -* Generates the implementation of the library into the included file -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation +* #define GRAPHICS_API_OPENGL_11 +* #define GRAPHICS_API_OPENGL_21 +* #define GRAPHICS_API_OPENGL_33 +* #define GRAPHICS_API_OPENGL_ES2 +* Use selected OpenGL graphics backend, should be supported by platform +* Those preprocessor defines are only used on rlgl module, if OpenGL version is +* required by any other module, use rlGetVersion() to check it * -* #define RLGL_RENDER_TEXTURES_HINT -* Enable framebuffer objects (fbo) support (enabled by default) -* Some GPUs could not support them despite the OpenGL version +* #define RLGL_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. * -* #define RLGL_SHOW_GL_DETAILS_INFO -* Show OpenGL extensions and capabilities detailed logs on init +* #define RLGL_STANDALONE +* Use rlgl as standalone library (no raylib dependency) * -* #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT -* Enable debug context (only available on OpenGL 4.3) -* -* rlgl capabilities could be customized just defining some internal -* values before library inclusion (default values listed): -* -* #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits -* #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) -* #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) -* #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture()) -* -* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack -* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported -* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance -* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance -* -* When loading a shader, the following vertex attributes and uniform -* location names are tried to be set automatically: -* -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))) -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices -* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) -* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) -* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) +* #define SUPPORT_GL_DETAILS_INFO +* Show OpenGL extensions and capabilities detailed logs on init * * DEPENDENCIES: -* - OpenGL libraries (depending on platform and OpenGL version selected) -* - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core) +* raymath - 3D math functionality (Vector3, Matrix, Quaternion) +* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) * * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -110,51 +60,50 @@ #ifndef RLGL_H #define RLGL_H -#define RLGL_VERSION "5.0" +#if defined(RLGL_STANDALONE) + #define RAYMATH_STANDALONE + #define RAYMATH_HEADER_ONLY -// Function specifiers in case library is build/used as a shared library -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -// NOTE: visibility(default) attribute makes symbols "visible" when compiled with -fvisibility=hidden -#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) -#elif defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __attribute__((visibility("default"))) // We are building the library as a Unix shared library (.so/.dylib) -#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #define RLAPI // We are building or using rlgl as a static library (or Linux shared library) + + #if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) + #endif + #endif + + // Support TRACELOG macros + #if !defined(TRACELOG) + #define TRACELOG(level, ...) (void)0 + #define TRACELOGD(...) (void)0 + #endif + + // Allow custom memory allocators + #ifndef RL_MALLOC + #define RL_MALLOC(sz) malloc(sz) + #endif + #ifndef RL_CALLOC + #define RL_CALLOC(n,sz) calloc(n,sz) + #endif + #ifndef RL_REALLOC + #define RL_REALLOC(n,sz) realloc(n,sz) + #endif + #ifndef RL_FREE + #define RL_FREE(p) free(p) + #endif +#else + #include "raylib.h" // Required for: Shader, Texture2D #endif -// Function specifiers definition -#ifndef RLAPI - #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -// Support TRACELOG macros -#ifndef TRACELOG - #define TRACELOG(level, ...) (void)0 - #define TRACELOGD(...) (void)0 -#endif - -// Allow custom memory allocators -#ifndef RL_MALLOC - #define RL_MALLOC(sz) malloc(sz) -#endif -#ifndef RL_CALLOC - #define RL_CALLOC(n,sz) calloc(n,sz) -#endif -#ifndef RL_REALLOC - #define RL_REALLOC(n,sz) realloc(n,sz) -#endif -#ifndef RL_FREE - #define RL_FREE(p) free(p) -#endif +#include "raymath.h" // Required for: Vector3, Matrix // Security check in case no GRAPHICS_API_OPENGL_* defined #if !defined(GRAPHICS_API_OPENGL_11) && \ !defined(GRAPHICS_API_OPENGL_21) && \ !defined(GRAPHICS_API_OPENGL_33) && \ - !defined(GRAPHICS_API_OPENGL_43) && \ - !defined(GRAPHICS_API_OPENGL_ES2) && \ - !defined(GRAPHICS_API_OPENGL_ES3) + !defined(GRAPHICS_API_OPENGL_ES2) #define GRAPHICS_API_OPENGL_33 #endif @@ -166,9 +115,6 @@ #if defined(GRAPHICS_API_OPENGL_33) #undef GRAPHICS_API_OPENGL_33 #endif - #if defined(GRAPHICS_API_OPENGL_43) - #undef GRAPHICS_API_OPENGL_43 - #endif #if defined(GRAPHICS_API_OPENGL_ES2) #undef GRAPHICS_API_OPENGL_ES2 #endif @@ -180,64 +126,59 @@ #define GRAPHICS_API_OPENGL_33 #endif -// OpenGL 4.3 uses OpenGL 3.3 Core functionality -#if defined(GRAPHICS_API_OPENGL_43) - #define GRAPHICS_API_OPENGL_33 -#endif - -// OpenGL ES 3.0 uses OpenGL ES 2.0 functionality (and more) -#if defined(GRAPHICS_API_OPENGL_ES3) - #define GRAPHICS_API_OPENGL_ES2 -#endif - -// Support framebuffer objects by default -// NOTE: Some driver implementation do not support it, despite they should -#define RLGL_RENDER_TEXTURES_HINT +#define SUPPORT_RENDER_TEXTURES_HINT //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- - -// Default internal render batch elements limits -#ifndef RL_DEFAULT_BATCH_BUFFER_ELEMENTS +// Default internal render batch limits +#ifndef DEFAULT_BATCH_BUFFER_ELEMENTS #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) // This is the maximum amount of elements (quads) per batch // NOTE: Be careful with text, every letter maps to a quad - #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 + #define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 #endif #if defined(GRAPHICS_API_OPENGL_ES2) // We reduce memory sizes for embedded systems (RPI and HTML5) // NOTE: On HTML5 (emscripten) this is allocated on heap, // by default it's only 16MB!...just take care... - #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 2048 + #define DEFAULT_BATCH_BUFFER_ELEMENTS 2048 #endif #endif -#ifndef RL_DEFAULT_BATCH_BUFFERS - #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) +#ifndef DEFAULT_BATCH_BUFFERS + #define DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) #endif -#ifndef RL_DEFAULT_BATCH_DRAWCALLS - #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) +#ifndef DEFAULT_BATCH_DRAWCALLS + #define DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) #endif -#ifndef RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS - #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture()) +#ifndef MAX_BATCH_ACTIVE_TEXTURES + #define MAX_BATCH_ACTIVE_TEXTURES 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture()) #endif // Internal Matrix stack -#ifndef RL_MAX_MATRIX_STACK_SIZE - #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of Matrix stack +#ifndef MAX_MATRIX_STACK_SIZE + #define MAX_MATRIX_STACK_SIZE 32 // Maximum size of Matrix stack #endif -// Shader limits -#ifndef RL_MAX_SHADER_LOCATIONS - #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported +// Vertex buffers id limit +#ifndef MAX_MESH_VERTEX_BUFFERS + #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh +#endif + +// Shader and material limits +#ifndef MAX_SHADER_LOCATIONS + #define MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported +#endif +#ifndef MAX_MATERIAL_MAPS + #define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported #endif // Projection matrix culling #ifndef RL_CULL_DISTANCE_NEAR - #define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance + #define RL_CULL_DISTANCE_NEAR 0.01 // Default near cull distance #endif #ifndef RL_CULL_DISTANCE_FAR - #define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance + #define RL_CULL_DISTANCE_FAR 1000.0 // Default far cull distance #endif // Texture parameters (equivalent to OpenGL defines) @@ -253,7 +194,6 @@ #define RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST #define RL_TEXTURE_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR #define RL_TEXTURE_FILTER_ANISOTROPIC 0x3000 // Anisotropic filter (custom identifier) -#define RL_TEXTURE_MIPMAP_BIAS_RATIO 0x4000 // Texture mipmap bias, percentage ratio (custom identifier) #define RL_TEXTURE_WRAP_REPEAT 0x2901 // GL_REPEAT #define RL_TEXTURE_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE @@ -274,119 +214,45 @@ #define RL_UNSIGNED_BYTE 0x1401 // GL_UNSIGNED_BYTE #define RL_FLOAT 0x1406 // GL_FLOAT -// GL buffer usage hint -#define RL_STREAM_DRAW 0x88E0 // GL_STREAM_DRAW -#define RL_STREAM_READ 0x88E1 // GL_STREAM_READ -#define RL_STREAM_COPY 0x88E2 // GL_STREAM_COPY -#define RL_STATIC_DRAW 0x88E4 // GL_STATIC_DRAW -#define RL_STATIC_READ 0x88E5 // GL_STATIC_READ -#define RL_STATIC_COPY 0x88E6 // GL_STATIC_COPY -#define RL_DYNAMIC_DRAW 0x88E8 // GL_DYNAMIC_DRAW -#define RL_DYNAMIC_READ 0x88E9 // GL_DYNAMIC_READ -#define RL_DYNAMIC_COPY 0x88EA // GL_DYNAMIC_COPY - -// GL Shader type -#define RL_FRAGMENT_SHADER 0x8B30 // GL_FRAGMENT_SHADER -#define RL_VERTEX_SHADER 0x8B31 // GL_VERTEX_SHADER -#define RL_COMPUTE_SHADER 0x91B9 // GL_COMPUTE_SHADER - -// GL blending factors -#define RL_ZERO 0 // GL_ZERO -#define RL_ONE 1 // GL_ONE -#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR -#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR -#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA -#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA -#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA -#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA -#define RL_DST_COLOR 0x0306 // GL_DST_COLOR -#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR -#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE -#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR -#define RL_ONE_MINUS_CONSTANT_COLOR 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR -#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA -#define RL_ONE_MINUS_CONSTANT_ALPHA 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA - -// GL blending functions/equations -#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD -#define RL_MIN 0x8007 // GL_MIN -#define RL_MAX 0x8008 // GL_MAX -#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT -#define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT -#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION -#define RL_BLEND_EQUATION_RGB 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) -#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA -#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB -#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB -#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA -#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA -#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR - -#define RL_READ_FRAMEBUFFER 0x8CA8 // GL_READ_FRAMEBUFFER -#define RL_DRAW_FRAMEBUFFER 0x8CA9 // GL_DRAW_FRAMEBUFFER - -// Default shader vertex attribute locations -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 -#endif - #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 -#endif -#ifdef RL_SUPPORT_MESH_GPU_SKINNING -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 -#endif -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9 -#endif - //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) - #include -#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) - // Boolean type -typedef enum bool { false = 0, true = !false } bool; -#endif +typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; -#if !defined(RL_MATRIX_TYPE) -// Matrix, 4x4 components, column major, OpenGL style, right handed -typedef struct Matrix { - float m0, m4, m8, m12; // Matrix first row (4 components) - float m1, m5, m9, m13; // Matrix second row (4 components) - float m2, m6, m10, m14; // Matrix third row (4 components) - float m3, m7, m11, m15; // Matrix fourth row (4 components) -} Matrix; -#define RL_MATRIX_TYPE -#endif +typedef enum { + RL_ATTACHMENT_COLOR_CHANNEL0 = 0, + RL_ATTACHMENT_COLOR_CHANNEL1, + RL_ATTACHMENT_COLOR_CHANNEL2, + RL_ATTACHMENT_COLOR_CHANNEL3, + RL_ATTACHMENT_COLOR_CHANNEL4, + RL_ATTACHMENT_COLOR_CHANNEL5, + RL_ATTACHMENT_COLOR_CHANNEL6, + RL_ATTACHMENT_COLOR_CHANNEL7, + RL_ATTACHMENT_DEPTH = 100, + RL_ATTACHMENT_STENCIL = 200, +} FramebufferAttachType; + +typedef enum { + RL_ATTACHMENT_CUBEMAP_POSITIVE_X = 0, + RL_ATTACHMENT_CUBEMAP_NEGATIVE_X, + RL_ATTACHMENT_CUBEMAP_POSITIVE_Y, + RL_ATTACHMENT_CUBEMAP_NEGATIVE_Y, + RL_ATTACHMENT_CUBEMAP_POSITIVE_Z, + RL_ATTACHMENT_CUBEMAP_NEGATIVE_Z, + RL_ATTACHMENT_TEXTURE2D = 100, + RL_ATTACHMENT_RENDERBUFFER = 200, +} FramebufferAttachTextureType; // Dynamic vertex buffers (position + texcoords + colors + indices arrays) -typedef struct rlVertexBuffer { - int elementCount; // Number of elements in the buffer (QUADS) +typedef struct VertexBuffer { + int elementsCount; // Number of elements in the buffer (QUADS) + + int vCounter; // Vertex position counter to process (and draw) from full buffer + int tcCounter; // Vertex texcoord counter to process (and draw) from full buffer + int cCounter; // Vertex color counter to process (and draw) from full buffer float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - float *normals; // Vertex normal (XYZ - 3 components per vertex) (shader-location = 2) unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) unsigned int *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) @@ -395,238 +261,219 @@ typedef struct rlVertexBuffer { unsigned short *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) #endif unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[5]; // OpenGL Vertex Buffer Objects id (5 types of vertex data) -} rlVertexBuffer; + unsigned int vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data) +} VertexBuffer; // Draw call type // NOTE: Only texture changes register a new draw, other state-change-related elements are not // used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any // of those state-change happens (this is done in core module) -typedef struct rlDrawCall { +typedef struct DrawCall { int mode; // Drawing mode: LINES, TRIANGLES, QUADS int vertexCount; // Number of vertex of the draw int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES) //unsigned int vaoId; // Vertex array id to be used on the draw -> Using RLGL.currentBatch->vertexBuffer.vaoId - //unsigned int shaderId; // Shader id to be used on the draw -> Using RLGL.currentShaderId + //unsigned int shaderId; // Shader id to be used on the draw -> Using RLGL.currentShader.id unsigned int textureId; // Texture id to be used on the draw -> Use to create new draw call if changes //Matrix projection; // Projection matrix for this draw -> Using RLGL.projection by default //Matrix modelview; // Modelview matrix for this draw -> Using RLGL.modelview by default -} rlDrawCall; +} DrawCall; -// rlRenderBatch type -typedef struct rlRenderBatch { - int bufferCount; // Number of vertex buffers (multi-buffering support) +// RenderBatch type +typedef struct RenderBatch { + int buffersCount; // Number of vertex buffers (multi-buffering support) int currentBuffer; // Current buffer tracking in case of multi-buffering - rlVertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data + VertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data - rlDrawCall *draws; // Draw calls array, depends on textureId - int drawCounter; // Draw calls counter + DrawCall *draws; // Draw calls array, depends on textureId + int drawsCounter; // Draw calls counter float currentDepth; // Current depth value for next draw -} rlRenderBatch; - -// OpenGL version -typedef enum { - RL_OPENGL_11 = 1, // OpenGL 1.1 - RL_OPENGL_21, // OpenGL 2.1 (GLSL 120) - RL_OPENGL_33, // OpenGL 3.3 (GLSL 330) - RL_OPENGL_43, // OpenGL 4.3 (using GLSL 330) - RL_OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100) - RL_OPENGL_ES_30 // OpenGL ES 3.0 (GLSL 300 es) -} rlGlVersion; - -// Trace log level -// NOTE: Organized by priority level -typedef enum { - RL_LOG_ALL = 0, // Display all logs - RL_LOG_TRACE, // Trace logging, intended for internal use only - RL_LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds - RL_LOG_INFO, // Info logging, used for program execution info - RL_LOG_WARNING, // Warning logging, used on recoverable failures - RL_LOG_ERROR, // Error logging, used on unrecoverable failures - RL_LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) - RL_LOG_NONE // Disable logging -} rlTraceLogLevel; - -// Texture pixel formats -// NOTE: Support depends on OpenGL version -typedef enum { - RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp - RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp - RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp - RL_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - RL_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) - RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) - RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) - RL_PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp - RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp - RL_PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp - RL_PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp - RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - RL_PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp - RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp - RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp -} rlPixelFormat; - -// Texture parameters: filter mode -// NOTE 1: Filtering considers mipmaps if available in the texture -// NOTE 2: Filter is accordingly set for minification and magnification -typedef enum { - RL_TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation - RL_TEXTURE_FILTER_BILINEAR, // Linear filtering - RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) - RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x - RL_TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x - RL_TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x -} rlTextureFilter; - -// Color blending modes (pre-defined) -typedef enum { - RL_BLEND_ALPHA = 0, // Blend textures considering alpha (default) - RL_BLEND_ADDITIVE, // Blend textures adding colors - RL_BLEND_MULTIPLIED, // Blend textures multiplying colors - RL_BLEND_ADD_COLORS, // Blend textures adding colors (alternative) - RL_BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) - RL_BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha - RL_BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) - RL_BLEND_CUSTOM_SEPARATE // Blend textures using custom src/dst factors (use rlSetBlendFactorsSeparate()) -} rlBlendMode; - -// Shader location point type -typedef enum { - RL_SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position - RL_SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 - RL_SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 - RL_SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal - RL_SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent - RL_SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color - RL_SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection - RL_SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) - RL_SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection - RL_SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) - RL_SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal - RL_SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view - RL_SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color - RL_SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color - RL_SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color - RL_SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: RL_SHADER_LOC_MAP_DIFFUSE) - RL_SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: RL_SHADER_LOC_MAP_SPECULAR) - RL_SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal - RL_SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness - RL_SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion - RL_SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission - RL_SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height - RL_SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap - RL_SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance - RL_SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter - RL_SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf -} rlShaderLocationIndex; - -#define RL_SHADER_LOC_MAP_DIFFUSE RL_SHADER_LOC_MAP_ALBEDO -#define RL_SHADER_LOC_MAP_SPECULAR RL_SHADER_LOC_MAP_METALNESS - -// Shader uniform data type -typedef enum { - RL_SHADER_UNIFORM_FLOAT = 0, // Shader uniform type: float - RL_SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) - RL_SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) - RL_SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) - RL_SHADER_UNIFORM_INT, // Shader uniform type: int - RL_SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) - RL_SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) - RL_SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) - RL_SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int - RL_SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) - RL_SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) - RL_SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) - RL_SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d -} rlShaderUniformDataType; +} RenderBatch; // Shader attribute data types typedef enum { - RL_SHADER_ATTRIB_FLOAT = 0, // Shader attribute type: float - RL_SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) - RL_SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) - RL_SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) -} rlShaderAttributeDataType; + SHADER_ATTRIB_FLOAT = 0, + SHADER_ATTRIB_VEC2, + SHADER_ATTRIB_VEC3, + SHADER_ATTRIB_VEC4 +} ShaderAttributeDataType; -// Framebuffer attachment type -// NOTE: By default up to 8 color channels defined, but it can be more -typedef enum { - RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0 - RL_ATTACHMENT_COLOR_CHANNEL1 = 1, // Framebuffer attachment type: color 1 - RL_ATTACHMENT_COLOR_CHANNEL2 = 2, // Framebuffer attachment type: color 2 - RL_ATTACHMENT_COLOR_CHANNEL3 = 3, // Framebuffer attachment type: color 3 - RL_ATTACHMENT_COLOR_CHANNEL4 = 4, // Framebuffer attachment type: color 4 - RL_ATTACHMENT_COLOR_CHANNEL5 = 5, // Framebuffer attachment type: color 5 - RL_ATTACHMENT_COLOR_CHANNEL6 = 6, // Framebuffer attachment type: color 6 - RL_ATTACHMENT_COLOR_CHANNEL7 = 7, // Framebuffer attachment type: color 7 - RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachment type: depth - RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachment type: stencil -} rlFramebufferAttachType; +#if defined(RLGL_STANDALONE) + #ifndef __cplusplus + // Boolean type + typedef enum { false, true } bool; + #endif -// Framebuffer texture attachment type -typedef enum { - RL_ATTACHMENT_CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side - RL_ATTACHMENT_CUBEMAP_NEGATIVE_X = 1, // Framebuffer texture attachment type: cubemap, -X side - RL_ATTACHMENT_CUBEMAP_POSITIVE_Y = 2, // Framebuffer texture attachment type: cubemap, +Y side - RL_ATTACHMENT_CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side - RL_ATTACHMENT_CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side - RL_ATTACHMENT_CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side - RL_ATTACHMENT_TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d - RL_ATTACHMENT_RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer -} rlFramebufferAttachTextureType; + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; -// Face culling mode -typedef enum { - RL_CULL_FACE_FRONT = 0, - RL_CULL_FACE_BACK -} rlCullMode; + // Texture type + // NOTE: Data stored in GPU memory + typedef struct Texture2D { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat) + } Texture2D; -//------------------------------------------------------------------------------------ -// Functions Declaration - Matrix operations -//------------------------------------------------------------------------------------ + // Shader type (generic) + typedef struct Shader { + unsigned int id; // Shader program id + int *locs; // Shader locations array (MAX_SHADER_LOCATIONS) + } Shader; + + // TraceLog message types + typedef enum { + LOG_ALL, + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARNING, + LOG_ERROR, + LOG_FATAL, + LOG_NONE + } TraceLogLevel; + + // Texture formats (support depends on OpenGL version) + typedef enum { + PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, + PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp + PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp + } PixelFormat; + + // Texture parameters: filter mode + // NOTE 1: Filtering considers mipmaps if available in the texture + // NOTE 2: Filter is accordingly set for minification and magnification + typedef enum { + TEXTURE_FILTER_POINT = 0, // No filter, just pixel aproximation + TEXTURE_FILTER_BILINEAR, // Linear filtering + TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x + } TextureFilter; + + // Texture parameters: wrap mode + typedef enum { + TEXTURE_WRAP_REPEAT = 0, // Repeats texture in tiled mode + TEXTURE_WRAP_CLAMP, // Clamps texture to edge pixel in tiled mode + TEXTURE_WRAP_MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode + TEXTURE_WRAP_MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode + } TextureWrap; + + // Color blending modes (pre-defined) + typedef enum { + BLEND_ALPHA = 0, // Blend textures considering alpha (default) + BLEND_ADDITIVE, // Blend textures adding colors + BLEND_MULTIPLIED, // Blend textures multiplying colors + BLEND_ADD_COLORS, // Blend textures adding colors (alternative) + BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + BLEND_CUSTOM // Belnd textures using custom src/dst factors (use SetBlendModeCustom()) + } BlendMode; + + // Shader location point type + typedef enum { + SHADER_LOC_VERTEX_POSITION = 0, + SHADER_LOC_VERTEX_TEXCOORD01, + SHADER_LOC_VERTEX_TEXCOORD02, + SHADER_LOC_VERTEX_NORMAL, + SHADER_LOC_VERTEX_TANGENT, + SHADER_LOC_VERTEX_COLOR, + SHADER_LOC_MATRIX_MVP, + SHADER_LOC_MATRIX_MODEL, + SHADER_LOC_MATRIX_VIEW, + SHADER_LOC_MATRIX_NORMAL, + SHADER_LOC_MATRIX_PROJECTION, + SHADER_LOC_VECTOR_VIEW, + SHADER_LOC_COLOR_DIFFUSE, + SHADER_LOC_COLOR_SPECULAR, + SHADER_LOC_COLOR_AMBIENT, + SHADER_LOC_MAP_ALBEDO, // SHADER_LOC_MAP_DIFFUSE + SHADER_LOC_MAP_METALNESS, // SHADER_LOC_MAP_SPECULAR + SHADER_LOC_MAP_NORMAL, + SHADER_LOC_MAP_ROUGHNESS, + SHADER_LOC_MAP_OCCLUSION, + SHADER_LOC_MAP_EMISSION, + SHADER_LOC_MAP_HEIGHT, + SHADER_LOC_MAP_CUBEMAP, + SHADER_LOC_MAP_IRRADIANCE, + SHADER_LOC_MAP_PREFILTER, + SHADER_LOC_MAP_BRDF + } ShaderLocationIndex; + + #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO + #define SHADER_LOC_MAP_SPECULAR SHADER_LOC_MAP_METALNESS + + // Shader uniform data types + typedef enum { + SHADER_UNIFORM_FLOAT = 0, + SHADER_UNIFORM_VEC2, + SHADER_UNIFORM_VEC3, + SHADER_UNIFORM_VEC4, + SHADER_UNIFORM_INT, + SHADER_UNIFORM_IVEC2, + SHADER_UNIFORM_IVEC3, + SHADER_UNIFORM_IVEC4, + SHADER_UNIFORM_SAMPLER2D + } ShaderUniformDataType; +#endif #if defined(__cplusplus) extern "C" { // Prevents name mangling of functions #endif -RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed -RLAPI void rlPushMatrix(void); // Push the current matrix to stack -RLAPI void rlPopMatrix(void); // Pop latest inserted matrix from stack -RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix -RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix -RLAPI void rlRotatef(float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix -RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix -RLAPI void rlMultMatrixf(const float *matf); // Multiply the current matrix by another matrix +//------------------------------------------------------------------------------------ +// Functions Declaration - Matrix operations +//------------------------------------------------------------------------------------ +RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed +RLAPI void rlPushMatrix(void); // Push the current matrix to stack +RLAPI void rlPopMatrix(void); // Pop lattest inserted matrix from stack +RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix +RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix +RLAPI void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix +RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix +RLAPI void rlMultMatrixf(float *matf); // Multiply the current matrix by another matrix RLAPI void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar); RLAPI void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar); RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area -RLAPI void rlSetClipPlanes(double nearPlane, double farPlane); // Set clip planes distances -RLAPI double rlGetCullDistanceNear(void); // Get cull plane distance near -RLAPI double rlGetCullDistanceFar(void); // Get cull plane distance far //------------------------------------------------------------------------------------ // Functions Declaration - Vertex level operations //------------------------------------------------------------------------------------ -RLAPI void rlBegin(int mode); // Initialize drawing mode (how to organize vertex) -RLAPI void rlEnd(void); // Finish vertex providing -RLAPI void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int -RLAPI void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float -RLAPI void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float -RLAPI void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float -RLAPI void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float -RLAPI void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Define one vertex (color) - 4 byte -RLAPI void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float +RLAPI void rlBegin(int mode); // Initialize drawing mode (how to organize vertex) +RLAPI void rlEnd(void); // Finish vertex providing +RLAPI void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int +RLAPI void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float +RLAPI void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float +RLAPI void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float +RLAPI void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float +RLAPI void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Define one vertex (color) - 4 byte +RLAPI void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float RLAPI void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 float //------------------------------------------------------------------------------------ @@ -640,13 +487,13 @@ RLAPI bool rlEnableVertexArray(unsigned int vaoId); // Enable vertex array ( RLAPI void rlDisableVertexArray(void); // Disable vertex array (VAO, if supported) RLAPI void rlEnableVertexBuffer(unsigned int id); // Enable vertex buffer (VBO) RLAPI void rlDisableVertexBuffer(void); // Disable vertex buffer (VBO) -RLAPI void rlEnableVertexBufferElement(unsigned int id); // Enable vertex buffer element (VBO element) +RLAPI void rlEnableVertexBufferElement(unsigned int id);// Enable vertex buffer element (VBO element) RLAPI void rlDisableVertexBufferElement(void); // Disable vertex buffer element (VBO element) RLAPI void rlEnableVertexAttribute(unsigned int index); // Enable vertex attribute index -RLAPI void rlDisableVertexAttribute(unsigned int index); // Disable vertex attribute index +RLAPI void rlDisableVertexAttribute(unsigned int index);// Disable vertex attribute index #if defined(GRAPHICS_API_OPENGL_11) -RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer); // Enable attribute state pointer -RLAPI void rlDisableStatePointer(int vertexAttribType); // Disable attribute state pointer +RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer); +RLAPI void rlDisableStatePointer(int vertexAttribType); #endif // Textures state @@ -656,7 +503,6 @@ RLAPI void rlDisableTexture(void); // Disable texture RLAPI void rlEnableTextureCubemap(unsigned int id); // Enable texture cubemap RLAPI void rlDisableTextureCubemap(void); // Disable texture cubemap RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) -RLAPI void rlCubemapParameters(unsigned int id, int param, int value); // Set cubemap parameters (filter, wrap) // Shader state RLAPI void rlEnableShader(unsigned int id); // Enable shader program @@ -665,27 +511,17 @@ RLAPI void rlDisableShader(void); // Disable shader progra // Framebuffer state RLAPI void rlEnableFramebuffer(unsigned int id); // Enable render texture (fbo) RLAPI void rlDisableFramebuffer(void); // Disable render texture (fbo), return to default framebuffer -RLAPI unsigned int rlGetActiveFramebuffer(void); // Get the currently active render texture (fbo), 0 for default framebuffer -RLAPI void rlActiveDrawBuffers(int count); // Activate multiple draw color buffers -RLAPI void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, int bufferMask); // Blit active framebuffer to main framebuffer -RLAPI void rlBindFramebuffer(unsigned int target, unsigned int framebuffer); // Bind framebuffer (FBO) // General render state -RLAPI void rlEnableColorBlend(void); // Enable color blending -RLAPI void rlDisableColorBlend(void); // Disable color blending RLAPI void rlEnableDepthTest(void); // Enable depth test RLAPI void rlDisableDepthTest(void); // Disable depth test RLAPI void rlEnableDepthMask(void); // Enable depth write RLAPI void rlDisableDepthMask(void); // Disable depth write RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling -RLAPI void rlColorMask(bool r, bool g, bool b, bool a); // Color mask control -RLAPI void rlSetCullFace(int mode); // Set face culling mode RLAPI void rlEnableScissorTest(void); // Enable scissor test RLAPI void rlDisableScissorTest(void); // Disable scissor test RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test -RLAPI void rlEnablePointMode(void); // Enable point mode -RLAPI void rlDisablePointMode(void); // Disable point mode RLAPI void rlEnableWireMode(void); // Enable wire mode RLAPI void rlDisableWireMode(void); // Disable wire mode RLAPI void rlSetLineWidth(float width); // Set the line drawing width @@ -701,101 +537,77 @@ RLAPI void rlClearScreenBuffers(void); // Clear used screen buf RLAPI void rlCheckErrors(void); // Check and log OpenGL error codes RLAPI void rlSetBlendMode(int mode); // Set blending mode RLAPI void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation); // Set blending mode factor and equation (using OpenGL factors) -RLAPI void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha); // Set blending mode factors and equations separately (using OpenGL factors) //------------------------------------------------------------------------------------ // Functions Declaration - rlgl functionality //------------------------------------------------------------------------------------ // rlgl initialization functions -RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states) -RLAPI void rlglClose(void); // De-initialize rlgl (buffers, shaders, textures) -RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required) -RLAPI int rlGetVersion(void); // Get current OpenGL version -RLAPI void rlSetFramebufferWidth(int width); // Set current framebuffer width -RLAPI int rlGetFramebufferWidth(void); // Get default framebuffer width -RLAPI void rlSetFramebufferHeight(int height); // Set current framebuffer height -RLAPI int rlGetFramebufferHeight(void); // Get default framebuffer height +RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states) +RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures) +RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required) +RLAPI int rlGetVersion(void); // Returns current OpenGL version +RLAPI int rlGetFramebufferWidth(void); // Get default framebuffer width +RLAPI int rlGetFramebufferHeight(void); // Get default framebuffer height -RLAPI unsigned int rlGetTextureIdDefault(void); // Get default texture id -RLAPI unsigned int rlGetShaderIdDefault(void); // Get default shader id -RLAPI int *rlGetShaderLocsDefault(void); // Get default shader locations +RLAPI Shader rlGetShaderDefault(void); // Get default shader +RLAPI Texture2D rlGetTextureDefault(void); // Get default texture // Render batch management // NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode // but this render batch API is exposed in case of custom batches are required -RLAPI rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements); // Load a render batch system -RLAPI void rlUnloadRenderBatch(rlRenderBatch batch); // Unload render batch system -RLAPI void rlDrawRenderBatch(rlRenderBatch *batch); // Draw render batch data (Update->Draw->Reset) -RLAPI void rlSetRenderBatchActive(rlRenderBatch *batch); // Set the active render batch for rlgl (NULL for default internal) -RLAPI void rlDrawRenderBatchActive(void); // Update and draw internal render batch -RLAPI bool rlCheckRenderBatchLimit(int vCount); // Check internal buffer overflow for a given number of vertex - -RLAPI void rlSetTexture(unsigned int id); // Set current texture for render batch and check buffers limits +RLAPI RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements); // Load a render batch system +RLAPI void rlUnloadRenderBatch(RenderBatch batch); // Unload render batch system +RLAPI void rlDrawRenderBatch(RenderBatch *batch); // Draw render batch data (Update->Draw->Reset) +RLAPI void rlSetRenderBatchActive(RenderBatch *batch); // Set the active render batch for rlgl (NULL for default internal) +RLAPI void rlDrawRenderBatchActive(void); // Update and draw internal render batch +RLAPI bool rlCheckRenderBatchLimit(int vCount); // Check internal buffer overflow for a given number of vertex +RLAPI void rlSetTexture(unsigned int id); // Set current texture for render batch and check buffers limits //------------------------------------------------------------------------------------------------------------------------ // Vertex buffers management -RLAPI unsigned int rlLoadVertexArray(void); // Load vertex array (vao) if supported -RLAPI unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic); // Load a vertex buffer object -RLAPI unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic); // Load vertex buffer elements object -RLAPI void rlUpdateVertexBuffer(unsigned int bufferId, const void *data, int dataSize, int offset); // Update vertex buffer object data on GPU buffer -RLAPI void rlUpdateVertexBufferElements(unsigned int id, const void *data, int dataSize, int offset); // Update vertex buffer elements data on GPU buffer -RLAPI void rlUnloadVertexArray(unsigned int vaoId); // Unload vertex array (vao) -RLAPI void rlUnloadVertexBuffer(unsigned int vboId); // Unload vertex buffer object -RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, int offset); // Set vertex attribute data configuration -RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor); // Set vertex attribute data divisor -RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value, when attribute to provided -RLAPI void rlDrawVertexArray(int offset, int count); // Draw vertex array (currently active vao) -RLAPI void rlDrawVertexArrayElements(int offset, int count, const void *buffer); // Draw vertex array elements -RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances); // Draw vertex array (currently active vao) with instancing -RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances); // Draw vertex array elements with instancing +RLAPI unsigned int rlLoadVertexArray(void); // Load vertex array (vao) if supported +RLAPI unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic); // Load a vertex buffer attribute +RLAPI unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic); // Load a new attributes element buffer +RLAPI void rlUpdateVertexBuffer(int bufferId, void *data, int dataSize, int offset); // Update GPU buffer with new data +RLAPI void rlUnloadVertexArray(unsigned int vaoId); +RLAPI void rlUnloadVertexBuffer(unsigned int vboId); +RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer); +RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor); +RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value +RLAPI void rlDrawVertexArray(int offset, int count); +RLAPI void rlDrawVertexArrayElements(int offset, int count, void *buffer); +RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances); +RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances); // Textures management -RLAPI unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount); // Load texture data -RLAPI unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo) -RLAPI unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount); // Load texture cubemap data -RLAPI void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data); // Update texture with new data on GPU -RLAPI void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats -RLAPI const char *rlGetPixelFormatName(unsigned int format); // Get name string for pixel format +RLAPI unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU +RLAPI unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo) +RLAPI unsigned int rlLoadTextureCubemap(void *data, int size, int format); // Load texture cubemap +RLAPI void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data); // Update GPU texture with new data +RLAPI void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats RLAPI void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory -RLAPI void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps); // Generate mipmap data for selected texture -RLAPI void *rlReadTexturePixels(unsigned int id, int width, int height, int format); // Read texture pixel data +RLAPI void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture +RLAPI void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) // Framebuffer management (fbo) -RLAPI unsigned int rlLoadFramebuffer(void); // Load an empty framebuffer -RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer +RLAPI unsigned int rlLoadFramebuffer(int width, int height); // Load an empty framebuffer +RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU // Shaders management RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings -RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) +RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: GL_VERTEX_SHADER, GL_FRAGMENT_SHADER) RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix -RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); // Set shader value sampler -RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations) - -// Compute shader management -RLAPI unsigned int rlLoadComputeShaderProgram(unsigned int shaderId); // Load compute shader program -RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pipeline) - -// Shader buffer storage object management (ssbo) -RLAPI unsigned int rlLoadShaderBuffer(unsigned int size, const void *data, int usageHint); // Load shader storage buffer object (SSBO) -RLAPI void rlUnloadShaderBuffer(unsigned int ssboId); // Unload shader storage buffer object (SSBO) -RLAPI void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSize, unsigned int offset); // Update SSBO buffer data -RLAPI void rlBindShaderBuffer(unsigned int id, unsigned int index); // Bind SSBO buffer -RLAPI void rlReadShaderBuffer(unsigned int id, void *dest, unsigned int count, unsigned int offset); // Read SSBO buffer data (GPU->CPU) -RLAPI void rlCopyShaderBuffer(unsigned int destId, unsigned int srcId, unsigned int destOffset, unsigned int srcOffset, unsigned int count); // Copy SSBO data between buffers -RLAPI unsigned int rlGetShaderBufferSize(unsigned int id); // Get SSBO buffer size - -// Buffer management -RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly); // Bind image texture +RLAPI void rlSetShader(Shader shader); // Set shader currently active // Matrix state management RLAPI Matrix rlGetMatrixModelview(void); // Get internal modelview matrix @@ -811,7 +623,6 @@ RLAPI void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left); // Set // Quick and dirty cube/quad buffers load->draw->unload RLAPI void rlLoadDrawCube(void); // Load and draw a cube RLAPI void rlLoadDrawQuad(void); // Load and draw a quad - #if defined(__cplusplus) } #endif @@ -826,19 +637,24 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #if defined(RLGL_IMPLEMENTATION) -// Expose OpenGL functions from glad in raylib -#if defined(BUILD_LIBTYPE_SHARED) - #define GLAD_API_CALL_EXPORT - #define GLAD_API_CALL_EXPORT_BUILD +#if !defined(RLGL_STANDALONE) + // Check if config flags have been externally provided on compilation line + #if !defined(EXTERNAL_CONFIG_FLAGS) + #include "config.h" // Defines module configuration flags + #endif + #include "raymath.h" // Required for: Vector3 and Matrix functions #endif +#include // Required for: malloc(), free() +#include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] + #if defined(GRAPHICS_API_OPENGL_11) #if defined(__APPLE__) #include // OpenGL 1.1 library for OSX - #include // OpenGL extensions library + #include #else // APIENTRY for OpenGL function pointer declarations is required - #if !defined(APIENTRY) + #ifndef APIENTRY #if defined(_WIN32) #define APIENTRY __stdcall #else @@ -855,56 +671,40 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #if defined(GRAPHICS_API_OPENGL_33) - #define GLAD_MALLOC RL_MALLOC - #define GLAD_FREE RL_FREE + #if defined(__APPLE__) + #include // OpenGL 3 library for OSX + #include // OpenGL 3 extensions library for OSX + #else + #define GLAD_REALLOC RL_REALLOC + #define GLAD_FREE RL_FREE - #define GLAD_GL_IMPLEMENTATION - #include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers + #define GLAD_IMPLEMENTATION + #if defined(RLGL_STANDALONE) + #include "glad.h" // GLAD extensions loading library, includes OpenGL headers + #else + #include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers + #endif + #endif #endif -#if defined(GRAPHICS_API_OPENGL_ES3) - #include // OpenGL ES 3.0 library +#if defined(GRAPHICS_API_OPENGL_ES2) #define GL_GLEXT_PROTOTYPES + //#include // EGL library -> not required, platform layer + #include // OpenGL ES 2.0 library #include // OpenGL ES 2.0 extensions library -#elif defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms, - // in that case, functions are loaded from a custom glad for OpenGL ES 2.0 - #if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL) - #define GLAD_GLES2_IMPLEMENTATION - #include "external/glad_gles2.h" - #else - #define GL_GLEXT_PROTOTYPES - //#include // EGL library -> not required, platform layer - #include // OpenGL ES 2.0 library - #include // OpenGL ES 2.0 extensions library - #endif // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi // provided headers (despite being defined in official Khronos GLES2 headers) - #if defined(PLATFORM_DRM) + #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor); #endif #endif -#include // Required for: malloc(), free() -#include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] -#include // Required for: sqrtf(), sinf(), cosf(), floor(), log() - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#ifndef PI - #define PI 3.14159265358979323846f -#endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif - #ifndef GL_SHADING_LANGUAGE_VERSION #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #endif @@ -950,14 +750,6 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #endif -#ifndef GL_PROGRAM_POINT_SIZE - #define GL_PROGRAM_POINT_SIZE 0x8642 -#endif - -#ifndef GL_LINE_WIDTH - #define GL_LINE_WIDTH 0x0B21 -#endif - #if defined(GRAPHICS_API_OPENGL_11) #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 @@ -971,70 +763,28 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #if defined(GRAPHICS_API_OPENGL_ES2) #define glClearDepth glClearDepthf - #if !defined(GRAPHICS_API_OPENGL_ES3) - #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER - #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER - #endif + #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER + #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER #endif // Default shader vertex attribute names to set location points -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION - #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION +#ifndef DEFAULT_SHADER_ATTRIB_NAME_POSITION + #define DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD +#ifndef DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD + #define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL +#ifndef DEFAULT_SHADER_ATTRIB_NAME_NORMAL + #define DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR +#ifndef DEFAULT_SHADER_ATTRIB_NAME_COLOR + #define DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT +#ifndef DEFAULT_SHADER_ATTRIB_NAME_TANGENT + #define DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS - #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS - #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX - #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX -#endif - -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP - #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW - #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION - #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL - #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL - #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)) -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR - #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES - #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices -#endif -#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 - #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) -#endif -#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 - #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) -#endif -#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 - #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) +#ifndef DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 + #define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 #endif //---------------------------------------------------------------------------------- @@ -1042,62 +792,45 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) typedef struct rlglData { - rlRenderBatch *currentBatch; // Current render batch - rlRenderBatch defaultBatch; // Default internal render batch + RenderBatch *currentBatch; // Current render batch + RenderBatch defaultBatch; // Default internal render batch struct { - int vertexCounter; // Current active render batch vertex counter (generic, used for all batches) - float texcoordx, texcoordy; // Current active texture coordinate (added on glVertex*()) - float normalx, normaly, normalz; // Current active normal (added on glVertex*()) - unsigned char colorr, colorg, colorb, colora; // Current active color (added on glVertex*()) - int currentMatrixMode; // Current matrix mode Matrix *currentMatrix; // Current matrix pointer Matrix modelview; // Default modelview matrix Matrix projection; // Default projection matrix Matrix transform; // Transform matrix to be used with rlTranslate, rlRotate, rlScale bool transformRequired; // Require transform matrix application to current draw-call vertex (if required) - Matrix stack[RL_MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop + Matrix stack[MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop int stackCounter; // Matrix stack counter unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader) - unsigned int activeTextureId[RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS]; // Active texture ids to be enabled on batch drawing (0 active by default) + unsigned int activeTextureId[MAX_BATCH_ACTIVE_TEXTURES]; // Active texture ids to be enabled on batch drawing (0 active by default) unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) - unsigned int defaultFShaderId; // Default fragment shader id (used by default shader program) - unsigned int defaultShaderId; // Default shader program id, supports vertex color and diffuse texture - int *defaultShaderLocs; // Default shader locations pointer to be used on rendering - unsigned int currentShaderId; // Current shader id to be used on rendering (by default, defaultShaderId) - int *currentShaderLocs; // Current shader locations pointer to be used on rendering (by default, defaultShaderLocs) + unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) + Shader defaultShader; // Basic shader, support vertex color and diffuse texture + Shader currentShader; // Shader to be used on rendering (by default, defaultShader) bool stereoRender; // Stereo rendering flag Matrix projectionStereo[2]; // VR stereo rendering eyes projection matrices Matrix viewOffsetStereo[2]; // VR stereo rendering eyes view offset matrices - // Blending variables int currentBlendMode; // Blending mode active int glBlendSrcFactor; // Blending source factor int glBlendDstFactor; // Blending destination factor int glBlendEquation; // Blending equation - int glBlendSrcFactorRGB; // Blending source RGB factor - int glBlendDestFactorRGB; // Blending destination RGB factor - int glBlendSrcFactorAlpha; // Blending source alpha factor - int glBlendDestFactorAlpha; // Blending destination alpha factor - int glBlendEquationRGB; // Blending equation for RGB - int glBlendEquationAlpha; // Blending equation for alpha - bool glCustomBlendModeModified; // Custom blending factor and equation modification status - int framebufferWidth; // Current framebuffer width - int framebufferHeight; // Current framebuffer height + int framebufferWidth; // Default framebuffer width + int framebufferHeight; // Default framebuffer height } State; // Renderer state struct { bool vao; // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object) bool instancing; // Instancing supported (GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced + GL_EXT_instanced_arrays) bool texNPOT; // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot) - bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_OES_depth_texture) - bool texDepthWebGL; // Depth textures supported WebGL specific (GL_WEBGL_depth_texture) + bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_WEBGL_depth_texture, GL_OES_depth_texture) bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_float) - bool texFloat16; // half float textures support (16 bit per channel) (GL_OES_texture_half_float) bool texCompDXT; // DDS texture compression support (GL_EXT_texture_compression_s3tc, GL_WEBGL_compressed_texture_s3tc, GL_WEBKIT_WEBGL_compressed_texture_s3tc) bool texCompETC1; // ETC1 texture compression support (GL_OES_compressed_ETC1_RGB8_texture, GL_WEBGL_compressed_texture_etc1) bool texCompETC2; // ETC2/EAC texture compression support (GL_ARB_ES3_compatibility) @@ -1105,8 +838,6 @@ typedef struct rlglData { bool texCompASTC; // ASTC texture compression support (GL_KHR_texture_compression_astc_hdr, GL_KHR_texture_compression_astc_ldr) bool texMirrorClamp; // Clamp mirror wrap mode supported (GL_EXT_texture_mirror_clamp) bool texAnisoFilter; // Anisotropic texture filtering support (GL_EXT_texture_filter_anisotropic) - bool computeShader; // Compute shaders support (GL_ARB_compute_shader) - bool ssbo; // Shader storage buffer object support (GL_ARB_shader_storage_buffer_object) float maxAnisotropyLevel; // Maximum anisotropy level supported (minimum is 2.0f) int maxDepthBits; // Maximum bits for depth component @@ -1121,14 +852,11 @@ typedef void *(*rlglLoadProc)(const char *name); // OpenGL extension functions //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static double rlCullDistanceNear = RL_CULL_DISTANCE_NEAR; -static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR; - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static rlglData RLGL = { 0 }; #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 -#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3) +#if defined(GRAPHICS_API_OPENGL_ES2) // NOTE: VAO functionality is exposed through extensions (OES) static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL; static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL; @@ -1144,26 +872,18 @@ static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; // Module specific Functions Declaration //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -static void rlLoadShaderDefault(void); // Load default shader -static void rlUnloadShaderDefault(void); // Unload default shader -#if defined(RLGL_SHOW_GL_DETAILS_INFO) -static const char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name -#endif // RLGL_SHOW_GL_DETAILS_INFO +static void rlLoadShaderDefault(void); // Load default shader (RLGL.State.defaultShader) +static void rlUnloadShaderDefault(void); // Unload default shader (RLGL.State.defaultShader) +#if defined(SUPPORT_GL_DETAILS_INFO) +static char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name +#endif // SUPPORT_GL_DETAILS_INFO #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 - +#if defined(GRAPHICS_API_OPENGL_11) +static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side +static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight); // Generate next mipmap level on CPU side +#endif static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) -// Auxiliar matrix math functions -typedef struct rl_float16 { - float v[16]; -} rl_float16; -static rl_float16 rlMatrixToFloatV(Matrix mat); // Get float array of matrix data -#define rlMatrixToFloat(mat) (rlMatrixToFloatV(mat).v) // Get float vector for Matrix -static Matrix rlMatrixIdentity(void); // Get identity matrix -static Matrix rlMatrixMultiply(Matrix left, Matrix right); // Multiply two matrices -static Matrix rlMatrixTranspose(Matrix mat); // Transposes provided matrix -static Matrix rlMatrixInvert(Matrix mat); // Invert provided matrix - //---------------------------------------------------------------------------------- // Module Functions Definition - Matrix operations //---------------------------------------------------------------------------------- @@ -1196,9 +916,9 @@ void rlPushMatrix(void) { glPushMatrix(); } void rlPopMatrix(void) { glPopMatrix(); } void rlLoadIdentity(void) { glLoadIdentity(); } void rlTranslatef(float x, float y, float z) { glTranslatef(x, y, z); } -void rlRotatef(float angle, float x, float y, float z) { glRotatef(angle, x, y, z); } +void rlRotatef(float angleDeg, float x, float y, float z) { glRotatef(angleDeg, x, y, z); } void rlScalef(float x, float y, float z) { glScalef(x, y, z); } -void rlMultMatrixf(const float *matf) { glMultMatrixf(matf); } +void rlMultMatrixf(float *matf) { glMultMatrixf(matf); } #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Choose the current matrix to be transformed @@ -1214,7 +934,7 @@ void rlMatrixMode(int mode) // Push the current matrix into RLGL.State.stack void rlPushMatrix(void) { - if (RLGL.State.stackCounter >= RL_MAX_MATRIX_STACK_SIZE) TRACELOG(RL_LOG_ERROR, "RLGL: Matrix stack overflow (RL_MAX_MATRIX_STACK_SIZE)"); + if (RLGL.State.stackCounter >= MAX_MATRIX_STACK_SIZE) TRACELOG(LOG_ERROR, "RLGL: Matrix stack overflow (MAX_MATRIX_STACK_SIZE)"); if (RLGL.State.currentMatrixMode == RL_MODELVIEW) { @@ -1246,84 +966,41 @@ void rlPopMatrix(void) // Reset current matrix to identity matrix void rlLoadIdentity(void) { - *RLGL.State.currentMatrix = rlMatrixIdentity(); + *RLGL.State.currentMatrix = MatrixIdentity(); } // Multiply the current matrix by a translation matrix void rlTranslatef(float x, float y, float z) { - Matrix matTranslation = { - 1.0f, 0.0f, 0.0f, x, - 0.0f, 1.0f, 0.0f, y, - 0.0f, 0.0f, 1.0f, z, - 0.0f, 0.0f, 0.0f, 1.0f - }; + Matrix matTranslation = MatrixTranslate(x, y, z); // NOTE: We transpose matrix with multiplication order - *RLGL.State.currentMatrix = rlMatrixMultiply(matTranslation, *RLGL.State.currentMatrix); + *RLGL.State.currentMatrix = MatrixMultiply(matTranslation, *RLGL.State.currentMatrix); } // Multiply the current matrix by a rotation matrix -// NOTE: The provided angle must be in degrees -void rlRotatef(float angle, float x, float y, float z) +void rlRotatef(float angleDeg, float x, float y, float z) { - Matrix matRotation = rlMatrixIdentity(); + Matrix matRotation = MatrixIdentity(); - // Axis vector (x, y, z) normalization - float lengthSquared = x*x + y*y + z*z; - if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) - { - float inverseLength = 1.0f/sqrtf(lengthSquared); - x *= inverseLength; - y *= inverseLength; - z *= inverseLength; - } - - // Rotation matrix generation - float sinres = sinf(DEG2RAD*angle); - float cosres = cosf(DEG2RAD*angle); - float t = 1.0f - cosres; - - matRotation.m0 = x*x*t + cosres; - matRotation.m1 = y*x*t + z*sinres; - matRotation.m2 = z*x*t - y*sinres; - matRotation.m3 = 0.0f; - - matRotation.m4 = x*y*t - z*sinres; - matRotation.m5 = y*y*t + cosres; - matRotation.m6 = z*y*t + x*sinres; - matRotation.m7 = 0.0f; - - matRotation.m8 = x*z*t + y*sinres; - matRotation.m9 = y*z*t - x*sinres; - matRotation.m10 = z*z*t + cosres; - matRotation.m11 = 0.0f; - - matRotation.m12 = 0.0f; - matRotation.m13 = 0.0f; - matRotation.m14 = 0.0f; - matRotation.m15 = 1.0f; + Vector3 axis = (Vector3){ x, y, z }; + matRotation = MatrixRotate(Vector3Normalize(axis), angleDeg*DEG2RAD); // NOTE: We transpose matrix with multiplication order - *RLGL.State.currentMatrix = rlMatrixMultiply(matRotation, *RLGL.State.currentMatrix); + *RLGL.State.currentMatrix = MatrixMultiply(matRotation, *RLGL.State.currentMatrix); } // Multiply the current matrix by a scaling matrix void rlScalef(float x, float y, float z) { - Matrix matScale = { - x, 0.0f, 0.0f, 0.0f, - 0.0f, y, 0.0f, 0.0f, - 0.0f, 0.0f, z, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; + Matrix matScale = MatrixScale(x, y, z); // NOTE: We transpose matrix with multiplication order - *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix); + *RLGL.State.currentMatrix = MatrixMultiply(matScale, *RLGL.State.currentMatrix); } // Multiply the current matrix by another matrix -void rlMultMatrixf(const float *matf) +void rlMultMatrixf(float *matf) { // Matrix creation from array Matrix mat = { matf[0], matf[4], matf[8], matf[12], @@ -1331,99 +1008,34 @@ void rlMultMatrixf(const float *matf) matf[2], matf[6], matf[10], matf[14], matf[3], matf[7], matf[11], matf[15] }; - *RLGL.State.currentMatrix = rlMatrixMultiply(mat, *RLGL.State.currentMatrix); + *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, mat); } // Multiply the current matrix by a perspective matrix generated by parameters void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar) { - Matrix matFrustum = { 0 }; + Matrix matPerps = MatrixFrustum(left, right, bottom, top, znear, zfar); - float rl = (float)(right - left); - float tb = (float)(top - bottom); - float fn = (float)(zfar - znear); - - matFrustum.m0 = ((float) znear*2.0f)/rl; - matFrustum.m1 = 0.0f; - matFrustum.m2 = 0.0f; - matFrustum.m3 = 0.0f; - - matFrustum.m4 = 0.0f; - matFrustum.m5 = ((float) znear*2.0f)/tb; - matFrustum.m6 = 0.0f; - matFrustum.m7 = 0.0f; - - matFrustum.m8 = ((float)right + (float)left)/rl; - matFrustum.m9 = ((float)top + (float)bottom)/tb; - matFrustum.m10 = -((float)zfar + (float)znear)/fn; - matFrustum.m11 = -1.0f; - - matFrustum.m12 = 0.0f; - matFrustum.m13 = 0.0f; - matFrustum.m14 = -((float)zfar*(float)znear*2.0f)/fn; - matFrustum.m15 = 0.0f; - - *RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matFrustum); + *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matPerps); } // Multiply the current matrix by an orthographic matrix generated by parameters void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) { - // NOTE: If left-right and top-botton values are equal it could create a division by zero, - // response to it is platform/compiler dependant - Matrix matOrtho = { 0 }; + // NOTE: If left-right and top-botton values are equal it could create + // a division by zero on MatrixOrtho(), response to it is platform/compiler dependant + Matrix matOrtho = MatrixOrtho(left, right, bottom, top, znear, zfar); - float rl = (float)(right - left); - float tb = (float)(top - bottom); - float fn = (float)(zfar - znear); - - matOrtho.m0 = 2.0f/rl; - matOrtho.m1 = 0.0f; - matOrtho.m2 = 0.0f; - matOrtho.m3 = 0.0f; - matOrtho.m4 = 0.0f; - matOrtho.m5 = 2.0f/tb; - matOrtho.m6 = 0.0f; - matOrtho.m7 = 0.0f; - matOrtho.m8 = 0.0f; - matOrtho.m9 = 0.0f; - matOrtho.m10 = -2.0f/fn; - matOrtho.m11 = 0.0f; - matOrtho.m12 = -((float)left + (float)right)/rl; - matOrtho.m13 = -((float)top + (float)bottom)/tb; - matOrtho.m14 = -((float)zfar + (float)znear)/fn; - matOrtho.m15 = 1.0f; - - *RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matOrtho); + *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matOrtho); } #endif // Set the viewport area (transformation from normalized device coordinates to window coordinates) -// NOTE: We store current viewport dimensions void rlViewport(int x, int y, int width, int height) { glViewport(x, y, width, height); } -// Set clip planes distances -void rlSetClipPlanes(double nearPlane, double farPlane) -{ - rlCullDistanceNear = nearPlane; - rlCullDistanceFar = farPlane; -} - -// Get cull plane distance near -double rlGetCullDistanceNear(void) -{ - return rlCullDistanceNear; -} - -// Get cull plane distance far -double rlGetCullDistanceFar(void) -{ - return rlCullDistanceFar; -} - //---------------------------------------------------------------------------------- // Module Functions Definition - Vertex level operations //---------------------------------------------------------------------------------- @@ -1441,7 +1053,7 @@ void rlBegin(int mode) } } -void rlEnd(void) { glEnd(); } +void rlEnd() { glEnd(); } void rlVertex2i(int x, int y) { glVertex2i(x, y); } void rlVertex2f(float x, float y) { glVertex2f(x, y); } void rlVertex3f(float x, float y, float z) { glVertex3f(x, y, z); } @@ -1457,106 +1069,111 @@ void rlBegin(int mode) { // Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS // NOTE: In all three cases, vertex are accumulated over default internal vertex buffer - if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode != mode) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode != mode) { - if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0) { // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, // that way, following QUADS drawing will keep aligned with index processing // It implies adding some extra alignment vertex at the end of the draw, // those vertex are not processed but they are considered as an additional offset // for the next set of vertex to be drawn - if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4); - else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4))); - else RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = 0; + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4); + else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4))); + else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0; - if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment)) + if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment)) { - RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; - RLGL.currentBatch->drawCounter++; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + + RLGL.currentBatch->drawsCounter++; } } - if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); + if (RLGL.currentBatch->drawsCounter >= DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = mode; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode = mode; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = RLGL.State.defaultTextureId; } } // Finish vertex providing void rlEnd(void) { + // Make sure vertexCount is the same for vertices, texcoords, colors and normals + // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls + + // Make sure colors count match vertex count + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter != RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter) + { + int addColors = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter; + + for (int i = 0; i < addColors; i++) + { + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 4]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 1] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 3]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 2] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 2]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 3] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 1]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter++; + } + } + + // Make sure texcoords count match vertex count + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter != RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter) + { + int addTexCoords = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter; + + for (int i = 0; i < addTexCoords; i++) + { + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter] = 0.0f; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter + 1] = 0.0f; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter++; + } + } + + // TODO: Make sure normals count match vertex count... if normals support is added in a future... :P + // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values, // as well as depth buffer bit-depth (16bit or 24bit or 32bit) // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) RLGL.currentBatch->currentDepth += (1.0f/20000.0f); + + // Verify internal buffers limits + // NOTE: This check is combined with usage of rlCheckRenderBatchLimit() + if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter) >= + (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4 - 4)) + { + // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlDrawRenderBatch(), + // we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call! + // If we have multiple matrix pushed, it will require "RLGL.State.stackCounter" pops before launching the draw + for (int i = RLGL.State.stackCounter; i >= 0; i--) rlPopMatrix(); + rlDrawRenderBatch(RLGL.currentBatch); + } } // Define one vertex (position) // NOTE: Vertex position data is the basic information required for drawing void rlVertex3f(float x, float y, float z) { - float tx = x; - float ty = y; - float tz = z; + Vector3 vec = { x, y, z }; // Transform provided vector if required - if (RLGL.State.transformRequired) + if (RLGL.State.transformRequired) vec = Vector3Transform(vec, RLGL.State.transform); + + // Verify that current vertex buffer elements limit has not been reached + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter < (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) { - tx = RLGL.State.transform.m0*x + RLGL.State.transform.m4*y + RLGL.State.transform.m8*z + RLGL.State.transform.m12; - ty = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z + RLGL.State.transform.m13; - tz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z + RLGL.State.transform.m14; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter] = vec.x; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 1] = vec.y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 2] = vec.z; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter++; + + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount++; } - - // WARNING: We can't break primitives when launching a new batch - // RL_LINES comes in pairs, RL_TRIANGLES come in groups of 3 vertices and RL_QUADS come in groups of 4 vertices - // We must check current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4 - if (RLGL.State.vertexCounter > (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4 - 4)) - { - if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) && - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%2 == 0)) - { - // Reached the maximum number of vertices for RL_LINES drawing - // Launch a draw call but keep current state for next vertices comming - // NOTE: We add +1 vertex to the check for security - rlCheckRenderBatchLimit(2 + 1); - } - else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) && - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%3 == 0)) - { - rlCheckRenderBatchLimit(3 + 1); - } - else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_QUADS) && - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4 == 0)) - { - rlCheckRenderBatchLimit(4 + 1); - } - } - - // Add vertices - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.State.vertexCounter] = tx; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.State.vertexCounter + 1] = ty; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.State.vertexCounter + 2] = tz; - - // Add current texcoord - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.State.vertexCounter] = RLGL.State.texcoordx; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.State.vertexCounter + 1] = RLGL.State.texcoordy; - - // Add current normal - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].normals[3*RLGL.State.vertexCounter] = RLGL.State.normalx; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].normals[3*RLGL.State.vertexCounter + 1] = RLGL.State.normaly; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].normals[3*RLGL.State.vertexCounter + 2] = RLGL.State.normalz; - - // Add current color - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter] = RLGL.State.colorr; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter + 1] = RLGL.State.colorg; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter + 2] = RLGL.State.colorb; - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter + 3] = RLGL.State.colora; - - RLGL.State.vertexCounter++; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount++; + else TRACELOG(LOG_ERROR, "RLGL: Batch elements overflow"); } // Define one vertex (position) @@ -1575,43 +1192,26 @@ void rlVertex2i(int x, int y) // NOTE: Texture coordinates are limited to QUADS only void rlTexCoord2f(float x, float y) { - RLGL.State.texcoordx = x; - RLGL.State.texcoordy = y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter] = x; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter + 1] = y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter++; } // Define one vertex (normal) // NOTE: Normals limited to TRIANGLES only? void rlNormal3f(float x, float y, float z) { - float normalx = x; - float normaly = y; - float normalz = z; - if (RLGL.State.transformRequired) - { - normalx = RLGL.State.transform.m0*x + RLGL.State.transform.m4*y + RLGL.State.transform.m8*z; - normaly = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z; - normalz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z; - } - float length = sqrtf(normalx*normalx + normaly*normaly + normalz*normalz); - if (length != 0.0f) - { - float ilength = 1.0f/length; - normalx *= ilength; - normaly *= ilength; - normalz *= ilength; - } - RLGL.State.normalx = normalx; - RLGL.State.normaly = normaly; - RLGL.State.normalz = normalz; + // TODO: Normals usage... } // Define one vertex (color) void rlColor4ub(unsigned char x, unsigned char y, unsigned char z, unsigned char w) { - RLGL.State.colorr = x; - RLGL.State.colorg = y; - RLGL.State.colorb = z; - RLGL.State.colora = w; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter] = x; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 1] = y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 2] = z; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 3] = w; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter++; } // Define one vertex (color) @@ -1641,8 +1241,8 @@ void rlSetTexture(unsigned int id) rlDisableTexture(); #else // NOTE: If quads batch limit is reached, we force a draw call and next batch starts - if (RLGL.State.vertexCounter >= - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4) + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter >= + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4) { rlDrawRenderBatch(RLGL.currentBatch); } @@ -1653,31 +1253,33 @@ void rlSetTexture(unsigned int id) #if defined(GRAPHICS_API_OPENGL_11) rlEnableTexture(id); #else - if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId != id) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId != id) { - if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0) { // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, // that way, following QUADS drawing will keep aligned with index processing // It implies adding some extra alignment vertex at the end of the draw, // those vertex are not processed but they are considered as an additional offset // for the next set of vertex to be drawn - if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4); - else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4))); - else RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = 0; + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4); + else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4))); + else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0; - if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment)) + if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment)) { - RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; - RLGL.currentBatch->drawCounter++; + RLGL.currentBatch->drawsCounter++; } } - if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); + if (RLGL.currentBatch->drawsCounter >= DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = id; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = id; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0; } #endif } @@ -1713,6 +1315,7 @@ void rlDisableTexture(void) void rlEnableTextureCubemap(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glEnable(GL_TEXTURE_CUBE_MAP); // Core in OpenGL 1.4 glBindTexture(GL_TEXTURE_CUBE_MAP, id); #endif } @@ -1721,6 +1324,7 @@ void rlEnableTextureCubemap(unsigned int id) void rlDisableTextureCubemap(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDisable(GL_TEXTURE_CUBE_MAP); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); #endif } @@ -1730,11 +1334,6 @@ void rlTextureParameters(unsigned int id, int param, int value) { glBindTexture(GL_TEXTURE_2D, id); -#if !defined(GRAPHICS_API_OPENGL_11) - // Reset anisotropy filter, in case it was set - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); -#endif - switch (param) { case RL_TEXTURE_WRAP_S: @@ -1744,10 +1343,11 @@ void rlTextureParameters(unsigned int id, int param, int value) { #if !defined(GRAPHICS_API_OPENGL_11) if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_2D, param, value); - else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); + else TRACELOG(LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); #endif } else glTexParameteri(GL_TEXTURE_2D, param, value); + } break; case RL_TEXTURE_MAG_FILTER: case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break; @@ -1757,64 +1357,18 @@ void rlTextureParameters(unsigned int id, int param, int value) if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) { - TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, (int)RLGL.ExtSupported.maxAnisotropyLevel); + TRACELOG(LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, RLGL.ExtSupported.maxAnisotropyLevel); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); } - else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported"); + else TRACELOG(LOG_WARNING, "GL: Anisotropic filtering not supported"); #endif } break; -#if defined(GRAPHICS_API_OPENGL_33) - case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, value/100.0f); -#endif default: break; } glBindTexture(GL_TEXTURE_2D, 0); } -// Set cubemap parameters (wrap mode/filter mode) -void rlCubemapParameters(unsigned int id, int param, int value) -{ -#if !defined(GRAPHICS_API_OPENGL_11) - glBindTexture(GL_TEXTURE_CUBE_MAP, id); - - // Reset anisotropy filter, in case it was set - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); - - switch (param) - { - case RL_TEXTURE_WRAP_S: - case RL_TEXTURE_WRAP_T: - { - if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP) - { - if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); - else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); - } - else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); - } break; - case RL_TEXTURE_MAG_FILTER: - case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break; - case RL_TEXTURE_FILTER_ANISOTROPIC: - { - if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); - else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) - { - TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, (int)RLGL.ExtSupported.maxAnisotropyLevel); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); - } - else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported"); - } break; -#if defined(GRAPHICS_API_OPENGL_33) - case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, value/100.0f); -#endif - default: break; - } - - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); -#endif -} - // Enable shader program void rlEnableShader(unsigned int id) { @@ -1834,88 +1388,19 @@ void rlDisableShader(void) // Enable rendering to texture (fbo) void rlEnableFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) glBindFramebuffer(GL_FRAMEBUFFER, id); #endif } -// return the active render texture (fbo) -unsigned int rlGetActiveFramebuffer(void) -{ - GLint fboId = 0; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT) - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId); -#endif - return fboId; -} - // Disable rendering to texture void rlDisableFramebuffer(void) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif } -// Blit active framebuffer to main framebuffer -void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, int bufferMask) -{ -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT) - glBlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask, GL_NEAREST); -#endif -} - -// Bind framebuffer object (fbo) -void rlBindFramebuffer(unsigned int target, unsigned int framebuffer) -{ -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) - glBindFramebuffer(target, framebuffer); -#endif -} - -// Activate multiple draw color buffers -// NOTE: One color buffer is always active by default -void rlActiveDrawBuffers(int count) -{ -#if ((defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT)) - // NOTE: Maximum number of draw buffers supported is implementation dependant, - // it can be queried with glGet*() but it must be at least 8 - //GLint maxDrawBuffers = 0; - //glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); - - if (count > 0) - { - if (count > 8) TRACELOG(LOG_WARNING, "GL: Max color buffers limited to 8"); - else - { - unsigned int buffers[8] = { - GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, - GL_COLOR_ATTACHMENT7, - }; - - glDrawBuffers(count, buffers); - } - } - else TRACELOG(LOG_WARNING, "GL: One color buffer active by default"); -#endif -} - -//---------------------------------------------------------------------------------- -// General render state configuration -//---------------------------------------------------------------------------------- - -// Enable color blending -void rlEnableColorBlend(void) { glEnable(GL_BLEND); } - -// Disable color blending -void rlDisableColorBlend(void) { glDisable(GL_BLEND); } - // Enable depth test void rlEnableDepthTest(void) { glEnable(GL_DEPTH_TEST); } @@ -1934,20 +1419,6 @@ void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); } // Disable backface culling void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); } -// Set color mask active for screen read/draw -void rlColorMask(bool r, bool g, bool b, bool a) { glColorMask(r, g, b, a); } - -// Set face culling mode -void rlSetCullFace(int mode) -{ - switch (mode) - { - case RL_CULL_FACE_BACK: glCullFace(GL_BACK); break; - case RL_CULL_FACE_FRONT: glCullFace(GL_FRONT); break; - default: break; - } -} - // Enable scissor test void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); } @@ -1974,28 +1445,11 @@ void rlDisableWireMode(void) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } - -// Enable point mode -void rlEnablePointMode(void) -{ -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - // NOTE: glPolygonMode() not available on OpenGL ES - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - glEnable(GL_PROGRAM_POINT_SIZE); -#endif -} - -// Disable point mode -void rlDisablePointMode(void) -{ -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - // NOTE: glPolygonMode() not available on OpenGL ES - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif -} - // Set the line drawing width -void rlSetLineWidth(float width) { glLineWidth(width); } +void rlSetLineWidth(float width) +{ + glLineWidth(width); +} // Get the line drawing width float rlGetLineWidth(void) @@ -2067,7 +1521,7 @@ void rlClearScreenBuffers(void) } // Check and log OpenGL error codes -void rlCheckErrors(void) +void rlCheckErrors() { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) int check = 1; @@ -2077,14 +1531,14 @@ void rlCheckErrors(void) switch (err) { case GL_NO_ERROR: check = 0; break; - case 0x0500: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_ENUM"); break; - case 0x0501: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_VALUE"); break; - case 0x0502: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_OPERATION"); break; - case 0x0503: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_STACK_OVERFLOW"); break; - case 0x0504: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_STACK_UNDERFLOW"); break; - case 0x0505: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_OUT_OF_MEMORY"); break; - case 0x0506: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_FRAMEBUFFER_OPERATION"); break; - default: TRACELOG(RL_LOG_WARNING, "GL: Error detected: Unknown error code: %x", err); break; + case 0x0500: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_ENUM"); break; + case 0x0501: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_VALUE"); break; + case 0x0502: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_OPERATION"); break; + case 0x0503: TRACELOG(LOG_WARNING, "GL: Error detected: GL_STACK_OVERFLOW"); break; + case 0x0504: TRACELOG(LOG_WARNING, "GL: Error detected: GL_STACK_UNDERFLOW"); break; + case 0x0505: TRACELOG(LOG_WARNING, "GL: Error detected: GL_OUT_OF_MEMORY"); break; + case 0x0506: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_FRAMEBUFFER_OPERATION"); break; + default: TRACELOG(LOG_WARNING, "GL: Error detected: Unknown error code: %x", err); break; } } #endif @@ -2094,34 +1548,22 @@ void rlCheckErrors(void) void rlSetBlendMode(int mode) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((RLGL.State.currentBlendMode != mode) || ((mode == RL_BLEND_CUSTOM || mode == RL_BLEND_CUSTOM_SEPARATE) && RLGL.State.glCustomBlendModeModified)) + if (RLGL.State.currentBlendMode != mode) { rlDrawRenderBatch(RLGL.currentBatch); switch (mode) { - case RL_BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; - case RL_BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; - case RL_BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; - case RL_BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; - case RL_BLEND_SUBTRACT_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_SUBTRACT); break; - case RL_BLEND_ALPHA_PREMULTIPLY: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; - case RL_BLEND_CUSTOM: - { - // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors() - glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); - } break; - case RL_BLEND_CUSTOM_SEPARATE: - { - // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate() - glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha); - glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha); - } break; + case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; + case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; + case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; + case BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; + case BLEND_SUBTRACT_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_SUBTRACT); break; + case BLEND_CUSTOM: glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); break; default: break; } RLGL.State.currentBlendMode = mode; - RLGL.State.glCustomBlendModeModified = false; } #endif } @@ -2130,102 +1572,12 @@ void rlSetBlendMode(int mode) void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((RLGL.State.glBlendSrcFactor != glSrcFactor) || - (RLGL.State.glBlendDstFactor != glDstFactor) || - (RLGL.State.glBlendEquation != glEquation)) - { - RLGL.State.glBlendSrcFactor = glSrcFactor; - RLGL.State.glBlendDstFactor = glDstFactor; - RLGL.State.glBlendEquation = glEquation; - - RLGL.State.glCustomBlendModeModified = true; - } + RLGL.State.glBlendSrcFactor = glSrcFactor; + RLGL.State.glBlendDstFactor = glDstFactor; + RLGL.State.glBlendEquation = glEquation; #endif } -// Set blending mode factor and equation separately for RGB and alpha -void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((RLGL.State.glBlendSrcFactorRGB != glSrcRGB) || - (RLGL.State.glBlendDestFactorRGB != glDstRGB) || - (RLGL.State.glBlendSrcFactorAlpha != glSrcAlpha) || - (RLGL.State.glBlendDestFactorAlpha != glDstAlpha) || - (RLGL.State.glBlendEquationRGB != glEqRGB) || - (RLGL.State.glBlendEquationAlpha != glEqAlpha)) - { - RLGL.State.glBlendSrcFactorRGB = glSrcRGB; - RLGL.State.glBlendDestFactorRGB = glDstRGB; - RLGL.State.glBlendSrcFactorAlpha = glSrcAlpha; - RLGL.State.glBlendDestFactorAlpha = glDstAlpha; - RLGL.State.glBlendEquationRGB = glEqRGB; - RLGL.State.glBlendEquationAlpha = glEqAlpha; - - RLGL.State.glCustomBlendModeModified = true; - } -#endif -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - OpenGL Debug -//---------------------------------------------------------------------------------- -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) -static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) -{ - // Ignore non-significant error/warning codes (NVidia drivers) - // NOTE: Here there are the details with a sample output: - // - #131169 - Framebuffer detailed info: The driver allocated storage for renderbuffer 2. (severity: low) - // - #131185 - Buffer detailed info: Buffer object 1 (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint is GL_ENUM_88e4) - // will use VIDEO memory as the source for buffer object operations. (severity: low) - // - #131218 - Program/shader state performance warning: Vertex shader in program 7 is being recompiled based on GL state. (severity: medium) - // - #131204 - Texture state usage warning: The texture object (0) bound to texture image unit 0 does not have - // a defined base level and cannot be used for texture mapping. (severity: low) - if ((id == 131169) || (id == 131185) || (id == 131218) || (id == 131204)) return; - - const char *msgSource = NULL; - switch (source) - { - case GL_DEBUG_SOURCE_API: msgSource = "API"; break; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: msgSource = "WINDOW_SYSTEM"; break; - case GL_DEBUG_SOURCE_SHADER_COMPILER: msgSource = "SHADER_COMPILER"; break; - case GL_DEBUG_SOURCE_THIRD_PARTY: msgSource = "THIRD_PARTY"; break; - case GL_DEBUG_SOURCE_APPLICATION: msgSource = "APPLICATION"; break; - case GL_DEBUG_SOURCE_OTHER: msgSource = "OTHER"; break; - default: break; - } - - const char *msgType = NULL; - switch (type) - { - case GL_DEBUG_TYPE_ERROR: msgType = "ERROR"; break; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: msgType = "DEPRECATED_BEHAVIOR"; break; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: msgType = "UNDEFINED_BEHAVIOR"; break; - case GL_DEBUG_TYPE_PORTABILITY: msgType = "PORTABILITY"; break; - case GL_DEBUG_TYPE_PERFORMANCE: msgType = "PERFORMANCE"; break; - case GL_DEBUG_TYPE_MARKER: msgType = "MARKER"; break; - case GL_DEBUG_TYPE_PUSH_GROUP: msgType = "PUSH_GROUP"; break; - case GL_DEBUG_TYPE_POP_GROUP: msgType = "POP_GROUP"; break; - case GL_DEBUG_TYPE_OTHER: msgType = "OTHER"; break; - default: break; - } - - const char *msgSeverity = "DEFAULT"; - switch (severity) - { - case GL_DEBUG_SEVERITY_LOW: msgSeverity = "LOW"; break; - case GL_DEBUG_SEVERITY_MEDIUM: msgSeverity = "MEDIUM"; break; - case GL_DEBUG_SEVERITY_HIGH: msgSeverity = "HIGH"; break; - case GL_DEBUG_SEVERITY_NOTIFICATION: msgSeverity = "NOTIFICATION"; break; - default: break; - } - - TRACELOG(LOG_WARNING, "GL: OpenGL debug message: %s", message); - TRACELOG(LOG_WARNING, " > Type: %s", msgType); - TRACELOG(LOG_WARNING, " > Source = %s", msgSource); - TRACELOG(LOG_WARNING, " > Severity = %s", msgSeverity); -} -#endif - //---------------------------------------------------------------------------------- // Module Functions Definition - rlgl functionality //---------------------------------------------------------------------------------- @@ -2233,49 +1585,29 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint // Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states void rlglInit(int width, int height) { - // Enable OpenGL debug context if required -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) - if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL)) - { - glDebugMessageCallback(rlDebugMessageCallback, 0); - // glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DEBUG_SEVERITY_HIGH, 0, 0, GL_TRUE); - - // Debug context options: - // - GL_DEBUG_OUTPUT - Faster version but not useful for breakpoints - // - GL_DEBUG_OUTPUT_SYNCHRONUS - Callback is in sync with errors, so a breakpoint can be placed on the callback in order to get a stacktrace for the GL error - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - } -#endif - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Init default white texture unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) - RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); - if (RLGL.State.defaultTextureId != 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId); - else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load default texture"); + if (RLGL.State.defaultTextureId != 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId); + else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load default texture"); // Init default Shader (customized for GL 3.3 and ES2) - // Loaded: RLGL.State.defaultShaderId + RLGL.State.defaultShaderLocs - rlLoadShaderDefault(); - RLGL.State.currentShaderId = RLGL.State.defaultShaderId; - RLGL.State.currentShaderLocs = RLGL.State.defaultShaderLocs; + rlLoadShaderDefault(); // RLGL.State.defaultShader + RLGL.State.currentShader = RLGL.State.defaultShader; // Init default vertex arrays buffers - // Simulate that the default shader has the location RL_SHADER_LOC_VERTEX_NORMAL to bind the normal buffer for the default render batch - RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL] = RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL; - RLGL.defaultBatch = rlLoadRenderBatch(RL_DEFAULT_BATCH_BUFFERS, RL_DEFAULT_BATCH_BUFFER_ELEMENTS); - RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL] = -1; + RLGL.defaultBatch = rlLoadRenderBatch(DEFAULT_BATCH_BUFFERS, DEFAULT_BATCH_BUFFER_ELEMENTS); RLGL.currentBatch = &RLGL.defaultBatch; // Init stack matrices (emulating OpenGL 1.1) - for (int i = 0; i < RL_MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = rlMatrixIdentity(); + for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = MatrixIdentity(); // Init internal matrices - RLGL.State.transform = rlMatrixIdentity(); - RLGL.State.projection = rlMatrixIdentity(); - RLGL.State.modelview = rlMatrixIdentity(); + RLGL.State.transform = MatrixIdentity(); + RLGL.State.projection = MatrixIdentity(); + RLGL.State.modelview = MatrixIdentity(); RLGL.State.currentMatrix = &RLGL.State.modelview; #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 @@ -2311,7 +1643,7 @@ void rlglInit(int width, int height) RLGL.State.framebufferWidth = width; RLGL.State.framebufferHeight = height; - TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); + TRACELOG(LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); //---------------------------------------------------------- #endif @@ -2330,7 +1662,7 @@ void rlglClose(void) rlUnloadShaderDefault(); // Unload default shader glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture - TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); #endif } @@ -2340,101 +1672,59 @@ void rlLoadExtensions(void *loader) { #if defined(GRAPHICS_API_OPENGL_33) // Also defined for GRAPHICS_API_OPENGL_21 // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions) - if (gladLoadGL((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL extensions"); - else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL extensions loaded successfully"); + #if !defined(__APPLE__) + if (!gladLoadGLLoader((GLADloadproc)loader)) TRACELOG(LOG_WARNING, "GLAD: Cannot load OpenGL extensions"); + else TRACELOG(LOG_INFO, "GLAD: OpenGL extensions loaded successfully"); + #endif // Get number of supported extensions GLint numExt = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); - TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); + TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt); -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if defined(SUPPORT_GL_DETAILS_INFO) // Get supported extensions list // WARNING: glGetStringi() not available on OpenGL 2.1 - TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:"); - for (int i = 0; i < numExt; i++) TRACELOG(RL_LOG_INFO, " %s", glGetStringi(GL_EXTENSIONS, i)); + char **extList = RL_MALLOC(numExt*sizeof(char *)); + TRACELOG(LOG_INFO, "GL: OpenGL extensions:"); + for (int i = 0; i < numExt; i++) + { + extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i); + TRACELOG(LOG_INFO, " %s", extList[i]); + } + RL_FREE(extList); // Free extensions pointers #endif -#if defined(GRAPHICS_API_OPENGL_21) - // Register supported extensions flags - // Optional OpenGL 2.1 extensions - RLGL.ExtSupported.vao = GLAD_GL_ARB_vertex_array_object; - RLGL.ExtSupported.instancing = (GLAD_GL_EXT_draw_instanced && GLAD_GL_ARB_instanced_arrays); - RLGL.ExtSupported.texNPOT = GLAD_GL_ARB_texture_non_power_of_two; - RLGL.ExtSupported.texFloat32 = GLAD_GL_ARB_texture_float; - RLGL.ExtSupported.texFloat16 = GLAD_GL_ARB_texture_float; - RLGL.ExtSupported.texDepth = GLAD_GL_ARB_depth_texture; - RLGL.ExtSupported.maxDepthBits = 32; - RLGL.ExtSupported.texAnisoFilter = GLAD_GL_EXT_texture_filter_anisotropic; - RLGL.ExtSupported.texMirrorClamp = GLAD_GL_EXT_texture_mirror_clamp; -#else // Register supported extensions flags // OpenGL 3.3 extensions supported by default (core) RLGL.ExtSupported.vao = true; RLGL.ExtSupported.instancing = true; RLGL.ExtSupported.texNPOT = true; RLGL.ExtSupported.texFloat32 = true; - RLGL.ExtSupported.texFloat16 = true; RLGL.ExtSupported.texDepth = true; RLGL.ExtSupported.maxDepthBits = 32; RLGL.ExtSupported.texAnisoFilter = true; RLGL.ExtSupported.texMirrorClamp = true; -#endif - - // Optional OpenGL 3.3 extensions - RLGL.ExtSupported.texCompASTC = GLAD_GL_KHR_texture_compression_astc_hdr && GLAD_GL_KHR_texture_compression_astc_ldr; - RLGL.ExtSupported.texCompDXT = GLAD_GL_EXT_texture_compression_s3tc; // Texture compression: DXT - RLGL.ExtSupported.texCompETC2 = GLAD_GL_ARB_ES3_compatibility; // Texture compression: ETC2/EAC - #if defined(GRAPHICS_API_OPENGL_43) - RLGL.ExtSupported.computeShader = GLAD_GL_ARB_compute_shader; - RLGL.ExtSupported.ssbo = GLAD_GL_ARB_shader_storage_buffer_object; + #if !defined(__APPLE__) + // NOTE: With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans + if (GLAD_GL_EXT_texture_compression_s3tc) RLGL.ExtSupported.texCompDXT = true; // Texture compression: DXT + if (GLAD_GL_ARB_ES3_compatibility) RLGL.ExtSupported.texCompETC2 = true; // Texture compression: ETC2/EAC #endif - #endif // GRAPHICS_API_OPENGL_33 -#if defined(GRAPHICS_API_OPENGL_ES3) - // Register supported extensions flags - // OpenGL ES 3.0 extensions supported by default (or it should be) - RLGL.ExtSupported.vao = true; - RLGL.ExtSupported.instancing = true; - RLGL.ExtSupported.texNPOT = true; - RLGL.ExtSupported.texFloat32 = true; - RLGL.ExtSupported.texFloat16 = true; - RLGL.ExtSupported.texDepth = true; - RLGL.ExtSupported.texDepthWebGL = true; - RLGL.ExtSupported.maxDepthBits = 24; - RLGL.ExtSupported.texAnisoFilter = true; - RLGL.ExtSupported.texMirrorClamp = true; - // TODO: Check for additional OpenGL ES 3.0 supported extensions: - //RLGL.ExtSupported.texCompDXT = true; - //RLGL.ExtSupported.texCompETC1 = true; - //RLGL.ExtSupported.texCompETC2 = true; - //RLGL.ExtSupported.texCompPVRT = true; - //RLGL.ExtSupported.texCompASTC = true; - //RLGL.ExtSupported.maxAnisotropyLevel = true; - //RLGL.ExtSupported.computeShader = true; - //RLGL.ExtSupported.ssbo = true; - -#elif defined(GRAPHICS_API_OPENGL_ES2) - - #if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL) - // TODO: Support GLAD loader for OpenGL ES 3.0 - if (gladLoadGLES2((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL ES2.0 functions"); - else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL ES 2.0 loaded successfully"); - #endif - +#if defined(GRAPHICS_API_OPENGL_ES2) // Get supported extensions list GLint numExt = 0; - const char **extList = (const char **)RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB) + const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB) const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string // NOTE: We have to duplicate string because glGetString() returns a const string - int size = strlen(extensions) + 1; // Get extensions string size in bytes - char *extensionsDup = (char *)RL_CALLOC(size, sizeof(char)); + int len = strlen(extensions) + 1; + char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char)); strcpy(extensionsDup, extensions); extList[numExt] = extensionsDup; - for (int i = 0; i < size; i++) + for (int i = 0; i < len; i++) { if (extensionsDup[i] == ' ') { @@ -2444,11 +1734,11 @@ void rlLoadExtensions(void *loader) } } - TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); + TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt); -#if defined(RLGL_SHOW_GL_DETAILS_INFO) - TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:"); - for (int i = 0; i < numExt; i++) TRACELOG(RL_LOG_INFO, " %s", extList[i]); +#if defined(SUPPORT_GL_DETAILS_INFO) + TRACELOG(LOG_INFO, "GL: OpenGL extensions:"); + for (int i = 0; i < numExt; i++) TRACELOG(LOG_INFO, " %s", extList[i]); #endif // Check required extensions @@ -2469,47 +1759,25 @@ void rlLoadExtensions(void *loader) } // Check instanced rendering support - if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) // Broad check for instanced_arrays + if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // Web ANGLE { - // Specific check - if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // ANGLE - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); - } - else if (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0) // EXT + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); + + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; + } + else + { + if ((strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) && // Standard EXT + (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0)) { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT"); - } - else if (strcmp(extList[i], (const char *)"GL_NV_instanced_arrays") == 0) // NVIDIA GLES - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV"); - } - // The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present - if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; - } - else if (strstr(extList[i], (const char *)"draw_instanced") != NULL) - { - // GL_ANGLE_draw_instanced doesn't exist - if (strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; } - else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0) - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); - } - - // But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist - if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; } // Check NPOT textures support @@ -2518,15 +1786,13 @@ void rlLoadExtensions(void *loader) // Check texture float support if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) RLGL.ExtSupported.texFloat32 = true; - if (strcmp(extList[i], (const char *)"GL_OES_texture_half_float") == 0) RLGL.ExtSupported.texFloat16 = true; // Check depth texture support - if (strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) RLGL.ExtSupported.texDepth = true; - if (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0) RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format - if (RLGL.ExtSupported.texDepthWebGL) RLGL.ExtSupported.texDepth = true; + if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) RLGL.ExtSupported.texDepth = true; - if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL - if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL + if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; + if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Check texture compression support: DXT if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || @@ -2561,11 +1827,11 @@ void rlLoadExtensions(void *loader) // Check OpenGL information and capabilities //------------------------------------------------------------------------------ // Show current OpenGL and GLSL version - TRACELOG(RL_LOG_INFO, "GL: OpenGL device information:"); - TRACELOG(RL_LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR)); - TRACELOG(RL_LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER)); - TRACELOG(RL_LOG_INFO, " > Version: %s", glGetString(GL_VERSION)); - TRACELOG(RL_LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); + TRACELOG(LOG_INFO, "GL: OpenGL device information:"); + TRACELOG(LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR)); + TRACELOG(LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER)); + TRACELOG(LOG_INFO, " > Version: %s", glGetString(GL_VERSION)); + TRACELOG(LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // NOTE: Anisotropy levels capability is an extension @@ -2574,166 +1840,140 @@ void rlLoadExtensions(void *loader) #endif glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel); -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if defined(SUPPORT_GL_DETAILS_INFO) // Show some OpenGL GPU capabilities - TRACELOG(RL_LOG_INFO, "GL: OpenGL capabilities:"); + TRACELOG(LOG_INFO, "GL: OpenGL capabilities:"); GLint capability = 0; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_TEXTURE_SIZE: %i", capability); + TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_SIZE: %i", capability); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_CUBE_MAP_TEXTURE_SIZE: %i", capability); + TRACELOG(LOG_INFO, " GL_MAX_CUBE_MAP_TEXTURE_SIZE: %i", capability); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_TEXTURE_IMAGE_UNITS: %i", capability); + TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_IMAGE_UNITS: %i", capability); glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_VERTEX_ATTRIBS: %i", capability); + TRACELOG(LOG_INFO, " GL_MAX_VERTEX_ATTRIBS: %i", capability); #if !defined(GRAPHICS_API_OPENGL_ES2) glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_UNIFORM_BLOCK_SIZE: %i", capability); + TRACELOG(LOG_INFO, " GL_MAX_UNIFORM_BLOCK_SIZE: %i", capability); glGetIntegerv(GL_MAX_DRAW_BUFFERS, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_DRAW_BUFFERS: %i", capability); - if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(RL_LOG_INFO, " GL_MAX_TEXTURE_MAX_ANISOTROPY: %.0f", RLGL.ExtSupported.maxAnisotropyLevel); + TRACELOG(LOG_INFO, " GL_MAX_DRAW_BUFFERS: %i", capability); + if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_MAX_ANISOTROPY: %.0f", RLGL.ExtSupported.maxAnisotropyLevel); #endif glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &capability); - TRACELOG(RL_LOG_INFO, " GL_NUM_COMPRESSED_TEXTURE_FORMATS: %i", capability); - GLint *compFormats = (GLint *)RL_CALLOC(capability, sizeof(GLint)); - glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, compFormats); - for (int i = 0; i < capability; i++) TRACELOG(RL_LOG_INFO, " %s", rlGetCompressedFormatName(compFormats[i])); - RL_FREE(compFormats); + TRACELOG(LOG_INFO, " GL_NUM_COMPRESSED_TEXTURE_FORMATS: %i", capability); + GLint format[32] = { 0 }; + glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format); + for (int i = 0; i < capability; i++) TRACELOG(LOG_INFO, " %s", rlGetCompressedFormatName(format[i])); -#if defined(GRAPHICS_API_OPENGL_43) + /* + // Following capabilities are only supported by OpenGL 4.3 or greater glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability); + TRACELOG(LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability); glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &capability); - TRACELOG(RL_LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability); -#endif // GRAPHICS_API_OPENGL_43 -#else // RLGL_SHOW_GL_DETAILS_INFO + TRACELOG(LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability); + */ +#else // SUPPORT_GL_DETAILS_INFO // Show some basic info about GL supported features - if (RLGL.ExtSupported.vao) TRACELOG(RL_LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully"); - else TRACELOG(RL_LOG_WARNING, "GL: VAO extension not found, VAO not supported"); - if (RLGL.ExtSupported.texNPOT) TRACELOG(RL_LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported"); - else TRACELOG(RL_LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)"); - if (RLGL.ExtSupported.texCompDXT) TRACELOG(RL_LOG_INFO, "GL: DXT compressed textures supported"); - if (RLGL.ExtSupported.texCompETC1) TRACELOG(RL_LOG_INFO, "GL: ETC1 compressed textures supported"); - if (RLGL.ExtSupported.texCompETC2) TRACELOG(RL_LOG_INFO, "GL: ETC2/EAC compressed textures supported"); - if (RLGL.ExtSupported.texCompPVRT) TRACELOG(RL_LOG_INFO, "GL: PVRT compressed textures supported"); - if (RLGL.ExtSupported.texCompASTC) TRACELOG(RL_LOG_INFO, "GL: ASTC compressed textures supported"); - if (RLGL.ExtSupported.computeShader) TRACELOG(RL_LOG_INFO, "GL: Compute shaders supported"); - if (RLGL.ExtSupported.ssbo) TRACELOG(RL_LOG_INFO, "GL: Shader storage buffer objects supported"); -#endif // RLGL_SHOW_GL_DETAILS_INFO + #if defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully"); + else TRACELOG(LOG_WARNING, "GL: VAO extension not found, VAO not supported"); + if (RLGL.ExtSupported.texNPOT) TRACELOG(LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported"); + else TRACELOG(LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)"); + #endif + if (RLGL.ExtSupported.texCompDXT) TRACELOG(LOG_INFO, "GL: DXT compressed textures supported"); + if (RLGL.ExtSupported.texCompETC1) TRACELOG(LOG_INFO, "GL: ETC1 compressed textures supported"); + if (RLGL.ExtSupported.texCompETC2) TRACELOG(LOG_INFO, "GL: ETC2/EAC compressed textures supported"); + if (RLGL.ExtSupported.texCompPVRT) TRACELOG(LOG_INFO, "GL: PVRT compressed textures supported"); + if (RLGL.ExtSupported.texCompASTC) TRACELOG(LOG_INFO, "GL: ASTC compressed textures supported"); +#endif // SUPPORT_GL_DETAILS_INFO #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 } -// Get current OpenGL version +// Returns current OpenGL version int rlGetVersion(void) { - int glVersion = 0; #if defined(GRAPHICS_API_OPENGL_11) - glVersion = RL_OPENGL_11; + return OPENGL_11; #endif #if defined(GRAPHICS_API_OPENGL_21) - glVersion = RL_OPENGL_21; -#elif defined(GRAPHICS_API_OPENGL_43) - glVersion = RL_OPENGL_43; + #if defined(__APPLE__) + return OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX + #else + return OPENGL_21; + #endif #elif defined(GRAPHICS_API_OPENGL_33) - glVersion = RL_OPENGL_33; + return OPENGL_33; #endif -#if defined(GRAPHICS_API_OPENGL_ES3) - glVersion = RL_OPENGL_ES_30; -#elif defined(GRAPHICS_API_OPENGL_ES2) - glVersion = RL_OPENGL_ES_20; -#endif - - return glVersion; -} - -// Set current framebuffer width -void rlSetFramebufferWidth(int width) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - RLGL.State.framebufferWidth = width; -#endif -} - -// Set current framebuffer height -void rlSetFramebufferHeight(int height) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - RLGL.State.framebufferHeight = height; +#if defined(GRAPHICS_API_OPENGL_ES2) + return OPENGL_ES_20; #endif } // Get default framebuffer width int rlGetFramebufferWidth(void) { - int width = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - width = RLGL.State.framebufferWidth; + return RLGL.State.framebufferWidth; +#else + return 0; #endif - return width; } // Get default framebuffer height int rlGetFramebufferHeight(void) { - int height = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - height = RLGL.State.framebufferHeight; + return RLGL.State.framebufferHeight; +#else + return 0; +#endif +} + +// Get default internal shader (simple texture + tint color) +Shader rlGetShaderDefault(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + return RLGL.State.defaultShader; +#else + Shader shader = { 0 }; + return shader; #endif - return height; } // Get default internal texture (white texture) -// NOTE: Default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 -unsigned int rlGetTextureIdDefault(void) +Texture2D rlGetTextureDefault(void) { - unsigned int id = 0; + Texture2D texture = { 0 }; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - id = RLGL.State.defaultTextureId; + texture.id = RLGL.State.defaultTextureId; + texture.width = 1; + texture.height = 1; + texture.mipmaps = 1; + texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; #endif - return id; -} - -// Get default shader id -unsigned int rlGetShaderIdDefault(void) -{ - unsigned int id = 0; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - id = RLGL.State.defaultShaderId; -#endif - return id; -} - -// Get default shader locs -int *rlGetShaderLocsDefault(void) -{ - int *locs = NULL; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - locs = RLGL.State.defaultShaderLocs; -#endif - return locs; + return texture; } // Render batch management //------------------------------------------------------------------------------------------------ // Load render batch -rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) +RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) { - rlRenderBatch batch = { 0 }; + RenderBatch batch = { 0 }; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes) //-------------------------------------------------------------------------------------------- - batch.vertexBuffer = (rlVertexBuffer *)RL_MALLOC(numBuffers*sizeof(rlVertexBuffer)); + batch.vertexBuffer = (VertexBuffer *)RL_MALLOC(numBuffers*sizeof(VertexBuffer)); for (int i = 0; i < numBuffers; i++) { - batch.vertexBuffer[i].elementCount = bufferElements; + batch.vertexBuffer[i].elementsCount = bufferElements; batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(bufferElements*2*4*sizeof(float)); // 2 float by texcoord, 4 texcoord by quad - batch.vertexBuffer[i].normals = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(bufferElements*4*4*sizeof(unsigned char)); // 4 float by color, 4 colors by quad #if defined(GRAPHICS_API_OPENGL_33) batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(bufferElements*6*sizeof(unsigned int)); // 6 int by quad (indices) @@ -2744,7 +1984,6 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f; for (int j = 0; j < (2*4*bufferElements); j++) batch.vertexBuffer[i].texcoords[j] = 0.0f; - for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].normals[j] = 0.0f; for (int j = 0; j < (4*4*bufferElements); j++) batch.vertexBuffer[i].colors[j] = 0; int k = 0; @@ -2762,10 +2001,12 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) k++; } - RLGL.State.vertexCounter = 0; + batch.vertexBuffer[i].vCounter = 0; + batch.vertexBuffer[i].tcCounter = 0; + batch.vertexBuffer[i].cCounter = 0; } - TRACELOG(RL_LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)"); + TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)"); //-------------------------------------------------------------------------------------------- // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs @@ -2784,33 +2025,26 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[0]); glBufferData(GL_ARRAY_BUFFER, bufferElements*3*4*sizeof(float), batch.vertexBuffer[i].vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION]); + glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); // Vertex texcoord buffer (shader-location = 1) glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]); glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[1]); glBufferData(GL_ARRAY_BUFFER, bufferElements*2*4*sizeof(float), batch.vertexBuffer[i].texcoords, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); - - // Vertex normal buffer (shader-location = 2) - glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]); - glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]); - glBufferData(GL_ARRAY_BUFFER, bufferElements*3*4*sizeof(float), batch.vertexBuffer[i].normals, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL], 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); + glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); // Vertex color buffer (shader-location = 3) - glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]); - glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]); + glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]); glBufferData(GL_ARRAY_BUFFER, bufferElements*4*4*sizeof(unsigned char), batch.vertexBuffer[i].colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR]); + glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); // Fill index buffer - glGenBuffers(1, &batch.vertexBuffer[i].vboId[4]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[4]); + glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]); #if defined(GRAPHICS_API_OPENGL_33) glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(int), batch.vertexBuffer[i].indices, GL_STATIC_DRAW); #endif @@ -2819,7 +2053,7 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) #endif } - TRACELOG(RL_LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)"); + TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)"); // Unbind the current VAO if (RLGL.ExtSupported.vao) glBindVertexArray(0); @@ -2827,9 +2061,9 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) // Init draw calls tracking system //-------------------------------------------------------------------------------------------- - batch.draws = (rlDrawCall *)RL_MALLOC(RL_DEFAULT_BATCH_DRAWCALLS*sizeof(rlDrawCall)); + batch.draws = (DrawCall *)RL_MALLOC(DEFAULT_BATCH_DRAWCALLS*sizeof(DrawCall)); - for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++) + for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++) { batch.draws[i].mode = RL_QUADS; batch.draws[i].vertexCount = 0; @@ -2837,12 +2071,12 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) //batch.draws[i].vaoId = 0; //batch.draws[i].shaderId = 0; batch.draws[i].textureId = RLGL.State.defaultTextureId; - //batch.draws[i].RLGL.State.projection = rlMatrixIdentity(); - //batch.draws[i].RLGL.State.modelview = rlMatrixIdentity(); + //batch.draws[i].RLGL.State.projection = MatrixIdentity(); + //batch.draws[i].RLGL.State.modelview = MatrixIdentity(); } - batch.bufferCount = numBuffers; // Record buffer count - batch.drawCounter = 1; // Reset draws counter + batch.buffersCount = numBuffers; // Record buffer count + batch.drawsCounter = 1; // Reset draws counter batch.currentDepth = -1.0f; // Reset depth value //-------------------------------------------------------------------------------------------- #endif @@ -2851,33 +2085,26 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) } // Unload default internal buffers vertex data from CPU and GPU -void rlUnloadRenderBatch(rlRenderBatch batch) +void rlUnloadRenderBatch(RenderBatch batch) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Unbind everything + if (RLGL.ExtSupported.vao) glBindVertexArray(0); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unload all vertex buffers data - for (int i = 0; i < batch.bufferCount; i++) + for (int i = 0; i < batch.buffersCount; i++) { - // Unbind VAO attribs data - if (RLGL.ExtSupported.vao) - { - glBindVertexArray(batch.vertexBuffer[i].vaoId); - glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); - glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); - glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); - glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR); - glBindVertexArray(0); - } - // Delete VBOs from GPU (VRAM) glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[0]); glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[1]); glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[2]); glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[3]); - glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[4]); // Delete VAOs from GPU (VRAM) if (RLGL.ExtSupported.vao) glDeleteVertexArrays(1, &batch.vertexBuffer[i].vaoId); @@ -2885,7 +2112,6 @@ void rlUnloadRenderBatch(rlRenderBatch batch) // Free vertex arrays memory from CPU (RAM) RL_FREE(batch.vertexBuffer[i].vertices); RL_FREE(batch.vertexBuffer[i].texcoords); - RL_FREE(batch.vertexBuffer[i].normals); RL_FREE(batch.vertexBuffer[i].colors); RL_FREE(batch.vertexBuffer[i].indices); } @@ -2898,43 +2124,38 @@ void rlUnloadRenderBatch(rlRenderBatch batch) // Draw render batch // NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer) -void rlDrawRenderBatch(rlRenderBatch *batch) +void rlDrawRenderBatch(RenderBatch *batch) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Update batch vertex buffers //------------------------------------------------------------------------------------------------------------ // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) - // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (use a change detector flag?) - if (RLGL.State.vertexCounter > 0) + // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) + if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0) { // Activate elements VAO if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); // Vertex positions buffer glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); - glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer + glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer // Texture coordinates buffer glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]); - glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*2*sizeof(float), batch->vertexBuffer[batch->currentBuffer].texcoords); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer - - // Normals buffer - glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); - glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].normals); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].normals, GL_DYNAMIC_DRAW); // Update all buffer + glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*2*sizeof(float), batch->vertexBuffer[batch->currentBuffer].texcoords); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer // Colors buffer - glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]); - glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*4*sizeof(unsigned char), batch->vertexBuffer[batch->currentBuffer].colors); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); + glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*4*sizeof(unsigned char), batch->vertexBuffer[batch->currentBuffer].colors); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer - // NOTE: glMapBuffer() causes sync issue - // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job - // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer() + // NOTE: glMapBuffer() causes sync issue. + // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job. + // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer(). // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new - // allocated pointer immediately even if GPU is still working with the previous data + // allocated pointer immediately even if GPU is still working with the previous data. // Another option: map the buffer object into client's memory // Probably this code could be moved somewhere else... @@ -2955,88 +2176,60 @@ void rlDrawRenderBatch(rlRenderBatch *batch) Matrix matProjection = RLGL.State.projection; Matrix matModelView = RLGL.State.modelview; - int eyeCount = 1; - if (RLGL.State.stereoRender) eyeCount = 2; + int eyesCount = 1; + if (RLGL.State.stereoRender) eyesCount = 2; - for (int eye = 0; eye < eyeCount; eye++) + for (int eye = 0; eye < eyesCount; eye++) { - if (eyeCount == 2) + if (eyesCount == 2) { // Setup current eye viewport (half screen width) rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight); // Set current eye view offset to modelview matrix - rlSetMatrixModelview(rlMatrixMultiply(matModelView, RLGL.State.viewOffsetStereo[eye])); + rlSetMatrixModelview(MatrixMultiply(matModelView, RLGL.State.viewOffsetStereo[eye])); // Set current eye projection matrix rlSetMatrixProjection(RLGL.State.projectionStereo[eye]); } // Draw buffers - if (RLGL.State.vertexCounter > 0) + if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0) { // Set current shader and upload current MVP matrix - glUseProgram(RLGL.State.currentShaderId); + glUseProgram(RLGL.State.currentShader.id); // Create modelview-projection matrix and upload to shader - Matrix matMVP = rlMatrixMultiply(RLGL.State.modelview, RLGL.State.projection); - glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MVP], 1, false, rlMatrixToFloat(matMVP)); - - if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_PROJECTION] != -1) - { - glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_PROJECTION], 1, false, rlMatrixToFloat(RLGL.State.projection)); - } - - // WARNING: For the following setup of the view, model, and normal matrices, it is expected that - // transformations and rendering occur between rlPushMatrix() and rlPopMatrix() - - if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_VIEW] != -1) - { - glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_VIEW], 1, false, rlMatrixToFloat(RLGL.State.modelview)); - } - - if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MODEL] != -1) - { - glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MODEL], 1, false, rlMatrixToFloat(RLGL.State.transform)); - } - - if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_NORMAL] != -1) - { - glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_NORMAL], 1, false, rlMatrixToFloat(rlMatrixTranspose(rlMatrixInvert(RLGL.State.transform)))); - } + Matrix matMVP = MatrixMultiply(RLGL.State.modelview, RLGL.State.projection); + glUniformMatrix4fv(RLGL.State.currentShader.locs[SHADER_LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP)); if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); else { // Bind vertex attrib: position (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION]); + glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION]); // Bind vertex attrib: texcoord (shader-location = 1) glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01]); - - // Bind vertex attrib: normal (shader-location = 2) - glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL]); + glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]); - glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR]); + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); + glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[4]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]); } // Setup some default shader values - glUniform4f(RLGL.State.currentShaderLocs[RL_SHADER_LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f); - glUniform1i(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MAP_DIFFUSE], 0); // Active default sampler2D: texture0 + glUniform4f(RLGL.State.currentShader.locs[SHADER_LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f); + glUniform1i(RLGL.State.currentShader.locs[SHADER_LOC_MAP_DIFFUSE], 0); // Active default sampler2D: texture0 // Activate additional sampler textures // Those additional textures will be common for all draw calls of the batch - for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) + for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++) { if (RLGL.State.activeTextureId[i] > 0) { @@ -3049,23 +2242,23 @@ void rlDrawRenderBatch(rlRenderBatch *batch) // NOTE: Batch system accumulates calls by texture0 changes, additional textures are enabled for all the draw calls glActiveTexture(GL_TEXTURE0); - for (int i = 0, vertexOffset = 0; i < batch->drawCounter; i++) + for (int i = 0, vertexOffset = 0; i < batch->drawsCounter; i++) { - // Bind current draw call texture, activated as GL_TEXTURE0 and bound to sampler2D texture0 by default + // Bind current draw call texture, activated as GL_TEXTURE0 and binded to sampler2D texture0 by default glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId); if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount); else { - #if defined(GRAPHICS_API_OPENGL_33) - // We need to define the number of indices to be processed: elementCount*6 +#if defined(GRAPHICS_API_OPENGL_33) + // We need to define the number of indices to be processed: quadsCount*6 // NOTE: The final parameter tells the GPU the offset in bytes from the // start of the index buffer to the location of the first index to process glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint))); - #endif - #if defined(GRAPHICS_API_OPENGL_ES2) +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(vertexOffset/4*6*sizeof(GLushort))); - #endif +#endif } vertexOffset += (batch->draws[i].vertexCount + batch->draws[i].vertexAlignment); @@ -3084,15 +2277,14 @@ void rlDrawRenderBatch(rlRenderBatch *batch) glUseProgram(0); // Unbind shader program } - - // Restore viewport to default measures - if (eyeCount == 2) rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); //------------------------------------------------------------------------------------------------------------ // Reset batch buffers //------------------------------------------------------------------------------------------------------------ - // Reset vertex counter for next frame - RLGL.State.vertexCounter = 0; + // Reset vertex counters for next frame + batch->vertexBuffer[batch->currentBuffer].vCounter = 0; + batch->vertexBuffer[batch->currentBuffer].tcCounter = 0; + batch->vertexBuffer[batch->currentBuffer].cCounter = 0; // Reset depth for next draw batch->currentDepth = -1.0f; @@ -3102,7 +2294,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch) RLGL.State.modelview = matModelView; // Reset RLGL.currentBatch->draws array - for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++) + for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++) { batch->draws[i].mode = RL_QUADS; batch->draws[i].vertexCount = 0; @@ -3110,20 +2302,20 @@ void rlDrawRenderBatch(rlRenderBatch *batch) } // Reset active texture units for next batch - for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) RLGL.State.activeTextureId[i] = 0; + for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++) RLGL.State.activeTextureId[i] = 0; // Reset draws counter to one draw for the batch - batch->drawCounter = 1; + batch->drawsCounter = 1; //------------------------------------------------------------------------------------------------------------ // Change to next buffer in the list (in case of multi-buffering) batch->currentBuffer++; - if (batch->currentBuffer >= batch->bufferCount) batch->currentBuffer = 0; + if (batch->currentBuffer >= batch->buffersCount) batch->currentBuffer = 0; #endif } // Set the active render batch for rlgl -void rlSetRenderBatchActive(rlRenderBatch *batch) +void rlSetRenderBatchActive(RenderBatch *batch) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) rlDrawRenderBatch(RLGL.currentBatch); @@ -3142,26 +2334,17 @@ void rlDrawRenderBatchActive(void) } // Check internal buffer overflow for a given number of vertex -// and force a rlRenderBatch draw call if required +// and force a RenderBatch draw call if required bool rlCheckRenderBatchLimit(int vCount) { bool overflow = false; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((RLGL.State.vertexCounter + vCount) >= - (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4)) + if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + vCount) >= + (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) { overflow = true; - - // Store current primitive drawing mode and texture id - int currentMode = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode; - int currentTexture = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId; - rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside - - // Restore state of last batch so we can continue adding vertices - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = currentMode; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = currentTexture; } #endif @@ -3171,48 +2354,48 @@ bool rlCheckRenderBatchLimit(int vCount) // Textures data management //----------------------------------------------------------------------------------------- // Convert image data to OpenGL texture (returns OpenGL valid Id) -unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount) +unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount) { - unsigned int id = 0; - glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding + unsigned int id = 0; + // Check texture format support by OpenGL 1.1 (compressed textures not supported) #if defined(GRAPHICS_API_OPENGL_11) - if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) + if (format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) { - TRACELOG(RL_LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats"); + TRACELOG(LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats"); return id; } #else - if ((!RLGL.ExtSupported.texCompDXT) && ((format == RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) || (format == RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA) || - (format == RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) || (format == RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA))) + if ((!RLGL.ExtSupported.texCompDXT) && ((format == PIXELFORMAT_COMPRESSED_DXT1_RGB) || (format == PIXELFORMAT_COMPRESSED_DXT1_RGBA) || + (format == PIXELFORMAT_COMPRESSED_DXT3_RGBA) || (format == PIXELFORMAT_COMPRESSED_DXT5_RGBA))) { - TRACELOG(RL_LOG_WARNING, "GL: DXT compressed texture format not supported"); + TRACELOG(LOG_WARNING, "GL: DXT compressed texture format not supported"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((!RLGL.ExtSupported.texCompETC1) && (format == RL_PIXELFORMAT_COMPRESSED_ETC1_RGB)) + if ((!RLGL.ExtSupported.texCompETC1) && (format == PIXELFORMAT_COMPRESSED_ETC1_RGB)) { - TRACELOG(RL_LOG_WARNING, "GL: ETC1 compressed texture format not supported"); + TRACELOG(LOG_WARNING, "GL: ETC1 compressed texture format not supported"); return id; } - if ((!RLGL.ExtSupported.texCompETC2) && ((format == RL_PIXELFORMAT_COMPRESSED_ETC2_RGB) || (format == RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA))) + if ((!RLGL.ExtSupported.texCompETC2) && ((format == PIXELFORMAT_COMPRESSED_ETC2_RGB) || (format == PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA))) { - TRACELOG(RL_LOG_WARNING, "GL: ETC2 compressed texture format not supported"); + TRACELOG(LOG_WARNING, "GL: ETC2 compressed texture format not supported"); return id; } - if ((!RLGL.ExtSupported.texCompPVRT) && ((format == RL_PIXELFORMAT_COMPRESSED_PVRT_RGB) || (format == RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA))) + if ((!RLGL.ExtSupported.texCompPVRT) && ((format == PIXELFORMAT_COMPRESSED_PVRT_RGB) || (format == PIXELFORMAT_COMPRESSED_PVRT_RGBA))) { - TRACELOG(RL_LOG_WARNING, "GL: PVRT compressed texture format not supported"); + TRACELOG(LOG_WARNING, "GL: PVRT compressed texture format not supported"); return id; } - if ((!RLGL.ExtSupported.texCompASTC) && ((format == RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA) || (format == RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA))) + if ((!RLGL.ExtSupported.texCompASTC) && ((format == PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA) || (format == PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA))) { - TRACELOG(RL_LOG_WARNING, "GL: ASTC compressed texture format not supported"); + TRACELOG(LOG_WARNING, "GL: ASTC compressed texture format not supported"); return id; } #endif @@ -3226,11 +2409,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipWidth = width; int mipHeight = height; - int mipOffset = 0; // Mipmap data offset, only used for tracelog - - // NOTE: Added pointer math separately from function to avoid UBSAN complaining - unsigned char *dataPtr = NULL; - if (data != NULL) dataPtr = (unsigned char *)data; + int mipOffset = 0; // Mipmap data offset // Load the different mipmap levels for (int i = 0; i < mipmapCount; i++) @@ -3242,20 +2421,20 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); - if (glInternalFormat != 0) + if (glInternalFormat != -1) { - if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, dataPtr); + if (format < PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, (unsigned char *)data + mipOffset); #if !defined(GRAPHICS_API_OPENGL_11) - else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, dataPtr); + else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, (unsigned char *)data + mipOffset); #endif #if defined(GRAPHICS_API_OPENGL_33) - if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) + if (format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) { GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } - else if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) + else if (format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) { #if defined(GRAPHICS_API_OPENGL_21) GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; @@ -3269,8 +2448,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, mipWidth /= 2; mipHeight /= 2; - mipOffset += mipSize; // Increment offset position to next mipmap - if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap + mipOffset += mipSize; // Security check for NPOT textures if (mipWidth < 1) mipWidth = 1; @@ -3307,7 +2485,6 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, // Activate Trilinear filtering if mipmaps are available glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // Required for user-defined mip count } #endif @@ -3318,14 +2495,14 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, // Unbind current texture glBindTexture(GL_TEXTURE_2D, 0); - if (id > 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Texture loaded successfully (%ix%i | %s | %i mipmaps)", id, width, height, rlGetPixelFormatName(format), mipmapCount); - else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load texture"); + if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Texture loaded successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount); + else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load texture"); return id; } // Load depth texture/renderbuffer (to be attached to fbo) -// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture and WebGL requires WEBGL_depth_texture extensions +// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture/WEBGL_depth_texture extensions unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) { unsigned int id = 0; @@ -3338,15 +2515,10 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F unsigned int glInternalFormat = GL_DEPTH_COMPONENT; -#if (defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_ES3)) - // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT) - // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities - if (!RLGL.ExtSupported.texDepthWebGL || useRenderBuffer) - { - if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES; - else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; - else glInternalFormat = GL_DEPTH_COMPONENT16; - } +#if defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES; + else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; + else glInternalFormat = GL_DEPTH_COMPONENT16; #endif if (!useRenderBuffer && RLGL.ExtSupported.texDepth) @@ -3362,7 +2534,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) glBindTexture(GL_TEXTURE_2D, 0); - TRACELOG(RL_LOG_INFO, "TEXTURE: Depth texture loaded successfully"); + TRACELOG(LOG_INFO, "TEXTURE: Depth texture loaded successfully"); } else { @@ -3374,7 +2546,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) glBindRenderbuffer(GL_RENDERBUFFER, 0); - TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16); + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16); } #endif @@ -3384,17 +2556,11 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) // Load texture cubemap // NOTE: Cubemap data is expected to be 6 images in a single data array (one after the other), // expected the following convention: +X, -X, +Y, -Y, +Z, -Z -unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount) +unsigned int rlLoadTextureCubemap(void *data, int size, int format) { unsigned int id = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - int mipSize = size; - - // NOTE: Added pointer math separately from function to avoid UBSAN complaining - unsigned char *dataPtr = NULL; - if (data != NULL) dataPtr = (unsigned char *)data; - unsigned int dataSize = rlGetPixelDataSize(size, size, format); glGenTextures(1, &id); @@ -3403,39 +2569,39 @@ unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mi unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - if (glInternalFormat != 0) + if (glInternalFormat != -1) { - // Load cubemap faces/mipmaps - for (int i = 0; i < 6*mipmapCount; i++) + // Load cubemap faces + for (unsigned int i = 0; i < 6; i++) { - int mipmapLevel = i/6; - int face = i%6; - if (data == NULL) { - if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) + if (format < PIXELFORMAT_COMPRESSED_DXT1_RGB) { - if ((format == RL_PIXELFORMAT_UNCOMPRESSED_R32) || - (format == RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32) || - (format == RL_PIXELFORMAT_UNCOMPRESSED_R16) || - (format == RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) TRACELOG(RL_LOG_WARNING, "TEXTURES: Cubemap requested format not supported"); - else glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mipmapLevel, glInternalFormat, mipSize, mipSize, 0, glFormat, glType, NULL); + if (format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) + { + // Instead of using a sized internal texture format (GL_RGB16F, GL_RGB32F), we let the driver to choose the better format for us (GL_RGB) + if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL); + else TRACELOG(LOG_WARNING, "TEXTURES: Cubemap requested format not supported"); + } + else if ((format == PIXELFORMAT_UNCOMPRESSED_R32) || (format == PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "TEXTURES: Cubemap requested format not supported"); + else glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, glFormat, glType, NULL); } - else TRACELOG(RL_LOG_WARNING, "TEXTURES: Empty cubemap creation does not support compressed format"); + else TRACELOG(LOG_WARNING, "TEXTURES: Empty cubemap creation does not support compressed format"); } else { - if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mipmapLevel, glInternalFormat, mipSize, mipSize, 0, glFormat, glType, (unsigned char *)dataPtr + face*dataSize); - else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mipmapLevel, glInternalFormat, mipSize, mipSize, 0, dataSize, (unsigned char *)dataPtr + face*dataSize); + if (format < PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, glFormat, glType, (unsigned char *)data + i*dataSize); + else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, dataSize, (unsigned char *)data + i*dataSize); } #if defined(GRAPHICS_API_OPENGL_33) - if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) + if (format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) { GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } - else if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) + else if (format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) { #if defined(GRAPHICS_API_OPENGL_21) GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; @@ -3445,23 +2611,11 @@ unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mi glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } #endif - if (face == 5) - { - mipSize /= 2; - if (data != NULL) dataPtr += dataSize*6; // Increment data pointer to next mipmap - - // Security check for NPOT textures - if (mipSize < 1) mipSize = 1; - - dataSize = rlGetPixelDataSize(mipSize, mipSize, format); - } } } // Set cubemap texture sampling parameters - if (mipmapCount > 1) glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - else glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -3472,8 +2626,8 @@ unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mi glBindTexture(GL_TEXTURE_CUBE_MAP, 0); #endif - if (id > 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Cubemap texture loaded successfully (%ix%i)", id, size, size); - else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load cubemap texture"); + if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Cubemap texture loaded successfully (%ix%i)", id, size, size); + else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load cubemap texture"); return id; } @@ -3487,83 +2641,62 @@ void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int h unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) + if ((glInternalFormat != -1) && (format < PIXELFORMAT_COMPRESSED_DXT1_RGB)) { - glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, data); + glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, (unsigned char *)data); } - else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format); + else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format); } // Get OpenGL internal formats and data type from raylib PixelFormat void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType) { - *glInternalFormat = 0; - *glFormat = 0; - *glType = 0; + *glInternalFormat = -1; + *glFormat = -1; + *glType = -1; switch (format) { #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA - case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; #if !defined(GRAPHICS_API_OPENGL_11) - #if defined(GRAPHICS_API_OPENGL_ES3) - case RL_PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F_EXT; *glFormat = GL_RED_EXT; *glType = GL_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F_EXT; *glFormat = GL_RGB; *glType = GL_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F_EXT; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_R16F_EXT; *glFormat = GL_RED_EXT; *glType = GL_HALF_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB16F_EXT; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA16F_EXT; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT; break; - #else - case RL_PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - #if defined(GRAPHICS_API_OPENGL_21) - case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_ARB; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_ARB; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_ARB; break; - #else // defined(GRAPHICS_API_OPENGL_ES2) - case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float - #endif - #endif + case PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float #endif #elif defined(GRAPHICS_API_OPENGL_33) - case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_R16F; *glFormat = GL_RED; *glType = GL_HALF_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB16F; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA16F; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT; break; + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; + case PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; #endif #if !defined(GRAPHICS_API_OPENGL_11) - case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; - case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; - case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; - case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; - case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: if (RLGL.ExtSupported.texCompETC1) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 - case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 - case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case PIXELFORMAT_COMPRESSED_DXT1_RGB: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case PIXELFORMAT_COMPRESSED_DXT1_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + case PIXELFORMAT_COMPRESSED_DXT3_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + case PIXELFORMAT_COMPRESSED_DXT5_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + case PIXELFORMAT_COMPRESSED_ETC1_RGB: if (RLGL.ExtSupported.texCompETC1) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 + case PIXELFORMAT_COMPRESSED_ETC2_RGB: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case PIXELFORMAT_COMPRESSED_PVRT_RGB: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case PIXELFORMAT_COMPRESSED_PVRT_RGBA: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 #endif - default: TRACELOG(RL_LOG_WARNING, "TEXTURE: Current format not supported (%i)", format); break; + default: TRACELOG(LOG_WARNING, "TEXTURE: Current format not supported (%i)", format); break; } } @@ -3574,91 +2707,133 @@ void rlUnloadTexture(unsigned int id) } // Generate mipmap data for selected texture -// NOTE: Only supports GPU mipmap generation -void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps) +void rlGenerateMipmaps(Texture2D *texture) { -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindTexture(GL_TEXTURE_2D, id); + glBindTexture(GL_TEXTURE_2D, texture->id); // Check if texture is power-of-two (POT) bool texIsPOT = false; - if (((width > 0) && ((width & (width - 1)) == 0)) && - ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true; + if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) && + ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true; +#if defined(GRAPHICS_API_OPENGL_11) + if (texIsPOT) + { + // WARNING: Manual mipmap generation only works for RGBA 32bit textures! + if (texture->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + { + // Retrieve texture data from VRAM + void *texData = rlReadTexturePixels(*texture); + + // NOTE: Texture data size is reallocated to fit mipmaps data + // NOTE: CPU mipmap generation only supports RGBA 32bit data + int mipmapCount = rlGenerateMipmapsData(texData, texture->width, texture->height); + + int size = texture->width*texture->height*4; + int offset = size; + + int mipWidth = texture->width/2; + int mipHeight = texture->height/2; + + // Load the mipmaps + for (int level = 1; level < mipmapCount; level++) + { + glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)texData + offset); + + size = mipWidth*mipHeight*4; + offset += size; + + mipWidth /= 2; + mipHeight /= 2; + } + + texture->mipmaps = mipmapCount + 1; + RL_FREE(texData); // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data + + TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Mipmaps generated manually on CPU side, total: %i", texture->id, texture->mipmaps); + } + else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps for provided texture format", texture->id); + } +#endif +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if ((texIsPOT) || (RLGL.ExtSupported.texNPOT)) { - //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorithm: GL_FASTEST, GL_NICEST, GL_DONT_CARE + //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically - #define MIN(a,b) (((a)<(b))? (a):(b)) - #define MAX(a,b) (((a)>(b))? (a):(b)) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps - *mipmaps = 1 + (int)floor(log(MAX(width, height))/log(2)); - TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps); + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MAX(a,b) (((a)>(b))?(a):(b)) + + texture->mipmaps = 1 + (int)floor(log(MAX(texture->width, texture->height))/log(2)); + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", texture->id, texture->mipmaps); } - else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", id); +#endif + else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", texture->id); glBindTexture(GL_TEXTURE_2D, 0); -#else - TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] GPU mipmap generation not supported", id); -#endif } + // Read texture pixel data -void *rlReadTexturePixels(unsigned int id, int width, int height, int format) +void *rlReadTexturePixels(Texture2D texture) { void *pixels = NULL; #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - glBindTexture(GL_TEXTURE_2D, id); + glBindTexture(GL_TEXTURE_2D, texture.id); - // NOTE: Using texture id, we can retrieve some texture info (but not on OpenGL ES 2.0) + // NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0) // Possible texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE //int width, height, format; //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); - // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding - // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting + // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding. + // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting. // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.) glPixelStorei(GL_PACK_ALIGNMENT, 1); unsigned int glInternalFormat, glFormat, glType; - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - unsigned int size = rlGetPixelDataSize(width, height, format); + rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType); + unsigned int size = rlGetPixelDataSize(texture.width, texture.height, texture.format); - if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) + if ((glInternalFormat != -1) && (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB)) { pixels = RL_MALLOC(size); glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); } - else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", id, format); + else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", texture.id, texture.format); glBindTexture(GL_TEXTURE_2D, 0); #endif #if defined(GRAPHICS_API_OPENGL_ES2) // glGetTexImage() is not available on OpenGL ES 2.0 - // Texture width and height are required on OpenGL ES 2.0, there is no way to get it from texture id + // Texture width and height are required on OpenGL ES 2.0. There is no way to get it from texture id. // Two possible Options: // 1 - Bind texture to color fbo attachment and glReadPixels() // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() // We are using Option 1, just need to care for texture format on retrieval // NOTE: This behaviour could be conditioned by graphic driver... - unsigned int fboId = rlLoadFramebuffer(); + unsigned int fboId = rlLoadFramebuffer(texture.width, texture.height); + + // TODO: Create depth texture/renderbuffer for fbo? glBindFramebuffer(GL_FRAMEBUFFER, fboId); glBindTexture(GL_TEXTURE_2D, 0); // Attach our texture to FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0); // We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format - pixels = (unsigned char *)RL_MALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + pixels = (unsigned char *)RL_MALLOC(rlGetPixelDataSize(texture.width, texture.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)); + glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -3669,40 +2844,33 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) return pixels; } + // Read screen pixel data (color buffer) unsigned char *rlReadScreenPixels(int width, int height) { - unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); + unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly! - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData); // Flip image vertically! - // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! - for (int y = height - 1; y >= height/2; y--) + unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char)); + + for (int y = height - 1; y >= 0; y--) { - for (int x = 0; x < (width*4); x += 4) + for (int x = 0; x < (width*4); x++) { - unsigned int s = ((height - 1) - y)*width*4 + x; - unsigned int e = y*width*4 + x; + imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line - unsigned char r = imgData[s]; - unsigned char g = imgData[s+1]; - unsigned char b = imgData[s+2]; - - imgData[s] = imgData[e]; - imgData[s+1] = imgData[e+1]; - imgData[s+2] = imgData[e+2]; - imgData[s+3] = 255; // Set alpha component value to 255 (no trasparent image retrieval) - - imgData[e] = r; - imgData[e+1] = g; - imgData[e+2] = b; - imgData[e+3] = 255; // Ditto + // Set alpha component value to 255 (no trasparent image retrieval) + // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! + if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255; } } + RL_FREE(screenData); + return imgData; // NOTE: image data should be freed } @@ -3710,11 +2878,11 @@ unsigned char *rlReadScreenPixels(int width, int height) //----------------------------------------------------------------------------------------- // Load a framebuffer to be used for rendering // NOTE: No textures attached -unsigned int rlLoadFramebuffer(void) +unsigned int rlLoadFramebuffer(int width, int height) { unsigned int fboId = 0; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) glGenFramebuffers(1, &fboId); // Create the framebuffer object glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer #endif @@ -3726,7 +2894,7 @@ unsigned int rlLoadFramebuffer(void) // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) glBindFramebuffer(GL_FRAMEBUFFER, fboId); switch (attachType) @@ -3743,16 +2911,19 @@ void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel); else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId); else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel); + } break; case RL_ATTACHMENT_DEPTH: { if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel); else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId); + } break; case RL_ATTACHMENT_STENCIL: { if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel); else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId); + } break; default: break; } @@ -3766,7 +2937,7 @@ bool rlFramebufferComplete(unsigned int id) { bool result = false; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) glBindFramebuffer(GL_FRAMEBUFFER, id); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3775,12 +2946,12 @@ bool rlFramebufferComplete(unsigned int id) { switch (status) { - case GL_FRAMEBUFFER_UNSUPPORTED: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer is unsupported", id); break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete attachment", id); break; + case GL_FRAMEBUFFER_UNSUPPORTED: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer is unsupported", id); break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete attachment", id); break; #if defined(GRAPHICS_API_OPENGL_ES2) - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete dimensions", id); break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete dimensions", id); break; #endif - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer has a missing attachment", id); break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has a missing attachment", id); break; default: break; } } @@ -3797,35 +2968,32 @@ bool rlFramebufferComplete(unsigned int id) // NOTE: All attached textures/cubemaps/renderbuffers are also deleted void rlUnloadFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) + // Query depth attachment to automatically delete texture/renderbuffer int depthType = 0, depthId = 0; glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &depthType); - - // TODO: Review warning retrieving object name in WebGL - // WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name - // https://registry.khronos.org/webgl/specs/latest/1.0/ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId); unsigned int depthIdU = (unsigned int)depthId; if (depthType == GL_RENDERBUFFER) glDeleteRenderbuffers(1, &depthIdU); - else if (depthType == GL_TEXTURE) glDeleteTextures(1, &depthIdU); + else if (depthType == GL_RENDERBUFFER) glDeleteTextures(1, &depthIdU); // NOTE: If a texture object is deleted while its image is attached to the *currently bound* framebuffer, - // the texture image is automatically detached from the currently bound framebuffer + // the texture image is automatically detached from the currently bound framebuffer. glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &id); - TRACELOG(RL_LOG_INFO, "FBO: [ID %i] Unloaded framebuffer from VRAM (GPU)", id); + TRACELOG(LOG_INFO, "FBO: [ID %i] Unloaded framebuffer from VRAM (GPU)", id); #endif } // Vertex data management //----------------------------------------------------------------------------------------- // Load a new attributes buffer -unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) +unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic) { unsigned int id = 0; @@ -3839,7 +3007,7 @@ unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) } // Load a new attributes element buffer -unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic) +unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic) { unsigned int id = 0; @@ -3852,7 +3020,6 @@ unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynami return id; } -// Enable vertex buffer (VBO) void rlEnableVertexBuffer(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3860,7 +3027,6 @@ void rlEnableVertexBuffer(unsigned int id) #endif } -// Disable vertex buffer (VBO) void rlDisableVertexBuffer(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3868,7 +3034,6 @@ void rlDisableVertexBuffer(void) #endif } -// Enable vertex buffer element (VBO element) void rlEnableVertexBufferElement(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3876,7 +3041,6 @@ void rlEnableVertexBufferElement(unsigned int id) #endif } -// Disable vertex buffer element (VBO element) void rlDisableVertexBufferElement(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3884,27 +3048,16 @@ void rlDisableVertexBufferElement(void) #endif } -// Update vertex buffer with new data +// Update GPU buffer with new data // NOTE: dataSize and offset must be provided in bytes -void rlUpdateVertexBuffer(unsigned int id, const void *data, int dataSize, int offset) +void rlUpdateVertexBuffer(int bufferId, void *data, int dataSize, int offset) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindBuffer(GL_ARRAY_BUFFER, id); + glBindBuffer(GL_ARRAY_BUFFER, bufferId); glBufferSubData(GL_ARRAY_BUFFER, offset, dataSize, data); #endif } -// Update vertex buffer elements with new data -// NOTE: dataSize and offset must be provided in bytes -void rlUpdateVertexBufferElements(unsigned int id, const void *data, int dataSize, int offset) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, dataSize, data); -#endif -} - -// Enable vertex array object (VAO) bool rlEnableVertexArray(unsigned int vaoId) { bool result = false; @@ -3918,7 +3071,6 @@ bool rlEnableVertexArray(unsigned int vaoId) return result; } -// Disable vertex array object (VAO) void rlDisableVertexArray(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3926,7 +3078,6 @@ void rlDisableVertexArray(void) #endif } -// Enable vertex attribute index void rlEnableVertexAttribute(unsigned int index) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3934,7 +3085,6 @@ void rlEnableVertexAttribute(unsigned int index) #endif } -// Disable vertex attribute index void rlDisableVertexAttribute(unsigned int index) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -3942,44 +3092,31 @@ void rlDisableVertexAttribute(unsigned int index) #endif } -// Draw vertex array void rlDrawVertexArray(int offset, int count) { glDrawArrays(GL_TRIANGLES, offset, count); } -// Draw vertex array elements -void rlDrawVertexArrayElements(int offset, int count, const void *buffer) +void rlDrawVertexArrayElements(int offset, int count, void *buffer) { - // NOTE: Added pointer math separately from function to avoid UBSAN complaining - unsigned short *bufferPtr = (unsigned short *)buffer; - if (offset > 0) bufferPtr += offset; - - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)bufferPtr); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short*)buffer + offset); } -// Draw vertex array instanced void rlDrawVertexArrayInstanced(int offset, int count, int instances) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDrawArraysInstanced(GL_TRIANGLES, offset, count, instances); + glDrawArraysInstanced(GL_TRIANGLES, 0, count, instances); #endif } -// Draw vertex array elements instanced -void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances) +void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: Added pointer math separately from function to avoid UBSAN complaining - unsigned short *bufferPtr = (unsigned short *)buffer; - if (offset > 0) bufferPtr += offset; - - glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)bufferPtr, instances); + glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short*)buffer + offset, instances); #endif } #if defined(GRAPHICS_API_OPENGL_11) -// Enable vertex state pointer void rlEnableStatePointer(int vertexAttribType, void *buffer) { if (buffer != NULL) glEnableClientState(vertexAttribType); @@ -3994,14 +3131,12 @@ void rlEnableStatePointer(int vertexAttribType, void *buffer) } } -// Disable vertex state pointer void rlDisableStatePointer(int vertexAttribType) { glDisableClientState(vertexAttribType); } #endif -// Load vertex array object (VAO) unsigned int rlLoadVertexArray(void) { unsigned int vaoId = 0; @@ -4014,21 +3149,13 @@ unsigned int rlLoadVertexArray(void) return vaoId; } -// Set vertex attribute -void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, int offset) +void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: Data type could be: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT - // Additional types (depends on OpenGL version or extensions): - // - GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, GL_FIXED, - // - GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_10F_11F_11F_REV - - size_t offsetNative = offset; - glVertexAttribPointer(index, compSize, type, normalized, stride, (void *)offsetNative); + glVertexAttribPointer(index, compSize, type, normalized, stride, pointer); #endif } -// Set vertex attribute divisor void rlSetVertexAttributeDivisor(unsigned int index, int divisor) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -4036,7 +3163,6 @@ void rlSetVertexAttributeDivisor(unsigned int index, int divisor) #endif } -// Unload vertex array object (VAO) void rlUnloadVertexArray(unsigned int vaoId) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -4044,17 +3170,16 @@ void rlUnloadVertexArray(unsigned int vaoId) { glBindVertexArray(0); glDeleteVertexArrays(1, &vaoId); - TRACELOG(RL_LOG_INFO, "VAO: [ID %i] Unloaded vertex array data from VRAM (GPU)", vaoId); + TRACELOG(LOG_INFO, "VAO: [ID %i] Unloaded vertex array data from VRAM (GPU)", vaoId); } #endif } -// Unload vertex buffer (VBO) void rlUnloadVertexBuffer(unsigned int vboId) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glDeleteBuffers(1, &vboId); - //TRACELOG(RL_LOG_INFO, "VBO: Unloaded vertex data from VRAM (GPU)"); + //TRACELOG(LOG_INFO, "VBO: Unloaded vertex data from VRAM (GPU)"); #endif } @@ -4067,71 +3192,56 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) unsigned int id = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShaderId = 0; - unsigned int fragmentShaderId = 0; + unsigned int vertexShaderId = RLGL.State.defaultVShaderId; + unsigned int fragmentShaderId = RLGL.State.defaultFShaderId; - // Compile vertex shader (if provided) - // NOTE: If not vertex shader is provided, use default one if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER); - else vertexShaderId = RLGL.State.defaultVShaderId; - - // Compile fragment shader (if provided) - // NOTE: If not vertex shader is provided, use default one if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER); - else fragmentShaderId = RLGL.State.defaultFShaderId; - // In case vertex and fragment shader are the default ones, no need to recompile, we can just assign the default shader program id - if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; - else if ((vertexShaderId > 0) && (fragmentShaderId > 0)) + if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShader.id; + else { - // One of or both shader are new, we need to compile a new shader program id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId); - // We can detach and delete vertex/fragment shaders (if not default ones) - // NOTE: We detach shader before deletion to make sure memory is freed if (vertexShaderId != RLGL.State.defaultVShaderId) { - // WARNING: Shader program linkage could fail and returned id is 0 - if (id > 0) glDetachShader(id, vertexShaderId); + // Detach shader before deletion to make sure memory is freed + glDetachShader(id, vertexShaderId); glDeleteShader(vertexShaderId); } if (fragmentShaderId != RLGL.State.defaultFShaderId) { - // WARNING: Shader program linkage could fail and returned id is 0 - if (id > 0) glDetachShader(id, fragmentShaderId); + // Detach shader before deletion to make sure memory is freed + glDetachShader(id, fragmentShaderId); glDeleteShader(fragmentShaderId); } - // In case shader program loading failed, we assign default shader if (id == 0) { - // In case shader loading fails, we return the default shader - TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader"); - id = RLGL.State.defaultShaderId; + TRACELOG(LOG_WARNING, "SHADER: Failed to load custom shader code"); + id = RLGL.State.defaultShader.id; } - /* - else - { - // Get available shader uniforms - // NOTE: This information is useful for debug... - int uniformCount = -1; - glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); + } - for (int i = 0; i < uniformCount; i++) - { - int namelen = -1; - int num = -1; - char name[256] = { 0 }; // Assume no variable names longer than 256 - GLenum type = GL_ZERO; + // Get available shader uniforms + // NOTE: This information is useful for debug... + int uniformCount = -1; - // Get the name of the uniforms - glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); - name[namelen] = 0; - TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); - } - } - */ + for (int i = 0; i < uniformCount; i++) + { + int namelen = -1; + int num = -1; + char name[256]; // Assume no variable names longer than 256 + GLenum type = GL_ZERO; + + // Get the name of the uniforms + glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); + + name[namelen] = 0; + + TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); } #endif @@ -4155,14 +3265,10 @@ unsigned int rlCompileShader(const char *shaderCode, int type) { switch (type) { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); break; + case GL_VERTEX_SHADER: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shader); break; + case GL_FRAGMENT_SHADER: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); break; //case GL_GEOMETRY_SHADER: - #if defined(GRAPHICS_API_OPENGL_43) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shader); break; - #elif defined(GRAPHICS_API_OPENGL_33) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; - #endif + //case GL_COMPUTE_SHADER: default: break; } @@ -4172,26 +3278,20 @@ unsigned int rlCompileShader(const char *shaderCode, int type) if (maxLength > 0) { int length = 0; - char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + char *log = RL_CALLOC(maxLength, sizeof(char)); glGetShaderInfoLog(shader, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log); + TRACELOG(LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log); RL_FREE(log); } - - shader = 0; } else { switch (type) { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); break; + case GL_VERTEX_SHADER: TRACELOG(LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break; + case GL_FRAGMENT_SHADER: TRACELOG(LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); break; //case GL_GEOMETRY_SHADER: - #if defined(GRAPHICS_API_OPENGL_43) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shader); break; - #elif defined(GRAPHICS_API_OPENGL_33) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; - #endif + //case GL_COMPUTE_SHADER: default: break; } } @@ -4212,19 +3312,13 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) glAttachShader(program, vShaderId); glAttachShader(program, fShaderId); - // NOTE: Default attribute shader locations must be Bound before linking - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX); - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); -#endif + // NOTE: Default attribute shader locations must be binded before linking + glBindAttribLocation(program, 0, DEFAULT_SHADER_ATTRIB_NAME_POSITION); + glBindAttribLocation(program, 1, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + glBindAttribLocation(program, 2, DEFAULT_SHADER_ATTRIB_NAME_NORMAL); + glBindAttribLocation(program, 3, DEFAULT_SHADER_ATTRIB_NAME_COLOR); + glBindAttribLocation(program, 4, DEFAULT_SHADER_ATTRIB_NAME_TANGENT); + glBindAttribLocation(program, 5, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); // NOTE: If some attrib name is no found on the shader, it locations becomes -1 @@ -4236,7 +3330,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) if (success == GL_FALSE) { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program); + TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program); int maxLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); @@ -4244,9 +3338,9 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) if (maxLength > 0) { int length = 0; - char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + char *log = RL_CALLOC(maxLength, sizeof(char)); glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); + TRACELOG(LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); RL_FREE(log); } @@ -4254,15 +3348,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) program = 0; } - else - { - // Get the size of compiled shader program (not available on OpenGL ES 2.0) - // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero - //GLint binarySize = 0; - //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", program); - } + else TRACELOG(LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", program); #endif return program; } @@ -4273,7 +3359,7 @@ void rlUnloadShaderProgram(unsigned int id) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glDeleteProgram(id); - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", id); + TRACELOG(LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", id); #endif } @@ -4284,8 +3370,8 @@ int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) location = glGetUniformLocation(shaderId, uniformName); - //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName); - //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location); + if (location == -1) TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName); + else TRACELOG(LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location); #endif return location; } @@ -4297,8 +3383,8 @@ int rlGetLocationAttrib(unsigned int shaderId, const char *attribName) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) location = glGetAttribLocation(shaderId, attribName); - //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName); - //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location); + if (location == -1) TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName); + else TRACELOG(LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location); #endif return location; } @@ -4309,24 +3395,16 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) switch (uniformType) { - case RL_SHADER_UNIFORM_FLOAT: glUniform1fv(locIndex, count, (float *)value); break; - case RL_SHADER_UNIFORM_VEC2: glUniform2fv(locIndex, count, (float *)value); break; - case RL_SHADER_UNIFORM_VEC3: glUniform3fv(locIndex, count, (float *)value); break; - case RL_SHADER_UNIFORM_VEC4: glUniform4fv(locIndex, count, (float *)value); break; - case RL_SHADER_UNIFORM_INT: glUniform1iv(locIndex, count, (int *)value); break; - case RL_SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break; - case RL_SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break; - case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break; - #if !defined(GRAPHICS_API_OPENGL_ES2) - case RL_SHADER_UNIFORM_UINT: glUniform1uiv(locIndex, count, (unsigned int *)value); break; - case RL_SHADER_UNIFORM_UIVEC2: glUniform2uiv(locIndex, count, (unsigned int *)value); break; - case RL_SHADER_UNIFORM_UIVEC3: glUniform3uiv(locIndex, count, (unsigned int *)value); break; - case RL_SHADER_UNIFORM_UIVEC4: glUniform4uiv(locIndex, count, (unsigned int *)value); break; - #endif - case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; - default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); - - // TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv() + case SHADER_UNIFORM_FLOAT: glUniform1fv(locIndex, count, (float *)value); break; + case SHADER_UNIFORM_VEC2: glUniform2fv(locIndex, count, (float *)value); break; + case SHADER_UNIFORM_VEC3: glUniform3fv(locIndex, count, (float *)value); break; + case SHADER_UNIFORM_VEC4: glUniform4fv(locIndex, count, (float *)value); break; + case SHADER_UNIFORM_INT: glUniform1iv(locIndex, count, (int *)value); break; + case SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break; + case SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break; + case SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break; + case SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; + default: TRACELOG(LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); } #endif } @@ -4337,11 +3415,11 @@ void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) switch (attribType) { - case RL_SHADER_ATTRIB_FLOAT: if (count == 1) glVertexAttrib1fv(locIndex, (float *)value); break; - case RL_SHADER_ATTRIB_VEC2: if (count == 2) glVertexAttrib2fv(locIndex, (float *)value); break; - case RL_SHADER_ATTRIB_VEC3: if (count == 3) glVertexAttrib3fv(locIndex, (float *)value); break; - case RL_SHADER_ATTRIB_VEC4: if (count == 4) glVertexAttrib4fv(locIndex, (float *)value); break; - default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set attrib default value, data type not recognized"); + case SHADER_ATTRIB_FLOAT: if (count == 1) glVertexAttrib1fv(locIndex, (float *)value); break; + case SHADER_ATTRIB_VEC2: if (count == 2) glVertexAttrib2fv(locIndex, (float *)value); break; + case SHADER_ATTRIB_VEC3: if (count == 3) glVertexAttrib3fv(locIndex, (float *)value); break; + case SHADER_ATTRIB_VEC4: if (count == 4) glVertexAttrib4fv(locIndex, (float *)value); break; + default: TRACELOG(LOG_WARNING, "SHADER: Failed to set attrib default value, data type not recognized"); } #endif } @@ -4350,25 +3428,7 @@ void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType void rlSetUniformMatrix(int locIndex, Matrix mat) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - float matfloat[16] = { - mat.m0, mat.m1, mat.m2, mat.m3, - mat.m4, mat.m5, mat.m6, mat.m7, - mat.m8, mat.m9, mat.m10, mat.m11, - mat.m12, mat.m13, mat.m14, mat.m15 - }; - glUniformMatrix4fv(locIndex, 1, false, matfloat); -#endif -} - -// Set shader value uniform matrix -void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count) -{ -#if defined(GRAPHICS_API_OPENGL_33) - glUniformMatrix4fv(locIndex, count, true, (const float *)matrices); -#elif defined(GRAPHICS_API_OPENGL_ES2) - // WARNING: WebGL does not support Matrix transpose ("true" parameter) - // REF: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniformMatrix - glUniformMatrix4fv(locIndex, count, false, (const float *)matrices); + glUniformMatrix4fv(locIndex, 1, false, MatrixToFloat(mat)); #endif } @@ -4377,18 +3437,11 @@ void rlSetUniformSampler(int locIndex, unsigned int textureId) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Check if texture is already active - for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) - { - if (RLGL.State.activeTextureId[i] == textureId) - { - glUniform1i(locIndex, 1 + i); - return; - } - } + for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++) if (RLGL.State.activeTextureId[i] == textureId) return; // Register a new active texture for the internal batch system // NOTE: Default texture is always activated as GL_TEXTURE0 - for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) + for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++) { if (RLGL.State.activeTextureId[i] == 0) { @@ -4400,223 +3453,48 @@ void rlSetUniformSampler(int locIndex, unsigned int textureId) #endif } -// Set shader currently active (id and locations) -void rlSetShader(unsigned int id, int *locs) +// Set shader currently active +void rlSetShader(Shader shader) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.State.currentShaderId != id) + if (RLGL.State.currentShader.id != shader.id) { rlDrawRenderBatch(RLGL.currentBatch); - RLGL.State.currentShaderId = id; - RLGL.State.currentShaderLocs = locs; + RLGL.State.currentShader = shader; } #endif } -// Load compute shader program -unsigned int rlLoadComputeShaderProgram(unsigned int shaderId) -{ - unsigned int program = 0; - -#if defined(GRAPHICS_API_OPENGL_43) - GLint success = 0; - program = glCreateProgram(); - glAttachShader(program, shaderId); - glLinkProgram(program); - - // NOTE: All uniform variables are intitialised to 0 when a program links - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", program); - - int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); - RL_FREE(log); - } - - glDeleteProgram(program); - - program = 0; - } - else - { - // Get the size of compiled shader program (not available on OpenGL ES 2.0) - // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero - //GLint binarySize = 0; - //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", program); - } -#else - TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43"); -#endif - - return program; -} - -// Dispatch compute shader (equivalent to *draw* for graphics pilepine) -void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glDispatchCompute(groupX, groupY, groupZ); -#endif -} - -// Load shader storage buffer object (SSBO) -unsigned int rlLoadShaderBuffer(unsigned int size, const void *data, int usageHint) -{ - unsigned int ssbo = 0; - -#if defined(GRAPHICS_API_OPENGL_43) - glGenBuffers(1, &ssbo); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); - glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY); - if (data == NULL) glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL); // Clear buffer data to 0 - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); -#else - TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); -#endif - - return ssbo; -} - -// Unload shader storage buffer object (SSBO) -void rlUnloadShaderBuffer(unsigned int ssboId) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glDeleteBuffers(1, &ssboId); -#else - TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); -#endif - -} - -// Update SSBO buffer data -void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSize, unsigned int offset) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); - glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, dataSize, data); -#endif -} - -// Get SSBO buffer size -unsigned int rlGetShaderBufferSize(unsigned int id) -{ -#if defined(GRAPHICS_API_OPENGL_43) - GLint64 size = 0; - glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); - glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size); - return (size > 0)? (unsigned int)size : 0; -#else - return 0; -#endif -} - -// Read SSBO buffer data (GPU->CPU) -void rlReadShaderBuffer(unsigned int id, void *dest, unsigned int count, unsigned int offset) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); - glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, count, dest); -#endif -} - -// Bind SSBO buffer -void rlBindShaderBuffer(unsigned int id, unsigned int index) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, id); -#endif -} - -// Copy SSBO buffer data -void rlCopyShaderBuffer(unsigned int destId, unsigned int srcId, unsigned int destOffset, unsigned int srcOffset, unsigned int count) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glBindBuffer(GL_COPY_READ_BUFFER, srcId); - glBindBuffer(GL_COPY_WRITE_BUFFER, destId); - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, destOffset, count); -#endif -} - -// Bind image texture -void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly) -{ -#if defined(GRAPHICS_API_OPENGL_43) - unsigned int glInternalFormat = 0, glFormat = 0, glType = 0; - - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - glBindImageTexture(index, id, 0, 0, 0, readonly? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat); -#else - TRACELOG(RL_LOG_WARNING, "TEXTURE: Image texture binding not enabled. Define GRAPHICS_API_OPENGL_43"); -#endif -} - // Matrix state management //----------------------------------------------------------------------------------------- -// Get internal modelview matrix +// Return internal modelview matrix Matrix rlGetMatrixModelview(void) { - Matrix matrix = rlMatrixIdentity(); + Matrix matrix = MatrixIdentity(); #if defined(GRAPHICS_API_OPENGL_11) float mat[16]; glGetFloatv(GL_MODELVIEW_MATRIX, mat); - matrix.m0 = mat[0]; - matrix.m1 = mat[1]; - matrix.m2 = mat[2]; - matrix.m3 = mat[3]; - matrix.m4 = mat[4]; - matrix.m5 = mat[5]; - matrix.m6 = mat[6]; - matrix.m7 = mat[7]; - matrix.m8 = mat[8]; - matrix.m9 = mat[9]; - matrix.m10 = mat[10]; - matrix.m11 = mat[11]; - matrix.m12 = mat[12]; - matrix.m13 = mat[13]; - matrix.m14 = mat[14]; - matrix.m15 = mat[15]; + matrix.m0 = mat[0]; matrix.m1 = mat[1]; matrix.m2 = mat[2]; matrix.m3 = mat[3]; + matrix.m4 = mat[4]; matrix.m5 = mat[5]; matrix.m6 = mat[6]; matrix.m7 = mat[7]; + matrix.m8 = mat[8]; matrix.m9 = mat[9]; matrix.m10 = mat[10]; matrix.m11 = mat[11]; + matrix.m12 = mat[12]; matrix.m13 = mat[13]; matrix.m14 = mat[14]; matrix.m15 = mat[15]; #else matrix = RLGL.State.modelview; #endif return matrix; } -// Get internal projection matrix +// Return internal projection matrix Matrix rlGetMatrixProjection(void) { #if defined(GRAPHICS_API_OPENGL_11) float mat[16]; glGetFloatv(GL_PROJECTION_MATRIX,mat); Matrix m; - m.m0 = mat[0]; - m.m1 = mat[1]; - m.m2 = mat[2]; - m.m3 = mat[3]; - m.m4 = mat[4]; - m.m5 = mat[5]; - m.m6 = mat[6]; - m.m7 = mat[7]; - m.m8 = mat[8]; - m.m9 = mat[9]; - m.m10 = mat[10]; - m.m11 = mat[11]; - m.m12 = mat[12]; - m.m13 = mat[13]; - m.m14 = mat[14]; - m.m15 = mat[15]; + m.m0 = mat[0]; m.m1 = mat[1]; m.m2 = mat[2]; m.m3 = mat[3]; + m.m4 = mat[4]; m.m5 = mat[5]; m.m6 = mat[6]; m.m7 = mat[7]; + m.m8 = mat[8]; m.m9 = mat[9]; m.m10 = mat[10]; m.m11 = mat[11]; + m.m12 = mat[12]; m.m13 = mat[13]; m.m14 = mat[14]; m.m15 = mat[15]; return m; #else return RLGL.State.projection; @@ -4626,21 +3504,21 @@ Matrix rlGetMatrixProjection(void) // Get internal accumulated transform matrix Matrix rlGetMatrixTransform(void) { - Matrix mat = rlMatrixIdentity(); + Matrix mat = MatrixIdentity(); #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // TODO: Consider possible transform matrices in the RLGL.State.stack // Is this the right order? or should we start with the first stored matrix instead of the last one? - //Matrix matStackTransform = rlMatrixIdentity(); - //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = rlMatrixMultiply(RLGL.State.stack[i], matStackTransform); + //Matrix matStackTransform = MatrixIdentity(); + //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = MatrixMultiply(RLGL.State.stack[i], matStackTransform); mat = RLGL.State.transform; #endif return mat; } // Get internal projection matrix for stereo render (selected eye) -Matrix rlGetMatrixProjectionStereo(int eye) +RLAPI Matrix rlGetMatrixProjectionStereo(int eye) { - Matrix mat = rlMatrixIdentity(); + Matrix mat = MatrixIdentity(); #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mat = RLGL.State.projectionStereo[eye]; #endif @@ -4648,9 +3526,9 @@ Matrix rlGetMatrixProjectionStereo(int eye) } // Get internal view offset matrix for stereo render (selected eye) -Matrix rlGetMatrixViewOffsetStereo(int eye) +RLAPI Matrix rlGetMatrixViewOffsetStereo(int eye) { - Matrix mat = rlMatrixIdentity(); + Matrix mat = MatrixIdentity(); #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mat = RLGL.State.viewOffsetStereo[eye]; #endif @@ -4691,7 +3569,7 @@ void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left) #endif } -// Load and draw a quad in NDC +// Load and draw a 1x1 XY quad in NDC void rlLoadDrawQuad(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -4716,10 +3594,10 @@ void rlLoadDrawQuad(void) glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); // Bind vertex attributes (position, texcoords) - glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); - glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions - glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); - glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); // Texcoords + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); // Texcoords // Draw quad glBindVertexArray(quadVAO); @@ -4732,7 +3610,7 @@ void rlLoadDrawQuad(void) #endif } -// Load and draw a cube in NDC +// Load and draw a 1x1 3D cube in NDC void rlLoadDrawCube(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -4790,12 +3668,12 @@ void rlLoadDrawCube(void) // Bind vertex attributes (position, normals, texcoords) glBindVertexArray(cubeVAO); - glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); - glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions - glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); - glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals - glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); - glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); // Texcoords + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); // Texcoords glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); @@ -4810,55 +3688,22 @@ void rlLoadDrawCube(void) #endif } -// Get name string for pixel format -const char *rlGetPixelFormatName(unsigned int format) -{ - switch (format) - { - case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: return "GRAYSCALE"; break; // 8 bit per pixel (no alpha) - case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: return "GRAY_ALPHA"; break; // 8*2 bpp (2 channels) - case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: return "R5G6B5"; break; // 16 bpp - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: return "R8G8B8"; break; // 24 bpp - case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: return "R5G5B5A1"; break; // 16 bpp (1 bit alpha) - case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: return "R4G4B4A4"; break; // 16 bpp (4 bit alpha) - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: return "R8G8B8A8"; break; // 32 bpp - case RL_PIXELFORMAT_UNCOMPRESSED_R32: return "R32"; break; // 32 bpp (1 channel - float) - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: return "R32G32B32"; break; // 32*3 bpp (3 channels - float) - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: return "R32G32B32A32"; break; // 32*4 bpp (4 channels - float) - case RL_PIXELFORMAT_UNCOMPRESSED_R16: return "R16"; break; // 16 bpp (1 channel - half float) - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: return "R16G16B16"; break; // 16*3 bpp (3 channels - half float) - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: return "R16G16B16A16"; break; // 16*4 bpp (4 channels - half float) - case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB: return "DXT1_RGB"; break; // 4 bpp (no alpha) - case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA: return "DXT1_RGBA"; break; // 4 bpp (1 bit alpha) - case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: return "DXT3_RGBA"; break; // 8 bpp - case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: return "DXT5_RGBA"; break; // 8 bpp - case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: return "ETC1_RGB"; break; // 4 bpp - case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: return "ETC2_RGB"; break; // 4 bpp - case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: return "ETC2_RGBA"; break; // 8 bpp - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: return "PVRT_RGB"; break; // 4 bpp - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: return "PVRT_RGBA"; break; // 4 bpp - case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: return "ASTC_4x4_RGBA"; break; // 8 bpp - case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: return "ASTC_8x8_RGBA"; break; // 2 bpp - default: return "UNKNOWN"; break; - } -} - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Load default shader (just vertex positioning and texture coloring) // NOTE: This shader program is used for internal buffers -// NOTE: Loaded: RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs +// NOTE: It uses global variable: RLGL.State.defaultShader static void rlLoadShaderDefault(void) { - RLGL.State.defaultShaderLocs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); + RLGL.State.defaultShader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int)); // NOTE: All locations must be reseted to -1 (no location) - for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) RLGL.State.defaultShaderLocs[i] = -1; + for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) RLGL.State.defaultShader.locs[i] = -1; // Vertex shader directly defined, no external file required - const char *defaultVShaderCode = + const char *vShaderDefault = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" "attribute vec3 vertexPosition; \n" @@ -4874,25 +3719,14 @@ static void rlLoadShaderDefault(void) "out vec2 fragTexCoord; \n" "out vec4 fragColor; \n" #endif - -#if defined(GRAPHICS_API_OPENGL_ES3) - "#version 300 es \n" - "precision mediump float; \n" // Precision required for OpenGL ES3 (WebGL 2) (on some browsers) - "in vec3 vertexPosition; \n" - "in vec2 vertexTexCoord; \n" - "in vec4 vertexColor; \n" - "out vec2 fragTexCoord; \n" - "out vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) +#if defined(GRAPHICS_API_OPENGL_ES2) "#version 100 \n" - "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) (on some browsers) "attribute vec3 vertexPosition; \n" "attribute vec2 vertexTexCoord; \n" "attribute vec4 vertexColor; \n" "varying vec2 fragTexCoord; \n" "varying vec4 fragColor; \n" #endif - "uniform mat4 mvp; \n" "void main() \n" "{ \n" @@ -4902,7 +3736,7 @@ static void rlLoadShaderDefault(void) "} \n"; // Fragment shader directly defined, no external file required - const char *defaultFShaderCode = + const char *fShaderDefault = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" "varying vec2 fragTexCoord; \n" @@ -4927,21 +3761,7 @@ static void rlLoadShaderDefault(void) " finalColor = texelColor*colDiffuse*fragColor; \n" "} \n"; #endif - -#if defined(GRAPHICS_API_OPENGL_ES3) - "#version 300 es \n" - "precision mediump float; \n" // Precision required for OpenGL ES3 (WebGL 2) - "in vec2 fragTexCoord; \n" - "in vec4 fragColor; \n" - "out vec4 finalColor; \n" - "uniform sampler2D texture0; \n" - "uniform vec4 colDiffuse; \n" - "void main() \n" - "{ \n" - " vec4 texelColor = texture(texture0, fragTexCoord); \n" - " finalColor = texelColor*colDiffuse*fragColor; \n" - "} \n"; -#elif defined(GRAPHICS_API_OPENGL_ES2) +#if defined(GRAPHICS_API_OPENGL_ES2) "#version 100 \n" "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) "varying vec2 fragTexCoord; \n" @@ -4955,126 +3775,258 @@ static void rlLoadShaderDefault(void) "} \n"; #endif - // NOTE: Compiled vertex/fragment shaders are not deleted, - // they are kept for re-use as default shaders in case some shader loading fails - RLGL.State.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader - RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader + // NOTE: Compiled vertex/fragment shaders are kept for re-use + RLGL.State.defaultVShaderId = rlCompileShader(vShaderDefault, GL_VERTEX_SHADER); // Compile default vertex shader + RLGL.State.defaultFShaderId = rlCompileShader(fShaderDefault, GL_FRAGMENT_SHADER); // Compile default fragment shader - RLGL.State.defaultShaderId = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); + RLGL.State.defaultShader.id = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); - if (RLGL.State.defaultShaderId > 0) + if (RLGL.State.defaultShader.id > 0) { - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader loaded successfully", RLGL.State.defaultShaderId); + TRACELOG(LOG_INFO, "SHADER: [ID %i] Default shader loaded successfully", RLGL.State.defaultShader.id); // Set default shader locations: attributes locations - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_POSITION] = glGetAttribLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_COLOR] = glGetAttribLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + RLGL.State.defaultShader.locs[SHADER_LOC_VERTEX_POSITION] = glGetAttribLocation(RLGL.State.defaultShader.id, "vertexPosition"); + RLGL.State.defaultShader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(RLGL.State.defaultShader.id, "vertexTexCoord"); + RLGL.State.defaultShader.locs[SHADER_LOC_VERTEX_COLOR] = glGetAttribLocation(RLGL.State.defaultShader.id, "vertexColor"); // Set default shader locations: uniform locations - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_MATRIX_MVP] = glGetUniformLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_COLOR_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_MAP_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0); + RLGL.State.defaultShader.locs[SHADER_LOC_MATRIX_MVP] = glGetUniformLocation(RLGL.State.defaultShader.id, "mvp"); + RLGL.State.defaultShader.locs[SHADER_LOC_COLOR_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShader.id, "colDiffuse"); + RLGL.State.defaultShader.locs[SHADER_LOC_MAP_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShader.id, "texture0"); } - else TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to load default shader", RLGL.State.defaultShaderId); + else TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to load default shader", RLGL.State.defaultShader.id); } // Unload default shader -// NOTE: Unloads: RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs +// NOTE: It uses global variable: RLGL.State.defaultShader static void rlUnloadShaderDefault(void) { glUseProgram(0); - glDetachShader(RLGL.State.defaultShaderId, RLGL.State.defaultVShaderId); - glDetachShader(RLGL.State.defaultShaderId, RLGL.State.defaultFShaderId); + glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultVShaderId); + glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultFShaderId); glDeleteShader(RLGL.State.defaultVShaderId); glDeleteShader(RLGL.State.defaultFShaderId); - glDeleteProgram(RLGL.State.defaultShaderId); + glDeleteProgram(RLGL.State.defaultShader.id); - RL_FREE(RLGL.State.defaultShaderLocs); + RL_FREE(RLGL.State.defaultShader.locs); - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShaderId); + TRACELOG(LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShader.id); } -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if defined(SUPPORT_GL_DETAILS_INFO) // Get compressed format official GL identifier name -static const char *rlGetCompressedFormatName(int format) +static char *rlGetCompressedFormatName(int format) { + static char compName[64] = { 0 }; + memset(compName, 0, 64); + switch (format) { // GL_EXT_texture_compression_s3tc - case 0x83F0: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"; break; - case 0x83F1: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"; break; - case 0x83F2: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"; break; - case 0x83F3: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"; break; + case 0x83F0: strcpy(compName, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"); break; + case 0x83F1: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"); break; + case 0x83F2: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"); break; + case 0x83F3: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"); break; // GL_3DFX_texture_compression_FXT1 - case 0x86B0: return "GL_COMPRESSED_RGB_FXT1_3DFX"; break; - case 0x86B1: return "GL_COMPRESSED_RGBA_FXT1_3DFX"; break; + case 0x86B0: strcpy(compName, "GL_COMPRESSED_RGB_FXT1_3DFX"); break; + case 0x86B1: strcpy(compName, "GL_COMPRESSED_RGBA_FXT1_3DFX"); break; // GL_IMG_texture_compression_pvrtc - case 0x8C00: return "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"; break; - case 0x8C01: return "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"; break; - case 0x8C02: return "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"; break; - case 0x8C03: return "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"; break; + case 0x8C00: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"); break; + case 0x8C01: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"); break; + case 0x8C02: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"); break; + case 0x8C03: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"); break; // GL_OES_compressed_ETC1_RGB8_texture - case 0x8D64: return "GL_ETC1_RGB8_OES"; break; + case 0x8D64: strcpy(compName, "GL_ETC1_RGB8_OES"); break; // GL_ARB_texture_compression_rgtc - case 0x8DBB: return "GL_COMPRESSED_RED_RGTC1"; break; - case 0x8DBC: return "GL_COMPRESSED_SIGNED_RED_RGTC1"; break; - case 0x8DBD: return "GL_COMPRESSED_RG_RGTC2"; break; - case 0x8DBE: return "GL_COMPRESSED_SIGNED_RG_RGTC2"; break; + case 0x8DBB: strcpy(compName, "GL_COMPRESSED_RED_RGTC1"); break; + case 0x8DBC: strcpy(compName, "GL_COMPRESSED_SIGNED_RED_RGTC1"); break; + case 0x8DBD: strcpy(compName, "GL_COMPRESSED_RG_RGTC2"); break; + case 0x8DBE: strcpy(compName, "GL_COMPRESSED_SIGNED_RG_RGTC2"); break; // GL_ARB_texture_compression_bptc - case 0x8E8C: return "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"; break; - case 0x8E8D: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"; break; - case 0x8E8E: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"; break; - case 0x8E8F: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"; break; + case 0x8E8C: strcpy(compName, "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"); break; + case 0x8E8D: strcpy(compName, "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"); break; + case 0x8E8E: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"); break; + case 0x8E8F: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"); break; // GL_ARB_ES3_compatibility - case 0x9274: return "GL_COMPRESSED_RGB8_ETC2"; break; - case 0x9275: return "GL_COMPRESSED_SRGB8_ETC2"; break; - case 0x9276: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"; break; - case 0x9277: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"; break; - case 0x9278: return "GL_COMPRESSED_RGBA8_ETC2_EAC"; break; - case 0x9279: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"; break; - case 0x9270: return "GL_COMPRESSED_R11_EAC"; break; - case 0x9271: return "GL_COMPRESSED_SIGNED_R11_EAC"; break; - case 0x9272: return "GL_COMPRESSED_RG11_EAC"; break; - case 0x9273: return "GL_COMPRESSED_SIGNED_RG11_EAC"; break; + case 0x9274: strcpy(compName, "GL_COMPRESSED_RGB8_ETC2"); break; + case 0x9275: strcpy(compName, "GL_COMPRESSED_SRGB8_ETC2"); break; + case 0x9276: strcpy(compName, "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break; + case 0x9277: strcpy(compName, "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break; + case 0x9278: strcpy(compName, "GL_COMPRESSED_RGBA8_ETC2_EAC"); break; + case 0x9279: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"); break; + case 0x9270: strcpy(compName, "GL_COMPRESSED_R11_EAC"); break; + case 0x9271: strcpy(compName, "GL_COMPRESSED_SIGNED_R11_EAC"); break; + case 0x9272: strcpy(compName, "GL_COMPRESSED_RG11_EAC"); break; + case 0x9273: strcpy(compName, "GL_COMPRESSED_SIGNED_RG11_EAC"); break; // GL_KHR_texture_compression_astc_hdr - case 0x93B0: return "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"; break; - case 0x93B1: return "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"; break; - case 0x93B2: return "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"; break; - case 0x93B3: return "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"; break; - case 0x93B4: return "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"; break; - case 0x93B5: return "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"; break; - case 0x93B6: return "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"; break; - case 0x93B7: return "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"; break; - case 0x93B8: return "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"; break; - case 0x93B9: return "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"; break; - case 0x93BA: return "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"; break; - case 0x93BB: return "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"; break; - case 0x93BC: return "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"; break; - case 0x93BD: return "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"; break; - case 0x93D0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"; break; - case 0x93D1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"; break; - case 0x93D2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"; break; - case 0x93D3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"; break; - case 0x93D4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"; break; - case 0x93D5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"; break; - case 0x93D6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"; break; - case 0x93D7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"; break; - case 0x93D8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"; break; - case 0x93D9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"; break; - case 0x93DA: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"; break; - case 0x93DB: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"; break; - case 0x93DC: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"; break; - case 0x93DD: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"; break; - default: return "GL_COMPRESSED_UNKNOWN"; break; + case 0x93B0: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"); break; + case 0x93B1: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"); break; + case 0x93B2: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"); break; + case 0x93B3: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"); break; + case 0x93B4: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"); break; + case 0x93B5: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"); break; + case 0x93B6: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"); break; + case 0x93B7: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"); break; + case 0x93B8: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"); break; + case 0x93B9: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"); break; + case 0x93BA: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"); break; + case 0x93BB: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"); break; + case 0x93BC: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"); break; + case 0x93BD: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"); break; + case 0x93D0: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"); break; + case 0x93D1: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"); break; + case 0x93D2: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"); break; + case 0x93D3: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"); break; + case 0x93D4: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"); break; + case 0x93D5: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"); break; + case 0x93D6: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"); break; + case 0x93D7: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"); break; + case 0x93D8: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"); break; + case 0x93D9: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"); break; + case 0x93DA: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"); break; + case 0x93DB: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"); break; + case 0x93DC: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"); break; + case 0x93DD: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"); break; + default: strcpy(compName, "GL_COMPRESSED_UNKNOWN"); break; } + + return compName; } -#endif // RLGL_SHOW_GL_DETAILS_INFO +#endif // SUPPORT_GL_DETAILS_INFO #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#if defined(GRAPHICS_API_OPENGL_11) +// Mipmaps data is generated after image data +// NOTE: Only works with RGBA (4 bytes) data! +static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight) +{ + int mipmapCount = 1; // Required mipmap levels count (including base level) + int width = baseWidth; + int height = baseHeight; + int size = baseWidth*baseHeight*4; // Size in bytes (will include mipmaps...), RGBA only + + // Count mipmap levels required + while ((width != 1) && (height != 1)) + { + width /= 2; + height /= 2; + + TRACELOGD("TEXTURE: Next mipmap size: %i x %i", width, height); + + mipmapCount++; + + size += (width*height*4); // Add mipmap size (in bytes) + } + + TRACELOGD("TEXTURE: Total mipmaps required: %i", mipmapCount); + TRACELOGD("TEXTURE: Total size of data required: %i", size); + + unsigned char *temp = RL_REALLOC(data, size); + + if (temp != NULL) data = temp; + else TRACELOG(LOG_WARNING, "TEXTURE: Failed to re-allocate required mipmaps memory"); + + width = baseWidth; + height = baseHeight; + size = (width*height*4); + + // Generate mipmaps + // NOTE: Every mipmap data is stored after data + Color *image = (Color *)RL_MALLOC(width*height*sizeof(Color)); + Color *mipmap = NULL; + int offset = 0; + int j = 0; + + for (int i = 0; i < size; i += 4) + { + image[j].r = data[i]; + image[j].g = data[i + 1]; + image[j].b = data[i + 2]; + image[j].a = data[i + 3]; + j++; + } + + TRACELOGD("TEXTURE: Mipmap base size (%ix%i)", width, height); + + for (int mip = 1; mip < mipmapCount; mip++) + { + mipmap = rlGenNextMipmapData(image, width, height); + + offset += (width*height*4); // Size of last mipmap + j = 0; + + width /= 2; + height /= 2; + size = (width*height*4); // Mipmap size to store after offset + + // Add mipmap to data + for (int i = 0; i < size; i += 4) + { + data[offset + i] = mipmap[j].r; + data[offset + i + 1] = mipmap[j].g; + data[offset + i + 2] = mipmap[j].b; + data[offset + i + 3] = mipmap[j].a; + j++; + } + + RL_FREE(image); + + image = mipmap; + mipmap = NULL; + } + + RL_FREE(mipmap); // free mipmap data + + return mipmapCount; +} + +// Manual mipmap generation (basic scaling algorithm) +static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight) +{ + int x2, y2; + Color prow, pcol; + + int width = srcWidth/2; + int height = srcHeight/2; + + Color *mipmap = (Color *)RL_MALLOC(width*height*sizeof(Color)); + + // Scaling algorithm works perfectly (box-filter) + for (int y = 0; y < height; y++) + { + y2 = 2*y; + + for (int x = 0; x < width; x++) + { + x2 = 2*x; + + prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2; + prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2; + prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2; + prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/2; + + pcol.r = (srcData[(y2+1)*srcWidth + x2].r + srcData[(y2+1)*srcWidth + x2 + 1].r)/2; + pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2; + pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2; + pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/2; + + mipmap[y*width + x].r = (prow.r + pcol.r)/2; + mipmap[y*width + x].g = (prow.g + pcol.g)/2; + mipmap[y*width + x].b = (prow.b + pcol.b)/2; + mipmap[y*width + x].a = (prow.a + pcol.a)/2; + } + } + + TRACELOGD("TEXTURE: Mipmap generated successfully (%ix%i)", width, height); + + return mipmap; +} +#endif // GRAPHICS_API_OPENGL_11 + // Get pixel data size in bytes (image or texture) // NOTE: Size depends on pixel format static int rlGetPixelDataSize(int width, int height, int format) @@ -5084,183 +4036,40 @@ static int rlGetPixelDataSize(int width, int height, int format) switch (format) { - case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 16; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 16*3; break; - case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 16*4; break; - case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB: - case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA: - case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: - case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; - case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: - case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: - case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: - case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; - case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; + case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; + case PIXELFORMAT_COMPRESSED_DXT1_RGB: + case PIXELFORMAT_COMPRESSED_DXT1_RGBA: + case PIXELFORMAT_COMPRESSED_ETC1_RGB: + case PIXELFORMAT_COMPRESSED_ETC2_RGB: + case PIXELFORMAT_COMPRESSED_PVRT_RGB: + case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; + case PIXELFORMAT_COMPRESSED_DXT3_RGBA: + case PIXELFORMAT_COMPRESSED_DXT5_RGBA: + case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: + case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; + case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; default: break; } - double bytesPerPixel = (double)bpp/8.0; - dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes + dataSize = width*height*bpp/8; // Total data size in bytes // Most compressed formats works on 4x4 blocks, // if texture is smaller, minimum dataSize is 8 or 16 if ((width < 4) && (height < 4)) { - if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; - else if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; + if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; + else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; } return dataSize; } - -// Auxiliar math functions - -// Get float array of matrix data -static rl_float16 rlMatrixToFloatV(Matrix mat) -{ - rl_float16 result = { 0 }; - - result.v[0] = mat.m0; - result.v[1] = mat.m1; - result.v[2] = mat.m2; - result.v[3] = mat.m3; - result.v[4] = mat.m4; - result.v[5] = mat.m5; - result.v[6] = mat.m6; - result.v[7] = mat.m7; - result.v[8] = mat.m8; - result.v[9] = mat.m9; - result.v[10] = mat.m10; - result.v[11] = mat.m11; - result.v[12] = mat.m12; - result.v[13] = mat.m13; - result.v[14] = mat.m14; - result.v[15] = mat.m15; - - return result; -} - -// Get identity matrix -static Matrix rlMatrixIdentity(void) -{ - Matrix result = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; - - return result; -} - -// Get two matrix multiplication -// NOTE: When multiplying matrices... the order matters! -static Matrix rlMatrixMultiply(Matrix left, Matrix right) -{ - Matrix result = { 0 }; - - result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12; - result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13; - result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14; - result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15; - result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12; - result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13; - result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14; - result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15; - result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12; - result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13; - result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14; - result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15; - result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12; - result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13; - result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14; - result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15; - - return result; -} - -// Transposes provided matrix -static Matrix rlMatrixTranspose(Matrix mat) -{ - Matrix result = { 0 }; - - result.m0 = mat.m0; - result.m1 = mat.m4; - result.m2 = mat.m8; - result.m3 = mat.m12; - result.m4 = mat.m1; - result.m5 = mat.m5; - result.m6 = mat.m9; - result.m7 = mat.m13; - result.m8 = mat.m2; - result.m9 = mat.m6; - result.m10 = mat.m10; - result.m11 = mat.m14; - result.m12 = mat.m3; - result.m13 = mat.m7; - result.m14 = mat.m11; - result.m15 = mat.m15; - - return result; -} - -// Invert provided matrix -static Matrix rlMatrixInvert(Matrix mat) -{ - Matrix result = { 0 }; - - // Cache the matrix values (speed optimization) - float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; - float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; - float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; - float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; - - float b00 = a00*a11 - a01*a10; - float b01 = a00*a12 - a02*a10; - float b02 = a00*a13 - a03*a10; - float b03 = a01*a12 - a02*a11; - float b04 = a01*a13 - a03*a11; - float b05 = a02*a13 - a03*a12; - float b06 = a20*a31 - a21*a30; - float b07 = a20*a32 - a22*a30; - float b08 = a20*a33 - a23*a30; - float b09 = a21*a32 - a22*a31; - float b10 = a21*a33 - a23*a31; - float b11 = a22*a33 - a23*a32; - - // Calculate the invert determinant (inlined to avoid double-caching) - float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); - - result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet; - result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet; - result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet; - result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet; - result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet; - result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet; - result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet; - result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet; - result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet; - result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet; - result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet; - result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet; - result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet; - result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet; - result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet; - result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet; - - return result; -} - #endif // RLGL_IMPLEMENTATION diff --git a/raylib/rlgl_cgo.go b/raylib/rlgl_cgo.go deleted file mode 100644 index bd60809..0000000 --- a/raylib/rlgl_cgo.go +++ /dev/null @@ -1,1010 +0,0 @@ -package rl - -/* -#include "raylib.h" -#include "rlgl.h" -#include -*/ -import "C" -import ( - "unsafe" -) - -// SetMatrixProjection - Set a custom projection matrix (replaces internal projection matrix) -func SetMatrixProjection(proj Matrix) { - cproj := proj.cptr() - C.rlSetMatrixProjection(*cproj) -} - -// SetMatrixModelview - Set a custom modelview matrix (replaces internal modelview matrix) -func SetMatrixModelview(view Matrix) { - cview := view.cptr() - C.rlSetMatrixModelview(*cview) -} - -// BeginShaderMode - Begin custom shader drawing -func BeginShaderMode(shader Shader) { - cshader := shader.cptr() - C.BeginShaderMode(*cshader) -} - -// EndShaderMode - End custom shader drawing (use default shader) -func EndShaderMode() { - C.EndShaderMode() -} - -// BeginBlendMode - Begin blending mode (alpha, additive, multiplied) -func BeginBlendMode(mode BlendMode) { - cmode := (C.int)(mode) - C.BeginBlendMode(cmode) -} - -// EndBlendMode - End blending mode (reset to default: alpha blending) -func EndBlendMode() { - C.EndBlendMode() -} - -// MatrixMode - Choose the current matrix to be transformed -func MatrixMode(mode int32) { - cmode := C.int(mode) - C.rlMatrixMode(cmode) -} - -// PushMatrix - Push the current matrix to stack -func PushMatrix() { - C.rlPushMatrix() -} - -// PopMatrix - Pop lattest inserted matrix from stack -func PopMatrix() { - C.rlPopMatrix() -} - -// LoadIdentity - Reset current matrix to identity matrix -func LoadIdentity() { - C.rlLoadIdentity() -} - -// Translatef - Multiply the current matrix by a translation matrix -func Translatef(x float32, y float32, z float32) { - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - C.rlTranslatef(cx, cy, cz) -} - -// Rotatef - Multiply the current matrix by a rotation matrix -func Rotatef(angle float32, x float32, y float32, z float32) { - cangle := C.float(angle) - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - C.rlRotatef(cangle, cx, cy, cz) -} - -// Scalef - Multiply the current matrix by a scaling matrix -func Scalef(x float32, y float32, z float32) { - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - C.rlScalef(cx, cy, cz) -} - -// MultMatrix - Multiply the current matrix by another matrix -func MultMatrix(m Matrix) { - f := MatrixToFloat(m) - C.rlMultMatrixf((*C.float)(&f[0])) -} - -// Frustum . -func Frustum(left float64, right float64, bottom float64, top float64, znear float64, zfar float64) { - cleft := C.double(left) - cright := C.double(right) - cbottom := C.double(bottom) - ctop := C.double(top) - cznear := C.double(znear) - czfar := C.double(zfar) - C.rlFrustum(cleft, cright, cbottom, ctop, cznear, czfar) -} - -// Ortho . -func Ortho(left float64, right float64, bottom float64, top float64, znear float64, zfar float64) { - cleft := C.double(left) - cright := C.double(right) - cbottom := C.double(bottom) - ctop := C.double(top) - cznear := C.double(znear) - czfar := C.double(zfar) - C.rlOrtho(cleft, cright, cbottom, ctop, cznear, czfar) -} - -// Viewport - Set the viewport area -func Viewport(x int32, y int32, width int32, height int32) { - cx := C.int(x) - cy := C.int(y) - cwidth := C.int(width) - cheight := C.int(height) - C.rlViewport(cx, cy, cwidth, cheight) -} - -// SetClipPlanes - Set clip planes distances -func SetClipPlanes(nearPlane, farPlane float64) { - C.rlSetClipPlanes(C.double(nearPlane), C.double(farPlane)) -} - -// GetCullDistanceNear - Get cull plane distance near -func GetCullDistanceNear() float64 { - ret := C.rlGetCullDistanceNear() - return float64(ret) -} - -// GetCullDistanceFar - Get cull plane distance far -func GetCullDistanceFar() float64 { - ret := C.rlGetCullDistanceFar() - return float64(ret) -} - -// Begin - Initialize drawing mode (how to organize vertex) -func Begin(mode int32) { - cmode := C.int(mode) - C.rlBegin(cmode) -} - -// End - Finish vertex providing -func End() { - C.rlEnd() -} - -// Vertex2i - Define one vertex (position) - 2 int -func Vertex2i(x int32, y int32) { - cx := C.int(x) - cy := C.int(y) - C.rlVertex2i(cx, cy) -} - -// Vertex2f - Define one vertex (position) - 2 float -func Vertex2f(x float32, y float32) { - cx := C.float(x) - cy := C.float(y) - C.rlVertex2f(cx, cy) -} - -// Vertex3f - Define one vertex (position) - 3 float -func Vertex3f(x float32, y float32, z float32) { - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - C.rlVertex3f(cx, cy, cz) -} - -// TexCoord2f - Define one vertex (texture coordinate) - 2 float -func TexCoord2f(x float32, y float32) { - cx := C.float(x) - cy := C.float(y) - C.rlTexCoord2f(cx, cy) -} - -// Normal3f - Define one vertex (normal) - 3 float -func Normal3f(x float32, y float32, z float32) { - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - C.rlNormal3f(cx, cy, cz) -} - -// Color4ub - Define one vertex (color) - 4 byte -func Color4ub(r uint8, g uint8, b uint8, a uint8) { - cr := C.uchar(r) - cg := C.uchar(g) - cb := C.uchar(b) - ca := C.uchar(a) - C.rlColor4ub(cr, cg, cb, ca) -} - -// Color3f - Define one vertex (color) - 3 float -func Color3f(x float32, y float32, z float32) { - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - C.rlColor3f(cx, cy, cz) -} - -// Color4f - Define one vertex (color) - 4 float -func Color4f(x float32, y float32, z float32, w float32) { - cx := C.float(x) - cy := C.float(y) - cz := C.float(z) - cw := C.float(w) - C.rlColor4f(cx, cy, cz, cw) -} - -// EnableVertexArray - Enable vertex array (VAO, if supported) -func EnableVertexArray(vaoId uint32) bool { - cvaoId := C.uint(vaoId) - return bool(C.rlEnableVertexArray(cvaoId)) -} - -// DisableVertexArray - Disable vertex array (VAO, if supported) -func DisableVertexArray() { - C.rlDisableVertexArray() -} - -// EnableVertexBuffer - Enable vertex buffer (VBO) -func EnableVertexBuffer(id uint32) { - cid := C.uint(id) - C.rlEnableVertexBuffer(cid) -} - -// DisableVertexBuffer - Disable vertex buffer (VBO) -func DisableVertexBuffer() { - C.rlDisableVertexBuffer() -} - -// EnableVertexBufferElement - Enable vertex buffer element (VBO element) -func EnableVertexBufferElement(id uint32) { - cid := C.uint(id) - C.rlEnableVertexBufferElement(cid) -} - -// DisableVertexBufferElement - Disable vertex buffer element (VBO element) -func DisableVertexBufferElement() { - C.rlDisableVertexBufferElement() -} - -// EnableVertexAttribute - Enable vertex attribute index -func EnableVertexAttribute(index uint32) { - cindex := C.uint(index) - C.rlEnableVertexAttribute(cindex) -} - -// DisableVertexAttribute - Disable vertex attribute index -func DisableVertexAttribute(index uint32) { - cindex := C.uint(index) - C.rlDisableVertexAttribute(cindex) -} - -// ActiveTextureSlot - Select and active a texture slot -func ActiveTextureSlot(slot int32) { - cslot := C.int(slot) - C.rlActiveTextureSlot(cslot) -} - -// EnableTexture - Enable texture -func EnableTexture(id uint32) { - cid := C.uint(id) - C.rlEnableTexture(cid) -} - -// DisableTexture - Disable texture -func DisableTexture() { - C.rlDisableTexture() -} - -// EnableTextureCubemap - Enable texture cubemap -func EnableTextureCubemap(id uint32) { - cid := C.uint(id) - C.rlEnableTextureCubemap(cid) -} - -// DisableTextureCubemap - Disable texture cubemap -func DisableTextureCubemap() { - C.rlDisableTextureCubemap() -} - -// TextureParameters - Set texture parameters (filter, wrap) -func TextureParameters(id uint32, param int32, value int32) { - cid := C.uint(id) - cparam := C.int(param) - cvalue := C.int(value) - C.rlTextureParameters(cid, cparam, cvalue) -} - -// CubemapParameters - Set cubemap parameters (filter, wrap) -func CubemapParameters(id uint32, param int32, value int32) { - cid := C.uint(id) - cparam := C.int(param) - cvalue := C.int(value) - C.rlCubemapParameters(cid, cparam, cvalue) -} - -// EnableShader - Enable shader program -func EnableShader(id uint32) { - cid := C.uint(id) - C.rlEnableShader(cid) -} - -// DisableShader - Disable shader program -func DisableShader() { - C.rlDisableShader() -} - -// EnableFramebuffer - Enable render texture (fbo) -func EnableFramebuffer(id uint32) { - cid := C.uint(id) - C.rlEnableFramebuffer(cid) -} - -// DisableFramebuffer - Disable render texture (fbo), return to default framebuffer -func DisableFramebuffer() { - C.rlDisableFramebuffer() -} - -// GetActiveFramebuffer - Get the currently active render texture (fbo), 0 for default framebuffer -func GetActiveFramebuffer() uint32 { - return uint32(C.rlGetActiveFramebuffer()) -} - -// ActiveDrawBuffers - Activate multiple draw color buffers -func ActiveDrawBuffers(count int32) { - ccount := C.int(count) - C.rlActiveDrawBuffers(ccount) -} - -// BlitFramebuffer - Blit active framebuffer to main framebuffer -func BlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask int32) { - C.rlBlitFramebuffer(C.int(srcX), C.int(srcY), C.int(srcWidth), C.int(srcHeight), C.int(dstX), C.int(dstY), C.int(dstWidth), C.int(dstHeight), C.int(bufferMask)) -} - -// BindFramebuffer - Bind framebuffer (FBO) -func BindFramebuffer(target, framebuffer uint32) { - C.rlBindFramebuffer(C.uint(target), C.uint(framebuffer)) -} - -// EnableColorBlend - Enable color blending -func EnableColorBlend() { - C.rlEnableColorBlend() -} - -// DisableColorBlend - Disable color blending -func DisableColorBlend() { - C.rlDisableColorBlend() -} - -// EnableDepthTest - Enable depth test -func EnableDepthTest() { - C.rlEnableDepthTest() -} - -// DisableDepthTest - Disable depth test -func DisableDepthTest() { - C.rlDisableDepthTest() -} - -// EnableDepthMask - Enable depth write -func EnableDepthMask() { - C.rlEnableDepthMask() -} - -// DisableDepthMask - Disable depth write -func DisableDepthMask() { - C.rlDisableDepthMask() -} - -// EnableBackfaceCulling - Enable backface culling -func EnableBackfaceCulling() { - C.rlEnableBackfaceCulling() -} - -// DisableBackfaceCulling - Disable backface culling -func DisableBackfaceCulling() { - C.rlDisableBackfaceCulling() -} - -// ColorMask - Color mask control -func ColorMask(r, g, b, a bool) { - C.rlColorMask(C.bool(r), C.bool(g), C.bool(b), C.bool(a)) -} - -// SetCullFace - Set face culling mode -func SetCullFace(mode int32) { - cmode := C.int(mode) - C.rlSetCullFace(cmode) -} - -// EnableScissorTest - Enable scissor test -func EnableScissorTest() { - C.rlEnableScissorTest() -} - -// DisableScissorTest - Disable scissor test -func DisableScissorTest() { - C.rlDisableScissorTest() -} - -// Scissor - Scissor test -func Scissor(x int32, y int32, width int32, height int32) { - cx := C.int(x) - cy := C.int(y) - cwidth := C.int(width) - cheight := C.int(height) - C.rlScissor(cx, cy, cwidth, cheight) -} - -// EnableWireMode - Enable wire mode -func EnableWireMode() { - C.rlEnableWireMode() -} - -// EnablePointMode - Enable point mode -func EnablePointMode() { - C.rlEnablePointMode() -} - -// DisableWireMode - Disable wire mode -func DisableWireMode() { - C.rlDisableWireMode() -} - -// SetLineWidth - Set the line drawing width -func SetLineWidth(width float32) { - cwidth := C.float(width) - C.rlSetLineWidth(cwidth) -} - -// GetLineWidth - Get the line drawing width -func GetLineWidth() float32 { - return float32(C.rlGetLineWidth()) -} - -// EnableSmoothLines - Enable line aliasing -func EnableSmoothLines() { - C.rlEnableSmoothLines() -} - -// DisableSmoothLines - Disable line aliasing -func DisableSmoothLines() { - C.rlDisableSmoothLines() -} - -// EnableStereoRender - Enable stereo rendering -func EnableStereoRender() { - C.rlEnableStereoRender() -} - -// DisableStereoRender - Disable stereo rendering -func DisableStereoRender() { - C.rlDisableStereoRender() -} - -// IsStereoRenderEnabled - Check if stereo render is enabled -func IsStereoRenderEnabled() bool { - return bool(C.rlIsStereoRenderEnabled()) -} - -// ClearColor - Clear color buffer with color -func ClearColor(r uint8, g uint8, b uint8, a uint8) { - cr := C.uchar(r) - cg := C.uchar(g) - cb := C.uchar(b) - ca := C.uchar(a) - C.rlClearColor(cr, cg, cb, ca) -} - -// ClearScreenBuffers - Clear used screen buffers (color and depth) -func ClearScreenBuffers() { - C.rlClearScreenBuffers() -} - -// CheckErrors - Check and log OpenGL error codes -func CheckErrors() { - C.rlCheckErrors() -} - -// SetBlendMode - Set blending mode -func SetBlendMode(mode BlendMode) { - cmode := C.int(mode) - C.rlSetBlendMode(cmode) -} - -// SetBlendFactors - Set blending mode factor and equation (using OpenGL factors) -func SetBlendFactors(glSrcFactor int32, glDstFactor int32, glEquation int32) { - cglSrcFactor := C.int(glSrcFactor) - cglDstFactor := C.int(glDstFactor) - cglEquation := C.int(glEquation) - C.rlSetBlendFactors(cglSrcFactor, cglDstFactor, cglEquation) -} - -// SetBlendFactorsSeparate - Set blending mode factors and equations separately (using OpenGL factors) -func SetBlendFactorsSeparate(glSrcRGB int32, glDstRGB int32, glSrcAlpha int32, glDstAlpha int32, glEqRGB int32, glEqAlpha int32) { - cglSrcRGB := C.int(glSrcRGB) - cglDstRGB := C.int(glDstRGB) - cglSrcAlpha := C.int(glSrcAlpha) - cglDstAlpha := C.int(glDstAlpha) - cglEqRGB := C.int(glEqRGB) - cglEqAlpha := C.int(glEqAlpha) - C.rlSetBlendFactorsSeparate(cglSrcRGB, cglDstRGB, cglSrcAlpha, cglDstAlpha, cglEqRGB, cglEqAlpha) -} - -// GlInit - Initialize rlgl (buffers, shaders, textures, states) -func GlInit(width int32, height int32) { - cwidth := C.int(width) - cheight := C.int(height) - C.rlglInit(cwidth, cheight) -} - -// GlClose - De-inititialize rlgl (buffers, shaders, textures) -func GlClose() { - C.rlglClose() -} - -// GetVersion - Get current OpenGL version -func GetVersion() int32 { - return int32(C.rlGetVersion()) -} - -// SetFramebufferWidth - Set current framebuffer width -func SetFramebufferWidth(width int32) { - cwidth := C.int(width) - C.rlSetFramebufferWidth(cwidth) -} - -// GetFramebufferWidth - Get default framebuffer width -func GetFramebufferWidth() int32 { - return int32(C.rlGetFramebufferWidth()) -} - -// SetFramebufferHeight - Set current framebuffer height -func SetFramebufferHeight(height int32) { - cheight := C.int(height) - C.rlSetFramebufferHeight(cheight) -} - -// GetFramebufferHeight - Get default framebuffer height -func GetFramebufferHeight() int32 { - return int32(C.rlGetFramebufferHeight()) -} - -// GetTextureIdDefault - Get default texture id -func GetTextureIdDefault() uint32 { - return uint32(C.rlGetTextureIdDefault()) -} - -// GetShaderIdDefault - Get default shader id -func GetShaderIdDefault() uint32 { - return uint32(C.rlGetShaderIdDefault()) -} - -// LoadRenderBatch - Load a render batch system -func LoadRenderBatch(numBuffers int32, bufferElements int32) RenderBatch { - ret := C.rlLoadRenderBatch(C.int(numBuffers), C.int(bufferElements)) - return *(*RenderBatch)(unsafe.Pointer(&ret)) -} - -// UnloadRenderBatch - Unload render batch system -func UnloadRenderBatch(batch RenderBatch) { - C.rlUnloadRenderBatch(*(*C.rlRenderBatch)(unsafe.Pointer(&batch))) -} - -// DrawRenderBatch - Draw render batch data (Update->Draw->Reset) -func DrawRenderBatch(batch *RenderBatch) { - C.rlDrawRenderBatch((*C.rlRenderBatch)(unsafe.Pointer(batch))) -} - -// SetRenderBatchActive - Set the active render batch for rlgl (NULL for default internal) -func SetRenderBatchActive(batch *RenderBatch) { - C.rlSetRenderBatchActive((*C.rlRenderBatch)(unsafe.Pointer(batch))) -} - -// DrawRenderBatchActive - Update and draw internal render batch -func DrawRenderBatchActive() { - C.rlDrawRenderBatchActive() -} - -// CheckRenderBatchLimit - Check internal buffer overflow for a given number of vertex -func CheckRenderBatchLimit(vCount int32) bool { - cvCount := C.int(vCount) - return bool(C.rlCheckRenderBatchLimit(cvCount)) -} - -// SetTexture - Set current texture for render batch and check buffers limits -func SetTexture(id uint32) { - cid := C.uint(id) - C.rlSetTexture(cid) -} - -// LoadVertexArray - Load vertex array (vao) if supported -func LoadVertexArray() uint32 { - return uint32(C.rlLoadVertexArray()) -} - -// UnloadVertexBuffer . -func UnloadVertexBuffer(vboId uint32) { - cvboId := C.uint(vboId) - C.rlUnloadVertexBuffer(cvboId) -} - -// SetVertexAttributeDivisor . -func SetVertexAttributeDivisor(index uint32, divisor int32) { - cindex := C.uint(index) - cdivisor := C.int(divisor) - C.rlSetVertexAttributeDivisor(cindex, cdivisor) -} - -// LoadTextureDepth - Load depth texture/renderbuffer (to be attached to fbo) -func LoadTextureDepth(width, height int32, useRenderBuffer bool) uint32 { - cwidth := C.int(width) - cheight := C.int(height) - cuseRenderBuffer := C.bool(useRenderBuffer) - cid := C.rlLoadTextureDepth(cwidth, cheight, cuseRenderBuffer) - return uint32(cid) -} - -// LoadFramebuffer - Load an empty framebuffer -func LoadFramebuffer() uint32 { - return uint32(C.rlLoadFramebuffer()) -} - -// FramebufferAttach - Attach texture/renderbuffer to a framebuffer -func FramebufferAttach(fboId uint32, texId uint32, attachType int32, texType int32, mipLevel int32) { - cfboId := C.uint(fboId) - ctexId := C.uint(texId) - cattachType := C.int(attachType) - ctexType := C.int(texType) - cmipLevel := C.int(mipLevel) - C.rlFramebufferAttach(cfboId, ctexId, cattachType, ctexType, cmipLevel) -} - -// FramebufferComplete - Verify framebuffer is complete -func FramebufferComplete(id uint32) bool { - cid := C.uint(id) - return bool(C.rlFramebufferComplete(cid)) -} - -// UnloadFramebuffer - Delete framebuffer from GPU -func UnloadFramebuffer(id uint32) { - cid := C.uint(id) - C.rlUnloadFramebuffer(cid) -} - -// LoadShaderCode - Load shader from code strings -func LoadShaderCode(vsCode string, fsCode string) uint32 { - cvsCode := C.CString(vsCode) - defer C.free(unsafe.Pointer(cvsCode)) - cfsCode := C.CString(fsCode) - defer C.free(unsafe.Pointer(cfsCode)) - return uint32(C.rlLoadShaderCode(cvsCode, cfsCode)) -} - -// CompileShader - Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER) -func CompileShader(shaderCode string, type_ int32) uint32 { - cshaderCode := C.CString(shaderCode) - defer C.free(unsafe.Pointer(cshaderCode)) - ctype_ := C.int(type_) - return uint32(C.rlCompileShader(cshaderCode, ctype_)) -} - -// LoadShaderProgram - Load custom shader program -func LoadShaderProgram(vShaderId uint32, fShaderId uint32) uint32 { - cvShaderId := C.uint(vShaderId) - cfShaderId := C.uint(fShaderId) - return uint32(C.rlLoadShaderProgram(cvShaderId, cfShaderId)) -} - -// UnloadShaderProgram - Unload shader program -func UnloadShaderProgram(id uint32) { - cid := C.uint(id) - C.rlUnloadShaderProgram(cid) -} - -// GetLocationUniform - Get shader location uniform -func GetLocationUniform(shaderId uint32, uniformName string) int32 { - cshaderId := C.uint(shaderId) - cuniformName := C.CString(uniformName) - defer C.free(unsafe.Pointer(cuniformName)) - return int32(C.rlGetLocationUniform(cshaderId, cuniformName)) -} - -// GetLocationAttrib - Get shader location attribute -func GetLocationAttrib(shaderId uint32, attribName string) int32 { - cshaderId := C.uint(shaderId) - cattribName := C.CString(attribName) - defer C.free(unsafe.Pointer(cattribName)) - return int32(C.rlGetLocationAttrib(cshaderId, cattribName)) -} - -// SetUniform - Set shader value uniform -func SetUniform(locIndex int32, value []float32, uniformType int32) { - C.rlSetUniform(C.int(locIndex), unsafe.Pointer(unsafe.SliceData(value)), C.int(uniformType), C.int((len(value)))) -} - -// SetUniformMatrix - Set shader value matrix -func SetUniformMatrix(locIndex int32, mat Matrix) { - cmat := (*C.Matrix)(unsafe.Pointer(&mat)) - C.rlSetUniformMatrix(C.int(locIndex), *cmat) -} - -// SetUniformMatrices - Set shader value matrices -func SetUniformMatrices(locIndex int32, mat []Matrix) { - cmat := (*C.Matrix)(unsafe.Pointer(unsafe.SliceData(mat))) - C.rlSetUniformMatrices(C.int(locIndex), cmat, C.int(len(mat))) -} - -// SetUniformSampler - Set shader value sampler -func SetUniformSampler(locIndex int32, textureId uint32) { - clocIndex := C.int(locIndex) - ctextureId := C.uint(textureId) - C.rlSetUniformSampler(clocIndex, ctextureId) -} - -// LoadComputeShaderProgram - -func LoadComputeShaderProgram(shaderID uint32) uint32 { - cshaderID := C.uint(shaderID) - return uint32(C.rlLoadComputeShaderProgram(cshaderID)) -} - -// ComputeShaderDispatch - Dispatch compute shader (equivalent to *draw* for graphics pilepine) -func ComputeShaderDispatch(groupX uint32, groupY uint32, groupZ uint32) { - cgroupX := C.uint(groupX) - cgroupY := C.uint(groupY) - cgroupZ := C.uint(groupZ) - C.rlComputeShaderDispatch(cgroupX, cgroupY, cgroupZ) -} - -// LoadShaderBuffer - Load shader storage buffer object (SSBO) -func LoadShaderBuffer(size uint32, data unsafe.Pointer, usageHint int32) uint32 { - csize := C.uint(size) - cdata := data - cusageHint := C.int(usageHint) - return uint32(C.rlLoadShaderBuffer(csize, cdata, cusageHint)) -} - -// UnloadShaderBuffer - Unload shader storage buffer object (SSBO) -func UnloadShaderBuffer(id uint32) { - cid := C.uint(id) - C.rlUnloadShaderBuffer(cid) -} - -// UpdateShaderBuffer - Update SSBO buffer data -func UpdateShaderBuffer(id uint32, data unsafe.Pointer, dataSize uint32, offset uint32) { - cid := C.uint(id) - cdata := data - cdataSize := C.uint(dataSize) - coffset := C.uint(offset) - C.rlUpdateShaderBuffer(cid, cdata, cdataSize, coffset) -} - -// BindShaderBuffer - Bind SSBO buffer -func BindShaderBuffer(id uint32, index uint32) { - cid := C.uint(id) - cindex := C.uint(index) - C.rlBindShaderBuffer(cid, cindex) -} - -// ReadShaderBuffer - Read SSBO buffer data (GPU->CPU) -func ReadShaderBuffer(id uint32, dest unsafe.Pointer, count uint32, offset uint32) { - cid := C.uint(id) - cdest := dest - ccount := C.uint(count) - coffset := C.uint(offset) - C.rlReadShaderBuffer(cid, cdest, ccount, coffset) -} - -// CopyShaderBuffer - Copy SSBO data between buffers -func CopyShaderBuffer(destId uint32, srcId uint32, destOffset uint32, srcOffset uint32, count uint32) { - cdestId := C.uint(destId) - csrcId := C.uint(srcId) - cdestOffset := C.uint(destOffset) - csrcOffset := C.uint(srcOffset) - ccount := C.uint(count) - C.rlCopyShaderBuffer(cdestId, csrcId, cdestOffset, csrcOffset, ccount) -} - -// GetShaderBufferSize - Get SSBO buffer size -func GetShaderBufferSize(id uint32) uint32 { - cid := C.uint(id) - return uint32(C.rlGetShaderBufferSize(cid)) -} - -// BindImageTexture - Bind image texture -func BindImageTexture(id uint32, index uint32, format int32, readonly bool) { - cid := C.uint(id) - cindex := C.uint(index) - cformat := C.int(format) - creadonly := C.bool(readonly) - C.rlBindImageTexture(cid, cindex, cformat, creadonly) -} - -// GetMatrixModelview - Get internal modelview matrix -func GetMatrixModelview() Matrix { - cResult := C.rlGetMatrixModelview() - var goRes Matrix - goRes.M4 = float32(cResult.m4) - goRes.M2 = float32(cResult.m2) - goRes.M14 = float32(cResult.m14) - goRes.M3 = float32(cResult.m3) - goRes.M7 = float32(cResult.m7) - goRes.M12 = float32(cResult.m12) - goRes.M6 = float32(cResult.m6) - goRes.M15 = float32(cResult.m15) - goRes.M5 = float32(cResult.m5) - goRes.M9 = float32(cResult.m9) - goRes.M13 = float32(cResult.m13) - goRes.M10 = float32(cResult.m10) - goRes.M11 = float32(cResult.m11) - goRes.M0 = float32(cResult.m0) - goRes.M8 = float32(cResult.m8) - goRes.M1 = float32(cResult.m1) - return goRes -} - -// GetMatrixProjection - Get internal projection matrix -func GetMatrixProjection() Matrix { - cResult := C.rlGetMatrixProjection() - var goRes Matrix - goRes.M13 = float32(cResult.m13) - goRes.M10 = float32(cResult.m10) - goRes.M11 = float32(cResult.m11) - goRes.M15 = float32(cResult.m15) - goRes.M5 = float32(cResult.m5) - goRes.M9 = float32(cResult.m9) - goRes.M1 = float32(cResult.m1) - goRes.M0 = float32(cResult.m0) - goRes.M8 = float32(cResult.m8) - goRes.M14 = float32(cResult.m14) - goRes.M3 = float32(cResult.m3) - goRes.M7 = float32(cResult.m7) - goRes.M4 = float32(cResult.m4) - goRes.M2 = float32(cResult.m2) - goRes.M12 = float32(cResult.m12) - goRes.M6 = float32(cResult.m6) - return goRes -} - -// GetMatrixTransform - Get internal accumulated transform matrix -func GetMatrixTransform() Matrix { - cResult := C.rlGetMatrixTransform() - var goRes Matrix - goRes.M0 = float32(cResult.m0) - goRes.M8 = float32(cResult.m8) - goRes.M1 = float32(cResult.m1) - goRes.M7 = float32(cResult.m7) - goRes.M4 = float32(cResult.m4) - goRes.M2 = float32(cResult.m2) - goRes.M14 = float32(cResult.m14) - goRes.M3 = float32(cResult.m3) - goRes.M12 = float32(cResult.m12) - goRes.M6 = float32(cResult.m6) - goRes.M11 = float32(cResult.m11) - goRes.M15 = float32(cResult.m15) - goRes.M5 = float32(cResult.m5) - goRes.M9 = float32(cResult.m9) - goRes.M13 = float32(cResult.m13) - goRes.M10 = float32(cResult.m10) - return goRes -} - -// GetMatrixProjectionStereo - Get internal projection matrix for stereo render (selected eye) -func GetMatrixProjectionStereo(eye int32) Matrix { - ceye := C.int(eye) - cResult := C.rlGetMatrixProjectionStereo(ceye) - var goRes Matrix - goRes.M12 = float32(cResult.m12) - goRes.M6 = float32(cResult.m6) - goRes.M15 = float32(cResult.m15) - goRes.M5 = float32(cResult.m5) - goRes.M9 = float32(cResult.m9) - goRes.M13 = float32(cResult.m13) - goRes.M10 = float32(cResult.m10) - goRes.M11 = float32(cResult.m11) - goRes.M0 = float32(cResult.m0) - goRes.M8 = float32(cResult.m8) - goRes.M1 = float32(cResult.m1) - goRes.M4 = float32(cResult.m4) - goRes.M2 = float32(cResult.m2) - goRes.M14 = float32(cResult.m14) - goRes.M3 = float32(cResult.m3) - goRes.M7 = float32(cResult.m7) - return goRes -} - -// GetMatrixViewOffsetStereo - Get internal view offset matrix for stereo render (selected eye) -func GetMatrixViewOffsetStereo(eye int32) Matrix { - ceye := C.int(eye) - cResult := C.rlGetMatrixViewOffsetStereo(ceye) - var goRes Matrix - goRes.M0 = float32(cResult.m0) - goRes.M8 = float32(cResult.m8) - goRes.M1 = float32(cResult.m1) - goRes.M4 = float32(cResult.m4) - goRes.M2 = float32(cResult.m2) - goRes.M14 = float32(cResult.m14) - goRes.M3 = float32(cResult.m3) - goRes.M7 = float32(cResult.m7) - goRes.M12 = float32(cResult.m12) - goRes.M6 = float32(cResult.m6) - goRes.M5 = float32(cResult.m5) - goRes.M9 = float32(cResult.m9) - goRes.M13 = float32(cResult.m13) - goRes.M10 = float32(cResult.m10) - goRes.M11 = float32(cResult.m11) - goRes.M15 = float32(cResult.m15) - return goRes -} - -// SetMatrixProjectionStereo - Set eyes projection matrices for stereo rendering -func SetMatrixProjectionStereo(right Matrix, left Matrix) { - var cright C.struct_Matrix - cright.m12 = C.float(right.M12) - cright.m6 = C.float(right.M6) - cright.m5 = C.float(right.M5) - cright.m9 = C.float(right.M9) - cright.m13 = C.float(right.M13) - cright.m10 = C.float(right.M10) - cright.m11 = C.float(right.M11) - cright.m15 = C.float(right.M15) - cright.m0 = C.float(right.M0) - cright.m8 = C.float(right.M8) - cright.m1 = C.float(right.M1) - cright.m4 = C.float(right.M4) - cright.m2 = C.float(right.M2) - cright.m14 = C.float(right.M14) - cright.m3 = C.float(right.M3) - cright.m7 = C.float(right.M7) - var cleft C.struct_Matrix - cleft.m10 = C.float(left.M10) - cleft.m11 = C.float(left.M11) - cleft.m15 = C.float(left.M15) - cleft.m5 = C.float(left.M5) - cleft.m9 = C.float(left.M9) - cleft.m13 = C.float(left.M13) - cleft.m0 = C.float(left.M0) - cleft.m8 = C.float(left.M8) - cleft.m1 = C.float(left.M1) - cleft.m3 = C.float(left.M3) - cleft.m7 = C.float(left.M7) - cleft.m4 = C.float(left.M4) - cleft.m2 = C.float(left.M2) - cleft.m14 = C.float(left.M14) - cleft.m12 = C.float(left.M12) - cleft.m6 = C.float(left.M6) - C.rlSetMatrixProjectionStereo(cright, cleft) -} - -// SetMatrixViewOffsetStereo - Set eyes view offsets matrices for stereo rendering -func SetMatrixViewOffsetStereo(right Matrix, left Matrix) { - var cright C.struct_Matrix - cright.m12 = C.float(right.M12) - cright.m6 = C.float(right.M6) - cright.m5 = C.float(right.M5) - cright.m9 = C.float(right.M9) - cright.m13 = C.float(right.M13) - cright.m10 = C.float(right.M10) - cright.m11 = C.float(right.M11) - cright.m15 = C.float(right.M15) - cright.m0 = C.float(right.M0) - cright.m8 = C.float(right.M8) - cright.m1 = C.float(right.M1) - cright.m4 = C.float(right.M4) - cright.m2 = C.float(right.M2) - cright.m14 = C.float(right.M14) - cright.m3 = C.float(right.M3) - cright.m7 = C.float(right.M7) - var cleft C.struct_Matrix - cleft.m12 = C.float(left.M12) - cleft.m6 = C.float(left.M6) - cleft.m5 = C.float(left.M5) - cleft.m9 = C.float(left.M9) - cleft.m13 = C.float(left.M13) - cleft.m10 = C.float(left.M10) - cleft.m11 = C.float(left.M11) - cleft.m15 = C.float(left.M15) - cleft.m0 = C.float(left.M0) - cleft.m8 = C.float(left.M8) - cleft.m1 = C.float(left.M1) - cleft.m4 = C.float(left.M4) - cleft.m2 = C.float(left.M2) - cleft.m14 = C.float(left.M14) - cleft.m3 = C.float(left.M3) - cleft.m7 = C.float(left.M7) - C.rlSetMatrixViewOffsetStereo(cright, cleft) -} - -// LoadDrawCube - Load and draw a cube -func LoadDrawCube() { - C.rlLoadDrawCube() -} - -// LoadDrawQuad - Load and draw a quad -func LoadDrawQuad() { - C.rlLoadDrawQuad() -} diff --git a/raylib/rlgl_purego.go b/raylib/rlgl_purego.go deleted file mode 100644 index 1439cfa..0000000 --- a/raylib/rlgl_purego.go +++ /dev/null @@ -1,944 +0,0 @@ -//go:build !cgo && windows -// +build !cgo,windows - -package rl - -import ( - "unsafe" - - "github.com/ebitengine/purego" -) - -var rlMatrixMode func(mode int32) -var rlPushMatrix func() -var rlPopMatrix func() -var rlLoadIdentity func() -var rlTranslatef func(x float32, y float32, z float32) -var rlRotatef func(angle float32, x float32, y float32, z float32) -var rlScalef func(x float32, y float32, z float32) -var rlMultMatrixf func(matf *float32) -var rlFrustum func(left float64, right float64, bottom float64, top float64, znear float64, zfar float64) -var rlOrtho func(left float64, right float64, bottom float64, top float64, znear float64, zfar float64) -var rlViewport func(x int32, y int32, width int32, height int32) -var rlSetClipPlanes func(float64, float64) -var rlGetCullDistanceNear func() float64 -var rlGetCullDistanceFar func() float64 -var rlBegin func(mode int32) -var rlEnd func() -var rlVertex2i func(x int32, y int32) -var rlVertex2f func(x float32, y float32) -var rlVertex3f func(x float32, y float32, z float32) -var rlTexCoord2f func(x float32, y float32) -var rlNormal3f func(x float32, y float32, z float32) -var rlColor4ub func(r byte, g byte, b byte, a byte) -var rlColor3f func(x float32, y float32, z float32) -var rlColor4f func(x float32, y float32, z float32, w float32) -var rlEnableVertexArray func(vaoId uint32) bool -var rlDisableVertexArray func() -var rlEnableVertexBuffer func(id uint32) -var rlDisableVertexBuffer func() -var rlEnableVertexBufferElement func(id uint32) -var rlDisableVertexBufferElement func() -var rlEnableVertexAttribute func(index uint32) -var rlDisableVertexAttribute func(index uint32) -var rlActiveTextureSlot func(slot int32) -var rlEnableTexture func(id uint32) -var rlDisableTexture func() -var rlEnableTextureCubemap func(id uint32) -var rlDisableTextureCubemap func() -var rlTextureParameters func(id uint32, param int32, value int32) -var rlCubemapParameters func(id uint32, param int32, value int32) -var rlEnableShader func(id uint32) -var rlDisableShader func() -var rlEnableFramebuffer func(id uint32) -var rlDisableFramebuffer func() -var rlGetActiveFramebuffer func() uint32 -var rlActiveDrawBuffers func(count int32) -var rlBlitFramebuffer func(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask int32) -var rlBindFramebuffer func(target, framebuffer uint32) -var rlEnableColorBlend func() -var rlDisableColorBlend func() -var rlEnableDepthTest func() -var rlDisableDepthTest func() -var rlEnableDepthMask func() -var rlDisableDepthMask func() -var rlEnableBackfaceCulling func() -var rlDisableBackfaceCulling func() -var rlColorMask func(r, g, b, a bool) -var rlSetCullFace func(mode int32) -var rlEnableScissorTest func() -var rlDisableScissorTest func() -var rlScissor func(x int32, y int32, width int32, height int32) -var rlEnableWireMode func() -var rlEnablePointMode func() -var rlDisableWireMode func() -var rlSetLineWidth func(width float32) -var rlGetLineWidth func() float32 -var rlEnableSmoothLines func() -var rlDisableSmoothLines func() -var rlEnableStereoRender func() -var rlDisableStereoRender func() -var rlIsStereoRenderEnabled func() bool -var rlClearColor func(r byte, g byte, b byte, a byte) -var rlClearScreenBuffers func() -var rlCheckErrors func() -var rlSetBlendMode func(mode int32) -var rlSetBlendFactors func(glSrcFactor int32, glDstFactor int32, glEquation int32) -var rlSetBlendFactorsSeparate func(glSrcRGB int32, glDstRGB int32, glSrcAlpha int32, glDstAlpha int32, glEqRGB int32, glEqAlpha int32) -var rlglInit func(width int32, height int32) -var rlglClose func() -var rlGetVersion func() int32 -var rlSetFramebufferWidth func(width int32) -var rlGetFramebufferWidth func() int32 -var rlSetFramebufferHeight func(height int32) -var rlGetFramebufferHeight func() int32 -var rlGetTextureIdDefault func() uint32 -var rlGetShaderIdDefault func() uint32 -var rlLoadRenderBatch func(batch uintptr, numBuffers int32, bufferElements int32) -var rlUnloadRenderBatch func(batch uintptr) -var rlDrawRenderBatch func(batch *RenderBatch) -var rlSetRenderBatchActive func(batch *RenderBatch) -var rlDrawRenderBatchActive func() -var rlCheckRenderBatchLimit func(vCount int32) bool -var rlSetTexture func(id uint32) -var rlLoadVertexArray func() uint32 -var rlUnloadVertexBuffer func(vboId uint32) -var rlSetVertexAttributeDivisor func(index uint32, divisor int32) -var rlLoadTextureDepth func(width int32, height int32, useRenderBuffer bool) uint32 -var rlLoadFramebuffer func() uint32 -var rlFramebufferAttach func(fboId uint32, texId uint32, attachType int32, texType int32, mipLevel int32) -var rlFramebufferComplete func(id uint32) bool -var rlUnloadFramebuffer func(id uint32) -var rlLoadShaderCode func(vsCode string, fsCode string) uint32 -var rlCompileShader func(shaderCode string, _type int32) uint32 -var rlLoadShaderProgram func(vShaderId uint32, fShaderId uint32) uint32 -var rlUnloadShaderProgram func(id uint32) -var rlGetLocationUniform func(shaderId uint32, uniformName string) int32 -var rlGetLocationAttrib func(shaderId uint32, attribName string) int32 -var rlSetUniform func(locIndex int32, value unsafe.Pointer, uniformType, count int32) -var rlSetUniformMatrix func(locIndex int32, mat uintptr) -var rlSetUniformMatrices func(locIndex int32, mat *Matrix, count int32) -var rlSetUniformSampler func(locIndex int32, textureId uint32) -var rlLoadComputeShaderProgram func(shaderID uint32) uint32 -var rlComputeShaderDispatch func(groupX uint32, groupY uint32, groupZ uint32) -var rlLoadShaderBuffer func(size uint32, data unsafe.Pointer, usageHint int32) uint32 -var rlUnloadShaderBuffer func(id uint32) -var rlUpdateShaderBuffer func(id uint32, data unsafe.Pointer, dataSize uint32, offset uint32) -var rlBindShaderBuffer func(id uint32, index uint32) -var rlReadShaderBuffer func(id uint32, dest unsafe.Pointer, count uint32, offset uint32) -var rlCopyShaderBuffer func(destId uint32, srcId uint32, destOffset uint32, srcOffset uint32, count uint32) -var rlGetShaderBufferSize func(id uint32) uint32 -var rlBindImageTexture func(id uint32, index uint32, format int32, readonly bool) -var rlGetMatrixModelview func(matrix uintptr) -var rlGetMatrixProjection func(matrix uintptr) -var rlGetMatrixTransform func(matrix uintptr) -var rlGetMatrixProjectionStereo func(matrix uintptr, eye int32) -var rlGetMatrixViewOffsetStereo func(matrix uintptr, eye int32) -var rlSetMatrixProjection func(proj uintptr) -var rlSetMatrixModelview func(view uintptr) -var rlSetMatrixProjectionStereo func(right uintptr, left uintptr) -var rlSetMatrixViewOffsetStereo func(right uintptr, left uintptr) -var rlLoadDrawCube func() -var rlLoadDrawQuad func() - -func initRlglPurego() { - purego.RegisterLibFunc(&rlMatrixMode, raylibDll, "rlMatrixMode") - purego.RegisterLibFunc(&rlPushMatrix, raylibDll, "rlPushMatrix") - purego.RegisterLibFunc(&rlPopMatrix, raylibDll, "rlPopMatrix") - purego.RegisterLibFunc(&rlLoadIdentity, raylibDll, "rlLoadIdentity") - purego.RegisterLibFunc(&rlTranslatef, raylibDll, "rlTranslatef") - purego.RegisterLibFunc(&rlRotatef, raylibDll, "rlRotatef") - purego.RegisterLibFunc(&rlScalef, raylibDll, "rlScalef") - purego.RegisterLibFunc(&rlMultMatrixf, raylibDll, "rlMultMatrixf") - purego.RegisterLibFunc(&rlFrustum, raylibDll, "rlFrustum") - purego.RegisterLibFunc(&rlOrtho, raylibDll, "rlOrtho") - purego.RegisterLibFunc(&rlViewport, raylibDll, "rlViewport") - purego.RegisterLibFunc(&rlSetClipPlanes, raylibDll, "rlSetClipPlanes") - purego.RegisterLibFunc(&rlGetCullDistanceNear, raylibDll, "rlGetCullDistanceNear") - purego.RegisterLibFunc(&rlGetCullDistanceFar, raylibDll, "rlGetCullDistanceFar") - purego.RegisterLibFunc(&rlBegin, raylibDll, "rlBegin") - purego.RegisterLibFunc(&rlEnd, raylibDll, "rlEnd") - purego.RegisterLibFunc(&rlVertex2i, raylibDll, "rlVertex2i") - purego.RegisterLibFunc(&rlVertex2f, raylibDll, "rlVertex2f") - purego.RegisterLibFunc(&rlVertex3f, raylibDll, "rlVertex3f") - purego.RegisterLibFunc(&rlTexCoord2f, raylibDll, "rlTexCoord2f") - purego.RegisterLibFunc(&rlNormal3f, raylibDll, "rlNormal3f") - purego.RegisterLibFunc(&rlColor4ub, raylibDll, "rlColor4ub") - purego.RegisterLibFunc(&rlColor3f, raylibDll, "rlColor3f") - purego.RegisterLibFunc(&rlColor4f, raylibDll, "rlColor4f") - purego.RegisterLibFunc(&rlEnableVertexArray, raylibDll, "rlEnableVertexArray") - purego.RegisterLibFunc(&rlDisableVertexArray, raylibDll, "rlDisableVertexArray") - purego.RegisterLibFunc(&rlEnableVertexBuffer, raylibDll, "rlEnableVertexBuffer") - purego.RegisterLibFunc(&rlDisableVertexBuffer, raylibDll, "rlDisableVertexBuffer") - purego.RegisterLibFunc(&rlEnableVertexBufferElement, raylibDll, "rlEnableVertexBufferElement") - purego.RegisterLibFunc(&rlDisableVertexBufferElement, raylibDll, "rlDisableVertexBufferElement") - purego.RegisterLibFunc(&rlEnableVertexAttribute, raylibDll, "rlEnableVertexAttribute") - purego.RegisterLibFunc(&rlDisableVertexAttribute, raylibDll, "rlDisableVertexAttribute") - purego.RegisterLibFunc(&rlActiveTextureSlot, raylibDll, "rlActiveTextureSlot") - purego.RegisterLibFunc(&rlEnableTexture, raylibDll, "rlEnableTexture") - purego.RegisterLibFunc(&rlDisableTexture, raylibDll, "rlDisableTexture") - purego.RegisterLibFunc(&rlEnableTextureCubemap, raylibDll, "rlEnableTextureCubemap") - purego.RegisterLibFunc(&rlDisableTextureCubemap, raylibDll, "rlDisableTextureCubemap") - purego.RegisterLibFunc(&rlTextureParameters, raylibDll, "rlTextureParameters") - purego.RegisterLibFunc(&rlCubemapParameters, raylibDll, "rlCubemapParameters") - purego.RegisterLibFunc(&rlEnableShader, raylibDll, "rlEnableShader") - purego.RegisterLibFunc(&rlDisableShader, raylibDll, "rlDisableShader") - purego.RegisterLibFunc(&rlEnableFramebuffer, raylibDll, "rlEnableFramebuffer") - purego.RegisterLibFunc(&rlDisableFramebuffer, raylibDll, "rlDisableFramebuffer") - purego.RegisterLibFunc(&rlGetActiveFramebuffer, raylibDll, "rlGetActiveFramebuffer") - purego.RegisterLibFunc(&rlActiveDrawBuffers, raylibDll, "rlActiveDrawBuffers") - purego.RegisterLibFunc(&rlBlitFramebuffer, raylibDll, "rlBlitFramebuffer") - purego.RegisterLibFunc(&rlBindFramebuffer, raylibDll, "rlBindFramebuffer") - purego.RegisterLibFunc(&rlEnableColorBlend, raylibDll, "rlEnableColorBlend") - purego.RegisterLibFunc(&rlDisableColorBlend, raylibDll, "rlDisableColorBlend") - purego.RegisterLibFunc(&rlEnableDepthTest, raylibDll, "rlEnableDepthTest") - purego.RegisterLibFunc(&rlDisableDepthTest, raylibDll, "rlDisableDepthTest") - purego.RegisterLibFunc(&rlEnableDepthMask, raylibDll, "rlEnableDepthMask") - purego.RegisterLibFunc(&rlDisableDepthMask, raylibDll, "rlDisableDepthMask") - purego.RegisterLibFunc(&rlEnableBackfaceCulling, raylibDll, "rlEnableBackfaceCulling") - purego.RegisterLibFunc(&rlDisableBackfaceCulling, raylibDll, "rlDisableBackfaceCulling") - purego.RegisterLibFunc(&rlColorMask, raylibDll, "rlColorMask") - purego.RegisterLibFunc(&rlSetCullFace, raylibDll, "rlSetCullFace") - purego.RegisterLibFunc(&rlEnableScissorTest, raylibDll, "rlEnableScissorTest") - purego.RegisterLibFunc(&rlDisableScissorTest, raylibDll, "rlDisableScissorTest") - purego.RegisterLibFunc(&rlScissor, raylibDll, "rlScissor") - purego.RegisterLibFunc(&rlEnableWireMode, raylibDll, "rlEnableWireMode") - purego.RegisterLibFunc(&rlEnablePointMode, raylibDll, "rlEnablePointMode") - purego.RegisterLibFunc(&rlDisableWireMode, raylibDll, "rlDisableWireMode") - purego.RegisterLibFunc(&rlSetLineWidth, raylibDll, "rlSetLineWidth") - purego.RegisterLibFunc(&rlGetLineWidth, raylibDll, "rlGetLineWidth") - purego.RegisterLibFunc(&rlEnableSmoothLines, raylibDll, "rlEnableSmoothLines") - purego.RegisterLibFunc(&rlDisableSmoothLines, raylibDll, "rlDisableSmoothLines") - purego.RegisterLibFunc(&rlEnableStereoRender, raylibDll, "rlEnableStereoRender") - purego.RegisterLibFunc(&rlDisableStereoRender, raylibDll, "rlDisableStereoRender") - purego.RegisterLibFunc(&rlIsStereoRenderEnabled, raylibDll, "rlIsStereoRenderEnabled") - purego.RegisterLibFunc(&rlClearColor, raylibDll, "rlClearColor") - purego.RegisterLibFunc(&rlClearScreenBuffers, raylibDll, "rlClearScreenBuffers") - purego.RegisterLibFunc(&rlCheckErrors, raylibDll, "rlCheckErrors") - purego.RegisterLibFunc(&rlSetBlendMode, raylibDll, "rlSetBlendMode") - purego.RegisterLibFunc(&rlSetBlendFactors, raylibDll, "rlSetBlendFactors") - purego.RegisterLibFunc(&rlSetBlendFactorsSeparate, raylibDll, "rlSetBlendFactorsSeparate") - purego.RegisterLibFunc(&rlglInit, raylibDll, "rlglInit") - purego.RegisterLibFunc(&rlglClose, raylibDll, "rlglClose") - purego.RegisterLibFunc(&rlGetVersion, raylibDll, "rlGetVersion") - purego.RegisterLibFunc(&rlSetFramebufferWidth, raylibDll, "rlSetFramebufferWidth") - purego.RegisterLibFunc(&rlGetFramebufferWidth, raylibDll, "rlGetFramebufferWidth") - purego.RegisterLibFunc(&rlSetFramebufferHeight, raylibDll, "rlSetFramebufferHeight") - purego.RegisterLibFunc(&rlGetFramebufferHeight, raylibDll, "rlGetFramebufferHeight") - purego.RegisterLibFunc(&rlGetTextureIdDefault, raylibDll, "rlGetTextureIdDefault") - purego.RegisterLibFunc(&rlGetShaderIdDefault, raylibDll, "rlGetShaderIdDefault") - purego.RegisterLibFunc(&rlLoadRenderBatch, raylibDll, "rlLoadRenderBatch") - purego.RegisterLibFunc(&rlUnloadRenderBatch, raylibDll, "rlUnloadRenderBatch") - purego.RegisterLibFunc(&rlDrawRenderBatch, raylibDll, "rlDrawRenderBatch") - purego.RegisterLibFunc(&rlSetRenderBatchActive, raylibDll, "rlSetRenderBatchActive") - purego.RegisterLibFunc(&rlDrawRenderBatchActive, raylibDll, "rlDrawRenderBatchActive") - purego.RegisterLibFunc(&rlCheckRenderBatchLimit, raylibDll, "rlCheckRenderBatchLimit") - purego.RegisterLibFunc(&rlSetTexture, raylibDll, "rlSetTexture") - purego.RegisterLibFunc(&rlLoadVertexArray, raylibDll, "rlLoadVertexArray") - purego.RegisterLibFunc(&rlUnloadVertexBuffer, raylibDll, "rlUnloadVertexBuffer") - purego.RegisterLibFunc(&rlSetVertexAttributeDivisor, raylibDll, "rlSetVertexAttributeDivisor") - purego.RegisterLibFunc(&rlLoadTextureDepth, raylibDll, "rlLoadTextureDepth") - purego.RegisterLibFunc(&rlLoadFramebuffer, raylibDll, "rlLoadFramebuffer") - purego.RegisterLibFunc(&rlFramebufferAttach, raylibDll, "rlFramebufferAttach") - purego.RegisterLibFunc(&rlFramebufferComplete, raylibDll, "rlFramebufferComplete") - purego.RegisterLibFunc(&rlUnloadFramebuffer, raylibDll, "rlUnloadFramebuffer") - purego.RegisterLibFunc(&rlLoadShaderCode, raylibDll, "rlLoadShaderCode") - purego.RegisterLibFunc(&rlCompileShader, raylibDll, "rlCompileShader") - purego.RegisterLibFunc(&rlLoadShaderProgram, raylibDll, "rlLoadShaderProgram") - purego.RegisterLibFunc(&rlUnloadShaderProgram, raylibDll, "rlUnloadShaderProgram") - purego.RegisterLibFunc(&rlGetLocationUniform, raylibDll, "rlGetLocationUniform") - purego.RegisterLibFunc(&rlGetLocationAttrib, raylibDll, "rlGetLocationAttrib") - purego.RegisterLibFunc(&rlSetUniform, raylibDll, "rlSetUniform") - purego.RegisterLibFunc(&rlSetUniformMatrix, raylibDll, "rlSetUniformMatrix") - purego.RegisterLibFunc(&rlSetUniformMatrices, raylibDll, "rlSetUniformMatrices") - purego.RegisterLibFunc(&rlSetUniformSampler, raylibDll, "rlSetUniformSampler") - purego.RegisterLibFunc(&rlLoadComputeShaderProgram, raylibDll, "rlLoadComputeShaderProgram") - purego.RegisterLibFunc(&rlComputeShaderDispatch, raylibDll, "rlComputeShaderDispatch") - purego.RegisterLibFunc(&rlLoadShaderBuffer, raylibDll, "rlLoadShaderBuffer") - purego.RegisterLibFunc(&rlUnloadShaderBuffer, raylibDll, "rlUnloadShaderBuffer") - purego.RegisterLibFunc(&rlUpdateShaderBuffer, raylibDll, "rlUpdateShaderBuffer") - purego.RegisterLibFunc(&rlBindShaderBuffer, raylibDll, "rlBindShaderBuffer") - purego.RegisterLibFunc(&rlReadShaderBuffer, raylibDll, "rlReadShaderBuffer") - purego.RegisterLibFunc(&rlCopyShaderBuffer, raylibDll, "rlCopyShaderBuffer") - purego.RegisterLibFunc(&rlGetShaderBufferSize, raylibDll, "rlGetShaderBufferSize") - purego.RegisterLibFunc(&rlBindImageTexture, raylibDll, "rlBindImageTexture") - purego.RegisterLibFunc(&rlGetMatrixModelview, raylibDll, "rlGetMatrixModelview") - purego.RegisterLibFunc(&rlGetMatrixProjection, raylibDll, "rlGetMatrixProjection") - purego.RegisterLibFunc(&rlGetMatrixTransform, raylibDll, "rlGetMatrixTransform") - purego.RegisterLibFunc(&rlGetMatrixProjectionStereo, raylibDll, "rlGetMatrixProjectionStereo") - purego.RegisterLibFunc(&rlGetMatrixViewOffsetStereo, raylibDll, "rlGetMatrixViewOffsetStereo") - purego.RegisterLibFunc(&rlSetMatrixProjection, raylibDll, "rlSetMatrixProjection") - purego.RegisterLibFunc(&rlSetMatrixModelview, raylibDll, "rlSetMatrixModelview") - purego.RegisterLibFunc(&rlSetMatrixProjectionStereo, raylibDll, "rlSetMatrixProjectionStereo") - purego.RegisterLibFunc(&rlSetMatrixViewOffsetStereo, raylibDll, "rlSetMatrixViewOffsetStereo") - purego.RegisterLibFunc(&rlLoadDrawCube, raylibDll, "rlLoadDrawCube") - purego.RegisterLibFunc(&rlLoadDrawQuad, raylibDll, "rlLoadDrawQuad") -} - -// SetMatrixProjection - Set a custom projection matrix (replaces internal projection matrix) -func SetMatrixProjection(proj Matrix) { - rlSetMatrixProjection(uintptr(unsafe.Pointer(&proj))) -} - -// SetMatrixModelview - Set a custom modelview matrix (replaces internal modelview matrix) -func SetMatrixModelview(view Matrix) { - rlSetMatrixModelview(uintptr(unsafe.Pointer(&view))) -} - -// MatrixMode - Choose the current matrix to be transformed -func MatrixMode(mode int32) { - rlMatrixMode(mode) -} - -// PushMatrix - Push the current matrix to stack -func PushMatrix() { - rlPushMatrix() -} - -// PopMatrix - Pop lattest inserted matrix from stack -func PopMatrix() { - rlPopMatrix() -} - -// LoadIdentity - Reset current matrix to identity matrix -func LoadIdentity() { - rlLoadIdentity() -} - -// Translatef - Multiply the current matrix by a translation matrix -func Translatef(x float32, y float32, z float32) { - rlTranslatef(x, y, z) -} - -// Rotatef - Multiply the current matrix by a rotation matrix -func Rotatef(angle float32, x float32, y float32, z float32) { - rlRotatef(angle, x, y, z) -} - -// Scalef - Multiply the current matrix by a scaling matrix -func Scalef(x float32, y float32, z float32) { - rlScalef(x, y, z) -} - -// MultMatrix - Multiply the current matrix by another matrix -func MultMatrix(m Matrix) { - f := MatrixToFloat(m) - rlMultMatrixf((*float32)(&f[0])) -} - -// Frustum . -func Frustum(left float64, right float64, bottom float64, top float64, znear float64, zfar float64) { - rlFrustum(left, right, bottom, top, znear, zfar) -} - -// Ortho . -func Ortho(left float64, right float64, bottom float64, top float64, znear float64, zfar float64) { - rlOrtho(left, right, bottom, top, znear, zfar) -} - -// Viewport - Set the viewport area -func Viewport(x int32, y int32, width int32, height int32) { - rlViewport(x, y, width, height) -} - -// SetClipPlanes - Set clip planes distances -func SetClipPlanes(nearPlane, farPlane float64) { - rlSetClipPlanes(nearPlane, farPlane) -} - -// GetCullDistanceNear - Get cull plane distance near -func GetCullDistanceNear() float64 { - return rlGetCullDistanceNear() -} - -// GetCullDistanceFar - Get cull plane distance far -func GetCullDistanceFar() float64 { - return rlGetCullDistanceFar() -} - -// Begin - Initialize drawing mode (how to organize vertex) -func Begin(mode int32) { - rlBegin(mode) -} - -// End - Finish vertex providing -func End() { - rlEnd() -} - -// Vertex2i - Define one vertex (position) - 2 int -func Vertex2i(x int32, y int32) { - rlVertex2i(x, y) -} - -// Vertex2f - Define one vertex (position) - 2 float -func Vertex2f(x float32, y float32) { - rlVertex2f(x, y) -} - -// Vertex3f - Define one vertex (position) - 3 float -func Vertex3f(x float32, y float32, z float32) { - rlVertex3f(x, y, z) -} - -// TexCoord2f - Define one vertex (texture coordinate) - 2 float -func TexCoord2f(x float32, y float32) { - rlTexCoord2f(x, y) -} - -// Normal3f - Define one vertex (normal) - 3 float -func Normal3f(x float32, y float32, z float32) { - rlNormal3f(x, y, z) -} - -// Color4ub - Define one vertex (color) - 4 byte -func Color4ub(r uint8, g uint8, b uint8, a uint8) { - rlColor4ub(r, g, b, a) -} - -// Color3f - Define one vertex (color) - 3 float -func Color3f(x float32, y float32, z float32) { - rlColor3f(x, y, z) -} - -// Color4f - Define one vertex (color) - 4 float -func Color4f(x float32, y float32, z float32, w float32) { - rlColor4f(x, y, z, w) -} - -// EnableVertexArray - Enable vertex array (VAO, if supported) -func EnableVertexArray(vaoId uint32) bool { - return rlEnableVertexArray(vaoId) -} - -// DisableVertexArray - Disable vertex array (VAO, if supported) -func DisableVertexArray() { - rlDisableVertexArray() -} - -// EnableVertexBuffer - Enable vertex buffer (VBO) -func EnableVertexBuffer(id uint32) { - rlEnableVertexBuffer(id) -} - -// DisableVertexBuffer - Disable vertex buffer (VBO) -func DisableVertexBuffer() { - rlDisableVertexBuffer() -} - -// EnableVertexBufferElement - Enable vertex buffer element (VBO element) -func EnableVertexBufferElement(id uint32) { - rlEnableVertexBufferElement(id) -} - -// DisableVertexBufferElement - Disable vertex buffer element (VBO element) -func DisableVertexBufferElement() { - rlDisableVertexBufferElement() -} - -// EnableVertexAttribute - Enable vertex attribute index -func EnableVertexAttribute(index uint32) { - rlEnableVertexAttribute(index) -} - -// DisableVertexAttribute - Disable vertex attribute index -func DisableVertexAttribute(index uint32) { - rlDisableVertexAttribute(index) -} - -// ActiveTextureSlot - Select and active a texture slot -func ActiveTextureSlot(slot int32) { - rlActiveTextureSlot(slot) -} - -// EnableTexture - Enable texture -func EnableTexture(id uint32) { - rlEnableTexture(id) -} - -// DisableTexture - Disable texture -func DisableTexture() { - rlDisableTexture() -} - -// EnableTextureCubemap - Enable texture cubemap -func EnableTextureCubemap(id uint32) { - rlEnableTextureCubemap(id) -} - -// DisableTextureCubemap - Disable texture cubemap -func DisableTextureCubemap() { - rlDisableTextureCubemap() -} - -// TextureParameters - Set texture parameters (filter, wrap) -func TextureParameters(id uint32, param int32, value int32) { - rlTextureParameters(id, param, value) -} - -// CubemapParameters - Set cubemap parameters (filter, wrap) -func CubemapParameters(id uint32, param int32, value int32) { - rlCubemapParameters(id, param, value) -} - -// EnableShader - Enable shader program -func EnableShader(id uint32) { - rlEnableShader(id) -} - -// DisableShader - Disable shader program -func DisableShader() { - rlDisableShader() -} - -// EnableFramebuffer - Enable render texture (fbo) -func EnableFramebuffer(id uint32) { - rlEnableFramebuffer(id) -} - -// DisableFramebuffer - Disable render texture (fbo), return to default framebuffer -func DisableFramebuffer() { - rlDisableFramebuffer() -} - -// GetActiveFramebuffer - Get the currently active render texture (fbo), 0 for default framebuffer -func GetActiveFramebuffer() uint32 { - return rlGetActiveFramebuffer() -} - -// ActiveDrawBuffers - Activate multiple draw color buffers -func ActiveDrawBuffers(count int32) { - rlActiveDrawBuffers(count) -} - -// BlitFramebuffer - Blit active framebuffer to main framebuffer -func BlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask int32) { - rlBlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask) -} - -// BindFramebuffer - Bind framebuffer (FBO) -func BindFramebuffer(target, framebuffer uint32) { - rlBindFramebuffer(target, framebuffer) -} - -// EnableColorBlend - Enable color blending -func EnableColorBlend() { - rlEnableColorBlend() -} - -// DisableColorBlend - Disable color blending -func DisableColorBlend() { - rlDisableColorBlend() -} - -// EnableDepthTest - Enable depth test -func EnableDepthTest() { - rlEnableDepthTest() -} - -// DisableDepthTest - Disable depth test -func DisableDepthTest() { - rlDisableDepthTest() -} - -// EnableDepthMask - Enable depth write -func EnableDepthMask() { - rlEnableDepthMask() -} - -// DisableDepthMask - Disable depth write -func DisableDepthMask() { - rlDisableDepthMask() -} - -// EnableBackfaceCulling - Enable backface culling -func EnableBackfaceCulling() { - rlEnableBackfaceCulling() -} - -// DisableBackfaceCulling - Disable backface culling -func DisableBackfaceCulling() { - rlDisableBackfaceCulling() -} - -// ColorMask - Color mask control -func ColorMask(r, g, b, a bool) { - rlColorMask(r, g, b, a) -} - -// SetCullFace - Set face culling mode -func SetCullFace(mode int32) { - rlSetCullFace(mode) -} - -// EnableScissorTest - Enable scissor test -func EnableScissorTest() { - rlEnableScissorTest() -} - -// DisableScissorTest - Disable scissor test -func DisableScissorTest() { - rlDisableScissorTest() -} - -// Scissor - Scissor test -func Scissor(x int32, y int32, width int32, height int32) { - rlScissor(x, y, width, height) -} - -// EnableWireMode - Enable wire mode -func EnableWireMode() { - rlEnableWireMode() -} - -// EnablePointMode - Enable point mode -func EnablePointMode() { - rlEnablePointMode() -} - -// DisableWireMode - Disable wire mode -func DisableWireMode() { - rlDisableWireMode() -} - -// SetLineWidth - Set the line drawing width -func SetLineWidth(width float32) { - rlSetLineWidth(width) -} - -// GetLineWidth - Get the line drawing width -func GetLineWidth() float32 { - return rlGetLineWidth() -} - -// EnableSmoothLines - Enable line aliasing -func EnableSmoothLines() { - rlEnableSmoothLines() -} - -// DisableSmoothLines - Disable line aliasing -func DisableSmoothLines() { - rlDisableSmoothLines() -} - -// EnableStereoRender - Enable stereo rendering -func EnableStereoRender() { - rlEnableStereoRender() -} - -// DisableStereoRender - Disable stereo rendering -func DisableStereoRender() { - rlDisableStereoRender() -} - -// IsStereoRenderEnabled - Check if stereo render is enabled -func IsStereoRenderEnabled() bool { - return rlIsStereoRenderEnabled() -} - -// ClearColor - Clear color buffer with color -func ClearColor(r uint8, g uint8, b uint8, a uint8) { - rlClearColor(r, g, b, a) -} - -// ClearScreenBuffers - Clear used screen buffers (color and depth) -func ClearScreenBuffers() { - rlClearScreenBuffers() -} - -// CheckErrors - Check and log OpenGL error codes -func CheckErrors() { - rlCheckErrors() -} - -// SetBlendMode - Set blending mode -func SetBlendMode(mode BlendMode) { - rlSetBlendMode(int32(mode)) -} - -// SetBlendFactors - Set blending mode factor and equation (using OpenGL factors) -func SetBlendFactors(glSrcFactor int32, glDstFactor int32, glEquation int32) { - rlSetBlendFactors(glSrcFactor, glDstFactor, glEquation) -} - -// SetBlendFactorsSeparate - Set blending mode factors and equations separately (using OpenGL factors) -func SetBlendFactorsSeparate(glSrcRGB int32, glDstRGB int32, glSrcAlpha int32, glDstAlpha int32, glEqRGB int32, glEqAlpha int32) { - rlSetBlendFactorsSeparate(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha) -} - -// GlInit - Initialize rlgl (buffers, shaders, textures, states) -func GlInit(width int32, height int32) { - rlglInit(width, height) -} - -// GlClose - De-inititialize rlgl (buffers, shaders, textures) -func GlClose() { - rlglClose() -} - -// GetVersion - Get current OpenGL version -func GetVersion() int32 { - return rlGetVersion() -} - -// SetFramebufferWidth - Set current framebuffer width -func SetFramebufferWidth(width int32) { - rlSetFramebufferWidth(width) -} - -// GetFramebufferWidth - Get default framebuffer width -func GetFramebufferWidth() int32 { - return rlGetFramebufferWidth() -} - -// SetFramebufferHeight - Set current framebuffer height -func SetFramebufferHeight(height int32) { - rlSetFramebufferHeight(height) -} - -// GetFramebufferHeight - Get default framebuffer height -func GetFramebufferHeight() int32 { - return rlGetFramebufferHeight() -} - -// GetTextureIdDefault - Get default texture id -func GetTextureIdDefault() uint32 { - return rlGetTextureIdDefault() -} - -// GetShaderIdDefault - Get default shader id -func GetShaderIdDefault() uint32 { - return rlGetShaderIdDefault() -} - -// LoadRenderBatch - Load a render batch system -func LoadRenderBatch(numBuffers int32, bufferElements int32) RenderBatch { - var batch RenderBatch - rlLoadRenderBatch(uintptr(unsafe.Pointer(&batch)), numBuffers, bufferElements) - return batch -} - -// UnloadRenderBatch - Unload render batch system -func UnloadRenderBatch(batch RenderBatch) { - rlUnloadRenderBatch(uintptr(unsafe.Pointer(&batch))) -} - -// DrawRenderBatch - Draw render batch data (Update->Draw->Reset) -func DrawRenderBatch(batch *RenderBatch) { - rlDrawRenderBatch(batch) -} - -// rlSetRenderBatchActive - Set the active render batch for rlgl (NULL for default internal) -func SetRenderBatchActive(batch *RenderBatch) { - rlSetRenderBatchActive(batch) -} - -// DrawRenderBatchActive - Update and draw internal render batch -func DrawRenderBatchActive() { - rlDrawRenderBatchActive() -} - -// CheckRenderBatchLimit - Check internal buffer overflow for a given number of vertex -func CheckRenderBatchLimit(vCount int32) bool { - return rlCheckRenderBatchLimit(vCount) -} - -// SetTexture - Set current texture for render batch and check buffers limits -func SetTexture(id uint32) { - rlSetTexture(id) -} - -// LoadVertexArray - Load vertex array (vao) if supported -func LoadVertexArray() uint32 { - return rlLoadVertexArray() -} - -// UnloadVertexBuffer . -func UnloadVertexBuffer(vboId uint32) { - rlUnloadVertexBuffer(vboId) -} - -// SetVertexAttributeDivisor . -func SetVertexAttributeDivisor(index uint32, divisor int32) { - rlSetVertexAttributeDivisor(index, divisor) -} - -// LoadTextureDepth - Load depth texture/renderbuffer (to be attached to fbo) -func LoadTextureDepth(width, height int32, useRenderBuffer bool) uint32{ - return rlLoadTextureDepth(width, height, useRenderBuffer) -} - -// LoadFramebuffer - Load an empty framebuffer -func LoadFramebuffer() uint32 { - return rlLoadFramebuffer() -} - -// FramebufferAttach - Attach texture/renderbuffer to a framebuffer -func FramebufferAttach(fboId uint32, texId uint32, attachType int32, texType int32, mipLevel int32) { - rlFramebufferAttach(fboId, texId, attachType, texType, mipLevel) -} - -// FramebufferComplete - Verify framebuffer is complete -func FramebufferComplete(id uint32) bool { - return rlFramebufferComplete(id) -} - -// UnloadFramebuffer - Delete framebuffer from GPU -func UnloadFramebuffer(id uint32) { - rlUnloadFramebuffer(id) -} - -// LoadShaderCode - Load shader from code strings -func LoadShaderCode(vsCode string, fsCode string) uint32 { - return rlLoadShaderCode(vsCode, fsCode) -} - -// CompileShader - Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER) -func CompileShader(shaderCode string, type_ int32) uint32 { - return rlCompileShader(shaderCode, type_) -} - -// LoadShaderProgram - Load custom shader program -func LoadShaderProgram(vShaderId uint32, fShaderId uint32) uint32 { - return rlLoadShaderProgram(vShaderId, fShaderId) -} - -// UnloadShaderProgram - Unload shader program -func UnloadShaderProgram(id uint32) { - rlUnloadShaderProgram(id) -} - -// GetLocationUniform - Get shader location uniform -func GetLocationUniform(shaderId uint32, uniformName string) int32 { - return rlGetLocationUniform(shaderId, uniformName) -} - -// GetLocationAttrib - Get shader location attribute -func GetLocationAttrib(shaderId uint32, attribName string) int32 { - return rlGetLocationAttrib(shaderId, attribName) -} - -// SetUniform - Set shader value uniform -func SetUniform(locIndex int32, value []float32, uniformType int32) { - rlSetUniform(locIndex, unsafe.Pointer(unsafe.SliceData(value)), uniformType, int32(len(value))) -} - -// SetUniformMatrix - Set shader value matrix -func SetUniformMatrix(locIndex int32, mat Matrix) { - rlSetUniformMatrix(locIndex, uintptr(unsafe.Pointer(&mat))) -} - -// SetUniformMatrices - Set shader value matrices -func SetUniformMatrices(locIndex int32, mat []Matrix) { - rlSetUniformMatrices(locIndex, unsafe.SliceData(mat), int32(len(mat))) -} - -// SetUniformSampler - Set shader value sampler -func SetUniformSampler(locIndex int32, textureId uint32) { - rlSetUniformSampler(locIndex, textureId) -} - -// LoadComputeShaderProgram - Load compute shader program -func LoadComputeShaderProgram(shaderID uint32) uint32 { - return rlLoadComputeShaderProgram(shaderID) -} - -// ComputeShaderDispatch - Dispatch compute shader (equivalent to *draw* for graphics pilepine) -func ComputeShaderDispatch(groupX uint32, groupY uint32, groupZ uint32) { - rlComputeShaderDispatch(groupX, groupY, groupZ) -} - -// LoadShaderBuffer loads a shader storage buffer object (SSBO) -func LoadShaderBuffer(size uint32, data unsafe.Pointer, usageHint int32) uint32 { - return rlLoadShaderBuffer(size, data, usageHint) -} - -// UnloadShaderBuffer - Unload shader storage buffer object (SSBO) -func UnloadShaderBuffer(id uint32) { - rlUnloadShaderBuffer(id) -} - -// UpdateShaderBuffer - Update SSBO buffer data -func UpdateShaderBuffer(id uint32, data unsafe.Pointer, dataSize uint32, offset uint32) { - rlUpdateShaderBuffer(id, data, dataSize, offset) -} - -// BindShaderBuffer - Bind SSBO buffer -func BindShaderBuffer(id uint32, index uint32) { - rlBindShaderBuffer(id, index) -} - -// ReadShaderBuffer - Read SSBO buffer data (GPU->CPU) -func ReadShaderBuffer(id uint32, dest unsafe.Pointer, count uint32, offset uint32) { - rlReadShaderBuffer(id, dest, count, offset) -} - -// CopyShaderBuffer - Copy SSBO data between buffers -func CopyShaderBuffer(destId uint32, srcId uint32, destOffset uint32, srcOffset uint32, count uint32) { - rlCopyShaderBuffer(destId, srcId, destOffset, srcOffset, count) -} - -// GetShaderBufferSize - Get SSBO buffer size -func GetShaderBufferSize(id uint32) uint32 { - return rlGetShaderBufferSize(id) -} - -// BindImageTexture - Bind image texture -func BindImageTexture(id uint32, index uint32, format int32, readonly bool) { - rlBindImageTexture(id, index, format, readonly) -} - -// GetMatrixModelview - Get internal modelview matrix -func GetMatrixModelview() Matrix { - var matrix Matrix - rlGetMatrixModelview(uintptr(unsafe.Pointer(&matrix))) - return matrix -} - -// GetMatrixProjection - Get internal projection matrix -func GetMatrixProjection() Matrix { - var matrix Matrix - rlGetMatrixProjection(uintptr(unsafe.Pointer(&matrix))) - return matrix -} - -// GetMatrixTransform - Get internal accumulated transform matrix -func GetMatrixTransform() Matrix { - var matrix Matrix - rlGetMatrixTransform(uintptr(unsafe.Pointer(&matrix))) - return matrix -} - -// GetMatrixProjectionStereo - Get internal projection matrix for stereo render (selected eye) -func GetMatrixProjectionStereo(eye int32) Matrix { - var matrix Matrix - rlGetMatrixProjectionStereo(uintptr(unsafe.Pointer(&matrix)), eye) - return matrix -} - -// GetMatrixViewOffsetStereo - Get internal view offset matrix for stereo render (selected eye) -func GetMatrixViewOffsetStereo(eye int32) Matrix { - var matrix Matrix - rlGetMatrixViewOffsetStereo(uintptr(unsafe.Pointer(&matrix)), eye) - return matrix -} - -// SetMatrixProjectionStereo - Set eyes projection matrices for stereo rendering -func SetMatrixProjectionStereo(right Matrix, left Matrix) { - rlSetMatrixProjectionStereo(uintptr(unsafe.Pointer(&right)), uintptr(unsafe.Pointer(&left))) -} - -// SetMatrixViewOffsetStereo - Set eyes view offsets matrices for stereo rendering -func SetMatrixViewOffsetStereo(right Matrix, left Matrix) { - rlSetMatrixViewOffsetStereo(uintptr(unsafe.Pointer(&right)), uintptr(unsafe.Pointer(&left))) -} - -// LoadDrawCube - Load and draw a cube -func LoadDrawCube() { - rlLoadDrawCube() -} - -// LoadDrawQuad - Load and draw a quad -func LoadDrawQuad() { - rlLoadDrawQuad() -} diff --git a/raylib/rmodels.c b/raylib/rmodels.c deleted file mode 100644 index 84daabc..0000000 --- a/raylib/rmodels.c +++ /dev/null @@ -1,6930 +0,0 @@ -/********************************************************************************************** -* -* rmodels - Basic functions to draw 3d shapes and load and draw 3d models -* -* CONFIGURATION: -* #define SUPPORT_MODULE_RMODELS -* rmodels module is included in the build -* -* #define SUPPORT_FILEFORMAT_OBJ -* #define SUPPORT_FILEFORMAT_MTL -* #define SUPPORT_FILEFORMAT_IQM -* #define SUPPORT_FILEFORMAT_GLTF -* #define SUPPORT_FILEFORMAT_VOX -* #define SUPPORT_FILEFORMAT_M3D -* Selected desired fileformats to be supported for model data loading. -* -* #define SUPPORT_MESH_GENERATION -* Support procedural mesh generation functions, uses external par_shapes.h library -* NOTE: Some generated meshes DO NOT include generated texture coordinates -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#include "raylib.h" // Declares module functions - -// Check if config flags have been externally provided on compilation line -#if !defined(EXTERNAL_CONFIG_FLAGS) - #include "config.h" // Defines module configuration flags -#endif - -#if defined(SUPPORT_MODULE_RMODELS) - -#include "utils.h" // Required for: TRACELOG(), LoadFileData(), LoadFileText(), SaveFileText() -#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality - -#include // Required for: sprintf() -#include // Required for: malloc(), calloc(), free() -#include // Required for: memcmp(), strlen(), strncpy() -#include // Required for: sinf(), cosf(), sqrtf(), fabsf() - -#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) - #define TINYOBJ_MALLOC RL_MALLOC - #define TINYOBJ_CALLOC RL_CALLOC - #define TINYOBJ_REALLOC RL_REALLOC - #define TINYOBJ_FREE RL_FREE - - #define TINYOBJ_LOADER_C_IMPLEMENTATION - #include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading -#endif - -#if defined(SUPPORT_FILEFORMAT_GLTF) - #define CGLTF_MALLOC RL_MALLOC - #define CGLTF_FREE RL_FREE - - #define CGLTF_IMPLEMENTATION - #include "external/cgltf.h" // glTF file format loading -#endif - -#if defined(SUPPORT_FILEFORMAT_VOX) - #define VOX_MALLOC RL_MALLOC - #define VOX_CALLOC RL_CALLOC - #define VOX_REALLOC RL_REALLOC - #define VOX_FREE RL_FREE - - #define VOX_LOADER_IMPLEMENTATION - #include "external/vox_loader.h" // VOX file format loading (MagikaVoxel) -#endif - -#if defined(SUPPORT_FILEFORMAT_M3D) - #define M3D_MALLOC RL_MALLOC - #define M3D_REALLOC RL_REALLOC - #define M3D_FREE RL_FREE - - #define M3D_IMPLEMENTATION - #include "external/m3d.h" // Model3D file format loading -#endif - -#if defined(SUPPORT_MESH_GENERATION) - #define PAR_MALLOC(T, N) ((T *)RL_MALLOC(N*sizeof(T))) - #define PAR_CALLOC(T, N) ((T *)RL_CALLOC(N*sizeof(T), 1)) - #define PAR_REALLOC(T, BUF, N) ((T *)RL_REALLOC(BUF, sizeof(T)*(N))) - #define PAR_FREE RL_FREE - - #if defined(_MSC_VER) // Disable some MSVC warning - #pragma warning(push) - #pragma warning(disable : 4244) - #pragma warning(disable : 4305) - #endif - - #define PAR_SHAPES_IMPLEMENTATION - #include "external/par_shapes.h" // Shapes 3d parametric generation - - #if defined(_MSC_VER) - #pragma warning(pop) // Disable MSVC warning suppression - #endif -#endif - -#if defined(_WIN32) - #include // Required for: _chdir() [Used in LoadOBJ()] - #define CHDIR _chdir -#else - #include // Required for: chdir() (POSIX) [Used in LoadOBJ()] - #define CHDIR chdir -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef MAX_MATERIAL_MAPS - #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported -#endif -#ifndef MAX_MESH_VERTEX_BUFFERS - #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_OBJ) -static Model LoadOBJ(const char *fileName); // Load OBJ mesh data -#endif -#if defined(SUPPORT_FILEFORMAT_IQM) -static Model LoadIQM(const char *fileName); // Load IQM mesh data -static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount); // Load IQM animation data -#endif -#if defined(SUPPORT_FILEFORMAT_GLTF) -static Model LoadGLTF(const char *fileName); // Load GLTF mesh data -static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount); // Load GLTF animation data -#endif -#if defined(SUPPORT_FILEFORMAT_VOX) -static Model LoadVOX(const char *filename); // Load VOX mesh data -#endif -#if defined(SUPPORT_FILEFORMAT_M3D) -static Model LoadM3D(const char *filename); // Load M3D mesh data -static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount); // Load M3D animation data -#endif -#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) -static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount); // Process obj materials -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Draw a line in 3D world space -void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) -{ - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex3f(startPos.x, startPos.y, startPos.z); - rlVertex3f(endPos.x, endPos.y, endPos.z); - rlEnd(); -} - -// Draw a point in 3D space, actually a small line -// WARNING: OpenGL ES 2.0 does not support point mode drawing -void DrawPoint3D(Vector3 position, Color color) -{ - rlPushMatrix(); - rlTranslatef(position.x, position.y, position.z); - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex3f(0.0f, 0.0f, 0.0f); - rlVertex3f(0.0f, 0.0f, 0.1f); - rlEnd(); - rlPopMatrix(); -} - -// Draw a circle in 3D world space -void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) -{ - rlPushMatrix(); - rlTranslatef(center.x, center.y, center.z); - rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - - rlBegin(RL_LINES); - for (int i = 0; i < 360; i += 10) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f); - rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f); - } - rlEnd(); - rlPopMatrix(); -} - -// Draw a color-filled triangle (vertex in counter-clockwise order!) -void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color) -{ - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex3f(v1.x, v1.y, v1.z); - rlVertex3f(v2.x, v2.y, v2.z); - rlVertex3f(v3.x, v3.y, v3.z); - rlEnd(); -} - -// Draw a triangle strip defined by points -void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color) -{ - if (pointCount < 3) return; // Security check - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 2; i < pointCount; i++) - { - if ((i%2) == 0) - { - rlVertex3f(points[i].x, points[i].y, points[i].z); - rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z); - rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z); - } - else - { - rlVertex3f(points[i].x, points[i].y, points[i].z); - rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z); - rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z); - } - } - rlEnd(); -} - -// Draw cube -// NOTE: Cube position is the center position -void DrawCube(Vector3 position, float width, float height, float length, Color color) -{ - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - - rlPushMatrix(); - // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) - rlTranslatef(position.x, position.y, position.z); - //rlRotatef(45, 0, 1, 0); - //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - // Front face - rlNormal3f(0.0f, 0.0f, 1.0f); - rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left - - rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right - - // Back face - rlNormal3f(0.0f, 0.0f, -1.0f); - rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left - rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right - - rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right - rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left - - // Top face - rlNormal3f(0.0f, 1.0f, 0.0f); - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left - rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left - rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right - - rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left - rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right - - // Bottom face - rlNormal3f(0.0f, -1.0f, 0.0f); - rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right - rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left - - rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right - rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left - - // Right face - rlNormal3f(1.0f, 0.0f, 0.0f); - rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right - rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right - rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left - - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left - rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right - rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left - - // Left face - rlNormal3f(-1.0f, 0.0f, 0.0f); - rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right - - rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left - rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right - rlEnd(); - rlPopMatrix(); -} - -// Draw cube (Vector version) -void DrawCubeV(Vector3 position, Vector3 size, Color color) -{ - DrawCube(position, size.x, size.y, size.z, color); -} - -// Draw cube wires -void DrawCubeWires(Vector3 position, float width, float height, float length, Color color) -{ - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - - rlPushMatrix(); - rlTranslatef(position.x, position.y, position.z); - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - // Front face - //------------------------------------------------------------------ - // Bottom line - rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom left - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom right - - // Left line - rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom right - rlVertex3f(x + width/2, y + height/2, z + length/2); // Top right - - // Top line - rlVertex3f(x + width/2, y + height/2, z + length/2); // Top right - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top left - - // Right line - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top left - rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom left - - // Back face - //------------------------------------------------------------------ - // Bottom line - rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom left - rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom right - - // Left line - rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom right - rlVertex3f(x + width/2, y + height/2, z - length/2); // Top right - - // Top line - rlVertex3f(x + width/2, y + height/2, z - length/2); // Top right - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top left - - // Right line - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top left - rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom left - - // Top face - //------------------------------------------------------------------ - // Left line - rlVertex3f(x - width/2, y + height/2, z + length/2); // Top left front - rlVertex3f(x - width/2, y + height/2, z - length/2); // Top left back - - // Right line - rlVertex3f(x + width/2, y + height/2, z + length/2); // Top right front - rlVertex3f(x + width/2, y + height/2, z - length/2); // Top right back - - // Bottom face - //------------------------------------------------------------------ - // Left line - rlVertex3f(x - width/2, y - height/2, z + length/2); // Top left front - rlVertex3f(x - width/2, y - height/2, z - length/2); // Top left back - - // Right line - rlVertex3f(x + width/2, y - height/2, z + length/2); // Top right front - rlVertex3f(x + width/2, y - height/2, z - length/2); // Top right back - rlEnd(); - rlPopMatrix(); -} - -// Draw cube wires (vector version) -void DrawCubeWiresV(Vector3 position, Vector3 size, Color color) -{ - DrawCubeWires(position, size.x, size.y, size.z, color); -} - -// Draw sphere -void DrawSphere(Vector3 centerPos, float radius, Color color) -{ - DrawSphereEx(centerPos, radius, 16, 16, color); -} - -// Draw sphere with extended parameters -void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color) -{ -#if 0 - // Basic implementation, do not use it! - // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls! - // New optimized version below only requires 4 cos()/sin() calls - - rlPushMatrix(); - // NOTE: Transformation is applied in inverse order (scale -> translate) - rlTranslatef(centerPos.x, centerPos.y, centerPos.z); - rlScalef(radius, radius, radius); - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 0; i < (rings + 2); i++) - { - for (int j = 0; j < slices; j++) - { - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); - - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); - } - } - rlEnd(); - rlPopMatrix(); -#endif - - rlPushMatrix(); - // NOTE: Transformation is applied in inverse order (scale -> translate) - rlTranslatef(centerPos.x, centerPos.y, centerPos.z); - rlScalef(radius, radius, radius); - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - float ringangle = DEG2RAD*(180.0f/(rings + 1)); // Angle between latitudinal parallels - float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians - - float cosring = cosf(ringangle); - float sinring = sinf(ringangle); - float cosslice = cosf(sliceangle); - float sinslice = sinf(sliceangle); - - Vector3 vertices[4] = { 0 }; // Required to store face vertices - vertices[2] = (Vector3){ 0, 1, 0 }; - vertices[3] = (Vector3){ sinring, cosring, 0 }; - - for (int i = 0; i < rings + 1; i++) - { - for (int j = 0; j < slices; j++) - { - vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face - vertices[1] = vertices[3]; - vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis - vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z }; - - rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z); - rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z); - rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z); - rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z); - rlNormal3f(vertices[1].x, vertices[1].y, vertices[1].z); - rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z); - - rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z); - rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z); - rlNormal3f(vertices[2].x, vertices[2].y, vertices[2].z); - rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z); - rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z); - rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z); - } - - vertices[2] = vertices[3]; // Rotate around z axis to set up starting vertices for next ring - vertices[3] = (Vector3){ cosring*vertices[3].x + sinring*vertices[3].y, -sinring*vertices[3].x + cosring*vertices[3].y, vertices[3].z }; // Rotation matrix around z axis - } - rlEnd(); - rlPopMatrix(); -} - -// Draw sphere wires -void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color) -{ - rlPushMatrix(); - // NOTE: Transformation is applied in inverse order (scale -> translate) - rlTranslatef(centerPos.x, centerPos.y, centerPos.z); - rlScalef(radius, radius, radius); - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 0; i < (rings + 2); i++) - { - for (int j = 0; j < slices; j++) - { - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); - - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); - - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); - } - } - rlEnd(); - rlPopMatrix(); -} - -// Draw a cylinder -// NOTE: It could be also used for pyramid and cone -void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) -{ - if (sides < 3) sides = 3; - - const float angleStep = 360.0f/sides; - - rlPushMatrix(); - rlTranslatef(position.x, position.y, position.z); - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - if (radiusTop > 0) - { - // Draw Body ------------------------------------------------------------------------------------- - for (int i = 0; i < sides; i++) - { - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); //Bottom Right - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right - - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); //Top Left - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right - } - - // Draw Cap -------------------------------------------------------------------------------------- - for (int i = 0; i < sides; i++) - { - rlVertex3f(0, height, 0); - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); - } - } - else - { - // Draw Cone ------------------------------------------------------------------------------------- - for (int i = 0; i < sides; i++) - { - rlVertex3f(0, height, 0); - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); - } - } - - // Draw Base ----------------------------------------------------------------------------------------- - for (int i = 0; i < sides; i++) - { - rlVertex3f(0, 0, 0); - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); - } - - rlEnd(); - rlPopMatrix(); -} - -// Draw a cylinder with base at startPos and top at endPos -// NOTE: It could be also used for pyramid and cone -void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color) -{ - if (sides < 3) sides = 3; - - Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; - if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check - - // Construct a basis of the base and the top face: - Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction)); - Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction)); - - float baseAngle = (2.0f*PI)/sides; - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 0; i < sides; i++) - { - // Compute the four vertices - float s1 = sinf(baseAngle*(i + 0))*startRadius; - float c1 = cosf(baseAngle*(i + 0))*startRadius; - Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z }; - float s2 = sinf(baseAngle*(i + 1))*startRadius; - float c2 = cosf(baseAngle*(i + 1))*startRadius; - Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z }; - float s3 = sinf(baseAngle*(i + 0))*endRadius; - float c3 = cosf(baseAngle*(i + 0))*endRadius; - Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z }; - float s4 = sinf(baseAngle*(i + 1))*endRadius; - float c4 = cosf(baseAngle*(i + 1))*endRadius; - Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z }; - - if (startRadius > 0) - { - rlVertex3f(startPos.x, startPos.y, startPos.z); // | - rlVertex3f(w2.x, w2.y, w2.z); // T0 - rlVertex3f(w1.x, w1.y, w1.z); // | - } - // w2 x.-----------x startPos - rlVertex3f(w1.x, w1.y, w1.z); // | |\'. T0 / - rlVertex3f(w2.x, w2.y, w2.z); // T1 | \ '. / - rlVertex3f(w3.x, w3.y, w3.z); // | |T \ '. / - // | 2 \ T 'x w1 - rlVertex3f(w2.x, w2.y, w2.z); // | w4 x.---\-1-|---x endPos - rlVertex3f(w4.x, w4.y, w4.z); // T2 '. \ |T3/ - rlVertex3f(w3.x, w3.y, w3.z); // | '. \ | / - // '.\|/ - if (endRadius > 0) // 'x w3 - { - rlVertex3f(endPos.x, endPos.y, endPos.z); // | - rlVertex3f(w3.x, w3.y, w3.z); // T3 - rlVertex3f(w4.x, w4.y, w4.z); // | - } // - } - rlEnd(); -} - -// Draw a wired cylinder -// NOTE: It could be also used for pyramid and cone -void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) -{ - if (sides < 3) sides = 3; - - const float angleStep = 360.0f/sides; - - rlPushMatrix(); - rlTranslatef(position.x, position.y, position.z); - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 0; i < sides; i++) - { - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); - - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); - - rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); - - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); - rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); - } - rlEnd(); - rlPopMatrix(); -} - -// Draw a wired cylinder with base at startPos and top at endPos -// NOTE: It could be also used for pyramid and cone -void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color) -{ - if (sides < 3) sides = 3; - - Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; - if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check - - // Construct a basis of the base and the top face: - Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction)); - Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction)); - - float baseAngle = (2.0f*PI)/sides; - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 0; i < sides; i++) - { - // Compute the four vertices - float s1 = sinf(baseAngle*(i + 0))*startRadius; - float c1 = cosf(baseAngle*(i + 0))*startRadius; - Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z }; - float s2 = sinf(baseAngle*(i + 1))*startRadius; - float c2 = cosf(baseAngle*(i + 1))*startRadius; - Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z }; - float s3 = sinf(baseAngle*(i + 0))*endRadius; - float c3 = cosf(baseAngle*(i + 0))*endRadius; - Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z }; - float s4 = sinf(baseAngle*(i + 1))*endRadius; - float c4 = cosf(baseAngle*(i + 1))*endRadius; - Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z }; - - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w2.x, w2.y, w2.z); - - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w4.x, w4.y, w4.z); - } - rlEnd(); -} - -// Draw a capsule with the center of its sphere caps at startPos and endPos -void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color) -{ - if (slices < 3) slices = 3; - - Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; - - // draw a sphere if start and end points are the same - bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0); - if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f}; - - // Construct a basis of the base and the caps: - Vector3 b0 = Vector3Normalize(direction); - Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction)); - Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction)); - Vector3 capCenter = endPos; - - float baseSliceAngle = (2.0f*PI)/slices; - float baseRingAngle = PI*0.5f/rings; - - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - // render both caps - for (int c = 0; c < 2; c++) - { - for (int i = 0; i < rings; i++) - { - for (int j = 0; j < slices; j++) - { - - // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier - - // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i)) - // as we iterate through the rings they must get smaller by the cos(angle(i)) - - // compute the four vertices - float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 )); - float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 )); - Vector3 w1 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius - }; - float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 )); - float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 )); - Vector3 w2 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius - }; - - float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 )); - float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 )); - Vector3 w3 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius - }; - float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 )); - float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 )); - Vector3 w4 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius - }; - - // Make sure cap triangle normals are facing outwards - if (c == 0) - { - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w4.x, w4.y, w4.z); - rlVertex3f(w3.x, w3.y, w3.z); - } - else - { - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w2.x, w2.y, w2.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w4.x, w4.y, w4.z); - } - } - } - capCenter = startPos; - b0 = Vector3Scale(b0, -1.0f); - } - // render middle - if (!sphereCase) - { - for (int j = 0; j < slices; j++) - { - // compute the four vertices - float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius; - float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w1 = { - startPos.x + ringSin1*b1.x + ringCos1*b2.x, - startPos.y + ringSin1*b1.y + ringCos1*b2.y, - startPos.z + ringSin1*b1.z + ringCos1*b2.z - }; - float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius; - float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w2 = { - startPos.x + ringSin2*b1.x + ringCos2*b2.x, - startPos.y + ringSin2*b1.y + ringCos2*b2.y, - startPos.z + ringSin2*b1.z + ringCos2*b2.z - }; - - float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius; - float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w3 = { - endPos.x + ringSin3*b1.x + ringCos3*b2.x, - endPos.y + ringSin3*b1.y + ringCos3*b2.y, - endPos.z + ringSin3*b1.z + ringCos3*b2.z - }; - float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius; - float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w4 = { - endPos.x + ringSin4*b1.x + ringCos4*b2.x, - endPos.y + ringSin4*b1.y + ringCos4*b2.y, - endPos.z + ringSin4*b1.z + ringCos4*b2.z - }; - // w2 x.-----------x startPos - rlVertex3f(w1.x, w1.y, w1.z); // | |\'. T0 / - rlVertex3f(w2.x, w2.y, w2.z); // T1 | \ '. / - rlVertex3f(w3.x, w3.y, w3.z); // | |T \ '. / - // | 2 \ T 'x w1 - rlVertex3f(w2.x, w2.y, w2.z); // | w4 x.---\-1-|---x endPos - rlVertex3f(w4.x, w4.y, w4.z); // T2 '. \ |T3/ - rlVertex3f(w3.x, w3.y, w3.z); // | '. \ | / - // '.\|/ - // 'x w3 - } - } - rlEnd(); -} - -// Draw capsule wires with the center of its sphere caps at startPos and endPos -void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color) -{ - if (slices < 3) slices = 3; - - Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; - - // draw a sphere if start and end points are the same - bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0); - if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f}; - - // Construct a basis of the base and the caps: - Vector3 b0 = Vector3Normalize(direction); - Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction)); - Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction)); - Vector3 capCenter = endPos; - - float baseSliceAngle = (2.0f*PI)/slices; - float baseRingAngle = PI*0.5f/rings; - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - // render both caps - for (int c = 0; c < 2; c++) - { - for (int i = 0; i < rings; i++) - { - for (int j = 0; j < slices; j++) - { - - // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier - - // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i)) - // as we iterate through the rings they must get smaller by the cos(angle(i)) - - // compute the four vertices - float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 )); - float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 )); - Vector3 w1 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius - }; - float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 )); - float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 )); - Vector3 w2 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius - }; - - float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 )); - float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 )); - Vector3 w3 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius - }; - float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 )); - float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 )); - Vector3 w4 = (Vector3){ - capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius, - capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius, - capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius - }; - - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w2.x, w2.y, w2.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w4.x, w4.y, w4.z); - - rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w4.x, w4.y, w4.z); - } - } - capCenter = startPos; - b0 = Vector3Scale(b0, -1.0f); - } - // render middle - if (!sphereCase) - { - for (int j = 0; j < slices; j++) - { - // compute the four vertices - float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius; - float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w1 = { - startPos.x + ringSin1*b1.x + ringCos1*b2.x, - startPos.y + ringSin1*b1.y + ringCos1*b2.y, - startPos.z + ringSin1*b1.z + ringCos1*b2.z - }; - float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius; - float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w2 = { - startPos.x + ringSin2*b1.x + ringCos2*b2.x, - startPos.y + ringSin2*b1.y + ringCos2*b2.y, - startPos.z + ringSin2*b1.z + ringCos2*b2.z - }; - - float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius; - float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w3 = { - endPos.x + ringSin3*b1.x + ringCos3*b2.x, - endPos.y + ringSin3*b1.y + ringCos3*b2.y, - endPos.z + ringSin3*b1.z + ringCos3*b2.z - }; - float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius; - float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w4 = { - endPos.x + ringSin4*b1.x + ringCos4*b2.x, - endPos.y + ringSin4*b1.y + ringCos4*b2.y, - endPos.z + ringSin4*b1.z + ringCos4*b2.z - }; - - rlVertex3f(w1.x, w1.y, w1.z); - rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w4.x, w4.y, w4.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w3.x, w3.y, w3.z); - } - } - rlEnd(); -} - -// Draw a plane -void DrawPlane(Vector3 centerPos, Vector2 size, Color color) -{ - // NOTE: Plane is always created on XZ ground - rlPushMatrix(); - rlTranslatef(centerPos.x, centerPos.y, centerPos.z); - rlScalef(size.x, 1.0f, size.y); - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - rlNormal3f(0.0f, 1.0f, 0.0f); - - rlVertex3f(-0.5f, 0.0f, -0.5f); - rlVertex3f(-0.5f, 0.0f, 0.5f); - rlVertex3f(0.5f, 0.0f, 0.5f); - rlVertex3f(0.5f, 0.0f, -0.5f); - rlEnd(); - rlPopMatrix(); -} - -// Draw a ray line -void DrawRay(Ray ray, Color color) -{ - float scale = 10000; - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex3f(ray.position.x, ray.position.y, ray.position.z); - rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale); - rlEnd(); -} - -// Draw a grid centered at (0, 0, 0) -void DrawGrid(int slices, float spacing) -{ - int halfSlices = slices/2; - - rlBegin(RL_LINES); - for (int i = -halfSlices; i <= halfSlices; i++) - { - if (i == 0) - { - rlColor3f(0.5f, 0.5f, 0.5f); - } - else - { - rlColor3f(0.75f, 0.75f, 0.75f); - } - - rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing); - rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing); - - rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing); - rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing); - } - rlEnd(); -} - -// Load model from files (mesh and material) -Model LoadModel(const char *fileName) -{ - Model model = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_OBJ) - if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_IQM) - if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_GLTF) - if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_VOX) - if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_M3D) - if (IsFileExtension(fileName, ".m3d")) model = LoadM3D(fileName); -#endif - - // Make sure model transform is set to identity matrix! - model.transform = MatrixIdentity(); - - if ((model.meshCount != 0) && (model.meshes != NULL)) - { - // Upload vertex data to GPU (static meshes) - for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false); - } - else TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load model mesh(es) data", fileName); - - if (model.materialCount == 0) - { - TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load model material data, default to white material", fileName); - - model.materialCount = 1; - model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); - model.materials[0] = LoadMaterialDefault(); - - if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); - } - - return model; -} - -// Load model from generated mesh -// WARNING: A shallow copy of mesh is generated, passed by value, -// as long as struct contains pointers to data and some values, we get a copy -// of mesh pointing to same data as original version... be careful! -Model LoadModelFromMesh(Mesh mesh) -{ - Model model = { 0 }; - - model.transform = MatrixIdentity(); - - model.meshCount = 1; - model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); - model.meshes[0] = mesh; - - model.materialCount = 1; - model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); - model.materials[0] = LoadMaterialDefault(); - - model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); - model.meshMaterial[0] = 0; // First material index - - return model; -} - -// Check if a model is valid (loaded in GPU, VAO/VBOs) -bool IsModelValid(Model model) -{ - bool result = false; - - if ((model.meshes != NULL) && // Validate model contains some mesh - (model.materials != NULL) && // Validate model contains some material (at least default one) - (model.meshMaterial != NULL) && // Validate mesh-material linkage - (model.meshCount > 0) && // Validate mesh count - (model.materialCount > 0)) result = true; // Validate material count - - // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs - // but some VBOs could not be used, it depends on Mesh vertex data - for (int i = 0; i < model.meshCount; i++) - { - if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; } // Vertex position buffer not uploaded to GPU - if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; } // Vertex textcoords buffer not uploaded to GPU - if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; } // Vertex normals buffer not uploaded to GPU - if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; } // Vertex colors buffer not uploaded to GPU - if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; } // Vertex tangents buffer not uploaded to GPU - if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; } // Vertex texcoords2 buffer not uploaded to GPU - if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; } // Vertex indices buffer not uploaded to GPU - if ((model.meshes[i].boneIds != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIds buffer not uploaded to GPU - if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU - - // NOTE: Some OpenGL versions do not support VAO, so we don't check it - //if (model.meshes[i].vaoId == 0) { result = false; break } - } - - return result; -} - -// Unload model (meshes/materials) from memory (RAM and/or VRAM) -// NOTE: This function takes care of all model elements, for a detailed control -// over them, use UnloadMesh() and UnloadMaterial() -void UnloadModel(Model model) -{ - // Unload meshes - for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]); - - // Unload materials maps - // NOTE: As the user could be sharing shaders and textures between models, - // we don't unload the material but just free its maps, - // the user is responsible for freeing models shaders and textures - for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); - - // Unload arrays - RL_FREE(model.meshes); - RL_FREE(model.materials); - RL_FREE(model.meshMaterial); - - // Unload animation data - RL_FREE(model.bones); - RL_FREE(model.bindPose); - - TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM"); -} - -// Compute model bounding box limits (considers all meshes) -BoundingBox GetModelBoundingBox(Model model) -{ - BoundingBox bounds = { 0 }; - - if (model.meshCount > 0) - { - Vector3 temp = { 0 }; - bounds = GetMeshBoundingBox(model.meshes[0]); - - for (int i = 1; i < model.meshCount; i++) - { - BoundingBox tempBounds = GetMeshBoundingBox(model.meshes[i]); - - temp.x = (bounds.min.x < tempBounds.min.x)? bounds.min.x : tempBounds.min.x; - temp.y = (bounds.min.y < tempBounds.min.y)? bounds.min.y : tempBounds.min.y; - temp.z = (bounds.min.z < tempBounds.min.z)? bounds.min.z : tempBounds.min.z; - bounds.min = temp; - - temp.x = (bounds.max.x > tempBounds.max.x)? bounds.max.x : tempBounds.max.x; - temp.y = (bounds.max.y > tempBounds.max.y)? bounds.max.y : tempBounds.max.y; - temp.z = (bounds.max.z > tempBounds.max.z)? bounds.max.z : tempBounds.max.z; - bounds.max = temp; - } - } - - // Apply model.transform to bounding box - // WARNING: Current BoundingBox structure design does not support rotation transformations, - // in those cases is up to the user to calculate the proper box bounds (8 vertices transformed) - bounds.min = Vector3Transform(bounds.min, model.transform); - bounds.max = Vector3Transform(bounds.max, model.transform); - - return bounds; -} - -// Upload vertex data into a VAO (if supported) and VBO -void UploadMesh(Mesh *mesh, bool dynamic) -{ - if (mesh->vaoId > 0) - { - // Check if mesh has already been loaded in GPU - TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId); - return; - } - - mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int)); - - mesh->vaoId = 0; // Vertex Array Object - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights -#endif - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - mesh->vaoId = rlLoadVertexArray(); - rlEnableVertexArray(mesh->vaoId); - - // NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data - - // Enable vertex attributes: position (shader-location = 0) - void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices; - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); - - // Enable vertex attributes: texcoords (shader-location = 1) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); - - // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute - // is part of current state, and it is maintained even if a different program object is used - - if (mesh->normals != NULL) - { - // Enable vertex attributes: normals (shader-location = 2) - void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals; - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); - } - else - { - // Default vertex attribute: normal - // WARNING: Default value provided to shader if location available - float value[3] = { 0.0f, 0.0f, 1.0f }; - rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, value, SHADER_ATTRIB_VEC3, 3); - rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); - } - - if (mesh->colors != NULL) - { - // Enable vertex attribute: color (shader-location = 3) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR); - } - else - { - // Default vertex attribute: color - // WARNING: Default value provided to shader if location available - float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // WHITE - rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, value, SHADER_ATTRIB_VEC4, 4); - rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR); - } - - if (mesh->tangents != NULL) - { - // Enable vertex attribute: tangent (shader-location = 4) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT); - } - else - { - // Default vertex attribute: tangent - // WARNING: Default value provided to shader if location available - float value[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; - rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, value, SHADER_ATTRIB_VEC4, 4); - rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT); - } - - if (mesh->texcoords2 != NULL) - { - // Enable vertex attribute: texcoord2 (shader-location = 5) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); - } - else - { - // Default vertex attribute: texcoord2 - // WARNING: Default value provided to shader if location available - float value[2] = { 0.0f, 0.0f }; - rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2); - rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); - } - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - if (mesh->boneIds != NULL) - { - // Enable vertex attribute: boneIds (shader-location = 7) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS); - } - else - { - // Default vertex attribute: boneIds - // WARNING: Default value provided to shader if location available - float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4); - rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS); - } - - if (mesh->boneWeights != NULL) - { - // Enable vertex attribute: boneWeights (shader-location = 8) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS); - } - else - { - // Default vertex attribute: boneWeights - // WARNING: Default value provided to shader if location available - float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2); - rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS); - } -#endif - - if (mesh->indices != NULL) - { - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic); - } - - if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId); - else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)"); - - rlDisableVertexArray(); -#endif -} - -// Update mesh vertex data in GPU for a specific buffer index -void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset) -{ - rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset); -} - -// Draw a 3d mesh with material and transform -void DrawMesh(Mesh mesh, Material material, Matrix transform) -{ -#if defined(GRAPHICS_API_OPENGL_11) - #define GL_VERTEX_ARRAY 0x8074 - #define GL_NORMAL_ARRAY 0x8075 - #define GL_COLOR_ARRAY 0x8076 - #define GL_TEXTURE_COORD_ARRAY 0x8078 - - rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id); - - if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices); - else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices); - - rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords); - if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormals); - else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals); - - rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors); - - rlPushMatrix(); - rlMultMatrixf(MatrixToFloat(transform)); - rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r, - material.maps[MATERIAL_MAP_DIFFUSE].color.g, - material.maps[MATERIAL_MAP_DIFFUSE].color.b, - material.maps[MATERIAL_MAP_DIFFUSE].color.a); - - if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices); - else rlDrawVertexArray(0, mesh.vertexCount); - rlPopMatrix(); - - rlDisableStatePointer(GL_VERTEX_ARRAY); - rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY); - rlDisableStatePointer(GL_NORMAL_ARRAY); - rlDisableStatePointer(GL_COLOR_ARRAY); - - rlDisableTexture(); -#endif - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Bind shader program - rlEnableShader(material.shader.id); - - // Send required data to shader (matrices, values) - //----------------------------------------------------- - // Upload to shader material.colDiffuse - if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1) - { - float values[4] = { - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f, - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f, - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f, - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f - }; - - rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1); - } - - // Upload to shader material.colSpecular (if location available) - if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1) - { - float values[4] = { - (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f, - (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f, - (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f, - (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f - }; - - rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); - } - - // Get a copy of current matrices to work with, - // just in case stereo render is required, and we need to modify them - // NOTE: At this point the modelview matrix just contains the view matrix (camera) - // That's because BeginMode3D() sets it and there is no model-drawing function - // that modifies it, all use rlPushMatrix() and rlPopMatrix() - Matrix matModel = MatrixIdentity(); - Matrix matView = rlGetMatrixModelview(); - Matrix matModelView = MatrixIdentity(); - Matrix matProjection = rlGetMatrixProjection(); - - // Upload view and projection matrices (if locations available) - if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView); - if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection); - - // Accumulate several model transformations: - // transform: model transformation provided (includes DrawModel() params combined with model.transform) - // rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack - matModel = MatrixMultiply(transform, rlGetMatrixTransform()); - - // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL - if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], matModel); - - // Get model-view matrix - matModelView = MatrixMultiply(matModel, matView); - - // Upload model normal matrix (if locations available) - if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - // Upload Bone Transforms - if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices) - { - rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); - } -#endif - //----------------------------------------------------- - - // Bind active texture maps (if available) - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - if (material.maps[i].texture.id > 0) - { - // Select current shader texture slot - rlActiveTextureSlot(i); - - // Enable texture for active slot - if ((i == MATERIAL_MAP_IRRADIANCE) || - (i == MATERIAL_MAP_PREFILTER) || - (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id); - else rlEnableTexture(material.maps[i].texture.id); - - rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1); - } - } - - // Try binding vertex array objects (VAO) or use VBOs if not possible - // WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values - // for shader expected vertex attributes that are not provided by the mesh (i.e. colors) - // This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes - if (!rlEnableVertexArray(mesh.vaoId)) - { - // Bind mesh VBO data: vertex position (shader-location = 0) - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); - - // Bind mesh VBO data: vertex texcoords (shader-location = 1) - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); - - if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) - { - // Bind mesh VBO data: vertex normals (shader-location = 2) - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); - } - - // Bind mesh VBO data: vertex colors (shader-location = 3, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) - { - if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); - } - else - { - // Set default value for defined vertex attribute in shader but not provided by mesh - // WARNING: It could result in GPU undefined behaviour - float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4); - rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); - } - } - - // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); - } - - // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); - } - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]); - } - - // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]); - } -#endif - - if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); - } - - int eyeCount = 1; - if (rlIsStereoRenderEnabled()) eyeCount = 2; - - for (int eye = 0; eye < eyeCount; eye++) - { - // Calculate model-view-projection matrix (MVP) - Matrix matModelViewProjection = MatrixIdentity(); - if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection); - else - { - // Setup current eye viewport (half screen width) - rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight()); - matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye)); - } - - // Send combined model-view-projection matrix to shader - rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection); - - // Draw mesh - if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0); - else rlDrawVertexArray(0, mesh.vertexCount); - } - - // Unbind all bound texture maps - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - if (material.maps[i].texture.id > 0) - { - // Select current shader texture slot - rlActiveTextureSlot(i); - - // Disable texture for active slot - if ((i == MATERIAL_MAP_IRRADIANCE) || - (i == MATERIAL_MAP_PREFILTER) || - (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); - else rlDisableTexture(); - } - } - - // Disable all possible vertex array objects (or VBOs) - rlDisableVertexArray(); - rlDisableVertexBuffer(); - rlDisableVertexBufferElement(); - - // Disable shader program - rlDisableShader(); - - // Restore rlgl internal modelview and projection matrices - rlSetMatrixModelview(matView); - rlSetMatrixProjection(matProjection); -#endif -} - -// Draw multiple mesh instances with material and different transforms -void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Instancing required variables - float16 *instanceTransforms = NULL; - unsigned int instancesVboId = 0; - - // Bind shader program - rlEnableShader(material.shader.id); - - // Send required data to shader (matrices, values) - //----------------------------------------------------- - // Upload to shader material.colDiffuse - if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1) - { - float values[4] = { - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f, - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f, - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f, - (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f - }; - - rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1); - } - - // Upload to shader material.colSpecular (if location available) - if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1) - { - float values[4] = { - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f, - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f, - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f, - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f - }; - - rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); - } - - // Get a copy of current matrices to work with, - // just in case stereo render is required, and we need to modify them - // NOTE: At this point the modelview matrix just contains the view matrix (camera) - // That's because BeginMode3D() sets it and there is no model-drawing function - // that modifies it, all use rlPushMatrix() and rlPopMatrix() - Matrix matModel = MatrixIdentity(); - Matrix matView = rlGetMatrixModelview(); - Matrix matModelView = MatrixIdentity(); - Matrix matProjection = rlGetMatrixProjection(); - - // Upload view and projection matrices (if locations available) - if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView); - if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection); - - // Create instances buffer - instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16)); - - // Fill buffer with instances transformations as float16 arrays - for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]); - - // Enable mesh VAO to attach new buffer - rlEnableVertexArray(mesh.vaoId); - - // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData() - // It isn't clear which would be reliably faster in all cases and on all platforms, - // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems - // no faster, since we're transferring all the transform matrices anyway - instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false); - - // Instances transformation matrices are sent to shader attribute location: SHADER_LOC_VERTEX_INSTANCE_TX - for (unsigned int i = 0; i < 4; i++) - { - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 4, RL_FLOAT, 0, sizeof(Matrix), i*sizeof(Vector4)); - rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 1); - } - - rlDisableVertexBuffer(); - rlDisableVertexArray(); - - // Accumulate internal matrix transform (push/pop) and view matrix - // NOTE: In this case, model instance transformation must be computed in the shader - matModelView = MatrixMultiply(rlGetMatrixTransform(), matView); - - // Upload model normal matrix (if locations available) - if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - // Upload Bone Transforms - if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices) - { - rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); - } -#endif - - //----------------------------------------------------- - - // Bind active texture maps (if available) - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - if (material.maps[i].texture.id > 0) - { - // Select current shader texture slot - rlActiveTextureSlot(i); - - // Enable texture for active slot - if ((i == MATERIAL_MAP_IRRADIANCE) || - (i == MATERIAL_MAP_PREFILTER) || - (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id); - else rlEnableTexture(material.maps[i].texture.id); - - rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1); - } - } - - // Try binding vertex array objects (VAO) - // or use VBOs if not possible - if (!rlEnableVertexArray(mesh.vaoId)) - { - // Bind mesh VBO data: vertex position (shader-location = 0) - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); - - // Bind mesh VBO data: vertex texcoords (shader-location = 1) - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); - - if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) - { - // Bind mesh VBO data: vertex normals (shader-location = 2) - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); - } - - // Bind mesh VBO data: vertex colors (shader-location = 3, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) - { - if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); - } - else - { - // Set default value for unused attribute - // NOTE: Required when using default shader and no VAO support - float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4); - rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); - } - } - - // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); - } - - // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); - } - -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]); - } - - // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available) - if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1) - { - rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]); - } -#endif - - if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); - } - - int eyeCount = 1; - if (rlIsStereoRenderEnabled()) eyeCount = 2; - - for (int eye = 0; eye < eyeCount; eye++) - { - // Calculate model-view-projection matrix (MVP) - Matrix matModelViewProjection = MatrixIdentity(); - if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection); - else - { - // Setup current eye viewport (half screen width) - rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight()); - matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye)); - } - - // Send combined model-view-projection matrix to shader - rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection); - - // Draw mesh instanced - if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances); - else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances); - } - - // Unbind all bound texture maps - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - if (material.maps[i].texture.id > 0) - { - // Select current shader texture slot - rlActiveTextureSlot(i); - - // Disable texture for active slot - if ((i == MATERIAL_MAP_IRRADIANCE) || - (i == MATERIAL_MAP_PREFILTER) || - (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); - else rlDisableTexture(); - } - } - - // Disable all possible vertex array objects (or VBOs) - rlDisableVertexArray(); - rlDisableVertexBuffer(); - rlDisableVertexBufferElement(); - - // Disable shader program - rlDisableShader(); - - // Remove instance transforms buffer - rlUnloadVertexBuffer(instancesVboId); - RL_FREE(instanceTransforms); -#endif -} - -// Unload mesh from memory (RAM and VRAM) -void UnloadMesh(Mesh mesh) -{ - // Unload rlgl mesh vboId data - rlUnloadVertexArray(mesh.vaoId); - - if (mesh.vboId != NULL) for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]); - RL_FREE(mesh.vboId); - - RL_FREE(mesh.vertices); - RL_FREE(mesh.texcoords); - RL_FREE(mesh.normals); - RL_FREE(mesh.colors); - RL_FREE(mesh.tangents); - RL_FREE(mesh.texcoords2); - RL_FREE(mesh.indices); - - RL_FREE(mesh.animVertices); - RL_FREE(mesh.animNormals); - RL_FREE(mesh.boneWeights); - RL_FREE(mesh.boneIds); - RL_FREE(mesh.boneMatrices); -} - -// Export mesh data to file -bool ExportMesh(Mesh mesh, const char *fileName) -{ - bool success = false; - - if (IsFileExtension(fileName, ".obj")) - { - // Estimated data size, it should be enough... - int vc = mesh.vertexCount; - int dataSize = vc*(int)strlen("v -0000.000000f -0000.000000f -0000.000000f\n") + - vc*(int)strlen("vt -0.000000f -0.000000f\n") + - vc*(int)strlen("vn -0.0000f -0.0000f -0.0000f\n") + - mesh.triangleCount*snprintf(NULL, 0, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", vc, vc, vc, vc, vc, vc, vc, vc, vc); - - // NOTE: Text data buffer size is estimated considering mesh data size - char *txtData = (char *)RL_CALLOC(dataSize + 1000, sizeof(char)); - - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n"); - byteCount += sprintf(txtData + byteCount, "# // //\n"); - byteCount += sprintf(txtData + byteCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n"); - byteCount += sprintf(txtData + byteCount, "# // //\n"); - byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n"); - byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n"); - byteCount += sprintf(txtData + byteCount, "# // //\n"); - byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); - byteCount += sprintf(txtData + byteCount, "# // //\n"); - byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); - byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount); - byteCount += sprintf(txtData + byteCount, "# Triangle Count: %i\n\n", mesh.triangleCount); - - byteCount += sprintf(txtData + byteCount, "g mesh\n"); - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) - { - byteCount += sprintf(txtData + byteCount, "v %.6f %.6f %.6f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); - } - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2) - { - byteCount += sprintf(txtData + byteCount, "vt %.6f %.6f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); - } - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) - { - byteCount += sprintf(txtData + byteCount, "vn %.4f %.4f %.4f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); - } - - if (mesh.indices != NULL) - { - for (int i = 0, v = 0; i < mesh.triangleCount; i++, v += 3) - { - byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", - mesh.indices[v] + 1, mesh.indices[v] + 1, mesh.indices[v] + 1, - mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, - mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1); - } - } - else - { - for (int i = 0, v = 1; i < mesh.triangleCount; i++, v += 3) - { - byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", v, v, v, v + 1, v + 1, v + 1, v + 2, v + 2, v + 2); - } - } - - // NOTE: Text data length exported is determined by '\0' (NULL) character - success = SaveFileText(fileName, txtData); - - RL_FREE(txtData); - } - else if (IsFileExtension(fileName, ".raw")) - { - // TODO: Support additional file formats to export mesh vertex data - } - - return success; -} - -// Export mesh as code file (.h) defining multiple arrays of vertex attributes -bool ExportMeshAsCode(Mesh mesh, const char *fileName) -{ - bool success = false; - -#ifndef TEXT_BYTES_PER_LINE - #define TEXT_BYTES_PER_LINE 20 -#endif - - // NOTE: Text data buffer size is fixed to 64MB - char *txtData = (char *)RL_CALLOC(64*1024*1024, sizeof(char)); // 64 MB - - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// MeshAsCode exporter v1.0 - Mesh vertex data exported as arrays //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); - byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2023 Ramon Santamaria (@raysan5) //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); - - // Get file name from path and convert variable name to uppercase - char varFileName[256] = { 0 }; - strcpy(varFileName, GetFileNameWithoutExt(fileName)); - for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } - - // Add image information - byteCount += sprintf(txtData + byteCount, "// Mesh basic information\n"); - byteCount += sprintf(txtData + byteCount, "#define %s_VERTEX_COUNT %i\n", varFileName, mesh.vertexCount); - byteCount += sprintf(txtData + byteCount, "#define %s_TRIANGLE_COUNT %i\n\n", varFileName, mesh.triangleCount); - - // Define vertex attributes data as separate arrays - //----------------------------------------------------------------------------------------- - if (mesh.vertices != NULL) // Vertex position (XYZ - 3 components per vertex - float) - { - byteCount += sprintf(txtData + byteCount, "static float %s_VERTEX_DATA[%i] = { ", varFileName, mesh.vertexCount*3); - for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.vertices[i]); - byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.vertices[mesh.vertexCount*3 - 1]); - } - - if (mesh.texcoords != NULL) // Vertex texture coordinates (UV - 2 components per vertex - float) - { - byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD_DATA[%i] = { ", varFileName, mesh.vertexCount*2); - for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords[i]); - byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords[mesh.vertexCount*2 - 1]); - } - - if (mesh.texcoords2 != NULL) // Vertex texture coordinates (UV - 2 components per vertex - float) - { - byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD2_DATA[%i] = { ", varFileName, mesh.vertexCount*2); - for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords2[i]); - byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords2[mesh.vertexCount*2 - 1]); - } - - if (mesh.normals != NULL) // Vertex normals (XYZ - 3 components per vertex - float) - { - byteCount += sprintf(txtData + byteCount, "static float %s_NORMAL_DATA[%i] = { ", varFileName, mesh.vertexCount*3); - for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.normals[i]); - byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.normals[mesh.vertexCount*3 - 1]); - } - - if (mesh.tangents != NULL) // Vertex tangents (XYZW - 4 components per vertex - float) - { - byteCount += sprintf(txtData + byteCount, "static float %s_TANGENT_DATA[%i] = { ", varFileName, mesh.vertexCount*4); - for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.tangents[i]); - byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.tangents[mesh.vertexCount*4 - 1]); - } - - if (mesh.colors != NULL) // Vertex colors (RGBA - 4 components per vertex - unsigned char) - { - byteCount += sprintf(txtData + byteCount, "static unsigned char %s_COLOR_DATA[%i] = { ", varFileName, mesh.vertexCount*4); - for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), mesh.colors[i]); - byteCount += sprintf(txtData + byteCount, "0x%x };\n\n", mesh.colors[mesh.vertexCount*4 - 1]); - } - - if (mesh.indices != NULL) // Vertex indices (3 index per triangle - unsigned short) - { - byteCount += sprintf(txtData + byteCount, "static unsigned short %s_INDEX_DATA[%i] = { ", varFileName, mesh.triangleCount*3); - for (int i = 0; i < mesh.triangleCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%i,\n" : "%i, "), mesh.indices[i]); - byteCount += sprintf(txtData + byteCount, "%i };\n", mesh.indices[mesh.triangleCount*3 - 1]); - } - //----------------------------------------------------------------------------------------- - - // NOTE: Text data size exported is determined by '\0' (NULL) character - success = SaveFileText(fileName, txtData); - - RL_FREE(txtData); - - //if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName); - //else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName); - - return success; -} - -#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) -// Process obj materials -static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount) -{ - // Init model mats - for (int m = 0; m < materialCount; m++) - { - // Init material to default - // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE - materials[m] = LoadMaterialDefault(); - - if (mats == NULL) continue; - - // Get default texture, in case no texture is defined - // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 - materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - - if (mats[m].diffuse_texname != NULL) materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(mats[m].diffuse_texname); //char *diffuse_texname; // map_Kd - else materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(mats[m].diffuse[0]*255.0f), (unsigned char)(mats[m].diffuse[1]*255.0f), (unsigned char)(mats[m].diffuse[2]*255.0f), 255 }; //float diffuse[3]; - materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; - - if (mats[m].specular_texname != NULL) materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(mats[m].specular_texname); //char *specular_texname; // map_Ks - materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(mats[m].specular[0]*255.0f), (unsigned char)(mats[m].specular[1]*255.0f), (unsigned char)(mats[m].specular[2]*255.0f), 255 }; //float specular[3]; - materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; - - if (mats[m].bump_texname != NULL) materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(mats[m].bump_texname); //char *bump_texname; // map_bump, bump - materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; - materials[m].maps[MATERIAL_MAP_NORMAL].value = mats[m].shininess; - - materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(mats[m].emission[0]*255.0f), (unsigned char)(mats[m].emission[1]*255.0f), (unsigned char)(mats[m].emission[2]*255.0f), 255 }; //float emission[3]; - - if (mats[m].displacement_texname != NULL) materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(mats[m].displacement_texname); //char *displacement_texname; // disp - } -} -#endif - -// Load materials from model file -Material *LoadMaterials(const char *fileName, int *materialCount) -{ - Material *materials = NULL; - unsigned int count = 0; - - // TODO: Support IQM and GLTF for materials parsing - -#if defined(SUPPORT_FILEFORMAT_MTL) - if (IsFileExtension(fileName, ".mtl")) - { - tinyobj_material_t *mats = NULL; - - int result = tinyobj_parse_mtl_file(&mats, &count, fileName); - if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName); - - materials = (Material *)RL_MALLOC(count*sizeof(Material)); - ProcessMaterialsOBJ(materials, mats, count); - - tinyobj_materials_free(mats, count); - } -#else - TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName); -#endif - - *materialCount = count; - return materials; -} - -// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -Material LoadMaterialDefault(void) -{ - Material material = { 0 }; - material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap)); - - // Using rlgl default shader - material.shader.id = rlGetShaderIdDefault(); - material.shader.locs = rlGetShaderLocsDefault(); - - // Using rlgl default texture (1x1 pixel, UNCOMPRESSED_R8G8B8A8, 1 mipmap) - material.maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - //material.maps[MATERIAL_MAP_NORMAL].texture; // NOTE: By default, not set - //material.maps[MATERIAL_MAP_SPECULAR].texture; // NOTE: By default, not set - - material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE; // Diffuse color - material.maps[MATERIAL_MAP_SPECULAR].color = WHITE; // Specular color - - return material; -} - -// Check if a material is valid (map textures loaded in GPU) -bool IsMaterialValid(Material material) -{ - bool result = false; - - if ((material.maps != NULL) && // Validate material contain some map - (material.shader.id > 0)) result = true; // Validate material shader is valid - - // TODO: Check if available maps contain loaded textures - - return result; -} - -// Unload material from memory -void UnloadMaterial(Material material) -{ - // Unload material shader (avoid unloading default shader, managed by raylib) - if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader); - - // Unload loaded texture maps (avoid unloading default texture, managed by raylib) - if (material.maps != NULL) - { - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id); - } - } - - RL_FREE(material.maps); -} - -// Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) -// NOTE: Previous texture should be manually unloaded -void SetMaterialTexture(Material *material, int mapType, Texture2D texture) -{ - material->maps[mapType].texture = texture; -} - -// Set the material for a mesh -void SetModelMeshMaterial(Model *model, int meshId, int materialId) -{ - if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count"); - else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count"); - else model->meshMaterial[meshId] = materialId; -} - -// Load model animations from file -ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount) -{ - ModelAnimation *animations = NULL; - -#if defined(SUPPORT_FILEFORMAT_IQM) - if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount); -#endif -#if defined(SUPPORT_FILEFORMAT_M3D) - if (IsFileExtension(fileName, ".m3d")) animations = LoadModelAnimationsM3D(fileName, animCount); -#endif -#if defined(SUPPORT_FILEFORMAT_GLTF) - if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationsGLTF(fileName, animCount); -#endif - - return animations; -} - -// Update model animated bones transform matrices for a given frame -// NOTE: Updated data is not uploaded to GPU but kept at model.meshes[i].boneMatrices[boneId], -// to be uploaded to shader at drawing, in case GPU skinning is enabled -void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame) -{ - if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL)) - { - if (frame >= anim.frameCount) frame = frame%anim.frameCount; - - // Get first mesh which have bones - int firstMeshWithBones = -1; - - for (int i = 0; i < model.meshCount; i++) - { - if (model.meshes[i].boneMatrices) - { - if (firstMeshWithBones == -1) - { - firstMeshWithBones = i; - break; - } - } - } - - if (firstMeshWithBones != -1) - { - // Update all bones and boneMatrices of first mesh with bones. - for (int boneId = 0; boneId < anim.boneCount; boneId++) - { - Transform *bindTransform = &model.bindPose[boneId]; - Matrix bindMatrix = MatrixMultiply(MatrixMultiply( - MatrixScale(bindTransform->scale.x, bindTransform->scale.y, bindTransform->scale.z), - QuaternionToMatrix(bindTransform->rotation)), - MatrixTranslate(bindTransform->translation.x, bindTransform->translation.y, bindTransform->translation.z)); - - Transform *targetTransform = &anim.framePoses[frame][boneId]; - Matrix targetMatrix = MatrixMultiply(MatrixMultiply( - MatrixScale(targetTransform->scale.x, targetTransform->scale.y, targetTransform->scale.z), - QuaternionToMatrix(targetTransform->rotation)), - MatrixTranslate(targetTransform->translation.x, targetTransform->translation.y, targetTransform->translation.z)); - - model.meshes[firstMeshWithBones].boneMatrices[boneId] = MatrixMultiply(MatrixInvert(bindMatrix), targetMatrix); - } - - // Update remaining meshes with bones - // NOTE: Using deep copy because shallow copy results in double free with 'UnloadModel()' - for (int i = firstMeshWithBones + 1; i < model.meshCount; i++) - { - if (model.meshes[i].boneMatrices) - { - memcpy(model.meshes[i].boneMatrices, - model.meshes[firstMeshWithBones].boneMatrices, - model.meshes[i].boneCount*sizeof(model.meshes[i].boneMatrices[0])); - } - } - } - } -} - -// at least 2x speed up vs the old method -// Update model animated vertex data (positions and normals) for a given frame -// NOTE: Updated data is uploaded to GPU -void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) -{ - UpdateModelAnimationBones(model,anim,frame); - - for (int m = 0; m < model.meshCount; m++) - { - Mesh mesh = model.meshes[m]; - Vector3 animVertex = { 0 }; - Vector3 animNormal = { 0 }; - int boneId = 0; - int boneCounter = 0; - float boneWeight = 0.0; - bool updated = false; // Flag to check when anim vertex information is updated - const int vValues = mesh.vertexCount*3; - - // Skip if missing bone data, causes segfault without on some models - if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue; - - for (int vCounter = 0; vCounter < vValues; vCounter += 3) - { - mesh.animVertices[vCounter] = 0; - mesh.animVertices[vCounter + 1] = 0; - mesh.animVertices[vCounter + 2] = 0; - if (mesh.animNormals != NULL) - { - mesh.animNormals[vCounter] = 0; - mesh.animNormals[vCounter + 1] = 0; - mesh.animNormals[vCounter + 2] = 0; - } - - // Iterates over 4 bones per vertex - for (int j = 0; j < 4; j++, boneCounter++) - { - boneWeight = mesh.boneWeights[boneCounter]; - boneId = mesh.boneIds[boneCounter]; - - // Early stop when no transformation will be applied - if (boneWeight == 0.0f) continue; - animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] }; - animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]); - mesh.animVertices[vCounter] += animVertex.x*boneWeight; - mesh.animVertices[vCounter+1] += animVertex.y*boneWeight; - mesh.animVertices[vCounter+2] += animVertex.z*boneWeight; - updated = true; - - // Normals processing - // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) - if ((mesh.normals != NULL) && (mesh.animNormals != NULL )) - { - animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] }; - animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.meshes[m].boneMatrices[boneId]))); - mesh.animNormals[vCounter] += animNormal.x*boneWeight; - mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight; - mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight; - } - } - } - - if (updated) - { - rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position - if (mesh.normals != NULL) rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); // Update vertex normals - } - } -} - -// Unload animation array data -void UnloadModelAnimations(ModelAnimation *animations, int animCount) -{ - for (int i = 0; i < animCount; i++) UnloadModelAnimation(animations[i]); - RL_FREE(animations); -} - -// Unload animation data -void UnloadModelAnimation(ModelAnimation anim) -{ - for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]); - - RL_FREE(anim.bones); - RL_FREE(anim.framePoses); -} - -// Check model animation skeleton match -// NOTE: Only number of bones and parent connections are checked -bool IsModelAnimationValid(Model model, ModelAnimation anim) -{ - int result = true; - - if (model.boneCount != anim.boneCount) result = false; - else - { - for (int i = 0; i < model.boneCount; i++) - { - if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; } - } - } - - return result; -} - -#if defined(SUPPORT_MESH_GENERATION) -// Generate polygonal mesh -Mesh GenMeshPoly(int sides, float radius) -{ - Mesh mesh = { 0 }; - - if (sides < 3) return mesh; // Security check - - int vertexCount = sides*3; - - // Vertices definition - Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); - - float d = 0.0f, dStep = 360.0f/sides; - for (int v = 0; v < vertexCount - 2; v += 3) - { - vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f }; - vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius }; - vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius }; - d += dStep; - } - - // Normals definition - Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); - for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; - - // TexCoords definition - Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2)); - for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f }; - - mesh.vertexCount = vertexCount; - mesh.triangleCount = sides; - mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - - // Mesh vertices position array - for (int i = 0; i < mesh.vertexCount; i++) - { - mesh.vertices[3*i] = vertices[i].x; - mesh.vertices[3*i + 1] = vertices[i].y; - mesh.vertices[3*i + 2] = vertices[i].z; - } - - // Mesh texcoords array - for (int i = 0; i < mesh.vertexCount; i++) - { - mesh.texcoords[2*i] = texcoords[i].x; - mesh.texcoords[2*i + 1] = texcoords[i].y; - } - - // Mesh normals array - for (int i = 0; i < mesh.vertexCount; i++) - { - mesh.normals[3*i] = normals[i].x; - mesh.normals[3*i + 1] = normals[i].y; - mesh.normals[3*i + 2] = normals[i].z; - } - - RL_FREE(vertices); - RL_FREE(normals); - RL_FREE(texcoords); - - // Upload vertex data to GPU (static mesh) - // NOTE: mesh.vboId array is allocated inside UploadMesh() - UploadMesh(&mesh, false); - - return mesh; -} - -// Generate plane mesh (with subdivisions) -Mesh GenMeshPlane(float width, float length, int resX, int resZ) -{ - Mesh mesh = { 0 }; - -#define CUSTOM_MESH_GEN_PLANE -#if defined(CUSTOM_MESH_GEN_PLANE) - resX++; - resZ++; - - // Vertices definition - int vertexCount = resX*resZ; // vertices get reused for the faces - - Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); - for (int z = 0; z < resZ; z++) - { - // [-length/2, length/2] - float zPos = ((float)z/(resZ - 1) - 0.5f)*length; - for (int x = 0; x < resX; x++) - { - // [-width/2, width/2] - float xPos = ((float)x/(resX - 1) - 0.5f)*width; - vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos }; - } - } - - // Normals definition - Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); - for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; - - // TexCoords definition - Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2)); - for (int v = 0; v < resZ; v++) - { - for (int u = 0; u < resX; u++) - { - texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) }; - } - } - - // Triangles definition (indices) - int numFaces = (resX - 1)*(resZ - 1); - int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int)); - int t = 0; - for (int face = 0; face < numFaces; face++) - { - // Retrieve lower left corner from face ind - int i = face + face/(resX - 1); - - triangles[t++] = i + resX; - triangles[t++] = i + 1; - triangles[t++] = i; - - triangles[t++] = i + resX; - triangles[t++] = i + resX + 1; - triangles[t++] = i + 1; - } - - mesh.vertexCount = vertexCount; - mesh.triangleCount = numFaces*2; - mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short)); - - // Mesh vertices position array - for (int i = 0; i < mesh.vertexCount; i++) - { - mesh.vertices[3*i] = vertices[i].x; - mesh.vertices[3*i + 1] = vertices[i].y; - mesh.vertices[3*i + 2] = vertices[i].z; - } - - // Mesh texcoords array - for (int i = 0; i < mesh.vertexCount; i++) - { - mesh.texcoords[2*i] = texcoords[i].x; - mesh.texcoords[2*i + 1] = texcoords[i].y; - } - - // Mesh normals array - for (int i = 0; i < mesh.vertexCount; i++) - { - mesh.normals[3*i] = normals[i].x; - mesh.normals[3*i + 1] = normals[i].y; - mesh.normals[3*i + 2] = normals[i].z; - } - - // Mesh indices array initialization - for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i]; - - RL_FREE(vertices); - RL_FREE(normals); - RL_FREE(texcoords); - RL_FREE(triangles); - -#else // Use par_shapes library to generate plane mesh - - par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!! - par_shapes_scale(plane, width, length, 1.0f); - par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 }); - par_shapes_translate(plane, -width/2, 0.0f, length/2); - - mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = plane->ntriangles*3; - mesh.triangleCount = plane->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = plane->points[plane->triangles[k]*3]; - mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2]; - - mesh.normals[k*3] = plane->normals[plane->triangles[k]*3]; - mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(plane); -#endif - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - - return mesh; -} - -// Generated cuboid mesh -Mesh GenMeshCube(float width, float height, float length) -{ - Mesh mesh = { 0 }; - -#define CUSTOM_MESH_GEN_CUBE -#if defined(CUSTOM_MESH_GEN_CUBE) - float vertices[] = { - -width/2, -height/2, length/2, - width/2, -height/2, length/2, - width/2, height/2, length/2, - -width/2, height/2, length/2, - -width/2, -height/2, -length/2, - -width/2, height/2, -length/2, - width/2, height/2, -length/2, - width/2, -height/2, -length/2, - -width/2, height/2, -length/2, - -width/2, height/2, length/2, - width/2, height/2, length/2, - width/2, height/2, -length/2, - -width/2, -height/2, -length/2, - width/2, -height/2, -length/2, - width/2, -height/2, length/2, - -width/2, -height/2, length/2, - width/2, -height/2, -length/2, - width/2, height/2, -length/2, - width/2, height/2, length/2, - width/2, -height/2, length/2, - -width/2, -height/2, -length/2, - -width/2, -height/2, length/2, - -width/2, height/2, length/2, - -width/2, height/2, -length/2 - }; - - float texcoords[] = { - 0.0f, 0.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - 0.0f, 1.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - 0.0f, 1.0f, - 0.0f, 0.0f, - 0.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - 1.0f, 1.0f, - 0.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 0.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - 0.0f, 1.0f, - 0.0f, 0.0f, - 0.0f, 0.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - 0.0f, 1.0f - }; - - float normals[] = { - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f,-1.0f, - 0.0f, 0.0f,-1.0f, - 0.0f, 0.0f,-1.0f, - 0.0f, 0.0f,-1.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f,-1.0f, 0.0f, - 0.0f,-1.0f, 0.0f, - 0.0f,-1.0f, 0.0f, - 0.0f,-1.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f - }; - - mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float)); - memcpy(mesh.vertices, vertices, 24*3*sizeof(float)); - - mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float)); - memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float)); - - mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float)); - memcpy(mesh.normals, normals, 24*3*sizeof(float)); - - mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short)); - - int k = 0; - - // Indices can be initialized right now - for (int i = 0; i < 36; i += 6) - { - mesh.indices[i] = 4*k; - mesh.indices[i + 1] = 4*k + 1; - mesh.indices[i + 2] = 4*k + 2; - mesh.indices[i + 3] = 4*k; - mesh.indices[i + 4] = 4*k + 2; - mesh.indices[i + 5] = 4*k + 3; - - k++; - } - - mesh.vertexCount = 24; - mesh.triangleCount = 12; - -#else // Use par_shapes library to generate cube mesh -/* -// Platonic solids: -par_shapes_mesh *par_shapes_create_tetrahedron(); // 4 sides polyhedron (pyramid) -par_shapes_mesh *par_shapes_create_cube(); // 6 sides polyhedron (cube) -par_shapes_mesh *par_shapes_create_octahedron(); // 8 sides polyhedron (diamond) -par_shapes_mesh *par_shapes_create_dodecahedron(); // 12 sides polyhedron -par_shapes_mesh *par_shapes_create_icosahedron(); // 20 sides polyhedron -*/ - // Platonic solid generation: cube (6 sides) - // NOTE: No normals/texcoords generated by default - par_shapes_mesh *cube = par_shapes_create_cube(); - cube->tcoords = PAR_MALLOC(float, 2*cube->npoints); - for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f; - par_shapes_scale(cube, width, height, length); - par_shapes_translate(cube, -width/2, 0.0f, -length/2); - par_shapes_compute_normals(cube); - - mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = cube->ntriangles*3; - mesh.triangleCount = cube->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = cube->points[cube->triangles[k]*3]; - mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2]; - - mesh.normals[k*3] = cube->normals[cube->triangles[k]*3]; - mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(cube); -#endif - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - - return mesh; -} - -// Generate sphere mesh (standard sphere) -Mesh GenMeshSphere(float radius, int rings, int slices) -{ - Mesh mesh = { 0 }; - - if ((rings >= 3) && (slices >= 3)) - { - par_shapes_set_epsilon_degenerate_sphere(0.0); - par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings); - par_shapes_scale(sphere, radius, radius, radius); - // NOTE: Soft normals are computed internally - - mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = sphere->ntriangles*3; - mesh.triangleCount = sphere->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; - mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; - - mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; - mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(sphere); - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - } - else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere"); - - return mesh; -} - -// Generate hemisphere mesh (half sphere, no bottom cap) -Mesh GenMeshHemiSphere(float radius, int rings, int slices) -{ - Mesh mesh = { 0 }; - - if ((rings >= 3) && (slices >= 3)) - { - if (radius < 0.0f) radius = 0.0f; - - par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings); - par_shapes_scale(sphere, radius, radius, radius); - // NOTE: Soft normals are computed internally - - mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = sphere->ntriangles*3; - mesh.triangleCount = sphere->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; - mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; - - mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; - mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(sphere); - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - } - else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere"); - - return mesh; -} - -// Generate cylinder mesh -Mesh GenMeshCylinder(float radius, float height, int slices) -{ - Mesh mesh = { 0 }; - - if (slices >= 3) - { - // Instance a cylinder that sits on the Z=0 plane using the given tessellation - // levels across the UV domain. Think of "slices" like a number of pizza - // slices, and "stacks" like a number of stacked rings - // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale - par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8); - par_shapes_scale(cylinder, radius, radius, height); - par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 }); - - // Generate an orientable disk shape (top cap) - par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 }); - capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints); - for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f; - par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 }); - par_shapes_rotate(capTop, 90*DEG2RAD, (float[]){ 0, 1, 0 }); - par_shapes_translate(capTop, 0, height, 0); - - // Generate an orientable disk shape (bottom cap) - par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 }); - capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints); - for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f; - par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 }); - par_shapes_rotate(capBottom, -90*DEG2RAD, (float[]){ 0, 1, 0 }); - - par_shapes_merge_and_free(cylinder, capTop); - par_shapes_merge_and_free(cylinder, capBottom); - - mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = cylinder->ntriangles*3; - mesh.triangleCount = cylinder->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3]; - mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2]; - - mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3]; - mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(cylinder); - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - } - else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder"); - - return mesh; -} - -// Generate cone/pyramid mesh -Mesh GenMeshCone(float radius, float height, int slices) -{ - Mesh mesh = { 0 }; - - if (slices >= 3) - { - // Instance a cone that sits on the Z=0 plane using the given tessellation - // levels across the UV domain. Think of "slices" like a number of pizza - // slices, and "stacks" like a number of stacked rings - // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale - par_shapes_mesh *cone = par_shapes_create_cone(slices, 8); - par_shapes_scale(cone, radius, radius, height); - par_shapes_rotate(cone, -PI/2.0f, (float[]){ 1, 0, 0 }); - par_shapes_rotate(cone, PI/2.0f, (float[]){ 0, 1, 0 }); - - // Generate an orientable disk shape (bottom cap) - par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 }); - capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints); - for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f; - par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 }); - - par_shapes_merge_and_free(cone, capBottom); - - mesh.vertices = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(cone->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = cone->ntriangles*3; - mesh.triangleCount = cone->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = cone->points[cone->triangles[k]*3]; - mesh.vertices[k*3 + 1] = cone->points[cone->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = cone->points[cone->triangles[k]*3 + 2]; - - mesh.normals[k*3] = cone->normals[cone->triangles[k]*3]; - mesh.normals[k*3 + 1] = cone->normals[cone->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = cone->normals[cone->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = cone->tcoords[cone->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = cone->tcoords[cone->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(cone); - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - } - else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cone"); - - return mesh; -} - -// Generate torus mesh -Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) -{ - Mesh mesh = { 0 }; - - if ((sides >= 3) && (radSeg >= 3)) - { - if (radius > 1.0f) radius = 1.0f; - else if (radius < 0.1f) radius = 0.1f; - - // Create a donut that sits on the Z=0 plane with the specified inner radius - // The outer radius can be controlled with par_shapes_scale - par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius); - par_shapes_scale(torus, size/2, size/2, size/2); - - mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = torus->ntriangles*3; - mesh.triangleCount = torus->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = torus->points[torus->triangles[k]*3]; - mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2]; - - mesh.normals[k*3] = torus->normals[torus->triangles[k]*3]; - mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(torus); - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - } - else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus"); - - return mesh; -} - -// Generate trefoil knot mesh -Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) -{ - Mesh mesh = { 0 }; - - if ((sides >= 3) && (radSeg >= 3)) - { - if (radius > 3.0f) radius = 3.0f; - else if (radius < 0.5f) radius = 0.5f; - - par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius); - par_shapes_scale(knot, size, size, size); - - mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float)); - - mesh.vertexCount = knot->ntriangles*3; - mesh.triangleCount = knot->ntriangles; - - for (int k = 0; k < mesh.vertexCount; k++) - { - mesh.vertices[k*3] = knot->points[knot->triangles[k]*3]; - mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1]; - mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2]; - - mesh.normals[k*3] = knot->normals[knot->triangles[k]*3]; - mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1]; - mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2]; - - mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2]; - mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1]; - } - - par_shapes_free_mesh(knot); - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - } - else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot"); - - return mesh; -} - -// Generate a mesh from heightmap -// NOTE: Vertex data is uploaded to GPU -Mesh GenMeshHeightmap(Image heightmap, Vector3 size) -{ - #define GRAY_VALUE(c) ((float)(c.r + c.g + c.b)/3.0f) - - Mesh mesh = { 0 }; - - int mapX = heightmap.width; - int mapZ = heightmap.height; - - Color *pixels = LoadImageColors(heightmap); - - // NOTE: One vertex per pixel - mesh.triangleCount = (mapX - 1)*(mapZ - 1)*2; // One quad every four pixels - - mesh.vertexCount = mesh.triangleCount*3; - - mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); - mesh.colors = NULL; - - int vCounter = 0; // Used to count vertices float by float - int tcCounter = 0; // Used to count texcoords float by float - int nCounter = 0; // Used to count normals float by float - - Vector3 scaleFactor = { size.x/(mapX - 1), size.y/255.0f, size.z/(mapZ - 1) }; - - Vector3 vA = { 0 }; - Vector3 vB = { 0 }; - Vector3 vC = { 0 }; - Vector3 vN = { 0 }; - - for (int z = 0; z < mapZ-1; z++) - { - for (int x = 0; x < mapX-1; x++) - { - // Fill vertices array with data - //---------------------------------------------------------- - - // one triangle - 3 vertex - mesh.vertices[vCounter] = (float)x*scaleFactor.x; - mesh.vertices[vCounter + 1] = GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y; - mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z; - - mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x; - mesh.vertices[vCounter + 4] = GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y; - mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z; - - mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x; - mesh.vertices[vCounter + 7] = GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y; - mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z; - - // Another triangle - 3 vertex - mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6]; - mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7]; - mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8]; - - mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3]; - mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4]; - mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5]; - - mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x; - mesh.vertices[vCounter + 16] = GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y; - mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z; - vCounter += 18; // 6 vertex, 18 floats - - // Fill texcoords array with data - //-------------------------------------------------------------- - mesh.texcoords[tcCounter] = (float)x/(mapX - 1); - mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1); - - mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1); - mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1); - - mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1); - mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1); - - mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4]; - mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5]; - - mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2]; - mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3]; - - mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1); - mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1); - tcCounter += 12; // 6 texcoords, 12 floats - - // Fill normals array with data - //-------------------------------------------------------------- - for (int i = 0; i < 18; i += 9) - { - vA.x = mesh.vertices[nCounter + i]; - vA.y = mesh.vertices[nCounter + i + 1]; - vA.z = mesh.vertices[nCounter + i + 2]; - - vB.x = mesh.vertices[nCounter + i + 3]; - vB.y = mesh.vertices[nCounter + i + 4]; - vB.z = mesh.vertices[nCounter + i + 5]; - - vC.x = mesh.vertices[nCounter + i + 6]; - vC.y = mesh.vertices[nCounter + i + 7]; - vC.z = mesh.vertices[nCounter + i + 8]; - - vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA))); - - mesh.normals[nCounter + i] = vN.x; - mesh.normals[nCounter + i + 1] = vN.y; - mesh.normals[nCounter + i + 2] = vN.z; - - mesh.normals[nCounter + i + 3] = vN.x; - mesh.normals[nCounter + i + 4] = vN.y; - mesh.normals[nCounter + i + 5] = vN.z; - - mesh.normals[nCounter + i + 6] = vN.x; - mesh.normals[nCounter + i + 7] = vN.y; - mesh.normals[nCounter + i + 8] = vN.z; - } - - nCounter += 18; // 6 vertex, 18 floats - } - } - - UnloadImageColors(pixels); // Unload pixels color data - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - - return mesh; -} - -// Generate a cubes mesh from pixel data -// NOTE: Vertex data is uploaded to GPU -Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) -{ - #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) - - Mesh mesh = { 0 }; - - Color *pixels = LoadImageColors(cubicmap); - - // NOTE: Max possible number of triangles numCubes*(12 triangles by cube) - int maxTriangles = cubicmap.width*cubicmap.height*12; - - int vCounter = 0; // Used to count vertices - int tcCounter = 0; // Used to count texcoords - int nCounter = 0; // Used to count normals - - float w = cubeSize.x; - float h = cubeSize.z; - float h2 = cubeSize.y; - - Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3)); - Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2)); - Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3)); - - // Define the 6 normals of the cube, we will combine them accordingly later... - Vector3 n1 = { 1.0f, 0.0f, 0.0f }; - Vector3 n2 = { -1.0f, 0.0f, 0.0f }; - Vector3 n3 = { 0.0f, 1.0f, 0.0f }; - Vector3 n4 = { 0.0f, -1.0f, 0.0f }; - Vector3 n5 = { 0.0f, 0.0f, -1.0f }; - Vector3 n6 = { 0.0f, 0.0f, 1.0f }; - - // NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6) - typedef struct RectangleF { - float x; - float y; - float width; - float height; - } RectangleF; - - RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f }; - RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f }; - RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f }; - RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f }; - RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f }; - RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f }; - - for (int z = 0; z < cubicmap.height; ++z) - { - for (int x = 0; x < cubicmap.width; ++x) - { - // Define the 8 vertex of the cube, we will combine them accordingly later... - Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) }; - Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) }; - Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) }; - Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) }; - Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) }; - Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) }; - Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) }; - Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) }; - - // We check pixel color to be WHITE -> draw full cube - if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE)) - { - // Define triangles and checking collateral cubes - //------------------------------------------------ - - // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4) - // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside - mapVertices[vCounter] = v1; - mapVertices[vCounter + 1] = v2; - mapVertices[vCounter + 2] = v3; - mapVertices[vCounter + 3] = v1; - mapVertices[vCounter + 4] = v3; - mapVertices[vCounter + 5] = v4; - vCounter += 6; - - mapNormals[nCounter] = n3; - mapNormals[nCounter + 1] = n3; - mapNormals[nCounter + 2] = n3; - mapNormals[nCounter + 3] = n3; - mapNormals[nCounter + 4] = n3; - mapNormals[nCounter + 5] = n3; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; - mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; - mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y }; - tcCounter += 6; - - // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8) - mapVertices[vCounter] = v6; - mapVertices[vCounter + 1] = v8; - mapVertices[vCounter + 2] = v7; - mapVertices[vCounter + 3] = v6; - mapVertices[vCounter + 4] = v5; - mapVertices[vCounter + 5] = v8; - vCounter += 6; - - mapNormals[nCounter] = n4; - mapNormals[nCounter + 1] = n4; - mapNormals[nCounter + 2] = n4; - mapNormals[nCounter + 3] = n4; - mapNormals[nCounter + 4] = n4; - mapNormals[nCounter + 5] = n4; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height }; - mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y }; - mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; - tcCounter += 6; - - // Checking cube on bottom of current cube - if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1)) - { - // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8 - // NOTE: Collateral occluded faces are not generated - mapVertices[vCounter] = v2; - mapVertices[vCounter + 1] = v7; - mapVertices[vCounter + 2] = v3; - mapVertices[vCounter + 3] = v3; - mapVertices[vCounter + 4] = v7; - mapVertices[vCounter + 5] = v8; - vCounter += 6; - - mapNormals[nCounter] = n6; - mapNormals[nCounter + 1] = n6; - mapNormals[nCounter + 2] = n6; - mapNormals[nCounter + 3] = n6; - mapNormals[nCounter + 4] = n6; - mapNormals[nCounter + 5] = n6; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y }; - mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height }; - mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height }; - tcCounter += 6; - } - - // Checking cube on top of current cube - if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0)) - { - // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5 - // NOTE: Collateral occluded faces are not generated - mapVertices[vCounter] = v1; - mapVertices[vCounter + 1] = v5; - mapVertices[vCounter + 2] = v6; - mapVertices[vCounter + 3] = v1; - mapVertices[vCounter + 4] = v4; - mapVertices[vCounter + 5] = v5; - vCounter += 6; - - mapNormals[nCounter] = n5; - mapNormals[nCounter + 1] = n5; - mapNormals[nCounter + 2] = n5; - mapNormals[nCounter + 3] = n5; - mapNormals[nCounter + 4] = n5; - mapNormals[nCounter + 5] = n5; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height }; - mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y }; - mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height }; - tcCounter += 6; - } - - // Checking cube on right of current cube - if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1)) - { - // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5 - // NOTE: Collateral occluded faces are not generated - mapVertices[vCounter] = v3; - mapVertices[vCounter + 1] = v8; - mapVertices[vCounter + 2] = v4; - mapVertices[vCounter + 3] = v4; - mapVertices[vCounter + 4] = v8; - mapVertices[vCounter + 5] = v5; - vCounter += 6; - - mapNormals[nCounter] = n1; - mapNormals[nCounter + 1] = n1; - mapNormals[nCounter + 2] = n1; - mapNormals[nCounter + 3] = n1; - mapNormals[nCounter + 4] = n1; - mapNormals[nCounter + 5] = n1; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y }; - mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height }; - mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height }; - tcCounter += 6; - } - - // Checking cube on left of current cube - if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0)) - { - // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7 - // NOTE: Collateral occluded faces are not generated - mapVertices[vCounter] = v1; - mapVertices[vCounter + 1] = v7; - mapVertices[vCounter + 2] = v2; - mapVertices[vCounter + 3] = v1; - mapVertices[vCounter + 4] = v6; - mapVertices[vCounter + 5] = v7; - vCounter += 6; - - mapNormals[nCounter] = n2; - mapNormals[nCounter + 1] = n2; - mapNormals[nCounter + 2] = n2; - mapNormals[nCounter + 3] = n2; - mapNormals[nCounter + 4] = n2; - mapNormals[nCounter + 5] = n2; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y }; - mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height }; - mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height }; - tcCounter += 6; - } - } - // We check pixel color to be BLACK, we will only draw floor and roof - else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK)) - { - // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4) - mapVertices[vCounter] = v1; - mapVertices[vCounter + 1] = v3; - mapVertices[vCounter + 2] = v2; - mapVertices[vCounter + 3] = v1; - mapVertices[vCounter + 4] = v4; - mapVertices[vCounter + 5] = v3; - vCounter += 6; - - mapNormals[nCounter] = n4; - mapNormals[nCounter + 1] = n4; - mapNormals[nCounter + 2] = n4; - mapNormals[nCounter + 3] = n4; - mapNormals[nCounter + 4] = n4; - mapNormals[nCounter + 5] = n4; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height }; - mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y }; - mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height }; - tcCounter += 6; - - // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8) - mapVertices[vCounter] = v6; - mapVertices[vCounter + 1] = v7; - mapVertices[vCounter + 2] = v8; - mapVertices[vCounter + 3] = v6; - mapVertices[vCounter + 4] = v8; - mapVertices[vCounter + 5] = v5; - vCounter += 6; - - mapNormals[nCounter] = n3; - mapNormals[nCounter + 1] = n3; - mapNormals[nCounter + 2] = n3; - mapNormals[nCounter + 3] = n3; - mapNormals[nCounter + 4] = n3; - mapNormals[nCounter + 5] = n3; - nCounter += 6; - - mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; - mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height }; - mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; - mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y }; - mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height }; - mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y }; - tcCounter += 6; - } - } - } - - // Move data from mapVertices temp arrays to vertices float array - mesh.vertexCount = vCounter; - mesh.triangleCount = vCounter/3; - - mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); - mesh.colors = NULL; - - int fCounter = 0; - - // Move vertices data - for (int i = 0; i < vCounter; i++) - { - mesh.vertices[fCounter] = mapVertices[i].x; - mesh.vertices[fCounter + 1] = mapVertices[i].y; - mesh.vertices[fCounter + 2] = mapVertices[i].z; - fCounter += 3; - } - - fCounter = 0; - - // Move normals data - for (int i = 0; i < nCounter; i++) - { - mesh.normals[fCounter] = mapNormals[i].x; - mesh.normals[fCounter + 1] = mapNormals[i].y; - mesh.normals[fCounter + 2] = mapNormals[i].z; - fCounter += 3; - } - - fCounter = 0; - - // Move texcoords data - for (int i = 0; i < tcCounter; i++) - { - mesh.texcoords[fCounter] = mapTexcoords[i].x; - mesh.texcoords[fCounter + 1] = mapTexcoords[i].y; - fCounter += 2; - } - - RL_FREE(mapVertices); - RL_FREE(mapNormals); - RL_FREE(mapTexcoords); - - UnloadImageColors(pixels); // Unload pixels color data - - // Upload vertex data to GPU (static mesh) - UploadMesh(&mesh, false); - - return mesh; -} -#endif // SUPPORT_MESH_GENERATION - -// Compute mesh bounding box limits -// NOTE: minVertex and maxVertex should be transformed by model transform matrix -BoundingBox GetMeshBoundingBox(Mesh mesh) -{ - // Get min and max vertex to construct bounds (AABB) - Vector3 minVertex = { 0 }; - Vector3 maxVertex = { 0 }; - - if (mesh.vertices != NULL) - { - minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; - maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; - - for (int i = 1; i < mesh.vertexCount; i++) - { - minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); - maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); - } - } - - // Create the bounding box - BoundingBox box = { 0 }; - box.min = minVertex; - box.max = maxVertex; - - return box; -} - -// Compute mesh tangents -void GenMeshTangents(Mesh *mesh) -{ - // Check if input mesh data is useful - if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL)) - { - TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data"); - return; - } - - // Allocate or reallocate tangents data - if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float)); - else - { - RL_FREE(mesh->tangents); - mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float)); - } - - // Allocate temporary arrays for tangents calculation - Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3)); - Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3)); - - if (tan1 == NULL || tan2 == NULL) - { - TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation"); - if (tan1) RL_FREE(tan1); - if (tan2) RL_FREE(tan2); - return; - } - - // Process all triangles of the mesh - // 'triangleCount' must be always valid - for (int t = 0; t < mesh->triangleCount; t++) - { - // Get triangle vertex indices - int i0, i1, i2; - - if (mesh->indices != NULL) - { - // Use indices if available - i0 = mesh->indices[t*3 + 0]; - i1 = mesh->indices[t*3 + 1]; - i2 = mesh->indices[t*3 + 2]; - } - else - { - // Sequential access for non-indexed mesh - i0 = t*3 + 0; - i1 = t*3 + 1; - i2 = t*3 + 2; - } - - // Get triangle vertices position - Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] }; - Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] }; - Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] }; - - // Get triangle texcoords - Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] }; - Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] }; - Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] }; - - // Calculate triangle edges - float x1 = v2.x - v1.x; - float y1 = v2.y - v1.y; - float z1 = v2.z - v1.z; - float x2 = v3.x - v1.x; - float y2 = v3.y - v1.y; - float z2 = v3.z - v1.z; - - // Calculate texture coordinate differences - float s1 = uv2.x - uv1.x; - float t1 = uv2.y - uv1.y; - float s2 = uv3.x - uv1.x; - float t2 = uv3.y - uv1.y; - - // Calculate denominator and check for degenerate UV - float div = s1*t2 - s2*t1; - float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div; - - // Calculate tangent and bitangent directions - Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; - Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; - - // Accumulate tangents and bitangents for each vertex of the triangle - tan1[i0] = Vector3Add(tan1[i0], sdir); - tan1[i1] = Vector3Add(tan1[i1], sdir); - tan1[i2] = Vector3Add(tan1[i2], sdir); - - tan2[i0] = Vector3Add(tan2[i0], tdir); - tan2[i1] = Vector3Add(tan2[i1], tdir); - tan2[i2] = Vector3Add(tan2[i2], tdir); - } - - // Calculate final tangents for each vertex - for (int i = 0; i < mesh->vertexCount; i++) - { - Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] }; - Vector3 tangent = tan1[i]; - - // Handle zero tangent (can happen with degenerate UVs) - if (Vector3Length(tangent) < 0.0001f) - { - // Create a tangent perpendicular to the normal - if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f }; - else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f }); - - mesh->tangents[i*4 + 0] = tangent.x; - mesh->tangents[i*4 + 1] = tangent.y; - mesh->tangents[i*4 + 2] = tangent.z; - mesh->tangents[i*4 + 3] = 1.0f; - continue; - } - - // Gram-Schmidt orthogonalization to make tangent orthogonal to normal - // T_prime = T - N * dot(N, T) - Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent))); - - // Handle cases where orthogonalized vector is too small - if (Vector3Length(orthogonalized) < 0.0001f) - { - // Create a tangent perpendicular to the normal - if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f }; - else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f }); - } - else - { - // Normalize the orthogonalized tangent - orthogonalized = Vector3Normalize(orthogonalized); - } - - // Store the calculated tangent - mesh->tangents[i*4 + 0] = orthogonalized.x; - mesh->tangents[i*4 + 1] = orthogonalized.y; - mesh->tangents[i*4 + 2] = orthogonalized.z; - - // Calculate the handedness (w component) - mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f; - } - - // Free temporary arrays - RL_FREE(tan1); - RL_FREE(tan2); - - // Update vertex buffers if available - if (mesh->vboId != NULL) - { - if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0) - { - // Update existing tangent vertex buffer - rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0); - } - else - { - // Create new tangent vertex buffer - mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false); - } - - // Set up vertex attributes for shader - rlEnableVertexArray(mesh->vaoId); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT); - rlDisableVertexArray(); - } - - TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh"); -} - -// Draw a model (with texture if set) -void DrawModel(Model model, Vector3 position, float scale, Color tint) -{ - Vector3 vScale = { scale, scale, scale }; - Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f }; - - DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); -} - -// Draw a model with extended parameters -void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) -{ - // Calculate transformation matrix from function parameters - // Get transform matrix (rotation -> scale -> translation) - Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); - Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); - Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); - - Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); - - // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) - model.transform = MatrixMultiply(model.transform, matTransform); - - for (int i = 0; i < model.meshCount; i++) - { - Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color; - - Color colorTint = WHITE; - colorTint.r = (unsigned char)(((int)color.r*(int)tint.r)/255); - colorTint.g = (unsigned char)(((int)color.g*(int)tint.g)/255); - colorTint.b = (unsigned char)(((int)color.b*(int)tint.b)/255); - colorTint.a = (unsigned char)(((int)color.a*(int)tint.a)/255); - - model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint; - DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform); - model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color; - } -} - -// Draw a model wires (with texture if set) -void DrawModelWires(Model model, Vector3 position, float scale, Color tint) -{ - rlEnableWireMode(); - - DrawModel(model, position, scale, tint); - - rlDisableWireMode(); -} - -// Draw a model wires (with texture if set) with extended parameters -void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) -{ - rlEnableWireMode(); - - DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); - - rlDisableWireMode(); -} - -// Draw a model points -// WARNING: OpenGL ES 2.0 does not support point mode drawing -void DrawModelPoints(Model model, Vector3 position, float scale, Color tint) -{ - rlEnablePointMode(); - rlDisableBackfaceCulling(); - - DrawModel(model, position, scale, tint); - - rlEnableBackfaceCulling(); - rlDisablePointMode(); -} - -// Draw a model points -// WARNING: OpenGL ES 2.0 does not support point mode drawing -void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) -{ - rlEnablePointMode(); - rlDisableBackfaceCulling(); - - DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); - - rlEnableBackfaceCulling(); - rlDisablePointMode(); -} - -// Draw a billboard -void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint) -{ - Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height }; - - DrawBillboardRec(camera, texture, source, position, (Vector2) { scale*fabsf((float)source.width/source.height), scale }, tint); -} - -// Draw a billboard (part of a texture defined by a rectangle) -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint) -{ - // NOTE: Billboard locked on axis-Y - Vector3 up = { 0.0f, 1.0f, 0.0f }; - - DrawBillboardPro(camera, texture, source, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint); -} - -// Draw a billboard with additional parameters -void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint) -{ - // Compute the up vector and the right vector - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - Vector3 right = { matView.m0, matView.m4, matView.m8 }; - right = Vector3Scale(right, size.x); - up = Vector3Scale(up, size.y); - - // Flip the content of the billboard while maintaining the counterclockwise edge rendering order - if (size.x < 0.0f) - { - source.x += size.x; - source.width *= -1.0; - right = Vector3Negate(right); - origin.x *= -1.0f; - } - if (size.y < 0.0f) - { - source.y += size.y; - source.height *= -1.0; - up = Vector3Negate(up); - origin.y *= -1.0f; - } - - // Draw the texture region described by source on the following rectangle in 3D space: - // - // size.x <--. - // 3 ^---------------------------+ 2 \ rotation - // | | / - // | | - // | origin.x position | - // up |.............. | size.y - // | . | - // | . origin.y | - // | . | - // 0 +---------------------------> 1 - // right - Vector3 forward; - if (rotation != 0.0) forward = Vector3CrossProduct(right, up); - - Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(right), origin.x), Vector3Scale(Vector3Normalize(up), origin.y)); - - Vector3 points[4]; - points[0] = Vector3Zero(); - points[1] = right; - points[2] = Vector3Add(up, right); - points[3] = up; - - for (int i = 0; i < 4; i++) - { - points[i] = Vector3Subtract(points[i], origin3D); - if (rotation != 0.0) points[i] = Vector3RotateByAxisAngle(points[i], forward, rotation*DEG2RAD); - points[i] = Vector3Add(points[i], position); - } - - Vector2 texcoords[4]; - texcoords[0] = (Vector2){ (float)source.x/texture.width, (float)(source.y + source.height)/texture.height }; - texcoords[1] = (Vector2){ (float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height }; - texcoords[2] = (Vector2){ (float)(source.x + source.width)/texture.width, (float)source.y/texture.height }; - texcoords[3] = (Vector2){ (float)source.x/texture.width, (float)source.y/texture.height }; - - rlSetTexture(texture.id); - rlBegin(RL_QUADS); - - rlColor4ub(tint.r, tint.g, tint.b, tint.a); - for (int i = 0; i < 4; i++) - { - rlTexCoord2f(texcoords[i].x, texcoords[i].y); - rlVertex3f(points[i].x, points[i].y, points[i].z); - } - - rlEnd(); - rlSetTexture(0); -} - -// Draw a bounding box with wires -void DrawBoundingBox(BoundingBox box, Color color) -{ - Vector3 size = { 0 }; - - size.x = fabsf(box.max.x - box.min.x); - size.y = fabsf(box.max.y - box.min.y); - size.z = fabsf(box.max.z - box.min.z); - - Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f }; - - DrawCubeWires(center, size.x, size.y, size.z, color); -} - -// Check collision between two spheres -bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2) -{ - bool collision = false; - - // Simple way to check for collision, just checking distance between two points - // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution - /* - float dx = center1.x - center2.x; // X distance between centers - float dy = center1.y - center2.y; // Y distance between centers - float dz = center1.z - center2.z; // Z distance between centers - - float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers - - if (distance <= (radius1 + radius2)) collision = true; - */ - - // Check for distances squared to avoid sqrtf() - if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true; - - return collision; -} - -// Check collision between two boxes -// NOTE: Boxes are defined by two points minimum and maximum -bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2) -{ - bool collision = true; - - if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x)) - { - if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false; - if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false; - } - else collision = false; - - return collision; -} - -// Check collision between box and sphere -bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius) -{ - bool collision = false; - - float dmin = 0; - - if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2); - else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2); - - if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2); - else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2); - - if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2); - else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2); - - if (dmin <= (radius*radius)) collision = true; - - return collision; -} - -// Get collision info between ray and sphere -RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius) -{ - RayCollision collision = { 0 }; - - Vector3 raySpherePos = Vector3Subtract(center, ray.position); - float vector = Vector3DotProduct(raySpherePos, ray.direction); - float distance = Vector3Length(raySpherePos); - float d = radius*radius - (distance*distance - vector*vector); - - collision.hit = d >= 0.0f; - - // Check if ray origin is inside the sphere to calculate the correct collision point - if (distance < radius) - { - collision.distance = vector + sqrtf(d); - - // Calculate collision point - collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance)); - - // Calculate collision normal (pointing outwards) - collision.normal = Vector3Negate(Vector3Normalize(Vector3Subtract(collision.point, center))); - } - else - { - collision.distance = vector - sqrtf(d); - - // Calculate collision point - collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance)); - - // Calculate collision normal (pointing inwards) - collision.normal = Vector3Normalize(Vector3Subtract(collision.point, center)); - } - - return collision; -} - -// Get collision info between ray and box -RayCollision GetRayCollisionBox(Ray ray, BoundingBox box) -{ - RayCollision collision = { 0 }; - - // Note: If ray.position is inside the box, the distance is negative (as if the ray was reversed) - // Reversing ray.direction will give use the correct result - bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) && - (ray.position.y > box.min.y) && (ray.position.y < box.max.y) && - (ray.position.z > box.min.z) && (ray.position.z < box.max.z); - - if (insideBox) ray.direction = Vector3Negate(ray.direction); - - float t[11] = { 0 }; - - t[8] = 1.0f/ray.direction.x; - t[9] = 1.0f/ray.direction.y; - t[10] = 1.0f/ray.direction.z; - - t[0] = (box.min.x - ray.position.x)*t[8]; - t[1] = (box.max.x - ray.position.x)*t[8]; - t[2] = (box.min.y - ray.position.y)*t[9]; - t[3] = (box.max.y - ray.position.y)*t[9]; - t[4] = (box.min.z - ray.position.z)*t[10]; - t[5] = (box.max.z - ray.position.z)*t[10]; - t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5])); - t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5])); - - collision.hit = !((t[7] < 0) || (t[6] > t[7])); - collision.distance = t[6]; - collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance)); - - // Get box center point - collision.normal = Vector3Lerp(box.min, box.max, 0.5f); - // Get vector center point->hit point - collision.normal = Vector3Subtract(collision.point, collision.normal); - // Scale vector to unit cube - // NOTE: We use an additional .01 to fix numerical errors - collision.normal = Vector3Scale(collision.normal, 2.01f); - collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min)); - // The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f) - // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal! - collision.normal.x = (float)((int)collision.normal.x); - collision.normal.y = (float)((int)collision.normal.y); - collision.normal.z = (float)((int)collision.normal.z); - - collision.normal = Vector3Normalize(collision.normal); - - if (insideBox) - { - // Reset ray.direction - ray.direction = Vector3Negate(ray.direction); - // Fix result - collision.distance *= -1.0f; - collision.normal = Vector3Negate(collision.normal); - } - - return collision; -} - -// Get collision info between ray and mesh -RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform) -{ - RayCollision collision = { 0 }; - - // Check if mesh vertex data on CPU for testing - if (mesh.vertices != NULL) - { - int triangleCount = mesh.triangleCount; - - // Test against all triangles in mesh - for (int i = 0; i < triangleCount; i++) - { - Vector3 a, b, c; - Vector3 *vertdata = (Vector3 *)mesh.vertices; - - if (mesh.indices) - { - a = vertdata[mesh.indices[i*3 + 0]]; - b = vertdata[mesh.indices[i*3 + 1]]; - c = vertdata[mesh.indices[i*3 + 2]]; - } - else - { - a = vertdata[i*3 + 0]; - b = vertdata[i*3 + 1]; - c = vertdata[i*3 + 2]; - } - - a = Vector3Transform(a, transform); - b = Vector3Transform(b, transform); - c = Vector3Transform(c, transform); - - RayCollision triHitInfo = GetRayCollisionTriangle(ray, a, b, c); - - if (triHitInfo.hit) - { - // Save the closest hit triangle - if ((!collision.hit) || (collision.distance > triHitInfo.distance)) collision = triHitInfo; - } - } - } - - return collision; -} - -// Get collision info between ray and triangle -// NOTE: The points are expected to be in counter-clockwise winding -// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm -RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) -{ - #define EPSILON 0.000001f // A small number - - RayCollision collision = { 0 }; - Vector3 edge1 = { 0 }; - Vector3 edge2 = { 0 }; - Vector3 p, q, tv; - float det, invDet, u, v, t; - - // Find vectors for two edges sharing V1 - edge1 = Vector3Subtract(p2, p1); - edge2 = Vector3Subtract(p3, p1); - - // Begin calculating determinant - also used to calculate u parameter - p = Vector3CrossProduct(ray.direction, edge2); - - // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle - det = Vector3DotProduct(edge1, p); - - // Avoid culling! - if ((det > -EPSILON) && (det < EPSILON)) return collision; - - invDet = 1.0f/det; - - // Calculate distance from V1 to ray origin - tv = Vector3Subtract(ray.position, p1); - - // Calculate u parameter and test bound - u = Vector3DotProduct(tv, p)*invDet; - - // The intersection lies outside the triangle - if ((u < 0.0f) || (u > 1.0f)) return collision; - - // Prepare to test v parameter - q = Vector3CrossProduct(tv, edge1); - - // Calculate V parameter and test bound - v = Vector3DotProduct(ray.direction, q)*invDet; - - // The intersection lies outside the triangle - if ((v < 0.0f) || ((u + v) > 1.0f)) return collision; - - t = Vector3DotProduct(edge2, q)*invDet; - - if (t > EPSILON) - { - // Ray hit, get hit point and normal - collision.hit = true; - collision.distance = t; - collision.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2)); - collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, t)); - } - - return collision; -} - -// Get collision info between ray and quad -// NOTE: The points are expected to be in counter-clockwise winding -RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4) -{ - RayCollision collision = { 0 }; - - collision = GetRayCollisionTriangle(ray, p1, p2, p4); - - if (!collision.hit) collision = GetRayCollisionTriangle(ray, p2, p3, p4); - - return collision; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_IQM) || defined(SUPPORT_FILEFORMAT_GLTF) -// Build pose from parent joints -// NOTE: Required for animations loading (required by IQM and GLTF) -static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms) -{ - for (int i = 0; i < boneCount; i++) - { - if (bones[i].parent >= 0) - { - if (bones[i].parent > i) - { - TRACELOG(LOG_WARNING, "Assumes bones are toplogically sorted, but bone %d has parent %d. Skipping.", i, bones[i].parent); - continue; - } - transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation); - transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation); - transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation); - transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale); - } - } -} -#endif - -#if defined(SUPPORT_FILEFORMAT_OBJ) -// Load OBJ mesh data -// -// Keep the following information in mind when reading this -// - A mesh is created for every material present in the obj file -// - the model.meshCount is therefore the materialCount returned from tinyobj -// - the mesh is automatically triangulated by tinyobj -static Model LoadOBJ(const char *fileName) -{ - tinyobj_attrib_t objAttributes = { 0 }; - tinyobj_shape_t *objShapes = NULL; - unsigned int objShapeCount = 0; - - tinyobj_material_t *objMaterials = NULL; - unsigned int objMaterialCount = 0; - - Model model = { 0 }; - model.transform = MatrixIdentity(); - - char *fileText = LoadFileText(fileName); - - if (fileText == NULL) - { - TRACELOG(LOG_ERROR, "MODEL: [%s] Unable to read obj file", fileName); - return model; - } - - char currentDir[1024] = { 0 }; - strcpy(currentDir, GetWorkingDirectory()); // Save current working directory - const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness - if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir); - - unsigned int dataSize = (unsigned int)strlen(fileText); - - unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; - int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags); - - if (ret != TINYOBJ_SUCCESS) - { - TRACELOG(LOG_ERROR, "MODEL: Unable to read obj data %s", fileName); - return model; - } - - UnloadFileText(fileText); - - unsigned int faceVertIndex = 0; - unsigned int nextShape = 1; - int lastMaterial = -1; - unsigned int meshIndex = 0; - - // Count meshes - unsigned int nextShapeEnd = objAttributes.num_face_num_verts; - - // See how many verts till the next shape - if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset; - - // Walk all the faces - for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++) - { - if (faceId >= nextShapeEnd) - { - // Try to find the last vert in the next shape - nextShape++; - if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset; - else nextShapeEnd = objAttributes.num_face_num_verts; // This is actually the total number of face verts in the file, not faces - meshIndex++; - } - else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial)) - { - meshIndex++; // If this is a new material, we need to allocate a new mesh - } - - lastMaterial = objAttributes.material_ids[faceId]; - faceVertIndex += objAttributes.face_num_verts[faceId]; - } - - // Allocate the base meshes and materials - model.meshCount = meshIndex + 1; - model.meshes = (Mesh *)MemAlloc(sizeof(Mesh)*model.meshCount); - - if (objMaterialCount > 0) - { - model.materialCount = objMaterialCount; - model.materials = (Material *)MemAlloc(sizeof(Material)*objMaterialCount); - } - else // We must allocate at least one material - { - model.materialCount = 1; - model.materials = (Material *)MemAlloc(sizeof(Material)*1); - } - - model.meshMaterial = (int *)MemAlloc(sizeof(int)*model.meshCount); - - // See how many verts are in each mesh - unsigned int *localMeshVertexCounts = (unsigned int *)MemAlloc(sizeof(unsigned int)*model.meshCount); - - faceVertIndex = 0; - nextShapeEnd = objAttributes.num_face_num_verts; - lastMaterial = -1; - meshIndex = 0; - unsigned int localMeshVertexCount = 0; - - nextShape = 1; - if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset; - - // Walk all the faces - for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++) - { - bool newMesh = false; // Do we need a new mesh? - if (faceId >= nextShapeEnd) - { - // Try to find the last vert in the next shape - nextShape++; - if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset; - else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces - - newMesh = true; - } - else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial)) - { - newMesh = true; - } - - lastMaterial = objAttributes.material_ids[faceId]; - - if (newMesh) - { - localMeshVertexCounts[meshIndex] = localMeshVertexCount; - - localMeshVertexCount = 0; - meshIndex++; - } - - faceVertIndex += objAttributes.face_num_verts[faceId]; - localMeshVertexCount += objAttributes.face_num_verts[faceId]; - } - - localMeshVertexCounts[meshIndex] = localMeshVertexCount; - - for (int i = 0; i < model.meshCount; i++) - { - // Allocate the buffers for each mesh - unsigned int vertexCount = localMeshVertexCounts[i]; - - model.meshes[i].vertexCount = vertexCount; - model.meshes[i].triangleCount = vertexCount/3; - - model.meshes[i].vertices = (float *)MemAlloc(sizeof(float)*vertexCount*3); - model.meshes[i].normals = (float *)MemAlloc(sizeof(float)*vertexCount*3); - model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2); - model.meshes[i].colors = (unsigned char *)MemAlloc(sizeof(unsigned char)*vertexCount*4); - } - - MemFree(localMeshVertexCounts); - localMeshVertexCounts = NULL; - - // Fill meshes - faceVertIndex = 0; - - nextShapeEnd = objAttributes.num_face_num_verts; - - // See how many verts till the next shape - nextShape = 1; - if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset; - lastMaterial = -1; - meshIndex = 0; - localMeshVertexCount = 0; - - // Walk all the faces - for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++) - { - bool newMesh = false; // Do we need a new mesh? - if (faceId >= nextShapeEnd) - { - // Try to find the last vert in the next shape - nextShape++; - if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset; - else nextShapeEnd = objAttributes.num_face_num_verts; // This is actually the total number of face verts in the file, not faces - newMesh = true; - } - - // If this is a new material, we need to allocate a new mesh - if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true; - lastMaterial = objAttributes.material_ids[faceId]; - - if (newMesh) - { - localMeshVertexCount = 0; - meshIndex++; - } - - int matId = 0; - if ((lastMaterial >= 0) && (lastMaterial < (int)objMaterialCount)) matId = lastMaterial; - - model.meshMaterial[meshIndex] = matId; - - for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++) - { - int vertIndex = objAttributes.faces[faceVertIndex].v_idx; - int normalIndex = objAttributes.faces[faceVertIndex].vn_idx; - int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx; - - for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i]; - - for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i]; - - for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i]; - - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1]; - - for (int i = 0; i < 4; i++) model.meshes[meshIndex].colors[localMeshVertexCount*4 + i] = 255; - - faceVertIndex++; - localMeshVertexCount++; - } - } - - if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount); - else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh - - tinyobj_attrib_free(&objAttributes); - tinyobj_shapes_free(objShapes, objShapeCount); - tinyobj_materials_free(objMaterials, objMaterialCount); - - for (int i = 0; i < model.meshCount; i++) UploadMesh(model.meshes + i, true); - - // Restore current working directory - if (CHDIR(currentDir) != 0) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir); - } - - return model; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_IQM) -// Load IQM mesh data -static Model LoadIQM(const char *fileName) -{ - #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number - #define IQM_VERSION 2 // only IQM version 2 supported - - #define BONE_NAME_LENGTH 32 // BoneInfo name string length - #define MESH_NAME_LENGTH 32 // Mesh name string length - #define MATERIAL_NAME_LENGTH 32 // Material name string length - - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - unsigned char *fileDataPtr = fileData; - - // IQM file structs - //----------------------------------------------------------------------------------- - typedef struct IQMHeader { - char magic[16]; - unsigned int version; - unsigned int dataSize; - unsigned int flags; - unsigned int num_text, ofs_text; - unsigned int num_meshes, ofs_meshes; - unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; - unsigned int num_triangles, ofs_triangles, ofs_adjacency; - unsigned int num_joints, ofs_joints; - unsigned int num_poses, ofs_poses; - unsigned int num_anims, ofs_anims; - unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds; - unsigned int num_comment, ofs_comment; - unsigned int num_extensions, ofs_extensions; - } IQMHeader; - - typedef struct IQMMesh { - unsigned int name; - unsigned int material; - unsigned int first_vertex, num_vertexes; - unsigned int first_triangle, num_triangles; - } IQMMesh; - - typedef struct IQMTriangle { - unsigned int vertex[3]; - } IQMTriangle; - - typedef struct IQMJoint { - unsigned int name; - int parent; - float translate[3], rotate[4], scale[3]; - } IQMJoint; - - typedef struct IQMVertexArray { - unsigned int type; - unsigned int flags; - unsigned int format; - unsigned int size; - unsigned int offset; - } IQMVertexArray; - - // NOTE: Below IQM structures are not used but listed for reference - /* - typedef struct IQMAdjacency { - unsigned int triangle[3]; - } IQMAdjacency; - - typedef struct IQMPose { - int parent; - unsigned int mask; - float channeloffset[10]; - float channelscale[10]; - } IQMPose; - - typedef struct IQMAnim { - unsigned int name; - unsigned int first_frame, num_frames; - float framerate; - unsigned int flags; - } IQMAnim; - - typedef struct IQMBounds { - float bbmin[3], bbmax[3]; - float xyradius, radius; - } IQMBounds; - */ - //----------------------------------------------------------------------------------- - - // IQM vertex data types - enum { - IQM_POSITION = 0, - IQM_TEXCOORD = 1, - IQM_NORMAL = 2, - IQM_TANGENT = 3, // NOTE: Tangents unused by default - IQM_BLENDINDEXES = 4, - IQM_BLENDWEIGHTS = 5, - IQM_COLOR = 6, - IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default - }; - - Model model = { 0 }; - - IQMMesh *imesh = NULL; - IQMTriangle *tri = NULL; - IQMVertexArray *va = NULL; - IQMJoint *ijoint = NULL; - - float *vertex = NULL; - float *normal = NULL; - float *text = NULL; - char *blendi = NULL; - unsigned char *blendw = NULL; - unsigned char *color = NULL; - - // In case file can not be read, return an empty model - if (fileDataPtr == NULL) return model; - - const char *basePath = GetDirectoryPath(fileName); - - // Read IQM header - IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr; - - if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); - UnloadFileData(fileData); - return model; - } - - if (iqmHeader->version != IQM_VERSION) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); - UnloadFileData(fileData); - return model; - } - - //fileDataPtr += sizeof(IQMHeader); // Move file data pointer - - // Meshes data processing - imesh = (IQMMesh *)RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh)); - //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET); - //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile); - memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh)); - - model.meshCount = iqmHeader->num_meshes; - model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); - - model.materialCount = model.meshCount; - model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); - model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); - - char name[MESH_NAME_LENGTH] = { 0 }; - char material[MATERIAL_NAME_LENGTH] = { 0 }; - - for (int i = 0; i < model.meshCount; i++) - { - //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET); - //fread(name, sizeof(char), MESH_NAME_LENGTH, iqmFile); - memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char)); - - //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET); - //fread(material, sizeof(char), MATERIAL_NAME_LENGTH, iqmFile); - memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char)); - - model.materials[i] = LoadMaterialDefault(); - model.materials[i].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture(TextFormat("%s/%s", basePath, material)); - - model.meshMaterial[i] = i; - - TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material); - - model.meshes[i].vertexCount = imesh[i].num_vertexes; - - model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions - model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals - model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords - - model.meshes[i].boneIds = (unsigned char *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported! - model.meshes[i].boneWeights = (float *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported! - - model.meshes[i].triangleCount = imesh[i].num_triangles; - model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short)); - - // Animated vertex data, what we actually process for rendering - // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning) - model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); - model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); - } - - // Triangles data processing - tri = (IQMTriangle *)RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle)); - //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET); - //fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile); - memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle)); - - for (int m = 0; m < model.meshCount; m++) - { - int tcounter = 0; - - for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++) - { - // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order, - // expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes - // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default - model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex; - model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex; - model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex; - tcounter += 3; - } - } - - // Vertex arrays data processing - va = (IQMVertexArray *)RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); - //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET); - //fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile); - memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); - - for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++) - { - switch (va[i].type) - { - case IQM_POSITION: - { - vertex = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float)); - //fseek(iqmFile, va[i].offset, SEEK_SET); - //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile); - memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float)); - - for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) - { - int vCounter = 0; - for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++) - { - model.meshes[m].vertices[vCounter] = vertex[i]; - model.meshes[m].animVertices[vCounter] = vertex[i]; - vCounter++; - } - } - } break; - case IQM_NORMAL: - { - normal = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float)); - //fseek(iqmFile, va[i].offset, SEEK_SET); - //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile); - memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float)); - - for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) - { - int vCounter = 0; - for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++) - { - model.meshes[m].normals[vCounter] = normal[i]; - model.meshes[m].animNormals[vCounter] = normal[i]; - vCounter++; - } - } - } break; - case IQM_TEXCOORD: - { - text = (float *)RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float)); - //fseek(iqmFile, va[i].offset, SEEK_SET); - //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile); - memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float)); - - for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) - { - int vCounter = 0; - for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++) - { - model.meshes[m].texcoords[vCounter] = text[i]; - vCounter++; - } - } - } break; - case IQM_BLENDINDEXES: - { - blendi = (char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char)); - //fseek(iqmFile, va[i].offset, SEEK_SET); - //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile); - memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char)); - - for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) - { - int boneCounter = 0; - for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) - { - model.meshes[m].boneIds[boneCounter] = blendi[i]; - boneCounter++; - } - } - } break; - case IQM_BLENDWEIGHTS: - { - blendw = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char)); - //fseek(iqmFile, va[i].offset, SEEK_SET); - //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile); - memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char)); - - for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) - { - int boneCounter = 0; - for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) - { - model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f; - boneCounter++; - } - } - } break; - case IQM_COLOR: - { - color = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char)); - //fseek(iqmFile, va[i].offset, SEEK_SET); - //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile); - memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char)); - - for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) - { - model.meshes[m].colors = (unsigned char *)RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char)); - - int vCounter = 0; - for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) - { - model.meshes[m].colors[vCounter] = color[i]; - vCounter++; - } - } - } break; - } - } - - // Bones (joints) data processing - ijoint = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint)); - //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET); - //fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile); - memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint)); - - model.boneCount = iqmHeader->num_joints; - model.bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo)); - model.bindPose = (Transform *)RL_MALLOC(iqmHeader->num_joints*sizeof(Transform)); - - for (unsigned int i = 0; i < iqmHeader->num_joints; i++) - { - // Bones - model.bones[i].parent = ijoint[i].parent; - //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET); - //fread(model.bones[i].name, sizeof(char), BONE_NAME_LENGTH, iqmFile); - memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char)); - - // Bind pose (base pose) - model.bindPose[i].translation.x = ijoint[i].translate[0]; - model.bindPose[i].translation.y = ijoint[i].translate[1]; - model.bindPose[i].translation.z = ijoint[i].translate[2]; - - model.bindPose[i].rotation.x = ijoint[i].rotate[0]; - model.bindPose[i].rotation.y = ijoint[i].rotate[1]; - model.bindPose[i].rotation.z = ijoint[i].rotate[2]; - model.bindPose[i].rotation.w = ijoint[i].rotate[3]; - - model.bindPose[i].scale.x = ijoint[i].scale[0]; - model.bindPose[i].scale.y = ijoint[i].scale[1]; - model.bindPose[i].scale.z = ijoint[i].scale[2]; - } - - BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose); - - for (int i = 0; i < model.meshCount; i++) - { - model.meshes[i].boneCount = model.boneCount; - model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix)); - - for (int j = 0; j < model.meshes[i].boneCount; j++) - { - model.meshes[i].boneMatrices[j] = MatrixIdentity(); - } - } - - UnloadFileData(fileData); - - RL_FREE(imesh); - RL_FREE(tri); - RL_FREE(va); - RL_FREE(vertex); - RL_FREE(normal); - RL_FREE(text); - RL_FREE(blendi); - RL_FREE(blendw); - RL_FREE(ijoint); - RL_FREE(color); - - return model; -} - -// Load IQM animation data -static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount) -{ - #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number - #define IQM_VERSION 2 // only IQM version 2 supported - - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - unsigned char *fileDataPtr = fileData; - - typedef struct IQMHeader { - char magic[16]; - unsigned int version; - unsigned int dataSize; - unsigned int flags; - unsigned int num_text, ofs_text; - unsigned int num_meshes, ofs_meshes; - unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; - unsigned int num_triangles, ofs_triangles, ofs_adjacency; - unsigned int num_joints, ofs_joints; - unsigned int num_poses, ofs_poses; - unsigned int num_anims, ofs_anims; - unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds; - unsigned int num_comment, ofs_comment; - unsigned int num_extensions, ofs_extensions; - } IQMHeader; - - typedef struct IQMJoint { - unsigned int name; - int parent; - float translate[3], rotate[4], scale[3]; - } IQMJoint; - - typedef struct IQMPose { - int parent; - unsigned int mask; - float channeloffset[10]; - float channelscale[10]; - } IQMPose; - - typedef struct IQMAnim { - unsigned int name; - unsigned int first_frame, num_frames; - float framerate; - unsigned int flags; - } IQMAnim; - - // In case file can not be read, return an empty model - if (fileDataPtr == NULL) return NULL; - - // Read IQM header - IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr; - - if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); - UnloadFileData(fileData); - return NULL; - } - - if (iqmHeader->version != IQM_VERSION) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); - UnloadFileData(fileData); - return NULL; - } - - // Get bones data - IQMPose *poses = (IQMPose *)RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose)); - //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET); - //fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile); - memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose)); - - // Get animations data - *animCount = iqmHeader->num_anims; - IQMAnim *anim = (IQMAnim *)RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim)); - //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET); - //fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile); - memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim)); - - ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation)); - - // frameposes - unsigned short *framedata = (unsigned short *)RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); - //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET); - //fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile); - memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); - - // joints - IQMJoint *joints = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint)); - memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint)); - - for (unsigned int a = 0; a < iqmHeader->num_anims; a++) - { - animations[a].frameCount = anim[a].num_frames; - animations[a].boneCount = iqmHeader->num_poses; - animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo)); - animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *)); - memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here - TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name); - // animations[a].framerate = anim.framerate; // TODO: Use animation framerate data? - - for (unsigned int j = 0; j < iqmHeader->num_poses; j++) - { - // If animations and skeleton are in the same file, copy bone names to anim - if (iqmHeader->num_joints > 0) - memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char)); - else - strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // default bone name otherwise - animations[a].bones[j].parent = poses[j].parent; - } - - for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = (Transform *)RL_MALLOC(iqmHeader->num_poses*sizeof(Transform)); - - int dcounter = anim[a].first_frame*iqmHeader->num_framechannels; - - for (unsigned int frame = 0; frame < anim[a].num_frames; frame++) - { - for (unsigned int i = 0; i < iqmHeader->num_poses; i++) - { - animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0]; - - if (poses[i].mask & 0x01) - { - animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0]; - dcounter++; - } - - animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1]; - - if (poses[i].mask & 0x02) - { - animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1]; - dcounter++; - } - - animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2]; - - if (poses[i].mask & 0x04) - { - animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2]; - dcounter++; - } - - animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3]; - - if (poses[i].mask & 0x08) - { - animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3]; - dcounter++; - } - - animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4]; - - if (poses[i].mask & 0x10) - { - animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4]; - dcounter++; - } - - animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5]; - - if (poses[i].mask & 0x20) - { - animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5]; - dcounter++; - } - - animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6]; - - if (poses[i].mask & 0x40) - { - animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6]; - dcounter++; - } - - animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7]; - - if (poses[i].mask & 0x80) - { - animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7]; - dcounter++; - } - - animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8]; - - if (poses[i].mask & 0x100) - { - animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8]; - dcounter++; - } - - animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9]; - - if (poses[i].mask & 0x200) - { - animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9]; - dcounter++; - } - - animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation); - } - } - - // Build frameposes - for (unsigned int frame = 0; frame < anim[a].num_frames; frame++) - { - for (int i = 0; i < animations[a].boneCount; i++) - { - if (animations[a].bones[i].parent >= 0) - { - animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation); - animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation); - animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation); - animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale); - } - } - } - } - - UnloadFileData(fileData); - - RL_FREE(joints); - RL_FREE(framedata); - RL_FREE(poses); - RL_FREE(anim); - - return animations; -} - -#endif - -#if defined(SUPPORT_FILEFORMAT_GLTF) -// Load file data callback for cgltf -static cgltf_result LoadFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, const char *path, cgltf_size *size, void **data) -{ - int filesize; - unsigned char *filedata = LoadFileData(path, &filesize); - - if (filedata == NULL) return cgltf_result_io_error; - - *size = filesize; - *data = filedata; - - return cgltf_result_success; -} - -// Release file data callback for cgltf -static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data) -{ - UnloadFileData(data); -} - -// Load image from different glTF provided methods (uri, path, buffer_view) -static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPath) -{ - Image image = { 0 }; - - if (cgltfImage == NULL) return image; - - if (cgltfImage->uri != NULL) // Check if image data is provided as an uri (base64 or path) - { - if ((strlen(cgltfImage->uri) > 5) && - (cgltfImage->uri[0] == 'd') && - (cgltfImage->uri[1] == 'a') && - (cgltfImage->uri[2] == 't') && - (cgltfImage->uri[3] == 'a') && - (cgltfImage->uri[4] == ':')) // Check if image is provided as base64 text data - { - // Data URI Format: data:;base64, - - // Find the comma - int i = 0; - while ((cgltfImage->uri[i] != ',') && (cgltfImage->uri[i] != 0)) i++; - - if (cgltfImage->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image"); - else - { - int base64Size = (int)strlen(cgltfImage->uri + i + 1); - while (cgltfImage->uri[i + base64Size] == '=') base64Size--; // Ignore optional paddings - int numberOfEncodedBits = base64Size*6 - (base64Size*6) % 8 ; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits - int outSize = numberOfEncodedBits/8 ; // Actual encoded bytes - void *data = NULL; - - cgltf_options options = { 0 }; - options.file.read = LoadFileGLTFCallback; - options.file.release = ReleaseFileGLTFCallback; - cgltf_result result = cgltf_load_buffer_base64(&options, outSize, cgltfImage->uri + i + 1, &data); - - if (result == cgltf_result_success) - { - image = LoadImageFromMemory(".png", (unsigned char *)data, outSize); - RL_FREE(data); - } - } - } - else // Check if image is provided as image path - { - image = LoadImage(TextFormat("%s/%s", texPath, cgltfImage->uri)); - } - } - else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL)) // Check if image is provided as data buffer - { - unsigned char *data = (unsigned char *)RL_MALLOC(cgltfImage->buffer_view->size); - int offset = (int)cgltfImage->buffer_view->offset; - int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1; - - // Copy buffer data to memory for loading - for (unsigned int i = 0; i < cgltfImage->buffer_view->size; i++) - { - data[i] = ((unsigned char *)cgltfImage->buffer_view->buffer->data)[offset]; - offset += stride; - } - - // Check mime_type for image: (cgltfImage->mime_type == "image/png") - // NOTE: Detected that some models define mime_type as "image\\/png" - if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) || (strcmp(cgltfImage->mime_type, "image/png") == 0)) - { - image = LoadImageFromMemory(".png", data, (int)cgltfImage->buffer_view->size); - } - else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) || (strcmp(cgltfImage->mime_type, "image/jpeg") == 0)) - { - image = LoadImageFromMemory(".jpg", data, (int)cgltfImage->buffer_view->size); - } - else TRACELOG(LOG_WARNING, "MODEL: glTF image data MIME type not recognized", TextFormat("%s/%s", texPath, cgltfImage->uri)); - - RL_FREE(data); - } - - return image; -} - -// Load bone info from GLTF skin data -static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount) -{ - *boneCount = (int)skin.joints_count; - BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo)); - - for (unsigned int i = 0; i < skin.joints_count; i++) - { - cgltf_node node = *skin.joints[i]; - if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1); - - // Find parent bone index - int parentIndex = -1; - - for (unsigned int j = 0; j < skin.joints_count; j++) - { - if (skin.joints[j] == node.parent) - { - parentIndex = (int)j; - break; - } - } - - bones[i].parent = parentIndex; - } - - return bones; -} - -// Load glTF file into model struct, .gltf and .glb supported -static Model LoadGLTF(const char *fileName) -{ - /********************************************************************************************* - - Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend) - Transform handling implemented by Paul Melis (@paulmelis) - Reviewed by Ramon Santamaria (@raysan5) - - FEATURES: - - Supports .gltf and .glb files - - Supports embedded (base64) or external textures - - Supports PBR metallic/roughness flow, loads material textures, values and colors - PBR specular/glossiness flow and extended texture flows not supported - - Supports multiple meshes per model (every primitives is loaded as a separate mesh) - - Supports basic animations - - Transforms, including parent-child relations, are applied on the mesh data, - but the hierarchy is not kept (as it can't be represented) - - Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes) - are turned into separate raylib Meshes - - RESTRICTIONS: - - Only triangle meshes supported - - Vertex attribute types and formats supported: - > Vertices (position): vec3: float - > Normals: vec3: float - > Texcoords: vec2: float - > Colors: vec4: u8, u16, f32 (normalized) - > Indices: u16, u32 (truncated to u16) - - Scenes defined in the glTF file are ignored. All nodes in the file - are used. - - ***********************************************************************************************/ - - // Macro to simplify attributes loading code - #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType) - - #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \ - { \ - int n = 0; \ - srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \ - for (unsigned int k = 0; k < accesor->count; k++) \ - {\ - for (int l = 0; l < numComp; l++) \ - {\ - dstPtr[numComp*k + l] = (dstType)buffer[n + l];\ - }\ - n += (int)(accesor->stride/sizeof(srcType));\ - }\ - } - - Model model = { 0 }; - - // glTF file loading - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - - if (fileData == NULL) return model; - - // glTF data loading - cgltf_options options = { 0 }; - options.file.read = LoadFileGLTFCallback; - options.file.release = ReleaseFileGLTFCallback; - cgltf_data *data = NULL; - cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); - - if (result == cgltf_result_success) - { - if (data->file_type == cgltf_file_type_glb) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glb) loaded successfully", fileName); - else if (data->file_type == cgltf_file_type_gltf) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glTF) loaded successfully", fileName); - else TRACELOG(LOG_WARNING, "MODEL: [%s] Model format not recognized", fileName); - - TRACELOG(LOG_INFO, " > Meshes count: %i", data->meshes_count); - TRACELOG(LOG_INFO, " > Materials count: %i (+1 default)", data->materials_count); - TRACELOG(LOG_DEBUG, " > Buffers count: %i", data->buffers_count); - TRACELOG(LOG_DEBUG, " > Images count: %i", data->images_count); - TRACELOG(LOG_DEBUG, " > Textures count: %i", data->textures_count); - - // Force reading data buffers (fills buffer_view->buffer->data) - // NOTE: If an uri is defined to base64 data or external path, it's automatically loaded - result = cgltf_load_buffers(&options, data, fileName); - if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName); - - int primitivesCount = 0; - - // NOTE: We will load every primitive in the glTF as a separate raylib Mesh. - // Determine total number of meshes needed from the node hierarchy. - for (unsigned int i = 0; i < data->nodes_count; i++) - { - cgltf_node *node = &(data->nodes[i]); - cgltf_mesh *mesh = node->mesh; - if (!mesh) continue; - - for (unsigned int p = 0; p < mesh->primitives_count; p++) - { - if (mesh->primitives[p].type == cgltf_primitive_type_triangles) primitivesCount++; - } - } - TRACELOG(LOG_DEBUG, " > Primitives (triangles only) count based on hierarchy : %i", primitivesCount); - - // Load our model data: meshes and materials - model.meshCount = primitivesCount; - model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); - - // NOTE: We keep an extra slot for default material, in case some mesh requires it - model.materialCount = (int)data->materials_count + 1; - model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); - model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0) - - // Load mesh-material indices, by default all meshes are mapped to material index: 0 - model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); - - // Load materials data - //---------------------------------------------------------------------------------------------------- - for (unsigned int i = 0, j = 1; i < data->materials_count; i++, j++) - { - model.materials[j] = LoadMaterialDefault(); - const char *texPath = GetDirectoryPath(fileName); - - // Check glTF material flow: PBR metallic/roughness flow - // NOTE: Alternatively, materials can follow PBR specular/glossiness flow - if (data->materials[i].has_pbr_metallic_roughness) - { - // Load base color texture (albedo) - if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture) - { - Image imAlbedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath); - if (imAlbedo.data != NULL) - { - model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo); - UnloadImage(imAlbedo); - } - } - // Load base color factor (tint) - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255); - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255); - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255); - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255); - - // Load metallic/roughness texture - if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture) - { - Image imMetallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath); - if (imMetallicRoughness.data != NULL) - { - Image imMetallic = { 0 }; - Image imRoughness = { 0 }; - - imMetallic.data = RL_MALLOC(imMetallicRoughness.width*imMetallicRoughness.height); - imRoughness.data = RL_MALLOC(imMetallicRoughness.width*imMetallicRoughness.height); - - imMetallic.width = imRoughness.width = imMetallicRoughness.width; - imMetallic.height = imRoughness.height = imMetallicRoughness.height; - - imMetallic.format = imRoughness.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - imMetallic.mipmaps = imRoughness.mipmaps = 1; - - for (int x = 0; x < imRoughness.width; x++) - { - for (int y = 0; y < imRoughness.height; y++) - { - Color color = GetImageColor(imMetallicRoughness, x, y); - - ((unsigned char *)imRoughness.data)[y*imRoughness.width + x] = color.g; // Roughness color channel - ((unsigned char *)imMetallic.data)[y*imMetallic.width + x] = color.b; // Metallic color channel - } - } - - model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(imRoughness); - model.materials[j].maps[MATERIAL_MAP_METALNESS].texture = LoadTextureFromImage(imMetallic); - - UnloadImage(imRoughness); - UnloadImage(imMetallic); - UnloadImage(imMetallicRoughness); - } - - // Load metallic/roughness material properties - float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor; - model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].value = roughness; - - float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor; - model.materials[j].maps[MATERIAL_MAP_METALNESS].value = metallic; - } - - // Load normal texture - if (data->materials[i].normal_texture.texture) - { - Image imNormal = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath); - if (imNormal.data != NULL) - { - model.materials[j].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(imNormal); - UnloadImage(imNormal); - } - } - - // Load ambient occlusion texture - if (data->materials[i].occlusion_texture.texture) - { - Image imOcclusion = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath); - if (imOcclusion.data != NULL) - { - model.materials[j].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(imOcclusion); - UnloadImage(imOcclusion); - } - } - - // Load emissive texture - if (data->materials[i].emissive_texture.texture) - { - Image imEmissive = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath); - if (imEmissive.data != NULL) - { - model.materials[j].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(imEmissive); - UnloadImage(imEmissive); - } - - // Load emissive color factor - model.materials[j].maps[MATERIAL_MAP_EMISSION].color.r = (unsigned char)(data->materials[i].emissive_factor[0]*255); - model.materials[j].maps[MATERIAL_MAP_EMISSION].color.g = (unsigned char)(data->materials[i].emissive_factor[1]*255); - model.materials[j].maps[MATERIAL_MAP_EMISSION].color.b = (unsigned char)(data->materials[i].emissive_factor[2]*255); - model.materials[j].maps[MATERIAL_MAP_EMISSION].color.a = 255; - } - } - - // Other possible materials not supported by raylib pipeline: - // has_clearcoat, has_transmission, has_volume, has_ior, has specular, has_sheen - } - - // Visit each node in the hierarchy and process any mesh linked from it. - // Each primitive within a glTF node becomes a Raylib Mesh. - // The local-to-world transform of each node is used to transform the - // points/normals/tangents of the created Mesh(es). - // Any glTF mesh linked from more than one Node (i.e. instancing) - // is turned into multiple Mesh's, as each Node will have its own - // transform applied. - // NOTE: The code below disregards the scenes defined in the file, all nodes are used. - //---------------------------------------------------------------------------------------------------- - int meshIndex = 0; - for (unsigned int i = 0; i < data->nodes_count; i++) - { - cgltf_node *node = &(data->nodes[i]); - - cgltf_mesh *mesh = node->mesh; - if (!mesh) - continue; - - cgltf_float worldTransform[16]; - cgltf_node_transform_world(node, worldTransform); - - Matrix worldMatrix = { - worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12], - worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13], - worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14], - worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15] - }; - - Matrix worldMatrixNormals = MatrixTranspose(MatrixInvert(worldMatrix)); - - for (unsigned int p = 0; p < mesh->primitives_count; p++) - { - // NOTE: We only support primitives defined by triangles - // Other alternatives: points, lines, line_strip, triangle_strip - if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue; - - // NOTE: Attributes data could be provided in several data formats (8, 8u, 16u, 32...), - // Only some formats for each attribute type are supported, read info at the top of this function! - - for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++) - { - // Check the different attributes for every primitive - if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_position) // POSITION, vec3, float - { - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - // WARNING: SPECS: POSITION accessor MUST have its min and max properties defined - - if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f)) - { - // Init raylib mesh vertices to copy glTF attribute data - model.meshes[meshIndex].vertexCount = (int)attribute->count; - model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); - - // Load 3 components of float data type into mesh.vertices - LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices) - - // Transform the vertices - float *vertices = model.meshes[meshIndex].vertices; - for (unsigned int k = 0; k < attribute->count; k++) - { - Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k+1], vertices[3*k+2] }, worldMatrix); - vertices[3*k] = vt.x; - vertices[3*k+1] = vt.y; - vertices[3*k+2] = vt.z; - } - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName); - } - else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_normal) // NORMAL, vec3, float - { - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f)) - { - // Init raylib mesh normals to copy glTF attribute data - model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); - - // Load 3 components of float data type into mesh.normals - LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals) - - // Transform the normals - float *normals = model.meshes[meshIndex].normals; - for (unsigned int k = 0; k < attribute->count; k++) - { - Vector3 nt = Vector3Transform((Vector3){ normals[3*k], normals[3*k+1], normals[3*k+2] }, worldMatrixNormals); - normals[3*k] = nt.x; - normals[3*k+1] = nt.y; - normals[3*k+2] = nt.z; - } - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName); - } - else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec3, float - { - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f)) - { - // Init raylib mesh tangent to copy glTF attribute data - model.meshes[meshIndex].tangents = (float *)RL_MALLOC(attribute->count*4*sizeof(float)); - - // Load 4 components of float data type into mesh.tangents - LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents) - - // Transform the tangents - float *tangents = model.meshes[meshIndex].tangents; - for (unsigned int k = 0; k < attribute->count; k++) - { - Vector3 tt = Vector3Transform((Vector3){ tangents[3*k], tangents[3*k+1], tangents[3*k+2] }, worldMatrix); - tangents[3*k] = tt.x; - tangents[3*k+1] = tt.y; - tangents[3*k+2] = tt.z; - } - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName); - } - else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) // TEXCOORD_n, vec2, float/u8n/u16n - { - // Support up to 2 texture coordinates attributes - float *texcoordPtr = NULL; - - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - if (attribute->type == cgltf_type_vec2) - { - if (attribute->component_type == cgltf_component_type_r_32f) // vec2, float - { - // Init raylib mesh texcoords to copy glTF attribute data - texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float)); - - // Load 3 components of float data type into mesh.texcoords - LOAD_ATTRIBUTE(attribute, 2, float, texcoordPtr) - } - else if (attribute->component_type == cgltf_component_type_r_8u) // vec2, u8n - { - // Init raylib mesh texcoords to copy glTF attribute data - texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*2*sizeof(unsigned char)); - LOAD_ATTRIBUTE(attribute, 2, unsigned char, temp); - - // Convert data to raylib texcoord data type (float) - for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/255.0f; - - RL_FREE(temp); - } - else if (attribute->component_type == cgltf_component_type_r_16u) // vec2, u16n - { - // Init raylib mesh texcoords to copy glTF attribute data - texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*2*sizeof(unsigned short)); - LOAD_ATTRIBUTE(attribute, 2, unsigned short, temp); - - // Convert data to raylib texcoord data type (float) - for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/65535.0f; - - RL_FREE(temp); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported", fileName); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported, use vec2 float", fileName); - - int index = mesh->primitives[p].attributes[j].index; - if (index == 0) model.meshes[meshIndex].texcoords = texcoordPtr; - else if (index == 1) model.meshes[meshIndex].texcoords2 = texcoordPtr; - else - { - TRACELOG(LOG_WARNING, "MODEL: [%s] No more than 2 texture coordinates attributes supported", fileName); - if (texcoordPtr != NULL) RL_FREE(texcoordPtr); - } - } - else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_color) // COLOR_n, vec3/vec4, float/u8n/u16n - { - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - // WARNING: SPECS: All components of each COLOR_n accessor element MUST be clamped to [0.0, 1.0] range - - if (attribute->type == cgltf_type_vec3) // RGB - { - if (attribute->component_type == cgltf_component_type_r_8u) - { - // Init raylib mesh color to copy glTF attribute data - model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char)); - LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp); - - // Convert data to raylib color data type (4 bytes) - for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3) - { - model.meshes[meshIndex].colors[c] = temp[k]; - model.meshes[meshIndex].colors[c + 1] = temp[k + 1]; - model.meshes[meshIndex].colors[c + 2] = temp[k + 2]; - model.meshes[meshIndex].colors[c + 3] = 255; - } - - RL_FREE(temp); - } - else if (attribute->component_type == cgltf_component_type_r_16u) - { - // Init raylib mesh color to copy glTF attribute data - model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short)); - LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp); - - // Convert data to raylib color data type (4 bytes) - for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3) - { - model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[k]/65535.0f)*255.0f); - model.meshes[meshIndex].colors[c + 1] = (unsigned char)(((float)temp[k + 1]/65535.0f)*255.0f); - model.meshes[meshIndex].colors[c + 2] = (unsigned char)(((float)temp[k + 2]/65535.0f)*255.0f); - model.meshes[meshIndex].colors[c + 3] = 255; - } - - RL_FREE(temp); - } - else if (attribute->component_type == cgltf_component_type_r_32f) - { - // Init raylib mesh color to copy glTF attribute data - model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - - // Load data into a temp buffer to be converted to raylib data type - float *temp = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); - LOAD_ATTRIBUTE(attribute, 3, float, temp); - - // Convert data to raylib color data type (4 bytes) - for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3) - { - model.meshes[meshIndex].colors[c] = (unsigned char)(temp[k]*255.0f); - model.meshes[meshIndex].colors[c + 1] = (unsigned char)(temp[k + 1]*255.0f); - model.meshes[meshIndex].colors[c + 2] = (unsigned char)(temp[k + 2]*255.0f); - model.meshes[meshIndex].colors[c + 3] = 255; - } - - RL_FREE(temp); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName); - } - else if (attribute->type == cgltf_type_vec4) // RGBA - { - if (attribute->component_type == cgltf_component_type_r_8u) - { - // Init raylib mesh color to copy glTF attribute data - model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - - // Load 4 components of unsigned char data type into mesh.colors - LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors) - } - else if (attribute->component_type == cgltf_component_type_r_16u) - { - // Init raylib mesh color to copy glTF attribute data - model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short)); - LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp); - - // Convert data to raylib color data type (4 bytes) - for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f); - - RL_FREE(temp); - } - else if (attribute->component_type == cgltf_component_type_r_32f) - { - // Init raylib mesh color to copy glTF attribute data - model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - - // Load data into a temp buffer to be converted to raylib data type - float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float)); - LOAD_ATTRIBUTE(attribute, 4, float, temp); - - // Convert data to raylib color data type (4 bytes), we expect the color data normalized - for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f); - - RL_FREE(temp); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName); - } - - // NOTE: Attributes related to animations are processed separately - } - - // Load primitive indices data (if provided) - if ((mesh->primitives[p].indices != NULL) && (mesh->primitives[p].indices->buffer_view != NULL)) - { - cgltf_accessor *attribute = mesh->primitives[p].indices; - - model.meshes[meshIndex].triangleCount = (int)attribute->count/3; - - if (attribute->component_type == cgltf_component_type_r_16u) - { - // Init raylib mesh indices to copy glTF attribute data - model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short)); - - // Load unsigned short data type into mesh.indices - LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices) - } - else if (attribute->component_type == cgltf_component_type_r_8u) - { - // Init raylib mesh indices to copy glTF attribute data - model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short)); - LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short) - - } - else if (attribute->component_type == cgltf_component_type_r_32u) - { - // Init raylib mesh indices to copy glTF attribute data - model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short)); - LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short); - - TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName); - } - else - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName); - } - } - else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3; // Unindexed mesh - - // Assign to the primitive mesh the corresponding material index - // NOTE: If no material defined, mesh uses the already assigned default material (index: 0) - for (unsigned int m = 0; m < data->materials_count; m++) - { - // The primitive actually keeps the pointer to the corresponding material, - // raylib instead assigns to the mesh the by its index, as loaded in model.materials array - // To get the index, we check if material pointers match, and we assign the corresponding index, - // skipping index 0, the default material - if (&data->materials[m] == mesh->primitives[p].material) - { - model.meshMaterial[meshIndex] = m + 1; - break; - } - } - - meshIndex++; // Move to next mesh - } - } - - // Load glTF meshes animation data - // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins - // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes - // - // LIMITATIONS: - // - Only supports 1 armature per file, and skips loading it if there are multiple armatures - // - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file) - // - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets) - //---------------------------------------------------------------------------------------------------- - if (data->skins_count > 0) - { - cgltf_skin skin = data->skins[0]; - model.bones = LoadBoneInfoGLTF(skin, &model.boneCount); - model.bindPose = (Transform *)RL_MALLOC(model.boneCount*sizeof(Transform)); - - for (int i = 0; i < model.boneCount; i++) - { - cgltf_node *node = skin.joints[i]; - cgltf_float worldTransform[16]; - cgltf_node_transform_world(node, worldTransform); - Matrix worldMatrix = { - worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12], - worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13], - worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14], - worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15] - }; - MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale)); - } - } - if (data->skins_count > 1) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count); - } - - meshIndex = 0; - for (unsigned int i = 0; i < data->nodes_count; i++) - { - cgltf_node *node = &(data->nodes[i]); - - cgltf_mesh *mesh = node->mesh; - if (!mesh) - continue; - - for (unsigned int p = 0; p < mesh->primitives_count; p++) - { - bool hasJoints = false; - - // NOTE: We only support primitives defined by triangles - if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue; - - for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++) - { - // NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib - if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16) - { - hasJoints = true; - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - // NOTE: JOINTS_n can only be vec4 and u8/u16 - // SPECS: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview - - // WARNING: raylib only supports model.meshes[].boneIds as u8 (unsigned char), - // if data is provided in any other format, it is converted to supported format but - // it could imply data loss (a warning message is issued in that case) - - if (attribute->type == cgltf_type_vec4) - { - if (attribute->component_type == cgltf_component_type_r_8u) - { - // Init raylib mesh boneIds to copy glTF attribute data - model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char)); - - // Load attribute: vec4, u8 (unsigned char) - LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds) - } - else if (attribute->component_type == cgltf_component_type_r_16u) - { - // Init raylib mesh boneIds to copy glTF attribute data - model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned short *temp = (unsigned short *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short)); - LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp); - - // Convert data to raylib color data type (4 bytes) - bool boneIdOverflowWarning = false; - for (int b = 0; b < model.meshes[meshIndex].vertexCount*4; b++) - { - if ((temp[b] > 255) && !boneIdOverflowWarning) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format (u16) overflow", fileName); - boneIdOverflowWarning = true; - } - - // Despite the possible overflow, we convert data to unsigned char - model.meshes[meshIndex].boneIds[b] = (unsigned char)temp[b]; - } - - RL_FREE(temp); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName); - } - else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_weights) // WEIGHTS_n (vec4, u8n/u16n/f32) - { - cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; - - if (attribute->type == cgltf_type_vec4) - { - if (attribute->component_type == cgltf_component_type_r_8u) - { - // Init raylib mesh bone weight to copy glTF attribute data - model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char)); - LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp); - - // Convert data to raylib bone weight data type (4 bytes) - for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/255.0f; - - RL_FREE(temp); - } - else if (attribute->component_type == cgltf_component_type_r_16u) - { - // Init raylib mesh bone weight to copy glTF attribute data - model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short)); - LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp); - - // Convert data to raylib bone weight data type - for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/65535.0f; - - RL_FREE(temp); - } - else if (attribute->component_type == cgltf_component_type_r_32f) - { - // Init raylib mesh bone weight to copy glTF attribute data - model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float)); - - // Load 4 components of float data type into mesh.boneWeights - // for cgltf_attribute_type_weights we have: - - // - data.meshes[0] (256 vertices) - // - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16) - LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights) - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName); - } - } - - // Check if we are animated, and the mesh was not given any bone assignments, but is the child of a bone node - // in this case we need to fully attach all the verts to the parent bone so it will animate with the bone - if (data->skins_count > 0 && !hasJoints && node->parent != NULL && node->parent->mesh == NULL) - { - int parentBoneId = -1; - for (int joint = 0; joint < model.boneCount; joint++) - { - if (data->skins[0].joints[joint] == node->parent) - { - parentBoneId = joint; - break; - } - } - - if (parentBoneId >= 0) - { - model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char)); - model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float)); - - for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4) - { - model.meshes[meshIndex].boneIds[vertexIndex] = (unsigned char)parentBoneId; - model.meshes[meshIndex].boneWeights[vertexIndex] = 1.0f; - } - } - } - - // Animated vertex data - model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float)); - memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float)); - model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float)); - if (model.meshes[meshIndex].normals != NULL) - { - memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float)); - } - - // Bone Transform Matrices - model.meshes[meshIndex].boneCount = model.boneCount; - model.meshes[meshIndex].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix)); - - for (int j = 0; j < model.meshes[meshIndex].boneCount; j++) - { - model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity(); - } - - meshIndex++; // Move to next mesh - } - } - - // Free all cgltf loaded data - cgltf_free(data); - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName); - - // WARNING: cgltf requires the file pointer available while reading data - UnloadFileData(fileData); - - return model; -} - -// Get interpolated pose for bone sampler at a specific time. Returns true on success -static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_accessor *input, cgltf_accessor *output, float time, void *data) -{ - if (interpolationType >= cgltf_interpolation_type_max_enum) return false; - - // Input and output should have the same count - float tstart = 0.0f; - float tend = 0.0f; - int keyframe = 0; // Defaults to first pose - - for (int i = 0; i < (int)input->count - 1; i++) - { - cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1); - if (!r1) return false; - - cgltf_bool r2 = cgltf_accessor_read_float(input, i + 1, &tend, 1); - if (!r2) return false; - - if ((tstart <= time) && (time < tend)) - { - keyframe = i; - break; - } - } - - // Constant animation, no need to interpolate - if (FloatEquals(tend, tstart)) return true; - - float duration = fmaxf((tend - tstart), EPSILON); - float t = (time - tstart)/duration; - t = (t < 0.0f)? 0.0f : t; - t = (t > 1.0f)? 1.0f : t; - - if (output->component_type != cgltf_component_type_r_32f) return false; - - if (output->type == cgltf_type_vec3) - { - switch (interpolationType) - { - case cgltf_interpolation_type_step: - { - float tmp[3] = { 0.0f }; - cgltf_accessor_read_float(output, keyframe, tmp, 3); - Vector3 v1 = {tmp[0], tmp[1], tmp[2]}; - Vector3 *r = data; - - *r = v1; - } break; - case cgltf_interpolation_type_linear: - { - float tmp[3] = { 0.0f }; - cgltf_accessor_read_float(output, keyframe, tmp, 3); - Vector3 v1 = {tmp[0], tmp[1], tmp[2]}; - cgltf_accessor_read_float(output, keyframe+1, tmp, 3); - Vector3 v2 = {tmp[0], tmp[1], tmp[2]}; - Vector3 *r = data; - - *r = Vector3Lerp(v1, v2, t); - } break; - case cgltf_interpolation_type_cubic_spline: - { - float tmp[3] = { 0.0f }; - cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 3); - Vector3 v1 = {tmp[0], tmp[1], tmp[2]}; - cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 3); - Vector3 tangent1 = {tmp[0], tmp[1], tmp[2]}; - cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 3); - Vector3 v2 = {tmp[0], tmp[1], tmp[2]}; - cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 3); - Vector3 tangent2 = {tmp[0], tmp[1], tmp[2]}; - Vector3 *r = data; - - *r = Vector3CubicHermite(v1, tangent1, v2, tangent2, t); - } break; - default: break; - } - } - else if (output->type == cgltf_type_vec4) - { - // Only v4 is for rotations, so we know it's a quaternion - switch (interpolationType) - { - case cgltf_interpolation_type_step: - { - float tmp[4] = { 0.0f }; - cgltf_accessor_read_float(output, keyframe, tmp, 4); - Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - Vector4 *r = data; - - *r = v1; - } break; - case cgltf_interpolation_type_linear: - { - float tmp[4] = { 0.0f }; - cgltf_accessor_read_float(output, keyframe, tmp, 4); - Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - cgltf_accessor_read_float(output, keyframe+1, tmp, 4); - Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - Vector4 *r = data; - - *r = QuaternionSlerp(v1, v2, t); - } break; - case cgltf_interpolation_type_cubic_spline: - { - float tmp[4] = { 0.0f }; - cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 4); - Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 4); - Vector4 outTangent1 = {tmp[0], tmp[1], tmp[2], 0.0f}; - cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 4); - Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 4); - Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2], 0.0f}; - Vector4 *r = data; - - v1 = QuaternionNormalize(v1); - v2 = QuaternionNormalize(v2); - - if (Vector4DotProduct(v1, v2) < 0.0f) - { - v2 = Vector4Negate(v2); - } - - outTangent1 = Vector4Scale(outTangent1, duration); - inTangent2 = Vector4Scale(inTangent2, duration); - - *r = QuaternionCubicHermiteSpline(v1, outTangent1, v2, inTangent2, t); - } break; - default: break; - } - } - - return true; -} - -#define GLTF_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms) - -static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount) -{ - // glTF file loading - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - - ModelAnimation *animations = NULL; - - // glTF data loading - cgltf_options options = { 0 }; - options.file.read = LoadFileGLTFCallback; - options.file.release = ReleaseFileGLTFCallback; - cgltf_data *data = NULL; - cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); - - if (result != cgltf_result_success) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName); - *animCount = 0; - return NULL; - } - - result = cgltf_load_buffers(&options, data, fileName); - if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load animation buffers", fileName); - - if (result == cgltf_result_success) - { - if (data->skins_count > 0) - { - cgltf_skin skin = data->skins[0]; - *animCount = (int)data->animations_count; - animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation)); - - for (unsigned int i = 0; i < data->animations_count; i++) - { - animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount); - - cgltf_animation animData = data->animations[i]; - - struct Channels { - cgltf_animation_channel *translate; - cgltf_animation_channel *rotate; - cgltf_animation_channel *scale; - cgltf_interpolation_type interpolationType; - }; - - struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[i].boneCount, sizeof(struct Channels)); - float animDuration = 0.0f; - - for (unsigned int j = 0; j < animData.channels_count; j++) - { - cgltf_animation_channel channel = animData.channels[j]; - int boneIndex = -1; - - for (unsigned int k = 0; k < skin.joints_count; k++) - { - if (animData.channels[j].target_node == skin.joints[k]) - { - boneIndex = k; - break; - } - } - - if (boneIndex == -1) - { - // Animation channel for a node not in the armature - continue; - } - - boneChannels[boneIndex].interpolationType = animData.channels[j].sampler->interpolation; - - if (animData.channels[j].sampler->interpolation != cgltf_interpolation_type_max_enum) - { - if (channel.target_path == cgltf_animation_path_type_translation) - { - boneChannels[boneIndex].translate = &animData.channels[j]; - } - else if (channel.target_path == cgltf_animation_path_type_rotation) - { - boneChannels[boneIndex].rotate = &animData.channels[j]; - } - else if (channel.target_path == cgltf_animation_path_type_scale) - { - boneChannels[boneIndex].scale = &animData.channels[j]; - } - else - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i); - } - } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Invalid interpolation curve encountered for GLTF animation.", fileName); - - float t = 0.0f; - cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1); - - if (!r) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName); - continue; - } - - animDuration = (t > animDuration)? t : animDuration; - } - - if (animData.name != NULL) strncpy(animations[i].name, animData.name, sizeof(animations[i].name) - 1); - - animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1; - animations[i].framePoses = (Transform **)RL_MALLOC(animations[i].frameCount*sizeof(Transform *)); - - for (int j = 0; j < animations[i].frameCount; j++) - { - animations[i].framePoses[j] = (Transform *)RL_MALLOC(animations[i].boneCount*sizeof(Transform)); - float time = ((float) j*GLTF_ANIMDELAY)/1000.0f; - - for (int k = 0; k < animations[i].boneCount; k++) - { - Vector3 translation = {skin.joints[k]->translation[0], skin.joints[k]->translation[1], skin.joints[k]->translation[2]}; - Quaternion rotation = {skin.joints[k]->rotation[0], skin.joints[k]->rotation[1], skin.joints[k]->rotation[2], skin.joints[k]->rotation[3]}; - Vector3 scale = {skin.joints[k]->scale[0], skin.joints[k]->scale[1], skin.joints[k]->scale[2]}; - - if (boneChannels[k].translate) - { - if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation)) - { - TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, animations[i].bones[k].name); - } - } - - if (boneChannels[k].rotate) - { - if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation)) - { - TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, animations[i].bones[k].name); - } - } - - if (boneChannels[k].scale) - { - if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale)) - { - TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, animations[i].bones[k].name); - } - } - - animations[i].framePoses[j][k] = (Transform){ - .translation = translation, - .rotation = rotation, - .scale = scale - }; - } - - BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]); - } - - TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s (%d frames, %fs)", fileName, (animData.name != NULL)? animData.name : "NULL", animations[i].frameCount, animDuration); - RL_FREE(boneChannels); - } - } - - if (data->skins_count > 1) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); - } - - cgltf_free(data); - } - UnloadFileData(fileData); - return animations; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_VOX) -// Load VOX (MagicaVoxel) mesh data -static Model LoadVOX(const char *fileName) -{ - Model model = { 0 }; - - int nbvertices = 0; - int meshescount = 0; - - // Read vox file into buffer - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - - if (fileData == 0) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName); - return model; - } - - // Read and build voxarray description - VoxArray3D voxarray = { 0 }; - int ret = Vox_LoadFromMemory(fileData, dataSize, &voxarray); - - if (ret != VOX_SUCCESS) - { - // Error - UnloadFileData(fileData); - - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName); - return model; - } - else - { - // Success: Compute meshes count - nbvertices = voxarray.vertices.used; - meshescount = 1 + (nbvertices/65536); - - TRACELOG(LOG_INFO, "MODEL: [%s] VOX data loaded successfully : %i vertices/%i meshes", fileName, nbvertices, meshescount); - } - - // Build models from meshes - model.transform = MatrixIdentity(); - - model.meshCount = meshescount; - model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); - - model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); - - model.materialCount = 1; - model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); - model.materials[0] = LoadMaterialDefault(); - - // Init model meshes - int verticesRemain = voxarray.vertices.used; - int verticesMax = 65532; // 5461 voxels x 12 vertices per voxel -> 65532 (must be inf 65536) - - // 6*4 = 12 vertices per voxel - Vector3 *pvertices = (Vector3 *)voxarray.vertices.array; - Vector3 *pnormals = (Vector3 *)voxarray.normals.array; - Color *pcolors = (Color *)voxarray.colors.array; - - unsigned short *pindices = voxarray.indices.array; // 5461*6*6 = 196596 indices max per mesh - - int size = 0; - - for (int i = 0; i < meshescount; i++) - { - Mesh *pmesh = &model.meshes[i]; - memset(pmesh, 0, sizeof(Mesh)); - - // Copy vertices - pmesh->vertexCount = (int)fmin(verticesMax, verticesRemain); - - size = pmesh->vertexCount*sizeof(float)*3; - pmesh->vertices = (float *)RL_MALLOC(size); - memcpy(pmesh->vertices, pvertices, size); - - // Copy normals - pmesh->normals = (float *)RL_MALLOC(size); - memcpy(pmesh->normals, pnormals, size); - - // Copy indices - size = voxarray.indices.used*sizeof(unsigned short); - pmesh->indices = (unsigned short *)RL_MALLOC(size); - memcpy(pmesh->indices, pindices, size); - - pmesh->triangleCount = (pmesh->vertexCount/4)*2; - - // Copy colors - size = pmesh->vertexCount*sizeof(Color); - pmesh->colors = (unsigned char *)RL_MALLOC(size); - memcpy(pmesh->colors, pcolors, size); - - // First material index - model.meshMaterial[i] = 0; - - verticesRemain -= verticesMax; - pvertices += verticesMax; - pnormals += verticesMax; - pcolors += verticesMax; - } - - // Free buffers - Vox_FreeArrays(&voxarray); - UnloadFileData(fileData); - - return model; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_M3D) -// Hook LoadFileData()/UnloadFileData() calls to M3D loaders -unsigned char *m3d_loaderhook(char *fn, unsigned int *len) { return LoadFileData((const char *)fn, (int *)len); } -void m3d_freehook(void *data) { UnloadFileData((unsigned char *)data); } - -// Load M3D mesh data -static Model LoadM3D(const char *fileName) -{ - Model model = { 0 }; - - m3d_t *m3d = NULL; - m3dp_t *prop = NULL; - int i, j, k, l, n, mi = -2, vcolor = 0; - - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - - if (fileData != NULL) - { - m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL); - - if (!m3d || M3D_ERR_ISFATAL(m3d->errcode)) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2); - if (m3d) m3d_free(m3d); - UnloadFileData(fileData); - return model; - } - else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial); - - // no face? this is probably just a material library - if (!m3d->numface) - { - m3d_free(m3d); - UnloadFileData(fileData); - return model; - } - - if (m3d->nummaterial > 0) - { - model.meshCount = model.materialCount = m3d->nummaterial; - TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", model.materialCount); - } - else - { - model.meshCount = 1; model.materialCount = 0; - TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material"); - } - - // We always need a default material, so we add +1 - model.materialCount++; - - // Faces must be in non-decreasing materialid order. Verify that quickly, sorting them otherwise - // WARNING: Sorting is not needed, valid M3D model files should already be sorted - // Just keeping the sorting function for reference (Check PR #3363 #3385) - /* - for (i = 1; i < m3d->numface; i++) - { - if (m3d->face[i-1].materialid <= m3d->face[i].materialid) continue; - - // face[i-1] > face[i]. slide face[i] lower - m3df_t slider = m3d->face[i]; - j = i-1; - - do - { // face[j] > slider, face[j+1] is svailable vacant gap - m3d->face[j+1] = m3d->face[j]; - j = j-1; - } - while (j >= 0 && m3d->face[j].materialid > slider.materialid); - - m3d->face[j+1] = slider; - } - */ - - model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); - model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); - model.materials = (Material *)RL_CALLOC(model.materialCount + 1, sizeof(Material)); - - // Map no material to index 0 with default shader, everything else materialid + 1 - model.materials[0] = LoadMaterialDefault(); - - for (i = l = 0, k = -1; i < (int)m3d->numface; i++, l++) - { - // Materials are grouped together - if (mi != m3d->face[i].materialid) - { - // there should be only one material switch per material kind, but be bulletproof for non-optimal model files - if (k + 1 >= model.meshCount) - { - model.meshCount++; - model.meshes = (Mesh *)RL_REALLOC(model.meshes, model.meshCount*sizeof(Mesh)); - memset(&model.meshes[model.meshCount - 1], 0, sizeof(Mesh)); - model.meshMaterial = (int *)RL_REALLOC(model.meshMaterial, model.meshCount*sizeof(int)); - } - - k++; - mi = m3d->face[i].materialid; - - // Only allocate colors VertexBuffer if there's a color vertex in the model for this material batch - // if all colors are fully transparent black for all verteces of this materal, then we assume no vertex colors - for (j = i, l = vcolor = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++) - { - if (!m3d->vertex[m3d->face[j].vertex[0]].color || - !m3d->vertex[m3d->face[j].vertex[1]].color || - !m3d->vertex[m3d->face[j].vertex[2]].color) vcolor = 1; - } - - model.meshes[k].vertexCount = l*3; - model.meshes[k].triangleCount = l; - model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); - model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - - // If no map is provided, or we have colors defined, we allocate storage for vertex colors - // M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors - if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); - - // If no map is provided and we allocated vertex colors, set them to white - if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL)) - { - for (int c = 0; c < model.meshes[k].vertexCount*4; c++) model.meshes[k].colors[c] = 255; - } - - if (m3d->numbone && m3d->numskin) - { - model.meshes[k].boneIds = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); - model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float)); - model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - } - - model.meshMaterial[k] = mi + 1; - l = 0; - } - - // Process meshes per material, add triangles - model.meshes[k].vertices[l*9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale; - model.meshes[k].vertices[l*9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale; - model.meshes[k].vertices[l*9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale; - model.meshes[k].vertices[l*9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale; - model.meshes[k].vertices[l*9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale; - model.meshes[k].vertices[l*9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale; - model.meshes[k].vertices[l*9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale; - model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale; - model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale; - - // Without vertex color (full transparency), we use the default color - if (model.meshes[k].colors != NULL) - { - if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000) - memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4); - if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xff000000) - memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4); - if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xff000000) - memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4); - } - - if (m3d->face[i].texcoord[0] != M3D_UNDEF) - { - model.meshes[k].texcoords[l*6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u; - model.meshes[k].texcoords[l*6 + 1] = 1.0f - m3d->tmap[m3d->face[i].texcoord[0]].v; - model.meshes[k].texcoords[l*6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u; - model.meshes[k].texcoords[l*6 + 3] = 1.0f - m3d->tmap[m3d->face[i].texcoord[1]].v; - model.meshes[k].texcoords[l*6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u; - model.meshes[k].texcoords[l*6 + 5] = 1.0f - m3d->tmap[m3d->face[i].texcoord[2]].v; - } - - if (m3d->face[i].normal[0] != M3D_UNDEF) - { - model.meshes[k].normals[l*9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x; - model.meshes[k].normals[l*9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y; - model.meshes[k].normals[l*9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z; - model.meshes[k].normals[l*9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x; - model.meshes[k].normals[l*9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y; - model.meshes[k].normals[l*9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z; - model.meshes[k].normals[l*9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x; - model.meshes[k].normals[l*9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y; - model.meshes[k].normals[l*9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z; - } - - // Add skin (vertex / bone weight pairs) - if (m3d->numbone && m3d->numskin) - { - for (n = 0; n < 3; n++) - { - int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid; - - // Check if there is a skin for this mesh, should be, just failsafe - if ((skinid != M3D_UNDEF) && (skinid < (int)m3d->numskin)) - { - for (j = 0; j < 4; j++) - { - model.meshes[k].boneIds[l*12 + n*4 + j] = m3d->skin[skinid].boneid[j]; - model.meshes[k].boneWeights[l*12 + n*4 + j] = m3d->skin[skinid].weight[j]; - } - } - else - { - // raylib does not handle boneless meshes with skeletal animations, so - // we put all vertices without a bone into a special "no bone" bone - model.meshes[k].boneIds[l*12 + n*4] = m3d->numbone; - model.meshes[k].boneWeights[l*12 + n*4] = 1.0f; - } - } - } - } - - // Load materials - for (i = 0; i < (int)m3d->nummaterial; i++) - { - model.materials[i + 1] = LoadMaterialDefault(); - - for (j = 0; j < m3d->material[i].numprop; j++) - { - prop = &m3d->material[i].prop[j]; - - switch (prop->type) - { - case m3dp_Kd: - { - memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].color, &prop->value.color, 4); - model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; - } break; - case m3dp_Ks: - { - memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].color, &prop->value.color, 4); - } break; - case m3dp_Ns: - { - model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].value = prop->value.fnum; - } break; - case m3dp_Ke: - { - memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].color, &prop->value.color, 4); - model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].value = 0.0f; - } break; - case m3dp_Pm: - { - model.materials[i + 1].maps[MATERIAL_MAP_METALNESS].value = prop->value.fnum; - } break; - case m3dp_Pr: - { - model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].value = prop->value.fnum; - } break; - case m3dp_Ps: - { - model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].color = WHITE; - model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].value = prop->value.fnum; - } break; - default: - { - if (prop->type >= 128) - { - Image image = { 0 }; - image.data = m3d->texture[prop->value.textureid].d; - image.width = m3d->texture[prop->value.textureid].w; - image.height = m3d->texture[prop->value.textureid].h; - image.mipmaps = 1; - image.format = (m3d->texture[prop->value.textureid].f == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : - ((m3d->texture[prop->value.textureid].f == 3)? PIXELFORMAT_UNCOMPRESSED_R8G8B8 : - ((m3d->texture[prop->value.textureid].f == 2)? PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)); - - switch (prop->type) - { - case m3dp_map_Kd: model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTextureFromImage(image); break; - case m3dp_map_Ks: model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].texture = LoadTextureFromImage(image); break; - case m3dp_map_Ke: model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(image); break; - case m3dp_map_Km: model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(image); break; - case m3dp_map_Ka: model.materials[i + 1].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(image); break; - case m3dp_map_Pm: model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(image); break; - default: break; - } - } - } break; - } - } - } - - // Load bones - if (m3d->numbone) - { - model.boneCount = m3d->numbone + 1; - model.bones = (BoneInfo *)RL_CALLOC(model.boneCount, sizeof(BoneInfo)); - model.bindPose = (Transform *)RL_CALLOC(model.boneCount, sizeof(Transform)); - - for (i = 0; i < (int)m3d->numbone; i++) - { - model.bones[i].parent = m3d->bone[i].parent; - strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name) - 1); - model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale; - model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale; - model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale; - model.bindPose[i].rotation.x = m3d->vertex[m3d->bone[i].ori].x; - model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y; - model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z; - model.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w; - - // TODO: If the orientation quaternion is not normalized, then that's encoding scaling - model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation); - model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f; - - // Child bones are stored in parent bone relative space, convert that into model space - if (model.bones[i].parent >= 0) - { - model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation); - model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation); - model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation); - model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale); - } - } - - // Add a special "no bone" bone - model.bones[i].parent = -1; - strcpy(model.bones[i].name, "NO BONE"); - model.bindPose[i].translation.x = 0.0f; - model.bindPose[i].translation.y = 0.0f; - model.bindPose[i].translation.z = 0.0f; - model.bindPose[i].rotation.x = 0.0f; - model.bindPose[i].rotation.y = 0.0f; - model.bindPose[i].rotation.z = 0.0f; - model.bindPose[i].rotation.w = 1.0f; - model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f; - } - - // Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets - // called, but not before, however DrawMesh uses these if they exist (so not good if they are left empty) - if (m3d->numbone && m3d->numskin) - { - for (i = 0; i < model.meshCount; i++) - { - memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float)); - memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float)); - - model.meshes[i].boneCount = model.boneCount; - model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix)); - for (j = 0; j < model.meshes[i].boneCount; j++) - { - model.meshes[i].boneMatrices[j] = MatrixIdentity(); - } - } - } - - m3d_free(m3d); - UnloadFileData(fileData); - } - - return model; -} - -#define M3D_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms) - -// Load M3D animation data -static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount) -{ - ModelAnimation *animations = NULL; - - m3d_t *m3d = NULL; - int i = 0, j = 0; - *animCount = 0; - - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - - if (fileData != NULL) - { - m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL); - - if (!m3d || M3D_ERR_ISFATAL(m3d->errcode)) - { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2); - UnloadFileData(fileData); - return NULL; - } - else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName, - m3d->numaction, m3d->numbone, m3d->numskin); - - // No animation or bone+skin? - if (!m3d->numaction || !m3d->numbone || !m3d->numskin) - { - m3d_free(m3d); - UnloadFileData(fileData); - return NULL; - } - - animations = (ModelAnimation *)RL_CALLOC(m3d->numaction, sizeof(ModelAnimation)); - *animCount = m3d->numaction; - - for (unsigned int a = 0; a < m3d->numaction; a++) - { - animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY; - animations[a].boneCount = m3d->numbone + 1; - animations[a].bones = (BoneInfo *)RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo)); - animations[a].framePoses = (Transform **)RL_MALLOC(animations[a].frameCount*sizeof(Transform *)); - strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1); - - TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount); - - for (i = 0; i < (int)m3d->numbone; i++) - { - animations[a].bones[i].parent = m3d->bone[i].parent; - strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name) - 1); - } - - // A special, never transformed "no bone" bone, used for boneless vertices - animations[a].bones[i].parent = -1; - strcpy(animations[a].bones[i].name, "NO BONE"); - - // M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at - // regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones - for (i = 0; i < animations[a].frameCount; i++) - { - animations[a].framePoses[i] = (Transform *)RL_MALLOC((m3d->numbone + 1)*sizeof(Transform)); - - m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY); - - if (pose != NULL) - { - for (j = 0; j < (int)m3d->numbone; j++) - { - animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x*m3d->scale; - animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y*m3d->scale; - animations[a].framePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z*m3d->scale; - animations[a].framePoses[i][j].rotation.x = m3d->vertex[pose[j].ori].x; - animations[a].framePoses[i][j].rotation.y = m3d->vertex[pose[j].ori].y; - animations[a].framePoses[i][j].rotation.z = m3d->vertex[pose[j].ori].z; - animations[a].framePoses[i][j].rotation.w = m3d->vertex[pose[j].ori].w; - animations[a].framePoses[i][j].rotation = QuaternionNormalize(animations[a].framePoses[i][j].rotation); - animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f; - - // Child bones are stored in parent bone relative space, convert that into model space - if (animations[a].bones[j].parent >= 0) - { - animations[a].framePoses[i][j].rotation = QuaternionMultiply(animations[a].framePoses[i][animations[a].bones[j].parent].rotation, animations[a].framePoses[i][j].rotation); - animations[a].framePoses[i][j].translation = Vector3RotateByQuaternion(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].rotation); - animations[a].framePoses[i][j].translation = Vector3Add(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].translation); - animations[a].framePoses[i][j].scale = Vector3Multiply(animations[a].framePoses[i][j].scale, animations[a].framePoses[i][animations[a].bones[j].parent].scale); - } - } - - // Default transform for the "no bone" bone - animations[a].framePoses[i][j].translation.x = 0.0f; - animations[a].framePoses[i][j].translation.y = 0.0f; - animations[a].framePoses[i][j].translation.z = 0.0f; - animations[a].framePoses[i][j].rotation.x = 0.0f; - animations[a].framePoses[i][j].rotation.y = 0.0f; - animations[a].framePoses[i][j].rotation.z = 0.0f; - animations[a].framePoses[i][j].rotation.w = 1.0f; - animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f; - RL_FREE(pose); - } - } - } - - m3d_free(m3d); - UnloadFileData(fileData); - } - - return animations; -} -#endif - -#endif // SUPPORT_MODULE_RMODELS diff --git a/raylib/rshapes.c b/raylib/rshapes.c deleted file mode 100644 index be28e6c..0000000 --- a/raylib/rshapes.c +++ /dev/null @@ -1,2442 +0,0 @@ -/********************************************************************************************** -* -* rshapes - Basic functions to draw 2d shapes and check collisions -* -* ADDITIONAL NOTES: -* Shapes can be draw using 3 types of primitives: LINES, TRIANGLES and QUADS. -* Some functions implement two drawing options: TRIANGLES and QUADS, by default TRIANGLES -* are used but QUADS implementation can be selected with SUPPORT_QUADS_DRAW_MODE define -* -* Some functions define texture coordinates (rlTexCoord2f()) for the shapes and use a -* user-provided texture with SetShapesTexture(), the pourpouse of this implementation -* is allowing to reduce draw calls when combined with a texture-atlas. -* -* By default, raylib sets the default texture and rectangle at InitWindow()[rcore] to one -* white character of default font [rtext], this way, raylib text and shapes can be draw with -* a single draw call and it also allows users to configure it the same way with their own fonts. -* -* CONFIGURATION: -* #define SUPPORT_MODULE_RSHAPES -* rshapes module is included in the build -* -* #define SUPPORT_QUADS_DRAW_MODE -* Use QUADS instead of TRIANGLES for drawing when possible. Lines-based shapes still use LINES -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#include "raylib.h" // Declares module functions - -// Check if config flags have been externally provided on compilation line -#if !defined(EXTERNAL_CONFIG_FLAGS) - #include "config.h" // Defines module configuration flags -#endif - -#if defined(SUPPORT_MODULE_RSHAPES) - -#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 - -#include // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf() -#include // Required for: FLT_EPSILON -#include // Required for: RL_FREE - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// Error rate to calculate how many segments we need to draw a smooth circle, -// taken from https://stackoverflow.com/a/2244088 -#ifndef SMOOTH_CIRCLE_ERROR_RATE - #define SMOOTH_CIRCLE_ERROR_RATE 0.5f // Circle error rate -#endif -#ifndef SPLINE_SEGMENT_DIVISIONS - #define SPLINE_SEGMENT_DIVISIONS 24 // Spline segment divisions -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// Not here... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (white pixel loaded by rlgl) -static Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f }; // Texture source rectangle used on shapes drawing - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Set texture and rectangle to be used on shapes drawing -// NOTE: It can be useful when using basic shapes and one single font, -// defining a font char white rectangle would allow drawing everything in a single draw call -void SetShapesTexture(Texture2D texture, Rectangle source) -{ - // Reset texture to default pixel if required - // WARNING: Shapes texture should be probably better validated, - // it can break the rendering of all shapes if misused - if ((texture.id == 0) || (source.width == 0) || (source.height == 0)) - { - texShapes = (Texture2D){ 1, 1, 1, 1, 7 }; - texShapesRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }; - } - else - { - texShapes = texture; - texShapesRec = source; - } -} - -// Get texture that is used for shapes drawing -Texture2D GetShapesTexture(void) -{ - return texShapes; -} - -// Get texture source rectangle that is used for shapes drawing -Rectangle GetShapesTextureRectangle(void) -{ - return texShapesRec; -} - -// Draw a pixel -void DrawPixel(int posX, int posY, Color color) -{ - DrawPixelV((Vector2){ (float)posX, (float)posY }, color); -} - -// Draw a pixel (Vector version) -void DrawPixelV(Vector2 position, Color color) -{ -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - - rlNormal3f(0.0f, 0.0f, 1.0f); - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(position.x, position.y); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(position.x, position.y + 1); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(position.x + 1, position.y + 1); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(position.x + 1, position.y); - - rlEnd(); - - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(position.x, position.y); - rlVertex2f(position.x, position.y + 1); - rlVertex2f(position.x + 1, position.y); - - rlVertex2f(position.x + 1, position.y); - rlVertex2f(position.x, position.y + 1); - rlVertex2f(position.x + 1, position.y + 1); - - rlEnd(); -#endif -} - -// Draw a line (using gl lines) -void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color) -{ - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f((float)startPosX, (float)startPosY); - rlVertex2f((float)endPosX, (float)endPosY); - rlEnd(); -} - -// Draw a line (using gl lines) -void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) -{ - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(startPos.x, startPos.y); - rlVertex2f(endPos.x, endPos.y); - rlEnd(); -} - -// Draw lines sequuence (using gl lines) -void DrawLineStrip(const Vector2 *points, int pointCount, Color color) -{ - if (pointCount < 2) return; // Security check - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 0; i < pointCount - 1; i++) - { - rlVertex2f(points[i].x, points[i].y); - rlVertex2f(points[i + 1].x, points[i + 1].y); - } - rlEnd(); -} - -// Draw line using cubic-bezier spline, in-out interpolation, no control points -void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) -{ - Vector2 previous = startPos; - Vector2 current = { 0 }; - - Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++) - { - // Cubic easing in-out - // NOTE: Easing is calculated only for y position value - current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)SPLINE_SEGMENT_DIVISIONS); - current.x = previous.x + (endPos.x - startPos.x)/(float)SPLINE_SEGMENT_DIVISIONS; - - float dy = current.y - previous.y; - float dx = current.x - previous.x; - float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); - - if (i == 1) - { - points[0].x = previous.x + dy*size; - points[0].y = previous.y - dx*size; - points[1].x = previous.x - dy*size; - points[1].y = previous.y + dx*size; - } - - points[2*i + 1].x = current.x - dy*size; - points[2*i + 1].y = current.y + dx*size; - points[2*i].x = current.x + dy*size; - points[2*i].y = current.y - dx*size; - - previous = current; - } - - DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); -} - -// Draw a line defining thickness -void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) -{ - Vector2 delta = { endPos.x - startPos.x, endPos.y - startPos.y }; - float length = sqrtf(delta.x*delta.x + delta.y*delta.y); - - if ((length > 0) && (thick > 0)) - { - float scale = thick/(2*length); - - Vector2 radius = { -scale*delta.y, scale*delta.x }; - Vector2 strip[4] = { - { startPos.x - radius.x, startPos.y - radius.y }, - { startPos.x + radius.x, startPos.y + radius.y }, - { endPos.x - radius.x, endPos.y - radius.y }, - { endPos.x + radius.x, endPos.y + radius.y } - }; - - DrawTriangleStrip(strip, 4, color); - } -} - -// Draw a color-filled circle -void DrawCircle(int centerX, int centerY, float radius, Color color) -{ - DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color); -} - -// Draw a color-filled circle (Vector version) -// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues -void DrawCircleV(Vector2 center, float radius, Color color) -{ - DrawCircleSector(center, radius, 0, 360, 36, color); -} - -// Draw a piece of a circle -void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color) -{ - if (startAngle == endAngle) return; - if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero - - // Function expects (endAngle > startAngle) - if (endAngle < startAngle) - { - // Swap values - float tmp = startAngle; - startAngle = endAngle; - endAngle = tmp; - } - - int minSegments = (int)ceilf((endAngle - startAngle)/90); - - if (segments < minSegments) - { - // Calculate the maximum angle between segments based on the error rate (usually 0.5f) - float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); - segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); - - if (segments <= 0) segments = minSegments; - } - - float stepLength = (endAngle - startAngle)/(float)segments; - float angle = startAngle; - -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - - // NOTE: Every QUAD actually represents two segments - for (int i = 0; i < segments/2; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2.0f))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2.0f))*radius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - - angle += (stepLength*2.0f); - } - - // NOTE: In case number of segments is odd, we add one last piece to the cake - if ((((unsigned int)segments)%2) == 1) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - } - - rlEnd(); - - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - - angle += stepLength; - } - rlEnd(); -#endif -} - -// Draw a piece of a circle outlines -void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color) -{ - if (startAngle == endAngle) return; - if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero issue - - // Function expects (endAngle > startAngle) - if (endAngle < startAngle) - { - // Swap values - float tmp = startAngle; - startAngle = endAngle; - endAngle = tmp; - } - - int minSegments = (int)ceilf((endAngle - startAngle)/90); - - if (segments < minSegments) - { - // Calculate the maximum angle between segments based on the error rate (usually 0.5f) - float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); - segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); - - if (segments <= 0) segments = minSegments; - } - - float stepLength = (endAngle - startAngle)/(float)segments; - float angle = startAngle; - bool showCapLines = true; - - rlBegin(RL_LINES); - if (showCapLines) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - } - - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - - angle += stepLength; - } - - if (showCapLines) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - } - rlEnd(); -} - -// Draw a gradient-filled circle -void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer) -{ - rlBegin(RL_TRIANGLES); - for (int i = 0; i < 360; i += 10) - { - rlColor4ub(inner.r, inner.g, inner.b, inner.a); - rlVertex2f((float)centerX, (float)centerY); - rlColor4ub(outer.r, outer.g, outer.b, outer.a); - rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radius, (float)centerY + sinf(DEG2RAD*(i + 10))*radius); - rlColor4ub(outer.r, outer.g, outer.b, outer.a); - rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radius, (float)centerY + sinf(DEG2RAD*i)*radius); - } - rlEnd(); -} - -// Draw circle outline -void DrawCircleLines(int centerX, int centerY, float radius, Color color) -{ - DrawCircleLinesV((Vector2){ (float)centerX, (float)centerY }, radius, color); -} - -// Draw circle outline (Vector version) -void DrawCircleLinesV(Vector2 center, float radius, Color color) -{ - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) - for (int i = 0; i < 360; i += 10) - { - rlVertex2f(center.x + cosf(DEG2RAD*i)*radius, center.y + sinf(DEG2RAD*i)*radius); - rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radius, center.y + sinf(DEG2RAD*(i + 10))*radius); - } - rlEnd(); -} - -// Draw ellipse -void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color) -{ - DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color); -} - -// Draw ellipse (Vector version) -void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color) -{ - rlBegin(RL_TRIANGLES); - for (int i = 0; i < 360; i += 10) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV); - rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV); - } - rlEnd(); -} - -// Draw ellipse outline -void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color) -{ - DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color); -} - -// Draw ellipse outline -void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color) -{ - rlBegin(RL_LINES); - for (int i = 0; i < 360; i += 10) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV); - rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV); - } - rlEnd(); -} - -// Draw ring -void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color) -{ - if (startAngle == endAngle) return; - - // Function expects (outerRadius > innerRadius) - if (outerRadius < innerRadius) - { - float tmp = outerRadius; - outerRadius = innerRadius; - innerRadius = tmp; - - if (outerRadius <= 0.0f) outerRadius = 0.1f; - } - - // Function expects (endAngle > startAngle) - if (endAngle < startAngle) - { - // Swap values - float tmp = startAngle; - startAngle = endAngle; - endAngle = tmp; - } - - int minSegments = (int)ceilf((endAngle - startAngle)/90); - - if (segments < minSegments) - { - // Calculate the maximum angle between segments based on the error rate (usually 0.5f) - float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1); - segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); - - if (segments <= 0) segments = minSegments; - } - - // Not a ring - if (innerRadius <= 0.0f) - { - DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, color); - return; - } - - float stepLength = (endAngle - startAngle)/(float)segments; - float angle = startAngle; - -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - - angle += stepLength; - } - rlEnd(); - - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - angle += stepLength; - } - rlEnd(); -#endif -} - -// Draw ring outline -void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color) -{ - if (startAngle == endAngle) return; - - // Function expects (outerRadius > innerRadius) - if (outerRadius < innerRadius) - { - float tmp = outerRadius; - outerRadius = innerRadius; - innerRadius = tmp; - - if (outerRadius <= 0.0f) outerRadius = 0.1f; - } - - // Function expects (endAngle > startAngle) - if (endAngle < startAngle) - { - // Swap values - float tmp = startAngle; - startAngle = endAngle; - endAngle = tmp; - } - - int minSegments = (int)ceilf((endAngle - startAngle)/90); - - if (segments < minSegments) - { - // Calculate the maximum angle between segments based on the error rate (usually 0.5f) - float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1); - segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); - - if (segments <= 0) segments = minSegments; - } - - if (innerRadius <= 0.0f) - { - DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, color); - return; - } - - float stepLength = (endAngle - startAngle)/(float)segments; - float angle = startAngle; - bool showCapLines = true; - - rlBegin(RL_LINES); - if (showCapLines) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - } - - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - - angle += stepLength; - } - - if (showCapLines) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - } - rlEnd(); -} - -// Draw a color-filled rectangle -void DrawRectangle(int posX, int posY, int width, int height, Color color) -{ - DrawRectangleV((Vector2){ (float)posX, (float)posY }, (Vector2){ (float)width, (float)height }, color); -} - -// Draw a color-filled rectangle (Vector version) -// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues -void DrawRectangleV(Vector2 position, Vector2 size, Color color) -{ - DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color); -} - -// Draw a color-filled rectangle -void DrawRectangleRec(Rectangle rec, Color color) -{ - DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color); -} - -// Draw a color-filled rectangle with pro parameters -void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color) -{ - Vector2 topLeft = { 0 }; - Vector2 topRight = { 0 }; - Vector2 bottomLeft = { 0 }; - Vector2 bottomRight = { 0 }; - - // Only calculate rotation if needed - if (rotation == 0.0f) - { - float x = rec.x - origin.x; - float y = rec.y - origin.y; - topLeft = (Vector2){ x, y }; - topRight = (Vector2){ x + rec.width, y }; - bottomLeft = (Vector2){ x, y + rec.height }; - bottomRight = (Vector2){ x + rec.width, y + rec.height }; - } - else - { - float sinRotation = sinf(rotation*DEG2RAD); - float cosRotation = cosf(rotation*DEG2RAD); - float x = rec.x; - float y = rec.y; - float dx = -origin.x; - float dy = -origin.y; - - topLeft.x = x + dx*cosRotation - dy*sinRotation; - topLeft.y = y + dx*sinRotation + dy*cosRotation; - - topRight.x = x + (dx + rec.width)*cosRotation - dy*sinRotation; - topRight.y = y + (dx + rec.width)*sinRotation + dy*cosRotation; - - bottomLeft.x = x + dx*cosRotation - (dy + rec.height)*sinRotation; - bottomLeft.y = y + dx*sinRotation + (dy + rec.height)*cosRotation; - - bottomRight.x = x + (dx + rec.width)*cosRotation - (dy + rec.height)*sinRotation; - bottomRight.y = y + (dx + rec.width)*sinRotation + (dy + rec.height)*cosRotation; - } - -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - - rlNormal3f(0.0f, 0.0f, 1.0f); - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(topLeft.x, topLeft.y); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(bottomLeft.x, bottomLeft.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(bottomRight.x, bottomRight.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(topRight.x, topRight.y); - - rlEnd(); - - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(topLeft.x, topLeft.y); - rlVertex2f(bottomLeft.x, bottomLeft.y); - rlVertex2f(topRight.x, topRight.y); - - rlVertex2f(topRight.x, topRight.y); - rlVertex2f(bottomLeft.x, bottomLeft.y); - rlVertex2f(bottomRight.x, bottomRight.y); - - rlEnd(); -#endif -} - -// Draw a vertical-gradient-filled rectangle -void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom) -{ - DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, top, bottom, bottom, top); -} - -// Draw a horizontal-gradient-filled rectangle -void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right) -{ - DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, left, left, right, right); -} - -// Draw a gradient-filled rectangle -void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight) -{ - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - rlNormal3f(0.0f, 0.0f, 1.0f); - - // NOTE: Default raylib font character 95 is a white square - rlColor4ub(topLeft.r, topLeft.g, topLeft.b, topLeft.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(rec.x, rec.y); - - rlColor4ub(bottomLeft.r, bottomLeft.g, bottomLeft.b, bottomLeft.a); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(rec.x, rec.y + rec.height); - - rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(rec.x + rec.width, rec.y + rec.height); - - rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(rec.x + rec.width, rec.y); - rlEnd(); - - rlSetTexture(0); -} - -// Draw rectangle outline -// WARNING: All Draw*Lines() functions use RL_LINES for drawing, -// it implies flushing the current batch and changing draw mode to RL_LINES -// but it solves another issue: https://github.com/raysan5/raylib/issues/3884 -void DrawRectangleLines(int posX, int posY, int width, int height, Color color) -{ - Matrix mat = rlGetMatrixTransform(); - float xOffset = 0.5f/mat.m0; - float yOffset = 0.5f/mat.m5; - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f((float)posX + xOffset, (float)posY + yOffset); - rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset); - - rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset); - rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset); - - rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset); - rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset); - - rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset); - rlVertex2f((float)posX + xOffset, (float)posY + yOffset); - rlEnd(); - -/* -// Previous implementation, it has issues... but it does not require view matrix... -#if defined(SUPPORT_QUADS_DRAW_MODE) - DrawRectangle(posX, posY, width, 1, color); - DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color); - DrawRectangle(posX, posY + height - 1, width, 1, color); - DrawRectangle(posX, posY + 1, 1, height - 2, color); -#else - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f((float)posX, (float)posY); - rlVertex2f((float)posX + (float)width, (float)posY + 1); - - rlVertex2f((float)posX + (float)width, (float)posY + 1); - rlVertex2f((float)posX + (float)width, (float)posY + (float)height); - - rlVertex2f((float)posX + (float)width, (float)posY + (float)height); - rlVertex2f((float)posX + 1, (float)posY + (float)height); - - rlVertex2f((float)posX + 1, (float)posY + (float)height); - rlVertex2f((float)posX + 1, (float)posY + 1); - rlEnd(); -#endif -*/ -} - -// Draw rectangle outline with extended parameters -void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color) -{ - if ((lineThick > rec.width) || (lineThick > rec.height)) - { - if (rec.width >= rec.height) lineThick = rec.height/2; - else if (rec.width <= rec.height) lineThick = rec.width/2; - } - - // When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following - // four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight): - // - // TTTTTTTT - // TTTTTTTT - // LL RR - // LL RR - // BBBBBBBB - // BBBBBBBB - // - - Rectangle top = { rec.x, rec.y, rec.width, lineThick }; - Rectangle bottom = { rec.x, rec.y - lineThick + rec.height, rec.width, lineThick }; - Rectangle left = { rec.x, rec.y + lineThick, lineThick, rec.height - lineThick*2.0f }; - Rectangle right = { rec.x - lineThick + rec.width, rec.y + lineThick, lineThick, rec.height - lineThick*2.0f }; - - DrawRectangleRec(top, color); - DrawRectangleRec(bottom, color); - DrawRectangleRec(left, color); - DrawRectangleRec(right, color); -} - -// Draw rectangle with rounded edges -void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color) -{ - // Not a rounded rectangle - if (roundness <= 0.0f) - { - DrawRectangleRec(rec, color); - return; - } - - if (roundness >= 1.0f) roundness = 1.0f; - - // Calculate corner radius - float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2; - if (radius <= 0.0f) return; - - // Calculate number of segments to use for the corners - if (segments < 4) - { - // Calculate the maximum angle between segments based on the error rate (usually 0.5f) - float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); - segments = (int)(ceilf(2*PI/th)/4.0f); - if (segments <= 0) segments = 4; - } - - float stepLength = 90.0f/(float)segments; - - /* - Quick sketch to make sense of all of this, - there are 9 parts to draw, also mark the 12 points we'll use - - P0____________________P1 - /| |\ - /1| 2 |3\ - P7 /__|____________________|__\ P2 - | |P8 P9| | - | 8 | 9 | 4 | - | __|____________________|__ | - P6 \ |P11 P10| / P3 - \7| 6 |5/ - \|____________________|/ - P5 P4 - */ - // Coordinates of the 12 points that define the rounded rect - const Vector2 point[12] = { - {(float)rec.x + radius, rec.y}, {(float)(rec.x + rec.width) - radius, rec.y}, { rec.x + rec.width, (float)rec.y + radius }, // PO, P1, P2 - {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height}, // P3, P4 - {(float)rec.x + radius, rec.y + rec.height}, { rec.x, (float)(rec.y + rec.height) - radius}, {rec.x, (float)rec.y + radius}, // P5, P6, P7 - {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius}, // P8, P9 - {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11 - }; - - const Vector2 centers[4] = { point[8], point[9], point[10], point[11] }; - const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f }; - -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - // Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - - // NOTE: Every QUAD actually represents two segments - for (int i = 0; i < segments/2; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - - angle += (stepLength*2); - } - - // NOTE: In case number of segments is odd, we add one last piece to the cake - if (segments%2) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - } - } - - // [2] Upper Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[0].x, point[0].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[8].x, point[8].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[9].x, point[9].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[1].x, point[1].y); - - // [4] Right Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[2].x, point[2].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[9].x, point[9].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[10].x, point[10].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[3].x, point[3].y); - - // [6] Bottom Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[11].x, point[11].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[5].x, point[5].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[4].x, point[4].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[10].x, point[10].y); - - // [8] Left Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[7].x, point[7].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[6].x, point[6].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[11].x, point[11].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[8].x, point[8].y); - - // [9] Middle Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[8].x, point[8].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[11].x, point[11].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[10].x, point[10].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[9].x, point[9].y); - - rlEnd(); - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - - // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); - angle += stepLength; - } - } - - // [2] Upper Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[0].x, point[0].y); - rlVertex2f(point[8].x, point[8].y); - rlVertex2f(point[9].x, point[9].y); - rlVertex2f(point[1].x, point[1].y); - rlVertex2f(point[0].x, point[0].y); - rlVertex2f(point[9].x, point[9].y); - - // [4] Right Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[9].x, point[9].y); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[3].x, point[3].y); - rlVertex2f(point[2].x, point[2].y); - rlVertex2f(point[9].x, point[9].y); - rlVertex2f(point[3].x, point[3].y); - - // [6] Bottom Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[11].x, point[11].y); - rlVertex2f(point[5].x, point[5].y); - rlVertex2f(point[4].x, point[4].y); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[11].x, point[11].y); - rlVertex2f(point[4].x, point[4].y); - - // [8] Left Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[7].x, point[7].y); - rlVertex2f(point[6].x, point[6].y); - rlVertex2f(point[11].x, point[11].y); - rlVertex2f(point[8].x, point[8].y); - rlVertex2f(point[7].x, point[7].y); - rlVertex2f(point[11].x, point[11].y); - - // [9] Middle Rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[8].x, point[8].y); - rlVertex2f(point[11].x, point[11].y); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[9].x, point[9].y); - rlVertex2f(point[8].x, point[8].y); - rlVertex2f(point[10].x, point[10].y); - rlEnd(); -#endif -} - -// Draw rectangle with rounded edges -// TODO: This function should be refactored to use RL_LINES, for consistency with other Draw*Lines() -void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color) -{ - DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color); -} - -// Draw rectangle with rounded edges outline -void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color) -{ - if (lineThick < 0) lineThick = 0; - - // Not a rounded rectangle - if (roundness <= 0.0f) - { - DrawRectangleLinesEx((Rectangle){rec.x-lineThick, rec.y-lineThick, rec.width+2*lineThick, rec.height+2*lineThick}, lineThick, color); - return; - } - - if (roundness >= 1.0f) roundness = 1.0f; - - // Calculate corner radius - float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2; - if (radius <= 0.0f) return; - - // Calculate number of segments to use for the corners - if (segments < 4) - { - // Calculate the maximum angle between segments based on the error rate (usually 0.5f) - float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); - segments = (int)(ceilf(2*PI/th)/2.0f); - if (segments <= 0) segments = 4; - } - - float stepLength = 90.0f/(float)segments; - const float outerRadius = radius + lineThick, innerRadius = radius; - - /* - Quick sketch to make sense of all of this, - marks the 16 + 4(corner centers P16-19) points we'll use - - P0 ================== P1 - // P8 P9 \\ - // \\ - P7 // P15 P10 \\ P2 - || *P16 P17* || - || || - || P14 P11 || - P6 \\ *P19 P18* // P3 - \\ // - \\ P13 P12 // - P5 ================== P4 - */ - const Vector2 point[16] = { - {(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f}, - {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f}, - {rec.x + rec.width + lineThick - 0.5f, (float)rec.y + innerRadius + 0.5f}, // PO, P1, P2 - {rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, - {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + lineThick - 0.5f}, // P3, P4 - {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f}, - {rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, - {rec.x - lineThick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7 - {(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f}, - {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9 - {rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f}, - {rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, // P10, P11 - {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f}, - {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13 - {rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, - {rec.x + 0.5f, (float)rec.y + innerRadius + 0.5f} // P14, P15 - }; - - const Vector2 centers[4] = { - {(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f}, - {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17 - {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, - {(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19 - }; - - const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f }; - - if (lineThick > 1) - { -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - - // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - angle += stepLength; - } - } - - // Upper rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[0].x, point[0].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[8].x, point[8].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[9].x, point[9].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[1].x, point[1].y); - - // Right rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[2].x, point[2].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[10].x, point[10].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[11].x, point[11].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[3].x, point[3].y); - - // Lower rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[13].x, point[13].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[5].x, point[5].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[4].x, point[4].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[12].x, point[12].y); - - // Left rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[15].x, point[15].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[7].x, point[7].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[6].x, point[6].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[14].x, point[14].y); - - rlEnd(); - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - - // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - angle += stepLength; - } - } - - // Upper rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[0].x, point[0].y); - rlVertex2f(point[8].x, point[8].y); - rlVertex2f(point[9].x, point[9].y); - rlVertex2f(point[1].x, point[1].y); - rlVertex2f(point[0].x, point[0].y); - rlVertex2f(point[9].x, point[9].y); - - // Right rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[11].x, point[11].y); - rlVertex2f(point[3].x, point[3].y); - rlVertex2f(point[2].x, point[2].y); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[3].x, point[3].y); - - // Lower rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[13].x, point[13].y); - rlVertex2f(point[5].x, point[5].y); - rlVertex2f(point[4].x, point[4].y); - rlVertex2f(point[12].x, point[12].y); - rlVertex2f(point[13].x, point[13].y); - rlVertex2f(point[4].x, point[4].y); - - // Left rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[7].x, point[7].y); - rlVertex2f(point[6].x, point[6].y); - rlVertex2f(point[14].x, point[14].y); - rlVertex2f(point[15].x, point[15].y); - rlVertex2f(point[7].x, point[7].y); - rlVertex2f(point[14].x, point[14].y); - rlEnd(); -#endif - } - else - { - // Use LINES to draw the outline - rlBegin(RL_LINES); - - // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - angle += stepLength; - } - } - - // And now the remaining 4 lines - for (int i = 0; i < 8; i += 2) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[i].x, point[i].y); - rlVertex2f(point[i + 1].x, point[i + 1].y); - } - - rlEnd(); - } -} - -// Draw a triangle -// NOTE: Vertex must be provided in counter-clockwise order -void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) -{ -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(v1.x, v1.y); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(v2.x, v2.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(v2.x, v2.y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(v3.x, v3.y); - rlEnd(); - - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(v1.x, v1.y); - rlVertex2f(v2.x, v2.y); - rlVertex2f(v3.x, v3.y); - rlEnd(); -#endif -} - -// Draw a triangle using lines -// NOTE: Vertex must be provided in counter-clockwise order -void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color) -{ - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(v1.x, v1.y); - rlVertex2f(v2.x, v2.y); - - rlVertex2f(v2.x, v2.y); - rlVertex2f(v3.x, v3.y); - - rlVertex2f(v3.x, v3.y); - rlVertex2f(v1.x, v1.y); - rlEnd(); -} - -// Draw a triangle fan defined by points -// NOTE: First vertex provided is the center, shared by all triangles -// By default, following vertex should be provided in counter-clockwise order -void DrawTriangleFan(const Vector2 *points, int pointCount, Color color) -{ - if (pointCount >= 3) - { - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 1; i < pointCount - 1; i++) - { - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(points[0].x, points[0].y); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(points[i].x, points[i].y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(points[i + 1].x, points[i + 1].y); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(points[i + 1].x, points[i + 1].y); - } - rlEnd(); - rlSetTexture(0); - } -} - -// Draw a triangle strip defined by points -// NOTE: Every new vertex connects with previous two -void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color) -{ - if (pointCount >= 3) - { - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 2; i < pointCount; i++) - { - if ((i%2) == 0) - { - rlVertex2f(points[i].x, points[i].y); - rlVertex2f(points[i - 2].x, points[i - 2].y); - rlVertex2f(points[i - 1].x, points[i - 1].y); - } - else - { - rlVertex2f(points[i].x, points[i].y); - rlVertex2f(points[i - 1].x, points[i - 1].y); - rlVertex2f(points[i - 2].x, points[i - 2].y); - } - } - rlEnd(); - } -} - -// Draw a regular polygon of n sides (Vector version) -void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color) -{ - if (sides < 3) sides = 3; - float centralAngle = rotation*DEG2RAD; - float angleStep = 360.0f/(float)sides*DEG2RAD; - -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - for (int i = 0; i < sides; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - float nextAngle = centralAngle + angleStep; - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x, center.y); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius); - - centralAngle = nextAngle; - } - rlEnd(); - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - for (int i = 0; i < sides; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius); - rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius); - - centralAngle += angleStep; - } - rlEnd(); -#endif -} - -// Draw a polygon outline of n sides -void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color) -{ - if (sides < 3) sides = 3; - float centralAngle = rotation*DEG2RAD; - float angleStep = 360.0f/(float)sides*DEG2RAD; - - rlBegin(RL_LINES); - for (int i = 0; i < sides; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius); - rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius); - - centralAngle += angleStep; - } - rlEnd(); -} - -void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color) -{ - if (sides < 3) sides = 3; - float centralAngle = rotation*DEG2RAD; - float exteriorAngle = 360.0f/(float)sides*DEG2RAD; - float innerRadius = radius - (lineThick*cosf(DEG2RAD*exteriorAngle/2.0f)); - -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); - - rlBegin(RL_QUADS); - for (int i = 0; i < sides; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - float nextAngle = centralAngle + exteriorAngle; - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius); - - centralAngle = nextAngle; - } - rlEnd(); - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - for (int i = 0; i < sides; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - float nextAngle = centralAngle + exteriorAngle; - - rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius); - rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius); - rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius); - - rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius); - rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius); - rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius); - - centralAngle = nextAngle; - } - rlEnd(); -#endif -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Splines functions -//---------------------------------------------------------------------------------- - -// Draw spline: linear, minimum 2 points -void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color) -{ - if (pointCount < 2) return; - -#if defined(SUPPORT_SPLINE_MITERS) - Vector2 prevNormal = (Vector2){-(points[1].y - points[0].y), (points[1].x - points[0].x)}; - float prevLength = sqrtf(prevNormal.x*prevNormal.x + prevNormal.y*prevNormal.y); - - if (prevLength > 0.0f) - { - prevNormal.x /= prevLength; - prevNormal.y /= prevLength; - } - else - { - prevNormal.x = 0.0f; - prevNormal.y = 0.0f; - } - - Vector2 prevRadius = { 0.5f*thick*prevNormal.x, 0.5f*thick*prevNormal.y }; - - for (int i = 0; i < pointCount - 1; i++) - { - Vector2 normal = { 0 }; - - if (i < pointCount - 2) - { - normal = (Vector2){-(points[i + 2].y - points[i + 1].y), (points[i + 2].x - points[i + 1].x)}; - float normalLength = sqrtf(normal.x*normal.x + normal.y*normal.y); - - if (normalLength > 0.0f) - { - normal.x /= normalLength; - normal.y /= normalLength; - } - else - { - normal.x = 0.0f; - normal.y = 0.0f; - } - } - else - { - normal = prevNormal; - } - - Vector2 radius = { prevNormal.x + normal.x, prevNormal.y + normal.y }; - float radiusLength = sqrtf(radius.x*radius.x + radius.y*radius.y); - - if (radiusLength > 0.0f) - { - radius.x /= radiusLength; - radius.y /= radiusLength; - } - else - { - radius.x = 0.0f; - radius.y = 0.0f; - } - - float cosTheta = radius.x*normal.x + radius.y*normal.y; - - if (cosTheta != 0.0f) - { - radius.x *= (thick*0.5f/cosTheta); - radius.y *= (thick*0.5f/cosTheta); - } - else - { - radius.x = 0.0f; - radius.y = 0.0f; - } - - Vector2 strip[4] = { - { points[i].x - prevRadius.x, points[i].y - prevRadius.y }, - { points[i].x + prevRadius.x, points[i].y + prevRadius.y }, - { points[i + 1].x - radius.x, points[i + 1].y - radius.y }, - { points[i + 1].x + radius.x, points[i + 1].y + radius.y } - }; - - DrawTriangleStrip(strip, 4, color); - - prevRadius = radius; - prevNormal = normal; - } - -#else // !SUPPORT_SPLINE_MITERS - - Vector2 delta = { 0 }; - float length = 0.0f; - float scale = 0.0f; - - for (int i = 0; i < pointCount - 1; i++) - { - delta = (Vector2){ points[i + 1].x - points[i].x, points[i + 1].y - points[i].y }; - length = sqrtf(delta.x*delta.x + delta.y*delta.y); - - if (length > 0) scale = thick/(2*length); - - Vector2 radius = { -scale*delta.y, scale*delta.x }; - Vector2 strip[4] = { - { points[i].x - radius.x, points[i].y - radius.y }, - { points[i].x + radius.x, points[i].y + radius.y }, - { points[i + 1].x - radius.x, points[i + 1].y - radius.y }, - { points[i + 1].x + radius.x, points[i + 1].y + radius.y } - }; - - DrawTriangleStrip(strip, 4, color); - } -#endif - -#if defined(SUPPORT_SPLINE_SEGMENT_CAPS) - // TODO: Add spline segment rounded caps at the begin/end of the spline -#endif -} - -// Draw spline: B-Spline, minimum 4 points -void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color) -{ - if (pointCount < 4) return; - - float a[4] = { 0 }; - float b[4] = { 0 }; - float dy = 0.0f; - float dx = 0.0f; - float size = 0.0f; - - Vector2 currentPoint = { 0 }; - Vector2 nextPoint = { 0 }; - Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - for (int i = 0; i < (pointCount - 3); i++) - { - float t = 0.0f; - Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3]; - - a[0] = (-p1.x + 3.0f*p2.x - 3.0f*p3.x + p4.x)/6.0f; - a[1] = (3.0f*p1.x - 6.0f*p2.x + 3.0f*p3.x)/6.0f; - a[2] = (-3.0f*p1.x + 3.0f*p3.x)/6.0f; - a[3] = (p1.x + 4.0f*p2.x + p3.x)/6.0f; - - b[0] = (-p1.y + 3.0f*p2.y - 3.0f*p3.y + p4.y)/6.0f; - b[1] = (3.0f*p1.y - 6.0f*p2.y + 3.0f*p3.y)/6.0f; - b[2] = (-3.0f*p1.y + 3.0f*p3.y)/6.0f; - b[3] = (p1.y + 4.0f*p2.y + p3.y)/6.0f; - - currentPoint.x = a[3]; - currentPoint.y = b[3]; - - if (i == 0) DrawCircleV(currentPoint, thick/2.0f, color); // Draw init line circle-cap - - if (i > 0) - { - vertices[0].x = currentPoint.x + dy*size; - vertices[0].y = currentPoint.y - dx*size; - vertices[1].x = currentPoint.x - dy*size; - vertices[1].y = currentPoint.y + dx*size; - } - - for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++) - { - t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS); - - nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0])); - nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0])); - - dy = nextPoint.y - currentPoint.y; - dx = nextPoint.x - currentPoint.x; - size = 0.5f*thick/sqrtf(dx*dx+dy*dy); - - if ((i == 0) && (j == 1)) - { - vertices[0].x = currentPoint.x + dy*size; - vertices[0].y = currentPoint.y - dx*size; - vertices[1].x = currentPoint.x - dy*size; - vertices[1].y = currentPoint.y + dx*size; - } - - vertices[2*j + 1].x = nextPoint.x - dy*size; - vertices[2*j + 1].y = nextPoint.y + dx*size; - vertices[2*j].x = nextPoint.x + dy*size; - vertices[2*j].y = nextPoint.y - dx*size; - - currentPoint = nextPoint; - } - - DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); - } - - // Cap circle drawing at the end of every segment - DrawCircleV(currentPoint, thick/2.0f, color); -} - -// Draw spline: Catmull-Rom, minimum 4 points -void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color) -{ - if (pointCount < 4) return; - - float dy = 0.0f; - float dx = 0.0f; - float size = 0.0f; - - Vector2 currentPoint = points[1]; - Vector2 nextPoint = { 0 }; - Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - DrawCircleV(currentPoint, thick/2.0f, color); // Draw init line circle-cap - - for (int i = 0; i < (pointCount - 3); i++) - { - float t = 0.0f; - Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3]; - - if (i > 0) - { - vertices[0].x = currentPoint.x + dy*size; - vertices[0].y = currentPoint.y - dx*size; - vertices[1].x = currentPoint.x - dy*size; - vertices[1].y = currentPoint.y + dx*size; - } - - for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++) - { - t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS); - - float q0 = (-1.0f*t*t*t) + (2.0f*t*t) + (-1.0f*t); - float q1 = (3.0f*t*t*t) + (-5.0f*t*t) + 2.0f; - float q2 = (-3.0f*t*t*t) + (4.0f*t*t) + t; - float q3 = t*t*t - t*t; - - nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3)); - nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3)); - - dy = nextPoint.y - currentPoint.y; - dx = nextPoint.x - currentPoint.x; - size = (0.5f*thick)/sqrtf(dx*dx + dy*dy); - - if ((i == 0) && (j == 1)) - { - vertices[0].x = currentPoint.x + dy*size; - vertices[0].y = currentPoint.y - dx*size; - vertices[1].x = currentPoint.x - dy*size; - vertices[1].y = currentPoint.y + dx*size; - } - - vertices[2*j + 1].x = nextPoint.x - dy*size; - vertices[2*j + 1].y = nextPoint.y + dx*size; - vertices[2*j].x = nextPoint.x + dy*size; - vertices[2*j].y = nextPoint.y - dx*size; - - currentPoint = nextPoint; - } - - DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); - } - - // Cap circle drawing at the end of every segment - DrawCircleV(currentPoint, thick/2.0f, color); -} - -// Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] -void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color) -{ - if (pointCount >= 3) - { - for (int i = 0; i < pointCount - 2; i += 2) DrawSplineSegmentBezierQuadratic(points[i], points[i + 1], points[i + 2], thick, color); - - // Cap circle drawing at the end of every segment - //for (int i = 2; i < pointCount - 2; i += 2) DrawCircleV(points[i], thick/2.0f, color); - } -} - -// Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] -void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color) -{ - if (pointCount >= 4) - { - for (int i = 0; i < pointCount - 3; i += 3) DrawSplineSegmentBezierCubic(points[i], points[i + 1], points[i + 2], points[i + 3], thick, color); - - // Cap circle drawing at the end of every segment - //for (int i = 3; i < pointCount - 3; i += 3) DrawCircleV(points[i], thick/2.0f, color); - } -} - -// Draw spline segment: Linear, 2 points -void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color) -{ - // NOTE: For the linear spline we don't use subdivisions, just a single quad - - Vector2 delta = { p2.x - p1.x, p2.y - p1.y }; - float length = sqrtf(delta.x*delta.x + delta.y*delta.y); - - if ((length > 0) && (thick > 0)) - { - float scale = thick/(2*length); - - Vector2 radius = { -scale*delta.y, scale*delta.x }; - Vector2 strip[4] = { - { p1.x - radius.x, p1.y - radius.y }, - { p1.x + radius.x, p1.y + radius.y }, - { p2.x - radius.x, p2.y - radius.y }, - { p2.x + radius.x, p2.y + radius.y } - }; - - DrawTriangleStrip(strip, 4, color); - } -} - -// Draw spline segment: B-Spline, 4 points -void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color) -{ - const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS; - - Vector2 currentPoint = { 0 }; - Vector2 nextPoint = { 0 }; - float t = 0.0f; - - Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - float a[4] = { 0 }; - float b[4] = { 0 }; - - a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f; - a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f; - a[2] = (-3*p1.x + 3*p3.x)/6.0f; - a[3] = (p1.x + 4*p2.x + p3.x)/6.0f; - - b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f; - b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f; - b[2] = (-3*p1.y + 3*p3.y)/6.0f; - b[3] = (p1.y + 4*p2.y + p3.y)/6.0f; - - currentPoint.x = a[3]; - currentPoint.y = b[3]; - - for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++) - { - t = step*(float)i; - - nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0])); - nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0])); - - float dy = nextPoint.y - currentPoint.y; - float dx = nextPoint.x - currentPoint.x; - float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy); - - if (i == 1) - { - points[0].x = currentPoint.x + dy*size; - points[0].y = currentPoint.y - dx*size; - points[1].x = currentPoint.x - dy*size; - points[1].y = currentPoint.y + dx*size; - } - - points[2*i + 1].x = nextPoint.x - dy*size; - points[2*i + 1].y = nextPoint.y + dx*size; - points[2*i].x = nextPoint.x + dy*size; - points[2*i].y = nextPoint.y - dx*size; - - currentPoint = nextPoint; - } - - DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS+2, color); -} - -// Draw spline segment: Catmull-Rom, 4 points -void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color) -{ - const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS; - - Vector2 currentPoint = p1; - Vector2 nextPoint = { 0 }; - float t = 0.0f; - - Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++) - { - t = step*(float)i; - - float q0 = (-1*t*t*t) + (2*t*t) + (-1*t); - float q1 = (3*t*t*t) + (-5*t*t) + 2; - float q2 = (-3*t*t*t) + (4*t*t) + t; - float q3 = t*t*t - t*t; - - nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3)); - nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3)); - - float dy = nextPoint.y - currentPoint.y; - float dx = nextPoint.x - currentPoint.x; - float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy); - - if (i == 1) - { - points[0].x = currentPoint.x + dy*size; - points[0].y = currentPoint.y - dx*size; - points[1].x = currentPoint.x - dy*size; - points[1].y = currentPoint.y + dx*size; - } - - points[2*i + 1].x = nextPoint.x - dy*size; - points[2*i + 1].y = nextPoint.y + dx*size; - points[2*i].x = nextPoint.x + dy*size; - points[2*i].y = nextPoint.y - dx*size; - - currentPoint = nextPoint; - } - - DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); -} - -// Draw spline segment: Quadratic Bezier, 2 points, 1 control point -void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color) -{ - const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS; - - Vector2 previous = p1; - Vector2 current = { 0 }; - float t = 0.0f; - - Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++) - { - t = step*(float)i; - - float a = powf(1.0f - t, 2); - float b = 2.0f*(1.0f - t)*t; - float c = powf(t, 2); - - // NOTE: The easing functions aren't suitable here because they don't take a control point - current.y = a*p1.y + b*c2.y + c*p3.y; - current.x = a*p1.x + b*c2.x + c*p3.x; - - float dy = current.y - previous.y; - float dx = current.x - previous.x; - float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); - - if (i == 1) - { - points[0].x = previous.x + dy*size; - points[0].y = previous.y - dx*size; - points[1].x = previous.x - dy*size; - points[1].y = previous.y + dx*size; - } - - points[2*i + 1].x = current.x - dy*size; - points[2*i + 1].y = current.y + dx*size; - points[2*i].x = current.x + dy*size; - points[2*i].y = current.y - dx*size; - - previous = current; - } - - DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); -} - -// Draw spline segment: Cubic Bezier, 2 points, 2 control points -void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color) -{ - const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS; - - Vector2 previous = p1; - Vector2 current = { 0 }; - float t = 0.0f; - - Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 }; - - for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++) - { - t = step*(float)i; - - float a = powf(1.0f - t, 3); - float b = 3.0f*powf(1.0f - t, 2)*t; - float c = 3.0f*(1.0f - t)*powf(t, 2); - float d = powf(t, 3); - - current.y = a*p1.y + b*c2.y + c*c3.y + d*p4.y; - current.x = a*p1.x + b*c2.x + c*c3.x + d*p4.x; - - float dy = current.y - previous.y; - float dx = current.x - previous.x; - float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); - - if (i == 1) - { - points[0].x = previous.x + dy*size; - points[0].y = previous.y - dx*size; - points[1].x = previous.x - dy*size; - points[1].y = previous.y + dx*size; - } - - points[2*i + 1].x = current.x - dy*size; - points[2*i + 1].y = current.y + dx*size; - points[2*i].x = current.x + dy*size; - points[2*i].y = current.y - dx*size; - - previous = current; - } - - DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); -} - -// Get spline point for a given t [0.0f .. 1.0f], Linear -Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t) -{ - Vector2 point = { 0 }; - - point.x = startPos.x*(1.0f - t) + endPos.x*t; - point.y = startPos.y*(1.0f - t) + endPos.y*t; - - return point; -} - -// Get spline point for a given t [0.0f .. 1.0f], B-Spline -Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t) -{ - Vector2 point = { 0 }; - - float a[4] = { 0 }; - float b[4] = { 0 }; - - a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f; - a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f; - a[2] = (-3*p1.x + 3*p3.x)/6.0f; - a[3] = (p1.x + 4*p2.x + p3.x)/6.0f; - - b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f; - b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f; - b[2] = (-3*p1.y + 3*p3.y)/6.0f; - b[3] = (p1.y + 4*p2.y + p3.y)/6.0f; - - point.x = a[3] + t*(a[2] + t*(a[1] + t*a[0])); - point.y = b[3] + t*(b[2] + t*(b[1] + t*b[0])); - - return point; -} - -// Get spline point for a given t [0.0f .. 1.0f], Catmull-Rom -Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t) -{ - Vector2 point = { 0 }; - - float q0 = (-1*t*t*t) + (2*t*t) + (-1*t); - float q1 = (3*t*t*t) + (-5*t*t) + 2; - float q2 = (-3*t*t*t) + (4*t*t) + t; - float q3 = t*t*t - t*t; - - point.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3)); - point.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3)); - - return point; -} - -// Get spline point for a given t [0.0f .. 1.0f], Quadratic Bezier -Vector2 GetSplinePointBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t) -{ - Vector2 point = { 0 }; - - float a = powf(1.0f - t, 2); - float b = 2.0f*(1.0f - t)*t; - float c = powf(t, 2); - - point.y = a*startPos.y + b*controlPos.y + c*endPos.y; - point.x = a*startPos.x + b*controlPos.x + c*endPos.x; - - return point; -} - -// Get spline point for a given t [0.0f .. 1.0f], Cubic Bezier -Vector2 GetSplinePointBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t) -{ - Vector2 point = { 0 }; - - float a = powf(1.0f - t, 3); - float b = 3.0f*powf(1.0f - t, 2)*t; - float c = 3.0f*(1.0f - t)*powf(t, 2); - float d = powf(t, 3); - - point.y = a*startPos.y + b*startControlPos.y + c*endControlPos.y + d*endPos.y; - point.x = a*startPos.x + b*startControlPos.x + c*endControlPos.x + d*endPos.x; - - return point; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Collision Detection functions -//---------------------------------------------------------------------------------- - -// Check if point is inside rectangle -bool CheckCollisionPointRec(Vector2 point, Rectangle rec) -{ - bool collision = false; - - if ((point.x >= rec.x) && (point.x < (rec.x + rec.width)) && (point.y >= rec.y) && (point.y < (rec.y + rec.height))) collision = true; - - return collision; -} - -// Check if point is inside circle -bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius) -{ - bool collision = false; - - float distanceSquared = (point.x - center.x)*(point.x - center.x) + (point.y - center.y)*(point.y - center.y); - - if (distanceSquared <= radius*radius) collision = true; - - return collision; -} - -// Check if point is inside a triangle defined by three points (p1, p2, p3) -bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3) -{ - bool collision = false; - - float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) / - ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); - - float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) / - ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); - - float gamma = 1.0f - alpha - beta; - - if ((alpha > 0) && (beta > 0) && (gamma > 0)) collision = true; - - return collision; -} - -// Check if point is within a polygon described by array of vertices -// NOTE: Based on http://jeffreythompson.org/collision-detection/poly-point.php -bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount) -{ - bool collision = false; - - if (pointCount > 2) - { - for (int i = 0, j = pointCount - 1; i < pointCount; j = i++) - { - if ((points[i].y > point.y) != (points[j].y > point.y) && - (point.x < (points[j].x - points[i].x)*(point.y - points[i].y)/(points[j].y - points[i].y) + points[i].x)) - { - collision = !collision; - } - } - } - - return collision; -} - -// Check collision between two rectangles -bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2) -{ - bool collision = false; - - if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) && - (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true; - - return collision; -} - -// Check collision between two circles -bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2) -{ - bool collision = false; - - float dx = center2.x - center1.x; // X distance between centers - float dy = center2.y - center1.y; // Y distance between centers - - float distanceSquared = dx*dx + dy*dy; // Distance between centers squared - float radiusSum = radius1 + radius2; - - collision = (distanceSquared <= (radiusSum*radiusSum)); - - return collision; -} - -// Check collision between circle and rectangle -// NOTE: Reviewed version to take into account corner limit case -bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) -{ - bool collision = false; - - float recCenterX = rec.x + rec.width/2.0f; - float recCenterY = rec.y + rec.height/2.0f; - - float dx = fabsf(center.x - recCenterX); - float dy = fabsf(center.y - recCenterY); - - if (dx > (rec.width/2.0f + radius)) { return false; } - if (dy > (rec.height/2.0f + radius)) { return false; } - - if (dx <= (rec.width/2.0f)) { return true; } - if (dy <= (rec.height/2.0f)) { return true; } - - float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) + - (dy - rec.height/2.0f)*(dy - rec.height/2.0f); - - collision = (cornerDistanceSq <= (radius*radius)); - - return collision; -} - -// Check the collision between two lines defined by two points each, returns collision point by reference -bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint) -{ - bool collision = false; - - float div = (endPos2.y - startPos2.y)*(endPos1.x - startPos1.x) - (endPos2.x - startPos2.x)*(endPos1.y - startPos1.y); - - if (fabsf(div) >= FLT_EPSILON) - { - collision = true; - - float xi = ((startPos2.x - endPos2.x)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.x - endPos1.x)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div; - float yi = ((startPos2.y - endPos2.y)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.y - endPos1.y)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div; - - if (((fabsf(startPos1.x - endPos1.x) > FLT_EPSILON) && (xi < fminf(startPos1.x, endPos1.x) || (xi > fmaxf(startPos1.x, endPos1.x)))) || - ((fabsf(startPos2.x - endPos2.x) > FLT_EPSILON) && (xi < fminf(startPos2.x, endPos2.x) || (xi > fmaxf(startPos2.x, endPos2.x)))) || - ((fabsf(startPos1.y - endPos1.y) > FLT_EPSILON) && (yi < fminf(startPos1.y, endPos1.y) || (yi > fmaxf(startPos1.y, endPos1.y)))) || - ((fabsf(startPos2.y - endPos2.y) > FLT_EPSILON) && (yi < fminf(startPos2.y, endPos2.y) || (yi > fmaxf(startPos2.y, endPos2.y))))) collision = false; - - if (collision && (collisionPoint != 0)) - { - collisionPoint->x = xi; - collisionPoint->y = yi; - } - } - - return collision; -} - -// Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] -bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold) -{ - bool collision = false; - - float dxc = point.x - p1.x; - float dyc = point.y - p1.y; - float dxl = p2.x - p1.x; - float dyl = p2.y - p1.y; - float cross = dxc*dyl - dyc*dxl; - - if (fabsf(cross) < (threshold*fmaxf(fabsf(dxl), fabsf(dyl)))) - { - if (fabsf(dxl) >= fabsf(dyl)) collision = (dxl > 0)? ((p1.x <= point.x) && (point.x <= p2.x)) : ((p2.x <= point.x) && (point.x <= p1.x)); - else collision = (dyl > 0)? ((p1.y <= point.y) && (point.y <= p2.y)) : ((p2.y <= point.y) && (point.y <= p1.y)); - } - - return collision; -} - -// Check if circle collides with a line created between two points [p1] and [p2] -RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2) -{ - float dx = p1.x - p2.x; - float dy = p1.y - p2.y; - - if ((fabsf(dx) + fabsf(dy)) <= FLT_EPSILON) - { - return CheckCollisionCircles(p1, 0, center, radius); - } - - float lengthSQ = ((dx*dx) + (dy*dy)); - float dotProduct = (((center.x - p1.x)*(p2.x - p1.x)) + ((center.y - p1.y)*(p2.y - p1.y)))/(lengthSQ); - - if (dotProduct > 1.0f) dotProduct = 1.0f; - else if (dotProduct < 0.0f) dotProduct = 0.0f; - - float dx2 = (p1.x - (dotProduct*(dx))) - center.x; - float dy2 = (p1.y - (dotProduct*(dy))) - center.y; - float distanceSQ = ((dx2*dx2) + (dy2*dy2)); - - return (distanceSQ <= radius*radius); -} - -// Get collision rectangle for two rectangles collision -Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) -{ - Rectangle overlap = { 0 }; - - float left = (rec1.x > rec2.x)? rec1.x : rec2.x; - float right1 = rec1.x + rec1.width; - float right2 = rec2.x + rec2.width; - float right = (right1 < right2)? right1 : right2; - float top = (rec1.y > rec2.y)? rec1.y : rec2.y; - float bottom1 = rec1.y + rec1.height; - float bottom2 = rec2.y + rec2.height; - float bottom = (bottom1 < bottom2)? bottom1 : bottom2; - - if ((left < right) && (top < bottom)) - { - overlap.x = left; - overlap.y = top; - overlap.width = right - left; - overlap.height = bottom - top; - } - - return overlap; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -// Cubic easing in-out -// NOTE: Used by DrawLineBezier() only -static float EaseCubicInOut(float t, float b, float c, float d) -{ - float result = 0.0f; - - if ((t /= 0.5f*d) < 1) result = 0.5f*c*t*t*t + b; - else - { - t -= 2; - result = 0.5f*c*(t*t*t + 2.0f) + b; - } - - return result; -} - -#endif // SUPPORT_MODULE_RSHAPES diff --git a/raylib/rshapes.go b/raylib/rshapes.go deleted file mode 100644 index 4922b3a..0000000 --- a/raylib/rshapes.go +++ /dev/null @@ -1,647 +0,0 @@ -package rl - -/* -#include "raylib.h" -#include -*/ -import "C" -import ( - "image/color" - "unsafe" -) - -// SetShapesTexture - Define default texture used to draw shapes -func SetShapesTexture(texture Texture2D, source Rectangle) { - ctexture := texture.cptr() - csource := source.cptr() - C.SetShapesTexture(*ctexture, *csource) -} - -// GetShapesTexture - Get texture that is used for shapes drawing -func GetShapesTexture() Texture2D { - ret := C.GetShapesTexture() - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetShapesTextureRectangle - Get texture source rectangle that is used for shapes drawing -func GetShapesTextureRectangle() Rectangle { - ret := C.GetShapesTextureRectangle() - v := newRectangleFromPointer(unsafe.Pointer(&ret)) - return v -} - -// DrawPixel - Draw a pixel -func DrawPixel(posX, posY int32, col color.RGBA) { - cposX := (C.int)(posX) - cposY := (C.int)(posY) - ccolor := colorCptr(col) - C.DrawPixel(cposX, cposY, *ccolor) -} - -// DrawPixelV - Draw a pixel (Vector version) -func DrawPixelV(position Vector2, col color.RGBA) { - cposition := position.cptr() - ccolor := colorCptr(col) - C.DrawPixelV(*cposition, *ccolor) -} - -// DrawLine - Draw a line -func DrawLine(startPosX, startPosY, endPosX, endPosY int32, col color.RGBA) { - cstartPosX := (C.int)(startPosX) - cstartPosY := (C.int)(startPosY) - cendPosX := (C.int)(endPosX) - cendPosY := (C.int)(endPosY) - ccolor := colorCptr(col) - C.DrawLine(cstartPosX, cstartPosY, cendPosX, cendPosY, *ccolor) -} - -// DrawLineV - Draw a line (Vector version) -func DrawLineV(startPos, endPos Vector2, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - ccolor := colorCptr(col) - C.DrawLineV(*cstartPos, *cendPos, *ccolor) -} - -// DrawLineEx - Draw a line defining thickness -func DrawLineEx(startPos, endPos Vector2, thick float32, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawLineEx(*cstartPos, *cendPos, cthick, *ccolor) -} - -// DrawLineStrip - Draw lines sequence -func DrawLineStrip(points []Vector2, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointCount := (C.int)(len(points)) - ccolor := colorCptr(col) - C.DrawLineStrip(cpoints, cpointCount, *ccolor) -} - -// DrawLineBezier - Draw a line using cubic-bezier curves in-out -func DrawLineBezier(startPos, endPos Vector2, thick float32, col color.RGBA) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawLineBezier(*cstartPos, *cendPos, cthick, *ccolor) -} - -// DrawCircle - Draw a color-filled circle -func DrawCircle(centerX, centerY int32, radius float32, col color.RGBA) { - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradius := (C.float)(radius) - ccolor := colorCptr(col) - C.DrawCircle(ccenterX, ccenterY, cradius, *ccolor) -} - -// DrawCircleSector - Draw a piece of a circle -func DrawCircleSector(center Vector2, radius, startAngle, endAngle float32, segments int32, col color.RGBA) { - ccenter := center.cptr() - cradius := (C.float)(radius) - cstartAngle := (C.float)(startAngle) - cendAngle := (C.float)(endAngle) - csegments := (C.int)(segments) - ccolor := colorCptr(col) - C.DrawCircleSector(*ccenter, cradius, cstartAngle, cendAngle, csegments, *ccolor) -} - -// DrawCircleSectorLines - -func DrawCircleSectorLines(center Vector2, radius, startAngle, endAngle float32, segments int32, col color.RGBA) { - ccenter := center.cptr() - cradius := (C.float)(radius) - cstartAngle := (C.float)(startAngle) - cendAngle := (C.float)(endAngle) - csegments := (C.int)(segments) - ccolor := colorCptr(col) - C.DrawCircleSectorLines(*ccenter, cradius, cstartAngle, cendAngle, csegments, *ccolor) -} - -// DrawCircleGradient - Draw a gradient-filled circle -func DrawCircleGradient(centerX, centerY int32, radius float32, inner, outer color.RGBA) { - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradius := (C.float)(radius) - cinner := colorCptr(inner) - couter := colorCptr(outer) - C.DrawCircleGradient(ccenterX, ccenterY, cradius, *cinner, *couter) -} - -// DrawCircleV - Draw a color-filled circle (Vector version) -func DrawCircleV(center Vector2, radius float32, col color.RGBA) { - ccenter := center.cptr() - cradius := (C.float)(radius) - ccolor := colorCptr(col) - C.DrawCircleV(*ccenter, cradius, *ccolor) -} - -// DrawCircleLines - Draw circle outline -func DrawCircleLines(centerX, centerY int32, radius float32, col color.RGBA) { - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradius := (C.float)(radius) - ccolor := colorCptr(col) - C.DrawCircleLines(ccenterX, ccenterY, cradius, *ccolor) -} - -// DrawCircleLinesV - Draw circle outline (Vector version) -func DrawCircleLinesV(center Vector2, radius float32, col color.RGBA) { - ccenter := center.cptr() - cradius := (C.float)(radius) - ccolor := colorCptr(col) - C.DrawCircleLinesV(*ccenter, cradius, *ccolor) -} - -// DrawEllipse - Draw ellipse -func DrawEllipse(centerX, centerY int32, radiusH, radiusV float32, col color.RGBA) { - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradiusH := (C.float)(radiusH) - cradiusV := (C.float)(radiusV) - ccolor := colorCptr(col) - C.DrawEllipse(ccenterX, ccenterY, cradiusH, cradiusV, *ccolor) -} - -// DrawEllipseLines - Draw ellipse outline -func DrawEllipseLines(centerX, centerY int32, radiusH, radiusV float32, col color.RGBA) { - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradiusH := (C.float)(radiusH) - cradiusV := (C.float)(radiusV) - ccolor := colorCptr(col) - C.DrawEllipseLines(ccenterX, ccenterY, cradiusH, cradiusV, *ccolor) -} - -// DrawRing - Draw ring -func DrawRing(center Vector2, innerRadius, outerRadius, startAngle, endAngle float32, segments int32, col color.RGBA) { - ccenter := center.cptr() - cinnerRadius := (C.float)(innerRadius) - couterRadius := (C.float)(outerRadius) - cstartAngle := (C.float)(startAngle) - cendAngle := (C.float)(endAngle) - csegments := (C.int)(segments) - ccolor := colorCptr(col) - C.DrawRing(*ccenter, cinnerRadius, couterRadius, cstartAngle, cendAngle, csegments, *ccolor) -} - -// DrawRingLines - Draw ring outline -func DrawRingLines(center Vector2, innerRadius, outerRadius, startAngle, endAngle float32, segments int32, col color.RGBA) { - ccenter := center.cptr() - cinnerRadius := (C.float)(innerRadius) - couterRadius := (C.float)(outerRadius) - cstartAngle := (C.float)(startAngle) - cendAngle := (C.float)(endAngle) - csegments := (C.int)(segments) - ccolor := colorCptr(col) - C.DrawRingLines(*ccenter, cinnerRadius, couterRadius, cstartAngle, cendAngle, csegments, *ccolor) -} - -// DrawRectangle - Draw a color-filled rectangle -func DrawRectangle(posX, posY, width, height int32, col color.RGBA) { - cposX := (C.int)(posX) - cposY := (C.int)(posY) - cwidth := (C.int)(width) - cheight := (C.int)(height) - ccolor := colorCptr(col) - C.DrawRectangle(cposX, cposY, cwidth, cheight, *ccolor) -} - -// DrawRectangleV - Draw a color-filled rectangle (Vector version) -func DrawRectangleV(position Vector2, size Vector2, col color.RGBA) { - cposition := position.cptr() - csize := size.cptr() - ccolor := colorCptr(col) - C.DrawRectangleV(*cposition, *csize, *ccolor) -} - -// DrawRectangleRec - Draw a color-filled rectangle -func DrawRectangleRec(rec Rectangle, col color.RGBA) { - crec := rec.cptr() - ccolor := colorCptr(col) - C.DrawRectangleRec(*crec, *ccolor) -} - -// DrawRectanglePro - Draw a color-filled rectangle with pro parameters -func DrawRectanglePro(rec Rectangle, origin Vector2, rotation float32, col color.RGBA) { - crec := rec.cptr() - corigin := origin.cptr() - crotation := (C.float)(rotation) - ccolor := colorCptr(col) - C.DrawRectanglePro(*crec, *corigin, crotation, *ccolor) -} - -// DrawRectangleGradientV - Draw a vertical-gradient-filled rectangle -func DrawRectangleGradientV(posX, posY, width, height int32, top, bottom color.RGBA) { - cposX := (C.int)(posX) - cposY := (C.int)(posY) - cwidth := (C.int)(width) - cheight := (C.int)(height) - ctop := colorCptr(top) - cbottom := colorCptr(bottom) - C.DrawRectangleGradientV(cposX, cposY, cwidth, cheight, *ctop, *cbottom) -} - -// DrawRectangleGradientH - Draw a horizontal-gradient-filled rectangle -func DrawRectangleGradientH(posX, posY, width, height int32, left, right color.RGBA) { - cposX := (C.int)(posX) - cposY := (C.int)(posY) - cwidth := (C.int)(width) - cheight := (C.int)(height) - cleft := colorCptr(left) - cright := colorCptr(right) - C.DrawRectangleGradientH(cposX, cposY, cwidth, cheight, *cleft, *cright) -} - -// DrawRectangleGradientEx - Draw a gradient-filled rectangle with custom vertex colors -func DrawRectangleGradientEx(rec Rectangle, topLeft, bottomLeft, topRight, bottomRight color.RGBA) { - crec := rec.cptr() - ctopLeft := colorCptr(topLeft) - cbottomLeft := colorCptr(bottomLeft) - ctopRight := colorCptr(topRight) - cbottomRight := colorCptr(bottomRight) - C.DrawRectangleGradientEx(*crec, *ctopLeft, *cbottomLeft, *ctopRight, *cbottomRight) -} - -// DrawRectangleLines - Draw rectangle outline -func DrawRectangleLines(posX, posY, width, height int32, col color.RGBA) { - cposX := (C.int)(posX) - cposY := (C.int)(posY) - cwidth := (C.int)(width) - cheight := (C.int)(height) - ccolor := colorCptr(col) - C.DrawRectangleLines(cposX, cposY, cwidth, cheight, *ccolor) -} - -// DrawRectangleLinesEx - Draw rectangle outline with extended parameters -func DrawRectangleLinesEx(rec Rectangle, lineThick float32, col color.RGBA) { - crec := rec.cptr() - clineThick := (C.float)(lineThick) - ccolor := colorCptr(col) - C.DrawRectangleLinesEx(*crec, clineThick, *ccolor) -} - -// DrawRectangleRounded - Draw rectangle with rounded edges -func DrawRectangleRounded(rec Rectangle, roundness float32, segments int32, col color.RGBA) { - crec := rec.cptr() - croundness := (C.float)(roundness) - csegments := (C.int)(segments) - ccolor := colorCptr(col) - C.DrawRectangleRounded(*crec, croundness, csegments, *ccolor) -} - -// DrawRectangleRoundedLines - Draw rectangle lines with rounded edges -func DrawRectangleRoundedLines(rec Rectangle, roundness float32, segments int32, col color.RGBA) { - crec := rec.cptr() - croundness := (C.float)(roundness) - csegments := (C.int)(segments) - ccolor := colorCptr(col) - C.DrawRectangleRoundedLines(*crec, croundness, csegments, *ccolor) -} - -// DrawRectangleRoundedLinesEx - Draw rectangle with rounded edges outline -func DrawRectangleRoundedLinesEx(rec Rectangle, roundness float32, segments int32, lineThick float32, col color.RGBA) { - crec := rec.cptr() - croundness := (C.float)(roundness) - csegments := (C.int)(segments) - clineThick := (C.float)(lineThick) - ccolor := colorCptr(col) - C.DrawRectangleRoundedLinesEx(*crec, croundness, csegments, clineThick, *ccolor) -} - -// DrawTriangle - Draw a color-filled triangle -func DrawTriangle(v1, v2, v3 Vector2, col color.RGBA) { - cv1 := v1.cptr() - cv2 := v2.cptr() - cv3 := v3.cptr() - ccolor := colorCptr(col) - C.DrawTriangle(*cv1, *cv2, *cv3, *ccolor) -} - -// DrawTriangleLines - Draw triangle outline -func DrawTriangleLines(v1, v2, v3 Vector2, col color.RGBA) { - cv1 := v1.cptr() - cv2 := v2.cptr() - cv3 := v3.cptr() - ccolor := colorCptr(col) - C.DrawTriangleLines(*cv1, *cv2, *cv3, *ccolor) -} - -// DrawTriangleFan - Draw a triangle fan defined by points -func DrawTriangleFan(points []Vector2, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointsCount := (C.int)(len(points)) - ccolor := colorCptr(col) - C.DrawTriangleFan(cpoints, cpointsCount, *ccolor) -} - -// DrawTriangleStrip - Draw a triangle strip defined by points -func DrawTriangleStrip(points []Vector2, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointsCount := (C.int)(int32(len(points))) - ccolor := colorCptr(col) - C.DrawTriangleStrip(cpoints, cpointsCount, *ccolor) -} - -// DrawPoly - Draw a regular polygon (Vector version) -func DrawPoly(center Vector2, sides int32, radius, rotation float32, col color.RGBA) { - ccenter := center.cptr() - csides := (C.int)(sides) - cradius := (C.float)(radius) - crotation := (C.float)(rotation) - ccolor := colorCptr(col) - C.DrawPoly(*ccenter, csides, cradius, crotation, *ccolor) -} - -// DrawPolyLines - Draw a polygon outline of n sides -func DrawPolyLines(center Vector2, sides int32, radius, rotation float32, col color.RGBA) { - ccenter := center.cptr() - csides := (C.int)(sides) - cradius := (C.float)(radius) - crotation := (C.float)(rotation) - ccolor := colorCptr(col) - C.DrawPolyLines(*ccenter, csides, cradius, crotation, *ccolor) -} - -// DrawPolyLinesEx - Draw a polygon outline of n sides with extended parameters -func DrawPolyLinesEx(center Vector2, sides int32, radius float32, rotation float32, lineThick float32, col color.RGBA) { - ccenter := center.cptr() - csides := (C.int)(sides) - cradius := (C.float)(radius) - crotation := (C.float)(rotation) - clineThick := (C.float)(lineThick) - ccolor := colorCptr(col) - C.DrawPolyLinesEx(*ccenter, csides, cradius, crotation, clineThick, *ccolor) -} - -// DrawSplineLinear - Draw spline: Linear, minimum 2 points -func DrawSplineLinear(points []Vector2, thick float32, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointCount := (C.int)(len(points)) - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineLinear(cpoints, cpointCount, cthick, *ccolor) -} - -// DrawSplineBasis - Draw spline: B-Spline, minimum 4 points -func DrawSplineBasis(points []Vector2, thick float32, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointCount := (C.int)(len(points)) - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineBasis(cpoints, cpointCount, cthick, *ccolor) -} - -// DrawSplineCatmullRom - Draw spline: Catmull-Rom, minimum 4 points -func DrawSplineCatmullRom(points []Vector2, thick float32, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointCount := (C.int)(len(points)) - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineCatmullRom(cpoints, cpointCount, cthick, *ccolor) -} - -// DrawSplineBezierQuadratic - Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] -func DrawSplineBezierQuadratic(points []Vector2, thick float32, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointCount := (C.int)(len(points)) - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineBezierQuadratic(cpoints, cpointCount, cthick, *ccolor) -} - -// DrawSplineBezierCubic - Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] -func DrawSplineBezierCubic(points []Vector2, thick float32, col color.RGBA) { - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - cpointCount := (C.int)(len(points)) - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineBezierCubic(cpoints, cpointCount, cthick, *ccolor) -} - -// DrawSplineSegmentLinear - Draw spline segment: Linear, 2 points -func DrawSplineSegmentLinear(p1, p2 Vector2, thick float32, col color.RGBA) { - cp1 := p1.cptr() - cp2 := p2.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineSegmentLinear(*cp1, *cp2, cthick, *ccolor) -} - -// DrawSplineSegmentBasis - Draw spline segment: B-Spline, 4 points -func DrawSplineSegmentBasis(p1, p2, p3, p4 Vector2, thick float32, col color.RGBA) { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineSegmentBasis(*cp1, *cp2, *cp3, *cp4, cthick, *ccolor) -} - -// DrawSplineSegmentCatmullRom - Draw spline segment: Catmull-Rom, 4 points -func DrawSplineSegmentCatmullRom(p1, p2, p3, p4 Vector2, thick float32, col color.RGBA) { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineSegmentCatmullRom(*cp1, *cp2, *cp3, *cp4, cthick, *ccolor) -} - -// DrawSplineSegmentBezierQuadratic - Draw spline segment: Quadratic Bezier, 2 points, 1 control point -func DrawSplineSegmentBezierQuadratic(p1, p2, p3 Vector2, thick float32, col color.RGBA) { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineSegmentBezierQuadratic(*cp1, *cp2, *cp3, cthick, *ccolor) -} - -// DrawSplineSegmentBezierCubic - Draw spline segment: Cubic Bezier, 2 points, 2 control points -func DrawSplineSegmentBezierCubic(p1, p2, p3, p4 Vector2, thick float32, col color.RGBA) { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - cthick := (C.float)(thick) - ccolor := colorCptr(col) - C.DrawSplineSegmentBezierCubic(*cp1, *cp2, *cp3, *cp4, cthick, *ccolor) -} - -// GetSplinePointLinear - Get (evaluate) spline point: Linear -func GetSplinePointLinear(p1, p2 Vector2, t float32) Vector2 { - cp1 := p1.cptr() - cp2 := p2.cptr() - ct := (C.float)(t) - ret := C.GetSplinePointLinear(*cp1, *cp2, ct) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetSplinePointBasis - Get (evaluate) spline point: B-Spline -func GetSplinePointBasis(p1, p2, p3, p4 Vector2, t float32) Vector2 { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - ct := (C.float)(t) - ret := C.GetSplinePointBasis(*cp1, *cp2, *cp3, *cp4, ct) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetSplinePointCatmullRom - Get (evaluate) spline point: Catmull-Rom -func GetSplinePointCatmullRom(p1, p2, p3, p4 Vector2, t float32) Vector2 { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - ct := (C.float)(t) - ret := C.GetSplinePointCatmullRom(*cp1, *cp2, *cp3, *cp4, ct) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetSplinePointBezierQuad - Get (evaluate) spline point: Quadratic Bezier -func GetSplinePointBezierQuad(p1, p2, p3 Vector2, t float32) Vector2 { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - ct := (C.float)(t) - ret := C.GetSplinePointBezierQuad(*cp1, *cp2, *cp3, ct) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetSplinePointBezierCubic - Get (evaluate) spline point: Cubic Bezier -func GetSplinePointBezierCubic(p1, p2, p3, p4 Vector2, t float32) Vector2 { - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - cp4 := p4.cptr() - ct := (C.float)(t) - ret := C.GetSplinePointBezierCubic(*cp1, *cp2, *cp3, *cp4, ct) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// CheckCollisionRecs - Check collision between two rectangles -func CheckCollisionRecs(rec1, rec2 Rectangle) bool { - crec1 := rec1.cptr() - crec2 := rec2.cptr() - ret := C.CheckCollisionRecs(*crec1, *crec2) - v := bool(ret) - return v -} - -// CheckCollisionCircles - Check collision between two circles -func CheckCollisionCircles(center1 Vector2, radius1 float32, center2 Vector2, radius2 float32) bool { - ccenter1 := center1.cptr() - cradius1 := (C.float)(radius1) - ccenter2 := center2.cptr() - cradius2 := (C.float)(radius2) - ret := C.CheckCollisionCircles(*ccenter1, cradius1, *ccenter2, cradius2) - v := bool(ret) - return v -} - -// CheckCollisionCircleRec - Check collision between circle and rectangle -func CheckCollisionCircleRec(center Vector2, radius float32, rec Rectangle) bool { - ccenter := center.cptr() - cradius := (C.float)(radius) - crec := rec.cptr() - ret := C.CheckCollisionCircleRec(*ccenter, cradius, *crec) - v := bool(ret) - return v -} - -// CheckCollisionCircleLine - Check if circle collides with a line created betweeen two points [p1] and [p2] -func CheckCollisionCircleLine(center Vector2, radius float32, p1, p2 Vector2) bool { - ccenter := center.cptr() - cradius := (C.float)(radius) - cp1 := p1.cptr() - cp2 := p2.cptr() - ret := C.CheckCollisionCircleLine(*ccenter, cradius, *cp1, *cp2) - v := bool(ret) - return v -} - -// CheckCollisionPointRec - Check if point is inside rectangle -func CheckCollisionPointRec(point Vector2, rec Rectangle) bool { - cpoint := point.cptr() - crec := rec.cptr() - ret := C.CheckCollisionPointRec(*cpoint, *crec) - v := bool(ret) - return v -} - -// CheckCollisionPointCircle - Check if point is inside circle -func CheckCollisionPointCircle(point Vector2, center Vector2, radius float32) bool { - cpoint := point.cptr() - ccenter := center.cptr() - cradius := (C.float)(radius) - ret := C.CheckCollisionPointCircle(*cpoint, *ccenter, cradius) - v := bool(ret) - return v -} - -// CheckCollisionPointTriangle - Check if point is inside a triangle -func CheckCollisionPointTriangle(point, p1, p2, p3 Vector2) bool { - cpoint := point.cptr() - cp1 := p1.cptr() - cp2 := p2.cptr() - cp3 := p3.cptr() - ret := C.CheckCollisionPointTriangle(*cpoint, *cp1, *cp2, *cp3) - v := bool(ret) - return v -} - -// CheckCollisionPointPoly - Check if point is within a polygon described by array of vertices -// -// NOTE: Based on http://jeffreythompson.org/collision-detection/poly-point.php -func CheckCollisionPointPoly(point Vector2, points []Vector2) bool { - cpoint := point.cptr() - cpoints := (&points[0]).cptr() - cpointCount := C.int(len(points)) - ret := C.CheckCollisionPointPoly(*cpoint, cpoints, cpointCount) - v := bool(ret) - return v -} - -// CheckCollisionLines - Check the collision between two lines defined by two points each, returns collision point by reference -func CheckCollisionLines(startPos1, endPos1, startPos2, endPos2 Vector2, point *Vector2) bool { - cstartPos1 := startPos1.cptr() - cendPos1 := endPos1.cptr() - cstartPos2 := startPos2.cptr() - cendPos2 := endPos2.cptr() - cpoint := point.cptr() - ret := C.CheckCollisionLines(*cstartPos1, *cendPos1, *cstartPos2, *cendPos2, cpoint) - v := bool(ret) - return v -} - -// CheckCollisionPointLine - Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] -func CheckCollisionPointLine(point, p1, p2 Vector2, threshold int32) bool { - cpoint := point.cptr() - cp1 := p1.cptr() - cp2 := p2.cptr() - cthreshold := (C.int)(threshold) - ret := C.CheckCollisionPointLine(*cpoint, *cp1, *cp2, cthreshold) - v := bool(ret) - return v -} - -// GetCollisionRec - Get collision rectangle for two rectangles collision -func GetCollisionRec(rec1, rec2 Rectangle) Rectangle { - crec1 := rec1.cptr() - crec2 := rec2.cptr() - ret := C.GetCollisionRec(*crec1, *crec2) - v := newRectangleFromPointer(unsafe.Pointer(&ret)) - return v -} diff --git a/raylib/rtext.c b/raylib/rtext.c deleted file mode 100644 index d7818d2..0000000 --- a/raylib/rtext.c +++ /dev/null @@ -1,2596 +0,0 @@ -/********************************************************************************************** -* -* rtext - Basic functions to load fonts and draw text -* -* CONFIGURATION: -* #define SUPPORT_MODULE_RTEXT -* rtext module is included in the build -* -* #define SUPPORT_DEFAULT_FONT -* Load default raylib font on initialization to be used by DrawText() and MeasureText(). -* If no default font loaded, DrawTextEx() and MeasureTextEx() are required. -* -* #define SUPPORT_FILEFORMAT_FNT -* #define SUPPORT_FILEFORMAT_TTF -* #define SUPPORT_FILEFORMAT_BDF -* Selected desired fileformats to be supported for loading. Some of those formats are -* supported by default, to remove support, just comment unrequired #define in this module -* -* #define SUPPORT_FONT_ATLAS_WHITE_REC -* On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle -* at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow -* drawing text and shapes with a single draw call [SetShapesTexture()]. -* -* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH -* TextSplit() function static buffer max size -* -* #define MAX_TEXTSPLIT_COUNT -* TextSplit() function static substrings pointers array (pointing to static buffer) -* -* DEPENDENCIES: -* stb_truetype - Load TTF file and rasterize characters data -* stb_rect_pack - Rectangles packing algorithms, required for font atlas generation -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#include "raylib.h" // Declares module functions - -// Check if config flags have been externally provided on compilation line -#if !defined(EXTERNAL_CONFIG_FLAGS) - #include "config.h" // Defines module configuration flags -#endif - -#if defined(SUPPORT_MODULE_RTEXT) - -#include "utils.h" // Required for: LoadFile*() -#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro() - -#include // Required for: malloc(), free() -#include // Required for: vsprintf() -#include // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] -#include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] -#include // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] - -#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF) - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" - #endif - - #define STB_RECT_PACK_IMPLEMENTATION - #include "external/stb_rect_pack.h" // Required for: ttf/bdf font rectangles packaging - - #include // Required for: ttf/bdf font rectangles packaging - - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic pop - #endif -#endif - -#if defined(SUPPORT_FILEFORMAT_TTF) - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" - #endif - - #define STBTT_STATIC - #define STB_TRUETYPE_IMPLEMENTATION - #include "external/stb_truetype.h" // Required for: ttf font data reading - - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic pop - #endif -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef MAX_TEXT_BUFFER_LENGTH - #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: - // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() -#endif -#ifndef MAX_TEXT_UNICODE_CHARS - #define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints() -#endif -#ifndef MAX_TEXTSPLIT_COUNT - #define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Global variables -//---------------------------------------------------------------------------------- -extern bool isGpuReady; -#if defined(SUPPORT_DEFAULT_FONT) -// Default font provided by raylib -// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core] -static Font defaultFont = { 0 }; -#endif - -//---------------------------------------------------------------------------------- -// Other Modules Functions Declaration (required by text) -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_FNT) -static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) -#endif -#if defined(SUPPORT_FILEFORMAT_BDF) -static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize); -#endif -static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines) - -#if defined(SUPPORT_DEFAULT_FONT) -extern void LoadFontDefault(void); -extern void UnloadFontDefault(void); -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_DEFAULT_FONT) -// Load raylib default font -extern void LoadFontDefault(void) -{ - #define BIT_CHECK(a,b) ((a) & (1u << (b))) - - // check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return - if (defaultFont.glyphs != NULL && !isGpuReady) - return; - - // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement - // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl - - defaultFont.glyphCount = 224; // Number of chars included in our default font - defaultFont.glyphPadding = 0; // Characters padding - - // Default font is directly defined here (data generated from a sprite font image) - // This way, we reconstruct Font without creating large global variables - // This data is automatically allocated to Stack and automatically deallocated at the end of this function - unsigned int defaultFontData[512] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f, - 0x4a2bf2a0, 0x0852091e, 0x41224000, 0x10041450, 0x2e292020, 0x08220812, 0x41222000, 0x10041450, 0x10f92020, 0x3efa084c, 0x7d22103c, 0x107df7de, - 0xe8a12020, 0x08220832, 0x05220800, 0x10450410, 0xa4a3f000, 0x08520832, 0x05220400, 0x10450410, 0xe2f92020, 0x0002085e, 0x7d3e0281, 0x107df41f, - 0x00200000, 0x8001b000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc0000fbe, 0xfbf7e00f, 0x5fbf7e7d, 0x0050bee8, 0x440808a2, 0x0a142fe8, 0x50810285, 0x0050a048, - 0x49e428a2, 0x0a142828, 0x40810284, 0x0048a048, 0x10020fbe, 0x09f7ebaf, 0xd89f3e84, 0x0047a04f, 0x09e48822, 0x0a142aa1, 0x50810284, 0x0048a048, - 0x04082822, 0x0a142fa0, 0x50810285, 0x0050a248, 0x00008fbe, 0xfbf42021, 0x5f817e7d, 0x07d09ce8, 0x00008000, 0x00000fe0, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000c0180, - 0xdfbf4282, 0x0bfbf7ef, 0x42850505, 0x004804bf, 0x50a142c6, 0x08401428, 0x42852505, 0x00a808a0, 0x50a146aa, 0x08401428, 0x42852505, 0x00081090, - 0x5fa14a92, 0x0843f7e8, 0x7e792505, 0x00082088, 0x40a15282, 0x08420128, 0x40852489, 0x00084084, 0x40a16282, 0x0842022a, 0x40852451, 0x00088082, - 0xc0bf4282, 0xf843f42f, 0x7e85fc21, 0x3e0900bf, 0x00000000, 0x00000004, 0x00000000, 0x000c0180, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000402, 0x41482000, 0x00000000, 0x00000800, - 0x04000404, 0x4100203c, 0x00000000, 0x00000800, 0xf7df7df0, 0x514bef85, 0xbefbefbe, 0x04513bef, 0x14414500, 0x494a2885, 0xa28a28aa, 0x04510820, - 0xf44145f0, 0x474a289d, 0xa28a28aa, 0x04510be0, 0x14414510, 0x494a2884, 0xa28a28aa, 0x02910a00, 0xf7df7df0, 0xd14a2f85, 0xbefbe8aa, 0x011f7be0, - 0x00000000, 0x00400804, 0x20080000, 0x00000000, 0x00000000, 0x00600f84, 0x20080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000f01, 0x00000000, 0x06000000, 0x24000000, 0x00000f01, 0x00000000, 0x09108000, - 0x24fa28a2, 0x00000f01, 0x00000000, 0x013e0000, 0x2242252a, 0x00000f52, 0x00000000, 0x038a8000, 0x2422222a, 0x00000f29, 0x00000000, 0x010a8000, - 0x2412252a, 0x00000f01, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000f01, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000, - 0x0003e000, 0x00000f00, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03, - 0x02bea080, 0xf0000020, 0xc452208a, 0x04202b02, 0xf8029122, 0x07f0003b, 0xe44b388e, 0x02203a02, 0x081e8a1c, 0x0411e92a, 0xf4420be0, 0x01248202, - 0xe8140414, 0x05d104ba, 0xe7c3b880, 0x00893a0a, 0x283c0e1c, 0x04500902, 0xc4400080, 0x00448002, 0xe8208422, 0x04500002, 0x80400000, 0x05200002, - 0x083e8e00, 0x04100002, 0x804003e0, 0x07000042, 0xf8008400, 0x07f00003, 0x80400000, 0x04000022, 0x00000000, 0x00000000, 0x80400000, 0x04000002, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800702, 0x1848a0c2, 0x84010000, 0x02920921, 0x01042642, 0x00005121, 0x42023f7f, 0x00291002, - 0xefc01422, 0x7efdfbf7, 0xefdfa109, 0x03bbbbf7, 0x28440f12, 0x42850a14, 0x20408109, 0x01111010, 0x28440408, 0x42850a14, 0x2040817f, 0x01111010, - 0xefc78204, 0x7efdfbf7, 0xe7cf8109, 0x011111f3, 0x2850a932, 0x42850a14, 0x2040a109, 0x01111010, 0x2850b840, 0x42850a14, 0xefdfbf79, 0x03bbbbf7, - 0x001fa020, 0x00000000, 0x00001000, 0x00000000, 0x00002070, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x08022800, 0x00012283, 0x02430802, 0x01010001, 0x8404147c, 0x20000144, 0x80048404, 0x00823f08, 0xdfbf4284, 0x7e03f7ef, 0x142850a1, 0x0000210a, - 0x50a14684, 0x528a1428, 0x142850a1, 0x03efa17a, 0x50a14a9e, 0x52521428, 0x142850a1, 0x02081f4a, 0x50a15284, 0x4a221428, 0xf42850a1, 0x03efa14b, - 0x50a16284, 0x4a521428, 0x042850a1, 0x0228a17a, 0xdfbf427c, 0x7e8bf7ef, 0xf7efdfbf, 0x03efbd0b, 0x00000000, 0x04000000, 0x00000000, 0x00000008, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200508, 0x00840400, 0x11458122, 0x00014210, - 0x00514294, 0x51420800, 0x20a22a94, 0x0050a508, 0x00200000, 0x00000000, 0x00050000, 0x08000000, 0xfefbefbe, 0xfbefbefb, 0xfbeb9114, 0x00fbefbe, - 0x20820820, 0x8a28a20a, 0x8a289114, 0x3e8a28a2, 0xfefbefbe, 0xfbefbe0b, 0x8a289114, 0x008a28a2, 0x228a28a2, 0x08208208, 0x8a289114, 0x088a28a2, - 0xfefbefbe, 0xfbefbefb, 0xfa2f9114, 0x00fbefbe, 0x00000000, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00210100, 0x00000004, 0x00000000, 0x00000000, 0x14508200, 0x00001402, 0x00000000, 0x00000000, - 0x00000010, 0x00000020, 0x00000000, 0x00000000, 0xa28a28be, 0x00002228, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, - 0xa28a28aa, 0x000022a8, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, 0xbefbefbe, 0x00003e2f, 0x00000000, 0x00000000, - 0x00000004, 0x00002028, 0x00000000, 0x00000000, 0x80000000, 0x00003e0f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; - - int charsHeight = 10; - int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically - - int charsWidth[224] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6, - 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5, - 2, 5, 5, 5, 5, 5, 4, 5, 5, 1, 2, 5, 2, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 3, 1, 3, 4, 4, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 5, 5, 5, 7, 1, 5, 3, 7, 3, 5, 4, 1, 7, 4, 3, 5, 3, 3, 2, 5, 6, 1, 2, 2, 3, 5, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 3, 3, 3, 3, 7, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 4, 6, - 5, 5, 5, 5, 5, 5, 9, 5, 5, 5, 5, 5, 2, 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5 }; - - // Re-construct image from defaultFontData and generate OpenGL texture - //---------------------------------------------------------------------- - Image imFont = { - .data = RL_CALLOC(128*128, 2), // 2 bytes per pixel (gray + alpha) - .width = 128, - .height = 128, - .mipmaps = 1, - .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA - }; - - // Fill image.data with defaultFontData (convert from bit to pixel!) - for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32) - { - for (int j = 31; j >= 0; j--) - { - if (BIT_CHECK(defaultFontData[counter], j)) - { - // NOTE: We are unreferencing data as short, so, - // we must consider data as little-endian order (alpha + gray) - ((unsigned short *)imFont.data)[i + j] = 0xffff; - } - else - { - ((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xff; - ((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00; - } - } - - counter++; - } - - if (isGpuReady) - { - defaultFont.texture = LoadTextureFromImage(imFont); - - // we have already loaded the font glyph data an image, and the GPU is ready, we are done - // if we don't do this, we will leak memory by reallocating the glyphs and rects - if (defaultFont.glyphs != NULL) - { - UnloadImage(imFont); - return; - } - } - - // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount - //------------------------------------------------------------------------------ - - // Allocate space for our characters info data - // NOTE: This memory must be freed at end! --> Done by CloseWindow() - defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo)); - defaultFont.recs = (Rectangle *)RL_CALLOC(defaultFont.glyphCount, sizeof(Rectangle)); - - int currentLine = 0; - int currentPosX = charsDivisor; - int testPosX = charsDivisor; - - for (int i = 0; i < defaultFont.glyphCount; i++) - { - defaultFont.glyphs[i].value = 32 + i; // First char is 32 - - defaultFont.recs[i].x = (float)currentPosX; - defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor)); - defaultFont.recs[i].width = (float)charsWidth[i]; - defaultFont.recs[i].height = (float)charsHeight; - - testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor); - - if (testPosX >= imFont.width) - { - currentLine++; - currentPosX = 2*charsDivisor + charsWidth[i]; - testPosX = currentPosX; - - defaultFont.recs[i].x = (float)charsDivisor; - defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor)); - } - else currentPosX = testPosX; - - // NOTE: On default font character offsets and xAdvance are not required - defaultFont.glyphs[i].offsetX = 0; - defaultFont.glyphs[i].offsetY = 0; - defaultFont.glyphs[i].advanceX = 0; - - // Fill character image data from fontClear data - defaultFont.glyphs[i].image = ImageFromImage(imFont, defaultFont.recs[i]); - } - - UnloadImage(imFont); - - defaultFont.baseSize = (int)defaultFont.recs[0].height; - - TRACELOG(LOG_INFO, "FONT: Default font loaded successfully (%i glyphs)", defaultFont.glyphCount); -} - -// Unload raylib default font -extern void UnloadFontDefault(void) -{ - for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image); - if (isGpuReady) UnloadTexture(defaultFont.texture); - RL_FREE(defaultFont.glyphs); - RL_FREE(defaultFont.recs); - defaultFont.glyphCount = 0; - defaultFont.glyphs = NULL; - defaultFont.recs = NULL; -} -#endif // SUPPORT_DEFAULT_FONT - -// Get the default font, useful to be used with extended parameters -Font GetFontDefault() -{ -#if defined(SUPPORT_DEFAULT_FONT) - return defaultFont; -#else - Font font = { 0 }; - return font; -#endif -} - -// Load Font from file into GPU memory (VRAM) -Font LoadFont(const char *fileName) -{ - // Default values for ttf font generation -#ifndef FONT_TTF_DEFAULT_SIZE - #define FONT_TTF_DEFAULT_SIZE 32 // TTF font generation default char size (char-height) -#endif -#ifndef FONT_TTF_DEFAULT_NUMCHARS - #define FONT_TTF_DEFAULT_NUMCHARS 95 // TTF font generation default charset: 95 glyphs (ASCII 32..126) -#endif -#ifndef FONT_TTF_DEFAULT_FIRST_CHAR - #define FONT_TTF_DEFAULT_FIRST_CHAR 32 // TTF font generation default first char for image sprite font (32-Space) -#endif -#ifndef FONT_TTF_DEFAULT_CHARS_PADDING - #define FONT_TTF_DEFAULT_CHARS_PADDING 4 // TTF font generation default chars padding -#endif - - Font font = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS); - else -#endif -#if defined(SUPPORT_FILEFORMAT_FNT) - if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName); - else -#endif -#if defined(SUPPORT_FILEFORMAT_BDF) - if (IsFileExtension(fileName, ".bdf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS); - else -#endif - { - Image image = LoadImage(fileName); - if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR); - UnloadImage(image); - } - - if (isGpuReady) - { - if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName); - else - { - SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance) - TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS); - } - } - - return font; -} - -// Load Font from TTF or BDF font file with generation parameters -// NOTE: You can pass an array with desired characters, those characters should be available in the font -// if array is NULL, default char set is selected 32..126 -Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount) -{ - Font font = { 0 }; - - // Loading file to memory - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); - - if (fileData != NULL) - { - // Loading font from memory data - font = LoadFontFromMemory(GetFileExtension(fileName), fileData, dataSize, fontSize, codepoints, codepointCount); - - UnloadFileData(fileData); - } - - return font; -} - -// Load an Image font file (XNA style) -Font LoadFontFromImage(Image image, Color key, int firstChar) -{ -#ifndef MAX_GLYPHS_FROM_IMAGE - #define MAX_GLYPHS_FROM_IMAGE 256 // Maximum number of glyphs supported on image scan -#endif - - #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)) - - Font font = GetFontDefault(); - - int charSpacing = 0; - int lineSpacing = 0; - - int x = 0; - int y = 0; - - // We allocate a temporal arrays for chars data measures, - // once we get the actual number of chars, we copy data to a sized arrays - int tempCharValues[MAX_GLYPHS_FROM_IMAGE] = { 0 }; - Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE] = { 0 }; - - Color *pixels = LoadImageColors(image); - - // Parse image data to get charSpacing and lineSpacing - for (y = 0; y < image.height; y++) - { - for (x = 0; x < image.width; x++) - { - if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break; - } - - if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break; - } - - if ((x == 0) || (y == 0)) return font; // Security check - - charSpacing = x; - lineSpacing = y; - - int charHeight = 0; - int j = 0; - - while (!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++; - - charHeight = j; - - // Check array values to get characters: value, x, y, w, h - int index = 0; - int lineToRead = 0; - int xPosToRead = charSpacing; - - // Parse image data to get rectangle sizes - while ((lineSpacing + lineToRead*(charHeight + lineSpacing)) < image.height) - { - while ((xPosToRead < image.width) && - !COLOR_EQUAL((pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead]), key)) - { - tempCharValues[index] = firstChar + index; - - tempCharRecs[index].x = (float)xPosToRead; - tempCharRecs[index].y = (float)(lineSpacing + lineToRead*(charHeight + lineSpacing)); - tempCharRecs[index].height = (float)charHeight; - - int charWidth = 0; - - while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++; - - tempCharRecs[index].width = (float)charWidth; - - index++; - - xPosToRead += (charWidth + charSpacing); - } - - lineToRead++; - xPosToRead = charSpacing; - } - - // NOTE: We need to remove key color borders from image to avoid weird - // artifacts on texture scaling when using TEXTURE_FILTER_BILINEAR or TEXTURE_FILTER_TRILINEAR - for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK; - - // Create a new image with the processed color data (key color replaced by BLANK) - Image fontClear = { - .data = pixels, - .width = image.width, - .height = image.height, - .mipmaps = 1, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 - }; - - // Set font with all data parsed from image - if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture - font.glyphCount = index; - font.glyphPadding = 0; - - // We got tempCharValues and tempCharsRecs populated with chars data - // Now we move temp data to sized charValues and charRecs arrays - font.glyphs = (GlyphInfo *)RL_MALLOC(font.glyphCount*sizeof(GlyphInfo)); - font.recs = (Rectangle *)RL_MALLOC(font.glyphCount*sizeof(Rectangle)); - - for (int i = 0; i < font.glyphCount; i++) - { - font.glyphs[i].value = tempCharValues[i]; - - // Get character rectangle in the font atlas texture - font.recs[i] = tempCharRecs[i]; - - // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) - font.glyphs[i].offsetX = 0; - font.glyphs[i].offsetY = 0; - font.glyphs[i].advanceX = 0; - - // Fill character image data from fontClear data - font.glyphs[i].image = ImageFromImage(fontClear, tempCharRecs[i]); - } - - UnloadImage(fontClear); // Unload processed image once converted to texture - - font.baseSize = (int)font.recs[0].height; - - return font; -} - -// Load font from memory buffer, fileType refers to extension: i.e. ".ttf" -Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount) -{ - Font font = { 0 }; - - char fileExtLower[16] = { 0 }; - strncpy(fileExtLower, TextToLower(fileType), 16 - 1); - - font.baseSize = fontSize; - font.glyphCount = (codepointCount > 0)? codepointCount : 95; - font.glyphPadding = 0; - -#if defined(SUPPORT_FILEFORMAT_TTF) - if (TextIsEqual(fileExtLower, ".ttf") || - TextIsEqual(fileExtLower, ".otf")) - { - font.glyphs = LoadFontData(fileData, dataSize, font.baseSize, codepoints, font.glyphCount, FONT_DEFAULT); - } - else -#endif -#if defined(SUPPORT_FILEFORMAT_BDF) - if (TextIsEqual(fileExtLower, ".bdf")) - { - font.glyphs = LoadFontDataBDF(fileData, dataSize, codepoints, font.glyphCount, &font.baseSize); - } - else -#endif - { - font.glyphs = NULL; - } - -#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF) - if (font.glyphs != NULL) - { - font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING; - - Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0); - if (isGpuReady) font.texture = LoadTextureFromImage(atlas); - - // Update glyphs[i].image to use alpha, required to be used on ImageDrawText() - for (int i = 0; i < font.glyphCount; i++) - { - UnloadImage(font.glyphs[i].image); - font.glyphs[i].image = ImageFromImage(atlas, font.recs[i]); - } - - UnloadImage(atlas); - - TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount); - } - else font = GetFontDefault(); -#else - font = GetFontDefault(); -#endif - - return font; -} - -// Check if a font is valid (font data loaded) -// WARNING: GPU texture not checked -bool IsFontValid(Font font) -{ - return ((font.baseSize > 0) && // Validate font size - (font.glyphCount > 0) && // Validate font contains some glyph - (font.recs != NULL) && // Validate font recs defining glyphs on texture atlas - (font.glyphs != NULL)); // Validate glyph data is loaded - - // NOTE: Further validations could be done to verify if recs and glyphs contain valid data (glyphs values, metrics...) -} - -// Load font data for further use -// NOTE: Requires TTF font memory data and can generate SDF data -GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type) -{ - // NOTE: Using some SDF generation default values, - // trades off precision with ability to handle *smaller* sizes -#ifndef FONT_SDF_CHAR_PADDING - #define FONT_SDF_CHAR_PADDING 4 // SDF font generation char padding -#endif -#ifndef FONT_SDF_ON_EDGE_VALUE - #define FONT_SDF_ON_EDGE_VALUE 128 // SDF font generation on edge value -#endif -#ifndef FONT_SDF_PIXEL_DIST_SCALE - #define FONT_SDF_PIXEL_DIST_SCALE 64.0f // SDF font generation pixel distance scale -#endif -#ifndef FONT_BITMAP_ALPHA_THRESHOLD - #define FONT_BITMAP_ALPHA_THRESHOLD 80 // Bitmap (B&W) font generation alpha threshold -#endif - - GlyphInfo *chars = NULL; - -#if defined(SUPPORT_FILEFORMAT_TTF) - // Load font data (including pixel data) from TTF memory file - // NOTE: Loaded information should be enough to generate font image atlas, using any packaging method - if (fileData != NULL) - { - bool genFontChars = false; - stbtt_fontinfo fontInfo = { 0 }; - - if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0)) // Initialize font for data reading - { - // Calculate font scale factor - float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize); - - // Calculate font basic metrics - // NOTE: ascent is equivalent to font baseline - int ascent, descent, lineGap; - stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); - - // In case no chars count provided, default to 95 - codepointCount = (codepointCount > 0)? codepointCount : 95; - - // Fill fontChars in case not provided externally - // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space) - if (codepoints == NULL) - { - codepoints = (int *)RL_MALLOC(codepointCount*sizeof(int)); - for (int i = 0; i < codepointCount; i++) codepoints[i] = i + 32; - genFontChars = true; - } - - chars = (GlyphInfo *)RL_CALLOC(codepointCount, sizeof(GlyphInfo)); - - // NOTE: Using simple packaging, one char after another - for (int i = 0; i < codepointCount; i++) - { - int chw = 0, chh = 0; // Character width and height (on generation) - int ch = codepoints[i]; // Character value to get info for - chars[i].value = ch; - - // Render a unicode codepoint to a bitmap - // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap - // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be - // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide - - // Check if a glyph is available in the font - // WARNING: if (index == 0), glyph not found, it could fallback to default .notdef glyph (if defined in font) - int index = stbtt_FindGlyphIndex(&fontInfo, ch); - - if (index > 0) - { - switch (type) - { - case FONT_DEFAULT: - case FONT_BITMAP: chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); break; - case FONT_SDF: if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); break; - default: break; - } - - if (chars[i].image.data != NULL) // Glyph data has been found in the font - { - stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); - chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor); - - if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch); - - // Load characters images - chars[i].image.width = chw; - chars[i].image.height = chh; - chars[i].image.mipmaps = 1; - chars[i].image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - - chars[i].offsetY += (int)((float)ascent*scaleFactor); - } - - // NOTE: We create an empty image for space character, - // it could be further required for atlas packing - if (ch == 32) - { - stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); - chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor); - - Image imSpace = { - .data = RL_CALLOC(chars[i].advanceX*fontSize, 2), - .width = chars[i].advanceX, - .height = fontSize, - .mipmaps = 1, - .format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE - }; - - chars[i].image = imSpace; - } - - if (type == FONT_BITMAP) - { - // Aliased bitmap (black & white) font generation, avoiding anti-aliasing - // NOTE: For optimum results, bitmap font should be generated at base pixel size - for (int p = 0; p < chw*chh; p++) - { - if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0; - else ((unsigned char *)chars[i].image.data)[p] = 255; - } - } - } - else - { - // TODO: Use some fallback glyph for codepoints not found in the font - } - } - } - else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data"); - - if (genFontChars) RL_FREE(codepoints); - } -#endif - - return chars; -} - -// Generate image font atlas using chars info -// NOTE: Packing method: 0-Default, 1-Skyline -#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF) -Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod) -{ - Image atlas = { 0 }; - - if (glyphs == NULL) - { - TRACELOG(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas"); - return atlas; - } - - *glyphRecs = NULL; - - // In case no chars count provided we suppose default of 95 - glyphCount = (glyphCount > 0)? glyphCount : 95; - - // NOTE: Rectangles memory is loaded here! - Rectangle *recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle)); - - // Calculate image size based on total glyph width and glyph row count - int totalWidth = 0; - int maxGlyphWidth = 0; - - for (int i = 0; i < glyphCount; i++) - { - if (glyphs[i].image.width > maxGlyphWidth) maxGlyphWidth = glyphs[i].image.width; - totalWidth += glyphs[i].image.width + 2*padding; - } - -//#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE -#if defined(SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE) - int rowCount = 0; - int imageSize = 64; // Define minimum starting value to avoid unnecessary calculation steps for very small images - - // NOTE: maxGlyphWidth is maximum possible space left at the end of row - while (totalWidth > (imageSize - maxGlyphWidth)*rowCount) - { - imageSize *= 2; // Double the size of image (to keep POT) - rowCount = imageSize/(fontSize + 2*padding); // Calculate new row count for the new image size - } - - atlas.width = imageSize; // Atlas bitmap width - atlas.height = imageSize; // Atlas bitmap height -#else - int paddedFontSize = fontSize + 2*padding; - // No need for a so-conservative atlas generation - float totalArea = totalWidth*paddedFontSize*1.2f; - float imageMinSize = sqrtf(totalArea); - int imageSize = (int)powf(2, ceilf(logf(imageMinSize)/logf(2))); - - if (totalArea < ((imageSize*imageSize)/2)) - { - atlas.width = imageSize; // Atlas bitmap width - atlas.height = imageSize/2; // Atlas bitmap height - } - else - { - atlas.width = imageSize; // Atlas bitmap width - atlas.height = imageSize; // Atlas bitmap height - } -#endif - - atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) - atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - atlas.mipmaps = 1; - - // DEBUG: We can see padding in the generated image setting a gray background... - //for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100; - - if (packMethod == 0) // Use basic packing algorithm - { - int offsetX = padding; - int offsetY = padding; - - // NOTE: Using simple packaging, one char after another - for (int i = 0; i < glyphCount; i++) - { - // Check remaining space for glyph - if (offsetX >= (atlas.width - glyphs[i].image.width - 2*padding)) - { - offsetX = padding; - - // NOTE: Be careful on offsetY for SDF fonts, by default SDF - // use an internal padding of 4 pixels, it means char rectangle - // height is bigger than fontSize, it could be up to (fontSize + 8) - offsetY += (fontSize + 2*padding); - - if (offsetY > (atlas.height - fontSize - padding)) - { - for (int j = i + 1; j < glyphCount; j++) - { - TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", j); - // Make sure remaining recs contain valid data - recs[j].x = 0; - recs[j].y = 0; - recs[j].width = 0; - recs[j].height = 0; - } - break; - } - } - - // Copy pixel data from glyph image to atlas - for (int y = 0; y < glyphs[i].image.height; y++) - { - for (int x = 0; x < glyphs[i].image.width; x++) - { - ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x]; - } - } - - // Fill chars rectangles in atlas info - recs[i].x = (float)offsetX; - recs[i].y = (float)offsetY; - recs[i].width = (float)glyphs[i].image.width; - recs[i].height = (float)glyphs[i].image.height; - - // Move atlas position X for next character drawing - offsetX += (glyphs[i].image.width + 2*padding); - } - } - else if (packMethod == 1) // Use Skyline rect packing algorithm (stb_pack_rect) - { - stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context)); - stbrp_node *nodes = (stbrp_node *)RL_MALLOC(glyphCount*sizeof(*nodes)); - - stbrp_init_target(context, atlas.width, atlas.height, nodes, glyphCount); - stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(glyphCount*sizeof(stbrp_rect)); - - // Fill rectangles for packaging - for (int i = 0; i < glyphCount; i++) - { - rects[i].id = i; - rects[i].w = glyphs[i].image.width + 2*padding; - rects[i].h = glyphs[i].image.height + 2*padding; - } - - // Package rectangles into atlas - stbrp_pack_rects(context, rects, glyphCount); - - for (int i = 0; i < glyphCount; i++) - { - // It returns char rectangles in atlas - recs[i].x = rects[i].x + (float)padding; - recs[i].y = rects[i].y + (float)padding; - recs[i].width = (float)glyphs[i].image.width; - recs[i].height = (float)glyphs[i].image.height; - - if (rects[i].was_packed) - { - // Copy pixel data from fc.data to atlas - for (int y = 0; y < glyphs[i].image.height; y++) - { - for (int x = 0; x < glyphs[i].image.width; x++) - { - ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x]; - } - } - } - else TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", i); - } - - RL_FREE(rects); - RL_FREE(nodes); - RL_FREE(context); - } - -#if defined(SUPPORT_FONT_ATLAS_WHITE_REC) - // Add a 3x3 white rectangle at the bottom-right corner of the generated atlas, - // useful to use as the white texture to draw shapes with raylib, using this rectangle - // shapes and text can be backed into a single draw call: SetShapesTexture() - for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++) - { - ((unsigned char *)atlas.data)[k - 0] = 255; - ((unsigned char *)atlas.data)[k - 1] = 255; - ((unsigned char *)atlas.data)[k - 2] = 255; - k -= atlas.width; - } -#endif - - // Convert image data from GRAYSCALE to GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels - - for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2) - { - dataGrayAlpha[k] = 255; - dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i]; - } - - RL_FREE(atlas.data); - atlas.data = dataGrayAlpha; - atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; - - *glyphRecs = recs; - - return atlas; -} -#endif - -// Unload font glyphs info data (RAM) -void UnloadFontData(GlyphInfo *glyphs, int glyphCount) -{ - if (glyphs != NULL) - { - for (int i = 0; i < glyphCount; i++) UnloadImage(glyphs[i].image); - - RL_FREE(glyphs); - } -} - -// Unload Font from GPU memory (VRAM) -void UnloadFont(Font font) -{ - // NOTE: Make sure font is not default font (fallback) - if (font.texture.id != GetFontDefault().texture.id) - { - UnloadFontData(font.glyphs, font.glyphCount); - if (isGpuReady) UnloadTexture(font.texture); - RL_FREE(font.recs); - - TRACELOGD("FONT: Unloaded font data from RAM and VRAM"); - } -} - -// Export font as code file, returns true on success -bool ExportFontAsCode(Font font, const char *fileName) -{ - bool success = false; - -#ifndef TEXT_BYTES_PER_LINE - #define TEXT_BYTES_PER_LINE 20 -#endif - - #define MAX_FONT_DATA_SIZE 1024*1024 // 1 MB - - // Get file name from path - char fileNamePascal[256] = { 0 }; - strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1); - - // NOTE: Text data buffer size is estimated considering image data size in bytes - // and requiring 6 char bytes for every byte: "0x00, " - char *txtData = (char *)RL_CALLOC(MAX_FONT_DATA_SIZE, sizeof(char)); - - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// FontAsCode exporter v1.0 - Font data exported as an array of bytes //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); - byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// TODO: Fill the information and license of the exported font here: //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Font name: .... //\n"); - byteCount += sprintf(txtData + byteCount, "// Font creator: .... //\n"); - byteCount += sprintf(txtData + byteCount, "// Font LICENSE: .... //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); - - // Support font export and initialization - // NOTE: This mechanism is highly coupled to raylib - Image image = LoadImageFromTexture(font.texture); - if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!"); - int imageDataSize = GetPixelDataSize(image.width, image.height, image.format); - - // Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE - //ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE); - -#define SUPPORT_COMPRESSED_FONT_ATLAS -#if defined(SUPPORT_COMPRESSED_FONT_ATLAS) - // WARNING: Data is compressed using raylib CompressData() DEFLATE, - // it requires to be decompressed with raylib DecompressData(), that requires - // compiling raylib with SUPPORT_COMPRESSION_API config flag enabled - - // Compress font image data - int compDataSize = 0; - unsigned char *compData = CompressData((const unsigned char *)image.data, imageDataSize, &compDataSize); - - // Save font image data (compressed) - byteCount += sprintf(txtData + byteCount, "#define COMPRESSED_DATA_SIZE_FONT_%s %i\n\n", TextToUpper(fileNamePascal), compDataSize); - byteCount += sprintf(txtData + byteCount, "// Font image pixels data compressed (DEFLATE)\n"); - byteCount += sprintf(txtData + byteCount, "// NOTE: Original pixel data simplified to GRAYSCALE\n"); - byteCount += sprintf(txtData + byteCount, "static unsigned char fontData_%s[COMPRESSED_DATA_SIZE_FONT_%s] = { ", fileNamePascal, TextToUpper(fileNamePascal)); - for (int i = 0; i < compDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n " : "0x%02x, "), compData[i]); - byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", compData[compDataSize - 1]); - RL_FREE(compData); -#else - // Save font image data (uncompressed) - byteCount += sprintf(txtData + byteCount, "// Font image pixels data\n"); - byteCount += sprintf(txtData + byteCount, "// NOTE: 2 bytes per pixel, GRAY + ALPHA channels\n"); - byteCount += sprintf(txtData + byteCount, "static unsigned char fontImageData_%s[%i] = { ", fileNamePascal, imageDataSize); - for (int i = 0; i < imageDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n " : "0x%02x, "), ((unsigned char *)imFont.data)[i]); - byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", ((unsigned char *)imFont.data)[imageDataSize - 1]); -#endif - - // Save font recs data - byteCount += sprintf(txtData + byteCount, "// Font characters rectangles data\n"); - byteCount += sprintf(txtData + byteCount, "static Rectangle fontRecs_%s[%i] = {\n", fileNamePascal, font.glyphCount); - for (int i = 0; i < font.glyphCount; i++) - { - byteCount += sprintf(txtData + byteCount, " { %1.0f, %1.0f, %1.0f , %1.0f },\n", font.recs[i].x, font.recs[i].y, font.recs[i].width, font.recs[i].height); - } - byteCount += sprintf(txtData + byteCount, "};\n\n"); - - // Save font glyphs data - // NOTE: Glyphs image data not saved (grayscale pixels), - // it could be generated from image and recs - byteCount += sprintf(txtData + byteCount, "// Font glyphs info data\n"); - byteCount += sprintf(txtData + byteCount, "// NOTE: No glyphs.image data provided\n"); - byteCount += sprintf(txtData + byteCount, "static GlyphInfo fontGlyphs_%s[%i] = {\n", fileNamePascal, font.glyphCount); - for (int i = 0; i < font.glyphCount; i++) - { - byteCount += sprintf(txtData + byteCount, " { %i, %i, %i, %i, { 0 }},\n", font.glyphs[i].value, font.glyphs[i].offsetX, font.glyphs[i].offsetY, font.glyphs[i].advanceX); - } - byteCount += sprintf(txtData + byteCount, "};\n\n"); - - // Custom font loading function - byteCount += sprintf(txtData + byteCount, "// Font loading function: %s\n", fileNamePascal); - byteCount += sprintf(txtData + byteCount, "static Font LoadFont_%s(void)\n{\n", fileNamePascal); - byteCount += sprintf(txtData + byteCount, " Font font = { 0 };\n\n"); - byteCount += sprintf(txtData + byteCount, " font.baseSize = %i;\n", font.baseSize); - byteCount += sprintf(txtData + byteCount, " font.glyphCount = %i;\n", font.glyphCount); - byteCount += sprintf(txtData + byteCount, " font.glyphPadding = %i;\n\n", font.glyphPadding); - byteCount += sprintf(txtData + byteCount, " // Custom font loading\n"); -#if defined(SUPPORT_COMPRESSED_FONT_ATLAS) - byteCount += sprintf(txtData + byteCount, " // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function\n"); - byteCount += sprintf(txtData + byteCount, " int fontDataSize_%s = 0;\n", fileNamePascal); - byteCount += sprintf(txtData + byteCount, " unsigned char *data = DecompressData(fontData_%s, COMPRESSED_DATA_SIZE_FONT_%s, &fontDataSize_%s);\n", fileNamePascal, TextToUpper(fileNamePascal), fileNamePascal); - byteCount += sprintf(txtData + byteCount, " Image imFont = { data, %i, %i, 1, %i };\n\n", image.width, image.height, image.format); -#else - byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format); -#endif - byteCount += sprintf(txtData + byteCount, " // Load texture from image\n"); - byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n"); -#if defined(SUPPORT_COMPRESSED_FONT_ATLAS) - byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n"); -#endif - // We have two possible mechanisms to assign font.recs and font.glyphs data, - // that data is already available as global arrays, we two options to assign that data: - // - 1. Data copy. This option consumes more memory and Font MUST be unloaded by user, requiring additional code - // - 2. Data assignment. This option consumes less memory and Font MUST NOT be unloaded by user because data is on protected DATA segment -//#define SUPPORT_FONT_DATA_COPY -#if defined(SUPPORT_FONT_DATA_COPY) - byteCount += sprintf(txtData + byteCount, " // Copy glyph recs data from global fontRecs\n"); - byteCount += sprintf(txtData + byteCount, " // NOTE: Required to avoid issues if trying to free font\n"); - byteCount += sprintf(txtData + byteCount, " font.recs = (Rectangle *)malloc(font.glyphCount*sizeof(Rectangle));\n"); - byteCount += sprintf(txtData + byteCount, " memcpy(font.recs, fontRecs_%s, font.glyphCount*sizeof(Rectangle));\n\n", fileNamePascal); - - byteCount += sprintf(txtData + byteCount, " // Copy font glyph info data from global fontChars\n"); - byteCount += sprintf(txtData + byteCount, " // NOTE: Required to avoid issues if trying to free font\n"); - byteCount += sprintf(txtData + byteCount, " font.glyphs = (GlyphInfo *)malloc(font.glyphCount*sizeof(GlyphInfo));\n"); - byteCount += sprintf(txtData + byteCount, " memcpy(font.glyphs, fontGlyphs_%s, font.glyphCount*sizeof(GlyphInfo));\n\n", fileNamePascal); -#else - byteCount += sprintf(txtData + byteCount, " // Assign glyph recs and info data directly\n"); - byteCount += sprintf(txtData + byteCount, " // WARNING: This font data must not be unloaded\n"); - byteCount += sprintf(txtData + byteCount, " font.recs = fontRecs_%s;\n", fileNamePascal); - byteCount += sprintf(txtData + byteCount, " font.glyphs = fontGlyphs_%s;\n\n", fileNamePascal); -#endif - byteCount += sprintf(txtData + byteCount, " return font;\n"); - byteCount += sprintf(txtData + byteCount, "}\n"); - - UnloadImage(image); - - // NOTE: Text data size exported is determined by '\0' (NULL) character - success = SaveFileText(fileName, txtData); - - RL_FREE(txtData); - - if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName); - else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fileName); - - return success; -} - -// Draw current FPS -// NOTE: Uses default font -void DrawFPS(int posX, int posY) -{ - Color color = LIME; // Good FPS - int fps = GetFPS(); - - if ((fps < 30) && (fps >= 15)) color = ORANGE; // Warning FPS - else if (fps < 15) color = RED; // Low FPS - - DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, color); -} - -// Draw text (using default font) -// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used -// NOTE: chars spacing is proportional to fontSize -void DrawText(const char *text, int posX, int posY, int fontSize, Color color) -{ - // Check if default font has been loaded - if (GetFontDefault().texture.id != 0) - { - Vector2 position = { (float)posX, (float)posY }; - - int defaultFontSize = 10; // Default Font chars height in pixel - if (fontSize < defaultFontSize) fontSize = defaultFontSize; - int spacing = fontSize/defaultFontSize; - - DrawTextEx(GetFontDefault(), text, position, (float)fontSize, (float)spacing, color); - } -} - -// Draw text using Font -// NOTE: chars spacing is NOT proportional to fontSize -void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint) -{ - if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font - - int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop - - float textOffsetY = 0; // Offset between lines (on linebreak '\n') - float textOffsetX = 0.0f; // Offset X to next character to draw - - float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor - - for (int i = 0; i < size;) - { - // Get next codepoint from byte string and glyph index in font - int codepointByteCount = 0; - int codepoint = GetCodepointNext(&text[i], &codepointByteCount); - int index = GetGlyphIndex(font, codepoint); - - if (codepoint == '\n') - { - // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup - textOffsetY += (fontSize + textLineSpacing); - textOffsetX = 0.0f; - } - else - { - if ((codepoint != ' ') && (codepoint != '\t')) - { - DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint); - } - - if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing); - else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing); - } - - i += codepointByteCount; // Move text bytes counter to next codepoint - } -} - -// Draw text using Font and pro parameters (rotation) -void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint) -{ - rlPushMatrix(); - - rlTranslatef(position.x, position.y, 0.0f); - rlRotatef(rotation, 0.0f, 0.0f, 1.0f); - rlTranslatef(-origin.x, -origin.y, 0.0f); - - DrawTextEx(font, text, (Vector2){ 0.0f, 0.0f }, fontSize, spacing, tint); - - rlPopMatrix(); -} - -// Draw one character (codepoint) -void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint) -{ - // Character index position in sprite font - // NOTE: In case a codepoint is not available in the font, index returned points to '?' - int index = GetGlyphIndex(font, codepoint); - float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor - - // Character destination rectangle on screen - // NOTE: We consider glyphPadding on drawing - Rectangle dstRec = { position.x + font.glyphs[index].offsetX*scaleFactor - (float)font.glyphPadding*scaleFactor, - position.y + font.glyphs[index].offsetY*scaleFactor - (float)font.glyphPadding*scaleFactor, - (font.recs[index].width + 2.0f*font.glyphPadding)*scaleFactor, - (font.recs[index].height + 2.0f*font.glyphPadding)*scaleFactor }; - - // Character source rectangle from font texture atlas - // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects - Rectangle srcRec = { font.recs[index].x - (float)font.glyphPadding, font.recs[index].y - (float)font.glyphPadding, - font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding }; - - // Draw the character texture on the screen - DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint); -} - -// Draw multiple character (codepoints) -void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint) -{ - float textOffsetY = 0; // Offset between lines (on linebreak '\n') - float textOffsetX = 0.0f; // Offset X to next character to draw - - float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor - - for (int i = 0; i < codepointCount; i++) - { - int index = GetGlyphIndex(font, codepoints[i]); - - if (codepoints[i] == '\n') - { - // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup - textOffsetY += (fontSize + textLineSpacing); - textOffsetX = 0.0f; - } - else - { - if ((codepoints[i] != ' ') && (codepoints[i] != '\t')) - { - DrawTextCodepoint(font, codepoints[i], (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint); - } - - if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing); - else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing); - } - } -} - -// Set vertical line spacing when drawing with line-breaks -void SetTextLineSpacing(int spacing) -{ - textLineSpacing = spacing; -} - -// Measure string width for default font -int MeasureText(const char *text, int fontSize) -{ - Vector2 textSize = { 0.0f, 0.0f }; - - // Check if default font has been loaded - if (GetFontDefault().texture.id != 0) - { - int defaultFontSize = 10; // Default Font chars height in pixel - if (fontSize < defaultFontSize) fontSize = defaultFontSize; - int spacing = fontSize/defaultFontSize; - - textSize = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing); - } - - return (int)textSize.x; -} - -// Measure string size for Font -Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing) -{ - Vector2 textSize = { 0 }; - - if ((isGpuReady && (font.texture.id == 0)) || - (text == NULL) || (text[0] == '\0')) return textSize; // Security check - - int size = TextLength(text); // Get size in bytes of text - int tempByteCounter = 0; // Used to count longer text line num chars - int byteCounter = 0; - - float textWidth = 0.0f; - float tempTextWidth = 0.0f; // Used to count longer text line width - - float textHeight = fontSize; - float scaleFactor = fontSize/(float)font.baseSize; - - int letter = 0; // Current character - int index = 0; // Index position in sprite font - - for (int i = 0; i < size;) - { - byteCounter++; - - int codepointByteCount = 0; - letter = GetCodepointNext(&text[i], &codepointByteCount); - index = GetGlyphIndex(font, letter); - - i += codepointByteCount; - - if (letter != '\n') - { - if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX; - else textWidth += (font.recs[index].width + font.glyphs[index].offsetX); - } - else - { - if (tempTextWidth < textWidth) tempTextWidth = textWidth; - byteCounter = 0; - textWidth = 0; - - // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup - textHeight += (fontSize + textLineSpacing); - } - - if (tempByteCounter < byteCounter) tempByteCounter = byteCounter; - } - - if (tempTextWidth < textWidth) tempTextWidth = textWidth; - - textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); - textSize.y = textHeight; - - return textSize; -} - -// Get index position for a unicode character on font -// NOTE: If codepoint is not found in the font it fallbacks to '?' -int GetGlyphIndex(Font font, int codepoint) -{ - int index = 0; - if (!IsFontValid(font)) return index; - -#define SUPPORT_UNORDERED_CHARSET -#if defined(SUPPORT_UNORDERED_CHARSET) - int fallbackIndex = 0; // Get index of fallback glyph '?' - - // Look for character index in the unordered charset - for (int i = 0; i < font.glyphCount; i++) - { - if (font.glyphs[i].value == 63) fallbackIndex = i; - - if (font.glyphs[i].value == codepoint) - { - index = i; - break; - } - } - - if ((index == 0) && (font.glyphs[0].value != codepoint)) index = fallbackIndex; -#else - index = codepoint - 32; -#endif - - return index; -} - -// Get glyph font info data for a codepoint (unicode character) -// NOTE: If codepoint is not found in the font it fallbacks to '?' -GlyphInfo GetGlyphInfo(Font font, int codepoint) -{ - GlyphInfo info = { 0 }; - - info = font.glyphs[GetGlyphIndex(font, codepoint)]; - - return info; -} - -// Get glyph rectangle in font atlas for a codepoint (unicode character) -// NOTE: If codepoint is not found in the font it fallbacks to '?' -Rectangle GetGlyphAtlasRec(Font font, int codepoint) -{ - Rectangle rec = { 0 }; - - rec = font.recs[GetGlyphIndex(font, codepoint)]; - - return rec; -} - -//---------------------------------------------------------------------------------- -// Text strings management functions -//---------------------------------------------------------------------------------- -// Get text length in bytes, check for \0 character -unsigned int TextLength(const char *text) -{ - unsigned int length = 0; - - if (text != NULL) - { - // NOTE: Alternative: use strlen(text) - - while (*text++) length++; - } - - return length; -} - -// Formatting of text with variables to 'embed' -// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times -const char *TextFormat(const char *text, ...) -{ -#ifndef MAX_TEXTFORMAT_BUFFERS - #define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting -#endif - - // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations - static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 }; - static int index = 0; - - char *currentBuffer = buffers[index]; - memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using - - va_list args; - va_start(args, text); - int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); - va_end(args); - - // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured - if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) - { - // Inserting "..." at the end of the string to mark as truncated - char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" - sprintf(truncBuffer, "..."); - } - - index += 1; // Move to next buffer for next function call - if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; - - return currentBuffer; -} - -// Get integer value from text -// NOTE: This function replaces atoi() [stdlib.h] -int TextToInteger(const char *text) -{ - int value = 0; - int sign = 1; - - if ((text[0] == '+') || (text[0] == '-')) - { - if (text[0] == '-') sign = -1; - text++; - } - - for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); - - return value*sign; -} - -// Get float value from text -// NOTE: This function replaces atof() [stdlib.h] -// WARNING: Only '.' character is understood as decimal point -float TextToFloat(const char *text) -{ - float value = 0.0f; - float sign = 1.0f; - - if ((text[0] == '+') || (text[0] == '-')) - { - if (text[0] == '-') sign = -1.0f; - text++; - } - - int i = 0; - for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); - - if (text[i++] == '.') - { - float divisor = 10.0f; - for (; ((text[i] >= '0') && (text[i] <= '9')); i++) - { - value += ((float)(text[i] - '0'))/divisor; - divisor = divisor*10.0f; - } - } - - return value*sign; -} - -#if defined(SUPPORT_TEXT_MANIPULATION) -// Copy one string to another, returns bytes copied -int TextCopy(char *dst, const char *src) -{ - int bytes = 0; - - if ((src != NULL) && (dst != NULL)) - { - // NOTE: Alternative: use strcpy(dst, src) - - while (*src != '\0') - { - *dst = *src; - dst++; - src++; - - bytes++; - } - - *dst = '\0'; - } - - return bytes; -} - -// Check if two text string are equal -// REQUIRES: strcmp() -bool TextIsEqual(const char *text1, const char *text2) -{ - bool result = false; - - if ((text1 != NULL) && (text2 != NULL)) - { - if (strcmp(text1, text2) == 0) result = true; - } - - return result; -} - -// Get a piece of a text string -const char *TextSubtext(const char *text, int position, int length) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - int textLength = TextLength(text); - - if (position >= textLength) - { - return buffer; //First char is already '\0' by memset - } - - int maxLength = textLength - position; - if (length > maxLength) length = maxLength; - if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1; - - // NOTE: Alternative: memcpy(buffer, text + position, length) - - for (int c = 0 ; c < length ; c++) - { - buffer[c] = text[position + c]; - } - - buffer[length] = '\0'; - - return buffer; -} - -// Replace text string -// REQUIRES: strstr(), strncpy(), strcpy() -// WARNING: Allocated memory must be manually freed -char *TextReplace(const char *text, const char *replace, const char *by) -{ - // Sanity checks and initialization - if (!text || !replace || !by) return NULL; - - char *result = NULL; - - char *insertPoint = NULL; // Next insert point - char *temp = NULL; // Temp pointer - int replaceLen = 0; // Replace string length of (the string to remove) - int byLen = 0; // Replacement length (the string to replace by) - int lastReplacePos = 0; // Distance between replace and end of last replace - int count = 0; // Number of replacements - - replaceLen = TextLength(replace); - if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count - - byLen = TextLength(by); - - // Count the number of replacements needed - insertPoint = (char *)text; - for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen; - - // Allocate returning string and point temp to it - temp = result = (char *)RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1); - - if (!result) return NULL; // Memory could not be allocated - - // First time through the loop, all the variable are set correctly from here on, - // - 'temp' points to the end of the result string - // - 'insertPoint' points to the next occurrence of replace in text - // - 'text' points to the remainder of text after "end of replace" - while (count--) - { - insertPoint = strstr(text, replace); - lastReplacePos = (int)(insertPoint - text); - temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; - temp = strcpy(temp, by) + byLen; - text += lastReplacePos + replaceLen; // Move to next "end of replace" - } - - // Copy remaind text part after replacement to result (pointed by moving temp) - strcpy(temp, text); - - return result; -} - -// Insert text in a specific position, moves all text forward -// WARNING: Allocated memory must be manually freed -char *TextInsert(const char *text, const char *insert, int position) -{ - int textLen = TextLength(text); - int insertLen = TextLength(insert); - - char *result = (char *)RL_MALLOC(textLen + insertLen + 1); - - for (int i = 0; i < position; i++) result[i] = text[i]; - for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; - for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; - - result[textLen + insertLen] = '\0'; // Make sure text string is valid! - - return result; -} - -// Join text strings with delimiter -// REQUIRES: memset(), memcpy() -char *TextJoin(char **textList, int count, const char *delimiter) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - char *textPtr = buffer; - - int totalLength = 0; - int delimiterLen = TextLength(delimiter); - - for (int i = 0; i < count; i++) - { - int textLength = TextLength(textList[i]); - - // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH - if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH) - { - memcpy(textPtr, textList[i], textLength); - totalLength += textLength; - textPtr += textLength; - - if ((delimiterLen > 0) && (i < (count - 1))) - { - memcpy(textPtr, delimiter, delimiterLen); - totalLength += delimiterLen; - textPtr += delimiterLen; - } - } - } - - return buffer; -} - -// Split string into multiple strings -// REQUIRES: memset() -char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT - // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH - - static char *result[MAX_TEXTSPLIT_COUNT] = { NULL }; - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings we have on text and point to every one - for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == MAX_TEXTSPLIT_COUNT) break; - } - } - } - - *count = counter; - return result; -} - -// Append text at specific position and move cursor -// WARNING: It's up to the user to make sure appended text does not overflow the buffer! -// REQUIRES: strcpy() -void TextAppend(char *text, const char *append, int *position) -{ - strcpy(text + *position, append); - *position += TextLength(append); -} - -// Find first text occurrence within a string -// REQUIRES: strstr() -int TextFindIndex(const char *text, const char *find) -{ - int position = -1; - - char *ptr = strstr(text, find); - - if (ptr != NULL) position = (int)(ptr - text); - - return position; -} - -// Get upper case version of provided string -// WARNING: Limited functionality, only basic characters set -// TODO: Support UTF-8 diacritics to upper-case, check codepoints -char *TextToUpper(const char *text) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - if (text != NULL) - { - for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++) - { - if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32; - else buffer[i] = text[i]; - } - } - - return buffer; -} - -// Get lower case version of provided string -// WARNING: Limited functionality, only basic characters set -char *TextToLower(const char *text) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - if (text != NULL) - { - for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++) - { - if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32; - else buffer[i] = text[i]; - } - } - - return buffer; -} - -// Get Pascal case notation version of provided string -// WARNING: Limited functionality, only basic characters set -char *TextToPascal(const char *text) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - if (text != NULL) - { - // Upper case first character - if ((text[0] >= 'a') && (text[0] <= 'z')) buffer[0] = text[0] - 32; - else buffer[0] = text[0]; - - // Check for next separator to upper case another character - for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++) - { - if (text[j] != '_') buffer[i] = text[j]; - else - { - j++; - if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32; - } - } - } - - return buffer; -} - -// Get snake case notation version of provided string -// WARNING: Limited functionality, only basic characters set -char *TextToSnake(const char *text) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0}; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - if (text != NULL) - { - // Check for next separator to upper case another character - for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++) - { - if ((text[j] >= 'A') && (text[j] <= 'Z')) - { - if (i >= 1) - { - buffer[i] = '_'; - i++; - } - buffer[i] = text[j] + 32; - } - else buffer[i] = text[j]; - } - } - - return buffer; -} - -// Get Camel case notation version of provided string -// WARNING: Limited functionality, only basic characters set -char *TextToCamel(const char *text) -{ - static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0}; - memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - - if (text != NULL) - { - // Lower case first character - if ((text[0] >= 'A') && (text[0] <= 'Z')) buffer[0] = text[0] + 32; - else buffer[0] = text[0]; - - // Check for next separator to upper case another character - for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++) - { - if (text[j] != '_') buffer[i] = text[j]; - else - { - j++; - if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32; - } - } - } - - return buffer; -} - -// Encode text codepoint into UTF-8 text -// REQUIRES: memcpy() -// WARNING: Allocated memory must be manually freed -char *LoadUTF8(const int *codepoints, int length) -{ - // We allocate enough memory to fit all possible codepoints - // NOTE: 5 bytes for every codepoint should be enough - char *text = (char *)RL_CALLOC(length*5, 1); - const char *utf8 = NULL; - int size = 0; - - for (int i = 0, bytes = 0; i < length; i++) - { - utf8 = CodepointToUTF8(codepoints[i], &bytes); - memcpy(text + size, utf8, bytes); - size += bytes; - } - - // Resize memory to text length + string NULL terminator - void *ptr = RL_REALLOC(text, size + 1); - - if (ptr != NULL) text = (char *)ptr; - - return text; -} - -// Unload UTF-8 text encoded from codepoints array -void UnloadUTF8(char *text) -{ - RL_FREE(text); -} - -// Load all codepoints from a UTF-8 text string, codepoints count returned by parameter -int *LoadCodepoints(const char *text, int *count) -{ - int textLength = TextLength(text); - - int codepointSize = 0; - int codepointCount = 0; - - // Allocate a big enough buffer to store as many codepoints as text bytes - int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int)); - - for (int i = 0; i < textLength; codepointCount++) - { - codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize); - i += codepointSize; - } - - // Re-allocate buffer to the actual number of codepoints loaded - codepoints = (int *)RL_REALLOC(codepoints, codepointCount*sizeof(int)); - - *count = codepointCount; - - return codepoints; -} - -// Unload codepoints data from memory -void UnloadCodepoints(int *codepoints) -{ - RL_FREE(codepoints); -} - -// Get total number of characters(codepoints) in a UTF-8 encoded text, until '\0' is found -// NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f) codepoint is counted instead -int GetCodepointCount(const char *text) -{ - unsigned int length = 0; - const char *ptr = text; - - while (*ptr != '\0') - { - int next = 0; - GetCodepointNext(ptr, &next); - - ptr += next; - - length++; - } - - return length; -} - -// Encode codepoint into utf8 text (char array length returned as parameter) -// NOTE: It uses a static array to store UTF-8 bytes -const char *CodepointToUTF8(int codepoint, int *utf8Size) -{ - static char utf8[6] = { 0 }; - memset(utf8, 0, 6); // Clear static array - int size = 0; // Byte size of codepoint - - if (codepoint <= 0x7f) - { - utf8[0] = (char)codepoint; - size = 1; - } - else if (codepoint <= 0x7ff) - { - utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); - utf8[1] = (char)((codepoint & 0x3f) | 0x80); - size = 2; - } - else if (codepoint <= 0xffff) - { - utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); - utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); - utf8[2] = (char)((codepoint & 0x3f) | 0x80); - size = 3; - } - else if (codepoint <= 0x10ffff) - { - utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); - utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); - utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); - utf8[3] = (char)((codepoint & 0x3f) | 0x80); - size = 4; - } - - *utf8Size = size; - - return utf8; -} -#endif // SUPPORT_TEXT_MANIPULATION - -// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found -// When an invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned -// Total number of bytes processed are returned as a parameter -// NOTE: The standard says U+FFFD should be returned in case of errors -// but that character is not supported by the default font in raylib -int GetCodepoint(const char *text, int *codepointSize) -{ -/* - UTF-8 specs from https://www.ietf.org/rfc/rfc3629.txt - - Char. number range | UTF-8 octet sequence - (hexadecimal) | (binary) - --------------------+--------------------------------------------- - 0000 0000-0000 007F | 0xxxxxxx - 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -*/ - // NOTE: on decode errors we return as soon as possible - - int codepoint = 0x3f; // Codepoint (defaults to '?') - int octet = (unsigned char)(text[0]); // The first UTF8 octet - *codepointSize = 1; - - if (octet <= 0x7f) - { - // Only one octet (ASCII range x00-7F) - codepoint = text[0]; - } - else if ((octet & 0xe0) == 0xc0) - { - // Two octets - - // [0]xC2-DF [1]UTF8-tail(x80-BF) - unsigned char octet1 = text[1]; - - if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *codepointSize = 2; return codepoint; } // Unexpected sequence - - if ((octet >= 0xc2) && (octet <= 0xdf)) - { - codepoint = ((octet & 0x1f) << 6) | (octet1 & 0x3f); - *codepointSize = 2; - } - } - else if ((octet & 0xf0) == 0xe0) - { - // Three octets - unsigned char octet1 = text[1]; - unsigned char octet2 = '\0'; - - if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *codepointSize = 2; return codepoint; } // Unexpected sequence - - octet2 = text[2]; - - if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *codepointSize = 3; return codepoint; } // Unexpected sequence - - // [0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF) - // [0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF) - // [0]xED [1]x80-9F [2]UTF8-tail(x80-BF) - // [0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF) - - if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) || - ((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *codepointSize = 2; return codepoint; } - - if ((octet >= 0xe0) && (octet <= 0xef)) - { - codepoint = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f); - *codepointSize = 3; - } - } - else if ((octet & 0xf8) == 0xf0) - { - // Four octets - if (octet > 0xf4) return codepoint; - - unsigned char octet1 = text[1]; - unsigned char octet2 = '\0'; - unsigned char octet3 = '\0'; - - if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *codepointSize = 2; return codepoint; } // Unexpected sequence - - octet2 = text[2]; - - if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *codepointSize = 3; return codepoint; } // Unexpected sequence - - octet3 = text[3]; - - if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *codepointSize = 4; return codepoint; } // Unexpected sequence - - // [0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail - // [0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail - // [0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail - - if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) || - ((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *codepointSize = 2; return codepoint; } // Unexpected sequence - - if (octet >= 0xf0) - { - codepoint = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f); - *codepointSize = 4; - } - } - - if (codepoint > 0x10ffff) codepoint = 0x3f; // Codepoints after U+10ffff are invalid - - return codepoint; -} - -// Get next codepoint in a byte sequence and bytes processed -int GetCodepointNext(const char *text, int *codepointSize) -{ - const char *ptr = text; - int codepoint = 0x3f; // Codepoint (defaults to '?') - *codepointSize = 1; - - // Get current codepoint and bytes processed - if (0xf0 == (0xf8 & ptr[0])) - { - // 4 byte UTF-8 codepoint - if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks - codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); - *codepointSize = 4; - } - else if (0xe0 == (0xf0 & ptr[0])) - { - // 3 byte UTF-8 codepoint */ - if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks - codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); - *codepointSize = 3; - } - else if (0xc0 == (0xe0 & ptr[0])) - { - // 2 byte UTF-8 codepoint - if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } // 10xxxxxx checks - codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); - *codepointSize = 2; - } - else if (0x00 == (0x80 & ptr[0])) - { - // 1 byte UTF-8 codepoint - codepoint = ptr[0]; - *codepointSize = 1; - } - - return codepoint; -} - -// Get previous codepoint in a byte sequence and bytes processed -int GetCodepointPrevious(const char *text, int *codepointSize) -{ - const char *ptr = text; - int codepoint = 0x3f; // Codepoint (defaults to '?') - int cpSize = 0; - *codepointSize = 0; - - // Move to previous codepoint - do ptr--; - while (((0x80 & ptr[0]) != 0) && ((0xc0 & ptr[0]) == 0x80)); - - codepoint = GetCodepointNext(ptr, &cpSize); - - if (codepoint != 0) *codepointSize = cpSize; - - return codepoint; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_FNT) || defined(SUPPORT_FILEFORMAT_BDF) -// Read a line from memory -// REQUIRES: memcpy() -// NOTE: Returns the number of bytes read -static int GetLine(const char *origin, char *buffer, int maxLength) -{ - int count = 0; - for (; count < maxLength - 1; count++) if (origin[count] == '\n') break; - memcpy(buffer, origin, count); - buffer[count] = '\0'; - return count; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_FNT) -// Load a BMFont file (AngelCode font file) -// REQUIRES: strstr(), sscanf(), strrchr(), memcpy() -static Font LoadBMFont(const char *fileName) -{ - #define MAX_BUFFER_SIZE 256 - #define MAX_FONT_IMAGE_PAGES 8 - - Font font = { 0 }; - - char buffer[MAX_BUFFER_SIZE] = { 0 }; - char *searchPoint = NULL; - - int fontSize = 0; - int glyphCount = 0; - - int imWidth = 0; - int imHeight = 0; - int pageCount = 1; - char imFileName[MAX_FONT_IMAGE_PAGES][129] = { 0 }; - - int base = 0; // Useless data - int readBytes = 0; // Data bytes read - int readVars = 0; // Variables filled by sscanf() - - char *fileText = LoadFileText(fileName); - - if (fileText == NULL) return font; - - char *fileTextPtr = fileText; - - // NOTE: We skip first line, it contains no useful information - readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); - fileTextPtr += (readBytes + 1); - - // Read line data - readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); - searchPoint = strstr(buffer, "lineHeight"); - readVars = sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i pages=%i", &fontSize, &base, &imWidth, &imHeight, &pageCount); - fileTextPtr += (readBytes + 1); - - if (readVars < 4) { UnloadFileText(fileText); return font; } // Some data not available, file malformed - - if (pageCount > MAX_FONT_IMAGE_PAGES) - { - TRACELOG(LOG_WARNING, "FONT: [%s] Font defines more pages than supported: %i/%i", fileName, pageCount, MAX_FONT_IMAGE_PAGES); - pageCount = MAX_FONT_IMAGE_PAGES; - } - - for (int i = 0; i < pageCount; i++) - { - readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); - searchPoint = strstr(buffer, "file"); - readVars = sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName[i]); - fileTextPtr += (readBytes + 1); - - if (readVars < 1) { UnloadFileText(fileText); return font; } // No fileName read - } - - readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); - searchPoint = strstr(buffer, "count"); - readVars = sscanf(searchPoint, "count=%i", &glyphCount); - fileTextPtr += (readBytes + 1); - - if (readVars < 1) { UnloadFileText(fileText); return font; } // No glyphCount read - - // Load all required images for further compose - Image *imFonts = (Image *)RL_CALLOC(pageCount, sizeof(Image)); // Font atlases, multiple images - - for (int i = 0; i < pageCount; i++) - { - imFonts[i] = LoadImage(TextFormat("%s/%s", GetDirectoryPath(fileName), imFileName[i])); - - if (imFonts[i].format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) - { - // Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel - Image imFontAlpha = { - .data = RL_CALLOC(imFonts[i].width*imFonts[i].height, 2), - .width = imFonts[i].width, - .height = imFonts[i].height, - .mipmaps = 1, - .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA - }; - - for (int p = 0, pi = 0; p < (imFonts[i].width*imFonts[i].height*2); p += 2, pi++) - { - ((unsigned char *)(imFontAlpha.data))[p] = 0xff; - ((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFonts[i].data)[pi]; - } - - UnloadImage(imFonts[i]); - imFonts[i] = imFontAlpha; - } - } - - Image fullFont = imFonts[0]; - for (int i = 1; i < pageCount; i++) UnloadImage(imFonts[i]); - - // If multiple atlas, then merge atlas - // NOTE: WARNING: This process could be really slow! - if (pageCount > 1) - { - // Resize font atlas to draw additional images - ImageResizeCanvas(&fullFont, imWidth, imHeight*pageCount, 0, 0, BLACK); - - for (int i = 1; i < pageCount; i++) - { - Rectangle srcRec = { 0.0f, 0.0f, (float)imWidth, (float)imHeight }; - Rectangle destRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight }; - ImageDraw(&fullFont, imFonts[i], srcRec, destRec, WHITE); - } - } - - RL_FREE(imFonts); - - if (isGpuReady) font.texture = LoadTextureFromImage(fullFont); - - // Fill font characters info data - font.baseSize = fontSize; - font.glyphCount = glyphCount; - font.glyphPadding = 0; - font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo)); - font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle)); - - int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID; - - for (int i = 0; i < glyphCount; i++) - { - readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); - readVars = sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i page=%i", - &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX, &pageID); - fileTextPtr += (readBytes + 1); - - if (readVars == 9) // Make sure all char data has been properly read - { - // Get character rectangle in the font atlas texture - font.recs[i] = (Rectangle){ (float)charX, (float)charY + (float)imHeight*pageID, (float)charWidth, (float)charHeight }; - - // Save data properly in sprite font - font.glyphs[i].value = charId; - font.glyphs[i].offsetX = charOffsetX; - font.glyphs[i].offsetY = charOffsetY; - font.glyphs[i].advanceX = charAdvanceX; - - // Fill character image data from full font data - font.glyphs[i].image = ImageFromImage(fullFont, font.recs[i]); - } - else - { - font.glyphs[i].image = GenImageColor((int)font.recs[i].width, (int)font.recs[i].height, BLACK); - TRACELOG(LOG_WARNING, "FONT: [%s] Some characters data not correctly provided", fileName); - } - } - - UnloadImage(fullFont); - UnloadFileText(fileText); - - if (isGpuReady && (font.texture.id == 0)) - { - UnloadFont(font); - font = GetFontDefault(); - TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName); - } - else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully (%i glyphs)", fileName, font.glyphCount); - - return font; -} - -#endif - -#if defined(SUPPORT_FILEFORMAT_BDF) - -// Convert hexadecimal to decimal (single digit) -static unsigned char HexToInt(char hex) -{ - if ((hex >= '0') && (hex <= '9')) return hex - '0'; - else if ((hex >= 'a') && (hex <= 'f')) return hex - 'a' + 10; - else if ((hex >= 'A') && (hex <= 'F')) return hex - 'A' + 10; - else return 0; -} - -// Load font data for further use -// NOTE: Requires BDF font memory data -static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize) -{ - #define MAX_BUFFER_SIZE 256 - - char buffer[MAX_BUFFER_SIZE] = { 0 }; - - GlyphInfo *glyphs = NULL; - bool genFontChars = false; - - int totalReadBytes = 0; // Data bytes read (total) - int readBytes = 0; // Data bytes read (line) - int readVars = 0; // Variables filled by sscanf() - - const char *fileText = (const char *)fileData; - const char *fileTextPtr = fileText; - - bool fontMalformed = false; // Is the font malformed - bool fontStarted = false; // Has font started (STARTFONT) - int fontBBw = 0; // Font base character bounding box width - int fontBBh = 0; // Font base character bounding box height - int fontBBxoff0 = 0; // Font base character bounding box X0 offset - int fontBByoff0 = 0; // Font base character bounding box Y0 offset - int fontAscent = 0; // Font ascent - - bool charStarted = false; // Has character started (STARTCHAR) - bool charBitmapStarted = false; // Has bitmap data started (BITMAP) - int charBitmapNextRow = 0; // Y position for the next row of bitmap data - int charEncoding = -1; // The unicode value of the character (-1 if not set) - int charBBw = 0; // Character bounding box width - int charBBh = 0; // Character bounding box height - int charBBxoff0 = 0; // Character bounding box X0 offset - int charBByoff0 = 0; // Character bounding box Y0 offset - int charDWidthX = 0; // Character advance X - int charDWidthY = 0; // Character advance Y (unused) - GlyphInfo *charGlyphInfo = NULL; // Pointer to output glyph info (NULL if not set) - - if (fileData == NULL) return glyphs; - - // In case no chars count provided, default to 95 - codepointCount = (codepointCount > 0)? codepointCount : 95; - - // Fill fontChars in case not provided externally - // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space) - if (codepoints == NULL) - { - codepoints = (int *)RL_MALLOC(codepointCount*sizeof(int)); - for (int i = 0; i < codepointCount; i++) codepoints[i] = i + 32; - genFontChars = true; - } - - glyphs = (GlyphInfo *)RL_CALLOC(codepointCount, sizeof(GlyphInfo)); - - while (totalReadBytes <= dataSize) - { - readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); - totalReadBytes += (readBytes + 1); - fileTextPtr += (readBytes + 1); - - // Line: COMMENT - if (strstr(buffer, "COMMENT") != NULL) continue; // Ignore line - - if (charStarted) - { - // Line: ENDCHAR - if (strstr(buffer, "ENDCHAR") != NULL) - { - charStarted = false; - continue; - } - - if (charBitmapStarted) - { - if (charGlyphInfo != NULL) - { - int pixelY = charBitmapNextRow++; - - if (pixelY >= charGlyphInfo->image.height) break; - - for (int x = 0; x < readBytes; x++) - { - unsigned char byte = HexToInt(buffer[x]); - - for (int bitX = 0; bitX < 4; bitX++) - { - int pixelX = ((x*4) + bitX); - - if (pixelX >= charGlyphInfo->image.width) break; - - if ((byte & (8 >> bitX)) > 0) ((unsigned char *)charGlyphInfo->image.data)[(pixelY*charGlyphInfo->image.width) + pixelX] = 255; - } - } - } - continue; - } - - // Line: ENCODING - if (strstr(buffer, "ENCODING") != NULL) - { - readVars = sscanf(buffer, "ENCODING %i", &charEncoding); - continue; - } - - // Line: BBX - if (strstr(buffer, "BBX") != NULL) - { - readVars = sscanf(buffer, "BBX %i %i %i %i", &charBBw, &charBBh, &charBBxoff0, &charBByoff0); - continue; - } - - // Line: DWIDTH - if (strstr(buffer, "DWIDTH") != NULL) - { - readVars = sscanf(buffer, "DWIDTH %i %i", &charDWidthX, &charDWidthY); - continue; - } - - // Line: BITMAP - if (strstr(buffer, "BITMAP") != NULL) - { - // Search for glyph index in codepoints - charGlyphInfo = NULL; - - for (int codepointIndex = 0; codepointIndex < codepointCount; codepointIndex++) - { - if (codepoints[codepointIndex] == charEncoding) - { - charGlyphInfo = &glyphs[codepointIndex]; - break; - } - } - - // Init glyph info - if (charGlyphInfo != NULL) - { - charGlyphInfo->value = charEncoding; - charGlyphInfo->offsetX = charBBxoff0 + fontBByoff0; - charGlyphInfo->offsetY = fontBBh - (charBBh + charBByoff0 + fontBByoff0 + fontAscent); - charGlyphInfo->advanceX = charDWidthX; - - charGlyphInfo->image.data = RL_CALLOC(charBBw*charBBh, 1); - charGlyphInfo->image.width = charBBw; - charGlyphInfo->image.height = charBBh; - charGlyphInfo->image.mipmaps = 1; - charGlyphInfo->image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - } - - charBitmapStarted = true; - charBitmapNextRow = 0; - - continue; - } - } - else if (fontStarted) - { - // Line: ENDFONT - if (strstr(buffer, "ENDFONT") != NULL) - { - fontStarted = false; - break; - } - - // Line: SIZE - if (strstr(buffer, "SIZE") != NULL) - { - if (outFontSize != NULL) readVars = sscanf(buffer, "SIZE %i", outFontSize); - continue; - } - - // PIXEL_SIZE - if (strstr(buffer, "PIXEL_SIZE") != NULL) - { - if (outFontSize != NULL) readVars = sscanf(buffer, "PIXEL_SIZE %i", outFontSize); - continue; - } - - // FONTBOUNDINGBOX - if (strstr(buffer, "FONTBOUNDINGBOX") != NULL) - { - readVars = sscanf(buffer, "FONTBOUNDINGBOX %i %i %i %i", &fontBBw, &fontBBh, &fontBBxoff0, &fontBByoff0); - continue; - } - - // FONT_ASCENT - if (strstr(buffer, "FONT_ASCENT") != NULL) - { - readVars = sscanf(buffer, "FONT_ASCENT %i", &fontAscent); - continue; - } - - // STARTCHAR - if (strstr(buffer, "STARTCHAR") != NULL) - { - charStarted = true; - charEncoding = -1; - charGlyphInfo = NULL; - charBBw = 0; - charBBh = 0; - charBBxoff0 = 0; - charBByoff0 = 0; - charDWidthX = 0; - charDWidthY = 0; - charGlyphInfo = NULL; - charBitmapStarted = false; - charBitmapNextRow = 0; - continue; - } - } - else - { - // STARTFONT - if (strstr(buffer, "STARTFONT") != NULL) - { - if (fontStarted) - { - fontMalformed = true; - break; - } - else - { - fontStarted = true; - continue; - } - } - } - } - - if (genFontChars) RL_FREE(codepoints); - - if (fontMalformed) - { - RL_FREE(glyphs); - glyphs = NULL; - } - - return glyphs; -} -#endif // SUPPORT_FILEFORMAT_BDF - -#endif // SUPPORT_MODULE_RTEXT diff --git a/raylib/rtext.go b/raylib/rtext.go deleted file mode 100644 index e32ee20..0000000 --- a/raylib/rtext.go +++ /dev/null @@ -1,261 +0,0 @@ -package rl - -/* -#include "raylib.h" -#include -*/ -import "C" -import ( - "image/color" - "unsafe" -) - -// newGlyphInfoFromPointer - Returns new GlyphInfo from pointer -func newGlyphInfoFromPointer(ptr unsafe.Pointer) GlyphInfo { - return *(*GlyphInfo)(ptr) -} - -// cptr returns C pointer -func (c *GlyphInfo) cptr() *C.GlyphInfo { - return (*C.GlyphInfo)(unsafe.Pointer(c)) -} - -// newFontFromPointer - Returns new Font from pointer -func newFontFromPointer(ptr unsafe.Pointer) Font { - return *(*Font)(ptr) -} - -// cptr returns C pointer -func (s *Font) cptr() *C.Font { - return (*C.Font)(unsafe.Pointer(s)) -} - -// GetFontDefault - Get the default Font -func GetFontDefault() Font { - ret := C.GetFontDefault() - v := newFontFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadFont - Load a Font image into GPU memory (VRAM) -func LoadFont(fileName string) Font { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadFont(cfileName) - v := newFontFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadFontEx - Load Font from file with extended parameters -func LoadFontEx(fileName string, fontSize int32, fontChars []rune, runesNumber ...int32) Font { - var cfontChars *C.int - var ccharsCount C.int - - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - cfontSize := (C.int)(fontSize) - if fontChars != nil { - cfontChars = (*C.int)(unsafe.Pointer(&fontChars[0])) - ccharsCount = (C.int)(len(fontChars)) - } - if fontChars == nil { - if len(runesNumber) > 0 { - ccharsCount = (C.int)(runesNumber[0]) - } - } - ret := C.LoadFontEx(cfileName, cfontSize, cfontChars, ccharsCount) - v := newFontFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadFontFromImage - Loads an Image font file (XNA style) -func LoadFontFromImage(image Image, key color.RGBA, firstChar int32) Font { - cimage := image.cptr() - ckey := colorCptr(key) - cfirstChar := (C.int)(firstChar) - ret := C.LoadFontFromImage(*cimage, *ckey, cfirstChar) - v := newFontFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadFontFromMemory - Load font from memory buffer, fileType refers to extension: i.e. ".ttf" -func LoadFontFromMemory(fileType string, fileData []byte, fontSize int32, codepoints []rune) Font { - cfileType := C.CString(fileType) - defer C.free(unsafe.Pointer(cfileType)) - cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) - cdataSize := (C.int)(len(fileData)) - cfontSize := (C.int)(fontSize) - cfontChars := (*C.int)(unsafe.SliceData(codepoints)) - ccharsCount := (C.int)(len(codepoints)) - ret := C.LoadFontFromMemory(cfileType, cfileData, cdataSize, cfontSize, cfontChars, ccharsCount) - v := newFontFromPointer(unsafe.Pointer(&ret)) - return v -} - -// IsFontValid - Check if a font is valid (font data loaded, WARNING: GPU texture not checked) -func IsFontValid(font Font) bool { - cfont := font.cptr() - ret := C.IsFontValid(*cfont) - v := bool(ret) - return v -} - -// LoadFontData - Load font data for further use -func LoadFontData(fileData []byte, fontSize int32, codePoints []rune, codepointCount, typ int32) []GlyphInfo { - cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) - cdataSize := (C.int)(len(fileData)) - cfontSize := (C.int)(fontSize) - ccodePoints := (*C.int)(unsafe.SliceData(codePoints)) - // In case no chars count provided, default to 95 - if codepointCount <= 0 { - codepointCount = 95 - } - ccodePointCount := (C.int)(codepointCount) - ctype := (C.int)(typ) - ret := C.LoadFontData(cfileData, cdataSize, cfontSize, ccodePoints, ccodePointCount, ctype) - v := unsafe.Slice((*GlyphInfo)(unsafe.Pointer(ret)), ccodePointCount) - return v -} - -// UnloadFontData - Unload font chars info data (RAM) -func UnloadFontData(glyphs []GlyphInfo) { - cglyphs := (*C.GlyphInfo)(unsafe.Pointer(&glyphs[0])) - C.UnloadFontData(cglyphs, C.int(len(glyphs))) -} - -// UnloadFont - Unload Font from GPU memory (VRAM) -func UnloadFont(font Font) { - cfont := font.cptr() - C.UnloadFont(*cfont) -} - -// DrawFPS - Shows current FPS -func DrawFPS(posX int32, posY int32) { - cposX := (C.int)(posX) - cposY := (C.int)(posY) - C.DrawFPS(cposX, cposY) -} - -// DrawText - Draw text (using default font) -func DrawText(text string, posX int32, posY int32, fontSize int32, col color.RGBA) { - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cposX := (C.int)(posX) - cposY := (C.int)(posY) - cfontSize := (C.int)(fontSize) - ccolor := colorCptr(col) - C.DrawText(ctext, cposX, cposY, cfontSize, *ccolor) -} - -// DrawTextEx - Draw text using Font and additional parameters -func DrawTextEx(font Font, text string, position Vector2, fontSize float32, spacing float32, tint color.RGBA) { - cfont := font.cptr() - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cposition := position.cptr() - cfontSize := (C.float)(fontSize) - cspacing := (C.float)(spacing) - ctint := colorCptr(tint) - C.DrawTextEx(*cfont, ctext, *cposition, cfontSize, cspacing, *ctint) -} - -// DrawTextPro - Draw text using Font and pro parameters (rotation) -func DrawTextPro(font Font, text string, position Vector2, origin Vector2, rotation, fontSize float32, spacing float32, tint color.RGBA) { - cfont := font.cptr() - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cposition := position.cptr() - crotation := (C.float)(rotation) - corigin := origin.cptr() - cfontSize := (C.float)(fontSize) - cspacing := (C.float)(spacing) - ctint := colorCptr(tint) - C.DrawTextPro(*cfont, ctext, *cposition, *corigin, crotation, cfontSize, cspacing, *ctint) -} - -// SetTextLineSpacing - Set vertical line spacing when drawing with line-breaks -func SetTextLineSpacing(spacing int) { - cspacing := (C.int)(spacing) - C.SetTextLineSpacing(cspacing) -} - -// MeasureText - Measure string width for default font -func MeasureText(text string, fontSize int32) int32 { - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cfontSize := (C.int)(fontSize) - ret := C.MeasureText(ctext, cfontSize) - v := (int32)(ret) - return v -} - -// MeasureTextEx - Measure string size for Font -func MeasureTextEx(font Font, text string, fontSize float32, spacing float32) Vector2 { - cfont := font.cptr() - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cfontSize := (C.float)(fontSize) - cspacing := (C.float)(spacing) - ret := C.MeasureTextEx(*cfont, ctext, cfontSize, cspacing) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetGlyphIndex - Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found -func GetGlyphIndex(font Font, codepoint int32) int32 { - cfont := font.cptr() - ccodepoint := (C.int)(codepoint) - ret := C.GetGlyphIndex(*cfont, ccodepoint) - v := (int32)(ret) - return v -} - -// GetGlyphInfo - Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found -func GetGlyphInfo(font Font, codepoint int32) GlyphInfo { - cfont := font.cptr() - ccodepoint := (C.int)(codepoint) - ret := C.GetGlyphInfo(*cfont, ccodepoint) - v := newGlyphInfoFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetGlyphAtlasRec - Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found -func GetGlyphAtlasRec(font Font, codepoint int32) Rectangle { - cfont := font.cptr() - ccodepoint := (C.int)(codepoint) - ret := C.GetGlyphAtlasRec(*cfont, ccodepoint) - v := newRectangleFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenImageFontAtlas - Generate image font atlas using chars info -func GenImageFontAtlas(glyphs []GlyphInfo, glyphRecs []*Rectangle, fontSize int32, padding int32, packMethod int32) Image { - cglyphs := (*C.GlyphInfo)(unsafe.Pointer(&glyphs[0])) - cglyphRecs := (**C.Rectangle)(unsafe.Pointer(&glyphRecs[0])) - cglyphCount := C.int(len(glyphs)) - ret := C.GenImageFontAtlas(cglyphs, cglyphRecs, cglyphCount, C.int(fontSize), C.int(padding), C.int(packMethod)) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return *v -} - -// DrawTextCodepoint - Draw one character (codepoint) -func DrawTextCodepoint(font Font, codepoint rune, position Vector2, fontSize float32, tint color.RGBA) { - cfont := font.cptr() - ccodepoint := (C.int)(codepoint) - cposition := position.cptr() - cfontSize := (C.float)(fontSize) - ctint := colorCptr(tint) - C.DrawTextCodepoint(*cfont, ccodepoint, *cposition, cfontSize, *ctint) -} - -// DrawTextCodepoints - Draw multiple character (codepoint) -func DrawTextCodepoints(font Font, codepoints []rune, position Vector2, fontSize float32, spacing float32, tint color.RGBA) { - cfont := font.cptr() - ccodepoints := (*C.int)(unsafe.SliceData(codepoints)) - ccodepointCount := C.int(len(codepoints)) - cposition := position.cptr() - cfontSize := (C.float)(fontSize) - cspacing := (C.float)(spacing) - ctint := colorCptr(tint) - C.DrawTextCodepoints(*cfont, ccodepoints, ccodepointCount, *cposition, cfontSize, cspacing, *ctint) -} diff --git a/raylib/shapes.c b/raylib/shapes.c new file mode 100644 index 0000000..5ed7acb --- /dev/null +++ b/raylib/shapes.c @@ -0,0 +1,1728 @@ +/********************************************************************************************** +* +* raylib.shapes - Basic functions to draw 2d Shapes and check collisions +* +* CONFIGURATION: +* +* #define SUPPORT_QUADS_DRAW_MODE +* Use QUADS instead of TRIANGLES for drawing when possible. +* Some lines-based shapes could still use lines +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" // Declares module functions + +// Check if config flags have been externally provided on compilation line +#if !defined(EXTERNAL_CONFIG_FLAGS) + #include "config.h" // Defines module configuration flags +#endif + +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 + +#include // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- + +// Error rate to calculate how many segments we need to draw a smooth circle, +// taken from https://stackoverflow.com/a/2244088 +#ifndef SMOOTH_CIRCLE_ERROR_RATE + #define SMOOTH_CIRCLE_ERROR_RATE 0.5f +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Not here... + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (usually a white pixel) +Rectangle texShapesRec = { 0, 0, 1, 1 }; // Texture source rectangle used on shapes drawing + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Set texture and rectangle to be used on shapes drawing +// NOTE: It can be useful when using basic shapes and one single font, +// defining a font char white rectangle would allow drawing everything in a single draw call +void SetShapesTexture(Texture2D texture, Rectangle source) +{ + texShapes = texture; + texShapesRec = source; +} + +// Draw a pixel +void DrawPixel(int posX, int posY, Color color) +{ + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2i(posX, posY); + rlVertex2i(posX + 1, posY + 1); + rlEnd(); +} + +// Draw a pixel (Vector version) +void DrawPixelV(Vector2 position, Color color) +{ + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(position.x, position.y); + rlVertex2f(position.x + 1.0f, position.y + 1.0f); + rlEnd(); +} + +// Draw a line +void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color) +{ + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2i(startPosX, startPosY); + rlVertex2i(endPosX, endPosY); + rlEnd(); +} + +// Draw a line (Vector version) +void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) +{ + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(startPos.x, startPos.y); + rlVertex2f(endPos.x, endPos.y); + rlEnd(); +} + +// Draw a line defining thickness +void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) +{ + Vector2 delta = {endPos.x-startPos.x, endPos.y-startPos.y}; + float length = sqrtf(delta.x*delta.x + delta.y*delta.y); + + if (length > 0 && thick > 0) + { + float scale = thick/(2*length); + Vector2 radius = {-scale*delta.y, scale*delta.x}; + Vector2 strip[] = {{startPos.x-radius.x, startPos.y-radius.y}, {startPos.x+radius.x, startPos.y+radius.y}, + {endPos.x-radius.x, endPos.y-radius.y}, {endPos.x+radius.x, endPos.y+radius.y}}; + + DrawTriangleStrip(strip, 4, color); + } +} + +// Draw line using cubic-bezier curves in-out +void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) +{ +#ifndef BEZIER_LINE_DIVISIONS + #define BEZIER_LINE_DIVISIONS 24 // Bezier line divisions +#endif + + Vector2 previous = startPos; + Vector2 current = { 0 }; + + for (int i = 1; i <= BEZIER_LINE_DIVISIONS; i++) + { + // Cubic easing in-out + // NOTE: Easing is calculated only for y position value + current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)BEZIER_LINE_DIVISIONS); + current.x = previous.x + (endPos.x - startPos.x)/ (float)BEZIER_LINE_DIVISIONS; + + DrawLineEx(previous, current, thick, color); + + previous = current; + } +} + +// Draw line using quadratic bezier curves with a control point +void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color) +{ + const float step = 1.0f/BEZIER_LINE_DIVISIONS; + + Vector2 previous = startPos; + Vector2 current = { 0 }; + float t = 0.0f; + + for (int i = 0; i <= BEZIER_LINE_DIVISIONS; i++) + { + t = step*i; + float a = powf(1 - t, 2); + float b = 2*(1 - t)*t; + float c = powf(t, 2); + + // NOTE: The easing functions aren't suitable here because they don't take a control point + current.y = a*startPos.y + b*controlPos.y + c*endPos.y; + current.x = a*startPos.x + b*controlPos.x + c*endPos.x; + + DrawLineEx(previous, current, thick, color); + + previous = current; + } +} + +// Draw lines sequence +void DrawLineStrip(Vector2 *points, int pointsCount, Color color) +{ + if (pointsCount >= 2) + { + rlCheckRenderBatchLimit(pointsCount); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 0; i < pointsCount - 1; i++) + { + rlVertex2f(points[i].x, points[i].y); + rlVertex2f(points[i + 1].x, points[i + 1].y); + } + rlEnd(); + } +} + +// Draw a color-filled circle +void DrawCircle(int centerX, int centerY, float radius, Color color) +{ + DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color); +} + +// Draw a piece of a circle +void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color) +{ + if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero + + // Function expects (endAngle > startAngle) + if (endAngle < startAngle) + { + // Swap values + float tmp = startAngle; + startAngle = endAngle; + endAngle = tmp; + } + + int minSegments = (int)ceilf((endAngle - startAngle)/90); + + if (segments < minSegments) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); + segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); + + if (segments <= 0) segments = minSegments; + } + + float stepLength = (endAngle - startAngle)/(float)segments; + float angle = startAngle; + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlCheckRenderBatchLimit(4*segments/2); + + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + // NOTE: Every QUAD actually represents two segments + for (int i = 0; i < segments/2; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x, center.y); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius); + + angle += (stepLength*2); + } + + // NOTE: In case number of segments is odd, we add one last piece to the cake + if (segments%2) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x, center.y); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x, center.y); + } + rlEnd(); + + rlSetTexture(0); +#else + rlCheckRenderBatchLimit(3*segments); + + rlBegin(RL_TRIANGLES); + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(center.x, center.y); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + + angle += stepLength; + } + rlEnd(); +#endif +} + +void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color) +{ + if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero issue + + // Function expects (endAngle > startAngle) + if (endAngle < startAngle) + { + // Swap values + float tmp = startAngle; + startAngle = endAngle; + endAngle = tmp; + } + + int minSegments = (int)ceilf((endAngle - startAngle)/90); + + if (segments < minSegments) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); + segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); + + if (segments <= 0) segments = minSegments; + } + + float stepLength = (endAngle - startAngle)/(float)segments; + float angle = startAngle; + + // Hide the cap lines when the circle is full + bool showCapLines = true; + int limit = 2*(segments + 2); + if ((int)(endAngle - startAngle)%360 == 0) { limit = 2*segments; showCapLines = false; } + + rlCheckRenderBatchLimit(limit); + + rlBegin(RL_LINES); + if (showCapLines) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x, center.y); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + } + + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + + angle += stepLength; + } + + if (showCapLines) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x, center.y); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + } + rlEnd(); +} + +// Draw a gradient-filled circle +// NOTE: Gradient goes from center (color1) to border (color2) +void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2) +{ + rlCheckRenderBatchLimit(3*36); + + rlBegin(RL_TRIANGLES); + for (int i = 0; i < 360; i += 10) + { + rlColor4ub(color1.r, color1.g, color1.b, color1.a); + rlVertex2f((float)centerX, (float)centerY); + rlColor4ub(color2.r, color2.g, color2.b, color2.a); + rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radius, (float)centerY + cosf(DEG2RAD*i)*radius); + rlColor4ub(color2.r, color2.g, color2.b, color2.a); + rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radius, (float)centerY + cosf(DEG2RAD*(i + 10))*radius); + } + rlEnd(); +} + +// Draw a color-filled circle (Vector version) +// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues +void DrawCircleV(Vector2 center, float radius, Color color) +{ + DrawCircleSector(center, radius, 0, 360, 36, color); +} + +// Draw circle outline +void DrawCircleLines(int centerX, int centerY, float radius, Color color) +{ + rlCheckRenderBatchLimit(2*36); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) + for (int i = 0; i < 360; i += 10) + { + rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); + } + rlEnd(); +} + +// Draw ellipse +void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color) +{ + rlCheckRenderBatchLimit(3*36); + + rlBegin(RL_TRIANGLES); + for (int i = 0; i < 360; i += 10) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f((float)centerX, (float)centerY); + rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV); + rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV); + } + rlEnd(); +} + +// Draw ellipse outline +void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color) +{ + rlCheckRenderBatchLimit(2*36); + + rlBegin(RL_LINES); + for (int i = 0; i < 360; i += 10) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV); + } + rlEnd(); +} + +void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color) +{ + if (startAngle == endAngle) return; + + // Function expects (outerRadius > innerRadius) + if (outerRadius < innerRadius) + { + float tmp = outerRadius; + outerRadius = innerRadius; + innerRadius = tmp; + + if (outerRadius <= 0.0f) outerRadius = 0.1f; + } + + // Function expects (endAngle > startAngle) + if (endAngle < startAngle) + { + // Swap values + float tmp = startAngle; + startAngle = endAngle; + endAngle = tmp; + } + + int minSegments = (int)ceilf((endAngle - startAngle)/90); + + if (segments < minSegments) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1); + segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); + + if (segments <= 0) segments = minSegments; + } + + // Not a ring + if (innerRadius <= 0.0f) + { + DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, color); + return; + } + + float stepLength = (endAngle - startAngle)/(float)segments; + float angle = startAngle; + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlCheckRenderBatchLimit(4*segments); + + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + + angle += stepLength; + } + rlEnd(); + + rlSetTexture(0); +#else + rlCheckRenderBatchLimit(6*segments); + + rlBegin(RL_TRIANGLES); + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); + + angle += stepLength; + } + rlEnd(); +#endif +} + +void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color) +{ + if (startAngle == endAngle) return; + + // Function expects (outerRadius > innerRadius) + if (outerRadius < innerRadius) + { + float tmp = outerRadius; + outerRadius = innerRadius; + innerRadius = tmp; + + if (outerRadius <= 0.0f) outerRadius = 0.1f; + } + + // Function expects (endAngle > startAngle) + if (endAngle < startAngle) + { + // Swap values + float tmp = startAngle; + startAngle = endAngle; + endAngle = tmp; + } + + int minSegments = (int)ceilf((endAngle - startAngle)/90); + + if (segments < minSegments) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1); + segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); + + if (segments <= 0) segments = minSegments; + } + + if (innerRadius <= 0.0f) + { + DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, color); + return; + } + + float stepLength = (endAngle - startAngle)/(float)segments; + float angle = startAngle; + + bool showCapLines = true; + int limit = 4*(segments + 1); + if ((int)(endAngle - startAngle)%360 == 0) { limit = 4*segments; showCapLines = false; } + + rlCheckRenderBatchLimit(limit); + + rlBegin(RL_LINES); + if (showCapLines) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + } + + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); + + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + + angle += stepLength; + } + + if (showCapLines) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + } + rlEnd(); +} + +// Draw a color-filled rectangle +void DrawRectangle(int posX, int posY, int width, int height, Color color) +{ + DrawRectangleV((Vector2){ (float)posX, (float)posY }, (Vector2){ (float)width, (float)height }, color); +} + +// Draw a color-filled rectangle (Vector version) +// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues +void DrawRectangleV(Vector2 position, Vector2 size, Color color) +{ + DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color); +} + +// Draw a color-filled rectangle +void DrawRectangleRec(Rectangle rec, Color color) +{ + DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color); +} + +// Draw a color-filled rectangle with pro parameters +void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color) +{ + rlCheckRenderBatchLimit(4); + + Vector2 topLeft = { 0 }; + Vector2 topRight = { 0 }; + Vector2 bottomLeft = { 0 }; + Vector2 bottomRight = { 0 }; + + // Only calculate rotation if needed + if (rotation == 0.0f) + { + float x = rec.x - origin.x; + float y = rec.y - origin.y; + topLeft = (Vector2){ x, y }; + topRight = (Vector2){ x + rec.width, y }; + bottomLeft = (Vector2){ x, y + rec.height }; + bottomRight = (Vector2){ x + rec.width, y + rec.height }; + } + else + { + float sinRotation = sinf(rotation*DEG2RAD); + float cosRotation = cosf(rotation*DEG2RAD); + float x = rec.x; + float y = rec.y; + float dx = -origin.x; + float dy = -origin.y; + + topLeft.x = x + dx*cosRotation - dy*sinRotation; + topLeft.y = y + dx*sinRotation + dy*cosRotation; + + topRight.x = x + (dx + rec.width)*cosRotation - dy*sinRotation; + topRight.y = y + (dx + rec.width)*sinRotation + dy*cosRotation; + + bottomLeft.x = x + dx*cosRotation - (dy + rec.height)*sinRotation; + bottomLeft.y = y + dx*sinRotation + (dy + rec.height)*cosRotation; + + bottomRight.x = x + (dx + rec.width)*cosRotation - (dy + rec.height)*sinRotation; + bottomRight.y = y + (dx + rec.width)*sinRotation + (dy + rec.height)*cosRotation; + } + + rlSetTexture(texShapes.id); + rlBegin(RL_QUADS); + + rlNormal3f(0.0f, 0.0f, 1.0f); + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(topLeft.x, topLeft.y); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(bottomLeft.x, bottomLeft.y); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(bottomRight.x, bottomRight.y); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(topRight.x, topRight.y); + + rlEnd(); + rlSetTexture(0); +} + +// Draw a vertical-gradient-filled rectangle +// NOTE: Gradient goes from bottom (color1) to top (color2) +void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) +{ + DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color2, color2, color1); +} + +// Draw a horizontal-gradient-filled rectangle +// NOTE: Gradient goes from bottom (color1) to top (color2) +void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2) +{ + DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color1, color2, color2); +} + +// Draw a gradient-filled rectangle +// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise +void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4) +{ + rlSetTexture(texShapes.id); + + rlPushMatrix(); + rlBegin(RL_QUADS); + rlNormal3f(0.0f, 0.0f, 1.0f); + + // NOTE: Default raylib font character 95 is a white square + rlColor4ub(col1.r, col1.g, col1.b, col1.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(rec.x, rec.y); + + rlColor4ub(col2.r, col2.g, col2.b, col2.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(rec.x, rec.y + rec.height); + + rlColor4ub(col3.r, col3.g, col3.b, col3.a); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(rec.x + rec.width, rec.y + rec.height); + + rlColor4ub(col4.r, col4.g, col4.b, col4.a); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(rec.x + rec.width, rec.y); + rlEnd(); + rlPopMatrix(); + + rlSetTexture(0); +} + +// Draw rectangle outline +// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues +void DrawRectangleLines(int posX, int posY, int width, int height, Color color) +{ +#if defined(SUPPORT_QUADS_DRAW_MODE) + DrawRectangle(posX, posY, width, 1, color); + DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color); + DrawRectangle(posX, posY + height - 1, width, 1, color); + DrawRectangle(posX, posY + 1, 1, height - 2, color); +#else + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2i(posX + 1, posY + 1); + rlVertex2i(posX + width, posY + 1); + + rlVertex2i(posX + width, posY + 1); + rlVertex2i(posX + width, posY + height); + + rlVertex2i(posX + width, posY + height); + rlVertex2i(posX + 1, posY + height); + + rlVertex2i(posX + 1, posY + height); + rlVertex2i(posX + 1, posY + 1); + rlEnd(); +#endif +} + +// Draw rectangle outline with extended parameters +void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color) +{ + if ((lineThick > rec.width) || (lineThick > rec.height)) + { + if (rec.width > rec.height) lineThick = rec.height/2; + else if (rec.width < rec.height) lineThick = rec.width/2; + } + + // When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following + // four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight): + // + // TTTTTTTT + // TTTTTTTT + // LL RR + // LL RR + // BBBBBBBB + // BBBBBBBB + // + + Rectangle top = { rec.x, rec.y, rec.width, lineThick }; + Rectangle bottom = { rec.x, rec.y - lineThick + rec.height, rec.width, lineThick }; + Rectangle left = { rec.x, rec.y + lineThick, lineThick, rec.height - lineThick*2.0f }; + Rectangle right = { rec.x - lineThick + rec.width, rec.y + lineThick, lineThick, rec.height - lineThick*2.0f }; + + DrawRectangleRec(top, color); + DrawRectangleRec(bottom, color); + DrawRectangleRec(left, color); + DrawRectangleRec(right, color); +} + +// Draw rectangle with rounded edges +void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color) +{ + // Not a rounded rectangle + if ((roundness <= 0.0f) || (rec.width < 1) || (rec.height < 1 )) + { + DrawRectangleRec(rec, color); + return; + } + + if (roundness >= 1.0f) roundness = 1.0f; + + // Calculate corner radius + float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2; + if (radius <= 0.0f) return; + + // Calculate number of segments to use for the corners + if (segments < 4) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); + segments = (int)(ceilf(2*PI/th)/4.0f); + if (segments <= 0) segments = 4; + } + + float stepLength = 90.0f/(float)segments; + + /* + Quick sketch to make sense of all of this, + there are 9 parts to draw, also mark the 12 points we'll use + + P0____________________P1 + /| |\ + /1| 2 |3\ + P7 /__|____________________|__\ P2 + | |P8 P9| | + | 8 | 9 | 4 | + | __|____________________|__ | + P6 \ |P11 P10| / P3 + \7| 6 |5/ + \|____________________|/ + P5 P4 + */ + // Coordinates of the 12 points that define the rounded rect + const Vector2 point[12] = { + {(float)rec.x + radius, rec.y}, {(float)(rec.x + rec.width) - radius, rec.y}, { rec.x + rec.width, (float)rec.y + radius }, // PO, P1, P2 + {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height}, // P3, P4 + {(float)rec.x + radius, rec.y + rec.height}, { rec.x, (float)(rec.y + rec.height) - radius}, {rec.x, (float)rec.y + radius}, // P5, P6, P7 + {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius}, // P8, P9 + {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11 + }; + + const Vector2 centers[4] = { point[8], point[9], point[10], point[11] }; + const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f }; + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlCheckRenderBatchLimit(16*segments/2 + 5*4); + + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + + // NOTE: Every QUAD actually represents two segments + for (int i = 0; i < segments/2; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x, center.y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius); + angle += (stepLength*2); + } + + // NOTE: In case number of segments is odd, we add one last piece to the cake + if (segments%2) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x, center.y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x, center.y); + } + } + + // [2] Upper Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[0].x, point[0].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[8].x, point[8].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[9].x, point[9].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[1].x, point[1].y); + + // [4] Right Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[2].x, point[2].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[9].x, point[9].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[10].x, point[10].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[3].x, point[3].y); + + // [6] Bottom Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[11].x, point[11].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[5].x, point[5].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[4].x, point[4].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[10].x, point[10].y); + + // [8] Left Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[7].x, point[7].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[6].x, point[6].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[11].x, point[11].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[8].x, point[8].y); + + // [9] Middle Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[8].x, point[8].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[11].x, point[11].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[10].x, point[10].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[9].x, point[9].y); + + rlEnd(); + rlSetTexture(0); +#else + rlCheckRenderBatchLimit(12*segments + 5*6); // 4 corners with 3 vertices per segment + 5 rectangles with 6 vertices each + + rlBegin(RL_TRIANGLES); + + // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x, center.y); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); + angle += stepLength; + } + } + + // [2] Upper Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[0].x, point[0].y); + rlVertex2f(point[8].x, point[8].y); + rlVertex2f(point[9].x, point[9].y); + rlVertex2f(point[1].x, point[1].y); + rlVertex2f(point[0].x, point[0].y); + rlVertex2f(point[9].x, point[9].y); + + // [4] Right Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[9].x, point[9].y); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[3].x, point[3].y); + rlVertex2f(point[2].x, point[2].y); + rlVertex2f(point[9].x, point[9].y); + rlVertex2f(point[3].x, point[3].y); + + // [6] Bottom Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[11].x, point[11].y); + rlVertex2f(point[5].x, point[5].y); + rlVertex2f(point[4].x, point[4].y); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[11].x, point[11].y); + rlVertex2f(point[4].x, point[4].y); + + // [8] Left Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[7].x, point[7].y); + rlVertex2f(point[6].x, point[6].y); + rlVertex2f(point[11].x, point[11].y); + rlVertex2f(point[8].x, point[8].y); + rlVertex2f(point[7].x, point[7].y); + rlVertex2f(point[11].x, point[11].y); + + // [9] Middle Rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[8].x, point[8].y); + rlVertex2f(point[11].x, point[11].y); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[9].x, point[9].y); + rlVertex2f(point[8].x, point[8].y); + rlVertex2f(point[10].x, point[10].y); + rlEnd(); +#endif +} + +// Draw rectangle with rounded edges outline +void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, float lineThick, Color color) +{ + if (lineThick < 0) lineThick = 0; + + // Not a rounded rectangle + if (roundness <= 0.0f) + { + DrawRectangleLinesEx((Rectangle){rec.x-lineThick, rec.y-lineThick, rec.width+2*lineThick, rec.height+2*lineThick}, lineThick, color); + return; + } + + if (roundness >= 1.0f) roundness = 1.0f; + + // Calculate corner radius + float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2; + if (radius <= 0.0f) return; + + // Calculate number of segments to use for the corners + if (segments < 4) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); + segments = (int)(ceilf(2*PI/th)/2.0f); + if (segments <= 0) segments = 4; + } + + float stepLength = 90.0f/(float)segments; + const float outerRadius = radius + lineThick, innerRadius = radius; + + /* + Quick sketch to make sense of all of this, + marks the 16 + 4(corner centers P16-19) points we'll use + + P0 ================== P1 + // P8 P9 \\ + // \\ + P7 // P15 P10 \\ P2 + || *P16 P17* || + || || + || P14 P11 || + P6 \\ *P19 P18* // P3 + \\ // + \\ P13 P12 // + P5 ================== P4 + */ + const Vector2 point[16] = { + {(float)rec.x + innerRadius, rec.y - lineThick}, {(float)(rec.x + rec.width) - innerRadius, rec.y - lineThick}, { rec.x + rec.width + lineThick, (float)rec.y + innerRadius }, // PO, P1, P2 + {rec.x + rec.width + lineThick, (float)(rec.y + rec.height) - innerRadius}, {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height + lineThick}, // P3, P4 + {(float)rec.x + innerRadius, rec.y + rec.height + lineThick}, { rec.x - lineThick, (float)(rec.y + rec.height) - innerRadius}, {rec.x - lineThick, (float)rec.y + innerRadius}, // P5, P6, P7 + {(float)rec.x + innerRadius, rec.y}, {(float)(rec.x + rec.width) - innerRadius, rec.y}, // P8, P9 + { rec.x + rec.width, (float)rec.y + innerRadius }, {rec.x + rec.width, (float)(rec.y + rec.height) - innerRadius}, // P10, P11 + {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height}, {(float)rec.x + innerRadius, rec.y + rec.height}, // P12, P13 + { rec.x, (float)(rec.y + rec.height) - innerRadius}, {rec.x, (float)rec.y + innerRadius} // P14, P15 + }; + + const Vector2 centers[4] = { + {(float)rec.x + innerRadius, (float)rec.y + innerRadius}, {(float)(rec.x + rec.width) - innerRadius, (float)rec.y + innerRadius}, // P16, P17 + {(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19 + }; + + const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f }; + + if (lineThick > 1) + { +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlCheckRenderBatchLimit(4*4*segments + 4*4); // 4 corners with 4 vertices for each segment + 4 rectangles with 4 vertices each + + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + + // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + + angle += stepLength; + } + } + + // Upper rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[0].x, point[0].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[8].x, point[8].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[9].x, point[9].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[1].x, point[1].y); + + // Right rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[2].x, point[2].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[10].x, point[10].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[11].x, point[11].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[3].x, point[3].y); + + // Lower rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[13].x, point[13].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[5].x, point[5].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[4].x, point[4].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[12].x, point[12].y); + + // Left rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[15].x, point[15].y); + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[7].x, point[7].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(point[6].x, point[6].y); + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(point[14].x, point[14].y); + + rlEnd(); + rlSetTexture(0); +#else + rlCheckRenderBatchLimit(4*6*segments + 4*6); // 4 corners with 6(2*3) vertices for each segment + 4 rectangles with 6 vertices each + + rlBegin(RL_TRIANGLES); + + // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); + + angle += stepLength; + } + } + + // Upper rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[0].x, point[0].y); + rlVertex2f(point[8].x, point[8].y); + rlVertex2f(point[9].x, point[9].y); + rlVertex2f(point[1].x, point[1].y); + rlVertex2f(point[0].x, point[0].y); + rlVertex2f(point[9].x, point[9].y); + + // Right rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[11].x, point[11].y); + rlVertex2f(point[3].x, point[3].y); + rlVertex2f(point[2].x, point[2].y); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[3].x, point[3].y); + + // Lower rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[13].x, point[13].y); + rlVertex2f(point[5].x, point[5].y); + rlVertex2f(point[4].x, point[4].y); + rlVertex2f(point[12].x, point[12].y); + rlVertex2f(point[13].x, point[13].y); + rlVertex2f(point[4].x, point[4].y); + + // Left rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[7].x, point[7].y); + rlVertex2f(point[6].x, point[6].y); + rlVertex2f(point[14].x, point[14].y); + rlVertex2f(point[15].x, point[15].y); + rlVertex2f(point[7].x, point[7].y); + rlVertex2f(point[14].x, point[14].y); + rlEnd(); +#endif + } + else + { + // Use LINES to draw the outline + rlCheckRenderBatchLimit(8*segments + 4*2); // 4 corners with 2 vertices for each segment + 4 rectangles with 2 vertices each + + rlBegin(RL_LINES); + + // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); + rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); + angle += stepLength; + } + } + + // And now the remaining 4 lines + for (int i = 0; i < 8; i += 2) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[i].x, point[i].y); + rlVertex2f(point[i + 1].x, point[i + 1].y); + } + + rlEnd(); + } +} + +// Draw a triangle +// NOTE: Vertex must be provided in counter-clockwise order +void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) +{ + rlCheckRenderBatchLimit(4); + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(v1.x, v1.y); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(v2.x, v2.y); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(v2.x, v2.y); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(v3.x, v3.y); + rlEnd(); + + rlSetTexture(0); +#else + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(v1.x, v1.y); + rlVertex2f(v2.x, v2.y); + rlVertex2f(v3.x, v3.y); + rlEnd(); +#endif +} + +// Draw a triangle using lines +// NOTE: Vertex must be provided in counter-clockwise order +void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color) +{ + rlCheckRenderBatchLimit(6); + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(v1.x, v1.y); + rlVertex2f(v2.x, v2.y); + + rlVertex2f(v2.x, v2.y); + rlVertex2f(v3.x, v3.y); + + rlVertex2f(v3.x, v3.y); + rlVertex2f(v1.x, v1.y); + rlEnd(); +} + +// Draw a triangle fan defined by points +// NOTE: First vertex provided is the center, shared by all triangles +// By default, following vertex should be provided in counter-clockwise order +void DrawTriangleFan(Vector2 *points, int pointsCount, Color color) +{ + if (pointsCount >= 3) + { + rlCheckRenderBatchLimit((pointsCount - 2)*4); + + rlSetTexture(texShapes.id); + rlBegin(RL_QUADS); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 1; i < pointsCount - 1; i++) + { + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(points[0].x, points[0].y); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(points[i].x, points[i].y); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(points[i + 1].x, points[i + 1].y); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(points[i + 1].x, points[i + 1].y); + } + rlEnd(); + rlSetTexture(0); + } +} + +// Draw a triangle strip defined by points +// NOTE: Every new vertex connects with previous two +void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color) +{ + if (pointsCount >= 3) + { + rlCheckRenderBatchLimit(3*(pointsCount - 2)); + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 2; i < pointsCount; i++) + { + if ((i%2) == 0) + { + rlVertex2f(points[i].x, points[i].y); + rlVertex2f(points[i - 2].x, points[i - 2].y); + rlVertex2f(points[i - 1].x, points[i - 1].y); + } + else + { + rlVertex2f(points[i].x, points[i].y); + rlVertex2f(points[i - 1].x, points[i - 1].y); + rlVertex2f(points[i - 2].x, points[i - 2].y); + } + } + rlEnd(); + } +} + +// Draw a regular polygon of n sides (Vector version) +void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color) +{ + if (sides < 3) sides = 3; + float centralAngle = 0.0f; + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlCheckRenderBatchLimit(4*sides); // Each side is a quad +#else + rlCheckRenderBatchLimit(3*sides); +#endif + + rlPushMatrix(); + rlTranslatef(center.x, center.y, 0.0f); + rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + for (int i = 0; i < sides; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(0, 0); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + + centralAngle += 360.0f/(float)sides; + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + } + rlEnd(); + rlSetTexture(0); +#else + rlBegin(RL_TRIANGLES); + for (int i = 0; i < sides; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(0, 0); + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + + centralAngle += 360.0f/(float)sides; + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + } + rlEnd(); +#endif + rlPopMatrix(); +} + +// Draw a polygon outline of n sides +void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color) +{ + if (sides < 3) sides = 3; + float centralAngle = 0.0f; + + rlCheckRenderBatchLimit(2*sides); + + rlPushMatrix(); + rlTranslatef(center.x, center.y, 0.0f); + rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + + rlBegin(RL_LINES); + for (int i = 0; i < sides; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + centralAngle += 360.0f/(float)sides; + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + } + rlEnd(); + rlPopMatrix(); +} + +void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color) +{ + if (sides < 3) sides = 3; + float centralAngle = 0.0f; + float exteriorAngle = 360.0f/(float)sides; + float innerRadius = radius - (lineThick*cosf(DEG2RAD*exteriorAngle/2.0f)); + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlCheckRenderBatchLimit(4*sides); +#else + rlCheckRenderBatchLimit(6*sides); +#endif + + rlPushMatrix(); + rlTranslatef(center.x, center.y, 0.0f); + rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + +#if defined(SUPPORT_QUADS_DRAW_MODE) + rlSetTexture(texShapes.id); + + rlBegin(RL_QUADS); + for (int i = 0; i < sides; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*innerRadius, cosf(DEG2RAD*centralAngle)*innerRadius); + + rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + + centralAngle += exteriorAngle; + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + + rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); + rlVertex2f(sinf(DEG2RAD*centralAngle)*innerRadius, cosf(DEG2RAD*centralAngle)*innerRadius); + } + rlEnd(); + rlSetTexture(0); +#else + rlBegin(RL_TRIANGLES); + for (int i = 0; i < sides; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + float nextAngle = centralAngle + exteriorAngle; + + rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius); + rlVertex2f(sinf(DEG2RAD*centralAngle)*innerRadius, cosf(DEG2RAD*centralAngle)*innerRadius); + rlVertex2f(sinf(DEG2RAD*nextAngle)*radius, cosf(DEG2RAD*nextAngle)*radius); + + rlVertex2f(sinf(DEG2RAD*centralAngle)*innerRadius, cosf(DEG2RAD*centralAngle)*innerRadius); + rlVertex2f(sinf(DEG2RAD*nextAngle)*radius, cosf(DEG2RAD*nextAngle)*radius); + rlVertex2f(sinf(DEG2RAD*nextAngle)*innerRadius, cosf(DEG2RAD*nextAngle)*innerRadius); + + centralAngle = nextAngle; + } + rlEnd(); +#endif + rlPopMatrix(); +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Collision Detection functions +//---------------------------------------------------------------------------------- + +// Check if point is inside rectangle +bool CheckCollisionPointRec(Vector2 point, Rectangle rec) +{ + bool collision = false; + + if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; + + return collision; +} + +// Check if point is inside circle +bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius) +{ + return CheckCollisionCircles(point, 0, center, radius); +} + +// Check if point is inside a triangle defined by three points (p1, p2, p3) +bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3) +{ + bool collision = false; + + float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) / + ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); + + float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) / + ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); + + float gamma = 1.0f - alpha - beta; + + if ((alpha > 0) && (beta > 0) && (gamma > 0)) collision = true; + + return collision; +} + +// Check collision between two rectangles +bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2) +{ + bool collision = false; + + if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) && + (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true; + + return collision; +} + +// Check collision between two circles +bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2) +{ + bool collision = false; + + float dx = center2.x - center1.x; // X distance between centers + float dy = center2.y - center1.y; // Y distance between centers + + float distance = sqrtf(dx*dx + dy*dy); // Distance between centers + + if (distance <= (radius1 + radius2)) collision = true; + + return collision; +} + +// Check collision between circle and rectangle +// NOTE: Reviewed version to take into account corner limit case +bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) +{ + int recCenterX = (int)(rec.x + rec.width/2.0f); + int recCenterY = (int)(rec.y + rec.height/2.0f); + + float dx = fabsf(center.x - (float)recCenterX); + float dy = fabsf(center.y - (float)recCenterY); + + if (dx > (rec.width/2.0f + radius)) { return false; } + if (dy > (rec.height/2.0f + radius)) { return false; } + + if (dx <= (rec.width/2.0f)) { return true; } + if (dy <= (rec.height/2.0f)) { return true; } + + float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) + + (dy - rec.height/2.0f)*(dy - rec.height/2.0f); + + return (cornerDistanceSq <= (radius*radius)); +} + +// Check the collision between two lines defined by two points each, returns collision point by reference +bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint) +{ + const float div = (endPos2.y - startPos2.y)*(endPos1.x - startPos1.x) - (endPos2.x - startPos2.x)*(endPos1.y - startPos1.y); + + if (div == 0.0f) return false; // WARNING: This check could not work due to float precision rounding issues... + + const float xi = ((startPos2.x - endPos2.x)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.x - endPos1.x)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div; + const float yi = ((startPos2.y - endPos2.y)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.y - endPos1.y)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div; + + if (xi < fminf(startPos1.x, endPos1.x) || xi > fmaxf(startPos1.x, endPos1.x)) return false; + if (xi < fminf(startPos2.x, endPos2.x) || xi > fmaxf(startPos2.x, endPos2.x)) return false; + if (yi < fminf(startPos1.y, endPos1.y) || yi > fmaxf(startPos1.y, endPos1.y)) return false; + if (yi < fminf(startPos2.y, endPos2.y) || yi > fmaxf(startPos2.y, endPos2.y)) return false; + + if (collisionPoint != 0) + { + collisionPoint->x = xi; + collisionPoint->y = yi; + } + + return true; +} + +// Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] +bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold) +{ + bool collision = false; + float dxc = point.x - p1.x; + float dyc = point.y - p1.y; + float dxl = p2.x - p1.x; + float dyl = p2.y - p1.y; + float cross = dxc*dyl - dyc*dxl; + + if (fabsf(cross) < (threshold*fmaxf(fabsf(dxl), fabsf(dyl)))) + { + if (fabsf(dxl) >= fabsf(dyl)) collision = (dxl > 0)? ((p1.x <= point.x) && (point.x <= p2.x)) : ((p2.x <= point.x) && (point.x <= p1.x)); + else collision = (dyl > 0)? ((p1.y <= point.y) && (point.y <= p2.y)) : ((p2.y <= point.y) && (point.y <= p1.y)); + } + + return collision; +} + +// Get collision rectangle for two rectangles collision +Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) +{ + Rectangle rec = { 0, 0, 0, 0 }; + + if (CheckCollisionRecs(rec1, rec2)) + { + float dxx = fabsf(rec1.x - rec2.x); + float dyy = fabsf(rec1.y - rec2.y); + + if (rec1.x <= rec2.x) + { + if (rec1.y <= rec2.y) + { + rec.x = rec2.x; + rec.y = rec2.y; + rec.width = rec1.width - dxx; + rec.height = rec1.height - dyy; + } + else + { + rec.x = rec2.x; + rec.y = rec1.y; + rec.width = rec1.width - dxx; + rec.height = rec2.height - dyy; + } + } + else + { + if (rec1.y <= rec2.y) + { + rec.x = rec1.x; + rec.y = rec2.y; + rec.width = rec2.width - dxx; + rec.height = rec1.height - dyy; + } + else + { + rec.x = rec1.x; + rec.y = rec1.y; + rec.width = rec2.width - dxx; + rec.height = rec2.height - dyy; + } + } + + if (rec1.width > rec2.width) + { + if (rec.width >= rec2.width) rec.width = rec2.width; + } + else + { + if (rec.width >= rec1.width) rec.width = rec1.width; + } + + if (rec1.height > rec2.height) + { + if (rec.height >= rec2.height) rec.height = rec2.height; + } + else + { + if (rec.height >= rec1.height) rec.height = rec1.height; + } + } + + return rec; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +// Cubic easing in-out +// NOTE: Required for DrawLineBezier() +static float EaseCubicInOut(float t, float b, float c, float d) +{ + if ((t /= 0.5f*d) < 1) return 0.5f*c*t*t*t + b; + + t -= 2; + + return 0.5f*c*(t*t*t + 2.0f) + b; +} diff --git a/raylib/shapes.go b/raylib/shapes.go new file mode 100644 index 0000000..06804e2 --- /dev/null +++ b/raylib/shapes.go @@ -0,0 +1,406 @@ +package rl + +/* +#include "raylib.h" +#include +*/ +import "C" +import "unsafe" + +// DrawPixel - Draw a pixel +func DrawPixel(posX, posY int32, color Color) { + cposX := (C.int)(posX) + cposY := (C.int)(posY) + ccolor := color.cptr() + C.DrawPixel(cposX, cposY, *ccolor) +} + +// DrawPixelV - Draw a pixel (Vector version) +func DrawPixelV(position Vector2, color Color) { + cposition := position.cptr() + ccolor := color.cptr() + C.DrawPixelV(*cposition, *ccolor) +} + +// DrawLine - Draw a line +func DrawLine(startPosX, startPosY, endPosX, endPosY int32, color Color) { + cstartPosX := (C.int)(startPosX) + cstartPosY := (C.int)(startPosY) + cendPosX := (C.int)(endPosX) + cendPosY := (C.int)(endPosY) + ccolor := color.cptr() + C.DrawLine(cstartPosX, cstartPosY, cendPosX, cendPosY, *ccolor) +} + +// DrawLineV - Draw a line (Vector version) +func DrawLineV(startPos, endPos Vector2, color Color) { + cstartPos := startPos.cptr() + cendPos := endPos.cptr() + ccolor := color.cptr() + C.DrawLineV(*cstartPos, *cendPos, *ccolor) +} + +// DrawLineEx - Draw a line defining thickness +func DrawLineEx(startPos, endPos Vector2, thick float32, color Color) { + cstartPos := startPos.cptr() + cendPos := endPos.cptr() + cthick := (C.float)(thick) + ccolor := color.cptr() + C.DrawLineEx(*cstartPos, *cendPos, cthick, *ccolor) +} + +// DrawLineBezier - Draw a line using cubic-bezier curves in-out +func DrawLineBezier(startPos, endPos Vector2, thick float32, color Color) { + cstartPos := startPos.cptr() + cendPos := endPos.cptr() + cthick := (C.float)(thick) + ccolor := color.cptr() + C.DrawLineBezier(*cstartPos, *cendPos, cthick, *ccolor) +} + +// DrawCircle - Draw a color-filled circle +func DrawCircle(centerX, centerY int32, radius float32, color Color) { + ccenterX := (C.int)(centerX) + ccenterY := (C.int)(centerY) + cradius := (C.float)(radius) + ccolor := color.cptr() + C.DrawCircle(ccenterX, ccenterY, cradius, *ccolor) +} + +// DrawCircleSector - Draw a piece of a circle +func DrawCircleSector(center Vector2, radius, startAngle, endAngle float32, segments int32, color Color) { + ccenter := center.cptr() + cradius := (C.float)(radius) + cstartAngle := (C.float)(startAngle) + cendAngle := (C.float)(endAngle) + csegments := (C.int)(segments) + ccolor := color.cptr() + C.DrawCircleSector(*ccenter, cradius, cstartAngle, cendAngle, csegments, *ccolor) +} + +// DrawCircleSectorLines - +func DrawCircleSectorLines(center Vector2, radius, startAngle, endAngle float32, segments int32, color Color) { + ccenter := center.cptr() + cradius := (C.float)(radius) + cstartAngle := (C.float)(startAngle) + cendAngle := (C.float)(endAngle) + csegments := (C.int)(segments) + ccolor := color.cptr() + C.DrawCircleSectorLines(*ccenter, cradius, cstartAngle, cendAngle, csegments, *ccolor) +} + +// DrawCircleGradient - Draw a gradient-filled circle +func DrawCircleGradient(centerX, centerY int32, radius float32, color1, color2 Color) { + ccenterX := (C.int)(centerX) + ccenterY := (C.int)(centerY) + cradius := (C.float)(radius) + ccolor1 := color1.cptr() + ccolor2 := color2.cptr() + C.DrawCircleGradient(ccenterX, ccenterY, cradius, *ccolor1, *ccolor2) +} + +// DrawCircleV - Draw a color-filled circle (Vector version) +func DrawCircleV(center Vector2, radius float32, color Color) { + ccenter := center.cptr() + cradius := (C.float)(radius) + ccolor := color.cptr() + C.DrawCircleV(*ccenter, cradius, *ccolor) +} + +// DrawCircleLines - Draw circle outline +func DrawCircleLines(centerX, centerY int32, radius float32, color Color) { + ccenterX := (C.int)(centerX) + ccenterY := (C.int)(centerY) + cradius := (C.float)(radius) + ccolor := color.cptr() + C.DrawCircleLines(ccenterX, ccenterY, cradius, *ccolor) +} + +// DrawEllipse - Draw ellipse +func DrawEllipse(centerX, centerY int32, radiusH, radiusV float32, color Color) { + ccenterX := (C.int)(centerX) + ccenterY := (C.int)(centerY) + cradiusH := (C.float)(radiusH) + cradiusV := (C.float)(radiusV) + ccolor := color.cptr() + C.DrawEllipse(ccenterX, ccenterY, cradiusH, cradiusV, *ccolor) +} + +// DrawEllipseLines - Draw ellipse outline +func DrawEllipseLines(centerX, centerY int32, radiusH, radiusV float32, color Color) { + ccenterX := (C.int)(centerX) + ccenterY := (C.int)(centerY) + cradiusH := (C.float)(radiusH) + cradiusV := (C.float)(radiusV) + ccolor := color.cptr() + C.DrawEllipseLines(ccenterX, ccenterY, cradiusH, cradiusV, *ccolor) +} + +// DrawRing - +func DrawRing(center Vector2, innerRadius, outerRadius, startAngle, endAngle float32, segments int32, color Color) { + ccenter := center.cptr() + cinnerRadius := (C.float)(innerRadius) + couterRadius := (C.float)(outerRadius) + cstartAngle := (C.float)(startAngle) + cendAngle := (C.float)(endAngle) + csegments := (C.int)(segments) + ccolor := color.cptr() + C.DrawRing(*ccenter, cinnerRadius, couterRadius, cstartAngle, cendAngle, csegments, *ccolor) +} + +// DrawRingLines - +func DrawRingLines(center Vector2, innerRadius, outerRadius, startAngle, endAngle float32, segments int32, color Color) { + ccenter := center.cptr() + cinnerRadius := (C.float)(innerRadius) + couterRadius := (C.float)(outerRadius) + cstartAngle := (C.float)(startAngle) + cendAngle := (C.float)(endAngle) + csegments := (C.int)(segments) + ccolor := color.cptr() + C.DrawRingLines(*ccenter, cinnerRadius, couterRadius, cstartAngle, cendAngle, csegments, *ccolor) +} + +// DrawRectangle - Draw a color-filled rectangle +func DrawRectangle(posX, posY, width, height int32, color Color) { + cposX := (C.int)(posX) + cposY := (C.int)(posY) + cwidth := (C.int)(width) + cheight := (C.int)(height) + ccolor := color.cptr() + C.DrawRectangle(cposX, cposY, cwidth, cheight, *ccolor) +} + +// DrawRectangleRec - Draw a color-filled rectangle +func DrawRectangleRec(rec Rectangle, color Color) { + crec := rec.cptr() + ccolor := color.cptr() + C.DrawRectangleRec(*crec, *ccolor) +} + +// DrawRectanglePro - Draw a color-filled rectangle with pro parameters +func DrawRectanglePro(rec Rectangle, origin Vector2, rotation float32, colors []Color) { + crec := rec.cptr() + corigin := origin.cptr() + crotation := (C.float)(rotation) + ccolor := (*C.Color)(unsafe.Pointer(&colors[0])) + C.DrawRectanglePro(*crec, *corigin, crotation, *ccolor) +} + +// DrawRectangleGradientV - Draw a vertical-gradient-filled rectangle +func DrawRectangleGradientV(posX, posY, width, height int32, color1, color2 Color) { + cposX := (C.int)(posX) + cposY := (C.int)(posY) + cwidth := (C.int)(width) + cheight := (C.int)(height) + ccolor1 := color1.cptr() + ccolor2 := color2.cptr() + C.DrawRectangleGradientV(cposX, cposY, cwidth, cheight, *ccolor1, *ccolor2) +} + +// DrawRectangleGradientH - Draw a horizontal-gradient-filled rectangle +func DrawRectangleGradientH(posX, posY, width, height int32, color1, color2 Color) { + cposX := (C.int)(posX) + cposY := (C.int)(posY) + cwidth := (C.int)(width) + cheight := (C.int)(height) + ccolor1 := color1.cptr() + ccolor2 := color2.cptr() + C.DrawRectangleGradientH(cposX, cposY, cwidth, cheight, *ccolor1, *ccolor2) +} + +// DrawRectangleGradientEx - Draw a gradient-filled rectangle with custom vertex colors +func DrawRectangleGradientEx(rec Rectangle, color1, color2, color3, color4 Color) { + crec := rec.cptr() + ccolor1 := color1.cptr() + ccolor2 := color2.cptr() + ccolor3 := color3.cptr() + ccolor4 := color4.cptr() + C.DrawRectangleGradientEx(*crec, *ccolor1, *ccolor2, *ccolor3, *ccolor4) +} + +// DrawRectangleV - Draw a color-filled rectangle (Vector version) +func DrawRectangleV(position Vector2, size Vector2, color Color) { + cposition := position.cptr() + csize := size.cptr() + ccolor := color.cptr() + C.DrawRectangleV(*cposition, *csize, *ccolor) +} + +// DrawRectangleLines - Draw rectangle outline +func DrawRectangleLines(posX, posY, width, height int32, color Color) { + cposX := (C.int)(posX) + cposY := (C.int)(posY) + cwidth := (C.int)(width) + cheight := (C.int)(height) + ccolor := color.cptr() + C.DrawRectangleLines(cposX, cposY, cwidth, cheight, *ccolor) +} + +// DrawRectangleLinesEx - Draw rectangle outline with extended parameters +func DrawRectangleLinesEx(rec Rectangle, lineThick float32, color Color) { + crec := rec.cptr() + clineThick := (C.float)(lineThick) + ccolor := color.cptr() + C.DrawRectangleLinesEx(*crec, clineThick, *ccolor) +} + +// DrawRectangleRounded - Draw rectangle with rounded edges +func DrawRectangleRounded(rec Rectangle, roundness float32, segments int32, color Color) { + crec := rec.cptr() + croundness := (C.float)(roundness) + csegments := (C.int)(segments) + ccolor := color.cptr() + C.DrawRectangleRounded(*crec, croundness, csegments, *ccolor) +} + +// DrawRectangleRoundedLines - Draw rectangle with rounded edges outline +func DrawRectangleRoundedLines(rec Rectangle, roundness float32, segments, lineThick float32, color Color) { + crec := rec.cptr() + croundness := (C.float)(roundness) + csegments := (C.int)(segments) + clineThick := (C.float)(lineThick) + ccolor := color.cptr() + C.DrawRectangleRoundedLines(*crec, croundness, csegments, clineThick, *ccolor) +} + +// DrawTriangle - Draw a color-filled triangle +func DrawTriangle(v1, v2, v3 Vector2, color Color) { + cv1 := v1.cptr() + cv2 := v2.cptr() + cv3 := v3.cptr() + ccolor := color.cptr() + C.DrawTriangle(*cv1, *cv2, *cv3, *ccolor) +} + +// DrawTriangleLines - Draw triangle outline +func DrawTriangleLines(v1, v2, v3 Vector2, color Color) { + cv1 := v1.cptr() + cv2 := v2.cptr() + cv3 := v3.cptr() + ccolor := color.cptr() + C.DrawTriangleLines(*cv1, *cv2, *cv3, *ccolor) +} + +// DrawTriangleFan - Draw a triangle fan defined by points +func DrawTriangleFan(points []Vector2, color Color) { + cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) + cpointsCount := (C.int)(int32(len(points))) + ccolor := color.cptr() + C.DrawTriangleFan(cpoints, cpointsCount, *ccolor) +} + +// DrawTriangleStrip - Draw a triangle strip defined by points +func DrawTriangleStrip(points []Vector2, color Color) { + cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) + cpointsCount := (C.int)(int32(len(points))) + ccolor := color.cptr() + C.DrawTriangleStrip(cpoints, cpointsCount, *ccolor) +} + +// DrawPoly - Draw a regular polygon (Vector version) +func DrawPoly(center Vector2, sides int32, radius, rotation float32, color Color) { + ccenter := center.cptr() + csides := (C.int)(sides) + cradius := (C.float)(radius) + crotation := (C.float)(rotation) + ccolor := color.cptr() + C.DrawPoly(*ccenter, csides, cradius, crotation, *ccolor) +} + +// DrawPolyLines - Draw a polygon outline of n sides +func DrawPolyLines(center Vector2, sides int32, radius, rotation float32, color Color) { + ccenter := center.cptr() + csides := (C.int)(sides) + cradius := (C.float)(radius) + crotation := (C.float)(rotation) + ccolor := color.cptr() + C.DrawPolyLines(*ccenter, csides, cradius, crotation, *ccolor) +} + +// CheckCollisionRecs - Check collision between two rectangles +func CheckCollisionRecs(rec1, rec2 Rectangle) bool { + crec1 := rec1.cptr() + crec2 := rec2.cptr() + ret := C.CheckCollisionRecs(*crec1, *crec2) + v := bool(ret) + return v +} + +// CheckCollisionCircles - Check collision between two circles +func CheckCollisionCircles(center1 Vector2, radius1 float32, center2 Vector2, radius2 float32) bool { + ccenter1 := center1.cptr() + cradius1 := (C.float)(radius1) + ccenter2 := center2.cptr() + cradius2 := (C.float)(radius2) + ret := C.CheckCollisionCircles(*ccenter1, cradius1, *ccenter2, cradius2) + v := bool(ret) + return v +} + +// CheckCollisionCircleRec - Check collision between circle and rectangle +func CheckCollisionCircleRec(center Vector2, radius float32, rec Rectangle) bool { + ccenter := center.cptr() + cradius := (C.float)(radius) + crec := rec.cptr() + ret := C.CheckCollisionCircleRec(*ccenter, cradius, *crec) + v := bool(ret) + return v +} + +// CheckCollisionPointRec - Check if point is inside rectangle +func CheckCollisionPointRec(point Vector2, rec Rectangle) bool { + cpoint := point.cptr() + crec := rec.cptr() + ret := C.CheckCollisionPointRec(*cpoint, *crec) + v := bool(ret) + return v +} + +// CheckCollisionPointCircle - Check if point is inside circle +func CheckCollisionPointCircle(point Vector2, center Vector2, radius float32) bool { + cpoint := point.cptr() + ccenter := center.cptr() + cradius := (C.float)(radius) + ret := C.CheckCollisionPointCircle(*cpoint, *ccenter, cradius) + v := bool(ret) + return v +} + +// CheckCollisionPointTriangle - Check if point is inside a triangle +func CheckCollisionPointTriangle(point, p1, p2, p3 Vector2) bool { + cpoint := point.cptr() + cp1 := p1.cptr() + cp2 := p2.cptr() + cp3 := p3.cptr() + ret := C.CheckCollisionPointTriangle(*cpoint, *cp1, *cp2, *cp3) + v := bool(ret) + return v +} + +// CheckCollisionLines - Check the collision between two lines defined by two points each, returns collision point by reference +func CheckCollisionLines(startPos1, endPos1, startPos2, endPos2 Vector2, point *Vector2) bool { + cstartPos1 := startPos1.cptr() + cendPos1 := endPos1.cptr() + cstartPos2 := startPos2.cptr() + cendPos2 := endPos2.cptr() + cpoint := point.cptr() + ret := C.CheckCollisionLines(*cstartPos1, *cendPos1, *cstartPos2, *cendPos2, cpoint) + v := bool(ret) + return v +} + +// GetCollisionRec - Get collision rectangle for two rectangles collision +func GetCollisionRec(rec1, rec2 Rectangle) Rectangle { + crec1 := rec1.cptr() + crec2 := rec2.cptr() + ret := C.GetCollisionRec(*crec1, *crec2) + v := newRectangleFromPointer(unsafe.Pointer(&ret)) + return v +} + +// SetShapesTexture - Define default texture used to draw shapes +func SetShapesTexture(texture Texture2D, source Rectangle) { + ctexture := texture.cptr() + csource := source.cptr() + C.SetShapesTexture(*ctexture, *csource) +} diff --git a/raylib/text.c b/raylib/text.c new file mode 100644 index 0000000..23cad7e --- /dev/null +++ b/raylib/text.c @@ -0,0 +1,1880 @@ +/********************************************************************************************** +* +* raylib.text - Basic functions to load Fonts and draw Text +* +* CONFIGURATION: +* +* #define SUPPORT_FILEFORMAT_FNT +* #define SUPPORT_FILEFORMAT_TTF +* Selected desired fileformats to be supported for loading. Some of those formats are +* supported by default, to remove support, just comment unrequired #define in this module +* +* #define SUPPORT_DEFAULT_FONT +* Load default raylib font on initialization to be used by DrawText() and MeasureText(). +* If no default font loaded, DrawTextEx() and MeasureTextEx() are required. +* +* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH +* TextSplit() function static buffer max size +* +* #define MAX_TEXTSPLIT_COUNT +* TextSplit() function static substrings pointers array (pointing to static buffer) +* +* +* DEPENDENCIES: +* stb_truetype - Load TTF file and rasterize characters data +* stb_rect_pack - Rectangles packing algorythms, required for font atlas generation +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" // Declares module functions + +// Check if config flags have been externally provided on compilation line +#if !defined(EXTERNAL_CONFIG_FLAGS) + #include "config.h" // Defines module configuration flags +#endif + +#include // Required for: malloc(), free() +#include // Required for: vsprintf() +#include // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] +#include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] +#include // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] + +#include "utils.h" // Required for: LoadFileText() + +#if defined(SUPPORT_FILEFORMAT_TTF) + #define STB_RECT_PACK_IMPLEMENTATION + #include "external/stb_rect_pack.h" // Required for: ttf font rectangles packaging + + #define STBTT_STATIC + #define STB_TRUETYPE_IMPLEMENTATION + #include "external/stb_truetype.h" // Required for: ttf font data reading +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef MAX_TEXT_BUFFER_LENGTH + #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: + // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() +#endif +#ifndef MAX_TEXT_UNICODE_CHARS + #define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints() +#endif +#ifndef MAX_TEXTSPLIT_COUNT + #define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Global variables +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_DEFAULT_FONT) +// Default font provided by raylib +// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core] +static Font defaultFont = { 0 }; +#endif + +//---------------------------------------------------------------------------------- +// Other Modules Functions Declaration (required by text) +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_FILEFORMAT_FNT) +static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) +#endif + +#if defined(SUPPORT_DEFAULT_FONT) +extern void LoadFontDefault(void); +extern void UnloadFontDefault(void); +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_DEFAULT_FONT) + +// Load raylib default font +extern void LoadFontDefault(void) +{ + #define BIT_CHECK(a,b) ((a) & (1u << (b))) + + // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement + // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl + + defaultFont.charsCount = 224; // Number of chars included in our default font + defaultFont.charsPadding = 0; // Characters padding + + // Default font is directly defined here (data generated from a sprite font image) + // This way, we reconstruct Font without creating large global variables + // This data is automatically allocated to Stack and automatically deallocated at the end of this function + unsigned int defaultFontData[512] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f, + 0x4a2bf2a0, 0x0852091e, 0x41224000, 0x10041450, 0x2e292020, 0x08220812, 0x41222000, 0x10041450, 0x10f92020, 0x3efa084c, 0x7d22103c, 0x107df7de, + 0xe8a12020, 0x08220832, 0x05220800, 0x10450410, 0xa4a3f000, 0x08520832, 0x05220400, 0x10450410, 0xe2f92020, 0x0002085e, 0x7d3e0281, 0x107df41f, + 0x00200000, 0x8001b000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc0000fbe, 0xfbf7e00f, 0x5fbf7e7d, 0x0050bee8, 0x440808a2, 0x0a142fe8, 0x50810285, 0x0050a048, + 0x49e428a2, 0x0a142828, 0x40810284, 0x0048a048, 0x10020fbe, 0x09f7ebaf, 0xd89f3e84, 0x0047a04f, 0x09e48822, 0x0a142aa1, 0x50810284, 0x0048a048, + 0x04082822, 0x0a142fa0, 0x50810285, 0x0050a248, 0x00008fbe, 0xfbf42021, 0x5f817e7d, 0x07d09ce8, 0x00008000, 0x00000fe0, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000c0180, + 0xdfbf4282, 0x0bfbf7ef, 0x42850505, 0x004804bf, 0x50a142c6, 0x08401428, 0x42852505, 0x00a808a0, 0x50a146aa, 0x08401428, 0x42852505, 0x00081090, + 0x5fa14a92, 0x0843f7e8, 0x7e792505, 0x00082088, 0x40a15282, 0x08420128, 0x40852489, 0x00084084, 0x40a16282, 0x0842022a, 0x40852451, 0x00088082, + 0xc0bf4282, 0xf843f42f, 0x7e85fc21, 0x3e0900bf, 0x00000000, 0x00000004, 0x00000000, 0x000c0180, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000402, 0x41482000, 0x00000000, 0x00000800, + 0x04000404, 0x4100203c, 0x00000000, 0x00000800, 0xf7df7df0, 0x514bef85, 0xbefbefbe, 0x04513bef, 0x14414500, 0x494a2885, 0xa28a28aa, 0x04510820, + 0xf44145f0, 0x474a289d, 0xa28a28aa, 0x04510be0, 0x14414510, 0x494a2884, 0xa28a28aa, 0x02910a00, 0xf7df7df0, 0xd14a2f85, 0xbefbe8aa, 0x011f7be0, + 0x00000000, 0x00400804, 0x20080000, 0x00000000, 0x00000000, 0x00600f84, 0x20080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000f01, 0x00000000, 0x06000000, 0x24000000, 0x00000f01, 0x00000000, 0x09108000, + 0x24fa28a2, 0x00000f01, 0x00000000, 0x013e0000, 0x2242252a, 0x00000f52, 0x00000000, 0x038a8000, 0x2422222a, 0x00000f29, 0x00000000, 0x010a8000, + 0x2412252a, 0x00000f01, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000f01, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000, + 0x0003e000, 0x00000f00, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03, + 0x02bea080, 0xf0000020, 0xc452208a, 0x04202b02, 0xf8029122, 0x07f0003b, 0xe44b388e, 0x02203a02, 0x081e8a1c, 0x0411e92a, 0xf4420be0, 0x01248202, + 0xe8140414, 0x05d104ba, 0xe7c3b880, 0x00893a0a, 0x283c0e1c, 0x04500902, 0xc4400080, 0x00448002, 0xe8208422, 0x04500002, 0x80400000, 0x05200002, + 0x083e8e00, 0x04100002, 0x804003e0, 0x07000042, 0xf8008400, 0x07f00003, 0x80400000, 0x04000022, 0x00000000, 0x00000000, 0x80400000, 0x04000002, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800702, 0x1848a0c2, 0x84010000, 0x02920921, 0x01042642, 0x00005121, 0x42023f7f, 0x00291002, + 0xefc01422, 0x7efdfbf7, 0xefdfa109, 0x03bbbbf7, 0x28440f12, 0x42850a14, 0x20408109, 0x01111010, 0x28440408, 0x42850a14, 0x2040817f, 0x01111010, + 0xefc78204, 0x7efdfbf7, 0xe7cf8109, 0x011111f3, 0x2850a932, 0x42850a14, 0x2040a109, 0x01111010, 0x2850b840, 0x42850a14, 0xefdfbf79, 0x03bbbbf7, + 0x001fa020, 0x00000000, 0x00001000, 0x00000000, 0x00002070, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08022800, 0x00012283, 0x02430802, 0x01010001, 0x8404147c, 0x20000144, 0x80048404, 0x00823f08, 0xdfbf4284, 0x7e03f7ef, 0x142850a1, 0x0000210a, + 0x50a14684, 0x528a1428, 0x142850a1, 0x03efa17a, 0x50a14a9e, 0x52521428, 0x142850a1, 0x02081f4a, 0x50a15284, 0x4a221428, 0xf42850a1, 0x03efa14b, + 0x50a16284, 0x4a521428, 0x042850a1, 0x0228a17a, 0xdfbf427c, 0x7e8bf7ef, 0xf7efdfbf, 0x03efbd0b, 0x00000000, 0x04000000, 0x00000000, 0x00000008, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200508, 0x00840400, 0x11458122, 0x00014210, + 0x00514294, 0x51420800, 0x20a22a94, 0x0050a508, 0x00200000, 0x00000000, 0x00050000, 0x08000000, 0xfefbefbe, 0xfbefbefb, 0xfbeb9114, 0x00fbefbe, + 0x20820820, 0x8a28a20a, 0x8a289114, 0x3e8a28a2, 0xfefbefbe, 0xfbefbe0b, 0x8a289114, 0x008a28a2, 0x228a28a2, 0x08208208, 0x8a289114, 0x088a28a2, + 0xfefbefbe, 0xfbefbefb, 0xfa2f9114, 0x00fbefbe, 0x00000000, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00210100, 0x00000004, 0x00000000, 0x00000000, 0x14508200, 0x00001402, 0x00000000, 0x00000000, + 0x00000010, 0x00000020, 0x00000000, 0x00000000, 0xa28a28be, 0x00002228, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, + 0xa28a28aa, 0x000022a8, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, 0xbefbefbe, 0x00003e2f, 0x00000000, 0x00000000, + 0x00000004, 0x00002028, 0x00000000, 0x00000000, 0x80000000, 0x00003e0f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + + int charsHeight = 10; + int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically + + int charsWidth[224] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5, + 2, 5, 5, 5, 5, 5, 4, 5, 5, 1, 2, 5, 2, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 3, 1, 3, 4, 4, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5, 5, 5, 7, 1, 5, 3, 7, 3, 5, 4, 1, 7, 4, 3, 5, 3, 3, 2, 5, 6, 1, 2, 2, 3, 5, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 3, 3, 3, 3, 7, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 4, 6, + 5, 5, 5, 5, 5, 5, 9, 5, 5, 5, 5, 5, 2, 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5 }; + + // Re-construct image from defaultFontData and generate OpenGL texture + //---------------------------------------------------------------------- + Image imFont = { + .data = calloc(128*128, 2), // 2 bytes per pixel (gray + alpha) + .width = 128, + .height = 128, + .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, + .mipmaps = 1 + }; + + // Fill image.data with defaultFontData (convert from bit to pixel!) + for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32) + { + for (int j = 31; j >= 0; j--) + { + if (BIT_CHECK(defaultFontData[counter], j)) + { + // NOTE: We are unreferencing data as short, so, + // we must consider data as little-endian order (alpha + gray) + ((unsigned short *)imFont.data)[i + j] = 0xffff; + } + else ((unsigned short *)imFont.data)[i + j] = 0x00ff; + } + + counter++; + } + + defaultFont.texture = LoadTextureFromImage(imFont); + + // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount + //------------------------------------------------------------------------------ + + // Allocate space for our characters info data + // NOTE: This memory should be freed at end! --> CloseWindow() + defaultFont.chars = (CharInfo *)RL_MALLOC(defaultFont.charsCount*sizeof(CharInfo)); + defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.charsCount*sizeof(Rectangle)); + + int currentLine = 0; + int currentPosX = charsDivisor; + int testPosX = charsDivisor; + + for (int i = 0; i < defaultFont.charsCount; i++) + { + defaultFont.chars[i].value = 32 + i; // First char is 32 + + defaultFont.recs[i].x = (float)currentPosX; + defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor)); + defaultFont.recs[i].width = (float)charsWidth[i]; + defaultFont.recs[i].height = (float)charsHeight; + + testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor); + + if (testPosX >= defaultFont.texture.width) + { + currentLine++; + currentPosX = 2*charsDivisor + charsWidth[i]; + testPosX = currentPosX; + + defaultFont.recs[i].x = (float)charsDivisor; + defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor)); + } + else currentPosX = testPosX; + + // NOTE: On default font character offsets and xAdvance are not required + defaultFont.chars[i].offsetX = 0; + defaultFont.chars[i].offsetY = 0; + defaultFont.chars[i].advanceX = 0; + + // Fill character image data from fontClear data + defaultFont.chars[i].image = ImageFromImage(imFont, defaultFont.recs[i]); + } + + UnloadImage(imFont); + + defaultFont.baseSize = (int)defaultFont.recs[0].height; + + TRACELOG(LOG_INFO, "FONT: Default font loaded successfully"); +} + +// Unload raylib default font +extern void UnloadFontDefault(void) +{ + for (int i = 0; i < defaultFont.charsCount; i++) UnloadImage(defaultFont.chars[i].image); + UnloadTexture(defaultFont.texture); + RL_FREE(defaultFont.chars); + RL_FREE(defaultFont.recs); +} +#endif // SUPPORT_DEFAULT_FONT + +// Get the default font, useful to be used with extended parameters +Font GetFontDefault() +{ +#if defined(SUPPORT_DEFAULT_FONT) + return defaultFont; +#else + Font font = { 0 }; + return font; +#endif +} + +// Load Font from file into GPU memory (VRAM) +Font LoadFont(const char *fileName) +{ + // Default values for ttf font generation +#ifndef FONT_TTF_DEFAULT_SIZE + #define FONT_TTF_DEFAULT_SIZE 32 // TTF font generation default char size (char-height) +#endif +#ifndef FONT_TTF_DEFAULT_NUMCHARS + #define FONT_TTF_DEFAULT_NUMCHARS 95 // TTF font generation default charset: 95 glyphs (ASCII 32..126) +#endif +#ifndef FONT_TTF_DEFAULT_FIRST_CHAR + #define FONT_TTF_DEFAULT_FIRST_CHAR 32 // TTF font generation default first char for image sprite font (32-Space) +#endif +#ifndef FONT_TTF_DEFAULT_CHARS_PADDING + #define FONT_TTF_DEFAULT_CHARS_PADDING 4 // TTF font generation default chars padding +#endif + + Font font = { 0 }; + +#if defined(SUPPORT_FILEFORMAT_TTF) + if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS); + else +#endif +#if defined(SUPPORT_FILEFORMAT_FNT) + if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName); + else +#endif + { + Image image = LoadImage(fileName); + if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR); + UnloadImage(image); + } + + if (font.texture.id == 0) + { + TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName); + font = GetFontDefault(); + } + else SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default we set point filter (best performance) + + return font; +} + +// Load Font from TTF font file with generation parameters +// NOTE: You can pass an array with desired characters, those characters should be available in the font +// if array is NULL, default char set is selected 32..126 +Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount) +{ + Font font = { 0 }; + + // Loading file to memory + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); + + if (fileData != NULL) + { + // Loading font from memory data + font = LoadFontFromMemory(GetFileExtension(fileName), fileData, fileSize, fontSize, fontChars, charsCount); + + RL_FREE(fileData); + } + else font = GetFontDefault(); + + return font; +} + +// Load an Image font file (XNA style) +Font LoadFontFromImage(Image image, Color key, int firstChar) +{ +#ifndef MAX_GLYPHS_FROM_IMAGE + #define MAX_GLYPHS_FROM_IMAGE 256 // Maximum number of glyphs supported on image scan +#endif + + #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) + + int charSpacing = 0; + int lineSpacing = 0; + + int x = 0; + int y = 0; + + // We allocate a temporal arrays for chars data measures, + // once we get the actual number of chars, we copy data to a sized arrays + int tempCharValues[MAX_GLYPHS_FROM_IMAGE]; + Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE]; + + Color *pixels = LoadImageColors(image); + + // Parse image data to get charSpacing and lineSpacing + for (y = 0; y < image.height; y++) + { + for (x = 0; x < image.width; x++) + { + if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break; + } + + if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break; + } + + charSpacing = x; + lineSpacing = y; + + int charHeight = 0; + int j = 0; + + while (!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++; + + charHeight = j; + + // Check array values to get characters: value, x, y, w, h + int index = 0; + int lineToRead = 0; + int xPosToRead = charSpacing; + + // Parse image data to get rectangle sizes + while ((lineSpacing + lineToRead*(charHeight + lineSpacing)) < image.height) + { + while ((xPosToRead < image.width) && + !COLOR_EQUAL((pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead]), key)) + { + tempCharValues[index] = firstChar + index; + + tempCharRecs[index].x = (float)xPosToRead; + tempCharRecs[index].y = (float)(lineSpacing + lineToRead*(charHeight + lineSpacing)); + tempCharRecs[index].height = (float)charHeight; + + int charWidth = 0; + + while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++; + + tempCharRecs[index].width = (float)charWidth; + + index++; + + xPosToRead += (charWidth + charSpacing); + } + + lineToRead++; + xPosToRead = charSpacing; + } + + // NOTE: We need to remove key color borders from image to avoid weird + // artifacts on texture scaling when using TEXTURE_FILTER_BILINEAR or TEXTURE_FILTER_TRILINEAR + for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK; + + // Create a new image with the processed color data (key color replaced by BLANK) + Image fontClear = { + .data = pixels, + .width = image.width, + .height = image.height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + // Create spritefont with all data parsed from image + Font font = { 0 }; + + font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture + font.charsCount = index; + font.charsPadding = 0; + + // We got tempCharValues and tempCharsRecs populated with chars data + // Now we move temp data to sized charValues and charRecs arrays + font.chars = (CharInfo *)RL_MALLOC(font.charsCount*sizeof(CharInfo)); + font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle)); + + for (int i = 0; i < font.charsCount; i++) + { + font.chars[i].value = tempCharValues[i]; + + // Get character rectangle in the font atlas texture + font.recs[i] = tempCharRecs[i]; + + // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) + font.chars[i].offsetX = 0; + font.chars[i].offsetY = 0; + font.chars[i].advanceX = 0; + + // Fill character image data from fontClear data + font.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]); + } + + UnloadImage(fontClear); // Unload processed image once converted to texture + + font.baseSize = (int)font.recs[0].height; + + return font; +} + +// Load font from memory buffer, fileType refers to extension: i.e. ".ttf" +Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount) +{ + Font font = { 0 }; + + char fileExtLower[16] = { 0 }; + strcpy(fileExtLower, TextToLower(fileType)); + +#if defined(SUPPORT_FILEFORMAT_TTF) + if (TextIsEqual(fileExtLower, ".ttf") || + TextIsEqual(fileExtLower, ".otf")) + { + font.baseSize = fontSize; + font.charsCount = (charsCount > 0)? charsCount : 95; + font.charsPadding = 0; + font.chars = LoadFontData(fileData, dataSize, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); + + if (font.chars != NULL) + { + font.charsPadding = FONT_TTF_DEFAULT_CHARS_PADDING; + + Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, font.charsPadding, 0); + font.texture = LoadTextureFromImage(atlas); + + // Update chars[i].image to use alpha, required to be used on ImageDrawText() + for (int i = 0; i < font.charsCount; i++) + { + UnloadImage(font.chars[i].image); + font.chars[i].image = ImageFromImage(atlas, font.recs[i]); + } + + UnloadImage(atlas); + } + else font = GetFontDefault(); + } +#else + font = GetFontDefault(); +#endif + + return font; +} + +// Load font data for further use +// NOTE: Requires TTF font memory data and can generate SDF data +CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type) +{ + // NOTE: Using some SDF generation default values, + // trades off precision with ability to handle *smaller* sizes +#ifndef FONT_SDF_CHAR_PADDING + #define FONT_SDF_CHAR_PADDING 4 // SDF font generation char padding +#endif +#ifndef FONT_SDF_ON_EDGE_VALUE + #define FONT_SDF_ON_EDGE_VALUE 128 // SDF font generation on edge value +#endif +#ifndef FONT_SDF_PIXEL_DIST_SCALE + #define FONT_SDF_PIXEL_DIST_SCALE 64.0f // SDF font generation pixel distance scale +#endif +#ifndef FONT_BITMAP_ALPHA_THRESHOLD + #define FONT_BITMAP_ALPHA_THRESHOLD 80 // Bitmap (B&W) font generation alpha threshold +#endif + + CharInfo *chars = NULL; + +#if defined(SUPPORT_FILEFORMAT_TTF) + // Load font data (including pixel data) from TTF memory file + // NOTE: Loaded information should be enough to generate font image atlas, using any packaging method + if (fileData != NULL) + { + int genFontChars = false; + stbtt_fontinfo fontInfo = { 0 }; + + if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0)) // Init font for data reading + { + // Calculate font scale factor + float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize); + + // Calculate font basic metrics + // NOTE: ascent is equivalent to font baseline + int ascent, descent, lineGap; + stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); + + // In case no chars count provided, default to 95 + charsCount = (charsCount > 0)? charsCount : 95; + + // Fill fontChars in case not provided externally + // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) + + if (fontChars == NULL) + { + fontChars = (int *)RL_MALLOC(charsCount*sizeof(int)); + for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; + genFontChars = true; + } + + chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); + + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) + { + int chw = 0, chh = 0; // Character width and height (on generation) + int ch = fontChars[i]; // Character value to get info for + chars[i].value = ch; + + // Render a unicode codepoint to a bitmap + // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap + // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be + // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide + + if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + else chars[i].image.data = NULL; + + stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); + chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor); + + // Load characters images + chars[i].image.width = chw; + chars[i].image.height = chh; + chars[i].image.mipmaps = 1; + chars[i].image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; + + chars[i].offsetY += (int)((float)ascent*scaleFactor); + + // NOTE: We create an empty image for space character, it could be further required for atlas packing + if (ch == 32) + { + Image imSpace = { + .data = calloc(chars[i].advanceX*fontSize, 2), + .width = chars[i].advanceX, + .height = fontSize, + .format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE, + .mipmaps = 1 + }; + + chars[i].image = imSpace; + } + + if (type == FONT_BITMAP) + { + // Aliased bitmap (black & white) font generation, avoiding anti-aliasing + // NOTE: For optimum results, bitmap font should be generated at base pixel size + for (int p = 0; p < chw*chh; p++) + { + if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0; + else ((unsigned char *)chars[i].image.data)[p] = 255; + } + } + + // Get bounding box for character (may be offset to account for chars that dip above or below the line) + /* + int chX1, chY1, chX2, chY2; + stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); + + TRACELOGD("FONT: Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1); + TRACELOGD("FONT: Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1); + */ + } + } + else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data"); + + if (genFontChars) RL_FREE(fontChars); + } +#endif + + return chars; +} + +// Generate image font atlas using chars info +// NOTE: Packing method: 0-Default, 1-Skyline +#if defined(SUPPORT_FILEFORMAT_TTF) +Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCount, int fontSize, int padding, int packMethod) +{ + Image atlas = { 0 }; + + if (chars == NULL) + { + TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas"); + return atlas; + } + + *charRecs = NULL; + + // In case no chars count provided we suppose default of 95 + charsCount = (charsCount > 0)? charsCount : 95; + + // NOTE: Rectangles memory is loaded here! + Rectangle *recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle)); + + // Calculate image size based on required pixel area + // NOTE 1: Image is forced to be squared and POT... very conservative! + // NOTE 2: SDF font characters already contain an internal padding, + // so image size would result bigger than default font type + float requiredArea = 0; + for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding)); + float guessSize = sqrtf(requiredArea)*1.3f; + int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT + + atlas.width = imageSize; // Atlas bitmap width + atlas.height = imageSize; // Atlas bitmap height + atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) + atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; + atlas.mipmaps = 1; + + // DEBUG: We can see padding in the generated image setting a gray background... + //for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100; + + if (packMethod == 0) // Use basic packing algorythm + { + int offsetX = padding; + int offsetY = padding; + + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) + { + // Copy pixel data from fc.data to atlas + for (int y = 0; y < chars[i].image.height; y++) + { + for (int x = 0; x < chars[i].image.width; x++) + { + ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = ((unsigned char *)chars[i].image.data)[y*chars[i].image.width + x]; + } + } + + // Fill chars rectangles in atlas info + recs[i].x = (float)offsetX; + recs[i].y = (float)offsetY; + recs[i].width = (float)chars[i].image.width; + recs[i].height = (float)chars[i].image.height; + + // Move atlas position X for next character drawing + offsetX += (chars[i].image.width + 2*padding); + + if (offsetX >= (atlas.width - chars[i].image.width - 2*padding)) + { + offsetX = padding; + + // NOTE: Be careful on offsetY for SDF fonts, by default SDF + // use an internal padding of 4 pixels, it means char rectangle + // height is bigger than fontSize, it could be up to (fontSize + 8) + offsetY += (fontSize + 2*padding); + + if (offsetY > (atlas.height - fontSize - padding)) break; + } + } + } + else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect) + { + stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context)); + stbrp_node *nodes = (stbrp_node *)RL_MALLOC(charsCount*sizeof(*nodes)); + + stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount); + stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(charsCount*sizeof(stbrp_rect)); + + // Fill rectangles for packaging + for (int i = 0; i < charsCount; i++) + { + rects[i].id = i; + rects[i].w = chars[i].image.width + 2*padding; + rects[i].h = chars[i].image.height + 2*padding; + } + + // Package rectangles into atlas + stbrp_pack_rects(context, rects, charsCount); + + for (int i = 0; i < charsCount; i++) + { + // It return char rectangles in atlas + recs[i].x = rects[i].x + (float)padding; + recs[i].y = rects[i].y + (float)padding; + recs[i].width = (float)chars[i].image.width; + recs[i].height = (float)chars[i].image.height; + + if (rects[i].was_packed) + { + // Copy pixel data from fc.data to atlas + for (int y = 0; y < chars[i].image.height; y++) + { + for (int x = 0; x < chars[i].image.width; x++) + { + ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = ((unsigned char *)chars[i].image.data)[y*chars[i].image.width + x]; + } + } + } + else TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", i); + } + + RL_FREE(rects); + RL_FREE(nodes); + RL_FREE(context); + } + + // TODO: Crop image if required for smaller size + + // Convert image data from GRAYSCALE to GRAY_ALPHA + unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels + + for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2) + { + dataGrayAlpha[k] = 255; + dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i]; + } + + RL_FREE(atlas.data); + atlas.data = dataGrayAlpha; + atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; + + *charRecs = recs; + + return atlas; +} +#endif + +// Unload font chars info data (RAM) +void UnloadFontData(CharInfo *chars, int charsCount) +{ + for (int i = 0; i < charsCount; i++) UnloadImage(chars[i].image); + + RL_FREE(chars); +} + +// Unload Font from GPU memory (VRAM) +void UnloadFont(Font font) +{ + // NOTE: Make sure font is not default font (fallback) + if (font.texture.id != GetFontDefault().texture.id) + { + UnloadFontData(font.chars, font.charsCount); + UnloadTexture(font.texture); + RL_FREE(font.recs); + + TRACELOGD("FONT: Unloaded font data from RAM and VRAM"); + } +} + +// Draw current FPS +// NOTE: Uses default font +void DrawFPS(int posX, int posY) +{ + Color color = LIME; // good fps + int fps = GetFPS(); + + if (fps < 30 && fps >= 15) color = ORANGE; // warning FPS + else if (fps < 15) color = RED; // bad FPS + + DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, color); +} + +// Draw text (using default font) +// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used +// NOTE: chars spacing is proportional to fontSize +void DrawText(const char *text, int posX, int posY, int fontSize, Color color) +{ + // Check if default font has been loaded + if (GetFontDefault().texture.id != 0) + { + Vector2 position = { (float)posX, (float)posY }; + + int defaultFontSize = 10; // Default Font chars height in pixel + if (fontSize < defaultFontSize) fontSize = defaultFontSize; + int spacing = fontSize/defaultFontSize; + + DrawTextEx(GetFontDefault(), text, position, (float)fontSize, (float)spacing, color); + } +} + +// Draw text using Font +// NOTE: chars spacing is NOT proportional to fontSize +void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint) +{ + if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font + + int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop + + int textOffsetY = 0; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor + + for (int i = 0; i < length;) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + + if (codepoint == '\n') + { + // NOTE: Fixed line spacing of 1.5 line-height + // TODO: Support custom line spacing defined by user + textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetX = 0.0f; + } + else + { + if ((codepoint != ' ') && (codepoint != '\t')) + { + DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint); + } + + if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing); + else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing); + } + + i += codepointByteCount; // Move text bytes counter to next codepoint + } +} + +// Draw text using font inside rectangle limits +void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) +{ + DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); +} + +// Draw text using font inside rectangle limits with support for text selection +void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint) +{ + int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop + + int textOffsetY = 0; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor + + // Word/character wrapping mechanism variables + enum { MEASURE_STATE = 0, DRAW_STATE = 1 }; + int state = wordWrap? MEASURE_STATE : DRAW_STATE; + + int startLine = -1; // Index where to begin drawing (where a line begins) + int endLine = -1; // Index where to stop drawing (where a line ends) + int lastk = -1; // Holds last value of the character position + + for (int i = 0, k = 0; i < length; i++, k++) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + i += (codepointByteCount - 1); + + int glyphWidth = 0; + if (codepoint != '\n') + { + glyphWidth = (font.chars[index].advanceX == 0)? + (int)(font.recs[index].width*scaleFactor + spacing): + (int)(font.chars[index].advanceX*scaleFactor + spacing); + } + + // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container + // We store this info in startLine and endLine, then we change states, draw the text between those two variables + // and change states again and again recursively until the end of the text (or until we get outside of the container). + // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately + // and begin drawing on the next line before we can get outside the container. + if (state == MEASURE_STATE) + { + // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more + // Ref: http://jkorpela.fi/chars/spaces.html + if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i; + + if ((textOffsetX + glyphWidth + 1) >= rec.width) + { + endLine = (endLine < 1)? i : endLine; + if (i == endLine) endLine -= codepointByteCount; + if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount); + + state = !state; + } + else if ((i + 1) == length) + { + endLine = i; + + state = !state; + } + else if (codepoint == '\n') state = !state; + + if (state == DRAW_STATE) + { + textOffsetX = 0; + i = startLine; + glyphWidth = 0; + + // Save character position when we switch states + int tmp = lastk; + lastk = k - 1; + k = tmp; + } + } + else + { + if (codepoint == '\n') + { + if (!wordWrap) + { + textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetX = 0; + } + } + else + { + if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width)) + { + textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetX = 0; + } + + // When text overflows rectangle height limit, just stop drawing + if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break; + + // Draw selection background + bool isGlyphSelected = false; + if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) + { + DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, (float)glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint); + isGlyphSelected = true; + } + + // Draw current character glyph + if ((codepoint != ' ') && (codepoint != '\t')) + { + DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint); + } + } + + if (wordWrap && (i == endLine)) + { + textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetX = 0; + startLine = endLine; + endLine = -1; + glyphWidth = 0; + selectStart += lastk - k; + k = lastk; + + state = !state; + } + } + + textOffsetX += glyphWidth; + } +} + +// Draw one character (codepoint) +void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint) +{ + // Character index position in sprite font + // NOTE: In case a codepoint is not available in the font, index returned points to '?' + int index = GetGlyphIndex(font, codepoint); + float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor + + // Character destination rectangle on screen + // NOTE: We consider charsPadding on drawing + Rectangle dstRec = { position.x + font.chars[index].offsetX*scaleFactor - (float)font.charsPadding*scaleFactor, + position.y + font.chars[index].offsetY*scaleFactor - (float)font.charsPadding*scaleFactor, + (font.recs[index].width + 2.0f*font.charsPadding)*scaleFactor, + (font.recs[index].height + 2.0f*font.charsPadding)*scaleFactor }; + + // Character source rectangle from font texture atlas + // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects + Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, + font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; + + // Draw the character texture on the screen + DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint); +} + +// Measure string width for default font +int MeasureText(const char *text, int fontSize) +{ + Vector2 vec = { 0.0f, 0.0f }; + + // Check if default font has been loaded + if (GetFontDefault().texture.id != 0) + { + int defaultFontSize = 10; // Default Font chars height in pixel + if (fontSize < defaultFontSize) fontSize = defaultFontSize; + int spacing = fontSize/defaultFontSize; + + vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing); + } + + return (int)vec.x; +} + +// Measure string size for Font +Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing) +{ + int len = TextLength(text); + int tempLen = 0; // Used to count longer text line num chars + int lenCounter = 0; + + float textWidth = 0.0f; + float tempTextWidth = 0.0f; // Used to count longer text line width + + float textHeight = (float)font.baseSize; + float scaleFactor = fontSize/(float)font.baseSize; + + int letter = 0; // Current character + int index = 0; // Index position in sprite font + + for (int i = 0; i < len; i++) + { + lenCounter++; + + int next = 0; + letter = GetNextCodepoint(&text[i], &next); + index = GetGlyphIndex(font, letter); + + // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 + if (letter == 0x3f) next = 1; + i += next - 1; + + if (letter != '\n') + { + if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX; + else textWidth += (font.recs[index].width + font.chars[index].offsetX); + } + else + { + if (tempTextWidth < textWidth) tempTextWidth = textWidth; + lenCounter = 0; + textWidth = 0; + textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines + } + + if (tempLen < lenCounter) tempLen = lenCounter; + } + + if (tempTextWidth < textWidth) tempTextWidth = textWidth; + + Vector2 vec = { 0 }; + vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure + vec.y = textHeight*scaleFactor; + + return vec; +} + +// Returns index position for a unicode character on spritefont +int GetGlyphIndex(Font font, int codepoint) +{ +#ifndef GLYPH_NOTFOUND_CHAR_FALLBACK + #define GLYPH_NOTFOUND_CHAR_FALLBACK 63 // Character used if requested codepoint is not found: '?' +#endif + +// Support charsets with any characters order +#define SUPPORT_UNORDERED_CHARSET +#if defined(SUPPORT_UNORDERED_CHARSET) + int index = GLYPH_NOTFOUND_CHAR_FALLBACK; + + for (int i = 0; i < font.charsCount; i++) + { + if (font.chars[i].value == codepoint) + { + index = i; + break; + } + } + + return index; +#else + return (codepoint - 32); +#endif +} + +//---------------------------------------------------------------------------------- +// Text strings management functions +//---------------------------------------------------------------------------------- +// Get text length in bytes, check for \0 character +unsigned int TextLength(const char *text) +{ + unsigned int length = 0; //strlen(text) + + if (text != NULL) + { + while (*text++) length++; + } + + return length; +} + +// Formatting of text with variables to 'embed' +// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times +const char *TextFormat(const char *text, ...) +{ +#ifndef MAX_TEXTFORMAT_BUFFERS + #define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting +#endif + + // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations + static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 }; + static int index = 0; + + char *currentBuffer = buffers[index]; + memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using + + va_list args; + va_start(args, text); + vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); + va_end(args); + + index += 1; // Move to next buffer for next function call + if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; + + return currentBuffer; +} + +// Get integer value from text +// NOTE: This function replaces atoi() [stdlib.h] +int TextToInteger(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0'); + + return value*sign; +} + +#if defined(SUPPORT_TEXT_MANIPULATION) +// Copy one string to another, returns bytes copied +int TextCopy(char *dst, const char *src) +{ + int bytes = 0; + + if (dst != NULL) + { + while (*src != '\0') + { + *dst = *src; + dst++; + src++; + + bytes++; + } + + *dst = '\0'; + } + + return bytes; +} + +// Check if two text string are equal +// REQUIRES: strcmp() +bool TextIsEqual(const char *text1, const char *text2) +{ + bool result = false; + + if (strcmp(text1, text2) == 0) result = true; + + return result; +} + +// Get a piece of a text string +const char *TextSubtext(const char *text, int position, int length) +{ + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + + int textLength = TextLength(text); + + if (position >= textLength) + { + position = textLength - 1; + length = 0; + } + + if (length >= textLength) length = textLength; + + for (int c = 0 ; c < length ; c++) + { + *(buffer + c) = *(text + position); + text++; + } + + *(buffer + length) = '\0'; + + return buffer; +} + +// Replace text string +// REQUIRES: strstr(), strncpy(), strcpy() +// WARNING: Internally allocated memory must be freed by the user (if return != NULL) +char *TextReplace(char *text, const char *replace, const char *by) +{ + // Sanity checks and initialization + if (!text || !replace || !by) return NULL; + + char *result; + + char *insertPoint; // Next insert point + char *temp; // Temp pointer + int replaceLen; // Replace string length of (the string to remove) + int byLen; // Replacement length (the string to replace replace by) + int lastReplacePos; // Distance between replace and end of last replace + int count; // Number of replacements + + replaceLen = TextLength(replace); + if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count + + byLen = TextLength(by); + + // Count the number of replacements needed + insertPoint = text; + for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen; + + // Allocate returning string and point temp to it + temp = result = RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1); + + if (!result) return NULL; // Memory could not be allocated + + // First time through the loop, all the variable are set correctly from here on, + // temp points to the end of the result string + // insertPoint points to the next occurrence of replace in text + // text points to the remainder of text after "end of replace" + while (count--) + { + insertPoint = strstr(text, replace); + lastReplacePos = (int)(insertPoint - text); + temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; + temp = strcpy(temp, by) + byLen; + text += lastReplacePos + replaceLen; // Move to next "end of replace" + } + + // Copy remaind text part after replacement to result (pointed by moving temp) + strcpy(temp, text); + + return result; +} + +// Insert text in a specific position, moves all text forward +// WARNING: Allocated memory should be manually freed +char *TextInsert(const char *text, const char *insert, int position) +{ + int textLen = TextLength(text); + int insertLen = TextLength(insert); + + char *result = (char *)RL_MALLOC(textLen + insertLen + 1); + + for (int i = 0; i < position; i++) result[i] = text[i]; + for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; + for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; + + result[textLen + insertLen] = '\0'; // Make sure text string is valid! + + return result; +} + +// Join text strings with delimiter +// REQUIRES: memset(), memcpy() +const char *TextJoin(const char **textList, int count, const char *delimiter) +{ + static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + memset(text, 0, MAX_TEXT_BUFFER_LENGTH); + char *textPtr = text; + + int totalLength = 0; + int delimiterLen = TextLength(delimiter); + + for (int i = 0; i < count; i++) + { + int textLength = TextLength(textList[i]); + + // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH + if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH) + { + memcpy(textPtr, textList[i], textLength); + totalLength += textLength; + textPtr += textLength; + + if ((delimiterLen > 0) && (i < (count - 1))) + { + memcpy(textPtr, delimiter, delimiterLen); + totalLength += delimiterLen; + textPtr += delimiterLen; + } + } + } + + return text; +} + +// Split string into multiple strings +// REQUIRES: memset() +const char **TextSplit(const char *text, char delimiter, int *count) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT + // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH + + static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL }; + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); + + result[0] = buffer; + int counter = 0; + + if (text != NULL) + { + counter = 1; + + // Count how many substrings we have on text and point to every one + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if (buffer[i] == delimiter) + { + buffer[i] = '\0'; // Set an end of string at this point + result[counter] = buffer + i + 1; + counter++; + + if (counter == MAX_TEXTSPLIT_COUNT) break; + } + } + } + + *count = counter; + return result; +} + +// Append text at specific position and move cursor! +// REQUIRES: strcpy() +void TextAppend(char *text, const char *append, int *position) +{ + strcpy(text + *position, append); + *position += TextLength(append); +} + +// Find first text occurrence within a string +// REQUIRES: strstr() +int TextFindIndex(const char *text, const char *find) +{ + int position = -1; + + char *ptr = strstr(text, find); + + if (ptr != NULL) position = (int)(ptr - text); + + return position; +} + +// Get upper case version of provided string +// REQUIRES: toupper() +const char *TextToUpper(const char *text) +{ + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + { + if (text[i] != '\0') + { + buffer[i] = (char)toupper(text[i]); + //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32; + + // TODO: Support Utf8 diacritics! + //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32; + } + else { buffer[i] = '\0'; break; } + } + + return buffer; +} + +// Get lower case version of provided string +// REQUIRES: tolower() +const char *TextToLower(const char *text) +{ + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + { + if (text[i] != '\0') + { + buffer[i] = (char)tolower(text[i]); + //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32; + } + else { buffer[i] = '\0'; break; } + } + + return buffer; +} + +// Get Pascal case notation version of provided string +// REQUIRES: toupper() +const char *TextToPascal(const char *text) +{ + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + + buffer[0] = (char)toupper(text[0]); + + for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++) + { + if (text[j] != '\0') + { + if (text[j] != '_') buffer[i] = text[j]; + else + { + j++; + buffer[i] = (char)toupper(text[j]); + } + } + else { buffer[i] = '\0'; break; } + } + + return buffer; +} + +// Encode text codepoint into utf8 text +// REQUIRES: memcpy() +// WARNING: Allocated memory should be manually freed +char *TextToUtf8(int *codepoints, int length) +{ + // We allocate enough memory fo fit all possible codepoints + // NOTE: 5 bytes for every codepoint should be enough + char *text = (char *)RL_CALLOC(length*5, 1); + const char *utf8 = NULL; + int size = 0; + + for (int i = 0, bytes = 0; i < length; i++) + { + utf8 = CodepointToUtf8(codepoints[i], &bytes); + memcpy(text + size, utf8, bytes); + size += bytes; + } + + // Resize memory to text length + string NULL terminator + void *ptr = RL_REALLOC(text, size + 1); + + if (ptr != NULL) text = (char *)ptr; + + return text; +} + +// Encode codepoint into utf8 text (char array length returned as parameter) +RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength) +{ + static char utf8[6] = { 0 }; + int length = 0; + + if (codepoint <= 0x7f) + { + utf8[0] = (char)codepoint; + length = 1; + } + else if (codepoint <= 0x7ff) + { + utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); + utf8[1] = (char)((codepoint & 0x3f) | 0x80); + length = 2; + } + else if (codepoint <= 0xffff) + { + utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); + utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[2] = (char)((codepoint & 0x3f) | 0x80); + length = 3; + } + else if (codepoint <= 0x10ffff) + { + utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); + utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); + utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[3] = (char)((codepoint & 0x3f) | 0x80); + length = 4; + } + + *byteLength = length; + + return utf8; +} + +// Get all codepoints in a string, codepoints count returned by parameters +// REQUIRES: memset() +int *GetCodepoints(const char *text, int *count) +{ + static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 }; + memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int)); + + int bytesProcessed = 0; + int textLength = TextLength(text); + int codepointsCount = 0; + + for (int i = 0; i < textLength; codepointsCount++) + { + codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed); + i += bytesProcessed; + } + + *count = codepointsCount; + + return codepoints; +} + +// Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found +// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead +int GetCodepointsCount(const char *text) +{ + unsigned int len = 0; + char *ptr = (char *)&text[0]; + + while (*ptr != '\0') + { + int next = 0; + int letter = GetNextCodepoint(ptr, &next); + + if (letter == 0x3f) ptr += 1; + else ptr += next; + + len++; + } + + return len; +} +#endif // SUPPORT_TEXT_MANIPULATION + +// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found +// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned +// Total number of bytes processed are returned as a parameter +// NOTE: the standard says U+FFFD should be returned in case of errors +// but that character is not supported by the default font in raylib +// TODO: Optimize this code for speed!! +int GetNextCodepoint(const char *text, int *bytesProcessed) +{ +/* + UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt + + Char. number range | UTF-8 octet sequence + (hexadecimal) | (binary) + --------------------+--------------------------------------------- + 0000 0000-0000 007F | 0xxxxxxx + 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +*/ + // NOTE: on decode errors we return as soon as possible + + int code = 0x3f; // Codepoint (defaults to '?') + int octet = (unsigned char)(text[0]); // The first UTF8 octet + *bytesProcessed = 1; + + if (octet <= 0x7f) + { + // Only one octet (ASCII range x00-7F) + code = text[0]; + } + else if ((octet & 0xe0) == 0xc0) + { + // Two octets + // [0]xC2-DF [1]UTF8-tail(x80-BF) + unsigned char octet1 = text[1]; + + if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence + + if ((octet >= 0xc2) && (octet <= 0xdf)) + { + code = ((octet & 0x1f) << 6) | (octet1 & 0x3f); + *bytesProcessed = 2; + } + } + else if ((octet & 0xf0) == 0xe0) + { + // Three octets + unsigned char octet1 = text[1]; + unsigned char octet2 = '\0'; + + if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence + + octet2 = text[2]; + + if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence + + /* + [0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF) + [0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF) + [0]xED [1]x80-9F [2]UTF8-tail(x80-BF) + [0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF) + */ + + if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) || + ((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; } + + if ((octet >= 0xe0) && (0 <= 0xef)) + { + code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f); + *bytesProcessed = 3; + } + } + else if ((octet & 0xf8) == 0xf0) + { + // Four octets + if (octet > 0xf4) return code; + + unsigned char octet1 = text[1]; + unsigned char octet2 = '\0'; + unsigned char octet3 = '\0'; + + if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence + + octet2 = text[2]; + + if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence + + octet3 = text[3]; + + if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; } // Unexpected sequence + + /* + [0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail + [0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail + [0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail + */ + + if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) || + ((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence + + if (octet >= 0xf0) + { + code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f); + *bytesProcessed = 4; + } + } + + if (code > 0x10ffff) code = 0x3f; // Codepoints after U+10ffff are invalid + + return code; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_FILEFORMAT_FNT) + +// Read a line from memory +// REQUIRES: memcpy() +// NOTE: Returns the number of bytes read +static int GetLine(const char *origin, char *buffer, int maxLength) +{ + int count = 0; + for (; count < maxLength; count++) if (origin[count] == '\n') break; + memcpy(buffer, origin, count); + return count; +} + +// Load a BMFont file (AngelCode font file) +// REQUIRES: strstr(), sscanf(), strrchr(), memcpy() +static Font LoadBMFont(const char *fileName) +{ + #define MAX_BUFFER_SIZE 256 + + Font font = { 0 }; + + char buffer[MAX_BUFFER_SIZE] = { 0 }; + char *searchPoint = NULL; + + int fontSize = 0; + int charsCount = 0; + + int imWidth = 0; + int imHeight = 0; + char imFileName[129]; + + int base = 0; // Useless data + + char *fileText = LoadFileText(fileName); + + if (fileText == NULL) return font; + + char *fileTextPtr = fileText; + + // NOTE: We skip first line, it contains no useful information + int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); + fileTextPtr += (lineBytes + 1); + + // Read line data + lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); + searchPoint = strstr(buffer, "lineHeight"); + sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight); + fileTextPtr += (lineBytes + 1); + + TRACELOGD("FONT: [%s] Loaded font info:", fileName); + TRACELOGD(" > Base size: %i", fontSize); + TRACELOGD(" > Texture scale: %ix%i", imWidth, imHeight); + + lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); + searchPoint = strstr(buffer, "file"); + sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName); + fileTextPtr += (lineBytes + 1); + + TRACELOGD(" > Texture filename: %s", imFileName); + + lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); + searchPoint = strstr(buffer, "count"); + sscanf(searchPoint, "count=%i", &charsCount); + fileTextPtr += (lineBytes + 1); + + TRACELOGD(" > Chars count: %i", charsCount); + + // Compose correct path using route of .fnt file (fileName) and imFileName + char *imPath = NULL; + char *lastSlash = NULL; + + lastSlash = strrchr(fileName, '/'); + if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\'); + + if (lastSlash != NULL) + { + // NOTE: We need some extra space to avoid memory corruption on next allocations! + imPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1); + memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1); + memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName)); + } + else imPath = imFileName; + + TRACELOGD(" > Image loading path: %s", imPath); + + Image imFont = LoadImage(imPath); + + if (imFont.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) + { + // Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel + Image imFontAlpha = { + .data = calloc(imFont.width*imFont.height, 2), + .width = imFont.width, + .height = imFont.height, + .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, + .mipmaps = 1 + }; + + for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++) + { + ((unsigned char *)(imFontAlpha.data))[p] = 0xff; + ((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i]; + } + + UnloadImage(imFont); + imFont = imFontAlpha; + } + + font.texture = LoadTextureFromImage(imFont); + + if (lastSlash != NULL) RL_FREE(imPath); + + // Fill font characters info data + font.baseSize = fontSize; + font.charsCount = charsCount; + font.charsPadding = 0; + font.chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); + font.recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle)); + + int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; + + for (int i = 0; i < charsCount; i++) + { + lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); + sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", + &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); + fileTextPtr += (lineBytes + 1); + + // Get character rectangle in the font atlas texture + font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight }; + + // Save data properly in sprite font + font.chars[i].value = charId; + font.chars[i].offsetX = charOffsetX; + font.chars[i].offsetY = charOffsetY; + font.chars[i].advanceX = charAdvanceX; + + // Fill character image data from imFont data + font.chars[i].image = ImageFromImage(imFont, font.recs[i]); + } + + UnloadImage(imFont); + UnloadFileText(fileText); + + if (font.texture.id == 0) + { + UnloadFont(font); + font = GetFontDefault(); + TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName); + } + else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully", fileName); + + return font; +} +#endif diff --git a/raylib/text.go b/raylib/text.go new file mode 100644 index 0000000..0189aa6 --- /dev/null +++ b/raylib/text.go @@ -0,0 +1,180 @@ +package rl + +/* +#include "raylib.h" +#include +*/ +import "C" +import "unsafe" + +// cptr returns C pointer +func (c *CharInfo) cptr() *C.CharInfo { + return (*C.CharInfo)(unsafe.Pointer(c)) +} + +// cptr returns C pointer +func (s *Font) cptr() *C.Font { + return (*C.Font)(unsafe.Pointer(s)) +} + +// GetFontDefault - Get the default Font +func GetFontDefault() Font { + ret := C.GetFontDefault() + v := newFontFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadFont - Load a Font image into GPU memory (VRAM) +func LoadFont(fileName string) Font { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadFont(cfileName) + v := newFontFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadFontEx - Load Font from file with extended parameters +func LoadFontEx(fileName string, fontSize int32, fontChars *int32, charsCount int32) Font { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + cfontSize := (C.int)(fontSize) + cfontChars := (*C.int)(unsafe.Pointer(fontChars)) + ccharsCount := (C.int)(charsCount) + ret := C.LoadFontEx(cfileName, cfontSize, cfontChars, ccharsCount) + v := newFontFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadFontFromImage - Loads an Image font file (XNA style) +func LoadFontFromImage(image Image, key Color, firstChar int32) Font { + cimage := image.cptr() + ckey := key.cptr() + cfirstChar := (C.int)(firstChar) + ret := C.LoadFontFromImage(*cimage, *ckey, cfirstChar) + v := newFontFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadFontFromMemory - Load font from memory buffer, fileType refers to extension: i.e. ".ttf" +func LoadFontFromMemory(fileType string, fileData []byte, dataSize int32, fontSize int32, fontChars *int32, charsCount int32) Font { + cfileType := C.CString(fileType) + defer C.free(unsafe.Pointer(cfileType)) + cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) + cdataSize := (C.int)(dataSize) + cfontSize := (C.int)(fontSize) + cfontChars := (*C.int)(unsafe.Pointer(fontChars)) + ccharsCount := (C.int)(charsCount) + ret := C.LoadFontFromMemory(cfileType, cfileData, cdataSize, cfontSize, cfontChars, ccharsCount) + v := newFontFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadFontData - Load font data for further use +func LoadFontData(fileData []byte, dataSize int32, fontSize int32, fontChars *int32, charsCount, typ int32) *CharInfo { + cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) + cdataSize := (C.int)(dataSize) + cfontSize := (C.int)(fontSize) + cfontChars := (*C.int)(unsafe.Pointer(fontChars)) + ccharsCount := (C.int)(charsCount) + ctype := (C.int)(typ) + ret := C.LoadFontData(cfileData, cdataSize, cfontSize, cfontChars, ccharsCount, ctype) + v := newCharInfoFromPointer(unsafe.Pointer(&ret)) + return &v +} + +// UnloadFont - Unload Font from GPU memory (VRAM) +func UnloadFont(font Font) { + cfont := font.cptr() + C.UnloadFont(*cfont) +} + +// DrawText - Draw text (using default font) +func DrawText(text string, posX int32, posY int32, fontSize int32, color Color) { + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cposX := (C.int)(posX) + cposY := (C.int)(posY) + cfontSize := (C.int)(fontSize) + ccolor := color.cptr() + C.DrawText(ctext, cposX, cposY, cfontSize, *ccolor) +} + +// DrawTextEx - Draw text using Font and additional parameters +func DrawTextEx(font Font, text string, position Vector2, fontSize float32, spacing float32, tint Color) { + cfont := font.cptr() + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cposition := position.cptr() + cfontSize := (C.float)(fontSize) + cspacing := (C.float)(spacing) + ctint := tint.cptr() + C.DrawTextEx(*cfont, ctext, *cposition, cfontSize, cspacing, *ctint) +} + +// DrawTextRec - Draw text using font inside rectangle limits +func DrawTextRec(font Font, text string, rec Rectangle, fontSize, spacing float32, wordWrap bool, tint Color) { + cfont := font.cptr() + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + crec := rec.cptr() + cfontSize := (C.float)(fontSize) + cspacing := (C.float)(spacing) + cwordWrap := (C.bool)(wordWrap) + ctint := tint.cptr() + C.DrawTextRec(*cfont, ctext, *crec, cfontSize, cspacing, cwordWrap, *ctint) +} + +// DrawTextRecEx - Draw text using font inside rectangle limits with support for text selection +func DrawTextRecEx(font Font, text string, rec Rectangle, fontSize, spacing float32, wordWrap bool, tint Color, selectStart, selectLength int32, selectText, selectBack Color) { + cfont := font.cptr() + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + crec := rec.cptr() + cfontSize := (C.float)(fontSize) + cspacing := (C.float)(spacing) + cwordWrap := (C.bool)(wordWrap) + ctint := tint.cptr() + cselectStart := (C.int)(selectStart) + cselectLength := (C.int)(selectLength) + cselectText := selectText.cptr() + cselectBack := selectBack.cptr() + C.DrawTextRecEx(*cfont, ctext, *crec, cfontSize, cspacing, cwordWrap, *ctint, cselectStart, cselectLength, *cselectText, *cselectBack) +} + +// MeasureText - Measure string width for default font +func MeasureText(text string, fontSize int32) int32 { + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cfontSize := (C.int)(fontSize) + ret := C.MeasureText(ctext, cfontSize) + v := (int32)(ret) + return v +} + +// MeasureTextEx - Measure string size for Font +func MeasureTextEx(font Font, text string, fontSize float32, spacing float32) Vector2 { + cfont := font.cptr() + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cfontSize := (C.float)(fontSize) + cspacing := (C.float)(spacing) + ret := C.MeasureTextEx(*cfont, ctext, cfontSize, cspacing) + v := newVector2FromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetGlyphIndex - Returns index position for a unicode character on spritefont +func GetGlyphIndex(font Font, character int32) int32 { + cfont := font.cptr() + ccharacter := (C.int)(character) + ret := C.GetGlyphIndex(*cfont, ccharacter) + v := (int32)(ret) + return v +} + +// DrawFPS - Shows current FPS +func DrawFPS(posX int32, posY int32) { + cposX := (C.int)(posX) + cposY := (C.int)(posY) + C.DrawFPS(cposX, cposY) +} diff --git a/raylib/rtextures.c b/raylib/textures.c similarity index 59% rename from raylib/rtextures.c rename to raylib/textures.c index ac06d6d..db562bd 100644 --- a/raylib/rtextures.c +++ b/raylib/textures.c @@ -1,48 +1,44 @@ /********************************************************************************************** * -* rtextures - Basic functions to load and draw textures +* raylib.textures - Basic functions to load and draw Textures (2d) * * CONFIGURATION: -* #define SUPPORT_MODULE_RTEXTURES -* rtextures module is included in the build * -* #define SUPPORT_FILEFORMAT_BMP -* #define SUPPORT_FILEFORMAT_PNG -* #define SUPPORT_FILEFORMAT_TGA -* #define SUPPORT_FILEFORMAT_JPG -* #define SUPPORT_FILEFORMAT_GIF -* #define SUPPORT_FILEFORMAT_QOI -* #define SUPPORT_FILEFORMAT_PSD -* #define SUPPORT_FILEFORMAT_HDR -* #define SUPPORT_FILEFORMAT_PIC -* #define SUPPORT_FILEFORMAT_PNM -* #define SUPPORT_FILEFORMAT_DDS -* #define SUPPORT_FILEFORMAT_PKM -* #define SUPPORT_FILEFORMAT_KTX -* #define SUPPORT_FILEFORMAT_PVR -* #define SUPPORT_FILEFORMAT_ASTC -* Select desired fileformats to be supported for image data loading. Some of those formats are -* supported by default, to remove support, just comment unrequired #define in this module +* #define SUPPORT_FILEFORMAT_BMP +* #define SUPPORT_FILEFORMAT_PNG +* #define SUPPORT_FILEFORMAT_TGA +* #define SUPPORT_FILEFORMAT_JPG +* #define SUPPORT_FILEFORMAT_GIF +* #define SUPPORT_FILEFORMAT_PSD +* #define SUPPORT_FILEFORMAT_PIC +* #define SUPPORT_FILEFORMAT_HDR +* #define SUPPORT_FILEFORMAT_DDS +* #define SUPPORT_FILEFORMAT_PKM +* #define SUPPORT_FILEFORMAT_KTX +* #define SUPPORT_FILEFORMAT_PVR +* #define SUPPORT_FILEFORMAT_ASTC +* Select desired fileformats to be supported for image data loading. Some of those formats are +* supported by default, to remove support, just comment unrequired #define in this module * -* #define SUPPORT_IMAGE_EXPORT -* Support image export in multiple file formats +* #define SUPPORT_IMAGE_EXPORT +* Support image export in multiple file formats * -* #define SUPPORT_IMAGE_MANIPULATION -* Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... -* If not defined only some image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageResize*() +* #define SUPPORT_IMAGE_MANIPULATION +* Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... +* If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT() * -* #define SUPPORT_IMAGE_GENERATION -* Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) +* #define SUPPORT_IMAGE_GENERATION +* Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) * * DEPENDENCIES: * stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) * NOTE: stb_image has been slightly modified to support Android platform. -* stb_image_resize - Multiple image resize algorithms +* stb_image_resize - Multiple image resize algorythms * * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -68,15 +64,15 @@ #include "config.h" // Defines module configuration flags #endif -#if defined(SUPPORT_MODULE_RTEXTURES) +#include // Required for: malloc(), free() +#include // Required for: strlen() [Used in ImageTextEx()] +#include // Required for: fabsf() -#include "utils.h" // Required for: TRACELOG() -#include "rlgl.h" // OpenGL abstraction layer to multiple versions +#include "utils.h" // Required for: fopen() Android mapping -#include // Required for: malloc(), calloc(), free() -#include // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()] -#include // Required for: fabsf() [Used in DrawTextureRec()] -#include // Required for: sprintf() [Used in ExportImageAsCode()] +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 + // Required for: rlLoadTexture() rlUnloadTexture(), + // rlGenerateMipmaps(), some funcs for DrawTexturePro() // Support only desired texture formats on stb_image #if !defined(SUPPORT_FILEFORMAT_BMP) @@ -103,100 +99,30 @@ #if !defined(SUPPORT_FILEFORMAT_HDR) #define STBI_NO_HDR #endif -#if !defined(SUPPORT_FILEFORMAT_PNM) - #define STBI_NO_PNM -#endif - -#if defined(SUPPORT_FILEFORMAT_DDS) - #define RL_GPUTEX_SUPPORT_DDS -#endif -#if defined(SUPPORT_FILEFORMAT_PKM) - #define RL_GPUTEX_SUPPORT_PKM -#endif -#if defined(SUPPORT_FILEFORMAT_KTX) - #define RL_GPUTEX_SUPPORT_KTX -#endif -#if defined(SUPPORT_FILEFORMAT_PVR) - #define RL_GPUTEX_SUPPORT_PVR -#endif -#if defined(SUPPORT_FILEFORMAT_ASTC) - #define RL_GPUTEX_SUPPORT_ASTC -#endif // Image fileformats not supported by default +#define STBI_NO_PIC +#define STBI_NO_PNM // Image format .ppm and .pgm + #if (defined(SUPPORT_FILEFORMAT_BMP) || \ defined(SUPPORT_FILEFORMAT_PNG) || \ defined(SUPPORT_FILEFORMAT_TGA) || \ defined(SUPPORT_FILEFORMAT_JPG) || \ defined(SUPPORT_FILEFORMAT_PSD) || \ defined(SUPPORT_FILEFORMAT_GIF) || \ - defined(SUPPORT_FILEFORMAT_HDR) || \ defined(SUPPORT_FILEFORMAT_PIC) || \ - defined(SUPPORT_FILEFORMAT_PNM)) - - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" - #endif + defined(SUPPORT_FILEFORMAT_HDR)) #define STBI_MALLOC RL_MALLOC #define STBI_FREE RL_FREE #define STBI_REALLOC RL_REALLOC - #define STBI_NO_THREAD_LOCALS - - #if defined(__TINYC__) - #define STBI_NO_SIMD - #endif - #define STB_IMAGE_IMPLEMENTATION #include "external/stb_image.h" // Required for: stbi_load_from_file() // NOTE: Used to read image data (multiple formats support) - - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic pop - #endif #endif -#if (defined(SUPPORT_FILEFORMAT_DDS) || \ - defined(SUPPORT_FILEFORMAT_PKM) || \ - defined(SUPPORT_FILEFORMAT_KTX) || \ - defined(SUPPORT_FILEFORMAT_PVR) || \ - defined(SUPPORT_FILEFORMAT_ASTC)) - - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" - #endif - - #define RL_GPUTEX_IMPLEMENTATION - #include "external/rl_gputex.h" // Required for: rl_load_xxx_from_memory() - // NOTE: Used to read compressed textures data (multiple formats support) - - #if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic pop - #endif -#endif - -#if defined(SUPPORT_FILEFORMAT_QOI) - #define QOI_MALLOC RL_MALLOC - #define QOI_FREE RL_FREE - - #if defined(_MSC_VER) // Disable some MSVC warning - #pragma warning(push) - #pragma warning(disable : 4267) - #endif - - #define QOI_IMPLEMENTATION - #include "external/qoi.h" - - #if defined(_MSC_VER) - #pragma warning(pop) // Disable MSVC warning suppression - #endif - -#endif - -#if defined(SUPPORT_IMAGE_EXPORT) +#if (defined(SUPPORT_IMAGE_EXPORT) || defined(SUPPORT_COMPRESSION_API)) #define STBIW_MALLOC RL_MALLOC #define STBIW_FREE RL_FREE #define STBIW_REALLOC RL_REALLOC @@ -205,29 +131,19 @@ #include "external/stb_image_write.h" // Required for: stbi_write_*() #endif +#if defined(SUPPORT_IMAGE_MANIPULATION) + #define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size)) + #define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr)) + + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()] +#endif + #if defined(SUPPORT_IMAGE_GENERATION) #define STB_PERLIN_IMPLEMENTATION #include "external/stb_perlin.h" // Required for: stb_perlin_fbm_noise3 #endif -#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size)) -#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr)) - -#if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" -#endif - -#if defined(__TINYC__) - #define STBIR_NO_SIMD -#endif -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "external/stb_image_resize2.h" // Required for: stbir_resize_uint8_linear() [ImageResize()] - -#if defined(__GNUC__) // GCC and Clang - #pragma GCC diagnostic pop -#endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -235,10 +151,6 @@ #define PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD 50 // Threshold over 255 to set alpha as 0 #endif -#ifndef GAUSSIAN_BLUR_ITERATIONS - #define GAUSSIAN_BLUR_ITERATIONS 4 // Number of box blur iterations to approximate gaussian blur -#endif - //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -252,14 +164,28 @@ //---------------------------------------------------------------------------------- // Other Modules Functions Declaration (required by text) //---------------------------------------------------------------------------------- -extern void LoadFontDefault(void); // [Module: text] Loads default font, required by ImageDrawText() +// ... //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static float HalfToFloat(unsigned short x); -static unsigned short FloatToHalf(float x); -static Vector4 *LoadImageDataNormalized(Image image); // Load pixel data from image as Vector4 array (float normalized) +#if defined(SUPPORT_FILEFORMAT_DDS) +static Image LoadDDS(const unsigned char *fileData, unsigned int fileSize); // Load DDS file data +#endif +#if defined(SUPPORT_FILEFORMAT_PKM) +static Image LoadPKM(const unsigned char *fileData, unsigned int fileSize); // Load PKM file data +#endif +#if defined(SUPPORT_FILEFORMAT_KTX) +static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize); // Load KTX file data +static int SaveKTX(Image image, const char *fileName); // Save image data as KTX file +#endif +#if defined(SUPPORT_FILEFORMAT_PVR) +static Image LoadPVR(const unsigned char *fileData, unsigned int fileSize); // Load PVR file data +#endif +#if defined(SUPPORT_FILEFORMAT_ASTC) +static Image LoadASTC(const unsigned char *fileData, unsigned int fileSize); // Load ASTC file data +#endif +static Vector4 *LoadImageDataNormalized(Image image); // Load pixel data from image as Vector4 array (float normalized) //---------------------------------------------------------------------------------- // Module Functions Definition @@ -277,22 +203,23 @@ Image LoadImage(const char *fileName) defined(SUPPORT_FILEFORMAT_GIF) || \ defined(SUPPORT_FILEFORMAT_PIC) || \ defined(SUPPORT_FILEFORMAT_HDR) || \ - defined(SUPPORT_FILEFORMAT_PNM) || \ defined(SUPPORT_FILEFORMAT_PSD) - - #define STBI_REQUIRED +#define STBI_REQUIRED #endif // Loading file to memory - int dataSize = 0; - unsigned char *fileData = LoadFileData(fileName, &dataSize); + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); - // Loading image from memory data if (fileData != NULL) { - image = LoadImageFromMemory(GetFileExtension(fileName), fileData, dataSize); + // Loading image from memory data + image = LoadImageFromMemory(GetFileExtension(fileName), fileData, fileSize); - UnloadFileData(fileData); + if (image.data != NULL) TRACELOG(LOG_INFO, "IMAGE: [%s] Data loaded successfully (%ix%i)", fileName, image.width, image.height); + else TRACELOG(LOG_WARNING, "IMAGE: [%s] Failed to load data", fileName); + + RL_FREE(fileData); } return image; @@ -303,28 +230,24 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int { Image image = { 0 }; - int dataSize = 0; + unsigned int dataSize = 0; unsigned char *fileData = LoadFileData(fileName, &dataSize); if (fileData != NULL) { unsigned char *dataPtr = fileData; - int size = GetPixelDataSize(width, height, format); + unsigned int size = GetPixelDataSize(width, height, format); - if (size <= dataSize) // Security check - { - // Offset file data to expected raw image by header size - if ((headerSize > 0) && ((headerSize + size) <= dataSize)) dataPtr += headerSize; + if (headerSize > 0) dataPtr += headerSize; - image.data = RL_MALLOC(size); // Allocate required memory in bytes - memcpy(image.data, dataPtr, size); // Copy required data to image - image.width = width; - image.height = height; - image.mipmaps = 1; - image.format = format; - } + image.data = RL_MALLOC(size); // Allocate required memory in bytes + memcpy(image.data, dataPtr, size); // Copy required data to image + image.width = width; + image.height = height; + image.mipmaps = 1; + image.format = format; - UnloadFileData(fileData); + RL_FREE(fileData); } return image; @@ -338,127 +261,71 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int Image LoadImageAnim(const char *fileName, int *frames) { Image image = { 0 }; - int frameCount = 0; + int framesCount = 1; #if defined(SUPPORT_FILEFORMAT_GIF) if (IsFileExtension(fileName, ".gif")) { - int dataSize = 0; + unsigned int dataSize = 0; unsigned char *fileData = LoadFileData(fileName, &dataSize); if (fileData != NULL) { int comp = 0; - int *delays = NULL; - image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4); + int **delays = NULL; + image.data = stbi_load_gif_from_memory(fileData, dataSize, delays, &image.width, &image.height, &framesCount, &comp, 4); image.mipmaps = 1; image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - UnloadFileData(fileData); + RL_FREE(fileData); RL_FREE(delays); // NOTE: Frames delays are discarded } } #else if (false) { } #endif - else - { - image = LoadImage(fileName); - frameCount = 1; - } + else image = LoadImage(fileName); - *frames = frameCount; - return image; -} + // TODO: Support APNG animated images? -// Load animated image data -// - Image.data buffer includes all frames: [image#0][image#1][image#2][...] -// - Number of frames is returned through 'frames' parameter -// - All frames are returned in RGBA format -// - Frames delay data is discarded -Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames) -{ - Image image = { 0 }; - int frameCount = 0; - - // Security check for input data - if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image; - -#if defined(SUPPORT_FILEFORMAT_GIF) - if ((strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0)) - { - if (fileData != NULL) - { - int comp = 0; - int *delays = NULL; - image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4); - - image.mipmaps = 1; - image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - RL_FREE(delays); // NOTE: Frames delays are discarded - } - } -#else - if (false) { } -#endif - else - { - image = LoadImageFromMemory(fileType, fileData, dataSize); - frameCount = 1; - } - - *frames = frameCount; + *frames = framesCount; return image; } // Load image from memory buffer, fileType refers to extension: i.e. ".png" -// WARNING: File extension must be provided in lower-case Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize) { Image image = { 0 }; - // Security check for input data - if ((fileData == NULL) || (dataSize == 0)) - { - TRACELOG(LOG_WARNING, "IMAGE: Invalid file data"); - return image; - } - if (fileType == NULL) - { - TRACELOG(LOG_WARNING, "IMAGE: Missing file extension"); - return image; - } + char fileExtLower[16] = { 0 }; + strcpy(fileExtLower, TextToLower(fileType)); - if ((false) #if defined(SUPPORT_FILEFORMAT_PNG) - || (strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0) + if ((TextIsEqual(fileExtLower, ".png")) +#else + if ((false) #endif #if defined(SUPPORT_FILEFORMAT_BMP) - || (strcmp(fileType, ".bmp") == 0) || (strcmp(fileType, ".BMP") == 0) + || (TextIsEqual(fileExtLower, ".bmp")) #endif #if defined(SUPPORT_FILEFORMAT_TGA) - || (strcmp(fileType, ".tga") == 0) || (strcmp(fileType, ".TGA") == 0) + || (TextIsEqual(fileExtLower, ".tga")) #endif #if defined(SUPPORT_FILEFORMAT_JPG) - || (strcmp(fileType, ".jpg") == 0) || (strcmp(fileType, ".jpeg") == 0) - || (strcmp(fileType, ".JPG") == 0) || (strcmp(fileType, ".JPEG") == 0) + || (TextIsEqual(fileExtLower, ".jpg") || + TextIsEqual(fileExtLower, ".jpeg")) #endif #if defined(SUPPORT_FILEFORMAT_GIF) - || (strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0) + || (TextIsEqual(fileExtLower, ".gif")) #endif #if defined(SUPPORT_FILEFORMAT_PIC) - || (strcmp(fileType, ".pic") == 0) || (strcmp(fileType, ".PIC") == 0) -#endif -#if defined(SUPPORT_FILEFORMAT_PNM) - || (strcmp(fileType, ".ppm") == 0) || (strcmp(fileType, ".pgm") == 0) - || (strcmp(fileType, ".PPM") == 0) || (strcmp(fileType, ".PGM") == 0) + || (TextIsEqual(fileExtLower, ".pic")) #endif #if defined(SUPPORT_FILEFORMAT_PSD) - || (strcmp(fileType, ".psd") == 0) || (strcmp(fileType, ".PSD") == 0) + || (TextIsEqual(fileExtLower, ".psd")) #endif - ) + ) { #if defined(STBI_REQUIRED) // NOTE: Using stb_image to load images (Supports multiple image formats) @@ -468,20 +335,17 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i int comp = 0; image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0); - if (image.data != NULL) - { - image.mipmaps = 1; + image.mipmaps = 1; - if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - else if (comp == 2) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; - else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8; - else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - } + if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; + else if (comp == 2) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; + else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8; + else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; } #endif } #if defined(SUPPORT_FILEFORMAT_HDR) - else if ((strcmp(fileType, ".hdr") == 0) || (strcmp(fileType, ".HDR") == 0)) + else if (TextIsEqual(fileExtLower, ".hdr")) { #if defined(STBI_REQUIRED) if (fileData != NULL) @@ -503,119 +367,26 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i #endif } #endif -#if defined(SUPPORT_FILEFORMAT_QOI) - else if ((strcmp(fileType, ".qoi") == 0) || (strcmp(fileType, ".QOI") == 0)) - { - if (fileData != NULL) - { - qoi_desc desc = { 0 }; - image.data = qoi_decode(fileData, dataSize, &desc, (int) fileData[12]); - image.width = desc.width; - image.height = desc.height; - image.format = desc.channels == 4 ? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8; - image.mipmaps = 1; - } - } -#endif #if defined(SUPPORT_FILEFORMAT_DDS) - else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0)) - { - image.data = rl_load_dds_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps); - } + else if (TextIsEqual(fileExtLower, ".dds")) image = LoadDDS(fileData, dataSize); #endif #if defined(SUPPORT_FILEFORMAT_PKM) - else if ((strcmp(fileType, ".pkm") == 0) || (strcmp(fileType, ".PKM") == 0)) - { - image.data = rl_load_pkm_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps); - } + else if (TextIsEqual(fileExtLower, ".pkm")) image = LoadPKM(fileData, dataSize); #endif #if defined(SUPPORT_FILEFORMAT_KTX) - else if ((strcmp(fileType, ".ktx") == 0) || (strcmp(fileType, ".KTX") == 0)) - { - image.data = rl_load_ktx_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps); - } + else if (TextIsEqual(fileExtLower, ".ktx")) image = LoadKTX(fileData, dataSize); #endif #if defined(SUPPORT_FILEFORMAT_PVR) - else if ((strcmp(fileType, ".pvr") == 0) || (strcmp(fileType, ".PVR") == 0)) - { - image.data = rl_load_pvr_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps); - } + else if (TextIsEqual(fileExtLower, ".pvr")) image = LoadPVR(fileData, dataSize); #endif #if defined(SUPPORT_FILEFORMAT_ASTC) - else if ((strcmp(fileType, ".astc") == 0) || (strcmp(fileType, ".ASTC") == 0)) - { - image.data = rl_load_astc_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps); - } + else if (TextIsEqual(fileExtLower, ".astc")) image = LoadASTC(fileData, dataSize); #endif - else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported"); - - if (image.data != NULL) TRACELOG(LOG_INFO, "IMAGE: Data loaded successfully (%ix%i | %s | %i mipmaps)", image.width, image.height, rlGetPixelFormatName(image.format), image.mipmaps); - else TRACELOG(LOG_WARNING, "IMAGE: Failed to load image data"); + else TRACELOG(LOG_WARNING, "IMAGE: File format not supported"); return image; } -// Load image from GPU texture data -// NOTE: Compressed texture formats not supported -Image LoadImageFromTexture(Texture2D texture) -{ - Image image = { 0 }; - - if (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB) - { - image.data = rlReadTexturePixels(texture.id, texture.width, texture.height, texture.format); - - if (image.data != NULL) - { - image.width = texture.width; - image.height = texture.height; - image.format = texture.format; - image.mipmaps = 1; - -#if defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA, - // coming from FBO color buffer attachment, but it seems - // original texture format is retrieved on RPI... - image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; -#endif - TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Pixel data retrieved successfully", texture.id); - } - else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve pixel data", texture.id); - } - else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve compressed pixel data", texture.id); - - return image; -} - -// Load image from screen buffer and (screenshot) -Image LoadImageFromScreen(void) -{ - Vector2 scale = GetWindowScaleDPI(); - Image image = { 0 }; - - image.width = (int)(GetScreenWidth()*scale.x); - image.height = (int)(GetScreenHeight()*scale.y); - image.mipmaps = 1; - image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - image.data = rlReadScreenPixels(image.width, image.height); - - return image; -} - -// Check if an image is ready -bool IsImageValid(Image image) -{ - bool result = false; - - if ((image.data != NULL) && // Validate pixel data available - (image.width > 0) && // Validate image width - (image.height > 0) && // Validate image height - (image.format > 0) && // Validate image format - (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level) - - return result; -} - // Unload image from CPU memory (RAM) void UnloadImage(Image image) { @@ -626,10 +397,7 @@ void UnloadImage(Image image) // NOTE: File format depends on fileName extension bool ExportImage(Image image, const char *fileName) { - int result = 0; - - // Security check for input data - if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return result; + int success = 0; #if defined(SUPPORT_IMAGE_EXPORT) int channels = 4; @@ -652,91 +420,38 @@ bool ExportImage(Image image, const char *fileName) { int dataSize = 0; unsigned char *fileData = stbi_write_png_to_mem((const unsigned char *)imgData, image.width*channels, image.width, image.height, channels, &dataSize); - result = SaveFileData(fileName, fileData, dataSize); + success = SaveFileData(fileName, fileData, dataSize); RL_FREE(fileData); } #else - if (false) { } + if (false) {} #endif #if defined(SUPPORT_FILEFORMAT_BMP) - else if (IsFileExtension(fileName, ".bmp")) result = stbi_write_bmp(fileName, image.width, image.height, channels, imgData); + else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, channels, imgData); #endif #if defined(SUPPORT_FILEFORMAT_TGA) - else if (IsFileExtension(fileName, ".tga")) result = stbi_write_tga(fileName, image.width, image.height, channels, imgData); + else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, channels, imgData); #endif #if defined(SUPPORT_FILEFORMAT_JPG) - else if (IsFileExtension(fileName, ".jpg") || - IsFileExtension(fileName, ".jpeg")) result = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90); // JPG quality: between 1 and 100 -#endif -#if defined(SUPPORT_FILEFORMAT_QOI) - else if (IsFileExtension(fileName, ".qoi")) - { - channels = 0; - if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3; - else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4; - else TRACELOG(LOG_WARNING, "IMAGE: Image pixel format must be R8G8B8 or R8G8B8A8"); - - if ((channels == 3) || (channels == 4)) - { - qoi_desc desc = { 0 }; - desc.width = image.width; - desc.height = image.height; - desc.channels = channels; - desc.colorspace = QOI_SRGB; - - result = qoi_write(fileName, imgData, &desc); - } - } + else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90); // JPG quality: between 1 and 100 #endif #if defined(SUPPORT_FILEFORMAT_KTX) - else if (IsFileExtension(fileName, ".ktx")) - { - result = rl_save_ktx(fileName, image.data, image.width, image.height, image.format, image.mipmaps); - } + else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName); #endif else if (IsFileExtension(fileName, ".raw")) { // Export raw pixel data (without header) // NOTE: It's up to the user to track image parameters - result = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format)); + success = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format)); } if (allocatedData) RL_FREE(imgData); #endif // SUPPORT_IMAGE_EXPORT - if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName); + if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName); else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName); - return result; -} - -// Export image to memory buffer -unsigned char *ExportImageToMemory(Image image, const char *fileType, int *dataSize) -{ - unsigned char *fileData = NULL; - *dataSize = 0; - - // Security check for input data - if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return NULL; - -#if defined(SUPPORT_IMAGE_EXPORT) - int channels = 4; - - if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) channels = 1; - else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) channels = 2; - else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3; - else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4; - -#if defined(SUPPORT_FILEFORMAT_PNG) - if ((strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0)) - { - fileData = stbi_write_png_to_mem((const unsigned char *)image.data, image.width*channels, image.width, image.height, channels, dataSize); - } -#endif - -#endif - - return fileData; + return success; } // Export image as code file (.h) defining an array of bytes @@ -744,8 +459,6 @@ bool ExportImageAsCode(Image image, const char *fileName) { bool success = false; -#if defined(SUPPORT_IMAGE_EXPORT) - #ifndef TEXT_BYTES_PER_LINE #define TEXT_BYTES_PER_LINE 20 #endif @@ -754,19 +467,19 @@ bool ExportImageAsCode(Image image, const char *fileName) // NOTE: Text data buffer size is estimated considering image data size in bytes // and requiring 6 char bytes for every byte: "0x00, " - char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char)); + char *txtData = (char *)RL_CALLOC(6*dataSize + 2000, sizeof(char)); - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); - byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); + int bytesCount = 0; + bytesCount += sprintf(txtData + bytesCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes //\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); + bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2020 Ramon Santamaria (@raysan5) //\n"); + bytesCount += sprintf(txtData + bytesCount, "// //\n"); + bytesCount += sprintf(txtData + bytesCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; @@ -774,25 +487,20 @@ bool ExportImageAsCode(Image image, const char *fileName) for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } // Add image information - byteCount += sprintf(txtData + byteCount, "// Image data information\n"); - byteCount += sprintf(txtData + byteCount, "#define %s_WIDTH %i\n", varFileName, image.width); - byteCount += sprintf(txtData + byteCount, "#define %s_HEIGHT %i\n", varFileName, image.height); - byteCount += sprintf(txtData + byteCount, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format); + bytesCount += sprintf(txtData + bytesCount, "// Image data information\n"); + bytesCount += sprintf(txtData + bytesCount, "#define %s_WIDTH %i\n", varFileName, image.width); + bytesCount += sprintf(txtData + bytesCount, "#define %s_HEIGHT %i\n", varFileName, image.height); + bytesCount += sprintf(txtData + bytesCount, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format); - byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); - for (int i = 0; i < dataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); - byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]); + bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); + for (int i = 0; i < dataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); + bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]); - // NOTE: Text data size exported is determined by '\0' (NULL) character + // NOTE: Text data length exported is determined by '\0' (NULL) character success = SaveFileText(fileName, txtData); RL_FREE(txtData); -#endif // SUPPORT_IMAGE_EXPORT - - if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName); - else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName); - return success; } @@ -818,43 +526,48 @@ Image GenImageColor(int width, int height, Color color) } #if defined(SUPPORT_IMAGE_GENERATION) -// Generate image: linear gradient -// The direction value specifies the direction of the gradient (in degrees) -// with 0 being vertical (from top to bottom), 90 being horizontal (from left to right) -// The gradient effectively rotates counter-clockwise by the specified amount -Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end) +// Generate image: vertical gradient +Image GenImageGradientV(int width, int height, Color top, Color bottom) { Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); - float radianDirection = (float)(90 - direction)/180.f*3.14159f; - float cosDir = cosf(radianDirection); - float sinDir = sinf(radianDirection); + for (int j = 0; j < height; j++) + { + float factor = (float)j/(float)height; + for (int i = 0; i < width; i++) + { + pixels[j*width + i].r = (int)((float)bottom.r*factor + (float)top.r*(1.f - factor)); + pixels[j*width + i].g = (int)((float)bottom.g*factor + (float)top.g*(1.f - factor)); + pixels[j*width + i].b = (int)((float)bottom.b*factor + (float)top.b*(1.f - factor)); + pixels[j*width + i].a = (int)((float)bottom.a*factor + (float)top.a*(1.f - factor)); + } + } - // Calculate how far the top-left pixel is along the gradient direction from the center of said gradient - float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2); + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +// Generate image: horizontal gradient +Image GenImageGradientH(int width, int height, Color left, Color right) +{ + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); - // With directions that lie in the first or third quadrant (i.e. from top-left to - // bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient - // (i.e. the pixel which should become one of the gradient's ends color); while for - // directions that lie in the second or fourth quadrant, that point is pixel (width, 0) - float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir); for (int i = 0; i < width; i++) { + float factor = (float)i/(float)width; for (int j = 0; j < height; j++) { - // Calculate the relative position of the pixel along the gradient direction - float pos = (startingPos + (i*cosDir + j*sinDir))/maxPosValue; - - float factor = pos; - factor = (factor > 1.0f)? 1.0f : factor; // Clamp to [-1,1] - factor = (factor < -1.0f)? -1.0f : factor; // Clamp to [-1,1] - factor = factor/2.0f + 0.5f; - - // Generate the color for this pixel - pixels[j*width + i].r = (int)((float)end.r*factor + (float)start.r*(1.0f - factor)); - pixels[j*width + i].g = (int)((float)end.g*factor + (float)start.g*(1.0f - factor)); - pixels[j*width + i].b = (int)((float)end.b*factor + (float)start.b*(1.0f - factor)); - pixels[j*width + i].a = (int)((float)end.a*factor + (float)start.a*(1.0f - factor)); + pixels[j*width + i].r = (int)((float)right.r*factor + (float)left.r*(1.f - factor)); + pixels[j*width + i].g = (int)((float)right.g*factor + (float)left.g*(1.f - factor)); + pixels[j*width + i].b = (int)((float)right.b*factor + (float)left.b*(1.f - factor)); + pixels[j*width + i].a = (int)((float)right.a*factor + (float)left.a*(1.f - factor)); } } @@ -886,7 +599,7 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, float factor = (dist - radius*density)/(radius*(1.0f - density)); factor = (float)fmax(factor, 0.0f); - factor = (float)fmin(factor, 1.f); // dist can be bigger than radius, so we have to check + factor = (float)fmin(factor, 1.f); // dist can be bigger than radius so we have to check pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor)); pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor)); @@ -906,55 +619,6 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, return image; } -// Generate image: square gradient -Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer) -{ - Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); - - float centerX = (float)width/2.0f; - float centerY = (float)height/2.0f; - - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - // Calculate the Manhattan distance from the center - float distX = fabsf(x - centerX); - float distY = fabsf(y - centerY); - - // Normalize the distances by the dimensions of the gradient rectangle - float normalizedDistX = distX/centerX; - float normalizedDistY = distY/centerY; - - // Calculate the total normalized Manhattan distance - float manhattanDist = fmaxf(normalizedDistX, normalizedDistY); - - // Subtract the density from the manhattanDist, then divide by (1 - density) - // This makes the gradient start from the center when density is 0, and from the edge when density is 1 - float factor = (manhattanDist - density)/(1.0f - density); - - // Clamp the factor between 0 and 1 - factor = fminf(fmaxf(factor, 0.0f), 1.0f); - - // Blend the colors based on the calculated factor - pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor)); - pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor)); - pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor)); - pixels[y*width + x].a = (int)((float)outer.a*factor + (float)inner.a*(1.0f - factor)); - } - } - - Image image = { - .data = pixels, - .width = width, - .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 - }; - - return image; -} - // Generate image: checked Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2) { @@ -981,7 +645,6 @@ Image GenImageChecked(int width, int height, int checksX, int checksY, Color col } // Generate image: white noise -// NOTE: It requires GetRandomValue(), defined in [rcore] Image GenImageWhiteNoise(int width, int height, float factor) { Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); @@ -1008,38 +671,23 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float { Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); - float aspectRatio = (float)width/(float)height; - for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - float nx = (float)(x + offsetX)*(scale/(float)width); - float ny = (float)(y + offsetY)*(scale/(float)height); + float nx = (float)(x + offsetX)*scale/(float)width; + float ny = (float)(y + offsetY)*scale/(float)height; - // Apply aspect ratio compensation to wider side - if (width > height) nx *= aspectRatio; - else ny /= aspectRatio; - - // Basic perlin noise implementation (not used) - //float p = (stb_perlin_noise3(nx, ny, 0.0f, 0, 0, 0); - - // Calculate a better perlin noise using fbm (fractal brownian motion) // Typical values to start playing with: // lacunarity = ~2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output) // gain = 0.5 -- relative weighting applied to each successive octave // octaves = 6 -- number of "octaves" of noise3() to sum - float p = stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6); - // Clamp between -1.0f and 1.0f - if (p < -1.0f) p = -1.0f; - if (p > 1.0f) p = 1.0f; + // NOTE: We need to translate the data from [-1..1] to [0..1] + float p = (stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6) + 1.0f)/2.0f; - // We need to normalize the data from [-1..1] to [0..1] - float np = (p + 1.0f)/2.0f; - - int intensity = (int)(np*255.0f); - pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; + int intensity = (int)(p*255.0f); + pixels[y*width + x] = (Color){intensity, intensity, intensity, 255}; } } @@ -1061,15 +709,15 @@ Image GenImageCellular(int width, int height, int tileSize) int seedsPerRow = width/tileSize; int seedsPerCol = height/tileSize; - int seedCount = seedsPerRow*seedsPerCol; + int seedsCount = seedsPerRow*seedsPerCol; - Vector2 *seeds = (Vector2 *)RL_MALLOC(seedCount*sizeof(Vector2)); + Vector2 *seeds = (Vector2 *)RL_MALLOC(seedsCount*sizeof(Vector2)); - for (int i = 0; i < seedCount; i++) + for (int i = 0; i < seedsCount; i++) { int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1); int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1); - seeds[i] = (Vector2){ (float)x, (float)y }; + seeds[i] = (Vector2){ (float)x, (float)y}; } for (int y = 0; y < height; y++) @@ -1080,7 +728,7 @@ Image GenImageCellular(int width, int height, int tileSize) { int tileX = x/tileSize; - float minDistance = 65536.0f; //(float)strtod("Inf", NULL); + float minDistance = (float)strtod("Inf", NULL); // Check all adjacent tiles for (int i = -1; i < 2; i++) @@ -1098,7 +746,7 @@ Image GenImageCellular(int width, int height, int tileSize) } } - // I made this up, but it seems to give good results at all tile sizes + // I made this up but it seems to give good results at all tile sizes int intensity = (int)(minDistance*256.0f/tileSize); if (intensity > 255) intensity = 255; @@ -1118,25 +766,6 @@ Image GenImageCellular(int width, int height, int tileSize) return image; } - -// Generate image: grayscale image from text data -Image GenImageText(int width, int height, const char *text) -{ - Image image = { 0 }; - - int textLength = (int)strlen(text); - int imageViewSize = width*height; - - image.width = width; - image.height = height; - image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - image.data = RL_CALLOC(imageViewSize, 1); - image.mipmaps = 1; - - memcpy(image.data, text, (textLength > imageViewSize)? imageViewSize : textLength); - - return image; -} #endif // SUPPORT_IMAGE_GENERATION //------------------------------------------------------------------------------------ @@ -1163,7 +792,7 @@ Image ImageCopy(Image image) if (height < 1) height = 1; } - newImage.data = RL_CALLOC(size, 1); + newImage.data = RL_MALLOC(size); if (newImage.data != NULL) { @@ -1186,13 +815,15 @@ Image ImageFromImage(Image image, Rectangle rec) int bytesPerPixel = GetPixelDataSize(1, 1, image.format); + // TODO: Check rec is valid? + result.width = (int)rec.width; result.height = (int)rec.height; - result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1); + result.data = RL_CALLOC((int)(rec.width*rec.height)*bytesPerPixel, 1); result.format = image.format; result.mipmaps = 1; - for (int y = 0; y < (int)rec.height; y++) + for (int y = 0; y < rec.height; y++) { memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); } @@ -1268,6 +899,8 @@ void ImageFormat(Image *image, int newFormat) image->data = NULL; image->format = newFormat; + int k = 0; + switch (image->format) { case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: @@ -1284,7 +917,7 @@ void ImageFormat(Image *image, int newFormat) { image->data = (unsigned char *)RL_MALLOC(image->width*image->height*2*sizeof(unsigned char)); - for (int i = 0, k = 0; i < image->width*image->height*2; i += 2, k++) + for (int i = 0; i < image->width*image->height*2; i += 2, k++) { ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f); ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f); @@ -1374,7 +1007,7 @@ void ImageFormat(Image *image, int newFormat) } break; case PIXELFORMAT_UNCOMPRESSED_R32: { - // WARNING: Image is converted to GRAYSCALE equivalent 32bit + // WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float)); @@ -1406,47 +1039,13 @@ void ImageFormat(Image *image, int newFormat) ((float *)image->data)[i + 3] = pixels[k].w; } } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - // WARNING: Image is converted to GRAYSCALE equivalent 16bit - - image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); - - for (int i = 0; i < image->width*image->height; i++) - { - ((unsigned short *)image->data)[i] = FloatToHalf((float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f)); - } - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - image->data = (unsigned short *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned short)); - - for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) - { - ((unsigned short *)image->data)[i] = FloatToHalf(pixels[k].x); - ((unsigned short *)image->data)[i + 1] = FloatToHalf(pixels[k].y); - ((unsigned short *)image->data)[i + 2] = FloatToHalf(pixels[k].z); - } - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - image->data = (unsigned short *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned short)); - - for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) - { - ((unsigned short *)image->data)[i] = FloatToHalf(pixels[k].x); - ((unsigned short *)image->data)[i + 1] = FloatToHalf(pixels[k].y); - ((unsigned short *)image->data)[i + 2] = FloatToHalf(pixels[k].z); - ((unsigned short *)image->data)[i + 3] = FloatToHalf(pixels[k].w); - } - } break; default: break; } RL_FREE(pixels); pixels = NULL; - // In case original image had mipmaps, generate mipmaps for formatted image + // In case original image had mipmaps, generate mipmaps for formated image // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost if (image->mipmaps > 1) { @@ -1460,418 +1059,6 @@ void ImageFormat(Image *image, int newFormat) } } -// Create an image from text (default font) -Image ImageText(const char *text, int fontSize, Color color) -{ - Image imText = { 0 }; -#if defined(SUPPORT_MODULE_RTEXT) - int defaultFontSize = 10; // Default Font chars height in pixel - if (fontSize < defaultFontSize) fontSize = defaultFontSize; - int spacing = fontSize/defaultFontSize; - imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color); // WARNING: Module required: rtext -#else - imText = GenImageColor(200, 60, BLACK); // Generating placeholder black image rectangle - TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext"); -#endif - return imText; -} - -// Create an image from text (custom sprite font) -// WARNING: Module required: rtext -Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint) -{ - Image imText = { 0 }; -#if defined(SUPPORT_MODULE_RTEXT) - int size = (int)strlen(text); // Get size in bytes of text - - int textOffsetX = 0; // Image drawing position X - int textOffsetY = 0; // Offset between lines (on linebreak '\n') - - // NOTE: Text image is generated at font base size, later scaled to desired font size - Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext - Vector2 textSize = MeasureTextEx(font, text, fontSize, spacing); - - // Create image to store text - imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); - - for (int i = 0; i < size;) - { - // Get next codepoint from byte string and glyph index in font - int codepointByteCount = 0; - int codepoint = GetCodepointNext(&text[i], &codepointByteCount); // WARNING: Module required: rtext - int index = GetGlyphIndex(font, codepoint); // WARNING: Module required: rtext - - if (codepoint == '\n') - { - // NOTE: Fixed line spacing of 1.5 line-height - // TODO: Support custom line spacing defined by user - textOffsetY += (font.baseSize + font.baseSize/2); - textOffsetX = 0; - } - else - { - if ((codepoint != ' ') && (codepoint != '\t')) - { - Rectangle rec = { (float)(textOffsetX + font.glyphs[index].offsetX), (float)(textOffsetY + font.glyphs[index].offsetY), (float)font.recs[index].width, (float)font.recs[index].height }; - ImageDraw(&imText, font.glyphs[index].image, (Rectangle){ 0, 0, (float)font.glyphs[index].image.width, (float)font.glyphs[index].image.height }, rec, tint); - } - - if (font.glyphs[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing); - else textOffsetX += font.glyphs[index].advanceX + (int)spacing; - } - - i += codepointByteCount; // Move text bytes counter to next codepoint - } - - // Scale image depending on text size - if (textSize.y != imSize.y) - { - float scaleFactor = textSize.y/imSize.y; - TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor); - - // Using nearest-neighbor scaling algorithm for default font - // TODO: Allow defining the preferred scaling mechanism externally - if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); - else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); - } -#else - imText = GenImageColor(200, 60, BLACK); // Generating placeholder black image rectangle - TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext"); -#endif - return imText; -} - -// Create an image from a selected channel of another image -Image ImageFromChannel(Image image, int selectedChannel) -{ - Image result = { 0 }; - - // Security check to avoid program crash - if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result; - - // Check selected channel is valid - if (selectedChannel < 0) - { - TRACELOG(LOG_WARNING, "Channel cannot be negative. Setting channel to 0."); - selectedChannel = 0; - } - - if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE || - image.format == PIXELFORMAT_UNCOMPRESSED_R32 || - image.format == PIXELFORMAT_UNCOMPRESSED_R16) - { - if (selectedChannel > 0) - { - TRACELOG(LOG_WARNING, "This image has only 1 channel. Setting channel to it."); - selectedChannel = 0; - } - } - else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) - { - if (selectedChannel > 1) - { - TRACELOG(LOG_WARNING, "This image has only 2 channels. Setting channel to alpha."); - selectedChannel = 1; - } - } - else if (image.format == PIXELFORMAT_UNCOMPRESSED_R5G6B5 || - image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8 || - image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32 || - image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) - { - if (selectedChannel > 2) - { - TRACELOG(LOG_WARNING, "This image has only 3 channels. Setting channel to red."); - selectedChannel = 0; - } - } - - // Check for RGBA formats - if (selectedChannel > 3) - { - TRACELOG(LOG_WARNING, "ImageFromChannel supports channels 0 to 3 (rgba). Setting channel to alpha."); - selectedChannel = 3; - } - - // TODO: Consider other one-channel formats: R16, R32 - result.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - result.height = image.height; - result.width = image.width; - result.mipmaps = 1; - - unsigned char *pixels = (unsigned char *)RL_CALLOC(image.width*image.height, sizeof(unsigned char)); // Values from 0 to 255 - - if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats"); - else - { - for (int i = 0, k = 0; i < image.width*image.height; i++) - { - float pixelValue = -1; - switch (image.format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - { - pixelValue = (float)((unsigned char *)image.data)[i + selectedChannel]/255.0f; - - } break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - { - pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f; - k += 2; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); - else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); - else if (selectedChannel == 2) pixelValue = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); - else if (selectedChannel == 3) pixelValue = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); - else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63); - else if (selectedChannel == 2) pixelValue = (float)(pixel & 0b0000000000011111)*(1.0f/31); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15); - else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15); - else if (selectedChannel == 2) pixelValue = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15); - else if (selectedChannel == 3) pixelValue = (float)(pixel & 0b0000000000001111)*(1.0f/15); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - { - pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f; - k += 4; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: - { - pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f; - k += 3; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32: - { - pixelValue = ((float *)image.data)[k]; - k += 1; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: - { - pixelValue = ((float *)image.data)[k + selectedChannel]; - k += 3; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - { - pixelValue = ((float *)image.data)[k + selectedChannel]; - k += 4; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - pixelValue = HalfToFloat(((unsigned short *)image.data)[k]); - k += 1; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - pixelValue = HalfToFloat(((unsigned short *)image.data)[k+selectedChannel]); - k += 3; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - pixelValue = HalfToFloat(((unsigned short *)image.data)[k + selectedChannel]); - k += 4; - - } break; - default: break; - } - - pixels[i] = (unsigned char)(pixelValue*255); - } - } - - result.data = pixels; - - return result; -} - -// Resize and image to new size using Nearest-Neighbor scaling algorithm -void ImageResizeNN(Image *image,int newWidth,int newHeight) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - Color *pixels = LoadImageColors(*image); - Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); - - // EDIT: added +1 to account for an early rounding problem - int xRatio = (int)((image->width << 16)/newWidth) + 1; - int yRatio = (int)((image->height << 16)/newHeight) + 1; - - int x2, y2; - for (int y = 0; y < newHeight; y++) - { - for (int x = 0; x < newWidth; x++) - { - x2 = ((x*xRatio) >> 16); - y2 = ((y*yRatio) >> 16); - - output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ; - } - } - - int format = image->format; - - RL_FREE(image->data); - - image->data = output; - image->width = newWidth; - image->height = newHeight; - image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - - UnloadImageColors(pixels); -} - -// Resize and image to new size -// NOTE: Uses stb default scaling filters (both bicubic): -// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM -// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) -void ImageResize(Image *image, int newWidth, int newHeight) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - // Check if we can use a fast path on image scaling - // It can be for 8 bit per channel images with 1 to 4 channels per pixel - if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || - (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) || - (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || - (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) - { - int bytesPerPixel = GetPixelDataSize(1, 1, image->format); - unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel); - - switch (image->format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)1); break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)2); break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)3); break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)4); break; - default: break; - } - - RL_FREE(image->data); - image->data = output; - image->width = newWidth; - image->height = newHeight; - } - else - { - // Get data as Color pixels array to work with it - Color *pixels = LoadImageColors(*image); - Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); - - // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem... - stbir_resize_uint8_linear((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, (stbir_pixel_layout)4); - - int format = image->format; - - UnloadImageColors(pixels); - RL_FREE(image->data); - - image->data = output; - image->width = newWidth; - image->height = newHeight; - image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - } -} - -// Resize canvas and fill with color -// NOTE: Resize offset is relative to the top-left corner of the original image -void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); - if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); - else if ((newWidth != image->width) || (newHeight != image->height)) - { - Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height }; - Vector2 dstPos = { (float)offsetX, (float)offsetY }; - - if (offsetX < 0) - { - srcRec.x = (float)-offsetX; - srcRec.width += (float)offsetX; - dstPos.x = 0; - } - else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX); - - if (offsetY < 0) - { - srcRec.y = (float)-offsetY; - srcRec.height += (float)offsetY; - dstPos.y = 0; - } - else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY); - - if (newWidth < srcRec.width) srcRec.width = (float)newWidth; - if (newHeight < srcRec.height) srcRec.height = (float)newHeight; - - int bytesPerPixel = GetPixelDataSize(1, 1, image->format); - unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1); - - // Fill resized canvas with fill color - // Set first pixel with image->format - SetPixelColor(resizedData, fill, image->format); - - // Fill remaining bytes of first row - for (int x = 1; x < newWidth; x++) - { - memcpy(resizedData + x*bytesPerPixel, resizedData, bytesPerPixel); - } - // Copy the first row into the other rows - for (int y = 1; y < newHeight; y++) - { - memcpy(resizedData + y*newWidth*bytesPerPixel, resizedData, newWidth*bytesPerPixel); - } - - // Copy old image to resized canvas - int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel; - - for (int y = 0; y < (int)srcRec.height; y++) - { - memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel); - dstOffsetSize += (newWidth*bytesPerPixel); - } - - RL_FREE(image->data); - image->data = resizedData; - image->width = newWidth; - image->height = newHeight; - } -} - -#if defined(SUPPORT_IMAGE_MANIPULATION) // Convert image to POT (power-of-two) // NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) void ImageToPOT(Image *image, Color fill) @@ -1888,8 +1075,82 @@ void ImageToPOT(Image *image, Color fill) if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill); } +#if defined(SUPPORT_IMAGE_MANIPULATION) +// Create an image from text (default font) +Image ImageText(const char *text, int fontSize, Color color) +{ + int defaultFontSize = 10; // Default Font chars height in pixel + if (fontSize < defaultFontSize) fontSize = defaultFontSize; + int spacing = fontSize/defaultFontSize; + + Image imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color); + + return imText; +} + +// Create an image from text (custom sprite font) +Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint) +{ + int length = (int)strlen(text); + + int textOffsetX = 0; // Image drawing position X + int textOffsetY = 0; // Offset between lines (on line break '\n') + + // NOTE: Text image is generated at font base size, later scaled to desired font size + Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); + + // Create image to store text + Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); + + for (int i = 0; i < length; i++) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + + if (codepoint == '\n') + { + // NOTE: Fixed line spacing of 1.5 line-height + // TODO: Support custom line spacing defined by user + textOffsetY += (font.baseSize + font.baseSize/2); + textOffsetX = 0; + } + else + { + if ((codepoint != ' ') && (codepoint != '\t')) + { + Rectangle rec = { (float)(textOffsetX + font.chars[index].offsetX), (float)(textOffsetY + font.chars[index].offsetY), (float)font.recs[index].width, (float)font.recs[index].height }; + ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, (float)font.chars[index].image.width, (float)font.chars[index].image.height }, rec, tint); + } + + if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing); + else textOffsetX += font.chars[index].advanceX + (int)spacing; + } + + i += (codepointByteCount - 1); // Move text bytes counter to next codepoint + } + + // Scale image depending on text size + if (fontSize > imSize.y) + { + float scaleFactor = fontSize/imSize.y; + TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor); + + // Using nearest-neighbor scaling algorithm for default font + if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); + else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); + } + + return imText; +} + // Crop image depending on alpha value -// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f +// NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f void ImageAlphaCrop(Image *image, float threshold) { // Security check to avoid program crash @@ -1987,19 +1248,6 @@ void ImageAlphaClear(Image *image, Color color, float threshold) } } } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - for (int i = 3; i < image->width*image->height*4; i += 4) - { - if (HalfToFloat(((unsigned short *)image->data)[i]) <= threshold) - { - ((unsigned short *)image->data)[i - 3] = FloatToHalf((float)color.r/255.0f); - ((unsigned short *)image->data)[i - 2] = FloatToHalf((float)color.g/255.0f); - ((unsigned short *)image->data)[i - 1] = FloatToHalf((float)color.b/255.0f); - ((unsigned short *)image->data)[i] = FloatToHalf((float)color.a/255.0f); - } - } - } break; default: break; } } @@ -2091,278 +1339,150 @@ void ImageAlphaPremultiply(Image *image) ImageFormat(image, format); } -// Apply box blur to image -void ImageBlurGaussian(Image *image, int blurSize) +// Resize and image to new size +// NOTE: Uses stb default scaling filters (both bicubic): +// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) +void ImageResize(Image *image, int newWidth, int newHeight) { // Security check to avoid program crash if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - ImageAlphaPremultiply(image); + bool fastPath = true; + if ((image->format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && (image->format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) fastPath = true; - Color *pixels = LoadImageColors(*image); - - // Loop switches between pixelsCopy1 and pixelsCopy2 - Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4)); - Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4)); - - for (int i = 0; i < (image->height*image->width); i++) + if (fastPath) { - pixelsCopy1[i].x = pixels[i].r; - pixelsCopy1[i].y = pixels[i].g; - pixelsCopy1[i].z = pixels[i].b; - pixelsCopy1[i].w = pixels[i].a; - } + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *output = RL_MALLOC(newWidth*newHeight*bytesPerPixel); - // Repeated convolution of rectangular window signal by itself converges to a gaussian distribution - for (int j = 0; j < GAUSSIAN_BLUR_ITERATIONS; j++) - { - // Horizontal motion blur - for (int row = 0; row < image->height; row++) + switch (image->format) { - float avgR = 0.0f; - float avgG = 0.0f; - float avgB = 0.0f; - float avgAlpha = 0.0f; - int convolutionSize = blurSize; - - for (int i = 0; i < blurSize; i++) - { - avgR += pixelsCopy1[row*image->width + i].x; - avgG += pixelsCopy1[row*image->width + i].y; - avgB += pixelsCopy1[row*image->width + i].z; - avgAlpha += pixelsCopy1[row*image->width + i].w; - } - - for (int x = 0; x < image->width; x++) - { - if (x-blurSize-1 >= 0) - { - avgR -= pixelsCopy1[row*image->width + x-blurSize-1].x; - avgG -= pixelsCopy1[row*image->width + x-blurSize-1].y; - avgB -= pixelsCopy1[row*image->width + x-blurSize-1].z; - avgAlpha -= pixelsCopy1[row*image->width + x-blurSize-1].w; - convolutionSize--; - } - - if (x+blurSize < image->width) - { - avgR += pixelsCopy1[row*image->width + x+blurSize].x; - avgG += pixelsCopy1[row*image->width + x+blurSize].y; - avgB += pixelsCopy1[row*image->width + x+blurSize].z; - avgAlpha += pixelsCopy1[row*image->width + x+blurSize].w; - convolutionSize++; - } - - pixelsCopy2[row*image->width + x].x = avgR/convolutionSize; - pixelsCopy2[row*image->width + x].y = avgG/convolutionSize; - pixelsCopy2[row*image->width + x].z = avgB/convolutionSize; - pixelsCopy2[row*image->width + x].w = avgAlpha/convolutionSize; - } + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break; + default: break; } - // Vertical motion blur - for (int col = 0; col < image->width; col++) - { - float avgR = 0.0f; - float avgG = 0.0f; - float avgB = 0.0f; - float avgAlpha = 0.0f; - int convolutionSize = blurSize; - - for (int i = 0; i < blurSize; i++) - { - avgR += pixelsCopy2[i*image->width + col].x; - avgG += pixelsCopy2[i*image->width + col].y; - avgB += pixelsCopy2[i*image->width + col].z; - avgAlpha += pixelsCopy2[i*image->width + col].w; - } - - for (int y = 0; y < image->height; y++) - { - if (y-blurSize-1 >= 0) - { - avgR -= pixelsCopy2[(y-blurSize-1)*image->width + col].x; - avgG -= pixelsCopy2[(y-blurSize-1)*image->width + col].y; - avgB -= pixelsCopy2[(y-blurSize-1)*image->width + col].z; - avgAlpha -= pixelsCopy2[(y-blurSize-1)*image->width + col].w; - convolutionSize--; - } - if (y+blurSize < image->height) - { - avgR += pixelsCopy2[(y+blurSize)*image->width + col].x; - avgG += pixelsCopy2[(y+blurSize)*image->width + col].y; - avgB += pixelsCopy2[(y+blurSize)*image->width + col].z; - avgAlpha += pixelsCopy2[(y+blurSize)*image->width + col].w; - convolutionSize++; - } - - pixelsCopy1[y*image->width + col].x = (unsigned char) (avgR/convolutionSize); - pixelsCopy1[y*image->width + col].y = (unsigned char) (avgG/convolutionSize); - pixelsCopy1[y*image->width + col].z = (unsigned char) (avgB/convolutionSize); - pixelsCopy1[y*image->width + col].w = (unsigned char) (avgAlpha/convolutionSize); - } - } - } - - // Reverse premultiply - for (int i = 0; i < (image->width)*(image->height); i++) - { - if (pixelsCopy1[i].w == 0.0f) - { - pixels[i].r = 0; - pixels[i].g = 0; - pixels[i].b = 0; - pixels[i].a = 0; - } - else if (pixelsCopy1[i].w <= 255.0f) - { - float alpha = (float)pixelsCopy1[i].w/255.0f; - pixels[i].r = (unsigned char)((float)pixelsCopy1[i].x/alpha); - pixels[i].g = (unsigned char)((float)pixelsCopy1[i].y/alpha); - pixels[i].b = (unsigned char)((float)pixelsCopy1[i].z/alpha); - pixels[i].a = (unsigned char) pixelsCopy1[i].w; - } - } - - int format = image->format; - RL_FREE(image->data); - RL_FREE(pixelsCopy1); - RL_FREE(pixelsCopy2); - - image->data = pixels; - image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - ImageFormat(image, format); -} - -// Apply custom square convolution kernel to image -// NOTE: The convolution kernel matrix is expected to be square -void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize) -{ - if ((image->data == NULL) || (image->width == 0) || (image->height == 0) || kernel == NULL) return; - - int kernelWidth = (int)sqrtf((float)kernelSize); - - if (kernelWidth*kernelWidth != kernelSize) - { - TRACELOG(LOG_WARNING, "IMAGE: Convolution kernel must be square to be applied"); - return; - } - - Color *pixels = LoadImageColors(*image); - - Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4)); - Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4)); - - for (int i = 0; i < kernelSize; i++) - { - temp[i].x = 0.0f; - temp[i].y = 0.0f; - temp[i].z = 0.0f; - temp[i].w = 0.0f; - } - - float rRes = 0.0f; - float gRes = 0.0f; - float bRes = 0.0f; - float aRes = 0.0f; - - int startRange = 0, endRange = 0; - - if (kernelWidth%2 == 0) - { - startRange = -kernelWidth/2; - endRange = kernelWidth/2; + RL_FREE(image->data); + image->data = output; + image->width = newWidth; + image->height = newHeight; } else { - startRange = -kernelWidth/2; - endRange = kernelWidth/2 + 1; + // Get data as Color pixels array to work with it + Color *pixels = LoadImageColors(*image); + Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); + + // NOTE: Color data is casted to (unsigned char *), there shouldn't been any problem... + stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); + + int format = image->format; + + UnloadImageColors(pixels); + RL_FREE(image->data); + + image->data = output; + image->width = newWidth; + image->height = newHeight; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); // Reformat 32bit RGBA image to original format } +} - for (int x = 0; x < image->height; x++) +// Resize and image to new size using Nearest-Neighbor scaling algorithm +void ImageResizeNN(Image *image,int newWidth,int newHeight) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + Color *pixels = LoadImageColors(*image); + Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); + + // EDIT: added +1 to account for an early rounding problem + int xRatio = (int)((image->width << 16)/newWidth) + 1; + int yRatio = (int)((image->height << 16)/newHeight) + 1; + + int x2, y2; + for (int y = 0; y < newHeight; y++) { - for (int y = 0; y < image->width; y++) + for (int x = 0; x < newWidth; x++) { - for (int xk = startRange; xk < endRange; xk++) - { - for (int yk = startRange; yk < endRange; yk++) - { - int xkabs = xk + kernelWidth/2; - int ykabs = yk + kernelWidth/2; - unsigned int imgindex = image->width*(x + xk) + (y + yk); + x2 = ((x*xRatio) >> 16); + y2 = ((y*yRatio) >> 16); - if (imgindex >= (unsigned int)(image->width*image->height)) - { - temp[kernelWidth*xkabs + ykabs].x = 0.0f; - temp[kernelWidth*xkabs + ykabs].y = 0.0f; - temp[kernelWidth*xkabs + ykabs].z = 0.0f; - temp[kernelWidth*xkabs + ykabs].w = 0.0f; - } - else - { - temp[kernelWidth*xkabs + ykabs].x = ((float)pixels[imgindex].r)/255.0f*kernel[kernelWidth*xkabs + ykabs]; - temp[kernelWidth*xkabs + ykabs].y = ((float)pixels[imgindex].g)/255.0f*kernel[kernelWidth*xkabs + ykabs]; - temp[kernelWidth*xkabs + ykabs].z = ((float)pixels[imgindex].b)/255.0f*kernel[kernelWidth*xkabs + ykabs]; - temp[kernelWidth*xkabs + ykabs].w = ((float)pixels[imgindex].a)/255.0f*kernel[kernelWidth*xkabs + ykabs]; - } - } - } - - for (int i = 0; i < kernelSize; i++) - { - rRes += temp[i].x; - gRes += temp[i].y; - bRes += temp[i].z; - aRes += temp[i].w; - } - - if (rRes < 0.0f) rRes = 0.0f; - if (gRes < 0.0f) gRes = 0.0f; - if (bRes < 0.0f) bRes = 0.0f; - - if (rRes > 1.0f) rRes = 1.0f; - if (gRes > 1.0f) gRes = 1.0f; - if (bRes > 1.0f) bRes = 1.0f; - - imageCopy2[image->width*x + y].x = rRes; - imageCopy2[image->width*x + y].y = gRes; - imageCopy2[image->width*x + y].z = bRes; - imageCopy2[image->width*x + y].w = aRes; - - rRes = 0.0f; - gRes = 0.0f; - bRes = 0.0f; - aRes = 0.0f; - - for (int i = 0; i < kernelSize; i++) - { - temp[i].x = 0.0f; - temp[i].y = 0.0f; - temp[i].z = 0.0f; - temp[i].w = 0.0f; - } + output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ; } } - for (int i = 0; i < (image->width*image->height); i++) - { - float alpha = (float)imageCopy2[i].w; - - pixels[i].r = (unsigned char)((imageCopy2[i].x)*255.0f); - pixels[i].g = (unsigned char)((imageCopy2[i].y)*255.0f); - pixels[i].b = (unsigned char)((imageCopy2[i].z)*255.0f); - pixels[i].a = (unsigned char)((alpha)*255.0f); - } - int format = image->format; - RL_FREE(image->data); - RL_FREE(imageCopy2); - RL_FREE(temp); - image->data = pixels; + RL_FREE(image->data); + + image->data = output; + image->width = newWidth; + image->height = newHeight; image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - ImageFormat(image, format); + + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + + UnloadImageColors(pixels); +} + +// Resize canvas and fill with color +// NOTE: Resize offset is relative to the top-left corner of the original image +void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); + if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); + else if ((newWidth != image->width) || (newHeight != image->height)) + { + Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height }; + Vector2 dstPos = { (float)offsetX, (float)offsetY }; + + if (offsetX < 0) + { + srcRec.x = (float)-offsetX; + srcRec.width += (float)offsetX; + dstPos.x = 0; + } + else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX); + + if (offsetY < 0) + { + srcRec.y = (float)-offsetY; + srcRec.height += (float)offsetY; + dstPos.y = 0; + } + else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY); + + if (newWidth < srcRec.width) srcRec.width = (float)newWidth; + if (newHeight < srcRec.height) srcRec.height = (float)newHeight; + + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1); + + // TODO: Fill resizedData with fill color (must be formatted to image->format) + + int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel; + + for (int y = 0; y < (int)srcRec.height; y++) + { + memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel); + dstOffsetSize += (newWidth*bytesPerPixel); + } + + RL_FREE(image->data); + image->data = resizedData; + image->width = newWidth; + image->height = newHeight; + } } // Generate all mipmap levels for a provided image @@ -2403,16 +1523,22 @@ void ImageMipmaps(Image *image) else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps required memory could not be allocated"); // Pointer to allocated memory point where store next mipmap level data - unsigned char *nextmip = image->data; + unsigned char *nextmip = (unsigned char *)image->data + GetPixelDataSize(image->width, image->height, image->format); - mipWidth = image->width; - mipHeight = image->height; + mipWidth = image->width/2; + mipHeight = image->height/2; mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); Image imCopy = ImageCopy(*image); for (int i = 1; i < mipCount; i++) { + TRACELOGD("IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip); + + ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter + + memcpy(nextmip, imCopy.data, mipSize); nextmip += mipSize; + image->mipmaps++; mipWidth /= 2; mipHeight /= 2; @@ -2422,25 +1548,15 @@ void ImageMipmaps(Image *image) if (mipHeight < 1) mipHeight = 1; mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); - - if (i < image->mipmaps) continue; - - TRACELOGD("IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip); - - ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter - - memcpy(nextmip, imCopy.data, mipSize); } UnloadImage(imCopy); - - image->mipmaps = mipCount; } else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps already available"); } // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -// NOTE: In case selected bpp do not represent a known 16bit format, +// NOTE: In case selected bpp do not represent an known 16bit format, // dithered data is stored in the LSB part of the unsigned short void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { @@ -2592,7 +1708,7 @@ void ImageFlipHorizontal(Image *image) { for (int x = 0; x < image->width; x++) { - // OPTION 1: Move pixels with memcpy() + // OPTION 1: Move pixels with memcopy() //memcpy(flippedData + (y*image->width + x)*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - 1 - x))*bytesPerPixel, bytesPerPixel); // OPTION 2: Just copy data pixel by pixel @@ -2620,65 +1736,6 @@ void ImageFlipHorizontal(Image *image) } } -// Rotate image in degrees -void ImageRotate(Image *image, int degrees) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); - if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); - else - { - float rad = degrees*PI/180.0f; - float sinRadius = sinf(rad); - float cosRadius = cosf(rad); - - int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius)); - int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius)); - - int bytesPerPixel = GetPixelDataSize(1, 1, image->format); - unsigned char *rotatedData = (unsigned char *)RL_CALLOC(width*height, bytesPerPixel); - - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f; - float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f; - - if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height)) - { - int x1 = (int)floorf(oldX); - int y1 = (int)floorf(oldY); - int x2 = MIN(x1 + 1, image->width - 1); - int y2 = MIN(y1 + 1, image->height - 1); - - float px = oldX - x1; - float py = oldY - y1; - - for (int i = 0; i < bytesPerPixel; i++) - { - float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i]; - float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i]; - float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i]; - float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i]; - - float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py; - - rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val; - } - } - } - } - - RL_FREE(image->data); - image->data = rotatedData; - image->width = width; - image->height = height; - } -} - // Rotate image clockwise 90deg void ImageRotateCW(Image *image) { @@ -2751,17 +1808,26 @@ void ImageColorTint(Image *image, Color color) Color *pixels = LoadImageColors(*image); - for (int i = 0; i < image->width*image->height; i++) - { - unsigned char r = (unsigned char)(((int)pixels[i].r*(int)color.r)/255); - unsigned char g = (unsigned char)(((int)pixels[i].g*(int)color.g)/255); - unsigned char b = (unsigned char)(((int)pixels[i].b*(int)color.b)/255); - unsigned char a = (unsigned char)(((int)pixels[i].a*(int)color.a)/255); + float cR = (float)color.r/255; + float cG = (float)color.g/255; + float cB = (float)color.b/255; + float cA = (float)color.a/255; - pixels[i].r = r; - pixels[i].g = g; - pixels[i].b = b; - pixels[i].a = a; + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + int index = y*image->width + x; + unsigned char r = (unsigned char)(((float)pixels[index].r/255*cR)*255.0f); + unsigned char g = (unsigned char)(((float)pixels[index].g/255*cG)*255.0f); + unsigned char b = (unsigned char)(((float)pixels[index].b/255*cB)*255.0f); + unsigned char a = (unsigned char)(((float)pixels[index].a/255*cA)*255.0f); + + pixels[y*image->width + x].r = r; + pixels[y*image->width + x].g = g; + pixels[y*image->width + x].b = b; + pixels[y*image->width + x].a = a; + } } int format = image->format; @@ -2781,11 +1847,14 @@ void ImageColorInvert(Image *image) Color *pixels = LoadImageColors(*image); - for (int i = 0; i < image->width*image->height; i++) + for (int y = 0; y < image->height; y++) { - pixels[i].r = 255 - pixels[i].r; - pixels[i].g = 255 - pixels[i].g; - pixels[i].b = 255 - pixels[i].b; + for (int x = 0; x < image->width; x++) + { + pixels[y*image->width + x].r = 255 - pixels[y*image->width + x].r; + pixels[y*image->width + x].g = 255 - pixels[y*image->width + x].g; + pixels[y*image->width + x].b = 255 - pixels[y*image->width + x].b; + } } int format = image->format; @@ -2818,35 +1887,38 @@ void ImageColorContrast(Image *image, float contrast) Color *pixels = LoadImageColors(*image); - for (int i = 0; i < image->width*image->height; i++) + for (int y = 0; y < image->height; y++) { - float pR = (float)pixels[i].r/255.0f; - pR -= 0.5f; - pR *= contrast; - pR += 0.5f; - pR *= 255; - if (pR < 0) pR = 0; - if (pR > 255) pR = 255; + for (int x = 0; x < image->width; x++) + { + float pR = (float)pixels[y*image->width + x].r/255.0f; + pR -= 0.5; + pR *= contrast; + pR += 0.5; + pR *= 255; + if (pR < 0) pR = 0; + if (pR > 255) pR = 255; - float pG = (float)pixels[i].g/255.0f; - pG -= 0.5f; - pG *= contrast; - pG += 0.5f; - pG *= 255; - if (pG < 0) pG = 0; - if (pG > 255) pG = 255; + float pG = (float)pixels[y*image->width + x].g/255.0f; + pG -= 0.5; + pG *= contrast; + pG += 0.5; + pG *= 255; + if (pG < 0) pG = 0; + if (pG > 255) pG = 255; - float pB = (float)pixels[i].b/255.0f; - pB -= 0.5f; - pB *= contrast; - pB += 0.5f; - pB *= 255; - if (pB < 0) pB = 0; - if (pB > 255) pB = 255; + float pB = (float)pixels[y*image->width + x].b/255.0f; + pB -= 0.5; + pB *= contrast; + pB += 0.5; + pB *= 255; + if (pB < 0) pB = 0; + if (pB > 255) pB = 255; - pixels[i].r = (unsigned char)pR; - pixels[i].g = (unsigned char)pG; - pixels[i].b = (unsigned char)pB; + pixels[y*image->width + x].r = (unsigned char)pR; + pixels[y*image->width + x].g = (unsigned char)pG; + pixels[y*image->width + x].b = (unsigned char)pB; + } } int format = image->format; @@ -2870,24 +1942,27 @@ void ImageColorBrightness(Image *image, int brightness) Color *pixels = LoadImageColors(*image); - for (int i = 0; i < image->width*image->height; i++) + for (int y = 0; y < image->height; y++) { - int cR = pixels[i].r + brightness; - int cG = pixels[i].g + brightness; - int cB = pixels[i].b + brightness; + for (int x = 0; x < image->width; x++) + { + int cR = pixels[y*image->width + x].r + brightness; + int cG = pixels[y*image->width + x].g + brightness; + int cB = pixels[y*image->width + x].b + brightness; - if (cR < 0) cR = 1; - if (cR > 255) cR = 255; + if (cR < 0) cR = 1; + if (cR > 255) cR = 255; - if (cG < 0) cG = 1; - if (cG > 255) cG = 255; + if (cG < 0) cG = 1; + if (cG > 255) cG = 255; - if (cB < 0) cB = 1; - if (cB > 255) cB = 255; + if (cB < 0) cB = 1; + if (cB > 255) cB = 255; - pixels[i].r = (unsigned char)cR; - pixels[i].g = (unsigned char)cG; - pixels[i].b = (unsigned char)cB; + pixels[y*image->width + x].r = (unsigned char)cR; + pixels[y*image->width + x].g = (unsigned char)cG; + pixels[y*image->width + x].b = (unsigned char)cB; + } } int format = image->format; @@ -2907,17 +1982,20 @@ void ImageColorReplace(Image *image, Color color, Color replace) Color *pixels = LoadImageColors(*image); - for (int i = 0; i < image->width*image->height; i++) + for (int y = 0; y < image->height; y++) { - if ((pixels[i].r == color.r) && - (pixels[i].g == color.g) && - (pixels[i].b == color.b) && - (pixels[i].a == color.a)) + for (int x = 0; x < image->width; x++) { - pixels[i].r = replace.r; - pixels[i].g = replace.g; - pixels[i].b = replace.b; - pixels[i].a = replace.a; + if ((pixels[y*image->width + x].r == color.r) && + (pixels[y*image->width + x].g == color.g) && + (pixels[y*image->width + x].b == color.b) && + (pixels[y*image->width + x].a == color.a)) + { + pixels[y*image->width + x].r = replace.r; + pixels[y*image->width + x].g = replace.g; + pixels[y*image->width + x].b = replace.b; + pixels[y*image->width + x].a = replace.a; + } } } @@ -2946,10 +2024,6 @@ Color *LoadImageColors(Image image) (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) || (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 32bit to 8bit per channel"); - if ((image.format == PIXELFORMAT_UNCOMPRESSED_R16) || - (image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) || - (image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 16bit to 8bit per channel"); - for (int i = 0, k = 0; i < image.width*image.height; i++) { switch (image.format) @@ -3026,7 +2100,6 @@ Color *LoadImageColors(Image image) pixels[i].b = 0; pixels[i].a = 255; - k += 1; } break; case PIXELFORMAT_UNCOMPRESSED_R32G32B32: { @@ -3040,36 +2113,9 @@ Color *LoadImageColors(Image image) case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: { pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); - pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f); - pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f); - pixels[i].a = (unsigned char)(((float *)image.data)[k + 3]*255.0f); - - k += 4; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f); - pixels[i].g = 0; - pixels[i].b = 0; - pixels[i].a = 255; - - k += 1; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f); - pixels[i].g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 1])*255.0f); - pixels[i].b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 2])*255.0f); - pixels[i].a = 255; - - k += 3; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f); - pixels[i].g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 1])*255.0f); - pixels[i].b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 2])*255.0f); - pixels[i].a = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 3])*255.0f); + pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f); k += 4; } break; @@ -3083,7 +2129,7 @@ Color *LoadImageColors(Image image) // Load colors palette from image as a Color array (RGBA - 32bit) // NOTE: Memory allocated should be freed using UnloadImagePalette() -Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount) +Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorsCount) { #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) @@ -3132,7 +2178,7 @@ Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount) UnloadImageColors(pixels); } - *colorCount = palCount; + *colorsCount = palCount; return palette; } @@ -3149,8 +2195,119 @@ void UnloadImagePalette(Color *colors) RL_FREE(colors); } +// Get pixel data from image as Vector4 array (float normalized) +static Vector4 *LoadImageDataNormalized(Image image) +{ + Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4)); + + if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats"); + else + { + for (int i = 0, k = 0; i < image.width*image.height; i++) + { + switch (image.format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + { + pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].w = 1.0f; + + } break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f; + + k += 2; + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); + pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); + pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); + pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); + pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63); + pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31); + pixels[i].w = 1.0f; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15); + pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15); + pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15); + pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15); + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; + pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f; + + k += 4; + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; + pixels[i].w = 1.0f; + + k += 3; + } break; + case PIXELFORMAT_UNCOMPRESSED_R32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = 0.0f; + pixels[i].z = 0.0f; + pixels[i].w = 1.0f; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = ((float *)image.data)[k + 1]; + pixels[i].z = ((float *)image.data)[k + 2]; + pixels[i].w = 1.0f; + + k += 3; + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = ((float *)image.data)[k + 1]; + pixels[i].z = ((float *)image.data)[k + 2]; + pixels[i].w = ((float *)image.data)[k + 3]; + + k += 4; + } + default: break; + } + } + } + + return pixels; +} + // Get image alpha border rectangle -// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f +// NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f Rectangle GetImageAlphaBorder(Image image, float threshold) { Rectangle crop = { 0 }; @@ -3190,153 +2347,13 @@ Rectangle GetImageAlphaBorder(Image image, float threshold) return crop; } -// Get image pixel color at (x, y) position -Color GetImageColor(Image image, int x, int y) -{ - Color color = { 0 }; - - if ((x >=0) && (x < image.width) && (y >= 0) && (y < image.height)) - { - switch (image.format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - { - color.r = ((unsigned char *)image.data)[y*image.width + x]; - color.g = ((unsigned char *)image.data)[y*image.width + x]; - color.b = ((unsigned char *)image.data)[y*image.width + x]; - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - { - color.r = ((unsigned char *)image.data)[(y*image.width + x)*2]; - color.g = ((unsigned char *)image.data)[(y*image.width + x)*2]; - color.b = ((unsigned char *)image.data)[(y*image.width + x)*2]; - color.a = ((unsigned char *)image.data)[(y*image.width + x)*2 + 1]; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - { - unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x]; - - color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); - color.g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); - color.b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); - color.a = (unsigned char)((pixel & 0b0000000000000001)*255); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: - { - unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x]; - - color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); - color.g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); - color.b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - { - unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x]; - - color.r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); - color.g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); - color.b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); - color.a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - { - color.r = ((unsigned char *)image.data)[(y*image.width + x)*4]; - color.g = ((unsigned char *)image.data)[(y*image.width + x)*4 + 1]; - color.b = ((unsigned char *)image.data)[(y*image.width + x)*4 + 2]; - color.a = ((unsigned char *)image.data)[(y*image.width + x)*4 + 3]; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: - { - color.r = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3]; - color.g = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3 + 1]; - color.b = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3 + 2]; - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32: - { - color.r = (unsigned char)(((float *)image.data)[y*image.width + x]*255.0f); - color.g = 0; - color.b = 0; - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: - { - color.r = (unsigned char)(((float *)image.data)[(y*image.width + x)*3]*255.0f); - color.g = (unsigned char)(((float *)image.data)[(y*image.width + x)*3 + 1]*255.0f); - color.b = (unsigned char)(((float *)image.data)[(y*image.width + x)*3 + 2]*255.0f); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - { - color.r = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f); - color.g = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f); - color.b = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f); - color.a = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[y*image.width + x])*255.0f); - color.g = 0; - color.b = 0; - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3])*255.0f); - color.g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3 + 1])*255.0f); - color.b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3 + 2])*255.0f); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f); - color.g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f); - color.b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f); - color.a = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f); - - } break; - default: TRACELOG(LOG_WARNING, "Compressed image format does not support color reading"); break; - } - } - else TRACELOG(LOG_WARNING, "Requested image pixel (%i, %i) out of bounds", x, y); - - return color; -} - //------------------------------------------------------------------------------------ // Image drawing functions //------------------------------------------------------------------------------------ // Clear image background with given color void ImageClearBackground(Image *dst, Color color) { - // Security check to avoid program crash - if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return; - - // Fill in first pixel based on image format - ImageDrawPixel(dst, 0, 0, color); - - unsigned char *pSrcPixel = (unsigned char *)dst->data; - int bytesPerPixel = GetPixelDataSize(1, 1, dst->format); - - // Repeat the first pixel data throughout the image - for (int i = 1; i < dst->width*dst->height; i++) - { - memcpy(pSrcPixel + i*bytesPerPixel, pSrcPixel, bytesPerPixel); - } + for (int i = 0; i < dst->width*dst->height; ++i) ImageDrawPixel(dst, i%dst->width, i/dst->width, color); } // Draw pixel within an image @@ -3387,7 +2404,7 @@ void ImageDrawPixel(Image *dst, int x, int y, Color color) unsigned char r = (unsigned char)(round(coln.x*31.0f)); unsigned char g = (unsigned char)(round(coln.y*31.0f)); unsigned char b = (unsigned char)(round(coln.z*31.0f)); - unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0; + unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;; ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; @@ -3447,34 +2464,6 @@ void ImageDrawPixel(Image *dst, int x, int y, Color color) ((float *)dst->data)[(y*dst->width + x)*4 + 2] = coln.z; ((float *)dst->data)[(y*dst->width + x)*4 + 3] = coln.w; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - // NOTE: Calculate grayscale equivalent color (normalized to 32bit) - Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; - - ((unsigned short*)dst->data)[y*dst->width + x] = FloatToHalf(coln.x*0.299f + coln.y*0.587f + coln.z*0.114f); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - // NOTE: Calculate R32G32B32 equivalent color (normalized to 32bit) - Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; - - ((unsigned short *)dst->data)[(y*dst->width + x)*3] = FloatToHalf(coln.x); - ((unsigned short *)dst->data)[(y*dst->width + x)*3 + 1] = FloatToHalf(coln.y); - ((unsigned short *)dst->data)[(y*dst->width + x)*3 + 2] = FloatToHalf(coln.z); - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - // NOTE: Calculate R32G32B32A32 equivalent color (normalized to 32bit) - Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f }; - - ((unsigned short *)dst->data)[(y*dst->width + x)*4] = FloatToHalf(coln.x); - ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 1] = FloatToHalf(coln.y); - ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 2] = FloatToHalf(coln.z); - ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 3] = FloatToHalf(coln.w); - } break; default: break; } @@ -3489,52 +2478,18 @@ void ImageDrawPixelV(Image *dst, Vector2 position, Color color) // Draw line within an image void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color) { - // Calculate differences in coordinates - int shortLen = endPosY - startPosY; - int longLen = endPosX - startPosX; - bool yLonger = false; + int m = 2*(endPosY - startPosY); + int slopeError = m - (endPosX - startPosX); - // Determine if the line is more vertical than horizontal - if (abs(shortLen) > abs(longLen)) + for (int x = startPosX, y = startPosY; x <= endPosX; x++) { - // Swap the lengths if the line is more vertical - int temp = shortLen; - shortLen = longLen; - longLen = temp; - yLonger = true; - } + ImageDrawPixel(dst, x, y, color); + slopeError += m; - // Initialize variables for drawing loop - int endVal = longLen; - int sgnInc = 1; - - // Adjust direction increment based on longLen sign - if (longLen < 0) - { - longLen = -longLen; - sgnInc = -1; - } - - // Calculate fixed-point increment for shorter length - int decInc = (longLen == 0)? 0 : (shortLen << 16)/longLen; - - // Draw the line pixel by pixel - if (yLonger) - { - // If line is more vertical, iterate over y-axis - for (int i = 0, j = 0; i != endVal; i += sgnInc, j += decInc) + if (slopeError >= 0) { - // Calculate pixel position and draw it - ImageDrawPixel(dst, startPosX + (j >> 16), startPosY + i, color); - } - } - else - { - // If line is more horizontal, iterate over x-axis - for (int i = 0, j = 0; i != endVal; i += sgnInc, j += decInc) - { - // Calculate pixel position and draw it - ImageDrawPixel(dst, startPosX + i, startPosY + (j >> 16), color); + y++; + slopeError -= 2*(endPosX - startPosX); } } } @@ -3542,96 +2497,13 @@ void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int en // Draw line within an image (Vector version) void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color) { - // Round start and end positions to nearest integer coordinates - int x1 = (int)(start.x + 0.5f); - int y1 = (int)(start.y + 0.5f); - int x2 = (int)(end.x + 0.5f); - int y2 = (int)(end.y + 0.5f); - - // Draw a vertical line using ImageDrawLine function - ImageDrawLine(dst, x1, y1, x2, y2, color); -} - -// Draw a line defining thickness within an image -void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color) -{ - // Round start and end positions to nearest integer coordinates - int x1 = (int)(start.x + 0.5f); - int y1 = (int)(start.y + 0.5f); - int x2 = (int)(end.x + 0.5f); - int y2 = (int)(end.y + 0.5f); - - // Calculate differences in x and y coordinates - int dx = x2 - x1; - int dy = y2 - y1; - - // Draw the main line between (x1, y1) and (x2, y2) - ImageDrawLine(dst, x1, y1, x2, y2, color); - - // Determine if the line is more horizontal or vertical - if ((dx != 0) && (abs(dy/dx) < 1)) - { - // Line is more horizontal - // Calculate half the width of the line - int wy = (thick - 1)*(int)sqrtf((float)(dx*dx + dy*dy))/(2*abs(dx)); - - // Draw additional lines above and below the main line - for (int i = 1; i <= wy; i++) - { - ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color); // Draw above the main line - ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color); // Draw below the main line - } - } - else if (dy != 0) - { - // Line is more vertical or perfectly horizontal - // Calculate half the width of the line - int wx = (thick - 1)*(int)sqrtf((float)(dx*dx + dy*dy))/(2*abs(dy)); - - // Draw additional lines to the left and right of the main line - for (int i = 1; i <= wx; i++) - { - ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color); // Draw left of the main line - ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color); // Draw right of the main line - } - } + ImageDrawLine(dst, (int)start.x, (int)start.y, (int)end.x, (int)end.y, color); } // Draw circle within an image -void ImageDrawCircle(Image* dst, int centerX, int centerY, int radius, Color color) +void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color) { - int x = 0; - int y = radius; - int decesionParameter = 3 - 2*radius; - - while (y >= x) - { - ImageDrawRectangle(dst, centerX - x, centerY + y, x*2, 1, color); - ImageDrawRectangle(dst, centerX - x, centerY - y, x*2, 1, color); - ImageDrawRectangle(dst, centerX - y, centerY + x, y*2, 1, color); - ImageDrawRectangle(dst, centerX - y, centerY - x, y*2, 1, color); - x++; - - if (decesionParameter > 0) - { - y--; - decesionParameter = decesionParameter + 4*(x - y) + 10; - } - else decesionParameter = decesionParameter + 4*x + 6; - } -} - -// Draw circle within an image (Vector version) -void ImageDrawCircleV(Image* dst, Vector2 center, int radius, Color color) -{ - ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color); -} - -// Draw circle outline within an image -void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color) -{ - int x = 0; - int y = radius; + int x = 0, y = radius; int decesionParameter = 3 - 2*radius; while (y >= x) @@ -3655,10 +2527,10 @@ void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Colo } } -// Draw circle outline within an image (Vector version) -void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color) +// Draw circle within an image (Vector version) +void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color) { - ImageDrawCircleLines(dst, (int)center.x, (int)center.y, radius, color); + ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color); } // Draw rectangle within an image @@ -3679,42 +2551,18 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color) // Security check to avoid program crash if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return; - // Security check to avoid drawing out of bounds in case of bad user data - if (rec.x < 0) { rec.width += rec.x; rec.x = 0; } - if (rec.y < 0) { rec.height += rec.y; rec.y = 0; } - if (rec.width < 0) rec.width = 0; - if (rec.height < 0) rec.height = 0; - - // Clamp the size the the image bounds - if ((rec.x + rec.width) >= dst->width) rec.width = dst->width - rec.x; - if ((rec.y + rec.height) >= dst->height) rec.height = dst->height - rec.y; - - // Check if the rect is even inside the image - if ((rec.x >= dst->width) || (rec.y >= dst->height)) return; - if (((rec.x + rec.width) <= 0) || (rec.y + rec.height <= 0)) return; - int sy = (int)rec.y; + int ey = sy + (int)rec.height; + int sx = (int)rec.x; + int ex = sx + (int)rec.width; - int bytesPerPixel = GetPixelDataSize(1, 1, dst->format); - - // Fill in the first pixel of the first row based on image format - ImageDrawPixel(dst, sx, sy, color); - - int bytesOffset = ((sy*dst->width) + sx)*bytesPerPixel; - unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset; - - // Repeat the first pixel data throughout the row - for (int x = 1; x < (int)rec.width; x++) + for (int y = sy; y < ey; y++) { - memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, bytesPerPixel); - } - - // Repeat the first row data for all other rows - int bytesPerRow = bytesPerPixel*(int)rec.width; - for (int y = 1; y < (int)rec.height; y++) - { - memcpy(pSrcPixel + (y*dst->width)*bytesPerPixel, pSrcPixel, bytesPerRow); + for (int x = sx; x < ex; x++) + { + ImageDrawPixel(dst, x, y, color); + } } } @@ -3727,194 +2575,6 @@ void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color) ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + rec.height - thick), (int)rec.width, thick, color); } -// Draw triangle within an image -void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color) -{ - // Calculate the 2D bounding box of the triangle - // Determine the minimum and maximum x and y coordinates of the triangle vertices - int xMin = (int)((v1.x < v2.x)? ((v1.x < v3.x)? v1.x : v3.x) : ((v2.x < v3.x)? v2.x : v3.x)); - int yMin = (int)((v1.y < v2.y)? ((v1.y < v3.y)? v1.y : v3.y) : ((v2.y < v3.y)? v2.y : v3.y)); - int xMax = (int)((v1.x > v2.x)? ((v1.x > v3.x)? v1.x : v3.x) : ((v2.x > v3.x)? v2.x : v3.x)); - int yMax = (int)((v1.y > v2.y)? ((v1.y > v3.y)? v1.y : v3.y) : ((v2.y > v3.y)? v2.y : v3.y)); - - // Clamp the bounding box to the image dimensions - if (xMin < 0) xMin = 0; - if (yMin < 0) yMin = 0; - if (xMax > dst->width) xMax = dst->width; - if (yMax > dst->height) yMax = dst->height; - - // Check the order of the vertices to determine if it's a front or back face - // NOTE: if signedArea is equal to 0, the face is degenerate - float signedArea = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y); - bool isBackFace = (signedArea > 0); - - // Barycentric interpolation setup - // Calculate the step increments for the barycentric coordinates - int w1XStep = (int)(v3.y - v2.y), w1YStep = (int)(v2.x - v3.x); - int w2XStep = (int)(v1.y - v3.y), w2YStep = (int)(v3.x - v1.x); - int w3XStep = (int)(v2.y - v1.y), w3YStep = (int)(v1.x - v2.x); - - // If the triangle is a back face, invert the steps - if (isBackFace) - { - w1XStep = -w1XStep, w1YStep = -w1YStep; - w2XStep = -w2XStep, w2YStep = -w2YStep; - w3XStep = -w3XStep, w3YStep = -w3YStep; - } - - // Calculate the initial barycentric coordinates for the top-left point of the bounding box - int w1Row = (int)((xMin - v2.x)*w1XStep + w1YStep*(yMin - v2.y)); - int w2Row = (int)((xMin - v3.x)*w2XStep + w2YStep*(yMin - v3.y)); - int w3Row = (int)((xMin - v1.x)*w3XStep + w3YStep*(yMin - v1.y)); - - // Rasterization loop - // Iterate through each pixel in the bounding box - for (int y = yMin; y <= yMax; y++) - { - int w1 = w1Row; - int w2 = w2Row; - int w3 = w3Row; - - for (int x = xMin; x <= xMax; x++) - { - // Check if the pixel is inside the triangle using barycentric coordinates - // If it is then we can draw the pixel with the given color - if ((w1 | w2 | w3) >= 0) ImageDrawPixel(dst, x, y, color); - - // Increment the barycentric coordinates for the next pixel - w1 += w1XStep; - w2 += w2XStep; - w3 += w3XStep; - } - - // Move to the next row in the bounding box - w1Row += w1YStep; - w2Row += w2YStep; - w3Row += w3YStep; - } -} - -// Draw triangle with interpolated colors within an image -void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3) -{ - // Calculate the 2D bounding box of the triangle - // Determine the minimum and maximum x and y coordinates of the triangle vertices - int xMin = (int)((v1.x < v2.x)? ((v1.x < v3.x)? v1.x : v3.x) : ((v2.x < v3.x)? v2.x : v3.x)); - int yMin = (int)((v1.y < v2.y)? ((v1.y < v3.y)? v1.y : v3.y) : ((v2.y < v3.y)? v2.y : v3.y)); - int xMax = (int)((v1.x > v2.x)? ((v1.x > v3.x)? v1.x : v3.x) : ((v2.x > v3.x)? v2.x : v3.x)); - int yMax = (int)((v1.y > v2.y)? ((v1.y > v3.y)? v1.y : v3.y) : ((v2.y > v3.y)? v2.y : v3.y)); - - // Clamp the bounding box to the image dimensions - if (xMin < 0) xMin = 0; - if (yMin < 0) yMin = 0; - if (xMax > dst->width) xMax = dst->width; - if (yMax > dst->height) yMax = dst->height; - - // Check the order of the vertices to determine if it's a front or back face - // NOTE: if signedArea is equal to 0, the face is degenerate - float signedArea = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y); - bool isBackFace = (signedArea > 0); - - // Barycentric interpolation setup - // Calculate the step increments for the barycentric coordinates - int w1XStep = (int)(v3.y - v2.y), w1YStep = (int)(v2.x - v3.x); - int w2XStep = (int)(v1.y - v3.y), w2YStep = (int)(v3.x - v1.x); - int w3XStep = (int)(v2.y - v1.y), w3YStep = (int)(v1.x - v2.x); - - // If the triangle is a back face, invert the steps - if (isBackFace) - { - w1XStep = -w1XStep, w1YStep = -w1YStep; - w2XStep = -w2XStep, w2YStep = -w2YStep; - w3XStep = -w3XStep, w3YStep = -w3YStep; - } - - // Calculate the initial barycentric coordinates for the top-left point of the bounding box - int w1Row = (int)((xMin - v2.x)*w1XStep + w1YStep*(yMin - v2.y)); - int w2Row = (int)((xMin - v3.x)*w2XStep + w2YStep*(yMin - v3.y)); - int w3Row = (int)((xMin - v1.x)*w3XStep + w3YStep*(yMin - v1.y)); - - // Calculate the inverse of the sum of the barycentric coordinates for normalization - // NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional - // calculations in the loop. This is acceptable because we are only interpolating colors - // NOTE 2: This sum remains constant throughout the triangle - float wInvSum = 255.0f/(w1Row + w2Row + w3Row); - - // Rasterization loop - // Iterate through each pixel in the bounding box - for (int y = yMin; y <= yMax; y++) - { - int w1 = w1Row; - int w2 = w2Row; - int w3 = w3Row; - - for (int x = xMin; x <= xMax; x++) - { - // Check if the pixel is inside the triangle using barycentric coordinates - if ((w1 | w2 | w3) >= 0) - { - // Compute the normalized barycentric coordinates - unsigned char aW1 = (unsigned char)((float)w1*wInvSum); - unsigned char aW2 = (unsigned char)((float)w2*wInvSum); - unsigned char aW3 = (unsigned char)((float)w3*wInvSum); - - // Interpolate the color using the barycentric coordinates - Color finalColor = { 0 }; - finalColor.r = (c1.r*aW1 + c2.r*aW2 + c3.r*aW3)/255; - finalColor.g = (c1.g*aW1 + c2.g*aW2 + c3.g*aW3)/255; - finalColor.b = (c1.b*aW1 + c2.b*aW2 + c3.b*aW3)/255; - finalColor.a = (c1.a*aW1 + c2.a*aW2 + c3.a*aW3)/255; - - // Draw the pixel with the interpolated color - ImageDrawPixel(dst, x, y, finalColor); - } - - // Increment the barycentric coordinates for the next pixel - w1 += w1XStep; - w2 += w2XStep; - w3 += w3XStep; - } - - // Move to the next row in the bounding box - w1Row += w1YStep; - w2Row += w2YStep; - w3Row += w3YStep; - } -} - -// Draw triangle outline within an image -void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color) -{ - ImageDrawLine(dst, (int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, color); - ImageDrawLine(dst, (int)v2.x, (int)v2.y, (int)v3.x, (int)v3.y, color); - ImageDrawLine(dst, (int)v3.x, (int)v3.y, (int)v1.x, (int)v1.y, color); -} - -// Draw a triangle fan defined by points within an image (first vertex is the center) -void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color) -{ - if (pointCount >= 3) - { - for (int i = 1; i < pointCount - 1; i++) - { - ImageDrawTriangle(dst, points[0], points[i], points[i + 1], color); - } - } -} - -// Draw a triangle strip defined by points within an image -void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color) -{ - if (pointCount >= 3) - { - for (int i = 2; i < pointCount; i++) - { - if ((i%2) == 0) ImageDrawTriangle(dst, points[i], points[i - 2], points[i - 1], color); - else ImageDrawTriangle(dst, points[i], points[i - 1], points[i - 2], color); - } - } -} - // Draw an image (source) within an image (destination) // NOTE: Color tint is applied to source image void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint) @@ -3923,6 +2583,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0) || (src.data == NULL) || (src.width == 0) || (src.height == 0)) return; + if (dst->mipmaps > 1) TRACELOG(LOG_WARNING, "Image drawing only applied to base mipmap level"); if (dst->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image drawing not supported for compressed formats"); else { @@ -3937,7 +2598,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y; // Check if source rectangle needs to be resized to destination rectangle - // In that case, we make a copy of source, and we apply all required transform + // In that case, we make a copy of source and we apply all required transform if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height)) { srcMod = ImageFromImage(src, srcRec); // Create image from another image @@ -3951,7 +2612,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color // Destination rectangle out-of-bounds security checks if (dstRec.x < 0) { - srcRec.x -= dstRec.x; + srcRec.x = -dstRec.x; srcRec.width += dstRec.x; dstRec.x = 0; } @@ -3959,7 +2620,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color if (dstRec.y < 0) { - srcRec.y -= dstRec.y; + srcRec.y = -dstRec.y; srcRec.height += dstRec.y; dstRec.y = 0; } @@ -3977,24 +2638,13 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color // [x] Optimize ColorAlphaBlend() for faster operations (maybe avoiding divs?) // [x] Consider fast path: no alpha blending required cases (src has no alpha) // [x] Consider fast path: same src/dst format with no alpha -> direct line copy - // [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend() - // [ ] Support f32bit channels drawing - - // TODO: Support PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 and PIXELFORMAT_UNCOMPRESSED_R1616B16A16 + // [-] GetPixelColor(): Return Vector4 instead of Color, easier for ColorAlphaBlend() Color colSrc, colDst, blend; bool blendRequired = true; // Fast path: Avoid blend if source has no alpha to blend - if ((tint.a == 255) && - ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || - (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) || - (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || - (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32) || - (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) || - (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16) || - (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16G16B16))) - blendRequired = false; + if ((tint.a == 255) && ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5))) blendRequired = false; int strideDst = GetPixelDataSize(dst->width, 1, dst->format); int bytesPerPixelDst = strideDst/(dst->width); @@ -4035,50 +2685,16 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color } if (useSrcMod) UnloadImage(srcMod); // Unload source modified image - - if ((dst->mipmaps > 1) && (src.mipmaps > 1)) - { - Image mipmapDst = *dst; - mipmapDst.data = (char *)mipmapDst.data + GetPixelDataSize(mipmapDst.width, mipmapDst.height, mipmapDst.format); - mipmapDst.width /= 2; - mipmapDst.height /= 2; - mipmapDst.mipmaps--; - - Image mipmapSrc = src; - mipmapSrc.data = (char *)mipmapSrc.data + GetPixelDataSize(mipmapSrc.width, mipmapSrc.height, mipmapSrc.format); - mipmapSrc.width /= 2; - mipmapSrc.height /= 2; - mipmapSrc.mipmaps--; - - Rectangle mipmapSrcRec = srcRec; - mipmapSrcRec.width /= 2; - mipmapSrcRec.height /= 2; - mipmapSrcRec.x /= 2; - mipmapSrcRec.y /= 2; - - Rectangle mipmapDstRec = dstRec; - mipmapDstRec.width /= 2; - mipmapDstRec.height /= 2; - mipmapDstRec.x /= 2; - mipmapDstRec.y /= 2; - - ImageDraw(&mipmapDst, mipmapSrc, mipmapSrcRec, mipmapDstRec, tint); - } } } // Draw text (default font) within an image (destination) void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color) { -#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT) - // Make sure default font is loaded to be used on image text drawing - if (GetFontDefault().texture.id == 0) LoadFontDefault(); - Vector2 position = { (float)posX, (float)posY }; - ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, 1.0f, color); // WARNING: Module required: rtext -#else - TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext"); -#endif + + // NOTE: For default font, sapcing is set to desired font size / default font size (10) + ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, (float)fontSize/10, color); } // Draw text (custom sprite font) within an image (destination) @@ -4119,7 +2735,7 @@ Texture2D LoadTextureFromImage(Image image) { Texture2D texture = { 0 }; - if ((image.width != 0) && (image.height != 0)) + if ((image.data != NULL) && (image.width != 0) && (image.height != 0)) { texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps); } @@ -4145,42 +2761,35 @@ TextureCubemap LoadTextureCubemap(Image image, int layout) { if ((image.width/6) == image.height) { layout = CUBEMAP_LAYOUT_LINE_HORIZONTAL; cubemap.width = image.width/6; } else if ((image.width/4) == (image.height/3)) { layout = CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; } + else if (image.width >= (int)((float)image.height*1.85f)) { layout = CUBEMAP_LAYOUT_PANORAMA; cubemap.width = image.width/4; } } else if (image.height > image.width) { if ((image.height/6) == image.width) { layout = CUBEMAP_LAYOUT_LINE_VERTICAL; cubemap.width = image.height/6; } else if ((image.width/3) == (image.height/4)) { layout = CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; } } - } - else - { - if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL) cubemap.width = image.height/6; - if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) cubemap.width = image.width/6; - if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR) cubemap.width = image.width/3; - if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE) cubemap.width = image.width/4; + + cubemap.height = cubemap.width; } - cubemap.height = cubemap.width; - - // Layout provided or already auto-detected if (layout != CUBEMAP_LAYOUT_AUTO_DETECT) { int size = cubemap.width; Image faces = { 0 }; // Vertical column image Rectangle faceRecs[6] = { 0 }; // Face source rectangles - for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, (float)size, (float)size }; if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL) { - faces = ImageCopy(image); // Image data already follows expected convention + faces = image; + for (int i = 0; i < 6; i++) faceRecs[i].y = (float)size*i; } - /*else if (layout == CUBEMAP_LAYOUT_PANORAMA) + else if (layout == CUBEMAP_LAYOUT_PANORAMA) { - // TODO: implement panorama by converting image to square faces... + // TODO: Convert panorama image to square faces... // Ref: https://github.com/denivip/panorama/blob/master/panorama.cpp - } */ + } else { if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = (float)size*i; @@ -4207,32 +2816,13 @@ TextureCubemap LoadTextureCubemap(Image image, int layout) faces = GenImageColor(size, size*6, MAGENTA); ImageFormat(&faces, image.format); - Image mipmapped = ImageCopy(image); - #if defined(SUPPORT_IMAGE_MANIPULATION) - if (image.mipmaps > 1) - { - ImageMipmaps(&mipmapped); - ImageMipmaps(&faces); - } - #endif - - // NOTE: Image formatting does not work with compressed textures - - for (int i = 0; i < 6; i++) ImageDraw(&faces, mipmapped, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE); - - UnloadImage(mipmapped); + // TODO: Image formating does not work with compressed textures! } - // NOTE: Cubemap data is expected to be provided as 6 images in a single data array, - // one after the other (that's a vertical image), following convention: +X, -X, +Y, -Y, +Z, -Z - cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format, faces.mipmaps); + for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE); - if (cubemap.id != 0) - { - cubemap.format = faces.format; - cubemap.mipmaps = faces.mipmaps; - } - else TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image"); + cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format); + if (cubemap.id == 0) TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image"); UnloadImage(faces); } @@ -4247,7 +2837,7 @@ RenderTexture2D LoadRenderTexture(int width, int height) { RenderTexture2D target = { 0 }; - target.id = rlLoadFramebuffer(); // Load an empty framebuffer + target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer if (target.id > 0) { @@ -4281,22 +2871,6 @@ RenderTexture2D LoadRenderTexture(int width, int height) return target; } -// Check if a texture is valid (loaded in GPU) -bool IsTextureValid(Texture2D texture) -{ - bool result = false; - - // TODO: Validate maximum texture size supported by GPU - - if ((texture.id > 0) && // Validate OpenGL id (texture uplaoded to GPU) - (texture.width > 0) && // Validate texture width - (texture.height > 0) && // Validate texture height - (texture.format > 0) && // Validate texture pixel format - (texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level) - - return result; -} - // Unload texture from GPU memory (VRAM) void UnloadTexture(Texture2D texture) { @@ -4308,28 +2882,13 @@ void UnloadTexture(Texture2D texture) } } -// Check if a render texture is valid (loaded in GPU) -bool IsRenderTextureValid(RenderTexture2D target) -{ - bool result = false; - - if ((target.id > 0) && // Validate OpenGL id (loaded on GPU) - IsTextureValid(target.depth) && // Validate FBO depth texture/renderbuffer attachment - IsTextureValid(target.texture)) result = true; // Validate FBO texture attachment - - return result; -} - // Unload render texture from GPU memory (VRAM) void UnloadRenderTexture(RenderTexture2D target) { if (target.id > 0) { - if (target.texture.id > 0) - { - // Color texture attached to FBO is deleted - rlUnloadTexture(target.texture.id); - } + // Color texture attached to FBO is deleted + rlUnloadTexture(target.texture.id); // NOTE: Depth texture/renderbuffer is automatically // queried and deleted before deleting framebuffer @@ -4351,6 +2910,52 @@ void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels) rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels); } +// Get pixel data from GPU texture and return an Image +// NOTE: Compressed texture formats not supported +Image GetTextureData(Texture2D texture) +{ + Image image = { 0 }; + + if (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB) + { + image.data = rlReadTexturePixels(texture); + + if (image.data != NULL) + { + image.width = texture.width; + image.height = texture.height; + image.format = texture.format; + image.mipmaps = 1; + +#if defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA, + // coming from FBO color buffer attachment, but it seems + // original texture format is retrieved on RPI... + image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; +#endif + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Pixel data retrieved successfully", texture.id); + } + else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve pixel data", texture.id); + } + else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve compressed pixel data", texture.id); + + return image; +} + +// Get pixel data from GPU frontbuffer and return an Image (screenshot) +Image GetScreenData(void) +{ + Image image = { 0 }; + + image.width = GetScreenWidth(); + image.height = GetScreenHeight(); + image.mipmaps = 1; + image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + image.data = rlReadScreenPixels(image.width, image.height); + + return image; +} + //------------------------------------------------------------------------------------ // Texture configuration functions //------------------------------------------------------------------------------------ @@ -4359,7 +2964,7 @@ void GenTextureMipmaps(Texture2D *texture) { // NOTE: NPOT textures support check inside function // On WebGL (OpenGL ES 2.0) NPOT textures support is limited - rlGenTextureMipmaps(texture->id, texture->width, texture->height, texture->format, &texture->mipmaps); + rlGenerateMipmaps(texture); } // Set texture scaling filter mode @@ -4435,7 +3040,6 @@ void SetTextureWrap(Texture2D texture, int wrap) { case TEXTURE_WRAP_REPEAT: { - // NOTE: It only works if NPOT textures are supported, i.e. OpenGL ES 2.0 could not support it rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_REPEAT); rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_REPEAT); } break; @@ -4461,19 +3065,19 @@ void SetTextureWrap(Texture2D texture, int wrap) //------------------------------------------------------------------------------------ // Texture drawing functions //------------------------------------------------------------------------------------ -// Draw a texture +// Draw a Texture2D void DrawTexture(Texture2D texture, int posX, int posY, Color tint) { DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY }, 0.0f, 1.0f, tint); } -// Draw a texture with position defined as Vector2 +// Draw a Texture2D with position defined as Vector2 void DrawTextureV(Texture2D texture, Vector2 position, Color tint) { DrawTextureEx(texture, position, 0, 1.0f, tint); } -// Draw a texture with extended parameters +// Draw a Texture2D with extended parameters void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) { Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height }; @@ -4492,6 +3096,101 @@ void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color DrawTexturePro(texture, source, dest, origin, 0.0f, tint); } +// Draw texture quad with tiling and offset parameters +// NOTE: Tiling and offset should be provided considering normalized texture values [0..1] +// i.e tiling = { 1.0f, 1.0f } refers to all texture, offset = { 0.5f, 0.5f } moves texture origin to center +void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint) +{ + Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height }; + Vector2 origin = { 0.0f, 0.0f }; + + DrawTexturePro(texture, source, quad, origin, 0.0f, tint); +} + +// Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. +// NOTE: For tilling a whole texture DrawTextureQuad() is better +void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint) +{ + if ((texture.id <= 0) || (scale <= 0.0f)) return; // Wanna see a infinite loop?!...just delete this line! + + int tileWidth = (int)(source.width*scale), tileHeight = (int)(source.height*scale); + if ((dest.width < tileWidth) && (dest.height < tileHeight)) + { + // Can fit only one tile + DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height}, + (Rectangle){dest.x, dest.y, dest.width, dest.height}, origin, rotation, tint); + } + else if (dest.width <= tileWidth) + { + // Tiled vertically (one column) + int dy = 0; + for (;dy+tileHeight < dest.height; dy += tileHeight) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, source.height}, (Rectangle){dest.x, dest.y + dy, dest.width, (float)tileHeight}, origin, rotation, tint); + } + + // Fit last tile + if (dy < dest.height) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height}, + (Rectangle){dest.x, dest.y + dy, dest.width, dest.height - dy}, origin, rotation, tint); + } + } + else if (dest.height <= tileHeight) + { + // Tiled horizontally (one row) + int dx = 0; + for (;dx+tileWidth < dest.width; dx += tileWidth) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, source.width, ((float)dest.height/tileHeight)*source.height}, (Rectangle){dest.x + dx, dest.y, (float)tileWidth, dest.height}, origin, rotation, tint); + } + + // Fit last tile + if (dx < dest.width) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height}, + (Rectangle){dest.x + dx, dest.y, dest.width - dx, dest.height}, origin, rotation, tint); + } + } + else + { + // Tiled both horizontally and vertically (rows and columns) + int dx = 0; + for (;dx+tileWidth < dest.width; dx += tileWidth) + { + int dy = 0; + for (;dy+tileHeight < dest.height; dy += tileHeight) + { + DrawTexturePro(texture, source, (Rectangle){dest.x + dx, dest.y + dy, (float)tileWidth, (float)tileHeight}, origin, rotation, tint); + } + + if (dy < dest.height) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, source.width, ((float)(dest.height - dy)/tileHeight)*source.height}, + (Rectangle){dest.x + dx, dest.y + dy, (float)tileWidth, dest.height - dy}, origin, rotation, tint); + } + } + + // Fit last column of tiles + if (dx < dest.width) + { + int dy = 0; + for (;dy+tileHeight < dest.height; dy += tileHeight) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, source.height}, + (Rectangle){dest.x + dx, dest.y + dy, dest.width - dx, (float)tileHeight}, origin, rotation, tint); + } + + // Draw final tile in the bottom right corner + if (dy < dest.height) + { + DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height}, + (Rectangle){dest.x + dx, dest.y + dy, dest.width - dx, dest.height - dy}, origin, rotation, tint); + } + } + } +} + // Draw a part of a texture (defined by a rectangle) with 'pro' parameters // NOTE: origin is relative to destination rectangle size void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint) @@ -4507,9 +3206,6 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 if (source.width < 0) { flipX = true; source.width *= -1; } if (source.height < 0) source.y -= source.height; - if (dest.width < 0) dest.width *= -1; - if (dest.height < 0) dest.height *= -1; - Vector2 topLeft = { 0 }; Vector2 topRight = { 0 }; Vector2 bottomLeft = { 0 }; @@ -4547,6 +3243,8 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 bottomRight.y = y + (dx + dest.width)*sinRotation + (dy + dest.height)*cosRotation; } + rlCheckRenderBatchLimit(4); // Make sure there is enough free space on the batch buffer + rlSetTexture(texture.id); rlBegin(RL_QUADS); @@ -4578,8 +3276,8 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 // NOTE: Vertex position can be transformed using matrices // but the process is way more costly than just calculating - // the vertex positions manually, like done above - // I leave here the old implementation for educational purposes, + // the vertex positions manually, like done above. + // I leave here the old implementation for educational pourposes, // just in case someone wants to do some performance test /* rlSetTexture(texture.id); @@ -4626,8 +3324,8 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, float width = (float)texture.width; float height = (float)texture.height; - float patchWidth = ((int)dest.width <= 0)? 0.0f : dest.width; - float patchHeight = ((int)dest.height <= 0)? 0.0f : dest.height; + float patchWidth = (dest.width <= 0.0f)? 0.0f : dest.width; + float patchHeight = (dest.height <= 0.0f)? 0.0f : dest.height; if (nPatchInfo.source.width < 0) nPatchInfo.source.x -= nPatchInfo.source.width; if (nPatchInfo.source.height < 0) nPatchInfo.source.y -= nPatchInfo.source.height; @@ -4641,15 +3339,14 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, float rightBorder = (float)nPatchInfo.right; float bottomBorder = (float)nPatchInfo.bottom; - // Adjust the lateral (left and right) border widths in case patchWidth < texture.width + // adjust the lateral (left and right) border widths in case patchWidth < texture.width if (patchWidth <= (leftBorder + rightBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_VERTICAL) { drawCenter = false; leftBorder = (leftBorder/(leftBorder + rightBorder))*patchWidth; rightBorder = patchWidth - leftBorder; } - - // Adjust the lateral (top and bottom) border heights in case patchHeight < texture.height + // adjust the lateral (top and bottom) border heights in case patchHeight < texture.height if (patchHeight <= (topBorder + bottomBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_HORIZONTAL) { drawMiddle = false; @@ -4815,43 +3512,55 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, } } -// Check if two colors are equal -bool ColorIsEqual(Color col1, Color col2) +// Draw textured polygon, defined by vertex and texturecoordinates +// NOTE: Polygon center must have straight line path to all points +// without crossing perimeter, points must be in anticlockwise order +void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointsCount, Color tint) { - bool result = false; + rlCheckRenderBatchLimit((pointsCount - 1)*4); - if ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)) result = true; + rlSetTexture(texture.id); - return result; + // Texturing is only supported on QUADs + rlBegin(RL_QUADS); + + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + + for (int i = 0; i < pointsCount - 1; i++) + { + rlTexCoord2f(0.5f, 0.5f); + rlVertex2f(center.x, center.y); + + rlTexCoord2f(texcoords[i].x, texcoords[i].y); + rlVertex2f(points[i].x + center.x, points[i].y + center.y); + + rlTexCoord2f(texcoords[i + 1].x, texcoords[i + 1].y); + rlVertex2f(points[i + 1].x + center.x, points[i + 1].y + center.y); + + rlTexCoord2f(texcoords[i + 1].x, texcoords[i + 1].y); + rlVertex2f(points[i + 1].x + center.x, points[i + 1].y + center.y); + } + rlEnd(); + + rlSetTexture(0); } -// Get color with alpha applied, alpha goes from 0.0f to 1.0f +// Returns color with alpha applied, alpha goes from 0.0f to 1.0f Color Fade(Color color, float alpha) { - Color result = color; - if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; - result.a = (unsigned char)(255.0f*alpha); - - return result; + return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)}; } -// Get hexadecimal value for a Color +// Returns hexadecimal value for a Color int ColorToInt(Color color) { - int result = 0; - - result = (int)(((unsigned int)color.r << 24) | - ((unsigned int)color.g << 16) | - ((unsigned int)color.b << 8) | - (unsigned int)color.a); - - return result; + return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); } -// Get color normalized as float [0..1] +// Returns color normalized as float [0..1] Vector4 ColorNormalize(Color color) { Vector4 result; @@ -4864,7 +3573,7 @@ Vector4 ColorNormalize(Color color) return result; } -// Get color from normalized values [0..1] +// Returns color from normalized values [0..1] Color ColorFromNormalized(Vector4 normalized) { Color result; @@ -4877,7 +3586,7 @@ Color ColorFromNormalized(Vector4 normalized) return result; } -// Get HSV values for a Color +// Returns HSV values for a Color // NOTE: Hue is returned as degrees [0..360] Vector3 ColorToHSV(Color color) { @@ -4929,7 +3638,7 @@ Vector3 ColorToHSV(Color color) return hsv; } -// Get a Color from HSV values +// Returns a Color from HSV values // Implementation reference: https://en.wikipedia.org/wiki/HSL_and_HSV#Alternative_HSV_conversion // NOTE: Color->HSV->Color conversion will not yield exactly the same color due to rounding errors // Hue is provided in degrees: [0..360] @@ -4965,123 +3674,25 @@ Color ColorFromHSV(float hue, float saturation, float value) return color; } -// Get color multiplied with another color -Color ColorTint(Color color, Color tint) -{ - Color result = color; - - unsigned char r = (unsigned char)(((int)color.r*(int)tint.r)/255); - unsigned char g = (unsigned char)(((int)color.g*(int)tint.g)/255); - unsigned char b = (unsigned char)(((int)color.b*(int)tint.b)/255); - unsigned char a = (unsigned char)(((int)color.a*(int)tint.a)/255); - - result.r = r; - result.g = g; - result.b = b; - result.a = a; - - return result; -} - -// Get color with brightness correction, brightness factor goes from -1.0f to 1.0f -Color ColorBrightness(Color color, float factor) -{ - Color result = color; - - if (factor > 1.0f) factor = 1.0f; - else if (factor < -1.0f) factor = -1.0f; - - float red = (float)color.r; - float green = (float)color.g; - float blue = (float)color.b; - - if (factor < 0.0f) - { - factor = 1.0f + factor; - red *= factor; - green *= factor; - blue *= factor; - } - else - { - red = (255 - red)*factor + red; - green = (255 - green)*factor + green; - blue = (255 - blue)*factor + blue; - } - - result.r = (unsigned char)red; - result.g = (unsigned char)green; - result.b = (unsigned char)blue; - - return result; -} - -// Get color with contrast correction -// NOTE: Contrast values between -1.0f and 1.0f -Color ColorContrast(Color color, float contrast) -{ - Color result = color; - - if (contrast < -1.0f) contrast = -1.0f; - else if (contrast > 1.0f) contrast = 1.0f; - - contrast = (1.0f + contrast); - contrast *= contrast; - - float pR = (float)color.r/255.0f; - pR -= 0.5f; - pR *= contrast; - pR += 0.5f; - pR *= 255; - if (pR < 0) pR = 0; - else if (pR > 255) pR = 255; - - float pG = (float)color.g/255.0f; - pG -= 0.5f; - pG *= contrast; - pG += 0.5f; - pG *= 255; - if (pG < 0) pG = 0; - else if (pG > 255) pG = 255; - - float pB = (float)color.b/255.0f; - pB -= 0.5f; - pB *= contrast; - pB += 0.5f; - pB *= 255; - if (pB < 0) pB = 0; - else if (pB > 255) pB = 255; - - result.r = (unsigned char)pR; - result.g = (unsigned char)pG; - result.b = (unsigned char)pB; - - return result; -} - -// Get color with alpha applied, alpha goes from 0.0f to 1.0f +// Returns color with alpha applied, alpha goes from 0.0f to 1.0f Color ColorAlpha(Color color, float alpha) { - Color result = color; - if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; - result.a = (unsigned char)(255.0f*alpha); - - return result; + return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)}; } -// Get src alpha-blended into dst color with tint +// Returns src alpha-blended into dst color with tint Color ColorAlphaBlend(Color dst, Color src, Color tint) { Color out = WHITE; // Apply color tint to source color - src.r = (unsigned char)(((unsigned int)src.r*((unsigned int)tint.r+1)) >> 8); - src.g = (unsigned char)(((unsigned int)src.g*((unsigned int)tint.g+1)) >> 8); - src.b = (unsigned char)(((unsigned int)src.b*((unsigned int)tint.b+1)) >> 8); - src.a = (unsigned char)(((unsigned int)src.a*((unsigned int)tint.a+1)) >> 8); + src.r = (unsigned char)(((unsigned int)src.r*(unsigned int)tint.r) >> 8); + src.g = (unsigned char)(((unsigned int)src.g*(unsigned int)tint.g) >> 8); + src.b = (unsigned char)(((unsigned int)src.b*(unsigned int)tint.b) >> 8); + src.a = (unsigned char)(((unsigned int)src.a*(unsigned int)tint.a) >> 8); //#define COLORALPHABLEND_FLOAT #define COLORALPHABLEND_INTEGERS @@ -5127,31 +3738,15 @@ Color ColorAlphaBlend(Color dst, Color src, Color tint) return out; } -// Get color lerp interpolation between two colors, factor [0.0f..1.0f] -Color ColorLerp(Color color1, Color color2, float factor) -{ - Color color = { 0 }; - - if (factor < 0.0f) factor = 0.0f; - else if (factor > 1.0f) factor = 1.0f; - - color.r = (unsigned char)((1.0f - factor)*color1.r + factor*color2.r); - color.g = (unsigned char)((1.0f - factor)*color1.g + factor*color2.g); - color.b = (unsigned char)((1.0f - factor)*color1.b + factor*color2.b); - color.a = (unsigned char)((1.0f - factor)*color1.a + factor*color2.a); - - return color; -} - -// Get a Color struct from hexadecimal value -Color GetColor(unsigned int hexValue) +// Returns a Color struct from hexadecimal value +Color GetColor(int hexValue) { Color color; - color.r = (unsigned char)(hexValue >> 24) & 0xff; - color.g = (unsigned char)(hexValue >> 16) & 0xff; - color.b = (unsigned char)(hexValue >> 8) & 0xff; - color.a = (unsigned char)hexValue & 0xff; + color.r = (unsigned char)(hexValue >> 24) & 0xFF; + color.g = (unsigned char)(hexValue >> 16) & 0xFF; + color.b = (unsigned char)(hexValue >> 8) & 0xFF; + color.a = (unsigned char)hexValue & 0xFF; return color; } @@ -5159,96 +3754,45 @@ Color GetColor(unsigned int hexValue) // Get color from a pixel from certain format Color GetPixelColor(void *srcPtr, int format) { - Color color = { 0 }; + Color col = { 0 }; switch (format) { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], 255 }; break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1] }; break; + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], 255 }; break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1] }; break; case PIXELFORMAT_UNCOMPRESSED_R5G6B5: { - color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31); - color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 5) & 0b0000000000111111)*255/63); - color.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31); - color.a = 255; + col.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31); + col.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 5) & 0b0000000000111111)*255/63); + col.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31); + col.a = 255; } break; case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: { - color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31); - color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 6) & 0b0000000000011111)*255/31); - color.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31); - color.a = (((unsigned short *)srcPtr)[0] & 0b0000000000000001)? 255 : 0; + col.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31); + col.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 6) & 0b0000000000011111)*255/31); + col.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31); + col.a = (((unsigned short *)srcPtr)[0] & 0b0000000000000001)? 255 : 0; } break; case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: { - color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 12)*255/15); - color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 8) & 0b0000000000001111)*255/15); - color.b = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 4) & 0b0000000000001111)*255/15); - color.a = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000001111)*255/15); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], ((unsigned char *)srcPtr)[3] }; break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], 255 }; break; - case PIXELFORMAT_UNCOMPRESSED_R32: - { - // NOTE: Pixel normalized float value is converted to [0..255] - color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f); - color.g = (unsigned char)(((float *)srcPtr)[0]*255.0f); - color.b = (unsigned char)(((float *)srcPtr)[0]*255.0f); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: - { - // NOTE: Pixel normalized float value is converted to [0..255] - color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f); - color.g = (unsigned char)(((float *)srcPtr)[1]*255.0f); - color.b = (unsigned char)(((float *)srcPtr)[2]*255.0f); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - { - // NOTE: Pixel normalized float value is converted to [0..255] - color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f); - color.g = (unsigned char)(((float *)srcPtr)[1]*255.0f); - color.b = (unsigned char)(((float *)srcPtr)[2]*255.0f); - color.a = (unsigned char)(((float *)srcPtr)[3]*255.0f); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - // NOTE: Pixel normalized float value is converted to [0..255] - color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f); - color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f); - color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - // NOTE: Pixel normalized float value is converted to [0..255] - color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f); - color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[1])*255.0f); - color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[2])*255.0f); - color.a = 255; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - // NOTE: Pixel normalized float value is converted to [0..255] - color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f); - color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[1])*255.0f); - color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[2])*255.0f); - color.a = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[3])*255.0f); + col.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 12)*255/15); + col.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 8) & 0b0000000000001111)*255/15); + col.b = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 4) & 0b0000000000001111)*255/15); + col.a = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000001111)*255/15); } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], ((unsigned char *)srcPtr)[3] }; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], 255 }; break; + // TODO: case PIXELFORMAT_UNCOMPRESSED_R32: break; + // TODO: case PIXELFORMAT_UNCOMPRESSED_R32G32B32: break; + // TODO: case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: break; default: break; } - return color; + return col; } // Set pixel color formatted into destination pointer @@ -5295,7 +3839,7 @@ void SetPixelColor(void *dstPtr, Color color, int format) unsigned char r = (unsigned char)(round(coln.x*31.0f)); unsigned char g = (unsigned char)(round(coln.y*31.0f)); unsigned char b = (unsigned char)(round(coln.z*31.0f)); - unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0; + unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;; ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; @@ -5351,9 +3895,6 @@ int GetPixelDataSize(int width, int height, int format) case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; - case PIXELFORMAT_UNCOMPRESSED_R16: bpp = 16; break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 16*3; break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 16*4; break; case PIXELFORMAT_COMPRESSED_DXT1_RGB: case PIXELFORMAT_COMPRESSED_DXT1_RGBA: case PIXELFORMAT_COMPRESSED_ETC1_RGB: @@ -5368,8 +3909,7 @@ int GetPixelDataSize(int width, int height, int format) default: break; } - double bytesPerPixel = (double)bpp/8.0; - dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes + dataSize = width*height*bpp/8; // Total data size in bytes // Most compressed formats works on 4x4 blocks, // if texture is smaller, minimum dataSize is 8 or 16 @@ -5385,185 +3925,670 @@ int GetPixelDataSize(int width, int height, int format) //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Convert half-float (stored as unsigned short) to float -// REF: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308 -static float HalfToFloat(unsigned short x) +#if defined(SUPPORT_FILEFORMAT_DDS) +// Loading DDS image data (compressed or uncompressed) +static Image LoadDDS(const unsigned char *fileData, unsigned int fileSize) { - float result = 0.0f; + unsigned char *fileDataPtr = (unsigned char *)fileData; - union { - float fm; - unsigned int ui; - } uni; + // Required extension: + // GL_EXT_texture_compression_s3tc - const unsigned int e = (x & 0x7c00) >> 10; // Exponent - const unsigned int m = (x & 0x03cc) << 13; // Mantissa - uni.fm = (float)m; - const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format - uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized + // Supported tokens (defined by extensions) + // GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 + // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 + // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 + // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 - result = uni.fm; + #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII + #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII + #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII - return result; -} + // DDS Pixel Format + typedef struct { + unsigned int size; + unsigned int flags; + unsigned int fourCC; + unsigned int rgbBitCount; + unsigned int rBitMask; + unsigned int gBitMask; + unsigned int bBitMask; + unsigned int aBitMask; + } DDSPixelFormat; -// Convert float to half-float (stored as unsigned short) -static unsigned short FloatToHalf(float x) -{ - unsigned short result = 0; + // DDS Header (124 bytes) + typedef struct { + unsigned int size; + unsigned int flags; + unsigned int height; + unsigned int width; + unsigned int pitchOrLinearSize; + unsigned int depth; + unsigned int mipmapCount; + unsigned int reserved1[11]; + DDSPixelFormat ddspf; + unsigned int caps; + unsigned int caps2; + unsigned int caps3; + unsigned int caps4; + unsigned int reserved2; + } DDSHeader; - union { - float fm; - unsigned int ui; - } uni; - uni.fm = x; + Image image = { 0 }; - const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa - const unsigned int e = (b & 0x7f800000) >> 23; // Exponent - const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding - - result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate - - return result; -} - -// Get pixel data from image as Vector4 array (float normalized) -static Vector4 *LoadImageDataNormalized(Image image) -{ - Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4)); - - if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats"); - else + if (fileDataPtr != NULL) { - for (int i = 0, k = 0; i < image.width*image.height; i++) + // Verify the type of file + unsigned char *ddsHeaderId = fileDataPtr; + fileDataPtr += 4; + + if ((ddsHeaderId[0] != 'D') || (ddsHeaderId[1] != 'D') || (ddsHeaderId[2] != 'S') || (ddsHeaderId[3] != ' ')) { - switch (image.format) + TRACELOG(LOG_WARNING, "IMAGE: DDS file data not valid"); + } + else + { + DDSHeader *ddsHeader = (DDSHeader *)fileDataPtr; + + TRACELOGD("IMAGE: DDS file data info:"); + TRACELOGD(" > Header size: %i", sizeof(DDSHeader)); + TRACELOGD(" > Pixel format size: %i", ddsHeader->ddspf.size); + TRACELOGD(" > Pixel format flags: 0x%x", ddsHeader->ddspf.flags); + TRACELOGD(" > File format: 0x%x", ddsHeader->ddspf.fourCC); + TRACELOGD(" > File bit count: 0x%x", ddsHeader->ddspf.rgbBitCount); + + fileDataPtr += sizeof(DDSHeader); // Skip header + + image.width = ddsHeader->width; + image.height = ddsHeader->height; + + if (ddsHeader->mipmapCount == 0) image.mipmaps = 1; // Parameter not used + else image.mipmaps = ddsHeader->mipmapCount; + + if (ddsHeader->ddspf.rgbBitCount == 16) // 16bit mode, no compressed { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + if (ddsHeader->ddspf.flags == 0x40) // no alpha channel { - pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f; - pixels[i].w = 1.0f; + int dataSize = image.width*image.height*sizeof(unsigned short); + image.data = (unsigned short *)RL_MALLOC(dataSize); - } break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + memcpy(image.data, fileDataPtr, dataSize); + + image.format = PIXELFORMAT_UNCOMPRESSED_R5G6B5; + } + else if (ddsHeader->ddspf.flags == 0x41) // with alpha channel { - pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f; + if (ddsHeader->ddspf.aBitMask == 0x8000) // 1bit alpha + { + int dataSize = image.width*image.height*sizeof(unsigned short); + image.data = (unsigned short *)RL_MALLOC(dataSize); - k += 2; - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + memcpy(image.data, fileDataPtr, dataSize); + + unsigned char alpha = 0; + + // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1 + for (int i = 0; i < image.width*image.height; i++) + { + alpha = ((unsigned short *)image.data)[i] >> 15; + ((unsigned short *)image.data)[i] = ((unsigned short *)image.data)[i] << 1; + ((unsigned short *)image.data)[i] += alpha; + } + + image.format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; + } + else if (ddsHeader->ddspf.aBitMask == 0xf000) // 4bit alpha + { + int dataSize = image.width*image.height*sizeof(unsigned short); + image.data = (unsigned short *)RL_MALLOC(dataSize); + + memcpy(image.data, fileDataPtr, dataSize); + + unsigned char alpha = 0; + + // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4 + for (int i = 0; i < image.width*image.height; i++) + { + alpha = ((unsigned short *)image.data)[i] >> 12; + ((unsigned short *)image.data)[i] = ((unsigned short *)image.data)[i] << 4; + ((unsigned short *)image.data)[i] += alpha; + } + + image.format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; + } + } + } + else if (ddsHeader->ddspf.flags == 0x40 && ddsHeader->ddspf.rgbBitCount == 24) // DDS_RGB, no compressed + { + int dataSize = image.width*image.height*3*sizeof(unsigned char); + image.data = (unsigned short *)RL_MALLOC(dataSize); + + memcpy(image.data, fileDataPtr, dataSize); + + image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8; + } + else if (ddsHeader->ddspf.flags == 0x41 && ddsHeader->ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed + { + int dataSize = image.width*image.height*4*sizeof(unsigned char); + image.data = (unsigned short *)RL_MALLOC(dataSize); + + memcpy(image.data, fileDataPtr, dataSize); + + unsigned char blue = 0; + + // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment) + // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA + // So, we must realign B8G8R8A8 to R8G8B8A8 + for (int i = 0; i < image.width*image.height*4; i += 4) { - unsigned short pixel = ((unsigned short *)image.data)[i]; + blue = ((unsigned char *)image.data)[i]; + ((unsigned char *)image.data)[i] = ((unsigned char *)image.data)[i + 2]; + ((unsigned char *)image.data)[i + 2] = blue; + } - pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); - pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); - pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); - pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f; + image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + } + else if (((ddsHeader->ddspf.flags == 0x04) || (ddsHeader->ddspf.flags == 0x05)) && (ddsHeader->ddspf.fourCC > 0)) // Compressed + { + int dataSize = 0; - } break; - case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + // Calculate data size, including all mipmaps + if (ddsHeader->mipmapCount > 1) dataSize = ddsHeader->pitchOrLinearSize*2; + else dataSize = ddsHeader->pitchOrLinearSize; + + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); + + memcpy(image.data, fileDataPtr, dataSize); + + switch (ddsHeader->ddspf.fourCC) { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); - pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63); - pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31); - pixels[i].w = 1.0f; - - } break; - case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15); - pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15); - pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15); - pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15); - - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - { - pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; - pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f; - - k += 4; - } break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: - { - pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; - pixels[i].w = 1.0f; - - k += 3; - } break; - case PIXELFORMAT_UNCOMPRESSED_R32: - { - pixels[i].x = ((float *)image.data)[k]; - pixels[i].y = 0.0f; - pixels[i].z = 0.0f; - pixels[i].w = 1.0f; - - k += 1; - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32: - { - pixels[i].x = ((float *)image.data)[k]; - pixels[i].y = ((float *)image.data)[k + 1]; - pixels[i].z = ((float *)image.data)[k + 2]; - pixels[i].w = 1.0f; - - k += 3; - } break; - case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - { - pixels[i].x = ((float *)image.data)[k]; - pixels[i].y = ((float *)image.data)[k + 1]; - pixels[i].z = ((float *)image.data)[k + 2]; - pixels[i].w = ((float *)image.data)[k + 3]; - - k += 4; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16: - { - pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]); - pixels[i].y = 0.0f; - pixels[i].z = 0.0f; - pixels[i].w = 1.0f; - - k += 1; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]); - pixels[i].y = HalfToFloat(((unsigned short *)image.data)[k + 1]); - pixels[i].z = HalfToFloat(((unsigned short *)image.data)[k + 2]); - pixels[i].w = 1.0f; - - k += 3; - } break; - case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]); - pixels[i].y = HalfToFloat(((unsigned short *)image.data)[k + 1]); - pixels[i].z = HalfToFloat(((unsigned short *)image.data)[k + 2]); - pixels[i].w = HalfToFloat(((unsigned short *)image.data)[k + 3]); - - k += 4; - } break; - default: break; + case FOURCC_DXT1: + { + if (ddsHeader->ddspf.flags == 0x04) image.format = PIXELFORMAT_COMPRESSED_DXT1_RGB; + else image.format = PIXELFORMAT_COMPRESSED_DXT1_RGBA; + } break; + case FOURCC_DXT3: image.format = PIXELFORMAT_COMPRESSED_DXT3_RGBA; break; + case FOURCC_DXT5: image.format = PIXELFORMAT_COMPRESSED_DXT5_RGBA; break; + default: break; + } } } } - return pixels; + return image; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_PKM) +// Loading PKM image data (ETC1/ETC2 compression) +// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps) +// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps) +static Image LoadPKM(const unsigned char *fileData, unsigned int fileSize) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + + // Required extensions: + // GL_OES_compressed_ETC1_RGB8_texture (ETC1) (OpenGL ES 2.0) + // GL_ARB_ES3_compatibility (ETC2/EAC) (OpenGL ES 3.0) + + // Supported tokens (defined by extensions) + // GL_ETC1_RGB8_OES 0x8D64 + // GL_COMPRESSED_RGB8_ETC2 0x9274 + // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 + + // PKM file (ETC1) Header (16 bytes) + typedef struct { + char id[4]; // "PKM " + char version[2]; // "10" or "20" + unsigned short format; // Data format (big-endian) (Check list below) + unsigned short width; // Texture width (big-endian) (origWidth rounded to multiple of 4) + unsigned short height; // Texture height (big-endian) (origHeight rounded to multiple of 4) + unsigned short origWidth; // Original width (big-endian) + unsigned short origHeight; // Original height (big-endian) + } PKMHeader; + + // Formats list + // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used) + // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R + + // NOTE: The extended width and height are the widths rounded up to a multiple of 4. + // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels) + + Image image = { 0 }; + + if (fileDataPtr != NULL) + { + PKMHeader *pkmHeader = (PKMHeader *)fileDataPtr; + + if ((pkmHeader->id[0] != 'P') || (pkmHeader->id[1] != 'K') || (pkmHeader->id[2] != 'M') || (pkmHeader->id[3] != ' ')) + { + TRACELOG(LOG_WARNING, "IMAGE: PKM file data not valid"); + } + else + { + fileDataPtr += sizeof(PKMHeader); // Skip header + + // NOTE: format, width and height come as big-endian, data must be swapped to little-endian + pkmHeader->format = ((pkmHeader->format & 0x00FF) << 8) | ((pkmHeader->format & 0xFF00) >> 8); + pkmHeader->width = ((pkmHeader->width & 0x00FF) << 8) | ((pkmHeader->width & 0xFF00) >> 8); + pkmHeader->height = ((pkmHeader->height & 0x00FF) << 8) | ((pkmHeader->height & 0xFF00) >> 8); + + TRACELOGD("IMAGE: PKM file data info:"); + TRACELOGD(" > Image width: %i", pkmHeader->width); + TRACELOGD(" > Image height: %i", pkmHeader->height); + TRACELOGD(" > Image format: %i", pkmHeader->format); + + image.width = pkmHeader->width; + image.height = pkmHeader->height; + image.mipmaps = 1; + + int bpp = 4; + if (pkmHeader->format == 3) bpp = 8; + + int dataSize = image.width*image.height*bpp/8; // Total data size in bytes + + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); + + memcpy(image.data, fileDataPtr, dataSize); + + if (pkmHeader->format == 0) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB; + else if (pkmHeader->format == 1) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB; + else if (pkmHeader->format == 3) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; + } + } + + return image; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_KTX) +// Load KTX compressed image data (ETC1/ETC2 compression) +static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + + // Required extensions: + // GL_OES_compressed_ETC1_RGB8_texture (ETC1) + // GL_ARB_ES3_compatibility (ETC2/EAC) + + // Supported tokens (defined by extensions) + // GL_ETC1_RGB8_OES 0x8D64 + // GL_COMPRESSED_RGB8_ETC2 0x9274 + // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 + + // KTX file Header (64 bytes) + // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ + // v2.0 - http://github.khronos.org/KTX-Specification/ + + // TODO: Support KTX 2.2 specs! + + typedef struct { + char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" + unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 + unsigned int glType; // For compressed textures, glType must equal 0 + unsigned int glTypeSize; // For compressed texture data, usually 1 + unsigned int glFormat; // For compressed textures is 0 + unsigned int glInternalFormat; // Compressed internal format + unsigned int glBaseInternalFormat; // Same as glFormat (RGB, RGBA, ALPHA...) + unsigned int width; // Texture image width in pixels + unsigned int height; // Texture image height in pixels + unsigned int depth; // For 2D textures is 0 + unsigned int elements; // Number of array elements, usually 0 + unsigned int faces; // Cubemap faces, for no-cubemap = 1 + unsigned int mipmapLevels; // Non-mipmapped textures = 1 + unsigned int keyValueDataSize; // Used to encode any arbitrary data... + } KTXHeader; + + // NOTE: Before start of every mipmap data block, we have: unsigned int dataSize + + Image image = { 0 }; + + if (fileDataPtr != NULL) + { + KTXHeader *ktxHeader = (KTXHeader *)fileDataPtr; + + if ((ktxHeader->id[1] != 'K') || (ktxHeader->id[2] != 'T') || (ktxHeader->id[3] != 'X') || + (ktxHeader->id[4] != ' ') || (ktxHeader->id[5] != '1') || (ktxHeader->id[6] != '1')) + { + TRACELOG(LOG_WARNING, "IMAGE: KTX file data not valid"); + } + else + { + fileDataPtr += sizeof(KTXHeader); // Move file data pointer + + image.width = ktxHeader->width; + image.height = ktxHeader->height; + image.mipmaps = ktxHeader->mipmapLevels; + + TRACELOGD("IMAGE: KTX file data info:"); + TRACELOGD(" > Image width: %i", ktxHeader->width); + TRACELOGD(" > Image height: %i", ktxHeader->height); + TRACELOGD(" > Image format: 0x%x", ktxHeader->glInternalFormat); + + fileDataPtr += ktxHeader->keyValueDataSize; // Skip value data size + + int dataSize = ((int *)fileDataPtr)[0]; + fileDataPtr += sizeof(int); + + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); + + memcpy(image.data, fileDataPtr, dataSize); + + if (ktxHeader->glInternalFormat == 0x8D64) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB; + else if (ktxHeader->glInternalFormat == 0x9274) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB; + else if (ktxHeader->glInternalFormat == 0x9278) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; + } + } + + return image; } -#endif // SUPPORT_MODULE_RTEXTURES +// Save image data as KTX file +// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018) +static int SaveKTX(Image image, const char *fileName) +{ + // KTX file Header (64 bytes) + // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ + // v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation + typedef struct { + char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n" + unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 + unsigned int glType; // For compressed textures, glType must equal 0 + unsigned int glTypeSize; // For compressed texture data, usually 1 + unsigned int glFormat; // For compressed textures is 0 + unsigned int glInternalFormat; // Compressed internal format + unsigned int glBaseInternalFormat; // Same as glFormat (RGB, RGBA, ALPHA...) // KTX 2.0: UInt32 vkFormat + unsigned int width; // Texture image width in pixels + unsigned int height; // Texture image height in pixels + unsigned int depth; // For 2D textures is 0 + unsigned int elements; // Number of array elements, usually 0 + unsigned int faces; // Cubemap faces, for no-cubemap = 1 + unsigned int mipmapLevels; // Non-mipmapped textures = 1 + unsigned int keyValueDataSize; // Used to encode any arbitrary data... // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0 + // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)... + // KTX 2.0 defines additional header elements... + } KTXHeader; + + // Calculate file dataSize required + int dataSize = sizeof(KTXHeader); + + for (int i = 0, width = image.width, height = image.height; i < image.mipmaps; i++) + { + dataSize += GetPixelDataSize(width, height, image.format); + width /= 2; height /= 2; + } + + unsigned char *fileData = RL_CALLOC(dataSize, 1); + unsigned char *fileDataPtr = fileData; + + KTXHeader ktxHeader = { 0 }; + + // KTX identifier (v1.1) + //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; + //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; + + const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; + + // Get the image header + memcpy(ktxHeader.id, ktxIdentifier, 12); // KTX 1.1 signature + ktxHeader.endianness = 0; + ktxHeader.glType = 0; // Obtained from image.format + ktxHeader.glTypeSize = 1; + ktxHeader.glFormat = 0; // Obtained from image.format + ktxHeader.glInternalFormat = 0; // Obtained from image.format + ktxHeader.glBaseInternalFormat = 0; + ktxHeader.width = image.width; + ktxHeader.height = image.height; + ktxHeader.depth = 0; + ktxHeader.elements = 0; + ktxHeader.faces = 1; + ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats) + ktxHeader.keyValueDataSize = 0; // No extra data after the header + + rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function + ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only + + // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC + + if (ktxHeader.glFormat == -1) TRACELOG(LOG_WARNING, "IMAGE: GL format not supported for KTX export (%i)", ktxHeader.glFormat); + else + { + memcpy(fileDataPtr, &ktxHeader, sizeof(KTXHeader)); + fileDataPtr += sizeof(KTXHeader); + + int width = image.width; + int height = image.height; + int dataOffset = 0; + + // Save all mipmaps data + for (int i = 0; i < image.mipmaps; i++) + { + unsigned int dataSize = GetPixelDataSize(width, height, image.format); + + memcpy(fileDataPtr, &dataSize, sizeof(unsigned int)); + memcpy(fileDataPtr + 4, (unsigned char *)image.data + dataOffset, dataSize); + + width /= 2; + height /= 2; + dataOffset += dataSize; + fileDataPtr += (4 + dataSize); + } + } + + int success = SaveFileData(fileName, fileData, dataSize); + + RL_FREE(fileData); // Free file data buffer + + // If all data has been written correctly to file, success = 1 + return success; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_PVR) +// Loading PVR image data (uncompressed or PVRT compression) +// NOTE: PVR v2 not supported, use PVR v3 instead +static Image LoadPVR(const unsigned char *fileData, unsigned int fileSize) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + + // Required extension: + // GL_IMG_texture_compression_pvrtc + + // Supported tokens (defined by extensions) + // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 + // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 + +#if 0 // Not used... + // PVR file v2 Header (52 bytes) + typedef struct { + unsigned int headerLength; + unsigned int height; + unsigned int width; + unsigned int numMipmaps; + unsigned int flags; + unsigned int dataLength; + unsigned int bpp; + unsigned int bitmaskRed; + unsigned int bitmaskGreen; + unsigned int bitmaskBlue; + unsigned int bitmaskAlpha; + unsigned int pvrTag; + unsigned int numSurfs; + } PVRHeaderV2; +#endif + + // PVR file v3 Header (52 bytes) + // NOTE: After it could be metadata (15 bytes?) + typedef struct { + char id[4]; + unsigned int flags; + unsigned char channels[4]; // pixelFormat high part + unsigned char channelDepth[4]; // pixelFormat low part + unsigned int colourSpace; + unsigned int channelType; + unsigned int height; + unsigned int width; + unsigned int depth; + unsigned int numSurfaces; + unsigned int numFaces; + unsigned int numMipmaps; + unsigned int metaDataSize; + } PVRHeaderV3; + +#if 0 // Not used... + // Metadata (usually 15 bytes) + typedef struct { + unsigned int devFOURCC; + unsigned int key; + unsigned int dataSize; // Not used? + unsigned char *data; // Not used? + } PVRMetadata; +#endif + + Image image = { 0 }; + + if (fileDataPtr != NULL) + { + // Check PVR image version + unsigned char pvrVersion = fileDataPtr[0]; + + // Load different PVR data formats + if (pvrVersion == 0x50) + { + PVRHeaderV3 *pvrHeader = (PVRHeaderV3 *)fileDataPtr; + + if ((pvrHeader->id[0] != 'P') || (pvrHeader->id[1] != 'V') || (pvrHeader->id[2] != 'R') || (pvrHeader->id[3] != 3)) + { + TRACELOG(LOG_WARNING, "IMAGE: PVR file data not valid"); + } + else + { + fileDataPtr += sizeof(PVRHeaderV3); // Skip header + + image.width = pvrHeader->width; + image.height = pvrHeader->height; + image.mipmaps = pvrHeader->numMipmaps; + + // Check data format + if (((pvrHeader->channels[0] == 'l') && (pvrHeader->channels[1] == 0)) && (pvrHeader->channelDepth[0] == 8)) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; + else if (((pvrHeader->channels[0] == 'l') && (pvrHeader->channels[1] == 'a')) && ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8))) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; + else if ((pvrHeader->channels[0] == 'r') && (pvrHeader->channels[1] == 'g') && (pvrHeader->channels[2] == 'b')) + { + if (pvrHeader->channels[3] == 'a') + { + if ((pvrHeader->channelDepth[0] == 5) && (pvrHeader->channelDepth[1] == 5) && (pvrHeader->channelDepth[2] == 5) && (pvrHeader->channelDepth[3] == 1)) image.format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; + else if ((pvrHeader->channelDepth[0] == 4) && (pvrHeader->channelDepth[1] == 4) && (pvrHeader->channelDepth[2] == 4) && (pvrHeader->channelDepth[3] == 4)) image.format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; + else if ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8) && (pvrHeader->channelDepth[2] == 8) && (pvrHeader->channelDepth[3] == 8)) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + } + else if (pvrHeader->channels[3] == 0) + { + if ((pvrHeader->channelDepth[0] == 5) && (pvrHeader->channelDepth[1] == 6) && (pvrHeader->channelDepth[2] == 5)) image.format = PIXELFORMAT_UNCOMPRESSED_R5G6B5; + else if ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8) && (pvrHeader->channelDepth[2] == 8)) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8; + } + } + else if (pvrHeader->channels[0] == 2) image.format = PIXELFORMAT_COMPRESSED_PVRT_RGB; + else if (pvrHeader->channels[0] == 3) image.format = PIXELFORMAT_COMPRESSED_PVRT_RGBA; + + fileDataPtr += pvrHeader->metaDataSize; // Skip meta data header + + // Calculate data size (depends on format) + int bpp = 0; + switch (image.format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; + case PIXELFORMAT_COMPRESSED_PVRT_RGB: + case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; + default: break; + } + + int dataSize = image.width*image.height*bpp/8; // Total data size in bytes + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); + + memcpy(image.data, fileDataPtr, dataSize); + } + } + else if (pvrVersion == 52) TRACELOG(LOG_INFO, "IMAGE: PVRv2 format not supported, update your files to PVRv3"); + } + + return image; +} +#endif + +#if defined(SUPPORT_FILEFORMAT_ASTC) +// Load ASTC compressed image data (ASTC compression) +static Image LoadASTC(const unsigned char *fileData, unsigned int fileSize) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + + // Required extensions: + // GL_KHR_texture_compression_astc_hdr + // GL_KHR_texture_compression_astc_ldr + + // Supported tokens (defined by extensions) + // GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0 + // GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 + + // ASTC file Header (16 bytes) + typedef struct { + unsigned char id[4]; // Signature: 0x13 0xAB 0xA1 0x5C + unsigned char blockX; // Block X dimensions + unsigned char blockY; // Block Y dimensions + unsigned char blockZ; // Block Z dimensions (1 for 2D images) + unsigned char width[3]; // Image width in pixels (24bit value) + unsigned char height[3]; // Image height in pixels (24bit value) + unsigned char length[3]; // Image Z-size (1 for 2D images) + } ASTCHeader; + + Image image = { 0 }; + + if (fileDataPtr != NULL) + { + ASTCHeader *astcHeader = (ASTCHeader *)fileDataPtr; + + if ((astcHeader->id[3] != 0x5c) || (astcHeader->id[2] != 0xa1) || (astcHeader->id[1] != 0xab) || (astcHeader->id[0] != 0x13)) + { + TRACELOG(LOG_WARNING, "IMAGE: ASTC file data not valid"); + } + else + { + fileDataPtr += sizeof(ASTCHeader); // Skip header + + // NOTE: Assuming Little Endian (could it be wrong?) + image.width = 0x00000000 | ((int)astcHeader->width[2] << 16) | ((int)astcHeader->width[1] << 8) | ((int)astcHeader->width[0]); + image.height = 0x00000000 | ((int)astcHeader->height[2] << 16) | ((int)astcHeader->height[1] << 8) | ((int)astcHeader->height[0]); + + TRACELOGD("IMAGE: ASTC file data info:"); + TRACELOGD(" > Image width: %i", image.width); + TRACELOGD(" > Image height: %i", image.height); + TRACELOGD(" > Image blocks: %ix%i", astcHeader->blockX, astcHeader->blockY); + + image.mipmaps = 1; // NOTE: ASTC format only contains one mipmap level + + // NOTE: Each block is always stored in 128bit so we can calculate the bpp + int bpp = 128/(astcHeader->blockX*astcHeader->blockY); + + // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8 + if ((bpp == 8) || (bpp == 2)) + { + int dataSize = image.width*image.height*bpp/8; // Data size in bytes + + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); + + memcpy(image.data, fileDataPtr, dataSize); + + if (bpp == 8) image.format = PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA; + else if (bpp == 2) image.format = PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA; + } + else TRACELOG(LOG_WARNING, "IMAGE: ASTC block size configuration not supported"); + } + } + + return image; +} +#endif diff --git a/raylib/rtextures.go b/raylib/textures.go similarity index 51% rename from raylib/rtextures.go rename to raylib/textures.go index 6cb16ad..b1c04a6 100644 --- a/raylib/rtextures.go +++ b/raylib/textures.go @@ -8,15 +8,9 @@ import "C" import ( "image" - "image/color" "unsafe" ) -// newImageFromPointer - Returns new Image from pointer -func newImageFromPointer(ptr unsafe.Pointer) *Image { - return (*Image)(ptr) -} - // cptr returns C pointer func (i *Image) cptr() *C.Image { return (*C.Image)(unsafe.Pointer(i)) @@ -28,7 +22,7 @@ func (i *Image) ToImage() image.Image { // Get pixel data from image (RGBA 32bit) cimg := i.cptr() - ret := C.LoadImageColors(*cimg) + ret := C.GetImageData(*cimg) pixels := (*[1 << 24]uint8)(unsafe.Pointer(ret))[0 : i.Width*i.Height*4] img.Pix = pixels @@ -36,51 +30,16 @@ func (i *Image) ToImage() image.Image { return img } -// newTexture2DFromPointer - Returns new Texture2D from pointer -func newTexture2DFromPointer(ptr unsafe.Pointer) Texture2D { - return *(*Texture2D)(ptr) -} - // cptr returns C pointer func (t *Texture2D) cptr() *C.Texture2D { return (*C.Texture2D)(unsafe.Pointer(t)) } -// newRenderTexture2DFromPointer - Returns new RenderTexture2D from pointer -func newRenderTexture2DFromPointer(ptr unsafe.Pointer) RenderTexture2D { - return *(*RenderTexture2D)(ptr) -} - // cptr returns C pointer func (r *RenderTexture2D) cptr() *C.RenderTexture2D { return (*C.RenderTexture2D)(unsafe.Pointer(r)) } -// NewImageFromImage - Returns new Image from Go image.Image -func NewImageFromImage(img image.Image) *Image { - size := img.Bounds().Size() - - cx := (C.int)(size.X) - cy := (C.int)(size.Y) - ccolor := colorCptr(White) - ret := C.GenImageColor(cx, cy, *ccolor) - - for y := 0; y < size.Y; y++ { - for x := 0; x < size.X; x++ { - color := img.At(x, y) - r, g, b, a := color.RGBA() - rcolor := NewColor(uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8)) - ccolor = colorCptr(rcolor) - - cx = (C.int)(x) - cy = (C.int)(y) - C.ImageDrawPixel(&ret, cx, cy, *ccolor) - } - } - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - // LoadImage - Load an image into CPU memory (RAM) func LoadImage(fileName string) *Image { cfileName := C.CString(fileName) @@ -113,18 +72,6 @@ func LoadImageAnim(fileName string, frames *int32) *Image { return v } -// LoadImageAnimFromMemory - Load image sequence from memory buffer -func LoadImageAnimFromMemory(fileType string, fileData []byte, dataSize int32, frames *int32) *Image { - cfileType := C.CString(fileType) - defer C.free(unsafe.Pointer(cfileType)) - cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) - cdataSize := (C.int)(dataSize) - cframes := (*C.int)(frames) - ret := C.LoadImageAnimFromMemory(cfileType, cfileData, cdataSize, cframes) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - // LoadImageFromMemory - Load image from memory buffer, fileType refers to extension: i.e. ".png" func LoadImageFromMemory(fileType string, fileData []byte, dataSize int32) *Image { cfileType := C.CString(fileType) @@ -136,29 +83,6 @@ func LoadImageFromMemory(fileType string, fileData []byte, dataSize int32) *Imag return v } -// LoadImageFromTexture - Get pixel data from GPU texture and return an Image -func LoadImageFromTexture(texture Texture2D) *Image { - ctexture := texture.cptr() - ret := C.LoadImageFromTexture(*ctexture) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadImageFromScreen - Load image from screen buffer (screenshot) -func LoadImageFromScreen() *Image { - ret := C.LoadImageFromScreen() - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// IsImageValid - Check if an image is valid (data and parameters) -func IsImageValid(image *Image) bool { - cimage := image.cptr() - ret := C.IsImageValid(*cimage) - v := bool(ret) - return v -} - // LoadTexture - Load an image as texture into GPU memory func LoadTexture(fileName string) Texture2D { cfileName := C.CString(fileName) @@ -185,70 +109,48 @@ func LoadRenderTexture(width, height int32) RenderTexture2D { return v } -// LoadTextureCubemap - Loads a texture for a cubemap using given layout -func LoadTextureCubemap(image *Image, layout int32) Texture2D { - cimage := image.cptr() - clayout := (C.int)(layout) - ret := C.LoadTextureCubemap(*cimage, clayout) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - // UnloadImage - Unload image from CPU memory (RAM) func UnloadImage(image *Image) { cimage := image.cptr() C.UnloadImage(*cimage) } -// IsTextureValid - Check if a texture is valid (loaded in GPU) -func IsTextureValid(texture Texture2D) bool { - ctexture := texture.cptr() - ret := C.IsTextureValid(*ctexture) - v := bool(ret) - return v -} - // UnloadTexture - Unload texture from GPU memory func UnloadTexture(texture Texture2D) { ctexture := texture.cptr() C.UnloadTexture(*ctexture) } -// IsRenderTextureValid - Check if a render texture is valid (loaded in GPU) -func IsRenderTextureValid(target RenderTexture2D) bool { - ctarget := target.cptr() - ret := C.IsRenderTextureValid(*ctarget) - v := bool(ret) - return v -} - // UnloadRenderTexture - Unload render texture from GPU memory func UnloadRenderTexture(target RenderTexture2D) { ctarget := target.cptr() C.UnloadRenderTexture(*ctarget) } -// LoadImageColors - Get pixel data from image as a Color slice -func LoadImageColors(img *Image) []color.RGBA { +// GetImageData - Get pixel data from image as a Color slice +func GetImageData(img *Image) []Color { cimg := img.cptr() - ret := C.LoadImageColors(*cimg) - return (*[1 << 24]color.RGBA)(unsafe.Pointer(ret))[0 : img.Width*img.Height] + ret := C.GetImageData(*cimg) + return (*[1 << 24]Color)(unsafe.Pointer(ret))[0 : img.Width*img.Height] } -// UnloadImageColors - Unload color data loaded with LoadImageColors() -func UnloadImageColors(cols []color.RGBA) { - C.UnloadImageColors((*C.Color)(unsafe.Pointer(&cols[0]))) +// GetTextureData - Get pixel data from GPU texture and return an Image +func GetTextureData(texture Texture2D) *Image { + ctexture := texture.cptr() + ret := C.GetTextureData(*ctexture) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v } // UpdateTexture - Update GPU texture with new data -func UpdateTexture(texture Texture2D, pixels []color.RGBA) { +func UpdateTexture(texture Texture2D, pixels []Color) { ctexture := texture.cptr() cpixels := unsafe.Pointer(&pixels[0]) C.UpdateTexture(*ctexture, cpixels) } // UpdateTextureRec - Update GPU texture rectangle with new data -func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []color.RGBA) { +func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []Color) { ctexture := texture.cptr() cpixels := unsafe.Pointer(&pixels[0]) crec := rec.cptr() @@ -256,23 +158,12 @@ func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []color.RGBA) { } // ExportImage - Export image as a PNG file -func ExportImage(image Image, fileName string) bool { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - cimage := image.cptr() - return bool(C.ExportImage(*cimage, cfileName)) -} - -// ExportImageToMemory - Export image to memory buffer -func ExportImageToMemory(image Image, fileType string) []byte { - cfileType := C.CString(fileType) - defer C.free(unsafe.Pointer(cfileType)) +func ExportImage(image Image, name string) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) cimage := image.cptr() - var size C.int - ret := C.ExportImageToMemory(*cimage, cfileType, &size) - v := unsafe.Slice((*byte)(unsafe.Pointer(ret)), size) - return v + C.ExportImage(*cimage, cname) } // ImageCopy - Create an image duplicate (useful for transformations) @@ -283,43 +174,25 @@ func ImageCopy(image *Image) *Image { return v } -// Create an image from another image piece -func ImageFromImage(image Image, rec Rectangle) Image { - cimage := image.cptr() - crec := rec.cptr() - ret := C.ImageFromImage(*cimage, *crec) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return *v -} - -// ImageFromChannel - Create an image from a selected channel of another image (GRAYSCALE) -func ImageFromChannel(image Image, selectedChannel int32) Image { - cimage := image.cptr() - cselectedChannel := C.int(selectedChannel) - ret := C.ImageFromChannel(*cimage, cselectedChannel) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return *v -} - // ImageText - Create an image from text (default font) -func ImageText(text string, fontSize int32, col color.RGBA) *Image { +func ImageText(text string, fontSize int32, color Color) *Image { ctext := C.CString(text) defer C.free(unsafe.Pointer(ctext)) cfontSize := (C.int)(fontSize) - ccolor := colorCptr(col) + ccolor := color.cptr() ret := C.ImageText(ctext, cfontSize, *ccolor) v := newImageFromPointer(unsafe.Pointer(&ret)) return v } // ImageTextEx - Create an image from text (custom sprite font) -func ImageTextEx(font Font, text string, fontSize, spacing float32, tint color.RGBA) *Image { +func ImageTextEx(font Font, text string, fontSize, spacing float32, tint Color) *Image { cfont := font.cptr() ctext := C.CString(text) defer C.free(unsafe.Pointer(ctext)) cfontSize := (C.float)(fontSize) cspacing := (C.float)(spacing) - ctint := colorCptr(tint) + ctint := tint.cptr() ret := C.ImageTextEx(*cfont, ctext, cfontSize, cspacing, *ctint) v := newImageFromPointer(unsafe.Pointer(&ret)) return v @@ -333,9 +206,9 @@ func ImageFormat(image *Image, newFormat PixelFormat) { } // ImageToPOT - Convert image to POT (power-of-two) -func ImageToPOT(image *Image, fillColor color.RGBA) { +func ImageToPOT(image *Image, fillColor Color) { cimage := image.cptr() - cfillColor := colorCptr(fillColor) + cfillColor := fillColor.cptr() C.ImageToPOT(cimage, *cfillColor) } @@ -354,9 +227,9 @@ func ImageAlphaCrop(image *Image, threshold float32) { } // ImageAlphaClear - Apply alpha mask to image -func ImageAlphaClear(image *Image, col color.RGBA, threshold float32) { +func ImageAlphaClear(image *Image, color Color, threshold float32) { cimage := image.cptr() - ccolor := colorCptr(col) + ccolor := color.cptr() cthreshold := (C.float)(threshold) C.ImageAlphaClear(cimage, *ccolor, cthreshold) } @@ -374,20 +247,6 @@ func ImageAlphaPremultiply(image *Image) { C.ImageAlphaPremultiply(cimage) } -// ImageBlurGaussian - Apply box blur -func ImageBlurGaussian(image *Image, blurSize int32) { - cimage := image.cptr() - cblurSize := C.int(blurSize) - C.ImageBlurGaussian(cimage, cblurSize) -} - -// ImageKernelConvolution - Apply custom square convolution kernel to image -func ImageKernelConvolution(image *Image, kernel []float32) { - cimage := image.cptr() - ckernel := (*C.float)(unsafe.Pointer(&kernel[0])) - C.ImageKernelConvolution(cimage, ckernel, C.int(len(kernel))) -} - // ImageResize - Resize an image (bilinear filtering) func ImageResize(image *Image, newWidth, newHeight int32) { cimage := image.cptr() @@ -405,13 +264,13 @@ func ImageResizeNN(image *Image, newWidth, newHeight int32) { } // ImageResizeCanvas - Resize canvas and fill with color -func ImageResizeCanvas(image *Image, newWidth, newHeight, offsetX, offsetY int32, col color.RGBA) { +func ImageResizeCanvas(image *Image, newWidth, newHeight, offsetX, offsetY int32, color Color) { cimage := image.cptr() cnewWidth := (C.int)(newWidth) cnewHeight := (C.int)(newHeight) coffsetX := (C.int)(offsetX) coffsetY := (C.int)(offsetY) - ccolor := colorCptr(col) + ccolor := color.cptr() C.ImageResizeCanvas(cimage, cnewWidth, cnewHeight, coffsetX, coffsetY, *ccolor) } @@ -443,13 +302,6 @@ func ImageFlipHorizontal(image *Image) { C.ImageFlipHorizontal(cimage) } -// ImageRotate - Rotate image by input angle in degrees (-359 to 359) -func ImageRotate(image *Image, degrees int32) { - cimage := image.cptr() - cdegrees := (C.int)(degrees) - C.ImageRotate(cimage, cdegrees) -} - // ImageRotateCW - Rotate image clockwise 90deg func ImageRotateCW(image *Image) { cimage := image.cptr() @@ -463,9 +315,9 @@ func ImageRotateCCW(image *Image) { } // ImageColorTint - Modify image color: tint -func ImageColorTint(image *Image, col color.RGBA) { +func ImageColorTint(image *Image, color Color) { cimage := image.cptr() - ccolor := colorCptr(col) + ccolor := color.cptr() C.ImageColorTint(cimage, *ccolor) } @@ -496,227 +348,57 @@ func ImageColorBrightness(image *Image, brightness int32) { } // ImageColorReplace - Modify image color: replace color -func ImageColorReplace(image *Image, col, replace color.RGBA) { +func ImageColorReplace(image *Image, color, replace Color) { cimage := image.cptr() - ccolor := colorCptr(col) - creplace := colorCptr(replace) + ccolor := color.cptr() + creplace := replace.cptr() C.ImageColorReplace(cimage, *ccolor, *creplace) } -// GetImageColor - Get image pixel color at (x, y) position -func GetImageColor(image Image, x, y int32) color.RGBA { - cimage := image.cptr() - cx := (C.int)(x) - cy := (C.int)(y) - - ret := C.GetImageColor(*cimage, cx, cy) - v := newColorFromPointer(unsafe.Pointer(&ret)) - return v -} - -// ImageClearBackground - Clear image background with given color -func ImageClearBackground(dst *Image, col color.RGBA) { - cdst := dst.cptr() - ccolor := colorCptr(col) - C.ImageClearBackground(cdst, *ccolor) -} - // ImageDraw - Draw a source image within a destination image -func ImageDraw(dst, src *Image, srcRec, dstRec Rectangle, tint color.RGBA) { +func ImageDraw(dst, src *Image, srcRec, dstRec Rectangle, tint Color) { cdst := dst.cptr() csrc := src.cptr() csrcRec := srcRec.cptr() cdstRec := dstRec.cptr() - ctint := colorCptr(tint) + ctint := tint.cptr() C.ImageDraw(cdst, *csrc, *csrcRec, *cdstRec, *ctint) } -// ImageDrawLine - Draw line within an image -func ImageDrawLine(dst *Image, startPosX, startPosY, endPosX, endPosY int32, col color.RGBA) { - cdst := dst.cptr() - cstartPosX := (C.int)(startPosX) - cstartPosY := (C.int)(startPosY) - cendPosX := (C.int)(endPosX) - cendPosY := (C.int)(endPosY) - ccolor := colorCptr(col) - C.ImageDrawLine(cdst, cstartPosX, cstartPosY, cendPosX, cendPosY, *ccolor) -} - -// ImageDrawLineV - Draw line within an image, vector version -func ImageDrawLineV(dst *Image, start, end Vector2, col color.RGBA) { - cdst := dst.cptr() - cstart := start.cptr() - cend := end.cptr() - ccolor := colorCptr(col) - C.ImageDrawLineV(cdst, *cstart, *cend, *ccolor) -} - -// ImageDrawLineEx - Draw a line defining thickness within an image -func ImageDrawLineEx(dst *Image, start, end Vector2, thick int32, col color.RGBA) { - cdst := dst.cptr() - cstart := start.cptr() - cend := end.cptr() - cthick := C.int(thick) - ccolor := colorCptr(col) - C.ImageDrawLineEx(cdst, *cstart, *cend, cthick, *ccolor) -} - -// ImageDrawCircle - Draw a filled circle within an image -func ImageDrawCircle(dst *Image, centerX, centerY, radius int32, col color.RGBA) { - cdst := dst.cptr() - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradius := (C.int)(radius) - ccolor := colorCptr(col) - C.ImageDrawCircle(cdst, ccenterX, ccenterY, cradius, *ccolor) -} - -// ImageDrawCircleV - Draw a filled circle within an image (Vector version) -func ImageDrawCircleV(dst *Image, center Vector2, radius int32, col color.RGBA) { - cdst := dst.cptr() - ccenter := center.cptr() - cradius := (C.int)(radius) - ccolor := colorCptr(col) - C.ImageDrawCircleV(cdst, *ccenter, cradius, *ccolor) -} - -// ImageDrawCircleLines - Draw circle outline within an image -func ImageDrawCircleLines(dst *Image, centerX, centerY, radius int32, col color.RGBA) { - cdst := dst.cptr() - ccenterX := (C.int)(centerX) - ccenterY := (C.int)(centerY) - cradius := (C.int)(radius) - ccolor := colorCptr(col) - C.ImageDrawCircleLines(cdst, ccenterX, ccenterY, cradius, *ccolor) -} - -// ImageDrawCircleLinesV - Draw circle outline within an image (Vector version) -func ImageDrawCircleLinesV(dst *Image, center Vector2, radius int32, col color.RGBA) { - cdst := dst.cptr() - ccenter := center.cptr() - cradius := (C.int)(radius) - ccolor := colorCptr(col) - C.ImageDrawCircleLinesV(cdst, *ccenter, cradius, *ccolor) -} - -// ImageDrawPixel - Draw pixel within an image -func ImageDrawPixel(dst *Image, posX, posY int32, col color.RGBA) { - cdst := dst.cptr() - cposX := (C.int)(posX) - cposY := (C.int)(posY) - ccolor := colorCptr(col) - C.ImageDrawPixel(cdst, cposX, cposY, *ccolor) -} - -// ImageDrawPixelV - Draw pixel within an image (Vector version) -func ImageDrawPixelV(dst *Image, position Vector2, col color.RGBA) { - cdst := dst.cptr() - cposition := position.cptr() - ccolor := colorCptr(col) - C.ImageDrawPixelV(cdst, *cposition, *ccolor) -} - // ImageDrawRectangle - Draw rectangle within an image -func ImageDrawRectangle(dst *Image, x, y, width, height int32, col color.RGBA) { +func ImageDrawRectangle(dst *Image, x, y, width, height int32, color Color) { cdst := dst.cptr() cx := (C.int)(x) cy := (C.int)(y) cwidth := (C.int)(width) cheight := (C.int)(height) - ccolor := colorCptr(col) + ccolor := color.cptr() C.ImageDrawRectangle(cdst, cx, cy, cwidth, cheight, *ccolor) } -// ImageDrawRectangleV - Draw rectangle within an image (Vector version) -func ImageDrawRectangleV(dst *Image, position, size Vector2, col color.RGBA) { - cdst := dst.cptr() - cposition := position.cptr() - csize := size.cptr() - ccolor := colorCptr(col) - C.ImageDrawRectangleV(cdst, *cposition, *csize, *ccolor) -} - // ImageDrawRectangleLines - Draw rectangle lines within an image -func ImageDrawRectangleLines(dst *Image, rec Rectangle, thick int, col color.RGBA) { +func ImageDrawRectangleLines(dst *Image, rec Rectangle, thick int, color Color) { cdst := dst.cptr() crec := rec.cptr() cthick := (C.int)(thick) - ccolor := colorCptr(col) + ccolor := color.cptr() C.ImageDrawRectangleLines(cdst, *crec, cthick, *ccolor) } -// ImageDrawTriangle - Draw triangle within an image -func ImageDrawTriangle(dst *Image, v1, v2, v3 Vector2, col color.RGBA) { - cdst := dst.cptr() - cv1 := v1.cptr() - cv2 := v2.cptr() - cv3 := v3.cptr() - ccol := colorCptr(col) - C.ImageDrawTriangle(cdst, *cv1, *cv2, *cv3, *ccol) -} - -// ImageDrawTriangleEx - Draw triangle with interpolated colors within an image -func ImageDrawTriangleEx(dst *Image, v1, v2, v3 Vector2, c1, c2, c3 color.RGBA) { - cdst := dst.cptr() - cv1 := v1.cptr() - cv2 := v2.cptr() - cv3 := v3.cptr() - cc1 := colorCptr(c1) - cc2 := colorCptr(c2) - cc3 := colorCptr(c3) - C.ImageDrawTriangleEx(cdst, *cv1, *cv2, *cv3, *cc1, *cc2, *cc3) -} - -// ImageDrawTriangleLines - Draw triangle outline within an image -func ImageDrawTriangleLines(dst *Image, v1, v2, v3 Vector2, col color.RGBA) { - cdst := dst.cptr() - cv1 := v1.cptr() - cv2 := v2.cptr() - cv3 := v3.cptr() - ccol := colorCptr(col) - C.ImageDrawTriangleLines(cdst, *cv1, *cv2, *cv3, *ccol) -} - -// ImageDrawTriangleFan - Draw a triangle fan defined by points within an image (first vertex is the center) -func ImageDrawTriangleFan(dst *Image, points []Vector2, col color.RGBA) { - cdst := dst.cptr() - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - pointCount := C.int(len(points)) - ccol := colorCptr(col) - C.ImageDrawTriangleFan(cdst, cpoints, pointCount, *ccol) -} - -// ImageDrawTriangleStrip - Draw a triangle strip defined by points within an image -func ImageDrawTriangleStrip(dst *Image, points []Vector2, col color.RGBA) { - cdst := dst.cptr() - cpoints := (*C.Vector2)(unsafe.Pointer(&points[0])) - pointCount := C.int(len(points)) - ccol := colorCptr(col) - C.ImageDrawTriangleStrip(cdst, cpoints, pointCount, *ccol) -} - -// ImageDrawRectangleRec - Draw rectangle within an image -func ImageDrawRectangleRec(dst *Image, rec Rectangle, col color.RGBA) { - cdst := dst.cptr() - crec := rec.cptr() - ccolor := colorCptr(col) - C.ImageDrawRectangleRec(cdst, *crec, *ccolor) -} - // ImageDrawText - Draw text (default font) within an image (destination) -func ImageDrawText(dst *Image, posX, posY int32, text string, fontSize int32, col color.RGBA) { +func ImageDrawText(dst *Image, posX, posY int32, text string, fontSize int32, color Color) { cdst := dst.cptr() posx := (C.int)(posX) posy := (C.int)(posY) ctext := C.CString(text) defer C.free(unsafe.Pointer(ctext)) cfontSize := (C.int)(fontSize) - ccolor := colorCptr(col) + ccolor := color.cptr() C.ImageDrawText(cdst, ctext, posx, posy, cfontSize, *ccolor) } // ImageDrawTextEx - Draw text (custom sprite font) within an image (destination) -func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontSize, spacing float32, col color.RGBA) { +func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontSize, spacing float32, color Color) { cdst := dst.cptr() cposition := position.cptr() cfont := font.cptr() @@ -724,68 +406,66 @@ func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontS defer C.free(unsafe.Pointer(ctext)) cfontSize := (C.float)(fontSize) cspacing := (C.float)(spacing) - ccolor := colorCptr(col) + ccolor := color.cptr() C.ImageDrawTextEx(cdst, *cfont, ctext, *cposition, cfontSize, cspacing, *ccolor) } // GenImageColor - Generate image: plain color -func GenImageColor(width, height int, col color.RGBA) *Image { +func GenImageColor(width, height int, color Color) *Image { cwidth := (C.int)(width) cheight := (C.int)(height) - ccolor := colorCptr(col) + ccolor := color.cptr() ret := C.GenImageColor(cwidth, cheight, *ccolor) v := newImageFromPointer(unsafe.Pointer(&ret)) return v } -// GenImageGradientLinear - Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient -func GenImageGradientLinear(width, height, direction int, start, end color.RGBA) *Image { +// GenImageGradientV - Generate image: vertical gradient +func GenImageGradientV(width, height int, top, bottom Color) *Image { cwidth := (C.int)(width) cheight := (C.int)(height) - cdensity := (C.int)(direction) - cstart := colorCptr(start) - cend := colorCptr(end) + ctop := top.cptr() + cbottom := bottom.cptr() - ret := C.GenImageGradientLinear(cwidth, cheight, cdensity, *cstart, *cend) + ret := C.GenImageGradientV(cwidth, cheight, *ctop, *cbottom) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenImageGradientH - Generate image: horizontal gradient +func GenImageGradientH(width, height int, left, right Color) *Image { + cwidth := (C.int)(width) + cheight := (C.int)(height) + cleft := left.cptr() + cright := right.cptr() + + ret := C.GenImageGradientH(cwidth, cheight, *cleft, *cright) v := newImageFromPointer(unsafe.Pointer(&ret)) return v } // GenImageGradientRadial - Generate image: radial gradient -func GenImageGradientRadial(width, height int, density float32, inner, outer color.RGBA) *Image { +func GenImageGradientRadial(width, height int, density float32, inner, outer Color) *Image { cwidth := (C.int)(width) cheight := (C.int)(height) cdensity := (C.float)(density) - cinner := colorCptr(inner) - couter := colorCptr(outer) + cinner := inner.cptr() + couter := outer.cptr() ret := C.GenImageGradientRadial(cwidth, cheight, cdensity, *cinner, *couter) v := newImageFromPointer(unsafe.Pointer(&ret)) return v } -// GenImageGradientSquare - Generate image: square gradient -func GenImageGradientSquare(width, height int, density float32, inner, outer color.RGBA) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - cdensity := (C.float)(density) - cinner := colorCptr(inner) - couter := colorCptr(outer) - - ret := C.GenImageGradientSquare(cwidth, cheight, cdensity, *cinner, *couter) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - // GenImageChecked - Generate image: checked -func GenImageChecked(width, height, checksX, checksY int, col1, col2 color.RGBA) *Image { +func GenImageChecked(width, height, checksX, checksY int, col1, col2 Color) *Image { cwidth := (C.int)(width) cheight := (C.int)(height) cchecksX := (C.int)(checksX) cchecksY := (C.int)(checksY) - ccol1 := colorCptr(col1) - ccol2 := colorCptr(col2) + ccol1 := col1.cptr() + ccol2 := col2.cptr() ret := C.GenImageChecked(cwidth, cheight, cchecksX, cchecksY, *ccol1, *ccol2) v := newImageFromPointer(unsafe.Pointer(&ret)) @@ -827,18 +507,6 @@ func GenImageCellular(width, height, tileSize int) *Image { return v } -// GenImageText - Generate image: grayscale image from text data -func GenImageText(width, height int, text string) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - - ret := C.GenImageText(cwidth, cheight, ctext) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - // GenTextureMipmaps - Generate GPU mipmaps for a texture func GenTextureMipmaps(texture *Texture2D) { ctexture := texture.cptr() @@ -860,64 +528,48 @@ func SetTextureWrap(texture Texture2D, wrapMode TextureWrapMode) { } // DrawTexture - Draw a Texture2D -func DrawTexture(texture Texture2D, posX int32, posY int32, tint color.RGBA) { +func DrawTexture(texture Texture2D, posX int32, posY int32, tint Color) { ctexture := texture.cptr() cposX := (C.int)(posX) cposY := (C.int)(posY) - ctint := colorCptr(tint) + ctint := tint.cptr() C.DrawTexture(*ctexture, cposX, cposY, *ctint) } // DrawTextureV - Draw a Texture2D with position defined as Vector2 -func DrawTextureV(texture Texture2D, position Vector2, tint color.RGBA) { +func DrawTextureV(texture Texture2D, position Vector2, tint Color) { ctexture := texture.cptr() cposition := position.cptr() - ctint := colorCptr(tint) + ctint := tint.cptr() C.DrawTextureV(*ctexture, *cposition, *ctint) } // DrawTextureEx - Draw a Texture2D with extended parameters -func DrawTextureEx(texture Texture2D, position Vector2, rotation, scale float32, tint color.RGBA) { +func DrawTextureEx(texture Texture2D, position Vector2, rotation, scale float32, tint Color) { ctexture := texture.cptr() cposition := position.cptr() crotation := (C.float)(rotation) cscale := (C.float)(scale) - ctint := colorCptr(tint) + ctint := tint.cptr() C.DrawTextureEx(*ctexture, *cposition, crotation, cscale, *ctint) } // DrawTextureRec - Draw a part of a texture defined by a rectangle -func DrawTextureRec(texture Texture2D, sourceRec Rectangle, position Vector2, tint color.RGBA) { +func DrawTextureRec(texture Texture2D, sourceRec Rectangle, position Vector2, tint Color) { ctexture := texture.cptr() csourceRec := sourceRec.cptr() cposition := position.cptr() - ctint := colorCptr(tint) + ctint := tint.cptr() C.DrawTextureRec(*ctexture, *csourceRec, *cposition, *ctint) } // DrawTexturePro - Draw a part of a texture defined by a rectangle with 'pro' parameters -func DrawTexturePro(texture Texture2D, sourceRec, destRec Rectangle, origin Vector2, rotation float32, tint color.RGBA) { +func DrawTexturePro(texture Texture2D, sourceRec, destRec Rectangle, origin Vector2, rotation float32, tint Color) { ctexture := texture.cptr() csourceRec := sourceRec.cptr() cdestRec := destRec.cptr() corigin := origin.cptr() crotation := (C.float)(rotation) - ctint := colorCptr(tint) + ctint := tint.cptr() C.DrawTexturePro(*ctexture, *csourceRec, *cdestRec, *corigin, crotation, *ctint) } - -// cptr returns C pointer -func (n *NPatchInfo) cptr() *C.NPatchInfo { - return (*C.NPatchInfo)(unsafe.Pointer(n)) -} - -// DrawTextureNPatch - Draws a texture (or part of it) that stretches or shrinks nicely using n-patch info -func DrawTextureNPatch(texture Texture2D, nPatchInfo NPatchInfo, dest Rectangle, origin Vector2, rotation float32, tint color.RGBA) { - ctexture := texture.cptr() - cnPatchInfo := nPatchInfo.cptr() - cdest := dest.cptr() - corigin := origin.cptr() - crotation := (C.float)(rotation) - ctint := colorCptr(tint) - C.DrawTextureNPatch(*ctexture, *cnPatchInfo, *cdest, *corigin, crotation, *ctint) -} diff --git a/raylib/utils.c b/raylib/utils.c index 26e7a1b..c21d231 100644 --- a/raylib/utils.c +++ b/raylib/utils.c @@ -3,14 +3,15 @@ * raylib.utils - Some common utility functions * * CONFIGURATION: -* #define SUPPORT_TRACELOG -* Show TraceLog() output messages -* NOTE: By default LOG_DEBUG traces not shown +* +* #define SUPPORT_TRACELOG +* Show TraceLog() output messages +* NOTE: By default LOG_DEBUG traces not shown * * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -41,7 +42,7 @@ #if defined(PLATFORM_ANDROID) #include // Required for: Android error types #include // Required for: Android log system: __android_log_vprint() - #include // Required for: Android assets manager: AAsset, AAssetManager_open()... + #include // Required for: Android assets manager: AAsset, AAssetManager_open(), ... #endif #include // Required for: exit() @@ -53,7 +54,10 @@ // Defines and Macros //---------------------------------------------------------------------------------- #ifndef MAX_TRACELOG_MSG_LENGTH - #define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message + #define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message +#endif +#ifndef MAX_UWP_MESSAGES + #define MAX_UWP_MESSAGES 512 // Max UWP messages to process #endif //---------------------------------------------------------------------------------- @@ -62,10 +66,10 @@ static int logTypeLevel = LOG_INFO; // Minimum log type level static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer -static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback function pointer -static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback function pointer -static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback function pointer -static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback function pointer +static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback funtion pointer +static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback funtion pointer +static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback funtion pointer +static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback funtion pointer //---------------------------------------------------------------------------------- // Functions to set internal callbacks @@ -76,9 +80,10 @@ void SetSaveFileDataCallback(SaveFileDataCallback callback) { saveFileData = cal void SetLoadFileTextCallback(LoadFileTextCallback callback) { loadFileText = callback; } // Set custom file text loader void SetSaveFileTextCallback(SaveFileTextCallback callback) { saveFileText = callback; } // Set custom file text saver + #if defined(PLATFORM_ANDROID) -static AAssetManager *assetManager = NULL; // Android assets manager pointer -static const char *internalDataPath = NULL; // Android internal data path +static AAssetManager *assetManager = NULL; // Android assets manager pointer +static const char *internalDataPath = NULL; // Android internal data path #endif //---------------------------------------------------------------------------------- @@ -119,7 +124,7 @@ void TraceLog(int logType, const char *text, ...) } #if defined(PLATFORM_ANDROID) - switch (logType) + switch(logType) { case LOG_TRACE: __android_log_vprint(ANDROID_LOG_VERBOSE, "raylib", text, args); break; case LOG_DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", text, args); break; @@ -143,30 +148,28 @@ void TraceLog(int logType, const char *text, ...) default: break; } - unsigned int textSize = (unsigned int)strlen(text); - memcpy(buffer + strlen(buffer), text, (textSize < (MAX_TRACELOG_MSG_LENGTH - 12))? textSize : (MAX_TRACELOG_MSG_LENGTH - 12)); + strcat(buffer, text); strcat(buffer, "\n"); vprintf(buffer, args); - fflush(stdout); #endif va_end(args); - if (logType == LOG_FATAL) exit(EXIT_FAILURE); // If fatal logging, exit program + if (logType == LOG_ERROR) exit(1); // If error, exit program #endif // SUPPORT_TRACELOG } // Internal memory allocator // NOTE: Initializes to zero by default -void *MemAlloc(unsigned int size) +void *MemAlloc(int size) { void *ptr = RL_CALLOC(size, 1); return ptr; } // Internal memory reallocator -void *MemRealloc(void *ptr, unsigned int size) +void *MemRealloc(void *ptr, int size) { void *ret = RL_REALLOC(ptr, size); return ret; @@ -179,16 +182,16 @@ void MemFree(void *ptr) } // Load data from file into a buffer -unsigned char *LoadFileData(const char *fileName, int *dataSize) +unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead) { unsigned char *data = NULL; - *dataSize = 0; + *bytesRead = 0; if (fileName != NULL) { if (loadFileData) { - data = loadFileData(fileName, dataSize); + data = loadFileData(fileName, bytesRead); return data; } #if defined(SUPPORT_STANDARD_FILEIO) @@ -199,36 +202,19 @@ unsigned char *LoadFileData(const char *fileName, int *dataSize) // WARNING: On binary streams SEEK_END could not be found, // using fseek() and ftell() could not work in some (rare) cases fseek(file, 0, SEEK_END); - int size = ftell(file); // WARNING: ftell() returns 'long int', maximum size returned is INT_MAX (2147483647 bytes) + int size = ftell(file); fseek(file, 0, SEEK_SET); if (size > 0) { data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char)); - if (data != NULL) - { - // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] - size_t count = fread(data, sizeof(unsigned char), size, file); + // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] + unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file); + *bytesRead = count; - // WARNING: fread() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation) - // dataSize is unified along raylib as a 'int' type, so, for file-sizes > INT_MAX (2147483647 bytes) we have a limitation - if (count > 2147483647) - { - TRACELOG(LOG_WARNING, "FILEIO: [%s] File is bigger than 2147483647 bytes, avoid using LoadFileData()", fileName); - - RL_FREE(data); - data = NULL; - } - else - { - *dataSize = (int)count; - - if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, dataSize, count); - else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName); - } - } - else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName); + if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName); + else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName); } else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName); @@ -251,7 +237,7 @@ void UnloadFileData(unsigned char *data) } // Save data to file from buffer -bool SaveFileData(const char *fileName, void *data, int dataSize) +bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite) { bool success = false; @@ -259,19 +245,17 @@ bool SaveFileData(const char *fileName, void *data, int dataSize) { if (saveFileData) { - return saveFileData(fileName, data, dataSize); + return saveFileData(fileName, data, bytesToWrite); } #if defined(SUPPORT_STANDARD_FILEIO) FILE *file = fopen(fileName, "wb"); if (file != NULL) { - // WARNING: fwrite() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation) - // and expects a size_t input value but as dataSize is limited to INT_MAX (2147483647 bytes), there shouldn't be a problem - int count = (int)fwrite(data, sizeof(unsigned char), dataSize, file); + unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file); if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName); - else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName); + else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName); else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName); int result = fclose(file); @@ -287,59 +271,6 @@ bool SaveFileData(const char *fileName, void *data, int dataSize) return success; } -// Export data to code (.h), returns true on success -bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName) -{ - bool success = false; - -#ifndef TEXT_BYTES_PER_LINE - #define TEXT_BYTES_PER_LINE 20 -#endif - - // NOTE: Text data buffer size is estimated considering raw data size in bytes - // and requiring 6 char bytes for every byte: "0x00, " - char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char)); - - int byteCount = 0; - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); - byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2025 Ramon Santamaria (@raysan5) //\n"); - byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); - - // Get file name from path - char varFileName[256] = { 0 }; - strcpy(varFileName, GetFileNameWithoutExt(fileName)); - for (int i = 0; varFileName[i] != '\0'; i++) - { - // Convert variable name to uppercase - if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } - // Replace non valid character for C identifier with '_' - else if (varFileName[i] == '.' || varFileName[i] == '-' || varFileName[i] == '?' || varFileName[i] == '!' || varFileName[i] == '+') { varFileName[i] = '_'; } - } - - byteCount += sprintf(txtData + byteCount, "#define %s_DATA_SIZE %i\n\n", varFileName, dataSize); - - byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%s_DATA_SIZE] = { ", varFileName, varFileName); - for (int i = 0; i < (dataSize - 1); i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]); - byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[dataSize - 1]); - - // NOTE: Text data size exported is determined by '\0' (NULL) character - success = SaveFileText(fileName, txtData); - - RL_FREE(txtData); - - if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName); - else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName); - - return success; -} - // Load text data from file, returns a '\0' terminated string // NOTE: text chars array should be freed manually char *LoadFileText(const char *fileName) @@ -368,21 +299,16 @@ char *LoadFileText(const char *fileName) if (size > 0) { text = (char *)RL_MALLOC((size + 1)*sizeof(char)); + unsigned int count = (unsigned int)fread(text, sizeof(char), size, file); - if (text != NULL) - { - unsigned int count = (unsigned int)fread(text, sizeof(char), size, file); + // WARNING: \r\n is converted to \n on reading, so, + // read bytes count gets reduced by the number of lines + if (count < size) text = RL_REALLOC(text, count + 1); - // WARNING: \r\n is converted to \n on reading, so, - // read bytes count gets reduced by the number of lines - if (count < size) text = RL_REALLOC(text, count + 1); + // Zero-terminate the string + text[count] = '\0'; - // Zero-terminate the string - text[count] = '\0'; - - TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName); - } - else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName); + TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName); } else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName); @@ -405,7 +331,7 @@ void UnloadFileText(char *text) } // Save text data to file (write), string must be '\0' terminated -bool SaveFileText(const char *fileName, const char *text) +bool SaveFileText(const char *fileName, char *text) { bool success = false; @@ -452,8 +378,8 @@ FILE *android_fopen(const char *fileName, const char *mode) { if (mode[0] == 'w') { - // fopen() is mapped to android_fopen() that only grants read access to - // assets directory through AAssetManager but we want to also be able to + // TODO: fopen() is mapped to android_fopen() that only grants read access + // to assets directory through AAssetManager but we want to also be able to // write data when required using the standard stdio FILE access functions // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only #undef fopen @@ -467,7 +393,7 @@ FILE *android_fopen(const char *fileName, const char *mode) if (asset != NULL) { - // Get pointer to file in the assets + // Return pointer to file in the assets return funopen(asset, android_read, android_write, android_seek, android_close); } else @@ -485,12 +411,12 @@ FILE *android_fopen(const char *fileName, const char *mode) // Module specific Functions Definition //---------------------------------------------------------------------------------- #if defined(PLATFORM_ANDROID) -static int android_read(void *cookie, char *data, int dataSize) +static int android_read(void *cookie, char *buf, int size) { - return AAsset_read((AAsset *)cookie, data, dataSize); + return AAsset_read((AAsset *)cookie, buf, size); } -static int android_write(void *cookie, const char *data, int dataSize) +static int android_write(void *cookie, const char *buf, int size) { TRACELOG(LOG_WARNING, "ANDROID: Failed to provide write access to APK"); diff --git a/raylib/utils.go b/raylib/utils.go index a4bc3e6..56cfad9 100644 --- a/raylib/utils.go +++ b/raylib/utils.go @@ -1,43 +1,48 @@ -//go:build !android -// +build !android +// +build !android,!windows package rl /* -#include "stdlib.h" #include "raylib.h" -void TraceLogWrapper(int logLevel, const char *text) -{ - TraceLog(logLevel, text); -} */ import "C" import ( "fmt" "os" - "unsafe" ) -// SetTraceLogLevel - Set the current threshold (minimum) log level -func SetTraceLogLevel(logLevel TraceLogLevel) { - clogLevel := (C.int)(logLevel) - C.SetTraceLogLevel(clogLevel) +// SetTraceLog - Enable trace log message types +func SetTraceLog(typeFlags int) { + logTypeFlags = typeFlags + + ctypeFlags := (C.int)(typeFlags) + C.SetTraceLogLevel(ctypeFlags) } -// TraceLog - Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) -func TraceLog(logLevel TraceLogLevel, text string, v ...interface{}) { - ctext := C.CString(fmt.Sprintf(text, v...)) - defer C.free(unsafe.Pointer(ctext)) - clogLevel := (C.int)(logLevel) - C.TraceLogWrapper(clogLevel, ctext) +// TraceLog - Show trace log messages (INFO, WARNING, ERROR, DEBUG) +func TraceLog(msgType int, text string, v ...interface{}) { + switch msgType { + case LogInfo: + if logTypeFlags&LogInfo == 0 { + fmt.Printf("INFO: "+text+"\n", v...) + } + case LogWarning: + if logTypeFlags&LogWarning == 0 { + fmt.Printf("WARNING: "+text+"\n", v...) + } + case LogError: + if logTypeFlags&LogError == 0 { + fmt.Printf("ERROR: "+text+"\n", v...) + } + case LogDebug: + if logTypeFlags&LogDebug == 0 { + fmt.Printf("DEBUG: "+text+"\n", v...) + } + } } // HomeDir - Returns user home directory -// NOTE: On Android this returns internal data path and must be called after InitWindow func HomeDir() string { - if homeDir, err := os.UserHomeDir(); err == nil { - return homeDir - } - return "" + return os.Getenv("HOME") } diff --git a/raylib/utils.h b/raylib/utils.h index 23eca8e..3d7a379 100644 --- a/raylib/utils.h +++ b/raylib/utils.h @@ -5,7 +5,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -55,7 +55,9 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -//... +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif //---------------------------------------------------------------------------------- // Global Variables Definition @@ -65,16 +67,12 @@ //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - #if defined(PLATFORM_ANDROID) void InitAssetManager(AAssetManager *manager, const char *dataPath); // Initialize asset manager from android app -FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only! +FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only! #endif -#if defined(__cplusplus) +#ifdef __cplusplus } #endif diff --git a/raylib/utils_android.c b/raylib/utils_android.c new file mode 100644 index 0000000..2b80116 --- /dev/null +++ b/raylib/utils_android.c @@ -0,0 +1,24 @@ +// +build android + +#include "_cgo_export.h" +#include + +void log_info(const char *msg) { + __android_log_print(ANDROID_LOG_INFO, "raylib", "%s\n", msg); +} + +void log_warn(const char *msg) { + __android_log_print(ANDROID_LOG_WARN, "raylib", "%s\n", msg); +} + +void log_error(const char *msg) { + __android_log_print(ANDROID_LOG_ERROR, "raylib", "%s\n", msg); +} + +void log_debug(const char *msg) { + __android_log_print(ANDROID_LOG_DEBUG, "raylib", "%s\n", msg); +} + +const char* get_internal_storage_path() { + return internal_storage_path; +} diff --git a/raylib/utils_android.go b/raylib/utils_android.go index 4189da4..44bb5a1 100644 --- a/raylib/utils_android.go +++ b/raylib/utils_android.go @@ -1,15 +1,17 @@ -//go:build android // +build android package rl /* -#include "stdlib.h" #include "raylib.h" -void TraceLogWrapper(int logLevel, const char *text) -{ - TraceLog(logLevel, text); -} +#include + +void log_info(const char *msg); +void log_warn(const char *msg); +void log_error(const char *msg); +void log_debug(const char *msg); + +extern char* get_internal_storage_path(); */ import "C" @@ -18,22 +20,46 @@ import ( "unsafe" ) -// SetTraceLogLevel - Set the current threshold (minimum) log level -func SetTraceLogLevel(logLevel TraceLogLevel) { - clogLevel := (C.int)(logLevel) - C.SetTraceLogLevel(clogLevel) +// SetTraceLog - Enable trace log message types (bit flags based) +func SetTraceLog(typeFlags int) { + logTypeFlags = typeFlags + + ctypeFlags := (C.int)(typeFlags) + C.SetTraceLogLevel(ctypeFlags) } -// TraceLog - Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) -func TraceLog(logLevel TraceLogLevel, text string, v ...interface{}) { - ctext := C.CString(fmt.Sprintf(text, v...)) - defer C.free(unsafe.Pointer(ctext)) - clogLevel := (C.int)(logLevel) - C.TraceLogWrapper(clogLevel, ctext) +// TraceLog - Trace log messages showing (INFO, WARNING, ERROR, DEBUG) +func TraceLog(msgType int, text string, v ...interface{}) { + switch msgType { + case LogInfo: + if logTypeFlags&LogInfo == 0 { + msg := C.CString(fmt.Sprintf("INFO: "+text, v...)) + defer C.free(unsafe.Pointer(msg)) + C.log_info(msg) + } + case LogWarning: + if logTypeFlags&LogWarning == 0 { + msg := C.CString(fmt.Sprintf("WARNING: "+text, v...)) + defer C.free(unsafe.Pointer(msg)) + C.log_warn(msg) + } + case LogError: + if logTypeFlags&LogError == 0 { + msg := C.CString(fmt.Sprintf("ERROR: "+text, v...)) + defer C.free(unsafe.Pointer(msg)) + C.log_error(msg) + } + case LogDebug: + if logTypeFlags&LogDebug == 0 { + msg := C.CString(fmt.Sprintf("DEBUG: "+text, v...)) + defer C.free(unsafe.Pointer(msg)) + C.log_debug(msg) + } + } } // HomeDir - Returns user home directory // NOTE: On Android this returns internal data path and must be called after InitWindow func HomeDir() string { - return getInternalStoragePath() + return C.GoString(C.get_internal_storage_path()) } diff --git a/raylib/utils_log.c b/raylib/utils_log.c index 7d3d95e..212a4ae 100644 --- a/raylib/utils_log.c +++ b/raylib/utils_log.c @@ -3,7 +3,7 @@ #include // Required for: vprintf() #include // Required for: strcpy(), strcat() -#define MAX_TRACELOG_BUFFER_SIZE 256 // As defined in utils.c from raylib +#define MAX_TRACELOG_BUFFER_SIZE 128 // As defined in utils.c from raylib void rayLogWrapperCallback(int logType, const char *text, va_list args) { char buffer[MAX_TRACELOG_BUFFER_SIZE] = { 0 }; diff --git a/raylib/utils_log.go b/raylib/utils_log.go index 4eec623..d116ae2 100644 --- a/raylib/utils_log.go +++ b/raylib/utils_log.go @@ -7,6 +7,9 @@ import "C" import "unsafe" +// TraceLogCallbackFun - function that will recive the trace log messages +type TraceLogCallbackFun func(int, string) + var internalTraceLogCallbackFun TraceLogCallbackFun = func(int, string) {} // SetTraceLogCallback - set a call-back function for trace log @@ -16,8 +19,8 @@ func SetTraceLogCallback(fn TraceLogCallbackFun) { } //export internalTraceLogCallbackGo -func internalTraceLogCallbackGo(logType C.int, cstr unsafe.Pointer, length C.int) { - str := string(C.GoBytes(cstr, length)) +func internalTraceLogCallbackGo(logType C.int, cstr unsafe.Pointer, len C.int) { + str := string(C.GoBytes(cstr, len)) lt := int(logType) internalTraceLogCallbackFun(lt, str) } diff --git a/raylib/utils_log.h b/raylib/utils_log.h index 8bfc72f..8842e4b 100644 --- a/raylib/utils_log.h +++ b/raylib/utils_log.h @@ -4,6 +4,7 @@ extern "C" { // Prevents name mangling of functions void setLogCallbackWrapper(void); // enable the call-back +void internalTraceLogCallbackGo(int, void*, int); // Go function that will get called #if defined(__cplusplus) } diff --git a/raylib/utils_windows.go b/raylib/utils_windows.go new file mode 100644 index 0000000..9145b6d --- /dev/null +++ b/raylib/utils_windows.go @@ -0,0 +1,52 @@ +// +build windows + +package rl + +/* +#include "raylib.h" +*/ +import "C" + +import ( + "fmt" + "os" +) + +// SetTraceLog - Enable trace log message types (bit flags based) +func SetTraceLog(typeFlags int) { + logTypeFlags = typeFlags + + ctypeFlags := (C.int)(typeFlags) + C.SetTraceLogLevel(ctypeFlags) +} + +// TraceLog - Show trace log messages (INFO, WARNING, ERROR, DEBUG) +func TraceLog(msgType int, text string, v ...interface{}) { + switch msgType { + case LogInfo: + if logTypeFlags&LogInfo == 0 { + fmt.Printf("INFO: "+text+"\n", v...) + } + case LogWarning: + if logTypeFlags&LogWarning == 0 { + fmt.Printf("WARNING: "+text+"\n", v...) + } + case LogError: + if logTypeFlags&LogError == 0 { + fmt.Printf("ERROR: "+text+"\n", v...) + } + case LogDebug: + if logTypeFlags&LogDebug == 0 { + fmt.Printf("DEBUG: "+text+"\n", v...) + } + } +} + +// HomeDir - Returns user home directory +func HomeDir() string { + home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + if home == "" { + home = os.Getenv("USERPROFILE") + } + return home +} diff --git a/rres/README.md b/rres/README.md new file mode 100644 index 0000000..9844231 --- /dev/null +++ b/rres/README.md @@ -0,0 +1,3 @@ +## rres [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/rres?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/rres) + +raylib resources. diff --git a/rres/cmd/rrem/README.md b/rres/cmd/rrem/README.md new file mode 100644 index 0000000..6e8b957 --- /dev/null +++ b/rres/cmd/rrem/README.md @@ -0,0 +1,27 @@ +## rrem + +rREM - raylib Resource EMbedder. + +### Usage + +``` +Usage of ./rrem: + -base string + Resources file basename (default "data") + -bin + Generate Go bindata (.go file) + -comp int + Compression type, 0=NONE, 1=DEFLATE, 2=LZ4, 5=LZMA2 (XZ), 6=BZIP2, 7=Snappy (default 1) + -enc int + Encryption type, 0=NONE, 1=XOR, 2=AES, 3=3DES, 4=Blowfish, 5=XTEA + -header + Generate C header (.h file) + -key string + Encryption key + -source + Generate C source (.c file) +``` + +### Example + +[Example](https://github.com/gen2brain/raylib-go/tree/master/examples/others/resources). diff --git a/rres/cmd/rrem/main.go b/rres/cmd/rrem/main.go new file mode 100644 index 0000000..5938f27 --- /dev/null +++ b/rres/cmd/rrem/main.go @@ -0,0 +1,434 @@ +// rREM - raylib Resource EMbedder +package main + +import ( + "bytes" + "encoding/binary" + "flag" + "fmt" + "image" + "image/color" + "image/draw" + "io" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strings" + "unsafe" + + _ "image/gif" + _ "image/jpeg" + _ "image/png" + + "github.com/blezek/tga" + _ "github.com/jbuchbinder/gopnm" + _ "golang.org/x/image/bmp" + + "github.com/jfreymuth/oggvorbis" + "github.com/jteeuwen/go-bindata" + "github.com/moutend/go-wav" + + "github.com/gen2brain/raylib-go/rres" +) + +func init() { + tga.RegisterFormat() +} + +func main() { + base := flag.String("base", "data", "Resources file basename") + comp := flag.Int("comp", rres.CompDeflate, "Compression type, 0=NONE, 1=DEFLATE, 2=LZ4, 5=LZMA2 (XZ), 6=BZIP2, 7=Snappy") + enc := flag.Int("enc", rres.CryptoNone, "Encryption type, 0=NONE, 1=XOR, 2=AES, 3=3DES, 4=Blowfish, 5=XTEA") + key := flag.String("key", "", "Encryption key") + header := flag.Bool("header", false, "Generate C header (.h file)") + source := flag.Bool("source", false, "Generate C source (.c file)") + bin := flag.Bool("bin", false, "Generate Go bindata (.go file)") + flag.Parse() + + if len(flag.Args()) == 0 { + flag.Usage() + os.Exit(1) + } + + if !validComp(*comp) { + fmt.Printf("compression type %d not implemented\n", *comp) + os.Exit(1) + } + + if !validEnc(*enc) { + fmt.Printf("encryption type %d not implemented\n", *enc) + os.Exit(1) + } + + if *enc != 0 { + if *key == "" { + fmt.Printf("encryption requires key (-k)\n") + os.Exit(1) + } + if len(*key) != 16 && len(*key) != 24 { + fmt.Printf("wrong key length, it should be 16 or 24\n") + os.Exit(1) + } + } + + rresFile, err := os.Create(fmt.Sprintf("%s.rres", *base)) + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + + var headerFile *os.File + if *header { + headerFile, err = os.Create(fmt.Sprintf("%s.h", *base)) + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + + defer headerFile.Close() + } + + var sourceFile *os.File + if *source { + sourceFile, err = os.Create(fmt.Sprintf("%s.c", *base)) + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + + defer sourceFile.Close() + } + + var fileHeader rres.FileHeader + + // "rRES" identifier + copy(fileHeader.ID[:], "rRES") + fileHeader.Count = uint16(len(flag.Args())) + fileHeader.Version = 1 + + // Write file header + err = binary.Write(rresFile, binary.LittleEndian, &fileHeader) + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + + rresFile.Seek(int64(unsafe.Sizeof(fileHeader)), os.SEEK_CUR) + + if *header { + // Write C header file + _, err = headerFile.Write([]byte(fmt.Sprintf("#define NUM_RESOURCES %d\n\n", flag.NArg()))) + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } + } + + for id, filename := range flag.Args() { + var data []byte + var infoHeader rres.InfoHeader + + file, err := os.Open(filename) + if err != nil { + fmt.Printf("%s: %v\n", filename, err) + continue + } + + data, err = ioutil.ReadAll(file) + if err != nil { + fmt.Printf("%s: %v\n", filename, err) + } + + file.Close() + + infoHeader.ID = uint32(id) + infoHeader.CompType = uint8(*comp) + infoHeader.CryptoType = uint8(*enc) + infoHeader.DataType = uint8(fileType(filename)) + infoHeader.PartsCount = uint8(1) + + // Params + data, infoHeader.Param1, infoHeader.Param2, infoHeader.Param3, infoHeader.Param4, err = params(data, int(infoHeader.DataType)) + if err != nil { + fmt.Printf("%s: %v\n", filename, err) + } + + // Encryption + data, err = rres.Encrypt([]byte(*key), data, int(infoHeader.CryptoType)) + if err != nil { + fmt.Printf("%v\n", err) + } + + infoHeader.UncompSize = uint32(len(data)) + + // Compression + data, err = rres.Compress(data, int(infoHeader.CompType)) + if err != nil { + fmt.Printf("%v\n", err) + } + + infoHeader.DataSize = uint32(len(data)) + + // Write resource info and parameters + err = binary.Write(rresFile, binary.LittleEndian, &infoHeader) + if err != nil { + fmt.Printf("%v\n", err) + } + + rresFile.Seek(int64(unsafe.Sizeof(infoHeader)), os.SEEK_CUR) + + // Write resource data + _, err = rresFile.Write(data) + if err != nil { + fmt.Printf("%v\n", err) + } + + fmt.Printf("%s %d // Embedded as %s\n", filepath.Base(filename), id, typeName(int(infoHeader.DataType))) + + if *header { + headerFile.Write([]byte(fmt.Sprintf("#define RES_%s 0x%08x\t\t// Embedded as %s\n", filepath.Base(filename), id, typeName(int(infoHeader.DataType))))) + } + } + + err = rresFile.Sync() + if err != nil { + fmt.Printf("%v\n", err) + } + + err = rresFile.Close() + if err != nil { + fmt.Printf("%v\n", err) + } + + // Generate C source + if *source { + fname := fmt.Sprintf("%s.rres", *base) + file, err := os.Open(fname) + if err != nil { + fmt.Printf("%s: %v\n", fname, err) + } + + d, err := ioutil.ReadAll(file) + if err != nil { + fmt.Printf("%s: %v\n", fname, err) + } + + file.Close() + + err = genSource(sourceFile, d) + if err != nil { + fmt.Printf("%v\n", err) + } + } + + // Generate Go bindata + if *bin { + err = genBin(*base) + if err != nil { + fmt.Printf("%v\n", err) + } + } +} + +// fileType returns resource file type +func fileType(f string) int { + switch strings.ToLower(filepath.Ext(f)) { + case ".jpg", ".jpeg", ".png", ".bmp", ".tga", ".gif": + return rres.TypeImage + case ".txt", ".csv", ".info", ".md": + return rres.TypeText + case ".wav": + return rres.TypeWave + case ".ogg": + return rres.TypeVorbis + case ".obj": + return rres.TypeVertex + default: + return rres.TypeRaw + } +} + +// typeName returns data type name +func typeName(dataType int) string { + switch dataType { + case rres.TypeImage: + return "IMAGE" + case rres.TypeWave: + return "WAVE" + case rres.TypeVorbis: + return "VORBIS" + case rres.TypeText: + return "TEXT" + default: + return "RAW" + } +} + +// validEnc checks if encryption type is valid +func validEnc(encType int) bool { + switch encType { + case rres.CryptoNone, rres.CryptoXOR: + return true + case rres.CryptoAES, rres.Crypto3DES: + return true + case rres.CryptoBlowfish, rres.CryptoXTEA: + return true + } + return false +} + +// validComp checks if compression type is valid +func validComp(compType int) bool { + switch compType { + case rres.CompNone, rres.CompDeflate: + return true + case rres.CompLZ4, rres.CompLZMA2: + return true + case rres.CompBZIP2, rres.CompSnappy: + return true + } + return false +} + +// params returns data params +func params(data []byte, dataType int) (d []byte, p1, p2, p3, p4 uint32, err error) { + switch dataType { + case rres.TypeImage: + var img image.Image + + img, _, err = image.Decode(bytes.NewReader(data)) + if err != nil { + return + } + + rect := img.Bounds() + width, height := rect.Dx(), rect.Dy() + + p1 = uint32(width) + p2 = uint32(height) + + switch img.ColorModel() { + case color.GrayModel: + p3 = rres.ImUncompGrayscale + + i := image.NewGray(rect) + draw.Draw(i, rect, img, rect.Min, draw.Src) + d = i.Pix + return + case color.Gray16Model: + p3 = rres.ImUncompGrayAlpha + + i := image.NewGray16(rect) + draw.Draw(i, rect, img, rect.Min, draw.Src) + d = i.Pix + return + default: + p3 = rres.ImUncompR8g8b8a8 + + i := image.NewNRGBA(rect) + draw.Draw(i, rect, img, rect.Min, draw.Src) + d = i.Pix + return + } + + case rres.TypeWave: + a := &wav.File{} + err = wav.Unmarshal(data, a) + if err != nil { + return + } + + d, err = ioutil.ReadAll(a) + if err != nil { + return + } + + p1 = uint32(a.Samples()) + p2 = uint32(a.SamplesPerSec()) + p3 = uint32(a.BitsPerSample()) + p4 = uint32(a.Channels()) + return + case rres.TypeVorbis: + r, e := oggvorbis.NewReader(bytes.NewReader(data)) + if e != nil { + err = e + return + } + + o, _, e := oggvorbis.ReadAll(bytes.NewReader(data)) + if e != nil { + err = e + return + } + + // Convert []float32 to []byte + header := *(*reflect.SliceHeader)(unsafe.Pointer(&o)) + header.Len *= 4 + header.Cap *= 4 + d = *(*[]byte)(unsafe.Pointer(&header)) + + p1 = uint32(r.SampleRate()) + p2 = uint32(r.Bitrate().Nominal) + p3 = uint32(r.Channels()) + return + case rres.TypeVertex: + // TODO https://github.com/sheenobu/go-obj + case rres.TypeText, rres.TypeRaw: + } + + return +} + +// genSource generates C source file +func genSource(w io.Writer, data []byte) error { + length := len(data) + + _, err := w.Write([]byte("// This file has been automatically generated by rREM - raylib Resource Embedder\n\n")) + if err != nil { + return err + } + + _, err = w.Write([]byte(fmt.Sprintf("const unsigned char data[%d] = {\n ", length))) + if err != nil { + fmt.Printf("%v\n", err) + } + + blCounter := 0 // break line counter + + for i := 0; i < len(data)-1; i++ { + blCounter++ + + _, err = w.Write([]byte(fmt.Sprintf("0x%.2x, ", data[i]))) + if err != nil { + return err + } + + if blCounter >= 24 { + _, err = w.Write([]byte("\n ")) + if err != nil { + return err + } + + blCounter = 0 + } + } + + _, err = w.Write([]byte(fmt.Sprintf("0x%.2x };\n", data[length-1]))) + if err != nil { + return err + } + + return nil +} + +//genBin generates go-bindata file +func genBin(base string) error { + cfg := bindata.NewConfig() + cfg.NoCompress = true + cfg.Output = fmt.Sprintf("%s.go", base) + cfg.Input = make([]bindata.InputConfig, 1) + cfg.Input[0] = bindata.InputConfig{Path: fmt.Sprintf("%s.rres", base), Recursive: false} + + return bindata.Translate(cfg) +} diff --git a/rres/rres.go b/rres/rres.go new file mode 100644 index 0000000..6337dae --- /dev/null +++ b/rres/rres.go @@ -0,0 +1,691 @@ +package rres + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/rand" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "os" + "unsafe" + + "github.com/dsnet/compress/bzip2" + "github.com/golang/snappy" + "github.com/klauspost/compress/flate" + "github.com/pierrec/lz4" + xor "github.com/rootlch/encrypt" + "github.com/ulikunitz/xz" + "golang.org/x/crypto/blowfish" + "golang.org/x/crypto/xtea" + + "github.com/gen2brain/raylib-go/raylib" +) + +type Data struct { + // Resource type (4 byte) + Type uint32 + + // Resource parameter 1 (4 byte) + Param1 uint32 + // Resource parameter 2 (4 byte) + Param2 uint32 + // Resource parameter 3 (4 byte) + Param3 uint32 + // Resource parameter 4 (4 byte) + Param4 uint32 + + // Resource data + Data []byte +} + +// FileHeader - rRES file header (8 byte) +type FileHeader struct { + // File identifier: rRES (4 byte) + ID [4]byte + // File version and subversion (2 byte) + Version uint16 + // Number of resources in this file (2 byte) + Count uint16 +} + +// InfoHeader - rRES info header, every resource includes this header (16 byte + 16 byte) +type InfoHeader struct { + // Resource unique identifier (4 byte) + ID uint32 + // Resource data type (1 byte) + DataType uint8 + // Resource data compression type (1 byte) + CompType uint8 + // Resource data encryption type (1 byte) + CryptoType uint8 + // Resource data parts count, used for splitted data (1 byte) + PartsCount uint8 + // Resource data size (compressed or not, only DATA) (4 byte) + DataSize uint32 + // Resource data size (uncompressed, only DATA) (4 byte) + UncompSize uint32 + // Resource parameter 1 (4 byte) + Param1 uint32 + // Resource parameter 2 (4 byte) + Param2 uint32 + // Resource parameter 3 (4 byte) + Param3 uint32 + // Resource parameter 4 (4 byte) + Param4 uint32 +} + +// rRES data types +const ( + TypeRaw = iota + TypeImage + TypeWave + TypeVertex + TypeText + TypeFontImage + TypeFontCharData + TypeDirectory + TypeVorbis +) + +// Compression types +const ( + // No data compression + CompNone = iota + // DEFLATE compression + CompDeflate + // LZ4 compression + CompLZ4 + // LZMA compression + CompLZMA + // BROTLI compression + CompBrotli + // LZMA2 (XZ) compression + CompLZMA2 + // BZIP2 compression + CompBZIP2 + // Snappy compression + CompSnappy +) + +// Encryption types +const ( + // No data encryption + CryptoNone = iota + // XOR (128 bit) encryption + CryptoXOR + // RIJNDAEL (128 bit) encryption (AES) + CryptoAES + // Triple DES encryption + Crypto3DES + // Blowfish encryption + CryptoBlowfish + // Extended TEA encryption + CryptoXTEA +) + +// Image formats +const ( + // 8 bit per pixel (no alpha) + ImUncompGrayscale = iota + 1 + // 16 bpp (2 channels) + ImUncompGrayAlpha + // 16 bpp + ImUncompR5g6b5 + // 24 bpp + ImUncompR8g8b8 + // 16 bpp (1 bit alpha) + ImUncompR5g5b5a1 + // 16 bpp (4 bit alpha) + ImUncompR4g4b4a4 + // 32 bpp + ImUncompR8g8b8a8 + // 4 bpp (no alpha) + ImCompDxt1Rgb + // 4 bpp (1 bit alpha) + ImCompDxt1Rgba + // 8 bpp + ImCompDxt3Rgba + // 8 bpp + ImCompDxt5Rgba + // 4 bpp + ImCompEtc1Rgb + // 4 bpp + ImCompEtc2Rgb + // 8 bpp + ImCompEtc2EacRgba + // 4 bpp + ImCompPvrtRgb + // 4 bpp + ImCompPvrtRgba + // 8 bpp + ImCompAstc4x4Rgba + // 2 bpp + ImCompAstc8x8Rgba +) + +// Vert +const ( + VertPosition = iota + VertTexcoord1 + VertTexcoord2 + VertTexcoord3 + VertTexcoord4 + VertNormal + VertTangent + VertColor + VertIndex +) + +// Vert +const ( + VertByte = iota + VertShort + VertInt + VertHfloat + VertFloat +) + +// LoadResource - Load resource from file by id +// NOTE: Returns uncompressed data with parameters, search resource by id +func LoadResource(reader io.ReadSeeker, rresID int, key []byte) (data Data) { + var fileHeader FileHeader + var infoHeader InfoHeader + + reader.Seek(0, 0) + + // Read rres file header + err := binary.Read(reader, binary.LittleEndian, &fileHeader) + if err != nil { + rl.TraceLog(rl.LogWarning, err.Error()) + return + } + + // Verify "rRES" identifier + if string(fileHeader.ID[:]) != "rRES" { + rl.TraceLog(rl.LogWarning, "not a valid raylib resource file") + return + } + + reader.Seek(int64(unsafe.Sizeof(fileHeader)), os.SEEK_CUR) + + for i := 0; i < int(fileHeader.Count); i++ { + // Read resource info and parameters + err = binary.Read(reader, binary.LittleEndian, &infoHeader) + if err != nil { + rl.TraceLog(rl.LogWarning, err.Error()) + return + } + + reader.Seek(int64(unsafe.Sizeof(infoHeader)), os.SEEK_CUR) + + if int(infoHeader.ID) == rresID { + data.Type = uint32(infoHeader.DataType) + data.Param1 = infoHeader.Param1 + data.Param2 = infoHeader.Param2 + data.Param3 = infoHeader.Param3 + data.Param4 = infoHeader.Param4 + + // Read resource data block + b := make([]byte, infoHeader.DataSize) + reader.Read(b) + + // Decompress data + data.Data, err = Decompress(b, int(infoHeader.CompType)) + if err != nil { + rl.TraceLog(rl.LogWarning, "[ID %d] %v", infoHeader.ID, err) + } + + // Decrypt data + data.Data, err = Decrypt(key, data.Data, int(infoHeader.CryptoType)) + if err != nil { + rl.TraceLog(rl.LogWarning, "[ID %d] %v", infoHeader.ID, err) + } + + if data.Data != nil && len(data.Data) == int(infoHeader.UncompSize) { + rl.TraceLog(rl.LogInfo, "[ID %d] Resource data loaded successfully", infoHeader.ID) + } + } else { + // Skip required data to read next resource infoHeader + reader.Seek(int64(infoHeader.DataSize), os.SEEK_CUR) + } + } + + if data.Data == nil { + rl.TraceLog(rl.LogWarning, "[ID %d] Requested resource could not be found", rresID) + } + + return +} + +// Encrypt data +func Encrypt(key, data []byte, cryptoType int) ([]byte, error) { + switch cryptoType { + case CryptoXOR: + c, err := xor.NewXor(string(key)) + if err != nil { + return nil, err + } + + return c.Encode(data), nil + case CryptoAES: + b, err := encryptAES(key, data) + if err != nil { + return nil, err + } + + return b, nil + case Crypto3DES: + b, err := encrypt3DES(key, data) + if err != nil { + return nil, err + } + + return b, nil + case CryptoBlowfish: + b, err := encryptBlowfish(key, data) + if err != nil { + return nil, err + } + + return b, nil + case CryptoXTEA: + b, err := encryptXTEA(key, data) + if err != nil { + fmt.Printf("%v\n", err) + } + + return b, nil + default: + return data, nil + } +} + +// Decrypt data +func Decrypt(key, data []byte, cryptoType int) ([]byte, error) { + switch cryptoType { + case CryptoXOR: + c, err := xor.NewXor(string(key)) + if err != nil { + return nil, err + } + + b := c.Encode(data) + return b, nil + case CryptoAES: + b, err := decryptAES(key, data) + if err != nil { + return nil, err + } + return b, nil + case Crypto3DES: + b, err := decrypt3DES(key, data) + if err != nil { + return nil, err + } + return b, nil + case CryptoBlowfish: + b, err := decryptBlowfish(key, data) + if err != nil { + return nil, err + } + return b, nil + case CryptoXTEA: + b, err := decryptXTEA(key, data) + if err != nil { + return nil, err + } + return b, nil + default: + return data, nil + } +} + +// Compress data +func Compress(data []byte, compType int) ([]byte, error) { + switch compType { + case CompNone: + return data, nil + case CompDeflate: + buf := new(bytes.Buffer) + + w, err := flate.NewWriter(buf, flate.DefaultCompression) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompLZ4: + buf := new(bytes.Buffer) + + w := lz4.NewWriter(buf) + + _, err := w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompLZMA2: + buf := new(bytes.Buffer) + + w, err := xz.NewWriter(buf) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompBZIP2: + buf := new(bytes.Buffer) + + w, err := bzip2.NewWriter(buf, &bzip2.WriterConfig{Level: bzip2.BestCompression}) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompSnappy: + buf := new(bytes.Buffer) + + w := snappy.NewWriter(buf) + + _, err := w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + default: + return data, nil + } +} + +// Decompress data +func Decompress(data []byte, compType int) ([]byte, error) { + switch compType { + case CompNone: + return data, nil + case CompDeflate: + r := flate.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + r.Close() + + return u, nil + case CompLZ4: + r := lz4.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case CompLZMA2: + r, err := xz.NewReader(bytes.NewReader(data)) + if err != nil { + return nil, err + } + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case CompBZIP2: + r, err := bzip2.NewReader(bytes.NewReader(data), &bzip2.ReaderConfig{}) + if err != nil { + return nil, err + } + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case CompSnappy: + r := snappy.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + default: + return data, nil + } +} + +// pad to block size +func pad(src []byte, blockSize int) []byte { + padding := blockSize - len(src)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(src, padtext...) +} + +// unpad +func unpad(src []byte) ([]byte, error) { + length := len(src) + unpadding := int(src[length-1]) + + if unpadding > length { + return nil, fmt.Errorf("unpad error. This can happen when incorrect encryption key is used.") + } + + return src[:(length - unpadding)], nil +} + +// encryptAES +func encryptAES(key, text []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, aes.BlockSize) + ciphertext := make([]byte, aes.BlockSize+len(msg)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cfb := cipher.NewCFBEncrypter(block, iv) + cfb.XORKeyStream(ciphertext[aes.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptAES +func decryptAES(key, text []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % aes.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:aes.BlockSize] + msg := text[aes.BlockSize:] + + cfb := cipher.NewCFBDecrypter(block, iv) + cfb.XORKeyStream(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encrypt3DES +func encrypt3DES(key, text []byte) ([]byte, error) { + block, err := des.NewTripleDESCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, des.BlockSize) + ciphertext := make([]byte, des.BlockSize+len(msg)) + iv := ciphertext[:des.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[des.BlockSize:], msg) + + return ciphertext, nil +} + +// decrypt3DES +func decrypt3DES(key, text []byte) ([]byte, error) { + block, err := des.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % des.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:des.BlockSize] + msg := text[des.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encryptBlowfish +func encryptBlowfish(key, text []byte) ([]byte, error) { + block, err := blowfish.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, blowfish.BlockSize) + ciphertext := make([]byte, blowfish.BlockSize+len(msg)) + iv := ciphertext[:blowfish.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[blowfish.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptBlowfish +func decryptBlowfish(key, text []byte) ([]byte, error) { + block, err := blowfish.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % blowfish.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:blowfish.BlockSize] + msg := text[blowfish.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encryptXTEA +func encryptXTEA(key, text []byte) ([]byte, error) { + block, err := xtea.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, xtea.BlockSize) + ciphertext := make([]byte, xtea.BlockSize+len(msg)) + iv := ciphertext[:xtea.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[xtea.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptXTEA +func decryptXTEA(key, text []byte) ([]byte, error) { + block, err := xtea.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % xtea.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:xtea.BlockSize] + msg := text[xtea.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +}